blob: 128e49dc085c6cba42816dd3359ddc3d87b82fb1 [file] [log] [blame]
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04001#!/usr/bin/perl
2###########################################################################
Andrey Ponomarenko07aea072012-11-12 16:15:07 +04003# ABI Compliance Checker (ACC) 1.98.5
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04004# A tool for checking backward compatibility of a C/C++ library API
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005#
Andrey Ponomarenko85043792012-05-14 16:48:07 +04006# Copyright (C) 2009-2010 The Linux Foundation
7# Copyright (C) 2009-2011 Institute for System Programming, RAS
8# Copyright (C) 2011-2012 Nokia Corporation and/or its subsidiary(-ies)
9# Copyright (C) 2011-2012 ROSA Laboratory
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010#
11# Written by Andrey Ponomarenko
12#
13# PLATFORMS
14# =========
15# Linux, FreeBSD, Mac OS X, Haiku, MS Windows, Symbian
16#
17# REQUIREMENTS
18# ============
19# Linux
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +040020# - G++ (3.0-4.7, recommended 4.5 or newer)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040021# - GNU Binutils (readelf, c++filt, objdump)
Andrey Ponomarenko85043792012-05-14 16:48:07 +040022# - Perl 5 (5.8 or newer)
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +040023# - Ctags (5.8 or newer)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040024#
25# Mac OS X
Andrey Ponomarenko07aea072012-11-12 16:15:07 +040026# - Xcode (g++, c++filt, nm)
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +040027# - Ctags (5.8 or newer)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040028#
29# MS Windows
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +040030# - MinGW (3.0-4.7, recommended 4.5 or newer)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040031# - MS Visual C++ (dumpbin, undname, cl)
Andrey Ponomarenko85043792012-05-14 16:48:07 +040032# - Active Perl 5 (5.8 or newer)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040033# - Sigcheck v1.71 or newer
34# - Info-ZIP 3.0 (zip, unzip)
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +040035# - Ctags (5.8 or newer)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040036# - Add gcc.exe path (C:\MinGW\bin\) to your system PATH variable
37# - Run vsvars32.bat (C:\Microsoft Visual Studio 9.0\Common7\Tools\)
38#
39# This program is free software: you can redistribute it and/or modify
40# it under the terms of the GNU General Public License or the GNU Lesser
41# General Public License as published by the Free Software Foundation.
42#
43# This program is distributed in the hope that it will be useful,
44# but WITHOUT ANY WARRANTY; without even the implied warranty of
45# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
46# GNU General Public License for more details.
47#
48# You should have received a copy of the GNU General Public License
49# and the GNU Lesser General Public License along with this program.
50# If not, see <http://www.gnu.org/licenses/>.
51###########################################################################
52use Getopt::Long;
53Getopt::Long::Configure ("posix_default", "no_ignore_case");
54use File::Path qw(mkpath rmtree);
55use File::Temp qw(tempdir);
56use File::Copy qw(copy move);
57use Cwd qw(abs_path cwd);
58use Data::Dumper;
Andrey Ponomarenko2fba6302012-03-29 17:44:47 +040059use Config;
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040060use Fcntl;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040061
Andrey Ponomarenko07aea072012-11-12 16:15:07 +040062my $TOOL_VERSION = "1.98.5";
63my $ABI_DUMP_VERSION = "2.19.2";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040064my $OLDEST_SUPPORTED_VERSION = "1.18";
65my $XML_REPORT_VERSION = "1.0";
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +040066my $XML_ABI_DUMP_VERSION = "1.2";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040067my $OSgroup = get_OSgroup();
68my $ORIG_DIR = cwd();
69my $TMP_DIR = tempdir(CLEANUP=>1);
70
71# Internal modules
72my $MODULES_DIR = get_Modules();
73push(@INC, get_dirname($MODULES_DIR));
74# Rules DB
75my %RULES_PATH = (
76 "Binary" => $MODULES_DIR."/RulesBin.xml",
77 "Source" => $MODULES_DIR."/RulesSrc.xml");
78
79my ($Help, $ShowVersion, %Descriptor, $TargetLibraryName, $GenerateTemplate,
80$TestTool, $DumpAPI, $SymbolsListPath, $CheckHeadersOnly_Opt, $UseDumps,
81$CheckObjectsOnly_Opt, $AppPath, $StrictCompat, $DumpVersion, $ParamNamesPath,
82%RelativeDirectory, $TargetLibraryFName, $TestDump, $CheckImpl, $LoggingPath,
83%TargetVersion, $InfoMsg, $UseOldDumps, %UsedDump, $CrossGcc, %OutputLogPath,
84$OutputReportPath, $OutputDumpPath, $ShowRetVal, $SystemRoot_Opt, $DumpSystem,
85$CmpSystems, $TargetLibsPath, $Debug, $CrossPrefix, $UseStaticLibs, $NoStdInc,
86$TargetComponent_Opt, $TargetSysInfo, $TargetHeader, $ExtendedCheck, $Quiet,
Andrey Ponomarenko07aea072012-11-12 16:15:07 +040087$SkipHeadersPath, $CppCompat, $LogMode, $StdOut, $ListAffected, $ReportFormat,
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040088$UserLang, $TargetHeadersPath, $BinaryOnly, $SourceOnly, $BinaryReportPath,
Andrey Ponomarenko07aea072012-11-12 16:15:07 +040089$SourceReportPath, $UseXML, $Browse, $OpenReport, $SortDump, $DumpFormat,
90$ExtraInfo);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040091
92my $CmdName = get_filename($0);
93my %OS_LibExt = (
94 "dynamic" => {
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040095 "linux"=>"so",
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040096 "macos"=>"dylib",
97 "windows"=>"dll",
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040098 "symbian"=>"dso",
99 "default"=>"so"
Andrey Ponomarenkoab282102012-03-11 11:57:02 +0400100 },
101 "static" => {
Andrey Ponomarenko9927e332012-10-19 10:50:48 +0400102 "linux"=>"a",
Andrey Ponomarenkoab282102012-03-11 11:57:02 +0400103 "windows"=>"lib",
Andrey Ponomarenko9927e332012-10-19 10:50:48 +0400104 "symbian"=>"lib",
105 "default"=>"a"
Andrey Ponomarenkoab282102012-03-11 11:57:02 +0400106 }
107);
108
109my %OS_Archive = (
110 "windows"=>"zip",
111 "default"=>"tar.gz"
112);
113
114my %ERROR_CODE = (
115 # Compatible verdict
116 "Compatible"=>0,
117 "Success"=>0,
118 # Incompatible verdict
119 "Incompatible"=>1,
120 # Undifferentiated error code
121 "Error"=>2,
122 # System command is not found
123 "Not_Found"=>3,
124 # Cannot access input files
125 "Access_Error"=>4,
126 # Cannot compile header files
127 "Cannot_Compile"=>5,
128 # Header compiled with errors
129 "Compile_Error"=>6,
130 # Invalid input ABI dump
131 "Invalid_Dump"=>7,
132 # Incompatible version of ABI dump
133 "Dump_Version"=>8,
134 # Cannot find a module
135 "Module_Error"=>9,
136 # Empty intersection between
137 # headers and shared objects
138 "Empty_Intersection"=>10,
139 # Empty set of symbols in headers
140 "Empty_Set"=>11
141);
142
143my %HomePage = (
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +0400144 "Wiki"=>"http://ispras.linuxbase.org/index.php/ABI_compliance_checker",
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +0400145 "Dev1"=>"https://github.com/lvc/abi-compliance-checker",
146 "Dev2"=>"http://forge.ispras.ru/projects/abi-compliance-checker"
Andrey Ponomarenkoab282102012-03-11 11:57:02 +0400147);
148
149my $ShortUsage = "ABI Compliance Checker (ACC) $TOOL_VERSION
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +0400150A tool for checking backward compatibility of a C/C++ library API
Andrey Ponomarenkoab282102012-03-11 11:57:02 +0400151Copyright (C) 2012 ROSA Laboratory
152License: GNU LGPL or GNU GPL
153
154Usage: $CmdName [options]
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +0400155Example: $CmdName -lib NAME -old OLD.xml -new NEW.xml
Andrey Ponomarenkoab282102012-03-11 11:57:02 +0400156
157OLD.xml and NEW.xml are XML-descriptors:
158
159 <version>
160 1.0
161 </version>
162
163 <headers>
164 /path/to/headers/
165 </headers>
166
167 <libs>
168 /path/to/libraries/
169 </libs>
170
171More info: $CmdName --help\n";
172
173if($#ARGV==-1) {
174 printMsg("INFO", $ShortUsage);
175 exit(0);
176}
177
178foreach (2 .. $#ARGV)
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +0400179{ # correct comma separated options
Andrey Ponomarenkoab282102012-03-11 11:57:02 +0400180 if($ARGV[$_-1] eq ",") {
181 $ARGV[$_-2].=",".$ARGV[$_];
182 splice(@ARGV, $_-1, 2);
183 }
184 elsif($ARGV[$_-1]=~/,\Z/) {
185 $ARGV[$_-1].=$ARGV[$_];
186 splice(@ARGV, $_, 1);
187 }
188 elsif($ARGV[$_]=~/\A,/
189 and $ARGV[$_] ne ",") {
190 $ARGV[$_-1].=$ARGV[$_];
191 splice(@ARGV, $_, 1);
192 }
193}
194
195GetOptions("h|help!" => \$Help,
196 "i|info!" => \$InfoMsg,
197 "v|version!" => \$ShowVersion,
198 "dumpversion!" => \$DumpVersion,
199# general options
200 "l|lib|library=s" => \$TargetLibraryName,
201 "d1|old|o=s" => \$Descriptor{1}{"Path"},
202 "d2|new|n=s" => \$Descriptor{2}{"Path"},
203 "dump|dump-abi|dump_abi=s" => \$DumpAPI,
204 "old-dumps!" => \$UseOldDumps,
205# extra options
206 "d|descriptor-template!" => \$GenerateTemplate,
207 "app|application=s" => \$AppPath,
208 "static-libs!" => \$UseStaticLibs,
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +0400209 "cross-gcc|gcc-path=s" => \$CrossGcc,
210 "cross-prefix|gcc-prefix=s" => \$CrossPrefix,
Andrey Ponomarenkoab282102012-03-11 11:57:02 +0400211 "sysroot=s" => \$SystemRoot_Opt,
212 "v1|version1|vnum=s" => \$TargetVersion{1},
213 "v2|version2=s" => \$TargetVersion{2},
214 "s|strict!" => \$StrictCompat,
215 "symbols-list=s" => \$SymbolsListPath,
216 "skip-headers=s" => \$SkipHeadersPath,
217 "headers-only|headers_only!" => \$CheckHeadersOnly_Opt,
218 "objects-only!" => \$CheckObjectsOnly_Opt,
219 "check-impl|check-implementation!" => \$CheckImpl,
220 "show-retval!" => \$ShowRetVal,
221 "use-dumps!" => \$UseDumps,
222 "nostdinc!" => \$NoStdInc,
223 "dump-system=s" => \$DumpSystem,
224 "sysinfo=s" => \$TargetSysInfo,
225 "cmp-systems!" => \$CmpSystems,
226 "libs-list=s" => \$TargetLibsPath,
227 "headers-list=s" => \$TargetHeadersPath,
228 "header=s" => \$TargetHeader,
229 "ext|extended!" => \$ExtendedCheck,
230 "q|quiet!" => \$Quiet,
231 "stdout!" => \$StdOut,
232 "report-format=s" => \$ReportFormat,
Andrey Ponomarenko5c09ef32012-06-14 18:17:33 +0400233 "dump-format=s" => \$DumpFormat,
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +0400234 "xml!" => \$UseXML,
Andrey Ponomarenkoab282102012-03-11 11:57:02 +0400235 "lang=s" => \$UserLang,
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +0400236 "binary|bin|abi!" => \$BinaryOnly,
237 "source|src|api!" => \$SourceOnly,
Andrey Ponomarenkoab282102012-03-11 11:57:02 +0400238# other options
239 "test!" => \$TestTool,
240 "test-dump!" => \$TestDump,
241 "debug!" => \$Debug,
Andrey Ponomarenko07aea072012-11-12 16:15:07 +0400242 "cpp-compatible!" => \$CppCompat,
Andrey Ponomarenkoab282102012-03-11 11:57:02 +0400243 "p|params=s" => \$ParamNamesPath,
244 "relpath1|relpath=s" => \$RelativeDirectory{1},
245 "relpath2=s" => \$RelativeDirectory{2},
246 "dump-path=s" => \$OutputDumpPath,
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +0400247 "sort!" => \$SortDump,
Andrey Ponomarenkoab282102012-03-11 11:57:02 +0400248 "report-path=s" => \$OutputReportPath,
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +0400249 "bin-report-path=s" => \$BinaryReportPath,
250 "src-report-path=s" => \$SourceReportPath,
Andrey Ponomarenkoab282102012-03-11 11:57:02 +0400251 "log-path=s" => \$LoggingPath,
252 "log1-path=s" => \$OutputLogPath{1},
253 "log2-path=s" => \$OutputLogPath{2},
254 "logging-mode=s" => \$LogMode,
255 "list-affected!" => \$ListAffected,
256 "l-full|lib-full=s" => \$TargetLibraryFName,
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +0400257 "component=s" => \$TargetComponent_Opt,
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +0400258 "b|browse=s" => \$Browse,
Andrey Ponomarenko07aea072012-11-12 16:15:07 +0400259 "open!" => \$OpenReport,
260 "extra-info=s" => \$ExtraInfo
Andrey Ponomarenkoab282102012-03-11 11:57:02 +0400261) or ERR_MESSAGE();
262
263sub ERR_MESSAGE()
264{
265 printMsg("INFO", "\n".$ShortUsage);
266 exit($ERROR_CODE{"Error"});
267}
268
269my $LIB_TYPE = $UseStaticLibs?"static":"dynamic";
270my $SLIB_TYPE = $LIB_TYPE;
271if($OSgroup!~/macos|windows/ and $SLIB_TYPE eq "dynamic")
272{ # show as "shared" library
273 $SLIB_TYPE = "shared";
274}
275my $LIB_EXT = getLIB_EXT($OSgroup);
276my $AR_EXT = getAR_EXT($OSgroup);
277my $BYTE_SIZE = 8;
278my $COMMON_LOG_PATH = "logs/run.log";
279
280my $HelpMessage="
281NAME:
282 ABI Compliance Checker ($CmdName)
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +0400283 Check backward compatibility of a C/C++ library API
Andrey Ponomarenkoab282102012-03-11 11:57:02 +0400284
285DESCRIPTION:
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +0400286 ABI Compliance Checker (ACC) is a tool for checking backward binary and
287 source-level compatibility of a $SLIB_TYPE C/C++ library. The tool checks
288 header files and $SLIB_TYPE libraries (*.$LIB_EXT) of old and new versions and
289 analyzes changes in API and ABI (ABI=API+compiler ABI) that may break binary
290 and/or source-level compatibility: changes in calling stack, v-table changes,
291 removed symbols, renamed fields, etc. Binary incompatibility may result in
292 crashing or incorrect behavior of applications built with an old version of
293 a library if they run on a new one. Source incompatibility may result in
294 recompilation errors with a new library version.
Andrey Ponomarenkoab282102012-03-11 11:57:02 +0400295
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +0400296 The tool is intended for developers of software libraries and maintainers
297 of operating systems who are interested in ensuring backward compatibility,
298 i.e. allow old applications to run or to be recompiled with newer library
299 versions.
300
301 Also the tool can be used by ISVs for checking applications portability to
302 new library versions. Found issues can be taken into account when adapting
303 the application to a new library version.
Andrey Ponomarenkoab282102012-03-11 11:57:02 +0400304
305 This tool is free software: you can redistribute it and/or modify it
306 under the terms of the GNU LGPL or GNU GPL.
307
308USAGE:
309 $CmdName [options]
310
311EXAMPLE:
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +0400312 $CmdName -lib NAME -old OLD.xml -new NEW.xml
Andrey Ponomarenkoab282102012-03-11 11:57:02 +0400313
314 OLD.xml and NEW.xml are XML-descriptors:
315
316 <version>
317 1.0
318 </version>
319
320 <headers>
321 /path1/to/header(s)/
322 /path2/to/header(s)/
323 ...
324 </headers>
325
326 <libs>
327 /path1/to/library(ies)/
328 /path2/to/library(ies)/
329 ...
330 </libs>
331
332INFORMATION OPTIONS:
333 -h|-help
334 Print this help.
335
336 -i|-info
337 Print complete info.
338
339 -v|-version
340 Print version information.
341
342 -dumpversion
343 Print the tool version ($TOOL_VERSION) and don't do anything else.
344
345GENERAL OPTIONS:
Andrey Ponomarenko07aea072012-11-12 16:15:07 +0400346 -l|-lib|-library NAME
Andrey Ponomarenkoab282102012-03-11 11:57:02 +0400347 Library name (without version).
Andrey Ponomarenkoab282102012-03-11 11:57:02 +0400348
Andrey Ponomarenko07aea072012-11-12 16:15:07 +0400349 -d1|-old|-o PATH
Andrey Ponomarenkoab282102012-03-11 11:57:02 +0400350 Descriptor of 1st (old) library version.
351 It may be one of the following:
352
353 1. XML-descriptor (VERSION.xml file):
354
355 <version>
356 1.0
357 </version>
358
359 <headers>
360 /path1/to/header(s)/
361 /path2/to/header(s)/
362 ...
363 </headers>
364
365 <libs>
366 /path1/to/library(ies)/
367 /path2/to/library(ies)/
368 ...
369 </libs>
370
371 ... (XML-descriptor template
372 can be generated by -d option)
373
374 2. ABI dump generated by -dump option
375 3. Directory with headers and/or $SLIB_TYPE libraries
376 4. Single header file
377 5. Single $SLIB_TYPE library
378 6. Comma separated list of headers and/or libraries
379
380 If you are using an 2-6 descriptor types then you should
381 specify version numbers with -v1 <num> and -v2 <num> options too.
382
383 For more information, please see:
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +0400384 http://ispras.linuxbase.org/index.php/Library_Descriptor
Andrey Ponomarenkoab282102012-03-11 11:57:02 +0400385
Andrey Ponomarenko07aea072012-11-12 16:15:07 +0400386 -d2|-new|-n PATH
Andrey Ponomarenkoab282102012-03-11 11:57:02 +0400387 Descriptor of 2nd (new) library version.
388
Andrey Ponomarenko07aea072012-11-12 16:15:07 +0400389 -dump|-dump-abi PATH
Andrey Ponomarenkoab282102012-03-11 11:57:02 +0400390 Dump library ABI to gzipped TXT format file. You can transfer it
391 anywhere and pass instead of the descriptor. Also it can be used
392 for debugging the tool. Compatible dump versions: ".majorVersion($ABI_DUMP_VERSION).".0<=V<=$ABI_DUMP_VERSION
393
394 -old-dumps
395 Enable support for old-version ABI dumps ($OLDEST_SUPPORTED_VERSION<=V<".majorVersion($ABI_DUMP_VERSION).".0).\n";
396
397sub HELP_MESSAGE() {
398 printMsg("INFO", $HelpMessage."
399MORE INFO:
400 $CmdName --info\n");
401}
402
403sub INFO_MESSAGE()
404{
405 printMsg("INFO", "$HelpMessage
406EXTRA OPTIONS:
407 -d|-descriptor-template
408 Create XML-descriptor template ./VERSION.xml
409
Andrey Ponomarenko07aea072012-11-12 16:15:07 +0400410 -app|-application PATH
Andrey Ponomarenkoab282102012-03-11 11:57:02 +0400411 This option allows to specify the application that should be checked
412 for portability to the new library version.
413
414 -static-libs
415 Check static libraries instead of the shared ones. The <libs> section
416 of the XML-descriptor should point to static libraries location.
417
Andrey Ponomarenko07aea072012-11-12 16:15:07 +0400418 -cross-gcc|-gcc-path PATH
Andrey Ponomarenkoab282102012-03-11 11:57:02 +0400419 Path to the cross GCC compiler to use instead of the usual (host) GCC.
420
Andrey Ponomarenko07aea072012-11-12 16:15:07 +0400421 -cross-prefix|-gcc-prefix PREFIX
Andrey Ponomarenkoab282102012-03-11 11:57:02 +0400422 GCC toolchain prefix.
423
Andrey Ponomarenko07aea072012-11-12 16:15:07 +0400424 -sysroot DIR
Andrey Ponomarenkoab282102012-03-11 11:57:02 +0400425 Specify the alternative root directory. The tool will search for include
Andrey Ponomarenko07aea072012-11-12 16:15:07 +0400426 paths in the DIR/usr/include and DIR/usr/lib directories.
Andrey Ponomarenkoab282102012-03-11 11:57:02 +0400427
Andrey Ponomarenko07aea072012-11-12 16:15:07 +0400428 -v1|-version1 NUM
Andrey Ponomarenkoab282102012-03-11 11:57:02 +0400429 Specify 1st library version outside the descriptor. This option is needed
430 if you have prefered an alternative descriptor type (see -d1 option).
431
432 In general case you should specify it in the XML-descriptor:
433 <version>
434 VERSION
435 </version>
436
Andrey Ponomarenko07aea072012-11-12 16:15:07 +0400437 -v2|-version2 NUM
Andrey Ponomarenkoab282102012-03-11 11:57:02 +0400438 Specify 2nd library version outside the descriptor.
439
440 -s|-strict
441 Treat all compatibility warnings as problems. Add a number of \"Low\"
442 severity problems to the return value of the tool.
443
444 -headers-only
445 Check header files without $SLIB_TYPE libraries. It is easy to run, but may
446 provide a low quality compatibility report with false positives and
447 without detecting of added/removed symbols.
448
449 Alternatively you can write \"none\" word to the <libs> section
450 in the XML-descriptor:
451 <libs>
452 none
453 </libs>
454
455 -objects-only
456 Check $SLIB_TYPE libraries without header files. It is easy to run, but may
457 provide a low quality compatibility report with false positives and
458 without analysis of changes in parameters and data types.
459
460 Alternatively you can write \"none\" word to the <headers> section
461 in the XML-descriptor:
462 <headers>
463 none
464 </headers>
465
466 -check-impl|-check-implementation
467 Compare canonified disassembled binary code of $SLIB_TYPE libraries to
468 detect changes in the implementation. Add \'Problems with Implementation\'
469 section to the report.
470
471 -show-retval
472 Show the symbol's return type in the report.
473
Andrey Ponomarenko07aea072012-11-12 16:15:07 +0400474 -symbols-list PATH
Andrey Ponomarenkoab282102012-03-11 11:57:02 +0400475 This option allows to specify a file with a list of symbols (mangled
476 names in C++) that should be checked, other symbols will not be checked.
477
Andrey Ponomarenko07aea072012-11-12 16:15:07 +0400478 -skip-headers PATH
Andrey Ponomarenkoab282102012-03-11 11:57:02 +0400479 The file with the list of header files, that should not be checked.
480
481 -use-dumps
482 Make dumps for two versions of a library and compare dumps. This should
483 increase the performance of the tool and decrease the system memory usage.
484
485 -nostdinc
486 Do not search the GCC standard system directories for header files.
487
Andrey Ponomarenko07aea072012-11-12 16:15:07 +0400488 -dump-system NAME -sysroot DIR
489 Find all the shared libraries and header files in DIR directory,
Andrey Ponomarenkoab282102012-03-11 11:57:02 +0400490 create XML descriptors and make ABI dumps for each library. The result
491 set of ABI dumps can be compared (--cmp-systems) with the other one
492 created for other version of operating system in order to check them for
493 compatibility. Do not forget to specify -cross-gcc option if your target
494 system requires some specific version of GCC compiler (different from
495 the host GCC). The system ABI dump will be generated to:
Andrey Ponomarenko07aea072012-11-12 16:15:07 +0400496 sys_dumps/NAME/ARCH
Andrey Ponomarenkoab282102012-03-11 11:57:02 +0400497
Andrey Ponomarenko07aea072012-11-12 16:15:07 +0400498 -dump-system DESCRIPTOR.xml
Andrey Ponomarenkoab282102012-03-11 11:57:02 +0400499 The same as the previous option but takes an XML descriptor of the target
500 system as input, where you should describe it:
501
502 /* Primary sections */
503
504 <name>
505 /* Name of the system */
506 </name>
507
508 <headers>
509 /* The list of paths to header files and/or
510 directories with header files, one per line */
511 </headers>
512
513 <libs>
514 /* The list of paths to shared libraries and/or
515 directories with shared libraries, one per line */
516 </libs>
517
518 /* Optional sections */
519
520 <search_headers>
521 /* List of directories to be searched
522 for header files to automatically
523 generate include paths, one per line */
524 </search_headers>
525
526 <search_libs>
527 /* List of directories to be searched
528 for shared libraries to resolve
529 dependencies, one per line */
530 </search_libs>
531
532 <tools>
533 /* List of directories with tools used
534 for analysis (GCC toolchain), one per line */
535 </tools>
536
537 <cross_prefix>
538 /* GCC toolchain prefix.
539 Examples:
540 arm-linux-gnueabi
541 arm-none-symbianelf */
542 </cross_prefix>
543
544 <gcc_options>
545 /* Additional GCC options, one per line */
546 </gcc_options>
547
Andrey Ponomarenko07aea072012-11-12 16:15:07 +0400548 -sysinfo DIR
Andrey Ponomarenkoab282102012-03-11 11:57:02 +0400549 This option may be used with -dump-system to dump ABI of operating
550 systems and configure the dumping process.
551 Default:
552 modules/Targets/{unix, symbian, windows}
553
Andrey Ponomarenko07aea072012-11-12 16:15:07 +0400554 -cmp-systems -d1 sys_dumps/NAME1/ARCH -d2 sys_dumps/NAME2/ARCH
Andrey Ponomarenkoab282102012-03-11 11:57:02 +0400555 Compare two system ABI dumps. Create compatibility reports for each
556 library and the common HTML report including the summary of test
557 results for all checked libraries. Report will be generated to:
Andrey Ponomarenko07aea072012-11-12 16:15:07 +0400558 sys_compat_reports/NAME1_to_NAME2/ARCH
Andrey Ponomarenkoab282102012-03-11 11:57:02 +0400559
Andrey Ponomarenko07aea072012-11-12 16:15:07 +0400560 -libs-list PATH
Andrey Ponomarenkoab282102012-03-11 11:57:02 +0400561 The file with a list of libraries, that should be dumped by
562 the -dump-system option or should be checked by the -cmp-systems option.
563
Andrey Ponomarenko07aea072012-11-12 16:15:07 +0400564 -header NAME
Andrey Ponomarenkoab282102012-03-11 11:57:02 +0400565 Check/Dump ABI of this header only.
566
Andrey Ponomarenko07aea072012-11-12 16:15:07 +0400567 -headers-list PATH
Andrey Ponomarenkoab282102012-03-11 11:57:02 +0400568 The file with a list of headers, that should be checked/dumped.
569
570 -ext|-extended
571 If your library A is supposed to be used by other library B and you
572 want to control the ABI of B, then you should enable this option. The
573 tool will check for changes in all data types, even if they are not
574 used by any function in the library A. Such data types are not part
575 of the A library ABI, but may be a part of the ABI of the B library.
576
577 The short scheme is:
578 app C (broken) -> lib B (broken ABI) -> lib A (stable ABI)
579
580 -q|-quiet
581 Print all messages to the file instead of stdout and stderr.
582 Default path (can be changed by -log-path option):
583 $COMMON_LOG_PATH
584
585 -stdout
586 Print analysis results (compatibility reports and ABI dumps) to stdout
587 instead of creating a file. This would allow piping data to other programs.
588
Andrey Ponomarenko07aea072012-11-12 16:15:07 +0400589 -report-format FMT
Andrey Ponomarenkoab282102012-03-11 11:57:02 +0400590 Change format of compatibility report.
591 Formats:
592 htm - HTML format (default)
593 xml - XML format
594
Andrey Ponomarenko07aea072012-11-12 16:15:07 +0400595 -dump-format FMT
Andrey Ponomarenko5c09ef32012-06-14 18:17:33 +0400596 Change format of ABI dump.
597 Formats:
598 perl - Data::Dumper format (default)
599 xml - XML format
600
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +0400601 -xml
Andrey Ponomarenko5c09ef32012-06-14 18:17:33 +0400602 Alias for: --report-format=xml or --dump-format=xml
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +0400603
Andrey Ponomarenko07aea072012-11-12 16:15:07 +0400604 -lang LANG
Andrey Ponomarenkoab282102012-03-11 11:57:02 +0400605 Set library language (C or C++). You can use this option if the tool
606 cannot auto-detect a language. This option may be useful for checking
607 C-library headers (--lang=C) in --headers-only or --extended modes.
608
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +0400609 -binary|-bin|-abi
610 Show \"Binary\" compatibility problems only.
611 Generate report to:
Andrey Ponomarenko07aea072012-11-12 16:15:07 +0400612 compat_reports/LIB_NAME/V1_to_V2/abi_compat_report.html
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +0400613
614 -source|-src|-api
615 Show \"Source\" compatibility problems only.
616 Generate report to:
Andrey Ponomarenko07aea072012-11-12 16:15:07 +0400617 compat_reports/LIB_NAME/V1_to_V2/src_compat_report.html
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +0400618
Andrey Ponomarenkoab282102012-03-11 11:57:02 +0400619OTHER OPTIONS:
620 -test
621 Run internal tests. Create two binary incompatible versions of a sample
622 library and run the tool to check them for compatibility. This option
623 allows to check if the tool works correctly in the current environment.
624
625 -test-dump
626 Test ability to create, read and compare ABI dumps.
627
628 -debug
629 Debugging mode. Print debug info on the screen. Save intermediate
630 analysis stages in the debug directory:
Andrey Ponomarenko07aea072012-11-12 16:15:07 +0400631 debug/LIB_NAME/VERSION/
Andrey Ponomarenkoab282102012-03-11 11:57:02 +0400632
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +0400633 Also consider using --dump option for debugging the tool.
634
Andrey Ponomarenkoab282102012-03-11 11:57:02 +0400635 -cpp-compatible
Andrey Ponomarenko07aea072012-11-12 16:15:07 +0400636 If your header files are written in C language and can be compiled
637 by the G++ compiler (i.e. don't use C++ keywords), then you can tell
638 the tool about this and speedup the analysis.
Andrey Ponomarenkoab282102012-03-11 11:57:02 +0400639
Andrey Ponomarenko07aea072012-11-12 16:15:07 +0400640 -p|-params PATH
Andrey Ponomarenkoab282102012-03-11 11:57:02 +0400641 Path to file with the function parameter names. It can be used
642 for improving report view if the library header files have no
643 parameter names. File format:
644
645 func1;param1;param2;param3 ...
646 func2;param1;param2;param3 ...
647 ...
648
Andrey Ponomarenko07aea072012-11-12 16:15:07 +0400649 -relpath PATH
650 Replace {RELPATH} macros to PATH in the XML-descriptor used
Andrey Ponomarenkoab282102012-03-11 11:57:02 +0400651 for dumping the library ABI (see -dump option).
652
Andrey Ponomarenko07aea072012-11-12 16:15:07 +0400653 -relpath1 PATH
654 Replace {RELPATH} macros to PATH in the 1st XML-descriptor (-d1).
Andrey Ponomarenkoab282102012-03-11 11:57:02 +0400655
Andrey Ponomarenko07aea072012-11-12 16:15:07 +0400656 -relpath2 PATH
657 Replace {RELPATH} macros to PATH in the 2nd XML-descriptor (-d2).
Andrey Ponomarenkoab282102012-03-11 11:57:02 +0400658
Andrey Ponomarenko07aea072012-11-12 16:15:07 +0400659 -dump-path PATH
Andrey Ponomarenko5c09ef32012-06-14 18:17:33 +0400660 Specify a *.abi.$AR_EXT or *.abi file path where to generate an ABI dump.
Andrey Ponomarenkoab282102012-03-11 11:57:02 +0400661 Default:
Andrey Ponomarenko07aea072012-11-12 16:15:07 +0400662 abi_dumps/LIB_NAME/LIB_NAME_VERSION.abi.$AR_EXT
Andrey Ponomarenkoab282102012-03-11 11:57:02 +0400663
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +0400664 -sort
665 Enable sorting of data in ABI dumps.
666
Andrey Ponomarenko07aea072012-11-12 16:15:07 +0400667 -report-path PATH
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +0400668 Path to compatibility report.
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +0400669 Default:
Andrey Ponomarenko07aea072012-11-12 16:15:07 +0400670 compat_reports/LIB_NAME/V1_to_V2/compat_report.html
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +0400671
Andrey Ponomarenko07aea072012-11-12 16:15:07 +0400672 -bin-report-path PATH
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +0400673 Path to \"Binary\" compatibility report.
Andrey Ponomarenkoab282102012-03-11 11:57:02 +0400674 Default:
Andrey Ponomarenko07aea072012-11-12 16:15:07 +0400675 compat_reports/LIB_NAME/V1_to_V2/abi_compat_report.html
Andrey Ponomarenkoab282102012-03-11 11:57:02 +0400676
Andrey Ponomarenko07aea072012-11-12 16:15:07 +0400677 -src-report-path PATH
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +0400678 Path to \"Source\" compatibility report.
679 Default:
Andrey Ponomarenko07aea072012-11-12 16:15:07 +0400680 compat_reports/LIB_NAME/V1_to_V2/src_compat_report.html
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +0400681
Andrey Ponomarenko07aea072012-11-12 16:15:07 +0400682 -log-path PATH
Andrey Ponomarenkoab282102012-03-11 11:57:02 +0400683 Log path for all messages.
684 Default:
Andrey Ponomarenko07aea072012-11-12 16:15:07 +0400685 logs/LIB_NAME/VERSION/log.txt
Andrey Ponomarenkoab282102012-03-11 11:57:02 +0400686
Andrey Ponomarenko07aea072012-11-12 16:15:07 +0400687 -log1-path PATH
Andrey Ponomarenkoab282102012-03-11 11:57:02 +0400688 Log path for 1st version of a library.
689 Default:
Andrey Ponomarenko07aea072012-11-12 16:15:07 +0400690 logs/LIB_NAME/V1/log.txt
Andrey Ponomarenkoab282102012-03-11 11:57:02 +0400691
Andrey Ponomarenko07aea072012-11-12 16:15:07 +0400692 -log2-path PATH
Andrey Ponomarenkoab282102012-03-11 11:57:02 +0400693 Log path for 2nd version of a library.
694 Default:
Andrey Ponomarenko07aea072012-11-12 16:15:07 +0400695 logs/LIB_NAME/V2/log.txt
Andrey Ponomarenkoab282102012-03-11 11:57:02 +0400696
Andrey Ponomarenko07aea072012-11-12 16:15:07 +0400697 -logging-mode MODE
Andrey Ponomarenkoab282102012-03-11 11:57:02 +0400698 Change logging mode.
699 Modes:
700 w - overwrite old logs (default)
701 a - append old logs
702 n - do not write any logs
703
704 -list-affected
705 Generate file with the list of incompatible
706 symbols beside the HTML compatibility report.
707 Use 'c++filt \@file' command from GNU binutils
708 to unmangle C++ symbols in the generated file.
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +0400709 Default names:
Andrey Ponomarenkoab282102012-03-11 11:57:02 +0400710 abi_affected.txt
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +0400711 src_affected.txt
Andrey Ponomarenkoab282102012-03-11 11:57:02 +0400712
Andrey Ponomarenko07aea072012-11-12 16:15:07 +0400713 -component NAME
Andrey Ponomarenkoab282102012-03-11 11:57:02 +0400714 The component name in the title and summary of the HTML report.
715 Default:
716 library
717
Andrey Ponomarenko07aea072012-11-12 16:15:07 +0400718 -l-full|-lib-full NAME
719 Change library name in the report title to NAME. By default
Andrey Ponomarenkoab282102012-03-11 11:57:02 +0400720 will be displayed a name specified by -l option.
721
Andrey Ponomarenko07aea072012-11-12 16:15:07 +0400722 -b|-browse PROGRAM
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +0400723 Open report(s) in the browser (firefox, opera, etc.).
724
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +0400725 -open
726 Open report(s) in the default browser.
Andrey Ponomarenko07aea072012-11-12 16:15:07 +0400727
728 -extra-info DIR
729 Dump extra info to DIR.
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +0400730
Andrey Ponomarenkoab282102012-03-11 11:57:02 +0400731REPORT:
732 Compatibility report will be generated to:
Andrey Ponomarenko07aea072012-11-12 16:15:07 +0400733 compat_reports/LIB_NAME/V1_to_V2/compat_report.html
Andrey Ponomarenkoab282102012-03-11 11:57:02 +0400734
735 Log will be generated to:
Andrey Ponomarenko07aea072012-11-12 16:15:07 +0400736 logs/LIB_NAME/V1/log.txt
737 logs/LIB_NAME/V2/log.txt
Andrey Ponomarenkoab282102012-03-11 11:57:02 +0400738
739EXIT CODES:
740 0 - Compatible. The tool has run without any errors.
741 non-zero - Incompatible or the tool has run with errors.
742
743REPORT BUGS TO:
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +0400744 Andrey Ponomarenko <aponomarenko\@rosalab.ru>
Andrey Ponomarenkoab282102012-03-11 11:57:02 +0400745
746MORE INFORMATION:
747 ".$HomePage{"Wiki"}."
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +0400748 ".$HomePage{"Dev1"}."\n");
Andrey Ponomarenkoab282102012-03-11 11:57:02 +0400749}
750
751my $DescriptorTemplate = "
752<?xml version=\"1.0\" encoding=\"utf-8\"?>
753<descriptor>
754
755/* Primary sections */
756
757<version>
758 /* Version of the library */
759</version>
760
761<headers>
762 /* The list of paths to header files and/or
763 directories with header files, one per line */
764</headers>
765
766<libs>
767 /* The list of paths to shared libraries (*.$LIB_EXT) and/or
768 directories with shared libraries, one per line */
769</libs>
770
771/* Optional sections */
772
773<include_paths>
774 /* The list of include paths that will be provided
775 to GCC to compile library headers, one per line.
776 NOTE: If you define this section then the tool
777 will not automatically generate include paths */
778</include_paths>
779
780<add_include_paths>
781 /* The list of include paths that will be added
782 to the automatically generated include paths, one per line */
783</add_include_paths>
784
785<skip_include_paths>
786 /* The list of include paths that will be removed from the
787 list of automatically generated include paths, one per line */
788</skip_include_paths>
789
790<gcc_options>
791 /* Additional GCC options, one per line */
792</gcc_options>
793
794<include_preamble>
795 /* The list of header files that will be
796 included before other headers, one per line.
797 Examples:
798 1) tree.h for libxml2
799 2) ft2build.h for freetype2 */
800</include_preamble>
801
802<defines>
803 /* The list of defines that will be added at the
804 headers compiling stage, one per line:
805 #define A B
806 #define C D */
807</defines>
808
Andrey Ponomarenkoa01311b2012-06-08 17:20:02 +0400809<add_namespaces>
810 /* The list of namespaces that should be added to the alanysis
811 if the tool cannot find them automatically, one per line */
812</add_namespaces>
813
Andrey Ponomarenkoab282102012-03-11 11:57:02 +0400814<skip_types>
815 /* The list of data types, that
816 should not be checked, one per line */
817</skip_types>
818
819<skip_symbols>
820 /* The list of functions (mangled/symbol names in C++),
821 that should not be checked, one per line */
822</skip_symbols>
823
824<skip_namespaces>
825 /* The list of C++ namespaces, that
826 should not be checked, one per line */
827</skip_namespaces>
828
829<skip_constants>
830 /* The list of constants that should
831 not be checked, one name per line */
832</skip_constants>
833
834<skip_headers>
835 /* The list of header files and/or directories
836 with header files that should not be checked, one per line */
837</skip_headers>
838
839<skip_libs>
840 /* The list of shared libraries and/or directories
841 with shared libraries that should not be checked, one per line */
842</skip_libs>
843
844<skip_including>
845 /* The list of header files, that cannot be included
846 directly (or non-self compiled ones), one per line */
847</skip_including>
848
849<search_headers>
850 /* List of directories to be searched
851 for header files to automatically
852 generate include paths, one per line. */
853</search_headers>
854
855<search_libs>
856 /* List of directories to be searched
857 for shared librariess to resolve
858 dependencies, one per line */
859</search_libs>
860
861<tools>
862 /* List of directories with tools used
863 for analysis (GCC toolchain), one per line */
864</tools>
865
866<cross_prefix>
867 /* GCC toolchain prefix.
868 Examples:
869 arm-linux-gnueabi
870 arm-none-symbianelf */
871</cross_prefix>
872
873</descriptor>";
874
875my %Operator_Indication = (
876 "not" => "~",
877 "assign" => "=",
878 "andassign" => "&=",
879 "orassign" => "|=",
880 "xorassign" => "^=",
881 "or" => "|",
882 "xor" => "^",
883 "addr" => "&",
884 "and" => "&",
885 "lnot" => "!",
886 "eq" => "==",
887 "ne" => "!=",
888 "lt" => "<",
889 "lshift" => "<<",
890 "lshiftassign" => "<<=",
891 "rshiftassign" => ">>=",
892 "call" => "()",
893 "mod" => "%",
894 "modassign" => "%=",
895 "subs" => "[]",
896 "land" => "&&",
897 "lor" => "||",
898 "rshift" => ">>",
899 "ref" => "->",
900 "le" => "<=",
901 "deref" => "*",
902 "mult" => "*",
903 "preinc" => "++",
904 "delete" => " delete",
905 "vecnew" => " new[]",
906 "vecdelete" => " delete[]",
907 "predec" => "--",
908 "postinc" => "++",
909 "postdec" => "--",
910 "plusassign" => "+=",
911 "plus" => "+",
912 "minus" => "-",
913 "minusassign" => "-=",
914 "gt" => ">",
915 "ge" => ">=",
916 "new" => " new",
917 "multassign" => "*=",
918 "divassign" => "/=",
919 "div" => "/",
920 "neg" => "-",
921 "pos" => "+",
922 "memref" => "->*",
923 "compound" => "," );
924
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +0400925my %UnknownOperator;
926
927my %NodeType= (
928 "array_type" => "Array",
929 "binfo" => "Other",
930 "boolean_type" => "Intrinsic",
931 "complex_type" => "Intrinsic",
932 "const_decl" => "Other",
933 "enumeral_type" => "Enum",
934 "field_decl" => "Other",
935 "function_decl" => "Other",
936 "function_type" => "FunctionType",
937 "identifier_node" => "Other",
938 "integer_cst" => "Other",
939 "integer_type" => "Intrinsic",
940 "method_type" => "MethodType",
941 "namespace_decl" => "Other",
942 "parm_decl" => "Other",
943 "pointer_type" => "Pointer",
944 "real_cst" => "Other",
945 "real_type" => "Intrinsic",
946 "record_type" => "Struct",
947 "reference_type" => "Ref",
948 "string_cst" => "Other",
949 "template_decl" => "Other",
950 "template_type_parm" => "Other",
951 "tree_list" => "Other",
952 "tree_vec" => "Other",
953 "type_decl" => "Other",
954 "union_type" => "Union",
955 "var_decl" => "Other",
956 "void_type" => "Intrinsic",
957 # "nop_expr" => "Other",
958 # "addr_expr" => "Other",
959 "offset_type" => "Other" );
960
Andrey Ponomarenkoab282102012-03-11 11:57:02 +0400961my %CppKeywords_C = map {$_=>1} (
962 # C++ 2003 keywords
963 "public",
964 "protected",
965 "private",
966 "default",
967 "template",
968 "new",
969 #"asm",
970 "dynamic_cast",
971 "auto",
972 "try",
973 "namespace",
974 "typename",
975 "using",
976 "reinterpret_cast",
977 "friend",
978 "class",
979 "virtual",
980 "const_cast",
981 "mutable",
982 "static_cast",
983 "export",
984 # C++0x keywords
985 "noexcept",
986 "nullptr",
987 "constexpr",
988 "static_assert",
989 "explicit",
990 # cannot be used as a macro name
991 # as it is an operator in C++
992 "and",
993 #"and_eq",
994 "not",
995 #"not_eq",
996 "or"
997 #"or_eq",
998 #"bitand",
999 #"bitor",
1000 #"xor",
1001 #"xor_eq",
1002 #"compl"
1003);
1004
1005my %CppKeywords_F = map {$_=>1} (
1006 "delete",
1007 "catch",
1008 "alignof",
1009 "thread_local",
1010 "decltype",
1011 "typeid"
1012);
1013
1014my %CppKeywords_O = map {$_=>1} (
1015 "bool",
1016 "register",
1017 "inline",
1018 "operator"
1019);
1020
1021my %CppKeywords_A = map {$_=>1} (
1022 "this",
1023 "throw"
1024);
1025
1026foreach (keys(%CppKeywords_C),
1027keys(%CppKeywords_F),
1028keys(%CppKeywords_O)) {
1029 $CppKeywords_A{$_}=1;
1030}
1031
1032# Header file extensions as described by gcc
1033my $HEADER_EXT = "h|hh|hp|hxx|hpp|h\\+\\+";
1034
1035my %IntrinsicMangling = (
1036 "void" => "v",
1037 "bool" => "b",
1038 "wchar_t" => "w",
1039 "char" => "c",
1040 "signed char" => "a",
1041 "unsigned char" => "h",
1042 "short" => "s",
1043 "unsigned short" => "t",
1044 "int" => "i",
1045 "unsigned int" => "j",
1046 "long" => "l",
1047 "unsigned long" => "m",
1048 "long long" => "x",
1049 "__int64" => "x",
1050 "unsigned long long" => "y",
1051 "__int128" => "n",
1052 "unsigned __int128" => "o",
1053 "float" => "f",
1054 "double" => "d",
1055 "long double" => "e",
1056 "__float80" => "e",
1057 "__float128" => "g",
1058 "..." => "z"
1059);
1060
1061my %StdcxxMangling = (
1062 "3std"=>"St",
1063 "3std9allocator"=>"Sa",
1064 "3std12basic_string"=>"Sb",
1065 "3std12basic_stringIcE"=>"Ss",
1066 "3std13basic_istreamIcE"=>"Si",
1067 "3std13basic_ostreamIcE"=>"So",
1068 "3std14basic_iostreamIcE"=>"Sd"
1069);
1070
Andrey Ponomarenko07aea072012-11-12 16:15:07 +04001071my $DEFAULT_STD_PARMS = "std::(allocator|less|char_traits|regex_traits)";
1072
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04001073my %ConstantSuffix = (
1074 "unsigned int"=>"u",
1075 "long"=>"l",
1076 "unsigned long"=>"ul",
1077 "long long"=>"ll",
1078 "unsigned long long"=>"ull"
1079);
1080
1081my %ConstantSuffixR =
1082reverse(%ConstantSuffix);
1083
1084my %OperatorMangling = (
1085 "~" => "co",
1086 "=" => "aS",
1087 "|" => "or",
1088 "^" => "eo",
1089 "&" => "an",#ad (addr)
1090 "==" => "eq",
1091 "!" => "nt",
1092 "!=" => "ne",
1093 "<" => "lt",
1094 "<=" => "le",
1095 "<<" => "ls",
1096 "<<=" => "lS",
1097 ">" => "gt",
1098 ">=" => "ge",
1099 ">>" => "rs",
1100 ">>=" => "rS",
1101 "()" => "cl",
1102 "%" => "rm",
1103 "[]" => "ix",
1104 "&&" => "aa",
1105 "||" => "oo",
1106 "*" => "ml",#de (deref)
1107 "++" => "pp",#
1108 "--" => "mm",#
1109 "new" => "nw",
1110 "delete" => "dl",
1111 "new[]" => "na",
1112 "delete[]" => "da",
1113 "+=" => "pL",
1114 "+" => "pl",#ps (pos)
1115 "-" => "mi",#ng (neg)
1116 "-=" => "mI",
1117 "*=" => "mL",
1118 "/=" => "dV",
1119 "&=" => "aN",
1120 "|=" => "oR",
1121 "%=" => "rM",
1122 "^=" => "eO",
1123 "/" => "dv",
1124 "->*" => "pm",
1125 "->" => "pt",#rf (ref)
1126 "," => "cm",
1127 "?" => "qu",
1128 "." => "dt",
1129 "sizeof"=> "sz"#st
1130);
1131
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04001132my %Intrinsic_Keywords = map {$_=>1} (
1133 "true",
1134 "false",
1135 "_Bool",
1136 "_Complex",
1137 "const",
1138 "int",
1139 "long",
1140 "void",
1141 "short",
1142 "float",
1143 "volatile",
1144 "restrict",
1145 "unsigned",
1146 "signed",
1147 "char",
1148 "double",
1149 "class",
1150 "struct",
1151 "union",
1152 "enum"
1153);
1154
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04001155my %GlibcHeader = map {$_=>1} (
1156 "aliases.h",
1157 "argp.h",
1158 "argz.h",
1159 "assert.h",
1160 "cpio.h",
1161 "ctype.h",
1162 "dirent.h",
1163 "envz.h",
1164 "errno.h",
1165 "error.h",
1166 "execinfo.h",
1167 "fcntl.h",
1168 "fstab.h",
1169 "ftw.h",
1170 "glob.h",
1171 "grp.h",
1172 "iconv.h",
1173 "ifaddrs.h",
1174 "inttypes.h",
1175 "langinfo.h",
1176 "limits.h",
1177 "link.h",
1178 "locale.h",
1179 "malloc.h",
1180 "math.h",
1181 "mntent.h",
1182 "monetary.h",
1183 "nl_types.h",
1184 "obstack.h",
1185 "printf.h",
1186 "pwd.h",
1187 "regex.h",
1188 "sched.h",
1189 "search.h",
1190 "setjmp.h",
1191 "shadow.h",
1192 "signal.h",
1193 "spawn.h",
1194 "stdarg.h",
1195 "stdint.h",
1196 "stdio.h",
1197 "stdlib.h",
1198 "string.h",
Andrey Ponomarenko9927e332012-10-19 10:50:48 +04001199 "strings.h",
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04001200 "tar.h",
1201 "termios.h",
1202 "time.h",
1203 "ulimit.h",
1204 "unistd.h",
1205 "utime.h",
1206 "wchar.h",
1207 "wctype.h",
1208 "wordexp.h" );
1209
1210my %GlibcDir = map {$_=>1} (
1211 "arpa",
1212 "bits",
1213 "gnu",
1214 "netinet",
1215 "net",
1216 "nfs",
1217 "rpc",
1218 "sys",
1219 "linux" );
1220
Andrey Ponomarenko9927e332012-10-19 10:50:48 +04001221my %WinHeaders = map {$_=>1} (
1222 "dos.h",
1223 "process.h",
1224 "winsock.h",
1225 "config-win.h",
1226 "mem.h",
1227 "windows.h",
1228 "winsock2.h",
1229 "crtdbg.h",
1230 "ws2tcpip.h"
1231);
1232
1233my %ObsoleteHeaders = map {$_=>1} (
1234 "iostream.h",
1235 "fstream.h"
1236);
1237
1238my %ConfHeaders = map {$_=>1} (
1239 "atomic",
1240 "conf.h",
1241 "config.h",
1242 "configure.h",
1243 "build.h",
1244 "setup.h"
1245);
1246
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04001247my %LocalIncludes = map {$_=>1} (
1248 "/usr/local/include",
1249 "/usr/local" );
1250
1251my %OS_AddPath=(
1252# These paths are needed if the tool cannot detect them automatically
1253 "macos"=>{
1254 "include"=>{
1255 "/Library"=>1,
1256 "/Developer/usr/include"=>1
1257 },
1258 "lib"=>{
1259 "/Library"=>1,
1260 "/Developer/usr/lib"=>1
1261 },
1262 "bin"=>{
1263 "/Developer/usr/bin"=>1
1264 }
1265 },
1266 "beos"=>{
1267 # Haiku has GCC 2.95.3 by default
1268 # try to find GCC>=3.0 in /boot/develop/abi
1269 "include"=>{
1270 "/boot/common"=>1,
1271 "/boot/develop"=>1},
1272 "lib"=>{
1273 "/boot/common/lib"=>1,
1274 "/boot/system/lib"=>1,
1275 "/boot/apps"=>1},
1276 "bin"=>{
1277 "/boot/common/bin"=>1,
1278 "/boot/system/bin"=>1,
1279 "/boot/develop/abi"=>1
1280 }
1281}
1282);
1283
1284my %Slash_Type=(
1285 "default"=>"/",
1286 "windows"=>"\\"
1287);
1288
1289my $SLASH = $Slash_Type{$OSgroup}?$Slash_Type{$OSgroup}:$Slash_Type{"default"};
1290
1291# Global Variables
1292my %COMMON_LANGUAGE=(
1293 1 => "C",
1294 2 => "C" );
1295
1296my $MAX_COMMAND_LINE_ARGUMENTS = 4096;
Andrey Ponomarenko9927e332012-10-19 10:50:48 +04001297my $MAX_CPPFILT_FILE_SIZE = 50000;
1298my $CPPFILT_SUPPORT_FILE;
1299
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04001300my (%WORD_SIZE, %CPU_ARCH, %GCC_VERSION);
1301
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04001302my $STDCXX_TESTING = 0;
1303my $GLIBC_TESTING = 0;
1304
1305my $CheckHeadersOnly = $CheckHeadersOnly_Opt;
1306my $CheckObjectsOnly = $CheckObjectsOnly_Opt;
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04001307my $TargetComponent;
1308
1309# Set Target Component Name
1310if($TargetComponent_Opt) {
1311 $TargetComponent = lc($TargetComponent_Opt);
1312}
1313else
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04001314{ # default: library
1315 # other components: header, system, ...
1316 $TargetComponent = "library";
1317}
1318
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04001319my $TOP_REF = "<a style='font-size:11px;' href='#Top'>to the top</a>";
1320
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04001321my $SystemRoot;
1322
1323my $MAIN_CPP_DIR;
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04001324my %RESULT;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04001325my %LOG_PATH;
1326my %DEBUG_PATH;
1327my %Cache;
1328my %LibInfo;
1329my $COMPILE_ERRORS = 0;
1330my %CompilerOptions;
1331my %CheckedDyLib;
1332my $TargetLibraryShortName = parse_libname($TargetLibraryName, "shortest", $OSgroup);
1333
1334# Constants (#defines)
1335my %Constants;
1336my %SkipConstants;
1337
1338# Types
1339my %TypeInfo;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04001340my %TemplateInstance;
Andrey Ponomarenko85043792012-05-14 16:48:07 +04001341my %TemplateDecl;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04001342my %SkipTypes = (
1343 "1"=>{},
1344 "2"=>{} );
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04001345my %CheckedTypes;
1346my %TName_Tid;
1347my %EnumMembName_Id;
1348my %NestedNameSpaces = (
1349 "1"=>{},
1350 "2"=>{} );
1351my %UsedType;
1352my %VirtualTable;
Andrey Ponomarenko16934472012-03-29 15:37:04 +04001353my %VirtualTable_Model;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04001354my %ClassVTable;
1355my %ClassVTable_Content;
1356my %VTableClass;
1357my %AllocableClass;
1358my %ClassMethods;
Andrey Ponomarenko16934472012-03-29 15:37:04 +04001359my %ClassNames;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04001360my %Class_SubClasses;
1361my %OverriddenMethods;
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04001362my $MAX_ID = 0;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04001363
1364# Typedefs
1365my %Typedef_BaseName;
1366my %Typedef_Tr;
1367my %Typedef_Eq;
1368my %StdCxxTypedef;
1369my %MissedTypedef;
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04001370my %MissedBase;
1371my %MissedBase_R;
Andrey Ponomarenko9927e332012-10-19 10:50:48 +04001372my %TypeTypedef;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04001373
1374# Symbols
1375my %SymbolInfo;
1376my %tr_name;
1377my %mangled_name_gcc;
1378my %mangled_name;
1379my %SkipSymbols = (
1380 "1"=>{},
1381 "2"=>{} );
1382my %SkipNameSpaces = (
1383 "1"=>{},
1384 "2"=>{} );
Andrey Ponomarenkoa01311b2012-06-08 17:20:02 +04001385my %AddNameSpaces = (
1386 "1"=>{},
1387 "2"=>{} );
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04001388my %SymbolsList;
1389my %SymbolsList_App;
1390my %CheckedSymbols;
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04001391my %Symbol_Library = (
1392 "1"=>{},
1393 "2"=>{} );
1394my %Library_Symbol = (
1395 "1"=>{},
1396 "2"=>{} );
1397my %DepSymbol_Library = (
1398 "1"=>{},
1399 "2"=>{} );
1400my %DepLibrary_Symbol = (
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04001401 "1"=>{},
1402 "2"=>{} );
1403my %MangledNames;
Andrey Ponomarenko9927e332012-10-19 10:50:48 +04001404my %Func_ShortName;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04001405my %AddIntParams;
1406my %Interface_Impl;
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04001407my %GlobalDataObject;
Andrey Ponomarenko07aea072012-11-12 16:15:07 +04001408my %WeakSymbols;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04001409
1410# Headers
1411my %Include_Preamble;
1412my %Registered_Headers;
1413my %HeaderName_Paths;
1414my %Header_Dependency;
1415my %Include_Neighbors;
1416my %Include_Paths;
1417my %INC_PATH_AUTODETECT = (
1418 "1"=>1,
1419 "2"=>1 );
1420my %Add_Include_Paths;
1421my %Skip_Include_Paths;
1422my %RegisteredDirs;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04001423my %Header_ErrorRedirect;
1424my %Header_Includes;
1425my %Header_ShouldNotBeUsed;
1426my %RecursiveIncludes;
1427my %Header_Include_Prefix;
1428my %SkipHeaders;
1429my %SkipHeadersList=(
1430 "1"=>{},
1431 "2"=>{} );
1432my %SkipLibs;
1433my %Include_Order;
1434my %TUnit_NameSpaces;
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +04001435my %TUnit_Classes;
Andrey Ponomarenko9927e332012-10-19 10:50:48 +04001436my %TUnit_Funcs;
1437my %TUnit_Vars;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04001438
Andrey Ponomarenko07aea072012-11-12 16:15:07 +04001439my %CppMode = (
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04001440 "1"=>0,
1441 "2"=>0 );
1442my %AutoPreambleMode = (
1443 "1"=>0,
1444 "2"=>0 );
1445my %MinGWMode = (
1446 "1"=>0,
1447 "2"=>0 );
Andrey Ponomarenko01117f12012-06-26 12:23:02 +04001448my %Cpp0xMode = (
1449 "1"=>0,
1450 "2"=>0 );
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04001451
1452# Shared Objects
Andrey Ponomarenko9927e332012-10-19 10:50:48 +04001453my %RegisteredObjects;
Andrey Ponomarenko07aea072012-11-12 16:15:07 +04001454my %RegisteredObjects_Short;
Andrey Ponomarenko9927e332012-10-19 10:50:48 +04001455my %RegisteredSONAMEs;
1456my %RegisteredObject_Dirs;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04001457
1458# System Objects
1459my %SystemObjects;
1460my %DefaultLibPaths;
Andrey Ponomarenko9927e332012-10-19 10:50:48 +04001461my %DyLib_DefaultPath;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04001462
1463# System Headers
1464my %SystemHeaders;
1465my %DefaultCppPaths;
1466my %DefaultGccPaths;
1467my %DefaultIncPaths;
1468my %DefaultCppHeader;
1469my %DefaultGccHeader;
1470my %UserIncPath;
1471
1472# Merging
1473my %CompleteSignature;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04001474my $Version;
1475my %AddedInt;
1476my %RemovedInt;
1477my %AddedInt_Virt;
1478my %RemovedInt_Virt;
1479my %VirtualReplacement;
1480my %ChangedTypedef;
1481my %CompatRules;
1482my %IncompleteRules;
1483my %UnknownRules;
Andrey Ponomarenko16934472012-03-29 15:37:04 +04001484my %VTableChanged_M;
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04001485my %ExtendedSymbols;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04001486my %ReturnedClass;
1487my %ParamClass;
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04001488my %SourceAlternative;
1489my %SourceAlternative_B;
1490my %SourceReplacement;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04001491
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +04001492# Calling Conventions
1493my %UseConv_Real = (
1494 "1"=>0,
1495 "2"=>0 );
1496
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04001497# OS Compliance
1498my %TargetLibs;
1499my %TargetHeaders;
1500
1501# OS Specifics
1502my $OStarget = $OSgroup;
1503my %TargetTools;
1504
1505# Compliance Report
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04001506my %Type_MaxSeverity;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04001507
1508# Recursion locks
1509my @RecurLib;
1510my @RecurSymlink;
1511my @RecurTypes;
1512my @RecurInclude;
1513my @RecurConstant;
1514
1515# System
1516my %SystemPaths;
1517my %DefaultBinPaths;
1518my $GCC_PATH;
1519
1520# Symbols versioning
1521my %SymVer = (
1522 "1"=>{},
1523 "2"=>{} );
1524
1525# Problem descriptions
1526my %CompatProblems;
1527my %ProblemsWithConstants;
1528my %ImplProblems;
1529my %TotalAffected;
1530
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04001531# Reports
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04001532my $ContentID = 1;
1533my $ContentSpanStart = "<span class=\"section\" onclick=\"javascript:showContent(this, 'CONTENT_ID')\">\n";
1534my $ContentSpanStart_Affected = "<span class=\"section_affected\" onclick=\"javascript:showContent(this, 'CONTENT_ID')\">\n";
1535my $ContentSpanStart_Info = "<span class=\"section_info\" onclick=\"javascript:showContent(this, 'CONTENT_ID')\">\n";
1536my $ContentSpanEnd = "</span>\n";
1537my $ContentDivStart = "<div id=\"CONTENT_ID\" style=\"display:none;\">\n";
1538my $ContentDivEnd = "</div>\n";
1539my $Content_Counter = 0;
1540
Andrey Ponomarenko5c09ef32012-06-14 18:17:33 +04001541# XML Dump
1542my $TAG_ID = 0;
1543my $INDENT = " ";
1544
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04001545# Modes
1546my $JoinReport = 1;
1547my $DoubleReport = 0;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04001548
1549sub get_Modules()
1550{
1551 my $TOOL_DIR = get_dirname($0);
1552 if(not $TOOL_DIR)
1553 { # patch for MS Windows
1554 $TOOL_DIR = ".";
1555 }
1556 my @SEARCH_DIRS = (
1557 # tool's directory
1558 abs_path($TOOL_DIR),
1559 # relative path to modules
1560 abs_path($TOOL_DIR)."/../share/abi-compliance-checker",
1561 # system directory
1562 "ACC_MODULES_INSTALL_PATH"
1563 );
1564 foreach my $DIR (@SEARCH_DIRS)
1565 {
1566 if(not is_abs($DIR))
1567 { # relative path
1568 $DIR = abs_path($TOOL_DIR)."/".$DIR;
1569 }
1570 if(-d $DIR."/modules") {
1571 return $DIR."/modules";
1572 }
1573 }
1574 exitStatus("Module_Error", "can't find modules");
1575}
1576
Andrey Ponomarenko01117f12012-06-26 12:23:02 +04001577my %LoadedModules = ();
1578
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04001579sub loadModule($)
1580{
1581 my $Name = $_[0];
Andrey Ponomarenko01117f12012-06-26 12:23:02 +04001582 if(defined $LoadedModules{$Name}) {
1583 return;
1584 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04001585 my $Path = $MODULES_DIR."/Internals/$Name.pm";
1586 if(not -f $Path) {
1587 exitStatus("Module_Error", "can't access \'$Path\'");
1588 }
1589 require $Path;
Andrey Ponomarenko01117f12012-06-26 12:23:02 +04001590 $LoadedModules{$Name} = 1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04001591}
1592
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04001593sub showPos($)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04001594{
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04001595 my $Number = $_[0];
1596 if(not $Number) {
1597 $Number = 1;
1598 }
1599 else {
1600 $Number = int($Number)+1;
1601 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04001602 if($Number>3) {
1603 return $Number."th";
1604 }
1605 elsif($Number==1) {
1606 return "1st";
1607 }
1608 elsif($Number==2) {
1609 return "2nd";
1610 }
1611 elsif($Number==3) {
1612 return "3rd";
1613 }
1614 else {
1615 return $Number;
1616 }
1617}
1618
1619sub search_Tools($)
1620{
1621 my $Name = $_[0];
1622 return "" if(not $Name);
1623 if(my @Paths = keys(%TargetTools))
1624 {
1625 foreach my $Path (@Paths)
1626 {
1627 if(-f joinPath($Path, $Name)) {
1628 return joinPath($Path, $Name);
1629 }
1630 if($CrossPrefix)
1631 { # user-defined prefix (arm-none-symbianelf, ...)
1632 my $Candidate = joinPath($Path, $CrossPrefix."-".$Name);
1633 if(-f $Candidate) {
1634 return $Candidate;
1635 }
1636 }
1637 }
1638 }
1639 else {
1640 return "";
1641 }
1642}
1643
1644sub synch_Cmd($)
1645{
1646 my $Name = $_[0];
1647 if(not $GCC_PATH)
1648 { # GCC was not found yet
1649 return "";
1650 }
1651 my $Candidate = $GCC_PATH;
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04001652 if($Candidate=~s/\bgcc(|\.\w+)\Z/$Name$1/) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04001653 return $Candidate;
1654 }
1655 return "";
1656}
1657
1658sub get_CmdPath($)
1659{
1660 my $Name = $_[0];
1661 return "" if(not $Name);
1662 if(defined $Cache{"get_CmdPath"}{$Name}) {
1663 return $Cache{"get_CmdPath"}{$Name};
1664 }
1665 my %BinUtils = map {$_=>1} (
1666 "c++filt",
1667 "objdump",
1668 "readelf"
1669 );
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04001670 if($BinUtils{$Name} and $GCC_PATH)
1671 {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04001672 if(my $Dir = get_dirname($GCC_PATH)) {
1673 $TargetTools{$Dir}=1;
1674 }
1675 }
1676 my $Path = search_Tools($Name);
1677 if(not $Path and $OSgroup eq "windows") {
1678 $Path = search_Tools($Name.".exe");
1679 }
1680 if(not $Path and $BinUtils{$Name})
1681 {
1682 if($CrossPrefix)
1683 { # user-defined prefix
1684 $Path = search_Cmd($CrossPrefix."-".$Name);
1685 }
1686 }
1687 if(not $Path and $BinUtils{$Name})
1688 {
1689 if(my $Candidate = synch_Cmd($Name))
1690 { # synch with GCC
1691 if($Candidate=~/[\/\\]/)
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04001692 { # command path
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04001693 if(-f $Candidate) {
1694 $Path = $Candidate;
1695 }
1696 }
1697 elsif($Candidate = search_Cmd($Candidate))
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04001698 { # command name
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04001699 $Path = $Candidate;
1700 }
1701 }
1702 }
1703 if(not $Path) {
1704 $Path = search_Cmd($Name);
1705 }
1706 if(not $Path and $OSgroup eq "windows")
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04001707 { # search for *.exe file
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04001708 $Path=search_Cmd($Name.".exe");
1709 }
1710 if($Path=~/\s/) {
1711 $Path = "\"".$Path."\"";
1712 }
1713 return ($Cache{"get_CmdPath"}{$Name}=$Path);
1714}
1715
1716sub search_Cmd($)
1717{
1718 my $Name = $_[0];
1719 return "" if(not $Name);
1720 if(defined $Cache{"search_Cmd"}{$Name}) {
1721 return $Cache{"search_Cmd"}{$Name};
1722 }
1723 if(my $DefaultPath = get_CmdPath_Default($Name)) {
1724 return ($Cache{"search_Cmd"}{$Name} = $DefaultPath);
1725 }
1726 foreach my $Path (sort {length($a)<=>length($b)} keys(%{$SystemPaths{"bin"}}))
1727 {
1728 my $CmdPath = joinPath($Path,$Name);
1729 if(-f $CmdPath)
1730 {
1731 if($Name=~/gcc/) {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04001732 next if(not check_gcc($CmdPath, "3"));
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04001733 }
1734 return ($Cache{"search_Cmd"}{$Name} = $CmdPath);
1735 }
1736 }
1737 return ($Cache{"search_Cmd"}{$Name} = "");
1738}
1739
1740sub get_CmdPath_Default($)
1741{ # search in PATH
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04001742 return "" if(not $_[0]);
1743 if(defined $Cache{"get_CmdPath_Default"}{$_[0]}) {
1744 return $Cache{"get_CmdPath_Default"}{$_[0]};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04001745 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04001746 return ($Cache{"get_CmdPath_Default"}{$_[0]} = get_CmdPath_Default_I($_[0]));
1747}
1748
1749sub get_CmdPath_Default_I($)
1750{ # search in PATH
1751 my $Name = $_[0];
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04001752 if($Name=~/find/)
1753 { # special case: search for "find" utility
Andrey Ponomarenkoa01311b2012-06-08 17:20:02 +04001754 if(`find \"$TMP_DIR\" -maxdepth 0 2>\"$TMP_DIR/null\"`) {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04001755 return "find";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04001756 }
1757 }
1758 elsif($Name=~/gcc/) {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04001759 return check_gcc($Name, "3");
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04001760 }
1761 if(check_command($Name)) {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04001762 return $Name;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04001763 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04001764 if($OSgroup eq "windows")
1765 {
Andrey Ponomarenkoa01311b2012-06-08 17:20:02 +04001766 if(`$Name /? 2>\"$TMP_DIR/null\"`) {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04001767 return $Name;
1768 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04001769 }
1770 if($Name!~/which/)
1771 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04001772 if(my $WhichCmd = get_CmdPath("which"))
1773 {
Andrey Ponomarenkoa01311b2012-06-08 17:20:02 +04001774 if(`$WhichCmd $Name 2>\"$TMP_DIR/null\"`) {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04001775 return $Name;
1776 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04001777 }
1778 }
1779 foreach my $Path (sort {length($a)<=>length($b)} keys(%DefaultBinPaths))
1780 {
1781 if(-f $Path."/".$Name) {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04001782 return joinPath($Path,$Name);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04001783 }
1784 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04001785 return "";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04001786}
1787
1788sub clean_path($)
1789{
1790 my $Path = $_[0];
1791 $Path=~s/[\/\\]+\Z//g;
1792 return $Path;
1793}
1794
1795sub classifyPath($)
1796{
1797 my $Path = $_[0];
1798 if($Path=~/[\*\[]/)
1799 { # wildcard
1800 $Path=~s/\*/.*/g;
1801 $Path=~s/\\/\\\\/g;
1802 return ($Path, "Pattern");
1803 }
1804 elsif($Path=~/[\/\\]/)
1805 { # directory or relative path
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04001806 $Path=~s/[\/\\]+\Z//g;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04001807 return (path_format($Path, $OSgroup), "Path");
1808 }
1809 else {
1810 return ($Path, "Name");
1811 }
1812}
1813
1814sub readDescriptor($$)
1815{
1816 my ($LibVersion, $Content) = @_;
1817 return if(not $LibVersion);
1818 my $DName = $DumpAPI?"descriptor":"descriptor \"d$LibVersion\"";
1819 if(not $Content) {
1820 exitStatus("Error", "$DName is empty");
1821 }
1822 if($Content!~/\</) {
Andrey Ponomarenko5c09ef32012-06-14 18:17:33 +04001823 exitStatus("Error", "incorrect descriptor (see -d1 option)");
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04001824 }
1825 $Content=~s/\/\*(.|\n)+?\*\///g;
1826 $Content=~s/<\!--(.|\n)+?-->//g;
1827 $Descriptor{$LibVersion}{"Version"} = parseTag(\$Content, "version");
1828 if($TargetVersion{$LibVersion}) {
1829 $Descriptor{$LibVersion}{"Version"} = $TargetVersion{$LibVersion};
1830 }
1831 if(not $Descriptor{$LibVersion}{"Version"}) {
1832 exitStatus("Error", "version in the $DName is not specified (<version> section)");
1833 }
1834 if($Content=~/{RELPATH}/)
1835 {
1836 if(my $RelDir = $RelativeDirectory{$LibVersion}) {
1837 $Content =~ s/{RELPATH}/$RelDir/g;
1838 }
1839 else
1840 {
1841 my $NeedRelpath = $DumpAPI?"-relpath":"-relpath$LibVersion";
1842 exitStatus("Error", "you have not specified $NeedRelpath option, but the $DName contains {RELPATH} macro");
1843 }
1844 }
1845
1846 if(not $CheckObjectsOnly_Opt)
1847 {
1848 my $DHeaders = parseTag(\$Content, "headers");
1849 if(not $DHeaders) {
1850 exitStatus("Error", "header files in the $DName are not specified (<headers> section)");
1851 }
1852 elsif(lc($DHeaders) ne "none")
1853 { # append the descriptor headers list
1854 if($Descriptor{$LibVersion}{"Headers"})
1855 { # multiple descriptors
1856 $Descriptor{$LibVersion}{"Headers"} .= "\n".$DHeaders;
1857 }
1858 else {
1859 $Descriptor{$LibVersion}{"Headers"} = $DHeaders;
1860 }
1861 foreach my $Path (split(/\s*\n\s*/, $DHeaders))
1862 {
1863 if(not -e $Path) {
1864 exitStatus("Access_Error", "can't access \'$Path\'");
1865 }
1866 }
1867 }
1868 }
1869 if(not $CheckHeadersOnly_Opt)
1870 {
1871 my $DObjects = parseTag(\$Content, "libs");
1872 if(not $DObjects) {
1873 exitStatus("Error", "$SLIB_TYPE libraries in the $DName are not specified (<libs> section)");
1874 }
1875 elsif(lc($DObjects) ne "none")
1876 { # append the descriptor libraries list
1877 if($Descriptor{$LibVersion}{"Libs"})
1878 { # multiple descriptors
1879 $Descriptor{$LibVersion}{"Libs"} .= "\n".$DObjects;
1880 }
1881 else {
1882 $Descriptor{$LibVersion}{"Libs"} .= $DObjects;
1883 }
1884 foreach my $Path (split(/\s*\n\s*/, $DObjects))
1885 {
1886 if(not -e $Path) {
1887 exitStatus("Access_Error", "can't access \'$Path\'");
1888 }
1889 }
1890 }
1891 }
1892 foreach my $Path (split(/\s*\n\s*/, parseTag(\$Content, "search_headers")))
1893 {
1894 $Path = clean_path($Path);
1895 if(not -d $Path) {
1896 exitStatus("Access_Error", "can't access directory \'$Path\'");
1897 }
1898 $Path = path_format($Path, $OSgroup);
1899 $SystemPaths{"include"}{$Path}=1;
1900 }
1901 foreach my $Path (split(/\s*\n\s*/, parseTag(\$Content, "search_libs")))
1902 {
1903 $Path = clean_path($Path);
1904 if(not -d $Path) {
1905 exitStatus("Access_Error", "can't access directory \'$Path\'");
1906 }
1907 $Path = path_format($Path, $OSgroup);
1908 $SystemPaths{"lib"}{$Path}=1;
1909 }
1910 foreach my $Path (split(/\s*\n\s*/, parseTag(\$Content, "tools")))
1911 {
1912 $Path=clean_path($Path);
1913 if(not -d $Path) {
1914 exitStatus("Access_Error", "can't access directory \'$Path\'");
1915 }
1916 $Path = path_format($Path, $OSgroup);
1917 $SystemPaths{"bin"}{$Path}=1;
1918 $TargetTools{$Path}=1;
1919 }
1920 if(my $Prefix = parseTag(\$Content, "cross_prefix")) {
1921 $CrossPrefix = $Prefix;
1922 }
1923 foreach my $Path (split(/\s*\n\s*/, parseTag(\$Content, "include_paths")))
1924 {
1925 $Path=clean_path($Path);
1926 if(not -d $Path) {
1927 exitStatus("Access_Error", "can't access directory \'$Path\'");
1928 }
1929 $Path = path_format($Path, $OSgroup);
1930 $Descriptor{$LibVersion}{"IncludePaths"}{$Path} = 1;
1931 }
1932 foreach my $Path (split(/\s*\n\s*/, parseTag(\$Content, "add_include_paths")))
1933 {
1934 $Path=clean_path($Path);
1935 if(not -d $Path) {
1936 exitStatus("Access_Error", "can't access directory \'$Path\'");
1937 }
1938 $Path = path_format($Path, $OSgroup);
1939 $Descriptor{$LibVersion}{"AddIncludePaths"}{$Path} = 1;
1940 }
1941 foreach my $Path (split(/\s*\n\s*/, parseTag(\$Content, "skip_include_paths")))
1942 {
1943 # skip some auto-generated include paths
1944 $Skip_Include_Paths{$LibVersion}{path_format($Path)}=1;
1945 }
1946 foreach my $Path (split(/\s*\n\s*/, parseTag(\$Content, "skip_including")))
1947 {
1948 # skip direct including of some headers
1949 my ($CPath, $Type) = classifyPath($Path);
1950 $SkipHeaders{$LibVersion}{$Type}{$CPath} = 2;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04001951 }
1952 $Descriptor{$LibVersion}{"GccOptions"} = parseTag(\$Content, "gcc_options");
1953 foreach my $Option (split(/\s*\n\s*/, $Descriptor{$LibVersion}{"GccOptions"})) {
1954 $CompilerOptions{$LibVersion} .= " ".$Option;
1955 }
1956 $Descriptor{$LibVersion}{"SkipHeaders"} = parseTag(\$Content, "skip_headers");
1957 foreach my $Path (split(/\s*\n\s*/, $Descriptor{$LibVersion}{"SkipHeaders"}))
1958 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04001959 $SkipHeadersList{$LibVersion}{$Path} = 1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04001960 my ($CPath, $Type) = classifyPath($Path);
1961 $SkipHeaders{$LibVersion}{$Type}{$CPath} = 1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04001962 }
1963 $Descriptor{$LibVersion}{"SkipLibs"} = parseTag(\$Content, "skip_libs");
1964 foreach my $Path (split(/\s*\n\s*/, $Descriptor{$LibVersion}{"SkipLibs"}))
1965 {
1966 my ($CPath, $Type) = classifyPath($Path);
1967 $SkipLibs{$LibVersion}{$Type}{$CPath} = 1;
1968 }
1969 if(my $DDefines = parseTag(\$Content, "defines"))
1970 {
1971 if($Descriptor{$LibVersion}{"Defines"})
1972 { # multiple descriptors
1973 $Descriptor{$LibVersion}{"Defines"} .= "\n".$DDefines;
1974 }
1975 else {
1976 $Descriptor{$LibVersion}{"Defines"} = $DDefines;
1977 }
1978 }
1979 foreach my $Order (split(/\s*\n\s*/, parseTag(\$Content, "include_order")))
1980 {
1981 if($Order=~/\A(.+):(.+)\Z/) {
1982 $Include_Order{$LibVersion}{$1} = $2;
1983 }
1984 }
1985 foreach my $Type_Name (split(/\s*\n\s*/, parseTag(\$Content, "opaque_types")),
1986 split(/\s*\n\s*/, parseTag(\$Content, "skip_types")))
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04001987 { # opaque_types renamed to skip_types (1.23.4)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04001988 $SkipTypes{$LibVersion}{$Type_Name} = 1;
1989 }
1990 foreach my $Symbol (split(/\s*\n\s*/, parseTag(\$Content, "skip_interfaces")),
1991 split(/\s*\n\s*/, parseTag(\$Content, "skip_symbols")))
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04001992 { # skip_interfaces renamed to skip_symbols (1.22.1)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04001993 $SkipSymbols{$LibVersion}{$Symbol} = 1;
1994 }
1995 foreach my $NameSpace (split(/\s*\n\s*/, parseTag(\$Content, "skip_namespaces"))) {
1996 $SkipNameSpaces{$LibVersion}{$NameSpace} = 1;
1997 }
Andrey Ponomarenkoa01311b2012-06-08 17:20:02 +04001998 foreach my $NameSpace (split(/\s*\n\s*/, parseTag(\$Content, "add_namespaces"))) {
1999 $AddNameSpaces{$LibVersion}{$NameSpace} = 1;
2000 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002001 foreach my $Constant (split(/\s*\n\s*/, parseTag(\$Content, "skip_constants"))) {
2002 $SkipConstants{$LibVersion}{$Constant} = 1;
2003 }
2004 if(my $DIncPreamble = parseTag(\$Content, "include_preamble"))
2005 {
2006 if($Descriptor{$LibVersion}{"IncludePreamble"})
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04002007 { # multiple descriptors
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002008 $Descriptor{$LibVersion}{"IncludePreamble"} .= "\n".$DIncPreamble;
2009 }
2010 else {
2011 $Descriptor{$LibVersion}{"IncludePreamble"} = $DIncPreamble;
2012 }
2013 }
2014}
2015
Andrey Ponomarenko01117f12012-06-26 12:23:02 +04002016sub parseTag(@)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002017{
Andrey Ponomarenko01117f12012-06-26 12:23:02 +04002018 my $CodeRef = shift(@_);
2019 my $Tag = shift(@_);
2020 if(not $Tag or not $CodeRef) {
2021 return undef;
2022 }
2023 my $Sp = 0;
2024 if(@_) {
2025 $Sp = shift(@_);
2026 }
2027 my $Start = index(${$CodeRef}, "<$Tag>");
2028 if($Start!=-1)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002029 {
Andrey Ponomarenko01117f12012-06-26 12:23:02 +04002030 my $End = index(${$CodeRef}, "</$Tag>");
2031 if($End!=-1)
2032 {
2033 my $TS = length($Tag)+3;
2034 my $Content = substr(${$CodeRef}, $Start, $End-$Start+$TS, "");
2035 substr($Content, 0, $TS-1, ""); # cut start tag
2036 substr($Content, -$TS, $TS, ""); # cut end tag
2037 if(not $Sp)
2038 {
2039 $Content=~s/\A\s+//g;
2040 $Content=~s/\s+\Z//g;
2041 }
2042 if(substr($Content, 0, 1) ne "<") {
2043 $Content = xmlSpecChars_R($Content);
2044 }
2045 return $Content;
2046 }
2047 }
2048 return undef;
2049}
2050
2051sub parseTag_E($$$)
2052{
2053 my ($CodeRef, $Tag, $Info) = @_;
2054 if(not $Tag or not $CodeRef
2055 or not $Info) {
2056 return undef;
2057 }
2058 if(${$CodeRef}=~s/\<\Q$Tag\E(\s+([^<>]+)|)\>((.|\n)*?)\<\/\Q$Tag\E\>//)
2059 {
2060 my ($Ext, $Content) = ($2, $3);
2061 $Content=~s/\A\s+//g;
2062 $Content=~s/\s+\Z//g;
2063 if($Ext)
2064 {
2065 while($Ext=~s/(\w+)\=\"([^\"]*)\"//)
2066 {
2067 my ($K, $V) = ($1, $2);
2068 $Info->{$K} = xmlSpecChars_R($V);
2069 }
2070 }
2071 if(substr($Content, 0, 1) ne "<") {
2072 $Content = xmlSpecChars_R($Content);
2073 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002074 return $Content;
2075 }
Andrey Ponomarenko01117f12012-06-26 12:23:02 +04002076 return undef;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002077}
2078
Andrey Ponomarenko35c44fd2012-06-18 17:50:25 +04002079sub addTag(@)
Andrey Ponomarenko5c09ef32012-06-14 18:17:33 +04002080{
Andrey Ponomarenko35c44fd2012-06-18 17:50:25 +04002081 my $Tag = shift(@_);
2082 my $Val = shift(@_);
2083 my @Ext = @_;
2084 my $Content = openTag($Tag, @Ext);
2085 chomp($Content);
Andrey Ponomarenko5c09ef32012-06-14 18:17:33 +04002086 $Content .= xmlSpecChars($Val);
2087 $Content .= "</$Tag>\n";
Andrey Ponomarenko35c44fd2012-06-18 17:50:25 +04002088 $TAG_ID-=1;
Andrey Ponomarenko5c09ef32012-06-14 18:17:33 +04002089
2090 return $Content;
2091}
2092
Andrey Ponomarenko35c44fd2012-06-18 17:50:25 +04002093sub openTag(@)
Andrey Ponomarenko5c09ef32012-06-14 18:17:33 +04002094{
2095 my $Tag = shift(@_);
2096 my @Ext = @_;
2097 my $Content = "";
2098 foreach (1 .. $TAG_ID) {
2099 $Content .= $INDENT;
2100 }
2101 $TAG_ID+=1;
Andrey Ponomarenko35c44fd2012-06-18 17:50:25 +04002102 if(@Ext)
Andrey Ponomarenko5c09ef32012-06-14 18:17:33 +04002103 {
Andrey Ponomarenko35c44fd2012-06-18 17:50:25 +04002104 $Content .= "<".$Tag;
2105 my $P = 0;
2106 while($P<=$#Ext-1)
2107 {
2108 $Content .= " ".$Ext[$P];
2109 $Content .= "=\"".xmlSpecChars($Ext[$P+1])."\"";
2110 $P+=2;
2111 }
2112 $Content .= ">\n";
Andrey Ponomarenko5c09ef32012-06-14 18:17:33 +04002113 }
Andrey Ponomarenko35c44fd2012-06-18 17:50:25 +04002114 else {
2115 $Content .= "<".$Tag.">\n";
2116 }
Andrey Ponomarenko5c09ef32012-06-14 18:17:33 +04002117 return $Content;
2118}
2119
2120sub closeTag($)
2121{
2122 my $Tag = $_[0];
2123 my $Content = "";
2124 $TAG_ID-=1;
2125 foreach (1 .. $TAG_ID) {
2126 $Content .= $INDENT;
2127 }
2128 $Content .= "</".$Tag.">\n";
2129 return $Content;
2130}
2131
2132sub checkTags()
2133{
2134 if($TAG_ID!=0) {
2135 printMsg("WARNING", "the number of opened tags is not equal to number of closed tags");
2136 }
2137}
2138
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002139sub getInfo($)
2140{
Andrey Ponomarenko85043792012-05-14 16:48:07 +04002141 my $DumpPath = $_[0];
2142 return if(not $DumpPath or not -f $DumpPath);
2143
2144 readTUDump($DumpPath);
2145
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002146 # processing info
2147 setTemplateParams_All();
2148 getTypeInfo_All();
2149 simplifyNames();
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002150 getVarInfo_All();
Andrey Ponomarenko01117f12012-06-26 12:23:02 +04002151 getSymbolInfo_All();
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002152
Andrey Ponomarenko85043792012-05-14 16:48:07 +04002153 # clean memory
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002154 %LibInfo = ();
2155 %TemplateInstance = ();
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002156 %MangledNames = ();
Andrey Ponomarenko85043792012-05-14 16:48:07 +04002157 %TemplateDecl = ();
2158 %StdCxxTypedef = ();
2159 %MissedTypedef = ();
2160 %Typedef_Tr = ();
2161 %Typedef_Eq = ();
2162
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04002163 # clean cache
2164 delete($Cache{"getTypeAttr"});
2165 delete($Cache{"getTypeDeclId"});
2166
2167 # remove unused types
2168 if($BinaryOnly and not $ExtendedCheck)
2169 { # --binary
2170 removeUnused($Version, "All");
2171 }
2172 else {
2173 removeUnused($Version, "Derived");
2174 }
2175
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002176 if($Debug) {
2177 # debugMangling($Version);
2178 }
2179}
2180
Andrey Ponomarenko85043792012-05-14 16:48:07 +04002181sub readTUDump($)
2182{
2183 my $DumpPath = $_[0];
2184
2185 open(TU_DUMP, $DumpPath);
2186 local $/ = undef;
2187 my $Content = <TU_DUMP>;
2188 close(TU_DUMP);
2189
2190 unlink($DumpPath);
2191
2192 $Content=~s/\n[ ]+/ /g;
2193 my @Lines = split("\n", $Content);
2194
2195 # clean memory
2196 undef $Content;
2197
2198 $MAX_ID = $#Lines+1;
2199
2200 foreach (0 .. $#Lines)
2201 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04002202 if($Lines[$_]=~/\A\@(\d+)[ ]+([a-z_]+)[ ]+(.+)\Z/i)
Andrey Ponomarenko85043792012-05-14 16:48:07 +04002203 { # get a number and attributes of a node
2204 next if(not $NodeType{$2});
2205 $LibInfo{$Version}{"info_type"}{$1}=$2;
2206 $LibInfo{$Version}{"info"}{$1}=$3;
2207 }
2208
2209 # clean memory
2210 delete($Lines[$_]);
2211 }
2212
2213 # clean memory
2214 undef @Lines;
2215}
2216
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002217sub simplifyNames()
2218{
2219 foreach my $Base (keys(%{$Typedef_Tr{$Version}}))
2220 {
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +04002221 if($Typedef_Eq{$Version}{$Base}) {
2222 next;
2223 }
2224 my @Translations = sort keys(%{$Typedef_Tr{$Version}{$Base}});
2225 if($#Translations==0)
2226 {
2227 if(length($Translations[0])<=length($Base)) {
2228 $Typedef_Eq{$Version}{$Base} = $Translations[0];
2229 }
2230 }
2231 else
2232 { # select most appropriate
2233 foreach my $Tr (@Translations)
2234 {
2235 if($Base=~/\A\Q$Tr\E/)
2236 {
2237 $Typedef_Eq{$Version}{$Base} = $Tr;
2238 last;
2239 }
2240 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002241 }
2242 }
Andrey Ponomarenkob8d203d2012-05-25 18:11:07 +04002243 foreach my $TypeId (keys(%{$TypeInfo{$Version}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002244 {
Andrey Ponomarenkob8d203d2012-05-25 18:11:07 +04002245 my $TypeName = $TypeInfo{$Version}{$TypeId}{"Name"};
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04002246 if(not $TypeName) {
2247 next;
2248 }
2249 next if(index($TypeName,"<")==-1);# template instances only
2250 if($TypeName=~/>(::\w+)+\Z/)
2251 { # skip unused types
2252 next;
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +04002253 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04002254 foreach my $Base (sort {length($b)<=>length($a)}
2255 sort {$b cmp $a} keys(%{$Typedef_Eq{$Version}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002256 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04002257 next if(not $Base);
2258 next if(index($TypeName,$Base)==-1);
2259 next if(length($TypeName) - length($Base) <= 3);
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +04002260 if(my $Typedef = $Typedef_Eq{$Version}{$Base})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002261 {
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +04002262 $TypeName=~s/(\<|\,)\Q$Base\E(\W|\Z)/$1$Typedef$2/g;
2263 $TypeName=~s/(\<|\,)\Q$Base\E(\w|\Z)/$1$Typedef $2/g;
2264 if(defined $TypeInfo{$Version}{$TypeId}{"TParam"})
Andrey Ponomarenko85043792012-05-14 16:48:07 +04002265 {
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +04002266 foreach my $TPos (keys(%{$TypeInfo{$Version}{$TypeId}{"TParam"}}))
2267 {
2268 if(my $TPName = $TypeInfo{$Version}{$TypeId}{"TParam"}{$TPos}{"name"})
2269 {
2270 $TPName=~s/\A\Q$Base\E(\W|\Z)/$Typedef$1/g;
2271 $TPName=~s/\A\Q$Base\E(\w|\Z)/$Typedef $1/g;
Andrey Ponomarenko9927e332012-10-19 10:50:48 +04002272 $TypeInfo{$Version}{$TypeId}{"TParam"}{$TPos}{"name"} = formatName($TPName, "T");
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +04002273 }
2274 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +04002275 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002276 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002277 }
Andrey Ponomarenko9927e332012-10-19 10:50:48 +04002278 $TypeName = formatName($TypeName, "T");
Andrey Ponomarenkob8d203d2012-05-25 18:11:07 +04002279 $TypeInfo{$Version}{$TypeId}{"Name"} = $TypeName;
2280 $TName_Tid{$Version}{$TypeName} = $TypeId;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002281 }
2282}
2283
2284sub setTemplateParams_All()
2285{
2286 foreach (keys(%{$LibInfo{$Version}{"info"}}))
2287 {
2288 if($LibInfo{$Version}{"info_type"}{$_} eq "template_decl") {
2289 setTemplateParams($_);
2290 }
2291 }
2292}
2293
2294sub setTemplateParams($)
2295{
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04002296 if(my $Info = $LibInfo{$Version}{"info"}{$_[0]})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002297 {
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04002298 if($Info=~/(inst|spcs)[ ]*:[ ]*@(\d+) /)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002299 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04002300 my $TmplInst_Id = $2;
2301 setTemplateInstParams($TmplInst_Id);
2302 while($TmplInst_Id = getNextElem($TmplInst_Id)) {
2303 setTemplateInstParams($TmplInst_Id);
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04002304 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002305 }
2306 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04002307 if(my $TypeId = getTreeAttr_Type($_[0]))
Andrey Ponomarenko85043792012-05-14 16:48:07 +04002308 {
2309 if(my $IType = $LibInfo{$Version}{"info_type"}{$TypeId})
2310 {
2311 if($IType eq "record_type") {
2312 $TemplateDecl{$Version}{$TypeId}=1;
2313 }
2314 }
2315 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002316}
2317
2318sub setTemplateInstParams($)
2319{
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04002320 if(my $Info = $LibInfo{$Version}{"info"}{$_[0]})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002321 {
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04002322 my ($Params_InfoId, $ElemId) = ();
2323 if($Info=~/purp[ ]*:[ ]*@(\d+) /) {
2324 $Params_InfoId = $1;
2325 }
2326 if($Info=~/valu[ ]*:[ ]*@(\d+) /) {
2327 $ElemId = $1;
2328 }
2329 if($Params_InfoId and $ElemId)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002330 {
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04002331 my $Params_Info = $LibInfo{$Version}{"info"}{$Params_InfoId};
2332 while($Params_Info=~s/ (\d+)[ ]*:[ ]*\@(\d+) / /)
2333 {
2334 my ($PPos, $PTypeId) = ($1, $2);
2335 if(my $PType = $LibInfo{$Version}{"info_type"}{$PTypeId})
2336 {
Andrey Ponomarenko85043792012-05-14 16:48:07 +04002337 if($PType eq "template_type_parm")
2338 {
2339 $TemplateDecl{$Version}{$ElemId}=1;
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04002340 return;
2341 }
2342 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +04002343 if($LibInfo{$Version}{"info_type"}{$ElemId} eq "function_decl")
2344 { # functions
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04002345 $TemplateInstance{$Version}{"Func"}{$ElemId}{$PPos} = $PTypeId;
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04002346 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +04002347 else
2348 { # types
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04002349 $TemplateInstance{$Version}{"Type"}{$ElemId}{$PPos} = $PTypeId;
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04002350 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002351 }
2352 }
2353 }
2354}
2355
2356sub getTypeDeclId($)
2357{
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04002358 if($_[0])
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04002359 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04002360 if(defined $Cache{"getTypeDeclId"}{$Version}{$_[0]}) {
2361 return $Cache{"getTypeDeclId"}{$Version}{$_[0]};
2362 }
2363 if(my $Info = $LibInfo{$Version}{"info"}{$_[0]})
2364 {
2365 if($Info=~/name[ ]*:[ ]*@(\d+)/) {
2366 return ($Cache{"getTypeDeclId"}{$Version}{$_[0]} = $1);
2367 }
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04002368 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002369 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04002370 return ($Cache{"getTypeDeclId"}{$Version}{$_[0]} = 0);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002371}
2372
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002373sub getTypeInfo_All()
2374{
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04002375 if(not check_gcc($GCC_PATH, "4.5"))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002376 { # support for GCC < 4.5
2377 # missed typedefs: QStyle::State is typedef to QFlags<QStyle::StateFlag>
2378 # but QStyleOption.state is of type QFlags<QStyle::StateFlag> in the TU dump
2379 # FIXME: check GCC versions
2380 addMissedTypes_Pre();
2381 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04002382
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002383 foreach (sort {int($a)<=>int($b)} keys(%{$LibInfo{$Version}{"info"}}))
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04002384 { # forward order only
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002385 my $IType = $LibInfo{$Version}{"info_type"}{$_};
2386 if($IType=~/_type\Z/ and $IType ne "function_type"
2387 and $IType ne "method_type") {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04002388 getTypeInfo("$_");
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002389 }
2390 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04002391
2392 # add "..." type
Andrey Ponomarenko01117f12012-06-26 12:23:02 +04002393 $TypeInfo{$Version}{"-1"} = {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04002394 "Name" => "...",
2395 "Type" => "Intrinsic",
Andrey Ponomarenko01117f12012-06-26 12:23:02 +04002396 "Tid" => "-1"
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04002397 };
Andrey Ponomarenko01117f12012-06-26 12:23:02 +04002398 $TName_Tid{$Version}{"..."} = "-1";
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04002399
2400 if(not check_gcc($GCC_PATH, "4.5"))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002401 { # support for GCC < 4.5
2402 addMissedTypes_Post();
2403 }
2404}
2405
2406sub addMissedTypes_Pre()
2407{
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04002408 my %MissedTypes = ();
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002409 foreach my $MissedTDid (sort {int($a)<=>int($b)} keys(%{$LibInfo{$Version}{"info"}}))
2410 { # detecting missed typedefs
2411 if($LibInfo{$Version}{"info_type"}{$MissedTDid} eq "type_decl")
2412 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04002413 my $TypeId = getTreeAttr_Type($MissedTDid);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002414 next if(not $TypeId);
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04002415 my $TypeType = getTypeType($TypeId);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002416 if($TypeType eq "Unknown")
2417 { # template_type_parm
2418 next;
2419 }
2420 my $TypeDeclId = getTypeDeclId($TypeId);
2421 next if($TypeDeclId eq $MissedTDid);#or not $TypeDeclId
2422 my $TypedefName = getNameByInfo($MissedTDid);
2423 next if(not $TypedefName);
2424 next if($TypedefName eq "__float80");
2425 next if(isAnon($TypedefName));
2426 if(not $TypeDeclId
2427 or getNameByInfo($TypeDeclId) ne $TypedefName) {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04002428 $MissedTypes{$Version}{$TypeId}{$MissedTDid} = 1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002429 }
2430 }
2431 }
Andrey Ponomarenkob8d203d2012-05-25 18:11:07 +04002432 my %AddTypes = ();
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04002433 foreach my $Tid (keys(%{$MissedTypes{$Version}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002434 { # add missed typedefs
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04002435 my @Missed = keys(%{$MissedTypes{$Version}{$Tid}});
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002436 if(not @Missed or $#Missed>=1) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002437 next;
2438 }
2439 my $MissedTDid = $Missed[0];
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002440 my ($TypedefName, $TypedefNS) = getTrivialName($MissedTDid, $Tid);
Andrey Ponomarenkob8d203d2012-05-25 18:11:07 +04002441 if(not $TypedefName) {
2442 next;
2443 }
2444 $MAX_ID++;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002445 my %MissedInfo = ( # typedef info
2446 "Name" => $TypedefName,
2447 "NameSpace" => $TypedefNS,
2448 "BaseType" => {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002449 "Tid" => $Tid
2450 },
2451 "Type" => "Typedef",
Andrey Ponomarenkob8d203d2012-05-25 18:11:07 +04002452 "Tid" => "$MAX_ID" );
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002453 my ($H, $L) = getLocation($MissedTDid);
2454 $MissedInfo{"Header"} = $H;
2455 $MissedInfo{"Line"} = $L;
Andrey Ponomarenkob8d203d2012-05-25 18:11:07 +04002456 if($TypedefName=~/\*|\&|\s/)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002457 { # other types
2458 next;
2459 }
Andrey Ponomarenkob8d203d2012-05-25 18:11:07 +04002460 if($TypedefName=~/>(::\w+)+\Z/)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002461 { # QFlags<Qt::DropAction>::enum_type
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002462 next;
2463 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04002464 if(getTypeType($Tid)=~/\A(Intrinsic|Union|Struct|Enum|Class)\Z/)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002465 { # double-check for the name of typedef
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04002466 my ($TName, $TNS) = getTrivialName(getTypeDeclId($Tid), $Tid); # base type info
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002467 next if(not $TName);
Andrey Ponomarenkob8d203d2012-05-25 18:11:07 +04002468 if(length($TypedefName)>=length($TName))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002469 { # too long typedef
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002470 next;
2471 }
Andrey Ponomarenkob8d203d2012-05-25 18:11:07 +04002472 if($TName=~/\A\Q$TypedefName\E</) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002473 next;
2474 }
Andrey Ponomarenkob8d203d2012-05-25 18:11:07 +04002475 if($TypedefName=~/\A\Q$TName\E/)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002476 { # QDateTimeEdit::Section and QDateTimeEdit::Sections::enum_type
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002477 next;
2478 }
Andrey Ponomarenkob8d203d2012-05-25 18:11:07 +04002479 if(get_depth($TypedefName)==0 and get_depth($TName)!=0)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002480 { # std::_Vector_base and std::vector::_Base
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002481 next;
2482 }
2483 }
Andrey Ponomarenkob8d203d2012-05-25 18:11:07 +04002484
2485 $AddTypes{$MissedInfo{"Tid"}} = \%MissedInfo;
2486
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002487 # register typedef
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002488 $MissedTypedef{$Version}{$Tid}{"Tid"} = $MissedInfo{"Tid"};
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04002489 $MissedTypedef{$Version}{$Tid}{"TDid"} = $MissedTDid;
Andrey Ponomarenkob8d203d2012-05-25 18:11:07 +04002490 $TName_Tid{$Version}{$TypedefName} = $MissedInfo{"Tid"};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002491 }
Andrey Ponomarenkob8d203d2012-05-25 18:11:07 +04002492
2493 # add missed & remove other
2494 $TypeInfo{$Version} = \%AddTypes;
2495 delete($Cache{"getTypeAttr"}{$Version});
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002496}
2497
2498sub addMissedTypes_Post()
2499{
2500 foreach my $BaseId (keys(%{$MissedTypedef{$Version}}))
2501 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04002502 if(my $Tid = $MissedTypedef{$Version}{$BaseId}{"Tid"})
2503 {
2504 $TypeInfo{$Version}{$Tid}{"Size"} = $TypeInfo{$Version}{$BaseId}{"Size"};
2505 if(my $TName = $TypeInfo{$Version}{$Tid}{"Name"}) {
2506 $Typedef_BaseName{$Version}{$TName} = $TypeInfo{$Version}{$BaseId}{"Name"};
2507 }
2508 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002509 }
2510}
2511
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04002512sub getTypeInfo($)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002513{
Andrey Ponomarenkob8d203d2012-05-25 18:11:07 +04002514 my $TypeId = $_[0];
2515 %{$TypeInfo{$Version}{$TypeId}} = getTypeAttr($TypeId);
2516 my $TName = $TypeInfo{$Version}{$TypeId}{"Name"};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002517 if(not $TName) {
Andrey Ponomarenkob8d203d2012-05-25 18:11:07 +04002518 delete($TypeInfo{$Version}{$TypeId});
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002519 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002520}
2521
2522sub getArraySize($$)
2523{
2524 my ($TypeId, $BaseName) = @_;
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04002525 if(my $Size = getSize($TypeId))
2526 {
2527 my $Elems = $Size/$BYTE_SIZE;
2528 while($BaseName=~s/\s*\[(\d+)\]//) {
2529 $Elems/=$1;
2530 }
2531 if(my $BasicId = $TName_Tid{$Version}{$BaseName})
2532 {
2533 if(my $BasicSize = $TypeInfo{$Version}{$BasicId}{"Size"}) {
2534 $Elems/=$BasicSize;
2535 }
2536 }
2537 return $Elems;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002538 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04002539 return 0;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002540}
2541
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04002542sub getTParams($$)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002543{
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04002544 my ($TypeId, $Kind) = @_;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002545 my @TmplParams = ();
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04002546 my @Positions = sort {int($a)<=>int($b)} keys(%{$TemplateInstance{$Version}{$Kind}{$TypeId}});
2547 foreach my $Pos (@Positions)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002548 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04002549 my $Param_TypeId = $TemplateInstance{$Version}{$Kind}{$TypeId}{$Pos};
2550 my $NodeType = $LibInfo{$Version}{"info_type"}{$Param_TypeId};
2551 if(not $NodeType)
2552 { # typename_type
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002553 return ();
2554 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04002555 if($NodeType eq "tree_vec")
2556 {
2557 if($Pos!=$#Positions)
2558 { # select last vector of parameters ( ns<P1>::type<P2> )
2559 next;
2560 }
2561 }
2562 my @Params = get_TemplateParam($Pos, $Param_TypeId);
2563 foreach my $P (@Params)
2564 {
2565 if($P eq "") {
2566 return ();
2567 }
2568 elsif($P ne "\@skip\@") {
2569 @TmplParams = (@TmplParams, $P);
2570 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002571 }
2572 }
2573 return @TmplParams;
2574}
2575
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04002576sub getTypeAttr($)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002577{
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04002578 my $TypeId = $_[0];
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04002579 my %TypeAttr = ();
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04002580 if(defined $TypeInfo{$Version}{$TypeId}
2581 and $TypeInfo{$Version}{$TypeId}{"Name"})
2582 { # already created
2583 return %{$TypeInfo{$Version}{$TypeId}};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002584 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04002585 elsif($Cache{"getTypeAttr"}{$Version}{$TypeId})
2586 { # incomplete type
2587 return ();
2588 }
2589 $Cache{"getTypeAttr"}{$Version}{$TypeId} = 1;
2590
2591 my $TypeDeclId = getTypeDeclId($TypeId);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002592 $TypeAttr{"Tid"} = $TypeId;
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04002593
2594 if(not $MissedBase{$Version}{$TypeId} and isTypedef($TypeId))
2595 {
2596 if(my $Info = $LibInfo{$Version}{"info"}{$TypeId})
2597 {
2598 if($Info=~/qual[ ]*:/)
2599 {
2600 if(my $NID = ++$MAX_ID)
2601 {
2602 $MissedBase{$Version}{$TypeId}="$NID";
2603 $MissedBase_R{$Version}{$NID}=$TypeId;
2604 $LibInfo{$Version}{"info"}{$NID} = $LibInfo{$Version}{"info"}{$TypeId};
2605 $LibInfo{$Version}{"info_type"}{$NID} = $LibInfo{$Version}{"info_type"}{$TypeId};
2606 }
2607 }
2608 }
2609 $TypeAttr{"Type"} = "Typedef";
2610 }
2611 else {
2612 $TypeAttr{"Type"} = getTypeType($TypeId);
2613 }
2614
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002615 if($TypeAttr{"Type"} eq "Unknown") {
2616 return ();
2617 }
2618 elsif($TypeAttr{"Type"}=~/(Func|Method|Field)Ptr/)
2619 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04002620 %TypeAttr = getMemPtrAttr(pointTo($TypeId), $TypeId, $TypeAttr{"Type"});
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04002621 if(my $TName = $TypeAttr{"Name"})
2622 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04002623 %{$TypeInfo{$Version}{$TypeId}} = %TypeAttr;
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04002624 $TName_Tid{$Version}{$TName} = $TypeId;
2625 return %TypeAttr;
2626 }
2627 else {
2628 return ();
2629 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002630 }
2631 elsif($TypeAttr{"Type"} eq "Array")
2632 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04002633 my ($BTid, $BTSpec) = selectBaseType($TypeId);
2634 if(not $BTid) {
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04002635 return ();
2636 }
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +04002637 if(my $Algn = getAlgn($TypeId)) {
2638 $TypeAttr{"Algn"} = $Algn/$BYTE_SIZE;
2639 }
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04002640 $TypeAttr{"BaseType"}{"Tid"} = $BTid;
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04002641 if(my %BTAttr = getTypeAttr($BTid))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002642 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04002643 if(not $BTAttr{"Name"}) {
2644 return ();
2645 }
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04002646 if(my $NElems = getArraySize($TypeId, $BTAttr{"Name"}))
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04002647 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04002648 if(my $Size = getSize($TypeId)) {
2649 $TypeAttr{"Size"} = $Size/$BYTE_SIZE;
2650 }
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04002651 if($BTAttr{"Name"}=~/\A([^\[\]]+)(\[(\d+|)\].*)\Z/) {
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04002652 $TypeAttr{"Name"} = $1."[$NElems]".$2;
2653 }
2654 else {
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04002655 $TypeAttr{"Name"} = $BTAttr{"Name"}."[$NElems]";
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04002656 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002657 }
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04002658 else
2659 {
2660 $TypeAttr{"Size"} = $WORD_SIZE{$Version}; # pointer
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04002661 if($BTAttr{"Name"}=~/\A([^\[\]]+)(\[(\d+|)\].*)\Z/) {
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04002662 $TypeAttr{"Name"} = $1."[]".$2;
2663 }
2664 else {
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04002665 $TypeAttr{"Name"} = $BTAttr{"Name"}."[]";
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04002666 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002667 }
Andrey Ponomarenko9927e332012-10-19 10:50:48 +04002668 $TypeAttr{"Name"} = formatName($TypeAttr{"Name"}, "T");
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04002669 if($BTAttr{"Header"}) {
2670 $TypeAttr{"Header"} = $BTAttr{"Header"};
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04002671 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04002672 %{$TypeInfo{$Version}{$TypeId}} = %TypeAttr;
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04002673 $TName_Tid{$Version}{$TypeAttr{"Name"}} = $TypeId;
2674 return %TypeAttr;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002675 }
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04002676 return ();
2677 }
2678 elsif($TypeAttr{"Type"}=~/\A(Intrinsic|Union|Struct|Enum|Class)\Z/)
2679 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04002680 %TypeAttr = getTrivialTypeAttr($TypeId);
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04002681 if($TypeAttr{"Name"})
2682 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04002683 %{$TypeInfo{$Version}{$TypeId}} = %TypeAttr;
2684 if($TypeAttr{"Name"} ne "int" or getTypeDeclId($TypeAttr{"Tid"}))
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04002685 { # NOTE: register only one int: with built-in decl
2686 if(not $TName_Tid{$Version}{$TypeAttr{"Name"}}) {
2687 $TName_Tid{$Version}{$TypeAttr{"Name"}} = $TypeId;
2688 }
2689 }
2690 return %TypeAttr;
2691 }
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04002692 else {
2693 return ();
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002694 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002695 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002696 else
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04002697 { # derived types
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04002698 my ($BTid, $BTSpec) = selectBaseType($TypeId);
2699 if(not $BTid) {
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04002700 return ();
2701 }
2702 $TypeAttr{"BaseType"}{"Tid"} = $BTid;
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04002703 if(defined $MissedTypedef{$Version}{$BTid})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002704 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04002705 if(my $MissedTDid = $MissedTypedef{$Version}{$BTid}{"TDid"})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002706 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04002707 if($MissedTDid ne $TypeDeclId) {
2708 $TypeAttr{"BaseType"}{"Tid"} = $MissedTypedef{$Version}{$BTid}{"Tid"};
2709 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002710 }
2711 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04002712 my %BTAttr = getTypeAttr($TypeAttr{"BaseType"}{"Tid"});
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04002713 if(not $BTAttr{"Name"})
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04002714 { # templates
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002715 return ();
2716 }
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04002717 if($BTAttr{"Type"} eq "Typedef")
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002718 { # relinking typedefs
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04002719 my %BaseBase = get_Type($BTAttr{"BaseType"}{"Tid"}, $Version);
2720 if($BTAttr{"Name"} eq $BaseBase{"Name"}) {
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04002721 $TypeAttr{"BaseType"}{"Tid"} = $BaseBase{"Tid"};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002722 }
2723 }
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04002724 if($BTSpec)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002725 {
2726 if($TypeAttr{"Type"} eq "Pointer"
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04002727 and $BTAttr{"Name"}=~/\([\*]+\)/)
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04002728 {
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04002729 $TypeAttr{"Name"} = $BTAttr{"Name"};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002730 $TypeAttr{"Name"}=~s/\(([*]+)\)/($1*)/g;
2731 }
2732 else {
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04002733 $TypeAttr{"Name"} = $BTAttr{"Name"}." ".$BTSpec;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002734 }
2735 }
2736 else {
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04002737 $TypeAttr{"Name"} = $BTAttr{"Name"};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002738 }
2739 if($TypeAttr{"Type"} eq "Typedef")
2740 {
2741 $TypeAttr{"Name"} = getNameByInfo($TypeDeclId);
Andrey Ponomarenko85043792012-05-14 16:48:07 +04002742 if(isAnon($TypeAttr{"Name"}))
2743 { # anon typedef to anon type: ._N
2744 return ();
2745 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002746 if(my $NS = getNameSpace($TypeDeclId))
2747 {
2748 my $TypeName = $TypeAttr{"Name"};
2749 if($NS=~/\A(struct |union |class |)((.+)::|)\Q$TypeName\E\Z/)
2750 { # "some_type" is the typedef to "struct some_type" in C++
2751 if($3) {
2752 $TypeAttr{"Name"} = $3."::".$TypeName;
2753 }
2754 }
2755 else
2756 {
2757 $TypeAttr{"NameSpace"} = $NS;
2758 $TypeAttr{"Name"} = $TypeAttr{"NameSpace"}."::".$TypeAttr{"Name"};
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04002759
2760 if($TypeAttr{"NameSpace"}=~/\Astd(::|\Z)/
2761 and $TypeAttr{"Name"}!~/>(::\w+)+\Z/)
2762 {
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04002763 if($BTAttr{"NameSpace"}
2764 and $BTAttr{"NameSpace"}=~/\Astd(::|\Z)/ and $BTAttr{"Name"}=~/</)
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04002765 { # types like "std::fpos<__mbstate_t>" are
2766 # not covered by typedefs in the TU dump
2767 # so trying to add such typedefs manually
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04002768 $StdCxxTypedef{$Version}{$BTAttr{"Name"}}{$TypeAttr{"Name"}} = 1;
2769 if(length($TypeAttr{"Name"})<=length($BTAttr{"Name"}))
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04002770 {
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04002771 if(($BTAttr{"Name"}!~/\A(std|boost)::/ or $TypeAttr{"Name"}!~/\A[a-z]+\Z/))
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04002772 { # skip "other" in "std" and "type" in "boost"
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04002773 $Typedef_Eq{$Version}{$BTAttr{"Name"}} = $TypeAttr{"Name"};
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04002774 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002775 }
2776 }
2777 }
2778 }
2779 }
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04002780 if($TypeAttr{"Name"} ne $BTAttr{"Name"}
2781 and $TypeAttr{"Name"}!~/>(::\w+)+\Z/ and $BTAttr{"Name"}!~/>(::\w+)+\Z/)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002782 {
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04002783 if(not defined $Typedef_BaseName{$Version}{$TypeAttr{"Name"}})
2784 { # typedef int*const TYPEDEF; // first
2785 # int foo(TYPEDEF p); // const is optimized out
2786 $Typedef_BaseName{$Version}{$TypeAttr{"Name"}} = $BTAttr{"Name"};
2787 if($BTAttr{"Name"}=~/</)
2788 {
2789 if(($BTAttr{"Name"}!~/\A(std|boost)::/ or $TypeAttr{"Name"}!~/\A[a-z]+\Z/)) {
2790 $Typedef_Tr{$Version}{$BTAttr{"Name"}}{$TypeAttr{"Name"}} = 1;
2791 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002792 }
2793 }
2794 }
2795 ($TypeAttr{"Header"}, $TypeAttr{"Line"}) = getLocation($TypeDeclId);
2796 }
2797 if(not $TypeAttr{"Size"})
2798 {
2799 if($TypeAttr{"Type"} eq "Pointer") {
2800 $TypeAttr{"Size"} = $WORD_SIZE{$Version};
2801 }
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04002802 elsif($BTAttr{"Size"}) {
2803 $TypeAttr{"Size"} = $BTAttr{"Size"};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002804 }
2805 }
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +04002806 if(my $Algn = getAlgn($TypeId)) {
2807 $TypeAttr{"Algn"} = $Algn/$BYTE_SIZE;
2808 }
Andrey Ponomarenko9927e332012-10-19 10:50:48 +04002809 $TypeAttr{"Name"} = formatName($TypeAttr{"Name"}, "T");
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04002810 if(not $TypeAttr{"Header"} and $BTAttr{"Header"}) {
2811 $TypeAttr{"Header"} = $BTAttr{"Header"};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002812 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04002813 %{$TypeInfo{$Version}{$TypeId}} = %TypeAttr;
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04002814 if($TypeAttr{"Name"} ne $BTAttr{"Name"})
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04002815 { # typedef to "class Class"
2816 # should not be registered in TName_Tid
2817 if(not $TName_Tid{$Version}{$TypeAttr{"Name"}}) {
2818 $TName_Tid{$Version}{$TypeAttr{"Name"}} = $TypeId;
2819 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002820 }
2821 return %TypeAttr;
2822 }
2823}
2824
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04002825sub getTreeVec($)
2826{
2827 my %Vector = ();
2828 if($_[0] and my $Info = $LibInfo{$Version}{"info"}{$_[0]})
2829 {
2830 while($Info=~s/ (\d+)[ ]*:[ ]*\@(\d+) / /)
2831 { # string length is N-1 because of the null terminator
2832 $Vector{$1} = $2;
2833 }
2834 }
2835 return \%Vector;
2836}
2837
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002838sub get_TemplateParam($$)
2839{
2840 my ($Pos, $Type_Id) = @_;
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04002841 return () if(not $Type_Id);
2842 my $NodeType = $LibInfo{$Version}{"info_type"}{$Type_Id};
2843 return () if(not $NodeType);
2844 if($NodeType eq "integer_cst")
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002845 { # int (1), unsigned (2u), char ('c' as 99), ...
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04002846 my $CstTid = getTreeAttr_Type($Type_Id);
Andrey Ponomarenkob8d203d2012-05-25 18:11:07 +04002847 my %CstType = getTypeAttr($CstTid); # without recursion
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002848 my $Num = getNodeIntCst($Type_Id);
2849 if(my $CstSuffix = $ConstantSuffix{$CstType{"Name"}}) {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04002850 return ($Num.$CstSuffix);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002851 }
2852 else {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04002853 return ("(".$CstType{"Name"}.")".$Num);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002854 }
2855 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04002856 elsif($NodeType eq "string_cst") {
2857 return (getNodeStrCst($Type_Id));
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002858 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04002859 elsif($NodeType eq "tree_vec")
2860 {
2861 my $Vector = getTreeVec($Type_Id);
2862 my @Params = ();
2863 foreach my $P1 (sort {int($a)<=>int($b)} keys(%{$Vector}))
2864 {
2865 foreach my $P2 (get_TemplateParam($Pos, $Vector->{$P1})) {
2866 push(@Params, $P2);
2867 }
2868 }
2869 return @Params;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002870 }
2871 else
2872 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04002873 my %ParamAttr = getTypeAttr($Type_Id);
Andrey Ponomarenkob8d203d2012-05-25 18:11:07 +04002874 my $PName = $ParamAttr{"Name"};
2875 if(not $PName) {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04002876 return ();
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002877 }
Andrey Ponomarenkob8d203d2012-05-25 18:11:07 +04002878 if($PName=~/\>/)
2879 {
2880 if(my $Cover = cover_stdcxx_typedef($PName)) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002881 $PName = $Cover;
2882 }
2883 }
2884 if($Pos>=1 and
2885 $PName=~/\Astd::(allocator|less|((char|regex)_traits)|((i|o)streambuf_iterator))\</)
2886 { # template<typename _Tp, typename _Alloc = std::allocator<_Tp> >
2887 # template<typename _Key, typename _Compare = std::less<_Key>
2888 # template<typename _CharT, typename _Traits = std::char_traits<_CharT> >
2889 # template<typename _Ch_type, typename _Rx_traits = regex_traits<_Ch_type> >
2890 # template<typename _CharT, typename _InIter = istreambuf_iterator<_CharT> >
2891 # template<typename _CharT, typename _OutIter = ostreambuf_iterator<_CharT> >
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04002892 return ("\@skip\@");
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002893 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04002894 return ($PName);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002895 }
2896}
2897
2898sub cover_stdcxx_typedef($)
2899{
2900 my $TypeName = $_[0];
2901 if(my @Covers = sort {length($a)<=>length($b)}
2902 sort keys(%{$StdCxxTypedef{$Version}{$TypeName}}))
2903 { # take the shortest typedef
2904 # FIXME: there may be more than
2905 # one typedefs to the same type
2906 return $Covers[0];
2907 }
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +04002908 my $Covered = $TypeName;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002909 while($TypeName=~s/(>)[ ]*(const|volatile|restrict| |\*|\&)\Z/$1/g){};
2910 if(my @Covers = sort {length($a)<=>length($b)} sort keys(%{$StdCxxTypedef{$Version}{$TypeName}}))
2911 {
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +04002912 if(my $Cover = $Covers[0])
2913 {
2914 $Covered=~s/\b\Q$TypeName\E(\W|\Z)/$Cover$1/g;
2915 $Covered=~s/\b\Q$TypeName\E(\w|\Z)/$Cover $1/g;
2916 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002917 }
Andrey Ponomarenko9927e332012-10-19 10:50:48 +04002918 return formatName($Covered, "T");
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002919}
2920
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002921sub getNodeIntCst($)
2922{
2923 my $CstId = $_[0];
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04002924 my $CstTypeId = getTreeAttr_Type($CstId);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002925 if($EnumMembName_Id{$Version}{$CstId}) {
2926 return $EnumMembName_Id{$Version}{$CstId};
2927 }
2928 elsif((my $Value = getTreeValue($CstId)) ne "")
2929 {
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04002930 if($Value eq "0")
2931 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04002932 if($LibInfo{$Version}{"info_type"}{$CstTypeId} eq "boolean_type") {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002933 return "false";
2934 }
2935 else {
2936 return "0";
2937 }
2938 }
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04002939 elsif($Value eq "1")
2940 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04002941 if($LibInfo{$Version}{"info_type"}{$CstTypeId} eq "boolean_type") {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002942 return "true";
2943 }
2944 else {
2945 return "1";
2946 }
2947 }
2948 else {
2949 return $Value;
2950 }
2951 }
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04002952 return "";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002953}
2954
2955sub getNodeStrCst($)
2956{
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04002957 if($_[0] and my $Info = $LibInfo{$Version}{"info"}{$_[0]})
2958 {
2959 if($Info=~/strg[ ]*: (.+) lngt:[ ]*(\d+)/)
Andrey Ponomarenko01117f12012-06-26 12:23:02 +04002960 {
2961 if($LibInfo{$Version}{"info_type"}{$_[0]} eq "string_cst")
2962 { # string length is N-1 because of the null terminator
2963 return substr($1, 0, $2-1);
2964 }
2965 else
2966 { # identifier_node
2967 return substr($1, 0, $2);
2968 }
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04002969 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002970 }
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04002971 return "";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002972}
2973
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04002974sub getMemPtrAttr($$$)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002975{ # function, method and field pointers
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04002976 my ($PtrId, $TypeId, $Type) = @_;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002977 my $MemInfo = $LibInfo{$Version}{"info"}{$PtrId};
2978 if($Type eq "FieldPtr") {
2979 $MemInfo = $LibInfo{$Version}{"info"}{$TypeId};
2980 }
2981 my $MemInfo_Type = $LibInfo{$Version}{"info_type"}{$PtrId};
2982 my $MemPtrName = "";
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04002983 my %TypeAttr = ("Size"=>$WORD_SIZE{$Version}, "Type"=>$Type, "Tid"=>$TypeId);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002984 if($Type eq "MethodPtr")
2985 { # size of "method pointer" may be greater than WORD size
Andrey Ponomarenko01117f12012-06-26 12:23:02 +04002986 if(my $Size = getSize($TypeId))
2987 {
2988 $Size/=$BYTE_SIZE;
2989 $TypeAttr{"Size"} = "$Size";
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04002990 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002991 }
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +04002992 if(my $Algn = getAlgn($TypeId)) {
2993 $TypeAttr{"Algn"} = $Algn/$BYTE_SIZE;
2994 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002995 # Return
2996 if($Type eq "FieldPtr")
2997 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04002998 my %ReturnAttr = getTypeAttr($PtrId);
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04002999 if($ReturnAttr{"Name"}) {
3000 $MemPtrName .= $ReturnAttr{"Name"};
3001 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003002 $TypeAttr{"Return"} = $PtrId;
3003 }
3004 else
3005 {
3006 if($MemInfo=~/retn[ ]*:[ ]*\@(\d+) /)
3007 {
3008 my $ReturnTypeId = $1;
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04003009 my %ReturnAttr = getTypeAttr($ReturnTypeId);
3010 if(not $ReturnAttr{"Name"})
3011 { # templates
3012 return ();
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04003013 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04003014 $MemPtrName .= $ReturnAttr{"Name"};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003015 $TypeAttr{"Return"} = $ReturnTypeId;
3016 }
3017 }
3018 # Class
3019 if($MemInfo=~/(clas|cls)[ ]*:[ ]*@(\d+) /)
3020 {
3021 $TypeAttr{"Class"} = $2;
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04003022 my %Class = getTypeAttr($TypeAttr{"Class"});
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003023 if($Class{"Name"}) {
3024 $MemPtrName .= " (".$Class{"Name"}."\:\:*)";
3025 }
3026 else {
3027 $MemPtrName .= " (*)";
3028 }
3029 }
3030 else {
3031 $MemPtrName .= " (*)";
3032 }
3033 # Parameters
3034 if($Type eq "FuncPtr"
3035 or $Type eq "MethodPtr")
3036 {
3037 my @ParamTypeName = ();
3038 if($MemInfo=~/prms[ ]*:[ ]*@(\d+) /)
3039 {
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04003040 my $PTypeInfoId = $1;
Andrey Ponomarenko01117f12012-06-26 12:23:02 +04003041 my ($Pos, $PPos) = (0, 0);
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04003042 while($PTypeInfoId)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003043 {
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04003044 my $PTypeInfo = $LibInfo{$Version}{"info"}{$PTypeInfoId};
3045 if($PTypeInfo=~/valu[ ]*:[ ]*@(\d+) /)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003046 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04003047 my $PTypeId = $1;
3048 my %ParamAttr = getTypeAttr($PTypeId);
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04003049 if(not $ParamAttr{"Name"})
3050 { # templates (template_type_parm), etc.
3051 return ();
3052 }
3053 if($ParamAttr{"Name"} eq "void") {
3054 last;
3055 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04003056 if($Pos!=0 or $Type ne "MethodPtr")
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04003057 {
Andrey Ponomarenko01117f12012-06-26 12:23:02 +04003058 $TypeAttr{"Param"}{$PPos++}{"type"} = $PTypeId;
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04003059 push(@ParamTypeName, $ParamAttr{"Name"});
3060 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04003061 if($PTypeInfoId = getNextElem($PTypeInfoId)) {
3062 $Pos+=1;
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04003063 }
3064 else {
3065 last;
3066 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003067 }
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04003068 else {
3069 last;
3070 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003071 }
3072 }
3073 $MemPtrName .= " (".join(", ", @ParamTypeName).")";
3074 }
Andrey Ponomarenko9927e332012-10-19 10:50:48 +04003075 $TypeAttr{"Name"} = formatName($MemPtrName, "T");
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003076 return %TypeAttr;
3077}
3078
3079sub getTreeTypeName($)
3080{
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04003081 my $TypeId = $_[0];
3082 if(my $Info = $LibInfo{$Version}{"info"}{$TypeId})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003083 {
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04003084 if($LibInfo{$Version}{"info_type"}{$_[0]} eq "integer_type")
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003085 {
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04003086 if(my $Name = getNameByInfo($TypeId))
3087 { # bit_size_type
3088 return $Name;
3089 }
3090 elsif($Info=~/unsigned/) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003091 return "unsigned int";
3092 }
3093 else {
3094 return "int";
3095 }
3096 }
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04003097 elsif($Info=~/name[ ]*:[ ]*@(\d+) /)
3098 {
3099 return getNameByInfo($1);
3100 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003101 }
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04003102 return "";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003103}
3104
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04003105sub isFuncPtr($)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003106{
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04003107 my $Ptd = pointTo($_[0]);
3108 return 0 if(not $Ptd);
3109 if(my $Info = $LibInfo{$Version}{"info"}{$_[0]})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003110 {
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04003111 if($Info=~/unql[ ]*:/ and $Info!~/qual[ ]*:/) {
3112 return 0;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003113 }
3114 }
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04003115 if(my $InfoT1 = $LibInfo{$Version}{"info_type"}{$_[0]}
3116 and my $InfoT2 = $LibInfo{$Version}{"info_type"}{$Ptd})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003117 {
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04003118 if($InfoT1 eq "pointer_type"
3119 and $InfoT2 eq "function_type") {
3120 return 1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003121 }
3122 }
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04003123 return 0;
3124}
3125
3126sub isMethodPtr($)
3127{
3128 my $Ptd = pointTo($_[0]);
3129 return 0 if(not $Ptd);
3130 if(my $Info = $LibInfo{$Version}{"info"}{$_[0]})
3131 {
3132 if($LibInfo{$Version}{"info_type"}{$_[0]} eq "record_type"
3133 and $LibInfo{$Version}{"info_type"}{$Ptd} eq "method_type"
3134 and $Info=~/ ptrmem /) {
3135 return 1;
3136 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003137 }
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04003138 return 0;
3139}
3140
3141sub isFieldPtr($)
3142{
3143 if($_[0] and my $Info = $LibInfo{$Version}{"info"}{$_[0]})
3144 {
3145 if($LibInfo{$Version}{"info_type"}{$_[0]} eq "offset_type"
3146 and $Info=~/ ptrmem /) {
3147 return 1;
3148 }
3149 }
3150 return 0;
3151}
3152
3153sub pointTo($)
3154{
3155 if($_[0] and my $Info = $LibInfo{$Version}{"info"}{$_[0]})
3156 {
3157 if($Info=~/ptd[ ]*:[ ]*@(\d+)/) {
3158 return $1;
3159 }
3160 }
3161 return "";
3162}
3163
3164sub getTypeTypeByTypeId($)
3165{
3166 my $TypeId = $_[0];
3167 if(my $TType = $LibInfo{$Version}{"info_type"}{$TypeId})
3168 {
3169 my $NType = $NodeType{$TType};
3170 if($NType eq "Intrinsic") {
3171 return $NType;
3172 }
3173 elsif(isFuncPtr($TypeId)) {
3174 return "FuncPtr";
3175 }
3176 elsif(isMethodPtr($TypeId)) {
3177 return "MethodPtr";
3178 }
3179 elsif(isFieldPtr($TypeId)) {
3180 return "FieldPtr";
3181 }
3182 elsif($NType ne "Other") {
3183 return $NType;
3184 }
3185 }
3186 return "Unknown";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003187}
3188
3189sub getQual($)
3190{
3191 my $TypeId = $_[0];
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003192 my %UnQual = (
3193 "r"=>"restrict",
3194 "v"=>"volatile",
3195 "c"=>"const",
3196 "cv"=>"const volatile"
3197 );
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04003198 if(my $Info = $LibInfo{$Version}{"info"}{$TypeId})
3199 {
3200 my ($Qual, $To) = ();
3201 if($Info=~/qual[ ]*:[ ]*(r|c|v|cv) /) {
3202 $Qual = $UnQual{$1};
3203 }
3204 if($Info=~/unql[ ]*:[ ]*\@(\d+)/) {
3205 $To = $1;
3206 }
3207 if($Qual and $To) {
3208 return ($Qual, $To);
3209 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003210 }
3211 return ();
3212}
3213
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04003214sub getQualType($)
3215{
3216 if($_[0] eq "const volatile") {
3217 return "ConstVolatile";
3218 }
3219 return ucfirst($_[0]);
3220}
3221
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04003222sub getTypeType($)
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04003223{
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04003224 my $TypeId = $_[0];
3225 my $TypeDeclId = getTypeDeclId($TypeId);
3226 if(defined $MissedTypedef{$Version}{$TypeId})
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04003227 { # support for old GCC versions
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04003228 if($MissedTypedef{$Version}{$TypeId}{"TDid"} eq $TypeDeclId) {
3229 return "Typedef";
3230 }
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04003231 }
3232 my $Info = $LibInfo{$Version}{"info"}{$TypeId};
3233 my ($Qual, $To) = getQual($TypeId);
Andrey Ponomarenko9927e332012-10-19 10:50:48 +04003234 if(($Qual or $To) and $TypeDeclId
3235 and (getTypeId($TypeDeclId) ne $TypeId))
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04003236 { # qualified types (special)
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04003237 return getQualType($Qual);
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04003238 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04003239 elsif(not $MissedBase_R{$Version}{$TypeId}
3240 and isTypedef($TypeId)) {
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04003241 return "Typedef";
3242 }
3243 elsif($Qual)
3244 { # qualified types
3245 return getQualType($Qual);
3246 }
Andrey Ponomarenko9927e332012-10-19 10:50:48 +04003247
3248 if($Info=~/unql[ ]*:[ ]*\@(\d+)/)
3249 { # typedef struct { ... } name
3250 $TypeTypedef{$Version}{$TypeId} = $1;
3251 }
3252
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04003253 my $TypeType = getTypeTypeByTypeId($TypeId);
3254 if($TypeType eq "Struct")
3255 {
3256 if($TypeDeclId
3257 and $LibInfo{$Version}{"info_type"}{$TypeDeclId} eq "template_decl") {
3258 return "Template";
3259 }
3260 }
3261 return $TypeType;
3262}
3263
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04003264sub isTypedef($)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003265{
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04003266 if($_[0] and my $Info = $LibInfo{$Version}{"info"}{$_[0]})
3267 {
3268 my $TDid = getTypeDeclId($_[0]);
3269 if(getNameByInfo($TDid)
3270 and $Info=~/unql[ ]*:[ ]*\@(\d+) /
3271 and getTypeId($TDid) eq $_[0]) {
3272 return $1;
3273 }
3274 }
3275 return 0;
3276}
3277
3278sub selectBaseType($)
3279{
3280 my $TypeId = $_[0];
3281 if(defined $MissedTypedef{$Version}{$TypeId})
3282 { # add missed typedefs
3283 if($MissedTypedef{$Version}{$TypeId}{"TDid"} eq getTypeDeclId($TypeId)) {
3284 return ($TypeId, "");
3285 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003286 }
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04003287 my $Info = $LibInfo{$Version}{"info"}{$TypeId};
3288 my $InfoType = $LibInfo{$Version}{"info_type"}{$TypeId};
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04003289
3290 my $MB_R = $MissedBase_R{$Version}{$TypeId};
3291 my $MB = $MissedBase{$Version}{$TypeId};
3292
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04003293 my ($Qual, $To) = getQual($TypeId);
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04003294 if(($Qual or $To) and $Info=~/name[ ]*:[ ]*\@(\d+) /
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04003295 and (getTypeId($1) ne $TypeId)
3296 and (not $MB_R or getTypeId($1) ne $MB_R))
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04003297 { # qualified types (special)
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04003298 return (getTypeId($1), $Qual);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003299 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04003300 elsif($MB)
3301 { # add base
3302 return ($MB, "");
3303 }
3304 elsif(not $MB_R and my $Bid = isTypedef($TypeId))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003305 { # typedefs
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04003306 return ($Bid, "");
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003307 }
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04003308 elsif($Qual or $To)
3309 { # qualified types
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04003310 return ($To, $Qual);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003311 }
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04003312 elsif($InfoType eq "reference_type")
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003313 {
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04003314 if($Info=~/refd[ ]*:[ ]*@(\d+) /) {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04003315 return ($1, "&");
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003316 }
3317 else {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04003318 return (0, "");
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003319 }
3320 }
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04003321 elsif($InfoType eq "array_type")
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003322 {
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04003323 if($Info=~/elts[ ]*:[ ]*@(\d+) /) {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04003324 return ($1, "");
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003325 }
3326 else {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04003327 return (0, "");
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003328 }
3329 }
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04003330 elsif($InfoType eq "pointer_type")
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003331 {
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04003332 if($Info=~/ptd[ ]*:[ ]*@(\d+) /) {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04003333 return ($1, "*");
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003334 }
3335 else {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04003336 return (0, "");
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003337 }
3338 }
3339 else {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04003340 return (0, "");
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003341 }
3342}
3343
3344sub getSymbolInfo_All()
3345{
3346 foreach (sort {int($b)<=>int($a)} keys(%{$LibInfo{$Version}{"info"}}))
3347 { # reverse order
3348 if($LibInfo{$Version}{"info_type"}{$_} eq "function_decl") {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04003349 getSymbolInfo($_);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003350 }
3351 }
3352}
3353
3354sub getVarInfo_All()
3355{
3356 foreach (sort {int($b)<=>int($a)} keys(%{$LibInfo{$Version}{"info"}}))
3357 { # reverse order
3358 if($LibInfo{$Version}{"info_type"}{$_} eq "var_decl") {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04003359 getVarInfo($_);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003360 }
3361 }
3362}
3363
3364sub isBuiltIn($) {
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04003365 return ($_[0] and $_[0]=~/\<built\-in\>|\<internal\>|\A\./);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003366}
3367
3368sub getVarInfo($)
3369{
3370 my $InfoId = $_[0];
Andrey Ponomarenko01117f12012-06-26 12:23:02 +04003371 if(my $NSid = getTreeAttr_Scpe($InfoId))
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04003372 {
3373 my $NSInfoType = $LibInfo{$Version}{"info_type"}{$NSid};
3374 if($NSInfoType and $NSInfoType eq "function_decl") {
3375 return;
3376 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003377 }
3378 ($SymbolInfo{$Version}{$InfoId}{"Header"}, $SymbolInfo{$Version}{$InfoId}{"Line"}) = getLocation($InfoId);
3379 if(not $SymbolInfo{$Version}{$InfoId}{"Header"}
3380 or isBuiltIn($SymbolInfo{$Version}{$InfoId}{"Header"})) {
3381 delete($SymbolInfo{$Version}{$InfoId});
3382 return;
3383 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04003384 my $ShortName = getTreeStr(getTreeAttr_Name($InfoId));
Andrey Ponomarenko85043792012-05-14 16:48:07 +04003385 if(not $ShortName) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003386 delete($SymbolInfo{$Version}{$InfoId});
3387 return;
3388 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +04003389 if($ShortName=~/\Atmp_add_class_\d+\Z/) {
3390 delete($SymbolInfo{$Version}{$InfoId});
3391 return;
3392 }
3393 $SymbolInfo{$Version}{$InfoId}{"ShortName"} = $ShortName;
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +04003394 if(my $MnglName = getTreeStr(getTreeAttr_Mngl($InfoId)))
3395 {
3396 if($OSgroup eq "windows")
3397 { # cut the offset
3398 $MnglName=~s/\@\d+\Z//g;
3399 }
3400 $SymbolInfo{$Version}{$InfoId}{"MnglName"} = $MnglName;
3401 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003402 if($SymbolInfo{$Version}{$InfoId}{"MnglName"}
Andrey Ponomarenko9927e332012-10-19 10:50:48 +04003403 and index($SymbolInfo{$Version}{$InfoId}{"MnglName"}, "_Z")!=0)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003404 { # validate mangled name
3405 delete($SymbolInfo{$Version}{$InfoId});
3406 return;
3407 }
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04003408 if(not $SymbolInfo{$Version}{$InfoId}{"MnglName"}
Andrey Ponomarenko9927e332012-10-19 10:50:48 +04003409 and index($ShortName, "_Z")==0)
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04003410 { # _ZTS, etc.
Andrey Ponomarenko85043792012-05-14 16:48:07 +04003411 $SymbolInfo{$Version}{$InfoId}{"MnglName"} = $ShortName;
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04003412 }
3413 if(isPrivateData($SymbolInfo{$Version}{$InfoId}{"MnglName"}))
3414 { # non-public global data
3415 delete($SymbolInfo{$Version}{$InfoId});
3416 return;
3417 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003418 $SymbolInfo{$Version}{$InfoId}{"Data"} = 1;
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04003419 if(my $Rid = getTypeId($InfoId))
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04003420 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04003421 if(not $TypeInfo{$Version}{$Rid}{"Name"})
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04003422 { # typename_type
3423 delete($SymbolInfo{$Version}{$InfoId});
3424 return;
3425 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04003426 $SymbolInfo{$Version}{$InfoId}{"Return"} = $Rid;
3427 my $Val = getDataVal($InfoId, $Rid);
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04003428 if(defined $Val) {
3429 $SymbolInfo{$Version}{$InfoId}{"Value"} = $Val;
3430 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003431 }
3432 set_Class_And_Namespace($InfoId);
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04003433 if(my $ClassId = $SymbolInfo{$Version}{$InfoId}{"Class"})
3434 {
3435 if(not $TypeInfo{$Version}{$ClassId}{"Name"})
3436 { # templates
3437 delete($SymbolInfo{$Version}{$InfoId});
3438 return;
3439 }
3440 }
Andrey Ponomarenko35c44fd2012-06-18 17:50:25 +04003441 if($LibInfo{$Version}{"info"}{$InfoId}=~/ lang:[ ]*C /i)
3442 { # extern "C"
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003443 $SymbolInfo{$Version}{$InfoId}{"Lang"} = "C";
Andrey Ponomarenko35c44fd2012-06-18 17:50:25 +04003444 $SymbolInfo{$Version}{$InfoId}{"MnglName"} = $ShortName;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003445 }
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04003446 if($UserLang and $UserLang eq "C")
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003447 { # --lang=C option
Andrey Ponomarenko85043792012-05-14 16:48:07 +04003448 $SymbolInfo{$Version}{$InfoId}{"MnglName"} = $ShortName;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003449 }
Andrey Ponomarenko5c09ef32012-06-14 18:17:33 +04003450 if(not $CheckHeadersOnly)
3451 {
3452 if(not $SymbolInfo{$Version}{$InfoId}{"Class"})
3453 {
3454 if(not $SymbolInfo{$Version}{$InfoId}{"MnglName"}
3455 or not link_symbol($SymbolInfo{$Version}{$InfoId}{"MnglName"}, $Version, "-Deps"))
3456 {
3457 if(link_symbol($ShortName, $Version, "-Deps"))
3458 { # "const" global data is mangled as _ZL... in the TU dump
3459 # but not mangled when compiling a C shared library
3460 $SymbolInfo{$Version}{$InfoId}{"MnglName"} = $ShortName;
3461 }
3462 }
3463 }
3464 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003465 if($COMMON_LANGUAGE{$Version} eq "C++")
3466 {
3467 if(not $SymbolInfo{$Version}{$InfoId}{"MnglName"})
3468 { # for some symbols (_ZTI) the short name is the mangled name
Andrey Ponomarenko9927e332012-10-19 10:50:48 +04003469 if(index($ShortName, "_Z")==0) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003470 $SymbolInfo{$Version}{$InfoId}{"MnglName"} = $ShortName;
3471 }
3472 }
3473 if(not $SymbolInfo{$Version}{$InfoId}{"MnglName"})
3474 { # try to mangle symbol (link with libraries)
3475 $SymbolInfo{$Version}{$InfoId}{"MnglName"} = linkSymbol($InfoId);
3476 }
3477 if($OStarget eq "windows")
3478 {
3479 if(my $Mangled = $mangled_name{$Version}{modelUnmangled($InfoId, "MSVC")})
3480 { # link MS C++ symbols from library with GCC symbols from headers
3481 $SymbolInfo{$Version}{$InfoId}{"MnglName"} = $Mangled;
3482 }
3483 }
3484 }
3485 if(not $SymbolInfo{$Version}{$InfoId}{"MnglName"}) {
3486 $SymbolInfo{$Version}{$InfoId}{"MnglName"} = $ShortName;
3487 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +04003488 if(my $Symbol = $SymbolInfo{$Version}{$InfoId}{"MnglName"})
3489 {
3490 if(not selectSymbol($Symbol, $SymbolInfo{$Version}{$InfoId}, "Dump", $Version))
3491 { # non-target symbols
3492 delete($SymbolInfo{$Version}{$InfoId});
3493 return;
3494 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003495 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04003496 if(my $Rid = $SymbolInfo{$Version}{$InfoId}{"Return"})
3497 {
3498 if(defined $MissedTypedef{$Version}{$Rid})
3499 {
3500 if(my $AddedTid = $MissedTypedef{$Version}{$Rid}{"Tid"}) {
3501 $SymbolInfo{$Version}{$InfoId}{"Return"} = $AddedTid;
3502 }
3503 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003504 }
3505 setFuncAccess($InfoId);
Andrey Ponomarenko9927e332012-10-19 10:50:48 +04003506 if(index($SymbolInfo{$Version}{$InfoId}{"MnglName"}, "_ZTV")==0) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003507 delete($SymbolInfo{$Version}{$InfoId}{"Return"});
3508 }
3509 if($ShortName=~/\A(_Z|\?)/) {
3510 delete($SymbolInfo{$Version}{$InfoId}{"ShortName"});
3511 }
3512}
3513
Andrey Ponomarenko85043792012-05-14 16:48:07 +04003514sub isConstType($$)
3515{
3516 my ($TypeId, $LibVersion) = @_;
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04003517 my %Base = get_Type($TypeId, $LibVersion);
Andrey Ponomarenko85043792012-05-14 16:48:07 +04003518 while(defined $Base{"Type"} and $Base{"Type"} eq "Typedef") {
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +04003519 %Base = get_OneStep_BaseType($Base{"Tid"}, $TypeInfo{$LibVersion});
Andrey Ponomarenko85043792012-05-14 16:48:07 +04003520 }
3521 return ($Base{"Type"} eq "Const");
3522}
3523
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003524sub getTrivialName($$)
3525{
3526 my ($TypeInfoId, $TypeId) = @_;
3527 my %TypeAttr = ();
3528 $TypeAttr{"Name"} = getNameByInfo($TypeInfoId);
3529 if(not $TypeAttr{"Name"}) {
3530 $TypeAttr{"Name"} = getTreeTypeName($TypeId);
3531 }
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04003532 ($TypeAttr{"Header"}, $TypeAttr{"Line"}) = getLocation($TypeInfoId);
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04003533 $TypeAttr{"Type"} = getTypeType($TypeId);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003534 $TypeAttr{"Name"}=~s/<(.+)\Z//g; # GCC 3.4.4 add template params to the name
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04003535 if(isAnon($TypeAttr{"Name"}))
3536 {
3537 my $NameSpaceId = $TypeId;
Andrey Ponomarenko01117f12012-06-26 12:23:02 +04003538 while(my $NSId = getTreeAttr_Scpe(getTypeDeclId($NameSpaceId)))
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04003539 { # searching for a first not anon scope
3540 if($NSId eq $NameSpaceId) {
3541 last;
3542 }
3543 else
3544 {
3545 $TypeAttr{"NameSpace"} = getNameSpace(getTypeDeclId($TypeId));
3546 if(not $TypeAttr{"NameSpace"}
3547 or isNotAnon($TypeAttr{"NameSpace"})) {
3548 last;
3549 }
3550 }
3551 $NameSpaceId=$NSId;
3552 }
3553 }
3554 else
3555 {
Andrey Ponomarenko01117f12012-06-26 12:23:02 +04003556 if(my $NameSpaceId = getTreeAttr_Scpe($TypeInfoId))
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04003557 {
3558 if($NameSpaceId ne $TypeId) {
3559 $TypeAttr{"NameSpace"} = getNameSpace($TypeInfoId);
3560 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003561 }
3562 }
3563 if($TypeAttr{"NameSpace"} and isNotAnon($TypeAttr{"Name"})) {
3564 $TypeAttr{"Name"} = $TypeAttr{"NameSpace"}."::".$TypeAttr{"Name"};
3565 }
Andrey Ponomarenko9927e332012-10-19 10:50:48 +04003566 $TypeAttr{"Name"} = formatName($TypeAttr{"Name"}, "T");
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003567 if(isAnon($TypeAttr{"Name"}))
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04003568 { # anon-struct-header.h-line
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04003569 $TypeAttr{"Name"} = "anon-".lc($TypeAttr{"Type"})."-";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003570 $TypeAttr{"Name"} .= $TypeAttr{"Header"}."-".$TypeAttr{"Line"};
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04003571 if($TypeAttr{"NameSpace"}) {
3572 $TypeAttr{"Name"} = $TypeAttr{"NameSpace"}."::".$TypeAttr{"Name"};
3573 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003574 }
Andrey Ponomarenkob8d203d2012-05-25 18:11:07 +04003575 if(defined $TemplateInstance{$Version}{"Type"}{$TypeId}
3576 and getTypeDeclId($TypeId) eq $TypeInfoId)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003577 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04003578 my @TParams = getTParams($TypeId, "Type");
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003579 if(not @TParams)
3580 { # template declarations with abstract params
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003581 return ("", "");
3582 }
Andrey Ponomarenko9927e332012-10-19 10:50:48 +04003583 $TypeAttr{"Name"} = formatName($TypeAttr{"Name"}."< ".join(", ", @TParams)." >", "T");
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003584 }
3585 return ($TypeAttr{"Name"}, $TypeAttr{"NameSpace"});
3586}
3587
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04003588sub getTrivialTypeAttr($)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003589{
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04003590 my $TypeId = $_[0];
3591 my $TypeInfoId = getTypeDeclId($_[0]);
Andrey Ponomarenko85043792012-05-14 16:48:07 +04003592
3593 if($TemplateDecl{$Version}{$TypeId})
3594 { # template_decl
3595 return ();
3596 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04003597 if(my $ScopeId = getTreeAttr_Scpe($TypeInfoId))
3598 {
3599 if($TemplateDecl{$Version}{$ScopeId})
3600 { # template_decl
3601 return ();
3602 }
3603 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +04003604
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003605 my %TypeAttr = ();
3606 if(getTypeTypeByTypeId($TypeId)!~/\A(Intrinsic|Union|Struct|Enum|Class)\Z/) {
3607 return ();
3608 }
3609 setTypeAccess($TypeId, \%TypeAttr);
3610 ($TypeAttr{"Header"}, $TypeAttr{"Line"}) = getLocation($TypeInfoId);
3611 if(isBuiltIn($TypeAttr{"Header"}))
3612 {
3613 delete($TypeAttr{"Header"});
3614 delete($TypeAttr{"Line"});
3615 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04003616 $TypeAttr{"Type"} = getTypeType($TypeId);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003617 ($TypeAttr{"Name"}, $TypeAttr{"NameSpace"}) = getTrivialName($TypeInfoId, $TypeId);
3618 if(not $TypeAttr{"Name"}) {
3619 return ();
3620 }
3621 if(not $TypeAttr{"NameSpace"}) {
3622 delete($TypeAttr{"NameSpace"});
3623 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04003624 if(defined $TemplateInstance{$Version}{"Type"}{$TypeId})
Andrey Ponomarenko16934472012-03-29 15:37:04 +04003625 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04003626 if(my @TParams = getTParams($TypeId, "Type"))
Andrey Ponomarenko16934472012-03-29 15:37:04 +04003627 {
3628 foreach my $Pos (0 .. $#TParams) {
3629 $TypeAttr{"TParam"}{$Pos}{"name"}=$TParams[$Pos];
3630 }
3631 }
3632 }
Andrey Ponomarenko01117f12012-06-26 12:23:02 +04003633 if(my $Size = getSize($TypeId))
3634 {
3635 $Size = $Size/$BYTE_SIZE;
3636 $TypeAttr{"Size"} = "$Size";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003637 }
Andrey Ponomarenko9927e332012-10-19 10:50:48 +04003638 else
3639 { # declaration only
3640 $TypeAttr{"Forward"} = 1;
3641 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003642 if($TypeAttr{"Type"} eq "Struct"
3643 and detect_lang($TypeId))
3644 {
3645 $TypeAttr{"Type"} = "Class";
Andrey Ponomarenko85043792012-05-14 16:48:07 +04003646 $TypeAttr{"Copied"} = 1; # default, will be changed in getSymbolInfo()
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003647 }
3648 if($TypeAttr{"Type"} eq "Struct"
Andrey Ponomarenko85043792012-05-14 16:48:07 +04003649 or $TypeAttr{"Type"} eq "Class")
3650 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04003651 my $Skip = setBaseClasses($TypeId, \%TypeAttr);
Andrey Ponomarenko85043792012-05-14 16:48:07 +04003652 if($Skip) {
3653 return ();
3654 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003655 }
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +04003656 if(my $Algn = getAlgn($TypeId)) {
3657 $TypeAttr{"Algn"} = $Algn/$BYTE_SIZE;
3658 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003659 setSpec($TypeId, \%TypeAttr);
3660 setTypeMemb($TypeId, \%TypeAttr);
3661 $TypeAttr{"Tid"} = $TypeId;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003662 if(my $VTable = $ClassVTable_Content{$Version}{$TypeAttr{"Name"}})
3663 {
3664 my @Entries = split(/\n/, $VTable);
3665 foreach (1 .. $#Entries)
3666 {
3667 my $Entry = $Entries[$_];
3668 if($Entry=~/\A(\d+)\s+(.+)\Z/) {
3669 $TypeAttr{"VTable"}{$1} = $2;
3670 }
3671 }
3672 }
3673 return %TypeAttr;
3674}
3675
3676sub detect_lang($)
3677{
3678 my $TypeId = $_[0];
3679 my $Info = $LibInfo{$Version}{"info"}{$TypeId};
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04003680 if(check_gcc($GCC_PATH, "4"))
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04003681 { # GCC 4 fncs-node points to only non-artificial methods
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003682 return ($Info=~/(fncs)[ ]*:[ ]*@(\d+) /);
3683 }
3684 else
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04003685 { # GCC 3
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04003686 my $Fncs = getTreeAttr_Fncs($TypeId);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003687 while($Fncs)
3688 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04003689 if($LibInfo{$Version}{"info"}{$Fncs}!~/artificial/) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003690 return 1;
3691 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04003692 $Fncs = getTreeAttr_Chan($Fncs);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003693 }
3694 }
3695 return 0;
3696}
3697
3698sub setSpec($$)
3699{
3700 my ($TypeId, $TypeAttr) = @_;
3701 my $Info = $LibInfo{$Version}{"info"}{$TypeId};
3702 if($Info=~/\s+spec\s+/) {
3703 $TypeAttr->{"Spec"} = 1;
3704 }
3705}
3706
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04003707sub setBaseClasses($$)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003708{
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04003709 my ($TypeId, $TypeAttr) = @_;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003710 my $Info = $LibInfo{$Version}{"info"}{$TypeId};
3711 if($Info=~/binf[ ]*:[ ]*@(\d+) /)
3712 {
3713 $Info = $LibInfo{$Version}{"info"}{$1};
3714 my $Pos = 0;
3715 while($Info=~s/(pub|public|prot|protected|priv|private|)[ ]+binf[ ]*:[ ]*@(\d+) //)
3716 {
3717 my ($Access, $BInfoId) = ($1, $2);
3718 my $ClassId = getBinfClassId($BInfoId);
Andrey Ponomarenko85043792012-05-14 16:48:07 +04003719 my $CType = $LibInfo{$Version}{"info_type"}{$ClassId};
3720 if(not $CType or $CType eq "template_type_parm"
3721 or $CType eq "typename_type")
3722 { # skip
3723 return 1;
3724 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003725 my $BaseInfo = $LibInfo{$Version}{"info"}{$BInfoId};
3726 if($Access=~/prot/)
3727 {
3728 $TypeAttr->{"Base"}{$ClassId}{"access"} = "protected";
3729 }
3730 elsif($Access=~/priv/)
3731 {
3732 $TypeAttr->{"Base"}{$ClassId}{"access"} = "private";
3733 }
Andrey Ponomarenko01117f12012-06-26 12:23:02 +04003734 $TypeAttr->{"Base"}{$ClassId}{"pos"} = "$Pos";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003735 if($BaseInfo=~/virt/)
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04003736 { # virtual base
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003737 $TypeAttr->{"Base"}{$ClassId}{"virtual"} = 1;
3738 }
3739 $Class_SubClasses{$Version}{$ClassId}{$TypeId}=1;
Andrey Ponomarenko01117f12012-06-26 12:23:02 +04003740 $Pos+=1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003741 }
3742 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +04003743 return 0;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003744}
3745
3746sub getBinfClassId($)
3747{
3748 my $Info = $LibInfo{$Version}{"info"}{$_[0]};
3749 $Info=~/type[ ]*:[ ]*@(\d+) /;
3750 return $1;
3751}
3752
3753sub unmangledFormat($$)
3754{
3755 my ($Name, $LibVersion) = @_;
3756 $Name = uncover_typedefs($Name, $LibVersion);
3757 while($Name=~s/([^\w>*])(const|volatile)(,|>|\Z)/$1$3/g){};
3758 $Name=~s/\(\w+\)(\d)/$1/;
3759 return $Name;
3760}
3761
3762sub modelUnmangled($$)
3763{
3764 my ($InfoId, $Compiler) = @_;
3765 if($Cache{"modelUnmangled"}{$Version}{$Compiler}{$InfoId}) {
3766 return $Cache{"modelUnmangled"}{$Version}{$Compiler}{$InfoId};
3767 }
3768 my $PureSignature = $SymbolInfo{$Version}{$InfoId}{"ShortName"};
3769 if($SymbolInfo{$Version}{$InfoId}{"Destructor"}) {
3770 $PureSignature = "~".$PureSignature;
3771 }
3772 if(not $SymbolInfo{$Version}{$InfoId}{"Data"})
3773 {
3774 my (@Params, @ParamTypes) = ();
3775 if(defined $SymbolInfo{$Version}{$InfoId}{"Param"}
3776 and not $SymbolInfo{$Version}{$InfoId}{"Destructor"}) {
3777 @Params = keys(%{$SymbolInfo{$Version}{$InfoId}{"Param"}});
3778 }
3779 foreach my $ParamPos (sort {int($a) <=> int($b)} @Params)
3780 { # checking parameters
3781 my $PId = $SymbolInfo{$Version}{$InfoId}{"Param"}{$ParamPos}{"type"};
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +04003782 my %PType = get_PureType($PId, $TypeInfo{$Version});
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003783 my $PTName = unmangledFormat($PType{"Name"}, $Version);
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04003784 $PTName=~s/\b(restrict|register)\b//g;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003785 if($Compiler eq "MSVC") {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04003786 $PTName=~s/\blong long\b/__int64/;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003787 }
3788 @ParamTypes = (@ParamTypes, $PTName);
3789 }
3790 if(@ParamTypes) {
3791 $PureSignature .= "(".join(", ", @ParamTypes).")";
3792 }
3793 else
3794 {
3795 if($Compiler eq "MSVC")
3796 {
3797 $PureSignature .= "(void)";
3798 }
3799 else
3800 { # GCC
3801 $PureSignature .= "()";
3802 }
3803 }
3804 $PureSignature = delete_keywords($PureSignature);
3805 }
3806 if(my $ClassId = $SymbolInfo{$Version}{$InfoId}{"Class"})
3807 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04003808 my $ClassName = unmangledFormat($TypeInfo{$Version}{$ClassId}{"Name"}, $Version);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003809 $PureSignature = $ClassName."::".$PureSignature;
3810 }
3811 elsif(my $NS = $SymbolInfo{$Version}{$InfoId}{"NameSpace"}) {
3812 $PureSignature = $NS."::".$PureSignature;
3813 }
3814 if($SymbolInfo{$Version}{$InfoId}{"Const"}) {
3815 $PureSignature .= " const";
3816 }
3817 if($SymbolInfo{$Version}{$InfoId}{"Volatile"}) {
3818 $PureSignature .= " volatile";
3819 }
3820 my $ShowReturn = 0;
3821 if($Compiler eq "MSVC"
3822 and $SymbolInfo{$Version}{$InfoId}{"Data"})
3823 {
3824 $ShowReturn=1;
3825 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04003826 elsif(defined $TemplateInstance{$Version}{"Func"}{$InfoId}
3827 and keys(%{$TemplateInstance{$Version}{"Func"}{$InfoId}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003828 {
3829 $ShowReturn=1;
3830 }
3831 if($ShowReturn)
3832 { # mangled names for template function specializations include return value
3833 if(my $ReturnId = $SymbolInfo{$Version}{$InfoId}{"Return"})
3834 {
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +04003835 my %RType = get_PureType($ReturnId, $TypeInfo{$Version});
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003836 my $ReturnName = unmangledFormat($RType{"Name"}, $Version);
3837 $PureSignature = $ReturnName." ".$PureSignature;
3838 }
3839 }
Andrey Ponomarenko9927e332012-10-19 10:50:48 +04003840 return ($Cache{"modelUnmangled"}{$Version}{$Compiler}{$InfoId} = formatName($PureSignature, "S"));
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003841}
3842
3843sub mangle_symbol($$$)
3844{ # mangling for simple methods
3845 # see gcc-4.6.0/gcc/cp/mangle.c
3846 my ($InfoId, $LibVersion, $Compiler) = @_;
3847 if($Cache{"mangle_symbol"}{$LibVersion}{$InfoId}{$Compiler}) {
3848 return $Cache{"mangle_symbol"}{$LibVersion}{$InfoId}{$Compiler};
3849 }
3850 my $Mangled = "";
3851 if($Compiler eq "GCC") {
Andrey Ponomarenko16934472012-03-29 15:37:04 +04003852 $Mangled = mangle_symbol_GCC($InfoId, $LibVersion);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003853 }
3854 elsif($Compiler eq "MSVC") {
Andrey Ponomarenko16934472012-03-29 15:37:04 +04003855 $Mangled = mangle_symbol_MSVC($InfoId, $LibVersion);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003856 }
3857 return ($Cache{"mangle_symbol"}{$LibVersion}{$InfoId}{$Compiler} = $Mangled);
3858}
3859
Andrey Ponomarenko16934472012-03-29 15:37:04 +04003860sub mangle_symbol_MSVC($$)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003861{
3862 my ($InfoId, $LibVersion) = @_;
3863 return "";
3864}
3865
Andrey Ponomarenko16934472012-03-29 15:37:04 +04003866sub mangle_symbol_GCC($$)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003867{ # see gcc-4.6.0/gcc/cp/mangle.c
3868 my ($InfoId, $LibVersion) = @_;
3869 my ($Mangled, $ClassId, $NameSpace) = ("_Z", 0, "");
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04003870 my $Return = $SymbolInfo{$LibVersion}{$InfoId}{"Return"};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003871 my %Repl = ();# SN_ replacements
3872 if($ClassId = $SymbolInfo{$LibVersion}{$InfoId}{"Class"})
3873 {
3874 my $MangledClass = mangle_param($ClassId, $LibVersion, \%Repl);
3875 if($MangledClass!~/\AN/) {
3876 $MangledClass = "N".$MangledClass;
3877 }
3878 else {
3879 $MangledClass=~s/E\Z//;
3880 }
3881 if($SymbolInfo{$LibVersion}{$InfoId}{"Volatile"}) {
3882 $MangledClass=~s/\AN/NV/;
3883 }
3884 if($SymbolInfo{$LibVersion}{$InfoId}{"Const"}) {
3885 $MangledClass=~s/\AN/NK/;
3886 }
3887 $Mangled .= $MangledClass;
3888 }
3889 elsif($NameSpace = $SymbolInfo{$LibVersion}{$InfoId}{"NameSpace"})
3890 { # mangled by name due to the absence of structured info
3891 my $MangledNS = mangle_ns($NameSpace, $LibVersion, \%Repl);
3892 if($MangledNS!~/\AN/) {
3893 $MangledNS = "N".$MangledNS;
3894 }
3895 else {
3896 $MangledNS=~s/E\Z//;
3897 }
3898 $Mangled .= $MangledNS;
3899 }
Andrey Ponomarenko07aea072012-11-12 16:15:07 +04003900 my ($ShortName, $TmplParams) = template_Base($SymbolInfo{$LibVersion}{$InfoId}{"ShortName"});
Andrey Ponomarenko16934472012-03-29 15:37:04 +04003901 my @TParams = ();
Andrey Ponomarenko35c44fd2012-06-18 17:50:25 +04003902 if(my @TPos = keys(%{$SymbolInfo{$LibVersion}{$InfoId}{"TParam"}}))
Andrey Ponomarenko16934472012-03-29 15:37:04 +04003903 { # parsing mode
Andrey Ponomarenko35c44fd2012-06-18 17:50:25 +04003904 foreach (@TPos) {
3905 push(@TParams, $SymbolInfo{$LibVersion}{$InfoId}{"TParam"}{$_}{"name"});
3906 }
Andrey Ponomarenko16934472012-03-29 15:37:04 +04003907 }
3908 elsif($TmplParams)
3909 { # remangling mode
3910 # support for old ABI dumps
Andrey Ponomarenko07aea072012-11-12 16:15:07 +04003911 @TParams = separate_Params($TmplParams, 0, 0);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003912 }
3913 if($SymbolInfo{$LibVersion}{$InfoId}{"Constructor"}) {
3914 $Mangled .= "C1";
3915 }
3916 elsif($SymbolInfo{$LibVersion}{$InfoId}{"Destructor"}) {
3917 $Mangled .= "D0";
3918 }
3919 elsif($ShortName)
3920 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04003921 if($SymbolInfo{$LibVersion}{$InfoId}{"Data"})
3922 {
Andrey Ponomarenko16934472012-03-29 15:37:04 +04003923 if(not $SymbolInfo{$LibVersion}{$InfoId}{"Class"}
Andrey Ponomarenko85043792012-05-14 16:48:07 +04003924 and isConstType($Return, $LibVersion))
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04003925 { # "const" global data is mangled as _ZL...
3926 $Mangled .= "L";
3927 }
3928 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003929 if($ShortName=~/\Aoperator(\W.*)\Z/)
3930 {
3931 my $Op = $1;
3932 $Op=~s/\A[ ]+//g;
3933 if(my $OpMngl = $OperatorMangling{$Op}) {
3934 $Mangled .= $OpMngl;
3935 }
3936 else { # conversion operator
3937 $Mangled .= "cv".mangle_param(getTypeIdByName($Op, $LibVersion), $LibVersion, \%Repl);
3938 }
3939 }
3940 else {
3941 $Mangled .= length($ShortName).$ShortName;
3942 }
3943 if(@TParams)
3944 { # templates
3945 $Mangled .= "I";
Andrey Ponomarenko07aea072012-11-12 16:15:07 +04003946 my $FP = $TParams[0];
3947 foreach my $TPos (0 .. $#TParams)
3948 {
3949 my $TParam = $TParams[$TPos];
3950 if($TPos>=1)
3951 {
3952 if($TParam=~/\A$DEFAULT_STD_PARMS<\Q$FP\E>\Z/)
3953 { # default allocators are not mangled
3954 next;
3955 }
3956 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003957 $Mangled .= mangle_template_param($TParam, $LibVersion, \%Repl);
3958 }
3959 $Mangled .= "E";
3960 }
3961 if(not $ClassId and @TParams) {
3962 add_substitution($ShortName, \%Repl, 0);
3963 }
3964 }
3965 if($ClassId or $NameSpace) {
3966 $Mangled .= "E";
3967 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +04003968 if(@TParams)
3969 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04003970 if($Return) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003971 $Mangled .= mangle_param($Return, $LibVersion, \%Repl);
3972 }
3973 }
3974 if(not $SymbolInfo{$LibVersion}{$InfoId}{"Data"})
3975 {
3976 my @Params = ();
3977 if(defined $SymbolInfo{$LibVersion}{$InfoId}{"Param"}
3978 and not $SymbolInfo{$LibVersion}{$InfoId}{"Destructor"}) {
3979 @Params = keys(%{$SymbolInfo{$LibVersion}{$InfoId}{"Param"}});
3980 }
3981 foreach my $ParamPos (sort {int($a) <=> int($b)} @Params)
3982 { # checking parameters
3983 my $ParamType_Id = $SymbolInfo{$LibVersion}{$InfoId}{"Param"}{$ParamPos}{"type"};
3984 $Mangled .= mangle_param($ParamType_Id, $LibVersion, \%Repl);
3985 }
3986 if(not @Params) {
3987 $Mangled .= "v";
3988 }
3989 }
3990 $Mangled = correct_incharge($InfoId, $LibVersion, $Mangled);
3991 $Mangled = write_stdcxx_substitution($Mangled);
3992 if($Mangled eq "_Z") {
3993 return "";
3994 }
3995 return $Mangled;
3996}
3997
3998sub correct_incharge($$$)
3999{
4000 my ($InfoId, $LibVersion, $Mangled) = @_;
4001 if($SymbolInfo{$LibVersion}{$InfoId}{"Constructor"})
4002 {
4003 if($MangledNames{$LibVersion}{$Mangled}) {
4004 $Mangled=~s/C1E/C2E/;
4005 }
4006 }
4007 elsif($SymbolInfo{$LibVersion}{$InfoId}{"Destructor"})
4008 {
4009 if($MangledNames{$LibVersion}{$Mangled}) {
4010 $Mangled=~s/D0E/D1E/;
4011 }
4012 if($MangledNames{$LibVersion}{$Mangled}) {
4013 $Mangled=~s/D1E/D2E/;
4014 }
4015 }
4016 return $Mangled;
4017}
4018
Andrey Ponomarenko07aea072012-11-12 16:15:07 +04004019sub template_Base($)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004020{ # NOTE: std::_Vector_base<mysqlpp::mysql_type_info>::_Vector_impl
Andrey Ponomarenko16934472012-03-29 15:37:04 +04004021 # NOTE: operators: >>, <<
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004022 my $Name = $_[0];
Andrey Ponomarenko16934472012-03-29 15:37:04 +04004023 if($Name!~/>\Z/ or $Name!~/</) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004024 return $Name;
4025 }
4026 my $TParams = $Name;
Andrey Ponomarenko16934472012-03-29 15:37:04 +04004027 while(my $CPos = find_center($TParams, "<"))
4028 { # search for the last <T>
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004029 $TParams = substr($TParams, $CPos);
4030 }
Andrey Ponomarenko16934472012-03-29 15:37:04 +04004031 if($TParams=~s/\A<(.+)>\Z/$1/) {
4032 $Name=~s/<\Q$TParams\E>\Z//;
4033 }
4034 else
4035 { # error
4036 $TParams = "";
4037 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004038 return ($Name, $TParams);
4039}
4040
4041sub get_sub_ns($)
4042{
4043 my $Name = $_[0];
4044 my @NS = ();
Andrey Ponomarenko16934472012-03-29 15:37:04 +04004045 while(my $CPos = find_center($Name, ":"))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004046 {
4047 push(@NS, substr($Name, 0, $CPos));
4048 $Name = substr($Name, $CPos);
4049 $Name=~s/\A:://;
4050 }
4051 return (join("::", @NS), $Name);
4052}
4053
4054sub mangle_ns($$$)
4055{
4056 my ($Name, $LibVersion, $Repl) = @_;
4057 if(my $Tid = $TName_Tid{$LibVersion}{$Name})
4058 {
4059 my $Mangled = mangle_param($Tid, $LibVersion, $Repl);
4060 $Mangled=~s/\AN(.+)E\Z/$1/;
4061 return $Mangled;
4062
4063 }
4064 else
4065 {
4066 my ($MangledNS, $SubNS) = ("", "");
4067 ($SubNS, $Name) = get_sub_ns($Name);
4068 if($SubNS) {
4069 $MangledNS .= mangle_ns($SubNS, $LibVersion, $Repl);
4070 }
4071 $MangledNS .= length($Name).$Name;
4072 add_substitution($MangledNS, $Repl, 0);
4073 return $MangledNS;
4074 }
4075}
4076
4077sub mangle_param($$$)
4078{
4079 my ($PTid, $LibVersion, $Repl) = @_;
4080 my ($MPrefix, $Mangled) = ("", "");
4081 my %ReplCopy = %{$Repl};
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04004082 my %BaseType = get_BaseType($PTid, $LibVersion);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004083 my $BaseType_Name = $BaseType{"Name"};
4084 if(not $BaseType_Name) {
4085 return "";
4086 }
Andrey Ponomarenko07aea072012-11-12 16:15:07 +04004087 my ($ShortName, $TmplParams) = template_Base($BaseType_Name);
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04004088 my $Suffix = get_BaseTypeQual($PTid, $LibVersion);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004089 while($Suffix=~s/\s*(const|volatile|restrict)\Z//g){};
4090 while($Suffix=~/(&|\*|const)\Z/)
4091 {
4092 if($Suffix=~s/[ ]*&\Z//) {
4093 $MPrefix .= "R";
4094 }
4095 if($Suffix=~s/[ ]*\*\Z//) {
4096 $MPrefix .= "P";
4097 }
4098 if($Suffix=~s/[ ]*const\Z//)
4099 {
4100 if($MPrefix=~/R|P/
4101 or $Suffix=~/&|\*/) {
4102 $MPrefix .= "K";
4103 }
4104 }
4105 if($Suffix=~s/[ ]*volatile\Z//) {
4106 $MPrefix .= "V";
4107 }
4108 #if($Suffix=~s/[ ]*restrict\Z//) {
4109 #$MPrefix .= "r";
4110 #}
4111 }
4112 if(my $Token = $IntrinsicMangling{$BaseType_Name}) {
4113 $Mangled .= $Token;
4114 }
4115 elsif($BaseType{"Type"}=~/(Class|Struct|Union|Enum)/)
4116 {
Andrey Ponomarenko16934472012-03-29 15:37:04 +04004117 my @TParams = ();
Andrey Ponomarenko35c44fd2012-06-18 17:50:25 +04004118 if(my @TPos = keys(%{$BaseType{"TParam"}}))
Andrey Ponomarenko16934472012-03-29 15:37:04 +04004119 { # parsing mode
Andrey Ponomarenko35c44fd2012-06-18 17:50:25 +04004120 foreach (@TPos) {
4121 push(@TParams, $BaseType{"TParam"}{$_}{"name"});
4122 }
Andrey Ponomarenko16934472012-03-29 15:37:04 +04004123 }
4124 elsif($TmplParams)
4125 { # remangling mode
4126 # support for old ABI dumps
Andrey Ponomarenko07aea072012-11-12 16:15:07 +04004127 @TParams = separate_Params($TmplParams, 0, 0);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004128 }
4129 my $MangledNS = "";
4130 my ($SubNS, $SName) = get_sub_ns($ShortName);
4131 if($SubNS) {
4132 $MangledNS .= mangle_ns($SubNS, $LibVersion, $Repl);
4133 }
4134 $MangledNS .= length($SName).$SName;
4135 if(@TParams) {
4136 add_substitution($MangledNS, $Repl, 0);
4137 }
4138 $Mangled .= "N".$MangledNS;
4139 if(@TParams)
4140 { # templates
4141 $Mangled .= "I";
4142 foreach my $TParam (@TParams) {
4143 $Mangled .= mangle_template_param($TParam, $LibVersion, $Repl);
4144 }
4145 $Mangled .= "E";
4146 }
4147 $Mangled .= "E";
4148 }
4149 elsif($BaseType{"Type"}=~/(FuncPtr|MethodPtr)/)
4150 {
4151 if($BaseType{"Type"} eq "MethodPtr") {
4152 $Mangled .= "M".mangle_param($BaseType{"Class"}, $LibVersion, $Repl)."F";
4153 }
4154 else {
4155 $Mangled .= "PF";
4156 }
4157 $Mangled .= mangle_param($BaseType{"Return"}, $LibVersion, $Repl);
4158 my @Params = keys(%{$BaseType{"Param"}});
4159 foreach my $Num (sort {int($a)<=>int($b)} @Params) {
4160 $Mangled .= mangle_param($BaseType{"Param"}{$Num}{"type"}, $LibVersion, $Repl);
4161 }
4162 if(not @Params) {
4163 $Mangled .= "v";
4164 }
4165 $Mangled .= "E";
4166 }
4167 elsif($BaseType{"Type"} eq "FieldPtr")
4168 {
4169 $Mangled .= "M".mangle_param($BaseType{"Class"}, $LibVersion, $Repl);
4170 $Mangled .= mangle_param($BaseType{"Return"}, $LibVersion, $Repl);
4171 }
4172 $Mangled = $MPrefix.$Mangled;# add prefix (RPK)
4173 if(my $Optimized = write_substitution($Mangled, \%ReplCopy))
4174 {
4175 if($Mangled eq $Optimized)
4176 {
4177 if($ShortName!~/::/)
4178 { # remove "N ... E"
4179 if($MPrefix) {
4180 $Mangled=~s/\A($MPrefix)N(.+)E\Z/$1$2/g;
4181 }
4182 else {
4183 $Mangled=~s/\AN(.+)E\Z/$1/g;
4184 }
4185 }
4186 }
4187 else {
4188 $Mangled = $Optimized;
4189 }
4190 }
4191 add_substitution($Mangled, $Repl, 1);
4192 return $Mangled;
4193}
4194
4195sub mangle_template_param($$$)
4196{ # types + literals
4197 my ($TParam, $LibVersion, $Repl) = @_;
4198 if(my $TPTid = $TName_Tid{$LibVersion}{$TParam}) {
4199 return mangle_param($TPTid, $LibVersion, $Repl);
4200 }
4201 elsif($TParam=~/\A(\d+)(\w+)\Z/)
4202 { # class_name<1u>::method(...)
4203 return "L".$IntrinsicMangling{$ConstantSuffixR{$2}}.$1."E";
4204 }
4205 elsif($TParam=~/\A\(([\w ]+)\)(\d+)\Z/)
4206 { # class_name<(signed char)1>::method(...)
4207 return "L".$IntrinsicMangling{$1}.$2."E";
4208 }
4209 elsif($TParam eq "true")
4210 { # class_name<true>::method(...)
4211 return "Lb1E";
4212 }
4213 elsif($TParam eq "false")
4214 { # class_name<true>::method(...)
4215 return "Lb0E";
4216 }
4217 else { # internal error
4218 return length($TParam).$TParam;
4219 }
4220}
4221
4222sub add_substitution($$$)
4223{
4224 my ($Value, $Repl, $Rec) = @_;
4225 if($Rec)
4226 { # subtypes
4227 my @Subs = ($Value);
4228 while($Value=~s/\A(R|P|K)//) {
4229 push(@Subs, $Value);
4230 }
4231 foreach (reverse(@Subs)) {
4232 add_substitution($_, $Repl, 0);
4233 }
4234 return;
4235 }
4236 return if($Value=~/\AS(\d*)_\Z/);
4237 $Value=~s/\AN(.+)E\Z/$1/g;
4238 return if(defined $Repl->{$Value});
4239 return if(length($Value)<=1);
4240 return if($StdcxxMangling{$Value});
4241 # check for duplicates
4242 my $Base = $Value;
4243 foreach my $Type (sort {$Repl->{$a}<=>$Repl->{$b}} sort keys(%{$Repl}))
4244 {
4245 my $Num = $Repl->{$Type};
4246 my $Replace = macro_mangle($Num);
4247 $Base=~s/\Q$Replace\E/$Type/;
4248 }
4249 if(my $OldNum = $Repl->{$Base})
4250 {
4251 $Repl->{$Value} = $OldNum;
4252 return;
4253 }
4254 my @Repls = sort {$b<=>$a} values(%{$Repl});
4255 if(@Repls) {
4256 $Repl->{$Value} = $Repls[0]+1;
4257 }
4258 else {
4259 $Repl->{$Value} = -1;
4260 }
4261 # register duplicates
4262 # upward
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04004263 $Base = $Value;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004264 foreach my $Type (sort {$Repl->{$a}<=>$Repl->{$b}} sort keys(%{$Repl}))
4265 {
4266 next if($Base eq $Type);
4267 my $Num = $Repl->{$Type};
4268 my $Replace = macro_mangle($Num);
4269 $Base=~s/\Q$Type\E/$Replace/;
4270 $Repl->{$Base} = $Repl->{$Value};
4271 }
4272}
4273
4274sub macro_mangle($)
4275{
4276 my $Num = $_[0];
4277 if($Num==-1) {
4278 return "S_";
4279 }
4280 else
4281 {
4282 my $Code = "";
4283 if($Num<10)
4284 { # S0_, S1_, S2_, ...
4285 $Code = $Num;
4286 }
4287 elsif($Num>=10 and $Num<=35)
4288 { # SA_, SB_, SC_, ...
4289 $Code = chr(55+$Num);
4290 }
4291 else
4292 { # S10_, S11_, S12_
4293 $Code = $Num-26; # 26 is length of english alphabet
4294 }
4295 return "S".$Code."_";
4296 }
4297}
4298
4299sub write_stdcxx_substitution($)
4300{
4301 my $Mangled = $_[0];
4302 if($StdcxxMangling{$Mangled}) {
4303 return $StdcxxMangling{$Mangled};
4304 }
4305 else
4306 {
4307 my @Repls = keys(%StdcxxMangling);
4308 @Repls = sort {length($b)<=>length($a)} sort {$b cmp $a} @Repls;
4309 foreach my $MangledType (@Repls)
4310 {
4311 my $Replace = $StdcxxMangling{$MangledType};
4312 #if($Mangled!~/$Replace/) {
4313 $Mangled=~s/N\Q$MangledType\EE/$Replace/g;
4314 $Mangled=~s/\Q$MangledType\E/$Replace/g;
4315 #}
4316 }
4317 }
4318 return $Mangled;
4319}
4320
4321sub write_substitution($$)
4322{
4323 my ($Mangled, $Repl) = @_;
4324 if(defined $Repl->{$Mangled}
4325 and my $MnglNum = $Repl->{$Mangled}) {
4326 $Mangled = macro_mangle($MnglNum);
4327 }
4328 else
4329 {
4330 my @Repls = keys(%{$Repl});
4331 #@Repls = sort {$Repl->{$a}<=>$Repl->{$b}} @Repls;
4332 # FIXME: how to apply replacements? by num or by pos
4333 @Repls = sort {length($b)<=>length($a)} sort {$b cmp $a} @Repls;
4334 foreach my $MangledType (@Repls)
4335 {
4336 my $Replace = macro_mangle($Repl->{$MangledType});
4337 if($Mangled!~/$Replace/) {
4338 $Mangled=~s/N\Q$MangledType\EE/$Replace/g;
4339 $Mangled=~s/\Q$MangledType\E/$Replace/g;
4340 }
4341 }
4342 }
4343 return $Mangled;
4344}
4345
4346sub delete_keywords($)
4347{
4348 my $TypeName = $_[0];
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04004349 $TypeName=~s/\b(enum|struct|union|class) //g;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004350 return $TypeName;
4351}
4352
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004353sub uncover_typedefs($$)
4354{
4355 my ($TypeName, $LibVersion) = @_;
4356 return "" if(not $TypeName);
4357 if(defined $Cache{"uncover_typedefs"}{$LibVersion}{$TypeName}) {
4358 return $Cache{"uncover_typedefs"}{$LibVersion}{$TypeName};
4359 }
Andrey Ponomarenko9927e332012-10-19 10:50:48 +04004360 my ($TypeName_New, $TypeName_Pre) = (formatName($TypeName, "T"), "");
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004361 while($TypeName_New ne $TypeName_Pre)
4362 {
4363 $TypeName_Pre = $TypeName_New;
4364 my $TypeName_Copy = $TypeName_New;
4365 my %Words = ();
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04004366 while($TypeName_Copy=~s/\b([a-z_]([\w:]*\w|))\b//io)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004367 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04004368 if(not $Intrinsic_Keywords{$1}) {
4369 $Words{$1} = 1;
4370 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004371 }
4372 foreach my $Word (keys(%Words))
4373 {
4374 my $BaseType_Name = $Typedef_BaseName{$LibVersion}{$Word};
4375 next if(not $BaseType_Name);
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04004376 next if($TypeName_New=~/\b(struct|union|enum)\s\Q$Word\E\b/);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004377 if($BaseType_Name=~/\([\*]+\)/)
4378 { # FuncPtr
4379 if($TypeName_New=~/\Q$Word\E(.*)\Z/)
4380 {
4381 my $Type_Suffix = $1;
4382 $TypeName_New = $BaseType_Name;
4383 if($TypeName_New=~s/\(([\*]+)\)/($1 $Type_Suffix)/) {
Andrey Ponomarenko9927e332012-10-19 10:50:48 +04004384 $TypeName_New = formatName($TypeName_New, "T");
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004385 }
4386 }
4387 }
4388 else
4389 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04004390 if($TypeName_New=~s/\b\Q$Word\E\b/$BaseType_Name/g) {
Andrey Ponomarenko9927e332012-10-19 10:50:48 +04004391 $TypeName_New = formatName($TypeName_New, "T");
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004392 }
4393 }
4394 }
4395 }
4396 return ($Cache{"uncover_typedefs"}{$LibVersion}{$TypeName} = $TypeName_New);
4397}
4398
4399sub isInternal($)
4400{
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04004401 if($_[0] and my $Info = $LibInfo{$Version}{"info"}{$_[0]})
4402 {
4403 if($Info=~/mngl[ ]*:[ ]*@(\d+) /)
4404 {
4405 if($LibInfo{$Version}{"info"}{$1}=~/\*[ ]*INTERNAL[ ]*\*/)
4406 { # _ZN7mysqlpp8DateTimeC1ERKS0_ *INTERNAL*
4407 return 1;
4408 }
4409 }
4410 }
4411 return 0;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004412}
4413
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04004414sub getDataVal($$)
4415{
4416 my ($InfoId, $TypeId) = @_;
4417 if(my $Info = $LibInfo{$Version}{"info"}{$InfoId})
4418 {
4419 if($Info=~/init[ ]*:[ ]*@(\d+) /)
4420 {
4421 if(defined $LibInfo{$Version}{"info_type"}{$1}
4422 and $LibInfo{$Version}{"info_type"}{$1} eq "nop_expr")
4423 { # char const* data = "str"
4424 # NOTE: disabled
4425 if(my $NopExpr = $LibInfo{$Version}{"info"}{$1})
4426 {
4427 if($NopExpr=~/op 0[ ]*:[ ]*@(\d+) /)
4428 {
4429 if(defined $LibInfo{$Version}{"info_type"}{$1}
4430 and $LibInfo{$Version}{"info_type"}{$1} eq "addr_expr")
4431 {
4432 if(my $AddrExpr = $LibInfo{$Version}{"info"}{$1})
4433 {
4434 if($AddrExpr=~/op 0[ ]*:[ ]*@(\d+) /)
4435 {
4436 return getInitVal($1, $TypeId);
4437 }
4438 }
4439 }
4440 }
4441 }
4442 }
4443 else {
4444 return getInitVal($1, $TypeId);
4445 }
4446 }
4447 }
4448 return undef;
4449}
4450
4451sub getInitVal($$)
4452{
4453 my ($InfoId, $TypeId) = @_;
4454 if(my $Info = $LibInfo{$Version}{"info"}{$InfoId})
4455 {
4456 if(my $InfoType = $LibInfo{$Version}{"info_type"}{$InfoId})
4457 {
4458 if($InfoType eq "integer_cst")
4459 {
4460 my $Val = getNodeIntCst($InfoId);
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04004461 if($TypeId and $TypeInfo{$Version}{$TypeId}{"Name"}=~/\Achar(| const)\Z/)
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04004462 { # characters
4463 $Val = chr($Val);
4464 }
4465 return $Val;
4466 }
4467 elsif($InfoType eq "string_cst") {
4468 return getNodeStrCst($InfoId);
4469 }
Andrey Ponomarenko01117f12012-06-26 12:23:02 +04004470 elsif($InfoType eq "var_decl")
4471 {
4472 if(my $Name = getNodeStrCst(getTreeAttr_Mngl($InfoId))) {
4473 return $Name;
4474 }
4475 }
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04004476 }
4477 }
4478 return undef;
4479}
4480
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004481sub set_Class_And_Namespace($)
4482{
4483 my $InfoId = $_[0];
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04004484 if(my $Info = $LibInfo{$Version}{"info"}{$InfoId})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004485 {
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04004486 if($Info=~/scpe[ ]*:[ ]*@(\d+) /)
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04004487 {
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04004488 my $NSInfoId = $1;
4489 if(my $InfoType = $LibInfo{$Version}{"info_type"}{$NSInfoId})
4490 {
4491 if($InfoType eq "namespace_decl") {
4492 $SymbolInfo{$Version}{$InfoId}{"NameSpace"} = getNameSpace($InfoId);
4493 }
4494 elsif($InfoType eq "record_type") {
4495 $SymbolInfo{$Version}{$InfoId}{"Class"} = $NSInfoId;
4496 }
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04004497 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004498 }
4499 }
4500 if($SymbolInfo{$Version}{$InfoId}{"Class"}
4501 or $SymbolInfo{$Version}{$InfoId}{"NameSpace"})
4502 { # identify language
4503 setLanguage($Version, "C++");
4504 }
4505}
4506
4507sub debugType($$)
4508{
4509 my ($Tid, $LibVersion) = @_;
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04004510 my %Type = get_Type($Tid, $LibVersion);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004511 printMsg("INFO", Dumper(\%Type));
4512}
4513
4514sub debugMangling($)
4515{
4516 my $LibVersion = $_[0];
4517 my %Mangled = ();
4518 foreach my $InfoId (keys(%{$SymbolInfo{$LibVersion}}))
4519 {
4520 if(my $Mngl = $SymbolInfo{$LibVersion}{$InfoId}{"MnglName"})
4521 {
4522 if($Mngl=~/\A(_Z|\?)/) {
4523 $Mangled{$Mngl}=$InfoId;
4524 }
4525 }
4526 }
4527 translateSymbols(keys(%Mangled), $LibVersion);
4528 foreach my $Mngl (keys(%Mangled))
4529 {
Andrey Ponomarenko85043792012-05-14 16:48:07 +04004530 my $U1 = modelUnmangled($Mangled{$Mngl}, "GCC");
4531 my $U2 = $tr_name{$Mngl};
4532 if($U1 ne $U2) {
4533 printMsg("INFO", "INCORRECT MANGLING:\n $Mngl\n $U1\n $U2\n");
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004534 }
4535 }
4536}
4537
4538sub linkSymbol($)
4539{ # link symbols from shared libraries
4540 # with the symbols from header files
4541 my $InfoId = $_[0];
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004542 # try to mangle symbol
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04004543 if((not check_gcc($GCC_PATH, "4") and $SymbolInfo{$Version}{$InfoId}{"Class"})
4544 or (check_gcc($GCC_PATH, "4") and not $SymbolInfo{$Version}{$InfoId}{"Class"}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004545 { # 1. GCC 3.x doesn't mangle class methods names in the TU dump (only functions and global data)
4546 # 2. GCC 4.x doesn't mangle C++ functions in the TU dump (only class methods) except extern "C" functions
Andrey Ponomarenko16934472012-03-29 15:37:04 +04004547 if(not $CheckHeadersOnly)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004548 {
4549 if(my $Mangled = $mangled_name_gcc{modelUnmangled($InfoId, "GCC")}) {
4550 return correct_incharge($InfoId, $Version, $Mangled);
4551 }
4552 }
Andrey Ponomarenko16934472012-03-29 15:37:04 +04004553 if($CheckHeadersOnly
4554 or not $BinaryOnly)
4555 { # 1. --headers-only mode
4556 # 2. not mangled src-only symbols
4557 if(my $Mangled = mangle_symbol($InfoId, $Version, "GCC")) {
4558 return $Mangled;
4559 }
4560 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004561 }
4562 return "";
4563}
4564
4565sub setLanguage($$)
4566{
4567 my ($LibVersion, $Lang) = @_;
4568 if(not $UserLang) {
4569 $COMMON_LANGUAGE{$LibVersion} = $Lang;
4570 }
4571}
4572
4573sub getSymbolInfo($)
4574{
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04004575 my $InfoId = $_[0];
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04004576 if(isInternal($InfoId)) {
4577 return;
4578 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04004579 ($SymbolInfo{$Version}{$InfoId}{"Header"}, $SymbolInfo{$Version}{$InfoId}{"Line"}) = getLocation($InfoId);
4580 if(not $SymbolInfo{$Version}{$InfoId}{"Header"}
Andrey Ponomarenkoa01311b2012-06-08 17:20:02 +04004581 or isBuiltIn($SymbolInfo{$Version}{$InfoId}{"Header"}))
4582 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04004583 delete($SymbolInfo{$Version}{$InfoId});
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004584 return;
4585 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04004586 setFuncAccess($InfoId);
4587 setFuncKind($InfoId);
Andrey Ponomarenkoa01311b2012-06-08 17:20:02 +04004588 if($SymbolInfo{$Version}{$InfoId}{"PseudoTemplate"})
4589 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04004590 delete($SymbolInfo{$Version}{$InfoId});
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004591 return;
4592 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04004593 $SymbolInfo{$Version}{$InfoId}{"Type"} = getFuncType($InfoId);
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04004594 if($SymbolInfo{$Version}{$InfoId}{"Return"} = getFuncReturn($InfoId))
4595 {
4596 if(not $TypeInfo{$Version}{$SymbolInfo{$Version}{$InfoId}{"Return"}}{"Name"})
4597 { # templates
4598 delete($SymbolInfo{$Version}{$InfoId});
4599 return;
4600 }
4601 }
4602 if(my $Rid = $SymbolInfo{$Version}{$InfoId}{"Return"})
4603 {
4604 if(defined $MissedTypedef{$Version}{$Rid})
4605 {
4606 if(my $AddedTid = $MissedTypedef{$Version}{$Rid}{"Tid"}) {
4607 $SymbolInfo{$Version}{$InfoId}{"Return"} = $AddedTid;
4608 }
4609 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004610 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04004611 if(not $SymbolInfo{$Version}{$InfoId}{"Return"}) {
4612 delete($SymbolInfo{$Version}{$InfoId}{"Return"});
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004613 }
Andrey Ponomarenkoa01311b2012-06-08 17:20:02 +04004614 my $Orig = getFuncOrig($InfoId);
4615 $SymbolInfo{$Version}{$InfoId}{"ShortName"} = getFuncShortName($Orig);
4616 if($SymbolInfo{$Version}{$InfoId}{"ShortName"}=~/\._/)
4617 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04004618 delete($SymbolInfo{$Version}{$InfoId});
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004619 return;
4620 }
Andrey Ponomarenkoa01311b2012-06-08 17:20:02 +04004621
4622 if(defined $TemplateInstance{$Version}{"Func"}{$Orig})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004623 {
Andrey Ponomarenkoa01311b2012-06-08 17:20:02 +04004624 my @TParams = getTParams($Orig, "Func");
4625 if(not @TParams)
4626 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04004627 delete($SymbolInfo{$Version}{$InfoId});
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004628 return;
4629 }
Andrey Ponomarenko16934472012-03-29 15:37:04 +04004630 foreach my $Pos (0 .. $#TParams) {
4631 $SymbolInfo{$Version}{$InfoId}{"TParam"}{$Pos}{"name"}=$TParams[$Pos];
4632 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004633 my $PrmsInLine = join(", ", @TParams);
Andrey Ponomarenko16934472012-03-29 15:37:04 +04004634 if($SymbolInfo{$Version}{$InfoId}{"ShortName"}=~/\Aoperator\W+\Z/)
4635 { # operator<< <T>, operator>> <T>
4636 $SymbolInfo{$Version}{$InfoId}{"ShortName"} .= " ";
4637 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04004638 $SymbolInfo{$Version}{$InfoId}{"ShortName"} .= "<".$PrmsInLine.">";
Andrey Ponomarenko9927e332012-10-19 10:50:48 +04004639 $SymbolInfo{$Version}{$InfoId}{"ShortName"} = formatName($SymbolInfo{$Version}{$InfoId}{"ShortName"}, "S");
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004640 }
4641 else
4642 { # support for GCC 3.4
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04004643 $SymbolInfo{$Version}{$InfoId}{"ShortName"}=~s/<.+>\Z//;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004644 }
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +04004645 if(my $MnglName = getTreeStr(getTreeAttr_Mngl($InfoId)))
4646 {
4647 if($OSgroup eq "windows")
4648 { # cut the offset
4649 $MnglName=~s/\@\d+\Z//g;
4650 }
4651 $SymbolInfo{$Version}{$InfoId}{"MnglName"} = $MnglName;
4652
4653 # NOTE: mangling of some symbols may change depending on GCC version
4654 # GCC 4.6: _ZN28QExplicitlySharedDataPointerI11QPixmapDataEC2IT_EERKS_IT_E
4655 # GCC 4.7: _ZN28QExplicitlySharedDataPointerI11QPixmapDataEC2ERKS1_
4656 }
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04004657
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04004658 if($SymbolInfo{$Version}{$InfoId}{"MnglName"}
Andrey Ponomarenko9927e332012-10-19 10:50:48 +04004659 and index($SymbolInfo{$Version}{$InfoId}{"MnglName"}, "_Z")!=0)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004660 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04004661 delete($SymbolInfo{$Version}{$InfoId});
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004662 return;
4663 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04004664 if(not $SymbolInfo{$Version}{$InfoId}{"Destructor"})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004665 { # destructors have an empty parameter list
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04004666 my $Skip = setFuncParams($InfoId);
Andrey Ponomarenko07aea072012-11-12 16:15:07 +04004667 if($Skip)
4668 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04004669 delete($SymbolInfo{$Version}{$InfoId});
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004670 return;
4671 }
4672 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04004673 set_Class_And_Namespace($InfoId);
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04004674 if(my $ClassId = $SymbolInfo{$Version}{$InfoId}{"Class"})
4675 {
4676 if(not $TypeInfo{$Version}{$ClassId}{"Name"})
4677 { # templates
4678 delete($SymbolInfo{$Version}{$InfoId});
4679 return;
4680 }
4681 }
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04004682 if(not $CheckHeadersOnly)
4683 {
4684 if($SymbolInfo{$Version}{$InfoId}{"Type"} eq "Function"
4685 and not $SymbolInfo{$Version}{$InfoId}{"Class"}
4686 and link_symbol($SymbolInfo{$Version}{$InfoId}{"ShortName"}, $Version, "-Deps"))
4687 { # functions (C++): not mangled in library, but are mangled in TU dump
4688 if(not $SymbolInfo{$Version}{$InfoId}{"MnglName"}
4689 or not link_symbol($SymbolInfo{$Version}{$InfoId}{"MnglName"}, $Version, "-Deps")) {
4690 $SymbolInfo{$Version}{$InfoId}{"MnglName"} = $SymbolInfo{$Version}{$InfoId}{"ShortName"};
4691 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004692 }
4693 }
Andrey Ponomarenko35c44fd2012-06-18 17:50:25 +04004694 if($LibInfo{$Version}{"info"}{$InfoId}=~/ lang:[ ]*C /i)
4695 { # extern "C"
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04004696 $SymbolInfo{$Version}{$InfoId}{"Lang"} = "C";
Andrey Ponomarenko35c44fd2012-06-18 17:50:25 +04004697 $SymbolInfo{$Version}{$InfoId}{"MnglName"} = $SymbolInfo{$Version}{$InfoId}{"ShortName"};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004698 }
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04004699 if($UserLang and $UserLang eq "C")
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004700 { # --lang=C option
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04004701 $SymbolInfo{$Version}{$InfoId}{"MnglName"} = $SymbolInfo{$Version}{$InfoId}{"ShortName"};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004702 }
4703 if($COMMON_LANGUAGE{$Version} eq "C++")
4704 { # correct mangled & short names
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04004705 # C++ or --headers-only mode
4706 if($SymbolInfo{$Version}{$InfoId}{"ShortName"}=~/\A__(comp|base|deleting)_(c|d)tor\Z/)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004707 { # support for old GCC versions: reconstruct real names for constructors and destructors
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04004708 $SymbolInfo{$Version}{$InfoId}{"ShortName"} = getNameByInfo(getTypeDeclId($SymbolInfo{$Version}{$InfoId}{"Class"}));
4709 $SymbolInfo{$Version}{$InfoId}{"ShortName"}=~s/<.+>\Z//;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004710 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04004711 if(not $SymbolInfo{$Version}{$InfoId}{"MnglName"})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004712 { # try to mangle symbol (link with libraries)
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04004713 if(my $Mangled = linkSymbol($InfoId)) {
4714 $SymbolInfo{$Version}{$InfoId}{"MnglName"} = $Mangled;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004715 }
4716 }
4717 if($OStarget eq "windows")
4718 { # link MS C++ symbols from library with GCC symbols from headers
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04004719 if(my $Mangled1 = $mangled_name{$Version}{modelUnmangled($InfoId, "MSVC")})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004720 { # exported symbols
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04004721 $SymbolInfo{$Version}{$InfoId}{"MnglName"} = $Mangled1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004722 }
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04004723 elsif(my $Mangled2 = mangle_symbol($InfoId, $Version, "MSVC"))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004724 { # pure virtual symbols
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04004725 $SymbolInfo{$Version}{$InfoId}{"MnglName"} = $Mangled2;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004726 }
4727 }
4728 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04004729 if(not $SymbolInfo{$Version}{$InfoId}{"MnglName"})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004730 { # can't detect symbol name
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04004731 delete($SymbolInfo{$Version}{$InfoId});
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004732 return;
4733 }
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04004734 if(not $SymbolInfo{$Version}{$InfoId}{"Constructor"}
Andrey Ponomarenkoa01311b2012-06-08 17:20:02 +04004735 and my $Spec = getVirtSpec($Orig))
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04004736 { # identify virtual and pure virtual functions
4737 # NOTE: constructors cannot be virtual
4738 # NOTE: in GCC 4.7 D1 destructors have no virtual spec
4739 # in the TU dump, so taking it from the original symbol
4740 if(not ($SymbolInfo{$Version}{$InfoId}{"Destructor"}
4741 and $SymbolInfo{$Version}{$InfoId}{"MnglName"}=~/D2E/))
4742 { # NOTE: D2 destructors are not present in a v-table
4743 $SymbolInfo{$Version}{$InfoId}{$Spec} = 1;
4744 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004745 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04004746 if(isInline($InfoId)) {
4747 $SymbolInfo{$Version}{$InfoId}{"InLine"} = 1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004748 }
Andrey Ponomarenkob8d203d2012-05-25 18:11:07 +04004749 if($LibInfo{$Version}{"info"}{$InfoId}=~/ artificial /i) {
4750 $SymbolInfo{$Version}{$InfoId}{"Artificial"} = 1;
4751 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04004752 if($SymbolInfo{$Version}{$InfoId}{"Constructor"}
4753 and my $ClassId = $SymbolInfo{$Version}{$InfoId}{"Class"})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004754 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04004755 if(not $SymbolInfo{$Version}{$InfoId}{"InLine"}
Andrey Ponomarenkob8d203d2012-05-25 18:11:07 +04004756 and not $SymbolInfo{$Version}{$InfoId}{"Artificial"})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004757 { # inline or auto-generated constructor
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04004758 delete($TypeInfo{$Version}{$ClassId}{"Copied"});
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004759 }
4760 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +04004761 if(my $Symbol = $SymbolInfo{$Version}{$InfoId}{"MnglName"})
4762 {
Andrey Ponomarenko35c44fd2012-06-18 17:50:25 +04004763 if(not selectSymbol($Symbol, $SymbolInfo{$Version}{$InfoId}, "Dump", $Version))
4764 { # non-target symbols
4765 delete($SymbolInfo{$Version}{$InfoId});
4766 return;
Andrey Ponomarenko85043792012-05-14 16:48:07 +04004767 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004768 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04004769 if($SymbolInfo{$Version}{$InfoId}{"Type"} eq "Method"
4770 or $SymbolInfo{$Version}{$InfoId}{"Constructor"}
4771 or $SymbolInfo{$Version}{$InfoId}{"Destructor"}
4772 or $SymbolInfo{$Version}{$InfoId}{"Class"})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004773 {
Andrey Ponomarenko9927e332012-10-19 10:50:48 +04004774 if($SymbolInfo{$Version}{$InfoId}{"MnglName"}!~/\A(_Z|\?)/)
4775 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04004776 delete($SymbolInfo{$Version}{$InfoId});
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004777 return;
4778 }
4779 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04004780 if($SymbolInfo{$Version}{$InfoId}{"MnglName"})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004781 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04004782 if($MangledNames{$Version}{$SymbolInfo{$Version}{$InfoId}{"MnglName"}})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004783 { # one instance for one mangled name only
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04004784 delete($SymbolInfo{$Version}{$InfoId});
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004785 return;
4786 }
4787 else {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04004788 $MangledNames{$Version}{$SymbolInfo{$Version}{$InfoId}{"MnglName"}} = 1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004789 }
4790 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04004791 if($SymbolInfo{$Version}{$InfoId}{"Constructor"}
4792 or $SymbolInfo{$Version}{$InfoId}{"Destructor"}) {
4793 delete($SymbolInfo{$Version}{$InfoId}{"Return"});
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004794 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04004795 if($SymbolInfo{$Version}{$InfoId}{"MnglName"}=~/\A(_Z|\?)/
4796 and $SymbolInfo{$Version}{$InfoId}{"Class"})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004797 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04004798 if($SymbolInfo{$Version}{$InfoId}{"Type"} eq "Function")
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004799 { # static methods
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04004800 $SymbolInfo{$Version}{$InfoId}{"Static"} = 1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004801 }
4802 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04004803 if(getFuncLink($InfoId) eq "Static") {
4804 $SymbolInfo{$Version}{$InfoId}{"Static"} = 1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004805 }
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04004806 if($SymbolInfo{$Version}{$InfoId}{"MnglName"}=~/\A(_Z|\?)/)
4807 {
4808 if(my $Unmangled = $tr_name{$SymbolInfo{$Version}{$InfoId}{"MnglName"}})
4809 {
Andrey Ponomarenko9927e332012-10-19 10:50:48 +04004810 if($Unmangled=~/\.\_\d/)
4811 {
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04004812 delete($SymbolInfo{$Version}{$InfoId});
4813 return;
4814 }
4815 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004816 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04004817 delete($SymbolInfo{$Version}{$InfoId}{"Type"});
4818 if($SymbolInfo{$Version}{$InfoId}{"MnglName"}=~/\A_ZN(V|)K/) {
4819 $SymbolInfo{$Version}{$InfoId}{"Const"} = 1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004820 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04004821 if($SymbolInfo{$Version}{$InfoId}{"MnglName"}=~/\A_ZN(K|)V/) {
4822 $SymbolInfo{$Version}{$InfoId}{"Volatile"} = 1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004823 }
Andrey Ponomarenko07aea072012-11-12 16:15:07 +04004824
4825 if($WeakSymbols{$Version}{$SymbolInfo{$Version}{$InfoId}{"MnglName"}}) {
4826 $SymbolInfo{$Version}{$InfoId}{"Weak"} = 1;
4827 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004828}
4829
4830sub isInline($)
4831{ # "body: undefined" in the tree
4832 # -fkeep-inline-functions GCC option should be specified
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04004833 if($_[0] and my $Info = $LibInfo{$Version}{"info"}{$_[0]})
4834 {
4835 if($Info=~/ undefined /i) {
4836 return 0;
4837 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004838 }
4839 return 1;
4840}
4841
4842sub getTypeId($)
4843{
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04004844 if($_[0] and my $Info = $LibInfo{$Version}{"info"}{$_[0]})
4845 {
4846 if($Info=~/type[ ]*:[ ]*@(\d+) /) {
4847 return $1;
4848 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004849 }
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04004850 return "";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004851}
4852
4853sub setTypeMemb($$)
4854{
4855 my ($TypeId, $TypeAttr) = @_;
4856 my $TypeType = $TypeAttr->{"Type"};
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04004857 my ($Pos, $UnnamedPos) = (0, 0);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004858 if($TypeType eq "Enum")
4859 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04004860 my $TypeMembInfoId = getTreeAttr_Csts($TypeId);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004861 while($TypeMembInfoId)
4862 {
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04004863 $TypeAttr->{"Memb"}{$Pos}{"value"} = getEnumMembVal($TypeMembInfoId);
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04004864 my $MembName = getTreeStr(getTreeAttr_Purp($TypeMembInfoId));
4865 $TypeAttr->{"Memb"}{$Pos}{"name"} = $MembName;
4866 $EnumMembName_Id{$Version}{getTreeAttr_Valu($TypeMembInfoId)} = ($TypeAttr->{"NameSpace"})?$TypeAttr->{"NameSpace"}."::".$MembName:$MembName;
4867 $TypeMembInfoId = getNextElem($TypeMembInfoId);
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04004868 $Pos += 1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004869 }
4870 }
4871 elsif($TypeType=~/\A(Struct|Class|Union)\Z/)
4872 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04004873 my $TypeMembInfoId = getTreeAttr_Flds($TypeId);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004874 while($TypeMembInfoId)
4875 {
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04004876 my $IType = $LibInfo{$Version}{"info_type"}{$TypeMembInfoId};
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04004877 my $MInfo = $LibInfo{$Version}{"info"}{$TypeMembInfoId};
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04004878 if(not $IType or $IType ne "field_decl")
4879 { # search for fields, skip other stuff in the declaration
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04004880 $TypeMembInfoId = getNextElem($TypeMembInfoId);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004881 next;
4882 }
Andrey Ponomarenko01117f12012-06-26 12:23:02 +04004883 my $StructMembName = getTreeStr(getTreeAttr_Name($TypeMembInfoId));
4884 if(index($StructMembName, "_vptr.")!=-1)
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04004885 { # virtual tables
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04004886 $TypeMembInfoId = getNextElem($TypeMembInfoId);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004887 next;
4888 }
4889 if(not $StructMembName)
4890 { # unnamed fields
Andrey Ponomarenko01117f12012-06-26 12:23:02 +04004891 if(index($TypeAttr->{"Name"}, "_type_info_pseudo")==-1)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004892 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04004893 my $UnnamedTid = getTreeAttr_Type($TypeMembInfoId);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004894 my $UnnamedTName = getNameByInfo(getTypeDeclId($UnnamedTid));
4895 if(isAnon($UnnamedTName))
4896 { # rename unnamed fields to unnamed0, unnamed1, ...
4897 $StructMembName = "unnamed".($UnnamedPos++);
4898 }
4899 }
4900 }
4901 if(not $StructMembName)
4902 { # unnamed fields and base classes
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04004903 $TypeMembInfoId = getNextElem($TypeMembInfoId);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004904 next;
4905 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04004906 my $MembTypeId = getTreeAttr_Type($TypeMembInfoId);
4907 if(defined $MissedTypedef{$Version}{$MembTypeId})
4908 {
4909 if(my $AddedTid = $MissedTypedef{$Version}{$MembTypeId}{"Tid"}) {
4910 $MembTypeId = $AddedTid;
4911 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004912 }
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04004913 $TypeAttr->{"Memb"}{$Pos}{"type"} = $MembTypeId;
4914 $TypeAttr->{"Memb"}{$Pos}{"name"} = $StructMembName;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004915 if((my $Access = getTreeAccess($TypeMembInfoId)) ne "public")
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04004916 { # marked only protected and private, public by default
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04004917 $TypeAttr->{"Memb"}{$Pos}{"access"} = $Access;
4918 }
4919 if($MInfo=~/spec:\s*mutable /)
4920 { # mutable fields
4921 $TypeAttr->{"Memb"}{$Pos}{"mutable"} = 1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004922 }
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +04004923 if(my $Algn = getAlgn($TypeMembInfoId)) {
4924 $TypeAttr->{"Memb"}{$Pos}{"algn"} = $Algn;
4925 }
4926 if(my $BFSize = getBitField($TypeMembInfoId))
4927 { # in bits
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04004928 $TypeAttr->{"Memb"}{$Pos}{"bitfield"} = $BFSize;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004929 }
4930 else
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +04004931 { # in bytes
4932 $TypeAttr->{"Memb"}{$Pos}{"algn"} /= $BYTE_SIZE;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004933 }
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +04004934
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04004935 $TypeMembInfoId = getNextElem($TypeMembInfoId);
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04004936 $Pos += 1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004937 }
4938 }
4939}
4940
4941sub setFuncParams($)
4942{
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04004943 my $InfoId = $_[0];
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04004944 my $ParamInfoId = getTreeAttr_Args($InfoId);
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04004945 if(getFuncType($InfoId) eq "Method")
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004946 { # check type of "this" pointer
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04004947 my $ObjectTypeId = getTreeAttr_Type($ParamInfoId);
4948 if(my $ObjectName = $TypeInfo{$Version}{$ObjectTypeId}{"Name"})
Andrey Ponomarenko85043792012-05-14 16:48:07 +04004949 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04004950 if($ObjectName=~/\bconst(| volatile)\*const\b/) {
Andrey Ponomarenko85043792012-05-14 16:48:07 +04004951 $SymbolInfo{$Version}{$InfoId}{"Const"} = 1;
4952 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04004953 if($ObjectName=~/\bvolatile\b/) {
Andrey Ponomarenko85043792012-05-14 16:48:07 +04004954 $SymbolInfo{$Version}{$InfoId}{"Volatile"} = 1;
4955 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004956 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +04004957 else
4958 { # skip
4959 return 1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004960 }
4961 $ParamInfoId = getNextElem($ParamInfoId);
4962 }
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04004963 my ($Pos, $Vtt_Pos) = (0, -1);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004964 while($ParamInfoId)
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04004965 { # formal args
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04004966 my $ParamTypeId = getTreeAttr_Type($ParamInfoId);
4967 my $ParamName = getTreeStr(getTreeAttr_Name($ParamInfoId));
4968 if(not $ParamName)
4969 { # unnamed
4970 $ParamName = "p".($Pos+1);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004971 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04004972 if(defined $MissedTypedef{$Version}{$ParamTypeId})
4973 {
4974 if(my $AddedTid = $MissedTypedef{$Version}{$ParamTypeId}{"Tid"}) {
4975 $ParamTypeId = $AddedTid;
4976 }
4977 }
4978 my $PType = $TypeInfo{$Version}{$ParamTypeId}{"Type"};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004979 if(not $PType or $PType eq "Unknown") {
4980 return 1;
4981 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04004982 my $PTName = $TypeInfo{$Version}{$ParamTypeId}{"Name"};
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04004983 if(not $PTName) {
4984 return 1;
4985 }
4986 if($PTName eq "void") {
4987 last;
4988 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004989 if($ParamName eq "__vtt_parm"
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04004990 and $TypeInfo{$Version}{$ParamTypeId}{"Name"} eq "void const**")
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004991 {
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04004992 $Vtt_Pos = $Pos;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004993 $ParamInfoId = getNextElem($ParamInfoId);
4994 next;
4995 }
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04004996 $SymbolInfo{$Version}{$InfoId}{"Param"}{$Pos}{"type"} = $ParamTypeId;
4997 $SymbolInfo{$Version}{$InfoId}{"Param"}{$Pos}{"name"} = $ParamName;
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04004998 if(my $Algn = getAlgn($ParamInfoId)) {
4999 $SymbolInfo{$Version}{$InfoId}{"Param"}{$Pos}{"algn"} = $Algn/$BYTE_SIZE;
5000 }
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04005001 if(not $SymbolInfo{$Version}{$InfoId}{"Param"}{$Pos}{"name"}) {
5002 $SymbolInfo{$Version}{$InfoId}{"Param"}{$Pos}{"name"} = "p".($Pos+1);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005003 }
5004 if($LibInfo{$Version}{"info"}{$ParamInfoId}=~/spec:\s*register /)
5005 { # foo(register type arg)
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04005006 $SymbolInfo{$Version}{$InfoId}{"Param"}{$Pos}{"reg"} = 1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005007 }
5008 $ParamInfoId = getNextElem($ParamInfoId);
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04005009 $Pos += 1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005010 }
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04005011 if(setFuncArgs($InfoId, $Vtt_Pos)) {
Andrey Ponomarenko01117f12012-06-26 12:23:02 +04005012 $SymbolInfo{$Version}{$InfoId}{"Param"}{$Pos}{"type"} = "-1";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005013 }
5014 return 0;
5015}
5016
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04005017sub setFuncArgs($$)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005018{
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04005019 my ($InfoId, $Vtt_Pos) = @_;
5020 my $FuncTypeId = getFuncTypeId($InfoId);
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04005021 my $ParamListElemId = getTreeAttr_Prms($FuncTypeId);
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04005022 if(getFuncType($InfoId) eq "Method") {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005023 $ParamListElemId = getNextElem($ParamListElemId);
5024 }
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04005025 if(not $ParamListElemId)
5026 { # foo(...)
5027 return 1;
5028 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005029 my $HaveVoid = 0;
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04005030 my $Pos = 0;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005031 while($ParamListElemId)
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04005032 { # actual params: may differ from formal args
5033 # formal int*const
5034 # actual: int*
5035 if($Vtt_Pos!=-1 and $Pos==$Vtt_Pos)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005036 {
5037 $Vtt_Pos=-1;
5038 $ParamListElemId = getNextElem($ParamListElemId);
5039 next;
5040 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04005041 my $ParamTypeId = getTreeAttr_Valu($ParamListElemId);
5042 if($TypeInfo{$Version}{$ParamTypeId}{"Name"} eq "void")
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04005043 {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005044 $HaveVoid = 1;
5045 last;
5046 }
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04005047 elsif(not defined $SymbolInfo{$Version}{$InfoId}{"Param"}{$Pos}{"type"})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005048 {
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04005049 $SymbolInfo{$Version}{$InfoId}{"Param"}{$Pos}{"type"} = $ParamTypeId;
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04005050 if(not $SymbolInfo{$Version}{$InfoId}{"Param"}{$Pos}{"name"})
5051 { # unnamed
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04005052 $SymbolInfo{$Version}{$InfoId}{"Param"}{$Pos}{"name"} = "p".($Pos+1);
5053 }
5054 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04005055 if(my $PurpId = getTreeAttr_Purp($ParamListElemId))
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04005056 { # default arguments
Andrey Ponomarenko01117f12012-06-26 12:23:02 +04005057 if(my $PurpType = $LibInfo{$Version}{"info_type"}{$PurpId})
5058 {
5059 my $Val = getInitVal($PurpId, $ParamTypeId);
5060 if(defined $Val) {
5061 $SymbolInfo{$Version}{$InfoId}{"Param"}{$Pos}{"default"} = $Val;
5062 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005063 }
5064 }
5065 $ParamListElemId = getNextElem($ParamListElemId);
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04005066 $Pos += 1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005067 }
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04005068 return ($Pos>=1 and not $HaveVoid);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005069}
5070
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04005071sub getTreeAttr_Chan($)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005072{
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04005073 if($_[0] and my $Info = $LibInfo{$Version}{"info"}{$_[0]})
5074 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04005075 if($Info=~/chan[ ]*:[ ]*@(\d+) /) {
5076 return $1;
5077 }
5078 }
5079 return "";
5080}
5081
5082sub getTreeAttr_Chain($)
5083{
5084 if($_[0] and my $Info = $LibInfo{$Version}{"info"}{$_[0]})
5085 {
5086 if($Info=~/chain[ ]*:[ ]*@(\d+) /) {
5087 return $1;
5088 }
5089 }
5090 return "";
5091}
5092
5093sub getTreeAttr_Scpe($)
5094{
5095 if($_[0] and my $Info = $LibInfo{$Version}{"info"}{$_[0]})
5096 {
5097 if($Info=~/scpe[ ]*:[ ]*@(\d+) /) {
5098 return $1;
5099 }
5100 }
5101 return "";
5102}
5103
5104sub getTreeAttr_Type($)
5105{
5106 if($_[0] and my $Info = $LibInfo{$Version}{"info"}{$_[0]})
5107 {
5108 if($Info=~/type[ ]*:[ ]*@(\d+) /) {
5109 return $1;
5110 }
5111 }
5112 return "";
5113}
5114
5115sub getTreeAttr_Name($)
5116{
5117 if($_[0] and my $Info = $LibInfo{$Version}{"info"}{$_[0]})
5118 {
5119 if($Info=~/name[ ]*:[ ]*@(\d+) /) {
5120 return $1;
5121 }
5122 }
5123 return "";
5124}
5125
5126sub getTreeAttr_Mngl($)
5127{
5128 if($_[0] and my $Info = $LibInfo{$Version}{"info"}{$_[0]})
5129 {
5130 if($Info=~/mngl[ ]*:[ ]*@(\d+) /) {
5131 return $1;
5132 }
5133 }
5134 return "";
5135}
5136
5137sub getTreeAttr_Prms($)
5138{
5139 if($_[0] and my $Info = $LibInfo{$Version}{"info"}{$_[0]})
5140 {
5141 if($Info=~/prms[ ]*:[ ]*@(\d+) /) {
5142 return $1;
5143 }
5144 }
5145 return "";
5146}
5147
5148sub getTreeAttr_Fncs($)
5149{
5150 if($_[0] and my $Info = $LibInfo{$Version}{"info"}{$_[0]})
5151 {
5152 if($Info=~/fncs[ ]*:[ ]*@(\d+) /) {
5153 return $1;
5154 }
5155 }
5156 return "";
5157}
5158
5159sub getTreeAttr_Csts($)
5160{
5161 if($_[0] and my $Info = $LibInfo{$Version}{"info"}{$_[0]})
5162 {
5163 if($Info=~/csts[ ]*:[ ]*@(\d+) /) {
5164 return $1;
5165 }
5166 }
5167 return "";
5168}
5169
5170sub getTreeAttr_Purp($)
5171{
5172 if($_[0] and my $Info = $LibInfo{$Version}{"info"}{$_[0]})
5173 {
5174 if($Info=~/purp[ ]*:[ ]*@(\d+) /) {
5175 return $1;
5176 }
5177 }
5178 return "";
5179}
5180
5181sub getTreeAttr_Valu($)
5182{
5183 if($_[0] and my $Info = $LibInfo{$Version}{"info"}{$_[0]})
5184 {
5185 if($Info=~/valu[ ]*:[ ]*@(\d+) /) {
5186 return $1;
5187 }
5188 }
5189 return "";
5190}
5191
5192sub getTreeAttr_Flds($)
5193{
5194 if($_[0] and my $Info = $LibInfo{$Version}{"info"}{$_[0]})
5195 {
5196 if($Info=~/flds[ ]*:[ ]*@(\d+) /) {
5197 return $1;
5198 }
5199 }
5200 return "";
5201}
5202
5203sub getTreeAttr_Args($)
5204{
5205 if($_[0] and my $Info = $LibInfo{$Version}{"info"}{$_[0]})
5206 {
5207 if($Info=~/args[ ]*:[ ]*@(\d+) /) {
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04005208 return $1;
5209 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005210 }
5211 return "";
5212}
5213
5214sub getTreeValue($)
5215{
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04005216 if($_[0] and my $Info = $LibInfo{$Version}{"info"}{$_[0]})
5217 {
5218 if($Info=~/low[ ]*:[ ]*([^ ]+) /) {
5219 return $1;
5220 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005221 }
5222 return "";
5223}
5224
5225sub getTreeAccess($)
5226{
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04005227 if($_[0] and my $Info = $LibInfo{$Version}{"info"}{$_[0]})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005228 {
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04005229 if($Info=~/accs[ ]*:[ ]*([a-zA-Z]+) /)
5230 {
5231 my $Access = $1;
5232 if($Access eq "prot") {
5233 return "protected";
5234 }
5235 elsif($Access eq "priv") {
5236 return "private";
5237 }
5238 }
5239 elsif($Info=~/ protected /)
5240 { # support for old GCC versions
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005241 return "protected";
5242 }
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04005243 elsif($Info=~/ private /)
5244 { # support for old GCC versions
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005245 return "private";
5246 }
5247 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005248 return "public";
5249}
5250
5251sub setFuncAccess($)
5252{
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04005253 my $Access = getTreeAccess($_[0]);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005254 if($Access eq "protected") {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04005255 $SymbolInfo{$Version}{$_[0]}{"Protected"} = 1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005256 }
5257 elsif($Access eq "private") {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04005258 $SymbolInfo{$Version}{$_[0]}{"Private"} = 1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005259 }
5260}
5261
5262sub setTypeAccess($$)
5263{
5264 my ($TypeId, $TypeAttr) = @_;
5265 my $Access = getTreeAccess($TypeId);
5266 if($Access eq "protected") {
5267 $TypeAttr->{"Protected"} = 1;
5268 }
5269 elsif($Access eq "private") {
5270 $TypeAttr->{"Private"} = 1;
5271 }
5272}
5273
5274sub setFuncKind($)
5275{
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04005276 if($_[0] and my $Info = $LibInfo{$Version}{"info"}{$_[0]})
5277 {
5278 if($Info=~/pseudo tmpl/) {
5279 $SymbolInfo{$Version}{$_[0]}{"PseudoTemplate"} = 1;
5280 }
5281 elsif($Info=~/ constructor /) {
5282 $SymbolInfo{$Version}{$_[0]}{"Constructor"} = 1;
5283 }
5284 elsif($Info=~/ destructor /) {
5285 $SymbolInfo{$Version}{$_[0]}{"Destructor"} = 1;
5286 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005287 }
5288}
5289
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04005290sub getVirtSpec($)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005291{
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04005292 if($_[0] and my $Info = $LibInfo{$Version}{"info"}{$_[0]})
5293 {
5294 if($Info=~/spec[ ]*:[ ]*pure /) {
5295 return "PureVirt";
5296 }
5297 elsif($Info=~/spec[ ]*:[ ]*virt /) {
5298 return "Virt";
5299 }
5300 elsif($Info=~/ pure\s+virtual /)
5301 { # support for old GCC versions
5302 return "PureVirt";
5303 }
5304 elsif($Info=~/ virtual /)
5305 { # support for old GCC versions
5306 return "Virt";
5307 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005308 }
5309 return "";
5310}
5311
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005312sub getFuncLink($)
5313{
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04005314 if($_[0] and my $Info = $LibInfo{$Version}{"info"}{$_[0]})
5315 {
5316 if($Info=~/link[ ]*:[ ]*static /) {
5317 return "Static";
5318 }
5319 elsif($Info=~/link[ ]*:[ ]*([a-zA-Z]+) /) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005320 return $1;
5321 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005322 }
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04005323 return "";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005324}
5325
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005326sub get_IntNameSpace($$)
5327{
5328 my ($Interface, $LibVersion) = @_;
5329 return "" if(not $Interface or not $LibVersion);
5330 if(defined $Cache{"get_IntNameSpace"}{$Interface}{$LibVersion}) {
5331 return $Cache{"get_IntNameSpace"}{$Interface}{$LibVersion};
5332 }
5333 my $Signature = get_Signature($Interface, $LibVersion);
5334 if($Signature=~/\:\:/)
5335 {
5336 my $FounNameSpace = 0;
5337 foreach my $NameSpace (sort {get_depth($b)<=>get_depth($a)} keys(%{$NestedNameSpaces{$LibVersion}}))
5338 {
5339 if($Signature=~/(\A|\s+for\s+)\Q$NameSpace\E\:\:/) {
5340 return ($Cache{"get_IntNameSpace"}{$Interface}{$LibVersion} = $NameSpace);
5341 }
5342 }
5343 }
5344 else {
5345 return ($Cache{"get_IntNameSpace"}{$Interface}{$LibVersion} = "");
5346 }
5347}
5348
5349sub parse_TypeNameSpace($$)
5350{
5351 my ($TypeName, $LibVersion) = @_;
5352 return "" if(not $TypeName or not $LibVersion);
5353 if(defined $Cache{"parse_TypeNameSpace"}{$TypeName}{$LibVersion}) {
5354 return $Cache{"parse_TypeNameSpace"}{$TypeName}{$LibVersion};
5355 }
5356 if($TypeName=~/\:\:/)
5357 {
5358 my $FounNameSpace = 0;
5359 foreach my $NameSpace (sort {get_depth($b)<=>get_depth($a)} keys(%{$NestedNameSpaces{$LibVersion}}))
5360 {
5361 if($TypeName=~/\A\Q$NameSpace\E\:\:/) {
5362 return ($Cache{"parse_TypeNameSpace"}{$TypeName}{$LibVersion} = $NameSpace);
5363 }
5364 }
5365 }
5366 else {
5367 return ($Cache{"parse_TypeNameSpace"}{$TypeName}{$LibVersion} = "");
5368 }
5369}
5370
5371sub getNameSpace($)
5372{
5373 my $TypeInfoId = $_[0];
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04005374 if(my $NSInfoId = getTreeAttr_Scpe($TypeInfoId))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005375 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04005376 if(my $InfoType = $LibInfo{$Version}{"info_type"}{$NSInfoId})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005377 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04005378 if($InfoType eq "namespace_decl")
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04005379 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04005380 if($LibInfo{$Version}{"info"}{$NSInfoId}=~/name[ ]*:[ ]*@(\d+) /)
5381 {
5382 my $NameSpace = getTreeStr($1);
5383 if($NameSpace eq "::")
5384 { # global namespace
5385 return "";
5386 }
5387 if(my $BaseNameSpace = getNameSpace($NSInfoId)) {
5388 $NameSpace = $BaseNameSpace."::".$NameSpace;
5389 }
5390 $NestedNameSpaces{$Version}{$NameSpace} = 1;
5391 return $NameSpace;
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04005392 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04005393 else {
5394 return "";
5395 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005396 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04005397 elsif($InfoType eq "record_type")
5398 { # inside data type
5399 my ($Name, $NameNS) = getTrivialName(getTypeDeclId($NSInfoId), $NSInfoId);
5400 return $Name;
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04005401 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005402 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005403 }
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04005404 return "";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005405}
5406
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005407sub getEnumMembVal($)
5408{
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04005409 if($_[0] and my $Info = $LibInfo{$Version}{"info"}{$_[0]})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005410 {
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04005411 if($Info=~/valu[ ]*:[ ]*\@(\d+)/)
5412 {
5413 if(my $VInfo = $LibInfo{$Version}{"info"}{$1})
5414 {
5415 if($VInfo=~/cnst[ ]*:[ ]*\@(\d+)/)
5416 { # in newer versions of GCC the value is in the "const_decl->cnst" node
5417 return getTreeValue($1);
5418 }
5419 else
5420 { # some old versions of GCC (3.3) have the value in the "integer_cst" node
5421 return getTreeValue($1);
5422 }
5423 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005424 }
5425 }
5426 return "";
5427}
5428
5429sub getSize($)
5430{
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04005431 if($_[0] and my $Info = $LibInfo{$Version}{"info"}{$_[0]})
5432 {
5433 if($Info=~/size[ ]*:[ ]*\@(\d+)/) {
5434 return getTreeValue($1);
5435 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005436 }
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04005437 return 0;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005438}
5439
5440sub getAlgn($)
5441{
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04005442 if($_[0] and my $Info = $LibInfo{$Version}{"info"}{$_[0]})
5443 {
5444 if($Info=~/algn[ ]*:[ ]*(\d+) /) {
5445 return $1;
5446 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005447 }
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04005448 return "";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005449}
5450
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +04005451sub getBitField($)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005452{
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04005453 if($_[0] and my $Info = $LibInfo{$Version}{"info"}{$_[0]})
5454 {
5455 if($Info=~/ bitfield /) {
5456 return getSize($_[0]);
5457 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005458 }
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04005459 return 0;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005460}
5461
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04005462sub getNextElem($)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005463{
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04005464 if(my $Chan = getTreeAttr_Chan($_[0])) {
5465 return $Chan;
5466 }
5467 elsif(my $Chain = getTreeAttr_Chain($_[0])) {
5468 return $Chain;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005469 }
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04005470 return "";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005471}
5472
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04005473sub registerHeader($$)
5474{ # input: absolute path of header, relative path or name
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005475 my ($Header, $LibVersion) = @_;
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04005476 if(not $Header) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005477 return "";
5478 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04005479 if(is_abs($Header) and not -f $Header)
5480 { # incorrect absolute path
5481 exitStatus("Access_Error", "can't access \'$Header\'");
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005482 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04005483 if(skipHeader($Header, $LibVersion))
5484 { # skip
5485 return "";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005486 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04005487 if(my $Header_Path = identifyHeader($Header, $LibVersion))
5488 {
5489 detect_header_includes($Header_Path, $LibVersion);
5490
5491 if(my $RHeader_Path = $Header_ErrorRedirect{$LibVersion}{$Header_Path})
5492 { # redirect
5493 if($Registered_Headers{$LibVersion}{$RHeader_Path}{"Identity"}
5494 or skipHeader($RHeader_Path, $LibVersion))
5495 { # skip
5496 return "";
5497 }
5498 $Header_Path = $RHeader_Path;
5499 }
5500 elsif($Header_ShouldNotBeUsed{$LibVersion}{$Header_Path})
5501 { # skip
5502 return "";
5503 }
5504
5505 if(my $HName = get_filename($Header_Path))
5506 { # register
5507 $Registered_Headers{$LibVersion}{$Header_Path}{"Identity"} = $HName;
5508 $HeaderName_Paths{$LibVersion}{$HName}{$Header_Path} = 1;
5509 }
5510
5511 if(($Header=~/\.(\w+)\Z/ and $1 ne "h")
5512 or $Header!~/\.(\w+)\Z/)
5513 { # hpp, hh
5514 setLanguage($LibVersion, "C++");
5515 }
5516
5517 if($CheckHeadersOnly
5518 and $Header=~/(\A|\/)c\+\+(\/|\Z)/)
5519 { # /usr/include/c++/4.6.1/...
5520 $STDCXX_TESTING = 1;
5521 }
5522
5523 return $Header_Path;
5524 }
5525 return "";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005526}
5527
5528sub register_directory($$$)
5529{
5530 my ($Dir, $WithDeps, $LibVersion) = @_;
5531 $Dir=~s/[\/\\]+\Z//g;
5532 return if(not $LibVersion or not $Dir or not -d $Dir);
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04005533 return if(skipHeader($Dir, $LibVersion));
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005534 $Dir = get_abs_path($Dir);
5535 my $Mode = "All";
Andrey Ponomarenko85043792012-05-14 16:48:07 +04005536 if($WithDeps)
5537 {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005538 if($RegisteredDirs{$LibVersion}{$Dir}{1}) {
5539 return;
5540 }
5541 elsif($RegisteredDirs{$LibVersion}{$Dir}{0}) {
5542 $Mode = "DepsOnly";
5543 }
5544 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +04005545 else
5546 {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005547 if($RegisteredDirs{$LibVersion}{$Dir}{1}
5548 or $RegisteredDirs{$LibVersion}{$Dir}{0}) {
5549 return;
5550 }
5551 }
5552 $Header_Dependency{$LibVersion}{$Dir} = 1;
5553 $RegisteredDirs{$LibVersion}{$Dir}{$WithDeps} = 1;
5554 if($Mode eq "DepsOnly")
5555 {
5556 foreach my $Path (cmd_find($Dir,"d","","")) {
5557 $Header_Dependency{$LibVersion}{$Path} = 1;
5558 }
5559 return;
5560 }
5561 foreach my $Path (sort {length($b)<=>length($a)} cmd_find($Dir,"f","",""))
5562 {
5563 if($WithDeps)
5564 {
5565 my $SubDir = $Path;
5566 while(($SubDir = get_dirname($SubDir)) ne $Dir)
5567 { # register all sub directories
5568 $Header_Dependency{$LibVersion}{$SubDir} = 1;
5569 }
5570 }
5571 next if(is_not_header($Path));
5572 next if(ignore_path($Path));
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04005573 next if(skipHeader($Path, $LibVersion));
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005574 # Neighbors
Andrey Ponomarenko9927e332012-10-19 10:50:48 +04005575 foreach my $Part (get_prefixes($Path)) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005576 $Include_Neighbors{$LibVersion}{$Part} = $Path;
5577 }
5578 }
5579 if(get_filename($Dir) eq "include")
5580 { # search for "lib/include/" directory
5581 my $LibDir = $Dir;
5582 if($LibDir=~s/([\/\\])include\Z/$1lib/g and -d $LibDir) {
5583 register_directory($LibDir, $WithDeps, $LibVersion);
5584 }
5585 }
5586}
5587
5588sub parse_redirect($$$)
5589{
5590 my ($Content, $Path, $LibVersion) = @_;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005591 my @Errors = ();
5592 while($Content=~s/#\s*error\s+([^\n]+?)\s*(\n|\Z)//) {
5593 push(@Errors, $1);
5594 }
5595 my $Redirect = "";
5596 foreach (@Errors)
5597 {
5598 s/\s{2,}/ /g;
5599 if(/(only|must\ include
5600 |update\ to\ include
5601 |replaced\ with
5602 |replaced\ by|renamed\ to
Andrey Ponomarenko9927e332012-10-19 10:50:48 +04005603 |\ is\ in|\ use)\ (<[^<>]+>|[\w\-\/\\]+\.($HEADER_EXT))/ix)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005604 {
5605 $Redirect = $2;
5606 last;
5607 }
5608 elsif(/(include|use|is\ in)\ (<[^<>]+>|[\w\-\/\\]+\.($HEADER_EXT))\ instead/i)
5609 {
5610 $Redirect = $2;
5611 last;
5612 }
5613 elsif(/this\ header\ should\ not\ be\ used
5614 |programs\ should\ not\ directly\ include
5615 |you\ should\ not\ (include|be\ (including|using)\ this\ (file|header))
5616 |is\ not\ supported\ API\ for\ general\ use
5617 |do\ not\ use
Andrey Ponomarenko9927e332012-10-19 10:50:48 +04005618 |should\ not\ be\ (used|using)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005619 |cannot\ be\ included\ directly/ix and not /\ from\ /i) {
5620 $Header_ShouldNotBeUsed{$LibVersion}{$Path} = 1;
5621 }
5622 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +04005623 if($Redirect)
5624 {
5625 $Redirect=~s/\A<//g;
5626 $Redirect=~s/>\Z//g;
5627 }
5628 return $Redirect;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005629}
5630
5631sub parse_includes($$)
5632{
5633 my ($Content, $Path) = @_;
5634 my %Includes = ();
5635 while($Content=~s/#([ \t]*)(include|include_next|import)([ \t]*)(<|")([^<>"]+)(>|")//)
Andrey Ponomarenko85043792012-05-14 16:48:07 +04005636 { # C/C++: include, Objective C/C++: import directive
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005637 my ($Header, $Method) = ($5, $4);
5638 $Header = path_format($Header, $OSgroup);
Andrey Ponomarenko85043792012-05-14 16:48:07 +04005639 if($Method eq "\"" or is_abs($Header))
5640 {
5641 if(-e joinPath(get_dirname($Path), $Header))
5642 { # relative path exists
5643 $Includes{$Header} = -1;
5644 }
5645 else
5646 { # include "..." that doesn't exist is equal to include <...>
5647 $Includes{$Header} = 2;
5648 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005649 }
5650 else {
5651 $Includes{$Header} = 1;
5652 }
5653 }
5654 return \%Includes;
5655}
5656
5657sub ignore_path($)
5658{
5659 my $Path = $_[0];
5660 if($Path=~/\~\Z/)
5661 {# skipping system backup files
5662 return 1;
5663 }
5664 if($Path=~/(\A|[\/\\]+)(\.(svn|git|bzr|hg)|CVS)([\/\\]+|\Z)/)
5665 {# skipping hidden .svn, .git, .bzr, .hg and CVS directories
5666 return 1;
5667 }
5668 return 0;
5669}
5670
Andrey Ponomarenko9927e332012-10-19 10:50:48 +04005671sub sortByWord($$)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005672{
5673 my ($ArrRef, $W) = @_;
5674 return if(length($W)<2);
5675 @{$ArrRef} = sort {get_filename($b)=~/\Q$W\E/i<=>get_filename($a)=~/\Q$W\E/i} @{$ArrRef};
5676}
5677
Andrey Ponomarenko9927e332012-10-19 10:50:48 +04005678sub sortHeaders($$)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005679{
5680 my ($H1, $H2) = @_;
5681 $H1=~s/\.[a-z]+\Z//ig;
5682 $H2=~s/\.[a-z]+\Z//ig;
5683 my ($HDir1, $Hname1) = separate_path($H1);
5684 my ($HDir2, $Hname2) = separate_path($H2);
5685 my $Dirname1 = get_filename($HDir1);
5686 my $Dirname2 = get_filename($HDir2);
Andrey Ponomarenko9927e332012-10-19 10:50:48 +04005687 if($_[0] eq $_[1]
5688 or $H1 eq $H2) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005689 return 0;
5690 }
5691 elsif($H1=~/\A\Q$H2\E/) {
5692 return 1;
5693 }
5694 elsif($H2=~/\A\Q$H1\E/) {
5695 return -1;
5696 }
5697 elsif($HDir1=~/\Q$Hname1\E/i
5698 and $HDir2!~/\Q$Hname2\E/i)
Andrey Ponomarenko9927e332012-10-19 10:50:48 +04005699 { # include/glib-2.0/glib.h
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005700 return -1;
5701 }
5702 elsif($HDir2=~/\Q$Hname2\E/i
5703 and $HDir1!~/\Q$Hname1\E/i)
Andrey Ponomarenko9927e332012-10-19 10:50:48 +04005704 { # include/glib-2.0/glib.h
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005705 return 1;
5706 }
5707 elsif($Hname1=~/\Q$Dirname1\E/i
5708 and $Hname2!~/\Q$Dirname2\E/i)
Andrey Ponomarenko9927e332012-10-19 10:50:48 +04005709 { # include/hildon-thumbnail/hildon-thumbnail-factory.h
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005710 return -1;
5711 }
5712 elsif($Hname2=~/\Q$Dirname2\E/i
5713 and $Hname1!~/\Q$Dirname1\E/i)
Andrey Ponomarenko9927e332012-10-19 10:50:48 +04005714 { # include/hildon-thumbnail/hildon-thumbnail-factory.h
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005715 return 1;
5716 }
Andrey Ponomarenko9927e332012-10-19 10:50:48 +04005717 elsif($Hname1=~/(config|lib|util)/i
5718 and $Hname2!~/(config|lib|util)/i)
5719 { # include/alsa/asoundlib.h
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005720 return -1;
5721 }
Andrey Ponomarenko9927e332012-10-19 10:50:48 +04005722 elsif($Hname2=~/(config|lib|util)/i
5723 and $Hname1!~/(config|lib|util)/i)
5724 { # include/alsa/asoundlib.h
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005725 return 1;
5726 }
5727 elsif(checkRelevance($H1)
5728 and not checkRelevance($H2))
Andrey Ponomarenko9927e332012-10-19 10:50:48 +04005729 { # libebook/e-book.h
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005730 return -1;
5731 }
5732 elsif(checkRelevance($H2)
5733 and not checkRelevance($H1))
Andrey Ponomarenko9927e332012-10-19 10:50:48 +04005734 { # libebook/e-book.h
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005735 return 1;
5736 }
Andrey Ponomarenko9927e332012-10-19 10:50:48 +04005737 else
5738 {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005739 return (lc($H1) cmp lc($H2));
5740 }
5741}
5742
5743sub searchForHeaders($)
5744{
5745 my $LibVersion = $_[0];
5746 # gcc standard include paths
5747 find_gcc_cxx_headers($LibVersion);
5748 # processing header paths
5749 foreach my $Path (keys(%{$Descriptor{$LibVersion}{"IncludePaths"}}),
5750 keys(%{$Descriptor{$LibVersion}{"AddIncludePaths"}}))
5751 {
5752 my $IPath = $Path;
Andrey Ponomarenkoa01311b2012-06-08 17:20:02 +04005753 if($SystemRoot)
5754 {
5755 if(is_abs($Path)) {
5756 $Path = $SystemRoot.$Path;
5757 }
5758 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005759 if(not -e $Path) {
5760 exitStatus("Access_Error", "can't access \'$Path\'");
5761 }
5762 elsif(-f $Path) {
5763 exitStatus("Access_Error", "\'$Path\' - not a directory");
5764 }
5765 elsif(-d $Path)
5766 {
5767 $Path = get_abs_path($Path);
5768 register_directory($Path, 0, $LibVersion);
5769 if($Descriptor{$LibVersion}{"AddIncludePaths"}{$IPath}) {
5770 $Add_Include_Paths{$LibVersion}{$Path} = 1;
5771 }
5772 else {
5773 $Include_Paths{$LibVersion}{$Path} = 1;
5774 }
5775 }
5776 }
5777 if(keys(%{$Include_Paths{$LibVersion}})) {
5778 $INC_PATH_AUTODETECT{$LibVersion} = 0;
5779 }
5780 # registering directories
5781 foreach my $Path (split(/\s*\n\s*/, $Descriptor{$LibVersion}{"Headers"}))
5782 {
5783 next if(not -e $Path);
5784 $Path = get_abs_path($Path);
5785 $Path = path_format($Path, $OSgroup);
5786 if(-d $Path) {
5787 register_directory($Path, 1, $LibVersion);
5788 }
5789 elsif(-f $Path)
5790 {
5791 my $Dir = get_dirname($Path);
5792 if(not $SystemPaths{"include"}{$Dir}
5793 and not $LocalIncludes{$Dir})
5794 {
5795 register_directory($Dir, 1, $LibVersion);
5796 if(my $OutDir = get_dirname($Dir))
5797 { # registering the outer directory
5798 if(not $SystemPaths{"include"}{$OutDir}
5799 and not $LocalIncludes{$OutDir}) {
5800 register_directory($OutDir, 0, $LibVersion);
5801 }
5802 }
5803 }
5804 }
5805 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +04005806
5807 # clean memory
5808 %RegisteredDirs = ();
5809
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005810 # registering headers
5811 my $Position = 0;
5812 foreach my $Dest (split(/\s*\n\s*/, $Descriptor{$LibVersion}{"Headers"}))
5813 {
5814 if(is_abs($Dest) and not -e $Dest) {
5815 exitStatus("Access_Error", "can't access \'$Dest\'");
5816 }
5817 $Dest = path_format($Dest, $OSgroup);
5818 if(is_header($Dest, 1, $LibVersion))
5819 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04005820 if(my $HPath = registerHeader($Dest, $LibVersion)) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005821 $Registered_Headers{$LibVersion}{$HPath}{"Pos"} = $Position++;
5822 }
5823 }
5824 elsif(-d $Dest)
5825 {
5826 my @Registered = ();
5827 foreach my $Path (cmd_find($Dest,"f","",""))
5828 {
5829 next if(ignore_path($Path));
5830 next if(not is_header($Path, 0, $LibVersion));
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04005831 if(my $HPath = registerHeader($Path, $LibVersion)) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005832 push(@Registered, $HPath);
5833 }
5834 }
Andrey Ponomarenko9927e332012-10-19 10:50:48 +04005835 @Registered = sort {sortHeaders($a, $b)} @Registered;
5836 sortByWord(\@Registered, $TargetLibraryShortName);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005837 foreach my $Path (@Registered) {
5838 $Registered_Headers{$LibVersion}{$Path}{"Pos"} = $Position++;
5839 }
5840 }
5841 else {
5842 exitStatus("Access_Error", "can't identify \'$Dest\' as a header file");
5843 }
5844 }
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04005845 if(my $HList = $Descriptor{$LibVersion}{"IncludePreamble"})
5846 { # preparing preamble headers
5847 my $PPos=0;
5848 foreach my $Header (split(/\s*\n\s*/, $HList))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005849 {
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04005850 if(is_abs($Header) and not -f $Header) {
5851 exitStatus("Access_Error", "can't access file \'$Header\'");
5852 }
5853 $Header = path_format($Header, $OSgroup);
5854 if(my $Header_Path = is_header($Header, 1, $LibVersion))
5855 {
Andrey Ponomarenko9927e332012-10-19 10:50:48 +04005856 if(defined $Include_Preamble{$LibVersion}{$Header_Path})
5857 { # duplicate
5858 next;
5859 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04005860 next if(skipHeader($Header_Path, $LibVersion));
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04005861 $Include_Preamble{$LibVersion}{$Header_Path}{"Position"} = $PPos++;
5862 }
5863 else {
5864 exitStatus("Access_Error", "can't identify \'$Header\' as a header file");
5865 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005866 }
5867 }
5868 foreach my $Header_Name (keys(%{$HeaderName_Paths{$LibVersion}}))
5869 { # set relative paths (for duplicates)
5870 if(keys(%{$HeaderName_Paths{$LibVersion}{$Header_Name}})>=2)
5871 { # search for duplicates
5872 my $FirstPath = (keys(%{$HeaderName_Paths{$LibVersion}{$Header_Name}}))[0];
5873 my $Prefix = get_dirname($FirstPath);
5874 while($Prefix=~/\A(.+)[\/\\]+[^\/\\]+\Z/)
5875 { # detect a shortest distinguishing prefix
5876 my $NewPrefix = $1;
5877 my %Identity = ();
5878 foreach my $Path (keys(%{$HeaderName_Paths{$LibVersion}{$Header_Name}}))
5879 {
5880 if($Path=~/\A\Q$Prefix\E[\/\\]+(.*)\Z/) {
5881 $Identity{$Path} = $1;
5882 }
5883 }
5884 if(keys(%Identity)==keys(%{$HeaderName_Paths{$LibVersion}{$Header_Name}}))
5885 { # all names are differend with current prefix
5886 foreach my $Path (keys(%{$HeaderName_Paths{$LibVersion}{$Header_Name}})) {
5887 $Registered_Headers{$LibVersion}{$Path}{"Identity"} = $Identity{$Path};
5888 }
5889 last;
5890 }
5891 $Prefix = $NewPrefix; # increase prefix
5892 }
5893 }
5894 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +04005895
5896 # clean memory
5897 %HeaderName_Paths = ();
5898
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005899 foreach my $HeaderName (keys(%{$Include_Order{$LibVersion}}))
5900 { # ordering headers according to descriptor
5901 my $PairName=$Include_Order{$LibVersion}{$HeaderName};
5902 my ($Pos, $PairPos) = (-1, -1);
5903 my ($Path, $PairPath) = ();
5904 my @Paths = keys(%{$Registered_Headers{$LibVersion}});
5905 @Paths = sort {int($Registered_Headers{$LibVersion}{$a}{"Pos"})<=>int($Registered_Headers{$LibVersion}{$b}{"Pos"})} @Paths;
5906 foreach my $Header_Path (@Paths)
5907 {
5908 if(get_filename($Header_Path) eq $PairName)
5909 {
5910 $PairPos = $Registered_Headers{$LibVersion}{$Header_Path}{"Pos"};
5911 $PairPath = $Header_Path;
5912 }
5913 if(get_filename($Header_Path) eq $HeaderName)
5914 {
5915 $Pos = $Registered_Headers{$LibVersion}{$Header_Path}{"Pos"};
5916 $Path = $Header_Path;
5917 }
5918 }
5919 if($PairPos!=-1 and $Pos!=-1
5920 and int($PairPos)<int($Pos))
5921 {
5922 my %Tmp = %{$Registered_Headers{$LibVersion}{$Path}};
5923 %{$Registered_Headers{$LibVersion}{$Path}} = %{$Registered_Headers{$LibVersion}{$PairPath}};
5924 %{$Registered_Headers{$LibVersion}{$PairPath}} = %Tmp;
5925 }
5926 }
5927 if(not keys(%{$Registered_Headers{$LibVersion}})) {
5928 exitStatus("Error", "header files are not found in the ".$Descriptor{$LibVersion}{"Version"});
5929 }
5930}
5931
5932sub detect_real_includes($$)
5933{
5934 my ($AbsPath, $LibVersion) = @_;
5935 return () if(not $LibVersion or not $AbsPath or not -e $AbsPath);
5936 if($Cache{"detect_real_includes"}{$LibVersion}{$AbsPath}
5937 or keys(%{$RecursiveIncludes{$LibVersion}{$AbsPath}})) {
5938 return keys(%{$RecursiveIncludes{$LibVersion}{$AbsPath}});
5939 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +04005940 $Cache{"detect_real_includes"}{$LibVersion}{$AbsPath}=1;
5941
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005942 my $Path = callPreprocessor($AbsPath, "", $LibVersion);
5943 return () if(not $Path);
5944 open(PREPROC, $Path);
5945 while(<PREPROC>)
5946 {
5947 if(/#\s+\d+\s+"([^"]+)"[\s\d]*\n/)
5948 {
5949 my $Include = path_format($1, $OSgroup);
5950 if($Include=~/\<(built\-in|internal|command(\-|\s)line)\>|\A\./) {
5951 next;
5952 }
5953 if($Include eq $AbsPath) {
5954 next;
5955 }
5956 $RecursiveIncludes{$LibVersion}{$AbsPath}{$Include} = 1;
5957 }
5958 }
5959 close(PREPROC);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005960 return keys(%{$RecursiveIncludes{$LibVersion}{$AbsPath}});
5961}
5962
5963sub detect_header_includes($$)
5964{
5965 my ($Path, $LibVersion) = @_;
Andrey Ponomarenko85043792012-05-14 16:48:07 +04005966 return if(not $LibVersion or not $Path);
5967 if(defined $Cache{"detect_header_includes"}{$LibVersion}{$Path}) {
5968 return;
5969 }
5970 $Cache{"detect_header_includes"}{$LibVersion}{$Path}=1;
5971
5972 if(not -e $Path) {
5973 return;
5974 }
5975
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005976 my $Content = readFile($Path);
Andrey Ponomarenko85043792012-05-14 16:48:07 +04005977 if(my $Redirect = parse_redirect($Content, $Path, $LibVersion))
5978 { # detect error directive in headers
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04005979 if(my $RedirectPath = identifyHeader($Redirect, $LibVersion))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005980 {
5981 if($RedirectPath=~/\/usr\/include\// and $Path!~/\/usr\/include\//) {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04005982 $RedirectPath = identifyHeader(get_filename($Redirect), $LibVersion);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005983 }
5984 if($RedirectPath ne $Path) {
5985 $Header_ErrorRedirect{$LibVersion}{$Path} = $RedirectPath;
5986 }
5987 }
Andrey Ponomarenko9927e332012-10-19 10:50:48 +04005988 else
5989 { # can't find
5990 $Header_ShouldNotBeUsed{$LibVersion}{$Path} = 1;
5991 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005992 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +04005993 if(my $Inc = parse_includes($Content, $Path))
5994 {
5995 foreach my $Include (keys(%{$Inc}))
5996 { # detect includes
Andrey Ponomarenko85043792012-05-14 16:48:07 +04005997 $Header_Includes{$LibVersion}{$Path}{$Include} = $Inc->{$Include};
5998 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005999 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006000}
6001
6002sub simplify_path($)
6003{
6004 my $Path = $_[0];
6005 while($Path=~s&([\/\\])[^\/\\]+[\/\\]\.\.[\/\\]&$1&){};
6006 return $Path;
6007}
6008
6009sub fromLibc($)
6010{ # GLIBC header
6011 my $Path = $_[0];
6012 my ($Dir, $Name) = separate_path($Path);
6013 if(get_filename($Dir)=~/\A(include|libc)\Z/ and $GlibcHeader{$Name})
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04006014 { # /usr/include/{stdio, ...}.h
6015 # epoc32/include/libc/{stdio, ...}.h
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006016 return 1;
6017 }
6018 if(isLibcDir($Dir)) {
6019 return 1;
6020 }
6021 return 0;
6022}
6023
6024sub isLibcDir($)
6025{ # GLIBC directory
6026 my $Dir = $_[0];
6027 my ($OutDir, $Name) = separate_path($Dir);
6028 if(get_filename($OutDir)=~/\A(include|libc)\Z/
6029 and ($Name=~/\Aasm(|-.+)\Z/ or $GlibcDir{$Name}))
6030 { # /usr/include/{sys,bits,asm,asm-*}/*.h
6031 return 1;
6032 }
6033 return 0;
6034}
6035
6036sub detect_recursive_includes($$)
6037{
6038 my ($AbsPath, $LibVersion) = @_;
6039 return () if(not $AbsPath);
6040 if(isCyclical(\@RecurInclude, $AbsPath)) {
6041 return keys(%{$RecursiveIncludes{$LibVersion}{$AbsPath}});
6042 }
6043 my ($AbsDir, $Name) = separate_path($AbsPath);
6044 if(isLibcDir($AbsDir))
6045 { # GLIBC internals
6046 return ();
6047 }
6048 if(keys(%{$RecursiveIncludes{$LibVersion}{$AbsPath}})) {
6049 return keys(%{$RecursiveIncludes{$LibVersion}{$AbsPath}});
6050 }
6051 return () if($OSgroup ne "windows" and $Name=~/windows|win32|win64/i);
6052 return () if($MAIN_CPP_DIR and $AbsPath=~/\A\Q$MAIN_CPP_DIR\E/ and not $STDCXX_TESTING);
6053 push(@RecurInclude, $AbsPath);
6054 if($DefaultGccPaths{$AbsDir}
6055 or fromLibc($AbsPath))
6056 { # check "real" (non-"model") include paths
6057 my @Paths = detect_real_includes($AbsPath, $LibVersion);
6058 pop(@RecurInclude);
6059 return @Paths;
6060 }
6061 if(not keys(%{$Header_Includes{$LibVersion}{$AbsPath}})) {
6062 detect_header_includes($AbsPath, $LibVersion);
6063 }
6064 foreach my $Include (keys(%{$Header_Includes{$LibVersion}{$AbsPath}}))
6065 {
Andrey Ponomarenko85043792012-05-14 16:48:07 +04006066 my $IncType = $Header_Includes{$LibVersion}{$AbsPath}{$Include};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006067 my $HPath = "";
Andrey Ponomarenko85043792012-05-14 16:48:07 +04006068 if($IncType<0)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006069 { # for #include "..."
6070 my $Candidate = joinPath($AbsDir, $Include);
6071 if(-f $Candidate) {
6072 $HPath = simplify_path($Candidate);
6073 }
6074 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +04006075 elsif($IncType>0
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04006076 and $Include=~/[\/\\]/) # and not find_in_defaults($Include)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006077 { # search for the nearest header
6078 # QtCore/qabstractanimation.h includes <QtCore/qobject.h>
6079 my $Candidate = joinPath(get_dirname($AbsDir), $Include);
6080 if(-f $Candidate) {
6081 $HPath = $Candidate;
6082 }
6083 }
6084 if(not $HPath) {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04006085 $HPath = identifyHeader($Include, $LibVersion);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006086 }
6087 next if(not $HPath);
6088 if($HPath eq $AbsPath) {
6089 next;
6090 }
Andrey Ponomarenko9927e332012-10-19 10:50:48 +04006091
6092 if($Debug)
6093 { # boundary headers
6094 #if($HPath=~/vtk/ and $AbsPath!~/vtk/)
6095 #{
6096 # print STDERR "$AbsPath -> $HPath\n";
6097 #}
6098 }
6099
Andrey Ponomarenko85043792012-05-14 16:48:07 +04006100 $RecursiveIncludes{$LibVersion}{$AbsPath}{$HPath} = $IncType;
6101 if($IncType>0)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006102 { # only include <...>, skip include "..." prefixes
6103 $Header_Include_Prefix{$LibVersion}{$AbsPath}{$HPath}{get_dirname($Include)} = 1;
6104 }
6105 foreach my $IncPath (detect_recursive_includes($HPath, $LibVersion))
6106 {
6107 if($IncPath eq $AbsPath) {
6108 next;
6109 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +04006110 my $RIncType = $RecursiveIncludes{$LibVersion}{$HPath}{$IncPath};
6111 if($RIncType==-1)
6112 { # include "..."
6113 $RIncType = $IncType;
6114 }
6115 elsif($RIncType==2)
6116 {
6117 if($IncType!=-1) {
6118 $RIncType = $IncType;
6119 }
6120 }
6121 $RecursiveIncludes{$LibVersion}{$AbsPath}{$IncPath} = $RIncType;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006122 foreach my $Prefix (keys(%{$Header_Include_Prefix{$LibVersion}{$HPath}{$IncPath}})) {
6123 $Header_Include_Prefix{$LibVersion}{$AbsPath}{$IncPath}{$Prefix} = 1;
6124 }
6125 }
6126 foreach my $Dep (keys(%{$Header_Include_Prefix{$LibVersion}{$AbsPath}}))
6127 {
6128 if($GlibcHeader{get_filename($Dep)} and keys(%{$Header_Include_Prefix{$LibVersion}{$AbsPath}{$Dep}})>=2
6129 and defined $Header_Include_Prefix{$LibVersion}{$AbsPath}{$Dep}{""})
6130 { # distinguish math.h from glibc and math.h from the tested library
6131 delete($Header_Include_Prefix{$LibVersion}{$AbsPath}{$Dep}{""});
6132 last;
6133 }
6134 }
6135 }
6136 pop(@RecurInclude);
6137 return keys(%{$RecursiveIncludes{$LibVersion}{$AbsPath}});
6138}
6139
6140sub find_in_framework($$$)
6141{
6142 my ($Header, $Framework, $LibVersion) = @_;
6143 return "" if(not $Header or not $Framework or not $LibVersion);
6144 if(defined $Cache{"find_in_framework"}{$LibVersion}{$Framework}{$Header}) {
6145 return $Cache{"find_in_framework"}{$LibVersion}{$Framework}{$Header};
6146 }
6147 foreach my $Dependency (sort {get_depth($a)<=>get_depth($b)} keys(%{$Header_Dependency{$LibVersion}}))
6148 {
6149 if(get_filename($Dependency) eq $Framework
6150 and -f get_dirname($Dependency)."/".$Header) {
6151 return ($Cache{"find_in_framework"}{$LibVersion}{$Framework}{$Header} = get_dirname($Dependency));
6152 }
6153 }
6154 return ($Cache{"find_in_framework"}{$LibVersion}{$Framework}{$Header} = "");
6155}
6156
6157sub find_in_defaults($)
6158{
6159 my $Header = $_[0];
6160 return "" if(not $Header);
6161 if(defined $Cache{"find_in_defaults"}{$Header}) {
6162 return $Cache{"find_in_defaults"}{$Header};
6163 }
6164 foreach my $Dir (sort {get_depth($a)<=>get_depth($b)}
6165 (keys(%DefaultIncPaths), keys(%DefaultGccPaths), keys(%DefaultCppPaths), keys(%UserIncPath)))
6166 {
6167 next if(not $Dir);
6168 if(-f $Dir."/".$Header) {
6169 return ($Cache{"find_in_defaults"}{$Header}=$Dir);
6170 }
6171 }
6172 return ($Cache{"find_in_defaults"}{$Header}="");
6173}
6174
6175sub cmp_paths($$)
6176{
6177 my ($Path1, $Path2) = @_;
6178 my @Parts1 = split(/[\/\\]/, $Path1);
6179 my @Parts2 = split(/[\/\\]/, $Path2);
6180 foreach my $Num (0 .. $#Parts1)
6181 {
6182 my $Part1 = $Parts1[$Num];
6183 my $Part2 = $Parts2[$Num];
6184 if($GlibcDir{$Part1}
6185 and not $GlibcDir{$Part2}) {
6186 return 1;
6187 }
6188 elsif($GlibcDir{$Part2}
6189 and not $GlibcDir{$Part1}) {
6190 return -1;
6191 }
6192 elsif($Part1=~/glib/
6193 and $Part2!~/glib/) {
6194 return 1;
6195 }
6196 elsif($Part1!~/glib/
6197 and $Part2=~/glib/) {
6198 return -1;
6199 }
6200 elsif(my $CmpRes = ($Part1 cmp $Part2)) {
6201 return $CmpRes;
6202 }
6203 }
6204 return 0;
6205}
6206
6207sub checkRelevance($)
6208{
6209 my ($Path) = @_;
6210 return 0 if(not $Path);
6211 if($SystemRoot) {
Andrey Ponomarenkoa01311b2012-06-08 17:20:02 +04006212 $Path = cut_path_prefix($Path, $SystemRoot);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006213 }
6214 my ($Dir, $Name) = separate_path($Path);
Andrey Ponomarenkoa01311b2012-06-08 17:20:02 +04006215 $Name=~s/\.\w+\Z//g; # remove extension (.h)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006216 my @Tokens = split(/[_\d\W]+/, $Name);
6217 foreach (@Tokens)
6218 {
6219 next if(not $_);
6220 if($Dir=~/(\A|lib|[_\d\W])\Q$_\E([_\d\W]|lib|\Z)/i
6221 or length($_)>=4 and $Dir=~/\Q$_\E/i)
6222 { # include/gupnp-1.0/libgupnp/gupnp-context.h
6223 # include/evolution-data-server-1.4/libebook/e-book.h
6224 return 1;
6225 }
6226 }
6227 return 0;
6228}
6229
6230sub checkFamily(@)
6231{
6232 my @Paths = @_;
6233 return 1 if($#Paths<=0);
6234 my %Prefix = ();
6235 foreach my $Path (@Paths)
6236 {
6237 if($SystemRoot) {
6238 $Path = cut_path_prefix($Path, $SystemRoot);
6239 }
6240 if(my $Dir = get_dirname($Path))
6241 {
6242 $Dir=~s/(\/[^\/]+?)[\d\.\-\_]+\Z/$1/g; # remove version suffix
6243 $Prefix{$Dir} += 1;
6244 $Prefix{get_dirname($Dir)} += 1;
6245 }
6246 }
6247 foreach (sort keys(%Prefix))
6248 {
6249 if(get_depth($_)>=3
6250 and $Prefix{$_}==$#Paths+1) {
6251 return 1;
6252 }
6253 }
6254 return 0;
6255}
6256
6257sub isAcceptable($$$)
6258{
6259 my ($Header, $Candidate, $LibVersion) = @_;
6260 my $HName = get_filename($Header);
6261 if(get_dirname($Header))
6262 { # with prefix
6263 return 1;
6264 }
6265 if($HName=~/config|setup/i and $Candidate=~/[\/\\]lib\d*[\/\\]/)
6266 { # allow to search for glibconfig.h in /usr/lib/glib-2.0/include/
6267 return 1;
6268 }
6269 if(checkRelevance($Candidate))
6270 { # allow to search for atk.h in /usr/include/atk-1.0/atk/
6271 return 1;
6272 }
6273 if(checkFamily(getSystemHeaders($HName, $LibVersion)))
6274 { # /usr/include/qt4/QtNetwork/qsslconfiguration.h
6275 # /usr/include/qt4/Qt/qsslconfiguration.h
6276 return 1;
6277 }
6278 if($OStarget eq "symbian")
6279 {
6280 if($Candidate=~/[\/\\]stdapis[\/\\]/) {
6281 return 1;
6282 }
6283 }
6284 return 0;
6285}
6286
6287sub isRelevant($$$)
6288{ # disallow to search for "abstract" headers in too deep directories
6289 my ($Header, $Candidate, $LibVersion) = @_;
6290 my $HName = get_filename($Header);
6291 if($OStarget eq "symbian")
6292 {
6293 if($Candidate=~/[\/\\](tools|stlportv5)[\/\\]/) {
6294 return 0;
6295 }
6296 }
Andrey Ponomarenko9927e332012-10-19 10:50:48 +04006297 if($OStarget ne "bsd")
6298 {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006299 if($Candidate=~/[\/\\]include[\/\\]bsd[\/\\]/)
6300 { # openssh: skip /usr/lib/bcc/include/bsd/signal.h
6301 return 0;
6302 }
6303 }
Andrey Ponomarenko9927e332012-10-19 10:50:48 +04006304 if($OStarget ne "windows")
6305 {
6306 if($Candidate=~/[\/\\](wine|msvcrt|windows)[\/\\]/)
6307 { # skip /usr/include/wine/msvcrt
6308 return 0;
6309 }
6310 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006311 if(not get_dirname($Header)
6312 and $Candidate=~/[\/\\]wx[\/\\]/)
6313 { # do NOT search in system /wx/ directory
6314 # for headers without a prefix: sstream.h
6315 return 0;
6316 }
6317 if($Candidate=~/c\+\+[\/\\]\d+/ and $MAIN_CPP_DIR
6318 and $Candidate!~/\A\Q$MAIN_CPP_DIR\E/)
6319 { # skip ../c++/3.3.3/ if using ../c++/4.5/
6320 return 0;
6321 }
6322 if($Candidate=~/[\/\\]asm-/
6323 and (my $Arch = getArch($LibVersion)) ne "unknown")
6324 { # arch-specific header files
6325 if($Candidate!~/[\/\\]asm-\Q$Arch\E/)
6326 {# skip ../asm-arm/ if using x86 architecture
6327 return 0;
6328 }
6329 }
6330 my @Candidates = getSystemHeaders($HName, $LibVersion);
6331 if($#Candidates==1)
6332 { # unique header
6333 return 1;
6334 }
6335 my @SCandidates = getSystemHeaders($Header, $LibVersion);
6336 if($#SCandidates==1)
6337 { # unique name
6338 return 1;
6339 }
6340 my $SystemDepth = $SystemRoot?get_depth($SystemRoot):0;
6341 if(get_depth($Candidate)-$SystemDepth>=5)
6342 { # abstract headers in too deep directories
6343 # sstream.h or typeinfo.h in /usr/include/wx-2.9/wx/
6344 if(not isAcceptable($Header, $Candidate, $LibVersion)) {
6345 return 0;
6346 }
6347 }
6348 if($Header eq "parser.h"
6349 and $Candidate!~/\/libxml2\//)
6350 { # select parser.h from xml2 library
6351 return 0;
6352 }
6353 if(not get_dirname($Header)
6354 and keys(%{$SystemHeaders{$HName}})>=3)
6355 { # many headers with the same name
6356 # like thread.h included without a prefix
6357 if(not checkFamily(@Candidates)) {
6358 return 0;
6359 }
6360 }
6361 return 1;
6362}
6363
6364sub selectSystemHeader($$)
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04006365{ # cache function
6366 if(defined $Cache{"selectSystemHeader"}{$_[1]}{$_[0]}) {
6367 return $Cache{"selectSystemHeader"}{$_[1]}{$_[0]};
6368 }
6369 return ($Cache{"selectSystemHeader"}{$_[1]}{$_[0]} = selectSystemHeader_I(@_));
6370}
6371
6372sub selectSystemHeader_I($$)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006373{
6374 my ($Header, $LibVersion) = @_;
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04006375 if(-f $Header) {
6376 return $Header;
6377 }
6378 if(is_abs($Header) and not -f $Header)
6379 { # incorrect absolute path
6380 return "";
6381 }
Andrey Ponomarenko9927e332012-10-19 10:50:48 +04006382 if(defined $ConfHeaders{lc($Header)})
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04006383 { # too abstract configuration headers
6384 return "";
6385 }
Andrey Ponomarenko9927e332012-10-19 10:50:48 +04006386 my $HName = get_filename($Header);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006387 if($OSgroup ne "windows")
6388 {
Andrey Ponomarenko9927e332012-10-19 10:50:48 +04006389 if(defined $WinHeaders{lc($HName)}
6390 or $HName=~/windows|win32|win64/i)
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04006391 { # windows headers
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006392 return "";
6393 }
Andrey Ponomarenko9927e332012-10-19 10:50:48 +04006394 }
6395 if($OSgroup ne "macos")
6396 {
6397 if($HName eq "fp.h")
6398 { # pngconf.h includes fp.h for MACOS
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006399 return "";
6400 }
6401 }
6402 if($OSgroup ne "solaris")
6403 {
Andrey Ponomarenko9927e332012-10-19 10:50:48 +04006404 if($Header eq "thread.h") {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006405 return "";
6406 }
6407 }
Andrey Ponomarenko07aea072012-11-12 16:15:07 +04006408 if($OSgroup ne "hpux")
6409 {
6410 if($Header eq "sys/stream.h") {
6411 return "";
6412 }
6413 }
Andrey Ponomarenko9927e332012-10-19 10:50:48 +04006414 if($ObsoleteHeaders{$HName}) {
6415 return "";
6416 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04006417
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006418 foreach my $Path (keys(%{$SystemPaths{"include"}}))
6419 { # search in default paths
6420 if(-f $Path."/".$Header) {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04006421 return joinPath($Path,$Header);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006422 }
6423 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04006424 if(not keys(%SystemHeaders))
6425 { # register all headers in system include dirs
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006426 detectSystemHeaders();
6427 }
6428 foreach my $Candidate (sort {get_depth($a)<=>get_depth($b)}
6429 sort {cmp_paths($b, $a)} getSystemHeaders($Header, $LibVersion))
6430 {
6431 if(isRelevant($Header, $Candidate, $LibVersion)) {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04006432 return $Candidate;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006433 }
6434 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04006435 # error
6436 return "";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006437}
6438
6439sub getSystemHeaders($$)
6440{
6441 my ($Header, $LibVersion) = @_;
6442 my @Candidates = ();
6443 foreach my $Candidate (sort keys(%{$SystemHeaders{$Header}}))
6444 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04006445 if(skipHeader($Candidate, $LibVersion)) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006446 next;
6447 }
6448 push(@Candidates, $Candidate);
6449 }
6450 return @Candidates;
6451}
6452
6453sub cut_path_prefix($$)
6454{
6455 my ($Path, $Prefix) = @_;
6456 return $Path if(not $Prefix);
6457 $Prefix=~s/[\/\\]+\Z//;
6458 $Path=~s/\A\Q$Prefix\E([\/\\]+|\Z)//;
6459 return $Path;
6460}
6461
6462sub is_default_include_dir($)
6463{
6464 my $Dir = $_[0];
6465 $Dir=~s/[\/\\]+\Z//;
6466 return ($DefaultGccPaths{$Dir} or $DefaultCppPaths{$Dir} or $DefaultIncPaths{$Dir});
6467}
6468
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04006469sub identifyHeader($$)
6470{ # cache function
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006471 my ($Header, $LibVersion) = @_;
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04006472 if(not $Header) {
6473 return "";
6474 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006475 $Header=~s/\A(\.\.[\\\/])+//g;
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04006476 if(defined $Cache{"identifyHeader"}{$LibVersion}{$Header}) {
6477 return $Cache{"identifyHeader"}{$LibVersion}{$Header};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006478 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04006479 return ($Cache{"identifyHeader"}{$LibVersion}{$Header} = identifyHeader_I($Header, $LibVersion));
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006480}
6481
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04006482sub identifyHeader_I($$)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006483{ # search for header by absolute path, relative path or name
6484 my ($Header, $LibVersion) = @_;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006485 if(-f $Header)
6486 { # it's relative or absolute path
6487 return get_abs_path($Header);
6488 }
6489 elsif($GlibcHeader{$Header} and not $GLIBC_TESTING
6490 and my $HeaderDir = find_in_defaults($Header))
6491 { # search for libc headers in the /usr/include
6492 # for non-libc target library before searching
6493 # in the library paths
6494 return joinPath($HeaderDir,$Header);
6495 }
6496 elsif(my $Path = $Include_Neighbors{$LibVersion}{$Header})
6497 { # search in the target library paths
6498 return $Path;
6499 }
6500 elsif($DefaultGccHeader{$Header})
6501 { # search in the internal GCC include paths
6502 return $DefaultGccHeader{$Header};
6503 }
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04006504 elsif(my $DefaultDir = find_in_defaults($Header))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006505 { # search in the default GCC include paths
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04006506 return joinPath($DefaultDir,$Header);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006507 }
6508 elsif($DefaultCppHeader{$Header})
6509 { # search in the default G++ include paths
6510 return $DefaultCppHeader{$Header};
6511 }
6512 elsif(my $AnyPath = selectSystemHeader($Header, $LibVersion))
6513 { # search everywhere in the system
6514 return $AnyPath;
6515 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04006516 elsif($OSgroup eq "macos")
6517 { # search in frameworks: "OpenGL/gl.h" is "OpenGL.framework/Headers/gl.h"
6518 if(my $Dir = get_dirname($Header))
6519 {
6520 my $RelPath = "Headers\/".get_filename($Header);
6521 if(my $HeaderDir = find_in_framework($RelPath, $Dir.".framework", $LibVersion)) {
6522 return joinPath($HeaderDir, $RelPath);
6523 }
6524 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006525 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04006526 # cannot find anything
6527 return "";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006528}
6529
6530sub getLocation($)
6531{
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04006532 if($_[0] and my $Info = $LibInfo{$Version}{"info"}{$_[0]})
6533 {
6534 if($Info=~/srcp[ ]*:[ ]*([\w\-\<\>\.\+\/\\]+):(\d+) /) {
Andrey Ponomarenko9927e332012-10-19 10:50:48 +04006535 return (path_format($1, $OSgroup), $2);
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04006536 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006537 }
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04006538 return ();
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006539}
6540
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006541sub getNameByInfo($)
6542{
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04006543 if($_[0] and my $Info = $LibInfo{$Version}{"info"}{$_[0]})
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04006544 {
6545 if($Info=~/name[ ]*:[ ]*@(\d+) /)
6546 {
6547 if(my $NInfo = $LibInfo{$Version}{"info"}{$1})
6548 {
6549 if($NInfo=~/strg[ ]*:[ ]*(.*?)[ ]+lngt/)
6550 { # short unsigned int (may include spaces)
6551 return $1;
6552 }
6553 }
6554 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006555 }
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04006556 return "";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006557}
6558
6559sub getTreeStr($)
6560{
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04006561 if($_[0] and my $Info = $LibInfo{$Version}{"info"}{$_[0]})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006562 {
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04006563 if($Info=~/strg[ ]*:[ ]*([^ ]*)/)
6564 {
6565 my $Str = $1;
Andrey Ponomarenko07aea072012-11-12 16:15:07 +04006566 if($CppMode{$Version}
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04006567 and $Str=~/\Ac99_(.+)\Z/) {
6568 if($CppKeywords_A{$1}) {
6569 $Str=$1;
6570 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006571 }
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04006572 return $Str;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006573 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006574 }
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04006575 return "";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006576}
6577
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006578sub getFuncShortName($)
6579{
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04006580 if(my $Info = $LibInfo{$Version}{"info"}{$_[0]})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006581 {
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04006582 if($Info=~/ operator /)
6583 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04006584 if($Info=~/ conversion /)
6585 {
6586 if(my $Rid = $SymbolInfo{$Version}{$_[0]}{"Return"})
6587 {
6588 if(my $RName = $TypeInfo{$Version}{$Rid}{"Name"}) {
6589 return "operator ".$RName;
6590 }
6591 }
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04006592 }
6593 else
6594 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04006595 if($Info=~/ operator[ ]+([a-zA-Z]+) /)
6596 {
6597 if(my $Ind = $Operator_Indication{$1}) {
6598 return "operator".$Ind;
6599 }
6600 elsif(not $UnknownOperator{$1})
6601 {
6602 printMsg("WARNING", "unknown operator $1");
6603 $UnknownOperator{$1} = 1;
6604 }
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04006605 }
6606 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006607 }
6608 else
6609 {
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04006610 if($Info=~/name[ ]*:[ ]*@(\d+) /) {
6611 return getTreeStr($1);
6612 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006613 }
6614 }
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04006615 return "";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006616}
6617
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006618sub getFuncReturn($)
6619{
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04006620 if($_[0] and my $Info = $LibInfo{$Version}{"info"}{$_[0]})
6621 {
6622 if($Info=~/type[ ]*:[ ]*@(\d+) /)
6623 {
6624 if($LibInfo{$Version}{"info"}{$1}=~/retn[ ]*:[ ]*@(\d+) /) {
6625 return $1;
6626 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006627 }
6628 }
6629 return "";
6630}
6631
6632sub getFuncOrig($)
6633{
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04006634 if($_[0] and my $Info = $LibInfo{$Version}{"info"}{$_[0]})
6635 {
6636 if($Info=~/orig[ ]*:[ ]*@(\d+) /) {
6637 return $1;
6638 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006639 }
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04006640 return $_[0];
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006641}
6642
6643sub unmangleSymbol($)
6644{
6645 my $Symbol = $_[0];
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04006646 if(my @Unmngl = unmangleArray($Symbol)) {
6647 return $Unmngl[0];
6648 }
6649 return "";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006650}
6651
6652sub unmangleArray(@)
6653{
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04006654 if($_[0]=~/\A\?/)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006655 { # MSVC mangling
6656 my $UndNameCmd = get_CmdPath("undname");
6657 if(not $UndNameCmd) {
6658 exitStatus("Not_Found", "can't find \"undname\"");
6659 }
6660 writeFile("$TMP_DIR/unmangle", join("\n", @_));
Andrey Ponomarenkoa01311b2012-06-08 17:20:02 +04006661 return split(/\n/, `$UndNameCmd 0x8386 \"$TMP_DIR/unmangle\"`);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006662 }
6663 else
6664 { # GCC mangling
6665 my $CppFiltCmd = get_CmdPath("c++filt");
6666 if(not $CppFiltCmd) {
6667 exitStatus("Not_Found", "can't find c++filt in PATH");
6668 }
Andrey Ponomarenko9927e332012-10-19 10:50:48 +04006669 if(not defined $CPPFILT_SUPPORT_FILE)
6670 {
6671 my $Info = `$CppFiltCmd -h 2>&1`;
6672 $CPPFILT_SUPPORT_FILE = $Info=~/\@<file>/;
6673 }
6674 if($CPPFILT_SUPPORT_FILE)
6675 { # new versions of c++filt can take a file
6676 if($#_>$MAX_CPPFILT_FILE_SIZE)
6677 { # c++filt <= 2.22 may crash on large files (larger than 8mb)
6678 # this is fixed in the oncoming version of Binutils
6679 my @Half = splice(@_, 0, ($#_+1)/2);
6680 return (unmangleArray(@Half), unmangleArray(@_))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006681 }
Andrey Ponomarenko9927e332012-10-19 10:50:48 +04006682 else
6683 {
6684 my $NoStrip = "";
6685 if($OSgroup eq "macos"
6686 or $OSgroup eq "windows") {
6687 $NoStrip = "-n";
6688 }
6689 writeFile("$TMP_DIR/unmangle", join("\n", @_));
6690 my $Res = `$CppFiltCmd $NoStrip \@\"$TMP_DIR/unmangle\"`;
6691 if($?==139)
6692 { # segmentation fault
6693 printMsg("ERROR", "internal error - c++filt crashed, try to reduce MAX_CPPFILT_FILE_SIZE constant");
6694 }
6695 return split(/\n/, $Res);
6696 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006697 }
6698 else
6699 { # old-style unmangling
Andrey Ponomarenko9927e332012-10-19 10:50:48 +04006700 if($#_>$MAX_COMMAND_LINE_ARGUMENTS)
6701 {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006702 my @Half = splice(@_, 0, ($#_+1)/2);
6703 return (unmangleArray(@Half), unmangleArray(@_))
6704 }
6705 else
6706 {
6707 my $NoStrip = "";
6708 if($OSgroup eq "macos"
6709 or $OSgroup eq "windows") {
6710 $NoStrip = "-n";
6711 }
6712 my $Strings = join(" ", @_);
Andrey Ponomarenko9927e332012-10-19 10:50:48 +04006713 my $Res = `$CppFiltCmd $NoStrip $Strings`;
6714 if($?==139)
6715 { # segmentation fault
6716 printMsg("ERROR", "internal error - c++filt crashed, try to reduce MAX_COMMAND_LINE_ARGUMENTS constant");
6717 }
6718 return split(/\n/, $Res);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006719 }
6720 }
6721 }
6722}
6723
6724sub get_SignatureNoInfo($$)
6725{
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04006726 my ($Symbol, $LibVersion) = @_;
6727 if($Cache{"get_SignatureNoInfo"}{$LibVersion}{$Symbol}) {
6728 return $Cache{"get_SignatureNoInfo"}{$LibVersion}{$Symbol};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006729 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04006730 my ($MnglName, $VersionSpec, $SymbolVersion) = separate_symbol($Symbol);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006731 my $Signature = $tr_name{$MnglName}?$tr_name{$MnglName}:$MnglName;
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04006732 if($Symbol=~/\A(_Z|\?)/)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006733 { # C++
6734 $Signature=~s/\Qstd::basic_string<char, std::char_traits<char>, std::allocator<char> >\E/std::string/g;
6735 $Signature=~s/\Qstd::map<std::string, std::string, std::less<std::string >, std::allocator<std::pair<std::string const, std::string > > >\E/std::map<std::string, std::string>/g;
6736 }
Andrey Ponomarenko82b005f2012-11-12 17:58:14 +04006737 if(not $CheckObjectsOnly or $OSgroup=~/linux|bsd|beos/i)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006738 { # ELF format marks data as OBJECT
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04006739 if($GlobalDataObject{$LibVersion}{$Symbol}) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006740 $Signature .= " [data]";
6741 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04006742 elsif($Symbol!~/\A(_Z|\?)/) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006743 $Signature .= " (...)";
6744 }
6745 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04006746 if(my $ChargeLevel = get_ChargeLevel($Symbol, $LibVersion))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006747 {
Andrey Ponomarenko16934472012-03-29 15:37:04 +04006748 my $ShortName = substr($Signature, 0, find_center($Signature, "("));
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006749 $Signature=~s/\A\Q$ShortName\E/$ShortName $ChargeLevel/g;
6750 }
6751 if($SymbolVersion) {
6752 $Signature .= $VersionSpec.$SymbolVersion;
6753 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04006754 return ($Cache{"get_SignatureNoInfo"}{$LibVersion}{$Symbol} = $Signature);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006755}
6756
6757sub get_ChargeLevel($$)
6758{
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04006759 my ($Symbol, $LibVersion) = @_;
6760 return "" if($Symbol!~/\A(_Z|\?)/);
6761 if(defined $CompleteSignature{$LibVersion}{$Symbol}
6762 and $CompleteSignature{$LibVersion}{$Symbol}{"Header"})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006763 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04006764 if($CompleteSignature{$LibVersion}{$Symbol}{"Constructor"})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006765 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04006766 if($Symbol=~/C1E/) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006767 return "[in-charge]";
6768 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04006769 elsif($Symbol=~/C2E/) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006770 return "[not-in-charge]";
6771 }
6772 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04006773 elsif($CompleteSignature{$LibVersion}{$Symbol}{"Destructor"})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006774 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04006775 if($Symbol=~/D1E/) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006776 return "[in-charge]";
6777 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04006778 elsif($Symbol=~/D2E/) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006779 return "[not-in-charge]";
6780 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04006781 elsif($Symbol=~/D0E/) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006782 return "[in-charge-deleting]";
6783 }
6784 }
6785 }
6786 else
6787 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04006788 if($Symbol=~/C1E/) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006789 return "[in-charge]";
6790 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04006791 elsif($Symbol=~/C2E/) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006792 return "[not-in-charge]";
6793 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04006794 elsif($Symbol=~/D1E/) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006795 return "[in-charge]";
6796 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04006797 elsif($Symbol=~/D2E/) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006798 return "[not-in-charge]";
6799 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04006800 elsif($Symbol=~/D0E/) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006801 return "[in-charge-deleting]";
6802 }
6803 }
6804 return "";
6805}
6806
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04006807sub get_Signature_M($$)
6808{
6809 my ($Symbol, $LibVersion) = @_;
6810 my $Signature_M = $tr_name{$Symbol};
6811 if(my $RTid = $CompleteSignature{$LibVersion}{$Symbol}{"Return"})
6812 { # add return type name
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04006813 $Signature_M = $TypeInfo{$LibVersion}{$RTid}{"Name"}." ".$Signature_M;
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04006814 }
6815 return $Signature_M;
6816}
6817
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006818sub get_Signature($$)
6819{
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04006820 my ($Symbol, $LibVersion) = @_;
6821 if($Cache{"get_Signature"}{$LibVersion}{$Symbol}) {
6822 return $Cache{"get_Signature"}{$LibVersion}{$Symbol};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006823 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04006824 my ($MnglName, $VersionSpec, $SymbolVersion) = separate_symbol($Symbol);
6825 if(isPrivateData($MnglName) or not $CompleteSignature{$LibVersion}{$Symbol}{"Header"})
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04006826 { # non-public global data
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04006827 return get_SignatureNoInfo($Symbol, $LibVersion);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006828 }
6829 my ($Func_Signature, @Param_Types_FromUnmangledName) = ();
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04006830 my $ShortName = $CompleteSignature{$LibVersion}{$Symbol}{"ShortName"};
6831 if($Symbol=~/\A(_Z|\?)/)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006832 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04006833 if(my $ClassId = $CompleteSignature{$LibVersion}{$Symbol}{"Class"}) {
6834 $Func_Signature = $TypeInfo{$LibVersion}{$ClassId}{"Name"}."::".(($CompleteSignature{$LibVersion}{$Symbol}{"Destructor"})?"~":"").$ShortName;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006835 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04006836 elsif(my $NameSpace = $CompleteSignature{$LibVersion}{$Symbol}{"NameSpace"}) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006837 $Func_Signature = $NameSpace."::".$ShortName;
6838 }
6839 else {
6840 $Func_Signature = $ShortName;
6841 }
Andrey Ponomarenko07aea072012-11-12 16:15:07 +04006842 my ($Short, $Params) = split_Signature($tr_name{$MnglName});
6843 @Param_Types_FromUnmangledName = separate_Params($Params, 0, 1);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006844 }
6845 else {
6846 $Func_Signature = $MnglName;
6847 }
6848 my @ParamArray = ();
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04006849 foreach my $Pos (sort {int($a) <=> int($b)} keys(%{$CompleteSignature{$LibVersion}{$Symbol}{"Param"}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006850 {
6851 next if($Pos eq "");
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04006852 my $ParamTypeId = $CompleteSignature{$LibVersion}{$Symbol}{"Param"}{$Pos}{"type"};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006853 next if(not $ParamTypeId);
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04006854 my $ParamTypeName = $TypeInfo{$LibVersion}{$ParamTypeId}{"Name"};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006855 if(not $ParamTypeName) {
6856 $ParamTypeName = $Param_Types_FromUnmangledName[$Pos];
6857 }
6858 foreach my $Typedef (keys(%ChangedTypedef))
6859 {
6860 my $Base = $Typedef_BaseName{$LibVersion}{$Typedef};
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04006861 $ParamTypeName=~s/\b\Q$Typedef\E\b/$Base/g;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006862 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04006863 if(my $ParamName = $CompleteSignature{$LibVersion}{$Symbol}{"Param"}{$Pos}{"name"}) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006864 push(@ParamArray, create_member_decl($ParamTypeName, $ParamName));
6865 }
6866 else {
6867 push(@ParamArray, $ParamTypeName);
6868 }
6869 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04006870 if($CompleteSignature{$LibVersion}{$Symbol}{"Data"}
6871 or $GlobalDataObject{$LibVersion}{$Symbol}) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006872 $Func_Signature .= " [data]";
6873 }
6874 else
6875 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04006876 if(my $ChargeLevel = get_ChargeLevel($Symbol, $LibVersion))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006877 { # add [in-charge]
6878 $Func_Signature .= " ".$ChargeLevel;
6879 }
6880 $Func_Signature .= " (".join(", ", @ParamArray).")";
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04006881 if($CompleteSignature{$LibVersion}{$Symbol}{"Const"}
6882 or $Symbol=~/\A_ZN(V|)K/) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006883 $Func_Signature .= " const";
6884 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04006885 if($CompleteSignature{$LibVersion}{$Symbol}{"Volatile"}
6886 or $Symbol=~/\A_ZN(K|)V/) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006887 $Func_Signature .= " volatile";
6888 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04006889 if($CompleteSignature{$LibVersion}{$Symbol}{"Static"}
6890 and $Symbol=~/\A(_Z|\?)/)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006891 {# for static methods
6892 $Func_Signature .= " [static]";
6893 }
6894 }
6895 if(defined $ShowRetVal
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04006896 and my $ReturnTId = $CompleteSignature{$LibVersion}{$Symbol}{"Return"}) {
6897 $Func_Signature .= ":".$TypeInfo{$LibVersion}{$ReturnTId}{"Name"};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006898 }
6899 if($SymbolVersion) {
6900 $Func_Signature .= $VersionSpec.$SymbolVersion;
6901 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04006902 return ($Cache{"get_Signature"}{$LibVersion}{$Symbol} = $Func_Signature);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006903}
6904
6905sub create_member_decl($$)
6906{
6907 my ($TName, $Member) = @_;
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04006908 if($TName=~/\([\*]+\)/)
6909 {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006910 $TName=~s/\(([\*]+)\)/\($1$Member\)/;
6911 return $TName;
6912 }
6913 else
6914 {
6915 my @ArraySizes = ();
6916 while($TName=~s/(\[[^\[\]]*\])\Z//) {
6917 push(@ArraySizes, $1);
6918 }
6919 return $TName." ".$Member.join("", @ArraySizes);
6920 }
6921}
6922
6923sub getFuncType($)
6924{
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04006925 if($_[0] and my $Info = $LibInfo{$Version}{"info"}{$_[0]})
6926 {
6927 if($Info=~/type[ ]*:[ ]*@(\d+) /)
6928 {
6929 if(my $Type = $LibInfo{$Version}{"info_type"}{$1})
6930 {
6931 if($Type eq "method_type") {
6932 return "Method";
6933 }
6934 elsif($Type eq "function_type") {
6935 return "Function";
6936 }
6937 else {
6938 return "Other";
6939 }
6940 }
6941 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006942 }
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +04006943 return "";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006944}
6945
6946sub getFuncTypeId($)
6947{
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04006948 if($_[0] and my $Info = $LibInfo{$Version}{"info"}{$_[0]})
6949 {
6950 if($Info=~/type[ ]*:[ ]*@(\d+)( |\Z)/) {
6951 return $1;
6952 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006953 }
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04006954 return 0;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006955}
6956
6957sub isNotAnon($) {
6958 return (not isAnon($_[0]));
6959}
6960
6961sub isAnon($)
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04006962{ # "._N" or "$_N" in older GCC versions
6963 return ($_[0] and $_[0]=~/(\.|\$)\_\d+|anon\-/);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006964}
6965
Andrey Ponomarenko9927e332012-10-19 10:50:48 +04006966sub formatName($$)
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04006967{ # type name correction
Andrey Ponomarenko9927e332012-10-19 10:50:48 +04006968 if(defined $Cache{"formatName"}{$_[1]}{$_[0]}) {
6969 return $Cache{"formatName"}{$_[1]}{$_[0]};
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04006970 }
6971
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +04006972 my $N = $_[0];
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04006973
Andrey Ponomarenko9927e332012-10-19 10:50:48 +04006974 if($_[1] ne "S")
6975 {
6976 $N=~s/\A[ ]+//g;
6977 $N=~s/[ ]+\Z//g;
6978 $N=~s/[ ]{2,}/ /g;
6979 }
6980
6981 $N=~s/[ ]*(\W)[ ]*/$1/g; # std::basic_string<char> const
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04006982
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +04006983 $N=~s/\bvolatile const\b/const volatile/g;
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04006984
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +04006985 $N=~s/\b(long long|short|long) unsigned\b/unsigned $1/g;
6986 $N=~s/\b(short|long) int\b/$1/g;
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04006987
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +04006988 $N=~s/([\)\]])(const|volatile)\b/$1 $2/g;
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04006989
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +04006990 while($N=~s/>>/> >/g) {};
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04006991
Andrey Ponomarenko9927e332012-10-19 10:50:48 +04006992 if($_[1] eq "S")
6993 {
6994 if(index($N, "operator")!=-1) {
6995 $N=~s/\b(operator[ ]*)> >/$1>>/;
6996 }
6997 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04006998
Andrey Ponomarenko9927e332012-10-19 10:50:48 +04006999 return ($Cache{"formatName"}{$_[1]}{$_[0]} = $N);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007000}
7001
7002sub get_HeaderDeps($$)
7003{
7004 my ($AbsPath, $LibVersion) = @_;
7005 return () if(not $AbsPath or not $LibVersion);
7006 if(defined $Cache{"get_HeaderDeps"}{$LibVersion}{$AbsPath}) {
7007 return @{$Cache{"get_HeaderDeps"}{$LibVersion}{$AbsPath}};
7008 }
7009 my %IncDir = ();
7010 detect_recursive_includes($AbsPath, $LibVersion);
7011 foreach my $HeaderPath (keys(%{$RecursiveIncludes{$LibVersion}{$AbsPath}}))
7012 {
7013 next if(not $HeaderPath);
7014 next if($MAIN_CPP_DIR and $HeaderPath=~/\A\Q$MAIN_CPP_DIR\E([\/\\]|\Z)/);
7015 my $Dir = get_dirname($HeaderPath);
7016 foreach my $Prefix (keys(%{$Header_Include_Prefix{$LibVersion}{$AbsPath}{$HeaderPath}}))
7017 {
7018 my $Dep = $Dir;
7019 if($Prefix)
7020 {
7021 if($OSgroup eq "windows")
7022 { # case insensitive seach on windows
7023 if(not $Dep=~s/[\/\\]+\Q$Prefix\E\Z//ig) {
7024 next;
7025 }
7026 }
7027 elsif($OSgroup eq "macos")
7028 { # seach in frameworks
7029 if(not $Dep=~s/[\/\\]+\Q$Prefix\E\Z//g)
7030 {
7031 if($HeaderPath=~/(.+\.framework)\/Headers\/([^\/]+)/)
7032 {# frameworks
7033 my ($HFramework, $HName) = ($1, $2);
7034 $Dep = $HFramework;
7035 }
7036 else
7037 {# mismatch
7038 next;
7039 }
7040 }
7041 }
7042 elsif(not $Dep=~s/[\/\\]+\Q$Prefix\E\Z//g)
7043 { # Linux, FreeBSD
7044 next;
7045 }
7046 }
7047 if(not $Dep)
7048 { # nothing to include
7049 next;
7050 }
7051 if(is_default_include_dir($Dep))
7052 { # included by the compiler
7053 next;
7054 }
7055 if(get_depth($Dep)==1)
7056 { # too short
7057 next;
7058 }
7059 if(isLibcDir($Dep))
7060 { # do NOT include /usr/include/{sys,bits}
7061 next;
7062 }
7063 $IncDir{$Dep}=1;
7064 }
7065 }
7066 $Cache{"get_HeaderDeps"}{$LibVersion}{$AbsPath} = sortIncPaths([keys(%IncDir)], $LibVersion);
7067 return @{$Cache{"get_HeaderDeps"}{$LibVersion}{$AbsPath}};
7068}
7069
7070sub sortIncPaths($$)
7071{
7072 my ($ArrRef, $LibVersion) = @_;
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04007073 if(not $ArrRef or $#{$ArrRef}<0) {
7074 return $ArrRef;
7075 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007076 @{$ArrRef} = sort {$b cmp $a} @{$ArrRef};
7077 @{$ArrRef} = sort {get_depth($a)<=>get_depth($b)} @{$ArrRef};
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04007078 @{$ArrRef} = sort {sortDeps($b, $a, $LibVersion)} @{$ArrRef};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007079 return $ArrRef;
7080}
7081
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04007082sub sortDeps($$$)
7083{
7084 if($Header_Dependency{$_[2]}{$_[0]}
7085 and not $Header_Dependency{$_[2]}{$_[1]}) {
7086 return 1;
7087 }
7088 elsif(not $Header_Dependency{$_[2]}{$_[0]}
7089 and $Header_Dependency{$_[2]}{$_[1]}) {
7090 return -1;
7091 }
7092 return 0;
7093}
7094
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007095sub joinPath($$) {
7096 return join($SLASH, @_);
7097}
7098
7099sub get_namespace_additions($)
7100{
7101 my $NameSpaces = $_[0];
7102 my ($Additions, $AddNameSpaceId) = ("", 1);
7103 foreach my $NS (sort {$a=~/_/ <=> $b=~/_/} sort {lc($a) cmp lc($b)} keys(%{$NameSpaces}))
7104 {
7105 next if($SkipNameSpaces{$Version}{$NS});
7106 next if(not $NS or $NameSpaces->{$NS}==-1);
7107 next if($NS=~/(\A|::)iterator(::|\Z)/i);
7108 next if($NS=~/\A__/i);
7109 next if(($NS=~/\Astd::/ or $NS=~/\A(std|tr1|rel_ops|fcntl)\Z/) and not $STDCXX_TESTING);
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04007110 $NestedNameSpaces{$Version}{$NS} = 1; # for future use in reports
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007111 my ($TypeDecl_Prefix, $TypeDecl_Suffix) = ();
7112 my @NS_Parts = split(/::/, $NS);
7113 next if($#NS_Parts==-1);
7114 next if($NS_Parts[0]=~/\A(random|or)\Z/);
7115 foreach my $NS_Part (@NS_Parts)
7116 {
7117 $TypeDecl_Prefix .= "namespace $NS_Part\{";
7118 $TypeDecl_Suffix .= "}";
7119 }
7120 my $TypeDecl = $TypeDecl_Prefix."typedef int tmp_add_type_$AddNameSpaceId;".$TypeDecl_Suffix;
7121 my $FuncDecl = "$NS\:\:tmp_add_type_$AddNameSpaceId tmp_add_func_$AddNameSpaceId(){return 0;};";
7122 $Additions.=" $TypeDecl\n $FuncDecl\n";
7123 $AddNameSpaceId+=1;
7124 }
7125 return $Additions;
7126}
7127
7128sub path_format($$)
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04007129{ # forward slash to pass into MinGW GCC
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007130 my ($Path, $Fmt) = @_;
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04007131 if($Fmt eq "windows")
7132 {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007133 $Path=~s/\//\\/g;
7134 $Path=lc($Path);
7135 }
7136 else {
7137 $Path=~s/\\/\//g;
7138 }
7139 return $Path;
7140}
7141
7142sub inc_opt($$)
7143{
7144 my ($Path, $Style) = @_;
7145 if($Style eq "GCC")
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04007146 { # GCC options
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007147 if($OSgroup eq "windows")
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04007148 { # to MinGW GCC
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007149 return "-I\"".path_format($Path, "unix")."\"";
7150 }
7151 elsif($OSgroup eq "macos"
7152 and $Path=~/\.framework\Z/)
7153 {# to Apple's GCC
7154 return "-F".esc(get_dirname($Path));
7155 }
7156 else {
7157 return "-I".esc($Path);
7158 }
7159 }
7160 elsif($Style eq "CL") {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04007161 return "/I \"".$Path."\"";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007162 }
7163 return "";
7164}
7165
7166sub platformSpecs($)
7167{
7168 my $LibVersion = $_[0];
7169 my $Arch = getArch($LibVersion);
7170 if($OStarget eq "symbian")
7171 { # options for GCCE compiler
7172 my %Symbian_Opts = map {$_=>1} (
7173 "-D__GCCE__",
7174 "-DUNICODE",
7175 "-fexceptions",
7176 "-D__SYMBIAN32__",
7177 "-D__MARM_INTERWORK__",
7178 "-D_UNICODE",
7179 "-D__S60_50__",
7180 "-D__S60_3X__",
7181 "-D__SERIES60_3X__",
7182 "-D__EPOC32__",
7183 "-D__MARM__",
7184 "-D__EABI__",
7185 "-D__MARM_ARMV5__",
7186 "-D__SUPPORT_CPP_EXCEPTIONS__",
7187 "-march=armv5t",
7188 "-mapcs",
7189 "-mthumb-interwork",
7190 "-DEKA2",
7191 "-DSYMBIAN_ENABLE_SPLIT_HEADERS"
7192 );
7193 return join(" ", keys(%Symbian_Opts));
7194 }
7195 elsif($OSgroup eq "windows"
7196 and get_dumpmachine($GCC_PATH)=~/mingw/i)
7197 { # add options to MinGW compiler
7198 # to simulate the MSVC compiler
7199 my %MinGW_Opts = map {$_=>1} (
7200 "-D_WIN32",
7201 "-D_STDCALL_SUPPORTED",
7202 "-D__int64=\"long long\"",
7203 "-D__int32=int",
7204 "-D__int16=short",
7205 "-D__int8=char",
7206 "-D__possibly_notnullterminated=\" \"",
7207 "-D__nullterminated=\" \"",
7208 "-D__nullnullterminated=\" \"",
7209 "-D__w64=\" \"",
7210 "-D__ptr32=\" \"",
7211 "-D__ptr64=\" \"",
7212 "-D__forceinline=inline",
7213 "-D__inline=inline",
7214 "-D__uuidof(x)=IID()",
7215 "-D__try=",
7216 "-D__except(x)=",
7217 "-D__declspec(x)=__attribute__((x))",
7218 "-D__pragma(x)=",
7219 "-D_inline=inline",
7220 "-D__forceinline=__inline",
7221 "-D__stdcall=__attribute__((__stdcall__))",
7222 "-D__cdecl=__attribute__((__cdecl__))",
7223 "-D__fastcall=__attribute__((__fastcall__))",
7224 "-D__thiscall=__attribute__((__thiscall__))",
7225 "-D_stdcall=__attribute__((__stdcall__))",
7226 "-D_cdecl=__attribute__((__cdecl__))",
7227 "-D_fastcall=__attribute__((__fastcall__))",
7228 "-D_thiscall=__attribute__((__thiscall__))",
7229 "-DSHSTDAPI_(x)=x",
7230 "-D_MSC_EXTENSIONS",
7231 "-DSECURITY_WIN32",
7232 "-D_MSC_VER=1500",
7233 "-D_USE_DECLSPECS_FOR_SAL",
7234 "-D__noop=\" \"",
7235 "-DDECLSPEC_DEPRECATED=\" \"",
7236 "-D__builtin_alignof(x)=__alignof__(x)",
7237 "-DSORTPP_PASS");
7238 if($Arch eq "x86") {
7239 $MinGW_Opts{"-D_M_IX86=300"}=1;
7240 }
7241 elsif($Arch eq "x86_64") {
7242 $MinGW_Opts{"-D_M_AMD64=300"}=1;
7243 }
7244 elsif($Arch eq "ia64") {
7245 $MinGW_Opts{"-D_M_IA64=300"}=1;
7246 }
7247 return join(" ", keys(%MinGW_Opts));
7248 }
7249 return "";
7250}
7251
7252my %C_Structure = map {$_=>1} (
7253# FIXME: Can't separate union and struct data types before dumping,
7254# so it sometimes cause compilation errors for unknown reason
7255# when trying to declare TYPE* tmp_add_class_N
7256# This is a list of such structures + list of other C structures
7257 "sigval",
7258 "sigevent",
7259 "sigaction",
7260 "sigvec",
7261 "sigstack",
7262 "timeval",
7263 "timezone",
7264 "rusage",
7265 "rlimit",
7266 "wait",
7267 "flock",
7268 "stat",
7269 "_stat",
7270 "stat32",
7271 "_stat32",
7272 "stat64",
7273 "_stat64",
7274 "_stati64",
7275 "if_nameindex",
7276 "usb_device",
7277 "sigaltstack",
7278 "sysinfo",
7279 "timeLocale",
7280 "tcp_debug",
7281 "rpc_createerr",
Andrey Ponomarenko82b005f2012-11-12 17:58:14 +04007282 # Other
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007283 "timespec",
7284 "random_data",
7285 "drand48_data",
7286 "_IO_marker",
7287 "_IO_FILE",
7288 "lconv",
7289 "sched_param",
7290 "tm",
7291 "itimerspec",
7292 "_pthread_cleanup_buffer",
7293 "fd_set",
Andrey Ponomarenko01117f12012-06-26 12:23:02 +04007294 "siginfo",
Andrey Ponomarenko82b005f2012-11-12 17:58:14 +04007295 "mallinfo",
7296 # Mac
7297 "_timex",
7298 "_class_t",
7299 "_category_t",
7300 "_class_ro_t",
7301 "_protocol_t",
7302 "_message_ref_t",
7303 "_super_message_ref_t",
7304 "_ivar_t",
7305 "_ivar_list_t"
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007306);
7307
7308sub getCompileCmd($$$)
7309{
7310 my ($Path, $Opt, $Inc) = @_;
7311 my $GccCall = $GCC_PATH;
7312 if($Opt) {
7313 $GccCall .= " ".$Opt;
7314 }
7315 $GccCall .= " -x ";
7316 if($OSgroup eq "macos") {
7317 $GccCall .= "objective-";
7318 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04007319 if(check_gcc($GCC_PATH, "4"))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007320 { # compile as "C++" header
7321 # to obtain complete dump using GCC 4.0
7322 $GccCall .= "c++-header";
7323 }
7324 else
7325 { # compile as "C++" source
7326 # GCC 3.3 cannot compile headers
7327 $GccCall .= "c++";
7328 }
7329 if(my $Opts = platformSpecs($Version))
7330 {# platform-specific options
7331 $GccCall .= " ".$Opts;
7332 }
7333 # allow extra qualifications
7334 # and other nonconformant code
Andrey Ponomarenko01117f12012-06-26 12:23:02 +04007335 $GccCall .= " -fpermissive";
7336 $GccCall .= " -w";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007337 if($NoStdInc)
7338 {
7339 $GccCall .= " -nostdinc";
7340 $GccCall .= " -nostdinc++";
7341 }
7342 if($CompilerOptions{$Version})
7343 { # user-defined options
7344 $GccCall .= " ".$CompilerOptions{$Version};
7345 }
Andrey Ponomarenkoa01311b2012-06-08 17:20:02 +04007346 $GccCall .= " \"$Path\"";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007347 if($Inc)
7348 { # include paths
7349 $GccCall .= " ".$Inc;
7350 }
7351 return $GccCall;
7352}
7353
Andrey Ponomarenko01117f12012-06-26 12:23:02 +04007354sub detectPreamble($$)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007355{
Andrey Ponomarenko01117f12012-06-26 12:23:02 +04007356 my ($Content, $LibVersion) = @_;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007357 my %HeaderElems = (
7358 # Types
7359 "stdio.h" => ["FILE", "va_list"],
Andrey Ponomarenko85043792012-05-14 16:48:07 +04007360 "stddef.h" => ["NULL", "ptrdiff_t"],
Andrey Ponomarenko9927e332012-10-19 10:50:48 +04007361 "stdint.h" => ["uint8_t", "uint16_t", "uint32_t", "uint64_t",
7362 "int8_t", "int16_t", "int32_t", "int64_t"],
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007363 "time.h" => ["time_t"],
7364 "sys/types.h" => ["ssize_t", "u_int32_t", "u_short", "u_char",
Andrey Ponomarenko9927e332012-10-19 10:50:48 +04007365 "u_int", "off_t", "u_quad_t", "u_long", "mode_t"],
7366 "unistd.h" => ["gid_t", "uid_t", "socklen_t"],
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007367 "stdbool.h" => ["_Bool"],
7368 "rpc/xdr.h" => ["bool_t"],
7369 "in_systm.h" => ["n_long", "n_short"],
7370 # Fields
Andrey Ponomarenkobede8372012-03-29 17:43:21 +04007371 "arpa/inet.h" => ["fw_src", "ip_src"],
7372 # Functions
Andrey Ponomarenko9927e332012-10-19 10:50:48 +04007373 "stdlib.h" => ["free", "malloc", "size_t"],
Andrey Ponomarenko85043792012-05-14 16:48:07 +04007374 "string.h" => ["memmove", "strcmp"]
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007375 );
7376 my %AutoPreamble = ();
Andrey Ponomarenko85043792012-05-14 16:48:07 +04007377 foreach (keys(%HeaderElems))
7378 {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007379 foreach my $Elem (@{$HeaderElems{$_}}) {
Andrey Ponomarenko9927e332012-10-19 10:50:48 +04007380 $AutoPreamble{$Elem} = $_;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007381 }
7382 }
Andrey Ponomarenko01117f12012-06-26 12:23:02 +04007383 my %Types = ();
7384 while($Content=~s/error\:\s*(field\s*|)\W+(.+?)\W+//)
7385 { # error: 'FILE' has not been declared
Andrey Ponomarenko9927e332012-10-19 10:50:48 +04007386 $Types{$2} = 1;
Andrey Ponomarenko01117f12012-06-26 12:23:02 +04007387 }
7388 if(keys(%Types))
7389 {
7390 my %AddHeaders = ();
7391 foreach my $Type (keys(%Types))
7392 {
7393 if(my $Header = $AutoPreamble{$Type})
7394 {
Andrey Ponomarenko9927e332012-10-19 10:50:48 +04007395 if(my $Path = identifyHeader($Header, $LibVersion))
7396 {
7397 if(skipHeader($Path, $LibVersion)) {
7398 next;
7399 }
7400 $Path = path_format($Path, $OSgroup);
7401 $AddHeaders{$Path}{"Type"} = $Type;
7402 $AddHeaders{$Path}{"Header"} = $Header;
Andrey Ponomarenko01117f12012-06-26 12:23:02 +04007403 }
7404 }
7405 }
7406 if(keys(%AddHeaders)) {
Andrey Ponomarenko9927e332012-10-19 10:50:48 +04007407 return \%AddHeaders;
Andrey Ponomarenko01117f12012-06-26 12:23:02 +04007408 }
7409 }
Andrey Ponomarenko9927e332012-10-19 10:50:48 +04007410 return undef;
Andrey Ponomarenko01117f12012-06-26 12:23:02 +04007411}
7412
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +04007413sub checkCTags($)
7414{
7415 my $Path = $_[0];
7416 if(not $Path) {
7417 return;
7418 }
7419 my $CTags = get_CmdPath("ctags");
7420 if(not $CTags) {
7421 return;
7422 }
Andrey Ponomarenkobdc85a92012-11-12 17:28:12 +04007423
Andrey Ponomarenko82b005f2012-11-12 17:58:14 +04007424 if($OSgroup ne "linux")
7425 { # macos, freebsd, etc.
Andrey Ponomarenkobdc85a92012-11-12 17:28:12 +04007426 my $Info = `$CTags --version 2>\"$TMP_DIR/null\"`;
7427 if($Info!~/exuberant/i)
7428 {
7429 printMsg("WARNING", "incompatible version of \'ctags\' program");
7430 return;
7431 }
7432 }
7433
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +04007434 my $Out = $TMP_DIR."/ctags.txt";
Andrey Ponomarenkobdc85a92012-11-12 17:28:12 +04007435 system("$CTags --c-kinds=pxn -f \"$Out\" \"$Path\" 2>\"$TMP_DIR/null\"");
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +04007436 if($Debug) {
Andrey Ponomarenko9927e332012-10-19 10:50:48 +04007437 copy($Out, $DEBUG_PATH{$Version}."/ctags.txt");
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +04007438 }
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +04007439 open(CTAGS, "<", $Out);
7440 while(my $Line = <CTAGS>)
7441 {
7442 chomp($Line);
7443 my ($Name, $Header, $Def, $Type, $Scpe) = split(/\t/, $Line);
Andrey Ponomarenko9927e332012-10-19 10:50:48 +04007444 if(defined $Intrinsic_Keywords{$Name})
7445 { # noise
7446 next;
7447 }
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +04007448 if($Type eq "n")
7449 {
Andrey Ponomarenko9927e332012-10-19 10:50:48 +04007450 if(index($Scpe, "class:")==0) {
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +04007451 next;
7452 }
Andrey Ponomarenko9927e332012-10-19 10:50:48 +04007453 if(index($Scpe, "struct:")==0) {
7454 next;
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +04007455 }
Andrey Ponomarenko9927e332012-10-19 10:50:48 +04007456 if(index($Scpe, "namespace:")==0)
7457 {
7458 if($Scpe=~s/\Anamespace://) {
7459 $Name = $Scpe."::".$Name;
7460 }
7461 }
7462 $TUnit_NameSpaces{$Version}{$Name} = 1;
7463 }
7464 elsif($Type eq "p")
7465 {
7466 if(not $Scpe or index($Scpe, "namespace:")==0) {
7467 $TUnit_Funcs{$Version}{$Name} = 1;
7468 }
7469 }
7470 elsif($Type eq "x")
7471 {
7472 if(not $Scpe or index($Scpe, "namespace:")==0) {
7473 $TUnit_Vars{$Version}{$Name} = 1;
7474 }
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +04007475 }
7476 }
7477 close(CTAGS);
7478}
7479
Andrey Ponomarenko01117f12012-06-26 12:23:02 +04007480sub getDump()
7481{
7482 if(not $GCC_PATH) {
7483 exitStatus("Error", "internal error - GCC path is not set");
7484 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04007485 my $TmpHeaderPath = $TMP_DIR."/dump".$Version.".h";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007486 my $MHeaderPath = $TmpHeaderPath;
Andrey Ponomarenko85043792012-05-14 16:48:07 +04007487 open(TMP_HEADER, ">", $TmpHeaderPath) || die ("can't open file \'$TmpHeaderPath\': $!\n");
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007488 if(my $AddDefines = $Descriptor{$Version}{"Defines"})
7489 {
7490 $AddDefines=~s/\n\s+/\n /g;
Andrey Ponomarenko85043792012-05-14 16:48:07 +04007491 print TMP_HEADER "\n // add defines\n ".$AddDefines."\n";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007492 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +04007493 print TMP_HEADER "\n // add includes\n";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007494 my @PreambleHeaders = keys(%{$Include_Preamble{$Version}});
7495 @PreambleHeaders = sort {int($Include_Preamble{$Version}{$a}{"Position"})<=>int($Include_Preamble{$Version}{$b}{"Position"})} @PreambleHeaders;
7496 foreach my $Header_Path (@PreambleHeaders) {
Andrey Ponomarenko85043792012-05-14 16:48:07 +04007497 print TMP_HEADER " #include \"".path_format($Header_Path, "unix")."\"\n";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007498 }
7499 my @Headers = keys(%{$Registered_Headers{$Version}});
7500 @Headers = sort {int($Registered_Headers{$Version}{$a}{"Pos"})<=>int($Registered_Headers{$Version}{$b}{"Pos"})} @Headers;
7501 foreach my $Header_Path (@Headers)
7502 {
7503 next if($Include_Preamble{$Version}{$Header_Path});
Andrey Ponomarenko85043792012-05-14 16:48:07 +04007504 print TMP_HEADER " #include \"".path_format($Header_Path, "unix")."\"\n";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007505 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +04007506 close(TMP_HEADER);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007507 my $IncludeString = getIncString(getIncPaths(@PreambleHeaders, @Headers), "GCC");
Andrey Ponomarenko9927e332012-10-19 10:50:48 +04007508
Andrey Ponomarenko07aea072012-11-12 16:15:07 +04007509 if($ExtraInfo)
7510 { # extra information for other tools
7511 writeFile($ExtraInfo."/include-string", $IncludeString);
7512 }
7513
Andrey Ponomarenko9927e332012-10-19 10:50:48 +04007514 if(not keys(%{$TargetHeaders{$Version}}))
7515 { # Target headers
7516 addTargetHeaders($Version);
7517 }
7518
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007519 if($Debug)
7520 { # debug mode
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04007521 writeFile($DEBUG_PATH{$Version}."/headers/direct-includes.txt", Dumper($Header_Includes{$Version}));
7522 writeFile($DEBUG_PATH{$Version}."/headers/recursive-includes.txt", Dumper($RecursiveIncludes{$Version}));
7523 writeFile($DEBUG_PATH{$Version}."/headers/include-paths.txt", Dumper($Cache{"get_HeaderDeps"}{$Version}));
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04007524 writeFile($DEBUG_PATH{$Version}."/headers/default-paths.txt", Dumper(\%DefaultIncPaths));
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007525 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +04007526
Andrey Ponomarenko85043792012-05-14 16:48:07 +04007527 # clean memory
7528 %RecursiveIncludes = ();
7529 %Header_Include_Prefix = ();
7530 %Header_Includes = ();
7531
7532 # clean cache
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04007533 delete($Cache{"identifyHeader"});
Andrey Ponomarenko85043792012-05-14 16:48:07 +04007534 delete($Cache{"detect_header_includes"});
7535 delete($Cache{"selectSystemHeader"});
7536
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007537 # preprocessing stage
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +04007538 my $Pre = callPreprocessor($TmpHeaderPath, $IncludeString, $Version);
7539 checkPreprocessedUnit($Pre);
Andrey Ponomarenko85043792012-05-14 16:48:07 +04007540
7541 # clean memory
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04007542 delete($Include_Neighbors{$Version});
Andrey Ponomarenko85043792012-05-14 16:48:07 +04007543
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +04007544 if($COMMON_LANGUAGE{$Version} eq "C++") {
7545 checkCTags($Pre);
7546 }
7547
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007548 my $MContent = "";
7549 my $PreprocessCmd = getCompileCmd($TmpHeaderPath, "-E", $IncludeString);
7550 if($OStarget eq "windows"
7551 and get_dumpmachine($GCC_PATH)=~/mingw/i
7552 and $MinGWMode{$Version}!=-1)
7553 { # modify headers to compile by MinGW
7554 if(not $MContent)
7555 { # preprocessing
Andrey Ponomarenkoa01311b2012-06-08 17:20:02 +04007556 $MContent = `$PreprocessCmd 2>\"$TMP_DIR/null\"`;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007557 }
7558 if($MContent=~s/__asm\s*(\{[^{}]*?\}|[^{};]*)//g)
7559 { # __asm { ... }
7560 $MinGWMode{$Version}=1;
7561 }
7562 if($MContent=~s/\s+(\/ \/.*?)\n/\n/g)
7563 { # comments after preprocessing
7564 $MinGWMode{$Version}=1;
7565 }
7566 if($MContent=~s/(\W)(0x[a-f]+|\d+)(i|ui)(8|16|32|64)(\W)/$1$2$5/g)
7567 { # 0xffui8
7568 $MinGWMode{$Version}=1;
7569 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +04007570 if($MinGWMode{$Version})
7571 {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007572 printMsg("INFO", "Using MinGW compatibility mode");
Andrey Ponomarenkob8d203d2012-05-25 18:11:07 +04007573 $MHeaderPath = $TMP_DIR."/dump$Version.i";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007574 }
7575 }
7576 if(($COMMON_LANGUAGE{$Version} eq "C" or $CheckHeadersOnly)
Andrey Ponomarenko07aea072012-11-12 16:15:07 +04007577 and $CppMode{$Version}!=-1 and not $CppCompat)
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04007578 { # rename C++ keywords in C code
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007579 if(not $MContent)
7580 { # preprocessing
Andrey Ponomarenkoa01311b2012-06-08 17:20:02 +04007581 $MContent = `$PreprocessCmd 2>\"$TMP_DIR/null\"`;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007582 }
7583 my $RegExp_C = join("|", keys(%CppKeywords_C));
7584 my $RegExp_F = join("|", keys(%CppKeywords_F));
7585 my $RegExp_O = join("|", keys(%CppKeywords_O));
Andrey Ponomarenkobdc85a92012-11-12 17:28:12 +04007586
7587 my $Detected = undef;
7588
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007589 while($MContent=~s/(\A|\n[^\#\/\n][^\n]*?|\n)(\*\s*|\s+|\@|\,|\()($RegExp_C|$RegExp_F)(\s*(\,|\)|\;|\-\>|\.|\:\s*\d))/$1$2c99_$3$4/g)
7590 { # MATCH:
7591 # int foo(int new, int class, int (*new)(int));
7592 # unsigned private: 8;
7593 # DO NOT MATCH:
7594 # #pragma GCC visibility push(default)
Andrey Ponomarenko07aea072012-11-12 16:15:07 +04007595 $CppMode{$Version} = 1;
Andrey Ponomarenkobdc85a92012-11-12 17:28:12 +04007596 $Detected = "$1$2$3$4" if(not defined $Detected);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007597 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04007598 if($MContent=~s/([^\w\s]|\w\s+)(?<!operator )(delete)(\s*\()/$1c99_$2$3/g)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007599 { # MATCH:
7600 # int delete(...);
7601 # int explicit(...);
7602 # DO NOT MATCH:
7603 # void operator delete(...)
Andrey Ponomarenko07aea072012-11-12 16:15:07 +04007604 $CppMode{$Version} = 1;
Andrey Ponomarenkobdc85a92012-11-12 17:28:12 +04007605 $Detected = "$1$2$3" if(not defined $Detected);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007606 }
7607 if($MContent=~s/(\s+)($RegExp_O)(\s*(\;|\:))/$1c99_$2$3/g)
7608 { # MATCH:
7609 # int bool;
7610 # DO NOT MATCH:
7611 # bool X;
7612 # return *this;
7613 # throw;
Andrey Ponomarenko07aea072012-11-12 16:15:07 +04007614 $CppMode{$Version} = 1;
Andrey Ponomarenkobdc85a92012-11-12 17:28:12 +04007615 $Detected = "$1$2$3" if(not defined $Detected);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007616 }
7617 if($MContent=~s/(\s+)(operator)(\s*(\(\s*\)\s*[^\(\s]|\(\s*[^\)\s]))/$1c99_$2$3/g)
7618 { # MATCH:
7619 # int operator(...);
7620 # DO NOT MATCH:
7621 # int operator()(...);
Andrey Ponomarenko07aea072012-11-12 16:15:07 +04007622 $CppMode{$Version} = 1;
Andrey Ponomarenkobdc85a92012-11-12 17:28:12 +04007623 $Detected = "$1$2$3" if(not defined $Detected);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007624 }
7625 if($MContent=~s/([^\w\(\,\s]\s*|\s+)(operator)(\s*(\,\s*[^\(\s]|\)))/$1c99_$2$3/g)
7626 { # MATCH:
7627 # int foo(int operator);
7628 # int foo(int operator, int other);
7629 # DO NOT MATCH:
7630 # int operator,(...);
Andrey Ponomarenko07aea072012-11-12 16:15:07 +04007631 $CppMode{$Version} = 1;
Andrey Ponomarenkobdc85a92012-11-12 17:28:12 +04007632 $Detected = "$1$2$3" if(not defined $Detected);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007633 }
7634 if($MContent=~s/(\*\s*|\w\s+)(bool)(\s*(\,|\)))/$1c99_$2$3/g)
7635 { # MATCH:
7636 # int foo(gboolean *bool);
7637 # DO NOT MATCH:
7638 # void setTabEnabled(int index, bool);
Andrey Ponomarenko07aea072012-11-12 16:15:07 +04007639 $CppMode{$Version} = 1;
Andrey Ponomarenkobdc85a92012-11-12 17:28:12 +04007640 $Detected = "$1$2$3" if(not defined $Detected);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007641 }
Andrey Ponomarenko9927e332012-10-19 10:50:48 +04007642 if($MContent=~s/(\w)(\s*[^\w\(\,\s]\s*|\s+)(this|throw)(\s*[\,\)])/$1$2c99_$3$4/g)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007643 { # MATCH:
7644 # int foo(int* this);
7645 # int bar(int this);
Andrey Ponomarenko9927e332012-10-19 10:50:48 +04007646 # int baz(int throw);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007647 # DO NOT MATCH:
Andrey Ponomarenko9927e332012-10-19 10:50:48 +04007648 # foo(X, this);
Andrey Ponomarenko07aea072012-11-12 16:15:07 +04007649 $CppMode{$Version} = 1;
Andrey Ponomarenkobdc85a92012-11-12 17:28:12 +04007650 $Detected = "$1$2$3$4" if(not defined $Detected);
Andrey Ponomarenko07aea072012-11-12 16:15:07 +04007651 }
7652
7653 if($CppMode{$Version} == 1)
7654 {
Andrey Ponomarenkobdc85a92012-11-12 17:28:12 +04007655 if($Debug)
7656 {
7657 $Detected=~s/\A\s+//g;
7658 printMsg("INFO", "Detected code: \"$Detected\"");
Andrey Ponomarenko07aea072012-11-12 16:15:07 +04007659 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007660 }
Andrey Ponomarenko9927e332012-10-19 10:50:48 +04007661
7662 # remove typedef enum NAME NAME;
7663 my @FwdTypedefs = $MContent=~/typedef\s+enum\s+(\w+)\s+(\w+);/g;
7664 my $N = 0;
7665 while($N<=$#FwdTypedefs-1)
7666 {
7667 my $S = $FwdTypedefs[$N];
7668 if($S eq $FwdTypedefs[$N+1])
7669 {
7670 $MContent=~s/typedef\s+enum\s+\Q$S\E\s+\Q$S\E;//g;
Andrey Ponomarenko07aea072012-11-12 16:15:07 +04007671 $CppMode{$Version}=1;
Andrey Ponomarenko9927e332012-10-19 10:50:48 +04007672 }
7673 $N+=2;
7674 }
7675
Andrey Ponomarenko07aea072012-11-12 16:15:07 +04007676 if($CppMode{$Version}==1)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007677 { # try to change C++ "keyword" to "c99_keyword"
Andrey Ponomarenko07aea072012-11-12 16:15:07 +04007678 printMsg("INFO", "Using C++ compatibility mode");
Andrey Ponomarenkob8d203d2012-05-25 18:11:07 +04007679 $MHeaderPath = $TMP_DIR."/dump$Version.i";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007680 }
7681 }
Andrey Ponomarenko07aea072012-11-12 16:15:07 +04007682 if($CppMode{$Version}==1
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007683 or $MinGWMode{$Version}==1)
7684 { # compile the corrected preprocessor output
7685 writeFile($MHeaderPath, $MContent);
7686 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +04007687
7688 # clean memory
7689 undef $MContent;
7690
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007691 if($COMMON_LANGUAGE{$Version} eq "C++")
7692 { # add classes and namespaces to the dump
7693 my $CHdump = "-fdump-class-hierarchy -c";
Andrey Ponomarenko07aea072012-11-12 16:15:07 +04007694 if($CppMode{$Version}==1
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007695 or $MinGWMode{$Version}==1) {
7696 $CHdump .= " -fpreprocessed";
7697 }
7698 my $ClassHierarchyCmd = getCompileCmd($MHeaderPath, $CHdump, $IncludeString);
7699 chdir($TMP_DIR);
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04007700 system($ClassHierarchyCmd." >null 2>&1");
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007701 chdir($ORIG_DIR);
7702 if(my $ClassDump = (cmd_find($TMP_DIR,"f","*.class",1))[0])
7703 {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007704 my $Content = readFile($ClassDump);
7705 foreach my $ClassInfo (split(/\n\n/, $Content))
7706 {
7707 if($ClassInfo=~/\AClass\s+(.+)\s*/i)
7708 {
7709 my $CName = $1;
7710 next if($CName=~/\A(__|_objc_|_opaque_)/);
7711 $TUnit_NameSpaces{$Version}{$CName} = -1;
7712 if($CName=~/\A[\w:]+\Z/)
7713 { # classes
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +04007714 $TUnit_Classes{$Version}{$CName} = 1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007715 }
7716 if($CName=~/(\w[\w:]*)::/)
7717 { # namespaces
7718 my $NS = $1;
7719 if(not defined $TUnit_NameSpaces{$Version}{$NS}) {
7720 $TUnit_NameSpaces{$Version}{$NS} = 1;
7721 }
7722 }
7723 }
7724 elsif($ClassInfo=~/\AVtable\s+for\s+(.+)\n((.|\n)+)\Z/i)
7725 { # read v-tables (advanced approach)
7726 my ($CName, $VTable) = ($1, $2);
7727 $ClassVTable_Content{$Version}{$CName} = $VTable;
7728 }
7729 }
Andrey Ponomarenkoa01311b2012-06-08 17:20:02 +04007730 foreach my $NS (keys(%{$AddNameSpaces{$Version}}))
7731 { # add user-defined namespaces
7732 $TUnit_NameSpaces{$Version}{$NS} = 1;
7733 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007734 if($Debug)
7735 { # debug mode
7736 mkpath($DEBUG_PATH{$Version});
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04007737 copy($ClassDump, $DEBUG_PATH{$Version}."/class-hierarchy-dump.txt");
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007738 }
7739 unlink($ClassDump);
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +04007740 }
7741
7742 # add namespaces and classes
7743 if(my $NS_Add = get_namespace_additions($TUnit_NameSpaces{$Version}))
7744 { # GCC on all supported platforms does not include namespaces to the dump by default
7745 appendFile($MHeaderPath, "\n // add namespaces\n".$NS_Add);
7746 }
7747 # some GCC versions don't include class methods to the TU dump by default
7748 my ($AddClass, $ClassNum) = ("", 0);
7749 foreach my $CName (sort keys(%{$TUnit_Classes{$Version}}))
7750 {
7751 next if($C_Structure{$CName});
7752 next if(not $STDCXX_TESTING and $CName=~/\Astd::/);
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +04007753 next if($SkipTypes{$Version}{$CName});
Andrey Ponomarenko82b005f2012-11-12 17:58:14 +04007754 if($OSgroup eq "linux")
7755 {
7756 next if(($CName=~tr![:]!!)>2);
7757 if($CName=~/\A(.+)::[^:]+\Z/)
7758 { # will be added by name space
7759 next;
7760 }
7761 }
7762 else
7763 {
7764 if($CName=~/\A(.+)::[^:]+\Z/
7765 and $TUnit_Classes{$Version}{$1})
7766 { # classes inside other classes
7767 next;
7768 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007769 }
Andrey Ponomarenko9927e332012-10-19 10:50:48 +04007770 if(defined $TUnit_Funcs{$Version}{$CName})
7771 { # the same name for a function and type
7772 next;
7773 }
7774 if(defined $TUnit_Vars{$Version}{$CName})
7775 { # the same name for a variable and type
7776 next;
7777 }
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +04007778 $AddClass .= " $CName* tmp_add_class_".($ClassNum++).";\n";
7779 }
7780 if($AddClass) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007781 appendFile($MHeaderPath, "\n // add classes\n".$AddClass);
7782 }
7783 }
7784 writeLog($Version, "Temporary header file \'$TmpHeaderPath\' with the following content will be compiled to create GCC translation unit dump:\n".readFile($TmpHeaderPath)."\n");
7785 # create TU dump
7786 my $TUdump = "-fdump-translation-unit -fkeep-inline-functions -c";
Andrey Ponomarenko07aea072012-11-12 16:15:07 +04007787 if($CppMode{$Version}==1
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007788 or $MinGWMode{$Version}==1) {
7789 $TUdump .= " -fpreprocessed";
7790 }
7791 my $SyntaxTreeCmd = getCompileCmd($MHeaderPath, $TUdump, $IncludeString);
7792 writeLog($Version, "The GCC parameters:\n $SyntaxTreeCmd\n\n");
7793 chdir($TMP_DIR);
Andrey Ponomarenkoa01311b2012-06-08 17:20:02 +04007794 system($SyntaxTreeCmd." >\"$TMP_DIR/tu_errors\" 2>&1");
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007795 if($?)
7796 { # failed to compile, but the TU dump still can be created
Andrey Ponomarenko01117f12012-06-26 12:23:02 +04007797 if(my $Errors = readFile($TMP_DIR."/tu_errors"))
7798 { # try to recompile
7799 # FIXME: handle other errors and try to recompile
Andrey Ponomarenko07aea072012-11-12 16:15:07 +04007800 if($CppMode{$Version}==1
Andrey Ponomarenko01117f12012-06-26 12:23:02 +04007801 and $Errors=~/c99_/)
7802 { # disable c99 mode and try again
Andrey Ponomarenko07aea072012-11-12 16:15:07 +04007803 $CppMode{$Version}=-1;
7804 printMsg("INFO", "Disabling C++ compatibility mode");
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007805 resetLogging($Version);
7806 $TMP_DIR = tempdir(CLEANUP=>1);
7807 return getDump();
7808 }
Andrey Ponomarenko01117f12012-06-26 12:23:02 +04007809 elsif($AutoPreambleMode{$Version}!=-1
Andrey Ponomarenko9927e332012-10-19 10:50:48 +04007810 and my $AddHeaders = detectPreamble($Errors, $Version))
Andrey Ponomarenko01117f12012-06-26 12:23:02 +04007811 { # add auto preamble headers and try again
7812 $AutoPreambleMode{$Version}=-1;
Andrey Ponomarenko9927e332012-10-19 10:50:48 +04007813 my @Headers = sort {$b cmp $a} keys(%{$AddHeaders}); # sys/types.h should be the first
Andrey Ponomarenko01117f12012-06-26 12:23:02 +04007814 foreach my $Num (0 .. $#Headers)
7815 {
7816 my $Path = $Headers[$Num];
7817 if(defined $Include_Preamble{$Version}{$Path})
7818 { # already added
7819 next;
7820 }
7821 $Include_Preamble{$Version}{$Path}{"Position"} = keys(%{$Include_Preamble{$Version}});
Andrey Ponomarenko9927e332012-10-19 10:50:48 +04007822 printMsg("INFO", "Add \'".$AddHeaders->{$Path}{"Header"}."\' preamble header for \'".$AddHeaders->{$Path}{"Type"}."\'");
Andrey Ponomarenko01117f12012-06-26 12:23:02 +04007823 }
7824 resetLogging($Version);
7825 $TMP_DIR = tempdir(CLEANUP=>1);
7826 return getDump();
7827 }
7828 elsif($Cpp0xMode{$Version}!=-1
7829 and ($Errors=~/\Q-std=c++0x\E/
7830 or $Errors=~/is not a class or namespace/))
7831 { # c++0x: enum class
7832 $Cpp0xMode{$Version}=-1;
7833 printMsg("INFO", "Enabling c++0x mode");
7834 resetLogging($Version);
7835 $TMP_DIR = tempdir(CLEANUP=>1);
7836 $CompilerOptions{$Version} .= " -std=c++0x";
7837 return getDump();
7838 }
7839 elsif($MinGWMode{$Version}==1)
7840 { # disable MinGW mode and try again
7841 $MinGWMode{$Version}=-1;
7842 resetLogging($Version);
7843 $TMP_DIR = tempdir(CLEANUP=>1);
7844 return getDump();
7845 }
7846 writeLog($Version, $Errors);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007847 }
Andrey Ponomarenko01117f12012-06-26 12:23:02 +04007848 else {
7849 writeLog($Version, "$!: $?\n");
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007850 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007851 printMsg("ERROR", "some errors occurred when compiling headers");
7852 printErrorLog($Version);
7853 $COMPILE_ERRORS = $ERROR_CODE{"Compile_Error"};
7854 writeLog($Version, "\n");# new line
7855 }
7856 chdir($ORIG_DIR);
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +04007857 unlink($TmpHeaderPath);
7858 unlink($MHeaderPath);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007859 return (cmd_find($TMP_DIR,"f","*.tu",1))[0];
7860}
7861
7862sub cmd_file($)
7863{
7864 my $Path = $_[0];
7865 return "" if(not $Path or not -e $Path);
7866 if(my $CmdPath = get_CmdPath("file")) {
7867 return `$CmdPath -b \"$Path\"`;
7868 }
7869 return "";
7870}
7871
7872sub getIncString($$)
7873{
7874 my ($ArrRef, $Style) = @_;
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04007875 return "" if(not $ArrRef or $#{$ArrRef}<0);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007876 my $String = "";
7877 foreach (@{$ArrRef}) {
7878 $String .= " ".inc_opt($_, $Style);
7879 }
7880 return $String;
7881}
7882
7883sub getIncPaths(@)
7884{
7885 my @HeaderPaths = @_;
7886 my @IncPaths = ();
7887 if($INC_PATH_AUTODETECT{$Version})
7888 { # auto-detecting dependencies
7889 my %Includes = ();
7890 foreach my $HPath (@HeaderPaths)
7891 {
7892 foreach my $Dir (get_HeaderDeps($HPath, $Version))
7893 {
7894 if($Skip_Include_Paths{$Version}{$Dir}) {
7895 next;
7896 }
Andrey Ponomarenkoa01311b2012-06-08 17:20:02 +04007897 if($SystemRoot)
7898 {
7899 if($Skip_Include_Paths{$Version}{$SystemRoot.$Dir}) {
7900 next;
7901 }
7902 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007903 $Includes{$Dir}=1;
7904 }
7905 }
7906 foreach my $Dir (keys(%{$Add_Include_Paths{$Version}}))
7907 { # added by user
7908 next if($Includes{$Dir});
7909 push(@IncPaths, $Dir);
7910 }
7911 foreach my $Dir (@{sortIncPaths([keys(%Includes)], $Version)}) {
7912 push(@IncPaths, $Dir);
7913 }
7914 }
7915 else
7916 { # user-defined paths
7917 foreach my $Dir (sort {get_depth($a)<=>get_depth($b)}
7918 sort {$b cmp $a} keys(%{$Include_Paths{$Version}})) {
7919 push(@IncPaths, $Dir);
7920 }
7921 }
7922 return \@IncPaths;
7923}
7924
7925sub callPreprocessor($$$)
7926{
7927 my ($Path, $Inc, $LibVersion) = @_;
7928 return "" if(not $Path or not -f $Path);
7929 my $IncludeString=$Inc;
7930 if(not $Inc) {
7931 $IncludeString = getIncString(getIncPaths($Path), "GCC");
7932 }
7933 my $Cmd = getCompileCmd($Path, "-dD -E", $IncludeString);
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +04007934 my $Out = $TMP_DIR."/preprocessed.h";
Andrey Ponomarenkoa01311b2012-06-08 17:20:02 +04007935 system($Cmd." >\"$Out\" 2>\"$TMP_DIR/null\"");
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04007936 return $Out;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007937}
7938
7939sub cmd_find($$$$)
7940{ # native "find" is much faster than File::Find (~6x)
7941 # also the File::Find doesn't support --maxdepth N option
7942 # so using the cross-platform wrapper for the native one
7943 my ($Path, $Type, $Name, $MaxDepth) = @_;
7944 return () if(not $Path or not -e $Path);
7945 if($OSgroup eq "windows")
7946 {
7947 my $DirCmd = get_CmdPath("dir");
7948 if(not $DirCmd) {
7949 exitStatus("Not_Found", "can't find \"dir\" command");
7950 }
7951 $Path=~s/[\\]+\Z//;
7952 $Path = get_abs_path($Path);
7953 $Path = path_format($Path, $OSgroup);
7954 my $Cmd = $DirCmd." \"$Path\" /B /O";
7955 if($MaxDepth!=1) {
7956 $Cmd .= " /S";
7957 }
7958 if($Type eq "d") {
7959 $Cmd .= " /AD";
7960 }
7961 my @Files = ();
7962 if($Name)
7963 { # FIXME: how to search file names in MS shell?
7964 $Name=~s/\*/.*/g if($Name!~/\]/);
7965 foreach my $File (split(/\n/, `$Cmd`))
7966 {
7967 if($File=~/$Name\Z/i) {
7968 push(@Files, $File);
7969 }
7970 }
7971 }
7972 else {
Andrey Ponomarenkoa01311b2012-06-08 17:20:02 +04007973 @Files = split(/\n/, `$Cmd 2>\"$TMP_DIR/null\"`);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007974 }
7975 my @AbsPaths = ();
7976 foreach my $File (@Files)
7977 {
7978 if(not is_abs($File)) {
7979 $File = joinPath($Path, $File);
7980 }
7981 if($Type eq "f" and not -f $File)
7982 { # skip dirs
7983 next;
7984 }
7985 push(@AbsPaths, path_format($File, $OSgroup));
7986 }
7987 if($Type eq "d") {
7988 push(@AbsPaths, $Path);
7989 }
7990 return @AbsPaths;
7991 }
7992 else
7993 {
7994 my $FindCmd = get_CmdPath("find");
7995 if(not $FindCmd) {
7996 exitStatus("Not_Found", "can't find a \"find\" command");
7997 }
7998 $Path = get_abs_path($Path);
7999 if(-d $Path and -l $Path
8000 and $Path!~/\/\Z/)
8001 { # for directories that are symlinks
8002 $Path.="/";
8003 }
8004 my $Cmd = $FindCmd." \"$Path\"";
8005 if($MaxDepth) {
8006 $Cmd .= " -maxdepth $MaxDepth";
8007 }
8008 if($Type) {
8009 $Cmd .= " -type $Type";
8010 }
8011 if($Name)
8012 { # file name
8013 if($Name=~/\]/) {
8014 $Cmd .= " -regex \"$Name\"";
8015 }
8016 else {
8017 $Cmd .= " -name \"$Name\"";
8018 }
8019 }
Andrey Ponomarenko9927e332012-10-19 10:50:48 +04008020 my $Res = `$Cmd 2>\"$TMP_DIR/null\"`;
8021 if($?) {
8022 printMsg("ERROR", "problem with \'find\' utility ($?): $!");
8023 }
8024 return split(/\n/, $Res);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008025 }
8026}
8027
8028sub unpackDump($)
8029{
8030 my $Path = $_[0];
8031 return "" if(not $Path or not -e $Path);
8032 $Path = get_abs_path($Path);
8033 $Path = path_format($Path, $OSgroup);
8034 my ($Dir, $FileName) = separate_path($Path);
8035 my $UnpackDir = $TMP_DIR."/unpack";
8036 rmtree($UnpackDir);
8037 mkpath($UnpackDir);
8038 if($FileName=~s/\Q.zip\E\Z//g)
8039 { # *.zip
8040 my $UnzipCmd = get_CmdPath("unzip");
8041 if(not $UnzipCmd) {
8042 exitStatus("Not_Found", "can't find \"unzip\" command");
8043 }
8044 chdir($UnpackDir);
Andrey Ponomarenkoa01311b2012-06-08 17:20:02 +04008045 system("$UnzipCmd \"$Path\" >contents.txt");
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008046 if($?) {
8047 exitStatus("Error", "can't extract \'$Path\'");
8048 }
8049 chdir($ORIG_DIR);
8050 my @Contents = ();
8051 foreach (split("\n", readFile("$UnpackDir/contents.txt")))
8052 {
8053 if(/inflating:\s*([^\s]+)/) {
8054 push(@Contents, $1);
8055 }
8056 }
8057 if(not @Contents) {
8058 exitStatus("Error", "can't extract \'$Path\'");
8059 }
8060 return joinPath($UnpackDir, $Contents[0]);
8061 }
8062 elsif($FileName=~s/\Q.tar.gz\E\Z//g)
8063 { # *.tar.gz
8064 if($OSgroup eq "windows")
8065 { # -xvzf option is not implemented in tar.exe (2003)
8066 # use "gzip.exe -k -d -f" + "tar.exe -xvf" instead
8067 my $TarCmd = get_CmdPath("tar");
8068 if(not $TarCmd) {
8069 exitStatus("Not_Found", "can't find \"tar\" command");
8070 }
8071 my $GzipCmd = get_CmdPath("gzip");
8072 if(not $GzipCmd) {
8073 exitStatus("Not_Found", "can't find \"gzip\" command");
8074 }
8075 chdir($UnpackDir);
Andrey Ponomarenkoa01311b2012-06-08 17:20:02 +04008076 system("$GzipCmd -k -d -f \"$Path\""); # keep input files (-k)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008077 if($?) {
8078 exitStatus("Error", "can't extract \'$Path\'");
8079 }
Andrey Ponomarenkoa01311b2012-06-08 17:20:02 +04008080 system("$TarCmd -xvf \"$Dir\\$FileName.tar\" >contents.txt");
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008081 if($?) {
8082 exitStatus("Error", "can't extract \'$Path\'");
8083 }
8084 chdir($ORIG_DIR);
8085 unlink($Dir."/".$FileName.".tar");
8086 my @Contents = split("\n", readFile("$UnpackDir/contents.txt"));
8087 if(not @Contents) {
8088 exitStatus("Error", "can't extract \'$Path\'");
8089 }
8090 return joinPath($UnpackDir, $Contents[0]);
8091 }
8092 else
8093 { # Unix
8094 my $TarCmd = get_CmdPath("tar");
8095 if(not $TarCmd) {
8096 exitStatus("Not_Found", "can't find \"tar\" command");
8097 }
8098 chdir($UnpackDir);
Andrey Ponomarenkoa01311b2012-06-08 17:20:02 +04008099 system("$TarCmd -xvzf \"$Path\" >contents.txt");
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008100 if($?) {
8101 exitStatus("Error", "can't extract \'$Path\'");
8102 }
8103 chdir($ORIG_DIR);
8104 # The content file name may be different
8105 # from the package file name
8106 my @Contents = split("\n", readFile("$UnpackDir/contents.txt"));
8107 if(not @Contents) {
8108 exitStatus("Error", "can't extract \'$Path\'");
8109 }
8110 return joinPath($UnpackDir, $Contents[0]);
8111 }
8112 }
8113}
8114
8115sub createArchive($$)
8116{
8117 my ($Path, $To) = @_;
Andrey Ponomarenko5c09ef32012-06-14 18:17:33 +04008118 if(not $To) {
8119 $To = ".";
8120 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008121 if(not $Path or not -e $Path
8122 or not -d $To) {
8123 return "";
8124 }
8125 my ($From, $Name) = separate_path($Path);
8126 if($OSgroup eq "windows")
8127 { # *.zip
8128 my $ZipCmd = get_CmdPath("zip");
8129 if(not $ZipCmd) {
8130 exitStatus("Not_Found", "can't find \"zip\"");
8131 }
8132 my $Pkg = $To."/".$Name.".zip";
8133 unlink($Pkg);
8134 chdir($To);
Andrey Ponomarenkoa01311b2012-06-08 17:20:02 +04008135 system("$ZipCmd -j \"$Name.zip\" \"$Path\" >\"$TMP_DIR/null\"");
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008136 if($?)
8137 { # cannot allocate memory (or other problems with "zip")
8138 unlink($Path);
8139 exitStatus("Error", "can't pack the ABI dump: ".$!);
8140 }
8141 chdir($ORIG_DIR);
8142 unlink($Path);
8143 return $Pkg;
8144 }
8145 else
8146 { # *.tar.gz
8147 my $TarCmd = get_CmdPath("tar");
8148 if(not $TarCmd) {
8149 exitStatus("Not_Found", "can't find \"tar\"");
8150 }
8151 my $GzipCmd = get_CmdPath("gzip");
8152 if(not $GzipCmd) {
8153 exitStatus("Not_Found", "can't find \"gzip\"");
8154 }
8155 my $Pkg = abs_path($To)."/".$Name.".tar.gz";
8156 unlink($Pkg);
8157 chdir($From);
8158 system($TarCmd, "-czf", $Pkg, $Name);
8159 if($?)
8160 { # cannot allocate memory (or other problems with "tar")
8161 unlink($Path);
8162 exitStatus("Error", "can't pack the ABI dump: ".$!);
8163 }
8164 chdir($ORIG_DIR);
8165 unlink($Path);
8166 return $To."/".$Name.".tar.gz";
8167 }
8168}
8169
Andrey Ponomarenko9927e332012-10-19 10:50:48 +04008170sub readBytes($)
8171{
8172 sysopen(FILE, $_[0], O_RDONLY);
8173 sysread(FILE, my $Header, 4);
8174 close(FILE);
8175 my @Bytes = map { sprintf('%02x', ord($_)) } split (//, $Header);
8176 return join("", @Bytes);
8177}
8178
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008179sub is_header_file($)
8180{
8181 if($_[0]=~/\.($HEADER_EXT)\Z/i) {
8182 return $_[0];
8183 }
8184 return 0;
8185}
8186
8187sub is_not_header($)
8188{
8189 if($_[0]=~/\.\w+\Z/
8190 and $_[0]!~/\.($HEADER_EXT)\Z/i) {
8191 return 1;
8192 }
8193 return 0;
8194}
8195
8196sub is_header($$$)
8197{
8198 my ($Header, $UserDefined, $LibVersion) = @_;
8199 return 0 if(-d $Header);
8200 if(-f $Header) {
8201 $Header = get_abs_path($Header);
8202 }
8203 else
8204 {
8205 if(is_abs($Header))
8206 { # incorrect absolute path
8207 return 0;
8208 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04008209 if(my $HPath = identifyHeader($Header, $LibVersion)) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008210 $Header = $HPath;
8211 }
8212 else
8213 { # can't find header
8214 return 0;
8215 }
8216 }
8217 if($Header=~/\.\w+\Z/)
8218 { # have an extension
8219 return is_header_file($Header);
8220 }
8221 else
8222 {
8223 if($UserDefined==2)
8224 { # specified on the command line
8225 if(cmd_file($Header)!~/HTML|XML/i) {
8226 return $Header;
8227 }
8228 }
8229 elsif($UserDefined)
8230 { # specified in the XML-descriptor
8231 # header file without an extension
8232 return $Header;
8233 }
8234 else
8235 {
Andrey Ponomarenko85043792012-05-14 16:48:07 +04008236 if($Header=~/\/include\//
8237 or cmd_file($Header)=~/C[\+]*\s+program/i)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008238 { # !~/HTML|XML|shared|dynamic/i
8239 return $Header;
8240 }
8241 }
8242 }
8243 return 0;
8244}
8245
Andrey Ponomarenko16934472012-03-29 15:37:04 +04008246sub addTargetHeaders($)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008247{
8248 my $LibVersion = $_[0];
8249 foreach my $RegHeader (keys(%{$Registered_Headers{$LibVersion}}))
8250 {
8251 my $RegDir = get_dirname($RegHeader);
8252 $TargetHeaders{$LibVersion}{get_filename($RegHeader)}=1;
Andrey Ponomarenko9927e332012-10-19 10:50:48 +04008253
8254 if(not $INC_PATH_AUTODETECT{$LibVersion}) {
8255 detect_recursive_includes($RegHeader, $LibVersion);
8256 }
8257
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008258 foreach my $RecInc (keys(%{$RecursiveIncludes{$LibVersion}{$RegHeader}}))
8259 {
8260 my $Dir = get_dirname($RecInc);
Andrey Ponomarenko85043792012-05-14 16:48:07 +04008261 if($Dir=~/\A\Q$RegDir\E([\/\\]|\Z)/
8262 or $RecursiveIncludes{$LibVersion}{$RegHeader}{$RecInc}!=1)
8263 { # in the same directory or included by #include "..."
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008264 $TargetHeaders{$LibVersion}{get_filename($RecInc)}=1;
8265 }
8266 }
8267 }
8268}
8269
8270sub readHeaders($)
8271{
8272 $Version = $_[0];
8273 printMsg("INFO", "checking header(s) ".$Descriptor{$Version}{"Version"}." ...");
8274 my $DumpPath = getDump();
8275 if(not $DumpPath) {
8276 exitStatus("Cannot_Compile", "can't compile header(s)");
8277 }
8278 if($Debug)
8279 { # debug mode
8280 mkpath($DEBUG_PATH{$Version});
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04008281 copy($DumpPath, $DEBUG_PATH{$Version}."/translation-unit-dump.txt");
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008282 }
8283 getInfo($DumpPath);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008284}
8285
8286sub prepareTypes($)
8287{
8288 my $LibVersion = $_[0];
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04008289 if(not checkDump($LibVersion, "2.0"))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008290 { # support for old ABI dumps
8291 # type names have been corrected in ACC 1.22 (dump 2.0 format)
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04008292 foreach my $TypeId (keys(%{$TypeInfo{$LibVersion}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008293 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04008294 my $TName = $TypeInfo{$LibVersion}{$TypeId}{"Name"};
8295 if($TName=~/\A(\w+)::(\w+)/) {
8296 my ($P1, $P2) = ($1, $2);
8297 if($P1 eq $P2) {
8298 $TName=~s/\A$P1:\:$P1(\W)/$P1$1/;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008299 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04008300 else {
8301 $TName=~s/\A(\w+:\:)$P2:\:$P2(\W)/$1$P2$2/;
8302 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008303 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04008304 $TypeInfo{$LibVersion}{$TypeId}{"Name"} = $TName;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008305 }
8306 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04008307 if(not checkDump($LibVersion, "2.5"))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008308 { # support for old ABI dumps
8309 # V < 2.5: array size == "number of elements"
8310 # V >= 2.5: array size in bytes
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04008311 foreach my $TypeId (sort {int($a)<=>int($b)} keys(%{$TypeInfo{$LibVersion}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008312 {
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +04008313 my %Type = get_PureType($TypeId, $TypeInfo{$LibVersion});
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04008314 if($Type{"Type"} eq "Array")
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008315 {
Andrey Ponomarenko01117f12012-06-26 12:23:02 +04008316 if(my $Size = $Type{"Size"})
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04008317 { # array[N]
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +04008318 my %Base = get_OneStep_BaseType($Type{"Tid"}, $TypeInfo{$LibVersion});
Andrey Ponomarenko01117f12012-06-26 12:23:02 +04008319 $Size *= $Base{"Size"};
8320 $TypeInfo{$LibVersion}{$TypeId}{"Size"} = "$Size";
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04008321 }
8322 else
8323 { # array[] is a pointer
8324 $TypeInfo{$LibVersion}{$TypeId}{"Size"} = $WORD_SIZE{$LibVersion};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008325 }
8326 }
8327 }
8328 }
8329 my $V2 = ($LibVersion==1)?2:1;
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04008330 if(not checkDump($LibVersion, "2.7"))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008331 { # support for old ABI dumps
8332 # size of "method ptr" corrected in 2.7
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04008333 foreach my $TypeId (sort {int($a)<=>int($b)} keys(%{$TypeInfo{$LibVersion}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008334 {
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +04008335 my %PureType = get_PureType($TypeId, $TypeInfo{$LibVersion});
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04008336 if($PureType{"Type"} eq "MethodPtr")
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008337 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04008338 my %Type = get_Type($TypeId, $LibVersion);
8339 my $TypeId_2 = getTypeIdByName($PureType{"Name"}, $V2);
8340 my %Type2 = get_Type($TypeId_2, $V2);
8341 if($Type{"Size"} ne $Type2{"Size"}) {
8342 $TypeInfo{$LibVersion}{$TypeId}{"Size"} = $Type2{"Size"};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008343 }
8344 }
8345 }
8346 }
8347}
8348
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04008349sub prepareSymbols($)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008350{
8351 my $LibVersion = $_[0];
Andrey Ponomarenko16934472012-03-29 15:37:04 +04008352
8353 if(not keys(%{$SymbolInfo{$LibVersion}}))
8354 { # check if input is valid
8355 if(not $ExtendedCheck and not $CheckObjectsOnly)
8356 {
8357 if($CheckHeadersOnly) {
8358 exitStatus("Empty_Set", "the set of public symbols is empty (".$Descriptor{$LibVersion}{"Version"}.")");
8359 }
8360 else {
8361 exitStatus("Empty_Intersection", "the sets of public symbols in headers and libraries have empty intersection (".$Descriptor{$LibVersion}{"Version"}.")");
8362 }
8363 }
8364 }
8365
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008366 my $Remangle = 0;
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04008367 if(not checkDump(1, "2.10")
8368 or not checkDump(2, "2.10"))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008369 { # different formats
8370 $Remangle = 1;
8371 }
8372 if($CheckHeadersOnly)
8373 { # different languages
8374 if($UserLang)
8375 { # --lang=LANG for both versions
8376 if(($UsedDump{1}{"V"} and $UserLang ne $UsedDump{1}{"L"})
8377 or ($UsedDump{2}{"V"} and $UserLang ne $UsedDump{2}{"L"}))
8378 {
8379 if($UserLang eq "C++")
8380 { # remangle symbols
8381 $Remangle = 1;
8382 }
8383 elsif($UserLang eq "C")
8384 { # remove mangling
8385 $Remangle = -1;
8386 }
8387 }
8388 }
8389 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04008390
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04008391 foreach my $InfoId (sort {int($b)<=>int($a)} keys(%{$SymbolInfo{$LibVersion}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008392 { # reverse order: D0, D1, D2, D0 (artificial, GCC < 4.5), C1, C2
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04008393 if(not checkDump($LibVersion, "2.13"))
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04008394 { # support for old ABI dumps
8395 if(defined $SymbolInfo{$LibVersion}{$InfoId}{"Param"})
8396 {
8397 foreach my $P (keys(%{$SymbolInfo{$LibVersion}{$InfoId}{"Param"}}))
8398 {
8399 my $TypeId = $SymbolInfo{$LibVersion}{$InfoId}{"Param"}{$P}{"type"};
8400 my $DVal = $SymbolInfo{$LibVersion}{$InfoId}{"Param"}{$P}{"default"};
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04008401 my $TName = $TypeInfo{$LibVersion}{$TypeId}{"Name"};
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04008402 if(defined $DVal and $DVal ne "")
8403 {
8404 if($TName eq "char") {
8405 $SymbolInfo{$LibVersion}{$InfoId}{"Param"}{$P}{"default"} = chr($DVal);
8406 }
8407 elsif($TName eq "bool") {
8408 $SymbolInfo{$LibVersion}{$InfoId}{"Param"}{$P}{"default"} = $DVal?"true":"false";
8409 }
8410 }
8411 }
8412 }
8413 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04008414 if($SymbolInfo{$LibVersion}{$InfoId}{"Destructor"})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008415 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04008416 if(defined $SymbolInfo{$LibVersion}{$InfoId}{"Param"}
8417 and keys(%{$SymbolInfo{$LibVersion}{$InfoId}{"Param"}})
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04008418 and $SymbolInfo{$LibVersion}{$InfoId}{"Param"}{0}{"name"})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008419 { # support for old GCC < 4.5: skip artificial ~dtor(int __in_chrg)
8420 # + support for old ABI dumps
8421 next;
8422 }
8423 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04008424 my $MnglName = $SymbolInfo{$LibVersion}{$InfoId}{"MnglName"};
Andrey Ponomarenko85043792012-05-14 16:48:07 +04008425 my $ShortName = $SymbolInfo{$LibVersion}{$InfoId}{"ShortName"};
Andrey Ponomarenko16934472012-03-29 15:37:04 +04008426 my $ClassID = $SymbolInfo{$LibVersion}{$InfoId}{"Class"};
Andrey Ponomarenko85043792012-05-14 16:48:07 +04008427 my $Return = $SymbolInfo{$LibVersion}{$InfoId}{"Return"};
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04008428
Andrey Ponomarenko16934472012-03-29 15:37:04 +04008429 my $SRemangle = 0;
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04008430 if(not checkDump(1, "2.12")
8431 or not checkDump(2, "2.12"))
Andrey Ponomarenko16934472012-03-29 15:37:04 +04008432 { # support for old ABI dumps
Andrey Ponomarenko85043792012-05-14 16:48:07 +04008433 if($ShortName eq "operator>>")
8434 {
8435 if(not $SymbolInfo{$LibVersion}{$InfoId}{"Class"})
8436 { # corrected mangling of operator>>
8437 $SRemangle = 1;
8438 }
Andrey Ponomarenko16934472012-03-29 15:37:04 +04008439 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +04008440 if($SymbolInfo{$LibVersion}{$InfoId}{"Data"})
8441 {
8442 if(not $SymbolInfo{$LibVersion}{$InfoId}{"Class"}
8443 and isConstType($Return, $LibVersion) and $MnglName!~/L\d+$ShortName/)
8444 { # corrected mangling of const global data
8445 # some global data is not mangled in the TU dump: qt_sine_table (Qt 4.8)
8446 # and incorrectly mangled by old ACC versions
8447 $SRemangle = 1;
8448 }
Andrey Ponomarenko16934472012-03-29 15:37:04 +04008449 }
8450 }
Andrey Ponomarenko5c09ef32012-06-14 18:17:33 +04008451 if(not $CheckHeadersOnly)
8452 { # support for old ABI dumps
8453 if(not checkDump(1, "2.17")
8454 or not checkDump(2, "2.17"))
8455 {
8456 if($SymbolInfo{$LibVersion}{$InfoId}{"Data"})
8457 {
8458 if(not $SymbolInfo{$LibVersion}{$InfoId}{"Class"})
8459 {
8460 if(link_symbol($ShortName, $LibVersion, "-Deps"))
8461 {
8462 $MnglName = $ShortName;
8463 $SymbolInfo{$LibVersion}{$InfoId}{"MnglName"} = $MnglName;
8464 }
8465 }
8466 }
8467 }
8468 }
Andrey Ponomarenko16934472012-03-29 15:37:04 +04008469 if($Remangle==1 or $SRemangle==1)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008470 { # support for old ABI dumps: some symbols are not mangled in old dumps
8471 # mangle both sets of symbols (old and new)
8472 # NOTE: remangling all symbols by the same mangler
8473 if($MnglName=~/\A_ZN(V|)K/)
8474 { # mangling may be incorrect on old ABI dumps
8475 # because of absent "Const" attribute
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04008476 $SymbolInfo{$LibVersion}{$InfoId}{"Const"} = 1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008477 }
8478 if($MnglName=~/\A_ZN(K|)V/)
8479 { # mangling may be incorrect on old ABI dumps
8480 # because of absent "Volatile" attribute
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04008481 $SymbolInfo{$LibVersion}{$InfoId}{"Volatile"} = 1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008482 }
Andrey Ponomarenko16934472012-03-29 15:37:04 +04008483 if(($ClassID and $MnglName!~/\A(_Z|\?)/)
8484 or (not $ClassID and $CheckHeadersOnly)
8485 or (not $ClassID and not link_symbol($MnglName, $LibVersion, "-Deps")))
8486 { # support for old ABI dumps, GCC >= 4.0
8487 # remangling all manually mangled symbols
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04008488 if($MnglName = mangle_symbol($InfoId, $LibVersion, "GCC"))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008489 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04008490 $SymbolInfo{$LibVersion}{$InfoId}{"MnglName"} = $MnglName;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008491 $MangledNames{$LibVersion}{$MnglName} = 1;
8492 }
8493 }
8494 }
8495 elsif($Remangle==-1)
8496 { # remove mangling
8497 $MnglName = "";
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04008498 $SymbolInfo{$LibVersion}{$InfoId}{"MnglName"} = "";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008499 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008500 if(not $MnglName) {
8501 next;
8502 }
8503 if(not $CompleteSignature{$LibVersion}{$MnglName}{"MnglName"})
8504 { # NOTE: global data may enter here twice
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04008505 %{$CompleteSignature{$LibVersion}{$MnglName}} = %{$SymbolInfo{$LibVersion}{$InfoId}};
8506
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008507 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04008508 if(not checkDump($LibVersion, "2.6"))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008509 { # support for old dumps
8510 # add "Volatile" attribute
8511 if($MnglName=~/_Z(K|)V/) {
8512 $CompleteSignature{$LibVersion}{$MnglName}{"Volatile"}=1;
8513 }
8514 }
8515 # symbol and its symlink have same signatures
8516 if($SymVer{$LibVersion}{$MnglName}) {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04008517 %{$CompleteSignature{$LibVersion}{$SymVer{$LibVersion}{$MnglName}}} = %{$SymbolInfo{$LibVersion}{$InfoId}};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008518 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +04008519
8520 # clean memory
Andrey Ponomarenko16934472012-03-29 15:37:04 +04008521 delete($SymbolInfo{$LibVersion}{$InfoId});
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008522 }
8523 if($COMMON_LANGUAGE{$LibVersion} eq "C++" or $OSgroup eq "windows") {
8524 translateSymbols(keys(%{$CompleteSignature{$LibVersion}}), $LibVersion);
8525 }
8526 if($ExtendedCheck)
8527 { # --ext option
8528 addExtension($LibVersion);
8529 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +04008530
8531 # clean memory
8532 delete($SymbolInfo{$LibVersion});
8533
8534 foreach my $Symbol (keys(%{$CompleteSignature{$LibVersion}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008535 { # detect allocable classes with public exported constructors
8536 # or classes with auto-generated or inline-only constructors
Andrey Ponomarenko9927e332012-10-19 10:50:48 +04008537 # and other temp info
Andrey Ponomarenko85043792012-05-14 16:48:07 +04008538 if(my $ClassId = $CompleteSignature{$LibVersion}{$Symbol}{"Class"})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008539 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04008540 my $ClassName = $TypeInfo{$LibVersion}{$ClassId}{"Name"};
Andrey Ponomarenko85043792012-05-14 16:48:07 +04008541 if($CompleteSignature{$LibVersion}{$Symbol}{"Constructor"}
8542 and not $CompleteSignature{$LibVersion}{$Symbol}{"InLine"})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008543 { # Class() { ... } will not be exported
Andrey Ponomarenko85043792012-05-14 16:48:07 +04008544 if(not $CompleteSignature{$LibVersion}{$Symbol}{"Private"})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008545 {
Andrey Ponomarenko85043792012-05-14 16:48:07 +04008546 if($CheckHeadersOnly or link_symbol($Symbol, $LibVersion, "-Deps")) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008547 $AllocableClass{$LibVersion}{$ClassName} = 1;
8548 }
8549 }
8550 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +04008551 if(not $CompleteSignature{$LibVersion}{$Symbol}{"Private"})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008552 { # all imported class methods
Andrey Ponomarenko85043792012-05-14 16:48:07 +04008553 if(symbolFilter($Symbol, $LibVersion, "Affected", "Binary"))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008554 {
Andrey Ponomarenko85043792012-05-14 16:48:07 +04008555 if($CheckHeadersOnly)
8556 {
8557 if(not $CompleteSignature{$LibVersion}{$Symbol}{"InLine"}
8558 or $CompleteSignature{$LibVersion}{$Symbol}{"Virt"})
8559 { # all symbols except non-virtual inline
8560 $ClassMethods{"Binary"}{$LibVersion}{$ClassName}{$Symbol} = 1;
8561 }
8562 }
8563 else {
8564 $ClassMethods{"Binary"}{$LibVersion}{$ClassName}{$Symbol} = 1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008565 }
8566 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04008567 if(symbolFilter($Symbol, $LibVersion, "Affected", "Source")) {
Andrey Ponomarenko85043792012-05-14 16:48:07 +04008568 $ClassMethods{"Source"}{$LibVersion}{$ClassName}{$Symbol} = 1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008569 }
8570 }
Andrey Ponomarenko16934472012-03-29 15:37:04 +04008571 $ClassNames{$LibVersion}{$ClassName} = 1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008572 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +04008573 if(my $RetId = $CompleteSignature{$LibVersion}{$Symbol}{"Return"})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008574 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04008575 my %Base = get_BaseType($RetId, $LibVersion);
Andrey Ponomarenko85043792012-05-14 16:48:07 +04008576 if(defined $Base{"Type"}
8577 and $Base{"Type"}=~/Struct|Class/)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008578 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04008579 my $Name = $TypeInfo{$LibVersion}{$Base{"Tid"}}{"Name"};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008580 if($Name=~/<([^<>\s]+)>/)
8581 {
8582 if(my $Tid = getTypeIdByName($1, $LibVersion)) {
8583 $ReturnedClass{$LibVersion}{$Tid} = 1;
8584 }
8585 }
8586 else {
8587 $ReturnedClass{$LibVersion}{$Base{"Tid"}} = 1;
8588 }
8589 }
8590 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +04008591 foreach my $Num (keys(%{$CompleteSignature{$LibVersion}{$Symbol}{"Param"}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008592 {
Andrey Ponomarenko85043792012-05-14 16:48:07 +04008593 my $PId = $CompleteSignature{$LibVersion}{$Symbol}{"Param"}{$Num}{"type"};
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04008594 if(get_PLevel($PId, $LibVersion)>=1)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008595 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04008596 if(my %Base = get_BaseType($PId, $LibVersion))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008597 {
Andrey Ponomarenko16934472012-03-29 15:37:04 +04008598 if($Base{"Type"}=~/Struct|Class/)
8599 {
Andrey Ponomarenko85043792012-05-14 16:48:07 +04008600 $ParamClass{$LibVersion}{$Base{"Tid"}}{$Symbol} = 1;
Andrey Ponomarenko16934472012-03-29 15:37:04 +04008601 foreach my $SubId (get_sub_classes($Base{"Tid"}, $LibVersion, 1))
8602 { # mark all derived classes
Andrey Ponomarenko85043792012-05-14 16:48:07 +04008603 $ParamClass{$LibVersion}{$SubId}{$Symbol} = 1;
Andrey Ponomarenko16934472012-03-29 15:37:04 +04008604 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008605 }
8606 }
8607 }
8608 }
Andrey Ponomarenko9927e332012-10-19 10:50:48 +04008609
8610 # mapping {short name => symbols}
8611 $Func_ShortName{$LibVersion}{$CompleteSignature{$LibVersion}{$Symbol}{"ShortName"}}{$Symbol} = 1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008612 }
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04008613 foreach my $MnglName (keys(%VTableClass))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008614 { # reconstruct header name for v-tables
Andrey Ponomarenko9927e332012-10-19 10:50:48 +04008615 if(index($MnglName, "_ZTV")==0)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008616 {
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04008617 if(my $ClassName = $VTableClass{$MnglName})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008618 {
8619 if(my $ClassId = $TName_Tid{$LibVersion}{$ClassName}) {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04008620 $CompleteSignature{$LibVersion}{$MnglName}{"Header"} = $TypeInfo{$LibVersion}{$ClassId}{"Header"};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008621 }
8622 }
8623 }
8624 }
Andrey Ponomarenko16934472012-03-29 15:37:04 +04008625
8626 # types
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04008627 foreach my $TypeId (keys(%{$TypeInfo{$LibVersion}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008628 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04008629 if(my $TName = $TypeInfo{$LibVersion}{$TypeId}{"Name"})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008630 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04008631 if(defined $TypeInfo{$LibVersion}{$TypeId}{"VTable"}) {
8632 $ClassNames{$LibVersion}{$TName} = 1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008633 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04008634 if(defined $TypeInfo{$LibVersion}{$TypeId}{"Base"})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008635 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04008636 $ClassNames{$LibVersion}{$TName} = 1;
8637 foreach my $Bid (keys(%{$TypeInfo{$LibVersion}{$TypeId}{"Base"}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008638 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04008639 if(my $BName = $TypeInfo{$LibVersion}{$Bid}{"Name"}) {
8640 $ClassNames{$LibVersion}{$BName} = 1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008641 }
8642 }
8643 }
8644 }
8645 }
8646}
8647
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04008648sub register_TypeUsage($$)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008649{
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04008650 my ($TypeId, $LibVersion) = @_;
8651 if(not $TypeId) {
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04008652 return 0;
8653 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04008654 if($UsedType{$LibVersion}{$TypeId})
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04008655 { # already registered
8656 return 1;
8657 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04008658 my %TInfo = get_Type($TypeId, $LibVersion);
Andrey Ponomarenko85043792012-05-14 16:48:07 +04008659 if($TInfo{"Type"})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008660 {
Andrey Ponomarenko85043792012-05-14 16:48:07 +04008661 if($TInfo{"Type"}=~/\A(Struct|Union|Class|FuncPtr|MethodPtr|FieldPtr|Enum)\Z/)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008662 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04008663 $UsedType{$LibVersion}{$TypeId} = 1;
Andrey Ponomarenko85043792012-05-14 16:48:07 +04008664 if($TInfo{"Type"}=~/\A(Struct|Class)\Z/)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008665 {
Andrey Ponomarenko85043792012-05-14 16:48:07 +04008666 foreach my $BaseId (keys(%{$TInfo{"Base"}}))
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04008667 { # register base classes
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04008668 register_TypeUsage($BaseId, $LibVersion);
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04008669 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +04008670 foreach my $TPos (keys(%{$TInfo{"TParam"}}))
8671 {
8672 my $TPName = $TInfo{"TParam"}{$TPos}{"name"};
8673 if(my $TTid = $TName_Tid{$LibVersion}{$TPName}) {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04008674 register_TypeUsage($TTid, $LibVersion);
Andrey Ponomarenko85043792012-05-14 16:48:07 +04008675 }
8676 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008677 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +04008678 foreach my $Memb_Pos (keys(%{$TInfo{"Memb"}}))
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04008679 {
Andrey Ponomarenko85043792012-05-14 16:48:07 +04008680 if(my $MTid = $TInfo{"Memb"}{$Memb_Pos}{"type"}) {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04008681 register_TypeUsage($MTid, $LibVersion);
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04008682 }
8683 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +04008684 if($TInfo{"Type"} eq "FuncPtr"
8685 or $TInfo{"Type"} eq "MethodPtr")
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04008686 {
Andrey Ponomarenko85043792012-05-14 16:48:07 +04008687 if(my $RTid = $TInfo{"Return"}) {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04008688 register_TypeUsage($RTid, $LibVersion);
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04008689 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +04008690 foreach my $Memb_Pos (keys(%{$TInfo{"Param"}}))
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04008691 {
Andrey Ponomarenko85043792012-05-14 16:48:07 +04008692 if(my $MTid = $TInfo{"Param"}{$Memb_Pos}{"type"}) {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04008693 register_TypeUsage($MTid, $LibVersion);
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04008694 }
8695 }
8696 }
8697 return 1;
8698 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +04008699 elsif($TInfo{"Type"}=~/\A(Const|ConstVolatile|Volatile|Pointer|Ref|Restrict|Array|Typedef)\Z/)
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04008700 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04008701 $UsedType{$LibVersion}{$TypeId} = 1;
8702 register_TypeUsage($TInfo{"BaseType"}{"Tid"}, $LibVersion);
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04008703 return 1;
8704 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04008705 elsif($TInfo{"Type"} eq "Intrinsic")
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04008706 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04008707 $UsedType{$LibVersion}{$TypeId} = 1;
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04008708 return 1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008709 }
8710 }
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04008711 return 0;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008712}
8713
Andrey Ponomarenko85043792012-05-14 16:48:07 +04008714sub selectSymbol($$$$)
Andrey Ponomarenko35c44fd2012-06-18 17:50:25 +04008715{ # select symbol to check or to dump
Andrey Ponomarenko85043792012-05-14 16:48:07 +04008716 my ($Symbol, $SInfo, $Level, $LibVersion) = @_;
8717
Andrey Ponomarenko35c44fd2012-06-18 17:50:25 +04008718 if($Level eq "Dump")
8719 {
8720 if($SInfo->{"Virt"} or $SInfo->{"PureVirt"})
8721 { # TODO: check if this symbol is from
8722 # base classes of other target symbols
8723 return 1;
8724 }
8725 }
8726
Andrey Ponomarenko85043792012-05-14 16:48:07 +04008727 if(not $STDCXX_TESTING and $Symbol=~/\A(_ZS|_ZNS|_ZNKS)/)
8728 { # stdc++ interfaces
8729 return 0;
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04008730 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +04008731
8732 my $Target = 0;
8733 if(my $Header = $SInfo->{"Header"}) {
8734 $Target = (is_target_header($Header, 1) or is_target_header($Header, 2));
8735 }
8736 if($CheckHeadersOnly)
8737 {
8738 if($Target)
8739 {
8740 if($Level eq "Dump")
8741 { # dumped
8742 if($BinaryOnly)
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04008743 {
Andrey Ponomarenko85043792012-05-14 16:48:07 +04008744 if(not $SInfo->{"InLine"} or $SInfo->{"Data"}) {
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04008745 return 1;
8746 }
8747 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +04008748 else {
8749 return 1;
8750 }
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04008751 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +04008752 elsif($Level eq "Source")
8753 { # checked
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04008754 return 1;
8755 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +04008756 elsif($Level eq "Binary")
8757 { # checked
8758 if(not $SInfo->{"InLine"} or $SInfo->{"Data"}
8759 or $SInfo->{"Virt"} or $SInfo->{"PureVirt"}) {
8760 return 1;
8761 }
8762 }
8763 }
8764 }
8765 else
8766 { # library is available
8767 if(link_symbol($Symbol, $LibVersion, "-Deps"))
8768 { # exported symbols
8769 return 1;
8770 }
8771 if($Level eq "Dump")
8772 { # dumped
Andrey Ponomarenko35c44fd2012-06-18 17:50:25 +04008773 if($BinaryOnly)
8774 {
8775 if($SInfo->{"Data"})
8776 {
8777 if($Target) {
8778 return 1;
8779 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +04008780 }
8781 }
Andrey Ponomarenko35c44fd2012-06-18 17:50:25 +04008782 else
8783 { # SrcBin
Andrey Ponomarenko85043792012-05-14 16:48:07 +04008784 if($Target) {
8785 return 1;
8786 }
8787 }
8788 }
8789 elsif($Level eq "Source")
8790 { # checked
Andrey Ponomarenko01117f12012-06-26 12:23:02 +04008791 if($SInfo->{"PureVirt"} or $SInfo->{"Data"} or $SInfo->{"InLine"}
8792 or isInLineInst($Symbol, $SInfo, $LibVersion))
Andrey Ponomarenko35c44fd2012-06-18 17:50:25 +04008793 { # skip LOCAL symbols
8794 if($Target) {
8795 return 1;
8796 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +04008797 }
8798 }
8799 elsif($Level eq "Binary")
8800 { # checked
8801 if($SInfo->{"PureVirt"} or $SInfo->{"Data"})
8802 {
8803 if($Target) {
8804 return 1;
8805 }
8806 }
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04008807 }
8808 }
8809 return 0;
8810}
8811
Andrey Ponomarenko85043792012-05-14 16:48:07 +04008812sub cleanDump($)
8813{ # clean data
Andrey Ponomarenko16934472012-03-29 15:37:04 +04008814 my $LibVersion = $_[0];
8815 foreach my $InfoId (keys(%{$SymbolInfo{$LibVersion}}))
8816 {
8817 my $MnglName = $SymbolInfo{$LibVersion}{$InfoId}{"MnglName"};
8818 if(not $MnglName) {
8819 delete($SymbolInfo{$LibVersion}{$InfoId});
8820 next;
8821 }
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04008822 my $ShortName = $SymbolInfo{$LibVersion}{$InfoId}{"ShortName"};
Andrey Ponomarenko85043792012-05-14 16:48:07 +04008823 if(not $ShortName) {
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04008824 delete($SymbolInfo{$LibVersion}{$InfoId});
8825 next;
Andrey Ponomarenko16934472012-03-29 15:37:04 +04008826 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +04008827 if($MnglName eq $ShortName)
8828 { # remove duplicate data
8829 delete($SymbolInfo{$LibVersion}{$InfoId}{"MnglName"});
Andrey Ponomarenko16934472012-03-29 15:37:04 +04008830 }
8831 if(not keys(%{$SymbolInfo{$LibVersion}{$InfoId}{"Param"}})) {
8832 delete($SymbolInfo{$LibVersion}{$InfoId}{"Param"});
8833 }
Andrey Ponomarenko01117f12012-06-26 12:23:02 +04008834 if(not keys(%{$SymbolInfo{$LibVersion}{$InfoId}{"TParam"}})) {
8835 delete($SymbolInfo{$LibVersion}{$InfoId}{"TParam"});
8836 }
Andrey Ponomarenko16934472012-03-29 15:37:04 +04008837 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04008838 foreach my $Tid (keys(%{$TypeInfo{$LibVersion}}))
Andrey Ponomarenko85043792012-05-14 16:48:07 +04008839 {
Andrey Ponomarenko01117f12012-06-26 12:23:02 +04008840 delete($TypeInfo{$LibVersion}{$Tid}{"Tid"});
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04008841 foreach my $Attr ("Header", "Line", "Size", "NameSpace")
Andrey Ponomarenko16934472012-03-29 15:37:04 +04008842 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04008843 if(not $TypeInfo{$LibVersion}{$Tid}{$Attr}) {
8844 delete($TypeInfo{$LibVersion}{$Tid}{$Attr});
8845 }
8846 }
Andrey Ponomarenko01117f12012-06-26 12:23:02 +04008847 if(not keys(%{$TypeInfo{$LibVersion}{$Tid}{"TParam"}})) {
8848 delete($TypeInfo{$LibVersion}{$Tid}{"TParam"});
8849 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04008850 }
8851}
8852
8853sub selectType($$)
8854{
8855 my ($Tid, $LibVersion) = @_;
Andrey Ponomarenko9927e332012-10-19 10:50:48 +04008856
8857 if(my $Dupl = $TypeTypedef{$LibVersion}{$Tid})
8858 {
8859 if(defined $TypeInfo{$LibVersion}{$Dupl})
8860 {
8861 if($TypeInfo{$LibVersion}{$Dupl}{"Name"} eq $TypeInfo{$LibVersion}{$Tid}{"Name"})
8862 { # duplicate
8863 return 0;
8864 }
8865 }
8866 }
8867
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04008868 if(my $THeader = $TypeInfo{$LibVersion}{$Tid}{"Header"})
8869 {
8870 if(not isBuiltIn($THeader))
8871 {
8872 if($TypeInfo{$LibVersion}{$Tid}{"Type"}=~/Class|Struct|Union|Enum|Typedef/)
Andrey Ponomarenko16934472012-03-29 15:37:04 +04008873 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04008874 if(not isAnon($TypeInfo{$LibVersion}{$Tid}{"Name"}))
8875 {
8876 if(is_target_header($THeader, $LibVersion))
8877 { # from target headers
8878 if(not selfTypedef($Tid, $LibVersion)) {
8879 return 1;
8880 }
8881 }
Andrey Ponomarenko16934472012-03-29 15:37:04 +04008882 }
8883 }
8884 }
8885 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04008886 return 0;
Andrey Ponomarenko16934472012-03-29 15:37:04 +04008887}
8888
Andrey Ponomarenko85043792012-05-14 16:48:07 +04008889sub removeUnused($$)
8890{ # remove unused data types from the ABI dump
8891 my ($LibVersion, $Kind) = @_;
8892 foreach my $InfoId (keys(%{$SymbolInfo{$LibVersion}}))
8893 {
8894 my %FuncInfo = %{$SymbolInfo{$LibVersion}{$InfoId}};
8895 if(my $RTid = $FuncInfo{"Return"}) {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04008896 register_TypeUsage($RTid, $LibVersion);
Andrey Ponomarenko85043792012-05-14 16:48:07 +04008897 }
8898 if(my $FCid = $FuncInfo{"Class"})
8899 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04008900 register_TypeUsage($FCid, $LibVersion);
8901 if(my $ThisId = getTypeIdByName($TypeInfo{$LibVersion}{$FCid}{"Name"}."*const", $LibVersion))
Andrey Ponomarenko85043792012-05-14 16:48:07 +04008902 { # register "this" pointer
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04008903 $UsedType{$LibVersion}{$ThisId} = 1;
8904 if(my %ThisType = get_Type($ThisId, $LibVersion)) {
8905 register_TypeUsage($ThisType{"BaseType"}{"Tid"}, $LibVersion);
Andrey Ponomarenko85043792012-05-14 16:48:07 +04008906 }
8907 }
8908 }
8909 foreach my $PPos (keys(%{$FuncInfo{"Param"}}))
8910 {
8911 if(my $PTid = $FuncInfo{"Param"}{$PPos}{"type"}) {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04008912 register_TypeUsage($PTid, $LibVersion);
Andrey Ponomarenko85043792012-05-14 16:48:07 +04008913 }
8914 }
8915 foreach my $TPos (keys(%{$FuncInfo{"TParam"}}))
8916 {
8917 my $TPName = $FuncInfo{"TParam"}{$TPos}{"name"};
8918 if(my $TTid = $TName_Tid{$LibVersion}{$TPName}) {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04008919 register_TypeUsage($TTid, $LibVersion);
Andrey Ponomarenko85043792012-05-14 16:48:07 +04008920 }
8921 }
8922 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04008923 foreach my $Tid (keys(%{$TypeInfo{$LibVersion}}))
8924 {
8925 if($UsedType{$LibVersion}{$Tid})
8926 { # All & Derived
8927 next;
8928 }
8929
8930 if($Kind eq "Derived")
Andrey Ponomarenko85043792012-05-14 16:48:07 +04008931 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04008932 if(selectType($Tid, $LibVersion)) {
8933 register_TypeUsage($Tid, $LibVersion);
Andrey Ponomarenko85043792012-05-14 16:48:07 +04008934 }
8935 }
8936 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04008937 foreach my $Tid (keys(%{$TypeInfo{$LibVersion}}))
8938 { # remove unused types
8939 if($UsedType{$LibVersion}{$Tid})
8940 { # All & Derived
8941 next;
8942 }
8943 # remove type
8944 delete($TypeInfo{$LibVersion}{$Tid});
8945 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +04008946
8947 # clean memory
8948 %UsedType = ();
8949}
8950
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04008951sub selfTypedef($$)
Andrey Ponomarenko85043792012-05-14 16:48:07 +04008952{
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04008953 my ($TypeId, $LibVersion) = @_;
8954 my %Type = get_Type($TypeId, $LibVersion);
Andrey Ponomarenko85043792012-05-14 16:48:07 +04008955 if($Type{"Type"} eq "Typedef")
8956 {
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +04008957 my %Base = get_OneStep_BaseType($TypeId, $TypeInfo{$LibVersion});
Andrey Ponomarenko85043792012-05-14 16:48:07 +04008958 if($Base{"Type"}=~/Class|Struct/)
8959 {
8960 if($Type{"Name"} eq $Base{"Name"}) {
8961 return 1;
8962 }
8963 elsif($Type{"Name"}=~/::(\w+)\Z/)
8964 {
8965 if($Type{"Name"} eq $Base{"Name"}."::".$1)
8966 { # QPointer<QWidget>::QPointer
8967 return 1;
8968 }
8969 }
8970 }
8971 }
8972 return 0;
8973}
8974
Andrey Ponomarenko16934472012-03-29 15:37:04 +04008975sub addExtension($)
8976{
8977 my $LibVersion = $_[0];
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04008978 foreach my $Tid (keys(%{$TypeInfo{$LibVersion}}))
Andrey Ponomarenko16934472012-03-29 15:37:04 +04008979 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04008980 if(selectType($Tid, $LibVersion))
Andrey Ponomarenko16934472012-03-29 15:37:04 +04008981 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04008982 my $Symbol = "external_func_".$TypeInfo{$LibVersion}{$Tid}{"Name"};
8983
8984 %{$CompleteSignature{$LibVersion}{$Symbol}} = (
8985 "Header" => "extended.h",
8986 "ShortName" => $Symbol,
8987 "MnglName" => $Symbol,
8988 "Param" => { 0 => { "type"=>$Tid, "name"=>"p1" } }
8989 );
8990
8991 $ExtendedSymbols{$Symbol}=1;
8992 $CheckedSymbols{"Binary"}{$Symbol}=1;
8993 $CheckedSymbols{"Source"}{$Symbol}=1;
Andrey Ponomarenko16934472012-03-29 15:37:04 +04008994 }
8995 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04008996 $ExtendedSymbols{"external_func_0"}=1;
8997 $CheckedSymbols{"Binary"}{"external_func_0"}=1;
8998 $CheckedSymbols{"Source"}{"external_func_0"}=1;
Andrey Ponomarenko16934472012-03-29 15:37:04 +04008999}
9000
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009001sub findMethod($$$)
9002{
9003 my ($VirtFunc, $ClassId, $LibVersion) = @_;
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04009004 foreach my $BaseClass_Id (keys(%{$TypeInfo{$LibVersion}{$ClassId}{"Base"}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009005 {
9006 if(my $VirtMethodInClass = findMethod_Class($VirtFunc, $BaseClass_Id, $LibVersion)) {
9007 return $VirtMethodInClass;
9008 }
9009 elsif(my $VirtMethodInBaseClasses = findMethod($VirtFunc, $BaseClass_Id, $LibVersion)) {
9010 return $VirtMethodInBaseClasses;
9011 }
9012 }
9013 return "";
9014}
9015
9016sub findMethod_Class($$$)
9017{
9018 my ($VirtFunc, $ClassId, $LibVersion) = @_;
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04009019 my $ClassName = $TypeInfo{$LibVersion}{$ClassId}{"Name"};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009020 return "" if(not defined $VirtualTable{$LibVersion}{$ClassName});
9021 my $TargetSuffix = get_symbol_suffix($VirtFunc, 1);
9022 my $TargetShortName = $CompleteSignature{$LibVersion}{$VirtFunc}{"ShortName"};
9023 foreach my $Candidate (keys(%{$VirtualTable{$LibVersion}{$ClassName}}))
9024 { # search for interface with the same parameters suffix (overridden)
9025 if($TargetSuffix eq get_symbol_suffix($Candidate, 1))
9026 {
9027 if($CompleteSignature{$LibVersion}{$VirtFunc}{"Destructor"}) {
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04009028 if($CompleteSignature{$LibVersion}{$Candidate}{"Destructor"})
9029 {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009030 if(($VirtFunc=~/D0E/ and $Candidate=~/D0E/)
9031 or ($VirtFunc=~/D1E/ and $Candidate=~/D1E/)
9032 or ($VirtFunc=~/D2E/ and $Candidate=~/D2E/)) {
9033 return $Candidate;
9034 }
9035 }
9036 }
9037 else {
9038 if($TargetShortName eq $CompleteSignature{$LibVersion}{$Candidate}{"ShortName"}) {
9039 return $Candidate;
9040 }
9041 }
9042 }
9043 }
9044 return "";
9045}
9046
Andrey Ponomarenko16934472012-03-29 15:37:04 +04009047sub registerVTable($)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009048{
Andrey Ponomarenko16934472012-03-29 15:37:04 +04009049 my $LibVersion = $_[0];
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04009050 foreach my $Symbol (keys(%{$CompleteSignature{$LibVersion}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009051 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04009052 if($CompleteSignature{$LibVersion}{$Symbol}{"Virt"}
9053 or $CompleteSignature{$LibVersion}{$Symbol}{"PureVirt"})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009054 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04009055 my $ClassName = $TypeInfo{$LibVersion}{$CompleteSignature{$LibVersion}{$Symbol}{"Class"}}{"Name"};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009056 next if(not $STDCXX_TESTING and $ClassName=~/\A(std::|__cxxabi)/);
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04009057 if($CompleteSignature{$LibVersion}{$Symbol}{"Destructor"}
9058 and $Symbol=~/D2E/)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009059 { # pure virtual D2-destructors are marked as "virt" in the dump
9060 # virtual D2-destructors are NOT marked as "virt" in the dump
9061 # both destructors are not presented in the v-table
9062 next;
9063 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04009064 my ($MnglName, $VersionSpec, $SymbolVersion) = separate_symbol($Symbol);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009065 $VirtualTable{$LibVersion}{$ClassName}{$MnglName} = 1;
9066 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009067 }
9068}
9069
9070sub registerOverriding($)
9071{
9072 my $LibVersion = $_[0];
9073 my @Classes = keys(%{$VirtualTable{$LibVersion}});
Andrey Ponomarenko85043792012-05-14 16:48:07 +04009074 @Classes = sort {int($TName_Tid{$LibVersion}{$a})<=>int($TName_Tid{$LibVersion}{$b})} @Classes;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009075 foreach my $ClassName (@Classes)
9076 {
9077 foreach my $VirtFunc (keys(%{$VirtualTable{$LibVersion}{$ClassName}}))
9078 {
Andrey Ponomarenko16934472012-03-29 15:37:04 +04009079 if($CompleteSignature{$LibVersion}{$VirtFunc}{"PureVirt"})
9080 { # pure virtuals
9081 next;
9082 }
9083 my $ClassId = $TName_Tid{$LibVersion}{$ClassName};
9084 if(my $Overridden = findMethod($VirtFunc, $ClassId, $LibVersion))
Andrey Ponomarenko85043792012-05-14 16:48:07 +04009085 {
9086 if($CompleteSignature{$LibVersion}{$Overridden}{"Virt"}
9087 or $CompleteSignature{$LibVersion}{$Overridden}{"PureVirt"})
9088 { # both overridden virtual methods
9089 # and implemented pure virtual methods
9090 $CompleteSignature{$LibVersion}{$VirtFunc}{"Override"} = $Overridden;
9091 $OverriddenMethods{$LibVersion}{$Overridden}{$VirtFunc} = 1;
9092 delete($VirtualTable{$LibVersion}{$ClassName}{$VirtFunc}); # remove from v-table model
9093 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009094 }
9095 }
9096 if(not keys(%{$VirtualTable{$LibVersion}{$ClassName}})) {
9097 delete($VirtualTable{$LibVersion}{$ClassName});
9098 }
9099 }
9100}
9101
9102sub setVirtFuncPositions($)
9103{
9104 my $LibVersion = $_[0];
9105 foreach my $ClassName (keys(%{$VirtualTable{$LibVersion}}))
9106 {
9107 my ($Num, $RelPos, $AbsNum) = (1, 0, 1);
9108 foreach my $VirtFunc (sort {int($CompleteSignature{$LibVersion}{$a}{"Line"}) <=> int($CompleteSignature{$LibVersion}{$b}{"Line"})}
9109 sort keys(%{$VirtualTable{$LibVersion}{$ClassName}}))
9110 {
Andrey Ponomarenko16934472012-03-29 15:37:04 +04009111 $VirtualTable{$LibVersion}{$ClassName}{$VirtFunc}=$Num++;
9112
9113 # set relative positions
9114 if(defined $VirtualTable{1}{$ClassName} and defined $VirtualTable{1}{$ClassName}{$VirtFunc}
9115 and defined $VirtualTable{2}{$ClassName} and defined $VirtualTable{2}{$ClassName}{$VirtFunc})
9116 { # relative position excluding added and removed virtual functions
9117 if(not $CompleteSignature{1}{$VirtFunc}{"Override"}
9118 and not $CompleteSignature{2}{$VirtFunc}{"Override"}) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009119 $CompleteSignature{$LibVersion}{$VirtFunc}{"RelPos"} = $RelPos++;
9120 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009121 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009122 }
9123 }
Andrey Ponomarenko16934472012-03-29 15:37:04 +04009124 foreach my $ClassName (keys(%{$ClassNames{$LibVersion}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009125 {
9126 my $AbsNum = 1;
Andrey Ponomarenko16934472012-03-29 15:37:04 +04009127 foreach my $VirtFunc (getVTable_Model($TName_Tid{$LibVersion}{$ClassName}, $LibVersion)) {
9128 $VirtualTable_Model{$LibVersion}{$ClassName}{$VirtFunc}=$AbsNum++;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009129 }
9130 }
9131}
9132
9133sub get_sub_classes($$$)
9134{
9135 my ($ClassId, $LibVersion, $Recursive) = @_;
9136 return () if(not defined $Class_SubClasses{$LibVersion}{$ClassId});
9137 my @Subs = ();
9138 foreach my $SubId (keys(%{$Class_SubClasses{$LibVersion}{$ClassId}}))
9139 {
Andrey Ponomarenko16934472012-03-29 15:37:04 +04009140 if($Recursive)
9141 {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009142 foreach my $SubSubId (get_sub_classes($SubId, $LibVersion, $Recursive)) {
9143 push(@Subs, $SubSubId);
9144 }
9145 }
9146 push(@Subs, $SubId);
9147 }
9148 return @Subs;
9149}
9150
9151sub get_base_classes($$$)
9152{
9153 my ($ClassId, $LibVersion, $Recursive) = @_;
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04009154 my %ClassType = get_Type($ClassId, $LibVersion);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009155 return () if(not defined $ClassType{"Base"});
9156 my @Bases = ();
9157 foreach my $BaseId (sort {int($ClassType{"Base"}{$a}{"pos"})<=>int($ClassType{"Base"}{$b}{"pos"})}
9158 keys(%{$ClassType{"Base"}}))
9159 {
Andrey Ponomarenko16934472012-03-29 15:37:04 +04009160 if($Recursive)
9161 {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009162 foreach my $SubBaseId (get_base_classes($BaseId, $LibVersion, $Recursive)) {
9163 push(@Bases, $SubBaseId);
9164 }
9165 }
9166 push(@Bases, $BaseId);
9167 }
9168 return @Bases;
9169}
9170
Andrey Ponomarenko16934472012-03-29 15:37:04 +04009171sub getVTable_Model($$)
9172{ # return an ordered list of v-table elements
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009173 my ($ClassId, $LibVersion) = @_;
9174 my @Bases = get_base_classes($ClassId, $LibVersion, 1);
9175 my @Elements = ();
9176 foreach my $BaseId (@Bases, $ClassId)
9177 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04009178 if(my $BName = $TypeInfo{$LibVersion}{$BaseId}{"Name"})
Andrey Ponomarenko85043792012-05-14 16:48:07 +04009179 {
9180 if(defined $VirtualTable{$LibVersion}{$BName})
9181 {
9182 my @VFunctions = keys(%{$VirtualTable{$LibVersion}{$BName}});
9183 @VFunctions = sort {int($CompleteSignature{$LibVersion}{$a}{"Line"}) <=> int($CompleteSignature{$LibVersion}{$b}{"Line"})} @VFunctions;
9184 foreach my $VFunc (@VFunctions) {
9185 push(@Elements, $VFunc);
9186 }
9187 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009188 }
9189 }
9190 return @Elements;
9191}
9192
9193sub getVShift($$)
9194{
9195 my ($ClassId, $LibVersion) = @_;
9196 my @Bases = get_base_classes($ClassId, $LibVersion, 1);
9197 my $VShift = 0;
9198 foreach my $BaseId (@Bases)
9199 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04009200 if(my $BName = $TypeInfo{$LibVersion}{$BaseId}{"Name"})
Andrey Ponomarenko85043792012-05-14 16:48:07 +04009201 {
9202 if(defined $VirtualTable{$LibVersion}{$BName}) {
9203 $VShift+=keys(%{$VirtualTable{$LibVersion}{$BName}});
9204 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009205 }
9206 }
9207 return $VShift;
9208}
9209
9210sub getShift($$)
9211{
9212 my ($ClassId, $LibVersion) = @_;
9213 my @Bases = get_base_classes($ClassId, $LibVersion, 0);
9214 my $Shift = 0;
9215 foreach my $BaseId (@Bases)
9216 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04009217 if(my $Size = $TypeInfo{$LibVersion}{$BaseId}{"Size"})
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04009218 {
9219 if($Size!=1)
9220 { # not empty base class
9221 $Shift+=$Size;
9222 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009223 }
9224 }
9225 return $Shift;
9226}
9227
Andrey Ponomarenko16934472012-03-29 15:37:04 +04009228sub getVTable_Size($$)
9229{ # number of v-table elements
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009230 my ($ClassName, $LibVersion) = @_;
Andrey Ponomarenko16934472012-03-29 15:37:04 +04009231 my $Size = 0;
9232 # three approaches
9233 if(not $Size)
9234 { # real size
9235 if(my %VTable = getVTable_Real($ClassName, $LibVersion)) {
9236 $Size = keys(%VTable);
9237 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009238 }
Andrey Ponomarenko16934472012-03-29 15:37:04 +04009239 if(not $Size)
9240 { # shared library symbol size
9241 if($Size = getSymbolSize($ClassVTable{$ClassName}, $LibVersion)) {
9242 $Size /= $WORD_SIZE{$LibVersion};
9243 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009244 }
Andrey Ponomarenko16934472012-03-29 15:37:04 +04009245 if(not $Size)
9246 { # model size
9247 if(defined $VirtualTable_Model{$LibVersion}{$ClassName}) {
9248 $Size = keys(%{$VirtualTable_Model{$LibVersion}{$ClassName}}) + 2;
9249 }
9250 }
9251 return $Size;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009252}
9253
9254sub isCopyingClass($$)
9255{
9256 my ($TypeId, $LibVersion) = @_;
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04009257 return $TypeInfo{$LibVersion}{$TypeId}{"Copied"};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009258}
9259
9260sub isLeafClass($$)
9261{
9262 my ($ClassId, $LibVersion) = @_;
9263 return (not keys(%{$Class_SubClasses{$LibVersion}{$ClassId}}));
9264}
9265
9266sub havePubFields($)
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04009267{ # check structured type for public fields
9268 return isAccessible($_[0], {}, 0, -1);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009269}
9270
9271sub isAccessible($$$$)
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04009272{ # check interval in structured type for public fields
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009273 my ($TypePtr, $Skip, $Start, $End) = @_;
9274 return 0 if(not $TypePtr);
9275 if($End==-1) {
9276 $End = keys(%{$TypePtr->{"Memb"}})-1;
9277 }
9278 foreach my $MemPos (keys(%{$TypePtr->{"Memb"}}))
9279 {
9280 if($Skip and $Skip->{$MemPos})
9281 { # skip removed/added fields
9282 next;
9283 }
9284 if(int($MemPos)>=$Start and int($MemPos)<=$End)
9285 {
9286 if(isPublic($TypePtr, $MemPos)) {
9287 return ($MemPos+1);
9288 }
9289 }
9290 }
9291 return 0;
9292}
9293
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009294sub isReserved($)
9295{ # reserved fields == private
9296 my $MName = $_[0];
9297 if($MName=~/reserved|padding|f_spare/i) {
9298 return 1;
9299 }
Andrey Ponomarenko9927e332012-10-19 10:50:48 +04009300 if($MName=~/\A[_]*(spare|pad|unused)[_\d]*\Z/i) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009301 return 1;
9302 }
9303 if($MName=~/(pad\d+)/i) {
9304 return 1;
9305 }
9306 return 0;
9307}
9308
9309sub isPublic($$)
9310{
9311 my ($TypePtr, $FieldPos) = @_;
9312 return 0 if(not $TypePtr);
9313 return 0 if(not defined $TypePtr->{"Memb"}{$FieldPos});
9314 return 0 if(not defined $TypePtr->{"Memb"}{$FieldPos}{"name"});
9315 if(not $TypePtr->{"Memb"}{$FieldPos}{"access"})
9316 { # by name in C language
9317 # FIXME: add other methods to detect private members
9318 my $MName = $TypePtr->{"Memb"}{$FieldPos}{"name"};
9319 if($MName=~/priv|abidata|parent_object/i)
9320 { # C-styled private data
9321 return 0;
9322 }
9323 if(lc($MName) eq "abi")
9324 { # ABI information/reserved field
9325 return 0;
9326 }
9327 if(isReserved($MName))
9328 { # reserved fields
9329 return 0;
9330 }
9331 return 1;
9332 }
9333 elsif($TypePtr->{"Memb"}{$FieldPos}{"access"} ne "private")
9334 { # by access in C++ language
9335 return 1;
9336 }
9337 return 0;
9338}
9339
Andrey Ponomarenko16934472012-03-29 15:37:04 +04009340sub getVTable_Real($$)
9341{
9342 my ($ClassName, $LibVersion) = @_;
9343 if(my $ClassId = $TName_Tid{$LibVersion}{$ClassName})
9344 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04009345 my %Type = get_Type($ClassId, $LibVersion);
Andrey Ponomarenko16934472012-03-29 15:37:04 +04009346 if(defined $Type{"VTable"}) {
9347 return %{$Type{"VTable"}};
9348 }
9349 }
9350 return ();
9351}
9352
9353sub cmpVTables($)
9354{
9355 my $ClassName = $_[0];
9356 my $Res = cmpVTables_Real($ClassName, 1);
9357 if($Res==-1) {
9358 $Res = cmpVTables_Model($ClassName);
9359 }
9360 return $Res;
9361}
9362
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009363sub cmpVTables_Model($)
9364{
9365 my $ClassName = $_[0];
Andrey Ponomarenko16934472012-03-29 15:37:04 +04009366 foreach my $Symbol (keys(%{$VirtualTable_Model{1}{$ClassName}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009367 {
Andrey Ponomarenko16934472012-03-29 15:37:04 +04009368 if(not defined $VirtualTable_Model{2}{$ClassName}{$Symbol}) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009369 return 1;
9370 }
9371 }
9372 return 0;
9373}
9374
Andrey Ponomarenko16934472012-03-29 15:37:04 +04009375sub cmpVTables_Real($$)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009376{
9377 my ($ClassName, $Strong) = @_;
Andrey Ponomarenko16934472012-03-29 15:37:04 +04009378 if(defined $Cache{"cmpVTables_Real"}{$Strong}{$ClassName}) {
9379 return $Cache{"cmpVTables_Real"}{$Strong}{$ClassName};
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04009380 }
Andrey Ponomarenko16934472012-03-29 15:37:04 +04009381 my %VTable_Old = getVTable_Real($ClassName, 1);
9382 my %VTable_New = getVTable_Real($ClassName, 2);
9383 if(not %VTable_Old or not %VTable_New)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009384 { # old ABI dumps
Andrey Ponomarenko16934472012-03-29 15:37:04 +04009385 return ($Cache{"cmpVTables_Real"}{$Strong}{$ClassName} = -1);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009386 }
Andrey Ponomarenko16934472012-03-29 15:37:04 +04009387 my %Indexes = map {$_=>1} (keys(%VTable_Old), keys(%VTable_New));
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009388 foreach my $Offset (sort {int($a)<=>int($b)} keys(%Indexes))
9389 {
Andrey Ponomarenko16934472012-03-29 15:37:04 +04009390 if(not defined $VTable_Old{$Offset})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009391 { # v-table v.1 < v-table v.2
Andrey Ponomarenko16934472012-03-29 15:37:04 +04009392 return ($Cache{"cmpVTables_Real"}{$Strong}{$ClassName} = $Strong);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009393 }
Andrey Ponomarenko16934472012-03-29 15:37:04 +04009394 my $Entry1 = $VTable_Old{$Offset};
9395 if(not defined $VTable_New{$Offset})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009396 { # v-table v.1 > v-table v.2
Andrey Ponomarenko16934472012-03-29 15:37:04 +04009397 return ($Cache{"cmpVTables_Real"}{$Strong}{$ClassName} = ($Strong or $Entry1!~/__cxa_pure_virtual/));
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009398 }
Andrey Ponomarenko16934472012-03-29 15:37:04 +04009399 my $Entry2 = $VTable_New{$Offset};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009400 $Entry1 = simpleVEntry($Entry1);
9401 $Entry2 = simpleVEntry($Entry2);
9402 if($Entry1 ne $Entry2)
9403 { # register as changed
9404 if($Entry1=~/::([^:]+)\Z/)
9405 {
9406 my $M1 = $1;
9407 if($Entry2=~/::([^:]+)\Z/)
9408 {
9409 my $M2 = $1;
9410 if($M1 eq $M2)
9411 { # overridden
9412 next;
9413 }
9414 }
9415 }
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04009416 if(differentDumps("G"))
9417 {
9418 if($Entry1=~/\A\-(0x|\d+)/ and $Entry2=~/\A\-(0x|\d+)/)
9419 {
9420 # GCC 4.6.1: -0x00000000000000010
9421 # GCC 4.7.0: -16
9422 next;
9423 }
9424 }
Andrey Ponomarenko16934472012-03-29 15:37:04 +04009425 return ($Cache{"cmpVTables_Real"}{$Strong}{$ClassName} = 1);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009426 }
9427 }
Andrey Ponomarenko16934472012-03-29 15:37:04 +04009428 return ($Cache{"cmpVTables_Real"}{$Strong}{$ClassName} = 0);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009429}
9430
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04009431sub mergeVTables($)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009432{ # merging v-tables without diagnostics
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04009433 my $Level = $_[0];
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009434 foreach my $ClassName (keys(%{$VirtualTable{1}}))
9435 {
Andrey Ponomarenko16934472012-03-29 15:37:04 +04009436 if($VTableChanged_M{$ClassName})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009437 { # already registered
9438 next;
9439 }
Andrey Ponomarenko16934472012-03-29 15:37:04 +04009440 if(cmpVTables_Real($ClassName, 0)==1)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009441 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04009442 my @Affected = (keys(%{$ClassMethods{$Level}{1}{$ClassName}}));
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009443 foreach my $Symbol (@Affected)
9444 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04009445 %{$CompatProblems{$Level}{$Symbol}{"Virtual_Table_Changed_Unknown"}{$ClassName}}=(
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009446 "Type_Name"=>$ClassName,
9447 "Type_Type"=>"Class",
9448 "Target"=>$ClassName);
9449 }
9450 }
9451 }
9452}
9453
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04009454sub mergeBases($)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009455{
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04009456 my $Level = $_[0];
Andrey Ponomarenko16934472012-03-29 15:37:04 +04009457 foreach my $ClassName (keys(%{$ClassNames{1}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009458 { # detect added and removed virtual functions
Andrey Ponomarenko16934472012-03-29 15:37:04 +04009459 my $ClassId = $TName_Tid{1}{$ClassName};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009460 next if(not $ClassId);
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04009461 if(defined $VirtualTable{2}{$ClassName})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009462 {
Andrey Ponomarenko16934472012-03-29 15:37:04 +04009463 foreach my $Symbol (keys(%{$VirtualTable{2}{$ClassName}}))
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04009464 {
Andrey Ponomarenko16934472012-03-29 15:37:04 +04009465 if($TName_Tid{1}{$ClassName}
9466 and not defined $VirtualTable{1}{$ClassName}{$Symbol})
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04009467 { # added to v-table
Andrey Ponomarenko16934472012-03-29 15:37:04 +04009468 if(defined $CompleteSignature{1}{$Symbol}
9469 and $CompleteSignature{1}{$Symbol}{"Virt"})
9470 { # override some method in v.1
9471 next;
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04009472 }
Andrey Ponomarenko16934472012-03-29 15:37:04 +04009473 $AddedInt_Virt{$Level}{$ClassName}{$Symbol} = 1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009474 }
9475 }
9476 }
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04009477 if(defined $VirtualTable{1}{$ClassName})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009478 {
Andrey Ponomarenko16934472012-03-29 15:37:04 +04009479 foreach my $Symbol (keys(%{$VirtualTable{1}{$ClassName}}))
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04009480 {
Andrey Ponomarenko16934472012-03-29 15:37:04 +04009481 if($TName_Tid{2}{$ClassName}
9482 and not defined $VirtualTable{2}{$ClassName}{$Symbol})
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04009483 { # removed from v-table
Andrey Ponomarenko16934472012-03-29 15:37:04 +04009484 if(defined $CompleteSignature{2}{$Symbol}
9485 and $CompleteSignature{2}{$Symbol}{"Virt"})
9486 { # override some method in v.2
9487 next;
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04009488 }
Andrey Ponomarenko16934472012-03-29 15:37:04 +04009489 $RemovedInt_Virt{$Level}{$ClassName}{$Symbol} = 1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009490 }
9491 }
9492 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04009493 if($Level eq "Binary")
9494 { # Binary-level
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04009495 my %Class_Type = get_Type($ClassId, 1);
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04009496 foreach my $AddedVFunc (keys(%{$AddedInt_Virt{$Level}{$ClassName}}))
9497 { # check replacements, including pure virtual methods
9498 my $AddedPos = $VirtualTable{2}{$ClassName}{$AddedVFunc};
9499 foreach my $RemovedVFunc (keys(%{$RemovedInt_Virt{$Level}{$ClassName}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009500 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04009501 my $RemovedPos = $VirtualTable{1}{$ClassName}{$RemovedVFunc};
9502 if($AddedPos==$RemovedPos)
9503 {
9504 $VirtualReplacement{$AddedVFunc} = $RemovedVFunc;
9505 $VirtualReplacement{$RemovedVFunc} = $AddedVFunc;
9506 last; # other methods will be reported as "added" or "removed"
9507 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009508 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04009509 if(my $RemovedVFunc = $VirtualReplacement{$AddedVFunc})
9510 {
9511 if(lc($AddedVFunc) eq lc($RemovedVFunc))
9512 { # skip: DomUi => DomUI parameter (Qt 4.2.3 to 4.3.0)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009513 next;
9514 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04009515 my $ProblemType = "Virtual_Replacement";
9516 my @Affected = ($RemovedVFunc);
9517 if($CompleteSignature{1}{$RemovedVFunc}{"PureVirt"})
9518 { # pure methods
9519 if(not isUsedClass($ClassId, 1, $Level))
9520 { # not a parameter of some exported method
9521 next;
9522 }
9523 $ProblemType = "Pure_Virtual_Replacement";
Andrey Ponomarenko9927e332012-10-19 10:50:48 +04009524
9525 # affected all methods (both virtual and non-virtual ones)
9526 @Affected = (keys(%{$ClassMethods{$Level}{1}{$ClassName}}));
9527 push(@Affected, keys(%{$OverriddenMethods{1}{$RemovedVFunc}}));
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009528 }
Andrey Ponomarenko9927e332012-10-19 10:50:48 +04009529 $VTableChanged_M{$ClassName}=1;
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04009530 foreach my $AffectedInt (@Affected)
9531 {
9532 if($CompleteSignature{1}{$AffectedInt}{"PureVirt"})
9533 { # affected exported methods only
9534 next;
9535 }
Andrey Ponomarenko9927e332012-10-19 10:50:48 +04009536 if(not symbolFilter($AffectedInt, 1, "Affected", $Level)) {
9537 next;
9538 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04009539 %{$CompatProblems{$Level}{$AffectedInt}{$ProblemType}{$tr_name{$AddedVFunc}}}=(
9540 "Type_Name"=>$Class_Type{"Name"},
9541 "Type_Type"=>"Class",
9542 "Target"=>get_Signature($AddedVFunc, 2),
9543 "Old_Value"=>get_Signature($RemovedVFunc, 1));
9544 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009545 }
9546 }
9547 }
9548 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04009549 if(not checkDump(1, "2.0")
9550 or not checkDump(2, "2.0"))
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04009551 { # support for old ABI dumps
Andrey Ponomarenko9927e332012-10-19 10:50:48 +04009552 # "Base" attribute introduced in ACC 1.22 (ABI dump 2.0 format)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009553 return;
9554 }
Andrey Ponomarenko16934472012-03-29 15:37:04 +04009555 foreach my $ClassName (sort keys(%{$ClassNames{1}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009556 {
Andrey Ponomarenko16934472012-03-29 15:37:04 +04009557 my $ClassId_Old = $TName_Tid{1}{$ClassName};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009558 next if(not $ClassId_Old);
9559 if(not isCreatable($ClassId_Old, 1))
9560 { # skip classes without public constructors (including auto-generated)
9561 # example: class has only a private exported or private inline constructor
9562 next;
9563 }
9564 if($ClassName=~/>/)
9565 { # skip affected template instances
9566 next;
9567 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04009568 my %Class_Old = get_Type($ClassId_Old, 1);
Andrey Ponomarenko16934472012-03-29 15:37:04 +04009569 my $ClassId_New = $TName_Tid{2}{$ClassName};
Andrey Ponomarenko85043792012-05-14 16:48:07 +04009570 if(not $ClassId_New) {
9571 next;
9572 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04009573 my %Class_New = get_Type($ClassId_New, 2);
Andrey Ponomarenko85043792012-05-14 16:48:07 +04009574 if($Class_New{"Type"}!~/Class|Struct/)
9575 { # became typedef
9576 if($Level eq "Binary") {
9577 next;
9578 }
9579 if($Level eq "Source")
9580 {
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +04009581 %Class_New = get_PureType($ClassId_New, $TypeInfo{2});
Andrey Ponomarenko85043792012-05-14 16:48:07 +04009582 if($Class_New{"Type"}!~/Class|Struct/) {
9583 next;
9584 }
9585 $ClassId_New = $Class_New{"Tid"};
9586 }
9587 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009588 my @Bases_Old = sort {$Class_Old{"Base"}{$a}{"pos"}<=>$Class_Old{"Base"}{$b}{"pos"}} keys(%{$Class_Old{"Base"}});
9589 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 +04009590
9591 my %Tr_Old = map {$TypeInfo{1}{$_}{"Name"} => uncover_typedefs($TypeInfo{1}{$_}{"Name"}, 1)} @Bases_Old;
9592 my %Tr_New = map {$TypeInfo{2}{$_}{"Name"} => uncover_typedefs($TypeInfo{2}{$_}{"Name"}, 2)} @Bases_New;
9593
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009594 my ($BNum1, $BNum2) = (1, 1);
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +04009595 my %BasePos_Old = map {$Tr_Old{$TypeInfo{1}{$_}{"Name"}} => $BNum1++} @Bases_Old;
9596 my %BasePos_New = map {$Tr_New{$TypeInfo{2}{$_}{"Name"}} => $BNum2++} @Bases_New;
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04009597 my %ShortBase_Old = map {get_ShortType($_, 1) => 1} @Bases_Old;
9598 my %ShortBase_New = map {get_ShortType($_, 2) => 1} @Bases_New;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009599 my $Shift_Old = getShift($ClassId_Old, 1);
9600 my $Shift_New = getShift($ClassId_New, 2);
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +04009601 my %BaseId_New = map {$Tr_New{$TypeInfo{2}{$_}{"Name"}} => $_} @Bases_New;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009602 my ($Added, $Removed) = (0, 0);
9603 my @StableBases_Old = ();
9604 foreach my $BaseId (@Bases_Old)
9605 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04009606 my $BaseName = $TypeInfo{1}{$BaseId}{"Name"};
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +04009607 if($BasePos_New{$Tr_Old{$BaseName}}) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009608 push(@StableBases_Old, $BaseId);
9609 }
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +04009610 elsif(not $ShortBase_New{$Tr_Old{$BaseName}}
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04009611 and not $ShortBase_New{get_ShortType($BaseId, 1)})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009612 { # removed base
9613 # excluding namespace::SomeClass to SomeClass renaming
9614 my $ProblemKind = "Removed_Base_Class";
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04009615 if($Level eq "Binary")
9616 { # Binary-level
9617 if($Shift_Old ne $Shift_New)
9618 { # affected fields
9619 if(havePubFields(\%Class_Old)) {
9620 $ProblemKind .= "_And_Shift";
9621 }
9622 elsif($Class_Old{"Size"} ne $Class_New{"Size"}) {
9623 $ProblemKind .= "_And_Size";
9624 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009625 }
Andrey Ponomarenko16934472012-03-29 15:37:04 +04009626 if(keys(%{$VirtualTable_Model{1}{$BaseName}})
9627 and cmpVTables($ClassName)==1)
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04009628 { # affected v-table
9629 $ProblemKind .= "_And_VTable";
Andrey Ponomarenko16934472012-03-29 15:37:04 +04009630 $VTableChanged_M{$ClassName}=1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009631 }
9632 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04009633 my @Affected = keys(%{$ClassMethods{$Level}{1}{$ClassName}});
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009634 foreach my $SubId (get_sub_classes($ClassId_Old, 1, 1))
9635 {
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +04009636 if(my $SubName = $TypeInfo{1}{$SubId}{"Name"})
9637 {
9638 push(@Affected, keys(%{$ClassMethods{$Level}{1}{$SubName}}));
9639 if($ProblemKind=~/VTable/) {
9640 $VTableChanged_M{$SubName}=1;
9641 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009642 }
9643 }
9644 foreach my $Interface (@Affected)
9645 {
Andrey Ponomarenko9927e332012-10-19 10:50:48 +04009646 if(not symbolFilter($Interface, 1, "Affected", $Level)) {
9647 next;
9648 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04009649 %{$CompatProblems{$Level}{$Interface}{$ProblemKind}{"this"}}=(
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009650 "Type_Name"=>$ClassName,
9651 "Type_Type"=>"Class",
9652 "Target"=>$BaseName,
9653 "Old_Size"=>$Class_Old{"Size"}*$BYTE_SIZE,
9654 "New_Size"=>$Class_New{"Size"}*$BYTE_SIZE,
9655 "Shift"=>abs($Shift_New-$Shift_Old) );
9656 }
9657 $Removed+=1;
9658 }
9659 }
9660 my @StableBases_New = ();
9661 foreach my $BaseId (@Bases_New)
9662 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04009663 my $BaseName = $TypeInfo{2}{$BaseId}{"Name"};
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +04009664 if($BasePos_Old{$Tr_New{$BaseName}}) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009665 push(@StableBases_New, $BaseId);
9666 }
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +04009667 elsif(not $ShortBase_Old{$Tr_New{$BaseName}}
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04009668 and not $ShortBase_Old{get_ShortType($BaseId, 2)})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009669 { # added base
9670 # excluding namespace::SomeClass to SomeClass renaming
9671 my $ProblemKind = "Added_Base_Class";
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04009672 if($Level eq "Binary")
9673 { # Binary-level
9674 if($Shift_Old ne $Shift_New)
9675 { # affected fields
9676 if(havePubFields(\%Class_Old)) {
9677 $ProblemKind .= "_And_Shift";
9678 }
9679 elsif($Class_Old{"Size"} ne $Class_New{"Size"}) {
9680 $ProblemKind .= "_And_Size";
9681 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009682 }
Andrey Ponomarenko16934472012-03-29 15:37:04 +04009683 if(keys(%{$VirtualTable_Model{2}{$BaseName}})
9684 and cmpVTables($ClassName)==1)
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04009685 { # affected v-table
9686 $ProblemKind .= "_And_VTable";
Andrey Ponomarenko16934472012-03-29 15:37:04 +04009687 $VTableChanged_M{$ClassName}=1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009688 }
9689 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04009690 my @Affected = keys(%{$ClassMethods{$Level}{1}{$ClassName}});
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009691 foreach my $SubId (get_sub_classes($ClassId_Old, 1, 1))
9692 {
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +04009693 if(my $SubName = $TypeInfo{1}{$SubId}{"Name"})
9694 {
9695 push(@Affected, keys(%{$ClassMethods{$Level}{1}{$SubName}}));
9696 if($ProblemKind=~/VTable/) {
9697 $VTableChanged_M{$SubName}=1;
9698 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009699 }
9700 }
9701 foreach my $Interface (@Affected)
9702 {
Andrey Ponomarenko9927e332012-10-19 10:50:48 +04009703 if(not symbolFilter($Interface, 1, "Affected", $Level)) {
9704 next;
9705 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04009706 %{$CompatProblems{$Level}{$Interface}{$ProblemKind}{"this"}}=(
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009707 "Type_Name"=>$ClassName,
9708 "Type_Type"=>"Class",
9709 "Target"=>$BaseName,
9710 "Old_Size"=>$Class_Old{"Size"}*$BYTE_SIZE,
9711 "New_Size"=>$Class_New{"Size"}*$BYTE_SIZE,
9712 "Shift"=>abs($Shift_New-$Shift_Old) );
9713 }
9714 $Added+=1;
9715 }
9716 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04009717 if($Level eq "Binary")
9718 { # Binary-level
9719 ($BNum1, $BNum2) = (1, 1);
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +04009720 my %BaseRelPos_Old = map {$Tr_Old{$TypeInfo{1}{$_}{"Name"}} => $BNum1++} @StableBases_Old;
9721 my %BaseRelPos_New = map {$Tr_New{$TypeInfo{2}{$_}{"Name"}} => $BNum2++} @StableBases_New;
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04009722 foreach my $BaseId (@Bases_Old)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009723 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04009724 my $BaseName = $TypeInfo{1}{$BaseId}{"Name"};
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +04009725 if(my $NewPos = $BaseRelPos_New{$Tr_Old{$BaseName}})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009726 {
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +04009727 my $BaseNewId = $BaseId_New{$Tr_Old{$BaseName}};
9728 my $OldPos = $BaseRelPos_Old{$Tr_Old{$BaseName}};
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04009729 if($NewPos!=$OldPos)
9730 { # changed position of the base class
9731 foreach my $Interface (keys(%{$ClassMethods{$Level}{1}{$ClassName}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009732 {
Andrey Ponomarenko9927e332012-10-19 10:50:48 +04009733 if(not symbolFilter($Interface, 1, "Affected", $Level)) {
9734 next;
9735 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04009736 %{$CompatProblems{$Level}{$Interface}{"Base_Class_Position"}{"this"}}=(
9737 "Type_Name"=>$ClassName,
9738 "Type_Type"=>"Class",
9739 "Target"=>$BaseName,
9740 "Old_Value"=>$OldPos-1,
9741 "New_Value"=>$NewPos-1 );
9742 }
9743 }
9744 if($Class_Old{"Base"}{$BaseId}{"virtual"}
9745 and not $Class_New{"Base"}{$BaseNewId}{"virtual"})
9746 { # became non-virtual base
9747 foreach my $Interface (keys(%{$ClassMethods{$Level}{1}{$ClassName}}))
9748 {
Andrey Ponomarenko9927e332012-10-19 10:50:48 +04009749 if(not symbolFilter($Interface, 1, "Affected", $Level)) {
9750 next;
9751 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04009752 %{$CompatProblems{$Level}{$Interface}{"Base_Class_Became_Non_Virtually_Inherited"}{"this->".$BaseName}}=(
9753 "Type_Name"=>$ClassName,
9754 "Type_Type"=>"Class",
9755 "Target"=>$BaseName );
9756 }
9757 }
9758 elsif(not $Class_Old{"Base"}{$BaseId}{"virtual"}
9759 and $Class_New{"Base"}{$BaseNewId}{"virtual"})
9760 { # became virtual base
9761 foreach my $Interface (keys(%{$ClassMethods{$Level}{1}{$ClassName}}))
9762 {
Andrey Ponomarenko9927e332012-10-19 10:50:48 +04009763 if(not symbolFilter($Interface, 1, "Affected", $Level)) {
9764 next;
9765 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04009766 %{$CompatProblems{$Level}{$Interface}{"Base_Class_Became_Virtually_Inherited"}{"this->".$BaseName}}=(
9767 "Type_Name"=>$ClassName,
9768 "Type_Type"=>"Class",
9769 "Target"=>$BaseName );
9770 }
9771 }
9772 }
9773 }
9774 # detect size changes in base classes
9775 if($Shift_Old!=$Shift_New)
9776 { # size of allocable class
9777 foreach my $BaseId (@StableBases_Old)
9778 { # search for changed base
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04009779 my %BaseType = get_Type($BaseId, 1);
9780 my $Size_Old = $TypeInfo{1}{$BaseId}{"Size"};
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +04009781 my $Size_New = $TypeInfo{2}{$BaseId_New{$Tr_Old{$BaseType{"Name"}}}}{"Size"};
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04009782 if($Size_Old ne $Size_New
9783 and $Size_Old and $Size_New)
9784 {
9785 my $ProblemType = "";
9786 if(isCopyingClass($BaseId, 1)) {
9787 $ProblemType = "Size_Of_Copying_Class";
9788 }
9789 elsif($AllocableClass{1}{$BaseType{"Name"}})
9790 {
9791 if($Size_New>$Size_Old)
9792 { # increased size
9793 $ProblemType = "Size_Of_Allocable_Class_Increased";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009794 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04009795 else
9796 { # decreased size
9797 $ProblemType = "Size_Of_Allocable_Class_Decreased";
9798 if(not havePubFields(\%Class_Old))
9799 { # affected class has no public members
9800 next;
9801 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009802 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04009803 }
9804 next if(not $ProblemType);
9805 foreach my $Interface (keys(%{$ClassMethods{$Level}{1}{$ClassName}}))
9806 { # base class size changes affecting current class
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}{$ProblemType}{"this->".$BaseType{"Name"}}}=(
9811 "Type_Name"=>$BaseType{"Name"},
9812 "Type_Type"=>"Class",
9813 "Target"=>$BaseType{"Name"},
9814 "Old_Size"=>$Size_Old*$BYTE_SIZE,
9815 "New_Size"=>$Size_New*$BYTE_SIZE );
9816 }
9817 }
9818 }
9819 }
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +04009820 if(defined $VirtualTable_Model{1}{$ClassName}
Andrey Ponomarenko16934472012-03-29 15:37:04 +04009821 and cmpVTables_Real($ClassName, 1)==1
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +04009822 and my @VFunctions = keys(%{$VirtualTable_Model{1}{$ClassName}}))
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04009823 { # compare virtual tables size in base classes
9824 my $VShift_Old = getVShift($ClassId_Old, 1);
9825 my $VShift_New = getVShift($ClassId_New, 2);
9826 if($VShift_Old ne $VShift_New)
9827 { # changes in the base class or changes in the list of base classes
9828 my @AllBases_Old = get_base_classes($ClassId_Old, 1, 1);
9829 my @AllBases_New = get_base_classes($ClassId_New, 2, 1);
9830 ($BNum1, $BNum2) = (1, 1);
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +04009831 my %StableBase = map {$Tr_New{$TypeInfo{2}{$_}{"Name"}} => $_} @AllBases_New;
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04009832 foreach my $BaseId (@AllBases_Old)
9833 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04009834 my %BaseType = get_Type($BaseId, 1);
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +04009835 if(not $StableBase{$Tr_Old{$BaseType{"Name"}}})
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04009836 { # lost base
9837 next;
9838 }
Andrey Ponomarenko16934472012-03-29 15:37:04 +04009839 my $VSize_Old = getVTable_Size($BaseType{"Name"}, 1);
9840 my $VSize_New = getVTable_Size($BaseType{"Name"}, 2);
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04009841 if($VSize_Old!=$VSize_New)
9842 {
Andrey Ponomarenko85043792012-05-14 16:48:07 +04009843 foreach my $Symbol (@VFunctions)
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +04009844 { # TODO: affected non-virtual methods?
9845 if(not defined $VirtualTable_Model{2}{$ClassName}{$Symbol})
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04009846 { # Removed_Virtual_Method, will be registered in mergeVirtualTables()
9847 next;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009848 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +04009849 if($VirtualTable_Model{2}{$ClassName}{$Symbol}-$VirtualTable_Model{1}{$ClassName}{$Symbol}==0)
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04009850 { # skip interfaces that have not changed the absolute virtual position
9851 next;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009852 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +04009853 if(not symbolFilter($Symbol, 1, "Affected", $Level)) {
9854 next;
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04009855 }
Andrey Ponomarenko16934472012-03-29 15:37:04 +04009856 $VTableChanged_M{$BaseType{"Name"}} = 1;
9857 $VTableChanged_M{$ClassName} = 1;
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04009858 foreach my $VirtFunc (keys(%{$AddedInt_Virt{$Level}{$BaseType{"Name"}}}))
9859 { # the reason of the layout change: added virtual functions
9860 next if($VirtualReplacement{$VirtFunc});
9861 my $ProblemType = "Added_Virtual_Method";
9862 if($CompleteSignature{2}{$VirtFunc}{"PureVirt"}) {
9863 $ProblemType = "Added_Pure_Virtual_Method";
9864 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +04009865 %{$CompatProblems{$Level}{$Symbol}{$ProblemType}{get_Signature($VirtFunc, 2)}}=(
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04009866 "Type_Name"=>$BaseType{"Name"},
9867 "Type_Type"=>"Class",
9868 "Target"=>get_Signature($VirtFunc, 2) );
9869 }
9870 foreach my $VirtFunc (keys(%{$RemovedInt_Virt{$Level}{$BaseType{"Name"}}}))
9871 { # the reason of the layout change: removed virtual functions
9872 next if($VirtualReplacement{$VirtFunc});
9873 my $ProblemType = "Removed_Virtual_Method";
9874 if($CompleteSignature{1}{$VirtFunc}{"PureVirt"}) {
9875 $ProblemType = "Removed_Pure_Virtual_Method";
9876 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +04009877 %{$CompatProblems{$Level}{$Symbol}{$ProblemType}{get_Signature($VirtFunc, 1)}}=(
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04009878 "Type_Name"=>$BaseType{"Name"},
9879 "Type_Type"=>"Class",
9880 "Target"=>get_Signature($VirtFunc, 1) );
9881 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009882 }
9883 }
9884 }
9885 }
9886 }
9887 }
9888 }
9889}
9890
9891sub isCreatable($$)
9892{
9893 my ($ClassId, $LibVersion) = @_;
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04009894 if($AllocableClass{$LibVersion}{$TypeInfo{$LibVersion}{$ClassId}{"Name"}}
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009895 or isCopyingClass($ClassId, $LibVersion)) {
9896 return 1;
9897 }
9898 if(keys(%{$Class_SubClasses{$LibVersion}{$ClassId}}))
9899 { # Fix for incomplete data: if this class has
9900 # a base class then it should also has a constructor
9901 return 1;
9902 }
9903 if($ReturnedClass{$LibVersion}{$ClassId})
9904 { # returned by some method of this class
9905 # or any other class
9906 return 1;
9907 }
9908 return 0;
9909}
9910
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04009911sub isUsedClass($$$)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009912{
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04009913 my ($ClassId, $LibVersion, $Level) = @_;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009914 if(keys(%{$ParamClass{$LibVersion}{$ClassId}}))
9915 { # parameter of some exported method
9916 return 1;
9917 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04009918 my $CName = $TypeInfo{$LibVersion}{$ClassId}{"Name"};
9919 if(keys(%{$ClassMethods{$Level}{$LibVersion}{$CName}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009920 { # method from target class
9921 return 1;
9922 }
9923 return 0;
9924}
9925
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04009926sub mergeVirtualTables($$)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009927{ # check for changes in the virtual table
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04009928 my ($Interface, $Level) = @_;
Andrey Ponomarenko16934472012-03-29 15:37:04 +04009929 # affected methods:
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009930 # - virtual
9931 # - pure-virtual
9932 # - non-virtual
9933 if($CompleteSignature{1}{$Interface}{"Data"})
9934 { # global data is not affected
9935 return;
9936 }
9937 my $Class_Id = $CompleteSignature{1}{$Interface}{"Class"};
Andrey Ponomarenko16934472012-03-29 15:37:04 +04009938 if(not $Class_Id) {
9939 return;
9940 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04009941 my $CName = $TypeInfo{1}{$Class_Id}{"Name"};
Andrey Ponomarenko16934472012-03-29 15:37:04 +04009942 if(cmpVTables_Real($CName, 1)==0)
9943 { # no changes
9944 return;
9945 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04009946 $CheckedTypes{$Level}{$CName} = 1;
9947 if($Level eq "Binary")
9948 { # Binary-level
9949 if($CompleteSignature{1}{$Interface}{"PureVirt"}
9950 and not isUsedClass($Class_Id, 1, $Level))
9951 { # pure virtuals should not be affected
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04009952 # if there are no exported methods using this class
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04009953 return;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009954 }
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04009955 }
9956 foreach my $Func (keys(%{$VirtualTable{1}{$CName}}))
9957 {
9958 if(defined $VirtualTable{2}{$CName}{$Func}
9959 and defined $CompleteSignature{2}{$Func})
9960 {
9961 if(not $CompleteSignature{1}{$Func}{"PureVirt"}
9962 and $CompleteSignature{2}{$Func}{"PureVirt"})
9963 { # became pure virtual
9964 %{$CompatProblems{$Level}{$Interface}{"Virtual_Method_Became_Pure"}{$tr_name{$Func}}}=(
9965 "Type_Name"=>$CName,
9966 "Type_Type"=>"Class",
9967 "Target"=>get_Signature_M($Func, 1) );
9968 $VTableChanged_M{$CName} = 1;
9969 }
9970 elsif($CompleteSignature{1}{$Func}{"PureVirt"}
9971 and not $CompleteSignature{2}{$Func}{"PureVirt"})
9972 { # became non-pure virtual
9973 %{$CompatProblems{$Level}{$Interface}{"Virtual_Method_Became_Non_Pure"}{$tr_name{$Func}}}=(
9974 "Type_Name"=>$CName,
9975 "Type_Type"=>"Class",
9976 "Target"=>get_Signature_M($Func, 1) );
9977 $VTableChanged_M{$CName} = 1;
9978 }
9979 }
9980 }
9981 if($Level eq "Binary")
9982 { # Binary-level
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04009983 # check virtual table structure
9984 foreach my $AddedVFunc (keys(%{$AddedInt_Virt{$Level}{$CName}}))
9985 {
9986 next if($Interface eq $AddedVFunc);
9987 next if($VirtualReplacement{$AddedVFunc});
9988 my $VPos_Added = $VirtualTable{2}{$CName}{$AddedVFunc};
9989 if($CompleteSignature{2}{$AddedVFunc}{"PureVirt"})
9990 { # pure virtual methods affect all others (virtual and non-virtual)
9991 %{$CompatProblems{$Level}{$Interface}{"Added_Pure_Virtual_Method"}{$tr_name{$AddedVFunc}}}=(
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009992 "Type_Name"=>$CName,
9993 "Type_Type"=>"Class",
9994 "Target"=>get_Signature($AddedVFunc, 2) );
Andrey Ponomarenko16934472012-03-29 15:37:04 +04009995 $VTableChanged_M{$CName} = 1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009996 }
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04009997 elsif(not defined $VirtualTable{1}{$CName}
9998 or $VPos_Added>keys(%{$VirtualTable{1}{$CName}}))
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04009999 { # added virtual function at the end of v-table
Andrey Ponomarenko16934472012-03-29 15:37:04 +040010000 if(not keys(%{$VirtualTable_Model{1}{$CName}}))
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040010001 { # became polymorphous class, added v-table pointer
10002 %{$CompatProblems{$Level}{$Interface}{"Added_First_Virtual_Method"}{$tr_name{$AddedVFunc}}}=(
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010003 "Type_Name"=>$CName,
10004 "Type_Type"=>"Class",
10005 "Target"=>get_Signature($AddedVFunc, 2) );
Andrey Ponomarenko16934472012-03-29 15:37:04 +040010006 $VTableChanged_M{$CName} = 1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010007 }
10008 else
10009 {
Andrey Ponomarenko16934472012-03-29 15:37:04 +040010010 my $VSize_Old = getVTable_Size($CName, 1);
10011 my $VSize_New = getVTable_Size($CName, 2);
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040010012 next if($VSize_Old==$VSize_New); # exception: register as removed and added virtual method
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040010013 if(isCopyingClass($Class_Id, 1))
10014 { # class has no constructors and v-table will be copied by applications, this may affect all methods
10015 my $ProblemType = "Added_Virtual_Method";
10016 if(isLeafClass($Class_Id, 1)) {
10017 $ProblemType = "Added_Virtual_Method_At_End_Of_Leaf_Copying_Class";
10018 }
10019 %{$CompatProblems{$Level}{$Interface}{$ProblemType}{$tr_name{$AddedVFunc}}}=(
10020 "Type_Name"=>$CName,
10021 "Type_Type"=>"Class",
10022 "Target"=>get_Signature($AddedVFunc, 2) );
Andrey Ponomarenko16934472012-03-29 15:37:04 +040010023 $VTableChanged_M{$CName} = 1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010024 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040010025 else
10026 {
10027 my $ProblemType = "Added_Virtual_Method";
10028 if(isLeafClass($Class_Id, 1)) {
10029 $ProblemType = "Added_Virtual_Method_At_End_Of_Leaf_Allocable_Class";
10030 }
10031 %{$CompatProblems{$Level}{$Interface}{$ProblemType}{$tr_name{$AddedVFunc}}}=(
10032 "Type_Name"=>$CName,
10033 "Type_Type"=>"Class",
10034 "Target"=>get_Signature($AddedVFunc, 2) );
Andrey Ponomarenko16934472012-03-29 15:37:04 +040010035 $VTableChanged_M{$CName} = 1;
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040010036 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010037 }
10038 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040010039 elsif($CompleteSignature{1}{$Interface}{"Virt"}
10040 or $CompleteSignature{1}{$Interface}{"PureVirt"})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010041 {
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040010042 if(defined $VirtualTable{1}{$CName}
10043 and defined $VirtualTable{2}{$CName})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010044 {
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040010045 my $VPos_Old = $VirtualTable{1}{$CName}{$Interface};
10046 my $VPos_New = $VirtualTable{2}{$CName}{$Interface};
10047 if($VPos_Added<=$VPos_Old and $VPos_Old!=$VPos_New)
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040010048 {
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040010049 my @Affected = ($Interface, keys(%{$OverriddenMethods{1}{$Interface}}));
10050 foreach my $ASymbol (@Affected)
10051 {
Andrey Ponomarenko85043792012-05-14 16:48:07 +040010052 if(not $CompleteSignature{1}{$ASymbol}{"PureVirt"})
10053 {
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040010054 if(not symbolFilter($ASymbol, 1, "Affected", $Level)) {
Andrey Ponomarenko85043792012-05-14 16:48:07 +040010055 next;
10056 }
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040010057 }
10058 $CheckedSymbols{$Level}{$ASymbol} = 1;
10059 %{$CompatProblems{$Level}{$ASymbol}{"Added_Virtual_Method"}{$tr_name{$AddedVFunc}}}=(
10060 "Type_Name"=>$CName,
10061 "Type_Type"=>"Class",
10062 "Target"=>get_Signature($AddedVFunc, 2) );
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040010063 $VTableChanged_M{$TypeInfo{1}{$CompleteSignature{1}{$ASymbol}{"Class"}}{"Name"}} = 1;
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040010064 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010065 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010066 }
10067 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040010068 else {
10069 # safe
10070 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010071 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040010072 foreach my $RemovedVFunc (keys(%{$RemovedInt_Virt{$Level}{$CName}}))
10073 {
10074 next if($VirtualReplacement{$RemovedVFunc});
10075 if($RemovedVFunc eq $Interface
10076 and $CompleteSignature{1}{$RemovedVFunc}{"PureVirt"})
10077 { # This case is for removed virtual methods
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040010078 # implemented in both versions of a library
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040010079 next;
10080 }
Andrey Ponomarenko16934472012-03-29 15:37:04 +040010081 if(not keys(%{$VirtualTable_Model{2}{$CName}}))
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040010082 { # became non-polymorphous class, removed v-table pointer
10083 %{$CompatProblems{$Level}{$Interface}{"Removed_Last_Virtual_Method"}{$tr_name{$RemovedVFunc}}}=(
10084 "Type_Name"=>$CName,
10085 "Type_Type"=>"Class",
10086 "Target"=>get_Signature($RemovedVFunc, 1) );
Andrey Ponomarenko16934472012-03-29 15:37:04 +040010087 $VTableChanged_M{$CName} = 1;
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040010088 }
10089 elsif($CompleteSignature{1}{$Interface}{"Virt"}
10090 or $CompleteSignature{1}{$Interface}{"PureVirt"})
10091 {
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040010092 if(defined $VirtualTable{1}{$CName} and defined $VirtualTable{2}{$CName})
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040010093 {
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040010094 if(not defined $VirtualTable{1}{$CName}{$Interface}) {
10095 next;
10096 }
10097 my $VPos_New = -1;
10098 if(defined $VirtualTable{2}{$CName}{$Interface})
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040010099 {
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040010100 $VPos_New = $VirtualTable{2}{$CName}{$Interface};
10101 }
10102 else
10103 {
10104 if($Interface ne $RemovedVFunc) {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040010105 next;
10106 }
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040010107 }
10108 my $VPos_Removed = $VirtualTable{1}{$CName}{$RemovedVFunc};
10109 my $VPos_Old = $VirtualTable{1}{$CName}{$Interface};
10110 if($VPos_Removed<=$VPos_Old and $VPos_Old!=$VPos_New)
10111 {
10112 my @Affected = ($Interface, keys(%{$OverriddenMethods{1}{$Interface}}));
10113 foreach my $ASymbol (@Affected)
10114 {
Andrey Ponomarenko85043792012-05-14 16:48:07 +040010115 if(not $CompleteSignature{1}{$ASymbol}{"PureVirt"})
10116 {
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040010117 if(not symbolFilter($ASymbol, 1, "Affected", $Level)) {
Andrey Ponomarenko85043792012-05-14 16:48:07 +040010118 next;
10119 }
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040010120 }
10121 my $ProblemType = "Removed_Virtual_Method";
10122 if($CompleteSignature{1}{$RemovedVFunc}{"PureVirt"}) {
10123 $ProblemType = "Removed_Pure_Virtual_Method";
10124 }
10125 $CheckedSymbols{$Level}{$ASymbol} = 1;
10126 %{$CompatProblems{$Level}{$ASymbol}{$ProblemType}{$tr_name{$RemovedVFunc}}}=(
10127 "Type_Name"=>$CName,
10128 "Type_Type"=>"Class",
10129 "Target"=>get_Signature($RemovedVFunc, 1) );
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040010130 $VTableChanged_M{$TypeInfo{1}{$CompleteSignature{1}{$ASymbol}{"Class"}}{"Name"}} = 1;
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040010131 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040010132 }
10133 }
10134 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010135 }
10136 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040010137 else
10138 { # Source-level
10139 foreach my $AddedVFunc (keys(%{$AddedInt_Virt{$Level}{$CName}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010140 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040010141 next if($Interface eq $AddedVFunc);
10142 if($CompleteSignature{2}{$AddedVFunc}{"PureVirt"})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010143 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040010144 %{$CompatProblems{$Level}{$Interface}{"Added_Pure_Virtual_Method"}{$tr_name{$AddedVFunc}}}=(
10145 "Type_Name"=>$CName,
10146 "Type_Type"=>"Class",
10147 "Target"=>get_Signature($AddedVFunc, 2) );
10148 }
10149 }
10150 foreach my $RemovedVFunc (keys(%{$RemovedInt_Virt{$Level}{$CName}}))
10151 {
10152 if($CompleteSignature{1}{$RemovedVFunc}{"PureVirt"})
10153 {
10154 %{$CompatProblems{$Level}{$Interface}{"Removed_Pure_Virtual_Method"}{$tr_name{$RemovedVFunc}}}=(
10155 "Type_Name"=>$CName,
10156 "Type_Type"=>"Class",
10157 "Target"=>get_Signature($RemovedVFunc, 1) );
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010158 }
10159 }
10160 }
10161}
10162
10163sub find_MemberPair_Pos_byName($$)
10164{
10165 my ($Member_Name, $Pair_Type) = @_;
10166 $Member_Name=~s/\A[_]+|[_]+\Z//g;
10167 foreach my $MemberPair_Pos (sort {int($a)<=>int($b)} keys(%{$Pair_Type->{"Memb"}}))
10168 {
10169 if(defined $Pair_Type->{"Memb"}{$MemberPair_Pos})
10170 {
10171 my $Name = $Pair_Type->{"Memb"}{$MemberPair_Pos}{"name"};
10172 $Name=~s/\A[_]+|[_]+\Z//g;
10173 if($Name eq $Member_Name) {
10174 return $MemberPair_Pos;
10175 }
10176 }
10177 }
10178 return "lost";
10179}
10180
10181sub find_MemberPair_Pos_byVal($$)
10182{
10183 my ($Member_Value, $Pair_Type) = @_;
10184 foreach my $MemberPair_Pos (sort {int($a)<=>int($b)} keys(%{$Pair_Type->{"Memb"}}))
10185 {
10186 if(defined $Pair_Type->{"Memb"}{$MemberPair_Pos}
10187 and $Pair_Type->{"Memb"}{$MemberPair_Pos}{"value"} eq $Member_Value) {
10188 return $MemberPair_Pos;
10189 }
10190 }
10191 return "lost";
10192}
10193
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040010194my %Severity_Val=(
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010195 "High"=>3,
10196 "Medium"=>2,
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040010197 "Low"=>1,
10198 "Safe"=>-1
10199);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010200
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040010201sub maxSeverity($$)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010202{
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040010203 my ($S1, $S2) = @_;
10204 if(cmpSeverities($S1, $S2)) {
10205 return $S1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010206 }
10207 else {
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040010208 return $S2;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010209 }
10210}
10211
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040010212sub cmpSeverities($$)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010213{
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040010214 my ($S1, $S2) = @_;
10215 if(not $S1) {
10216 return 0;
10217 }
10218 elsif(not $S2) {
10219 return 1;
10220 }
10221 return ($Severity_Val{$S1}>$Severity_Val{$S2});
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010222}
10223
10224sub getProblemSeverity($$)
10225{
10226 my ($Level, $Kind) = @_;
10227 return $CompatRules{$Level}{$Kind}{"Severity"};
10228}
10229
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040010230sub isRecurType($$)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010231{
10232 foreach (@RecurTypes)
10233 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040010234 if( $_->{"T1"} eq $_[0]
10235 and $_->{"T2"} eq $_[1] )
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010236 {
10237 return 1;
10238 }
10239 }
10240 return 0;
10241}
10242
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040010243sub pushType($$)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010244{
10245 my %TypeIDs=(
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040010246 "T1" => $_[0], #Tid1
10247 "T2" => $_[1] #Tid2
Andrey Ponomarenko16934472012-03-29 15:37:04 +040010248 );
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010249 push(@RecurTypes, \%TypeIDs);
10250}
10251
10252sub isRenamed($$$$$)
10253{
10254 my ($MemPos, $Type1, $LVersion1, $Type2, $LVersion2) = @_;
10255 my $Member_Name = $Type1->{"Memb"}{$MemPos}{"name"};
10256 my $MemberType_Id = $Type1->{"Memb"}{$MemPos}{"type"};
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +040010257 my %MemberType_Pure = get_PureType($MemberType_Id, $TypeInfo{$LVersion1});
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010258 if(not defined $Type2->{"Memb"}{$MemPos}) {
10259 return "";
10260 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040010261 my $PairType_Id = $Type2->{"Memb"}{$MemPos}{"type"};
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +040010262 my %PairType_Pure = get_PureType($PairType_Id, $TypeInfo{$LVersion2});
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010263
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040010264 my $Pair_Name = $Type2->{"Memb"}{$MemPos}{"name"};
10265 my $MemberPair_Pos_Rev = ($Member_Name eq $Pair_Name)?$MemPos:find_MemberPair_Pos_byName($Pair_Name, $Type1);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010266 if($MemberPair_Pos_Rev eq "lost")
10267 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040010268 if($MemberType_Pure{"Name"} eq $PairType_Pure{"Name"})
10269 { # base type match
10270 return $Pair_Name;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010271 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040010272 if($TypeInfo{$LVersion1}{$MemberType_Id}{"Name"} eq $TypeInfo{$LVersion2}{$PairType_Id}{"Name"})
10273 { # exact type match
10274 return $Pair_Name;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010275 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040010276 if($MemberType_Pure{"Size"} eq $PairType_Pure{"Size"})
10277 { # size match
10278 return $Pair_Name;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010279 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040010280 if(isReserved($Pair_Name))
10281 { # reserved fields
10282 return $Pair_Name;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010283 }
10284 }
10285 return "";
10286}
10287
10288sub isLastElem($$)
10289{
10290 my ($Pos, $TypeRef) = @_;
10291 my $Name = $TypeRef->{"Memb"}{$Pos}{"name"};
10292 if($Name=~/last|count|max|total/i)
10293 { # GST_LEVEL_COUNT, GST_RTSP_ELAST
10294 return 1;
10295 }
10296 elsif($Name=~/END|NLIMITS\Z/)
10297 { # __RLIMIT_NLIMITS
10298 return 1;
10299 }
10300 elsif($Name=~/\AN[A-Z](.+)[a-z]+s\Z/
10301 and $Pos+1==keys(%{$TypeRef->{"Memb"}}))
10302 { # NImageFormats, NColorRoles
10303 return 1;
10304 }
10305 return 0;
10306}
10307
10308sub nonComparable($$)
10309{
10310 my ($T1, $T2) = @_;
10311 if($T1->{"Name"} ne $T2->{"Name"}
10312 and not isAnon($T1->{"Name"})
10313 and not isAnon($T2->{"Name"}))
10314 { # different names
10315 if($T1->{"Type"} ne "Pointer"
10316 or $T2->{"Type"} ne "Pointer")
10317 { # compare base types
10318 return 1;
10319 }
10320 if($T1->{"Name"}!~/\Avoid\s*\*/
10321 and $T2->{"Name"}=~/\Avoid\s*\*/)
10322 {
10323 return 1;
10324 }
10325 }
10326 elsif($T1->{"Type"} ne $T2->{"Type"})
10327 { # different types
10328 if($T1->{"Type"} eq "Class"
10329 and $T2->{"Type"} eq "Struct")
10330 { # "class" to "struct"
10331 return 0;
10332 }
10333 elsif($T2->{"Type"} eq "Class"
10334 and $T1->{"Type"} eq "Struct")
10335 { # "struct" to "class"
10336 return 0;
10337 }
10338 else
10339 { # "class" to "enum"
10340 # "union" to "class"
10341 # ...
10342 return 1;
10343 }
10344 }
10345 return 0;
10346}
10347
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040010348sub mergeTypes($$$)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010349{
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040010350 my ($Type1_Id, $Type2_Id, $Level) = @_;
10351 return () if(not $Type1_Id or not $Type2_Id);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010352 my (%Sub_SubProblems, %SubProblems) = ();
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040010353 if($Cache{"mergeTypes"}{$Level}{$Type1_Id}{$Type2_Id})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010354 { # already merged
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040010355 return %{$Cache{"mergeTypes"}{$Level}{$Type1_Id}{$Type2_Id}};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010356 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040010357 my %Type1 = get_Type($Type1_Id, 1);
10358 my %Type2 = get_Type($Type2_Id, 2);
Andrey Ponomarenko16934472012-03-29 15:37:04 +040010359 if(not $Type1{"Name"} or not $Type2{"Name"}) {
10360 return ();
10361 }
10362 $CheckedTypes{$Level}{$Type1{"Name"}}=1;
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +040010363 my %Type1_Pure = get_PureType($Type1_Id, $TypeInfo{1});
10364 my %Type2_Pure = get_PureType($Type2_Id, $TypeInfo{2});
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040010365 $CheckedTypes{$Level}{$Type1_Pure{"Name"}}=1;
Andrey Ponomarenko85043792012-05-14 16:48:07 +040010366 if(not $Type1_Pure{"Size"} or not $Type2_Pure{"Size"})
10367 { # including a case when "class Class { ... };" changed to "class Class;"
10368 return ();
10369 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040010370 if(isRecurType($Type1_Pure{"Tid"}, $Type2_Pure{"Tid"}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010371 { # skip recursive declarations
10372 return ();
10373 }
10374 return () if(not $Type1_Pure{"Name"} or not $Type2_Pure{"Name"});
10375 return () if($SkipTypes{1}{$Type1_Pure{"Name"}});
10376 return () if($SkipTypes{1}{$Type1{"Name"}});
10377
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040010378 my %Typedef_1 = goToFirst($Type1{"Tid"}, 1, "Typedef");
10379 my %Typedef_2 = goToFirst($Type2{"Tid"}, 2, "Typedef");
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040010380 if(not $UseOldDumps and %Typedef_1 and %Typedef_2
10381 and $Typedef_1{"Type"} eq "Typedef" and $Typedef_2{"Type"} eq "Typedef"
10382 and $Typedef_1{"Name"} eq $Typedef_2{"Name"})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010383 {
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +040010384 my %Base_1 = get_OneStep_BaseType($Typedef_1{"Tid"}, $TypeInfo{1});
10385 my %Base_2 = get_OneStep_BaseType($Typedef_2{"Tid"}, $TypeInfo{2});
Andrey Ponomarenko85043792012-05-14 16:48:07 +040010386 if($Base_1{"Name"} ne $Base_2{"Name"})
10387 {
10388 if(differentDumps("G")
10389 or differentDumps("V"))
10390 { # different GCC versions or different dumps
10391 $Base_1{"Name"} = uncover_typedefs($Base_1{"Name"}, 1);
10392 $Base_2{"Name"} = uncover_typedefs($Base_2{"Name"}, 2);
10393 # std::__va_list and __va_list
10394 $Base_1{"Name"}=~s/\A(\w+::)+//;
10395 $Base_2{"Name"}=~s/\A(\w+::)+//;
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040010396 $Base_1{"Name"} = formatName($Base_1{"Name"}, "T");
10397 $Base_2{"Name"} = formatName($Base_2{"Name"}, "T");
Andrey Ponomarenko85043792012-05-14 16:48:07 +040010398 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010399 }
10400 if($Base_1{"Name"}!~/anon\-/ and $Base_2{"Name"}!~/anon\-/
10401 and $Base_1{"Name"} ne $Base_2{"Name"})
10402 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040010403 if($Level eq "Binary"
10404 and $Type1{"Size"} ne $Type2{"Size"})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010405 {
10406 %{$SubProblems{"DataType_Size"}{$Typedef_1{"Name"}}}=(
10407 "Target"=>$Typedef_1{"Name"},
10408 "Type_Name"=>$Typedef_1{"Name"},
10409 "Type_Type"=>"Typedef",
10410 "Old_Size"=>$Type1{"Size"}*$BYTE_SIZE,
10411 "New_Size"=>$Type2{"Size"}*$BYTE_SIZE );
10412 }
10413 %{$SubProblems{"Typedef_BaseType"}{$Typedef_1{"Name"}}}=(
10414 "Target"=>$Typedef_1{"Name"},
10415 "Type_Name"=>$Typedef_1{"Name"},
10416 "Type_Type"=>"Typedef",
10417 "Old_Value"=>$Base_1{"Name"},
10418 "New_Value"=>$Base_2{"Name"} );
10419 }
10420 }
10421 if(nonComparable(\%Type1_Pure, \%Type2_Pure))
10422 { # different types (reported in detectTypeChange(...))
10423 if($Type1_Pure{"Name"} eq $Type2_Pure{"Name"}
10424 and $Type1_Pure{"Type"} ne $Type2_Pure{"Type"}
10425 and $Type1_Pure{"Type"}!~/Intrinsic|Pointer|Ref|Typedef/)
10426 { # different type of the type
10427 %{$SubProblems{"DataType_Type"}{$Type1_Pure{"Name"}}}=(
10428 "Target"=>$Type1_Pure{"Name"},
10429 "Type_Name"=>$Type1_Pure{"Name"},
10430 "Type_Type"=>$Type1_Pure{"Type"},
10431 "Old_Value"=>lc($Type1_Pure{"Type"}),
10432 "New_Value"=>lc($Type2_Pure{"Type"}) );
10433 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040010434 %{$Cache{"mergeTypes"}{$Level}{$Type1_Id}{$Type2_Id}} = %SubProblems;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010435 return %SubProblems;
10436 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040010437 pushType($Type1_Pure{"Tid"}, $Type2_Pure{"Tid"});
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010438 if(($Type1_Pure{"Name"} eq $Type2_Pure{"Name"}
10439 or (isAnon($Type1_Pure{"Name"}) and isAnon($Type2_Pure{"Name"})))
10440 and $Type1_Pure{"Type"}=~/\A(Struct|Class|Union)\Z/)
10441 { # checking size
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040010442 if($Level eq "Binary"
10443 and $Type1_Pure{"Size"} ne $Type2_Pure{"Size"})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010444 {
10445 my $ProblemKind = "DataType_Size";
10446 if($Type1_Pure{"Type"} eq "Class"
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040010447 and keys(%{$ClassMethods{$Level}{1}{$Type1_Pure{"Name"}}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010448 {
10449 if(isCopyingClass($Type1_Pure{"Tid"}, 1)) {
10450 $ProblemKind = "Size_Of_Copying_Class";
10451 }
10452 elsif($AllocableClass{1}{$Type1_Pure{"Name"}})
10453 {
10454 if(int($Type2_Pure{"Size"})>int($Type1_Pure{"Size"})) {
10455 $ProblemKind = "Size_Of_Allocable_Class_Increased";
10456 }
10457 else {
10458 # descreased size of allocable class
10459 # it has no special effects
10460 }
10461 }
10462 }
10463 %{$SubProblems{$ProblemKind}{$Type1_Pure{"Name"}}}=(
10464 "Target"=>$Type1_Pure{"Name"},
10465 "Type_Name"=>$Type1_Pure{"Name"},
10466 "Type_Type"=>$Type1_Pure{"Type"},
10467 "Old_Size"=>$Type1_Pure{"Size"}*$BYTE_SIZE,
10468 "New_Size"=>$Type2_Pure{"Size"}*$BYTE_SIZE,
10469 "InitialType_Type"=>$Type1_Pure{"Type"} );
10470 }
10471 }
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040010472 if(defined $Type1_Pure{"BaseType"} and $Type1_Pure{"BaseType"}{"Tid"}
10473 and defined $Type2_Pure{"BaseType"} and $Type2_Pure{"BaseType"}{"Tid"})
10474 { # checking base types
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040010475 %Sub_SubProblems = mergeTypes($Type1_Pure{"BaseType"}{"Tid"}, $Type2_Pure{"BaseType"}{"Tid"}, $Level);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010476 foreach my $Sub_SubProblemType (keys(%Sub_SubProblems))
10477 {
10478 foreach my $Sub_SubLocation (keys(%{$Sub_SubProblems{$Sub_SubProblemType}}))
10479 {
10480 foreach my $Attr (keys(%{$Sub_SubProblems{$Sub_SubProblemType}{$Sub_SubLocation}})) {
10481 $SubProblems{$Sub_SubProblemType}{$Sub_SubLocation}{$Attr} = $Sub_SubProblems{$Sub_SubProblemType}{$Sub_SubLocation}{$Attr};
10482 }
10483 $SubProblems{$Sub_SubProblemType}{$Sub_SubLocation}{"InitialType_Type"} = $Type1_Pure{"Type"};
10484 }
10485 }
10486 }
10487 my (%AddedField, %RemovedField, %RenamedField, %RenamedField_Rev, %RelatedField, %RelatedField_Rev) = ();
10488 my %NameToPosA = map {$Type1_Pure{"Memb"}{$_}{"name"}=>$_} keys(%{$Type1_Pure{"Memb"}});
10489 my %NameToPosB = map {$Type2_Pure{"Memb"}{$_}{"name"}=>$_} keys(%{$Type2_Pure{"Memb"}});
10490 foreach my $Member_Pos (sort {int($a) <=> int($b)} keys(%{$Type1_Pure{"Memb"}}))
10491 { # detect removed and renamed fields
10492 my $Member_Name = $Type1_Pure{"Memb"}{$Member_Pos}{"name"};
10493 next if(not $Member_Name);
10494 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);
10495 if($MemberPair_Pos eq "lost")
10496 {
10497 if($Type2_Pure{"Type"}=~/\A(Struct|Class|Union)\Z/)
10498 {
10499 if(isUnnamed($Member_Name))
10500 { # support for old-version dumps
10501 # unnamed fields have been introduced in the ACC 1.23 (dump 2.1 format)
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040010502 if(not checkDump(2, "2.1")) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010503 next;
10504 }
10505 }
10506 if(my $RenamedTo = isRenamed($Member_Pos, \%Type1_Pure, 1, \%Type2_Pure, 2))
10507 { # renamed
10508 $RenamedField{$Member_Pos}=$RenamedTo;
10509 $RenamedField_Rev{$NameToPosB{$RenamedTo}}=$Member_Name;
10510 }
10511 else
10512 { # removed
10513 $RemovedField{$Member_Pos}=1;
10514 }
10515 }
10516 elsif($Type1_Pure{"Type"} eq "Enum")
10517 {
10518 my $Member_Value1 = $Type1_Pure{"Memb"}{$Member_Pos}{"value"};
10519 next if($Member_Value1 eq "");
10520 $MemberPair_Pos = find_MemberPair_Pos_byVal($Member_Value1, \%Type2_Pure);
10521 if($MemberPair_Pos ne "lost")
10522 { # renamed
10523 my $RenamedTo = $Type2_Pure{"Memb"}{$MemberPair_Pos}{"name"};
10524 my $MemberPair_Pos_Rev = find_MemberPair_Pos_byName($RenamedTo, \%Type1_Pure);
10525 if($MemberPair_Pos_Rev eq "lost")
10526 {
10527 $RenamedField{$Member_Pos}=$RenamedTo;
10528 $RenamedField_Rev{$NameToPosB{$RenamedTo}}=$Member_Name;
10529 }
10530 else {
10531 $RemovedField{$Member_Pos}=1;
10532 }
10533 }
10534 else
10535 { # removed
10536 $RemovedField{$Member_Pos}=1;
10537 }
10538 }
10539 }
10540 else
10541 { # related
10542 $RelatedField{$Member_Pos} = $MemberPair_Pos;
10543 $RelatedField_Rev{$MemberPair_Pos} = $Member_Pos;
10544 }
10545 }
10546 foreach my $Member_Pos (sort {int($a) <=> int($b)} keys(%{$Type2_Pure{"Memb"}}))
10547 { # detect added fields
10548 my $Member_Name = $Type2_Pure{"Memb"}{$Member_Pos}{"name"};
10549 next if(not $Member_Name);
10550 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);
10551 if($MemberPair_Pos eq "lost")
10552 {
10553 if(isUnnamed($Member_Name))
10554 { # support for old-version dumps
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040010555 # unnamed fields have been introduced in the ACC 1.23 (dump 2.1 format)
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040010556 if(not checkDump(1, "2.1")) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010557 next;
10558 }
10559 }
10560 if($Type2_Pure{"Type"}=~/\A(Struct|Class|Union|Enum)\Z/)
10561 {
10562 if(not $RenamedField_Rev{$Member_Pos})
10563 { # added
10564 $AddedField{$Member_Pos}=1;
10565 }
10566 }
10567 }
10568 }
10569 if($Type2_Pure{"Type"}=~/\A(Struct|Class)\Z/)
10570 { # detect moved fields
10571 my (%RelPos, %RelPosName, %AbsPos) = ();
10572 my $Pos = 0;
10573 foreach my $Member_Pos (sort {int($a) <=> int($b)} keys(%{$Type1_Pure{"Memb"}}))
10574 { # relative positions in 1st version
10575 my $Member_Name = $Type1_Pure{"Memb"}{$Member_Pos}{"name"};
10576 next if(not $Member_Name);
10577 if(not $RemovedField{$Member_Pos})
10578 { # old type without removed fields
10579 $RelPos{1}{$Member_Name}=$Pos;
10580 $RelPosName{1}{$Pos} = $Member_Name;
10581 $AbsPos{1}{$Pos++} = $Member_Pos;
10582 }
10583 }
10584 $Pos = 0;
10585 foreach my $Member_Pos (sort {int($a) <=> int($b)} keys(%{$Type2_Pure{"Memb"}}))
10586 { # relative positions in 2nd version
10587 my $Member_Name = $Type2_Pure{"Memb"}{$Member_Pos}{"name"};
10588 next if(not $Member_Name);
10589 if(not $AddedField{$Member_Pos})
10590 { # new type without added fields
10591 $RelPos{2}{$Member_Name}=$Pos;
10592 $RelPosName{2}{$Pos} = $Member_Name;
10593 $AbsPos{2}{$Pos++} = $Member_Pos;
10594 }
10595 }
10596 foreach my $Member_Name (keys(%{$RelPos{1}}))
10597 {
10598 my $RPos1 = $RelPos{1}{$Member_Name};
10599 my $AbsPos1 = $NameToPosA{$Member_Name};
10600 my $Member_Name2 = $Member_Name;
10601 if(my $RenamedTo = $RenamedField{$AbsPos1})
10602 { # renamed
10603 $Member_Name2 = $RenamedTo;
10604 }
10605 my $RPos2 = $RelPos{2}{$Member_Name2};
10606 if($RPos2 ne "" and $RPos1 ne $RPos2)
10607 { # different relative positions
10608 my $AbsPos2 = $NameToPosB{$Member_Name2};
10609 if($AbsPos1 ne $AbsPos2)
10610 { # different absolute positions
10611 my $ProblemType = "Moved_Field";
10612 if(not isPublic(\%Type1_Pure, $AbsPos1))
10613 { # may change layout and size of type
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040010614 if($Level eq "Source") {
10615 next;
10616 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010617 $ProblemType = "Moved_Private_Field";
10618 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040010619 if($Level eq "Binary"
10620 and $Type1_Pure{"Size"} ne $Type2_Pure{"Size"})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010621 { # affected size
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040010622 my $MemSize1 = $TypeInfo{1}{$Type1_Pure{"Memb"}{$AbsPos1}{"type"}}{"Size"};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010623 my $MovedAbsPos = $AbsPos{1}{$RPos2};
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040010624 my $MemSize2 = $TypeInfo{1}{$Type1_Pure{"Memb"}{$MovedAbsPos}{"type"}}{"Size"};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010625 if($MemSize1 ne $MemSize2) {
10626 $ProblemType .= "_And_Size";
10627 }
10628 }
10629 if($ProblemType eq "Moved_Private_Field") {
10630 next;
10631 }
10632 %{$SubProblems{$ProblemType}{$Member_Name}}=(
10633 "Target"=>$Member_Name,
10634 "Type_Name"=>$Type1_Pure{"Name"},
10635 "Type_Type"=>$Type1_Pure{"Type"},
10636 "Old_Value"=>$RPos1,
10637 "New_Value"=>$RPos2 );
10638 }
10639 }
10640 }
10641 }
10642 foreach my $Member_Pos (sort {int($a) <=> int($b)} keys(%{$Type1_Pure{"Memb"}}))
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040010643 { # check older fields, public and private
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010644 my $Member_Name = $Type1_Pure{"Memb"}{$Member_Pos}{"name"};
10645 next if(not $Member_Name);
10646 if(my $RenamedTo = $RenamedField{$Member_Pos})
10647 { # renamed
10648 if($Type2_Pure{"Type"}=~/\A(Struct|Class|Union)\Z/)
10649 {
10650 if(isPublic(\%Type1_Pure, $Member_Pos))
10651 {
10652 %{$SubProblems{"Renamed_Field"}{$Member_Name}}=(
10653 "Target"=>$Member_Name,
10654 "Type_Name"=>$Type1_Pure{"Name"},
10655 "Type_Type"=>$Type1_Pure{"Type"},
10656 "Old_Value"=>$Member_Name,
10657 "New_Value"=>$RenamedTo );
10658 }
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040010659 elsif(isReserved($Member_Name))
10660 {
10661 %{$SubProblems{"Used_Reserved_Field"}{$Member_Name}}=(
10662 "Target"=>$Member_Name,
10663 "Type_Name"=>$Type1_Pure{"Name"},
10664 "Type_Type"=>$Type1_Pure{"Type"},
10665 "Old_Value"=>$Member_Name,
10666 "New_Value"=>$RenamedTo );
10667 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010668 }
10669 elsif($Type1_Pure{"Type"} eq "Enum")
10670 {
10671 %{$SubProblems{"Enum_Member_Name"}{$Type1_Pure{"Memb"}{$Member_Pos}{"value"}}}=(
10672 "Target"=>$Type1_Pure{"Memb"}{$Member_Pos}{"value"},
10673 "Type_Name"=>$Type1_Pure{"Name"},
10674 "Type_Type"=>$Type1_Pure{"Type"},
10675 "Old_Value"=>$Member_Name,
10676 "New_Value"=>$RenamedTo );
10677 }
10678 }
10679 elsif($RemovedField{$Member_Pos})
10680 { # removed
10681 if($Type2_Pure{"Type"}=~/\A(Struct|Class)\Z/)
10682 {
10683 my $ProblemType = "Removed_Field";
10684 if(not isPublic(\%Type1_Pure, $Member_Pos)
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040010685 or isUnnamed($Member_Name))
10686 {
10687 if($Level eq "Source") {
10688 next;
10689 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010690 $ProblemType = "Removed_Private_Field";
10691 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040010692 if($Level eq "Binary"
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +040010693 and not isMemPadded($Member_Pos, -1, \%Type1_Pure, \%RemovedField, $TypeInfo{1}, $WORD_SIZE{1}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010694 {
10695 if(my $MNum = isAccessible(\%Type1_Pure, \%RemovedField, $Member_Pos+1, -1))
10696 { # affected fields
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +040010697 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 +040010698 { # changed offset
10699 $ProblemType .= "_And_Layout";
10700 }
10701 }
10702 if($Type1_Pure{"Size"} ne $Type2_Pure{"Size"})
10703 { # affected size
10704 $ProblemType .= "_And_Size";
10705 }
10706 }
10707 if($ProblemType eq "Removed_Private_Field") {
10708 next;
10709 }
10710 %{$SubProblems{$ProblemType}{$Member_Name}}=(
10711 "Target"=>$Member_Name,
10712 "Type_Name"=>$Type1_Pure{"Name"},
10713 "Type_Type"=>$Type1_Pure{"Type"} );
10714 }
10715 elsif($Type2_Pure{"Type"} eq "Union")
10716 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040010717 if($Level eq "Binary"
10718 and $Type1_Pure{"Size"} ne $Type2_Pure{"Size"})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010719 {
10720 %{$SubProblems{"Removed_Union_Field_And_Size"}{$Member_Name}}=(
10721 "Target"=>$Member_Name,
10722 "Type_Name"=>$Type1_Pure{"Name"},
10723 "Type_Type"=>$Type1_Pure{"Type"} );
10724 }
10725 else
10726 {
10727 %{$SubProblems{"Removed_Union_Field"}{$Member_Name}}=(
10728 "Target"=>$Member_Name,
10729 "Type_Name"=>$Type1_Pure{"Name"},
10730 "Type_Type"=>$Type1_Pure{"Type"} );
10731 }
10732 }
10733 elsif($Type1_Pure{"Type"} eq "Enum")
10734 {
10735 %{$SubProblems{"Enum_Member_Removed"}{$Member_Name}}=(
10736 "Target"=>$Member_Name,
10737 "Type_Name"=>$Type1_Pure{"Name"},
10738 "Type_Type"=>$Type1_Pure{"Type"},
10739 "Old_Value"=>$Member_Name );
10740 }
10741 }
10742 else
10743 { # changed
10744 my $MemberPair_Pos = $RelatedField{$Member_Pos};
10745 if($Type1_Pure{"Type"} eq "Enum")
10746 {
10747 my $Member_Value1 = $Type1_Pure{"Memb"}{$Member_Pos}{"value"};
10748 next if($Member_Value1 eq "");
10749 my $Member_Value2 = $Type2_Pure{"Memb"}{$MemberPair_Pos}{"value"};
10750 next if($Member_Value2 eq "");
10751 if($Member_Value1 ne $Member_Value2)
10752 {
10753 my $ProblemType = "Enum_Member_Value";
10754 if(isLastElem($Member_Pos, \%Type1_Pure)) {
10755 $ProblemType = "Enum_Last_Member_Value";
10756 }
10757 %{$SubProblems{$ProblemType}{$Member_Name}}=(
10758 "Target"=>$Member_Name,
10759 "Type_Name"=>$Type1_Pure{"Name"},
10760 "Type_Type"=>$Type1_Pure{"Type"},
10761 "Old_Value"=>$Member_Value1,
10762 "New_Value"=>$Member_Value2 );
10763 }
10764 }
10765 elsif($Type2_Pure{"Type"}=~/\A(Struct|Class|Union)\Z/)
10766 {
10767 my $MemberType1_Id = $Type1_Pure{"Memb"}{$Member_Pos}{"type"};
10768 my $MemberType2_Id = $Type2_Pure{"Memb"}{$MemberPair_Pos}{"type"};
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040010769 my $SizeV1 = $TypeInfo{1}{$MemberType1_Id}{"Size"}*$BYTE_SIZE;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010770 if(my $BSize1 = $Type1_Pure{"Memb"}{$Member_Pos}{"bitfield"}) {
10771 $SizeV1 = $BSize1;
10772 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040010773 my $SizeV2 = $TypeInfo{2}{$MemberType2_Id}{"Size"}*$BYTE_SIZE;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010774 if(my $BSize2 = $Type2_Pure{"Memb"}{$MemberPair_Pos}{"bitfield"}) {
10775 $SizeV2 = $BSize2;
10776 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040010777 my $MemberType1_Name = $TypeInfo{1}{$MemberType1_Id}{"Name"};
10778 my $MemberType2_Name = $TypeInfo{2}{$MemberType2_Id}{"Name"};
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040010779 if($Level eq "Binary"
10780 and $SizeV1 ne $SizeV2)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010781 {
10782 if($MemberType1_Name eq $MemberType2_Name or (isAnon($MemberType1_Name) and isAnon($MemberType2_Name))
10783 or ($Type1_Pure{"Memb"}{$Member_Pos}{"bitfield"} and $Type2_Pure{"Memb"}{$MemberPair_Pos}{"bitfield"}))
10784 { # field size change (including anon-structures and unions)
10785 # - same types
10786 # - unnamed types
10787 # - bitfields
10788 my $ProblemType = "Field_Size";
10789 if(not isPublic(\%Type1_Pure, $Member_Pos)
10790 or isUnnamed($Member_Name))
10791 { # should not be accessed by applications, goes to "Low Severity"
10792 # example: "abidata" members in GStreamer types
10793 $ProblemType = "Private_".$ProblemType;
10794 }
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +040010795 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 +040010796 { # check an effect
10797 if(my $MNum = isAccessible(\%Type1_Pure, \%RemovedField, $Member_Pos+1, -1))
10798 { # public fields after the current
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +040010799 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 +040010800 { # changed offset
10801 $ProblemType .= "_And_Layout";
10802 }
10803 }
10804 if($Type1_Pure{"Size"} ne $Type2_Pure{"Size"}) {
10805 $ProblemType .= "_And_Type_Size";
10806 }
10807 }
10808 if($ProblemType eq "Private_Field_Size")
10809 { # private field size with no effect
10810 $ProblemType = "";
10811 }
10812 if($ProblemType)
10813 { # register a problem
10814 %{$SubProblems{$ProblemType}{$Member_Name}}=(
10815 "Target"=>$Member_Name,
10816 "Type_Name"=>$Type1_Pure{"Name"},
10817 "Type_Type"=>$Type1_Pure{"Type"},
10818 "Old_Size"=>$SizeV1,
10819 "New_Size"=>$SizeV2);
10820 }
10821 }
10822 }
10823 if($Type1_Pure{"Memb"}{$Member_Pos}{"bitfield"}
10824 or $Type2_Pure{"Memb"}{$MemberPair_Pos}{"bitfield"})
10825 { # do NOT check bitfield type changes
10826 next;
10827 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040010828 if(checkDump(1, "2.13") and checkDump(2, "2.13"))
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040010829 {
10830 if(not $Type1_Pure{"Memb"}{$Member_Pos}{"mutable"}
10831 and $Type2_Pure{"Memb"}{$MemberPair_Pos}{"mutable"})
10832 {
10833 %{$SubProblems{"Field_Became_Mutable"}{$Member_Name}}=(
10834 "Target"=>$Member_Name,
10835 "Type_Name"=>$Type1_Pure{"Name"},
10836 "Type_Type"=>$Type1_Pure{"Type"});
10837 }
10838 elsif($Type1_Pure{"Memb"}{$Member_Pos}{"mutable"}
10839 and not $Type2_Pure{"Memb"}{$MemberPair_Pos}{"mutable"})
10840 {
10841 %{$SubProblems{"Field_Became_NonMutable"}{$Member_Name}}=(
10842 "Target"=>$Member_Name,
10843 "Type_Name"=>$Type1_Pure{"Name"},
10844 "Type_Type"=>$Type1_Pure{"Type"});
10845 }
10846 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040010847 %Sub_SubProblems = detectTypeChange($MemberType1_Id, $MemberType2_Id, "Field", $Level);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010848 foreach my $ProblemType (keys(%Sub_SubProblems))
10849 {
10850 my $Old_Value = $Sub_SubProblems{$ProblemType}{"Old_Value"};
10851 my $New_Value = $Sub_SubProblems{$ProblemType}{"New_Value"};
10852 if($ProblemType eq "Field_Type"
10853 or $ProblemType eq "Field_Type_And_Size")
10854 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040010855 if(checkDump(1, "2.6") and checkDump(2, "2.6"))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010856 {
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040010857 if(my $RA = addedQual($Old_Value, $New_Value, "volatile"))
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040010858 {
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040010859 %{$Sub_SubProblems{"Field_Became_Volatile"}} = %{$Sub_SubProblems{$ProblemType}};
10860 if($Level eq "Source"
10861 and cmpBTypes($Old_Value, $New_Value, 1, 2)) {
10862 delete($Sub_SubProblems{$ProblemType});
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040010863 }
10864 }
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040010865 elsif(my $RR = removedQual($Old_Value, $New_Value, "volatile"))
10866 {
10867 %{$Sub_SubProblems{"Field_Became_NonVolatile"}} = %{$Sub_SubProblems{$ProblemType}};
10868 if($Level eq "Source"
10869 and cmpBTypes($Old_Value, $New_Value, 1, 2)) {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040010870 delete($Sub_SubProblems{$ProblemType});
10871 }
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040010872 }
10873 }
10874 if(my $RA = addedQual($Old_Value, $New_Value, "const"))
10875 {
10876 if($RA==2) {
10877 %{$Sub_SubProblems{"Field_Added_Const"}} = %{$Sub_SubProblems{$ProblemType}};
10878 }
10879 else {
10880 %{$Sub_SubProblems{"Field_Became_Const"}} = %{$Sub_SubProblems{$ProblemType}};
10881 }
10882 if($Level eq "Source"
10883 and cmpBTypes($Old_Value, $New_Value, 1, 2)) {
10884 delete($Sub_SubProblems{$ProblemType});
10885 }
10886 }
10887 elsif(my $RR = removedQual($Old_Value, $New_Value, "const"))
10888 {
10889 if($RR==2) {
10890 %{$Sub_SubProblems{"Field_Removed_Const"}} = %{$Sub_SubProblems{$ProblemType}};
10891 }
10892 else {
10893 %{$Sub_SubProblems{"Field_Became_NonConst"}} = %{$Sub_SubProblems{$ProblemType}};
10894 }
10895 if($Level eq "Source"
10896 and cmpBTypes($Old_Value, $New_Value, 1, 2)) {
10897 delete($Sub_SubProblems{$ProblemType});
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010898 }
10899 }
10900 }
10901 }
10902 foreach my $ProblemType (keys(%Sub_SubProblems))
10903 {
10904 my $ProblemType_Init = $ProblemType;
10905 if($ProblemType eq "Field_Type_And_Size")
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040010906 { # Binary
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010907 if(not isPublic(\%Type1_Pure, $Member_Pos)
10908 or isUnnamed($Member_Name)) {
10909 $ProblemType = "Private_".$ProblemType;
10910 }
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +040010911 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 +040010912 { # check an effect
10913 if(my $MNum = isAccessible(\%Type1_Pure, \%RemovedField, $Member_Pos+1, -1))
10914 { # public fields after the current
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +040010915 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 +040010916 { # changed offset
10917 $ProblemType .= "_And_Layout";
10918 }
10919 }
10920 if($Type1_Pure{"Size"} ne $Type2_Pure{"Size"}) {
10921 $ProblemType .= "_And_Type_Size";
10922 }
10923 }
10924 }
10925 else
10926 {
10927 if(not isPublic(\%Type1_Pure, $Member_Pos)
10928 or isUnnamed($Member_Name)) {
10929 next;
10930 }
10931 }
10932 if($ProblemType eq "Private_Field_Type_And_Size")
10933 { # private field change with no effect
10934 next;
10935 }
10936 %{$SubProblems{$ProblemType}{$Member_Name}}=(
10937 "Target"=>$Member_Name,
10938 "Type_Name"=>$Type1_Pure{"Name"},
10939 "Type_Type"=>$Type1_Pure{"Type"} );
10940 foreach my $Attr (keys(%{$Sub_SubProblems{$ProblemType_Init}}))
10941 { # other properties
10942 $SubProblems{$ProblemType}{$Member_Name}{$Attr} = $Sub_SubProblems{$ProblemType_Init}{$Attr};
10943 }
10944 }
10945 if(not isPublic(\%Type1_Pure, $Member_Pos))
10946 { # do NOT check internal type changes
10947 next;
10948 }
10949 if($MemberType1_Id and $MemberType2_Id)
10950 {# checking member type changes (replace)
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040010951 %Sub_SubProblems = mergeTypes($MemberType1_Id, $MemberType2_Id, $Level);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010952 foreach my $Sub_SubProblemType (keys(%Sub_SubProblems))
10953 {
10954 foreach my $Sub_SubLocation (keys(%{$Sub_SubProblems{$Sub_SubProblemType}}))
10955 {
10956 my $NewLocation = ($Sub_SubLocation)?$Member_Name."->".$Sub_SubLocation:$Member_Name;
10957 $SubProblems{$Sub_SubProblemType}{$NewLocation}{"IsInTypeInternals"}=1;
10958 foreach my $Attr (keys(%{$Sub_SubProblems{$Sub_SubProblemType}{$Sub_SubLocation}})) {
10959 $SubProblems{$Sub_SubProblemType}{$NewLocation}{$Attr} = $Sub_SubProblems{$Sub_SubProblemType}{$Sub_SubLocation}{$Attr};
10960 }
10961 if($Sub_SubLocation!~/\-\>/) {
10962 $SubProblems{$Sub_SubProblemType}{$NewLocation}{"Start_Type_Name"} = $MemberType1_Name;
10963 }
10964 }
10965 }
10966 }
10967 }
10968 }
10969 }
10970 foreach my $Member_Pos (sort {int($a) <=> int($b)} keys(%{$Type2_Pure{"Memb"}}))
10971 { # checking added members, public and private
10972 my $Member_Name = $Type2_Pure{"Memb"}{$Member_Pos}{"name"};
10973 next if(not $Member_Name);
10974 if($AddedField{$Member_Pos})
10975 { # added
10976 if($Type2_Pure{"Type"}=~/\A(Struct|Class)\Z/)
10977 {
10978 my $ProblemType = "Added_Field";
10979 if(not isPublic(\%Type2_Pure, $Member_Pos)
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040010980 or isUnnamed($Member_Name))
10981 {
10982 if($Level eq "Source") {
10983 next;
10984 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010985 $ProblemType = "Added_Private_Field";
10986 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040010987 if($Level eq "Binary"
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +040010988 and not isMemPadded($Member_Pos, -1, \%Type2_Pure, \%AddedField, $TypeInfo{2}, $WORD_SIZE{2}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010989 {
10990 if(my $MNum = isAccessible(\%Type2_Pure, \%AddedField, $Member_Pos, -1))
10991 { # public fields after the current
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +040010992 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 +040010993 { # changed offset
10994 $ProblemType .= "_And_Layout";
10995 }
10996 }
10997 if($Type1_Pure{"Size"} ne $Type2_Pure{"Size"}) {
10998 $ProblemType .= "_And_Size";
10999 }
11000 }
11001 if($ProblemType eq "Added_Private_Field")
11002 { # skip added private fields
11003 next;
11004 }
11005 %{$SubProblems{$ProblemType}{$Member_Name}}=(
11006 "Target"=>$Member_Name,
11007 "Type_Name"=>$Type1_Pure{"Name"},
11008 "Type_Type"=>$Type1_Pure{"Type"} );
11009 }
11010 elsif($Type2_Pure{"Type"} eq "Union")
11011 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011012 if($Level eq "Binary"
11013 and $Type1_Pure{"Size"} ne $Type2_Pure{"Size"})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011014 {
11015 %{$SubProblems{"Added_Union_Field_And_Size"}{$Member_Name}}=(
11016 "Target"=>$Member_Name,
11017 "Type_Name"=>$Type1_Pure{"Name"},
11018 "Type_Type"=>$Type1_Pure{"Type"} );
11019 }
11020 else
11021 {
11022 %{$SubProblems{"Added_Union_Field"}{$Member_Name}}=(
11023 "Target"=>$Member_Name,
11024 "Type_Name"=>$Type1_Pure{"Name"},
11025 "Type_Type"=>$Type1_Pure{"Type"} );
11026 }
11027 }
11028 elsif($Type2_Pure{"Type"} eq "Enum")
11029 {
11030 my $Member_Value = $Type2_Pure{"Memb"}{$Member_Pos}{"value"};
11031 next if($Member_Value eq "");
11032 %{$SubProblems{"Added_Enum_Member"}{$Member_Name}}=(
11033 "Target"=>$Member_Name,
11034 "Type_Name"=>$Type2_Pure{"Name"},
11035 "Type_Type"=>$Type2_Pure{"Type"},
11036 "New_Value"=>$Member_Value );
11037 }
11038 }
11039 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040011040 %{$Cache{"mergeTypes"}{$Level}{$Type1_Id}{$Type2_Id}} = %SubProblems;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011041 pop(@RecurTypes);
11042 return %SubProblems;
11043}
11044
11045sub isUnnamed($) {
11046 return $_[0]=~/\Aunnamed\d+\Z/;
11047}
11048
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040011049sub get_ShortType($$)
11050{
11051 my ($TypeId, $LibVersion) = @_;
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +040011052 my $TypeName = uncover_typedefs($TypeInfo{$LibVersion}{$TypeId}{"Name"}, $LibVersion);
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040011053 if(my $NameSpace = $TypeInfo{$LibVersion}{$TypeId}{"NameSpace"}) {
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040011054 $TypeName=~s/\A$NameSpace\:\://g;
11055 }
11056 return $TypeName;
11057}
11058
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040011059sub goToFirst($$$)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011060{
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040011061 my ($TypeId, $LibVersion, $Type_Type) = @_;
Andrey Ponomarenko16934472012-03-29 15:37:04 +040011062 return () if(not $TypeId);
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040011063 if(defined $Cache{"goToFirst"}{$TypeId}{$LibVersion}{$Type_Type}) {
11064 return %{$Cache{"goToFirst"}{$TypeId}{$LibVersion}{$Type_Type}};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011065 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040011066 return () if(not $TypeInfo{$LibVersion}{$TypeId});
11067 my %Type = %{$TypeInfo{$LibVersion}{$TypeId}};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011068 return () if(not $Type{"Type"});
11069 if($Type{"Type"} ne $Type_Type)
11070 {
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040011071 return () if(not defined $Type{"BaseType"});
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040011072 return () if(not $Type{"BaseType"}{"Tid"});
11073 %Type = goToFirst($Type{"BaseType"}{"Tid"}, $LibVersion, $Type_Type);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011074 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040011075 $Cache{"goToFirst"}{$TypeId}{$LibVersion}{$Type_Type} = \%Type;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011076 return %Type;
11077}
11078
11079my %TypeSpecAttributes = (
11080 "Const" => 1,
11081 "Volatile" => 1,
11082 "ConstVolatile" => 1,
11083 "Restrict" => 1,
11084 "Typedef" => 1
11085);
11086
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040011087sub get_PureType($$)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011088{
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +040011089 my ($TypeId, $Info) = @_;
11090 if(not $TypeId or not $Info
11091 or not $Info->{$TypeId}) {
11092 return ();
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011093 }
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +040011094 if(defined $Cache{"get_PureType"}{$TypeId}{$Info}) {
11095 return %{$Cache{"get_PureType"}{$TypeId}{$Info}};
11096 }
11097 my %Type = %{$Info->{$TypeId}};
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040011098 return %Type if(not defined $Type{"BaseType"});
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040011099 return %Type if(not $Type{"BaseType"}{"Tid"});
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011100 if($TypeSpecAttributes{$Type{"Type"}}) {
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +040011101 %Type = get_PureType($Type{"BaseType"}{"Tid"}, $Info);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011102 }
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +040011103 $Cache{"get_PureType"}{$TypeId}{$Info} = \%Type;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011104 return %Type;
11105}
11106
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040011107sub get_PLevel($$)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011108{
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040011109 my ($TypeId, $LibVersion) = @_;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011110 return 0 if(not $TypeId);
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040011111 if(defined $Cache{"get_PLevel"}{$TypeId}{$LibVersion}) {
11112 return $Cache{"get_PLevel"}{$TypeId}{$LibVersion};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011113 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040011114 return 0 if(not $TypeInfo{$LibVersion}{$TypeId});
11115 my %Type = %{$TypeInfo{$LibVersion}{$TypeId}};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011116 return 1 if($Type{"Type"}=~/FuncPtr|MethodPtr|FieldPtr/);
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040011117 return 0 if(not defined $Type{"BaseType"});
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040011118 return 0 if(not $Type{"BaseType"}{"Tid"});
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011119 my $PointerLevel = 0;
11120 if($Type{"Type"} =~/Pointer|Ref|FuncPtr|MethodPtr|FieldPtr/) {
11121 $PointerLevel += 1;
11122 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040011123 $PointerLevel += get_PLevel($Type{"BaseType"}{"Tid"}, $LibVersion);
11124 $Cache{"get_PLevel"}{$TypeId}{$LibVersion} = $PointerLevel;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011125 return $PointerLevel;
11126}
11127
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040011128sub get_BaseType($$)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011129{
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040011130 my ($TypeId, $LibVersion) = @_;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011131 return () if(not $TypeId);
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040011132 if(defined $Cache{"get_BaseType"}{$TypeId}{$LibVersion}) {
11133 return %{$Cache{"get_BaseType"}{$TypeId}{$LibVersion}};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011134 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040011135 return () if(not $TypeInfo{$LibVersion}{$TypeId});
11136 my %Type = %{$TypeInfo{$LibVersion}{$TypeId}};
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040011137 return %Type if(not defined $Type{"BaseType"});
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040011138 return %Type if(not $Type{"BaseType"}{"Tid"});
11139 %Type = get_BaseType($Type{"BaseType"}{"Tid"}, $LibVersion);
11140 $Cache{"get_BaseType"}{$TypeId}{$LibVersion} = \%Type;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011141 return %Type;
11142}
11143
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040011144sub get_BaseTypeQual($$)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011145{
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040011146 my ($TypeId, $LibVersion) = @_;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011147 return "" if(not $TypeId);
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040011148 return "" if(not $TypeInfo{$LibVersion}{$TypeId});
11149 my %Type = %{$TypeInfo{$LibVersion}{$TypeId}};
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040011150 return "" if(not defined $Type{"BaseType"});
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040011151 return "" if(not $Type{"BaseType"}{"Tid"});
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011152 my $Qual = "";
11153 if($Type{"Type"} eq "Pointer") {
11154 $Qual .= "*";
11155 }
11156 elsif($Type{"Type"} eq "Ref") {
11157 $Qual .= "&";
11158 }
11159 elsif($Type{"Type"} eq "ConstVolatile") {
11160 $Qual .= "const volatile";
11161 }
11162 elsif($Type{"Type"} eq "Const"
11163 or $Type{"Type"} eq "Volatile"
11164 or $Type{"Type"} eq "Restrict") {
11165 $Qual .= lc($Type{"Type"});
11166 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040011167 my $BQual = get_BaseTypeQual($Type{"BaseType"}{"Tid"}, $LibVersion);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011168 return $BQual.$Qual;
11169}
11170
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040011171sub get_OneStep_BaseType($$)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011172{
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +040011173 my ($TypeId, $Info) = @_;
11174 if(not $TypeId or not $Info
11175 or not $Info->{$TypeId}) {
11176 return ();
11177 }
11178 my %Type = %{$Info->{$TypeId}};
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040011179 return %Type if(not defined $Type{"BaseType"});
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +040011180 if(my $BTid = $Type{"BaseType"}{"Tid"})
11181 {
11182 if($Info->{$BTid}) {
11183 return %{$Info->{$BTid}};
11184 }
11185 else { # something is going wrong
11186 return ();
11187 }
11188 }
11189 else {
11190 return %Type;
11191 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011192}
11193
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040011194sub get_Type($$)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011195{
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040011196 my ($TypeId, $LibVersion) = @_;
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040011197 return () if(not $TypeId);
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040011198 return () if(not $TypeInfo{$LibVersion}{$TypeId});
11199 return %{$TypeInfo{$LibVersion}{$TypeId}};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011200}
11201
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +040011202sub isPrivateData($)
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040011203{ # non-public global data
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011204 my $Symbol = $_[0];
11205 return ($Symbol=~/\A(_ZGV|_ZTI|_ZTS|_ZTT|_ZTV|_ZTC|_ZThn|_ZTv0_n)/);
11206}
11207
Andrey Ponomarenko01117f12012-06-26 12:23:02 +040011208sub isInLineInst($$$) {
11209 return (isTemplateInstance(@_) and not isTemplateSpec(@_));
11210}
11211
11212sub isTemplateInstance($$$)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011213{
Andrey Ponomarenko01117f12012-06-26 12:23:02 +040011214 my ($Symbol, $SInfo, $LibVersion) = @_;
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040011215 if($CheckObjectsOnly)
11216 {
11217 if($Symbol!~/\A(_Z|\?)/) {
11218 return 0;
11219 }
11220 if(my $Signature = $tr_name{$Symbol})
11221 {
11222 if(index($Signature,">")==-1) {
11223 return 0;
11224 }
11225 if(my $ShortName = substr($Signature, 0, find_center($Signature, "(")))
11226 {
Andrey Ponomarenko01117f12012-06-26 12:23:02 +040011227 if(index($ShortName,"<")!=-1
11228 and index($ShortName,">")!=-1) {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040011229 return 1;
11230 }
11231 }
11232 }
11233 }
11234 else
11235 {
Andrey Ponomarenko01117f12012-06-26 12:23:02 +040011236 if(my $ClassId = $SInfo->{"Class"})
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040011237 {
11238 if(my $ClassName = $TypeInfo{$LibVersion}{$ClassId}{"Name"})
11239 {
11240 if(index($ClassName,"<")!=-1) {
11241 return 1;
11242 }
11243 }
11244 }
Andrey Ponomarenko01117f12012-06-26 12:23:02 +040011245 if(my $ShortName = $SInfo->{"ShortName"})
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040011246 {
Andrey Ponomarenko01117f12012-06-26 12:23:02 +040011247 if(index($ShortName,"<")!=-1
11248 and index($ShortName,">")!=-1) {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040011249 return 1;
11250 }
11251 }
11252 }
11253 return 0;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011254}
11255
Andrey Ponomarenko01117f12012-06-26 12:23:02 +040011256sub isTemplateSpec($$$)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011257{
Andrey Ponomarenko01117f12012-06-26 12:23:02 +040011258 my ($Symbol, $SInfo, $LibVersion) = @_;
11259 if(my $ClassId = $SInfo->{"Class"})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011260 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040011261 if($TypeInfo{$LibVersion}{$ClassId}{"Spec"})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011262 { # class specialization
11263 return 1;
11264 }
Andrey Ponomarenko01117f12012-06-26 12:23:02 +040011265 elsif($SInfo->{"Spec"})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011266 { # method specialization
11267 return 1;
11268 }
11269 }
11270 return 0;
11271}
11272
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011273sub symbolFilter($$$$)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011274{ # some special cases when the symbol cannot be imported
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011275 my ($Symbol, $LibVersion, $Type, $Level) = @_;
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +040011276 if(isPrivateData($Symbol))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011277 { # non-public global data
11278 return 0;
11279 }
11280 if($CheckObjectsOnly) {
11281 return 0 if($Symbol=~/\A(_init|_fini)\Z/);
11282 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040011283 if($CheckHeadersOnly and not checkDump($LibVersion, "2.7"))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011284 { # support for old ABI dumps in --headers-only mode
11285 foreach my $Pos (keys(%{$CompleteSignature{$LibVersion}{$Symbol}{"Param"}}))
11286 {
11287 if(my $Pid = $CompleteSignature{$LibVersion}{$Symbol}{"Param"}{$Pos}{"type"})
11288 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040011289 my $PType = $TypeInfo{$LibVersion}{$Pid}{"Type"};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011290 if(not $PType or $PType eq "Unknown") {
11291 return 0;
11292 }
11293 }
11294 }
11295 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +040011296 if($Type=~/Affected/)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011297 {
11298 my $ClassId = $CompleteSignature{$LibVersion}{$Symbol}{"Class"};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011299 if($SkipSymbols{$LibVersion}{$Symbol})
11300 { # user defined symbols to ignore
11301 return 0;
11302 }
11303 my $NameSpace = $CompleteSignature{$LibVersion}{$Symbol}{"NameSpace"};
11304 if(not $NameSpace and $ClassId)
11305 { # class methods have no "NameSpace" attribute
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040011306 $NameSpace = $TypeInfo{$LibVersion}{$ClassId}{"NameSpace"};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011307 }
11308 if($NameSpace)
11309 { # user defined namespaces to ignore
11310 if($SkipNameSpaces{$LibVersion}{$NameSpace}) {
11311 return 0;
11312 }
11313 foreach my $NS (keys(%{$SkipNameSpaces{$LibVersion}}))
11314 { # nested namespaces
11315 if($NameSpace=~/\A\Q$NS\E(\:\:|\Z)/) {
11316 return 0;
11317 }
11318 }
11319 }
11320 if(my $Header = $CompleteSignature{$LibVersion}{$Symbol}{"Header"})
11321 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040011322 if(my $Skip = skipHeader($Header, $LibVersion))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011323 { # --skip-headers or <skip_headers> (not <skip_including>)
11324 if($Skip==1) {
11325 return 0;
11326 }
11327 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011328 }
11329 if($SymbolsListPath and not $SymbolsList{$Symbol})
11330 { # user defined symbols
11331 return 0;
11332 }
11333 if($AppPath and not $SymbolsList_App{$Symbol})
11334 { # user defined symbols (in application)
11335 return 0;
11336 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +040011337 if(not selectSymbol($Symbol, $CompleteSignature{$LibVersion}{$Symbol}, $Level, $LibVersion))
11338 { # non-target symbols
11339 return 0;
11340 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011341 if($Level eq "Binary")
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011342 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040011343 if($CheckObjectsOnly)
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011344 {
Andrey Ponomarenko01117f12012-06-26 12:23:02 +040011345 if(isTemplateInstance($Symbol, $CompleteSignature{$LibVersion}{$Symbol}, $LibVersion)) {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040011346 return 0;
11347 }
11348 }
11349 else
11350 {
11351 if($CompleteSignature{$LibVersion}{$Symbol}{"InLine"}
Andrey Ponomarenko01117f12012-06-26 12:23:02 +040011352 or isInLineInst($Symbol, $CompleteSignature{$LibVersion}{$Symbol}, $LibVersion))
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040011353 {
11354 if($ClassId and $CompleteSignature{$LibVersion}{$Symbol}{"Virt"})
11355 { # inline virtual methods
11356 if($Type=~/InlineVirt/) {
11357 return 1;
11358 }
11359 my $Allocable = (not isCopyingClass($ClassId, $LibVersion));
11360 if(not $Allocable)
11361 { # check bases
11362 foreach my $DCId (get_sub_classes($ClassId, $LibVersion, 1))
11363 {
11364 if(not isCopyingClass($DCId, $LibVersion))
11365 { # exists a derived class without default c-tor
11366 $Allocable=1;
11367 last;
11368 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011369 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011370 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040011371 if(not $Allocable) {
11372 return 0;
11373 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011374 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040011375 else
11376 { # inline non-virtual methods
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011377 return 0;
11378 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011379 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011380 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011381 }
11382 }
11383 return 1;
11384}
11385
11386sub mergeImpl()
11387{
11388 my $DiffCmd = get_CmdPath("diff");
11389 if(not $DiffCmd) {
11390 exitStatus("Not_Found", "can't find \"diff\"");
11391 }
11392 foreach my $Interface (sort keys(%{$Symbol_Library{1}}))
11393 { # implementation changes
11394 next if($CompleteSignature{1}{$Interface}{"Private"});
11395 next if(not $CompleteSignature{1}{$Interface}{"Header"} and not $CheckObjectsOnly);
11396 next if(not $Symbol_Library{2}{$Interface} and not $Symbol_Library{2}{$SymVer{2}{$Interface}});
Andrey Ponomarenko85043792012-05-14 16:48:07 +040011397 if(not symbolFilter($Interface, 1, "Affected", "Binary")) {
11398 next;
11399 }
Andrey Ponomarenko16934472012-03-29 15:37:04 +040011400 my $Impl1 = canonifyImpl($Interface_Impl{1}{$Interface});
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011401 next if(not $Impl1);
Andrey Ponomarenko16934472012-03-29 15:37:04 +040011402 my $Impl2 = canonifyImpl($Interface_Impl{2}{$Interface});
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011403 next if(not $Impl2);
11404 if($Impl1 ne $Impl2)
11405 {
11406 writeFile("$TMP_DIR/impl1", $Impl1);
11407 writeFile("$TMP_DIR/impl2", $Impl2);
Andrey Ponomarenkoa01311b2012-06-08 17:20:02 +040011408 my $Diff = `$DiffCmd -rNau \"$TMP_DIR/impl1\" \"$TMP_DIR/impl2\"`;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011409 $Diff=~s/(---|\+\+\+).+\n//g;
11410 $Diff=~s/[ ]{3,}/ /g;
11411 $Diff=~s/\n\@\@/\n \n\@\@/g;
Andrey Ponomarenkoa01311b2012-06-08 17:20:02 +040011412 unlink("$TMP_DIR/impl1");
11413 unlink("$TMP_DIR/impl2");
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011414 %{$ImplProblems{$Interface}}=(
11415 "Diff" => get_CodeView($Diff) );
11416 }
11417 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +040011418
11419 # clean memory
11420 %Interface_Impl = ();
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011421}
11422
Andrey Ponomarenko16934472012-03-29 15:37:04 +040011423sub canonifyImpl($)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011424{
11425 my $FuncBody= $_[0];
11426 return "" if(not $FuncBody);
11427 $FuncBody=~s/0x[a-f\d]+/0x?/g;# addr
11428 $FuncBody=~s/((\A|\n)[a-z]+[\t ]+)[a-f\d]+([^x]|\Z)/$1?$3/g;# call, jump
11429 $FuncBody=~s/# [a-f\d]+ /# ? /g;# call, jump
11430 $FuncBody=~s/%([a-z]+[a-f\d]*)/\%reg/g;# registers
11431 while($FuncBody=~s/\nnop[ \t]*(\n|\Z)/$1/g){};# empty op
11432 $FuncBody=~s/<.+?\.cpp.+?>/<name.cpp>/g;
11433 $FuncBody=~s/(\A|\n)[a-f\d]+ </$1? </g;# 5e74 <_ZN...
11434 $FuncBody=~s/\.L\d+/.L/g;
11435 $FuncBody=~s/#(-?)\d+/#$1?/g;# r3, [r3, #120]
11436 $FuncBody=~s/[\n]{2,}/\n/g;
11437 return $FuncBody;
11438}
11439
11440sub get_CodeView($)
11441{
11442 my $Code = $_[0];
11443 my $View = "";
11444 foreach my $Line (split(/\n/, $Code))
11445 {
11446 if($Line=~s/\A(\+|-)/$1 /g)
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040011447 { # bold line
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011448 $View .= "<tr><td><b>".htmlSpecChars($Line)."</b></td></tr>\n";
11449 }
11450 else {
11451 $View .= "<tr><td>".htmlSpecChars($Line)."</td></tr>\n";
11452 }
11453 }
11454 return "<table class='code_view'>$View</table>\n";
11455}
11456
11457sub getImplementations($$)
11458{
11459 my ($LibVersion, $Path) = @_;
11460 return if(not $LibVersion or not -e $Path);
11461 if($OSgroup eq "macos")
11462 {
11463 my $OtoolCmd = get_CmdPath("otool");
11464 if(not $OtoolCmd) {
11465 exitStatus("Not_Found", "can't find \"otool\"");
11466 }
11467 my $CurInterface = "";
Andrey Ponomarenkoa01311b2012-06-08 17:20:02 +040011468 foreach my $Line (split(/\n/, `$OtoolCmd -tv \"$Path\" 2>\"$TMP_DIR/null\"`))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011469 {
11470 if($Line=~/\A\s*_(\w+)\s*:/i) {
11471 $CurInterface = $1;
11472 }
11473 elsif($Line=~/\A\s*[\da-z]+\s+(.+?)\Z/i) {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040011474 $Interface_Impl{$LibVersion}{$CurInterface} .= $1."\n";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011475 }
11476 }
11477 }
11478 else
11479 {
11480 my $ObjdumpCmd = get_CmdPath("objdump");
11481 if(not $ObjdumpCmd) {
11482 exitStatus("Not_Found", "can't find \"objdump\"");
11483 }
11484 my $CurInterface = "";
Andrey Ponomarenkoa01311b2012-06-08 17:20:02 +040011485 foreach my $Line (split(/\n/, `$ObjdumpCmd -d \"$Path\" 2>\"$TMP_DIR/null\"`))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011486 {
11487 if($Line=~/\A[\da-z]+\s+<(\w+)>/i) {
11488 $CurInterface = $1;
11489 }
11490 else
11491 { # x86: 51fa:(\t)89 e5 (\t)mov %esp,%ebp
11492 # arm: 5020:(\t)e24cb004(\t)sub(\t)fp, ip, #4(\t); 0x4
11493 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 +040011494 $Interface_Impl{$LibVersion}{$CurInterface} .= $2."\n";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011495 }
11496 }
11497 }
11498 }
11499}
11500
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011501sub detectAdded($)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011502{
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011503 my $Level = $_[0];
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011504 foreach my $Symbol (keys(%{$Symbol_Library{2}}))
11505 {
11506 if(link_symbol($Symbol, 1, "+Deps"))
11507 { # linker can find a new symbol
11508 # in the old-version library
11509 # So, it's not a new symbol
11510 next;
11511 }
11512 if(my $VSym = $SymVer{2}{$Symbol}
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040011513 and index($Symbol,"\@")==-1) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011514 next;
11515 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011516 $AddedInt{$Level}{$Symbol} = 1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011517 }
11518}
11519
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011520sub detectRemoved($)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011521{
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011522 my $Level = $_[0];
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011523 foreach my $Symbol (keys(%{$Symbol_Library{1}}))
11524 {
11525 if($CheckObjectsOnly) {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011526 $CheckedSymbols{"Binary"}{$Symbol} = 1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011527 }
11528 if(link_symbol($Symbol, 2, "+Deps"))
11529 { # linker can find an old symbol
11530 # in the new-version library
11531 next;
11532 }
11533 if(my $VSym = $SymVer{1}{$Symbol}
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040011534 and index($Symbol,"\@")==-1) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011535 next;
11536 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011537 $RemovedInt{$Level}{$Symbol} = 1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011538 }
11539}
11540
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011541sub mergeLibs($)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011542{
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011543 my $Level = $_[0];
11544 foreach my $Symbol (sort keys(%{$AddedInt{$Level}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011545 { # checking added symbols
11546 next if($CompleteSignature{2}{$Symbol}{"Private"});
11547 next if(not $CompleteSignature{2}{$Symbol}{"Header"} and not $CheckObjectsOnly);
Andrey Ponomarenko85043792012-05-14 16:48:07 +040011548 next if(not symbolFilter($Symbol, 2, "Affected", $Level));
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011549 %{$CompatProblems{$Level}{$Symbol}{"Added_Symbol"}{""}}=();
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011550 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011551 foreach my $Symbol (sort keys(%{$RemovedInt{$Level}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011552 { # checking removed symbols
11553 next if($CompleteSignature{1}{$Symbol}{"Private"});
11554 next if(not $CompleteSignature{1}{$Symbol}{"Header"} and not $CheckObjectsOnly);
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040011555 if(index($Symbol, "_ZTV")==0)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011556 { # skip v-tables for templates, that should not be imported by applications
11557 next if($tr_name{$Symbol}=~/</);
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040011558 if(my $CName = $VTableClass{$Symbol})
11559 {
11560 if(not keys(%{$ClassMethods{$Level}{1}{$CName}}))
11561 { # vtables for "private" classes
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040011562 # use case: vtable for QDragManager (Qt 4.5.3 to 4.6.0) became HIDDEN symbol
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040011563 next;
11564 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011565 }
11566 }
11567 else {
Andrey Ponomarenko85043792012-05-14 16:48:07 +040011568 next if(not symbolFilter($Symbol, 1, "Affected", $Level));
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011569 }
11570 if($CompleteSignature{1}{$Symbol}{"PureVirt"})
11571 { # symbols for pure virtual methods cannot be called by clients
11572 next;
11573 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011574 %{$CompatProblems{$Level}{$Symbol}{"Removed_Symbol"}{""}}=();
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011575 }
11576}
11577
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040011578sub checkDump($$)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011579{
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040011580 my ($LibVersion, $V) = @_;
11581 if(defined $Cache{"checkDump"}{$LibVersion}{$V}) {
11582 return $Cache{"checkDump"}{$LibVersion}{$V};
11583 }
11584 return ($Cache{"checkDump"}{$LibVersion}{$V} = (not $UsedDump{$LibVersion}{"V"} or cmpVersions($UsedDump{$LibVersion}{"V"}, $V)>=0));
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011585}
11586
11587sub detectAdded_H($)
11588{
11589 my $Level = $_[0];
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011590 foreach my $Symbol (sort keys(%{$CompleteSignature{2}}))
11591 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011592 if($Level eq "Source")
11593 { # remove symbol version
11594 my ($SN, $SS, $SV) = separate_symbol($Symbol);
11595 $Symbol=$SN;
Andrey Ponomarenkob8d203d2012-05-25 18:11:07 +040011596
11597 if($CompleteSignature{2}{$Symbol}{"Artificial"})
11598 { # skip artificial constructors
11599 next;
11600 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011601 }
Andrey Ponomarenko16934472012-03-29 15:37:04 +040011602 if(not $CompleteSignature{2}{$Symbol}{"Header"}
11603 or not $CompleteSignature{2}{$Symbol}{"MnglName"}) {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011604 next;
11605 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040011606 if($ExtendedSymbols{$Symbol}) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011607 next;
11608 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011609 if(not defined $CompleteSignature{1}{$Symbol}
11610 or not $CompleteSignature{1}{$Symbol}{"MnglName"})
11611 {
Andrey Ponomarenko16934472012-03-29 15:37:04 +040011612 if($UsedDump{2}{"SrcBin"})
11613 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040011614 if($UsedDump{1}{"BinOnly"} or not checkDump(1, "2.11"))
Andrey Ponomarenko16934472012-03-29 15:37:04 +040011615 { # support for old and different (!) ABI dumps
11616 if(not $CompleteSignature{2}{$Symbol}{"Virt"}
11617 and not $CompleteSignature{2}{$Symbol}{"PureVirt"})
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011618 {
Andrey Ponomarenko16934472012-03-29 15:37:04 +040011619 if($CheckHeadersOnly)
Andrey Ponomarenko85043792012-05-14 16:48:07 +040011620 {
11621 if(my $Lang = $CompleteSignature{2}{$Symbol}{"Lang"})
11622 {
11623 if($Lang eq "C")
11624 { # support for old ABI dumps: missed extern "C" functions
11625 next;
11626 }
11627 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011628 }
Andrey Ponomarenko16934472012-03-29 15:37:04 +040011629 else
11630 {
11631 if(not link_symbol($Symbol, 2, "-Deps"))
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040011632 { # skip added inline symbols and const global data
Andrey Ponomarenko16934472012-03-29 15:37:04 +040011633 next;
11634 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011635 }
11636 }
11637 }
11638 }
11639 $AddedInt{$Level}{$Symbol} = 1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011640 }
11641 }
11642}
11643
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011644sub detectRemoved_H($)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011645{
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011646 my $Level = $_[0];
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011647 foreach my $Symbol (sort keys(%{$CompleteSignature{1}}))
11648 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011649 if($Level eq "Source")
11650 { # remove symbol version
11651 my ($SN, $SS, $SV) = separate_symbol($Symbol);
11652 $Symbol=$SN;
11653 }
Andrey Ponomarenko16934472012-03-29 15:37:04 +040011654 if(not $CompleteSignature{1}{$Symbol}{"Header"}
11655 or not $CompleteSignature{1}{$Symbol}{"MnglName"}) {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011656 next;
11657 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040011658 if($ExtendedSymbols{$Symbol}) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011659 next;
11660 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011661 if(not defined $CompleteSignature{2}{$Symbol}
11662 or not $CompleteSignature{2}{$Symbol}{"MnglName"})
Andrey Ponomarenko85043792012-05-14 16:48:07 +040011663 {
Andrey Ponomarenko16934472012-03-29 15:37:04 +040011664 if($UsedDump{1}{"SrcBin"})
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011665 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040011666 if($UsedDump{2}{"BinOnly"} or not checkDump(2, "2.11"))
Andrey Ponomarenko85043792012-05-14 16:48:07 +040011667 { # support for old and different (!) ABI dumps
Andrey Ponomarenko16934472012-03-29 15:37:04 +040011668 if(not $CompleteSignature{1}{$Symbol}{"Virt"}
11669 and not $CompleteSignature{1}{$Symbol}{"PureVirt"})
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011670 {
Andrey Ponomarenko16934472012-03-29 15:37:04 +040011671 if($CheckHeadersOnly)
11672 { # skip all removed symbols
Andrey Ponomarenko85043792012-05-14 16:48:07 +040011673 if(my $Lang = $CompleteSignature{1}{$Symbol}{"Lang"})
11674 {
11675 if($Lang eq "C")
11676 { # support for old ABI dumps: missed extern "C" functions
11677 next;
11678 }
11679 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011680 }
Andrey Ponomarenko16934472012-03-29 15:37:04 +040011681 else
11682 {
11683 if(not link_symbol($Symbol, 1, "-Deps"))
11684 { # skip removed inline symbols
11685 next;
11686 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011687 }
11688 }
11689 }
11690 }
Andrey Ponomarenkob8d203d2012-05-25 18:11:07 +040011691 if(not checkDump(1, "2.15"))
11692 {
11693 if($Symbol=~/_IT_E\Z/)
11694 { # _ZN28QExplicitlySharedDataPointerI22QSslCertificatePrivateEC1IT_EERKS_IT_E
11695 next;
11696 }
11697 }
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040011698 if(not $CompleteSignature{1}{$Symbol}{"Class"})
11699 {
11700 if(my $Short = $CompleteSignature{1}{$Symbol}{"ShortName"})
11701 {
11702 if(defined $Constants{2}{$Short})
11703 {
11704 my $Val = $Constants{2}{$Short}{"Value"};
11705 if(defined $Func_ShortName{2}{$Val})
11706 { # old name defined to new
11707 next;
11708 }
11709 }
11710 }
11711
11712 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011713 $RemovedInt{$Level}{$Symbol} = 1;
11714 if($Level eq "Source")
11715 { # search for a source-compatible equivalent
11716 setAlternative($Symbol, $Level);
11717 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011718 }
11719 }
11720}
11721
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011722sub mergeHeaders($)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011723{
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011724 my $Level = $_[0];
11725 foreach my $Symbol (sort keys(%{$AddedInt{$Level}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011726 { # checking added symbols
11727 next if($CompleteSignature{2}{$Symbol}{"PureVirt"});
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040011728 next if($CompleteSignature{2}{$Symbol}{"Private"});
11729 next if(not symbolFilter($Symbol, 2, "Affected", $Level));
Andrey Ponomarenko85043792012-05-14 16:48:07 +040011730 if($Level eq "Binary")
11731 {
11732 if($CompleteSignature{2}{$Symbol}{"InLine"})
11733 {
11734 if(not $CompleteSignature{2}{$Symbol}{"Virt"})
11735 { # skip inline non-virtual functions
11736 next;
11737 }
11738 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011739 }
11740 else
11741 { # Source
11742 if($SourceAlternative_B{$Symbol}) {
11743 next;
11744 }
11745 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011746 %{$CompatProblems{$Level}{$Symbol}{"Added_Symbol"}{""}}=();
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011747 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011748 foreach my $Symbol (sort keys(%{$RemovedInt{$Level}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011749 { # checking removed symbols
11750 next if($CompleteSignature{1}{$Symbol}{"PureVirt"});
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040011751 next if($CompleteSignature{1}{$Symbol}{"Private"});
11752 next if(not symbolFilter($Symbol, 1, "Affected", $Level));
Andrey Ponomarenko85043792012-05-14 16:48:07 +040011753 if($Level eq "Binary")
11754 {
11755 if($CompleteSignature{1}{$Symbol}{"InLine"})
11756 {
11757 if(not $CompleteSignature{1}{$Symbol}{"Virt"})
11758 { # skip inline non-virtual functions
11759 next;
11760 }
11761 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011762 }
11763 else
11764 { # Source
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040011765 if(my $Alt = $SourceAlternative{$Symbol})
11766 {
11767 if(defined $CompleteSignature{1}{$Alt}
11768 and $CompleteSignature{1}{$Symbol}{"Const"})
11769 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040011770 my $Cid = $CompleteSignature{1}{$Symbol}{"Class"};
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040011771 %{$CompatProblems{$Level}{$Symbol}{"Removed_Const_Overload"}{$tr_name{$Symbol}}}=(
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040011772 "Type_Name"=>$TypeInfo{1}{$Cid}{"Name"},
Andrey Ponomarenko85043792012-05-14 16:48:07 +040011773 "Type_Type"=>"Class",
11774 "Target"=>get_Signature($Alt, 1) );
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040011775 }
11776 else
11777 { # do NOT show removed symbol
11778 next;
11779 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011780 }
11781 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011782 %{$CompatProblems{$Level}{$Symbol}{"Removed_Symbol"}{""}}=();
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011783 }
11784}
11785
11786sub addParamNames($)
11787{
11788 my $LibraryVersion = $_[0];
11789 return if(not keys(%AddIntParams));
11790 my $SecondVersion = $LibraryVersion==1?2:1;
11791 foreach my $Interface (sort keys(%{$CompleteSignature{$LibraryVersion}}))
11792 {
11793 next if(not keys(%{$AddIntParams{$Interface}}));
11794 foreach my $ParamPos (sort {int($a)<=>int($b)} keys(%{$CompleteSignature{$LibraryVersion}{$Interface}{"Param"}}))
Andrey Ponomarenko85043792012-05-14 16:48:07 +040011795 { # add absent parameter names
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011796 my $ParamName = $CompleteSignature{$LibraryVersion}{$Interface}{"Param"}{$ParamPos}{"name"};
11797 if($ParamName=~/\Ap\d+\Z/ and my $NewParamName = $AddIntParams{$Interface}{$ParamPos})
Andrey Ponomarenko85043792012-05-14 16:48:07 +040011798 { # names from the external file
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011799 if(defined $CompleteSignature{$SecondVersion}{$Interface}
11800 and defined $CompleteSignature{$SecondVersion}{$Interface}{"Param"}{$ParamPos})
11801 {
11802 if($CompleteSignature{$SecondVersion}{$Interface}{"Param"}{$ParamPos}{"name"}=~/\Ap\d+\Z/) {
11803 $CompleteSignature{$LibraryVersion}{$Interface}{"Param"}{$ParamPos}{"name"} = $NewParamName;
11804 }
11805 }
11806 else {
11807 $CompleteSignature{$LibraryVersion}{$Interface}{"Param"}{$ParamPos}{"name"} = $NewParamName;
11808 }
11809 }
11810 }
11811 }
11812}
11813
11814sub detectChangedTypedefs()
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +040011815{ # detect changed typedefs to show
11816 # correct function signatures
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011817 foreach my $Typedef (keys(%{$Typedef_BaseName{1}}))
11818 {
11819 next if(not $Typedef);
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +040011820 my $BName1 = $Typedef_BaseName{1}{$Typedef};
11821 if(not $BName1 or isAnon($BName1)) {
11822 next;
11823 }
11824 my $BName2 = $Typedef_BaseName{2}{$Typedef};
11825 if(not $BName2 or isAnon($BName2)) {
11826 next;
11827 }
11828 if($BName1 ne $BName2) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011829 $ChangedTypedef{$Typedef} = 1;
11830 }
11831 }
11832}
11833
11834sub get_symbol_suffix($$)
11835{
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011836 my ($Symbol, $Full) = @_;
11837 my ($SN, $SO, $SV) = separate_symbol($Symbol);
11838 $Symbol=$SN;# remove version
11839 my $Signature = $tr_name{$Symbol};
Andrey Ponomarenko16934472012-03-29 15:37:04 +040011840 my $Suffix = substr($Signature, find_center($Signature, "("));
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011841 if(not $Full) {
11842 $Suffix=~s/(\))\s*(const volatile|volatile const|const|volatile)\Z/$1/g;
11843 }
11844 return $Suffix;
11845}
11846
11847sub get_symbol_prefix($$)
11848{
11849 my ($Symbol, $LibVersion) = @_;
11850 my $ShortName = $CompleteSignature{$LibVersion}{$Symbol}{"ShortName"};
11851 if(my $ClassId = $CompleteSignature{$LibVersion}{$Symbol}{"Class"})
11852 { # methods
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040011853 $ShortName = $TypeInfo{$LibVersion}{$ClassId}{"Name"}."::".$ShortName;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011854 }
11855 return $ShortName;
11856}
11857
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011858sub setAlternative($)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011859{
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011860 my $Symbol = $_[0];
11861 my $PSymbol = $Symbol;
11862 if(not defined $CompleteSignature{2}{$PSymbol}
11863 or (not $CompleteSignature{2}{$PSymbol}{"MnglName"}
11864 and not $CompleteSignature{2}{$PSymbol}{"ShortName"}))
11865 { # search for a pair
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040011866 if(my $ShortName = $CompleteSignature{1}{$PSymbol}{"ShortName"})
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011867 {
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040011868 if($CompleteSignature{1}{$PSymbol}{"Data"})
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011869 {
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040011870 if($PSymbol=~s/L(\d+$ShortName(E)\Z)/$1/
11871 or $PSymbol=~s/(\d+$ShortName(E)\Z)/L$1/)
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011872 {
11873 if(defined $CompleteSignature{2}{$PSymbol}
11874 and $CompleteSignature{2}{$PSymbol}{"MnglName"})
11875 {
11876 $SourceAlternative{$Symbol} = $PSymbol;
11877 $SourceAlternative_B{$PSymbol} = $Symbol;
11878 if(not defined $CompleteSignature{1}{$PSymbol}
11879 or not $CompleteSignature{1}{$PSymbol}{"MnglName"}) {
11880 $SourceReplacement{$Symbol} = $PSymbol;
11881 }
11882 }
11883 }
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040011884 }
11885 else
11886 {
11887 foreach my $Sp ("KV", "VK", "K", "V")
11888 {
11889 if($PSymbol=~s/\A_ZN$Sp/_ZN/
11890 or $PSymbol=~s/\A_ZN/_ZN$Sp/)
11891 {
11892 if(defined $CompleteSignature{2}{$PSymbol}
11893 and $CompleteSignature{2}{$PSymbol}{"MnglName"})
11894 {
11895 $SourceAlternative{$Symbol} = $PSymbol;
11896 $SourceAlternative_B{$PSymbol} = $Symbol;
11897 if(not defined $CompleteSignature{1}{$PSymbol}
11898 or not $CompleteSignature{1}{$PSymbol}{"MnglName"}) {
11899 $SourceReplacement{$Symbol} = $PSymbol;
11900 }
11901 }
11902 }
11903 $PSymbol = $Symbol;
11904 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011905 }
11906 }
11907 }
11908 return "";
11909}
11910
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040011911sub getSymKind($$)
11912{
11913 my ($Symbol, $LibVersion) = @_;
11914 if($CompleteSignature{$LibVersion}{$Symbol}{"Data"})
11915 {
11916 return "Global_Data";
11917 }
11918 elsif($CompleteSignature{$LibVersion}{$Symbol}{"Class"})
11919 {
11920 return "Method";
11921 }
11922 return "Function";
11923}
11924
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011925sub mergeSignatures($)
11926{
11927 my $Level = $_[0];
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011928 my %SubProblems = ();
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011929
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011930 mergeBases($Level);
11931
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011932 my %AddedOverloads = ();
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011933 foreach my $Symbol (sort keys(%{$AddedInt{$Level}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011934 { # check all added exported symbols
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011935 if(not $CompleteSignature{2}{$Symbol}{"Header"}) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011936 next;
11937 }
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040011938 if(defined $CompleteSignature{1}{$Symbol}
11939 and $CompleteSignature{1}{$Symbol}{"Header"})
11940 { # double-check added symbol
11941 next;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011942 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +040011943 if(not symbolFilter($Symbol, 2, "Affected", $Level)) {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011944 next;
11945 }
11946 if($Symbol=~/\A(_Z|\?)/)
11947 { # C++
11948 $AddedOverloads{get_symbol_prefix($Symbol, 2)}{get_symbol_suffix($Symbol, 1)} = $Symbol;
11949 }
11950 if(my $OverriddenMethod = $CompleteSignature{2}{$Symbol}{"Override"})
11951 { # register virtual overridings
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040011952 my $Cid = $CompleteSignature{2}{$Symbol}{"Class"};
11953 my $AffectedClass_Name = $TypeInfo{2}{$Cid}{"Name"};
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040011954 if(defined $CompleteSignature{1}{$OverriddenMethod} and $CompleteSignature{1}{$OverriddenMethod}{"Virt"}
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011955 and not $CompleteSignature{1}{$OverriddenMethod}{"Private"})
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040011956 {
11957 if($TName_Tid{1}{$AffectedClass_Name})
11958 { # class should exist in previous version
11959 if(not isCopyingClass($TName_Tid{1}{$AffectedClass_Name}, 1))
11960 { # old v-table is NOT copied by old applications
11961 %{$CompatProblems{$Level}{$OverriddenMethod}{"Overridden_Virtual_Method"}{$tr_name{$Symbol}}}=(
11962 "Type_Name"=>$AffectedClass_Name,
11963 "Type_Type"=>"Class",
11964 "Target"=>get_Signature($Symbol, 2),
11965 "Old_Value"=>get_Signature($OverriddenMethod, 2),
11966 "New_Value"=>get_Signature($Symbol, 2) );
11967 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011968 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011969 }
11970 }
11971 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011972 foreach my $Symbol (sort keys(%{$RemovedInt{$Level}}))
11973 { # check all removed exported symbols
11974 if(not $CompleteSignature{1}{$Symbol}{"Header"}) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011975 next;
11976 }
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040011977 if(defined $CompleteSignature{2}{$Symbol}
11978 and $CompleteSignature{2}{$Symbol}{"Header"})
11979 { # double-check removed symbol
11980 next;
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011981 }
11982 if($CompleteSignature{1}{$Symbol}{"Private"})
11983 { # skip private methods
11984 next;
11985 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +040011986 if(not symbolFilter($Symbol, 1, "Affected", $Level)) {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011987 next;
11988 }
11989 $CheckedSymbols{$Level}{$Symbol} = 1;
11990 if(my $OverriddenMethod = $CompleteSignature{1}{$Symbol}{"Override"})
11991 { # register virtual overridings
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040011992 my $Cid = $CompleteSignature{1}{$Symbol}{"Class"};
11993 my $AffectedClass_Name = $TypeInfo{1}{$Cid}{"Name"};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011994 if(defined $CompleteSignature{2}{$OverriddenMethod}
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040011995 and $CompleteSignature{2}{$OverriddenMethod}{"Virt"})
11996 {
11997 if($TName_Tid{2}{$AffectedClass_Name})
11998 { # class should exist in newer version
11999 if(not isCopyingClass($CompleteSignature{1}{$Symbol}{"Class"}, 1))
12000 { # old v-table is NOT copied by old applications
12001 %{$CompatProblems{$Level}{$Symbol}{"Overridden_Virtual_Method_B"}{$tr_name{$OverriddenMethod}}}=(
12002 "Type_Name"=>$AffectedClass_Name,
12003 "Type_Type"=>"Class",
12004 "Target"=>get_Signature($OverriddenMethod, 1),
12005 "Old_Value"=>get_Signature($Symbol, 1),
12006 "New_Value"=>get_Signature($OverriddenMethod, 1) );
12007 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012008 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012009 }
12010 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012011 if($Level eq "Binary"
12012 and $OSgroup eq "windows")
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012013 { # register the reason of symbol name change
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040012014 if(my $NewSym = $mangled_name{2}{$tr_name{$Symbol}})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012015 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040012016 if($AddedInt{$Level}{$NewSym})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012017 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040012018 if($CompleteSignature{1}{$Symbol}{"Static"} ne $CompleteSignature{2}{$NewSym}{"Static"})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012019 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040012020 if($CompleteSignature{2}{$NewSym}{"Static"})
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012021 {
12022 %{$CompatProblems{$Level}{$Symbol}{"Symbol_Became_Static"}{$tr_name{$Symbol}}}=(
12023 "Target"=>$tr_name{$Symbol},
12024 "Old_Value"=>$Symbol,
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040012025 "New_Value"=>$NewSym );
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012026 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012027 else
12028 {
12029 %{$CompatProblems{$Level}{$Symbol}{"Symbol_Became_NonStatic"}{$tr_name{$Symbol}}}=(
12030 "Target"=>$tr_name{$Symbol},
12031 "Old_Value"=>$Symbol,
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040012032 "New_Value"=>$NewSym );
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012033 }
12034 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040012035 if($CompleteSignature{1}{$Symbol}{"Virt"} ne $CompleteSignature{2}{$NewSym}{"Virt"})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012036 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040012037 if($CompleteSignature{2}{$NewSym}{"Virt"})
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012038 {
12039 %{$CompatProblems{$Level}{$Symbol}{"Symbol_Became_Virtual"}{$tr_name{$Symbol}}}=(
12040 "Target"=>$tr_name{$Symbol},
12041 "Old_Value"=>$Symbol,
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040012042 "New_Value"=>$NewSym );
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012043 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012044 else
12045 {
12046 %{$CompatProblems{$Level}{$Symbol}{"Symbol_Became_NonVirtual"}{$tr_name{$Symbol}}}=(
12047 "Target"=>$tr_name{$Symbol},
12048 "Old_Value"=>$Symbol,
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040012049 "New_Value"=>$NewSym );
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012050 }
12051 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040012052 my $RTId1 = $CompleteSignature{1}{$Symbol}{"Return"};
12053 my $RTId2 = $CompleteSignature{2}{$NewSym}{"Return"};
12054 my $RTName1 = $TypeInfo{1}{$RTId1}{"Name"};
12055 my $RTName2 = $TypeInfo{2}{$RTId2}{"Name"};
12056 if($RTName1 ne $RTName2)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012057 {
12058 my $ProblemType = "Symbol_Changed_Return";
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012059 if($CompleteSignature{1}{$Symbol}{"Data"}) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012060 $ProblemType = "Global_Data_Symbol_Changed_Type";
12061 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012062 %{$CompatProblems{$Level}{$Symbol}{$ProblemType}{$tr_name{$Symbol}}}=(
12063 "Target"=>$tr_name{$Symbol},
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040012064 "Old_Type"=>$RTName1,
12065 "New_Type"=>$RTName2,
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012066 "Old_Value"=>$Symbol,
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040012067 "New_Value"=>$NewSym );
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012068 }
12069 }
12070 }
12071 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012072 if($Symbol=~/\A(_Z|\?)/)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012073 { # C++
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012074 my $Prefix = get_symbol_prefix($Symbol, 1);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012075 if(my @Overloads = sort keys(%{$AddedOverloads{$Prefix}})
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012076 and not $AddedOverloads{$Prefix}{get_symbol_suffix($Symbol, 1)})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012077 { # changed signature: params, "const"-qualifier
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040012078 my $NewSym = $AddedOverloads{$Prefix}{$Overloads[0]};
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012079 if($CompleteSignature{1}{$Symbol}{"Constructor"})
12080 {
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +040012081 if($Symbol=~/(C1E|C2E)/)
12082 {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012083 my $CtorType = $1;
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040012084 $NewSym=~s/(C1E|C2E)/$CtorType/g;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012085 }
12086 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012087 elsif($CompleteSignature{1}{$Symbol}{"Destructor"})
12088 {
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +040012089 if($Symbol=~/(D0E|D1E|D2E)/)
12090 {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012091 my $DtorType = $1;
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040012092 $NewSym=~s/(D0E|D1E|D2E)/$DtorType/g;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012093 }
12094 }
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040012095 my $NS1 = $CompleteSignature{1}{$Symbol}{"NameSpace"};
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040012096 my $NS2 = $CompleteSignature{2}{$NewSym}{"NameSpace"};
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040012097 if((not $NS1 and not $NS2) or ($NS1 and $NS2 and $NS1 eq $NS2))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012098 { # from the same class and namespace
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012099 if($CompleteSignature{1}{$Symbol}{"Const"}
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040012100 and not $CompleteSignature{2}{$NewSym}{"Const"})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012101 { # "const" to non-"const"
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040012102 %{$CompatProblems{$Level}{$Symbol}{"Method_Became_NonConst"}{$tr_name{$Symbol}}}=(
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040012103 "Type_Name"=>$TypeInfo{1}{$CompleteSignature{1}{$Symbol}{"Class"}}{"Name"},
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012104 "Target"=>$tr_name{$Symbol},
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040012105 "New_Signature"=>get_Signature($NewSym, 2),
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012106 "Old_Value"=>$Symbol,
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040012107 "New_Value"=>$NewSym );
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012108 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012109 elsif(not $CompleteSignature{1}{$Symbol}{"Const"}
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040012110 and $CompleteSignature{2}{$NewSym}{"Const"})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012111 { # non-"const" to "const"
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040012112 %{$CompatProblems{$Level}{$Symbol}{"Method_Became_Const"}{$tr_name{$Symbol}}}=(
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012113 "Target"=>$tr_name{$Symbol},
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040012114 "New_Signature"=>get_Signature($NewSym, 2),
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012115 "Old_Value"=>$Symbol,
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040012116 "New_Value"=>$NewSym );
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012117 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012118 if($CompleteSignature{1}{$Symbol}{"Volatile"}
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040012119 and not $CompleteSignature{2}{$NewSym}{"Volatile"})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012120 { # "volatile" to non-"volatile"
12121
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040012122 %{$CompatProblems{$Level}{$Symbol}{"Method_Became_NonVolatile"}{$tr_name{$Symbol}}}=(
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012123 "Target"=>$tr_name{$Symbol},
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040012124 "New_Signature"=>get_Signature($NewSym, 2),
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012125 "Old_Value"=>$Symbol,
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040012126 "New_Value"=>$NewSym );
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012127 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012128 elsif(not $CompleteSignature{1}{$Symbol}{"Volatile"}
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040012129 and $CompleteSignature{2}{$NewSym}{"Volatile"})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012130 { # non-"volatile" to "volatile"
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040012131 %{$CompatProblems{$Level}{$Symbol}{"Method_Became_Volatile"}{$tr_name{$Symbol}}}=(
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012132 "Target"=>$tr_name{$Symbol},
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040012133 "New_Signature"=>get_Signature($NewSym, 2),
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012134 "Old_Value"=>$Symbol,
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040012135 "New_Value"=>$NewSym );
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012136 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040012137 if(get_symbol_suffix($Symbol, 0) ne get_symbol_suffix($NewSym, 0))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012138 { # params list
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012139 %{$CompatProblems{$Level}{$Symbol}{"Symbol_Changed_Parameters"}{$tr_name{$Symbol}}}=(
12140 "Target"=>$tr_name{$Symbol},
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040012141 "New_Signature"=>get_Signature($NewSym, 2),
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012142 "Old_Value"=>$Symbol,
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040012143 "New_Value"=>$NewSym );
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012144 }
12145 }
12146 }
12147 }
12148 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012149 foreach my $Symbol (sort keys(%{$CompleteSignature{1}}))
12150 { # checking symbols
12151 my ($SN, $SS, $SV) = separate_symbol($Symbol);
12152 if($Level eq "Source")
12153 { # remove symbol version
12154 $Symbol=$SN;
12155 }
12156 else
12157 { # Binary
12158 if(not $SV)
12159 { # symbol without version
12160 if(my $VSym = $SymVer{1}{$Symbol})
12161 { # the symbol is linked with versioned symbol
12162 if($CompleteSignature{2}{$VSym}{"MnglName"})
12163 { # show report for symbol@ver only
12164 next;
12165 }
12166 elsif(not link_symbol($VSym, 2, "-Deps"))
12167 { # changed version: sym@v1 to sym@v2
12168 # do NOT show report for symbol
12169 next;
12170 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012171 }
12172 }
12173 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012174 my $PSymbol = $Symbol;
12175 if($Level eq "Source"
12176 and my $S = $SourceReplacement{$Symbol})
12177 { # take a source-compatible replacement function
12178 $PSymbol = $S;
12179 }
12180 if($CompleteSignature{1}{$Symbol}{"Private"})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012181 { # private symbols
12182 next;
12183 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012184 if(not defined $CompleteSignature{1}{$Symbol}
12185 or not defined $CompleteSignature{2}{$PSymbol})
12186 { # no info
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012187 next;
12188 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012189 if(not $CompleteSignature{1}{$Symbol}{"MnglName"}
12190 or not $CompleteSignature{2}{$PSymbol}{"MnglName"})
12191 { # no mangled name
12192 next;
12193 }
12194 if(not $CompleteSignature{1}{$Symbol}{"Header"}
12195 or not $CompleteSignature{2}{$PSymbol}{"Header"})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012196 { # without a header
12197 next;
12198 }
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040012199
12200 if(not $CompleteSignature{1}{$Symbol}{"PureVirt"}
12201 and $CompleteSignature{2}{$PSymbol}{"PureVirt"})
12202 { # became pure
12203 next;
12204 }
12205 if($CompleteSignature{1}{$Symbol}{"PureVirt"}
12206 and not $CompleteSignature{2}{$PSymbol}{"PureVirt"})
12207 { # became non-pure
12208 next;
12209 }
12210
12211 if(not symbolFilter($Symbol, 1, "Affected + InlineVirt", $Level))
12212 { # exported, target, inline virtual and pure virtual
12213 next;
12214 }
12215 if(not symbolFilter($PSymbol, 2, "Affected + InlineVirt", $Level))
12216 { # exported, target, inline virtual and pure virtual
12217 next;
12218 }
12219
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040012220 if(checkDump(1, "2.13") and checkDump(2, "2.13"))
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040012221 {
12222 if($CompleteSignature{1}{$Symbol}{"Data"}
12223 and $CompleteSignature{2}{$PSymbol}{"Data"})
12224 {
12225 my $Value1 = $CompleteSignature{1}{$Symbol}{"Value"};
12226 my $Value2 = $CompleteSignature{2}{$PSymbol}{"Value"};
12227 if(defined $Value1)
12228 {
12229 $Value1 = showVal($Value1, $CompleteSignature{1}{$Symbol}{"Return"}, 1);
12230 if(defined $Value2)
12231 {
12232 $Value2 = showVal($Value2, $CompleteSignature{2}{$PSymbol}{"Return"}, 2);
12233 if($Value1 ne $Value2)
12234 {
12235 %{$CompatProblems{$Level}{$Symbol}{"Global_Data_Value_Changed"}{""}}=(
12236 "Old_Value"=>$Value1,
12237 "New_Value"=>$Value2,
12238 "Target"=>get_Signature($Symbol, 1) );
12239 }
12240 }
12241 }
12242 }
12243 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +040012244
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040012245 if($CompleteSignature{2}{$PSymbol}{"Private"})
12246 {
12247 %{$CompatProblems{$Level}{$Symbol}{getSymKind($Symbol, 1)."_Became_Private"}{""}}=(
12248 "Target"=>get_Signature_M($PSymbol, 2) );
12249 }
12250 elsif(not $CompleteSignature{1}{$Symbol}{"Protected"}
12251 and $CompleteSignature{2}{$PSymbol}{"Protected"})
12252 {
12253 %{$CompatProblems{$Level}{$Symbol}{getSymKind($Symbol, 1)."_Became_Protected"}{""}}=(
12254 "Target"=>get_Signature_M($PSymbol, 2) );
12255 }
12256 elsif($CompleteSignature{1}{$Symbol}{"Protected"}
12257 and not $CompleteSignature{2}{$PSymbol}{"Protected"})
12258 {
12259 %{$CompatProblems{$Level}{$Symbol}{getSymKind($Symbol, 1)."_Became_Public"}{""}}=(
12260 "Target"=>get_Signature_M($PSymbol, 2) );
12261 }
12262
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012263 # checking virtual table
Andrey Ponomarenko16934472012-03-29 15:37:04 +040012264 mergeVirtualTables($Symbol, $Level);
12265
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012266 if($COMPILE_ERRORS)
12267 { # if some errors occurred at the compiling stage
12268 # then some false positives can be skipped here
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012269 if(not $CompleteSignature{1}{$Symbol}{"Data"} and $CompleteSignature{2}{$PSymbol}{"Data"}
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040012270 and not $GlobalDataObject{2}{$Symbol})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012271 { # missed information about parameters in newer version
12272 next;
12273 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040012274 if($CompleteSignature{1}{$Symbol}{"Data"} and not $GlobalDataObject{1}{$Symbol}
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012275 and not $CompleteSignature{2}{$PSymbol}{"Data"})
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040012276 { # missed information about parameters in older version
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012277 next;
12278 }
12279 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012280 my ($MnglName, $VersionSpec, $SymbolVersion) = separate_symbol($Symbol);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012281 # checking attributes
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012282 if($CompleteSignature{2}{$PSymbol}{"Static"}
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040012283 and not $CompleteSignature{1}{$Symbol}{"Static"} and $Symbol=~/\A(_Z|\?)/)
12284 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012285 %{$CompatProblems{$Level}{$Symbol}{"Method_Became_Static"}{""}}=(
12286 "Target"=>get_Signature($Symbol, 1)
12287 );
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012288 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012289 elsif(not $CompleteSignature{2}{$PSymbol}{"Static"}
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040012290 and $CompleteSignature{1}{$Symbol}{"Static"} and $Symbol=~/\A(_Z|\?)/)
12291 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012292 %{$CompatProblems{$Level}{$Symbol}{"Method_Became_NonStatic"}{""}}=(
12293 "Target"=>get_Signature($Symbol, 1)
12294 );
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012295 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012296 if(($CompleteSignature{1}{$Symbol}{"Virt"} and $CompleteSignature{2}{$PSymbol}{"Virt"})
12297 or ($CompleteSignature{1}{$Symbol}{"PureVirt"} and $CompleteSignature{2}{$PSymbol}{"PureVirt"}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012298 { # relative position of virtual and pure virtual methods
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012299 if($Level eq "Binary")
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012300 {
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040012301 if(defined $CompleteSignature{1}{$Symbol}{"RelPos"} and defined $CompleteSignature{2}{$PSymbol}{"RelPos"}
12302 and $CompleteSignature{1}{$Symbol}{"RelPos"}!=$CompleteSignature{2}{$PSymbol}{"RelPos"})
12303 { # top-level virtual methods only
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012304 my $Class_Id = $CompleteSignature{1}{$Symbol}{"Class"};
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040012305 my $Class_Name = $TypeInfo{1}{$Class_Id}{"Name"};
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040012306 if(defined $VirtualTable{1}{$Class_Name} and defined $VirtualTable{2}{$Class_Name}
12307 and $VirtualTable{1}{$Class_Name}{$Symbol}!=$VirtualTable{2}{$Class_Name}{$Symbol})
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012308 { # check the absolute position of virtual method (including added and removed methods)
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040012309 my %Class_Type = get_Type($Class_Id, 1);
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012310 my $ProblemType = "Virtual_Method_Position";
12311 if($CompleteSignature{1}{$Symbol}{"PureVirt"}) {
12312 $ProblemType = "Pure_Virtual_Method_Position";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012313 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012314 if(isUsedClass($Class_Id, 1, $Level))
12315 {
12316 my @Affected = ($Symbol, keys(%{$OverriddenMethods{1}{$Symbol}}));
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040012317 foreach my $ASymbol (@Affected)
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012318 {
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040012319 if(not symbolFilter($ASymbol, 1, "Affected", $Level)) {
12320 next;
12321 }
12322 %{$CompatProblems{$Level}{$ASymbol}{$ProblemType}{$tr_name{$MnglName}}}=(
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012323 "Type_Name"=>$Class_Type{"Name"},
12324 "Type_Type"=>"Class",
12325 "Old_Value"=>$CompleteSignature{1}{$Symbol}{"RelPos"},
12326 "New_Value"=>$CompleteSignature{2}{$PSymbol}{"RelPos"},
12327 "Target"=>get_Signature($Symbol, 1) );
12328 }
Andrey Ponomarenko16934472012-03-29 15:37:04 +040012329 $VTableChanged_M{$Class_Type{"Name"}} = 1;
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012330 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012331 }
12332 }
12333 }
12334 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012335 if($CompleteSignature{1}{$Symbol}{"PureVirt"}
12336 or $CompleteSignature{2}{$PSymbol}{"PureVirt"})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012337 { # do NOT check type changes in pure virtuals
12338 next;
12339 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012340 $CheckedSymbols{$Level}{$Symbol}=1;
12341 if($Symbol=~/\A(_Z|\?)/
12342 or keys(%{$CompleteSignature{1}{$Symbol}{"Param"}})==keys(%{$CompleteSignature{2}{$PSymbol}{"Param"}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012343 { # C/C++: changes in parameters
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012344 foreach my $ParamPos (sort {int($a) <=> int($b)} keys(%{$CompleteSignature{1}{$Symbol}{"Param"}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012345 { # checking parameters
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012346 mergeParameters($Symbol, $PSymbol, $ParamPos, $ParamPos, $Level);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012347 }
12348 }
12349 else
12350 { # C: added/removed parameters
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012351 foreach my $ParamPos (sort {int($a) <=> int($b)} keys(%{$CompleteSignature{2}{$PSymbol}{"Param"}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012352 { # checking added parameters
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040012353 my $PType2_Id = $CompleteSignature{2}{$PSymbol}{"Param"}{$ParamPos}{"type"};
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040012354 my $PType2_Name = $TypeInfo{2}{$PType2_Id}{"Name"};
12355 last if($PType2_Name eq "...");
12356 my $PName = $CompleteSignature{2}{$PSymbol}{"Param"}{$ParamPos}{"name"};
12357 my $PName_Old = (defined $CompleteSignature{1}{$Symbol}{"Param"}{$ParamPos})?$CompleteSignature{1}{$Symbol}{"Param"}{$ParamPos}{"name"}:"";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012358 my $ParamPos_Prev = "-1";
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040012359 if($PName=~/\Ap\d+\Z/i)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012360 { # added unnamed parameter ( pN )
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040012361 my @Positions1 = find_ParamPair_Pos_byTypeAndPos($PType2_Name, $ParamPos, "backward", $Symbol, 1);
12362 my @Positions2 = find_ParamPair_Pos_byTypeAndPos($PType2_Name, $ParamPos, "backward", $Symbol, 2);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012363 if($#Positions1==-1 or $#Positions2>$#Positions1) {
12364 $ParamPos_Prev = "lost";
12365 }
12366 }
12367 else {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040012368 $ParamPos_Prev = find_ParamPair_Pos_byName($PName, $Symbol, 1);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012369 }
12370 if($ParamPos_Prev eq "lost")
12371 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012372 if($ParamPos>keys(%{$CompleteSignature{1}{$Symbol}{"Param"}})-1)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012373 {
12374 my $ProblemType = "Added_Parameter";
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040012375 if($PName=~/\Ap\d+\Z/) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012376 $ProblemType = "Added_Unnamed_Parameter";
12377 }
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040012378 %{$CompatProblems{$Level}{$Symbol}{$ProblemType}{showPos($ParamPos)." Parameter"}}=(
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040012379 "Target"=>$PName,
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012380 "Param_Pos"=>$ParamPos,
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040012381 "Param_Type"=>$PType2_Name,
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012382 "New_Signature"=>get_Signature($Symbol, 2) );
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012383 }
12384 else
12385 {
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +040012386 my %ParamType_Pure = get_PureType($PType2_Id, $TypeInfo{2});
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040012387 my $PairType_Id = $CompleteSignature{1}{$Symbol}{"Param"}{$ParamPos}{"type"};
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +040012388 my %PairType_Pure = get_PureType($PairType_Id, $TypeInfo{1});
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040012389 if(($ParamType_Pure{"Name"} eq $PairType_Pure{"Name"} or $PType2_Name eq $TypeInfo{1}{$PairType_Id}{"Name"})
12390 and find_ParamPair_Pos_byName($PName_Old, $Symbol, 2) eq "lost")
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012391 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040012392 if($PName_Old!~/\Ap\d+\Z/ and $PName!~/\Ap\d+\Z/)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012393 {
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040012394 %{$CompatProblems{$Level}{$Symbol}{"Renamed_Parameter"}{showPos($ParamPos)." Parameter"}}=(
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040012395 "Target"=>$PName_Old,
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012396 "Param_Pos"=>$ParamPos,
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040012397 "Param_Type"=>$PType2_Name,
12398 "Old_Value"=>$PName_Old,
12399 "New_Value"=>$PName,
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012400 "New_Signature"=>get_Signature($Symbol, 2) );
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012401 }
12402 }
12403 else
12404 {
12405 my $ProblemType = "Added_Middle_Parameter";
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040012406 if($PName=~/\Ap\d+\Z/) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012407 $ProblemType = "Added_Middle_Unnamed_Parameter";
12408 }
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040012409 %{$CompatProblems{$Level}{$Symbol}{$ProblemType}{showPos($ParamPos)." Parameter"}}=(
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040012410 "Target"=>$PName,
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012411 "Param_Pos"=>$ParamPos,
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040012412 "Param_Type"=>$PType2_Name,
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012413 "New_Signature"=>get_Signature($Symbol, 2) );
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012414 }
12415 }
12416 }
12417 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012418 foreach my $ParamPos (sort {int($a) <=> int($b)} keys(%{$CompleteSignature{1}{$Symbol}{"Param"}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012419 { # check relevant parameters
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040012420 my $PType1_Id = $CompleteSignature{1}{$Symbol}{"Param"}{$ParamPos}{"type"};
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012421 my $ParamName1 = $CompleteSignature{1}{$Symbol}{"Param"}{$ParamPos}{"name"};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012422 # FIXME: find relevant parameter by name
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012423 if(defined $CompleteSignature{2}{$PSymbol}{"Param"}{$ParamPos})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012424 {
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040012425 my $PType2_Id = $CompleteSignature{2}{$PSymbol}{"Param"}{$ParamPos}{"type"};
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012426 my $ParamName2 = $CompleteSignature{2}{$PSymbol}{"Param"}{$ParamPos}{"name"};
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040012427 if($TypeInfo{1}{$PType1_Id}{"Name"} eq $TypeInfo{2}{$PType2_Id}{"Name"}
12428 or ($ParamName1!~/\Ap\d+\Z/i and $ParamName1 eq $ParamName2)) {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012429 mergeParameters($Symbol, $PSymbol, $ParamPos, $ParamPos, $Level);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012430 }
12431 }
12432 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012433 foreach my $ParamPos (sort {int($a) <=> int($b)} keys(%{$CompleteSignature{1}{$Symbol}{"Param"}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012434 { # checking removed parameters
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040012435 my $PType1_Id = $CompleteSignature{1}{$Symbol}{"Param"}{$ParamPos}{"type"};
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040012436 my $PType1_Name = $TypeInfo{1}{$PType1_Id}{"Name"};
12437 last if($PType1_Name eq "...");
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012438 my $Parameter_Name = $CompleteSignature{1}{$Symbol}{"Param"}{$ParamPos}{"name"};
12439 my $Parameter_NewName = (defined $CompleteSignature{2}{$PSymbol}{"Param"}{$ParamPos})?$CompleteSignature{2}{$PSymbol}{"Param"}{$ParamPos}{"name"}:"";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012440 my $ParamPos_New = "-1";
12441 if($Parameter_Name=~/\Ap\d+\Z/i)
12442 { # removed unnamed parameter ( pN )
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040012443 my @Positions1 = find_ParamPair_Pos_byTypeAndPos($PType1_Name, $ParamPos, "forward", $Symbol, 1);
12444 my @Positions2 = find_ParamPair_Pos_byTypeAndPos($PType1_Name, $ParamPos, "forward", $Symbol, 2);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012445 if($#Positions2==-1 or $#Positions2<$#Positions1) {
12446 $ParamPos_New = "lost";
12447 }
12448 }
12449 else {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012450 $ParamPos_New = find_ParamPair_Pos_byName($Parameter_Name, $Symbol, 2);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012451 }
12452 if($ParamPos_New eq "lost")
12453 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012454 if($ParamPos>keys(%{$CompleteSignature{2}{$PSymbol}{"Param"}})-1)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012455 {
12456 my $ProblemType = "Removed_Parameter";
12457 if($Parameter_Name=~/\Ap\d+\Z/) {
12458 $ProblemType = "Removed_Unnamed_Parameter";
12459 }
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040012460 %{$CompatProblems{$Level}{$Symbol}{$ProblemType}{showPos($ParamPos)." Parameter"}}=(
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012461 "Target"=>$Parameter_Name,
12462 "Param_Pos"=>$ParamPos,
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040012463 "Param_Type"=>$PType1_Name,
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012464 "New_Signature"=>get_Signature($Symbol, 2) );
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012465 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012466 elsif($ParamPos<keys(%{$CompleteSignature{1}{$Symbol}{"Param"}})-1)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012467 {
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +040012468 my %ParamType_Pure = get_PureType($PType1_Id, $TypeInfo{1});
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040012469 my $PairType_Id = $CompleteSignature{2}{$PSymbol}{"Param"}{$ParamPos}{"type"};
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +040012470 my %PairType_Pure = get_PureType($PairType_Id, $TypeInfo{2});
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040012471 if(($ParamType_Pure{"Name"} eq $PairType_Pure{"Name"} or $PType1_Name eq $TypeInfo{2}{$PairType_Id}{"Name"})
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012472 and find_ParamPair_Pos_byName($Parameter_NewName, $Symbol, 1) eq "lost")
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012473 {
12474 if($Parameter_NewName!~/\Ap\d+\Z/ and $Parameter_Name!~/\Ap\d+\Z/)
12475 {
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040012476 %{$CompatProblems{$Level}{$Symbol}{"Renamed_Parameter"}{showPos($ParamPos)." Parameter"}}=(
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012477 "Target"=>$Parameter_Name,
12478 "Param_Pos"=>$ParamPos,
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040012479 "Param_Type"=>$PType1_Name,
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012480 "Old_Value"=>$Parameter_Name,
12481 "New_Value"=>$Parameter_NewName,
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012482 "New_Signature"=>get_Signature($Symbol, 2) );
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012483 }
12484 }
12485 else
12486 {
12487 my $ProblemType = "Removed_Middle_Parameter";
12488 if($Parameter_Name=~/\Ap\d+\Z/) {
12489 $ProblemType = "Removed_Middle_Unnamed_Parameter";
12490 }
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040012491 %{$CompatProblems{$Level}{$Symbol}{$ProblemType}{showPos($ParamPos)." Parameter"}}=(
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012492 "Target"=>$Parameter_Name,
12493 "Param_Pos"=>$ParamPos,
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040012494 "Param_Type"=>$PType1_Name,
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012495 "New_Signature"=>get_Signature($Symbol, 2) );
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012496 }
12497 }
12498 }
12499 }
12500 }
12501 # checking return type
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012502 my $ReturnType1_Id = $CompleteSignature{1}{$Symbol}{"Return"};
12503 my $ReturnType2_Id = $CompleteSignature{2}{$PSymbol}{"Return"};
12504 %SubProblems = detectTypeChange($ReturnType1_Id, $ReturnType2_Id, "Return", $Level);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012505 foreach my $SubProblemType (keys(%SubProblems))
12506 {
12507 my $New_Value = $SubProblems{$SubProblemType}{"New_Value"};
12508 my $Old_Value = $SubProblems{$SubProblemType}{"Old_Value"};
12509 my $NewProblemType = $SubProblemType;
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040012510 my $AddProblemType = undef;
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +040012511
12512 if($SubProblemType eq "Return_Type_And_Size"
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012513 and $CompleteSignature{1}{$Symbol}{"Data"}) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012514 $NewProblemType = "Global_Data_Type_And_Size";
12515 }
12516 elsif($SubProblemType eq "Return_Type")
12517 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012518 if($CompleteSignature{1}{$Symbol}{"Data"})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012519 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012520 if(removedQual($Old_Value, $New_Value, "const"))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012521 { # const -> non-const global data
12522 $NewProblemType = "Global_Data_Became_Non_Const";
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040012523 $AddProblemType = "Global_Data_Type";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012524 }
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040012525 elsif(addedQual($Old_Value, $New_Value, "const"))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012526 { # non-const -> const global data
12527 $NewProblemType = "Global_Data_Became_Const";
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040012528 $AddProblemType = "Global_Data_Type";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012529 }
12530 else {
12531 $NewProblemType = "Global_Data_Type";
12532 }
12533 }
12534 else
12535 {
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040012536 if(addedQual($Old_Value, $New_Value, "const"))
12537 {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012538 $NewProblemType = "Return_Type_Became_Const";
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040012539 $AddProblemType = "Return_Type";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012540 }
12541 }
12542 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012543 elsif($SubProblemType eq "Return_Type_Format")
12544 {
12545 if($CompleteSignature{1}{$Symbol}{"Data"}) {
12546 $NewProblemType = "Global_Data_Type_Format";
12547 }
12548 }
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +040012549 if($Level eq "Binary"
12550 and not $CompleteSignature{1}{$Symbol}{"Data"})
12551 {
12552 my ($Arch1, $Arch2) = (getArch(1), getArch(2));
12553 if($Arch1 eq "unknown" or $Arch2 eq "unknown")
12554 { # if one of the architectures is unknown
12555 # then set other arhitecture to unknown too
12556 ($Arch1, $Arch2) = ("unknown", "unknown");
12557 }
12558 my (%Conv1, %Conv2) = ();
12559 if($UseConv_Real{1} and $UseConv_Real{1})
12560 {
12561 %Conv1 = callingConvention_R_Real($CompleteSignature{1}{$Symbol});
12562 %Conv2 = callingConvention_R_Real($CompleteSignature{2}{$PSymbol});
12563 }
12564 else
12565 {
12566 %Conv1 = callingConvention_R_Model($CompleteSignature{1}{$Symbol}, $TypeInfo{1}, $Arch1, $OStarget, $WORD_SIZE{1});
12567 %Conv2 = callingConvention_R_Model($CompleteSignature{2}{$PSymbol}, $TypeInfo{2}, $Arch2, $OStarget, $WORD_SIZE{2});
12568 }
12569
12570 if($SubProblemType eq "Return_Type_Became_Void")
12571 {
12572 if(keys(%{$CompleteSignature{1}{$Symbol}{"Param"}}))
12573 { # parameters stack has been affected
12574 if($Conv1{"Method"} eq "stack") {
12575 $NewProblemType = "Return_Type_Became_Void_And_Stack_Layout";
12576 }
12577 elsif($Conv1{"Hidden"}) {
12578 $NewProblemType = "Return_Type_Became_Void_And_Register";
12579 }
12580 }
12581 }
12582 elsif($SubProblemType eq "Return_Type_From_Void")
12583 {
12584 if(keys(%{$CompleteSignature{1}{$Symbol}{"Param"}}))
12585 { # parameters stack has been affected
12586 if($Conv2{"Method"} eq "stack") {
12587 $NewProblemType = "Return_Type_From_Void_And_Stack_Layout";
12588 }
12589 elsif($Conv2{"Hidden"}) {
12590 $NewProblemType = "Return_Type_From_Void_And_Register";
12591 }
12592 }
12593 }
12594 elsif($SubProblemType eq "Return_Type"
12595 or $SubProblemType eq "Return_Type_And_Size"
12596 or $SubProblemType eq "Return_Type_Format")
12597 {
12598 if($Conv1{"Method"} ne $Conv2{"Method"})
12599 {
12600 if($Conv1{"Method"} eq "stack")
12601 { # returns in a register instead of a hidden first parameter
12602 $NewProblemType = "Return_Type_From_Stack_To_Register";
12603 }
12604 else {
12605 $NewProblemType = "Return_Type_From_Register_To_Stack";
12606 }
12607 }
12608 else
12609 {
12610 if($Conv1{"Method"} eq "reg")
12611 {
12612 if($Conv1{"Registers"} ne $Conv2{"Registers"})
12613 {
12614 if($Conv1{"Hidden"}) {
12615 $NewProblemType = "Return_Type_And_Register_Was_Hidden_Parameter";
12616 }
12617 elsif($Conv2{"Hidden"}) {
12618 $NewProblemType = "Return_Type_And_Register_Became_Hidden_Parameter";
12619 }
12620 else {
12621 $NewProblemType = "Return_Type_And_Register";
12622 }
12623 }
12624 }
12625 }
12626 }
12627 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012628 @{$CompatProblems{$Level}{$Symbol}{$NewProblemType}{"retval"}}{keys(%{$SubProblems{$SubProblemType}})} = values %{$SubProblems{$SubProblemType}};
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040012629 if(defined $AddProblemType) {
12630 @{$CompatProblems{$Level}{$Symbol}{$AddProblemType}{"retval"}}{keys(%{$SubProblems{$SubProblemType}})} = values %{$SubProblems{$SubProblemType}};
12631 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012632 }
12633 if($ReturnType1_Id and $ReturnType2_Id)
12634 {
12635 @RecurTypes = ();
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040012636 %SubProblems = mergeTypes($ReturnType1_Id, $ReturnType2_Id, $Level);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012637 foreach my $SubProblemType (keys(%SubProblems))
12638 { # add "Global_Data_Size" problem
12639 my $New_Value = $SubProblems{$SubProblemType}{"New_Value"};
12640 my $Old_Value = $SubProblems{$SubProblemType}{"Old_Value"};
12641 if($SubProblemType eq "DataType_Size"
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012642 and $CompleteSignature{1}{$Symbol}{"Data"}
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040012643 and get_PLevel($ReturnType1_Id, 1)==0)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012644 { # add a new problem
12645 %{$SubProblems{"Global_Data_Size"}} = %{$SubProblems{$SubProblemType}};
12646 }
12647 }
12648 foreach my $SubProblemType (keys(%SubProblems))
12649 {
12650 foreach my $SubLocation (keys(%{$SubProblems{$SubProblemType}}))
12651 {
12652 my $NewLocation = ($SubLocation)?"retval->".$SubLocation:"retval";
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012653 %{$CompatProblems{$Level}{$Symbol}{$SubProblemType}{$NewLocation}}=(
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040012654 "Return_Type_Name"=>$TypeInfo{1}{$ReturnType1_Id}{"Name"} );
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012655 @{$CompatProblems{$Level}{$Symbol}{$SubProblemType}{$NewLocation}}{keys(%{$SubProblems{$SubProblemType}{$SubLocation}})} = values %{$SubProblems{$SubProblemType}{$SubLocation}};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012656 if($SubLocation!~/\-\>/) {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040012657 $CompatProblems{$Level}{$Symbol}{$SubProblemType}{$NewLocation}{"Start_Type_Name"} = $TypeInfo{1}{$ReturnType1_Id}{"Name"};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012658 }
12659 }
12660 }
12661 }
12662
12663 # checking object type
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040012664 my $ObjTId1 = $CompleteSignature{1}{$Symbol}{"Class"};
12665 my $ObjTId2 = $CompleteSignature{2}{$PSymbol}{"Class"};
12666 if($ObjTId1 and $ObjTId2
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012667 and not $CompleteSignature{1}{$Symbol}{"Static"})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012668 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040012669 my $ThisPtr1_Id = getTypeIdByName($TypeInfo{1}{$ObjTId1}{"Name"}."*const", 1);
12670 my $ThisPtr2_Id = getTypeIdByName($TypeInfo{2}{$ObjTId2}{"Name"}."*const", 2);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012671 if($ThisPtr1_Id and $ThisPtr2_Id)
12672 {
12673 @RecurTypes = ();
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040012674 %SubProblems = mergeTypes($ThisPtr1_Id, $ThisPtr2_Id, $Level);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012675 foreach my $SubProblemType (keys(%SubProblems))
12676 {
12677 foreach my $SubLocation (keys(%{$SubProblems{$SubProblemType}}))
12678 {
12679 my $NewLocation = ($SubLocation)?"this->".$SubLocation:"this";
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012680 %{$CompatProblems{$Level}{$Symbol}{$SubProblemType}{$NewLocation}}=(
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040012681 "Object_Type_Name"=>$TypeInfo{1}{$ObjTId1}{"Name"} );
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012682 @{$CompatProblems{$Level}{$Symbol}{$SubProblemType}{$NewLocation}}{keys(%{$SubProblems{$SubProblemType}{$SubLocation}})} = values %{$SubProblems{$SubProblemType}{$SubLocation}};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012683 if($SubLocation!~/\-\>/) {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040012684 $CompatProblems{$Level}{$Symbol}{$SubProblemType}{$NewLocation}{"Start_Type_Name"} = $TypeInfo{1}{$ObjTId1}{"Name"};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012685 }
12686 }
12687 }
12688 }
12689 }
12690 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012691 if($Level eq "Binary") {
12692 mergeVTables($Level);
12693 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +040012694 foreach my $Symbol (keys(%{$CompatProblems{$Level}})) {
12695 $CheckedSymbols{$Level}{$Symbol} = 1;
12696 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012697}
12698
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040012699sub rmQuals($$)
12700{
12701 my ($Value, $Qual) = @_;
12702 if(not $Qual) {
12703 return $Value;
12704 }
12705 if($Qual eq "all")
12706 { # all quals
12707 $Qual = "const|volatile|restrict";
12708 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040012709 while($Value=~s/\b$Qual\b//) {
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040012710 $Value = formatName($Value, "T");
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040012711 }
12712 return $Value;
12713}
12714
12715sub cmpBTypes($$$$)
12716{
12717 my ($T1, $T2, $V1, $V2) = @_;
12718 $T1 = uncover_typedefs($T1, $V1);
12719 $T2 = uncover_typedefs($T2, $V2);
12720 return (rmQuals($T1, "all") eq rmQuals($T2, "all"));
12721}
12722
12723sub addedQual($$$)
12724{
12725 my ($Old_Value, $New_Value, $Qual) = @_;
Andrey Ponomarenko85043792012-05-14 16:48:07 +040012726 return removedQual_($New_Value, $Old_Value, 2, 1, $Qual);
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040012727}
12728
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012729sub removedQual($$$)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012730{
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012731 my ($Old_Value, $New_Value, $Qual) = @_;
Andrey Ponomarenko85043792012-05-14 16:48:07 +040012732 return removedQual_($Old_Value, $New_Value, 1, 2, $Qual);
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040012733}
12734
12735sub removedQual_($$$$$)
12736{
12737 my ($Old_Value, $New_Value, $V1, $V2, $Qual) = @_;
12738 $Old_Value = uncover_typedefs($Old_Value, $V1);
12739 $New_Value = uncover_typedefs($New_Value, $V2);
12740 if($Old_Value eq $New_Value)
12741 { # equal types
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012742 return 0;
12743 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040012744 if($Old_Value!~/\b$Qual\b/)
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040012745 { # without a qual
12746 return 0;
12747 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040012748 elsif($New_Value!~/\b$Qual\b/)
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040012749 { # became non-qual
12750 return 1;
12751 }
12752 else
12753 {
12754 my @BQ1 = getQualModel($Old_Value, $Qual);
12755 my @BQ2 = getQualModel($New_Value, $Qual);
12756 foreach (0 .. $#BQ1)
12757 { # removed qual
12758 if($BQ1[$_]==1
12759 and $BQ2[$_]!=1)
12760 {
12761 return 2;
12762 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012763 }
12764 }
12765 return 0;
12766}
12767
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040012768sub getQualModel($$)
12769{
12770 my ($Value, $Qual) = @_;
12771 if(not $Qual) {
12772 return $Value;
12773 }
12774
12775 # cleaning
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040012776 while($Value=~/(\w+)/ and $1 ne $Qual) {
12777 $Value=~s/\b$1\b//g;
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040012778 }
12779 $Value=~s/[^\*\&\w]+//g;
12780
12781 # modeling
12782 # int*const*const == 011
12783 # int**const == 001
12784 my @Model = ();
12785 my @Elems = split(/[\*\&]/, $Value);
12786 if(not @Elems) {
12787 return (0);
12788 }
12789 foreach (@Elems)
12790 {
12791 if($_ eq $Qual) {
12792 push(@Model, 1);
12793 }
12794 else {
12795 push(@Model, 0);
12796 }
12797 }
12798
12799 return @Model;
12800}
12801
12802sub showVal($$$)
12803{
12804 my ($Value, $TypeId, $LibVersion) = @_;
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +040012805 my %PureType = get_PureType($TypeId, $TypeInfo{$LibVersion});
Andrey Ponomarenkoa01311b2012-06-08 17:20:02 +040012806 my $TName = uncover_typedefs($PureType{"Name"}, $LibVersion);
Andrey Ponomarenko01117f12012-06-26 12:23:02 +040012807 if(substr($Value, 0, 2) eq "_Z")
12808 {
12809 if(my $Unmangled = $tr_name{$Value}) {
12810 return $Unmangled;
12811 }
12812 }
Andrey Ponomarenko07aea072012-11-12 16:15:07 +040012813 elsif($TName=~/\A(char(| const)\*|std::(string(| const)|basic_string<char>(|const))(|&))\Z/)
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040012814 { # strings
12815 return "\"$Value\"";
12816 }
Andrey Ponomarenkoa01311b2012-06-08 17:20:02 +040012817 elsif($TName=~/\Achar(| const)\Z/)
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040012818 { # characters
12819 return "\'$Value\'";
12820 }
12821 return $Value;
12822}
12823
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012824sub mergeParameters($$$$$)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012825{
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012826 my ($Symbol, $PSymbol, $ParamPos1, $ParamPos2, $Level) = @_;
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040012827 if(not $Symbol) {
12828 return;
12829 }
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040012830 my $PType1_Id = $CompleteSignature{1}{$Symbol}{"Param"}{$ParamPos1}{"type"};
12831 my $PName1 = $CompleteSignature{1}{$Symbol}{"Param"}{$ParamPos1}{"name"};
12832 my $PType2_Id = $CompleteSignature{2}{$PSymbol}{"Param"}{$ParamPos2}{"type"};
12833 my $PName2 = $CompleteSignature{2}{$PSymbol}{"Param"}{$ParamPos2}{"name"};
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040012834 if(not $PType1_Id
12835 or not $PType2_Id) {
12836 return;
12837 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040012838 my %Type1 = get_Type($PType1_Id, 1);
12839 my %Type2 = get_Type($PType2_Id, 2);
12840 my %BaseType1 = get_BaseType($PType1_Id, 1);
12841 my %BaseType2 = get_BaseType($PType2_Id, 2);
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040012842 my $Parameter_Location = ($PName1)?$PName1:showPos($ParamPos1)." Parameter";
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012843 if($Level eq "Binary")
12844 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040012845 if(checkDump(1, "2.6.1") and checkDump(2, "2.6.1"))
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012846 { # "reg" attribute added in ACC 1.95.1 (dump 2.6.1 format)
12847 if($CompleteSignature{1}{$Symbol}{"Param"}{$ParamPos1}{"reg"}
12848 and not $CompleteSignature{2}{$PSymbol}{"Param"}{$ParamPos2}{"reg"})
12849 {
12850 %{$CompatProblems{$Level}{$Symbol}{"Parameter_Became_Non_Register"}{$Parameter_Location}}=(
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040012851 "Target"=>$PName1,
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012852 "Param_Pos"=>$ParamPos1 );
12853 }
12854 elsif(not $CompleteSignature{1}{$Symbol}{"Param"}{$ParamPos1}{"reg"}
12855 and $CompleteSignature{2}{$PSymbol}{"Param"}{$ParamPos2}{"reg"})
12856 {
12857 %{$CompatProblems{$Level}{$Symbol}{"Parameter_Became_Register"}{$Parameter_Location}}=(
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040012858 "Target"=>$PName1,
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012859 "Param_Pos"=>$ParamPos1 );
12860 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012861 }
12862 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040012863 if(checkDump(1, "2.0") and checkDump(2, "2.0"))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012864 { # "default" attribute added in ACC 1.22 (dump 2.0 format)
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040012865 my $Value_Old = $CompleteSignature{1}{$Symbol}{"Param"}{$ParamPos1}{"default"};
12866 my $Value_New = $CompleteSignature{2}{$PSymbol}{"Param"}{$ParamPos2}{"default"};
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040012867 if(not checkDump(1, "2.13")
12868 and checkDump(2, "2.13"))
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040012869 { # support for old ABI dumps
12870 if(defined $Value_Old and defined $Value_New)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012871 {
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040012872 if($Type1{"Name"} eq "bool"
12873 and $Value_Old eq "false" and $Value_New eq "0")
12874 { # int class::method ( bool p = 0 );
12875 # old ABI dumps: "false"
12876 # new ABI dumps: "0"
12877 $Value_Old = "0";
12878 }
12879 }
12880 }
Andrey Ponomarenko01117f12012-06-26 12:23:02 +040012881 if(not checkDump(1, "2.18")
12882 and checkDump(2, "2.18"))
12883 { # support for old ABI dumps
12884 if(not defined $Value_Old
12885 and substr($Value_New, 0, 2) eq "_Z") {
12886 $Value_Old = $Value_New;
12887 }
12888 }
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040012889 if(defined $Value_Old)
12890 {
12891 $Value_Old = showVal($Value_Old, $PType1_Id, 1);
12892 if(defined $Value_New)
12893 {
12894 $Value_New = showVal($Value_New, $PType2_Id, 2);
12895 if($Value_Old ne $Value_New)
12896 { # FIXME: how to distinguish "0" and 0 (NULL)
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012897 %{$CompatProblems{$Level}{$Symbol}{"Parameter_Default_Value_Changed"}{$Parameter_Location}}=(
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040012898 "Target"=>$PName1,
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012899 "Param_Pos"=>$ParamPos1,
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040012900 "Old_Value"=>$Value_Old,
12901 "New_Value"=>$Value_New );
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012902 }
12903 }
12904 else
12905 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012906 %{$CompatProblems{$Level}{$Symbol}{"Parameter_Default_Value_Removed"}{$Parameter_Location}}=(
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040012907 "Target"=>$PName1,
12908 "Param_Pos"=>$ParamPos1,
12909 "Old_Value"=>$Value_Old );
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012910 }
12911 }
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040012912 elsif(defined $Value_New)
12913 {
12914 $Value_New = showVal($Value_New, $PType2_Id, 2);
12915 %{$CompatProblems{$Level}{$Symbol}{"Parameter_Default_Value_Added"}{$Parameter_Location}}=(
12916 "Target"=>$PName1,
12917 "Param_Pos"=>$ParamPos1,
12918 "New_Value"=>$Value_New );
12919 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012920 }
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040012921 if($PName1 and $PName2 and $PName1 ne $PName2
12922 and $PType1_Id!=-1 and $PType2_Id!=-1
12923 and $PName1!~/\Ap\d+\Z/ and $PName2!~/\Ap\d+\Z/)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012924 { # except unnamed "..." value list (Id=-1)
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040012925 %{$CompatProblems{$Level}{$Symbol}{"Renamed_Parameter"}{showPos($ParamPos1)." Parameter"}}=(
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040012926 "Target"=>$PName1,
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012927 "Param_Pos"=>$ParamPos1,
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040012928 "Param_Type"=>$TypeInfo{1}{$PType1_Id}{"Name"},
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040012929 "Old_Value"=>$PName1,
12930 "New_Value"=>$PName2,
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012931 "New_Signature"=>get_Signature($Symbol, 2) );
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012932 }
12933 # checking type change (replace)
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040012934 my %SubProblems = detectTypeChange($PType1_Id, $PType2_Id, "Parameter", $Level);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012935 foreach my $SubProblemType (keys(%SubProblems))
12936 { # add new problems, remove false alarms
12937 my $New_Value = $SubProblems{$SubProblemType}{"New_Value"};
12938 my $Old_Value = $SubProblems{$SubProblemType}{"Old_Value"};
12939 if($SubProblemType eq "Parameter_Type")
12940 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040012941 if(checkDump(1, "2.6") and checkDump(2, "2.6"))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012942 {
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040012943 if(my $RA = addedQual($Old_Value, $New_Value, "restrict"))
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012944 {
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040012945 %{$SubProblems{"Parameter_Became_Restrict"}} = %{$SubProblems{$SubProblemType}};
12946 if($Level eq "Source"
12947 and cmpBTypes($Old_Value, $New_Value, 1, 2)) {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012948 delete($SubProblems{$SubProblemType});
12949 }
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040012950 }
12951 elsif(my $RR = removedQual($Old_Value, $New_Value, "restrict"))
12952 {
12953 %{$SubProblems{"Parameter_Became_NonRestrict"}} = %{$SubProblems{$SubProblemType}};
12954 if($Level eq "Source"
12955 and cmpBTypes($Old_Value, $New_Value, 1, 2)) {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012956 delete($SubProblems{$SubProblemType});
12957 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012958 }
12959 }
12960 if($Type2{"Type"} eq "Const" and $BaseType2{"Name"} eq $Type1{"Name"}
12961 and $Type1{"Type"}=~/Intrinsic|Class|Struct|Union|Enum/)
12962 { # int to "int const"
12963 delete($SubProblems{$SubProblemType});
12964 }
12965 if($Type1{"Type"} eq "Const" and $BaseType1{"Name"} eq $Type2{"Name"}
12966 and $Type2{"Type"}=~/Intrinsic|Class|Struct|Union|Enum/)
12967 { # "int const" to int
12968 delete($SubProblems{$SubProblemType});
12969 }
12970 }
12971 }
12972 foreach my $SubProblemType (keys(%SubProblems))
12973 { # modify/register problems
12974 my $New_Value = $SubProblems{$SubProblemType}{"New_Value"};
12975 my $Old_Value = $SubProblems{$SubProblemType}{"Old_Value"};
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +040012976 my $New_Size = $SubProblems{$SubProblemType}{"New_Size"};
12977 my $Old_Size = $SubProblems{$SubProblemType}{"Old_Size"};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012978 my $NewProblemType = $SubProblemType;
12979 if($Old_Value eq "..." and $New_Value ne "...")
12980 { # change from "..." to "int"
12981 if($ParamPos1==0)
12982 { # ISO C requires a named argument before "..."
12983 next;
12984 }
12985 $NewProblemType = "Parameter_Became_NonVaList";
12986 }
12987 elsif($New_Value eq "..." and $Old_Value ne "...")
12988 { # change from "int" to "..."
12989 if($ParamPos2==0)
12990 { # ISO C requires a named argument before "..."
12991 next;
12992 }
12993 $NewProblemType = "Parameter_Became_VaList";
12994 }
12995 elsif($SubProblemType eq "Parameter_Type"
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012996 and removedQual($Old_Value, $New_Value, "const"))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012997 { # parameter: "const" to non-"const"
12998 $NewProblemType = "Parameter_Became_Non_Const";
12999 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040013000 elsif($Level eq "Binary" and ($SubProblemType eq "Parameter_Type_And_Size"
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +040013001 or $SubProblemType eq "Parameter_Type" or $SubProblemType eq "Parameter_Type_Format"))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013002 {
13003 my ($Arch1, $Arch2) = (getArch(1), getArch(2));
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +040013004 if($Arch1 eq "unknown"
13005 or $Arch2 eq "unknown")
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013006 { # if one of the architectures is unknown
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +040013007 # then set other arhitecture to unknown too
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013008 ($Arch1, $Arch2) = ("unknown", "unknown");
13009 }
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +040013010 my (%Conv1, %Conv2) = ();
13011 if($UseConv_Real{1} and $UseConv_Real{1})
13012 { # real
13013 %Conv1 = callingConvention_P_Real($CompleteSignature{1}{$Symbol}, $ParamPos1);
13014 %Conv2 = callingConvention_P_Real($CompleteSignature{2}{$Symbol}, $ParamPos2);
13015 }
13016 else
13017 { # model
13018 %Conv1 = callingConvention_P_Model($CompleteSignature{1}{$Symbol}, $ParamPos1, $TypeInfo{1}, $Arch1, $OStarget, $WORD_SIZE{1});
13019 %Conv2 = callingConvention_P_Model($CompleteSignature{2}{$Symbol}, $ParamPos2, $TypeInfo{2}, $Arch2, $OStarget, $WORD_SIZE{2});
13020 }
13021 if($Conv1{"Method"} eq $Conv2{"Method"})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013022 {
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +040013023 if($Conv1{"Method"} eq "stack")
13024 {
13025 if($Old_Size ne $New_Size) { # FIXME: isMemPadded, getOffset
13026 $NewProblemType = "Parameter_Type_And_Stack";
13027 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013028 }
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +040013029 elsif($Conv1{"Method"} eq "reg")
13030 {
13031 if($Conv1{"Registers"} ne $Conv2{"Registers"}) {
13032 $NewProblemType = "Parameter_Type_And_Register";
13033 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013034 }
13035 }
13036 else
13037 {
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +040013038 if($Conv1{"Method"} eq "stack") {
13039 $NewProblemType = "Parameter_Type_From_Stack_To_Register";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013040 }
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +040013041 elsif($Conv1{"Method"} eq "register") {
13042 $NewProblemType = "Parameter_Type_From_Register_To_Stack";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013043 }
13044 }
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +040013045 $SubProblems{$SubProblemType}{"Old_Reg"} = $Conv1{"Registers"};
13046 $SubProblems{$SubProblemType}{"New_Reg"} = $Conv2{"Registers"};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013047 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040013048 %{$CompatProblems{$Level}{$Symbol}{$NewProblemType}{$Parameter_Location}}=(
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040013049 "Target"=>$PName1,
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013050 "Param_Pos"=>$ParamPos1,
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040013051 "New_Signature"=>get_Signature($Symbol, 2) );
13052 @{$CompatProblems{$Level}{$Symbol}{$NewProblemType}{$Parameter_Location}}{keys(%{$SubProblems{$SubProblemType}})} = values %{$SubProblems{$SubProblemType}};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013053 }
13054 @RecurTypes = ();
13055 # checking type definition changes
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040013056 my %SubProblems_Merge = mergeTypes($PType1_Id, $PType2_Id, $Level);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013057 foreach my $SubProblemType (keys(%SubProblems_Merge))
13058 {
13059 foreach my $SubLocation (keys(%{$SubProblems_Merge{$SubProblemType}}))
13060 {
13061 my $NewProblemType = $SubProblemType;
13062 if($SubProblemType eq "DataType_Size")
13063 {
13064 my $InitialType_Type = $SubProblems_Merge{$SubProblemType}{$SubLocation}{"InitialType_Type"};
13065 if($InitialType_Type!~/\A(Pointer|Ref)\Z/ and $SubLocation!~/\-\>/)
13066 { # stack has been affected
13067 $NewProblemType = "DataType_Size_And_Stack";
13068 }
13069 }
13070 my $NewLocation = ($SubLocation)?$Parameter_Location."->".$SubLocation:$Parameter_Location;
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040013071 %{$CompatProblems{$Level}{$Symbol}{$NewProblemType}{$NewLocation}}=(
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040013072 "Param_Type"=>$TypeInfo{1}{$PType1_Id}{"Name"},
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013073 "Param_Pos"=>$ParamPos1,
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040013074 "Param_Name"=>$PName1 );
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040013075 @{$CompatProblems{$Level}{$Symbol}{$NewProblemType}{$NewLocation}}{keys(%{$SubProblems_Merge{$SubProblemType}{$SubLocation}})} = values %{$SubProblems_Merge{$SubProblemType}{$SubLocation}};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013076 if($SubLocation!~/\-\>/) {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040013077 $CompatProblems{$Level}{$Symbol}{$NewProblemType}{$NewLocation}{"Start_Type_Name"} = $TypeInfo{1}{$PType1_Id}{"Name"};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013078 }
13079 }
13080 }
13081}
13082
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013083sub find_ParamPair_Pos_byName($$$)
13084{
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040013085 my ($Name, $Symbol, $LibVersion) = @_;
13086 foreach my $ParamPos (sort {int($a)<=>int($b)} keys(%{$CompleteSignature{$LibVersion}{$Symbol}{"Param"}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013087 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040013088 next if(not defined $CompleteSignature{$LibVersion}{$Symbol}{"Param"}{$ParamPos});
13089 if($CompleteSignature{$LibVersion}{$Symbol}{"Param"}{$ParamPos}{"name"} eq $Name)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013090 {
13091 return $ParamPos;
13092 }
13093 }
13094 return "lost";
13095}
13096
13097sub find_ParamPair_Pos_byTypeAndPos($$$$$)
13098{
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040013099 my ($TypeName, $MediumPos, $Order, $Symbol, $LibVersion) = @_;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013100 my @Positions = ();
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040013101 foreach my $ParamPos (sort {int($a)<=>int($b)} keys(%{$CompleteSignature{$LibVersion}{$Symbol}{"Param"}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013102 {
13103 next if($Order eq "backward" and $ParamPos>$MediumPos);
13104 next if($Order eq "forward" and $ParamPos<$MediumPos);
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040013105 next if(not defined $CompleteSignature{$LibVersion}{$Symbol}{"Param"}{$ParamPos});
13106 my $PTypeId = $CompleteSignature{$LibVersion}{$Symbol}{"Param"}{$ParamPos}{"type"};
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040013107 if($TypeInfo{$LibVersion}{$PTypeId}{"Name"} eq $TypeName) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013108 push(@Positions, $ParamPos);
13109 }
13110 }
13111 return @Positions;
13112}
13113
13114sub getTypeIdByName($$)
13115{
13116 my ($TypeName, $Version) = @_;
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040013117 return $TName_Tid{$Version}{formatName($TypeName, "T")};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013118}
13119
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040013120sub checkFormatChange($$$)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013121{
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040013122 my ($Type1_Id, $Type2_Id, $Level) = @_;
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +040013123 my %Type1_Pure = get_PureType($Type1_Id, $TypeInfo{1});
13124 my %Type2_Pure = get_PureType($Type2_Id, $TypeInfo{2});
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013125 if($Type1_Pure{"Name"} eq $Type2_Pure{"Name"})
13126 { # equal types
13127 return 0;
13128 }
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040013129 if($Type1_Pure{"Name"} eq "void")
13130 { # from void* to something
13131 return 0;
13132 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013133 if($Type1_Pure{"Name"}=~/\*/
13134 or $Type2_Pure{"Name"}=~/\*/)
13135 { # compared in detectTypeChange()
13136 return 0;
13137 }
13138 my %FloatType = map {$_=>1} (
13139 "float",
13140 "double",
13141 "long double"
13142 );
13143 if($Type1_Pure{"Type"} ne $Type2_Pure{"Type"})
13144 { # different types
13145 if($Type1_Pure{"Type"} eq "Intrinsic"
13146 and $Type2_Pure{"Type"} eq "Enum")
13147 { # "int" to "enum"
13148 return 0;
13149 }
13150 elsif($Type2_Pure{"Type"} eq "Intrinsic"
13151 and $Type1_Pure{"Type"} eq "Enum")
13152 { # "enum" to "int"
13153 return 0;
13154 }
13155 else
13156 { # "union" to "struct"
13157 # ...
13158 return 1;
13159 }
13160 }
13161 else
13162 {
13163 if($Type1_Pure{"Type"} eq "Intrinsic")
13164 {
13165 if($FloatType{$Type1_Pure{"Name"}}
13166 or $FloatType{$Type2_Pure{"Name"}})
13167 { # "float" to "double"
13168 # "float" to "int"
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040013169 if($Level eq "Source")
13170 { # Safe
13171 return 0;
13172 }
13173 else {
13174 return 1;
13175 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013176 }
13177 }
13178 elsif($Type1_Pure{"Type"}=~/Class|Struct|Union|Enum/)
13179 {
13180 my @Membs1 = keys(%{$Type1_Pure{"Memb"}});
13181 my @Membs2 = keys(%{$Type2_Pure{"Memb"}});
13182 if($#Membs1!=$#Membs2)
13183 { # different number of elements
13184 return 1;
13185 }
13186 if($Type1_Pure{"Type"} eq "Enum")
13187 {
13188 foreach my $Pos (@Membs1)
13189 { # compare elements by name and value
13190 if($Type1_Pure{"Memb"}{$Pos}{"name"} ne $Type2_Pure{"Memb"}{$Pos}{"name"}
13191 or $Type1_Pure{"Memb"}{$Pos}{"value"} ne $Type2_Pure{"Memb"}{$Pos}{"value"})
13192 { # different names
13193 return 1;
13194 }
13195 }
13196 }
13197 else
13198 {
13199 foreach my $Pos (@Membs1)
13200 { # compare elements by type name
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040013201 my $MT1 = $TypeInfo{1}{$Type1_Pure{"Memb"}{$Pos}{"type"}}{"Name"};
13202 my $MT2 = $TypeInfo{2}{$Type2_Pure{"Memb"}{$Pos}{"type"}}{"Name"};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013203 if($MT1 ne $MT2)
13204 { # different types
13205 return 1;
13206 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040013207 if($Level eq "Source")
13208 {
13209 if($Type1_Pure{"Memb"}{$Pos}{"name"} ne $Type2_Pure{"Memb"}{$Pos}{"name"})
13210 { # different names
13211 return 1;
13212 }
13213 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013214 }
13215 }
13216 }
13217 }
13218 return 0;
13219}
13220
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040013221sub detectTypeChange($$$$)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013222{
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040013223 my ($Type1_Id, $Type2_Id, $Prefix, $Level) = @_;
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040013224 if(not $Type1_Id or not $Type2_Id) {
13225 return ();
13226 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013227 my %LocalProblems = ();
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040013228 my %Type1 = get_Type($Type1_Id, 1);
13229 my %Type2 = get_Type($Type2_Id, 2);
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +040013230 my %Type1_Pure = get_PureType($Type1_Id, $TypeInfo{1});
13231 my %Type2_Pure = get_PureType($Type2_Id, $TypeInfo{2});
13232 my %Type1_Base = ($Type1_Pure{"Type"} eq "Array")?get_OneStep_BaseType($Type1_Pure{"Tid"}, $TypeInfo{1}):get_BaseType($Type1_Id, 1);
13233 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 +040013234 my $Type1_PLevel = get_PLevel($Type1_Id, 1);
13235 my $Type2_PLevel = get_PLevel($Type2_Id, 2);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013236 return () if(not $Type1{"Name"} or not $Type2{"Name"});
13237 return () if(not $Type1_Base{"Name"} or not $Type2_Base{"Name"});
13238 return () if($Type1_PLevel eq "" or $Type2_PLevel eq "");
13239 if($Type1_Base{"Name"} ne $Type2_Base{"Name"}
13240 and ($Type1{"Name"} eq $Type2{"Name"} or ($Type1_PLevel>=1 and $Type1_PLevel==$Type2_PLevel
13241 and $Type1_Base{"Name"} ne "void" and $Type2_Base{"Name"} ne "void")))
13242 { # base type change
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040013243 if($Type1{"Name"} eq $Type2{"Name"})
13244 {
13245 if($Type1{"Type"} eq "Typedef" and $Type2{"Type"} eq "Typedef")
13246 { # will be reported in mergeTypes() as typedef problem
13247 return ();
13248 }
13249 my %Typedef_1 = goToFirst($Type1{"Tid"}, 1, "Typedef");
13250 my %Typedef_2 = goToFirst($Type2{"Tid"}, 2, "Typedef");
13251 if(%Typedef_1 and %Typedef_2)
13252 {
13253 if($Typedef_1{"Name"} eq $Typedef_2{"Name"}
13254 and $Typedef_1{"Type"} eq "Typedef" and $Typedef_2{"Type"} eq "Typedef")
13255 { # const Typedef
13256 return ();
13257 }
13258 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013259 }
13260 if($Type1_Base{"Name"}!~/anon\-/ and $Type2_Base{"Name"}!~/anon\-/)
13261 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040013262 if($Level eq "Binary"
13263 and $Type1_Base{"Size"} ne $Type2_Base{"Size"}
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013264 and $Type1_Base{"Size"} and $Type2_Base{"Size"})
13265 {
13266 %{$LocalProblems{$Prefix."_BaseType_And_Size"}}=(
13267 "Old_Value"=>$Type1_Base{"Name"},
13268 "New_Value"=>$Type2_Base{"Name"},
13269 "Old_Size"=>$Type1_Base{"Size"}*$BYTE_SIZE,
13270 "New_Size"=>$Type2_Base{"Size"}*$BYTE_SIZE,
13271 "InitialType_Type"=>$Type1_Pure{"Type"});
13272 }
13273 else
13274 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040013275 if(checkFormatChange($Type1_Base{"Tid"}, $Type2_Base{"Tid"}, $Level))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013276 { # format change
13277 %{$LocalProblems{$Prefix."_BaseType_Format"}}=(
13278 "Old_Value"=>$Type1_Base{"Name"},
13279 "New_Value"=>$Type2_Base{"Name"},
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +040013280 "Old_Size"=>$Type1_Base{"Size"}*$BYTE_SIZE,
13281 "New_Size"=>$Type2_Base{"Size"}*$BYTE_SIZE,
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013282 "InitialType_Type"=>$Type1_Pure{"Type"});
13283 }
13284 elsif(tNameLock($Type1_Base{"Tid"}, $Type2_Base{"Tid"}))
13285 {
13286 %{$LocalProblems{$Prefix."_BaseType"}}=(
13287 "Old_Value"=>$Type1_Base{"Name"},
13288 "New_Value"=>$Type2_Base{"Name"},
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +040013289 "Old_Size"=>$Type1_Base{"Size"}*$BYTE_SIZE,
13290 "New_Size"=>$Type2_Base{"Size"}*$BYTE_SIZE,
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013291 "InitialType_Type"=>$Type1_Pure{"Type"});
13292 }
13293 }
13294 }
13295 }
13296 elsif($Type1{"Name"} ne $Type2{"Name"})
13297 { # type change
13298 if($Type1{"Name"}!~/anon\-/ and $Type2{"Name"}!~/anon\-/)
13299 {
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +040013300 if($Prefix eq "Return"
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013301 and $Type1_Pure{"Name"} eq "void")
13302 {
13303 %{$LocalProblems{"Return_Type_From_Void"}}=(
13304 "New_Value"=>$Type2{"Name"},
13305 "New_Size"=>$Type2{"Size"}*$BYTE_SIZE,
13306 "InitialType_Type"=>$Type1_Pure{"Type"});
13307 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013308 elsif($Prefix eq "Return"
13309 and $Type2_Pure{"Name"} eq "void")
13310 {
13311 %{$LocalProblems{"Return_Type_Became_Void"}}=(
13312 "Old_Value"=>$Type1{"Name"},
13313 "Old_Size"=>$Type1{"Size"}*$BYTE_SIZE,
13314 "InitialType_Type"=>$Type1_Pure{"Type"});
13315 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013316 else
13317 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040013318 if($Level eq "Binary"
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040013319 and $Type1{"Size"} and $Type2{"Size"}
13320 and $Type1{"Size"} ne $Type2{"Size"})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013321 {
13322 %{$LocalProblems{$Prefix."_Type_And_Size"}}=(
13323 "Old_Value"=>$Type1{"Name"},
13324 "New_Value"=>$Type2{"Name"},
13325 "Old_Size"=>$Type1{"Size"}*$BYTE_SIZE,
13326 "New_Size"=>$Type2{"Size"}*$BYTE_SIZE,
13327 "InitialType_Type"=>$Type1_Pure{"Type"});
13328 }
13329 else
13330 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040013331 if(checkFormatChange($Type1_Id, $Type2_Id, $Level))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013332 { # format change
13333 %{$LocalProblems{$Prefix."_Type_Format"}}=(
13334 "Old_Value"=>$Type1{"Name"},
13335 "New_Value"=>$Type2{"Name"},
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +040013336 "Old_Size"=>$Type1{"Size"}*$BYTE_SIZE,
13337 "New_Size"=>$Type2{"Size"}*$BYTE_SIZE,
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013338 "InitialType_Type"=>$Type1_Pure{"Type"});
13339 }
13340 elsif(tNameLock($Type1_Id, $Type2_Id))
13341 { # FIXME: correct this condition
13342 %{$LocalProblems{$Prefix."_Type"}}=(
13343 "Old_Value"=>$Type1{"Name"},
13344 "New_Value"=>$Type2{"Name"},
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +040013345 "Old_Size"=>$Type1{"Size"}*$BYTE_SIZE,
13346 "New_Size"=>$Type2{"Size"}*$BYTE_SIZE,
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013347 "InitialType_Type"=>$Type1_Pure{"Type"});
13348 }
13349 }
13350 }
13351 }
13352 }
13353 if($Type1_PLevel!=$Type2_PLevel)
13354 {
13355 if($Type1{"Name"} ne "void" and $Type1{"Name"} ne "..."
13356 and $Type2{"Name"} ne "void" and $Type2{"Name"} ne "...")
13357 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040013358 if($Level eq "Source")
13359 {
13360 %{$LocalProblems{$Prefix."_PointerLevel"}}=(
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013361 "Old_Value"=>$Type1_PLevel,
13362 "New_Value"=>$Type2_PLevel);
13363 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040013364 else
13365 {
13366 if($Type2_PLevel>$Type1_PLevel) {
13367 %{$LocalProblems{$Prefix."_PointerLevel_Increased"}}=(
13368 "Old_Value"=>$Type1_PLevel,
13369 "New_Value"=>$Type2_PLevel);
13370 }
13371 else {
13372 %{$LocalProblems{$Prefix."_PointerLevel_Decreased"}}=(
13373 "Old_Value"=>$Type1_PLevel,
13374 "New_Value"=>$Type2_PLevel);
13375 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013376 }
13377 }
13378 }
13379 if($Type1_Pure{"Type"} eq "Array")
13380 { # base_type[N] -> base_type[N]
13381 # base_type: older_structure -> typedef to newer_structure
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040013382 my %SubProblems = detectTypeChange($Type1_Base{"Tid"}, $Type2_Base{"Tid"}, $Prefix, $Level);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013383 foreach my $SubProblemType (keys(%SubProblems))
13384 {
13385 $SubProblemType=~s/_Type/_BaseType/g;
13386 next if(defined $LocalProblems{$SubProblemType});
13387 foreach my $Attr (keys(%{$SubProblems{$SubProblemType}})) {
13388 $LocalProblems{$SubProblemType}{$Attr} = $SubProblems{$SubProblemType}{$Attr};
13389 }
13390 }
13391 }
13392 return %LocalProblems;
13393}
13394
13395sub tNameLock($$)
13396{
13397 my ($Tid1, $Tid2) = @_;
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040013398 my $Changed = 0;
13399 if(differentDumps("G"))
13400 { # different GCC versions
13401 $Changed = 1;
13402 }
13403 elsif(differentDumps("V"))
13404 { # different versions of ABI dumps
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040013405 if(not checkDump(1, "2.13")
13406 or not checkDump(2, "2.13"))
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040013407 { # latest names update
13408 # 2.6: added restrict qualifier
13409 # 2.13: added missed typedefs to qualified types
13410 $Changed = 1;
13411 }
13412 }
13413 if($Changed)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013414 { # different formats
13415 if($UseOldDumps)
13416 { # old dumps
13417 return 0;
13418 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040013419 my $TN1 = $TypeInfo{1}{$Tid1}{"Name"};
13420 my $TN2 = $TypeInfo{2}{$Tid2}{"Name"};
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040013421
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040013422 my $TT1 = $TypeInfo{1}{$Tid1}{"Type"};
13423 my $TT2 = $TypeInfo{2}{$Tid2}{"Type"};
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040013424
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040013425 my %Base1 = get_Type($Tid1, 1);
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040013426 while(defined $Base1{"Type"} and $Base1{"Type"} eq "Typedef") {
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +040013427 %Base1 = get_OneStep_BaseType($Base1{"Tid"}, $TypeInfo{1});
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013428 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040013429 my %Base2 = get_Type($Tid2, 2);
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040013430 while(defined $Base2{"Type"} and $Base2{"Type"} eq "Typedef") {
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +040013431 %Base2 = get_OneStep_BaseType($Base2{"Tid"}, $TypeInfo{2});
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013432 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +040013433 my $BName1 = uncover_typedefs($Base1{"Name"}, 1);
13434 my $BName2 = uncover_typedefs($Base2{"Name"}, 2);
13435 if($BName1 eq $BName2)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013436 { # equal base types
13437 return 0;
13438 }
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040013439
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040013440 if(not checkDump(1, "2.13")
13441 or not checkDump(2, "2.13"))
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040013442 { # broken array names in ABI dumps < 2.13
13443 if($TT1 eq "Array"
13444 and $TT2 eq "Array")
13445 {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013446 return 0;
13447 }
13448 }
13449
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040013450 if(not checkDump(1, "2.6")
13451 or not checkDump(2, "2.6"))
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040013452 { # added restrict attribute in 2.6
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040013453 if($TN1!~/\brestrict\b/
13454 and $TN2=~/\brestrict\b/)
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040013455 {
13456 return 0;
13457 }
13458 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013459 }
13460 return 1;
13461}
13462
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040013463sub differentDumps($)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013464{
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040013465 my $Check = $_[0];
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +040013466 if(defined $Cache{"differentDumps"}{$Check}) {
13467 return $Cache{"differentDumps"}{$Check};
13468 }
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040013469 if($UsedDump{1}{"V"} and $UsedDump{2}{"V"})
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040013470 {
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040013471 if($Check eq "G")
13472 {
13473 if(getGccVersion(1) ne getGccVersion(2))
13474 { # different GCC versions
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +040013475 return ($Cache{"differentDumps"}{$Check}=1);
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040013476 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040013477 }
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040013478 if($Check eq "V")
13479 {
13480 if(cmpVersions(formatVersion($UsedDump{1}{"V"}, 2),
13481 formatVersion($UsedDump{2}{"V"}, 2))!=0)
13482 { # different dump versions (skip micro version)
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +040013483 return ($Cache{"differentDumps"}{$Check}=1);
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040013484 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040013485 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013486 }
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +040013487 return ($Cache{"differentDumps"}{$Check}=0);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013488}
13489
13490sub formatVersion($$)
13491{ # cut off version digits
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040013492 my ($V, $Digits) = @_;
13493 my @Elems = split(/\./, $V);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013494 return join(".", splice(@Elems, 0, $Digits));
13495}
13496
13497sub htmlSpecChars($)
13498{
13499 my $Str = $_[0];
Andrey Ponomarenko5c09ef32012-06-14 18:17:33 +040013500 if(not $Str) {
13501 return $Str;
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040013502 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013503 $Str=~s/\&([^#]|\Z)/&amp;$1/g;
13504 $Str=~s/</&lt;/g;
13505 $Str=~s/\-\>/&#45;&gt;/g; # &minus;
13506 $Str=~s/>/&gt;/g;
13507 $Str=~s/([^ ])( )([^ ])/$1\@ALONE_SP\@$3/g;
13508 $Str=~s/ /&#160;/g; # &nbsp;
13509 $Str=~s/\@ALONE_SP\@/ /g;
13510 $Str=~s/\n/<br\/>/g;
13511 $Str=~s/\"/&quot;/g;
13512 $Str=~s/\'/&#39;/g;
13513 return $Str;
13514}
13515
Andrey Ponomarenko5c09ef32012-06-14 18:17:33 +040013516sub xmlSpecChars($)
13517{
13518 my $Str = $_[0];
13519 if(not $Str) {
13520 return $Str;
13521 }
13522
13523 $Str=~s/\&([^#]|\Z)/&amp;$1/g;
13524 $Str=~s/</&lt;/g;
13525 $Str=~s/>/&gt;/g;
13526
13527 $Str=~s/\"/&quot;/g;
13528 $Str=~s/\'/&#39;/g;
13529
13530 return $Str;
13531}
13532
Andrey Ponomarenko01117f12012-06-26 12:23:02 +040013533sub xmlSpecChars_R($)
13534{
13535 my $Str = $_[0];
13536 if(not $Str) {
13537 return $Str;
13538 }
13539
13540 $Str=~s/&amp;/&/g;
13541 $Str=~s/&lt;/</g;
13542 $Str=~s/&gt;/>/g;
13543
13544 $Str=~s/&quot;/"/g;
13545 $Str=~s/&#39;/'/g;
13546
13547 return $Str;
13548}
13549
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013550sub black_name($)
13551{
13552 my $Name = $_[0];
13553 return "<span class='iname_b'>".highLight_Signature($Name)."</span>";
13554}
13555
13556sub highLight_Signature($)
13557{
13558 my $Signature = $_[0];
13559 return highLight_Signature_PPos_Italic($Signature, "", 0, 0, 0);
13560}
13561
13562sub highLight_Signature_Italic_Color($)
13563{
13564 my $Signature = $_[0];
13565 return highLight_Signature_PPos_Italic($Signature, "", 1, 1, 1);
13566}
13567
13568sub separate_symbol($)
13569{
13570 my $Symbol = $_[0];
13571 my ($Name, $Spec, $Ver) = ($Symbol, "", "");
13572 if($Symbol=~/\A([^\@\$\?]+)([\@\$]+)([^\@\$]+)\Z/) {
13573 ($Name, $Spec, $Ver) = ($1, $2, $3);
13574 }
13575 return ($Name, $Spec, $Ver);
13576}
13577
13578sub cut_f_attrs($)
13579{
13580 if($_[0]=~s/(\))((| (const volatile|const|volatile))(| \[static\]))\Z/$1/) {
13581 return $2;
13582 }
13583 return "";
13584}
13585
13586sub highLight_Signature_PPos_Italic($$$$$)
13587{
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040013588 my ($FullSignature, $Param_Pos, $ItalicParams, $ColorParams, $ShowReturn) = @_;
13589 $Param_Pos = "" if(not defined $Param_Pos);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013590 if($CheckObjectsOnly) {
13591 $ItalicParams=$ColorParams=0;
13592 }
13593 my ($Signature, $VersionSpec, $SymbolVersion) = separate_symbol($FullSignature);
13594 my $Return = "";
13595 if($ShowRetVal and $Signature=~s/([^:]):([^:].+?)\Z/$1/g) {
13596 $Return = $2;
13597 }
Andrey Ponomarenko16934472012-03-29 15:37:04 +040013598 my $SCenter = find_center($Signature, "(");
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013599 if(not $SCenter)
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040013600 { # global data
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013601 $Signature = htmlSpecChars($Signature);
13602 $Signature=~s!(\[data\])!<span style='color:Black;font-weight:normal;'>$1</span>!g;
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040013603 $Signature .= (($SymbolVersion)?"<span class='sym_ver'>&#160;$VersionSpec&#160;$SymbolVersion</span>":"");
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013604 if($Return and $ShowReturn) {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040013605 $Signature .= "<span class='sym_p nowrap'> &#160;<b>:</b>&#160;&#160;".htmlSpecChars($Return)."</span>";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013606 }
13607 return $Signature;
13608 }
13609 my ($Begin, $End) = (substr($Signature, 0, $SCenter), "");
13610 $Begin.=" " if($Begin!~/ \Z/);
13611 $End = cut_f_attrs($Signature);
13612 my @Parts = ();
Andrey Ponomarenko07aea072012-11-12 16:15:07 +040013613 my ($Short, $Params) = split_Signature($Signature);
13614 my @SParts = separate_Params($Params, 1, 1);
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040013615 foreach my $Pos (0 .. $#SParts)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013616 {
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040013617 my $Part = $SParts[$Pos];
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013618 $Part=~s/\A\s+|\s+\Z//g;
13619 my ($Part_Styled, $ParamName) = (htmlSpecChars($Part), "");
13620 if($Part=~/\([\*]+(\w+)\)/i) {
13621 $ParamName = $1;#func-ptr
13622 }
13623 elsif($Part=~/(\w+)[\,\)]*\Z/i) {
13624 $ParamName = $1;
13625 }
13626 if(not $ParamName) {
13627 push(@Parts, $Part_Styled);
13628 next;
13629 }
13630 if($ItalicParams and not $TName_Tid{1}{$Part}
13631 and not $TName_Tid{2}{$Part})
13632 {
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040013633 my $Style = "param";
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040013634 if($Param_Pos ne ""
13635 and $Pos==$Param_Pos) {
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040013636 $Style = "focus_p";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013637 }
13638 elsif($ColorParams) {
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040013639 $Style = "color_p";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013640 }
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040013641 $Part_Styled =~ s!(\W)$ParamName([\,\)]|\Z)!$1<span class=\'$Style\'>$ParamName</span>$2!ig;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013642 }
13643 $Part_Styled=~s/,(\w)/, $1/g;
13644 push(@Parts, $Part_Styled);
13645 }
13646 if(@Parts)
13647 {
13648 foreach my $Num (0 .. $#Parts)
13649 {
13650 if($Num==$#Parts)
13651 { # add ")" to the last parameter
13652 $Parts[$Num] = "<span class='nowrap'>".$Parts[$Num]." )</span>";
13653 }
13654 elsif(length($Parts[$Num])<=45) {
13655 $Parts[$Num] = "<span class='nowrap'>".$Parts[$Num]."</span>";
13656 }
13657 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040013658 $Signature = htmlSpecChars($Begin)."<span class='sym_p'>(&#160;".join(" ", @Parts)."</span>".$End;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013659 }
13660 else {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040013661 $Signature = htmlSpecChars($Begin)."<span class='sym_p'>(&#160;)</span>".$End;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013662 }
13663 if($Return and $ShowReturn) {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040013664 $Signature .= "<span class='sym_p nowrap'> &#160;<b>:</b>&#160;&#160;".htmlSpecChars($Return)."</span>";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013665 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040013666 $Signature=~s!\[\]![&#160;]!g;
13667 $Signature=~s!operator=!operator&#160;=!g;
13668 $Signature=~s!(\[in-charge\]|\[not-in-charge\]|\[in-charge-deleting\]|\[static\])!<span class='sym_kind'>$1</span>!g;
13669 return $Signature.(($SymbolVersion)?"<span class='sym_ver'>&#160;$VersionSpec&#160;$SymbolVersion</span>":"");
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013670}
13671
Andrey Ponomarenko07aea072012-11-12 16:15:07 +040013672sub split_Signature($)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013673{
Andrey Ponomarenko07aea072012-11-12 16:15:07 +040013674 my $Signature = $_[0];
13675 if(my $ShortName = substr($Signature, 0, find_center($Signature, "(")))
13676 {
13677 $Signature=~s/\A\Q$ShortName\E\(//g;
13678 cut_f_attrs($Signature);
13679 $Signature=~s/\)\Z//;
13680 return ($ShortName, $Signature);
13681 }
13682
13683 # error
13684 return ($Signature, "");
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013685}
13686
Andrey Ponomarenko07aea072012-11-12 16:15:07 +040013687sub separate_Params($$$)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013688{
Andrey Ponomarenko07aea072012-11-12 16:15:07 +040013689 my ($Params, $Comma, $Sp) = @_;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013690 my @Parts = ();
Andrey Ponomarenko16934472012-03-29 15:37:04 +040013691 my %B = ( "("=>0, "<"=>0, ")"=>0, ">"=>0 );
13692 my $Part = 0;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013693 foreach my $Pos (0 .. length($Params) - 1)
13694 {
Andrey Ponomarenko16934472012-03-29 15:37:04 +040013695 my $S = substr($Params, $Pos, 1);
13696 if(defined $B{$S}) {
Andrey Ponomarenko07aea072012-11-12 16:15:07 +040013697 $B{$S} += 1;
Andrey Ponomarenko16934472012-03-29 15:37:04 +040013698 }
13699 if($S eq "," and
13700 $B{"("}==$B{")"} and $B{"<"}==$B{">"})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013701 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040013702 if($Comma)
13703 { # include comma
Andrey Ponomarenko16934472012-03-29 15:37:04 +040013704 $Parts[$Part] .= $S;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013705 }
Andrey Ponomarenko16934472012-03-29 15:37:04 +040013706 $Part += 1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013707 }
13708 else {
Andrey Ponomarenko16934472012-03-29 15:37:04 +040013709 $Parts[$Part] .= $S;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013710 }
13711 }
Andrey Ponomarenko07aea072012-11-12 16:15:07 +040013712 if(not $Sp)
13713 { # remove spaces
13714 foreach (@Parts)
13715 {
13716 s/\A //g;
13717 s/ \Z//g;
13718 }
13719 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013720 return @Parts;
13721}
13722
Andrey Ponomarenko16934472012-03-29 15:37:04 +040013723sub find_center($$)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013724{
13725 my ($Sign, $Target) = @_;
Andrey Ponomarenko16934472012-03-29 15:37:04 +040013726 my %B = ( "("=>0, "<"=>0, ")"=>0, ">"=>0 );
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013727 my $Center = 0;
Andrey Ponomarenko16934472012-03-29 15:37:04 +040013728 if($Sign=~s/(operator([^\w\s\(\)]+|\(\)))//g)
13729 { # operators
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013730 $Center+=length($1);
13731 }
13732 foreach my $Pos (0 .. length($Sign)-1)
13733 {
13734 my $S = substr($Sign, $Pos, 1);
13735 if($S eq $Target)
13736 {
13737 if($B{"("}==$B{")"}
13738 and $B{"<"}==$B{">"}) {
13739 return $Center;
13740 }
13741 }
13742 if(defined $B{$S}) {
13743 $B{$S}+=1;
13744 }
13745 $Center+=1;
13746 }
13747 return 0;
13748}
13749
13750sub appendFile($$)
13751{
13752 my ($Path, $Content) = @_;
13753 return if(not $Path);
13754 if(my $Dir = get_dirname($Path)) {
13755 mkpath($Dir);
13756 }
Andrey Ponomarenko16934472012-03-29 15:37:04 +040013757 open(FILE, ">>", $Path) || die ("can't open file \'$Path\': $!\n");
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013758 print FILE $Content;
13759 close(FILE);
13760}
13761
13762sub writeFile($$)
13763{
13764 my ($Path, $Content) = @_;
13765 return if(not $Path);
13766 if(my $Dir = get_dirname($Path)) {
13767 mkpath($Dir);
13768 }
Andrey Ponomarenko16934472012-03-29 15:37:04 +040013769 open(FILE, ">", $Path) || die ("can't open file \'$Path\': $!\n");
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013770 print FILE $Content;
13771 close(FILE);
13772}
13773
13774sub readFile($)
13775{
13776 my $Path = $_[0];
13777 return "" if(not $Path or not -f $Path);
Andrey Ponomarenko16934472012-03-29 15:37:04 +040013778 open(FILE, $Path);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013779 local $/ = undef;
13780 my $Content = <FILE>;
13781 close(FILE);
Andrey Ponomarenko85043792012-05-14 16:48:07 +040013782 if($Path!~/\.(tu|class|abi)\Z/) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013783 $Content=~s/\r/\n/g;
13784 }
13785 return $Content;
13786}
13787
13788sub get_filename($)
13789{ # much faster than basename() from File::Basename module
Andrey Ponomarenko85043792012-05-14 16:48:07 +040013790 if(defined $Cache{"get_filename"}{$_[0]}) {
13791 return $Cache{"get_filename"}{$_[0]};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013792 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +040013793 if($_[0] and $_[0]=~/([^\/\\]+)[\/\\]*\Z/) {
13794 return ($Cache{"get_filename"}{$_[0]}=$1);
13795 }
13796 return ($Cache{"get_filename"}{$_[0]}="");
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013797}
13798
13799sub get_dirname($)
13800{ # much faster than dirname() from File::Basename module
Andrey Ponomarenko85043792012-05-14 16:48:07 +040013801 if(defined $Cache{"get_dirname"}{$_[0]}) {
13802 return $Cache{"get_dirname"}{$_[0]};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013803 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +040013804 if($_[0] and $_[0]=~/\A(.*?)[\/\\]+[^\/\\]*[\/\\]*\Z/) {
13805 return ($Cache{"get_dirname"}{$_[0]}=$1);
13806 }
13807 return ($Cache{"get_dirname"}{$_[0]}="");
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013808}
13809
13810sub separate_path($) {
13811 return (get_dirname($_[0]), get_filename($_[0]));
13812}
13813
13814sub esc($)
13815{
13816 my $Str = $_[0];
13817 $Str=~s/([()\[\]{}$ &'"`;,<>\+])/\\$1/g;
13818 return $Str;
13819}
13820
13821sub readLineNum($$)
13822{
13823 my ($Path, $Num) = @_;
13824 return "" if(not $Path or not -f $Path);
Andrey Ponomarenko16934472012-03-29 15:37:04 +040013825 open(FILE, $Path);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013826 foreach (1 ... $Num) {
13827 <FILE>;
13828 }
13829 my $Line = <FILE>;
13830 close(FILE);
13831 return $Line;
13832}
13833
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040013834sub readAttributes($$)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013835{
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040013836 my ($Path, $Num) = @_;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013837 return () if(not $Path or not -f $Path);
13838 my %Attributes = ();
Andrey Ponomarenko85043792012-05-14 16:48:07 +040013839 if(readLineNum($Path, $Num)=~/<!--\s+(.+)\s+-->/)
13840 {
13841 foreach my $AttrVal (split(/;/, $1))
13842 {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013843 if($AttrVal=~/(.+):(.+)/)
13844 {
13845 my ($Name, $Value) = ($1, $2);
13846 $Attributes{$Name} = $Value;
13847 }
13848 }
13849 }
13850 return \%Attributes;
13851}
13852
13853sub is_abs($) {
13854 return ($_[0]=~/\A(\/|\w+:[\/\\])/);
13855}
13856
13857sub get_abs_path($)
13858{ # abs_path() should NOT be called for absolute inputs
13859 # because it can change them
13860 my $Path = $_[0];
13861 if(not is_abs($Path)) {
13862 $Path = abs_path($Path);
13863 }
13864 return $Path;
13865}
13866
13867sub get_OSgroup()
13868{
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +040013869 my $N = $Config{"osname"};
13870 if($N=~/macos|darwin|rhapsody/i) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013871 return "macos";
13872 }
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +040013873 elsif($N=~/freebsd|openbsd|netbsd/i) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013874 return "bsd";
13875 }
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +040013876 elsif($N=~/haiku|beos/i) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013877 return "beos";
13878 }
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +040013879 elsif($N=~/symbian|epoc/i) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013880 return "symbian";
13881 }
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +040013882 elsif($N=~/win/i) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013883 return "windows";
13884 }
13885 else {
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +040013886 return $N;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013887 }
13888}
13889
13890sub getGccVersion($)
13891{
13892 my $LibVersion = $_[0];
13893 if($GCC_VERSION{$LibVersion})
13894 { # dump version
13895 return $GCC_VERSION{$LibVersion};
13896 }
13897 elsif($UsedDump{$LibVersion}{"V"})
13898 { # old-version dumps
13899 return "unknown";
13900 }
13901 my $GccVersion = get_dumpversion($GCC_PATH); # host version
13902 if(not $GccVersion) {
13903 return "unknown";
13904 }
13905 return $GccVersion;
13906}
13907
13908sub showArch($)
13909{
13910 my $Arch = $_[0];
13911 if($Arch eq "arm"
13912 or $Arch eq "mips") {
13913 return uc($Arch);
13914 }
13915 return $Arch;
13916}
13917
13918sub getArch($)
13919{
13920 my $LibVersion = $_[0];
13921 if($CPU_ARCH{$LibVersion})
13922 { # dump version
13923 return $CPU_ARCH{$LibVersion};
13924 }
13925 elsif($UsedDump{$LibVersion}{"V"})
13926 { # old-version dumps
13927 return "unknown";
13928 }
13929 if(defined $Cache{"getArch"}{$LibVersion}) {
13930 return $Cache{"getArch"}{$LibVersion};
13931 }
13932 my $Arch = get_dumpmachine($GCC_PATH); # host version
13933 if(not $Arch) {
13934 return "unknown";
13935 }
13936 if($Arch=~/\A([\w]{3,})(-|\Z)/) {
13937 $Arch = $1;
13938 }
13939 $Arch = "x86" if($Arch=~/\Ai[3-7]86\Z/);
13940 if($OSgroup eq "windows") {
13941 $Arch = "x86" if($Arch=~/win32|mingw32/i);
13942 $Arch = "x86_64" if($Arch=~/win64|mingw64/i);
13943 }
13944 $Cache{"getArch"}{$LibVersion} = $Arch;
13945 return $Arch;
13946}
13947
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040013948sub get_Report_Header($)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013949{
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040013950 my $Level = $_[0];
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013951 my $ArchInfo = " on <span style='color:Blue;'>".showArch(getArch(1))."</span>";
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040013952 if(getArch(1) ne getArch(2)
13953 or getArch(1) eq "unknown"
13954 or $Level eq "Source")
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013955 { # don't show architecture in the header
13956 $ArchInfo="";
13957 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040013958 my $Report_Header = "<h1><span class='nowrap'>";
13959 if($Level eq "Source") {
13960 $Report_Header .= "Source compatibility";
13961 }
13962 elsif($Level eq "Binary") {
13963 $Report_Header .= "Binary compatibility";
13964 }
13965 else {
13966 $Report_Header .= "API compatibility";
13967 }
13968 $Report_Header .= " report for the <span style='color:Blue;'>$TargetLibraryFName</span> $TargetComponent</span>";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013969 $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>";
13970 if($AppPath) {
13971 $Report_Header .= " <span class='nowrap'>&#160;(relating to the portability of application <span style='color:Blue;'>".get_filename($AppPath)."</span>)</span>";
13972 }
13973 $Report_Header .= "</h1>\n";
13974 return $Report_Header;
13975}
13976
13977sub get_SourceInfo()
13978{
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040013979 my ($CheckedHeaders, $CheckedLibs) = ("", "");
13980 if(not $CheckObjectsOnly)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013981 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040013982 $CheckedHeaders = "<a name='Headers'></a><h2>Header Files (".keys(%{$Registered_Headers{1}}).")</h2><hr/>\n";
13983 $CheckedHeaders .= "<div class='h_list'>\n";
13984 foreach my $Header_Path (sort {lc($Registered_Headers{1}{$a}{"Identity"}) cmp lc($Registered_Headers{1}{$b}{"Identity"})} keys(%{$Registered_Headers{1}}))
13985 {
13986 my $Identity = $Registered_Headers{1}{$Header_Path}{"Identity"};
13987 my $Header_Name = get_filename($Identity);
13988 my $Dest_Comment = ($Identity=~/[\/\\]/)?" ($Identity)":"";
13989 $CheckedHeaders .= $Header_Name.$Dest_Comment."<br/>\n";
13990 }
13991 $CheckedHeaders .= "</div>\n";
13992 $CheckedHeaders .= "<br/>$TOP_REF<br/>\n";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013993 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040013994 if(not $CheckHeadersOnly)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013995 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040013996 $CheckedLibs = "<a name='Libs'></a><h2>".ucfirst($SLIB_TYPE)." Libraries (".keys(%{$Library_Symbol{1}}).")</h2><hr/>\n";
13997 $CheckedLibs .= "<div class='lib_list'>\n";
13998 foreach my $Library (sort {lc($a) cmp lc($b)} keys(%{$Library_Symbol{1}}))
13999 {
14000 $Library.=" (.$LIB_EXT)" if($Library!~/\.\w+\Z/);
14001 $CheckedLibs .= $Library."<br/>\n";
14002 }
14003 $CheckedLibs .= "</div>\n";
14004 $CheckedLibs .= "<br/>$TOP_REF<br/>\n";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014005 }
14006 return $CheckedHeaders.$CheckedLibs;
14007}
14008
14009sub get_TypeProblems_Count($$$)
14010{
14011 my ($TypeChanges, $TargetPriority, $Level) = @_;
14012 my $Type_Problems_Count = 0;
14013 foreach my $Type_Name (sort keys(%{$TypeChanges}))
14014 {
14015 my %Kinds_Target = ();
14016 foreach my $Kind (keys(%{$TypeChanges->{$Type_Name}}))
14017 {
14018 foreach my $Location (keys(%{$TypeChanges->{$Type_Name}{$Kind}}))
14019 {
14020 my $Target = $TypeChanges->{$Type_Name}{$Kind}{$Location}{"Target"};
14021 my $Priority = getProblemSeverity($Level, $Kind);
14022 next if($Priority ne $TargetPriority);
14023 if($Kinds_Target{$Kind}{$Target}) {
14024 next;
14025 }
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040014026 if(cmpSeverities($Type_MaxSeverity{$Level}{$Type_Name}{$Kind}{$Target}, $Priority))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014027 { # select a problem with the highest priority
14028 next;
14029 }
14030 $Kinds_Target{$Kind}{$Target} = 1;
14031 $Type_Problems_Count += 1;
14032 }
14033 }
14034 }
14035 return $Type_Problems_Count;
14036}
14037
14038sub get_Summary($)
14039{
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014040 my $Level = $_[0];
14041 my ($Added, $Removed, $I_Problems_High, $I_Problems_Medium, $I_Problems_Low, $T_Problems_High,
14042 $C_Problems_Low, $T_Problems_Medium, $T_Problems_Low, $I_Other, $T_Other) = (0,0,0,0,0,0,0,0,0,0,0);
14043 %{$RESULT{$Level}} = (
14044 "Problems"=>0,
14045 "Warnings"=>0,
14046 "Affected"=>0 );
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014047 # check rules
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014048 foreach my $Interface (sort keys(%{$CompatProblems{$Level}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014049 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014050 foreach my $Kind (keys(%{$CompatProblems{$Level}{$Interface}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014051 {
14052 if(not defined $CompatRules{$Level}{$Kind})
14053 { # unknown rule
14054 if(not $UnknownRules{$Level}{$Kind})
14055 { # only one warning
14056 printMsg("WARNING", "unknown rule \"$Kind\" (\"$Level\")");
14057 $UnknownRules{$Level}{$Kind}=1;
14058 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014059 delete($CompatProblems{$Level}{$Interface}{$Kind});
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014060 }
14061 }
14062 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014063 foreach my $Interface (sort keys(%{$CompatProblems{$Level}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014064 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014065 foreach my $Kind (sort keys(%{$CompatProblems{$Level}{$Interface}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014066 {
14067 if($CompatRules{$Level}{$Kind}{"Kind"} eq "Symbols")
14068 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014069 foreach my $Location (sort keys(%{$CompatProblems{$Level}{$Interface}{$Kind}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014070 {
14071 my $Priority = getProblemSeverity($Level, $Kind);
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014072 if($Kind eq "Added_Symbol") {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014073 $Added += 1;
14074 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014075 elsif($Kind eq "Removed_Symbol")
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014076 {
14077 $Removed += 1;
14078 $TotalAffected{$Level}{$Interface} = $Priority;
14079 }
14080 else
14081 {
14082 if($Priority eq "Safe") {
14083 $I_Other += 1;
14084 }
14085 elsif($Priority eq "High") {
14086 $I_Problems_High += 1;
14087 }
14088 elsif($Priority eq "Medium") {
14089 $I_Problems_Medium += 1;
14090 }
14091 elsif($Priority eq "Low") {
14092 $I_Problems_Low += 1;
14093 }
14094 if(($Priority ne "Low" or $StrictCompat)
14095 and $Priority ne "Safe") {
14096 $TotalAffected{$Level}{$Interface} = $Priority;
14097 }
14098 }
14099 }
14100 }
14101 }
14102 }
14103 my %TypeChanges = ();
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014104 foreach my $Interface (sort keys(%{$CompatProblems{$Level}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014105 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014106 foreach my $Kind (keys(%{$CompatProblems{$Level}{$Interface}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014107 {
14108 if($CompatRules{$Level}{$Kind}{"Kind"} eq "Types")
14109 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014110 foreach my $Location (sort {cmp_locations($b, $a)} sort keys(%{$CompatProblems{$Level}{$Interface}{$Kind}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014111 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014112 my $Type_Name = $CompatProblems{$Level}{$Interface}{$Kind}{$Location}{"Type_Name"};
14113 my $Target = $CompatProblems{$Level}{$Interface}{$Kind}{$Location}{"Target"};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014114 my $Priority = getProblemSeverity($Level, $Kind);
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040014115 if(cmpSeverities($Type_MaxSeverity{$Level}{$Type_Name}{$Kind}{$Target}, $Priority))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014116 { # select a problem with the highest priority
14117 next;
14118 }
14119 if(($Priority ne "Low" or $StrictCompat)
14120 and $Priority ne "Safe") {
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040014121 $TotalAffected{$Level}{$Interface} = maxSeverity($TotalAffected{$Level}{$Interface}, $Priority);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014122 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014123 %{$TypeChanges{$Type_Name}{$Kind}{$Location}} = %{$CompatProblems{$Level}{$Interface}{$Kind}{$Location}};
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040014124 $Type_MaxSeverity{$Level}{$Type_Name}{$Kind}{$Target} = maxSeverity($Type_MaxSeverity{$Level}{$Type_Name}{$Kind}{$Target}, $Priority);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014125 }
14126 }
14127 }
14128 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014129
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014130 $T_Problems_High = get_TypeProblems_Count(\%TypeChanges, "High", $Level);
14131 $T_Problems_Medium = get_TypeProblems_Count(\%TypeChanges, "Medium", $Level);
14132 $T_Problems_Low = get_TypeProblems_Count(\%TypeChanges, "Low", $Level);
14133 $T_Other = get_TypeProblems_Count(\%TypeChanges, "Safe", $Level);
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014134
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014135 if($CheckObjectsOnly)
14136 { # only removed exported symbols
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014137 $RESULT{$Level}{"Affected"} = $Removed*100/keys(%{$Symbol_Library{1}});
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014138 }
14139 else
14140 { # changed and removed public symbols
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014141 my $SCount = keys(%{$CheckedSymbols{$Level}});
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014142 if($ExtendedCheck)
14143 { # don't count external_func_0 for constants
14144 $SCount-=1;
14145 }
14146 if($SCount)
14147 {
14148 my %Weight = (
14149 "High" => 100,
14150 "Medium" => 50,
14151 "Low" => 25
14152 );
14153 foreach (keys(%{$TotalAffected{$Level}})) {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014154 $RESULT{$Level}{"Affected"}+=$Weight{$TotalAffected{$Level}{$_}};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014155 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014156 $RESULT{$Level}{"Affected"} = $RESULT{$Level}{"Affected"}/$SCount;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014157 }
14158 else {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014159 $RESULT{$Level}{"Affected"} = 0;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014160 }
14161 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014162 $RESULT{$Level}{"Affected"} = show_number($RESULT{$Level}{"Affected"});
14163 if($RESULT{$Level}{"Affected"}>=100) {
14164 $RESULT{$Level}{"Affected"} = 100;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014165 }
14166
Andrey Ponomarenko85043792012-05-14 16:48:07 +040014167 $RESULT{$Level}{"Problems"} += $Removed;
14168 $RESULT{$Level}{"Problems"} += $T_Problems_High + $I_Problems_High;
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014169 $RESULT{$Level}{"Problems"} += $T_Problems_Medium + $I_Problems_Medium;
Andrey Ponomarenko85043792012-05-14 16:48:07 +040014170 if($StrictCompat) {
14171 $RESULT{$Level}{"Problems"} += $T_Problems_Low + $I_Problems_Low;
14172 }
14173 else {
14174 $RESULT{$Level}{"Warnings"} += $T_Problems_Low + $I_Problems_Low;
14175 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014176
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014177 if($C_Problems_Low = keys(%{$ProblemsWithConstants{$Level}}))
14178 {
Andrey Ponomarenko85043792012-05-14 16:48:07 +040014179 if(defined $CompatRules{$Level}{"Changed_Constant"})
14180 {
14181 if($StrictCompat) {
14182 $RESULT{$Level}{"Problems"} += $C_Problems_Low;
14183 }
14184 else {
14185 $RESULT{$Level}{"Warnings"} += $C_Problems_Low;
14186 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014187 }
14188 else
14189 {
14190 printMsg("WARNING", "unknown rule \"Changed_Constant\" (\"$Level\")");
14191 $C_Problems_Low = 0;
14192 }
14193 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +040014194 if($CheckImpl and $Level eq "Binary")
14195 {
14196 if($StrictCompat) {
14197 $RESULT{$Level}{"Problems"} += keys(%ImplProblems);
14198 }
14199 else {
14200 $RESULT{$Level}{"Warnings"} += keys(%ImplProblems);
14201 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014202 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +040014203 if($RESULT{$Level}{"Problems"}
14204 and $RESULT{$Level}{"Affected"}) {
14205 $RESULT{$Level}{"Verdict"} = "incompatible";
14206 }
14207 else {
14208 $RESULT{$Level}{"Verdict"} = "compatible";
14209 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014210
14211 my $TotalTypes = keys(%{$CheckedTypes{$Level}});
14212 if(not $TotalTypes)
14213 { # list all the types
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014214 $TotalTypes = keys(%{$TName_Tid{1}});
14215 }
14216
14217 my ($Arch1, $Arch2) = (getArch(1), getArch(2));
14218 my ($GccV1, $GccV2) = (getGccVersion(1), getGccVersion(2));
14219
14220 my ($TestInfo, $TestResults, $Problem_Summary) = ();
14221
14222 if($ReportFormat eq "xml")
14223 { # XML
14224 # test info
14225 $TestInfo .= " <library>$TargetLibraryName</library>\n";
14226 $TestInfo .= " <version1>\n";
14227 $TestInfo .= " <number>".$Descriptor{1}{"Version"}."</number>\n";
14228 $TestInfo .= " <architecture>$Arch1</architecture>\n";
14229 $TestInfo .= " <gcc>$GccV1</gcc>\n";
14230 $TestInfo .= " </version1>\n";
14231
14232 $TestInfo .= " <version2>\n";
14233 $TestInfo .= " <number>".$Descriptor{2}{"Version"}."</number>\n";
14234 $TestInfo .= " <architecture>$Arch2</architecture>\n";
14235 $TestInfo .= " <gcc>$GccV2</gcc>\n";
14236 $TestInfo .= " </version2>\n";
14237 $TestInfo = "<test_info>\n".$TestInfo."</test_info>\n\n";
14238
14239 # test results
14240 $TestResults .= " <headers>\n";
14241 foreach my $Name (sort {lc($Registered_Headers{1}{$a}{"Identity"}) cmp lc($Registered_Headers{1}{$b}{"Identity"})} keys(%{$Registered_Headers{1}}))
14242 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014243 my $Identity = $Registered_Headers{1}{$Name}{"Identity"};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014244 my $Comment = ($Identity=~/[\/\\]/)?" ($Identity)":"";
14245 $TestResults .= " <name>".get_filename($Name).$Comment."</name>\n";
14246 }
14247 $TestResults .= " </headers>\n";
14248
14249 $TestResults .= " <libs>\n";
14250 foreach my $Library (sort {lc($a) cmp lc($b)} keys(%{$Library_Symbol{1}}))
14251 {
14252 $Library.=" (.$LIB_EXT)" if($Library!~/\.\w+\Z/);
14253 $TestResults .= " <name>$Library</name>\n";
14254 }
14255 $TestResults .= " </libs>\n";
14256
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040014257 $TestResults .= " <symbols>".(keys(%{$CheckedSymbols{$Level}}) - keys(%ExtendedSymbols))."</symbols>\n";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014258 $TestResults .= " <types>".$TotalTypes."</types>\n";
14259
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014260 $TestResults .= " <verdict>".$RESULT{$Level}{"Verdict"}."</verdict>\n";
14261 $TestResults .= " <affected>".$RESULT{$Level}{"Affected"}."</affected>\n";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014262 $TestResults = "<test_results>\n".$TestResults."</test_results>\n\n";
14263
14264 # problem summary
14265 $Problem_Summary .= " <added_symbols>".$Added."</added_symbols>\n";
14266 $Problem_Summary .= " <removed_symbols>".$Removed."</removed_symbols>\n";
14267
14268 $Problem_Summary .= " <problems_with_types>\n";
14269 $Problem_Summary .= " <high>$T_Problems_High</high>\n";
14270 $Problem_Summary .= " <medium>$T_Problems_Medium</medium>\n";
14271 $Problem_Summary .= " <low>$T_Problems_Low</low>\n";
14272 $Problem_Summary .= " <safe>$T_Other</safe>\n";
14273 $Problem_Summary .= " </problems_with_types>\n";
14274
14275 $Problem_Summary .= " <problems_with_symbols>\n";
14276 $Problem_Summary .= " <high>$I_Problems_High</high>\n";
14277 $Problem_Summary .= " <medium>$I_Problems_Medium</medium>\n";
14278 $Problem_Summary .= " <low>$I_Problems_Low</low>\n";
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014279 $Problem_Summary .= " <safe>$I_Other</safe>\n";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014280 $Problem_Summary .= " </problems_with_symbols>\n";
14281
14282 $Problem_Summary .= " <problems_with_constants>\n";
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014283 $Problem_Summary .= " <low>$C_Problems_Low</low>\n";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014284 $Problem_Summary .= " </problems_with_constants>\n";
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014285 if($CheckImpl and $Level eq "Binary")
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014286 {
14287 $Problem_Summary .= " <impl>\n";
14288 $Problem_Summary .= " <low>".keys(%ImplProblems)."</low>\n";
14289 $Problem_Summary .= " </impl>\n";
14290 }
14291 $Problem_Summary = "<problem_summary>\n".$Problem_Summary."</problem_summary>\n\n";
14292
14293 return ($TestInfo.$TestResults.$Problem_Summary, "");
14294 }
14295 else
14296 { # HTML
14297 # test info
14298 $TestInfo = "<h2>Test Info</h2><hr/>\n";
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014299 $TestInfo .= "<table class='summary'>\n";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014300 $TestInfo .= "<tr><th>".ucfirst($TargetComponent)." Name</th><td>$TargetLibraryFName</td></tr>\n";
14301
14302 my (@VInf1, @VInf2, $AddTestInfo) = ();
14303 if($Arch1 ne "unknown"
14304 and $Arch2 ne "unknown")
14305 { # CPU arch
14306 if($Arch1 eq $Arch2)
14307 { # go to the separate section
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014308 $AddTestInfo .= "<tr><th>CPU Type</th><td>".showArch($Arch1)."</td></tr>\n";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014309 }
14310 else
14311 { # go to the version number
14312 push(@VInf1, showArch($Arch1));
14313 push(@VInf2, showArch($Arch2));
14314 }
14315 }
14316 if($GccV1 ne "unknown"
14317 and $GccV2 ne "unknown"
14318 and $OStarget ne "windows")
14319 { # GCC version
14320 if($GccV1 eq $GccV2)
14321 { # go to the separate section
14322 $AddTestInfo .= "<tr><th>GCC Version</th><td>$GccV1</td></tr>\n";
14323 }
14324 else
14325 { # go to the version number
14326 push(@VInf1, "gcc ".$GccV1);
14327 push(@VInf2, "gcc ".$GccV2);
14328 }
14329 }
14330 # show long version names with GCC version and CPU architecture name (if different)
14331 $TestInfo .= "<tr><th>Version #1</th><td>".$Descriptor{1}{"Version"}.(@VInf1?" (".join(", ", reverse(@VInf1)).")":"")."</td></tr>\n";
14332 $TestInfo .= "<tr><th>Version #2</th><td>".$Descriptor{2}{"Version"}.(@VInf2?" (".join(", ", reverse(@VInf2)).")":"")."</td></tr>\n";
14333 $TestInfo .= $AddTestInfo;
14334 #if($COMMON_LANGUAGE{1}) {
14335 # $TestInfo .= "<tr><th>Language</th><td>".$COMMON_LANGUAGE{1}."</td></tr>\n";
14336 #}
14337 if($ExtendedCheck) {
14338 $TestInfo .= "<tr><th>Mode</th><td>Extended</td></tr>\n";
14339 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014340 if($JoinReport)
14341 {
14342 if($Level eq "Binary") {
Andrey Ponomarenko16934472012-03-29 15:37:04 +040014343 $TestInfo .= "<tr><th>Subject</th><td width='150px'>Binary Compatibility</td></tr>\n"; # Run-time
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014344 }
14345 if($Level eq "Source") {
Andrey Ponomarenko16934472012-03-29 15:37:04 +040014346 $TestInfo .= "<tr><th>Subject</th><td width='150px'>Source Compatibility</td></tr>\n"; # Build-time
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014347 }
14348 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014349 $TestInfo .= "</table>\n";
14350
14351 # test results
14352 $TestResults = "<h2>Test Results</h2><hr/>\n";
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014353 $TestResults .= "<table class='summary'>";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014354
14355 my $Headers_Link = "0";
14356 $Headers_Link = "<a href='#Headers' style='color:Blue;'>".keys(%{$Registered_Headers{1}})."</a>" if(keys(%{$Registered_Headers{1}})>0);
14357 $TestResults .= "<tr><th>Total Header Files</th><td>".($CheckObjectsOnly?"0&#160;(not&#160;analyzed)":$Headers_Link)."</td></tr>\n";
14358
14359 if(not $ExtendedCheck)
14360 {
14361 my $Libs_Link = "0";
14362 $Libs_Link = "<a href='#Libs' style='color:Blue;'>".keys(%{$Library_Symbol{1}})."</a>" if(keys(%{$Library_Symbol{1}})>0);
14363 $TestResults .= "<tr><th>Total ".ucfirst($SLIB_TYPE)." Libraries</th><td>".($CheckHeadersOnly?"0&#160;(not&#160;analyzed)":$Libs_Link)."</td></tr>\n";
14364 }
14365
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040014366 $TestResults .= "<tr><th>Total Symbols / Types</th><td>".(keys(%{$CheckedSymbols{$Level}}) - keys(%ExtendedSymbols))." / ".$TotalTypes."</td></tr>\n";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014367
Andrey Ponomarenko85043792012-05-14 16:48:07 +040014368 my $META_DATA = "verdict:".$RESULT{$Level}{"Verdict"}.";";
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014369 if($JoinReport) {
14370 $META_DATA = "kind:".lc($Level).";".$META_DATA;
14371 }
Andrey Ponomarenko16934472012-03-29 15:37:04 +040014372 $TestResults .= "<tr><th>Verdict</th>";
Andrey Ponomarenko85043792012-05-14 16:48:07 +040014373 if($RESULT{$Level}{"Verdict"} eq "incompatible") {
Andrey Ponomarenko16934472012-03-29 15:37:04 +040014374 $TestResults .= "<td><span style='color:Red;'><b>Incompatible<br/>(".$RESULT{$Level}{"Affected"}."%)</b></span></td>";
14375 }
14376 else {
14377 $TestResults .= "<td><span style='color:Green;'><b>Compatible</b></span></td>";
14378 }
14379 $TestResults .= "</tr>\n";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014380 $TestResults .= "</table>\n";
14381
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014382 $META_DATA .= "affected:".$RESULT{$Level}{"Affected"}.";";# in percents
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014383 # problem summary
14384 $Problem_Summary = "<h2>Problem Summary</h2><hr/>\n";
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014385 $Problem_Summary .= "<table class='summary'>";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014386 $Problem_Summary .= "<tr><th></th><th style='text-align:center;'>Severity</th><th style='text-align:center;'>Count</th></tr>";
14387
14388 my $Added_Link = "0";
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014389 if($Added>0)
14390 {
14391 if($JoinReport) {
14392 $Added_Link = "<a href='#".$Level."_Added' style='color:Blue;'>$Added</a>";
14393 }
14394 else {
14395 $Added_Link = "<a href='#Added' style='color:Blue;'>$Added</a>";
14396 }
14397 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014398 $META_DATA .= "added:$Added;";
Andrey Ponomarenko16934472012-03-29 15:37:04 +040014399 $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 +040014400
14401 my $Removed_Link = "0";
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014402 if($Removed>0)
14403 {
14404 if($JoinReport) {
14405 $Removed_Link = "<a href='#".$Level."_Removed' style='color:Blue;'>$Removed</a>"
14406 }
14407 else {
14408 $Removed_Link = "<a href='#Removed' style='color:Blue;'>$Removed</a>"
14409 }
14410 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014411 $META_DATA .= "removed:$Removed;";
Andrey Ponomarenko16934472012-03-29 15:37:04 +040014412 $Problem_Summary .= "<tr><th>Removed Symbols</th>";
14413 $Problem_Summary .= "<td>High</td><td".getStyle("I", "R", $Removed).">$Removed_Link</td></tr>\n";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014414
14415 my $TH_Link = "0";
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014416 $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 +040014417 $TH_Link = "n/a" if($CheckObjectsOnly);
14418 $META_DATA .= "type_problems_high:$T_Problems_High;";
Andrey Ponomarenko16934472012-03-29 15:37:04 +040014419 $Problem_Summary .= "<tr><th rowspan='3'>Problems with<br/>Data Types</th>";
14420 $Problem_Summary .= "<td>High</td><td".getStyle("T", "H", $T_Problems_High).">$TH_Link</td></tr>\n";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014421
14422 my $TM_Link = "0";
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014423 $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 +040014424 $TM_Link = "n/a" if($CheckObjectsOnly);
14425 $META_DATA .= "type_problems_medium:$T_Problems_Medium;";
Andrey Ponomarenko16934472012-03-29 15:37:04 +040014426 $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 +040014427
14428 my $TL_Link = "0";
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014429 $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 +040014430 $TL_Link = "n/a" if($CheckObjectsOnly);
14431 $META_DATA .= "type_problems_low:$T_Problems_Low;";
Andrey Ponomarenko16934472012-03-29 15:37:04 +040014432 $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 +040014433
14434 my $IH_Link = "0";
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014435 $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 +040014436 $IH_Link = "n/a" if($CheckObjectsOnly);
14437 $META_DATA .= "interface_problems_high:$I_Problems_High;";
Andrey Ponomarenko16934472012-03-29 15:37:04 +040014438 $Problem_Summary .= "<tr><th rowspan='3'>Problems with<br/>Symbols</th>";
14439 $Problem_Summary .= "<td>High</td><td".getStyle("I", "H", $I_Problems_High).">$IH_Link</td></tr>\n";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014440
14441 my $IM_Link = "0";
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014442 $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 +040014443 $IM_Link = "n/a" if($CheckObjectsOnly);
14444 $META_DATA .= "interface_problems_medium:$I_Problems_Medium;";
Andrey Ponomarenko16934472012-03-29 15:37:04 +040014445 $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 +040014446
14447 my $IL_Link = "0";
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014448 $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 +040014449 $IL_Link = "n/a" if($CheckObjectsOnly);
14450 $META_DATA .= "interface_problems_low:$I_Problems_Low;";
Andrey Ponomarenko16934472012-03-29 15:37:04 +040014451 $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 +040014452
14453 my $ChangedConstants_Link = "0";
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014454 if(keys(%{$CheckedSymbols{$Level}}) and $C_Problems_Low)
14455 {
14456 if($JoinReport) {
14457 $ChangedConstants_Link = "<a href='#".$Level."_Changed_Constants' style='color:Blue;'>$C_Problems_Low</a>";
14458 }
14459 else {
14460 $ChangedConstants_Link = "<a href='#Changed_Constants' style='color:Blue;'>$C_Problems_Low</a>";
14461 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014462 }
14463 $ChangedConstants_Link = "n/a" if($CheckObjectsOnly);
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014464 $META_DATA .= "changed_constants:$C_Problems_Low;";
Andrey Ponomarenko16934472012-03-29 15:37:04 +040014465 $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 +040014466
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014467 if($CheckImpl and $Level eq "Binary")
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014468 {
14469 my $ChangedImpl_Link = "0";
14470 $ChangedImpl_Link = "<a href='#Changed_Implementation' style='color:Blue;'>".keys(%ImplProblems)."</a>" if(keys(%ImplProblems)>0);
14471 $ChangedImpl_Link = "n/a" if($CheckHeadersOnly);
14472 $META_DATA .= "changed_implementation:".keys(%ImplProblems).";";
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040014473 $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 +040014474 }
14475 # Safe Changes
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014476 if($T_Other and not $CheckObjectsOnly)
14477 {
14478 my $TS_Link = "<a href='#".get_Anchor("Type", $Level, "Safe")."' style='color:Blue;'>$T_Other</a>";
Andrey Ponomarenko16934472012-03-29 15:37:04 +040014479 $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 +040014480 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014481
14482 if($I_Other and not $CheckObjectsOnly)
14483 {
14484 my $IS_Link = "<a href='#".get_Anchor("Symbol", $Level, "Safe")."' style='color:Blue;'>$I_Other</a>";
Andrey Ponomarenko16934472012-03-29 15:37:04 +040014485 $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 +040014486 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014487
14488 $META_DATA .= "tool_version:$TOOL_VERSION";
14489 $Problem_Summary .= "</table>\n";
Andrey Ponomarenko16934472012-03-29 15:37:04 +040014490 # $TestInfo = getLegend().$TestInfo;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014491 return ($TestInfo.$TestResults.$Problem_Summary, $META_DATA);
14492 }
14493}
14494
Andrey Ponomarenko16934472012-03-29 15:37:04 +040014495sub getStyle($$$)
14496{
14497 my ($Subj, $Act, $Num) = @_;
14498 my %Style = (
14499 "A"=>"new",
14500 "R"=>"failed",
14501 "S"=>"passed",
14502 "L"=>"warning",
14503 "M"=>"failed",
14504 "H"=>"failed"
14505 );
14506 if($Num>0) {
14507 return " class='".$Style{$Act}."'";
14508 }
14509 return "";
14510}
14511
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014512sub show_number($)
14513{
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014514 if($_[0])
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014515 {
Andrey Ponomarenko16934472012-03-29 15:37:04 +040014516 my $Num = cut_off_number($_[0], 2, 0);
14517 if($Num eq "0")
14518 {
14519 foreach my $P (3 .. 7)
14520 {
14521 $Num = cut_off_number($_[0], $P, 1);
14522 if($Num ne "0") {
14523 last;
14524 }
14525 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014526 }
14527 if($Num eq "0") {
14528 $Num = $_[0];
14529 }
14530 return $Num;
14531 }
14532 return $_[0];
14533}
14534
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014535sub cut_off_number($$$)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014536{
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014537 my ($num, $digs_to_cut, $z) = @_;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014538 if($num!~/\./)
14539 {
14540 $num .= ".";
14541 foreach (1 .. $digs_to_cut-1) {
14542 $num .= "0";
14543 }
14544 }
14545 elsif($num=~/\.(.+)\Z/ and length($1)<$digs_to_cut-1)
14546 {
14547 foreach (1 .. $digs_to_cut - 1 - length($1)) {
14548 $num .= "0";
14549 }
14550 }
14551 elsif($num=~/\d+\.(\d){$digs_to_cut,}/) {
14552 $num=sprintf("%.".($digs_to_cut-1)."f", $num);
14553 }
14554 $num=~s/\.[0]+\Z//g;
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014555 if($z) {
14556 $num=~s/(\.[1-9]+)[0]+\Z/$1/g;
14557 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014558 return $num;
14559}
14560
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014561sub get_Report_ChangedConstants($)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014562{
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014563 my $Level = $_[0];
Andrey Ponomarenko16934472012-03-29 15:37:04 +040014564 my $CHANGED_CONSTANTS = "";
14565 my %ReportMap = ();
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014566 foreach my $Constant (keys(%{$ProblemsWithConstants{$Level}})) {
Andrey Ponomarenko16934472012-03-29 15:37:04 +040014567 $ReportMap{$Constants{1}{$Constant}{"Header"}}{$Constant} = 1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014568 }
14569 my $Kind = "Changed_Constant";
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014570 if(not defined $CompatRules{$Level}{$Kind}) {
14571 return "";
14572 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014573 if($ReportFormat eq "xml")
14574 { # XML
Andrey Ponomarenko16934472012-03-29 15:37:04 +040014575 foreach my $HeaderName (sort {lc($a) cmp lc($b)} keys(%ReportMap))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014576 {
14577 $CHANGED_CONSTANTS .= " <header name=\"$HeaderName\">\n";
Andrey Ponomarenko16934472012-03-29 15:37:04 +040014578 foreach my $Constant (sort {lc($a) cmp lc($b)} keys(%{$ReportMap{$HeaderName}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014579 {
14580 $CHANGED_CONSTANTS .= " <constant name=\"$Constant\">\n";
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014581 my $Change = $CompatRules{$Level}{$Kind}{"Change"};
14582 my $Effect = $CompatRules{$Level}{$Kind}{"Effect"};
14583 my $Overcome = $CompatRules{$Level}{$Kind}{"Overcome"};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014584 $CHANGED_CONSTANTS .= " <problem id=\"$Kind\">\n";
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014585 $CHANGED_CONSTANTS .= " <change".getXmlParams($Change, $ProblemsWithConstants{$Level}{$Constant}).">$Change</change>\n";
14586 $CHANGED_CONSTANTS .= " <effect".getXmlParams($Effect, $ProblemsWithConstants{$Level}{$Constant}).">$Effect</effect>\n";
14587 $CHANGED_CONSTANTS .= " <overcome".getXmlParams($Overcome, $ProblemsWithConstants{$Level}{$Constant}).">$Overcome</overcome>\n";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014588 $CHANGED_CONSTANTS .= " </problem>\n";
14589 $CHANGED_CONSTANTS .= " </constant>\n";
14590 }
14591 $CHANGED_CONSTANTS .= " </header>\n";
14592 }
14593 $CHANGED_CONSTANTS = "<problems_with_constants severity=\"Low\">\n".$CHANGED_CONSTANTS."</problems_with_constants>\n\n";
14594 }
14595 else
14596 { # HTML
14597 my $Number = 0;
Andrey Ponomarenko16934472012-03-29 15:37:04 +040014598 foreach my $HeaderName (sort {lc($a) cmp lc($b)} keys(%ReportMap))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014599 {
14600 $CHANGED_CONSTANTS .= "<span class='h_name'>$HeaderName</span><br/>\n";
Andrey Ponomarenko16934472012-03-29 15:37:04 +040014601 foreach my $Name (sort {lc($a) cmp lc($b)} keys(%{$ReportMap{$HeaderName}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014602 {
14603 $Number += 1;
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014604 my $Change = applyMacroses($Level, $Kind, $CompatRules{$Level}{$Kind}{"Change"}, $ProblemsWithConstants{$Level}{$Name});
14605 my $Effect = $CompatRules{$Level}{$Kind}{"Effect"};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014606 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 +040014607 $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 +040014608 $Report = $ContentSpanStart."<span class='extendable'>[+]</span> ".$Name.$ContentSpanEnd."<br/>\n".$Report;
14609 $CHANGED_CONSTANTS .= insertIDs($Report);
14610 }
14611 $CHANGED_CONSTANTS .= "<br/>\n";
14612 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014613 if($CHANGED_CONSTANTS)
14614 {
14615 my $Anchor = "<a name='Changed_Constants'></a>";
14616 if($JoinReport) {
14617 $Anchor = "<a name='".$Level."_Changed_Constants'></a>";
14618 }
14619 $CHANGED_CONSTANTS = $Anchor."<h2>Problems with Constants ($Number)</h2><hr/>\n".$CHANGED_CONSTANTS.$TOP_REF."<br/>\n";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014620 }
14621 }
14622 return $CHANGED_CONSTANTS;
14623}
14624
14625sub get_Report_Impl()
14626{
Andrey Ponomarenko16934472012-03-29 15:37:04 +040014627 my $CHANGED_IMPLEMENTATION = "";
14628 my %ReportMap = ();
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014629 foreach my $Interface (sort keys(%ImplProblems))
14630 {
14631 my $HeaderName = $CompleteSignature{1}{$Interface}{"Header"};
14632 my $DyLib = $Symbol_Library{1}{$Interface};
Andrey Ponomarenko16934472012-03-29 15:37:04 +040014633 $ReportMap{$HeaderName}{$DyLib}{$Interface} = 1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014634 }
14635 my $Changed_Number = 0;
Andrey Ponomarenko16934472012-03-29 15:37:04 +040014636 foreach my $HeaderName (sort {lc($a) cmp lc($b)} keys(%ReportMap))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014637 {
Andrey Ponomarenko16934472012-03-29 15:37:04 +040014638 foreach my $DyLib (sort {lc($a) cmp lc($b)} keys(%{$ReportMap{$HeaderName}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014639 {
14640 my $FDyLib=$DyLib.($DyLib!~/\.\w+\Z/?" (.$LIB_EXT)":"");
14641 if($HeaderName) {
14642 $CHANGED_IMPLEMENTATION .= "<span class='h_name'>$HeaderName</span>, <span class='lib_name'>$FDyLib</span><br/>\n";
14643 }
14644 else {
14645 $CHANGED_IMPLEMENTATION .= "<span class='lib_name'>$DyLib</span><br/>\n";
14646 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014647 my %NameSpaceSymbols = ();
Andrey Ponomarenko16934472012-03-29 15:37:04 +040014648 foreach my $Interface (keys(%{$ReportMap{$HeaderName}{$DyLib}})) {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014649 $NameSpaceSymbols{get_IntNameSpace($Interface, 2)}{$Interface} = 1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014650 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014651 foreach my $NameSpace (sort keys(%NameSpaceSymbols))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014652 {
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040014653 $CHANGED_IMPLEMENTATION .= ($NameSpace)?"<span class='ns_title'>namespace</span> <span class='ns'>$NameSpace</span><br/>\n":"";
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014654 my @SortedInterfaces = sort {lc(get_Signature($a, 1)) cmp lc(get_Signature($b, 1))} keys(%{$NameSpaceSymbols{$NameSpace}});
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014655 foreach my $Interface (@SortedInterfaces)
14656 {
14657 $Changed_Number += 1;
14658 my $Signature = get_Signature($Interface, 1);
14659 if($NameSpace) {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040014660 $Signature=~s/\b\Q$NameSpace\E::\b//g;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014661 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014662 $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 +040014663 }
14664 }
14665 $CHANGED_IMPLEMENTATION .= "<br/>\n";
14666 }
14667 }
14668 if($CHANGED_IMPLEMENTATION) {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014669 $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 +040014670 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +040014671
14672 # clean memory
14673 %ImplProblems = ();
14674
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014675 return $CHANGED_IMPLEMENTATION;
14676}
14677
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014678sub getTitle($$$)
14679{
14680 my ($Header, $Library, $NameSpace) = @_;
14681 my $Title = "";
14682 if($Library and $Library!~/\.\w+\Z/) {
14683 $Library .= " (.$LIB_EXT)";
14684 }
14685 if($Header and $Library)
14686 {
14687 $Title .= "<span class='h_name'>$Header</span>";
14688 $Title .= ", <span class='lib_name'>$Library</span><br/>\n";
14689 }
14690 elsif($Library) {
14691 $Title .= "<span class='lib_name'>$Library</span><br/>\n";
14692 }
14693 elsif($Header) {
14694 $Title .= "<span class='h_name'>$Header</span><br/>\n";
14695 }
14696 if($NameSpace) {
14697 $Title .= "<span class='ns_title'>namespace</span> <span class='ns'>$NameSpace</span><br/>\n";
14698 }
14699 return $Title;
14700}
14701
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014702sub get_Report_Added($)
14703{
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014704 my $Level = $_[0];
Andrey Ponomarenko16934472012-03-29 15:37:04 +040014705 my $ADDED_INTERFACES = "";
14706 my %ReportMap = ();
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014707 foreach my $Interface (sort keys(%{$CompatProblems{$Level}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014708 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014709 foreach my $Kind (sort keys(%{$CompatProblems{$Level}{$Interface}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014710 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014711 if($Kind eq "Added_Symbol")
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014712 {
14713 my $HeaderName = $CompleteSignature{2}{$Interface}{"Header"};
14714 my $DyLib = $Symbol_Library{2}{$Interface};
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014715 if($Level eq "Source" and $ReportFormat eq "html")
14716 { # do not show library name in HTML report
14717 $DyLib = "";
14718 }
14719 $ReportMap{$HeaderName}{$DyLib}{$Interface} = 1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014720 }
14721 }
14722 }
14723 if($ReportFormat eq "xml")
14724 { # XML
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014725 foreach my $HeaderName (sort {lc($a) cmp lc($b)} keys(%ReportMap))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014726 {
14727 $ADDED_INTERFACES .= " <header name=\"$HeaderName\">\n";
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014728 foreach my $DyLib (sort {lc($a) cmp lc($b)} keys(%{$ReportMap{$HeaderName}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014729 {
14730 $ADDED_INTERFACES .= " <library name=\"$DyLib\">\n";
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014731 foreach my $Interface (keys(%{$ReportMap{$HeaderName}{$DyLib}})) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014732 $ADDED_INTERFACES .= " <name>$Interface</name>\n";
14733 }
14734 $ADDED_INTERFACES .= " </library>\n";
14735 }
14736 $ADDED_INTERFACES .= " </header>\n";
14737 }
14738 $ADDED_INTERFACES = "<added_symbols>\n".$ADDED_INTERFACES."</added_symbols>\n\n";
14739 }
14740 else
14741 { # HTML
14742 my $Added_Number = 0;
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014743 foreach my $HeaderName (sort {lc($a) cmp lc($b)} keys(%ReportMap))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014744 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014745 foreach my $DyLib (sort {lc($a) cmp lc($b)} keys(%{$ReportMap{$HeaderName}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014746 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014747 my %NameSpaceSymbols = ();
14748 foreach my $Interface (keys(%{$ReportMap{$HeaderName}{$DyLib}})) {
14749 $NameSpaceSymbols{get_IntNameSpace($Interface, 2)}{$Interface} = 1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014750 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014751 foreach my $NameSpace (sort keys(%NameSpaceSymbols))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014752 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014753 $ADDED_INTERFACES .= getTitle($HeaderName, $DyLib, $NameSpace);
14754 my @SortedInterfaces = sort {lc(get_Signature($a, 2)) cmp lc(get_Signature($b, 2))} keys(%{$NameSpaceSymbols{$NameSpace}});
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014755 foreach my $Interface (@SortedInterfaces)
14756 {
14757 $Added_Number += 1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014758 my $Signature = get_Signature($Interface, 2);
14759 if($NameSpace) {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040014760 $Signature=~s/\b\Q$NameSpace\E::\b//g;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014761 }
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040014762 if($Interface=~/\A(_Z|\?)/)
14763 {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014764 if($Signature) {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014765 $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 +040014766 }
14767 else {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014768 $ADDED_INTERFACES .= "<span class=\"iname\">".$Interface."</span><br/>\n";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014769 }
14770 }
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040014771 else
14772 {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014773 if($Signature) {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014774 $ADDED_INTERFACES .= "<span class=\"iname\">".highLight_Signature_Italic_Color($Signature)."</span><br/>\n";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014775 }
14776 else {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014777 $ADDED_INTERFACES .= "<span class=\"iname\">".$Interface."</span><br/>\n";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014778 }
14779 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014780 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014781 $ADDED_INTERFACES .= "<br/>\n";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014782 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014783 }
14784 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014785 if($ADDED_INTERFACES)
14786 {
14787 my $Anchor = "<a name='Added'></a>";
14788 if($JoinReport) {
14789 $Anchor = "<a name='".$Level."_Added'></a>";
14790 }
14791 $ADDED_INTERFACES = $Anchor."<h2>Added Symbols ($Added_Number)</h2><hr/>\n".$ADDED_INTERFACES.$TOP_REF."<br/>\n";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014792 }
14793 }
14794 return $ADDED_INTERFACES;
14795}
14796
14797sub get_Report_Removed($)
14798{
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014799 my $Level = $_[0];
Andrey Ponomarenko16934472012-03-29 15:37:04 +040014800 my $REMOVED_INTERFACES = "";
14801 my %ReportMap = ();
Andrey Ponomarenko85043792012-05-14 16:48:07 +040014802 foreach my $Symbol (sort keys(%{$CompatProblems{$Level}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014803 {
Andrey Ponomarenko85043792012-05-14 16:48:07 +040014804 foreach my $Kind (sort keys(%{$CompatProblems{$Level}{$Symbol}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014805 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014806 if($Kind eq "Removed_Symbol")
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014807 {
Andrey Ponomarenko85043792012-05-14 16:48:07 +040014808 my $HeaderName = $CompleteSignature{1}{$Symbol}{"Header"};
14809 my $DyLib = $Symbol_Library{1}{$Symbol};
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014810 if($Level eq "Source" and $ReportFormat eq "html")
14811 { # do not show library name in HTML report
14812 $DyLib = "";
14813 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +040014814 $ReportMap{$HeaderName}{$DyLib}{$Symbol} = 1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014815 }
14816 }
14817 }
14818 if($ReportFormat eq "xml")
14819 { # XML
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014820 foreach my $HeaderName (sort {lc($a) cmp lc($b)} keys(%ReportMap))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014821 {
14822 $REMOVED_INTERFACES .= " <header name=\"$HeaderName\">\n";
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014823 foreach my $DyLib (sort {lc($a) cmp lc($b)} keys(%{$ReportMap{$HeaderName}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014824 {
14825 $REMOVED_INTERFACES .= " <library name=\"$DyLib\">\n";
Andrey Ponomarenko85043792012-05-14 16:48:07 +040014826 foreach my $Symbol (keys(%{$ReportMap{$HeaderName}{$DyLib}})) {
14827 $REMOVED_INTERFACES .= " <name>$Symbol</name>\n";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014828 }
14829 $REMOVED_INTERFACES .= " </library>\n";
14830 }
14831 $REMOVED_INTERFACES .= " </header>\n";
14832 }
14833 $REMOVED_INTERFACES = "<removed_symbols>\n".$REMOVED_INTERFACES."</removed_symbols>\n\n";
14834 }
14835 else
14836 { # HTML
14837 my $Removed_Number = 0;
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014838 foreach my $HeaderName (sort {lc($a) cmp lc($b)} keys(%ReportMap))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014839 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014840 foreach my $DyLib (sort {lc($a) cmp lc($b)} keys(%{$ReportMap{$HeaderName}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014841 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014842 my %NameSpaceSymbols = ();
14843 foreach my $Interface (keys(%{$ReportMap{$HeaderName}{$DyLib}})) {
14844 $NameSpaceSymbols{get_IntNameSpace($Interface, 1)}{$Interface} = 1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014845 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014846 foreach my $NameSpace (sort keys(%NameSpaceSymbols))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014847 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014848 $REMOVED_INTERFACES .= getTitle($HeaderName, $DyLib, $NameSpace);
14849 my @SortedInterfaces = sort {lc(get_Signature($a, 1)) cmp lc(get_Signature($b, 1))} keys(%{$NameSpaceSymbols{$NameSpace}});
Andrey Ponomarenko85043792012-05-14 16:48:07 +040014850 foreach my $Symbol (@SortedInterfaces)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014851 {
14852 $Removed_Number += 1;
14853 my $SubReport = "";
Andrey Ponomarenko85043792012-05-14 16:48:07 +040014854 my $Signature = get_Signature($Symbol, 1);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014855 if($NameSpace) {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040014856 $Signature=~s/\b\Q$NameSpace\E::\b//g;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014857 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +040014858 if($Symbol=~/\A(_Z|\?)/)
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014859 {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014860 if($Signature) {
Andrey Ponomarenko85043792012-05-14 16:48:07 +040014861 $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 +040014862 }
14863 else {
Andrey Ponomarenko85043792012-05-14 16:48:07 +040014864 $REMOVED_INTERFACES .= "<span class=\"iname\">".$Symbol."</span><br/>\n";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014865 }
14866 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014867 else
14868 {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014869 if($Signature) {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014870 $REMOVED_INTERFACES .= "<span class=\"iname\">".highLight_Signature_Italic_Color($Signature)."</span><br/>\n";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014871 }
14872 else {
Andrey Ponomarenko85043792012-05-14 16:48:07 +040014873 $REMOVED_INTERFACES .= "<span class=\"iname\">".$Symbol."</span><br/>\n";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014874 }
14875 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014876 }
14877 }
14878 $REMOVED_INTERFACES .= "<br/>\n";
14879 }
14880 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014881 if($REMOVED_INTERFACES)
14882 {
14883 my $Anchor = "<a name='Removed'></a><a name='Withdrawn'></a>";
14884 if($JoinReport) {
14885 $Anchor = "<a name='".$Level."_Removed'></a><a name='".$Level."_Withdrawn'></a>";
14886 }
14887 $REMOVED_INTERFACES = $Anchor."<h2>Removed Symbols ($Removed_Number)</h2><hr/>\n".$REMOVED_INTERFACES.$TOP_REF."<br/>\n";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014888 }
14889 }
14890 return $REMOVED_INTERFACES;
14891}
14892
14893sub getXmlParams($$)
14894{
14895 my ($Content, $Problem) = @_;
14896 return "" if(not $Content or not $Problem);
14897 my %XMLparams = ();
14898 foreach my $Attr (sort {$b cmp $a} keys(%{$Problem}))
14899 {
14900 my $Macro = "\@".lc($Attr);
14901 if($Content=~/\Q$Macro\E/) {
14902 $XMLparams{lc($Attr)} = $Problem->{$Attr};
14903 }
14904 }
14905 my @PString = ();
14906 foreach my $P (sort {$b cmp $a} keys(%XMLparams)) {
Andrey Ponomarenko5c09ef32012-06-14 18:17:33 +040014907 push(@PString, $P."=\"".xmlSpecChars($XMLparams{$P})."\"");
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014908 }
14909 if(@PString) {
14910 return " ".join(" ", @PString);
14911 }
14912 else {
14913 return "";
14914 }
14915}
14916
14917sub addMarkup($)
14918{
14919 my $Content = $_[0];
14920 # auto-markup
14921 $Content=~s/\n[ ]*//; # spaces
14922 $Content=~s!(\@\w+\s*\(\@\w+\))!<nowrap>$1</nowrap>!g; # @old_type (@old_size)
14923 $Content=~s!(... \(\w+\))!<nowrap><b>$1</b></nowrap>!g; # ... (va_list)
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040014924 $Content=~s!<nowrap>(.+?)</nowrap>!<span class='nowrap'>$1</span>!g;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014925 $Content=~s!([2-9]\))!<br/>$1!g; # 1), 2), ...
14926 if($Content=~/\ANOTE:/)
14927 { # notes
14928 $Content=~s!(NOTE):!<b>$1</b>:!g;
14929 }
14930 else {
14931 $Content=~s!(NOTE):!<br/><b>$1</b>:!g;
14932 }
14933 $Content=~s! (out)-! <b>$1</b>-!g; # out-parameters
14934 my @Keywords = (
14935 "void",
14936 "const",
14937 "static",
14938 "restrict",
14939 "volatile",
14940 "register",
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040014941 "virtual"
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014942 );
14943 my $MKeys = join("|", @Keywords);
14944 foreach (@Keywords) {
14945 $MKeys .= "|non-".$_;
14946 }
14947 $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 +040014948
14949 # Markdown
14950 $Content=~s!\*\*([\w\-]+)\*\*!<b>$1</b>!ig;
14951 $Content=~s!\*([\w\-]+)\*!<i>$1</i>!ig;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014952 return $Content;
14953}
14954
14955sub applyMacroses($$$$)
14956{
14957 my ($Level, $Kind, $Content, $Problem) = @_;
14958 return "" if(not $Content or not $Problem);
14959 $Problem->{"Word_Size"} = $WORD_SIZE{2};
14960 $Content = addMarkup($Content);
14961 # macros
14962 foreach my $Attr (sort {$b cmp $a} keys(%{$Problem}))
14963 {
14964 my $Macro = "\@".lc($Attr);
14965 my $Value = $Problem->{$Attr};
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040014966 if(not defined $Value
14967 or $Value eq "") {
14968 next;
14969 }
Andrey Ponomarenko5c09ef32012-06-14 18:17:33 +040014970 if($Value=~/\s\(/ and $Value!~/['"]/)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014971 { # functions
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014972 $Value=~s/\s*\[[\w\-]+\]//g; # remove quals
14973 $Value=~s/\s\w+(\)|,)/$1/g; # remove parameter names
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014974 $Value = black_name($Value);
14975 }
14976 elsif($Value=~/\s/) {
14977 $Value = "<span class='value'>".htmlSpecChars($Value)."</span>";
14978 }
14979 elsif($Value=~/\A\d+\Z/
14980 and ($Attr eq "Old_Size" or $Attr eq "New_Size"))
14981 { # bits to bytes
14982 if($Value % $BYTE_SIZE)
14983 { # bits
14984 if($Value==1) {
14985 $Value = "<b>".$Value."</b> bit";
14986 }
14987 else {
14988 $Value = "<b>".$Value."</b> bits";
14989 }
14990 }
14991 else
14992 { # bytes
14993 $Value /= $BYTE_SIZE;
14994 if($Value==1) {
14995 $Value = "<b>".$Value."</b> byte";
14996 }
14997 else {
14998 $Value = "<b>".$Value."</b> bytes";
14999 }
15000 }
15001 }
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040015002 else
15003 {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015004 $Value = "<b>".htmlSpecChars($Value)."</b>";
15005 }
15006 $Content=~s/\Q$Macro\E/$Value/g;
15007 }
15008
15009 if($Content=~/(\A|[^\@\w])\@\w/)
15010 {
15011 if(not $IncompleteRules{$Level}{$Kind})
15012 { # only one warning
15013 printMsg("WARNING", "incomplete rule \"$Kind\" (\"$Level\")");
15014 $IncompleteRules{$Level}{$Kind} = 1;
15015 }
15016 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015017 return $Content;
15018}
15019
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040015020sub get_Report_SymbolProblems($$)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015021{
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015022 my ($TargetSeverity, $Level) = @_;
Andrey Ponomarenko16934472012-03-29 15:37:04 +040015023 my $INTERFACE_PROBLEMS = "";
15024 my (%ReportMap, %SymbolChanges) = ();
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015025 foreach my $Symbol (sort keys(%{$CompatProblems{$Level}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015026 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015027 my ($SN, $SS, $SV) = separate_symbol($Symbol);
15028 if($SV and defined $CompatProblems{$Level}{$SN}) {
15029 next;
15030 }
15031 foreach my $Kind (sort keys(%{$CompatProblems{$Level}{$Symbol}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015032 {
15033 if($CompatRules{$Level}{$Kind}{"Kind"} eq "Symbols"
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015034 and $Kind ne "Added_Symbol" and $Kind ne "Removed_Symbol")
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015035 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015036 my $HeaderName = $CompleteSignature{1}{$Symbol}{"Header"};
15037 my $DyLib = $Symbol_Library{1}{$Symbol};
15038 if(not $DyLib and my $VSym = $SymVer{1}{$Symbol})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015039 { # Symbol with Version
15040 $DyLib = $Symbol_Library{1}{$VSym};
15041 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040015042 if(not $DyLib)
15043 { # const global data
15044 $DyLib = "";
15045 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015046 if($Level eq "Source" and $ReportFormat eq "html")
15047 { # do not show library name in HTML report
15048 $DyLib = "";
15049 }
15050 %{$SymbolChanges{$Symbol}{$Kind}} = %{$CompatProblems{$Level}{$Symbol}{$Kind}};
15051 foreach my $Location (sort keys(%{$SymbolChanges{$Symbol}{$Kind}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015052 {
15053 my $Priority = getProblemSeverity($Level, $Kind);
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015054 if($Priority ne $TargetSeverity) {
15055 delete($SymbolChanges{$Symbol}{$Kind}{$Location});
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015056 }
15057 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015058 if(not keys(%{$SymbolChanges{$Symbol}{$Kind}}))
15059 {
15060 delete($SymbolChanges{$Symbol}{$Kind});
15061 next;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015062 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015063 $ReportMap{$HeaderName}{$DyLib}{$Symbol} = 1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015064 }
15065 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015066 if(not keys(%{$SymbolChanges{$Symbol}})) {
15067 delete($SymbolChanges{$Symbol});
15068 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015069 }
15070 if($ReportFormat eq "xml")
15071 { # XML
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015072 foreach my $HeaderName (sort {lc($a) cmp lc($b)} keys(%ReportMap))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015073 {
15074 $INTERFACE_PROBLEMS .= " <header name=\"$HeaderName\">\n";
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015075 foreach my $DyLib (sort {lc($a) cmp lc($b)} keys(%{$ReportMap{$HeaderName}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015076 {
15077 $INTERFACE_PROBLEMS .= " <library name=\"$DyLib\">\n";
15078 foreach my $Symbol (sort {lc($tr_name{$a}) cmp lc($tr_name{$b})} keys(%SymbolChanges))
15079 {
15080 $INTERFACE_PROBLEMS .= " <symbol name=\"$Symbol\">\n";
15081 foreach my $Kind (keys(%{$SymbolChanges{$Symbol}}))
15082 {
15083 foreach my $Location (sort keys(%{$SymbolChanges{$Symbol}{$Kind}}))
15084 {
15085 my %Problem = %{$SymbolChanges{$Symbol}{$Kind}{$Location}};
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040015086 $Problem{"Param_Pos"} = showPos($Problem{"Param_Pos"});
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015087 $INTERFACE_PROBLEMS .= " <problem id=\"$Kind\">\n";
15088 my $Change = $CompatRules{$Level}{$Kind}{"Change"};
15089 $INTERFACE_PROBLEMS .= " <change".getXmlParams($Change, \%Problem).">$Change</change>\n";
15090 my $Effect = $CompatRules{$Level}{$Kind}{"Effect"};
15091 $INTERFACE_PROBLEMS .= " <effect".getXmlParams($Effect, \%Problem).">$Effect</effect>\n";
15092 my $Overcome = $CompatRules{$Level}{$Kind}{"Overcome"};
15093 $INTERFACE_PROBLEMS .= " <overcome".getXmlParams($Overcome, \%Problem).">$Overcome</overcome>\n";
15094 $INTERFACE_PROBLEMS .= " </problem>\n";
15095 }
15096 }
15097 $INTERFACE_PROBLEMS .= " </symbol>\n";
15098 }
15099 $INTERFACE_PROBLEMS .= " </library>\n";
15100 }
15101 $INTERFACE_PROBLEMS .= " </header>\n";
15102 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015103 $INTERFACE_PROBLEMS = "<problems_with_symbols severity=\"$TargetSeverity\">\n".$INTERFACE_PROBLEMS."</problems_with_symbols>\n\n";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015104 }
15105 else
15106 { # HTML
15107 my $ProblemsNum = 0;
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015108 foreach my $HeaderName (sort {lc($a) cmp lc($b)} keys(%ReportMap))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015109 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015110 foreach my $DyLib (sort {lc($a) cmp lc($b)} keys(%{$ReportMap{$HeaderName}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015111 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015112 my (%NameSpaceSymbols, %NewSignature) = ();
15113 foreach my $Symbol (keys(%{$ReportMap{$HeaderName}{$DyLib}})) {
15114 $NameSpaceSymbols{get_IntNameSpace($Symbol, 1)}{$Symbol} = 1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015115 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015116 foreach my $NameSpace (sort keys(%NameSpaceSymbols))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015117 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015118 $INTERFACE_PROBLEMS .= getTitle($HeaderName, $DyLib, $NameSpace);
15119 my @SortedInterfaces = sort {lc($tr_name{$a}) cmp lc($tr_name{$b})} keys(%{$NameSpaceSymbols{$NameSpace}});
15120 foreach my $Symbol (@SortedInterfaces)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015121 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015122 my $Signature = get_Signature($Symbol, 1);
15123 my $SYMBOL_REPORT = "";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015124 my $ProblemNum = 1;
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015125 foreach my $Kind (keys(%{$SymbolChanges{$Symbol}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015126 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015127 foreach my $Location (sort keys(%{$SymbolChanges{$Symbol}{$Kind}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015128 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015129 my %Problem = %{$SymbolChanges{$Symbol}{$Kind}{$Location}};
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040015130 $Problem{"Param_Pos"} = showPos($Problem{"Param_Pos"});
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015131 if($Problem{"New_Signature"}) {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015132 $NewSignature{$Symbol} = $Problem{"New_Signature"};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015133 }
15134 if(my $Change = applyMacroses($Level, $Kind, $CompatRules{$Level}{$Kind}{"Change"}, \%Problem))
15135 {
15136 my $Effect = applyMacroses($Level, $Kind, $CompatRules{$Level}{$Kind}{"Effect"}, \%Problem);
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015137 $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 +040015138 $ProblemNum += 1;
15139 $ProblemsNum += 1;
15140 }
15141 }
15142 }
15143 $ProblemNum -= 1;
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015144 if($SYMBOL_REPORT)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015145 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015146 $INTERFACE_PROBLEMS .= $ContentSpanStart."<span class='extendable'>[+]</span> ";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015147 if($Signature) {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015148 $INTERFACE_PROBLEMS .= highLight_Signature_Italic_Color($Signature);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015149 }
15150 else {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015151 $INTERFACE_PROBLEMS .= $Symbol;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015152 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015153 $INTERFACE_PROBLEMS .= " ($ProblemNum)".$ContentSpanEnd."<br/>\n";
15154 $INTERFACE_PROBLEMS .= $ContentDivStart."\n";
15155 if($NewSignature{$Symbol})
15156 { # argument list changed to
15157 $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 +040015158 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015159 if($Symbol=~/\A(_Z|\?)/) {
15160 $INTERFACE_PROBLEMS .= "<span class='mangled'>&#160;&#160;&#160;&#160;[symbol: <b>$Symbol</b>]</span><br/>\n";
15161 }
15162 $INTERFACE_PROBLEMS .= "<table class='ptable'><tr><th width='2%'></th><th width='47%'>Change</th><th>Effect</th></tr>$SYMBOL_REPORT</table><br/>\n";
15163 $INTERFACE_PROBLEMS .= $ContentDivEnd;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015164 if($NameSpace) {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040015165 $INTERFACE_PROBLEMS=~s/\b\Q$NameSpace\E::\b//g;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015166 }
15167 }
15168 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015169 $INTERFACE_PROBLEMS .= "<br/>";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015170 }
15171 }
15172 }
15173 if($INTERFACE_PROBLEMS)
15174 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015175 $INTERFACE_PROBLEMS = insertIDs($INTERFACE_PROBLEMS);
15176 my $Title = "Problems with Symbols, $TargetSeverity Severity";
15177 if($TargetSeverity eq "Safe")
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015178 { # Safe Changes
15179 $Title = "Other Changes in Symbols";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015180 }
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040015181 $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 +040015182 }
15183 }
15184 return $INTERFACE_PROBLEMS;
15185}
15186
15187sub get_Report_TypeProblems($$)
15188{
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015189 my ($TargetSeverity, $Level) = @_;
Andrey Ponomarenko16934472012-03-29 15:37:04 +040015190 my $TYPE_PROBLEMS = "";
15191 my (%ReportMap, %TypeChanges, %TypeType) = ();
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015192 foreach my $Interface (sort keys(%{$CompatProblems{$Level}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015193 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015194 foreach my $Kind (keys(%{$CompatProblems{$Level}{$Interface}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015195 {
15196 if($CompatRules{$Level}{$Kind}{"Kind"} eq "Types")
15197 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015198 foreach my $Location (sort {cmp_locations($b, $a)} sort keys(%{$CompatProblems{$Level}{$Interface}{$Kind}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015199 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015200 my $TypeName = $CompatProblems{$Level}{$Interface}{$Kind}{$Location}{"Type_Name"};
15201 my $TypeType = $CompatProblems{$Level}{$Interface}{$Kind}{$Location}{"Type_Type"};
15202 my $Target = $CompatProblems{$Level}{$Interface}{$Kind}{$Location}{"Target"};
15203 $CompatProblems{$Level}{$Interface}{$Kind}{$Location}{"Type_Type"} = lc($TypeType);
15204 my $Severity = getProblemSeverity($Level, $Kind);
15205 if($Severity eq "Safe"
15206 and $TargetSeverity ne "Safe") {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015207 next;
15208 }
15209 if(not $TypeType{$TypeName}
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015210 or $TypeType{$TypeName} eq "struct")
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015211 { # register type of the type, select "class" if type has "class"- and "struct"-type changes
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015212 $TypeType{$TypeName} = $CompatProblems{$Level}{$Interface}{$Kind}{$Location}{"Type_Type"};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015213 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015214
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040015215 if(cmpSeverities($Type_MaxSeverity{$Level}{$TypeName}{$Kind}{$Target}, $Severity))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015216 { # select a problem with the highest priority
15217 next;
15218 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015219 %{$TypeChanges{$TypeName}{$Kind}{$Location}} = %{$CompatProblems{$Level}{$Interface}{$Kind}{$Location}};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015220 }
15221 }
15222 }
15223 }
15224 my %Kinds_Locations = ();
15225 foreach my $TypeName (keys(%TypeChanges))
15226 {
15227 my %Kinds_Target = ();
15228 foreach my $Kind (sort keys(%{$TypeChanges{$TypeName}}))
15229 {
15230 foreach my $Location (sort {cmp_locations($b, $a)} sort keys(%{$TypeChanges{$TypeName}{$Kind}}))
15231 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015232 my $Severity = getProblemSeverity($Level, $Kind);
15233 if($Severity ne $TargetSeverity)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015234 { # other priority
15235 delete($TypeChanges{$TypeName}{$Kind}{$Location});
15236 next;
15237 }
15238 $Kinds_Locations{$TypeName}{$Kind}{$Location} = 1;
15239 my $Target = $TypeChanges{$TypeName}{$Kind}{$Location}{"Target"};
15240 if($Kinds_Target{$Kind}{$Target})
15241 { # duplicate target
15242 delete($TypeChanges{$TypeName}{$Kind}{$Location});
15243 next;
15244 }
15245 $Kinds_Target{$Kind}{$Target} = 1;
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040015246 my $HeaderName = $TypeInfo{1}{$TName_Tid{1}{$TypeName}}{"Header"};
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015247 $ReportMap{$HeaderName}{$TypeName} = 1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015248 }
15249 if(not keys(%{$TypeChanges{$TypeName}{$Kind}})) {
15250 delete($TypeChanges{$TypeName}{$Kind});
15251 }
15252 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015253 if(not keys(%{$TypeChanges{$TypeName}})) {
15254 delete($TypeChanges{$TypeName});
15255 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015256 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +040015257 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 +040015258 if($ReportFormat eq "xml")
15259 { # XML
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015260 foreach my $HeaderName (sort {lc($a) cmp lc($b)} keys(%ReportMap))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015261 {
15262 $TYPE_PROBLEMS .= " <header name=\"$HeaderName\">\n";
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015263 foreach my $TypeName (keys(%{$ReportMap{$HeaderName}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015264 {
Andrey Ponomarenko5c09ef32012-06-14 18:17:33 +040015265 $TYPE_PROBLEMS .= " <type name=\"".xmlSpecChars($TypeName)."\">\n";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015266 foreach my $Kind (sort {$b=~/Size/ <=> $a=~/Size/} sort keys(%{$TypeChanges{$TypeName}}))
15267 {
15268 foreach my $Location (sort {cmp_locations($b, $a)} sort keys(%{$TypeChanges{$TypeName}{$Kind}}))
15269 {
15270 my %Problem = %{$TypeChanges{$TypeName}{$Kind}{$Location}};
15271 $TYPE_PROBLEMS .= " <problem id=\"$Kind\">\n";
15272 my $Change = $CompatRules{$Level}{$Kind}{"Change"};
15273 $TYPE_PROBLEMS .= " <change".getXmlParams($Change, \%Problem).">$Change</change>\n";
15274 my $Effect = $CompatRules{$Level}{$Kind}{"Effect"};
15275 $TYPE_PROBLEMS .= " <effect".getXmlParams($Effect, \%Problem).">$Effect</effect>\n";
15276 my $Overcome = $CompatRules{$Level}{$Kind}{"Overcome"};
15277 $TYPE_PROBLEMS .= " <overcome".getXmlParams($Overcome, \%Problem).">$Overcome</overcome>\n";
15278 $TYPE_PROBLEMS .= " </problem>\n";
15279 }
15280 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +040015281 $TYPE_PROBLEMS .= getAffectedSymbols($Level, $TypeName, $Kinds_Locations{$TypeName}, \@Symbols);
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015282 if($Level eq "Binary" and grep {$_=~/Virtual|Base_Class/} keys(%{$Kinds_Locations{$TypeName}})) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015283 $TYPE_PROBLEMS .= showVTables($TypeName);
15284 }
15285 $TYPE_PROBLEMS .= " </type>\n";
15286 }
15287 $TYPE_PROBLEMS .= " </header>\n";
15288 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015289 $TYPE_PROBLEMS = "<problems_with_types severity=\"$TargetSeverity\">\n".$TYPE_PROBLEMS."</problems_with_types>\n\n";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015290 }
15291 else
15292 { # HTML
15293 my $ProblemsNum = 0;
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015294 foreach my $HeaderName (sort {lc($a) cmp lc($b)} keys(%ReportMap))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015295 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015296 my (%NameSpace_Type) = ();
15297 foreach my $TypeName (keys(%{$ReportMap{$HeaderName}})) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015298 $NameSpace_Type{parse_TypeNameSpace($TypeName, 1)}{$TypeName} = 1;
15299 }
15300 foreach my $NameSpace (sort keys(%NameSpace_Type))
15301 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015302 $TYPE_PROBLEMS .= getTitle($HeaderName, "", $NameSpace);
15303 my @SortedTypes = sort {$TypeType{$a}." ".lc($a) cmp $TypeType{$b}." ".lc($b)} keys(%{$NameSpace_Type{$NameSpace}});
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015304 foreach my $TypeName (@SortedTypes)
15305 {
15306 my $ProblemNum = 1;
15307 my $TYPE_REPORT = "";
15308 foreach my $Kind (sort {$b=~/Size/ <=> $a=~/Size/} sort keys(%{$TypeChanges{$TypeName}}))
15309 {
15310 foreach my $Location (sort {cmp_locations($b, $a)} sort keys(%{$TypeChanges{$TypeName}{$Kind}}))
15311 {
15312 my %Problem = %{$TypeChanges{$TypeName}{$Kind}{$Location}};
15313 if(my $Change = applyMacroses($Level, $Kind, $CompatRules{$Level}{$Kind}{"Change"}, \%Problem))
15314 {
15315 my $Effect = applyMacroses($Level, $Kind, $CompatRules{$Level}{$Kind}{"Effect"}, \%Problem);
15316 $TYPE_REPORT .= "<tr><th>$ProblemNum</th><td align='left' valign='top'>".$Change."</td><td align='left' valign='top'>$Effect</td></tr>\n";
15317 $ProblemNum += 1;
15318 $ProblemsNum += 1;
15319 }
15320 }
15321 }
15322 $ProblemNum -= 1;
15323 if($TYPE_REPORT)
15324 {
Andrey Ponomarenko85043792012-05-14 16:48:07 +040015325 my $Affected = getAffectedSymbols($Level, $TypeName, $Kinds_Locations{$TypeName}, \@Symbols);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015326 my $ShowVTables = "";
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015327 if($Level eq "Binary" and grep {$_=~/Virtual|Base_Class/} keys(%{$Kinds_Locations{$TypeName}})) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015328 $ShowVTables = showVTables($TypeName);
15329 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015330 $TYPE_PROBLEMS .= $ContentSpanStart."<span class='extendable'>[+]</span> <span class='ttype'>".$TypeType{$TypeName}."</span> ".htmlSpecChars($TypeName)." ($ProblemNum)".$ContentSpanEnd;
15331 $TYPE_PROBLEMS .= "<br/>\n".$ContentDivStart."<table class='ptable'><tr>\n";
15332 $TYPE_PROBLEMS .= "<th width='2%'></th><th width='47%'>Change</th>\n";
15333 $TYPE_PROBLEMS .= "<th>Effect</th></tr>".$TYPE_REPORT."</table>\n";
15334 $TYPE_PROBLEMS .= $ShowVTables.$Affected."<br/><br/>".$ContentDivEnd."\n";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015335 if($NameSpace) {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040015336 $TYPE_PROBLEMS=~s/\b\Q$NameSpace\E::(\w|\~)/$1/g;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015337 }
15338 }
15339 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015340 $TYPE_PROBLEMS .= "<br/>";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015341 }
15342 }
15343 if($TYPE_PROBLEMS)
15344 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015345 $TYPE_PROBLEMS = insertIDs($TYPE_PROBLEMS);
15346 my $Title = "Problems with Data Types, $TargetSeverity Severity";
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015347 if($TargetSeverity eq "Safe")
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015348 { # Safe Changes
15349 $Title = "Other Changes in Data Types";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015350 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015351 $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 +040015352 }
15353 }
15354 return $TYPE_PROBLEMS;
15355}
15356
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015357sub get_Anchor($$$)
15358{
15359 my ($Kind, $Level, $Severity) = @_;
15360 if($JoinReport)
15361 {
15362 if($Severity eq "Safe") {
15363 return "Other_".$Level."_Changes_In_".$Kind."s";
15364 }
15365 else {
15366 return $Kind."_".$Level."_Problems_".$Severity;
15367 }
15368 }
15369 else
15370 {
15371 if($Severity eq "Safe") {
15372 return "Other_Changes_In_".$Kind."s";
15373 }
15374 else {
15375 return $Kind."_Problems_".$Severity;
15376 }
15377 }
15378}
15379
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015380sub showVTables($)
15381{
15382 my $TypeName = $_[0];
15383 my $TypeId1 = $TName_Tid{1}{$TypeName};
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040015384 my %Type1 = get_Type($TypeId1, 1);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015385 if(defined $Type1{"VTable"}
15386 and keys(%{$Type1{"VTable"}}))
15387 {
15388 my $TypeId2 = $TName_Tid{2}{$TypeName};
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040015389 my %Type2 = get_Type($TypeId2, 2);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015390 if(defined $Type2{"VTable"}
15391 and keys(%{$Type2{"VTable"}}))
15392 {
15393 my %Indexes = map {$_=>1} (keys(%{$Type1{"VTable"}}), keys(%{$Type2{"VTable"}}));
15394 my %Entries = ();
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015395 foreach my $Index (sort {int($a)<=>int($b)} (keys(%Indexes)))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015396 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015397 $Entries{$Index}{"E1"} = simpleVEntry($Type1{"VTable"}{$Index});
15398 $Entries{$Index}{"E2"} = simpleVEntry($Type2{"VTable"}{$Index});
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015399 }
15400 my $VTABLES = "";
15401 if($ReportFormat eq "xml")
15402 { # XML
15403 $VTABLES .= " <vtable>\n";
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015404 foreach my $Index (sort {int($a)<=>int($b)} (keys(%Entries)))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015405 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015406 $VTABLES .= " <entry offset=\"".$Index."\">\n";
Andrey Ponomarenko5c09ef32012-06-14 18:17:33 +040015407 $VTABLES .= " <old>".xmlSpecChars($Entries{$Index}{"E1"})."</old>\n";
15408 $VTABLES .= " <new>".xmlSpecChars($Entries{$Index}{"E2"})."</new>\n";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015409 $VTABLES .= " </entry>\n";
15410 }
15411 $VTABLES .= " </vtable>\n\n";
15412 }
15413 else
15414 { # HTML
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015415 $VTABLES .= "<table class='vtable'>";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015416 $VTABLES .= "<tr><th width='2%'>Offset</th>";
15417 $VTABLES .= "<th width='45%'>Virtual Table (Old) - ".(keys(%{$Type1{"VTable"}}))." entries</th>";
15418 $VTABLES .= "<th>Virtual Table (New) - ".(keys(%{$Type2{"VTable"}}))." entries</th></tr>";
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015419 foreach my $Index (sort {int($a)<=>int($b)} (keys(%Entries)))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015420 {
15421 my ($Color1, $Color2) = ("", "");
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015422 if($Entries{$Index}{"E1"} ne $Entries{$Index}{"E2"})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015423 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015424 if($Entries{$Index}{"E1"})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015425 {
Andrey Ponomarenko16934472012-03-29 15:37:04 +040015426 $Color1 = " class='failed'";
15427 $Color2 = " class='failed'";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015428 }
15429 else {
Andrey Ponomarenko16934472012-03-29 15:37:04 +040015430 $Color2 = " class='warning'";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015431 }
15432 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015433 $VTABLES .= "<tr><th>".$Index."</th>\n";
15434 $VTABLES .= "<td$Color1>".htmlSpecChars($Entries{$Index}{"E1"})."</td>\n";
15435 $VTABLES .= "<td$Color2>".htmlSpecChars($Entries{$Index}{"E2"})."</td></tr>\n";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015436 }
15437 $VTABLES .= "</table><br/>\n";
15438 $VTABLES = $ContentDivStart.$VTABLES.$ContentDivEnd;
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015439 $VTABLES = $ContentSpanStart_Info."[+] show v-table (old and new)".$ContentSpanEnd."<br/>\n".$VTABLES;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015440 }
15441 return $VTABLES;
15442 }
15443 }
15444 return "";
15445}
15446
15447sub simpleVEntry($)
15448{
15449 my $VEntry = $_[0];
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040015450 if(not defined $VEntry
15451 or $VEntry eq "") {
15452 return "";
15453 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015454 $VEntry=~s/\A(.+)::(_ZThn.+)\Z/$2/; # thunks
15455 $VEntry=~s/_ZTI\w+/typeinfo/g; # typeinfo
15456 if($VEntry=~/\A_ZThn.+\Z/) {
15457 $VEntry = "non-virtual thunk";
15458 }
15459 $VEntry=~s/\A\(int \(\*\)\(...\)\)([^\(\d])/$1/i;
15460 # support for old GCC versions
15461 $VEntry=~s/\A0u\Z/(int (*)(...))0/;
15462 $VEntry=~s/\A4294967268u\Z/(int (*)(...))-0x000000004/;
15463 $VEntry=~s/\A&_Z\Z/& _Z/;
15464 # templates
15465 if($VEntry=~s/ \[with (\w+) = (.+?)(, [^=]+ = .+|])\Z//g)
15466 { # std::basic_streambuf<_CharT, _Traits>::imbue [with _CharT = char, _Traits = std::char_traits<char>]
15467 # become std::basic_streambuf<char, ...>::imbue
15468 my ($Pname, $Pval) = ($1, $2);
15469 if($Pname eq "_CharT" and $VEntry=~/\Astd::/)
15470 { # stdc++ typedefs
15471 $VEntry=~s/<$Pname(, [^<>]+|)>/<$Pval>/g;
15472 # FIXME: simplify names using stdcxx typedefs (StdCxxTypedef)
15473 # The typedef info should be added to ABI dumps
15474 }
15475 else
15476 {
15477 $VEntry=~s/<$Pname>/<$Pval>/g;
15478 $VEntry=~s/<$Pname, [^<>]+>/<$Pval, ...>/g;
15479 }
15480 }
15481 $VEntry=~s/([^:]+)::\~([^:]+)\Z/~$1/; # destructors
15482 return $VEntry;
15483}
15484
Andrey Ponomarenko85043792012-05-14 16:48:07 +040015485sub getAffectedSymbols($$$$)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015486{
Andrey Ponomarenko85043792012-05-14 16:48:07 +040015487 my ($Level, $Target_TypeName, $Kinds_Locations, $Syms) = @_;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015488 my $LIMIT = 1000;
Andrey Ponomarenko85043792012-05-14 16:48:07 +040015489 if($#{$Syms}>=10000)
15490 { # reduce size of the report
15491 $LIMIT = 10;
15492 }
15493 my %SProblems = ();
15494 foreach my $Symbol (@{$Syms})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015495 {
Andrey Ponomarenko85043792012-05-14 16:48:07 +040015496 if(keys(%SProblems)>$LIMIT) {
15497 last;
15498 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015499 if(($Symbol=~/C2E|D2E|D0E/))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015500 { # duplicated problems for C2 constructors, D2 and D0 destructors
15501 next;
15502 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015503 my ($SN, $SS, $SV) = separate_symbol($Symbol);
15504 if($Level eq "Source")
15505 { # remove symbol version
15506 $Symbol=$SN;
15507 }
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040015508 my ($MinPath_Length, $ProblemLocation_Last) = (-1, "");
15509 my $Severity_Max = 0;
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015510 my $Signature = get_Signature($Symbol, 1);
15511 foreach my $Kind (keys(%{$CompatProblems{$Level}{$Symbol}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015512 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015513 foreach my $Location (keys(%{$CompatProblems{$Level}{$Symbol}{$Kind}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015514 {
15515 if(not defined $Kinds_Locations->{$Kind}
15516 or not $Kinds_Locations->{$Kind}{$Location}) {
15517 next;
15518 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015519 if($SV and defined $CompatProblems{$Level}{$SN}
15520 and defined $CompatProblems{$Level}{$SN}{$Kind}{$Location})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015521 { # duplicated problems for versioned symbols
15522 next;
15523 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015524 my $Type_Name = $CompatProblems{$Level}{$Symbol}{$Kind}{$Location}{"Type_Name"};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015525 next if($Type_Name ne $Target_TypeName);
15526
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015527 my $Position = $CompatProblems{$Level}{$Symbol}{$Kind}{$Location}{"Param_Pos"};
15528 my $Param_Name = $CompatProblems{$Level}{$Symbol}{$Kind}{$Location}{"Param_Name"};
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040015529 my $Severity = getProblemSeverity($Level, $Kind);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015530 my $Path_Length = 0;
15531 my $ProblemLocation = $Location;
15532 if($Type_Name) {
15533 $ProblemLocation=~s/->\Q$Type_Name\E\Z//g;
15534 }
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040015535 while($ProblemLocation=~/\-\>/g) {
15536 $Path_Length += 1;
15537 }
15538 if($MinPath_Length==-1 or ($Path_Length<=$MinPath_Length and $Severity_Val{$Severity}>$Severity_Max)
15539 or (cmp_locations($ProblemLocation, $ProblemLocation_Last) and $Severity_Val{$Severity}==$Severity_Max))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015540 {
15541 $MinPath_Length = $Path_Length;
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040015542 $Severity_Max = $Severity_Val{$Severity};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015543 $ProblemLocation_Last = $ProblemLocation;
Andrey Ponomarenko85043792012-05-14 16:48:07 +040015544 %{$SProblems{$Symbol}} = (
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040015545 "Descr"=>getAffectDescription($Level, $Symbol, $Kind, $Location),
15546 "Severity_Max"=>$Severity_Max,
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015547 "Signature"=>$Signature,
15548 "Position"=>$Position,
15549 "Param_Name"=>$Param_Name,
15550 "Location"=>$Location
15551 );
15552 }
15553 }
15554 }
15555 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +040015556 my @Symbols = keys(%SProblems);
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015557 @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 +040015558 @Symbols = sort {$SProblems{$b}{"Severity_Max"}<=>$SProblems{$a}{"Severity_Max"}} @Symbols;
15559 if($#Symbols+1>$LIMIT)
15560 { # remove last element
15561 pop(@Symbols);
15562 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015563 my $Affected = "";
15564 if($ReportFormat eq "xml")
15565 { # XML
15566 $Affected .= " <affected>\n";
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015567 foreach my $Symbol (@Symbols)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015568 {
Andrey Ponomarenko85043792012-05-14 16:48:07 +040015569 my $Param_Name = $SProblems{$Symbol}{"Param_Name"};
15570 my $Description = $SProblems{$Symbol}{"Descr"};
15571 my $Location = $SProblems{$Symbol}{"Location"};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015572 my $Target = "";
15573 if($Param_Name) {
15574 $Target = " affected=\"param\" param_name=\"$Param_Name\"";
15575 }
15576 elsif($Location=~/\Aretval(\-|\Z)/i) {
15577 $Target = " affected=\"retval\"";
15578 }
15579 elsif($Location=~/\Athis(\-|\Z)/i) {
15580 $Target = " affected=\"this\"";
15581 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015582 $Affected .= " <symbol$Target name=\"$Symbol\">\n";
Andrey Ponomarenko5c09ef32012-06-14 18:17:33 +040015583 $Affected .= " <comment>".xmlSpecChars($Description)."</comment>\n";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015584 $Affected .= " </symbol>\n";
15585 }
15586 $Affected .= " </affected>\n";
15587 }
15588 else
15589 { # HTML
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015590 foreach my $Symbol (@Symbols)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015591 {
Andrey Ponomarenko85043792012-05-14 16:48:07 +040015592 my $Description = $SProblems{$Symbol}{"Descr"};
15593 my $Signature = $SProblems{$Symbol}{"Signature"};
15594 my $Pos = $SProblems{$Symbol}{"Position"};
Andrey Ponomarenkoa01311b2012-06-08 17:20:02 +040015595 $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 +040015596 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +040015597 if(keys(%SProblems)>$LIMIT) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015598 $Affected .= "and others ...<br/>";
15599 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +040015600 $Affected = "<div class='affected'>".$Affected."</div>";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015601 if($Affected)
15602 {
15603 $Affected = $ContentDivStart.$Affected.$ContentDivEnd;
Andrey Ponomarenko85043792012-05-14 16:48:07 +040015604 $Affected = $ContentSpanStart_Affected."[+] affected symbols (".(keys(%SProblems)>$LIMIT?">".$LIMIT:keys(%SProblems)).")".$ContentSpanEnd.$Affected;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015605 }
15606 }
15607 return $Affected;
15608}
15609
15610sub cmp_locations($$)
15611{
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040015612 my ($L1, $L2) = @_;
15613 if($L2=~/\b(retval|this)\b/
15614 and $L1!~/\b(retval|this)\b/ and $L1!~/\-\>/) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015615 return 1;
15616 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040015617 if($L2=~/\b(retval|this)\b/ and $L2=~/\-\>/
15618 and $L1!~/\b(retval|this)\b/ and $L1=~/\-\>/) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015619 return 1;
15620 }
15621 return 0;
15622}
15623
15624sub getAffectDescription($$$$)
15625{
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015626 my ($Level, $Symbol, $Kind, $Location) = @_;
15627 my %Problem = %{$CompatProblems{$Level}{$Symbol}{$Kind}{$Location}};
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040015628 my $PPos = showPos($Problem{"Param_Pos"});
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015629 my @Sentence = ();
15630 $Location=~s/\A(.*)\-\>.+?\Z/$1/;
15631 if($Kind eq "Overridden_Virtual_Method"
15632 or $Kind eq "Overridden_Virtual_Method_B") {
15633 push(@Sentence, "The method '".$Problem{"New_Value"}."' will be called instead of this method.");
15634 }
15635 elsif($CompatRules{$Level}{$Kind}{"Kind"} eq "Types")
15636 {
15637 if($Location eq "this" or $Kind=~/(\A|_)Virtual(_|\Z)/)
15638 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015639 my $METHOD_TYPE = $CompleteSignature{1}{$Symbol}{"Constructor"}?"constructor":"method";
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040015640 my $ClassName = $TypeInfo{1}{$CompleteSignature{1}{$Symbol}{"Class"}}{"Name"};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015641 if($ClassName eq $Problem{"Type_Name"}) {
15642 push(@Sentence, "This $METHOD_TYPE is from \'".$Problem{"Type_Name"}."\' class.");
15643 }
15644 else {
15645 push(@Sentence, "This $METHOD_TYPE is from derived class \'".$ClassName."\'.");
15646 }
15647 }
15648 else
15649 {
15650 if($Location=~/retval/)
15651 { # return value
15652 if($Location=~/\-\>/) {
15653 push(@Sentence, "Field \'".$Location."\' in return value");
15654 }
15655 else {
15656 push(@Sentence, "Return value");
15657 }
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040015658 if(my $Init = $Problem{"InitialType_Type"})
15659 {
15660 if($Init eq "Pointer") {
15661 push(@Sentence, "(pointer)");
15662 }
15663 elsif($Init eq "Ref") {
15664 push(@Sentence, "(reference)");
15665 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015666 }
15667 }
15668 elsif($Location=~/this/)
15669 { # "this" pointer
15670 if($Location=~/\-\>/) {
15671 push(@Sentence, "Field \'".$Location."\' in the object of this method");
15672 }
15673 else {
15674 push(@Sentence, "\'this\' pointer");
15675 }
15676 }
15677 else
15678 { # parameters
15679 if($Location=~/\-\>/) {
15680 push(@Sentence, "Field \'".$Location."\' in $PPos parameter");
15681 }
15682 else {
15683 push(@Sentence, "$PPos parameter");
15684 }
15685 if($Problem{"Param_Name"}) {
15686 push(@Sentence, "\'".$Problem{"Param_Name"}."\'");
15687 }
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040015688 if(my $Init = $Problem{"InitialType_Type"})
15689 {
15690 if($Init eq "Pointer") {
15691 push(@Sentence, "(pointer)");
15692 }
15693 elsif($Init eq "Ref") {
15694 push(@Sentence, "(reference)");
15695 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015696 }
15697 }
15698 if($Location eq "this") {
15699 push(@Sentence, "has base type \'".$Problem{"Type_Name"}."\'.");
15700 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040015701 elsif(defined $Problem{"Start_Type_Name"}
15702 and $Problem{"Start_Type_Name"} eq $Problem{"Type_Name"}) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015703 push(@Sentence, "has type \'".$Problem{"Type_Name"}."\'.");
15704 }
15705 else {
15706 push(@Sentence, "has base type \'".$Problem{"Type_Name"}."\'.");
15707 }
15708 }
15709 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040015710 if($ExtendedSymbols{$Symbol}) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015711 push(@Sentence, " This is a symbol from an artificial external library that may use the \'$TargetLibraryName\' library and change its ABI after recompiling.");
15712 }
15713 return join(" ", @Sentence);
15714}
15715
15716sub get_XmlSign($$)
15717{
15718 my ($Symbol, $LibVersion) = @_;
15719 my $Info = $CompleteSignature{$LibVersion}{$Symbol};
15720 my $Report = "";
15721 foreach my $Pos (sort {int($a)<=>int($b)} keys(%{$Info->{"Param"}}))
15722 {
15723 my $Name = $Info->{"Param"}{$Pos}{"name"};
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040015724 my $Type = $Info->{"Param"}{$Pos}{"type"};
15725 my $TypeName = $TypeInfo{$LibVersion}{$Type}{"Name"};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015726 foreach my $Typedef (keys(%ChangedTypedef))
15727 {
15728 my $Base = $Typedef_BaseName{$LibVersion}{$Typedef};
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040015729 $TypeName=~s/\b\Q$Typedef\E\b/$Base/g;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015730 }
15731 $Report .= " <param pos=\"$Pos\">\n";
15732 $Report .= " <name>".$Name."</name>\n";
Andrey Ponomarenko5c09ef32012-06-14 18:17:33 +040015733 $Report .= " <type>".xmlSpecChars($TypeName)."</type>\n";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015734 $Report .= " </param>\n";
15735 }
15736 if(my $Return = $Info->{"Return"})
15737 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040015738 my $RTName = $TypeInfo{$LibVersion}{$Return}{"Name"};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015739 $Report .= " <retval>\n";
Andrey Ponomarenko5c09ef32012-06-14 18:17:33 +040015740 $Report .= " <type>".xmlSpecChars($RTName)."</type>\n";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015741 $Report .= " </retval>\n";
15742 }
15743 return $Report;
15744}
15745
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015746sub get_Report_SymbolsInfo($)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015747{
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015748 my $Level = $_[0];
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015749 my $Report = "<symbols_info>\n";
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015750 foreach my $Symbol (sort keys(%{$CompatProblems{$Level}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015751 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015752 my ($SN, $SS, $SV) = separate_symbol($Symbol);
15753 if($SV and defined $CompatProblems{$Level}{$SN}) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015754 next;
15755 }
15756 $Report .= " <symbol name=\"$Symbol\">\n";
15757 my ($S1, $P1, $S2, $P2) = ();
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015758 if(not $AddedInt{$Level}{$Symbol})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015759 {
15760 if(defined $CompleteSignature{1}{$Symbol}
15761 and defined $CompleteSignature{1}{$Symbol}{"Header"})
15762 {
15763 $P1 = get_XmlSign($Symbol, 1);
15764 $S1 = get_Signature($Symbol, 1);
15765 }
15766 elsif($Symbol=~/\A(_Z|\?)/) {
15767 $S1 = $tr_name{$Symbol};
15768 }
15769 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015770 if(not $RemovedInt{$Level}{$Symbol})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015771 {
15772 if(defined $CompleteSignature{2}{$Symbol}
15773 and defined $CompleteSignature{2}{$Symbol}{"Header"})
15774 {
15775 $P2 = get_XmlSign($Symbol, 2);
15776 $S2 = get_Signature($Symbol, 2);
15777 }
15778 elsif($Symbol=~/\A(_Z|\?)/) {
15779 $S2 = $tr_name{$Symbol};
15780 }
15781 }
15782 if($S1)
15783 {
Andrey Ponomarenko5c09ef32012-06-14 18:17:33 +040015784 $Report .= " <old signature=\"".xmlSpecChars($S1)."\">\n";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015785 $Report .= $P1;
15786 $Report .= " </old>\n";
15787 }
15788 if($S2 and $S2 ne $S1)
15789 {
Andrey Ponomarenko5c09ef32012-06-14 18:17:33 +040015790 $Report .= " <new signature=\"".xmlSpecChars($S2)."\">\n";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015791 $Report .= $P2;
15792 $Report .= " </new>\n";
15793 }
15794 $Report .= " </symbol>\n";
15795 }
15796 $Report .= "</symbols_info>\n";
15797 return $Report;
15798}
15799
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015800sub writeReport($$)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015801{
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015802 my ($Level, $Report) = @_;
15803 if($ReportFormat eq "xml") {
15804 $Report = "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n".$Report;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015805 }
15806 if($StdOut)
15807 { # --stdout option
15808 print STDOUT $Report;
15809 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015810 else
15811 {
15812 my $RPath = getReportPath($Level);
Andrey Ponomarenko85043792012-05-14 16:48:07 +040015813 mkpath(get_dirname($RPath));
15814
15815 open(REPORT, ">", $RPath) || die ("can't open file \'$RPath\': $!\n");
15816 print REPORT $Report;
15817 close(REPORT);
15818
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040015819 if($Browse or $OpenReport)
15820 { # open in browser
15821 openReport($RPath);
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015822 if($JoinReport or $DoubleReport)
15823 {
15824 if($Level eq "Binary")
15825 { # wait to open a browser
15826 sleep(1);
15827 }
15828 }
15829 }
15830 }
15831}
15832
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040015833sub openReport($)
15834{
15835 my $Path = $_[0];
15836 my $Cmd = "";
15837 if($Browse)
15838 { # user-defined browser
Andrey Ponomarenkoa01311b2012-06-08 17:20:02 +040015839 $Cmd = $Browse." \"$Path\"";
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040015840 }
15841 if(not $Cmd)
15842 { # default browser
15843 if($OSgroup eq "macos") {
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +040015844 $Cmd = "open \"$Path\"";
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040015845 }
15846 elsif($OSgroup eq "windows") {
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +040015847 $Cmd = "start ".path_format($Path, $OSgroup);
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040015848 }
15849 else
15850 { # linux, freebsd, solaris
15851 my @Browsers = (
15852 "x-www-browser",
15853 "sensible-browser",
15854 "firefox",
15855 "opera",
15856 "xdg-open",
15857 "lynx",
15858 "links"
15859 );
15860 foreach my $Br (@Browsers)
15861 {
15862 if($Br = get_CmdPath($Br))
15863 {
Andrey Ponomarenkoa01311b2012-06-08 17:20:02 +040015864 $Cmd = $Br." \"$Path\"";
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040015865 last;
15866 }
15867 }
15868 }
15869 }
15870 if($Cmd)
15871 {
15872 if($Debug) {
15873 printMsg("INFO", "running $Cmd");
15874 }
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +040015875 if($OSgroup ne "windows"
15876 and $OSgroup ne "macos")
15877 {
15878 if($Cmd!~/lynx|links/) {
15879 $Cmd .= " >\"$TMP_DIR/null\" 2>&1 &";
15880 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040015881 }
15882 system($Cmd);
15883 }
15884 else {
15885 printMsg("ERROR", "cannot open report in browser");
15886 }
15887}
15888
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015889sub getReport($)
15890{
15891 my $Level = $_[0];
15892 if($ReportFormat eq "xml")
15893 { # XML
15894
15895 if($Level eq "Join")
15896 {
15897 my $Report = "<reports>\n";
15898 $Report .= getReport("Binary");
15899 $Report .= getReport("Source");
15900 $Report .= "</reports>\n";
15901 return $Report;
15902 }
15903 else
15904 {
15905 my $Report = "<report kind=\"".lc($Level)."\" version=\"$XML_REPORT_VERSION\">\n\n";
15906 my ($Summary, $MetaData) = get_Summary($Level);
15907 $Report .= $Summary."\n";
15908 $Report .= get_Report_Added($Level).get_Report_Removed($Level);
15909 $Report .= get_Report_Problems("High", $Level).get_Report_Problems("Medium", $Level).get_Report_Problems("Low", $Level).get_Report_Problems("Safe", $Level);
15910 $Report .= get_Report_SymbolsInfo($Level);
15911 $Report .= "</report>\n";
15912 return $Report;
15913 }
15914 }
15915 else
15916 { # HTML
15917 my $CssStyles = readModule("Styles", "Report.css");
15918 my $JScripts = readModule("Scripts", "Sections.js");
15919 if($Level eq "Join")
15920 {
15921 $CssStyles .= "\n".readModule("Styles", "Tabs.css");
15922 $JScripts .= "\n".readModule("Scripts", "Tabs.js");
Andrey Ponomarenkob8d203d2012-05-25 18:11:07 +040015923 my $Title = $TargetLibraryFName.": ".$Descriptor{1}{"Version"}." to ".$Descriptor{2}{"Version"}." compatibility report";
15924 my $Keywords = $TargetLibraryFName.", compatibility, API, report";
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015925 my $Description = "Compatibility report for the $TargetLibraryFName $TargetComponent between ".$Descriptor{1}{"Version"}." and ".$Descriptor{2}{"Version"}." versions";
15926 my ($BSummary, $BMetaData) = get_Summary("Binary");
15927 my ($SSummary, $SMetaData) = get_Summary("Source");
15928 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>";
15929 $Report .= get_Report_Header("Join")."
15930 <br/><div class='tabset'>
Andrey Ponomarenko16934472012-03-29 15:37:04 +040015931 <a id='BinaryID' href='#BinaryTab' class='tab active'>Binary<br/>Compatibility</a>
15932 <a id='SourceID' href='#SourceTab' style='margin-left:3px' class='tab disabled'>Source<br/>Compatibility</a>
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015933 </div>";
15934 $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>";
15935 $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 +040015936 $Report .= getReportFooter($TargetLibraryFName, not $JoinReport);
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015937 $Report .= "\n<div style='height:999px;'></div>\n</body></html>";
15938 return $Report;
15939 }
15940 else
15941 {
15942 my ($Summary, $MetaData) = get_Summary($Level);
Andrey Ponomarenkob8d203d2012-05-25 18:11:07 +040015943 my $Title = $TargetLibraryFName.": ".$Descriptor{1}{"Version"}." to ".$Descriptor{2}{"Version"}." ".lc($Level)." compatibility report";
15944 my $Keywords = $TargetLibraryFName.", ".lc($Level)." compatibility, API, report";
15945 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 +040015946 if($Level eq "Binary")
15947 {
15948 if(getArch(1) eq getArch(2)
15949 and getArch(1) ne "unknown") {
15950 $Description .= " on ".showArch(getArch(1));
15951 }
15952 }
15953 my $Report = "<!-\- $MetaData -\->\n".composeHTML_Head($Title, $Keywords, $Description, $CssStyles, $JScripts)."\n<body>\n<div><a name='Top'></a>\n";
15954 $Report .= get_Report_Header($Level)."\n".$Summary."\n";
15955 $Report .= get_Report_Added($Level).get_Report_Removed($Level);
15956 $Report .= get_Report_Problems("High", $Level).get_Report_Problems("Medium", $Level).get_Report_Problems("Low", $Level).get_Report_Problems("Safe", $Level);
15957 $Report .= get_SourceInfo();
15958 $Report .= "</div>\n<br/><br/><br/><hr/>\n";
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040015959 $Report .= getReportFooter($TargetLibraryFName, not $JoinReport);
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015960 $Report .= "\n<div style='height:999px;'></div>\n</body></html>";
15961 return $Report;
15962 }
15963 }
15964}
15965
Andrey Ponomarenko16934472012-03-29 15:37:04 +040015966sub getLegend()
15967{
15968 return "<br/>
15969<table class='summary'>
15970<tr>
15971 <td class='new'>added</td>
15972 <td class='passed'>compatible</td>
15973</tr>
15974<tr>
15975 <td class='warning'>warning</td>
15976 <td class='failed'>incompatible</td>
15977</tr></table>\n";
15978}
15979
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015980sub createReport()
15981{
15982 if($JoinReport)
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040015983 { # --stdout
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015984 writeReport("Join", getReport("Join"));
15985 }
15986 elsif($DoubleReport)
15987 { # default
15988 writeReport("Binary", getReport("Binary"));
15989 writeReport("Source", getReport("Source"));
15990 }
15991 elsif($BinaryOnly)
15992 { # --binary
15993 writeReport("Binary", getReport("Binary"));
15994 }
15995 elsif($SourceOnly)
15996 { # --source
15997 writeReport("Source", getReport("Source"));
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015998 }
15999}
16000
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040016001sub getReportFooter($$)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040016002{
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040016003 my ($LibName, $Wide) = @_;
16004 my $FooterStyle = $Wide?"width:99%":"width:97%;padding-top:3px";
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040016005 my $Footer = "<div style='$FooterStyle;font-size:11px;' align='right'><i>Generated on ".(localtime time); # report date
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040016006 $Footer .= " for <span style='font-weight:bold'>$LibName</span>"; # tested library/system name
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040016007 $Footer .= " by <a href='".$HomePage{"Wiki"}."'>ABI Compliance Checker</a>"; # tool name
16008 my $ToolSummary = "<br/>A tool for checking backward compatibility of a C/C++ library API&#160;&#160;";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040016009 $Footer .= " $TOOL_VERSION &#160;$ToolSummary</i></div>"; # tool version
16010 return $Footer;
16011}
16012
16013sub get_Report_Problems($$)
16014{
16015 my ($Priority, $Level) = @_;
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040016016 my $Report = get_Report_TypeProblems($Priority, $Level);
Andrey Ponomarenko16934472012-03-29 15:37:04 +040016017 if(my $SProblems = get_Report_SymbolProblems($Priority, $Level)) {
16018 $Report .= $SProblems;
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040016019 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040016020 if($Priority eq "Low")
16021 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040016022 $Report .= get_Report_ChangedConstants($Level);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040016023 if($ReportFormat eq "html") {
16024 if($CheckImpl and $Level eq "Binary") {
16025 $Report .= get_Report_Impl();
16026 }
16027 }
16028 }
16029 if($ReportFormat eq "html")
16030 {
16031 if($Report)
16032 { # add anchor
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040016033 if($JoinReport)
16034 {
16035 if($Priority eq "Safe") {
16036 $Report = "<a name=\'Other_".$Level."_Changes\'></a>".$Report;
16037 }
16038 else {
16039 $Report = "<a name=\'".$Priority."_Risk_".$Level."_Problems\'></a>".$Report;
16040 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040016041 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040016042 else
16043 {
16044 if($Priority eq "Safe") {
16045 $Report = "<a name=\'Other_Changes\'></a>".$Report;
16046 }
16047 else {
16048 $Report = "<a name=\'".$Priority."_Risk_Problems\'></a>".$Report;
16049 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040016050 }
16051 }
16052 }
16053 return $Report;
16054}
16055
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040016056sub composeHTML_Head($$$$$)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040016057{
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040016058 my ($Title, $Keywords, $Description, $Styles, $Scripts) = @_;
16059 return "<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.0 Transitional//EN\" \"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd\">
16060 <html xmlns=\"http://www.w3.org/1999/xhtml\" xml:lang=\"en\" lang=\"en\">
16061 <head>
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040016062 <meta http-equiv=\"Content-Type\" content=\"text/html; charset=utf-8\" />
16063 <meta name=\"keywords\" content=\"$Keywords\" />
16064 <meta name=\"description\" content=\"$Description\" />
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040016065 <title>
16066 $Title
16067 </title>
16068 <style type=\"text/css\">
16069 $Styles
16070 </style>
16071 <script type=\"text/javascript\" language=\"JavaScript\">
16072 <!--
16073 $Scripts
16074 -->
16075 </script>
16076 </head>";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040016077}
16078
16079sub insertIDs($)
16080{
16081 my $Text = $_[0];
16082 while($Text=~/CONTENT_ID/)
16083 {
16084 if(int($Content_Counter)%2) {
16085 $ContentID -= 1;
16086 }
16087 $Text=~s/CONTENT_ID/c_$ContentID/;
16088 $ContentID += 1;
16089 $Content_Counter += 1;
16090 }
16091 return $Text;
16092}
16093
16094sub checkPreprocessedUnit($)
16095{
16096 my $Path = $_[0];
Andrey Ponomarenkoa01311b2012-06-08 17:20:02 +040016097 my ($CurHeader, $CurHeaderName) = ("", "");
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040016098 open(PREPROC, $Path) || die ("can't open file \'$Path\': $!\n");
Andrey Ponomarenkoa01311b2012-06-08 17:20:02 +040016099 while(my $Line = <PREPROC>)
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040016100 { # detecting public and private constants
Andrey Ponomarenkoa01311b2012-06-08 17:20:02 +040016101
16102 if(substr($Line, 0, 1) eq "#")
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040016103 {
Andrey Ponomarenkoa01311b2012-06-08 17:20:02 +040016104 chomp($Line);
16105 if($Line=~/\A\#\s+\d+\s+\"(.+)\"/)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040016106 {
Andrey Ponomarenkoa01311b2012-06-08 17:20:02 +040016107 $CurHeader = path_format($1, $OSgroup);
16108 $CurHeaderName = get_filename($CurHeader);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040016109 }
Andrey Ponomarenkoa01311b2012-06-08 17:20:02 +040016110 if(not $Include_Neighbors{$Version}{$CurHeaderName}
16111 and not $Registered_Headers{$Version}{$CurHeader})
16112 { # not a target
16113 next;
16114 }
16115 if(not is_target_header($CurHeaderName, 1)
16116 and not is_target_header($CurHeaderName, 2))
16117 { # user-defined header
16118 next;
16119 }
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040016120 if($Line=~/\A\#\s*define\s+(\w+)\s+(.+)\s*\Z/)
Andrey Ponomarenkoa01311b2012-06-08 17:20:02 +040016121 {
16122 my ($Name, $Value) = ($1, $2);
16123 if(not $Constants{$Version}{$Name}{"Access"})
16124 {
16125 $Constants{$Version}{$Name}{"Access"} = "public";
16126 $Constants{$Version}{$Name}{"Value"} = $Value;
16127 $Constants{$Version}{$Name}{"Header"} = $CurHeaderName;
16128 }
16129 }
16130 elsif($Line=~/\A\#[ \t]*undef[ \t]+([_A-Z]+)[ \t]*/) {
16131 $Constants{$Version}{$1}{"Access"} = "private";
16132 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040016133 }
16134 }
16135 close(PREPROC);
16136 foreach my $Constant (keys(%{$Constants{$Version}}))
16137 {
Andrey Ponomarenkoa01311b2012-06-08 17:20:02 +040016138 if($Constants{$Version}{$Constant}{"Access"} eq "private"
16139 or $Constant=~/_h\Z/i
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040016140 or isBuiltIn($Constants{$Version}{$Constant}{"Header"}))
16141 { # skip private constants
16142 delete($Constants{$Version}{$Constant});
16143 }
16144 else {
16145 delete($Constants{$Version}{$Constant}{"Access"});
16146 }
16147 }
Andrey Ponomarenkoa01311b2012-06-08 17:20:02 +040016148 if($Debug)
16149 {
16150 mkpath($DEBUG_PATH{$Version});
16151 copy($Path, $DEBUG_PATH{$Version}."/preprocessor.txt");
16152 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040016153}
16154
Andrey Ponomarenko16934472012-03-29 15:37:04 +040016155sub uncoverConstant($$)
16156{
16157 my ($LibVersion, $Constant) = @_;
16158 return "" if(not $LibVersion or not $Constant);
16159 return $Constant if(isCyclical(\@RecurConstant, $Constant));
16160 if(defined $Cache{"uncoverConstant"}{$LibVersion}{$Constant}) {
16161 return $Cache{"uncoverConstant"}{$LibVersion}{$Constant};
16162 }
16163 my $Value = $Constants{$LibVersion}{$Constant}{"Value"};
16164 if(defined $Value)
16165 {
16166 if($Value=~/\A[A-Z0-9_]+\Z/ and $Value=~/[A-Z]/)
16167 {
16168 push(@RecurConstant, $Constant);
16169 my $Uncovered = uncoverConstant($LibVersion, $Value);
16170 if($Uncovered ne "") {
16171 $Value = $Uncovered;
16172 }
16173 pop(@RecurConstant);
16174 }
16175 # FIXME: uncover $Value using all the enum constants
16176 # USECASE: change of define NC_LONG from NC_INT (enum value) to NC_INT (define)
16177 return ($Cache{"uncoverConstant"}{$LibVersion}{$Constant} = $Value);
16178 }
16179 return ($Cache{"uncoverConstant"}{$LibVersion}{$Constant} = "");
16180}
16181
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040016182my %IgnoreConstant = map {$_=>1} (
16183 "VERSION",
16184 "VERSIONCODE",
16185 "VERNUM",
16186 "VERS_INFO",
16187 "PATCHLEVEL",
16188 "INSTALLPREFIX",
16189 "VBUILD",
16190 "VPATCH",
16191 "VMINOR",
16192 "BUILD_STRING",
16193 "BUILD_TIME",
16194 "PACKAGE_STRING",
16195 "PRODUCTION",
16196 "CONFIGURE_COMMAND",
16197 "INSTALLDIR",
16198 "BINDIR",
16199 "CONFIG_FILE_PATH",
16200 "DATADIR",
16201 "EXTENSION_DIR",
16202 "INCLUDE_PATH",
16203 "LIBDIR",
16204 "LOCALSTATEDIR",
16205 "SBINDIR",
16206 "SYSCONFDIR",
16207 "RELEASE",
16208 "SOURCE_ID",
16209 "SUBMINOR",
16210 "MINOR",
16211 "MINNOR",
16212 "MINORVERSION",
16213 "MAJOR",
16214 "MAJORVERSION",
16215 "MICRO",
16216 "MICROVERSION",
16217 "BINARY_AGE",
16218 "INTERFACE_AGE",
16219 "CORE_ABI",
16220 "PATCH",
16221 "COPYRIGHT",
16222 "TIMESTAMP",
16223 "REVISION",
16224 "PACKAGE_TAG",
16225 "PACKAGEDATE",
16226 "NUMVERSION",
16227 "Release",
16228 "Version"
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040016229);
16230
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040016231sub mergeConstants($)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040016232{
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040016233 my $Level = $_[0];
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040016234 foreach my $Constant (keys(%{$Constants{1}}))
16235 {
16236 if($SkipConstants{1}{$Constant})
16237 { # skipped by the user
16238 next;
16239 }
Andrey Ponomarenko16934472012-03-29 15:37:04 +040016240 if(not defined $Constants{2}{$Constant}{"Value"}
16241 or $Constants{2}{$Constant}{"Value"} eq "")
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040016242 { # empty value
16243 next;
16244 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +040016245 my $Header = $Constants{1}{$Constant}{"Header"};
16246 if(not is_target_header($Header, 1)
16247 and not is_target_header($Header, 2))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040016248 { # user-defined header
16249 next;
16250 }
16251 my ($Old_Value, $New_Value, $Old_Value_Pure, $New_Value_Pure);
Andrey Ponomarenko16934472012-03-29 15:37:04 +040016252 $Old_Value = $Old_Value_Pure = uncoverConstant(1, $Constant);
16253 $New_Value = $New_Value_Pure = uncoverConstant(2, $Constant);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040016254 $Old_Value_Pure=~s/(\W)\s+/$1/g;
16255 $Old_Value_Pure=~s/\s+(\W)/$1/g;
16256 $New_Value_Pure=~s/(\W)\s+/$1/g;
16257 $New_Value_Pure=~s/\s+(\W)/$1/g;
16258 next if($New_Value_Pure eq "" or $Old_Value_Pure eq "");
16259 if($New_Value_Pure ne $Old_Value_Pure)
16260 { # different values
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040016261 if($Level eq "Binary")
16262 {
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040016263 foreach (keys(%IgnoreConstant))
16264 {
16265 if($Constant=~/(\A|_)$_(_|\Z)/)
16266 { # ignore library version
16267 next;
16268 }
16269 if(/\A[A-Z].*[a-z]\Z/)
16270 {
16271 if($Constant=~/(\A|[a-z])$_([A-Z]|\Z)/)
16272 { # ignore library version
16273 next;
16274 }
16275 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040016276 }
16277 if($Constant=~/(\A|_)(lib|open|)$TargetLibraryShortName(_|)(VERSION|VER|DATE|API|PREFIX)(_|\Z)/i)
16278 { # ignore library version
16279 next;
16280 }
16281 if($Old_Value=~/\A('|"|)[\/\\]\w+([\/\\]|:|('|"|)\Z)/ or $Old_Value=~/[\/\\]\w+[\/\\]\w+/)
16282 { # ignoring path defines:
Andrey Ponomarenko85043792012-05-14 16:48:07 +040016283 # /lib64:/usr/lib64:/lib:/usr/lib:/usr/X11R6/lib/Xaw3d ...
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040016284 next;
16285 }
16286 if($Old_Value=~/\A\(*[a-z_]+(\s+|\|)/i)
16287 { # ignore source defines:
Andrey Ponomarenko85043792012-05-14 16:48:07 +040016288 # static int gcry_pth_init ( void) { return ...
16289 # (RE_BACKSLASH_ESCAPE_IN_LISTS | RE...
16290 next;
16291 }
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040016292 if($Old_Value=~/\(/i and $Old_Value!~/\A[\"\']/i)
Andrey Ponomarenko85043792012-05-14 16:48:07 +040016293 { # ignore source defines:
16294 # foo(p)
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040016295 next;
16296 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040016297 }
16298 if(convert_integer($Old_Value) eq convert_integer($New_Value))
16299 { # 0x0001 and 0x1, 0x1 and 1 equal constants
16300 next;
16301 }
16302 if($Old_Value eq "0" and $New_Value eq "NULL")
16303 { # 0 => NULL
16304 next;
16305 }
16306 if($Old_Value eq "NULL" and $New_Value eq "0")
16307 { # NULL => 0
16308 next;
16309 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040016310 %{$ProblemsWithConstants{$Level}{$Constant}} = (
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040016311 "Target"=>$Constant,
16312 "Old_Value"=>$Old_Value,
16313 "New_Value"=>$New_Value );
16314 }
16315 }
16316}
16317
16318sub convert_integer($)
16319{
16320 my $Value = $_[0];
16321 if($Value=~/\A0x[a-f0-9]+\Z/)
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040016322 { # hexadecimal
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040016323 return hex($Value);
16324 }
16325 elsif($Value=~/\A0[0-7]+\Z/)
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040016326 { # octal
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040016327 return oct($Value);
16328 }
16329 elsif($Value=~/\A0b[0-1]+\Z/)
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040016330 { # binary
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040016331 return oct($Value);
16332 }
16333 else {
16334 return $Value;
16335 }
16336}
16337
Andrey Ponomarenko16934472012-03-29 15:37:04 +040016338sub readSymbols($)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040016339{
16340 my $LibVersion = $_[0];
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040016341 my @LibPaths = getSOPaths($LibVersion);
Andrey Ponomarenko16934472012-03-29 15:37:04 +040016342 if($#LibPaths==-1 and not $CheckHeadersOnly)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040016343 {
16344 if($LibVersion==1)
16345 {
16346 printMsg("WARNING", "checking headers only");
16347 $CheckHeadersOnly = 1;
16348 }
16349 else {
16350 exitStatus("Error", "$SLIB_TYPE libraries are not found in ".$Descriptor{$LibVersion}{"Version"});
16351 }
16352 }
Andrey Ponomarenko16934472012-03-29 15:37:04 +040016353 foreach my $LibPath (sort {length($a)<=>length($b)} @LibPaths) {
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040016354 readSymbols_Lib($LibVersion, $LibPath, 0, "+Weak", 1, 1);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040016355 }
Andrey Ponomarenko16934472012-03-29 15:37:04 +040016356 if(not $CheckHeadersOnly)
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040016357 {
Andrey Ponomarenko16934472012-03-29 15:37:04 +040016358 if($#LibPaths!=-1)
16359 {
16360 if(not keys(%{$Symbol_Library{$LibVersion}}))
16361 {
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040016362 printMsg("WARNING", "the set of public symbols in library(ies) is empty ($LibVersion)");
Andrey Ponomarenko16934472012-03-29 15:37:04 +040016363 printMsg("WARNING", "checking headers only");
16364 $CheckHeadersOnly = 1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040016365 }
16366 }
16367 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +040016368
Andrey Ponomarenko07aea072012-11-12 16:15:07 +040016369 # clean memory
Andrey Ponomarenko85043792012-05-14 16:48:07 +040016370 %SystemObjects = ();
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040016371}
16372
Andrey Ponomarenko16934472012-03-29 15:37:04 +040016373sub getSymbolSize($$)
16374{ # size from the shared library
16375 my ($Symbol, $LibVersion) = @_;
16376 return 0 if(not $Symbol);
16377 if(defined $Symbol_Library{$LibVersion}{$Symbol}
16378 and my $LibName = $Symbol_Library{$LibVersion}{$Symbol})
16379 {
16380 if(defined $Library_Symbol{$LibVersion}{$LibName}{$Symbol}
16381 and my $Size = $Library_Symbol{$LibVersion}{$LibName}{$Symbol})
16382 {
16383 if($Size<0) {
16384 return -$Size;
16385 }
16386 }
16387 }
16388 return 0;
16389}
16390
Andrey Ponomarenko07aea072012-11-12 16:15:07 +040016391sub canonifyName($$)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040016392{ # make TIFFStreamOpen(char const*, std::basic_ostream<char, std::char_traits<char> >*)
16393 # to be TIFFStreamOpen(char const*, std::basic_ostream<char>*)
Andrey Ponomarenko07aea072012-11-12 16:15:07 +040016394 my ($Name, $Type) = @_;
16395
16396 # single
16397 while($Name=~/([^<>,]+),\s*$DEFAULT_STD_PARMS<([^<>,]+)>\s*/ and $1 eq $3)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040016398 {
Andrey Ponomarenko85043792012-05-14 16:48:07 +040016399 my $P = $1;
Andrey Ponomarenko07aea072012-11-12 16:15:07 +040016400 $Name=~s/\Q$P\E,\s*$DEFAULT_STD_PARMS<\Q$P\E>\s*/$P/g;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040016401 }
Andrey Ponomarenko07aea072012-11-12 16:15:07 +040016402
16403 # double
16404 if($Name=~/$DEFAULT_STD_PARMS/)
16405 {
16406 if($Type eq "F")
16407 {
16408 my ($ShortName, $FuncParams) = split_Signature($Name);
16409
16410 foreach my $FParam (separate_Params($FuncParams, 0, 0))
16411 {
16412 if(index($FParam, "<")!=-1)
16413 {
16414 $FParam=~s/>([^<>]+)\Z/>/; # remove quals
16415 my $FParam_N = canonifyName($FParam, "T");
16416 if($FParam_N ne $FParam) {
16417 $Name=~s/\Q$FParam\E/$FParam_N/g;
16418 }
16419 }
16420 }
16421 }
16422 elsif($Type eq "T")
16423 {
16424 my ($ShortTmpl, $TmplParams) = template_Base($Name);
16425
16426 my @TParams = separate_Params($TmplParams, 0, 0);
16427 my $Pos = 0;
16428 while($Pos <= $#TParams-1)
16429 {
16430 my $TParam1 = canonifyName($TParams[$Pos], "T");
16431 my $TParam2 = canonifyName($TParams[$Pos+1], "T");
16432
16433 if($TParam2=~/\A$DEFAULT_STD_PARMS<\Q$TParam1\E >\Z/) {
16434 $Name=~s/\Q$TParam1, $TParam2\E/$TParam1/g;
16435 }
16436
16437 $Pos+=2;
16438 }
16439 }
16440 }
16441
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040016442 return $Name;
16443}
16444
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040016445sub translateSymbols(@)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040016446{
16447 my $LibVersion = pop(@_);
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040016448 my (@MnglNames1, @MnglNames2, @UnmangledNames) = ();
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040016449 foreach my $Symbol (sort @_)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040016450 {
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040016451 if(index($Symbol, "_Z")==0)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040016452 {
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040016453 next if($tr_name{$Symbol});
16454 $Symbol=~s/[\@\$]+(.*)\Z//;
16455 push(@MnglNames1, $Symbol);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040016456 }
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040016457 elsif(index($Symbol, "?")==0) {
16458 push(@MnglNames2, $Symbol);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040016459 }
16460 else
16461 { # not mangled
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040016462 $tr_name{$Symbol} = $Symbol;
16463 $mangled_name_gcc{$Symbol} = $Symbol;
16464 $mangled_name{$LibVersion}{$Symbol} = $Symbol;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040016465 }
16466 }
16467 if($#MnglNames1 > -1)
16468 { # GCC names
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040016469 @UnmangledNames = reverse(unmangleArray(@MnglNames1));
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040016470 foreach my $MnglName (@MnglNames1)
16471 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040016472 if(my $Unmangled = pop(@UnmangledNames))
16473 {
Andrey Ponomarenko07aea072012-11-12 16:15:07 +040016474 $tr_name{$MnglName} = formatName(canonifyName($Unmangled, "F"), "S");
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040016475 if(not $mangled_name_gcc{$tr_name{$MnglName}}) {
16476 $mangled_name_gcc{$tr_name{$MnglName}} = $MnglName;
16477 }
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040016478 if(index($MnglName, "_ZTV")==0
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040016479 and $tr_name{$MnglName}=~/vtable for (.+)/)
16480 { # bind class name and v-table symbol
16481 my $ClassName = $1;
16482 $ClassVTable{$ClassName} = $MnglName;
16483 $VTableClass{$MnglName} = $ClassName;
16484 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040016485 }
16486 }
16487 }
16488 if($#MnglNames2 > -1)
16489 { # MSVC names
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040016490 @UnmangledNames = reverse(unmangleArray(@MnglNames2));
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040016491 foreach my $MnglName (@MnglNames2)
16492 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040016493 if(my $Unmangled = pop(@UnmangledNames))
16494 {
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040016495 $tr_name{$MnglName} = formatName($Unmangled, "S");
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040016496 $mangled_name{$LibVersion}{$tr_name{$MnglName}} = $MnglName;
16497 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040016498 }
16499 }
16500 return \%tr_name;
16501}
16502
16503sub link_symbol($$$)
16504{
16505 my ($Symbol, $RunWith, $Deps) = @_;
16506 if(link_symbol_internal($Symbol, $RunWith, \%Symbol_Library)) {
16507 return 1;
16508 }
16509 if($Deps eq "+Deps")
16510 { # check the dependencies
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040016511 if(link_symbol_internal($Symbol, $RunWith, \%DepSymbol_Library)) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040016512 return 1;
16513 }
16514 }
16515 return 0;
16516}
16517
16518sub link_symbol_internal($$$)
16519{
16520 my ($Symbol, $RunWith, $Where) = @_;
16521 return 0 if(not $Where or not $Symbol);
16522 if($Where->{$RunWith}{$Symbol})
16523 { # the exact match by symbol name
16524 return 1;
16525 }
16526 if(my $VSym = $SymVer{$RunWith}{$Symbol})
16527 { # indirect symbol version, i.e.
16528 # foo_old and its symlink foo@v (or foo@@v)
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040016529 # foo_old may be in symtab table
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040016530 if($Where->{$RunWith}{$VSym}) {
16531 return 1;
16532 }
16533 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040016534 my ($Sym, $Spec, $Ver) = separate_symbol($Symbol);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040016535 if($Sym and $Ver)
16536 { # search for the symbol with the same version
16537 # or without version
16538 if($Where->{$RunWith}{$Sym})
16539 { # old: foo@v|foo@@v
16540 # new: foo
16541 return 1;
16542 }
16543 if($Where->{$RunWith}{$Sym."\@".$Ver})
16544 { # old: foo|foo@@v
16545 # new: foo@v
16546 return 1;
16547 }
16548 if($Where->{$RunWith}{$Sym."\@\@".$Ver})
16549 { # old: foo|foo@v
16550 # new: foo@@v
16551 return 1;
16552 }
16553 }
16554 return 0;
16555}
16556
Andrey Ponomarenko16934472012-03-29 15:37:04 +040016557sub readSymbols_App($)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040016558{
16559 my $Path = $_[0];
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040016560 return () if(not $Path);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040016561 my @Imported = ();
16562 if($OSgroup eq "macos")
16563 {
Andrey Ponomarenko07aea072012-11-12 16:15:07 +040016564 my $NM = get_CmdPath("nm");
16565 if(not $NM) {
16566 exitStatus("Not_Found", "can't find \"nm\"");
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040016567 }
Andrey Ponomarenko07aea072012-11-12 16:15:07 +040016568 open(APP, "$NM -g \"$Path\" 2>\"$TMP_DIR/null\" |");
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040016569 while(<APP>)
16570 {
Andrey Ponomarenko07aea072012-11-12 16:15:07 +040016571 if(/ U _([\w\$]+)\s*\Z/) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040016572 push(@Imported, $1);
16573 }
16574 }
16575 close(APP);
16576 }
16577 elsif($OSgroup eq "windows")
16578 {
16579 my $DumpBinCmd = get_CmdPath("dumpbin");
16580 if(not $DumpBinCmd) {
16581 exitStatus("Not_Found", "can't find \"dumpbin.exe\"");
16582 }
Andrey Ponomarenkoa01311b2012-06-08 17:20:02 +040016583 open(APP, "$DumpBinCmd /IMPORTS \"$Path\" 2>\"$TMP_DIR/null\" |");
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040016584 while(<APP>)
16585 {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040016586 if(/\s*\w+\s+\w+\s+\w+\s+([\w\?\@]+)\s*/) {
16587 push(@Imported, $1);
16588 }
16589 }
16590 close(APP);
16591 }
16592 else
16593 {
16594 my $ReadelfCmd = get_CmdPath("readelf");
16595 if(not $ReadelfCmd) {
16596 exitStatus("Not_Found", "can't find \"readelf\"");
16597 }
Andrey Ponomarenkoa01311b2012-06-08 17:20:02 +040016598 open(APP, "$ReadelfCmd -WhlSsdA \"$Path\" 2>\"$TMP_DIR/null\" |");
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040016599 my $symtab = undef; # indicates that we are processing 'symtab' section of 'readelf' output
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040016600 while(<APP>)
16601 {
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040016602 if(defined $symtab)
16603 { # do nothing with symtab
16604 if(index($_, "'.dynsym'")!=-1)
16605 { # dynamic table
16606 $symtab = undef;
16607 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040016608 }
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040016609 elsif(index($_, "'.symtab'")!=-1)
16610 { # symbol table
16611 $symtab = 1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040016612 }
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040016613 elsif(my @Info = readline_ELF($_))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040016614 {
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040016615 my ($Ndx, $Symbol) = ($Info[5], $Info[6]);
16616 if($Ndx eq "UND")
16617 { # only imported symbols
16618 push(@Imported, $Symbol);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040016619 }
16620 }
16621 }
16622 close(APP);
16623 }
16624 return @Imported;
16625}
16626
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040016627my %ELF_BIND = map {$_=>1} (
16628 "WEAK",
16629 "GLOBAL"
16630);
16631
16632my %ELF_TYPE = map {$_=>1} (
16633 "FUNC",
16634 "IFUNC",
16635 "OBJECT",
16636 "COMMON"
16637);
16638
16639my %ELF_VIS = map {$_=>1} (
16640 "DEFAULT",
16641 "PROTECTED"
16642);
16643
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040016644sub readline_ELF($)
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040016645{ # read the line of 'readelf' output corresponding to the symbol
16646 my @Info = split(/\s+/, $_[0]);
16647 # Num: Value Size Type Bind Vis Ndx Name
16648 # 3629: 000b09c0 32 FUNC GLOBAL DEFAULT 13 _ZNSt12__basic_fileIcED1Ev@@GLIBCXX_3.4
16649 shift(@Info); # spaces
16650 shift(@Info); # num
16651 if($#Info!=6)
16652 { # other lines
16653 return ();
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040016654 }
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040016655 return () if(not defined $ELF_TYPE{$Info[2]});
16656 return () if(not defined $ELF_BIND{$Info[3]});
16657 return () if(not defined $ELF_VIS{$Info[4]});
16658 if($Info[5] eq "ABS" and $Info[0]=~/\A0+\Z/)
16659 { # 1272: 00000000 0 OBJECT GLOBAL DEFAULT ABS CXXABI_1.3
16660 return ();
16661 }
16662 if($OStarget eq "symbian")
16663 { # _ZN12CCTTokenType4NewLE4TUid3RFs@@ctfinder{000a0000}[102020e5].dll
16664 if(index($Info[6], "_._.absent_export_")!=-1)
16665 { # "_._.absent_export_111"@@libstdcpp{00010001}[10282872].dll
16666 return ();
16667 }
16668 $Info[6]=~s/\@.+//g; # remove version
16669 }
16670 if(index($Info[2], "0x") == 0)
16671 { # size == 0x3d158
16672 $Info[2] = hex($Info[2]);
16673 }
16674 return @Info;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040016675}
16676
Andrey Ponomarenko16934472012-03-29 15:37:04 +040016677sub read_symlink($)
16678{
16679 my $Path = $_[0];
Andrey Ponomarenko16934472012-03-29 15:37:04 +040016680 if(my $Res = readlink($Path)) {
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040016681 return $Res;
Andrey Ponomarenko16934472012-03-29 15:37:04 +040016682 }
16683 elsif(my $ReadlinkCmd = get_CmdPath("readlink")) {
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040016684 return `$ReadlinkCmd -n \"$Path\"`;
Andrey Ponomarenko16934472012-03-29 15:37:04 +040016685 }
16686 elsif(my $FileCmd = get_CmdPath("file"))
16687 {
Andrey Ponomarenkoa01311b2012-06-08 17:20:02 +040016688 my $Info = `$FileCmd \"$Path\"`;
Andrey Ponomarenko16934472012-03-29 15:37:04 +040016689 if($Info=~/symbolic\s+link\s+to\s+['`"]*([\w\d\.\-\/\\]+)['`"]*/i) {
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040016690 return $1;
Andrey Ponomarenko16934472012-03-29 15:37:04 +040016691 }
16692 }
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040016693
16694 # can't read
16695 return "";
Andrey Ponomarenko16934472012-03-29 15:37:04 +040016696}
16697
16698sub resolve_symlink($)
16699{
16700 my $Path = $_[0];
16701 return "" if(not $Path);
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040016702
Andrey Ponomarenko16934472012-03-29 15:37:04 +040016703 if(defined $Cache{"resolve_symlink"}{$Path}) {
16704 return $Cache{"resolve_symlink"}{$Path};
16705 }
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040016706 if(not -f $Path and not -l $Path)
16707 { # broken
16708 return ($Cache{"resolve_symlink"}{$Path} = "");
16709 }
16710 return ($Cache{"resolve_symlink"}{$Path} = resolve_symlink_I($Path));
16711}
16712
16713sub resolve_symlink_I($)
16714{
16715 my $Path = $_[0];
Andrey Ponomarenko16934472012-03-29 15:37:04 +040016716 return $Path if(isCyclical(\@RecurSymlink, $Path));
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040016717 my $Res = $Path;
Andrey Ponomarenko16934472012-03-29 15:37:04 +040016718 push(@RecurSymlink, $Path);
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040016719 if(-l $Path and my $Redirect = read_symlink($Path))
Andrey Ponomarenko16934472012-03-29 15:37:04 +040016720 {
16721 if(is_abs($Redirect))
16722 { # absolute path
16723 if($SystemRoot and $SystemRoot ne "/"
16724 and $Path=~/\A\Q$SystemRoot\E\//
16725 and (-f $SystemRoot.$Redirect or -l $SystemRoot.$Redirect))
16726 { # symbolic links from the sysroot
16727 # should be corrected to point to
16728 # the files inside sysroot
16729 $Redirect = $SystemRoot.$Redirect;
16730 }
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040016731 $Res = resolve_symlink($Redirect);
Andrey Ponomarenko16934472012-03-29 15:37:04 +040016732 }
16733 elsif($Redirect=~/\.\.[\/\\]/)
16734 { # relative path
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040016735 $Redirect = joinPath(get_dirname($Path), $Redirect);
Andrey Ponomarenko16934472012-03-29 15:37:04 +040016736 while($Redirect=~s&(/|\\)[^\/\\]+(\/|\\)\.\.(\/|\\)&$1&){};
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040016737 $Res = resolve_symlink($Redirect);
Andrey Ponomarenko16934472012-03-29 15:37:04 +040016738 }
16739 elsif(-f get_dirname($Path)."/".$Redirect)
16740 { # file name in the same directory
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040016741 $Res = resolve_symlink(joinPath(get_dirname($Path), $Redirect));
Andrey Ponomarenko16934472012-03-29 15:37:04 +040016742 }
16743 else
16744 { # broken link
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040016745 $Res = "";
Andrey Ponomarenko16934472012-03-29 15:37:04 +040016746 }
16747 }
16748 pop(@RecurSymlink);
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040016749 return $Res;
Andrey Ponomarenko16934472012-03-29 15:37:04 +040016750}
16751
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040016752sub get_LibPath($$)
Andrey Ponomarenko16934472012-03-29 15:37:04 +040016753{
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040016754 my ($LibVersion, $Name) = @_;
16755 return "" if(not $LibVersion or not $Name);
16756 if(defined $Cache{"get_LibPath"}{$LibVersion}{$Name}) {
16757 return $Cache{"get_LibPath"}{$LibVersion}{$Name};
Andrey Ponomarenko16934472012-03-29 15:37:04 +040016758 }
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040016759 return ($Cache{"get_LibPath"}{$LibVersion}{$Name} = get_LibPath_I($LibVersion, $Name));
16760}
16761
16762sub get_LibPath_I($$)
16763{
16764 my ($LibVersion, $Name) = @_;
16765 if(is_abs($Name))
Andrey Ponomarenko16934472012-03-29 15:37:04 +040016766 {
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040016767 if(-f $Name)
16768 { # absolute path
16769 return $Name;
16770 }
16771 else
16772 { # broken
16773 return "";
16774 }
16775 }
Andrey Ponomarenko07aea072012-11-12 16:15:07 +040016776 if(defined $RegisteredObjects{$LibVersion}{$Name})
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040016777 { # registered paths
Andrey Ponomarenko07aea072012-11-12 16:15:07 +040016778 return $RegisteredObjects{$LibVersion}{$Name};
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040016779 }
Andrey Ponomarenko07aea072012-11-12 16:15:07 +040016780 if(defined $RegisteredSONAMEs{$LibVersion}{$Name})
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040016781 { # registered paths
Andrey Ponomarenko07aea072012-11-12 16:15:07 +040016782 return $RegisteredSONAMEs{$LibVersion}{$Name};
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040016783 }
16784 if(my $DefaultPath = $DyLib_DefaultPath{$Name})
16785 { # ldconfig default paths
16786 return $DefaultPath;
16787 }
16788 foreach my $Dir (sort keys(%DefaultLibPaths), sort keys(%{$SystemPaths{"lib"}}))
16789 { # search in default linker directories
16790 # and then in all system paths
16791 if(-f $Dir."/".$Name) {
16792 return joinPath($Dir,$Name);
16793 }
16794 }
16795 detectSystemObjects() if(not keys(%SystemObjects));
16796 if(my @AllObjects = keys(%{$SystemObjects{$Name}})) {
16797 return $AllObjects[0];
16798 }
16799 if(my $ShortName = parse_libname($Name, "name+ext", $OStarget))
16800 {
16801 if($ShortName ne $Name)
16802 { # FIXME: check this case
16803 if(my $Path = get_LibPath($LibVersion, $ShortName)) {
16804 return $Path;
Andrey Ponomarenko16934472012-03-29 15:37:04 +040016805 }
16806 }
Andrey Ponomarenko16934472012-03-29 15:37:04 +040016807 }
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040016808 # can't find
16809 return "";
Andrey Ponomarenko16934472012-03-29 15:37:04 +040016810}
16811
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040016812sub readSymbols_Lib($$$$$$)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040016813{
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040016814 my ($LibVersion, $Lib_Path, $IsNeededLib, $Weak, $Deps, $Vers) = @_;
16815 return () if(not $LibVersion or not $Lib_Path);
16816 my $Lib_Name = get_filename(resolve_symlink($Lib_Path));
16817 if($IsNeededLib)
16818 {
16819 if($CheckedDyLib{$LibVersion}{$Lib_Name}) {
16820 return ();
16821 }
16822 }
16823 return () if(isCyclical(\@RecurLib, $Lib_Name) or $#RecurLib>=1);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040016824 $CheckedDyLib{$LibVersion}{$Lib_Name} = 1;
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040016825
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040016826 if($CheckImpl)
16827 {
16828 if(not $IsNeededLib) {
16829 getImplementations($LibVersion, $Lib_Path);
16830 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040016831 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040016832
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040016833 push(@RecurLib, $Lib_Name);
16834 my (%Value_Interface, %Interface_Value, %NeededLib) = ();
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040016835 my $Lib_ShortName = parse_libname($Lib_Name, "short", $OStarget);
16836 if($IsNeededLib)
16837 { # change short name to use later for needed libraries
16838 $Lib_ShortName = parse_libname($Lib_Name, "name+ext", $OStarget);
16839 }
16840 else
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040016841 { # libstdc++ and libc are always used by other libs
16842 # if you test one of these libs then you not need
16843 # to find them in the system for reusing
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040016844 if($Lib_ShortName eq "libstdc++")
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040016845 { # libstdc++.so.6
16846 $STDCXX_TESTING = 1;
16847 }
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040016848 elsif($Lib_ShortName eq "libc")
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040016849 { # libc-2.11.3.so
16850 $GLIBC_TESTING = 1;
16851 }
16852 }
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040016853 my $DebugPath = "";
Andrey Ponomarenkoa01311b2012-06-08 17:20:02 +040016854 if($Debug and not $DumpSystem)
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040016855 { # debug mode
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040016856 $DebugPath = $DEBUG_PATH{$LibVersion}."/libs/".get_filename($Lib_Path).".txt";
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040016857 mkpath(get_dirname($DebugPath));
16858 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040016859 if($OStarget eq "macos")
16860 { # Mac OS X: *.dylib, *.a
Andrey Ponomarenko07aea072012-11-12 16:15:07 +040016861 my $NM = get_CmdPath("nm");
16862 if(not $NM)
16863 {
16864 print STDERR "ERROR: can't find \"nm\"\n";
16865 exit(1);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040016866 }
Andrey Ponomarenko07aea072012-11-12 16:15:07 +040016867 $NM .= " -g \"$Lib_Path\" 2>\"$TMP_DIR/null\"";
Andrey Ponomarenkoa01311b2012-06-08 17:20:02 +040016868 if($DebugPath)
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040016869 { # debug mode
Andrey Ponomarenko16934472012-03-29 15:37:04 +040016870 # write to file
Andrey Ponomarenko07aea072012-11-12 16:15:07 +040016871 system($NM." >\"$DebugPath\"");
Andrey Ponomarenko16934472012-03-29 15:37:04 +040016872 open(LIB, $DebugPath);
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040016873 }
Andrey Ponomarenko16934472012-03-29 15:37:04 +040016874 else
16875 { # write to pipe
Andrey Ponomarenko07aea072012-11-12 16:15:07 +040016876 open(LIB, $NM." |");
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040016877 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040016878 while(<LIB>)
16879 {
Andrey Ponomarenko07aea072012-11-12 16:15:07 +040016880 if(/ [STD] _([\w\$]+)\s*\Z/)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040016881 {
16882 my $realname = $1;
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040016883 if($IsNeededLib)
16884 {
Andrey Ponomarenko07aea072012-11-12 16:15:07 +040016885 if(not defined $RegisteredObjects_Short{$Lib_ShortName})
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040016886 {
16887 $DepSymbol_Library{$LibVersion}{$realname} = $Lib_Name;
16888 $DepLibrary_Symbol{$LibVersion}{$Lib_Name}{$realname} = 1;
16889 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040016890 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040016891 else
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040016892 {
16893 $Symbol_Library{$LibVersion}{$realname} = $Lib_Name;
16894 $Library_Symbol{$LibVersion}{$Lib_Name}{$realname} = 1;
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040016895 if($COMMON_LANGUAGE{$LibVersion} ne "C++")
16896 {
16897 if(index($realname, "_Z")==0 or index($realname, "?")==0) {
16898 setLanguage($LibVersion, "C++");
16899 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040016900 }
16901 if($CheckObjectsOnly
16902 and $LibVersion==1) {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040016903 $CheckedSymbols{"Binary"}{$realname} = 1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040016904 }
16905 }
16906 }
16907 }
16908 close(LIB);
Andrey Ponomarenko07aea072012-11-12 16:15:07 +040016909
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040016910 if($Deps)
16911 {
16912 if($LIB_TYPE eq "dynamic")
16913 { # dependencies
Andrey Ponomarenko07aea072012-11-12 16:15:07 +040016914
16915 my $OtoolCmd = get_CmdPath("otool");
16916 if(not $OtoolCmd)
16917 {
16918 print STDERR "ERROR: can't find \"otool\"\n";
16919 exit(1);
16920 }
16921
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040016922 open(LIB, "$OtoolCmd -L \"$Lib_Path\" 2>\"$TMP_DIR/null\" |");
16923 while(<LIB>)
16924 {
16925 if(/\s*([\/\\].+\.$LIB_EXT)\s*/
16926 and $1 ne $Lib_Path) {
16927 $NeededLib{$1} = 1;
16928 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040016929 }
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040016930 close(LIB);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040016931 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040016932 }
16933 }
16934 elsif($OStarget eq "windows")
16935 { # Windows *.dll, *.lib
16936 my $DumpBinCmd = get_CmdPath("dumpbin");
16937 if(not $DumpBinCmd) {
16938 exitStatus("Not_Found", "can't find \"dumpbin\"");
16939 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040016940 $DumpBinCmd .= " /EXPORTS \"".$Lib_Path."\" 2>$TMP_DIR/null";
Andrey Ponomarenkoa01311b2012-06-08 17:20:02 +040016941 if($DebugPath)
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040016942 { # debug mode
Andrey Ponomarenko16934472012-03-29 15:37:04 +040016943 # write to file
Andrey Ponomarenkoa01311b2012-06-08 17:20:02 +040016944 system($DumpBinCmd." >\"$DebugPath\"");
Andrey Ponomarenko16934472012-03-29 15:37:04 +040016945 open(LIB, $DebugPath);
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040016946 }
Andrey Ponomarenko16934472012-03-29 15:37:04 +040016947 else
16948 { # write to pipe
16949 open(LIB, $DumpBinCmd." |");
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040016950 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040016951 while(<LIB>)
16952 { # 1197 4AC 0000A620 SetThreadStackGuarantee
16953 # 1198 4AD SetThreadToken (forwarded to ...)
16954 # 3368 _o2i_ECPublicKey
16955 if(/\A\s*\d+\s+[a-f\d]+\s+[a-f\d]+\s+([\w\?\@]+)\s*\Z/i
16956 or /\A\s*\d+\s+[a-f\d]+\s+([\w\?\@]+)\s*\(\s*forwarded\s+/
16957 or /\A\s*\d+\s+_([\w\?\@]+)\s*\Z/)
16958 { # dynamic, static and forwarded symbols
16959 my $realname = $1;
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040016960 if($IsNeededLib)
16961 {
Andrey Ponomarenko07aea072012-11-12 16:15:07 +040016962 if(not defined $RegisteredObjects_Short{$Lib_ShortName})
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040016963 {
16964 $DepSymbol_Library{$LibVersion}{$realname} = $Lib_Name;
16965 $DepLibrary_Symbol{$LibVersion}{$Lib_Name}{$realname} = 1;
16966 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040016967 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040016968 else
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040016969 {
16970 $Symbol_Library{$LibVersion}{$realname} = $Lib_Name;
16971 $Library_Symbol{$LibVersion}{$Lib_Name}{$realname} = 1;
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040016972 if($COMMON_LANGUAGE{$LibVersion} ne "C++")
16973 {
16974 if(index($realname, "_Z")==0 or index($realname, "?")==0) {
16975 setLanguage($LibVersion, "C++");
16976 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040016977 }
16978 if($CheckObjectsOnly
16979 and $LibVersion==1) {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040016980 $CheckedSymbols{"Binary"}{$realname} = 1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040016981 }
16982 }
16983 }
16984 }
16985 close(LIB);
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040016986 if($Deps)
16987 {
16988 if($LIB_TYPE eq "dynamic")
16989 { # dependencies
16990 open(LIB, "$DumpBinCmd /DEPENDENTS \"$Lib_Path\" 2>\"$TMP_DIR/null\" |");
16991 while(<LIB>)
16992 {
16993 if(/\s*([^\s]+?\.$LIB_EXT)\s*/i
16994 and $1 ne $Lib_Path) {
16995 $NeededLib{path_format($1, $OSgroup)} = 1;
16996 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040016997 }
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040016998 close(LIB);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040016999 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017000 }
17001 }
17002 else
17003 { # Unix; *.so, *.a
17004 # Symbian: *.dso, *.lib
17005 my $ReadelfCmd = get_CmdPath("readelf");
17006 if(not $ReadelfCmd) {
17007 exitStatus("Not_Found", "can't find \"readelf\"");
17008 }
Andrey Ponomarenkoa01311b2012-06-08 17:20:02 +040017009 $ReadelfCmd .= " -WhlSsdA \"$Lib_Path\" 2>\"$TMP_DIR/null\"";
17010 if($DebugPath)
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040017011 { # debug mode
Andrey Ponomarenko16934472012-03-29 15:37:04 +040017012 # write to file
Andrey Ponomarenkoa01311b2012-06-08 17:20:02 +040017013 system($ReadelfCmd." >\"$DebugPath\"");
Andrey Ponomarenko16934472012-03-29 15:37:04 +040017014 open(LIB, $DebugPath);
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040017015 }
Andrey Ponomarenko16934472012-03-29 15:37:04 +040017016 else
17017 { # write to pipe
17018 open(LIB, $ReadelfCmd." |");
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040017019 }
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040017020 my $symtab = undef; # indicates that we are processing 'symtab' section of 'readelf' output
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017021 while(<LIB>)
17022 {
17023 if($LIB_TYPE eq "dynamic")
17024 { # dynamic library specifics
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040017025 if(defined $symtab)
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040017026 {
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040017027 if(index($_, "'.dynsym'")!=-1)
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040017028 { # dynamic table
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040017029 $symtab = undef;
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040017030 }
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040017031 # do nothing with symtab
17032 next;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017033 }
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040017034 elsif(index($_, "'.symtab'")!=-1)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017035 { # symbol table
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040017036 $symtab = 1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017037 next;
17038 }
17039 }
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040017040 if(my ($Value, $Size, $Type, $Bind, $Vis, $Ndx, $Symbol) = readline_ELF($_))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017041 { # read ELF entry
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040017042 if($Ndx eq "UND")
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017043 { # ignore interfaces that are imported from somewhere else
17044 next;
17045 }
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040017046 if($Bind eq "WEAK"
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017047 and $Weak eq "-Weak")
17048 { # skip WEAK symbols
Andrey Ponomarenko07aea072012-11-12 16:15:07 +040017049 $WeakSymbols{$LibVersion}{$Symbol} = 1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017050 next;
17051 }
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040017052 my $Short = $Symbol;
17053 $Short=~s/\@.+//g;
17054 if($Type eq "OBJECT")
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017055 { # global data
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040017056 $GlobalDataObject{$LibVersion}{$Symbol} = 1;
17057 $GlobalDataObject{$LibVersion}{$Short} = 1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017058 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040017059 if($IsNeededLib)
17060 {
Andrey Ponomarenko07aea072012-11-12 16:15:07 +040017061 if(not defined $RegisteredObjects_Short{$Lib_ShortName})
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040017062 {
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040017063 $DepSymbol_Library{$LibVersion}{$Symbol} = $Lib_Name;
17064 $DepLibrary_Symbol{$LibVersion}{$Lib_Name}{$Symbol} = ($Type eq "OBJECT")?-$Size:1;
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040017065 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017066 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040017067 else
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017068 {
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040017069 $Symbol_Library{$LibVersion}{$Symbol} = $Lib_Name;
17070 $Library_Symbol{$LibVersion}{$Lib_Name}{$Symbol} = ($Type eq "OBJECT")?-$Size:1;
17071 if($Vers)
17072 {
17073 if($LIB_EXT eq "so")
17074 { # value
17075 $Interface_Value{$LibVersion}{$Symbol} = $Value;
17076 $Value_Interface{$LibVersion}{$Value}{$Symbol} = 1;
17077 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017078 }
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040017079 if($COMMON_LANGUAGE{$LibVersion} ne "C++")
17080 {
17081 if(index($Symbol, "_Z")==0 or index($Symbol, "?")==0) {
17082 setLanguage($LibVersion, "C++");
17083 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017084 }
17085 if($CheckObjectsOnly
17086 and $LibVersion==1) {
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040017087 $CheckedSymbols{"Binary"}{$Symbol} = 1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017088 }
17089 }
17090 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040017091 elsif($LIB_TYPE eq "dynamic")
17092 { # dynamic library specifics
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040017093 if($Deps)
17094 {
17095 if(/NEEDED.+\[([^\[\]]+)\]/)
17096 { # dependencies:
17097 # 0x00000001 (NEEDED) Shared library: [libc.so.6]
17098 $NeededLib{$1} = 1;
17099 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040017100 }
17101 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017102 }
17103 close(LIB);
17104 }
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040017105 if($Vers)
17106 {
17107 if(not $IsNeededLib and $LIB_EXT eq "so")
17108 { # get symbol versions
17109 foreach my $Symbol (keys(%{$Symbol_Library{$LibVersion}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017110 {
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040017111 next if(index($Symbol,"\@")==-1);
17112 if(my $Value = $Interface_Value{$LibVersion}{$Symbol})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017113 {
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040017114 my $Interface_SymName = "";
17115 foreach my $Symbol_SameValue (keys(%{$Value_Interface{$LibVersion}{$Value}}))
Andrey Ponomarenkoa01311b2012-06-08 17:20:02 +040017116 {
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040017117 if($Symbol_SameValue ne $Symbol
17118 and index($Symbol_SameValue,"\@")==-1)
17119 {
17120 $SymVer{$LibVersion}{$Symbol_SameValue} = $Symbol;
17121 $Interface_SymName = $Symbol_SameValue;
17122 last;
17123 }
Andrey Ponomarenkoa01311b2012-06-08 17:20:02 +040017124 }
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040017125 if(not $Interface_SymName)
17126 {
17127 if($Symbol=~/\A([^\@\$\?]*)[\@\$]+([^\@\$]*)\Z/
17128 and not $SymVer{$LibVersion}{$1}) {
17129 $SymVer{$LibVersion}{$1} = $Symbol;
17130 }
Andrey Ponomarenkoa01311b2012-06-08 17:20:02 +040017131 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017132 }
17133 }
17134 }
17135 }
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040017136 if($Deps)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017137 {
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040017138 foreach my $DyLib (sort keys(%NeededLib))
17139 {
17140 if(my $DepPath = get_LibPath($LibVersion, $DyLib)) {
17141 readSymbols_Lib($LibVersion, $DepPath, 1, "+Weak", $Deps, $Vers);
17142 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017143 }
17144 }
17145 pop(@RecurLib);
17146 return $Library_Symbol{$LibVersion};
17147}
17148
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040017149sub get_prefixes($)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017150{
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017151 my %Prefixes = ();
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040017152 get_prefixes_I([$_[0]], \%Prefixes);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017153 return keys(%Prefixes);
17154}
17155
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040017156sub get_prefixes_I($$)
17157{
17158 foreach my $P (@{$_[0]})
17159 {
17160 my @Parts = reverse(split(/[\/\\]+/, $P));
17161 my $Name = $Parts[0];
17162 foreach (1 .. $#Parts)
17163 {
17164 $_[1]->{$Name}{$P} = 1;
17165 last if($_>4 or $Parts[$_] eq "include");
17166 $Name = $Parts[$_].$SLASH.$Name;
17167 }
17168 }
17169}
17170
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017171sub detectSystemHeaders()
17172{
17173 my @SysHeaders = ();
17174 foreach my $DevelPath (keys(%{$SystemPaths{"include"}}))
17175 {
17176 next if(not -d $DevelPath);
17177 # search for all header files in the /usr/include
17178 # with or without extension (ncurses.h, QtCore, ...)
17179 @SysHeaders = (@SysHeaders, cmd_find($DevelPath,"f","",""));
17180 foreach my $Link (cmd_find($DevelPath,"l","",""))
17181 { # add symbolic links
17182 if(-f $Link) {
17183 push(@SysHeaders, $Link);
17184 }
17185 }
17186 }
17187 foreach my $DevelPath (keys(%{$SystemPaths{"lib"}}))
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040017188 { # search for config headers in the /usr/lib
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017189 next if(not -d $DevelPath);
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040017190 foreach (cmd_find($DevelPath,"f","",""))
17191 {
17192 if(not /\/(gcc|jvm|syslinux|kbd|parrot|xemacs)/)
17193 {
17194 if(/\.h\Z|\/include\//) {
17195 push(@SysHeaders, $_);
17196 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017197 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017198 }
17199 }
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040017200 get_prefixes_I(\@SysHeaders, \%SystemHeaders);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017201}
17202
17203sub detectSystemObjects()
17204{
17205 foreach my $DevelPath (keys(%{$SystemPaths{"lib"}}))
17206 {
17207 next if(not -d $DevelPath);
17208 foreach my $Path (find_libs($DevelPath,"",""))
17209 { # search for shared libraries in the /usr/lib (including symbolic links)
17210 $SystemObjects{parse_libname(get_filename($Path), "name+ext", $OStarget)}{$Path}=1;
17211 }
17212 }
17213}
17214
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040017215sub getSOPaths($)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017216{
17217 my $LibVersion = $_[0];
17218 my @SoPaths = ();
17219 foreach my $Dest (split(/\s*\n\s*/, $Descriptor{$LibVersion}{"Libs"}))
17220 {
17221 if(not -e $Dest) {
17222 exitStatus("Access_Error", "can't access \'$Dest\'");
17223 }
17224 my @SoPaths_Dest = getSOPaths_Dest($Dest, $LibVersion);
17225 foreach (@SoPaths_Dest) {
17226 push(@SoPaths, $_);
17227 }
17228 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040017229 return sort @SoPaths;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017230}
17231
17232sub skip_lib($$)
17233{
17234 my ($Path, $LibVersion) = @_;
17235 return 1 if(not $Path or not $LibVersion);
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040017236 my $Name = get_filename($Path);
17237 if($SkipLibs{$LibVersion}{"Name"}{$Name}) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017238 return 1;
17239 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040017240 my $ShortName = parse_libname($Name, "name+ext", $OStarget);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017241 if($SkipLibs{$LibVersion}{"Name"}{$ShortName}) {
17242 return 1;
17243 }
17244 foreach my $Dir (keys(%{$SkipLibs{$LibVersion}{"Path"}}))
17245 {
17246 if($Path=~/\Q$Dir\E([\/\\]|\Z)/) {
17247 return 1;
17248 }
17249 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040017250 foreach my $P (keys(%{$SkipLibs{$LibVersion}{"Pattern"}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017251 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040017252 if($Name=~/$P/) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017253 return 1;
17254 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040017255 if($P=~/[\/\\]/ and $Path=~/$P/) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017256 return 1;
17257 }
17258 }
17259 return 0;
17260}
17261
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040017262sub skipHeader($$)
17263{
17264 my ($Path, $LibVersion) = @_;
17265 return 1 if(not $Path or not $LibVersion);
17266 if(not keys(%{$SkipHeaders{$LibVersion}})) {
17267 return 0;
17268 }
17269 if(defined $Cache{"skipHeader"}{$Path}) {
17270 return $Cache{"skipHeader"}{$Path};
17271 }
17272 return ($Cache{"skipHeader"}{$Path} = skipHeader_I(@_));
17273}
17274
17275sub skipHeader_I($$)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017276{ # returns:
17277 # 1 - if header should NOT be included and checked
17278 # 2 - if header should NOT be included, but should be checked
17279 my ($Path, $LibVersion) = @_;
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040017280 my $Name = get_filename($Path);
17281 if(my $Kind = $SkipHeaders{$LibVersion}{"Name"}{$Name}) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017282 return $Kind;
17283 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040017284 foreach my $D (keys(%{$SkipHeaders{$LibVersion}{"Path"}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017285 {
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040017286 if(index($Path, $D)!=-1)
17287 {
17288 if($Path=~/\Q$D\E([\/\\]|\Z)/) {
17289 return $SkipHeaders{$LibVersion}{"Path"}{$D};
17290 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017291 }
17292 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040017293 foreach my $P (keys(%{$SkipHeaders{$LibVersion}{"Pattern"}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017294 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040017295 if(my $Kind = $SkipHeaders{$LibVersion}{"Pattern"}{$P})
17296 {
17297 if($Name=~/$P/) {
17298 return $Kind;
17299 }
17300 if($P=~/[\/\\]/ and $Path=~/$P/) {
17301 return $Kind;
17302 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017303 }
17304 }
17305 return 0;
17306}
17307
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040017308sub registerObject_Dir($$)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017309{
17310 my ($Dir, $LibVersion) = @_;
17311 if($SystemPaths{"lib"}{$Dir})
17312 { # system directory
17313 return;
17314 }
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040017315 if($RegisteredObject_Dirs{$LibVersion}{$Dir})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017316 { # already registered
17317 return;
17318 }
17319 foreach my $Path (find_libs($Dir,"",1))
17320 {
17321 next if(ignore_path($Path));
17322 next if(skip_lib($Path, $LibVersion));
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040017323 registerObject($Path, $LibVersion);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017324 }
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040017325 $RegisteredObject_Dirs{$LibVersion}{$Dir} = 1;
17326}
17327
17328sub registerObject($$)
17329{
17330 my ($Path, $LibVersion) = @_;
17331 my $Name = get_filename($Path);
Andrey Ponomarenko07aea072012-11-12 16:15:07 +040017332 $RegisteredObjects{$LibVersion}{$Name} = $Path;
Andrey Ponomarenko27681702012-11-12 16:33:39 +040017333 if($OSgroup=~/linux|bsd/i)
17334 {
17335 if(my $SONAME = getSONAME($Path)) {
17336 $RegisteredSONAMEs{$LibVersion}{$SONAME} = $Path;
17337 }
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040017338 }
17339 if(my $SName = parse_libname($Name, "name", $OStarget)) {
Andrey Ponomarenko07aea072012-11-12 16:15:07 +040017340 $RegisteredObjects_Short{$LibVersion}{$SName} = $Path;
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040017341 }
17342}
17343
17344sub getSONAME($)
17345{
17346 my $Path = $_[0];
17347 return if(not $Path);
17348 if(defined $Cache{"getSONAME"}{$Path}) {
17349 return $Cache{"getSONAME"}{$Path};
17350 }
17351 my $ObjdumpCmd = get_CmdPath("objdump");
17352 if(not $ObjdumpCmd) {
17353 exitStatus("Not_Found", "can't find \"objdump\"");
17354 }
17355 my $SonameCmd = "$ObjdumpCmd -x $Path 2>$TMP_DIR/null";
17356 if($OSgroup eq "windows") {
17357 $SonameCmd .= " | find \"SONAME\"";
17358 }
17359 else {
17360 $SonameCmd .= " | grep SONAME";
17361 }
17362 if(my $SonameInfo = `$SonameCmd`) {
17363 if($SonameInfo=~/SONAME\s+([^\s]+)/) {
17364 return ($Cache{"getSONAME"}{$Path} = $1);
17365 }
17366 }
17367 return ($Cache{"getSONAME"}{$Path}="");
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017368}
17369
17370sub getSOPaths_Dest($$)
17371{
17372 my ($Dest, $LibVersion) = @_;
17373 if(skip_lib($Dest, $LibVersion)) {
17374 return ();
17375 }
17376 if(-f $Dest)
17377 {
17378 if(not parse_libname($Dest, "name", $OStarget)) {
17379 exitStatus("Error", "incorrect format of library (should be *.$LIB_EXT): \'$Dest\'");
17380 }
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040017381 registerObject($Dest, $LibVersion);
17382 registerObject_Dir(get_dirname($Dest), $LibVersion);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017383 return ($Dest);
17384 }
17385 elsif(-d $Dest)
17386 {
17387 $Dest=~s/[\/\\]+\Z//g;
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040017388 my %Libs = ();
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017389 if($SystemPaths{"lib"}{$Dest})
17390 { # you have specified /usr/lib as the search directory (<libs>) in the XML descriptor
17391 # and the real name of the library by -l option (bz2, stdc++, Xaw, ...)
17392 foreach my $Path (cmd_find($Dest,"","*".esc($TargetLibraryName)."*\.$LIB_EXT*",2))
17393 { # all files and symlinks that match the name of a library
17394 if(get_filename($Path)=~/\A(|lib)\Q$TargetLibraryName\E[\d\-]*\.$LIB_EXT[\d\.]*\Z/i)
17395 {
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040017396 registerObject($Path, $LibVersion);
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040017397 $Libs{resolve_symlink($Path)}=1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017398 }
17399 }
17400 }
17401 else
17402 { # search for all files and symlinks
17403 foreach my $Path (find_libs($Dest,"",""))
17404 {
17405 next if(ignore_path($Path));
17406 next if(skip_lib($Path, $LibVersion));
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040017407 registerObject($Path, $LibVersion);
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040017408 $Libs{resolve_symlink($Path)}=1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017409 }
17410 if($OSgroup eq "macos")
17411 { # shared libraries on MacOS X may have no extension
17412 foreach my $Path (cmd_find($Dest,"f","",""))
17413 {
17414 next if(ignore_path($Path));
17415 next if(skip_lib($Path, $LibVersion));
17416 if(get_filename($Path)!~/\./
Andrey Ponomarenko85043792012-05-14 16:48:07 +040017417 and cmd_file($Path)=~/(shared|dynamic)\s+library/i)
17418 {
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040017419 registerObject($Path, $LibVersion);
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040017420 $Libs{resolve_symlink($Path)}=1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017421 }
17422 }
17423 }
17424 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040017425 return keys(%Libs);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017426 }
17427 else {
17428 return ();
17429 }
17430}
17431
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040017432sub isCyclical($$)
17433{
17434 my ($Stack, $Value) = @_;
17435 return (grep {$_ eq $Value} @{$Stack});
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017436}
17437
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017438sub generateTemplate()
17439{
17440 writeFile("VERSION.xml", $DescriptorTemplate."\n");
17441 printMsg("INFO", "XML-descriptor template ./VERSION.xml has been generated");
17442}
17443
17444sub detectWordSize()
17445{
17446 return "" if(not $GCC_PATH);
17447 if($Cache{"detectWordSize"}) {
17448 return $Cache{"detectWordSize"};
17449 }
17450 writeFile("$TMP_DIR/empty.h", "");
Andrey Ponomarenkoa01311b2012-06-08 17:20:02 +040017451 my $Defines = `$GCC_PATH -E -dD \"$TMP_DIR/empty.h\"`;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017452 unlink("$TMP_DIR/empty.h");
17453 my $WSize = 0;
17454 if($Defines=~/ __SIZEOF_POINTER__\s+(\d+)/)
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040017455 { # GCC 4
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017456 $WSize = $1;
17457 }
17458 elsif($Defines=~/ __PTRDIFF_TYPE__\s+(\w+)/)
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040017459 { # GCC 3
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017460 my $PTRDIFF = $1;
17461 if($PTRDIFF=~/long/) {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040017462 $WSize = "8";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017463 }
17464 else {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040017465 $WSize = "4";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017466 }
17467 }
Andrey Ponomarenko01117f12012-06-26 12:23:02 +040017468 if(not $WSize) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017469 exitStatus("Error", "can't check WORD size");
17470 }
17471 return ($Cache{"detectWordSize"} = $WSize);
17472}
17473
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +040017474sub getWordSize($) {
17475 return $WORD_SIZE{$_[0]};
17476}
17477
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017478sub majorVersion($)
17479{
17480 my $V = $_[0];
17481 return 0 if(not $V);
17482 my @VParts = split(/\./, $V);
17483 return $VParts[0];
17484}
17485
17486sub cmpVersions($$)
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040017487{ # compare two versions in dotted-numeric format
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017488 my ($V1, $V2) = @_;
17489 return 0 if($V1 eq $V2);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017490 my @V1Parts = split(/\./, $V1);
17491 my @V2Parts = split(/\./, $V2);
17492 for (my $i = 0; $i <= $#V1Parts && $i <= $#V2Parts; $i++) {
17493 return -1 if(int($V1Parts[$i]) < int($V2Parts[$i]));
17494 return 1 if(int($V1Parts[$i]) > int($V2Parts[$i]));
17495 }
17496 return -1 if($#V1Parts < $#V2Parts);
17497 return 1 if($#V1Parts > $#V2Parts);
17498 return 0;
17499}
17500
17501sub read_ABI_Dump($$)
17502{
17503 my ($LibVersion, $Path) = @_;
17504 return if(not $LibVersion or not -e $Path);
17505 my $FilePath = "";
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040017506 if(isDump_U($Path))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017507 { # input *.abi
17508 $FilePath = $Path;
17509 }
17510 else
17511 { # input *.abi.tar.gz
17512 $FilePath = unpackDump($Path);
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040017513 if(not isDump_U($FilePath)) {
17514 exitStatus("Invalid_Dump", "specified ABI dump \'$Path\' is not valid, try to recreate it");
17515 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017516 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +040017517
Andrey Ponomarenko01117f12012-06-26 12:23:02 +040017518 my $ABI = {};
Andrey Ponomarenko5c09ef32012-06-14 18:17:33 +040017519
Andrey Ponomarenko01117f12012-06-26 12:23:02 +040017520 my $Line = readLineNum($FilePath, 0);
17521 if($Line=~/xml/)
17522 { # XML format
17523 loadModule("XmlDump");
17524 $ABI = readXmlDump($FilePath);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017525 }
Andrey Ponomarenko01117f12012-06-26 12:23:02 +040017526 else
17527 { # Perl Data::Dumper format (default)
17528 open(DUMP, $FilePath);
17529 local $/ = undef;
17530 my $Content = <DUMP>;
17531 close(DUMP);
17532
17533 if(get_dirname($FilePath) eq $TMP_DIR."/unpack")
17534 { # remove temp file
17535 unlink($FilePath);
17536 }
17537 if($Content!~/};\s*\Z/) {
17538 exitStatus("Invalid_Dump", "specified ABI dump \'$Path\' is not valid, try to recreate it");
17539 }
17540 $ABI = eval($Content);
17541 if(not $ABI) {
17542 exitStatus("Error", "internal error - eval() procedure seem to not working correctly, try to remove 'use strict' and try again");
17543 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017544 }
17545 # new dumps (>=1.22) have a personal versioning
Andrey Ponomarenko01117f12012-06-26 12:23:02 +040017546 my $DumpVersion = $ABI->{"ABI_DUMP_VERSION"};
17547 my $ToolVersion = $ABI->{"ABI_COMPLIANCE_CHECKER_VERSION"};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017548 if(not $DumpVersion)
17549 { # old dumps (<=1.21.6) have been marked by the tool version
17550 $DumpVersion = $ToolVersion;
17551 }
17552 $UsedDump{$LibVersion}{"V"} = $DumpVersion;
17553 if(majorVersion($DumpVersion) ne majorVersion($ABI_DUMP_VERSION))
17554 { # should be compatible with dumps of the same major version
17555 if(cmpVersions($DumpVersion, $ABI_DUMP_VERSION)>0)
17556 { # Don't know how to parse future dump formats
Andrey Ponomarenko01117f12012-06-26 12:23:02 +040017557 exitStatus("Dump_Version", "incompatible version \'$DumpVersion\' of specified ABI dump (newer than $ABI_DUMP_VERSION)");
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017558 }
Andrey Ponomarenko01117f12012-06-26 12:23:02 +040017559 elsif(cmpVersions($DumpVersion, $TOOL_VERSION)>0 and not $ABI->{"ABI_DUMP_VERSION"})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017560 { # Don't know how to parse future dump formats
Andrey Ponomarenko01117f12012-06-26 12:23:02 +040017561 exitStatus("Dump_Version", "incompatible version \'$DumpVersion\' of specified ABI dump (newer than $TOOL_VERSION)");
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017562 }
17563 if($UseOldDumps)
17564 {
17565 if(cmpVersions($DumpVersion, $OLDEST_SUPPORTED_VERSION)<0) {
Andrey Ponomarenko01117f12012-06-26 12:23:02 +040017566 exitStatus("Dump_Version", "incompatible version \'$DumpVersion\' of specified ABI dump (older than $OLDEST_SUPPORTED_VERSION)");
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017567 }
17568 }
17569 else
17570 {
Andrey Ponomarenko01117f12012-06-26 12:23:02 +040017571 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 +040017572 if(cmpVersions($DumpVersion, $OLDEST_SUPPORTED_VERSION)>=0) {
17573 $Msg .= "\nUse -old-dumps option to use old-version dumps ($OLDEST_SUPPORTED_VERSION<=V<".majorVersion($ABI_DUMP_VERSION).".0)";
17574 }
17575 exitStatus("Dump_Version", $Msg);
17576 }
17577 }
Andrey Ponomarenko5c09ef32012-06-14 18:17:33 +040017578 if(not checkDump($LibVersion, "2.11"))
17579 { # old ABI dumps
17580 $UsedDump{$LibVersion}{"BinOnly"} = 1;
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040017581 }
Andrey Ponomarenko01117f12012-06-26 12:23:02 +040017582 elsif($ABI->{"BinOnly"})
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040017583 { # ABI dump created with --binary option
17584 $UsedDump{$LibVersion}{"BinOnly"} = 1;
17585 }
Andrey Ponomarenko5c09ef32012-06-14 18:17:33 +040017586 else
17587 { # default
17588 $UsedDump{$LibVersion}{"SrcBin"} = 1;
17589 }
Andrey Ponomarenko01117f12012-06-26 12:23:02 +040017590 if(defined $ABI->{"Mode"}
17591 and $ABI->{"Mode"} eq "Extended")
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017592 { # --ext option
17593 $ExtendedCheck = 1;
17594 }
Andrey Ponomarenko01117f12012-06-26 12:23:02 +040017595 if(my $Lang = $ABI->{"Language"})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017596 {
17597 $UsedDump{$LibVersion}{"L"} = $Lang;
17598 setLanguage($LibVersion, $Lang);
17599 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040017600 if(checkDump($LibVersion, "2.15")) {
Andrey Ponomarenko01117f12012-06-26 12:23:02 +040017601 $TypeInfo{$LibVersion} = $ABI->{"TypeInfo"};
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040017602 }
17603 else
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017604 { # support for old ABI dumps
Andrey Ponomarenko01117f12012-06-26 12:23:02 +040017605 my $TInfo = $ABI->{"TypeInfo"};
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040017606 if(not $TInfo)
17607 { # support for older ABI dumps
Andrey Ponomarenko01117f12012-06-26 12:23:02 +040017608 $TInfo = $ABI->{"TypeDescr"};
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040017609 }
17610 my %Tid_TDid = ();
17611 foreach my $TDid (keys(%{$TInfo}))
17612 {
17613 foreach my $Tid (keys(%{$TInfo->{$TDid}}))
17614 {
17615 $MAX_ID = $Tid if($Tid>$MAX_ID);
17616 $MAX_ID = $TDid if($TDid and $TDid>$MAX_ID);
17617 $Tid_TDid{$Tid}{$TDid}=1;
17618 }
17619 }
17620 my %NewID = ();
17621 foreach my $Tid (keys(%Tid_TDid))
17622 {
17623 my @TDids = keys(%{$Tid_TDid{$Tid}});
17624 if($#TDids>=1)
17625 {
17626 foreach my $TDid (@TDids)
17627 {
17628 if($TDid) {
17629 %{$TypeInfo{$LibVersion}{$Tid}} = %{$TInfo->{$TDid}{$Tid}};
17630 }
17631 else
17632 {
17633 if(my $ID = ++$MAX_ID)
17634 {
17635 $NewID{$TDid}{$Tid} = $ID;
17636 %{$TypeInfo{$LibVersion}{$ID}} = %{$TInfo->{$TDid}{$Tid}};
17637 $TypeInfo{$LibVersion}{$ID}{"Tid"} = $ID;
17638 }
17639 }
17640 }
17641 }
17642 else
17643 {
17644 my $TDid = $TDids[0];
17645 %{$TypeInfo{$LibVersion}{$Tid}} = %{$TInfo->{$TDid}{$Tid}};
17646 }
17647 }
17648 foreach my $Tid (keys(%{$TypeInfo{$LibVersion}}))
17649 {
17650 my %Info = %{$TypeInfo{$LibVersion}{$Tid}};
17651 if(defined $Info{"BaseType"})
17652 {
17653 my $Bid = $Info{"BaseType"}{"Tid"};
17654 my $BDid = $Info{"BaseType"}{"TDid"};
17655 $BDid="" if(not defined $BDid);
17656 if(defined $NewID{$BDid} and my $ID = $NewID{$BDid}{$Bid}) {
17657 $TypeInfo{$LibVersion}{$Tid}{"BaseType"}{"Tid"} = $ID;
17658 }
17659 delete($TypeInfo{$LibVersion}{$Tid}{"BaseType"}{"TDid"});
17660 }
17661 delete($TypeInfo{$LibVersion}{$Tid}{"TDid"});
17662 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017663 }
Andrey Ponomarenko01117f12012-06-26 12:23:02 +040017664 read_Machine_DumpInfo($ABI, $LibVersion);
17665 $SymbolInfo{$LibVersion} = $ABI->{"SymbolInfo"};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017666 if(not $SymbolInfo{$LibVersion})
17667 { # support for old dumps
Andrey Ponomarenko01117f12012-06-26 12:23:02 +040017668 $SymbolInfo{$LibVersion} = $ABI->{"FuncDescr"};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017669 }
17670 if(not keys(%{$SymbolInfo{$LibVersion}}))
17671 { # validation of old-version dumps
17672 if(not $ExtendedCheck) {
17673 exitStatus("Invalid_Dump", "the input dump d$LibVersion is invalid");
17674 }
17675 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040017676 if(checkDump($LibVersion, "2.15")) {
Andrey Ponomarenko01117f12012-06-26 12:23:02 +040017677 $DepLibrary_Symbol{$LibVersion} = $ABI->{"DepSymbols"};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017678 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040017679 else
17680 { # support for old ABI dumps
Andrey Ponomarenko01117f12012-06-26 12:23:02 +040017681 my $DepSymbols = $ABI->{"DepSymbols"};
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040017682 if(not $DepSymbols) {
Andrey Ponomarenko01117f12012-06-26 12:23:02 +040017683 $DepSymbols = $ABI->{"DepInterfaces"};
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040017684 }
17685 if(not $DepSymbols)
17686 { # Cannot reconstruct DepSymbols. This may result in false
17687 # positives if the old dump is for library 2. Not a problem if
17688 # old dumps are only from old libraries.
17689 $DepSymbols = {};
17690 }
17691 foreach my $Symbol (keys(%{$DepSymbols})) {
17692 $DepSymbol_Library{$LibVersion}{$Symbol} = 1;
17693 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017694 }
Andrey Ponomarenko01117f12012-06-26 12:23:02 +040017695 $SymVer{$LibVersion} = $ABI->{"SymbolVersion"};
17696 $Descriptor{$LibVersion}{"Version"} = $ABI->{"LibraryVersion"};
17697 $SkipTypes{$LibVersion} = $ABI->{"SkipTypes"};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017698 if(not $SkipTypes{$LibVersion})
17699 { # support for old dumps
Andrey Ponomarenko01117f12012-06-26 12:23:02 +040017700 $SkipTypes{$LibVersion} = $ABI->{"OpaqueTypes"};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017701 }
Andrey Ponomarenko01117f12012-06-26 12:23:02 +040017702 $SkipSymbols{$LibVersion} = $ABI->{"SkipSymbols"};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017703 if(not $SkipSymbols{$LibVersion})
17704 { # support for old dumps
Andrey Ponomarenko01117f12012-06-26 12:23:02 +040017705 $SkipSymbols{$LibVersion} = $ABI->{"SkipInterfaces"};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017706 }
17707 if(not $SkipSymbols{$LibVersion})
17708 { # support for old dumps
Andrey Ponomarenko01117f12012-06-26 12:23:02 +040017709 $SkipSymbols{$LibVersion} = $ABI->{"InternalInterfaces"};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017710 }
Andrey Ponomarenko01117f12012-06-26 12:23:02 +040017711 $SkipNameSpaces{$LibVersion} = $ABI->{"SkipNameSpaces"};
17712 $TargetHeaders{$LibVersion} = $ABI->{"TargetHeaders"};
17713 foreach my $Path (keys(%{$ABI->{"SkipHeaders"}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017714 {
Andrey Ponomarenko01117f12012-06-26 12:23:02 +040017715 $SkipHeadersList{$LibVersion}{$Path} = $ABI->{"SkipHeaders"}{$Path};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017716 my ($CPath, $Type) = classifyPath($Path);
Andrey Ponomarenko01117f12012-06-26 12:23:02 +040017717 $SkipHeaders{$LibVersion}{$Type}{$CPath} = $ABI->{"SkipHeaders"}{$Path};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017718 }
Andrey Ponomarenko01117f12012-06-26 12:23:02 +040017719 read_Headers_DumpInfo($ABI, $LibVersion);
17720 read_Libs_DumpInfo($ABI, $LibVersion);
Andrey Ponomarenko5c09ef32012-06-14 18:17:33 +040017721 if(not checkDump($LibVersion, "2.10.1")
17722 or not $TargetHeaders{$LibVersion})
Andrey Ponomarenko85043792012-05-14 16:48:07 +040017723 { # support for old ABI dumps: added target headers
17724 foreach (keys(%{$Registered_Headers{$LibVersion}})) {
17725 $TargetHeaders{$LibVersion}{get_filename($_)}=1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017726 }
17727 }
Andrey Ponomarenko01117f12012-06-26 12:23:02 +040017728 $Constants{$LibVersion} = $ABI->{"Constants"};
17729 $NestedNameSpaces{$LibVersion} = $ABI->{"NameSpaces"};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017730 if(not $NestedNameSpaces{$LibVersion})
17731 { # support for old dumps
17732 # Cannot reconstruct NameSpaces. This may affect design
17733 # of the compatibility report.
17734 $NestedNameSpaces{$LibVersion} = {};
17735 }
17736 # target system type
17737 # needed to adopt HTML report
17738 if(not $DumpSystem)
17739 { # to use in createSymbolsList(...)
Andrey Ponomarenko01117f12012-06-26 12:23:02 +040017740 $OStarget = $ABI->{"Target"};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017741 }
17742 # recreate environment
17743 foreach my $Lib_Name (keys(%{$Library_Symbol{$LibVersion}}))
17744 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040017745 foreach my $Symbol (keys(%{$Library_Symbol{$LibVersion}{$Lib_Name}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017746 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040017747 $Symbol_Library{$LibVersion}{$Symbol} = $Lib_Name;
17748 if($Library_Symbol{$LibVersion}{$Lib_Name}{$Symbol}<=-1)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017749 { # data marked as -size in the dump
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040017750 $GlobalDataObject{$LibVersion}{$Symbol}=1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017751 }
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040017752 if($COMMON_LANGUAGE{$LibVersion} ne "C++")
17753 {
17754 if(index($Symbol, "_Z")==0 or index($Symbol, "?")==0) {
17755 setLanguage($LibVersion, "C++");
17756 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017757 }
17758 }
17759 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040017760 foreach my $Lib_Name (keys(%{$DepLibrary_Symbol{$LibVersion}}))
17761 {
17762 foreach my $Symbol (keys(%{$DepLibrary_Symbol{$LibVersion}{$Lib_Name}})) {
17763 $DepSymbol_Library{$LibVersion}{$Symbol} = $Lib_Name;
17764 }
17765 }
17766
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017767 my @VFunc = ();
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040017768 foreach my $InfoId (keys(%{$SymbolInfo{$LibVersion}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017769 {
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +040017770 if(my $MnglName = $SymbolInfo{$LibVersion}{$InfoId}{"MnglName"})
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040017771 {
17772 if(not $Symbol_Library{$LibVersion}{$MnglName}
17773 and not $DepSymbol_Library{$LibVersion}{$MnglName}) {
17774 push(@VFunc, $MnglName);
17775 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017776 }
17777 }
17778 translateSymbols(@VFunc, $LibVersion);
17779 translateSymbols(keys(%{$Symbol_Library{$LibVersion}}), $LibVersion);
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040017780 translateSymbols(keys(%{$DepSymbol_Library{$LibVersion}}), $LibVersion);
17781
17782 foreach my $TypeId (sort {int($a)<=>int($b)} keys(%{$TypeInfo{$LibVersion}}))
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +040017783 { # order is important
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040017784 if(defined $TypeInfo{$LibVersion}{$TypeId}{"BaseClass"})
17785 { # support for old ABI dumps < 2.0 (ACC 1.22)
17786 foreach my $BId (keys(%{$TypeInfo{$LibVersion}{$TypeId}{"BaseClass"}}))
17787 {
17788 if(my $Access = $TypeInfo{$LibVersion}{$TypeId}{"BaseClass"}{$BId})
17789 {
17790 if($Access ne "public") {
17791 $TypeInfo{$LibVersion}{$TypeId}{"Base"}{$BId}{"access"} = $Access;
17792 }
17793 }
17794 $TypeInfo{$LibVersion}{$TypeId}{"Base"}{$BId} = {};
17795 }
17796 delete($TypeInfo{$LibVersion}{$TypeId}{"BaseClass"});
17797 }
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040017798 if(my $Header = $TypeInfo{$LibVersion}{$TypeId}{"Header"})
17799 { # support for old ABI dumps
17800 $TypeInfo{$LibVersion}{$TypeId}{"Header"} = path_format($Header, $OSgroup);
17801 }
Andrey Ponomarenko01117f12012-06-26 12:23:02 +040017802 if(not defined $TypeInfo{$LibVersion}{$TypeId}{"Tid"}) {
17803 $TypeInfo{$LibVersion}{$TypeId}{"Tid"} = $TypeId;
17804 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040017805 my %TInfo = %{$TypeInfo{$LibVersion}{$TypeId}};
17806 if(defined $TInfo{"Base"})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017807 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040017808 foreach (keys(%{$TInfo{"Base"}})) {
17809 $Class_SubClasses{$LibVersion}{$_}{$TypeId}=1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017810 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040017811 }
Andrey Ponomarenko01117f12012-06-26 12:23:02 +040017812 if($TInfo{"Type"} eq "MethodPtr")
17813 {
17814 if(defined $TInfo{"Param"})
17815 { # support for old ABI dumps <= 1.17
17816 if(not defined $TInfo{"Param"}{"0"})
17817 {
17818 my $Max = keys(%{$TInfo{"Param"}});
17819 foreach my $Pos (1 .. $Max) {
17820 $TInfo{"Param"}{$Pos-1} = $TInfo{"Param"}{$Pos};
17821 }
17822 delete($TInfo{"Param"}{$Max});
17823 %{$TypeInfo{$LibVersion}{$TypeId}} = %TInfo;
17824 }
17825 }
17826 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040017827 if($TInfo{"Type"} eq "Typedef" and defined $TInfo{"BaseType"})
17828 {
17829 if(my $BTid = $TInfo{"BaseType"}{"Tid"})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017830 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040017831 my $BName = $TypeInfo{$LibVersion}{$BTid}{"Name"};
17832 if(not $BName)
17833 { # broken type
17834 next;
17835 }
17836 if($TInfo{"Name"} eq $BName)
17837 { # typedef to "class Class"
17838 # should not be registered in TName_Tid
17839 next;
17840 }
17841 if(not $Typedef_BaseName{$LibVersion}{$TInfo{"Name"}}) {
17842 $Typedef_BaseName{$LibVersion}{$TInfo{"Name"}} = $BName;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017843 }
17844 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040017845 }
17846 if(not $TName_Tid{$LibVersion}{$TInfo{"Name"}})
17847 { # classes: class (id1), typedef (artificial, id2 > id1)
17848 $TName_Tid{$LibVersion}{$TInfo{"Name"}} = $TypeId;
17849 }
17850 }
17851
17852 if(not checkDump($LibVersion, "2.15"))
17853 { # support for old ABI dumps
17854 my %Dups = ();
17855 foreach my $InfoId (keys(%{$SymbolInfo{$LibVersion}}))
17856 {
17857 if(my $ClassId = $SymbolInfo{$LibVersion}{$InfoId}{"Class"})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017858 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040017859 if(not defined $TypeInfo{$LibVersion}{$ClassId})
17860 { # remove template decls
17861 delete($SymbolInfo{$LibVersion}{$InfoId});
17862 next;
Andrey Ponomarenko16934472012-03-29 15:37:04 +040017863 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017864 }
Andrey Ponomarenkob8d203d2012-05-25 18:11:07 +040017865 my $MName = $SymbolInfo{$LibVersion}{$InfoId}{"MnglName"};
17866 if(not $MName and $SymbolInfo{$LibVersion}{$InfoId}{"Class"})
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040017867 { # templates
17868 delete($SymbolInfo{$LibVersion}{$InfoId});
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017869 }
17870 }
17871 }
17872
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +040017873 foreach my $InfoId (keys(%{$SymbolInfo{$LibVersion}}))
17874 {
17875 if(not $SymbolInfo{$LibVersion}{$InfoId}{"MnglName"})
17876 { # ABI dumps have no mangled names for C-functions
17877 $SymbolInfo{$LibVersion}{$InfoId}{"MnglName"} = $SymbolInfo{$LibVersion}{$InfoId}{"ShortName"};
17878 }
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040017879 if(my $Header = $SymbolInfo{$LibVersion}{$InfoId}{"Header"})
17880 { # support for old ABI dumps
17881 $SymbolInfo{$LibVersion}{$InfoId}{"Header"} = path_format($Header, $OSgroup);
17882 }
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +040017883 }
17884
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017885 $Descriptor{$LibVersion}{"Dump"} = 1;
17886}
17887
17888sub read_Machine_DumpInfo($$)
17889{
Andrey Ponomarenko01117f12012-06-26 12:23:02 +040017890 my ($ABI, $LibVersion) = @_;
17891 if($ABI->{"Arch"}) {
17892 $CPU_ARCH{$LibVersion} = $ABI->{"Arch"};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017893 }
Andrey Ponomarenko01117f12012-06-26 12:23:02 +040017894 if($ABI->{"WordSize"}) {
17895 $WORD_SIZE{$LibVersion} = $ABI->{"WordSize"};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017896 }
17897 else
17898 { # support for old dumps
Andrey Ponomarenko01117f12012-06-26 12:23:02 +040017899 $WORD_SIZE{$LibVersion} = $ABI->{"SizeOfPointer"};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017900 }
17901 if(not $WORD_SIZE{$LibVersion})
17902 { # support for old dumps (<1.23)
17903 if(my $Tid = getTypeIdByName("char*", $LibVersion))
17904 { # size of char*
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040017905 $WORD_SIZE{$LibVersion} = $TypeInfo{$LibVersion}{$Tid}{"Size"};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017906 }
17907 else
17908 {
17909 my $PSize = 0;
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040017910 foreach my $Tid (keys(%{$TypeInfo{$LibVersion}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017911 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040017912 if($TypeInfo{$LibVersion}{$Tid}{"Type"} eq "Pointer")
17913 { # any "pointer"-type
17914 $PSize = $TypeInfo{$LibVersion}{$Tid}{"Size"};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017915 last;
17916 }
17917 }
17918 if($PSize)
17919 { # a pointer type size
17920 $WORD_SIZE{$LibVersion} = $PSize;
17921 }
17922 else {
17923 printMsg("WARNING", "cannot identify a WORD size in the ABI dump (too old format)");
17924 }
17925 }
17926 }
Andrey Ponomarenko01117f12012-06-26 12:23:02 +040017927 if($ABI->{"GccVersion"}) {
17928 $GCC_VERSION{$LibVersion} = $ABI->{"GccVersion"};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017929 }
17930}
17931
17932sub read_Libs_DumpInfo($$)
17933{
Andrey Ponomarenko01117f12012-06-26 12:23:02 +040017934 my ($ABI, $LibVersion) = @_;
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040017935 $Library_Symbol{$LibVersion} = $ABI->{"Symbols"};
17936 if(not $Library_Symbol{$LibVersion})
17937 { # support for old dumps
17938 $Library_Symbol{$LibVersion} = $ABI->{"Interfaces"};
17939 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017940 if(keys(%{$Library_Symbol{$LibVersion}})
17941 and not $DumpAPI) {
17942 $Descriptor{$LibVersion}{"Libs"} = "OK";
17943 }
17944}
17945
17946sub read_Headers_DumpInfo($$)
17947{
Andrey Ponomarenko01117f12012-06-26 12:23:02 +040017948 my ($ABI, $LibVersion) = @_;
17949 if(keys(%{$ABI->{"Headers"}})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017950 and not $DumpAPI) {
17951 $Descriptor{$LibVersion}{"Headers"} = "OK";
17952 }
Andrey Ponomarenko01117f12012-06-26 12:23:02 +040017953 foreach my $Identity (sort {$ABI->{"Headers"}{$a}<=>$ABI->{"Headers"}{$b}} keys(%{$ABI->{"Headers"}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017954 { # headers info is stored in the old dumps in the different way
17955 if($UseOldDumps
Andrey Ponomarenko01117f12012-06-26 12:23:02 +040017956 and my $Name = $ABI->{"Headers"}{$Identity}{"Name"})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017957 { # support for old dumps: headers info corrected in 1.22
17958 $Identity = $Name;
17959 }
17960 $Registered_Headers{$LibVersion}{$Identity}{"Identity"} = $Identity;
Andrey Ponomarenko01117f12012-06-26 12:23:02 +040017961 $Registered_Headers{$LibVersion}{$Identity}{"Pos"} = $ABI->{"Headers"}{$Identity};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017962 }
17963}
17964
17965sub find_libs($$$)
17966{
17967 my ($Path, $Type, $MaxDepth) = @_;
17968 # FIXME: correct the search pattern
17969 return cmd_find($Path, $Type, ".*\\.$LIB_EXT\[0-9.]*", $MaxDepth);
17970}
17971
17972sub createDescriptor($$)
17973{
17974 my ($LibVersion, $Path) = @_;
17975 if(not $LibVersion or not $Path
17976 or not -e $Path) {
17977 return "";
17978 }
17979 if(-d $Path)
17980 { # directory with headers files and shared objects
17981 return "
17982 <version>
17983 ".$TargetVersion{$LibVersion}."
17984 </version>
17985
17986 <headers>
17987 $Path
17988 </headers>
17989
17990 <libs>
17991 $Path
17992 </libs>";
17993 }
17994 else
17995 { # files
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040017996 if($Path=~/\.(xml|desc)\Z/i)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017997 { # standard XML-descriptor
17998 return readFile($Path);
17999 }
18000 elsif(is_header($Path, 2, $LibVersion))
18001 { # header file
18002 return "
18003 <version>
18004 ".$TargetVersion{$LibVersion}."
18005 </version>
18006
18007 <headers>
18008 $Path
18009 </headers>
18010
18011 <libs>
18012 none
18013 </libs>";
18014 }
18015 elsif(parse_libname($Path, "name", $OStarget))
18016 { # shared object
18017 return "
18018 <version>
18019 ".$TargetVersion{$LibVersion}."
18020 </version>
18021
18022 <headers>
18023 none
18024 </headers>
18025
18026 <libs>
18027 $Path
18028 </libs>";
18029 }
18030 else
18031 { # standard XML-descriptor
18032 return readFile($Path);
18033 }
18034 }
18035}
18036
18037sub detect_lib_default_paths()
18038{
18039 my %LPaths = ();
18040 if($OSgroup eq "bsd")
18041 {
Andrey Ponomarenkoa01311b2012-06-08 17:20:02 +040018042 if(my $LdConfig = get_CmdPath("ldconfig"))
18043 {
18044 foreach my $Line (split(/\n/, `$LdConfig -r 2>\"$TMP_DIR/null\"`))
18045 {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040018046 if($Line=~/\A[ \t]*\d+:\-l(.+) \=\> (.+)\Z/) {
18047 $LPaths{"lib".$1} = $2;
18048 }
18049 }
18050 }
18051 else {
18052 printMsg("WARNING", "can't find ldconfig");
18053 }
18054 }
18055 else
18056 {
18057 if(my $LdConfig = get_CmdPath("ldconfig"))
18058 {
18059 if($SystemRoot and $OSgroup eq "linux")
18060 { # use host (x86) ldconfig with the target (arm) ld.so.conf
18061 if(-e $SystemRoot."/etc/ld.so.conf") {
18062 $LdConfig .= " -f ".$SystemRoot."/etc/ld.so.conf";
18063 }
18064 }
Andrey Ponomarenkoa01311b2012-06-08 17:20:02 +040018065 foreach my $Line (split(/\n/, `$LdConfig -p 2>\"$TMP_DIR/null\"`))
18066 {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040018067 if($Line=~/\A[ \t]*([^ \t]+) .* \=\> (.+)\Z/)
18068 {
18069 my ($Name, $Path) = ($1, $2);
18070 $Path=~s/[\/]{2,}/\//;
18071 $LPaths{$Name} = $Path;
18072 }
18073 }
18074 }
Andrey Ponomarenko82b005f2012-11-12 17:58:14 +040018075 elsif($OSgroup eq "linux") {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040018076 printMsg("WARNING", "can't find ldconfig");
18077 }
18078 }
18079 return \%LPaths;
18080}
18081
18082sub detect_bin_default_paths()
18083{
18084 my $EnvPaths = $ENV{"PATH"};
18085 if($OSgroup eq "beos") {
18086 $EnvPaths.=":".$ENV{"BETOOLS"};
18087 }
18088 my $Sep = ($OSgroup eq "windows")?";":":|;";
18089 foreach my $Path (sort {length($a)<=>length($b)} split(/$Sep/, $EnvPaths))
18090 {
18091 $Path = path_format($Path, $OSgroup);
18092 $Path=~s/[\/\\]+\Z//g;
18093 next if(not $Path);
18094 if($SystemRoot
18095 and $Path=~/\A\Q$SystemRoot\E\//)
18096 { # do NOT use binaries from target system
18097 next;
18098 }
18099 $DefaultBinPaths{$Path} = 1;
18100 }
18101}
18102
18103sub detect_inc_default_paths()
18104{
18105 return () if(not $GCC_PATH);
18106 my %DPaths = ("Cpp"=>{},"Gcc"=>{},"Inc"=>{});
18107 writeFile("$TMP_DIR/empty.h", "");
Andrey Ponomarenkoa01311b2012-06-08 17:20:02 +040018108 foreach my $Line (split(/\n/, `$GCC_PATH -v -x c++ -E \"$TMP_DIR/empty.h\" 2>&1`))
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040018109 { # detecting GCC default include paths
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040018110 if($Line=~/\A[ \t]*((\/|\w+:\\).+)[ \t]*\Z/)
18111 {
18112 my $Path = simplify_path($1);
18113 $Path=~s/[\/\\]+\Z//g;
18114 $Path = path_format($Path, $OSgroup);
18115 if($Path=~/c\+\+|\/g\+\+\//)
18116 {
18117 $DPaths{"Cpp"}{$Path}=1;
18118 if(not defined $MAIN_CPP_DIR
18119 or get_depth($MAIN_CPP_DIR)>get_depth($Path)) {
18120 $MAIN_CPP_DIR = $Path;
18121 }
18122 }
18123 elsif($Path=~/gcc/) {
18124 $DPaths{"Gcc"}{$Path}=1;
18125 }
18126 else
18127 {
18128 next if($Path=~/local[\/\\]+include/);
18129 if($SystemRoot
18130 and $Path!~/\A\Q$SystemRoot\E(\/|\Z)/)
18131 { # The GCC include path for user headers is not a part of the system root
18132 # The reason: you are not specified the --cross-gcc option or selected a wrong compiler
18133 # or it is the internal cross-GCC path like arm-linux-gnueabi/include
18134 next;
18135 }
18136 $DPaths{"Inc"}{$Path}=1;
18137 }
18138 }
18139 }
18140 unlink("$TMP_DIR/empty.h");
18141 return %DPaths;
18142}
18143
18144sub detect_default_paths($)
18145{
18146 my ($HSearch, $LSearch, $BSearch, $GSearch) = (1, 1, 1, 1);
18147 my $Search = $_[0];
18148 if($Search!~/inc/) {
18149 $HSearch = 0;
18150 }
18151 if($Search!~/lib/) {
18152 $LSearch = 0;
18153 }
18154 if($Search!~/bin/) {
18155 $BSearch = 0;
18156 }
18157 if($Search!~/gcc/) {
18158 $GSearch = 0;
18159 }
18160 if(keys(%{$SystemPaths{"include"}}))
18161 { # <search_headers> section of the XML descriptor
18162 # do NOT search for systems headers
18163 $HSearch = 0;
18164 }
18165 if(keys(%{$SystemPaths{"lib"}}))
18166 { # <search_headers> section of the XML descriptor
18167 # do NOT search for systems headers
18168 $LSearch = 0;
18169 }
18170 foreach my $Type (keys(%{$OS_AddPath{$OSgroup}}))
18171 { # additional search paths
18172 next if($Type eq "include" and not $HSearch);
18173 next if($Type eq "lib" and not $LSearch);
18174 next if($Type eq "bin" and not $BSearch);
18175 foreach my $Path (keys(%{$OS_AddPath{$OSgroup}{$Type}}))
18176 {
18177 next if(not -d $Path);
18178 $SystemPaths{$Type}{$Path} = $OS_AddPath{$OSgroup}{$Type}{$Path};
18179 }
18180 }
18181 if($OSgroup ne "windows")
18182 { # unix-like
18183 foreach my $Type ("include", "lib", "bin")
18184 { # automatic detection of system "devel" directories
18185 next if($Type eq "include" and not $HSearch);
18186 next if($Type eq "lib" and not $LSearch);
18187 next if($Type eq "bin" and not $BSearch);
18188 my ($UsrDir, $RootDir) = ("/usr", "/");
18189 if($SystemRoot and $Type ne "bin")
18190 { # 1. search for target headers and libraries
18191 # 2. use host commands: ldconfig, readelf, etc.
18192 ($UsrDir, $RootDir) = ("$SystemRoot/usr", $SystemRoot);
18193 }
18194 foreach my $Path (cmd_find($RootDir,"d","*$Type*",1)) {
18195 $SystemPaths{$Type}{$Path} = 1;
18196 }
18197 if(-d $RootDir."/".$Type)
18198 { # if "/lib" is symbolic link
18199 if($RootDir eq "/") {
18200 $SystemPaths{$Type}{"/".$Type} = 1;
18201 }
18202 else {
18203 $SystemPaths{$Type}{$RootDir."/".$Type} = 1;
18204 }
18205 }
18206 if(-d $UsrDir) {
18207 foreach my $Path (cmd_find($UsrDir,"d","*$Type*",1)) {
18208 $SystemPaths{$Type}{$Path} = 1;
18209 }
18210 if(-d $UsrDir."/".$Type)
18211 { # if "/usr/lib" is symbolic link
18212 $SystemPaths{$Type}{$UsrDir."/".$Type} = 1;
18213 }
18214 }
18215 }
18216 }
18217 if($BSearch)
18218 {
18219 detect_bin_default_paths();
18220 foreach my $Path (keys(%DefaultBinPaths)) {
18221 $SystemPaths{"bin"}{$Path} = $DefaultBinPaths{$Path};
18222 }
18223 }
18224 # check environment variables
18225 if($OSgroup eq "beos")
18226 {
18227 foreach (keys(%{$SystemPaths{"bin"}}))
18228 {
18229 if($_ eq ".") {
18230 next;
18231 }
18232 foreach my $Path (cmd_find($_, "d", "bin", ""))
18233 { # search for /boot/develop/abi/x86/gcc4/tools/gcc-4.4.4-haiku-101111/bin/
18234 $SystemPaths{"bin"}{$Path} = 1;
18235 }
18236 }
18237 if($HSearch)
18238 {
18239 foreach my $Path (split(/:|;/, $ENV{"BEINCLUDES"}))
18240 {
18241 if(is_abs($Path)) {
18242 $DefaultIncPaths{$Path} = 1;
18243 }
18244 }
18245 }
18246 if($LSearch)
18247 {
18248 foreach my $Path (split(/:|;/, $ENV{"BELIBRARIES"}), split(/:|;/, $ENV{"LIBRARY_PATH"}))
18249 {
18250 if(is_abs($Path)) {
18251 $DefaultLibPaths{$Path} = 1;
18252 }
18253 }
18254 }
18255 }
18256 if($LSearch)
18257 { # using linker to get system paths
18258 if(my $LPaths = detect_lib_default_paths())
18259 { # unix-like
18260 foreach my $Name (keys(%{$LPaths}))
18261 {
18262 if($SystemRoot
18263 and $LPaths->{$Name}!~/\A\Q$SystemRoot\E\//)
18264 { # wrong ldconfig configuration
18265 # check your <sysroot>/etc/ld.so.conf
18266 next;
18267 }
18268 $DyLib_DefaultPath{$Name} = $LPaths->{$Name};
18269 $DefaultLibPaths{get_dirname($LPaths->{$Name})} = 1;
18270 }
18271 }
18272 foreach my $Path (keys(%DefaultLibPaths)) {
18273 $SystemPaths{"lib"}{$Path} = $DefaultLibPaths{$Path};
18274 }
18275 }
18276 if($BSearch)
18277 {
18278 if($CrossGcc)
18279 { # --cross-gcc=arm-linux-gcc
18280 if(-e $CrossGcc)
18281 { # absolute or relative path
18282 $GCC_PATH = get_abs_path($CrossGcc);
18283 }
18284 elsif($CrossGcc!~/\// and get_CmdPath($CrossGcc))
18285 { # command name
18286 $GCC_PATH = $CrossGcc;
18287 }
18288 else {
18289 exitStatus("Access_Error", "can't access \'$CrossGcc\'");
18290 }
18291 if($GCC_PATH=~/\s/) {
18292 $GCC_PATH = "\"".$GCC_PATH."\"";
18293 }
18294 }
18295 }
18296 if($GSearch)
18297 { # GCC path and default include dirs
18298 if(not $CrossGcc) {
18299 $GCC_PATH = get_CmdPath("gcc");
18300 }
Andrey Ponomarenko01117f12012-06-26 12:23:02 +040018301 if(not $GCC_PATH)
18302 { # try to find gcc-X.Y
18303 foreach my $Path (sort {$b=~/\/usr\/bin/ cmp $a=~/\/usr\/bin/}
18304 keys(%{$SystemPaths{"bin"}}))
18305 {
18306 if(my @GCCs = cmd_find($Path, "", ".*/gcc-[0-9.]*", 1))
18307 { # select the latest version
18308 @GCCs = sort {$b cmp $a} @GCCs;
18309 if(check_gcc($GCCs[0], "3"))
18310 {
18311 $GCC_PATH = $GCCs[0];
18312 last;
18313 }
18314 }
18315 }
18316 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040018317 if(not $GCC_PATH) {
18318 exitStatus("Not_Found", "can't find GCC>=3.0 in PATH");
18319 }
18320 if(not $CheckObjectsOnly_Opt)
18321 {
18322 if(my $GCC_Ver = get_dumpversion($GCC_PATH))
18323 {
18324 my $GccTarget = get_dumpmachine($GCC_PATH);
18325 printMsg("INFO", "Using GCC $GCC_Ver ($GccTarget)");
18326 if($GccTarget=~/symbian/)
18327 {
18328 $OStarget = "symbian";
18329 $LIB_EXT = $OS_LibExt{$LIB_TYPE}{$OStarget};
18330 }
18331 }
18332 else {
18333 exitStatus("Error", "something is going wrong with the GCC compiler");
18334 }
18335 }
18336 if(not $NoStdInc)
18337 { # do NOT search in GCC standard paths
18338 my %DPaths = detect_inc_default_paths();
18339 %DefaultCppPaths = %{$DPaths{"Cpp"}};
18340 %DefaultGccPaths = %{$DPaths{"Gcc"}};
18341 %DefaultIncPaths = %{$DPaths{"Inc"}};
18342 foreach my $Path (keys(%DefaultIncPaths)) {
18343 $SystemPaths{"include"}{$Path} = $DefaultIncPaths{$Path};
18344 }
18345 }
18346 }
18347 if($HSearch)
18348 { # user include paths
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040018349 my $IncPath = "/usr/include";
18350 if($SystemRoot) {
18351 $IncPath = $SystemRoot.$IncPath;
18352 }
18353 if(-d $IncPath) {
18354 $UserIncPath{$IncPath}=1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040018355 }
18356 }
18357}
18358
18359sub getLIB_EXT($)
18360{
18361 my $Target = $_[0];
18362 if(my $Ext = $OS_LibExt{$LIB_TYPE}{$Target}) {
18363 return $Ext;
18364 }
18365 return $OS_LibExt{$LIB_TYPE}{"default"};
18366}
18367
18368sub getAR_EXT($)
18369{
18370 my $Target = $_[0];
18371 if(my $Ext = $OS_Archive{$Target}) {
18372 return $Ext;
18373 }
18374 return $OS_Archive{"default"};
18375}
18376
18377sub get_dumpversion($)
18378{
18379 my $Cmd = $_[0];
18380 return "" if(not $Cmd);
18381 if($Cache{"get_dumpversion"}{$Cmd}) {
18382 return $Cache{"get_dumpversion"}{$Cmd};
18383 }
Andrey Ponomarenkoa01311b2012-06-08 17:20:02 +040018384 my $V = `$Cmd -dumpversion 2>\"$TMP_DIR/null\"`;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040018385 chomp($V);
18386 return ($Cache{"get_dumpversion"}{$Cmd} = $V);
18387}
18388
18389sub get_dumpmachine($)
18390{
18391 my $Cmd = $_[0];
18392 return "" if(not $Cmd);
18393 if($Cache{"get_dumpmachine"}{$Cmd}) {
18394 return $Cache{"get_dumpmachine"}{$Cmd};
18395 }
Andrey Ponomarenkoa01311b2012-06-08 17:20:02 +040018396 my $Machine = `$Cmd -dumpmachine 2>\"$TMP_DIR/null\"`;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040018397 chomp($Machine);
18398 return ($Cache{"get_dumpmachine"}{$Cmd} = $Machine);
18399}
18400
18401sub check_command($)
18402{
18403 my $Cmd = $_[0];
18404 return "" if(not $Cmd);
18405 my @Options = (
18406 "--version",
18407 "-help"
18408 );
18409 foreach my $Opt (@Options)
18410 {
Andrey Ponomarenkoa01311b2012-06-08 17:20:02 +040018411 my $Info = `$Cmd $Opt 2>\"$TMP_DIR/null\"`;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040018412 if($Info) {
18413 return 1;
18414 }
18415 }
18416 return 0;
18417}
18418
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040018419sub check_gcc($$)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040018420{
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040018421 my ($Cmd, $ReqVer) = @_;
18422 return 0 if(not $Cmd or not $ReqVer);
18423 if(defined $Cache{"check_gcc"}{$Cmd}{$ReqVer}) {
18424 return $Cache{"check_gcc"}{$Cmd}{$ReqVer};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040018425 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040018426 if(my $GccVer = get_dumpversion($Cmd))
18427 {
18428 $GccVer=~s/(-|_)[a-z_]+.*\Z//; # remove suffix (like "-haiku-100818")
18429 if(cmpVersions($GccVer, $ReqVer)>=0) {
18430 return ($Cache{"check_gcc"}{$Cmd}{$ReqVer} = $Cmd);
18431 }
18432 }
18433 return ($Cache{"check_gcc"}{$Cmd}{$ReqVer} = "");
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040018434}
18435
18436sub get_depth($)
18437{
18438 if(defined $Cache{"get_depth"}{$_[0]}) {
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040018439 return $Cache{"get_depth"}{$_[0]};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040018440 }
18441 return ($Cache{"get_depth"}{$_[0]} = ($_[0]=~tr![\/\\]|\:\:!!));
18442}
18443
18444sub find_gcc_cxx_headers($)
18445{
18446 my $LibVersion = $_[0];
18447 return if($Cache{"find_gcc_cxx_headers"});# this function should be called once
18448 # detecting system header paths
18449 foreach my $Path (sort {get_depth($b) <=> get_depth($a)} keys(%DefaultGccPaths))
18450 {
18451 foreach my $HeaderPath (sort {get_depth($a) <=> get_depth($b)} cmd_find($Path,"f","",""))
18452 {
18453 my $FileName = get_filename($HeaderPath);
18454 next if($DefaultGccHeader{$FileName});
18455 $DefaultGccHeader{$FileName} = $HeaderPath;
18456 }
18457 }
18458 if($COMMON_LANGUAGE{$LibVersion} eq "C++" and not $STDCXX_TESTING)
18459 {
18460 foreach my $CppDir (sort {get_depth($b)<=>get_depth($a)} keys(%DefaultCppPaths))
18461 {
18462 my @AllCppHeaders = cmd_find($CppDir,"f","","");
18463 foreach my $Path (sort {get_depth($a)<=>get_depth($b)} @AllCppHeaders)
18464 {
18465 my $FileName = get_filename($Path);
18466 next if($DefaultCppHeader{$FileName});
18467 $DefaultCppHeader{$FileName} = $Path;
18468 }
18469 }
18470 }
18471 $Cache{"find_gcc_cxx_headers"} = 1;
18472}
18473
18474sub parse_libname($$$)
18475{
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040018476 return "" if(not $_[0]);
18477 if(defined $Cache{"parse_libname"}{$_[2]}{$_[1]}{$_[0]}) {
18478 return $Cache{"parse_libname"}{$_[2]}{$_[1]}{$_[0]};
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040018479 }
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040018480 return ($Cache{"parse_libname"}{$_[2]}{$_[1]}{$_[0]} = parse_libname_I(@_));
18481}
18482
18483sub parse_libname_I($$$)
18484{
18485 my ($Name, $Type, $Target) = @_;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040018486 if($Target eq "symbian") {
18487 return parse_libname_symbian($Name, $Type);
18488 }
18489 elsif($Target eq "windows") {
18490 return parse_libname_windows($Name, $Type);
18491 }
18492 my $Ext = getLIB_EXT($Target);
Andrey Ponomarenkoa01311b2012-06-08 17:20:02 +040018493 if($Name=~/((((lib|).+?)([\-\_][\d\-\.\_]+.*?|))\.$Ext)(\.(.+)|)\Z/)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040018494 { # libSDL-1.2.so.0.7.1
18495 # libwbxml2.so.0.0.18
Andrey Ponomarenkoa01311b2012-06-08 17:20:02 +040018496 # libopcodes-2.21.53-system.20110810.so
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040018497 if($Type eq "name")
18498 { # libSDL-1.2
18499 # libwbxml2
18500 return $2;
18501 }
18502 elsif($Type eq "name+ext")
18503 { # libSDL-1.2.so
18504 # libwbxml2.so
18505 return $1;
18506 }
18507 elsif($Type eq "version")
18508 {
Andrey Ponomarenkoa01311b2012-06-08 17:20:02 +040018509 if(defined $7
18510 and $7 ne "")
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040018511 { # 0.7.1
18512 return $7;
18513 }
18514 else
18515 { # libc-2.5.so (=>2.5 version)
18516 my $MV = $5;
18517 $MV=~s/\A[\-\_]+//g;
18518 return $MV;
18519 }
18520 }
18521 elsif($Type eq "short")
18522 { # libSDL
18523 # libwbxml2
18524 return $3;
18525 }
18526 elsif($Type eq "shortest")
18527 { # SDL
18528 # wbxml
18529 return shortest_name($3);
18530 }
18531 }
18532 return "";# error
18533}
18534
18535sub parse_libname_symbian($$)
18536{
18537 my ($Name, $Type) = @_;
18538 my $Ext = getLIB_EXT("symbian");
18539 if($Name=~/(((.+?)(\{.+\}|))\.$Ext)\Z/)
18540 { # libpthread{00010001}.dso
18541 if($Type eq "name")
18542 { # libpthread{00010001}
18543 return $2;
18544 }
18545 elsif($Type eq "name+ext")
18546 { # libpthread{00010001}.dso
18547 return $1;
18548 }
18549 elsif($Type eq "version")
18550 { # 00010001
18551 my $V = $4;
18552 $V=~s/\{(.+)\}/$1/;
18553 return $V;
18554 }
18555 elsif($Type eq "short")
18556 { # libpthread
18557 return $3;
18558 }
18559 elsif($Type eq "shortest")
18560 { # pthread
18561 return shortest_name($3);
18562 }
18563 }
18564 return "";# error
18565}
18566
18567sub parse_libname_windows($$)
18568{
18569 my ($Name, $Type) = @_;
18570 my $Ext = getLIB_EXT("windows");
18571 if($Name=~/((.+?)\.$Ext)\Z/)
18572 { # netapi32.dll
18573 if($Type eq "name")
18574 { # netapi32
18575 return $2;
18576 }
18577 elsif($Type eq "name+ext")
18578 { # netapi32.dll
18579 return $1;
18580 }
18581 elsif($Type eq "version")
18582 { # DLL version embedded
18583 # at binary-level
18584 return "";
18585 }
18586 elsif($Type eq "short")
18587 { # netapi32
18588 return $2;
18589 }
18590 elsif($Type eq "shortest")
18591 { # netapi
18592 return shortest_name($2);
18593 }
18594 }
18595 return "";# error
18596}
18597
18598sub shortest_name($)
18599{
18600 my $Name = $_[0];
18601 # remove prefix
18602 $Name=~s/\A(lib|open)//;
18603 # remove suffix
18604 $Name=~s/[\W\d_]+\Z//i;
18605 $Name=~s/([a-z]{2,})(lib)\Z/$1/i;
18606 return $Name;
18607}
18608
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040018609sub createSymbolsList($$$$$)
18610{
18611 my ($DPath, $SaveTo, $LName, $LVersion, $ArchName) = @_;
18612 read_ABI_Dump(1, $DPath);
18613 if(not $CheckObjectsOnly) {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040018614 prepareSymbols(1);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040018615 }
18616 my %SymbolHeaderLib = ();
18617 my $Total = 0;
18618 # Get List
18619 foreach my $Symbol (sort keys(%{$CompleteSignature{1}}))
18620 {
18621 if(not link_symbol($Symbol, 1, "-Deps"))
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040018622 { # skip src only and all external functions
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040018623 next;
18624 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040018625 if(not symbolFilter($Symbol, 1, "Public", "Binary"))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040018626 { # skip other symbols
18627 next;
18628 }
18629 my $HeaderName = $CompleteSignature{1}{$Symbol}{"Header"};
18630 if(not $HeaderName)
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040018631 { # skip src only and all external functions
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040018632 next;
18633 }
18634 my $DyLib = $Symbol_Library{1}{$Symbol};
18635 if(not $DyLib)
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040018636 { # skip src only and all external functions
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040018637 next;
18638 }
18639 $SymbolHeaderLib{$HeaderName}{$DyLib}{$Symbol} = 1;
18640 $Total+=1;
18641 }
18642 # Draw List
18643 my $SYMBOLS_LIST = "<h1>Public symbols in <span style='color:Blue;'>$LName</span> (<span style='color:Red;'>$LVersion</span>)";
18644 $SYMBOLS_LIST .= " on <span style='color:Blue;'>".showArch($ArchName)."</span><br/>Total: $Total</h1><br/>";
18645 foreach my $HeaderName (sort {lc($a) cmp lc($b)} keys(%SymbolHeaderLib))
18646 {
18647 foreach my $DyLib (sort {lc($a) cmp lc($b)} keys(%{$SymbolHeaderLib{$HeaderName}}))
18648 {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040018649 my %NS_Symbol = ();
18650 foreach my $Symbol (keys(%{$SymbolHeaderLib{$HeaderName}{$DyLib}})) {
18651 $NS_Symbol{get_IntNameSpace($Symbol, 1)}{$Symbol} = 1;
18652 }
18653 foreach my $NameSpace (sort keys(%NS_Symbol))
18654 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040018655 $SYMBOLS_LIST .= getTitle($HeaderName, $DyLib, $NameSpace);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040018656 my @SortedInterfaces = sort {lc(get_Signature($a, 1)) cmp lc(get_Signature($b, 1))} keys(%{$NS_Symbol{$NameSpace}});
18657 foreach my $Symbol (@SortedInterfaces)
18658 {
18659 my $SubReport = "";
18660 my $Signature = get_Signature($Symbol, 1);
18661 if($NameSpace) {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040018662 $Signature=~s/\b\Q$NameSpace\E::\b//g;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040018663 }
18664 if($Symbol=~/\A(_Z|\?)/)
18665 {
18666 if($Signature) {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040018667 $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 +040018668 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040018669 else {
18670 $SubReport = "<span class='iname'>".$Symbol."</span><br/>\n";
18671 }
18672 }
18673 else
18674 {
18675 if($Signature) {
18676 $SubReport = "<span class='iname'>".highLight_Signature_Italic_Color($Signature)."</span><br/>\n";
18677 }
18678 else {
18679 $SubReport = "<span class='iname'>".$Symbol."</span><br/>\n";
18680 }
18681 }
18682 $SYMBOLS_LIST .= $SubReport;
18683 }
18684 }
18685 $SYMBOLS_LIST .= "<br/>\n";
18686 }
18687 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040018688 # clear info
18689 (%TypeInfo, %SymbolInfo, %Library_Symbol, %DepSymbol_Library,
18690 %DepLibrary_Symbol, %SymVer, %SkipTypes, %SkipSymbols,
18691 %NestedNameSpaces, %ClassMethods, %AllocableClass, %ClassNames,
18692 %CompleteSignature, %SkipNameSpaces, %Symbol_Library, %Library_Symbol) = ();
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040018693 ($Content_Counter, $ContentID) = (0, 0);
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040018694 # print report
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040018695 my $CssStyles = readModule("Styles", "SymbolsList.css");
18696 my $JScripts = readModule("Scripts", "Sections.js");
18697 $SYMBOLS_LIST = "<a name='Top'></a>".$SYMBOLS_LIST.$TOP_REF."<br/>\n";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040018698 my $Title = "$LName: public symbols";
18699 my $Keywords = "$LName, API, symbols";
18700 my $Description = "List of symbols in $LName ($LVersion) on ".showArch($ArchName);
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040018701 $SYMBOLS_LIST = composeHTML_Head($Title, $Keywords, $Description, $CssStyles, $JScripts)."
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040018702 <body><div>\n$SYMBOLS_LIST</div>
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040018703 <br/><br/><hr/>\n".getReportFooter($LName, 1)."
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040018704 <div style='height:999px;'></div></body></html>";
18705 writeFile($SaveTo, $SYMBOLS_LIST);
18706}
18707
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040018708sub readModule($$)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040018709{
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040018710 my ($Module, $Name) = @_;
18711 my $Path = $MODULES_DIR."/Internals/$Module/".$Name;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040018712 if(not -f $Path) {
18713 exitStatus("Module_Error", "can't access \'$Path\'");
18714 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040018715 return readFile($Path);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040018716}
18717
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040018718sub add_target_libs($)
18719{
18720 foreach (@{$_[0]}) {
18721 $TargetLibs{$_} = 1;
18722 }
18723}
18724
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040018725sub is_target_lib($)
18726{
18727 my $LName = $_[0];
Andrey Ponomarenkoa01311b2012-06-08 17:20:02 +040018728 if(not $LName) {
18729 return 0;
18730 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040018731 if($TargetLibraryName
18732 and $LName!~/\Q$TargetLibraryName\E/) {
18733 return 0;
18734 }
18735 if(keys(%TargetLibs)
18736 and not $TargetLibs{$LName}
18737 and not $TargetLibs{parse_libname($LName, "name+ext", $OStarget)}) {
18738 return 0;
18739 }
18740 return 1;
18741}
18742
Andrey Ponomarenko85043792012-05-14 16:48:07 +040018743sub is_target_header($$)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040018744{ # --header, --headers-list
Andrey Ponomarenko85043792012-05-14 16:48:07 +040018745 my ($H, $V) = @_;
18746 if(keys(%{$TargetHeaders{$V}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040018747 {
Andrey Ponomarenko85043792012-05-14 16:48:07 +040018748 if($TargetHeaders{$V}{$H}) {
18749 return 1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040018750 }
18751 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +040018752 return 0;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040018753}
18754
18755sub checkVersionNum($$)
18756{
18757 my ($LibVersion, $Path) = @_;
18758 if(my $VerNum = $TargetVersion{$LibVersion}) {
18759 return $VerNum;
18760 }
18761 my $UsedAltDescr = 0;
18762 foreach my $Part (split(/\s*,\s*/, $Path))
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040018763 { # try to get version string from file path
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040018764 next if(isDump($Part)); # ABI dump
18765 next if($Part=~/\.(xml|desc)\Z/i); # XML descriptor
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040018766 my $VerNum = "";
18767 if(parse_libname($Part, "name", $OStarget))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040018768 {
18769 $UsedAltDescr = 1;
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040018770 $VerNum = parse_libname($Part, "version", $OStarget);
18771 if(not $VerNum) {
Andrey Ponomarenko07aea072012-11-12 16:15:07 +040018772 $VerNum = readStrVer($Part);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040018773 }
18774 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040018775 elsif(is_header($Part, 2, $LibVersion) or -d $Part)
18776 {
18777 $UsedAltDescr = 1;
Andrey Ponomarenko07aea072012-11-12 16:15:07 +040018778 $VerNum = readStrVer($Part);
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040018779 }
18780 if($VerNum ne "")
18781 {
18782 $TargetVersion{$LibVersion} = $VerNum;
18783 if($DumpAPI) {
18784 printMsg("WARNING", "setting version number to $VerNum (use -vnum <num> option to change it)");
18785 }
18786 else {
18787 printMsg("WARNING", "setting ".($LibVersion==1?"1st":"2nd")." version number to \"$VerNum\" (use -v$LibVersion <num> option to change it)");
18788 }
18789 return $TargetVersion{$LibVersion};
18790 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040018791 }
18792 if($UsedAltDescr)
18793 {
18794 if($DumpAPI) {
18795 exitStatus("Error", "version number is not set (use -vnum <num> option)");
18796 }
18797 else {
18798 exitStatus("Error", ($LibVersion==1?"1st":"2nd")." version number is not set (use -v$LibVersion <num> option)");
18799 }
18800 }
18801}
18802
Andrey Ponomarenko07aea072012-11-12 16:15:07 +040018803sub readStrVer($)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040018804{
18805 my $Str = $_[0];
18806 return "" if(not $Str);
18807 $Str=~s/\Q$TargetLibraryName\E//g;
18808 if($Str=~/(\/|\\|\w|\A)[\-\_]*(\d+[\d\.\-]+\d+|\d+)/)
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040018809 { # .../libssh-0.4.0/...
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040018810 return $2;
18811 }
18812 elsif(my $V = parse_libname($Str, "version", $OStarget)) {
18813 return $V;
18814 }
18815 return "";
18816}
18817
18818sub readLibs($)
18819{
18820 my $LibVersion = $_[0];
18821 if($OStarget eq "windows")
18822 { # dumpbin.exe will crash
18823 # without VS Environment
18824 check_win32_env();
18825 }
Andrey Ponomarenko16934472012-03-29 15:37:04 +040018826 readSymbols($LibVersion);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040018827 translateSymbols(keys(%{$Symbol_Library{$LibVersion}}), $LibVersion);
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040018828 translateSymbols(keys(%{$DepSymbol_Library{$LibVersion}}), $LibVersion);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040018829}
18830
18831sub dump_sorting($)
18832{
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +040018833 my $Hash = $_[0];
18834 return [] if(not $Hash);
18835 my @Keys = keys(%{$Hash});
18836 return [] if($#Keys<0);
18837 if($Keys[0]=~/\A\d+\Z/)
18838 { # numbers
18839 return [sort {int($a)<=>int($b)} @Keys];
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040018840 }
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +040018841 else
18842 { # strings
18843 return [sort {$a cmp $b} @Keys];
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040018844 }
18845}
18846
18847sub printMsg($$)
18848{
18849 my ($Type, $Msg) = @_;
18850 if($Type!~/\AINFO/) {
18851 $Msg = $Type.": ".$Msg;
18852 }
18853 if($Type!~/_C\Z/) {
18854 $Msg .= "\n";
18855 }
18856 if($Quiet)
18857 { # --quiet option
18858 appendFile($COMMON_LOG_PATH, $Msg);
18859 }
18860 else
18861 {
18862 if($Type eq "ERROR") {
18863 print STDERR $Msg;
18864 }
18865 else {
18866 print $Msg;
18867 }
18868 }
18869}
18870
18871sub exitStatus($$)
18872{
18873 my ($Code, $Msg) = @_;
18874 printMsg("ERROR", $Msg);
18875 exit($ERROR_CODE{$Code});
18876}
18877
18878sub exitReport()
18879{ # the tool has run without any errors
18880 printReport();
18881 if($COMPILE_ERRORS)
18882 { # errors in headers may add false positives/negatives
18883 exit($ERROR_CODE{"Compile_Error"});
18884 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040018885 if($BinaryOnly and $RESULT{"Binary"}{"Problems"})
18886 { # --binary
18887 exit($ERROR_CODE{"Incompatible"});
18888 }
18889 elsif($SourceOnly and $RESULT{"Source"}{"Problems"})
18890 { # --source
18891 exit($ERROR_CODE{"Incompatible"});
18892 }
18893 elsif($RESULT{"Source"}{"Problems"}
18894 or $RESULT{"Binary"}{"Problems"})
18895 { # default
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040018896 exit($ERROR_CODE{"Incompatible"});
18897 }
18898 else {
18899 exit($ERROR_CODE{"Compatible"});
18900 }
18901}
18902
18903sub readRules($)
18904{
18905 my $Kind = $_[0];
18906 if(not -f $RULES_PATH{$Kind}) {
18907 exitStatus("Module_Error", "can't access \'".$RULES_PATH{$Kind}."\'");
18908 }
18909 my $Content = readFile($RULES_PATH{$Kind});
18910 while(my $Rule = parseTag(\$Content, "rule"))
18911 {
18912 my $RId = parseTag(\$Rule, "id");
18913 my @Properties = ("Severity", "Change", "Effect", "Overcome", "Kind");
18914 foreach my $Prop (@Properties) {
18915 if(my $Value = parseTag(\$Rule, lc($Prop)))
18916 {
18917 $Value=~s/\n[ ]*//;
18918 $CompatRules{$Kind}{$RId}{$Prop} = $Value;
18919 }
18920 }
18921 if($CompatRules{$Kind}{$RId}{"Kind"}=~/\A(Symbols|Parameters)\Z/) {
18922 $CompatRules{$Kind}{$RId}{"Kind"} = "Symbols";
18923 }
18924 else {
18925 $CompatRules{$Kind}{$RId}{"Kind"} = "Types";
18926 }
18927 }
18928}
18929
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040018930sub getReportPath($)
18931{
18932 my $Level = $_[0];
18933 my $Dir = "compat_reports/$TargetLibraryName/".$Descriptor{1}{"Version"}."_to_".$Descriptor{2}{"Version"};
18934 if($Level eq "Binary")
18935 {
18936 if($BinaryReportPath)
18937 { # --bin-report-path
18938 return $BinaryReportPath;
18939 }
18940 elsif($OutputReportPath)
18941 { # --report-path
18942 return $OutputReportPath;
18943 }
18944 else
18945 { # default
18946 return $Dir."/abi_compat_report.$ReportFormat";
18947 }
18948 }
18949 elsif($Level eq "Source")
18950 {
18951 if($SourceReportPath)
18952 { # --src-report-path
18953 return $SourceReportPath;
18954 }
18955 elsif($OutputReportPath)
18956 { # --report-path
18957 return $OutputReportPath;
18958 }
18959 else
18960 { # default
18961 return $Dir."/src_compat_report.$ReportFormat";
18962 }
18963 }
18964 else
18965 {
18966 if($OutputReportPath)
18967 { # --report-path
18968 return $OutputReportPath;
18969 }
18970 else
18971 { # default
18972 return $Dir."/compat_report.$ReportFormat";
18973 }
18974 }
18975}
18976
18977sub printStatMsg($)
18978{
18979 my $Level = $_[0];
18980 printMsg("INFO", "total \"$Level\" compatibility problems: ".$RESULT{$Level}{"Problems"}.", warnings: ".$RESULT{$Level}{"Warnings"});
18981}
18982
18983sub listAffected($)
18984{
18985 my $Level = $_[0];
18986 my $List = "";
18987 foreach (keys(%{$TotalAffected{$Level}}))
18988 {
18989 if($StrictCompat and $TotalAffected{$Level}{$_} eq "Low")
18990 { # skip "Low"-severity problems
18991 next;
18992 }
18993 $List .= "$_\n";
18994 }
18995 my $Dir = get_dirname(getReportPath($Level));
18996 if($Level eq "Binary") {
18997 writeFile($Dir."/abi_affected.txt", $List);
18998 }
18999 elsif($Level eq "Source") {
19000 writeFile($Dir."/src_affected.txt", $List);
19001 }
19002}
19003
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040019004sub printReport()
19005{
19006 printMsg("INFO", "creating compatibility report ...");
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040019007 createReport();
19008 if($JoinReport or $DoubleReport)
19009 {
19010 if($RESULT{"Binary"}{"Problems"}
19011 or $RESULT{"Source"}{"Problems"}) {
19012 printMsg("INFO", "result: INCOMPATIBLE (Binary: ".$RESULT{"Binary"}{"Affected"}."\%, Source: ".$RESULT{"Source"}{"Affected"}."\%)");
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040019013 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040019014 else {
19015 printMsg("INFO", "result: COMPATIBLE");
19016 }
19017 printStatMsg("Binary");
19018 printStatMsg("Source");
19019 if($ListAffected)
19020 { # --list-affected
19021 listAffected("Binary");
19022 listAffected("Source");
19023 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040019024 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040019025 elsif($BinaryOnly)
19026 {
19027 if($RESULT{"Binary"}{"Problems"}) {
19028 printMsg("INFO", "result: INCOMPATIBLE (".$RESULT{"Binary"}{"Affected"}."\%)");
19029 }
19030 else {
19031 printMsg("INFO", "result: COMPATIBLE");
19032 }
19033 printStatMsg("Binary");
19034 if($ListAffected)
19035 { # --list-affected
19036 listAffected("Binary");
19037 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040019038 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040019039 elsif($SourceOnly)
19040 {
19041 if($RESULT{"Source"}{"Problems"}) {
19042 printMsg("INFO", "result: INCOMPATIBLE (".$RESULT{"Source"}{"Affected"}."\%)");
19043 }
19044 else {
19045 printMsg("INFO", "result: COMPATIBLE");
19046 }
19047 printStatMsg("Source");
19048 if($ListAffected)
19049 { # --list-affected
19050 listAffected("Source");
19051 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040019052 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040019053 if($StdOut)
19054 {
19055 if($JoinReport or not $DoubleReport)
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040019056 { # --binary or --source
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040019057 printMsg("INFO", "compatibility report has been generated to stdout");
19058 }
19059 else
19060 { # default
19061 printMsg("INFO", "compatibility reports have been generated to stdout");
19062 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040019063 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040019064 else
19065 {
19066 if($JoinReport)
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040019067 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040019068 printMsg("INFO", "see detailed report:\n ".getReportPath("Join"));
19069 }
19070 elsif($DoubleReport)
19071 { # default
19072 printMsg("INFO", "see detailed reports:\n ".getReportPath("Binary")."\n ".getReportPath("Source"));
19073 }
19074 elsif($BinaryOnly)
19075 { # --binary
19076 printMsg("INFO", "see detailed report:\n ".getReportPath("Binary"));
19077 }
19078 elsif($SourceOnly)
19079 { # --source
19080 printMsg("INFO", "see detailed report:\n ".getReportPath("Source"));
19081 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040019082 }
19083}
19084
19085sub check_win32_env()
19086{
19087 if(not $ENV{"DevEnvDir"}
19088 or not $ENV{"LIB"}) {
19089 exitStatus("Error", "can't start without VS environment (vsvars32.bat)");
19090 }
19091}
19092
Andrey Ponomarenko5c09ef32012-06-14 18:17:33 +040019093sub diffSets($$)
19094{
19095 my ($S1, $S2) = @_;
19096 my @SK1 = keys(%{$S1});
19097 my @SK2 = keys(%{$S2});
19098 if($#SK1!=$#SK2) {
19099 return 1;
19100 }
19101 foreach my $K1 (@SK1)
19102 {
19103 if(not defined $S2->{$K1}) {
19104 return 1;
19105 }
19106 }
19107 return 0;
19108}
19109
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040019110sub create_ABI_Dump()
19111{
19112 if(not -e $DumpAPI) {
19113 exitStatus("Access_Error", "can't access \'$DumpAPI\'");
19114 }
19115 # check the archive utilities
19116 if($OSgroup eq "windows")
19117 { # using zip
19118 my $ZipCmd = get_CmdPath("zip");
19119 if(not $ZipCmd) {
19120 exitStatus("Not_Found", "can't find \"zip\"");
19121 }
19122 }
19123 else
19124 { # using tar and gzip
19125 my $TarCmd = get_CmdPath("tar");
19126 if(not $TarCmd) {
19127 exitStatus("Not_Found", "can't find \"tar\"");
19128 }
19129 my $GzipCmd = get_CmdPath("gzip");
19130 if(not $GzipCmd) {
19131 exitStatus("Not_Found", "can't find \"gzip\"");
19132 }
19133 }
19134 my @DParts = split(/\s*,\s*/, $DumpAPI);
19135 foreach my $Part (@DParts)
19136 {
19137 if(not -e $Part) {
19138 exitStatus("Access_Error", "can't access \'$Part\'");
19139 }
19140 }
19141 checkVersionNum(1, $DumpAPI);
19142 foreach my $Part (@DParts)
19143 {
19144 if(isDump($Part)) {
19145 read_ABI_Dump(1, $Part);
19146 }
19147 else {
19148 readDescriptor(1, createDescriptor(1, $Part));
19149 }
19150 }
19151 initLogging(1);
19152 detect_default_paths("inc|lib|bin|gcc"); # complete analysis
Andrey Ponomarenko01117f12012-06-26 12:23:02 +040019153 if(not $Descriptor{1}{"Dump"})
19154 {
19155 if(not $CheckHeadersOnly) {
19156 readLibs(1);
19157 }
19158 if($CheckHeadersOnly) {
19159 setLanguage(1, "C++");
19160 }
19161 if(not $CheckObjectsOnly) {
19162 searchForHeaders(1);
19163 }
19164 $WORD_SIZE{1} = detectWordSize();
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040019165 }
Andrey Ponomarenko01117f12012-06-26 12:23:02 +040019166 if(not $Descriptor{1}{"Dump"})
19167 {
19168 if($Descriptor{1}{"Headers"}) {
19169 readHeaders(1);
19170 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040019171 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +040019172 cleanDump(1);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040019173 if(not keys(%{$SymbolInfo{1}}))
19174 { # check if created dump is valid
19175 if(not $ExtendedCheck and not $CheckObjectsOnly)
19176 {
19177 if($CheckHeadersOnly) {
19178 exitStatus("Empty_Set", "the set of public symbols is empty");
19179 }
19180 else {
19181 exitStatus("Empty_Intersection", "the sets of public symbols in headers and libraries have empty intersection");
19182 }
19183 }
19184 }
19185 my %HeadersInfo = ();
19186 foreach my $HPath (keys(%{$Registered_Headers{1}}))
19187 { # headers info stored without paths in the dump
19188 $HeadersInfo{$Registered_Headers{1}{$HPath}{"Identity"}} = $Registered_Headers{1}{$HPath}{"Pos"};
19189 }
19190 printMsg("INFO", "creating library ABI dump ...");
Andrey Ponomarenko01117f12012-06-26 12:23:02 +040019191 my %ABI = (
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040019192 "TypeInfo" => $TypeInfo{1},
19193 "SymbolInfo" => $SymbolInfo{1},
19194 "Symbols" => $Library_Symbol{1},
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040019195 "DepSymbols" => $DepLibrary_Symbol{1},
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040019196 "SymbolVersion" => $SymVer{1},
19197 "LibraryVersion" => $Descriptor{1}{"Version"},
19198 "LibraryName" => $TargetLibraryName,
19199 "Language" => $COMMON_LANGUAGE{1},
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040019200 "SkipTypes" => $SkipTypes{1},
19201 "SkipSymbols" => $SkipSymbols{1},
19202 "SkipNameSpaces" => $SkipNameSpaces{1},
19203 "SkipHeaders" => $SkipHeadersList{1},
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040019204 "Headers" => \%HeadersInfo,
19205 "Constants" => $Constants{1},
19206 "NameSpaces" => $NestedNameSpaces{1},
19207 "Target" => $OStarget,
19208 "Arch" => getArch(1),
19209 "WordSize" => $WORD_SIZE{1},
19210 "GccVersion" => get_dumpversion($GCC_PATH),
19211 "ABI_DUMP_VERSION" => $ABI_DUMP_VERSION,
19212 "ABI_COMPLIANCE_CHECKER_VERSION" => $TOOL_VERSION
19213 );
Andrey Ponomarenko5c09ef32012-06-14 18:17:33 +040019214 if(diffSets($TargetHeaders{1}, \%HeadersInfo)) {
Andrey Ponomarenko01117f12012-06-26 12:23:02 +040019215 $ABI{"TargetHeaders"} = $TargetHeaders{1};
Andrey Ponomarenko5c09ef32012-06-14 18:17:33 +040019216 }
19217 if($UseXML) {
Andrey Ponomarenko01117f12012-06-26 12:23:02 +040019218 $ABI{"XML_ABI_DUMP_VERSION"} = $XML_ABI_DUMP_VERSION;
Andrey Ponomarenko5c09ef32012-06-14 18:17:33 +040019219 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040019220 if($ExtendedCheck)
19221 { # --ext option
Andrey Ponomarenko01117f12012-06-26 12:23:02 +040019222 $ABI{"Mode"} = "Extended";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040019223 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040019224 if($BinaryOnly)
19225 { # --binary
Andrey Ponomarenko01117f12012-06-26 12:23:02 +040019226 $ABI{"BinOnly"} = 1;
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040019227 }
Andrey Ponomarenko5c09ef32012-06-14 18:17:33 +040019228
19229 my $ABI_DUMP = "";
19230 if($UseXML)
19231 {
19232 loadModule("XmlDump");
Andrey Ponomarenko01117f12012-06-26 12:23:02 +040019233 $ABI_DUMP = createXmlDump(\%ABI);
Andrey Ponomarenko5c09ef32012-06-14 18:17:33 +040019234 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040019235 else
19236 { # default
Andrey Ponomarenko01117f12012-06-26 12:23:02 +040019237 $ABI_DUMP = Dumper(\%ABI);
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040019238 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040019239 if($StdOut)
19240 { # --stdout option
Andrey Ponomarenko5c09ef32012-06-14 18:17:33 +040019241 print STDOUT $ABI_DUMP;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040019242 printMsg("INFO", "ABI dump has been generated to stdout");
19243 return;
19244 }
19245 else
19246 { # write to gzipped file
Andrey Ponomarenko5c09ef32012-06-14 18:17:33 +040019247 my $DumpPath = "abi_dumps/$TargetLibraryName/".$TargetLibraryName."_".$Descriptor{1}{"Version"}.".abi";
19248 $DumpPath .= ".".$AR_EXT; # gzipped by default
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040019249 if($OutputDumpPath)
19250 { # user defined path
19251 $DumpPath = $OutputDumpPath;
19252 }
Andrey Ponomarenko5c09ef32012-06-14 18:17:33 +040019253 my $Archive = ($DumpPath=~s/\Q.$AR_EXT\E\Z//g);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040019254 my ($DDir, $DName) = separate_path($DumpPath);
19255 my $DPath = $TMP_DIR."/".$DName;
Andrey Ponomarenko5c09ef32012-06-14 18:17:33 +040019256 if(not $Archive) {
19257 $DPath = $DumpPath;
19258 }
19259
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040019260 mkpath($DDir);
Andrey Ponomarenko85043792012-05-14 16:48:07 +040019261
19262 open(DUMP, ">", $DPath) || die ("can't open file \'$DPath\': $!\n");
Andrey Ponomarenko5c09ef32012-06-14 18:17:33 +040019263 print DUMP $ABI_DUMP;
Andrey Ponomarenko85043792012-05-14 16:48:07 +040019264 close(DUMP);
19265
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040019266 if(not -s $DPath) {
19267 exitStatus("Error", "can't create ABI dump because something is going wrong with the Data::Dumper module");
19268 }
Andrey Ponomarenko07aea072012-11-12 16:15:07 +040019269 if($Archive) {
19270 $DumpPath = createArchive($DPath, $DDir);
Andrey Ponomarenko5c09ef32012-06-14 18:17:33 +040019271 }
19272
Andrey Ponomarenko07aea072012-11-12 16:15:07 +040019273 if(not $OutputDumpPath)
19274 {
19275 printMsg("INFO", "library ABI has been dumped to:\n $DumpPath");
19276 printMsg("INFO", "you can transfer this dump everywhere and use instead of the ".$Descriptor{1}{"Version"}." version descriptor");
19277 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040019278 }
19279}
19280
19281sub quickEmptyReports()
19282{ # Quick "empty" reports
19283 # 4 times faster than merging equal dumps
19284 # NOTE: the dump contains the "LibraryVersion" attribute
19285 # if you change the version, then your dump will be different
19286 # OVERCOME: use -v1 and v2 options for comparing dumps
19287 # and don't change version in the XML descriptor (and dumps)
19288 # OVERCOME 2: separate meta info from the dumps in ACC 2.0
19289 if(-s $Descriptor{1}{"Path"} == -s $Descriptor{2}{"Path"})
19290 {
19291 my $FilePath1 = unpackDump($Descriptor{1}{"Path"});
19292 my $FilePath2 = unpackDump($Descriptor{2}{"Path"});
19293 if($FilePath1 and $FilePath2)
19294 {
Andrey Ponomarenko01117f12012-06-26 12:23:02 +040019295 my $Line = readLineNum($FilePath1, 0);
19296 if($Line=~/xml/)
19297 { # XML format
19298 # is not supported yet
19299 return;
19300 }
19301
Andrey Ponomarenko85043792012-05-14 16:48:07 +040019302 local $/ = undef;
19303
19304 open(DUMP1, $FilePath1);
19305 my $Content1 = <DUMP1>;
19306 close(DUMP1);
19307
19308 open(DUMP2, $FilePath2);
19309 my $Content2 = <DUMP2>;
19310 close(DUMP2);
19311
19312 if($Content1 eq $Content2)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040019313 {
Andrey Ponomarenko85043792012-05-14 16:48:07 +040019314 # clean memory
19315 undef $Content2;
19316
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040019317 # read a number of headers, libs, symbols and types
Andrey Ponomarenko85043792012-05-14 16:48:07 +040019318 my $ABIdump = eval($Content1);
19319
19320 # clean memory
19321 undef $Content1;
19322
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040019323 if(not $ABIdump) {
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040019324 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 +040019325 }
19326 if(not $ABIdump->{"TypeInfo"})
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040019327 { # support for old dumps
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040019328 $ABIdump->{"TypeInfo"} = $ABIdump->{"TypeDescr"};
19329 }
19330 if(not $ABIdump->{"SymbolInfo"})
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040019331 { # support for old dumps
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040019332 $ABIdump->{"SymbolInfo"} = $ABIdump->{"FuncDescr"};
19333 }
19334 read_Headers_DumpInfo($ABIdump, 1);
19335 read_Libs_DumpInfo($ABIdump, 1);
19336 read_Machine_DumpInfo($ABIdump, 1);
19337 read_Machine_DumpInfo($ABIdump, 2);
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040019338
19339 %{$CheckedTypes{"Binary"}} = %{$ABIdump->{"TypeInfo"}};
19340 %{$CheckedTypes{"Source"}} = %{$ABIdump->{"TypeInfo"}};
19341
19342 %{$CheckedSymbols{"Binary"}} = %{$ABIdump->{"SymbolInfo"}};
19343 %{$CheckedSymbols{"Source"}} = %{$ABIdump->{"SymbolInfo"}};
19344
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040019345 $Descriptor{1}{"Version"} = $TargetVersion{1}?$TargetVersion{1}:$ABIdump->{"LibraryVersion"};
19346 $Descriptor{2}{"Version"} = $TargetVersion{2}?$TargetVersion{2}:$ABIdump->{"LibraryVersion"};
19347 exitReport();
19348 }
19349 }
19350 }
19351}
19352
19353sub initLogging($)
19354{
19355 my $LibVersion = $_[0];
19356 # create log directory
19357 my ($LOG_DIR, $LOG_FILE) = ("logs/$TargetLibraryName/".$Descriptor{$LibVersion}{"Version"}, "log.txt");
19358 if($OutputLogPath{$LibVersion})
19359 { # user-defined by -log-path option
19360 ($LOG_DIR, $LOG_FILE) = separate_path($OutputLogPath{$LibVersion});
19361 }
19362 if($LogMode ne "n") {
19363 mkpath($LOG_DIR);
19364 }
19365 $LOG_PATH{$LibVersion} = get_abs_path($LOG_DIR)."/".$LOG_FILE;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040019366 if($Debug)
19367 { # debug directory
19368 $DEBUG_PATH{$LibVersion} = "debug/$TargetLibraryName/".$Descriptor{$LibVersion}{"Version"};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040019369 }
Andrey Ponomarenko35c44fd2012-06-18 17:50:25 +040019370 resetLogging($LibVersion);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040019371}
19372
19373sub writeLog($$)
19374{
19375 my ($LibVersion, $Msg) = @_;
19376 if($LogMode ne "n") {
19377 appendFile($LOG_PATH{$LibVersion}, $Msg);
19378 }
19379}
19380
19381sub resetLogging($)
19382{
19383 my $LibVersion = $_[0];
19384 if($LogMode!~/a|n/)
19385 { # remove old log
19386 unlink($LOG_PATH{$LibVersion});
Andrey Ponomarenko35c44fd2012-06-18 17:50:25 +040019387 if($Debug) {
19388 rmtree($DEBUG_PATH{$LibVersion});
19389 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040019390 }
19391}
19392
19393sub printErrorLog($)
19394{
19395 my $LibVersion = $_[0];
19396 if($LogMode ne "n") {
19397 printMsg("ERROR", "see log for details:\n ".$LOG_PATH{$LibVersion}."\n");
19398 }
19399}
19400
19401sub isDump($)
19402{
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040019403 if(get_filename($_[0])=~/\A(.+)\.(abi|abidump)(\.tar\.gz|\.zip|\.xml|)\Z/) {
19404 return $1;
19405 }
19406 return 0;
19407}
19408
19409sub isDump_U($)
19410{
19411 if(get_filename($_[0])=~/\A(.+)\.(abi|abidump)(\.xml|)\Z/) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040019412 return $1;
19413 }
19414 return 0;
19415}
19416
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040019417sub compareInit()
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040019418{
19419 # read input XML descriptors or ABI dumps
19420 if(not $Descriptor{1}{"Path"}) {
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040019421 exitStatus("Error", "-old option is not specified");
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040019422 }
19423 my @DParts1 = split(/\s*,\s*/, $Descriptor{1}{"Path"});
19424 foreach my $Part (@DParts1)
19425 {
19426 if(not -e $Part) {
19427 exitStatus("Access_Error", "can't access \'$Part\'");
19428 }
19429 }
19430 if(not $Descriptor{2}{"Path"}) {
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040019431 exitStatus("Error", "-new option is not specified");
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040019432 }
19433 my @DParts2 = split(/\s*,\s*/, $Descriptor{2}{"Path"});
19434 foreach my $Part (@DParts2)
19435 {
19436 if(not -e $Part) {
19437 exitStatus("Access_Error", "can't access \'$Part\'");
19438 }
19439 }
19440 detect_default_paths("bin"); # to extract dumps
19441 if($#DParts1==0 and $#DParts2==0
19442 and isDump($Descriptor{1}{"Path"})
19443 and isDump($Descriptor{2}{"Path"}))
19444 { # optimization: equal ABI dumps
19445 quickEmptyReports();
19446 }
19447 checkVersionNum(1, $Descriptor{1}{"Path"});
19448 checkVersionNum(2, $Descriptor{2}{"Path"});
19449 printMsg("INFO", "preparation, please wait ...");
19450 foreach my $Part (@DParts1)
19451 {
19452 if(isDump($Part)) {
19453 read_ABI_Dump(1, $Part);
19454 }
19455 else {
19456 readDescriptor(1, createDescriptor(1, $Part));
19457 }
19458 }
19459 foreach my $Part (@DParts2)
19460 {
19461 if(isDump($Part)) {
19462 read_ABI_Dump(2, $Part);
19463 }
19464 else {
19465 readDescriptor(2, createDescriptor(2, $Part));
19466 }
19467 }
19468 initLogging(1);
19469 initLogging(2);
19470 # check consistency
19471 if(not $Descriptor{1}{"Headers"}
19472 and not $Descriptor{1}{"Libs"}) {
19473 exitStatus("Error", "descriptor d1 does not contain both header files and libraries info");
19474 }
19475 if(not $Descriptor{2}{"Headers"}
19476 and not $Descriptor{2}{"Libs"}) {
19477 exitStatus("Error", "descriptor d2 does not contain both header files and libraries info");
19478 }
19479 if($Descriptor{1}{"Headers"} and not $Descriptor{1}{"Libs"}
19480 and not $Descriptor{2}{"Headers"} and $Descriptor{2}{"Libs"}) {
19481 exitStatus("Error", "can't compare headers with $SLIB_TYPE libraries");
19482 }
19483 elsif(not $Descriptor{1}{"Headers"} and $Descriptor{1}{"Libs"}
19484 and $Descriptor{2}{"Headers"} and not $Descriptor{2}{"Libs"}) {
19485 exitStatus("Error", "can't compare $SLIB_TYPE libraries with headers");
19486 }
Andrey Ponomarenkobdc85a92012-11-12 17:28:12 +040019487 if(not $Descriptor{1}{"Headers"})
19488 {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040019489 if($CheckHeadersOnly_Opt) {
19490 exitStatus("Error", "can't find header files info in descriptor d1");
19491 }
19492 }
Andrey Ponomarenkobdc85a92012-11-12 17:28:12 +040019493 if(not $Descriptor{2}{"Headers"})
19494 {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040019495 if($CheckHeadersOnly_Opt) {
19496 exitStatus("Error", "can't find header files info in descriptor d2");
19497 }
19498 }
19499 if(not $Descriptor{1}{"Headers"}
Andrey Ponomarenkobdc85a92012-11-12 17:28:12 +040019500 or not $Descriptor{2}{"Headers"})
19501 {
19502 if(not $CheckObjectsOnly_Opt)
19503 {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040019504 printMsg("WARNING", "comparing $SLIB_TYPE libraries only");
19505 $CheckObjectsOnly = 1;
19506 }
19507 }
Andrey Ponomarenkobdc85a92012-11-12 17:28:12 +040019508 if(not $Descriptor{1}{"Libs"})
19509 {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040019510 if($CheckObjectsOnly_Opt) {
19511 exitStatus("Error", "can't find $SLIB_TYPE libraries info in descriptor d1");
19512 }
19513 }
Andrey Ponomarenkobdc85a92012-11-12 17:28:12 +040019514 if(not $Descriptor{2}{"Libs"})
19515 {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040019516 if($CheckObjectsOnly_Opt) {
19517 exitStatus("Error", "can't find $SLIB_TYPE libraries info in descriptor d2");
19518 }
19519 }
19520 if(not $Descriptor{1}{"Libs"}
19521 or not $Descriptor{2}{"Libs"})
19522 { # comparing standalone header files
19523 # comparing ABI dumps created with --headers-only
19524 if(not $CheckHeadersOnly_Opt)
19525 {
19526 printMsg("WARNING", "checking headers only");
19527 $CheckHeadersOnly = 1;
19528 }
19529 }
19530 if($UseDumps)
19531 { # --use-dumps
19532 # parallel processing
19533 my $pid = fork();
19534 if($pid)
19535 { # dump on two CPU cores
19536 my @PARAMS = ("-dump", $Descriptor{1}{"Path"}, "-l", $TargetLibraryName);
19537 if($RelativeDirectory{1}) {
19538 @PARAMS = (@PARAMS, "-relpath", $RelativeDirectory{1});
19539 }
19540 if($OutputLogPath{1}) {
19541 @PARAMS = (@PARAMS, "-log-path", $OutputLogPath{1});
19542 }
19543 if($CrossGcc) {
19544 @PARAMS = (@PARAMS, "-cross-gcc", $CrossGcc);
19545 }
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040019546 if($Quiet)
19547 {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040019548 @PARAMS = (@PARAMS, "-quiet");
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040019549 @PARAMS = (@PARAMS, "-logging-mode", "a");
19550 }
19551 elsif($LogMode and $LogMode ne "w")
19552 { # "w" is default
19553 @PARAMS = (@PARAMS, "-logging-mode", $LogMode);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040019554 }
19555 if($ExtendedCheck) {
19556 @PARAMS = (@PARAMS, "-extended");
19557 }
19558 if($UserLang) {
19559 @PARAMS = (@PARAMS, "-lang", $UserLang);
19560 }
19561 if($TargetVersion{1}) {
19562 @PARAMS = (@PARAMS, "-vnum", $TargetVersion{1});
19563 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +040019564 if($BinaryOnly) {
19565 @PARAMS = (@PARAMS, "-binary");
19566 }
19567 if($SourceOnly) {
19568 @PARAMS = (@PARAMS, "-source");
19569 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040019570 if($SortDump) {
19571 @PARAMS = (@PARAMS, "-sort");
19572 }
Andrey Ponomarenko01117f12012-06-26 12:23:02 +040019573 if($DumpFormat and $DumpFormat ne "perl") {
19574 @PARAMS = (@PARAMS, "-dump-format", $DumpFormat);
19575 }
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +040019576 if($CheckHeadersOnly) {
19577 @PARAMS = (@PARAMS, "-headers-only");
19578 }
19579 if($CheckObjectsOnly) {
19580 @PARAMS = (@PARAMS, "-objects-only");
19581 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +040019582 if($Debug)
19583 {
19584 @PARAMS = (@PARAMS, "-debug");
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040019585 printMsg("INFO", "running perl $0 @PARAMS");
Andrey Ponomarenko85043792012-05-14 16:48:07 +040019586 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040019587 system("perl", $0, @PARAMS);
19588 if($?) {
19589 exit(1);
19590 }
19591 }
19592 else
19593 { # child
19594 my @PARAMS = ("-dump", $Descriptor{2}{"Path"}, "-l", $TargetLibraryName);
19595 if($RelativeDirectory{2}) {
19596 @PARAMS = (@PARAMS, "-relpath", $RelativeDirectory{2});
19597 }
19598 if($OutputLogPath{2}) {
19599 @PARAMS = (@PARAMS, "-log-path", $OutputLogPath{2});
19600 }
19601 if($CrossGcc) {
19602 @PARAMS = (@PARAMS, "-cross-gcc", $CrossGcc);
19603 }
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040019604 if($Quiet)
19605 {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040019606 @PARAMS = (@PARAMS, "-quiet");
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040019607 @PARAMS = (@PARAMS, "-logging-mode", "a");
19608 }
19609 elsif($LogMode and $LogMode ne "w")
19610 { # "w" is default
19611 @PARAMS = (@PARAMS, "-logging-mode", $LogMode);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040019612 }
19613 if($ExtendedCheck) {
19614 @PARAMS = (@PARAMS, "-extended");
19615 }
19616 if($UserLang) {
19617 @PARAMS = (@PARAMS, "-lang", $UserLang);
19618 }
19619 if($TargetVersion{2}) {
19620 @PARAMS = (@PARAMS, "-vnum", $TargetVersion{2});
19621 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +040019622 if($BinaryOnly) {
19623 @PARAMS = (@PARAMS, "-binary");
19624 }
19625 if($SourceOnly) {
19626 @PARAMS = (@PARAMS, "-source");
19627 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040019628 if($SortDump) {
19629 @PARAMS = (@PARAMS, "-sort");
19630 }
Andrey Ponomarenko01117f12012-06-26 12:23:02 +040019631 if($DumpFormat and $DumpFormat ne "perl") {
19632 @PARAMS = (@PARAMS, "-dump-format", $DumpFormat);
19633 }
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +040019634 if($CheckHeadersOnly) {
19635 @PARAMS = (@PARAMS, "-headers-only");
19636 }
19637 if($CheckObjectsOnly) {
19638 @PARAMS = (@PARAMS, "-objects-only");
19639 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +040019640 if($Debug)
19641 {
19642 @PARAMS = (@PARAMS, "-debug");
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040019643 printMsg("INFO", "running perl $0 @PARAMS");
Andrey Ponomarenko85043792012-05-14 16:48:07 +040019644 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040019645 system("perl", $0, @PARAMS);
19646 if($?) {
19647 exit(1);
19648 }
19649 else {
19650 exit(0);
19651 }
19652 }
19653 waitpid($pid, 0);
19654 my @CMP_PARAMS = ("-l", $TargetLibraryName);
19655 @CMP_PARAMS = (@CMP_PARAMS, "-d1", "abi_dumps/$TargetLibraryName/".$TargetLibraryName."_".$Descriptor{1}{"Version"}.".abi.$AR_EXT");
19656 @CMP_PARAMS = (@CMP_PARAMS, "-d2", "abi_dumps/$TargetLibraryName/".$TargetLibraryName."_".$Descriptor{2}{"Version"}.".abi.$AR_EXT");
19657 if($TargetLibraryFName ne $TargetLibraryName) {
19658 @CMP_PARAMS = (@CMP_PARAMS, "-l-full", $TargetLibraryFName);
19659 }
19660 if($ShowRetVal) {
19661 @CMP_PARAMS = (@CMP_PARAMS, "-show-retval");
19662 }
19663 if($CrossGcc) {
19664 @CMP_PARAMS = (@CMP_PARAMS, "-cross-gcc", $CrossGcc);
19665 }
Andrey Ponomarenko35c44fd2012-06-18 17:50:25 +040019666 @CMP_PARAMS = (@CMP_PARAMS, "-logging-mode", "a");
19667 if($Quiet) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040019668 @CMP_PARAMS = (@CMP_PARAMS, "-quiet");
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040019669 }
19670 if($ReportFormat and $ReportFormat ne "html")
19671 { # HTML is default format
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040019672 @CMP_PARAMS = (@CMP_PARAMS, "-report-format", $ReportFormat);
19673 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040019674 if($OutputReportPath) {
19675 @CMP_PARAMS = (@CMP_PARAMS, "-report-path", $OutputReportPath);
19676 }
19677 if($BinaryReportPath) {
19678 @CMP_PARAMS = (@CMP_PARAMS, "-bin-report-path", $BinaryReportPath);
19679 }
19680 if($SourceReportPath) {
19681 @CMP_PARAMS = (@CMP_PARAMS, "-src-report-path", $SourceReportPath);
19682 }
19683 if($LoggingPath) {
19684 @CMP_PARAMS = (@CMP_PARAMS, "-log-path", $LoggingPath);
19685 }
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +040019686 if($CheckHeadersOnly) {
19687 @CMP_PARAMS = (@CMP_PARAMS, "-headers-only");
19688 }
19689 if($CheckObjectsOnly) {
19690 @CMP_PARAMS = (@CMP_PARAMS, "-objects-only");
19691 }
19692 if($BinaryOnly) {
19693 @CMP_PARAMS = (@CMP_PARAMS, "-binary");
19694 }
19695 if($SourceOnly) {
19696 @CMP_PARAMS = (@CMP_PARAMS, "-source");
19697 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +040019698 if($Browse) {
19699 @CMP_PARAMS = (@CMP_PARAMS, "-browse", $Browse);
19700 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040019701 if($OpenReport) {
19702 @CMP_PARAMS = (@CMP_PARAMS, "-open");
19703 }
19704 if($Debug)
19705 {
19706 @CMP_PARAMS = (@CMP_PARAMS, "-debug");
19707 printMsg("INFO", "running perl $0 @CMP_PARAMS");
Andrey Ponomarenko85043792012-05-14 16:48:07 +040019708 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040019709 system("perl", $0, @CMP_PARAMS);
19710 exit($?>>8);
19711 }
19712 if(not $Descriptor{1}{"Dump"}
19713 or not $Descriptor{2}{"Dump"})
19714 { # need GCC toolchain to analyze
19715 # header files and libraries
19716 detect_default_paths("inc|lib|gcc");
19717 }
19718 if(not $Descriptor{1}{"Dump"})
19719 {
19720 if(not $CheckHeadersOnly) {
19721 readLibs(1);
19722 }
19723 if($CheckHeadersOnly) {
19724 setLanguage(1, "C++");
19725 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +040019726 if(not $CheckObjectsOnly) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040019727 searchForHeaders(1);
19728 }
19729 $WORD_SIZE{1} = detectWordSize();
19730 }
19731 if(not $Descriptor{2}{"Dump"})
19732 {
19733 if(not $CheckHeadersOnly) {
19734 readLibs(2);
19735 }
19736 if($CheckHeadersOnly) {
19737 setLanguage(2, "C++");
19738 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +040019739 if(not $CheckObjectsOnly) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040019740 searchForHeaders(2);
19741 }
19742 $WORD_SIZE{2} = detectWordSize();
19743 }
19744 if($WORD_SIZE{1} ne $WORD_SIZE{2})
19745 { # support for old ABI dumps
19746 # try to synch different WORD sizes
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040019747 if(not checkDump(1, "2.1"))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040019748 {
19749 $WORD_SIZE{1} = $WORD_SIZE{2};
19750 printMsg("WARNING", "set WORD size to ".$WORD_SIZE{2}." bytes");
19751 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040019752 elsif(not checkDump(2, "2.1"))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040019753 {
19754 $WORD_SIZE{2} = $WORD_SIZE{1};
19755 printMsg("WARNING", "set WORD size to ".$WORD_SIZE{1}." bytes");
19756 }
19757 }
19758 elsif(not $WORD_SIZE{1}
19759 and not $WORD_SIZE{2})
19760 { # support for old ABI dumps
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040019761 $WORD_SIZE{1} = "4";
19762 $WORD_SIZE{2} = "4";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040019763 }
19764 if($Descriptor{1}{"Dump"})
19765 { # support for old ABI dumps
19766 prepareTypes(1);
19767 }
19768 if($Descriptor{2}{"Dump"})
19769 { # support for old ABI dumps
19770 prepareTypes(2);
19771 }
19772 if($AppPath and not keys(%{$Symbol_Library{1}})) {
19773 printMsg("WARNING", "the application ".get_filename($AppPath)." has no symbols imported from the $SLIB_TYPE libraries");
19774 }
19775 # started to process input data
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040019776 if(not $CheckObjectsOnly)
19777 {
19778 if($Descriptor{1}{"Headers"}
19779 and not $Descriptor{1}{"Dump"}) {
19780 readHeaders(1);
19781 }
19782 if($Descriptor{2}{"Headers"}
19783 and not $Descriptor{2}{"Dump"}) {
19784 readHeaders(2);
19785 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040019786 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +040019787
19788 # clean memory
19789 %SystemHeaders = ();
19790 %mangled_name_gcc = ();
19791
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040019792 prepareSymbols(1);
19793 prepareSymbols(2);
Andrey Ponomarenko16934472012-03-29 15:37:04 +040019794
Andrey Ponomarenko85043792012-05-14 16:48:07 +040019795 # clean memory
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040019796 %SymbolInfo = ();
Andrey Ponomarenko16934472012-03-29 15:37:04 +040019797
19798 # Virtual Tables
19799 registerVTable(1);
19800 registerVTable(2);
19801
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040019802 if(not checkDump(1, "1.22")
19803 and checkDump(2, "1.22"))
Andrey Ponomarenko16934472012-03-29 15:37:04 +040019804 { # support for old ABI dumps
19805 foreach my $ClassName (keys(%{$VirtualTable{2}}))
19806 {
19807 if($ClassName=~/</)
19808 { # templates
19809 if(not defined $VirtualTable{1}{$ClassName})
19810 { # synchronize
19811 delete($VirtualTable{2}{$ClassName});
19812 }
19813 }
19814 }
19815 }
19816
19817 registerOverriding(1);
19818 registerOverriding(2);
19819
19820 setVirtFuncPositions(1);
19821 setVirtFuncPositions(2);
19822
19823 # Other
19824 addParamNames(1);
19825 addParamNames(2);
19826
19827 detectChangedTypedefs();
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040019828}
19829
19830sub compareAPIs($)
19831{
19832 my $Level = $_[0];
19833 readRules($Level);
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +040019834 loadModule("CallConv");
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040019835 if($Level eq "Binary") {
19836 printMsg("INFO", "comparing ABIs ...");
19837 }
19838 else {
19839 printMsg("INFO", "comparing APIs ...");
19840 }
19841 if($CheckHeadersOnly
19842 or $Level eq "Source")
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040019843 { # added/removed in headers
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040019844 detectAdded_H($Level);
19845 detectRemoved_H($Level);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040019846 }
19847 else
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040019848 { # added/removed in libs
19849 detectAdded($Level);
19850 detectRemoved($Level);
19851 }
19852 if(not $CheckObjectsOnly)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040019853 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040019854 mergeSignatures($Level);
19855 if(keys(%{$CheckedSymbols{$Level}})) {
19856 mergeConstants($Level);
19857 }
19858 }
19859 if($CheckHeadersOnly
19860 or $Level eq "Source")
19861 { # added/removed in headers
19862 mergeHeaders($Level);
19863 }
19864 else
19865 { # added/removed in libs
19866 mergeLibs($Level);
19867 if($CheckImpl
19868 and $Level eq "Binary") {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040019869 mergeImpl();
19870 }
19871 }
19872}
19873
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040019874sub getSysOpts()
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040019875{
19876 my %Opts = (
19877 "OStarget"=>$OStarget,
19878 "Debug"=>$Debug,
19879 "Quiet"=>$Quiet,
19880 "LogMode"=>$LogMode,
19881 "CheckHeadersOnly"=>$CheckHeadersOnly,
19882
19883 "SystemRoot"=>$SystemRoot,
19884 "MODULES_DIR"=>$MODULES_DIR,
19885 "GCC_PATH"=>$GCC_PATH,
19886 "TargetSysInfo"=>$TargetSysInfo,
19887 "CrossPrefix"=>$CrossPrefix,
19888 "TargetLibraryName"=>$TargetLibraryName,
19889 "CrossGcc"=>$CrossGcc,
19890 "UseStaticLibs"=>$UseStaticLibs,
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040019891 "NoStdInc"=>$NoStdInc,
19892
19893 "BinaryOnly" => $BinaryOnly,
19894 "SourceOnly" => $SourceOnly
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040019895 );
19896 return \%Opts;
19897}
19898
19899sub get_CoreError($)
19900{
19901 my %CODE_ERROR = reverse(%ERROR_CODE);
19902 return $CODE_ERROR{$_[0]};
19903}
19904
19905sub scenario()
19906{
19907 if($StdOut)
19908 { # enable quiet mode
19909 $Quiet = 1;
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040019910 $JoinReport = 1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040019911 }
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040019912 if(not $LogMode)
19913 { # default
19914 $LogMode = "w";
19915 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040019916 if($UserLang)
19917 { # --lang=C++
19918 $UserLang = uc($UserLang);
19919 $COMMON_LANGUAGE{1}=$UserLang;
19920 $COMMON_LANGUAGE{2}=$UserLang;
19921 }
19922 if($LoggingPath)
19923 {
19924 $OutputLogPath{1} = $LoggingPath;
19925 $OutputLogPath{2} = $LoggingPath;
19926 if($Quiet) {
19927 $COMMON_LOG_PATH = $LoggingPath;
19928 }
19929 }
Andrey Ponomarenko5c09ef32012-06-14 18:17:33 +040019930 if($OutputDumpPath)
19931 { # validate
19932 if($OutputDumpPath!~/\.abi(\.\Q$AR_EXT\E|)\Z/) {
19933 exitStatus("Error", "the dump path should be a path to *.abi.$AR_EXT or *.abi file");
19934 }
19935 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040019936 if($BinaryOnly and $SourceOnly)
19937 { # both --binary and --source
19938 # is the default mode
19939 $DoubleReport = 1;
19940 $JoinReport = 0;
19941 $BinaryOnly = 0;
19942 $SourceOnly = 0;
19943 if($OutputReportPath)
19944 { # --report-path
19945 $DoubleReport = 0;
19946 $JoinReport = 1;
19947 }
19948 }
19949 elsif($BinaryOnly or $SourceOnly)
19950 { # --binary or --source
19951 $DoubleReport = 0;
19952 $JoinReport = 0;
19953 }
19954 if($UseXML)
19955 { # --xml option
19956 $ReportFormat = "xml";
Andrey Ponomarenko5c09ef32012-06-14 18:17:33 +040019957 $DumpFormat = "xml";
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040019958 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040019959 if($ReportFormat)
19960 { # validate
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040019961 $ReportFormat = lc($ReportFormat);
19962 if($ReportFormat!~/\A(xml|html|htm)\Z/) {
Andrey Ponomarenko5c09ef32012-06-14 18:17:33 +040019963 exitStatus("Error", "unknown report format \'$ReportFormat\'");
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040019964 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040019965 if($ReportFormat eq "htm")
19966 { # HTM == HTML
19967 $ReportFormat = "html";
19968 }
19969 elsif($ReportFormat eq "xml")
19970 { # --report-format=XML equal to --xml
19971 $UseXML = 1;
19972 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040019973 }
19974 else
19975 { # default: HTML
19976 $ReportFormat = "html";
19977 }
Andrey Ponomarenko5c09ef32012-06-14 18:17:33 +040019978 if($DumpFormat)
19979 { # validate
19980 $DumpFormat = lc($DumpFormat);
19981 if($DumpFormat!~/\A(xml|perl)\Z/) {
19982 exitStatus("Error", "unknown ABI dump format \'$DumpFormat\'");
19983 }
19984 if($DumpFormat eq "xml")
19985 { # --dump-format=XML equal to --xml
19986 $UseXML = 1;
19987 }
19988 }
19989 else
Andrey Ponomarenko01117f12012-06-26 12:23:02 +040019990 { # default: Perl Data::Dumper
Andrey Ponomarenko5c09ef32012-06-14 18:17:33 +040019991 $DumpFormat = "perl";
19992 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040019993 if($Quiet and $LogMode!~/a|n/)
19994 { # --quiet log
19995 if(-f $COMMON_LOG_PATH) {
19996 unlink($COMMON_LOG_PATH);
19997 }
19998 }
19999 if($TestTool and $UseDumps)
20000 { # --test && --use-dumps == --test-dump
20001 $TestDump = 1;
20002 }
20003 if($Help) {
20004 HELP_MESSAGE();
20005 exit(0);
20006 }
20007 if($InfoMsg) {
20008 INFO_MESSAGE();
20009 exit(0);
20010 }
20011 if($ShowVersion) {
20012 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.");
20013 exit(0);
20014 }
20015 if($DumpVersion) {
20016 printMsg("INFO", $TOOL_VERSION);
20017 exit(0);
20018 }
20019 if($ExtendedCheck) {
20020 $CheckHeadersOnly = 1;
20021 }
20022 if($SystemRoot_Opt)
20023 { # user defined root
20024 if(not -e $SystemRoot_Opt) {
20025 exitStatus("Access_Error", "can't access \'$SystemRoot\'");
20026 }
20027 $SystemRoot = $SystemRoot_Opt;
20028 $SystemRoot=~s/[\/]+\Z//g;
20029 if($SystemRoot) {
20030 $SystemRoot = get_abs_path($SystemRoot);
20031 }
20032 }
20033 $Data::Dumper::Sortkeys = 1;
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +040020034
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040020035 if($SortDump)
20036 {
20037 $Data::Dumper::Useperl = 1;
20038 $Data::Dumper::Sortkeys = \&dump_sorting;
20039 }
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +040020040
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040020041 if($TargetLibsPath)
20042 {
20043 if(not -f $TargetLibsPath) {
20044 exitStatus("Access_Error", "can't access file \'$TargetLibsPath\'");
20045 }
20046 foreach my $Lib (split(/\s*\n\s*/, readFile($TargetLibsPath))) {
20047 $TargetLibs{$Lib} = 1;
20048 }
20049 }
20050 if($TargetHeadersPath)
20051 { # --headers-list
20052 if(not -f $TargetHeadersPath) {
20053 exitStatus("Access_Error", "can't access file \'$TargetHeadersPath\'");
20054 }
20055 foreach my $Header (split(/\s*\n\s*/, readFile($TargetHeadersPath)))
20056 {
20057 $TargetHeaders{1}{$Header} = 1;
20058 $TargetHeaders{2}{$Header} = 1;
20059 }
20060 }
20061 if($TargetHeader)
20062 { # --header
20063 $TargetHeaders{1}{$TargetHeader} = 1;
20064 $TargetHeaders{2}{$TargetHeader} = 1;
20065 }
20066 if($TestTool
20067 or $TestDump)
20068 { # --test, --test-dump
20069 detect_default_paths("bin|gcc"); # to compile libs
20070 loadModule("RegTests");
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +040020071 testTool($TestDump, $Debug, $Quiet, $ExtendedCheck, $LogMode, $ReportFormat, $DumpFormat,
20072 $LIB_EXT, $GCC_PATH, $Browse, $OpenReport, $SortDump, $CheckHeadersOnly, $CheckObjectsOnly);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040020073 exit(0);
20074 }
20075 if($DumpSystem)
20076 { # --dump-system
20077 loadModule("SysCheck");
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040020078 if($DumpSystem=~/\.(xml|desc)\Z/)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040020079 { # system XML descriptor
20080 if(not -f $DumpSystem) {
20081 exitStatus("Access_Error", "can't access file \'$DumpSystem\'");
20082 }
20083 my $Ret = readSystemDescriptor(readFile($DumpSystem));
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040020084 foreach (@{$Ret->{"Tools"}})
20085 {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040020086 $SystemPaths{"bin"}{$_} = 1;
20087 $TargetTools{$_}=1;
20088 }
20089 if($Ret->{"CrossPrefix"}) {
20090 $CrossPrefix = $Ret->{"CrossPrefix"};
20091 }
20092 }
20093 elsif($SystemRoot_Opt)
20094 { # -sysroot "/" option
20095 # default target: /usr/lib, /usr/include
20096 # search libs: /usr/lib and /lib
20097 if(not -e $SystemRoot."/usr/lib") {
20098 exitStatus("Access_Error", "can't access '".$SystemRoot."/usr/lib'");
20099 }
20100 if(not -e $SystemRoot."/lib") {
20101 exitStatus("Access_Error", "can't access '".$SystemRoot."/lib'");
20102 }
20103 if(not -e $SystemRoot."/usr/include") {
20104 exitStatus("Access_Error", "can't access '".$SystemRoot."/usr/include'");
20105 }
20106 readSystemDescriptor("
20107 <name>
20108 $DumpSystem
20109 </name>
20110 <headers>
20111 $SystemRoot/usr/include
20112 </headers>
20113 <libs>
20114 $SystemRoot/usr/lib
20115 </libs>
20116 <search_libs>
20117 $SystemRoot/lib
20118 </search_libs>");
20119 }
20120 else {
20121 exitStatus("Error", "-sysroot <dirpath> option should be specified, usually it's \"/\"");
20122 }
20123 detect_default_paths("bin|gcc"); # to check symbols
20124 if($OStarget eq "windows")
20125 { # to run dumpbin.exe
20126 # and undname.exe
20127 check_win32_env();
20128 }
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040020129 dumpSystem(getSysOpts());
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040020130 exit(0);
20131 }
20132 if($CmpSystems)
20133 { # --cmp-systems
20134 detect_default_paths("bin"); # to extract dumps
20135 loadModule("SysCheck");
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040020136 cmpSystems($Descriptor{1}{"Path"}, $Descriptor{2}{"Path"}, getSysOpts());
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040020137 exit(0);
20138 }
20139 if($GenerateTemplate) {
20140 generateTemplate();
20141 exit(0);
20142 }
20143 if(not $TargetLibraryName) {
20144 exitStatus("Error", "library name is not selected (option -l <name>)");
20145 }
20146 else
20147 { # validate library name
20148 if($TargetLibraryName=~/[\*\/\\]/) {
20149 exitStatus("Error", "\"\\\", \"\/\" and \"*\" symbols are not allowed in the library name");
20150 }
20151 }
20152 if(not $TargetLibraryFName) {
20153 $TargetLibraryFName = $TargetLibraryName;
20154 }
20155 if($CheckHeadersOnly_Opt and $CheckObjectsOnly_Opt) {
20156 exitStatus("Error", "you can't specify both -headers-only and -objects-only options at the same time");
20157 }
20158 if($SymbolsListPath)
20159 {
20160 if(not -f $SymbolsListPath) {
20161 exitStatus("Access_Error", "can't access file \'$SymbolsListPath\'");
20162 }
20163 foreach my $Interface (split(/\s*\n\s*/, readFile($SymbolsListPath))) {
20164 $SymbolsList{$Interface} = 1;
20165 }
20166 }
20167 if($SkipHeadersPath)
20168 {
20169 if(not -f $SkipHeadersPath) {
20170 exitStatus("Access_Error", "can't access file \'$SkipHeadersPath\'");
20171 }
20172 foreach my $Path (split(/\s*\n\s*/, readFile($SkipHeadersPath)))
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040020173 { # register for both versions
20174 $SkipHeadersList{1}{$Path} = 1;
20175 $SkipHeadersList{2}{$Path} = 1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040020176 my ($CPath, $Type) = classifyPath($Path);
20177 $SkipHeaders{1}{$Type}{$CPath} = 1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040020178 $SkipHeaders{2}{$Type}{$CPath} = 1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040020179 }
20180 }
20181 if($ParamNamesPath)
20182 {
20183 if(not -f $ParamNamesPath) {
20184 exitStatus("Access_Error", "can't access file \'$ParamNamesPath\'");
20185 }
20186 foreach my $Line (split(/\n/, readFile($ParamNamesPath)))
20187 {
20188 if($Line=~s/\A(\w+)\;//)
20189 {
20190 my $Interface = $1;
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040020191 if($Line=~/;(\d+);/)
20192 {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040020193 while($Line=~s/(\d+);(\w+)//) {
20194 $AddIntParams{$Interface}{$1}=$2;
20195 }
20196 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040020197 else
20198 {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040020199 my $Num = 0;
20200 foreach my $Name (split(/;/, $Line)) {
20201 $AddIntParams{$Interface}{$Num++}=$Name;
20202 }
20203 }
20204 }
20205 }
20206 }
20207 if($AppPath)
20208 {
20209 if(not -f $AppPath) {
20210 exitStatus("Access_Error", "can't access file \'$AppPath\'");
20211 }
Andrey Ponomarenko16934472012-03-29 15:37:04 +040020212 foreach my $Interface (readSymbols_App($AppPath)) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040020213 $SymbolsList_App{$Interface} = 1;
20214 }
20215 }
20216 if($DumpAPI)
20217 { # --dump-abi
20218 # make an API dump
20219 create_ABI_Dump();
20220 exit($COMPILE_ERRORS);
20221 }
20222 # default: compare APIs
20223 # -d1 <path>
20224 # -d2 <path>
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040020225 compareInit();
20226 if($JoinReport or $DoubleReport)
20227 {
20228 compareAPIs("Binary");
20229 compareAPIs("Source");
20230 }
20231 elsif($BinaryOnly) {
20232 compareAPIs("Binary");
20233 }
20234 elsif($SourceOnly) {
20235 compareAPIs("Source");
20236 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040020237 exitReport();
20238}
20239
20240scenario();