blob: 8822c1865e9b55a20bf4b3423564bfa296901c8c [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 Ponomarenkoe3d6bf02012-11-14 11:49:09 +04001071my $DEFAULT_STD_PARMS = "std::(allocator|less|char_traits|regex_traits|istreambuf_iterator|ostreambuf_iterator)";
Andrey Ponomarenko07aea072012-11-12 16:15:07 +04001072
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;
Andrey Ponomarenko82bc2572012-11-14 13:55:30 +04001337my %EnumConstants;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04001338
1339# Types
1340my %TypeInfo;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04001341my %TemplateInstance;
Andrey Ponomarenko85043792012-05-14 16:48:07 +04001342my %TemplateDecl;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04001343my %SkipTypes = (
1344 "1"=>{},
1345 "2"=>{} );
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04001346my %CheckedTypes;
1347my %TName_Tid;
1348my %EnumMembName_Id;
1349my %NestedNameSpaces = (
1350 "1"=>{},
1351 "2"=>{} );
1352my %UsedType;
1353my %VirtualTable;
Andrey Ponomarenko16934472012-03-29 15:37:04 +04001354my %VirtualTable_Model;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04001355my %ClassVTable;
1356my %ClassVTable_Content;
1357my %VTableClass;
1358my %AllocableClass;
1359my %ClassMethods;
Andrey Ponomarenko16934472012-03-29 15:37:04 +04001360my %ClassNames;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04001361my %Class_SubClasses;
1362my %OverriddenMethods;
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04001363my $MAX_ID = 0;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04001364
1365# Typedefs
1366my %Typedef_BaseName;
1367my %Typedef_Tr;
1368my %Typedef_Eq;
1369my %StdCxxTypedef;
1370my %MissedTypedef;
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04001371my %MissedBase;
1372my %MissedBase_R;
Andrey Ponomarenko9927e332012-10-19 10:50:48 +04001373my %TypeTypedef;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04001374
1375# Symbols
1376my %SymbolInfo;
1377my %tr_name;
1378my %mangled_name_gcc;
1379my %mangled_name;
1380my %SkipSymbols = (
1381 "1"=>{},
1382 "2"=>{} );
1383my %SkipNameSpaces = (
1384 "1"=>{},
1385 "2"=>{} );
Andrey Ponomarenkoa01311b2012-06-08 17:20:02 +04001386my %AddNameSpaces = (
1387 "1"=>{},
1388 "2"=>{} );
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04001389my %SymbolsList;
1390my %SymbolsList_App;
1391my %CheckedSymbols;
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04001392my %Symbol_Library = (
1393 "1"=>{},
1394 "2"=>{} );
1395my %Library_Symbol = (
1396 "1"=>{},
1397 "2"=>{} );
1398my %DepSymbol_Library = (
1399 "1"=>{},
1400 "2"=>{} );
1401my %DepLibrary_Symbol = (
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04001402 "1"=>{},
1403 "2"=>{} );
1404my %MangledNames;
Andrey Ponomarenko9927e332012-10-19 10:50:48 +04001405my %Func_ShortName;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04001406my %AddIntParams;
1407my %Interface_Impl;
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04001408my %GlobalDataObject;
Andrey Ponomarenko07aea072012-11-12 16:15:07 +04001409my %WeakSymbols;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04001410
1411# Headers
1412my %Include_Preamble;
1413my %Registered_Headers;
1414my %HeaderName_Paths;
1415my %Header_Dependency;
1416my %Include_Neighbors;
1417my %Include_Paths;
1418my %INC_PATH_AUTODETECT = (
1419 "1"=>1,
1420 "2"=>1 );
1421my %Add_Include_Paths;
1422my %Skip_Include_Paths;
1423my %RegisteredDirs;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04001424my %Header_ErrorRedirect;
1425my %Header_Includes;
1426my %Header_ShouldNotBeUsed;
1427my %RecursiveIncludes;
1428my %Header_Include_Prefix;
1429my %SkipHeaders;
1430my %SkipHeadersList=(
1431 "1"=>{},
1432 "2"=>{} );
1433my %SkipLibs;
1434my %Include_Order;
1435my %TUnit_NameSpaces;
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +04001436my %TUnit_Classes;
Andrey Ponomarenko9927e332012-10-19 10:50:48 +04001437my %TUnit_Funcs;
1438my %TUnit_Vars;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04001439
Andrey Ponomarenko07aea072012-11-12 16:15:07 +04001440my %CppMode = (
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04001441 "1"=>0,
1442 "2"=>0 );
1443my %AutoPreambleMode = (
1444 "1"=>0,
1445 "2"=>0 );
1446my %MinGWMode = (
1447 "1"=>0,
1448 "2"=>0 );
Andrey Ponomarenko01117f12012-06-26 12:23:02 +04001449my %Cpp0xMode = (
1450 "1"=>0,
1451 "2"=>0 );
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04001452
1453# Shared Objects
Andrey Ponomarenko9927e332012-10-19 10:50:48 +04001454my %RegisteredObjects;
Andrey Ponomarenko07aea072012-11-12 16:15:07 +04001455my %RegisteredObjects_Short;
Andrey Ponomarenko9927e332012-10-19 10:50:48 +04001456my %RegisteredSONAMEs;
1457my %RegisteredObject_Dirs;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04001458
1459# System Objects
1460my %SystemObjects;
1461my %DefaultLibPaths;
Andrey Ponomarenko9927e332012-10-19 10:50:48 +04001462my %DyLib_DefaultPath;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04001463
1464# System Headers
1465my %SystemHeaders;
1466my %DefaultCppPaths;
1467my %DefaultGccPaths;
1468my %DefaultIncPaths;
1469my %DefaultCppHeader;
1470my %DefaultGccHeader;
1471my %UserIncPath;
1472
1473# Merging
1474my %CompleteSignature;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04001475my $Version;
1476my %AddedInt;
1477my %RemovedInt;
1478my %AddedInt_Virt;
1479my %RemovedInt_Virt;
1480my %VirtualReplacement;
1481my %ChangedTypedef;
1482my %CompatRules;
1483my %IncompleteRules;
1484my %UnknownRules;
Andrey Ponomarenko16934472012-03-29 15:37:04 +04001485my %VTableChanged_M;
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04001486my %ExtendedSymbols;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04001487my %ReturnedClass;
1488my %ParamClass;
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04001489my %SourceAlternative;
1490my %SourceAlternative_B;
1491my %SourceReplacement;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04001492
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +04001493# Calling Conventions
1494my %UseConv_Real = (
1495 "1"=>0,
1496 "2"=>0 );
1497
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04001498# OS Compliance
1499my %TargetLibs;
1500my %TargetHeaders;
1501
1502# OS Specifics
1503my $OStarget = $OSgroup;
1504my %TargetTools;
1505
1506# Compliance Report
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04001507my %Type_MaxSeverity;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04001508
1509# Recursion locks
1510my @RecurLib;
1511my @RecurSymlink;
1512my @RecurTypes;
1513my @RecurInclude;
1514my @RecurConstant;
1515
1516# System
1517my %SystemPaths;
1518my %DefaultBinPaths;
1519my $GCC_PATH;
1520
1521# Symbols versioning
1522my %SymVer = (
1523 "1"=>{},
1524 "2"=>{} );
1525
1526# Problem descriptions
1527my %CompatProblems;
1528my %ProblemsWithConstants;
1529my %ImplProblems;
1530my %TotalAffected;
1531
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04001532# Reports
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04001533my $ContentID = 1;
1534my $ContentSpanStart = "<span class=\"section\" onclick=\"javascript:showContent(this, 'CONTENT_ID')\">\n";
1535my $ContentSpanStart_Affected = "<span class=\"section_affected\" onclick=\"javascript:showContent(this, 'CONTENT_ID')\">\n";
1536my $ContentSpanStart_Info = "<span class=\"section_info\" onclick=\"javascript:showContent(this, 'CONTENT_ID')\">\n";
1537my $ContentSpanEnd = "</span>\n";
1538my $ContentDivStart = "<div id=\"CONTENT_ID\" style=\"display:none;\">\n";
1539my $ContentDivEnd = "</div>\n";
1540my $Content_Counter = 0;
1541
Andrey Ponomarenko5c09ef32012-06-14 18:17:33 +04001542# XML Dump
1543my $TAG_ID = 0;
1544my $INDENT = " ";
1545
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04001546# Modes
1547my $JoinReport = 1;
1548my $DoubleReport = 0;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04001549
1550sub get_Modules()
1551{
1552 my $TOOL_DIR = get_dirname($0);
1553 if(not $TOOL_DIR)
1554 { # patch for MS Windows
1555 $TOOL_DIR = ".";
1556 }
1557 my @SEARCH_DIRS = (
1558 # tool's directory
1559 abs_path($TOOL_DIR),
1560 # relative path to modules
1561 abs_path($TOOL_DIR)."/../share/abi-compliance-checker",
1562 # system directory
1563 "ACC_MODULES_INSTALL_PATH"
1564 );
1565 foreach my $DIR (@SEARCH_DIRS)
1566 {
1567 if(not is_abs($DIR))
1568 { # relative path
1569 $DIR = abs_path($TOOL_DIR)."/".$DIR;
1570 }
1571 if(-d $DIR."/modules") {
1572 return $DIR."/modules";
1573 }
1574 }
1575 exitStatus("Module_Error", "can't find modules");
1576}
1577
Andrey Ponomarenko01117f12012-06-26 12:23:02 +04001578my %LoadedModules = ();
1579
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04001580sub loadModule($)
1581{
1582 my $Name = $_[0];
Andrey Ponomarenko01117f12012-06-26 12:23:02 +04001583 if(defined $LoadedModules{$Name}) {
1584 return;
1585 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04001586 my $Path = $MODULES_DIR."/Internals/$Name.pm";
1587 if(not -f $Path) {
1588 exitStatus("Module_Error", "can't access \'$Path\'");
1589 }
1590 require $Path;
Andrey Ponomarenko01117f12012-06-26 12:23:02 +04001591 $LoadedModules{$Name} = 1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04001592}
1593
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04001594sub showPos($)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04001595{
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04001596 my $Number = $_[0];
1597 if(not $Number) {
1598 $Number = 1;
1599 }
1600 else {
1601 $Number = int($Number)+1;
1602 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04001603 if($Number>3) {
1604 return $Number."th";
1605 }
1606 elsif($Number==1) {
1607 return "1st";
1608 }
1609 elsif($Number==2) {
1610 return "2nd";
1611 }
1612 elsif($Number==3) {
1613 return "3rd";
1614 }
1615 else {
1616 return $Number;
1617 }
1618}
1619
1620sub search_Tools($)
1621{
1622 my $Name = $_[0];
1623 return "" if(not $Name);
1624 if(my @Paths = keys(%TargetTools))
1625 {
1626 foreach my $Path (@Paths)
1627 {
1628 if(-f joinPath($Path, $Name)) {
1629 return joinPath($Path, $Name);
1630 }
1631 if($CrossPrefix)
1632 { # user-defined prefix (arm-none-symbianelf, ...)
1633 my $Candidate = joinPath($Path, $CrossPrefix."-".$Name);
1634 if(-f $Candidate) {
1635 return $Candidate;
1636 }
1637 }
1638 }
1639 }
1640 else {
1641 return "";
1642 }
1643}
1644
1645sub synch_Cmd($)
1646{
1647 my $Name = $_[0];
1648 if(not $GCC_PATH)
1649 { # GCC was not found yet
1650 return "";
1651 }
1652 my $Candidate = $GCC_PATH;
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04001653 if($Candidate=~s/\bgcc(|\.\w+)\Z/$Name$1/) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04001654 return $Candidate;
1655 }
1656 return "";
1657}
1658
1659sub get_CmdPath($)
1660{
1661 my $Name = $_[0];
1662 return "" if(not $Name);
1663 if(defined $Cache{"get_CmdPath"}{$Name}) {
1664 return $Cache{"get_CmdPath"}{$Name};
1665 }
1666 my %BinUtils = map {$_=>1} (
1667 "c++filt",
1668 "objdump",
1669 "readelf"
1670 );
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04001671 if($BinUtils{$Name} and $GCC_PATH)
1672 {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04001673 if(my $Dir = get_dirname($GCC_PATH)) {
1674 $TargetTools{$Dir}=1;
1675 }
1676 }
1677 my $Path = search_Tools($Name);
1678 if(not $Path and $OSgroup eq "windows") {
1679 $Path = search_Tools($Name.".exe");
1680 }
1681 if(not $Path and $BinUtils{$Name})
1682 {
1683 if($CrossPrefix)
1684 { # user-defined prefix
1685 $Path = search_Cmd($CrossPrefix."-".$Name);
1686 }
1687 }
1688 if(not $Path and $BinUtils{$Name})
1689 {
1690 if(my $Candidate = synch_Cmd($Name))
1691 { # synch with GCC
1692 if($Candidate=~/[\/\\]/)
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04001693 { # command path
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04001694 if(-f $Candidate) {
1695 $Path = $Candidate;
1696 }
1697 }
1698 elsif($Candidate = search_Cmd($Candidate))
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04001699 { # command name
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04001700 $Path = $Candidate;
1701 }
1702 }
1703 }
1704 if(not $Path) {
1705 $Path = search_Cmd($Name);
1706 }
1707 if(not $Path and $OSgroup eq "windows")
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04001708 { # search for *.exe file
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04001709 $Path=search_Cmd($Name.".exe");
1710 }
1711 if($Path=~/\s/) {
1712 $Path = "\"".$Path."\"";
1713 }
1714 return ($Cache{"get_CmdPath"}{$Name}=$Path);
1715}
1716
1717sub search_Cmd($)
1718{
1719 my $Name = $_[0];
1720 return "" if(not $Name);
1721 if(defined $Cache{"search_Cmd"}{$Name}) {
1722 return $Cache{"search_Cmd"}{$Name};
1723 }
1724 if(my $DefaultPath = get_CmdPath_Default($Name)) {
1725 return ($Cache{"search_Cmd"}{$Name} = $DefaultPath);
1726 }
1727 foreach my $Path (sort {length($a)<=>length($b)} keys(%{$SystemPaths{"bin"}}))
1728 {
1729 my $CmdPath = joinPath($Path,$Name);
1730 if(-f $CmdPath)
1731 {
1732 if($Name=~/gcc/) {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04001733 next if(not check_gcc($CmdPath, "3"));
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04001734 }
1735 return ($Cache{"search_Cmd"}{$Name} = $CmdPath);
1736 }
1737 }
1738 return ($Cache{"search_Cmd"}{$Name} = "");
1739}
1740
1741sub get_CmdPath_Default($)
1742{ # search in PATH
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04001743 return "" if(not $_[0]);
1744 if(defined $Cache{"get_CmdPath_Default"}{$_[0]}) {
1745 return $Cache{"get_CmdPath_Default"}{$_[0]};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04001746 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04001747 return ($Cache{"get_CmdPath_Default"}{$_[0]} = get_CmdPath_Default_I($_[0]));
1748}
1749
1750sub get_CmdPath_Default_I($)
1751{ # search in PATH
1752 my $Name = $_[0];
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04001753 if($Name=~/find/)
1754 { # special case: search for "find" utility
Andrey Ponomarenkoa01311b2012-06-08 17:20:02 +04001755 if(`find \"$TMP_DIR\" -maxdepth 0 2>\"$TMP_DIR/null\"`) {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04001756 return "find";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04001757 }
1758 }
1759 elsif($Name=~/gcc/) {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04001760 return check_gcc($Name, "3");
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04001761 }
1762 if(check_command($Name)) {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04001763 return $Name;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04001764 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04001765 if($OSgroup eq "windows")
1766 {
Andrey Ponomarenkoa01311b2012-06-08 17:20:02 +04001767 if(`$Name /? 2>\"$TMP_DIR/null\"`) {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04001768 return $Name;
1769 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04001770 }
1771 if($Name!~/which/)
1772 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04001773 if(my $WhichCmd = get_CmdPath("which"))
1774 {
Andrey Ponomarenkoa01311b2012-06-08 17:20:02 +04001775 if(`$WhichCmd $Name 2>\"$TMP_DIR/null\"`) {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04001776 return $Name;
1777 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04001778 }
1779 }
1780 foreach my $Path (sort {length($a)<=>length($b)} keys(%DefaultBinPaths))
1781 {
1782 if(-f $Path."/".$Name) {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04001783 return joinPath($Path,$Name);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04001784 }
1785 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04001786 return "";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04001787}
1788
1789sub clean_path($)
1790{
1791 my $Path = $_[0];
1792 $Path=~s/[\/\\]+\Z//g;
1793 return $Path;
1794}
1795
1796sub classifyPath($)
1797{
1798 my $Path = $_[0];
1799 if($Path=~/[\*\[]/)
1800 { # wildcard
1801 $Path=~s/\*/.*/g;
1802 $Path=~s/\\/\\\\/g;
1803 return ($Path, "Pattern");
1804 }
1805 elsif($Path=~/[\/\\]/)
1806 { # directory or relative path
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04001807 $Path=~s/[\/\\]+\Z//g;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04001808 return (path_format($Path, $OSgroup), "Path");
1809 }
1810 else {
1811 return ($Path, "Name");
1812 }
1813}
1814
1815sub readDescriptor($$)
1816{
1817 my ($LibVersion, $Content) = @_;
1818 return if(not $LibVersion);
1819 my $DName = $DumpAPI?"descriptor":"descriptor \"d$LibVersion\"";
1820 if(not $Content) {
1821 exitStatus("Error", "$DName is empty");
1822 }
1823 if($Content!~/\</) {
Andrey Ponomarenko5c09ef32012-06-14 18:17:33 +04001824 exitStatus("Error", "incorrect descriptor (see -d1 option)");
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04001825 }
1826 $Content=~s/\/\*(.|\n)+?\*\///g;
1827 $Content=~s/<\!--(.|\n)+?-->//g;
1828 $Descriptor{$LibVersion}{"Version"} = parseTag(\$Content, "version");
1829 if($TargetVersion{$LibVersion}) {
1830 $Descriptor{$LibVersion}{"Version"} = $TargetVersion{$LibVersion};
1831 }
1832 if(not $Descriptor{$LibVersion}{"Version"}) {
1833 exitStatus("Error", "version in the $DName is not specified (<version> section)");
1834 }
1835 if($Content=~/{RELPATH}/)
1836 {
1837 if(my $RelDir = $RelativeDirectory{$LibVersion}) {
1838 $Content =~ s/{RELPATH}/$RelDir/g;
1839 }
1840 else
1841 {
1842 my $NeedRelpath = $DumpAPI?"-relpath":"-relpath$LibVersion";
1843 exitStatus("Error", "you have not specified $NeedRelpath option, but the $DName contains {RELPATH} macro");
1844 }
1845 }
1846
1847 if(not $CheckObjectsOnly_Opt)
1848 {
1849 my $DHeaders = parseTag(\$Content, "headers");
1850 if(not $DHeaders) {
1851 exitStatus("Error", "header files in the $DName are not specified (<headers> section)");
1852 }
1853 elsif(lc($DHeaders) ne "none")
1854 { # append the descriptor headers list
1855 if($Descriptor{$LibVersion}{"Headers"})
1856 { # multiple descriptors
1857 $Descriptor{$LibVersion}{"Headers"} .= "\n".$DHeaders;
1858 }
1859 else {
1860 $Descriptor{$LibVersion}{"Headers"} = $DHeaders;
1861 }
1862 foreach my $Path (split(/\s*\n\s*/, $DHeaders))
1863 {
1864 if(not -e $Path) {
1865 exitStatus("Access_Error", "can't access \'$Path\'");
1866 }
1867 }
1868 }
1869 }
1870 if(not $CheckHeadersOnly_Opt)
1871 {
1872 my $DObjects = parseTag(\$Content, "libs");
1873 if(not $DObjects) {
1874 exitStatus("Error", "$SLIB_TYPE libraries in the $DName are not specified (<libs> section)");
1875 }
1876 elsif(lc($DObjects) ne "none")
1877 { # append the descriptor libraries list
1878 if($Descriptor{$LibVersion}{"Libs"})
1879 { # multiple descriptors
1880 $Descriptor{$LibVersion}{"Libs"} .= "\n".$DObjects;
1881 }
1882 else {
1883 $Descriptor{$LibVersion}{"Libs"} .= $DObjects;
1884 }
1885 foreach my $Path (split(/\s*\n\s*/, $DObjects))
1886 {
1887 if(not -e $Path) {
1888 exitStatus("Access_Error", "can't access \'$Path\'");
1889 }
1890 }
1891 }
1892 }
1893 foreach my $Path (split(/\s*\n\s*/, parseTag(\$Content, "search_headers")))
1894 {
1895 $Path = clean_path($Path);
1896 if(not -d $Path) {
1897 exitStatus("Access_Error", "can't access directory \'$Path\'");
1898 }
1899 $Path = path_format($Path, $OSgroup);
1900 $SystemPaths{"include"}{$Path}=1;
1901 }
1902 foreach my $Path (split(/\s*\n\s*/, parseTag(\$Content, "search_libs")))
1903 {
1904 $Path = clean_path($Path);
1905 if(not -d $Path) {
1906 exitStatus("Access_Error", "can't access directory \'$Path\'");
1907 }
1908 $Path = path_format($Path, $OSgroup);
1909 $SystemPaths{"lib"}{$Path}=1;
1910 }
1911 foreach my $Path (split(/\s*\n\s*/, parseTag(\$Content, "tools")))
1912 {
1913 $Path=clean_path($Path);
1914 if(not -d $Path) {
1915 exitStatus("Access_Error", "can't access directory \'$Path\'");
1916 }
1917 $Path = path_format($Path, $OSgroup);
1918 $SystemPaths{"bin"}{$Path}=1;
1919 $TargetTools{$Path}=1;
1920 }
1921 if(my $Prefix = parseTag(\$Content, "cross_prefix")) {
1922 $CrossPrefix = $Prefix;
1923 }
1924 foreach my $Path (split(/\s*\n\s*/, parseTag(\$Content, "include_paths")))
1925 {
1926 $Path=clean_path($Path);
1927 if(not -d $Path) {
1928 exitStatus("Access_Error", "can't access directory \'$Path\'");
1929 }
1930 $Path = path_format($Path, $OSgroup);
1931 $Descriptor{$LibVersion}{"IncludePaths"}{$Path} = 1;
1932 }
1933 foreach my $Path (split(/\s*\n\s*/, parseTag(\$Content, "add_include_paths")))
1934 {
1935 $Path=clean_path($Path);
1936 if(not -d $Path) {
1937 exitStatus("Access_Error", "can't access directory \'$Path\'");
1938 }
1939 $Path = path_format($Path, $OSgroup);
1940 $Descriptor{$LibVersion}{"AddIncludePaths"}{$Path} = 1;
1941 }
1942 foreach my $Path (split(/\s*\n\s*/, parseTag(\$Content, "skip_include_paths")))
1943 {
1944 # skip some auto-generated include paths
1945 $Skip_Include_Paths{$LibVersion}{path_format($Path)}=1;
1946 }
1947 foreach my $Path (split(/\s*\n\s*/, parseTag(\$Content, "skip_including")))
1948 {
1949 # skip direct including of some headers
1950 my ($CPath, $Type) = classifyPath($Path);
1951 $SkipHeaders{$LibVersion}{$Type}{$CPath} = 2;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04001952 }
1953 $Descriptor{$LibVersion}{"GccOptions"} = parseTag(\$Content, "gcc_options");
1954 foreach my $Option (split(/\s*\n\s*/, $Descriptor{$LibVersion}{"GccOptions"})) {
1955 $CompilerOptions{$LibVersion} .= " ".$Option;
1956 }
1957 $Descriptor{$LibVersion}{"SkipHeaders"} = parseTag(\$Content, "skip_headers");
1958 foreach my $Path (split(/\s*\n\s*/, $Descriptor{$LibVersion}{"SkipHeaders"}))
1959 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04001960 $SkipHeadersList{$LibVersion}{$Path} = 1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04001961 my ($CPath, $Type) = classifyPath($Path);
1962 $SkipHeaders{$LibVersion}{$Type}{$CPath} = 1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04001963 }
1964 $Descriptor{$LibVersion}{"SkipLibs"} = parseTag(\$Content, "skip_libs");
1965 foreach my $Path (split(/\s*\n\s*/, $Descriptor{$LibVersion}{"SkipLibs"}))
1966 {
1967 my ($CPath, $Type) = classifyPath($Path);
1968 $SkipLibs{$LibVersion}{$Type}{$CPath} = 1;
1969 }
1970 if(my $DDefines = parseTag(\$Content, "defines"))
1971 {
1972 if($Descriptor{$LibVersion}{"Defines"})
1973 { # multiple descriptors
1974 $Descriptor{$LibVersion}{"Defines"} .= "\n".$DDefines;
1975 }
1976 else {
1977 $Descriptor{$LibVersion}{"Defines"} = $DDefines;
1978 }
1979 }
1980 foreach my $Order (split(/\s*\n\s*/, parseTag(\$Content, "include_order")))
1981 {
1982 if($Order=~/\A(.+):(.+)\Z/) {
1983 $Include_Order{$LibVersion}{$1} = $2;
1984 }
1985 }
1986 foreach my $Type_Name (split(/\s*\n\s*/, parseTag(\$Content, "opaque_types")),
1987 split(/\s*\n\s*/, parseTag(\$Content, "skip_types")))
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04001988 { # opaque_types renamed to skip_types (1.23.4)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04001989 $SkipTypes{$LibVersion}{$Type_Name} = 1;
1990 }
1991 foreach my $Symbol (split(/\s*\n\s*/, parseTag(\$Content, "skip_interfaces")),
1992 split(/\s*\n\s*/, parseTag(\$Content, "skip_symbols")))
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04001993 { # skip_interfaces renamed to skip_symbols (1.22.1)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04001994 $SkipSymbols{$LibVersion}{$Symbol} = 1;
1995 }
1996 foreach my $NameSpace (split(/\s*\n\s*/, parseTag(\$Content, "skip_namespaces"))) {
1997 $SkipNameSpaces{$LibVersion}{$NameSpace} = 1;
1998 }
Andrey Ponomarenkoa01311b2012-06-08 17:20:02 +04001999 foreach my $NameSpace (split(/\s*\n\s*/, parseTag(\$Content, "add_namespaces"))) {
2000 $AddNameSpaces{$LibVersion}{$NameSpace} = 1;
2001 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002002 foreach my $Constant (split(/\s*\n\s*/, parseTag(\$Content, "skip_constants"))) {
2003 $SkipConstants{$LibVersion}{$Constant} = 1;
2004 }
2005 if(my $DIncPreamble = parseTag(\$Content, "include_preamble"))
2006 {
2007 if($Descriptor{$LibVersion}{"IncludePreamble"})
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04002008 { # multiple descriptors
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002009 $Descriptor{$LibVersion}{"IncludePreamble"} .= "\n".$DIncPreamble;
2010 }
2011 else {
2012 $Descriptor{$LibVersion}{"IncludePreamble"} = $DIncPreamble;
2013 }
2014 }
2015}
2016
Andrey Ponomarenko01117f12012-06-26 12:23:02 +04002017sub parseTag(@)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002018{
Andrey Ponomarenko01117f12012-06-26 12:23:02 +04002019 my $CodeRef = shift(@_);
2020 my $Tag = shift(@_);
2021 if(not $Tag or not $CodeRef) {
2022 return undef;
2023 }
2024 my $Sp = 0;
2025 if(@_) {
2026 $Sp = shift(@_);
2027 }
2028 my $Start = index(${$CodeRef}, "<$Tag>");
2029 if($Start!=-1)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002030 {
Andrey Ponomarenko01117f12012-06-26 12:23:02 +04002031 my $End = index(${$CodeRef}, "</$Tag>");
2032 if($End!=-1)
2033 {
2034 my $TS = length($Tag)+3;
2035 my $Content = substr(${$CodeRef}, $Start, $End-$Start+$TS, "");
2036 substr($Content, 0, $TS-1, ""); # cut start tag
2037 substr($Content, -$TS, $TS, ""); # cut end tag
2038 if(not $Sp)
2039 {
2040 $Content=~s/\A\s+//g;
2041 $Content=~s/\s+\Z//g;
2042 }
2043 if(substr($Content, 0, 1) ne "<") {
2044 $Content = xmlSpecChars_R($Content);
2045 }
2046 return $Content;
2047 }
2048 }
2049 return undef;
2050}
2051
2052sub parseTag_E($$$)
2053{
2054 my ($CodeRef, $Tag, $Info) = @_;
2055 if(not $Tag or not $CodeRef
2056 or not $Info) {
2057 return undef;
2058 }
2059 if(${$CodeRef}=~s/\<\Q$Tag\E(\s+([^<>]+)|)\>((.|\n)*?)\<\/\Q$Tag\E\>//)
2060 {
2061 my ($Ext, $Content) = ($2, $3);
2062 $Content=~s/\A\s+//g;
2063 $Content=~s/\s+\Z//g;
2064 if($Ext)
2065 {
2066 while($Ext=~s/(\w+)\=\"([^\"]*)\"//)
2067 {
2068 my ($K, $V) = ($1, $2);
2069 $Info->{$K} = xmlSpecChars_R($V);
2070 }
2071 }
2072 if(substr($Content, 0, 1) ne "<") {
2073 $Content = xmlSpecChars_R($Content);
2074 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002075 return $Content;
2076 }
Andrey Ponomarenko01117f12012-06-26 12:23:02 +04002077 return undef;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002078}
2079
Andrey Ponomarenko35c44fd2012-06-18 17:50:25 +04002080sub addTag(@)
Andrey Ponomarenko5c09ef32012-06-14 18:17:33 +04002081{
Andrey Ponomarenko35c44fd2012-06-18 17:50:25 +04002082 my $Tag = shift(@_);
2083 my $Val = shift(@_);
2084 my @Ext = @_;
2085 my $Content = openTag($Tag, @Ext);
2086 chomp($Content);
Andrey Ponomarenko5c09ef32012-06-14 18:17:33 +04002087 $Content .= xmlSpecChars($Val);
2088 $Content .= "</$Tag>\n";
Andrey Ponomarenko35c44fd2012-06-18 17:50:25 +04002089 $TAG_ID-=1;
Andrey Ponomarenko5c09ef32012-06-14 18:17:33 +04002090
2091 return $Content;
2092}
2093
Andrey Ponomarenko35c44fd2012-06-18 17:50:25 +04002094sub openTag(@)
Andrey Ponomarenko5c09ef32012-06-14 18:17:33 +04002095{
2096 my $Tag = shift(@_);
2097 my @Ext = @_;
2098 my $Content = "";
2099 foreach (1 .. $TAG_ID) {
2100 $Content .= $INDENT;
2101 }
2102 $TAG_ID+=1;
Andrey Ponomarenko35c44fd2012-06-18 17:50:25 +04002103 if(@Ext)
Andrey Ponomarenko5c09ef32012-06-14 18:17:33 +04002104 {
Andrey Ponomarenko35c44fd2012-06-18 17:50:25 +04002105 $Content .= "<".$Tag;
2106 my $P = 0;
2107 while($P<=$#Ext-1)
2108 {
2109 $Content .= " ".$Ext[$P];
2110 $Content .= "=\"".xmlSpecChars($Ext[$P+1])."\"";
2111 $P+=2;
2112 }
2113 $Content .= ">\n";
Andrey Ponomarenko5c09ef32012-06-14 18:17:33 +04002114 }
Andrey Ponomarenko35c44fd2012-06-18 17:50:25 +04002115 else {
2116 $Content .= "<".$Tag.">\n";
2117 }
Andrey Ponomarenko5c09ef32012-06-14 18:17:33 +04002118 return $Content;
2119}
2120
2121sub closeTag($)
2122{
2123 my $Tag = $_[0];
2124 my $Content = "";
2125 $TAG_ID-=1;
2126 foreach (1 .. $TAG_ID) {
2127 $Content .= $INDENT;
2128 }
2129 $Content .= "</".$Tag.">\n";
2130 return $Content;
2131}
2132
2133sub checkTags()
2134{
2135 if($TAG_ID!=0) {
2136 printMsg("WARNING", "the number of opened tags is not equal to number of closed tags");
2137 }
2138}
2139
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002140sub getInfo($)
2141{
Andrey Ponomarenko85043792012-05-14 16:48:07 +04002142 my $DumpPath = $_[0];
2143 return if(not $DumpPath or not -f $DumpPath);
2144
2145 readTUDump($DumpPath);
2146
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002147 # processing info
2148 setTemplateParams_All();
2149 getTypeInfo_All();
2150 simplifyNames();
Andrey Ponomarenko82bc2572012-11-14 13:55:30 +04002151 simplifyConstants();
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002152 getVarInfo_All();
Andrey Ponomarenko01117f12012-06-26 12:23:02 +04002153 getSymbolInfo_All();
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002154
Andrey Ponomarenko82bc2572012-11-14 13:55:30 +04002155
Andrey Ponomarenko85043792012-05-14 16:48:07 +04002156 # clean memory
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002157 %LibInfo = ();
2158 %TemplateInstance = ();
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002159 %MangledNames = ();
Andrey Ponomarenko85043792012-05-14 16:48:07 +04002160 %TemplateDecl = ();
2161 %StdCxxTypedef = ();
2162 %MissedTypedef = ();
2163 %Typedef_Tr = ();
2164 %Typedef_Eq = ();
2165
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04002166 # clean cache
2167 delete($Cache{"getTypeAttr"});
2168 delete($Cache{"getTypeDeclId"});
2169
2170 # remove unused types
2171 if($BinaryOnly and not $ExtendedCheck)
2172 { # --binary
2173 removeUnused($Version, "All");
2174 }
2175 else {
2176 removeUnused($Version, "Derived");
2177 }
2178
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002179 if($Debug) {
2180 # debugMangling($Version);
2181 }
2182}
2183
Andrey Ponomarenko85043792012-05-14 16:48:07 +04002184sub readTUDump($)
2185{
2186 my $DumpPath = $_[0];
2187
2188 open(TU_DUMP, $DumpPath);
2189 local $/ = undef;
2190 my $Content = <TU_DUMP>;
2191 close(TU_DUMP);
2192
2193 unlink($DumpPath);
2194
2195 $Content=~s/\n[ ]+/ /g;
2196 my @Lines = split("\n", $Content);
2197
2198 # clean memory
2199 undef $Content;
2200
2201 $MAX_ID = $#Lines+1;
2202
2203 foreach (0 .. $#Lines)
2204 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04002205 if($Lines[$_]=~/\A\@(\d+)[ ]+([a-z_]+)[ ]+(.+)\Z/i)
Andrey Ponomarenko85043792012-05-14 16:48:07 +04002206 { # get a number and attributes of a node
2207 next if(not $NodeType{$2});
2208 $LibInfo{$Version}{"info_type"}{$1}=$2;
2209 $LibInfo{$Version}{"info"}{$1}=$3;
2210 }
2211
2212 # clean memory
2213 delete($Lines[$_]);
2214 }
2215
2216 # clean memory
2217 undef @Lines;
2218}
2219
Andrey Ponomarenko82bc2572012-11-14 13:55:30 +04002220sub simplifyConstants()
2221{
2222 foreach my $Constant (keys(%{$Constants{$Version}}))
2223 {
Andrey Ponomarenko2956b972012-11-14 19:16:16 +04002224 my $Value = $Constants{$Version}{$Constant}{"Value"};
2225 if(defined $EnumConstants{$Version}{$Value}) {
2226 $Constants{$Version}{$Constant}{"Value"} = $EnumConstants{$Version}{$Constant}{"Value"};
Andrey Ponomarenko82bc2572012-11-14 13:55:30 +04002227 }
2228 }
2229}
2230
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002231sub simplifyNames()
2232{
2233 foreach my $Base (keys(%{$Typedef_Tr{$Version}}))
2234 {
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +04002235 if($Typedef_Eq{$Version}{$Base}) {
2236 next;
2237 }
2238 my @Translations = sort keys(%{$Typedef_Tr{$Version}{$Base}});
2239 if($#Translations==0)
2240 {
2241 if(length($Translations[0])<=length($Base)) {
2242 $Typedef_Eq{$Version}{$Base} = $Translations[0];
2243 }
2244 }
2245 else
2246 { # select most appropriate
2247 foreach my $Tr (@Translations)
2248 {
2249 if($Base=~/\A\Q$Tr\E/)
2250 {
2251 $Typedef_Eq{$Version}{$Base} = $Tr;
2252 last;
2253 }
2254 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002255 }
2256 }
Andrey Ponomarenkob8d203d2012-05-25 18:11:07 +04002257 foreach my $TypeId (keys(%{$TypeInfo{$Version}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002258 {
Andrey Ponomarenkob8d203d2012-05-25 18:11:07 +04002259 my $TypeName = $TypeInfo{$Version}{$TypeId}{"Name"};
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04002260 if(not $TypeName) {
2261 next;
2262 }
2263 next if(index($TypeName,"<")==-1);# template instances only
2264 if($TypeName=~/>(::\w+)+\Z/)
2265 { # skip unused types
2266 next;
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +04002267 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04002268 foreach my $Base (sort {length($b)<=>length($a)}
2269 sort {$b cmp $a} keys(%{$Typedef_Eq{$Version}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002270 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04002271 next if(not $Base);
2272 next if(index($TypeName,$Base)==-1);
2273 next if(length($TypeName) - length($Base) <= 3);
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +04002274 if(my $Typedef = $Typedef_Eq{$Version}{$Base})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002275 {
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +04002276 $TypeName=~s/(\<|\,)\Q$Base\E(\W|\Z)/$1$Typedef$2/g;
2277 $TypeName=~s/(\<|\,)\Q$Base\E(\w|\Z)/$1$Typedef $2/g;
2278 if(defined $TypeInfo{$Version}{$TypeId}{"TParam"})
Andrey Ponomarenko85043792012-05-14 16:48:07 +04002279 {
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +04002280 foreach my $TPos (keys(%{$TypeInfo{$Version}{$TypeId}{"TParam"}}))
2281 {
2282 if(my $TPName = $TypeInfo{$Version}{$TypeId}{"TParam"}{$TPos}{"name"})
2283 {
2284 $TPName=~s/\A\Q$Base\E(\W|\Z)/$Typedef$1/g;
2285 $TPName=~s/\A\Q$Base\E(\w|\Z)/$Typedef $1/g;
Andrey Ponomarenko9927e332012-10-19 10:50:48 +04002286 $TypeInfo{$Version}{$TypeId}{"TParam"}{$TPos}{"name"} = formatName($TPName, "T");
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +04002287 }
2288 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +04002289 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002290 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002291 }
Andrey Ponomarenko9927e332012-10-19 10:50:48 +04002292 $TypeName = formatName($TypeName, "T");
Andrey Ponomarenkob8d203d2012-05-25 18:11:07 +04002293 $TypeInfo{$Version}{$TypeId}{"Name"} = $TypeName;
2294 $TName_Tid{$Version}{$TypeName} = $TypeId;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002295 }
2296}
2297
2298sub setTemplateParams_All()
2299{
2300 foreach (keys(%{$LibInfo{$Version}{"info"}}))
2301 {
2302 if($LibInfo{$Version}{"info_type"}{$_} eq "template_decl") {
2303 setTemplateParams($_);
2304 }
2305 }
2306}
2307
2308sub setTemplateParams($)
2309{
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04002310 if(my $Info = $LibInfo{$Version}{"info"}{$_[0]})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002311 {
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04002312 if($Info=~/(inst|spcs)[ ]*:[ ]*@(\d+) /)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002313 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04002314 my $TmplInst_Id = $2;
2315 setTemplateInstParams($TmplInst_Id);
2316 while($TmplInst_Id = getNextElem($TmplInst_Id)) {
2317 setTemplateInstParams($TmplInst_Id);
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04002318 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002319 }
2320 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04002321 if(my $TypeId = getTreeAttr_Type($_[0]))
Andrey Ponomarenko85043792012-05-14 16:48:07 +04002322 {
2323 if(my $IType = $LibInfo{$Version}{"info_type"}{$TypeId})
2324 {
2325 if($IType eq "record_type") {
2326 $TemplateDecl{$Version}{$TypeId}=1;
2327 }
2328 }
2329 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002330}
2331
2332sub setTemplateInstParams($)
2333{
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04002334 if(my $Info = $LibInfo{$Version}{"info"}{$_[0]})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002335 {
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04002336 my ($Params_InfoId, $ElemId) = ();
2337 if($Info=~/purp[ ]*:[ ]*@(\d+) /) {
2338 $Params_InfoId = $1;
2339 }
2340 if($Info=~/valu[ ]*:[ ]*@(\d+) /) {
2341 $ElemId = $1;
2342 }
2343 if($Params_InfoId and $ElemId)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002344 {
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04002345 my $Params_Info = $LibInfo{$Version}{"info"}{$Params_InfoId};
2346 while($Params_Info=~s/ (\d+)[ ]*:[ ]*\@(\d+) / /)
2347 {
2348 my ($PPos, $PTypeId) = ($1, $2);
2349 if(my $PType = $LibInfo{$Version}{"info_type"}{$PTypeId})
2350 {
Andrey Ponomarenko85043792012-05-14 16:48:07 +04002351 if($PType eq "template_type_parm")
2352 {
2353 $TemplateDecl{$Version}{$ElemId}=1;
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04002354 return;
2355 }
2356 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +04002357 if($LibInfo{$Version}{"info_type"}{$ElemId} eq "function_decl")
2358 { # functions
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04002359 $TemplateInstance{$Version}{"Func"}{$ElemId}{$PPos} = $PTypeId;
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04002360 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +04002361 else
2362 { # types
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04002363 $TemplateInstance{$Version}{"Type"}{$ElemId}{$PPos} = $PTypeId;
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04002364 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002365 }
2366 }
2367 }
2368}
2369
2370sub getTypeDeclId($)
2371{
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04002372 if($_[0])
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04002373 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04002374 if(defined $Cache{"getTypeDeclId"}{$Version}{$_[0]}) {
2375 return $Cache{"getTypeDeclId"}{$Version}{$_[0]};
2376 }
2377 if(my $Info = $LibInfo{$Version}{"info"}{$_[0]})
2378 {
2379 if($Info=~/name[ ]*:[ ]*@(\d+)/) {
2380 return ($Cache{"getTypeDeclId"}{$Version}{$_[0]} = $1);
2381 }
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04002382 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002383 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04002384 return ($Cache{"getTypeDeclId"}{$Version}{$_[0]} = 0);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002385}
2386
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002387sub getTypeInfo_All()
2388{
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04002389 if(not check_gcc($GCC_PATH, "4.5"))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002390 { # support for GCC < 4.5
2391 # missed typedefs: QStyle::State is typedef to QFlags<QStyle::StateFlag>
2392 # but QStyleOption.state is of type QFlags<QStyle::StateFlag> in the TU dump
2393 # FIXME: check GCC versions
2394 addMissedTypes_Pre();
2395 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04002396
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002397 foreach (sort {int($a)<=>int($b)} keys(%{$LibInfo{$Version}{"info"}}))
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04002398 { # forward order only
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002399 my $IType = $LibInfo{$Version}{"info_type"}{$_};
2400 if($IType=~/_type\Z/ and $IType ne "function_type"
2401 and $IType ne "method_type") {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04002402 getTypeInfo("$_");
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002403 }
2404 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04002405
2406 # add "..." type
Andrey Ponomarenko01117f12012-06-26 12:23:02 +04002407 $TypeInfo{$Version}{"-1"} = {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04002408 "Name" => "...",
2409 "Type" => "Intrinsic",
Andrey Ponomarenko01117f12012-06-26 12:23:02 +04002410 "Tid" => "-1"
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04002411 };
Andrey Ponomarenko01117f12012-06-26 12:23:02 +04002412 $TName_Tid{$Version}{"..."} = "-1";
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04002413
2414 if(not check_gcc($GCC_PATH, "4.5"))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002415 { # support for GCC < 4.5
2416 addMissedTypes_Post();
2417 }
2418}
2419
2420sub addMissedTypes_Pre()
2421{
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04002422 my %MissedTypes = ();
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002423 foreach my $MissedTDid (sort {int($a)<=>int($b)} keys(%{$LibInfo{$Version}{"info"}}))
2424 { # detecting missed typedefs
2425 if($LibInfo{$Version}{"info_type"}{$MissedTDid} eq "type_decl")
2426 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04002427 my $TypeId = getTreeAttr_Type($MissedTDid);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002428 next if(not $TypeId);
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04002429 my $TypeType = getTypeType($TypeId);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002430 if($TypeType eq "Unknown")
2431 { # template_type_parm
2432 next;
2433 }
2434 my $TypeDeclId = getTypeDeclId($TypeId);
2435 next if($TypeDeclId eq $MissedTDid);#or not $TypeDeclId
2436 my $TypedefName = getNameByInfo($MissedTDid);
2437 next if(not $TypedefName);
2438 next if($TypedefName eq "__float80");
2439 next if(isAnon($TypedefName));
2440 if(not $TypeDeclId
2441 or getNameByInfo($TypeDeclId) ne $TypedefName) {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04002442 $MissedTypes{$Version}{$TypeId}{$MissedTDid} = 1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002443 }
2444 }
2445 }
Andrey Ponomarenkob8d203d2012-05-25 18:11:07 +04002446 my %AddTypes = ();
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04002447 foreach my $Tid (keys(%{$MissedTypes{$Version}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002448 { # add missed typedefs
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04002449 my @Missed = keys(%{$MissedTypes{$Version}{$Tid}});
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002450 if(not @Missed or $#Missed>=1) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002451 next;
2452 }
2453 my $MissedTDid = $Missed[0];
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002454 my ($TypedefName, $TypedefNS) = getTrivialName($MissedTDid, $Tid);
Andrey Ponomarenkob8d203d2012-05-25 18:11:07 +04002455 if(not $TypedefName) {
2456 next;
2457 }
2458 $MAX_ID++;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002459 my %MissedInfo = ( # typedef info
2460 "Name" => $TypedefName,
2461 "NameSpace" => $TypedefNS,
2462 "BaseType" => {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002463 "Tid" => $Tid
2464 },
2465 "Type" => "Typedef",
Andrey Ponomarenkob8d203d2012-05-25 18:11:07 +04002466 "Tid" => "$MAX_ID" );
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002467 my ($H, $L) = getLocation($MissedTDid);
2468 $MissedInfo{"Header"} = $H;
2469 $MissedInfo{"Line"} = $L;
Andrey Ponomarenkob8d203d2012-05-25 18:11:07 +04002470 if($TypedefName=~/\*|\&|\s/)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002471 { # other types
2472 next;
2473 }
Andrey Ponomarenkob8d203d2012-05-25 18:11:07 +04002474 if($TypedefName=~/>(::\w+)+\Z/)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002475 { # QFlags<Qt::DropAction>::enum_type
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002476 next;
2477 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04002478 if(getTypeType($Tid)=~/\A(Intrinsic|Union|Struct|Enum|Class)\Z/)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002479 { # double-check for the name of typedef
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04002480 my ($TName, $TNS) = getTrivialName(getTypeDeclId($Tid), $Tid); # base type info
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002481 next if(not $TName);
Andrey Ponomarenkob8d203d2012-05-25 18:11:07 +04002482 if(length($TypedefName)>=length($TName))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002483 { # too long typedef
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002484 next;
2485 }
Andrey Ponomarenkob8d203d2012-05-25 18:11:07 +04002486 if($TName=~/\A\Q$TypedefName\E</) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002487 next;
2488 }
Andrey Ponomarenkob8d203d2012-05-25 18:11:07 +04002489 if($TypedefName=~/\A\Q$TName\E/)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002490 { # QDateTimeEdit::Section and QDateTimeEdit::Sections::enum_type
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002491 next;
2492 }
Andrey Ponomarenkob8d203d2012-05-25 18:11:07 +04002493 if(get_depth($TypedefName)==0 and get_depth($TName)!=0)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002494 { # std::_Vector_base and std::vector::_Base
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002495 next;
2496 }
2497 }
Andrey Ponomarenkob8d203d2012-05-25 18:11:07 +04002498
2499 $AddTypes{$MissedInfo{"Tid"}} = \%MissedInfo;
2500
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002501 # register typedef
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002502 $MissedTypedef{$Version}{$Tid}{"Tid"} = $MissedInfo{"Tid"};
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04002503 $MissedTypedef{$Version}{$Tid}{"TDid"} = $MissedTDid;
Andrey Ponomarenkob8d203d2012-05-25 18:11:07 +04002504 $TName_Tid{$Version}{$TypedefName} = $MissedInfo{"Tid"};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002505 }
Andrey Ponomarenkob8d203d2012-05-25 18:11:07 +04002506
2507 # add missed & remove other
2508 $TypeInfo{$Version} = \%AddTypes;
2509 delete($Cache{"getTypeAttr"}{$Version});
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002510}
2511
2512sub addMissedTypes_Post()
2513{
2514 foreach my $BaseId (keys(%{$MissedTypedef{$Version}}))
2515 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04002516 if(my $Tid = $MissedTypedef{$Version}{$BaseId}{"Tid"})
2517 {
2518 $TypeInfo{$Version}{$Tid}{"Size"} = $TypeInfo{$Version}{$BaseId}{"Size"};
2519 if(my $TName = $TypeInfo{$Version}{$Tid}{"Name"}) {
2520 $Typedef_BaseName{$Version}{$TName} = $TypeInfo{$Version}{$BaseId}{"Name"};
2521 }
2522 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002523 }
2524}
2525
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04002526sub getTypeInfo($)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002527{
Andrey Ponomarenkob8d203d2012-05-25 18:11:07 +04002528 my $TypeId = $_[0];
2529 %{$TypeInfo{$Version}{$TypeId}} = getTypeAttr($TypeId);
2530 my $TName = $TypeInfo{$Version}{$TypeId}{"Name"};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002531 if(not $TName) {
Andrey Ponomarenkob8d203d2012-05-25 18:11:07 +04002532 delete($TypeInfo{$Version}{$TypeId});
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002533 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002534}
2535
2536sub getArraySize($$)
2537{
2538 my ($TypeId, $BaseName) = @_;
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04002539 if(my $Size = getSize($TypeId))
2540 {
2541 my $Elems = $Size/$BYTE_SIZE;
2542 while($BaseName=~s/\s*\[(\d+)\]//) {
2543 $Elems/=$1;
2544 }
2545 if(my $BasicId = $TName_Tid{$Version}{$BaseName})
2546 {
2547 if(my $BasicSize = $TypeInfo{$Version}{$BasicId}{"Size"}) {
2548 $Elems/=$BasicSize;
2549 }
2550 }
2551 return $Elems;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002552 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04002553 return 0;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002554}
2555
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04002556sub getTParams($$)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002557{
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04002558 my ($TypeId, $Kind) = @_;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002559 my @TmplParams = ();
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04002560 my @Positions = sort {int($a)<=>int($b)} keys(%{$TemplateInstance{$Version}{$Kind}{$TypeId}});
2561 foreach my $Pos (@Positions)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002562 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04002563 my $Param_TypeId = $TemplateInstance{$Version}{$Kind}{$TypeId}{$Pos};
2564 my $NodeType = $LibInfo{$Version}{"info_type"}{$Param_TypeId};
2565 if(not $NodeType)
2566 { # typename_type
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002567 return ();
2568 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04002569 if($NodeType eq "tree_vec")
2570 {
2571 if($Pos!=$#Positions)
2572 { # select last vector of parameters ( ns<P1>::type<P2> )
2573 next;
2574 }
2575 }
2576 my @Params = get_TemplateParam($Pos, $Param_TypeId);
2577 foreach my $P (@Params)
2578 {
2579 if($P eq "") {
2580 return ();
2581 }
2582 elsif($P ne "\@skip\@") {
2583 @TmplParams = (@TmplParams, $P);
2584 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002585 }
2586 }
2587 return @TmplParams;
2588}
2589
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04002590sub getTypeAttr($)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002591{
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04002592 my $TypeId = $_[0];
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04002593 my %TypeAttr = ();
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04002594 if(defined $TypeInfo{$Version}{$TypeId}
2595 and $TypeInfo{$Version}{$TypeId}{"Name"})
2596 { # already created
2597 return %{$TypeInfo{$Version}{$TypeId}};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002598 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04002599 elsif($Cache{"getTypeAttr"}{$Version}{$TypeId})
2600 { # incomplete type
2601 return ();
2602 }
2603 $Cache{"getTypeAttr"}{$Version}{$TypeId} = 1;
2604
2605 my $TypeDeclId = getTypeDeclId($TypeId);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002606 $TypeAttr{"Tid"} = $TypeId;
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04002607
2608 if(not $MissedBase{$Version}{$TypeId} and isTypedef($TypeId))
2609 {
2610 if(my $Info = $LibInfo{$Version}{"info"}{$TypeId})
2611 {
2612 if($Info=~/qual[ ]*:/)
2613 {
2614 if(my $NID = ++$MAX_ID)
2615 {
2616 $MissedBase{$Version}{$TypeId}="$NID";
2617 $MissedBase_R{$Version}{$NID}=$TypeId;
2618 $LibInfo{$Version}{"info"}{$NID} = $LibInfo{$Version}{"info"}{$TypeId};
2619 $LibInfo{$Version}{"info_type"}{$NID} = $LibInfo{$Version}{"info_type"}{$TypeId};
2620 }
2621 }
2622 }
2623 $TypeAttr{"Type"} = "Typedef";
2624 }
2625 else {
2626 $TypeAttr{"Type"} = getTypeType($TypeId);
2627 }
2628
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002629 if($TypeAttr{"Type"} eq "Unknown") {
2630 return ();
2631 }
2632 elsif($TypeAttr{"Type"}=~/(Func|Method|Field)Ptr/)
2633 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04002634 %TypeAttr = getMemPtrAttr(pointTo($TypeId), $TypeId, $TypeAttr{"Type"});
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04002635 if(my $TName = $TypeAttr{"Name"})
2636 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04002637 %{$TypeInfo{$Version}{$TypeId}} = %TypeAttr;
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04002638 $TName_Tid{$Version}{$TName} = $TypeId;
2639 return %TypeAttr;
2640 }
2641 else {
2642 return ();
2643 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002644 }
2645 elsif($TypeAttr{"Type"} eq "Array")
2646 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04002647 my ($BTid, $BTSpec) = selectBaseType($TypeId);
2648 if(not $BTid) {
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04002649 return ();
2650 }
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +04002651 if(my $Algn = getAlgn($TypeId)) {
2652 $TypeAttr{"Algn"} = $Algn/$BYTE_SIZE;
2653 }
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04002654 $TypeAttr{"BaseType"}{"Tid"} = $BTid;
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04002655 if(my %BTAttr = getTypeAttr($BTid))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002656 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04002657 if(not $BTAttr{"Name"}) {
2658 return ();
2659 }
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04002660 if(my $NElems = getArraySize($TypeId, $BTAttr{"Name"}))
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04002661 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04002662 if(my $Size = getSize($TypeId)) {
2663 $TypeAttr{"Size"} = $Size/$BYTE_SIZE;
2664 }
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04002665 if($BTAttr{"Name"}=~/\A([^\[\]]+)(\[(\d+|)\].*)\Z/) {
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04002666 $TypeAttr{"Name"} = $1."[$NElems]".$2;
2667 }
2668 else {
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04002669 $TypeAttr{"Name"} = $BTAttr{"Name"}."[$NElems]";
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04002670 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002671 }
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04002672 else
2673 {
2674 $TypeAttr{"Size"} = $WORD_SIZE{$Version}; # pointer
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04002675 if($BTAttr{"Name"}=~/\A([^\[\]]+)(\[(\d+|)\].*)\Z/) {
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04002676 $TypeAttr{"Name"} = $1."[]".$2;
2677 }
2678 else {
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04002679 $TypeAttr{"Name"} = $BTAttr{"Name"}."[]";
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04002680 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002681 }
Andrey Ponomarenko9927e332012-10-19 10:50:48 +04002682 $TypeAttr{"Name"} = formatName($TypeAttr{"Name"}, "T");
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04002683 if($BTAttr{"Header"}) {
2684 $TypeAttr{"Header"} = $BTAttr{"Header"};
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04002685 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04002686 %{$TypeInfo{$Version}{$TypeId}} = %TypeAttr;
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04002687 $TName_Tid{$Version}{$TypeAttr{"Name"}} = $TypeId;
2688 return %TypeAttr;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002689 }
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04002690 return ();
2691 }
2692 elsif($TypeAttr{"Type"}=~/\A(Intrinsic|Union|Struct|Enum|Class)\Z/)
2693 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04002694 %TypeAttr = getTrivialTypeAttr($TypeId);
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04002695 if($TypeAttr{"Name"})
2696 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04002697 %{$TypeInfo{$Version}{$TypeId}} = %TypeAttr;
2698 if($TypeAttr{"Name"} ne "int" or getTypeDeclId($TypeAttr{"Tid"}))
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04002699 { # NOTE: register only one int: with built-in decl
2700 if(not $TName_Tid{$Version}{$TypeAttr{"Name"}}) {
2701 $TName_Tid{$Version}{$TypeAttr{"Name"}} = $TypeId;
2702 }
2703 }
2704 return %TypeAttr;
2705 }
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04002706 else {
2707 return ();
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002708 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002709 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002710 else
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04002711 { # derived types
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04002712 my ($BTid, $BTSpec) = selectBaseType($TypeId);
2713 if(not $BTid) {
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04002714 return ();
2715 }
2716 $TypeAttr{"BaseType"}{"Tid"} = $BTid;
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04002717 if(defined $MissedTypedef{$Version}{$BTid})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002718 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04002719 if(my $MissedTDid = $MissedTypedef{$Version}{$BTid}{"TDid"})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002720 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04002721 if($MissedTDid ne $TypeDeclId) {
2722 $TypeAttr{"BaseType"}{"Tid"} = $MissedTypedef{$Version}{$BTid}{"Tid"};
2723 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002724 }
2725 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04002726 my %BTAttr = getTypeAttr($TypeAttr{"BaseType"}{"Tid"});
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04002727 if(not $BTAttr{"Name"})
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04002728 { # templates
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002729 return ();
2730 }
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04002731 if($BTAttr{"Type"} eq "Typedef")
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002732 { # relinking typedefs
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04002733 my %BaseBase = get_Type($BTAttr{"BaseType"}{"Tid"}, $Version);
2734 if($BTAttr{"Name"} eq $BaseBase{"Name"}) {
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04002735 $TypeAttr{"BaseType"}{"Tid"} = $BaseBase{"Tid"};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002736 }
2737 }
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04002738 if($BTSpec)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002739 {
2740 if($TypeAttr{"Type"} eq "Pointer"
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04002741 and $BTAttr{"Name"}=~/\([\*]+\)/)
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04002742 {
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04002743 $TypeAttr{"Name"} = $BTAttr{"Name"};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002744 $TypeAttr{"Name"}=~s/\(([*]+)\)/($1*)/g;
2745 }
2746 else {
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04002747 $TypeAttr{"Name"} = $BTAttr{"Name"}." ".$BTSpec;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002748 }
2749 }
2750 else {
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04002751 $TypeAttr{"Name"} = $BTAttr{"Name"};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002752 }
2753 if($TypeAttr{"Type"} eq "Typedef")
2754 {
2755 $TypeAttr{"Name"} = getNameByInfo($TypeDeclId);
Andrey Ponomarenko85043792012-05-14 16:48:07 +04002756 if(isAnon($TypeAttr{"Name"}))
2757 { # anon typedef to anon type: ._N
2758 return ();
2759 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002760 if(my $NS = getNameSpace($TypeDeclId))
2761 {
2762 my $TypeName = $TypeAttr{"Name"};
2763 if($NS=~/\A(struct |union |class |)((.+)::|)\Q$TypeName\E\Z/)
2764 { # "some_type" is the typedef to "struct some_type" in C++
2765 if($3) {
2766 $TypeAttr{"Name"} = $3."::".$TypeName;
2767 }
2768 }
2769 else
2770 {
2771 $TypeAttr{"NameSpace"} = $NS;
2772 $TypeAttr{"Name"} = $TypeAttr{"NameSpace"}."::".$TypeAttr{"Name"};
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04002773
2774 if($TypeAttr{"NameSpace"}=~/\Astd(::|\Z)/
2775 and $TypeAttr{"Name"}!~/>(::\w+)+\Z/)
2776 {
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04002777 if($BTAttr{"NameSpace"}
2778 and $BTAttr{"NameSpace"}=~/\Astd(::|\Z)/ and $BTAttr{"Name"}=~/</)
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04002779 { # types like "std::fpos<__mbstate_t>" are
2780 # not covered by typedefs in the TU dump
2781 # so trying to add such typedefs manually
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04002782 $StdCxxTypedef{$Version}{$BTAttr{"Name"}}{$TypeAttr{"Name"}} = 1;
2783 if(length($TypeAttr{"Name"})<=length($BTAttr{"Name"}))
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04002784 {
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04002785 if(($BTAttr{"Name"}!~/\A(std|boost)::/ or $TypeAttr{"Name"}!~/\A[a-z]+\Z/))
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04002786 { # skip "other" in "std" and "type" in "boost"
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04002787 $Typedef_Eq{$Version}{$BTAttr{"Name"}} = $TypeAttr{"Name"};
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04002788 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002789 }
2790 }
2791 }
2792 }
2793 }
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04002794 if($TypeAttr{"Name"} ne $BTAttr{"Name"}
2795 and $TypeAttr{"Name"}!~/>(::\w+)+\Z/ and $BTAttr{"Name"}!~/>(::\w+)+\Z/)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002796 {
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04002797 if(not defined $Typedef_BaseName{$Version}{$TypeAttr{"Name"}})
2798 { # typedef int*const TYPEDEF; // first
2799 # int foo(TYPEDEF p); // const is optimized out
2800 $Typedef_BaseName{$Version}{$TypeAttr{"Name"}} = $BTAttr{"Name"};
2801 if($BTAttr{"Name"}=~/</)
2802 {
2803 if(($BTAttr{"Name"}!~/\A(std|boost)::/ or $TypeAttr{"Name"}!~/\A[a-z]+\Z/)) {
2804 $Typedef_Tr{$Version}{$BTAttr{"Name"}}{$TypeAttr{"Name"}} = 1;
2805 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002806 }
2807 }
2808 }
2809 ($TypeAttr{"Header"}, $TypeAttr{"Line"}) = getLocation($TypeDeclId);
2810 }
2811 if(not $TypeAttr{"Size"})
2812 {
2813 if($TypeAttr{"Type"} eq "Pointer") {
2814 $TypeAttr{"Size"} = $WORD_SIZE{$Version};
2815 }
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04002816 elsif($BTAttr{"Size"}) {
2817 $TypeAttr{"Size"} = $BTAttr{"Size"};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002818 }
2819 }
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +04002820 if(my $Algn = getAlgn($TypeId)) {
2821 $TypeAttr{"Algn"} = $Algn/$BYTE_SIZE;
2822 }
Andrey Ponomarenko9927e332012-10-19 10:50:48 +04002823 $TypeAttr{"Name"} = formatName($TypeAttr{"Name"}, "T");
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04002824 if(not $TypeAttr{"Header"} and $BTAttr{"Header"}) {
2825 $TypeAttr{"Header"} = $BTAttr{"Header"};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002826 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04002827 %{$TypeInfo{$Version}{$TypeId}} = %TypeAttr;
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04002828 if($TypeAttr{"Name"} ne $BTAttr{"Name"})
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04002829 { # typedef to "class Class"
2830 # should not be registered in TName_Tid
2831 if(not $TName_Tid{$Version}{$TypeAttr{"Name"}}) {
2832 $TName_Tid{$Version}{$TypeAttr{"Name"}} = $TypeId;
2833 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002834 }
2835 return %TypeAttr;
2836 }
2837}
2838
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04002839sub getTreeVec($)
2840{
2841 my %Vector = ();
2842 if($_[0] and my $Info = $LibInfo{$Version}{"info"}{$_[0]})
2843 {
2844 while($Info=~s/ (\d+)[ ]*:[ ]*\@(\d+) / /)
2845 { # string length is N-1 because of the null terminator
2846 $Vector{$1} = $2;
2847 }
2848 }
2849 return \%Vector;
2850}
2851
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002852sub get_TemplateParam($$)
2853{
2854 my ($Pos, $Type_Id) = @_;
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04002855 return () if(not $Type_Id);
2856 my $NodeType = $LibInfo{$Version}{"info_type"}{$Type_Id};
2857 return () if(not $NodeType);
2858 if($NodeType eq "integer_cst")
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002859 { # int (1), unsigned (2u), char ('c' as 99), ...
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04002860 my $CstTid = getTreeAttr_Type($Type_Id);
Andrey Ponomarenkob8d203d2012-05-25 18:11:07 +04002861 my %CstType = getTypeAttr($CstTid); # without recursion
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002862 my $Num = getNodeIntCst($Type_Id);
2863 if(my $CstSuffix = $ConstantSuffix{$CstType{"Name"}}) {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04002864 return ($Num.$CstSuffix);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002865 }
2866 else {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04002867 return ("(".$CstType{"Name"}.")".$Num);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002868 }
2869 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04002870 elsif($NodeType eq "string_cst") {
2871 return (getNodeStrCst($Type_Id));
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002872 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04002873 elsif($NodeType eq "tree_vec")
2874 {
2875 my $Vector = getTreeVec($Type_Id);
2876 my @Params = ();
2877 foreach my $P1 (sort {int($a)<=>int($b)} keys(%{$Vector}))
2878 {
2879 foreach my $P2 (get_TemplateParam($Pos, $Vector->{$P1})) {
2880 push(@Params, $P2);
2881 }
2882 }
2883 return @Params;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002884 }
2885 else
2886 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04002887 my %ParamAttr = getTypeAttr($Type_Id);
Andrey Ponomarenkob8d203d2012-05-25 18:11:07 +04002888 my $PName = $ParamAttr{"Name"};
2889 if(not $PName) {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04002890 return ();
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002891 }
Andrey Ponomarenkob8d203d2012-05-25 18:11:07 +04002892 if($PName=~/\>/)
2893 {
2894 if(my $Cover = cover_stdcxx_typedef($PName)) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002895 $PName = $Cover;
2896 }
2897 }
2898 if($Pos>=1 and
Andrey Ponomarenko1477d2c2012-11-12 18:55:45 +04002899 $PName=~/\A$DEFAULT_STD_PARMS\</)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002900 { # template<typename _Tp, typename _Alloc = std::allocator<_Tp> >
2901 # template<typename _Key, typename _Compare = std::less<_Key>
2902 # template<typename _CharT, typename _Traits = std::char_traits<_CharT> >
2903 # template<typename _Ch_type, typename _Rx_traits = regex_traits<_Ch_type> >
2904 # template<typename _CharT, typename _InIter = istreambuf_iterator<_CharT> >
2905 # template<typename _CharT, typename _OutIter = ostreambuf_iterator<_CharT> >
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04002906 return ("\@skip\@");
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002907 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04002908 return ($PName);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002909 }
2910}
2911
2912sub cover_stdcxx_typedef($)
2913{
2914 my $TypeName = $_[0];
2915 if(my @Covers = sort {length($a)<=>length($b)}
2916 sort keys(%{$StdCxxTypedef{$Version}{$TypeName}}))
2917 { # take the shortest typedef
2918 # FIXME: there may be more than
2919 # one typedefs to the same type
2920 return $Covers[0];
2921 }
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +04002922 my $Covered = $TypeName;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002923 while($TypeName=~s/(>)[ ]*(const|volatile|restrict| |\*|\&)\Z/$1/g){};
2924 if(my @Covers = sort {length($a)<=>length($b)} sort keys(%{$StdCxxTypedef{$Version}{$TypeName}}))
2925 {
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +04002926 if(my $Cover = $Covers[0])
2927 {
2928 $Covered=~s/\b\Q$TypeName\E(\W|\Z)/$Cover$1/g;
2929 $Covered=~s/\b\Q$TypeName\E(\w|\Z)/$Cover $1/g;
2930 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002931 }
Andrey Ponomarenko9927e332012-10-19 10:50:48 +04002932 return formatName($Covered, "T");
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002933}
2934
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002935sub getNodeIntCst($)
2936{
2937 my $CstId = $_[0];
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04002938 my $CstTypeId = getTreeAttr_Type($CstId);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002939 if($EnumMembName_Id{$Version}{$CstId}) {
2940 return $EnumMembName_Id{$Version}{$CstId};
2941 }
2942 elsif((my $Value = getTreeValue($CstId)) ne "")
2943 {
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04002944 if($Value eq "0")
2945 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04002946 if($LibInfo{$Version}{"info_type"}{$CstTypeId} eq "boolean_type") {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002947 return "false";
2948 }
2949 else {
2950 return "0";
2951 }
2952 }
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04002953 elsif($Value eq "1")
2954 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04002955 if($LibInfo{$Version}{"info_type"}{$CstTypeId} eq "boolean_type") {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002956 return "true";
2957 }
2958 else {
2959 return "1";
2960 }
2961 }
2962 else {
2963 return $Value;
2964 }
2965 }
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04002966 return "";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002967}
2968
2969sub getNodeStrCst($)
2970{
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04002971 if($_[0] and my $Info = $LibInfo{$Version}{"info"}{$_[0]})
2972 {
2973 if($Info=~/strg[ ]*: (.+) lngt:[ ]*(\d+)/)
Andrey Ponomarenko01117f12012-06-26 12:23:02 +04002974 {
2975 if($LibInfo{$Version}{"info_type"}{$_[0]} eq "string_cst")
2976 { # string length is N-1 because of the null terminator
2977 return substr($1, 0, $2-1);
2978 }
2979 else
2980 { # identifier_node
2981 return substr($1, 0, $2);
2982 }
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04002983 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002984 }
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04002985 return "";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002986}
2987
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04002988sub getMemPtrAttr($$$)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002989{ # function, method and field pointers
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04002990 my ($PtrId, $TypeId, $Type) = @_;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002991 my $MemInfo = $LibInfo{$Version}{"info"}{$PtrId};
2992 if($Type eq "FieldPtr") {
2993 $MemInfo = $LibInfo{$Version}{"info"}{$TypeId};
2994 }
2995 my $MemInfo_Type = $LibInfo{$Version}{"info_type"}{$PtrId};
2996 my $MemPtrName = "";
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04002997 my %TypeAttr = ("Size"=>$WORD_SIZE{$Version}, "Type"=>$Type, "Tid"=>$TypeId);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002998 if($Type eq "MethodPtr")
2999 { # size of "method pointer" may be greater than WORD size
Andrey Ponomarenko01117f12012-06-26 12:23:02 +04003000 if(my $Size = getSize($TypeId))
3001 {
3002 $Size/=$BYTE_SIZE;
3003 $TypeAttr{"Size"} = "$Size";
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04003004 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003005 }
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +04003006 if(my $Algn = getAlgn($TypeId)) {
3007 $TypeAttr{"Algn"} = $Algn/$BYTE_SIZE;
3008 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003009 # Return
3010 if($Type eq "FieldPtr")
3011 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04003012 my %ReturnAttr = getTypeAttr($PtrId);
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04003013 if($ReturnAttr{"Name"}) {
3014 $MemPtrName .= $ReturnAttr{"Name"};
3015 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003016 $TypeAttr{"Return"} = $PtrId;
3017 }
3018 else
3019 {
3020 if($MemInfo=~/retn[ ]*:[ ]*\@(\d+) /)
3021 {
3022 my $ReturnTypeId = $1;
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04003023 my %ReturnAttr = getTypeAttr($ReturnTypeId);
3024 if(not $ReturnAttr{"Name"})
3025 { # templates
3026 return ();
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04003027 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04003028 $MemPtrName .= $ReturnAttr{"Name"};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003029 $TypeAttr{"Return"} = $ReturnTypeId;
3030 }
3031 }
3032 # Class
3033 if($MemInfo=~/(clas|cls)[ ]*:[ ]*@(\d+) /)
3034 {
3035 $TypeAttr{"Class"} = $2;
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04003036 my %Class = getTypeAttr($TypeAttr{"Class"});
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003037 if($Class{"Name"}) {
3038 $MemPtrName .= " (".$Class{"Name"}."\:\:*)";
3039 }
3040 else {
3041 $MemPtrName .= " (*)";
3042 }
3043 }
3044 else {
3045 $MemPtrName .= " (*)";
3046 }
3047 # Parameters
3048 if($Type eq "FuncPtr"
3049 or $Type eq "MethodPtr")
3050 {
3051 my @ParamTypeName = ();
3052 if($MemInfo=~/prms[ ]*:[ ]*@(\d+) /)
3053 {
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04003054 my $PTypeInfoId = $1;
Andrey Ponomarenko01117f12012-06-26 12:23:02 +04003055 my ($Pos, $PPos) = (0, 0);
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04003056 while($PTypeInfoId)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003057 {
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04003058 my $PTypeInfo = $LibInfo{$Version}{"info"}{$PTypeInfoId};
3059 if($PTypeInfo=~/valu[ ]*:[ ]*@(\d+) /)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003060 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04003061 my $PTypeId = $1;
3062 my %ParamAttr = getTypeAttr($PTypeId);
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04003063 if(not $ParamAttr{"Name"})
3064 { # templates (template_type_parm), etc.
3065 return ();
3066 }
3067 if($ParamAttr{"Name"} eq "void") {
3068 last;
3069 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04003070 if($Pos!=0 or $Type ne "MethodPtr")
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04003071 {
Andrey Ponomarenko01117f12012-06-26 12:23:02 +04003072 $TypeAttr{"Param"}{$PPos++}{"type"} = $PTypeId;
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04003073 push(@ParamTypeName, $ParamAttr{"Name"});
3074 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04003075 if($PTypeInfoId = getNextElem($PTypeInfoId)) {
3076 $Pos+=1;
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04003077 }
3078 else {
3079 last;
3080 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003081 }
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04003082 else {
3083 last;
3084 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003085 }
3086 }
3087 $MemPtrName .= " (".join(", ", @ParamTypeName).")";
3088 }
Andrey Ponomarenko9927e332012-10-19 10:50:48 +04003089 $TypeAttr{"Name"} = formatName($MemPtrName, "T");
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003090 return %TypeAttr;
3091}
3092
3093sub getTreeTypeName($)
3094{
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04003095 my $TypeId = $_[0];
3096 if(my $Info = $LibInfo{$Version}{"info"}{$TypeId})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003097 {
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04003098 if($LibInfo{$Version}{"info_type"}{$_[0]} eq "integer_type")
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003099 {
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04003100 if(my $Name = getNameByInfo($TypeId))
3101 { # bit_size_type
3102 return $Name;
3103 }
3104 elsif($Info=~/unsigned/) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003105 return "unsigned int";
3106 }
3107 else {
3108 return "int";
3109 }
3110 }
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04003111 elsif($Info=~/name[ ]*:[ ]*@(\d+) /)
3112 {
3113 return getNameByInfo($1);
3114 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003115 }
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04003116 return "";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003117}
3118
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04003119sub isFuncPtr($)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003120{
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04003121 my $Ptd = pointTo($_[0]);
3122 return 0 if(not $Ptd);
3123 if(my $Info = $LibInfo{$Version}{"info"}{$_[0]})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003124 {
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04003125 if($Info=~/unql[ ]*:/ and $Info!~/qual[ ]*:/) {
3126 return 0;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003127 }
3128 }
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04003129 if(my $InfoT1 = $LibInfo{$Version}{"info_type"}{$_[0]}
3130 and my $InfoT2 = $LibInfo{$Version}{"info_type"}{$Ptd})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003131 {
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04003132 if($InfoT1 eq "pointer_type"
3133 and $InfoT2 eq "function_type") {
3134 return 1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003135 }
3136 }
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04003137 return 0;
3138}
3139
3140sub isMethodPtr($)
3141{
3142 my $Ptd = pointTo($_[0]);
3143 return 0 if(not $Ptd);
3144 if(my $Info = $LibInfo{$Version}{"info"}{$_[0]})
3145 {
3146 if($LibInfo{$Version}{"info_type"}{$_[0]} eq "record_type"
3147 and $LibInfo{$Version}{"info_type"}{$Ptd} eq "method_type"
3148 and $Info=~/ ptrmem /) {
3149 return 1;
3150 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003151 }
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04003152 return 0;
3153}
3154
3155sub isFieldPtr($)
3156{
3157 if($_[0] and my $Info = $LibInfo{$Version}{"info"}{$_[0]})
3158 {
3159 if($LibInfo{$Version}{"info_type"}{$_[0]} eq "offset_type"
3160 and $Info=~/ ptrmem /) {
3161 return 1;
3162 }
3163 }
3164 return 0;
3165}
3166
3167sub pointTo($)
3168{
3169 if($_[0] and my $Info = $LibInfo{$Version}{"info"}{$_[0]})
3170 {
3171 if($Info=~/ptd[ ]*:[ ]*@(\d+)/) {
3172 return $1;
3173 }
3174 }
3175 return "";
3176}
3177
3178sub getTypeTypeByTypeId($)
3179{
3180 my $TypeId = $_[0];
3181 if(my $TType = $LibInfo{$Version}{"info_type"}{$TypeId})
3182 {
3183 my $NType = $NodeType{$TType};
3184 if($NType eq "Intrinsic") {
3185 return $NType;
3186 }
3187 elsif(isFuncPtr($TypeId)) {
3188 return "FuncPtr";
3189 }
3190 elsif(isMethodPtr($TypeId)) {
3191 return "MethodPtr";
3192 }
3193 elsif(isFieldPtr($TypeId)) {
3194 return "FieldPtr";
3195 }
3196 elsif($NType ne "Other") {
3197 return $NType;
3198 }
3199 }
3200 return "Unknown";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003201}
3202
3203sub getQual($)
3204{
3205 my $TypeId = $_[0];
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003206 my %UnQual = (
3207 "r"=>"restrict",
3208 "v"=>"volatile",
3209 "c"=>"const",
3210 "cv"=>"const volatile"
3211 );
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04003212 if(my $Info = $LibInfo{$Version}{"info"}{$TypeId})
3213 {
3214 my ($Qual, $To) = ();
3215 if($Info=~/qual[ ]*:[ ]*(r|c|v|cv) /) {
3216 $Qual = $UnQual{$1};
3217 }
3218 if($Info=~/unql[ ]*:[ ]*\@(\d+)/) {
3219 $To = $1;
3220 }
3221 if($Qual and $To) {
3222 return ($Qual, $To);
3223 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003224 }
3225 return ();
3226}
3227
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04003228sub getQualType($)
3229{
3230 if($_[0] eq "const volatile") {
3231 return "ConstVolatile";
3232 }
3233 return ucfirst($_[0]);
3234}
3235
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04003236sub getTypeType($)
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04003237{
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04003238 my $TypeId = $_[0];
3239 my $TypeDeclId = getTypeDeclId($TypeId);
3240 if(defined $MissedTypedef{$Version}{$TypeId})
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04003241 { # support for old GCC versions
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04003242 if($MissedTypedef{$Version}{$TypeId}{"TDid"} eq $TypeDeclId) {
3243 return "Typedef";
3244 }
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04003245 }
3246 my $Info = $LibInfo{$Version}{"info"}{$TypeId};
3247 my ($Qual, $To) = getQual($TypeId);
Andrey Ponomarenko9927e332012-10-19 10:50:48 +04003248 if(($Qual or $To) and $TypeDeclId
3249 and (getTypeId($TypeDeclId) ne $TypeId))
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04003250 { # qualified types (special)
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04003251 return getQualType($Qual);
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04003252 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04003253 elsif(not $MissedBase_R{$Version}{$TypeId}
3254 and isTypedef($TypeId)) {
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04003255 return "Typedef";
3256 }
3257 elsif($Qual)
3258 { # qualified types
3259 return getQualType($Qual);
3260 }
Andrey Ponomarenko9927e332012-10-19 10:50:48 +04003261
3262 if($Info=~/unql[ ]*:[ ]*\@(\d+)/)
3263 { # typedef struct { ... } name
3264 $TypeTypedef{$Version}{$TypeId} = $1;
3265 }
3266
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04003267 my $TypeType = getTypeTypeByTypeId($TypeId);
3268 if($TypeType eq "Struct")
3269 {
3270 if($TypeDeclId
3271 and $LibInfo{$Version}{"info_type"}{$TypeDeclId} eq "template_decl") {
3272 return "Template";
3273 }
3274 }
3275 return $TypeType;
3276}
3277
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04003278sub isTypedef($)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003279{
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04003280 if($_[0] and my $Info = $LibInfo{$Version}{"info"}{$_[0]})
3281 {
3282 my $TDid = getTypeDeclId($_[0]);
3283 if(getNameByInfo($TDid)
3284 and $Info=~/unql[ ]*:[ ]*\@(\d+) /
3285 and getTypeId($TDid) eq $_[0]) {
3286 return $1;
3287 }
3288 }
3289 return 0;
3290}
3291
3292sub selectBaseType($)
3293{
3294 my $TypeId = $_[0];
3295 if(defined $MissedTypedef{$Version}{$TypeId})
3296 { # add missed typedefs
3297 if($MissedTypedef{$Version}{$TypeId}{"TDid"} eq getTypeDeclId($TypeId)) {
3298 return ($TypeId, "");
3299 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003300 }
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04003301 my $Info = $LibInfo{$Version}{"info"}{$TypeId};
3302 my $InfoType = $LibInfo{$Version}{"info_type"}{$TypeId};
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04003303
3304 my $MB_R = $MissedBase_R{$Version}{$TypeId};
3305 my $MB = $MissedBase{$Version}{$TypeId};
3306
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04003307 my ($Qual, $To) = getQual($TypeId);
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04003308 if(($Qual or $To) and $Info=~/name[ ]*:[ ]*\@(\d+) /
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04003309 and (getTypeId($1) ne $TypeId)
3310 and (not $MB_R or getTypeId($1) ne $MB_R))
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04003311 { # qualified types (special)
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04003312 return (getTypeId($1), $Qual);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003313 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04003314 elsif($MB)
3315 { # add base
3316 return ($MB, "");
3317 }
3318 elsif(not $MB_R and my $Bid = isTypedef($TypeId))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003319 { # typedefs
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04003320 return ($Bid, "");
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003321 }
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04003322 elsif($Qual or $To)
3323 { # qualified types
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04003324 return ($To, $Qual);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003325 }
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04003326 elsif($InfoType eq "reference_type")
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003327 {
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04003328 if($Info=~/refd[ ]*:[ ]*@(\d+) /) {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04003329 return ($1, "&");
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003330 }
3331 else {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04003332 return (0, "");
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003333 }
3334 }
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04003335 elsif($InfoType eq "array_type")
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003336 {
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04003337 if($Info=~/elts[ ]*:[ ]*@(\d+) /) {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04003338 return ($1, "");
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003339 }
3340 else {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04003341 return (0, "");
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003342 }
3343 }
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04003344 elsif($InfoType eq "pointer_type")
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003345 {
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04003346 if($Info=~/ptd[ ]*:[ ]*@(\d+) /) {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04003347 return ($1, "*");
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003348 }
3349 else {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04003350 return (0, "");
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003351 }
3352 }
3353 else {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04003354 return (0, "");
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003355 }
3356}
3357
3358sub getSymbolInfo_All()
3359{
3360 foreach (sort {int($b)<=>int($a)} keys(%{$LibInfo{$Version}{"info"}}))
3361 { # reverse order
3362 if($LibInfo{$Version}{"info_type"}{$_} eq "function_decl") {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04003363 getSymbolInfo($_);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003364 }
3365 }
3366}
3367
3368sub getVarInfo_All()
3369{
3370 foreach (sort {int($b)<=>int($a)} keys(%{$LibInfo{$Version}{"info"}}))
3371 { # reverse order
3372 if($LibInfo{$Version}{"info_type"}{$_} eq "var_decl") {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04003373 getVarInfo($_);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003374 }
3375 }
3376}
3377
3378sub isBuiltIn($) {
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04003379 return ($_[0] and $_[0]=~/\<built\-in\>|\<internal\>|\A\./);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003380}
3381
3382sub getVarInfo($)
3383{
3384 my $InfoId = $_[0];
Andrey Ponomarenko01117f12012-06-26 12:23:02 +04003385 if(my $NSid = getTreeAttr_Scpe($InfoId))
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04003386 {
3387 my $NSInfoType = $LibInfo{$Version}{"info_type"}{$NSid};
3388 if($NSInfoType and $NSInfoType eq "function_decl") {
3389 return;
3390 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003391 }
3392 ($SymbolInfo{$Version}{$InfoId}{"Header"}, $SymbolInfo{$Version}{$InfoId}{"Line"}) = getLocation($InfoId);
3393 if(not $SymbolInfo{$Version}{$InfoId}{"Header"}
3394 or isBuiltIn($SymbolInfo{$Version}{$InfoId}{"Header"})) {
3395 delete($SymbolInfo{$Version}{$InfoId});
3396 return;
3397 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04003398 my $ShortName = getTreeStr(getTreeAttr_Name($InfoId));
Andrey Ponomarenko85043792012-05-14 16:48:07 +04003399 if(not $ShortName) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003400 delete($SymbolInfo{$Version}{$InfoId});
3401 return;
3402 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +04003403 if($ShortName=~/\Atmp_add_class_\d+\Z/) {
3404 delete($SymbolInfo{$Version}{$InfoId});
3405 return;
3406 }
3407 $SymbolInfo{$Version}{$InfoId}{"ShortName"} = $ShortName;
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +04003408 if(my $MnglName = getTreeStr(getTreeAttr_Mngl($InfoId)))
3409 {
3410 if($OSgroup eq "windows")
3411 { # cut the offset
3412 $MnglName=~s/\@\d+\Z//g;
3413 }
3414 $SymbolInfo{$Version}{$InfoId}{"MnglName"} = $MnglName;
3415 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003416 if($SymbolInfo{$Version}{$InfoId}{"MnglName"}
Andrey Ponomarenko9927e332012-10-19 10:50:48 +04003417 and index($SymbolInfo{$Version}{$InfoId}{"MnglName"}, "_Z")!=0)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003418 { # validate mangled name
3419 delete($SymbolInfo{$Version}{$InfoId});
3420 return;
3421 }
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04003422 if(not $SymbolInfo{$Version}{$InfoId}{"MnglName"}
Andrey Ponomarenko9927e332012-10-19 10:50:48 +04003423 and index($ShortName, "_Z")==0)
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04003424 { # _ZTS, etc.
Andrey Ponomarenko85043792012-05-14 16:48:07 +04003425 $SymbolInfo{$Version}{$InfoId}{"MnglName"} = $ShortName;
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04003426 }
3427 if(isPrivateData($SymbolInfo{$Version}{$InfoId}{"MnglName"}))
3428 { # non-public global data
3429 delete($SymbolInfo{$Version}{$InfoId});
3430 return;
3431 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003432 $SymbolInfo{$Version}{$InfoId}{"Data"} = 1;
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04003433 if(my $Rid = getTypeId($InfoId))
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04003434 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04003435 if(not $TypeInfo{$Version}{$Rid}{"Name"})
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04003436 { # typename_type
3437 delete($SymbolInfo{$Version}{$InfoId});
3438 return;
3439 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04003440 $SymbolInfo{$Version}{$InfoId}{"Return"} = $Rid;
3441 my $Val = getDataVal($InfoId, $Rid);
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04003442 if(defined $Val) {
3443 $SymbolInfo{$Version}{$InfoId}{"Value"} = $Val;
3444 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003445 }
3446 set_Class_And_Namespace($InfoId);
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04003447 if(my $ClassId = $SymbolInfo{$Version}{$InfoId}{"Class"})
3448 {
3449 if(not $TypeInfo{$Version}{$ClassId}{"Name"})
3450 { # templates
3451 delete($SymbolInfo{$Version}{$InfoId});
3452 return;
3453 }
3454 }
Andrey Ponomarenko35c44fd2012-06-18 17:50:25 +04003455 if($LibInfo{$Version}{"info"}{$InfoId}=~/ lang:[ ]*C /i)
3456 { # extern "C"
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003457 $SymbolInfo{$Version}{$InfoId}{"Lang"} = "C";
Andrey Ponomarenko35c44fd2012-06-18 17:50:25 +04003458 $SymbolInfo{$Version}{$InfoId}{"MnglName"} = $ShortName;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003459 }
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04003460 if($UserLang and $UserLang eq "C")
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003461 { # --lang=C option
Andrey Ponomarenko85043792012-05-14 16:48:07 +04003462 $SymbolInfo{$Version}{$InfoId}{"MnglName"} = $ShortName;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003463 }
Andrey Ponomarenko5c09ef32012-06-14 18:17:33 +04003464 if(not $CheckHeadersOnly)
3465 {
3466 if(not $SymbolInfo{$Version}{$InfoId}{"Class"})
3467 {
3468 if(not $SymbolInfo{$Version}{$InfoId}{"MnglName"}
3469 or not link_symbol($SymbolInfo{$Version}{$InfoId}{"MnglName"}, $Version, "-Deps"))
3470 {
3471 if(link_symbol($ShortName, $Version, "-Deps"))
3472 { # "const" global data is mangled as _ZL... in the TU dump
3473 # but not mangled when compiling a C shared library
3474 $SymbolInfo{$Version}{$InfoId}{"MnglName"} = $ShortName;
3475 }
3476 }
3477 }
3478 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003479 if($COMMON_LANGUAGE{$Version} eq "C++")
3480 {
3481 if(not $SymbolInfo{$Version}{$InfoId}{"MnglName"})
3482 { # for some symbols (_ZTI) the short name is the mangled name
Andrey Ponomarenko9927e332012-10-19 10:50:48 +04003483 if(index($ShortName, "_Z")==0) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003484 $SymbolInfo{$Version}{$InfoId}{"MnglName"} = $ShortName;
3485 }
3486 }
3487 if(not $SymbolInfo{$Version}{$InfoId}{"MnglName"})
3488 { # try to mangle symbol (link with libraries)
3489 $SymbolInfo{$Version}{$InfoId}{"MnglName"} = linkSymbol($InfoId);
3490 }
3491 if($OStarget eq "windows")
3492 {
3493 if(my $Mangled = $mangled_name{$Version}{modelUnmangled($InfoId, "MSVC")})
3494 { # link MS C++ symbols from library with GCC symbols from headers
3495 $SymbolInfo{$Version}{$InfoId}{"MnglName"} = $Mangled;
3496 }
3497 }
3498 }
3499 if(not $SymbolInfo{$Version}{$InfoId}{"MnglName"}) {
3500 $SymbolInfo{$Version}{$InfoId}{"MnglName"} = $ShortName;
3501 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +04003502 if(my $Symbol = $SymbolInfo{$Version}{$InfoId}{"MnglName"})
3503 {
3504 if(not selectSymbol($Symbol, $SymbolInfo{$Version}{$InfoId}, "Dump", $Version))
3505 { # non-target symbols
3506 delete($SymbolInfo{$Version}{$InfoId});
3507 return;
3508 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003509 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04003510 if(my $Rid = $SymbolInfo{$Version}{$InfoId}{"Return"})
3511 {
3512 if(defined $MissedTypedef{$Version}{$Rid})
3513 {
3514 if(my $AddedTid = $MissedTypedef{$Version}{$Rid}{"Tid"}) {
3515 $SymbolInfo{$Version}{$InfoId}{"Return"} = $AddedTid;
3516 }
3517 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003518 }
3519 setFuncAccess($InfoId);
Andrey Ponomarenko9927e332012-10-19 10:50:48 +04003520 if(index($SymbolInfo{$Version}{$InfoId}{"MnglName"}, "_ZTV")==0) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003521 delete($SymbolInfo{$Version}{$InfoId}{"Return"});
3522 }
3523 if($ShortName=~/\A(_Z|\?)/) {
3524 delete($SymbolInfo{$Version}{$InfoId}{"ShortName"});
3525 }
3526}
3527
Andrey Ponomarenko85043792012-05-14 16:48:07 +04003528sub isConstType($$)
3529{
3530 my ($TypeId, $LibVersion) = @_;
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04003531 my %Base = get_Type($TypeId, $LibVersion);
Andrey Ponomarenko85043792012-05-14 16:48:07 +04003532 while(defined $Base{"Type"} and $Base{"Type"} eq "Typedef") {
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +04003533 %Base = get_OneStep_BaseType($Base{"Tid"}, $TypeInfo{$LibVersion});
Andrey Ponomarenko85043792012-05-14 16:48:07 +04003534 }
3535 return ($Base{"Type"} eq "Const");
3536}
3537
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003538sub getTrivialName($$)
3539{
3540 my ($TypeInfoId, $TypeId) = @_;
3541 my %TypeAttr = ();
3542 $TypeAttr{"Name"} = getNameByInfo($TypeInfoId);
3543 if(not $TypeAttr{"Name"}) {
3544 $TypeAttr{"Name"} = getTreeTypeName($TypeId);
3545 }
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04003546 ($TypeAttr{"Header"}, $TypeAttr{"Line"}) = getLocation($TypeInfoId);
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04003547 $TypeAttr{"Type"} = getTypeType($TypeId);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003548 $TypeAttr{"Name"}=~s/<(.+)\Z//g; # GCC 3.4.4 add template params to the name
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04003549 if(isAnon($TypeAttr{"Name"}))
3550 {
3551 my $NameSpaceId = $TypeId;
Andrey Ponomarenko01117f12012-06-26 12:23:02 +04003552 while(my $NSId = getTreeAttr_Scpe(getTypeDeclId($NameSpaceId)))
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04003553 { # searching for a first not anon scope
3554 if($NSId eq $NameSpaceId) {
3555 last;
3556 }
3557 else
3558 {
3559 $TypeAttr{"NameSpace"} = getNameSpace(getTypeDeclId($TypeId));
3560 if(not $TypeAttr{"NameSpace"}
Andrey Ponomarenko2956b972012-11-14 19:16:16 +04003561 or not isAnon($TypeAttr{"NameSpace"})) {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04003562 last;
3563 }
3564 }
3565 $NameSpaceId=$NSId;
3566 }
3567 }
3568 else
3569 {
Andrey Ponomarenko01117f12012-06-26 12:23:02 +04003570 if(my $NameSpaceId = getTreeAttr_Scpe($TypeInfoId))
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04003571 {
3572 if($NameSpaceId ne $TypeId) {
3573 $TypeAttr{"NameSpace"} = getNameSpace($TypeInfoId);
3574 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003575 }
3576 }
Andrey Ponomarenko2956b972012-11-14 19:16:16 +04003577 if($TypeAttr{"NameSpace"} and not isAnon($TypeAttr{"Name"})) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003578 $TypeAttr{"Name"} = $TypeAttr{"NameSpace"}."::".$TypeAttr{"Name"};
3579 }
Andrey Ponomarenko9927e332012-10-19 10:50:48 +04003580 $TypeAttr{"Name"} = formatName($TypeAttr{"Name"}, "T");
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003581 if(isAnon($TypeAttr{"Name"}))
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04003582 { # anon-struct-header.h-line
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04003583 $TypeAttr{"Name"} = "anon-".lc($TypeAttr{"Type"})."-";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003584 $TypeAttr{"Name"} .= $TypeAttr{"Header"}."-".$TypeAttr{"Line"};
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04003585 if($TypeAttr{"NameSpace"}) {
3586 $TypeAttr{"Name"} = $TypeAttr{"NameSpace"}."::".$TypeAttr{"Name"};
3587 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003588 }
Andrey Ponomarenkob8d203d2012-05-25 18:11:07 +04003589 if(defined $TemplateInstance{$Version}{"Type"}{$TypeId}
3590 and getTypeDeclId($TypeId) eq $TypeInfoId)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003591 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04003592 my @TParams = getTParams($TypeId, "Type");
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003593 if(not @TParams)
3594 { # template declarations with abstract params
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003595 return ("", "");
3596 }
Andrey Ponomarenko9927e332012-10-19 10:50:48 +04003597 $TypeAttr{"Name"} = formatName($TypeAttr{"Name"}."< ".join(", ", @TParams)." >", "T");
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003598 }
3599 return ($TypeAttr{"Name"}, $TypeAttr{"NameSpace"});
3600}
3601
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04003602sub getTrivialTypeAttr($)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003603{
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04003604 my $TypeId = $_[0];
3605 my $TypeInfoId = getTypeDeclId($_[0]);
Andrey Ponomarenko85043792012-05-14 16:48:07 +04003606
3607 if($TemplateDecl{$Version}{$TypeId})
3608 { # template_decl
3609 return ();
3610 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04003611 if(my $ScopeId = getTreeAttr_Scpe($TypeInfoId))
3612 {
3613 if($TemplateDecl{$Version}{$ScopeId})
3614 { # template_decl
3615 return ();
3616 }
3617 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +04003618
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003619 my %TypeAttr = ();
3620 if(getTypeTypeByTypeId($TypeId)!~/\A(Intrinsic|Union|Struct|Enum|Class)\Z/) {
3621 return ();
3622 }
3623 setTypeAccess($TypeId, \%TypeAttr);
3624 ($TypeAttr{"Header"}, $TypeAttr{"Line"}) = getLocation($TypeInfoId);
3625 if(isBuiltIn($TypeAttr{"Header"}))
3626 {
3627 delete($TypeAttr{"Header"});
3628 delete($TypeAttr{"Line"});
3629 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04003630 $TypeAttr{"Type"} = getTypeType($TypeId);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003631 ($TypeAttr{"Name"}, $TypeAttr{"NameSpace"}) = getTrivialName($TypeInfoId, $TypeId);
3632 if(not $TypeAttr{"Name"}) {
3633 return ();
3634 }
3635 if(not $TypeAttr{"NameSpace"}) {
3636 delete($TypeAttr{"NameSpace"});
3637 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04003638 if(defined $TemplateInstance{$Version}{"Type"}{$TypeId})
Andrey Ponomarenko16934472012-03-29 15:37:04 +04003639 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04003640 if(my @TParams = getTParams($TypeId, "Type"))
Andrey Ponomarenko16934472012-03-29 15:37:04 +04003641 {
3642 foreach my $Pos (0 .. $#TParams) {
3643 $TypeAttr{"TParam"}{$Pos}{"name"}=$TParams[$Pos];
3644 }
3645 }
3646 }
Andrey Ponomarenko01117f12012-06-26 12:23:02 +04003647 if(my $Size = getSize($TypeId))
3648 {
3649 $Size = $Size/$BYTE_SIZE;
3650 $TypeAttr{"Size"} = "$Size";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003651 }
Andrey Ponomarenko9927e332012-10-19 10:50:48 +04003652 else
3653 { # declaration only
3654 $TypeAttr{"Forward"} = 1;
3655 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003656 if($TypeAttr{"Type"} eq "Struct"
3657 and detect_lang($TypeId))
3658 {
3659 $TypeAttr{"Type"} = "Class";
Andrey Ponomarenko85043792012-05-14 16:48:07 +04003660 $TypeAttr{"Copied"} = 1; # default, will be changed in getSymbolInfo()
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003661 }
3662 if($TypeAttr{"Type"} eq "Struct"
Andrey Ponomarenko85043792012-05-14 16:48:07 +04003663 or $TypeAttr{"Type"} eq "Class")
3664 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04003665 my $Skip = setBaseClasses($TypeId, \%TypeAttr);
Andrey Ponomarenko85043792012-05-14 16:48:07 +04003666 if($Skip) {
3667 return ();
3668 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003669 }
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +04003670 if(my $Algn = getAlgn($TypeId)) {
3671 $TypeAttr{"Algn"} = $Algn/$BYTE_SIZE;
3672 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003673 setSpec($TypeId, \%TypeAttr);
3674 setTypeMemb($TypeId, \%TypeAttr);
3675 $TypeAttr{"Tid"} = $TypeId;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003676 if(my $VTable = $ClassVTable_Content{$Version}{$TypeAttr{"Name"}})
3677 {
3678 my @Entries = split(/\n/, $VTable);
3679 foreach (1 .. $#Entries)
3680 {
3681 my $Entry = $Entries[$_];
3682 if($Entry=~/\A(\d+)\s+(.+)\Z/) {
3683 $TypeAttr{"VTable"}{$1} = $2;
3684 }
3685 }
3686 }
Andrey Ponomarenko82bc2572012-11-14 13:55:30 +04003687
3688 if($TypeAttr{"Type"} eq "Enum")
3689 {
3690 if(not $TypeAttr{"NameSpace"})
3691 {
3692 foreach my $Pos (keys(%{$TypeAttr{"Memb"}}))
3693 {
3694 my $MName = $TypeAttr{"Memb"}{$Pos}{"name"};
3695 $EnumConstants{$Version}{$MName} = {
3696 "Value"=>$TypeAttr{"Memb"}{$Pos}{"value"},
3697 "Header"=>$TypeAttr{"Header"}
3698 };
3699 }
3700 }
3701 }
3702
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003703 return %TypeAttr;
3704}
3705
3706sub detect_lang($)
3707{
3708 my $TypeId = $_[0];
3709 my $Info = $LibInfo{$Version}{"info"}{$TypeId};
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04003710 if(check_gcc($GCC_PATH, "4"))
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04003711 { # GCC 4 fncs-node points to only non-artificial methods
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003712 return ($Info=~/(fncs)[ ]*:[ ]*@(\d+) /);
3713 }
3714 else
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04003715 { # GCC 3
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04003716 my $Fncs = getTreeAttr_Fncs($TypeId);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003717 while($Fncs)
3718 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04003719 if($LibInfo{$Version}{"info"}{$Fncs}!~/artificial/) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003720 return 1;
3721 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04003722 $Fncs = getTreeAttr_Chan($Fncs);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003723 }
3724 }
3725 return 0;
3726}
3727
3728sub setSpec($$)
3729{
3730 my ($TypeId, $TypeAttr) = @_;
3731 my $Info = $LibInfo{$Version}{"info"}{$TypeId};
3732 if($Info=~/\s+spec\s+/) {
3733 $TypeAttr->{"Spec"} = 1;
3734 }
3735}
3736
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04003737sub setBaseClasses($$)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003738{
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04003739 my ($TypeId, $TypeAttr) = @_;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003740 my $Info = $LibInfo{$Version}{"info"}{$TypeId};
3741 if($Info=~/binf[ ]*:[ ]*@(\d+) /)
3742 {
3743 $Info = $LibInfo{$Version}{"info"}{$1};
3744 my $Pos = 0;
3745 while($Info=~s/(pub|public|prot|protected|priv|private|)[ ]+binf[ ]*:[ ]*@(\d+) //)
3746 {
3747 my ($Access, $BInfoId) = ($1, $2);
3748 my $ClassId = getBinfClassId($BInfoId);
Andrey Ponomarenko85043792012-05-14 16:48:07 +04003749 my $CType = $LibInfo{$Version}{"info_type"}{$ClassId};
3750 if(not $CType or $CType eq "template_type_parm"
3751 or $CType eq "typename_type")
3752 { # skip
3753 return 1;
3754 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003755 my $BaseInfo = $LibInfo{$Version}{"info"}{$BInfoId};
3756 if($Access=~/prot/)
3757 {
3758 $TypeAttr->{"Base"}{$ClassId}{"access"} = "protected";
3759 }
3760 elsif($Access=~/priv/)
3761 {
3762 $TypeAttr->{"Base"}{$ClassId}{"access"} = "private";
3763 }
Andrey Ponomarenko01117f12012-06-26 12:23:02 +04003764 $TypeAttr->{"Base"}{$ClassId}{"pos"} = "$Pos";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003765 if($BaseInfo=~/virt/)
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04003766 { # virtual base
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003767 $TypeAttr->{"Base"}{$ClassId}{"virtual"} = 1;
3768 }
3769 $Class_SubClasses{$Version}{$ClassId}{$TypeId}=1;
Andrey Ponomarenko01117f12012-06-26 12:23:02 +04003770 $Pos+=1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003771 }
3772 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +04003773 return 0;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003774}
3775
3776sub getBinfClassId($)
3777{
3778 my $Info = $LibInfo{$Version}{"info"}{$_[0]};
3779 $Info=~/type[ ]*:[ ]*@(\d+) /;
3780 return $1;
3781}
3782
3783sub unmangledFormat($$)
3784{
3785 my ($Name, $LibVersion) = @_;
3786 $Name = uncover_typedefs($Name, $LibVersion);
3787 while($Name=~s/([^\w>*])(const|volatile)(,|>|\Z)/$1$3/g){};
3788 $Name=~s/\(\w+\)(\d)/$1/;
3789 return $Name;
3790}
3791
3792sub modelUnmangled($$)
3793{
3794 my ($InfoId, $Compiler) = @_;
3795 if($Cache{"modelUnmangled"}{$Version}{$Compiler}{$InfoId}) {
3796 return $Cache{"modelUnmangled"}{$Version}{$Compiler}{$InfoId};
3797 }
3798 my $PureSignature = $SymbolInfo{$Version}{$InfoId}{"ShortName"};
3799 if($SymbolInfo{$Version}{$InfoId}{"Destructor"}) {
3800 $PureSignature = "~".$PureSignature;
3801 }
3802 if(not $SymbolInfo{$Version}{$InfoId}{"Data"})
3803 {
3804 my (@Params, @ParamTypes) = ();
3805 if(defined $SymbolInfo{$Version}{$InfoId}{"Param"}
3806 and not $SymbolInfo{$Version}{$InfoId}{"Destructor"}) {
3807 @Params = keys(%{$SymbolInfo{$Version}{$InfoId}{"Param"}});
3808 }
3809 foreach my $ParamPos (sort {int($a) <=> int($b)} @Params)
3810 { # checking parameters
3811 my $PId = $SymbolInfo{$Version}{$InfoId}{"Param"}{$ParamPos}{"type"};
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +04003812 my %PType = get_PureType($PId, $TypeInfo{$Version});
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003813 my $PTName = unmangledFormat($PType{"Name"}, $Version);
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04003814 $PTName=~s/\b(restrict|register)\b//g;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003815 if($Compiler eq "MSVC") {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04003816 $PTName=~s/\blong long\b/__int64/;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003817 }
3818 @ParamTypes = (@ParamTypes, $PTName);
3819 }
3820 if(@ParamTypes) {
3821 $PureSignature .= "(".join(", ", @ParamTypes).")";
3822 }
3823 else
3824 {
3825 if($Compiler eq "MSVC")
3826 {
3827 $PureSignature .= "(void)";
3828 }
3829 else
3830 { # GCC
3831 $PureSignature .= "()";
3832 }
3833 }
3834 $PureSignature = delete_keywords($PureSignature);
3835 }
3836 if(my $ClassId = $SymbolInfo{$Version}{$InfoId}{"Class"})
3837 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04003838 my $ClassName = unmangledFormat($TypeInfo{$Version}{$ClassId}{"Name"}, $Version);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003839 $PureSignature = $ClassName."::".$PureSignature;
3840 }
3841 elsif(my $NS = $SymbolInfo{$Version}{$InfoId}{"NameSpace"}) {
3842 $PureSignature = $NS."::".$PureSignature;
3843 }
3844 if($SymbolInfo{$Version}{$InfoId}{"Const"}) {
3845 $PureSignature .= " const";
3846 }
3847 if($SymbolInfo{$Version}{$InfoId}{"Volatile"}) {
3848 $PureSignature .= " volatile";
3849 }
3850 my $ShowReturn = 0;
3851 if($Compiler eq "MSVC"
3852 and $SymbolInfo{$Version}{$InfoId}{"Data"})
3853 {
3854 $ShowReturn=1;
3855 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04003856 elsif(defined $TemplateInstance{$Version}{"Func"}{$InfoId}
3857 and keys(%{$TemplateInstance{$Version}{"Func"}{$InfoId}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003858 {
3859 $ShowReturn=1;
3860 }
3861 if($ShowReturn)
3862 { # mangled names for template function specializations include return value
3863 if(my $ReturnId = $SymbolInfo{$Version}{$InfoId}{"Return"})
3864 {
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +04003865 my %RType = get_PureType($ReturnId, $TypeInfo{$Version});
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003866 my $ReturnName = unmangledFormat($RType{"Name"}, $Version);
3867 $PureSignature = $ReturnName." ".$PureSignature;
3868 }
3869 }
Andrey Ponomarenko9927e332012-10-19 10:50:48 +04003870 return ($Cache{"modelUnmangled"}{$Version}{$Compiler}{$InfoId} = formatName($PureSignature, "S"));
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003871}
3872
3873sub mangle_symbol($$$)
3874{ # mangling for simple methods
3875 # see gcc-4.6.0/gcc/cp/mangle.c
3876 my ($InfoId, $LibVersion, $Compiler) = @_;
3877 if($Cache{"mangle_symbol"}{$LibVersion}{$InfoId}{$Compiler}) {
3878 return $Cache{"mangle_symbol"}{$LibVersion}{$InfoId}{$Compiler};
3879 }
3880 my $Mangled = "";
3881 if($Compiler eq "GCC") {
Andrey Ponomarenko16934472012-03-29 15:37:04 +04003882 $Mangled = mangle_symbol_GCC($InfoId, $LibVersion);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003883 }
3884 elsif($Compiler eq "MSVC") {
Andrey Ponomarenko16934472012-03-29 15:37:04 +04003885 $Mangled = mangle_symbol_MSVC($InfoId, $LibVersion);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003886 }
3887 return ($Cache{"mangle_symbol"}{$LibVersion}{$InfoId}{$Compiler} = $Mangled);
3888}
3889
Andrey Ponomarenko16934472012-03-29 15:37:04 +04003890sub mangle_symbol_MSVC($$)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003891{
3892 my ($InfoId, $LibVersion) = @_;
3893 return "";
3894}
3895
Andrey Ponomarenko16934472012-03-29 15:37:04 +04003896sub mangle_symbol_GCC($$)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003897{ # see gcc-4.6.0/gcc/cp/mangle.c
3898 my ($InfoId, $LibVersion) = @_;
3899 my ($Mangled, $ClassId, $NameSpace) = ("_Z", 0, "");
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04003900 my $Return = $SymbolInfo{$LibVersion}{$InfoId}{"Return"};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003901 my %Repl = ();# SN_ replacements
3902 if($ClassId = $SymbolInfo{$LibVersion}{$InfoId}{"Class"})
3903 {
3904 my $MangledClass = mangle_param($ClassId, $LibVersion, \%Repl);
3905 if($MangledClass!~/\AN/) {
3906 $MangledClass = "N".$MangledClass;
3907 }
3908 else {
3909 $MangledClass=~s/E\Z//;
3910 }
3911 if($SymbolInfo{$LibVersion}{$InfoId}{"Volatile"}) {
3912 $MangledClass=~s/\AN/NV/;
3913 }
3914 if($SymbolInfo{$LibVersion}{$InfoId}{"Const"}) {
3915 $MangledClass=~s/\AN/NK/;
3916 }
3917 $Mangled .= $MangledClass;
3918 }
3919 elsif($NameSpace = $SymbolInfo{$LibVersion}{$InfoId}{"NameSpace"})
3920 { # mangled by name due to the absence of structured info
3921 my $MangledNS = mangle_ns($NameSpace, $LibVersion, \%Repl);
3922 if($MangledNS!~/\AN/) {
3923 $MangledNS = "N".$MangledNS;
3924 }
3925 else {
3926 $MangledNS=~s/E\Z//;
3927 }
3928 $Mangled .= $MangledNS;
3929 }
Andrey Ponomarenko07aea072012-11-12 16:15:07 +04003930 my ($ShortName, $TmplParams) = template_Base($SymbolInfo{$LibVersion}{$InfoId}{"ShortName"});
Andrey Ponomarenko16934472012-03-29 15:37:04 +04003931 my @TParams = ();
Andrey Ponomarenko35c44fd2012-06-18 17:50:25 +04003932 if(my @TPos = keys(%{$SymbolInfo{$LibVersion}{$InfoId}{"TParam"}}))
Andrey Ponomarenko16934472012-03-29 15:37:04 +04003933 { # parsing mode
Andrey Ponomarenko35c44fd2012-06-18 17:50:25 +04003934 foreach (@TPos) {
3935 push(@TParams, $SymbolInfo{$LibVersion}{$InfoId}{"TParam"}{$_}{"name"});
3936 }
Andrey Ponomarenko16934472012-03-29 15:37:04 +04003937 }
3938 elsif($TmplParams)
3939 { # remangling mode
3940 # support for old ABI dumps
Andrey Ponomarenko07aea072012-11-12 16:15:07 +04003941 @TParams = separate_Params($TmplParams, 0, 0);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003942 }
3943 if($SymbolInfo{$LibVersion}{$InfoId}{"Constructor"}) {
3944 $Mangled .= "C1";
3945 }
3946 elsif($SymbolInfo{$LibVersion}{$InfoId}{"Destructor"}) {
3947 $Mangled .= "D0";
3948 }
3949 elsif($ShortName)
3950 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04003951 if($SymbolInfo{$LibVersion}{$InfoId}{"Data"})
3952 {
Andrey Ponomarenko16934472012-03-29 15:37:04 +04003953 if(not $SymbolInfo{$LibVersion}{$InfoId}{"Class"}
Andrey Ponomarenko85043792012-05-14 16:48:07 +04003954 and isConstType($Return, $LibVersion))
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04003955 { # "const" global data is mangled as _ZL...
3956 $Mangled .= "L";
3957 }
3958 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003959 if($ShortName=~/\Aoperator(\W.*)\Z/)
3960 {
3961 my $Op = $1;
3962 $Op=~s/\A[ ]+//g;
3963 if(my $OpMngl = $OperatorMangling{$Op}) {
3964 $Mangled .= $OpMngl;
3965 }
3966 else { # conversion operator
3967 $Mangled .= "cv".mangle_param(getTypeIdByName($Op, $LibVersion), $LibVersion, \%Repl);
3968 }
3969 }
3970 else {
3971 $Mangled .= length($ShortName).$ShortName;
3972 }
3973 if(@TParams)
3974 { # templates
3975 $Mangled .= "I";
Andrey Ponomarenko1477d2c2012-11-12 18:55:45 +04003976 foreach my $TParam (@TParams) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003977 $Mangled .= mangle_template_param($TParam, $LibVersion, \%Repl);
3978 }
3979 $Mangled .= "E";
3980 }
3981 if(not $ClassId and @TParams) {
3982 add_substitution($ShortName, \%Repl, 0);
3983 }
3984 }
3985 if($ClassId or $NameSpace) {
3986 $Mangled .= "E";
3987 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +04003988 if(@TParams)
3989 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04003990 if($Return) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003991 $Mangled .= mangle_param($Return, $LibVersion, \%Repl);
3992 }
3993 }
3994 if(not $SymbolInfo{$LibVersion}{$InfoId}{"Data"})
3995 {
3996 my @Params = ();
3997 if(defined $SymbolInfo{$LibVersion}{$InfoId}{"Param"}
3998 and not $SymbolInfo{$LibVersion}{$InfoId}{"Destructor"}) {
3999 @Params = keys(%{$SymbolInfo{$LibVersion}{$InfoId}{"Param"}});
4000 }
4001 foreach my $ParamPos (sort {int($a) <=> int($b)} @Params)
4002 { # checking parameters
4003 my $ParamType_Id = $SymbolInfo{$LibVersion}{$InfoId}{"Param"}{$ParamPos}{"type"};
4004 $Mangled .= mangle_param($ParamType_Id, $LibVersion, \%Repl);
4005 }
4006 if(not @Params) {
4007 $Mangled .= "v";
4008 }
4009 }
4010 $Mangled = correct_incharge($InfoId, $LibVersion, $Mangled);
4011 $Mangled = write_stdcxx_substitution($Mangled);
4012 if($Mangled eq "_Z") {
4013 return "";
4014 }
4015 return $Mangled;
4016}
4017
4018sub correct_incharge($$$)
4019{
4020 my ($InfoId, $LibVersion, $Mangled) = @_;
4021 if($SymbolInfo{$LibVersion}{$InfoId}{"Constructor"})
4022 {
4023 if($MangledNames{$LibVersion}{$Mangled}) {
4024 $Mangled=~s/C1E/C2E/;
4025 }
4026 }
4027 elsif($SymbolInfo{$LibVersion}{$InfoId}{"Destructor"})
4028 {
4029 if($MangledNames{$LibVersion}{$Mangled}) {
4030 $Mangled=~s/D0E/D1E/;
4031 }
4032 if($MangledNames{$LibVersion}{$Mangled}) {
4033 $Mangled=~s/D1E/D2E/;
4034 }
4035 }
4036 return $Mangled;
4037}
4038
Andrey Ponomarenko07aea072012-11-12 16:15:07 +04004039sub template_Base($)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004040{ # NOTE: std::_Vector_base<mysqlpp::mysql_type_info>::_Vector_impl
Andrey Ponomarenko16934472012-03-29 15:37:04 +04004041 # NOTE: operators: >>, <<
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004042 my $Name = $_[0];
Andrey Ponomarenko16934472012-03-29 15:37:04 +04004043 if($Name!~/>\Z/ or $Name!~/</) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004044 return $Name;
4045 }
4046 my $TParams = $Name;
Andrey Ponomarenko16934472012-03-29 15:37:04 +04004047 while(my $CPos = find_center($TParams, "<"))
4048 { # search for the last <T>
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004049 $TParams = substr($TParams, $CPos);
4050 }
Andrey Ponomarenko16934472012-03-29 15:37:04 +04004051 if($TParams=~s/\A<(.+)>\Z/$1/) {
4052 $Name=~s/<\Q$TParams\E>\Z//;
4053 }
4054 else
4055 { # error
4056 $TParams = "";
4057 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004058 return ($Name, $TParams);
4059}
4060
4061sub get_sub_ns($)
4062{
4063 my $Name = $_[0];
4064 my @NS = ();
Andrey Ponomarenko16934472012-03-29 15:37:04 +04004065 while(my $CPos = find_center($Name, ":"))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004066 {
4067 push(@NS, substr($Name, 0, $CPos));
4068 $Name = substr($Name, $CPos);
4069 $Name=~s/\A:://;
4070 }
4071 return (join("::", @NS), $Name);
4072}
4073
4074sub mangle_ns($$$)
4075{
4076 my ($Name, $LibVersion, $Repl) = @_;
4077 if(my $Tid = $TName_Tid{$LibVersion}{$Name})
4078 {
4079 my $Mangled = mangle_param($Tid, $LibVersion, $Repl);
4080 $Mangled=~s/\AN(.+)E\Z/$1/;
4081 return $Mangled;
4082
4083 }
4084 else
4085 {
4086 my ($MangledNS, $SubNS) = ("", "");
4087 ($SubNS, $Name) = get_sub_ns($Name);
4088 if($SubNS) {
4089 $MangledNS .= mangle_ns($SubNS, $LibVersion, $Repl);
4090 }
4091 $MangledNS .= length($Name).$Name;
4092 add_substitution($MangledNS, $Repl, 0);
4093 return $MangledNS;
4094 }
4095}
4096
4097sub mangle_param($$$)
4098{
4099 my ($PTid, $LibVersion, $Repl) = @_;
4100 my ($MPrefix, $Mangled) = ("", "");
4101 my %ReplCopy = %{$Repl};
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04004102 my %BaseType = get_BaseType($PTid, $LibVersion);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004103 my $BaseType_Name = $BaseType{"Name"};
4104 if(not $BaseType_Name) {
4105 return "";
4106 }
Andrey Ponomarenko07aea072012-11-12 16:15:07 +04004107 my ($ShortName, $TmplParams) = template_Base($BaseType_Name);
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04004108 my $Suffix = get_BaseTypeQual($PTid, $LibVersion);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004109 while($Suffix=~s/\s*(const|volatile|restrict)\Z//g){};
4110 while($Suffix=~/(&|\*|const)\Z/)
4111 {
4112 if($Suffix=~s/[ ]*&\Z//) {
4113 $MPrefix .= "R";
4114 }
4115 if($Suffix=~s/[ ]*\*\Z//) {
4116 $MPrefix .= "P";
4117 }
4118 if($Suffix=~s/[ ]*const\Z//)
4119 {
4120 if($MPrefix=~/R|P/
4121 or $Suffix=~/&|\*/) {
4122 $MPrefix .= "K";
4123 }
4124 }
4125 if($Suffix=~s/[ ]*volatile\Z//) {
4126 $MPrefix .= "V";
4127 }
4128 #if($Suffix=~s/[ ]*restrict\Z//) {
4129 #$MPrefix .= "r";
4130 #}
4131 }
4132 if(my $Token = $IntrinsicMangling{$BaseType_Name}) {
4133 $Mangled .= $Token;
4134 }
4135 elsif($BaseType{"Type"}=~/(Class|Struct|Union|Enum)/)
4136 {
Andrey Ponomarenko16934472012-03-29 15:37:04 +04004137 my @TParams = ();
Andrey Ponomarenko35c44fd2012-06-18 17:50:25 +04004138 if(my @TPos = keys(%{$BaseType{"TParam"}}))
Andrey Ponomarenko16934472012-03-29 15:37:04 +04004139 { # parsing mode
Andrey Ponomarenko35c44fd2012-06-18 17:50:25 +04004140 foreach (@TPos) {
4141 push(@TParams, $BaseType{"TParam"}{$_}{"name"});
4142 }
Andrey Ponomarenko16934472012-03-29 15:37:04 +04004143 }
4144 elsif($TmplParams)
4145 { # remangling mode
4146 # support for old ABI dumps
Andrey Ponomarenko07aea072012-11-12 16:15:07 +04004147 @TParams = separate_Params($TmplParams, 0, 0);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004148 }
4149 my $MangledNS = "";
4150 my ($SubNS, $SName) = get_sub_ns($ShortName);
4151 if($SubNS) {
4152 $MangledNS .= mangle_ns($SubNS, $LibVersion, $Repl);
4153 }
4154 $MangledNS .= length($SName).$SName;
4155 if(@TParams) {
4156 add_substitution($MangledNS, $Repl, 0);
4157 }
4158 $Mangled .= "N".$MangledNS;
4159 if(@TParams)
4160 { # templates
4161 $Mangled .= "I";
4162 foreach my $TParam (@TParams) {
4163 $Mangled .= mangle_template_param($TParam, $LibVersion, $Repl);
4164 }
4165 $Mangled .= "E";
4166 }
4167 $Mangled .= "E";
4168 }
4169 elsif($BaseType{"Type"}=~/(FuncPtr|MethodPtr)/)
4170 {
4171 if($BaseType{"Type"} eq "MethodPtr") {
4172 $Mangled .= "M".mangle_param($BaseType{"Class"}, $LibVersion, $Repl)."F";
4173 }
4174 else {
4175 $Mangled .= "PF";
4176 }
4177 $Mangled .= mangle_param($BaseType{"Return"}, $LibVersion, $Repl);
4178 my @Params = keys(%{$BaseType{"Param"}});
4179 foreach my $Num (sort {int($a)<=>int($b)} @Params) {
4180 $Mangled .= mangle_param($BaseType{"Param"}{$Num}{"type"}, $LibVersion, $Repl);
4181 }
4182 if(not @Params) {
4183 $Mangled .= "v";
4184 }
4185 $Mangled .= "E";
4186 }
4187 elsif($BaseType{"Type"} eq "FieldPtr")
4188 {
4189 $Mangled .= "M".mangle_param($BaseType{"Class"}, $LibVersion, $Repl);
4190 $Mangled .= mangle_param($BaseType{"Return"}, $LibVersion, $Repl);
4191 }
4192 $Mangled = $MPrefix.$Mangled;# add prefix (RPK)
4193 if(my $Optimized = write_substitution($Mangled, \%ReplCopy))
4194 {
4195 if($Mangled eq $Optimized)
4196 {
4197 if($ShortName!~/::/)
4198 { # remove "N ... E"
4199 if($MPrefix) {
4200 $Mangled=~s/\A($MPrefix)N(.+)E\Z/$1$2/g;
4201 }
4202 else {
4203 $Mangled=~s/\AN(.+)E\Z/$1/g;
4204 }
4205 }
4206 }
4207 else {
4208 $Mangled = $Optimized;
4209 }
4210 }
4211 add_substitution($Mangled, $Repl, 1);
4212 return $Mangled;
4213}
4214
4215sub mangle_template_param($$$)
4216{ # types + literals
4217 my ($TParam, $LibVersion, $Repl) = @_;
4218 if(my $TPTid = $TName_Tid{$LibVersion}{$TParam}) {
4219 return mangle_param($TPTid, $LibVersion, $Repl);
4220 }
4221 elsif($TParam=~/\A(\d+)(\w+)\Z/)
4222 { # class_name<1u>::method(...)
4223 return "L".$IntrinsicMangling{$ConstantSuffixR{$2}}.$1."E";
4224 }
4225 elsif($TParam=~/\A\(([\w ]+)\)(\d+)\Z/)
4226 { # class_name<(signed char)1>::method(...)
4227 return "L".$IntrinsicMangling{$1}.$2."E";
4228 }
4229 elsif($TParam eq "true")
4230 { # class_name<true>::method(...)
4231 return "Lb1E";
4232 }
4233 elsif($TParam eq "false")
4234 { # class_name<true>::method(...)
4235 return "Lb0E";
4236 }
4237 else { # internal error
4238 return length($TParam).$TParam;
4239 }
4240}
4241
4242sub add_substitution($$$)
4243{
4244 my ($Value, $Repl, $Rec) = @_;
4245 if($Rec)
4246 { # subtypes
4247 my @Subs = ($Value);
4248 while($Value=~s/\A(R|P|K)//) {
4249 push(@Subs, $Value);
4250 }
4251 foreach (reverse(@Subs)) {
4252 add_substitution($_, $Repl, 0);
4253 }
4254 return;
4255 }
4256 return if($Value=~/\AS(\d*)_\Z/);
4257 $Value=~s/\AN(.+)E\Z/$1/g;
4258 return if(defined $Repl->{$Value});
4259 return if(length($Value)<=1);
4260 return if($StdcxxMangling{$Value});
4261 # check for duplicates
4262 my $Base = $Value;
4263 foreach my $Type (sort {$Repl->{$a}<=>$Repl->{$b}} sort keys(%{$Repl}))
4264 {
4265 my $Num = $Repl->{$Type};
4266 my $Replace = macro_mangle($Num);
4267 $Base=~s/\Q$Replace\E/$Type/;
4268 }
4269 if(my $OldNum = $Repl->{$Base})
4270 {
4271 $Repl->{$Value} = $OldNum;
4272 return;
4273 }
4274 my @Repls = sort {$b<=>$a} values(%{$Repl});
4275 if(@Repls) {
4276 $Repl->{$Value} = $Repls[0]+1;
4277 }
4278 else {
4279 $Repl->{$Value} = -1;
4280 }
4281 # register duplicates
4282 # upward
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04004283 $Base = $Value;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004284 foreach my $Type (sort {$Repl->{$a}<=>$Repl->{$b}} sort keys(%{$Repl}))
4285 {
4286 next if($Base eq $Type);
4287 my $Num = $Repl->{$Type};
4288 my $Replace = macro_mangle($Num);
4289 $Base=~s/\Q$Type\E/$Replace/;
4290 $Repl->{$Base} = $Repl->{$Value};
4291 }
4292}
4293
4294sub macro_mangle($)
4295{
4296 my $Num = $_[0];
4297 if($Num==-1) {
4298 return "S_";
4299 }
4300 else
4301 {
4302 my $Code = "";
4303 if($Num<10)
4304 { # S0_, S1_, S2_, ...
4305 $Code = $Num;
4306 }
4307 elsif($Num>=10 and $Num<=35)
4308 { # SA_, SB_, SC_, ...
4309 $Code = chr(55+$Num);
4310 }
4311 else
4312 { # S10_, S11_, S12_
4313 $Code = $Num-26; # 26 is length of english alphabet
4314 }
4315 return "S".$Code."_";
4316 }
4317}
4318
4319sub write_stdcxx_substitution($)
4320{
4321 my $Mangled = $_[0];
4322 if($StdcxxMangling{$Mangled}) {
4323 return $StdcxxMangling{$Mangled};
4324 }
4325 else
4326 {
4327 my @Repls = keys(%StdcxxMangling);
4328 @Repls = sort {length($b)<=>length($a)} sort {$b cmp $a} @Repls;
4329 foreach my $MangledType (@Repls)
4330 {
4331 my $Replace = $StdcxxMangling{$MangledType};
4332 #if($Mangled!~/$Replace/) {
4333 $Mangled=~s/N\Q$MangledType\EE/$Replace/g;
4334 $Mangled=~s/\Q$MangledType\E/$Replace/g;
4335 #}
4336 }
4337 }
4338 return $Mangled;
4339}
4340
4341sub write_substitution($$)
4342{
4343 my ($Mangled, $Repl) = @_;
4344 if(defined $Repl->{$Mangled}
4345 and my $MnglNum = $Repl->{$Mangled}) {
4346 $Mangled = macro_mangle($MnglNum);
4347 }
4348 else
4349 {
4350 my @Repls = keys(%{$Repl});
4351 #@Repls = sort {$Repl->{$a}<=>$Repl->{$b}} @Repls;
4352 # FIXME: how to apply replacements? by num or by pos
4353 @Repls = sort {length($b)<=>length($a)} sort {$b cmp $a} @Repls;
4354 foreach my $MangledType (@Repls)
4355 {
4356 my $Replace = macro_mangle($Repl->{$MangledType});
4357 if($Mangled!~/$Replace/) {
4358 $Mangled=~s/N\Q$MangledType\EE/$Replace/g;
4359 $Mangled=~s/\Q$MangledType\E/$Replace/g;
4360 }
4361 }
4362 }
4363 return $Mangled;
4364}
4365
4366sub delete_keywords($)
4367{
4368 my $TypeName = $_[0];
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04004369 $TypeName=~s/\b(enum|struct|union|class) //g;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004370 return $TypeName;
4371}
4372
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004373sub uncover_typedefs($$)
4374{
4375 my ($TypeName, $LibVersion) = @_;
4376 return "" if(not $TypeName);
4377 if(defined $Cache{"uncover_typedefs"}{$LibVersion}{$TypeName}) {
4378 return $Cache{"uncover_typedefs"}{$LibVersion}{$TypeName};
4379 }
Andrey Ponomarenko9927e332012-10-19 10:50:48 +04004380 my ($TypeName_New, $TypeName_Pre) = (formatName($TypeName, "T"), "");
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004381 while($TypeName_New ne $TypeName_Pre)
4382 {
4383 $TypeName_Pre = $TypeName_New;
4384 my $TypeName_Copy = $TypeName_New;
4385 my %Words = ();
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04004386 while($TypeName_Copy=~s/\b([a-z_]([\w:]*\w|))\b//io)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004387 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04004388 if(not $Intrinsic_Keywords{$1}) {
4389 $Words{$1} = 1;
4390 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004391 }
4392 foreach my $Word (keys(%Words))
4393 {
4394 my $BaseType_Name = $Typedef_BaseName{$LibVersion}{$Word};
4395 next if(not $BaseType_Name);
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04004396 next if($TypeName_New=~/\b(struct|union|enum)\s\Q$Word\E\b/);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004397 if($BaseType_Name=~/\([\*]+\)/)
4398 { # FuncPtr
4399 if($TypeName_New=~/\Q$Word\E(.*)\Z/)
4400 {
4401 my $Type_Suffix = $1;
4402 $TypeName_New = $BaseType_Name;
4403 if($TypeName_New=~s/\(([\*]+)\)/($1 $Type_Suffix)/) {
Andrey Ponomarenko9927e332012-10-19 10:50:48 +04004404 $TypeName_New = formatName($TypeName_New, "T");
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004405 }
4406 }
4407 }
4408 else
4409 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04004410 if($TypeName_New=~s/\b\Q$Word\E\b/$BaseType_Name/g) {
Andrey Ponomarenko9927e332012-10-19 10:50:48 +04004411 $TypeName_New = formatName($TypeName_New, "T");
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004412 }
4413 }
4414 }
4415 }
4416 return ($Cache{"uncover_typedefs"}{$LibVersion}{$TypeName} = $TypeName_New);
4417}
4418
4419sub isInternal($)
4420{
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04004421 if($_[0] and my $Info = $LibInfo{$Version}{"info"}{$_[0]})
4422 {
4423 if($Info=~/mngl[ ]*:[ ]*@(\d+) /)
4424 {
4425 if($LibInfo{$Version}{"info"}{$1}=~/\*[ ]*INTERNAL[ ]*\*/)
4426 { # _ZN7mysqlpp8DateTimeC1ERKS0_ *INTERNAL*
4427 return 1;
4428 }
4429 }
4430 }
4431 return 0;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004432}
4433
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04004434sub getDataVal($$)
4435{
4436 my ($InfoId, $TypeId) = @_;
4437 if(my $Info = $LibInfo{$Version}{"info"}{$InfoId})
4438 {
4439 if($Info=~/init[ ]*:[ ]*@(\d+) /)
4440 {
4441 if(defined $LibInfo{$Version}{"info_type"}{$1}
4442 and $LibInfo{$Version}{"info_type"}{$1} eq "nop_expr")
4443 { # char const* data = "str"
4444 # NOTE: disabled
4445 if(my $NopExpr = $LibInfo{$Version}{"info"}{$1})
4446 {
4447 if($NopExpr=~/op 0[ ]*:[ ]*@(\d+) /)
4448 {
4449 if(defined $LibInfo{$Version}{"info_type"}{$1}
4450 and $LibInfo{$Version}{"info_type"}{$1} eq "addr_expr")
4451 {
4452 if(my $AddrExpr = $LibInfo{$Version}{"info"}{$1})
4453 {
4454 if($AddrExpr=~/op 0[ ]*:[ ]*@(\d+) /)
4455 {
4456 return getInitVal($1, $TypeId);
4457 }
4458 }
4459 }
4460 }
4461 }
4462 }
4463 else {
4464 return getInitVal($1, $TypeId);
4465 }
4466 }
4467 }
4468 return undef;
4469}
4470
4471sub getInitVal($$)
4472{
4473 my ($InfoId, $TypeId) = @_;
4474 if(my $Info = $LibInfo{$Version}{"info"}{$InfoId})
4475 {
4476 if(my $InfoType = $LibInfo{$Version}{"info_type"}{$InfoId})
4477 {
4478 if($InfoType eq "integer_cst")
4479 {
4480 my $Val = getNodeIntCst($InfoId);
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04004481 if($TypeId and $TypeInfo{$Version}{$TypeId}{"Name"}=~/\Achar(| const)\Z/)
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04004482 { # characters
4483 $Val = chr($Val);
4484 }
4485 return $Val;
4486 }
4487 elsif($InfoType eq "string_cst") {
4488 return getNodeStrCst($InfoId);
4489 }
Andrey Ponomarenko01117f12012-06-26 12:23:02 +04004490 elsif($InfoType eq "var_decl")
4491 {
4492 if(my $Name = getNodeStrCst(getTreeAttr_Mngl($InfoId))) {
4493 return $Name;
4494 }
4495 }
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04004496 }
4497 }
4498 return undef;
4499}
4500
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004501sub set_Class_And_Namespace($)
4502{
4503 my $InfoId = $_[0];
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04004504 if(my $Info = $LibInfo{$Version}{"info"}{$InfoId})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004505 {
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04004506 if($Info=~/scpe[ ]*:[ ]*@(\d+) /)
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04004507 {
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04004508 my $NSInfoId = $1;
4509 if(my $InfoType = $LibInfo{$Version}{"info_type"}{$NSInfoId})
4510 {
4511 if($InfoType eq "namespace_decl") {
4512 $SymbolInfo{$Version}{$InfoId}{"NameSpace"} = getNameSpace($InfoId);
4513 }
4514 elsif($InfoType eq "record_type") {
4515 $SymbolInfo{$Version}{$InfoId}{"Class"} = $NSInfoId;
4516 }
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04004517 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004518 }
4519 }
4520 if($SymbolInfo{$Version}{$InfoId}{"Class"}
4521 or $SymbolInfo{$Version}{$InfoId}{"NameSpace"})
4522 { # identify language
4523 setLanguage($Version, "C++");
4524 }
4525}
4526
4527sub debugType($$)
4528{
4529 my ($Tid, $LibVersion) = @_;
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04004530 my %Type = get_Type($Tid, $LibVersion);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004531 printMsg("INFO", Dumper(\%Type));
4532}
4533
4534sub debugMangling($)
4535{
4536 my $LibVersion = $_[0];
4537 my %Mangled = ();
4538 foreach my $InfoId (keys(%{$SymbolInfo{$LibVersion}}))
4539 {
4540 if(my $Mngl = $SymbolInfo{$LibVersion}{$InfoId}{"MnglName"})
4541 {
4542 if($Mngl=~/\A(_Z|\?)/) {
4543 $Mangled{$Mngl}=$InfoId;
4544 }
4545 }
4546 }
4547 translateSymbols(keys(%Mangled), $LibVersion);
4548 foreach my $Mngl (keys(%Mangled))
4549 {
Andrey Ponomarenko85043792012-05-14 16:48:07 +04004550 my $U1 = modelUnmangled($Mangled{$Mngl}, "GCC");
4551 my $U2 = $tr_name{$Mngl};
4552 if($U1 ne $U2) {
4553 printMsg("INFO", "INCORRECT MANGLING:\n $Mngl\n $U1\n $U2\n");
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004554 }
4555 }
4556}
4557
4558sub linkSymbol($)
4559{ # link symbols from shared libraries
4560 # with the symbols from header files
4561 my $InfoId = $_[0];
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004562 # try to mangle symbol
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04004563 if((not check_gcc($GCC_PATH, "4") and $SymbolInfo{$Version}{$InfoId}{"Class"})
4564 or (check_gcc($GCC_PATH, "4") and not $SymbolInfo{$Version}{$InfoId}{"Class"}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004565 { # 1. GCC 3.x doesn't mangle class methods names in the TU dump (only functions and global data)
4566 # 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 +04004567 if(not $CheckHeadersOnly)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004568 {
4569 if(my $Mangled = $mangled_name_gcc{modelUnmangled($InfoId, "GCC")}) {
4570 return correct_incharge($InfoId, $Version, $Mangled);
4571 }
4572 }
Andrey Ponomarenko16934472012-03-29 15:37:04 +04004573 if($CheckHeadersOnly
4574 or not $BinaryOnly)
4575 { # 1. --headers-only mode
4576 # 2. not mangled src-only symbols
4577 if(my $Mangled = mangle_symbol($InfoId, $Version, "GCC")) {
4578 return $Mangled;
4579 }
4580 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004581 }
4582 return "";
4583}
4584
4585sub setLanguage($$)
4586{
4587 my ($LibVersion, $Lang) = @_;
4588 if(not $UserLang) {
4589 $COMMON_LANGUAGE{$LibVersion} = $Lang;
4590 }
4591}
4592
4593sub getSymbolInfo($)
4594{
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04004595 my $InfoId = $_[0];
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04004596 if(isInternal($InfoId)) {
4597 return;
4598 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04004599 ($SymbolInfo{$Version}{$InfoId}{"Header"}, $SymbolInfo{$Version}{$InfoId}{"Line"}) = getLocation($InfoId);
4600 if(not $SymbolInfo{$Version}{$InfoId}{"Header"}
Andrey Ponomarenkoa01311b2012-06-08 17:20:02 +04004601 or isBuiltIn($SymbolInfo{$Version}{$InfoId}{"Header"}))
4602 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04004603 delete($SymbolInfo{$Version}{$InfoId});
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004604 return;
4605 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04004606 setFuncAccess($InfoId);
4607 setFuncKind($InfoId);
Andrey Ponomarenkoa01311b2012-06-08 17:20:02 +04004608 if($SymbolInfo{$Version}{$InfoId}{"PseudoTemplate"})
4609 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04004610 delete($SymbolInfo{$Version}{$InfoId});
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004611 return;
4612 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04004613 $SymbolInfo{$Version}{$InfoId}{"Type"} = getFuncType($InfoId);
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04004614 if($SymbolInfo{$Version}{$InfoId}{"Return"} = getFuncReturn($InfoId))
4615 {
4616 if(not $TypeInfo{$Version}{$SymbolInfo{$Version}{$InfoId}{"Return"}}{"Name"})
4617 { # templates
4618 delete($SymbolInfo{$Version}{$InfoId});
4619 return;
4620 }
4621 }
4622 if(my $Rid = $SymbolInfo{$Version}{$InfoId}{"Return"})
4623 {
4624 if(defined $MissedTypedef{$Version}{$Rid})
4625 {
4626 if(my $AddedTid = $MissedTypedef{$Version}{$Rid}{"Tid"}) {
4627 $SymbolInfo{$Version}{$InfoId}{"Return"} = $AddedTid;
4628 }
4629 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004630 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04004631 if(not $SymbolInfo{$Version}{$InfoId}{"Return"}) {
4632 delete($SymbolInfo{$Version}{$InfoId}{"Return"});
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004633 }
Andrey Ponomarenkoa01311b2012-06-08 17:20:02 +04004634 my $Orig = getFuncOrig($InfoId);
4635 $SymbolInfo{$Version}{$InfoId}{"ShortName"} = getFuncShortName($Orig);
4636 if($SymbolInfo{$Version}{$InfoId}{"ShortName"}=~/\._/)
4637 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04004638 delete($SymbolInfo{$Version}{$InfoId});
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004639 return;
4640 }
Andrey Ponomarenkoa01311b2012-06-08 17:20:02 +04004641
4642 if(defined $TemplateInstance{$Version}{"Func"}{$Orig})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004643 {
Andrey Ponomarenkoa01311b2012-06-08 17:20:02 +04004644 my @TParams = getTParams($Orig, "Func");
4645 if(not @TParams)
4646 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04004647 delete($SymbolInfo{$Version}{$InfoId});
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004648 return;
4649 }
Andrey Ponomarenko16934472012-03-29 15:37:04 +04004650 foreach my $Pos (0 .. $#TParams) {
4651 $SymbolInfo{$Version}{$InfoId}{"TParam"}{$Pos}{"name"}=$TParams[$Pos];
4652 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004653 my $PrmsInLine = join(", ", @TParams);
Andrey Ponomarenko16934472012-03-29 15:37:04 +04004654 if($SymbolInfo{$Version}{$InfoId}{"ShortName"}=~/\Aoperator\W+\Z/)
4655 { # operator<< <T>, operator>> <T>
4656 $SymbolInfo{$Version}{$InfoId}{"ShortName"} .= " ";
4657 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04004658 $SymbolInfo{$Version}{$InfoId}{"ShortName"} .= "<".$PrmsInLine.">";
Andrey Ponomarenko9927e332012-10-19 10:50:48 +04004659 $SymbolInfo{$Version}{$InfoId}{"ShortName"} = formatName($SymbolInfo{$Version}{$InfoId}{"ShortName"}, "S");
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004660 }
4661 else
4662 { # support for GCC 3.4
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04004663 $SymbolInfo{$Version}{$InfoId}{"ShortName"}=~s/<.+>\Z//;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004664 }
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +04004665 if(my $MnglName = getTreeStr(getTreeAttr_Mngl($InfoId)))
4666 {
4667 if($OSgroup eq "windows")
4668 { # cut the offset
4669 $MnglName=~s/\@\d+\Z//g;
4670 }
4671 $SymbolInfo{$Version}{$InfoId}{"MnglName"} = $MnglName;
4672
4673 # NOTE: mangling of some symbols may change depending on GCC version
4674 # GCC 4.6: _ZN28QExplicitlySharedDataPointerI11QPixmapDataEC2IT_EERKS_IT_E
4675 # GCC 4.7: _ZN28QExplicitlySharedDataPointerI11QPixmapDataEC2ERKS1_
4676 }
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04004677
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04004678 if($SymbolInfo{$Version}{$InfoId}{"MnglName"}
Andrey Ponomarenko9927e332012-10-19 10:50:48 +04004679 and index($SymbolInfo{$Version}{$InfoId}{"MnglName"}, "_Z")!=0)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004680 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04004681 delete($SymbolInfo{$Version}{$InfoId});
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004682 return;
4683 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04004684 if(not $SymbolInfo{$Version}{$InfoId}{"Destructor"})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004685 { # destructors have an empty parameter list
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04004686 my $Skip = setFuncParams($InfoId);
Andrey Ponomarenko07aea072012-11-12 16:15:07 +04004687 if($Skip)
4688 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04004689 delete($SymbolInfo{$Version}{$InfoId});
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004690 return;
4691 }
4692 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04004693 set_Class_And_Namespace($InfoId);
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04004694 if(my $ClassId = $SymbolInfo{$Version}{$InfoId}{"Class"})
4695 {
4696 if(not $TypeInfo{$Version}{$ClassId}{"Name"})
4697 { # templates
4698 delete($SymbolInfo{$Version}{$InfoId});
4699 return;
4700 }
4701 }
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04004702 if(not $CheckHeadersOnly)
4703 {
4704 if($SymbolInfo{$Version}{$InfoId}{"Type"} eq "Function"
4705 and not $SymbolInfo{$Version}{$InfoId}{"Class"}
4706 and link_symbol($SymbolInfo{$Version}{$InfoId}{"ShortName"}, $Version, "-Deps"))
4707 { # functions (C++): not mangled in library, but are mangled in TU dump
4708 if(not $SymbolInfo{$Version}{$InfoId}{"MnglName"}
4709 or not link_symbol($SymbolInfo{$Version}{$InfoId}{"MnglName"}, $Version, "-Deps")) {
4710 $SymbolInfo{$Version}{$InfoId}{"MnglName"} = $SymbolInfo{$Version}{$InfoId}{"ShortName"};
4711 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004712 }
4713 }
Andrey Ponomarenko35c44fd2012-06-18 17:50:25 +04004714 if($LibInfo{$Version}{"info"}{$InfoId}=~/ lang:[ ]*C /i)
4715 { # extern "C"
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04004716 $SymbolInfo{$Version}{$InfoId}{"Lang"} = "C";
Andrey Ponomarenko35c44fd2012-06-18 17:50:25 +04004717 $SymbolInfo{$Version}{$InfoId}{"MnglName"} = $SymbolInfo{$Version}{$InfoId}{"ShortName"};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004718 }
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04004719 if($UserLang and $UserLang eq "C")
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004720 { # --lang=C option
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04004721 $SymbolInfo{$Version}{$InfoId}{"MnglName"} = $SymbolInfo{$Version}{$InfoId}{"ShortName"};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004722 }
4723 if($COMMON_LANGUAGE{$Version} eq "C++")
4724 { # correct mangled & short names
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04004725 # C++ or --headers-only mode
4726 if($SymbolInfo{$Version}{$InfoId}{"ShortName"}=~/\A__(comp|base|deleting)_(c|d)tor\Z/)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004727 { # support for old GCC versions: reconstruct real names for constructors and destructors
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04004728 $SymbolInfo{$Version}{$InfoId}{"ShortName"} = getNameByInfo(getTypeDeclId($SymbolInfo{$Version}{$InfoId}{"Class"}));
4729 $SymbolInfo{$Version}{$InfoId}{"ShortName"}=~s/<.+>\Z//;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004730 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04004731 if(not $SymbolInfo{$Version}{$InfoId}{"MnglName"})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004732 { # try to mangle symbol (link with libraries)
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04004733 if(my $Mangled = linkSymbol($InfoId)) {
4734 $SymbolInfo{$Version}{$InfoId}{"MnglName"} = $Mangled;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004735 }
4736 }
4737 if($OStarget eq "windows")
4738 { # link MS C++ symbols from library with GCC symbols from headers
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04004739 if(my $Mangled1 = $mangled_name{$Version}{modelUnmangled($InfoId, "MSVC")})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004740 { # exported symbols
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04004741 $SymbolInfo{$Version}{$InfoId}{"MnglName"} = $Mangled1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004742 }
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04004743 elsif(my $Mangled2 = mangle_symbol($InfoId, $Version, "MSVC"))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004744 { # pure virtual symbols
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04004745 $SymbolInfo{$Version}{$InfoId}{"MnglName"} = $Mangled2;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004746 }
4747 }
4748 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04004749 if(not $SymbolInfo{$Version}{$InfoId}{"MnglName"})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004750 { # can't detect symbol name
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04004751 delete($SymbolInfo{$Version}{$InfoId});
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004752 return;
4753 }
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04004754 if(not $SymbolInfo{$Version}{$InfoId}{"Constructor"}
Andrey Ponomarenkoa01311b2012-06-08 17:20:02 +04004755 and my $Spec = getVirtSpec($Orig))
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04004756 { # identify virtual and pure virtual functions
4757 # NOTE: constructors cannot be virtual
4758 # NOTE: in GCC 4.7 D1 destructors have no virtual spec
4759 # in the TU dump, so taking it from the original symbol
4760 if(not ($SymbolInfo{$Version}{$InfoId}{"Destructor"}
4761 and $SymbolInfo{$Version}{$InfoId}{"MnglName"}=~/D2E/))
4762 { # NOTE: D2 destructors are not present in a v-table
4763 $SymbolInfo{$Version}{$InfoId}{$Spec} = 1;
4764 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004765 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04004766 if(isInline($InfoId)) {
4767 $SymbolInfo{$Version}{$InfoId}{"InLine"} = 1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004768 }
Andrey Ponomarenko82bc2572012-11-14 13:55:30 +04004769 if(hasThrow($InfoId)) {
Andrey Ponomarenkoe3d6bf02012-11-14 11:49:09 +04004770 $SymbolInfo{$Version}{$InfoId}{"Throw"} = 1;
4771 }
Andrey Ponomarenkob8d203d2012-05-25 18:11:07 +04004772 if($LibInfo{$Version}{"info"}{$InfoId}=~/ artificial /i) {
4773 $SymbolInfo{$Version}{$InfoId}{"Artificial"} = 1;
4774 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04004775 if($SymbolInfo{$Version}{$InfoId}{"Constructor"}
4776 and my $ClassId = $SymbolInfo{$Version}{$InfoId}{"Class"})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004777 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04004778 if(not $SymbolInfo{$Version}{$InfoId}{"InLine"}
Andrey Ponomarenkob8d203d2012-05-25 18:11:07 +04004779 and not $SymbolInfo{$Version}{$InfoId}{"Artificial"})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004780 { # inline or auto-generated constructor
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04004781 delete($TypeInfo{$Version}{$ClassId}{"Copied"});
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004782 }
4783 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +04004784 if(my $Symbol = $SymbolInfo{$Version}{$InfoId}{"MnglName"})
4785 {
Andrey Ponomarenko35c44fd2012-06-18 17:50:25 +04004786 if(not selectSymbol($Symbol, $SymbolInfo{$Version}{$InfoId}, "Dump", $Version))
4787 { # non-target symbols
4788 delete($SymbolInfo{$Version}{$InfoId});
4789 return;
Andrey Ponomarenko85043792012-05-14 16:48:07 +04004790 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004791 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04004792 if($SymbolInfo{$Version}{$InfoId}{"Type"} eq "Method"
4793 or $SymbolInfo{$Version}{$InfoId}{"Constructor"}
4794 or $SymbolInfo{$Version}{$InfoId}{"Destructor"}
4795 or $SymbolInfo{$Version}{$InfoId}{"Class"})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004796 {
Andrey Ponomarenko9927e332012-10-19 10:50:48 +04004797 if($SymbolInfo{$Version}{$InfoId}{"MnglName"}!~/\A(_Z|\?)/)
4798 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04004799 delete($SymbolInfo{$Version}{$InfoId});
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004800 return;
4801 }
4802 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04004803 if($SymbolInfo{$Version}{$InfoId}{"MnglName"})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004804 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04004805 if($MangledNames{$Version}{$SymbolInfo{$Version}{$InfoId}{"MnglName"}})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004806 { # one instance for one mangled name only
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04004807 delete($SymbolInfo{$Version}{$InfoId});
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004808 return;
4809 }
4810 else {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04004811 $MangledNames{$Version}{$SymbolInfo{$Version}{$InfoId}{"MnglName"}} = 1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004812 }
4813 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04004814 if($SymbolInfo{$Version}{$InfoId}{"Constructor"}
4815 or $SymbolInfo{$Version}{$InfoId}{"Destructor"}) {
4816 delete($SymbolInfo{$Version}{$InfoId}{"Return"});
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004817 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04004818 if($SymbolInfo{$Version}{$InfoId}{"MnglName"}=~/\A(_Z|\?)/
4819 and $SymbolInfo{$Version}{$InfoId}{"Class"})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004820 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04004821 if($SymbolInfo{$Version}{$InfoId}{"Type"} eq "Function")
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004822 { # static methods
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04004823 $SymbolInfo{$Version}{$InfoId}{"Static"} = 1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004824 }
4825 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04004826 if(getFuncLink($InfoId) eq "Static") {
4827 $SymbolInfo{$Version}{$InfoId}{"Static"} = 1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004828 }
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04004829 if($SymbolInfo{$Version}{$InfoId}{"MnglName"}=~/\A(_Z|\?)/)
4830 {
4831 if(my $Unmangled = $tr_name{$SymbolInfo{$Version}{$InfoId}{"MnglName"}})
4832 {
Andrey Ponomarenko9927e332012-10-19 10:50:48 +04004833 if($Unmangled=~/\.\_\d/)
4834 {
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04004835 delete($SymbolInfo{$Version}{$InfoId});
4836 return;
4837 }
4838 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004839 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04004840 delete($SymbolInfo{$Version}{$InfoId}{"Type"});
4841 if($SymbolInfo{$Version}{$InfoId}{"MnglName"}=~/\A_ZN(V|)K/) {
4842 $SymbolInfo{$Version}{$InfoId}{"Const"} = 1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004843 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04004844 if($SymbolInfo{$Version}{$InfoId}{"MnglName"}=~/\A_ZN(K|)V/) {
4845 $SymbolInfo{$Version}{$InfoId}{"Volatile"} = 1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004846 }
Andrey Ponomarenko07aea072012-11-12 16:15:07 +04004847
4848 if($WeakSymbols{$Version}{$SymbolInfo{$Version}{$InfoId}{"MnglName"}}) {
4849 $SymbolInfo{$Version}{$InfoId}{"Weak"} = 1;
4850 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004851}
4852
4853sub isInline($)
4854{ # "body: undefined" in the tree
4855 # -fkeep-inline-functions GCC option should be specified
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04004856 if($_[0] and my $Info = $LibInfo{$Version}{"info"}{$_[0]})
4857 {
4858 if($Info=~/ undefined /i) {
4859 return 0;
4860 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004861 }
4862 return 1;
4863}
4864
Andrey Ponomarenkoe3d6bf02012-11-14 11:49:09 +04004865sub hasThrow($)
4866{
4867 if($_[0] and my $Info = $LibInfo{$Version}{"info"}{$_[0]})
4868 {
4869 if($Info=~/type[ ]*:[ ]*@(\d+) /) {
4870 return getTreeAttr_Unql($1, "unql");
4871 }
4872 }
4873 return 1;
4874}
4875
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004876sub getTypeId($)
4877{
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04004878 if($_[0] and my $Info = $LibInfo{$Version}{"info"}{$_[0]})
4879 {
4880 if($Info=~/type[ ]*:[ ]*@(\d+) /) {
4881 return $1;
4882 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004883 }
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04004884 return "";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004885}
4886
4887sub setTypeMemb($$)
4888{
4889 my ($TypeId, $TypeAttr) = @_;
4890 my $TypeType = $TypeAttr->{"Type"};
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04004891 my ($Pos, $UnnamedPos) = (0, 0);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004892 if($TypeType eq "Enum")
4893 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04004894 my $TypeMembInfoId = getTreeAttr_Csts($TypeId);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004895 while($TypeMembInfoId)
4896 {
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04004897 $TypeAttr->{"Memb"}{$Pos}{"value"} = getEnumMembVal($TypeMembInfoId);
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04004898 my $MembName = getTreeStr(getTreeAttr_Purp($TypeMembInfoId));
4899 $TypeAttr->{"Memb"}{$Pos}{"name"} = $MembName;
4900 $EnumMembName_Id{$Version}{getTreeAttr_Valu($TypeMembInfoId)} = ($TypeAttr->{"NameSpace"})?$TypeAttr->{"NameSpace"}."::".$MembName:$MembName;
4901 $TypeMembInfoId = getNextElem($TypeMembInfoId);
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04004902 $Pos += 1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004903 }
4904 }
4905 elsif($TypeType=~/\A(Struct|Class|Union)\Z/)
4906 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04004907 my $TypeMembInfoId = getTreeAttr_Flds($TypeId);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004908 while($TypeMembInfoId)
4909 {
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04004910 my $IType = $LibInfo{$Version}{"info_type"}{$TypeMembInfoId};
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04004911 my $MInfo = $LibInfo{$Version}{"info"}{$TypeMembInfoId};
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04004912 if(not $IType or $IType ne "field_decl")
4913 { # search for fields, skip other stuff in the declaration
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04004914 $TypeMembInfoId = getNextElem($TypeMembInfoId);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004915 next;
4916 }
Andrey Ponomarenko01117f12012-06-26 12:23:02 +04004917 my $StructMembName = getTreeStr(getTreeAttr_Name($TypeMembInfoId));
4918 if(index($StructMembName, "_vptr.")!=-1)
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04004919 { # virtual tables
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04004920 $TypeMembInfoId = getNextElem($TypeMembInfoId);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004921 next;
4922 }
4923 if(not $StructMembName)
4924 { # unnamed fields
Andrey Ponomarenko01117f12012-06-26 12:23:02 +04004925 if(index($TypeAttr->{"Name"}, "_type_info_pseudo")==-1)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004926 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04004927 my $UnnamedTid = getTreeAttr_Type($TypeMembInfoId);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004928 my $UnnamedTName = getNameByInfo(getTypeDeclId($UnnamedTid));
4929 if(isAnon($UnnamedTName))
4930 { # rename unnamed fields to unnamed0, unnamed1, ...
4931 $StructMembName = "unnamed".($UnnamedPos++);
4932 }
4933 }
4934 }
4935 if(not $StructMembName)
4936 { # unnamed fields and base classes
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04004937 $TypeMembInfoId = getNextElem($TypeMembInfoId);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004938 next;
4939 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04004940 my $MembTypeId = getTreeAttr_Type($TypeMembInfoId);
4941 if(defined $MissedTypedef{$Version}{$MembTypeId})
4942 {
4943 if(my $AddedTid = $MissedTypedef{$Version}{$MembTypeId}{"Tid"}) {
4944 $MembTypeId = $AddedTid;
4945 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004946 }
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04004947 $TypeAttr->{"Memb"}{$Pos}{"type"} = $MembTypeId;
4948 $TypeAttr->{"Memb"}{$Pos}{"name"} = $StructMembName;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004949 if((my $Access = getTreeAccess($TypeMembInfoId)) ne "public")
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04004950 { # marked only protected and private, public by default
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04004951 $TypeAttr->{"Memb"}{$Pos}{"access"} = $Access;
4952 }
4953 if($MInfo=~/spec:\s*mutable /)
4954 { # mutable fields
4955 $TypeAttr->{"Memb"}{$Pos}{"mutable"} = 1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004956 }
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +04004957 if(my $Algn = getAlgn($TypeMembInfoId)) {
4958 $TypeAttr->{"Memb"}{$Pos}{"algn"} = $Algn;
4959 }
4960 if(my $BFSize = getBitField($TypeMembInfoId))
4961 { # in bits
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04004962 $TypeAttr->{"Memb"}{$Pos}{"bitfield"} = $BFSize;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004963 }
4964 else
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +04004965 { # in bytes
4966 $TypeAttr->{"Memb"}{$Pos}{"algn"} /= $BYTE_SIZE;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004967 }
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +04004968
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04004969 $TypeMembInfoId = getNextElem($TypeMembInfoId);
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04004970 $Pos += 1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004971 }
4972 }
4973}
4974
4975sub setFuncParams($)
4976{
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04004977 my $InfoId = $_[0];
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04004978 my $ParamInfoId = getTreeAttr_Args($InfoId);
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04004979 if(getFuncType($InfoId) eq "Method")
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004980 { # check type of "this" pointer
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04004981 my $ObjectTypeId = getTreeAttr_Type($ParamInfoId);
4982 if(my $ObjectName = $TypeInfo{$Version}{$ObjectTypeId}{"Name"})
Andrey Ponomarenko85043792012-05-14 16:48:07 +04004983 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04004984 if($ObjectName=~/\bconst(| volatile)\*const\b/) {
Andrey Ponomarenko85043792012-05-14 16:48:07 +04004985 $SymbolInfo{$Version}{$InfoId}{"Const"} = 1;
4986 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04004987 if($ObjectName=~/\bvolatile\b/) {
Andrey Ponomarenko85043792012-05-14 16:48:07 +04004988 $SymbolInfo{$Version}{$InfoId}{"Volatile"} = 1;
4989 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004990 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +04004991 else
4992 { # skip
4993 return 1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004994 }
4995 $ParamInfoId = getNextElem($ParamInfoId);
4996 }
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04004997 my ($Pos, $Vtt_Pos) = (0, -1);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004998 while($ParamInfoId)
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04004999 { # formal args
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04005000 my $ParamTypeId = getTreeAttr_Type($ParamInfoId);
5001 my $ParamName = getTreeStr(getTreeAttr_Name($ParamInfoId));
5002 if(not $ParamName)
5003 { # unnamed
5004 $ParamName = "p".($Pos+1);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005005 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04005006 if(defined $MissedTypedef{$Version}{$ParamTypeId})
5007 {
5008 if(my $AddedTid = $MissedTypedef{$Version}{$ParamTypeId}{"Tid"}) {
5009 $ParamTypeId = $AddedTid;
5010 }
5011 }
5012 my $PType = $TypeInfo{$Version}{$ParamTypeId}{"Type"};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005013 if(not $PType or $PType eq "Unknown") {
5014 return 1;
5015 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04005016 my $PTName = $TypeInfo{$Version}{$ParamTypeId}{"Name"};
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04005017 if(not $PTName) {
5018 return 1;
5019 }
5020 if($PTName eq "void") {
5021 last;
5022 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005023 if($ParamName eq "__vtt_parm"
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04005024 and $TypeInfo{$Version}{$ParamTypeId}{"Name"} eq "void const**")
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005025 {
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04005026 $Vtt_Pos = $Pos;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005027 $ParamInfoId = getNextElem($ParamInfoId);
5028 next;
5029 }
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04005030 $SymbolInfo{$Version}{$InfoId}{"Param"}{$Pos}{"type"} = $ParamTypeId;
5031 $SymbolInfo{$Version}{$InfoId}{"Param"}{$Pos}{"name"} = $ParamName;
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04005032 if(my $Algn = getAlgn($ParamInfoId)) {
5033 $SymbolInfo{$Version}{$InfoId}{"Param"}{$Pos}{"algn"} = $Algn/$BYTE_SIZE;
5034 }
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04005035 if(not $SymbolInfo{$Version}{$InfoId}{"Param"}{$Pos}{"name"}) {
5036 $SymbolInfo{$Version}{$InfoId}{"Param"}{$Pos}{"name"} = "p".($Pos+1);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005037 }
5038 if($LibInfo{$Version}{"info"}{$ParamInfoId}=~/spec:\s*register /)
5039 { # foo(register type arg)
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04005040 $SymbolInfo{$Version}{$InfoId}{"Param"}{$Pos}{"reg"} = 1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005041 }
5042 $ParamInfoId = getNextElem($ParamInfoId);
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04005043 $Pos += 1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005044 }
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04005045 if(setFuncArgs($InfoId, $Vtt_Pos)) {
Andrey Ponomarenko01117f12012-06-26 12:23:02 +04005046 $SymbolInfo{$Version}{$InfoId}{"Param"}{$Pos}{"type"} = "-1";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005047 }
5048 return 0;
5049}
5050
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04005051sub setFuncArgs($$)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005052{
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04005053 my ($InfoId, $Vtt_Pos) = @_;
5054 my $FuncTypeId = getFuncTypeId($InfoId);
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04005055 my $ParamListElemId = getTreeAttr_Prms($FuncTypeId);
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04005056 if(getFuncType($InfoId) eq "Method") {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005057 $ParamListElemId = getNextElem($ParamListElemId);
5058 }
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04005059 if(not $ParamListElemId)
5060 { # foo(...)
5061 return 1;
5062 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005063 my $HaveVoid = 0;
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04005064 my $Pos = 0;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005065 while($ParamListElemId)
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04005066 { # actual params: may differ from formal args
5067 # formal int*const
5068 # actual: int*
5069 if($Vtt_Pos!=-1 and $Pos==$Vtt_Pos)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005070 {
5071 $Vtt_Pos=-1;
5072 $ParamListElemId = getNextElem($ParamListElemId);
5073 next;
5074 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04005075 my $ParamTypeId = getTreeAttr_Valu($ParamListElemId);
5076 if($TypeInfo{$Version}{$ParamTypeId}{"Name"} eq "void")
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04005077 {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005078 $HaveVoid = 1;
5079 last;
5080 }
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04005081 elsif(not defined $SymbolInfo{$Version}{$InfoId}{"Param"}{$Pos}{"type"})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005082 {
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04005083 $SymbolInfo{$Version}{$InfoId}{"Param"}{$Pos}{"type"} = $ParamTypeId;
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04005084 if(not $SymbolInfo{$Version}{$InfoId}{"Param"}{$Pos}{"name"})
5085 { # unnamed
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04005086 $SymbolInfo{$Version}{$InfoId}{"Param"}{$Pos}{"name"} = "p".($Pos+1);
5087 }
5088 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04005089 if(my $PurpId = getTreeAttr_Purp($ParamListElemId))
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04005090 { # default arguments
Andrey Ponomarenko01117f12012-06-26 12:23:02 +04005091 if(my $PurpType = $LibInfo{$Version}{"info_type"}{$PurpId})
5092 {
5093 my $Val = getInitVal($PurpId, $ParamTypeId);
5094 if(defined $Val) {
5095 $SymbolInfo{$Version}{$InfoId}{"Param"}{$Pos}{"default"} = $Val;
5096 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005097 }
5098 }
5099 $ParamListElemId = getNextElem($ParamListElemId);
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04005100 $Pos += 1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005101 }
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04005102 return ($Pos>=1 and not $HaveVoid);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005103}
5104
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04005105sub getTreeAttr_Chan($)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005106{
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04005107 if($_[0] and my $Info = $LibInfo{$Version}{"info"}{$_[0]})
5108 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04005109 if($Info=~/chan[ ]*:[ ]*@(\d+) /) {
5110 return $1;
5111 }
5112 }
5113 return "";
5114}
5115
5116sub getTreeAttr_Chain($)
5117{
5118 if($_[0] and my $Info = $LibInfo{$Version}{"info"}{$_[0]})
5119 {
5120 if($Info=~/chain[ ]*:[ ]*@(\d+) /) {
5121 return $1;
5122 }
5123 }
5124 return "";
5125}
5126
Andrey Ponomarenkoe3d6bf02012-11-14 11:49:09 +04005127sub getTreeAttr_Unql($)
5128{
5129 if($_[0] and my $Info = $LibInfo{$Version}{"info"}{$_[0]})
5130 {
5131 if($Info=~/unql[ ]*:[ ]*@(\d+) /) {
5132 return $1;
5133 }
5134 }
5135 return "";
5136}
5137
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04005138sub getTreeAttr_Scpe($)
5139{
5140 if($_[0] and my $Info = $LibInfo{$Version}{"info"}{$_[0]})
5141 {
5142 if($Info=~/scpe[ ]*:[ ]*@(\d+) /) {
5143 return $1;
5144 }
5145 }
5146 return "";
5147}
5148
5149sub getTreeAttr_Type($)
5150{
5151 if($_[0] and my $Info = $LibInfo{$Version}{"info"}{$_[0]})
5152 {
5153 if($Info=~/type[ ]*:[ ]*@(\d+) /) {
5154 return $1;
5155 }
5156 }
5157 return "";
5158}
5159
5160sub getTreeAttr_Name($)
5161{
5162 if($_[0] and my $Info = $LibInfo{$Version}{"info"}{$_[0]})
5163 {
5164 if($Info=~/name[ ]*:[ ]*@(\d+) /) {
5165 return $1;
5166 }
5167 }
5168 return "";
5169}
5170
5171sub getTreeAttr_Mngl($)
5172{
5173 if($_[0] and my $Info = $LibInfo{$Version}{"info"}{$_[0]})
5174 {
5175 if($Info=~/mngl[ ]*:[ ]*@(\d+) /) {
5176 return $1;
5177 }
5178 }
5179 return "";
5180}
5181
5182sub getTreeAttr_Prms($)
5183{
5184 if($_[0] and my $Info = $LibInfo{$Version}{"info"}{$_[0]})
5185 {
5186 if($Info=~/prms[ ]*:[ ]*@(\d+) /) {
5187 return $1;
5188 }
5189 }
5190 return "";
5191}
5192
5193sub getTreeAttr_Fncs($)
5194{
5195 if($_[0] and my $Info = $LibInfo{$Version}{"info"}{$_[0]})
5196 {
5197 if($Info=~/fncs[ ]*:[ ]*@(\d+) /) {
5198 return $1;
5199 }
5200 }
5201 return "";
5202}
5203
5204sub getTreeAttr_Csts($)
5205{
5206 if($_[0] and my $Info = $LibInfo{$Version}{"info"}{$_[0]})
5207 {
5208 if($Info=~/csts[ ]*:[ ]*@(\d+) /) {
5209 return $1;
5210 }
5211 }
5212 return "";
5213}
5214
5215sub getTreeAttr_Purp($)
5216{
5217 if($_[0] and my $Info = $LibInfo{$Version}{"info"}{$_[0]})
5218 {
5219 if($Info=~/purp[ ]*:[ ]*@(\d+) /) {
5220 return $1;
5221 }
5222 }
5223 return "";
5224}
5225
5226sub getTreeAttr_Valu($)
5227{
5228 if($_[0] and my $Info = $LibInfo{$Version}{"info"}{$_[0]})
5229 {
5230 if($Info=~/valu[ ]*:[ ]*@(\d+) /) {
5231 return $1;
5232 }
5233 }
5234 return "";
5235}
5236
5237sub getTreeAttr_Flds($)
5238{
5239 if($_[0] and my $Info = $LibInfo{$Version}{"info"}{$_[0]})
5240 {
5241 if($Info=~/flds[ ]*:[ ]*@(\d+) /) {
5242 return $1;
5243 }
5244 }
5245 return "";
5246}
5247
5248sub getTreeAttr_Args($)
5249{
5250 if($_[0] and my $Info = $LibInfo{$Version}{"info"}{$_[0]})
5251 {
5252 if($Info=~/args[ ]*:[ ]*@(\d+) /) {
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04005253 return $1;
5254 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005255 }
5256 return "";
5257}
5258
5259sub getTreeValue($)
5260{
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04005261 if($_[0] and my $Info = $LibInfo{$Version}{"info"}{$_[0]})
5262 {
5263 if($Info=~/low[ ]*:[ ]*([^ ]+) /) {
5264 return $1;
5265 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005266 }
5267 return "";
5268}
5269
5270sub getTreeAccess($)
5271{
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04005272 if($_[0] and my $Info = $LibInfo{$Version}{"info"}{$_[0]})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005273 {
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04005274 if($Info=~/accs[ ]*:[ ]*([a-zA-Z]+) /)
5275 {
5276 my $Access = $1;
5277 if($Access eq "prot") {
5278 return "protected";
5279 }
5280 elsif($Access eq "priv") {
5281 return "private";
5282 }
5283 }
5284 elsif($Info=~/ protected /)
5285 { # support for old GCC versions
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005286 return "protected";
5287 }
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04005288 elsif($Info=~/ private /)
5289 { # support for old GCC versions
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005290 return "private";
5291 }
5292 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005293 return "public";
5294}
5295
5296sub setFuncAccess($)
5297{
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04005298 my $Access = getTreeAccess($_[0]);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005299 if($Access eq "protected") {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04005300 $SymbolInfo{$Version}{$_[0]}{"Protected"} = 1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005301 }
5302 elsif($Access eq "private") {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04005303 $SymbolInfo{$Version}{$_[0]}{"Private"} = 1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005304 }
5305}
5306
5307sub setTypeAccess($$)
5308{
5309 my ($TypeId, $TypeAttr) = @_;
5310 my $Access = getTreeAccess($TypeId);
5311 if($Access eq "protected") {
5312 $TypeAttr->{"Protected"} = 1;
5313 }
5314 elsif($Access eq "private") {
5315 $TypeAttr->{"Private"} = 1;
5316 }
5317}
5318
5319sub setFuncKind($)
5320{
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04005321 if($_[0] and my $Info = $LibInfo{$Version}{"info"}{$_[0]})
5322 {
5323 if($Info=~/pseudo tmpl/) {
5324 $SymbolInfo{$Version}{$_[0]}{"PseudoTemplate"} = 1;
5325 }
5326 elsif($Info=~/ constructor /) {
5327 $SymbolInfo{$Version}{$_[0]}{"Constructor"} = 1;
5328 }
5329 elsif($Info=~/ destructor /) {
5330 $SymbolInfo{$Version}{$_[0]}{"Destructor"} = 1;
5331 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005332 }
5333}
5334
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04005335sub getVirtSpec($)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005336{
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04005337 if($_[0] and my $Info = $LibInfo{$Version}{"info"}{$_[0]})
5338 {
5339 if($Info=~/spec[ ]*:[ ]*pure /) {
5340 return "PureVirt";
5341 }
5342 elsif($Info=~/spec[ ]*:[ ]*virt /) {
5343 return "Virt";
5344 }
5345 elsif($Info=~/ pure\s+virtual /)
5346 { # support for old GCC versions
5347 return "PureVirt";
5348 }
5349 elsif($Info=~/ virtual /)
5350 { # support for old GCC versions
5351 return "Virt";
5352 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005353 }
5354 return "";
5355}
5356
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005357sub getFuncLink($)
5358{
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04005359 if($_[0] and my $Info = $LibInfo{$Version}{"info"}{$_[0]})
5360 {
5361 if($Info=~/link[ ]*:[ ]*static /) {
5362 return "Static";
5363 }
5364 elsif($Info=~/link[ ]*:[ ]*([a-zA-Z]+) /) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005365 return $1;
5366 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005367 }
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04005368 return "";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005369}
5370
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005371sub get_IntNameSpace($$)
5372{
5373 my ($Interface, $LibVersion) = @_;
5374 return "" if(not $Interface or not $LibVersion);
5375 if(defined $Cache{"get_IntNameSpace"}{$Interface}{$LibVersion}) {
5376 return $Cache{"get_IntNameSpace"}{$Interface}{$LibVersion};
5377 }
5378 my $Signature = get_Signature($Interface, $LibVersion);
5379 if($Signature=~/\:\:/)
5380 {
5381 my $FounNameSpace = 0;
5382 foreach my $NameSpace (sort {get_depth($b)<=>get_depth($a)} keys(%{$NestedNameSpaces{$LibVersion}}))
5383 {
5384 if($Signature=~/(\A|\s+for\s+)\Q$NameSpace\E\:\:/) {
5385 return ($Cache{"get_IntNameSpace"}{$Interface}{$LibVersion} = $NameSpace);
5386 }
5387 }
5388 }
5389 else {
5390 return ($Cache{"get_IntNameSpace"}{$Interface}{$LibVersion} = "");
5391 }
5392}
5393
5394sub parse_TypeNameSpace($$)
5395{
5396 my ($TypeName, $LibVersion) = @_;
5397 return "" if(not $TypeName or not $LibVersion);
5398 if(defined $Cache{"parse_TypeNameSpace"}{$TypeName}{$LibVersion}) {
5399 return $Cache{"parse_TypeNameSpace"}{$TypeName}{$LibVersion};
5400 }
5401 if($TypeName=~/\:\:/)
5402 {
5403 my $FounNameSpace = 0;
5404 foreach my $NameSpace (sort {get_depth($b)<=>get_depth($a)} keys(%{$NestedNameSpaces{$LibVersion}}))
5405 {
5406 if($TypeName=~/\A\Q$NameSpace\E\:\:/) {
5407 return ($Cache{"parse_TypeNameSpace"}{$TypeName}{$LibVersion} = $NameSpace);
5408 }
5409 }
5410 }
5411 else {
5412 return ($Cache{"parse_TypeNameSpace"}{$TypeName}{$LibVersion} = "");
5413 }
5414}
5415
5416sub getNameSpace($)
5417{
5418 my $TypeInfoId = $_[0];
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04005419 if(my $NSInfoId = getTreeAttr_Scpe($TypeInfoId))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005420 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04005421 if(my $InfoType = $LibInfo{$Version}{"info_type"}{$NSInfoId})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005422 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04005423 if($InfoType eq "namespace_decl")
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04005424 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04005425 if($LibInfo{$Version}{"info"}{$NSInfoId}=~/name[ ]*:[ ]*@(\d+) /)
5426 {
5427 my $NameSpace = getTreeStr($1);
5428 if($NameSpace eq "::")
5429 { # global namespace
5430 return "";
5431 }
5432 if(my $BaseNameSpace = getNameSpace($NSInfoId)) {
5433 $NameSpace = $BaseNameSpace."::".$NameSpace;
5434 }
5435 $NestedNameSpaces{$Version}{$NameSpace} = 1;
5436 return $NameSpace;
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04005437 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04005438 else {
5439 return "";
5440 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005441 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04005442 elsif($InfoType eq "record_type")
5443 { # inside data type
5444 my ($Name, $NameNS) = getTrivialName(getTypeDeclId($NSInfoId), $NSInfoId);
5445 return $Name;
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04005446 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005447 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005448 }
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04005449 return "";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005450}
5451
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005452sub getEnumMembVal($)
5453{
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04005454 if($_[0] and my $Info = $LibInfo{$Version}{"info"}{$_[0]})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005455 {
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04005456 if($Info=~/valu[ ]*:[ ]*\@(\d+)/)
5457 {
5458 if(my $VInfo = $LibInfo{$Version}{"info"}{$1})
5459 {
5460 if($VInfo=~/cnst[ ]*:[ ]*\@(\d+)/)
5461 { # in newer versions of GCC the value is in the "const_decl->cnst" node
5462 return getTreeValue($1);
5463 }
5464 else
5465 { # some old versions of GCC (3.3) have the value in the "integer_cst" node
5466 return getTreeValue($1);
5467 }
5468 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005469 }
5470 }
5471 return "";
5472}
5473
5474sub getSize($)
5475{
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04005476 if($_[0] and my $Info = $LibInfo{$Version}{"info"}{$_[0]})
5477 {
5478 if($Info=~/size[ ]*:[ ]*\@(\d+)/) {
5479 return getTreeValue($1);
5480 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005481 }
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04005482 return 0;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005483}
5484
5485sub getAlgn($)
5486{
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04005487 if($_[0] and my $Info = $LibInfo{$Version}{"info"}{$_[0]})
5488 {
5489 if($Info=~/algn[ ]*:[ ]*(\d+) /) {
5490 return $1;
5491 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005492 }
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04005493 return "";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005494}
5495
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +04005496sub getBitField($)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005497{
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04005498 if($_[0] and my $Info = $LibInfo{$Version}{"info"}{$_[0]})
5499 {
5500 if($Info=~/ bitfield /) {
5501 return getSize($_[0]);
5502 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005503 }
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04005504 return 0;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005505}
5506
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04005507sub getNextElem($)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005508{
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04005509 if(my $Chan = getTreeAttr_Chan($_[0])) {
5510 return $Chan;
5511 }
5512 elsif(my $Chain = getTreeAttr_Chain($_[0])) {
5513 return $Chain;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005514 }
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04005515 return "";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005516}
5517
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04005518sub registerHeader($$)
5519{ # input: absolute path of header, relative path or name
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005520 my ($Header, $LibVersion) = @_;
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04005521 if(not $Header) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005522 return "";
5523 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04005524 if(is_abs($Header) and not -f $Header)
5525 { # incorrect absolute path
5526 exitStatus("Access_Error", "can't access \'$Header\'");
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005527 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04005528 if(skipHeader($Header, $LibVersion))
5529 { # skip
5530 return "";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005531 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04005532 if(my $Header_Path = identifyHeader($Header, $LibVersion))
5533 {
5534 detect_header_includes($Header_Path, $LibVersion);
5535
5536 if(my $RHeader_Path = $Header_ErrorRedirect{$LibVersion}{$Header_Path})
5537 { # redirect
5538 if($Registered_Headers{$LibVersion}{$RHeader_Path}{"Identity"}
5539 or skipHeader($RHeader_Path, $LibVersion))
5540 { # skip
5541 return "";
5542 }
5543 $Header_Path = $RHeader_Path;
5544 }
5545 elsif($Header_ShouldNotBeUsed{$LibVersion}{$Header_Path})
5546 { # skip
5547 return "";
5548 }
5549
5550 if(my $HName = get_filename($Header_Path))
5551 { # register
5552 $Registered_Headers{$LibVersion}{$Header_Path}{"Identity"} = $HName;
5553 $HeaderName_Paths{$LibVersion}{$HName}{$Header_Path} = 1;
5554 }
5555
5556 if(($Header=~/\.(\w+)\Z/ and $1 ne "h")
5557 or $Header!~/\.(\w+)\Z/)
5558 { # hpp, hh
5559 setLanguage($LibVersion, "C++");
5560 }
5561
5562 if($CheckHeadersOnly
5563 and $Header=~/(\A|\/)c\+\+(\/|\Z)/)
5564 { # /usr/include/c++/4.6.1/...
5565 $STDCXX_TESTING = 1;
5566 }
5567
5568 return $Header_Path;
5569 }
5570 return "";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005571}
5572
5573sub register_directory($$$)
5574{
5575 my ($Dir, $WithDeps, $LibVersion) = @_;
5576 $Dir=~s/[\/\\]+\Z//g;
5577 return if(not $LibVersion or not $Dir or not -d $Dir);
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04005578 return if(skipHeader($Dir, $LibVersion));
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005579 $Dir = get_abs_path($Dir);
5580 my $Mode = "All";
Andrey Ponomarenko85043792012-05-14 16:48:07 +04005581 if($WithDeps)
5582 {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005583 if($RegisteredDirs{$LibVersion}{$Dir}{1}) {
5584 return;
5585 }
5586 elsif($RegisteredDirs{$LibVersion}{$Dir}{0}) {
5587 $Mode = "DepsOnly";
5588 }
5589 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +04005590 else
5591 {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005592 if($RegisteredDirs{$LibVersion}{$Dir}{1}
5593 or $RegisteredDirs{$LibVersion}{$Dir}{0}) {
5594 return;
5595 }
5596 }
5597 $Header_Dependency{$LibVersion}{$Dir} = 1;
5598 $RegisteredDirs{$LibVersion}{$Dir}{$WithDeps} = 1;
5599 if($Mode eq "DepsOnly")
5600 {
5601 foreach my $Path (cmd_find($Dir,"d","","")) {
5602 $Header_Dependency{$LibVersion}{$Path} = 1;
5603 }
5604 return;
5605 }
5606 foreach my $Path (sort {length($b)<=>length($a)} cmd_find($Dir,"f","",""))
5607 {
5608 if($WithDeps)
5609 {
5610 my $SubDir = $Path;
5611 while(($SubDir = get_dirname($SubDir)) ne $Dir)
5612 { # register all sub directories
5613 $Header_Dependency{$LibVersion}{$SubDir} = 1;
5614 }
5615 }
5616 next if(is_not_header($Path));
5617 next if(ignore_path($Path));
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04005618 next if(skipHeader($Path, $LibVersion));
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005619 # Neighbors
Andrey Ponomarenko9927e332012-10-19 10:50:48 +04005620 foreach my $Part (get_prefixes($Path)) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005621 $Include_Neighbors{$LibVersion}{$Part} = $Path;
5622 }
5623 }
5624 if(get_filename($Dir) eq "include")
5625 { # search for "lib/include/" directory
5626 my $LibDir = $Dir;
5627 if($LibDir=~s/([\/\\])include\Z/$1lib/g and -d $LibDir) {
5628 register_directory($LibDir, $WithDeps, $LibVersion);
5629 }
5630 }
5631}
5632
5633sub parse_redirect($$$)
5634{
5635 my ($Content, $Path, $LibVersion) = @_;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005636 my @Errors = ();
5637 while($Content=~s/#\s*error\s+([^\n]+?)\s*(\n|\Z)//) {
5638 push(@Errors, $1);
5639 }
5640 my $Redirect = "";
5641 foreach (@Errors)
5642 {
5643 s/\s{2,}/ /g;
5644 if(/(only|must\ include
5645 |update\ to\ include
5646 |replaced\ with
5647 |replaced\ by|renamed\ to
Andrey Ponomarenko9927e332012-10-19 10:50:48 +04005648 |\ is\ in|\ use)\ (<[^<>]+>|[\w\-\/\\]+\.($HEADER_EXT))/ix)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005649 {
5650 $Redirect = $2;
5651 last;
5652 }
5653 elsif(/(include|use|is\ in)\ (<[^<>]+>|[\w\-\/\\]+\.($HEADER_EXT))\ instead/i)
5654 {
5655 $Redirect = $2;
5656 last;
5657 }
5658 elsif(/this\ header\ should\ not\ be\ used
5659 |programs\ should\ not\ directly\ include
5660 |you\ should\ not\ (include|be\ (including|using)\ this\ (file|header))
5661 |is\ not\ supported\ API\ for\ general\ use
5662 |do\ not\ use
Andrey Ponomarenko9927e332012-10-19 10:50:48 +04005663 |should\ not\ be\ (used|using)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005664 |cannot\ be\ included\ directly/ix and not /\ from\ /i) {
5665 $Header_ShouldNotBeUsed{$LibVersion}{$Path} = 1;
5666 }
5667 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +04005668 if($Redirect)
5669 {
5670 $Redirect=~s/\A<//g;
5671 $Redirect=~s/>\Z//g;
5672 }
5673 return $Redirect;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005674}
5675
5676sub parse_includes($$)
5677{
5678 my ($Content, $Path) = @_;
5679 my %Includes = ();
5680 while($Content=~s/#([ \t]*)(include|include_next|import)([ \t]*)(<|")([^<>"]+)(>|")//)
Andrey Ponomarenko85043792012-05-14 16:48:07 +04005681 { # C/C++: include, Objective C/C++: import directive
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005682 my ($Header, $Method) = ($5, $4);
5683 $Header = path_format($Header, $OSgroup);
Andrey Ponomarenko85043792012-05-14 16:48:07 +04005684 if($Method eq "\"" or is_abs($Header))
5685 {
5686 if(-e joinPath(get_dirname($Path), $Header))
5687 { # relative path exists
5688 $Includes{$Header} = -1;
5689 }
5690 else
5691 { # include "..." that doesn't exist is equal to include <...>
5692 $Includes{$Header} = 2;
5693 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005694 }
5695 else {
5696 $Includes{$Header} = 1;
5697 }
5698 }
5699 return \%Includes;
5700}
5701
5702sub ignore_path($)
5703{
5704 my $Path = $_[0];
5705 if($Path=~/\~\Z/)
5706 {# skipping system backup files
5707 return 1;
5708 }
5709 if($Path=~/(\A|[\/\\]+)(\.(svn|git|bzr|hg)|CVS)([\/\\]+|\Z)/)
5710 {# skipping hidden .svn, .git, .bzr, .hg and CVS directories
5711 return 1;
5712 }
5713 return 0;
5714}
5715
Andrey Ponomarenko9927e332012-10-19 10:50:48 +04005716sub sortByWord($$)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005717{
5718 my ($ArrRef, $W) = @_;
5719 return if(length($W)<2);
5720 @{$ArrRef} = sort {get_filename($b)=~/\Q$W\E/i<=>get_filename($a)=~/\Q$W\E/i} @{$ArrRef};
5721}
5722
Andrey Ponomarenko9927e332012-10-19 10:50:48 +04005723sub sortHeaders($$)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005724{
5725 my ($H1, $H2) = @_;
5726 $H1=~s/\.[a-z]+\Z//ig;
5727 $H2=~s/\.[a-z]+\Z//ig;
5728 my ($HDir1, $Hname1) = separate_path($H1);
5729 my ($HDir2, $Hname2) = separate_path($H2);
5730 my $Dirname1 = get_filename($HDir1);
5731 my $Dirname2 = get_filename($HDir2);
Andrey Ponomarenko9927e332012-10-19 10:50:48 +04005732 if($_[0] eq $_[1]
5733 or $H1 eq $H2) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005734 return 0;
5735 }
5736 elsif($H1=~/\A\Q$H2\E/) {
5737 return 1;
5738 }
5739 elsif($H2=~/\A\Q$H1\E/) {
5740 return -1;
5741 }
5742 elsif($HDir1=~/\Q$Hname1\E/i
5743 and $HDir2!~/\Q$Hname2\E/i)
Andrey Ponomarenko9927e332012-10-19 10:50:48 +04005744 { # include/glib-2.0/glib.h
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005745 return -1;
5746 }
5747 elsif($HDir2=~/\Q$Hname2\E/i
5748 and $HDir1!~/\Q$Hname1\E/i)
Andrey Ponomarenko9927e332012-10-19 10:50:48 +04005749 { # include/glib-2.0/glib.h
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005750 return 1;
5751 }
5752 elsif($Hname1=~/\Q$Dirname1\E/i
5753 and $Hname2!~/\Q$Dirname2\E/i)
Andrey Ponomarenko9927e332012-10-19 10:50:48 +04005754 { # include/hildon-thumbnail/hildon-thumbnail-factory.h
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005755 return -1;
5756 }
5757 elsif($Hname2=~/\Q$Dirname2\E/i
5758 and $Hname1!~/\Q$Dirname1\E/i)
Andrey Ponomarenko9927e332012-10-19 10:50:48 +04005759 { # include/hildon-thumbnail/hildon-thumbnail-factory.h
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005760 return 1;
5761 }
Andrey Ponomarenko9927e332012-10-19 10:50:48 +04005762 elsif($Hname1=~/(config|lib|util)/i
5763 and $Hname2!~/(config|lib|util)/i)
5764 { # include/alsa/asoundlib.h
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005765 return -1;
5766 }
Andrey Ponomarenko9927e332012-10-19 10:50:48 +04005767 elsif($Hname2=~/(config|lib|util)/i
5768 and $Hname1!~/(config|lib|util)/i)
5769 { # include/alsa/asoundlib.h
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005770 return 1;
5771 }
5772 elsif(checkRelevance($H1)
5773 and not checkRelevance($H2))
Andrey Ponomarenko9927e332012-10-19 10:50:48 +04005774 { # libebook/e-book.h
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005775 return -1;
5776 }
5777 elsif(checkRelevance($H2)
5778 and not checkRelevance($H1))
Andrey Ponomarenko9927e332012-10-19 10:50:48 +04005779 { # libebook/e-book.h
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005780 return 1;
5781 }
Andrey Ponomarenko9927e332012-10-19 10:50:48 +04005782 else
5783 {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005784 return (lc($H1) cmp lc($H2));
5785 }
5786}
5787
5788sub searchForHeaders($)
5789{
5790 my $LibVersion = $_[0];
5791 # gcc standard include paths
5792 find_gcc_cxx_headers($LibVersion);
5793 # processing header paths
5794 foreach my $Path (keys(%{$Descriptor{$LibVersion}{"IncludePaths"}}),
5795 keys(%{$Descriptor{$LibVersion}{"AddIncludePaths"}}))
5796 {
5797 my $IPath = $Path;
Andrey Ponomarenkoa01311b2012-06-08 17:20:02 +04005798 if($SystemRoot)
5799 {
5800 if(is_abs($Path)) {
5801 $Path = $SystemRoot.$Path;
5802 }
5803 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005804 if(not -e $Path) {
5805 exitStatus("Access_Error", "can't access \'$Path\'");
5806 }
5807 elsif(-f $Path) {
5808 exitStatus("Access_Error", "\'$Path\' - not a directory");
5809 }
5810 elsif(-d $Path)
5811 {
5812 $Path = get_abs_path($Path);
5813 register_directory($Path, 0, $LibVersion);
5814 if($Descriptor{$LibVersion}{"AddIncludePaths"}{$IPath}) {
5815 $Add_Include_Paths{$LibVersion}{$Path} = 1;
5816 }
5817 else {
5818 $Include_Paths{$LibVersion}{$Path} = 1;
5819 }
5820 }
5821 }
5822 if(keys(%{$Include_Paths{$LibVersion}})) {
5823 $INC_PATH_AUTODETECT{$LibVersion} = 0;
5824 }
5825 # registering directories
5826 foreach my $Path (split(/\s*\n\s*/, $Descriptor{$LibVersion}{"Headers"}))
5827 {
5828 next if(not -e $Path);
5829 $Path = get_abs_path($Path);
5830 $Path = path_format($Path, $OSgroup);
5831 if(-d $Path) {
5832 register_directory($Path, 1, $LibVersion);
5833 }
5834 elsif(-f $Path)
5835 {
5836 my $Dir = get_dirname($Path);
5837 if(not $SystemPaths{"include"}{$Dir}
5838 and not $LocalIncludes{$Dir})
5839 {
5840 register_directory($Dir, 1, $LibVersion);
5841 if(my $OutDir = get_dirname($Dir))
5842 { # registering the outer directory
5843 if(not $SystemPaths{"include"}{$OutDir}
5844 and not $LocalIncludes{$OutDir}) {
5845 register_directory($OutDir, 0, $LibVersion);
5846 }
5847 }
5848 }
5849 }
5850 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +04005851
5852 # clean memory
5853 %RegisteredDirs = ();
5854
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005855 # registering headers
5856 my $Position = 0;
5857 foreach my $Dest (split(/\s*\n\s*/, $Descriptor{$LibVersion}{"Headers"}))
5858 {
5859 if(is_abs($Dest) and not -e $Dest) {
5860 exitStatus("Access_Error", "can't access \'$Dest\'");
5861 }
5862 $Dest = path_format($Dest, $OSgroup);
5863 if(is_header($Dest, 1, $LibVersion))
5864 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04005865 if(my $HPath = registerHeader($Dest, $LibVersion)) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005866 $Registered_Headers{$LibVersion}{$HPath}{"Pos"} = $Position++;
5867 }
5868 }
5869 elsif(-d $Dest)
5870 {
5871 my @Registered = ();
5872 foreach my $Path (cmd_find($Dest,"f","",""))
5873 {
5874 next if(ignore_path($Path));
5875 next if(not is_header($Path, 0, $LibVersion));
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04005876 if(my $HPath = registerHeader($Path, $LibVersion)) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005877 push(@Registered, $HPath);
5878 }
5879 }
Andrey Ponomarenko9927e332012-10-19 10:50:48 +04005880 @Registered = sort {sortHeaders($a, $b)} @Registered;
5881 sortByWord(\@Registered, $TargetLibraryShortName);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005882 foreach my $Path (@Registered) {
5883 $Registered_Headers{$LibVersion}{$Path}{"Pos"} = $Position++;
5884 }
5885 }
5886 else {
5887 exitStatus("Access_Error", "can't identify \'$Dest\' as a header file");
5888 }
5889 }
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04005890 if(my $HList = $Descriptor{$LibVersion}{"IncludePreamble"})
5891 { # preparing preamble headers
5892 my $PPos=0;
5893 foreach my $Header (split(/\s*\n\s*/, $HList))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005894 {
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04005895 if(is_abs($Header) and not -f $Header) {
5896 exitStatus("Access_Error", "can't access file \'$Header\'");
5897 }
5898 $Header = path_format($Header, $OSgroup);
5899 if(my $Header_Path = is_header($Header, 1, $LibVersion))
5900 {
Andrey Ponomarenko9927e332012-10-19 10:50:48 +04005901 if(defined $Include_Preamble{$LibVersion}{$Header_Path})
5902 { # duplicate
5903 next;
5904 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04005905 next if(skipHeader($Header_Path, $LibVersion));
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04005906 $Include_Preamble{$LibVersion}{$Header_Path}{"Position"} = $PPos++;
5907 }
5908 else {
5909 exitStatus("Access_Error", "can't identify \'$Header\' as a header file");
5910 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005911 }
5912 }
5913 foreach my $Header_Name (keys(%{$HeaderName_Paths{$LibVersion}}))
5914 { # set relative paths (for duplicates)
5915 if(keys(%{$HeaderName_Paths{$LibVersion}{$Header_Name}})>=2)
5916 { # search for duplicates
5917 my $FirstPath = (keys(%{$HeaderName_Paths{$LibVersion}{$Header_Name}}))[0];
5918 my $Prefix = get_dirname($FirstPath);
5919 while($Prefix=~/\A(.+)[\/\\]+[^\/\\]+\Z/)
5920 { # detect a shortest distinguishing prefix
5921 my $NewPrefix = $1;
5922 my %Identity = ();
5923 foreach my $Path (keys(%{$HeaderName_Paths{$LibVersion}{$Header_Name}}))
5924 {
5925 if($Path=~/\A\Q$Prefix\E[\/\\]+(.*)\Z/) {
5926 $Identity{$Path} = $1;
5927 }
5928 }
5929 if(keys(%Identity)==keys(%{$HeaderName_Paths{$LibVersion}{$Header_Name}}))
5930 { # all names are differend with current prefix
5931 foreach my $Path (keys(%{$HeaderName_Paths{$LibVersion}{$Header_Name}})) {
5932 $Registered_Headers{$LibVersion}{$Path}{"Identity"} = $Identity{$Path};
5933 }
5934 last;
5935 }
5936 $Prefix = $NewPrefix; # increase prefix
5937 }
5938 }
5939 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +04005940
5941 # clean memory
5942 %HeaderName_Paths = ();
5943
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005944 foreach my $HeaderName (keys(%{$Include_Order{$LibVersion}}))
5945 { # ordering headers according to descriptor
5946 my $PairName=$Include_Order{$LibVersion}{$HeaderName};
5947 my ($Pos, $PairPos) = (-1, -1);
5948 my ($Path, $PairPath) = ();
5949 my @Paths = keys(%{$Registered_Headers{$LibVersion}});
5950 @Paths = sort {int($Registered_Headers{$LibVersion}{$a}{"Pos"})<=>int($Registered_Headers{$LibVersion}{$b}{"Pos"})} @Paths;
5951 foreach my $Header_Path (@Paths)
5952 {
5953 if(get_filename($Header_Path) eq $PairName)
5954 {
5955 $PairPos = $Registered_Headers{$LibVersion}{$Header_Path}{"Pos"};
5956 $PairPath = $Header_Path;
5957 }
5958 if(get_filename($Header_Path) eq $HeaderName)
5959 {
5960 $Pos = $Registered_Headers{$LibVersion}{$Header_Path}{"Pos"};
5961 $Path = $Header_Path;
5962 }
5963 }
5964 if($PairPos!=-1 and $Pos!=-1
5965 and int($PairPos)<int($Pos))
5966 {
5967 my %Tmp = %{$Registered_Headers{$LibVersion}{$Path}};
5968 %{$Registered_Headers{$LibVersion}{$Path}} = %{$Registered_Headers{$LibVersion}{$PairPath}};
5969 %{$Registered_Headers{$LibVersion}{$PairPath}} = %Tmp;
5970 }
5971 }
5972 if(not keys(%{$Registered_Headers{$LibVersion}})) {
5973 exitStatus("Error", "header files are not found in the ".$Descriptor{$LibVersion}{"Version"});
5974 }
5975}
5976
5977sub detect_real_includes($$)
5978{
5979 my ($AbsPath, $LibVersion) = @_;
5980 return () if(not $LibVersion or not $AbsPath or not -e $AbsPath);
5981 if($Cache{"detect_real_includes"}{$LibVersion}{$AbsPath}
5982 or keys(%{$RecursiveIncludes{$LibVersion}{$AbsPath}})) {
5983 return keys(%{$RecursiveIncludes{$LibVersion}{$AbsPath}});
5984 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +04005985 $Cache{"detect_real_includes"}{$LibVersion}{$AbsPath}=1;
5986
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005987 my $Path = callPreprocessor($AbsPath, "", $LibVersion);
5988 return () if(not $Path);
5989 open(PREPROC, $Path);
5990 while(<PREPROC>)
5991 {
5992 if(/#\s+\d+\s+"([^"]+)"[\s\d]*\n/)
5993 {
5994 my $Include = path_format($1, $OSgroup);
5995 if($Include=~/\<(built\-in|internal|command(\-|\s)line)\>|\A\./) {
5996 next;
5997 }
5998 if($Include eq $AbsPath) {
5999 next;
6000 }
6001 $RecursiveIncludes{$LibVersion}{$AbsPath}{$Include} = 1;
6002 }
6003 }
6004 close(PREPROC);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006005 return keys(%{$RecursiveIncludes{$LibVersion}{$AbsPath}});
6006}
6007
6008sub detect_header_includes($$)
6009{
6010 my ($Path, $LibVersion) = @_;
Andrey Ponomarenko85043792012-05-14 16:48:07 +04006011 return if(not $LibVersion or not $Path);
6012 if(defined $Cache{"detect_header_includes"}{$LibVersion}{$Path}) {
6013 return;
6014 }
6015 $Cache{"detect_header_includes"}{$LibVersion}{$Path}=1;
6016
6017 if(not -e $Path) {
6018 return;
6019 }
6020
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006021 my $Content = readFile($Path);
Andrey Ponomarenko85043792012-05-14 16:48:07 +04006022 if(my $Redirect = parse_redirect($Content, $Path, $LibVersion))
6023 { # detect error directive in headers
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04006024 if(my $RedirectPath = identifyHeader($Redirect, $LibVersion))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006025 {
6026 if($RedirectPath=~/\/usr\/include\// and $Path!~/\/usr\/include\//) {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04006027 $RedirectPath = identifyHeader(get_filename($Redirect), $LibVersion);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006028 }
6029 if($RedirectPath ne $Path) {
6030 $Header_ErrorRedirect{$LibVersion}{$Path} = $RedirectPath;
6031 }
6032 }
Andrey Ponomarenko9927e332012-10-19 10:50:48 +04006033 else
6034 { # can't find
6035 $Header_ShouldNotBeUsed{$LibVersion}{$Path} = 1;
6036 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006037 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +04006038 if(my $Inc = parse_includes($Content, $Path))
6039 {
6040 foreach my $Include (keys(%{$Inc}))
6041 { # detect includes
Andrey Ponomarenko85043792012-05-14 16:48:07 +04006042 $Header_Includes{$LibVersion}{$Path}{$Include} = $Inc->{$Include};
6043 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006044 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006045}
6046
6047sub simplify_path($)
6048{
6049 my $Path = $_[0];
6050 while($Path=~s&([\/\\])[^\/\\]+[\/\\]\.\.[\/\\]&$1&){};
6051 return $Path;
6052}
6053
6054sub fromLibc($)
6055{ # GLIBC header
6056 my $Path = $_[0];
6057 my ($Dir, $Name) = separate_path($Path);
6058 if(get_filename($Dir)=~/\A(include|libc)\Z/ and $GlibcHeader{$Name})
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04006059 { # /usr/include/{stdio, ...}.h
6060 # epoc32/include/libc/{stdio, ...}.h
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006061 return 1;
6062 }
6063 if(isLibcDir($Dir)) {
6064 return 1;
6065 }
6066 return 0;
6067}
6068
6069sub isLibcDir($)
6070{ # GLIBC directory
6071 my $Dir = $_[0];
6072 my ($OutDir, $Name) = separate_path($Dir);
6073 if(get_filename($OutDir)=~/\A(include|libc)\Z/
6074 and ($Name=~/\Aasm(|-.+)\Z/ or $GlibcDir{$Name}))
6075 { # /usr/include/{sys,bits,asm,asm-*}/*.h
6076 return 1;
6077 }
6078 return 0;
6079}
6080
6081sub detect_recursive_includes($$)
6082{
6083 my ($AbsPath, $LibVersion) = @_;
6084 return () if(not $AbsPath);
6085 if(isCyclical(\@RecurInclude, $AbsPath)) {
6086 return keys(%{$RecursiveIncludes{$LibVersion}{$AbsPath}});
6087 }
6088 my ($AbsDir, $Name) = separate_path($AbsPath);
6089 if(isLibcDir($AbsDir))
6090 { # GLIBC internals
6091 return ();
6092 }
6093 if(keys(%{$RecursiveIncludes{$LibVersion}{$AbsPath}})) {
6094 return keys(%{$RecursiveIncludes{$LibVersion}{$AbsPath}});
6095 }
6096 return () if($OSgroup ne "windows" and $Name=~/windows|win32|win64/i);
6097 return () if($MAIN_CPP_DIR and $AbsPath=~/\A\Q$MAIN_CPP_DIR\E/ and not $STDCXX_TESTING);
6098 push(@RecurInclude, $AbsPath);
6099 if($DefaultGccPaths{$AbsDir}
6100 or fromLibc($AbsPath))
6101 { # check "real" (non-"model") include paths
6102 my @Paths = detect_real_includes($AbsPath, $LibVersion);
6103 pop(@RecurInclude);
6104 return @Paths;
6105 }
6106 if(not keys(%{$Header_Includes{$LibVersion}{$AbsPath}})) {
6107 detect_header_includes($AbsPath, $LibVersion);
6108 }
6109 foreach my $Include (keys(%{$Header_Includes{$LibVersion}{$AbsPath}}))
6110 {
Andrey Ponomarenko85043792012-05-14 16:48:07 +04006111 my $IncType = $Header_Includes{$LibVersion}{$AbsPath}{$Include};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006112 my $HPath = "";
Andrey Ponomarenko85043792012-05-14 16:48:07 +04006113 if($IncType<0)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006114 { # for #include "..."
6115 my $Candidate = joinPath($AbsDir, $Include);
6116 if(-f $Candidate) {
6117 $HPath = simplify_path($Candidate);
6118 }
6119 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +04006120 elsif($IncType>0
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04006121 and $Include=~/[\/\\]/) # and not find_in_defaults($Include)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006122 { # search for the nearest header
6123 # QtCore/qabstractanimation.h includes <QtCore/qobject.h>
6124 my $Candidate = joinPath(get_dirname($AbsDir), $Include);
6125 if(-f $Candidate) {
6126 $HPath = $Candidate;
6127 }
6128 }
6129 if(not $HPath) {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04006130 $HPath = identifyHeader($Include, $LibVersion);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006131 }
6132 next if(not $HPath);
6133 if($HPath eq $AbsPath) {
6134 next;
6135 }
Andrey Ponomarenko9927e332012-10-19 10:50:48 +04006136
6137 if($Debug)
6138 { # boundary headers
6139 #if($HPath=~/vtk/ and $AbsPath!~/vtk/)
6140 #{
6141 # print STDERR "$AbsPath -> $HPath\n";
6142 #}
6143 }
6144
Andrey Ponomarenko85043792012-05-14 16:48:07 +04006145 $RecursiveIncludes{$LibVersion}{$AbsPath}{$HPath} = $IncType;
6146 if($IncType>0)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006147 { # only include <...>, skip include "..." prefixes
6148 $Header_Include_Prefix{$LibVersion}{$AbsPath}{$HPath}{get_dirname($Include)} = 1;
6149 }
6150 foreach my $IncPath (detect_recursive_includes($HPath, $LibVersion))
6151 {
6152 if($IncPath eq $AbsPath) {
6153 next;
6154 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +04006155 my $RIncType = $RecursiveIncludes{$LibVersion}{$HPath}{$IncPath};
6156 if($RIncType==-1)
6157 { # include "..."
6158 $RIncType = $IncType;
6159 }
6160 elsif($RIncType==2)
6161 {
6162 if($IncType!=-1) {
6163 $RIncType = $IncType;
6164 }
6165 }
6166 $RecursiveIncludes{$LibVersion}{$AbsPath}{$IncPath} = $RIncType;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006167 foreach my $Prefix (keys(%{$Header_Include_Prefix{$LibVersion}{$HPath}{$IncPath}})) {
6168 $Header_Include_Prefix{$LibVersion}{$AbsPath}{$IncPath}{$Prefix} = 1;
6169 }
6170 }
6171 foreach my $Dep (keys(%{$Header_Include_Prefix{$LibVersion}{$AbsPath}}))
6172 {
6173 if($GlibcHeader{get_filename($Dep)} and keys(%{$Header_Include_Prefix{$LibVersion}{$AbsPath}{$Dep}})>=2
6174 and defined $Header_Include_Prefix{$LibVersion}{$AbsPath}{$Dep}{""})
6175 { # distinguish math.h from glibc and math.h from the tested library
6176 delete($Header_Include_Prefix{$LibVersion}{$AbsPath}{$Dep}{""});
6177 last;
6178 }
6179 }
6180 }
6181 pop(@RecurInclude);
6182 return keys(%{$RecursiveIncludes{$LibVersion}{$AbsPath}});
6183}
6184
6185sub find_in_framework($$$)
6186{
6187 my ($Header, $Framework, $LibVersion) = @_;
6188 return "" if(not $Header or not $Framework or not $LibVersion);
6189 if(defined $Cache{"find_in_framework"}{$LibVersion}{$Framework}{$Header}) {
6190 return $Cache{"find_in_framework"}{$LibVersion}{$Framework}{$Header};
6191 }
6192 foreach my $Dependency (sort {get_depth($a)<=>get_depth($b)} keys(%{$Header_Dependency{$LibVersion}}))
6193 {
6194 if(get_filename($Dependency) eq $Framework
6195 and -f get_dirname($Dependency)."/".$Header) {
6196 return ($Cache{"find_in_framework"}{$LibVersion}{$Framework}{$Header} = get_dirname($Dependency));
6197 }
6198 }
6199 return ($Cache{"find_in_framework"}{$LibVersion}{$Framework}{$Header} = "");
6200}
6201
6202sub find_in_defaults($)
6203{
6204 my $Header = $_[0];
6205 return "" if(not $Header);
6206 if(defined $Cache{"find_in_defaults"}{$Header}) {
6207 return $Cache{"find_in_defaults"}{$Header};
6208 }
6209 foreach my $Dir (sort {get_depth($a)<=>get_depth($b)}
6210 (keys(%DefaultIncPaths), keys(%DefaultGccPaths), keys(%DefaultCppPaths), keys(%UserIncPath)))
6211 {
6212 next if(not $Dir);
6213 if(-f $Dir."/".$Header) {
6214 return ($Cache{"find_in_defaults"}{$Header}=$Dir);
6215 }
6216 }
6217 return ($Cache{"find_in_defaults"}{$Header}="");
6218}
6219
6220sub cmp_paths($$)
6221{
6222 my ($Path1, $Path2) = @_;
6223 my @Parts1 = split(/[\/\\]/, $Path1);
6224 my @Parts2 = split(/[\/\\]/, $Path2);
6225 foreach my $Num (0 .. $#Parts1)
6226 {
6227 my $Part1 = $Parts1[$Num];
6228 my $Part2 = $Parts2[$Num];
6229 if($GlibcDir{$Part1}
6230 and not $GlibcDir{$Part2}) {
6231 return 1;
6232 }
6233 elsif($GlibcDir{$Part2}
6234 and not $GlibcDir{$Part1}) {
6235 return -1;
6236 }
6237 elsif($Part1=~/glib/
6238 and $Part2!~/glib/) {
6239 return 1;
6240 }
6241 elsif($Part1!~/glib/
6242 and $Part2=~/glib/) {
6243 return -1;
6244 }
6245 elsif(my $CmpRes = ($Part1 cmp $Part2)) {
6246 return $CmpRes;
6247 }
6248 }
6249 return 0;
6250}
6251
6252sub checkRelevance($)
6253{
6254 my ($Path) = @_;
6255 return 0 if(not $Path);
6256 if($SystemRoot) {
Andrey Ponomarenkoa01311b2012-06-08 17:20:02 +04006257 $Path = cut_path_prefix($Path, $SystemRoot);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006258 }
6259 my ($Dir, $Name) = separate_path($Path);
Andrey Ponomarenkoa01311b2012-06-08 17:20:02 +04006260 $Name=~s/\.\w+\Z//g; # remove extension (.h)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006261 my @Tokens = split(/[_\d\W]+/, $Name);
6262 foreach (@Tokens)
6263 {
6264 next if(not $_);
6265 if($Dir=~/(\A|lib|[_\d\W])\Q$_\E([_\d\W]|lib|\Z)/i
6266 or length($_)>=4 and $Dir=~/\Q$_\E/i)
6267 { # include/gupnp-1.0/libgupnp/gupnp-context.h
6268 # include/evolution-data-server-1.4/libebook/e-book.h
6269 return 1;
6270 }
6271 }
6272 return 0;
6273}
6274
6275sub checkFamily(@)
6276{
6277 my @Paths = @_;
6278 return 1 if($#Paths<=0);
6279 my %Prefix = ();
6280 foreach my $Path (@Paths)
6281 {
6282 if($SystemRoot) {
6283 $Path = cut_path_prefix($Path, $SystemRoot);
6284 }
6285 if(my $Dir = get_dirname($Path))
6286 {
6287 $Dir=~s/(\/[^\/]+?)[\d\.\-\_]+\Z/$1/g; # remove version suffix
6288 $Prefix{$Dir} += 1;
6289 $Prefix{get_dirname($Dir)} += 1;
6290 }
6291 }
6292 foreach (sort keys(%Prefix))
6293 {
6294 if(get_depth($_)>=3
6295 and $Prefix{$_}==$#Paths+1) {
6296 return 1;
6297 }
6298 }
6299 return 0;
6300}
6301
6302sub isAcceptable($$$)
6303{
6304 my ($Header, $Candidate, $LibVersion) = @_;
6305 my $HName = get_filename($Header);
6306 if(get_dirname($Header))
6307 { # with prefix
6308 return 1;
6309 }
6310 if($HName=~/config|setup/i and $Candidate=~/[\/\\]lib\d*[\/\\]/)
6311 { # allow to search for glibconfig.h in /usr/lib/glib-2.0/include/
6312 return 1;
6313 }
6314 if(checkRelevance($Candidate))
6315 { # allow to search for atk.h in /usr/include/atk-1.0/atk/
6316 return 1;
6317 }
6318 if(checkFamily(getSystemHeaders($HName, $LibVersion)))
6319 { # /usr/include/qt4/QtNetwork/qsslconfiguration.h
6320 # /usr/include/qt4/Qt/qsslconfiguration.h
6321 return 1;
6322 }
6323 if($OStarget eq "symbian")
6324 {
6325 if($Candidate=~/[\/\\]stdapis[\/\\]/) {
6326 return 1;
6327 }
6328 }
6329 return 0;
6330}
6331
6332sub isRelevant($$$)
6333{ # disallow to search for "abstract" headers in too deep directories
6334 my ($Header, $Candidate, $LibVersion) = @_;
6335 my $HName = get_filename($Header);
6336 if($OStarget eq "symbian")
6337 {
6338 if($Candidate=~/[\/\\](tools|stlportv5)[\/\\]/) {
6339 return 0;
6340 }
6341 }
Andrey Ponomarenko9927e332012-10-19 10:50:48 +04006342 if($OStarget ne "bsd")
6343 {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006344 if($Candidate=~/[\/\\]include[\/\\]bsd[\/\\]/)
6345 { # openssh: skip /usr/lib/bcc/include/bsd/signal.h
6346 return 0;
6347 }
6348 }
Andrey Ponomarenko9927e332012-10-19 10:50:48 +04006349 if($OStarget ne "windows")
6350 {
6351 if($Candidate=~/[\/\\](wine|msvcrt|windows)[\/\\]/)
6352 { # skip /usr/include/wine/msvcrt
6353 return 0;
6354 }
6355 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006356 if(not get_dirname($Header)
6357 and $Candidate=~/[\/\\]wx[\/\\]/)
6358 { # do NOT search in system /wx/ directory
6359 # for headers without a prefix: sstream.h
6360 return 0;
6361 }
6362 if($Candidate=~/c\+\+[\/\\]\d+/ and $MAIN_CPP_DIR
6363 and $Candidate!~/\A\Q$MAIN_CPP_DIR\E/)
6364 { # skip ../c++/3.3.3/ if using ../c++/4.5/
6365 return 0;
6366 }
6367 if($Candidate=~/[\/\\]asm-/
6368 and (my $Arch = getArch($LibVersion)) ne "unknown")
6369 { # arch-specific header files
6370 if($Candidate!~/[\/\\]asm-\Q$Arch\E/)
6371 {# skip ../asm-arm/ if using x86 architecture
6372 return 0;
6373 }
6374 }
6375 my @Candidates = getSystemHeaders($HName, $LibVersion);
6376 if($#Candidates==1)
6377 { # unique header
6378 return 1;
6379 }
6380 my @SCandidates = getSystemHeaders($Header, $LibVersion);
6381 if($#SCandidates==1)
6382 { # unique name
6383 return 1;
6384 }
6385 my $SystemDepth = $SystemRoot?get_depth($SystemRoot):0;
6386 if(get_depth($Candidate)-$SystemDepth>=5)
6387 { # abstract headers in too deep directories
6388 # sstream.h or typeinfo.h in /usr/include/wx-2.9/wx/
6389 if(not isAcceptable($Header, $Candidate, $LibVersion)) {
6390 return 0;
6391 }
6392 }
6393 if($Header eq "parser.h"
6394 and $Candidate!~/\/libxml2\//)
6395 { # select parser.h from xml2 library
6396 return 0;
6397 }
6398 if(not get_dirname($Header)
6399 and keys(%{$SystemHeaders{$HName}})>=3)
6400 { # many headers with the same name
6401 # like thread.h included without a prefix
6402 if(not checkFamily(@Candidates)) {
6403 return 0;
6404 }
6405 }
6406 return 1;
6407}
6408
6409sub selectSystemHeader($$)
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04006410{ # cache function
6411 if(defined $Cache{"selectSystemHeader"}{$_[1]}{$_[0]}) {
6412 return $Cache{"selectSystemHeader"}{$_[1]}{$_[0]};
6413 }
6414 return ($Cache{"selectSystemHeader"}{$_[1]}{$_[0]} = selectSystemHeader_I(@_));
6415}
6416
6417sub selectSystemHeader_I($$)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006418{
6419 my ($Header, $LibVersion) = @_;
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04006420 if(-f $Header) {
6421 return $Header;
6422 }
6423 if(is_abs($Header) and not -f $Header)
6424 { # incorrect absolute path
6425 return "";
6426 }
Andrey Ponomarenko9927e332012-10-19 10:50:48 +04006427 if(defined $ConfHeaders{lc($Header)})
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04006428 { # too abstract configuration headers
6429 return "";
6430 }
Andrey Ponomarenko9927e332012-10-19 10:50:48 +04006431 my $HName = get_filename($Header);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006432 if($OSgroup ne "windows")
6433 {
Andrey Ponomarenko9927e332012-10-19 10:50:48 +04006434 if(defined $WinHeaders{lc($HName)}
6435 or $HName=~/windows|win32|win64/i)
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04006436 { # windows headers
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006437 return "";
6438 }
Andrey Ponomarenko9927e332012-10-19 10:50:48 +04006439 }
6440 if($OSgroup ne "macos")
6441 {
6442 if($HName eq "fp.h")
6443 { # pngconf.h includes fp.h for MACOS
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006444 return "";
6445 }
6446 }
6447 if($OSgroup ne "solaris")
6448 {
Andrey Ponomarenko9927e332012-10-19 10:50:48 +04006449 if($Header eq "thread.h") {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006450 return "";
6451 }
6452 }
Andrey Ponomarenko07aea072012-11-12 16:15:07 +04006453 if($OSgroup ne "hpux")
6454 {
6455 if($Header eq "sys/stream.h") {
6456 return "";
6457 }
6458 }
Andrey Ponomarenko9927e332012-10-19 10:50:48 +04006459 if($ObsoleteHeaders{$HName}) {
6460 return "";
6461 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04006462
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006463 foreach my $Path (keys(%{$SystemPaths{"include"}}))
6464 { # search in default paths
6465 if(-f $Path."/".$Header) {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04006466 return joinPath($Path,$Header);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006467 }
6468 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04006469 if(not keys(%SystemHeaders))
6470 { # register all headers in system include dirs
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006471 detectSystemHeaders();
6472 }
6473 foreach my $Candidate (sort {get_depth($a)<=>get_depth($b)}
6474 sort {cmp_paths($b, $a)} getSystemHeaders($Header, $LibVersion))
6475 {
6476 if(isRelevant($Header, $Candidate, $LibVersion)) {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04006477 return $Candidate;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006478 }
6479 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04006480 # error
6481 return "";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006482}
6483
6484sub getSystemHeaders($$)
6485{
6486 my ($Header, $LibVersion) = @_;
6487 my @Candidates = ();
6488 foreach my $Candidate (sort keys(%{$SystemHeaders{$Header}}))
6489 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04006490 if(skipHeader($Candidate, $LibVersion)) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006491 next;
6492 }
6493 push(@Candidates, $Candidate);
6494 }
6495 return @Candidates;
6496}
6497
6498sub cut_path_prefix($$)
6499{
6500 my ($Path, $Prefix) = @_;
6501 return $Path if(not $Prefix);
6502 $Prefix=~s/[\/\\]+\Z//;
6503 $Path=~s/\A\Q$Prefix\E([\/\\]+|\Z)//;
6504 return $Path;
6505}
6506
6507sub is_default_include_dir($)
6508{
6509 my $Dir = $_[0];
6510 $Dir=~s/[\/\\]+\Z//;
6511 return ($DefaultGccPaths{$Dir} or $DefaultCppPaths{$Dir} or $DefaultIncPaths{$Dir});
6512}
6513
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04006514sub identifyHeader($$)
6515{ # cache function
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006516 my ($Header, $LibVersion) = @_;
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04006517 if(not $Header) {
6518 return "";
6519 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006520 $Header=~s/\A(\.\.[\\\/])+//g;
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04006521 if(defined $Cache{"identifyHeader"}{$LibVersion}{$Header}) {
6522 return $Cache{"identifyHeader"}{$LibVersion}{$Header};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006523 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04006524 return ($Cache{"identifyHeader"}{$LibVersion}{$Header} = identifyHeader_I($Header, $LibVersion));
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006525}
6526
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04006527sub identifyHeader_I($$)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006528{ # search for header by absolute path, relative path or name
6529 my ($Header, $LibVersion) = @_;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006530 if(-f $Header)
6531 { # it's relative or absolute path
6532 return get_abs_path($Header);
6533 }
6534 elsif($GlibcHeader{$Header} and not $GLIBC_TESTING
6535 and my $HeaderDir = find_in_defaults($Header))
6536 { # search for libc headers in the /usr/include
6537 # for non-libc target library before searching
6538 # in the library paths
6539 return joinPath($HeaderDir,$Header);
6540 }
6541 elsif(my $Path = $Include_Neighbors{$LibVersion}{$Header})
6542 { # search in the target library paths
6543 return $Path;
6544 }
6545 elsif($DefaultGccHeader{$Header})
6546 { # search in the internal GCC include paths
6547 return $DefaultGccHeader{$Header};
6548 }
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04006549 elsif(my $DefaultDir = find_in_defaults($Header))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006550 { # search in the default GCC include paths
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04006551 return joinPath($DefaultDir,$Header);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006552 }
6553 elsif($DefaultCppHeader{$Header})
6554 { # search in the default G++ include paths
6555 return $DefaultCppHeader{$Header};
6556 }
6557 elsif(my $AnyPath = selectSystemHeader($Header, $LibVersion))
6558 { # search everywhere in the system
6559 return $AnyPath;
6560 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04006561 elsif($OSgroup eq "macos")
6562 { # search in frameworks: "OpenGL/gl.h" is "OpenGL.framework/Headers/gl.h"
6563 if(my $Dir = get_dirname($Header))
6564 {
6565 my $RelPath = "Headers\/".get_filename($Header);
6566 if(my $HeaderDir = find_in_framework($RelPath, $Dir.".framework", $LibVersion)) {
6567 return joinPath($HeaderDir, $RelPath);
6568 }
6569 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006570 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04006571 # cannot find anything
6572 return "";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006573}
6574
6575sub getLocation($)
6576{
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04006577 if($_[0] and my $Info = $LibInfo{$Version}{"info"}{$_[0]})
6578 {
6579 if($Info=~/srcp[ ]*:[ ]*([\w\-\<\>\.\+\/\\]+):(\d+) /) {
Andrey Ponomarenko9927e332012-10-19 10:50:48 +04006580 return (path_format($1, $OSgroup), $2);
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04006581 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006582 }
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04006583 return ();
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006584}
6585
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006586sub getNameByInfo($)
6587{
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04006588 if($_[0] and my $Info = $LibInfo{$Version}{"info"}{$_[0]})
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04006589 {
6590 if($Info=~/name[ ]*:[ ]*@(\d+) /)
6591 {
6592 if(my $NInfo = $LibInfo{$Version}{"info"}{$1})
6593 {
6594 if($NInfo=~/strg[ ]*:[ ]*(.*?)[ ]+lngt/)
6595 { # short unsigned int (may include spaces)
6596 return $1;
6597 }
6598 }
6599 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006600 }
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04006601 return "";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006602}
6603
6604sub getTreeStr($)
6605{
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04006606 if($_[0] and my $Info = $LibInfo{$Version}{"info"}{$_[0]})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006607 {
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04006608 if($Info=~/strg[ ]*:[ ]*([^ ]*)/)
6609 {
6610 my $Str = $1;
Andrey Ponomarenko07aea072012-11-12 16:15:07 +04006611 if($CppMode{$Version}
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04006612 and $Str=~/\Ac99_(.+)\Z/) {
6613 if($CppKeywords_A{$1}) {
6614 $Str=$1;
6615 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006616 }
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04006617 return $Str;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006618 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006619 }
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04006620 return "";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006621}
6622
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006623sub getFuncShortName($)
6624{
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04006625 if(my $Info = $LibInfo{$Version}{"info"}{$_[0]})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006626 {
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04006627 if($Info=~/ operator /)
6628 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04006629 if($Info=~/ conversion /)
6630 {
6631 if(my $Rid = $SymbolInfo{$Version}{$_[0]}{"Return"})
6632 {
6633 if(my $RName = $TypeInfo{$Version}{$Rid}{"Name"}) {
6634 return "operator ".$RName;
6635 }
6636 }
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04006637 }
6638 else
6639 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04006640 if($Info=~/ operator[ ]+([a-zA-Z]+) /)
6641 {
6642 if(my $Ind = $Operator_Indication{$1}) {
6643 return "operator".$Ind;
6644 }
6645 elsif(not $UnknownOperator{$1})
6646 {
6647 printMsg("WARNING", "unknown operator $1");
6648 $UnknownOperator{$1} = 1;
6649 }
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04006650 }
6651 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006652 }
6653 else
6654 {
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04006655 if($Info=~/name[ ]*:[ ]*@(\d+) /) {
6656 return getTreeStr($1);
6657 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006658 }
6659 }
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04006660 return "";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006661}
6662
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006663sub getFuncReturn($)
6664{
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04006665 if($_[0] and my $Info = $LibInfo{$Version}{"info"}{$_[0]})
6666 {
6667 if($Info=~/type[ ]*:[ ]*@(\d+) /)
6668 {
6669 if($LibInfo{$Version}{"info"}{$1}=~/retn[ ]*:[ ]*@(\d+) /) {
6670 return $1;
6671 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006672 }
6673 }
6674 return "";
6675}
6676
6677sub getFuncOrig($)
6678{
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04006679 if($_[0] and my $Info = $LibInfo{$Version}{"info"}{$_[0]})
6680 {
6681 if($Info=~/orig[ ]*:[ ]*@(\d+) /) {
6682 return $1;
6683 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006684 }
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04006685 return $_[0];
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006686}
6687
6688sub unmangleSymbol($)
6689{
6690 my $Symbol = $_[0];
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04006691 if(my @Unmngl = unmangleArray($Symbol)) {
6692 return $Unmngl[0];
6693 }
6694 return "";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006695}
6696
6697sub unmangleArray(@)
6698{
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04006699 if($_[0]=~/\A\?/)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006700 { # MSVC mangling
6701 my $UndNameCmd = get_CmdPath("undname");
6702 if(not $UndNameCmd) {
6703 exitStatus("Not_Found", "can't find \"undname\"");
6704 }
6705 writeFile("$TMP_DIR/unmangle", join("\n", @_));
Andrey Ponomarenkoa01311b2012-06-08 17:20:02 +04006706 return split(/\n/, `$UndNameCmd 0x8386 \"$TMP_DIR/unmangle\"`);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006707 }
6708 else
6709 { # GCC mangling
6710 my $CppFiltCmd = get_CmdPath("c++filt");
6711 if(not $CppFiltCmd) {
6712 exitStatus("Not_Found", "can't find c++filt in PATH");
6713 }
Andrey Ponomarenko9927e332012-10-19 10:50:48 +04006714 if(not defined $CPPFILT_SUPPORT_FILE)
6715 {
6716 my $Info = `$CppFiltCmd -h 2>&1`;
6717 $CPPFILT_SUPPORT_FILE = $Info=~/\@<file>/;
6718 }
6719 if($CPPFILT_SUPPORT_FILE)
6720 { # new versions of c++filt can take a file
6721 if($#_>$MAX_CPPFILT_FILE_SIZE)
6722 { # c++filt <= 2.22 may crash on large files (larger than 8mb)
6723 # this is fixed in the oncoming version of Binutils
6724 my @Half = splice(@_, 0, ($#_+1)/2);
6725 return (unmangleArray(@Half), unmangleArray(@_))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006726 }
Andrey Ponomarenko9927e332012-10-19 10:50:48 +04006727 else
6728 {
6729 my $NoStrip = "";
6730 if($OSgroup eq "macos"
6731 or $OSgroup eq "windows") {
6732 $NoStrip = "-n";
6733 }
6734 writeFile("$TMP_DIR/unmangle", join("\n", @_));
6735 my $Res = `$CppFiltCmd $NoStrip \@\"$TMP_DIR/unmangle\"`;
6736 if($?==139)
6737 { # segmentation fault
6738 printMsg("ERROR", "internal error - c++filt crashed, try to reduce MAX_CPPFILT_FILE_SIZE constant");
6739 }
6740 return split(/\n/, $Res);
6741 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006742 }
6743 else
6744 { # old-style unmangling
Andrey Ponomarenko9927e332012-10-19 10:50:48 +04006745 if($#_>$MAX_COMMAND_LINE_ARGUMENTS)
6746 {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006747 my @Half = splice(@_, 0, ($#_+1)/2);
6748 return (unmangleArray(@Half), unmangleArray(@_))
6749 }
6750 else
6751 {
6752 my $NoStrip = "";
6753 if($OSgroup eq "macos"
6754 or $OSgroup eq "windows") {
6755 $NoStrip = "-n";
6756 }
6757 my $Strings = join(" ", @_);
Andrey Ponomarenko9927e332012-10-19 10:50:48 +04006758 my $Res = `$CppFiltCmd $NoStrip $Strings`;
6759 if($?==139)
6760 { # segmentation fault
6761 printMsg("ERROR", "internal error - c++filt crashed, try to reduce MAX_COMMAND_LINE_ARGUMENTS constant");
6762 }
6763 return split(/\n/, $Res);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006764 }
6765 }
6766 }
6767}
6768
6769sub get_SignatureNoInfo($$)
6770{
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04006771 my ($Symbol, $LibVersion) = @_;
6772 if($Cache{"get_SignatureNoInfo"}{$LibVersion}{$Symbol}) {
6773 return $Cache{"get_SignatureNoInfo"}{$LibVersion}{$Symbol};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006774 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04006775 my ($MnglName, $VersionSpec, $SymbolVersion) = separate_symbol($Symbol);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006776 my $Signature = $tr_name{$MnglName}?$tr_name{$MnglName}:$MnglName;
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04006777 if($Symbol=~/\A(_Z|\?)/)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006778 { # C++
Andrey Ponomarenko1477d2c2012-11-12 18:55:45 +04006779 # some standard typedefs
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006780 $Signature=~s/\Qstd::basic_string<char, std::char_traits<char>, std::allocator<char> >\E/std::string/g;
6781 $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;
6782 }
Andrey Ponomarenko82b005f2012-11-12 17:58:14 +04006783 if(not $CheckObjectsOnly or $OSgroup=~/linux|bsd|beos/i)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006784 { # ELF format marks data as OBJECT
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04006785 if($GlobalDataObject{$LibVersion}{$Symbol}) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006786 $Signature .= " [data]";
6787 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04006788 elsif($Symbol!~/\A(_Z|\?)/) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006789 $Signature .= " (...)";
6790 }
6791 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04006792 if(my $ChargeLevel = get_ChargeLevel($Symbol, $LibVersion))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006793 {
Andrey Ponomarenko16934472012-03-29 15:37:04 +04006794 my $ShortName = substr($Signature, 0, find_center($Signature, "("));
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006795 $Signature=~s/\A\Q$ShortName\E/$ShortName $ChargeLevel/g;
6796 }
6797 if($SymbolVersion) {
6798 $Signature .= $VersionSpec.$SymbolVersion;
6799 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04006800 return ($Cache{"get_SignatureNoInfo"}{$LibVersion}{$Symbol} = $Signature);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006801}
6802
6803sub get_ChargeLevel($$)
6804{
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04006805 my ($Symbol, $LibVersion) = @_;
6806 return "" if($Symbol!~/\A(_Z|\?)/);
6807 if(defined $CompleteSignature{$LibVersion}{$Symbol}
6808 and $CompleteSignature{$LibVersion}{$Symbol}{"Header"})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006809 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04006810 if($CompleteSignature{$LibVersion}{$Symbol}{"Constructor"})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006811 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04006812 if($Symbol=~/C1E/) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006813 return "[in-charge]";
6814 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04006815 elsif($Symbol=~/C2E/) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006816 return "[not-in-charge]";
6817 }
6818 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04006819 elsif($CompleteSignature{$LibVersion}{$Symbol}{"Destructor"})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006820 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04006821 if($Symbol=~/D1E/) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006822 return "[in-charge]";
6823 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04006824 elsif($Symbol=~/D2E/) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006825 return "[not-in-charge]";
6826 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04006827 elsif($Symbol=~/D0E/) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006828 return "[in-charge-deleting]";
6829 }
6830 }
6831 }
6832 else
6833 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04006834 if($Symbol=~/C1E/) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006835 return "[in-charge]";
6836 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04006837 elsif($Symbol=~/C2E/) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006838 return "[not-in-charge]";
6839 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04006840 elsif($Symbol=~/D1E/) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006841 return "[in-charge]";
6842 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04006843 elsif($Symbol=~/D2E/) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006844 return "[not-in-charge]";
6845 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04006846 elsif($Symbol=~/D0E/) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006847 return "[in-charge-deleting]";
6848 }
6849 }
6850 return "";
6851}
6852
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04006853sub get_Signature_M($$)
6854{
6855 my ($Symbol, $LibVersion) = @_;
6856 my $Signature_M = $tr_name{$Symbol};
6857 if(my $RTid = $CompleteSignature{$LibVersion}{$Symbol}{"Return"})
6858 { # add return type name
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04006859 $Signature_M = $TypeInfo{$LibVersion}{$RTid}{"Name"}." ".$Signature_M;
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04006860 }
6861 return $Signature_M;
6862}
6863
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006864sub get_Signature($$)
6865{
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04006866 my ($Symbol, $LibVersion) = @_;
6867 if($Cache{"get_Signature"}{$LibVersion}{$Symbol}) {
6868 return $Cache{"get_Signature"}{$LibVersion}{$Symbol};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006869 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04006870 my ($MnglName, $VersionSpec, $SymbolVersion) = separate_symbol($Symbol);
6871 if(isPrivateData($MnglName) or not $CompleteSignature{$LibVersion}{$Symbol}{"Header"})
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04006872 { # non-public global data
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04006873 return get_SignatureNoInfo($Symbol, $LibVersion);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006874 }
6875 my ($Func_Signature, @Param_Types_FromUnmangledName) = ();
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04006876 my $ShortName = $CompleteSignature{$LibVersion}{$Symbol}{"ShortName"};
6877 if($Symbol=~/\A(_Z|\?)/)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006878 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04006879 if(my $ClassId = $CompleteSignature{$LibVersion}{$Symbol}{"Class"}) {
6880 $Func_Signature = $TypeInfo{$LibVersion}{$ClassId}{"Name"}."::".(($CompleteSignature{$LibVersion}{$Symbol}{"Destructor"})?"~":"").$ShortName;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006881 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04006882 elsif(my $NameSpace = $CompleteSignature{$LibVersion}{$Symbol}{"NameSpace"}) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006883 $Func_Signature = $NameSpace."::".$ShortName;
6884 }
6885 else {
6886 $Func_Signature = $ShortName;
6887 }
Andrey Ponomarenko07aea072012-11-12 16:15:07 +04006888 my ($Short, $Params) = split_Signature($tr_name{$MnglName});
6889 @Param_Types_FromUnmangledName = separate_Params($Params, 0, 1);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006890 }
6891 else {
6892 $Func_Signature = $MnglName;
6893 }
6894 my @ParamArray = ();
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04006895 foreach my $Pos (sort {int($a) <=> int($b)} keys(%{$CompleteSignature{$LibVersion}{$Symbol}{"Param"}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006896 {
6897 next if($Pos eq "");
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04006898 my $ParamTypeId = $CompleteSignature{$LibVersion}{$Symbol}{"Param"}{$Pos}{"type"};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006899 next if(not $ParamTypeId);
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04006900 my $ParamTypeName = $TypeInfo{$LibVersion}{$ParamTypeId}{"Name"};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006901 if(not $ParamTypeName) {
6902 $ParamTypeName = $Param_Types_FromUnmangledName[$Pos];
6903 }
6904 foreach my $Typedef (keys(%ChangedTypedef))
6905 {
6906 my $Base = $Typedef_BaseName{$LibVersion}{$Typedef};
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04006907 $ParamTypeName=~s/\b\Q$Typedef\E\b/$Base/g;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006908 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04006909 if(my $ParamName = $CompleteSignature{$LibVersion}{$Symbol}{"Param"}{$Pos}{"name"}) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006910 push(@ParamArray, create_member_decl($ParamTypeName, $ParamName));
6911 }
6912 else {
6913 push(@ParamArray, $ParamTypeName);
6914 }
6915 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04006916 if($CompleteSignature{$LibVersion}{$Symbol}{"Data"}
6917 or $GlobalDataObject{$LibVersion}{$Symbol}) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006918 $Func_Signature .= " [data]";
6919 }
6920 else
6921 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04006922 if(my $ChargeLevel = get_ChargeLevel($Symbol, $LibVersion))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006923 { # add [in-charge]
6924 $Func_Signature .= " ".$ChargeLevel;
6925 }
6926 $Func_Signature .= " (".join(", ", @ParamArray).")";
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04006927 if($CompleteSignature{$LibVersion}{$Symbol}{"Const"}
6928 or $Symbol=~/\A_ZN(V|)K/) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006929 $Func_Signature .= " const";
6930 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04006931 if($CompleteSignature{$LibVersion}{$Symbol}{"Volatile"}
6932 or $Symbol=~/\A_ZN(K|)V/) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006933 $Func_Signature .= " volatile";
6934 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04006935 if($CompleteSignature{$LibVersion}{$Symbol}{"Static"}
6936 and $Symbol=~/\A(_Z|\?)/)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006937 {# for static methods
6938 $Func_Signature .= " [static]";
6939 }
6940 }
6941 if(defined $ShowRetVal
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04006942 and my $ReturnTId = $CompleteSignature{$LibVersion}{$Symbol}{"Return"}) {
6943 $Func_Signature .= ":".$TypeInfo{$LibVersion}{$ReturnTId}{"Name"};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006944 }
6945 if($SymbolVersion) {
6946 $Func_Signature .= $VersionSpec.$SymbolVersion;
6947 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04006948 return ($Cache{"get_Signature"}{$LibVersion}{$Symbol} = $Func_Signature);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006949}
6950
6951sub create_member_decl($$)
6952{
6953 my ($TName, $Member) = @_;
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04006954 if($TName=~/\([\*]+\)/)
6955 {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006956 $TName=~s/\(([\*]+)\)/\($1$Member\)/;
6957 return $TName;
6958 }
6959 else
6960 {
6961 my @ArraySizes = ();
6962 while($TName=~s/(\[[^\[\]]*\])\Z//) {
6963 push(@ArraySizes, $1);
6964 }
6965 return $TName." ".$Member.join("", @ArraySizes);
6966 }
6967}
6968
6969sub getFuncType($)
6970{
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04006971 if($_[0] and my $Info = $LibInfo{$Version}{"info"}{$_[0]})
6972 {
6973 if($Info=~/type[ ]*:[ ]*@(\d+) /)
6974 {
6975 if(my $Type = $LibInfo{$Version}{"info_type"}{$1})
6976 {
6977 if($Type eq "method_type") {
6978 return "Method";
6979 }
6980 elsif($Type eq "function_type") {
6981 return "Function";
6982 }
6983 else {
6984 return "Other";
6985 }
6986 }
6987 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006988 }
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +04006989 return "";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006990}
6991
6992sub getFuncTypeId($)
6993{
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04006994 if($_[0] and my $Info = $LibInfo{$Version}{"info"}{$_[0]})
6995 {
6996 if($Info=~/type[ ]*:[ ]*@(\d+)( |\Z)/) {
6997 return $1;
6998 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006999 }
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04007000 return 0;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007001}
7002
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007003sub isAnon($)
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04007004{ # "._N" or "$_N" in older GCC versions
7005 return ($_[0] and $_[0]=~/(\.|\$)\_\d+|anon\-/);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007006}
7007
Andrey Ponomarenko9927e332012-10-19 10:50:48 +04007008sub formatName($$)
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04007009{ # type name correction
Andrey Ponomarenko9927e332012-10-19 10:50:48 +04007010 if(defined $Cache{"formatName"}{$_[1]}{$_[0]}) {
7011 return $Cache{"formatName"}{$_[1]}{$_[0]};
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04007012 }
7013
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +04007014 my $N = $_[0];
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04007015
Andrey Ponomarenko9927e332012-10-19 10:50:48 +04007016 if($_[1] ne "S")
7017 {
7018 $N=~s/\A[ ]+//g;
7019 $N=~s/[ ]+\Z//g;
7020 $N=~s/[ ]{2,}/ /g;
7021 }
7022
7023 $N=~s/[ ]*(\W)[ ]*/$1/g; # std::basic_string<char> const
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04007024
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +04007025 $N=~s/\bvolatile const\b/const volatile/g;
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04007026
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +04007027 $N=~s/\b(long long|short|long) unsigned\b/unsigned $1/g;
7028 $N=~s/\b(short|long) int\b/$1/g;
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04007029
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +04007030 $N=~s/([\)\]])(const|volatile)\b/$1 $2/g;
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04007031
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +04007032 while($N=~s/>>/> >/g) {};
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04007033
Andrey Ponomarenko9927e332012-10-19 10:50:48 +04007034 if($_[1] eq "S")
7035 {
7036 if(index($N, "operator")!=-1) {
7037 $N=~s/\b(operator[ ]*)> >/$1>>/;
7038 }
7039 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04007040
Andrey Ponomarenko9927e332012-10-19 10:50:48 +04007041 return ($Cache{"formatName"}{$_[1]}{$_[0]} = $N);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007042}
7043
7044sub get_HeaderDeps($$)
7045{
7046 my ($AbsPath, $LibVersion) = @_;
7047 return () if(not $AbsPath or not $LibVersion);
7048 if(defined $Cache{"get_HeaderDeps"}{$LibVersion}{$AbsPath}) {
7049 return @{$Cache{"get_HeaderDeps"}{$LibVersion}{$AbsPath}};
7050 }
7051 my %IncDir = ();
7052 detect_recursive_includes($AbsPath, $LibVersion);
7053 foreach my $HeaderPath (keys(%{$RecursiveIncludes{$LibVersion}{$AbsPath}}))
7054 {
7055 next if(not $HeaderPath);
7056 next if($MAIN_CPP_DIR and $HeaderPath=~/\A\Q$MAIN_CPP_DIR\E([\/\\]|\Z)/);
7057 my $Dir = get_dirname($HeaderPath);
7058 foreach my $Prefix (keys(%{$Header_Include_Prefix{$LibVersion}{$AbsPath}{$HeaderPath}}))
7059 {
7060 my $Dep = $Dir;
7061 if($Prefix)
7062 {
7063 if($OSgroup eq "windows")
7064 { # case insensitive seach on windows
7065 if(not $Dep=~s/[\/\\]+\Q$Prefix\E\Z//ig) {
7066 next;
7067 }
7068 }
7069 elsif($OSgroup eq "macos")
7070 { # seach in frameworks
7071 if(not $Dep=~s/[\/\\]+\Q$Prefix\E\Z//g)
7072 {
7073 if($HeaderPath=~/(.+\.framework)\/Headers\/([^\/]+)/)
7074 {# frameworks
7075 my ($HFramework, $HName) = ($1, $2);
7076 $Dep = $HFramework;
7077 }
7078 else
7079 {# mismatch
7080 next;
7081 }
7082 }
7083 }
7084 elsif(not $Dep=~s/[\/\\]+\Q$Prefix\E\Z//g)
7085 { # Linux, FreeBSD
7086 next;
7087 }
7088 }
7089 if(not $Dep)
7090 { # nothing to include
7091 next;
7092 }
7093 if(is_default_include_dir($Dep))
7094 { # included by the compiler
7095 next;
7096 }
7097 if(get_depth($Dep)==1)
7098 { # too short
7099 next;
7100 }
7101 if(isLibcDir($Dep))
7102 { # do NOT include /usr/include/{sys,bits}
7103 next;
7104 }
7105 $IncDir{$Dep}=1;
7106 }
7107 }
7108 $Cache{"get_HeaderDeps"}{$LibVersion}{$AbsPath} = sortIncPaths([keys(%IncDir)], $LibVersion);
7109 return @{$Cache{"get_HeaderDeps"}{$LibVersion}{$AbsPath}};
7110}
7111
7112sub sortIncPaths($$)
7113{
7114 my ($ArrRef, $LibVersion) = @_;
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04007115 if(not $ArrRef or $#{$ArrRef}<0) {
7116 return $ArrRef;
7117 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007118 @{$ArrRef} = sort {$b cmp $a} @{$ArrRef};
7119 @{$ArrRef} = sort {get_depth($a)<=>get_depth($b)} @{$ArrRef};
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04007120 @{$ArrRef} = sort {sortDeps($b, $a, $LibVersion)} @{$ArrRef};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007121 return $ArrRef;
7122}
7123
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04007124sub sortDeps($$$)
7125{
7126 if($Header_Dependency{$_[2]}{$_[0]}
7127 and not $Header_Dependency{$_[2]}{$_[1]}) {
7128 return 1;
7129 }
7130 elsif(not $Header_Dependency{$_[2]}{$_[0]}
7131 and $Header_Dependency{$_[2]}{$_[1]}) {
7132 return -1;
7133 }
7134 return 0;
7135}
7136
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007137sub joinPath($$) {
7138 return join($SLASH, @_);
7139}
7140
7141sub get_namespace_additions($)
7142{
7143 my $NameSpaces = $_[0];
7144 my ($Additions, $AddNameSpaceId) = ("", 1);
7145 foreach my $NS (sort {$a=~/_/ <=> $b=~/_/} sort {lc($a) cmp lc($b)} keys(%{$NameSpaces}))
7146 {
7147 next if($SkipNameSpaces{$Version}{$NS});
7148 next if(not $NS or $NameSpaces->{$NS}==-1);
7149 next if($NS=~/(\A|::)iterator(::|\Z)/i);
7150 next if($NS=~/\A__/i);
7151 next if(($NS=~/\Astd::/ or $NS=~/\A(std|tr1|rel_ops|fcntl)\Z/) and not $STDCXX_TESTING);
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04007152 $NestedNameSpaces{$Version}{$NS} = 1; # for future use in reports
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007153 my ($TypeDecl_Prefix, $TypeDecl_Suffix) = ();
7154 my @NS_Parts = split(/::/, $NS);
7155 next if($#NS_Parts==-1);
7156 next if($NS_Parts[0]=~/\A(random|or)\Z/);
7157 foreach my $NS_Part (@NS_Parts)
7158 {
7159 $TypeDecl_Prefix .= "namespace $NS_Part\{";
7160 $TypeDecl_Suffix .= "}";
7161 }
7162 my $TypeDecl = $TypeDecl_Prefix."typedef int tmp_add_type_$AddNameSpaceId;".$TypeDecl_Suffix;
7163 my $FuncDecl = "$NS\:\:tmp_add_type_$AddNameSpaceId tmp_add_func_$AddNameSpaceId(){return 0;};";
7164 $Additions.=" $TypeDecl\n $FuncDecl\n";
7165 $AddNameSpaceId+=1;
7166 }
7167 return $Additions;
7168}
7169
7170sub path_format($$)
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04007171{ # forward slash to pass into MinGW GCC
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007172 my ($Path, $Fmt) = @_;
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04007173 if($Fmt eq "windows")
7174 {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007175 $Path=~s/\//\\/g;
7176 $Path=lc($Path);
7177 }
7178 else {
7179 $Path=~s/\\/\//g;
7180 }
7181 return $Path;
7182}
7183
7184sub inc_opt($$)
7185{
7186 my ($Path, $Style) = @_;
7187 if($Style eq "GCC")
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04007188 { # GCC options
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007189 if($OSgroup eq "windows")
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04007190 { # to MinGW GCC
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007191 return "-I\"".path_format($Path, "unix")."\"";
7192 }
7193 elsif($OSgroup eq "macos"
7194 and $Path=~/\.framework\Z/)
7195 {# to Apple's GCC
7196 return "-F".esc(get_dirname($Path));
7197 }
7198 else {
7199 return "-I".esc($Path);
7200 }
7201 }
7202 elsif($Style eq "CL") {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04007203 return "/I \"".$Path."\"";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007204 }
7205 return "";
7206}
7207
7208sub platformSpecs($)
7209{
7210 my $LibVersion = $_[0];
7211 my $Arch = getArch($LibVersion);
7212 if($OStarget eq "symbian")
7213 { # options for GCCE compiler
7214 my %Symbian_Opts = map {$_=>1} (
7215 "-D__GCCE__",
7216 "-DUNICODE",
7217 "-fexceptions",
7218 "-D__SYMBIAN32__",
7219 "-D__MARM_INTERWORK__",
7220 "-D_UNICODE",
7221 "-D__S60_50__",
7222 "-D__S60_3X__",
7223 "-D__SERIES60_3X__",
7224 "-D__EPOC32__",
7225 "-D__MARM__",
7226 "-D__EABI__",
7227 "-D__MARM_ARMV5__",
7228 "-D__SUPPORT_CPP_EXCEPTIONS__",
7229 "-march=armv5t",
7230 "-mapcs",
7231 "-mthumb-interwork",
7232 "-DEKA2",
7233 "-DSYMBIAN_ENABLE_SPLIT_HEADERS"
7234 );
7235 return join(" ", keys(%Symbian_Opts));
7236 }
7237 elsif($OSgroup eq "windows"
7238 and get_dumpmachine($GCC_PATH)=~/mingw/i)
7239 { # add options to MinGW compiler
7240 # to simulate the MSVC compiler
7241 my %MinGW_Opts = map {$_=>1} (
7242 "-D_WIN32",
7243 "-D_STDCALL_SUPPORTED",
7244 "-D__int64=\"long long\"",
7245 "-D__int32=int",
7246 "-D__int16=short",
7247 "-D__int8=char",
7248 "-D__possibly_notnullterminated=\" \"",
7249 "-D__nullterminated=\" \"",
7250 "-D__nullnullterminated=\" \"",
7251 "-D__w64=\" \"",
7252 "-D__ptr32=\" \"",
7253 "-D__ptr64=\" \"",
7254 "-D__forceinline=inline",
7255 "-D__inline=inline",
7256 "-D__uuidof(x)=IID()",
7257 "-D__try=",
7258 "-D__except(x)=",
7259 "-D__declspec(x)=__attribute__((x))",
7260 "-D__pragma(x)=",
7261 "-D_inline=inline",
7262 "-D__forceinline=__inline",
7263 "-D__stdcall=__attribute__((__stdcall__))",
7264 "-D__cdecl=__attribute__((__cdecl__))",
7265 "-D__fastcall=__attribute__((__fastcall__))",
7266 "-D__thiscall=__attribute__((__thiscall__))",
7267 "-D_stdcall=__attribute__((__stdcall__))",
7268 "-D_cdecl=__attribute__((__cdecl__))",
7269 "-D_fastcall=__attribute__((__fastcall__))",
7270 "-D_thiscall=__attribute__((__thiscall__))",
7271 "-DSHSTDAPI_(x)=x",
7272 "-D_MSC_EXTENSIONS",
7273 "-DSECURITY_WIN32",
7274 "-D_MSC_VER=1500",
7275 "-D_USE_DECLSPECS_FOR_SAL",
7276 "-D__noop=\" \"",
7277 "-DDECLSPEC_DEPRECATED=\" \"",
7278 "-D__builtin_alignof(x)=__alignof__(x)",
7279 "-DSORTPP_PASS");
7280 if($Arch eq "x86") {
7281 $MinGW_Opts{"-D_M_IX86=300"}=1;
7282 }
7283 elsif($Arch eq "x86_64") {
7284 $MinGW_Opts{"-D_M_AMD64=300"}=1;
7285 }
7286 elsif($Arch eq "ia64") {
7287 $MinGW_Opts{"-D_M_IA64=300"}=1;
7288 }
7289 return join(" ", keys(%MinGW_Opts));
7290 }
7291 return "";
7292}
7293
7294my %C_Structure = map {$_=>1} (
7295# FIXME: Can't separate union and struct data types before dumping,
7296# so it sometimes cause compilation errors for unknown reason
7297# when trying to declare TYPE* tmp_add_class_N
7298# This is a list of such structures + list of other C structures
7299 "sigval",
7300 "sigevent",
7301 "sigaction",
7302 "sigvec",
7303 "sigstack",
7304 "timeval",
7305 "timezone",
7306 "rusage",
7307 "rlimit",
7308 "wait",
7309 "flock",
7310 "stat",
7311 "_stat",
7312 "stat32",
7313 "_stat32",
7314 "stat64",
7315 "_stat64",
7316 "_stati64",
7317 "if_nameindex",
7318 "usb_device",
7319 "sigaltstack",
7320 "sysinfo",
7321 "timeLocale",
7322 "tcp_debug",
7323 "rpc_createerr",
Andrey Ponomarenko82b005f2012-11-12 17:58:14 +04007324 # Other
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007325 "timespec",
7326 "random_data",
7327 "drand48_data",
7328 "_IO_marker",
7329 "_IO_FILE",
7330 "lconv",
7331 "sched_param",
7332 "tm",
7333 "itimerspec",
7334 "_pthread_cleanup_buffer",
7335 "fd_set",
Andrey Ponomarenko01117f12012-06-26 12:23:02 +04007336 "siginfo",
Andrey Ponomarenko82b005f2012-11-12 17:58:14 +04007337 "mallinfo",
7338 # Mac
7339 "_timex",
7340 "_class_t",
7341 "_category_t",
7342 "_class_ro_t",
7343 "_protocol_t",
7344 "_message_ref_t",
7345 "_super_message_ref_t",
7346 "_ivar_t",
7347 "_ivar_list_t"
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007348);
7349
7350sub getCompileCmd($$$)
7351{
7352 my ($Path, $Opt, $Inc) = @_;
7353 my $GccCall = $GCC_PATH;
7354 if($Opt) {
7355 $GccCall .= " ".$Opt;
7356 }
7357 $GccCall .= " -x ";
7358 if($OSgroup eq "macos") {
7359 $GccCall .= "objective-";
7360 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04007361 if(check_gcc($GCC_PATH, "4"))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007362 { # compile as "C++" header
7363 # to obtain complete dump using GCC 4.0
7364 $GccCall .= "c++-header";
7365 }
7366 else
7367 { # compile as "C++" source
7368 # GCC 3.3 cannot compile headers
7369 $GccCall .= "c++";
7370 }
7371 if(my $Opts = platformSpecs($Version))
7372 {# platform-specific options
7373 $GccCall .= " ".$Opts;
7374 }
7375 # allow extra qualifications
7376 # and other nonconformant code
Andrey Ponomarenko01117f12012-06-26 12:23:02 +04007377 $GccCall .= " -fpermissive";
7378 $GccCall .= " -w";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007379 if($NoStdInc)
7380 {
7381 $GccCall .= " -nostdinc";
7382 $GccCall .= " -nostdinc++";
7383 }
7384 if($CompilerOptions{$Version})
7385 { # user-defined options
7386 $GccCall .= " ".$CompilerOptions{$Version};
7387 }
Andrey Ponomarenkoa01311b2012-06-08 17:20:02 +04007388 $GccCall .= " \"$Path\"";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007389 if($Inc)
7390 { # include paths
7391 $GccCall .= " ".$Inc;
7392 }
7393 return $GccCall;
7394}
7395
Andrey Ponomarenko01117f12012-06-26 12:23:02 +04007396sub detectPreamble($$)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007397{
Andrey Ponomarenko01117f12012-06-26 12:23:02 +04007398 my ($Content, $LibVersion) = @_;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007399 my %HeaderElems = (
7400 # Types
7401 "stdio.h" => ["FILE", "va_list"],
Andrey Ponomarenko85043792012-05-14 16:48:07 +04007402 "stddef.h" => ["NULL", "ptrdiff_t"],
Andrey Ponomarenko9927e332012-10-19 10:50:48 +04007403 "stdint.h" => ["uint8_t", "uint16_t", "uint32_t", "uint64_t",
7404 "int8_t", "int16_t", "int32_t", "int64_t"],
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007405 "time.h" => ["time_t"],
7406 "sys/types.h" => ["ssize_t", "u_int32_t", "u_short", "u_char",
Andrey Ponomarenko9927e332012-10-19 10:50:48 +04007407 "u_int", "off_t", "u_quad_t", "u_long", "mode_t"],
7408 "unistd.h" => ["gid_t", "uid_t", "socklen_t"],
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007409 "stdbool.h" => ["_Bool"],
7410 "rpc/xdr.h" => ["bool_t"],
7411 "in_systm.h" => ["n_long", "n_short"],
7412 # Fields
Andrey Ponomarenkobede8372012-03-29 17:43:21 +04007413 "arpa/inet.h" => ["fw_src", "ip_src"],
7414 # Functions
Andrey Ponomarenko9927e332012-10-19 10:50:48 +04007415 "stdlib.h" => ["free", "malloc", "size_t"],
Andrey Ponomarenko85043792012-05-14 16:48:07 +04007416 "string.h" => ["memmove", "strcmp"]
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007417 );
7418 my %AutoPreamble = ();
Andrey Ponomarenko85043792012-05-14 16:48:07 +04007419 foreach (keys(%HeaderElems))
7420 {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007421 foreach my $Elem (@{$HeaderElems{$_}}) {
Andrey Ponomarenko9927e332012-10-19 10:50:48 +04007422 $AutoPreamble{$Elem} = $_;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007423 }
7424 }
Andrey Ponomarenko01117f12012-06-26 12:23:02 +04007425 my %Types = ();
7426 while($Content=~s/error\:\s*(field\s*|)\W+(.+?)\W+//)
7427 { # error: 'FILE' has not been declared
Andrey Ponomarenko9927e332012-10-19 10:50:48 +04007428 $Types{$2} = 1;
Andrey Ponomarenko01117f12012-06-26 12:23:02 +04007429 }
7430 if(keys(%Types))
7431 {
7432 my %AddHeaders = ();
7433 foreach my $Type (keys(%Types))
7434 {
7435 if(my $Header = $AutoPreamble{$Type})
7436 {
Andrey Ponomarenko9927e332012-10-19 10:50:48 +04007437 if(my $Path = identifyHeader($Header, $LibVersion))
7438 {
7439 if(skipHeader($Path, $LibVersion)) {
7440 next;
7441 }
7442 $Path = path_format($Path, $OSgroup);
7443 $AddHeaders{$Path}{"Type"} = $Type;
7444 $AddHeaders{$Path}{"Header"} = $Header;
Andrey Ponomarenko01117f12012-06-26 12:23:02 +04007445 }
7446 }
7447 }
7448 if(keys(%AddHeaders)) {
Andrey Ponomarenko9927e332012-10-19 10:50:48 +04007449 return \%AddHeaders;
Andrey Ponomarenko01117f12012-06-26 12:23:02 +04007450 }
7451 }
Andrey Ponomarenko9927e332012-10-19 10:50:48 +04007452 return undef;
Andrey Ponomarenko01117f12012-06-26 12:23:02 +04007453}
7454
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +04007455sub checkCTags($)
7456{
7457 my $Path = $_[0];
7458 if(not $Path) {
7459 return;
7460 }
7461 my $CTags = get_CmdPath("ctags");
7462 if(not $CTags) {
7463 return;
7464 }
Andrey Ponomarenkobdc85a92012-11-12 17:28:12 +04007465
Andrey Ponomarenko82b005f2012-11-12 17:58:14 +04007466 if($OSgroup ne "linux")
7467 { # macos, freebsd, etc.
Andrey Ponomarenkobdc85a92012-11-12 17:28:12 +04007468 my $Info = `$CTags --version 2>\"$TMP_DIR/null\"`;
7469 if($Info!~/exuberant/i)
7470 {
7471 printMsg("WARNING", "incompatible version of \'ctags\' program");
7472 return;
7473 }
7474 }
7475
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +04007476 my $Out = $TMP_DIR."/ctags.txt";
Andrey Ponomarenkobdc85a92012-11-12 17:28:12 +04007477 system("$CTags --c-kinds=pxn -f \"$Out\" \"$Path\" 2>\"$TMP_DIR/null\"");
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +04007478 if($Debug) {
Andrey Ponomarenko9927e332012-10-19 10:50:48 +04007479 copy($Out, $DEBUG_PATH{$Version}."/ctags.txt");
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +04007480 }
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +04007481 open(CTAGS, "<", $Out);
7482 while(my $Line = <CTAGS>)
7483 {
7484 chomp($Line);
7485 my ($Name, $Header, $Def, $Type, $Scpe) = split(/\t/, $Line);
Andrey Ponomarenko9927e332012-10-19 10:50:48 +04007486 if(defined $Intrinsic_Keywords{$Name})
7487 { # noise
7488 next;
7489 }
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +04007490 if($Type eq "n")
7491 {
Andrey Ponomarenko9927e332012-10-19 10:50:48 +04007492 if(index($Scpe, "class:")==0) {
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +04007493 next;
7494 }
Andrey Ponomarenko9927e332012-10-19 10:50:48 +04007495 if(index($Scpe, "struct:")==0) {
7496 next;
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +04007497 }
Andrey Ponomarenko9927e332012-10-19 10:50:48 +04007498 if(index($Scpe, "namespace:")==0)
7499 {
7500 if($Scpe=~s/\Anamespace://) {
7501 $Name = $Scpe."::".$Name;
7502 }
7503 }
7504 $TUnit_NameSpaces{$Version}{$Name} = 1;
7505 }
7506 elsif($Type eq "p")
7507 {
7508 if(not $Scpe or index($Scpe, "namespace:")==0) {
7509 $TUnit_Funcs{$Version}{$Name} = 1;
7510 }
7511 }
7512 elsif($Type eq "x")
7513 {
7514 if(not $Scpe or index($Scpe, "namespace:")==0) {
7515 $TUnit_Vars{$Version}{$Name} = 1;
7516 }
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +04007517 }
7518 }
7519 close(CTAGS);
7520}
7521
Andrey Ponomarenko01117f12012-06-26 12:23:02 +04007522sub getDump()
7523{
7524 if(not $GCC_PATH) {
7525 exitStatus("Error", "internal error - GCC path is not set");
7526 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04007527 my $TmpHeaderPath = $TMP_DIR."/dump".$Version.".h";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007528 my $MHeaderPath = $TmpHeaderPath;
Andrey Ponomarenko85043792012-05-14 16:48:07 +04007529 open(TMP_HEADER, ">", $TmpHeaderPath) || die ("can't open file \'$TmpHeaderPath\': $!\n");
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007530 if(my $AddDefines = $Descriptor{$Version}{"Defines"})
7531 {
7532 $AddDefines=~s/\n\s+/\n /g;
Andrey Ponomarenko85043792012-05-14 16:48:07 +04007533 print TMP_HEADER "\n // add defines\n ".$AddDefines."\n";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007534 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +04007535 print TMP_HEADER "\n // add includes\n";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007536 my @PreambleHeaders = keys(%{$Include_Preamble{$Version}});
7537 @PreambleHeaders = sort {int($Include_Preamble{$Version}{$a}{"Position"})<=>int($Include_Preamble{$Version}{$b}{"Position"})} @PreambleHeaders;
7538 foreach my $Header_Path (@PreambleHeaders) {
Andrey Ponomarenko85043792012-05-14 16:48:07 +04007539 print TMP_HEADER " #include \"".path_format($Header_Path, "unix")."\"\n";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007540 }
7541 my @Headers = keys(%{$Registered_Headers{$Version}});
7542 @Headers = sort {int($Registered_Headers{$Version}{$a}{"Pos"})<=>int($Registered_Headers{$Version}{$b}{"Pos"})} @Headers;
7543 foreach my $Header_Path (@Headers)
7544 {
7545 next if($Include_Preamble{$Version}{$Header_Path});
Andrey Ponomarenko85043792012-05-14 16:48:07 +04007546 print TMP_HEADER " #include \"".path_format($Header_Path, "unix")."\"\n";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007547 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +04007548 close(TMP_HEADER);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007549 my $IncludeString = getIncString(getIncPaths(@PreambleHeaders, @Headers), "GCC");
Andrey Ponomarenko9927e332012-10-19 10:50:48 +04007550
Andrey Ponomarenko07aea072012-11-12 16:15:07 +04007551 if($ExtraInfo)
7552 { # extra information for other tools
7553 writeFile($ExtraInfo."/include-string", $IncludeString);
7554 }
7555
Andrey Ponomarenko9927e332012-10-19 10:50:48 +04007556 if(not keys(%{$TargetHeaders{$Version}}))
7557 { # Target headers
7558 addTargetHeaders($Version);
7559 }
7560
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007561 if($Debug)
7562 { # debug mode
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04007563 writeFile($DEBUG_PATH{$Version}."/headers/direct-includes.txt", Dumper($Header_Includes{$Version}));
7564 writeFile($DEBUG_PATH{$Version}."/headers/recursive-includes.txt", Dumper($RecursiveIncludes{$Version}));
7565 writeFile($DEBUG_PATH{$Version}."/headers/include-paths.txt", Dumper($Cache{"get_HeaderDeps"}{$Version}));
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04007566 writeFile($DEBUG_PATH{$Version}."/headers/default-paths.txt", Dumper(\%DefaultIncPaths));
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007567 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +04007568
Andrey Ponomarenko85043792012-05-14 16:48:07 +04007569 # clean memory
7570 %RecursiveIncludes = ();
7571 %Header_Include_Prefix = ();
7572 %Header_Includes = ();
7573
7574 # clean cache
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04007575 delete($Cache{"identifyHeader"});
Andrey Ponomarenko85043792012-05-14 16:48:07 +04007576 delete($Cache{"detect_header_includes"});
7577 delete($Cache{"selectSystemHeader"});
7578
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007579 # preprocessing stage
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +04007580 my $Pre = callPreprocessor($TmpHeaderPath, $IncludeString, $Version);
7581 checkPreprocessedUnit($Pre);
Andrey Ponomarenko85043792012-05-14 16:48:07 +04007582
7583 # clean memory
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04007584 delete($Include_Neighbors{$Version});
Andrey Ponomarenko85043792012-05-14 16:48:07 +04007585
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +04007586 if($COMMON_LANGUAGE{$Version} eq "C++") {
7587 checkCTags($Pre);
7588 }
7589
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007590 my $MContent = "";
7591 my $PreprocessCmd = getCompileCmd($TmpHeaderPath, "-E", $IncludeString);
7592 if($OStarget eq "windows"
7593 and get_dumpmachine($GCC_PATH)=~/mingw/i
7594 and $MinGWMode{$Version}!=-1)
7595 { # modify headers to compile by MinGW
7596 if(not $MContent)
7597 { # preprocessing
Andrey Ponomarenkoa01311b2012-06-08 17:20:02 +04007598 $MContent = `$PreprocessCmd 2>\"$TMP_DIR/null\"`;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007599 }
7600 if($MContent=~s/__asm\s*(\{[^{}]*?\}|[^{};]*)//g)
7601 { # __asm { ... }
7602 $MinGWMode{$Version}=1;
7603 }
7604 if($MContent=~s/\s+(\/ \/.*?)\n/\n/g)
7605 { # comments after preprocessing
7606 $MinGWMode{$Version}=1;
7607 }
7608 if($MContent=~s/(\W)(0x[a-f]+|\d+)(i|ui)(8|16|32|64)(\W)/$1$2$5/g)
7609 { # 0xffui8
7610 $MinGWMode{$Version}=1;
7611 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +04007612 if($MinGWMode{$Version})
7613 {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007614 printMsg("INFO", "Using MinGW compatibility mode");
Andrey Ponomarenkob8d203d2012-05-25 18:11:07 +04007615 $MHeaderPath = $TMP_DIR."/dump$Version.i";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007616 }
7617 }
7618 if(($COMMON_LANGUAGE{$Version} eq "C" or $CheckHeadersOnly)
Andrey Ponomarenko07aea072012-11-12 16:15:07 +04007619 and $CppMode{$Version}!=-1 and not $CppCompat)
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04007620 { # rename C++ keywords in C code
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007621 if(not $MContent)
7622 { # preprocessing
Andrey Ponomarenkoa01311b2012-06-08 17:20:02 +04007623 $MContent = `$PreprocessCmd 2>\"$TMP_DIR/null\"`;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007624 }
7625 my $RegExp_C = join("|", keys(%CppKeywords_C));
7626 my $RegExp_F = join("|", keys(%CppKeywords_F));
7627 my $RegExp_O = join("|", keys(%CppKeywords_O));
Andrey Ponomarenkobdc85a92012-11-12 17:28:12 +04007628
7629 my $Detected = undef;
7630
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007631 while($MContent=~s/(\A|\n[^\#\/\n][^\n]*?|\n)(\*\s*|\s+|\@|\,|\()($RegExp_C|$RegExp_F)(\s*(\,|\)|\;|\-\>|\.|\:\s*\d))/$1$2c99_$3$4/g)
7632 { # MATCH:
7633 # int foo(int new, int class, int (*new)(int));
7634 # unsigned private: 8;
7635 # DO NOT MATCH:
7636 # #pragma GCC visibility push(default)
Andrey Ponomarenko07aea072012-11-12 16:15:07 +04007637 $CppMode{$Version} = 1;
Andrey Ponomarenkobdc85a92012-11-12 17:28:12 +04007638 $Detected = "$1$2$3$4" if(not defined $Detected);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007639 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04007640 if($MContent=~s/([^\w\s]|\w\s+)(?<!operator )(delete)(\s*\()/$1c99_$2$3/g)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007641 { # MATCH:
7642 # int delete(...);
7643 # int explicit(...);
7644 # DO NOT MATCH:
7645 # void operator delete(...)
Andrey Ponomarenko07aea072012-11-12 16:15:07 +04007646 $CppMode{$Version} = 1;
Andrey Ponomarenkobdc85a92012-11-12 17:28:12 +04007647 $Detected = "$1$2$3" if(not defined $Detected);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007648 }
7649 if($MContent=~s/(\s+)($RegExp_O)(\s*(\;|\:))/$1c99_$2$3/g)
7650 { # MATCH:
7651 # int bool;
7652 # DO NOT MATCH:
7653 # bool X;
7654 # return *this;
7655 # throw;
Andrey Ponomarenko07aea072012-11-12 16:15:07 +04007656 $CppMode{$Version} = 1;
Andrey Ponomarenkobdc85a92012-11-12 17:28:12 +04007657 $Detected = "$1$2$3" if(not defined $Detected);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007658 }
7659 if($MContent=~s/(\s+)(operator)(\s*(\(\s*\)\s*[^\(\s]|\(\s*[^\)\s]))/$1c99_$2$3/g)
7660 { # MATCH:
7661 # int operator(...);
7662 # DO NOT MATCH:
7663 # int operator()(...);
Andrey Ponomarenko07aea072012-11-12 16:15:07 +04007664 $CppMode{$Version} = 1;
Andrey Ponomarenkobdc85a92012-11-12 17:28:12 +04007665 $Detected = "$1$2$3" if(not defined $Detected);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007666 }
7667 if($MContent=~s/([^\w\(\,\s]\s*|\s+)(operator)(\s*(\,\s*[^\(\s]|\)))/$1c99_$2$3/g)
7668 { # MATCH:
7669 # int foo(int operator);
7670 # int foo(int operator, int other);
7671 # DO NOT MATCH:
7672 # int operator,(...);
Andrey Ponomarenko07aea072012-11-12 16:15:07 +04007673 $CppMode{$Version} = 1;
Andrey Ponomarenkobdc85a92012-11-12 17:28:12 +04007674 $Detected = "$1$2$3" if(not defined $Detected);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007675 }
7676 if($MContent=~s/(\*\s*|\w\s+)(bool)(\s*(\,|\)))/$1c99_$2$3/g)
7677 { # MATCH:
7678 # int foo(gboolean *bool);
7679 # DO NOT MATCH:
7680 # void setTabEnabled(int index, bool);
Andrey Ponomarenko07aea072012-11-12 16:15:07 +04007681 $CppMode{$Version} = 1;
Andrey Ponomarenkobdc85a92012-11-12 17:28:12 +04007682 $Detected = "$1$2$3" if(not defined $Detected);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007683 }
Andrey Ponomarenko9927e332012-10-19 10:50:48 +04007684 if($MContent=~s/(\w)(\s*[^\w\(\,\s]\s*|\s+)(this|throw)(\s*[\,\)])/$1$2c99_$3$4/g)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007685 { # MATCH:
7686 # int foo(int* this);
7687 # int bar(int this);
Andrey Ponomarenko9927e332012-10-19 10:50:48 +04007688 # int baz(int throw);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007689 # DO NOT MATCH:
Andrey Ponomarenko9927e332012-10-19 10:50:48 +04007690 # foo(X, this);
Andrey Ponomarenko07aea072012-11-12 16:15:07 +04007691 $CppMode{$Version} = 1;
Andrey Ponomarenkobdc85a92012-11-12 17:28:12 +04007692 $Detected = "$1$2$3$4" if(not defined $Detected);
Andrey Ponomarenko07aea072012-11-12 16:15:07 +04007693 }
7694
7695 if($CppMode{$Version} == 1)
7696 {
Andrey Ponomarenkobdc85a92012-11-12 17:28:12 +04007697 if($Debug)
7698 {
7699 $Detected=~s/\A\s+//g;
7700 printMsg("INFO", "Detected code: \"$Detected\"");
Andrey Ponomarenko07aea072012-11-12 16:15:07 +04007701 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007702 }
Andrey Ponomarenko9927e332012-10-19 10:50:48 +04007703
7704 # remove typedef enum NAME NAME;
7705 my @FwdTypedefs = $MContent=~/typedef\s+enum\s+(\w+)\s+(\w+);/g;
7706 my $N = 0;
7707 while($N<=$#FwdTypedefs-1)
7708 {
7709 my $S = $FwdTypedefs[$N];
7710 if($S eq $FwdTypedefs[$N+1])
7711 {
7712 $MContent=~s/typedef\s+enum\s+\Q$S\E\s+\Q$S\E;//g;
Andrey Ponomarenko07aea072012-11-12 16:15:07 +04007713 $CppMode{$Version}=1;
Andrey Ponomarenko9927e332012-10-19 10:50:48 +04007714 }
7715 $N+=2;
7716 }
7717
Andrey Ponomarenko07aea072012-11-12 16:15:07 +04007718 if($CppMode{$Version}==1)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007719 { # try to change C++ "keyword" to "c99_keyword"
Andrey Ponomarenko07aea072012-11-12 16:15:07 +04007720 printMsg("INFO", "Using C++ compatibility mode");
Andrey Ponomarenkob8d203d2012-05-25 18:11:07 +04007721 $MHeaderPath = $TMP_DIR."/dump$Version.i";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007722 }
7723 }
Andrey Ponomarenko07aea072012-11-12 16:15:07 +04007724 if($CppMode{$Version}==1
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007725 or $MinGWMode{$Version}==1)
7726 { # compile the corrected preprocessor output
7727 writeFile($MHeaderPath, $MContent);
7728 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +04007729
7730 # clean memory
7731 undef $MContent;
7732
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007733 if($COMMON_LANGUAGE{$Version} eq "C++")
7734 { # add classes and namespaces to the dump
7735 my $CHdump = "-fdump-class-hierarchy -c";
Andrey Ponomarenko07aea072012-11-12 16:15:07 +04007736 if($CppMode{$Version}==1
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007737 or $MinGWMode{$Version}==1) {
7738 $CHdump .= " -fpreprocessed";
7739 }
7740 my $ClassHierarchyCmd = getCompileCmd($MHeaderPath, $CHdump, $IncludeString);
7741 chdir($TMP_DIR);
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04007742 system($ClassHierarchyCmd." >null 2>&1");
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007743 chdir($ORIG_DIR);
7744 if(my $ClassDump = (cmd_find($TMP_DIR,"f","*.class",1))[0])
7745 {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007746 my $Content = readFile($ClassDump);
7747 foreach my $ClassInfo (split(/\n\n/, $Content))
7748 {
7749 if($ClassInfo=~/\AClass\s+(.+)\s*/i)
7750 {
7751 my $CName = $1;
7752 next if($CName=~/\A(__|_objc_|_opaque_)/);
7753 $TUnit_NameSpaces{$Version}{$CName} = -1;
7754 if($CName=~/\A[\w:]+\Z/)
7755 { # classes
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +04007756 $TUnit_Classes{$Version}{$CName} = 1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007757 }
7758 if($CName=~/(\w[\w:]*)::/)
7759 { # namespaces
7760 my $NS = $1;
7761 if(not defined $TUnit_NameSpaces{$Version}{$NS}) {
7762 $TUnit_NameSpaces{$Version}{$NS} = 1;
7763 }
7764 }
7765 }
7766 elsif($ClassInfo=~/\AVtable\s+for\s+(.+)\n((.|\n)+)\Z/i)
7767 { # read v-tables (advanced approach)
7768 my ($CName, $VTable) = ($1, $2);
7769 $ClassVTable_Content{$Version}{$CName} = $VTable;
7770 }
7771 }
Andrey Ponomarenkoa01311b2012-06-08 17:20:02 +04007772 foreach my $NS (keys(%{$AddNameSpaces{$Version}}))
7773 { # add user-defined namespaces
7774 $TUnit_NameSpaces{$Version}{$NS} = 1;
7775 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007776 if($Debug)
7777 { # debug mode
7778 mkpath($DEBUG_PATH{$Version});
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04007779 copy($ClassDump, $DEBUG_PATH{$Version}."/class-hierarchy-dump.txt");
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007780 }
7781 unlink($ClassDump);
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +04007782 }
7783
7784 # add namespaces and classes
7785 if(my $NS_Add = get_namespace_additions($TUnit_NameSpaces{$Version}))
7786 { # GCC on all supported platforms does not include namespaces to the dump by default
7787 appendFile($MHeaderPath, "\n // add namespaces\n".$NS_Add);
7788 }
7789 # some GCC versions don't include class methods to the TU dump by default
7790 my ($AddClass, $ClassNum) = ("", 0);
7791 foreach my $CName (sort keys(%{$TUnit_Classes{$Version}}))
7792 {
7793 next if($C_Structure{$CName});
7794 next if(not $STDCXX_TESTING and $CName=~/\Astd::/);
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +04007795 next if($SkipTypes{$Version}{$CName});
Andrey Ponomarenko82b005f2012-11-12 17:58:14 +04007796 if($OSgroup eq "linux")
7797 {
7798 next if(($CName=~tr![:]!!)>2);
7799 if($CName=~/\A(.+)::[^:]+\Z/)
7800 { # will be added by name space
7801 next;
7802 }
7803 }
7804 else
7805 {
7806 if($CName=~/\A(.+)::[^:]+\Z/
7807 and $TUnit_Classes{$Version}{$1})
7808 { # classes inside other classes
7809 next;
7810 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007811 }
Andrey Ponomarenko9927e332012-10-19 10:50:48 +04007812 if(defined $TUnit_Funcs{$Version}{$CName})
7813 { # the same name for a function and type
7814 next;
7815 }
7816 if(defined $TUnit_Vars{$Version}{$CName})
7817 { # the same name for a variable and type
7818 next;
7819 }
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +04007820 $AddClass .= " $CName* tmp_add_class_".($ClassNum++).";\n";
7821 }
7822 if($AddClass) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007823 appendFile($MHeaderPath, "\n // add classes\n".$AddClass);
7824 }
7825 }
7826 writeLog($Version, "Temporary header file \'$TmpHeaderPath\' with the following content will be compiled to create GCC translation unit dump:\n".readFile($TmpHeaderPath)."\n");
7827 # create TU dump
7828 my $TUdump = "-fdump-translation-unit -fkeep-inline-functions -c";
Andrey Ponomarenko07aea072012-11-12 16:15:07 +04007829 if($CppMode{$Version}==1
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007830 or $MinGWMode{$Version}==1) {
7831 $TUdump .= " -fpreprocessed";
7832 }
7833 my $SyntaxTreeCmd = getCompileCmd($MHeaderPath, $TUdump, $IncludeString);
7834 writeLog($Version, "The GCC parameters:\n $SyntaxTreeCmd\n\n");
7835 chdir($TMP_DIR);
Andrey Ponomarenkoa01311b2012-06-08 17:20:02 +04007836 system($SyntaxTreeCmd." >\"$TMP_DIR/tu_errors\" 2>&1");
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007837 if($?)
7838 { # failed to compile, but the TU dump still can be created
Andrey Ponomarenko01117f12012-06-26 12:23:02 +04007839 if(my $Errors = readFile($TMP_DIR."/tu_errors"))
7840 { # try to recompile
7841 # FIXME: handle other errors and try to recompile
Andrey Ponomarenko07aea072012-11-12 16:15:07 +04007842 if($CppMode{$Version}==1
Andrey Ponomarenko01117f12012-06-26 12:23:02 +04007843 and $Errors=~/c99_/)
7844 { # disable c99 mode and try again
Andrey Ponomarenko07aea072012-11-12 16:15:07 +04007845 $CppMode{$Version}=-1;
7846 printMsg("INFO", "Disabling C++ compatibility mode");
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007847 resetLogging($Version);
7848 $TMP_DIR = tempdir(CLEANUP=>1);
7849 return getDump();
7850 }
Andrey Ponomarenko01117f12012-06-26 12:23:02 +04007851 elsif($AutoPreambleMode{$Version}!=-1
Andrey Ponomarenko9927e332012-10-19 10:50:48 +04007852 and my $AddHeaders = detectPreamble($Errors, $Version))
Andrey Ponomarenko01117f12012-06-26 12:23:02 +04007853 { # add auto preamble headers and try again
7854 $AutoPreambleMode{$Version}=-1;
Andrey Ponomarenko9927e332012-10-19 10:50:48 +04007855 my @Headers = sort {$b cmp $a} keys(%{$AddHeaders}); # sys/types.h should be the first
Andrey Ponomarenko01117f12012-06-26 12:23:02 +04007856 foreach my $Num (0 .. $#Headers)
7857 {
7858 my $Path = $Headers[$Num];
7859 if(defined $Include_Preamble{$Version}{$Path})
7860 { # already added
7861 next;
7862 }
7863 $Include_Preamble{$Version}{$Path}{"Position"} = keys(%{$Include_Preamble{$Version}});
Andrey Ponomarenko9927e332012-10-19 10:50:48 +04007864 printMsg("INFO", "Add \'".$AddHeaders->{$Path}{"Header"}."\' preamble header for \'".$AddHeaders->{$Path}{"Type"}."\'");
Andrey Ponomarenko01117f12012-06-26 12:23:02 +04007865 }
7866 resetLogging($Version);
7867 $TMP_DIR = tempdir(CLEANUP=>1);
7868 return getDump();
7869 }
7870 elsif($Cpp0xMode{$Version}!=-1
7871 and ($Errors=~/\Q-std=c++0x\E/
7872 or $Errors=~/is not a class or namespace/))
7873 { # c++0x: enum class
7874 $Cpp0xMode{$Version}=-1;
7875 printMsg("INFO", "Enabling c++0x mode");
7876 resetLogging($Version);
7877 $TMP_DIR = tempdir(CLEANUP=>1);
7878 $CompilerOptions{$Version} .= " -std=c++0x";
7879 return getDump();
7880 }
7881 elsif($MinGWMode{$Version}==1)
7882 { # disable MinGW mode and try again
7883 $MinGWMode{$Version}=-1;
7884 resetLogging($Version);
7885 $TMP_DIR = tempdir(CLEANUP=>1);
7886 return getDump();
7887 }
7888 writeLog($Version, $Errors);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007889 }
Andrey Ponomarenko01117f12012-06-26 12:23:02 +04007890 else {
7891 writeLog($Version, "$!: $?\n");
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007892 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007893 printMsg("ERROR", "some errors occurred when compiling headers");
7894 printErrorLog($Version);
7895 $COMPILE_ERRORS = $ERROR_CODE{"Compile_Error"};
7896 writeLog($Version, "\n");# new line
7897 }
7898 chdir($ORIG_DIR);
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +04007899 unlink($TmpHeaderPath);
7900 unlink($MHeaderPath);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007901 return (cmd_find($TMP_DIR,"f","*.tu",1))[0];
7902}
7903
7904sub cmd_file($)
7905{
7906 my $Path = $_[0];
7907 return "" if(not $Path or not -e $Path);
7908 if(my $CmdPath = get_CmdPath("file")) {
7909 return `$CmdPath -b \"$Path\"`;
7910 }
7911 return "";
7912}
7913
7914sub getIncString($$)
7915{
7916 my ($ArrRef, $Style) = @_;
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04007917 return "" if(not $ArrRef or $#{$ArrRef}<0);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007918 my $String = "";
7919 foreach (@{$ArrRef}) {
7920 $String .= " ".inc_opt($_, $Style);
7921 }
7922 return $String;
7923}
7924
7925sub getIncPaths(@)
7926{
7927 my @HeaderPaths = @_;
7928 my @IncPaths = ();
7929 if($INC_PATH_AUTODETECT{$Version})
7930 { # auto-detecting dependencies
7931 my %Includes = ();
7932 foreach my $HPath (@HeaderPaths)
7933 {
7934 foreach my $Dir (get_HeaderDeps($HPath, $Version))
7935 {
7936 if($Skip_Include_Paths{$Version}{$Dir}) {
7937 next;
7938 }
Andrey Ponomarenkoa01311b2012-06-08 17:20:02 +04007939 if($SystemRoot)
7940 {
7941 if($Skip_Include_Paths{$Version}{$SystemRoot.$Dir}) {
7942 next;
7943 }
7944 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007945 $Includes{$Dir}=1;
7946 }
7947 }
7948 foreach my $Dir (keys(%{$Add_Include_Paths{$Version}}))
7949 { # added by user
7950 next if($Includes{$Dir});
7951 push(@IncPaths, $Dir);
7952 }
7953 foreach my $Dir (@{sortIncPaths([keys(%Includes)], $Version)}) {
7954 push(@IncPaths, $Dir);
7955 }
7956 }
7957 else
7958 { # user-defined paths
7959 foreach my $Dir (sort {get_depth($a)<=>get_depth($b)}
7960 sort {$b cmp $a} keys(%{$Include_Paths{$Version}})) {
7961 push(@IncPaths, $Dir);
7962 }
7963 }
7964 return \@IncPaths;
7965}
7966
7967sub callPreprocessor($$$)
7968{
7969 my ($Path, $Inc, $LibVersion) = @_;
7970 return "" if(not $Path or not -f $Path);
7971 my $IncludeString=$Inc;
7972 if(not $Inc) {
7973 $IncludeString = getIncString(getIncPaths($Path), "GCC");
7974 }
7975 my $Cmd = getCompileCmd($Path, "-dD -E", $IncludeString);
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +04007976 my $Out = $TMP_DIR."/preprocessed.h";
Andrey Ponomarenkoa01311b2012-06-08 17:20:02 +04007977 system($Cmd." >\"$Out\" 2>\"$TMP_DIR/null\"");
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04007978 return $Out;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007979}
7980
7981sub cmd_find($$$$)
7982{ # native "find" is much faster than File::Find (~6x)
7983 # also the File::Find doesn't support --maxdepth N option
7984 # so using the cross-platform wrapper for the native one
7985 my ($Path, $Type, $Name, $MaxDepth) = @_;
7986 return () if(not $Path or not -e $Path);
7987 if($OSgroup eq "windows")
7988 {
7989 my $DirCmd = get_CmdPath("dir");
7990 if(not $DirCmd) {
7991 exitStatus("Not_Found", "can't find \"dir\" command");
7992 }
7993 $Path=~s/[\\]+\Z//;
7994 $Path = get_abs_path($Path);
7995 $Path = path_format($Path, $OSgroup);
7996 my $Cmd = $DirCmd." \"$Path\" /B /O";
7997 if($MaxDepth!=1) {
7998 $Cmd .= " /S";
7999 }
8000 if($Type eq "d") {
8001 $Cmd .= " /AD";
8002 }
8003 my @Files = ();
8004 if($Name)
8005 { # FIXME: how to search file names in MS shell?
8006 $Name=~s/\*/.*/g if($Name!~/\]/);
8007 foreach my $File (split(/\n/, `$Cmd`))
8008 {
8009 if($File=~/$Name\Z/i) {
8010 push(@Files, $File);
8011 }
8012 }
8013 }
8014 else {
Andrey Ponomarenkoa01311b2012-06-08 17:20:02 +04008015 @Files = split(/\n/, `$Cmd 2>\"$TMP_DIR/null\"`);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008016 }
8017 my @AbsPaths = ();
8018 foreach my $File (@Files)
8019 {
8020 if(not is_abs($File)) {
8021 $File = joinPath($Path, $File);
8022 }
8023 if($Type eq "f" and not -f $File)
8024 { # skip dirs
8025 next;
8026 }
8027 push(@AbsPaths, path_format($File, $OSgroup));
8028 }
8029 if($Type eq "d") {
8030 push(@AbsPaths, $Path);
8031 }
8032 return @AbsPaths;
8033 }
8034 else
8035 {
8036 my $FindCmd = get_CmdPath("find");
8037 if(not $FindCmd) {
8038 exitStatus("Not_Found", "can't find a \"find\" command");
8039 }
8040 $Path = get_abs_path($Path);
8041 if(-d $Path and -l $Path
8042 and $Path!~/\/\Z/)
8043 { # for directories that are symlinks
8044 $Path.="/";
8045 }
8046 my $Cmd = $FindCmd." \"$Path\"";
8047 if($MaxDepth) {
8048 $Cmd .= " -maxdepth $MaxDepth";
8049 }
8050 if($Type) {
8051 $Cmd .= " -type $Type";
8052 }
8053 if($Name)
8054 { # file name
8055 if($Name=~/\]/) {
8056 $Cmd .= " -regex \"$Name\"";
8057 }
8058 else {
8059 $Cmd .= " -name \"$Name\"";
8060 }
8061 }
Andrey Ponomarenko9927e332012-10-19 10:50:48 +04008062 my $Res = `$Cmd 2>\"$TMP_DIR/null\"`;
8063 if($?) {
8064 printMsg("ERROR", "problem with \'find\' utility ($?): $!");
8065 }
8066 return split(/\n/, $Res);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008067 }
8068}
8069
8070sub unpackDump($)
8071{
8072 my $Path = $_[0];
8073 return "" if(not $Path or not -e $Path);
8074 $Path = get_abs_path($Path);
8075 $Path = path_format($Path, $OSgroup);
8076 my ($Dir, $FileName) = separate_path($Path);
8077 my $UnpackDir = $TMP_DIR."/unpack";
8078 rmtree($UnpackDir);
8079 mkpath($UnpackDir);
8080 if($FileName=~s/\Q.zip\E\Z//g)
8081 { # *.zip
8082 my $UnzipCmd = get_CmdPath("unzip");
8083 if(not $UnzipCmd) {
8084 exitStatus("Not_Found", "can't find \"unzip\" command");
8085 }
8086 chdir($UnpackDir);
Andrey Ponomarenkoa01311b2012-06-08 17:20:02 +04008087 system("$UnzipCmd \"$Path\" >contents.txt");
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008088 if($?) {
8089 exitStatus("Error", "can't extract \'$Path\'");
8090 }
8091 chdir($ORIG_DIR);
8092 my @Contents = ();
8093 foreach (split("\n", readFile("$UnpackDir/contents.txt")))
8094 {
8095 if(/inflating:\s*([^\s]+)/) {
8096 push(@Contents, $1);
8097 }
8098 }
8099 if(not @Contents) {
8100 exitStatus("Error", "can't extract \'$Path\'");
8101 }
8102 return joinPath($UnpackDir, $Contents[0]);
8103 }
8104 elsif($FileName=~s/\Q.tar.gz\E\Z//g)
8105 { # *.tar.gz
8106 if($OSgroup eq "windows")
8107 { # -xvzf option is not implemented in tar.exe (2003)
8108 # use "gzip.exe -k -d -f" + "tar.exe -xvf" instead
8109 my $TarCmd = get_CmdPath("tar");
8110 if(not $TarCmd) {
8111 exitStatus("Not_Found", "can't find \"tar\" command");
8112 }
8113 my $GzipCmd = get_CmdPath("gzip");
8114 if(not $GzipCmd) {
8115 exitStatus("Not_Found", "can't find \"gzip\" command");
8116 }
8117 chdir($UnpackDir);
Andrey Ponomarenkoa01311b2012-06-08 17:20:02 +04008118 system("$GzipCmd -k -d -f \"$Path\""); # keep input files (-k)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008119 if($?) {
8120 exitStatus("Error", "can't extract \'$Path\'");
8121 }
Andrey Ponomarenkoa01311b2012-06-08 17:20:02 +04008122 system("$TarCmd -xvf \"$Dir\\$FileName.tar\" >contents.txt");
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008123 if($?) {
8124 exitStatus("Error", "can't extract \'$Path\'");
8125 }
8126 chdir($ORIG_DIR);
8127 unlink($Dir."/".$FileName.".tar");
8128 my @Contents = split("\n", readFile("$UnpackDir/contents.txt"));
8129 if(not @Contents) {
8130 exitStatus("Error", "can't extract \'$Path\'");
8131 }
8132 return joinPath($UnpackDir, $Contents[0]);
8133 }
8134 else
8135 { # Unix
8136 my $TarCmd = get_CmdPath("tar");
8137 if(not $TarCmd) {
8138 exitStatus("Not_Found", "can't find \"tar\" command");
8139 }
8140 chdir($UnpackDir);
Andrey Ponomarenkoa01311b2012-06-08 17:20:02 +04008141 system("$TarCmd -xvzf \"$Path\" >contents.txt");
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008142 if($?) {
8143 exitStatus("Error", "can't extract \'$Path\'");
8144 }
8145 chdir($ORIG_DIR);
8146 # The content file name may be different
8147 # from the package file name
8148 my @Contents = split("\n", readFile("$UnpackDir/contents.txt"));
8149 if(not @Contents) {
8150 exitStatus("Error", "can't extract \'$Path\'");
8151 }
8152 return joinPath($UnpackDir, $Contents[0]);
8153 }
8154 }
8155}
8156
8157sub createArchive($$)
8158{
8159 my ($Path, $To) = @_;
Andrey Ponomarenko5c09ef32012-06-14 18:17:33 +04008160 if(not $To) {
8161 $To = ".";
8162 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008163 if(not $Path or not -e $Path
8164 or not -d $To) {
8165 return "";
8166 }
8167 my ($From, $Name) = separate_path($Path);
8168 if($OSgroup eq "windows")
8169 { # *.zip
8170 my $ZipCmd = get_CmdPath("zip");
8171 if(not $ZipCmd) {
8172 exitStatus("Not_Found", "can't find \"zip\"");
8173 }
8174 my $Pkg = $To."/".$Name.".zip";
8175 unlink($Pkg);
8176 chdir($To);
Andrey Ponomarenkoa01311b2012-06-08 17:20:02 +04008177 system("$ZipCmd -j \"$Name.zip\" \"$Path\" >\"$TMP_DIR/null\"");
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008178 if($?)
8179 { # cannot allocate memory (or other problems with "zip")
8180 unlink($Path);
8181 exitStatus("Error", "can't pack the ABI dump: ".$!);
8182 }
8183 chdir($ORIG_DIR);
8184 unlink($Path);
8185 return $Pkg;
8186 }
8187 else
8188 { # *.tar.gz
8189 my $TarCmd = get_CmdPath("tar");
8190 if(not $TarCmd) {
8191 exitStatus("Not_Found", "can't find \"tar\"");
8192 }
8193 my $GzipCmd = get_CmdPath("gzip");
8194 if(not $GzipCmd) {
8195 exitStatus("Not_Found", "can't find \"gzip\"");
8196 }
8197 my $Pkg = abs_path($To)."/".$Name.".tar.gz";
8198 unlink($Pkg);
8199 chdir($From);
8200 system($TarCmd, "-czf", $Pkg, $Name);
8201 if($?)
8202 { # cannot allocate memory (or other problems with "tar")
8203 unlink($Path);
8204 exitStatus("Error", "can't pack the ABI dump: ".$!);
8205 }
8206 chdir($ORIG_DIR);
8207 unlink($Path);
8208 return $To."/".$Name.".tar.gz";
8209 }
8210}
8211
Andrey Ponomarenko9927e332012-10-19 10:50:48 +04008212sub readBytes($)
8213{
8214 sysopen(FILE, $_[0], O_RDONLY);
8215 sysread(FILE, my $Header, 4);
8216 close(FILE);
8217 my @Bytes = map { sprintf('%02x', ord($_)) } split (//, $Header);
8218 return join("", @Bytes);
8219}
8220
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008221sub is_header_file($)
8222{
8223 if($_[0]=~/\.($HEADER_EXT)\Z/i) {
8224 return $_[0];
8225 }
8226 return 0;
8227}
8228
8229sub is_not_header($)
8230{
8231 if($_[0]=~/\.\w+\Z/
8232 and $_[0]!~/\.($HEADER_EXT)\Z/i) {
8233 return 1;
8234 }
8235 return 0;
8236}
8237
8238sub is_header($$$)
8239{
8240 my ($Header, $UserDefined, $LibVersion) = @_;
8241 return 0 if(-d $Header);
8242 if(-f $Header) {
8243 $Header = get_abs_path($Header);
8244 }
8245 else
8246 {
8247 if(is_abs($Header))
8248 { # incorrect absolute path
8249 return 0;
8250 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04008251 if(my $HPath = identifyHeader($Header, $LibVersion)) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008252 $Header = $HPath;
8253 }
8254 else
8255 { # can't find header
8256 return 0;
8257 }
8258 }
8259 if($Header=~/\.\w+\Z/)
8260 { # have an extension
8261 return is_header_file($Header);
8262 }
8263 else
8264 {
8265 if($UserDefined==2)
8266 { # specified on the command line
8267 if(cmd_file($Header)!~/HTML|XML/i) {
8268 return $Header;
8269 }
8270 }
8271 elsif($UserDefined)
8272 { # specified in the XML-descriptor
8273 # header file without an extension
8274 return $Header;
8275 }
8276 else
8277 {
Andrey Ponomarenko85043792012-05-14 16:48:07 +04008278 if($Header=~/\/include\//
8279 or cmd_file($Header)=~/C[\+]*\s+program/i)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008280 { # !~/HTML|XML|shared|dynamic/i
8281 return $Header;
8282 }
8283 }
8284 }
8285 return 0;
8286}
8287
Andrey Ponomarenko16934472012-03-29 15:37:04 +04008288sub addTargetHeaders($)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008289{
8290 my $LibVersion = $_[0];
8291 foreach my $RegHeader (keys(%{$Registered_Headers{$LibVersion}}))
8292 {
8293 my $RegDir = get_dirname($RegHeader);
8294 $TargetHeaders{$LibVersion}{get_filename($RegHeader)}=1;
Andrey Ponomarenko9927e332012-10-19 10:50:48 +04008295
8296 if(not $INC_PATH_AUTODETECT{$LibVersion}) {
8297 detect_recursive_includes($RegHeader, $LibVersion);
8298 }
8299
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008300 foreach my $RecInc (keys(%{$RecursiveIncludes{$LibVersion}{$RegHeader}}))
8301 {
8302 my $Dir = get_dirname($RecInc);
Andrey Ponomarenko85043792012-05-14 16:48:07 +04008303 if($Dir=~/\A\Q$RegDir\E([\/\\]|\Z)/
8304 or $RecursiveIncludes{$LibVersion}{$RegHeader}{$RecInc}!=1)
8305 { # in the same directory or included by #include "..."
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008306 $TargetHeaders{$LibVersion}{get_filename($RecInc)}=1;
8307 }
8308 }
8309 }
8310}
8311
8312sub readHeaders($)
8313{
8314 $Version = $_[0];
8315 printMsg("INFO", "checking header(s) ".$Descriptor{$Version}{"Version"}." ...");
8316 my $DumpPath = getDump();
8317 if(not $DumpPath) {
8318 exitStatus("Cannot_Compile", "can't compile header(s)");
8319 }
8320 if($Debug)
8321 { # debug mode
8322 mkpath($DEBUG_PATH{$Version});
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04008323 copy($DumpPath, $DEBUG_PATH{$Version}."/translation-unit-dump.txt");
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008324 }
8325 getInfo($DumpPath);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008326}
8327
8328sub prepareTypes($)
8329{
8330 my $LibVersion = $_[0];
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04008331 if(not checkDump($LibVersion, "2.0"))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008332 { # support for old ABI dumps
8333 # type names have been corrected in ACC 1.22 (dump 2.0 format)
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04008334 foreach my $TypeId (keys(%{$TypeInfo{$LibVersion}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008335 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04008336 my $TName = $TypeInfo{$LibVersion}{$TypeId}{"Name"};
8337 if($TName=~/\A(\w+)::(\w+)/) {
8338 my ($P1, $P2) = ($1, $2);
8339 if($P1 eq $P2) {
8340 $TName=~s/\A$P1:\:$P1(\W)/$P1$1/;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008341 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04008342 else {
8343 $TName=~s/\A(\w+:\:)$P2:\:$P2(\W)/$1$P2$2/;
8344 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008345 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04008346 $TypeInfo{$LibVersion}{$TypeId}{"Name"} = $TName;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008347 }
8348 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04008349 if(not checkDump($LibVersion, "2.5"))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008350 { # support for old ABI dumps
8351 # V < 2.5: array size == "number of elements"
8352 # V >= 2.5: array size in bytes
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04008353 foreach my $TypeId (sort {int($a)<=>int($b)} keys(%{$TypeInfo{$LibVersion}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008354 {
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +04008355 my %Type = get_PureType($TypeId, $TypeInfo{$LibVersion});
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04008356 if($Type{"Type"} eq "Array")
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008357 {
Andrey Ponomarenko01117f12012-06-26 12:23:02 +04008358 if(my $Size = $Type{"Size"})
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04008359 { # array[N]
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +04008360 my %Base = get_OneStep_BaseType($Type{"Tid"}, $TypeInfo{$LibVersion});
Andrey Ponomarenko01117f12012-06-26 12:23:02 +04008361 $Size *= $Base{"Size"};
8362 $TypeInfo{$LibVersion}{$TypeId}{"Size"} = "$Size";
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04008363 }
8364 else
8365 { # array[] is a pointer
8366 $TypeInfo{$LibVersion}{$TypeId}{"Size"} = $WORD_SIZE{$LibVersion};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008367 }
8368 }
8369 }
8370 }
8371 my $V2 = ($LibVersion==1)?2:1;
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04008372 if(not checkDump($LibVersion, "2.7"))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008373 { # support for old ABI dumps
8374 # size of "method ptr" corrected in 2.7
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04008375 foreach my $TypeId (sort {int($a)<=>int($b)} keys(%{$TypeInfo{$LibVersion}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008376 {
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +04008377 my %PureType = get_PureType($TypeId, $TypeInfo{$LibVersion});
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04008378 if($PureType{"Type"} eq "MethodPtr")
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008379 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04008380 my %Type = get_Type($TypeId, $LibVersion);
8381 my $TypeId_2 = getTypeIdByName($PureType{"Name"}, $V2);
8382 my %Type2 = get_Type($TypeId_2, $V2);
8383 if($Type{"Size"} ne $Type2{"Size"}) {
8384 $TypeInfo{$LibVersion}{$TypeId}{"Size"} = $Type2{"Size"};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008385 }
8386 }
8387 }
8388 }
8389}
8390
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04008391sub prepareSymbols($)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008392{
8393 my $LibVersion = $_[0];
Andrey Ponomarenko16934472012-03-29 15:37:04 +04008394
8395 if(not keys(%{$SymbolInfo{$LibVersion}}))
8396 { # check if input is valid
8397 if(not $ExtendedCheck and not $CheckObjectsOnly)
8398 {
8399 if($CheckHeadersOnly) {
8400 exitStatus("Empty_Set", "the set of public symbols is empty (".$Descriptor{$LibVersion}{"Version"}.")");
8401 }
8402 else {
8403 exitStatus("Empty_Intersection", "the sets of public symbols in headers and libraries have empty intersection (".$Descriptor{$LibVersion}{"Version"}.")");
8404 }
8405 }
8406 }
8407
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008408 my $Remangle = 0;
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04008409 if(not checkDump(1, "2.10")
8410 or not checkDump(2, "2.10"))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008411 { # different formats
8412 $Remangle = 1;
8413 }
8414 if($CheckHeadersOnly)
8415 { # different languages
8416 if($UserLang)
8417 { # --lang=LANG for both versions
8418 if(($UsedDump{1}{"V"} and $UserLang ne $UsedDump{1}{"L"})
8419 or ($UsedDump{2}{"V"} and $UserLang ne $UsedDump{2}{"L"}))
8420 {
8421 if($UserLang eq "C++")
8422 { # remangle symbols
8423 $Remangle = 1;
8424 }
8425 elsif($UserLang eq "C")
8426 { # remove mangling
8427 $Remangle = -1;
8428 }
8429 }
8430 }
8431 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04008432
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04008433 foreach my $InfoId (sort {int($b)<=>int($a)} keys(%{$SymbolInfo{$LibVersion}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008434 { # reverse order: D0, D1, D2, D0 (artificial, GCC < 4.5), C1, C2
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04008435 if(not checkDump($LibVersion, "2.13"))
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04008436 { # support for old ABI dumps
8437 if(defined $SymbolInfo{$LibVersion}{$InfoId}{"Param"})
8438 {
8439 foreach my $P (keys(%{$SymbolInfo{$LibVersion}{$InfoId}{"Param"}}))
8440 {
8441 my $TypeId = $SymbolInfo{$LibVersion}{$InfoId}{"Param"}{$P}{"type"};
8442 my $DVal = $SymbolInfo{$LibVersion}{$InfoId}{"Param"}{$P}{"default"};
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04008443 my $TName = $TypeInfo{$LibVersion}{$TypeId}{"Name"};
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04008444 if(defined $DVal and $DVal ne "")
8445 {
8446 if($TName eq "char") {
8447 $SymbolInfo{$LibVersion}{$InfoId}{"Param"}{$P}{"default"} = chr($DVal);
8448 }
8449 elsif($TName eq "bool") {
8450 $SymbolInfo{$LibVersion}{$InfoId}{"Param"}{$P}{"default"} = $DVal?"true":"false";
8451 }
8452 }
8453 }
8454 }
8455 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04008456 if($SymbolInfo{$LibVersion}{$InfoId}{"Destructor"})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008457 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04008458 if(defined $SymbolInfo{$LibVersion}{$InfoId}{"Param"}
8459 and keys(%{$SymbolInfo{$LibVersion}{$InfoId}{"Param"}})
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04008460 and $SymbolInfo{$LibVersion}{$InfoId}{"Param"}{0}{"name"})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008461 { # support for old GCC < 4.5: skip artificial ~dtor(int __in_chrg)
8462 # + support for old ABI dumps
8463 next;
8464 }
8465 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04008466 my $MnglName = $SymbolInfo{$LibVersion}{$InfoId}{"MnglName"};
Andrey Ponomarenko85043792012-05-14 16:48:07 +04008467 my $ShortName = $SymbolInfo{$LibVersion}{$InfoId}{"ShortName"};
Andrey Ponomarenko16934472012-03-29 15:37:04 +04008468 my $ClassID = $SymbolInfo{$LibVersion}{$InfoId}{"Class"};
Andrey Ponomarenko85043792012-05-14 16:48:07 +04008469 my $Return = $SymbolInfo{$LibVersion}{$InfoId}{"Return"};
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04008470
Andrey Ponomarenko16934472012-03-29 15:37:04 +04008471 my $SRemangle = 0;
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04008472 if(not checkDump(1, "2.12")
8473 or not checkDump(2, "2.12"))
Andrey Ponomarenko16934472012-03-29 15:37:04 +04008474 { # support for old ABI dumps
Andrey Ponomarenko85043792012-05-14 16:48:07 +04008475 if($ShortName eq "operator>>")
8476 {
8477 if(not $SymbolInfo{$LibVersion}{$InfoId}{"Class"})
8478 { # corrected mangling of operator>>
8479 $SRemangle = 1;
8480 }
Andrey Ponomarenko16934472012-03-29 15:37:04 +04008481 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +04008482 if($SymbolInfo{$LibVersion}{$InfoId}{"Data"})
8483 {
8484 if(not $SymbolInfo{$LibVersion}{$InfoId}{"Class"}
8485 and isConstType($Return, $LibVersion) and $MnglName!~/L\d+$ShortName/)
8486 { # corrected mangling of const global data
8487 # some global data is not mangled in the TU dump: qt_sine_table (Qt 4.8)
8488 # and incorrectly mangled by old ACC versions
8489 $SRemangle = 1;
8490 }
Andrey Ponomarenko16934472012-03-29 15:37:04 +04008491 }
8492 }
Andrey Ponomarenko5c09ef32012-06-14 18:17:33 +04008493 if(not $CheckHeadersOnly)
8494 { # support for old ABI dumps
8495 if(not checkDump(1, "2.17")
8496 or not checkDump(2, "2.17"))
8497 {
8498 if($SymbolInfo{$LibVersion}{$InfoId}{"Data"})
8499 {
8500 if(not $SymbolInfo{$LibVersion}{$InfoId}{"Class"})
8501 {
8502 if(link_symbol($ShortName, $LibVersion, "-Deps"))
8503 {
8504 $MnglName = $ShortName;
8505 $SymbolInfo{$LibVersion}{$InfoId}{"MnglName"} = $MnglName;
8506 }
8507 }
8508 }
8509 }
8510 }
Andrey Ponomarenko16934472012-03-29 15:37:04 +04008511 if($Remangle==1 or $SRemangle==1)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008512 { # support for old ABI dumps: some symbols are not mangled in old dumps
8513 # mangle both sets of symbols (old and new)
8514 # NOTE: remangling all symbols by the same mangler
8515 if($MnglName=~/\A_ZN(V|)K/)
8516 { # mangling may be incorrect on old ABI dumps
8517 # because of absent "Const" attribute
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04008518 $SymbolInfo{$LibVersion}{$InfoId}{"Const"} = 1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008519 }
8520 if($MnglName=~/\A_ZN(K|)V/)
8521 { # mangling may be incorrect on old ABI dumps
8522 # because of absent "Volatile" attribute
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04008523 $SymbolInfo{$LibVersion}{$InfoId}{"Volatile"} = 1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008524 }
Andrey Ponomarenko16934472012-03-29 15:37:04 +04008525 if(($ClassID and $MnglName!~/\A(_Z|\?)/)
8526 or (not $ClassID and $CheckHeadersOnly)
8527 or (not $ClassID and not link_symbol($MnglName, $LibVersion, "-Deps")))
8528 { # support for old ABI dumps, GCC >= 4.0
8529 # remangling all manually mangled symbols
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04008530 if($MnglName = mangle_symbol($InfoId, $LibVersion, "GCC"))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008531 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04008532 $SymbolInfo{$LibVersion}{$InfoId}{"MnglName"} = $MnglName;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008533 $MangledNames{$LibVersion}{$MnglName} = 1;
8534 }
8535 }
8536 }
8537 elsif($Remangle==-1)
8538 { # remove mangling
8539 $MnglName = "";
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04008540 $SymbolInfo{$LibVersion}{$InfoId}{"MnglName"} = "";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008541 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008542 if(not $MnglName) {
8543 next;
8544 }
8545 if(not $CompleteSignature{$LibVersion}{$MnglName}{"MnglName"})
8546 { # NOTE: global data may enter here twice
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04008547 %{$CompleteSignature{$LibVersion}{$MnglName}} = %{$SymbolInfo{$LibVersion}{$InfoId}};
8548
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008549 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04008550 if(not checkDump($LibVersion, "2.6"))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008551 { # support for old dumps
8552 # add "Volatile" attribute
8553 if($MnglName=~/_Z(K|)V/) {
8554 $CompleteSignature{$LibVersion}{$MnglName}{"Volatile"}=1;
8555 }
8556 }
8557 # symbol and its symlink have same signatures
8558 if($SymVer{$LibVersion}{$MnglName}) {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04008559 %{$CompleteSignature{$LibVersion}{$SymVer{$LibVersion}{$MnglName}}} = %{$SymbolInfo{$LibVersion}{$InfoId}};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008560 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +04008561
8562 # clean memory
Andrey Ponomarenko16934472012-03-29 15:37:04 +04008563 delete($SymbolInfo{$LibVersion}{$InfoId});
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008564 }
8565 if($COMMON_LANGUAGE{$LibVersion} eq "C++" or $OSgroup eq "windows") {
8566 translateSymbols(keys(%{$CompleteSignature{$LibVersion}}), $LibVersion);
8567 }
8568 if($ExtendedCheck)
8569 { # --ext option
8570 addExtension($LibVersion);
8571 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +04008572
8573 # clean memory
8574 delete($SymbolInfo{$LibVersion});
8575
8576 foreach my $Symbol (keys(%{$CompleteSignature{$LibVersion}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008577 { # detect allocable classes with public exported constructors
8578 # or classes with auto-generated or inline-only constructors
Andrey Ponomarenko9927e332012-10-19 10:50:48 +04008579 # and other temp info
Andrey Ponomarenko85043792012-05-14 16:48:07 +04008580 if(my $ClassId = $CompleteSignature{$LibVersion}{$Symbol}{"Class"})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008581 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04008582 my $ClassName = $TypeInfo{$LibVersion}{$ClassId}{"Name"};
Andrey Ponomarenko85043792012-05-14 16:48:07 +04008583 if($CompleteSignature{$LibVersion}{$Symbol}{"Constructor"}
8584 and not $CompleteSignature{$LibVersion}{$Symbol}{"InLine"})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008585 { # Class() { ... } will not be exported
Andrey Ponomarenko85043792012-05-14 16:48:07 +04008586 if(not $CompleteSignature{$LibVersion}{$Symbol}{"Private"})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008587 {
Andrey Ponomarenko85043792012-05-14 16:48:07 +04008588 if($CheckHeadersOnly or link_symbol($Symbol, $LibVersion, "-Deps")) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008589 $AllocableClass{$LibVersion}{$ClassName} = 1;
8590 }
8591 }
8592 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +04008593 if(not $CompleteSignature{$LibVersion}{$Symbol}{"Private"})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008594 { # all imported class methods
Andrey Ponomarenko85043792012-05-14 16:48:07 +04008595 if(symbolFilter($Symbol, $LibVersion, "Affected", "Binary"))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008596 {
Andrey Ponomarenko85043792012-05-14 16:48:07 +04008597 if($CheckHeadersOnly)
8598 {
8599 if(not $CompleteSignature{$LibVersion}{$Symbol}{"InLine"}
8600 or $CompleteSignature{$LibVersion}{$Symbol}{"Virt"})
8601 { # all symbols except non-virtual inline
8602 $ClassMethods{"Binary"}{$LibVersion}{$ClassName}{$Symbol} = 1;
8603 }
8604 }
8605 else {
8606 $ClassMethods{"Binary"}{$LibVersion}{$ClassName}{$Symbol} = 1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008607 }
8608 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04008609 if(symbolFilter($Symbol, $LibVersion, "Affected", "Source")) {
Andrey Ponomarenko85043792012-05-14 16:48:07 +04008610 $ClassMethods{"Source"}{$LibVersion}{$ClassName}{$Symbol} = 1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008611 }
8612 }
Andrey Ponomarenko16934472012-03-29 15:37:04 +04008613 $ClassNames{$LibVersion}{$ClassName} = 1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008614 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +04008615 if(my $RetId = $CompleteSignature{$LibVersion}{$Symbol}{"Return"})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008616 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04008617 my %Base = get_BaseType($RetId, $LibVersion);
Andrey Ponomarenko85043792012-05-14 16:48:07 +04008618 if(defined $Base{"Type"}
8619 and $Base{"Type"}=~/Struct|Class/)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008620 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04008621 my $Name = $TypeInfo{$LibVersion}{$Base{"Tid"}}{"Name"};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008622 if($Name=~/<([^<>\s]+)>/)
8623 {
8624 if(my $Tid = getTypeIdByName($1, $LibVersion)) {
8625 $ReturnedClass{$LibVersion}{$Tid} = 1;
8626 }
8627 }
8628 else {
8629 $ReturnedClass{$LibVersion}{$Base{"Tid"}} = 1;
8630 }
8631 }
8632 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +04008633 foreach my $Num (keys(%{$CompleteSignature{$LibVersion}{$Symbol}{"Param"}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008634 {
Andrey Ponomarenko85043792012-05-14 16:48:07 +04008635 my $PId = $CompleteSignature{$LibVersion}{$Symbol}{"Param"}{$Num}{"type"};
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04008636 if(get_PLevel($PId, $LibVersion)>=1)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008637 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04008638 if(my %Base = get_BaseType($PId, $LibVersion))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008639 {
Andrey Ponomarenko16934472012-03-29 15:37:04 +04008640 if($Base{"Type"}=~/Struct|Class/)
8641 {
Andrey Ponomarenko85043792012-05-14 16:48:07 +04008642 $ParamClass{$LibVersion}{$Base{"Tid"}}{$Symbol} = 1;
Andrey Ponomarenko16934472012-03-29 15:37:04 +04008643 foreach my $SubId (get_sub_classes($Base{"Tid"}, $LibVersion, 1))
8644 { # mark all derived classes
Andrey Ponomarenko85043792012-05-14 16:48:07 +04008645 $ParamClass{$LibVersion}{$SubId}{$Symbol} = 1;
Andrey Ponomarenko16934472012-03-29 15:37:04 +04008646 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008647 }
8648 }
8649 }
8650 }
Andrey Ponomarenko9927e332012-10-19 10:50:48 +04008651
8652 # mapping {short name => symbols}
8653 $Func_ShortName{$LibVersion}{$CompleteSignature{$LibVersion}{$Symbol}{"ShortName"}}{$Symbol} = 1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008654 }
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04008655 foreach my $MnglName (keys(%VTableClass))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008656 { # reconstruct header name for v-tables
Andrey Ponomarenko9927e332012-10-19 10:50:48 +04008657 if(index($MnglName, "_ZTV")==0)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008658 {
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04008659 if(my $ClassName = $VTableClass{$MnglName})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008660 {
8661 if(my $ClassId = $TName_Tid{$LibVersion}{$ClassName}) {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04008662 $CompleteSignature{$LibVersion}{$MnglName}{"Header"} = $TypeInfo{$LibVersion}{$ClassId}{"Header"};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008663 }
8664 }
8665 }
8666 }
Andrey Ponomarenko16934472012-03-29 15:37:04 +04008667
8668 # types
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04008669 foreach my $TypeId (keys(%{$TypeInfo{$LibVersion}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008670 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04008671 if(my $TName = $TypeInfo{$LibVersion}{$TypeId}{"Name"})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008672 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04008673 if(defined $TypeInfo{$LibVersion}{$TypeId}{"VTable"}) {
8674 $ClassNames{$LibVersion}{$TName} = 1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008675 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04008676 if(defined $TypeInfo{$LibVersion}{$TypeId}{"Base"})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008677 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04008678 $ClassNames{$LibVersion}{$TName} = 1;
8679 foreach my $Bid (keys(%{$TypeInfo{$LibVersion}{$TypeId}{"Base"}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008680 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04008681 if(my $BName = $TypeInfo{$LibVersion}{$Bid}{"Name"}) {
8682 $ClassNames{$LibVersion}{$BName} = 1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008683 }
8684 }
8685 }
8686 }
8687 }
8688}
8689
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04008690sub register_TypeUsage($$)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008691{
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04008692 my ($TypeId, $LibVersion) = @_;
8693 if(not $TypeId) {
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04008694 return 0;
8695 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04008696 if($UsedType{$LibVersion}{$TypeId})
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04008697 { # already registered
8698 return 1;
8699 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04008700 my %TInfo = get_Type($TypeId, $LibVersion);
Andrey Ponomarenko85043792012-05-14 16:48:07 +04008701 if($TInfo{"Type"})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008702 {
Andrey Ponomarenko85043792012-05-14 16:48:07 +04008703 if($TInfo{"Type"}=~/\A(Struct|Union|Class|FuncPtr|MethodPtr|FieldPtr|Enum)\Z/)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008704 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04008705 $UsedType{$LibVersion}{$TypeId} = 1;
Andrey Ponomarenko85043792012-05-14 16:48:07 +04008706 if($TInfo{"Type"}=~/\A(Struct|Class)\Z/)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008707 {
Andrey Ponomarenko85043792012-05-14 16:48:07 +04008708 foreach my $BaseId (keys(%{$TInfo{"Base"}}))
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04008709 { # register base classes
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04008710 register_TypeUsage($BaseId, $LibVersion);
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04008711 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +04008712 foreach my $TPos (keys(%{$TInfo{"TParam"}}))
8713 {
8714 my $TPName = $TInfo{"TParam"}{$TPos}{"name"};
8715 if(my $TTid = $TName_Tid{$LibVersion}{$TPName}) {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04008716 register_TypeUsage($TTid, $LibVersion);
Andrey Ponomarenko85043792012-05-14 16:48:07 +04008717 }
8718 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008719 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +04008720 foreach my $Memb_Pos (keys(%{$TInfo{"Memb"}}))
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04008721 {
Andrey Ponomarenko85043792012-05-14 16:48:07 +04008722 if(my $MTid = $TInfo{"Memb"}{$Memb_Pos}{"type"}) {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04008723 register_TypeUsage($MTid, $LibVersion);
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04008724 }
8725 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +04008726 if($TInfo{"Type"} eq "FuncPtr"
8727 or $TInfo{"Type"} eq "MethodPtr")
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04008728 {
Andrey Ponomarenko85043792012-05-14 16:48:07 +04008729 if(my $RTid = $TInfo{"Return"}) {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04008730 register_TypeUsage($RTid, $LibVersion);
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04008731 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +04008732 foreach my $Memb_Pos (keys(%{$TInfo{"Param"}}))
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04008733 {
Andrey Ponomarenko85043792012-05-14 16:48:07 +04008734 if(my $MTid = $TInfo{"Param"}{$Memb_Pos}{"type"}) {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04008735 register_TypeUsage($MTid, $LibVersion);
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04008736 }
8737 }
8738 }
8739 return 1;
8740 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +04008741 elsif($TInfo{"Type"}=~/\A(Const|ConstVolatile|Volatile|Pointer|Ref|Restrict|Array|Typedef)\Z/)
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04008742 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04008743 $UsedType{$LibVersion}{$TypeId} = 1;
8744 register_TypeUsage($TInfo{"BaseType"}{"Tid"}, $LibVersion);
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04008745 return 1;
8746 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04008747 elsif($TInfo{"Type"} eq "Intrinsic")
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04008748 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04008749 $UsedType{$LibVersion}{$TypeId} = 1;
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04008750 return 1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008751 }
8752 }
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04008753 return 0;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008754}
8755
Andrey Ponomarenko85043792012-05-14 16:48:07 +04008756sub selectSymbol($$$$)
Andrey Ponomarenko35c44fd2012-06-18 17:50:25 +04008757{ # select symbol to check or to dump
Andrey Ponomarenko85043792012-05-14 16:48:07 +04008758 my ($Symbol, $SInfo, $Level, $LibVersion) = @_;
8759
Andrey Ponomarenko35c44fd2012-06-18 17:50:25 +04008760 if($Level eq "Dump")
8761 {
8762 if($SInfo->{"Virt"} or $SInfo->{"PureVirt"})
8763 { # TODO: check if this symbol is from
8764 # base classes of other target symbols
8765 return 1;
8766 }
8767 }
8768
Andrey Ponomarenko85043792012-05-14 16:48:07 +04008769 if(not $STDCXX_TESTING and $Symbol=~/\A(_ZS|_ZNS|_ZNKS)/)
8770 { # stdc++ interfaces
8771 return 0;
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04008772 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +04008773
8774 my $Target = 0;
8775 if(my $Header = $SInfo->{"Header"}) {
8776 $Target = (is_target_header($Header, 1) or is_target_header($Header, 2));
8777 }
8778 if($CheckHeadersOnly)
8779 {
8780 if($Target)
8781 {
8782 if($Level eq "Dump")
8783 { # dumped
8784 if($BinaryOnly)
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04008785 {
Andrey Ponomarenko85043792012-05-14 16:48:07 +04008786 if(not $SInfo->{"InLine"} or $SInfo->{"Data"}) {
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04008787 return 1;
8788 }
8789 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +04008790 else {
8791 return 1;
8792 }
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04008793 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +04008794 elsif($Level eq "Source")
8795 { # checked
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04008796 return 1;
8797 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +04008798 elsif($Level eq "Binary")
8799 { # checked
8800 if(not $SInfo->{"InLine"} or $SInfo->{"Data"}
8801 or $SInfo->{"Virt"} or $SInfo->{"PureVirt"}) {
8802 return 1;
8803 }
8804 }
8805 }
8806 }
8807 else
8808 { # library is available
8809 if(link_symbol($Symbol, $LibVersion, "-Deps"))
8810 { # exported symbols
8811 return 1;
8812 }
8813 if($Level eq "Dump")
8814 { # dumped
Andrey Ponomarenko35c44fd2012-06-18 17:50:25 +04008815 if($BinaryOnly)
8816 {
8817 if($SInfo->{"Data"})
8818 {
8819 if($Target) {
8820 return 1;
8821 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +04008822 }
8823 }
Andrey Ponomarenko35c44fd2012-06-18 17:50:25 +04008824 else
8825 { # SrcBin
Andrey Ponomarenko85043792012-05-14 16:48:07 +04008826 if($Target) {
8827 return 1;
8828 }
8829 }
8830 }
8831 elsif($Level eq "Source")
8832 { # checked
Andrey Ponomarenko01117f12012-06-26 12:23:02 +04008833 if($SInfo->{"PureVirt"} or $SInfo->{"Data"} or $SInfo->{"InLine"}
8834 or isInLineInst($Symbol, $SInfo, $LibVersion))
Andrey Ponomarenko35c44fd2012-06-18 17:50:25 +04008835 { # skip LOCAL symbols
8836 if($Target) {
8837 return 1;
8838 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +04008839 }
8840 }
8841 elsif($Level eq "Binary")
8842 { # checked
8843 if($SInfo->{"PureVirt"} or $SInfo->{"Data"})
8844 {
8845 if($Target) {
8846 return 1;
8847 }
8848 }
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04008849 }
8850 }
8851 return 0;
8852}
8853
Andrey Ponomarenko85043792012-05-14 16:48:07 +04008854sub cleanDump($)
8855{ # clean data
Andrey Ponomarenko16934472012-03-29 15:37:04 +04008856 my $LibVersion = $_[0];
8857 foreach my $InfoId (keys(%{$SymbolInfo{$LibVersion}}))
8858 {
8859 my $MnglName = $SymbolInfo{$LibVersion}{$InfoId}{"MnglName"};
8860 if(not $MnglName) {
8861 delete($SymbolInfo{$LibVersion}{$InfoId});
8862 next;
8863 }
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04008864 my $ShortName = $SymbolInfo{$LibVersion}{$InfoId}{"ShortName"};
Andrey Ponomarenko85043792012-05-14 16:48:07 +04008865 if(not $ShortName) {
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04008866 delete($SymbolInfo{$LibVersion}{$InfoId});
8867 next;
Andrey Ponomarenko16934472012-03-29 15:37:04 +04008868 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +04008869 if($MnglName eq $ShortName)
8870 { # remove duplicate data
8871 delete($SymbolInfo{$LibVersion}{$InfoId}{"MnglName"});
Andrey Ponomarenko16934472012-03-29 15:37:04 +04008872 }
8873 if(not keys(%{$SymbolInfo{$LibVersion}{$InfoId}{"Param"}})) {
8874 delete($SymbolInfo{$LibVersion}{$InfoId}{"Param"});
8875 }
Andrey Ponomarenko01117f12012-06-26 12:23:02 +04008876 if(not keys(%{$SymbolInfo{$LibVersion}{$InfoId}{"TParam"}})) {
8877 delete($SymbolInfo{$LibVersion}{$InfoId}{"TParam"});
8878 }
Andrey Ponomarenko16934472012-03-29 15:37:04 +04008879 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04008880 foreach my $Tid (keys(%{$TypeInfo{$LibVersion}}))
Andrey Ponomarenko85043792012-05-14 16:48:07 +04008881 {
Andrey Ponomarenko01117f12012-06-26 12:23:02 +04008882 delete($TypeInfo{$LibVersion}{$Tid}{"Tid"});
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04008883 foreach my $Attr ("Header", "Line", "Size", "NameSpace")
Andrey Ponomarenko16934472012-03-29 15:37:04 +04008884 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04008885 if(not $TypeInfo{$LibVersion}{$Tid}{$Attr}) {
8886 delete($TypeInfo{$LibVersion}{$Tid}{$Attr});
8887 }
8888 }
Andrey Ponomarenko01117f12012-06-26 12:23:02 +04008889 if(not keys(%{$TypeInfo{$LibVersion}{$Tid}{"TParam"}})) {
8890 delete($TypeInfo{$LibVersion}{$Tid}{"TParam"});
8891 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04008892 }
8893}
8894
8895sub selectType($$)
8896{
8897 my ($Tid, $LibVersion) = @_;
Andrey Ponomarenko9927e332012-10-19 10:50:48 +04008898
8899 if(my $Dupl = $TypeTypedef{$LibVersion}{$Tid})
8900 {
8901 if(defined $TypeInfo{$LibVersion}{$Dupl})
8902 {
8903 if($TypeInfo{$LibVersion}{$Dupl}{"Name"} eq $TypeInfo{$LibVersion}{$Tid}{"Name"})
8904 { # duplicate
8905 return 0;
8906 }
8907 }
8908 }
8909
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04008910 if(my $THeader = $TypeInfo{$LibVersion}{$Tid}{"Header"})
8911 {
8912 if(not isBuiltIn($THeader))
8913 {
8914 if($TypeInfo{$LibVersion}{$Tid}{"Type"}=~/Class|Struct|Union|Enum|Typedef/)
Andrey Ponomarenko16934472012-03-29 15:37:04 +04008915 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04008916 if(not isAnon($TypeInfo{$LibVersion}{$Tid}{"Name"}))
8917 {
8918 if(is_target_header($THeader, $LibVersion))
8919 { # from target headers
8920 if(not selfTypedef($Tid, $LibVersion)) {
8921 return 1;
8922 }
8923 }
Andrey Ponomarenko16934472012-03-29 15:37:04 +04008924 }
8925 }
8926 }
8927 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04008928 return 0;
Andrey Ponomarenko16934472012-03-29 15:37:04 +04008929}
8930
Andrey Ponomarenko85043792012-05-14 16:48:07 +04008931sub removeUnused($$)
8932{ # remove unused data types from the ABI dump
8933 my ($LibVersion, $Kind) = @_;
8934 foreach my $InfoId (keys(%{$SymbolInfo{$LibVersion}}))
8935 {
8936 my %FuncInfo = %{$SymbolInfo{$LibVersion}{$InfoId}};
8937 if(my $RTid = $FuncInfo{"Return"}) {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04008938 register_TypeUsage($RTid, $LibVersion);
Andrey Ponomarenko85043792012-05-14 16:48:07 +04008939 }
8940 if(my $FCid = $FuncInfo{"Class"})
8941 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04008942 register_TypeUsage($FCid, $LibVersion);
8943 if(my $ThisId = getTypeIdByName($TypeInfo{$LibVersion}{$FCid}{"Name"}."*const", $LibVersion))
Andrey Ponomarenko85043792012-05-14 16:48:07 +04008944 { # register "this" pointer
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04008945 $UsedType{$LibVersion}{$ThisId} = 1;
8946 if(my %ThisType = get_Type($ThisId, $LibVersion)) {
8947 register_TypeUsage($ThisType{"BaseType"}{"Tid"}, $LibVersion);
Andrey Ponomarenko85043792012-05-14 16:48:07 +04008948 }
8949 }
8950 }
8951 foreach my $PPos (keys(%{$FuncInfo{"Param"}}))
8952 {
8953 if(my $PTid = $FuncInfo{"Param"}{$PPos}{"type"}) {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04008954 register_TypeUsage($PTid, $LibVersion);
Andrey Ponomarenko85043792012-05-14 16:48:07 +04008955 }
8956 }
8957 foreach my $TPos (keys(%{$FuncInfo{"TParam"}}))
8958 {
8959 my $TPName = $FuncInfo{"TParam"}{$TPos}{"name"};
8960 if(my $TTid = $TName_Tid{$LibVersion}{$TPName}) {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04008961 register_TypeUsage($TTid, $LibVersion);
Andrey Ponomarenko85043792012-05-14 16:48:07 +04008962 }
8963 }
8964 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04008965 foreach my $Tid (keys(%{$TypeInfo{$LibVersion}}))
8966 {
8967 if($UsedType{$LibVersion}{$Tid})
8968 { # All & Derived
8969 next;
8970 }
8971
8972 if($Kind eq "Derived")
Andrey Ponomarenko85043792012-05-14 16:48:07 +04008973 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04008974 if(selectType($Tid, $LibVersion)) {
8975 register_TypeUsage($Tid, $LibVersion);
Andrey Ponomarenko85043792012-05-14 16:48:07 +04008976 }
8977 }
8978 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04008979 foreach my $Tid (keys(%{$TypeInfo{$LibVersion}}))
8980 { # remove unused types
8981 if($UsedType{$LibVersion}{$Tid})
8982 { # All & Derived
8983 next;
8984 }
8985 # remove type
8986 delete($TypeInfo{$LibVersion}{$Tid});
8987 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +04008988
8989 # clean memory
8990 %UsedType = ();
8991}
8992
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04008993sub selfTypedef($$)
Andrey Ponomarenko85043792012-05-14 16:48:07 +04008994{
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04008995 my ($TypeId, $LibVersion) = @_;
8996 my %Type = get_Type($TypeId, $LibVersion);
Andrey Ponomarenko85043792012-05-14 16:48:07 +04008997 if($Type{"Type"} eq "Typedef")
8998 {
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +04008999 my %Base = get_OneStep_BaseType($TypeId, $TypeInfo{$LibVersion});
Andrey Ponomarenko85043792012-05-14 16:48:07 +04009000 if($Base{"Type"}=~/Class|Struct/)
9001 {
9002 if($Type{"Name"} eq $Base{"Name"}) {
9003 return 1;
9004 }
9005 elsif($Type{"Name"}=~/::(\w+)\Z/)
9006 {
9007 if($Type{"Name"} eq $Base{"Name"}."::".$1)
9008 { # QPointer<QWidget>::QPointer
9009 return 1;
9010 }
9011 }
9012 }
9013 }
9014 return 0;
9015}
9016
Andrey Ponomarenko16934472012-03-29 15:37:04 +04009017sub addExtension($)
9018{
9019 my $LibVersion = $_[0];
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04009020 foreach my $Tid (keys(%{$TypeInfo{$LibVersion}}))
Andrey Ponomarenko16934472012-03-29 15:37:04 +04009021 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04009022 if(selectType($Tid, $LibVersion))
Andrey Ponomarenko16934472012-03-29 15:37:04 +04009023 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04009024 my $Symbol = "external_func_".$TypeInfo{$LibVersion}{$Tid}{"Name"};
9025
9026 %{$CompleteSignature{$LibVersion}{$Symbol}} = (
9027 "Header" => "extended.h",
9028 "ShortName" => $Symbol,
9029 "MnglName" => $Symbol,
9030 "Param" => { 0 => { "type"=>$Tid, "name"=>"p1" } }
9031 );
9032
9033 $ExtendedSymbols{$Symbol}=1;
9034 $CheckedSymbols{"Binary"}{$Symbol}=1;
9035 $CheckedSymbols{"Source"}{$Symbol}=1;
Andrey Ponomarenko16934472012-03-29 15:37:04 +04009036 }
9037 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04009038 $ExtendedSymbols{"external_func_0"}=1;
9039 $CheckedSymbols{"Binary"}{"external_func_0"}=1;
9040 $CheckedSymbols{"Source"}{"external_func_0"}=1;
Andrey Ponomarenko16934472012-03-29 15:37:04 +04009041}
9042
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009043sub findMethod($$$)
9044{
9045 my ($VirtFunc, $ClassId, $LibVersion) = @_;
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04009046 foreach my $BaseClass_Id (keys(%{$TypeInfo{$LibVersion}{$ClassId}{"Base"}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009047 {
9048 if(my $VirtMethodInClass = findMethod_Class($VirtFunc, $BaseClass_Id, $LibVersion)) {
9049 return $VirtMethodInClass;
9050 }
9051 elsif(my $VirtMethodInBaseClasses = findMethod($VirtFunc, $BaseClass_Id, $LibVersion)) {
9052 return $VirtMethodInBaseClasses;
9053 }
9054 }
9055 return "";
9056}
9057
9058sub findMethod_Class($$$)
9059{
9060 my ($VirtFunc, $ClassId, $LibVersion) = @_;
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04009061 my $ClassName = $TypeInfo{$LibVersion}{$ClassId}{"Name"};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009062 return "" if(not defined $VirtualTable{$LibVersion}{$ClassName});
9063 my $TargetSuffix = get_symbol_suffix($VirtFunc, 1);
9064 my $TargetShortName = $CompleteSignature{$LibVersion}{$VirtFunc}{"ShortName"};
9065 foreach my $Candidate (keys(%{$VirtualTable{$LibVersion}{$ClassName}}))
9066 { # search for interface with the same parameters suffix (overridden)
9067 if($TargetSuffix eq get_symbol_suffix($Candidate, 1))
9068 {
Andrey Ponomarenkoe3d6bf02012-11-14 11:49:09 +04009069 if($CompleteSignature{$LibVersion}{$VirtFunc}{"Destructor"})
9070 {
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04009071 if($CompleteSignature{$LibVersion}{$Candidate}{"Destructor"})
9072 {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009073 if(($VirtFunc=~/D0E/ and $Candidate=~/D0E/)
9074 or ($VirtFunc=~/D1E/ and $Candidate=~/D1E/)
9075 or ($VirtFunc=~/D2E/ and $Candidate=~/D2E/)) {
9076 return $Candidate;
9077 }
9078 }
9079 }
Andrey Ponomarenkoe3d6bf02012-11-14 11:49:09 +04009080 else
9081 {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009082 if($TargetShortName eq $CompleteSignature{$LibVersion}{$Candidate}{"ShortName"}) {
9083 return $Candidate;
9084 }
9085 }
9086 }
9087 }
9088 return "";
9089}
9090
Andrey Ponomarenko16934472012-03-29 15:37:04 +04009091sub registerVTable($)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009092{
Andrey Ponomarenko16934472012-03-29 15:37:04 +04009093 my $LibVersion = $_[0];
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04009094 foreach my $Symbol (keys(%{$CompleteSignature{$LibVersion}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009095 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04009096 if($CompleteSignature{$LibVersion}{$Symbol}{"Virt"}
9097 or $CompleteSignature{$LibVersion}{$Symbol}{"PureVirt"})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009098 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04009099 my $ClassName = $TypeInfo{$LibVersion}{$CompleteSignature{$LibVersion}{$Symbol}{"Class"}}{"Name"};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009100 next if(not $STDCXX_TESTING and $ClassName=~/\A(std::|__cxxabi)/);
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04009101 if($CompleteSignature{$LibVersion}{$Symbol}{"Destructor"}
9102 and $Symbol=~/D2E/)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009103 { # pure virtual D2-destructors are marked as "virt" in the dump
9104 # virtual D2-destructors are NOT marked as "virt" in the dump
9105 # both destructors are not presented in the v-table
9106 next;
9107 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04009108 my ($MnglName, $VersionSpec, $SymbolVersion) = separate_symbol($Symbol);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009109 $VirtualTable{$LibVersion}{$ClassName}{$MnglName} = 1;
9110 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009111 }
9112}
9113
9114sub registerOverriding($)
9115{
9116 my $LibVersion = $_[0];
9117 my @Classes = keys(%{$VirtualTable{$LibVersion}});
Andrey Ponomarenko85043792012-05-14 16:48:07 +04009118 @Classes = sort {int($TName_Tid{$LibVersion}{$a})<=>int($TName_Tid{$LibVersion}{$b})} @Classes;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009119 foreach my $ClassName (@Classes)
9120 {
9121 foreach my $VirtFunc (keys(%{$VirtualTable{$LibVersion}{$ClassName}}))
9122 {
Andrey Ponomarenko16934472012-03-29 15:37:04 +04009123 if($CompleteSignature{$LibVersion}{$VirtFunc}{"PureVirt"})
9124 { # pure virtuals
9125 next;
9126 }
9127 my $ClassId = $TName_Tid{$LibVersion}{$ClassName};
9128 if(my $Overridden = findMethod($VirtFunc, $ClassId, $LibVersion))
Andrey Ponomarenko85043792012-05-14 16:48:07 +04009129 {
9130 if($CompleteSignature{$LibVersion}{$Overridden}{"Virt"}
9131 or $CompleteSignature{$LibVersion}{$Overridden}{"PureVirt"})
9132 { # both overridden virtual methods
9133 # and implemented pure virtual methods
9134 $CompleteSignature{$LibVersion}{$VirtFunc}{"Override"} = $Overridden;
9135 $OverriddenMethods{$LibVersion}{$Overridden}{$VirtFunc} = 1;
9136 delete($VirtualTable{$LibVersion}{$ClassName}{$VirtFunc}); # remove from v-table model
9137 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009138 }
9139 }
9140 if(not keys(%{$VirtualTable{$LibVersion}{$ClassName}})) {
9141 delete($VirtualTable{$LibVersion}{$ClassName});
9142 }
9143 }
9144}
9145
9146sub setVirtFuncPositions($)
9147{
9148 my $LibVersion = $_[0];
9149 foreach my $ClassName (keys(%{$VirtualTable{$LibVersion}}))
9150 {
9151 my ($Num, $RelPos, $AbsNum) = (1, 0, 1);
9152 foreach my $VirtFunc (sort {int($CompleteSignature{$LibVersion}{$a}{"Line"}) <=> int($CompleteSignature{$LibVersion}{$b}{"Line"})}
9153 sort keys(%{$VirtualTable{$LibVersion}{$ClassName}}))
9154 {
Andrey Ponomarenko16934472012-03-29 15:37:04 +04009155 $VirtualTable{$LibVersion}{$ClassName}{$VirtFunc}=$Num++;
9156
9157 # set relative positions
9158 if(defined $VirtualTable{1}{$ClassName} and defined $VirtualTable{1}{$ClassName}{$VirtFunc}
9159 and defined $VirtualTable{2}{$ClassName} and defined $VirtualTable{2}{$ClassName}{$VirtFunc})
9160 { # relative position excluding added and removed virtual functions
9161 if(not $CompleteSignature{1}{$VirtFunc}{"Override"}
9162 and not $CompleteSignature{2}{$VirtFunc}{"Override"}) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009163 $CompleteSignature{$LibVersion}{$VirtFunc}{"RelPos"} = $RelPos++;
9164 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009165 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009166 }
9167 }
Andrey Ponomarenko16934472012-03-29 15:37:04 +04009168 foreach my $ClassName (keys(%{$ClassNames{$LibVersion}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009169 {
9170 my $AbsNum = 1;
Andrey Ponomarenko16934472012-03-29 15:37:04 +04009171 foreach my $VirtFunc (getVTable_Model($TName_Tid{$LibVersion}{$ClassName}, $LibVersion)) {
9172 $VirtualTable_Model{$LibVersion}{$ClassName}{$VirtFunc}=$AbsNum++;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009173 }
9174 }
9175}
9176
9177sub get_sub_classes($$$)
9178{
9179 my ($ClassId, $LibVersion, $Recursive) = @_;
9180 return () if(not defined $Class_SubClasses{$LibVersion}{$ClassId});
9181 my @Subs = ();
9182 foreach my $SubId (keys(%{$Class_SubClasses{$LibVersion}{$ClassId}}))
9183 {
Andrey Ponomarenko16934472012-03-29 15:37:04 +04009184 if($Recursive)
9185 {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009186 foreach my $SubSubId (get_sub_classes($SubId, $LibVersion, $Recursive)) {
9187 push(@Subs, $SubSubId);
9188 }
9189 }
9190 push(@Subs, $SubId);
9191 }
9192 return @Subs;
9193}
9194
9195sub get_base_classes($$$)
9196{
9197 my ($ClassId, $LibVersion, $Recursive) = @_;
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04009198 my %ClassType = get_Type($ClassId, $LibVersion);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009199 return () if(not defined $ClassType{"Base"});
9200 my @Bases = ();
9201 foreach my $BaseId (sort {int($ClassType{"Base"}{$a}{"pos"})<=>int($ClassType{"Base"}{$b}{"pos"})}
9202 keys(%{$ClassType{"Base"}}))
9203 {
Andrey Ponomarenko16934472012-03-29 15:37:04 +04009204 if($Recursive)
9205 {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009206 foreach my $SubBaseId (get_base_classes($BaseId, $LibVersion, $Recursive)) {
9207 push(@Bases, $SubBaseId);
9208 }
9209 }
9210 push(@Bases, $BaseId);
9211 }
9212 return @Bases;
9213}
9214
Andrey Ponomarenko16934472012-03-29 15:37:04 +04009215sub getVTable_Model($$)
9216{ # return an ordered list of v-table elements
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009217 my ($ClassId, $LibVersion) = @_;
9218 my @Bases = get_base_classes($ClassId, $LibVersion, 1);
9219 my @Elements = ();
9220 foreach my $BaseId (@Bases, $ClassId)
9221 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04009222 if(my $BName = $TypeInfo{$LibVersion}{$BaseId}{"Name"})
Andrey Ponomarenko85043792012-05-14 16:48:07 +04009223 {
9224 if(defined $VirtualTable{$LibVersion}{$BName})
9225 {
9226 my @VFunctions = keys(%{$VirtualTable{$LibVersion}{$BName}});
9227 @VFunctions = sort {int($CompleteSignature{$LibVersion}{$a}{"Line"}) <=> int($CompleteSignature{$LibVersion}{$b}{"Line"})} @VFunctions;
9228 foreach my $VFunc (@VFunctions) {
9229 push(@Elements, $VFunc);
9230 }
9231 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009232 }
9233 }
9234 return @Elements;
9235}
9236
9237sub getVShift($$)
9238{
9239 my ($ClassId, $LibVersion) = @_;
9240 my @Bases = get_base_classes($ClassId, $LibVersion, 1);
9241 my $VShift = 0;
9242 foreach my $BaseId (@Bases)
9243 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04009244 if(my $BName = $TypeInfo{$LibVersion}{$BaseId}{"Name"})
Andrey Ponomarenko85043792012-05-14 16:48:07 +04009245 {
9246 if(defined $VirtualTable{$LibVersion}{$BName}) {
9247 $VShift+=keys(%{$VirtualTable{$LibVersion}{$BName}});
9248 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009249 }
9250 }
9251 return $VShift;
9252}
9253
9254sub getShift($$)
9255{
9256 my ($ClassId, $LibVersion) = @_;
9257 my @Bases = get_base_classes($ClassId, $LibVersion, 0);
9258 my $Shift = 0;
9259 foreach my $BaseId (@Bases)
9260 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04009261 if(my $Size = $TypeInfo{$LibVersion}{$BaseId}{"Size"})
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04009262 {
9263 if($Size!=1)
9264 { # not empty base class
9265 $Shift+=$Size;
9266 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009267 }
9268 }
9269 return $Shift;
9270}
9271
Andrey Ponomarenko16934472012-03-29 15:37:04 +04009272sub getVTable_Size($$)
9273{ # number of v-table elements
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009274 my ($ClassName, $LibVersion) = @_;
Andrey Ponomarenko16934472012-03-29 15:37:04 +04009275 my $Size = 0;
9276 # three approaches
9277 if(not $Size)
9278 { # real size
9279 if(my %VTable = getVTable_Real($ClassName, $LibVersion)) {
9280 $Size = keys(%VTable);
9281 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009282 }
Andrey Ponomarenko16934472012-03-29 15:37:04 +04009283 if(not $Size)
9284 { # shared library symbol size
9285 if($Size = getSymbolSize($ClassVTable{$ClassName}, $LibVersion)) {
9286 $Size /= $WORD_SIZE{$LibVersion};
9287 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009288 }
Andrey Ponomarenko16934472012-03-29 15:37:04 +04009289 if(not $Size)
9290 { # model size
9291 if(defined $VirtualTable_Model{$LibVersion}{$ClassName}) {
9292 $Size = keys(%{$VirtualTable_Model{$LibVersion}{$ClassName}}) + 2;
9293 }
9294 }
9295 return $Size;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009296}
9297
9298sub isCopyingClass($$)
9299{
9300 my ($TypeId, $LibVersion) = @_;
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04009301 return $TypeInfo{$LibVersion}{$TypeId}{"Copied"};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009302}
9303
9304sub isLeafClass($$)
9305{
9306 my ($ClassId, $LibVersion) = @_;
9307 return (not keys(%{$Class_SubClasses{$LibVersion}{$ClassId}}));
9308}
9309
9310sub havePubFields($)
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04009311{ # check structured type for public fields
9312 return isAccessible($_[0], {}, 0, -1);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009313}
9314
9315sub isAccessible($$$$)
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04009316{ # check interval in structured type for public fields
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009317 my ($TypePtr, $Skip, $Start, $End) = @_;
9318 return 0 if(not $TypePtr);
9319 if($End==-1) {
9320 $End = keys(%{$TypePtr->{"Memb"}})-1;
9321 }
9322 foreach my $MemPos (keys(%{$TypePtr->{"Memb"}}))
9323 {
9324 if($Skip and $Skip->{$MemPos})
9325 { # skip removed/added fields
9326 next;
9327 }
9328 if(int($MemPos)>=$Start and int($MemPos)<=$End)
9329 {
9330 if(isPublic($TypePtr, $MemPos)) {
9331 return ($MemPos+1);
9332 }
9333 }
9334 }
9335 return 0;
9336}
9337
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009338sub isReserved($)
9339{ # reserved fields == private
9340 my $MName = $_[0];
9341 if($MName=~/reserved|padding|f_spare/i) {
9342 return 1;
9343 }
Andrey Ponomarenko9927e332012-10-19 10:50:48 +04009344 if($MName=~/\A[_]*(spare|pad|unused)[_\d]*\Z/i) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009345 return 1;
9346 }
9347 if($MName=~/(pad\d+)/i) {
9348 return 1;
9349 }
9350 return 0;
9351}
9352
9353sub isPublic($$)
9354{
9355 my ($TypePtr, $FieldPos) = @_;
9356 return 0 if(not $TypePtr);
9357 return 0 if(not defined $TypePtr->{"Memb"}{$FieldPos});
9358 return 0 if(not defined $TypePtr->{"Memb"}{$FieldPos}{"name"});
9359 if(not $TypePtr->{"Memb"}{$FieldPos}{"access"})
9360 { # by name in C language
9361 # FIXME: add other methods to detect private members
9362 my $MName = $TypePtr->{"Memb"}{$FieldPos}{"name"};
9363 if($MName=~/priv|abidata|parent_object/i)
9364 { # C-styled private data
9365 return 0;
9366 }
9367 if(lc($MName) eq "abi")
9368 { # ABI information/reserved field
9369 return 0;
9370 }
9371 if(isReserved($MName))
9372 { # reserved fields
9373 return 0;
9374 }
9375 return 1;
9376 }
9377 elsif($TypePtr->{"Memb"}{$FieldPos}{"access"} ne "private")
9378 { # by access in C++ language
9379 return 1;
9380 }
9381 return 0;
9382}
9383
Andrey Ponomarenko16934472012-03-29 15:37:04 +04009384sub getVTable_Real($$)
9385{
9386 my ($ClassName, $LibVersion) = @_;
9387 if(my $ClassId = $TName_Tid{$LibVersion}{$ClassName})
9388 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04009389 my %Type = get_Type($ClassId, $LibVersion);
Andrey Ponomarenko16934472012-03-29 15:37:04 +04009390 if(defined $Type{"VTable"}) {
9391 return %{$Type{"VTable"}};
9392 }
9393 }
9394 return ();
9395}
9396
9397sub cmpVTables($)
9398{
9399 my $ClassName = $_[0];
9400 my $Res = cmpVTables_Real($ClassName, 1);
9401 if($Res==-1) {
9402 $Res = cmpVTables_Model($ClassName);
9403 }
9404 return $Res;
9405}
9406
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009407sub cmpVTables_Model($)
9408{
9409 my $ClassName = $_[0];
Andrey Ponomarenko16934472012-03-29 15:37:04 +04009410 foreach my $Symbol (keys(%{$VirtualTable_Model{1}{$ClassName}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009411 {
Andrey Ponomarenko16934472012-03-29 15:37:04 +04009412 if(not defined $VirtualTable_Model{2}{$ClassName}{$Symbol}) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009413 return 1;
9414 }
9415 }
9416 return 0;
9417}
9418
Andrey Ponomarenko16934472012-03-29 15:37:04 +04009419sub cmpVTables_Real($$)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009420{
9421 my ($ClassName, $Strong) = @_;
Andrey Ponomarenko16934472012-03-29 15:37:04 +04009422 if(defined $Cache{"cmpVTables_Real"}{$Strong}{$ClassName}) {
9423 return $Cache{"cmpVTables_Real"}{$Strong}{$ClassName};
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04009424 }
Andrey Ponomarenko16934472012-03-29 15:37:04 +04009425 my %VTable_Old = getVTable_Real($ClassName, 1);
9426 my %VTable_New = getVTable_Real($ClassName, 2);
9427 if(not %VTable_Old or not %VTable_New)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009428 { # old ABI dumps
Andrey Ponomarenko16934472012-03-29 15:37:04 +04009429 return ($Cache{"cmpVTables_Real"}{$Strong}{$ClassName} = -1);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009430 }
Andrey Ponomarenko16934472012-03-29 15:37:04 +04009431 my %Indexes = map {$_=>1} (keys(%VTable_Old), keys(%VTable_New));
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009432 foreach my $Offset (sort {int($a)<=>int($b)} keys(%Indexes))
9433 {
Andrey Ponomarenko16934472012-03-29 15:37:04 +04009434 if(not defined $VTable_Old{$Offset})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009435 { # v-table v.1 < v-table v.2
Andrey Ponomarenko16934472012-03-29 15:37:04 +04009436 return ($Cache{"cmpVTables_Real"}{$Strong}{$ClassName} = $Strong);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009437 }
Andrey Ponomarenko16934472012-03-29 15:37:04 +04009438 my $Entry1 = $VTable_Old{$Offset};
9439 if(not defined $VTable_New{$Offset})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009440 { # v-table v.1 > v-table v.2
Andrey Ponomarenko16934472012-03-29 15:37:04 +04009441 return ($Cache{"cmpVTables_Real"}{$Strong}{$ClassName} = ($Strong or $Entry1!~/__cxa_pure_virtual/));
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009442 }
Andrey Ponomarenko16934472012-03-29 15:37:04 +04009443 my $Entry2 = $VTable_New{$Offset};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009444 $Entry1 = simpleVEntry($Entry1);
9445 $Entry2 = simpleVEntry($Entry2);
9446 if($Entry1 ne $Entry2)
9447 { # register as changed
9448 if($Entry1=~/::([^:]+)\Z/)
9449 {
9450 my $M1 = $1;
9451 if($Entry2=~/::([^:]+)\Z/)
9452 {
9453 my $M2 = $1;
9454 if($M1 eq $M2)
9455 { # overridden
9456 next;
9457 }
9458 }
9459 }
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04009460 if(differentDumps("G"))
9461 {
9462 if($Entry1=~/\A\-(0x|\d+)/ and $Entry2=~/\A\-(0x|\d+)/)
9463 {
9464 # GCC 4.6.1: -0x00000000000000010
9465 # GCC 4.7.0: -16
9466 next;
9467 }
9468 }
Andrey Ponomarenko16934472012-03-29 15:37:04 +04009469 return ($Cache{"cmpVTables_Real"}{$Strong}{$ClassName} = 1);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009470 }
9471 }
Andrey Ponomarenko16934472012-03-29 15:37:04 +04009472 return ($Cache{"cmpVTables_Real"}{$Strong}{$ClassName} = 0);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009473}
9474
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04009475sub mergeVTables($)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009476{ # merging v-tables without diagnostics
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04009477 my $Level = $_[0];
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009478 foreach my $ClassName (keys(%{$VirtualTable{1}}))
9479 {
Andrey Ponomarenko16934472012-03-29 15:37:04 +04009480 if($VTableChanged_M{$ClassName})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009481 { # already registered
9482 next;
9483 }
Andrey Ponomarenko16934472012-03-29 15:37:04 +04009484 if(cmpVTables_Real($ClassName, 0)==1)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009485 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04009486 my @Affected = (keys(%{$ClassMethods{$Level}{1}{$ClassName}}));
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009487 foreach my $Symbol (@Affected)
9488 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04009489 %{$CompatProblems{$Level}{$Symbol}{"Virtual_Table_Changed_Unknown"}{$ClassName}}=(
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009490 "Type_Name"=>$ClassName,
9491 "Type_Type"=>"Class",
9492 "Target"=>$ClassName);
9493 }
9494 }
9495 }
9496}
9497
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04009498sub mergeBases($)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009499{
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04009500 my $Level = $_[0];
Andrey Ponomarenko16934472012-03-29 15:37:04 +04009501 foreach my $ClassName (keys(%{$ClassNames{1}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009502 { # detect added and removed virtual functions
Andrey Ponomarenko16934472012-03-29 15:37:04 +04009503 my $ClassId = $TName_Tid{1}{$ClassName};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009504 next if(not $ClassId);
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04009505 if(defined $VirtualTable{2}{$ClassName})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009506 {
Andrey Ponomarenko16934472012-03-29 15:37:04 +04009507 foreach my $Symbol (keys(%{$VirtualTable{2}{$ClassName}}))
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04009508 {
Andrey Ponomarenko16934472012-03-29 15:37:04 +04009509 if($TName_Tid{1}{$ClassName}
9510 and not defined $VirtualTable{1}{$ClassName}{$Symbol})
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04009511 { # added to v-table
Andrey Ponomarenko16934472012-03-29 15:37:04 +04009512 if(defined $CompleteSignature{1}{$Symbol}
9513 and $CompleteSignature{1}{$Symbol}{"Virt"})
9514 { # override some method in v.1
9515 next;
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04009516 }
Andrey Ponomarenko16934472012-03-29 15:37:04 +04009517 $AddedInt_Virt{$Level}{$ClassName}{$Symbol} = 1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009518 }
9519 }
9520 }
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04009521 if(defined $VirtualTable{1}{$ClassName})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009522 {
Andrey Ponomarenko16934472012-03-29 15:37:04 +04009523 foreach my $Symbol (keys(%{$VirtualTable{1}{$ClassName}}))
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04009524 {
Andrey Ponomarenko16934472012-03-29 15:37:04 +04009525 if($TName_Tid{2}{$ClassName}
9526 and not defined $VirtualTable{2}{$ClassName}{$Symbol})
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04009527 { # removed from v-table
Andrey Ponomarenko16934472012-03-29 15:37:04 +04009528 if(defined $CompleteSignature{2}{$Symbol}
9529 and $CompleteSignature{2}{$Symbol}{"Virt"})
9530 { # override some method in v.2
9531 next;
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04009532 }
Andrey Ponomarenko16934472012-03-29 15:37:04 +04009533 $RemovedInt_Virt{$Level}{$ClassName}{$Symbol} = 1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009534 }
9535 }
9536 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04009537 if($Level eq "Binary")
9538 { # Binary-level
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04009539 my %Class_Type = get_Type($ClassId, 1);
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04009540 foreach my $AddedVFunc (keys(%{$AddedInt_Virt{$Level}{$ClassName}}))
9541 { # check replacements, including pure virtual methods
9542 my $AddedPos = $VirtualTable{2}{$ClassName}{$AddedVFunc};
9543 foreach my $RemovedVFunc (keys(%{$RemovedInt_Virt{$Level}{$ClassName}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009544 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04009545 my $RemovedPos = $VirtualTable{1}{$ClassName}{$RemovedVFunc};
9546 if($AddedPos==$RemovedPos)
9547 {
9548 $VirtualReplacement{$AddedVFunc} = $RemovedVFunc;
9549 $VirtualReplacement{$RemovedVFunc} = $AddedVFunc;
9550 last; # other methods will be reported as "added" or "removed"
9551 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009552 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04009553 if(my $RemovedVFunc = $VirtualReplacement{$AddedVFunc})
9554 {
9555 if(lc($AddedVFunc) eq lc($RemovedVFunc))
9556 { # skip: DomUi => DomUI parameter (Qt 4.2.3 to 4.3.0)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009557 next;
9558 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04009559 my $ProblemType = "Virtual_Replacement";
9560 my @Affected = ($RemovedVFunc);
9561 if($CompleteSignature{1}{$RemovedVFunc}{"PureVirt"})
9562 { # pure methods
9563 if(not isUsedClass($ClassId, 1, $Level))
9564 { # not a parameter of some exported method
9565 next;
9566 }
9567 $ProblemType = "Pure_Virtual_Replacement";
Andrey Ponomarenko9927e332012-10-19 10:50:48 +04009568
9569 # affected all methods (both virtual and non-virtual ones)
9570 @Affected = (keys(%{$ClassMethods{$Level}{1}{$ClassName}}));
9571 push(@Affected, keys(%{$OverriddenMethods{1}{$RemovedVFunc}}));
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009572 }
Andrey Ponomarenko9927e332012-10-19 10:50:48 +04009573 $VTableChanged_M{$ClassName}=1;
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04009574 foreach my $AffectedInt (@Affected)
9575 {
9576 if($CompleteSignature{1}{$AffectedInt}{"PureVirt"})
9577 { # affected exported methods only
9578 next;
9579 }
Andrey Ponomarenko9927e332012-10-19 10:50:48 +04009580 if(not symbolFilter($AffectedInt, 1, "Affected", $Level)) {
9581 next;
9582 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04009583 %{$CompatProblems{$Level}{$AffectedInt}{$ProblemType}{$tr_name{$AddedVFunc}}}=(
9584 "Type_Name"=>$Class_Type{"Name"},
9585 "Type_Type"=>"Class",
9586 "Target"=>get_Signature($AddedVFunc, 2),
9587 "Old_Value"=>get_Signature($RemovedVFunc, 1));
9588 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009589 }
9590 }
9591 }
9592 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04009593 if(not checkDump(1, "2.0")
9594 or not checkDump(2, "2.0"))
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04009595 { # support for old ABI dumps
Andrey Ponomarenko9927e332012-10-19 10:50:48 +04009596 # "Base" attribute introduced in ACC 1.22 (ABI dump 2.0 format)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009597 return;
9598 }
Andrey Ponomarenko16934472012-03-29 15:37:04 +04009599 foreach my $ClassName (sort keys(%{$ClassNames{1}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009600 {
Andrey Ponomarenko16934472012-03-29 15:37:04 +04009601 my $ClassId_Old = $TName_Tid{1}{$ClassName};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009602 next if(not $ClassId_Old);
9603 if(not isCreatable($ClassId_Old, 1))
9604 { # skip classes without public constructors (including auto-generated)
9605 # example: class has only a private exported or private inline constructor
9606 next;
9607 }
9608 if($ClassName=~/>/)
9609 { # skip affected template instances
9610 next;
9611 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04009612 my %Class_Old = get_Type($ClassId_Old, 1);
Andrey Ponomarenko16934472012-03-29 15:37:04 +04009613 my $ClassId_New = $TName_Tid{2}{$ClassName};
Andrey Ponomarenko85043792012-05-14 16:48:07 +04009614 if(not $ClassId_New) {
9615 next;
9616 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04009617 my %Class_New = get_Type($ClassId_New, 2);
Andrey Ponomarenko85043792012-05-14 16:48:07 +04009618 if($Class_New{"Type"}!~/Class|Struct/)
9619 { # became typedef
9620 if($Level eq "Binary") {
9621 next;
9622 }
9623 if($Level eq "Source")
9624 {
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +04009625 %Class_New = get_PureType($ClassId_New, $TypeInfo{2});
Andrey Ponomarenko85043792012-05-14 16:48:07 +04009626 if($Class_New{"Type"}!~/Class|Struct/) {
9627 next;
9628 }
9629 $ClassId_New = $Class_New{"Tid"};
9630 }
9631 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009632 my @Bases_Old = sort {$Class_Old{"Base"}{$a}{"pos"}<=>$Class_Old{"Base"}{$b}{"pos"}} keys(%{$Class_Old{"Base"}});
9633 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 +04009634
9635 my %Tr_Old = map {$TypeInfo{1}{$_}{"Name"} => uncover_typedefs($TypeInfo{1}{$_}{"Name"}, 1)} @Bases_Old;
9636 my %Tr_New = map {$TypeInfo{2}{$_}{"Name"} => uncover_typedefs($TypeInfo{2}{$_}{"Name"}, 2)} @Bases_New;
9637
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009638 my ($BNum1, $BNum2) = (1, 1);
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +04009639 my %BasePos_Old = map {$Tr_Old{$TypeInfo{1}{$_}{"Name"}} => $BNum1++} @Bases_Old;
9640 my %BasePos_New = map {$Tr_New{$TypeInfo{2}{$_}{"Name"}} => $BNum2++} @Bases_New;
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04009641 my %ShortBase_Old = map {get_ShortType($_, 1) => 1} @Bases_Old;
9642 my %ShortBase_New = map {get_ShortType($_, 2) => 1} @Bases_New;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009643 my $Shift_Old = getShift($ClassId_Old, 1);
9644 my $Shift_New = getShift($ClassId_New, 2);
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +04009645 my %BaseId_New = map {$Tr_New{$TypeInfo{2}{$_}{"Name"}} => $_} @Bases_New;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009646 my ($Added, $Removed) = (0, 0);
9647 my @StableBases_Old = ();
9648 foreach my $BaseId (@Bases_Old)
9649 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04009650 my $BaseName = $TypeInfo{1}{$BaseId}{"Name"};
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +04009651 if($BasePos_New{$Tr_Old{$BaseName}}) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009652 push(@StableBases_Old, $BaseId);
9653 }
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +04009654 elsif(not $ShortBase_New{$Tr_Old{$BaseName}}
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04009655 and not $ShortBase_New{get_ShortType($BaseId, 1)})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009656 { # removed base
9657 # excluding namespace::SomeClass to SomeClass renaming
9658 my $ProblemKind = "Removed_Base_Class";
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04009659 if($Level eq "Binary")
9660 { # Binary-level
9661 if($Shift_Old ne $Shift_New)
9662 { # affected fields
9663 if(havePubFields(\%Class_Old)) {
9664 $ProblemKind .= "_And_Shift";
9665 }
9666 elsif($Class_Old{"Size"} ne $Class_New{"Size"}) {
9667 $ProblemKind .= "_And_Size";
9668 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009669 }
Andrey Ponomarenko16934472012-03-29 15:37:04 +04009670 if(keys(%{$VirtualTable_Model{1}{$BaseName}})
9671 and cmpVTables($ClassName)==1)
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04009672 { # affected v-table
9673 $ProblemKind .= "_And_VTable";
Andrey Ponomarenko16934472012-03-29 15:37:04 +04009674 $VTableChanged_M{$ClassName}=1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009675 }
9676 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04009677 my @Affected = keys(%{$ClassMethods{$Level}{1}{$ClassName}});
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009678 foreach my $SubId (get_sub_classes($ClassId_Old, 1, 1))
9679 {
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +04009680 if(my $SubName = $TypeInfo{1}{$SubId}{"Name"})
9681 {
9682 push(@Affected, keys(%{$ClassMethods{$Level}{1}{$SubName}}));
9683 if($ProblemKind=~/VTable/) {
9684 $VTableChanged_M{$SubName}=1;
9685 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009686 }
9687 }
9688 foreach my $Interface (@Affected)
9689 {
Andrey Ponomarenko9927e332012-10-19 10:50:48 +04009690 if(not symbolFilter($Interface, 1, "Affected", $Level)) {
9691 next;
9692 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04009693 %{$CompatProblems{$Level}{$Interface}{$ProblemKind}{"this"}}=(
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009694 "Type_Name"=>$ClassName,
9695 "Type_Type"=>"Class",
9696 "Target"=>$BaseName,
9697 "Old_Size"=>$Class_Old{"Size"}*$BYTE_SIZE,
9698 "New_Size"=>$Class_New{"Size"}*$BYTE_SIZE,
9699 "Shift"=>abs($Shift_New-$Shift_Old) );
9700 }
9701 $Removed+=1;
9702 }
9703 }
9704 my @StableBases_New = ();
9705 foreach my $BaseId (@Bases_New)
9706 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04009707 my $BaseName = $TypeInfo{2}{$BaseId}{"Name"};
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +04009708 if($BasePos_Old{$Tr_New{$BaseName}}) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009709 push(@StableBases_New, $BaseId);
9710 }
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +04009711 elsif(not $ShortBase_Old{$Tr_New{$BaseName}}
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04009712 and not $ShortBase_Old{get_ShortType($BaseId, 2)})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009713 { # added base
9714 # excluding namespace::SomeClass to SomeClass renaming
9715 my $ProblemKind = "Added_Base_Class";
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04009716 if($Level eq "Binary")
9717 { # Binary-level
9718 if($Shift_Old ne $Shift_New)
9719 { # affected fields
9720 if(havePubFields(\%Class_Old)) {
9721 $ProblemKind .= "_And_Shift";
9722 }
9723 elsif($Class_Old{"Size"} ne $Class_New{"Size"}) {
9724 $ProblemKind .= "_And_Size";
9725 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009726 }
Andrey Ponomarenko16934472012-03-29 15:37:04 +04009727 if(keys(%{$VirtualTable_Model{2}{$BaseName}})
9728 and cmpVTables($ClassName)==1)
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04009729 { # affected v-table
9730 $ProblemKind .= "_And_VTable";
Andrey Ponomarenko16934472012-03-29 15:37:04 +04009731 $VTableChanged_M{$ClassName}=1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009732 }
9733 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04009734 my @Affected = keys(%{$ClassMethods{$Level}{1}{$ClassName}});
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009735 foreach my $SubId (get_sub_classes($ClassId_Old, 1, 1))
9736 {
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +04009737 if(my $SubName = $TypeInfo{1}{$SubId}{"Name"})
9738 {
9739 push(@Affected, keys(%{$ClassMethods{$Level}{1}{$SubName}}));
9740 if($ProblemKind=~/VTable/) {
9741 $VTableChanged_M{$SubName}=1;
9742 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009743 }
9744 }
9745 foreach my $Interface (@Affected)
9746 {
Andrey Ponomarenko9927e332012-10-19 10:50:48 +04009747 if(not symbolFilter($Interface, 1, "Affected", $Level)) {
9748 next;
9749 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04009750 %{$CompatProblems{$Level}{$Interface}{$ProblemKind}{"this"}}=(
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009751 "Type_Name"=>$ClassName,
9752 "Type_Type"=>"Class",
9753 "Target"=>$BaseName,
9754 "Old_Size"=>$Class_Old{"Size"}*$BYTE_SIZE,
9755 "New_Size"=>$Class_New{"Size"}*$BYTE_SIZE,
9756 "Shift"=>abs($Shift_New-$Shift_Old) );
9757 }
9758 $Added+=1;
9759 }
9760 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04009761 if($Level eq "Binary")
9762 { # Binary-level
9763 ($BNum1, $BNum2) = (1, 1);
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +04009764 my %BaseRelPos_Old = map {$Tr_Old{$TypeInfo{1}{$_}{"Name"}} => $BNum1++} @StableBases_Old;
9765 my %BaseRelPos_New = map {$Tr_New{$TypeInfo{2}{$_}{"Name"}} => $BNum2++} @StableBases_New;
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04009766 foreach my $BaseId (@Bases_Old)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009767 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04009768 my $BaseName = $TypeInfo{1}{$BaseId}{"Name"};
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +04009769 if(my $NewPos = $BaseRelPos_New{$Tr_Old{$BaseName}})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009770 {
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +04009771 my $BaseNewId = $BaseId_New{$Tr_Old{$BaseName}};
9772 my $OldPos = $BaseRelPos_Old{$Tr_Old{$BaseName}};
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04009773 if($NewPos!=$OldPos)
9774 { # changed position of the base class
9775 foreach my $Interface (keys(%{$ClassMethods{$Level}{1}{$ClassName}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009776 {
Andrey Ponomarenko9927e332012-10-19 10:50:48 +04009777 if(not symbolFilter($Interface, 1, "Affected", $Level)) {
9778 next;
9779 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04009780 %{$CompatProblems{$Level}{$Interface}{"Base_Class_Position"}{"this"}}=(
9781 "Type_Name"=>$ClassName,
9782 "Type_Type"=>"Class",
9783 "Target"=>$BaseName,
9784 "Old_Value"=>$OldPos-1,
9785 "New_Value"=>$NewPos-1 );
9786 }
9787 }
9788 if($Class_Old{"Base"}{$BaseId}{"virtual"}
9789 and not $Class_New{"Base"}{$BaseNewId}{"virtual"})
9790 { # became non-virtual base
9791 foreach my $Interface (keys(%{$ClassMethods{$Level}{1}{$ClassName}}))
9792 {
Andrey Ponomarenko9927e332012-10-19 10:50:48 +04009793 if(not symbolFilter($Interface, 1, "Affected", $Level)) {
9794 next;
9795 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04009796 %{$CompatProblems{$Level}{$Interface}{"Base_Class_Became_Non_Virtually_Inherited"}{"this->".$BaseName}}=(
9797 "Type_Name"=>$ClassName,
9798 "Type_Type"=>"Class",
9799 "Target"=>$BaseName );
9800 }
9801 }
9802 elsif(not $Class_Old{"Base"}{$BaseId}{"virtual"}
9803 and $Class_New{"Base"}{$BaseNewId}{"virtual"})
9804 { # became virtual base
9805 foreach my $Interface (keys(%{$ClassMethods{$Level}{1}{$ClassName}}))
9806 {
Andrey Ponomarenko9927e332012-10-19 10:50:48 +04009807 if(not symbolFilter($Interface, 1, "Affected", $Level)) {
9808 next;
9809 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04009810 %{$CompatProblems{$Level}{$Interface}{"Base_Class_Became_Virtually_Inherited"}{"this->".$BaseName}}=(
9811 "Type_Name"=>$ClassName,
9812 "Type_Type"=>"Class",
9813 "Target"=>$BaseName );
9814 }
9815 }
9816 }
9817 }
9818 # detect size changes in base classes
9819 if($Shift_Old!=$Shift_New)
9820 { # size of allocable class
9821 foreach my $BaseId (@StableBases_Old)
9822 { # search for changed base
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04009823 my %BaseType = get_Type($BaseId, 1);
9824 my $Size_Old = $TypeInfo{1}{$BaseId}{"Size"};
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +04009825 my $Size_New = $TypeInfo{2}{$BaseId_New{$Tr_Old{$BaseType{"Name"}}}}{"Size"};
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04009826 if($Size_Old ne $Size_New
9827 and $Size_Old and $Size_New)
9828 {
9829 my $ProblemType = "";
9830 if(isCopyingClass($BaseId, 1)) {
9831 $ProblemType = "Size_Of_Copying_Class";
9832 }
9833 elsif($AllocableClass{1}{$BaseType{"Name"}})
9834 {
9835 if($Size_New>$Size_Old)
9836 { # increased size
9837 $ProblemType = "Size_Of_Allocable_Class_Increased";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009838 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04009839 else
9840 { # decreased size
9841 $ProblemType = "Size_Of_Allocable_Class_Decreased";
9842 if(not havePubFields(\%Class_Old))
9843 { # affected class has no public members
9844 next;
9845 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009846 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04009847 }
9848 next if(not $ProblemType);
9849 foreach my $Interface (keys(%{$ClassMethods{$Level}{1}{$ClassName}}))
9850 { # base class size changes affecting current class
Andrey Ponomarenko9927e332012-10-19 10:50:48 +04009851 if(not symbolFilter($Interface, 1, "Affected", $Level)) {
9852 next;
9853 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04009854 %{$CompatProblems{$Level}{$Interface}{$ProblemType}{"this->".$BaseType{"Name"}}}=(
9855 "Type_Name"=>$BaseType{"Name"},
9856 "Type_Type"=>"Class",
9857 "Target"=>$BaseType{"Name"},
9858 "Old_Size"=>$Size_Old*$BYTE_SIZE,
9859 "New_Size"=>$Size_New*$BYTE_SIZE );
9860 }
9861 }
9862 }
9863 }
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +04009864 if(defined $VirtualTable_Model{1}{$ClassName}
Andrey Ponomarenko16934472012-03-29 15:37:04 +04009865 and cmpVTables_Real($ClassName, 1)==1
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +04009866 and my @VFunctions = keys(%{$VirtualTable_Model{1}{$ClassName}}))
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04009867 { # compare virtual tables size in base classes
9868 my $VShift_Old = getVShift($ClassId_Old, 1);
9869 my $VShift_New = getVShift($ClassId_New, 2);
9870 if($VShift_Old ne $VShift_New)
9871 { # changes in the base class or changes in the list of base classes
9872 my @AllBases_Old = get_base_classes($ClassId_Old, 1, 1);
9873 my @AllBases_New = get_base_classes($ClassId_New, 2, 1);
9874 ($BNum1, $BNum2) = (1, 1);
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +04009875 my %StableBase = map {$Tr_New{$TypeInfo{2}{$_}{"Name"}} => $_} @AllBases_New;
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04009876 foreach my $BaseId (@AllBases_Old)
9877 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04009878 my %BaseType = get_Type($BaseId, 1);
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +04009879 if(not $StableBase{$Tr_Old{$BaseType{"Name"}}})
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04009880 { # lost base
9881 next;
9882 }
Andrey Ponomarenko16934472012-03-29 15:37:04 +04009883 my $VSize_Old = getVTable_Size($BaseType{"Name"}, 1);
9884 my $VSize_New = getVTable_Size($BaseType{"Name"}, 2);
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04009885 if($VSize_Old!=$VSize_New)
9886 {
Andrey Ponomarenko85043792012-05-14 16:48:07 +04009887 foreach my $Symbol (@VFunctions)
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +04009888 { # TODO: affected non-virtual methods?
9889 if(not defined $VirtualTable_Model{2}{$ClassName}{$Symbol})
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04009890 { # Removed_Virtual_Method, will be registered in mergeVirtualTables()
9891 next;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009892 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +04009893 if($VirtualTable_Model{2}{$ClassName}{$Symbol}-$VirtualTable_Model{1}{$ClassName}{$Symbol}==0)
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04009894 { # skip interfaces that have not changed the absolute virtual position
9895 next;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009896 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +04009897 if(not symbolFilter($Symbol, 1, "Affected", $Level)) {
9898 next;
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04009899 }
Andrey Ponomarenko16934472012-03-29 15:37:04 +04009900 $VTableChanged_M{$BaseType{"Name"}} = 1;
9901 $VTableChanged_M{$ClassName} = 1;
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04009902 foreach my $VirtFunc (keys(%{$AddedInt_Virt{$Level}{$BaseType{"Name"}}}))
9903 { # the reason of the layout change: added virtual functions
9904 next if($VirtualReplacement{$VirtFunc});
9905 my $ProblemType = "Added_Virtual_Method";
9906 if($CompleteSignature{2}{$VirtFunc}{"PureVirt"}) {
9907 $ProblemType = "Added_Pure_Virtual_Method";
9908 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +04009909 %{$CompatProblems{$Level}{$Symbol}{$ProblemType}{get_Signature($VirtFunc, 2)}}=(
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04009910 "Type_Name"=>$BaseType{"Name"},
9911 "Type_Type"=>"Class",
9912 "Target"=>get_Signature($VirtFunc, 2) );
9913 }
9914 foreach my $VirtFunc (keys(%{$RemovedInt_Virt{$Level}{$BaseType{"Name"}}}))
9915 { # the reason of the layout change: removed virtual functions
9916 next if($VirtualReplacement{$VirtFunc});
9917 my $ProblemType = "Removed_Virtual_Method";
9918 if($CompleteSignature{1}{$VirtFunc}{"PureVirt"}) {
9919 $ProblemType = "Removed_Pure_Virtual_Method";
9920 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +04009921 %{$CompatProblems{$Level}{$Symbol}{$ProblemType}{get_Signature($VirtFunc, 1)}}=(
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04009922 "Type_Name"=>$BaseType{"Name"},
9923 "Type_Type"=>"Class",
9924 "Target"=>get_Signature($VirtFunc, 1) );
9925 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009926 }
9927 }
9928 }
9929 }
9930 }
9931 }
9932 }
9933}
9934
9935sub isCreatable($$)
9936{
9937 my ($ClassId, $LibVersion) = @_;
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04009938 if($AllocableClass{$LibVersion}{$TypeInfo{$LibVersion}{$ClassId}{"Name"}}
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009939 or isCopyingClass($ClassId, $LibVersion)) {
9940 return 1;
9941 }
9942 if(keys(%{$Class_SubClasses{$LibVersion}{$ClassId}}))
9943 { # Fix for incomplete data: if this class has
9944 # a base class then it should also has a constructor
9945 return 1;
9946 }
9947 if($ReturnedClass{$LibVersion}{$ClassId})
9948 { # returned by some method of this class
9949 # or any other class
9950 return 1;
9951 }
9952 return 0;
9953}
9954
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04009955sub isUsedClass($$$)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009956{
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04009957 my ($ClassId, $LibVersion, $Level) = @_;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009958 if(keys(%{$ParamClass{$LibVersion}{$ClassId}}))
9959 { # parameter of some exported method
9960 return 1;
9961 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04009962 my $CName = $TypeInfo{$LibVersion}{$ClassId}{"Name"};
9963 if(keys(%{$ClassMethods{$Level}{$LibVersion}{$CName}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009964 { # method from target class
9965 return 1;
9966 }
9967 return 0;
9968}
9969
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04009970sub mergeVirtualTables($$)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009971{ # check for changes in the virtual table
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04009972 my ($Interface, $Level) = @_;
Andrey Ponomarenko16934472012-03-29 15:37:04 +04009973 # affected methods:
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009974 # - virtual
9975 # - pure-virtual
9976 # - non-virtual
9977 if($CompleteSignature{1}{$Interface}{"Data"})
9978 { # global data is not affected
9979 return;
9980 }
9981 my $Class_Id = $CompleteSignature{1}{$Interface}{"Class"};
Andrey Ponomarenko16934472012-03-29 15:37:04 +04009982 if(not $Class_Id) {
9983 return;
9984 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04009985 my $CName = $TypeInfo{1}{$Class_Id}{"Name"};
Andrey Ponomarenko16934472012-03-29 15:37:04 +04009986 if(cmpVTables_Real($CName, 1)==0)
9987 { # no changes
9988 return;
9989 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04009990 $CheckedTypes{$Level}{$CName} = 1;
9991 if($Level eq "Binary")
9992 { # Binary-level
9993 if($CompleteSignature{1}{$Interface}{"PureVirt"}
9994 and not isUsedClass($Class_Id, 1, $Level))
9995 { # pure virtuals should not be affected
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04009996 # if there are no exported methods using this class
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04009997 return;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009998 }
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04009999 }
10000 foreach my $Func (keys(%{$VirtualTable{1}{$CName}}))
10001 {
10002 if(defined $VirtualTable{2}{$CName}{$Func}
10003 and defined $CompleteSignature{2}{$Func})
10004 {
10005 if(not $CompleteSignature{1}{$Func}{"PureVirt"}
10006 and $CompleteSignature{2}{$Func}{"PureVirt"})
10007 { # became pure virtual
10008 %{$CompatProblems{$Level}{$Interface}{"Virtual_Method_Became_Pure"}{$tr_name{$Func}}}=(
10009 "Type_Name"=>$CName,
10010 "Type_Type"=>"Class",
10011 "Target"=>get_Signature_M($Func, 1) );
10012 $VTableChanged_M{$CName} = 1;
10013 }
10014 elsif($CompleteSignature{1}{$Func}{"PureVirt"}
10015 and not $CompleteSignature{2}{$Func}{"PureVirt"})
10016 { # became non-pure virtual
10017 %{$CompatProblems{$Level}{$Interface}{"Virtual_Method_Became_Non_Pure"}{$tr_name{$Func}}}=(
10018 "Type_Name"=>$CName,
10019 "Type_Type"=>"Class",
10020 "Target"=>get_Signature_M($Func, 1) );
10021 $VTableChanged_M{$CName} = 1;
10022 }
10023 }
10024 }
10025 if($Level eq "Binary")
10026 { # Binary-level
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040010027 # check virtual table structure
10028 foreach my $AddedVFunc (keys(%{$AddedInt_Virt{$Level}{$CName}}))
10029 {
10030 next if($Interface eq $AddedVFunc);
10031 next if($VirtualReplacement{$AddedVFunc});
10032 my $VPos_Added = $VirtualTable{2}{$CName}{$AddedVFunc};
10033 if($CompleteSignature{2}{$AddedVFunc}{"PureVirt"})
10034 { # pure virtual methods affect all others (virtual and non-virtual)
10035 %{$CompatProblems{$Level}{$Interface}{"Added_Pure_Virtual_Method"}{$tr_name{$AddedVFunc}}}=(
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010036 "Type_Name"=>$CName,
10037 "Type_Type"=>"Class",
10038 "Target"=>get_Signature($AddedVFunc, 2) );
Andrey Ponomarenko16934472012-03-29 15:37:04 +040010039 $VTableChanged_M{$CName} = 1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010040 }
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040010041 elsif(not defined $VirtualTable{1}{$CName}
10042 or $VPos_Added>keys(%{$VirtualTable{1}{$CName}}))
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040010043 { # added virtual function at the end of v-table
Andrey Ponomarenko16934472012-03-29 15:37:04 +040010044 if(not keys(%{$VirtualTable_Model{1}{$CName}}))
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040010045 { # became polymorphous class, added v-table pointer
10046 %{$CompatProblems{$Level}{$Interface}{"Added_First_Virtual_Method"}{$tr_name{$AddedVFunc}}}=(
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010047 "Type_Name"=>$CName,
10048 "Type_Type"=>"Class",
10049 "Target"=>get_Signature($AddedVFunc, 2) );
Andrey Ponomarenko16934472012-03-29 15:37:04 +040010050 $VTableChanged_M{$CName} = 1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010051 }
10052 else
10053 {
Andrey Ponomarenko16934472012-03-29 15:37:04 +040010054 my $VSize_Old = getVTable_Size($CName, 1);
10055 my $VSize_New = getVTable_Size($CName, 2);
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040010056 next if($VSize_Old==$VSize_New); # exception: register as removed and added virtual method
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040010057 if(isCopyingClass($Class_Id, 1))
10058 { # class has no constructors and v-table will be copied by applications, this may affect all methods
10059 my $ProblemType = "Added_Virtual_Method";
10060 if(isLeafClass($Class_Id, 1)) {
10061 $ProblemType = "Added_Virtual_Method_At_End_Of_Leaf_Copying_Class";
10062 }
10063 %{$CompatProblems{$Level}{$Interface}{$ProblemType}{$tr_name{$AddedVFunc}}}=(
10064 "Type_Name"=>$CName,
10065 "Type_Type"=>"Class",
10066 "Target"=>get_Signature($AddedVFunc, 2) );
Andrey Ponomarenko16934472012-03-29 15:37:04 +040010067 $VTableChanged_M{$CName} = 1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010068 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040010069 else
10070 {
10071 my $ProblemType = "Added_Virtual_Method";
10072 if(isLeafClass($Class_Id, 1)) {
10073 $ProblemType = "Added_Virtual_Method_At_End_Of_Leaf_Allocable_Class";
10074 }
10075 %{$CompatProblems{$Level}{$Interface}{$ProblemType}{$tr_name{$AddedVFunc}}}=(
10076 "Type_Name"=>$CName,
10077 "Type_Type"=>"Class",
10078 "Target"=>get_Signature($AddedVFunc, 2) );
Andrey Ponomarenko16934472012-03-29 15:37:04 +040010079 $VTableChanged_M{$CName} = 1;
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040010080 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010081 }
10082 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040010083 elsif($CompleteSignature{1}{$Interface}{"Virt"}
10084 or $CompleteSignature{1}{$Interface}{"PureVirt"})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010085 {
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040010086 if(defined $VirtualTable{1}{$CName}
10087 and defined $VirtualTable{2}{$CName})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010088 {
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040010089 my $VPos_Old = $VirtualTable{1}{$CName}{$Interface};
10090 my $VPos_New = $VirtualTable{2}{$CName}{$Interface};
10091 if($VPos_Added<=$VPos_Old and $VPos_Old!=$VPos_New)
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040010092 {
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040010093 my @Affected = ($Interface, keys(%{$OverriddenMethods{1}{$Interface}}));
10094 foreach my $ASymbol (@Affected)
10095 {
Andrey Ponomarenko85043792012-05-14 16:48:07 +040010096 if(not $CompleteSignature{1}{$ASymbol}{"PureVirt"})
10097 {
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040010098 if(not symbolFilter($ASymbol, 1, "Affected", $Level)) {
Andrey Ponomarenko85043792012-05-14 16:48:07 +040010099 next;
10100 }
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040010101 }
10102 $CheckedSymbols{$Level}{$ASymbol} = 1;
10103 %{$CompatProblems{$Level}{$ASymbol}{"Added_Virtual_Method"}{$tr_name{$AddedVFunc}}}=(
10104 "Type_Name"=>$CName,
10105 "Type_Type"=>"Class",
10106 "Target"=>get_Signature($AddedVFunc, 2) );
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040010107 $VTableChanged_M{$TypeInfo{1}{$CompleteSignature{1}{$ASymbol}{"Class"}}{"Name"}} = 1;
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040010108 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010109 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010110 }
10111 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040010112 else {
10113 # safe
10114 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010115 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040010116 foreach my $RemovedVFunc (keys(%{$RemovedInt_Virt{$Level}{$CName}}))
10117 {
10118 next if($VirtualReplacement{$RemovedVFunc});
10119 if($RemovedVFunc eq $Interface
10120 and $CompleteSignature{1}{$RemovedVFunc}{"PureVirt"})
10121 { # This case is for removed virtual methods
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040010122 # implemented in both versions of a library
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040010123 next;
10124 }
Andrey Ponomarenko16934472012-03-29 15:37:04 +040010125 if(not keys(%{$VirtualTable_Model{2}{$CName}}))
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040010126 { # became non-polymorphous class, removed v-table pointer
10127 %{$CompatProblems{$Level}{$Interface}{"Removed_Last_Virtual_Method"}{$tr_name{$RemovedVFunc}}}=(
10128 "Type_Name"=>$CName,
10129 "Type_Type"=>"Class",
10130 "Target"=>get_Signature($RemovedVFunc, 1) );
Andrey Ponomarenko16934472012-03-29 15:37:04 +040010131 $VTableChanged_M{$CName} = 1;
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040010132 }
10133 elsif($CompleteSignature{1}{$Interface}{"Virt"}
10134 or $CompleteSignature{1}{$Interface}{"PureVirt"})
10135 {
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040010136 if(defined $VirtualTable{1}{$CName} and defined $VirtualTable{2}{$CName})
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040010137 {
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040010138 if(not defined $VirtualTable{1}{$CName}{$Interface}) {
10139 next;
10140 }
10141 my $VPos_New = -1;
10142 if(defined $VirtualTable{2}{$CName}{$Interface})
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040010143 {
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040010144 $VPos_New = $VirtualTable{2}{$CName}{$Interface};
10145 }
10146 else
10147 {
10148 if($Interface ne $RemovedVFunc) {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040010149 next;
10150 }
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040010151 }
10152 my $VPos_Removed = $VirtualTable{1}{$CName}{$RemovedVFunc};
10153 my $VPos_Old = $VirtualTable{1}{$CName}{$Interface};
10154 if($VPos_Removed<=$VPos_Old and $VPos_Old!=$VPos_New)
10155 {
10156 my @Affected = ($Interface, keys(%{$OverriddenMethods{1}{$Interface}}));
10157 foreach my $ASymbol (@Affected)
10158 {
Andrey Ponomarenko85043792012-05-14 16:48:07 +040010159 if(not $CompleteSignature{1}{$ASymbol}{"PureVirt"})
10160 {
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040010161 if(not symbolFilter($ASymbol, 1, "Affected", $Level)) {
Andrey Ponomarenko85043792012-05-14 16:48:07 +040010162 next;
10163 }
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040010164 }
10165 my $ProblemType = "Removed_Virtual_Method";
10166 if($CompleteSignature{1}{$RemovedVFunc}{"PureVirt"}) {
10167 $ProblemType = "Removed_Pure_Virtual_Method";
10168 }
10169 $CheckedSymbols{$Level}{$ASymbol} = 1;
10170 %{$CompatProblems{$Level}{$ASymbol}{$ProblemType}{$tr_name{$RemovedVFunc}}}=(
10171 "Type_Name"=>$CName,
10172 "Type_Type"=>"Class",
10173 "Target"=>get_Signature($RemovedVFunc, 1) );
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040010174 $VTableChanged_M{$TypeInfo{1}{$CompleteSignature{1}{$ASymbol}{"Class"}}{"Name"}} = 1;
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040010175 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040010176 }
10177 }
10178 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010179 }
10180 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040010181 else
10182 { # Source-level
10183 foreach my $AddedVFunc (keys(%{$AddedInt_Virt{$Level}{$CName}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010184 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040010185 next if($Interface eq $AddedVFunc);
10186 if($CompleteSignature{2}{$AddedVFunc}{"PureVirt"})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010187 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040010188 %{$CompatProblems{$Level}{$Interface}{"Added_Pure_Virtual_Method"}{$tr_name{$AddedVFunc}}}=(
10189 "Type_Name"=>$CName,
10190 "Type_Type"=>"Class",
10191 "Target"=>get_Signature($AddedVFunc, 2) );
10192 }
10193 }
10194 foreach my $RemovedVFunc (keys(%{$RemovedInt_Virt{$Level}{$CName}}))
10195 {
10196 if($CompleteSignature{1}{$RemovedVFunc}{"PureVirt"})
10197 {
10198 %{$CompatProblems{$Level}{$Interface}{"Removed_Pure_Virtual_Method"}{$tr_name{$RemovedVFunc}}}=(
10199 "Type_Name"=>$CName,
10200 "Type_Type"=>"Class",
10201 "Target"=>get_Signature($RemovedVFunc, 1) );
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010202 }
10203 }
10204 }
10205}
10206
10207sub find_MemberPair_Pos_byName($$)
10208{
10209 my ($Member_Name, $Pair_Type) = @_;
10210 $Member_Name=~s/\A[_]+|[_]+\Z//g;
10211 foreach my $MemberPair_Pos (sort {int($a)<=>int($b)} keys(%{$Pair_Type->{"Memb"}}))
10212 {
10213 if(defined $Pair_Type->{"Memb"}{$MemberPair_Pos})
10214 {
10215 my $Name = $Pair_Type->{"Memb"}{$MemberPair_Pos}{"name"};
10216 $Name=~s/\A[_]+|[_]+\Z//g;
10217 if($Name eq $Member_Name) {
10218 return $MemberPair_Pos;
10219 }
10220 }
10221 }
10222 return "lost";
10223}
10224
10225sub find_MemberPair_Pos_byVal($$)
10226{
10227 my ($Member_Value, $Pair_Type) = @_;
10228 foreach my $MemberPair_Pos (sort {int($a)<=>int($b)} keys(%{$Pair_Type->{"Memb"}}))
10229 {
10230 if(defined $Pair_Type->{"Memb"}{$MemberPair_Pos}
10231 and $Pair_Type->{"Memb"}{$MemberPair_Pos}{"value"} eq $Member_Value) {
10232 return $MemberPair_Pos;
10233 }
10234 }
10235 return "lost";
10236}
10237
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040010238my %Severity_Val=(
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010239 "High"=>3,
10240 "Medium"=>2,
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040010241 "Low"=>1,
10242 "Safe"=>-1
10243);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010244
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040010245sub maxSeverity($$)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010246{
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040010247 my ($S1, $S2) = @_;
10248 if(cmpSeverities($S1, $S2)) {
10249 return $S1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010250 }
10251 else {
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040010252 return $S2;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010253 }
10254}
10255
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040010256sub cmpSeverities($$)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010257{
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040010258 my ($S1, $S2) = @_;
10259 if(not $S1) {
10260 return 0;
10261 }
10262 elsif(not $S2) {
10263 return 1;
10264 }
10265 return ($Severity_Val{$S1}>$Severity_Val{$S2});
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010266}
10267
10268sub getProblemSeverity($$)
10269{
10270 my ($Level, $Kind) = @_;
10271 return $CompatRules{$Level}{$Kind}{"Severity"};
10272}
10273
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040010274sub isRecurType($$)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010275{
10276 foreach (@RecurTypes)
10277 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040010278 if( $_->{"T1"} eq $_[0]
10279 and $_->{"T2"} eq $_[1] )
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010280 {
10281 return 1;
10282 }
10283 }
10284 return 0;
10285}
10286
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040010287sub pushType($$)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010288{
10289 my %TypeIDs=(
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040010290 "T1" => $_[0], #Tid1
10291 "T2" => $_[1] #Tid2
Andrey Ponomarenko16934472012-03-29 15:37:04 +040010292 );
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010293 push(@RecurTypes, \%TypeIDs);
10294}
10295
10296sub isRenamed($$$$$)
10297{
10298 my ($MemPos, $Type1, $LVersion1, $Type2, $LVersion2) = @_;
10299 my $Member_Name = $Type1->{"Memb"}{$MemPos}{"name"};
10300 my $MemberType_Id = $Type1->{"Memb"}{$MemPos}{"type"};
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +040010301 my %MemberType_Pure = get_PureType($MemberType_Id, $TypeInfo{$LVersion1});
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010302 if(not defined $Type2->{"Memb"}{$MemPos}) {
10303 return "";
10304 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040010305 my $PairType_Id = $Type2->{"Memb"}{$MemPos}{"type"};
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +040010306 my %PairType_Pure = get_PureType($PairType_Id, $TypeInfo{$LVersion2});
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010307
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040010308 my $Pair_Name = $Type2->{"Memb"}{$MemPos}{"name"};
10309 my $MemberPair_Pos_Rev = ($Member_Name eq $Pair_Name)?$MemPos:find_MemberPair_Pos_byName($Pair_Name, $Type1);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010310 if($MemberPair_Pos_Rev eq "lost")
10311 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040010312 if($MemberType_Pure{"Name"} eq $PairType_Pure{"Name"})
10313 { # base type match
10314 return $Pair_Name;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010315 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040010316 if($TypeInfo{$LVersion1}{$MemberType_Id}{"Name"} eq $TypeInfo{$LVersion2}{$PairType_Id}{"Name"})
10317 { # exact type match
10318 return $Pair_Name;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010319 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040010320 if($MemberType_Pure{"Size"} eq $PairType_Pure{"Size"})
10321 { # size match
10322 return $Pair_Name;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010323 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040010324 if(isReserved($Pair_Name))
10325 { # reserved fields
10326 return $Pair_Name;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010327 }
10328 }
10329 return "";
10330}
10331
10332sub isLastElem($$)
10333{
10334 my ($Pos, $TypeRef) = @_;
10335 my $Name = $TypeRef->{"Memb"}{$Pos}{"name"};
10336 if($Name=~/last|count|max|total/i)
10337 { # GST_LEVEL_COUNT, GST_RTSP_ELAST
10338 return 1;
10339 }
10340 elsif($Name=~/END|NLIMITS\Z/)
10341 { # __RLIMIT_NLIMITS
10342 return 1;
10343 }
10344 elsif($Name=~/\AN[A-Z](.+)[a-z]+s\Z/
10345 and $Pos+1==keys(%{$TypeRef->{"Memb"}}))
10346 { # NImageFormats, NColorRoles
10347 return 1;
10348 }
10349 return 0;
10350}
10351
10352sub nonComparable($$)
10353{
10354 my ($T1, $T2) = @_;
10355 if($T1->{"Name"} ne $T2->{"Name"}
10356 and not isAnon($T1->{"Name"})
10357 and not isAnon($T2->{"Name"}))
10358 { # different names
10359 if($T1->{"Type"} ne "Pointer"
10360 or $T2->{"Type"} ne "Pointer")
10361 { # compare base types
10362 return 1;
10363 }
10364 if($T1->{"Name"}!~/\Avoid\s*\*/
10365 and $T2->{"Name"}=~/\Avoid\s*\*/)
10366 {
10367 return 1;
10368 }
10369 }
10370 elsif($T1->{"Type"} ne $T2->{"Type"})
10371 { # different types
10372 if($T1->{"Type"} eq "Class"
10373 and $T2->{"Type"} eq "Struct")
10374 { # "class" to "struct"
10375 return 0;
10376 }
10377 elsif($T2->{"Type"} eq "Class"
10378 and $T1->{"Type"} eq "Struct")
10379 { # "struct" to "class"
10380 return 0;
10381 }
10382 else
10383 { # "class" to "enum"
10384 # "union" to "class"
10385 # ...
10386 return 1;
10387 }
10388 }
10389 return 0;
10390}
10391
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040010392sub mergeTypes($$$)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010393{
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040010394 my ($Type1_Id, $Type2_Id, $Level) = @_;
10395 return () if(not $Type1_Id or not $Type2_Id);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010396 my (%Sub_SubProblems, %SubProblems) = ();
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040010397 if($Cache{"mergeTypes"}{$Level}{$Type1_Id}{$Type2_Id})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010398 { # already merged
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040010399 return %{$Cache{"mergeTypes"}{$Level}{$Type1_Id}{$Type2_Id}};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010400 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040010401 my %Type1 = get_Type($Type1_Id, 1);
10402 my %Type2 = get_Type($Type2_Id, 2);
Andrey Ponomarenko16934472012-03-29 15:37:04 +040010403 if(not $Type1{"Name"} or not $Type2{"Name"}) {
10404 return ();
10405 }
10406 $CheckedTypes{$Level}{$Type1{"Name"}}=1;
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +040010407 my %Type1_Pure = get_PureType($Type1_Id, $TypeInfo{1});
10408 my %Type2_Pure = get_PureType($Type2_Id, $TypeInfo{2});
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040010409 $CheckedTypes{$Level}{$Type1_Pure{"Name"}}=1;
Andrey Ponomarenko85043792012-05-14 16:48:07 +040010410 if(not $Type1_Pure{"Size"} or not $Type2_Pure{"Size"})
10411 { # including a case when "class Class { ... };" changed to "class Class;"
10412 return ();
10413 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040010414 if(isRecurType($Type1_Pure{"Tid"}, $Type2_Pure{"Tid"}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010415 { # skip recursive declarations
10416 return ();
10417 }
10418 return () if(not $Type1_Pure{"Name"} or not $Type2_Pure{"Name"});
10419 return () if($SkipTypes{1}{$Type1_Pure{"Name"}});
10420 return () if($SkipTypes{1}{$Type1{"Name"}});
10421
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040010422 my %Typedef_1 = goToFirst($Type1{"Tid"}, 1, "Typedef");
10423 my %Typedef_2 = goToFirst($Type2{"Tid"}, 2, "Typedef");
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040010424 if(not $UseOldDumps and %Typedef_1 and %Typedef_2
10425 and $Typedef_1{"Type"} eq "Typedef" and $Typedef_2{"Type"} eq "Typedef"
10426 and $Typedef_1{"Name"} eq $Typedef_2{"Name"})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010427 {
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +040010428 my %Base_1 = get_OneStep_BaseType($Typedef_1{"Tid"}, $TypeInfo{1});
10429 my %Base_2 = get_OneStep_BaseType($Typedef_2{"Tid"}, $TypeInfo{2});
Andrey Ponomarenko85043792012-05-14 16:48:07 +040010430 if($Base_1{"Name"} ne $Base_2{"Name"})
10431 {
10432 if(differentDumps("G")
10433 or differentDumps("V"))
10434 { # different GCC versions or different dumps
10435 $Base_1{"Name"} = uncover_typedefs($Base_1{"Name"}, 1);
10436 $Base_2{"Name"} = uncover_typedefs($Base_2{"Name"}, 2);
10437 # std::__va_list and __va_list
10438 $Base_1{"Name"}=~s/\A(\w+::)+//;
10439 $Base_2{"Name"}=~s/\A(\w+::)+//;
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040010440 $Base_1{"Name"} = formatName($Base_1{"Name"}, "T");
10441 $Base_2{"Name"} = formatName($Base_2{"Name"}, "T");
Andrey Ponomarenko85043792012-05-14 16:48:07 +040010442 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010443 }
10444 if($Base_1{"Name"}!~/anon\-/ and $Base_2{"Name"}!~/anon\-/
10445 and $Base_1{"Name"} ne $Base_2{"Name"})
10446 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040010447 if($Level eq "Binary"
10448 and $Type1{"Size"} ne $Type2{"Size"})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010449 {
10450 %{$SubProblems{"DataType_Size"}{$Typedef_1{"Name"}}}=(
10451 "Target"=>$Typedef_1{"Name"},
10452 "Type_Name"=>$Typedef_1{"Name"},
10453 "Type_Type"=>"Typedef",
10454 "Old_Size"=>$Type1{"Size"}*$BYTE_SIZE,
10455 "New_Size"=>$Type2{"Size"}*$BYTE_SIZE );
10456 }
10457 %{$SubProblems{"Typedef_BaseType"}{$Typedef_1{"Name"}}}=(
10458 "Target"=>$Typedef_1{"Name"},
10459 "Type_Name"=>$Typedef_1{"Name"},
10460 "Type_Type"=>"Typedef",
10461 "Old_Value"=>$Base_1{"Name"},
10462 "New_Value"=>$Base_2{"Name"} );
10463 }
10464 }
10465 if(nonComparable(\%Type1_Pure, \%Type2_Pure))
10466 { # different types (reported in detectTypeChange(...))
10467 if($Type1_Pure{"Name"} eq $Type2_Pure{"Name"}
10468 and $Type1_Pure{"Type"} ne $Type2_Pure{"Type"}
10469 and $Type1_Pure{"Type"}!~/Intrinsic|Pointer|Ref|Typedef/)
10470 { # different type of the type
10471 %{$SubProblems{"DataType_Type"}{$Type1_Pure{"Name"}}}=(
10472 "Target"=>$Type1_Pure{"Name"},
10473 "Type_Name"=>$Type1_Pure{"Name"},
10474 "Type_Type"=>$Type1_Pure{"Type"},
10475 "Old_Value"=>lc($Type1_Pure{"Type"}),
10476 "New_Value"=>lc($Type2_Pure{"Type"}) );
10477 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040010478 %{$Cache{"mergeTypes"}{$Level}{$Type1_Id}{$Type2_Id}} = %SubProblems;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010479 return %SubProblems;
10480 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040010481 pushType($Type1_Pure{"Tid"}, $Type2_Pure{"Tid"});
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010482 if(($Type1_Pure{"Name"} eq $Type2_Pure{"Name"}
10483 or (isAnon($Type1_Pure{"Name"}) and isAnon($Type2_Pure{"Name"})))
10484 and $Type1_Pure{"Type"}=~/\A(Struct|Class|Union)\Z/)
10485 { # checking size
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040010486 if($Level eq "Binary"
10487 and $Type1_Pure{"Size"} ne $Type2_Pure{"Size"})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010488 {
10489 my $ProblemKind = "DataType_Size";
10490 if($Type1_Pure{"Type"} eq "Class"
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040010491 and keys(%{$ClassMethods{$Level}{1}{$Type1_Pure{"Name"}}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010492 {
10493 if(isCopyingClass($Type1_Pure{"Tid"}, 1)) {
10494 $ProblemKind = "Size_Of_Copying_Class";
10495 }
10496 elsif($AllocableClass{1}{$Type1_Pure{"Name"}})
10497 {
10498 if(int($Type2_Pure{"Size"})>int($Type1_Pure{"Size"})) {
10499 $ProblemKind = "Size_Of_Allocable_Class_Increased";
10500 }
10501 else {
10502 # descreased size of allocable class
10503 # it has no special effects
10504 }
10505 }
10506 }
10507 %{$SubProblems{$ProblemKind}{$Type1_Pure{"Name"}}}=(
10508 "Target"=>$Type1_Pure{"Name"},
10509 "Type_Name"=>$Type1_Pure{"Name"},
10510 "Type_Type"=>$Type1_Pure{"Type"},
10511 "Old_Size"=>$Type1_Pure{"Size"}*$BYTE_SIZE,
10512 "New_Size"=>$Type2_Pure{"Size"}*$BYTE_SIZE,
10513 "InitialType_Type"=>$Type1_Pure{"Type"} );
10514 }
10515 }
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040010516 if(defined $Type1_Pure{"BaseType"} and $Type1_Pure{"BaseType"}{"Tid"}
10517 and defined $Type2_Pure{"BaseType"} and $Type2_Pure{"BaseType"}{"Tid"})
10518 { # checking base types
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040010519 %Sub_SubProblems = mergeTypes($Type1_Pure{"BaseType"}{"Tid"}, $Type2_Pure{"BaseType"}{"Tid"}, $Level);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010520 foreach my $Sub_SubProblemType (keys(%Sub_SubProblems))
10521 {
10522 foreach my $Sub_SubLocation (keys(%{$Sub_SubProblems{$Sub_SubProblemType}}))
10523 {
10524 foreach my $Attr (keys(%{$Sub_SubProblems{$Sub_SubProblemType}{$Sub_SubLocation}})) {
10525 $SubProblems{$Sub_SubProblemType}{$Sub_SubLocation}{$Attr} = $Sub_SubProblems{$Sub_SubProblemType}{$Sub_SubLocation}{$Attr};
10526 }
10527 $SubProblems{$Sub_SubProblemType}{$Sub_SubLocation}{"InitialType_Type"} = $Type1_Pure{"Type"};
10528 }
10529 }
10530 }
10531 my (%AddedField, %RemovedField, %RenamedField, %RenamedField_Rev, %RelatedField, %RelatedField_Rev) = ();
10532 my %NameToPosA = map {$Type1_Pure{"Memb"}{$_}{"name"}=>$_} keys(%{$Type1_Pure{"Memb"}});
10533 my %NameToPosB = map {$Type2_Pure{"Memb"}{$_}{"name"}=>$_} keys(%{$Type2_Pure{"Memb"}});
10534 foreach my $Member_Pos (sort {int($a) <=> int($b)} keys(%{$Type1_Pure{"Memb"}}))
10535 { # detect removed and renamed fields
10536 my $Member_Name = $Type1_Pure{"Memb"}{$Member_Pos}{"name"};
10537 next if(not $Member_Name);
10538 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);
10539 if($MemberPair_Pos eq "lost")
10540 {
10541 if($Type2_Pure{"Type"}=~/\A(Struct|Class|Union)\Z/)
10542 {
10543 if(isUnnamed($Member_Name))
10544 { # support for old-version dumps
10545 # unnamed fields have been introduced in the ACC 1.23 (dump 2.1 format)
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040010546 if(not checkDump(2, "2.1")) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010547 next;
10548 }
10549 }
10550 if(my $RenamedTo = isRenamed($Member_Pos, \%Type1_Pure, 1, \%Type2_Pure, 2))
10551 { # renamed
10552 $RenamedField{$Member_Pos}=$RenamedTo;
10553 $RenamedField_Rev{$NameToPosB{$RenamedTo}}=$Member_Name;
10554 }
10555 else
10556 { # removed
10557 $RemovedField{$Member_Pos}=1;
10558 }
10559 }
10560 elsif($Type1_Pure{"Type"} eq "Enum")
10561 {
10562 my $Member_Value1 = $Type1_Pure{"Memb"}{$Member_Pos}{"value"};
10563 next if($Member_Value1 eq "");
10564 $MemberPair_Pos = find_MemberPair_Pos_byVal($Member_Value1, \%Type2_Pure);
10565 if($MemberPair_Pos ne "lost")
10566 { # renamed
10567 my $RenamedTo = $Type2_Pure{"Memb"}{$MemberPair_Pos}{"name"};
10568 my $MemberPair_Pos_Rev = find_MemberPair_Pos_byName($RenamedTo, \%Type1_Pure);
10569 if($MemberPair_Pos_Rev eq "lost")
10570 {
10571 $RenamedField{$Member_Pos}=$RenamedTo;
10572 $RenamedField_Rev{$NameToPosB{$RenamedTo}}=$Member_Name;
10573 }
10574 else {
10575 $RemovedField{$Member_Pos}=1;
10576 }
10577 }
10578 else
10579 { # removed
10580 $RemovedField{$Member_Pos}=1;
10581 }
10582 }
10583 }
10584 else
10585 { # related
10586 $RelatedField{$Member_Pos} = $MemberPair_Pos;
10587 $RelatedField_Rev{$MemberPair_Pos} = $Member_Pos;
10588 }
10589 }
10590 foreach my $Member_Pos (sort {int($a) <=> int($b)} keys(%{$Type2_Pure{"Memb"}}))
10591 { # detect added fields
10592 my $Member_Name = $Type2_Pure{"Memb"}{$Member_Pos}{"name"};
10593 next if(not $Member_Name);
10594 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);
10595 if($MemberPair_Pos eq "lost")
10596 {
10597 if(isUnnamed($Member_Name))
10598 { # support for old-version dumps
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040010599 # unnamed fields have been introduced in the ACC 1.23 (dump 2.1 format)
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040010600 if(not checkDump(1, "2.1")) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010601 next;
10602 }
10603 }
10604 if($Type2_Pure{"Type"}=~/\A(Struct|Class|Union|Enum)\Z/)
10605 {
10606 if(not $RenamedField_Rev{$Member_Pos})
10607 { # added
10608 $AddedField{$Member_Pos}=1;
10609 }
10610 }
10611 }
10612 }
10613 if($Type2_Pure{"Type"}=~/\A(Struct|Class)\Z/)
10614 { # detect moved fields
10615 my (%RelPos, %RelPosName, %AbsPos) = ();
10616 my $Pos = 0;
10617 foreach my $Member_Pos (sort {int($a) <=> int($b)} keys(%{$Type1_Pure{"Memb"}}))
10618 { # relative positions in 1st version
10619 my $Member_Name = $Type1_Pure{"Memb"}{$Member_Pos}{"name"};
10620 next if(not $Member_Name);
10621 if(not $RemovedField{$Member_Pos})
10622 { # old type without removed fields
10623 $RelPos{1}{$Member_Name}=$Pos;
10624 $RelPosName{1}{$Pos} = $Member_Name;
10625 $AbsPos{1}{$Pos++} = $Member_Pos;
10626 }
10627 }
10628 $Pos = 0;
10629 foreach my $Member_Pos (sort {int($a) <=> int($b)} keys(%{$Type2_Pure{"Memb"}}))
10630 { # relative positions in 2nd version
10631 my $Member_Name = $Type2_Pure{"Memb"}{$Member_Pos}{"name"};
10632 next if(not $Member_Name);
10633 if(not $AddedField{$Member_Pos})
10634 { # new type without added fields
10635 $RelPos{2}{$Member_Name}=$Pos;
10636 $RelPosName{2}{$Pos} = $Member_Name;
10637 $AbsPos{2}{$Pos++} = $Member_Pos;
10638 }
10639 }
10640 foreach my $Member_Name (keys(%{$RelPos{1}}))
10641 {
10642 my $RPos1 = $RelPos{1}{$Member_Name};
10643 my $AbsPos1 = $NameToPosA{$Member_Name};
10644 my $Member_Name2 = $Member_Name;
10645 if(my $RenamedTo = $RenamedField{$AbsPos1})
10646 { # renamed
10647 $Member_Name2 = $RenamedTo;
10648 }
10649 my $RPos2 = $RelPos{2}{$Member_Name2};
10650 if($RPos2 ne "" and $RPos1 ne $RPos2)
10651 { # different relative positions
10652 my $AbsPos2 = $NameToPosB{$Member_Name2};
10653 if($AbsPos1 ne $AbsPos2)
10654 { # different absolute positions
10655 my $ProblemType = "Moved_Field";
10656 if(not isPublic(\%Type1_Pure, $AbsPos1))
10657 { # may change layout and size of type
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040010658 if($Level eq "Source") {
10659 next;
10660 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010661 $ProblemType = "Moved_Private_Field";
10662 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040010663 if($Level eq "Binary"
10664 and $Type1_Pure{"Size"} ne $Type2_Pure{"Size"})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010665 { # affected size
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040010666 my $MemSize1 = $TypeInfo{1}{$Type1_Pure{"Memb"}{$AbsPos1}{"type"}}{"Size"};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010667 my $MovedAbsPos = $AbsPos{1}{$RPos2};
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040010668 my $MemSize2 = $TypeInfo{1}{$Type1_Pure{"Memb"}{$MovedAbsPos}{"type"}}{"Size"};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010669 if($MemSize1 ne $MemSize2) {
10670 $ProblemType .= "_And_Size";
10671 }
10672 }
10673 if($ProblemType eq "Moved_Private_Field") {
10674 next;
10675 }
10676 %{$SubProblems{$ProblemType}{$Member_Name}}=(
10677 "Target"=>$Member_Name,
10678 "Type_Name"=>$Type1_Pure{"Name"},
10679 "Type_Type"=>$Type1_Pure{"Type"},
10680 "Old_Value"=>$RPos1,
10681 "New_Value"=>$RPos2 );
10682 }
10683 }
10684 }
10685 }
10686 foreach my $Member_Pos (sort {int($a) <=> int($b)} keys(%{$Type1_Pure{"Memb"}}))
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040010687 { # check older fields, public and private
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010688 my $Member_Name = $Type1_Pure{"Memb"}{$Member_Pos}{"name"};
10689 next if(not $Member_Name);
10690 if(my $RenamedTo = $RenamedField{$Member_Pos})
10691 { # renamed
10692 if($Type2_Pure{"Type"}=~/\A(Struct|Class|Union)\Z/)
10693 {
10694 if(isPublic(\%Type1_Pure, $Member_Pos))
10695 {
10696 %{$SubProblems{"Renamed_Field"}{$Member_Name}}=(
10697 "Target"=>$Member_Name,
10698 "Type_Name"=>$Type1_Pure{"Name"},
10699 "Type_Type"=>$Type1_Pure{"Type"},
10700 "Old_Value"=>$Member_Name,
10701 "New_Value"=>$RenamedTo );
10702 }
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040010703 elsif(isReserved($Member_Name))
10704 {
10705 %{$SubProblems{"Used_Reserved_Field"}{$Member_Name}}=(
10706 "Target"=>$Member_Name,
10707 "Type_Name"=>$Type1_Pure{"Name"},
10708 "Type_Type"=>$Type1_Pure{"Type"},
10709 "Old_Value"=>$Member_Name,
10710 "New_Value"=>$RenamedTo );
10711 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010712 }
10713 elsif($Type1_Pure{"Type"} eq "Enum")
10714 {
10715 %{$SubProblems{"Enum_Member_Name"}{$Type1_Pure{"Memb"}{$Member_Pos}{"value"}}}=(
10716 "Target"=>$Type1_Pure{"Memb"}{$Member_Pos}{"value"},
10717 "Type_Name"=>$Type1_Pure{"Name"},
10718 "Type_Type"=>$Type1_Pure{"Type"},
10719 "Old_Value"=>$Member_Name,
10720 "New_Value"=>$RenamedTo );
10721 }
10722 }
10723 elsif($RemovedField{$Member_Pos})
10724 { # removed
10725 if($Type2_Pure{"Type"}=~/\A(Struct|Class)\Z/)
10726 {
10727 my $ProblemType = "Removed_Field";
10728 if(not isPublic(\%Type1_Pure, $Member_Pos)
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040010729 or isUnnamed($Member_Name))
10730 {
10731 if($Level eq "Source") {
10732 next;
10733 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010734 $ProblemType = "Removed_Private_Field";
10735 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040010736 if($Level eq "Binary"
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +040010737 and not isMemPadded($Member_Pos, -1, \%Type1_Pure, \%RemovedField, $TypeInfo{1}, $WORD_SIZE{1}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010738 {
10739 if(my $MNum = isAccessible(\%Type1_Pure, \%RemovedField, $Member_Pos+1, -1))
10740 { # affected fields
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +040010741 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 +040010742 { # changed offset
10743 $ProblemType .= "_And_Layout";
10744 }
10745 }
10746 if($Type1_Pure{"Size"} ne $Type2_Pure{"Size"})
10747 { # affected size
10748 $ProblemType .= "_And_Size";
10749 }
10750 }
10751 if($ProblemType eq "Removed_Private_Field") {
10752 next;
10753 }
10754 %{$SubProblems{$ProblemType}{$Member_Name}}=(
10755 "Target"=>$Member_Name,
10756 "Type_Name"=>$Type1_Pure{"Name"},
10757 "Type_Type"=>$Type1_Pure{"Type"} );
10758 }
10759 elsif($Type2_Pure{"Type"} eq "Union")
10760 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040010761 if($Level eq "Binary"
10762 and $Type1_Pure{"Size"} ne $Type2_Pure{"Size"})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010763 {
10764 %{$SubProblems{"Removed_Union_Field_And_Size"}{$Member_Name}}=(
10765 "Target"=>$Member_Name,
10766 "Type_Name"=>$Type1_Pure{"Name"},
10767 "Type_Type"=>$Type1_Pure{"Type"} );
10768 }
10769 else
10770 {
10771 %{$SubProblems{"Removed_Union_Field"}{$Member_Name}}=(
10772 "Target"=>$Member_Name,
10773 "Type_Name"=>$Type1_Pure{"Name"},
10774 "Type_Type"=>$Type1_Pure{"Type"} );
10775 }
10776 }
10777 elsif($Type1_Pure{"Type"} eq "Enum")
10778 {
10779 %{$SubProblems{"Enum_Member_Removed"}{$Member_Name}}=(
10780 "Target"=>$Member_Name,
10781 "Type_Name"=>$Type1_Pure{"Name"},
10782 "Type_Type"=>$Type1_Pure{"Type"},
10783 "Old_Value"=>$Member_Name );
10784 }
10785 }
10786 else
10787 { # changed
10788 my $MemberPair_Pos = $RelatedField{$Member_Pos};
10789 if($Type1_Pure{"Type"} eq "Enum")
10790 {
10791 my $Member_Value1 = $Type1_Pure{"Memb"}{$Member_Pos}{"value"};
10792 next if($Member_Value1 eq "");
10793 my $Member_Value2 = $Type2_Pure{"Memb"}{$MemberPair_Pos}{"value"};
10794 next if($Member_Value2 eq "");
10795 if($Member_Value1 ne $Member_Value2)
10796 {
10797 my $ProblemType = "Enum_Member_Value";
10798 if(isLastElem($Member_Pos, \%Type1_Pure)) {
10799 $ProblemType = "Enum_Last_Member_Value";
10800 }
10801 %{$SubProblems{$ProblemType}{$Member_Name}}=(
10802 "Target"=>$Member_Name,
10803 "Type_Name"=>$Type1_Pure{"Name"},
10804 "Type_Type"=>$Type1_Pure{"Type"},
10805 "Old_Value"=>$Member_Value1,
10806 "New_Value"=>$Member_Value2 );
10807 }
10808 }
10809 elsif($Type2_Pure{"Type"}=~/\A(Struct|Class|Union)\Z/)
10810 {
10811 my $MemberType1_Id = $Type1_Pure{"Memb"}{$Member_Pos}{"type"};
10812 my $MemberType2_Id = $Type2_Pure{"Memb"}{$MemberPair_Pos}{"type"};
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040010813 my $SizeV1 = $TypeInfo{1}{$MemberType1_Id}{"Size"}*$BYTE_SIZE;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010814 if(my $BSize1 = $Type1_Pure{"Memb"}{$Member_Pos}{"bitfield"}) {
10815 $SizeV1 = $BSize1;
10816 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040010817 my $SizeV2 = $TypeInfo{2}{$MemberType2_Id}{"Size"}*$BYTE_SIZE;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010818 if(my $BSize2 = $Type2_Pure{"Memb"}{$MemberPair_Pos}{"bitfield"}) {
10819 $SizeV2 = $BSize2;
10820 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040010821 my $MemberType1_Name = $TypeInfo{1}{$MemberType1_Id}{"Name"};
10822 my $MemberType2_Name = $TypeInfo{2}{$MemberType2_Id}{"Name"};
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040010823 if($Level eq "Binary"
10824 and $SizeV1 ne $SizeV2)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010825 {
10826 if($MemberType1_Name eq $MemberType2_Name or (isAnon($MemberType1_Name) and isAnon($MemberType2_Name))
10827 or ($Type1_Pure{"Memb"}{$Member_Pos}{"bitfield"} and $Type2_Pure{"Memb"}{$MemberPair_Pos}{"bitfield"}))
10828 { # field size change (including anon-structures and unions)
10829 # - same types
10830 # - unnamed types
10831 # - bitfields
10832 my $ProblemType = "Field_Size";
10833 if(not isPublic(\%Type1_Pure, $Member_Pos)
10834 or isUnnamed($Member_Name))
10835 { # should not be accessed by applications, goes to "Low Severity"
10836 # example: "abidata" members in GStreamer types
10837 $ProblemType = "Private_".$ProblemType;
10838 }
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +040010839 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 +040010840 { # check an effect
10841 if(my $MNum = isAccessible(\%Type1_Pure, \%RemovedField, $Member_Pos+1, -1))
10842 { # public fields after the current
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +040010843 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 +040010844 { # changed offset
10845 $ProblemType .= "_And_Layout";
10846 }
10847 }
10848 if($Type1_Pure{"Size"} ne $Type2_Pure{"Size"}) {
10849 $ProblemType .= "_And_Type_Size";
10850 }
10851 }
10852 if($ProblemType eq "Private_Field_Size")
10853 { # private field size with no effect
10854 $ProblemType = "";
10855 }
10856 if($ProblemType)
10857 { # register a problem
10858 %{$SubProblems{$ProblemType}{$Member_Name}}=(
10859 "Target"=>$Member_Name,
10860 "Type_Name"=>$Type1_Pure{"Name"},
10861 "Type_Type"=>$Type1_Pure{"Type"},
10862 "Old_Size"=>$SizeV1,
10863 "New_Size"=>$SizeV2);
10864 }
10865 }
10866 }
10867 if($Type1_Pure{"Memb"}{$Member_Pos}{"bitfield"}
10868 or $Type2_Pure{"Memb"}{$MemberPair_Pos}{"bitfield"})
10869 { # do NOT check bitfield type changes
10870 next;
10871 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040010872 if(checkDump(1, "2.13") and checkDump(2, "2.13"))
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040010873 {
10874 if(not $Type1_Pure{"Memb"}{$Member_Pos}{"mutable"}
10875 and $Type2_Pure{"Memb"}{$MemberPair_Pos}{"mutable"})
10876 {
10877 %{$SubProblems{"Field_Became_Mutable"}{$Member_Name}}=(
10878 "Target"=>$Member_Name,
10879 "Type_Name"=>$Type1_Pure{"Name"},
10880 "Type_Type"=>$Type1_Pure{"Type"});
10881 }
10882 elsif($Type1_Pure{"Memb"}{$Member_Pos}{"mutable"}
10883 and not $Type2_Pure{"Memb"}{$MemberPair_Pos}{"mutable"})
10884 {
10885 %{$SubProblems{"Field_Became_NonMutable"}{$Member_Name}}=(
10886 "Target"=>$Member_Name,
10887 "Type_Name"=>$Type1_Pure{"Name"},
10888 "Type_Type"=>$Type1_Pure{"Type"});
10889 }
10890 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040010891 %Sub_SubProblems = detectTypeChange($MemberType1_Id, $MemberType2_Id, "Field", $Level);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010892 foreach my $ProblemType (keys(%Sub_SubProblems))
10893 {
10894 my $Old_Value = $Sub_SubProblems{$ProblemType}{"Old_Value"};
10895 my $New_Value = $Sub_SubProblems{$ProblemType}{"New_Value"};
10896 if($ProblemType eq "Field_Type"
10897 or $ProblemType eq "Field_Type_And_Size")
10898 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040010899 if(checkDump(1, "2.6") and checkDump(2, "2.6"))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010900 {
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040010901 if(my $RA = addedQual($Old_Value, $New_Value, "volatile"))
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040010902 {
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040010903 %{$Sub_SubProblems{"Field_Became_Volatile"}} = %{$Sub_SubProblems{$ProblemType}};
10904 if($Level eq "Source"
10905 and cmpBTypes($Old_Value, $New_Value, 1, 2)) {
10906 delete($Sub_SubProblems{$ProblemType});
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040010907 }
10908 }
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040010909 elsif(my $RR = removedQual($Old_Value, $New_Value, "volatile"))
10910 {
10911 %{$Sub_SubProblems{"Field_Became_NonVolatile"}} = %{$Sub_SubProblems{$ProblemType}};
10912 if($Level eq "Source"
10913 and cmpBTypes($Old_Value, $New_Value, 1, 2)) {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040010914 delete($Sub_SubProblems{$ProblemType});
10915 }
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040010916 }
10917 }
10918 if(my $RA = addedQual($Old_Value, $New_Value, "const"))
10919 {
10920 if($RA==2) {
10921 %{$Sub_SubProblems{"Field_Added_Const"}} = %{$Sub_SubProblems{$ProblemType}};
10922 }
10923 else {
10924 %{$Sub_SubProblems{"Field_Became_Const"}} = %{$Sub_SubProblems{$ProblemType}};
10925 }
10926 if($Level eq "Source"
10927 and cmpBTypes($Old_Value, $New_Value, 1, 2)) {
10928 delete($Sub_SubProblems{$ProblemType});
10929 }
10930 }
10931 elsif(my $RR = removedQual($Old_Value, $New_Value, "const"))
10932 {
10933 if($RR==2) {
10934 %{$Sub_SubProblems{"Field_Removed_Const"}} = %{$Sub_SubProblems{$ProblemType}};
10935 }
10936 else {
10937 %{$Sub_SubProblems{"Field_Became_NonConst"}} = %{$Sub_SubProblems{$ProblemType}};
10938 }
10939 if($Level eq "Source"
10940 and cmpBTypes($Old_Value, $New_Value, 1, 2)) {
10941 delete($Sub_SubProblems{$ProblemType});
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010942 }
10943 }
10944 }
10945 }
10946 foreach my $ProblemType (keys(%Sub_SubProblems))
10947 {
10948 my $ProblemType_Init = $ProblemType;
10949 if($ProblemType eq "Field_Type_And_Size")
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040010950 { # Binary
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010951 if(not isPublic(\%Type1_Pure, $Member_Pos)
10952 or isUnnamed($Member_Name)) {
10953 $ProblemType = "Private_".$ProblemType;
10954 }
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +040010955 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 +040010956 { # check an effect
10957 if(my $MNum = isAccessible(\%Type1_Pure, \%RemovedField, $Member_Pos+1, -1))
10958 { # public fields after the current
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +040010959 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 +040010960 { # changed offset
10961 $ProblemType .= "_And_Layout";
10962 }
10963 }
10964 if($Type1_Pure{"Size"} ne $Type2_Pure{"Size"}) {
10965 $ProblemType .= "_And_Type_Size";
10966 }
10967 }
10968 }
10969 else
10970 {
10971 if(not isPublic(\%Type1_Pure, $Member_Pos)
10972 or isUnnamed($Member_Name)) {
10973 next;
10974 }
10975 }
10976 if($ProblemType eq "Private_Field_Type_And_Size")
10977 { # private field change with no effect
10978 next;
10979 }
10980 %{$SubProblems{$ProblemType}{$Member_Name}}=(
10981 "Target"=>$Member_Name,
10982 "Type_Name"=>$Type1_Pure{"Name"},
10983 "Type_Type"=>$Type1_Pure{"Type"} );
10984 foreach my $Attr (keys(%{$Sub_SubProblems{$ProblemType_Init}}))
10985 { # other properties
10986 $SubProblems{$ProblemType}{$Member_Name}{$Attr} = $Sub_SubProblems{$ProblemType_Init}{$Attr};
10987 }
10988 }
10989 if(not isPublic(\%Type1_Pure, $Member_Pos))
10990 { # do NOT check internal type changes
10991 next;
10992 }
10993 if($MemberType1_Id and $MemberType2_Id)
10994 {# checking member type changes (replace)
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040010995 %Sub_SubProblems = mergeTypes($MemberType1_Id, $MemberType2_Id, $Level);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010996 foreach my $Sub_SubProblemType (keys(%Sub_SubProblems))
10997 {
10998 foreach my $Sub_SubLocation (keys(%{$Sub_SubProblems{$Sub_SubProblemType}}))
10999 {
11000 my $NewLocation = ($Sub_SubLocation)?$Member_Name."->".$Sub_SubLocation:$Member_Name;
11001 $SubProblems{$Sub_SubProblemType}{$NewLocation}{"IsInTypeInternals"}=1;
11002 foreach my $Attr (keys(%{$Sub_SubProblems{$Sub_SubProblemType}{$Sub_SubLocation}})) {
11003 $SubProblems{$Sub_SubProblemType}{$NewLocation}{$Attr} = $Sub_SubProblems{$Sub_SubProblemType}{$Sub_SubLocation}{$Attr};
11004 }
11005 if($Sub_SubLocation!~/\-\>/) {
11006 $SubProblems{$Sub_SubProblemType}{$NewLocation}{"Start_Type_Name"} = $MemberType1_Name;
11007 }
11008 }
11009 }
11010 }
11011 }
11012 }
11013 }
11014 foreach my $Member_Pos (sort {int($a) <=> int($b)} keys(%{$Type2_Pure{"Memb"}}))
11015 { # checking added members, public and private
11016 my $Member_Name = $Type2_Pure{"Memb"}{$Member_Pos}{"name"};
11017 next if(not $Member_Name);
11018 if($AddedField{$Member_Pos})
11019 { # added
11020 if($Type2_Pure{"Type"}=~/\A(Struct|Class)\Z/)
11021 {
11022 my $ProblemType = "Added_Field";
11023 if(not isPublic(\%Type2_Pure, $Member_Pos)
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011024 or isUnnamed($Member_Name))
11025 {
11026 if($Level eq "Source") {
11027 next;
11028 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011029 $ProblemType = "Added_Private_Field";
11030 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011031 if($Level eq "Binary"
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +040011032 and not isMemPadded($Member_Pos, -1, \%Type2_Pure, \%AddedField, $TypeInfo{2}, $WORD_SIZE{2}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011033 {
11034 if(my $MNum = isAccessible(\%Type2_Pure, \%AddedField, $Member_Pos, -1))
11035 { # public fields after the current
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +040011036 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 +040011037 { # changed offset
11038 $ProblemType .= "_And_Layout";
11039 }
11040 }
11041 if($Type1_Pure{"Size"} ne $Type2_Pure{"Size"}) {
11042 $ProblemType .= "_And_Size";
11043 }
11044 }
11045 if($ProblemType eq "Added_Private_Field")
11046 { # skip added private fields
11047 next;
11048 }
11049 %{$SubProblems{$ProblemType}{$Member_Name}}=(
11050 "Target"=>$Member_Name,
11051 "Type_Name"=>$Type1_Pure{"Name"},
11052 "Type_Type"=>$Type1_Pure{"Type"} );
11053 }
11054 elsif($Type2_Pure{"Type"} eq "Union")
11055 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011056 if($Level eq "Binary"
11057 and $Type1_Pure{"Size"} ne $Type2_Pure{"Size"})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011058 {
11059 %{$SubProblems{"Added_Union_Field_And_Size"}{$Member_Name}}=(
11060 "Target"=>$Member_Name,
11061 "Type_Name"=>$Type1_Pure{"Name"},
11062 "Type_Type"=>$Type1_Pure{"Type"} );
11063 }
11064 else
11065 {
11066 %{$SubProblems{"Added_Union_Field"}{$Member_Name}}=(
11067 "Target"=>$Member_Name,
11068 "Type_Name"=>$Type1_Pure{"Name"},
11069 "Type_Type"=>$Type1_Pure{"Type"} );
11070 }
11071 }
11072 elsif($Type2_Pure{"Type"} eq "Enum")
11073 {
11074 my $Member_Value = $Type2_Pure{"Memb"}{$Member_Pos}{"value"};
11075 next if($Member_Value eq "");
11076 %{$SubProblems{"Added_Enum_Member"}{$Member_Name}}=(
11077 "Target"=>$Member_Name,
11078 "Type_Name"=>$Type2_Pure{"Name"},
11079 "Type_Type"=>$Type2_Pure{"Type"},
11080 "New_Value"=>$Member_Value );
11081 }
11082 }
11083 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040011084 %{$Cache{"mergeTypes"}{$Level}{$Type1_Id}{$Type2_Id}} = %SubProblems;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011085 pop(@RecurTypes);
11086 return %SubProblems;
11087}
11088
11089sub isUnnamed($) {
11090 return $_[0]=~/\Aunnamed\d+\Z/;
11091}
11092
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040011093sub get_ShortType($$)
11094{
11095 my ($TypeId, $LibVersion) = @_;
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +040011096 my $TypeName = uncover_typedefs($TypeInfo{$LibVersion}{$TypeId}{"Name"}, $LibVersion);
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040011097 if(my $NameSpace = $TypeInfo{$LibVersion}{$TypeId}{"NameSpace"}) {
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040011098 $TypeName=~s/\A$NameSpace\:\://g;
11099 }
11100 return $TypeName;
11101}
11102
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040011103sub goToFirst($$$)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011104{
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040011105 my ($TypeId, $LibVersion, $Type_Type) = @_;
Andrey Ponomarenko16934472012-03-29 15:37:04 +040011106 return () if(not $TypeId);
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040011107 if(defined $Cache{"goToFirst"}{$TypeId}{$LibVersion}{$Type_Type}) {
11108 return %{$Cache{"goToFirst"}{$TypeId}{$LibVersion}{$Type_Type}};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011109 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040011110 return () if(not $TypeInfo{$LibVersion}{$TypeId});
11111 my %Type = %{$TypeInfo{$LibVersion}{$TypeId}};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011112 return () if(not $Type{"Type"});
11113 if($Type{"Type"} ne $Type_Type)
11114 {
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040011115 return () if(not defined $Type{"BaseType"});
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040011116 return () if(not $Type{"BaseType"}{"Tid"});
11117 %Type = goToFirst($Type{"BaseType"}{"Tid"}, $LibVersion, $Type_Type);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011118 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040011119 $Cache{"goToFirst"}{$TypeId}{$LibVersion}{$Type_Type} = \%Type;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011120 return %Type;
11121}
11122
11123my %TypeSpecAttributes = (
11124 "Const" => 1,
11125 "Volatile" => 1,
11126 "ConstVolatile" => 1,
11127 "Restrict" => 1,
11128 "Typedef" => 1
11129);
11130
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040011131sub get_PureType($$)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011132{
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +040011133 my ($TypeId, $Info) = @_;
11134 if(not $TypeId or not $Info
11135 or not $Info->{$TypeId}) {
11136 return ();
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011137 }
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +040011138 if(defined $Cache{"get_PureType"}{$TypeId}{$Info}) {
11139 return %{$Cache{"get_PureType"}{$TypeId}{$Info}};
11140 }
11141 my %Type = %{$Info->{$TypeId}};
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040011142 return %Type if(not defined $Type{"BaseType"});
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040011143 return %Type if(not $Type{"BaseType"}{"Tid"});
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011144 if($TypeSpecAttributes{$Type{"Type"}}) {
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +040011145 %Type = get_PureType($Type{"BaseType"}{"Tid"}, $Info);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011146 }
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +040011147 $Cache{"get_PureType"}{$TypeId}{$Info} = \%Type;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011148 return %Type;
11149}
11150
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040011151sub get_PLevel($$)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011152{
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040011153 my ($TypeId, $LibVersion) = @_;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011154 return 0 if(not $TypeId);
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040011155 if(defined $Cache{"get_PLevel"}{$TypeId}{$LibVersion}) {
11156 return $Cache{"get_PLevel"}{$TypeId}{$LibVersion};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011157 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040011158 return 0 if(not $TypeInfo{$LibVersion}{$TypeId});
11159 my %Type = %{$TypeInfo{$LibVersion}{$TypeId}};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011160 return 1 if($Type{"Type"}=~/FuncPtr|MethodPtr|FieldPtr/);
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040011161 return 0 if(not defined $Type{"BaseType"});
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040011162 return 0 if(not $Type{"BaseType"}{"Tid"});
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011163 my $PointerLevel = 0;
11164 if($Type{"Type"} =~/Pointer|Ref|FuncPtr|MethodPtr|FieldPtr/) {
11165 $PointerLevel += 1;
11166 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040011167 $PointerLevel += get_PLevel($Type{"BaseType"}{"Tid"}, $LibVersion);
11168 $Cache{"get_PLevel"}{$TypeId}{$LibVersion} = $PointerLevel;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011169 return $PointerLevel;
11170}
11171
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040011172sub get_BaseType($$)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011173{
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040011174 my ($TypeId, $LibVersion) = @_;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011175 return () if(not $TypeId);
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040011176 if(defined $Cache{"get_BaseType"}{$TypeId}{$LibVersion}) {
11177 return %{$Cache{"get_BaseType"}{$TypeId}{$LibVersion}};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011178 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040011179 return () if(not $TypeInfo{$LibVersion}{$TypeId});
11180 my %Type = %{$TypeInfo{$LibVersion}{$TypeId}};
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040011181 return %Type if(not defined $Type{"BaseType"});
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040011182 return %Type if(not $Type{"BaseType"}{"Tid"});
11183 %Type = get_BaseType($Type{"BaseType"}{"Tid"}, $LibVersion);
11184 $Cache{"get_BaseType"}{$TypeId}{$LibVersion} = \%Type;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011185 return %Type;
11186}
11187
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040011188sub get_BaseTypeQual($$)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011189{
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040011190 my ($TypeId, $LibVersion) = @_;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011191 return "" if(not $TypeId);
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040011192 return "" if(not $TypeInfo{$LibVersion}{$TypeId});
11193 my %Type = %{$TypeInfo{$LibVersion}{$TypeId}};
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040011194 return "" if(not defined $Type{"BaseType"});
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040011195 return "" if(not $Type{"BaseType"}{"Tid"});
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011196 my $Qual = "";
11197 if($Type{"Type"} eq "Pointer") {
11198 $Qual .= "*";
11199 }
11200 elsif($Type{"Type"} eq "Ref") {
11201 $Qual .= "&";
11202 }
11203 elsif($Type{"Type"} eq "ConstVolatile") {
11204 $Qual .= "const volatile";
11205 }
11206 elsif($Type{"Type"} eq "Const"
11207 or $Type{"Type"} eq "Volatile"
11208 or $Type{"Type"} eq "Restrict") {
11209 $Qual .= lc($Type{"Type"});
11210 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040011211 my $BQual = get_BaseTypeQual($Type{"BaseType"}{"Tid"}, $LibVersion);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011212 return $BQual.$Qual;
11213}
11214
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040011215sub get_OneStep_BaseType($$)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011216{
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +040011217 my ($TypeId, $Info) = @_;
11218 if(not $TypeId or not $Info
11219 or not $Info->{$TypeId}) {
11220 return ();
11221 }
11222 my %Type = %{$Info->{$TypeId}};
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040011223 return %Type if(not defined $Type{"BaseType"});
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +040011224 if(my $BTid = $Type{"BaseType"}{"Tid"})
11225 {
11226 if($Info->{$BTid}) {
11227 return %{$Info->{$BTid}};
11228 }
11229 else { # something is going wrong
11230 return ();
11231 }
11232 }
11233 else {
11234 return %Type;
11235 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011236}
11237
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040011238sub get_Type($$)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011239{
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040011240 my ($TypeId, $LibVersion) = @_;
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040011241 return () if(not $TypeId);
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040011242 return () if(not $TypeInfo{$LibVersion}{$TypeId});
11243 return %{$TypeInfo{$LibVersion}{$TypeId}};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011244}
11245
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +040011246sub isPrivateData($)
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040011247{ # non-public global data
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011248 my $Symbol = $_[0];
11249 return ($Symbol=~/\A(_ZGV|_ZTI|_ZTS|_ZTT|_ZTV|_ZTC|_ZThn|_ZTv0_n)/);
11250}
11251
Andrey Ponomarenko01117f12012-06-26 12:23:02 +040011252sub isInLineInst($$$) {
11253 return (isTemplateInstance(@_) and not isTemplateSpec(@_));
11254}
11255
11256sub isTemplateInstance($$$)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011257{
Andrey Ponomarenko01117f12012-06-26 12:23:02 +040011258 my ($Symbol, $SInfo, $LibVersion) = @_;
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040011259 if($CheckObjectsOnly)
11260 {
11261 if($Symbol!~/\A(_Z|\?)/) {
11262 return 0;
11263 }
11264 if(my $Signature = $tr_name{$Symbol})
11265 {
11266 if(index($Signature,">")==-1) {
11267 return 0;
11268 }
11269 if(my $ShortName = substr($Signature, 0, find_center($Signature, "(")))
11270 {
Andrey Ponomarenko01117f12012-06-26 12:23:02 +040011271 if(index($ShortName,"<")!=-1
11272 and index($ShortName,">")!=-1) {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040011273 return 1;
11274 }
11275 }
11276 }
11277 }
11278 else
11279 {
Andrey Ponomarenko01117f12012-06-26 12:23:02 +040011280 if(my $ClassId = $SInfo->{"Class"})
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040011281 {
11282 if(my $ClassName = $TypeInfo{$LibVersion}{$ClassId}{"Name"})
11283 {
11284 if(index($ClassName,"<")!=-1) {
11285 return 1;
11286 }
11287 }
11288 }
Andrey Ponomarenko01117f12012-06-26 12:23:02 +040011289 if(my $ShortName = $SInfo->{"ShortName"})
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040011290 {
Andrey Ponomarenko01117f12012-06-26 12:23:02 +040011291 if(index($ShortName,"<")!=-1
11292 and index($ShortName,">")!=-1) {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040011293 return 1;
11294 }
11295 }
11296 }
11297 return 0;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011298}
11299
Andrey Ponomarenko01117f12012-06-26 12:23:02 +040011300sub isTemplateSpec($$$)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011301{
Andrey Ponomarenko01117f12012-06-26 12:23:02 +040011302 my ($Symbol, $SInfo, $LibVersion) = @_;
11303 if(my $ClassId = $SInfo->{"Class"})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011304 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040011305 if($TypeInfo{$LibVersion}{$ClassId}{"Spec"})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011306 { # class specialization
11307 return 1;
11308 }
Andrey Ponomarenko01117f12012-06-26 12:23:02 +040011309 elsif($SInfo->{"Spec"})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011310 { # method specialization
11311 return 1;
11312 }
11313 }
11314 return 0;
11315}
11316
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011317sub symbolFilter($$$$)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011318{ # some special cases when the symbol cannot be imported
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011319 my ($Symbol, $LibVersion, $Type, $Level) = @_;
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +040011320 if(isPrivateData($Symbol))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011321 { # non-public global data
11322 return 0;
11323 }
11324 if($CheckObjectsOnly) {
11325 return 0 if($Symbol=~/\A(_init|_fini)\Z/);
11326 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040011327 if($CheckHeadersOnly and not checkDump($LibVersion, "2.7"))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011328 { # support for old ABI dumps in --headers-only mode
11329 foreach my $Pos (keys(%{$CompleteSignature{$LibVersion}{$Symbol}{"Param"}}))
11330 {
11331 if(my $Pid = $CompleteSignature{$LibVersion}{$Symbol}{"Param"}{$Pos}{"type"})
11332 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040011333 my $PType = $TypeInfo{$LibVersion}{$Pid}{"Type"};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011334 if(not $PType or $PType eq "Unknown") {
11335 return 0;
11336 }
11337 }
11338 }
11339 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +040011340 if($Type=~/Affected/)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011341 {
11342 my $ClassId = $CompleteSignature{$LibVersion}{$Symbol}{"Class"};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011343 if($SkipSymbols{$LibVersion}{$Symbol})
11344 { # user defined symbols to ignore
11345 return 0;
11346 }
11347 my $NameSpace = $CompleteSignature{$LibVersion}{$Symbol}{"NameSpace"};
11348 if(not $NameSpace and $ClassId)
11349 { # class methods have no "NameSpace" attribute
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040011350 $NameSpace = $TypeInfo{$LibVersion}{$ClassId}{"NameSpace"};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011351 }
11352 if($NameSpace)
11353 { # user defined namespaces to ignore
11354 if($SkipNameSpaces{$LibVersion}{$NameSpace}) {
11355 return 0;
11356 }
11357 foreach my $NS (keys(%{$SkipNameSpaces{$LibVersion}}))
11358 { # nested namespaces
11359 if($NameSpace=~/\A\Q$NS\E(\:\:|\Z)/) {
11360 return 0;
11361 }
11362 }
11363 }
11364 if(my $Header = $CompleteSignature{$LibVersion}{$Symbol}{"Header"})
11365 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040011366 if(my $Skip = skipHeader($Header, $LibVersion))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011367 { # --skip-headers or <skip_headers> (not <skip_including>)
11368 if($Skip==1) {
11369 return 0;
11370 }
11371 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011372 }
11373 if($SymbolsListPath and not $SymbolsList{$Symbol})
11374 { # user defined symbols
11375 return 0;
11376 }
11377 if($AppPath and not $SymbolsList_App{$Symbol})
11378 { # user defined symbols (in application)
11379 return 0;
11380 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +040011381 if(not selectSymbol($Symbol, $CompleteSignature{$LibVersion}{$Symbol}, $Level, $LibVersion))
11382 { # non-target symbols
11383 return 0;
11384 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011385 if($Level eq "Binary")
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011386 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040011387 if($CheckObjectsOnly)
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011388 {
Andrey Ponomarenko01117f12012-06-26 12:23:02 +040011389 if(isTemplateInstance($Symbol, $CompleteSignature{$LibVersion}{$Symbol}, $LibVersion)) {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040011390 return 0;
11391 }
11392 }
11393 else
11394 {
11395 if($CompleteSignature{$LibVersion}{$Symbol}{"InLine"}
Andrey Ponomarenko01117f12012-06-26 12:23:02 +040011396 or isInLineInst($Symbol, $CompleteSignature{$LibVersion}{$Symbol}, $LibVersion))
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040011397 {
11398 if($ClassId and $CompleteSignature{$LibVersion}{$Symbol}{"Virt"})
11399 { # inline virtual methods
11400 if($Type=~/InlineVirt/) {
11401 return 1;
11402 }
11403 my $Allocable = (not isCopyingClass($ClassId, $LibVersion));
11404 if(not $Allocable)
11405 { # check bases
11406 foreach my $DCId (get_sub_classes($ClassId, $LibVersion, 1))
11407 {
11408 if(not isCopyingClass($DCId, $LibVersion))
11409 { # exists a derived class without default c-tor
11410 $Allocable=1;
11411 last;
11412 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011413 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011414 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040011415 if(not $Allocable) {
11416 return 0;
11417 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011418 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040011419 else
11420 { # inline non-virtual methods
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011421 return 0;
11422 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011423 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011424 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011425 }
11426 }
11427 return 1;
11428}
11429
11430sub mergeImpl()
11431{
11432 my $DiffCmd = get_CmdPath("diff");
11433 if(not $DiffCmd) {
11434 exitStatus("Not_Found", "can't find \"diff\"");
11435 }
11436 foreach my $Interface (sort keys(%{$Symbol_Library{1}}))
11437 { # implementation changes
11438 next if($CompleteSignature{1}{$Interface}{"Private"});
11439 next if(not $CompleteSignature{1}{$Interface}{"Header"} and not $CheckObjectsOnly);
11440 next if(not $Symbol_Library{2}{$Interface} and not $Symbol_Library{2}{$SymVer{2}{$Interface}});
Andrey Ponomarenko85043792012-05-14 16:48:07 +040011441 if(not symbolFilter($Interface, 1, "Affected", "Binary")) {
11442 next;
11443 }
Andrey Ponomarenko16934472012-03-29 15:37:04 +040011444 my $Impl1 = canonifyImpl($Interface_Impl{1}{$Interface});
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011445 next if(not $Impl1);
Andrey Ponomarenko16934472012-03-29 15:37:04 +040011446 my $Impl2 = canonifyImpl($Interface_Impl{2}{$Interface});
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011447 next if(not $Impl2);
11448 if($Impl1 ne $Impl2)
11449 {
11450 writeFile("$TMP_DIR/impl1", $Impl1);
11451 writeFile("$TMP_DIR/impl2", $Impl2);
Andrey Ponomarenkoa01311b2012-06-08 17:20:02 +040011452 my $Diff = `$DiffCmd -rNau \"$TMP_DIR/impl1\" \"$TMP_DIR/impl2\"`;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011453 $Diff=~s/(---|\+\+\+).+\n//g;
11454 $Diff=~s/[ ]{3,}/ /g;
11455 $Diff=~s/\n\@\@/\n \n\@\@/g;
Andrey Ponomarenkoa01311b2012-06-08 17:20:02 +040011456 unlink("$TMP_DIR/impl1");
11457 unlink("$TMP_DIR/impl2");
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011458 %{$ImplProblems{$Interface}}=(
11459 "Diff" => get_CodeView($Diff) );
11460 }
11461 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +040011462
11463 # clean memory
11464 %Interface_Impl = ();
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011465}
11466
Andrey Ponomarenko16934472012-03-29 15:37:04 +040011467sub canonifyImpl($)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011468{
11469 my $FuncBody= $_[0];
11470 return "" if(not $FuncBody);
11471 $FuncBody=~s/0x[a-f\d]+/0x?/g;# addr
11472 $FuncBody=~s/((\A|\n)[a-z]+[\t ]+)[a-f\d]+([^x]|\Z)/$1?$3/g;# call, jump
11473 $FuncBody=~s/# [a-f\d]+ /# ? /g;# call, jump
11474 $FuncBody=~s/%([a-z]+[a-f\d]*)/\%reg/g;# registers
11475 while($FuncBody=~s/\nnop[ \t]*(\n|\Z)/$1/g){};# empty op
11476 $FuncBody=~s/<.+?\.cpp.+?>/<name.cpp>/g;
11477 $FuncBody=~s/(\A|\n)[a-f\d]+ </$1? </g;# 5e74 <_ZN...
11478 $FuncBody=~s/\.L\d+/.L/g;
11479 $FuncBody=~s/#(-?)\d+/#$1?/g;# r3, [r3, #120]
11480 $FuncBody=~s/[\n]{2,}/\n/g;
11481 return $FuncBody;
11482}
11483
11484sub get_CodeView($)
11485{
11486 my $Code = $_[0];
11487 my $View = "";
11488 foreach my $Line (split(/\n/, $Code))
11489 {
11490 if($Line=~s/\A(\+|-)/$1 /g)
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040011491 { # bold line
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011492 $View .= "<tr><td><b>".htmlSpecChars($Line)."</b></td></tr>\n";
11493 }
11494 else {
11495 $View .= "<tr><td>".htmlSpecChars($Line)."</td></tr>\n";
11496 }
11497 }
11498 return "<table class='code_view'>$View</table>\n";
11499}
11500
11501sub getImplementations($$)
11502{
11503 my ($LibVersion, $Path) = @_;
11504 return if(not $LibVersion or not -e $Path);
11505 if($OSgroup eq "macos")
11506 {
11507 my $OtoolCmd = get_CmdPath("otool");
11508 if(not $OtoolCmd) {
11509 exitStatus("Not_Found", "can't find \"otool\"");
11510 }
11511 my $CurInterface = "";
Andrey Ponomarenkoa01311b2012-06-08 17:20:02 +040011512 foreach my $Line (split(/\n/, `$OtoolCmd -tv \"$Path\" 2>\"$TMP_DIR/null\"`))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011513 {
11514 if($Line=~/\A\s*_(\w+)\s*:/i) {
11515 $CurInterface = $1;
11516 }
11517 elsif($Line=~/\A\s*[\da-z]+\s+(.+?)\Z/i) {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040011518 $Interface_Impl{$LibVersion}{$CurInterface} .= $1."\n";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011519 }
11520 }
11521 }
11522 else
11523 {
11524 my $ObjdumpCmd = get_CmdPath("objdump");
11525 if(not $ObjdumpCmd) {
11526 exitStatus("Not_Found", "can't find \"objdump\"");
11527 }
11528 my $CurInterface = "";
Andrey Ponomarenkoa01311b2012-06-08 17:20:02 +040011529 foreach my $Line (split(/\n/, `$ObjdumpCmd -d \"$Path\" 2>\"$TMP_DIR/null\"`))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011530 {
11531 if($Line=~/\A[\da-z]+\s+<(\w+)>/i) {
11532 $CurInterface = $1;
11533 }
11534 else
11535 { # x86: 51fa:(\t)89 e5 (\t)mov %esp,%ebp
11536 # arm: 5020:(\t)e24cb004(\t)sub(\t)fp, ip, #4(\t); 0x4
11537 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 +040011538 $Interface_Impl{$LibVersion}{$CurInterface} .= $2."\n";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011539 }
11540 }
11541 }
11542 }
11543}
11544
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011545sub detectAdded($)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011546{
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011547 my $Level = $_[0];
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011548 foreach my $Symbol (keys(%{$Symbol_Library{2}}))
11549 {
11550 if(link_symbol($Symbol, 1, "+Deps"))
11551 { # linker can find a new symbol
11552 # in the old-version library
11553 # So, it's not a new symbol
11554 next;
11555 }
11556 if(my $VSym = $SymVer{2}{$Symbol}
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040011557 and index($Symbol,"\@")==-1) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011558 next;
11559 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011560 $AddedInt{$Level}{$Symbol} = 1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011561 }
11562}
11563
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011564sub detectRemoved($)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011565{
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011566 my $Level = $_[0];
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011567 foreach my $Symbol (keys(%{$Symbol_Library{1}}))
11568 {
11569 if($CheckObjectsOnly) {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011570 $CheckedSymbols{"Binary"}{$Symbol} = 1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011571 }
11572 if(link_symbol($Symbol, 2, "+Deps"))
11573 { # linker can find an old symbol
11574 # in the new-version library
11575 next;
11576 }
11577 if(my $VSym = $SymVer{1}{$Symbol}
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040011578 and index($Symbol,"\@")==-1) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011579 next;
11580 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011581 $RemovedInt{$Level}{$Symbol} = 1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011582 }
11583}
11584
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011585sub mergeLibs($)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011586{
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011587 my $Level = $_[0];
11588 foreach my $Symbol (sort keys(%{$AddedInt{$Level}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011589 { # checking added symbols
11590 next if($CompleteSignature{2}{$Symbol}{"Private"});
11591 next if(not $CompleteSignature{2}{$Symbol}{"Header"} and not $CheckObjectsOnly);
Andrey Ponomarenko85043792012-05-14 16:48:07 +040011592 next if(not symbolFilter($Symbol, 2, "Affected", $Level));
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011593 %{$CompatProblems{$Level}{$Symbol}{"Added_Symbol"}{""}}=();
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011594 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011595 foreach my $Symbol (sort keys(%{$RemovedInt{$Level}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011596 { # checking removed symbols
11597 next if($CompleteSignature{1}{$Symbol}{"Private"});
11598 next if(not $CompleteSignature{1}{$Symbol}{"Header"} and not $CheckObjectsOnly);
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040011599 if(index($Symbol, "_ZTV")==0)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011600 { # skip v-tables for templates, that should not be imported by applications
11601 next if($tr_name{$Symbol}=~/</);
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040011602 if(my $CName = $VTableClass{$Symbol})
11603 {
11604 if(not keys(%{$ClassMethods{$Level}{1}{$CName}}))
11605 { # vtables for "private" classes
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040011606 # use case: vtable for QDragManager (Qt 4.5.3 to 4.6.0) became HIDDEN symbol
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040011607 next;
11608 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011609 }
11610 }
11611 else {
Andrey Ponomarenko85043792012-05-14 16:48:07 +040011612 next if(not symbolFilter($Symbol, 1, "Affected", $Level));
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011613 }
11614 if($CompleteSignature{1}{$Symbol}{"PureVirt"})
11615 { # symbols for pure virtual methods cannot be called by clients
11616 next;
11617 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011618 %{$CompatProblems{$Level}{$Symbol}{"Removed_Symbol"}{""}}=();
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011619 }
11620}
11621
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040011622sub checkDump($$)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011623{
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040011624 my ($LibVersion, $V) = @_;
11625 if(defined $Cache{"checkDump"}{$LibVersion}{$V}) {
11626 return $Cache{"checkDump"}{$LibVersion}{$V};
11627 }
11628 return ($Cache{"checkDump"}{$LibVersion}{$V} = (not $UsedDump{$LibVersion}{"V"} or cmpVersions($UsedDump{$LibVersion}{"V"}, $V)>=0));
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011629}
11630
11631sub detectAdded_H($)
11632{
11633 my $Level = $_[0];
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011634 foreach my $Symbol (sort keys(%{$CompleteSignature{2}}))
11635 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011636 if($Level eq "Source")
11637 { # remove symbol version
11638 my ($SN, $SS, $SV) = separate_symbol($Symbol);
11639 $Symbol=$SN;
Andrey Ponomarenkob8d203d2012-05-25 18:11:07 +040011640
11641 if($CompleteSignature{2}{$Symbol}{"Artificial"})
11642 { # skip artificial constructors
11643 next;
11644 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011645 }
Andrey Ponomarenko16934472012-03-29 15:37:04 +040011646 if(not $CompleteSignature{2}{$Symbol}{"Header"}
11647 or not $CompleteSignature{2}{$Symbol}{"MnglName"}) {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011648 next;
11649 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040011650 if($ExtendedSymbols{$Symbol}) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011651 next;
11652 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011653 if(not defined $CompleteSignature{1}{$Symbol}
11654 or not $CompleteSignature{1}{$Symbol}{"MnglName"})
11655 {
Andrey Ponomarenko16934472012-03-29 15:37:04 +040011656 if($UsedDump{2}{"SrcBin"})
11657 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040011658 if($UsedDump{1}{"BinOnly"} or not checkDump(1, "2.11"))
Andrey Ponomarenko16934472012-03-29 15:37:04 +040011659 { # support for old and different (!) ABI dumps
11660 if(not $CompleteSignature{2}{$Symbol}{"Virt"}
11661 and not $CompleteSignature{2}{$Symbol}{"PureVirt"})
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011662 {
Andrey Ponomarenko16934472012-03-29 15:37:04 +040011663 if($CheckHeadersOnly)
Andrey Ponomarenko85043792012-05-14 16:48:07 +040011664 {
11665 if(my $Lang = $CompleteSignature{2}{$Symbol}{"Lang"})
11666 {
11667 if($Lang eq "C")
11668 { # support for old ABI dumps: missed extern "C" functions
11669 next;
11670 }
11671 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011672 }
Andrey Ponomarenko16934472012-03-29 15:37:04 +040011673 else
11674 {
11675 if(not link_symbol($Symbol, 2, "-Deps"))
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040011676 { # skip added inline symbols and const global data
Andrey Ponomarenko16934472012-03-29 15:37:04 +040011677 next;
11678 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011679 }
11680 }
11681 }
11682 }
11683 $AddedInt{$Level}{$Symbol} = 1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011684 }
11685 }
11686}
11687
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011688sub detectRemoved_H($)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011689{
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011690 my $Level = $_[0];
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011691 foreach my $Symbol (sort keys(%{$CompleteSignature{1}}))
11692 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011693 if($Level eq "Source")
11694 { # remove symbol version
11695 my ($SN, $SS, $SV) = separate_symbol($Symbol);
11696 $Symbol=$SN;
11697 }
Andrey Ponomarenko16934472012-03-29 15:37:04 +040011698 if(not $CompleteSignature{1}{$Symbol}{"Header"}
11699 or not $CompleteSignature{1}{$Symbol}{"MnglName"}) {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011700 next;
11701 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040011702 if($ExtendedSymbols{$Symbol}) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011703 next;
11704 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011705 if(not defined $CompleteSignature{2}{$Symbol}
11706 or not $CompleteSignature{2}{$Symbol}{"MnglName"})
Andrey Ponomarenko85043792012-05-14 16:48:07 +040011707 {
Andrey Ponomarenko16934472012-03-29 15:37:04 +040011708 if($UsedDump{1}{"SrcBin"})
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011709 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040011710 if($UsedDump{2}{"BinOnly"} or not checkDump(2, "2.11"))
Andrey Ponomarenko85043792012-05-14 16:48:07 +040011711 { # support for old and different (!) ABI dumps
Andrey Ponomarenko16934472012-03-29 15:37:04 +040011712 if(not $CompleteSignature{1}{$Symbol}{"Virt"}
11713 and not $CompleteSignature{1}{$Symbol}{"PureVirt"})
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011714 {
Andrey Ponomarenko16934472012-03-29 15:37:04 +040011715 if($CheckHeadersOnly)
11716 { # skip all removed symbols
Andrey Ponomarenko85043792012-05-14 16:48:07 +040011717 if(my $Lang = $CompleteSignature{1}{$Symbol}{"Lang"})
11718 {
11719 if($Lang eq "C")
11720 { # support for old ABI dumps: missed extern "C" functions
11721 next;
11722 }
11723 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011724 }
Andrey Ponomarenko16934472012-03-29 15:37:04 +040011725 else
11726 {
11727 if(not link_symbol($Symbol, 1, "-Deps"))
11728 { # skip removed inline symbols
11729 next;
11730 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011731 }
11732 }
11733 }
11734 }
Andrey Ponomarenkob8d203d2012-05-25 18:11:07 +040011735 if(not checkDump(1, "2.15"))
11736 {
11737 if($Symbol=~/_IT_E\Z/)
11738 { # _ZN28QExplicitlySharedDataPointerI22QSslCertificatePrivateEC1IT_EERKS_IT_E
11739 next;
11740 }
11741 }
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040011742 if(not $CompleteSignature{1}{$Symbol}{"Class"})
11743 {
11744 if(my $Short = $CompleteSignature{1}{$Symbol}{"ShortName"})
11745 {
11746 if(defined $Constants{2}{$Short})
11747 {
11748 my $Val = $Constants{2}{$Short}{"Value"};
11749 if(defined $Func_ShortName{2}{$Val})
11750 { # old name defined to new
11751 next;
11752 }
11753 }
11754 }
11755
11756 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011757 $RemovedInt{$Level}{$Symbol} = 1;
11758 if($Level eq "Source")
11759 { # search for a source-compatible equivalent
11760 setAlternative($Symbol, $Level);
11761 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011762 }
11763 }
11764}
11765
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011766sub mergeHeaders($)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011767{
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011768 my $Level = $_[0];
11769 foreach my $Symbol (sort keys(%{$AddedInt{$Level}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011770 { # checking added symbols
11771 next if($CompleteSignature{2}{$Symbol}{"PureVirt"});
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040011772 next if($CompleteSignature{2}{$Symbol}{"Private"});
11773 next if(not symbolFilter($Symbol, 2, "Affected", $Level));
Andrey Ponomarenko85043792012-05-14 16:48:07 +040011774 if($Level eq "Binary")
11775 {
11776 if($CompleteSignature{2}{$Symbol}{"InLine"})
11777 {
11778 if(not $CompleteSignature{2}{$Symbol}{"Virt"})
11779 { # skip inline non-virtual functions
11780 next;
11781 }
11782 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011783 }
11784 else
11785 { # Source
11786 if($SourceAlternative_B{$Symbol}) {
11787 next;
11788 }
11789 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011790 %{$CompatProblems{$Level}{$Symbol}{"Added_Symbol"}{""}}=();
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011791 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011792 foreach my $Symbol (sort keys(%{$RemovedInt{$Level}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011793 { # checking removed symbols
11794 next if($CompleteSignature{1}{$Symbol}{"PureVirt"});
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040011795 next if($CompleteSignature{1}{$Symbol}{"Private"});
11796 next if(not symbolFilter($Symbol, 1, "Affected", $Level));
Andrey Ponomarenko85043792012-05-14 16:48:07 +040011797 if($Level eq "Binary")
11798 {
11799 if($CompleteSignature{1}{$Symbol}{"InLine"})
11800 {
11801 if(not $CompleteSignature{1}{$Symbol}{"Virt"})
11802 { # skip inline non-virtual functions
11803 next;
11804 }
11805 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011806 }
11807 else
11808 { # Source
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040011809 if(my $Alt = $SourceAlternative{$Symbol})
11810 {
11811 if(defined $CompleteSignature{1}{$Alt}
11812 and $CompleteSignature{1}{$Symbol}{"Const"})
11813 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040011814 my $Cid = $CompleteSignature{1}{$Symbol}{"Class"};
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040011815 %{$CompatProblems{$Level}{$Symbol}{"Removed_Const_Overload"}{$tr_name{$Symbol}}}=(
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040011816 "Type_Name"=>$TypeInfo{1}{$Cid}{"Name"},
Andrey Ponomarenko85043792012-05-14 16:48:07 +040011817 "Type_Type"=>"Class",
11818 "Target"=>get_Signature($Alt, 1) );
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040011819 }
11820 else
11821 { # do NOT show removed symbol
11822 next;
11823 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011824 }
11825 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011826 %{$CompatProblems{$Level}{$Symbol}{"Removed_Symbol"}{""}}=();
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011827 }
11828}
11829
11830sub addParamNames($)
11831{
11832 my $LibraryVersion = $_[0];
11833 return if(not keys(%AddIntParams));
11834 my $SecondVersion = $LibraryVersion==1?2:1;
11835 foreach my $Interface (sort keys(%{$CompleteSignature{$LibraryVersion}}))
11836 {
11837 next if(not keys(%{$AddIntParams{$Interface}}));
11838 foreach my $ParamPos (sort {int($a)<=>int($b)} keys(%{$CompleteSignature{$LibraryVersion}{$Interface}{"Param"}}))
Andrey Ponomarenko85043792012-05-14 16:48:07 +040011839 { # add absent parameter names
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011840 my $ParamName = $CompleteSignature{$LibraryVersion}{$Interface}{"Param"}{$ParamPos}{"name"};
11841 if($ParamName=~/\Ap\d+\Z/ and my $NewParamName = $AddIntParams{$Interface}{$ParamPos})
Andrey Ponomarenko85043792012-05-14 16:48:07 +040011842 { # names from the external file
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011843 if(defined $CompleteSignature{$SecondVersion}{$Interface}
11844 and defined $CompleteSignature{$SecondVersion}{$Interface}{"Param"}{$ParamPos})
11845 {
11846 if($CompleteSignature{$SecondVersion}{$Interface}{"Param"}{$ParamPos}{"name"}=~/\Ap\d+\Z/) {
11847 $CompleteSignature{$LibraryVersion}{$Interface}{"Param"}{$ParamPos}{"name"} = $NewParamName;
11848 }
11849 }
11850 else {
11851 $CompleteSignature{$LibraryVersion}{$Interface}{"Param"}{$ParamPos}{"name"} = $NewParamName;
11852 }
11853 }
11854 }
11855 }
11856}
11857
11858sub detectChangedTypedefs()
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +040011859{ # detect changed typedefs to show
11860 # correct function signatures
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011861 foreach my $Typedef (keys(%{$Typedef_BaseName{1}}))
11862 {
11863 next if(not $Typedef);
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +040011864 my $BName1 = $Typedef_BaseName{1}{$Typedef};
11865 if(not $BName1 or isAnon($BName1)) {
11866 next;
11867 }
11868 my $BName2 = $Typedef_BaseName{2}{$Typedef};
11869 if(not $BName2 or isAnon($BName2)) {
11870 next;
11871 }
11872 if($BName1 ne $BName2) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011873 $ChangedTypedef{$Typedef} = 1;
11874 }
11875 }
11876}
11877
11878sub get_symbol_suffix($$)
11879{
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011880 my ($Symbol, $Full) = @_;
11881 my ($SN, $SO, $SV) = separate_symbol($Symbol);
11882 $Symbol=$SN;# remove version
11883 my $Signature = $tr_name{$Symbol};
Andrey Ponomarenko16934472012-03-29 15:37:04 +040011884 my $Suffix = substr($Signature, find_center($Signature, "("));
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011885 if(not $Full) {
11886 $Suffix=~s/(\))\s*(const volatile|volatile const|const|volatile)\Z/$1/g;
11887 }
11888 return $Suffix;
11889}
11890
11891sub get_symbol_prefix($$)
11892{
11893 my ($Symbol, $LibVersion) = @_;
11894 my $ShortName = $CompleteSignature{$LibVersion}{$Symbol}{"ShortName"};
11895 if(my $ClassId = $CompleteSignature{$LibVersion}{$Symbol}{"Class"})
11896 { # methods
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040011897 $ShortName = $TypeInfo{$LibVersion}{$ClassId}{"Name"}."::".$ShortName;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011898 }
11899 return $ShortName;
11900}
11901
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011902sub setAlternative($)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011903{
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011904 my $Symbol = $_[0];
11905 my $PSymbol = $Symbol;
11906 if(not defined $CompleteSignature{2}{$PSymbol}
11907 or (not $CompleteSignature{2}{$PSymbol}{"MnglName"}
11908 and not $CompleteSignature{2}{$PSymbol}{"ShortName"}))
11909 { # search for a pair
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040011910 if(my $ShortName = $CompleteSignature{1}{$PSymbol}{"ShortName"})
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011911 {
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040011912 if($CompleteSignature{1}{$PSymbol}{"Data"})
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011913 {
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040011914 if($PSymbol=~s/L(\d+$ShortName(E)\Z)/$1/
11915 or $PSymbol=~s/(\d+$ShortName(E)\Z)/L$1/)
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011916 {
11917 if(defined $CompleteSignature{2}{$PSymbol}
11918 and $CompleteSignature{2}{$PSymbol}{"MnglName"})
11919 {
11920 $SourceAlternative{$Symbol} = $PSymbol;
11921 $SourceAlternative_B{$PSymbol} = $Symbol;
11922 if(not defined $CompleteSignature{1}{$PSymbol}
11923 or not $CompleteSignature{1}{$PSymbol}{"MnglName"}) {
11924 $SourceReplacement{$Symbol} = $PSymbol;
11925 }
11926 }
11927 }
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040011928 }
11929 else
11930 {
11931 foreach my $Sp ("KV", "VK", "K", "V")
11932 {
11933 if($PSymbol=~s/\A_ZN$Sp/_ZN/
11934 or $PSymbol=~s/\A_ZN/_ZN$Sp/)
11935 {
11936 if(defined $CompleteSignature{2}{$PSymbol}
11937 and $CompleteSignature{2}{$PSymbol}{"MnglName"})
11938 {
11939 $SourceAlternative{$Symbol} = $PSymbol;
11940 $SourceAlternative_B{$PSymbol} = $Symbol;
11941 if(not defined $CompleteSignature{1}{$PSymbol}
11942 or not $CompleteSignature{1}{$PSymbol}{"MnglName"}) {
11943 $SourceReplacement{$Symbol} = $PSymbol;
11944 }
11945 }
11946 }
11947 $PSymbol = $Symbol;
11948 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011949 }
11950 }
11951 }
11952 return "";
11953}
11954
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040011955sub getSymKind($$)
11956{
11957 my ($Symbol, $LibVersion) = @_;
11958 if($CompleteSignature{$LibVersion}{$Symbol}{"Data"})
11959 {
11960 return "Global_Data";
11961 }
11962 elsif($CompleteSignature{$LibVersion}{$Symbol}{"Class"})
11963 {
11964 return "Method";
11965 }
11966 return "Function";
11967}
11968
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011969sub mergeSignatures($)
11970{
11971 my $Level = $_[0];
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011972 my %SubProblems = ();
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011973
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011974 mergeBases($Level);
11975
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011976 my %AddedOverloads = ();
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011977 foreach my $Symbol (sort keys(%{$AddedInt{$Level}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011978 { # check all added exported symbols
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011979 if(not $CompleteSignature{2}{$Symbol}{"Header"}) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011980 next;
11981 }
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040011982 if(defined $CompleteSignature{1}{$Symbol}
11983 and $CompleteSignature{1}{$Symbol}{"Header"})
11984 { # double-check added symbol
11985 next;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011986 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +040011987 if(not symbolFilter($Symbol, 2, "Affected", $Level)) {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011988 next;
11989 }
11990 if($Symbol=~/\A(_Z|\?)/)
11991 { # C++
11992 $AddedOverloads{get_symbol_prefix($Symbol, 2)}{get_symbol_suffix($Symbol, 1)} = $Symbol;
11993 }
11994 if(my $OverriddenMethod = $CompleteSignature{2}{$Symbol}{"Override"})
11995 { # register virtual overridings
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040011996 my $Cid = $CompleteSignature{2}{$Symbol}{"Class"};
11997 my $AffectedClass_Name = $TypeInfo{2}{$Cid}{"Name"};
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040011998 if(defined $CompleteSignature{1}{$OverriddenMethod} and $CompleteSignature{1}{$OverriddenMethod}{"Virt"}
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011999 and not $CompleteSignature{1}{$OverriddenMethod}{"Private"})
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040012000 {
12001 if($TName_Tid{1}{$AffectedClass_Name})
12002 { # class should exist in previous version
12003 if(not isCopyingClass($TName_Tid{1}{$AffectedClass_Name}, 1))
12004 { # old v-table is NOT copied by old applications
12005 %{$CompatProblems{$Level}{$OverriddenMethod}{"Overridden_Virtual_Method"}{$tr_name{$Symbol}}}=(
12006 "Type_Name"=>$AffectedClass_Name,
12007 "Type_Type"=>"Class",
12008 "Target"=>get_Signature($Symbol, 2),
12009 "Old_Value"=>get_Signature($OverriddenMethod, 2),
12010 "New_Value"=>get_Signature($Symbol, 2) );
12011 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012012 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012013 }
12014 }
12015 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012016 foreach my $Symbol (sort keys(%{$RemovedInt{$Level}}))
12017 { # check all removed exported symbols
12018 if(not $CompleteSignature{1}{$Symbol}{"Header"}) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012019 next;
12020 }
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040012021 if(defined $CompleteSignature{2}{$Symbol}
12022 and $CompleteSignature{2}{$Symbol}{"Header"})
12023 { # double-check removed symbol
12024 next;
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012025 }
12026 if($CompleteSignature{1}{$Symbol}{"Private"})
12027 { # skip private methods
12028 next;
12029 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +040012030 if(not symbolFilter($Symbol, 1, "Affected", $Level)) {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012031 next;
12032 }
12033 $CheckedSymbols{$Level}{$Symbol} = 1;
12034 if(my $OverriddenMethod = $CompleteSignature{1}{$Symbol}{"Override"})
12035 { # register virtual overridings
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040012036 my $Cid = $CompleteSignature{1}{$Symbol}{"Class"};
12037 my $AffectedClass_Name = $TypeInfo{1}{$Cid}{"Name"};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012038 if(defined $CompleteSignature{2}{$OverriddenMethod}
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040012039 and $CompleteSignature{2}{$OverriddenMethod}{"Virt"})
12040 {
12041 if($TName_Tid{2}{$AffectedClass_Name})
12042 { # class should exist in newer version
12043 if(not isCopyingClass($CompleteSignature{1}{$Symbol}{"Class"}, 1))
12044 { # old v-table is NOT copied by old applications
12045 %{$CompatProblems{$Level}{$Symbol}{"Overridden_Virtual_Method_B"}{$tr_name{$OverriddenMethod}}}=(
12046 "Type_Name"=>$AffectedClass_Name,
12047 "Type_Type"=>"Class",
12048 "Target"=>get_Signature($OverriddenMethod, 1),
12049 "Old_Value"=>get_Signature($Symbol, 1),
12050 "New_Value"=>get_Signature($OverriddenMethod, 1) );
12051 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012052 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012053 }
12054 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012055 if($Level eq "Binary"
12056 and $OSgroup eq "windows")
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012057 { # register the reason of symbol name change
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040012058 if(my $NewSym = $mangled_name{2}{$tr_name{$Symbol}})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012059 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040012060 if($AddedInt{$Level}{$NewSym})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012061 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040012062 if($CompleteSignature{1}{$Symbol}{"Static"} ne $CompleteSignature{2}{$NewSym}{"Static"})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012063 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040012064 if($CompleteSignature{2}{$NewSym}{"Static"})
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012065 {
12066 %{$CompatProblems{$Level}{$Symbol}{"Symbol_Became_Static"}{$tr_name{$Symbol}}}=(
12067 "Target"=>$tr_name{$Symbol},
12068 "Old_Value"=>$Symbol,
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040012069 "New_Value"=>$NewSym );
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012070 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012071 else
12072 {
12073 %{$CompatProblems{$Level}{$Symbol}{"Symbol_Became_NonStatic"}{$tr_name{$Symbol}}}=(
12074 "Target"=>$tr_name{$Symbol},
12075 "Old_Value"=>$Symbol,
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040012076 "New_Value"=>$NewSym );
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012077 }
12078 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040012079 if($CompleteSignature{1}{$Symbol}{"Virt"} ne $CompleteSignature{2}{$NewSym}{"Virt"})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012080 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040012081 if($CompleteSignature{2}{$NewSym}{"Virt"})
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012082 {
12083 %{$CompatProblems{$Level}{$Symbol}{"Symbol_Became_Virtual"}{$tr_name{$Symbol}}}=(
12084 "Target"=>$tr_name{$Symbol},
12085 "Old_Value"=>$Symbol,
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040012086 "New_Value"=>$NewSym );
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012087 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012088 else
12089 {
12090 %{$CompatProblems{$Level}{$Symbol}{"Symbol_Became_NonVirtual"}{$tr_name{$Symbol}}}=(
12091 "Target"=>$tr_name{$Symbol},
12092 "Old_Value"=>$Symbol,
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040012093 "New_Value"=>$NewSym );
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012094 }
12095 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040012096 my $RTId1 = $CompleteSignature{1}{$Symbol}{"Return"};
12097 my $RTId2 = $CompleteSignature{2}{$NewSym}{"Return"};
12098 my $RTName1 = $TypeInfo{1}{$RTId1}{"Name"};
12099 my $RTName2 = $TypeInfo{2}{$RTId2}{"Name"};
12100 if($RTName1 ne $RTName2)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012101 {
12102 my $ProblemType = "Symbol_Changed_Return";
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012103 if($CompleteSignature{1}{$Symbol}{"Data"}) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012104 $ProblemType = "Global_Data_Symbol_Changed_Type";
12105 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012106 %{$CompatProblems{$Level}{$Symbol}{$ProblemType}{$tr_name{$Symbol}}}=(
12107 "Target"=>$tr_name{$Symbol},
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040012108 "Old_Type"=>$RTName1,
12109 "New_Type"=>$RTName2,
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012110 "Old_Value"=>$Symbol,
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040012111 "New_Value"=>$NewSym );
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012112 }
12113 }
12114 }
12115 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012116 if($Symbol=~/\A(_Z|\?)/)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012117 { # C++
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012118 my $Prefix = get_symbol_prefix($Symbol, 1);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012119 if(my @Overloads = sort keys(%{$AddedOverloads{$Prefix}})
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012120 and not $AddedOverloads{$Prefix}{get_symbol_suffix($Symbol, 1)})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012121 { # changed signature: params, "const"-qualifier
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040012122 my $NewSym = $AddedOverloads{$Prefix}{$Overloads[0]};
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012123 if($CompleteSignature{1}{$Symbol}{"Constructor"})
12124 {
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +040012125 if($Symbol=~/(C1E|C2E)/)
12126 {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012127 my $CtorType = $1;
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040012128 $NewSym=~s/(C1E|C2E)/$CtorType/g;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012129 }
12130 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012131 elsif($CompleteSignature{1}{$Symbol}{"Destructor"})
12132 {
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +040012133 if($Symbol=~/(D0E|D1E|D2E)/)
12134 {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012135 my $DtorType = $1;
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040012136 $NewSym=~s/(D0E|D1E|D2E)/$DtorType/g;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012137 }
12138 }
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040012139 my $NS1 = $CompleteSignature{1}{$Symbol}{"NameSpace"};
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040012140 my $NS2 = $CompleteSignature{2}{$NewSym}{"NameSpace"};
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040012141 if((not $NS1 and not $NS2) or ($NS1 and $NS2 and $NS1 eq $NS2))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012142 { # from the same class and namespace
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012143 if($CompleteSignature{1}{$Symbol}{"Const"}
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040012144 and not $CompleteSignature{2}{$NewSym}{"Const"})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012145 { # "const" to non-"const"
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040012146 %{$CompatProblems{$Level}{$Symbol}{"Method_Became_NonConst"}{$tr_name{$Symbol}}}=(
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040012147 "Type_Name"=>$TypeInfo{1}{$CompleteSignature{1}{$Symbol}{"Class"}}{"Name"},
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012148 "Target"=>$tr_name{$Symbol},
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040012149 "New_Signature"=>get_Signature($NewSym, 2),
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012150 "Old_Value"=>$Symbol,
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040012151 "New_Value"=>$NewSym );
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012152 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012153 elsif(not $CompleteSignature{1}{$Symbol}{"Const"}
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040012154 and $CompleteSignature{2}{$NewSym}{"Const"})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012155 { # non-"const" to "const"
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040012156 %{$CompatProblems{$Level}{$Symbol}{"Method_Became_Const"}{$tr_name{$Symbol}}}=(
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012157 "Target"=>$tr_name{$Symbol},
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040012158 "New_Signature"=>get_Signature($NewSym, 2),
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012159 "Old_Value"=>$Symbol,
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040012160 "New_Value"=>$NewSym );
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012161 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012162 if($CompleteSignature{1}{$Symbol}{"Volatile"}
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040012163 and not $CompleteSignature{2}{$NewSym}{"Volatile"})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012164 { # "volatile" to non-"volatile"
12165
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040012166 %{$CompatProblems{$Level}{$Symbol}{"Method_Became_NonVolatile"}{$tr_name{$Symbol}}}=(
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012167 "Target"=>$tr_name{$Symbol},
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040012168 "New_Signature"=>get_Signature($NewSym, 2),
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012169 "Old_Value"=>$Symbol,
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040012170 "New_Value"=>$NewSym );
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012171 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012172 elsif(not $CompleteSignature{1}{$Symbol}{"Volatile"}
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040012173 and $CompleteSignature{2}{$NewSym}{"Volatile"})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012174 { # non-"volatile" to "volatile"
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040012175 %{$CompatProblems{$Level}{$Symbol}{"Method_Became_Volatile"}{$tr_name{$Symbol}}}=(
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012176 "Target"=>$tr_name{$Symbol},
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040012177 "New_Signature"=>get_Signature($NewSym, 2),
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012178 "Old_Value"=>$Symbol,
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040012179 "New_Value"=>$NewSym );
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012180 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040012181 if(get_symbol_suffix($Symbol, 0) ne get_symbol_suffix($NewSym, 0))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012182 { # params list
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012183 %{$CompatProblems{$Level}{$Symbol}{"Symbol_Changed_Parameters"}{$tr_name{$Symbol}}}=(
12184 "Target"=>$tr_name{$Symbol},
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040012185 "New_Signature"=>get_Signature($NewSym, 2),
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012186 "Old_Value"=>$Symbol,
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040012187 "New_Value"=>$NewSym );
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012188 }
12189 }
12190 }
12191 }
12192 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012193 foreach my $Symbol (sort keys(%{$CompleteSignature{1}}))
12194 { # checking symbols
12195 my ($SN, $SS, $SV) = separate_symbol($Symbol);
12196 if($Level eq "Source")
12197 { # remove symbol version
12198 $Symbol=$SN;
12199 }
12200 else
12201 { # Binary
12202 if(not $SV)
12203 { # symbol without version
12204 if(my $VSym = $SymVer{1}{$Symbol})
12205 { # the symbol is linked with versioned symbol
12206 if($CompleteSignature{2}{$VSym}{"MnglName"})
12207 { # show report for symbol@ver only
12208 next;
12209 }
12210 elsif(not link_symbol($VSym, 2, "-Deps"))
12211 { # changed version: sym@v1 to sym@v2
12212 # do NOT show report for symbol
12213 next;
12214 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012215 }
12216 }
12217 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012218 my $PSymbol = $Symbol;
12219 if($Level eq "Source"
12220 and my $S = $SourceReplacement{$Symbol})
12221 { # take a source-compatible replacement function
12222 $PSymbol = $S;
12223 }
12224 if($CompleteSignature{1}{$Symbol}{"Private"})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012225 { # private symbols
12226 next;
12227 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012228 if(not defined $CompleteSignature{1}{$Symbol}
12229 or not defined $CompleteSignature{2}{$PSymbol})
12230 { # no info
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012231 next;
12232 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012233 if(not $CompleteSignature{1}{$Symbol}{"MnglName"}
12234 or not $CompleteSignature{2}{$PSymbol}{"MnglName"})
12235 { # no mangled name
12236 next;
12237 }
12238 if(not $CompleteSignature{1}{$Symbol}{"Header"}
12239 or not $CompleteSignature{2}{$PSymbol}{"Header"})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012240 { # without a header
12241 next;
12242 }
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040012243
12244 if(not $CompleteSignature{1}{$Symbol}{"PureVirt"}
12245 and $CompleteSignature{2}{$PSymbol}{"PureVirt"})
12246 { # became pure
12247 next;
12248 }
12249 if($CompleteSignature{1}{$Symbol}{"PureVirt"}
12250 and not $CompleteSignature{2}{$PSymbol}{"PureVirt"})
12251 { # became non-pure
12252 next;
12253 }
12254
12255 if(not symbolFilter($Symbol, 1, "Affected + InlineVirt", $Level))
12256 { # exported, target, inline virtual and pure virtual
12257 next;
12258 }
12259 if(not symbolFilter($PSymbol, 2, "Affected + InlineVirt", $Level))
12260 { # exported, target, inline virtual and pure virtual
12261 next;
12262 }
12263
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040012264 if(checkDump(1, "2.13") and checkDump(2, "2.13"))
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040012265 {
12266 if($CompleteSignature{1}{$Symbol}{"Data"}
12267 and $CompleteSignature{2}{$PSymbol}{"Data"})
12268 {
12269 my $Value1 = $CompleteSignature{1}{$Symbol}{"Value"};
12270 my $Value2 = $CompleteSignature{2}{$PSymbol}{"Value"};
12271 if(defined $Value1)
12272 {
12273 $Value1 = showVal($Value1, $CompleteSignature{1}{$Symbol}{"Return"}, 1);
12274 if(defined $Value2)
12275 {
12276 $Value2 = showVal($Value2, $CompleteSignature{2}{$PSymbol}{"Return"}, 2);
12277 if($Value1 ne $Value2)
12278 {
12279 %{$CompatProblems{$Level}{$Symbol}{"Global_Data_Value_Changed"}{""}}=(
12280 "Old_Value"=>$Value1,
12281 "New_Value"=>$Value2,
12282 "Target"=>get_Signature($Symbol, 1) );
12283 }
12284 }
12285 }
12286 }
12287 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +040012288
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040012289 if($CompleteSignature{2}{$PSymbol}{"Private"})
12290 {
12291 %{$CompatProblems{$Level}{$Symbol}{getSymKind($Symbol, 1)."_Became_Private"}{""}}=(
12292 "Target"=>get_Signature_M($PSymbol, 2) );
12293 }
12294 elsif(not $CompleteSignature{1}{$Symbol}{"Protected"}
12295 and $CompleteSignature{2}{$PSymbol}{"Protected"})
12296 {
12297 %{$CompatProblems{$Level}{$Symbol}{getSymKind($Symbol, 1)."_Became_Protected"}{""}}=(
12298 "Target"=>get_Signature_M($PSymbol, 2) );
12299 }
12300 elsif($CompleteSignature{1}{$Symbol}{"Protected"}
12301 and not $CompleteSignature{2}{$PSymbol}{"Protected"})
12302 {
12303 %{$CompatProblems{$Level}{$Symbol}{getSymKind($Symbol, 1)."_Became_Public"}{""}}=(
12304 "Target"=>get_Signature_M($PSymbol, 2) );
12305 }
12306
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012307 # checking virtual table
Andrey Ponomarenko16934472012-03-29 15:37:04 +040012308 mergeVirtualTables($Symbol, $Level);
12309
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012310 if($COMPILE_ERRORS)
12311 { # if some errors occurred at the compiling stage
12312 # then some false positives can be skipped here
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012313 if(not $CompleteSignature{1}{$Symbol}{"Data"} and $CompleteSignature{2}{$PSymbol}{"Data"}
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040012314 and not $GlobalDataObject{2}{$Symbol})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012315 { # missed information about parameters in newer version
12316 next;
12317 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040012318 if($CompleteSignature{1}{$Symbol}{"Data"} and not $GlobalDataObject{1}{$Symbol}
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012319 and not $CompleteSignature{2}{$PSymbol}{"Data"})
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040012320 { # missed information about parameters in older version
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012321 next;
12322 }
12323 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012324 my ($MnglName, $VersionSpec, $SymbolVersion) = separate_symbol($Symbol);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012325 # checking attributes
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012326 if($CompleteSignature{2}{$PSymbol}{"Static"}
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040012327 and not $CompleteSignature{1}{$Symbol}{"Static"} and $Symbol=~/\A(_Z|\?)/)
12328 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012329 %{$CompatProblems{$Level}{$Symbol}{"Method_Became_Static"}{""}}=(
12330 "Target"=>get_Signature($Symbol, 1)
12331 );
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012332 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012333 elsif(not $CompleteSignature{2}{$PSymbol}{"Static"}
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040012334 and $CompleteSignature{1}{$Symbol}{"Static"} and $Symbol=~/\A(_Z|\?)/)
12335 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012336 %{$CompatProblems{$Level}{$Symbol}{"Method_Became_NonStatic"}{""}}=(
12337 "Target"=>get_Signature($Symbol, 1)
12338 );
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012339 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012340 if(($CompleteSignature{1}{$Symbol}{"Virt"} and $CompleteSignature{2}{$PSymbol}{"Virt"})
12341 or ($CompleteSignature{1}{$Symbol}{"PureVirt"} and $CompleteSignature{2}{$PSymbol}{"PureVirt"}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012342 { # relative position of virtual and pure virtual methods
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012343 if($Level eq "Binary")
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012344 {
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040012345 if(defined $CompleteSignature{1}{$Symbol}{"RelPos"} and defined $CompleteSignature{2}{$PSymbol}{"RelPos"}
12346 and $CompleteSignature{1}{$Symbol}{"RelPos"}!=$CompleteSignature{2}{$PSymbol}{"RelPos"})
12347 { # top-level virtual methods only
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012348 my $Class_Id = $CompleteSignature{1}{$Symbol}{"Class"};
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040012349 my $Class_Name = $TypeInfo{1}{$Class_Id}{"Name"};
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040012350 if(defined $VirtualTable{1}{$Class_Name} and defined $VirtualTable{2}{$Class_Name}
12351 and $VirtualTable{1}{$Class_Name}{$Symbol}!=$VirtualTable{2}{$Class_Name}{$Symbol})
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012352 { # check the absolute position of virtual method (including added and removed methods)
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040012353 my %Class_Type = get_Type($Class_Id, 1);
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012354 my $ProblemType = "Virtual_Method_Position";
12355 if($CompleteSignature{1}{$Symbol}{"PureVirt"}) {
12356 $ProblemType = "Pure_Virtual_Method_Position";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012357 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012358 if(isUsedClass($Class_Id, 1, $Level))
12359 {
12360 my @Affected = ($Symbol, keys(%{$OverriddenMethods{1}{$Symbol}}));
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040012361 foreach my $ASymbol (@Affected)
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012362 {
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040012363 if(not symbolFilter($ASymbol, 1, "Affected", $Level)) {
12364 next;
12365 }
12366 %{$CompatProblems{$Level}{$ASymbol}{$ProblemType}{$tr_name{$MnglName}}}=(
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012367 "Type_Name"=>$Class_Type{"Name"},
12368 "Type_Type"=>"Class",
12369 "Old_Value"=>$CompleteSignature{1}{$Symbol}{"RelPos"},
12370 "New_Value"=>$CompleteSignature{2}{$PSymbol}{"RelPos"},
12371 "Target"=>get_Signature($Symbol, 1) );
12372 }
Andrey Ponomarenko16934472012-03-29 15:37:04 +040012373 $VTableChanged_M{$Class_Type{"Name"}} = 1;
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012374 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012375 }
12376 }
12377 }
12378 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012379 if($CompleteSignature{1}{$Symbol}{"PureVirt"}
12380 or $CompleteSignature{2}{$PSymbol}{"PureVirt"})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012381 { # do NOT check type changes in pure virtuals
12382 next;
12383 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012384 $CheckedSymbols{$Level}{$Symbol}=1;
12385 if($Symbol=~/\A(_Z|\?)/
12386 or keys(%{$CompleteSignature{1}{$Symbol}{"Param"}})==keys(%{$CompleteSignature{2}{$PSymbol}{"Param"}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012387 { # C/C++: changes in parameters
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012388 foreach my $ParamPos (sort {int($a) <=> int($b)} keys(%{$CompleteSignature{1}{$Symbol}{"Param"}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012389 { # checking parameters
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012390 mergeParameters($Symbol, $PSymbol, $ParamPos, $ParamPos, $Level);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012391 }
12392 }
12393 else
12394 { # C: added/removed parameters
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012395 foreach my $ParamPos (sort {int($a) <=> int($b)} keys(%{$CompleteSignature{2}{$PSymbol}{"Param"}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012396 { # checking added parameters
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040012397 my $PType2_Id = $CompleteSignature{2}{$PSymbol}{"Param"}{$ParamPos}{"type"};
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040012398 my $PType2_Name = $TypeInfo{2}{$PType2_Id}{"Name"};
12399 last if($PType2_Name eq "...");
12400 my $PName = $CompleteSignature{2}{$PSymbol}{"Param"}{$ParamPos}{"name"};
12401 my $PName_Old = (defined $CompleteSignature{1}{$Symbol}{"Param"}{$ParamPos})?$CompleteSignature{1}{$Symbol}{"Param"}{$ParamPos}{"name"}:"";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012402 my $ParamPos_Prev = "-1";
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040012403 if($PName=~/\Ap\d+\Z/i)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012404 { # added unnamed parameter ( pN )
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040012405 my @Positions1 = find_ParamPair_Pos_byTypeAndPos($PType2_Name, $ParamPos, "backward", $Symbol, 1);
12406 my @Positions2 = find_ParamPair_Pos_byTypeAndPos($PType2_Name, $ParamPos, "backward", $Symbol, 2);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012407 if($#Positions1==-1 or $#Positions2>$#Positions1) {
12408 $ParamPos_Prev = "lost";
12409 }
12410 }
12411 else {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040012412 $ParamPos_Prev = find_ParamPair_Pos_byName($PName, $Symbol, 1);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012413 }
12414 if($ParamPos_Prev eq "lost")
12415 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012416 if($ParamPos>keys(%{$CompleteSignature{1}{$Symbol}{"Param"}})-1)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012417 {
12418 my $ProblemType = "Added_Parameter";
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040012419 if($PName=~/\Ap\d+\Z/) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012420 $ProblemType = "Added_Unnamed_Parameter";
12421 }
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040012422 %{$CompatProblems{$Level}{$Symbol}{$ProblemType}{showPos($ParamPos)." Parameter"}}=(
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040012423 "Target"=>$PName,
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012424 "Param_Pos"=>$ParamPos,
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040012425 "Param_Type"=>$PType2_Name,
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012426 "New_Signature"=>get_Signature($Symbol, 2) );
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012427 }
12428 else
12429 {
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +040012430 my %ParamType_Pure = get_PureType($PType2_Id, $TypeInfo{2});
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040012431 my $PairType_Id = $CompleteSignature{1}{$Symbol}{"Param"}{$ParamPos}{"type"};
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +040012432 my %PairType_Pure = get_PureType($PairType_Id, $TypeInfo{1});
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040012433 if(($ParamType_Pure{"Name"} eq $PairType_Pure{"Name"} or $PType2_Name eq $TypeInfo{1}{$PairType_Id}{"Name"})
12434 and find_ParamPair_Pos_byName($PName_Old, $Symbol, 2) eq "lost")
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012435 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040012436 if($PName_Old!~/\Ap\d+\Z/ and $PName!~/\Ap\d+\Z/)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012437 {
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040012438 %{$CompatProblems{$Level}{$Symbol}{"Renamed_Parameter"}{showPos($ParamPos)." Parameter"}}=(
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040012439 "Target"=>$PName_Old,
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012440 "Param_Pos"=>$ParamPos,
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040012441 "Param_Type"=>$PType2_Name,
12442 "Old_Value"=>$PName_Old,
12443 "New_Value"=>$PName,
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012444 "New_Signature"=>get_Signature($Symbol, 2) );
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012445 }
12446 }
12447 else
12448 {
12449 my $ProblemType = "Added_Middle_Parameter";
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040012450 if($PName=~/\Ap\d+\Z/) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012451 $ProblemType = "Added_Middle_Unnamed_Parameter";
12452 }
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040012453 %{$CompatProblems{$Level}{$Symbol}{$ProblemType}{showPos($ParamPos)." Parameter"}}=(
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040012454 "Target"=>$PName,
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012455 "Param_Pos"=>$ParamPos,
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040012456 "Param_Type"=>$PType2_Name,
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012457 "New_Signature"=>get_Signature($Symbol, 2) );
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012458 }
12459 }
12460 }
12461 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012462 foreach my $ParamPos (sort {int($a) <=> int($b)} keys(%{$CompleteSignature{1}{$Symbol}{"Param"}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012463 { # check relevant parameters
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040012464 my $PType1_Id = $CompleteSignature{1}{$Symbol}{"Param"}{$ParamPos}{"type"};
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012465 my $ParamName1 = $CompleteSignature{1}{$Symbol}{"Param"}{$ParamPos}{"name"};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012466 # FIXME: find relevant parameter by name
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012467 if(defined $CompleteSignature{2}{$PSymbol}{"Param"}{$ParamPos})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012468 {
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040012469 my $PType2_Id = $CompleteSignature{2}{$PSymbol}{"Param"}{$ParamPos}{"type"};
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012470 my $ParamName2 = $CompleteSignature{2}{$PSymbol}{"Param"}{$ParamPos}{"name"};
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040012471 if($TypeInfo{1}{$PType1_Id}{"Name"} eq $TypeInfo{2}{$PType2_Id}{"Name"}
12472 or ($ParamName1!~/\Ap\d+\Z/i and $ParamName1 eq $ParamName2)) {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012473 mergeParameters($Symbol, $PSymbol, $ParamPos, $ParamPos, $Level);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012474 }
12475 }
12476 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012477 foreach my $ParamPos (sort {int($a) <=> int($b)} keys(%{$CompleteSignature{1}{$Symbol}{"Param"}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012478 { # checking removed parameters
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040012479 my $PType1_Id = $CompleteSignature{1}{$Symbol}{"Param"}{$ParamPos}{"type"};
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040012480 my $PType1_Name = $TypeInfo{1}{$PType1_Id}{"Name"};
12481 last if($PType1_Name eq "...");
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012482 my $Parameter_Name = $CompleteSignature{1}{$Symbol}{"Param"}{$ParamPos}{"name"};
12483 my $Parameter_NewName = (defined $CompleteSignature{2}{$PSymbol}{"Param"}{$ParamPos})?$CompleteSignature{2}{$PSymbol}{"Param"}{$ParamPos}{"name"}:"";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012484 my $ParamPos_New = "-1";
12485 if($Parameter_Name=~/\Ap\d+\Z/i)
12486 { # removed unnamed parameter ( pN )
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040012487 my @Positions1 = find_ParamPair_Pos_byTypeAndPos($PType1_Name, $ParamPos, "forward", $Symbol, 1);
12488 my @Positions2 = find_ParamPair_Pos_byTypeAndPos($PType1_Name, $ParamPos, "forward", $Symbol, 2);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012489 if($#Positions2==-1 or $#Positions2<$#Positions1) {
12490 $ParamPos_New = "lost";
12491 }
12492 }
12493 else {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012494 $ParamPos_New = find_ParamPair_Pos_byName($Parameter_Name, $Symbol, 2);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012495 }
12496 if($ParamPos_New eq "lost")
12497 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012498 if($ParamPos>keys(%{$CompleteSignature{2}{$PSymbol}{"Param"}})-1)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012499 {
12500 my $ProblemType = "Removed_Parameter";
12501 if($Parameter_Name=~/\Ap\d+\Z/) {
12502 $ProblemType = "Removed_Unnamed_Parameter";
12503 }
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040012504 %{$CompatProblems{$Level}{$Symbol}{$ProblemType}{showPos($ParamPos)." Parameter"}}=(
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012505 "Target"=>$Parameter_Name,
12506 "Param_Pos"=>$ParamPos,
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040012507 "Param_Type"=>$PType1_Name,
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012508 "New_Signature"=>get_Signature($Symbol, 2) );
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012509 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012510 elsif($ParamPos<keys(%{$CompleteSignature{1}{$Symbol}{"Param"}})-1)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012511 {
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +040012512 my %ParamType_Pure = get_PureType($PType1_Id, $TypeInfo{1});
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040012513 my $PairType_Id = $CompleteSignature{2}{$PSymbol}{"Param"}{$ParamPos}{"type"};
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +040012514 my %PairType_Pure = get_PureType($PairType_Id, $TypeInfo{2});
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040012515 if(($ParamType_Pure{"Name"} eq $PairType_Pure{"Name"} or $PType1_Name eq $TypeInfo{2}{$PairType_Id}{"Name"})
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012516 and find_ParamPair_Pos_byName($Parameter_NewName, $Symbol, 1) eq "lost")
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012517 {
12518 if($Parameter_NewName!~/\Ap\d+\Z/ and $Parameter_Name!~/\Ap\d+\Z/)
12519 {
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040012520 %{$CompatProblems{$Level}{$Symbol}{"Renamed_Parameter"}{showPos($ParamPos)." Parameter"}}=(
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012521 "Target"=>$Parameter_Name,
12522 "Param_Pos"=>$ParamPos,
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040012523 "Param_Type"=>$PType1_Name,
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012524 "Old_Value"=>$Parameter_Name,
12525 "New_Value"=>$Parameter_NewName,
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012526 "New_Signature"=>get_Signature($Symbol, 2) );
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012527 }
12528 }
12529 else
12530 {
12531 my $ProblemType = "Removed_Middle_Parameter";
12532 if($Parameter_Name=~/\Ap\d+\Z/) {
12533 $ProblemType = "Removed_Middle_Unnamed_Parameter";
12534 }
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040012535 %{$CompatProblems{$Level}{$Symbol}{$ProblemType}{showPos($ParamPos)." Parameter"}}=(
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012536 "Target"=>$Parameter_Name,
12537 "Param_Pos"=>$ParamPos,
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040012538 "Param_Type"=>$PType1_Name,
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012539 "New_Signature"=>get_Signature($Symbol, 2) );
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012540 }
12541 }
12542 }
12543 }
12544 }
12545 # checking return type
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012546 my $ReturnType1_Id = $CompleteSignature{1}{$Symbol}{"Return"};
12547 my $ReturnType2_Id = $CompleteSignature{2}{$PSymbol}{"Return"};
12548 %SubProblems = detectTypeChange($ReturnType1_Id, $ReturnType2_Id, "Return", $Level);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012549 foreach my $SubProblemType (keys(%SubProblems))
12550 {
12551 my $New_Value = $SubProblems{$SubProblemType}{"New_Value"};
12552 my $Old_Value = $SubProblems{$SubProblemType}{"Old_Value"};
12553 my $NewProblemType = $SubProblemType;
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040012554 my $AddProblemType = undef;
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +040012555
12556 if($SubProblemType eq "Return_Type_And_Size"
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012557 and $CompleteSignature{1}{$Symbol}{"Data"}) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012558 $NewProblemType = "Global_Data_Type_And_Size";
12559 }
12560 elsif($SubProblemType eq "Return_Type")
12561 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012562 if($CompleteSignature{1}{$Symbol}{"Data"})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012563 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012564 if(removedQual($Old_Value, $New_Value, "const"))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012565 { # const -> non-const global data
12566 $NewProblemType = "Global_Data_Became_Non_Const";
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040012567 $AddProblemType = "Global_Data_Type";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012568 }
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040012569 elsif(addedQual($Old_Value, $New_Value, "const"))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012570 { # non-const -> const global data
12571 $NewProblemType = "Global_Data_Became_Const";
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040012572 $AddProblemType = "Global_Data_Type";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012573 }
12574 else {
12575 $NewProblemType = "Global_Data_Type";
12576 }
12577 }
12578 else
12579 {
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040012580 if(addedQual($Old_Value, $New_Value, "const"))
12581 {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012582 $NewProblemType = "Return_Type_Became_Const";
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040012583 $AddProblemType = "Return_Type";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012584 }
12585 }
12586 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012587 elsif($SubProblemType eq "Return_Type_Format")
12588 {
12589 if($CompleteSignature{1}{$Symbol}{"Data"}) {
12590 $NewProblemType = "Global_Data_Type_Format";
12591 }
12592 }
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +040012593 if($Level eq "Binary"
12594 and not $CompleteSignature{1}{$Symbol}{"Data"})
12595 {
12596 my ($Arch1, $Arch2) = (getArch(1), getArch(2));
12597 if($Arch1 eq "unknown" or $Arch2 eq "unknown")
12598 { # if one of the architectures is unknown
12599 # then set other arhitecture to unknown too
12600 ($Arch1, $Arch2) = ("unknown", "unknown");
12601 }
12602 my (%Conv1, %Conv2) = ();
12603 if($UseConv_Real{1} and $UseConv_Real{1})
12604 {
12605 %Conv1 = callingConvention_R_Real($CompleteSignature{1}{$Symbol});
12606 %Conv2 = callingConvention_R_Real($CompleteSignature{2}{$PSymbol});
12607 }
12608 else
12609 {
12610 %Conv1 = callingConvention_R_Model($CompleteSignature{1}{$Symbol}, $TypeInfo{1}, $Arch1, $OStarget, $WORD_SIZE{1});
12611 %Conv2 = callingConvention_R_Model($CompleteSignature{2}{$PSymbol}, $TypeInfo{2}, $Arch2, $OStarget, $WORD_SIZE{2});
12612 }
12613
12614 if($SubProblemType eq "Return_Type_Became_Void")
12615 {
12616 if(keys(%{$CompleteSignature{1}{$Symbol}{"Param"}}))
12617 { # parameters stack has been affected
12618 if($Conv1{"Method"} eq "stack") {
12619 $NewProblemType = "Return_Type_Became_Void_And_Stack_Layout";
12620 }
12621 elsif($Conv1{"Hidden"}) {
12622 $NewProblemType = "Return_Type_Became_Void_And_Register";
12623 }
12624 }
12625 }
12626 elsif($SubProblemType eq "Return_Type_From_Void")
12627 {
12628 if(keys(%{$CompleteSignature{1}{$Symbol}{"Param"}}))
12629 { # parameters stack has been affected
12630 if($Conv2{"Method"} eq "stack") {
12631 $NewProblemType = "Return_Type_From_Void_And_Stack_Layout";
12632 }
12633 elsif($Conv2{"Hidden"}) {
12634 $NewProblemType = "Return_Type_From_Void_And_Register";
12635 }
12636 }
12637 }
12638 elsif($SubProblemType eq "Return_Type"
12639 or $SubProblemType eq "Return_Type_And_Size"
12640 or $SubProblemType eq "Return_Type_Format")
12641 {
12642 if($Conv1{"Method"} ne $Conv2{"Method"})
12643 {
12644 if($Conv1{"Method"} eq "stack")
12645 { # returns in a register instead of a hidden first parameter
12646 $NewProblemType = "Return_Type_From_Stack_To_Register";
12647 }
12648 else {
12649 $NewProblemType = "Return_Type_From_Register_To_Stack";
12650 }
12651 }
12652 else
12653 {
12654 if($Conv1{"Method"} eq "reg")
12655 {
12656 if($Conv1{"Registers"} ne $Conv2{"Registers"})
12657 {
12658 if($Conv1{"Hidden"}) {
12659 $NewProblemType = "Return_Type_And_Register_Was_Hidden_Parameter";
12660 }
12661 elsif($Conv2{"Hidden"}) {
12662 $NewProblemType = "Return_Type_And_Register_Became_Hidden_Parameter";
12663 }
12664 else {
12665 $NewProblemType = "Return_Type_And_Register";
12666 }
12667 }
12668 }
12669 }
12670 }
12671 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012672 @{$CompatProblems{$Level}{$Symbol}{$NewProblemType}{"retval"}}{keys(%{$SubProblems{$SubProblemType}})} = values %{$SubProblems{$SubProblemType}};
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040012673 if(defined $AddProblemType) {
12674 @{$CompatProblems{$Level}{$Symbol}{$AddProblemType}{"retval"}}{keys(%{$SubProblems{$SubProblemType}})} = values %{$SubProblems{$SubProblemType}};
12675 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012676 }
12677 if($ReturnType1_Id and $ReturnType2_Id)
12678 {
12679 @RecurTypes = ();
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040012680 %SubProblems = mergeTypes($ReturnType1_Id, $ReturnType2_Id, $Level);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012681 foreach my $SubProblemType (keys(%SubProblems))
12682 { # add "Global_Data_Size" problem
12683 my $New_Value = $SubProblems{$SubProblemType}{"New_Value"};
12684 my $Old_Value = $SubProblems{$SubProblemType}{"Old_Value"};
12685 if($SubProblemType eq "DataType_Size"
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012686 and $CompleteSignature{1}{$Symbol}{"Data"}
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040012687 and get_PLevel($ReturnType1_Id, 1)==0)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012688 { # add a new problem
12689 %{$SubProblems{"Global_Data_Size"}} = %{$SubProblems{$SubProblemType}};
12690 }
12691 }
12692 foreach my $SubProblemType (keys(%SubProblems))
12693 {
12694 foreach my $SubLocation (keys(%{$SubProblems{$SubProblemType}}))
12695 {
12696 my $NewLocation = ($SubLocation)?"retval->".$SubLocation:"retval";
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012697 %{$CompatProblems{$Level}{$Symbol}{$SubProblemType}{$NewLocation}}=(
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040012698 "Return_Type_Name"=>$TypeInfo{1}{$ReturnType1_Id}{"Name"} );
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012699 @{$CompatProblems{$Level}{$Symbol}{$SubProblemType}{$NewLocation}}{keys(%{$SubProblems{$SubProblemType}{$SubLocation}})} = values %{$SubProblems{$SubProblemType}{$SubLocation}};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012700 if($SubLocation!~/\-\>/) {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040012701 $CompatProblems{$Level}{$Symbol}{$SubProblemType}{$NewLocation}{"Start_Type_Name"} = $TypeInfo{1}{$ReturnType1_Id}{"Name"};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012702 }
12703 }
12704 }
12705 }
12706
12707 # checking object type
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040012708 my $ObjTId1 = $CompleteSignature{1}{$Symbol}{"Class"};
12709 my $ObjTId2 = $CompleteSignature{2}{$PSymbol}{"Class"};
12710 if($ObjTId1 and $ObjTId2
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012711 and not $CompleteSignature{1}{$Symbol}{"Static"})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012712 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040012713 my $ThisPtr1_Id = getTypeIdByName($TypeInfo{1}{$ObjTId1}{"Name"}."*const", 1);
12714 my $ThisPtr2_Id = getTypeIdByName($TypeInfo{2}{$ObjTId2}{"Name"}."*const", 2);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012715 if($ThisPtr1_Id and $ThisPtr2_Id)
12716 {
12717 @RecurTypes = ();
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040012718 %SubProblems = mergeTypes($ThisPtr1_Id, $ThisPtr2_Id, $Level);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012719 foreach my $SubProblemType (keys(%SubProblems))
12720 {
12721 foreach my $SubLocation (keys(%{$SubProblems{$SubProblemType}}))
12722 {
12723 my $NewLocation = ($SubLocation)?"this->".$SubLocation:"this";
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012724 %{$CompatProblems{$Level}{$Symbol}{$SubProblemType}{$NewLocation}}=(
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040012725 "Object_Type_Name"=>$TypeInfo{1}{$ObjTId1}{"Name"} );
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012726 @{$CompatProblems{$Level}{$Symbol}{$SubProblemType}{$NewLocation}}{keys(%{$SubProblems{$SubProblemType}{$SubLocation}})} = values %{$SubProblems{$SubProblemType}{$SubLocation}};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012727 if($SubLocation!~/\-\>/) {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040012728 $CompatProblems{$Level}{$Symbol}{$SubProblemType}{$NewLocation}{"Start_Type_Name"} = $TypeInfo{1}{$ObjTId1}{"Name"};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012729 }
12730 }
12731 }
12732 }
12733 }
12734 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012735 if($Level eq "Binary") {
12736 mergeVTables($Level);
12737 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +040012738 foreach my $Symbol (keys(%{$CompatProblems{$Level}})) {
12739 $CheckedSymbols{$Level}{$Symbol} = 1;
12740 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012741}
12742
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040012743sub rmQuals($$)
12744{
12745 my ($Value, $Qual) = @_;
12746 if(not $Qual) {
12747 return $Value;
12748 }
12749 if($Qual eq "all")
12750 { # all quals
12751 $Qual = "const|volatile|restrict";
12752 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040012753 while($Value=~s/\b$Qual\b//) {
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040012754 $Value = formatName($Value, "T");
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040012755 }
12756 return $Value;
12757}
12758
12759sub cmpBTypes($$$$)
12760{
12761 my ($T1, $T2, $V1, $V2) = @_;
12762 $T1 = uncover_typedefs($T1, $V1);
12763 $T2 = uncover_typedefs($T2, $V2);
12764 return (rmQuals($T1, "all") eq rmQuals($T2, "all"));
12765}
12766
12767sub addedQual($$$)
12768{
12769 my ($Old_Value, $New_Value, $Qual) = @_;
Andrey Ponomarenko85043792012-05-14 16:48:07 +040012770 return removedQual_($New_Value, $Old_Value, 2, 1, $Qual);
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040012771}
12772
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012773sub removedQual($$$)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012774{
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012775 my ($Old_Value, $New_Value, $Qual) = @_;
Andrey Ponomarenko85043792012-05-14 16:48:07 +040012776 return removedQual_($Old_Value, $New_Value, 1, 2, $Qual);
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040012777}
12778
12779sub removedQual_($$$$$)
12780{
12781 my ($Old_Value, $New_Value, $V1, $V2, $Qual) = @_;
12782 $Old_Value = uncover_typedefs($Old_Value, $V1);
12783 $New_Value = uncover_typedefs($New_Value, $V2);
12784 if($Old_Value eq $New_Value)
12785 { # equal types
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012786 return 0;
12787 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040012788 if($Old_Value!~/\b$Qual\b/)
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040012789 { # without a qual
12790 return 0;
12791 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040012792 elsif($New_Value!~/\b$Qual\b/)
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040012793 { # became non-qual
12794 return 1;
12795 }
12796 else
12797 {
12798 my @BQ1 = getQualModel($Old_Value, $Qual);
12799 my @BQ2 = getQualModel($New_Value, $Qual);
12800 foreach (0 .. $#BQ1)
12801 { # removed qual
12802 if($BQ1[$_]==1
12803 and $BQ2[$_]!=1)
12804 {
12805 return 2;
12806 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012807 }
12808 }
12809 return 0;
12810}
12811
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040012812sub getQualModel($$)
12813{
12814 my ($Value, $Qual) = @_;
12815 if(not $Qual) {
12816 return $Value;
12817 }
12818
12819 # cleaning
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040012820 while($Value=~/(\w+)/ and $1 ne $Qual) {
12821 $Value=~s/\b$1\b//g;
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040012822 }
12823 $Value=~s/[^\*\&\w]+//g;
12824
12825 # modeling
12826 # int*const*const == 011
12827 # int**const == 001
12828 my @Model = ();
12829 my @Elems = split(/[\*\&]/, $Value);
12830 if(not @Elems) {
12831 return (0);
12832 }
12833 foreach (@Elems)
12834 {
12835 if($_ eq $Qual) {
12836 push(@Model, 1);
12837 }
12838 else {
12839 push(@Model, 0);
12840 }
12841 }
12842
12843 return @Model;
12844}
12845
12846sub showVal($$$)
12847{
12848 my ($Value, $TypeId, $LibVersion) = @_;
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +040012849 my %PureType = get_PureType($TypeId, $TypeInfo{$LibVersion});
Andrey Ponomarenkoa01311b2012-06-08 17:20:02 +040012850 my $TName = uncover_typedefs($PureType{"Name"}, $LibVersion);
Andrey Ponomarenko01117f12012-06-26 12:23:02 +040012851 if(substr($Value, 0, 2) eq "_Z")
12852 {
12853 if(my $Unmangled = $tr_name{$Value}) {
12854 return $Unmangled;
12855 }
12856 }
Andrey Ponomarenko07aea072012-11-12 16:15:07 +040012857 elsif($TName=~/\A(char(| const)\*|std::(string(| const)|basic_string<char>(|const))(|&))\Z/)
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040012858 { # strings
12859 return "\"$Value\"";
12860 }
Andrey Ponomarenkoa01311b2012-06-08 17:20:02 +040012861 elsif($TName=~/\Achar(| const)\Z/)
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040012862 { # characters
12863 return "\'$Value\'";
12864 }
12865 return $Value;
12866}
12867
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012868sub mergeParameters($$$$$)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012869{
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012870 my ($Symbol, $PSymbol, $ParamPos1, $ParamPos2, $Level) = @_;
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040012871 if(not $Symbol) {
12872 return;
12873 }
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040012874 my $PType1_Id = $CompleteSignature{1}{$Symbol}{"Param"}{$ParamPos1}{"type"};
12875 my $PName1 = $CompleteSignature{1}{$Symbol}{"Param"}{$ParamPos1}{"name"};
12876 my $PType2_Id = $CompleteSignature{2}{$PSymbol}{"Param"}{$ParamPos2}{"type"};
12877 my $PName2 = $CompleteSignature{2}{$PSymbol}{"Param"}{$ParamPos2}{"name"};
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040012878 if(not $PType1_Id
12879 or not $PType2_Id) {
12880 return;
12881 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040012882 my %Type1 = get_Type($PType1_Id, 1);
12883 my %Type2 = get_Type($PType2_Id, 2);
12884 my %BaseType1 = get_BaseType($PType1_Id, 1);
12885 my %BaseType2 = get_BaseType($PType2_Id, 2);
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040012886 my $Parameter_Location = ($PName1)?$PName1:showPos($ParamPos1)." Parameter";
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012887 if($Level eq "Binary")
12888 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040012889 if(checkDump(1, "2.6.1") and checkDump(2, "2.6.1"))
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012890 { # "reg" attribute added in ACC 1.95.1 (dump 2.6.1 format)
12891 if($CompleteSignature{1}{$Symbol}{"Param"}{$ParamPos1}{"reg"}
12892 and not $CompleteSignature{2}{$PSymbol}{"Param"}{$ParamPos2}{"reg"})
12893 {
12894 %{$CompatProblems{$Level}{$Symbol}{"Parameter_Became_Non_Register"}{$Parameter_Location}}=(
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040012895 "Target"=>$PName1,
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012896 "Param_Pos"=>$ParamPos1 );
12897 }
12898 elsif(not $CompleteSignature{1}{$Symbol}{"Param"}{$ParamPos1}{"reg"}
12899 and $CompleteSignature{2}{$PSymbol}{"Param"}{$ParamPos2}{"reg"})
12900 {
12901 %{$CompatProblems{$Level}{$Symbol}{"Parameter_Became_Register"}{$Parameter_Location}}=(
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040012902 "Target"=>$PName1,
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012903 "Param_Pos"=>$ParamPos1 );
12904 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012905 }
12906 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040012907 if(checkDump(1, "2.0") and checkDump(2, "2.0"))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012908 { # "default" attribute added in ACC 1.22 (dump 2.0 format)
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040012909 my $Value_Old = $CompleteSignature{1}{$Symbol}{"Param"}{$ParamPos1}{"default"};
12910 my $Value_New = $CompleteSignature{2}{$PSymbol}{"Param"}{$ParamPos2}{"default"};
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040012911 if(not checkDump(1, "2.13")
12912 and checkDump(2, "2.13"))
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040012913 { # support for old ABI dumps
12914 if(defined $Value_Old and defined $Value_New)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012915 {
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040012916 if($Type1{"Name"} eq "bool"
12917 and $Value_Old eq "false" and $Value_New eq "0")
12918 { # int class::method ( bool p = 0 );
12919 # old ABI dumps: "false"
12920 # new ABI dumps: "0"
12921 $Value_Old = "0";
12922 }
12923 }
12924 }
Andrey Ponomarenko01117f12012-06-26 12:23:02 +040012925 if(not checkDump(1, "2.18")
12926 and checkDump(2, "2.18"))
12927 { # support for old ABI dumps
12928 if(not defined $Value_Old
12929 and substr($Value_New, 0, 2) eq "_Z") {
12930 $Value_Old = $Value_New;
12931 }
12932 }
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040012933 if(defined $Value_Old)
12934 {
12935 $Value_Old = showVal($Value_Old, $PType1_Id, 1);
12936 if(defined $Value_New)
12937 {
12938 $Value_New = showVal($Value_New, $PType2_Id, 2);
12939 if($Value_Old ne $Value_New)
12940 { # FIXME: how to distinguish "0" and 0 (NULL)
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012941 %{$CompatProblems{$Level}{$Symbol}{"Parameter_Default_Value_Changed"}{$Parameter_Location}}=(
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040012942 "Target"=>$PName1,
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012943 "Param_Pos"=>$ParamPos1,
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040012944 "Old_Value"=>$Value_Old,
12945 "New_Value"=>$Value_New );
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012946 }
12947 }
12948 else
12949 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012950 %{$CompatProblems{$Level}{$Symbol}{"Parameter_Default_Value_Removed"}{$Parameter_Location}}=(
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040012951 "Target"=>$PName1,
12952 "Param_Pos"=>$ParamPos1,
12953 "Old_Value"=>$Value_Old );
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012954 }
12955 }
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040012956 elsif(defined $Value_New)
12957 {
12958 $Value_New = showVal($Value_New, $PType2_Id, 2);
12959 %{$CompatProblems{$Level}{$Symbol}{"Parameter_Default_Value_Added"}{$Parameter_Location}}=(
12960 "Target"=>$PName1,
12961 "Param_Pos"=>$ParamPos1,
12962 "New_Value"=>$Value_New );
12963 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012964 }
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040012965 if($PName1 and $PName2 and $PName1 ne $PName2
12966 and $PType1_Id!=-1 and $PType2_Id!=-1
12967 and $PName1!~/\Ap\d+\Z/ and $PName2!~/\Ap\d+\Z/)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012968 { # except unnamed "..." value list (Id=-1)
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040012969 %{$CompatProblems{$Level}{$Symbol}{"Renamed_Parameter"}{showPos($ParamPos1)." Parameter"}}=(
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040012970 "Target"=>$PName1,
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012971 "Param_Pos"=>$ParamPos1,
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040012972 "Param_Type"=>$TypeInfo{1}{$PType1_Id}{"Name"},
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040012973 "Old_Value"=>$PName1,
12974 "New_Value"=>$PName2,
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012975 "New_Signature"=>get_Signature($Symbol, 2) );
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012976 }
12977 # checking type change (replace)
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040012978 my %SubProblems = detectTypeChange($PType1_Id, $PType2_Id, "Parameter", $Level);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012979 foreach my $SubProblemType (keys(%SubProblems))
12980 { # add new problems, remove false alarms
12981 my $New_Value = $SubProblems{$SubProblemType}{"New_Value"};
12982 my $Old_Value = $SubProblems{$SubProblemType}{"Old_Value"};
12983 if($SubProblemType eq "Parameter_Type")
12984 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040012985 if(checkDump(1, "2.6") and checkDump(2, "2.6"))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012986 {
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040012987 if(my $RA = addedQual($Old_Value, $New_Value, "restrict"))
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012988 {
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040012989 %{$SubProblems{"Parameter_Became_Restrict"}} = %{$SubProblems{$SubProblemType}};
12990 if($Level eq "Source"
12991 and cmpBTypes($Old_Value, $New_Value, 1, 2)) {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012992 delete($SubProblems{$SubProblemType});
12993 }
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040012994 }
12995 elsif(my $RR = removedQual($Old_Value, $New_Value, "restrict"))
12996 {
12997 %{$SubProblems{"Parameter_Became_NonRestrict"}} = %{$SubProblems{$SubProblemType}};
12998 if($Level eq "Source"
12999 and cmpBTypes($Old_Value, $New_Value, 1, 2)) {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040013000 delete($SubProblems{$SubProblemType});
13001 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013002 }
13003 }
13004 if($Type2{"Type"} eq "Const" and $BaseType2{"Name"} eq $Type1{"Name"}
13005 and $Type1{"Type"}=~/Intrinsic|Class|Struct|Union|Enum/)
13006 { # int to "int const"
13007 delete($SubProblems{$SubProblemType});
13008 }
13009 if($Type1{"Type"} eq "Const" and $BaseType1{"Name"} eq $Type2{"Name"}
13010 and $Type2{"Type"}=~/Intrinsic|Class|Struct|Union|Enum/)
13011 { # "int const" to int
13012 delete($SubProblems{$SubProblemType});
13013 }
13014 }
13015 }
13016 foreach my $SubProblemType (keys(%SubProblems))
13017 { # modify/register problems
13018 my $New_Value = $SubProblems{$SubProblemType}{"New_Value"};
13019 my $Old_Value = $SubProblems{$SubProblemType}{"Old_Value"};
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +040013020 my $New_Size = $SubProblems{$SubProblemType}{"New_Size"};
13021 my $Old_Size = $SubProblems{$SubProblemType}{"Old_Size"};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013022 my $NewProblemType = $SubProblemType;
13023 if($Old_Value eq "..." and $New_Value ne "...")
13024 { # change from "..." to "int"
13025 if($ParamPos1==0)
13026 { # ISO C requires a named argument before "..."
13027 next;
13028 }
13029 $NewProblemType = "Parameter_Became_NonVaList";
13030 }
13031 elsif($New_Value eq "..." and $Old_Value ne "...")
13032 { # change from "int" to "..."
13033 if($ParamPos2==0)
13034 { # ISO C requires a named argument before "..."
13035 next;
13036 }
13037 $NewProblemType = "Parameter_Became_VaList";
13038 }
13039 elsif($SubProblemType eq "Parameter_Type"
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040013040 and removedQual($Old_Value, $New_Value, "const"))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013041 { # parameter: "const" to non-"const"
13042 $NewProblemType = "Parameter_Became_Non_Const";
13043 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040013044 elsif($Level eq "Binary" and ($SubProblemType eq "Parameter_Type_And_Size"
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +040013045 or $SubProblemType eq "Parameter_Type" or $SubProblemType eq "Parameter_Type_Format"))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013046 {
13047 my ($Arch1, $Arch2) = (getArch(1), getArch(2));
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +040013048 if($Arch1 eq "unknown"
13049 or $Arch2 eq "unknown")
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013050 { # if one of the architectures is unknown
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +040013051 # then set other arhitecture to unknown too
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013052 ($Arch1, $Arch2) = ("unknown", "unknown");
13053 }
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +040013054 my (%Conv1, %Conv2) = ();
13055 if($UseConv_Real{1} and $UseConv_Real{1})
13056 { # real
13057 %Conv1 = callingConvention_P_Real($CompleteSignature{1}{$Symbol}, $ParamPos1);
13058 %Conv2 = callingConvention_P_Real($CompleteSignature{2}{$Symbol}, $ParamPos2);
13059 }
13060 else
13061 { # model
13062 %Conv1 = callingConvention_P_Model($CompleteSignature{1}{$Symbol}, $ParamPos1, $TypeInfo{1}, $Arch1, $OStarget, $WORD_SIZE{1});
13063 %Conv2 = callingConvention_P_Model($CompleteSignature{2}{$Symbol}, $ParamPos2, $TypeInfo{2}, $Arch2, $OStarget, $WORD_SIZE{2});
13064 }
13065 if($Conv1{"Method"} eq $Conv2{"Method"})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013066 {
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +040013067 if($Conv1{"Method"} eq "stack")
13068 {
13069 if($Old_Size ne $New_Size) { # FIXME: isMemPadded, getOffset
13070 $NewProblemType = "Parameter_Type_And_Stack";
13071 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013072 }
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +040013073 elsif($Conv1{"Method"} eq "reg")
13074 {
13075 if($Conv1{"Registers"} ne $Conv2{"Registers"}) {
13076 $NewProblemType = "Parameter_Type_And_Register";
13077 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013078 }
13079 }
13080 else
13081 {
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +040013082 if($Conv1{"Method"} eq "stack") {
13083 $NewProblemType = "Parameter_Type_From_Stack_To_Register";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013084 }
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +040013085 elsif($Conv1{"Method"} eq "register") {
13086 $NewProblemType = "Parameter_Type_From_Register_To_Stack";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013087 }
13088 }
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +040013089 $SubProblems{$SubProblemType}{"Old_Reg"} = $Conv1{"Registers"};
13090 $SubProblems{$SubProblemType}{"New_Reg"} = $Conv2{"Registers"};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013091 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040013092 %{$CompatProblems{$Level}{$Symbol}{$NewProblemType}{$Parameter_Location}}=(
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040013093 "Target"=>$PName1,
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013094 "Param_Pos"=>$ParamPos1,
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040013095 "New_Signature"=>get_Signature($Symbol, 2) );
13096 @{$CompatProblems{$Level}{$Symbol}{$NewProblemType}{$Parameter_Location}}{keys(%{$SubProblems{$SubProblemType}})} = values %{$SubProblems{$SubProblemType}};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013097 }
13098 @RecurTypes = ();
13099 # checking type definition changes
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040013100 my %SubProblems_Merge = mergeTypes($PType1_Id, $PType2_Id, $Level);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013101 foreach my $SubProblemType (keys(%SubProblems_Merge))
13102 {
13103 foreach my $SubLocation (keys(%{$SubProblems_Merge{$SubProblemType}}))
13104 {
13105 my $NewProblemType = $SubProblemType;
13106 if($SubProblemType eq "DataType_Size")
13107 {
13108 my $InitialType_Type = $SubProblems_Merge{$SubProblemType}{$SubLocation}{"InitialType_Type"};
13109 if($InitialType_Type!~/\A(Pointer|Ref)\Z/ and $SubLocation!~/\-\>/)
13110 { # stack has been affected
13111 $NewProblemType = "DataType_Size_And_Stack";
13112 }
13113 }
13114 my $NewLocation = ($SubLocation)?$Parameter_Location."->".$SubLocation:$Parameter_Location;
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040013115 %{$CompatProblems{$Level}{$Symbol}{$NewProblemType}{$NewLocation}}=(
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040013116 "Param_Type"=>$TypeInfo{1}{$PType1_Id}{"Name"},
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013117 "Param_Pos"=>$ParamPos1,
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040013118 "Param_Name"=>$PName1 );
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040013119 @{$CompatProblems{$Level}{$Symbol}{$NewProblemType}{$NewLocation}}{keys(%{$SubProblems_Merge{$SubProblemType}{$SubLocation}})} = values %{$SubProblems_Merge{$SubProblemType}{$SubLocation}};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013120 if($SubLocation!~/\-\>/) {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040013121 $CompatProblems{$Level}{$Symbol}{$NewProblemType}{$NewLocation}{"Start_Type_Name"} = $TypeInfo{1}{$PType1_Id}{"Name"};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013122 }
13123 }
13124 }
13125}
13126
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013127sub find_ParamPair_Pos_byName($$$)
13128{
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040013129 my ($Name, $Symbol, $LibVersion) = @_;
13130 foreach my $ParamPos (sort {int($a)<=>int($b)} keys(%{$CompleteSignature{$LibVersion}{$Symbol}{"Param"}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013131 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040013132 next if(not defined $CompleteSignature{$LibVersion}{$Symbol}{"Param"}{$ParamPos});
13133 if($CompleteSignature{$LibVersion}{$Symbol}{"Param"}{$ParamPos}{"name"} eq $Name)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013134 {
13135 return $ParamPos;
13136 }
13137 }
13138 return "lost";
13139}
13140
13141sub find_ParamPair_Pos_byTypeAndPos($$$$$)
13142{
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040013143 my ($TypeName, $MediumPos, $Order, $Symbol, $LibVersion) = @_;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013144 my @Positions = ();
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040013145 foreach my $ParamPos (sort {int($a)<=>int($b)} keys(%{$CompleteSignature{$LibVersion}{$Symbol}{"Param"}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013146 {
13147 next if($Order eq "backward" and $ParamPos>$MediumPos);
13148 next if($Order eq "forward" and $ParamPos<$MediumPos);
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040013149 next if(not defined $CompleteSignature{$LibVersion}{$Symbol}{"Param"}{$ParamPos});
13150 my $PTypeId = $CompleteSignature{$LibVersion}{$Symbol}{"Param"}{$ParamPos}{"type"};
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040013151 if($TypeInfo{$LibVersion}{$PTypeId}{"Name"} eq $TypeName) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013152 push(@Positions, $ParamPos);
13153 }
13154 }
13155 return @Positions;
13156}
13157
13158sub getTypeIdByName($$)
13159{
13160 my ($TypeName, $Version) = @_;
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040013161 return $TName_Tid{$Version}{formatName($TypeName, "T")};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013162}
13163
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040013164sub checkFormatChange($$$)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013165{
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040013166 my ($Type1_Id, $Type2_Id, $Level) = @_;
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +040013167 my %Type1_Pure = get_PureType($Type1_Id, $TypeInfo{1});
13168 my %Type2_Pure = get_PureType($Type2_Id, $TypeInfo{2});
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013169 if($Type1_Pure{"Name"} eq $Type2_Pure{"Name"})
13170 { # equal types
13171 return 0;
13172 }
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040013173 if($Type1_Pure{"Name"} eq "void")
13174 { # from void* to something
13175 return 0;
13176 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013177 if($Type1_Pure{"Name"}=~/\*/
13178 or $Type2_Pure{"Name"}=~/\*/)
13179 { # compared in detectTypeChange()
13180 return 0;
13181 }
13182 my %FloatType = map {$_=>1} (
13183 "float",
13184 "double",
13185 "long double"
13186 );
13187 if($Type1_Pure{"Type"} ne $Type2_Pure{"Type"})
13188 { # different types
13189 if($Type1_Pure{"Type"} eq "Intrinsic"
13190 and $Type2_Pure{"Type"} eq "Enum")
13191 { # "int" to "enum"
13192 return 0;
13193 }
13194 elsif($Type2_Pure{"Type"} eq "Intrinsic"
13195 and $Type1_Pure{"Type"} eq "Enum")
13196 { # "enum" to "int"
13197 return 0;
13198 }
13199 else
13200 { # "union" to "struct"
13201 # ...
13202 return 1;
13203 }
13204 }
13205 else
13206 {
13207 if($Type1_Pure{"Type"} eq "Intrinsic")
13208 {
13209 if($FloatType{$Type1_Pure{"Name"}}
13210 or $FloatType{$Type2_Pure{"Name"}})
13211 { # "float" to "double"
13212 # "float" to "int"
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040013213 if($Level eq "Source")
13214 { # Safe
13215 return 0;
13216 }
13217 else {
13218 return 1;
13219 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013220 }
13221 }
13222 elsif($Type1_Pure{"Type"}=~/Class|Struct|Union|Enum/)
13223 {
13224 my @Membs1 = keys(%{$Type1_Pure{"Memb"}});
13225 my @Membs2 = keys(%{$Type2_Pure{"Memb"}});
13226 if($#Membs1!=$#Membs2)
13227 { # different number of elements
13228 return 1;
13229 }
13230 if($Type1_Pure{"Type"} eq "Enum")
13231 {
13232 foreach my $Pos (@Membs1)
13233 { # compare elements by name and value
13234 if($Type1_Pure{"Memb"}{$Pos}{"name"} ne $Type2_Pure{"Memb"}{$Pos}{"name"}
13235 or $Type1_Pure{"Memb"}{$Pos}{"value"} ne $Type2_Pure{"Memb"}{$Pos}{"value"})
13236 { # different names
13237 return 1;
13238 }
13239 }
13240 }
13241 else
13242 {
13243 foreach my $Pos (@Membs1)
13244 { # compare elements by type name
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040013245 my $MT1 = $TypeInfo{1}{$Type1_Pure{"Memb"}{$Pos}{"type"}}{"Name"};
13246 my $MT2 = $TypeInfo{2}{$Type2_Pure{"Memb"}{$Pos}{"type"}}{"Name"};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013247 if($MT1 ne $MT2)
13248 { # different types
Andrey Ponomarenko2956b972012-11-14 19:16:16 +040013249 if(not isAnon($MT1) and not isAnon($MT2)) {
13250 return 1;
13251 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013252 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040013253 if($Level eq "Source")
13254 {
13255 if($Type1_Pure{"Memb"}{$Pos}{"name"} ne $Type2_Pure{"Memb"}{$Pos}{"name"})
13256 { # different names
13257 return 1;
13258 }
13259 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013260 }
13261 }
13262 }
13263 }
13264 return 0;
13265}
13266
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040013267sub detectTypeChange($$$$)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013268{
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040013269 my ($Type1_Id, $Type2_Id, $Prefix, $Level) = @_;
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040013270 if(not $Type1_Id or not $Type2_Id) {
13271 return ();
13272 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013273 my %LocalProblems = ();
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040013274 my %Type1 = get_Type($Type1_Id, 1);
13275 my %Type2 = get_Type($Type2_Id, 2);
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +040013276 my %Type1_Pure = get_PureType($Type1_Id, $TypeInfo{1});
13277 my %Type2_Pure = get_PureType($Type2_Id, $TypeInfo{2});
13278 my %Type1_Base = ($Type1_Pure{"Type"} eq "Array")?get_OneStep_BaseType($Type1_Pure{"Tid"}, $TypeInfo{1}):get_BaseType($Type1_Id, 1);
13279 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 +040013280 my $Type1_PLevel = get_PLevel($Type1_Id, 1);
13281 my $Type2_PLevel = get_PLevel($Type2_Id, 2);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013282 return () if(not $Type1{"Name"} or not $Type2{"Name"});
13283 return () if(not $Type1_Base{"Name"} or not $Type2_Base{"Name"});
13284 return () if($Type1_PLevel eq "" or $Type2_PLevel eq "");
13285 if($Type1_Base{"Name"} ne $Type2_Base{"Name"}
13286 and ($Type1{"Name"} eq $Type2{"Name"} or ($Type1_PLevel>=1 and $Type1_PLevel==$Type2_PLevel
13287 and $Type1_Base{"Name"} ne "void" and $Type2_Base{"Name"} ne "void")))
13288 { # base type change
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040013289 if($Type1{"Name"} eq $Type2{"Name"})
13290 {
13291 if($Type1{"Type"} eq "Typedef" and $Type2{"Type"} eq "Typedef")
13292 { # will be reported in mergeTypes() as typedef problem
13293 return ();
13294 }
13295 my %Typedef_1 = goToFirst($Type1{"Tid"}, 1, "Typedef");
13296 my %Typedef_2 = goToFirst($Type2{"Tid"}, 2, "Typedef");
13297 if(%Typedef_1 and %Typedef_2)
13298 {
13299 if($Typedef_1{"Name"} eq $Typedef_2{"Name"}
13300 and $Typedef_1{"Type"} eq "Typedef" and $Typedef_2{"Type"} eq "Typedef")
13301 { # const Typedef
13302 return ();
13303 }
13304 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013305 }
13306 if($Type1_Base{"Name"}!~/anon\-/ and $Type2_Base{"Name"}!~/anon\-/)
13307 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040013308 if($Level eq "Binary"
13309 and $Type1_Base{"Size"} ne $Type2_Base{"Size"}
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013310 and $Type1_Base{"Size"} and $Type2_Base{"Size"})
13311 {
13312 %{$LocalProblems{$Prefix."_BaseType_And_Size"}}=(
13313 "Old_Value"=>$Type1_Base{"Name"},
13314 "New_Value"=>$Type2_Base{"Name"},
13315 "Old_Size"=>$Type1_Base{"Size"}*$BYTE_SIZE,
13316 "New_Size"=>$Type2_Base{"Size"}*$BYTE_SIZE,
13317 "InitialType_Type"=>$Type1_Pure{"Type"});
13318 }
13319 else
13320 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040013321 if(checkFormatChange($Type1_Base{"Tid"}, $Type2_Base{"Tid"}, $Level))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013322 { # format change
13323 %{$LocalProblems{$Prefix."_BaseType_Format"}}=(
13324 "Old_Value"=>$Type1_Base{"Name"},
13325 "New_Value"=>$Type2_Base{"Name"},
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +040013326 "Old_Size"=>$Type1_Base{"Size"}*$BYTE_SIZE,
13327 "New_Size"=>$Type2_Base{"Size"}*$BYTE_SIZE,
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013328 "InitialType_Type"=>$Type1_Pure{"Type"});
13329 }
13330 elsif(tNameLock($Type1_Base{"Tid"}, $Type2_Base{"Tid"}))
13331 {
13332 %{$LocalProblems{$Prefix."_BaseType"}}=(
13333 "Old_Value"=>$Type1_Base{"Name"},
13334 "New_Value"=>$Type2_Base{"Name"},
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +040013335 "Old_Size"=>$Type1_Base{"Size"}*$BYTE_SIZE,
13336 "New_Size"=>$Type2_Base{"Size"}*$BYTE_SIZE,
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013337 "InitialType_Type"=>$Type1_Pure{"Type"});
13338 }
13339 }
13340 }
13341 }
13342 elsif($Type1{"Name"} ne $Type2{"Name"})
13343 { # type change
13344 if($Type1{"Name"}!~/anon\-/ and $Type2{"Name"}!~/anon\-/)
13345 {
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +040013346 if($Prefix eq "Return"
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013347 and $Type1_Pure{"Name"} eq "void")
13348 {
13349 %{$LocalProblems{"Return_Type_From_Void"}}=(
13350 "New_Value"=>$Type2{"Name"},
13351 "New_Size"=>$Type2{"Size"}*$BYTE_SIZE,
13352 "InitialType_Type"=>$Type1_Pure{"Type"});
13353 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013354 elsif($Prefix eq "Return"
13355 and $Type2_Pure{"Name"} eq "void")
13356 {
13357 %{$LocalProblems{"Return_Type_Became_Void"}}=(
13358 "Old_Value"=>$Type1{"Name"},
13359 "Old_Size"=>$Type1{"Size"}*$BYTE_SIZE,
13360 "InitialType_Type"=>$Type1_Pure{"Type"});
13361 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013362 else
13363 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040013364 if($Level eq "Binary"
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040013365 and $Type1{"Size"} and $Type2{"Size"}
13366 and $Type1{"Size"} ne $Type2{"Size"})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013367 {
13368 %{$LocalProblems{$Prefix."_Type_And_Size"}}=(
13369 "Old_Value"=>$Type1{"Name"},
13370 "New_Value"=>$Type2{"Name"},
13371 "Old_Size"=>$Type1{"Size"}*$BYTE_SIZE,
13372 "New_Size"=>$Type2{"Size"}*$BYTE_SIZE,
13373 "InitialType_Type"=>$Type1_Pure{"Type"});
13374 }
13375 else
13376 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040013377 if(checkFormatChange($Type1_Id, $Type2_Id, $Level))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013378 { # format change
13379 %{$LocalProblems{$Prefix."_Type_Format"}}=(
13380 "Old_Value"=>$Type1{"Name"},
13381 "New_Value"=>$Type2{"Name"},
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +040013382 "Old_Size"=>$Type1{"Size"}*$BYTE_SIZE,
13383 "New_Size"=>$Type2{"Size"}*$BYTE_SIZE,
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013384 "InitialType_Type"=>$Type1_Pure{"Type"});
13385 }
13386 elsif(tNameLock($Type1_Id, $Type2_Id))
13387 { # FIXME: correct this condition
13388 %{$LocalProblems{$Prefix."_Type"}}=(
13389 "Old_Value"=>$Type1{"Name"},
13390 "New_Value"=>$Type2{"Name"},
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +040013391 "Old_Size"=>$Type1{"Size"}*$BYTE_SIZE,
13392 "New_Size"=>$Type2{"Size"}*$BYTE_SIZE,
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013393 "InitialType_Type"=>$Type1_Pure{"Type"});
13394 }
13395 }
13396 }
13397 }
13398 }
13399 if($Type1_PLevel!=$Type2_PLevel)
13400 {
13401 if($Type1{"Name"} ne "void" and $Type1{"Name"} ne "..."
13402 and $Type2{"Name"} ne "void" and $Type2{"Name"} ne "...")
13403 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040013404 if($Level eq "Source")
13405 {
13406 %{$LocalProblems{$Prefix."_PointerLevel"}}=(
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013407 "Old_Value"=>$Type1_PLevel,
13408 "New_Value"=>$Type2_PLevel);
13409 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040013410 else
13411 {
13412 if($Type2_PLevel>$Type1_PLevel) {
13413 %{$LocalProblems{$Prefix."_PointerLevel_Increased"}}=(
13414 "Old_Value"=>$Type1_PLevel,
13415 "New_Value"=>$Type2_PLevel);
13416 }
13417 else {
13418 %{$LocalProblems{$Prefix."_PointerLevel_Decreased"}}=(
13419 "Old_Value"=>$Type1_PLevel,
13420 "New_Value"=>$Type2_PLevel);
13421 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013422 }
13423 }
13424 }
13425 if($Type1_Pure{"Type"} eq "Array")
13426 { # base_type[N] -> base_type[N]
13427 # base_type: older_structure -> typedef to newer_structure
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040013428 my %SubProblems = detectTypeChange($Type1_Base{"Tid"}, $Type2_Base{"Tid"}, $Prefix, $Level);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013429 foreach my $SubProblemType (keys(%SubProblems))
13430 {
13431 $SubProblemType=~s/_Type/_BaseType/g;
13432 next if(defined $LocalProblems{$SubProblemType});
13433 foreach my $Attr (keys(%{$SubProblems{$SubProblemType}})) {
13434 $LocalProblems{$SubProblemType}{$Attr} = $SubProblems{$SubProblemType}{$Attr};
13435 }
13436 }
13437 }
13438 return %LocalProblems;
13439}
13440
13441sub tNameLock($$)
13442{
13443 my ($Tid1, $Tid2) = @_;
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040013444 my $Changed = 0;
13445 if(differentDumps("G"))
13446 { # different GCC versions
13447 $Changed = 1;
13448 }
13449 elsif(differentDumps("V"))
13450 { # different versions of ABI dumps
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040013451 if(not checkDump(1, "2.13")
13452 or not checkDump(2, "2.13"))
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040013453 { # latest names update
13454 # 2.6: added restrict qualifier
13455 # 2.13: added missed typedefs to qualified types
13456 $Changed = 1;
13457 }
13458 }
13459 if($Changed)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013460 { # different formats
13461 if($UseOldDumps)
13462 { # old dumps
13463 return 0;
13464 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040013465 my $TN1 = $TypeInfo{1}{$Tid1}{"Name"};
13466 my $TN2 = $TypeInfo{2}{$Tid2}{"Name"};
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040013467
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040013468 my $TT1 = $TypeInfo{1}{$Tid1}{"Type"};
13469 my $TT2 = $TypeInfo{2}{$Tid2}{"Type"};
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040013470
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040013471 my %Base1 = get_Type($Tid1, 1);
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040013472 while(defined $Base1{"Type"} and $Base1{"Type"} eq "Typedef") {
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +040013473 %Base1 = get_OneStep_BaseType($Base1{"Tid"}, $TypeInfo{1});
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013474 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040013475 my %Base2 = get_Type($Tid2, 2);
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040013476 while(defined $Base2{"Type"} and $Base2{"Type"} eq "Typedef") {
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +040013477 %Base2 = get_OneStep_BaseType($Base2{"Tid"}, $TypeInfo{2});
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013478 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +040013479 my $BName1 = uncover_typedefs($Base1{"Name"}, 1);
13480 my $BName2 = uncover_typedefs($Base2{"Name"}, 2);
13481 if($BName1 eq $BName2)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013482 { # equal base types
13483 return 0;
13484 }
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040013485
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040013486 if(not checkDump(1, "2.13")
13487 or not checkDump(2, "2.13"))
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040013488 { # broken array names in ABI dumps < 2.13
13489 if($TT1 eq "Array"
13490 and $TT2 eq "Array")
13491 {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013492 return 0;
13493 }
13494 }
13495
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040013496 if(not checkDump(1, "2.6")
13497 or not checkDump(2, "2.6"))
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040013498 { # added restrict attribute in 2.6
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040013499 if($TN1!~/\brestrict\b/
13500 and $TN2=~/\brestrict\b/)
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040013501 {
13502 return 0;
13503 }
13504 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013505 }
13506 return 1;
13507}
13508
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040013509sub differentDumps($)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013510{
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040013511 my $Check = $_[0];
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +040013512 if(defined $Cache{"differentDumps"}{$Check}) {
13513 return $Cache{"differentDumps"}{$Check};
13514 }
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040013515 if($UsedDump{1}{"V"} and $UsedDump{2}{"V"})
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040013516 {
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040013517 if($Check eq "G")
13518 {
13519 if(getGccVersion(1) ne getGccVersion(2))
13520 { # different GCC versions
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +040013521 return ($Cache{"differentDumps"}{$Check}=1);
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040013522 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040013523 }
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040013524 if($Check eq "V")
13525 {
13526 if(cmpVersions(formatVersion($UsedDump{1}{"V"}, 2),
13527 formatVersion($UsedDump{2}{"V"}, 2))!=0)
13528 { # different dump versions (skip micro version)
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +040013529 return ($Cache{"differentDumps"}{$Check}=1);
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040013530 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040013531 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013532 }
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +040013533 return ($Cache{"differentDumps"}{$Check}=0);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013534}
13535
13536sub formatVersion($$)
13537{ # cut off version digits
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040013538 my ($V, $Digits) = @_;
13539 my @Elems = split(/\./, $V);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013540 return join(".", splice(@Elems, 0, $Digits));
13541}
13542
13543sub htmlSpecChars($)
13544{
13545 my $Str = $_[0];
Andrey Ponomarenko5c09ef32012-06-14 18:17:33 +040013546 if(not $Str) {
13547 return $Str;
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040013548 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013549 $Str=~s/\&([^#]|\Z)/&amp;$1/g;
13550 $Str=~s/</&lt;/g;
13551 $Str=~s/\-\>/&#45;&gt;/g; # &minus;
13552 $Str=~s/>/&gt;/g;
13553 $Str=~s/([^ ])( )([^ ])/$1\@ALONE_SP\@$3/g;
13554 $Str=~s/ /&#160;/g; # &nbsp;
13555 $Str=~s/\@ALONE_SP\@/ /g;
13556 $Str=~s/\n/<br\/>/g;
13557 $Str=~s/\"/&quot;/g;
13558 $Str=~s/\'/&#39;/g;
13559 return $Str;
13560}
13561
Andrey Ponomarenko5c09ef32012-06-14 18:17:33 +040013562sub xmlSpecChars($)
13563{
13564 my $Str = $_[0];
13565 if(not $Str) {
13566 return $Str;
13567 }
13568
13569 $Str=~s/\&([^#]|\Z)/&amp;$1/g;
13570 $Str=~s/</&lt;/g;
13571 $Str=~s/>/&gt;/g;
13572
13573 $Str=~s/\"/&quot;/g;
13574 $Str=~s/\'/&#39;/g;
13575
13576 return $Str;
13577}
13578
Andrey Ponomarenko01117f12012-06-26 12:23:02 +040013579sub xmlSpecChars_R($)
13580{
13581 my $Str = $_[0];
13582 if(not $Str) {
13583 return $Str;
13584 }
13585
13586 $Str=~s/&amp;/&/g;
13587 $Str=~s/&lt;/</g;
13588 $Str=~s/&gt;/>/g;
13589
13590 $Str=~s/&quot;/"/g;
13591 $Str=~s/&#39;/'/g;
13592
13593 return $Str;
13594}
13595
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013596sub black_name($)
13597{
13598 my $Name = $_[0];
13599 return "<span class='iname_b'>".highLight_Signature($Name)."</span>";
13600}
13601
13602sub highLight_Signature($)
13603{
13604 my $Signature = $_[0];
13605 return highLight_Signature_PPos_Italic($Signature, "", 0, 0, 0);
13606}
13607
13608sub highLight_Signature_Italic_Color($)
13609{
13610 my $Signature = $_[0];
13611 return highLight_Signature_PPos_Italic($Signature, "", 1, 1, 1);
13612}
13613
13614sub separate_symbol($)
13615{
13616 my $Symbol = $_[0];
13617 my ($Name, $Spec, $Ver) = ($Symbol, "", "");
13618 if($Symbol=~/\A([^\@\$\?]+)([\@\$]+)([^\@\$]+)\Z/) {
13619 ($Name, $Spec, $Ver) = ($1, $2, $3);
13620 }
13621 return ($Name, $Spec, $Ver);
13622}
13623
13624sub cut_f_attrs($)
13625{
13626 if($_[0]=~s/(\))((| (const volatile|const|volatile))(| \[static\]))\Z/$1/) {
13627 return $2;
13628 }
13629 return "";
13630}
13631
13632sub highLight_Signature_PPos_Italic($$$$$)
13633{
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040013634 my ($FullSignature, $Param_Pos, $ItalicParams, $ColorParams, $ShowReturn) = @_;
13635 $Param_Pos = "" if(not defined $Param_Pos);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013636 if($CheckObjectsOnly) {
13637 $ItalicParams=$ColorParams=0;
13638 }
13639 my ($Signature, $VersionSpec, $SymbolVersion) = separate_symbol($FullSignature);
13640 my $Return = "";
13641 if($ShowRetVal and $Signature=~s/([^:]):([^:].+?)\Z/$1/g) {
13642 $Return = $2;
13643 }
Andrey Ponomarenko16934472012-03-29 15:37:04 +040013644 my $SCenter = find_center($Signature, "(");
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013645 if(not $SCenter)
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040013646 { # global data
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013647 $Signature = htmlSpecChars($Signature);
13648 $Signature=~s!(\[data\])!<span style='color:Black;font-weight:normal;'>$1</span>!g;
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040013649 $Signature .= (($SymbolVersion)?"<span class='sym_ver'>&#160;$VersionSpec&#160;$SymbolVersion</span>":"");
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013650 if($Return and $ShowReturn) {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040013651 $Signature .= "<span class='sym_p nowrap'> &#160;<b>:</b>&#160;&#160;".htmlSpecChars($Return)."</span>";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013652 }
13653 return $Signature;
13654 }
13655 my ($Begin, $End) = (substr($Signature, 0, $SCenter), "");
13656 $Begin.=" " if($Begin!~/ \Z/);
13657 $End = cut_f_attrs($Signature);
13658 my @Parts = ();
Andrey Ponomarenko07aea072012-11-12 16:15:07 +040013659 my ($Short, $Params) = split_Signature($Signature);
13660 my @SParts = separate_Params($Params, 1, 1);
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040013661 foreach my $Pos (0 .. $#SParts)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013662 {
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040013663 my $Part = $SParts[$Pos];
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013664 $Part=~s/\A\s+|\s+\Z//g;
13665 my ($Part_Styled, $ParamName) = (htmlSpecChars($Part), "");
13666 if($Part=~/\([\*]+(\w+)\)/i) {
13667 $ParamName = $1;#func-ptr
13668 }
13669 elsif($Part=~/(\w+)[\,\)]*\Z/i) {
13670 $ParamName = $1;
13671 }
13672 if(not $ParamName) {
13673 push(@Parts, $Part_Styled);
13674 next;
13675 }
13676 if($ItalicParams and not $TName_Tid{1}{$Part}
13677 and not $TName_Tid{2}{$Part})
13678 {
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040013679 my $Style = "param";
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040013680 if($Param_Pos ne ""
13681 and $Pos==$Param_Pos) {
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040013682 $Style = "focus_p";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013683 }
13684 elsif($ColorParams) {
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040013685 $Style = "color_p";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013686 }
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040013687 $Part_Styled =~ s!(\W)$ParamName([\,\)]|\Z)!$1<span class=\'$Style\'>$ParamName</span>$2!ig;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013688 }
13689 $Part_Styled=~s/,(\w)/, $1/g;
13690 push(@Parts, $Part_Styled);
13691 }
13692 if(@Parts)
13693 {
13694 foreach my $Num (0 .. $#Parts)
13695 {
13696 if($Num==$#Parts)
13697 { # add ")" to the last parameter
13698 $Parts[$Num] = "<span class='nowrap'>".$Parts[$Num]." )</span>";
13699 }
13700 elsif(length($Parts[$Num])<=45) {
13701 $Parts[$Num] = "<span class='nowrap'>".$Parts[$Num]."</span>";
13702 }
13703 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040013704 $Signature = htmlSpecChars($Begin)."<span class='sym_p'>(&#160;".join(" ", @Parts)."</span>".$End;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013705 }
13706 else {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040013707 $Signature = htmlSpecChars($Begin)."<span class='sym_p'>(&#160;)</span>".$End;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013708 }
13709 if($Return and $ShowReturn) {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040013710 $Signature .= "<span class='sym_p nowrap'> &#160;<b>:</b>&#160;&#160;".htmlSpecChars($Return)."</span>";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013711 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040013712 $Signature=~s!\[\]![&#160;]!g;
13713 $Signature=~s!operator=!operator&#160;=!g;
13714 $Signature=~s!(\[in-charge\]|\[not-in-charge\]|\[in-charge-deleting\]|\[static\])!<span class='sym_kind'>$1</span>!g;
13715 return $Signature.(($SymbolVersion)?"<span class='sym_ver'>&#160;$VersionSpec&#160;$SymbolVersion</span>":"");
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013716}
13717
Andrey Ponomarenko07aea072012-11-12 16:15:07 +040013718sub split_Signature($)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013719{
Andrey Ponomarenko07aea072012-11-12 16:15:07 +040013720 my $Signature = $_[0];
13721 if(my $ShortName = substr($Signature, 0, find_center($Signature, "(")))
13722 {
13723 $Signature=~s/\A\Q$ShortName\E\(//g;
13724 cut_f_attrs($Signature);
13725 $Signature=~s/\)\Z//;
13726 return ($ShortName, $Signature);
13727 }
13728
13729 # error
13730 return ($Signature, "");
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013731}
13732
Andrey Ponomarenko07aea072012-11-12 16:15:07 +040013733sub separate_Params($$$)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013734{
Andrey Ponomarenko07aea072012-11-12 16:15:07 +040013735 my ($Params, $Comma, $Sp) = @_;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013736 my @Parts = ();
Andrey Ponomarenko16934472012-03-29 15:37:04 +040013737 my %B = ( "("=>0, "<"=>0, ")"=>0, ">"=>0 );
13738 my $Part = 0;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013739 foreach my $Pos (0 .. length($Params) - 1)
13740 {
Andrey Ponomarenko16934472012-03-29 15:37:04 +040013741 my $S = substr($Params, $Pos, 1);
13742 if(defined $B{$S}) {
Andrey Ponomarenko07aea072012-11-12 16:15:07 +040013743 $B{$S} += 1;
Andrey Ponomarenko16934472012-03-29 15:37:04 +040013744 }
13745 if($S eq "," and
13746 $B{"("}==$B{")"} and $B{"<"}==$B{">"})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013747 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040013748 if($Comma)
13749 { # include comma
Andrey Ponomarenko16934472012-03-29 15:37:04 +040013750 $Parts[$Part] .= $S;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013751 }
Andrey Ponomarenko16934472012-03-29 15:37:04 +040013752 $Part += 1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013753 }
13754 else {
Andrey Ponomarenko16934472012-03-29 15:37:04 +040013755 $Parts[$Part] .= $S;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013756 }
13757 }
Andrey Ponomarenko07aea072012-11-12 16:15:07 +040013758 if(not $Sp)
13759 { # remove spaces
13760 foreach (@Parts)
13761 {
13762 s/\A //g;
13763 s/ \Z//g;
13764 }
13765 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013766 return @Parts;
13767}
13768
Andrey Ponomarenko16934472012-03-29 15:37:04 +040013769sub find_center($$)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013770{
13771 my ($Sign, $Target) = @_;
Andrey Ponomarenko16934472012-03-29 15:37:04 +040013772 my %B = ( "("=>0, "<"=>0, ")"=>0, ">"=>0 );
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013773 my $Center = 0;
Andrey Ponomarenko16934472012-03-29 15:37:04 +040013774 if($Sign=~s/(operator([^\w\s\(\)]+|\(\)))//g)
13775 { # operators
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013776 $Center+=length($1);
13777 }
13778 foreach my $Pos (0 .. length($Sign)-1)
13779 {
13780 my $S = substr($Sign, $Pos, 1);
13781 if($S eq $Target)
13782 {
13783 if($B{"("}==$B{")"}
13784 and $B{"<"}==$B{">"}) {
13785 return $Center;
13786 }
13787 }
13788 if(defined $B{$S}) {
13789 $B{$S}+=1;
13790 }
13791 $Center+=1;
13792 }
13793 return 0;
13794}
13795
13796sub appendFile($$)
13797{
13798 my ($Path, $Content) = @_;
13799 return if(not $Path);
13800 if(my $Dir = get_dirname($Path)) {
13801 mkpath($Dir);
13802 }
Andrey Ponomarenko16934472012-03-29 15:37:04 +040013803 open(FILE, ">>", $Path) || die ("can't open file \'$Path\': $!\n");
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013804 print FILE $Content;
13805 close(FILE);
13806}
13807
13808sub writeFile($$)
13809{
13810 my ($Path, $Content) = @_;
13811 return if(not $Path);
13812 if(my $Dir = get_dirname($Path)) {
13813 mkpath($Dir);
13814 }
Andrey Ponomarenko16934472012-03-29 15:37:04 +040013815 open(FILE, ">", $Path) || die ("can't open file \'$Path\': $!\n");
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013816 print FILE $Content;
13817 close(FILE);
13818}
13819
13820sub readFile($)
13821{
13822 my $Path = $_[0];
13823 return "" if(not $Path or not -f $Path);
Andrey Ponomarenko16934472012-03-29 15:37:04 +040013824 open(FILE, $Path);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013825 local $/ = undef;
13826 my $Content = <FILE>;
13827 close(FILE);
Andrey Ponomarenko85043792012-05-14 16:48:07 +040013828 if($Path!~/\.(tu|class|abi)\Z/) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013829 $Content=~s/\r/\n/g;
13830 }
13831 return $Content;
13832}
13833
13834sub get_filename($)
13835{ # much faster than basename() from File::Basename module
Andrey Ponomarenko85043792012-05-14 16:48:07 +040013836 if(defined $Cache{"get_filename"}{$_[0]}) {
13837 return $Cache{"get_filename"}{$_[0]};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013838 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +040013839 if($_[0] and $_[0]=~/([^\/\\]+)[\/\\]*\Z/) {
13840 return ($Cache{"get_filename"}{$_[0]}=$1);
13841 }
13842 return ($Cache{"get_filename"}{$_[0]}="");
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013843}
13844
13845sub get_dirname($)
13846{ # much faster than dirname() from File::Basename module
Andrey Ponomarenko85043792012-05-14 16:48:07 +040013847 if(defined $Cache{"get_dirname"}{$_[0]}) {
13848 return $Cache{"get_dirname"}{$_[0]};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013849 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +040013850 if($_[0] and $_[0]=~/\A(.*?)[\/\\]+[^\/\\]*[\/\\]*\Z/) {
13851 return ($Cache{"get_dirname"}{$_[0]}=$1);
13852 }
13853 return ($Cache{"get_dirname"}{$_[0]}="");
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013854}
13855
13856sub separate_path($) {
13857 return (get_dirname($_[0]), get_filename($_[0]));
13858}
13859
13860sub esc($)
13861{
13862 my $Str = $_[0];
13863 $Str=~s/([()\[\]{}$ &'"`;,<>\+])/\\$1/g;
13864 return $Str;
13865}
13866
13867sub readLineNum($$)
13868{
13869 my ($Path, $Num) = @_;
13870 return "" if(not $Path or not -f $Path);
Andrey Ponomarenko16934472012-03-29 15:37:04 +040013871 open(FILE, $Path);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013872 foreach (1 ... $Num) {
13873 <FILE>;
13874 }
13875 my $Line = <FILE>;
13876 close(FILE);
13877 return $Line;
13878}
13879
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040013880sub readAttributes($$)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013881{
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040013882 my ($Path, $Num) = @_;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013883 return () if(not $Path or not -f $Path);
13884 my %Attributes = ();
Andrey Ponomarenko85043792012-05-14 16:48:07 +040013885 if(readLineNum($Path, $Num)=~/<!--\s+(.+)\s+-->/)
13886 {
13887 foreach my $AttrVal (split(/;/, $1))
13888 {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013889 if($AttrVal=~/(.+):(.+)/)
13890 {
13891 my ($Name, $Value) = ($1, $2);
13892 $Attributes{$Name} = $Value;
13893 }
13894 }
13895 }
13896 return \%Attributes;
13897}
13898
13899sub is_abs($) {
13900 return ($_[0]=~/\A(\/|\w+:[\/\\])/);
13901}
13902
13903sub get_abs_path($)
13904{ # abs_path() should NOT be called for absolute inputs
13905 # because it can change them
13906 my $Path = $_[0];
13907 if(not is_abs($Path)) {
13908 $Path = abs_path($Path);
13909 }
13910 return $Path;
13911}
13912
13913sub get_OSgroup()
13914{
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +040013915 my $N = $Config{"osname"};
13916 if($N=~/macos|darwin|rhapsody/i) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013917 return "macos";
13918 }
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +040013919 elsif($N=~/freebsd|openbsd|netbsd/i) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013920 return "bsd";
13921 }
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +040013922 elsif($N=~/haiku|beos/i) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013923 return "beos";
13924 }
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +040013925 elsif($N=~/symbian|epoc/i) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013926 return "symbian";
13927 }
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +040013928 elsif($N=~/win/i) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013929 return "windows";
13930 }
13931 else {
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +040013932 return $N;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013933 }
13934}
13935
13936sub getGccVersion($)
13937{
13938 my $LibVersion = $_[0];
13939 if($GCC_VERSION{$LibVersion})
13940 { # dump version
13941 return $GCC_VERSION{$LibVersion};
13942 }
13943 elsif($UsedDump{$LibVersion}{"V"})
13944 { # old-version dumps
13945 return "unknown";
13946 }
13947 my $GccVersion = get_dumpversion($GCC_PATH); # host version
13948 if(not $GccVersion) {
13949 return "unknown";
13950 }
13951 return $GccVersion;
13952}
13953
13954sub showArch($)
13955{
13956 my $Arch = $_[0];
13957 if($Arch eq "arm"
13958 or $Arch eq "mips") {
13959 return uc($Arch);
13960 }
13961 return $Arch;
13962}
13963
13964sub getArch($)
13965{
13966 my $LibVersion = $_[0];
13967 if($CPU_ARCH{$LibVersion})
13968 { # dump version
13969 return $CPU_ARCH{$LibVersion};
13970 }
13971 elsif($UsedDump{$LibVersion}{"V"})
13972 { # old-version dumps
13973 return "unknown";
13974 }
13975 if(defined $Cache{"getArch"}{$LibVersion}) {
13976 return $Cache{"getArch"}{$LibVersion};
13977 }
13978 my $Arch = get_dumpmachine($GCC_PATH); # host version
13979 if(not $Arch) {
13980 return "unknown";
13981 }
13982 if($Arch=~/\A([\w]{3,})(-|\Z)/) {
13983 $Arch = $1;
13984 }
13985 $Arch = "x86" if($Arch=~/\Ai[3-7]86\Z/);
13986 if($OSgroup eq "windows") {
13987 $Arch = "x86" if($Arch=~/win32|mingw32/i);
13988 $Arch = "x86_64" if($Arch=~/win64|mingw64/i);
13989 }
13990 $Cache{"getArch"}{$LibVersion} = $Arch;
13991 return $Arch;
13992}
13993
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040013994sub get_Report_Header($)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013995{
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040013996 my $Level = $_[0];
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013997 my $ArchInfo = " on <span style='color:Blue;'>".showArch(getArch(1))."</span>";
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040013998 if(getArch(1) ne getArch(2)
13999 or getArch(1) eq "unknown"
14000 or $Level eq "Source")
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014001 { # don't show architecture in the header
14002 $ArchInfo="";
14003 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014004 my $Report_Header = "<h1><span class='nowrap'>";
14005 if($Level eq "Source") {
14006 $Report_Header .= "Source compatibility";
14007 }
14008 elsif($Level eq "Binary") {
14009 $Report_Header .= "Binary compatibility";
14010 }
14011 else {
14012 $Report_Header .= "API compatibility";
14013 }
14014 $Report_Header .= " report for the <span style='color:Blue;'>$TargetLibraryFName</span> $TargetComponent</span>";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014015 $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>";
14016 if($AppPath) {
14017 $Report_Header .= " <span class='nowrap'>&#160;(relating to the portability of application <span style='color:Blue;'>".get_filename($AppPath)."</span>)</span>";
14018 }
14019 $Report_Header .= "</h1>\n";
14020 return $Report_Header;
14021}
14022
14023sub get_SourceInfo()
14024{
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040014025 my ($CheckedHeaders, $CheckedLibs) = ("", "");
14026 if(not $CheckObjectsOnly)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014027 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040014028 $CheckedHeaders = "<a name='Headers'></a><h2>Header Files (".keys(%{$Registered_Headers{1}}).")</h2><hr/>\n";
14029 $CheckedHeaders .= "<div class='h_list'>\n";
14030 foreach my $Header_Path (sort {lc($Registered_Headers{1}{$a}{"Identity"}) cmp lc($Registered_Headers{1}{$b}{"Identity"})} keys(%{$Registered_Headers{1}}))
14031 {
14032 my $Identity = $Registered_Headers{1}{$Header_Path}{"Identity"};
14033 my $Header_Name = get_filename($Identity);
14034 my $Dest_Comment = ($Identity=~/[\/\\]/)?" ($Identity)":"";
14035 $CheckedHeaders .= $Header_Name.$Dest_Comment."<br/>\n";
14036 }
14037 $CheckedHeaders .= "</div>\n";
14038 $CheckedHeaders .= "<br/>$TOP_REF<br/>\n";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014039 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040014040 if(not $CheckHeadersOnly)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014041 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040014042 $CheckedLibs = "<a name='Libs'></a><h2>".ucfirst($SLIB_TYPE)." Libraries (".keys(%{$Library_Symbol{1}}).")</h2><hr/>\n";
14043 $CheckedLibs .= "<div class='lib_list'>\n";
14044 foreach my $Library (sort {lc($a) cmp lc($b)} keys(%{$Library_Symbol{1}}))
14045 {
14046 $Library.=" (.$LIB_EXT)" if($Library!~/\.\w+\Z/);
14047 $CheckedLibs .= $Library."<br/>\n";
14048 }
14049 $CheckedLibs .= "</div>\n";
14050 $CheckedLibs .= "<br/>$TOP_REF<br/>\n";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014051 }
14052 return $CheckedHeaders.$CheckedLibs;
14053}
14054
14055sub get_TypeProblems_Count($$$)
14056{
14057 my ($TypeChanges, $TargetPriority, $Level) = @_;
14058 my $Type_Problems_Count = 0;
14059 foreach my $Type_Name (sort keys(%{$TypeChanges}))
14060 {
14061 my %Kinds_Target = ();
14062 foreach my $Kind (keys(%{$TypeChanges->{$Type_Name}}))
14063 {
14064 foreach my $Location (keys(%{$TypeChanges->{$Type_Name}{$Kind}}))
14065 {
14066 my $Target = $TypeChanges->{$Type_Name}{$Kind}{$Location}{"Target"};
14067 my $Priority = getProblemSeverity($Level, $Kind);
14068 next if($Priority ne $TargetPriority);
14069 if($Kinds_Target{$Kind}{$Target}) {
14070 next;
14071 }
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040014072 if(cmpSeverities($Type_MaxSeverity{$Level}{$Type_Name}{$Kind}{$Target}, $Priority))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014073 { # select a problem with the highest priority
14074 next;
14075 }
14076 $Kinds_Target{$Kind}{$Target} = 1;
14077 $Type_Problems_Count += 1;
14078 }
14079 }
14080 }
14081 return $Type_Problems_Count;
14082}
14083
14084sub get_Summary($)
14085{
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014086 my $Level = $_[0];
14087 my ($Added, $Removed, $I_Problems_High, $I_Problems_Medium, $I_Problems_Low, $T_Problems_High,
14088 $C_Problems_Low, $T_Problems_Medium, $T_Problems_Low, $I_Other, $T_Other) = (0,0,0,0,0,0,0,0,0,0,0);
14089 %{$RESULT{$Level}} = (
14090 "Problems"=>0,
14091 "Warnings"=>0,
14092 "Affected"=>0 );
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014093 # check rules
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014094 foreach my $Interface (sort keys(%{$CompatProblems{$Level}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014095 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014096 foreach my $Kind (keys(%{$CompatProblems{$Level}{$Interface}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014097 {
14098 if(not defined $CompatRules{$Level}{$Kind})
14099 { # unknown rule
14100 if(not $UnknownRules{$Level}{$Kind})
14101 { # only one warning
14102 printMsg("WARNING", "unknown rule \"$Kind\" (\"$Level\")");
14103 $UnknownRules{$Level}{$Kind}=1;
14104 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014105 delete($CompatProblems{$Level}{$Interface}{$Kind});
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014106 }
14107 }
14108 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014109 foreach my $Interface (sort keys(%{$CompatProblems{$Level}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014110 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014111 foreach my $Kind (sort keys(%{$CompatProblems{$Level}{$Interface}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014112 {
14113 if($CompatRules{$Level}{$Kind}{"Kind"} eq "Symbols")
14114 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014115 foreach my $Location (sort keys(%{$CompatProblems{$Level}{$Interface}{$Kind}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014116 {
14117 my $Priority = getProblemSeverity($Level, $Kind);
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014118 if($Kind eq "Added_Symbol") {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014119 $Added += 1;
14120 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014121 elsif($Kind eq "Removed_Symbol")
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014122 {
14123 $Removed += 1;
14124 $TotalAffected{$Level}{$Interface} = $Priority;
14125 }
14126 else
14127 {
14128 if($Priority eq "Safe") {
14129 $I_Other += 1;
14130 }
14131 elsif($Priority eq "High") {
14132 $I_Problems_High += 1;
14133 }
14134 elsif($Priority eq "Medium") {
14135 $I_Problems_Medium += 1;
14136 }
14137 elsif($Priority eq "Low") {
14138 $I_Problems_Low += 1;
14139 }
14140 if(($Priority ne "Low" or $StrictCompat)
14141 and $Priority ne "Safe") {
14142 $TotalAffected{$Level}{$Interface} = $Priority;
14143 }
14144 }
14145 }
14146 }
14147 }
14148 }
14149 my %TypeChanges = ();
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014150 foreach my $Interface (sort keys(%{$CompatProblems{$Level}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014151 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014152 foreach my $Kind (keys(%{$CompatProblems{$Level}{$Interface}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014153 {
14154 if($CompatRules{$Level}{$Kind}{"Kind"} eq "Types")
14155 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014156 foreach my $Location (sort {cmp_locations($b, $a)} sort keys(%{$CompatProblems{$Level}{$Interface}{$Kind}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014157 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014158 my $Type_Name = $CompatProblems{$Level}{$Interface}{$Kind}{$Location}{"Type_Name"};
14159 my $Target = $CompatProblems{$Level}{$Interface}{$Kind}{$Location}{"Target"};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014160 my $Priority = getProblemSeverity($Level, $Kind);
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040014161 if(cmpSeverities($Type_MaxSeverity{$Level}{$Type_Name}{$Kind}{$Target}, $Priority))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014162 { # select a problem with the highest priority
14163 next;
14164 }
14165 if(($Priority ne "Low" or $StrictCompat)
14166 and $Priority ne "Safe") {
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040014167 $TotalAffected{$Level}{$Interface} = maxSeverity($TotalAffected{$Level}{$Interface}, $Priority);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014168 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014169 %{$TypeChanges{$Type_Name}{$Kind}{$Location}} = %{$CompatProblems{$Level}{$Interface}{$Kind}{$Location}};
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040014170 $Type_MaxSeverity{$Level}{$Type_Name}{$Kind}{$Target} = maxSeverity($Type_MaxSeverity{$Level}{$Type_Name}{$Kind}{$Target}, $Priority);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014171 }
14172 }
14173 }
14174 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014175
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014176 $T_Problems_High = get_TypeProblems_Count(\%TypeChanges, "High", $Level);
14177 $T_Problems_Medium = get_TypeProblems_Count(\%TypeChanges, "Medium", $Level);
14178 $T_Problems_Low = get_TypeProblems_Count(\%TypeChanges, "Low", $Level);
14179 $T_Other = get_TypeProblems_Count(\%TypeChanges, "Safe", $Level);
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014180
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014181 if($CheckObjectsOnly)
14182 { # only removed exported symbols
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014183 $RESULT{$Level}{"Affected"} = $Removed*100/keys(%{$Symbol_Library{1}});
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014184 }
14185 else
14186 { # changed and removed public symbols
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014187 my $SCount = keys(%{$CheckedSymbols{$Level}});
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014188 if($ExtendedCheck)
14189 { # don't count external_func_0 for constants
14190 $SCount-=1;
14191 }
14192 if($SCount)
14193 {
14194 my %Weight = (
14195 "High" => 100,
14196 "Medium" => 50,
14197 "Low" => 25
14198 );
14199 foreach (keys(%{$TotalAffected{$Level}})) {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014200 $RESULT{$Level}{"Affected"}+=$Weight{$TotalAffected{$Level}{$_}};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014201 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014202 $RESULT{$Level}{"Affected"} = $RESULT{$Level}{"Affected"}/$SCount;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014203 }
14204 else {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014205 $RESULT{$Level}{"Affected"} = 0;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014206 }
14207 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014208 $RESULT{$Level}{"Affected"} = show_number($RESULT{$Level}{"Affected"});
14209 if($RESULT{$Level}{"Affected"}>=100) {
14210 $RESULT{$Level}{"Affected"} = 100;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014211 }
14212
Andrey Ponomarenko85043792012-05-14 16:48:07 +040014213 $RESULT{$Level}{"Problems"} += $Removed;
14214 $RESULT{$Level}{"Problems"} += $T_Problems_High + $I_Problems_High;
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014215 $RESULT{$Level}{"Problems"} += $T_Problems_Medium + $I_Problems_Medium;
Andrey Ponomarenko85043792012-05-14 16:48:07 +040014216 if($StrictCompat) {
14217 $RESULT{$Level}{"Problems"} += $T_Problems_Low + $I_Problems_Low;
14218 }
14219 else {
14220 $RESULT{$Level}{"Warnings"} += $T_Problems_Low + $I_Problems_Low;
14221 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014222
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014223 if($C_Problems_Low = keys(%{$ProblemsWithConstants{$Level}}))
14224 {
Andrey Ponomarenko85043792012-05-14 16:48:07 +040014225 if(defined $CompatRules{$Level}{"Changed_Constant"})
14226 {
14227 if($StrictCompat) {
14228 $RESULT{$Level}{"Problems"} += $C_Problems_Low;
14229 }
14230 else {
14231 $RESULT{$Level}{"Warnings"} += $C_Problems_Low;
14232 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014233 }
14234 else
14235 {
14236 printMsg("WARNING", "unknown rule \"Changed_Constant\" (\"$Level\")");
14237 $C_Problems_Low = 0;
14238 }
14239 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +040014240 if($CheckImpl and $Level eq "Binary")
14241 {
14242 if($StrictCompat) {
14243 $RESULT{$Level}{"Problems"} += keys(%ImplProblems);
14244 }
14245 else {
14246 $RESULT{$Level}{"Warnings"} += keys(%ImplProblems);
14247 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014248 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +040014249 if($RESULT{$Level}{"Problems"}
14250 and $RESULT{$Level}{"Affected"}) {
14251 $RESULT{$Level}{"Verdict"} = "incompatible";
14252 }
14253 else {
14254 $RESULT{$Level}{"Verdict"} = "compatible";
14255 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014256
14257 my $TotalTypes = keys(%{$CheckedTypes{$Level}});
14258 if(not $TotalTypes)
14259 { # list all the types
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014260 $TotalTypes = keys(%{$TName_Tid{1}});
14261 }
14262
14263 my ($Arch1, $Arch2) = (getArch(1), getArch(2));
14264 my ($GccV1, $GccV2) = (getGccVersion(1), getGccVersion(2));
14265
14266 my ($TestInfo, $TestResults, $Problem_Summary) = ();
14267
14268 if($ReportFormat eq "xml")
14269 { # XML
14270 # test info
14271 $TestInfo .= " <library>$TargetLibraryName</library>\n";
14272 $TestInfo .= " <version1>\n";
14273 $TestInfo .= " <number>".$Descriptor{1}{"Version"}."</number>\n";
14274 $TestInfo .= " <architecture>$Arch1</architecture>\n";
14275 $TestInfo .= " <gcc>$GccV1</gcc>\n";
14276 $TestInfo .= " </version1>\n";
14277
14278 $TestInfo .= " <version2>\n";
14279 $TestInfo .= " <number>".$Descriptor{2}{"Version"}."</number>\n";
14280 $TestInfo .= " <architecture>$Arch2</architecture>\n";
14281 $TestInfo .= " <gcc>$GccV2</gcc>\n";
14282 $TestInfo .= " </version2>\n";
14283 $TestInfo = "<test_info>\n".$TestInfo."</test_info>\n\n";
14284
14285 # test results
14286 $TestResults .= " <headers>\n";
14287 foreach my $Name (sort {lc($Registered_Headers{1}{$a}{"Identity"}) cmp lc($Registered_Headers{1}{$b}{"Identity"})} keys(%{$Registered_Headers{1}}))
14288 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014289 my $Identity = $Registered_Headers{1}{$Name}{"Identity"};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014290 my $Comment = ($Identity=~/[\/\\]/)?" ($Identity)":"";
14291 $TestResults .= " <name>".get_filename($Name).$Comment."</name>\n";
14292 }
14293 $TestResults .= " </headers>\n";
14294
14295 $TestResults .= " <libs>\n";
14296 foreach my $Library (sort {lc($a) cmp lc($b)} keys(%{$Library_Symbol{1}}))
14297 {
14298 $Library.=" (.$LIB_EXT)" if($Library!~/\.\w+\Z/);
14299 $TestResults .= " <name>$Library</name>\n";
14300 }
14301 $TestResults .= " </libs>\n";
14302
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040014303 $TestResults .= " <symbols>".(keys(%{$CheckedSymbols{$Level}}) - keys(%ExtendedSymbols))."</symbols>\n";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014304 $TestResults .= " <types>".$TotalTypes."</types>\n";
14305
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014306 $TestResults .= " <verdict>".$RESULT{$Level}{"Verdict"}."</verdict>\n";
14307 $TestResults .= " <affected>".$RESULT{$Level}{"Affected"}."</affected>\n";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014308 $TestResults = "<test_results>\n".$TestResults."</test_results>\n\n";
14309
14310 # problem summary
14311 $Problem_Summary .= " <added_symbols>".$Added."</added_symbols>\n";
14312 $Problem_Summary .= " <removed_symbols>".$Removed."</removed_symbols>\n";
14313
14314 $Problem_Summary .= " <problems_with_types>\n";
14315 $Problem_Summary .= " <high>$T_Problems_High</high>\n";
14316 $Problem_Summary .= " <medium>$T_Problems_Medium</medium>\n";
14317 $Problem_Summary .= " <low>$T_Problems_Low</low>\n";
14318 $Problem_Summary .= " <safe>$T_Other</safe>\n";
14319 $Problem_Summary .= " </problems_with_types>\n";
14320
14321 $Problem_Summary .= " <problems_with_symbols>\n";
14322 $Problem_Summary .= " <high>$I_Problems_High</high>\n";
14323 $Problem_Summary .= " <medium>$I_Problems_Medium</medium>\n";
14324 $Problem_Summary .= " <low>$I_Problems_Low</low>\n";
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014325 $Problem_Summary .= " <safe>$I_Other</safe>\n";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014326 $Problem_Summary .= " </problems_with_symbols>\n";
14327
14328 $Problem_Summary .= " <problems_with_constants>\n";
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014329 $Problem_Summary .= " <low>$C_Problems_Low</low>\n";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014330 $Problem_Summary .= " </problems_with_constants>\n";
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014331 if($CheckImpl and $Level eq "Binary")
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014332 {
14333 $Problem_Summary .= " <impl>\n";
14334 $Problem_Summary .= " <low>".keys(%ImplProblems)."</low>\n";
14335 $Problem_Summary .= " </impl>\n";
14336 }
14337 $Problem_Summary = "<problem_summary>\n".$Problem_Summary."</problem_summary>\n\n";
14338
14339 return ($TestInfo.$TestResults.$Problem_Summary, "");
14340 }
14341 else
14342 { # HTML
14343 # test info
14344 $TestInfo = "<h2>Test Info</h2><hr/>\n";
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014345 $TestInfo .= "<table class='summary'>\n";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014346 $TestInfo .= "<tr><th>".ucfirst($TargetComponent)." Name</th><td>$TargetLibraryFName</td></tr>\n";
14347
14348 my (@VInf1, @VInf2, $AddTestInfo) = ();
14349 if($Arch1 ne "unknown"
14350 and $Arch2 ne "unknown")
14351 { # CPU arch
14352 if($Arch1 eq $Arch2)
14353 { # go to the separate section
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014354 $AddTestInfo .= "<tr><th>CPU Type</th><td>".showArch($Arch1)."</td></tr>\n";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014355 }
14356 else
14357 { # go to the version number
14358 push(@VInf1, showArch($Arch1));
14359 push(@VInf2, showArch($Arch2));
14360 }
14361 }
14362 if($GccV1 ne "unknown"
14363 and $GccV2 ne "unknown"
14364 and $OStarget ne "windows")
14365 { # GCC version
14366 if($GccV1 eq $GccV2)
14367 { # go to the separate section
14368 $AddTestInfo .= "<tr><th>GCC Version</th><td>$GccV1</td></tr>\n";
14369 }
14370 else
14371 { # go to the version number
14372 push(@VInf1, "gcc ".$GccV1);
14373 push(@VInf2, "gcc ".$GccV2);
14374 }
14375 }
14376 # show long version names with GCC version and CPU architecture name (if different)
14377 $TestInfo .= "<tr><th>Version #1</th><td>".$Descriptor{1}{"Version"}.(@VInf1?" (".join(", ", reverse(@VInf1)).")":"")."</td></tr>\n";
14378 $TestInfo .= "<tr><th>Version #2</th><td>".$Descriptor{2}{"Version"}.(@VInf2?" (".join(", ", reverse(@VInf2)).")":"")."</td></tr>\n";
14379 $TestInfo .= $AddTestInfo;
14380 #if($COMMON_LANGUAGE{1}) {
14381 # $TestInfo .= "<tr><th>Language</th><td>".$COMMON_LANGUAGE{1}."</td></tr>\n";
14382 #}
14383 if($ExtendedCheck) {
14384 $TestInfo .= "<tr><th>Mode</th><td>Extended</td></tr>\n";
14385 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014386 if($JoinReport)
14387 {
14388 if($Level eq "Binary") {
Andrey Ponomarenko16934472012-03-29 15:37:04 +040014389 $TestInfo .= "<tr><th>Subject</th><td width='150px'>Binary Compatibility</td></tr>\n"; # Run-time
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014390 }
14391 if($Level eq "Source") {
Andrey Ponomarenko16934472012-03-29 15:37:04 +040014392 $TestInfo .= "<tr><th>Subject</th><td width='150px'>Source Compatibility</td></tr>\n"; # Build-time
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014393 }
14394 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014395 $TestInfo .= "</table>\n";
14396
14397 # test results
14398 $TestResults = "<h2>Test Results</h2><hr/>\n";
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014399 $TestResults .= "<table class='summary'>";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014400
14401 my $Headers_Link = "0";
14402 $Headers_Link = "<a href='#Headers' style='color:Blue;'>".keys(%{$Registered_Headers{1}})."</a>" if(keys(%{$Registered_Headers{1}})>0);
14403 $TestResults .= "<tr><th>Total Header Files</th><td>".($CheckObjectsOnly?"0&#160;(not&#160;analyzed)":$Headers_Link)."</td></tr>\n";
14404
14405 if(not $ExtendedCheck)
14406 {
14407 my $Libs_Link = "0";
14408 $Libs_Link = "<a href='#Libs' style='color:Blue;'>".keys(%{$Library_Symbol{1}})."</a>" if(keys(%{$Library_Symbol{1}})>0);
14409 $TestResults .= "<tr><th>Total ".ucfirst($SLIB_TYPE)." Libraries</th><td>".($CheckHeadersOnly?"0&#160;(not&#160;analyzed)":$Libs_Link)."</td></tr>\n";
14410 }
14411
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040014412 $TestResults .= "<tr><th>Total Symbols / Types</th><td>".(keys(%{$CheckedSymbols{$Level}}) - keys(%ExtendedSymbols))." / ".$TotalTypes."</td></tr>\n";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014413
Andrey Ponomarenko85043792012-05-14 16:48:07 +040014414 my $META_DATA = "verdict:".$RESULT{$Level}{"Verdict"}.";";
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014415 if($JoinReport) {
14416 $META_DATA = "kind:".lc($Level).";".$META_DATA;
14417 }
Andrey Ponomarenko16934472012-03-29 15:37:04 +040014418 $TestResults .= "<tr><th>Verdict</th>";
Andrey Ponomarenko85043792012-05-14 16:48:07 +040014419 if($RESULT{$Level}{"Verdict"} eq "incompatible") {
Andrey Ponomarenko16934472012-03-29 15:37:04 +040014420 $TestResults .= "<td><span style='color:Red;'><b>Incompatible<br/>(".$RESULT{$Level}{"Affected"}."%)</b></span></td>";
14421 }
14422 else {
14423 $TestResults .= "<td><span style='color:Green;'><b>Compatible</b></span></td>";
14424 }
14425 $TestResults .= "</tr>\n";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014426 $TestResults .= "</table>\n";
14427
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014428 $META_DATA .= "affected:".$RESULT{$Level}{"Affected"}.";";# in percents
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014429 # problem summary
14430 $Problem_Summary = "<h2>Problem Summary</h2><hr/>\n";
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014431 $Problem_Summary .= "<table class='summary'>";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014432 $Problem_Summary .= "<tr><th></th><th style='text-align:center;'>Severity</th><th style='text-align:center;'>Count</th></tr>";
14433
14434 my $Added_Link = "0";
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014435 if($Added>0)
14436 {
14437 if($JoinReport) {
14438 $Added_Link = "<a href='#".$Level."_Added' style='color:Blue;'>$Added</a>";
14439 }
14440 else {
14441 $Added_Link = "<a href='#Added' style='color:Blue;'>$Added</a>";
14442 }
14443 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014444 $META_DATA .= "added:$Added;";
Andrey Ponomarenko16934472012-03-29 15:37:04 +040014445 $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 +040014446
14447 my $Removed_Link = "0";
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014448 if($Removed>0)
14449 {
14450 if($JoinReport) {
14451 $Removed_Link = "<a href='#".$Level."_Removed' style='color:Blue;'>$Removed</a>"
14452 }
14453 else {
14454 $Removed_Link = "<a href='#Removed' style='color:Blue;'>$Removed</a>"
14455 }
14456 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014457 $META_DATA .= "removed:$Removed;";
Andrey Ponomarenko16934472012-03-29 15:37:04 +040014458 $Problem_Summary .= "<tr><th>Removed Symbols</th>";
14459 $Problem_Summary .= "<td>High</td><td".getStyle("I", "R", $Removed).">$Removed_Link</td></tr>\n";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014460
14461 my $TH_Link = "0";
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014462 $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 +040014463 $TH_Link = "n/a" if($CheckObjectsOnly);
14464 $META_DATA .= "type_problems_high:$T_Problems_High;";
Andrey Ponomarenko16934472012-03-29 15:37:04 +040014465 $Problem_Summary .= "<tr><th rowspan='3'>Problems with<br/>Data Types</th>";
14466 $Problem_Summary .= "<td>High</td><td".getStyle("T", "H", $T_Problems_High).">$TH_Link</td></tr>\n";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014467
14468 my $TM_Link = "0";
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014469 $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 +040014470 $TM_Link = "n/a" if($CheckObjectsOnly);
14471 $META_DATA .= "type_problems_medium:$T_Problems_Medium;";
Andrey Ponomarenko16934472012-03-29 15:37:04 +040014472 $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 +040014473
14474 my $TL_Link = "0";
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014475 $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 +040014476 $TL_Link = "n/a" if($CheckObjectsOnly);
14477 $META_DATA .= "type_problems_low:$T_Problems_Low;";
Andrey Ponomarenko16934472012-03-29 15:37:04 +040014478 $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 +040014479
14480 my $IH_Link = "0";
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014481 $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 +040014482 $IH_Link = "n/a" if($CheckObjectsOnly);
14483 $META_DATA .= "interface_problems_high:$I_Problems_High;";
Andrey Ponomarenko16934472012-03-29 15:37:04 +040014484 $Problem_Summary .= "<tr><th rowspan='3'>Problems with<br/>Symbols</th>";
14485 $Problem_Summary .= "<td>High</td><td".getStyle("I", "H", $I_Problems_High).">$IH_Link</td></tr>\n";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014486
14487 my $IM_Link = "0";
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014488 $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 +040014489 $IM_Link = "n/a" if($CheckObjectsOnly);
14490 $META_DATA .= "interface_problems_medium:$I_Problems_Medium;";
Andrey Ponomarenko16934472012-03-29 15:37:04 +040014491 $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 +040014492
14493 my $IL_Link = "0";
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014494 $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 +040014495 $IL_Link = "n/a" if($CheckObjectsOnly);
14496 $META_DATA .= "interface_problems_low:$I_Problems_Low;";
Andrey Ponomarenko16934472012-03-29 15:37:04 +040014497 $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 +040014498
14499 my $ChangedConstants_Link = "0";
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014500 if(keys(%{$CheckedSymbols{$Level}}) and $C_Problems_Low)
14501 {
14502 if($JoinReport) {
14503 $ChangedConstants_Link = "<a href='#".$Level."_Changed_Constants' style='color:Blue;'>$C_Problems_Low</a>";
14504 }
14505 else {
14506 $ChangedConstants_Link = "<a href='#Changed_Constants' style='color:Blue;'>$C_Problems_Low</a>";
14507 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014508 }
14509 $ChangedConstants_Link = "n/a" if($CheckObjectsOnly);
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014510 $META_DATA .= "changed_constants:$C_Problems_Low;";
Andrey Ponomarenko16934472012-03-29 15:37:04 +040014511 $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 +040014512
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014513 if($CheckImpl and $Level eq "Binary")
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014514 {
14515 my $ChangedImpl_Link = "0";
14516 $ChangedImpl_Link = "<a href='#Changed_Implementation' style='color:Blue;'>".keys(%ImplProblems)."</a>" if(keys(%ImplProblems)>0);
14517 $ChangedImpl_Link = "n/a" if($CheckHeadersOnly);
14518 $META_DATA .= "changed_implementation:".keys(%ImplProblems).";";
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040014519 $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 +040014520 }
14521 # Safe Changes
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014522 if($T_Other and not $CheckObjectsOnly)
14523 {
14524 my $TS_Link = "<a href='#".get_Anchor("Type", $Level, "Safe")."' style='color:Blue;'>$T_Other</a>";
Andrey Ponomarenko16934472012-03-29 15:37:04 +040014525 $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 +040014526 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014527
14528 if($I_Other and not $CheckObjectsOnly)
14529 {
14530 my $IS_Link = "<a href='#".get_Anchor("Symbol", $Level, "Safe")."' style='color:Blue;'>$I_Other</a>";
Andrey Ponomarenko16934472012-03-29 15:37:04 +040014531 $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 +040014532 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014533
14534 $META_DATA .= "tool_version:$TOOL_VERSION";
14535 $Problem_Summary .= "</table>\n";
Andrey Ponomarenko16934472012-03-29 15:37:04 +040014536 # $TestInfo = getLegend().$TestInfo;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014537 return ($TestInfo.$TestResults.$Problem_Summary, $META_DATA);
14538 }
14539}
14540
Andrey Ponomarenko16934472012-03-29 15:37:04 +040014541sub getStyle($$$)
14542{
14543 my ($Subj, $Act, $Num) = @_;
14544 my %Style = (
14545 "A"=>"new",
14546 "R"=>"failed",
14547 "S"=>"passed",
14548 "L"=>"warning",
14549 "M"=>"failed",
14550 "H"=>"failed"
14551 );
14552 if($Num>0) {
14553 return " class='".$Style{$Act}."'";
14554 }
14555 return "";
14556}
14557
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014558sub show_number($)
14559{
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014560 if($_[0])
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014561 {
Andrey Ponomarenko16934472012-03-29 15:37:04 +040014562 my $Num = cut_off_number($_[0], 2, 0);
14563 if($Num eq "0")
14564 {
14565 foreach my $P (3 .. 7)
14566 {
14567 $Num = cut_off_number($_[0], $P, 1);
14568 if($Num ne "0") {
14569 last;
14570 }
14571 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014572 }
14573 if($Num eq "0") {
14574 $Num = $_[0];
14575 }
14576 return $Num;
14577 }
14578 return $_[0];
14579}
14580
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014581sub cut_off_number($$$)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014582{
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014583 my ($num, $digs_to_cut, $z) = @_;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014584 if($num!~/\./)
14585 {
14586 $num .= ".";
14587 foreach (1 .. $digs_to_cut-1) {
14588 $num .= "0";
14589 }
14590 }
14591 elsif($num=~/\.(.+)\Z/ and length($1)<$digs_to_cut-1)
14592 {
14593 foreach (1 .. $digs_to_cut - 1 - length($1)) {
14594 $num .= "0";
14595 }
14596 }
14597 elsif($num=~/\d+\.(\d){$digs_to_cut,}/) {
14598 $num=sprintf("%.".($digs_to_cut-1)."f", $num);
14599 }
14600 $num=~s/\.[0]+\Z//g;
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014601 if($z) {
14602 $num=~s/(\.[1-9]+)[0]+\Z/$1/g;
14603 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014604 return $num;
14605}
14606
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014607sub get_Report_ChangedConstants($)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014608{
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014609 my $Level = $_[0];
Andrey Ponomarenko16934472012-03-29 15:37:04 +040014610 my $CHANGED_CONSTANTS = "";
14611 my %ReportMap = ();
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014612 foreach my $Constant (keys(%{$ProblemsWithConstants{$Level}})) {
Andrey Ponomarenko16934472012-03-29 15:37:04 +040014613 $ReportMap{$Constants{1}{$Constant}{"Header"}}{$Constant} = 1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014614 }
14615 my $Kind = "Changed_Constant";
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014616 if(not defined $CompatRules{$Level}{$Kind}) {
14617 return "";
14618 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014619 if($ReportFormat eq "xml")
14620 { # XML
Andrey Ponomarenko16934472012-03-29 15:37:04 +040014621 foreach my $HeaderName (sort {lc($a) cmp lc($b)} keys(%ReportMap))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014622 {
14623 $CHANGED_CONSTANTS .= " <header name=\"$HeaderName\">\n";
Andrey Ponomarenko16934472012-03-29 15:37:04 +040014624 foreach my $Constant (sort {lc($a) cmp lc($b)} keys(%{$ReportMap{$HeaderName}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014625 {
14626 $CHANGED_CONSTANTS .= " <constant name=\"$Constant\">\n";
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014627 my $Change = $CompatRules{$Level}{$Kind}{"Change"};
14628 my $Effect = $CompatRules{$Level}{$Kind}{"Effect"};
14629 my $Overcome = $CompatRules{$Level}{$Kind}{"Overcome"};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014630 $CHANGED_CONSTANTS .= " <problem id=\"$Kind\">\n";
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014631 $CHANGED_CONSTANTS .= " <change".getXmlParams($Change, $ProblemsWithConstants{$Level}{$Constant}).">$Change</change>\n";
14632 $CHANGED_CONSTANTS .= " <effect".getXmlParams($Effect, $ProblemsWithConstants{$Level}{$Constant}).">$Effect</effect>\n";
14633 $CHANGED_CONSTANTS .= " <overcome".getXmlParams($Overcome, $ProblemsWithConstants{$Level}{$Constant}).">$Overcome</overcome>\n";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014634 $CHANGED_CONSTANTS .= " </problem>\n";
14635 $CHANGED_CONSTANTS .= " </constant>\n";
14636 }
14637 $CHANGED_CONSTANTS .= " </header>\n";
14638 }
14639 $CHANGED_CONSTANTS = "<problems_with_constants severity=\"Low\">\n".$CHANGED_CONSTANTS."</problems_with_constants>\n\n";
14640 }
14641 else
14642 { # HTML
14643 my $Number = 0;
Andrey Ponomarenko16934472012-03-29 15:37:04 +040014644 foreach my $HeaderName (sort {lc($a) cmp lc($b)} keys(%ReportMap))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014645 {
14646 $CHANGED_CONSTANTS .= "<span class='h_name'>$HeaderName</span><br/>\n";
Andrey Ponomarenko16934472012-03-29 15:37:04 +040014647 foreach my $Name (sort {lc($a) cmp lc($b)} keys(%{$ReportMap{$HeaderName}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014648 {
14649 $Number += 1;
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014650 my $Change = applyMacroses($Level, $Kind, $CompatRules{$Level}{$Kind}{"Change"}, $ProblemsWithConstants{$Level}{$Name});
14651 my $Effect = $CompatRules{$Level}{$Kind}{"Effect"};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014652 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 +040014653 $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 +040014654 $Report = $ContentSpanStart."<span class='extendable'>[+]</span> ".$Name.$ContentSpanEnd."<br/>\n".$Report;
14655 $CHANGED_CONSTANTS .= insertIDs($Report);
14656 }
14657 $CHANGED_CONSTANTS .= "<br/>\n";
14658 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014659 if($CHANGED_CONSTANTS)
14660 {
14661 my $Anchor = "<a name='Changed_Constants'></a>";
14662 if($JoinReport) {
14663 $Anchor = "<a name='".$Level."_Changed_Constants'></a>";
14664 }
14665 $CHANGED_CONSTANTS = $Anchor."<h2>Problems with Constants ($Number)</h2><hr/>\n".$CHANGED_CONSTANTS.$TOP_REF."<br/>\n";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014666 }
14667 }
14668 return $CHANGED_CONSTANTS;
14669}
14670
14671sub get_Report_Impl()
14672{
Andrey Ponomarenko16934472012-03-29 15:37:04 +040014673 my $CHANGED_IMPLEMENTATION = "";
14674 my %ReportMap = ();
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014675 foreach my $Interface (sort keys(%ImplProblems))
14676 {
14677 my $HeaderName = $CompleteSignature{1}{$Interface}{"Header"};
14678 my $DyLib = $Symbol_Library{1}{$Interface};
Andrey Ponomarenko16934472012-03-29 15:37:04 +040014679 $ReportMap{$HeaderName}{$DyLib}{$Interface} = 1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014680 }
14681 my $Changed_Number = 0;
Andrey Ponomarenko16934472012-03-29 15:37:04 +040014682 foreach my $HeaderName (sort {lc($a) cmp lc($b)} keys(%ReportMap))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014683 {
Andrey Ponomarenko16934472012-03-29 15:37:04 +040014684 foreach my $DyLib (sort {lc($a) cmp lc($b)} keys(%{$ReportMap{$HeaderName}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014685 {
14686 my $FDyLib=$DyLib.($DyLib!~/\.\w+\Z/?" (.$LIB_EXT)":"");
14687 if($HeaderName) {
14688 $CHANGED_IMPLEMENTATION .= "<span class='h_name'>$HeaderName</span>, <span class='lib_name'>$FDyLib</span><br/>\n";
14689 }
14690 else {
14691 $CHANGED_IMPLEMENTATION .= "<span class='lib_name'>$DyLib</span><br/>\n";
14692 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014693 my %NameSpaceSymbols = ();
Andrey Ponomarenko16934472012-03-29 15:37:04 +040014694 foreach my $Interface (keys(%{$ReportMap{$HeaderName}{$DyLib}})) {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014695 $NameSpaceSymbols{get_IntNameSpace($Interface, 2)}{$Interface} = 1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014696 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014697 foreach my $NameSpace (sort keys(%NameSpaceSymbols))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014698 {
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040014699 $CHANGED_IMPLEMENTATION .= ($NameSpace)?"<span class='ns_title'>namespace</span> <span class='ns'>$NameSpace</span><br/>\n":"";
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014700 my @SortedInterfaces = sort {lc(get_Signature($a, 1)) cmp lc(get_Signature($b, 1))} keys(%{$NameSpaceSymbols{$NameSpace}});
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014701 foreach my $Interface (@SortedInterfaces)
14702 {
14703 $Changed_Number += 1;
14704 my $Signature = get_Signature($Interface, 1);
14705 if($NameSpace) {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040014706 $Signature=~s/\b\Q$NameSpace\E::\b//g;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014707 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014708 $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 +040014709 }
14710 }
14711 $CHANGED_IMPLEMENTATION .= "<br/>\n";
14712 }
14713 }
14714 if($CHANGED_IMPLEMENTATION) {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014715 $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 +040014716 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +040014717
14718 # clean memory
14719 %ImplProblems = ();
14720
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014721 return $CHANGED_IMPLEMENTATION;
14722}
14723
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014724sub getTitle($$$)
14725{
14726 my ($Header, $Library, $NameSpace) = @_;
14727 my $Title = "";
14728 if($Library and $Library!~/\.\w+\Z/) {
14729 $Library .= " (.$LIB_EXT)";
14730 }
14731 if($Header and $Library)
14732 {
14733 $Title .= "<span class='h_name'>$Header</span>";
14734 $Title .= ", <span class='lib_name'>$Library</span><br/>\n";
14735 }
14736 elsif($Library) {
14737 $Title .= "<span class='lib_name'>$Library</span><br/>\n";
14738 }
14739 elsif($Header) {
14740 $Title .= "<span class='h_name'>$Header</span><br/>\n";
14741 }
14742 if($NameSpace) {
14743 $Title .= "<span class='ns_title'>namespace</span> <span class='ns'>$NameSpace</span><br/>\n";
14744 }
14745 return $Title;
14746}
14747
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014748sub get_Report_Added($)
14749{
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014750 my $Level = $_[0];
Andrey Ponomarenko16934472012-03-29 15:37:04 +040014751 my $ADDED_INTERFACES = "";
14752 my %ReportMap = ();
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014753 foreach my $Interface (sort keys(%{$CompatProblems{$Level}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014754 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014755 foreach my $Kind (sort keys(%{$CompatProblems{$Level}{$Interface}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014756 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014757 if($Kind eq "Added_Symbol")
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014758 {
14759 my $HeaderName = $CompleteSignature{2}{$Interface}{"Header"};
14760 my $DyLib = $Symbol_Library{2}{$Interface};
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014761 if($Level eq "Source" and $ReportFormat eq "html")
14762 { # do not show library name in HTML report
14763 $DyLib = "";
14764 }
14765 $ReportMap{$HeaderName}{$DyLib}{$Interface} = 1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014766 }
14767 }
14768 }
14769 if($ReportFormat eq "xml")
14770 { # XML
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014771 foreach my $HeaderName (sort {lc($a) cmp lc($b)} keys(%ReportMap))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014772 {
14773 $ADDED_INTERFACES .= " <header name=\"$HeaderName\">\n";
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014774 foreach my $DyLib (sort {lc($a) cmp lc($b)} keys(%{$ReportMap{$HeaderName}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014775 {
14776 $ADDED_INTERFACES .= " <library name=\"$DyLib\">\n";
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014777 foreach my $Interface (keys(%{$ReportMap{$HeaderName}{$DyLib}})) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014778 $ADDED_INTERFACES .= " <name>$Interface</name>\n";
14779 }
14780 $ADDED_INTERFACES .= " </library>\n";
14781 }
14782 $ADDED_INTERFACES .= " </header>\n";
14783 }
14784 $ADDED_INTERFACES = "<added_symbols>\n".$ADDED_INTERFACES."</added_symbols>\n\n";
14785 }
14786 else
14787 { # HTML
14788 my $Added_Number = 0;
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014789 foreach my $HeaderName (sort {lc($a) cmp lc($b)} keys(%ReportMap))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014790 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014791 foreach my $DyLib (sort {lc($a) cmp lc($b)} keys(%{$ReportMap{$HeaderName}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014792 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014793 my %NameSpaceSymbols = ();
14794 foreach my $Interface (keys(%{$ReportMap{$HeaderName}{$DyLib}})) {
14795 $NameSpaceSymbols{get_IntNameSpace($Interface, 2)}{$Interface} = 1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014796 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014797 foreach my $NameSpace (sort keys(%NameSpaceSymbols))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014798 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014799 $ADDED_INTERFACES .= getTitle($HeaderName, $DyLib, $NameSpace);
14800 my @SortedInterfaces = sort {lc(get_Signature($a, 2)) cmp lc(get_Signature($b, 2))} keys(%{$NameSpaceSymbols{$NameSpace}});
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014801 foreach my $Interface (@SortedInterfaces)
14802 {
14803 $Added_Number += 1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014804 my $Signature = get_Signature($Interface, 2);
14805 if($NameSpace) {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040014806 $Signature=~s/\b\Q$NameSpace\E::\b//g;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014807 }
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040014808 if($Interface=~/\A(_Z|\?)/)
14809 {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014810 if($Signature) {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014811 $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 +040014812 }
14813 else {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014814 $ADDED_INTERFACES .= "<span class=\"iname\">".$Interface."</span><br/>\n";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014815 }
14816 }
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040014817 else
14818 {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014819 if($Signature) {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014820 $ADDED_INTERFACES .= "<span class=\"iname\">".highLight_Signature_Italic_Color($Signature)."</span><br/>\n";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014821 }
14822 else {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014823 $ADDED_INTERFACES .= "<span class=\"iname\">".$Interface."</span><br/>\n";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014824 }
14825 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014826 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014827 $ADDED_INTERFACES .= "<br/>\n";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014828 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014829 }
14830 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014831 if($ADDED_INTERFACES)
14832 {
14833 my $Anchor = "<a name='Added'></a>";
14834 if($JoinReport) {
14835 $Anchor = "<a name='".$Level."_Added'></a>";
14836 }
14837 $ADDED_INTERFACES = $Anchor."<h2>Added Symbols ($Added_Number)</h2><hr/>\n".$ADDED_INTERFACES.$TOP_REF."<br/>\n";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014838 }
14839 }
14840 return $ADDED_INTERFACES;
14841}
14842
14843sub get_Report_Removed($)
14844{
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014845 my $Level = $_[0];
Andrey Ponomarenko16934472012-03-29 15:37:04 +040014846 my $REMOVED_INTERFACES = "";
14847 my %ReportMap = ();
Andrey Ponomarenko85043792012-05-14 16:48:07 +040014848 foreach my $Symbol (sort keys(%{$CompatProblems{$Level}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014849 {
Andrey Ponomarenko85043792012-05-14 16:48:07 +040014850 foreach my $Kind (sort keys(%{$CompatProblems{$Level}{$Symbol}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014851 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014852 if($Kind eq "Removed_Symbol")
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014853 {
Andrey Ponomarenko85043792012-05-14 16:48:07 +040014854 my $HeaderName = $CompleteSignature{1}{$Symbol}{"Header"};
14855 my $DyLib = $Symbol_Library{1}{$Symbol};
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014856 if($Level eq "Source" and $ReportFormat eq "html")
14857 { # do not show library name in HTML report
14858 $DyLib = "";
14859 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +040014860 $ReportMap{$HeaderName}{$DyLib}{$Symbol} = 1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014861 }
14862 }
14863 }
14864 if($ReportFormat eq "xml")
14865 { # XML
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014866 foreach my $HeaderName (sort {lc($a) cmp lc($b)} keys(%ReportMap))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014867 {
14868 $REMOVED_INTERFACES .= " <header name=\"$HeaderName\">\n";
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014869 foreach my $DyLib (sort {lc($a) cmp lc($b)} keys(%{$ReportMap{$HeaderName}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014870 {
14871 $REMOVED_INTERFACES .= " <library name=\"$DyLib\">\n";
Andrey Ponomarenko85043792012-05-14 16:48:07 +040014872 foreach my $Symbol (keys(%{$ReportMap{$HeaderName}{$DyLib}})) {
14873 $REMOVED_INTERFACES .= " <name>$Symbol</name>\n";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014874 }
14875 $REMOVED_INTERFACES .= " </library>\n";
14876 }
14877 $REMOVED_INTERFACES .= " </header>\n";
14878 }
14879 $REMOVED_INTERFACES = "<removed_symbols>\n".$REMOVED_INTERFACES."</removed_symbols>\n\n";
14880 }
14881 else
14882 { # HTML
14883 my $Removed_Number = 0;
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014884 foreach my $HeaderName (sort {lc($a) cmp lc($b)} keys(%ReportMap))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014885 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014886 foreach my $DyLib (sort {lc($a) cmp lc($b)} keys(%{$ReportMap{$HeaderName}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014887 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014888 my %NameSpaceSymbols = ();
14889 foreach my $Interface (keys(%{$ReportMap{$HeaderName}{$DyLib}})) {
14890 $NameSpaceSymbols{get_IntNameSpace($Interface, 1)}{$Interface} = 1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014891 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014892 foreach my $NameSpace (sort keys(%NameSpaceSymbols))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014893 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014894 $REMOVED_INTERFACES .= getTitle($HeaderName, $DyLib, $NameSpace);
14895 my @SortedInterfaces = sort {lc(get_Signature($a, 1)) cmp lc(get_Signature($b, 1))} keys(%{$NameSpaceSymbols{$NameSpace}});
Andrey Ponomarenko85043792012-05-14 16:48:07 +040014896 foreach my $Symbol (@SortedInterfaces)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014897 {
14898 $Removed_Number += 1;
14899 my $SubReport = "";
Andrey Ponomarenko85043792012-05-14 16:48:07 +040014900 my $Signature = get_Signature($Symbol, 1);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014901 if($NameSpace) {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040014902 $Signature=~s/\b\Q$NameSpace\E::\b//g;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014903 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +040014904 if($Symbol=~/\A(_Z|\?)/)
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014905 {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014906 if($Signature) {
Andrey Ponomarenko85043792012-05-14 16:48:07 +040014907 $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 +040014908 }
14909 else {
Andrey Ponomarenko85043792012-05-14 16:48:07 +040014910 $REMOVED_INTERFACES .= "<span class=\"iname\">".$Symbol."</span><br/>\n";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014911 }
14912 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014913 else
14914 {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014915 if($Signature) {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014916 $REMOVED_INTERFACES .= "<span class=\"iname\">".highLight_Signature_Italic_Color($Signature)."</span><br/>\n";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014917 }
14918 else {
Andrey Ponomarenko85043792012-05-14 16:48:07 +040014919 $REMOVED_INTERFACES .= "<span class=\"iname\">".$Symbol."</span><br/>\n";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014920 }
14921 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014922 }
14923 }
14924 $REMOVED_INTERFACES .= "<br/>\n";
14925 }
14926 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014927 if($REMOVED_INTERFACES)
14928 {
14929 my $Anchor = "<a name='Removed'></a><a name='Withdrawn'></a>";
14930 if($JoinReport) {
14931 $Anchor = "<a name='".$Level."_Removed'></a><a name='".$Level."_Withdrawn'></a>";
14932 }
14933 $REMOVED_INTERFACES = $Anchor."<h2>Removed Symbols ($Removed_Number)</h2><hr/>\n".$REMOVED_INTERFACES.$TOP_REF."<br/>\n";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014934 }
14935 }
14936 return $REMOVED_INTERFACES;
14937}
14938
14939sub getXmlParams($$)
14940{
14941 my ($Content, $Problem) = @_;
14942 return "" if(not $Content or not $Problem);
14943 my %XMLparams = ();
14944 foreach my $Attr (sort {$b cmp $a} keys(%{$Problem}))
14945 {
14946 my $Macro = "\@".lc($Attr);
14947 if($Content=~/\Q$Macro\E/) {
14948 $XMLparams{lc($Attr)} = $Problem->{$Attr};
14949 }
14950 }
14951 my @PString = ();
14952 foreach my $P (sort {$b cmp $a} keys(%XMLparams)) {
Andrey Ponomarenko5c09ef32012-06-14 18:17:33 +040014953 push(@PString, $P."=\"".xmlSpecChars($XMLparams{$P})."\"");
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014954 }
14955 if(@PString) {
14956 return " ".join(" ", @PString);
14957 }
14958 else {
14959 return "";
14960 }
14961}
14962
14963sub addMarkup($)
14964{
14965 my $Content = $_[0];
14966 # auto-markup
14967 $Content=~s/\n[ ]*//; # spaces
14968 $Content=~s!(\@\w+\s*\(\@\w+\))!<nowrap>$1</nowrap>!g; # @old_type (@old_size)
14969 $Content=~s!(... \(\w+\))!<nowrap><b>$1</b></nowrap>!g; # ... (va_list)
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040014970 $Content=~s!<nowrap>(.+?)</nowrap>!<span class='nowrap'>$1</span>!g;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014971 $Content=~s!([2-9]\))!<br/>$1!g; # 1), 2), ...
14972 if($Content=~/\ANOTE:/)
14973 { # notes
14974 $Content=~s!(NOTE):!<b>$1</b>:!g;
14975 }
14976 else {
14977 $Content=~s!(NOTE):!<br/><b>$1</b>:!g;
14978 }
14979 $Content=~s! (out)-! <b>$1</b>-!g; # out-parameters
14980 my @Keywords = (
14981 "void",
14982 "const",
14983 "static",
14984 "restrict",
14985 "volatile",
14986 "register",
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040014987 "virtual"
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014988 );
14989 my $MKeys = join("|", @Keywords);
14990 foreach (@Keywords) {
14991 $MKeys .= "|non-".$_;
14992 }
14993 $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 +040014994
14995 # Markdown
14996 $Content=~s!\*\*([\w\-]+)\*\*!<b>$1</b>!ig;
14997 $Content=~s!\*([\w\-]+)\*!<i>$1</i>!ig;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014998 return $Content;
14999}
15000
15001sub applyMacroses($$$$)
15002{
15003 my ($Level, $Kind, $Content, $Problem) = @_;
15004 return "" if(not $Content or not $Problem);
15005 $Problem->{"Word_Size"} = $WORD_SIZE{2};
15006 $Content = addMarkup($Content);
15007 # macros
15008 foreach my $Attr (sort {$b cmp $a} keys(%{$Problem}))
15009 {
15010 my $Macro = "\@".lc($Attr);
15011 my $Value = $Problem->{$Attr};
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040015012 if(not defined $Value
15013 or $Value eq "") {
15014 next;
15015 }
Andrey Ponomarenko5c09ef32012-06-14 18:17:33 +040015016 if($Value=~/\s\(/ and $Value!~/['"]/)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015017 { # functions
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015018 $Value=~s/\s*\[[\w\-]+\]//g; # remove quals
15019 $Value=~s/\s\w+(\)|,)/$1/g; # remove parameter names
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015020 $Value = black_name($Value);
15021 }
15022 elsif($Value=~/\s/) {
15023 $Value = "<span class='value'>".htmlSpecChars($Value)."</span>";
15024 }
15025 elsif($Value=~/\A\d+\Z/
15026 and ($Attr eq "Old_Size" or $Attr eq "New_Size"))
15027 { # bits to bytes
15028 if($Value % $BYTE_SIZE)
15029 { # bits
15030 if($Value==1) {
15031 $Value = "<b>".$Value."</b> bit";
15032 }
15033 else {
15034 $Value = "<b>".$Value."</b> bits";
15035 }
15036 }
15037 else
15038 { # bytes
15039 $Value /= $BYTE_SIZE;
15040 if($Value==1) {
15041 $Value = "<b>".$Value."</b> byte";
15042 }
15043 else {
15044 $Value = "<b>".$Value."</b> bytes";
15045 }
15046 }
15047 }
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040015048 else
15049 {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015050 $Value = "<b>".htmlSpecChars($Value)."</b>";
15051 }
15052 $Content=~s/\Q$Macro\E/$Value/g;
15053 }
15054
15055 if($Content=~/(\A|[^\@\w])\@\w/)
15056 {
15057 if(not $IncompleteRules{$Level}{$Kind})
15058 { # only one warning
15059 printMsg("WARNING", "incomplete rule \"$Kind\" (\"$Level\")");
15060 $IncompleteRules{$Level}{$Kind} = 1;
15061 }
15062 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015063 return $Content;
15064}
15065
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040015066sub get_Report_SymbolProblems($$)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015067{
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015068 my ($TargetSeverity, $Level) = @_;
Andrey Ponomarenko16934472012-03-29 15:37:04 +040015069 my $INTERFACE_PROBLEMS = "";
15070 my (%ReportMap, %SymbolChanges) = ();
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015071 foreach my $Symbol (sort keys(%{$CompatProblems{$Level}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015072 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015073 my ($SN, $SS, $SV) = separate_symbol($Symbol);
15074 if($SV and defined $CompatProblems{$Level}{$SN}) {
15075 next;
15076 }
15077 foreach my $Kind (sort keys(%{$CompatProblems{$Level}{$Symbol}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015078 {
15079 if($CompatRules{$Level}{$Kind}{"Kind"} eq "Symbols"
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015080 and $Kind ne "Added_Symbol" and $Kind ne "Removed_Symbol")
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015081 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015082 my $HeaderName = $CompleteSignature{1}{$Symbol}{"Header"};
15083 my $DyLib = $Symbol_Library{1}{$Symbol};
15084 if(not $DyLib and my $VSym = $SymVer{1}{$Symbol})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015085 { # Symbol with Version
15086 $DyLib = $Symbol_Library{1}{$VSym};
15087 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040015088 if(not $DyLib)
15089 { # const global data
15090 $DyLib = "";
15091 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015092 if($Level eq "Source" and $ReportFormat eq "html")
15093 { # do not show library name in HTML report
15094 $DyLib = "";
15095 }
15096 %{$SymbolChanges{$Symbol}{$Kind}} = %{$CompatProblems{$Level}{$Symbol}{$Kind}};
15097 foreach my $Location (sort keys(%{$SymbolChanges{$Symbol}{$Kind}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015098 {
15099 my $Priority = getProblemSeverity($Level, $Kind);
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015100 if($Priority ne $TargetSeverity) {
15101 delete($SymbolChanges{$Symbol}{$Kind}{$Location});
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015102 }
15103 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015104 if(not keys(%{$SymbolChanges{$Symbol}{$Kind}}))
15105 {
15106 delete($SymbolChanges{$Symbol}{$Kind});
15107 next;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015108 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015109 $ReportMap{$HeaderName}{$DyLib}{$Symbol} = 1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015110 }
15111 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015112 if(not keys(%{$SymbolChanges{$Symbol}})) {
15113 delete($SymbolChanges{$Symbol});
15114 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015115 }
15116 if($ReportFormat eq "xml")
15117 { # XML
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015118 foreach my $HeaderName (sort {lc($a) cmp lc($b)} keys(%ReportMap))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015119 {
15120 $INTERFACE_PROBLEMS .= " <header name=\"$HeaderName\">\n";
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015121 foreach my $DyLib (sort {lc($a) cmp lc($b)} keys(%{$ReportMap{$HeaderName}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015122 {
15123 $INTERFACE_PROBLEMS .= " <library name=\"$DyLib\">\n";
15124 foreach my $Symbol (sort {lc($tr_name{$a}) cmp lc($tr_name{$b})} keys(%SymbolChanges))
15125 {
15126 $INTERFACE_PROBLEMS .= " <symbol name=\"$Symbol\">\n";
15127 foreach my $Kind (keys(%{$SymbolChanges{$Symbol}}))
15128 {
15129 foreach my $Location (sort keys(%{$SymbolChanges{$Symbol}{$Kind}}))
15130 {
15131 my %Problem = %{$SymbolChanges{$Symbol}{$Kind}{$Location}};
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040015132 $Problem{"Param_Pos"} = showPos($Problem{"Param_Pos"});
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015133 $INTERFACE_PROBLEMS .= " <problem id=\"$Kind\">\n";
15134 my $Change = $CompatRules{$Level}{$Kind}{"Change"};
15135 $INTERFACE_PROBLEMS .= " <change".getXmlParams($Change, \%Problem).">$Change</change>\n";
15136 my $Effect = $CompatRules{$Level}{$Kind}{"Effect"};
15137 $INTERFACE_PROBLEMS .= " <effect".getXmlParams($Effect, \%Problem).">$Effect</effect>\n";
15138 my $Overcome = $CompatRules{$Level}{$Kind}{"Overcome"};
15139 $INTERFACE_PROBLEMS .= " <overcome".getXmlParams($Overcome, \%Problem).">$Overcome</overcome>\n";
15140 $INTERFACE_PROBLEMS .= " </problem>\n";
15141 }
15142 }
15143 $INTERFACE_PROBLEMS .= " </symbol>\n";
15144 }
15145 $INTERFACE_PROBLEMS .= " </library>\n";
15146 }
15147 $INTERFACE_PROBLEMS .= " </header>\n";
15148 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015149 $INTERFACE_PROBLEMS = "<problems_with_symbols severity=\"$TargetSeverity\">\n".$INTERFACE_PROBLEMS."</problems_with_symbols>\n\n";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015150 }
15151 else
15152 { # HTML
15153 my $ProblemsNum = 0;
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015154 foreach my $HeaderName (sort {lc($a) cmp lc($b)} keys(%ReportMap))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015155 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015156 foreach my $DyLib (sort {lc($a) cmp lc($b)} keys(%{$ReportMap{$HeaderName}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015157 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015158 my (%NameSpaceSymbols, %NewSignature) = ();
15159 foreach my $Symbol (keys(%{$ReportMap{$HeaderName}{$DyLib}})) {
15160 $NameSpaceSymbols{get_IntNameSpace($Symbol, 1)}{$Symbol} = 1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015161 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015162 foreach my $NameSpace (sort keys(%NameSpaceSymbols))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015163 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015164 $INTERFACE_PROBLEMS .= getTitle($HeaderName, $DyLib, $NameSpace);
15165 my @SortedInterfaces = sort {lc($tr_name{$a}) cmp lc($tr_name{$b})} keys(%{$NameSpaceSymbols{$NameSpace}});
15166 foreach my $Symbol (@SortedInterfaces)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015167 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015168 my $Signature = get_Signature($Symbol, 1);
15169 my $SYMBOL_REPORT = "";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015170 my $ProblemNum = 1;
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015171 foreach my $Kind (keys(%{$SymbolChanges{$Symbol}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015172 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015173 foreach my $Location (sort keys(%{$SymbolChanges{$Symbol}{$Kind}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015174 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015175 my %Problem = %{$SymbolChanges{$Symbol}{$Kind}{$Location}};
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040015176 $Problem{"Param_Pos"} = showPos($Problem{"Param_Pos"});
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015177 if($Problem{"New_Signature"}) {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015178 $NewSignature{$Symbol} = $Problem{"New_Signature"};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015179 }
15180 if(my $Change = applyMacroses($Level, $Kind, $CompatRules{$Level}{$Kind}{"Change"}, \%Problem))
15181 {
15182 my $Effect = applyMacroses($Level, $Kind, $CompatRules{$Level}{$Kind}{"Effect"}, \%Problem);
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015183 $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 +040015184 $ProblemNum += 1;
15185 $ProblemsNum += 1;
15186 }
15187 }
15188 }
15189 $ProblemNum -= 1;
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015190 if($SYMBOL_REPORT)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015191 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015192 $INTERFACE_PROBLEMS .= $ContentSpanStart."<span class='extendable'>[+]</span> ";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015193 if($Signature) {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015194 $INTERFACE_PROBLEMS .= highLight_Signature_Italic_Color($Signature);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015195 }
15196 else {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015197 $INTERFACE_PROBLEMS .= $Symbol;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015198 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015199 $INTERFACE_PROBLEMS .= " ($ProblemNum)".$ContentSpanEnd."<br/>\n";
15200 $INTERFACE_PROBLEMS .= $ContentDivStart."\n";
15201 if($NewSignature{$Symbol})
15202 { # argument list changed to
15203 $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 +040015204 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015205 if($Symbol=~/\A(_Z|\?)/) {
15206 $INTERFACE_PROBLEMS .= "<span class='mangled'>&#160;&#160;&#160;&#160;[symbol: <b>$Symbol</b>]</span><br/>\n";
15207 }
15208 $INTERFACE_PROBLEMS .= "<table class='ptable'><tr><th width='2%'></th><th width='47%'>Change</th><th>Effect</th></tr>$SYMBOL_REPORT</table><br/>\n";
15209 $INTERFACE_PROBLEMS .= $ContentDivEnd;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015210 if($NameSpace) {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040015211 $INTERFACE_PROBLEMS=~s/\b\Q$NameSpace\E::\b//g;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015212 }
15213 }
15214 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015215 $INTERFACE_PROBLEMS .= "<br/>";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015216 }
15217 }
15218 }
15219 if($INTERFACE_PROBLEMS)
15220 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015221 $INTERFACE_PROBLEMS = insertIDs($INTERFACE_PROBLEMS);
15222 my $Title = "Problems with Symbols, $TargetSeverity Severity";
15223 if($TargetSeverity eq "Safe")
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015224 { # Safe Changes
15225 $Title = "Other Changes in Symbols";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015226 }
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040015227 $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 +040015228 }
15229 }
15230 return $INTERFACE_PROBLEMS;
15231}
15232
15233sub get_Report_TypeProblems($$)
15234{
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015235 my ($TargetSeverity, $Level) = @_;
Andrey Ponomarenko16934472012-03-29 15:37:04 +040015236 my $TYPE_PROBLEMS = "";
15237 my (%ReportMap, %TypeChanges, %TypeType) = ();
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015238 foreach my $Interface (sort keys(%{$CompatProblems{$Level}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015239 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015240 foreach my $Kind (keys(%{$CompatProblems{$Level}{$Interface}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015241 {
15242 if($CompatRules{$Level}{$Kind}{"Kind"} eq "Types")
15243 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015244 foreach my $Location (sort {cmp_locations($b, $a)} sort keys(%{$CompatProblems{$Level}{$Interface}{$Kind}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015245 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015246 my $TypeName = $CompatProblems{$Level}{$Interface}{$Kind}{$Location}{"Type_Name"};
15247 my $TypeType = $CompatProblems{$Level}{$Interface}{$Kind}{$Location}{"Type_Type"};
15248 my $Target = $CompatProblems{$Level}{$Interface}{$Kind}{$Location}{"Target"};
15249 $CompatProblems{$Level}{$Interface}{$Kind}{$Location}{"Type_Type"} = lc($TypeType);
15250 my $Severity = getProblemSeverity($Level, $Kind);
15251 if($Severity eq "Safe"
15252 and $TargetSeverity ne "Safe") {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015253 next;
15254 }
15255 if(not $TypeType{$TypeName}
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015256 or $TypeType{$TypeName} eq "struct")
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015257 { # register type of the type, select "class" if type has "class"- and "struct"-type changes
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015258 $TypeType{$TypeName} = $CompatProblems{$Level}{$Interface}{$Kind}{$Location}{"Type_Type"};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015259 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015260
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040015261 if(cmpSeverities($Type_MaxSeverity{$Level}{$TypeName}{$Kind}{$Target}, $Severity))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015262 { # select a problem with the highest priority
15263 next;
15264 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015265 %{$TypeChanges{$TypeName}{$Kind}{$Location}} = %{$CompatProblems{$Level}{$Interface}{$Kind}{$Location}};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015266 }
15267 }
15268 }
15269 }
15270 my %Kinds_Locations = ();
15271 foreach my $TypeName (keys(%TypeChanges))
15272 {
15273 my %Kinds_Target = ();
15274 foreach my $Kind (sort keys(%{$TypeChanges{$TypeName}}))
15275 {
15276 foreach my $Location (sort {cmp_locations($b, $a)} sort keys(%{$TypeChanges{$TypeName}{$Kind}}))
15277 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015278 my $Severity = getProblemSeverity($Level, $Kind);
15279 if($Severity ne $TargetSeverity)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015280 { # other priority
15281 delete($TypeChanges{$TypeName}{$Kind}{$Location});
15282 next;
15283 }
15284 $Kinds_Locations{$TypeName}{$Kind}{$Location} = 1;
15285 my $Target = $TypeChanges{$TypeName}{$Kind}{$Location}{"Target"};
15286 if($Kinds_Target{$Kind}{$Target})
15287 { # duplicate target
15288 delete($TypeChanges{$TypeName}{$Kind}{$Location});
15289 next;
15290 }
15291 $Kinds_Target{$Kind}{$Target} = 1;
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040015292 my $HeaderName = $TypeInfo{1}{$TName_Tid{1}{$TypeName}}{"Header"};
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015293 $ReportMap{$HeaderName}{$TypeName} = 1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015294 }
15295 if(not keys(%{$TypeChanges{$TypeName}{$Kind}})) {
15296 delete($TypeChanges{$TypeName}{$Kind});
15297 }
15298 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015299 if(not keys(%{$TypeChanges{$TypeName}})) {
15300 delete($TypeChanges{$TypeName});
15301 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015302 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +040015303 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 +040015304 if($ReportFormat eq "xml")
15305 { # XML
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015306 foreach my $HeaderName (sort {lc($a) cmp lc($b)} keys(%ReportMap))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015307 {
15308 $TYPE_PROBLEMS .= " <header name=\"$HeaderName\">\n";
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015309 foreach my $TypeName (keys(%{$ReportMap{$HeaderName}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015310 {
Andrey Ponomarenko5c09ef32012-06-14 18:17:33 +040015311 $TYPE_PROBLEMS .= " <type name=\"".xmlSpecChars($TypeName)."\">\n";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015312 foreach my $Kind (sort {$b=~/Size/ <=> $a=~/Size/} sort keys(%{$TypeChanges{$TypeName}}))
15313 {
15314 foreach my $Location (sort {cmp_locations($b, $a)} sort keys(%{$TypeChanges{$TypeName}{$Kind}}))
15315 {
15316 my %Problem = %{$TypeChanges{$TypeName}{$Kind}{$Location}};
15317 $TYPE_PROBLEMS .= " <problem id=\"$Kind\">\n";
15318 my $Change = $CompatRules{$Level}{$Kind}{"Change"};
15319 $TYPE_PROBLEMS .= " <change".getXmlParams($Change, \%Problem).">$Change</change>\n";
15320 my $Effect = $CompatRules{$Level}{$Kind}{"Effect"};
15321 $TYPE_PROBLEMS .= " <effect".getXmlParams($Effect, \%Problem).">$Effect</effect>\n";
15322 my $Overcome = $CompatRules{$Level}{$Kind}{"Overcome"};
15323 $TYPE_PROBLEMS .= " <overcome".getXmlParams($Overcome, \%Problem).">$Overcome</overcome>\n";
15324 $TYPE_PROBLEMS .= " </problem>\n";
15325 }
15326 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +040015327 $TYPE_PROBLEMS .= getAffectedSymbols($Level, $TypeName, $Kinds_Locations{$TypeName}, \@Symbols);
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015328 if($Level eq "Binary" and grep {$_=~/Virtual|Base_Class/} keys(%{$Kinds_Locations{$TypeName}})) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015329 $TYPE_PROBLEMS .= showVTables($TypeName);
15330 }
15331 $TYPE_PROBLEMS .= " </type>\n";
15332 }
15333 $TYPE_PROBLEMS .= " </header>\n";
15334 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015335 $TYPE_PROBLEMS = "<problems_with_types severity=\"$TargetSeverity\">\n".$TYPE_PROBLEMS."</problems_with_types>\n\n";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015336 }
15337 else
15338 { # HTML
15339 my $ProblemsNum = 0;
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015340 foreach my $HeaderName (sort {lc($a) cmp lc($b)} keys(%ReportMap))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015341 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015342 my (%NameSpace_Type) = ();
15343 foreach my $TypeName (keys(%{$ReportMap{$HeaderName}})) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015344 $NameSpace_Type{parse_TypeNameSpace($TypeName, 1)}{$TypeName} = 1;
15345 }
15346 foreach my $NameSpace (sort keys(%NameSpace_Type))
15347 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015348 $TYPE_PROBLEMS .= getTitle($HeaderName, "", $NameSpace);
15349 my @SortedTypes = sort {$TypeType{$a}." ".lc($a) cmp $TypeType{$b}." ".lc($b)} keys(%{$NameSpace_Type{$NameSpace}});
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015350 foreach my $TypeName (@SortedTypes)
15351 {
15352 my $ProblemNum = 1;
15353 my $TYPE_REPORT = "";
15354 foreach my $Kind (sort {$b=~/Size/ <=> $a=~/Size/} sort keys(%{$TypeChanges{$TypeName}}))
15355 {
15356 foreach my $Location (sort {cmp_locations($b, $a)} sort keys(%{$TypeChanges{$TypeName}{$Kind}}))
15357 {
15358 my %Problem = %{$TypeChanges{$TypeName}{$Kind}{$Location}};
15359 if(my $Change = applyMacroses($Level, $Kind, $CompatRules{$Level}{$Kind}{"Change"}, \%Problem))
15360 {
15361 my $Effect = applyMacroses($Level, $Kind, $CompatRules{$Level}{$Kind}{"Effect"}, \%Problem);
15362 $TYPE_REPORT .= "<tr><th>$ProblemNum</th><td align='left' valign='top'>".$Change."</td><td align='left' valign='top'>$Effect</td></tr>\n";
15363 $ProblemNum += 1;
15364 $ProblemsNum += 1;
15365 }
15366 }
15367 }
15368 $ProblemNum -= 1;
15369 if($TYPE_REPORT)
15370 {
Andrey Ponomarenko85043792012-05-14 16:48:07 +040015371 my $Affected = getAffectedSymbols($Level, $TypeName, $Kinds_Locations{$TypeName}, \@Symbols);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015372 my $ShowVTables = "";
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015373 if($Level eq "Binary" and grep {$_=~/Virtual|Base_Class/} keys(%{$Kinds_Locations{$TypeName}})) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015374 $ShowVTables = showVTables($TypeName);
15375 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015376 $TYPE_PROBLEMS .= $ContentSpanStart."<span class='extendable'>[+]</span> <span class='ttype'>".$TypeType{$TypeName}."</span> ".htmlSpecChars($TypeName)." ($ProblemNum)".$ContentSpanEnd;
15377 $TYPE_PROBLEMS .= "<br/>\n".$ContentDivStart."<table class='ptable'><tr>\n";
15378 $TYPE_PROBLEMS .= "<th width='2%'></th><th width='47%'>Change</th>\n";
15379 $TYPE_PROBLEMS .= "<th>Effect</th></tr>".$TYPE_REPORT."</table>\n";
15380 $TYPE_PROBLEMS .= $ShowVTables.$Affected."<br/><br/>".$ContentDivEnd."\n";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015381 if($NameSpace) {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040015382 $TYPE_PROBLEMS=~s/\b\Q$NameSpace\E::(\w|\~)/$1/g;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015383 }
15384 }
15385 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015386 $TYPE_PROBLEMS .= "<br/>";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015387 }
15388 }
15389 if($TYPE_PROBLEMS)
15390 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015391 $TYPE_PROBLEMS = insertIDs($TYPE_PROBLEMS);
15392 my $Title = "Problems with Data Types, $TargetSeverity Severity";
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015393 if($TargetSeverity eq "Safe")
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015394 { # Safe Changes
15395 $Title = "Other Changes in Data Types";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015396 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015397 $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 +040015398 }
15399 }
15400 return $TYPE_PROBLEMS;
15401}
15402
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015403sub get_Anchor($$$)
15404{
15405 my ($Kind, $Level, $Severity) = @_;
15406 if($JoinReport)
15407 {
15408 if($Severity eq "Safe") {
15409 return "Other_".$Level."_Changes_In_".$Kind."s";
15410 }
15411 else {
15412 return $Kind."_".$Level."_Problems_".$Severity;
15413 }
15414 }
15415 else
15416 {
15417 if($Severity eq "Safe") {
15418 return "Other_Changes_In_".$Kind."s";
15419 }
15420 else {
15421 return $Kind."_Problems_".$Severity;
15422 }
15423 }
15424}
15425
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015426sub showVTables($)
15427{
15428 my $TypeName = $_[0];
15429 my $TypeId1 = $TName_Tid{1}{$TypeName};
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040015430 my %Type1 = get_Type($TypeId1, 1);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015431 if(defined $Type1{"VTable"}
15432 and keys(%{$Type1{"VTable"}}))
15433 {
15434 my $TypeId2 = $TName_Tid{2}{$TypeName};
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040015435 my %Type2 = get_Type($TypeId2, 2);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015436 if(defined $Type2{"VTable"}
15437 and keys(%{$Type2{"VTable"}}))
15438 {
15439 my %Indexes = map {$_=>1} (keys(%{$Type1{"VTable"}}), keys(%{$Type2{"VTable"}}));
15440 my %Entries = ();
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015441 foreach my $Index (sort {int($a)<=>int($b)} (keys(%Indexes)))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015442 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015443 $Entries{$Index}{"E1"} = simpleVEntry($Type1{"VTable"}{$Index});
15444 $Entries{$Index}{"E2"} = simpleVEntry($Type2{"VTable"}{$Index});
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015445 }
15446 my $VTABLES = "";
15447 if($ReportFormat eq "xml")
15448 { # XML
15449 $VTABLES .= " <vtable>\n";
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015450 foreach my $Index (sort {int($a)<=>int($b)} (keys(%Entries)))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015451 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015452 $VTABLES .= " <entry offset=\"".$Index."\">\n";
Andrey Ponomarenko5c09ef32012-06-14 18:17:33 +040015453 $VTABLES .= " <old>".xmlSpecChars($Entries{$Index}{"E1"})."</old>\n";
15454 $VTABLES .= " <new>".xmlSpecChars($Entries{$Index}{"E2"})."</new>\n";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015455 $VTABLES .= " </entry>\n";
15456 }
15457 $VTABLES .= " </vtable>\n\n";
15458 }
15459 else
15460 { # HTML
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015461 $VTABLES .= "<table class='vtable'>";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015462 $VTABLES .= "<tr><th width='2%'>Offset</th>";
15463 $VTABLES .= "<th width='45%'>Virtual Table (Old) - ".(keys(%{$Type1{"VTable"}}))." entries</th>";
15464 $VTABLES .= "<th>Virtual Table (New) - ".(keys(%{$Type2{"VTable"}}))." entries</th></tr>";
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015465 foreach my $Index (sort {int($a)<=>int($b)} (keys(%Entries)))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015466 {
15467 my ($Color1, $Color2) = ("", "");
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015468 if($Entries{$Index}{"E1"} ne $Entries{$Index}{"E2"})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015469 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015470 if($Entries{$Index}{"E1"})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015471 {
Andrey Ponomarenko16934472012-03-29 15:37:04 +040015472 $Color1 = " class='failed'";
15473 $Color2 = " class='failed'";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015474 }
15475 else {
Andrey Ponomarenko16934472012-03-29 15:37:04 +040015476 $Color2 = " class='warning'";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015477 }
15478 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015479 $VTABLES .= "<tr><th>".$Index."</th>\n";
15480 $VTABLES .= "<td$Color1>".htmlSpecChars($Entries{$Index}{"E1"})."</td>\n";
15481 $VTABLES .= "<td$Color2>".htmlSpecChars($Entries{$Index}{"E2"})."</td></tr>\n";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015482 }
15483 $VTABLES .= "</table><br/>\n";
15484 $VTABLES = $ContentDivStart.$VTABLES.$ContentDivEnd;
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015485 $VTABLES = $ContentSpanStart_Info."[+] show v-table (old and new)".$ContentSpanEnd."<br/>\n".$VTABLES;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015486 }
15487 return $VTABLES;
15488 }
15489 }
15490 return "";
15491}
15492
15493sub simpleVEntry($)
15494{
15495 my $VEntry = $_[0];
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040015496 if(not defined $VEntry
15497 or $VEntry eq "") {
15498 return "";
15499 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015500 $VEntry=~s/\A(.+)::(_ZThn.+)\Z/$2/; # thunks
15501 $VEntry=~s/_ZTI\w+/typeinfo/g; # typeinfo
15502 if($VEntry=~/\A_ZThn.+\Z/) {
15503 $VEntry = "non-virtual thunk";
15504 }
15505 $VEntry=~s/\A\(int \(\*\)\(...\)\)([^\(\d])/$1/i;
15506 # support for old GCC versions
15507 $VEntry=~s/\A0u\Z/(int (*)(...))0/;
15508 $VEntry=~s/\A4294967268u\Z/(int (*)(...))-0x000000004/;
15509 $VEntry=~s/\A&_Z\Z/& _Z/;
15510 # templates
15511 if($VEntry=~s/ \[with (\w+) = (.+?)(, [^=]+ = .+|])\Z//g)
15512 { # std::basic_streambuf<_CharT, _Traits>::imbue [with _CharT = char, _Traits = std::char_traits<char>]
15513 # become std::basic_streambuf<char, ...>::imbue
15514 my ($Pname, $Pval) = ($1, $2);
15515 if($Pname eq "_CharT" and $VEntry=~/\Astd::/)
15516 { # stdc++ typedefs
15517 $VEntry=~s/<$Pname(, [^<>]+|)>/<$Pval>/g;
15518 # FIXME: simplify names using stdcxx typedefs (StdCxxTypedef)
15519 # The typedef info should be added to ABI dumps
15520 }
15521 else
15522 {
15523 $VEntry=~s/<$Pname>/<$Pval>/g;
15524 $VEntry=~s/<$Pname, [^<>]+>/<$Pval, ...>/g;
15525 }
15526 }
15527 $VEntry=~s/([^:]+)::\~([^:]+)\Z/~$1/; # destructors
15528 return $VEntry;
15529}
15530
Andrey Ponomarenko85043792012-05-14 16:48:07 +040015531sub getAffectedSymbols($$$$)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015532{
Andrey Ponomarenko85043792012-05-14 16:48:07 +040015533 my ($Level, $Target_TypeName, $Kinds_Locations, $Syms) = @_;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015534 my $LIMIT = 1000;
Andrey Ponomarenko85043792012-05-14 16:48:07 +040015535 if($#{$Syms}>=10000)
15536 { # reduce size of the report
15537 $LIMIT = 10;
15538 }
15539 my %SProblems = ();
15540 foreach my $Symbol (@{$Syms})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015541 {
Andrey Ponomarenko85043792012-05-14 16:48:07 +040015542 if(keys(%SProblems)>$LIMIT) {
15543 last;
15544 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015545 if(($Symbol=~/C2E|D2E|D0E/))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015546 { # duplicated problems for C2 constructors, D2 and D0 destructors
15547 next;
15548 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015549 my ($SN, $SS, $SV) = separate_symbol($Symbol);
15550 if($Level eq "Source")
15551 { # remove symbol version
15552 $Symbol=$SN;
15553 }
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040015554 my ($MinPath_Length, $ProblemLocation_Last) = (-1, "");
15555 my $Severity_Max = 0;
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015556 my $Signature = get_Signature($Symbol, 1);
15557 foreach my $Kind (keys(%{$CompatProblems{$Level}{$Symbol}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015558 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015559 foreach my $Location (keys(%{$CompatProblems{$Level}{$Symbol}{$Kind}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015560 {
15561 if(not defined $Kinds_Locations->{$Kind}
15562 or not $Kinds_Locations->{$Kind}{$Location}) {
15563 next;
15564 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015565 if($SV and defined $CompatProblems{$Level}{$SN}
15566 and defined $CompatProblems{$Level}{$SN}{$Kind}{$Location})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015567 { # duplicated problems for versioned symbols
15568 next;
15569 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015570 my $Type_Name = $CompatProblems{$Level}{$Symbol}{$Kind}{$Location}{"Type_Name"};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015571 next if($Type_Name ne $Target_TypeName);
15572
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015573 my $Position = $CompatProblems{$Level}{$Symbol}{$Kind}{$Location}{"Param_Pos"};
15574 my $Param_Name = $CompatProblems{$Level}{$Symbol}{$Kind}{$Location}{"Param_Name"};
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040015575 my $Severity = getProblemSeverity($Level, $Kind);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015576 my $Path_Length = 0;
15577 my $ProblemLocation = $Location;
15578 if($Type_Name) {
15579 $ProblemLocation=~s/->\Q$Type_Name\E\Z//g;
15580 }
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040015581 while($ProblemLocation=~/\-\>/g) {
15582 $Path_Length += 1;
15583 }
15584 if($MinPath_Length==-1 or ($Path_Length<=$MinPath_Length and $Severity_Val{$Severity}>$Severity_Max)
15585 or (cmp_locations($ProblemLocation, $ProblemLocation_Last) and $Severity_Val{$Severity}==$Severity_Max))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015586 {
15587 $MinPath_Length = $Path_Length;
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040015588 $Severity_Max = $Severity_Val{$Severity};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015589 $ProblemLocation_Last = $ProblemLocation;
Andrey Ponomarenko85043792012-05-14 16:48:07 +040015590 %{$SProblems{$Symbol}} = (
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040015591 "Descr"=>getAffectDescription($Level, $Symbol, $Kind, $Location),
15592 "Severity_Max"=>$Severity_Max,
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015593 "Signature"=>$Signature,
15594 "Position"=>$Position,
15595 "Param_Name"=>$Param_Name,
15596 "Location"=>$Location
15597 );
15598 }
15599 }
15600 }
15601 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +040015602 my @Symbols = keys(%SProblems);
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015603 @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 +040015604 @Symbols = sort {$SProblems{$b}{"Severity_Max"}<=>$SProblems{$a}{"Severity_Max"}} @Symbols;
15605 if($#Symbols+1>$LIMIT)
15606 { # remove last element
15607 pop(@Symbols);
15608 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015609 my $Affected = "";
15610 if($ReportFormat eq "xml")
15611 { # XML
15612 $Affected .= " <affected>\n";
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015613 foreach my $Symbol (@Symbols)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015614 {
Andrey Ponomarenko85043792012-05-14 16:48:07 +040015615 my $Param_Name = $SProblems{$Symbol}{"Param_Name"};
15616 my $Description = $SProblems{$Symbol}{"Descr"};
15617 my $Location = $SProblems{$Symbol}{"Location"};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015618 my $Target = "";
15619 if($Param_Name) {
15620 $Target = " affected=\"param\" param_name=\"$Param_Name\"";
15621 }
15622 elsif($Location=~/\Aretval(\-|\Z)/i) {
15623 $Target = " affected=\"retval\"";
15624 }
15625 elsif($Location=~/\Athis(\-|\Z)/i) {
15626 $Target = " affected=\"this\"";
15627 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015628 $Affected .= " <symbol$Target name=\"$Symbol\">\n";
Andrey Ponomarenko5c09ef32012-06-14 18:17:33 +040015629 $Affected .= " <comment>".xmlSpecChars($Description)."</comment>\n";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015630 $Affected .= " </symbol>\n";
15631 }
15632 $Affected .= " </affected>\n";
15633 }
15634 else
15635 { # HTML
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015636 foreach my $Symbol (@Symbols)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015637 {
Andrey Ponomarenko85043792012-05-14 16:48:07 +040015638 my $Description = $SProblems{$Symbol}{"Descr"};
15639 my $Signature = $SProblems{$Symbol}{"Signature"};
15640 my $Pos = $SProblems{$Symbol}{"Position"};
Andrey Ponomarenkoa01311b2012-06-08 17:20:02 +040015641 $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 +040015642 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +040015643 if(keys(%SProblems)>$LIMIT) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015644 $Affected .= "and others ...<br/>";
15645 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +040015646 $Affected = "<div class='affected'>".$Affected."</div>";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015647 if($Affected)
15648 {
15649 $Affected = $ContentDivStart.$Affected.$ContentDivEnd;
Andrey Ponomarenko85043792012-05-14 16:48:07 +040015650 $Affected = $ContentSpanStart_Affected."[+] affected symbols (".(keys(%SProblems)>$LIMIT?">".$LIMIT:keys(%SProblems)).")".$ContentSpanEnd.$Affected;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015651 }
15652 }
15653 return $Affected;
15654}
15655
15656sub cmp_locations($$)
15657{
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040015658 my ($L1, $L2) = @_;
15659 if($L2=~/\b(retval|this)\b/
15660 and $L1!~/\b(retval|this)\b/ and $L1!~/\-\>/) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015661 return 1;
15662 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040015663 if($L2=~/\b(retval|this)\b/ and $L2=~/\-\>/
15664 and $L1!~/\b(retval|this)\b/ and $L1=~/\-\>/) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015665 return 1;
15666 }
15667 return 0;
15668}
15669
15670sub getAffectDescription($$$$)
15671{
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015672 my ($Level, $Symbol, $Kind, $Location) = @_;
15673 my %Problem = %{$CompatProblems{$Level}{$Symbol}{$Kind}{$Location}};
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040015674 my $PPos = showPos($Problem{"Param_Pos"});
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015675 my @Sentence = ();
15676 $Location=~s/\A(.*)\-\>.+?\Z/$1/;
15677 if($Kind eq "Overridden_Virtual_Method"
15678 or $Kind eq "Overridden_Virtual_Method_B") {
15679 push(@Sentence, "The method '".$Problem{"New_Value"}."' will be called instead of this method.");
15680 }
15681 elsif($CompatRules{$Level}{$Kind}{"Kind"} eq "Types")
15682 {
15683 if($Location eq "this" or $Kind=~/(\A|_)Virtual(_|\Z)/)
15684 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015685 my $METHOD_TYPE = $CompleteSignature{1}{$Symbol}{"Constructor"}?"constructor":"method";
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040015686 my $ClassName = $TypeInfo{1}{$CompleteSignature{1}{$Symbol}{"Class"}}{"Name"};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015687 if($ClassName eq $Problem{"Type_Name"}) {
15688 push(@Sentence, "This $METHOD_TYPE is from \'".$Problem{"Type_Name"}."\' class.");
15689 }
15690 else {
15691 push(@Sentence, "This $METHOD_TYPE is from derived class \'".$ClassName."\'.");
15692 }
15693 }
15694 else
15695 {
15696 if($Location=~/retval/)
15697 { # return value
15698 if($Location=~/\-\>/) {
15699 push(@Sentence, "Field \'".$Location."\' in return value");
15700 }
15701 else {
15702 push(@Sentence, "Return value");
15703 }
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040015704 if(my $Init = $Problem{"InitialType_Type"})
15705 {
15706 if($Init eq "Pointer") {
15707 push(@Sentence, "(pointer)");
15708 }
15709 elsif($Init eq "Ref") {
15710 push(@Sentence, "(reference)");
15711 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015712 }
15713 }
15714 elsif($Location=~/this/)
15715 { # "this" pointer
15716 if($Location=~/\-\>/) {
15717 push(@Sentence, "Field \'".$Location."\' in the object of this method");
15718 }
15719 else {
15720 push(@Sentence, "\'this\' pointer");
15721 }
15722 }
15723 else
15724 { # parameters
15725 if($Location=~/\-\>/) {
15726 push(@Sentence, "Field \'".$Location."\' in $PPos parameter");
15727 }
15728 else {
15729 push(@Sentence, "$PPos parameter");
15730 }
15731 if($Problem{"Param_Name"}) {
15732 push(@Sentence, "\'".$Problem{"Param_Name"}."\'");
15733 }
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040015734 if(my $Init = $Problem{"InitialType_Type"})
15735 {
15736 if($Init eq "Pointer") {
15737 push(@Sentence, "(pointer)");
15738 }
15739 elsif($Init eq "Ref") {
15740 push(@Sentence, "(reference)");
15741 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015742 }
15743 }
15744 if($Location eq "this") {
15745 push(@Sentence, "has base type \'".$Problem{"Type_Name"}."\'.");
15746 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040015747 elsif(defined $Problem{"Start_Type_Name"}
15748 and $Problem{"Start_Type_Name"} eq $Problem{"Type_Name"}) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015749 push(@Sentence, "has type \'".$Problem{"Type_Name"}."\'.");
15750 }
15751 else {
15752 push(@Sentence, "has base type \'".$Problem{"Type_Name"}."\'.");
15753 }
15754 }
15755 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040015756 if($ExtendedSymbols{$Symbol}) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015757 push(@Sentence, " This is a symbol from an artificial external library that may use the \'$TargetLibraryName\' library and change its ABI after recompiling.");
15758 }
15759 return join(" ", @Sentence);
15760}
15761
15762sub get_XmlSign($$)
15763{
15764 my ($Symbol, $LibVersion) = @_;
15765 my $Info = $CompleteSignature{$LibVersion}{$Symbol};
15766 my $Report = "";
15767 foreach my $Pos (sort {int($a)<=>int($b)} keys(%{$Info->{"Param"}}))
15768 {
15769 my $Name = $Info->{"Param"}{$Pos}{"name"};
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040015770 my $Type = $Info->{"Param"}{$Pos}{"type"};
15771 my $TypeName = $TypeInfo{$LibVersion}{$Type}{"Name"};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015772 foreach my $Typedef (keys(%ChangedTypedef))
15773 {
15774 my $Base = $Typedef_BaseName{$LibVersion}{$Typedef};
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040015775 $TypeName=~s/\b\Q$Typedef\E\b/$Base/g;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015776 }
15777 $Report .= " <param pos=\"$Pos\">\n";
15778 $Report .= " <name>".$Name."</name>\n";
Andrey Ponomarenko5c09ef32012-06-14 18:17:33 +040015779 $Report .= " <type>".xmlSpecChars($TypeName)."</type>\n";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015780 $Report .= " </param>\n";
15781 }
15782 if(my $Return = $Info->{"Return"})
15783 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040015784 my $RTName = $TypeInfo{$LibVersion}{$Return}{"Name"};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015785 $Report .= " <retval>\n";
Andrey Ponomarenko5c09ef32012-06-14 18:17:33 +040015786 $Report .= " <type>".xmlSpecChars($RTName)."</type>\n";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015787 $Report .= " </retval>\n";
15788 }
15789 return $Report;
15790}
15791
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015792sub get_Report_SymbolsInfo($)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015793{
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015794 my $Level = $_[0];
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015795 my $Report = "<symbols_info>\n";
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015796 foreach my $Symbol (sort keys(%{$CompatProblems{$Level}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015797 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015798 my ($SN, $SS, $SV) = separate_symbol($Symbol);
15799 if($SV and defined $CompatProblems{$Level}{$SN}) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015800 next;
15801 }
15802 $Report .= " <symbol name=\"$Symbol\">\n";
15803 my ($S1, $P1, $S2, $P2) = ();
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015804 if(not $AddedInt{$Level}{$Symbol})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015805 {
15806 if(defined $CompleteSignature{1}{$Symbol}
15807 and defined $CompleteSignature{1}{$Symbol}{"Header"})
15808 {
15809 $P1 = get_XmlSign($Symbol, 1);
15810 $S1 = get_Signature($Symbol, 1);
15811 }
15812 elsif($Symbol=~/\A(_Z|\?)/) {
15813 $S1 = $tr_name{$Symbol};
15814 }
15815 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015816 if(not $RemovedInt{$Level}{$Symbol})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015817 {
15818 if(defined $CompleteSignature{2}{$Symbol}
15819 and defined $CompleteSignature{2}{$Symbol}{"Header"})
15820 {
15821 $P2 = get_XmlSign($Symbol, 2);
15822 $S2 = get_Signature($Symbol, 2);
15823 }
15824 elsif($Symbol=~/\A(_Z|\?)/) {
15825 $S2 = $tr_name{$Symbol};
15826 }
15827 }
15828 if($S1)
15829 {
Andrey Ponomarenko5c09ef32012-06-14 18:17:33 +040015830 $Report .= " <old signature=\"".xmlSpecChars($S1)."\">\n";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015831 $Report .= $P1;
15832 $Report .= " </old>\n";
15833 }
15834 if($S2 and $S2 ne $S1)
15835 {
Andrey Ponomarenko5c09ef32012-06-14 18:17:33 +040015836 $Report .= " <new signature=\"".xmlSpecChars($S2)."\">\n";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015837 $Report .= $P2;
15838 $Report .= " </new>\n";
15839 }
15840 $Report .= " </symbol>\n";
15841 }
15842 $Report .= "</symbols_info>\n";
15843 return $Report;
15844}
15845
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015846sub writeReport($$)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015847{
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015848 my ($Level, $Report) = @_;
15849 if($ReportFormat eq "xml") {
15850 $Report = "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n".$Report;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015851 }
15852 if($StdOut)
15853 { # --stdout option
15854 print STDOUT $Report;
15855 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015856 else
15857 {
15858 my $RPath = getReportPath($Level);
Andrey Ponomarenko85043792012-05-14 16:48:07 +040015859 mkpath(get_dirname($RPath));
15860
15861 open(REPORT, ">", $RPath) || die ("can't open file \'$RPath\': $!\n");
15862 print REPORT $Report;
15863 close(REPORT);
15864
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040015865 if($Browse or $OpenReport)
15866 { # open in browser
15867 openReport($RPath);
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015868 if($JoinReport or $DoubleReport)
15869 {
15870 if($Level eq "Binary")
15871 { # wait to open a browser
15872 sleep(1);
15873 }
15874 }
15875 }
15876 }
15877}
15878
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040015879sub openReport($)
15880{
15881 my $Path = $_[0];
15882 my $Cmd = "";
15883 if($Browse)
15884 { # user-defined browser
Andrey Ponomarenkoa01311b2012-06-08 17:20:02 +040015885 $Cmd = $Browse." \"$Path\"";
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040015886 }
15887 if(not $Cmd)
15888 { # default browser
15889 if($OSgroup eq "macos") {
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +040015890 $Cmd = "open \"$Path\"";
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040015891 }
15892 elsif($OSgroup eq "windows") {
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +040015893 $Cmd = "start ".path_format($Path, $OSgroup);
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040015894 }
15895 else
15896 { # linux, freebsd, solaris
15897 my @Browsers = (
15898 "x-www-browser",
15899 "sensible-browser",
15900 "firefox",
15901 "opera",
15902 "xdg-open",
15903 "lynx",
15904 "links"
15905 );
15906 foreach my $Br (@Browsers)
15907 {
15908 if($Br = get_CmdPath($Br))
15909 {
Andrey Ponomarenkoa01311b2012-06-08 17:20:02 +040015910 $Cmd = $Br." \"$Path\"";
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040015911 last;
15912 }
15913 }
15914 }
15915 }
15916 if($Cmd)
15917 {
15918 if($Debug) {
15919 printMsg("INFO", "running $Cmd");
15920 }
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +040015921 if($OSgroup ne "windows"
15922 and $OSgroup ne "macos")
15923 {
15924 if($Cmd!~/lynx|links/) {
15925 $Cmd .= " >\"$TMP_DIR/null\" 2>&1 &";
15926 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040015927 }
15928 system($Cmd);
15929 }
15930 else {
15931 printMsg("ERROR", "cannot open report in browser");
15932 }
15933}
15934
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015935sub getReport($)
15936{
15937 my $Level = $_[0];
15938 if($ReportFormat eq "xml")
15939 { # XML
15940
15941 if($Level eq "Join")
15942 {
15943 my $Report = "<reports>\n";
15944 $Report .= getReport("Binary");
15945 $Report .= getReport("Source");
15946 $Report .= "</reports>\n";
15947 return $Report;
15948 }
15949 else
15950 {
15951 my $Report = "<report kind=\"".lc($Level)."\" version=\"$XML_REPORT_VERSION\">\n\n";
15952 my ($Summary, $MetaData) = get_Summary($Level);
15953 $Report .= $Summary."\n";
15954 $Report .= get_Report_Added($Level).get_Report_Removed($Level);
15955 $Report .= get_Report_Problems("High", $Level).get_Report_Problems("Medium", $Level).get_Report_Problems("Low", $Level).get_Report_Problems("Safe", $Level);
15956 $Report .= get_Report_SymbolsInfo($Level);
15957 $Report .= "</report>\n";
15958 return $Report;
15959 }
15960 }
15961 else
15962 { # HTML
15963 my $CssStyles = readModule("Styles", "Report.css");
15964 my $JScripts = readModule("Scripts", "Sections.js");
15965 if($Level eq "Join")
15966 {
15967 $CssStyles .= "\n".readModule("Styles", "Tabs.css");
15968 $JScripts .= "\n".readModule("Scripts", "Tabs.js");
Andrey Ponomarenkob8d203d2012-05-25 18:11:07 +040015969 my $Title = $TargetLibraryFName.": ".$Descriptor{1}{"Version"}." to ".$Descriptor{2}{"Version"}." compatibility report";
15970 my $Keywords = $TargetLibraryFName.", compatibility, API, report";
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015971 my $Description = "Compatibility report for the $TargetLibraryFName $TargetComponent between ".$Descriptor{1}{"Version"}." and ".$Descriptor{2}{"Version"}." versions";
15972 my ($BSummary, $BMetaData) = get_Summary("Binary");
15973 my ($SSummary, $SMetaData) = get_Summary("Source");
15974 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>";
15975 $Report .= get_Report_Header("Join")."
15976 <br/><div class='tabset'>
Andrey Ponomarenko16934472012-03-29 15:37:04 +040015977 <a id='BinaryID' href='#BinaryTab' class='tab active'>Binary<br/>Compatibility</a>
15978 <a id='SourceID' href='#SourceTab' style='margin-left:3px' class='tab disabled'>Source<br/>Compatibility</a>
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015979 </div>";
15980 $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>";
15981 $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 +040015982 $Report .= getReportFooter($TargetLibraryFName, not $JoinReport);
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015983 $Report .= "\n<div style='height:999px;'></div>\n</body></html>";
15984 return $Report;
15985 }
15986 else
15987 {
15988 my ($Summary, $MetaData) = get_Summary($Level);
Andrey Ponomarenkob8d203d2012-05-25 18:11:07 +040015989 my $Title = $TargetLibraryFName.": ".$Descriptor{1}{"Version"}." to ".$Descriptor{2}{"Version"}." ".lc($Level)." compatibility report";
15990 my $Keywords = $TargetLibraryFName.", ".lc($Level)." compatibility, API, report";
15991 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 +040015992 if($Level eq "Binary")
15993 {
15994 if(getArch(1) eq getArch(2)
15995 and getArch(1) ne "unknown") {
15996 $Description .= " on ".showArch(getArch(1));
15997 }
15998 }
15999 my $Report = "<!-\- $MetaData -\->\n".composeHTML_Head($Title, $Keywords, $Description, $CssStyles, $JScripts)."\n<body>\n<div><a name='Top'></a>\n";
16000 $Report .= get_Report_Header($Level)."\n".$Summary."\n";
16001 $Report .= get_Report_Added($Level).get_Report_Removed($Level);
16002 $Report .= get_Report_Problems("High", $Level).get_Report_Problems("Medium", $Level).get_Report_Problems("Low", $Level).get_Report_Problems("Safe", $Level);
16003 $Report .= get_SourceInfo();
16004 $Report .= "</div>\n<br/><br/><br/><hr/>\n";
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040016005 $Report .= getReportFooter($TargetLibraryFName, not $JoinReport);
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040016006 $Report .= "\n<div style='height:999px;'></div>\n</body></html>";
16007 return $Report;
16008 }
16009 }
16010}
16011
Andrey Ponomarenko16934472012-03-29 15:37:04 +040016012sub getLegend()
16013{
16014 return "<br/>
16015<table class='summary'>
16016<tr>
16017 <td class='new'>added</td>
16018 <td class='passed'>compatible</td>
16019</tr>
16020<tr>
16021 <td class='warning'>warning</td>
16022 <td class='failed'>incompatible</td>
16023</tr></table>\n";
16024}
16025
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040016026sub createReport()
16027{
16028 if($JoinReport)
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040016029 { # --stdout
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040016030 writeReport("Join", getReport("Join"));
16031 }
16032 elsif($DoubleReport)
16033 { # default
16034 writeReport("Binary", getReport("Binary"));
16035 writeReport("Source", getReport("Source"));
16036 }
16037 elsif($BinaryOnly)
16038 { # --binary
16039 writeReport("Binary", getReport("Binary"));
16040 }
16041 elsif($SourceOnly)
16042 { # --source
16043 writeReport("Source", getReport("Source"));
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040016044 }
16045}
16046
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040016047sub getReportFooter($$)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040016048{
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040016049 my ($LibName, $Wide) = @_;
16050 my $FooterStyle = $Wide?"width:99%":"width:97%;padding-top:3px";
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040016051 my $Footer = "<div style='$FooterStyle;font-size:11px;' align='right'><i>Generated on ".(localtime time); # report date
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040016052 $Footer .= " for <span style='font-weight:bold'>$LibName</span>"; # tested library/system name
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040016053 $Footer .= " by <a href='".$HomePage{"Wiki"}."'>ABI Compliance Checker</a>"; # tool name
16054 my $ToolSummary = "<br/>A tool for checking backward compatibility of a C/C++ library API&#160;&#160;";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040016055 $Footer .= " $TOOL_VERSION &#160;$ToolSummary</i></div>"; # tool version
16056 return $Footer;
16057}
16058
16059sub get_Report_Problems($$)
16060{
16061 my ($Priority, $Level) = @_;
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040016062 my $Report = get_Report_TypeProblems($Priority, $Level);
Andrey Ponomarenko16934472012-03-29 15:37:04 +040016063 if(my $SProblems = get_Report_SymbolProblems($Priority, $Level)) {
16064 $Report .= $SProblems;
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040016065 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040016066 if($Priority eq "Low")
16067 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040016068 $Report .= get_Report_ChangedConstants($Level);
Andrey Ponomarenko82bc2572012-11-14 13:55:30 +040016069 if($ReportFormat eq "html")
16070 {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040016071 if($CheckImpl and $Level eq "Binary") {
16072 $Report .= get_Report_Impl();
16073 }
16074 }
16075 }
16076 if($ReportFormat eq "html")
16077 {
16078 if($Report)
16079 { # add anchor
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040016080 if($JoinReport)
16081 {
16082 if($Priority eq "Safe") {
16083 $Report = "<a name=\'Other_".$Level."_Changes\'></a>".$Report;
16084 }
16085 else {
16086 $Report = "<a name=\'".$Priority."_Risk_".$Level."_Problems\'></a>".$Report;
16087 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040016088 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040016089 else
16090 {
16091 if($Priority eq "Safe") {
16092 $Report = "<a name=\'Other_Changes\'></a>".$Report;
16093 }
16094 else {
16095 $Report = "<a name=\'".$Priority."_Risk_Problems\'></a>".$Report;
16096 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040016097 }
16098 }
16099 }
16100 return $Report;
16101}
16102
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040016103sub composeHTML_Head($$$$$)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040016104{
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040016105 my ($Title, $Keywords, $Description, $Styles, $Scripts) = @_;
16106 return "<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.0 Transitional//EN\" \"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd\">
16107 <html xmlns=\"http://www.w3.org/1999/xhtml\" xml:lang=\"en\" lang=\"en\">
16108 <head>
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040016109 <meta http-equiv=\"Content-Type\" content=\"text/html; charset=utf-8\" />
16110 <meta name=\"keywords\" content=\"$Keywords\" />
16111 <meta name=\"description\" content=\"$Description\" />
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040016112 <title>
16113 $Title
16114 </title>
16115 <style type=\"text/css\">
16116 $Styles
16117 </style>
16118 <script type=\"text/javascript\" language=\"JavaScript\">
16119 <!--
16120 $Scripts
16121 -->
16122 </script>
16123 </head>";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040016124}
16125
16126sub insertIDs($)
16127{
16128 my $Text = $_[0];
16129 while($Text=~/CONTENT_ID/)
16130 {
16131 if(int($Content_Counter)%2) {
16132 $ContentID -= 1;
16133 }
16134 $Text=~s/CONTENT_ID/c_$ContentID/;
16135 $ContentID += 1;
16136 $Content_Counter += 1;
16137 }
16138 return $Text;
16139}
16140
16141sub checkPreprocessedUnit($)
16142{
16143 my $Path = $_[0];
Andrey Ponomarenkoa01311b2012-06-08 17:20:02 +040016144 my ($CurHeader, $CurHeaderName) = ("", "");
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040016145 open(PREPROC, $Path) || die ("can't open file \'$Path\': $!\n");
Andrey Ponomarenkoa01311b2012-06-08 17:20:02 +040016146 while(my $Line = <PREPROC>)
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040016147 { # detecting public and private constants
Andrey Ponomarenkoa01311b2012-06-08 17:20:02 +040016148
16149 if(substr($Line, 0, 1) eq "#")
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040016150 {
Andrey Ponomarenkoa01311b2012-06-08 17:20:02 +040016151 chomp($Line);
16152 if($Line=~/\A\#\s+\d+\s+\"(.+)\"/)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040016153 {
Andrey Ponomarenkoa01311b2012-06-08 17:20:02 +040016154 $CurHeader = path_format($1, $OSgroup);
16155 $CurHeaderName = get_filename($CurHeader);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040016156 }
Andrey Ponomarenkoa01311b2012-06-08 17:20:02 +040016157 if(not $Include_Neighbors{$Version}{$CurHeaderName}
16158 and not $Registered_Headers{$Version}{$CurHeader})
16159 { # not a target
16160 next;
16161 }
16162 if(not is_target_header($CurHeaderName, 1)
16163 and not is_target_header($CurHeaderName, 2))
16164 { # user-defined header
16165 next;
16166 }
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040016167 if($Line=~/\A\#\s*define\s+(\w+)\s+(.+)\s*\Z/)
Andrey Ponomarenkoa01311b2012-06-08 17:20:02 +040016168 {
16169 my ($Name, $Value) = ($1, $2);
16170 if(not $Constants{$Version}{$Name}{"Access"})
16171 {
16172 $Constants{$Version}{$Name}{"Access"} = "public";
16173 $Constants{$Version}{$Name}{"Value"} = $Value;
16174 $Constants{$Version}{$Name}{"Header"} = $CurHeaderName;
16175 }
16176 }
16177 elsif($Line=~/\A\#[ \t]*undef[ \t]+([_A-Z]+)[ \t]*/) {
16178 $Constants{$Version}{$1}{"Access"} = "private";
16179 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040016180 }
16181 }
16182 close(PREPROC);
16183 foreach my $Constant (keys(%{$Constants{$Version}}))
16184 {
Andrey Ponomarenkoa01311b2012-06-08 17:20:02 +040016185 if($Constants{$Version}{$Constant}{"Access"} eq "private"
16186 or $Constant=~/_h\Z/i
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040016187 or isBuiltIn($Constants{$Version}{$Constant}{"Header"}))
16188 { # skip private constants
16189 delete($Constants{$Version}{$Constant});
16190 }
16191 else {
16192 delete($Constants{$Version}{$Constant}{"Access"});
16193 }
16194 }
Andrey Ponomarenkoa01311b2012-06-08 17:20:02 +040016195 if($Debug)
16196 {
16197 mkpath($DEBUG_PATH{$Version});
16198 copy($Path, $DEBUG_PATH{$Version}."/preprocessor.txt");
16199 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040016200}
16201
Andrey Ponomarenko16934472012-03-29 15:37:04 +040016202sub uncoverConstant($$)
16203{
16204 my ($LibVersion, $Constant) = @_;
16205 return "" if(not $LibVersion or not $Constant);
16206 return $Constant if(isCyclical(\@RecurConstant, $Constant));
16207 if(defined $Cache{"uncoverConstant"}{$LibVersion}{$Constant}) {
16208 return $Cache{"uncoverConstant"}{$LibVersion}{$Constant};
16209 }
16210 my $Value = $Constants{$LibVersion}{$Constant}{"Value"};
16211 if(defined $Value)
16212 {
16213 if($Value=~/\A[A-Z0-9_]+\Z/ and $Value=~/[A-Z]/)
16214 {
16215 push(@RecurConstant, $Constant);
16216 my $Uncovered = uncoverConstant($LibVersion, $Value);
16217 if($Uncovered ne "") {
16218 $Value = $Uncovered;
16219 }
16220 pop(@RecurConstant);
16221 }
16222 # FIXME: uncover $Value using all the enum constants
16223 # USECASE: change of define NC_LONG from NC_INT (enum value) to NC_INT (define)
16224 return ($Cache{"uncoverConstant"}{$LibVersion}{$Constant} = $Value);
16225 }
16226 return ($Cache{"uncoverConstant"}{$LibVersion}{$Constant} = "");
16227}
16228
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040016229my %IgnoreConstant = map {$_=>1} (
16230 "VERSION",
16231 "VERSIONCODE",
16232 "VERNUM",
16233 "VERS_INFO",
16234 "PATCHLEVEL",
16235 "INSTALLPREFIX",
16236 "VBUILD",
16237 "VPATCH",
16238 "VMINOR",
16239 "BUILD_STRING",
16240 "BUILD_TIME",
16241 "PACKAGE_STRING",
16242 "PRODUCTION",
16243 "CONFIGURE_COMMAND",
16244 "INSTALLDIR",
16245 "BINDIR",
16246 "CONFIG_FILE_PATH",
16247 "DATADIR",
16248 "EXTENSION_DIR",
16249 "INCLUDE_PATH",
16250 "LIBDIR",
16251 "LOCALSTATEDIR",
16252 "SBINDIR",
16253 "SYSCONFDIR",
16254 "RELEASE",
16255 "SOURCE_ID",
16256 "SUBMINOR",
16257 "MINOR",
16258 "MINNOR",
16259 "MINORVERSION",
16260 "MAJOR",
16261 "MAJORVERSION",
16262 "MICRO",
16263 "MICROVERSION",
16264 "BINARY_AGE",
16265 "INTERFACE_AGE",
16266 "CORE_ABI",
16267 "PATCH",
16268 "COPYRIGHT",
16269 "TIMESTAMP",
16270 "REVISION",
16271 "PACKAGE_TAG",
16272 "PACKAGEDATE",
16273 "NUMVERSION",
16274 "Release",
16275 "Version"
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040016276);
16277
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040016278sub mergeConstants($)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040016279{
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040016280 my $Level = $_[0];
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040016281 foreach my $Constant (keys(%{$Constants{1}}))
16282 {
16283 if($SkipConstants{1}{$Constant})
16284 { # skipped by the user
16285 next;
16286 }
Andrey Ponomarenko16934472012-03-29 15:37:04 +040016287 if(not defined $Constants{2}{$Constant}{"Value"}
16288 or $Constants{2}{$Constant}{"Value"} eq "")
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040016289 { # empty value
16290 next;
16291 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +040016292 my $Header = $Constants{1}{$Constant}{"Header"};
16293 if(not is_target_header($Header, 1)
16294 and not is_target_header($Header, 2))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040016295 { # user-defined header
16296 next;
16297 }
16298 my ($Old_Value, $New_Value, $Old_Value_Pure, $New_Value_Pure);
Andrey Ponomarenko16934472012-03-29 15:37:04 +040016299 $Old_Value = $Old_Value_Pure = uncoverConstant(1, $Constant);
16300 $New_Value = $New_Value_Pure = uncoverConstant(2, $Constant);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040016301 $Old_Value_Pure=~s/(\W)\s+/$1/g;
16302 $Old_Value_Pure=~s/\s+(\W)/$1/g;
16303 $New_Value_Pure=~s/(\W)\s+/$1/g;
16304 $New_Value_Pure=~s/\s+(\W)/$1/g;
16305 next if($New_Value_Pure eq "" or $Old_Value_Pure eq "");
16306 if($New_Value_Pure ne $Old_Value_Pure)
16307 { # different values
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040016308 if($Level eq "Binary")
16309 {
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040016310 foreach (keys(%IgnoreConstant))
16311 {
16312 if($Constant=~/(\A|_)$_(_|\Z)/)
16313 { # ignore library version
16314 next;
16315 }
16316 if(/\A[A-Z].*[a-z]\Z/)
16317 {
16318 if($Constant=~/(\A|[a-z])$_([A-Z]|\Z)/)
16319 { # ignore library version
16320 next;
16321 }
16322 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040016323 }
16324 if($Constant=~/(\A|_)(lib|open|)$TargetLibraryShortName(_|)(VERSION|VER|DATE|API|PREFIX)(_|\Z)/i)
16325 { # ignore library version
16326 next;
16327 }
16328 if($Old_Value=~/\A('|"|)[\/\\]\w+([\/\\]|:|('|"|)\Z)/ or $Old_Value=~/[\/\\]\w+[\/\\]\w+/)
16329 { # ignoring path defines:
Andrey Ponomarenko85043792012-05-14 16:48:07 +040016330 # /lib64:/usr/lib64:/lib:/usr/lib:/usr/X11R6/lib/Xaw3d ...
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040016331 next;
16332 }
16333 if($Old_Value=~/\A\(*[a-z_]+(\s+|\|)/i)
16334 { # ignore source defines:
Andrey Ponomarenko85043792012-05-14 16:48:07 +040016335 # static int gcry_pth_init ( void) { return ...
16336 # (RE_BACKSLASH_ESCAPE_IN_LISTS | RE...
16337 next;
16338 }
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040016339 if($Old_Value=~/\(/i and $Old_Value!~/\A[\"\']/i)
Andrey Ponomarenko85043792012-05-14 16:48:07 +040016340 { # ignore source defines:
16341 # foo(p)
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040016342 next;
16343 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040016344 }
16345 if(convert_integer($Old_Value) eq convert_integer($New_Value))
16346 { # 0x0001 and 0x1, 0x1 and 1 equal constants
16347 next;
16348 }
16349 if($Old_Value eq "0" and $New_Value eq "NULL")
16350 { # 0 => NULL
16351 next;
16352 }
16353 if($Old_Value eq "NULL" and $New_Value eq "0")
16354 { # NULL => 0
16355 next;
16356 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040016357 %{$ProblemsWithConstants{$Level}{$Constant}} = (
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040016358 "Target"=>$Constant,
16359 "Old_Value"=>$Old_Value,
16360 "New_Value"=>$New_Value );
16361 }
16362 }
16363}
16364
16365sub convert_integer($)
16366{
16367 my $Value = $_[0];
16368 if($Value=~/\A0x[a-f0-9]+\Z/)
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040016369 { # hexadecimal
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040016370 return hex($Value);
16371 }
16372 elsif($Value=~/\A0[0-7]+\Z/)
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040016373 { # octal
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040016374 return oct($Value);
16375 }
16376 elsif($Value=~/\A0b[0-1]+\Z/)
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040016377 { # binary
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040016378 return oct($Value);
16379 }
16380 else {
16381 return $Value;
16382 }
16383}
16384
Andrey Ponomarenko16934472012-03-29 15:37:04 +040016385sub readSymbols($)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040016386{
16387 my $LibVersion = $_[0];
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040016388 my @LibPaths = getSOPaths($LibVersion);
Andrey Ponomarenko16934472012-03-29 15:37:04 +040016389 if($#LibPaths==-1 and not $CheckHeadersOnly)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040016390 {
16391 if($LibVersion==1)
16392 {
16393 printMsg("WARNING", "checking headers only");
16394 $CheckHeadersOnly = 1;
16395 }
16396 else {
16397 exitStatus("Error", "$SLIB_TYPE libraries are not found in ".$Descriptor{$LibVersion}{"Version"});
16398 }
16399 }
Andrey Ponomarenko16934472012-03-29 15:37:04 +040016400 foreach my $LibPath (sort {length($a)<=>length($b)} @LibPaths) {
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040016401 readSymbols_Lib($LibVersion, $LibPath, 0, "+Weak", 1, 1);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040016402 }
Andrey Ponomarenko16934472012-03-29 15:37:04 +040016403 if(not $CheckHeadersOnly)
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040016404 {
Andrey Ponomarenko16934472012-03-29 15:37:04 +040016405 if($#LibPaths!=-1)
16406 {
16407 if(not keys(%{$Symbol_Library{$LibVersion}}))
16408 {
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040016409 printMsg("WARNING", "the set of public symbols in library(ies) is empty ($LibVersion)");
Andrey Ponomarenko16934472012-03-29 15:37:04 +040016410 printMsg("WARNING", "checking headers only");
16411 $CheckHeadersOnly = 1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040016412 }
16413 }
16414 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +040016415
Andrey Ponomarenko07aea072012-11-12 16:15:07 +040016416 # clean memory
Andrey Ponomarenko85043792012-05-14 16:48:07 +040016417 %SystemObjects = ();
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040016418}
16419
Andrey Ponomarenko16934472012-03-29 15:37:04 +040016420sub getSymbolSize($$)
16421{ # size from the shared library
16422 my ($Symbol, $LibVersion) = @_;
16423 return 0 if(not $Symbol);
16424 if(defined $Symbol_Library{$LibVersion}{$Symbol}
16425 and my $LibName = $Symbol_Library{$LibVersion}{$Symbol})
16426 {
16427 if(defined $Library_Symbol{$LibVersion}{$LibName}{$Symbol}
16428 and my $Size = $Library_Symbol{$LibVersion}{$LibName}{$Symbol})
16429 {
16430 if($Size<0) {
16431 return -$Size;
16432 }
16433 }
16434 }
16435 return 0;
16436}
16437
Andrey Ponomarenko07aea072012-11-12 16:15:07 +040016438sub canonifyName($$)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040016439{ # make TIFFStreamOpen(char const*, std::basic_ostream<char, std::char_traits<char> >*)
16440 # to be TIFFStreamOpen(char const*, std::basic_ostream<char>*)
Andrey Ponomarenko07aea072012-11-12 16:15:07 +040016441 my ($Name, $Type) = @_;
16442
16443 # single
16444 while($Name=~/([^<>,]+),\s*$DEFAULT_STD_PARMS<([^<>,]+)>\s*/ and $1 eq $3)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040016445 {
Andrey Ponomarenko85043792012-05-14 16:48:07 +040016446 my $P = $1;
Andrey Ponomarenko07aea072012-11-12 16:15:07 +040016447 $Name=~s/\Q$P\E,\s*$DEFAULT_STD_PARMS<\Q$P\E>\s*/$P/g;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040016448 }
Andrey Ponomarenko07aea072012-11-12 16:15:07 +040016449
16450 # double
16451 if($Name=~/$DEFAULT_STD_PARMS/)
16452 {
Andrey Ponomarenkoe3d6bf02012-11-14 11:49:09 +040016453 if($Type eq "S")
Andrey Ponomarenko07aea072012-11-12 16:15:07 +040016454 {
16455 my ($ShortName, $FuncParams) = split_Signature($Name);
16456
16457 foreach my $FParam (separate_Params($FuncParams, 0, 0))
16458 {
16459 if(index($FParam, "<")!=-1)
16460 {
16461 $FParam=~s/>([^<>]+)\Z/>/; # remove quals
16462 my $FParam_N = canonifyName($FParam, "T");
16463 if($FParam_N ne $FParam) {
16464 $Name=~s/\Q$FParam\E/$FParam_N/g;
16465 }
16466 }
16467 }
16468 }
16469 elsif($Type eq "T")
16470 {
16471 my ($ShortTmpl, $TmplParams) = template_Base($Name);
16472
16473 my @TParams = separate_Params($TmplParams, 0, 0);
Andrey Ponomarenkoe3d6bf02012-11-14 11:49:09 +040016474 if($#TParams>=1)
Andrey Ponomarenko07aea072012-11-12 16:15:07 +040016475 {
Andrey Ponomarenkoe3d6bf02012-11-14 11:49:09 +040016476 my $FParam = $TParams[0];
16477 foreach my $Pos (1 .. $#TParams)
16478 {
16479 my $TParam = $TParams[$Pos];
16480 if($TParam=~/\A$DEFAULT_STD_PARMS<\Q$FParam\E\s*>\Z/) {
16481 $Name=~s/\Q$FParam, $TParam\E\s*/$FParam/g;
16482 }
Andrey Ponomarenko07aea072012-11-12 16:15:07 +040016483 }
Andrey Ponomarenko07aea072012-11-12 16:15:07 +040016484 }
16485 }
16486 }
Andrey Ponomarenkoe3d6bf02012-11-14 11:49:09 +040016487 if($Type eq "S") {
16488 return formatName($Name, "S");
16489 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040016490 return $Name;
16491}
16492
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040016493sub translateSymbols(@)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040016494{
16495 my $LibVersion = pop(@_);
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040016496 my (@MnglNames1, @MnglNames2, @UnmangledNames) = ();
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040016497 foreach my $Symbol (sort @_)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040016498 {
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040016499 if(index($Symbol, "_Z")==0)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040016500 {
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040016501 next if($tr_name{$Symbol});
16502 $Symbol=~s/[\@\$]+(.*)\Z//;
16503 push(@MnglNames1, $Symbol);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040016504 }
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040016505 elsif(index($Symbol, "?")==0) {
16506 push(@MnglNames2, $Symbol);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040016507 }
16508 else
16509 { # not mangled
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040016510 $tr_name{$Symbol} = $Symbol;
16511 $mangled_name_gcc{$Symbol} = $Symbol;
16512 $mangled_name{$LibVersion}{$Symbol} = $Symbol;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040016513 }
16514 }
16515 if($#MnglNames1 > -1)
16516 { # GCC names
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040016517 @UnmangledNames = reverse(unmangleArray(@MnglNames1));
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040016518 foreach my $MnglName (@MnglNames1)
16519 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040016520 if(my $Unmangled = pop(@UnmangledNames))
16521 {
Andrey Ponomarenko72930b92012-11-14 12:09:17 +040016522 $tr_name{$MnglName} = canonifyName($Unmangled, "S");
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040016523 if(not $mangled_name_gcc{$tr_name{$MnglName}}) {
16524 $mangled_name_gcc{$tr_name{$MnglName}} = $MnglName;
16525 }
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040016526 if(index($MnglName, "_ZTV")==0
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040016527 and $tr_name{$MnglName}=~/vtable for (.+)/)
16528 { # bind class name and v-table symbol
16529 my $ClassName = $1;
16530 $ClassVTable{$ClassName} = $MnglName;
16531 $VTableClass{$MnglName} = $ClassName;
16532 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040016533 }
16534 }
16535 }
16536 if($#MnglNames2 > -1)
16537 { # MSVC names
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040016538 @UnmangledNames = reverse(unmangleArray(@MnglNames2));
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040016539 foreach my $MnglName (@MnglNames2)
16540 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040016541 if(my $Unmangled = pop(@UnmangledNames))
16542 {
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040016543 $tr_name{$MnglName} = formatName($Unmangled, "S");
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040016544 $mangled_name{$LibVersion}{$tr_name{$MnglName}} = $MnglName;
16545 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040016546 }
16547 }
16548 return \%tr_name;
16549}
16550
16551sub link_symbol($$$)
16552{
16553 my ($Symbol, $RunWith, $Deps) = @_;
16554 if(link_symbol_internal($Symbol, $RunWith, \%Symbol_Library)) {
16555 return 1;
16556 }
16557 if($Deps eq "+Deps")
16558 { # check the dependencies
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040016559 if(link_symbol_internal($Symbol, $RunWith, \%DepSymbol_Library)) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040016560 return 1;
16561 }
16562 }
16563 return 0;
16564}
16565
16566sub link_symbol_internal($$$)
16567{
16568 my ($Symbol, $RunWith, $Where) = @_;
16569 return 0 if(not $Where or not $Symbol);
16570 if($Where->{$RunWith}{$Symbol})
16571 { # the exact match by symbol name
16572 return 1;
16573 }
16574 if(my $VSym = $SymVer{$RunWith}{$Symbol})
16575 { # indirect symbol version, i.e.
16576 # foo_old and its symlink foo@v (or foo@@v)
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040016577 # foo_old may be in symtab table
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040016578 if($Where->{$RunWith}{$VSym}) {
16579 return 1;
16580 }
16581 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040016582 my ($Sym, $Spec, $Ver) = separate_symbol($Symbol);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040016583 if($Sym and $Ver)
16584 { # search for the symbol with the same version
16585 # or without version
16586 if($Where->{$RunWith}{$Sym})
16587 { # old: foo@v|foo@@v
16588 # new: foo
16589 return 1;
16590 }
16591 if($Where->{$RunWith}{$Sym."\@".$Ver})
16592 { # old: foo|foo@@v
16593 # new: foo@v
16594 return 1;
16595 }
16596 if($Where->{$RunWith}{$Sym."\@\@".$Ver})
16597 { # old: foo|foo@v
16598 # new: foo@@v
16599 return 1;
16600 }
16601 }
16602 return 0;
16603}
16604
Andrey Ponomarenko16934472012-03-29 15:37:04 +040016605sub readSymbols_App($)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040016606{
16607 my $Path = $_[0];
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040016608 return () if(not $Path);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040016609 my @Imported = ();
16610 if($OSgroup eq "macos")
16611 {
Andrey Ponomarenko07aea072012-11-12 16:15:07 +040016612 my $NM = get_CmdPath("nm");
16613 if(not $NM) {
16614 exitStatus("Not_Found", "can't find \"nm\"");
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040016615 }
Andrey Ponomarenko07aea072012-11-12 16:15:07 +040016616 open(APP, "$NM -g \"$Path\" 2>\"$TMP_DIR/null\" |");
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040016617 while(<APP>)
16618 {
Andrey Ponomarenko07aea072012-11-12 16:15:07 +040016619 if(/ U _([\w\$]+)\s*\Z/) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040016620 push(@Imported, $1);
16621 }
16622 }
16623 close(APP);
16624 }
16625 elsif($OSgroup eq "windows")
16626 {
16627 my $DumpBinCmd = get_CmdPath("dumpbin");
16628 if(not $DumpBinCmd) {
16629 exitStatus("Not_Found", "can't find \"dumpbin.exe\"");
16630 }
Andrey Ponomarenkoa01311b2012-06-08 17:20:02 +040016631 open(APP, "$DumpBinCmd /IMPORTS \"$Path\" 2>\"$TMP_DIR/null\" |");
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040016632 while(<APP>)
16633 {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040016634 if(/\s*\w+\s+\w+\s+\w+\s+([\w\?\@]+)\s*/) {
16635 push(@Imported, $1);
16636 }
16637 }
16638 close(APP);
16639 }
16640 else
16641 {
16642 my $ReadelfCmd = get_CmdPath("readelf");
16643 if(not $ReadelfCmd) {
16644 exitStatus("Not_Found", "can't find \"readelf\"");
16645 }
Andrey Ponomarenkoa01311b2012-06-08 17:20:02 +040016646 open(APP, "$ReadelfCmd -WhlSsdA \"$Path\" 2>\"$TMP_DIR/null\" |");
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040016647 my $symtab = undef; # indicates that we are processing 'symtab' section of 'readelf' output
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040016648 while(<APP>)
16649 {
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040016650 if(defined $symtab)
16651 { # do nothing with symtab
16652 if(index($_, "'.dynsym'")!=-1)
16653 { # dynamic table
16654 $symtab = undef;
16655 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040016656 }
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040016657 elsif(index($_, "'.symtab'")!=-1)
16658 { # symbol table
16659 $symtab = 1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040016660 }
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040016661 elsif(my @Info = readline_ELF($_))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040016662 {
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040016663 my ($Ndx, $Symbol) = ($Info[5], $Info[6]);
16664 if($Ndx eq "UND")
16665 { # only imported symbols
16666 push(@Imported, $Symbol);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040016667 }
16668 }
16669 }
16670 close(APP);
16671 }
16672 return @Imported;
16673}
16674
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040016675my %ELF_BIND = map {$_=>1} (
16676 "WEAK",
16677 "GLOBAL"
16678);
16679
16680my %ELF_TYPE = map {$_=>1} (
16681 "FUNC",
16682 "IFUNC",
16683 "OBJECT",
16684 "COMMON"
16685);
16686
16687my %ELF_VIS = map {$_=>1} (
16688 "DEFAULT",
16689 "PROTECTED"
16690);
16691
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040016692sub readline_ELF($)
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040016693{ # read the line of 'readelf' output corresponding to the symbol
16694 my @Info = split(/\s+/, $_[0]);
16695 # Num: Value Size Type Bind Vis Ndx Name
16696 # 3629: 000b09c0 32 FUNC GLOBAL DEFAULT 13 _ZNSt12__basic_fileIcED1Ev@@GLIBCXX_3.4
16697 shift(@Info); # spaces
16698 shift(@Info); # num
16699 if($#Info!=6)
16700 { # other lines
16701 return ();
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040016702 }
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040016703 return () if(not defined $ELF_TYPE{$Info[2]});
16704 return () if(not defined $ELF_BIND{$Info[3]});
16705 return () if(not defined $ELF_VIS{$Info[4]});
16706 if($Info[5] eq "ABS" and $Info[0]=~/\A0+\Z/)
16707 { # 1272: 00000000 0 OBJECT GLOBAL DEFAULT ABS CXXABI_1.3
16708 return ();
16709 }
16710 if($OStarget eq "symbian")
16711 { # _ZN12CCTTokenType4NewLE4TUid3RFs@@ctfinder{000a0000}[102020e5].dll
16712 if(index($Info[6], "_._.absent_export_")!=-1)
16713 { # "_._.absent_export_111"@@libstdcpp{00010001}[10282872].dll
16714 return ();
16715 }
16716 $Info[6]=~s/\@.+//g; # remove version
16717 }
16718 if(index($Info[2], "0x") == 0)
16719 { # size == 0x3d158
16720 $Info[2] = hex($Info[2]);
16721 }
16722 return @Info;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040016723}
16724
Andrey Ponomarenko16934472012-03-29 15:37:04 +040016725sub read_symlink($)
16726{
16727 my $Path = $_[0];
Andrey Ponomarenko16934472012-03-29 15:37:04 +040016728 if(my $Res = readlink($Path)) {
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040016729 return $Res;
Andrey Ponomarenko16934472012-03-29 15:37:04 +040016730 }
16731 elsif(my $ReadlinkCmd = get_CmdPath("readlink")) {
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040016732 return `$ReadlinkCmd -n \"$Path\"`;
Andrey Ponomarenko16934472012-03-29 15:37:04 +040016733 }
16734 elsif(my $FileCmd = get_CmdPath("file"))
16735 {
Andrey Ponomarenkoa01311b2012-06-08 17:20:02 +040016736 my $Info = `$FileCmd \"$Path\"`;
Andrey Ponomarenko16934472012-03-29 15:37:04 +040016737 if($Info=~/symbolic\s+link\s+to\s+['`"]*([\w\d\.\-\/\\]+)['`"]*/i) {
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040016738 return $1;
Andrey Ponomarenko16934472012-03-29 15:37:04 +040016739 }
16740 }
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040016741
16742 # can't read
16743 return "";
Andrey Ponomarenko16934472012-03-29 15:37:04 +040016744}
16745
16746sub resolve_symlink($)
16747{
16748 my $Path = $_[0];
16749 return "" if(not $Path);
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040016750
Andrey Ponomarenko16934472012-03-29 15:37:04 +040016751 if(defined $Cache{"resolve_symlink"}{$Path}) {
16752 return $Cache{"resolve_symlink"}{$Path};
16753 }
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040016754 if(not -f $Path and not -l $Path)
16755 { # broken
16756 return ($Cache{"resolve_symlink"}{$Path} = "");
16757 }
16758 return ($Cache{"resolve_symlink"}{$Path} = resolve_symlink_I($Path));
16759}
16760
16761sub resolve_symlink_I($)
16762{
16763 my $Path = $_[0];
Andrey Ponomarenko16934472012-03-29 15:37:04 +040016764 return $Path if(isCyclical(\@RecurSymlink, $Path));
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040016765 my $Res = $Path;
Andrey Ponomarenko16934472012-03-29 15:37:04 +040016766 push(@RecurSymlink, $Path);
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040016767 if(-l $Path and my $Redirect = read_symlink($Path))
Andrey Ponomarenko16934472012-03-29 15:37:04 +040016768 {
16769 if(is_abs($Redirect))
16770 { # absolute path
16771 if($SystemRoot and $SystemRoot ne "/"
16772 and $Path=~/\A\Q$SystemRoot\E\//
16773 and (-f $SystemRoot.$Redirect or -l $SystemRoot.$Redirect))
16774 { # symbolic links from the sysroot
16775 # should be corrected to point to
16776 # the files inside sysroot
16777 $Redirect = $SystemRoot.$Redirect;
16778 }
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040016779 $Res = resolve_symlink($Redirect);
Andrey Ponomarenko16934472012-03-29 15:37:04 +040016780 }
16781 elsif($Redirect=~/\.\.[\/\\]/)
16782 { # relative path
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040016783 $Redirect = joinPath(get_dirname($Path), $Redirect);
Andrey Ponomarenko16934472012-03-29 15:37:04 +040016784 while($Redirect=~s&(/|\\)[^\/\\]+(\/|\\)\.\.(\/|\\)&$1&){};
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040016785 $Res = resolve_symlink($Redirect);
Andrey Ponomarenko16934472012-03-29 15:37:04 +040016786 }
16787 elsif(-f get_dirname($Path)."/".$Redirect)
16788 { # file name in the same directory
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040016789 $Res = resolve_symlink(joinPath(get_dirname($Path), $Redirect));
Andrey Ponomarenko16934472012-03-29 15:37:04 +040016790 }
16791 else
16792 { # broken link
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040016793 $Res = "";
Andrey Ponomarenko16934472012-03-29 15:37:04 +040016794 }
16795 }
16796 pop(@RecurSymlink);
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040016797 return $Res;
Andrey Ponomarenko16934472012-03-29 15:37:04 +040016798}
16799
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040016800sub get_LibPath($$)
Andrey Ponomarenko16934472012-03-29 15:37:04 +040016801{
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040016802 my ($LibVersion, $Name) = @_;
16803 return "" if(not $LibVersion or not $Name);
16804 if(defined $Cache{"get_LibPath"}{$LibVersion}{$Name}) {
16805 return $Cache{"get_LibPath"}{$LibVersion}{$Name};
Andrey Ponomarenko16934472012-03-29 15:37:04 +040016806 }
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040016807 return ($Cache{"get_LibPath"}{$LibVersion}{$Name} = get_LibPath_I($LibVersion, $Name));
16808}
16809
16810sub get_LibPath_I($$)
16811{
16812 my ($LibVersion, $Name) = @_;
16813 if(is_abs($Name))
Andrey Ponomarenko16934472012-03-29 15:37:04 +040016814 {
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040016815 if(-f $Name)
16816 { # absolute path
16817 return $Name;
16818 }
16819 else
16820 { # broken
16821 return "";
16822 }
16823 }
Andrey Ponomarenko07aea072012-11-12 16:15:07 +040016824 if(defined $RegisteredObjects{$LibVersion}{$Name})
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040016825 { # registered paths
Andrey Ponomarenko07aea072012-11-12 16:15:07 +040016826 return $RegisteredObjects{$LibVersion}{$Name};
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040016827 }
Andrey Ponomarenko07aea072012-11-12 16:15:07 +040016828 if(defined $RegisteredSONAMEs{$LibVersion}{$Name})
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040016829 { # registered paths
Andrey Ponomarenko07aea072012-11-12 16:15:07 +040016830 return $RegisteredSONAMEs{$LibVersion}{$Name};
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040016831 }
16832 if(my $DefaultPath = $DyLib_DefaultPath{$Name})
16833 { # ldconfig default paths
16834 return $DefaultPath;
16835 }
16836 foreach my $Dir (sort keys(%DefaultLibPaths), sort keys(%{$SystemPaths{"lib"}}))
16837 { # search in default linker directories
16838 # and then in all system paths
16839 if(-f $Dir."/".$Name) {
16840 return joinPath($Dir,$Name);
16841 }
16842 }
16843 detectSystemObjects() if(not keys(%SystemObjects));
16844 if(my @AllObjects = keys(%{$SystemObjects{$Name}})) {
16845 return $AllObjects[0];
16846 }
16847 if(my $ShortName = parse_libname($Name, "name+ext", $OStarget))
16848 {
16849 if($ShortName ne $Name)
16850 { # FIXME: check this case
16851 if(my $Path = get_LibPath($LibVersion, $ShortName)) {
16852 return $Path;
Andrey Ponomarenko16934472012-03-29 15:37:04 +040016853 }
16854 }
Andrey Ponomarenko16934472012-03-29 15:37:04 +040016855 }
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040016856 # can't find
16857 return "";
Andrey Ponomarenko16934472012-03-29 15:37:04 +040016858}
16859
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040016860sub readSymbols_Lib($$$$$$)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040016861{
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040016862 my ($LibVersion, $Lib_Path, $IsNeededLib, $Weak, $Deps, $Vers) = @_;
16863 return () if(not $LibVersion or not $Lib_Path);
16864 my $Lib_Name = get_filename(resolve_symlink($Lib_Path));
16865 if($IsNeededLib)
16866 {
16867 if($CheckedDyLib{$LibVersion}{$Lib_Name}) {
16868 return ();
16869 }
16870 }
16871 return () if(isCyclical(\@RecurLib, $Lib_Name) or $#RecurLib>=1);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040016872 $CheckedDyLib{$LibVersion}{$Lib_Name} = 1;
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040016873
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040016874 if($CheckImpl)
16875 {
16876 if(not $IsNeededLib) {
16877 getImplementations($LibVersion, $Lib_Path);
16878 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040016879 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040016880
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040016881 push(@RecurLib, $Lib_Name);
16882 my (%Value_Interface, %Interface_Value, %NeededLib) = ();
Andrey Ponomarenko57a405d2012-11-15 11:34:08 +040016883 my $Lib_ShortName = parse_libname($Lib_Name, "name+ext", $OStarget);
16884
16885 if(not $IsNeededLib)
16886 { # special cases: libstdc++ and libc
16887 if(my $ShortName = parse_libname($Lib_Name, "short", $OStarget))
16888 {
16889 if($ShortName eq "libstdc++")
16890 { # libstdc++.so.6
16891 $STDCXX_TESTING = 1;
16892 }
16893 elsif($ShortName eq "libc")
16894 { # libc-2.11.3.so
16895 $GLIBC_TESTING = 1;
16896 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040016897 }
16898 }
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040016899 my $DebugPath = "";
Andrey Ponomarenkoa01311b2012-06-08 17:20:02 +040016900 if($Debug and not $DumpSystem)
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040016901 { # debug mode
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040016902 $DebugPath = $DEBUG_PATH{$LibVersion}."/libs/".get_filename($Lib_Path).".txt";
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040016903 mkpath(get_dirname($DebugPath));
16904 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040016905 if($OStarget eq "macos")
16906 { # Mac OS X: *.dylib, *.a
Andrey Ponomarenko07aea072012-11-12 16:15:07 +040016907 my $NM = get_CmdPath("nm");
16908 if(not $NM)
16909 {
16910 print STDERR "ERROR: can't find \"nm\"\n";
16911 exit(1);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040016912 }
Andrey Ponomarenko07aea072012-11-12 16:15:07 +040016913 $NM .= " -g \"$Lib_Path\" 2>\"$TMP_DIR/null\"";
Andrey Ponomarenkoa01311b2012-06-08 17:20:02 +040016914 if($DebugPath)
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040016915 { # debug mode
Andrey Ponomarenko16934472012-03-29 15:37:04 +040016916 # write to file
Andrey Ponomarenko07aea072012-11-12 16:15:07 +040016917 system($NM." >\"$DebugPath\"");
Andrey Ponomarenko16934472012-03-29 15:37:04 +040016918 open(LIB, $DebugPath);
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040016919 }
Andrey Ponomarenko16934472012-03-29 15:37:04 +040016920 else
16921 { # write to pipe
Andrey Ponomarenko07aea072012-11-12 16:15:07 +040016922 open(LIB, $NM." |");
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040016923 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040016924 while(<LIB>)
16925 {
Andrey Ponomarenko07aea072012-11-12 16:15:07 +040016926 if(/ [STD] _([\w\$]+)\s*\Z/)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040016927 {
16928 my $realname = $1;
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040016929 if($IsNeededLib)
16930 {
Andrey Ponomarenko57a405d2012-11-15 11:34:08 +040016931 if(not defined $RegisteredObjects_Short{$LibVersion}{$Lib_ShortName})
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040016932 {
16933 $DepSymbol_Library{$LibVersion}{$realname} = $Lib_Name;
16934 $DepLibrary_Symbol{$LibVersion}{$Lib_Name}{$realname} = 1;
16935 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040016936 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040016937 else
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040016938 {
16939 $Symbol_Library{$LibVersion}{$realname} = $Lib_Name;
16940 $Library_Symbol{$LibVersion}{$Lib_Name}{$realname} = 1;
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040016941 if($COMMON_LANGUAGE{$LibVersion} ne "C++")
16942 {
16943 if(index($realname, "_Z")==0 or index($realname, "?")==0) {
16944 setLanguage($LibVersion, "C++");
16945 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040016946 }
16947 if($CheckObjectsOnly
16948 and $LibVersion==1) {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040016949 $CheckedSymbols{"Binary"}{$realname} = 1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040016950 }
16951 }
16952 }
16953 }
16954 close(LIB);
Andrey Ponomarenko07aea072012-11-12 16:15:07 +040016955
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040016956 if($Deps)
16957 {
16958 if($LIB_TYPE eq "dynamic")
16959 { # dependencies
Andrey Ponomarenko07aea072012-11-12 16:15:07 +040016960
16961 my $OtoolCmd = get_CmdPath("otool");
16962 if(not $OtoolCmd)
16963 {
16964 print STDERR "ERROR: can't find \"otool\"\n";
16965 exit(1);
16966 }
16967
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040016968 open(LIB, "$OtoolCmd -L \"$Lib_Path\" 2>\"$TMP_DIR/null\" |");
16969 while(<LIB>)
16970 {
16971 if(/\s*([\/\\].+\.$LIB_EXT)\s*/
16972 and $1 ne $Lib_Path) {
16973 $NeededLib{$1} = 1;
16974 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040016975 }
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040016976 close(LIB);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040016977 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040016978 }
16979 }
16980 elsif($OStarget eq "windows")
16981 { # Windows *.dll, *.lib
16982 my $DumpBinCmd = get_CmdPath("dumpbin");
16983 if(not $DumpBinCmd) {
16984 exitStatus("Not_Found", "can't find \"dumpbin\"");
16985 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040016986 $DumpBinCmd .= " /EXPORTS \"".$Lib_Path."\" 2>$TMP_DIR/null";
Andrey Ponomarenkoa01311b2012-06-08 17:20:02 +040016987 if($DebugPath)
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040016988 { # debug mode
Andrey Ponomarenko16934472012-03-29 15:37:04 +040016989 # write to file
Andrey Ponomarenkoa01311b2012-06-08 17:20:02 +040016990 system($DumpBinCmd." >\"$DebugPath\"");
Andrey Ponomarenko16934472012-03-29 15:37:04 +040016991 open(LIB, $DebugPath);
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040016992 }
Andrey Ponomarenko16934472012-03-29 15:37:04 +040016993 else
16994 { # write to pipe
16995 open(LIB, $DumpBinCmd." |");
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040016996 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040016997 while(<LIB>)
16998 { # 1197 4AC 0000A620 SetThreadStackGuarantee
16999 # 1198 4AD SetThreadToken (forwarded to ...)
17000 # 3368 _o2i_ECPublicKey
17001 if(/\A\s*\d+\s+[a-f\d]+\s+[a-f\d]+\s+([\w\?\@]+)\s*\Z/i
17002 or /\A\s*\d+\s+[a-f\d]+\s+([\w\?\@]+)\s*\(\s*forwarded\s+/
17003 or /\A\s*\d+\s+_([\w\?\@]+)\s*\Z/)
17004 { # dynamic, static and forwarded symbols
17005 my $realname = $1;
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040017006 if($IsNeededLib)
17007 {
Andrey Ponomarenko57a405d2012-11-15 11:34:08 +040017008 if(not defined $RegisteredObjects_Short{$LibVersion}{$Lib_ShortName})
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040017009 {
17010 $DepSymbol_Library{$LibVersion}{$realname} = $Lib_Name;
17011 $DepLibrary_Symbol{$LibVersion}{$Lib_Name}{$realname} = 1;
17012 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017013 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040017014 else
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017015 {
17016 $Symbol_Library{$LibVersion}{$realname} = $Lib_Name;
17017 $Library_Symbol{$LibVersion}{$Lib_Name}{$realname} = 1;
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040017018 if($COMMON_LANGUAGE{$LibVersion} ne "C++")
17019 {
17020 if(index($realname, "_Z")==0 or index($realname, "?")==0) {
17021 setLanguage($LibVersion, "C++");
17022 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017023 }
17024 if($CheckObjectsOnly
17025 and $LibVersion==1) {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040017026 $CheckedSymbols{"Binary"}{$realname} = 1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017027 }
17028 }
17029 }
17030 }
17031 close(LIB);
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040017032 if($Deps)
17033 {
17034 if($LIB_TYPE eq "dynamic")
17035 { # dependencies
17036 open(LIB, "$DumpBinCmd /DEPENDENTS \"$Lib_Path\" 2>\"$TMP_DIR/null\" |");
17037 while(<LIB>)
17038 {
17039 if(/\s*([^\s]+?\.$LIB_EXT)\s*/i
17040 and $1 ne $Lib_Path) {
17041 $NeededLib{path_format($1, $OSgroup)} = 1;
17042 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017043 }
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040017044 close(LIB);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017045 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017046 }
17047 }
17048 else
17049 { # Unix; *.so, *.a
17050 # Symbian: *.dso, *.lib
17051 my $ReadelfCmd = get_CmdPath("readelf");
17052 if(not $ReadelfCmd) {
17053 exitStatus("Not_Found", "can't find \"readelf\"");
17054 }
Andrey Ponomarenkoa01311b2012-06-08 17:20:02 +040017055 $ReadelfCmd .= " -WhlSsdA \"$Lib_Path\" 2>\"$TMP_DIR/null\"";
17056 if($DebugPath)
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040017057 { # debug mode
Andrey Ponomarenko16934472012-03-29 15:37:04 +040017058 # write to file
Andrey Ponomarenkoa01311b2012-06-08 17:20:02 +040017059 system($ReadelfCmd." >\"$DebugPath\"");
Andrey Ponomarenko16934472012-03-29 15:37:04 +040017060 open(LIB, $DebugPath);
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040017061 }
Andrey Ponomarenko16934472012-03-29 15:37:04 +040017062 else
17063 { # write to pipe
17064 open(LIB, $ReadelfCmd." |");
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040017065 }
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040017066 my $symtab = undef; # indicates that we are processing 'symtab' section of 'readelf' output
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017067 while(<LIB>)
17068 {
17069 if($LIB_TYPE eq "dynamic")
17070 { # dynamic library specifics
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040017071 if(defined $symtab)
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040017072 {
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040017073 if(index($_, "'.dynsym'")!=-1)
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040017074 { # dynamic table
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040017075 $symtab = undef;
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040017076 }
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040017077 # do nothing with symtab
17078 next;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017079 }
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040017080 elsif(index($_, "'.symtab'")!=-1)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017081 { # symbol table
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040017082 $symtab = 1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017083 next;
17084 }
17085 }
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040017086 if(my ($Value, $Size, $Type, $Bind, $Vis, $Ndx, $Symbol) = readline_ELF($_))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017087 { # read ELF entry
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040017088 if($Ndx eq "UND")
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017089 { # ignore interfaces that are imported from somewhere else
17090 next;
17091 }
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040017092 if($Bind eq "WEAK"
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017093 and $Weak eq "-Weak")
17094 { # skip WEAK symbols
Andrey Ponomarenko07aea072012-11-12 16:15:07 +040017095 $WeakSymbols{$LibVersion}{$Symbol} = 1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017096 next;
17097 }
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040017098 my $Short = $Symbol;
17099 $Short=~s/\@.+//g;
17100 if($Type eq "OBJECT")
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017101 { # global data
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040017102 $GlobalDataObject{$LibVersion}{$Symbol} = 1;
17103 $GlobalDataObject{$LibVersion}{$Short} = 1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017104 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040017105 if($IsNeededLib)
17106 {
Andrey Ponomarenko57a405d2012-11-15 11:34:08 +040017107 if(not defined $RegisteredObjects_Short{$LibVersion}{$Lib_ShortName})
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040017108 {
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040017109 $DepSymbol_Library{$LibVersion}{$Symbol} = $Lib_Name;
17110 $DepLibrary_Symbol{$LibVersion}{$Lib_Name}{$Symbol} = ($Type eq "OBJECT")?-$Size:1;
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040017111 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017112 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040017113 else
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017114 {
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040017115 $Symbol_Library{$LibVersion}{$Symbol} = $Lib_Name;
17116 $Library_Symbol{$LibVersion}{$Lib_Name}{$Symbol} = ($Type eq "OBJECT")?-$Size:1;
17117 if($Vers)
17118 {
17119 if($LIB_EXT eq "so")
17120 { # value
17121 $Interface_Value{$LibVersion}{$Symbol} = $Value;
17122 $Value_Interface{$LibVersion}{$Value}{$Symbol} = 1;
17123 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017124 }
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040017125 if($COMMON_LANGUAGE{$LibVersion} ne "C++")
17126 {
17127 if(index($Symbol, "_Z")==0 or index($Symbol, "?")==0) {
17128 setLanguage($LibVersion, "C++");
17129 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017130 }
17131 if($CheckObjectsOnly
17132 and $LibVersion==1) {
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040017133 $CheckedSymbols{"Binary"}{$Symbol} = 1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017134 }
17135 }
17136 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040017137 elsif($LIB_TYPE eq "dynamic")
17138 { # dynamic library specifics
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040017139 if($Deps)
17140 {
17141 if(/NEEDED.+\[([^\[\]]+)\]/)
17142 { # dependencies:
17143 # 0x00000001 (NEEDED) Shared library: [libc.so.6]
17144 $NeededLib{$1} = 1;
17145 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040017146 }
17147 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017148 }
17149 close(LIB);
17150 }
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040017151 if($Vers)
17152 {
17153 if(not $IsNeededLib and $LIB_EXT eq "so")
17154 { # get symbol versions
17155 foreach my $Symbol (keys(%{$Symbol_Library{$LibVersion}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017156 {
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040017157 next if(index($Symbol,"\@")==-1);
17158 if(my $Value = $Interface_Value{$LibVersion}{$Symbol})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017159 {
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040017160 my $Interface_SymName = "";
17161 foreach my $Symbol_SameValue (keys(%{$Value_Interface{$LibVersion}{$Value}}))
Andrey Ponomarenkoa01311b2012-06-08 17:20:02 +040017162 {
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040017163 if($Symbol_SameValue ne $Symbol
17164 and index($Symbol_SameValue,"\@")==-1)
17165 {
17166 $SymVer{$LibVersion}{$Symbol_SameValue} = $Symbol;
17167 $Interface_SymName = $Symbol_SameValue;
17168 last;
17169 }
Andrey Ponomarenkoa01311b2012-06-08 17:20:02 +040017170 }
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040017171 if(not $Interface_SymName)
17172 {
17173 if($Symbol=~/\A([^\@\$\?]*)[\@\$]+([^\@\$]*)\Z/
17174 and not $SymVer{$LibVersion}{$1}) {
17175 $SymVer{$LibVersion}{$1} = $Symbol;
17176 }
Andrey Ponomarenkoa01311b2012-06-08 17:20:02 +040017177 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017178 }
17179 }
17180 }
17181 }
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040017182 if($Deps)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017183 {
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040017184 foreach my $DyLib (sort keys(%NeededLib))
17185 {
17186 if(my $DepPath = get_LibPath($LibVersion, $DyLib)) {
17187 readSymbols_Lib($LibVersion, $DepPath, 1, "+Weak", $Deps, $Vers);
17188 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017189 }
17190 }
17191 pop(@RecurLib);
17192 return $Library_Symbol{$LibVersion};
17193}
17194
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040017195sub get_prefixes($)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017196{
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017197 my %Prefixes = ();
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040017198 get_prefixes_I([$_[0]], \%Prefixes);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017199 return keys(%Prefixes);
17200}
17201
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040017202sub get_prefixes_I($$)
17203{
17204 foreach my $P (@{$_[0]})
17205 {
17206 my @Parts = reverse(split(/[\/\\]+/, $P));
17207 my $Name = $Parts[0];
17208 foreach (1 .. $#Parts)
17209 {
17210 $_[1]->{$Name}{$P} = 1;
17211 last if($_>4 or $Parts[$_] eq "include");
17212 $Name = $Parts[$_].$SLASH.$Name;
17213 }
17214 }
17215}
17216
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017217sub detectSystemHeaders()
17218{
17219 my @SysHeaders = ();
17220 foreach my $DevelPath (keys(%{$SystemPaths{"include"}}))
17221 {
17222 next if(not -d $DevelPath);
17223 # search for all header files in the /usr/include
17224 # with or without extension (ncurses.h, QtCore, ...)
17225 @SysHeaders = (@SysHeaders, cmd_find($DevelPath,"f","",""));
17226 foreach my $Link (cmd_find($DevelPath,"l","",""))
17227 { # add symbolic links
17228 if(-f $Link) {
17229 push(@SysHeaders, $Link);
17230 }
17231 }
17232 }
17233 foreach my $DevelPath (keys(%{$SystemPaths{"lib"}}))
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040017234 { # search for config headers in the /usr/lib
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017235 next if(not -d $DevelPath);
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040017236 foreach (cmd_find($DevelPath,"f","",""))
17237 {
17238 if(not /\/(gcc|jvm|syslinux|kbd|parrot|xemacs)/)
17239 {
17240 if(/\.h\Z|\/include\//) {
17241 push(@SysHeaders, $_);
17242 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017243 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017244 }
17245 }
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040017246 get_prefixes_I(\@SysHeaders, \%SystemHeaders);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017247}
17248
17249sub detectSystemObjects()
17250{
17251 foreach my $DevelPath (keys(%{$SystemPaths{"lib"}}))
17252 {
17253 next if(not -d $DevelPath);
17254 foreach my $Path (find_libs($DevelPath,"",""))
17255 { # search for shared libraries in the /usr/lib (including symbolic links)
17256 $SystemObjects{parse_libname(get_filename($Path), "name+ext", $OStarget)}{$Path}=1;
17257 }
17258 }
17259}
17260
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040017261sub getSOPaths($)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017262{
17263 my $LibVersion = $_[0];
17264 my @SoPaths = ();
17265 foreach my $Dest (split(/\s*\n\s*/, $Descriptor{$LibVersion}{"Libs"}))
17266 {
17267 if(not -e $Dest) {
17268 exitStatus("Access_Error", "can't access \'$Dest\'");
17269 }
17270 my @SoPaths_Dest = getSOPaths_Dest($Dest, $LibVersion);
17271 foreach (@SoPaths_Dest) {
17272 push(@SoPaths, $_);
17273 }
17274 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040017275 return sort @SoPaths;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017276}
17277
17278sub skip_lib($$)
17279{
17280 my ($Path, $LibVersion) = @_;
17281 return 1 if(not $Path or not $LibVersion);
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040017282 my $Name = get_filename($Path);
17283 if($SkipLibs{$LibVersion}{"Name"}{$Name}) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017284 return 1;
17285 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040017286 my $ShortName = parse_libname($Name, "name+ext", $OStarget);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017287 if($SkipLibs{$LibVersion}{"Name"}{$ShortName}) {
17288 return 1;
17289 }
17290 foreach my $Dir (keys(%{$SkipLibs{$LibVersion}{"Path"}}))
17291 {
17292 if($Path=~/\Q$Dir\E([\/\\]|\Z)/) {
17293 return 1;
17294 }
17295 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040017296 foreach my $P (keys(%{$SkipLibs{$LibVersion}{"Pattern"}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017297 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040017298 if($Name=~/$P/) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017299 return 1;
17300 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040017301 if($P=~/[\/\\]/ and $Path=~/$P/) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017302 return 1;
17303 }
17304 }
17305 return 0;
17306}
17307
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040017308sub skipHeader($$)
17309{
17310 my ($Path, $LibVersion) = @_;
17311 return 1 if(not $Path or not $LibVersion);
17312 if(not keys(%{$SkipHeaders{$LibVersion}})) {
17313 return 0;
17314 }
17315 if(defined $Cache{"skipHeader"}{$Path}) {
17316 return $Cache{"skipHeader"}{$Path};
17317 }
17318 return ($Cache{"skipHeader"}{$Path} = skipHeader_I(@_));
17319}
17320
17321sub skipHeader_I($$)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017322{ # returns:
17323 # 1 - if header should NOT be included and checked
17324 # 2 - if header should NOT be included, but should be checked
17325 my ($Path, $LibVersion) = @_;
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040017326 my $Name = get_filename($Path);
17327 if(my $Kind = $SkipHeaders{$LibVersion}{"Name"}{$Name}) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017328 return $Kind;
17329 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040017330 foreach my $D (keys(%{$SkipHeaders{$LibVersion}{"Path"}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017331 {
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040017332 if(index($Path, $D)!=-1)
17333 {
17334 if($Path=~/\Q$D\E([\/\\]|\Z)/) {
17335 return $SkipHeaders{$LibVersion}{"Path"}{$D};
17336 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017337 }
17338 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040017339 foreach my $P (keys(%{$SkipHeaders{$LibVersion}{"Pattern"}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017340 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040017341 if(my $Kind = $SkipHeaders{$LibVersion}{"Pattern"}{$P})
17342 {
17343 if($Name=~/$P/) {
17344 return $Kind;
17345 }
17346 if($P=~/[\/\\]/ and $Path=~/$P/) {
17347 return $Kind;
17348 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017349 }
17350 }
17351 return 0;
17352}
17353
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040017354sub registerObject_Dir($$)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017355{
17356 my ($Dir, $LibVersion) = @_;
17357 if($SystemPaths{"lib"}{$Dir})
17358 { # system directory
17359 return;
17360 }
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040017361 if($RegisteredObject_Dirs{$LibVersion}{$Dir})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017362 { # already registered
17363 return;
17364 }
17365 foreach my $Path (find_libs($Dir,"",1))
17366 {
17367 next if(ignore_path($Path));
17368 next if(skip_lib($Path, $LibVersion));
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040017369 registerObject($Path, $LibVersion);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017370 }
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040017371 $RegisteredObject_Dirs{$LibVersion}{$Dir} = 1;
17372}
17373
17374sub registerObject($$)
17375{
17376 my ($Path, $LibVersion) = @_;
17377 my $Name = get_filename($Path);
Andrey Ponomarenko07aea072012-11-12 16:15:07 +040017378 $RegisteredObjects{$LibVersion}{$Name} = $Path;
Andrey Ponomarenko27681702012-11-12 16:33:39 +040017379 if($OSgroup=~/linux|bsd/i)
17380 {
17381 if(my $SONAME = getSONAME($Path)) {
17382 $RegisteredSONAMEs{$LibVersion}{$SONAME} = $Path;
17383 }
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040017384 }
Andrey Ponomarenko57a405d2012-11-15 11:34:08 +040017385 if(my $Short = parse_libname($Name, "name+ext", $OStarget)) {
17386 $RegisteredObjects_Short{$LibVersion}{$Short} = $Path;
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040017387 }
17388}
17389
17390sub getSONAME($)
17391{
17392 my $Path = $_[0];
17393 return if(not $Path);
17394 if(defined $Cache{"getSONAME"}{$Path}) {
17395 return $Cache{"getSONAME"}{$Path};
17396 }
17397 my $ObjdumpCmd = get_CmdPath("objdump");
17398 if(not $ObjdumpCmd) {
17399 exitStatus("Not_Found", "can't find \"objdump\"");
17400 }
17401 my $SonameCmd = "$ObjdumpCmd -x $Path 2>$TMP_DIR/null";
17402 if($OSgroup eq "windows") {
17403 $SonameCmd .= " | find \"SONAME\"";
17404 }
17405 else {
17406 $SonameCmd .= " | grep SONAME";
17407 }
17408 if(my $SonameInfo = `$SonameCmd`) {
17409 if($SonameInfo=~/SONAME\s+([^\s]+)/) {
17410 return ($Cache{"getSONAME"}{$Path} = $1);
17411 }
17412 }
17413 return ($Cache{"getSONAME"}{$Path}="");
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017414}
17415
17416sub getSOPaths_Dest($$)
17417{
17418 my ($Dest, $LibVersion) = @_;
17419 if(skip_lib($Dest, $LibVersion)) {
17420 return ();
17421 }
17422 if(-f $Dest)
17423 {
17424 if(not parse_libname($Dest, "name", $OStarget)) {
17425 exitStatus("Error", "incorrect format of library (should be *.$LIB_EXT): \'$Dest\'");
17426 }
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040017427 registerObject($Dest, $LibVersion);
17428 registerObject_Dir(get_dirname($Dest), $LibVersion);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017429 return ($Dest);
17430 }
17431 elsif(-d $Dest)
17432 {
17433 $Dest=~s/[\/\\]+\Z//g;
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040017434 my %Libs = ();
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017435 if($SystemPaths{"lib"}{$Dest})
17436 { # you have specified /usr/lib as the search directory (<libs>) in the XML descriptor
17437 # and the real name of the library by -l option (bz2, stdc++, Xaw, ...)
17438 foreach my $Path (cmd_find($Dest,"","*".esc($TargetLibraryName)."*\.$LIB_EXT*",2))
17439 { # all files and symlinks that match the name of a library
17440 if(get_filename($Path)=~/\A(|lib)\Q$TargetLibraryName\E[\d\-]*\.$LIB_EXT[\d\.]*\Z/i)
17441 {
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040017442 registerObject($Path, $LibVersion);
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040017443 $Libs{resolve_symlink($Path)}=1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017444 }
17445 }
17446 }
17447 else
17448 { # search for all files and symlinks
17449 foreach my $Path (find_libs($Dest,"",""))
17450 {
17451 next if(ignore_path($Path));
17452 next if(skip_lib($Path, $LibVersion));
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040017453 registerObject($Path, $LibVersion);
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040017454 $Libs{resolve_symlink($Path)}=1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017455 }
17456 if($OSgroup eq "macos")
17457 { # shared libraries on MacOS X may have no extension
17458 foreach my $Path (cmd_find($Dest,"f","",""))
17459 {
17460 next if(ignore_path($Path));
17461 next if(skip_lib($Path, $LibVersion));
17462 if(get_filename($Path)!~/\./
Andrey Ponomarenko85043792012-05-14 16:48:07 +040017463 and cmd_file($Path)=~/(shared|dynamic)\s+library/i)
17464 {
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040017465 registerObject($Path, $LibVersion);
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040017466 $Libs{resolve_symlink($Path)}=1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017467 }
17468 }
17469 }
17470 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040017471 return keys(%Libs);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017472 }
17473 else {
17474 return ();
17475 }
17476}
17477
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040017478sub isCyclical($$)
17479{
17480 my ($Stack, $Value) = @_;
17481 return (grep {$_ eq $Value} @{$Stack});
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017482}
17483
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017484sub generateTemplate()
17485{
17486 writeFile("VERSION.xml", $DescriptorTemplate."\n");
17487 printMsg("INFO", "XML-descriptor template ./VERSION.xml has been generated");
17488}
17489
17490sub detectWordSize()
17491{
17492 return "" if(not $GCC_PATH);
17493 if($Cache{"detectWordSize"}) {
17494 return $Cache{"detectWordSize"};
17495 }
17496 writeFile("$TMP_DIR/empty.h", "");
Andrey Ponomarenkoa01311b2012-06-08 17:20:02 +040017497 my $Defines = `$GCC_PATH -E -dD \"$TMP_DIR/empty.h\"`;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017498 unlink("$TMP_DIR/empty.h");
17499 my $WSize = 0;
17500 if($Defines=~/ __SIZEOF_POINTER__\s+(\d+)/)
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040017501 { # GCC 4
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017502 $WSize = $1;
17503 }
17504 elsif($Defines=~/ __PTRDIFF_TYPE__\s+(\w+)/)
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040017505 { # GCC 3
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017506 my $PTRDIFF = $1;
17507 if($PTRDIFF=~/long/) {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040017508 $WSize = "8";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017509 }
17510 else {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040017511 $WSize = "4";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017512 }
17513 }
Andrey Ponomarenko01117f12012-06-26 12:23:02 +040017514 if(not $WSize) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017515 exitStatus("Error", "can't check WORD size");
17516 }
17517 return ($Cache{"detectWordSize"} = $WSize);
17518}
17519
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +040017520sub getWordSize($) {
17521 return $WORD_SIZE{$_[0]};
17522}
17523
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017524sub majorVersion($)
17525{
17526 my $V = $_[0];
17527 return 0 if(not $V);
17528 my @VParts = split(/\./, $V);
17529 return $VParts[0];
17530}
17531
17532sub cmpVersions($$)
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040017533{ # compare two versions in dotted-numeric format
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017534 my ($V1, $V2) = @_;
17535 return 0 if($V1 eq $V2);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017536 my @V1Parts = split(/\./, $V1);
17537 my @V2Parts = split(/\./, $V2);
17538 for (my $i = 0; $i <= $#V1Parts && $i <= $#V2Parts; $i++) {
17539 return -1 if(int($V1Parts[$i]) < int($V2Parts[$i]));
17540 return 1 if(int($V1Parts[$i]) > int($V2Parts[$i]));
17541 }
17542 return -1 if($#V1Parts < $#V2Parts);
17543 return 1 if($#V1Parts > $#V2Parts);
17544 return 0;
17545}
17546
17547sub read_ABI_Dump($$)
17548{
17549 my ($LibVersion, $Path) = @_;
17550 return if(not $LibVersion or not -e $Path);
17551 my $FilePath = "";
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040017552 if(isDump_U($Path))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017553 { # input *.abi
17554 $FilePath = $Path;
17555 }
17556 else
17557 { # input *.abi.tar.gz
17558 $FilePath = unpackDump($Path);
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040017559 if(not isDump_U($FilePath)) {
17560 exitStatus("Invalid_Dump", "specified ABI dump \'$Path\' is not valid, try to recreate it");
17561 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017562 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +040017563
Andrey Ponomarenko01117f12012-06-26 12:23:02 +040017564 my $ABI = {};
Andrey Ponomarenko5c09ef32012-06-14 18:17:33 +040017565
Andrey Ponomarenko01117f12012-06-26 12:23:02 +040017566 my $Line = readLineNum($FilePath, 0);
17567 if($Line=~/xml/)
17568 { # XML format
17569 loadModule("XmlDump");
17570 $ABI = readXmlDump($FilePath);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017571 }
Andrey Ponomarenko01117f12012-06-26 12:23:02 +040017572 else
17573 { # Perl Data::Dumper format (default)
17574 open(DUMP, $FilePath);
17575 local $/ = undef;
17576 my $Content = <DUMP>;
17577 close(DUMP);
17578
17579 if(get_dirname($FilePath) eq $TMP_DIR."/unpack")
17580 { # remove temp file
17581 unlink($FilePath);
17582 }
17583 if($Content!~/};\s*\Z/) {
17584 exitStatus("Invalid_Dump", "specified ABI dump \'$Path\' is not valid, try to recreate it");
17585 }
17586 $ABI = eval($Content);
17587 if(not $ABI) {
17588 exitStatus("Error", "internal error - eval() procedure seem to not working correctly, try to remove 'use strict' and try again");
17589 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017590 }
17591 # new dumps (>=1.22) have a personal versioning
Andrey Ponomarenko01117f12012-06-26 12:23:02 +040017592 my $DumpVersion = $ABI->{"ABI_DUMP_VERSION"};
17593 my $ToolVersion = $ABI->{"ABI_COMPLIANCE_CHECKER_VERSION"};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017594 if(not $DumpVersion)
17595 { # old dumps (<=1.21.6) have been marked by the tool version
17596 $DumpVersion = $ToolVersion;
17597 }
17598 $UsedDump{$LibVersion}{"V"} = $DumpVersion;
17599 if(majorVersion($DumpVersion) ne majorVersion($ABI_DUMP_VERSION))
17600 { # should be compatible with dumps of the same major version
17601 if(cmpVersions($DumpVersion, $ABI_DUMP_VERSION)>0)
17602 { # Don't know how to parse future dump formats
Andrey Ponomarenko01117f12012-06-26 12:23:02 +040017603 exitStatus("Dump_Version", "incompatible version \'$DumpVersion\' of specified ABI dump (newer than $ABI_DUMP_VERSION)");
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017604 }
Andrey Ponomarenko01117f12012-06-26 12:23:02 +040017605 elsif(cmpVersions($DumpVersion, $TOOL_VERSION)>0 and not $ABI->{"ABI_DUMP_VERSION"})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017606 { # Don't know how to parse future dump formats
Andrey Ponomarenko01117f12012-06-26 12:23:02 +040017607 exitStatus("Dump_Version", "incompatible version \'$DumpVersion\' of specified ABI dump (newer than $TOOL_VERSION)");
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017608 }
17609 if($UseOldDumps)
17610 {
17611 if(cmpVersions($DumpVersion, $OLDEST_SUPPORTED_VERSION)<0) {
Andrey Ponomarenko01117f12012-06-26 12:23:02 +040017612 exitStatus("Dump_Version", "incompatible version \'$DumpVersion\' of specified ABI dump (older than $OLDEST_SUPPORTED_VERSION)");
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017613 }
17614 }
17615 else
17616 {
Andrey Ponomarenko01117f12012-06-26 12:23:02 +040017617 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 +040017618 if(cmpVersions($DumpVersion, $OLDEST_SUPPORTED_VERSION)>=0) {
17619 $Msg .= "\nUse -old-dumps option to use old-version dumps ($OLDEST_SUPPORTED_VERSION<=V<".majorVersion($ABI_DUMP_VERSION).".0)";
17620 }
17621 exitStatus("Dump_Version", $Msg);
17622 }
17623 }
Andrey Ponomarenko5c09ef32012-06-14 18:17:33 +040017624 if(not checkDump($LibVersion, "2.11"))
17625 { # old ABI dumps
17626 $UsedDump{$LibVersion}{"BinOnly"} = 1;
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040017627 }
Andrey Ponomarenko01117f12012-06-26 12:23:02 +040017628 elsif($ABI->{"BinOnly"})
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040017629 { # ABI dump created with --binary option
17630 $UsedDump{$LibVersion}{"BinOnly"} = 1;
17631 }
Andrey Ponomarenko5c09ef32012-06-14 18:17:33 +040017632 else
17633 { # default
17634 $UsedDump{$LibVersion}{"SrcBin"} = 1;
17635 }
Andrey Ponomarenko01117f12012-06-26 12:23:02 +040017636 if(defined $ABI->{"Mode"}
17637 and $ABI->{"Mode"} eq "Extended")
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017638 { # --ext option
17639 $ExtendedCheck = 1;
17640 }
Andrey Ponomarenko01117f12012-06-26 12:23:02 +040017641 if(my $Lang = $ABI->{"Language"})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017642 {
17643 $UsedDump{$LibVersion}{"L"} = $Lang;
17644 setLanguage($LibVersion, $Lang);
17645 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040017646 if(checkDump($LibVersion, "2.15")) {
Andrey Ponomarenko01117f12012-06-26 12:23:02 +040017647 $TypeInfo{$LibVersion} = $ABI->{"TypeInfo"};
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040017648 }
17649 else
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017650 { # support for old ABI dumps
Andrey Ponomarenko01117f12012-06-26 12:23:02 +040017651 my $TInfo = $ABI->{"TypeInfo"};
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040017652 if(not $TInfo)
17653 { # support for older ABI dumps
Andrey Ponomarenko01117f12012-06-26 12:23:02 +040017654 $TInfo = $ABI->{"TypeDescr"};
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040017655 }
17656 my %Tid_TDid = ();
17657 foreach my $TDid (keys(%{$TInfo}))
17658 {
17659 foreach my $Tid (keys(%{$TInfo->{$TDid}}))
17660 {
17661 $MAX_ID = $Tid if($Tid>$MAX_ID);
17662 $MAX_ID = $TDid if($TDid and $TDid>$MAX_ID);
17663 $Tid_TDid{$Tid}{$TDid}=1;
17664 }
17665 }
17666 my %NewID = ();
17667 foreach my $Tid (keys(%Tid_TDid))
17668 {
17669 my @TDids = keys(%{$Tid_TDid{$Tid}});
17670 if($#TDids>=1)
17671 {
17672 foreach my $TDid (@TDids)
17673 {
17674 if($TDid) {
17675 %{$TypeInfo{$LibVersion}{$Tid}} = %{$TInfo->{$TDid}{$Tid}};
17676 }
17677 else
17678 {
17679 if(my $ID = ++$MAX_ID)
17680 {
17681 $NewID{$TDid}{$Tid} = $ID;
17682 %{$TypeInfo{$LibVersion}{$ID}} = %{$TInfo->{$TDid}{$Tid}};
17683 $TypeInfo{$LibVersion}{$ID}{"Tid"} = $ID;
17684 }
17685 }
17686 }
17687 }
17688 else
17689 {
17690 my $TDid = $TDids[0];
17691 %{$TypeInfo{$LibVersion}{$Tid}} = %{$TInfo->{$TDid}{$Tid}};
17692 }
17693 }
17694 foreach my $Tid (keys(%{$TypeInfo{$LibVersion}}))
17695 {
17696 my %Info = %{$TypeInfo{$LibVersion}{$Tid}};
17697 if(defined $Info{"BaseType"})
17698 {
17699 my $Bid = $Info{"BaseType"}{"Tid"};
17700 my $BDid = $Info{"BaseType"}{"TDid"};
17701 $BDid="" if(not defined $BDid);
17702 if(defined $NewID{$BDid} and my $ID = $NewID{$BDid}{$Bid}) {
17703 $TypeInfo{$LibVersion}{$Tid}{"BaseType"}{"Tid"} = $ID;
17704 }
17705 delete($TypeInfo{$LibVersion}{$Tid}{"BaseType"}{"TDid"});
17706 }
17707 delete($TypeInfo{$LibVersion}{$Tid}{"TDid"});
17708 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017709 }
Andrey Ponomarenko01117f12012-06-26 12:23:02 +040017710 read_Machine_DumpInfo($ABI, $LibVersion);
17711 $SymbolInfo{$LibVersion} = $ABI->{"SymbolInfo"};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017712 if(not $SymbolInfo{$LibVersion})
17713 { # support for old dumps
Andrey Ponomarenko01117f12012-06-26 12:23:02 +040017714 $SymbolInfo{$LibVersion} = $ABI->{"FuncDescr"};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017715 }
17716 if(not keys(%{$SymbolInfo{$LibVersion}}))
17717 { # validation of old-version dumps
17718 if(not $ExtendedCheck) {
17719 exitStatus("Invalid_Dump", "the input dump d$LibVersion is invalid");
17720 }
17721 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040017722 if(checkDump($LibVersion, "2.15")) {
Andrey Ponomarenko01117f12012-06-26 12:23:02 +040017723 $DepLibrary_Symbol{$LibVersion} = $ABI->{"DepSymbols"};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017724 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040017725 else
17726 { # support for old ABI dumps
Andrey Ponomarenko01117f12012-06-26 12:23:02 +040017727 my $DepSymbols = $ABI->{"DepSymbols"};
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040017728 if(not $DepSymbols) {
Andrey Ponomarenko01117f12012-06-26 12:23:02 +040017729 $DepSymbols = $ABI->{"DepInterfaces"};
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040017730 }
17731 if(not $DepSymbols)
17732 { # Cannot reconstruct DepSymbols. This may result in false
17733 # positives if the old dump is for library 2. Not a problem if
17734 # old dumps are only from old libraries.
17735 $DepSymbols = {};
17736 }
17737 foreach my $Symbol (keys(%{$DepSymbols})) {
17738 $DepSymbol_Library{$LibVersion}{$Symbol} = 1;
17739 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017740 }
Andrey Ponomarenko01117f12012-06-26 12:23:02 +040017741 $SymVer{$LibVersion} = $ABI->{"SymbolVersion"};
17742 $Descriptor{$LibVersion}{"Version"} = $ABI->{"LibraryVersion"};
17743 $SkipTypes{$LibVersion} = $ABI->{"SkipTypes"};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017744 if(not $SkipTypes{$LibVersion})
17745 { # support for old dumps
Andrey Ponomarenko01117f12012-06-26 12:23:02 +040017746 $SkipTypes{$LibVersion} = $ABI->{"OpaqueTypes"};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017747 }
Andrey Ponomarenko01117f12012-06-26 12:23:02 +040017748 $SkipSymbols{$LibVersion} = $ABI->{"SkipSymbols"};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017749 if(not $SkipSymbols{$LibVersion})
17750 { # support for old dumps
Andrey Ponomarenko01117f12012-06-26 12:23:02 +040017751 $SkipSymbols{$LibVersion} = $ABI->{"SkipInterfaces"};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017752 }
17753 if(not $SkipSymbols{$LibVersion})
17754 { # support for old dumps
Andrey Ponomarenko01117f12012-06-26 12:23:02 +040017755 $SkipSymbols{$LibVersion} = $ABI->{"InternalInterfaces"};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017756 }
Andrey Ponomarenko01117f12012-06-26 12:23:02 +040017757 $SkipNameSpaces{$LibVersion} = $ABI->{"SkipNameSpaces"};
17758 $TargetHeaders{$LibVersion} = $ABI->{"TargetHeaders"};
17759 foreach my $Path (keys(%{$ABI->{"SkipHeaders"}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017760 {
Andrey Ponomarenko01117f12012-06-26 12:23:02 +040017761 $SkipHeadersList{$LibVersion}{$Path} = $ABI->{"SkipHeaders"}{$Path};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017762 my ($CPath, $Type) = classifyPath($Path);
Andrey Ponomarenko01117f12012-06-26 12:23:02 +040017763 $SkipHeaders{$LibVersion}{$Type}{$CPath} = $ABI->{"SkipHeaders"}{$Path};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017764 }
Andrey Ponomarenko01117f12012-06-26 12:23:02 +040017765 read_Headers_DumpInfo($ABI, $LibVersion);
17766 read_Libs_DumpInfo($ABI, $LibVersion);
Andrey Ponomarenko5c09ef32012-06-14 18:17:33 +040017767 if(not checkDump($LibVersion, "2.10.1")
17768 or not $TargetHeaders{$LibVersion})
Andrey Ponomarenko85043792012-05-14 16:48:07 +040017769 { # support for old ABI dumps: added target headers
17770 foreach (keys(%{$Registered_Headers{$LibVersion}})) {
17771 $TargetHeaders{$LibVersion}{get_filename($_)}=1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017772 }
17773 }
Andrey Ponomarenko01117f12012-06-26 12:23:02 +040017774 $Constants{$LibVersion} = $ABI->{"Constants"};
17775 $NestedNameSpaces{$LibVersion} = $ABI->{"NameSpaces"};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017776 if(not $NestedNameSpaces{$LibVersion})
17777 { # support for old dumps
17778 # Cannot reconstruct NameSpaces. This may affect design
17779 # of the compatibility report.
17780 $NestedNameSpaces{$LibVersion} = {};
17781 }
17782 # target system type
17783 # needed to adopt HTML report
17784 if(not $DumpSystem)
17785 { # to use in createSymbolsList(...)
Andrey Ponomarenko01117f12012-06-26 12:23:02 +040017786 $OStarget = $ABI->{"Target"};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017787 }
17788 # recreate environment
17789 foreach my $Lib_Name (keys(%{$Library_Symbol{$LibVersion}}))
17790 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040017791 foreach my $Symbol (keys(%{$Library_Symbol{$LibVersion}{$Lib_Name}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017792 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040017793 $Symbol_Library{$LibVersion}{$Symbol} = $Lib_Name;
17794 if($Library_Symbol{$LibVersion}{$Lib_Name}{$Symbol}<=-1)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017795 { # data marked as -size in the dump
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040017796 $GlobalDataObject{$LibVersion}{$Symbol}=1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017797 }
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040017798 if($COMMON_LANGUAGE{$LibVersion} ne "C++")
17799 {
17800 if(index($Symbol, "_Z")==0 or index($Symbol, "?")==0) {
17801 setLanguage($LibVersion, "C++");
17802 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017803 }
17804 }
17805 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040017806 foreach my $Lib_Name (keys(%{$DepLibrary_Symbol{$LibVersion}}))
17807 {
17808 foreach my $Symbol (keys(%{$DepLibrary_Symbol{$LibVersion}{$Lib_Name}})) {
17809 $DepSymbol_Library{$LibVersion}{$Symbol} = $Lib_Name;
17810 }
17811 }
17812
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017813 my @VFunc = ();
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040017814 foreach my $InfoId (keys(%{$SymbolInfo{$LibVersion}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017815 {
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +040017816 if(my $MnglName = $SymbolInfo{$LibVersion}{$InfoId}{"MnglName"})
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040017817 {
17818 if(not $Symbol_Library{$LibVersion}{$MnglName}
17819 and not $DepSymbol_Library{$LibVersion}{$MnglName}) {
17820 push(@VFunc, $MnglName);
17821 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017822 }
17823 }
17824 translateSymbols(@VFunc, $LibVersion);
17825 translateSymbols(keys(%{$Symbol_Library{$LibVersion}}), $LibVersion);
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040017826 translateSymbols(keys(%{$DepSymbol_Library{$LibVersion}}), $LibVersion);
17827
17828 foreach my $TypeId (sort {int($a)<=>int($b)} keys(%{$TypeInfo{$LibVersion}}))
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +040017829 { # order is important
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040017830 if(defined $TypeInfo{$LibVersion}{$TypeId}{"BaseClass"})
17831 { # support for old ABI dumps < 2.0 (ACC 1.22)
17832 foreach my $BId (keys(%{$TypeInfo{$LibVersion}{$TypeId}{"BaseClass"}}))
17833 {
17834 if(my $Access = $TypeInfo{$LibVersion}{$TypeId}{"BaseClass"}{$BId})
17835 {
17836 if($Access ne "public") {
17837 $TypeInfo{$LibVersion}{$TypeId}{"Base"}{$BId}{"access"} = $Access;
17838 }
17839 }
17840 $TypeInfo{$LibVersion}{$TypeId}{"Base"}{$BId} = {};
17841 }
17842 delete($TypeInfo{$LibVersion}{$TypeId}{"BaseClass"});
17843 }
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040017844 if(my $Header = $TypeInfo{$LibVersion}{$TypeId}{"Header"})
17845 { # support for old ABI dumps
17846 $TypeInfo{$LibVersion}{$TypeId}{"Header"} = path_format($Header, $OSgroup);
17847 }
Andrey Ponomarenko01117f12012-06-26 12:23:02 +040017848 if(not defined $TypeInfo{$LibVersion}{$TypeId}{"Tid"}) {
17849 $TypeInfo{$LibVersion}{$TypeId}{"Tid"} = $TypeId;
17850 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040017851 my %TInfo = %{$TypeInfo{$LibVersion}{$TypeId}};
17852 if(defined $TInfo{"Base"})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017853 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040017854 foreach (keys(%{$TInfo{"Base"}})) {
17855 $Class_SubClasses{$LibVersion}{$_}{$TypeId}=1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017856 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040017857 }
Andrey Ponomarenko01117f12012-06-26 12:23:02 +040017858 if($TInfo{"Type"} eq "MethodPtr")
17859 {
17860 if(defined $TInfo{"Param"})
17861 { # support for old ABI dumps <= 1.17
17862 if(not defined $TInfo{"Param"}{"0"})
17863 {
17864 my $Max = keys(%{$TInfo{"Param"}});
17865 foreach my $Pos (1 .. $Max) {
17866 $TInfo{"Param"}{$Pos-1} = $TInfo{"Param"}{$Pos};
17867 }
17868 delete($TInfo{"Param"}{$Max});
17869 %{$TypeInfo{$LibVersion}{$TypeId}} = %TInfo;
17870 }
17871 }
17872 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040017873 if($TInfo{"Type"} eq "Typedef" and defined $TInfo{"BaseType"})
17874 {
17875 if(my $BTid = $TInfo{"BaseType"}{"Tid"})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017876 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040017877 my $BName = $TypeInfo{$LibVersion}{$BTid}{"Name"};
17878 if(not $BName)
17879 { # broken type
17880 next;
17881 }
17882 if($TInfo{"Name"} eq $BName)
17883 { # typedef to "class Class"
17884 # should not be registered in TName_Tid
17885 next;
17886 }
17887 if(not $Typedef_BaseName{$LibVersion}{$TInfo{"Name"}}) {
17888 $Typedef_BaseName{$LibVersion}{$TInfo{"Name"}} = $BName;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017889 }
17890 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040017891 }
17892 if(not $TName_Tid{$LibVersion}{$TInfo{"Name"}})
17893 { # classes: class (id1), typedef (artificial, id2 > id1)
17894 $TName_Tid{$LibVersion}{$TInfo{"Name"}} = $TypeId;
17895 }
17896 }
17897
17898 if(not checkDump($LibVersion, "2.15"))
17899 { # support for old ABI dumps
17900 my %Dups = ();
17901 foreach my $InfoId (keys(%{$SymbolInfo{$LibVersion}}))
17902 {
17903 if(my $ClassId = $SymbolInfo{$LibVersion}{$InfoId}{"Class"})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017904 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040017905 if(not defined $TypeInfo{$LibVersion}{$ClassId})
17906 { # remove template decls
17907 delete($SymbolInfo{$LibVersion}{$InfoId});
17908 next;
Andrey Ponomarenko16934472012-03-29 15:37:04 +040017909 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017910 }
Andrey Ponomarenkob8d203d2012-05-25 18:11:07 +040017911 my $MName = $SymbolInfo{$LibVersion}{$InfoId}{"MnglName"};
17912 if(not $MName and $SymbolInfo{$LibVersion}{$InfoId}{"Class"})
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040017913 { # templates
17914 delete($SymbolInfo{$LibVersion}{$InfoId});
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017915 }
17916 }
17917 }
17918
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +040017919 foreach my $InfoId (keys(%{$SymbolInfo{$LibVersion}}))
17920 {
17921 if(not $SymbolInfo{$LibVersion}{$InfoId}{"MnglName"})
17922 { # ABI dumps have no mangled names for C-functions
17923 $SymbolInfo{$LibVersion}{$InfoId}{"MnglName"} = $SymbolInfo{$LibVersion}{$InfoId}{"ShortName"};
17924 }
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040017925 if(my $Header = $SymbolInfo{$LibVersion}{$InfoId}{"Header"})
17926 { # support for old ABI dumps
17927 $SymbolInfo{$LibVersion}{$InfoId}{"Header"} = path_format($Header, $OSgroup);
17928 }
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +040017929 }
17930
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017931 $Descriptor{$LibVersion}{"Dump"} = 1;
17932}
17933
17934sub read_Machine_DumpInfo($$)
17935{
Andrey Ponomarenko01117f12012-06-26 12:23:02 +040017936 my ($ABI, $LibVersion) = @_;
17937 if($ABI->{"Arch"}) {
17938 $CPU_ARCH{$LibVersion} = $ABI->{"Arch"};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017939 }
Andrey Ponomarenko01117f12012-06-26 12:23:02 +040017940 if($ABI->{"WordSize"}) {
17941 $WORD_SIZE{$LibVersion} = $ABI->{"WordSize"};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017942 }
17943 else
17944 { # support for old dumps
Andrey Ponomarenko01117f12012-06-26 12:23:02 +040017945 $WORD_SIZE{$LibVersion} = $ABI->{"SizeOfPointer"};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017946 }
17947 if(not $WORD_SIZE{$LibVersion})
17948 { # support for old dumps (<1.23)
17949 if(my $Tid = getTypeIdByName("char*", $LibVersion))
17950 { # size of char*
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040017951 $WORD_SIZE{$LibVersion} = $TypeInfo{$LibVersion}{$Tid}{"Size"};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017952 }
17953 else
17954 {
17955 my $PSize = 0;
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040017956 foreach my $Tid (keys(%{$TypeInfo{$LibVersion}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017957 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040017958 if($TypeInfo{$LibVersion}{$Tid}{"Type"} eq "Pointer")
17959 { # any "pointer"-type
17960 $PSize = $TypeInfo{$LibVersion}{$Tid}{"Size"};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017961 last;
17962 }
17963 }
17964 if($PSize)
17965 { # a pointer type size
17966 $WORD_SIZE{$LibVersion} = $PSize;
17967 }
17968 else {
17969 printMsg("WARNING", "cannot identify a WORD size in the ABI dump (too old format)");
17970 }
17971 }
17972 }
Andrey Ponomarenko01117f12012-06-26 12:23:02 +040017973 if($ABI->{"GccVersion"}) {
17974 $GCC_VERSION{$LibVersion} = $ABI->{"GccVersion"};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017975 }
17976}
17977
17978sub read_Libs_DumpInfo($$)
17979{
Andrey Ponomarenko01117f12012-06-26 12:23:02 +040017980 my ($ABI, $LibVersion) = @_;
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040017981 $Library_Symbol{$LibVersion} = $ABI->{"Symbols"};
17982 if(not $Library_Symbol{$LibVersion})
17983 { # support for old dumps
17984 $Library_Symbol{$LibVersion} = $ABI->{"Interfaces"};
17985 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017986 if(keys(%{$Library_Symbol{$LibVersion}})
17987 and not $DumpAPI) {
17988 $Descriptor{$LibVersion}{"Libs"} = "OK";
17989 }
17990}
17991
17992sub read_Headers_DumpInfo($$)
17993{
Andrey Ponomarenko01117f12012-06-26 12:23:02 +040017994 my ($ABI, $LibVersion) = @_;
17995 if(keys(%{$ABI->{"Headers"}})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017996 and not $DumpAPI) {
17997 $Descriptor{$LibVersion}{"Headers"} = "OK";
17998 }
Andrey Ponomarenko01117f12012-06-26 12:23:02 +040017999 foreach my $Identity (sort {$ABI->{"Headers"}{$a}<=>$ABI->{"Headers"}{$b}} keys(%{$ABI->{"Headers"}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040018000 { # headers info is stored in the old dumps in the different way
18001 if($UseOldDumps
Andrey Ponomarenko01117f12012-06-26 12:23:02 +040018002 and my $Name = $ABI->{"Headers"}{$Identity}{"Name"})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040018003 { # support for old dumps: headers info corrected in 1.22
18004 $Identity = $Name;
18005 }
18006 $Registered_Headers{$LibVersion}{$Identity}{"Identity"} = $Identity;
Andrey Ponomarenko01117f12012-06-26 12:23:02 +040018007 $Registered_Headers{$LibVersion}{$Identity}{"Pos"} = $ABI->{"Headers"}{$Identity};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040018008 }
18009}
18010
18011sub find_libs($$$)
18012{
18013 my ($Path, $Type, $MaxDepth) = @_;
18014 # FIXME: correct the search pattern
18015 return cmd_find($Path, $Type, ".*\\.$LIB_EXT\[0-9.]*", $MaxDepth);
18016}
18017
18018sub createDescriptor($$)
18019{
18020 my ($LibVersion, $Path) = @_;
18021 if(not $LibVersion or not $Path
18022 or not -e $Path) {
18023 return "";
18024 }
18025 if(-d $Path)
18026 { # directory with headers files and shared objects
18027 return "
18028 <version>
18029 ".$TargetVersion{$LibVersion}."
18030 </version>
18031
18032 <headers>
18033 $Path
18034 </headers>
18035
18036 <libs>
18037 $Path
18038 </libs>";
18039 }
18040 else
18041 { # files
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040018042 if($Path=~/\.(xml|desc)\Z/i)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040018043 { # standard XML-descriptor
18044 return readFile($Path);
18045 }
18046 elsif(is_header($Path, 2, $LibVersion))
18047 { # header file
18048 return "
18049 <version>
18050 ".$TargetVersion{$LibVersion}."
18051 </version>
18052
18053 <headers>
18054 $Path
18055 </headers>
18056
18057 <libs>
18058 none
18059 </libs>";
18060 }
18061 elsif(parse_libname($Path, "name", $OStarget))
18062 { # shared object
18063 return "
18064 <version>
18065 ".$TargetVersion{$LibVersion}."
18066 </version>
18067
18068 <headers>
18069 none
18070 </headers>
18071
18072 <libs>
18073 $Path
18074 </libs>";
18075 }
18076 else
18077 { # standard XML-descriptor
18078 return readFile($Path);
18079 }
18080 }
18081}
18082
18083sub detect_lib_default_paths()
18084{
18085 my %LPaths = ();
18086 if($OSgroup eq "bsd")
18087 {
Andrey Ponomarenkoa01311b2012-06-08 17:20:02 +040018088 if(my $LdConfig = get_CmdPath("ldconfig"))
18089 {
18090 foreach my $Line (split(/\n/, `$LdConfig -r 2>\"$TMP_DIR/null\"`))
18091 {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040018092 if($Line=~/\A[ \t]*\d+:\-l(.+) \=\> (.+)\Z/) {
18093 $LPaths{"lib".$1} = $2;
18094 }
18095 }
18096 }
18097 else {
18098 printMsg("WARNING", "can't find ldconfig");
18099 }
18100 }
18101 else
18102 {
18103 if(my $LdConfig = get_CmdPath("ldconfig"))
18104 {
18105 if($SystemRoot and $OSgroup eq "linux")
18106 { # use host (x86) ldconfig with the target (arm) ld.so.conf
18107 if(-e $SystemRoot."/etc/ld.so.conf") {
18108 $LdConfig .= " -f ".$SystemRoot."/etc/ld.so.conf";
18109 }
18110 }
Andrey Ponomarenkoa01311b2012-06-08 17:20:02 +040018111 foreach my $Line (split(/\n/, `$LdConfig -p 2>\"$TMP_DIR/null\"`))
18112 {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040018113 if($Line=~/\A[ \t]*([^ \t]+) .* \=\> (.+)\Z/)
18114 {
18115 my ($Name, $Path) = ($1, $2);
18116 $Path=~s/[\/]{2,}/\//;
18117 $LPaths{$Name} = $Path;
18118 }
18119 }
18120 }
Andrey Ponomarenko82b005f2012-11-12 17:58:14 +040018121 elsif($OSgroup eq "linux") {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040018122 printMsg("WARNING", "can't find ldconfig");
18123 }
18124 }
18125 return \%LPaths;
18126}
18127
18128sub detect_bin_default_paths()
18129{
18130 my $EnvPaths = $ENV{"PATH"};
18131 if($OSgroup eq "beos") {
18132 $EnvPaths.=":".$ENV{"BETOOLS"};
18133 }
18134 my $Sep = ($OSgroup eq "windows")?";":":|;";
18135 foreach my $Path (sort {length($a)<=>length($b)} split(/$Sep/, $EnvPaths))
18136 {
18137 $Path = path_format($Path, $OSgroup);
18138 $Path=~s/[\/\\]+\Z//g;
18139 next if(not $Path);
18140 if($SystemRoot
18141 and $Path=~/\A\Q$SystemRoot\E\//)
18142 { # do NOT use binaries from target system
18143 next;
18144 }
18145 $DefaultBinPaths{$Path} = 1;
18146 }
18147}
18148
18149sub detect_inc_default_paths()
18150{
18151 return () if(not $GCC_PATH);
18152 my %DPaths = ("Cpp"=>{},"Gcc"=>{},"Inc"=>{});
18153 writeFile("$TMP_DIR/empty.h", "");
Andrey Ponomarenkoa01311b2012-06-08 17:20:02 +040018154 foreach my $Line (split(/\n/, `$GCC_PATH -v -x c++ -E \"$TMP_DIR/empty.h\" 2>&1`))
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040018155 { # detecting GCC default include paths
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040018156 if($Line=~/\A[ \t]*((\/|\w+:\\).+)[ \t]*\Z/)
18157 {
18158 my $Path = simplify_path($1);
18159 $Path=~s/[\/\\]+\Z//g;
18160 $Path = path_format($Path, $OSgroup);
18161 if($Path=~/c\+\+|\/g\+\+\//)
18162 {
18163 $DPaths{"Cpp"}{$Path}=1;
18164 if(not defined $MAIN_CPP_DIR
18165 or get_depth($MAIN_CPP_DIR)>get_depth($Path)) {
18166 $MAIN_CPP_DIR = $Path;
18167 }
18168 }
18169 elsif($Path=~/gcc/) {
18170 $DPaths{"Gcc"}{$Path}=1;
18171 }
18172 else
18173 {
18174 next if($Path=~/local[\/\\]+include/);
18175 if($SystemRoot
18176 and $Path!~/\A\Q$SystemRoot\E(\/|\Z)/)
18177 { # The GCC include path for user headers is not a part of the system root
18178 # The reason: you are not specified the --cross-gcc option or selected a wrong compiler
18179 # or it is the internal cross-GCC path like arm-linux-gnueabi/include
18180 next;
18181 }
18182 $DPaths{"Inc"}{$Path}=1;
18183 }
18184 }
18185 }
18186 unlink("$TMP_DIR/empty.h");
18187 return %DPaths;
18188}
18189
18190sub detect_default_paths($)
18191{
18192 my ($HSearch, $LSearch, $BSearch, $GSearch) = (1, 1, 1, 1);
18193 my $Search = $_[0];
18194 if($Search!~/inc/) {
18195 $HSearch = 0;
18196 }
18197 if($Search!~/lib/) {
18198 $LSearch = 0;
18199 }
18200 if($Search!~/bin/) {
18201 $BSearch = 0;
18202 }
18203 if($Search!~/gcc/) {
18204 $GSearch = 0;
18205 }
18206 if(keys(%{$SystemPaths{"include"}}))
18207 { # <search_headers> section of the XML descriptor
18208 # do NOT search for systems headers
18209 $HSearch = 0;
18210 }
18211 if(keys(%{$SystemPaths{"lib"}}))
18212 { # <search_headers> section of the XML descriptor
18213 # do NOT search for systems headers
18214 $LSearch = 0;
18215 }
18216 foreach my $Type (keys(%{$OS_AddPath{$OSgroup}}))
18217 { # additional search paths
18218 next if($Type eq "include" and not $HSearch);
18219 next if($Type eq "lib" and not $LSearch);
18220 next if($Type eq "bin" and not $BSearch);
18221 foreach my $Path (keys(%{$OS_AddPath{$OSgroup}{$Type}}))
18222 {
18223 next if(not -d $Path);
18224 $SystemPaths{$Type}{$Path} = $OS_AddPath{$OSgroup}{$Type}{$Path};
18225 }
18226 }
18227 if($OSgroup ne "windows")
18228 { # unix-like
18229 foreach my $Type ("include", "lib", "bin")
18230 { # automatic detection of system "devel" directories
18231 next if($Type eq "include" and not $HSearch);
18232 next if($Type eq "lib" and not $LSearch);
18233 next if($Type eq "bin" and not $BSearch);
18234 my ($UsrDir, $RootDir) = ("/usr", "/");
18235 if($SystemRoot and $Type ne "bin")
18236 { # 1. search for target headers and libraries
18237 # 2. use host commands: ldconfig, readelf, etc.
18238 ($UsrDir, $RootDir) = ("$SystemRoot/usr", $SystemRoot);
18239 }
18240 foreach my $Path (cmd_find($RootDir,"d","*$Type*",1)) {
18241 $SystemPaths{$Type}{$Path} = 1;
18242 }
18243 if(-d $RootDir."/".$Type)
18244 { # if "/lib" is symbolic link
18245 if($RootDir eq "/") {
18246 $SystemPaths{$Type}{"/".$Type} = 1;
18247 }
18248 else {
18249 $SystemPaths{$Type}{$RootDir."/".$Type} = 1;
18250 }
18251 }
18252 if(-d $UsrDir) {
18253 foreach my $Path (cmd_find($UsrDir,"d","*$Type*",1)) {
18254 $SystemPaths{$Type}{$Path} = 1;
18255 }
18256 if(-d $UsrDir."/".$Type)
18257 { # if "/usr/lib" is symbolic link
18258 $SystemPaths{$Type}{$UsrDir."/".$Type} = 1;
18259 }
18260 }
18261 }
18262 }
18263 if($BSearch)
18264 {
18265 detect_bin_default_paths();
18266 foreach my $Path (keys(%DefaultBinPaths)) {
18267 $SystemPaths{"bin"}{$Path} = $DefaultBinPaths{$Path};
18268 }
18269 }
18270 # check environment variables
18271 if($OSgroup eq "beos")
18272 {
18273 foreach (keys(%{$SystemPaths{"bin"}}))
18274 {
18275 if($_ eq ".") {
18276 next;
18277 }
18278 foreach my $Path (cmd_find($_, "d", "bin", ""))
18279 { # search for /boot/develop/abi/x86/gcc4/tools/gcc-4.4.4-haiku-101111/bin/
18280 $SystemPaths{"bin"}{$Path} = 1;
18281 }
18282 }
18283 if($HSearch)
18284 {
18285 foreach my $Path (split(/:|;/, $ENV{"BEINCLUDES"}))
18286 {
18287 if(is_abs($Path)) {
18288 $DefaultIncPaths{$Path} = 1;
18289 }
18290 }
18291 }
18292 if($LSearch)
18293 {
18294 foreach my $Path (split(/:|;/, $ENV{"BELIBRARIES"}), split(/:|;/, $ENV{"LIBRARY_PATH"}))
18295 {
18296 if(is_abs($Path)) {
18297 $DefaultLibPaths{$Path} = 1;
18298 }
18299 }
18300 }
18301 }
18302 if($LSearch)
18303 { # using linker to get system paths
18304 if(my $LPaths = detect_lib_default_paths())
18305 { # unix-like
18306 foreach my $Name (keys(%{$LPaths}))
18307 {
18308 if($SystemRoot
18309 and $LPaths->{$Name}!~/\A\Q$SystemRoot\E\//)
18310 { # wrong ldconfig configuration
18311 # check your <sysroot>/etc/ld.so.conf
18312 next;
18313 }
18314 $DyLib_DefaultPath{$Name} = $LPaths->{$Name};
18315 $DefaultLibPaths{get_dirname($LPaths->{$Name})} = 1;
18316 }
18317 }
18318 foreach my $Path (keys(%DefaultLibPaths)) {
18319 $SystemPaths{"lib"}{$Path} = $DefaultLibPaths{$Path};
18320 }
18321 }
18322 if($BSearch)
18323 {
18324 if($CrossGcc)
18325 { # --cross-gcc=arm-linux-gcc
18326 if(-e $CrossGcc)
18327 { # absolute or relative path
18328 $GCC_PATH = get_abs_path($CrossGcc);
18329 }
18330 elsif($CrossGcc!~/\// and get_CmdPath($CrossGcc))
18331 { # command name
18332 $GCC_PATH = $CrossGcc;
18333 }
18334 else {
18335 exitStatus("Access_Error", "can't access \'$CrossGcc\'");
18336 }
18337 if($GCC_PATH=~/\s/) {
18338 $GCC_PATH = "\"".$GCC_PATH."\"";
18339 }
18340 }
18341 }
18342 if($GSearch)
18343 { # GCC path and default include dirs
18344 if(not $CrossGcc) {
18345 $GCC_PATH = get_CmdPath("gcc");
18346 }
Andrey Ponomarenko01117f12012-06-26 12:23:02 +040018347 if(not $GCC_PATH)
18348 { # try to find gcc-X.Y
18349 foreach my $Path (sort {$b=~/\/usr\/bin/ cmp $a=~/\/usr\/bin/}
18350 keys(%{$SystemPaths{"bin"}}))
18351 {
18352 if(my @GCCs = cmd_find($Path, "", ".*/gcc-[0-9.]*", 1))
18353 { # select the latest version
18354 @GCCs = sort {$b cmp $a} @GCCs;
18355 if(check_gcc($GCCs[0], "3"))
18356 {
18357 $GCC_PATH = $GCCs[0];
18358 last;
18359 }
18360 }
18361 }
18362 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040018363 if(not $GCC_PATH) {
18364 exitStatus("Not_Found", "can't find GCC>=3.0 in PATH");
18365 }
18366 if(not $CheckObjectsOnly_Opt)
18367 {
18368 if(my $GCC_Ver = get_dumpversion($GCC_PATH))
18369 {
18370 my $GccTarget = get_dumpmachine($GCC_PATH);
18371 printMsg("INFO", "Using GCC $GCC_Ver ($GccTarget)");
18372 if($GccTarget=~/symbian/)
18373 {
18374 $OStarget = "symbian";
18375 $LIB_EXT = $OS_LibExt{$LIB_TYPE}{$OStarget};
18376 }
18377 }
18378 else {
18379 exitStatus("Error", "something is going wrong with the GCC compiler");
18380 }
18381 }
18382 if(not $NoStdInc)
18383 { # do NOT search in GCC standard paths
18384 my %DPaths = detect_inc_default_paths();
18385 %DefaultCppPaths = %{$DPaths{"Cpp"}};
18386 %DefaultGccPaths = %{$DPaths{"Gcc"}};
18387 %DefaultIncPaths = %{$DPaths{"Inc"}};
18388 foreach my $Path (keys(%DefaultIncPaths)) {
18389 $SystemPaths{"include"}{$Path} = $DefaultIncPaths{$Path};
18390 }
18391 }
18392 }
18393 if($HSearch)
18394 { # user include paths
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040018395 my $IncPath = "/usr/include";
18396 if($SystemRoot) {
18397 $IncPath = $SystemRoot.$IncPath;
18398 }
18399 if(-d $IncPath) {
18400 $UserIncPath{$IncPath}=1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040018401 }
18402 }
18403}
18404
18405sub getLIB_EXT($)
18406{
18407 my $Target = $_[0];
18408 if(my $Ext = $OS_LibExt{$LIB_TYPE}{$Target}) {
18409 return $Ext;
18410 }
18411 return $OS_LibExt{$LIB_TYPE}{"default"};
18412}
18413
18414sub getAR_EXT($)
18415{
18416 my $Target = $_[0];
18417 if(my $Ext = $OS_Archive{$Target}) {
18418 return $Ext;
18419 }
18420 return $OS_Archive{"default"};
18421}
18422
18423sub get_dumpversion($)
18424{
18425 my $Cmd = $_[0];
18426 return "" if(not $Cmd);
18427 if($Cache{"get_dumpversion"}{$Cmd}) {
18428 return $Cache{"get_dumpversion"}{$Cmd};
18429 }
Andrey Ponomarenkoa01311b2012-06-08 17:20:02 +040018430 my $V = `$Cmd -dumpversion 2>\"$TMP_DIR/null\"`;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040018431 chomp($V);
18432 return ($Cache{"get_dumpversion"}{$Cmd} = $V);
18433}
18434
18435sub get_dumpmachine($)
18436{
18437 my $Cmd = $_[0];
18438 return "" if(not $Cmd);
18439 if($Cache{"get_dumpmachine"}{$Cmd}) {
18440 return $Cache{"get_dumpmachine"}{$Cmd};
18441 }
Andrey Ponomarenkoa01311b2012-06-08 17:20:02 +040018442 my $Machine = `$Cmd -dumpmachine 2>\"$TMP_DIR/null\"`;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040018443 chomp($Machine);
18444 return ($Cache{"get_dumpmachine"}{$Cmd} = $Machine);
18445}
18446
18447sub check_command($)
18448{
18449 my $Cmd = $_[0];
18450 return "" if(not $Cmd);
18451 my @Options = (
18452 "--version",
18453 "-help"
18454 );
18455 foreach my $Opt (@Options)
18456 {
Andrey Ponomarenkoa01311b2012-06-08 17:20:02 +040018457 my $Info = `$Cmd $Opt 2>\"$TMP_DIR/null\"`;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040018458 if($Info) {
18459 return 1;
18460 }
18461 }
18462 return 0;
18463}
18464
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040018465sub check_gcc($$)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040018466{
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040018467 my ($Cmd, $ReqVer) = @_;
18468 return 0 if(not $Cmd or not $ReqVer);
18469 if(defined $Cache{"check_gcc"}{$Cmd}{$ReqVer}) {
18470 return $Cache{"check_gcc"}{$Cmd}{$ReqVer};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040018471 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040018472 if(my $GccVer = get_dumpversion($Cmd))
18473 {
18474 $GccVer=~s/(-|_)[a-z_]+.*\Z//; # remove suffix (like "-haiku-100818")
18475 if(cmpVersions($GccVer, $ReqVer)>=0) {
18476 return ($Cache{"check_gcc"}{$Cmd}{$ReqVer} = $Cmd);
18477 }
18478 }
18479 return ($Cache{"check_gcc"}{$Cmd}{$ReqVer} = "");
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040018480}
18481
18482sub get_depth($)
18483{
18484 if(defined $Cache{"get_depth"}{$_[0]}) {
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040018485 return $Cache{"get_depth"}{$_[0]};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040018486 }
18487 return ($Cache{"get_depth"}{$_[0]} = ($_[0]=~tr![\/\\]|\:\:!!));
18488}
18489
18490sub find_gcc_cxx_headers($)
18491{
18492 my $LibVersion = $_[0];
18493 return if($Cache{"find_gcc_cxx_headers"});# this function should be called once
18494 # detecting system header paths
18495 foreach my $Path (sort {get_depth($b) <=> get_depth($a)} keys(%DefaultGccPaths))
18496 {
18497 foreach my $HeaderPath (sort {get_depth($a) <=> get_depth($b)} cmd_find($Path,"f","",""))
18498 {
18499 my $FileName = get_filename($HeaderPath);
18500 next if($DefaultGccHeader{$FileName});
18501 $DefaultGccHeader{$FileName} = $HeaderPath;
18502 }
18503 }
18504 if($COMMON_LANGUAGE{$LibVersion} eq "C++" and not $STDCXX_TESTING)
18505 {
18506 foreach my $CppDir (sort {get_depth($b)<=>get_depth($a)} keys(%DefaultCppPaths))
18507 {
18508 my @AllCppHeaders = cmd_find($CppDir,"f","","");
18509 foreach my $Path (sort {get_depth($a)<=>get_depth($b)} @AllCppHeaders)
18510 {
18511 my $FileName = get_filename($Path);
18512 next if($DefaultCppHeader{$FileName});
18513 $DefaultCppHeader{$FileName} = $Path;
18514 }
18515 }
18516 }
18517 $Cache{"find_gcc_cxx_headers"} = 1;
18518}
18519
18520sub parse_libname($$$)
18521{
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040018522 return "" if(not $_[0]);
18523 if(defined $Cache{"parse_libname"}{$_[2]}{$_[1]}{$_[0]}) {
18524 return $Cache{"parse_libname"}{$_[2]}{$_[1]}{$_[0]};
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040018525 }
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040018526 return ($Cache{"parse_libname"}{$_[2]}{$_[1]}{$_[0]} = parse_libname_I(@_));
18527}
18528
18529sub parse_libname_I($$$)
18530{
18531 my ($Name, $Type, $Target) = @_;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040018532 if($Target eq "symbian") {
18533 return parse_libname_symbian($Name, $Type);
18534 }
18535 elsif($Target eq "windows") {
18536 return parse_libname_windows($Name, $Type);
18537 }
18538 my $Ext = getLIB_EXT($Target);
Andrey Ponomarenkoa01311b2012-06-08 17:20:02 +040018539 if($Name=~/((((lib|).+?)([\-\_][\d\-\.\_]+.*?|))\.$Ext)(\.(.+)|)\Z/)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040018540 { # libSDL-1.2.so.0.7.1
18541 # libwbxml2.so.0.0.18
Andrey Ponomarenkoa01311b2012-06-08 17:20:02 +040018542 # libopcodes-2.21.53-system.20110810.so
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040018543 if($Type eq "name")
18544 { # libSDL-1.2
18545 # libwbxml2
18546 return $2;
18547 }
18548 elsif($Type eq "name+ext")
18549 { # libSDL-1.2.so
18550 # libwbxml2.so
18551 return $1;
18552 }
18553 elsif($Type eq "version")
18554 {
Andrey Ponomarenkoa01311b2012-06-08 17:20:02 +040018555 if(defined $7
18556 and $7 ne "")
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040018557 { # 0.7.1
18558 return $7;
18559 }
18560 else
18561 { # libc-2.5.so (=>2.5 version)
18562 my $MV = $5;
18563 $MV=~s/\A[\-\_]+//g;
18564 return $MV;
18565 }
18566 }
18567 elsif($Type eq "short")
18568 { # libSDL
18569 # libwbxml2
18570 return $3;
18571 }
18572 elsif($Type eq "shortest")
18573 { # SDL
18574 # wbxml
18575 return shortest_name($3);
18576 }
18577 }
18578 return "";# error
18579}
18580
18581sub parse_libname_symbian($$)
18582{
18583 my ($Name, $Type) = @_;
18584 my $Ext = getLIB_EXT("symbian");
18585 if($Name=~/(((.+?)(\{.+\}|))\.$Ext)\Z/)
18586 { # libpthread{00010001}.dso
18587 if($Type eq "name")
18588 { # libpthread{00010001}
18589 return $2;
18590 }
18591 elsif($Type eq "name+ext")
18592 { # libpthread{00010001}.dso
18593 return $1;
18594 }
18595 elsif($Type eq "version")
18596 { # 00010001
18597 my $V = $4;
18598 $V=~s/\{(.+)\}/$1/;
18599 return $V;
18600 }
18601 elsif($Type eq "short")
18602 { # libpthread
18603 return $3;
18604 }
18605 elsif($Type eq "shortest")
18606 { # pthread
18607 return shortest_name($3);
18608 }
18609 }
18610 return "";# error
18611}
18612
18613sub parse_libname_windows($$)
18614{
18615 my ($Name, $Type) = @_;
18616 my $Ext = getLIB_EXT("windows");
18617 if($Name=~/((.+?)\.$Ext)\Z/)
18618 { # netapi32.dll
18619 if($Type eq "name")
18620 { # netapi32
18621 return $2;
18622 }
18623 elsif($Type eq "name+ext")
18624 { # netapi32.dll
18625 return $1;
18626 }
18627 elsif($Type eq "version")
18628 { # DLL version embedded
18629 # at binary-level
18630 return "";
18631 }
18632 elsif($Type eq "short")
18633 { # netapi32
18634 return $2;
18635 }
18636 elsif($Type eq "shortest")
18637 { # netapi
18638 return shortest_name($2);
18639 }
18640 }
18641 return "";# error
18642}
18643
18644sub shortest_name($)
18645{
18646 my $Name = $_[0];
18647 # remove prefix
18648 $Name=~s/\A(lib|open)//;
18649 # remove suffix
18650 $Name=~s/[\W\d_]+\Z//i;
18651 $Name=~s/([a-z]{2,})(lib)\Z/$1/i;
18652 return $Name;
18653}
18654
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040018655sub createSymbolsList($$$$$)
18656{
18657 my ($DPath, $SaveTo, $LName, $LVersion, $ArchName) = @_;
18658 read_ABI_Dump(1, $DPath);
18659 if(not $CheckObjectsOnly) {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040018660 prepareSymbols(1);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040018661 }
18662 my %SymbolHeaderLib = ();
18663 my $Total = 0;
18664 # Get List
18665 foreach my $Symbol (sort keys(%{$CompleteSignature{1}}))
18666 {
18667 if(not link_symbol($Symbol, 1, "-Deps"))
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040018668 { # skip src only and all external functions
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040018669 next;
18670 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040018671 if(not symbolFilter($Symbol, 1, "Public", "Binary"))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040018672 { # skip other symbols
18673 next;
18674 }
18675 my $HeaderName = $CompleteSignature{1}{$Symbol}{"Header"};
18676 if(not $HeaderName)
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040018677 { # skip src only and all external functions
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040018678 next;
18679 }
18680 my $DyLib = $Symbol_Library{1}{$Symbol};
18681 if(not $DyLib)
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040018682 { # skip src only and all external functions
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040018683 next;
18684 }
18685 $SymbolHeaderLib{$HeaderName}{$DyLib}{$Symbol} = 1;
18686 $Total+=1;
18687 }
18688 # Draw List
18689 my $SYMBOLS_LIST = "<h1>Public symbols in <span style='color:Blue;'>$LName</span> (<span style='color:Red;'>$LVersion</span>)";
18690 $SYMBOLS_LIST .= " on <span style='color:Blue;'>".showArch($ArchName)."</span><br/>Total: $Total</h1><br/>";
18691 foreach my $HeaderName (sort {lc($a) cmp lc($b)} keys(%SymbolHeaderLib))
18692 {
18693 foreach my $DyLib (sort {lc($a) cmp lc($b)} keys(%{$SymbolHeaderLib{$HeaderName}}))
18694 {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040018695 my %NS_Symbol = ();
18696 foreach my $Symbol (keys(%{$SymbolHeaderLib{$HeaderName}{$DyLib}})) {
18697 $NS_Symbol{get_IntNameSpace($Symbol, 1)}{$Symbol} = 1;
18698 }
18699 foreach my $NameSpace (sort keys(%NS_Symbol))
18700 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040018701 $SYMBOLS_LIST .= getTitle($HeaderName, $DyLib, $NameSpace);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040018702 my @SortedInterfaces = sort {lc(get_Signature($a, 1)) cmp lc(get_Signature($b, 1))} keys(%{$NS_Symbol{$NameSpace}});
18703 foreach my $Symbol (@SortedInterfaces)
18704 {
18705 my $SubReport = "";
18706 my $Signature = get_Signature($Symbol, 1);
18707 if($NameSpace) {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040018708 $Signature=~s/\b\Q$NameSpace\E::\b//g;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040018709 }
18710 if($Symbol=~/\A(_Z|\?)/)
18711 {
18712 if($Signature) {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040018713 $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 +040018714 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040018715 else {
18716 $SubReport = "<span class='iname'>".$Symbol."</span><br/>\n";
18717 }
18718 }
18719 else
18720 {
18721 if($Signature) {
18722 $SubReport = "<span class='iname'>".highLight_Signature_Italic_Color($Signature)."</span><br/>\n";
18723 }
18724 else {
18725 $SubReport = "<span class='iname'>".$Symbol."</span><br/>\n";
18726 }
18727 }
18728 $SYMBOLS_LIST .= $SubReport;
18729 }
18730 }
18731 $SYMBOLS_LIST .= "<br/>\n";
18732 }
18733 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040018734 # clear info
18735 (%TypeInfo, %SymbolInfo, %Library_Symbol, %DepSymbol_Library,
18736 %DepLibrary_Symbol, %SymVer, %SkipTypes, %SkipSymbols,
18737 %NestedNameSpaces, %ClassMethods, %AllocableClass, %ClassNames,
18738 %CompleteSignature, %SkipNameSpaces, %Symbol_Library, %Library_Symbol) = ();
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040018739 ($Content_Counter, $ContentID) = (0, 0);
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040018740 # print report
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040018741 my $CssStyles = readModule("Styles", "SymbolsList.css");
18742 my $JScripts = readModule("Scripts", "Sections.js");
18743 $SYMBOLS_LIST = "<a name='Top'></a>".$SYMBOLS_LIST.$TOP_REF."<br/>\n";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040018744 my $Title = "$LName: public symbols";
18745 my $Keywords = "$LName, API, symbols";
18746 my $Description = "List of symbols in $LName ($LVersion) on ".showArch($ArchName);
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040018747 $SYMBOLS_LIST = composeHTML_Head($Title, $Keywords, $Description, $CssStyles, $JScripts)."
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040018748 <body><div>\n$SYMBOLS_LIST</div>
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040018749 <br/><br/><hr/>\n".getReportFooter($LName, 1)."
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040018750 <div style='height:999px;'></div></body></html>";
18751 writeFile($SaveTo, $SYMBOLS_LIST);
18752}
18753
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040018754sub readModule($$)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040018755{
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040018756 my ($Module, $Name) = @_;
18757 my $Path = $MODULES_DIR."/Internals/$Module/".$Name;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040018758 if(not -f $Path) {
18759 exitStatus("Module_Error", "can't access \'$Path\'");
18760 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040018761 return readFile($Path);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040018762}
18763
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040018764sub add_target_libs($)
18765{
18766 foreach (@{$_[0]}) {
18767 $TargetLibs{$_} = 1;
18768 }
18769}
18770
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040018771sub is_target_lib($)
18772{
18773 my $LName = $_[0];
Andrey Ponomarenkoa01311b2012-06-08 17:20:02 +040018774 if(not $LName) {
18775 return 0;
18776 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040018777 if($TargetLibraryName
18778 and $LName!~/\Q$TargetLibraryName\E/) {
18779 return 0;
18780 }
18781 if(keys(%TargetLibs)
18782 and not $TargetLibs{$LName}
18783 and not $TargetLibs{parse_libname($LName, "name+ext", $OStarget)}) {
18784 return 0;
18785 }
18786 return 1;
18787}
18788
Andrey Ponomarenko85043792012-05-14 16:48:07 +040018789sub is_target_header($$)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040018790{ # --header, --headers-list
Andrey Ponomarenko85043792012-05-14 16:48:07 +040018791 my ($H, $V) = @_;
18792 if(keys(%{$TargetHeaders{$V}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040018793 {
Andrey Ponomarenko85043792012-05-14 16:48:07 +040018794 if($TargetHeaders{$V}{$H}) {
18795 return 1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040018796 }
18797 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +040018798 return 0;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040018799}
18800
18801sub checkVersionNum($$)
18802{
18803 my ($LibVersion, $Path) = @_;
18804 if(my $VerNum = $TargetVersion{$LibVersion}) {
18805 return $VerNum;
18806 }
18807 my $UsedAltDescr = 0;
18808 foreach my $Part (split(/\s*,\s*/, $Path))
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040018809 { # try to get version string from file path
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040018810 next if(isDump($Part)); # ABI dump
18811 next if($Part=~/\.(xml|desc)\Z/i); # XML descriptor
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040018812 my $VerNum = "";
18813 if(parse_libname($Part, "name", $OStarget))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040018814 {
18815 $UsedAltDescr = 1;
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040018816 $VerNum = parse_libname($Part, "version", $OStarget);
18817 if(not $VerNum) {
Andrey Ponomarenko07aea072012-11-12 16:15:07 +040018818 $VerNum = readStrVer($Part);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040018819 }
18820 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040018821 elsif(is_header($Part, 2, $LibVersion) or -d $Part)
18822 {
18823 $UsedAltDescr = 1;
Andrey Ponomarenko07aea072012-11-12 16:15:07 +040018824 $VerNum = readStrVer($Part);
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040018825 }
18826 if($VerNum ne "")
18827 {
18828 $TargetVersion{$LibVersion} = $VerNum;
18829 if($DumpAPI) {
18830 printMsg("WARNING", "setting version number to $VerNum (use -vnum <num> option to change it)");
18831 }
18832 else {
18833 printMsg("WARNING", "setting ".($LibVersion==1?"1st":"2nd")." version number to \"$VerNum\" (use -v$LibVersion <num> option to change it)");
18834 }
18835 return $TargetVersion{$LibVersion};
18836 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040018837 }
18838 if($UsedAltDescr)
18839 {
18840 if($DumpAPI) {
18841 exitStatus("Error", "version number is not set (use -vnum <num> option)");
18842 }
18843 else {
18844 exitStatus("Error", ($LibVersion==1?"1st":"2nd")." version number is not set (use -v$LibVersion <num> option)");
18845 }
18846 }
18847}
18848
Andrey Ponomarenko07aea072012-11-12 16:15:07 +040018849sub readStrVer($)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040018850{
18851 my $Str = $_[0];
18852 return "" if(not $Str);
18853 $Str=~s/\Q$TargetLibraryName\E//g;
18854 if($Str=~/(\/|\\|\w|\A)[\-\_]*(\d+[\d\.\-]+\d+|\d+)/)
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040018855 { # .../libssh-0.4.0/...
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040018856 return $2;
18857 }
18858 elsif(my $V = parse_libname($Str, "version", $OStarget)) {
18859 return $V;
18860 }
18861 return "";
18862}
18863
18864sub readLibs($)
18865{
18866 my $LibVersion = $_[0];
18867 if($OStarget eq "windows")
18868 { # dumpbin.exe will crash
18869 # without VS Environment
18870 check_win32_env();
18871 }
Andrey Ponomarenko16934472012-03-29 15:37:04 +040018872 readSymbols($LibVersion);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040018873 translateSymbols(keys(%{$Symbol_Library{$LibVersion}}), $LibVersion);
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040018874 translateSymbols(keys(%{$DepSymbol_Library{$LibVersion}}), $LibVersion);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040018875}
18876
18877sub dump_sorting($)
18878{
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +040018879 my $Hash = $_[0];
18880 return [] if(not $Hash);
18881 my @Keys = keys(%{$Hash});
18882 return [] if($#Keys<0);
18883 if($Keys[0]=~/\A\d+\Z/)
18884 { # numbers
18885 return [sort {int($a)<=>int($b)} @Keys];
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040018886 }
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +040018887 else
18888 { # strings
18889 return [sort {$a cmp $b} @Keys];
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040018890 }
18891}
18892
18893sub printMsg($$)
18894{
18895 my ($Type, $Msg) = @_;
18896 if($Type!~/\AINFO/) {
18897 $Msg = $Type.": ".$Msg;
18898 }
18899 if($Type!~/_C\Z/) {
18900 $Msg .= "\n";
18901 }
18902 if($Quiet)
18903 { # --quiet option
18904 appendFile($COMMON_LOG_PATH, $Msg);
18905 }
18906 else
18907 {
18908 if($Type eq "ERROR") {
18909 print STDERR $Msg;
18910 }
18911 else {
18912 print $Msg;
18913 }
18914 }
18915}
18916
18917sub exitStatus($$)
18918{
18919 my ($Code, $Msg) = @_;
18920 printMsg("ERROR", $Msg);
18921 exit($ERROR_CODE{$Code});
18922}
18923
18924sub exitReport()
18925{ # the tool has run without any errors
18926 printReport();
18927 if($COMPILE_ERRORS)
18928 { # errors in headers may add false positives/negatives
18929 exit($ERROR_CODE{"Compile_Error"});
18930 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040018931 if($BinaryOnly and $RESULT{"Binary"}{"Problems"})
18932 { # --binary
18933 exit($ERROR_CODE{"Incompatible"});
18934 }
18935 elsif($SourceOnly and $RESULT{"Source"}{"Problems"})
18936 { # --source
18937 exit($ERROR_CODE{"Incompatible"});
18938 }
18939 elsif($RESULT{"Source"}{"Problems"}
18940 or $RESULT{"Binary"}{"Problems"})
18941 { # default
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040018942 exit($ERROR_CODE{"Incompatible"});
18943 }
18944 else {
18945 exit($ERROR_CODE{"Compatible"});
18946 }
18947}
18948
18949sub readRules($)
18950{
18951 my $Kind = $_[0];
18952 if(not -f $RULES_PATH{$Kind}) {
18953 exitStatus("Module_Error", "can't access \'".$RULES_PATH{$Kind}."\'");
18954 }
18955 my $Content = readFile($RULES_PATH{$Kind});
18956 while(my $Rule = parseTag(\$Content, "rule"))
18957 {
18958 my $RId = parseTag(\$Rule, "id");
18959 my @Properties = ("Severity", "Change", "Effect", "Overcome", "Kind");
18960 foreach my $Prop (@Properties) {
18961 if(my $Value = parseTag(\$Rule, lc($Prop)))
18962 {
18963 $Value=~s/\n[ ]*//;
18964 $CompatRules{$Kind}{$RId}{$Prop} = $Value;
18965 }
18966 }
18967 if($CompatRules{$Kind}{$RId}{"Kind"}=~/\A(Symbols|Parameters)\Z/) {
18968 $CompatRules{$Kind}{$RId}{"Kind"} = "Symbols";
18969 }
18970 else {
18971 $CompatRules{$Kind}{$RId}{"Kind"} = "Types";
18972 }
18973 }
18974}
18975
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040018976sub getReportPath($)
18977{
18978 my $Level = $_[0];
18979 my $Dir = "compat_reports/$TargetLibraryName/".$Descriptor{1}{"Version"}."_to_".$Descriptor{2}{"Version"};
18980 if($Level eq "Binary")
18981 {
18982 if($BinaryReportPath)
18983 { # --bin-report-path
18984 return $BinaryReportPath;
18985 }
18986 elsif($OutputReportPath)
18987 { # --report-path
18988 return $OutputReportPath;
18989 }
18990 else
18991 { # default
18992 return $Dir."/abi_compat_report.$ReportFormat";
18993 }
18994 }
18995 elsif($Level eq "Source")
18996 {
18997 if($SourceReportPath)
18998 { # --src-report-path
18999 return $SourceReportPath;
19000 }
19001 elsif($OutputReportPath)
19002 { # --report-path
19003 return $OutputReportPath;
19004 }
19005 else
19006 { # default
19007 return $Dir."/src_compat_report.$ReportFormat";
19008 }
19009 }
19010 else
19011 {
19012 if($OutputReportPath)
19013 { # --report-path
19014 return $OutputReportPath;
19015 }
19016 else
19017 { # default
19018 return $Dir."/compat_report.$ReportFormat";
19019 }
19020 }
19021}
19022
19023sub printStatMsg($)
19024{
19025 my $Level = $_[0];
19026 printMsg("INFO", "total \"$Level\" compatibility problems: ".$RESULT{$Level}{"Problems"}.", warnings: ".$RESULT{$Level}{"Warnings"});
19027}
19028
19029sub listAffected($)
19030{
19031 my $Level = $_[0];
19032 my $List = "";
19033 foreach (keys(%{$TotalAffected{$Level}}))
19034 {
19035 if($StrictCompat and $TotalAffected{$Level}{$_} eq "Low")
19036 { # skip "Low"-severity problems
19037 next;
19038 }
19039 $List .= "$_\n";
19040 }
19041 my $Dir = get_dirname(getReportPath($Level));
19042 if($Level eq "Binary") {
19043 writeFile($Dir."/abi_affected.txt", $List);
19044 }
19045 elsif($Level eq "Source") {
19046 writeFile($Dir."/src_affected.txt", $List);
19047 }
19048}
19049
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040019050sub printReport()
19051{
19052 printMsg("INFO", "creating compatibility report ...");
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040019053 createReport();
19054 if($JoinReport or $DoubleReport)
19055 {
19056 if($RESULT{"Binary"}{"Problems"}
19057 or $RESULT{"Source"}{"Problems"}) {
19058 printMsg("INFO", "result: INCOMPATIBLE (Binary: ".$RESULT{"Binary"}{"Affected"}."\%, Source: ".$RESULT{"Source"}{"Affected"}."\%)");
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040019059 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040019060 else {
19061 printMsg("INFO", "result: COMPATIBLE");
19062 }
19063 printStatMsg("Binary");
19064 printStatMsg("Source");
19065 if($ListAffected)
19066 { # --list-affected
19067 listAffected("Binary");
19068 listAffected("Source");
19069 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040019070 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040019071 elsif($BinaryOnly)
19072 {
19073 if($RESULT{"Binary"}{"Problems"}) {
19074 printMsg("INFO", "result: INCOMPATIBLE (".$RESULT{"Binary"}{"Affected"}."\%)");
19075 }
19076 else {
19077 printMsg("INFO", "result: COMPATIBLE");
19078 }
19079 printStatMsg("Binary");
19080 if($ListAffected)
19081 { # --list-affected
19082 listAffected("Binary");
19083 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040019084 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040019085 elsif($SourceOnly)
19086 {
19087 if($RESULT{"Source"}{"Problems"}) {
19088 printMsg("INFO", "result: INCOMPATIBLE (".$RESULT{"Source"}{"Affected"}."\%)");
19089 }
19090 else {
19091 printMsg("INFO", "result: COMPATIBLE");
19092 }
19093 printStatMsg("Source");
19094 if($ListAffected)
19095 { # --list-affected
19096 listAffected("Source");
19097 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040019098 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040019099 if($StdOut)
19100 {
19101 if($JoinReport or not $DoubleReport)
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040019102 { # --binary or --source
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040019103 printMsg("INFO", "compatibility report has been generated to stdout");
19104 }
19105 else
19106 { # default
19107 printMsg("INFO", "compatibility reports have been generated to stdout");
19108 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040019109 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040019110 else
19111 {
19112 if($JoinReport)
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040019113 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040019114 printMsg("INFO", "see detailed report:\n ".getReportPath("Join"));
19115 }
19116 elsif($DoubleReport)
19117 { # default
19118 printMsg("INFO", "see detailed reports:\n ".getReportPath("Binary")."\n ".getReportPath("Source"));
19119 }
19120 elsif($BinaryOnly)
19121 { # --binary
19122 printMsg("INFO", "see detailed report:\n ".getReportPath("Binary"));
19123 }
19124 elsif($SourceOnly)
19125 { # --source
19126 printMsg("INFO", "see detailed report:\n ".getReportPath("Source"));
19127 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040019128 }
19129}
19130
19131sub check_win32_env()
19132{
19133 if(not $ENV{"DevEnvDir"}
19134 or not $ENV{"LIB"}) {
19135 exitStatus("Error", "can't start without VS environment (vsvars32.bat)");
19136 }
19137}
19138
Andrey Ponomarenko5c09ef32012-06-14 18:17:33 +040019139sub diffSets($$)
19140{
19141 my ($S1, $S2) = @_;
19142 my @SK1 = keys(%{$S1});
19143 my @SK2 = keys(%{$S2});
19144 if($#SK1!=$#SK2) {
19145 return 1;
19146 }
19147 foreach my $K1 (@SK1)
19148 {
19149 if(not defined $S2->{$K1}) {
19150 return 1;
19151 }
19152 }
19153 return 0;
19154}
19155
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040019156sub create_ABI_Dump()
19157{
19158 if(not -e $DumpAPI) {
19159 exitStatus("Access_Error", "can't access \'$DumpAPI\'");
19160 }
19161 # check the archive utilities
19162 if($OSgroup eq "windows")
19163 { # using zip
19164 my $ZipCmd = get_CmdPath("zip");
19165 if(not $ZipCmd) {
19166 exitStatus("Not_Found", "can't find \"zip\"");
19167 }
19168 }
19169 else
19170 { # using tar and gzip
19171 my $TarCmd = get_CmdPath("tar");
19172 if(not $TarCmd) {
19173 exitStatus("Not_Found", "can't find \"tar\"");
19174 }
19175 my $GzipCmd = get_CmdPath("gzip");
19176 if(not $GzipCmd) {
19177 exitStatus("Not_Found", "can't find \"gzip\"");
19178 }
19179 }
19180 my @DParts = split(/\s*,\s*/, $DumpAPI);
19181 foreach my $Part (@DParts)
19182 {
19183 if(not -e $Part) {
19184 exitStatus("Access_Error", "can't access \'$Part\'");
19185 }
19186 }
19187 checkVersionNum(1, $DumpAPI);
19188 foreach my $Part (@DParts)
19189 {
19190 if(isDump($Part)) {
19191 read_ABI_Dump(1, $Part);
19192 }
19193 else {
19194 readDescriptor(1, createDescriptor(1, $Part));
19195 }
19196 }
19197 initLogging(1);
19198 detect_default_paths("inc|lib|bin|gcc"); # complete analysis
Andrey Ponomarenko01117f12012-06-26 12:23:02 +040019199 if(not $Descriptor{1}{"Dump"})
19200 {
19201 if(not $CheckHeadersOnly) {
19202 readLibs(1);
19203 }
19204 if($CheckHeadersOnly) {
19205 setLanguage(1, "C++");
19206 }
19207 if(not $CheckObjectsOnly) {
19208 searchForHeaders(1);
19209 }
19210 $WORD_SIZE{1} = detectWordSize();
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040019211 }
Andrey Ponomarenko01117f12012-06-26 12:23:02 +040019212 if(not $Descriptor{1}{"Dump"})
19213 {
19214 if($Descriptor{1}{"Headers"}) {
19215 readHeaders(1);
19216 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040019217 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +040019218 cleanDump(1);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040019219 if(not keys(%{$SymbolInfo{1}}))
19220 { # check if created dump is valid
19221 if(not $ExtendedCheck and not $CheckObjectsOnly)
19222 {
19223 if($CheckHeadersOnly) {
19224 exitStatus("Empty_Set", "the set of public symbols is empty");
19225 }
19226 else {
19227 exitStatus("Empty_Intersection", "the sets of public symbols in headers and libraries have empty intersection");
19228 }
19229 }
19230 }
19231 my %HeadersInfo = ();
19232 foreach my $HPath (keys(%{$Registered_Headers{1}}))
19233 { # headers info stored without paths in the dump
19234 $HeadersInfo{$Registered_Headers{1}{$HPath}{"Identity"}} = $Registered_Headers{1}{$HPath}{"Pos"};
19235 }
19236 printMsg("INFO", "creating library ABI dump ...");
Andrey Ponomarenko01117f12012-06-26 12:23:02 +040019237 my %ABI = (
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040019238 "TypeInfo" => $TypeInfo{1},
19239 "SymbolInfo" => $SymbolInfo{1},
19240 "Symbols" => $Library_Symbol{1},
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040019241 "DepSymbols" => $DepLibrary_Symbol{1},
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040019242 "SymbolVersion" => $SymVer{1},
19243 "LibraryVersion" => $Descriptor{1}{"Version"},
19244 "LibraryName" => $TargetLibraryName,
19245 "Language" => $COMMON_LANGUAGE{1},
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040019246 "SkipTypes" => $SkipTypes{1},
19247 "SkipSymbols" => $SkipSymbols{1},
19248 "SkipNameSpaces" => $SkipNameSpaces{1},
19249 "SkipHeaders" => $SkipHeadersList{1},
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040019250 "Headers" => \%HeadersInfo,
19251 "Constants" => $Constants{1},
19252 "NameSpaces" => $NestedNameSpaces{1},
19253 "Target" => $OStarget,
19254 "Arch" => getArch(1),
19255 "WordSize" => $WORD_SIZE{1},
19256 "GccVersion" => get_dumpversion($GCC_PATH),
19257 "ABI_DUMP_VERSION" => $ABI_DUMP_VERSION,
19258 "ABI_COMPLIANCE_CHECKER_VERSION" => $TOOL_VERSION
19259 );
Andrey Ponomarenko5c09ef32012-06-14 18:17:33 +040019260 if(diffSets($TargetHeaders{1}, \%HeadersInfo)) {
Andrey Ponomarenko01117f12012-06-26 12:23:02 +040019261 $ABI{"TargetHeaders"} = $TargetHeaders{1};
Andrey Ponomarenko5c09ef32012-06-14 18:17:33 +040019262 }
19263 if($UseXML) {
Andrey Ponomarenko01117f12012-06-26 12:23:02 +040019264 $ABI{"XML_ABI_DUMP_VERSION"} = $XML_ABI_DUMP_VERSION;
Andrey Ponomarenko5c09ef32012-06-14 18:17:33 +040019265 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040019266 if($ExtendedCheck)
19267 { # --ext option
Andrey Ponomarenko01117f12012-06-26 12:23:02 +040019268 $ABI{"Mode"} = "Extended";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040019269 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040019270 if($BinaryOnly)
19271 { # --binary
Andrey Ponomarenko01117f12012-06-26 12:23:02 +040019272 $ABI{"BinOnly"} = 1;
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040019273 }
Andrey Ponomarenko5c09ef32012-06-14 18:17:33 +040019274
19275 my $ABI_DUMP = "";
19276 if($UseXML)
19277 {
19278 loadModule("XmlDump");
Andrey Ponomarenko01117f12012-06-26 12:23:02 +040019279 $ABI_DUMP = createXmlDump(\%ABI);
Andrey Ponomarenko5c09ef32012-06-14 18:17:33 +040019280 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040019281 else
19282 { # default
Andrey Ponomarenko01117f12012-06-26 12:23:02 +040019283 $ABI_DUMP = Dumper(\%ABI);
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040019284 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040019285 if($StdOut)
19286 { # --stdout option
Andrey Ponomarenko5c09ef32012-06-14 18:17:33 +040019287 print STDOUT $ABI_DUMP;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040019288 printMsg("INFO", "ABI dump has been generated to stdout");
19289 return;
19290 }
19291 else
19292 { # write to gzipped file
Andrey Ponomarenko5c09ef32012-06-14 18:17:33 +040019293 my $DumpPath = "abi_dumps/$TargetLibraryName/".$TargetLibraryName."_".$Descriptor{1}{"Version"}.".abi";
19294 $DumpPath .= ".".$AR_EXT; # gzipped by default
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040019295 if($OutputDumpPath)
19296 { # user defined path
19297 $DumpPath = $OutputDumpPath;
19298 }
Andrey Ponomarenko5c09ef32012-06-14 18:17:33 +040019299 my $Archive = ($DumpPath=~s/\Q.$AR_EXT\E\Z//g);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040019300 my ($DDir, $DName) = separate_path($DumpPath);
19301 my $DPath = $TMP_DIR."/".$DName;
Andrey Ponomarenko5c09ef32012-06-14 18:17:33 +040019302 if(not $Archive) {
19303 $DPath = $DumpPath;
19304 }
19305
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040019306 mkpath($DDir);
Andrey Ponomarenko85043792012-05-14 16:48:07 +040019307
19308 open(DUMP, ">", $DPath) || die ("can't open file \'$DPath\': $!\n");
Andrey Ponomarenko5c09ef32012-06-14 18:17:33 +040019309 print DUMP $ABI_DUMP;
Andrey Ponomarenko85043792012-05-14 16:48:07 +040019310 close(DUMP);
19311
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040019312 if(not -s $DPath) {
19313 exitStatus("Error", "can't create ABI dump because something is going wrong with the Data::Dumper module");
19314 }
Andrey Ponomarenko07aea072012-11-12 16:15:07 +040019315 if($Archive) {
19316 $DumpPath = createArchive($DPath, $DDir);
Andrey Ponomarenko5c09ef32012-06-14 18:17:33 +040019317 }
19318
Andrey Ponomarenko07aea072012-11-12 16:15:07 +040019319 if(not $OutputDumpPath)
19320 {
19321 printMsg("INFO", "library ABI has been dumped to:\n $DumpPath");
19322 printMsg("INFO", "you can transfer this dump everywhere and use instead of the ".$Descriptor{1}{"Version"}." version descriptor");
19323 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040019324 }
19325}
19326
19327sub quickEmptyReports()
19328{ # Quick "empty" reports
19329 # 4 times faster than merging equal dumps
19330 # NOTE: the dump contains the "LibraryVersion" attribute
19331 # if you change the version, then your dump will be different
19332 # OVERCOME: use -v1 and v2 options for comparing dumps
19333 # and don't change version in the XML descriptor (and dumps)
19334 # OVERCOME 2: separate meta info from the dumps in ACC 2.0
19335 if(-s $Descriptor{1}{"Path"} == -s $Descriptor{2}{"Path"})
19336 {
19337 my $FilePath1 = unpackDump($Descriptor{1}{"Path"});
19338 my $FilePath2 = unpackDump($Descriptor{2}{"Path"});
19339 if($FilePath1 and $FilePath2)
19340 {
Andrey Ponomarenko01117f12012-06-26 12:23:02 +040019341 my $Line = readLineNum($FilePath1, 0);
19342 if($Line=~/xml/)
19343 { # XML format
19344 # is not supported yet
19345 return;
19346 }
19347
Andrey Ponomarenko85043792012-05-14 16:48:07 +040019348 local $/ = undef;
19349
19350 open(DUMP1, $FilePath1);
19351 my $Content1 = <DUMP1>;
19352 close(DUMP1);
19353
19354 open(DUMP2, $FilePath2);
19355 my $Content2 = <DUMP2>;
19356 close(DUMP2);
19357
19358 if($Content1 eq $Content2)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040019359 {
Andrey Ponomarenko85043792012-05-14 16:48:07 +040019360 # clean memory
19361 undef $Content2;
19362
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040019363 # read a number of headers, libs, symbols and types
Andrey Ponomarenko85043792012-05-14 16:48:07 +040019364 my $ABIdump = eval($Content1);
19365
19366 # clean memory
19367 undef $Content1;
19368
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040019369 if(not $ABIdump) {
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040019370 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 +040019371 }
19372 if(not $ABIdump->{"TypeInfo"})
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040019373 { # support for old dumps
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040019374 $ABIdump->{"TypeInfo"} = $ABIdump->{"TypeDescr"};
19375 }
19376 if(not $ABIdump->{"SymbolInfo"})
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040019377 { # support for old dumps
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040019378 $ABIdump->{"SymbolInfo"} = $ABIdump->{"FuncDescr"};
19379 }
19380 read_Headers_DumpInfo($ABIdump, 1);
19381 read_Libs_DumpInfo($ABIdump, 1);
19382 read_Machine_DumpInfo($ABIdump, 1);
19383 read_Machine_DumpInfo($ABIdump, 2);
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040019384
19385 %{$CheckedTypes{"Binary"}} = %{$ABIdump->{"TypeInfo"}};
19386 %{$CheckedTypes{"Source"}} = %{$ABIdump->{"TypeInfo"}};
19387
19388 %{$CheckedSymbols{"Binary"}} = %{$ABIdump->{"SymbolInfo"}};
19389 %{$CheckedSymbols{"Source"}} = %{$ABIdump->{"SymbolInfo"}};
19390
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040019391 $Descriptor{1}{"Version"} = $TargetVersion{1}?$TargetVersion{1}:$ABIdump->{"LibraryVersion"};
19392 $Descriptor{2}{"Version"} = $TargetVersion{2}?$TargetVersion{2}:$ABIdump->{"LibraryVersion"};
19393 exitReport();
19394 }
19395 }
19396 }
19397}
19398
19399sub initLogging($)
19400{
19401 my $LibVersion = $_[0];
19402 # create log directory
19403 my ($LOG_DIR, $LOG_FILE) = ("logs/$TargetLibraryName/".$Descriptor{$LibVersion}{"Version"}, "log.txt");
19404 if($OutputLogPath{$LibVersion})
19405 { # user-defined by -log-path option
19406 ($LOG_DIR, $LOG_FILE) = separate_path($OutputLogPath{$LibVersion});
19407 }
19408 if($LogMode ne "n") {
19409 mkpath($LOG_DIR);
19410 }
19411 $LOG_PATH{$LibVersion} = get_abs_path($LOG_DIR)."/".$LOG_FILE;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040019412 if($Debug)
19413 { # debug directory
19414 $DEBUG_PATH{$LibVersion} = "debug/$TargetLibraryName/".$Descriptor{$LibVersion}{"Version"};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040019415 }
Andrey Ponomarenko35c44fd2012-06-18 17:50:25 +040019416 resetLogging($LibVersion);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040019417}
19418
19419sub writeLog($$)
19420{
19421 my ($LibVersion, $Msg) = @_;
19422 if($LogMode ne "n") {
19423 appendFile($LOG_PATH{$LibVersion}, $Msg);
19424 }
19425}
19426
19427sub resetLogging($)
19428{
19429 my $LibVersion = $_[0];
19430 if($LogMode!~/a|n/)
19431 { # remove old log
19432 unlink($LOG_PATH{$LibVersion});
Andrey Ponomarenko35c44fd2012-06-18 17:50:25 +040019433 if($Debug) {
19434 rmtree($DEBUG_PATH{$LibVersion});
19435 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040019436 }
19437}
19438
19439sub printErrorLog($)
19440{
19441 my $LibVersion = $_[0];
19442 if($LogMode ne "n") {
19443 printMsg("ERROR", "see log for details:\n ".$LOG_PATH{$LibVersion}."\n");
19444 }
19445}
19446
19447sub isDump($)
19448{
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040019449 if(get_filename($_[0])=~/\A(.+)\.(abi|abidump)(\.tar\.gz|\.zip|\.xml|)\Z/) {
19450 return $1;
19451 }
19452 return 0;
19453}
19454
19455sub isDump_U($)
19456{
19457 if(get_filename($_[0])=~/\A(.+)\.(abi|abidump)(\.xml|)\Z/) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040019458 return $1;
19459 }
19460 return 0;
19461}
19462
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040019463sub compareInit()
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040019464{
19465 # read input XML descriptors or ABI dumps
19466 if(not $Descriptor{1}{"Path"}) {
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040019467 exitStatus("Error", "-old option is not specified");
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040019468 }
19469 my @DParts1 = split(/\s*,\s*/, $Descriptor{1}{"Path"});
19470 foreach my $Part (@DParts1)
19471 {
19472 if(not -e $Part) {
19473 exitStatus("Access_Error", "can't access \'$Part\'");
19474 }
19475 }
19476 if(not $Descriptor{2}{"Path"}) {
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040019477 exitStatus("Error", "-new option is not specified");
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040019478 }
19479 my @DParts2 = split(/\s*,\s*/, $Descriptor{2}{"Path"});
19480 foreach my $Part (@DParts2)
19481 {
19482 if(not -e $Part) {
19483 exitStatus("Access_Error", "can't access \'$Part\'");
19484 }
19485 }
19486 detect_default_paths("bin"); # to extract dumps
19487 if($#DParts1==0 and $#DParts2==0
19488 and isDump($Descriptor{1}{"Path"})
19489 and isDump($Descriptor{2}{"Path"}))
19490 { # optimization: equal ABI dumps
19491 quickEmptyReports();
19492 }
19493 checkVersionNum(1, $Descriptor{1}{"Path"});
19494 checkVersionNum(2, $Descriptor{2}{"Path"});
19495 printMsg("INFO", "preparation, please wait ...");
19496 foreach my $Part (@DParts1)
19497 {
19498 if(isDump($Part)) {
19499 read_ABI_Dump(1, $Part);
19500 }
19501 else {
19502 readDescriptor(1, createDescriptor(1, $Part));
19503 }
19504 }
19505 foreach my $Part (@DParts2)
19506 {
19507 if(isDump($Part)) {
19508 read_ABI_Dump(2, $Part);
19509 }
19510 else {
19511 readDescriptor(2, createDescriptor(2, $Part));
19512 }
19513 }
19514 initLogging(1);
19515 initLogging(2);
19516 # check consistency
19517 if(not $Descriptor{1}{"Headers"}
19518 and not $Descriptor{1}{"Libs"}) {
19519 exitStatus("Error", "descriptor d1 does not contain both header files and libraries info");
19520 }
19521 if(not $Descriptor{2}{"Headers"}
19522 and not $Descriptor{2}{"Libs"}) {
19523 exitStatus("Error", "descriptor d2 does not contain both header files and libraries info");
19524 }
19525 if($Descriptor{1}{"Headers"} and not $Descriptor{1}{"Libs"}
19526 and not $Descriptor{2}{"Headers"} and $Descriptor{2}{"Libs"}) {
19527 exitStatus("Error", "can't compare headers with $SLIB_TYPE libraries");
19528 }
19529 elsif(not $Descriptor{1}{"Headers"} and $Descriptor{1}{"Libs"}
19530 and $Descriptor{2}{"Headers"} and not $Descriptor{2}{"Libs"}) {
19531 exitStatus("Error", "can't compare $SLIB_TYPE libraries with headers");
19532 }
Andrey Ponomarenkobdc85a92012-11-12 17:28:12 +040019533 if(not $Descriptor{1}{"Headers"})
19534 {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040019535 if($CheckHeadersOnly_Opt) {
19536 exitStatus("Error", "can't find header files info in descriptor d1");
19537 }
19538 }
Andrey Ponomarenkobdc85a92012-11-12 17:28:12 +040019539 if(not $Descriptor{2}{"Headers"})
19540 {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040019541 if($CheckHeadersOnly_Opt) {
19542 exitStatus("Error", "can't find header files info in descriptor d2");
19543 }
19544 }
19545 if(not $Descriptor{1}{"Headers"}
Andrey Ponomarenkobdc85a92012-11-12 17:28:12 +040019546 or not $Descriptor{2}{"Headers"})
19547 {
19548 if(not $CheckObjectsOnly_Opt)
19549 {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040019550 printMsg("WARNING", "comparing $SLIB_TYPE libraries only");
19551 $CheckObjectsOnly = 1;
19552 }
19553 }
Andrey Ponomarenkobdc85a92012-11-12 17:28:12 +040019554 if(not $Descriptor{1}{"Libs"})
19555 {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040019556 if($CheckObjectsOnly_Opt) {
19557 exitStatus("Error", "can't find $SLIB_TYPE libraries info in descriptor d1");
19558 }
19559 }
Andrey Ponomarenkobdc85a92012-11-12 17:28:12 +040019560 if(not $Descriptor{2}{"Libs"})
19561 {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040019562 if($CheckObjectsOnly_Opt) {
19563 exitStatus("Error", "can't find $SLIB_TYPE libraries info in descriptor d2");
19564 }
19565 }
19566 if(not $Descriptor{1}{"Libs"}
19567 or not $Descriptor{2}{"Libs"})
19568 { # comparing standalone header files
19569 # comparing ABI dumps created with --headers-only
19570 if(not $CheckHeadersOnly_Opt)
19571 {
19572 printMsg("WARNING", "checking headers only");
19573 $CheckHeadersOnly = 1;
19574 }
19575 }
19576 if($UseDumps)
19577 { # --use-dumps
19578 # parallel processing
19579 my $pid = fork();
19580 if($pid)
19581 { # dump on two CPU cores
19582 my @PARAMS = ("-dump", $Descriptor{1}{"Path"}, "-l", $TargetLibraryName);
19583 if($RelativeDirectory{1}) {
19584 @PARAMS = (@PARAMS, "-relpath", $RelativeDirectory{1});
19585 }
19586 if($OutputLogPath{1}) {
19587 @PARAMS = (@PARAMS, "-log-path", $OutputLogPath{1});
19588 }
19589 if($CrossGcc) {
19590 @PARAMS = (@PARAMS, "-cross-gcc", $CrossGcc);
19591 }
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040019592 if($Quiet)
19593 {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040019594 @PARAMS = (@PARAMS, "-quiet");
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040019595 @PARAMS = (@PARAMS, "-logging-mode", "a");
19596 }
19597 elsif($LogMode and $LogMode ne "w")
19598 { # "w" is default
19599 @PARAMS = (@PARAMS, "-logging-mode", $LogMode);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040019600 }
19601 if($ExtendedCheck) {
19602 @PARAMS = (@PARAMS, "-extended");
19603 }
19604 if($UserLang) {
19605 @PARAMS = (@PARAMS, "-lang", $UserLang);
19606 }
19607 if($TargetVersion{1}) {
19608 @PARAMS = (@PARAMS, "-vnum", $TargetVersion{1});
19609 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +040019610 if($BinaryOnly) {
19611 @PARAMS = (@PARAMS, "-binary");
19612 }
19613 if($SourceOnly) {
19614 @PARAMS = (@PARAMS, "-source");
19615 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040019616 if($SortDump) {
19617 @PARAMS = (@PARAMS, "-sort");
19618 }
Andrey Ponomarenko01117f12012-06-26 12:23:02 +040019619 if($DumpFormat and $DumpFormat ne "perl") {
19620 @PARAMS = (@PARAMS, "-dump-format", $DumpFormat);
19621 }
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +040019622 if($CheckHeadersOnly) {
19623 @PARAMS = (@PARAMS, "-headers-only");
19624 }
19625 if($CheckObjectsOnly) {
19626 @PARAMS = (@PARAMS, "-objects-only");
19627 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +040019628 if($Debug)
19629 {
19630 @PARAMS = (@PARAMS, "-debug");
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040019631 printMsg("INFO", "running perl $0 @PARAMS");
Andrey Ponomarenko85043792012-05-14 16:48:07 +040019632 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040019633 system("perl", $0, @PARAMS);
19634 if($?) {
19635 exit(1);
19636 }
19637 }
19638 else
19639 { # child
19640 my @PARAMS = ("-dump", $Descriptor{2}{"Path"}, "-l", $TargetLibraryName);
19641 if($RelativeDirectory{2}) {
19642 @PARAMS = (@PARAMS, "-relpath", $RelativeDirectory{2});
19643 }
19644 if($OutputLogPath{2}) {
19645 @PARAMS = (@PARAMS, "-log-path", $OutputLogPath{2});
19646 }
19647 if($CrossGcc) {
19648 @PARAMS = (@PARAMS, "-cross-gcc", $CrossGcc);
19649 }
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040019650 if($Quiet)
19651 {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040019652 @PARAMS = (@PARAMS, "-quiet");
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040019653 @PARAMS = (@PARAMS, "-logging-mode", "a");
19654 }
19655 elsif($LogMode and $LogMode ne "w")
19656 { # "w" is default
19657 @PARAMS = (@PARAMS, "-logging-mode", $LogMode);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040019658 }
19659 if($ExtendedCheck) {
19660 @PARAMS = (@PARAMS, "-extended");
19661 }
19662 if($UserLang) {
19663 @PARAMS = (@PARAMS, "-lang", $UserLang);
19664 }
19665 if($TargetVersion{2}) {
19666 @PARAMS = (@PARAMS, "-vnum", $TargetVersion{2});
19667 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +040019668 if($BinaryOnly) {
19669 @PARAMS = (@PARAMS, "-binary");
19670 }
19671 if($SourceOnly) {
19672 @PARAMS = (@PARAMS, "-source");
19673 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040019674 if($SortDump) {
19675 @PARAMS = (@PARAMS, "-sort");
19676 }
Andrey Ponomarenko01117f12012-06-26 12:23:02 +040019677 if($DumpFormat and $DumpFormat ne "perl") {
19678 @PARAMS = (@PARAMS, "-dump-format", $DumpFormat);
19679 }
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +040019680 if($CheckHeadersOnly) {
19681 @PARAMS = (@PARAMS, "-headers-only");
19682 }
19683 if($CheckObjectsOnly) {
19684 @PARAMS = (@PARAMS, "-objects-only");
19685 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +040019686 if($Debug)
19687 {
19688 @PARAMS = (@PARAMS, "-debug");
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040019689 printMsg("INFO", "running perl $0 @PARAMS");
Andrey Ponomarenko85043792012-05-14 16:48:07 +040019690 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040019691 system("perl", $0, @PARAMS);
19692 if($?) {
19693 exit(1);
19694 }
19695 else {
19696 exit(0);
19697 }
19698 }
19699 waitpid($pid, 0);
19700 my @CMP_PARAMS = ("-l", $TargetLibraryName);
19701 @CMP_PARAMS = (@CMP_PARAMS, "-d1", "abi_dumps/$TargetLibraryName/".$TargetLibraryName."_".$Descriptor{1}{"Version"}.".abi.$AR_EXT");
19702 @CMP_PARAMS = (@CMP_PARAMS, "-d2", "abi_dumps/$TargetLibraryName/".$TargetLibraryName."_".$Descriptor{2}{"Version"}.".abi.$AR_EXT");
19703 if($TargetLibraryFName ne $TargetLibraryName) {
19704 @CMP_PARAMS = (@CMP_PARAMS, "-l-full", $TargetLibraryFName);
19705 }
19706 if($ShowRetVal) {
19707 @CMP_PARAMS = (@CMP_PARAMS, "-show-retval");
19708 }
19709 if($CrossGcc) {
19710 @CMP_PARAMS = (@CMP_PARAMS, "-cross-gcc", $CrossGcc);
19711 }
Andrey Ponomarenko35c44fd2012-06-18 17:50:25 +040019712 @CMP_PARAMS = (@CMP_PARAMS, "-logging-mode", "a");
19713 if($Quiet) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040019714 @CMP_PARAMS = (@CMP_PARAMS, "-quiet");
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040019715 }
19716 if($ReportFormat and $ReportFormat ne "html")
19717 { # HTML is default format
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040019718 @CMP_PARAMS = (@CMP_PARAMS, "-report-format", $ReportFormat);
19719 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040019720 if($OutputReportPath) {
19721 @CMP_PARAMS = (@CMP_PARAMS, "-report-path", $OutputReportPath);
19722 }
19723 if($BinaryReportPath) {
19724 @CMP_PARAMS = (@CMP_PARAMS, "-bin-report-path", $BinaryReportPath);
19725 }
19726 if($SourceReportPath) {
19727 @CMP_PARAMS = (@CMP_PARAMS, "-src-report-path", $SourceReportPath);
19728 }
19729 if($LoggingPath) {
19730 @CMP_PARAMS = (@CMP_PARAMS, "-log-path", $LoggingPath);
19731 }
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +040019732 if($CheckHeadersOnly) {
19733 @CMP_PARAMS = (@CMP_PARAMS, "-headers-only");
19734 }
19735 if($CheckObjectsOnly) {
19736 @CMP_PARAMS = (@CMP_PARAMS, "-objects-only");
19737 }
19738 if($BinaryOnly) {
19739 @CMP_PARAMS = (@CMP_PARAMS, "-binary");
19740 }
19741 if($SourceOnly) {
19742 @CMP_PARAMS = (@CMP_PARAMS, "-source");
19743 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +040019744 if($Browse) {
19745 @CMP_PARAMS = (@CMP_PARAMS, "-browse", $Browse);
19746 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040019747 if($OpenReport) {
19748 @CMP_PARAMS = (@CMP_PARAMS, "-open");
19749 }
19750 if($Debug)
19751 {
19752 @CMP_PARAMS = (@CMP_PARAMS, "-debug");
19753 printMsg("INFO", "running perl $0 @CMP_PARAMS");
Andrey Ponomarenko85043792012-05-14 16:48:07 +040019754 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040019755 system("perl", $0, @CMP_PARAMS);
19756 exit($?>>8);
19757 }
19758 if(not $Descriptor{1}{"Dump"}
19759 or not $Descriptor{2}{"Dump"})
19760 { # need GCC toolchain to analyze
19761 # header files and libraries
19762 detect_default_paths("inc|lib|gcc");
19763 }
19764 if(not $Descriptor{1}{"Dump"})
19765 {
19766 if(not $CheckHeadersOnly) {
19767 readLibs(1);
19768 }
19769 if($CheckHeadersOnly) {
19770 setLanguage(1, "C++");
19771 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +040019772 if(not $CheckObjectsOnly) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040019773 searchForHeaders(1);
19774 }
19775 $WORD_SIZE{1} = detectWordSize();
19776 }
19777 if(not $Descriptor{2}{"Dump"})
19778 {
19779 if(not $CheckHeadersOnly) {
19780 readLibs(2);
19781 }
19782 if($CheckHeadersOnly) {
19783 setLanguage(2, "C++");
19784 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +040019785 if(not $CheckObjectsOnly) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040019786 searchForHeaders(2);
19787 }
19788 $WORD_SIZE{2} = detectWordSize();
19789 }
19790 if($WORD_SIZE{1} ne $WORD_SIZE{2})
19791 { # support for old ABI dumps
19792 # try to synch different WORD sizes
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040019793 if(not checkDump(1, "2.1"))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040019794 {
19795 $WORD_SIZE{1} = $WORD_SIZE{2};
19796 printMsg("WARNING", "set WORD size to ".$WORD_SIZE{2}." bytes");
19797 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040019798 elsif(not checkDump(2, "2.1"))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040019799 {
19800 $WORD_SIZE{2} = $WORD_SIZE{1};
19801 printMsg("WARNING", "set WORD size to ".$WORD_SIZE{1}." bytes");
19802 }
19803 }
19804 elsif(not $WORD_SIZE{1}
19805 and not $WORD_SIZE{2})
19806 { # support for old ABI dumps
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040019807 $WORD_SIZE{1} = "4";
19808 $WORD_SIZE{2} = "4";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040019809 }
19810 if($Descriptor{1}{"Dump"})
19811 { # support for old ABI dumps
19812 prepareTypes(1);
19813 }
19814 if($Descriptor{2}{"Dump"})
19815 { # support for old ABI dumps
19816 prepareTypes(2);
19817 }
19818 if($AppPath and not keys(%{$Symbol_Library{1}})) {
19819 printMsg("WARNING", "the application ".get_filename($AppPath)." has no symbols imported from the $SLIB_TYPE libraries");
19820 }
19821 # started to process input data
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040019822 if(not $CheckObjectsOnly)
19823 {
19824 if($Descriptor{1}{"Headers"}
19825 and not $Descriptor{1}{"Dump"}) {
19826 readHeaders(1);
19827 }
19828 if($Descriptor{2}{"Headers"}
19829 and not $Descriptor{2}{"Dump"}) {
19830 readHeaders(2);
19831 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040019832 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +040019833
19834 # clean memory
19835 %SystemHeaders = ();
19836 %mangled_name_gcc = ();
19837
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040019838 prepareSymbols(1);
19839 prepareSymbols(2);
Andrey Ponomarenko16934472012-03-29 15:37:04 +040019840
Andrey Ponomarenko85043792012-05-14 16:48:07 +040019841 # clean memory
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040019842 %SymbolInfo = ();
Andrey Ponomarenko16934472012-03-29 15:37:04 +040019843
19844 # Virtual Tables
19845 registerVTable(1);
19846 registerVTable(2);
19847
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040019848 if(not checkDump(1, "1.22")
19849 and checkDump(2, "1.22"))
Andrey Ponomarenko16934472012-03-29 15:37:04 +040019850 { # support for old ABI dumps
19851 foreach my $ClassName (keys(%{$VirtualTable{2}}))
19852 {
19853 if($ClassName=~/</)
19854 { # templates
19855 if(not defined $VirtualTable{1}{$ClassName})
19856 { # synchronize
19857 delete($VirtualTable{2}{$ClassName});
19858 }
19859 }
19860 }
19861 }
19862
19863 registerOverriding(1);
19864 registerOverriding(2);
19865
19866 setVirtFuncPositions(1);
19867 setVirtFuncPositions(2);
19868
19869 # Other
19870 addParamNames(1);
19871 addParamNames(2);
19872
19873 detectChangedTypedefs();
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040019874}
19875
19876sub compareAPIs($)
19877{
19878 my $Level = $_[0];
19879 readRules($Level);
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +040019880 loadModule("CallConv");
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040019881 if($Level eq "Binary") {
19882 printMsg("INFO", "comparing ABIs ...");
19883 }
19884 else {
19885 printMsg("INFO", "comparing APIs ...");
19886 }
19887 if($CheckHeadersOnly
19888 or $Level eq "Source")
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040019889 { # added/removed in headers
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040019890 detectAdded_H($Level);
19891 detectRemoved_H($Level);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040019892 }
19893 else
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040019894 { # added/removed in libs
19895 detectAdded($Level);
19896 detectRemoved($Level);
19897 }
19898 if(not $CheckObjectsOnly)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040019899 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040019900 mergeSignatures($Level);
19901 if(keys(%{$CheckedSymbols{$Level}})) {
19902 mergeConstants($Level);
19903 }
19904 }
19905 if($CheckHeadersOnly
19906 or $Level eq "Source")
19907 { # added/removed in headers
19908 mergeHeaders($Level);
19909 }
19910 else
19911 { # added/removed in libs
19912 mergeLibs($Level);
19913 if($CheckImpl
19914 and $Level eq "Binary") {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040019915 mergeImpl();
19916 }
19917 }
19918}
19919
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040019920sub getSysOpts()
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040019921{
19922 my %Opts = (
19923 "OStarget"=>$OStarget,
19924 "Debug"=>$Debug,
19925 "Quiet"=>$Quiet,
19926 "LogMode"=>$LogMode,
19927 "CheckHeadersOnly"=>$CheckHeadersOnly,
19928
19929 "SystemRoot"=>$SystemRoot,
19930 "MODULES_DIR"=>$MODULES_DIR,
19931 "GCC_PATH"=>$GCC_PATH,
19932 "TargetSysInfo"=>$TargetSysInfo,
19933 "CrossPrefix"=>$CrossPrefix,
19934 "TargetLibraryName"=>$TargetLibraryName,
19935 "CrossGcc"=>$CrossGcc,
19936 "UseStaticLibs"=>$UseStaticLibs,
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040019937 "NoStdInc"=>$NoStdInc,
19938
19939 "BinaryOnly" => $BinaryOnly,
19940 "SourceOnly" => $SourceOnly
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040019941 );
19942 return \%Opts;
19943}
19944
19945sub get_CoreError($)
19946{
19947 my %CODE_ERROR = reverse(%ERROR_CODE);
19948 return $CODE_ERROR{$_[0]};
19949}
19950
19951sub scenario()
19952{
19953 if($StdOut)
19954 { # enable quiet mode
19955 $Quiet = 1;
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040019956 $JoinReport = 1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040019957 }
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040019958 if(not $LogMode)
19959 { # default
19960 $LogMode = "w";
19961 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040019962 if($UserLang)
19963 { # --lang=C++
19964 $UserLang = uc($UserLang);
19965 $COMMON_LANGUAGE{1}=$UserLang;
19966 $COMMON_LANGUAGE{2}=$UserLang;
19967 }
19968 if($LoggingPath)
19969 {
19970 $OutputLogPath{1} = $LoggingPath;
19971 $OutputLogPath{2} = $LoggingPath;
19972 if($Quiet) {
19973 $COMMON_LOG_PATH = $LoggingPath;
19974 }
19975 }
Andrey Ponomarenko5c09ef32012-06-14 18:17:33 +040019976 if($OutputDumpPath)
19977 { # validate
19978 if($OutputDumpPath!~/\.abi(\.\Q$AR_EXT\E|)\Z/) {
19979 exitStatus("Error", "the dump path should be a path to *.abi.$AR_EXT or *.abi file");
19980 }
19981 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040019982 if($BinaryOnly and $SourceOnly)
19983 { # both --binary and --source
19984 # is the default mode
19985 $DoubleReport = 1;
19986 $JoinReport = 0;
19987 $BinaryOnly = 0;
19988 $SourceOnly = 0;
19989 if($OutputReportPath)
19990 { # --report-path
19991 $DoubleReport = 0;
19992 $JoinReport = 1;
19993 }
19994 }
19995 elsif($BinaryOnly or $SourceOnly)
19996 { # --binary or --source
19997 $DoubleReport = 0;
19998 $JoinReport = 0;
19999 }
20000 if($UseXML)
20001 { # --xml option
20002 $ReportFormat = "xml";
Andrey Ponomarenko5c09ef32012-06-14 18:17:33 +040020003 $DumpFormat = "xml";
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040020004 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040020005 if($ReportFormat)
20006 { # validate
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040020007 $ReportFormat = lc($ReportFormat);
20008 if($ReportFormat!~/\A(xml|html|htm)\Z/) {
Andrey Ponomarenko5c09ef32012-06-14 18:17:33 +040020009 exitStatus("Error", "unknown report format \'$ReportFormat\'");
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040020010 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040020011 if($ReportFormat eq "htm")
20012 { # HTM == HTML
20013 $ReportFormat = "html";
20014 }
20015 elsif($ReportFormat eq "xml")
20016 { # --report-format=XML equal to --xml
20017 $UseXML = 1;
20018 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040020019 }
20020 else
20021 { # default: HTML
20022 $ReportFormat = "html";
20023 }
Andrey Ponomarenko5c09ef32012-06-14 18:17:33 +040020024 if($DumpFormat)
20025 { # validate
20026 $DumpFormat = lc($DumpFormat);
20027 if($DumpFormat!~/\A(xml|perl)\Z/) {
20028 exitStatus("Error", "unknown ABI dump format \'$DumpFormat\'");
20029 }
20030 if($DumpFormat eq "xml")
20031 { # --dump-format=XML equal to --xml
20032 $UseXML = 1;
20033 }
20034 }
20035 else
Andrey Ponomarenko01117f12012-06-26 12:23:02 +040020036 { # default: Perl Data::Dumper
Andrey Ponomarenko5c09ef32012-06-14 18:17:33 +040020037 $DumpFormat = "perl";
20038 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040020039 if($Quiet and $LogMode!~/a|n/)
20040 { # --quiet log
20041 if(-f $COMMON_LOG_PATH) {
20042 unlink($COMMON_LOG_PATH);
20043 }
20044 }
20045 if($TestTool and $UseDumps)
20046 { # --test && --use-dumps == --test-dump
20047 $TestDump = 1;
20048 }
20049 if($Help) {
20050 HELP_MESSAGE();
20051 exit(0);
20052 }
20053 if($InfoMsg) {
20054 INFO_MESSAGE();
20055 exit(0);
20056 }
20057 if($ShowVersion) {
20058 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.");
20059 exit(0);
20060 }
20061 if($DumpVersion) {
20062 printMsg("INFO", $TOOL_VERSION);
20063 exit(0);
20064 }
20065 if($ExtendedCheck) {
20066 $CheckHeadersOnly = 1;
20067 }
20068 if($SystemRoot_Opt)
20069 { # user defined root
20070 if(not -e $SystemRoot_Opt) {
20071 exitStatus("Access_Error", "can't access \'$SystemRoot\'");
20072 }
20073 $SystemRoot = $SystemRoot_Opt;
20074 $SystemRoot=~s/[\/]+\Z//g;
20075 if($SystemRoot) {
20076 $SystemRoot = get_abs_path($SystemRoot);
20077 }
20078 }
20079 $Data::Dumper::Sortkeys = 1;
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +040020080
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040020081 if($SortDump)
20082 {
20083 $Data::Dumper::Useperl = 1;
20084 $Data::Dumper::Sortkeys = \&dump_sorting;
20085 }
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +040020086
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040020087 if($TargetLibsPath)
20088 {
20089 if(not -f $TargetLibsPath) {
20090 exitStatus("Access_Error", "can't access file \'$TargetLibsPath\'");
20091 }
20092 foreach my $Lib (split(/\s*\n\s*/, readFile($TargetLibsPath))) {
20093 $TargetLibs{$Lib} = 1;
20094 }
20095 }
20096 if($TargetHeadersPath)
20097 { # --headers-list
20098 if(not -f $TargetHeadersPath) {
20099 exitStatus("Access_Error", "can't access file \'$TargetHeadersPath\'");
20100 }
20101 foreach my $Header (split(/\s*\n\s*/, readFile($TargetHeadersPath)))
20102 {
20103 $TargetHeaders{1}{$Header} = 1;
20104 $TargetHeaders{2}{$Header} = 1;
20105 }
20106 }
20107 if($TargetHeader)
20108 { # --header
20109 $TargetHeaders{1}{$TargetHeader} = 1;
20110 $TargetHeaders{2}{$TargetHeader} = 1;
20111 }
20112 if($TestTool
20113 or $TestDump)
20114 { # --test, --test-dump
20115 detect_default_paths("bin|gcc"); # to compile libs
20116 loadModule("RegTests");
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +040020117 testTool($TestDump, $Debug, $Quiet, $ExtendedCheck, $LogMode, $ReportFormat, $DumpFormat,
20118 $LIB_EXT, $GCC_PATH, $Browse, $OpenReport, $SortDump, $CheckHeadersOnly, $CheckObjectsOnly);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040020119 exit(0);
20120 }
20121 if($DumpSystem)
20122 { # --dump-system
20123 loadModule("SysCheck");
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040020124 if($DumpSystem=~/\.(xml|desc)\Z/)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040020125 { # system XML descriptor
20126 if(not -f $DumpSystem) {
20127 exitStatus("Access_Error", "can't access file \'$DumpSystem\'");
20128 }
20129 my $Ret = readSystemDescriptor(readFile($DumpSystem));
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040020130 foreach (@{$Ret->{"Tools"}})
20131 {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040020132 $SystemPaths{"bin"}{$_} = 1;
20133 $TargetTools{$_}=1;
20134 }
20135 if($Ret->{"CrossPrefix"}) {
20136 $CrossPrefix = $Ret->{"CrossPrefix"};
20137 }
20138 }
20139 elsif($SystemRoot_Opt)
20140 { # -sysroot "/" option
20141 # default target: /usr/lib, /usr/include
20142 # search libs: /usr/lib and /lib
20143 if(not -e $SystemRoot."/usr/lib") {
20144 exitStatus("Access_Error", "can't access '".$SystemRoot."/usr/lib'");
20145 }
20146 if(not -e $SystemRoot."/lib") {
20147 exitStatus("Access_Error", "can't access '".$SystemRoot."/lib'");
20148 }
20149 if(not -e $SystemRoot."/usr/include") {
20150 exitStatus("Access_Error", "can't access '".$SystemRoot."/usr/include'");
20151 }
20152 readSystemDescriptor("
20153 <name>
20154 $DumpSystem
20155 </name>
20156 <headers>
20157 $SystemRoot/usr/include
20158 </headers>
20159 <libs>
20160 $SystemRoot/usr/lib
20161 </libs>
20162 <search_libs>
20163 $SystemRoot/lib
20164 </search_libs>");
20165 }
20166 else {
20167 exitStatus("Error", "-sysroot <dirpath> option should be specified, usually it's \"/\"");
20168 }
20169 detect_default_paths("bin|gcc"); # to check symbols
20170 if($OStarget eq "windows")
20171 { # to run dumpbin.exe
20172 # and undname.exe
20173 check_win32_env();
20174 }
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040020175 dumpSystem(getSysOpts());
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040020176 exit(0);
20177 }
20178 if($CmpSystems)
20179 { # --cmp-systems
20180 detect_default_paths("bin"); # to extract dumps
20181 loadModule("SysCheck");
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040020182 cmpSystems($Descriptor{1}{"Path"}, $Descriptor{2}{"Path"}, getSysOpts());
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040020183 exit(0);
20184 }
20185 if($GenerateTemplate) {
20186 generateTemplate();
20187 exit(0);
20188 }
20189 if(not $TargetLibraryName) {
20190 exitStatus("Error", "library name is not selected (option -l <name>)");
20191 }
20192 else
20193 { # validate library name
20194 if($TargetLibraryName=~/[\*\/\\]/) {
20195 exitStatus("Error", "\"\\\", \"\/\" and \"*\" symbols are not allowed in the library name");
20196 }
20197 }
20198 if(not $TargetLibraryFName) {
20199 $TargetLibraryFName = $TargetLibraryName;
20200 }
20201 if($CheckHeadersOnly_Opt and $CheckObjectsOnly_Opt) {
20202 exitStatus("Error", "you can't specify both -headers-only and -objects-only options at the same time");
20203 }
20204 if($SymbolsListPath)
20205 {
20206 if(not -f $SymbolsListPath) {
20207 exitStatus("Access_Error", "can't access file \'$SymbolsListPath\'");
20208 }
20209 foreach my $Interface (split(/\s*\n\s*/, readFile($SymbolsListPath))) {
20210 $SymbolsList{$Interface} = 1;
20211 }
20212 }
20213 if($SkipHeadersPath)
20214 {
20215 if(not -f $SkipHeadersPath) {
20216 exitStatus("Access_Error", "can't access file \'$SkipHeadersPath\'");
20217 }
20218 foreach my $Path (split(/\s*\n\s*/, readFile($SkipHeadersPath)))
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040020219 { # register for both versions
20220 $SkipHeadersList{1}{$Path} = 1;
20221 $SkipHeadersList{2}{$Path} = 1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040020222 my ($CPath, $Type) = classifyPath($Path);
20223 $SkipHeaders{1}{$Type}{$CPath} = 1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040020224 $SkipHeaders{2}{$Type}{$CPath} = 1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040020225 }
20226 }
20227 if($ParamNamesPath)
20228 {
20229 if(not -f $ParamNamesPath) {
20230 exitStatus("Access_Error", "can't access file \'$ParamNamesPath\'");
20231 }
20232 foreach my $Line (split(/\n/, readFile($ParamNamesPath)))
20233 {
20234 if($Line=~s/\A(\w+)\;//)
20235 {
20236 my $Interface = $1;
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040020237 if($Line=~/;(\d+);/)
20238 {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040020239 while($Line=~s/(\d+);(\w+)//) {
20240 $AddIntParams{$Interface}{$1}=$2;
20241 }
20242 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040020243 else
20244 {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040020245 my $Num = 0;
20246 foreach my $Name (split(/;/, $Line)) {
20247 $AddIntParams{$Interface}{$Num++}=$Name;
20248 }
20249 }
20250 }
20251 }
20252 }
20253 if($AppPath)
20254 {
20255 if(not -f $AppPath) {
20256 exitStatus("Access_Error", "can't access file \'$AppPath\'");
20257 }
Andrey Ponomarenko16934472012-03-29 15:37:04 +040020258 foreach my $Interface (readSymbols_App($AppPath)) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040020259 $SymbolsList_App{$Interface} = 1;
20260 }
20261 }
20262 if($DumpAPI)
20263 { # --dump-abi
20264 # make an API dump
20265 create_ABI_Dump();
20266 exit($COMPILE_ERRORS);
20267 }
20268 # default: compare APIs
20269 # -d1 <path>
20270 # -d2 <path>
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040020271 compareInit();
20272 if($JoinReport or $DoubleReport)
20273 {
20274 compareAPIs("Binary");
20275 compareAPIs("Source");
20276 }
20277 elsif($BinaryOnly) {
20278 compareAPIs("Binary");
20279 }
20280 elsif($SourceOnly) {
20281 compareAPIs("Source");
20282 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040020283 exitReport();
20284}
20285
20286scenario();