blob: 8f3a5320661fd06e839537178b42c9d417f83c00 [file] [log] [blame]
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04001#!/usr/bin/perl
2###########################################################################
Andrey Ponomarenko07aea072012-11-12 16:15:07 +04003# ABI Compliance Checker (ACC) 1.98.5
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04004# A tool for checking backward compatibility of a C/C++ library API
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005#
Andrey Ponomarenko85043792012-05-14 16:48:07 +04006# Copyright (C) 2009-2010 The Linux Foundation
7# Copyright (C) 2009-2011 Institute for System Programming, RAS
8# Copyright (C) 2011-2012 Nokia Corporation and/or its subsidiary(-ies)
9# Copyright (C) 2011-2012 ROSA Laboratory
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010#
11# Written by Andrey Ponomarenko
12#
13# PLATFORMS
14# =========
15# Linux, FreeBSD, Mac OS X, Haiku, MS Windows, Symbian
16#
17# REQUIREMENTS
18# ============
19# Linux
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +040020# - G++ (3.0-4.7, recommended 4.5 or newer)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040021# - GNU Binutils (readelf, c++filt, objdump)
Andrey Ponomarenko85043792012-05-14 16:48:07 +040022# - Perl 5 (5.8 or newer)
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +040023# - Ctags (5.8 or newer)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040024#
25# Mac OS X
Andrey Ponomarenko07aea072012-11-12 16:15:07 +040026# - Xcode (g++, c++filt, nm)
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +040027# - Ctags (5.8 or newer)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040028#
29# MS Windows
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +040030# - MinGW (3.0-4.7, recommended 4.5 or newer)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040031# - MS Visual C++ (dumpbin, undname, cl)
Andrey Ponomarenko85043792012-05-14 16:48:07 +040032# - Active Perl 5 (5.8 or newer)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040033# - Sigcheck v1.71 or newer
34# - Info-ZIP 3.0 (zip, unzip)
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +040035# - Ctags (5.8 or newer)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040036# - Add gcc.exe path (C:\MinGW\bin\) to your system PATH variable
37# - Run vsvars32.bat (C:\Microsoft Visual Studio 9.0\Common7\Tools\)
38#
39# This program is free software: you can redistribute it and/or modify
40# it under the terms of the GNU General Public License or the GNU Lesser
41# General Public License as published by the Free Software Foundation.
42#
43# This program is distributed in the hope that it will be useful,
44# but WITHOUT ANY WARRANTY; without even the implied warranty of
45# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
46# GNU General Public License for more details.
47#
48# You should have received a copy of the GNU General Public License
49# and the GNU Lesser General Public License along with this program.
50# If not, see <http://www.gnu.org/licenses/>.
51###########################################################################
52use Getopt::Long;
53Getopt::Long::Configure ("posix_default", "no_ignore_case");
54use File::Path qw(mkpath rmtree);
55use File::Temp qw(tempdir);
56use File::Copy qw(copy move);
57use Cwd qw(abs_path cwd);
58use Data::Dumper;
Andrey Ponomarenko2fba6302012-03-29 17:44:47 +040059use Config;
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040060use Fcntl;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040061
Andrey Ponomarenko07aea072012-11-12 16:15:07 +040062my $TOOL_VERSION = "1.98.5";
63my $ABI_DUMP_VERSION = "2.19.2";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040064my $OLDEST_SUPPORTED_VERSION = "1.18";
65my $XML_REPORT_VERSION = "1.0";
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +040066my $XML_ABI_DUMP_VERSION = "1.2";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040067my $OSgroup = get_OSgroup();
68my $ORIG_DIR = cwd();
69my $TMP_DIR = tempdir(CLEANUP=>1);
70
71# Internal modules
72my $MODULES_DIR = get_Modules();
73push(@INC, get_dirname($MODULES_DIR));
74# Rules DB
75my %RULES_PATH = (
76 "Binary" => $MODULES_DIR."/RulesBin.xml",
77 "Source" => $MODULES_DIR."/RulesSrc.xml");
78
79my ($Help, $ShowVersion, %Descriptor, $TargetLibraryName, $GenerateTemplate,
80$TestTool, $DumpAPI, $SymbolsListPath, $CheckHeadersOnly_Opt, $UseDumps,
81$CheckObjectsOnly_Opt, $AppPath, $StrictCompat, $DumpVersion, $ParamNamesPath,
82%RelativeDirectory, $TargetLibraryFName, $TestDump, $CheckImpl, $LoggingPath,
83%TargetVersion, $InfoMsg, $UseOldDumps, %UsedDump, $CrossGcc, %OutputLogPath,
84$OutputReportPath, $OutputDumpPath, $ShowRetVal, $SystemRoot_Opt, $DumpSystem,
85$CmpSystems, $TargetLibsPath, $Debug, $CrossPrefix, $UseStaticLibs, $NoStdInc,
86$TargetComponent_Opt, $TargetSysInfo, $TargetHeader, $ExtendedCheck, $Quiet,
Andrey Ponomarenko07aea072012-11-12 16:15:07 +040087$SkipHeadersPath, $CppCompat, $LogMode, $StdOut, $ListAffected, $ReportFormat,
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040088$UserLang, $TargetHeadersPath, $BinaryOnly, $SourceOnly, $BinaryReportPath,
Andrey Ponomarenko07aea072012-11-12 16:15:07 +040089$SourceReportPath, $UseXML, $Browse, $OpenReport, $SortDump, $DumpFormat,
90$ExtraInfo);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040091
92my $CmdName = get_filename($0);
93my %OS_LibExt = (
94 "dynamic" => {
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040095 "linux"=>"so",
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040096 "macos"=>"dylib",
97 "windows"=>"dll",
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040098 "symbian"=>"dso",
99 "default"=>"so"
Andrey Ponomarenkoab282102012-03-11 11:57:02 +0400100 },
101 "static" => {
Andrey Ponomarenko9927e332012-10-19 10:50:48 +0400102 "linux"=>"a",
Andrey Ponomarenkoab282102012-03-11 11:57:02 +0400103 "windows"=>"lib",
Andrey Ponomarenko9927e332012-10-19 10:50:48 +0400104 "symbian"=>"lib",
105 "default"=>"a"
Andrey Ponomarenkoab282102012-03-11 11:57:02 +0400106 }
107);
108
109my %OS_Archive = (
110 "windows"=>"zip",
111 "default"=>"tar.gz"
112);
113
114my %ERROR_CODE = (
115 # Compatible verdict
116 "Compatible"=>0,
117 "Success"=>0,
118 # Incompatible verdict
119 "Incompatible"=>1,
120 # Undifferentiated error code
121 "Error"=>2,
122 # System command is not found
123 "Not_Found"=>3,
124 # Cannot access input files
125 "Access_Error"=>4,
126 # Cannot compile header files
127 "Cannot_Compile"=>5,
128 # Header compiled with errors
129 "Compile_Error"=>6,
130 # Invalid input ABI dump
131 "Invalid_Dump"=>7,
132 # Incompatible version of ABI dump
133 "Dump_Version"=>8,
134 # Cannot find a module
135 "Module_Error"=>9,
136 # Empty intersection between
137 # headers and shared objects
138 "Empty_Intersection"=>10,
139 # Empty set of symbols in headers
140 "Empty_Set"=>11
141);
142
143my %HomePage = (
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +0400144 "Wiki"=>"http://ispras.linuxbase.org/index.php/ABI_compliance_checker",
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +0400145 "Dev1"=>"https://github.com/lvc/abi-compliance-checker",
146 "Dev2"=>"http://forge.ispras.ru/projects/abi-compliance-checker"
Andrey Ponomarenkoab282102012-03-11 11:57:02 +0400147);
148
149my $ShortUsage = "ABI Compliance Checker (ACC) $TOOL_VERSION
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +0400150A tool for checking backward compatibility of a C/C++ library API
Andrey Ponomarenkoab282102012-03-11 11:57:02 +0400151Copyright (C) 2012 ROSA Laboratory
152License: GNU LGPL or GNU GPL
153
154Usage: $CmdName [options]
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +0400155Example: $CmdName -lib NAME -old OLD.xml -new NEW.xml
Andrey Ponomarenkoab282102012-03-11 11:57:02 +0400156
157OLD.xml and NEW.xml are XML-descriptors:
158
159 <version>
160 1.0
161 </version>
162
163 <headers>
164 /path/to/headers/
165 </headers>
166
167 <libs>
168 /path/to/libraries/
169 </libs>
170
171More info: $CmdName --help\n";
172
173if($#ARGV==-1) {
174 printMsg("INFO", $ShortUsage);
175 exit(0);
176}
177
178foreach (2 .. $#ARGV)
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +0400179{ # correct comma separated options
Andrey Ponomarenkoab282102012-03-11 11:57:02 +0400180 if($ARGV[$_-1] eq ",") {
181 $ARGV[$_-2].=",".$ARGV[$_];
182 splice(@ARGV, $_-1, 2);
183 }
184 elsif($ARGV[$_-1]=~/,\Z/) {
185 $ARGV[$_-1].=$ARGV[$_];
186 splice(@ARGV, $_, 1);
187 }
188 elsif($ARGV[$_]=~/\A,/
189 and $ARGV[$_] ne ",") {
190 $ARGV[$_-1].=$ARGV[$_];
191 splice(@ARGV, $_, 1);
192 }
193}
194
195GetOptions("h|help!" => \$Help,
196 "i|info!" => \$InfoMsg,
197 "v|version!" => \$ShowVersion,
198 "dumpversion!" => \$DumpVersion,
199# general options
200 "l|lib|library=s" => \$TargetLibraryName,
201 "d1|old|o=s" => \$Descriptor{1}{"Path"},
202 "d2|new|n=s" => \$Descriptor{2}{"Path"},
203 "dump|dump-abi|dump_abi=s" => \$DumpAPI,
204 "old-dumps!" => \$UseOldDumps,
205# extra options
206 "d|descriptor-template!" => \$GenerateTemplate,
207 "app|application=s" => \$AppPath,
208 "static-libs!" => \$UseStaticLibs,
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +0400209 "cross-gcc|gcc-path=s" => \$CrossGcc,
210 "cross-prefix|gcc-prefix=s" => \$CrossPrefix,
Andrey Ponomarenkoab282102012-03-11 11:57:02 +0400211 "sysroot=s" => \$SystemRoot_Opt,
212 "v1|version1|vnum=s" => \$TargetVersion{1},
213 "v2|version2=s" => \$TargetVersion{2},
214 "s|strict!" => \$StrictCompat,
215 "symbols-list=s" => \$SymbolsListPath,
216 "skip-headers=s" => \$SkipHeadersPath,
217 "headers-only|headers_only!" => \$CheckHeadersOnly_Opt,
218 "objects-only!" => \$CheckObjectsOnly_Opt,
219 "check-impl|check-implementation!" => \$CheckImpl,
220 "show-retval!" => \$ShowRetVal,
221 "use-dumps!" => \$UseDumps,
222 "nostdinc!" => \$NoStdInc,
223 "dump-system=s" => \$DumpSystem,
224 "sysinfo=s" => \$TargetSysInfo,
225 "cmp-systems!" => \$CmpSystems,
226 "libs-list=s" => \$TargetLibsPath,
227 "headers-list=s" => \$TargetHeadersPath,
228 "header=s" => \$TargetHeader,
229 "ext|extended!" => \$ExtendedCheck,
230 "q|quiet!" => \$Quiet,
231 "stdout!" => \$StdOut,
232 "report-format=s" => \$ReportFormat,
Andrey Ponomarenko5c09ef32012-06-14 18:17:33 +0400233 "dump-format=s" => \$DumpFormat,
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +0400234 "xml!" => \$UseXML,
Andrey Ponomarenkoab282102012-03-11 11:57:02 +0400235 "lang=s" => \$UserLang,
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +0400236 "binary|bin|abi!" => \$BinaryOnly,
237 "source|src|api!" => \$SourceOnly,
Andrey Ponomarenkoab282102012-03-11 11:57:02 +0400238# other options
239 "test!" => \$TestTool,
240 "test-dump!" => \$TestDump,
241 "debug!" => \$Debug,
Andrey Ponomarenko07aea072012-11-12 16:15:07 +0400242 "cpp-compatible!" => \$CppCompat,
Andrey Ponomarenkoab282102012-03-11 11:57:02 +0400243 "p|params=s" => \$ParamNamesPath,
244 "relpath1|relpath=s" => \$RelativeDirectory{1},
245 "relpath2=s" => \$RelativeDirectory{2},
246 "dump-path=s" => \$OutputDumpPath,
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +0400247 "sort!" => \$SortDump,
Andrey Ponomarenkoab282102012-03-11 11:57:02 +0400248 "report-path=s" => \$OutputReportPath,
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +0400249 "bin-report-path=s" => \$BinaryReportPath,
250 "src-report-path=s" => \$SourceReportPath,
Andrey Ponomarenkoab282102012-03-11 11:57:02 +0400251 "log-path=s" => \$LoggingPath,
252 "log1-path=s" => \$OutputLogPath{1},
253 "log2-path=s" => \$OutputLogPath{2},
254 "logging-mode=s" => \$LogMode,
255 "list-affected!" => \$ListAffected,
256 "l-full|lib-full=s" => \$TargetLibraryFName,
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +0400257 "component=s" => \$TargetComponent_Opt,
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +0400258 "b|browse=s" => \$Browse,
Andrey Ponomarenko07aea072012-11-12 16:15:07 +0400259 "open!" => \$OpenReport,
260 "extra-info=s" => \$ExtraInfo
Andrey Ponomarenkoab282102012-03-11 11:57:02 +0400261) or ERR_MESSAGE();
262
263sub ERR_MESSAGE()
264{
265 printMsg("INFO", "\n".$ShortUsage);
266 exit($ERROR_CODE{"Error"});
267}
268
269my $LIB_TYPE = $UseStaticLibs?"static":"dynamic";
270my $SLIB_TYPE = $LIB_TYPE;
271if($OSgroup!~/macos|windows/ and $SLIB_TYPE eq "dynamic")
272{ # show as "shared" library
273 $SLIB_TYPE = "shared";
274}
275my $LIB_EXT = getLIB_EXT($OSgroup);
276my $AR_EXT = getAR_EXT($OSgroup);
277my $BYTE_SIZE = 8;
278my $COMMON_LOG_PATH = "logs/run.log";
279
280my $HelpMessage="
281NAME:
282 ABI Compliance Checker ($CmdName)
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +0400283 Check backward compatibility of a C/C++ library API
Andrey Ponomarenkoab282102012-03-11 11:57:02 +0400284
285DESCRIPTION:
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +0400286 ABI Compliance Checker (ACC) is a tool for checking backward binary and
287 source-level compatibility of a $SLIB_TYPE C/C++ library. The tool checks
288 header files and $SLIB_TYPE libraries (*.$LIB_EXT) of old and new versions and
289 analyzes changes in API and ABI (ABI=API+compiler ABI) that may break binary
290 and/or source-level compatibility: changes in calling stack, v-table changes,
291 removed symbols, renamed fields, etc. Binary incompatibility may result in
292 crashing or incorrect behavior of applications built with an old version of
293 a library if they run on a new one. Source incompatibility may result in
294 recompilation errors with a new library version.
Andrey Ponomarenkoab282102012-03-11 11:57:02 +0400295
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +0400296 The tool is intended for developers of software libraries and maintainers
297 of operating systems who are interested in ensuring backward compatibility,
298 i.e. allow old applications to run or to be recompiled with newer library
299 versions.
300
301 Also the tool can be used by ISVs for checking applications portability to
302 new library versions. Found issues can be taken into account when adapting
303 the application to a new library version.
Andrey Ponomarenkoab282102012-03-11 11:57:02 +0400304
305 This tool is free software: you can redistribute it and/or modify it
306 under the terms of the GNU LGPL or GNU GPL.
307
308USAGE:
309 $CmdName [options]
310
311EXAMPLE:
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +0400312 $CmdName -lib NAME -old OLD.xml -new NEW.xml
Andrey Ponomarenkoab282102012-03-11 11:57:02 +0400313
314 OLD.xml and NEW.xml are XML-descriptors:
315
316 <version>
317 1.0
318 </version>
319
320 <headers>
321 /path1/to/header(s)/
322 /path2/to/header(s)/
323 ...
324 </headers>
325
326 <libs>
327 /path1/to/library(ies)/
328 /path2/to/library(ies)/
329 ...
330 </libs>
331
332INFORMATION OPTIONS:
333 -h|-help
334 Print this help.
335
336 -i|-info
337 Print complete info.
338
339 -v|-version
340 Print version information.
341
342 -dumpversion
343 Print the tool version ($TOOL_VERSION) and don't do anything else.
344
345GENERAL OPTIONS:
Andrey Ponomarenko07aea072012-11-12 16:15:07 +0400346 -l|-lib|-library NAME
Andrey Ponomarenkoab282102012-03-11 11:57:02 +0400347 Library name (without version).
Andrey Ponomarenkoab282102012-03-11 11:57:02 +0400348
Andrey Ponomarenko07aea072012-11-12 16:15:07 +0400349 -d1|-old|-o PATH
Andrey Ponomarenkoab282102012-03-11 11:57:02 +0400350 Descriptor of 1st (old) library version.
351 It may be one of the following:
352
353 1. XML-descriptor (VERSION.xml file):
354
355 <version>
356 1.0
357 </version>
358
359 <headers>
360 /path1/to/header(s)/
361 /path2/to/header(s)/
362 ...
363 </headers>
364
365 <libs>
366 /path1/to/library(ies)/
367 /path2/to/library(ies)/
368 ...
369 </libs>
370
371 ... (XML-descriptor template
372 can be generated by -d option)
373
374 2. ABI dump generated by -dump option
375 3. Directory with headers and/or $SLIB_TYPE libraries
376 4. Single header file
377 5. Single $SLIB_TYPE library
378 6. Comma separated list of headers and/or libraries
379
380 If you are using an 2-6 descriptor types then you should
381 specify version numbers with -v1 <num> and -v2 <num> options too.
382
383 For more information, please see:
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +0400384 http://ispras.linuxbase.org/index.php/Library_Descriptor
Andrey Ponomarenkoab282102012-03-11 11:57:02 +0400385
Andrey Ponomarenko07aea072012-11-12 16:15:07 +0400386 -d2|-new|-n PATH
Andrey Ponomarenkoab282102012-03-11 11:57:02 +0400387 Descriptor of 2nd (new) library version.
388
Andrey Ponomarenko07aea072012-11-12 16:15:07 +0400389 -dump|-dump-abi PATH
Andrey Ponomarenkoab282102012-03-11 11:57:02 +0400390 Dump library ABI to gzipped TXT format file. You can transfer it
391 anywhere and pass instead of the descriptor. Also it can be used
392 for debugging the tool. Compatible dump versions: ".majorVersion($ABI_DUMP_VERSION).".0<=V<=$ABI_DUMP_VERSION
393
394 -old-dumps
395 Enable support for old-version ABI dumps ($OLDEST_SUPPORTED_VERSION<=V<".majorVersion($ABI_DUMP_VERSION).".0).\n";
396
397sub HELP_MESSAGE() {
398 printMsg("INFO", $HelpMessage."
399MORE INFO:
400 $CmdName --info\n");
401}
402
403sub INFO_MESSAGE()
404{
405 printMsg("INFO", "$HelpMessage
406EXTRA OPTIONS:
407 -d|-descriptor-template
408 Create XML-descriptor template ./VERSION.xml
409
Andrey Ponomarenko07aea072012-11-12 16:15:07 +0400410 -app|-application PATH
Andrey Ponomarenkoab282102012-03-11 11:57:02 +0400411 This option allows to specify the application that should be checked
412 for portability to the new library version.
413
414 -static-libs
415 Check static libraries instead of the shared ones. The <libs> section
416 of the XML-descriptor should point to static libraries location.
417
Andrey Ponomarenko07aea072012-11-12 16:15:07 +0400418 -cross-gcc|-gcc-path PATH
Andrey Ponomarenkoab282102012-03-11 11:57:02 +0400419 Path to the cross GCC compiler to use instead of the usual (host) GCC.
420
Andrey Ponomarenko07aea072012-11-12 16:15:07 +0400421 -cross-prefix|-gcc-prefix PREFIX
Andrey Ponomarenkoab282102012-03-11 11:57:02 +0400422 GCC toolchain prefix.
423
Andrey Ponomarenko07aea072012-11-12 16:15:07 +0400424 -sysroot DIR
Andrey Ponomarenkoab282102012-03-11 11:57:02 +0400425 Specify the alternative root directory. The tool will search for include
Andrey Ponomarenko07aea072012-11-12 16:15:07 +0400426 paths in the DIR/usr/include and DIR/usr/lib directories.
Andrey Ponomarenkoab282102012-03-11 11:57:02 +0400427
Andrey Ponomarenko07aea072012-11-12 16:15:07 +0400428 -v1|-version1 NUM
Andrey Ponomarenkoab282102012-03-11 11:57:02 +0400429 Specify 1st library version outside the descriptor. This option is needed
430 if you have prefered an alternative descriptor type (see -d1 option).
431
432 In general case you should specify it in the XML-descriptor:
433 <version>
434 VERSION
435 </version>
436
Andrey Ponomarenko07aea072012-11-12 16:15:07 +0400437 -v2|-version2 NUM
Andrey Ponomarenkoab282102012-03-11 11:57:02 +0400438 Specify 2nd library version outside the descriptor.
439
440 -s|-strict
441 Treat all compatibility warnings as problems. Add a number of \"Low\"
442 severity problems to the return value of the tool.
443
444 -headers-only
445 Check header files without $SLIB_TYPE libraries. It is easy to run, but may
446 provide a low quality compatibility report with false positives and
447 without detecting of added/removed symbols.
448
449 Alternatively you can write \"none\" word to the <libs> section
450 in the XML-descriptor:
451 <libs>
452 none
453 </libs>
454
455 -objects-only
456 Check $SLIB_TYPE libraries without header files. It is easy to run, but may
457 provide a low quality compatibility report with false positives and
458 without analysis of changes in parameters and data types.
459
460 Alternatively you can write \"none\" word to the <headers> section
461 in the XML-descriptor:
462 <headers>
463 none
464 </headers>
465
466 -check-impl|-check-implementation
467 Compare canonified disassembled binary code of $SLIB_TYPE libraries to
468 detect changes in the implementation. Add \'Problems with Implementation\'
469 section to the report.
470
471 -show-retval
472 Show the symbol's return type in the report.
473
Andrey Ponomarenko07aea072012-11-12 16:15:07 +0400474 -symbols-list PATH
Andrey Ponomarenkoab282102012-03-11 11:57:02 +0400475 This option allows to specify a file with a list of symbols (mangled
476 names in C++) that should be checked, other symbols will not be checked.
477
Andrey Ponomarenko07aea072012-11-12 16:15:07 +0400478 -skip-headers PATH
Andrey Ponomarenkoab282102012-03-11 11:57:02 +0400479 The file with the list of header files, that should not be checked.
480
481 -use-dumps
482 Make dumps for two versions of a library and compare dumps. This should
483 increase the performance of the tool and decrease the system memory usage.
484
485 -nostdinc
486 Do not search the GCC standard system directories for header files.
487
Andrey Ponomarenko07aea072012-11-12 16:15:07 +0400488 -dump-system NAME -sysroot DIR
489 Find all the shared libraries and header files in DIR directory,
Andrey Ponomarenkoab282102012-03-11 11:57:02 +0400490 create XML descriptors and make ABI dumps for each library. The result
491 set of ABI dumps can be compared (--cmp-systems) with the other one
492 created for other version of operating system in order to check them for
493 compatibility. Do not forget to specify -cross-gcc option if your target
494 system requires some specific version of GCC compiler (different from
495 the host GCC). The system ABI dump will be generated to:
Andrey Ponomarenko07aea072012-11-12 16:15:07 +0400496 sys_dumps/NAME/ARCH
Andrey Ponomarenkoab282102012-03-11 11:57:02 +0400497
Andrey Ponomarenko07aea072012-11-12 16:15:07 +0400498 -dump-system DESCRIPTOR.xml
Andrey Ponomarenkoab282102012-03-11 11:57:02 +0400499 The same as the previous option but takes an XML descriptor of the target
500 system as input, where you should describe it:
501
502 /* Primary sections */
503
504 <name>
505 /* Name of the system */
506 </name>
507
508 <headers>
509 /* The list of paths to header files and/or
510 directories with header files, one per line */
511 </headers>
512
513 <libs>
514 /* The list of paths to shared libraries and/or
515 directories with shared libraries, one per line */
516 </libs>
517
518 /* Optional sections */
519
520 <search_headers>
521 /* List of directories to be searched
522 for header files to automatically
523 generate include paths, one per line */
524 </search_headers>
525
526 <search_libs>
527 /* List of directories to be searched
528 for shared libraries to resolve
529 dependencies, one per line */
530 </search_libs>
531
532 <tools>
533 /* List of directories with tools used
534 for analysis (GCC toolchain), one per line */
535 </tools>
536
537 <cross_prefix>
538 /* GCC toolchain prefix.
539 Examples:
540 arm-linux-gnueabi
541 arm-none-symbianelf */
542 </cross_prefix>
543
544 <gcc_options>
545 /* Additional GCC options, one per line */
546 </gcc_options>
547
Andrey Ponomarenko07aea072012-11-12 16:15:07 +0400548 -sysinfo DIR
Andrey Ponomarenkoab282102012-03-11 11:57:02 +0400549 This option may be used with -dump-system to dump ABI of operating
550 systems and configure the dumping process.
551 Default:
552 modules/Targets/{unix, symbian, windows}
553
Andrey Ponomarenko07aea072012-11-12 16:15:07 +0400554 -cmp-systems -d1 sys_dumps/NAME1/ARCH -d2 sys_dumps/NAME2/ARCH
Andrey Ponomarenkoab282102012-03-11 11:57:02 +0400555 Compare two system ABI dumps. Create compatibility reports for each
556 library and the common HTML report including the summary of test
557 results for all checked libraries. Report will be generated to:
Andrey Ponomarenko07aea072012-11-12 16:15:07 +0400558 sys_compat_reports/NAME1_to_NAME2/ARCH
Andrey Ponomarenkoab282102012-03-11 11:57:02 +0400559
Andrey Ponomarenko07aea072012-11-12 16:15:07 +0400560 -libs-list PATH
Andrey Ponomarenkoab282102012-03-11 11:57:02 +0400561 The file with a list of libraries, that should be dumped by
562 the -dump-system option or should be checked by the -cmp-systems option.
563
Andrey Ponomarenko07aea072012-11-12 16:15:07 +0400564 -header NAME
Andrey Ponomarenkoab282102012-03-11 11:57:02 +0400565 Check/Dump ABI of this header only.
566
Andrey Ponomarenko07aea072012-11-12 16:15:07 +0400567 -headers-list PATH
Andrey Ponomarenkoab282102012-03-11 11:57:02 +0400568 The file with a list of headers, that should be checked/dumped.
569
570 -ext|-extended
571 If your library A is supposed to be used by other library B and you
572 want to control the ABI of B, then you should enable this option. The
573 tool will check for changes in all data types, even if they are not
574 used by any function in the library A. Such data types are not part
575 of the A library ABI, but may be a part of the ABI of the B library.
576
577 The short scheme is:
578 app C (broken) -> lib B (broken ABI) -> lib A (stable ABI)
579
580 -q|-quiet
581 Print all messages to the file instead of stdout and stderr.
582 Default path (can be changed by -log-path option):
583 $COMMON_LOG_PATH
584
585 -stdout
586 Print analysis results (compatibility reports and ABI dumps) to stdout
587 instead of creating a file. This would allow piping data to other programs.
588
Andrey Ponomarenko07aea072012-11-12 16:15:07 +0400589 -report-format FMT
Andrey Ponomarenkoab282102012-03-11 11:57:02 +0400590 Change format of compatibility report.
591 Formats:
592 htm - HTML format (default)
593 xml - XML format
594
Andrey Ponomarenko07aea072012-11-12 16:15:07 +0400595 -dump-format FMT
Andrey Ponomarenko5c09ef32012-06-14 18:17:33 +0400596 Change format of ABI dump.
597 Formats:
598 perl - Data::Dumper format (default)
599 xml - XML format
600
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +0400601 -xml
Andrey Ponomarenko5c09ef32012-06-14 18:17:33 +0400602 Alias for: --report-format=xml or --dump-format=xml
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +0400603
Andrey Ponomarenko07aea072012-11-12 16:15:07 +0400604 -lang LANG
Andrey Ponomarenkoab282102012-03-11 11:57:02 +0400605 Set library language (C or C++). You can use this option if the tool
606 cannot auto-detect a language. This option may be useful for checking
607 C-library headers (--lang=C) in --headers-only or --extended modes.
608
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +0400609 -binary|-bin|-abi
610 Show \"Binary\" compatibility problems only.
611 Generate report to:
Andrey Ponomarenko07aea072012-11-12 16:15:07 +0400612 compat_reports/LIB_NAME/V1_to_V2/abi_compat_report.html
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +0400613
614 -source|-src|-api
615 Show \"Source\" compatibility problems only.
616 Generate report to:
Andrey Ponomarenko07aea072012-11-12 16:15:07 +0400617 compat_reports/LIB_NAME/V1_to_V2/src_compat_report.html
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +0400618
Andrey Ponomarenkoab282102012-03-11 11:57:02 +0400619OTHER OPTIONS:
620 -test
621 Run internal tests. Create two binary incompatible versions of a sample
622 library and run the tool to check them for compatibility. This option
623 allows to check if the tool works correctly in the current environment.
624
625 -test-dump
626 Test ability to create, read and compare ABI dumps.
627
628 -debug
629 Debugging mode. Print debug info on the screen. Save intermediate
630 analysis stages in the debug directory:
Andrey Ponomarenko07aea072012-11-12 16:15:07 +0400631 debug/LIB_NAME/VERSION/
Andrey Ponomarenkoab282102012-03-11 11:57:02 +0400632
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +0400633 Also consider using --dump option for debugging the tool.
634
Andrey Ponomarenkoab282102012-03-11 11:57:02 +0400635 -cpp-compatible
Andrey Ponomarenko07aea072012-11-12 16:15:07 +0400636 If your header files are written in C language and can be compiled
637 by the G++ compiler (i.e. don't use C++ keywords), then you can tell
638 the tool about this and speedup the analysis.
Andrey Ponomarenkoab282102012-03-11 11:57:02 +0400639
Andrey Ponomarenko07aea072012-11-12 16:15:07 +0400640 -p|-params PATH
Andrey Ponomarenkoab282102012-03-11 11:57:02 +0400641 Path to file with the function parameter names. It can be used
642 for improving report view if the library header files have no
643 parameter names. File format:
644
645 func1;param1;param2;param3 ...
646 func2;param1;param2;param3 ...
647 ...
648
Andrey Ponomarenko07aea072012-11-12 16:15:07 +0400649 -relpath PATH
650 Replace {RELPATH} macros to PATH in the XML-descriptor used
Andrey Ponomarenkoab282102012-03-11 11:57:02 +0400651 for dumping the library ABI (see -dump option).
652
Andrey Ponomarenko07aea072012-11-12 16:15:07 +0400653 -relpath1 PATH
654 Replace {RELPATH} macros to PATH in the 1st XML-descriptor (-d1).
Andrey Ponomarenkoab282102012-03-11 11:57:02 +0400655
Andrey Ponomarenko07aea072012-11-12 16:15:07 +0400656 -relpath2 PATH
657 Replace {RELPATH} macros to PATH in the 2nd XML-descriptor (-d2).
Andrey Ponomarenkoab282102012-03-11 11:57:02 +0400658
Andrey Ponomarenko07aea072012-11-12 16:15:07 +0400659 -dump-path PATH
Andrey Ponomarenko5c09ef32012-06-14 18:17:33 +0400660 Specify a *.abi.$AR_EXT or *.abi file path where to generate an ABI dump.
Andrey Ponomarenkoab282102012-03-11 11:57:02 +0400661 Default:
Andrey Ponomarenko07aea072012-11-12 16:15:07 +0400662 abi_dumps/LIB_NAME/LIB_NAME_VERSION.abi.$AR_EXT
Andrey Ponomarenkoab282102012-03-11 11:57:02 +0400663
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +0400664 -sort
665 Enable sorting of data in ABI dumps.
666
Andrey Ponomarenko07aea072012-11-12 16:15:07 +0400667 -report-path PATH
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +0400668 Path to compatibility report.
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +0400669 Default:
Andrey Ponomarenko07aea072012-11-12 16:15:07 +0400670 compat_reports/LIB_NAME/V1_to_V2/compat_report.html
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +0400671
Andrey Ponomarenko07aea072012-11-12 16:15:07 +0400672 -bin-report-path PATH
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +0400673 Path to \"Binary\" compatibility report.
Andrey Ponomarenkoab282102012-03-11 11:57:02 +0400674 Default:
Andrey Ponomarenko07aea072012-11-12 16:15:07 +0400675 compat_reports/LIB_NAME/V1_to_V2/abi_compat_report.html
Andrey Ponomarenkoab282102012-03-11 11:57:02 +0400676
Andrey Ponomarenko07aea072012-11-12 16:15:07 +0400677 -src-report-path PATH
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +0400678 Path to \"Source\" compatibility report.
679 Default:
Andrey Ponomarenko07aea072012-11-12 16:15:07 +0400680 compat_reports/LIB_NAME/V1_to_V2/src_compat_report.html
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +0400681
Andrey Ponomarenko07aea072012-11-12 16:15:07 +0400682 -log-path PATH
Andrey Ponomarenkoab282102012-03-11 11:57:02 +0400683 Log path for all messages.
684 Default:
Andrey Ponomarenko07aea072012-11-12 16:15:07 +0400685 logs/LIB_NAME/VERSION/log.txt
Andrey Ponomarenkoab282102012-03-11 11:57:02 +0400686
Andrey Ponomarenko07aea072012-11-12 16:15:07 +0400687 -log1-path PATH
Andrey Ponomarenkoab282102012-03-11 11:57:02 +0400688 Log path for 1st version of a library.
689 Default:
Andrey Ponomarenko07aea072012-11-12 16:15:07 +0400690 logs/LIB_NAME/V1/log.txt
Andrey Ponomarenkoab282102012-03-11 11:57:02 +0400691
Andrey Ponomarenko07aea072012-11-12 16:15:07 +0400692 -log2-path PATH
Andrey Ponomarenkoab282102012-03-11 11:57:02 +0400693 Log path for 2nd version of a library.
694 Default:
Andrey Ponomarenko07aea072012-11-12 16:15:07 +0400695 logs/LIB_NAME/V2/log.txt
Andrey Ponomarenkoab282102012-03-11 11:57:02 +0400696
Andrey Ponomarenko07aea072012-11-12 16:15:07 +0400697 -logging-mode MODE
Andrey Ponomarenkoab282102012-03-11 11:57:02 +0400698 Change logging mode.
699 Modes:
700 w - overwrite old logs (default)
701 a - append old logs
702 n - do not write any logs
703
704 -list-affected
705 Generate file with the list of incompatible
706 symbols beside the HTML compatibility report.
707 Use 'c++filt \@file' command from GNU binutils
708 to unmangle C++ symbols in the generated file.
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +0400709 Default names:
Andrey Ponomarenkoab282102012-03-11 11:57:02 +0400710 abi_affected.txt
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +0400711 src_affected.txt
Andrey Ponomarenkoab282102012-03-11 11:57:02 +0400712
Andrey Ponomarenko07aea072012-11-12 16:15:07 +0400713 -component NAME
Andrey Ponomarenkoab282102012-03-11 11:57:02 +0400714 The component name in the title and summary of the HTML report.
715 Default:
716 library
717
Andrey Ponomarenko07aea072012-11-12 16:15:07 +0400718 -l-full|-lib-full NAME
719 Change library name in the report title to NAME. By default
Andrey Ponomarenkoab282102012-03-11 11:57:02 +0400720 will be displayed a name specified by -l option.
721
Andrey Ponomarenko07aea072012-11-12 16:15:07 +0400722 -b|-browse PROGRAM
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +0400723 Open report(s) in the browser (firefox, opera, etc.).
724
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +0400725 -open
726 Open report(s) in the default browser.
Andrey Ponomarenko07aea072012-11-12 16:15:07 +0400727
728 -extra-info DIR
729 Dump extra info to DIR.
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +0400730
Andrey Ponomarenkoab282102012-03-11 11:57:02 +0400731REPORT:
732 Compatibility report will be generated to:
Andrey Ponomarenko07aea072012-11-12 16:15:07 +0400733 compat_reports/LIB_NAME/V1_to_V2/compat_report.html
Andrey Ponomarenkoab282102012-03-11 11:57:02 +0400734
735 Log will be generated to:
Andrey Ponomarenko07aea072012-11-12 16:15:07 +0400736 logs/LIB_NAME/V1/log.txt
737 logs/LIB_NAME/V2/log.txt
Andrey Ponomarenkoab282102012-03-11 11:57:02 +0400738
739EXIT CODES:
740 0 - Compatible. The tool has run without any errors.
741 non-zero - Incompatible or the tool has run with errors.
742
743REPORT BUGS TO:
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +0400744 Andrey Ponomarenko <aponomarenko\@rosalab.ru>
Andrey Ponomarenkoab282102012-03-11 11:57:02 +0400745
746MORE INFORMATION:
747 ".$HomePage{"Wiki"}."
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +0400748 ".$HomePage{"Dev1"}."\n");
Andrey Ponomarenkoab282102012-03-11 11:57:02 +0400749}
750
751my $DescriptorTemplate = "
752<?xml version=\"1.0\" encoding=\"utf-8\"?>
753<descriptor>
754
755/* Primary sections */
756
757<version>
758 /* Version of the library */
759</version>
760
761<headers>
762 /* The list of paths to header files and/or
763 directories with header files, one per line */
764</headers>
765
766<libs>
767 /* The list of paths to shared libraries (*.$LIB_EXT) and/or
768 directories with shared libraries, one per line */
769</libs>
770
771/* Optional sections */
772
773<include_paths>
774 /* The list of include paths that will be provided
775 to GCC to compile library headers, one per line.
776 NOTE: If you define this section then the tool
777 will not automatically generate include paths */
778</include_paths>
779
780<add_include_paths>
781 /* The list of include paths that will be added
782 to the automatically generated include paths, one per line */
783</add_include_paths>
784
785<skip_include_paths>
786 /* The list of include paths that will be removed from the
787 list of automatically generated include paths, one per line */
788</skip_include_paths>
789
790<gcc_options>
791 /* Additional GCC options, one per line */
792</gcc_options>
793
794<include_preamble>
795 /* The list of header files that will be
796 included before other headers, one per line.
797 Examples:
798 1) tree.h for libxml2
799 2) ft2build.h for freetype2 */
800</include_preamble>
801
802<defines>
803 /* The list of defines that will be added at the
804 headers compiling stage, one per line:
805 #define A B
806 #define C D */
807</defines>
808
Andrey Ponomarenkoa01311b2012-06-08 17:20:02 +0400809<add_namespaces>
810 /* The list of namespaces that should be added to the alanysis
811 if the tool cannot find them automatically, one per line */
812</add_namespaces>
813
Andrey Ponomarenkoab282102012-03-11 11:57:02 +0400814<skip_types>
815 /* The list of data types, that
816 should not be checked, one per line */
817</skip_types>
818
819<skip_symbols>
820 /* The list of functions (mangled/symbol names in C++),
821 that should not be checked, one per line */
822</skip_symbols>
823
824<skip_namespaces>
825 /* The list of C++ namespaces, that
826 should not be checked, one per line */
827</skip_namespaces>
828
829<skip_constants>
830 /* The list of constants that should
831 not be checked, one name per line */
832</skip_constants>
833
834<skip_headers>
835 /* The list of header files and/or directories
836 with header files that should not be checked, one per line */
837</skip_headers>
838
839<skip_libs>
840 /* The list of shared libraries and/or directories
841 with shared libraries that should not be checked, one per line */
842</skip_libs>
843
844<skip_including>
845 /* The list of header files, that cannot be included
846 directly (or non-self compiled ones), one per line */
847</skip_including>
848
849<search_headers>
850 /* List of directories to be searched
851 for header files to automatically
852 generate include paths, one per line. */
853</search_headers>
854
855<search_libs>
856 /* List of directories to be searched
857 for shared librariess to resolve
858 dependencies, one per line */
859</search_libs>
860
861<tools>
862 /* List of directories with tools used
863 for analysis (GCC toolchain), one per line */
864</tools>
865
866<cross_prefix>
867 /* GCC toolchain prefix.
868 Examples:
869 arm-linux-gnueabi
870 arm-none-symbianelf */
871</cross_prefix>
872
873</descriptor>";
874
875my %Operator_Indication = (
876 "not" => "~",
877 "assign" => "=",
878 "andassign" => "&=",
879 "orassign" => "|=",
880 "xorassign" => "^=",
881 "or" => "|",
882 "xor" => "^",
883 "addr" => "&",
884 "and" => "&",
885 "lnot" => "!",
886 "eq" => "==",
887 "ne" => "!=",
888 "lt" => "<",
889 "lshift" => "<<",
890 "lshiftassign" => "<<=",
891 "rshiftassign" => ">>=",
892 "call" => "()",
893 "mod" => "%",
894 "modassign" => "%=",
895 "subs" => "[]",
896 "land" => "&&",
897 "lor" => "||",
898 "rshift" => ">>",
899 "ref" => "->",
900 "le" => "<=",
901 "deref" => "*",
902 "mult" => "*",
903 "preinc" => "++",
904 "delete" => " delete",
905 "vecnew" => " new[]",
906 "vecdelete" => " delete[]",
907 "predec" => "--",
908 "postinc" => "++",
909 "postdec" => "--",
910 "plusassign" => "+=",
911 "plus" => "+",
912 "minus" => "-",
913 "minusassign" => "-=",
914 "gt" => ">",
915 "ge" => ">=",
916 "new" => " new",
917 "multassign" => "*=",
918 "divassign" => "/=",
919 "div" => "/",
920 "neg" => "-",
921 "pos" => "+",
922 "memref" => "->*",
923 "compound" => "," );
924
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +0400925my %UnknownOperator;
926
927my %NodeType= (
928 "array_type" => "Array",
929 "binfo" => "Other",
930 "boolean_type" => "Intrinsic",
931 "complex_type" => "Intrinsic",
932 "const_decl" => "Other",
933 "enumeral_type" => "Enum",
934 "field_decl" => "Other",
935 "function_decl" => "Other",
936 "function_type" => "FunctionType",
937 "identifier_node" => "Other",
938 "integer_cst" => "Other",
939 "integer_type" => "Intrinsic",
940 "method_type" => "MethodType",
941 "namespace_decl" => "Other",
942 "parm_decl" => "Other",
943 "pointer_type" => "Pointer",
944 "real_cst" => "Other",
945 "real_type" => "Intrinsic",
946 "record_type" => "Struct",
947 "reference_type" => "Ref",
948 "string_cst" => "Other",
949 "template_decl" => "Other",
950 "template_type_parm" => "Other",
951 "tree_list" => "Other",
952 "tree_vec" => "Other",
953 "type_decl" => "Other",
954 "union_type" => "Union",
955 "var_decl" => "Other",
956 "void_type" => "Intrinsic",
957 # "nop_expr" => "Other",
958 # "addr_expr" => "Other",
959 "offset_type" => "Other" );
960
Andrey Ponomarenkoab282102012-03-11 11:57:02 +0400961my %CppKeywords_C = map {$_=>1} (
962 # C++ 2003 keywords
963 "public",
964 "protected",
965 "private",
966 "default",
967 "template",
968 "new",
969 #"asm",
970 "dynamic_cast",
971 "auto",
972 "try",
973 "namespace",
974 "typename",
975 "using",
976 "reinterpret_cast",
977 "friend",
978 "class",
979 "virtual",
980 "const_cast",
981 "mutable",
982 "static_cast",
983 "export",
984 # C++0x keywords
985 "noexcept",
986 "nullptr",
987 "constexpr",
988 "static_assert",
989 "explicit",
990 # cannot be used as a macro name
991 # as it is an operator in C++
992 "and",
993 #"and_eq",
994 "not",
995 #"not_eq",
996 "or"
997 #"or_eq",
998 #"bitand",
999 #"bitor",
1000 #"xor",
1001 #"xor_eq",
1002 #"compl"
1003);
1004
1005my %CppKeywords_F = map {$_=>1} (
1006 "delete",
1007 "catch",
1008 "alignof",
1009 "thread_local",
1010 "decltype",
1011 "typeid"
1012);
1013
1014my %CppKeywords_O = map {$_=>1} (
1015 "bool",
1016 "register",
1017 "inline",
1018 "operator"
1019);
1020
1021my %CppKeywords_A = map {$_=>1} (
1022 "this",
1023 "throw"
1024);
1025
1026foreach (keys(%CppKeywords_C),
1027keys(%CppKeywords_F),
1028keys(%CppKeywords_O)) {
1029 $CppKeywords_A{$_}=1;
1030}
1031
1032# Header file extensions as described by gcc
1033my $HEADER_EXT = "h|hh|hp|hxx|hpp|h\\+\\+";
1034
1035my %IntrinsicMangling = (
1036 "void" => "v",
1037 "bool" => "b",
1038 "wchar_t" => "w",
1039 "char" => "c",
1040 "signed char" => "a",
1041 "unsigned char" => "h",
1042 "short" => "s",
1043 "unsigned short" => "t",
1044 "int" => "i",
1045 "unsigned int" => "j",
1046 "long" => "l",
1047 "unsigned long" => "m",
1048 "long long" => "x",
1049 "__int64" => "x",
1050 "unsigned long long" => "y",
1051 "__int128" => "n",
1052 "unsigned __int128" => "o",
1053 "float" => "f",
1054 "double" => "d",
1055 "long double" => "e",
1056 "__float80" => "e",
1057 "__float128" => "g",
1058 "..." => "z"
1059);
1060
1061my %StdcxxMangling = (
1062 "3std"=>"St",
1063 "3std9allocator"=>"Sa",
1064 "3std12basic_string"=>"Sb",
1065 "3std12basic_stringIcE"=>"Ss",
1066 "3std13basic_istreamIcE"=>"Si",
1067 "3std13basic_ostreamIcE"=>"So",
1068 "3std14basic_iostreamIcE"=>"Sd"
1069);
1070
Andrey Ponomarenko07aea072012-11-12 16:15:07 +04001071my $DEFAULT_STD_PARMS = "std::(allocator|less|char_traits|regex_traits)";
1072
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04001073my %ConstantSuffix = (
1074 "unsigned int"=>"u",
1075 "long"=>"l",
1076 "unsigned long"=>"ul",
1077 "long long"=>"ll",
1078 "unsigned long long"=>"ull"
1079);
1080
1081my %ConstantSuffixR =
1082reverse(%ConstantSuffix);
1083
1084my %OperatorMangling = (
1085 "~" => "co",
1086 "=" => "aS",
1087 "|" => "or",
1088 "^" => "eo",
1089 "&" => "an",#ad (addr)
1090 "==" => "eq",
1091 "!" => "nt",
1092 "!=" => "ne",
1093 "<" => "lt",
1094 "<=" => "le",
1095 "<<" => "ls",
1096 "<<=" => "lS",
1097 ">" => "gt",
1098 ">=" => "ge",
1099 ">>" => "rs",
1100 ">>=" => "rS",
1101 "()" => "cl",
1102 "%" => "rm",
1103 "[]" => "ix",
1104 "&&" => "aa",
1105 "||" => "oo",
1106 "*" => "ml",#de (deref)
1107 "++" => "pp",#
1108 "--" => "mm",#
1109 "new" => "nw",
1110 "delete" => "dl",
1111 "new[]" => "na",
1112 "delete[]" => "da",
1113 "+=" => "pL",
1114 "+" => "pl",#ps (pos)
1115 "-" => "mi",#ng (neg)
1116 "-=" => "mI",
1117 "*=" => "mL",
1118 "/=" => "dV",
1119 "&=" => "aN",
1120 "|=" => "oR",
1121 "%=" => "rM",
1122 "^=" => "eO",
1123 "/" => "dv",
1124 "->*" => "pm",
1125 "->" => "pt",#rf (ref)
1126 "," => "cm",
1127 "?" => "qu",
1128 "." => "dt",
1129 "sizeof"=> "sz"#st
1130);
1131
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04001132my %Intrinsic_Keywords = map {$_=>1} (
1133 "true",
1134 "false",
1135 "_Bool",
1136 "_Complex",
1137 "const",
1138 "int",
1139 "long",
1140 "void",
1141 "short",
1142 "float",
1143 "volatile",
1144 "restrict",
1145 "unsigned",
1146 "signed",
1147 "char",
1148 "double",
1149 "class",
1150 "struct",
1151 "union",
1152 "enum"
1153);
1154
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04001155my %GlibcHeader = map {$_=>1} (
1156 "aliases.h",
1157 "argp.h",
1158 "argz.h",
1159 "assert.h",
1160 "cpio.h",
1161 "ctype.h",
1162 "dirent.h",
1163 "envz.h",
1164 "errno.h",
1165 "error.h",
1166 "execinfo.h",
1167 "fcntl.h",
1168 "fstab.h",
1169 "ftw.h",
1170 "glob.h",
1171 "grp.h",
1172 "iconv.h",
1173 "ifaddrs.h",
1174 "inttypes.h",
1175 "langinfo.h",
1176 "limits.h",
1177 "link.h",
1178 "locale.h",
1179 "malloc.h",
1180 "math.h",
1181 "mntent.h",
1182 "monetary.h",
1183 "nl_types.h",
1184 "obstack.h",
1185 "printf.h",
1186 "pwd.h",
1187 "regex.h",
1188 "sched.h",
1189 "search.h",
1190 "setjmp.h",
1191 "shadow.h",
1192 "signal.h",
1193 "spawn.h",
1194 "stdarg.h",
1195 "stdint.h",
1196 "stdio.h",
1197 "stdlib.h",
1198 "string.h",
Andrey Ponomarenko9927e332012-10-19 10:50:48 +04001199 "strings.h",
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04001200 "tar.h",
1201 "termios.h",
1202 "time.h",
1203 "ulimit.h",
1204 "unistd.h",
1205 "utime.h",
1206 "wchar.h",
1207 "wctype.h",
1208 "wordexp.h" );
1209
1210my %GlibcDir = map {$_=>1} (
1211 "arpa",
1212 "bits",
1213 "gnu",
1214 "netinet",
1215 "net",
1216 "nfs",
1217 "rpc",
1218 "sys",
1219 "linux" );
1220
Andrey Ponomarenko9927e332012-10-19 10:50:48 +04001221my %WinHeaders = map {$_=>1} (
1222 "dos.h",
1223 "process.h",
1224 "winsock.h",
1225 "config-win.h",
1226 "mem.h",
1227 "windows.h",
1228 "winsock2.h",
1229 "crtdbg.h",
1230 "ws2tcpip.h"
1231);
1232
1233my %ObsoleteHeaders = map {$_=>1} (
1234 "iostream.h",
1235 "fstream.h"
1236);
1237
1238my %ConfHeaders = map {$_=>1} (
1239 "atomic",
1240 "conf.h",
1241 "config.h",
1242 "configure.h",
1243 "build.h",
1244 "setup.h"
1245);
1246
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04001247my %LocalIncludes = map {$_=>1} (
1248 "/usr/local/include",
1249 "/usr/local" );
1250
1251my %OS_AddPath=(
1252# These paths are needed if the tool cannot detect them automatically
1253 "macos"=>{
1254 "include"=>{
1255 "/Library"=>1,
1256 "/Developer/usr/include"=>1
1257 },
1258 "lib"=>{
1259 "/Library"=>1,
1260 "/Developer/usr/lib"=>1
1261 },
1262 "bin"=>{
1263 "/Developer/usr/bin"=>1
1264 }
1265 },
1266 "beos"=>{
1267 # Haiku has GCC 2.95.3 by default
1268 # try to find GCC>=3.0 in /boot/develop/abi
1269 "include"=>{
1270 "/boot/common"=>1,
1271 "/boot/develop"=>1},
1272 "lib"=>{
1273 "/boot/common/lib"=>1,
1274 "/boot/system/lib"=>1,
1275 "/boot/apps"=>1},
1276 "bin"=>{
1277 "/boot/common/bin"=>1,
1278 "/boot/system/bin"=>1,
1279 "/boot/develop/abi"=>1
1280 }
1281}
1282);
1283
1284my %Slash_Type=(
1285 "default"=>"/",
1286 "windows"=>"\\"
1287);
1288
1289my $SLASH = $Slash_Type{$OSgroup}?$Slash_Type{$OSgroup}:$Slash_Type{"default"};
1290
1291# Global Variables
1292my %COMMON_LANGUAGE=(
1293 1 => "C",
1294 2 => "C" );
1295
1296my $MAX_COMMAND_LINE_ARGUMENTS = 4096;
Andrey Ponomarenko9927e332012-10-19 10:50:48 +04001297my $MAX_CPPFILT_FILE_SIZE = 50000;
1298my $CPPFILT_SUPPORT_FILE;
1299
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04001300my (%WORD_SIZE, %CPU_ARCH, %GCC_VERSION);
1301
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04001302my $STDCXX_TESTING = 0;
1303my $GLIBC_TESTING = 0;
1304
1305my $CheckHeadersOnly = $CheckHeadersOnly_Opt;
1306my $CheckObjectsOnly = $CheckObjectsOnly_Opt;
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04001307my $TargetComponent;
1308
1309# Set Target Component Name
1310if($TargetComponent_Opt) {
1311 $TargetComponent = lc($TargetComponent_Opt);
1312}
1313else
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04001314{ # default: library
1315 # other components: header, system, ...
1316 $TargetComponent = "library";
1317}
1318
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04001319my $TOP_REF = "<a style='font-size:11px;' href='#Top'>to the top</a>";
1320
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04001321my $SystemRoot;
1322
1323my $MAIN_CPP_DIR;
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04001324my %RESULT;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04001325my %LOG_PATH;
1326my %DEBUG_PATH;
1327my %Cache;
1328my %LibInfo;
1329my $COMPILE_ERRORS = 0;
1330my %CompilerOptions;
1331my %CheckedDyLib;
1332my $TargetLibraryShortName = parse_libname($TargetLibraryName, "shortest", $OSgroup);
1333
1334# Constants (#defines)
1335my %Constants;
1336my %SkipConstants;
1337
1338# Types
1339my %TypeInfo;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04001340my %TemplateInstance;
Andrey Ponomarenko85043792012-05-14 16:48:07 +04001341my %TemplateDecl;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04001342my %SkipTypes = (
1343 "1"=>{},
1344 "2"=>{} );
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04001345my %CheckedTypes;
1346my %TName_Tid;
1347my %EnumMembName_Id;
1348my %NestedNameSpaces = (
1349 "1"=>{},
1350 "2"=>{} );
1351my %UsedType;
1352my %VirtualTable;
Andrey Ponomarenko16934472012-03-29 15:37:04 +04001353my %VirtualTable_Model;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04001354my %ClassVTable;
1355my %ClassVTable_Content;
1356my %VTableClass;
1357my %AllocableClass;
1358my %ClassMethods;
Andrey Ponomarenko16934472012-03-29 15:37:04 +04001359my %ClassNames;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04001360my %Class_SubClasses;
1361my %OverriddenMethods;
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04001362my $MAX_ID = 0;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04001363
1364# Typedefs
1365my %Typedef_BaseName;
1366my %Typedef_Tr;
1367my %Typedef_Eq;
1368my %StdCxxTypedef;
1369my %MissedTypedef;
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04001370my %MissedBase;
1371my %MissedBase_R;
Andrey Ponomarenko9927e332012-10-19 10:50:48 +04001372my %TypeTypedef;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04001373
1374# Symbols
1375my %SymbolInfo;
1376my %tr_name;
1377my %mangled_name_gcc;
1378my %mangled_name;
1379my %SkipSymbols = (
1380 "1"=>{},
1381 "2"=>{} );
1382my %SkipNameSpaces = (
1383 "1"=>{},
1384 "2"=>{} );
Andrey Ponomarenkoa01311b2012-06-08 17:20:02 +04001385my %AddNameSpaces = (
1386 "1"=>{},
1387 "2"=>{} );
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04001388my %SymbolsList;
1389my %SymbolsList_App;
1390my %CheckedSymbols;
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04001391my %Symbol_Library = (
1392 "1"=>{},
1393 "2"=>{} );
1394my %Library_Symbol = (
1395 "1"=>{},
1396 "2"=>{} );
1397my %DepSymbol_Library = (
1398 "1"=>{},
1399 "2"=>{} );
1400my %DepLibrary_Symbol = (
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04001401 "1"=>{},
1402 "2"=>{} );
1403my %MangledNames;
Andrey Ponomarenko9927e332012-10-19 10:50:48 +04001404my %Func_ShortName;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04001405my %AddIntParams;
1406my %Interface_Impl;
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04001407my %GlobalDataObject;
Andrey Ponomarenko07aea072012-11-12 16:15:07 +04001408my %WeakSymbols;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04001409
1410# Headers
1411my %Include_Preamble;
1412my %Registered_Headers;
1413my %HeaderName_Paths;
1414my %Header_Dependency;
1415my %Include_Neighbors;
1416my %Include_Paths;
1417my %INC_PATH_AUTODETECT = (
1418 "1"=>1,
1419 "2"=>1 );
1420my %Add_Include_Paths;
1421my %Skip_Include_Paths;
1422my %RegisteredDirs;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04001423my %Header_ErrorRedirect;
1424my %Header_Includes;
1425my %Header_ShouldNotBeUsed;
1426my %RecursiveIncludes;
1427my %Header_Include_Prefix;
1428my %SkipHeaders;
1429my %SkipHeadersList=(
1430 "1"=>{},
1431 "2"=>{} );
1432my %SkipLibs;
1433my %Include_Order;
1434my %TUnit_NameSpaces;
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +04001435my %TUnit_Classes;
Andrey Ponomarenko9927e332012-10-19 10:50:48 +04001436my %TUnit_Funcs;
1437my %TUnit_Vars;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04001438
Andrey Ponomarenko07aea072012-11-12 16:15:07 +04001439my %CppMode = (
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04001440 "1"=>0,
1441 "2"=>0 );
1442my %AutoPreambleMode = (
1443 "1"=>0,
1444 "2"=>0 );
1445my %MinGWMode = (
1446 "1"=>0,
1447 "2"=>0 );
Andrey Ponomarenko01117f12012-06-26 12:23:02 +04001448my %Cpp0xMode = (
1449 "1"=>0,
1450 "2"=>0 );
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04001451
1452# Shared Objects
Andrey Ponomarenko9927e332012-10-19 10:50:48 +04001453my %RegisteredObjects;
Andrey Ponomarenko07aea072012-11-12 16:15:07 +04001454my %RegisteredObjects_Short;
Andrey Ponomarenko9927e332012-10-19 10:50:48 +04001455my %RegisteredSONAMEs;
1456my %RegisteredObject_Dirs;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04001457
1458# System Objects
1459my %SystemObjects;
1460my %DefaultLibPaths;
Andrey Ponomarenko9927e332012-10-19 10:50:48 +04001461my %DyLib_DefaultPath;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04001462
1463# System Headers
1464my %SystemHeaders;
1465my %DefaultCppPaths;
1466my %DefaultGccPaths;
1467my %DefaultIncPaths;
1468my %DefaultCppHeader;
1469my %DefaultGccHeader;
1470my %UserIncPath;
1471
1472# Merging
1473my %CompleteSignature;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04001474my $Version;
1475my %AddedInt;
1476my %RemovedInt;
1477my %AddedInt_Virt;
1478my %RemovedInt_Virt;
1479my %VirtualReplacement;
1480my %ChangedTypedef;
1481my %CompatRules;
1482my %IncompleteRules;
1483my %UnknownRules;
Andrey Ponomarenko16934472012-03-29 15:37:04 +04001484my %VTableChanged_M;
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04001485my %ExtendedSymbols;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04001486my %ReturnedClass;
1487my %ParamClass;
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04001488my %SourceAlternative;
1489my %SourceAlternative_B;
1490my %SourceReplacement;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04001491
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +04001492# Calling Conventions
1493my %UseConv_Real = (
1494 "1"=>0,
1495 "2"=>0 );
1496
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04001497# OS Compliance
1498my %TargetLibs;
1499my %TargetHeaders;
1500
1501# OS Specifics
1502my $OStarget = $OSgroup;
1503my %TargetTools;
1504
1505# Compliance Report
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04001506my %Type_MaxSeverity;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04001507
1508# Recursion locks
1509my @RecurLib;
1510my @RecurSymlink;
1511my @RecurTypes;
1512my @RecurInclude;
1513my @RecurConstant;
1514
1515# System
1516my %SystemPaths;
1517my %DefaultBinPaths;
1518my $GCC_PATH;
1519
1520# Symbols versioning
1521my %SymVer = (
1522 "1"=>{},
1523 "2"=>{} );
1524
1525# Problem descriptions
1526my %CompatProblems;
1527my %ProblemsWithConstants;
1528my %ImplProblems;
1529my %TotalAffected;
1530
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04001531# Reports
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04001532my $ContentID = 1;
1533my $ContentSpanStart = "<span class=\"section\" onclick=\"javascript:showContent(this, 'CONTENT_ID')\">\n";
1534my $ContentSpanStart_Affected = "<span class=\"section_affected\" onclick=\"javascript:showContent(this, 'CONTENT_ID')\">\n";
1535my $ContentSpanStart_Info = "<span class=\"section_info\" onclick=\"javascript:showContent(this, 'CONTENT_ID')\">\n";
1536my $ContentSpanEnd = "</span>\n";
1537my $ContentDivStart = "<div id=\"CONTENT_ID\" style=\"display:none;\">\n";
1538my $ContentDivEnd = "</div>\n";
1539my $Content_Counter = 0;
1540
Andrey Ponomarenko5c09ef32012-06-14 18:17:33 +04001541# XML Dump
1542my $TAG_ID = 0;
1543my $INDENT = " ";
1544
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04001545# Modes
1546my $JoinReport = 1;
1547my $DoubleReport = 0;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04001548
1549sub get_Modules()
1550{
1551 my $TOOL_DIR = get_dirname($0);
1552 if(not $TOOL_DIR)
1553 { # patch for MS Windows
1554 $TOOL_DIR = ".";
1555 }
1556 my @SEARCH_DIRS = (
1557 # tool's directory
1558 abs_path($TOOL_DIR),
1559 # relative path to modules
1560 abs_path($TOOL_DIR)."/../share/abi-compliance-checker",
1561 # system directory
1562 "ACC_MODULES_INSTALL_PATH"
1563 );
1564 foreach my $DIR (@SEARCH_DIRS)
1565 {
1566 if(not is_abs($DIR))
1567 { # relative path
1568 $DIR = abs_path($TOOL_DIR)."/".$DIR;
1569 }
1570 if(-d $DIR."/modules") {
1571 return $DIR."/modules";
1572 }
1573 }
1574 exitStatus("Module_Error", "can't find modules");
1575}
1576
Andrey Ponomarenko01117f12012-06-26 12:23:02 +04001577my %LoadedModules = ();
1578
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04001579sub loadModule($)
1580{
1581 my $Name = $_[0];
Andrey Ponomarenko01117f12012-06-26 12:23:02 +04001582 if(defined $LoadedModules{$Name}) {
1583 return;
1584 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04001585 my $Path = $MODULES_DIR."/Internals/$Name.pm";
1586 if(not -f $Path) {
1587 exitStatus("Module_Error", "can't access \'$Path\'");
1588 }
1589 require $Path;
Andrey Ponomarenko01117f12012-06-26 12:23:02 +04001590 $LoadedModules{$Name} = 1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04001591}
1592
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04001593sub showPos($)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04001594{
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04001595 my $Number = $_[0];
1596 if(not $Number) {
1597 $Number = 1;
1598 }
1599 else {
1600 $Number = int($Number)+1;
1601 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04001602 if($Number>3) {
1603 return $Number."th";
1604 }
1605 elsif($Number==1) {
1606 return "1st";
1607 }
1608 elsif($Number==2) {
1609 return "2nd";
1610 }
1611 elsif($Number==3) {
1612 return "3rd";
1613 }
1614 else {
1615 return $Number;
1616 }
1617}
1618
1619sub search_Tools($)
1620{
1621 my $Name = $_[0];
1622 return "" if(not $Name);
1623 if(my @Paths = keys(%TargetTools))
1624 {
1625 foreach my $Path (@Paths)
1626 {
1627 if(-f joinPath($Path, $Name)) {
1628 return joinPath($Path, $Name);
1629 }
1630 if($CrossPrefix)
1631 { # user-defined prefix (arm-none-symbianelf, ...)
1632 my $Candidate = joinPath($Path, $CrossPrefix."-".$Name);
1633 if(-f $Candidate) {
1634 return $Candidate;
1635 }
1636 }
1637 }
1638 }
1639 else {
1640 return "";
1641 }
1642}
1643
1644sub synch_Cmd($)
1645{
1646 my $Name = $_[0];
1647 if(not $GCC_PATH)
1648 { # GCC was not found yet
1649 return "";
1650 }
1651 my $Candidate = $GCC_PATH;
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04001652 if($Candidate=~s/\bgcc(|\.\w+)\Z/$Name$1/) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04001653 return $Candidate;
1654 }
1655 return "";
1656}
1657
1658sub get_CmdPath($)
1659{
1660 my $Name = $_[0];
1661 return "" if(not $Name);
1662 if(defined $Cache{"get_CmdPath"}{$Name}) {
1663 return $Cache{"get_CmdPath"}{$Name};
1664 }
1665 my %BinUtils = map {$_=>1} (
1666 "c++filt",
1667 "objdump",
1668 "readelf"
1669 );
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04001670 if($BinUtils{$Name} and $GCC_PATH)
1671 {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04001672 if(my $Dir = get_dirname($GCC_PATH)) {
1673 $TargetTools{$Dir}=1;
1674 }
1675 }
1676 my $Path = search_Tools($Name);
1677 if(not $Path and $OSgroup eq "windows") {
1678 $Path = search_Tools($Name.".exe");
1679 }
1680 if(not $Path and $BinUtils{$Name})
1681 {
1682 if($CrossPrefix)
1683 { # user-defined prefix
1684 $Path = search_Cmd($CrossPrefix."-".$Name);
1685 }
1686 }
1687 if(not $Path and $BinUtils{$Name})
1688 {
1689 if(my $Candidate = synch_Cmd($Name))
1690 { # synch with GCC
1691 if($Candidate=~/[\/\\]/)
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04001692 { # command path
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04001693 if(-f $Candidate) {
1694 $Path = $Candidate;
1695 }
1696 }
1697 elsif($Candidate = search_Cmd($Candidate))
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04001698 { # command name
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04001699 $Path = $Candidate;
1700 }
1701 }
1702 }
1703 if(not $Path) {
1704 $Path = search_Cmd($Name);
1705 }
1706 if(not $Path and $OSgroup eq "windows")
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04001707 { # search for *.exe file
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04001708 $Path=search_Cmd($Name.".exe");
1709 }
1710 if($Path=~/\s/) {
1711 $Path = "\"".$Path."\"";
1712 }
1713 return ($Cache{"get_CmdPath"}{$Name}=$Path);
1714}
1715
1716sub search_Cmd($)
1717{
1718 my $Name = $_[0];
1719 return "" if(not $Name);
1720 if(defined $Cache{"search_Cmd"}{$Name}) {
1721 return $Cache{"search_Cmd"}{$Name};
1722 }
1723 if(my $DefaultPath = get_CmdPath_Default($Name)) {
1724 return ($Cache{"search_Cmd"}{$Name} = $DefaultPath);
1725 }
1726 foreach my $Path (sort {length($a)<=>length($b)} keys(%{$SystemPaths{"bin"}}))
1727 {
1728 my $CmdPath = joinPath($Path,$Name);
1729 if(-f $CmdPath)
1730 {
1731 if($Name=~/gcc/) {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04001732 next if(not check_gcc($CmdPath, "3"));
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04001733 }
1734 return ($Cache{"search_Cmd"}{$Name} = $CmdPath);
1735 }
1736 }
1737 return ($Cache{"search_Cmd"}{$Name} = "");
1738}
1739
1740sub get_CmdPath_Default($)
1741{ # search in PATH
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04001742 return "" if(not $_[0]);
1743 if(defined $Cache{"get_CmdPath_Default"}{$_[0]}) {
1744 return $Cache{"get_CmdPath_Default"}{$_[0]};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04001745 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04001746 return ($Cache{"get_CmdPath_Default"}{$_[0]} = get_CmdPath_Default_I($_[0]));
1747}
1748
1749sub get_CmdPath_Default_I($)
1750{ # search in PATH
1751 my $Name = $_[0];
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04001752 if($Name=~/find/)
1753 { # special case: search for "find" utility
Andrey Ponomarenkoa01311b2012-06-08 17:20:02 +04001754 if(`find \"$TMP_DIR\" -maxdepth 0 2>\"$TMP_DIR/null\"`) {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04001755 return "find";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04001756 }
1757 }
1758 elsif($Name=~/gcc/) {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04001759 return check_gcc($Name, "3");
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04001760 }
1761 if(check_command($Name)) {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04001762 return $Name;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04001763 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04001764 if($OSgroup eq "windows")
1765 {
Andrey Ponomarenkoa01311b2012-06-08 17:20:02 +04001766 if(`$Name /? 2>\"$TMP_DIR/null\"`) {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04001767 return $Name;
1768 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04001769 }
1770 if($Name!~/which/)
1771 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04001772 if(my $WhichCmd = get_CmdPath("which"))
1773 {
Andrey Ponomarenkoa01311b2012-06-08 17:20:02 +04001774 if(`$WhichCmd $Name 2>\"$TMP_DIR/null\"`) {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04001775 return $Name;
1776 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04001777 }
1778 }
1779 foreach my $Path (sort {length($a)<=>length($b)} keys(%DefaultBinPaths))
1780 {
1781 if(-f $Path."/".$Name) {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04001782 return joinPath($Path,$Name);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04001783 }
1784 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04001785 return "";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04001786}
1787
1788sub clean_path($)
1789{
1790 my $Path = $_[0];
1791 $Path=~s/[\/\\]+\Z//g;
1792 return $Path;
1793}
1794
1795sub classifyPath($)
1796{
1797 my $Path = $_[0];
1798 if($Path=~/[\*\[]/)
1799 { # wildcard
1800 $Path=~s/\*/.*/g;
1801 $Path=~s/\\/\\\\/g;
1802 return ($Path, "Pattern");
1803 }
1804 elsif($Path=~/[\/\\]/)
1805 { # directory or relative path
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04001806 $Path=~s/[\/\\]+\Z//g;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04001807 return (path_format($Path, $OSgroup), "Path");
1808 }
1809 else {
1810 return ($Path, "Name");
1811 }
1812}
1813
1814sub readDescriptor($$)
1815{
1816 my ($LibVersion, $Content) = @_;
1817 return if(not $LibVersion);
1818 my $DName = $DumpAPI?"descriptor":"descriptor \"d$LibVersion\"";
1819 if(not $Content) {
1820 exitStatus("Error", "$DName is empty");
1821 }
1822 if($Content!~/\</) {
Andrey Ponomarenko5c09ef32012-06-14 18:17:33 +04001823 exitStatus("Error", "incorrect descriptor (see -d1 option)");
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04001824 }
1825 $Content=~s/\/\*(.|\n)+?\*\///g;
1826 $Content=~s/<\!--(.|\n)+?-->//g;
1827 $Descriptor{$LibVersion}{"Version"} = parseTag(\$Content, "version");
1828 if($TargetVersion{$LibVersion}) {
1829 $Descriptor{$LibVersion}{"Version"} = $TargetVersion{$LibVersion};
1830 }
1831 if(not $Descriptor{$LibVersion}{"Version"}) {
1832 exitStatus("Error", "version in the $DName is not specified (<version> section)");
1833 }
1834 if($Content=~/{RELPATH}/)
1835 {
1836 if(my $RelDir = $RelativeDirectory{$LibVersion}) {
1837 $Content =~ s/{RELPATH}/$RelDir/g;
1838 }
1839 else
1840 {
1841 my $NeedRelpath = $DumpAPI?"-relpath":"-relpath$LibVersion";
1842 exitStatus("Error", "you have not specified $NeedRelpath option, but the $DName contains {RELPATH} macro");
1843 }
1844 }
1845
1846 if(not $CheckObjectsOnly_Opt)
1847 {
1848 my $DHeaders = parseTag(\$Content, "headers");
1849 if(not $DHeaders) {
1850 exitStatus("Error", "header files in the $DName are not specified (<headers> section)");
1851 }
1852 elsif(lc($DHeaders) ne "none")
1853 { # append the descriptor headers list
1854 if($Descriptor{$LibVersion}{"Headers"})
1855 { # multiple descriptors
1856 $Descriptor{$LibVersion}{"Headers"} .= "\n".$DHeaders;
1857 }
1858 else {
1859 $Descriptor{$LibVersion}{"Headers"} = $DHeaders;
1860 }
1861 foreach my $Path (split(/\s*\n\s*/, $DHeaders))
1862 {
1863 if(not -e $Path) {
1864 exitStatus("Access_Error", "can't access \'$Path\'");
1865 }
1866 }
1867 }
1868 }
1869 if(not $CheckHeadersOnly_Opt)
1870 {
1871 my $DObjects = parseTag(\$Content, "libs");
1872 if(not $DObjects) {
1873 exitStatus("Error", "$SLIB_TYPE libraries in the $DName are not specified (<libs> section)");
1874 }
1875 elsif(lc($DObjects) ne "none")
1876 { # append the descriptor libraries list
1877 if($Descriptor{$LibVersion}{"Libs"})
1878 { # multiple descriptors
1879 $Descriptor{$LibVersion}{"Libs"} .= "\n".$DObjects;
1880 }
1881 else {
1882 $Descriptor{$LibVersion}{"Libs"} .= $DObjects;
1883 }
1884 foreach my $Path (split(/\s*\n\s*/, $DObjects))
1885 {
1886 if(not -e $Path) {
1887 exitStatus("Access_Error", "can't access \'$Path\'");
1888 }
1889 }
1890 }
1891 }
1892 foreach my $Path (split(/\s*\n\s*/, parseTag(\$Content, "search_headers")))
1893 {
1894 $Path = clean_path($Path);
1895 if(not -d $Path) {
1896 exitStatus("Access_Error", "can't access directory \'$Path\'");
1897 }
1898 $Path = path_format($Path, $OSgroup);
1899 $SystemPaths{"include"}{$Path}=1;
1900 }
1901 foreach my $Path (split(/\s*\n\s*/, parseTag(\$Content, "search_libs")))
1902 {
1903 $Path = clean_path($Path);
1904 if(not -d $Path) {
1905 exitStatus("Access_Error", "can't access directory \'$Path\'");
1906 }
1907 $Path = path_format($Path, $OSgroup);
1908 $SystemPaths{"lib"}{$Path}=1;
1909 }
1910 foreach my $Path (split(/\s*\n\s*/, parseTag(\$Content, "tools")))
1911 {
1912 $Path=clean_path($Path);
1913 if(not -d $Path) {
1914 exitStatus("Access_Error", "can't access directory \'$Path\'");
1915 }
1916 $Path = path_format($Path, $OSgroup);
1917 $SystemPaths{"bin"}{$Path}=1;
1918 $TargetTools{$Path}=1;
1919 }
1920 if(my $Prefix = parseTag(\$Content, "cross_prefix")) {
1921 $CrossPrefix = $Prefix;
1922 }
1923 foreach my $Path (split(/\s*\n\s*/, parseTag(\$Content, "include_paths")))
1924 {
1925 $Path=clean_path($Path);
1926 if(not -d $Path) {
1927 exitStatus("Access_Error", "can't access directory \'$Path\'");
1928 }
1929 $Path = path_format($Path, $OSgroup);
1930 $Descriptor{$LibVersion}{"IncludePaths"}{$Path} = 1;
1931 }
1932 foreach my $Path (split(/\s*\n\s*/, parseTag(\$Content, "add_include_paths")))
1933 {
1934 $Path=clean_path($Path);
1935 if(not -d $Path) {
1936 exitStatus("Access_Error", "can't access directory \'$Path\'");
1937 }
1938 $Path = path_format($Path, $OSgroup);
1939 $Descriptor{$LibVersion}{"AddIncludePaths"}{$Path} = 1;
1940 }
1941 foreach my $Path (split(/\s*\n\s*/, parseTag(\$Content, "skip_include_paths")))
1942 {
1943 # skip some auto-generated include paths
1944 $Skip_Include_Paths{$LibVersion}{path_format($Path)}=1;
1945 }
1946 foreach my $Path (split(/\s*\n\s*/, parseTag(\$Content, "skip_including")))
1947 {
1948 # skip direct including of some headers
1949 my ($CPath, $Type) = classifyPath($Path);
1950 $SkipHeaders{$LibVersion}{$Type}{$CPath} = 2;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04001951 }
1952 $Descriptor{$LibVersion}{"GccOptions"} = parseTag(\$Content, "gcc_options");
1953 foreach my $Option (split(/\s*\n\s*/, $Descriptor{$LibVersion}{"GccOptions"})) {
1954 $CompilerOptions{$LibVersion} .= " ".$Option;
1955 }
1956 $Descriptor{$LibVersion}{"SkipHeaders"} = parseTag(\$Content, "skip_headers");
1957 foreach my $Path (split(/\s*\n\s*/, $Descriptor{$LibVersion}{"SkipHeaders"}))
1958 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04001959 $SkipHeadersList{$LibVersion}{$Path} = 1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04001960 my ($CPath, $Type) = classifyPath($Path);
1961 $SkipHeaders{$LibVersion}{$Type}{$CPath} = 1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04001962 }
1963 $Descriptor{$LibVersion}{"SkipLibs"} = parseTag(\$Content, "skip_libs");
1964 foreach my $Path (split(/\s*\n\s*/, $Descriptor{$LibVersion}{"SkipLibs"}))
1965 {
1966 my ($CPath, $Type) = classifyPath($Path);
1967 $SkipLibs{$LibVersion}{$Type}{$CPath} = 1;
1968 }
1969 if(my $DDefines = parseTag(\$Content, "defines"))
1970 {
1971 if($Descriptor{$LibVersion}{"Defines"})
1972 { # multiple descriptors
1973 $Descriptor{$LibVersion}{"Defines"} .= "\n".$DDefines;
1974 }
1975 else {
1976 $Descriptor{$LibVersion}{"Defines"} = $DDefines;
1977 }
1978 }
1979 foreach my $Order (split(/\s*\n\s*/, parseTag(\$Content, "include_order")))
1980 {
1981 if($Order=~/\A(.+):(.+)\Z/) {
1982 $Include_Order{$LibVersion}{$1} = $2;
1983 }
1984 }
1985 foreach my $Type_Name (split(/\s*\n\s*/, parseTag(\$Content, "opaque_types")),
1986 split(/\s*\n\s*/, parseTag(\$Content, "skip_types")))
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04001987 { # opaque_types renamed to skip_types (1.23.4)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04001988 $SkipTypes{$LibVersion}{$Type_Name} = 1;
1989 }
1990 foreach my $Symbol (split(/\s*\n\s*/, parseTag(\$Content, "skip_interfaces")),
1991 split(/\s*\n\s*/, parseTag(\$Content, "skip_symbols")))
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04001992 { # skip_interfaces renamed to skip_symbols (1.22.1)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04001993 $SkipSymbols{$LibVersion}{$Symbol} = 1;
1994 }
1995 foreach my $NameSpace (split(/\s*\n\s*/, parseTag(\$Content, "skip_namespaces"))) {
1996 $SkipNameSpaces{$LibVersion}{$NameSpace} = 1;
1997 }
Andrey Ponomarenkoa01311b2012-06-08 17:20:02 +04001998 foreach my $NameSpace (split(/\s*\n\s*/, parseTag(\$Content, "add_namespaces"))) {
1999 $AddNameSpaces{$LibVersion}{$NameSpace} = 1;
2000 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002001 foreach my $Constant (split(/\s*\n\s*/, parseTag(\$Content, "skip_constants"))) {
2002 $SkipConstants{$LibVersion}{$Constant} = 1;
2003 }
2004 if(my $DIncPreamble = parseTag(\$Content, "include_preamble"))
2005 {
2006 if($Descriptor{$LibVersion}{"IncludePreamble"})
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04002007 { # multiple descriptors
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002008 $Descriptor{$LibVersion}{"IncludePreamble"} .= "\n".$DIncPreamble;
2009 }
2010 else {
2011 $Descriptor{$LibVersion}{"IncludePreamble"} = $DIncPreamble;
2012 }
2013 }
2014}
2015
Andrey Ponomarenko01117f12012-06-26 12:23:02 +04002016sub parseTag(@)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002017{
Andrey Ponomarenko01117f12012-06-26 12:23:02 +04002018 my $CodeRef = shift(@_);
2019 my $Tag = shift(@_);
2020 if(not $Tag or not $CodeRef) {
2021 return undef;
2022 }
2023 my $Sp = 0;
2024 if(@_) {
2025 $Sp = shift(@_);
2026 }
2027 my $Start = index(${$CodeRef}, "<$Tag>");
2028 if($Start!=-1)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002029 {
Andrey Ponomarenko01117f12012-06-26 12:23:02 +04002030 my $End = index(${$CodeRef}, "</$Tag>");
2031 if($End!=-1)
2032 {
2033 my $TS = length($Tag)+3;
2034 my $Content = substr(${$CodeRef}, $Start, $End-$Start+$TS, "");
2035 substr($Content, 0, $TS-1, ""); # cut start tag
2036 substr($Content, -$TS, $TS, ""); # cut end tag
2037 if(not $Sp)
2038 {
2039 $Content=~s/\A\s+//g;
2040 $Content=~s/\s+\Z//g;
2041 }
2042 if(substr($Content, 0, 1) ne "<") {
2043 $Content = xmlSpecChars_R($Content);
2044 }
2045 return $Content;
2046 }
2047 }
2048 return undef;
2049}
2050
2051sub parseTag_E($$$)
2052{
2053 my ($CodeRef, $Tag, $Info) = @_;
2054 if(not $Tag or not $CodeRef
2055 or not $Info) {
2056 return undef;
2057 }
2058 if(${$CodeRef}=~s/\<\Q$Tag\E(\s+([^<>]+)|)\>((.|\n)*?)\<\/\Q$Tag\E\>//)
2059 {
2060 my ($Ext, $Content) = ($2, $3);
2061 $Content=~s/\A\s+//g;
2062 $Content=~s/\s+\Z//g;
2063 if($Ext)
2064 {
2065 while($Ext=~s/(\w+)\=\"([^\"]*)\"//)
2066 {
2067 my ($K, $V) = ($1, $2);
2068 $Info->{$K} = xmlSpecChars_R($V);
2069 }
2070 }
2071 if(substr($Content, 0, 1) ne "<") {
2072 $Content = xmlSpecChars_R($Content);
2073 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002074 return $Content;
2075 }
Andrey Ponomarenko01117f12012-06-26 12:23:02 +04002076 return undef;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002077}
2078
Andrey Ponomarenko35c44fd2012-06-18 17:50:25 +04002079sub addTag(@)
Andrey Ponomarenko5c09ef32012-06-14 18:17:33 +04002080{
Andrey Ponomarenko35c44fd2012-06-18 17:50:25 +04002081 my $Tag = shift(@_);
2082 my $Val = shift(@_);
2083 my @Ext = @_;
2084 my $Content = openTag($Tag, @Ext);
2085 chomp($Content);
Andrey Ponomarenko5c09ef32012-06-14 18:17:33 +04002086 $Content .= xmlSpecChars($Val);
2087 $Content .= "</$Tag>\n";
Andrey Ponomarenko35c44fd2012-06-18 17:50:25 +04002088 $TAG_ID-=1;
Andrey Ponomarenko5c09ef32012-06-14 18:17:33 +04002089
2090 return $Content;
2091}
2092
Andrey Ponomarenko35c44fd2012-06-18 17:50:25 +04002093sub openTag(@)
Andrey Ponomarenko5c09ef32012-06-14 18:17:33 +04002094{
2095 my $Tag = shift(@_);
2096 my @Ext = @_;
2097 my $Content = "";
2098 foreach (1 .. $TAG_ID) {
2099 $Content .= $INDENT;
2100 }
2101 $TAG_ID+=1;
Andrey Ponomarenko35c44fd2012-06-18 17:50:25 +04002102 if(@Ext)
Andrey Ponomarenko5c09ef32012-06-14 18:17:33 +04002103 {
Andrey Ponomarenko35c44fd2012-06-18 17:50:25 +04002104 $Content .= "<".$Tag;
2105 my $P = 0;
2106 while($P<=$#Ext-1)
2107 {
2108 $Content .= " ".$Ext[$P];
2109 $Content .= "=\"".xmlSpecChars($Ext[$P+1])."\"";
2110 $P+=2;
2111 }
2112 $Content .= ">\n";
Andrey Ponomarenko5c09ef32012-06-14 18:17:33 +04002113 }
Andrey Ponomarenko35c44fd2012-06-18 17:50:25 +04002114 else {
2115 $Content .= "<".$Tag.">\n";
2116 }
Andrey Ponomarenko5c09ef32012-06-14 18:17:33 +04002117 return $Content;
2118}
2119
2120sub closeTag($)
2121{
2122 my $Tag = $_[0];
2123 my $Content = "";
2124 $TAG_ID-=1;
2125 foreach (1 .. $TAG_ID) {
2126 $Content .= $INDENT;
2127 }
2128 $Content .= "</".$Tag.">\n";
2129 return $Content;
2130}
2131
2132sub checkTags()
2133{
2134 if($TAG_ID!=0) {
2135 printMsg("WARNING", "the number of opened tags is not equal to number of closed tags");
2136 }
2137}
2138
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002139sub getInfo($)
2140{
Andrey Ponomarenko85043792012-05-14 16:48:07 +04002141 my $DumpPath = $_[0];
2142 return if(not $DumpPath or not -f $DumpPath);
2143
2144 readTUDump($DumpPath);
2145
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002146 # processing info
2147 setTemplateParams_All();
2148 getTypeInfo_All();
2149 simplifyNames();
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002150 getVarInfo_All();
Andrey Ponomarenko01117f12012-06-26 12:23:02 +04002151 getSymbolInfo_All();
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002152
Andrey Ponomarenko85043792012-05-14 16:48:07 +04002153 # clean memory
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002154 %LibInfo = ();
2155 %TemplateInstance = ();
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002156 %MangledNames = ();
Andrey Ponomarenko85043792012-05-14 16:48:07 +04002157 %TemplateDecl = ();
2158 %StdCxxTypedef = ();
2159 %MissedTypedef = ();
2160 %Typedef_Tr = ();
2161 %Typedef_Eq = ();
2162
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04002163 # clean cache
2164 delete($Cache{"getTypeAttr"});
2165 delete($Cache{"getTypeDeclId"});
2166
2167 # remove unused types
2168 if($BinaryOnly and not $ExtendedCheck)
2169 { # --binary
2170 removeUnused($Version, "All");
2171 }
2172 else {
2173 removeUnused($Version, "Derived");
2174 }
2175
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002176 if($Debug) {
2177 # debugMangling($Version);
2178 }
2179}
2180
Andrey Ponomarenko85043792012-05-14 16:48:07 +04002181sub readTUDump($)
2182{
2183 my $DumpPath = $_[0];
2184
2185 open(TU_DUMP, $DumpPath);
2186 local $/ = undef;
2187 my $Content = <TU_DUMP>;
2188 close(TU_DUMP);
2189
2190 unlink($DumpPath);
2191
2192 $Content=~s/\n[ ]+/ /g;
2193 my @Lines = split("\n", $Content);
2194
2195 # clean memory
2196 undef $Content;
2197
2198 $MAX_ID = $#Lines+1;
2199
2200 foreach (0 .. $#Lines)
2201 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04002202 if($Lines[$_]=~/\A\@(\d+)[ ]+([a-z_]+)[ ]+(.+)\Z/i)
Andrey Ponomarenko85043792012-05-14 16:48:07 +04002203 { # get a number and attributes of a node
2204 next if(not $NodeType{$2});
2205 $LibInfo{$Version}{"info_type"}{$1}=$2;
2206 $LibInfo{$Version}{"info"}{$1}=$3;
2207 }
2208
2209 # clean memory
2210 delete($Lines[$_]);
2211 }
2212
2213 # clean memory
2214 undef @Lines;
2215}
2216
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002217sub simplifyNames()
2218{
2219 foreach my $Base (keys(%{$Typedef_Tr{$Version}}))
2220 {
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +04002221 if($Typedef_Eq{$Version}{$Base}) {
2222 next;
2223 }
2224 my @Translations = sort keys(%{$Typedef_Tr{$Version}{$Base}});
2225 if($#Translations==0)
2226 {
2227 if(length($Translations[0])<=length($Base)) {
2228 $Typedef_Eq{$Version}{$Base} = $Translations[0];
2229 }
2230 }
2231 else
2232 { # select most appropriate
2233 foreach my $Tr (@Translations)
2234 {
2235 if($Base=~/\A\Q$Tr\E/)
2236 {
2237 $Typedef_Eq{$Version}{$Base} = $Tr;
2238 last;
2239 }
2240 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002241 }
2242 }
Andrey Ponomarenkob8d203d2012-05-25 18:11:07 +04002243 foreach my $TypeId (keys(%{$TypeInfo{$Version}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002244 {
Andrey Ponomarenkob8d203d2012-05-25 18:11:07 +04002245 my $TypeName = $TypeInfo{$Version}{$TypeId}{"Name"};
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04002246 if(not $TypeName) {
2247 next;
2248 }
2249 next if(index($TypeName,"<")==-1);# template instances only
2250 if($TypeName=~/>(::\w+)+\Z/)
2251 { # skip unused types
2252 next;
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +04002253 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04002254 foreach my $Base (sort {length($b)<=>length($a)}
2255 sort {$b cmp $a} keys(%{$Typedef_Eq{$Version}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002256 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04002257 next if(not $Base);
2258 next if(index($TypeName,$Base)==-1);
2259 next if(length($TypeName) - length($Base) <= 3);
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +04002260 if(my $Typedef = $Typedef_Eq{$Version}{$Base})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002261 {
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +04002262 $TypeName=~s/(\<|\,)\Q$Base\E(\W|\Z)/$1$Typedef$2/g;
2263 $TypeName=~s/(\<|\,)\Q$Base\E(\w|\Z)/$1$Typedef $2/g;
2264 if(defined $TypeInfo{$Version}{$TypeId}{"TParam"})
Andrey Ponomarenko85043792012-05-14 16:48:07 +04002265 {
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +04002266 foreach my $TPos (keys(%{$TypeInfo{$Version}{$TypeId}{"TParam"}}))
2267 {
2268 if(my $TPName = $TypeInfo{$Version}{$TypeId}{"TParam"}{$TPos}{"name"})
2269 {
2270 $TPName=~s/\A\Q$Base\E(\W|\Z)/$Typedef$1/g;
2271 $TPName=~s/\A\Q$Base\E(\w|\Z)/$Typedef $1/g;
Andrey Ponomarenko9927e332012-10-19 10:50:48 +04002272 $TypeInfo{$Version}{$TypeId}{"TParam"}{$TPos}{"name"} = formatName($TPName, "T");
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +04002273 }
2274 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +04002275 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002276 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002277 }
Andrey Ponomarenko9927e332012-10-19 10:50:48 +04002278 $TypeName = formatName($TypeName, "T");
Andrey Ponomarenkob8d203d2012-05-25 18:11:07 +04002279 $TypeInfo{$Version}{$TypeId}{"Name"} = $TypeName;
2280 $TName_Tid{$Version}{$TypeName} = $TypeId;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002281 }
2282}
2283
2284sub setTemplateParams_All()
2285{
2286 foreach (keys(%{$LibInfo{$Version}{"info"}}))
2287 {
2288 if($LibInfo{$Version}{"info_type"}{$_} eq "template_decl") {
2289 setTemplateParams($_);
2290 }
2291 }
2292}
2293
2294sub setTemplateParams($)
2295{
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04002296 if(my $Info = $LibInfo{$Version}{"info"}{$_[0]})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002297 {
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04002298 if($Info=~/(inst|spcs)[ ]*:[ ]*@(\d+) /)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002299 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04002300 my $TmplInst_Id = $2;
2301 setTemplateInstParams($TmplInst_Id);
2302 while($TmplInst_Id = getNextElem($TmplInst_Id)) {
2303 setTemplateInstParams($TmplInst_Id);
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04002304 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002305 }
2306 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04002307 if(my $TypeId = getTreeAttr_Type($_[0]))
Andrey Ponomarenko85043792012-05-14 16:48:07 +04002308 {
2309 if(my $IType = $LibInfo{$Version}{"info_type"}{$TypeId})
2310 {
2311 if($IType eq "record_type") {
2312 $TemplateDecl{$Version}{$TypeId}=1;
2313 }
2314 }
2315 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002316}
2317
2318sub setTemplateInstParams($)
2319{
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04002320 if(my $Info = $LibInfo{$Version}{"info"}{$_[0]})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002321 {
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04002322 my ($Params_InfoId, $ElemId) = ();
2323 if($Info=~/purp[ ]*:[ ]*@(\d+) /) {
2324 $Params_InfoId = $1;
2325 }
2326 if($Info=~/valu[ ]*:[ ]*@(\d+) /) {
2327 $ElemId = $1;
2328 }
2329 if($Params_InfoId and $ElemId)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002330 {
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04002331 my $Params_Info = $LibInfo{$Version}{"info"}{$Params_InfoId};
2332 while($Params_Info=~s/ (\d+)[ ]*:[ ]*\@(\d+) / /)
2333 {
2334 my ($PPos, $PTypeId) = ($1, $2);
2335 if(my $PType = $LibInfo{$Version}{"info_type"}{$PTypeId})
2336 {
Andrey Ponomarenko85043792012-05-14 16:48:07 +04002337 if($PType eq "template_type_parm")
2338 {
2339 $TemplateDecl{$Version}{$ElemId}=1;
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04002340 return;
2341 }
2342 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +04002343 if($LibInfo{$Version}{"info_type"}{$ElemId} eq "function_decl")
2344 { # functions
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04002345 $TemplateInstance{$Version}{"Func"}{$ElemId}{$PPos} = $PTypeId;
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04002346 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +04002347 else
2348 { # types
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04002349 $TemplateInstance{$Version}{"Type"}{$ElemId}{$PPos} = $PTypeId;
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04002350 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002351 }
2352 }
2353 }
2354}
2355
2356sub getTypeDeclId($)
2357{
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04002358 if($_[0])
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04002359 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04002360 if(defined $Cache{"getTypeDeclId"}{$Version}{$_[0]}) {
2361 return $Cache{"getTypeDeclId"}{$Version}{$_[0]};
2362 }
2363 if(my $Info = $LibInfo{$Version}{"info"}{$_[0]})
2364 {
2365 if($Info=~/name[ ]*:[ ]*@(\d+)/) {
2366 return ($Cache{"getTypeDeclId"}{$Version}{$_[0]} = $1);
2367 }
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04002368 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002369 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04002370 return ($Cache{"getTypeDeclId"}{$Version}{$_[0]} = 0);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002371}
2372
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002373sub getTypeInfo_All()
2374{
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04002375 if(not check_gcc($GCC_PATH, "4.5"))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002376 { # support for GCC < 4.5
2377 # missed typedefs: QStyle::State is typedef to QFlags<QStyle::StateFlag>
2378 # but QStyleOption.state is of type QFlags<QStyle::StateFlag> in the TU dump
2379 # FIXME: check GCC versions
2380 addMissedTypes_Pre();
2381 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04002382
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002383 foreach (sort {int($a)<=>int($b)} keys(%{$LibInfo{$Version}{"info"}}))
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04002384 { # forward order only
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002385 my $IType = $LibInfo{$Version}{"info_type"}{$_};
2386 if($IType=~/_type\Z/ and $IType ne "function_type"
2387 and $IType ne "method_type") {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04002388 getTypeInfo("$_");
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002389 }
2390 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04002391
2392 # add "..." type
Andrey Ponomarenko01117f12012-06-26 12:23:02 +04002393 $TypeInfo{$Version}{"-1"} = {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04002394 "Name" => "...",
2395 "Type" => "Intrinsic",
Andrey Ponomarenko01117f12012-06-26 12:23:02 +04002396 "Tid" => "-1"
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04002397 };
Andrey Ponomarenko01117f12012-06-26 12:23:02 +04002398 $TName_Tid{$Version}{"..."} = "-1";
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04002399
2400 if(not check_gcc($GCC_PATH, "4.5"))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002401 { # support for GCC < 4.5
2402 addMissedTypes_Post();
2403 }
2404}
2405
2406sub addMissedTypes_Pre()
2407{
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04002408 my %MissedTypes = ();
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002409 foreach my $MissedTDid (sort {int($a)<=>int($b)} keys(%{$LibInfo{$Version}{"info"}}))
2410 { # detecting missed typedefs
2411 if($LibInfo{$Version}{"info_type"}{$MissedTDid} eq "type_decl")
2412 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04002413 my $TypeId = getTreeAttr_Type($MissedTDid);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002414 next if(not $TypeId);
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04002415 my $TypeType = getTypeType($TypeId);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002416 if($TypeType eq "Unknown")
2417 { # template_type_parm
2418 next;
2419 }
2420 my $TypeDeclId = getTypeDeclId($TypeId);
2421 next if($TypeDeclId eq $MissedTDid);#or not $TypeDeclId
2422 my $TypedefName = getNameByInfo($MissedTDid);
2423 next if(not $TypedefName);
2424 next if($TypedefName eq "__float80");
2425 next if(isAnon($TypedefName));
2426 if(not $TypeDeclId
2427 or getNameByInfo($TypeDeclId) ne $TypedefName) {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04002428 $MissedTypes{$Version}{$TypeId}{$MissedTDid} = 1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002429 }
2430 }
2431 }
Andrey Ponomarenkob8d203d2012-05-25 18:11:07 +04002432 my %AddTypes = ();
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04002433 foreach my $Tid (keys(%{$MissedTypes{$Version}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002434 { # add missed typedefs
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04002435 my @Missed = keys(%{$MissedTypes{$Version}{$Tid}});
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002436 if(not @Missed or $#Missed>=1) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002437 next;
2438 }
2439 my $MissedTDid = $Missed[0];
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002440 my ($TypedefName, $TypedefNS) = getTrivialName($MissedTDid, $Tid);
Andrey Ponomarenkob8d203d2012-05-25 18:11:07 +04002441 if(not $TypedefName) {
2442 next;
2443 }
2444 $MAX_ID++;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002445 my %MissedInfo = ( # typedef info
2446 "Name" => $TypedefName,
2447 "NameSpace" => $TypedefNS,
2448 "BaseType" => {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002449 "Tid" => $Tid
2450 },
2451 "Type" => "Typedef",
Andrey Ponomarenkob8d203d2012-05-25 18:11:07 +04002452 "Tid" => "$MAX_ID" );
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002453 my ($H, $L) = getLocation($MissedTDid);
2454 $MissedInfo{"Header"} = $H;
2455 $MissedInfo{"Line"} = $L;
Andrey Ponomarenkob8d203d2012-05-25 18:11:07 +04002456 if($TypedefName=~/\*|\&|\s/)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002457 { # other types
2458 next;
2459 }
Andrey Ponomarenkob8d203d2012-05-25 18:11:07 +04002460 if($TypedefName=~/>(::\w+)+\Z/)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002461 { # QFlags<Qt::DropAction>::enum_type
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002462 next;
2463 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04002464 if(getTypeType($Tid)=~/\A(Intrinsic|Union|Struct|Enum|Class)\Z/)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002465 { # double-check for the name of typedef
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04002466 my ($TName, $TNS) = getTrivialName(getTypeDeclId($Tid), $Tid); # base type info
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002467 next if(not $TName);
Andrey Ponomarenkob8d203d2012-05-25 18:11:07 +04002468 if(length($TypedefName)>=length($TName))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002469 { # too long typedef
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002470 next;
2471 }
Andrey Ponomarenkob8d203d2012-05-25 18:11:07 +04002472 if($TName=~/\A\Q$TypedefName\E</) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002473 next;
2474 }
Andrey Ponomarenkob8d203d2012-05-25 18:11:07 +04002475 if($TypedefName=~/\A\Q$TName\E/)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002476 { # QDateTimeEdit::Section and QDateTimeEdit::Sections::enum_type
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002477 next;
2478 }
Andrey Ponomarenkob8d203d2012-05-25 18:11:07 +04002479 if(get_depth($TypedefName)==0 and get_depth($TName)!=0)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002480 { # std::_Vector_base and std::vector::_Base
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002481 next;
2482 }
2483 }
Andrey Ponomarenkob8d203d2012-05-25 18:11:07 +04002484
2485 $AddTypes{$MissedInfo{"Tid"}} = \%MissedInfo;
2486
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002487 # register typedef
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002488 $MissedTypedef{$Version}{$Tid}{"Tid"} = $MissedInfo{"Tid"};
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04002489 $MissedTypedef{$Version}{$Tid}{"TDid"} = $MissedTDid;
Andrey Ponomarenkob8d203d2012-05-25 18:11:07 +04002490 $TName_Tid{$Version}{$TypedefName} = $MissedInfo{"Tid"};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002491 }
Andrey Ponomarenkob8d203d2012-05-25 18:11:07 +04002492
2493 # add missed & remove other
2494 $TypeInfo{$Version} = \%AddTypes;
2495 delete($Cache{"getTypeAttr"}{$Version});
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002496}
2497
2498sub addMissedTypes_Post()
2499{
2500 foreach my $BaseId (keys(%{$MissedTypedef{$Version}}))
2501 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04002502 if(my $Tid = $MissedTypedef{$Version}{$BaseId}{"Tid"})
2503 {
2504 $TypeInfo{$Version}{$Tid}{"Size"} = $TypeInfo{$Version}{$BaseId}{"Size"};
2505 if(my $TName = $TypeInfo{$Version}{$Tid}{"Name"}) {
2506 $Typedef_BaseName{$Version}{$TName} = $TypeInfo{$Version}{$BaseId}{"Name"};
2507 }
2508 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002509 }
2510}
2511
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04002512sub getTypeInfo($)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002513{
Andrey Ponomarenkob8d203d2012-05-25 18:11:07 +04002514 my $TypeId = $_[0];
2515 %{$TypeInfo{$Version}{$TypeId}} = getTypeAttr($TypeId);
2516 my $TName = $TypeInfo{$Version}{$TypeId}{"Name"};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002517 if(not $TName) {
Andrey Ponomarenkob8d203d2012-05-25 18:11:07 +04002518 delete($TypeInfo{$Version}{$TypeId});
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002519 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002520}
2521
2522sub getArraySize($$)
2523{
2524 my ($TypeId, $BaseName) = @_;
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04002525 if(my $Size = getSize($TypeId))
2526 {
2527 my $Elems = $Size/$BYTE_SIZE;
2528 while($BaseName=~s/\s*\[(\d+)\]//) {
2529 $Elems/=$1;
2530 }
2531 if(my $BasicId = $TName_Tid{$Version}{$BaseName})
2532 {
2533 if(my $BasicSize = $TypeInfo{$Version}{$BasicId}{"Size"}) {
2534 $Elems/=$BasicSize;
2535 }
2536 }
2537 return $Elems;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002538 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04002539 return 0;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002540}
2541
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04002542sub getTParams($$)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002543{
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04002544 my ($TypeId, $Kind) = @_;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002545 my @TmplParams = ();
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04002546 my @Positions = sort {int($a)<=>int($b)} keys(%{$TemplateInstance{$Version}{$Kind}{$TypeId}});
2547 foreach my $Pos (@Positions)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002548 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04002549 my $Param_TypeId = $TemplateInstance{$Version}{$Kind}{$TypeId}{$Pos};
2550 my $NodeType = $LibInfo{$Version}{"info_type"}{$Param_TypeId};
2551 if(not $NodeType)
2552 { # typename_type
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002553 return ();
2554 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04002555 if($NodeType eq "tree_vec")
2556 {
2557 if($Pos!=$#Positions)
2558 { # select last vector of parameters ( ns<P1>::type<P2> )
2559 next;
2560 }
2561 }
2562 my @Params = get_TemplateParam($Pos, $Param_TypeId);
2563 foreach my $P (@Params)
2564 {
2565 if($P eq "") {
2566 return ();
2567 }
2568 elsif($P ne "\@skip\@") {
2569 @TmplParams = (@TmplParams, $P);
2570 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002571 }
2572 }
2573 return @TmplParams;
2574}
2575
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04002576sub getTypeAttr($)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002577{
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04002578 my $TypeId = $_[0];
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04002579 my %TypeAttr = ();
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04002580 if(defined $TypeInfo{$Version}{$TypeId}
2581 and $TypeInfo{$Version}{$TypeId}{"Name"})
2582 { # already created
2583 return %{$TypeInfo{$Version}{$TypeId}};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002584 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04002585 elsif($Cache{"getTypeAttr"}{$Version}{$TypeId})
2586 { # incomplete type
2587 return ();
2588 }
2589 $Cache{"getTypeAttr"}{$Version}{$TypeId} = 1;
2590
2591 my $TypeDeclId = getTypeDeclId($TypeId);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002592 $TypeAttr{"Tid"} = $TypeId;
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04002593
2594 if(not $MissedBase{$Version}{$TypeId} and isTypedef($TypeId))
2595 {
2596 if(my $Info = $LibInfo{$Version}{"info"}{$TypeId})
2597 {
2598 if($Info=~/qual[ ]*:/)
2599 {
2600 if(my $NID = ++$MAX_ID)
2601 {
2602 $MissedBase{$Version}{$TypeId}="$NID";
2603 $MissedBase_R{$Version}{$NID}=$TypeId;
2604 $LibInfo{$Version}{"info"}{$NID} = $LibInfo{$Version}{"info"}{$TypeId};
2605 $LibInfo{$Version}{"info_type"}{$NID} = $LibInfo{$Version}{"info_type"}{$TypeId};
2606 }
2607 }
2608 }
2609 $TypeAttr{"Type"} = "Typedef";
2610 }
2611 else {
2612 $TypeAttr{"Type"} = getTypeType($TypeId);
2613 }
2614
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002615 if($TypeAttr{"Type"} eq "Unknown") {
2616 return ();
2617 }
2618 elsif($TypeAttr{"Type"}=~/(Func|Method|Field)Ptr/)
2619 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04002620 %TypeAttr = getMemPtrAttr(pointTo($TypeId), $TypeId, $TypeAttr{"Type"});
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04002621 if(my $TName = $TypeAttr{"Name"})
2622 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04002623 %{$TypeInfo{$Version}{$TypeId}} = %TypeAttr;
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04002624 $TName_Tid{$Version}{$TName} = $TypeId;
2625 return %TypeAttr;
2626 }
2627 else {
2628 return ();
2629 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002630 }
2631 elsif($TypeAttr{"Type"} eq "Array")
2632 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04002633 my ($BTid, $BTSpec) = selectBaseType($TypeId);
2634 if(not $BTid) {
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04002635 return ();
2636 }
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +04002637 if(my $Algn = getAlgn($TypeId)) {
2638 $TypeAttr{"Algn"} = $Algn/$BYTE_SIZE;
2639 }
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04002640 $TypeAttr{"BaseType"}{"Tid"} = $BTid;
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04002641 if(my %BTAttr = getTypeAttr($BTid))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002642 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04002643 if(not $BTAttr{"Name"}) {
2644 return ();
2645 }
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04002646 if(my $NElems = getArraySize($TypeId, $BTAttr{"Name"}))
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04002647 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04002648 if(my $Size = getSize($TypeId)) {
2649 $TypeAttr{"Size"} = $Size/$BYTE_SIZE;
2650 }
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04002651 if($BTAttr{"Name"}=~/\A([^\[\]]+)(\[(\d+|)\].*)\Z/) {
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04002652 $TypeAttr{"Name"} = $1."[$NElems]".$2;
2653 }
2654 else {
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04002655 $TypeAttr{"Name"} = $BTAttr{"Name"}."[$NElems]";
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04002656 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002657 }
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04002658 else
2659 {
2660 $TypeAttr{"Size"} = $WORD_SIZE{$Version}; # pointer
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04002661 if($BTAttr{"Name"}=~/\A([^\[\]]+)(\[(\d+|)\].*)\Z/) {
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04002662 $TypeAttr{"Name"} = $1."[]".$2;
2663 }
2664 else {
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04002665 $TypeAttr{"Name"} = $BTAttr{"Name"}."[]";
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04002666 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002667 }
Andrey Ponomarenko9927e332012-10-19 10:50:48 +04002668 $TypeAttr{"Name"} = formatName($TypeAttr{"Name"}, "T");
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04002669 if($BTAttr{"Header"}) {
2670 $TypeAttr{"Header"} = $BTAttr{"Header"};
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04002671 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04002672 %{$TypeInfo{$Version}{$TypeId}} = %TypeAttr;
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04002673 $TName_Tid{$Version}{$TypeAttr{"Name"}} = $TypeId;
2674 return %TypeAttr;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002675 }
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04002676 return ();
2677 }
2678 elsif($TypeAttr{"Type"}=~/\A(Intrinsic|Union|Struct|Enum|Class)\Z/)
2679 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04002680 %TypeAttr = getTrivialTypeAttr($TypeId);
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04002681 if($TypeAttr{"Name"})
2682 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04002683 %{$TypeInfo{$Version}{$TypeId}} = %TypeAttr;
2684 if($TypeAttr{"Name"} ne "int" or getTypeDeclId($TypeAttr{"Tid"}))
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04002685 { # NOTE: register only one int: with built-in decl
2686 if(not $TName_Tid{$Version}{$TypeAttr{"Name"}}) {
2687 $TName_Tid{$Version}{$TypeAttr{"Name"}} = $TypeId;
2688 }
2689 }
2690 return %TypeAttr;
2691 }
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04002692 else {
2693 return ();
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002694 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002695 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002696 else
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04002697 { # derived types
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04002698 my ($BTid, $BTSpec) = selectBaseType($TypeId);
2699 if(not $BTid) {
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04002700 return ();
2701 }
2702 $TypeAttr{"BaseType"}{"Tid"} = $BTid;
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04002703 if(defined $MissedTypedef{$Version}{$BTid})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002704 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04002705 if(my $MissedTDid = $MissedTypedef{$Version}{$BTid}{"TDid"})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002706 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04002707 if($MissedTDid ne $TypeDeclId) {
2708 $TypeAttr{"BaseType"}{"Tid"} = $MissedTypedef{$Version}{$BTid}{"Tid"};
2709 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002710 }
2711 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04002712 my %BTAttr = getTypeAttr($TypeAttr{"BaseType"}{"Tid"});
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04002713 if(not $BTAttr{"Name"})
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04002714 { # templates
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002715 return ();
2716 }
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04002717 if($BTAttr{"Type"} eq "Typedef")
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002718 { # relinking typedefs
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04002719 my %BaseBase = get_Type($BTAttr{"BaseType"}{"Tid"}, $Version);
2720 if($BTAttr{"Name"} eq $BaseBase{"Name"}) {
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04002721 $TypeAttr{"BaseType"}{"Tid"} = $BaseBase{"Tid"};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002722 }
2723 }
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04002724 if($BTSpec)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002725 {
2726 if($TypeAttr{"Type"} eq "Pointer"
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04002727 and $BTAttr{"Name"}=~/\([\*]+\)/)
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04002728 {
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04002729 $TypeAttr{"Name"} = $BTAttr{"Name"};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002730 $TypeAttr{"Name"}=~s/\(([*]+)\)/($1*)/g;
2731 }
2732 else {
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04002733 $TypeAttr{"Name"} = $BTAttr{"Name"}." ".$BTSpec;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002734 }
2735 }
2736 else {
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04002737 $TypeAttr{"Name"} = $BTAttr{"Name"};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002738 }
2739 if($TypeAttr{"Type"} eq "Typedef")
2740 {
2741 $TypeAttr{"Name"} = getNameByInfo($TypeDeclId);
Andrey Ponomarenko85043792012-05-14 16:48:07 +04002742 if(isAnon($TypeAttr{"Name"}))
2743 { # anon typedef to anon type: ._N
2744 return ();
2745 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002746 if(my $NS = getNameSpace($TypeDeclId))
2747 {
2748 my $TypeName = $TypeAttr{"Name"};
2749 if($NS=~/\A(struct |union |class |)((.+)::|)\Q$TypeName\E\Z/)
2750 { # "some_type" is the typedef to "struct some_type" in C++
2751 if($3) {
2752 $TypeAttr{"Name"} = $3."::".$TypeName;
2753 }
2754 }
2755 else
2756 {
2757 $TypeAttr{"NameSpace"} = $NS;
2758 $TypeAttr{"Name"} = $TypeAttr{"NameSpace"}."::".$TypeAttr{"Name"};
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04002759
2760 if($TypeAttr{"NameSpace"}=~/\Astd(::|\Z)/
2761 and $TypeAttr{"Name"}!~/>(::\w+)+\Z/)
2762 {
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04002763 if($BTAttr{"NameSpace"}
2764 and $BTAttr{"NameSpace"}=~/\Astd(::|\Z)/ and $BTAttr{"Name"}=~/</)
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04002765 { # types like "std::fpos<__mbstate_t>" are
2766 # not covered by typedefs in the TU dump
2767 # so trying to add such typedefs manually
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04002768 $StdCxxTypedef{$Version}{$BTAttr{"Name"}}{$TypeAttr{"Name"}} = 1;
2769 if(length($TypeAttr{"Name"})<=length($BTAttr{"Name"}))
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04002770 {
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04002771 if(($BTAttr{"Name"}!~/\A(std|boost)::/ or $TypeAttr{"Name"}!~/\A[a-z]+\Z/))
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04002772 { # skip "other" in "std" and "type" in "boost"
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04002773 $Typedef_Eq{$Version}{$BTAttr{"Name"}} = $TypeAttr{"Name"};
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04002774 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002775 }
2776 }
2777 }
2778 }
2779 }
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04002780 if($TypeAttr{"Name"} ne $BTAttr{"Name"}
2781 and $TypeAttr{"Name"}!~/>(::\w+)+\Z/ and $BTAttr{"Name"}!~/>(::\w+)+\Z/)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002782 {
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04002783 if(not defined $Typedef_BaseName{$Version}{$TypeAttr{"Name"}})
2784 { # typedef int*const TYPEDEF; // first
2785 # int foo(TYPEDEF p); // const is optimized out
2786 $Typedef_BaseName{$Version}{$TypeAttr{"Name"}} = $BTAttr{"Name"};
2787 if($BTAttr{"Name"}=~/</)
2788 {
2789 if(($BTAttr{"Name"}!~/\A(std|boost)::/ or $TypeAttr{"Name"}!~/\A[a-z]+\Z/)) {
2790 $Typedef_Tr{$Version}{$BTAttr{"Name"}}{$TypeAttr{"Name"}} = 1;
2791 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002792 }
2793 }
2794 }
2795 ($TypeAttr{"Header"}, $TypeAttr{"Line"}) = getLocation($TypeDeclId);
2796 }
2797 if(not $TypeAttr{"Size"})
2798 {
2799 if($TypeAttr{"Type"} eq "Pointer") {
2800 $TypeAttr{"Size"} = $WORD_SIZE{$Version};
2801 }
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04002802 elsif($BTAttr{"Size"}) {
2803 $TypeAttr{"Size"} = $BTAttr{"Size"};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002804 }
2805 }
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +04002806 if(my $Algn = getAlgn($TypeId)) {
2807 $TypeAttr{"Algn"} = $Algn/$BYTE_SIZE;
2808 }
Andrey Ponomarenko9927e332012-10-19 10:50:48 +04002809 $TypeAttr{"Name"} = formatName($TypeAttr{"Name"}, "T");
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04002810 if(not $TypeAttr{"Header"} and $BTAttr{"Header"}) {
2811 $TypeAttr{"Header"} = $BTAttr{"Header"};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002812 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04002813 %{$TypeInfo{$Version}{$TypeId}} = %TypeAttr;
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04002814 if($TypeAttr{"Name"} ne $BTAttr{"Name"})
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04002815 { # typedef to "class Class"
2816 # should not be registered in TName_Tid
2817 if(not $TName_Tid{$Version}{$TypeAttr{"Name"}}) {
2818 $TName_Tid{$Version}{$TypeAttr{"Name"}} = $TypeId;
2819 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002820 }
2821 return %TypeAttr;
2822 }
2823}
2824
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04002825sub getTreeVec($)
2826{
2827 my %Vector = ();
2828 if($_[0] and my $Info = $LibInfo{$Version}{"info"}{$_[0]})
2829 {
2830 while($Info=~s/ (\d+)[ ]*:[ ]*\@(\d+) / /)
2831 { # string length is N-1 because of the null terminator
2832 $Vector{$1} = $2;
2833 }
2834 }
2835 return \%Vector;
2836}
2837
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002838sub get_TemplateParam($$)
2839{
2840 my ($Pos, $Type_Id) = @_;
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04002841 return () if(not $Type_Id);
2842 my $NodeType = $LibInfo{$Version}{"info_type"}{$Type_Id};
2843 return () if(not $NodeType);
2844 if($NodeType eq "integer_cst")
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002845 { # int (1), unsigned (2u), char ('c' as 99), ...
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04002846 my $CstTid = getTreeAttr_Type($Type_Id);
Andrey Ponomarenkob8d203d2012-05-25 18:11:07 +04002847 my %CstType = getTypeAttr($CstTid); # without recursion
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002848 my $Num = getNodeIntCst($Type_Id);
2849 if(my $CstSuffix = $ConstantSuffix{$CstType{"Name"}}) {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04002850 return ($Num.$CstSuffix);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002851 }
2852 else {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04002853 return ("(".$CstType{"Name"}.")".$Num);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002854 }
2855 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04002856 elsif($NodeType eq "string_cst") {
2857 return (getNodeStrCst($Type_Id));
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002858 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04002859 elsif($NodeType eq "tree_vec")
2860 {
2861 my $Vector = getTreeVec($Type_Id);
2862 my @Params = ();
2863 foreach my $P1 (sort {int($a)<=>int($b)} keys(%{$Vector}))
2864 {
2865 foreach my $P2 (get_TemplateParam($Pos, $Vector->{$P1})) {
2866 push(@Params, $P2);
2867 }
2868 }
2869 return @Params;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002870 }
2871 else
2872 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04002873 my %ParamAttr = getTypeAttr($Type_Id);
Andrey Ponomarenkob8d203d2012-05-25 18:11:07 +04002874 my $PName = $ParamAttr{"Name"};
2875 if(not $PName) {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04002876 return ();
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002877 }
Andrey Ponomarenkob8d203d2012-05-25 18:11:07 +04002878 if($PName=~/\>/)
2879 {
2880 if(my $Cover = cover_stdcxx_typedef($PName)) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002881 $PName = $Cover;
2882 }
2883 }
2884 if($Pos>=1 and
2885 $PName=~/\Astd::(allocator|less|((char|regex)_traits)|((i|o)streambuf_iterator))\</)
2886 { # template<typename _Tp, typename _Alloc = std::allocator<_Tp> >
2887 # template<typename _Key, typename _Compare = std::less<_Key>
2888 # template<typename _CharT, typename _Traits = std::char_traits<_CharT> >
2889 # template<typename _Ch_type, typename _Rx_traits = regex_traits<_Ch_type> >
2890 # template<typename _CharT, typename _InIter = istreambuf_iterator<_CharT> >
2891 # template<typename _CharT, typename _OutIter = ostreambuf_iterator<_CharT> >
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04002892 return ("\@skip\@");
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002893 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04002894 return ($PName);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002895 }
2896}
2897
2898sub cover_stdcxx_typedef($)
2899{
2900 my $TypeName = $_[0];
2901 if(my @Covers = sort {length($a)<=>length($b)}
2902 sort keys(%{$StdCxxTypedef{$Version}{$TypeName}}))
2903 { # take the shortest typedef
2904 # FIXME: there may be more than
2905 # one typedefs to the same type
2906 return $Covers[0];
2907 }
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +04002908 my $Covered = $TypeName;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002909 while($TypeName=~s/(>)[ ]*(const|volatile|restrict| |\*|\&)\Z/$1/g){};
2910 if(my @Covers = sort {length($a)<=>length($b)} sort keys(%{$StdCxxTypedef{$Version}{$TypeName}}))
2911 {
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +04002912 if(my $Cover = $Covers[0])
2913 {
2914 $Covered=~s/\b\Q$TypeName\E(\W|\Z)/$Cover$1/g;
2915 $Covered=~s/\b\Q$TypeName\E(\w|\Z)/$Cover $1/g;
2916 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002917 }
Andrey Ponomarenko9927e332012-10-19 10:50:48 +04002918 return formatName($Covered, "T");
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002919}
2920
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002921sub getNodeIntCst($)
2922{
2923 my $CstId = $_[0];
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04002924 my $CstTypeId = getTreeAttr_Type($CstId);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002925 if($EnumMembName_Id{$Version}{$CstId}) {
2926 return $EnumMembName_Id{$Version}{$CstId};
2927 }
2928 elsif((my $Value = getTreeValue($CstId)) ne "")
2929 {
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04002930 if($Value eq "0")
2931 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04002932 if($LibInfo{$Version}{"info_type"}{$CstTypeId} eq "boolean_type") {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002933 return "false";
2934 }
2935 else {
2936 return "0";
2937 }
2938 }
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04002939 elsif($Value eq "1")
2940 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04002941 if($LibInfo{$Version}{"info_type"}{$CstTypeId} eq "boolean_type") {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002942 return "true";
2943 }
2944 else {
2945 return "1";
2946 }
2947 }
2948 else {
2949 return $Value;
2950 }
2951 }
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04002952 return "";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002953}
2954
2955sub getNodeStrCst($)
2956{
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04002957 if($_[0] and my $Info = $LibInfo{$Version}{"info"}{$_[0]})
2958 {
2959 if($Info=~/strg[ ]*: (.+) lngt:[ ]*(\d+)/)
Andrey Ponomarenko01117f12012-06-26 12:23:02 +04002960 {
2961 if($LibInfo{$Version}{"info_type"}{$_[0]} eq "string_cst")
2962 { # string length is N-1 because of the null terminator
2963 return substr($1, 0, $2-1);
2964 }
2965 else
2966 { # identifier_node
2967 return substr($1, 0, $2);
2968 }
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04002969 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002970 }
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04002971 return "";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002972}
2973
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04002974sub getMemPtrAttr($$$)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002975{ # function, method and field pointers
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04002976 my ($PtrId, $TypeId, $Type) = @_;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002977 my $MemInfo = $LibInfo{$Version}{"info"}{$PtrId};
2978 if($Type eq "FieldPtr") {
2979 $MemInfo = $LibInfo{$Version}{"info"}{$TypeId};
2980 }
2981 my $MemInfo_Type = $LibInfo{$Version}{"info_type"}{$PtrId};
2982 my $MemPtrName = "";
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04002983 my %TypeAttr = ("Size"=>$WORD_SIZE{$Version}, "Type"=>$Type, "Tid"=>$TypeId);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002984 if($Type eq "MethodPtr")
2985 { # size of "method pointer" may be greater than WORD size
Andrey Ponomarenko01117f12012-06-26 12:23:02 +04002986 if(my $Size = getSize($TypeId))
2987 {
2988 $Size/=$BYTE_SIZE;
2989 $TypeAttr{"Size"} = "$Size";
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04002990 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002991 }
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +04002992 if(my $Algn = getAlgn($TypeId)) {
2993 $TypeAttr{"Algn"} = $Algn/$BYTE_SIZE;
2994 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002995 # Return
2996 if($Type eq "FieldPtr")
2997 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04002998 my %ReturnAttr = getTypeAttr($PtrId);
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04002999 if($ReturnAttr{"Name"}) {
3000 $MemPtrName .= $ReturnAttr{"Name"};
3001 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003002 $TypeAttr{"Return"} = $PtrId;
3003 }
3004 else
3005 {
3006 if($MemInfo=~/retn[ ]*:[ ]*\@(\d+) /)
3007 {
3008 my $ReturnTypeId = $1;
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04003009 my %ReturnAttr = getTypeAttr($ReturnTypeId);
3010 if(not $ReturnAttr{"Name"})
3011 { # templates
3012 return ();
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04003013 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04003014 $MemPtrName .= $ReturnAttr{"Name"};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003015 $TypeAttr{"Return"} = $ReturnTypeId;
3016 }
3017 }
3018 # Class
3019 if($MemInfo=~/(clas|cls)[ ]*:[ ]*@(\d+) /)
3020 {
3021 $TypeAttr{"Class"} = $2;
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04003022 my %Class = getTypeAttr($TypeAttr{"Class"});
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003023 if($Class{"Name"}) {
3024 $MemPtrName .= " (".$Class{"Name"}."\:\:*)";
3025 }
3026 else {
3027 $MemPtrName .= " (*)";
3028 }
3029 }
3030 else {
3031 $MemPtrName .= " (*)";
3032 }
3033 # Parameters
3034 if($Type eq "FuncPtr"
3035 or $Type eq "MethodPtr")
3036 {
3037 my @ParamTypeName = ();
3038 if($MemInfo=~/prms[ ]*:[ ]*@(\d+) /)
3039 {
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04003040 my $PTypeInfoId = $1;
Andrey Ponomarenko01117f12012-06-26 12:23:02 +04003041 my ($Pos, $PPos) = (0, 0);
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04003042 while($PTypeInfoId)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003043 {
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04003044 my $PTypeInfo = $LibInfo{$Version}{"info"}{$PTypeInfoId};
3045 if($PTypeInfo=~/valu[ ]*:[ ]*@(\d+) /)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003046 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04003047 my $PTypeId = $1;
3048 my %ParamAttr = getTypeAttr($PTypeId);
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04003049 if(not $ParamAttr{"Name"})
3050 { # templates (template_type_parm), etc.
3051 return ();
3052 }
3053 if($ParamAttr{"Name"} eq "void") {
3054 last;
3055 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04003056 if($Pos!=0 or $Type ne "MethodPtr")
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04003057 {
Andrey Ponomarenko01117f12012-06-26 12:23:02 +04003058 $TypeAttr{"Param"}{$PPos++}{"type"} = $PTypeId;
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04003059 push(@ParamTypeName, $ParamAttr{"Name"});
3060 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04003061 if($PTypeInfoId = getNextElem($PTypeInfoId)) {
3062 $Pos+=1;
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04003063 }
3064 else {
3065 last;
3066 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003067 }
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04003068 else {
3069 last;
3070 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003071 }
3072 }
3073 $MemPtrName .= " (".join(", ", @ParamTypeName).")";
3074 }
Andrey Ponomarenko9927e332012-10-19 10:50:48 +04003075 $TypeAttr{"Name"} = formatName($MemPtrName, "T");
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003076 return %TypeAttr;
3077}
3078
3079sub getTreeTypeName($)
3080{
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04003081 my $TypeId = $_[0];
3082 if(my $Info = $LibInfo{$Version}{"info"}{$TypeId})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003083 {
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04003084 if($LibInfo{$Version}{"info_type"}{$_[0]} eq "integer_type")
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003085 {
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04003086 if(my $Name = getNameByInfo($TypeId))
3087 { # bit_size_type
3088 return $Name;
3089 }
3090 elsif($Info=~/unsigned/) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003091 return "unsigned int";
3092 }
3093 else {
3094 return "int";
3095 }
3096 }
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04003097 elsif($Info=~/name[ ]*:[ ]*@(\d+) /)
3098 {
3099 return getNameByInfo($1);
3100 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003101 }
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04003102 return "";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003103}
3104
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04003105sub isFuncPtr($)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003106{
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04003107 my $Ptd = pointTo($_[0]);
3108 return 0 if(not $Ptd);
3109 if(my $Info = $LibInfo{$Version}{"info"}{$_[0]})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003110 {
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04003111 if($Info=~/unql[ ]*:/ and $Info!~/qual[ ]*:/) {
3112 return 0;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003113 }
3114 }
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04003115 if(my $InfoT1 = $LibInfo{$Version}{"info_type"}{$_[0]}
3116 and my $InfoT2 = $LibInfo{$Version}{"info_type"}{$Ptd})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003117 {
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04003118 if($InfoT1 eq "pointer_type"
3119 and $InfoT2 eq "function_type") {
3120 return 1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003121 }
3122 }
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04003123 return 0;
3124}
3125
3126sub isMethodPtr($)
3127{
3128 my $Ptd = pointTo($_[0]);
3129 return 0 if(not $Ptd);
3130 if(my $Info = $LibInfo{$Version}{"info"}{$_[0]})
3131 {
3132 if($LibInfo{$Version}{"info_type"}{$_[0]} eq "record_type"
3133 and $LibInfo{$Version}{"info_type"}{$Ptd} eq "method_type"
3134 and $Info=~/ ptrmem /) {
3135 return 1;
3136 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003137 }
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04003138 return 0;
3139}
3140
3141sub isFieldPtr($)
3142{
3143 if($_[0] and my $Info = $LibInfo{$Version}{"info"}{$_[0]})
3144 {
3145 if($LibInfo{$Version}{"info_type"}{$_[0]} eq "offset_type"
3146 and $Info=~/ ptrmem /) {
3147 return 1;
3148 }
3149 }
3150 return 0;
3151}
3152
3153sub pointTo($)
3154{
3155 if($_[0] and my $Info = $LibInfo{$Version}{"info"}{$_[0]})
3156 {
3157 if($Info=~/ptd[ ]*:[ ]*@(\d+)/) {
3158 return $1;
3159 }
3160 }
3161 return "";
3162}
3163
3164sub getTypeTypeByTypeId($)
3165{
3166 my $TypeId = $_[0];
3167 if(my $TType = $LibInfo{$Version}{"info_type"}{$TypeId})
3168 {
3169 my $NType = $NodeType{$TType};
3170 if($NType eq "Intrinsic") {
3171 return $NType;
3172 }
3173 elsif(isFuncPtr($TypeId)) {
3174 return "FuncPtr";
3175 }
3176 elsif(isMethodPtr($TypeId)) {
3177 return "MethodPtr";
3178 }
3179 elsif(isFieldPtr($TypeId)) {
3180 return "FieldPtr";
3181 }
3182 elsif($NType ne "Other") {
3183 return $NType;
3184 }
3185 }
3186 return "Unknown";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003187}
3188
3189sub getQual($)
3190{
3191 my $TypeId = $_[0];
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003192 my %UnQual = (
3193 "r"=>"restrict",
3194 "v"=>"volatile",
3195 "c"=>"const",
3196 "cv"=>"const volatile"
3197 );
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04003198 if(my $Info = $LibInfo{$Version}{"info"}{$TypeId})
3199 {
3200 my ($Qual, $To) = ();
3201 if($Info=~/qual[ ]*:[ ]*(r|c|v|cv) /) {
3202 $Qual = $UnQual{$1};
3203 }
3204 if($Info=~/unql[ ]*:[ ]*\@(\d+)/) {
3205 $To = $1;
3206 }
3207 if($Qual and $To) {
3208 return ($Qual, $To);
3209 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003210 }
3211 return ();
3212}
3213
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04003214sub getQualType($)
3215{
3216 if($_[0] eq "const volatile") {
3217 return "ConstVolatile";
3218 }
3219 return ucfirst($_[0]);
3220}
3221
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04003222sub getTypeType($)
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04003223{
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04003224 my $TypeId = $_[0];
3225 my $TypeDeclId = getTypeDeclId($TypeId);
3226 if(defined $MissedTypedef{$Version}{$TypeId})
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04003227 { # support for old GCC versions
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04003228 if($MissedTypedef{$Version}{$TypeId}{"TDid"} eq $TypeDeclId) {
3229 return "Typedef";
3230 }
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04003231 }
3232 my $Info = $LibInfo{$Version}{"info"}{$TypeId};
3233 my ($Qual, $To) = getQual($TypeId);
Andrey Ponomarenko9927e332012-10-19 10:50:48 +04003234 if(($Qual or $To) and $TypeDeclId
3235 and (getTypeId($TypeDeclId) ne $TypeId))
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04003236 { # qualified types (special)
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04003237 return getQualType($Qual);
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04003238 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04003239 elsif(not $MissedBase_R{$Version}{$TypeId}
3240 and isTypedef($TypeId)) {
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04003241 return "Typedef";
3242 }
3243 elsif($Qual)
3244 { # qualified types
3245 return getQualType($Qual);
3246 }
Andrey Ponomarenko9927e332012-10-19 10:50:48 +04003247
3248 if($Info=~/unql[ ]*:[ ]*\@(\d+)/)
3249 { # typedef struct { ... } name
3250 $TypeTypedef{$Version}{$TypeId} = $1;
3251 }
3252
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04003253 my $TypeType = getTypeTypeByTypeId($TypeId);
3254 if($TypeType eq "Struct")
3255 {
3256 if($TypeDeclId
3257 and $LibInfo{$Version}{"info_type"}{$TypeDeclId} eq "template_decl") {
3258 return "Template";
3259 }
3260 }
3261 return $TypeType;
3262}
3263
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04003264sub isTypedef($)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003265{
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04003266 if($_[0] and my $Info = $LibInfo{$Version}{"info"}{$_[0]})
3267 {
3268 my $TDid = getTypeDeclId($_[0]);
3269 if(getNameByInfo($TDid)
3270 and $Info=~/unql[ ]*:[ ]*\@(\d+) /
3271 and getTypeId($TDid) eq $_[0]) {
3272 return $1;
3273 }
3274 }
3275 return 0;
3276}
3277
3278sub selectBaseType($)
3279{
3280 my $TypeId = $_[0];
3281 if(defined $MissedTypedef{$Version}{$TypeId})
3282 { # add missed typedefs
3283 if($MissedTypedef{$Version}{$TypeId}{"TDid"} eq getTypeDeclId($TypeId)) {
3284 return ($TypeId, "");
3285 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003286 }
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04003287 my $Info = $LibInfo{$Version}{"info"}{$TypeId};
3288 my $InfoType = $LibInfo{$Version}{"info_type"}{$TypeId};
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04003289
3290 my $MB_R = $MissedBase_R{$Version}{$TypeId};
3291 my $MB = $MissedBase{$Version}{$TypeId};
3292
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04003293 my ($Qual, $To) = getQual($TypeId);
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04003294 if(($Qual or $To) and $Info=~/name[ ]*:[ ]*\@(\d+) /
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04003295 and (getTypeId($1) ne $TypeId)
3296 and (not $MB_R or getTypeId($1) ne $MB_R))
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04003297 { # qualified types (special)
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04003298 return (getTypeId($1), $Qual);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003299 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04003300 elsif($MB)
3301 { # add base
3302 return ($MB, "");
3303 }
3304 elsif(not $MB_R and my $Bid = isTypedef($TypeId))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003305 { # typedefs
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04003306 return ($Bid, "");
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003307 }
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04003308 elsif($Qual or $To)
3309 { # qualified types
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04003310 return ($To, $Qual);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003311 }
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04003312 elsif($InfoType eq "reference_type")
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003313 {
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04003314 if($Info=~/refd[ ]*:[ ]*@(\d+) /) {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04003315 return ($1, "&");
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003316 }
3317 else {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04003318 return (0, "");
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003319 }
3320 }
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04003321 elsif($InfoType eq "array_type")
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003322 {
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04003323 if($Info=~/elts[ ]*:[ ]*@(\d+) /) {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04003324 return ($1, "");
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003325 }
3326 else {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04003327 return (0, "");
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003328 }
3329 }
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04003330 elsif($InfoType eq "pointer_type")
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003331 {
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04003332 if($Info=~/ptd[ ]*:[ ]*@(\d+) /) {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04003333 return ($1, "*");
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003334 }
3335 else {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04003336 return (0, "");
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003337 }
3338 }
3339 else {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04003340 return (0, "");
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003341 }
3342}
3343
3344sub getSymbolInfo_All()
3345{
3346 foreach (sort {int($b)<=>int($a)} keys(%{$LibInfo{$Version}{"info"}}))
3347 { # reverse order
3348 if($LibInfo{$Version}{"info_type"}{$_} eq "function_decl") {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04003349 getSymbolInfo($_);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003350 }
3351 }
3352}
3353
3354sub getVarInfo_All()
3355{
3356 foreach (sort {int($b)<=>int($a)} keys(%{$LibInfo{$Version}{"info"}}))
3357 { # reverse order
3358 if($LibInfo{$Version}{"info_type"}{$_} eq "var_decl") {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04003359 getVarInfo($_);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003360 }
3361 }
3362}
3363
3364sub isBuiltIn($) {
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04003365 return ($_[0] and $_[0]=~/\<built\-in\>|\<internal\>|\A\./);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003366}
3367
3368sub getVarInfo($)
3369{
3370 my $InfoId = $_[0];
Andrey Ponomarenko01117f12012-06-26 12:23:02 +04003371 if(my $NSid = getTreeAttr_Scpe($InfoId))
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04003372 {
3373 my $NSInfoType = $LibInfo{$Version}{"info_type"}{$NSid};
3374 if($NSInfoType and $NSInfoType eq "function_decl") {
3375 return;
3376 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003377 }
3378 ($SymbolInfo{$Version}{$InfoId}{"Header"}, $SymbolInfo{$Version}{$InfoId}{"Line"}) = getLocation($InfoId);
3379 if(not $SymbolInfo{$Version}{$InfoId}{"Header"}
3380 or isBuiltIn($SymbolInfo{$Version}{$InfoId}{"Header"})) {
3381 delete($SymbolInfo{$Version}{$InfoId});
3382 return;
3383 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04003384 my $ShortName = getTreeStr(getTreeAttr_Name($InfoId));
Andrey Ponomarenko85043792012-05-14 16:48:07 +04003385 if(not $ShortName) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003386 delete($SymbolInfo{$Version}{$InfoId});
3387 return;
3388 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +04003389 if($ShortName=~/\Atmp_add_class_\d+\Z/) {
3390 delete($SymbolInfo{$Version}{$InfoId});
3391 return;
3392 }
3393 $SymbolInfo{$Version}{$InfoId}{"ShortName"} = $ShortName;
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +04003394 if(my $MnglName = getTreeStr(getTreeAttr_Mngl($InfoId)))
3395 {
3396 if($OSgroup eq "windows")
3397 { # cut the offset
3398 $MnglName=~s/\@\d+\Z//g;
3399 }
3400 $SymbolInfo{$Version}{$InfoId}{"MnglName"} = $MnglName;
3401 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003402 if($SymbolInfo{$Version}{$InfoId}{"MnglName"}
Andrey Ponomarenko9927e332012-10-19 10:50:48 +04003403 and index($SymbolInfo{$Version}{$InfoId}{"MnglName"}, "_Z")!=0)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003404 { # validate mangled name
3405 delete($SymbolInfo{$Version}{$InfoId});
3406 return;
3407 }
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04003408 if(not $SymbolInfo{$Version}{$InfoId}{"MnglName"}
Andrey Ponomarenko9927e332012-10-19 10:50:48 +04003409 and index($ShortName, "_Z")==0)
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04003410 { # _ZTS, etc.
Andrey Ponomarenko85043792012-05-14 16:48:07 +04003411 $SymbolInfo{$Version}{$InfoId}{"MnglName"} = $ShortName;
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04003412 }
3413 if(isPrivateData($SymbolInfo{$Version}{$InfoId}{"MnglName"}))
3414 { # non-public global data
3415 delete($SymbolInfo{$Version}{$InfoId});
3416 return;
3417 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003418 $SymbolInfo{$Version}{$InfoId}{"Data"} = 1;
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04003419 if(my $Rid = getTypeId($InfoId))
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04003420 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04003421 if(not $TypeInfo{$Version}{$Rid}{"Name"})
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04003422 { # typename_type
3423 delete($SymbolInfo{$Version}{$InfoId});
3424 return;
3425 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04003426 $SymbolInfo{$Version}{$InfoId}{"Return"} = $Rid;
3427 my $Val = getDataVal($InfoId, $Rid);
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04003428 if(defined $Val) {
3429 $SymbolInfo{$Version}{$InfoId}{"Value"} = $Val;
3430 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003431 }
3432 set_Class_And_Namespace($InfoId);
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04003433 if(my $ClassId = $SymbolInfo{$Version}{$InfoId}{"Class"})
3434 {
3435 if(not $TypeInfo{$Version}{$ClassId}{"Name"})
3436 { # templates
3437 delete($SymbolInfo{$Version}{$InfoId});
3438 return;
3439 }
3440 }
Andrey Ponomarenko35c44fd2012-06-18 17:50:25 +04003441 if($LibInfo{$Version}{"info"}{$InfoId}=~/ lang:[ ]*C /i)
3442 { # extern "C"
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003443 $SymbolInfo{$Version}{$InfoId}{"Lang"} = "C";
Andrey Ponomarenko35c44fd2012-06-18 17:50:25 +04003444 $SymbolInfo{$Version}{$InfoId}{"MnglName"} = $ShortName;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003445 }
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04003446 if($UserLang and $UserLang eq "C")
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003447 { # --lang=C option
Andrey Ponomarenko85043792012-05-14 16:48:07 +04003448 $SymbolInfo{$Version}{$InfoId}{"MnglName"} = $ShortName;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003449 }
Andrey Ponomarenko5c09ef32012-06-14 18:17:33 +04003450 if(not $CheckHeadersOnly)
3451 {
3452 if(not $SymbolInfo{$Version}{$InfoId}{"Class"})
3453 {
3454 if(not $SymbolInfo{$Version}{$InfoId}{"MnglName"}
3455 or not link_symbol($SymbolInfo{$Version}{$InfoId}{"MnglName"}, $Version, "-Deps"))
3456 {
3457 if(link_symbol($ShortName, $Version, "-Deps"))
3458 { # "const" global data is mangled as _ZL... in the TU dump
3459 # but not mangled when compiling a C shared library
3460 $SymbolInfo{$Version}{$InfoId}{"MnglName"} = $ShortName;
3461 }
3462 }
3463 }
3464 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003465 if($COMMON_LANGUAGE{$Version} eq "C++")
3466 {
3467 if(not $SymbolInfo{$Version}{$InfoId}{"MnglName"})
3468 { # for some symbols (_ZTI) the short name is the mangled name
Andrey Ponomarenko9927e332012-10-19 10:50:48 +04003469 if(index($ShortName, "_Z")==0) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003470 $SymbolInfo{$Version}{$InfoId}{"MnglName"} = $ShortName;
3471 }
3472 }
3473 if(not $SymbolInfo{$Version}{$InfoId}{"MnglName"})
3474 { # try to mangle symbol (link with libraries)
3475 $SymbolInfo{$Version}{$InfoId}{"MnglName"} = linkSymbol($InfoId);
3476 }
3477 if($OStarget eq "windows")
3478 {
3479 if(my $Mangled = $mangled_name{$Version}{modelUnmangled($InfoId, "MSVC")})
3480 { # link MS C++ symbols from library with GCC symbols from headers
3481 $SymbolInfo{$Version}{$InfoId}{"MnglName"} = $Mangled;
3482 }
3483 }
3484 }
3485 if(not $SymbolInfo{$Version}{$InfoId}{"MnglName"}) {
3486 $SymbolInfo{$Version}{$InfoId}{"MnglName"} = $ShortName;
3487 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +04003488 if(my $Symbol = $SymbolInfo{$Version}{$InfoId}{"MnglName"})
3489 {
3490 if(not selectSymbol($Symbol, $SymbolInfo{$Version}{$InfoId}, "Dump", $Version))
3491 { # non-target symbols
3492 delete($SymbolInfo{$Version}{$InfoId});
3493 return;
3494 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003495 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04003496 if(my $Rid = $SymbolInfo{$Version}{$InfoId}{"Return"})
3497 {
3498 if(defined $MissedTypedef{$Version}{$Rid})
3499 {
3500 if(my $AddedTid = $MissedTypedef{$Version}{$Rid}{"Tid"}) {
3501 $SymbolInfo{$Version}{$InfoId}{"Return"} = $AddedTid;
3502 }
3503 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003504 }
3505 setFuncAccess($InfoId);
Andrey Ponomarenko9927e332012-10-19 10:50:48 +04003506 if(index($SymbolInfo{$Version}{$InfoId}{"MnglName"}, "_ZTV")==0) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003507 delete($SymbolInfo{$Version}{$InfoId}{"Return"});
3508 }
3509 if($ShortName=~/\A(_Z|\?)/) {
3510 delete($SymbolInfo{$Version}{$InfoId}{"ShortName"});
3511 }
3512}
3513
Andrey Ponomarenko85043792012-05-14 16:48:07 +04003514sub isConstType($$)
3515{
3516 my ($TypeId, $LibVersion) = @_;
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04003517 my %Base = get_Type($TypeId, $LibVersion);
Andrey Ponomarenko85043792012-05-14 16:48:07 +04003518 while(defined $Base{"Type"} and $Base{"Type"} eq "Typedef") {
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +04003519 %Base = get_OneStep_BaseType($Base{"Tid"}, $TypeInfo{$LibVersion});
Andrey Ponomarenko85043792012-05-14 16:48:07 +04003520 }
3521 return ($Base{"Type"} eq "Const");
3522}
3523
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003524sub getTrivialName($$)
3525{
3526 my ($TypeInfoId, $TypeId) = @_;
3527 my %TypeAttr = ();
3528 $TypeAttr{"Name"} = getNameByInfo($TypeInfoId);
3529 if(not $TypeAttr{"Name"}) {
3530 $TypeAttr{"Name"} = getTreeTypeName($TypeId);
3531 }
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04003532 ($TypeAttr{"Header"}, $TypeAttr{"Line"}) = getLocation($TypeInfoId);
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04003533 $TypeAttr{"Type"} = getTypeType($TypeId);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003534 $TypeAttr{"Name"}=~s/<(.+)\Z//g; # GCC 3.4.4 add template params to the name
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04003535 if(isAnon($TypeAttr{"Name"}))
3536 {
3537 my $NameSpaceId = $TypeId;
Andrey Ponomarenko01117f12012-06-26 12:23:02 +04003538 while(my $NSId = getTreeAttr_Scpe(getTypeDeclId($NameSpaceId)))
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04003539 { # searching for a first not anon scope
3540 if($NSId eq $NameSpaceId) {
3541 last;
3542 }
3543 else
3544 {
3545 $TypeAttr{"NameSpace"} = getNameSpace(getTypeDeclId($TypeId));
3546 if(not $TypeAttr{"NameSpace"}
3547 or isNotAnon($TypeAttr{"NameSpace"})) {
3548 last;
3549 }
3550 }
3551 $NameSpaceId=$NSId;
3552 }
3553 }
3554 else
3555 {
Andrey Ponomarenko01117f12012-06-26 12:23:02 +04003556 if(my $NameSpaceId = getTreeAttr_Scpe($TypeInfoId))
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04003557 {
3558 if($NameSpaceId ne $TypeId) {
3559 $TypeAttr{"NameSpace"} = getNameSpace($TypeInfoId);
3560 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003561 }
3562 }
3563 if($TypeAttr{"NameSpace"} and isNotAnon($TypeAttr{"Name"})) {
3564 $TypeAttr{"Name"} = $TypeAttr{"NameSpace"}."::".$TypeAttr{"Name"};
3565 }
Andrey Ponomarenko9927e332012-10-19 10:50:48 +04003566 $TypeAttr{"Name"} = formatName($TypeAttr{"Name"}, "T");
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003567 if(isAnon($TypeAttr{"Name"}))
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04003568 { # anon-struct-header.h-line
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04003569 $TypeAttr{"Name"} = "anon-".lc($TypeAttr{"Type"})."-";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003570 $TypeAttr{"Name"} .= $TypeAttr{"Header"}."-".$TypeAttr{"Line"};
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04003571 if($TypeAttr{"NameSpace"}) {
3572 $TypeAttr{"Name"} = $TypeAttr{"NameSpace"}."::".$TypeAttr{"Name"};
3573 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003574 }
Andrey Ponomarenkob8d203d2012-05-25 18:11:07 +04003575 if(defined $TemplateInstance{$Version}{"Type"}{$TypeId}
3576 and getTypeDeclId($TypeId) eq $TypeInfoId)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003577 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04003578 my @TParams = getTParams($TypeId, "Type");
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003579 if(not @TParams)
3580 { # template declarations with abstract params
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003581 return ("", "");
3582 }
Andrey Ponomarenko9927e332012-10-19 10:50:48 +04003583 $TypeAttr{"Name"} = formatName($TypeAttr{"Name"}."< ".join(", ", @TParams)." >", "T");
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003584 }
3585 return ($TypeAttr{"Name"}, $TypeAttr{"NameSpace"});
3586}
3587
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04003588sub getTrivialTypeAttr($)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003589{
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04003590 my $TypeId = $_[0];
3591 my $TypeInfoId = getTypeDeclId($_[0]);
Andrey Ponomarenko85043792012-05-14 16:48:07 +04003592
3593 if($TemplateDecl{$Version}{$TypeId})
3594 { # template_decl
3595 return ();
3596 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04003597 if(my $ScopeId = getTreeAttr_Scpe($TypeInfoId))
3598 {
3599 if($TemplateDecl{$Version}{$ScopeId})
3600 { # template_decl
3601 return ();
3602 }
3603 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +04003604
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003605 my %TypeAttr = ();
3606 if(getTypeTypeByTypeId($TypeId)!~/\A(Intrinsic|Union|Struct|Enum|Class)\Z/) {
3607 return ();
3608 }
3609 setTypeAccess($TypeId, \%TypeAttr);
3610 ($TypeAttr{"Header"}, $TypeAttr{"Line"}) = getLocation($TypeInfoId);
3611 if(isBuiltIn($TypeAttr{"Header"}))
3612 {
3613 delete($TypeAttr{"Header"});
3614 delete($TypeAttr{"Line"});
3615 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04003616 $TypeAttr{"Type"} = getTypeType($TypeId);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003617 ($TypeAttr{"Name"}, $TypeAttr{"NameSpace"}) = getTrivialName($TypeInfoId, $TypeId);
3618 if(not $TypeAttr{"Name"}) {
3619 return ();
3620 }
3621 if(not $TypeAttr{"NameSpace"}) {
3622 delete($TypeAttr{"NameSpace"});
3623 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04003624 if(defined $TemplateInstance{$Version}{"Type"}{$TypeId})
Andrey Ponomarenko16934472012-03-29 15:37:04 +04003625 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04003626 if(my @TParams = getTParams($TypeId, "Type"))
Andrey Ponomarenko16934472012-03-29 15:37:04 +04003627 {
3628 foreach my $Pos (0 .. $#TParams) {
3629 $TypeAttr{"TParam"}{$Pos}{"name"}=$TParams[$Pos];
3630 }
3631 }
3632 }
Andrey Ponomarenko01117f12012-06-26 12:23:02 +04003633 if(my $Size = getSize($TypeId))
3634 {
3635 $Size = $Size/$BYTE_SIZE;
3636 $TypeAttr{"Size"} = "$Size";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003637 }
Andrey Ponomarenko9927e332012-10-19 10:50:48 +04003638 else
3639 { # declaration only
3640 $TypeAttr{"Forward"} = 1;
3641 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003642 if($TypeAttr{"Type"} eq "Struct"
3643 and detect_lang($TypeId))
3644 {
3645 $TypeAttr{"Type"} = "Class";
Andrey Ponomarenko85043792012-05-14 16:48:07 +04003646 $TypeAttr{"Copied"} = 1; # default, will be changed in getSymbolInfo()
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003647 }
3648 if($TypeAttr{"Type"} eq "Struct"
Andrey Ponomarenko85043792012-05-14 16:48:07 +04003649 or $TypeAttr{"Type"} eq "Class")
3650 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04003651 my $Skip = setBaseClasses($TypeId, \%TypeAttr);
Andrey Ponomarenko85043792012-05-14 16:48:07 +04003652 if($Skip) {
3653 return ();
3654 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003655 }
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +04003656 if(my $Algn = getAlgn($TypeId)) {
3657 $TypeAttr{"Algn"} = $Algn/$BYTE_SIZE;
3658 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003659 setSpec($TypeId, \%TypeAttr);
3660 setTypeMemb($TypeId, \%TypeAttr);
3661 $TypeAttr{"Tid"} = $TypeId;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003662 if(my $VTable = $ClassVTable_Content{$Version}{$TypeAttr{"Name"}})
3663 {
3664 my @Entries = split(/\n/, $VTable);
3665 foreach (1 .. $#Entries)
3666 {
3667 my $Entry = $Entries[$_];
3668 if($Entry=~/\A(\d+)\s+(.+)\Z/) {
3669 $TypeAttr{"VTable"}{$1} = $2;
3670 }
3671 }
3672 }
3673 return %TypeAttr;
3674}
3675
3676sub detect_lang($)
3677{
3678 my $TypeId = $_[0];
3679 my $Info = $LibInfo{$Version}{"info"}{$TypeId};
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04003680 if(check_gcc($GCC_PATH, "4"))
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04003681 { # GCC 4 fncs-node points to only non-artificial methods
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003682 return ($Info=~/(fncs)[ ]*:[ ]*@(\d+) /);
3683 }
3684 else
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04003685 { # GCC 3
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04003686 my $Fncs = getTreeAttr_Fncs($TypeId);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003687 while($Fncs)
3688 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04003689 if($LibInfo{$Version}{"info"}{$Fncs}!~/artificial/) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003690 return 1;
3691 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04003692 $Fncs = getTreeAttr_Chan($Fncs);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003693 }
3694 }
3695 return 0;
3696}
3697
3698sub setSpec($$)
3699{
3700 my ($TypeId, $TypeAttr) = @_;
3701 my $Info = $LibInfo{$Version}{"info"}{$TypeId};
3702 if($Info=~/\s+spec\s+/) {
3703 $TypeAttr->{"Spec"} = 1;
3704 }
3705}
3706
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04003707sub setBaseClasses($$)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003708{
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04003709 my ($TypeId, $TypeAttr) = @_;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003710 my $Info = $LibInfo{$Version}{"info"}{$TypeId};
3711 if($Info=~/binf[ ]*:[ ]*@(\d+) /)
3712 {
3713 $Info = $LibInfo{$Version}{"info"}{$1};
3714 my $Pos = 0;
3715 while($Info=~s/(pub|public|prot|protected|priv|private|)[ ]+binf[ ]*:[ ]*@(\d+) //)
3716 {
3717 my ($Access, $BInfoId) = ($1, $2);
3718 my $ClassId = getBinfClassId($BInfoId);
Andrey Ponomarenko85043792012-05-14 16:48:07 +04003719 my $CType = $LibInfo{$Version}{"info_type"}{$ClassId};
3720 if(not $CType or $CType eq "template_type_parm"
3721 or $CType eq "typename_type")
3722 { # skip
3723 return 1;
3724 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003725 my $BaseInfo = $LibInfo{$Version}{"info"}{$BInfoId};
3726 if($Access=~/prot/)
3727 {
3728 $TypeAttr->{"Base"}{$ClassId}{"access"} = "protected";
3729 }
3730 elsif($Access=~/priv/)
3731 {
3732 $TypeAttr->{"Base"}{$ClassId}{"access"} = "private";
3733 }
Andrey Ponomarenko01117f12012-06-26 12:23:02 +04003734 $TypeAttr->{"Base"}{$ClassId}{"pos"} = "$Pos";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003735 if($BaseInfo=~/virt/)
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04003736 { # virtual base
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003737 $TypeAttr->{"Base"}{$ClassId}{"virtual"} = 1;
3738 }
3739 $Class_SubClasses{$Version}{$ClassId}{$TypeId}=1;
Andrey Ponomarenko01117f12012-06-26 12:23:02 +04003740 $Pos+=1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003741 }
3742 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +04003743 return 0;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003744}
3745
3746sub getBinfClassId($)
3747{
3748 my $Info = $LibInfo{$Version}{"info"}{$_[0]};
3749 $Info=~/type[ ]*:[ ]*@(\d+) /;
3750 return $1;
3751}
3752
3753sub unmangledFormat($$)
3754{
3755 my ($Name, $LibVersion) = @_;
3756 $Name = uncover_typedefs($Name, $LibVersion);
3757 while($Name=~s/([^\w>*])(const|volatile)(,|>|\Z)/$1$3/g){};
3758 $Name=~s/\(\w+\)(\d)/$1/;
3759 return $Name;
3760}
3761
3762sub modelUnmangled($$)
3763{
3764 my ($InfoId, $Compiler) = @_;
3765 if($Cache{"modelUnmangled"}{$Version}{$Compiler}{$InfoId}) {
3766 return $Cache{"modelUnmangled"}{$Version}{$Compiler}{$InfoId};
3767 }
3768 my $PureSignature = $SymbolInfo{$Version}{$InfoId}{"ShortName"};
3769 if($SymbolInfo{$Version}{$InfoId}{"Destructor"}) {
3770 $PureSignature = "~".$PureSignature;
3771 }
3772 if(not $SymbolInfo{$Version}{$InfoId}{"Data"})
3773 {
3774 my (@Params, @ParamTypes) = ();
3775 if(defined $SymbolInfo{$Version}{$InfoId}{"Param"}
3776 and not $SymbolInfo{$Version}{$InfoId}{"Destructor"}) {
3777 @Params = keys(%{$SymbolInfo{$Version}{$InfoId}{"Param"}});
3778 }
3779 foreach my $ParamPos (sort {int($a) <=> int($b)} @Params)
3780 { # checking parameters
3781 my $PId = $SymbolInfo{$Version}{$InfoId}{"Param"}{$ParamPos}{"type"};
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +04003782 my %PType = get_PureType($PId, $TypeInfo{$Version});
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003783 my $PTName = unmangledFormat($PType{"Name"}, $Version);
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04003784 $PTName=~s/\b(restrict|register)\b//g;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003785 if($Compiler eq "MSVC") {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04003786 $PTName=~s/\blong long\b/__int64/;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003787 }
3788 @ParamTypes = (@ParamTypes, $PTName);
3789 }
3790 if(@ParamTypes) {
3791 $PureSignature .= "(".join(", ", @ParamTypes).")";
3792 }
3793 else
3794 {
3795 if($Compiler eq "MSVC")
3796 {
3797 $PureSignature .= "(void)";
3798 }
3799 else
3800 { # GCC
3801 $PureSignature .= "()";
3802 }
3803 }
3804 $PureSignature = delete_keywords($PureSignature);
3805 }
3806 if(my $ClassId = $SymbolInfo{$Version}{$InfoId}{"Class"})
3807 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04003808 my $ClassName = unmangledFormat($TypeInfo{$Version}{$ClassId}{"Name"}, $Version);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003809 $PureSignature = $ClassName."::".$PureSignature;
3810 }
3811 elsif(my $NS = $SymbolInfo{$Version}{$InfoId}{"NameSpace"}) {
3812 $PureSignature = $NS."::".$PureSignature;
3813 }
3814 if($SymbolInfo{$Version}{$InfoId}{"Const"}) {
3815 $PureSignature .= " const";
3816 }
3817 if($SymbolInfo{$Version}{$InfoId}{"Volatile"}) {
3818 $PureSignature .= " volatile";
3819 }
3820 my $ShowReturn = 0;
3821 if($Compiler eq "MSVC"
3822 and $SymbolInfo{$Version}{$InfoId}{"Data"})
3823 {
3824 $ShowReturn=1;
3825 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04003826 elsif(defined $TemplateInstance{$Version}{"Func"}{$InfoId}
3827 and keys(%{$TemplateInstance{$Version}{"Func"}{$InfoId}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003828 {
3829 $ShowReturn=1;
3830 }
3831 if($ShowReturn)
3832 { # mangled names for template function specializations include return value
3833 if(my $ReturnId = $SymbolInfo{$Version}{$InfoId}{"Return"})
3834 {
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +04003835 my %RType = get_PureType($ReturnId, $TypeInfo{$Version});
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003836 my $ReturnName = unmangledFormat($RType{"Name"}, $Version);
3837 $PureSignature = $ReturnName." ".$PureSignature;
3838 }
3839 }
Andrey Ponomarenko9927e332012-10-19 10:50:48 +04003840 return ($Cache{"modelUnmangled"}{$Version}{$Compiler}{$InfoId} = formatName($PureSignature, "S"));
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003841}
3842
3843sub mangle_symbol($$$)
3844{ # mangling for simple methods
3845 # see gcc-4.6.0/gcc/cp/mangle.c
3846 my ($InfoId, $LibVersion, $Compiler) = @_;
3847 if($Cache{"mangle_symbol"}{$LibVersion}{$InfoId}{$Compiler}) {
3848 return $Cache{"mangle_symbol"}{$LibVersion}{$InfoId}{$Compiler};
3849 }
3850 my $Mangled = "";
3851 if($Compiler eq "GCC") {
Andrey Ponomarenko16934472012-03-29 15:37:04 +04003852 $Mangled = mangle_symbol_GCC($InfoId, $LibVersion);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003853 }
3854 elsif($Compiler eq "MSVC") {
Andrey Ponomarenko16934472012-03-29 15:37:04 +04003855 $Mangled = mangle_symbol_MSVC($InfoId, $LibVersion);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003856 }
3857 return ($Cache{"mangle_symbol"}{$LibVersion}{$InfoId}{$Compiler} = $Mangled);
3858}
3859
Andrey Ponomarenko16934472012-03-29 15:37:04 +04003860sub mangle_symbol_MSVC($$)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003861{
3862 my ($InfoId, $LibVersion) = @_;
3863 return "";
3864}
3865
Andrey Ponomarenko16934472012-03-29 15:37:04 +04003866sub mangle_symbol_GCC($$)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003867{ # see gcc-4.6.0/gcc/cp/mangle.c
3868 my ($InfoId, $LibVersion) = @_;
3869 my ($Mangled, $ClassId, $NameSpace) = ("_Z", 0, "");
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04003870 my $Return = $SymbolInfo{$LibVersion}{$InfoId}{"Return"};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003871 my %Repl = ();# SN_ replacements
3872 if($ClassId = $SymbolInfo{$LibVersion}{$InfoId}{"Class"})
3873 {
3874 my $MangledClass = mangle_param($ClassId, $LibVersion, \%Repl);
3875 if($MangledClass!~/\AN/) {
3876 $MangledClass = "N".$MangledClass;
3877 }
3878 else {
3879 $MangledClass=~s/E\Z//;
3880 }
3881 if($SymbolInfo{$LibVersion}{$InfoId}{"Volatile"}) {
3882 $MangledClass=~s/\AN/NV/;
3883 }
3884 if($SymbolInfo{$LibVersion}{$InfoId}{"Const"}) {
3885 $MangledClass=~s/\AN/NK/;
3886 }
3887 $Mangled .= $MangledClass;
3888 }
3889 elsif($NameSpace = $SymbolInfo{$LibVersion}{$InfoId}{"NameSpace"})
3890 { # mangled by name due to the absence of structured info
3891 my $MangledNS = mangle_ns($NameSpace, $LibVersion, \%Repl);
3892 if($MangledNS!~/\AN/) {
3893 $MangledNS = "N".$MangledNS;
3894 }
3895 else {
3896 $MangledNS=~s/E\Z//;
3897 }
3898 $Mangled .= $MangledNS;
3899 }
Andrey Ponomarenko07aea072012-11-12 16:15:07 +04003900 my ($ShortName, $TmplParams) = template_Base($SymbolInfo{$LibVersion}{$InfoId}{"ShortName"});
Andrey Ponomarenko16934472012-03-29 15:37:04 +04003901 my @TParams = ();
Andrey Ponomarenko35c44fd2012-06-18 17:50:25 +04003902 if(my @TPos = keys(%{$SymbolInfo{$LibVersion}{$InfoId}{"TParam"}}))
Andrey Ponomarenko16934472012-03-29 15:37:04 +04003903 { # parsing mode
Andrey Ponomarenko35c44fd2012-06-18 17:50:25 +04003904 foreach (@TPos) {
3905 push(@TParams, $SymbolInfo{$LibVersion}{$InfoId}{"TParam"}{$_}{"name"});
3906 }
Andrey Ponomarenko16934472012-03-29 15:37:04 +04003907 }
3908 elsif($TmplParams)
3909 { # remangling mode
3910 # support for old ABI dumps
Andrey Ponomarenko07aea072012-11-12 16:15:07 +04003911 @TParams = separate_Params($TmplParams, 0, 0);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003912 }
3913 if($SymbolInfo{$LibVersion}{$InfoId}{"Constructor"}) {
3914 $Mangled .= "C1";
3915 }
3916 elsif($SymbolInfo{$LibVersion}{$InfoId}{"Destructor"}) {
3917 $Mangled .= "D0";
3918 }
3919 elsif($ShortName)
3920 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04003921 if($SymbolInfo{$LibVersion}{$InfoId}{"Data"})
3922 {
Andrey Ponomarenko16934472012-03-29 15:37:04 +04003923 if(not $SymbolInfo{$LibVersion}{$InfoId}{"Class"}
Andrey Ponomarenko85043792012-05-14 16:48:07 +04003924 and isConstType($Return, $LibVersion))
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04003925 { # "const" global data is mangled as _ZL...
3926 $Mangled .= "L";
3927 }
3928 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003929 if($ShortName=~/\Aoperator(\W.*)\Z/)
3930 {
3931 my $Op = $1;
3932 $Op=~s/\A[ ]+//g;
3933 if(my $OpMngl = $OperatorMangling{$Op}) {
3934 $Mangled .= $OpMngl;
3935 }
3936 else { # conversion operator
3937 $Mangled .= "cv".mangle_param(getTypeIdByName($Op, $LibVersion), $LibVersion, \%Repl);
3938 }
3939 }
3940 else {
3941 $Mangled .= length($ShortName).$ShortName;
3942 }
3943 if(@TParams)
3944 { # templates
3945 $Mangled .= "I";
Andrey Ponomarenko07aea072012-11-12 16:15:07 +04003946 my $FP = $TParams[0];
3947 foreach my $TPos (0 .. $#TParams)
3948 {
3949 my $TParam = $TParams[$TPos];
3950 if($TPos>=1)
3951 {
3952 if($TParam=~/\A$DEFAULT_STD_PARMS<\Q$FP\E>\Z/)
3953 { # default allocators are not mangled
3954 next;
3955 }
3956 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003957 $Mangled .= mangle_template_param($TParam, $LibVersion, \%Repl);
3958 }
3959 $Mangled .= "E";
3960 }
3961 if(not $ClassId and @TParams) {
3962 add_substitution($ShortName, \%Repl, 0);
3963 }
3964 }
3965 if($ClassId or $NameSpace) {
3966 $Mangled .= "E";
3967 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +04003968 if(@TParams)
3969 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04003970 if($Return) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003971 $Mangled .= mangle_param($Return, $LibVersion, \%Repl);
3972 }
3973 }
3974 if(not $SymbolInfo{$LibVersion}{$InfoId}{"Data"})
3975 {
3976 my @Params = ();
3977 if(defined $SymbolInfo{$LibVersion}{$InfoId}{"Param"}
3978 and not $SymbolInfo{$LibVersion}{$InfoId}{"Destructor"}) {
3979 @Params = keys(%{$SymbolInfo{$LibVersion}{$InfoId}{"Param"}});
3980 }
3981 foreach my $ParamPos (sort {int($a) <=> int($b)} @Params)
3982 { # checking parameters
3983 my $ParamType_Id = $SymbolInfo{$LibVersion}{$InfoId}{"Param"}{$ParamPos}{"type"};
3984 $Mangled .= mangle_param($ParamType_Id, $LibVersion, \%Repl);
3985 }
3986 if(not @Params) {
3987 $Mangled .= "v";
3988 }
3989 }
3990 $Mangled = correct_incharge($InfoId, $LibVersion, $Mangled);
3991 $Mangled = write_stdcxx_substitution($Mangled);
3992 if($Mangled eq "_Z") {
3993 return "";
3994 }
3995 return $Mangled;
3996}
3997
3998sub correct_incharge($$$)
3999{
4000 my ($InfoId, $LibVersion, $Mangled) = @_;
4001 if($SymbolInfo{$LibVersion}{$InfoId}{"Constructor"})
4002 {
4003 if($MangledNames{$LibVersion}{$Mangled}) {
4004 $Mangled=~s/C1E/C2E/;
4005 }
4006 }
4007 elsif($SymbolInfo{$LibVersion}{$InfoId}{"Destructor"})
4008 {
4009 if($MangledNames{$LibVersion}{$Mangled}) {
4010 $Mangled=~s/D0E/D1E/;
4011 }
4012 if($MangledNames{$LibVersion}{$Mangled}) {
4013 $Mangled=~s/D1E/D2E/;
4014 }
4015 }
4016 return $Mangled;
4017}
4018
Andrey Ponomarenko07aea072012-11-12 16:15:07 +04004019sub template_Base($)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004020{ # NOTE: std::_Vector_base<mysqlpp::mysql_type_info>::_Vector_impl
Andrey Ponomarenko16934472012-03-29 15:37:04 +04004021 # NOTE: operators: >>, <<
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004022 my $Name = $_[0];
Andrey Ponomarenko16934472012-03-29 15:37:04 +04004023 if($Name!~/>\Z/ or $Name!~/</) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004024 return $Name;
4025 }
4026 my $TParams = $Name;
Andrey Ponomarenko16934472012-03-29 15:37:04 +04004027 while(my $CPos = find_center($TParams, "<"))
4028 { # search for the last <T>
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004029 $TParams = substr($TParams, $CPos);
4030 }
Andrey Ponomarenko16934472012-03-29 15:37:04 +04004031 if($TParams=~s/\A<(.+)>\Z/$1/) {
4032 $Name=~s/<\Q$TParams\E>\Z//;
4033 }
4034 else
4035 { # error
4036 $TParams = "";
4037 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004038 return ($Name, $TParams);
4039}
4040
4041sub get_sub_ns($)
4042{
4043 my $Name = $_[0];
4044 my @NS = ();
Andrey Ponomarenko16934472012-03-29 15:37:04 +04004045 while(my $CPos = find_center($Name, ":"))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004046 {
4047 push(@NS, substr($Name, 0, $CPos));
4048 $Name = substr($Name, $CPos);
4049 $Name=~s/\A:://;
4050 }
4051 return (join("::", @NS), $Name);
4052}
4053
4054sub mangle_ns($$$)
4055{
4056 my ($Name, $LibVersion, $Repl) = @_;
4057 if(my $Tid = $TName_Tid{$LibVersion}{$Name})
4058 {
4059 my $Mangled = mangle_param($Tid, $LibVersion, $Repl);
4060 $Mangled=~s/\AN(.+)E\Z/$1/;
4061 return $Mangled;
4062
4063 }
4064 else
4065 {
4066 my ($MangledNS, $SubNS) = ("", "");
4067 ($SubNS, $Name) = get_sub_ns($Name);
4068 if($SubNS) {
4069 $MangledNS .= mangle_ns($SubNS, $LibVersion, $Repl);
4070 }
4071 $MangledNS .= length($Name).$Name;
4072 add_substitution($MangledNS, $Repl, 0);
4073 return $MangledNS;
4074 }
4075}
4076
4077sub mangle_param($$$)
4078{
4079 my ($PTid, $LibVersion, $Repl) = @_;
4080 my ($MPrefix, $Mangled) = ("", "");
4081 my %ReplCopy = %{$Repl};
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04004082 my %BaseType = get_BaseType($PTid, $LibVersion);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004083 my $BaseType_Name = $BaseType{"Name"};
4084 if(not $BaseType_Name) {
4085 return "";
4086 }
Andrey Ponomarenko07aea072012-11-12 16:15:07 +04004087 my ($ShortName, $TmplParams) = template_Base($BaseType_Name);
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04004088 my $Suffix = get_BaseTypeQual($PTid, $LibVersion);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004089 while($Suffix=~s/\s*(const|volatile|restrict)\Z//g){};
4090 while($Suffix=~/(&|\*|const)\Z/)
4091 {
4092 if($Suffix=~s/[ ]*&\Z//) {
4093 $MPrefix .= "R";
4094 }
4095 if($Suffix=~s/[ ]*\*\Z//) {
4096 $MPrefix .= "P";
4097 }
4098 if($Suffix=~s/[ ]*const\Z//)
4099 {
4100 if($MPrefix=~/R|P/
4101 or $Suffix=~/&|\*/) {
4102 $MPrefix .= "K";
4103 }
4104 }
4105 if($Suffix=~s/[ ]*volatile\Z//) {
4106 $MPrefix .= "V";
4107 }
4108 #if($Suffix=~s/[ ]*restrict\Z//) {
4109 #$MPrefix .= "r";
4110 #}
4111 }
4112 if(my $Token = $IntrinsicMangling{$BaseType_Name}) {
4113 $Mangled .= $Token;
4114 }
4115 elsif($BaseType{"Type"}=~/(Class|Struct|Union|Enum)/)
4116 {
Andrey Ponomarenko16934472012-03-29 15:37:04 +04004117 my @TParams = ();
Andrey Ponomarenko35c44fd2012-06-18 17:50:25 +04004118 if(my @TPos = keys(%{$BaseType{"TParam"}}))
Andrey Ponomarenko16934472012-03-29 15:37:04 +04004119 { # parsing mode
Andrey Ponomarenko35c44fd2012-06-18 17:50:25 +04004120 foreach (@TPos) {
4121 push(@TParams, $BaseType{"TParam"}{$_}{"name"});
4122 }
Andrey Ponomarenko16934472012-03-29 15:37:04 +04004123 }
4124 elsif($TmplParams)
4125 { # remangling mode
4126 # support for old ABI dumps
Andrey Ponomarenko07aea072012-11-12 16:15:07 +04004127 @TParams = separate_Params($TmplParams, 0, 0);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004128 }
4129 my $MangledNS = "";
4130 my ($SubNS, $SName) = get_sub_ns($ShortName);
4131 if($SubNS) {
4132 $MangledNS .= mangle_ns($SubNS, $LibVersion, $Repl);
4133 }
4134 $MangledNS .= length($SName).$SName;
4135 if(@TParams) {
4136 add_substitution($MangledNS, $Repl, 0);
4137 }
4138 $Mangled .= "N".$MangledNS;
4139 if(@TParams)
4140 { # templates
4141 $Mangled .= "I";
4142 foreach my $TParam (@TParams) {
4143 $Mangled .= mangle_template_param($TParam, $LibVersion, $Repl);
4144 }
4145 $Mangled .= "E";
4146 }
4147 $Mangled .= "E";
4148 }
4149 elsif($BaseType{"Type"}=~/(FuncPtr|MethodPtr)/)
4150 {
4151 if($BaseType{"Type"} eq "MethodPtr") {
4152 $Mangled .= "M".mangle_param($BaseType{"Class"}, $LibVersion, $Repl)."F";
4153 }
4154 else {
4155 $Mangled .= "PF";
4156 }
4157 $Mangled .= mangle_param($BaseType{"Return"}, $LibVersion, $Repl);
4158 my @Params = keys(%{$BaseType{"Param"}});
4159 foreach my $Num (sort {int($a)<=>int($b)} @Params) {
4160 $Mangled .= mangle_param($BaseType{"Param"}{$Num}{"type"}, $LibVersion, $Repl);
4161 }
4162 if(not @Params) {
4163 $Mangled .= "v";
4164 }
4165 $Mangled .= "E";
4166 }
4167 elsif($BaseType{"Type"} eq "FieldPtr")
4168 {
4169 $Mangled .= "M".mangle_param($BaseType{"Class"}, $LibVersion, $Repl);
4170 $Mangled .= mangle_param($BaseType{"Return"}, $LibVersion, $Repl);
4171 }
4172 $Mangled = $MPrefix.$Mangled;# add prefix (RPK)
4173 if(my $Optimized = write_substitution($Mangled, \%ReplCopy))
4174 {
4175 if($Mangled eq $Optimized)
4176 {
4177 if($ShortName!~/::/)
4178 { # remove "N ... E"
4179 if($MPrefix) {
4180 $Mangled=~s/\A($MPrefix)N(.+)E\Z/$1$2/g;
4181 }
4182 else {
4183 $Mangled=~s/\AN(.+)E\Z/$1/g;
4184 }
4185 }
4186 }
4187 else {
4188 $Mangled = $Optimized;
4189 }
4190 }
4191 add_substitution($Mangled, $Repl, 1);
4192 return $Mangled;
4193}
4194
4195sub mangle_template_param($$$)
4196{ # types + literals
4197 my ($TParam, $LibVersion, $Repl) = @_;
4198 if(my $TPTid = $TName_Tid{$LibVersion}{$TParam}) {
4199 return mangle_param($TPTid, $LibVersion, $Repl);
4200 }
4201 elsif($TParam=~/\A(\d+)(\w+)\Z/)
4202 { # class_name<1u>::method(...)
4203 return "L".$IntrinsicMangling{$ConstantSuffixR{$2}}.$1."E";
4204 }
4205 elsif($TParam=~/\A\(([\w ]+)\)(\d+)\Z/)
4206 { # class_name<(signed char)1>::method(...)
4207 return "L".$IntrinsicMangling{$1}.$2."E";
4208 }
4209 elsif($TParam eq "true")
4210 { # class_name<true>::method(...)
4211 return "Lb1E";
4212 }
4213 elsif($TParam eq "false")
4214 { # class_name<true>::method(...)
4215 return "Lb0E";
4216 }
4217 else { # internal error
4218 return length($TParam).$TParam;
4219 }
4220}
4221
4222sub add_substitution($$$)
4223{
4224 my ($Value, $Repl, $Rec) = @_;
4225 if($Rec)
4226 { # subtypes
4227 my @Subs = ($Value);
4228 while($Value=~s/\A(R|P|K)//) {
4229 push(@Subs, $Value);
4230 }
4231 foreach (reverse(@Subs)) {
4232 add_substitution($_, $Repl, 0);
4233 }
4234 return;
4235 }
4236 return if($Value=~/\AS(\d*)_\Z/);
4237 $Value=~s/\AN(.+)E\Z/$1/g;
4238 return if(defined $Repl->{$Value});
4239 return if(length($Value)<=1);
4240 return if($StdcxxMangling{$Value});
4241 # check for duplicates
4242 my $Base = $Value;
4243 foreach my $Type (sort {$Repl->{$a}<=>$Repl->{$b}} sort keys(%{$Repl}))
4244 {
4245 my $Num = $Repl->{$Type};
4246 my $Replace = macro_mangle($Num);
4247 $Base=~s/\Q$Replace\E/$Type/;
4248 }
4249 if(my $OldNum = $Repl->{$Base})
4250 {
4251 $Repl->{$Value} = $OldNum;
4252 return;
4253 }
4254 my @Repls = sort {$b<=>$a} values(%{$Repl});
4255 if(@Repls) {
4256 $Repl->{$Value} = $Repls[0]+1;
4257 }
4258 else {
4259 $Repl->{$Value} = -1;
4260 }
4261 # register duplicates
4262 # upward
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04004263 $Base = $Value;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004264 foreach my $Type (sort {$Repl->{$a}<=>$Repl->{$b}} sort keys(%{$Repl}))
4265 {
4266 next if($Base eq $Type);
4267 my $Num = $Repl->{$Type};
4268 my $Replace = macro_mangle($Num);
4269 $Base=~s/\Q$Type\E/$Replace/;
4270 $Repl->{$Base} = $Repl->{$Value};
4271 }
4272}
4273
4274sub macro_mangle($)
4275{
4276 my $Num = $_[0];
4277 if($Num==-1) {
4278 return "S_";
4279 }
4280 else
4281 {
4282 my $Code = "";
4283 if($Num<10)
4284 { # S0_, S1_, S2_, ...
4285 $Code = $Num;
4286 }
4287 elsif($Num>=10 and $Num<=35)
4288 { # SA_, SB_, SC_, ...
4289 $Code = chr(55+$Num);
4290 }
4291 else
4292 { # S10_, S11_, S12_
4293 $Code = $Num-26; # 26 is length of english alphabet
4294 }
4295 return "S".$Code."_";
4296 }
4297}
4298
4299sub write_stdcxx_substitution($)
4300{
4301 my $Mangled = $_[0];
4302 if($StdcxxMangling{$Mangled}) {
4303 return $StdcxxMangling{$Mangled};
4304 }
4305 else
4306 {
4307 my @Repls = keys(%StdcxxMangling);
4308 @Repls = sort {length($b)<=>length($a)} sort {$b cmp $a} @Repls;
4309 foreach my $MangledType (@Repls)
4310 {
4311 my $Replace = $StdcxxMangling{$MangledType};
4312 #if($Mangled!~/$Replace/) {
4313 $Mangled=~s/N\Q$MangledType\EE/$Replace/g;
4314 $Mangled=~s/\Q$MangledType\E/$Replace/g;
4315 #}
4316 }
4317 }
4318 return $Mangled;
4319}
4320
4321sub write_substitution($$)
4322{
4323 my ($Mangled, $Repl) = @_;
4324 if(defined $Repl->{$Mangled}
4325 and my $MnglNum = $Repl->{$Mangled}) {
4326 $Mangled = macro_mangle($MnglNum);
4327 }
4328 else
4329 {
4330 my @Repls = keys(%{$Repl});
4331 #@Repls = sort {$Repl->{$a}<=>$Repl->{$b}} @Repls;
4332 # FIXME: how to apply replacements? by num or by pos
4333 @Repls = sort {length($b)<=>length($a)} sort {$b cmp $a} @Repls;
4334 foreach my $MangledType (@Repls)
4335 {
4336 my $Replace = macro_mangle($Repl->{$MangledType});
4337 if($Mangled!~/$Replace/) {
4338 $Mangled=~s/N\Q$MangledType\EE/$Replace/g;
4339 $Mangled=~s/\Q$MangledType\E/$Replace/g;
4340 }
4341 }
4342 }
4343 return $Mangled;
4344}
4345
4346sub delete_keywords($)
4347{
4348 my $TypeName = $_[0];
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04004349 $TypeName=~s/\b(enum|struct|union|class) //g;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004350 return $TypeName;
4351}
4352
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004353sub uncover_typedefs($$)
4354{
4355 my ($TypeName, $LibVersion) = @_;
4356 return "" if(not $TypeName);
4357 if(defined $Cache{"uncover_typedefs"}{$LibVersion}{$TypeName}) {
4358 return $Cache{"uncover_typedefs"}{$LibVersion}{$TypeName};
4359 }
Andrey Ponomarenko9927e332012-10-19 10:50:48 +04004360 my ($TypeName_New, $TypeName_Pre) = (formatName($TypeName, "T"), "");
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004361 while($TypeName_New ne $TypeName_Pre)
4362 {
4363 $TypeName_Pre = $TypeName_New;
4364 my $TypeName_Copy = $TypeName_New;
4365 my %Words = ();
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04004366 while($TypeName_Copy=~s/\b([a-z_]([\w:]*\w|))\b//io)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004367 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04004368 if(not $Intrinsic_Keywords{$1}) {
4369 $Words{$1} = 1;
4370 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004371 }
4372 foreach my $Word (keys(%Words))
4373 {
4374 my $BaseType_Name = $Typedef_BaseName{$LibVersion}{$Word};
4375 next if(not $BaseType_Name);
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04004376 next if($TypeName_New=~/\b(struct|union|enum)\s\Q$Word\E\b/);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004377 if($BaseType_Name=~/\([\*]+\)/)
4378 { # FuncPtr
4379 if($TypeName_New=~/\Q$Word\E(.*)\Z/)
4380 {
4381 my $Type_Suffix = $1;
4382 $TypeName_New = $BaseType_Name;
4383 if($TypeName_New=~s/\(([\*]+)\)/($1 $Type_Suffix)/) {
Andrey Ponomarenko9927e332012-10-19 10:50:48 +04004384 $TypeName_New = formatName($TypeName_New, "T");
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004385 }
4386 }
4387 }
4388 else
4389 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04004390 if($TypeName_New=~s/\b\Q$Word\E\b/$BaseType_Name/g) {
Andrey Ponomarenko9927e332012-10-19 10:50:48 +04004391 $TypeName_New = formatName($TypeName_New, "T");
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004392 }
4393 }
4394 }
4395 }
4396 return ($Cache{"uncover_typedefs"}{$LibVersion}{$TypeName} = $TypeName_New);
4397}
4398
4399sub isInternal($)
4400{
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04004401 if($_[0] and my $Info = $LibInfo{$Version}{"info"}{$_[0]})
4402 {
4403 if($Info=~/mngl[ ]*:[ ]*@(\d+) /)
4404 {
4405 if($LibInfo{$Version}{"info"}{$1}=~/\*[ ]*INTERNAL[ ]*\*/)
4406 { # _ZN7mysqlpp8DateTimeC1ERKS0_ *INTERNAL*
4407 return 1;
4408 }
4409 }
4410 }
4411 return 0;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004412}
4413
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04004414sub getDataVal($$)
4415{
4416 my ($InfoId, $TypeId) = @_;
4417 if(my $Info = $LibInfo{$Version}{"info"}{$InfoId})
4418 {
4419 if($Info=~/init[ ]*:[ ]*@(\d+) /)
4420 {
4421 if(defined $LibInfo{$Version}{"info_type"}{$1}
4422 and $LibInfo{$Version}{"info_type"}{$1} eq "nop_expr")
4423 { # char const* data = "str"
4424 # NOTE: disabled
4425 if(my $NopExpr = $LibInfo{$Version}{"info"}{$1})
4426 {
4427 if($NopExpr=~/op 0[ ]*:[ ]*@(\d+) /)
4428 {
4429 if(defined $LibInfo{$Version}{"info_type"}{$1}
4430 and $LibInfo{$Version}{"info_type"}{$1} eq "addr_expr")
4431 {
4432 if(my $AddrExpr = $LibInfo{$Version}{"info"}{$1})
4433 {
4434 if($AddrExpr=~/op 0[ ]*:[ ]*@(\d+) /)
4435 {
4436 return getInitVal($1, $TypeId);
4437 }
4438 }
4439 }
4440 }
4441 }
4442 }
4443 else {
4444 return getInitVal($1, $TypeId);
4445 }
4446 }
4447 }
4448 return undef;
4449}
4450
4451sub getInitVal($$)
4452{
4453 my ($InfoId, $TypeId) = @_;
4454 if(my $Info = $LibInfo{$Version}{"info"}{$InfoId})
4455 {
4456 if(my $InfoType = $LibInfo{$Version}{"info_type"}{$InfoId})
4457 {
4458 if($InfoType eq "integer_cst")
4459 {
4460 my $Val = getNodeIntCst($InfoId);
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04004461 if($TypeId and $TypeInfo{$Version}{$TypeId}{"Name"}=~/\Achar(| const)\Z/)
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04004462 { # characters
4463 $Val = chr($Val);
4464 }
4465 return $Val;
4466 }
4467 elsif($InfoType eq "string_cst") {
4468 return getNodeStrCst($InfoId);
4469 }
Andrey Ponomarenko01117f12012-06-26 12:23:02 +04004470 elsif($InfoType eq "var_decl")
4471 {
4472 if(my $Name = getNodeStrCst(getTreeAttr_Mngl($InfoId))) {
4473 return $Name;
4474 }
4475 }
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04004476 }
4477 }
4478 return undef;
4479}
4480
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004481sub set_Class_And_Namespace($)
4482{
4483 my $InfoId = $_[0];
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04004484 if(my $Info = $LibInfo{$Version}{"info"}{$InfoId})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004485 {
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04004486 if($Info=~/scpe[ ]*:[ ]*@(\d+) /)
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04004487 {
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04004488 my $NSInfoId = $1;
4489 if(my $InfoType = $LibInfo{$Version}{"info_type"}{$NSInfoId})
4490 {
4491 if($InfoType eq "namespace_decl") {
4492 $SymbolInfo{$Version}{$InfoId}{"NameSpace"} = getNameSpace($InfoId);
4493 }
4494 elsif($InfoType eq "record_type") {
4495 $SymbolInfo{$Version}{$InfoId}{"Class"} = $NSInfoId;
4496 }
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04004497 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004498 }
4499 }
4500 if($SymbolInfo{$Version}{$InfoId}{"Class"}
4501 or $SymbolInfo{$Version}{$InfoId}{"NameSpace"})
4502 { # identify language
4503 setLanguage($Version, "C++");
4504 }
4505}
4506
4507sub debugType($$)
4508{
4509 my ($Tid, $LibVersion) = @_;
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04004510 my %Type = get_Type($Tid, $LibVersion);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004511 printMsg("INFO", Dumper(\%Type));
4512}
4513
4514sub debugMangling($)
4515{
4516 my $LibVersion = $_[0];
4517 my %Mangled = ();
4518 foreach my $InfoId (keys(%{$SymbolInfo{$LibVersion}}))
4519 {
4520 if(my $Mngl = $SymbolInfo{$LibVersion}{$InfoId}{"MnglName"})
4521 {
4522 if($Mngl=~/\A(_Z|\?)/) {
4523 $Mangled{$Mngl}=$InfoId;
4524 }
4525 }
4526 }
4527 translateSymbols(keys(%Mangled), $LibVersion);
4528 foreach my $Mngl (keys(%Mangled))
4529 {
Andrey Ponomarenko85043792012-05-14 16:48:07 +04004530 my $U1 = modelUnmangled($Mangled{$Mngl}, "GCC");
4531 my $U2 = $tr_name{$Mngl};
4532 if($U1 ne $U2) {
4533 printMsg("INFO", "INCORRECT MANGLING:\n $Mngl\n $U1\n $U2\n");
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004534 }
4535 }
4536}
4537
4538sub linkSymbol($)
4539{ # link symbols from shared libraries
4540 # with the symbols from header files
4541 my $InfoId = $_[0];
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004542 # try to mangle symbol
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04004543 if((not check_gcc($GCC_PATH, "4") and $SymbolInfo{$Version}{$InfoId}{"Class"})
4544 or (check_gcc($GCC_PATH, "4") and not $SymbolInfo{$Version}{$InfoId}{"Class"}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004545 { # 1. GCC 3.x doesn't mangle class methods names in the TU dump (only functions and global data)
4546 # 2. GCC 4.x doesn't mangle C++ functions in the TU dump (only class methods) except extern "C" functions
Andrey Ponomarenko16934472012-03-29 15:37:04 +04004547 if(not $CheckHeadersOnly)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004548 {
4549 if(my $Mangled = $mangled_name_gcc{modelUnmangled($InfoId, "GCC")}) {
4550 return correct_incharge($InfoId, $Version, $Mangled);
4551 }
4552 }
Andrey Ponomarenko16934472012-03-29 15:37:04 +04004553 if($CheckHeadersOnly
4554 or not $BinaryOnly)
4555 { # 1. --headers-only mode
4556 # 2. not mangled src-only symbols
4557 if(my $Mangled = mangle_symbol($InfoId, $Version, "GCC")) {
4558 return $Mangled;
4559 }
4560 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004561 }
4562 return "";
4563}
4564
4565sub setLanguage($$)
4566{
4567 my ($LibVersion, $Lang) = @_;
4568 if(not $UserLang) {
4569 $COMMON_LANGUAGE{$LibVersion} = $Lang;
4570 }
4571}
4572
4573sub getSymbolInfo($)
4574{
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04004575 my $InfoId = $_[0];
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04004576 if(isInternal($InfoId)) {
4577 return;
4578 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04004579 ($SymbolInfo{$Version}{$InfoId}{"Header"}, $SymbolInfo{$Version}{$InfoId}{"Line"}) = getLocation($InfoId);
4580 if(not $SymbolInfo{$Version}{$InfoId}{"Header"}
Andrey Ponomarenkoa01311b2012-06-08 17:20:02 +04004581 or isBuiltIn($SymbolInfo{$Version}{$InfoId}{"Header"}))
4582 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04004583 delete($SymbolInfo{$Version}{$InfoId});
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004584 return;
4585 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04004586 setFuncAccess($InfoId);
4587 setFuncKind($InfoId);
Andrey Ponomarenkoa01311b2012-06-08 17:20:02 +04004588 if($SymbolInfo{$Version}{$InfoId}{"PseudoTemplate"})
4589 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04004590 delete($SymbolInfo{$Version}{$InfoId});
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004591 return;
4592 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04004593 $SymbolInfo{$Version}{$InfoId}{"Type"} = getFuncType($InfoId);
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04004594 if($SymbolInfo{$Version}{$InfoId}{"Return"} = getFuncReturn($InfoId))
4595 {
4596 if(not $TypeInfo{$Version}{$SymbolInfo{$Version}{$InfoId}{"Return"}}{"Name"})
4597 { # templates
4598 delete($SymbolInfo{$Version}{$InfoId});
4599 return;
4600 }
4601 }
4602 if(my $Rid = $SymbolInfo{$Version}{$InfoId}{"Return"})
4603 {
4604 if(defined $MissedTypedef{$Version}{$Rid})
4605 {
4606 if(my $AddedTid = $MissedTypedef{$Version}{$Rid}{"Tid"}) {
4607 $SymbolInfo{$Version}{$InfoId}{"Return"} = $AddedTid;
4608 }
4609 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004610 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04004611 if(not $SymbolInfo{$Version}{$InfoId}{"Return"}) {
4612 delete($SymbolInfo{$Version}{$InfoId}{"Return"});
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004613 }
Andrey Ponomarenkoa01311b2012-06-08 17:20:02 +04004614 my $Orig = getFuncOrig($InfoId);
4615 $SymbolInfo{$Version}{$InfoId}{"ShortName"} = getFuncShortName($Orig);
4616 if($SymbolInfo{$Version}{$InfoId}{"ShortName"}=~/\._/)
4617 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04004618 delete($SymbolInfo{$Version}{$InfoId});
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004619 return;
4620 }
Andrey Ponomarenkoa01311b2012-06-08 17:20:02 +04004621
4622 if(defined $TemplateInstance{$Version}{"Func"}{$Orig})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004623 {
Andrey Ponomarenkoa01311b2012-06-08 17:20:02 +04004624 my @TParams = getTParams($Orig, "Func");
4625 if(not @TParams)
4626 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04004627 delete($SymbolInfo{$Version}{$InfoId});
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004628 return;
4629 }
Andrey Ponomarenko16934472012-03-29 15:37:04 +04004630 foreach my $Pos (0 .. $#TParams) {
4631 $SymbolInfo{$Version}{$InfoId}{"TParam"}{$Pos}{"name"}=$TParams[$Pos];
4632 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004633 my $PrmsInLine = join(", ", @TParams);
Andrey Ponomarenko16934472012-03-29 15:37:04 +04004634 if($SymbolInfo{$Version}{$InfoId}{"ShortName"}=~/\Aoperator\W+\Z/)
4635 { # operator<< <T>, operator>> <T>
4636 $SymbolInfo{$Version}{$InfoId}{"ShortName"} .= " ";
4637 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04004638 $SymbolInfo{$Version}{$InfoId}{"ShortName"} .= "<".$PrmsInLine.">";
Andrey Ponomarenko9927e332012-10-19 10:50:48 +04004639 $SymbolInfo{$Version}{$InfoId}{"ShortName"} = formatName($SymbolInfo{$Version}{$InfoId}{"ShortName"}, "S");
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004640 }
4641 else
4642 { # support for GCC 3.4
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04004643 $SymbolInfo{$Version}{$InfoId}{"ShortName"}=~s/<.+>\Z//;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004644 }
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +04004645 if(my $MnglName = getTreeStr(getTreeAttr_Mngl($InfoId)))
4646 {
4647 if($OSgroup eq "windows")
4648 { # cut the offset
4649 $MnglName=~s/\@\d+\Z//g;
4650 }
4651 $SymbolInfo{$Version}{$InfoId}{"MnglName"} = $MnglName;
4652
4653 # NOTE: mangling of some symbols may change depending on GCC version
4654 # GCC 4.6: _ZN28QExplicitlySharedDataPointerI11QPixmapDataEC2IT_EERKS_IT_E
4655 # GCC 4.7: _ZN28QExplicitlySharedDataPointerI11QPixmapDataEC2ERKS1_
4656 }
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04004657
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04004658 if($SymbolInfo{$Version}{$InfoId}{"MnglName"}
Andrey Ponomarenko9927e332012-10-19 10:50:48 +04004659 and index($SymbolInfo{$Version}{$InfoId}{"MnglName"}, "_Z")!=0)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004660 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04004661 delete($SymbolInfo{$Version}{$InfoId});
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004662 return;
4663 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04004664 if(not $SymbolInfo{$Version}{$InfoId}{"Destructor"})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004665 { # destructors have an empty parameter list
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04004666 my $Skip = setFuncParams($InfoId);
Andrey Ponomarenko07aea072012-11-12 16:15:07 +04004667 if($Skip)
4668 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04004669 delete($SymbolInfo{$Version}{$InfoId});
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004670 return;
4671 }
4672 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04004673 set_Class_And_Namespace($InfoId);
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04004674 if(my $ClassId = $SymbolInfo{$Version}{$InfoId}{"Class"})
4675 {
4676 if(not $TypeInfo{$Version}{$ClassId}{"Name"})
4677 { # templates
4678 delete($SymbolInfo{$Version}{$InfoId});
4679 return;
4680 }
4681 }
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04004682 if(not $CheckHeadersOnly)
4683 {
4684 if($SymbolInfo{$Version}{$InfoId}{"Type"} eq "Function"
4685 and not $SymbolInfo{$Version}{$InfoId}{"Class"}
4686 and link_symbol($SymbolInfo{$Version}{$InfoId}{"ShortName"}, $Version, "-Deps"))
4687 { # functions (C++): not mangled in library, but are mangled in TU dump
4688 if(not $SymbolInfo{$Version}{$InfoId}{"MnglName"}
4689 or not link_symbol($SymbolInfo{$Version}{$InfoId}{"MnglName"}, $Version, "-Deps")) {
4690 $SymbolInfo{$Version}{$InfoId}{"MnglName"} = $SymbolInfo{$Version}{$InfoId}{"ShortName"};
4691 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004692 }
4693 }
Andrey Ponomarenko35c44fd2012-06-18 17:50:25 +04004694 if($LibInfo{$Version}{"info"}{$InfoId}=~/ lang:[ ]*C /i)
4695 { # extern "C"
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04004696 $SymbolInfo{$Version}{$InfoId}{"Lang"} = "C";
Andrey Ponomarenko35c44fd2012-06-18 17:50:25 +04004697 $SymbolInfo{$Version}{$InfoId}{"MnglName"} = $SymbolInfo{$Version}{$InfoId}{"ShortName"};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004698 }
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04004699 if($UserLang and $UserLang eq "C")
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004700 { # --lang=C option
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04004701 $SymbolInfo{$Version}{$InfoId}{"MnglName"} = $SymbolInfo{$Version}{$InfoId}{"ShortName"};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004702 }
4703 if($COMMON_LANGUAGE{$Version} eq "C++")
4704 { # correct mangled & short names
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04004705 # C++ or --headers-only mode
4706 if($SymbolInfo{$Version}{$InfoId}{"ShortName"}=~/\A__(comp|base|deleting)_(c|d)tor\Z/)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004707 { # support for old GCC versions: reconstruct real names for constructors and destructors
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04004708 $SymbolInfo{$Version}{$InfoId}{"ShortName"} = getNameByInfo(getTypeDeclId($SymbolInfo{$Version}{$InfoId}{"Class"}));
4709 $SymbolInfo{$Version}{$InfoId}{"ShortName"}=~s/<.+>\Z//;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004710 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04004711 if(not $SymbolInfo{$Version}{$InfoId}{"MnglName"})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004712 { # try to mangle symbol (link with libraries)
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04004713 if(my $Mangled = linkSymbol($InfoId)) {
4714 $SymbolInfo{$Version}{$InfoId}{"MnglName"} = $Mangled;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004715 }
4716 }
4717 if($OStarget eq "windows")
4718 { # link MS C++ symbols from library with GCC symbols from headers
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04004719 if(my $Mangled1 = $mangled_name{$Version}{modelUnmangled($InfoId, "MSVC")})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004720 { # exported symbols
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04004721 $SymbolInfo{$Version}{$InfoId}{"MnglName"} = $Mangled1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004722 }
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04004723 elsif(my $Mangled2 = mangle_symbol($InfoId, $Version, "MSVC"))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004724 { # pure virtual symbols
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04004725 $SymbolInfo{$Version}{$InfoId}{"MnglName"} = $Mangled2;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004726 }
4727 }
4728 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04004729 if(not $SymbolInfo{$Version}{$InfoId}{"MnglName"})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004730 { # can't detect symbol name
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04004731 delete($SymbolInfo{$Version}{$InfoId});
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004732 return;
4733 }
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04004734 if(not $SymbolInfo{$Version}{$InfoId}{"Constructor"}
Andrey Ponomarenkoa01311b2012-06-08 17:20:02 +04004735 and my $Spec = getVirtSpec($Orig))
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04004736 { # identify virtual and pure virtual functions
4737 # NOTE: constructors cannot be virtual
4738 # NOTE: in GCC 4.7 D1 destructors have no virtual spec
4739 # in the TU dump, so taking it from the original symbol
4740 if(not ($SymbolInfo{$Version}{$InfoId}{"Destructor"}
4741 and $SymbolInfo{$Version}{$InfoId}{"MnglName"}=~/D2E/))
4742 { # NOTE: D2 destructors are not present in a v-table
4743 $SymbolInfo{$Version}{$InfoId}{$Spec} = 1;
4744 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004745 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04004746 if(isInline($InfoId)) {
4747 $SymbolInfo{$Version}{$InfoId}{"InLine"} = 1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004748 }
Andrey Ponomarenkob8d203d2012-05-25 18:11:07 +04004749 if($LibInfo{$Version}{"info"}{$InfoId}=~/ artificial /i) {
4750 $SymbolInfo{$Version}{$InfoId}{"Artificial"} = 1;
4751 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04004752 if($SymbolInfo{$Version}{$InfoId}{"Constructor"}
4753 and my $ClassId = $SymbolInfo{$Version}{$InfoId}{"Class"})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004754 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04004755 if(not $SymbolInfo{$Version}{$InfoId}{"InLine"}
Andrey Ponomarenkob8d203d2012-05-25 18:11:07 +04004756 and not $SymbolInfo{$Version}{$InfoId}{"Artificial"})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004757 { # inline or auto-generated constructor
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04004758 delete($TypeInfo{$Version}{$ClassId}{"Copied"});
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004759 }
4760 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +04004761 if(my $Symbol = $SymbolInfo{$Version}{$InfoId}{"MnglName"})
4762 {
Andrey Ponomarenko35c44fd2012-06-18 17:50:25 +04004763 if(not selectSymbol($Symbol, $SymbolInfo{$Version}{$InfoId}, "Dump", $Version))
4764 { # non-target symbols
4765 delete($SymbolInfo{$Version}{$InfoId});
4766 return;
Andrey Ponomarenko85043792012-05-14 16:48:07 +04004767 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004768 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04004769 if($SymbolInfo{$Version}{$InfoId}{"Type"} eq "Method"
4770 or $SymbolInfo{$Version}{$InfoId}{"Constructor"}
4771 or $SymbolInfo{$Version}{$InfoId}{"Destructor"}
4772 or $SymbolInfo{$Version}{$InfoId}{"Class"})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004773 {
Andrey Ponomarenko9927e332012-10-19 10:50:48 +04004774 if($SymbolInfo{$Version}{$InfoId}{"MnglName"}!~/\A(_Z|\?)/)
4775 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04004776 delete($SymbolInfo{$Version}{$InfoId});
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004777 return;
4778 }
4779 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04004780 if($SymbolInfo{$Version}{$InfoId}{"MnglName"})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004781 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04004782 if($MangledNames{$Version}{$SymbolInfo{$Version}{$InfoId}{"MnglName"}})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004783 { # one instance for one mangled name only
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04004784 delete($SymbolInfo{$Version}{$InfoId});
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004785 return;
4786 }
4787 else {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04004788 $MangledNames{$Version}{$SymbolInfo{$Version}{$InfoId}{"MnglName"}} = 1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004789 }
4790 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04004791 if($SymbolInfo{$Version}{$InfoId}{"Constructor"}
4792 or $SymbolInfo{$Version}{$InfoId}{"Destructor"}) {
4793 delete($SymbolInfo{$Version}{$InfoId}{"Return"});
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004794 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04004795 if($SymbolInfo{$Version}{$InfoId}{"MnglName"}=~/\A(_Z|\?)/
4796 and $SymbolInfo{$Version}{$InfoId}{"Class"})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004797 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04004798 if($SymbolInfo{$Version}{$InfoId}{"Type"} eq "Function")
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004799 { # static methods
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04004800 $SymbolInfo{$Version}{$InfoId}{"Static"} = 1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004801 }
4802 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04004803 if(getFuncLink($InfoId) eq "Static") {
4804 $SymbolInfo{$Version}{$InfoId}{"Static"} = 1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004805 }
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04004806 if($SymbolInfo{$Version}{$InfoId}{"MnglName"}=~/\A(_Z|\?)/)
4807 {
4808 if(my $Unmangled = $tr_name{$SymbolInfo{$Version}{$InfoId}{"MnglName"}})
4809 {
Andrey Ponomarenko9927e332012-10-19 10:50:48 +04004810 if($Unmangled=~/\.\_\d/)
4811 {
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04004812 delete($SymbolInfo{$Version}{$InfoId});
4813 return;
4814 }
4815 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004816 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04004817 delete($SymbolInfo{$Version}{$InfoId}{"Type"});
4818 if($SymbolInfo{$Version}{$InfoId}{"MnglName"}=~/\A_ZN(V|)K/) {
4819 $SymbolInfo{$Version}{$InfoId}{"Const"} = 1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004820 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04004821 if($SymbolInfo{$Version}{$InfoId}{"MnglName"}=~/\A_ZN(K|)V/) {
4822 $SymbolInfo{$Version}{$InfoId}{"Volatile"} = 1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004823 }
Andrey Ponomarenko07aea072012-11-12 16:15:07 +04004824
4825 if($WeakSymbols{$Version}{$SymbolInfo{$Version}{$InfoId}{"MnglName"}}) {
4826 $SymbolInfo{$Version}{$InfoId}{"Weak"} = 1;
4827 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004828}
4829
4830sub isInline($)
4831{ # "body: undefined" in the tree
4832 # -fkeep-inline-functions GCC option should be specified
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04004833 if($_[0] and my $Info = $LibInfo{$Version}{"info"}{$_[0]})
4834 {
4835 if($Info=~/ undefined /i) {
4836 return 0;
4837 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004838 }
4839 return 1;
4840}
4841
4842sub getTypeId($)
4843{
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04004844 if($_[0] and my $Info = $LibInfo{$Version}{"info"}{$_[0]})
4845 {
4846 if($Info=~/type[ ]*:[ ]*@(\d+) /) {
4847 return $1;
4848 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004849 }
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04004850 return "";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004851}
4852
4853sub setTypeMemb($$)
4854{
4855 my ($TypeId, $TypeAttr) = @_;
4856 my $TypeType = $TypeAttr->{"Type"};
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04004857 my ($Pos, $UnnamedPos) = (0, 0);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004858 if($TypeType eq "Enum")
4859 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04004860 my $TypeMembInfoId = getTreeAttr_Csts($TypeId);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004861 while($TypeMembInfoId)
4862 {
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04004863 $TypeAttr->{"Memb"}{$Pos}{"value"} = getEnumMembVal($TypeMembInfoId);
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04004864 my $MembName = getTreeStr(getTreeAttr_Purp($TypeMembInfoId));
4865 $TypeAttr->{"Memb"}{$Pos}{"name"} = $MembName;
4866 $EnumMembName_Id{$Version}{getTreeAttr_Valu($TypeMembInfoId)} = ($TypeAttr->{"NameSpace"})?$TypeAttr->{"NameSpace"}."::".$MembName:$MembName;
4867 $TypeMembInfoId = getNextElem($TypeMembInfoId);
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04004868 $Pos += 1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004869 }
4870 }
4871 elsif($TypeType=~/\A(Struct|Class|Union)\Z/)
4872 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04004873 my $TypeMembInfoId = getTreeAttr_Flds($TypeId);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004874 while($TypeMembInfoId)
4875 {
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04004876 my $IType = $LibInfo{$Version}{"info_type"}{$TypeMembInfoId};
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04004877 my $MInfo = $LibInfo{$Version}{"info"}{$TypeMembInfoId};
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04004878 if(not $IType or $IType ne "field_decl")
4879 { # search for fields, skip other stuff in the declaration
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04004880 $TypeMembInfoId = getNextElem($TypeMembInfoId);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004881 next;
4882 }
Andrey Ponomarenko01117f12012-06-26 12:23:02 +04004883 my $StructMembName = getTreeStr(getTreeAttr_Name($TypeMembInfoId));
4884 if(index($StructMembName, "_vptr.")!=-1)
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04004885 { # virtual tables
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04004886 $TypeMembInfoId = getNextElem($TypeMembInfoId);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004887 next;
4888 }
4889 if(not $StructMembName)
4890 { # unnamed fields
Andrey Ponomarenko01117f12012-06-26 12:23:02 +04004891 if(index($TypeAttr->{"Name"}, "_type_info_pseudo")==-1)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004892 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04004893 my $UnnamedTid = getTreeAttr_Type($TypeMembInfoId);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004894 my $UnnamedTName = getNameByInfo(getTypeDeclId($UnnamedTid));
4895 if(isAnon($UnnamedTName))
4896 { # rename unnamed fields to unnamed0, unnamed1, ...
4897 $StructMembName = "unnamed".($UnnamedPos++);
4898 }
4899 }
4900 }
4901 if(not $StructMembName)
4902 { # unnamed fields and base classes
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04004903 $TypeMembInfoId = getNextElem($TypeMembInfoId);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004904 next;
4905 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04004906 my $MembTypeId = getTreeAttr_Type($TypeMembInfoId);
4907 if(defined $MissedTypedef{$Version}{$MembTypeId})
4908 {
4909 if(my $AddedTid = $MissedTypedef{$Version}{$MembTypeId}{"Tid"}) {
4910 $MembTypeId = $AddedTid;
4911 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004912 }
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04004913 $TypeAttr->{"Memb"}{$Pos}{"type"} = $MembTypeId;
4914 $TypeAttr->{"Memb"}{$Pos}{"name"} = $StructMembName;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004915 if((my $Access = getTreeAccess($TypeMembInfoId)) ne "public")
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04004916 { # marked only protected and private, public by default
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04004917 $TypeAttr->{"Memb"}{$Pos}{"access"} = $Access;
4918 }
4919 if($MInfo=~/spec:\s*mutable /)
4920 { # mutable fields
4921 $TypeAttr->{"Memb"}{$Pos}{"mutable"} = 1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004922 }
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +04004923 if(my $Algn = getAlgn($TypeMembInfoId)) {
4924 $TypeAttr->{"Memb"}{$Pos}{"algn"} = $Algn;
4925 }
4926 if(my $BFSize = getBitField($TypeMembInfoId))
4927 { # in bits
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04004928 $TypeAttr->{"Memb"}{$Pos}{"bitfield"} = $BFSize;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004929 }
4930 else
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +04004931 { # in bytes
4932 $TypeAttr->{"Memb"}{$Pos}{"algn"} /= $BYTE_SIZE;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004933 }
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +04004934
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04004935 $TypeMembInfoId = getNextElem($TypeMembInfoId);
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04004936 $Pos += 1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004937 }
4938 }
4939}
4940
4941sub setFuncParams($)
4942{
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04004943 my $InfoId = $_[0];
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04004944 my $ParamInfoId = getTreeAttr_Args($InfoId);
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04004945 if(getFuncType($InfoId) eq "Method")
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004946 { # check type of "this" pointer
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04004947 my $ObjectTypeId = getTreeAttr_Type($ParamInfoId);
4948 if(my $ObjectName = $TypeInfo{$Version}{$ObjectTypeId}{"Name"})
Andrey Ponomarenko85043792012-05-14 16:48:07 +04004949 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04004950 if($ObjectName=~/\bconst(| volatile)\*const\b/) {
Andrey Ponomarenko85043792012-05-14 16:48:07 +04004951 $SymbolInfo{$Version}{$InfoId}{"Const"} = 1;
4952 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04004953 if($ObjectName=~/\bvolatile\b/) {
Andrey Ponomarenko85043792012-05-14 16:48:07 +04004954 $SymbolInfo{$Version}{$InfoId}{"Volatile"} = 1;
4955 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004956 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +04004957 else
4958 { # skip
4959 return 1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004960 }
4961 $ParamInfoId = getNextElem($ParamInfoId);
4962 }
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04004963 my ($Pos, $Vtt_Pos) = (0, -1);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004964 while($ParamInfoId)
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04004965 { # formal args
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04004966 my $ParamTypeId = getTreeAttr_Type($ParamInfoId);
4967 my $ParamName = getTreeStr(getTreeAttr_Name($ParamInfoId));
4968 if(not $ParamName)
4969 { # unnamed
4970 $ParamName = "p".($Pos+1);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004971 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04004972 if(defined $MissedTypedef{$Version}{$ParamTypeId})
4973 {
4974 if(my $AddedTid = $MissedTypedef{$Version}{$ParamTypeId}{"Tid"}) {
4975 $ParamTypeId = $AddedTid;
4976 }
4977 }
4978 my $PType = $TypeInfo{$Version}{$ParamTypeId}{"Type"};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004979 if(not $PType or $PType eq "Unknown") {
4980 return 1;
4981 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04004982 my $PTName = $TypeInfo{$Version}{$ParamTypeId}{"Name"};
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04004983 if(not $PTName) {
4984 return 1;
4985 }
4986 if($PTName eq "void") {
4987 last;
4988 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004989 if($ParamName eq "__vtt_parm"
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04004990 and $TypeInfo{$Version}{$ParamTypeId}{"Name"} eq "void const**")
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004991 {
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04004992 $Vtt_Pos = $Pos;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004993 $ParamInfoId = getNextElem($ParamInfoId);
4994 next;
4995 }
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04004996 $SymbolInfo{$Version}{$InfoId}{"Param"}{$Pos}{"type"} = $ParamTypeId;
4997 $SymbolInfo{$Version}{$InfoId}{"Param"}{$Pos}{"name"} = $ParamName;
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04004998 if(my $Algn = getAlgn($ParamInfoId)) {
4999 $SymbolInfo{$Version}{$InfoId}{"Param"}{$Pos}{"algn"} = $Algn/$BYTE_SIZE;
5000 }
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04005001 if(not $SymbolInfo{$Version}{$InfoId}{"Param"}{$Pos}{"name"}) {
5002 $SymbolInfo{$Version}{$InfoId}{"Param"}{$Pos}{"name"} = "p".($Pos+1);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005003 }
5004 if($LibInfo{$Version}{"info"}{$ParamInfoId}=~/spec:\s*register /)
5005 { # foo(register type arg)
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04005006 $SymbolInfo{$Version}{$InfoId}{"Param"}{$Pos}{"reg"} = 1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005007 }
5008 $ParamInfoId = getNextElem($ParamInfoId);
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04005009 $Pos += 1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005010 }
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04005011 if(setFuncArgs($InfoId, $Vtt_Pos)) {
Andrey Ponomarenko01117f12012-06-26 12:23:02 +04005012 $SymbolInfo{$Version}{$InfoId}{"Param"}{$Pos}{"type"} = "-1";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005013 }
5014 return 0;
5015}
5016
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04005017sub setFuncArgs($$)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005018{
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04005019 my ($InfoId, $Vtt_Pos) = @_;
5020 my $FuncTypeId = getFuncTypeId($InfoId);
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04005021 my $ParamListElemId = getTreeAttr_Prms($FuncTypeId);
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04005022 if(getFuncType($InfoId) eq "Method") {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005023 $ParamListElemId = getNextElem($ParamListElemId);
5024 }
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04005025 if(not $ParamListElemId)
5026 { # foo(...)
5027 return 1;
5028 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005029 my $HaveVoid = 0;
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04005030 my $Pos = 0;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005031 while($ParamListElemId)
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04005032 { # actual params: may differ from formal args
5033 # formal int*const
5034 # actual: int*
5035 if($Vtt_Pos!=-1 and $Pos==$Vtt_Pos)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005036 {
5037 $Vtt_Pos=-1;
5038 $ParamListElemId = getNextElem($ParamListElemId);
5039 next;
5040 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04005041 my $ParamTypeId = getTreeAttr_Valu($ParamListElemId);
5042 if($TypeInfo{$Version}{$ParamTypeId}{"Name"} eq "void")
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04005043 {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005044 $HaveVoid = 1;
5045 last;
5046 }
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04005047 elsif(not defined $SymbolInfo{$Version}{$InfoId}{"Param"}{$Pos}{"type"})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005048 {
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04005049 $SymbolInfo{$Version}{$InfoId}{"Param"}{$Pos}{"type"} = $ParamTypeId;
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04005050 if(not $SymbolInfo{$Version}{$InfoId}{"Param"}{$Pos}{"name"})
5051 { # unnamed
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04005052 $SymbolInfo{$Version}{$InfoId}{"Param"}{$Pos}{"name"} = "p".($Pos+1);
5053 }
5054 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04005055 if(my $PurpId = getTreeAttr_Purp($ParamListElemId))
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04005056 { # default arguments
Andrey Ponomarenko01117f12012-06-26 12:23:02 +04005057 if(my $PurpType = $LibInfo{$Version}{"info_type"}{$PurpId})
5058 {
5059 my $Val = getInitVal($PurpId, $ParamTypeId);
5060 if(defined $Val) {
5061 $SymbolInfo{$Version}{$InfoId}{"Param"}{$Pos}{"default"} = $Val;
5062 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005063 }
5064 }
5065 $ParamListElemId = getNextElem($ParamListElemId);
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04005066 $Pos += 1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005067 }
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04005068 return ($Pos>=1 and not $HaveVoid);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005069}
5070
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04005071sub getTreeAttr_Chan($)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005072{
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04005073 if($_[0] and my $Info = $LibInfo{$Version}{"info"}{$_[0]})
5074 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04005075 if($Info=~/chan[ ]*:[ ]*@(\d+) /) {
5076 return $1;
5077 }
5078 }
5079 return "";
5080}
5081
5082sub getTreeAttr_Chain($)
5083{
5084 if($_[0] and my $Info = $LibInfo{$Version}{"info"}{$_[0]})
5085 {
5086 if($Info=~/chain[ ]*:[ ]*@(\d+) /) {
5087 return $1;
5088 }
5089 }
5090 return "";
5091}
5092
5093sub getTreeAttr_Scpe($)
5094{
5095 if($_[0] and my $Info = $LibInfo{$Version}{"info"}{$_[0]})
5096 {
5097 if($Info=~/scpe[ ]*:[ ]*@(\d+) /) {
5098 return $1;
5099 }
5100 }
5101 return "";
5102}
5103
5104sub getTreeAttr_Type($)
5105{
5106 if($_[0] and my $Info = $LibInfo{$Version}{"info"}{$_[0]})
5107 {
5108 if($Info=~/type[ ]*:[ ]*@(\d+) /) {
5109 return $1;
5110 }
5111 }
5112 return "";
5113}
5114
5115sub getTreeAttr_Name($)
5116{
5117 if($_[0] and my $Info = $LibInfo{$Version}{"info"}{$_[0]})
5118 {
5119 if($Info=~/name[ ]*:[ ]*@(\d+) /) {
5120 return $1;
5121 }
5122 }
5123 return "";
5124}
5125
5126sub getTreeAttr_Mngl($)
5127{
5128 if($_[0] and my $Info = $LibInfo{$Version}{"info"}{$_[0]})
5129 {
5130 if($Info=~/mngl[ ]*:[ ]*@(\d+) /) {
5131 return $1;
5132 }
5133 }
5134 return "";
5135}
5136
5137sub getTreeAttr_Prms($)
5138{
5139 if($_[0] and my $Info = $LibInfo{$Version}{"info"}{$_[0]})
5140 {
5141 if($Info=~/prms[ ]*:[ ]*@(\d+) /) {
5142 return $1;
5143 }
5144 }
5145 return "";
5146}
5147
5148sub getTreeAttr_Fncs($)
5149{
5150 if($_[0] and my $Info = $LibInfo{$Version}{"info"}{$_[0]})
5151 {
5152 if($Info=~/fncs[ ]*:[ ]*@(\d+) /) {
5153 return $1;
5154 }
5155 }
5156 return "";
5157}
5158
5159sub getTreeAttr_Csts($)
5160{
5161 if($_[0] and my $Info = $LibInfo{$Version}{"info"}{$_[0]})
5162 {
5163 if($Info=~/csts[ ]*:[ ]*@(\d+) /) {
5164 return $1;
5165 }
5166 }
5167 return "";
5168}
5169
5170sub getTreeAttr_Purp($)
5171{
5172 if($_[0] and my $Info = $LibInfo{$Version}{"info"}{$_[0]})
5173 {
5174 if($Info=~/purp[ ]*:[ ]*@(\d+) /) {
5175 return $1;
5176 }
5177 }
5178 return "";
5179}
5180
5181sub getTreeAttr_Valu($)
5182{
5183 if($_[0] and my $Info = $LibInfo{$Version}{"info"}{$_[0]})
5184 {
5185 if($Info=~/valu[ ]*:[ ]*@(\d+) /) {
5186 return $1;
5187 }
5188 }
5189 return "";
5190}
5191
5192sub getTreeAttr_Flds($)
5193{
5194 if($_[0] and my $Info = $LibInfo{$Version}{"info"}{$_[0]})
5195 {
5196 if($Info=~/flds[ ]*:[ ]*@(\d+) /) {
5197 return $1;
5198 }
5199 }
5200 return "";
5201}
5202
5203sub getTreeAttr_Args($)
5204{
5205 if($_[0] and my $Info = $LibInfo{$Version}{"info"}{$_[0]})
5206 {
5207 if($Info=~/args[ ]*:[ ]*@(\d+) /) {
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04005208 return $1;
5209 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005210 }
5211 return "";
5212}
5213
5214sub getTreeValue($)
5215{
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04005216 if($_[0] and my $Info = $LibInfo{$Version}{"info"}{$_[0]})
5217 {
5218 if($Info=~/low[ ]*:[ ]*([^ ]+) /) {
5219 return $1;
5220 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005221 }
5222 return "";
5223}
5224
5225sub getTreeAccess($)
5226{
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04005227 if($_[0] and my $Info = $LibInfo{$Version}{"info"}{$_[0]})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005228 {
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04005229 if($Info=~/accs[ ]*:[ ]*([a-zA-Z]+) /)
5230 {
5231 my $Access = $1;
5232 if($Access eq "prot") {
5233 return "protected";
5234 }
5235 elsif($Access eq "priv") {
5236 return "private";
5237 }
5238 }
5239 elsif($Info=~/ protected /)
5240 { # support for old GCC versions
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005241 return "protected";
5242 }
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04005243 elsif($Info=~/ private /)
5244 { # support for old GCC versions
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005245 return "private";
5246 }
5247 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005248 return "public";
5249}
5250
5251sub setFuncAccess($)
5252{
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04005253 my $Access = getTreeAccess($_[0]);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005254 if($Access eq "protected") {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04005255 $SymbolInfo{$Version}{$_[0]}{"Protected"} = 1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005256 }
5257 elsif($Access eq "private") {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04005258 $SymbolInfo{$Version}{$_[0]}{"Private"} = 1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005259 }
5260}
5261
5262sub setTypeAccess($$)
5263{
5264 my ($TypeId, $TypeAttr) = @_;
5265 my $Access = getTreeAccess($TypeId);
5266 if($Access eq "protected") {
5267 $TypeAttr->{"Protected"} = 1;
5268 }
5269 elsif($Access eq "private") {
5270 $TypeAttr->{"Private"} = 1;
5271 }
5272}
5273
5274sub setFuncKind($)
5275{
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04005276 if($_[0] and my $Info = $LibInfo{$Version}{"info"}{$_[0]})
5277 {
5278 if($Info=~/pseudo tmpl/) {
5279 $SymbolInfo{$Version}{$_[0]}{"PseudoTemplate"} = 1;
5280 }
5281 elsif($Info=~/ constructor /) {
5282 $SymbolInfo{$Version}{$_[0]}{"Constructor"} = 1;
5283 }
5284 elsif($Info=~/ destructor /) {
5285 $SymbolInfo{$Version}{$_[0]}{"Destructor"} = 1;
5286 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005287 }
5288}
5289
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04005290sub getVirtSpec($)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005291{
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04005292 if($_[0] and my $Info = $LibInfo{$Version}{"info"}{$_[0]})
5293 {
5294 if($Info=~/spec[ ]*:[ ]*pure /) {
5295 return "PureVirt";
5296 }
5297 elsif($Info=~/spec[ ]*:[ ]*virt /) {
5298 return "Virt";
5299 }
5300 elsif($Info=~/ pure\s+virtual /)
5301 { # support for old GCC versions
5302 return "PureVirt";
5303 }
5304 elsif($Info=~/ virtual /)
5305 { # support for old GCC versions
5306 return "Virt";
5307 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005308 }
5309 return "";
5310}
5311
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005312sub getFuncLink($)
5313{
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04005314 if($_[0] and my $Info = $LibInfo{$Version}{"info"}{$_[0]})
5315 {
5316 if($Info=~/link[ ]*:[ ]*static /) {
5317 return "Static";
5318 }
5319 elsif($Info=~/link[ ]*:[ ]*([a-zA-Z]+) /) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005320 return $1;
5321 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005322 }
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04005323 return "";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005324}
5325
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005326sub get_IntNameSpace($$)
5327{
5328 my ($Interface, $LibVersion) = @_;
5329 return "" if(not $Interface or not $LibVersion);
5330 if(defined $Cache{"get_IntNameSpace"}{$Interface}{$LibVersion}) {
5331 return $Cache{"get_IntNameSpace"}{$Interface}{$LibVersion};
5332 }
5333 my $Signature = get_Signature($Interface, $LibVersion);
5334 if($Signature=~/\:\:/)
5335 {
5336 my $FounNameSpace = 0;
5337 foreach my $NameSpace (sort {get_depth($b)<=>get_depth($a)} keys(%{$NestedNameSpaces{$LibVersion}}))
5338 {
5339 if($Signature=~/(\A|\s+for\s+)\Q$NameSpace\E\:\:/) {
5340 return ($Cache{"get_IntNameSpace"}{$Interface}{$LibVersion} = $NameSpace);
5341 }
5342 }
5343 }
5344 else {
5345 return ($Cache{"get_IntNameSpace"}{$Interface}{$LibVersion} = "");
5346 }
5347}
5348
5349sub parse_TypeNameSpace($$)
5350{
5351 my ($TypeName, $LibVersion) = @_;
5352 return "" if(not $TypeName or not $LibVersion);
5353 if(defined $Cache{"parse_TypeNameSpace"}{$TypeName}{$LibVersion}) {
5354 return $Cache{"parse_TypeNameSpace"}{$TypeName}{$LibVersion};
5355 }
5356 if($TypeName=~/\:\:/)
5357 {
5358 my $FounNameSpace = 0;
5359 foreach my $NameSpace (sort {get_depth($b)<=>get_depth($a)} keys(%{$NestedNameSpaces{$LibVersion}}))
5360 {
5361 if($TypeName=~/\A\Q$NameSpace\E\:\:/) {
5362 return ($Cache{"parse_TypeNameSpace"}{$TypeName}{$LibVersion} = $NameSpace);
5363 }
5364 }
5365 }
5366 else {
5367 return ($Cache{"parse_TypeNameSpace"}{$TypeName}{$LibVersion} = "");
5368 }
5369}
5370
5371sub getNameSpace($)
5372{
5373 my $TypeInfoId = $_[0];
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04005374 if(my $NSInfoId = getTreeAttr_Scpe($TypeInfoId))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005375 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04005376 if(my $InfoType = $LibInfo{$Version}{"info_type"}{$NSInfoId})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005377 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04005378 if($InfoType eq "namespace_decl")
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04005379 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04005380 if($LibInfo{$Version}{"info"}{$NSInfoId}=~/name[ ]*:[ ]*@(\d+) /)
5381 {
5382 my $NameSpace = getTreeStr($1);
5383 if($NameSpace eq "::")
5384 { # global namespace
5385 return "";
5386 }
5387 if(my $BaseNameSpace = getNameSpace($NSInfoId)) {
5388 $NameSpace = $BaseNameSpace."::".$NameSpace;
5389 }
5390 $NestedNameSpaces{$Version}{$NameSpace} = 1;
5391 return $NameSpace;
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04005392 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04005393 else {
5394 return "";
5395 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005396 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04005397 elsif($InfoType eq "record_type")
5398 { # inside data type
5399 my ($Name, $NameNS) = getTrivialName(getTypeDeclId($NSInfoId), $NSInfoId);
5400 return $Name;
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04005401 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005402 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005403 }
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04005404 return "";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005405}
5406
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005407sub getEnumMembVal($)
5408{
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04005409 if($_[0] and my $Info = $LibInfo{$Version}{"info"}{$_[0]})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005410 {
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04005411 if($Info=~/valu[ ]*:[ ]*\@(\d+)/)
5412 {
5413 if(my $VInfo = $LibInfo{$Version}{"info"}{$1})
5414 {
5415 if($VInfo=~/cnst[ ]*:[ ]*\@(\d+)/)
5416 { # in newer versions of GCC the value is in the "const_decl->cnst" node
5417 return getTreeValue($1);
5418 }
5419 else
5420 { # some old versions of GCC (3.3) have the value in the "integer_cst" node
5421 return getTreeValue($1);
5422 }
5423 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005424 }
5425 }
5426 return "";
5427}
5428
5429sub getSize($)
5430{
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04005431 if($_[0] and my $Info = $LibInfo{$Version}{"info"}{$_[0]})
5432 {
5433 if($Info=~/size[ ]*:[ ]*\@(\d+)/) {
5434 return getTreeValue($1);
5435 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005436 }
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04005437 return 0;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005438}
5439
5440sub getAlgn($)
5441{
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04005442 if($_[0] and my $Info = $LibInfo{$Version}{"info"}{$_[0]})
5443 {
5444 if($Info=~/algn[ ]*:[ ]*(\d+) /) {
5445 return $1;
5446 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005447 }
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04005448 return "";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005449}
5450
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +04005451sub getBitField($)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005452{
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04005453 if($_[0] and my $Info = $LibInfo{$Version}{"info"}{$_[0]})
5454 {
5455 if($Info=~/ bitfield /) {
5456 return getSize($_[0]);
5457 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005458 }
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04005459 return 0;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005460}
5461
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04005462sub getNextElem($)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005463{
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04005464 if(my $Chan = getTreeAttr_Chan($_[0])) {
5465 return $Chan;
5466 }
5467 elsif(my $Chain = getTreeAttr_Chain($_[0])) {
5468 return $Chain;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005469 }
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04005470 return "";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005471}
5472
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04005473sub registerHeader($$)
5474{ # input: absolute path of header, relative path or name
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005475 my ($Header, $LibVersion) = @_;
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04005476 if(not $Header) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005477 return "";
5478 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04005479 if(is_abs($Header) and not -f $Header)
5480 { # incorrect absolute path
5481 exitStatus("Access_Error", "can't access \'$Header\'");
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005482 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04005483 if(skipHeader($Header, $LibVersion))
5484 { # skip
5485 return "";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005486 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04005487 if(my $Header_Path = identifyHeader($Header, $LibVersion))
5488 {
5489 detect_header_includes($Header_Path, $LibVersion);
5490
5491 if(my $RHeader_Path = $Header_ErrorRedirect{$LibVersion}{$Header_Path})
5492 { # redirect
5493 if($Registered_Headers{$LibVersion}{$RHeader_Path}{"Identity"}
5494 or skipHeader($RHeader_Path, $LibVersion))
5495 { # skip
5496 return "";
5497 }
5498 $Header_Path = $RHeader_Path;
5499 }
5500 elsif($Header_ShouldNotBeUsed{$LibVersion}{$Header_Path})
5501 { # skip
5502 return "";
5503 }
5504
5505 if(my $HName = get_filename($Header_Path))
5506 { # register
5507 $Registered_Headers{$LibVersion}{$Header_Path}{"Identity"} = $HName;
5508 $HeaderName_Paths{$LibVersion}{$HName}{$Header_Path} = 1;
5509 }
5510
5511 if(($Header=~/\.(\w+)\Z/ and $1 ne "h")
5512 or $Header!~/\.(\w+)\Z/)
5513 { # hpp, hh
5514 setLanguage($LibVersion, "C++");
5515 }
5516
5517 if($CheckHeadersOnly
5518 and $Header=~/(\A|\/)c\+\+(\/|\Z)/)
5519 { # /usr/include/c++/4.6.1/...
5520 $STDCXX_TESTING = 1;
5521 }
5522
5523 return $Header_Path;
5524 }
5525 return "";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005526}
5527
5528sub register_directory($$$)
5529{
5530 my ($Dir, $WithDeps, $LibVersion) = @_;
5531 $Dir=~s/[\/\\]+\Z//g;
5532 return if(not $LibVersion or not $Dir or not -d $Dir);
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04005533 return if(skipHeader($Dir, $LibVersion));
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005534 $Dir = get_abs_path($Dir);
5535 my $Mode = "All";
Andrey Ponomarenko85043792012-05-14 16:48:07 +04005536 if($WithDeps)
5537 {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005538 if($RegisteredDirs{$LibVersion}{$Dir}{1}) {
5539 return;
5540 }
5541 elsif($RegisteredDirs{$LibVersion}{$Dir}{0}) {
5542 $Mode = "DepsOnly";
5543 }
5544 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +04005545 else
5546 {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005547 if($RegisteredDirs{$LibVersion}{$Dir}{1}
5548 or $RegisteredDirs{$LibVersion}{$Dir}{0}) {
5549 return;
5550 }
5551 }
5552 $Header_Dependency{$LibVersion}{$Dir} = 1;
5553 $RegisteredDirs{$LibVersion}{$Dir}{$WithDeps} = 1;
5554 if($Mode eq "DepsOnly")
5555 {
5556 foreach my $Path (cmd_find($Dir,"d","","")) {
5557 $Header_Dependency{$LibVersion}{$Path} = 1;
5558 }
5559 return;
5560 }
5561 foreach my $Path (sort {length($b)<=>length($a)} cmd_find($Dir,"f","",""))
5562 {
5563 if($WithDeps)
5564 {
5565 my $SubDir = $Path;
5566 while(($SubDir = get_dirname($SubDir)) ne $Dir)
5567 { # register all sub directories
5568 $Header_Dependency{$LibVersion}{$SubDir} = 1;
5569 }
5570 }
5571 next if(is_not_header($Path));
5572 next if(ignore_path($Path));
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04005573 next if(skipHeader($Path, $LibVersion));
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005574 # Neighbors
Andrey Ponomarenko9927e332012-10-19 10:50:48 +04005575 foreach my $Part (get_prefixes($Path)) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005576 $Include_Neighbors{$LibVersion}{$Part} = $Path;
5577 }
5578 }
5579 if(get_filename($Dir) eq "include")
5580 { # search for "lib/include/" directory
5581 my $LibDir = $Dir;
5582 if($LibDir=~s/([\/\\])include\Z/$1lib/g and -d $LibDir) {
5583 register_directory($LibDir, $WithDeps, $LibVersion);
5584 }
5585 }
5586}
5587
5588sub parse_redirect($$$)
5589{
5590 my ($Content, $Path, $LibVersion) = @_;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005591 my @Errors = ();
5592 while($Content=~s/#\s*error\s+([^\n]+?)\s*(\n|\Z)//) {
5593 push(@Errors, $1);
5594 }
5595 my $Redirect = "";
5596 foreach (@Errors)
5597 {
5598 s/\s{2,}/ /g;
5599 if(/(only|must\ include
5600 |update\ to\ include
5601 |replaced\ with
5602 |replaced\ by|renamed\ to
Andrey Ponomarenko9927e332012-10-19 10:50:48 +04005603 |\ is\ in|\ use)\ (<[^<>]+>|[\w\-\/\\]+\.($HEADER_EXT))/ix)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005604 {
5605 $Redirect = $2;
5606 last;
5607 }
5608 elsif(/(include|use|is\ in)\ (<[^<>]+>|[\w\-\/\\]+\.($HEADER_EXT))\ instead/i)
5609 {
5610 $Redirect = $2;
5611 last;
5612 }
5613 elsif(/this\ header\ should\ not\ be\ used
5614 |programs\ should\ not\ directly\ include
5615 |you\ should\ not\ (include|be\ (including|using)\ this\ (file|header))
5616 |is\ not\ supported\ API\ for\ general\ use
5617 |do\ not\ use
Andrey Ponomarenko9927e332012-10-19 10:50:48 +04005618 |should\ not\ be\ (used|using)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005619 |cannot\ be\ included\ directly/ix and not /\ from\ /i) {
5620 $Header_ShouldNotBeUsed{$LibVersion}{$Path} = 1;
5621 }
5622 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +04005623 if($Redirect)
5624 {
5625 $Redirect=~s/\A<//g;
5626 $Redirect=~s/>\Z//g;
5627 }
5628 return $Redirect;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005629}
5630
5631sub parse_includes($$)
5632{
5633 my ($Content, $Path) = @_;
5634 my %Includes = ();
5635 while($Content=~s/#([ \t]*)(include|include_next|import)([ \t]*)(<|")([^<>"]+)(>|")//)
Andrey Ponomarenko85043792012-05-14 16:48:07 +04005636 { # C/C++: include, Objective C/C++: import directive
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005637 my ($Header, $Method) = ($5, $4);
5638 $Header = path_format($Header, $OSgroup);
Andrey Ponomarenko85043792012-05-14 16:48:07 +04005639 if($Method eq "\"" or is_abs($Header))
5640 {
5641 if(-e joinPath(get_dirname($Path), $Header))
5642 { # relative path exists
5643 $Includes{$Header} = -1;
5644 }
5645 else
5646 { # include "..." that doesn't exist is equal to include <...>
5647 $Includes{$Header} = 2;
5648 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005649 }
5650 else {
5651 $Includes{$Header} = 1;
5652 }
5653 }
5654 return \%Includes;
5655}
5656
5657sub ignore_path($)
5658{
5659 my $Path = $_[0];
5660 if($Path=~/\~\Z/)
5661 {# skipping system backup files
5662 return 1;
5663 }
5664 if($Path=~/(\A|[\/\\]+)(\.(svn|git|bzr|hg)|CVS)([\/\\]+|\Z)/)
5665 {# skipping hidden .svn, .git, .bzr, .hg and CVS directories
5666 return 1;
5667 }
5668 return 0;
5669}
5670
Andrey Ponomarenko9927e332012-10-19 10:50:48 +04005671sub sortByWord($$)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005672{
5673 my ($ArrRef, $W) = @_;
5674 return if(length($W)<2);
5675 @{$ArrRef} = sort {get_filename($b)=~/\Q$W\E/i<=>get_filename($a)=~/\Q$W\E/i} @{$ArrRef};
5676}
5677
Andrey Ponomarenko9927e332012-10-19 10:50:48 +04005678sub sortHeaders($$)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005679{
5680 my ($H1, $H2) = @_;
5681 $H1=~s/\.[a-z]+\Z//ig;
5682 $H2=~s/\.[a-z]+\Z//ig;
5683 my ($HDir1, $Hname1) = separate_path($H1);
5684 my ($HDir2, $Hname2) = separate_path($H2);
5685 my $Dirname1 = get_filename($HDir1);
5686 my $Dirname2 = get_filename($HDir2);
Andrey Ponomarenko9927e332012-10-19 10:50:48 +04005687 if($_[0] eq $_[1]
5688 or $H1 eq $H2) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005689 return 0;
5690 }
5691 elsif($H1=~/\A\Q$H2\E/) {
5692 return 1;
5693 }
5694 elsif($H2=~/\A\Q$H1\E/) {
5695 return -1;
5696 }
5697 elsif($HDir1=~/\Q$Hname1\E/i
5698 and $HDir2!~/\Q$Hname2\E/i)
Andrey Ponomarenko9927e332012-10-19 10:50:48 +04005699 { # include/glib-2.0/glib.h
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005700 return -1;
5701 }
5702 elsif($HDir2=~/\Q$Hname2\E/i
5703 and $HDir1!~/\Q$Hname1\E/i)
Andrey Ponomarenko9927e332012-10-19 10:50:48 +04005704 { # include/glib-2.0/glib.h
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005705 return 1;
5706 }
5707 elsif($Hname1=~/\Q$Dirname1\E/i
5708 and $Hname2!~/\Q$Dirname2\E/i)
Andrey Ponomarenko9927e332012-10-19 10:50:48 +04005709 { # include/hildon-thumbnail/hildon-thumbnail-factory.h
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005710 return -1;
5711 }
5712 elsif($Hname2=~/\Q$Dirname2\E/i
5713 and $Hname1!~/\Q$Dirname1\E/i)
Andrey Ponomarenko9927e332012-10-19 10:50:48 +04005714 { # include/hildon-thumbnail/hildon-thumbnail-factory.h
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005715 return 1;
5716 }
Andrey Ponomarenko9927e332012-10-19 10:50:48 +04005717 elsif($Hname1=~/(config|lib|util)/i
5718 and $Hname2!~/(config|lib|util)/i)
5719 { # include/alsa/asoundlib.h
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005720 return -1;
5721 }
Andrey Ponomarenko9927e332012-10-19 10:50:48 +04005722 elsif($Hname2=~/(config|lib|util)/i
5723 and $Hname1!~/(config|lib|util)/i)
5724 { # include/alsa/asoundlib.h
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005725 return 1;
5726 }
5727 elsif(checkRelevance($H1)
5728 and not checkRelevance($H2))
Andrey Ponomarenko9927e332012-10-19 10:50:48 +04005729 { # libebook/e-book.h
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005730 return -1;
5731 }
5732 elsif(checkRelevance($H2)
5733 and not checkRelevance($H1))
Andrey Ponomarenko9927e332012-10-19 10:50:48 +04005734 { # libebook/e-book.h
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005735 return 1;
5736 }
Andrey Ponomarenko9927e332012-10-19 10:50:48 +04005737 else
5738 {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005739 return (lc($H1) cmp lc($H2));
5740 }
5741}
5742
5743sub searchForHeaders($)
5744{
5745 my $LibVersion = $_[0];
5746 # gcc standard include paths
5747 find_gcc_cxx_headers($LibVersion);
5748 # processing header paths
5749 foreach my $Path (keys(%{$Descriptor{$LibVersion}{"IncludePaths"}}),
5750 keys(%{$Descriptor{$LibVersion}{"AddIncludePaths"}}))
5751 {
5752 my $IPath = $Path;
Andrey Ponomarenkoa01311b2012-06-08 17:20:02 +04005753 if($SystemRoot)
5754 {
5755 if(is_abs($Path)) {
5756 $Path = $SystemRoot.$Path;
5757 }
5758 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005759 if(not -e $Path) {
5760 exitStatus("Access_Error", "can't access \'$Path\'");
5761 }
5762 elsif(-f $Path) {
5763 exitStatus("Access_Error", "\'$Path\' - not a directory");
5764 }
5765 elsif(-d $Path)
5766 {
5767 $Path = get_abs_path($Path);
5768 register_directory($Path, 0, $LibVersion);
5769 if($Descriptor{$LibVersion}{"AddIncludePaths"}{$IPath}) {
5770 $Add_Include_Paths{$LibVersion}{$Path} = 1;
5771 }
5772 else {
5773 $Include_Paths{$LibVersion}{$Path} = 1;
5774 }
5775 }
5776 }
5777 if(keys(%{$Include_Paths{$LibVersion}})) {
5778 $INC_PATH_AUTODETECT{$LibVersion} = 0;
5779 }
5780 # registering directories
5781 foreach my $Path (split(/\s*\n\s*/, $Descriptor{$LibVersion}{"Headers"}))
5782 {
5783 next if(not -e $Path);
5784 $Path = get_abs_path($Path);
5785 $Path = path_format($Path, $OSgroup);
5786 if(-d $Path) {
5787 register_directory($Path, 1, $LibVersion);
5788 }
5789 elsif(-f $Path)
5790 {
5791 my $Dir = get_dirname($Path);
5792 if(not $SystemPaths{"include"}{$Dir}
5793 and not $LocalIncludes{$Dir})
5794 {
5795 register_directory($Dir, 1, $LibVersion);
5796 if(my $OutDir = get_dirname($Dir))
5797 { # registering the outer directory
5798 if(not $SystemPaths{"include"}{$OutDir}
5799 and not $LocalIncludes{$OutDir}) {
5800 register_directory($OutDir, 0, $LibVersion);
5801 }
5802 }
5803 }
5804 }
5805 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +04005806
5807 # clean memory
5808 %RegisteredDirs = ();
5809
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005810 # registering headers
5811 my $Position = 0;
5812 foreach my $Dest (split(/\s*\n\s*/, $Descriptor{$LibVersion}{"Headers"}))
5813 {
5814 if(is_abs($Dest) and not -e $Dest) {
5815 exitStatus("Access_Error", "can't access \'$Dest\'");
5816 }
5817 $Dest = path_format($Dest, $OSgroup);
5818 if(is_header($Dest, 1, $LibVersion))
5819 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04005820 if(my $HPath = registerHeader($Dest, $LibVersion)) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005821 $Registered_Headers{$LibVersion}{$HPath}{"Pos"} = $Position++;
5822 }
5823 }
5824 elsif(-d $Dest)
5825 {
5826 my @Registered = ();
5827 foreach my $Path (cmd_find($Dest,"f","",""))
5828 {
5829 next if(ignore_path($Path));
5830 next if(not is_header($Path, 0, $LibVersion));
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04005831 if(my $HPath = registerHeader($Path, $LibVersion)) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005832 push(@Registered, $HPath);
5833 }
5834 }
Andrey Ponomarenko9927e332012-10-19 10:50:48 +04005835 @Registered = sort {sortHeaders($a, $b)} @Registered;
5836 sortByWord(\@Registered, $TargetLibraryShortName);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005837 foreach my $Path (@Registered) {
5838 $Registered_Headers{$LibVersion}{$Path}{"Pos"} = $Position++;
5839 }
5840 }
5841 else {
5842 exitStatus("Access_Error", "can't identify \'$Dest\' as a header file");
5843 }
5844 }
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04005845 if(my $HList = $Descriptor{$LibVersion}{"IncludePreamble"})
5846 { # preparing preamble headers
5847 my $PPos=0;
5848 foreach my $Header (split(/\s*\n\s*/, $HList))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005849 {
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04005850 if(is_abs($Header) and not -f $Header) {
5851 exitStatus("Access_Error", "can't access file \'$Header\'");
5852 }
5853 $Header = path_format($Header, $OSgroup);
5854 if(my $Header_Path = is_header($Header, 1, $LibVersion))
5855 {
Andrey Ponomarenko9927e332012-10-19 10:50:48 +04005856 if(defined $Include_Preamble{$LibVersion}{$Header_Path})
5857 { # duplicate
5858 next;
5859 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04005860 next if(skipHeader($Header_Path, $LibVersion));
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04005861 $Include_Preamble{$LibVersion}{$Header_Path}{"Position"} = $PPos++;
5862 }
5863 else {
5864 exitStatus("Access_Error", "can't identify \'$Header\' as a header file");
5865 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005866 }
5867 }
5868 foreach my $Header_Name (keys(%{$HeaderName_Paths{$LibVersion}}))
5869 { # set relative paths (for duplicates)
5870 if(keys(%{$HeaderName_Paths{$LibVersion}{$Header_Name}})>=2)
5871 { # search for duplicates
5872 my $FirstPath = (keys(%{$HeaderName_Paths{$LibVersion}{$Header_Name}}))[0];
5873 my $Prefix = get_dirname($FirstPath);
5874 while($Prefix=~/\A(.+)[\/\\]+[^\/\\]+\Z/)
5875 { # detect a shortest distinguishing prefix
5876 my $NewPrefix = $1;
5877 my %Identity = ();
5878 foreach my $Path (keys(%{$HeaderName_Paths{$LibVersion}{$Header_Name}}))
5879 {
5880 if($Path=~/\A\Q$Prefix\E[\/\\]+(.*)\Z/) {
5881 $Identity{$Path} = $1;
5882 }
5883 }
5884 if(keys(%Identity)==keys(%{$HeaderName_Paths{$LibVersion}{$Header_Name}}))
5885 { # all names are differend with current prefix
5886 foreach my $Path (keys(%{$HeaderName_Paths{$LibVersion}{$Header_Name}})) {
5887 $Registered_Headers{$LibVersion}{$Path}{"Identity"} = $Identity{$Path};
5888 }
5889 last;
5890 }
5891 $Prefix = $NewPrefix; # increase prefix
5892 }
5893 }
5894 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +04005895
5896 # clean memory
5897 %HeaderName_Paths = ();
5898
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005899 foreach my $HeaderName (keys(%{$Include_Order{$LibVersion}}))
5900 { # ordering headers according to descriptor
5901 my $PairName=$Include_Order{$LibVersion}{$HeaderName};
5902 my ($Pos, $PairPos) = (-1, -1);
5903 my ($Path, $PairPath) = ();
5904 my @Paths = keys(%{$Registered_Headers{$LibVersion}});
5905 @Paths = sort {int($Registered_Headers{$LibVersion}{$a}{"Pos"})<=>int($Registered_Headers{$LibVersion}{$b}{"Pos"})} @Paths;
5906 foreach my $Header_Path (@Paths)
5907 {
5908 if(get_filename($Header_Path) eq $PairName)
5909 {
5910 $PairPos = $Registered_Headers{$LibVersion}{$Header_Path}{"Pos"};
5911 $PairPath = $Header_Path;
5912 }
5913 if(get_filename($Header_Path) eq $HeaderName)
5914 {
5915 $Pos = $Registered_Headers{$LibVersion}{$Header_Path}{"Pos"};
5916 $Path = $Header_Path;
5917 }
5918 }
5919 if($PairPos!=-1 and $Pos!=-1
5920 and int($PairPos)<int($Pos))
5921 {
5922 my %Tmp = %{$Registered_Headers{$LibVersion}{$Path}};
5923 %{$Registered_Headers{$LibVersion}{$Path}} = %{$Registered_Headers{$LibVersion}{$PairPath}};
5924 %{$Registered_Headers{$LibVersion}{$PairPath}} = %Tmp;
5925 }
5926 }
5927 if(not keys(%{$Registered_Headers{$LibVersion}})) {
5928 exitStatus("Error", "header files are not found in the ".$Descriptor{$LibVersion}{"Version"});
5929 }
5930}
5931
5932sub detect_real_includes($$)
5933{
5934 my ($AbsPath, $LibVersion) = @_;
5935 return () if(not $LibVersion or not $AbsPath or not -e $AbsPath);
5936 if($Cache{"detect_real_includes"}{$LibVersion}{$AbsPath}
5937 or keys(%{$RecursiveIncludes{$LibVersion}{$AbsPath}})) {
5938 return keys(%{$RecursiveIncludes{$LibVersion}{$AbsPath}});
5939 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +04005940 $Cache{"detect_real_includes"}{$LibVersion}{$AbsPath}=1;
5941
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005942 my $Path = callPreprocessor($AbsPath, "", $LibVersion);
5943 return () if(not $Path);
5944 open(PREPROC, $Path);
5945 while(<PREPROC>)
5946 {
5947 if(/#\s+\d+\s+"([^"]+)"[\s\d]*\n/)
5948 {
5949 my $Include = path_format($1, $OSgroup);
5950 if($Include=~/\<(built\-in|internal|command(\-|\s)line)\>|\A\./) {
5951 next;
5952 }
5953 if($Include eq $AbsPath) {
5954 next;
5955 }
5956 $RecursiveIncludes{$LibVersion}{$AbsPath}{$Include} = 1;
5957 }
5958 }
5959 close(PREPROC);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005960 return keys(%{$RecursiveIncludes{$LibVersion}{$AbsPath}});
5961}
5962
5963sub detect_header_includes($$)
5964{
5965 my ($Path, $LibVersion) = @_;
Andrey Ponomarenko85043792012-05-14 16:48:07 +04005966 return if(not $LibVersion or not $Path);
5967 if(defined $Cache{"detect_header_includes"}{$LibVersion}{$Path}) {
5968 return;
5969 }
5970 $Cache{"detect_header_includes"}{$LibVersion}{$Path}=1;
5971
5972 if(not -e $Path) {
5973 return;
5974 }
5975
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005976 my $Content = readFile($Path);
Andrey Ponomarenko85043792012-05-14 16:48:07 +04005977 if(my $Redirect = parse_redirect($Content, $Path, $LibVersion))
5978 { # detect error directive in headers
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04005979 if(my $RedirectPath = identifyHeader($Redirect, $LibVersion))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005980 {
5981 if($RedirectPath=~/\/usr\/include\// and $Path!~/\/usr\/include\//) {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04005982 $RedirectPath = identifyHeader(get_filename($Redirect), $LibVersion);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005983 }
5984 if($RedirectPath ne $Path) {
5985 $Header_ErrorRedirect{$LibVersion}{$Path} = $RedirectPath;
5986 }
5987 }
Andrey Ponomarenko9927e332012-10-19 10:50:48 +04005988 else
5989 { # can't find
5990 $Header_ShouldNotBeUsed{$LibVersion}{$Path} = 1;
5991 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005992 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +04005993 if(my $Inc = parse_includes($Content, $Path))
5994 {
5995 foreach my $Include (keys(%{$Inc}))
5996 { # detect includes
Andrey Ponomarenko85043792012-05-14 16:48:07 +04005997 $Header_Includes{$LibVersion}{$Path}{$Include} = $Inc->{$Include};
5998 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005999 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006000}
6001
6002sub simplify_path($)
6003{
6004 my $Path = $_[0];
6005 while($Path=~s&([\/\\])[^\/\\]+[\/\\]\.\.[\/\\]&$1&){};
6006 return $Path;
6007}
6008
6009sub fromLibc($)
6010{ # GLIBC header
6011 my $Path = $_[0];
6012 my ($Dir, $Name) = separate_path($Path);
6013 if(get_filename($Dir)=~/\A(include|libc)\Z/ and $GlibcHeader{$Name})
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04006014 { # /usr/include/{stdio, ...}.h
6015 # epoc32/include/libc/{stdio, ...}.h
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006016 return 1;
6017 }
6018 if(isLibcDir($Dir)) {
6019 return 1;
6020 }
6021 return 0;
6022}
6023
6024sub isLibcDir($)
6025{ # GLIBC directory
6026 my $Dir = $_[0];
6027 my ($OutDir, $Name) = separate_path($Dir);
6028 if(get_filename($OutDir)=~/\A(include|libc)\Z/
6029 and ($Name=~/\Aasm(|-.+)\Z/ or $GlibcDir{$Name}))
6030 { # /usr/include/{sys,bits,asm,asm-*}/*.h
6031 return 1;
6032 }
6033 return 0;
6034}
6035
6036sub detect_recursive_includes($$)
6037{
6038 my ($AbsPath, $LibVersion) = @_;
6039 return () if(not $AbsPath);
6040 if(isCyclical(\@RecurInclude, $AbsPath)) {
6041 return keys(%{$RecursiveIncludes{$LibVersion}{$AbsPath}});
6042 }
6043 my ($AbsDir, $Name) = separate_path($AbsPath);
6044 if(isLibcDir($AbsDir))
6045 { # GLIBC internals
6046 return ();
6047 }
6048 if(keys(%{$RecursiveIncludes{$LibVersion}{$AbsPath}})) {
6049 return keys(%{$RecursiveIncludes{$LibVersion}{$AbsPath}});
6050 }
6051 return () if($OSgroup ne "windows" and $Name=~/windows|win32|win64/i);
6052 return () if($MAIN_CPP_DIR and $AbsPath=~/\A\Q$MAIN_CPP_DIR\E/ and not $STDCXX_TESTING);
6053 push(@RecurInclude, $AbsPath);
6054 if($DefaultGccPaths{$AbsDir}
6055 or fromLibc($AbsPath))
6056 { # check "real" (non-"model") include paths
6057 my @Paths = detect_real_includes($AbsPath, $LibVersion);
6058 pop(@RecurInclude);
6059 return @Paths;
6060 }
6061 if(not keys(%{$Header_Includes{$LibVersion}{$AbsPath}})) {
6062 detect_header_includes($AbsPath, $LibVersion);
6063 }
6064 foreach my $Include (keys(%{$Header_Includes{$LibVersion}{$AbsPath}}))
6065 {
Andrey Ponomarenko85043792012-05-14 16:48:07 +04006066 my $IncType = $Header_Includes{$LibVersion}{$AbsPath}{$Include};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006067 my $HPath = "";
Andrey Ponomarenko85043792012-05-14 16:48:07 +04006068 if($IncType<0)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006069 { # for #include "..."
6070 my $Candidate = joinPath($AbsDir, $Include);
6071 if(-f $Candidate) {
6072 $HPath = simplify_path($Candidate);
6073 }
6074 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +04006075 elsif($IncType>0
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04006076 and $Include=~/[\/\\]/) # and not find_in_defaults($Include)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006077 { # search for the nearest header
6078 # QtCore/qabstractanimation.h includes <QtCore/qobject.h>
6079 my $Candidate = joinPath(get_dirname($AbsDir), $Include);
6080 if(-f $Candidate) {
6081 $HPath = $Candidate;
6082 }
6083 }
6084 if(not $HPath) {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04006085 $HPath = identifyHeader($Include, $LibVersion);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006086 }
6087 next if(not $HPath);
6088 if($HPath eq $AbsPath) {
6089 next;
6090 }
Andrey Ponomarenko9927e332012-10-19 10:50:48 +04006091
6092 if($Debug)
6093 { # boundary headers
6094 #if($HPath=~/vtk/ and $AbsPath!~/vtk/)
6095 #{
6096 # print STDERR "$AbsPath -> $HPath\n";
6097 #}
6098 }
6099
Andrey Ponomarenko85043792012-05-14 16:48:07 +04006100 $RecursiveIncludes{$LibVersion}{$AbsPath}{$HPath} = $IncType;
6101 if($IncType>0)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006102 { # only include <...>, skip include "..." prefixes
6103 $Header_Include_Prefix{$LibVersion}{$AbsPath}{$HPath}{get_dirname($Include)} = 1;
6104 }
6105 foreach my $IncPath (detect_recursive_includes($HPath, $LibVersion))
6106 {
6107 if($IncPath eq $AbsPath) {
6108 next;
6109 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +04006110 my $RIncType = $RecursiveIncludes{$LibVersion}{$HPath}{$IncPath};
6111 if($RIncType==-1)
6112 { # include "..."
6113 $RIncType = $IncType;
6114 }
6115 elsif($RIncType==2)
6116 {
6117 if($IncType!=-1) {
6118 $RIncType = $IncType;
6119 }
6120 }
6121 $RecursiveIncludes{$LibVersion}{$AbsPath}{$IncPath} = $RIncType;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006122 foreach my $Prefix (keys(%{$Header_Include_Prefix{$LibVersion}{$HPath}{$IncPath}})) {
6123 $Header_Include_Prefix{$LibVersion}{$AbsPath}{$IncPath}{$Prefix} = 1;
6124 }
6125 }
6126 foreach my $Dep (keys(%{$Header_Include_Prefix{$LibVersion}{$AbsPath}}))
6127 {
6128 if($GlibcHeader{get_filename($Dep)} and keys(%{$Header_Include_Prefix{$LibVersion}{$AbsPath}{$Dep}})>=2
6129 and defined $Header_Include_Prefix{$LibVersion}{$AbsPath}{$Dep}{""})
6130 { # distinguish math.h from glibc and math.h from the tested library
6131 delete($Header_Include_Prefix{$LibVersion}{$AbsPath}{$Dep}{""});
6132 last;
6133 }
6134 }
6135 }
6136 pop(@RecurInclude);
6137 return keys(%{$RecursiveIncludes{$LibVersion}{$AbsPath}});
6138}
6139
6140sub find_in_framework($$$)
6141{
6142 my ($Header, $Framework, $LibVersion) = @_;
6143 return "" if(not $Header or not $Framework or not $LibVersion);
6144 if(defined $Cache{"find_in_framework"}{$LibVersion}{$Framework}{$Header}) {
6145 return $Cache{"find_in_framework"}{$LibVersion}{$Framework}{$Header};
6146 }
6147 foreach my $Dependency (sort {get_depth($a)<=>get_depth($b)} keys(%{$Header_Dependency{$LibVersion}}))
6148 {
6149 if(get_filename($Dependency) eq $Framework
6150 and -f get_dirname($Dependency)."/".$Header) {
6151 return ($Cache{"find_in_framework"}{$LibVersion}{$Framework}{$Header} = get_dirname($Dependency));
6152 }
6153 }
6154 return ($Cache{"find_in_framework"}{$LibVersion}{$Framework}{$Header} = "");
6155}
6156
6157sub find_in_defaults($)
6158{
6159 my $Header = $_[0];
6160 return "" if(not $Header);
6161 if(defined $Cache{"find_in_defaults"}{$Header}) {
6162 return $Cache{"find_in_defaults"}{$Header};
6163 }
6164 foreach my $Dir (sort {get_depth($a)<=>get_depth($b)}
6165 (keys(%DefaultIncPaths), keys(%DefaultGccPaths), keys(%DefaultCppPaths), keys(%UserIncPath)))
6166 {
6167 next if(not $Dir);
6168 if(-f $Dir."/".$Header) {
6169 return ($Cache{"find_in_defaults"}{$Header}=$Dir);
6170 }
6171 }
6172 return ($Cache{"find_in_defaults"}{$Header}="");
6173}
6174
6175sub cmp_paths($$)
6176{
6177 my ($Path1, $Path2) = @_;
6178 my @Parts1 = split(/[\/\\]/, $Path1);
6179 my @Parts2 = split(/[\/\\]/, $Path2);
6180 foreach my $Num (0 .. $#Parts1)
6181 {
6182 my $Part1 = $Parts1[$Num];
6183 my $Part2 = $Parts2[$Num];
6184 if($GlibcDir{$Part1}
6185 and not $GlibcDir{$Part2}) {
6186 return 1;
6187 }
6188 elsif($GlibcDir{$Part2}
6189 and not $GlibcDir{$Part1}) {
6190 return -1;
6191 }
6192 elsif($Part1=~/glib/
6193 and $Part2!~/glib/) {
6194 return 1;
6195 }
6196 elsif($Part1!~/glib/
6197 and $Part2=~/glib/) {
6198 return -1;
6199 }
6200 elsif(my $CmpRes = ($Part1 cmp $Part2)) {
6201 return $CmpRes;
6202 }
6203 }
6204 return 0;
6205}
6206
6207sub checkRelevance($)
6208{
6209 my ($Path) = @_;
6210 return 0 if(not $Path);
6211 if($SystemRoot) {
Andrey Ponomarenkoa01311b2012-06-08 17:20:02 +04006212 $Path = cut_path_prefix($Path, $SystemRoot);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006213 }
6214 my ($Dir, $Name) = separate_path($Path);
Andrey Ponomarenkoa01311b2012-06-08 17:20:02 +04006215 $Name=~s/\.\w+\Z//g; # remove extension (.h)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006216 my @Tokens = split(/[_\d\W]+/, $Name);
6217 foreach (@Tokens)
6218 {
6219 next if(not $_);
6220 if($Dir=~/(\A|lib|[_\d\W])\Q$_\E([_\d\W]|lib|\Z)/i
6221 or length($_)>=4 and $Dir=~/\Q$_\E/i)
6222 { # include/gupnp-1.0/libgupnp/gupnp-context.h
6223 # include/evolution-data-server-1.4/libebook/e-book.h
6224 return 1;
6225 }
6226 }
6227 return 0;
6228}
6229
6230sub checkFamily(@)
6231{
6232 my @Paths = @_;
6233 return 1 if($#Paths<=0);
6234 my %Prefix = ();
6235 foreach my $Path (@Paths)
6236 {
6237 if($SystemRoot) {
6238 $Path = cut_path_prefix($Path, $SystemRoot);
6239 }
6240 if(my $Dir = get_dirname($Path))
6241 {
6242 $Dir=~s/(\/[^\/]+?)[\d\.\-\_]+\Z/$1/g; # remove version suffix
6243 $Prefix{$Dir} += 1;
6244 $Prefix{get_dirname($Dir)} += 1;
6245 }
6246 }
6247 foreach (sort keys(%Prefix))
6248 {
6249 if(get_depth($_)>=3
6250 and $Prefix{$_}==$#Paths+1) {
6251 return 1;
6252 }
6253 }
6254 return 0;
6255}
6256
6257sub isAcceptable($$$)
6258{
6259 my ($Header, $Candidate, $LibVersion) = @_;
6260 my $HName = get_filename($Header);
6261 if(get_dirname($Header))
6262 { # with prefix
6263 return 1;
6264 }
6265 if($HName=~/config|setup/i and $Candidate=~/[\/\\]lib\d*[\/\\]/)
6266 { # allow to search for glibconfig.h in /usr/lib/glib-2.0/include/
6267 return 1;
6268 }
6269 if(checkRelevance($Candidate))
6270 { # allow to search for atk.h in /usr/include/atk-1.0/atk/
6271 return 1;
6272 }
6273 if(checkFamily(getSystemHeaders($HName, $LibVersion)))
6274 { # /usr/include/qt4/QtNetwork/qsslconfiguration.h
6275 # /usr/include/qt4/Qt/qsslconfiguration.h
6276 return 1;
6277 }
6278 if($OStarget eq "symbian")
6279 {
6280 if($Candidate=~/[\/\\]stdapis[\/\\]/) {
6281 return 1;
6282 }
6283 }
6284 return 0;
6285}
6286
6287sub isRelevant($$$)
6288{ # disallow to search for "abstract" headers in too deep directories
6289 my ($Header, $Candidate, $LibVersion) = @_;
6290 my $HName = get_filename($Header);
6291 if($OStarget eq "symbian")
6292 {
6293 if($Candidate=~/[\/\\](tools|stlportv5)[\/\\]/) {
6294 return 0;
6295 }
6296 }
Andrey Ponomarenko9927e332012-10-19 10:50:48 +04006297 if($OStarget ne "bsd")
6298 {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006299 if($Candidate=~/[\/\\]include[\/\\]bsd[\/\\]/)
6300 { # openssh: skip /usr/lib/bcc/include/bsd/signal.h
6301 return 0;
6302 }
6303 }
Andrey Ponomarenko9927e332012-10-19 10:50:48 +04006304 if($OStarget ne "windows")
6305 {
6306 if($Candidate=~/[\/\\](wine|msvcrt|windows)[\/\\]/)
6307 { # skip /usr/include/wine/msvcrt
6308 return 0;
6309 }
6310 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006311 if(not get_dirname($Header)
6312 and $Candidate=~/[\/\\]wx[\/\\]/)
6313 { # do NOT search in system /wx/ directory
6314 # for headers without a prefix: sstream.h
6315 return 0;
6316 }
6317 if($Candidate=~/c\+\+[\/\\]\d+/ and $MAIN_CPP_DIR
6318 and $Candidate!~/\A\Q$MAIN_CPP_DIR\E/)
6319 { # skip ../c++/3.3.3/ if using ../c++/4.5/
6320 return 0;
6321 }
6322 if($Candidate=~/[\/\\]asm-/
6323 and (my $Arch = getArch($LibVersion)) ne "unknown")
6324 { # arch-specific header files
6325 if($Candidate!~/[\/\\]asm-\Q$Arch\E/)
6326 {# skip ../asm-arm/ if using x86 architecture
6327 return 0;
6328 }
6329 }
6330 my @Candidates = getSystemHeaders($HName, $LibVersion);
6331 if($#Candidates==1)
6332 { # unique header
6333 return 1;
6334 }
6335 my @SCandidates = getSystemHeaders($Header, $LibVersion);
6336 if($#SCandidates==1)
6337 { # unique name
6338 return 1;
6339 }
6340 my $SystemDepth = $SystemRoot?get_depth($SystemRoot):0;
6341 if(get_depth($Candidate)-$SystemDepth>=5)
6342 { # abstract headers in too deep directories
6343 # sstream.h or typeinfo.h in /usr/include/wx-2.9/wx/
6344 if(not isAcceptable($Header, $Candidate, $LibVersion)) {
6345 return 0;
6346 }
6347 }
6348 if($Header eq "parser.h"
6349 and $Candidate!~/\/libxml2\//)
6350 { # select parser.h from xml2 library
6351 return 0;
6352 }
6353 if(not get_dirname($Header)
6354 and keys(%{$SystemHeaders{$HName}})>=3)
6355 { # many headers with the same name
6356 # like thread.h included without a prefix
6357 if(not checkFamily(@Candidates)) {
6358 return 0;
6359 }
6360 }
6361 return 1;
6362}
6363
6364sub selectSystemHeader($$)
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04006365{ # cache function
6366 if(defined $Cache{"selectSystemHeader"}{$_[1]}{$_[0]}) {
6367 return $Cache{"selectSystemHeader"}{$_[1]}{$_[0]};
6368 }
6369 return ($Cache{"selectSystemHeader"}{$_[1]}{$_[0]} = selectSystemHeader_I(@_));
6370}
6371
6372sub selectSystemHeader_I($$)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006373{
6374 my ($Header, $LibVersion) = @_;
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04006375 if(-f $Header) {
6376 return $Header;
6377 }
6378 if(is_abs($Header) and not -f $Header)
6379 { # incorrect absolute path
6380 return "";
6381 }
Andrey Ponomarenko9927e332012-10-19 10:50:48 +04006382 if(defined $ConfHeaders{lc($Header)})
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04006383 { # too abstract configuration headers
6384 return "";
6385 }
Andrey Ponomarenko9927e332012-10-19 10:50:48 +04006386 my $HName = get_filename($Header);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006387 if($OSgroup ne "windows")
6388 {
Andrey Ponomarenko9927e332012-10-19 10:50:48 +04006389 if(defined $WinHeaders{lc($HName)}
6390 or $HName=~/windows|win32|win64/i)
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04006391 { # windows headers
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006392 return "";
6393 }
Andrey Ponomarenko9927e332012-10-19 10:50:48 +04006394 }
6395 if($OSgroup ne "macos")
6396 {
6397 if($HName eq "fp.h")
6398 { # pngconf.h includes fp.h for MACOS
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006399 return "";
6400 }
6401 }
6402 if($OSgroup ne "solaris")
6403 {
Andrey Ponomarenko9927e332012-10-19 10:50:48 +04006404 if($Header eq "thread.h") {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006405 return "";
6406 }
6407 }
Andrey Ponomarenko07aea072012-11-12 16:15:07 +04006408 if($OSgroup ne "hpux")
6409 {
6410 if($Header eq "sys/stream.h") {
6411 return "";
6412 }
6413 }
Andrey Ponomarenko9927e332012-10-19 10:50:48 +04006414 if($ObsoleteHeaders{$HName}) {
6415 return "";
6416 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04006417
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006418 foreach my $Path (keys(%{$SystemPaths{"include"}}))
6419 { # search in default paths
6420 if(-f $Path."/".$Header) {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04006421 return joinPath($Path,$Header);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006422 }
6423 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04006424 if(not keys(%SystemHeaders))
6425 { # register all headers in system include dirs
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006426 detectSystemHeaders();
6427 }
6428 foreach my $Candidate (sort {get_depth($a)<=>get_depth($b)}
6429 sort {cmp_paths($b, $a)} getSystemHeaders($Header, $LibVersion))
6430 {
6431 if(isRelevant($Header, $Candidate, $LibVersion)) {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04006432 return $Candidate;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006433 }
6434 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04006435 # error
6436 return "";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006437}
6438
6439sub getSystemHeaders($$)
6440{
6441 my ($Header, $LibVersion) = @_;
6442 my @Candidates = ();
6443 foreach my $Candidate (sort keys(%{$SystemHeaders{$Header}}))
6444 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04006445 if(skipHeader($Candidate, $LibVersion)) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006446 next;
6447 }
6448 push(@Candidates, $Candidate);
6449 }
6450 return @Candidates;
6451}
6452
6453sub cut_path_prefix($$)
6454{
6455 my ($Path, $Prefix) = @_;
6456 return $Path if(not $Prefix);
6457 $Prefix=~s/[\/\\]+\Z//;
6458 $Path=~s/\A\Q$Prefix\E([\/\\]+|\Z)//;
6459 return $Path;
6460}
6461
6462sub is_default_include_dir($)
6463{
6464 my $Dir = $_[0];
6465 $Dir=~s/[\/\\]+\Z//;
6466 return ($DefaultGccPaths{$Dir} or $DefaultCppPaths{$Dir} or $DefaultIncPaths{$Dir});
6467}
6468
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04006469sub identifyHeader($$)
6470{ # cache function
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006471 my ($Header, $LibVersion) = @_;
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04006472 if(not $Header) {
6473 return "";
6474 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006475 $Header=~s/\A(\.\.[\\\/])+//g;
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04006476 if(defined $Cache{"identifyHeader"}{$LibVersion}{$Header}) {
6477 return $Cache{"identifyHeader"}{$LibVersion}{$Header};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006478 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04006479 return ($Cache{"identifyHeader"}{$LibVersion}{$Header} = identifyHeader_I($Header, $LibVersion));
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006480}
6481
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04006482sub identifyHeader_I($$)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006483{ # search for header by absolute path, relative path or name
6484 my ($Header, $LibVersion) = @_;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006485 if(-f $Header)
6486 { # it's relative or absolute path
6487 return get_abs_path($Header);
6488 }
6489 elsif($GlibcHeader{$Header} and not $GLIBC_TESTING
6490 and my $HeaderDir = find_in_defaults($Header))
6491 { # search for libc headers in the /usr/include
6492 # for non-libc target library before searching
6493 # in the library paths
6494 return joinPath($HeaderDir,$Header);
6495 }
6496 elsif(my $Path = $Include_Neighbors{$LibVersion}{$Header})
6497 { # search in the target library paths
6498 return $Path;
6499 }
6500 elsif($DefaultGccHeader{$Header})
6501 { # search in the internal GCC include paths
6502 return $DefaultGccHeader{$Header};
6503 }
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04006504 elsif(my $DefaultDir = find_in_defaults($Header))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006505 { # search in the default GCC include paths
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04006506 return joinPath($DefaultDir,$Header);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006507 }
6508 elsif($DefaultCppHeader{$Header})
6509 { # search in the default G++ include paths
6510 return $DefaultCppHeader{$Header};
6511 }
6512 elsif(my $AnyPath = selectSystemHeader($Header, $LibVersion))
6513 { # search everywhere in the system
6514 return $AnyPath;
6515 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04006516 elsif($OSgroup eq "macos")
6517 { # search in frameworks: "OpenGL/gl.h" is "OpenGL.framework/Headers/gl.h"
6518 if(my $Dir = get_dirname($Header))
6519 {
6520 my $RelPath = "Headers\/".get_filename($Header);
6521 if(my $HeaderDir = find_in_framework($RelPath, $Dir.".framework", $LibVersion)) {
6522 return joinPath($HeaderDir, $RelPath);
6523 }
6524 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006525 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04006526 # cannot find anything
6527 return "";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006528}
6529
6530sub getLocation($)
6531{
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04006532 if($_[0] and my $Info = $LibInfo{$Version}{"info"}{$_[0]})
6533 {
6534 if($Info=~/srcp[ ]*:[ ]*([\w\-\<\>\.\+\/\\]+):(\d+) /) {
Andrey Ponomarenko9927e332012-10-19 10:50:48 +04006535 return (path_format($1, $OSgroup), $2);
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04006536 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006537 }
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04006538 return ();
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006539}
6540
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006541sub getNameByInfo($)
6542{
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04006543 if($_[0] and my $Info = $LibInfo{$Version}{"info"}{$_[0]})
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04006544 {
6545 if($Info=~/name[ ]*:[ ]*@(\d+) /)
6546 {
6547 if(my $NInfo = $LibInfo{$Version}{"info"}{$1})
6548 {
6549 if($NInfo=~/strg[ ]*:[ ]*(.*?)[ ]+lngt/)
6550 { # short unsigned int (may include spaces)
6551 return $1;
6552 }
6553 }
6554 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006555 }
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04006556 return "";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006557}
6558
6559sub getTreeStr($)
6560{
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04006561 if($_[0] and my $Info = $LibInfo{$Version}{"info"}{$_[0]})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006562 {
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04006563 if($Info=~/strg[ ]*:[ ]*([^ ]*)/)
6564 {
6565 my $Str = $1;
Andrey Ponomarenko07aea072012-11-12 16:15:07 +04006566 if($CppMode{$Version}
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04006567 and $Str=~/\Ac99_(.+)\Z/) {
6568 if($CppKeywords_A{$1}) {
6569 $Str=$1;
6570 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006571 }
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04006572 return $Str;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006573 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006574 }
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04006575 return "";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006576}
6577
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006578sub getFuncShortName($)
6579{
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04006580 if(my $Info = $LibInfo{$Version}{"info"}{$_[0]})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006581 {
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04006582 if($Info=~/ operator /)
6583 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04006584 if($Info=~/ conversion /)
6585 {
6586 if(my $Rid = $SymbolInfo{$Version}{$_[0]}{"Return"})
6587 {
6588 if(my $RName = $TypeInfo{$Version}{$Rid}{"Name"}) {
6589 return "operator ".$RName;
6590 }
6591 }
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04006592 }
6593 else
6594 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04006595 if($Info=~/ operator[ ]+([a-zA-Z]+) /)
6596 {
6597 if(my $Ind = $Operator_Indication{$1}) {
6598 return "operator".$Ind;
6599 }
6600 elsif(not $UnknownOperator{$1})
6601 {
6602 printMsg("WARNING", "unknown operator $1");
6603 $UnknownOperator{$1} = 1;
6604 }
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04006605 }
6606 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006607 }
6608 else
6609 {
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04006610 if($Info=~/name[ ]*:[ ]*@(\d+) /) {
6611 return getTreeStr($1);
6612 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006613 }
6614 }
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04006615 return "";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006616}
6617
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006618sub getFuncReturn($)
6619{
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04006620 if($_[0] and my $Info = $LibInfo{$Version}{"info"}{$_[0]})
6621 {
6622 if($Info=~/type[ ]*:[ ]*@(\d+) /)
6623 {
6624 if($LibInfo{$Version}{"info"}{$1}=~/retn[ ]*:[ ]*@(\d+) /) {
6625 return $1;
6626 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006627 }
6628 }
6629 return "";
6630}
6631
6632sub getFuncOrig($)
6633{
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04006634 if($_[0] and my $Info = $LibInfo{$Version}{"info"}{$_[0]})
6635 {
6636 if($Info=~/orig[ ]*:[ ]*@(\d+) /) {
6637 return $1;
6638 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006639 }
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04006640 return $_[0];
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006641}
6642
6643sub unmangleSymbol($)
6644{
6645 my $Symbol = $_[0];
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04006646 if(my @Unmngl = unmangleArray($Symbol)) {
6647 return $Unmngl[0];
6648 }
6649 return "";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006650}
6651
6652sub unmangleArray(@)
6653{
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04006654 if($_[0]=~/\A\?/)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006655 { # MSVC mangling
6656 my $UndNameCmd = get_CmdPath("undname");
6657 if(not $UndNameCmd) {
6658 exitStatus("Not_Found", "can't find \"undname\"");
6659 }
6660 writeFile("$TMP_DIR/unmangle", join("\n", @_));
Andrey Ponomarenkoa01311b2012-06-08 17:20:02 +04006661 return split(/\n/, `$UndNameCmd 0x8386 \"$TMP_DIR/unmangle\"`);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006662 }
6663 else
6664 { # GCC mangling
6665 my $CppFiltCmd = get_CmdPath("c++filt");
6666 if(not $CppFiltCmd) {
6667 exitStatus("Not_Found", "can't find c++filt in PATH");
6668 }
Andrey Ponomarenko9927e332012-10-19 10:50:48 +04006669 if(not defined $CPPFILT_SUPPORT_FILE)
6670 {
6671 my $Info = `$CppFiltCmd -h 2>&1`;
6672 $CPPFILT_SUPPORT_FILE = $Info=~/\@<file>/;
6673 }
6674 if($CPPFILT_SUPPORT_FILE)
6675 { # new versions of c++filt can take a file
6676 if($#_>$MAX_CPPFILT_FILE_SIZE)
6677 { # c++filt <= 2.22 may crash on large files (larger than 8mb)
6678 # this is fixed in the oncoming version of Binutils
6679 my @Half = splice(@_, 0, ($#_+1)/2);
6680 return (unmangleArray(@Half), unmangleArray(@_))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006681 }
Andrey Ponomarenko9927e332012-10-19 10:50:48 +04006682 else
6683 {
6684 my $NoStrip = "";
6685 if($OSgroup eq "macos"
6686 or $OSgroup eq "windows") {
6687 $NoStrip = "-n";
6688 }
6689 writeFile("$TMP_DIR/unmangle", join("\n", @_));
6690 my $Res = `$CppFiltCmd $NoStrip \@\"$TMP_DIR/unmangle\"`;
6691 if($?==139)
6692 { # segmentation fault
6693 printMsg("ERROR", "internal error - c++filt crashed, try to reduce MAX_CPPFILT_FILE_SIZE constant");
6694 }
6695 return split(/\n/, $Res);
6696 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006697 }
6698 else
6699 { # old-style unmangling
Andrey Ponomarenko9927e332012-10-19 10:50:48 +04006700 if($#_>$MAX_COMMAND_LINE_ARGUMENTS)
6701 {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006702 my @Half = splice(@_, 0, ($#_+1)/2);
6703 return (unmangleArray(@Half), unmangleArray(@_))
6704 }
6705 else
6706 {
6707 my $NoStrip = "";
6708 if($OSgroup eq "macos"
6709 or $OSgroup eq "windows") {
6710 $NoStrip = "-n";
6711 }
6712 my $Strings = join(" ", @_);
Andrey Ponomarenko9927e332012-10-19 10:50:48 +04006713 my $Res = `$CppFiltCmd $NoStrip $Strings`;
6714 if($?==139)
6715 { # segmentation fault
6716 printMsg("ERROR", "internal error - c++filt crashed, try to reduce MAX_COMMAND_LINE_ARGUMENTS constant");
6717 }
6718 return split(/\n/, $Res);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006719 }
6720 }
6721 }
6722}
6723
6724sub get_SignatureNoInfo($$)
6725{
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04006726 my ($Symbol, $LibVersion) = @_;
6727 if($Cache{"get_SignatureNoInfo"}{$LibVersion}{$Symbol}) {
6728 return $Cache{"get_SignatureNoInfo"}{$LibVersion}{$Symbol};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006729 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04006730 my ($MnglName, $VersionSpec, $SymbolVersion) = separate_symbol($Symbol);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006731 my $Signature = $tr_name{$MnglName}?$tr_name{$MnglName}:$MnglName;
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04006732 if($Symbol=~/\A(_Z|\?)/)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006733 { # C++
6734 $Signature=~s/\Qstd::basic_string<char, std::char_traits<char>, std::allocator<char> >\E/std::string/g;
6735 $Signature=~s/\Qstd::map<std::string, std::string, std::less<std::string >, std::allocator<std::pair<std::string const, std::string > > >\E/std::map<std::string, std::string>/g;
6736 }
6737 if(not $CheckObjectsOnly or $OSgroup=~/linux|bsd|beos/)
6738 { # ELF format marks data as OBJECT
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04006739 if($GlobalDataObject{$LibVersion}{$Symbol}) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006740 $Signature .= " [data]";
6741 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04006742 elsif($Symbol!~/\A(_Z|\?)/) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006743 $Signature .= " (...)";
6744 }
6745 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04006746 if(my $ChargeLevel = get_ChargeLevel($Symbol, $LibVersion))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006747 {
Andrey Ponomarenko16934472012-03-29 15:37:04 +04006748 my $ShortName = substr($Signature, 0, find_center($Signature, "("));
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006749 $Signature=~s/\A\Q$ShortName\E/$ShortName $ChargeLevel/g;
6750 }
6751 if($SymbolVersion) {
6752 $Signature .= $VersionSpec.$SymbolVersion;
6753 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04006754 return ($Cache{"get_SignatureNoInfo"}{$LibVersion}{$Symbol} = $Signature);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006755}
6756
6757sub get_ChargeLevel($$)
6758{
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04006759 my ($Symbol, $LibVersion) = @_;
6760 return "" if($Symbol!~/\A(_Z|\?)/);
6761 if(defined $CompleteSignature{$LibVersion}{$Symbol}
6762 and $CompleteSignature{$LibVersion}{$Symbol}{"Header"})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006763 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04006764 if($CompleteSignature{$LibVersion}{$Symbol}{"Constructor"})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006765 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04006766 if($Symbol=~/C1E/) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006767 return "[in-charge]";
6768 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04006769 elsif($Symbol=~/C2E/) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006770 return "[not-in-charge]";
6771 }
6772 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04006773 elsif($CompleteSignature{$LibVersion}{$Symbol}{"Destructor"})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006774 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04006775 if($Symbol=~/D1E/) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006776 return "[in-charge]";
6777 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04006778 elsif($Symbol=~/D2E/) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006779 return "[not-in-charge]";
6780 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04006781 elsif($Symbol=~/D0E/) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006782 return "[in-charge-deleting]";
6783 }
6784 }
6785 }
6786 else
6787 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04006788 if($Symbol=~/C1E/) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006789 return "[in-charge]";
6790 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04006791 elsif($Symbol=~/C2E/) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006792 return "[not-in-charge]";
6793 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04006794 elsif($Symbol=~/D1E/) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006795 return "[in-charge]";
6796 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04006797 elsif($Symbol=~/D2E/) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006798 return "[not-in-charge]";
6799 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04006800 elsif($Symbol=~/D0E/) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006801 return "[in-charge-deleting]";
6802 }
6803 }
6804 return "";
6805}
6806
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04006807sub get_Signature_M($$)
6808{
6809 my ($Symbol, $LibVersion) = @_;
6810 my $Signature_M = $tr_name{$Symbol};
6811 if(my $RTid = $CompleteSignature{$LibVersion}{$Symbol}{"Return"})
6812 { # add return type name
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04006813 $Signature_M = $TypeInfo{$LibVersion}{$RTid}{"Name"}." ".$Signature_M;
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04006814 }
6815 return $Signature_M;
6816}
6817
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006818sub get_Signature($$)
6819{
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04006820 my ($Symbol, $LibVersion) = @_;
6821 if($Cache{"get_Signature"}{$LibVersion}{$Symbol}) {
6822 return $Cache{"get_Signature"}{$LibVersion}{$Symbol};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006823 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04006824 my ($MnglName, $VersionSpec, $SymbolVersion) = separate_symbol($Symbol);
6825 if(isPrivateData($MnglName) or not $CompleteSignature{$LibVersion}{$Symbol}{"Header"})
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04006826 { # non-public global data
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04006827 return get_SignatureNoInfo($Symbol, $LibVersion);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006828 }
6829 my ($Func_Signature, @Param_Types_FromUnmangledName) = ();
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04006830 my $ShortName = $CompleteSignature{$LibVersion}{$Symbol}{"ShortName"};
6831 if($Symbol=~/\A(_Z|\?)/)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006832 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04006833 if(my $ClassId = $CompleteSignature{$LibVersion}{$Symbol}{"Class"}) {
6834 $Func_Signature = $TypeInfo{$LibVersion}{$ClassId}{"Name"}."::".(($CompleteSignature{$LibVersion}{$Symbol}{"Destructor"})?"~":"").$ShortName;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006835 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04006836 elsif(my $NameSpace = $CompleteSignature{$LibVersion}{$Symbol}{"NameSpace"}) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006837 $Func_Signature = $NameSpace."::".$ShortName;
6838 }
6839 else {
6840 $Func_Signature = $ShortName;
6841 }
Andrey Ponomarenko07aea072012-11-12 16:15:07 +04006842 my ($Short, $Params) = split_Signature($tr_name{$MnglName});
6843 @Param_Types_FromUnmangledName = separate_Params($Params, 0, 1);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006844 }
6845 else {
6846 $Func_Signature = $MnglName;
6847 }
6848 my @ParamArray = ();
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04006849 foreach my $Pos (sort {int($a) <=> int($b)} keys(%{$CompleteSignature{$LibVersion}{$Symbol}{"Param"}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006850 {
6851 next if($Pos eq "");
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04006852 my $ParamTypeId = $CompleteSignature{$LibVersion}{$Symbol}{"Param"}{$Pos}{"type"};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006853 next if(not $ParamTypeId);
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04006854 my $ParamTypeName = $TypeInfo{$LibVersion}{$ParamTypeId}{"Name"};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006855 if(not $ParamTypeName) {
6856 $ParamTypeName = $Param_Types_FromUnmangledName[$Pos];
6857 }
6858 foreach my $Typedef (keys(%ChangedTypedef))
6859 {
6860 my $Base = $Typedef_BaseName{$LibVersion}{$Typedef};
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04006861 $ParamTypeName=~s/\b\Q$Typedef\E\b/$Base/g;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006862 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04006863 if(my $ParamName = $CompleteSignature{$LibVersion}{$Symbol}{"Param"}{$Pos}{"name"}) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006864 push(@ParamArray, create_member_decl($ParamTypeName, $ParamName));
6865 }
6866 else {
6867 push(@ParamArray, $ParamTypeName);
6868 }
6869 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04006870 if($CompleteSignature{$LibVersion}{$Symbol}{"Data"}
6871 or $GlobalDataObject{$LibVersion}{$Symbol}) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006872 $Func_Signature .= " [data]";
6873 }
6874 else
6875 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04006876 if(my $ChargeLevel = get_ChargeLevel($Symbol, $LibVersion))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006877 { # add [in-charge]
6878 $Func_Signature .= " ".$ChargeLevel;
6879 }
6880 $Func_Signature .= " (".join(", ", @ParamArray).")";
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04006881 if($CompleteSignature{$LibVersion}{$Symbol}{"Const"}
6882 or $Symbol=~/\A_ZN(V|)K/) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006883 $Func_Signature .= " const";
6884 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04006885 if($CompleteSignature{$LibVersion}{$Symbol}{"Volatile"}
6886 or $Symbol=~/\A_ZN(K|)V/) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006887 $Func_Signature .= " volatile";
6888 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04006889 if($CompleteSignature{$LibVersion}{$Symbol}{"Static"}
6890 and $Symbol=~/\A(_Z|\?)/)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006891 {# for static methods
6892 $Func_Signature .= " [static]";
6893 }
6894 }
6895 if(defined $ShowRetVal
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04006896 and my $ReturnTId = $CompleteSignature{$LibVersion}{$Symbol}{"Return"}) {
6897 $Func_Signature .= ":".$TypeInfo{$LibVersion}{$ReturnTId}{"Name"};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006898 }
6899 if($SymbolVersion) {
6900 $Func_Signature .= $VersionSpec.$SymbolVersion;
6901 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04006902 return ($Cache{"get_Signature"}{$LibVersion}{$Symbol} = $Func_Signature);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006903}
6904
6905sub create_member_decl($$)
6906{
6907 my ($TName, $Member) = @_;
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04006908 if($TName=~/\([\*]+\)/)
6909 {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006910 $TName=~s/\(([\*]+)\)/\($1$Member\)/;
6911 return $TName;
6912 }
6913 else
6914 {
6915 my @ArraySizes = ();
6916 while($TName=~s/(\[[^\[\]]*\])\Z//) {
6917 push(@ArraySizes, $1);
6918 }
6919 return $TName." ".$Member.join("", @ArraySizes);
6920 }
6921}
6922
6923sub getFuncType($)
6924{
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04006925 if($_[0] and my $Info = $LibInfo{$Version}{"info"}{$_[0]})
6926 {
6927 if($Info=~/type[ ]*:[ ]*@(\d+) /)
6928 {
6929 if(my $Type = $LibInfo{$Version}{"info_type"}{$1})
6930 {
6931 if($Type eq "method_type") {
6932 return "Method";
6933 }
6934 elsif($Type eq "function_type") {
6935 return "Function";
6936 }
6937 else {
6938 return "Other";
6939 }
6940 }
6941 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006942 }
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +04006943 return "";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006944}
6945
6946sub getFuncTypeId($)
6947{
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04006948 if($_[0] and my $Info = $LibInfo{$Version}{"info"}{$_[0]})
6949 {
6950 if($Info=~/type[ ]*:[ ]*@(\d+)( |\Z)/) {
6951 return $1;
6952 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006953 }
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04006954 return 0;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006955}
6956
6957sub isNotAnon($) {
6958 return (not isAnon($_[0]));
6959}
6960
6961sub isAnon($)
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04006962{ # "._N" or "$_N" in older GCC versions
6963 return ($_[0] and $_[0]=~/(\.|\$)\_\d+|anon\-/);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006964}
6965
Andrey Ponomarenko9927e332012-10-19 10:50:48 +04006966sub formatName($$)
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04006967{ # type name correction
Andrey Ponomarenko9927e332012-10-19 10:50:48 +04006968 if(defined $Cache{"formatName"}{$_[1]}{$_[0]}) {
6969 return $Cache{"formatName"}{$_[1]}{$_[0]};
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04006970 }
6971
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +04006972 my $N = $_[0];
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04006973
Andrey Ponomarenko9927e332012-10-19 10:50:48 +04006974 if($_[1] ne "S")
6975 {
6976 $N=~s/\A[ ]+//g;
6977 $N=~s/[ ]+\Z//g;
6978 $N=~s/[ ]{2,}/ /g;
6979 }
6980
6981 $N=~s/[ ]*(\W)[ ]*/$1/g; # std::basic_string<char> const
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04006982
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +04006983 $N=~s/\bvolatile const\b/const volatile/g;
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04006984
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +04006985 $N=~s/\b(long long|short|long) unsigned\b/unsigned $1/g;
6986 $N=~s/\b(short|long) int\b/$1/g;
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04006987
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +04006988 $N=~s/([\)\]])(const|volatile)\b/$1 $2/g;
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04006989
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +04006990 while($N=~s/>>/> >/g) {};
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04006991
Andrey Ponomarenko9927e332012-10-19 10:50:48 +04006992 if($_[1] eq "S")
6993 {
6994 if(index($N, "operator")!=-1) {
6995 $N=~s/\b(operator[ ]*)> >/$1>>/;
6996 }
6997 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04006998
Andrey Ponomarenko9927e332012-10-19 10:50:48 +04006999 return ($Cache{"formatName"}{$_[1]}{$_[0]} = $N);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007000}
7001
7002sub get_HeaderDeps($$)
7003{
7004 my ($AbsPath, $LibVersion) = @_;
7005 return () if(not $AbsPath or not $LibVersion);
7006 if(defined $Cache{"get_HeaderDeps"}{$LibVersion}{$AbsPath}) {
7007 return @{$Cache{"get_HeaderDeps"}{$LibVersion}{$AbsPath}};
7008 }
7009 my %IncDir = ();
7010 detect_recursive_includes($AbsPath, $LibVersion);
7011 foreach my $HeaderPath (keys(%{$RecursiveIncludes{$LibVersion}{$AbsPath}}))
7012 {
7013 next if(not $HeaderPath);
7014 next if($MAIN_CPP_DIR and $HeaderPath=~/\A\Q$MAIN_CPP_DIR\E([\/\\]|\Z)/);
7015 my $Dir = get_dirname($HeaderPath);
7016 foreach my $Prefix (keys(%{$Header_Include_Prefix{$LibVersion}{$AbsPath}{$HeaderPath}}))
7017 {
7018 my $Dep = $Dir;
7019 if($Prefix)
7020 {
7021 if($OSgroup eq "windows")
7022 { # case insensitive seach on windows
7023 if(not $Dep=~s/[\/\\]+\Q$Prefix\E\Z//ig) {
7024 next;
7025 }
7026 }
7027 elsif($OSgroup eq "macos")
7028 { # seach in frameworks
7029 if(not $Dep=~s/[\/\\]+\Q$Prefix\E\Z//g)
7030 {
7031 if($HeaderPath=~/(.+\.framework)\/Headers\/([^\/]+)/)
7032 {# frameworks
7033 my ($HFramework, $HName) = ($1, $2);
7034 $Dep = $HFramework;
7035 }
7036 else
7037 {# mismatch
7038 next;
7039 }
7040 }
7041 }
7042 elsif(not $Dep=~s/[\/\\]+\Q$Prefix\E\Z//g)
7043 { # Linux, FreeBSD
7044 next;
7045 }
7046 }
7047 if(not $Dep)
7048 { # nothing to include
7049 next;
7050 }
7051 if(is_default_include_dir($Dep))
7052 { # included by the compiler
7053 next;
7054 }
7055 if(get_depth($Dep)==1)
7056 { # too short
7057 next;
7058 }
7059 if(isLibcDir($Dep))
7060 { # do NOT include /usr/include/{sys,bits}
7061 next;
7062 }
7063 $IncDir{$Dep}=1;
7064 }
7065 }
7066 $Cache{"get_HeaderDeps"}{$LibVersion}{$AbsPath} = sortIncPaths([keys(%IncDir)], $LibVersion);
7067 return @{$Cache{"get_HeaderDeps"}{$LibVersion}{$AbsPath}};
7068}
7069
7070sub sortIncPaths($$)
7071{
7072 my ($ArrRef, $LibVersion) = @_;
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04007073 if(not $ArrRef or $#{$ArrRef}<0) {
7074 return $ArrRef;
7075 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007076 @{$ArrRef} = sort {$b cmp $a} @{$ArrRef};
7077 @{$ArrRef} = sort {get_depth($a)<=>get_depth($b)} @{$ArrRef};
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04007078 @{$ArrRef} = sort {sortDeps($b, $a, $LibVersion)} @{$ArrRef};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007079 return $ArrRef;
7080}
7081
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04007082sub sortDeps($$$)
7083{
7084 if($Header_Dependency{$_[2]}{$_[0]}
7085 and not $Header_Dependency{$_[2]}{$_[1]}) {
7086 return 1;
7087 }
7088 elsif(not $Header_Dependency{$_[2]}{$_[0]}
7089 and $Header_Dependency{$_[2]}{$_[1]}) {
7090 return -1;
7091 }
7092 return 0;
7093}
7094
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007095sub joinPath($$) {
7096 return join($SLASH, @_);
7097}
7098
7099sub get_namespace_additions($)
7100{
7101 my $NameSpaces = $_[0];
7102 my ($Additions, $AddNameSpaceId) = ("", 1);
7103 foreach my $NS (sort {$a=~/_/ <=> $b=~/_/} sort {lc($a) cmp lc($b)} keys(%{$NameSpaces}))
7104 {
7105 next if($SkipNameSpaces{$Version}{$NS});
7106 next if(not $NS or $NameSpaces->{$NS}==-1);
7107 next if($NS=~/(\A|::)iterator(::|\Z)/i);
7108 next if($NS=~/\A__/i);
7109 next if(($NS=~/\Astd::/ or $NS=~/\A(std|tr1|rel_ops|fcntl)\Z/) and not $STDCXX_TESTING);
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04007110 $NestedNameSpaces{$Version}{$NS} = 1; # for future use in reports
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007111 my ($TypeDecl_Prefix, $TypeDecl_Suffix) = ();
7112 my @NS_Parts = split(/::/, $NS);
7113 next if($#NS_Parts==-1);
7114 next if($NS_Parts[0]=~/\A(random|or)\Z/);
7115 foreach my $NS_Part (@NS_Parts)
7116 {
7117 $TypeDecl_Prefix .= "namespace $NS_Part\{";
7118 $TypeDecl_Suffix .= "}";
7119 }
7120 my $TypeDecl = $TypeDecl_Prefix."typedef int tmp_add_type_$AddNameSpaceId;".$TypeDecl_Suffix;
7121 my $FuncDecl = "$NS\:\:tmp_add_type_$AddNameSpaceId tmp_add_func_$AddNameSpaceId(){return 0;};";
7122 $Additions.=" $TypeDecl\n $FuncDecl\n";
7123 $AddNameSpaceId+=1;
7124 }
7125 return $Additions;
7126}
7127
7128sub path_format($$)
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04007129{ # forward slash to pass into MinGW GCC
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007130 my ($Path, $Fmt) = @_;
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04007131 if($Fmt eq "windows")
7132 {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007133 $Path=~s/\//\\/g;
7134 $Path=lc($Path);
7135 }
7136 else {
7137 $Path=~s/\\/\//g;
7138 }
7139 return $Path;
7140}
7141
7142sub inc_opt($$)
7143{
7144 my ($Path, $Style) = @_;
7145 if($Style eq "GCC")
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04007146 { # GCC options
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007147 if($OSgroup eq "windows")
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04007148 { # to MinGW GCC
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007149 return "-I\"".path_format($Path, "unix")."\"";
7150 }
7151 elsif($OSgroup eq "macos"
7152 and $Path=~/\.framework\Z/)
7153 {# to Apple's GCC
7154 return "-F".esc(get_dirname($Path));
7155 }
7156 else {
7157 return "-I".esc($Path);
7158 }
7159 }
7160 elsif($Style eq "CL") {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04007161 return "/I \"".$Path."\"";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007162 }
7163 return "";
7164}
7165
7166sub platformSpecs($)
7167{
7168 my $LibVersion = $_[0];
7169 my $Arch = getArch($LibVersion);
7170 if($OStarget eq "symbian")
7171 { # options for GCCE compiler
7172 my %Symbian_Opts = map {$_=>1} (
7173 "-D__GCCE__",
7174 "-DUNICODE",
7175 "-fexceptions",
7176 "-D__SYMBIAN32__",
7177 "-D__MARM_INTERWORK__",
7178 "-D_UNICODE",
7179 "-D__S60_50__",
7180 "-D__S60_3X__",
7181 "-D__SERIES60_3X__",
7182 "-D__EPOC32__",
7183 "-D__MARM__",
7184 "-D__EABI__",
7185 "-D__MARM_ARMV5__",
7186 "-D__SUPPORT_CPP_EXCEPTIONS__",
7187 "-march=armv5t",
7188 "-mapcs",
7189 "-mthumb-interwork",
7190 "-DEKA2",
7191 "-DSYMBIAN_ENABLE_SPLIT_HEADERS"
7192 );
7193 return join(" ", keys(%Symbian_Opts));
7194 }
7195 elsif($OSgroup eq "windows"
7196 and get_dumpmachine($GCC_PATH)=~/mingw/i)
7197 { # add options to MinGW compiler
7198 # to simulate the MSVC compiler
7199 my %MinGW_Opts = map {$_=>1} (
7200 "-D_WIN32",
7201 "-D_STDCALL_SUPPORTED",
7202 "-D__int64=\"long long\"",
7203 "-D__int32=int",
7204 "-D__int16=short",
7205 "-D__int8=char",
7206 "-D__possibly_notnullterminated=\" \"",
7207 "-D__nullterminated=\" \"",
7208 "-D__nullnullterminated=\" \"",
7209 "-D__w64=\" \"",
7210 "-D__ptr32=\" \"",
7211 "-D__ptr64=\" \"",
7212 "-D__forceinline=inline",
7213 "-D__inline=inline",
7214 "-D__uuidof(x)=IID()",
7215 "-D__try=",
7216 "-D__except(x)=",
7217 "-D__declspec(x)=__attribute__((x))",
7218 "-D__pragma(x)=",
7219 "-D_inline=inline",
7220 "-D__forceinline=__inline",
7221 "-D__stdcall=__attribute__((__stdcall__))",
7222 "-D__cdecl=__attribute__((__cdecl__))",
7223 "-D__fastcall=__attribute__((__fastcall__))",
7224 "-D__thiscall=__attribute__((__thiscall__))",
7225 "-D_stdcall=__attribute__((__stdcall__))",
7226 "-D_cdecl=__attribute__((__cdecl__))",
7227 "-D_fastcall=__attribute__((__fastcall__))",
7228 "-D_thiscall=__attribute__((__thiscall__))",
7229 "-DSHSTDAPI_(x)=x",
7230 "-D_MSC_EXTENSIONS",
7231 "-DSECURITY_WIN32",
7232 "-D_MSC_VER=1500",
7233 "-D_USE_DECLSPECS_FOR_SAL",
7234 "-D__noop=\" \"",
7235 "-DDECLSPEC_DEPRECATED=\" \"",
7236 "-D__builtin_alignof(x)=__alignof__(x)",
7237 "-DSORTPP_PASS");
7238 if($Arch eq "x86") {
7239 $MinGW_Opts{"-D_M_IX86=300"}=1;
7240 }
7241 elsif($Arch eq "x86_64") {
7242 $MinGW_Opts{"-D_M_AMD64=300"}=1;
7243 }
7244 elsif($Arch eq "ia64") {
7245 $MinGW_Opts{"-D_M_IA64=300"}=1;
7246 }
7247 return join(" ", keys(%MinGW_Opts));
7248 }
7249 return "";
7250}
7251
7252my %C_Structure = map {$_=>1} (
7253# FIXME: Can't separate union and struct data types before dumping,
7254# so it sometimes cause compilation errors for unknown reason
7255# when trying to declare TYPE* tmp_add_class_N
7256# This is a list of such structures + list of other C structures
7257 "sigval",
7258 "sigevent",
7259 "sigaction",
7260 "sigvec",
7261 "sigstack",
7262 "timeval",
7263 "timezone",
7264 "rusage",
7265 "rlimit",
7266 "wait",
7267 "flock",
7268 "stat",
7269 "_stat",
7270 "stat32",
7271 "_stat32",
7272 "stat64",
7273 "_stat64",
7274 "_stati64",
7275 "if_nameindex",
7276 "usb_device",
7277 "sigaltstack",
7278 "sysinfo",
7279 "timeLocale",
7280 "tcp_debug",
7281 "rpc_createerr",
7282# Other C structures appearing in every dump
7283 "timespec",
7284 "random_data",
7285 "drand48_data",
7286 "_IO_marker",
7287 "_IO_FILE",
7288 "lconv",
7289 "sched_param",
7290 "tm",
7291 "itimerspec",
7292 "_pthread_cleanup_buffer",
7293 "fd_set",
Andrey Ponomarenko01117f12012-06-26 12:23:02 +04007294 "siginfo",
7295 "mallinfo"
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007296);
7297
7298sub getCompileCmd($$$)
7299{
7300 my ($Path, $Opt, $Inc) = @_;
7301 my $GccCall = $GCC_PATH;
7302 if($Opt) {
7303 $GccCall .= " ".$Opt;
7304 }
7305 $GccCall .= " -x ";
7306 if($OSgroup eq "macos") {
7307 $GccCall .= "objective-";
7308 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04007309 if(check_gcc($GCC_PATH, "4"))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007310 { # compile as "C++" header
7311 # to obtain complete dump using GCC 4.0
7312 $GccCall .= "c++-header";
7313 }
7314 else
7315 { # compile as "C++" source
7316 # GCC 3.3 cannot compile headers
7317 $GccCall .= "c++";
7318 }
7319 if(my $Opts = platformSpecs($Version))
7320 {# platform-specific options
7321 $GccCall .= " ".$Opts;
7322 }
7323 # allow extra qualifications
7324 # and other nonconformant code
Andrey Ponomarenko01117f12012-06-26 12:23:02 +04007325 $GccCall .= " -fpermissive";
7326 $GccCall .= " -w";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007327 if($NoStdInc)
7328 {
7329 $GccCall .= " -nostdinc";
7330 $GccCall .= " -nostdinc++";
7331 }
7332 if($CompilerOptions{$Version})
7333 { # user-defined options
7334 $GccCall .= " ".$CompilerOptions{$Version};
7335 }
Andrey Ponomarenkoa01311b2012-06-08 17:20:02 +04007336 $GccCall .= " \"$Path\"";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007337 if($Inc)
7338 { # include paths
7339 $GccCall .= " ".$Inc;
7340 }
7341 return $GccCall;
7342}
7343
Andrey Ponomarenko01117f12012-06-26 12:23:02 +04007344sub detectPreamble($$)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007345{
Andrey Ponomarenko01117f12012-06-26 12:23:02 +04007346 my ($Content, $LibVersion) = @_;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007347 my %HeaderElems = (
7348 # Types
7349 "stdio.h" => ["FILE", "va_list"],
Andrey Ponomarenko85043792012-05-14 16:48:07 +04007350 "stddef.h" => ["NULL", "ptrdiff_t"],
Andrey Ponomarenko9927e332012-10-19 10:50:48 +04007351 "stdint.h" => ["uint8_t", "uint16_t", "uint32_t", "uint64_t",
7352 "int8_t", "int16_t", "int32_t", "int64_t"],
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007353 "time.h" => ["time_t"],
7354 "sys/types.h" => ["ssize_t", "u_int32_t", "u_short", "u_char",
Andrey Ponomarenko9927e332012-10-19 10:50:48 +04007355 "u_int", "off_t", "u_quad_t", "u_long", "mode_t"],
7356 "unistd.h" => ["gid_t", "uid_t", "socklen_t"],
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007357 "stdbool.h" => ["_Bool"],
7358 "rpc/xdr.h" => ["bool_t"],
7359 "in_systm.h" => ["n_long", "n_short"],
7360 # Fields
Andrey Ponomarenkobede8372012-03-29 17:43:21 +04007361 "arpa/inet.h" => ["fw_src", "ip_src"],
7362 # Functions
Andrey Ponomarenko9927e332012-10-19 10:50:48 +04007363 "stdlib.h" => ["free", "malloc", "size_t"],
Andrey Ponomarenko85043792012-05-14 16:48:07 +04007364 "string.h" => ["memmove", "strcmp"]
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007365 );
7366 my %AutoPreamble = ();
Andrey Ponomarenko85043792012-05-14 16:48:07 +04007367 foreach (keys(%HeaderElems))
7368 {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007369 foreach my $Elem (@{$HeaderElems{$_}}) {
Andrey Ponomarenko9927e332012-10-19 10:50:48 +04007370 $AutoPreamble{$Elem} = $_;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007371 }
7372 }
Andrey Ponomarenko01117f12012-06-26 12:23:02 +04007373 my %Types = ();
7374 while($Content=~s/error\:\s*(field\s*|)\W+(.+?)\W+//)
7375 { # error: 'FILE' has not been declared
Andrey Ponomarenko9927e332012-10-19 10:50:48 +04007376 $Types{$2} = 1;
Andrey Ponomarenko01117f12012-06-26 12:23:02 +04007377 }
7378 if(keys(%Types))
7379 {
7380 my %AddHeaders = ();
7381 foreach my $Type (keys(%Types))
7382 {
7383 if(my $Header = $AutoPreamble{$Type})
7384 {
Andrey Ponomarenko9927e332012-10-19 10:50:48 +04007385 if(my $Path = identifyHeader($Header, $LibVersion))
7386 {
7387 if(skipHeader($Path, $LibVersion)) {
7388 next;
7389 }
7390 $Path = path_format($Path, $OSgroup);
7391 $AddHeaders{$Path}{"Type"} = $Type;
7392 $AddHeaders{$Path}{"Header"} = $Header;
Andrey Ponomarenko01117f12012-06-26 12:23:02 +04007393 }
7394 }
7395 }
7396 if(keys(%AddHeaders)) {
Andrey Ponomarenko9927e332012-10-19 10:50:48 +04007397 return \%AddHeaders;
Andrey Ponomarenko01117f12012-06-26 12:23:02 +04007398 }
7399 }
Andrey Ponomarenko9927e332012-10-19 10:50:48 +04007400 return undef;
Andrey Ponomarenko01117f12012-06-26 12:23:02 +04007401}
7402
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +04007403sub checkCTags($)
7404{
7405 my $Path = $_[0];
7406 if(not $Path) {
7407 return;
7408 }
7409 my $CTags = get_CmdPath("ctags");
7410 if(not $CTags) {
7411 return;
7412 }
Andrey Ponomarenkobdc85a92012-11-12 17:28:12 +04007413
7414 if($OSgroup eq "macos")
7415 {
7416 my $Info = `$CTags --version 2>\"$TMP_DIR/null\"`;
7417 if($Info!~/exuberant/i)
7418 {
7419 printMsg("WARNING", "incompatible version of \'ctags\' program");
7420 return;
7421 }
7422 }
7423
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +04007424 my $Out = $TMP_DIR."/ctags.txt";
Andrey Ponomarenkobdc85a92012-11-12 17:28:12 +04007425 system("$CTags --c-kinds=pxn -f \"$Out\" \"$Path\" 2>\"$TMP_DIR/null\"");
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +04007426 if($Debug) {
Andrey Ponomarenko9927e332012-10-19 10:50:48 +04007427 copy($Out, $DEBUG_PATH{$Version}."/ctags.txt");
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +04007428 }
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +04007429 open(CTAGS, "<", $Out);
7430 while(my $Line = <CTAGS>)
7431 {
7432 chomp($Line);
7433 my ($Name, $Header, $Def, $Type, $Scpe) = split(/\t/, $Line);
Andrey Ponomarenko9927e332012-10-19 10:50:48 +04007434 if(defined $Intrinsic_Keywords{$Name})
7435 { # noise
7436 next;
7437 }
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +04007438 if($Type eq "n")
7439 {
Andrey Ponomarenko9927e332012-10-19 10:50:48 +04007440 if(index($Scpe, "class:")==0) {
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +04007441 next;
7442 }
Andrey Ponomarenko9927e332012-10-19 10:50:48 +04007443 if(index($Scpe, "struct:")==0) {
7444 next;
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +04007445 }
Andrey Ponomarenko9927e332012-10-19 10:50:48 +04007446 if(index($Scpe, "namespace:")==0)
7447 {
7448 if($Scpe=~s/\Anamespace://) {
7449 $Name = $Scpe."::".$Name;
7450 }
7451 }
7452 $TUnit_NameSpaces{$Version}{$Name} = 1;
7453 }
7454 elsif($Type eq "p")
7455 {
7456 if(not $Scpe or index($Scpe, "namespace:")==0) {
7457 $TUnit_Funcs{$Version}{$Name} = 1;
7458 }
7459 }
7460 elsif($Type eq "x")
7461 {
7462 if(not $Scpe or index($Scpe, "namespace:")==0) {
7463 $TUnit_Vars{$Version}{$Name} = 1;
7464 }
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +04007465 }
7466 }
7467 close(CTAGS);
7468}
7469
Andrey Ponomarenko01117f12012-06-26 12:23:02 +04007470sub getDump()
7471{
7472 if(not $GCC_PATH) {
7473 exitStatus("Error", "internal error - GCC path is not set");
7474 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04007475 my $TmpHeaderPath = $TMP_DIR."/dump".$Version.".h";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007476 my $MHeaderPath = $TmpHeaderPath;
Andrey Ponomarenko85043792012-05-14 16:48:07 +04007477 open(TMP_HEADER, ">", $TmpHeaderPath) || die ("can't open file \'$TmpHeaderPath\': $!\n");
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007478 if(my $AddDefines = $Descriptor{$Version}{"Defines"})
7479 {
7480 $AddDefines=~s/\n\s+/\n /g;
Andrey Ponomarenko85043792012-05-14 16:48:07 +04007481 print TMP_HEADER "\n // add defines\n ".$AddDefines."\n";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007482 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +04007483 print TMP_HEADER "\n // add includes\n";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007484 my @PreambleHeaders = keys(%{$Include_Preamble{$Version}});
7485 @PreambleHeaders = sort {int($Include_Preamble{$Version}{$a}{"Position"})<=>int($Include_Preamble{$Version}{$b}{"Position"})} @PreambleHeaders;
7486 foreach my $Header_Path (@PreambleHeaders) {
Andrey Ponomarenko85043792012-05-14 16:48:07 +04007487 print TMP_HEADER " #include \"".path_format($Header_Path, "unix")."\"\n";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007488 }
7489 my @Headers = keys(%{$Registered_Headers{$Version}});
7490 @Headers = sort {int($Registered_Headers{$Version}{$a}{"Pos"})<=>int($Registered_Headers{$Version}{$b}{"Pos"})} @Headers;
7491 foreach my $Header_Path (@Headers)
7492 {
7493 next if($Include_Preamble{$Version}{$Header_Path});
Andrey Ponomarenko85043792012-05-14 16:48:07 +04007494 print TMP_HEADER " #include \"".path_format($Header_Path, "unix")."\"\n";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007495 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +04007496 close(TMP_HEADER);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007497 my $IncludeString = getIncString(getIncPaths(@PreambleHeaders, @Headers), "GCC");
Andrey Ponomarenko9927e332012-10-19 10:50:48 +04007498
Andrey Ponomarenko07aea072012-11-12 16:15:07 +04007499 if($ExtraInfo)
7500 { # extra information for other tools
7501 writeFile($ExtraInfo."/include-string", $IncludeString);
7502 }
7503
Andrey Ponomarenko9927e332012-10-19 10:50:48 +04007504 if(not keys(%{$TargetHeaders{$Version}}))
7505 { # Target headers
7506 addTargetHeaders($Version);
7507 }
7508
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007509 if($Debug)
7510 { # debug mode
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04007511 writeFile($DEBUG_PATH{$Version}."/headers/direct-includes.txt", Dumper($Header_Includes{$Version}));
7512 writeFile($DEBUG_PATH{$Version}."/headers/recursive-includes.txt", Dumper($RecursiveIncludes{$Version}));
7513 writeFile($DEBUG_PATH{$Version}."/headers/include-paths.txt", Dumper($Cache{"get_HeaderDeps"}{$Version}));
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04007514 writeFile($DEBUG_PATH{$Version}."/headers/default-paths.txt", Dumper(\%DefaultIncPaths));
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007515 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +04007516
Andrey Ponomarenko85043792012-05-14 16:48:07 +04007517 # clean memory
7518 %RecursiveIncludes = ();
7519 %Header_Include_Prefix = ();
7520 %Header_Includes = ();
7521
7522 # clean cache
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04007523 delete($Cache{"identifyHeader"});
Andrey Ponomarenko85043792012-05-14 16:48:07 +04007524 delete($Cache{"detect_header_includes"});
7525 delete($Cache{"selectSystemHeader"});
7526
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007527 # preprocessing stage
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +04007528 my $Pre = callPreprocessor($TmpHeaderPath, $IncludeString, $Version);
7529 checkPreprocessedUnit($Pre);
Andrey Ponomarenko85043792012-05-14 16:48:07 +04007530
7531 # clean memory
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04007532 delete($Include_Neighbors{$Version});
Andrey Ponomarenko85043792012-05-14 16:48:07 +04007533
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +04007534 if($COMMON_LANGUAGE{$Version} eq "C++") {
7535 checkCTags($Pre);
7536 }
7537
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007538 my $MContent = "";
7539 my $PreprocessCmd = getCompileCmd($TmpHeaderPath, "-E", $IncludeString);
7540 if($OStarget eq "windows"
7541 and get_dumpmachine($GCC_PATH)=~/mingw/i
7542 and $MinGWMode{$Version}!=-1)
7543 { # modify headers to compile by MinGW
7544 if(not $MContent)
7545 { # preprocessing
Andrey Ponomarenkoa01311b2012-06-08 17:20:02 +04007546 $MContent = `$PreprocessCmd 2>\"$TMP_DIR/null\"`;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007547 }
7548 if($MContent=~s/__asm\s*(\{[^{}]*?\}|[^{};]*)//g)
7549 { # __asm { ... }
7550 $MinGWMode{$Version}=1;
7551 }
7552 if($MContent=~s/\s+(\/ \/.*?)\n/\n/g)
7553 { # comments after preprocessing
7554 $MinGWMode{$Version}=1;
7555 }
7556 if($MContent=~s/(\W)(0x[a-f]+|\d+)(i|ui)(8|16|32|64)(\W)/$1$2$5/g)
7557 { # 0xffui8
7558 $MinGWMode{$Version}=1;
7559 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +04007560 if($MinGWMode{$Version})
7561 {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007562 printMsg("INFO", "Using MinGW compatibility mode");
Andrey Ponomarenkob8d203d2012-05-25 18:11:07 +04007563 $MHeaderPath = $TMP_DIR."/dump$Version.i";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007564 }
7565 }
7566 if(($COMMON_LANGUAGE{$Version} eq "C" or $CheckHeadersOnly)
Andrey Ponomarenko07aea072012-11-12 16:15:07 +04007567 and $CppMode{$Version}!=-1 and not $CppCompat)
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04007568 { # rename C++ keywords in C code
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007569 if(not $MContent)
7570 { # preprocessing
Andrey Ponomarenkoa01311b2012-06-08 17:20:02 +04007571 $MContent = `$PreprocessCmd 2>\"$TMP_DIR/null\"`;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007572 }
7573 my $RegExp_C = join("|", keys(%CppKeywords_C));
7574 my $RegExp_F = join("|", keys(%CppKeywords_F));
7575 my $RegExp_O = join("|", keys(%CppKeywords_O));
Andrey Ponomarenkobdc85a92012-11-12 17:28:12 +04007576
7577 my $Detected = undef;
7578
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007579 while($MContent=~s/(\A|\n[^\#\/\n][^\n]*?|\n)(\*\s*|\s+|\@|\,|\()($RegExp_C|$RegExp_F)(\s*(\,|\)|\;|\-\>|\.|\:\s*\d))/$1$2c99_$3$4/g)
7580 { # MATCH:
7581 # int foo(int new, int class, int (*new)(int));
7582 # unsigned private: 8;
7583 # DO NOT MATCH:
7584 # #pragma GCC visibility push(default)
Andrey Ponomarenko07aea072012-11-12 16:15:07 +04007585 $CppMode{$Version} = 1;
Andrey Ponomarenkobdc85a92012-11-12 17:28:12 +04007586 $Detected = "$1$2$3$4" if(not defined $Detected);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007587 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04007588 if($MContent=~s/([^\w\s]|\w\s+)(?<!operator )(delete)(\s*\()/$1c99_$2$3/g)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007589 { # MATCH:
7590 # int delete(...);
7591 # int explicit(...);
7592 # DO NOT MATCH:
7593 # void operator delete(...)
Andrey Ponomarenko07aea072012-11-12 16:15:07 +04007594 $CppMode{$Version} = 1;
Andrey Ponomarenkobdc85a92012-11-12 17:28:12 +04007595 $Detected = "$1$2$3" if(not defined $Detected);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007596 }
7597 if($MContent=~s/(\s+)($RegExp_O)(\s*(\;|\:))/$1c99_$2$3/g)
7598 { # MATCH:
7599 # int bool;
7600 # DO NOT MATCH:
7601 # bool X;
7602 # return *this;
7603 # throw;
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+)(operator)(\s*(\(\s*\)\s*[^\(\s]|\(\s*[^\)\s]))/$1c99_$2$3/g)
7608 { # MATCH:
7609 # int operator(...);
7610 # DO NOT MATCH:
7611 # int operator()(...);
Andrey Ponomarenko07aea072012-11-12 16:15:07 +04007612 $CppMode{$Version} = 1;
Andrey Ponomarenkobdc85a92012-11-12 17:28:12 +04007613 $Detected = "$1$2$3" if(not defined $Detected);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007614 }
7615 if($MContent=~s/([^\w\(\,\s]\s*|\s+)(operator)(\s*(\,\s*[^\(\s]|\)))/$1c99_$2$3/g)
7616 { # MATCH:
7617 # int foo(int operator);
7618 # int foo(int operator, int other);
7619 # DO NOT MATCH:
7620 # int operator,(...);
Andrey Ponomarenko07aea072012-11-12 16:15:07 +04007621 $CppMode{$Version} = 1;
Andrey Ponomarenkobdc85a92012-11-12 17:28:12 +04007622 $Detected = "$1$2$3" if(not defined $Detected);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007623 }
7624 if($MContent=~s/(\*\s*|\w\s+)(bool)(\s*(\,|\)))/$1c99_$2$3/g)
7625 { # MATCH:
7626 # int foo(gboolean *bool);
7627 # DO NOT MATCH:
7628 # void setTabEnabled(int index, bool);
Andrey Ponomarenko07aea072012-11-12 16:15:07 +04007629 $CppMode{$Version} = 1;
Andrey Ponomarenkobdc85a92012-11-12 17:28:12 +04007630 $Detected = "$1$2$3" if(not defined $Detected);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007631 }
Andrey Ponomarenko9927e332012-10-19 10:50:48 +04007632 if($MContent=~s/(\w)(\s*[^\w\(\,\s]\s*|\s+)(this|throw)(\s*[\,\)])/$1$2c99_$3$4/g)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007633 { # MATCH:
7634 # int foo(int* this);
7635 # int bar(int this);
Andrey Ponomarenko9927e332012-10-19 10:50:48 +04007636 # int baz(int throw);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007637 # DO NOT MATCH:
Andrey Ponomarenko9927e332012-10-19 10:50:48 +04007638 # foo(X, this);
Andrey Ponomarenko07aea072012-11-12 16:15:07 +04007639 $CppMode{$Version} = 1;
Andrey Ponomarenkobdc85a92012-11-12 17:28:12 +04007640 $Detected = "$1$2$3$4" if(not defined $Detected);
Andrey Ponomarenko07aea072012-11-12 16:15:07 +04007641 }
7642
7643 if($CppMode{$Version} == 1)
7644 {
Andrey Ponomarenkobdc85a92012-11-12 17:28:12 +04007645 if($Debug)
7646 {
7647 $Detected=~s/\A\s+//g;
7648 printMsg("INFO", "Detected code: \"$Detected\"");
Andrey Ponomarenko07aea072012-11-12 16:15:07 +04007649 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007650 }
Andrey Ponomarenko9927e332012-10-19 10:50:48 +04007651
7652 # remove typedef enum NAME NAME;
7653 my @FwdTypedefs = $MContent=~/typedef\s+enum\s+(\w+)\s+(\w+);/g;
7654 my $N = 0;
7655 while($N<=$#FwdTypedefs-1)
7656 {
7657 my $S = $FwdTypedefs[$N];
7658 if($S eq $FwdTypedefs[$N+1])
7659 {
7660 $MContent=~s/typedef\s+enum\s+\Q$S\E\s+\Q$S\E;//g;
Andrey Ponomarenko07aea072012-11-12 16:15:07 +04007661 $CppMode{$Version}=1;
Andrey Ponomarenko9927e332012-10-19 10:50:48 +04007662 }
7663 $N+=2;
7664 }
7665
Andrey Ponomarenko07aea072012-11-12 16:15:07 +04007666 if($CppMode{$Version}==1)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007667 { # try to change C++ "keyword" to "c99_keyword"
Andrey Ponomarenko07aea072012-11-12 16:15:07 +04007668 printMsg("INFO", "Using C++ compatibility mode");
Andrey Ponomarenkob8d203d2012-05-25 18:11:07 +04007669 $MHeaderPath = $TMP_DIR."/dump$Version.i";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007670 }
7671 }
Andrey Ponomarenko07aea072012-11-12 16:15:07 +04007672 if($CppMode{$Version}==1
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007673 or $MinGWMode{$Version}==1)
7674 { # compile the corrected preprocessor output
7675 writeFile($MHeaderPath, $MContent);
7676 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +04007677
7678 # clean memory
7679 undef $MContent;
7680
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007681 if($COMMON_LANGUAGE{$Version} eq "C++")
7682 { # add classes and namespaces to the dump
7683 my $CHdump = "-fdump-class-hierarchy -c";
Andrey Ponomarenko07aea072012-11-12 16:15:07 +04007684 if($CppMode{$Version}==1
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007685 or $MinGWMode{$Version}==1) {
7686 $CHdump .= " -fpreprocessed";
7687 }
7688 my $ClassHierarchyCmd = getCompileCmd($MHeaderPath, $CHdump, $IncludeString);
7689 chdir($TMP_DIR);
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04007690 system($ClassHierarchyCmd." >null 2>&1");
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007691 chdir($ORIG_DIR);
7692 if(my $ClassDump = (cmd_find($TMP_DIR,"f","*.class",1))[0])
7693 {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007694 my $Content = readFile($ClassDump);
7695 foreach my $ClassInfo (split(/\n\n/, $Content))
7696 {
7697 if($ClassInfo=~/\AClass\s+(.+)\s*/i)
7698 {
7699 my $CName = $1;
7700 next if($CName=~/\A(__|_objc_|_opaque_)/);
7701 $TUnit_NameSpaces{$Version}{$CName} = -1;
7702 if($CName=~/\A[\w:]+\Z/)
7703 { # classes
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +04007704 $TUnit_Classes{$Version}{$CName} = 1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007705 }
7706 if($CName=~/(\w[\w:]*)::/)
7707 { # namespaces
7708 my $NS = $1;
7709 if(not defined $TUnit_NameSpaces{$Version}{$NS}) {
7710 $TUnit_NameSpaces{$Version}{$NS} = 1;
7711 }
7712 }
7713 }
7714 elsif($ClassInfo=~/\AVtable\s+for\s+(.+)\n((.|\n)+)\Z/i)
7715 { # read v-tables (advanced approach)
7716 my ($CName, $VTable) = ($1, $2);
7717 $ClassVTable_Content{$Version}{$CName} = $VTable;
7718 }
7719 }
Andrey Ponomarenkoa01311b2012-06-08 17:20:02 +04007720 foreach my $NS (keys(%{$AddNameSpaces{$Version}}))
7721 { # add user-defined namespaces
7722 $TUnit_NameSpaces{$Version}{$NS} = 1;
7723 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007724 if($Debug)
7725 { # debug mode
7726 mkpath($DEBUG_PATH{$Version});
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04007727 copy($ClassDump, $DEBUG_PATH{$Version}."/class-hierarchy-dump.txt");
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007728 }
7729 unlink($ClassDump);
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +04007730 }
7731
7732 # add namespaces and classes
7733 if(my $NS_Add = get_namespace_additions($TUnit_NameSpaces{$Version}))
7734 { # GCC on all supported platforms does not include namespaces to the dump by default
7735 appendFile($MHeaderPath, "\n // add namespaces\n".$NS_Add);
7736 }
7737 # some GCC versions don't include class methods to the TU dump by default
7738 my ($AddClass, $ClassNum) = ("", 0);
7739 foreach my $CName (sort keys(%{$TUnit_Classes{$Version}}))
7740 {
7741 next if($C_Structure{$CName});
7742 next if(not $STDCXX_TESTING and $CName=~/\Astd::/);
7743 next if(($CName=~tr![:]!!)>2);
7744 next if($SkipTypes{$Version}{$CName});
Andrey Ponomarenkobdc85a92012-11-12 17:28:12 +04007745 if($CName=~/\A(.+)::[^:]+\Z/
7746 and $TUnit_Classes{$Version}{$1})
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +04007747 { # will be added by name space
7748 next;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007749 }
Andrey Ponomarenko9927e332012-10-19 10:50:48 +04007750 if(defined $TUnit_Funcs{$Version}{$CName})
7751 { # the same name for a function and type
7752 next;
7753 }
7754 if(defined $TUnit_Vars{$Version}{$CName})
7755 { # the same name for a variable and type
7756 next;
7757 }
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +04007758 $AddClass .= " $CName* tmp_add_class_".($ClassNum++).";\n";
7759 }
7760 if($AddClass) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007761 appendFile($MHeaderPath, "\n // add classes\n".$AddClass);
7762 }
7763 }
7764 writeLog($Version, "Temporary header file \'$TmpHeaderPath\' with the following content will be compiled to create GCC translation unit dump:\n".readFile($TmpHeaderPath)."\n");
7765 # create TU dump
7766 my $TUdump = "-fdump-translation-unit -fkeep-inline-functions -c";
Andrey Ponomarenko07aea072012-11-12 16:15:07 +04007767 if($CppMode{$Version}==1
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007768 or $MinGWMode{$Version}==1) {
7769 $TUdump .= " -fpreprocessed";
7770 }
7771 my $SyntaxTreeCmd = getCompileCmd($MHeaderPath, $TUdump, $IncludeString);
7772 writeLog($Version, "The GCC parameters:\n $SyntaxTreeCmd\n\n");
7773 chdir($TMP_DIR);
Andrey Ponomarenkoa01311b2012-06-08 17:20:02 +04007774 system($SyntaxTreeCmd." >\"$TMP_DIR/tu_errors\" 2>&1");
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007775 if($?)
7776 { # failed to compile, but the TU dump still can be created
Andrey Ponomarenko01117f12012-06-26 12:23:02 +04007777 if(my $Errors = readFile($TMP_DIR."/tu_errors"))
7778 { # try to recompile
7779 # FIXME: handle other errors and try to recompile
Andrey Ponomarenko07aea072012-11-12 16:15:07 +04007780 if($CppMode{$Version}==1
Andrey Ponomarenko01117f12012-06-26 12:23:02 +04007781 and $Errors=~/c99_/)
7782 { # disable c99 mode and try again
Andrey Ponomarenko07aea072012-11-12 16:15:07 +04007783 $CppMode{$Version}=-1;
7784 printMsg("INFO", "Disabling C++ compatibility mode");
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007785 resetLogging($Version);
7786 $TMP_DIR = tempdir(CLEANUP=>1);
7787 return getDump();
7788 }
Andrey Ponomarenko01117f12012-06-26 12:23:02 +04007789 elsif($AutoPreambleMode{$Version}!=-1
Andrey Ponomarenko9927e332012-10-19 10:50:48 +04007790 and my $AddHeaders = detectPreamble($Errors, $Version))
Andrey Ponomarenko01117f12012-06-26 12:23:02 +04007791 { # add auto preamble headers and try again
7792 $AutoPreambleMode{$Version}=-1;
Andrey Ponomarenko9927e332012-10-19 10:50:48 +04007793 my @Headers = sort {$b cmp $a} keys(%{$AddHeaders}); # sys/types.h should be the first
Andrey Ponomarenko01117f12012-06-26 12:23:02 +04007794 foreach my $Num (0 .. $#Headers)
7795 {
7796 my $Path = $Headers[$Num];
7797 if(defined $Include_Preamble{$Version}{$Path})
7798 { # already added
7799 next;
7800 }
7801 $Include_Preamble{$Version}{$Path}{"Position"} = keys(%{$Include_Preamble{$Version}});
Andrey Ponomarenko9927e332012-10-19 10:50:48 +04007802 printMsg("INFO", "Add \'".$AddHeaders->{$Path}{"Header"}."\' preamble header for \'".$AddHeaders->{$Path}{"Type"}."\'");
Andrey Ponomarenko01117f12012-06-26 12:23:02 +04007803 }
7804 resetLogging($Version);
7805 $TMP_DIR = tempdir(CLEANUP=>1);
7806 return getDump();
7807 }
7808 elsif($Cpp0xMode{$Version}!=-1
7809 and ($Errors=~/\Q-std=c++0x\E/
7810 or $Errors=~/is not a class or namespace/))
7811 { # c++0x: enum class
7812 $Cpp0xMode{$Version}=-1;
7813 printMsg("INFO", "Enabling c++0x mode");
7814 resetLogging($Version);
7815 $TMP_DIR = tempdir(CLEANUP=>1);
7816 $CompilerOptions{$Version} .= " -std=c++0x";
7817 return getDump();
7818 }
7819 elsif($MinGWMode{$Version}==1)
7820 { # disable MinGW mode and try again
7821 $MinGWMode{$Version}=-1;
7822 resetLogging($Version);
7823 $TMP_DIR = tempdir(CLEANUP=>1);
7824 return getDump();
7825 }
7826 writeLog($Version, $Errors);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007827 }
Andrey Ponomarenko01117f12012-06-26 12:23:02 +04007828 else {
7829 writeLog($Version, "$!: $?\n");
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007830 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007831 printMsg("ERROR", "some errors occurred when compiling headers");
7832 printErrorLog($Version);
7833 $COMPILE_ERRORS = $ERROR_CODE{"Compile_Error"};
7834 writeLog($Version, "\n");# new line
7835 }
7836 chdir($ORIG_DIR);
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +04007837 unlink($TmpHeaderPath);
7838 unlink($MHeaderPath);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007839 return (cmd_find($TMP_DIR,"f","*.tu",1))[0];
7840}
7841
7842sub cmd_file($)
7843{
7844 my $Path = $_[0];
7845 return "" if(not $Path or not -e $Path);
7846 if(my $CmdPath = get_CmdPath("file")) {
7847 return `$CmdPath -b \"$Path\"`;
7848 }
7849 return "";
7850}
7851
7852sub getIncString($$)
7853{
7854 my ($ArrRef, $Style) = @_;
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04007855 return "" if(not $ArrRef or $#{$ArrRef}<0);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007856 my $String = "";
7857 foreach (@{$ArrRef}) {
7858 $String .= " ".inc_opt($_, $Style);
7859 }
7860 return $String;
7861}
7862
7863sub getIncPaths(@)
7864{
7865 my @HeaderPaths = @_;
7866 my @IncPaths = ();
7867 if($INC_PATH_AUTODETECT{$Version})
7868 { # auto-detecting dependencies
7869 my %Includes = ();
7870 foreach my $HPath (@HeaderPaths)
7871 {
7872 foreach my $Dir (get_HeaderDeps($HPath, $Version))
7873 {
7874 if($Skip_Include_Paths{$Version}{$Dir}) {
7875 next;
7876 }
Andrey Ponomarenkoa01311b2012-06-08 17:20:02 +04007877 if($SystemRoot)
7878 {
7879 if($Skip_Include_Paths{$Version}{$SystemRoot.$Dir}) {
7880 next;
7881 }
7882 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007883 $Includes{$Dir}=1;
7884 }
7885 }
7886 foreach my $Dir (keys(%{$Add_Include_Paths{$Version}}))
7887 { # added by user
7888 next if($Includes{$Dir});
7889 push(@IncPaths, $Dir);
7890 }
7891 foreach my $Dir (@{sortIncPaths([keys(%Includes)], $Version)}) {
7892 push(@IncPaths, $Dir);
7893 }
7894 }
7895 else
7896 { # user-defined paths
7897 foreach my $Dir (sort {get_depth($a)<=>get_depth($b)}
7898 sort {$b cmp $a} keys(%{$Include_Paths{$Version}})) {
7899 push(@IncPaths, $Dir);
7900 }
7901 }
7902 return \@IncPaths;
7903}
7904
7905sub callPreprocessor($$$)
7906{
7907 my ($Path, $Inc, $LibVersion) = @_;
7908 return "" if(not $Path or not -f $Path);
7909 my $IncludeString=$Inc;
7910 if(not $Inc) {
7911 $IncludeString = getIncString(getIncPaths($Path), "GCC");
7912 }
7913 my $Cmd = getCompileCmd($Path, "-dD -E", $IncludeString);
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +04007914 my $Out = $TMP_DIR."/preprocessed.h";
Andrey Ponomarenkoa01311b2012-06-08 17:20:02 +04007915 system($Cmd." >\"$Out\" 2>\"$TMP_DIR/null\"");
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04007916 return $Out;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007917}
7918
7919sub cmd_find($$$$)
7920{ # native "find" is much faster than File::Find (~6x)
7921 # also the File::Find doesn't support --maxdepth N option
7922 # so using the cross-platform wrapper for the native one
7923 my ($Path, $Type, $Name, $MaxDepth) = @_;
7924 return () if(not $Path or not -e $Path);
7925 if($OSgroup eq "windows")
7926 {
7927 my $DirCmd = get_CmdPath("dir");
7928 if(not $DirCmd) {
7929 exitStatus("Not_Found", "can't find \"dir\" command");
7930 }
7931 $Path=~s/[\\]+\Z//;
7932 $Path = get_abs_path($Path);
7933 $Path = path_format($Path, $OSgroup);
7934 my $Cmd = $DirCmd." \"$Path\" /B /O";
7935 if($MaxDepth!=1) {
7936 $Cmd .= " /S";
7937 }
7938 if($Type eq "d") {
7939 $Cmd .= " /AD";
7940 }
7941 my @Files = ();
7942 if($Name)
7943 { # FIXME: how to search file names in MS shell?
7944 $Name=~s/\*/.*/g if($Name!~/\]/);
7945 foreach my $File (split(/\n/, `$Cmd`))
7946 {
7947 if($File=~/$Name\Z/i) {
7948 push(@Files, $File);
7949 }
7950 }
7951 }
7952 else {
Andrey Ponomarenkoa01311b2012-06-08 17:20:02 +04007953 @Files = split(/\n/, `$Cmd 2>\"$TMP_DIR/null\"`);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007954 }
7955 my @AbsPaths = ();
7956 foreach my $File (@Files)
7957 {
7958 if(not is_abs($File)) {
7959 $File = joinPath($Path, $File);
7960 }
7961 if($Type eq "f" and not -f $File)
7962 { # skip dirs
7963 next;
7964 }
7965 push(@AbsPaths, path_format($File, $OSgroup));
7966 }
7967 if($Type eq "d") {
7968 push(@AbsPaths, $Path);
7969 }
7970 return @AbsPaths;
7971 }
7972 else
7973 {
7974 my $FindCmd = get_CmdPath("find");
7975 if(not $FindCmd) {
7976 exitStatus("Not_Found", "can't find a \"find\" command");
7977 }
7978 $Path = get_abs_path($Path);
7979 if(-d $Path and -l $Path
7980 and $Path!~/\/\Z/)
7981 { # for directories that are symlinks
7982 $Path.="/";
7983 }
7984 my $Cmd = $FindCmd." \"$Path\"";
7985 if($MaxDepth) {
7986 $Cmd .= " -maxdepth $MaxDepth";
7987 }
7988 if($Type) {
7989 $Cmd .= " -type $Type";
7990 }
7991 if($Name)
7992 { # file name
7993 if($Name=~/\]/) {
7994 $Cmd .= " -regex \"$Name\"";
7995 }
7996 else {
7997 $Cmd .= " -name \"$Name\"";
7998 }
7999 }
Andrey Ponomarenko9927e332012-10-19 10:50:48 +04008000 my $Res = `$Cmd 2>\"$TMP_DIR/null\"`;
8001 if($?) {
8002 printMsg("ERROR", "problem with \'find\' utility ($?): $!");
8003 }
8004 return split(/\n/, $Res);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008005 }
8006}
8007
8008sub unpackDump($)
8009{
8010 my $Path = $_[0];
8011 return "" if(not $Path or not -e $Path);
8012 $Path = get_abs_path($Path);
8013 $Path = path_format($Path, $OSgroup);
8014 my ($Dir, $FileName) = separate_path($Path);
8015 my $UnpackDir = $TMP_DIR."/unpack";
8016 rmtree($UnpackDir);
8017 mkpath($UnpackDir);
8018 if($FileName=~s/\Q.zip\E\Z//g)
8019 { # *.zip
8020 my $UnzipCmd = get_CmdPath("unzip");
8021 if(not $UnzipCmd) {
8022 exitStatus("Not_Found", "can't find \"unzip\" command");
8023 }
8024 chdir($UnpackDir);
Andrey Ponomarenkoa01311b2012-06-08 17:20:02 +04008025 system("$UnzipCmd \"$Path\" >contents.txt");
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008026 if($?) {
8027 exitStatus("Error", "can't extract \'$Path\'");
8028 }
8029 chdir($ORIG_DIR);
8030 my @Contents = ();
8031 foreach (split("\n", readFile("$UnpackDir/contents.txt")))
8032 {
8033 if(/inflating:\s*([^\s]+)/) {
8034 push(@Contents, $1);
8035 }
8036 }
8037 if(not @Contents) {
8038 exitStatus("Error", "can't extract \'$Path\'");
8039 }
8040 return joinPath($UnpackDir, $Contents[0]);
8041 }
8042 elsif($FileName=~s/\Q.tar.gz\E\Z//g)
8043 { # *.tar.gz
8044 if($OSgroup eq "windows")
8045 { # -xvzf option is not implemented in tar.exe (2003)
8046 # use "gzip.exe -k -d -f" + "tar.exe -xvf" instead
8047 my $TarCmd = get_CmdPath("tar");
8048 if(not $TarCmd) {
8049 exitStatus("Not_Found", "can't find \"tar\" command");
8050 }
8051 my $GzipCmd = get_CmdPath("gzip");
8052 if(not $GzipCmd) {
8053 exitStatus("Not_Found", "can't find \"gzip\" command");
8054 }
8055 chdir($UnpackDir);
Andrey Ponomarenkoa01311b2012-06-08 17:20:02 +04008056 system("$GzipCmd -k -d -f \"$Path\""); # keep input files (-k)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008057 if($?) {
8058 exitStatus("Error", "can't extract \'$Path\'");
8059 }
Andrey Ponomarenkoa01311b2012-06-08 17:20:02 +04008060 system("$TarCmd -xvf \"$Dir\\$FileName.tar\" >contents.txt");
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008061 if($?) {
8062 exitStatus("Error", "can't extract \'$Path\'");
8063 }
8064 chdir($ORIG_DIR);
8065 unlink($Dir."/".$FileName.".tar");
8066 my @Contents = split("\n", readFile("$UnpackDir/contents.txt"));
8067 if(not @Contents) {
8068 exitStatus("Error", "can't extract \'$Path\'");
8069 }
8070 return joinPath($UnpackDir, $Contents[0]);
8071 }
8072 else
8073 { # Unix
8074 my $TarCmd = get_CmdPath("tar");
8075 if(not $TarCmd) {
8076 exitStatus("Not_Found", "can't find \"tar\" command");
8077 }
8078 chdir($UnpackDir);
Andrey Ponomarenkoa01311b2012-06-08 17:20:02 +04008079 system("$TarCmd -xvzf \"$Path\" >contents.txt");
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008080 if($?) {
8081 exitStatus("Error", "can't extract \'$Path\'");
8082 }
8083 chdir($ORIG_DIR);
8084 # The content file name may be different
8085 # from the package file name
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 }
8093}
8094
8095sub createArchive($$)
8096{
8097 my ($Path, $To) = @_;
Andrey Ponomarenko5c09ef32012-06-14 18:17:33 +04008098 if(not $To) {
8099 $To = ".";
8100 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008101 if(not $Path or not -e $Path
8102 or not -d $To) {
8103 return "";
8104 }
8105 my ($From, $Name) = separate_path($Path);
8106 if($OSgroup eq "windows")
8107 { # *.zip
8108 my $ZipCmd = get_CmdPath("zip");
8109 if(not $ZipCmd) {
8110 exitStatus("Not_Found", "can't find \"zip\"");
8111 }
8112 my $Pkg = $To."/".$Name.".zip";
8113 unlink($Pkg);
8114 chdir($To);
Andrey Ponomarenkoa01311b2012-06-08 17:20:02 +04008115 system("$ZipCmd -j \"$Name.zip\" \"$Path\" >\"$TMP_DIR/null\"");
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008116 if($?)
8117 { # cannot allocate memory (or other problems with "zip")
8118 unlink($Path);
8119 exitStatus("Error", "can't pack the ABI dump: ".$!);
8120 }
8121 chdir($ORIG_DIR);
8122 unlink($Path);
8123 return $Pkg;
8124 }
8125 else
8126 { # *.tar.gz
8127 my $TarCmd = get_CmdPath("tar");
8128 if(not $TarCmd) {
8129 exitStatus("Not_Found", "can't find \"tar\"");
8130 }
8131 my $GzipCmd = get_CmdPath("gzip");
8132 if(not $GzipCmd) {
8133 exitStatus("Not_Found", "can't find \"gzip\"");
8134 }
8135 my $Pkg = abs_path($To)."/".$Name.".tar.gz";
8136 unlink($Pkg);
8137 chdir($From);
8138 system($TarCmd, "-czf", $Pkg, $Name);
8139 if($?)
8140 { # cannot allocate memory (or other problems with "tar")
8141 unlink($Path);
8142 exitStatus("Error", "can't pack the ABI dump: ".$!);
8143 }
8144 chdir($ORIG_DIR);
8145 unlink($Path);
8146 return $To."/".$Name.".tar.gz";
8147 }
8148}
8149
Andrey Ponomarenko9927e332012-10-19 10:50:48 +04008150sub readBytes($)
8151{
8152 sysopen(FILE, $_[0], O_RDONLY);
8153 sysread(FILE, my $Header, 4);
8154 close(FILE);
8155 my @Bytes = map { sprintf('%02x', ord($_)) } split (//, $Header);
8156 return join("", @Bytes);
8157}
8158
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008159sub is_header_file($)
8160{
8161 if($_[0]=~/\.($HEADER_EXT)\Z/i) {
8162 return $_[0];
8163 }
8164 return 0;
8165}
8166
8167sub is_not_header($)
8168{
8169 if($_[0]=~/\.\w+\Z/
8170 and $_[0]!~/\.($HEADER_EXT)\Z/i) {
8171 return 1;
8172 }
8173 return 0;
8174}
8175
8176sub is_header($$$)
8177{
8178 my ($Header, $UserDefined, $LibVersion) = @_;
8179 return 0 if(-d $Header);
8180 if(-f $Header) {
8181 $Header = get_abs_path($Header);
8182 }
8183 else
8184 {
8185 if(is_abs($Header))
8186 { # incorrect absolute path
8187 return 0;
8188 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04008189 if(my $HPath = identifyHeader($Header, $LibVersion)) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008190 $Header = $HPath;
8191 }
8192 else
8193 { # can't find header
8194 return 0;
8195 }
8196 }
8197 if($Header=~/\.\w+\Z/)
8198 { # have an extension
8199 return is_header_file($Header);
8200 }
8201 else
8202 {
8203 if($UserDefined==2)
8204 { # specified on the command line
8205 if(cmd_file($Header)!~/HTML|XML/i) {
8206 return $Header;
8207 }
8208 }
8209 elsif($UserDefined)
8210 { # specified in the XML-descriptor
8211 # header file without an extension
8212 return $Header;
8213 }
8214 else
8215 {
Andrey Ponomarenko85043792012-05-14 16:48:07 +04008216 if($Header=~/\/include\//
8217 or cmd_file($Header)=~/C[\+]*\s+program/i)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008218 { # !~/HTML|XML|shared|dynamic/i
8219 return $Header;
8220 }
8221 }
8222 }
8223 return 0;
8224}
8225
Andrey Ponomarenko16934472012-03-29 15:37:04 +04008226sub addTargetHeaders($)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008227{
8228 my $LibVersion = $_[0];
8229 foreach my $RegHeader (keys(%{$Registered_Headers{$LibVersion}}))
8230 {
8231 my $RegDir = get_dirname($RegHeader);
8232 $TargetHeaders{$LibVersion}{get_filename($RegHeader)}=1;
Andrey Ponomarenko9927e332012-10-19 10:50:48 +04008233
8234 if(not $INC_PATH_AUTODETECT{$LibVersion}) {
8235 detect_recursive_includes($RegHeader, $LibVersion);
8236 }
8237
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008238 foreach my $RecInc (keys(%{$RecursiveIncludes{$LibVersion}{$RegHeader}}))
8239 {
8240 my $Dir = get_dirname($RecInc);
Andrey Ponomarenko85043792012-05-14 16:48:07 +04008241 if($Dir=~/\A\Q$RegDir\E([\/\\]|\Z)/
8242 or $RecursiveIncludes{$LibVersion}{$RegHeader}{$RecInc}!=1)
8243 { # in the same directory or included by #include "..."
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008244 $TargetHeaders{$LibVersion}{get_filename($RecInc)}=1;
8245 }
8246 }
8247 }
8248}
8249
8250sub readHeaders($)
8251{
8252 $Version = $_[0];
8253 printMsg("INFO", "checking header(s) ".$Descriptor{$Version}{"Version"}." ...");
8254 my $DumpPath = getDump();
8255 if(not $DumpPath) {
8256 exitStatus("Cannot_Compile", "can't compile header(s)");
8257 }
8258 if($Debug)
8259 { # debug mode
8260 mkpath($DEBUG_PATH{$Version});
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04008261 copy($DumpPath, $DEBUG_PATH{$Version}."/translation-unit-dump.txt");
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008262 }
8263 getInfo($DumpPath);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008264}
8265
8266sub prepareTypes($)
8267{
8268 my $LibVersion = $_[0];
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04008269 if(not checkDump($LibVersion, "2.0"))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008270 { # support for old ABI dumps
8271 # type names have been corrected in ACC 1.22 (dump 2.0 format)
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04008272 foreach my $TypeId (keys(%{$TypeInfo{$LibVersion}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008273 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04008274 my $TName = $TypeInfo{$LibVersion}{$TypeId}{"Name"};
8275 if($TName=~/\A(\w+)::(\w+)/) {
8276 my ($P1, $P2) = ($1, $2);
8277 if($P1 eq $P2) {
8278 $TName=~s/\A$P1:\:$P1(\W)/$P1$1/;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008279 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04008280 else {
8281 $TName=~s/\A(\w+:\:)$P2:\:$P2(\W)/$1$P2$2/;
8282 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008283 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04008284 $TypeInfo{$LibVersion}{$TypeId}{"Name"} = $TName;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008285 }
8286 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04008287 if(not checkDump($LibVersion, "2.5"))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008288 { # support for old ABI dumps
8289 # V < 2.5: array size == "number of elements"
8290 # V >= 2.5: array size in bytes
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04008291 foreach my $TypeId (sort {int($a)<=>int($b)} keys(%{$TypeInfo{$LibVersion}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008292 {
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +04008293 my %Type = get_PureType($TypeId, $TypeInfo{$LibVersion});
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04008294 if($Type{"Type"} eq "Array")
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008295 {
Andrey Ponomarenko01117f12012-06-26 12:23:02 +04008296 if(my $Size = $Type{"Size"})
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04008297 { # array[N]
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +04008298 my %Base = get_OneStep_BaseType($Type{"Tid"}, $TypeInfo{$LibVersion});
Andrey Ponomarenko01117f12012-06-26 12:23:02 +04008299 $Size *= $Base{"Size"};
8300 $TypeInfo{$LibVersion}{$TypeId}{"Size"} = "$Size";
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04008301 }
8302 else
8303 { # array[] is a pointer
8304 $TypeInfo{$LibVersion}{$TypeId}{"Size"} = $WORD_SIZE{$LibVersion};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008305 }
8306 }
8307 }
8308 }
8309 my $V2 = ($LibVersion==1)?2:1;
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04008310 if(not checkDump($LibVersion, "2.7"))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008311 { # support for old ABI dumps
8312 # size of "method ptr" corrected in 2.7
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04008313 foreach my $TypeId (sort {int($a)<=>int($b)} keys(%{$TypeInfo{$LibVersion}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008314 {
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +04008315 my %PureType = get_PureType($TypeId, $TypeInfo{$LibVersion});
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04008316 if($PureType{"Type"} eq "MethodPtr")
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008317 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04008318 my %Type = get_Type($TypeId, $LibVersion);
8319 my $TypeId_2 = getTypeIdByName($PureType{"Name"}, $V2);
8320 my %Type2 = get_Type($TypeId_2, $V2);
8321 if($Type{"Size"} ne $Type2{"Size"}) {
8322 $TypeInfo{$LibVersion}{$TypeId}{"Size"} = $Type2{"Size"};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008323 }
8324 }
8325 }
8326 }
8327}
8328
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04008329sub prepareSymbols($)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008330{
8331 my $LibVersion = $_[0];
Andrey Ponomarenko16934472012-03-29 15:37:04 +04008332
8333 if(not keys(%{$SymbolInfo{$LibVersion}}))
8334 { # check if input is valid
8335 if(not $ExtendedCheck and not $CheckObjectsOnly)
8336 {
8337 if($CheckHeadersOnly) {
8338 exitStatus("Empty_Set", "the set of public symbols is empty (".$Descriptor{$LibVersion}{"Version"}.")");
8339 }
8340 else {
8341 exitStatus("Empty_Intersection", "the sets of public symbols in headers and libraries have empty intersection (".$Descriptor{$LibVersion}{"Version"}.")");
8342 }
8343 }
8344 }
8345
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008346 my $Remangle = 0;
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04008347 if(not checkDump(1, "2.10")
8348 or not checkDump(2, "2.10"))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008349 { # different formats
8350 $Remangle = 1;
8351 }
8352 if($CheckHeadersOnly)
8353 { # different languages
8354 if($UserLang)
8355 { # --lang=LANG for both versions
8356 if(($UsedDump{1}{"V"} and $UserLang ne $UsedDump{1}{"L"})
8357 or ($UsedDump{2}{"V"} and $UserLang ne $UsedDump{2}{"L"}))
8358 {
8359 if($UserLang eq "C++")
8360 { # remangle symbols
8361 $Remangle = 1;
8362 }
8363 elsif($UserLang eq "C")
8364 { # remove mangling
8365 $Remangle = -1;
8366 }
8367 }
8368 }
8369 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04008370
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04008371 foreach my $InfoId (sort {int($b)<=>int($a)} keys(%{$SymbolInfo{$LibVersion}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008372 { # reverse order: D0, D1, D2, D0 (artificial, GCC < 4.5), C1, C2
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04008373 if(not checkDump($LibVersion, "2.13"))
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04008374 { # support for old ABI dumps
8375 if(defined $SymbolInfo{$LibVersion}{$InfoId}{"Param"})
8376 {
8377 foreach my $P (keys(%{$SymbolInfo{$LibVersion}{$InfoId}{"Param"}}))
8378 {
8379 my $TypeId = $SymbolInfo{$LibVersion}{$InfoId}{"Param"}{$P}{"type"};
8380 my $DVal = $SymbolInfo{$LibVersion}{$InfoId}{"Param"}{$P}{"default"};
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04008381 my $TName = $TypeInfo{$LibVersion}{$TypeId}{"Name"};
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04008382 if(defined $DVal and $DVal ne "")
8383 {
8384 if($TName eq "char") {
8385 $SymbolInfo{$LibVersion}{$InfoId}{"Param"}{$P}{"default"} = chr($DVal);
8386 }
8387 elsif($TName eq "bool") {
8388 $SymbolInfo{$LibVersion}{$InfoId}{"Param"}{$P}{"default"} = $DVal?"true":"false";
8389 }
8390 }
8391 }
8392 }
8393 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04008394 if($SymbolInfo{$LibVersion}{$InfoId}{"Destructor"})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008395 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04008396 if(defined $SymbolInfo{$LibVersion}{$InfoId}{"Param"}
8397 and keys(%{$SymbolInfo{$LibVersion}{$InfoId}{"Param"}})
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04008398 and $SymbolInfo{$LibVersion}{$InfoId}{"Param"}{0}{"name"})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008399 { # support for old GCC < 4.5: skip artificial ~dtor(int __in_chrg)
8400 # + support for old ABI dumps
8401 next;
8402 }
8403 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04008404 my $MnglName = $SymbolInfo{$LibVersion}{$InfoId}{"MnglName"};
Andrey Ponomarenko85043792012-05-14 16:48:07 +04008405 my $ShortName = $SymbolInfo{$LibVersion}{$InfoId}{"ShortName"};
Andrey Ponomarenko16934472012-03-29 15:37:04 +04008406 my $ClassID = $SymbolInfo{$LibVersion}{$InfoId}{"Class"};
Andrey Ponomarenko85043792012-05-14 16:48:07 +04008407 my $Return = $SymbolInfo{$LibVersion}{$InfoId}{"Return"};
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04008408
Andrey Ponomarenko16934472012-03-29 15:37:04 +04008409 my $SRemangle = 0;
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04008410 if(not checkDump(1, "2.12")
8411 or not checkDump(2, "2.12"))
Andrey Ponomarenko16934472012-03-29 15:37:04 +04008412 { # support for old ABI dumps
Andrey Ponomarenko85043792012-05-14 16:48:07 +04008413 if($ShortName eq "operator>>")
8414 {
8415 if(not $SymbolInfo{$LibVersion}{$InfoId}{"Class"})
8416 { # corrected mangling of operator>>
8417 $SRemangle = 1;
8418 }
Andrey Ponomarenko16934472012-03-29 15:37:04 +04008419 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +04008420 if($SymbolInfo{$LibVersion}{$InfoId}{"Data"})
8421 {
8422 if(not $SymbolInfo{$LibVersion}{$InfoId}{"Class"}
8423 and isConstType($Return, $LibVersion) and $MnglName!~/L\d+$ShortName/)
8424 { # corrected mangling of const global data
8425 # some global data is not mangled in the TU dump: qt_sine_table (Qt 4.8)
8426 # and incorrectly mangled by old ACC versions
8427 $SRemangle = 1;
8428 }
Andrey Ponomarenko16934472012-03-29 15:37:04 +04008429 }
8430 }
Andrey Ponomarenko5c09ef32012-06-14 18:17:33 +04008431 if(not $CheckHeadersOnly)
8432 { # support for old ABI dumps
8433 if(not checkDump(1, "2.17")
8434 or not checkDump(2, "2.17"))
8435 {
8436 if($SymbolInfo{$LibVersion}{$InfoId}{"Data"})
8437 {
8438 if(not $SymbolInfo{$LibVersion}{$InfoId}{"Class"})
8439 {
8440 if(link_symbol($ShortName, $LibVersion, "-Deps"))
8441 {
8442 $MnglName = $ShortName;
8443 $SymbolInfo{$LibVersion}{$InfoId}{"MnglName"} = $MnglName;
8444 }
8445 }
8446 }
8447 }
8448 }
Andrey Ponomarenko16934472012-03-29 15:37:04 +04008449 if($Remangle==1 or $SRemangle==1)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008450 { # support for old ABI dumps: some symbols are not mangled in old dumps
8451 # mangle both sets of symbols (old and new)
8452 # NOTE: remangling all symbols by the same mangler
8453 if($MnglName=~/\A_ZN(V|)K/)
8454 { # mangling may be incorrect on old ABI dumps
8455 # because of absent "Const" attribute
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04008456 $SymbolInfo{$LibVersion}{$InfoId}{"Const"} = 1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008457 }
8458 if($MnglName=~/\A_ZN(K|)V/)
8459 { # mangling may be incorrect on old ABI dumps
8460 # because of absent "Volatile" attribute
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04008461 $SymbolInfo{$LibVersion}{$InfoId}{"Volatile"} = 1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008462 }
Andrey Ponomarenko16934472012-03-29 15:37:04 +04008463 if(($ClassID and $MnglName!~/\A(_Z|\?)/)
8464 or (not $ClassID and $CheckHeadersOnly)
8465 or (not $ClassID and not link_symbol($MnglName, $LibVersion, "-Deps")))
8466 { # support for old ABI dumps, GCC >= 4.0
8467 # remangling all manually mangled symbols
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04008468 if($MnglName = mangle_symbol($InfoId, $LibVersion, "GCC"))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008469 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04008470 $SymbolInfo{$LibVersion}{$InfoId}{"MnglName"} = $MnglName;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008471 $MangledNames{$LibVersion}{$MnglName} = 1;
8472 }
8473 }
8474 }
8475 elsif($Remangle==-1)
8476 { # remove mangling
8477 $MnglName = "";
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04008478 $SymbolInfo{$LibVersion}{$InfoId}{"MnglName"} = "";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008479 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008480 if(not $MnglName) {
8481 next;
8482 }
8483 if(not $CompleteSignature{$LibVersion}{$MnglName}{"MnglName"})
8484 { # NOTE: global data may enter here twice
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04008485 %{$CompleteSignature{$LibVersion}{$MnglName}} = %{$SymbolInfo{$LibVersion}{$InfoId}};
8486
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008487 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04008488 if(not checkDump($LibVersion, "2.6"))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008489 { # support for old dumps
8490 # add "Volatile" attribute
8491 if($MnglName=~/_Z(K|)V/) {
8492 $CompleteSignature{$LibVersion}{$MnglName}{"Volatile"}=1;
8493 }
8494 }
8495 # symbol and its symlink have same signatures
8496 if($SymVer{$LibVersion}{$MnglName}) {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04008497 %{$CompleteSignature{$LibVersion}{$SymVer{$LibVersion}{$MnglName}}} = %{$SymbolInfo{$LibVersion}{$InfoId}};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008498 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +04008499
8500 # clean memory
Andrey Ponomarenko16934472012-03-29 15:37:04 +04008501 delete($SymbolInfo{$LibVersion}{$InfoId});
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008502 }
8503 if($COMMON_LANGUAGE{$LibVersion} eq "C++" or $OSgroup eq "windows") {
8504 translateSymbols(keys(%{$CompleteSignature{$LibVersion}}), $LibVersion);
8505 }
8506 if($ExtendedCheck)
8507 { # --ext option
8508 addExtension($LibVersion);
8509 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +04008510
8511 # clean memory
8512 delete($SymbolInfo{$LibVersion});
8513
8514 foreach my $Symbol (keys(%{$CompleteSignature{$LibVersion}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008515 { # detect allocable classes with public exported constructors
8516 # or classes with auto-generated or inline-only constructors
Andrey Ponomarenko9927e332012-10-19 10:50:48 +04008517 # and other temp info
Andrey Ponomarenko85043792012-05-14 16:48:07 +04008518 if(my $ClassId = $CompleteSignature{$LibVersion}{$Symbol}{"Class"})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008519 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04008520 my $ClassName = $TypeInfo{$LibVersion}{$ClassId}{"Name"};
Andrey Ponomarenko85043792012-05-14 16:48:07 +04008521 if($CompleteSignature{$LibVersion}{$Symbol}{"Constructor"}
8522 and not $CompleteSignature{$LibVersion}{$Symbol}{"InLine"})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008523 { # Class() { ... } will not be exported
Andrey Ponomarenko85043792012-05-14 16:48:07 +04008524 if(not $CompleteSignature{$LibVersion}{$Symbol}{"Private"})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008525 {
Andrey Ponomarenko85043792012-05-14 16:48:07 +04008526 if($CheckHeadersOnly or link_symbol($Symbol, $LibVersion, "-Deps")) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008527 $AllocableClass{$LibVersion}{$ClassName} = 1;
8528 }
8529 }
8530 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +04008531 if(not $CompleteSignature{$LibVersion}{$Symbol}{"Private"})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008532 { # all imported class methods
Andrey Ponomarenko85043792012-05-14 16:48:07 +04008533 if(symbolFilter($Symbol, $LibVersion, "Affected", "Binary"))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008534 {
Andrey Ponomarenko85043792012-05-14 16:48:07 +04008535 if($CheckHeadersOnly)
8536 {
8537 if(not $CompleteSignature{$LibVersion}{$Symbol}{"InLine"}
8538 or $CompleteSignature{$LibVersion}{$Symbol}{"Virt"})
8539 { # all symbols except non-virtual inline
8540 $ClassMethods{"Binary"}{$LibVersion}{$ClassName}{$Symbol} = 1;
8541 }
8542 }
8543 else {
8544 $ClassMethods{"Binary"}{$LibVersion}{$ClassName}{$Symbol} = 1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008545 }
8546 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04008547 if(symbolFilter($Symbol, $LibVersion, "Affected", "Source")) {
Andrey Ponomarenko85043792012-05-14 16:48:07 +04008548 $ClassMethods{"Source"}{$LibVersion}{$ClassName}{$Symbol} = 1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008549 }
8550 }
Andrey Ponomarenko16934472012-03-29 15:37:04 +04008551 $ClassNames{$LibVersion}{$ClassName} = 1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008552 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +04008553 if(my $RetId = $CompleteSignature{$LibVersion}{$Symbol}{"Return"})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008554 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04008555 my %Base = get_BaseType($RetId, $LibVersion);
Andrey Ponomarenko85043792012-05-14 16:48:07 +04008556 if(defined $Base{"Type"}
8557 and $Base{"Type"}=~/Struct|Class/)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008558 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04008559 my $Name = $TypeInfo{$LibVersion}{$Base{"Tid"}}{"Name"};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008560 if($Name=~/<([^<>\s]+)>/)
8561 {
8562 if(my $Tid = getTypeIdByName($1, $LibVersion)) {
8563 $ReturnedClass{$LibVersion}{$Tid} = 1;
8564 }
8565 }
8566 else {
8567 $ReturnedClass{$LibVersion}{$Base{"Tid"}} = 1;
8568 }
8569 }
8570 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +04008571 foreach my $Num (keys(%{$CompleteSignature{$LibVersion}{$Symbol}{"Param"}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008572 {
Andrey Ponomarenko85043792012-05-14 16:48:07 +04008573 my $PId = $CompleteSignature{$LibVersion}{$Symbol}{"Param"}{$Num}{"type"};
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04008574 if(get_PLevel($PId, $LibVersion)>=1)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008575 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04008576 if(my %Base = get_BaseType($PId, $LibVersion))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008577 {
Andrey Ponomarenko16934472012-03-29 15:37:04 +04008578 if($Base{"Type"}=~/Struct|Class/)
8579 {
Andrey Ponomarenko85043792012-05-14 16:48:07 +04008580 $ParamClass{$LibVersion}{$Base{"Tid"}}{$Symbol} = 1;
Andrey Ponomarenko16934472012-03-29 15:37:04 +04008581 foreach my $SubId (get_sub_classes($Base{"Tid"}, $LibVersion, 1))
8582 { # mark all derived classes
Andrey Ponomarenko85043792012-05-14 16:48:07 +04008583 $ParamClass{$LibVersion}{$SubId}{$Symbol} = 1;
Andrey Ponomarenko16934472012-03-29 15:37:04 +04008584 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008585 }
8586 }
8587 }
8588 }
Andrey Ponomarenko9927e332012-10-19 10:50:48 +04008589
8590 # mapping {short name => symbols}
8591 $Func_ShortName{$LibVersion}{$CompleteSignature{$LibVersion}{$Symbol}{"ShortName"}}{$Symbol} = 1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008592 }
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04008593 foreach my $MnglName (keys(%VTableClass))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008594 { # reconstruct header name for v-tables
Andrey Ponomarenko9927e332012-10-19 10:50:48 +04008595 if(index($MnglName, "_ZTV")==0)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008596 {
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04008597 if(my $ClassName = $VTableClass{$MnglName})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008598 {
8599 if(my $ClassId = $TName_Tid{$LibVersion}{$ClassName}) {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04008600 $CompleteSignature{$LibVersion}{$MnglName}{"Header"} = $TypeInfo{$LibVersion}{$ClassId}{"Header"};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008601 }
8602 }
8603 }
8604 }
Andrey Ponomarenko16934472012-03-29 15:37:04 +04008605
8606 # types
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04008607 foreach my $TypeId (keys(%{$TypeInfo{$LibVersion}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008608 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04008609 if(my $TName = $TypeInfo{$LibVersion}{$TypeId}{"Name"})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008610 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04008611 if(defined $TypeInfo{$LibVersion}{$TypeId}{"VTable"}) {
8612 $ClassNames{$LibVersion}{$TName} = 1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008613 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04008614 if(defined $TypeInfo{$LibVersion}{$TypeId}{"Base"})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008615 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04008616 $ClassNames{$LibVersion}{$TName} = 1;
8617 foreach my $Bid (keys(%{$TypeInfo{$LibVersion}{$TypeId}{"Base"}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008618 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04008619 if(my $BName = $TypeInfo{$LibVersion}{$Bid}{"Name"}) {
8620 $ClassNames{$LibVersion}{$BName} = 1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008621 }
8622 }
8623 }
8624 }
8625 }
8626}
8627
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04008628sub register_TypeUsage($$)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008629{
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04008630 my ($TypeId, $LibVersion) = @_;
8631 if(not $TypeId) {
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04008632 return 0;
8633 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04008634 if($UsedType{$LibVersion}{$TypeId})
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04008635 { # already registered
8636 return 1;
8637 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04008638 my %TInfo = get_Type($TypeId, $LibVersion);
Andrey Ponomarenko85043792012-05-14 16:48:07 +04008639 if($TInfo{"Type"})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008640 {
Andrey Ponomarenko85043792012-05-14 16:48:07 +04008641 if($TInfo{"Type"}=~/\A(Struct|Union|Class|FuncPtr|MethodPtr|FieldPtr|Enum)\Z/)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008642 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04008643 $UsedType{$LibVersion}{$TypeId} = 1;
Andrey Ponomarenko85043792012-05-14 16:48:07 +04008644 if($TInfo{"Type"}=~/\A(Struct|Class)\Z/)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008645 {
Andrey Ponomarenko85043792012-05-14 16:48:07 +04008646 foreach my $BaseId (keys(%{$TInfo{"Base"}}))
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04008647 { # register base classes
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04008648 register_TypeUsage($BaseId, $LibVersion);
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04008649 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +04008650 foreach my $TPos (keys(%{$TInfo{"TParam"}}))
8651 {
8652 my $TPName = $TInfo{"TParam"}{$TPos}{"name"};
8653 if(my $TTid = $TName_Tid{$LibVersion}{$TPName}) {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04008654 register_TypeUsage($TTid, $LibVersion);
Andrey Ponomarenko85043792012-05-14 16:48:07 +04008655 }
8656 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008657 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +04008658 foreach my $Memb_Pos (keys(%{$TInfo{"Memb"}}))
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04008659 {
Andrey Ponomarenko85043792012-05-14 16:48:07 +04008660 if(my $MTid = $TInfo{"Memb"}{$Memb_Pos}{"type"}) {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04008661 register_TypeUsage($MTid, $LibVersion);
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04008662 }
8663 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +04008664 if($TInfo{"Type"} eq "FuncPtr"
8665 or $TInfo{"Type"} eq "MethodPtr")
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04008666 {
Andrey Ponomarenko85043792012-05-14 16:48:07 +04008667 if(my $RTid = $TInfo{"Return"}) {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04008668 register_TypeUsage($RTid, $LibVersion);
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04008669 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +04008670 foreach my $Memb_Pos (keys(%{$TInfo{"Param"}}))
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04008671 {
Andrey Ponomarenko85043792012-05-14 16:48:07 +04008672 if(my $MTid = $TInfo{"Param"}{$Memb_Pos}{"type"}) {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04008673 register_TypeUsage($MTid, $LibVersion);
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04008674 }
8675 }
8676 }
8677 return 1;
8678 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +04008679 elsif($TInfo{"Type"}=~/\A(Const|ConstVolatile|Volatile|Pointer|Ref|Restrict|Array|Typedef)\Z/)
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04008680 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04008681 $UsedType{$LibVersion}{$TypeId} = 1;
8682 register_TypeUsage($TInfo{"BaseType"}{"Tid"}, $LibVersion);
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04008683 return 1;
8684 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04008685 elsif($TInfo{"Type"} eq "Intrinsic")
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04008686 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04008687 $UsedType{$LibVersion}{$TypeId} = 1;
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04008688 return 1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008689 }
8690 }
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04008691 return 0;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008692}
8693
Andrey Ponomarenko85043792012-05-14 16:48:07 +04008694sub selectSymbol($$$$)
Andrey Ponomarenko35c44fd2012-06-18 17:50:25 +04008695{ # select symbol to check or to dump
Andrey Ponomarenko85043792012-05-14 16:48:07 +04008696 my ($Symbol, $SInfo, $Level, $LibVersion) = @_;
8697
Andrey Ponomarenko35c44fd2012-06-18 17:50:25 +04008698 if($Level eq "Dump")
8699 {
8700 if($SInfo->{"Virt"} or $SInfo->{"PureVirt"})
8701 { # TODO: check if this symbol is from
8702 # base classes of other target symbols
8703 return 1;
8704 }
8705 }
8706
Andrey Ponomarenko85043792012-05-14 16:48:07 +04008707 if(not $STDCXX_TESTING and $Symbol=~/\A(_ZS|_ZNS|_ZNKS)/)
8708 { # stdc++ interfaces
8709 return 0;
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04008710 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +04008711
8712 my $Target = 0;
8713 if(my $Header = $SInfo->{"Header"}) {
8714 $Target = (is_target_header($Header, 1) or is_target_header($Header, 2));
8715 }
8716 if($CheckHeadersOnly)
8717 {
8718 if($Target)
8719 {
8720 if($Level eq "Dump")
8721 { # dumped
8722 if($BinaryOnly)
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04008723 {
Andrey Ponomarenko85043792012-05-14 16:48:07 +04008724 if(not $SInfo->{"InLine"} or $SInfo->{"Data"}) {
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04008725 return 1;
8726 }
8727 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +04008728 else {
8729 return 1;
8730 }
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04008731 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +04008732 elsif($Level eq "Source")
8733 { # checked
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04008734 return 1;
8735 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +04008736 elsif($Level eq "Binary")
8737 { # checked
8738 if(not $SInfo->{"InLine"} or $SInfo->{"Data"}
8739 or $SInfo->{"Virt"} or $SInfo->{"PureVirt"}) {
8740 return 1;
8741 }
8742 }
8743 }
8744 }
8745 else
8746 { # library is available
8747 if(link_symbol($Symbol, $LibVersion, "-Deps"))
8748 { # exported symbols
8749 return 1;
8750 }
8751 if($Level eq "Dump")
8752 { # dumped
Andrey Ponomarenko35c44fd2012-06-18 17:50:25 +04008753 if($BinaryOnly)
8754 {
8755 if($SInfo->{"Data"})
8756 {
8757 if($Target) {
8758 return 1;
8759 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +04008760 }
8761 }
Andrey Ponomarenko35c44fd2012-06-18 17:50:25 +04008762 else
8763 { # SrcBin
Andrey Ponomarenko85043792012-05-14 16:48:07 +04008764 if($Target) {
8765 return 1;
8766 }
8767 }
8768 }
8769 elsif($Level eq "Source")
8770 { # checked
Andrey Ponomarenko01117f12012-06-26 12:23:02 +04008771 if($SInfo->{"PureVirt"} or $SInfo->{"Data"} or $SInfo->{"InLine"}
8772 or isInLineInst($Symbol, $SInfo, $LibVersion))
Andrey Ponomarenko35c44fd2012-06-18 17:50:25 +04008773 { # skip LOCAL symbols
8774 if($Target) {
8775 return 1;
8776 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +04008777 }
8778 }
8779 elsif($Level eq "Binary")
8780 { # checked
8781 if($SInfo->{"PureVirt"} or $SInfo->{"Data"})
8782 {
8783 if($Target) {
8784 return 1;
8785 }
8786 }
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04008787 }
8788 }
8789 return 0;
8790}
8791
Andrey Ponomarenko85043792012-05-14 16:48:07 +04008792sub cleanDump($)
8793{ # clean data
Andrey Ponomarenko16934472012-03-29 15:37:04 +04008794 my $LibVersion = $_[0];
8795 foreach my $InfoId (keys(%{$SymbolInfo{$LibVersion}}))
8796 {
8797 my $MnglName = $SymbolInfo{$LibVersion}{$InfoId}{"MnglName"};
8798 if(not $MnglName) {
8799 delete($SymbolInfo{$LibVersion}{$InfoId});
8800 next;
8801 }
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04008802 my $ShortName = $SymbolInfo{$LibVersion}{$InfoId}{"ShortName"};
Andrey Ponomarenko85043792012-05-14 16:48:07 +04008803 if(not $ShortName) {
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04008804 delete($SymbolInfo{$LibVersion}{$InfoId});
8805 next;
Andrey Ponomarenko16934472012-03-29 15:37:04 +04008806 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +04008807 if($MnglName eq $ShortName)
8808 { # remove duplicate data
8809 delete($SymbolInfo{$LibVersion}{$InfoId}{"MnglName"});
Andrey Ponomarenko16934472012-03-29 15:37:04 +04008810 }
8811 if(not keys(%{$SymbolInfo{$LibVersion}{$InfoId}{"Param"}})) {
8812 delete($SymbolInfo{$LibVersion}{$InfoId}{"Param"});
8813 }
Andrey Ponomarenko01117f12012-06-26 12:23:02 +04008814 if(not keys(%{$SymbolInfo{$LibVersion}{$InfoId}{"TParam"}})) {
8815 delete($SymbolInfo{$LibVersion}{$InfoId}{"TParam"});
8816 }
Andrey Ponomarenko16934472012-03-29 15:37:04 +04008817 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04008818 foreach my $Tid (keys(%{$TypeInfo{$LibVersion}}))
Andrey Ponomarenko85043792012-05-14 16:48:07 +04008819 {
Andrey Ponomarenko01117f12012-06-26 12:23:02 +04008820 delete($TypeInfo{$LibVersion}{$Tid}{"Tid"});
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04008821 foreach my $Attr ("Header", "Line", "Size", "NameSpace")
Andrey Ponomarenko16934472012-03-29 15:37:04 +04008822 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04008823 if(not $TypeInfo{$LibVersion}{$Tid}{$Attr}) {
8824 delete($TypeInfo{$LibVersion}{$Tid}{$Attr});
8825 }
8826 }
Andrey Ponomarenko01117f12012-06-26 12:23:02 +04008827 if(not keys(%{$TypeInfo{$LibVersion}{$Tid}{"TParam"}})) {
8828 delete($TypeInfo{$LibVersion}{$Tid}{"TParam"});
8829 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04008830 }
8831}
8832
8833sub selectType($$)
8834{
8835 my ($Tid, $LibVersion) = @_;
Andrey Ponomarenko9927e332012-10-19 10:50:48 +04008836
8837 if(my $Dupl = $TypeTypedef{$LibVersion}{$Tid})
8838 {
8839 if(defined $TypeInfo{$LibVersion}{$Dupl})
8840 {
8841 if($TypeInfo{$LibVersion}{$Dupl}{"Name"} eq $TypeInfo{$LibVersion}{$Tid}{"Name"})
8842 { # duplicate
8843 return 0;
8844 }
8845 }
8846 }
8847
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04008848 if(my $THeader = $TypeInfo{$LibVersion}{$Tid}{"Header"})
8849 {
8850 if(not isBuiltIn($THeader))
8851 {
8852 if($TypeInfo{$LibVersion}{$Tid}{"Type"}=~/Class|Struct|Union|Enum|Typedef/)
Andrey Ponomarenko16934472012-03-29 15:37:04 +04008853 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04008854 if(not isAnon($TypeInfo{$LibVersion}{$Tid}{"Name"}))
8855 {
8856 if(is_target_header($THeader, $LibVersion))
8857 { # from target headers
8858 if(not selfTypedef($Tid, $LibVersion)) {
8859 return 1;
8860 }
8861 }
Andrey Ponomarenko16934472012-03-29 15:37:04 +04008862 }
8863 }
8864 }
8865 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04008866 return 0;
Andrey Ponomarenko16934472012-03-29 15:37:04 +04008867}
8868
Andrey Ponomarenko85043792012-05-14 16:48:07 +04008869sub removeUnused($$)
8870{ # remove unused data types from the ABI dump
8871 my ($LibVersion, $Kind) = @_;
8872 foreach my $InfoId (keys(%{$SymbolInfo{$LibVersion}}))
8873 {
8874 my %FuncInfo = %{$SymbolInfo{$LibVersion}{$InfoId}};
8875 if(my $RTid = $FuncInfo{"Return"}) {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04008876 register_TypeUsage($RTid, $LibVersion);
Andrey Ponomarenko85043792012-05-14 16:48:07 +04008877 }
8878 if(my $FCid = $FuncInfo{"Class"})
8879 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04008880 register_TypeUsage($FCid, $LibVersion);
8881 if(my $ThisId = getTypeIdByName($TypeInfo{$LibVersion}{$FCid}{"Name"}."*const", $LibVersion))
Andrey Ponomarenko85043792012-05-14 16:48:07 +04008882 { # register "this" pointer
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04008883 $UsedType{$LibVersion}{$ThisId} = 1;
8884 if(my %ThisType = get_Type($ThisId, $LibVersion)) {
8885 register_TypeUsage($ThisType{"BaseType"}{"Tid"}, $LibVersion);
Andrey Ponomarenko85043792012-05-14 16:48:07 +04008886 }
8887 }
8888 }
8889 foreach my $PPos (keys(%{$FuncInfo{"Param"}}))
8890 {
8891 if(my $PTid = $FuncInfo{"Param"}{$PPos}{"type"}) {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04008892 register_TypeUsage($PTid, $LibVersion);
Andrey Ponomarenko85043792012-05-14 16:48:07 +04008893 }
8894 }
8895 foreach my $TPos (keys(%{$FuncInfo{"TParam"}}))
8896 {
8897 my $TPName = $FuncInfo{"TParam"}{$TPos}{"name"};
8898 if(my $TTid = $TName_Tid{$LibVersion}{$TPName}) {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04008899 register_TypeUsage($TTid, $LibVersion);
Andrey Ponomarenko85043792012-05-14 16:48:07 +04008900 }
8901 }
8902 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04008903 foreach my $Tid (keys(%{$TypeInfo{$LibVersion}}))
8904 {
8905 if($UsedType{$LibVersion}{$Tid})
8906 { # All & Derived
8907 next;
8908 }
8909
8910 if($Kind eq "Derived")
Andrey Ponomarenko85043792012-05-14 16:48:07 +04008911 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04008912 if(selectType($Tid, $LibVersion)) {
8913 register_TypeUsage($Tid, $LibVersion);
Andrey Ponomarenko85043792012-05-14 16:48:07 +04008914 }
8915 }
8916 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04008917 foreach my $Tid (keys(%{$TypeInfo{$LibVersion}}))
8918 { # remove unused types
8919 if($UsedType{$LibVersion}{$Tid})
8920 { # All & Derived
8921 next;
8922 }
8923 # remove type
8924 delete($TypeInfo{$LibVersion}{$Tid});
8925 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +04008926
8927 # clean memory
8928 %UsedType = ();
8929}
8930
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04008931sub selfTypedef($$)
Andrey Ponomarenko85043792012-05-14 16:48:07 +04008932{
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04008933 my ($TypeId, $LibVersion) = @_;
8934 my %Type = get_Type($TypeId, $LibVersion);
Andrey Ponomarenko85043792012-05-14 16:48:07 +04008935 if($Type{"Type"} eq "Typedef")
8936 {
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +04008937 my %Base = get_OneStep_BaseType($TypeId, $TypeInfo{$LibVersion});
Andrey Ponomarenko85043792012-05-14 16:48:07 +04008938 if($Base{"Type"}=~/Class|Struct/)
8939 {
8940 if($Type{"Name"} eq $Base{"Name"}) {
8941 return 1;
8942 }
8943 elsif($Type{"Name"}=~/::(\w+)\Z/)
8944 {
8945 if($Type{"Name"} eq $Base{"Name"}."::".$1)
8946 { # QPointer<QWidget>::QPointer
8947 return 1;
8948 }
8949 }
8950 }
8951 }
8952 return 0;
8953}
8954
Andrey Ponomarenko16934472012-03-29 15:37:04 +04008955sub addExtension($)
8956{
8957 my $LibVersion = $_[0];
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04008958 foreach my $Tid (keys(%{$TypeInfo{$LibVersion}}))
Andrey Ponomarenko16934472012-03-29 15:37:04 +04008959 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04008960 if(selectType($Tid, $LibVersion))
Andrey Ponomarenko16934472012-03-29 15:37:04 +04008961 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04008962 my $Symbol = "external_func_".$TypeInfo{$LibVersion}{$Tid}{"Name"};
8963
8964 %{$CompleteSignature{$LibVersion}{$Symbol}} = (
8965 "Header" => "extended.h",
8966 "ShortName" => $Symbol,
8967 "MnglName" => $Symbol,
8968 "Param" => { 0 => { "type"=>$Tid, "name"=>"p1" } }
8969 );
8970
8971 $ExtendedSymbols{$Symbol}=1;
8972 $CheckedSymbols{"Binary"}{$Symbol}=1;
8973 $CheckedSymbols{"Source"}{$Symbol}=1;
Andrey Ponomarenko16934472012-03-29 15:37:04 +04008974 }
8975 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04008976 $ExtendedSymbols{"external_func_0"}=1;
8977 $CheckedSymbols{"Binary"}{"external_func_0"}=1;
8978 $CheckedSymbols{"Source"}{"external_func_0"}=1;
Andrey Ponomarenko16934472012-03-29 15:37:04 +04008979}
8980
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008981sub findMethod($$$)
8982{
8983 my ($VirtFunc, $ClassId, $LibVersion) = @_;
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04008984 foreach my $BaseClass_Id (keys(%{$TypeInfo{$LibVersion}{$ClassId}{"Base"}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008985 {
8986 if(my $VirtMethodInClass = findMethod_Class($VirtFunc, $BaseClass_Id, $LibVersion)) {
8987 return $VirtMethodInClass;
8988 }
8989 elsif(my $VirtMethodInBaseClasses = findMethod($VirtFunc, $BaseClass_Id, $LibVersion)) {
8990 return $VirtMethodInBaseClasses;
8991 }
8992 }
8993 return "";
8994}
8995
8996sub findMethod_Class($$$)
8997{
8998 my ($VirtFunc, $ClassId, $LibVersion) = @_;
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04008999 my $ClassName = $TypeInfo{$LibVersion}{$ClassId}{"Name"};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009000 return "" if(not defined $VirtualTable{$LibVersion}{$ClassName});
9001 my $TargetSuffix = get_symbol_suffix($VirtFunc, 1);
9002 my $TargetShortName = $CompleteSignature{$LibVersion}{$VirtFunc}{"ShortName"};
9003 foreach my $Candidate (keys(%{$VirtualTable{$LibVersion}{$ClassName}}))
9004 { # search for interface with the same parameters suffix (overridden)
9005 if($TargetSuffix eq get_symbol_suffix($Candidate, 1))
9006 {
9007 if($CompleteSignature{$LibVersion}{$VirtFunc}{"Destructor"}) {
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04009008 if($CompleteSignature{$LibVersion}{$Candidate}{"Destructor"})
9009 {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009010 if(($VirtFunc=~/D0E/ and $Candidate=~/D0E/)
9011 or ($VirtFunc=~/D1E/ and $Candidate=~/D1E/)
9012 or ($VirtFunc=~/D2E/ and $Candidate=~/D2E/)) {
9013 return $Candidate;
9014 }
9015 }
9016 }
9017 else {
9018 if($TargetShortName eq $CompleteSignature{$LibVersion}{$Candidate}{"ShortName"}) {
9019 return $Candidate;
9020 }
9021 }
9022 }
9023 }
9024 return "";
9025}
9026
Andrey Ponomarenko16934472012-03-29 15:37:04 +04009027sub registerVTable($)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009028{
Andrey Ponomarenko16934472012-03-29 15:37:04 +04009029 my $LibVersion = $_[0];
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04009030 foreach my $Symbol (keys(%{$CompleteSignature{$LibVersion}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009031 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04009032 if($CompleteSignature{$LibVersion}{$Symbol}{"Virt"}
9033 or $CompleteSignature{$LibVersion}{$Symbol}{"PureVirt"})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009034 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04009035 my $ClassName = $TypeInfo{$LibVersion}{$CompleteSignature{$LibVersion}{$Symbol}{"Class"}}{"Name"};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009036 next if(not $STDCXX_TESTING and $ClassName=~/\A(std::|__cxxabi)/);
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04009037 if($CompleteSignature{$LibVersion}{$Symbol}{"Destructor"}
9038 and $Symbol=~/D2E/)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009039 { # pure virtual D2-destructors are marked as "virt" in the dump
9040 # virtual D2-destructors are NOT marked as "virt" in the dump
9041 # both destructors are not presented in the v-table
9042 next;
9043 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04009044 my ($MnglName, $VersionSpec, $SymbolVersion) = separate_symbol($Symbol);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009045 $VirtualTable{$LibVersion}{$ClassName}{$MnglName} = 1;
9046 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009047 }
9048}
9049
9050sub registerOverriding($)
9051{
9052 my $LibVersion = $_[0];
9053 my @Classes = keys(%{$VirtualTable{$LibVersion}});
Andrey Ponomarenko85043792012-05-14 16:48:07 +04009054 @Classes = sort {int($TName_Tid{$LibVersion}{$a})<=>int($TName_Tid{$LibVersion}{$b})} @Classes;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009055 foreach my $ClassName (@Classes)
9056 {
9057 foreach my $VirtFunc (keys(%{$VirtualTable{$LibVersion}{$ClassName}}))
9058 {
Andrey Ponomarenko16934472012-03-29 15:37:04 +04009059 if($CompleteSignature{$LibVersion}{$VirtFunc}{"PureVirt"})
9060 { # pure virtuals
9061 next;
9062 }
9063 my $ClassId = $TName_Tid{$LibVersion}{$ClassName};
9064 if(my $Overridden = findMethod($VirtFunc, $ClassId, $LibVersion))
Andrey Ponomarenko85043792012-05-14 16:48:07 +04009065 {
9066 if($CompleteSignature{$LibVersion}{$Overridden}{"Virt"}
9067 or $CompleteSignature{$LibVersion}{$Overridden}{"PureVirt"})
9068 { # both overridden virtual methods
9069 # and implemented pure virtual methods
9070 $CompleteSignature{$LibVersion}{$VirtFunc}{"Override"} = $Overridden;
9071 $OverriddenMethods{$LibVersion}{$Overridden}{$VirtFunc} = 1;
9072 delete($VirtualTable{$LibVersion}{$ClassName}{$VirtFunc}); # remove from v-table model
9073 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009074 }
9075 }
9076 if(not keys(%{$VirtualTable{$LibVersion}{$ClassName}})) {
9077 delete($VirtualTable{$LibVersion}{$ClassName});
9078 }
9079 }
9080}
9081
9082sub setVirtFuncPositions($)
9083{
9084 my $LibVersion = $_[0];
9085 foreach my $ClassName (keys(%{$VirtualTable{$LibVersion}}))
9086 {
9087 my ($Num, $RelPos, $AbsNum) = (1, 0, 1);
9088 foreach my $VirtFunc (sort {int($CompleteSignature{$LibVersion}{$a}{"Line"}) <=> int($CompleteSignature{$LibVersion}{$b}{"Line"})}
9089 sort keys(%{$VirtualTable{$LibVersion}{$ClassName}}))
9090 {
Andrey Ponomarenko16934472012-03-29 15:37:04 +04009091 $VirtualTable{$LibVersion}{$ClassName}{$VirtFunc}=$Num++;
9092
9093 # set relative positions
9094 if(defined $VirtualTable{1}{$ClassName} and defined $VirtualTable{1}{$ClassName}{$VirtFunc}
9095 and defined $VirtualTable{2}{$ClassName} and defined $VirtualTable{2}{$ClassName}{$VirtFunc})
9096 { # relative position excluding added and removed virtual functions
9097 if(not $CompleteSignature{1}{$VirtFunc}{"Override"}
9098 and not $CompleteSignature{2}{$VirtFunc}{"Override"}) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009099 $CompleteSignature{$LibVersion}{$VirtFunc}{"RelPos"} = $RelPos++;
9100 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009101 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009102 }
9103 }
Andrey Ponomarenko16934472012-03-29 15:37:04 +04009104 foreach my $ClassName (keys(%{$ClassNames{$LibVersion}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009105 {
9106 my $AbsNum = 1;
Andrey Ponomarenko16934472012-03-29 15:37:04 +04009107 foreach my $VirtFunc (getVTable_Model($TName_Tid{$LibVersion}{$ClassName}, $LibVersion)) {
9108 $VirtualTable_Model{$LibVersion}{$ClassName}{$VirtFunc}=$AbsNum++;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009109 }
9110 }
9111}
9112
9113sub get_sub_classes($$$)
9114{
9115 my ($ClassId, $LibVersion, $Recursive) = @_;
9116 return () if(not defined $Class_SubClasses{$LibVersion}{$ClassId});
9117 my @Subs = ();
9118 foreach my $SubId (keys(%{$Class_SubClasses{$LibVersion}{$ClassId}}))
9119 {
Andrey Ponomarenko16934472012-03-29 15:37:04 +04009120 if($Recursive)
9121 {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009122 foreach my $SubSubId (get_sub_classes($SubId, $LibVersion, $Recursive)) {
9123 push(@Subs, $SubSubId);
9124 }
9125 }
9126 push(@Subs, $SubId);
9127 }
9128 return @Subs;
9129}
9130
9131sub get_base_classes($$$)
9132{
9133 my ($ClassId, $LibVersion, $Recursive) = @_;
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04009134 my %ClassType = get_Type($ClassId, $LibVersion);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009135 return () if(not defined $ClassType{"Base"});
9136 my @Bases = ();
9137 foreach my $BaseId (sort {int($ClassType{"Base"}{$a}{"pos"})<=>int($ClassType{"Base"}{$b}{"pos"})}
9138 keys(%{$ClassType{"Base"}}))
9139 {
Andrey Ponomarenko16934472012-03-29 15:37:04 +04009140 if($Recursive)
9141 {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009142 foreach my $SubBaseId (get_base_classes($BaseId, $LibVersion, $Recursive)) {
9143 push(@Bases, $SubBaseId);
9144 }
9145 }
9146 push(@Bases, $BaseId);
9147 }
9148 return @Bases;
9149}
9150
Andrey Ponomarenko16934472012-03-29 15:37:04 +04009151sub getVTable_Model($$)
9152{ # return an ordered list of v-table elements
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009153 my ($ClassId, $LibVersion) = @_;
9154 my @Bases = get_base_classes($ClassId, $LibVersion, 1);
9155 my @Elements = ();
9156 foreach my $BaseId (@Bases, $ClassId)
9157 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04009158 if(my $BName = $TypeInfo{$LibVersion}{$BaseId}{"Name"})
Andrey Ponomarenko85043792012-05-14 16:48:07 +04009159 {
9160 if(defined $VirtualTable{$LibVersion}{$BName})
9161 {
9162 my @VFunctions = keys(%{$VirtualTable{$LibVersion}{$BName}});
9163 @VFunctions = sort {int($CompleteSignature{$LibVersion}{$a}{"Line"}) <=> int($CompleteSignature{$LibVersion}{$b}{"Line"})} @VFunctions;
9164 foreach my $VFunc (@VFunctions) {
9165 push(@Elements, $VFunc);
9166 }
9167 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009168 }
9169 }
9170 return @Elements;
9171}
9172
9173sub getVShift($$)
9174{
9175 my ($ClassId, $LibVersion) = @_;
9176 my @Bases = get_base_classes($ClassId, $LibVersion, 1);
9177 my $VShift = 0;
9178 foreach my $BaseId (@Bases)
9179 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04009180 if(my $BName = $TypeInfo{$LibVersion}{$BaseId}{"Name"})
Andrey Ponomarenko85043792012-05-14 16:48:07 +04009181 {
9182 if(defined $VirtualTable{$LibVersion}{$BName}) {
9183 $VShift+=keys(%{$VirtualTable{$LibVersion}{$BName}});
9184 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009185 }
9186 }
9187 return $VShift;
9188}
9189
9190sub getShift($$)
9191{
9192 my ($ClassId, $LibVersion) = @_;
9193 my @Bases = get_base_classes($ClassId, $LibVersion, 0);
9194 my $Shift = 0;
9195 foreach my $BaseId (@Bases)
9196 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04009197 if(my $Size = $TypeInfo{$LibVersion}{$BaseId}{"Size"})
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04009198 {
9199 if($Size!=1)
9200 { # not empty base class
9201 $Shift+=$Size;
9202 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009203 }
9204 }
9205 return $Shift;
9206}
9207
Andrey Ponomarenko16934472012-03-29 15:37:04 +04009208sub getVTable_Size($$)
9209{ # number of v-table elements
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009210 my ($ClassName, $LibVersion) = @_;
Andrey Ponomarenko16934472012-03-29 15:37:04 +04009211 my $Size = 0;
9212 # three approaches
9213 if(not $Size)
9214 { # real size
9215 if(my %VTable = getVTable_Real($ClassName, $LibVersion)) {
9216 $Size = keys(%VTable);
9217 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009218 }
Andrey Ponomarenko16934472012-03-29 15:37:04 +04009219 if(not $Size)
9220 { # shared library symbol size
9221 if($Size = getSymbolSize($ClassVTable{$ClassName}, $LibVersion)) {
9222 $Size /= $WORD_SIZE{$LibVersion};
9223 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009224 }
Andrey Ponomarenko16934472012-03-29 15:37:04 +04009225 if(not $Size)
9226 { # model size
9227 if(defined $VirtualTable_Model{$LibVersion}{$ClassName}) {
9228 $Size = keys(%{$VirtualTable_Model{$LibVersion}{$ClassName}}) + 2;
9229 }
9230 }
9231 return $Size;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009232}
9233
9234sub isCopyingClass($$)
9235{
9236 my ($TypeId, $LibVersion) = @_;
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04009237 return $TypeInfo{$LibVersion}{$TypeId}{"Copied"};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009238}
9239
9240sub isLeafClass($$)
9241{
9242 my ($ClassId, $LibVersion) = @_;
9243 return (not keys(%{$Class_SubClasses{$LibVersion}{$ClassId}}));
9244}
9245
9246sub havePubFields($)
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04009247{ # check structured type for public fields
9248 return isAccessible($_[0], {}, 0, -1);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009249}
9250
9251sub isAccessible($$$$)
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04009252{ # check interval in structured type for public fields
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009253 my ($TypePtr, $Skip, $Start, $End) = @_;
9254 return 0 if(not $TypePtr);
9255 if($End==-1) {
9256 $End = keys(%{$TypePtr->{"Memb"}})-1;
9257 }
9258 foreach my $MemPos (keys(%{$TypePtr->{"Memb"}}))
9259 {
9260 if($Skip and $Skip->{$MemPos})
9261 { # skip removed/added fields
9262 next;
9263 }
9264 if(int($MemPos)>=$Start and int($MemPos)<=$End)
9265 {
9266 if(isPublic($TypePtr, $MemPos)) {
9267 return ($MemPos+1);
9268 }
9269 }
9270 }
9271 return 0;
9272}
9273
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009274sub isReserved($)
9275{ # reserved fields == private
9276 my $MName = $_[0];
9277 if($MName=~/reserved|padding|f_spare/i) {
9278 return 1;
9279 }
Andrey Ponomarenko9927e332012-10-19 10:50:48 +04009280 if($MName=~/\A[_]*(spare|pad|unused)[_\d]*\Z/i) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009281 return 1;
9282 }
9283 if($MName=~/(pad\d+)/i) {
9284 return 1;
9285 }
9286 return 0;
9287}
9288
9289sub isPublic($$)
9290{
9291 my ($TypePtr, $FieldPos) = @_;
9292 return 0 if(not $TypePtr);
9293 return 0 if(not defined $TypePtr->{"Memb"}{$FieldPos});
9294 return 0 if(not defined $TypePtr->{"Memb"}{$FieldPos}{"name"});
9295 if(not $TypePtr->{"Memb"}{$FieldPos}{"access"})
9296 { # by name in C language
9297 # FIXME: add other methods to detect private members
9298 my $MName = $TypePtr->{"Memb"}{$FieldPos}{"name"};
9299 if($MName=~/priv|abidata|parent_object/i)
9300 { # C-styled private data
9301 return 0;
9302 }
9303 if(lc($MName) eq "abi")
9304 { # ABI information/reserved field
9305 return 0;
9306 }
9307 if(isReserved($MName))
9308 { # reserved fields
9309 return 0;
9310 }
9311 return 1;
9312 }
9313 elsif($TypePtr->{"Memb"}{$FieldPos}{"access"} ne "private")
9314 { # by access in C++ language
9315 return 1;
9316 }
9317 return 0;
9318}
9319
Andrey Ponomarenko16934472012-03-29 15:37:04 +04009320sub getVTable_Real($$)
9321{
9322 my ($ClassName, $LibVersion) = @_;
9323 if(my $ClassId = $TName_Tid{$LibVersion}{$ClassName})
9324 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04009325 my %Type = get_Type($ClassId, $LibVersion);
Andrey Ponomarenko16934472012-03-29 15:37:04 +04009326 if(defined $Type{"VTable"}) {
9327 return %{$Type{"VTable"}};
9328 }
9329 }
9330 return ();
9331}
9332
9333sub cmpVTables($)
9334{
9335 my $ClassName = $_[0];
9336 my $Res = cmpVTables_Real($ClassName, 1);
9337 if($Res==-1) {
9338 $Res = cmpVTables_Model($ClassName);
9339 }
9340 return $Res;
9341}
9342
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009343sub cmpVTables_Model($)
9344{
9345 my $ClassName = $_[0];
Andrey Ponomarenko16934472012-03-29 15:37:04 +04009346 foreach my $Symbol (keys(%{$VirtualTable_Model{1}{$ClassName}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009347 {
Andrey Ponomarenko16934472012-03-29 15:37:04 +04009348 if(not defined $VirtualTable_Model{2}{$ClassName}{$Symbol}) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009349 return 1;
9350 }
9351 }
9352 return 0;
9353}
9354
Andrey Ponomarenko16934472012-03-29 15:37:04 +04009355sub cmpVTables_Real($$)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009356{
9357 my ($ClassName, $Strong) = @_;
Andrey Ponomarenko16934472012-03-29 15:37:04 +04009358 if(defined $Cache{"cmpVTables_Real"}{$Strong}{$ClassName}) {
9359 return $Cache{"cmpVTables_Real"}{$Strong}{$ClassName};
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04009360 }
Andrey Ponomarenko16934472012-03-29 15:37:04 +04009361 my %VTable_Old = getVTable_Real($ClassName, 1);
9362 my %VTable_New = getVTable_Real($ClassName, 2);
9363 if(not %VTable_Old or not %VTable_New)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009364 { # old ABI dumps
Andrey Ponomarenko16934472012-03-29 15:37:04 +04009365 return ($Cache{"cmpVTables_Real"}{$Strong}{$ClassName} = -1);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009366 }
Andrey Ponomarenko16934472012-03-29 15:37:04 +04009367 my %Indexes = map {$_=>1} (keys(%VTable_Old), keys(%VTable_New));
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009368 foreach my $Offset (sort {int($a)<=>int($b)} keys(%Indexes))
9369 {
Andrey Ponomarenko16934472012-03-29 15:37:04 +04009370 if(not defined $VTable_Old{$Offset})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009371 { # v-table v.1 < v-table v.2
Andrey Ponomarenko16934472012-03-29 15:37:04 +04009372 return ($Cache{"cmpVTables_Real"}{$Strong}{$ClassName} = $Strong);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009373 }
Andrey Ponomarenko16934472012-03-29 15:37:04 +04009374 my $Entry1 = $VTable_Old{$Offset};
9375 if(not defined $VTable_New{$Offset})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009376 { # v-table v.1 > v-table v.2
Andrey Ponomarenko16934472012-03-29 15:37:04 +04009377 return ($Cache{"cmpVTables_Real"}{$Strong}{$ClassName} = ($Strong or $Entry1!~/__cxa_pure_virtual/));
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009378 }
Andrey Ponomarenko16934472012-03-29 15:37:04 +04009379 my $Entry2 = $VTable_New{$Offset};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009380 $Entry1 = simpleVEntry($Entry1);
9381 $Entry2 = simpleVEntry($Entry2);
9382 if($Entry1 ne $Entry2)
9383 { # register as changed
9384 if($Entry1=~/::([^:]+)\Z/)
9385 {
9386 my $M1 = $1;
9387 if($Entry2=~/::([^:]+)\Z/)
9388 {
9389 my $M2 = $1;
9390 if($M1 eq $M2)
9391 { # overridden
9392 next;
9393 }
9394 }
9395 }
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04009396 if(differentDumps("G"))
9397 {
9398 if($Entry1=~/\A\-(0x|\d+)/ and $Entry2=~/\A\-(0x|\d+)/)
9399 {
9400 # GCC 4.6.1: -0x00000000000000010
9401 # GCC 4.7.0: -16
9402 next;
9403 }
9404 }
Andrey Ponomarenko16934472012-03-29 15:37:04 +04009405 return ($Cache{"cmpVTables_Real"}{$Strong}{$ClassName} = 1);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009406 }
9407 }
Andrey Ponomarenko16934472012-03-29 15:37:04 +04009408 return ($Cache{"cmpVTables_Real"}{$Strong}{$ClassName} = 0);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009409}
9410
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04009411sub mergeVTables($)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009412{ # merging v-tables without diagnostics
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04009413 my $Level = $_[0];
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009414 foreach my $ClassName (keys(%{$VirtualTable{1}}))
9415 {
Andrey Ponomarenko16934472012-03-29 15:37:04 +04009416 if($VTableChanged_M{$ClassName})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009417 { # already registered
9418 next;
9419 }
Andrey Ponomarenko16934472012-03-29 15:37:04 +04009420 if(cmpVTables_Real($ClassName, 0)==1)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009421 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04009422 my @Affected = (keys(%{$ClassMethods{$Level}{1}{$ClassName}}));
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009423 foreach my $Symbol (@Affected)
9424 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04009425 %{$CompatProblems{$Level}{$Symbol}{"Virtual_Table_Changed_Unknown"}{$ClassName}}=(
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009426 "Type_Name"=>$ClassName,
9427 "Type_Type"=>"Class",
9428 "Target"=>$ClassName);
9429 }
9430 }
9431 }
9432}
9433
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04009434sub mergeBases($)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009435{
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04009436 my $Level = $_[0];
Andrey Ponomarenko16934472012-03-29 15:37:04 +04009437 foreach my $ClassName (keys(%{$ClassNames{1}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009438 { # detect added and removed virtual functions
Andrey Ponomarenko16934472012-03-29 15:37:04 +04009439 my $ClassId = $TName_Tid{1}{$ClassName};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009440 next if(not $ClassId);
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04009441 if(defined $VirtualTable{2}{$ClassName})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009442 {
Andrey Ponomarenko16934472012-03-29 15:37:04 +04009443 foreach my $Symbol (keys(%{$VirtualTable{2}{$ClassName}}))
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04009444 {
Andrey Ponomarenko16934472012-03-29 15:37:04 +04009445 if($TName_Tid{1}{$ClassName}
9446 and not defined $VirtualTable{1}{$ClassName}{$Symbol})
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04009447 { # added to v-table
Andrey Ponomarenko16934472012-03-29 15:37:04 +04009448 if(defined $CompleteSignature{1}{$Symbol}
9449 and $CompleteSignature{1}{$Symbol}{"Virt"})
9450 { # override some method in v.1
9451 next;
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04009452 }
Andrey Ponomarenko16934472012-03-29 15:37:04 +04009453 $AddedInt_Virt{$Level}{$ClassName}{$Symbol} = 1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009454 }
9455 }
9456 }
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04009457 if(defined $VirtualTable{1}{$ClassName})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009458 {
Andrey Ponomarenko16934472012-03-29 15:37:04 +04009459 foreach my $Symbol (keys(%{$VirtualTable{1}{$ClassName}}))
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04009460 {
Andrey Ponomarenko16934472012-03-29 15:37:04 +04009461 if($TName_Tid{2}{$ClassName}
9462 and not defined $VirtualTable{2}{$ClassName}{$Symbol})
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04009463 { # removed from v-table
Andrey Ponomarenko16934472012-03-29 15:37:04 +04009464 if(defined $CompleteSignature{2}{$Symbol}
9465 and $CompleteSignature{2}{$Symbol}{"Virt"})
9466 { # override some method in v.2
9467 next;
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04009468 }
Andrey Ponomarenko16934472012-03-29 15:37:04 +04009469 $RemovedInt_Virt{$Level}{$ClassName}{$Symbol} = 1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009470 }
9471 }
9472 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04009473 if($Level eq "Binary")
9474 { # Binary-level
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04009475 my %Class_Type = get_Type($ClassId, 1);
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04009476 foreach my $AddedVFunc (keys(%{$AddedInt_Virt{$Level}{$ClassName}}))
9477 { # check replacements, including pure virtual methods
9478 my $AddedPos = $VirtualTable{2}{$ClassName}{$AddedVFunc};
9479 foreach my $RemovedVFunc (keys(%{$RemovedInt_Virt{$Level}{$ClassName}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009480 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04009481 my $RemovedPos = $VirtualTable{1}{$ClassName}{$RemovedVFunc};
9482 if($AddedPos==$RemovedPos)
9483 {
9484 $VirtualReplacement{$AddedVFunc} = $RemovedVFunc;
9485 $VirtualReplacement{$RemovedVFunc} = $AddedVFunc;
9486 last; # other methods will be reported as "added" or "removed"
9487 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009488 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04009489 if(my $RemovedVFunc = $VirtualReplacement{$AddedVFunc})
9490 {
9491 if(lc($AddedVFunc) eq lc($RemovedVFunc))
9492 { # skip: DomUi => DomUI parameter (Qt 4.2.3 to 4.3.0)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009493 next;
9494 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04009495 my $ProblemType = "Virtual_Replacement";
9496 my @Affected = ($RemovedVFunc);
9497 if($CompleteSignature{1}{$RemovedVFunc}{"PureVirt"})
9498 { # pure methods
9499 if(not isUsedClass($ClassId, 1, $Level))
9500 { # not a parameter of some exported method
9501 next;
9502 }
9503 $ProblemType = "Pure_Virtual_Replacement";
Andrey Ponomarenko9927e332012-10-19 10:50:48 +04009504
9505 # affected all methods (both virtual and non-virtual ones)
9506 @Affected = (keys(%{$ClassMethods{$Level}{1}{$ClassName}}));
9507 push(@Affected, keys(%{$OverriddenMethods{1}{$RemovedVFunc}}));
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009508 }
Andrey Ponomarenko9927e332012-10-19 10:50:48 +04009509 $VTableChanged_M{$ClassName}=1;
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04009510 foreach my $AffectedInt (@Affected)
9511 {
9512 if($CompleteSignature{1}{$AffectedInt}{"PureVirt"})
9513 { # affected exported methods only
9514 next;
9515 }
Andrey Ponomarenko9927e332012-10-19 10:50:48 +04009516 if(not symbolFilter($AffectedInt, 1, "Affected", $Level)) {
9517 next;
9518 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04009519 %{$CompatProblems{$Level}{$AffectedInt}{$ProblemType}{$tr_name{$AddedVFunc}}}=(
9520 "Type_Name"=>$Class_Type{"Name"},
9521 "Type_Type"=>"Class",
9522 "Target"=>get_Signature($AddedVFunc, 2),
9523 "Old_Value"=>get_Signature($RemovedVFunc, 1));
9524 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009525 }
9526 }
9527 }
9528 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04009529 if(not checkDump(1, "2.0")
9530 or not checkDump(2, "2.0"))
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04009531 { # support for old ABI dumps
Andrey Ponomarenko9927e332012-10-19 10:50:48 +04009532 # "Base" attribute introduced in ACC 1.22 (ABI dump 2.0 format)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009533 return;
9534 }
Andrey Ponomarenko16934472012-03-29 15:37:04 +04009535 foreach my $ClassName (sort keys(%{$ClassNames{1}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009536 {
Andrey Ponomarenko16934472012-03-29 15:37:04 +04009537 my $ClassId_Old = $TName_Tid{1}{$ClassName};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009538 next if(not $ClassId_Old);
9539 if(not isCreatable($ClassId_Old, 1))
9540 { # skip classes without public constructors (including auto-generated)
9541 # example: class has only a private exported or private inline constructor
9542 next;
9543 }
9544 if($ClassName=~/>/)
9545 { # skip affected template instances
9546 next;
9547 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04009548 my %Class_Old = get_Type($ClassId_Old, 1);
Andrey Ponomarenko16934472012-03-29 15:37:04 +04009549 my $ClassId_New = $TName_Tid{2}{$ClassName};
Andrey Ponomarenko85043792012-05-14 16:48:07 +04009550 if(not $ClassId_New) {
9551 next;
9552 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04009553 my %Class_New = get_Type($ClassId_New, 2);
Andrey Ponomarenko85043792012-05-14 16:48:07 +04009554 if($Class_New{"Type"}!~/Class|Struct/)
9555 { # became typedef
9556 if($Level eq "Binary") {
9557 next;
9558 }
9559 if($Level eq "Source")
9560 {
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +04009561 %Class_New = get_PureType($ClassId_New, $TypeInfo{2});
Andrey Ponomarenko85043792012-05-14 16:48:07 +04009562 if($Class_New{"Type"}!~/Class|Struct/) {
9563 next;
9564 }
9565 $ClassId_New = $Class_New{"Tid"};
9566 }
9567 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009568 my @Bases_Old = sort {$Class_Old{"Base"}{$a}{"pos"}<=>$Class_Old{"Base"}{$b}{"pos"}} keys(%{$Class_Old{"Base"}});
9569 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 +04009570
9571 my %Tr_Old = map {$TypeInfo{1}{$_}{"Name"} => uncover_typedefs($TypeInfo{1}{$_}{"Name"}, 1)} @Bases_Old;
9572 my %Tr_New = map {$TypeInfo{2}{$_}{"Name"} => uncover_typedefs($TypeInfo{2}{$_}{"Name"}, 2)} @Bases_New;
9573
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009574 my ($BNum1, $BNum2) = (1, 1);
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +04009575 my %BasePos_Old = map {$Tr_Old{$TypeInfo{1}{$_}{"Name"}} => $BNum1++} @Bases_Old;
9576 my %BasePos_New = map {$Tr_New{$TypeInfo{2}{$_}{"Name"}} => $BNum2++} @Bases_New;
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04009577 my %ShortBase_Old = map {get_ShortType($_, 1) => 1} @Bases_Old;
9578 my %ShortBase_New = map {get_ShortType($_, 2) => 1} @Bases_New;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009579 my $Shift_Old = getShift($ClassId_Old, 1);
9580 my $Shift_New = getShift($ClassId_New, 2);
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +04009581 my %BaseId_New = map {$Tr_New{$TypeInfo{2}{$_}{"Name"}} => $_} @Bases_New;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009582 my ($Added, $Removed) = (0, 0);
9583 my @StableBases_Old = ();
9584 foreach my $BaseId (@Bases_Old)
9585 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04009586 my $BaseName = $TypeInfo{1}{$BaseId}{"Name"};
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +04009587 if($BasePos_New{$Tr_Old{$BaseName}}) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009588 push(@StableBases_Old, $BaseId);
9589 }
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +04009590 elsif(not $ShortBase_New{$Tr_Old{$BaseName}}
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04009591 and not $ShortBase_New{get_ShortType($BaseId, 1)})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009592 { # removed base
9593 # excluding namespace::SomeClass to SomeClass renaming
9594 my $ProblemKind = "Removed_Base_Class";
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04009595 if($Level eq "Binary")
9596 { # Binary-level
9597 if($Shift_Old ne $Shift_New)
9598 { # affected fields
9599 if(havePubFields(\%Class_Old)) {
9600 $ProblemKind .= "_And_Shift";
9601 }
9602 elsif($Class_Old{"Size"} ne $Class_New{"Size"}) {
9603 $ProblemKind .= "_And_Size";
9604 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009605 }
Andrey Ponomarenko16934472012-03-29 15:37:04 +04009606 if(keys(%{$VirtualTable_Model{1}{$BaseName}})
9607 and cmpVTables($ClassName)==1)
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04009608 { # affected v-table
9609 $ProblemKind .= "_And_VTable";
Andrey Ponomarenko16934472012-03-29 15:37:04 +04009610 $VTableChanged_M{$ClassName}=1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009611 }
9612 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04009613 my @Affected = keys(%{$ClassMethods{$Level}{1}{$ClassName}});
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009614 foreach my $SubId (get_sub_classes($ClassId_Old, 1, 1))
9615 {
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +04009616 if(my $SubName = $TypeInfo{1}{$SubId}{"Name"})
9617 {
9618 push(@Affected, keys(%{$ClassMethods{$Level}{1}{$SubName}}));
9619 if($ProblemKind=~/VTable/) {
9620 $VTableChanged_M{$SubName}=1;
9621 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009622 }
9623 }
9624 foreach my $Interface (@Affected)
9625 {
Andrey Ponomarenko9927e332012-10-19 10:50:48 +04009626 if(not symbolFilter($Interface, 1, "Affected", $Level)) {
9627 next;
9628 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04009629 %{$CompatProblems{$Level}{$Interface}{$ProblemKind}{"this"}}=(
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009630 "Type_Name"=>$ClassName,
9631 "Type_Type"=>"Class",
9632 "Target"=>$BaseName,
9633 "Old_Size"=>$Class_Old{"Size"}*$BYTE_SIZE,
9634 "New_Size"=>$Class_New{"Size"}*$BYTE_SIZE,
9635 "Shift"=>abs($Shift_New-$Shift_Old) );
9636 }
9637 $Removed+=1;
9638 }
9639 }
9640 my @StableBases_New = ();
9641 foreach my $BaseId (@Bases_New)
9642 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04009643 my $BaseName = $TypeInfo{2}{$BaseId}{"Name"};
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +04009644 if($BasePos_Old{$Tr_New{$BaseName}}) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009645 push(@StableBases_New, $BaseId);
9646 }
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +04009647 elsif(not $ShortBase_Old{$Tr_New{$BaseName}}
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04009648 and not $ShortBase_Old{get_ShortType($BaseId, 2)})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009649 { # added base
9650 # excluding namespace::SomeClass to SomeClass renaming
9651 my $ProblemKind = "Added_Base_Class";
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04009652 if($Level eq "Binary")
9653 { # Binary-level
9654 if($Shift_Old ne $Shift_New)
9655 { # affected fields
9656 if(havePubFields(\%Class_Old)) {
9657 $ProblemKind .= "_And_Shift";
9658 }
9659 elsif($Class_Old{"Size"} ne $Class_New{"Size"}) {
9660 $ProblemKind .= "_And_Size";
9661 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009662 }
Andrey Ponomarenko16934472012-03-29 15:37:04 +04009663 if(keys(%{$VirtualTable_Model{2}{$BaseName}})
9664 and cmpVTables($ClassName)==1)
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04009665 { # affected v-table
9666 $ProblemKind .= "_And_VTable";
Andrey Ponomarenko16934472012-03-29 15:37:04 +04009667 $VTableChanged_M{$ClassName}=1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009668 }
9669 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04009670 my @Affected = keys(%{$ClassMethods{$Level}{1}{$ClassName}});
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009671 foreach my $SubId (get_sub_classes($ClassId_Old, 1, 1))
9672 {
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +04009673 if(my $SubName = $TypeInfo{1}{$SubId}{"Name"})
9674 {
9675 push(@Affected, keys(%{$ClassMethods{$Level}{1}{$SubName}}));
9676 if($ProblemKind=~/VTable/) {
9677 $VTableChanged_M{$SubName}=1;
9678 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009679 }
9680 }
9681 foreach my $Interface (@Affected)
9682 {
Andrey Ponomarenko9927e332012-10-19 10:50:48 +04009683 if(not symbolFilter($Interface, 1, "Affected", $Level)) {
9684 next;
9685 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04009686 %{$CompatProblems{$Level}{$Interface}{$ProblemKind}{"this"}}=(
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009687 "Type_Name"=>$ClassName,
9688 "Type_Type"=>"Class",
9689 "Target"=>$BaseName,
9690 "Old_Size"=>$Class_Old{"Size"}*$BYTE_SIZE,
9691 "New_Size"=>$Class_New{"Size"}*$BYTE_SIZE,
9692 "Shift"=>abs($Shift_New-$Shift_Old) );
9693 }
9694 $Added+=1;
9695 }
9696 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04009697 if($Level eq "Binary")
9698 { # Binary-level
9699 ($BNum1, $BNum2) = (1, 1);
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +04009700 my %BaseRelPos_Old = map {$Tr_Old{$TypeInfo{1}{$_}{"Name"}} => $BNum1++} @StableBases_Old;
9701 my %BaseRelPos_New = map {$Tr_New{$TypeInfo{2}{$_}{"Name"}} => $BNum2++} @StableBases_New;
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04009702 foreach my $BaseId (@Bases_Old)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009703 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04009704 my $BaseName = $TypeInfo{1}{$BaseId}{"Name"};
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +04009705 if(my $NewPos = $BaseRelPos_New{$Tr_Old{$BaseName}})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009706 {
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +04009707 my $BaseNewId = $BaseId_New{$Tr_Old{$BaseName}};
9708 my $OldPos = $BaseRelPos_Old{$Tr_Old{$BaseName}};
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04009709 if($NewPos!=$OldPos)
9710 { # changed position of the base class
9711 foreach my $Interface (keys(%{$ClassMethods{$Level}{1}{$ClassName}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009712 {
Andrey Ponomarenko9927e332012-10-19 10:50:48 +04009713 if(not symbolFilter($Interface, 1, "Affected", $Level)) {
9714 next;
9715 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04009716 %{$CompatProblems{$Level}{$Interface}{"Base_Class_Position"}{"this"}}=(
9717 "Type_Name"=>$ClassName,
9718 "Type_Type"=>"Class",
9719 "Target"=>$BaseName,
9720 "Old_Value"=>$OldPos-1,
9721 "New_Value"=>$NewPos-1 );
9722 }
9723 }
9724 if($Class_Old{"Base"}{$BaseId}{"virtual"}
9725 and not $Class_New{"Base"}{$BaseNewId}{"virtual"})
9726 { # became non-virtual base
9727 foreach my $Interface (keys(%{$ClassMethods{$Level}{1}{$ClassName}}))
9728 {
Andrey Ponomarenko9927e332012-10-19 10:50:48 +04009729 if(not symbolFilter($Interface, 1, "Affected", $Level)) {
9730 next;
9731 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04009732 %{$CompatProblems{$Level}{$Interface}{"Base_Class_Became_Non_Virtually_Inherited"}{"this->".$BaseName}}=(
9733 "Type_Name"=>$ClassName,
9734 "Type_Type"=>"Class",
9735 "Target"=>$BaseName );
9736 }
9737 }
9738 elsif(not $Class_Old{"Base"}{$BaseId}{"virtual"}
9739 and $Class_New{"Base"}{$BaseNewId}{"virtual"})
9740 { # became virtual base
9741 foreach my $Interface (keys(%{$ClassMethods{$Level}{1}{$ClassName}}))
9742 {
Andrey Ponomarenko9927e332012-10-19 10:50:48 +04009743 if(not symbolFilter($Interface, 1, "Affected", $Level)) {
9744 next;
9745 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04009746 %{$CompatProblems{$Level}{$Interface}{"Base_Class_Became_Virtually_Inherited"}{"this->".$BaseName}}=(
9747 "Type_Name"=>$ClassName,
9748 "Type_Type"=>"Class",
9749 "Target"=>$BaseName );
9750 }
9751 }
9752 }
9753 }
9754 # detect size changes in base classes
9755 if($Shift_Old!=$Shift_New)
9756 { # size of allocable class
9757 foreach my $BaseId (@StableBases_Old)
9758 { # search for changed base
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04009759 my %BaseType = get_Type($BaseId, 1);
9760 my $Size_Old = $TypeInfo{1}{$BaseId}{"Size"};
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +04009761 my $Size_New = $TypeInfo{2}{$BaseId_New{$Tr_Old{$BaseType{"Name"}}}}{"Size"};
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04009762 if($Size_Old ne $Size_New
9763 and $Size_Old and $Size_New)
9764 {
9765 my $ProblemType = "";
9766 if(isCopyingClass($BaseId, 1)) {
9767 $ProblemType = "Size_Of_Copying_Class";
9768 }
9769 elsif($AllocableClass{1}{$BaseType{"Name"}})
9770 {
9771 if($Size_New>$Size_Old)
9772 { # increased size
9773 $ProblemType = "Size_Of_Allocable_Class_Increased";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009774 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04009775 else
9776 { # decreased size
9777 $ProblemType = "Size_Of_Allocable_Class_Decreased";
9778 if(not havePubFields(\%Class_Old))
9779 { # affected class has no public members
9780 next;
9781 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009782 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04009783 }
9784 next if(not $ProblemType);
9785 foreach my $Interface (keys(%{$ClassMethods{$Level}{1}{$ClassName}}))
9786 { # base class size changes affecting current class
Andrey Ponomarenko9927e332012-10-19 10:50:48 +04009787 if(not symbolFilter($Interface, 1, "Affected", $Level)) {
9788 next;
9789 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04009790 %{$CompatProblems{$Level}{$Interface}{$ProblemType}{"this->".$BaseType{"Name"}}}=(
9791 "Type_Name"=>$BaseType{"Name"},
9792 "Type_Type"=>"Class",
9793 "Target"=>$BaseType{"Name"},
9794 "Old_Size"=>$Size_Old*$BYTE_SIZE,
9795 "New_Size"=>$Size_New*$BYTE_SIZE );
9796 }
9797 }
9798 }
9799 }
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +04009800 if(defined $VirtualTable_Model{1}{$ClassName}
Andrey Ponomarenko16934472012-03-29 15:37:04 +04009801 and cmpVTables_Real($ClassName, 1)==1
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +04009802 and my @VFunctions = keys(%{$VirtualTable_Model{1}{$ClassName}}))
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04009803 { # compare virtual tables size in base classes
9804 my $VShift_Old = getVShift($ClassId_Old, 1);
9805 my $VShift_New = getVShift($ClassId_New, 2);
9806 if($VShift_Old ne $VShift_New)
9807 { # changes in the base class or changes in the list of base classes
9808 my @AllBases_Old = get_base_classes($ClassId_Old, 1, 1);
9809 my @AllBases_New = get_base_classes($ClassId_New, 2, 1);
9810 ($BNum1, $BNum2) = (1, 1);
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +04009811 my %StableBase = map {$Tr_New{$TypeInfo{2}{$_}{"Name"}} => $_} @AllBases_New;
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04009812 foreach my $BaseId (@AllBases_Old)
9813 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04009814 my %BaseType = get_Type($BaseId, 1);
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +04009815 if(not $StableBase{$Tr_Old{$BaseType{"Name"}}})
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04009816 { # lost base
9817 next;
9818 }
Andrey Ponomarenko16934472012-03-29 15:37:04 +04009819 my $VSize_Old = getVTable_Size($BaseType{"Name"}, 1);
9820 my $VSize_New = getVTable_Size($BaseType{"Name"}, 2);
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04009821 if($VSize_Old!=$VSize_New)
9822 {
Andrey Ponomarenko85043792012-05-14 16:48:07 +04009823 foreach my $Symbol (@VFunctions)
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +04009824 { # TODO: affected non-virtual methods?
9825 if(not defined $VirtualTable_Model{2}{$ClassName}{$Symbol})
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04009826 { # Removed_Virtual_Method, will be registered in mergeVirtualTables()
9827 next;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009828 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +04009829 if($VirtualTable_Model{2}{$ClassName}{$Symbol}-$VirtualTable_Model{1}{$ClassName}{$Symbol}==0)
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04009830 { # skip interfaces that have not changed the absolute virtual position
9831 next;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009832 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +04009833 if(not symbolFilter($Symbol, 1, "Affected", $Level)) {
9834 next;
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04009835 }
Andrey Ponomarenko16934472012-03-29 15:37:04 +04009836 $VTableChanged_M{$BaseType{"Name"}} = 1;
9837 $VTableChanged_M{$ClassName} = 1;
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04009838 foreach my $VirtFunc (keys(%{$AddedInt_Virt{$Level}{$BaseType{"Name"}}}))
9839 { # the reason of the layout change: added virtual functions
9840 next if($VirtualReplacement{$VirtFunc});
9841 my $ProblemType = "Added_Virtual_Method";
9842 if($CompleteSignature{2}{$VirtFunc}{"PureVirt"}) {
9843 $ProblemType = "Added_Pure_Virtual_Method";
9844 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +04009845 %{$CompatProblems{$Level}{$Symbol}{$ProblemType}{get_Signature($VirtFunc, 2)}}=(
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04009846 "Type_Name"=>$BaseType{"Name"},
9847 "Type_Type"=>"Class",
9848 "Target"=>get_Signature($VirtFunc, 2) );
9849 }
9850 foreach my $VirtFunc (keys(%{$RemovedInt_Virt{$Level}{$BaseType{"Name"}}}))
9851 { # the reason of the layout change: removed virtual functions
9852 next if($VirtualReplacement{$VirtFunc});
9853 my $ProblemType = "Removed_Virtual_Method";
9854 if($CompleteSignature{1}{$VirtFunc}{"PureVirt"}) {
9855 $ProblemType = "Removed_Pure_Virtual_Method";
9856 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +04009857 %{$CompatProblems{$Level}{$Symbol}{$ProblemType}{get_Signature($VirtFunc, 1)}}=(
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04009858 "Type_Name"=>$BaseType{"Name"},
9859 "Type_Type"=>"Class",
9860 "Target"=>get_Signature($VirtFunc, 1) );
9861 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009862 }
9863 }
9864 }
9865 }
9866 }
9867 }
9868 }
9869}
9870
9871sub isCreatable($$)
9872{
9873 my ($ClassId, $LibVersion) = @_;
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04009874 if($AllocableClass{$LibVersion}{$TypeInfo{$LibVersion}{$ClassId}{"Name"}}
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009875 or isCopyingClass($ClassId, $LibVersion)) {
9876 return 1;
9877 }
9878 if(keys(%{$Class_SubClasses{$LibVersion}{$ClassId}}))
9879 { # Fix for incomplete data: if this class has
9880 # a base class then it should also has a constructor
9881 return 1;
9882 }
9883 if($ReturnedClass{$LibVersion}{$ClassId})
9884 { # returned by some method of this class
9885 # or any other class
9886 return 1;
9887 }
9888 return 0;
9889}
9890
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04009891sub isUsedClass($$$)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009892{
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04009893 my ($ClassId, $LibVersion, $Level) = @_;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009894 if(keys(%{$ParamClass{$LibVersion}{$ClassId}}))
9895 { # parameter of some exported method
9896 return 1;
9897 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04009898 my $CName = $TypeInfo{$LibVersion}{$ClassId}{"Name"};
9899 if(keys(%{$ClassMethods{$Level}{$LibVersion}{$CName}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009900 { # method from target class
9901 return 1;
9902 }
9903 return 0;
9904}
9905
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04009906sub mergeVirtualTables($$)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009907{ # check for changes in the virtual table
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04009908 my ($Interface, $Level) = @_;
Andrey Ponomarenko16934472012-03-29 15:37:04 +04009909 # affected methods:
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009910 # - virtual
9911 # - pure-virtual
9912 # - non-virtual
9913 if($CompleteSignature{1}{$Interface}{"Data"})
9914 { # global data is not affected
9915 return;
9916 }
9917 my $Class_Id = $CompleteSignature{1}{$Interface}{"Class"};
Andrey Ponomarenko16934472012-03-29 15:37:04 +04009918 if(not $Class_Id) {
9919 return;
9920 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04009921 my $CName = $TypeInfo{1}{$Class_Id}{"Name"};
Andrey Ponomarenko16934472012-03-29 15:37:04 +04009922 if(cmpVTables_Real($CName, 1)==0)
9923 { # no changes
9924 return;
9925 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04009926 $CheckedTypes{$Level}{$CName} = 1;
9927 if($Level eq "Binary")
9928 { # Binary-level
9929 if($CompleteSignature{1}{$Interface}{"PureVirt"}
9930 and not isUsedClass($Class_Id, 1, $Level))
9931 { # pure virtuals should not be affected
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04009932 # if there are no exported methods using this class
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04009933 return;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009934 }
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04009935 }
9936 foreach my $Func (keys(%{$VirtualTable{1}{$CName}}))
9937 {
9938 if(defined $VirtualTable{2}{$CName}{$Func}
9939 and defined $CompleteSignature{2}{$Func})
9940 {
9941 if(not $CompleteSignature{1}{$Func}{"PureVirt"}
9942 and $CompleteSignature{2}{$Func}{"PureVirt"})
9943 { # became pure virtual
9944 %{$CompatProblems{$Level}{$Interface}{"Virtual_Method_Became_Pure"}{$tr_name{$Func}}}=(
9945 "Type_Name"=>$CName,
9946 "Type_Type"=>"Class",
9947 "Target"=>get_Signature_M($Func, 1) );
9948 $VTableChanged_M{$CName} = 1;
9949 }
9950 elsif($CompleteSignature{1}{$Func}{"PureVirt"}
9951 and not $CompleteSignature{2}{$Func}{"PureVirt"})
9952 { # became non-pure virtual
9953 %{$CompatProblems{$Level}{$Interface}{"Virtual_Method_Became_Non_Pure"}{$tr_name{$Func}}}=(
9954 "Type_Name"=>$CName,
9955 "Type_Type"=>"Class",
9956 "Target"=>get_Signature_M($Func, 1) );
9957 $VTableChanged_M{$CName} = 1;
9958 }
9959 }
9960 }
9961 if($Level eq "Binary")
9962 { # Binary-level
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04009963 # check virtual table structure
9964 foreach my $AddedVFunc (keys(%{$AddedInt_Virt{$Level}{$CName}}))
9965 {
9966 next if($Interface eq $AddedVFunc);
9967 next if($VirtualReplacement{$AddedVFunc});
9968 my $VPos_Added = $VirtualTable{2}{$CName}{$AddedVFunc};
9969 if($CompleteSignature{2}{$AddedVFunc}{"PureVirt"})
9970 { # pure virtual methods affect all others (virtual and non-virtual)
9971 %{$CompatProblems{$Level}{$Interface}{"Added_Pure_Virtual_Method"}{$tr_name{$AddedVFunc}}}=(
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009972 "Type_Name"=>$CName,
9973 "Type_Type"=>"Class",
9974 "Target"=>get_Signature($AddedVFunc, 2) );
Andrey Ponomarenko16934472012-03-29 15:37:04 +04009975 $VTableChanged_M{$CName} = 1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009976 }
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04009977 elsif(not defined $VirtualTable{1}{$CName}
9978 or $VPos_Added>keys(%{$VirtualTable{1}{$CName}}))
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04009979 { # added virtual function at the end of v-table
Andrey Ponomarenko16934472012-03-29 15:37:04 +04009980 if(not keys(%{$VirtualTable_Model{1}{$CName}}))
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04009981 { # became polymorphous class, added v-table pointer
9982 %{$CompatProblems{$Level}{$Interface}{"Added_First_Virtual_Method"}{$tr_name{$AddedVFunc}}}=(
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009983 "Type_Name"=>$CName,
9984 "Type_Type"=>"Class",
9985 "Target"=>get_Signature($AddedVFunc, 2) );
Andrey Ponomarenko16934472012-03-29 15:37:04 +04009986 $VTableChanged_M{$CName} = 1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009987 }
9988 else
9989 {
Andrey Ponomarenko16934472012-03-29 15:37:04 +04009990 my $VSize_Old = getVTable_Size($CName, 1);
9991 my $VSize_New = getVTable_Size($CName, 2);
Andrey Ponomarenko9927e332012-10-19 10:50:48 +04009992 next if($VSize_Old==$VSize_New); # exception: register as removed and added virtual method
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04009993 if(isCopyingClass($Class_Id, 1))
9994 { # class has no constructors and v-table will be copied by applications, this may affect all methods
9995 my $ProblemType = "Added_Virtual_Method";
9996 if(isLeafClass($Class_Id, 1)) {
9997 $ProblemType = "Added_Virtual_Method_At_End_Of_Leaf_Copying_Class";
9998 }
9999 %{$CompatProblems{$Level}{$Interface}{$ProblemType}{$tr_name{$AddedVFunc}}}=(
10000 "Type_Name"=>$CName,
10001 "Type_Type"=>"Class",
10002 "Target"=>get_Signature($AddedVFunc, 2) );
Andrey Ponomarenko16934472012-03-29 15:37:04 +040010003 $VTableChanged_M{$CName} = 1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010004 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040010005 else
10006 {
10007 my $ProblemType = "Added_Virtual_Method";
10008 if(isLeafClass($Class_Id, 1)) {
10009 $ProblemType = "Added_Virtual_Method_At_End_Of_Leaf_Allocable_Class";
10010 }
10011 %{$CompatProblems{$Level}{$Interface}{$ProblemType}{$tr_name{$AddedVFunc}}}=(
10012 "Type_Name"=>$CName,
10013 "Type_Type"=>"Class",
10014 "Target"=>get_Signature($AddedVFunc, 2) );
Andrey Ponomarenko16934472012-03-29 15:37:04 +040010015 $VTableChanged_M{$CName} = 1;
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040010016 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010017 }
10018 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040010019 elsif($CompleteSignature{1}{$Interface}{"Virt"}
10020 or $CompleteSignature{1}{$Interface}{"PureVirt"})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010021 {
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040010022 if(defined $VirtualTable{1}{$CName}
10023 and defined $VirtualTable{2}{$CName})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010024 {
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040010025 my $VPos_Old = $VirtualTable{1}{$CName}{$Interface};
10026 my $VPos_New = $VirtualTable{2}{$CName}{$Interface};
10027 if($VPos_Added<=$VPos_Old and $VPos_Old!=$VPos_New)
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040010028 {
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040010029 my @Affected = ($Interface, keys(%{$OverriddenMethods{1}{$Interface}}));
10030 foreach my $ASymbol (@Affected)
10031 {
Andrey Ponomarenko85043792012-05-14 16:48:07 +040010032 if(not $CompleteSignature{1}{$ASymbol}{"PureVirt"})
10033 {
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040010034 if(not symbolFilter($ASymbol, 1, "Affected", $Level)) {
Andrey Ponomarenko85043792012-05-14 16:48:07 +040010035 next;
10036 }
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040010037 }
10038 $CheckedSymbols{$Level}{$ASymbol} = 1;
10039 %{$CompatProblems{$Level}{$ASymbol}{"Added_Virtual_Method"}{$tr_name{$AddedVFunc}}}=(
10040 "Type_Name"=>$CName,
10041 "Type_Type"=>"Class",
10042 "Target"=>get_Signature($AddedVFunc, 2) );
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040010043 $VTableChanged_M{$TypeInfo{1}{$CompleteSignature{1}{$ASymbol}{"Class"}}{"Name"}} = 1;
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040010044 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010045 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010046 }
10047 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040010048 else {
10049 # safe
10050 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010051 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040010052 foreach my $RemovedVFunc (keys(%{$RemovedInt_Virt{$Level}{$CName}}))
10053 {
10054 next if($VirtualReplacement{$RemovedVFunc});
10055 if($RemovedVFunc eq $Interface
10056 and $CompleteSignature{1}{$RemovedVFunc}{"PureVirt"})
10057 { # This case is for removed virtual methods
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040010058 # implemented in both versions of a library
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040010059 next;
10060 }
Andrey Ponomarenko16934472012-03-29 15:37:04 +040010061 if(not keys(%{$VirtualTable_Model{2}{$CName}}))
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040010062 { # became non-polymorphous class, removed v-table pointer
10063 %{$CompatProblems{$Level}{$Interface}{"Removed_Last_Virtual_Method"}{$tr_name{$RemovedVFunc}}}=(
10064 "Type_Name"=>$CName,
10065 "Type_Type"=>"Class",
10066 "Target"=>get_Signature($RemovedVFunc, 1) );
Andrey Ponomarenko16934472012-03-29 15:37:04 +040010067 $VTableChanged_M{$CName} = 1;
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040010068 }
10069 elsif($CompleteSignature{1}{$Interface}{"Virt"}
10070 or $CompleteSignature{1}{$Interface}{"PureVirt"})
10071 {
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040010072 if(defined $VirtualTable{1}{$CName} and defined $VirtualTable{2}{$CName})
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040010073 {
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040010074 if(not defined $VirtualTable{1}{$CName}{$Interface}) {
10075 next;
10076 }
10077 my $VPos_New = -1;
10078 if(defined $VirtualTable{2}{$CName}{$Interface})
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040010079 {
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040010080 $VPos_New = $VirtualTable{2}{$CName}{$Interface};
10081 }
10082 else
10083 {
10084 if($Interface ne $RemovedVFunc) {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040010085 next;
10086 }
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040010087 }
10088 my $VPos_Removed = $VirtualTable{1}{$CName}{$RemovedVFunc};
10089 my $VPos_Old = $VirtualTable{1}{$CName}{$Interface};
10090 if($VPos_Removed<=$VPos_Old and $VPos_Old!=$VPos_New)
10091 {
10092 my @Affected = ($Interface, keys(%{$OverriddenMethods{1}{$Interface}}));
10093 foreach my $ASymbol (@Affected)
10094 {
Andrey Ponomarenko85043792012-05-14 16:48:07 +040010095 if(not $CompleteSignature{1}{$ASymbol}{"PureVirt"})
10096 {
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040010097 if(not symbolFilter($ASymbol, 1, "Affected", $Level)) {
Andrey Ponomarenko85043792012-05-14 16:48:07 +040010098 next;
10099 }
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040010100 }
10101 my $ProblemType = "Removed_Virtual_Method";
10102 if($CompleteSignature{1}{$RemovedVFunc}{"PureVirt"}) {
10103 $ProblemType = "Removed_Pure_Virtual_Method";
10104 }
10105 $CheckedSymbols{$Level}{$ASymbol} = 1;
10106 %{$CompatProblems{$Level}{$ASymbol}{$ProblemType}{$tr_name{$RemovedVFunc}}}=(
10107 "Type_Name"=>$CName,
10108 "Type_Type"=>"Class",
10109 "Target"=>get_Signature($RemovedVFunc, 1) );
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040010110 $VTableChanged_M{$TypeInfo{1}{$CompleteSignature{1}{$ASymbol}{"Class"}}{"Name"}} = 1;
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040010111 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040010112 }
10113 }
10114 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010115 }
10116 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040010117 else
10118 { # Source-level
10119 foreach my $AddedVFunc (keys(%{$AddedInt_Virt{$Level}{$CName}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010120 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040010121 next if($Interface eq $AddedVFunc);
10122 if($CompleteSignature{2}{$AddedVFunc}{"PureVirt"})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010123 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040010124 %{$CompatProblems{$Level}{$Interface}{"Added_Pure_Virtual_Method"}{$tr_name{$AddedVFunc}}}=(
10125 "Type_Name"=>$CName,
10126 "Type_Type"=>"Class",
10127 "Target"=>get_Signature($AddedVFunc, 2) );
10128 }
10129 }
10130 foreach my $RemovedVFunc (keys(%{$RemovedInt_Virt{$Level}{$CName}}))
10131 {
10132 if($CompleteSignature{1}{$RemovedVFunc}{"PureVirt"})
10133 {
10134 %{$CompatProblems{$Level}{$Interface}{"Removed_Pure_Virtual_Method"}{$tr_name{$RemovedVFunc}}}=(
10135 "Type_Name"=>$CName,
10136 "Type_Type"=>"Class",
10137 "Target"=>get_Signature($RemovedVFunc, 1) );
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010138 }
10139 }
10140 }
10141}
10142
10143sub find_MemberPair_Pos_byName($$)
10144{
10145 my ($Member_Name, $Pair_Type) = @_;
10146 $Member_Name=~s/\A[_]+|[_]+\Z//g;
10147 foreach my $MemberPair_Pos (sort {int($a)<=>int($b)} keys(%{$Pair_Type->{"Memb"}}))
10148 {
10149 if(defined $Pair_Type->{"Memb"}{$MemberPair_Pos})
10150 {
10151 my $Name = $Pair_Type->{"Memb"}{$MemberPair_Pos}{"name"};
10152 $Name=~s/\A[_]+|[_]+\Z//g;
10153 if($Name eq $Member_Name) {
10154 return $MemberPair_Pos;
10155 }
10156 }
10157 }
10158 return "lost";
10159}
10160
10161sub find_MemberPair_Pos_byVal($$)
10162{
10163 my ($Member_Value, $Pair_Type) = @_;
10164 foreach my $MemberPair_Pos (sort {int($a)<=>int($b)} keys(%{$Pair_Type->{"Memb"}}))
10165 {
10166 if(defined $Pair_Type->{"Memb"}{$MemberPair_Pos}
10167 and $Pair_Type->{"Memb"}{$MemberPair_Pos}{"value"} eq $Member_Value) {
10168 return $MemberPair_Pos;
10169 }
10170 }
10171 return "lost";
10172}
10173
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040010174my %Severity_Val=(
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010175 "High"=>3,
10176 "Medium"=>2,
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040010177 "Low"=>1,
10178 "Safe"=>-1
10179);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010180
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040010181sub maxSeverity($$)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010182{
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040010183 my ($S1, $S2) = @_;
10184 if(cmpSeverities($S1, $S2)) {
10185 return $S1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010186 }
10187 else {
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040010188 return $S2;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010189 }
10190}
10191
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040010192sub cmpSeverities($$)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010193{
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040010194 my ($S1, $S2) = @_;
10195 if(not $S1) {
10196 return 0;
10197 }
10198 elsif(not $S2) {
10199 return 1;
10200 }
10201 return ($Severity_Val{$S1}>$Severity_Val{$S2});
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010202}
10203
10204sub getProblemSeverity($$)
10205{
10206 my ($Level, $Kind) = @_;
10207 return $CompatRules{$Level}{$Kind}{"Severity"};
10208}
10209
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040010210sub isRecurType($$)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010211{
10212 foreach (@RecurTypes)
10213 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040010214 if( $_->{"T1"} eq $_[0]
10215 and $_->{"T2"} eq $_[1] )
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010216 {
10217 return 1;
10218 }
10219 }
10220 return 0;
10221}
10222
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040010223sub pushType($$)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010224{
10225 my %TypeIDs=(
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040010226 "T1" => $_[0], #Tid1
10227 "T2" => $_[1] #Tid2
Andrey Ponomarenko16934472012-03-29 15:37:04 +040010228 );
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010229 push(@RecurTypes, \%TypeIDs);
10230}
10231
10232sub isRenamed($$$$$)
10233{
10234 my ($MemPos, $Type1, $LVersion1, $Type2, $LVersion2) = @_;
10235 my $Member_Name = $Type1->{"Memb"}{$MemPos}{"name"};
10236 my $MemberType_Id = $Type1->{"Memb"}{$MemPos}{"type"};
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +040010237 my %MemberType_Pure = get_PureType($MemberType_Id, $TypeInfo{$LVersion1});
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010238 if(not defined $Type2->{"Memb"}{$MemPos}) {
10239 return "";
10240 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040010241 my $PairType_Id = $Type2->{"Memb"}{$MemPos}{"type"};
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +040010242 my %PairType_Pure = get_PureType($PairType_Id, $TypeInfo{$LVersion2});
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010243
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040010244 my $Pair_Name = $Type2->{"Memb"}{$MemPos}{"name"};
10245 my $MemberPair_Pos_Rev = ($Member_Name eq $Pair_Name)?$MemPos:find_MemberPair_Pos_byName($Pair_Name, $Type1);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010246 if($MemberPair_Pos_Rev eq "lost")
10247 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040010248 if($MemberType_Pure{"Name"} eq $PairType_Pure{"Name"})
10249 { # base type match
10250 return $Pair_Name;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010251 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040010252 if($TypeInfo{$LVersion1}{$MemberType_Id}{"Name"} eq $TypeInfo{$LVersion2}{$PairType_Id}{"Name"})
10253 { # exact type match
10254 return $Pair_Name;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010255 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040010256 if($MemberType_Pure{"Size"} eq $PairType_Pure{"Size"})
10257 { # size match
10258 return $Pair_Name;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010259 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040010260 if(isReserved($Pair_Name))
10261 { # reserved fields
10262 return $Pair_Name;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010263 }
10264 }
10265 return "";
10266}
10267
10268sub isLastElem($$)
10269{
10270 my ($Pos, $TypeRef) = @_;
10271 my $Name = $TypeRef->{"Memb"}{$Pos}{"name"};
10272 if($Name=~/last|count|max|total/i)
10273 { # GST_LEVEL_COUNT, GST_RTSP_ELAST
10274 return 1;
10275 }
10276 elsif($Name=~/END|NLIMITS\Z/)
10277 { # __RLIMIT_NLIMITS
10278 return 1;
10279 }
10280 elsif($Name=~/\AN[A-Z](.+)[a-z]+s\Z/
10281 and $Pos+1==keys(%{$TypeRef->{"Memb"}}))
10282 { # NImageFormats, NColorRoles
10283 return 1;
10284 }
10285 return 0;
10286}
10287
10288sub nonComparable($$)
10289{
10290 my ($T1, $T2) = @_;
10291 if($T1->{"Name"} ne $T2->{"Name"}
10292 and not isAnon($T1->{"Name"})
10293 and not isAnon($T2->{"Name"}))
10294 { # different names
10295 if($T1->{"Type"} ne "Pointer"
10296 or $T2->{"Type"} ne "Pointer")
10297 { # compare base types
10298 return 1;
10299 }
10300 if($T1->{"Name"}!~/\Avoid\s*\*/
10301 and $T2->{"Name"}=~/\Avoid\s*\*/)
10302 {
10303 return 1;
10304 }
10305 }
10306 elsif($T1->{"Type"} ne $T2->{"Type"})
10307 { # different types
10308 if($T1->{"Type"} eq "Class"
10309 and $T2->{"Type"} eq "Struct")
10310 { # "class" to "struct"
10311 return 0;
10312 }
10313 elsif($T2->{"Type"} eq "Class"
10314 and $T1->{"Type"} eq "Struct")
10315 { # "struct" to "class"
10316 return 0;
10317 }
10318 else
10319 { # "class" to "enum"
10320 # "union" to "class"
10321 # ...
10322 return 1;
10323 }
10324 }
10325 return 0;
10326}
10327
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040010328sub mergeTypes($$$)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010329{
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040010330 my ($Type1_Id, $Type2_Id, $Level) = @_;
10331 return () if(not $Type1_Id or not $Type2_Id);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010332 my (%Sub_SubProblems, %SubProblems) = ();
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040010333 if($Cache{"mergeTypes"}{$Level}{$Type1_Id}{$Type2_Id})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010334 { # already merged
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040010335 return %{$Cache{"mergeTypes"}{$Level}{$Type1_Id}{$Type2_Id}};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010336 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040010337 my %Type1 = get_Type($Type1_Id, 1);
10338 my %Type2 = get_Type($Type2_Id, 2);
Andrey Ponomarenko16934472012-03-29 15:37:04 +040010339 if(not $Type1{"Name"} or not $Type2{"Name"}) {
10340 return ();
10341 }
10342 $CheckedTypes{$Level}{$Type1{"Name"}}=1;
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +040010343 my %Type1_Pure = get_PureType($Type1_Id, $TypeInfo{1});
10344 my %Type2_Pure = get_PureType($Type2_Id, $TypeInfo{2});
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040010345 $CheckedTypes{$Level}{$Type1_Pure{"Name"}}=1;
Andrey Ponomarenko85043792012-05-14 16:48:07 +040010346 if(not $Type1_Pure{"Size"} or not $Type2_Pure{"Size"})
10347 { # including a case when "class Class { ... };" changed to "class Class;"
10348 return ();
10349 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040010350 if(isRecurType($Type1_Pure{"Tid"}, $Type2_Pure{"Tid"}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010351 { # skip recursive declarations
10352 return ();
10353 }
10354 return () if(not $Type1_Pure{"Name"} or not $Type2_Pure{"Name"});
10355 return () if($SkipTypes{1}{$Type1_Pure{"Name"}});
10356 return () if($SkipTypes{1}{$Type1{"Name"}});
10357
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040010358 my %Typedef_1 = goToFirst($Type1{"Tid"}, 1, "Typedef");
10359 my %Typedef_2 = goToFirst($Type2{"Tid"}, 2, "Typedef");
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040010360 if(not $UseOldDumps and %Typedef_1 and %Typedef_2
10361 and $Typedef_1{"Type"} eq "Typedef" and $Typedef_2{"Type"} eq "Typedef"
10362 and $Typedef_1{"Name"} eq $Typedef_2{"Name"})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010363 {
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +040010364 my %Base_1 = get_OneStep_BaseType($Typedef_1{"Tid"}, $TypeInfo{1});
10365 my %Base_2 = get_OneStep_BaseType($Typedef_2{"Tid"}, $TypeInfo{2});
Andrey Ponomarenko85043792012-05-14 16:48:07 +040010366 if($Base_1{"Name"} ne $Base_2{"Name"})
10367 {
10368 if(differentDumps("G")
10369 or differentDumps("V"))
10370 { # different GCC versions or different dumps
10371 $Base_1{"Name"} = uncover_typedefs($Base_1{"Name"}, 1);
10372 $Base_2{"Name"} = uncover_typedefs($Base_2{"Name"}, 2);
10373 # std::__va_list and __va_list
10374 $Base_1{"Name"}=~s/\A(\w+::)+//;
10375 $Base_2{"Name"}=~s/\A(\w+::)+//;
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040010376 $Base_1{"Name"} = formatName($Base_1{"Name"}, "T");
10377 $Base_2{"Name"} = formatName($Base_2{"Name"}, "T");
Andrey Ponomarenko85043792012-05-14 16:48:07 +040010378 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010379 }
10380 if($Base_1{"Name"}!~/anon\-/ and $Base_2{"Name"}!~/anon\-/
10381 and $Base_1{"Name"} ne $Base_2{"Name"})
10382 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040010383 if($Level eq "Binary"
10384 and $Type1{"Size"} ne $Type2{"Size"})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010385 {
10386 %{$SubProblems{"DataType_Size"}{$Typedef_1{"Name"}}}=(
10387 "Target"=>$Typedef_1{"Name"},
10388 "Type_Name"=>$Typedef_1{"Name"},
10389 "Type_Type"=>"Typedef",
10390 "Old_Size"=>$Type1{"Size"}*$BYTE_SIZE,
10391 "New_Size"=>$Type2{"Size"}*$BYTE_SIZE );
10392 }
10393 %{$SubProblems{"Typedef_BaseType"}{$Typedef_1{"Name"}}}=(
10394 "Target"=>$Typedef_1{"Name"},
10395 "Type_Name"=>$Typedef_1{"Name"},
10396 "Type_Type"=>"Typedef",
10397 "Old_Value"=>$Base_1{"Name"},
10398 "New_Value"=>$Base_2{"Name"} );
10399 }
10400 }
10401 if(nonComparable(\%Type1_Pure, \%Type2_Pure))
10402 { # different types (reported in detectTypeChange(...))
10403 if($Type1_Pure{"Name"} eq $Type2_Pure{"Name"}
10404 and $Type1_Pure{"Type"} ne $Type2_Pure{"Type"}
10405 and $Type1_Pure{"Type"}!~/Intrinsic|Pointer|Ref|Typedef/)
10406 { # different type of the type
10407 %{$SubProblems{"DataType_Type"}{$Type1_Pure{"Name"}}}=(
10408 "Target"=>$Type1_Pure{"Name"},
10409 "Type_Name"=>$Type1_Pure{"Name"},
10410 "Type_Type"=>$Type1_Pure{"Type"},
10411 "Old_Value"=>lc($Type1_Pure{"Type"}),
10412 "New_Value"=>lc($Type2_Pure{"Type"}) );
10413 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040010414 %{$Cache{"mergeTypes"}{$Level}{$Type1_Id}{$Type2_Id}} = %SubProblems;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010415 return %SubProblems;
10416 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040010417 pushType($Type1_Pure{"Tid"}, $Type2_Pure{"Tid"});
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010418 if(($Type1_Pure{"Name"} eq $Type2_Pure{"Name"}
10419 or (isAnon($Type1_Pure{"Name"}) and isAnon($Type2_Pure{"Name"})))
10420 and $Type1_Pure{"Type"}=~/\A(Struct|Class|Union)\Z/)
10421 { # checking size
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040010422 if($Level eq "Binary"
10423 and $Type1_Pure{"Size"} ne $Type2_Pure{"Size"})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010424 {
10425 my $ProblemKind = "DataType_Size";
10426 if($Type1_Pure{"Type"} eq "Class"
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040010427 and keys(%{$ClassMethods{$Level}{1}{$Type1_Pure{"Name"}}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010428 {
10429 if(isCopyingClass($Type1_Pure{"Tid"}, 1)) {
10430 $ProblemKind = "Size_Of_Copying_Class";
10431 }
10432 elsif($AllocableClass{1}{$Type1_Pure{"Name"}})
10433 {
10434 if(int($Type2_Pure{"Size"})>int($Type1_Pure{"Size"})) {
10435 $ProblemKind = "Size_Of_Allocable_Class_Increased";
10436 }
10437 else {
10438 # descreased size of allocable class
10439 # it has no special effects
10440 }
10441 }
10442 }
10443 %{$SubProblems{$ProblemKind}{$Type1_Pure{"Name"}}}=(
10444 "Target"=>$Type1_Pure{"Name"},
10445 "Type_Name"=>$Type1_Pure{"Name"},
10446 "Type_Type"=>$Type1_Pure{"Type"},
10447 "Old_Size"=>$Type1_Pure{"Size"}*$BYTE_SIZE,
10448 "New_Size"=>$Type2_Pure{"Size"}*$BYTE_SIZE,
10449 "InitialType_Type"=>$Type1_Pure{"Type"} );
10450 }
10451 }
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040010452 if(defined $Type1_Pure{"BaseType"} and $Type1_Pure{"BaseType"}{"Tid"}
10453 and defined $Type2_Pure{"BaseType"} and $Type2_Pure{"BaseType"}{"Tid"})
10454 { # checking base types
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040010455 %Sub_SubProblems = mergeTypes($Type1_Pure{"BaseType"}{"Tid"}, $Type2_Pure{"BaseType"}{"Tid"}, $Level);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010456 foreach my $Sub_SubProblemType (keys(%Sub_SubProblems))
10457 {
10458 foreach my $Sub_SubLocation (keys(%{$Sub_SubProblems{$Sub_SubProblemType}}))
10459 {
10460 foreach my $Attr (keys(%{$Sub_SubProblems{$Sub_SubProblemType}{$Sub_SubLocation}})) {
10461 $SubProblems{$Sub_SubProblemType}{$Sub_SubLocation}{$Attr} = $Sub_SubProblems{$Sub_SubProblemType}{$Sub_SubLocation}{$Attr};
10462 }
10463 $SubProblems{$Sub_SubProblemType}{$Sub_SubLocation}{"InitialType_Type"} = $Type1_Pure{"Type"};
10464 }
10465 }
10466 }
10467 my (%AddedField, %RemovedField, %RenamedField, %RenamedField_Rev, %RelatedField, %RelatedField_Rev) = ();
10468 my %NameToPosA = map {$Type1_Pure{"Memb"}{$_}{"name"}=>$_} keys(%{$Type1_Pure{"Memb"}});
10469 my %NameToPosB = map {$Type2_Pure{"Memb"}{$_}{"name"}=>$_} keys(%{$Type2_Pure{"Memb"}});
10470 foreach my $Member_Pos (sort {int($a) <=> int($b)} keys(%{$Type1_Pure{"Memb"}}))
10471 { # detect removed and renamed fields
10472 my $Member_Name = $Type1_Pure{"Memb"}{$Member_Pos}{"name"};
10473 next if(not $Member_Name);
10474 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);
10475 if($MemberPair_Pos eq "lost")
10476 {
10477 if($Type2_Pure{"Type"}=~/\A(Struct|Class|Union)\Z/)
10478 {
10479 if(isUnnamed($Member_Name))
10480 { # support for old-version dumps
10481 # unnamed fields have been introduced in the ACC 1.23 (dump 2.1 format)
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040010482 if(not checkDump(2, "2.1")) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010483 next;
10484 }
10485 }
10486 if(my $RenamedTo = isRenamed($Member_Pos, \%Type1_Pure, 1, \%Type2_Pure, 2))
10487 { # renamed
10488 $RenamedField{$Member_Pos}=$RenamedTo;
10489 $RenamedField_Rev{$NameToPosB{$RenamedTo}}=$Member_Name;
10490 }
10491 else
10492 { # removed
10493 $RemovedField{$Member_Pos}=1;
10494 }
10495 }
10496 elsif($Type1_Pure{"Type"} eq "Enum")
10497 {
10498 my $Member_Value1 = $Type1_Pure{"Memb"}{$Member_Pos}{"value"};
10499 next if($Member_Value1 eq "");
10500 $MemberPair_Pos = find_MemberPair_Pos_byVal($Member_Value1, \%Type2_Pure);
10501 if($MemberPair_Pos ne "lost")
10502 { # renamed
10503 my $RenamedTo = $Type2_Pure{"Memb"}{$MemberPair_Pos}{"name"};
10504 my $MemberPair_Pos_Rev = find_MemberPair_Pos_byName($RenamedTo, \%Type1_Pure);
10505 if($MemberPair_Pos_Rev eq "lost")
10506 {
10507 $RenamedField{$Member_Pos}=$RenamedTo;
10508 $RenamedField_Rev{$NameToPosB{$RenamedTo}}=$Member_Name;
10509 }
10510 else {
10511 $RemovedField{$Member_Pos}=1;
10512 }
10513 }
10514 else
10515 { # removed
10516 $RemovedField{$Member_Pos}=1;
10517 }
10518 }
10519 }
10520 else
10521 { # related
10522 $RelatedField{$Member_Pos} = $MemberPair_Pos;
10523 $RelatedField_Rev{$MemberPair_Pos} = $Member_Pos;
10524 }
10525 }
10526 foreach my $Member_Pos (sort {int($a) <=> int($b)} keys(%{$Type2_Pure{"Memb"}}))
10527 { # detect added fields
10528 my $Member_Name = $Type2_Pure{"Memb"}{$Member_Pos}{"name"};
10529 next if(not $Member_Name);
10530 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);
10531 if($MemberPair_Pos eq "lost")
10532 {
10533 if(isUnnamed($Member_Name))
10534 { # support for old-version dumps
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040010535 # unnamed fields have been introduced in the ACC 1.23 (dump 2.1 format)
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040010536 if(not checkDump(1, "2.1")) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010537 next;
10538 }
10539 }
10540 if($Type2_Pure{"Type"}=~/\A(Struct|Class|Union|Enum)\Z/)
10541 {
10542 if(not $RenamedField_Rev{$Member_Pos})
10543 { # added
10544 $AddedField{$Member_Pos}=1;
10545 }
10546 }
10547 }
10548 }
10549 if($Type2_Pure{"Type"}=~/\A(Struct|Class)\Z/)
10550 { # detect moved fields
10551 my (%RelPos, %RelPosName, %AbsPos) = ();
10552 my $Pos = 0;
10553 foreach my $Member_Pos (sort {int($a) <=> int($b)} keys(%{$Type1_Pure{"Memb"}}))
10554 { # relative positions in 1st version
10555 my $Member_Name = $Type1_Pure{"Memb"}{$Member_Pos}{"name"};
10556 next if(not $Member_Name);
10557 if(not $RemovedField{$Member_Pos})
10558 { # old type without removed fields
10559 $RelPos{1}{$Member_Name}=$Pos;
10560 $RelPosName{1}{$Pos} = $Member_Name;
10561 $AbsPos{1}{$Pos++} = $Member_Pos;
10562 }
10563 }
10564 $Pos = 0;
10565 foreach my $Member_Pos (sort {int($a) <=> int($b)} keys(%{$Type2_Pure{"Memb"}}))
10566 { # relative positions in 2nd version
10567 my $Member_Name = $Type2_Pure{"Memb"}{$Member_Pos}{"name"};
10568 next if(not $Member_Name);
10569 if(not $AddedField{$Member_Pos})
10570 { # new type without added fields
10571 $RelPos{2}{$Member_Name}=$Pos;
10572 $RelPosName{2}{$Pos} = $Member_Name;
10573 $AbsPos{2}{$Pos++} = $Member_Pos;
10574 }
10575 }
10576 foreach my $Member_Name (keys(%{$RelPos{1}}))
10577 {
10578 my $RPos1 = $RelPos{1}{$Member_Name};
10579 my $AbsPos1 = $NameToPosA{$Member_Name};
10580 my $Member_Name2 = $Member_Name;
10581 if(my $RenamedTo = $RenamedField{$AbsPos1})
10582 { # renamed
10583 $Member_Name2 = $RenamedTo;
10584 }
10585 my $RPos2 = $RelPos{2}{$Member_Name2};
10586 if($RPos2 ne "" and $RPos1 ne $RPos2)
10587 { # different relative positions
10588 my $AbsPos2 = $NameToPosB{$Member_Name2};
10589 if($AbsPos1 ne $AbsPos2)
10590 { # different absolute positions
10591 my $ProblemType = "Moved_Field";
10592 if(not isPublic(\%Type1_Pure, $AbsPos1))
10593 { # may change layout and size of type
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040010594 if($Level eq "Source") {
10595 next;
10596 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010597 $ProblemType = "Moved_Private_Field";
10598 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040010599 if($Level eq "Binary"
10600 and $Type1_Pure{"Size"} ne $Type2_Pure{"Size"})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010601 { # affected size
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040010602 my $MemSize1 = $TypeInfo{1}{$Type1_Pure{"Memb"}{$AbsPos1}{"type"}}{"Size"};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010603 my $MovedAbsPos = $AbsPos{1}{$RPos2};
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040010604 my $MemSize2 = $TypeInfo{1}{$Type1_Pure{"Memb"}{$MovedAbsPos}{"type"}}{"Size"};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010605 if($MemSize1 ne $MemSize2) {
10606 $ProblemType .= "_And_Size";
10607 }
10608 }
10609 if($ProblemType eq "Moved_Private_Field") {
10610 next;
10611 }
10612 %{$SubProblems{$ProblemType}{$Member_Name}}=(
10613 "Target"=>$Member_Name,
10614 "Type_Name"=>$Type1_Pure{"Name"},
10615 "Type_Type"=>$Type1_Pure{"Type"},
10616 "Old_Value"=>$RPos1,
10617 "New_Value"=>$RPos2 );
10618 }
10619 }
10620 }
10621 }
10622 foreach my $Member_Pos (sort {int($a) <=> int($b)} keys(%{$Type1_Pure{"Memb"}}))
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040010623 { # check older fields, public and private
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010624 my $Member_Name = $Type1_Pure{"Memb"}{$Member_Pos}{"name"};
10625 next if(not $Member_Name);
10626 if(my $RenamedTo = $RenamedField{$Member_Pos})
10627 { # renamed
10628 if($Type2_Pure{"Type"}=~/\A(Struct|Class|Union)\Z/)
10629 {
10630 if(isPublic(\%Type1_Pure, $Member_Pos))
10631 {
10632 %{$SubProblems{"Renamed_Field"}{$Member_Name}}=(
10633 "Target"=>$Member_Name,
10634 "Type_Name"=>$Type1_Pure{"Name"},
10635 "Type_Type"=>$Type1_Pure{"Type"},
10636 "Old_Value"=>$Member_Name,
10637 "New_Value"=>$RenamedTo );
10638 }
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040010639 elsif(isReserved($Member_Name))
10640 {
10641 %{$SubProblems{"Used_Reserved_Field"}{$Member_Name}}=(
10642 "Target"=>$Member_Name,
10643 "Type_Name"=>$Type1_Pure{"Name"},
10644 "Type_Type"=>$Type1_Pure{"Type"},
10645 "Old_Value"=>$Member_Name,
10646 "New_Value"=>$RenamedTo );
10647 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010648 }
10649 elsif($Type1_Pure{"Type"} eq "Enum")
10650 {
10651 %{$SubProblems{"Enum_Member_Name"}{$Type1_Pure{"Memb"}{$Member_Pos}{"value"}}}=(
10652 "Target"=>$Type1_Pure{"Memb"}{$Member_Pos}{"value"},
10653 "Type_Name"=>$Type1_Pure{"Name"},
10654 "Type_Type"=>$Type1_Pure{"Type"},
10655 "Old_Value"=>$Member_Name,
10656 "New_Value"=>$RenamedTo );
10657 }
10658 }
10659 elsif($RemovedField{$Member_Pos})
10660 { # removed
10661 if($Type2_Pure{"Type"}=~/\A(Struct|Class)\Z/)
10662 {
10663 my $ProblemType = "Removed_Field";
10664 if(not isPublic(\%Type1_Pure, $Member_Pos)
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040010665 or isUnnamed($Member_Name))
10666 {
10667 if($Level eq "Source") {
10668 next;
10669 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010670 $ProblemType = "Removed_Private_Field";
10671 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040010672 if($Level eq "Binary"
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +040010673 and not isMemPadded($Member_Pos, -1, \%Type1_Pure, \%RemovedField, $TypeInfo{1}, $WORD_SIZE{1}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010674 {
10675 if(my $MNum = isAccessible(\%Type1_Pure, \%RemovedField, $Member_Pos+1, -1))
10676 { # affected fields
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +040010677 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 +040010678 { # changed offset
10679 $ProblemType .= "_And_Layout";
10680 }
10681 }
10682 if($Type1_Pure{"Size"} ne $Type2_Pure{"Size"})
10683 { # affected size
10684 $ProblemType .= "_And_Size";
10685 }
10686 }
10687 if($ProblemType eq "Removed_Private_Field") {
10688 next;
10689 }
10690 %{$SubProblems{$ProblemType}{$Member_Name}}=(
10691 "Target"=>$Member_Name,
10692 "Type_Name"=>$Type1_Pure{"Name"},
10693 "Type_Type"=>$Type1_Pure{"Type"} );
10694 }
10695 elsif($Type2_Pure{"Type"} eq "Union")
10696 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040010697 if($Level eq "Binary"
10698 and $Type1_Pure{"Size"} ne $Type2_Pure{"Size"})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010699 {
10700 %{$SubProblems{"Removed_Union_Field_And_Size"}{$Member_Name}}=(
10701 "Target"=>$Member_Name,
10702 "Type_Name"=>$Type1_Pure{"Name"},
10703 "Type_Type"=>$Type1_Pure{"Type"} );
10704 }
10705 else
10706 {
10707 %{$SubProblems{"Removed_Union_Field"}{$Member_Name}}=(
10708 "Target"=>$Member_Name,
10709 "Type_Name"=>$Type1_Pure{"Name"},
10710 "Type_Type"=>$Type1_Pure{"Type"} );
10711 }
10712 }
10713 elsif($Type1_Pure{"Type"} eq "Enum")
10714 {
10715 %{$SubProblems{"Enum_Member_Removed"}{$Member_Name}}=(
10716 "Target"=>$Member_Name,
10717 "Type_Name"=>$Type1_Pure{"Name"},
10718 "Type_Type"=>$Type1_Pure{"Type"},
10719 "Old_Value"=>$Member_Name );
10720 }
10721 }
10722 else
10723 { # changed
10724 my $MemberPair_Pos = $RelatedField{$Member_Pos};
10725 if($Type1_Pure{"Type"} eq "Enum")
10726 {
10727 my $Member_Value1 = $Type1_Pure{"Memb"}{$Member_Pos}{"value"};
10728 next if($Member_Value1 eq "");
10729 my $Member_Value2 = $Type2_Pure{"Memb"}{$MemberPair_Pos}{"value"};
10730 next if($Member_Value2 eq "");
10731 if($Member_Value1 ne $Member_Value2)
10732 {
10733 my $ProblemType = "Enum_Member_Value";
10734 if(isLastElem($Member_Pos, \%Type1_Pure)) {
10735 $ProblemType = "Enum_Last_Member_Value";
10736 }
10737 %{$SubProblems{$ProblemType}{$Member_Name}}=(
10738 "Target"=>$Member_Name,
10739 "Type_Name"=>$Type1_Pure{"Name"},
10740 "Type_Type"=>$Type1_Pure{"Type"},
10741 "Old_Value"=>$Member_Value1,
10742 "New_Value"=>$Member_Value2 );
10743 }
10744 }
10745 elsif($Type2_Pure{"Type"}=~/\A(Struct|Class|Union)\Z/)
10746 {
10747 my $MemberType1_Id = $Type1_Pure{"Memb"}{$Member_Pos}{"type"};
10748 my $MemberType2_Id = $Type2_Pure{"Memb"}{$MemberPair_Pos}{"type"};
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040010749 my $SizeV1 = $TypeInfo{1}{$MemberType1_Id}{"Size"}*$BYTE_SIZE;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010750 if(my $BSize1 = $Type1_Pure{"Memb"}{$Member_Pos}{"bitfield"}) {
10751 $SizeV1 = $BSize1;
10752 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040010753 my $SizeV2 = $TypeInfo{2}{$MemberType2_Id}{"Size"}*$BYTE_SIZE;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010754 if(my $BSize2 = $Type2_Pure{"Memb"}{$MemberPair_Pos}{"bitfield"}) {
10755 $SizeV2 = $BSize2;
10756 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040010757 my $MemberType1_Name = $TypeInfo{1}{$MemberType1_Id}{"Name"};
10758 my $MemberType2_Name = $TypeInfo{2}{$MemberType2_Id}{"Name"};
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040010759 if($Level eq "Binary"
10760 and $SizeV1 ne $SizeV2)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010761 {
10762 if($MemberType1_Name eq $MemberType2_Name or (isAnon($MemberType1_Name) and isAnon($MemberType2_Name))
10763 or ($Type1_Pure{"Memb"}{$Member_Pos}{"bitfield"} and $Type2_Pure{"Memb"}{$MemberPair_Pos}{"bitfield"}))
10764 { # field size change (including anon-structures and unions)
10765 # - same types
10766 # - unnamed types
10767 # - bitfields
10768 my $ProblemType = "Field_Size";
10769 if(not isPublic(\%Type1_Pure, $Member_Pos)
10770 or isUnnamed($Member_Name))
10771 { # should not be accessed by applications, goes to "Low Severity"
10772 # example: "abidata" members in GStreamer types
10773 $ProblemType = "Private_".$ProblemType;
10774 }
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +040010775 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 +040010776 { # check an effect
10777 if(my $MNum = isAccessible(\%Type1_Pure, \%RemovedField, $Member_Pos+1, -1))
10778 { # public fields after the current
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +040010779 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 +040010780 { # changed offset
10781 $ProblemType .= "_And_Layout";
10782 }
10783 }
10784 if($Type1_Pure{"Size"} ne $Type2_Pure{"Size"}) {
10785 $ProblemType .= "_And_Type_Size";
10786 }
10787 }
10788 if($ProblemType eq "Private_Field_Size")
10789 { # private field size with no effect
10790 $ProblemType = "";
10791 }
10792 if($ProblemType)
10793 { # register a problem
10794 %{$SubProblems{$ProblemType}{$Member_Name}}=(
10795 "Target"=>$Member_Name,
10796 "Type_Name"=>$Type1_Pure{"Name"},
10797 "Type_Type"=>$Type1_Pure{"Type"},
10798 "Old_Size"=>$SizeV1,
10799 "New_Size"=>$SizeV2);
10800 }
10801 }
10802 }
10803 if($Type1_Pure{"Memb"}{$Member_Pos}{"bitfield"}
10804 or $Type2_Pure{"Memb"}{$MemberPair_Pos}{"bitfield"})
10805 { # do NOT check bitfield type changes
10806 next;
10807 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040010808 if(checkDump(1, "2.13") and checkDump(2, "2.13"))
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040010809 {
10810 if(not $Type1_Pure{"Memb"}{$Member_Pos}{"mutable"}
10811 and $Type2_Pure{"Memb"}{$MemberPair_Pos}{"mutable"})
10812 {
10813 %{$SubProblems{"Field_Became_Mutable"}{$Member_Name}}=(
10814 "Target"=>$Member_Name,
10815 "Type_Name"=>$Type1_Pure{"Name"},
10816 "Type_Type"=>$Type1_Pure{"Type"});
10817 }
10818 elsif($Type1_Pure{"Memb"}{$Member_Pos}{"mutable"}
10819 and not $Type2_Pure{"Memb"}{$MemberPair_Pos}{"mutable"})
10820 {
10821 %{$SubProblems{"Field_Became_NonMutable"}{$Member_Name}}=(
10822 "Target"=>$Member_Name,
10823 "Type_Name"=>$Type1_Pure{"Name"},
10824 "Type_Type"=>$Type1_Pure{"Type"});
10825 }
10826 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040010827 %Sub_SubProblems = detectTypeChange($MemberType1_Id, $MemberType2_Id, "Field", $Level);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010828 foreach my $ProblemType (keys(%Sub_SubProblems))
10829 {
10830 my $Old_Value = $Sub_SubProblems{$ProblemType}{"Old_Value"};
10831 my $New_Value = $Sub_SubProblems{$ProblemType}{"New_Value"};
10832 if($ProblemType eq "Field_Type"
10833 or $ProblemType eq "Field_Type_And_Size")
10834 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040010835 if(checkDump(1, "2.6") and checkDump(2, "2.6"))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010836 {
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040010837 if(my $RA = addedQual($Old_Value, $New_Value, "volatile"))
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040010838 {
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040010839 %{$Sub_SubProblems{"Field_Became_Volatile"}} = %{$Sub_SubProblems{$ProblemType}};
10840 if($Level eq "Source"
10841 and cmpBTypes($Old_Value, $New_Value, 1, 2)) {
10842 delete($Sub_SubProblems{$ProblemType});
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040010843 }
10844 }
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040010845 elsif(my $RR = removedQual($Old_Value, $New_Value, "volatile"))
10846 {
10847 %{$Sub_SubProblems{"Field_Became_NonVolatile"}} = %{$Sub_SubProblems{$ProblemType}};
10848 if($Level eq "Source"
10849 and cmpBTypes($Old_Value, $New_Value, 1, 2)) {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040010850 delete($Sub_SubProblems{$ProblemType});
10851 }
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040010852 }
10853 }
10854 if(my $RA = addedQual($Old_Value, $New_Value, "const"))
10855 {
10856 if($RA==2) {
10857 %{$Sub_SubProblems{"Field_Added_Const"}} = %{$Sub_SubProblems{$ProblemType}};
10858 }
10859 else {
10860 %{$Sub_SubProblems{"Field_Became_Const"}} = %{$Sub_SubProblems{$ProblemType}};
10861 }
10862 if($Level eq "Source"
10863 and cmpBTypes($Old_Value, $New_Value, 1, 2)) {
10864 delete($Sub_SubProblems{$ProblemType});
10865 }
10866 }
10867 elsif(my $RR = removedQual($Old_Value, $New_Value, "const"))
10868 {
10869 if($RR==2) {
10870 %{$Sub_SubProblems{"Field_Removed_Const"}} = %{$Sub_SubProblems{$ProblemType}};
10871 }
10872 else {
10873 %{$Sub_SubProblems{"Field_Became_NonConst"}} = %{$Sub_SubProblems{$ProblemType}};
10874 }
10875 if($Level eq "Source"
10876 and cmpBTypes($Old_Value, $New_Value, 1, 2)) {
10877 delete($Sub_SubProblems{$ProblemType});
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010878 }
10879 }
10880 }
10881 }
10882 foreach my $ProblemType (keys(%Sub_SubProblems))
10883 {
10884 my $ProblemType_Init = $ProblemType;
10885 if($ProblemType eq "Field_Type_And_Size")
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040010886 { # Binary
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010887 if(not isPublic(\%Type1_Pure, $Member_Pos)
10888 or isUnnamed($Member_Name)) {
10889 $ProblemType = "Private_".$ProblemType;
10890 }
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +040010891 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 +040010892 { # check an effect
10893 if(my $MNum = isAccessible(\%Type1_Pure, \%RemovedField, $Member_Pos+1, -1))
10894 { # public fields after the current
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +040010895 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 +040010896 { # changed offset
10897 $ProblemType .= "_And_Layout";
10898 }
10899 }
10900 if($Type1_Pure{"Size"} ne $Type2_Pure{"Size"}) {
10901 $ProblemType .= "_And_Type_Size";
10902 }
10903 }
10904 }
10905 else
10906 {
10907 if(not isPublic(\%Type1_Pure, $Member_Pos)
10908 or isUnnamed($Member_Name)) {
10909 next;
10910 }
10911 }
10912 if($ProblemType eq "Private_Field_Type_And_Size")
10913 { # private field change with no effect
10914 next;
10915 }
10916 %{$SubProblems{$ProblemType}{$Member_Name}}=(
10917 "Target"=>$Member_Name,
10918 "Type_Name"=>$Type1_Pure{"Name"},
10919 "Type_Type"=>$Type1_Pure{"Type"} );
10920 foreach my $Attr (keys(%{$Sub_SubProblems{$ProblemType_Init}}))
10921 { # other properties
10922 $SubProblems{$ProblemType}{$Member_Name}{$Attr} = $Sub_SubProblems{$ProblemType_Init}{$Attr};
10923 }
10924 }
10925 if(not isPublic(\%Type1_Pure, $Member_Pos))
10926 { # do NOT check internal type changes
10927 next;
10928 }
10929 if($MemberType1_Id and $MemberType2_Id)
10930 {# checking member type changes (replace)
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040010931 %Sub_SubProblems = mergeTypes($MemberType1_Id, $MemberType2_Id, $Level);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010932 foreach my $Sub_SubProblemType (keys(%Sub_SubProblems))
10933 {
10934 foreach my $Sub_SubLocation (keys(%{$Sub_SubProblems{$Sub_SubProblemType}}))
10935 {
10936 my $NewLocation = ($Sub_SubLocation)?$Member_Name."->".$Sub_SubLocation:$Member_Name;
10937 $SubProblems{$Sub_SubProblemType}{$NewLocation}{"IsInTypeInternals"}=1;
10938 foreach my $Attr (keys(%{$Sub_SubProblems{$Sub_SubProblemType}{$Sub_SubLocation}})) {
10939 $SubProblems{$Sub_SubProblemType}{$NewLocation}{$Attr} = $Sub_SubProblems{$Sub_SubProblemType}{$Sub_SubLocation}{$Attr};
10940 }
10941 if($Sub_SubLocation!~/\-\>/) {
10942 $SubProblems{$Sub_SubProblemType}{$NewLocation}{"Start_Type_Name"} = $MemberType1_Name;
10943 }
10944 }
10945 }
10946 }
10947 }
10948 }
10949 }
10950 foreach my $Member_Pos (sort {int($a) <=> int($b)} keys(%{$Type2_Pure{"Memb"}}))
10951 { # checking added members, public and private
10952 my $Member_Name = $Type2_Pure{"Memb"}{$Member_Pos}{"name"};
10953 next if(not $Member_Name);
10954 if($AddedField{$Member_Pos})
10955 { # added
10956 if($Type2_Pure{"Type"}=~/\A(Struct|Class)\Z/)
10957 {
10958 my $ProblemType = "Added_Field";
10959 if(not isPublic(\%Type2_Pure, $Member_Pos)
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040010960 or isUnnamed($Member_Name))
10961 {
10962 if($Level eq "Source") {
10963 next;
10964 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010965 $ProblemType = "Added_Private_Field";
10966 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040010967 if($Level eq "Binary"
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +040010968 and not isMemPadded($Member_Pos, -1, \%Type2_Pure, \%AddedField, $TypeInfo{2}, $WORD_SIZE{2}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010969 {
10970 if(my $MNum = isAccessible(\%Type2_Pure, \%AddedField, $Member_Pos, -1))
10971 { # public fields after the current
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +040010972 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 +040010973 { # changed offset
10974 $ProblemType .= "_And_Layout";
10975 }
10976 }
10977 if($Type1_Pure{"Size"} ne $Type2_Pure{"Size"}) {
10978 $ProblemType .= "_And_Size";
10979 }
10980 }
10981 if($ProblemType eq "Added_Private_Field")
10982 { # skip added private fields
10983 next;
10984 }
10985 %{$SubProblems{$ProblemType}{$Member_Name}}=(
10986 "Target"=>$Member_Name,
10987 "Type_Name"=>$Type1_Pure{"Name"},
10988 "Type_Type"=>$Type1_Pure{"Type"} );
10989 }
10990 elsif($Type2_Pure{"Type"} eq "Union")
10991 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040010992 if($Level eq "Binary"
10993 and $Type1_Pure{"Size"} ne $Type2_Pure{"Size"})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010994 {
10995 %{$SubProblems{"Added_Union_Field_And_Size"}{$Member_Name}}=(
10996 "Target"=>$Member_Name,
10997 "Type_Name"=>$Type1_Pure{"Name"},
10998 "Type_Type"=>$Type1_Pure{"Type"} );
10999 }
11000 else
11001 {
11002 %{$SubProblems{"Added_Union_Field"}{$Member_Name}}=(
11003 "Target"=>$Member_Name,
11004 "Type_Name"=>$Type1_Pure{"Name"},
11005 "Type_Type"=>$Type1_Pure{"Type"} );
11006 }
11007 }
11008 elsif($Type2_Pure{"Type"} eq "Enum")
11009 {
11010 my $Member_Value = $Type2_Pure{"Memb"}{$Member_Pos}{"value"};
11011 next if($Member_Value eq "");
11012 %{$SubProblems{"Added_Enum_Member"}{$Member_Name}}=(
11013 "Target"=>$Member_Name,
11014 "Type_Name"=>$Type2_Pure{"Name"},
11015 "Type_Type"=>$Type2_Pure{"Type"},
11016 "New_Value"=>$Member_Value );
11017 }
11018 }
11019 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040011020 %{$Cache{"mergeTypes"}{$Level}{$Type1_Id}{$Type2_Id}} = %SubProblems;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011021 pop(@RecurTypes);
11022 return %SubProblems;
11023}
11024
11025sub isUnnamed($) {
11026 return $_[0]=~/\Aunnamed\d+\Z/;
11027}
11028
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040011029sub get_ShortType($$)
11030{
11031 my ($TypeId, $LibVersion) = @_;
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +040011032 my $TypeName = uncover_typedefs($TypeInfo{$LibVersion}{$TypeId}{"Name"}, $LibVersion);
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040011033 if(my $NameSpace = $TypeInfo{$LibVersion}{$TypeId}{"NameSpace"}) {
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040011034 $TypeName=~s/\A$NameSpace\:\://g;
11035 }
11036 return $TypeName;
11037}
11038
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040011039sub goToFirst($$$)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011040{
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040011041 my ($TypeId, $LibVersion, $Type_Type) = @_;
Andrey Ponomarenko16934472012-03-29 15:37:04 +040011042 return () if(not $TypeId);
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040011043 if(defined $Cache{"goToFirst"}{$TypeId}{$LibVersion}{$Type_Type}) {
11044 return %{$Cache{"goToFirst"}{$TypeId}{$LibVersion}{$Type_Type}};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011045 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040011046 return () if(not $TypeInfo{$LibVersion}{$TypeId});
11047 my %Type = %{$TypeInfo{$LibVersion}{$TypeId}};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011048 return () if(not $Type{"Type"});
11049 if($Type{"Type"} ne $Type_Type)
11050 {
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040011051 return () if(not defined $Type{"BaseType"});
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040011052 return () if(not $Type{"BaseType"}{"Tid"});
11053 %Type = goToFirst($Type{"BaseType"}{"Tid"}, $LibVersion, $Type_Type);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011054 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040011055 $Cache{"goToFirst"}{$TypeId}{$LibVersion}{$Type_Type} = \%Type;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011056 return %Type;
11057}
11058
11059my %TypeSpecAttributes = (
11060 "Const" => 1,
11061 "Volatile" => 1,
11062 "ConstVolatile" => 1,
11063 "Restrict" => 1,
11064 "Typedef" => 1
11065);
11066
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040011067sub get_PureType($$)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011068{
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +040011069 my ($TypeId, $Info) = @_;
11070 if(not $TypeId or not $Info
11071 or not $Info->{$TypeId}) {
11072 return ();
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011073 }
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +040011074 if(defined $Cache{"get_PureType"}{$TypeId}{$Info}) {
11075 return %{$Cache{"get_PureType"}{$TypeId}{$Info}};
11076 }
11077 my %Type = %{$Info->{$TypeId}};
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040011078 return %Type if(not defined $Type{"BaseType"});
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040011079 return %Type if(not $Type{"BaseType"}{"Tid"});
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011080 if($TypeSpecAttributes{$Type{"Type"}}) {
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +040011081 %Type = get_PureType($Type{"BaseType"}{"Tid"}, $Info);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011082 }
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +040011083 $Cache{"get_PureType"}{$TypeId}{$Info} = \%Type;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011084 return %Type;
11085}
11086
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040011087sub get_PLevel($$)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011088{
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040011089 my ($TypeId, $LibVersion) = @_;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011090 return 0 if(not $TypeId);
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040011091 if(defined $Cache{"get_PLevel"}{$TypeId}{$LibVersion}) {
11092 return $Cache{"get_PLevel"}{$TypeId}{$LibVersion};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011093 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040011094 return 0 if(not $TypeInfo{$LibVersion}{$TypeId});
11095 my %Type = %{$TypeInfo{$LibVersion}{$TypeId}};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011096 return 1 if($Type{"Type"}=~/FuncPtr|MethodPtr|FieldPtr/);
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040011097 return 0 if(not defined $Type{"BaseType"});
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040011098 return 0 if(not $Type{"BaseType"}{"Tid"});
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011099 my $PointerLevel = 0;
11100 if($Type{"Type"} =~/Pointer|Ref|FuncPtr|MethodPtr|FieldPtr/) {
11101 $PointerLevel += 1;
11102 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040011103 $PointerLevel += get_PLevel($Type{"BaseType"}{"Tid"}, $LibVersion);
11104 $Cache{"get_PLevel"}{$TypeId}{$LibVersion} = $PointerLevel;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011105 return $PointerLevel;
11106}
11107
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040011108sub get_BaseType($$)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011109{
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040011110 my ($TypeId, $LibVersion) = @_;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011111 return () if(not $TypeId);
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040011112 if(defined $Cache{"get_BaseType"}{$TypeId}{$LibVersion}) {
11113 return %{$Cache{"get_BaseType"}{$TypeId}{$LibVersion}};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011114 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040011115 return () if(not $TypeInfo{$LibVersion}{$TypeId});
11116 my %Type = %{$TypeInfo{$LibVersion}{$TypeId}};
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040011117 return %Type if(not defined $Type{"BaseType"});
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040011118 return %Type if(not $Type{"BaseType"}{"Tid"});
11119 %Type = get_BaseType($Type{"BaseType"}{"Tid"}, $LibVersion);
11120 $Cache{"get_BaseType"}{$TypeId}{$LibVersion} = \%Type;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011121 return %Type;
11122}
11123
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040011124sub get_BaseTypeQual($$)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011125{
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040011126 my ($TypeId, $LibVersion) = @_;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011127 return "" if(not $TypeId);
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040011128 return "" if(not $TypeInfo{$LibVersion}{$TypeId});
11129 my %Type = %{$TypeInfo{$LibVersion}{$TypeId}};
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040011130 return "" if(not defined $Type{"BaseType"});
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040011131 return "" if(not $Type{"BaseType"}{"Tid"});
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011132 my $Qual = "";
11133 if($Type{"Type"} eq "Pointer") {
11134 $Qual .= "*";
11135 }
11136 elsif($Type{"Type"} eq "Ref") {
11137 $Qual .= "&";
11138 }
11139 elsif($Type{"Type"} eq "ConstVolatile") {
11140 $Qual .= "const volatile";
11141 }
11142 elsif($Type{"Type"} eq "Const"
11143 or $Type{"Type"} eq "Volatile"
11144 or $Type{"Type"} eq "Restrict") {
11145 $Qual .= lc($Type{"Type"});
11146 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040011147 my $BQual = get_BaseTypeQual($Type{"BaseType"}{"Tid"}, $LibVersion);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011148 return $BQual.$Qual;
11149}
11150
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040011151sub get_OneStep_BaseType($$)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011152{
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +040011153 my ($TypeId, $Info) = @_;
11154 if(not $TypeId or not $Info
11155 or not $Info->{$TypeId}) {
11156 return ();
11157 }
11158 my %Type = %{$Info->{$TypeId}};
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040011159 return %Type if(not defined $Type{"BaseType"});
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +040011160 if(my $BTid = $Type{"BaseType"}{"Tid"})
11161 {
11162 if($Info->{$BTid}) {
11163 return %{$Info->{$BTid}};
11164 }
11165 else { # something is going wrong
11166 return ();
11167 }
11168 }
11169 else {
11170 return %Type;
11171 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011172}
11173
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040011174sub get_Type($$)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011175{
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040011176 my ($TypeId, $LibVersion) = @_;
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040011177 return () if(not $TypeId);
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040011178 return () if(not $TypeInfo{$LibVersion}{$TypeId});
11179 return %{$TypeInfo{$LibVersion}{$TypeId}};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011180}
11181
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +040011182sub isPrivateData($)
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040011183{ # non-public global data
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011184 my $Symbol = $_[0];
11185 return ($Symbol=~/\A(_ZGV|_ZTI|_ZTS|_ZTT|_ZTV|_ZTC|_ZThn|_ZTv0_n)/);
11186}
11187
Andrey Ponomarenko01117f12012-06-26 12:23:02 +040011188sub isInLineInst($$$) {
11189 return (isTemplateInstance(@_) and not isTemplateSpec(@_));
11190}
11191
11192sub isTemplateInstance($$$)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011193{
Andrey Ponomarenko01117f12012-06-26 12:23:02 +040011194 my ($Symbol, $SInfo, $LibVersion) = @_;
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040011195 if($CheckObjectsOnly)
11196 {
11197 if($Symbol!~/\A(_Z|\?)/) {
11198 return 0;
11199 }
11200 if(my $Signature = $tr_name{$Symbol})
11201 {
11202 if(index($Signature,">")==-1) {
11203 return 0;
11204 }
11205 if(my $ShortName = substr($Signature, 0, find_center($Signature, "(")))
11206 {
Andrey Ponomarenko01117f12012-06-26 12:23:02 +040011207 if(index($ShortName,"<")!=-1
11208 and index($ShortName,">")!=-1) {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040011209 return 1;
11210 }
11211 }
11212 }
11213 }
11214 else
11215 {
Andrey Ponomarenko01117f12012-06-26 12:23:02 +040011216 if(my $ClassId = $SInfo->{"Class"})
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040011217 {
11218 if(my $ClassName = $TypeInfo{$LibVersion}{$ClassId}{"Name"})
11219 {
11220 if(index($ClassName,"<")!=-1) {
11221 return 1;
11222 }
11223 }
11224 }
Andrey Ponomarenko01117f12012-06-26 12:23:02 +040011225 if(my $ShortName = $SInfo->{"ShortName"})
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040011226 {
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 return 0;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011234}
11235
Andrey Ponomarenko01117f12012-06-26 12:23:02 +040011236sub isTemplateSpec($$$)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011237{
Andrey Ponomarenko01117f12012-06-26 12:23:02 +040011238 my ($Symbol, $SInfo, $LibVersion) = @_;
11239 if(my $ClassId = $SInfo->{"Class"})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011240 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040011241 if($TypeInfo{$LibVersion}{$ClassId}{"Spec"})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011242 { # class specialization
11243 return 1;
11244 }
Andrey Ponomarenko01117f12012-06-26 12:23:02 +040011245 elsif($SInfo->{"Spec"})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011246 { # method specialization
11247 return 1;
11248 }
11249 }
11250 return 0;
11251}
11252
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011253sub symbolFilter($$$$)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011254{ # some special cases when the symbol cannot be imported
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011255 my ($Symbol, $LibVersion, $Type, $Level) = @_;
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +040011256 if(isPrivateData($Symbol))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011257 { # non-public global data
11258 return 0;
11259 }
11260 if($CheckObjectsOnly) {
11261 return 0 if($Symbol=~/\A(_init|_fini)\Z/);
11262 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040011263 if($CheckHeadersOnly and not checkDump($LibVersion, "2.7"))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011264 { # support for old ABI dumps in --headers-only mode
11265 foreach my $Pos (keys(%{$CompleteSignature{$LibVersion}{$Symbol}{"Param"}}))
11266 {
11267 if(my $Pid = $CompleteSignature{$LibVersion}{$Symbol}{"Param"}{$Pos}{"type"})
11268 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040011269 my $PType = $TypeInfo{$LibVersion}{$Pid}{"Type"};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011270 if(not $PType or $PType eq "Unknown") {
11271 return 0;
11272 }
11273 }
11274 }
11275 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +040011276 if($Type=~/Affected/)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011277 {
11278 my $ClassId = $CompleteSignature{$LibVersion}{$Symbol}{"Class"};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011279 if($SkipSymbols{$LibVersion}{$Symbol})
11280 { # user defined symbols to ignore
11281 return 0;
11282 }
11283 my $NameSpace = $CompleteSignature{$LibVersion}{$Symbol}{"NameSpace"};
11284 if(not $NameSpace and $ClassId)
11285 { # class methods have no "NameSpace" attribute
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040011286 $NameSpace = $TypeInfo{$LibVersion}{$ClassId}{"NameSpace"};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011287 }
11288 if($NameSpace)
11289 { # user defined namespaces to ignore
11290 if($SkipNameSpaces{$LibVersion}{$NameSpace}) {
11291 return 0;
11292 }
11293 foreach my $NS (keys(%{$SkipNameSpaces{$LibVersion}}))
11294 { # nested namespaces
11295 if($NameSpace=~/\A\Q$NS\E(\:\:|\Z)/) {
11296 return 0;
11297 }
11298 }
11299 }
11300 if(my $Header = $CompleteSignature{$LibVersion}{$Symbol}{"Header"})
11301 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040011302 if(my $Skip = skipHeader($Header, $LibVersion))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011303 { # --skip-headers or <skip_headers> (not <skip_including>)
11304 if($Skip==1) {
11305 return 0;
11306 }
11307 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011308 }
11309 if($SymbolsListPath and not $SymbolsList{$Symbol})
11310 { # user defined symbols
11311 return 0;
11312 }
11313 if($AppPath and not $SymbolsList_App{$Symbol})
11314 { # user defined symbols (in application)
11315 return 0;
11316 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +040011317 if(not selectSymbol($Symbol, $CompleteSignature{$LibVersion}{$Symbol}, $Level, $LibVersion))
11318 { # non-target symbols
11319 return 0;
11320 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011321 if($Level eq "Binary")
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011322 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040011323 if($CheckObjectsOnly)
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011324 {
Andrey Ponomarenko01117f12012-06-26 12:23:02 +040011325 if(isTemplateInstance($Symbol, $CompleteSignature{$LibVersion}{$Symbol}, $LibVersion)) {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040011326 return 0;
11327 }
11328 }
11329 else
11330 {
11331 if($CompleteSignature{$LibVersion}{$Symbol}{"InLine"}
Andrey Ponomarenko01117f12012-06-26 12:23:02 +040011332 or isInLineInst($Symbol, $CompleteSignature{$LibVersion}{$Symbol}, $LibVersion))
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040011333 {
11334 if($ClassId and $CompleteSignature{$LibVersion}{$Symbol}{"Virt"})
11335 { # inline virtual methods
11336 if($Type=~/InlineVirt/) {
11337 return 1;
11338 }
11339 my $Allocable = (not isCopyingClass($ClassId, $LibVersion));
11340 if(not $Allocable)
11341 { # check bases
11342 foreach my $DCId (get_sub_classes($ClassId, $LibVersion, 1))
11343 {
11344 if(not isCopyingClass($DCId, $LibVersion))
11345 { # exists a derived class without default c-tor
11346 $Allocable=1;
11347 last;
11348 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011349 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011350 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040011351 if(not $Allocable) {
11352 return 0;
11353 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011354 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040011355 else
11356 { # inline non-virtual methods
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011357 return 0;
11358 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011359 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011360 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011361 }
11362 }
11363 return 1;
11364}
11365
11366sub mergeImpl()
11367{
11368 my $DiffCmd = get_CmdPath("diff");
11369 if(not $DiffCmd) {
11370 exitStatus("Not_Found", "can't find \"diff\"");
11371 }
11372 foreach my $Interface (sort keys(%{$Symbol_Library{1}}))
11373 { # implementation changes
11374 next if($CompleteSignature{1}{$Interface}{"Private"});
11375 next if(not $CompleteSignature{1}{$Interface}{"Header"} and not $CheckObjectsOnly);
11376 next if(not $Symbol_Library{2}{$Interface} and not $Symbol_Library{2}{$SymVer{2}{$Interface}});
Andrey Ponomarenko85043792012-05-14 16:48:07 +040011377 if(not symbolFilter($Interface, 1, "Affected", "Binary")) {
11378 next;
11379 }
Andrey Ponomarenko16934472012-03-29 15:37:04 +040011380 my $Impl1 = canonifyImpl($Interface_Impl{1}{$Interface});
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011381 next if(not $Impl1);
Andrey Ponomarenko16934472012-03-29 15:37:04 +040011382 my $Impl2 = canonifyImpl($Interface_Impl{2}{$Interface});
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011383 next if(not $Impl2);
11384 if($Impl1 ne $Impl2)
11385 {
11386 writeFile("$TMP_DIR/impl1", $Impl1);
11387 writeFile("$TMP_DIR/impl2", $Impl2);
Andrey Ponomarenkoa01311b2012-06-08 17:20:02 +040011388 my $Diff = `$DiffCmd -rNau \"$TMP_DIR/impl1\" \"$TMP_DIR/impl2\"`;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011389 $Diff=~s/(---|\+\+\+).+\n//g;
11390 $Diff=~s/[ ]{3,}/ /g;
11391 $Diff=~s/\n\@\@/\n \n\@\@/g;
Andrey Ponomarenkoa01311b2012-06-08 17:20:02 +040011392 unlink("$TMP_DIR/impl1");
11393 unlink("$TMP_DIR/impl2");
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011394 %{$ImplProblems{$Interface}}=(
11395 "Diff" => get_CodeView($Diff) );
11396 }
11397 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +040011398
11399 # clean memory
11400 %Interface_Impl = ();
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011401}
11402
Andrey Ponomarenko16934472012-03-29 15:37:04 +040011403sub canonifyImpl($)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011404{
11405 my $FuncBody= $_[0];
11406 return "" if(not $FuncBody);
11407 $FuncBody=~s/0x[a-f\d]+/0x?/g;# addr
11408 $FuncBody=~s/((\A|\n)[a-z]+[\t ]+)[a-f\d]+([^x]|\Z)/$1?$3/g;# call, jump
11409 $FuncBody=~s/# [a-f\d]+ /# ? /g;# call, jump
11410 $FuncBody=~s/%([a-z]+[a-f\d]*)/\%reg/g;# registers
11411 while($FuncBody=~s/\nnop[ \t]*(\n|\Z)/$1/g){};# empty op
11412 $FuncBody=~s/<.+?\.cpp.+?>/<name.cpp>/g;
11413 $FuncBody=~s/(\A|\n)[a-f\d]+ </$1? </g;# 5e74 <_ZN...
11414 $FuncBody=~s/\.L\d+/.L/g;
11415 $FuncBody=~s/#(-?)\d+/#$1?/g;# r3, [r3, #120]
11416 $FuncBody=~s/[\n]{2,}/\n/g;
11417 return $FuncBody;
11418}
11419
11420sub get_CodeView($)
11421{
11422 my $Code = $_[0];
11423 my $View = "";
11424 foreach my $Line (split(/\n/, $Code))
11425 {
11426 if($Line=~s/\A(\+|-)/$1 /g)
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040011427 { # bold line
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011428 $View .= "<tr><td><b>".htmlSpecChars($Line)."</b></td></tr>\n";
11429 }
11430 else {
11431 $View .= "<tr><td>".htmlSpecChars($Line)."</td></tr>\n";
11432 }
11433 }
11434 return "<table class='code_view'>$View</table>\n";
11435}
11436
11437sub getImplementations($$)
11438{
11439 my ($LibVersion, $Path) = @_;
11440 return if(not $LibVersion or not -e $Path);
11441 if($OSgroup eq "macos")
11442 {
11443 my $OtoolCmd = get_CmdPath("otool");
11444 if(not $OtoolCmd) {
11445 exitStatus("Not_Found", "can't find \"otool\"");
11446 }
11447 my $CurInterface = "";
Andrey Ponomarenkoa01311b2012-06-08 17:20:02 +040011448 foreach my $Line (split(/\n/, `$OtoolCmd -tv \"$Path\" 2>\"$TMP_DIR/null\"`))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011449 {
11450 if($Line=~/\A\s*_(\w+)\s*:/i) {
11451 $CurInterface = $1;
11452 }
11453 elsif($Line=~/\A\s*[\da-z]+\s+(.+?)\Z/i) {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040011454 $Interface_Impl{$LibVersion}{$CurInterface} .= $1."\n";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011455 }
11456 }
11457 }
11458 else
11459 {
11460 my $ObjdumpCmd = get_CmdPath("objdump");
11461 if(not $ObjdumpCmd) {
11462 exitStatus("Not_Found", "can't find \"objdump\"");
11463 }
11464 my $CurInterface = "";
Andrey Ponomarenkoa01311b2012-06-08 17:20:02 +040011465 foreach my $Line (split(/\n/, `$ObjdumpCmd -d \"$Path\" 2>\"$TMP_DIR/null\"`))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011466 {
11467 if($Line=~/\A[\da-z]+\s+<(\w+)>/i) {
11468 $CurInterface = $1;
11469 }
11470 else
11471 { # x86: 51fa:(\t)89 e5 (\t)mov %esp,%ebp
11472 # arm: 5020:(\t)e24cb004(\t)sub(\t)fp, ip, #4(\t); 0x4
11473 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 +040011474 $Interface_Impl{$LibVersion}{$CurInterface} .= $2."\n";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011475 }
11476 }
11477 }
11478 }
11479}
11480
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011481sub detectAdded($)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011482{
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011483 my $Level = $_[0];
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011484 foreach my $Symbol (keys(%{$Symbol_Library{2}}))
11485 {
11486 if(link_symbol($Symbol, 1, "+Deps"))
11487 { # linker can find a new symbol
11488 # in the old-version library
11489 # So, it's not a new symbol
11490 next;
11491 }
11492 if(my $VSym = $SymVer{2}{$Symbol}
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040011493 and index($Symbol,"\@")==-1) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011494 next;
11495 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011496 $AddedInt{$Level}{$Symbol} = 1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011497 }
11498}
11499
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011500sub detectRemoved($)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011501{
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011502 my $Level = $_[0];
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011503 foreach my $Symbol (keys(%{$Symbol_Library{1}}))
11504 {
11505 if($CheckObjectsOnly) {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011506 $CheckedSymbols{"Binary"}{$Symbol} = 1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011507 }
11508 if(link_symbol($Symbol, 2, "+Deps"))
11509 { # linker can find an old symbol
11510 # in the new-version library
11511 next;
11512 }
11513 if(my $VSym = $SymVer{1}{$Symbol}
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040011514 and index($Symbol,"\@")==-1) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011515 next;
11516 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011517 $RemovedInt{$Level}{$Symbol} = 1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011518 }
11519}
11520
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011521sub mergeLibs($)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011522{
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011523 my $Level = $_[0];
11524 foreach my $Symbol (sort keys(%{$AddedInt{$Level}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011525 { # checking added symbols
11526 next if($CompleteSignature{2}{$Symbol}{"Private"});
11527 next if(not $CompleteSignature{2}{$Symbol}{"Header"} and not $CheckObjectsOnly);
Andrey Ponomarenko85043792012-05-14 16:48:07 +040011528 next if(not symbolFilter($Symbol, 2, "Affected", $Level));
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011529 %{$CompatProblems{$Level}{$Symbol}{"Added_Symbol"}{""}}=();
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011530 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011531 foreach my $Symbol (sort keys(%{$RemovedInt{$Level}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011532 { # checking removed symbols
11533 next if($CompleteSignature{1}{$Symbol}{"Private"});
11534 next if(not $CompleteSignature{1}{$Symbol}{"Header"} and not $CheckObjectsOnly);
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040011535 if(index($Symbol, "_ZTV")==0)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011536 { # skip v-tables for templates, that should not be imported by applications
11537 next if($tr_name{$Symbol}=~/</);
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040011538 if(my $CName = $VTableClass{$Symbol})
11539 {
11540 if(not keys(%{$ClassMethods{$Level}{1}{$CName}}))
11541 { # vtables for "private" classes
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040011542 # use case: vtable for QDragManager (Qt 4.5.3 to 4.6.0) became HIDDEN symbol
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040011543 next;
11544 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011545 }
11546 }
11547 else {
Andrey Ponomarenko85043792012-05-14 16:48:07 +040011548 next if(not symbolFilter($Symbol, 1, "Affected", $Level));
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011549 }
11550 if($CompleteSignature{1}{$Symbol}{"PureVirt"})
11551 { # symbols for pure virtual methods cannot be called by clients
11552 next;
11553 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011554 %{$CompatProblems{$Level}{$Symbol}{"Removed_Symbol"}{""}}=();
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011555 }
11556}
11557
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040011558sub checkDump($$)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011559{
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040011560 my ($LibVersion, $V) = @_;
11561 if(defined $Cache{"checkDump"}{$LibVersion}{$V}) {
11562 return $Cache{"checkDump"}{$LibVersion}{$V};
11563 }
11564 return ($Cache{"checkDump"}{$LibVersion}{$V} = (not $UsedDump{$LibVersion}{"V"} or cmpVersions($UsedDump{$LibVersion}{"V"}, $V)>=0));
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011565}
11566
11567sub detectAdded_H($)
11568{
11569 my $Level = $_[0];
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011570 foreach my $Symbol (sort keys(%{$CompleteSignature{2}}))
11571 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011572 if($Level eq "Source")
11573 { # remove symbol version
11574 my ($SN, $SS, $SV) = separate_symbol($Symbol);
11575 $Symbol=$SN;
Andrey Ponomarenkob8d203d2012-05-25 18:11:07 +040011576
11577 if($CompleteSignature{2}{$Symbol}{"Artificial"})
11578 { # skip artificial constructors
11579 next;
11580 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011581 }
Andrey Ponomarenko16934472012-03-29 15:37:04 +040011582 if(not $CompleteSignature{2}{$Symbol}{"Header"}
11583 or not $CompleteSignature{2}{$Symbol}{"MnglName"}) {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011584 next;
11585 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040011586 if($ExtendedSymbols{$Symbol}) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011587 next;
11588 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011589 if(not defined $CompleteSignature{1}{$Symbol}
11590 or not $CompleteSignature{1}{$Symbol}{"MnglName"})
11591 {
Andrey Ponomarenko16934472012-03-29 15:37:04 +040011592 if($UsedDump{2}{"SrcBin"})
11593 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040011594 if($UsedDump{1}{"BinOnly"} or not checkDump(1, "2.11"))
Andrey Ponomarenko16934472012-03-29 15:37:04 +040011595 { # support for old and different (!) ABI dumps
11596 if(not $CompleteSignature{2}{$Symbol}{"Virt"}
11597 and not $CompleteSignature{2}{$Symbol}{"PureVirt"})
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011598 {
Andrey Ponomarenko16934472012-03-29 15:37:04 +040011599 if($CheckHeadersOnly)
Andrey Ponomarenko85043792012-05-14 16:48:07 +040011600 {
11601 if(my $Lang = $CompleteSignature{2}{$Symbol}{"Lang"})
11602 {
11603 if($Lang eq "C")
11604 { # support for old ABI dumps: missed extern "C" functions
11605 next;
11606 }
11607 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011608 }
Andrey Ponomarenko16934472012-03-29 15:37:04 +040011609 else
11610 {
11611 if(not link_symbol($Symbol, 2, "-Deps"))
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040011612 { # skip added inline symbols and const global data
Andrey Ponomarenko16934472012-03-29 15:37:04 +040011613 next;
11614 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011615 }
11616 }
11617 }
11618 }
11619 $AddedInt{$Level}{$Symbol} = 1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011620 }
11621 }
11622}
11623
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011624sub detectRemoved_H($)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011625{
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011626 my $Level = $_[0];
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011627 foreach my $Symbol (sort keys(%{$CompleteSignature{1}}))
11628 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011629 if($Level eq "Source")
11630 { # remove symbol version
11631 my ($SN, $SS, $SV) = separate_symbol($Symbol);
11632 $Symbol=$SN;
11633 }
Andrey Ponomarenko16934472012-03-29 15:37:04 +040011634 if(not $CompleteSignature{1}{$Symbol}{"Header"}
11635 or not $CompleteSignature{1}{$Symbol}{"MnglName"}) {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011636 next;
11637 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040011638 if($ExtendedSymbols{$Symbol}) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011639 next;
11640 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011641 if(not defined $CompleteSignature{2}{$Symbol}
11642 or not $CompleteSignature{2}{$Symbol}{"MnglName"})
Andrey Ponomarenko85043792012-05-14 16:48:07 +040011643 {
Andrey Ponomarenko16934472012-03-29 15:37:04 +040011644 if($UsedDump{1}{"SrcBin"})
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011645 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040011646 if($UsedDump{2}{"BinOnly"} or not checkDump(2, "2.11"))
Andrey Ponomarenko85043792012-05-14 16:48:07 +040011647 { # support for old and different (!) ABI dumps
Andrey Ponomarenko16934472012-03-29 15:37:04 +040011648 if(not $CompleteSignature{1}{$Symbol}{"Virt"}
11649 and not $CompleteSignature{1}{$Symbol}{"PureVirt"})
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011650 {
Andrey Ponomarenko16934472012-03-29 15:37:04 +040011651 if($CheckHeadersOnly)
11652 { # skip all removed symbols
Andrey Ponomarenko85043792012-05-14 16:48:07 +040011653 if(my $Lang = $CompleteSignature{1}{$Symbol}{"Lang"})
11654 {
11655 if($Lang eq "C")
11656 { # support for old ABI dumps: missed extern "C" functions
11657 next;
11658 }
11659 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011660 }
Andrey Ponomarenko16934472012-03-29 15:37:04 +040011661 else
11662 {
11663 if(not link_symbol($Symbol, 1, "-Deps"))
11664 { # skip removed inline symbols
11665 next;
11666 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011667 }
11668 }
11669 }
11670 }
Andrey Ponomarenkob8d203d2012-05-25 18:11:07 +040011671 if(not checkDump(1, "2.15"))
11672 {
11673 if($Symbol=~/_IT_E\Z/)
11674 { # _ZN28QExplicitlySharedDataPointerI22QSslCertificatePrivateEC1IT_EERKS_IT_E
11675 next;
11676 }
11677 }
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040011678 if(not $CompleteSignature{1}{$Symbol}{"Class"})
11679 {
11680 if(my $Short = $CompleteSignature{1}{$Symbol}{"ShortName"})
11681 {
11682 if(defined $Constants{2}{$Short})
11683 {
11684 my $Val = $Constants{2}{$Short}{"Value"};
11685 if(defined $Func_ShortName{2}{$Val})
11686 { # old name defined to new
11687 next;
11688 }
11689 }
11690 }
11691
11692 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011693 $RemovedInt{$Level}{$Symbol} = 1;
11694 if($Level eq "Source")
11695 { # search for a source-compatible equivalent
11696 setAlternative($Symbol, $Level);
11697 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011698 }
11699 }
11700}
11701
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011702sub mergeHeaders($)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011703{
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011704 my $Level = $_[0];
11705 foreach my $Symbol (sort keys(%{$AddedInt{$Level}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011706 { # checking added symbols
11707 next if($CompleteSignature{2}{$Symbol}{"PureVirt"});
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040011708 next if($CompleteSignature{2}{$Symbol}{"Private"});
11709 next if(not symbolFilter($Symbol, 2, "Affected", $Level));
Andrey Ponomarenko85043792012-05-14 16:48:07 +040011710 if($Level eq "Binary")
11711 {
11712 if($CompleteSignature{2}{$Symbol}{"InLine"})
11713 {
11714 if(not $CompleteSignature{2}{$Symbol}{"Virt"})
11715 { # skip inline non-virtual functions
11716 next;
11717 }
11718 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011719 }
11720 else
11721 { # Source
11722 if($SourceAlternative_B{$Symbol}) {
11723 next;
11724 }
11725 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011726 %{$CompatProblems{$Level}{$Symbol}{"Added_Symbol"}{""}}=();
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011727 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011728 foreach my $Symbol (sort keys(%{$RemovedInt{$Level}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011729 { # checking removed symbols
11730 next if($CompleteSignature{1}{$Symbol}{"PureVirt"});
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040011731 next if($CompleteSignature{1}{$Symbol}{"Private"});
11732 next if(not symbolFilter($Symbol, 1, "Affected", $Level));
Andrey Ponomarenko85043792012-05-14 16:48:07 +040011733 if($Level eq "Binary")
11734 {
11735 if($CompleteSignature{1}{$Symbol}{"InLine"})
11736 {
11737 if(not $CompleteSignature{1}{$Symbol}{"Virt"})
11738 { # skip inline non-virtual functions
11739 next;
11740 }
11741 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011742 }
11743 else
11744 { # Source
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040011745 if(my $Alt = $SourceAlternative{$Symbol})
11746 {
11747 if(defined $CompleteSignature{1}{$Alt}
11748 and $CompleteSignature{1}{$Symbol}{"Const"})
11749 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040011750 my $Cid = $CompleteSignature{1}{$Symbol}{"Class"};
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040011751 %{$CompatProblems{$Level}{$Symbol}{"Removed_Const_Overload"}{$tr_name{$Symbol}}}=(
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040011752 "Type_Name"=>$TypeInfo{1}{$Cid}{"Name"},
Andrey Ponomarenko85043792012-05-14 16:48:07 +040011753 "Type_Type"=>"Class",
11754 "Target"=>get_Signature($Alt, 1) );
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040011755 }
11756 else
11757 { # do NOT show removed symbol
11758 next;
11759 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011760 }
11761 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011762 %{$CompatProblems{$Level}{$Symbol}{"Removed_Symbol"}{""}}=();
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011763 }
11764}
11765
11766sub addParamNames($)
11767{
11768 my $LibraryVersion = $_[0];
11769 return if(not keys(%AddIntParams));
11770 my $SecondVersion = $LibraryVersion==1?2:1;
11771 foreach my $Interface (sort keys(%{$CompleteSignature{$LibraryVersion}}))
11772 {
11773 next if(not keys(%{$AddIntParams{$Interface}}));
11774 foreach my $ParamPos (sort {int($a)<=>int($b)} keys(%{$CompleteSignature{$LibraryVersion}{$Interface}{"Param"}}))
Andrey Ponomarenko85043792012-05-14 16:48:07 +040011775 { # add absent parameter names
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011776 my $ParamName = $CompleteSignature{$LibraryVersion}{$Interface}{"Param"}{$ParamPos}{"name"};
11777 if($ParamName=~/\Ap\d+\Z/ and my $NewParamName = $AddIntParams{$Interface}{$ParamPos})
Andrey Ponomarenko85043792012-05-14 16:48:07 +040011778 { # names from the external file
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011779 if(defined $CompleteSignature{$SecondVersion}{$Interface}
11780 and defined $CompleteSignature{$SecondVersion}{$Interface}{"Param"}{$ParamPos})
11781 {
11782 if($CompleteSignature{$SecondVersion}{$Interface}{"Param"}{$ParamPos}{"name"}=~/\Ap\d+\Z/) {
11783 $CompleteSignature{$LibraryVersion}{$Interface}{"Param"}{$ParamPos}{"name"} = $NewParamName;
11784 }
11785 }
11786 else {
11787 $CompleteSignature{$LibraryVersion}{$Interface}{"Param"}{$ParamPos}{"name"} = $NewParamName;
11788 }
11789 }
11790 }
11791 }
11792}
11793
11794sub detectChangedTypedefs()
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +040011795{ # detect changed typedefs to show
11796 # correct function signatures
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011797 foreach my $Typedef (keys(%{$Typedef_BaseName{1}}))
11798 {
11799 next if(not $Typedef);
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +040011800 my $BName1 = $Typedef_BaseName{1}{$Typedef};
11801 if(not $BName1 or isAnon($BName1)) {
11802 next;
11803 }
11804 my $BName2 = $Typedef_BaseName{2}{$Typedef};
11805 if(not $BName2 or isAnon($BName2)) {
11806 next;
11807 }
11808 if($BName1 ne $BName2) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011809 $ChangedTypedef{$Typedef} = 1;
11810 }
11811 }
11812}
11813
11814sub get_symbol_suffix($$)
11815{
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011816 my ($Symbol, $Full) = @_;
11817 my ($SN, $SO, $SV) = separate_symbol($Symbol);
11818 $Symbol=$SN;# remove version
11819 my $Signature = $tr_name{$Symbol};
Andrey Ponomarenko16934472012-03-29 15:37:04 +040011820 my $Suffix = substr($Signature, find_center($Signature, "("));
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011821 if(not $Full) {
11822 $Suffix=~s/(\))\s*(const volatile|volatile const|const|volatile)\Z/$1/g;
11823 }
11824 return $Suffix;
11825}
11826
11827sub get_symbol_prefix($$)
11828{
11829 my ($Symbol, $LibVersion) = @_;
11830 my $ShortName = $CompleteSignature{$LibVersion}{$Symbol}{"ShortName"};
11831 if(my $ClassId = $CompleteSignature{$LibVersion}{$Symbol}{"Class"})
11832 { # methods
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040011833 $ShortName = $TypeInfo{$LibVersion}{$ClassId}{"Name"}."::".$ShortName;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011834 }
11835 return $ShortName;
11836}
11837
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011838sub setAlternative($)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011839{
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011840 my $Symbol = $_[0];
11841 my $PSymbol = $Symbol;
11842 if(not defined $CompleteSignature{2}{$PSymbol}
11843 or (not $CompleteSignature{2}{$PSymbol}{"MnglName"}
11844 and not $CompleteSignature{2}{$PSymbol}{"ShortName"}))
11845 { # search for a pair
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040011846 if(my $ShortName = $CompleteSignature{1}{$PSymbol}{"ShortName"})
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011847 {
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040011848 if($CompleteSignature{1}{$PSymbol}{"Data"})
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011849 {
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040011850 if($PSymbol=~s/L(\d+$ShortName(E)\Z)/$1/
11851 or $PSymbol=~s/(\d+$ShortName(E)\Z)/L$1/)
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011852 {
11853 if(defined $CompleteSignature{2}{$PSymbol}
11854 and $CompleteSignature{2}{$PSymbol}{"MnglName"})
11855 {
11856 $SourceAlternative{$Symbol} = $PSymbol;
11857 $SourceAlternative_B{$PSymbol} = $Symbol;
11858 if(not defined $CompleteSignature{1}{$PSymbol}
11859 or not $CompleteSignature{1}{$PSymbol}{"MnglName"}) {
11860 $SourceReplacement{$Symbol} = $PSymbol;
11861 }
11862 }
11863 }
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040011864 }
11865 else
11866 {
11867 foreach my $Sp ("KV", "VK", "K", "V")
11868 {
11869 if($PSymbol=~s/\A_ZN$Sp/_ZN/
11870 or $PSymbol=~s/\A_ZN/_ZN$Sp/)
11871 {
11872 if(defined $CompleteSignature{2}{$PSymbol}
11873 and $CompleteSignature{2}{$PSymbol}{"MnglName"})
11874 {
11875 $SourceAlternative{$Symbol} = $PSymbol;
11876 $SourceAlternative_B{$PSymbol} = $Symbol;
11877 if(not defined $CompleteSignature{1}{$PSymbol}
11878 or not $CompleteSignature{1}{$PSymbol}{"MnglName"}) {
11879 $SourceReplacement{$Symbol} = $PSymbol;
11880 }
11881 }
11882 }
11883 $PSymbol = $Symbol;
11884 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011885 }
11886 }
11887 }
11888 return "";
11889}
11890
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040011891sub getSymKind($$)
11892{
11893 my ($Symbol, $LibVersion) = @_;
11894 if($CompleteSignature{$LibVersion}{$Symbol}{"Data"})
11895 {
11896 return "Global_Data";
11897 }
11898 elsif($CompleteSignature{$LibVersion}{$Symbol}{"Class"})
11899 {
11900 return "Method";
11901 }
11902 return "Function";
11903}
11904
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011905sub mergeSignatures($)
11906{
11907 my $Level = $_[0];
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011908 my %SubProblems = ();
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011909
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011910 mergeBases($Level);
11911
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011912 my %AddedOverloads = ();
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011913 foreach my $Symbol (sort keys(%{$AddedInt{$Level}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011914 { # check all added exported symbols
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011915 if(not $CompleteSignature{2}{$Symbol}{"Header"}) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011916 next;
11917 }
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040011918 if(defined $CompleteSignature{1}{$Symbol}
11919 and $CompleteSignature{1}{$Symbol}{"Header"})
11920 { # double-check added symbol
11921 next;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011922 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +040011923 if(not symbolFilter($Symbol, 2, "Affected", $Level)) {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011924 next;
11925 }
11926 if($Symbol=~/\A(_Z|\?)/)
11927 { # C++
11928 $AddedOverloads{get_symbol_prefix($Symbol, 2)}{get_symbol_suffix($Symbol, 1)} = $Symbol;
11929 }
11930 if(my $OverriddenMethod = $CompleteSignature{2}{$Symbol}{"Override"})
11931 { # register virtual overridings
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040011932 my $Cid = $CompleteSignature{2}{$Symbol}{"Class"};
11933 my $AffectedClass_Name = $TypeInfo{2}{$Cid}{"Name"};
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040011934 if(defined $CompleteSignature{1}{$OverriddenMethod} and $CompleteSignature{1}{$OverriddenMethod}{"Virt"}
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011935 and not $CompleteSignature{1}{$OverriddenMethod}{"Private"})
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040011936 {
11937 if($TName_Tid{1}{$AffectedClass_Name})
11938 { # class should exist in previous version
11939 if(not isCopyingClass($TName_Tid{1}{$AffectedClass_Name}, 1))
11940 { # old v-table is NOT copied by old applications
11941 %{$CompatProblems{$Level}{$OverriddenMethod}{"Overridden_Virtual_Method"}{$tr_name{$Symbol}}}=(
11942 "Type_Name"=>$AffectedClass_Name,
11943 "Type_Type"=>"Class",
11944 "Target"=>get_Signature($Symbol, 2),
11945 "Old_Value"=>get_Signature($OverriddenMethod, 2),
11946 "New_Value"=>get_Signature($Symbol, 2) );
11947 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011948 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011949 }
11950 }
11951 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011952 foreach my $Symbol (sort keys(%{$RemovedInt{$Level}}))
11953 { # check all removed exported symbols
11954 if(not $CompleteSignature{1}{$Symbol}{"Header"}) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011955 next;
11956 }
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040011957 if(defined $CompleteSignature{2}{$Symbol}
11958 and $CompleteSignature{2}{$Symbol}{"Header"})
11959 { # double-check removed symbol
11960 next;
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011961 }
11962 if($CompleteSignature{1}{$Symbol}{"Private"})
11963 { # skip private methods
11964 next;
11965 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +040011966 if(not symbolFilter($Symbol, 1, "Affected", $Level)) {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011967 next;
11968 }
11969 $CheckedSymbols{$Level}{$Symbol} = 1;
11970 if(my $OverriddenMethod = $CompleteSignature{1}{$Symbol}{"Override"})
11971 { # register virtual overridings
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040011972 my $Cid = $CompleteSignature{1}{$Symbol}{"Class"};
11973 my $AffectedClass_Name = $TypeInfo{1}{$Cid}{"Name"};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011974 if(defined $CompleteSignature{2}{$OverriddenMethod}
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040011975 and $CompleteSignature{2}{$OverriddenMethod}{"Virt"})
11976 {
11977 if($TName_Tid{2}{$AffectedClass_Name})
11978 { # class should exist in newer version
11979 if(not isCopyingClass($CompleteSignature{1}{$Symbol}{"Class"}, 1))
11980 { # old v-table is NOT copied by old applications
11981 %{$CompatProblems{$Level}{$Symbol}{"Overridden_Virtual_Method_B"}{$tr_name{$OverriddenMethod}}}=(
11982 "Type_Name"=>$AffectedClass_Name,
11983 "Type_Type"=>"Class",
11984 "Target"=>get_Signature($OverriddenMethod, 1),
11985 "Old_Value"=>get_Signature($Symbol, 1),
11986 "New_Value"=>get_Signature($OverriddenMethod, 1) );
11987 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011988 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011989 }
11990 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011991 if($Level eq "Binary"
11992 and $OSgroup eq "windows")
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011993 { # register the reason of symbol name change
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040011994 if(my $NewSym = $mangled_name{2}{$tr_name{$Symbol}})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011995 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040011996 if($AddedInt{$Level}{$NewSym})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011997 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040011998 if($CompleteSignature{1}{$Symbol}{"Static"} ne $CompleteSignature{2}{$NewSym}{"Static"})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011999 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040012000 if($CompleteSignature{2}{$NewSym}{"Static"})
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012001 {
12002 %{$CompatProblems{$Level}{$Symbol}{"Symbol_Became_Static"}{$tr_name{$Symbol}}}=(
12003 "Target"=>$tr_name{$Symbol},
12004 "Old_Value"=>$Symbol,
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040012005 "New_Value"=>$NewSym );
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012006 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012007 else
12008 {
12009 %{$CompatProblems{$Level}{$Symbol}{"Symbol_Became_NonStatic"}{$tr_name{$Symbol}}}=(
12010 "Target"=>$tr_name{$Symbol},
12011 "Old_Value"=>$Symbol,
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040012012 "New_Value"=>$NewSym );
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012013 }
12014 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040012015 if($CompleteSignature{1}{$Symbol}{"Virt"} ne $CompleteSignature{2}{$NewSym}{"Virt"})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012016 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040012017 if($CompleteSignature{2}{$NewSym}{"Virt"})
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012018 {
12019 %{$CompatProblems{$Level}{$Symbol}{"Symbol_Became_Virtual"}{$tr_name{$Symbol}}}=(
12020 "Target"=>$tr_name{$Symbol},
12021 "Old_Value"=>$Symbol,
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040012022 "New_Value"=>$NewSym );
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012023 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012024 else
12025 {
12026 %{$CompatProblems{$Level}{$Symbol}{"Symbol_Became_NonVirtual"}{$tr_name{$Symbol}}}=(
12027 "Target"=>$tr_name{$Symbol},
12028 "Old_Value"=>$Symbol,
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040012029 "New_Value"=>$NewSym );
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012030 }
12031 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040012032 my $RTId1 = $CompleteSignature{1}{$Symbol}{"Return"};
12033 my $RTId2 = $CompleteSignature{2}{$NewSym}{"Return"};
12034 my $RTName1 = $TypeInfo{1}{$RTId1}{"Name"};
12035 my $RTName2 = $TypeInfo{2}{$RTId2}{"Name"};
12036 if($RTName1 ne $RTName2)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012037 {
12038 my $ProblemType = "Symbol_Changed_Return";
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012039 if($CompleteSignature{1}{$Symbol}{"Data"}) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012040 $ProblemType = "Global_Data_Symbol_Changed_Type";
12041 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012042 %{$CompatProblems{$Level}{$Symbol}{$ProblemType}{$tr_name{$Symbol}}}=(
12043 "Target"=>$tr_name{$Symbol},
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040012044 "Old_Type"=>$RTName1,
12045 "New_Type"=>$RTName2,
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012046 "Old_Value"=>$Symbol,
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040012047 "New_Value"=>$NewSym );
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012048 }
12049 }
12050 }
12051 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012052 if($Symbol=~/\A(_Z|\?)/)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012053 { # C++
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012054 my $Prefix = get_symbol_prefix($Symbol, 1);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012055 if(my @Overloads = sort keys(%{$AddedOverloads{$Prefix}})
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012056 and not $AddedOverloads{$Prefix}{get_symbol_suffix($Symbol, 1)})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012057 { # changed signature: params, "const"-qualifier
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040012058 my $NewSym = $AddedOverloads{$Prefix}{$Overloads[0]};
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012059 if($CompleteSignature{1}{$Symbol}{"Constructor"})
12060 {
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +040012061 if($Symbol=~/(C1E|C2E)/)
12062 {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012063 my $CtorType = $1;
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040012064 $NewSym=~s/(C1E|C2E)/$CtorType/g;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012065 }
12066 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012067 elsif($CompleteSignature{1}{$Symbol}{"Destructor"})
12068 {
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +040012069 if($Symbol=~/(D0E|D1E|D2E)/)
12070 {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012071 my $DtorType = $1;
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040012072 $NewSym=~s/(D0E|D1E|D2E)/$DtorType/g;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012073 }
12074 }
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040012075 my $NS1 = $CompleteSignature{1}{$Symbol}{"NameSpace"};
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040012076 my $NS2 = $CompleteSignature{2}{$NewSym}{"NameSpace"};
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040012077 if((not $NS1 and not $NS2) or ($NS1 and $NS2 and $NS1 eq $NS2))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012078 { # from the same class and namespace
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012079 if($CompleteSignature{1}{$Symbol}{"Const"}
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040012080 and not $CompleteSignature{2}{$NewSym}{"Const"})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012081 { # "const" to non-"const"
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040012082 %{$CompatProblems{$Level}{$Symbol}{"Method_Became_NonConst"}{$tr_name{$Symbol}}}=(
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040012083 "Type_Name"=>$TypeInfo{1}{$CompleteSignature{1}{$Symbol}{"Class"}}{"Name"},
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012084 "Target"=>$tr_name{$Symbol},
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040012085 "New_Signature"=>get_Signature($NewSym, 2),
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012086 "Old_Value"=>$Symbol,
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040012087 "New_Value"=>$NewSym );
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012088 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012089 elsif(not $CompleteSignature{1}{$Symbol}{"Const"}
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040012090 and $CompleteSignature{2}{$NewSym}{"Const"})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012091 { # non-"const" to "const"
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040012092 %{$CompatProblems{$Level}{$Symbol}{"Method_Became_Const"}{$tr_name{$Symbol}}}=(
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012093 "Target"=>$tr_name{$Symbol},
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040012094 "New_Signature"=>get_Signature($NewSym, 2),
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012095 "Old_Value"=>$Symbol,
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040012096 "New_Value"=>$NewSym );
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012097 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012098 if($CompleteSignature{1}{$Symbol}{"Volatile"}
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040012099 and not $CompleteSignature{2}{$NewSym}{"Volatile"})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012100 { # "volatile" to non-"volatile"
12101
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040012102 %{$CompatProblems{$Level}{$Symbol}{"Method_Became_NonVolatile"}{$tr_name{$Symbol}}}=(
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012103 "Target"=>$tr_name{$Symbol},
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040012104 "New_Signature"=>get_Signature($NewSym, 2),
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012105 "Old_Value"=>$Symbol,
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040012106 "New_Value"=>$NewSym );
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012107 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012108 elsif(not $CompleteSignature{1}{$Symbol}{"Volatile"}
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040012109 and $CompleteSignature{2}{$NewSym}{"Volatile"})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012110 { # non-"volatile" to "volatile"
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040012111 %{$CompatProblems{$Level}{$Symbol}{"Method_Became_Volatile"}{$tr_name{$Symbol}}}=(
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012112 "Target"=>$tr_name{$Symbol},
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040012113 "New_Signature"=>get_Signature($NewSym, 2),
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012114 "Old_Value"=>$Symbol,
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040012115 "New_Value"=>$NewSym );
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012116 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040012117 if(get_symbol_suffix($Symbol, 0) ne get_symbol_suffix($NewSym, 0))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012118 { # params list
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012119 %{$CompatProblems{$Level}{$Symbol}{"Symbol_Changed_Parameters"}{$tr_name{$Symbol}}}=(
12120 "Target"=>$tr_name{$Symbol},
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040012121 "New_Signature"=>get_Signature($NewSym, 2),
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012122 "Old_Value"=>$Symbol,
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040012123 "New_Value"=>$NewSym );
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012124 }
12125 }
12126 }
12127 }
12128 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012129 foreach my $Symbol (sort keys(%{$CompleteSignature{1}}))
12130 { # checking symbols
12131 my ($SN, $SS, $SV) = separate_symbol($Symbol);
12132 if($Level eq "Source")
12133 { # remove symbol version
12134 $Symbol=$SN;
12135 }
12136 else
12137 { # Binary
12138 if(not $SV)
12139 { # symbol without version
12140 if(my $VSym = $SymVer{1}{$Symbol})
12141 { # the symbol is linked with versioned symbol
12142 if($CompleteSignature{2}{$VSym}{"MnglName"})
12143 { # show report for symbol@ver only
12144 next;
12145 }
12146 elsif(not link_symbol($VSym, 2, "-Deps"))
12147 { # changed version: sym@v1 to sym@v2
12148 # do NOT show report for symbol
12149 next;
12150 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012151 }
12152 }
12153 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012154 my $PSymbol = $Symbol;
12155 if($Level eq "Source"
12156 and my $S = $SourceReplacement{$Symbol})
12157 { # take a source-compatible replacement function
12158 $PSymbol = $S;
12159 }
12160 if($CompleteSignature{1}{$Symbol}{"Private"})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012161 { # private symbols
12162 next;
12163 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012164 if(not defined $CompleteSignature{1}{$Symbol}
12165 or not defined $CompleteSignature{2}{$PSymbol})
12166 { # no info
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012167 next;
12168 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012169 if(not $CompleteSignature{1}{$Symbol}{"MnglName"}
12170 or not $CompleteSignature{2}{$PSymbol}{"MnglName"})
12171 { # no mangled name
12172 next;
12173 }
12174 if(not $CompleteSignature{1}{$Symbol}{"Header"}
12175 or not $CompleteSignature{2}{$PSymbol}{"Header"})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012176 { # without a header
12177 next;
12178 }
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040012179
12180 if(not $CompleteSignature{1}{$Symbol}{"PureVirt"}
12181 and $CompleteSignature{2}{$PSymbol}{"PureVirt"})
12182 { # became pure
12183 next;
12184 }
12185 if($CompleteSignature{1}{$Symbol}{"PureVirt"}
12186 and not $CompleteSignature{2}{$PSymbol}{"PureVirt"})
12187 { # became non-pure
12188 next;
12189 }
12190
12191 if(not symbolFilter($Symbol, 1, "Affected + InlineVirt", $Level))
12192 { # exported, target, inline virtual and pure virtual
12193 next;
12194 }
12195 if(not symbolFilter($PSymbol, 2, "Affected + InlineVirt", $Level))
12196 { # exported, target, inline virtual and pure virtual
12197 next;
12198 }
12199
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040012200 if(checkDump(1, "2.13") and checkDump(2, "2.13"))
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040012201 {
12202 if($CompleteSignature{1}{$Symbol}{"Data"}
12203 and $CompleteSignature{2}{$PSymbol}{"Data"})
12204 {
12205 my $Value1 = $CompleteSignature{1}{$Symbol}{"Value"};
12206 my $Value2 = $CompleteSignature{2}{$PSymbol}{"Value"};
12207 if(defined $Value1)
12208 {
12209 $Value1 = showVal($Value1, $CompleteSignature{1}{$Symbol}{"Return"}, 1);
12210 if(defined $Value2)
12211 {
12212 $Value2 = showVal($Value2, $CompleteSignature{2}{$PSymbol}{"Return"}, 2);
12213 if($Value1 ne $Value2)
12214 {
12215 %{$CompatProblems{$Level}{$Symbol}{"Global_Data_Value_Changed"}{""}}=(
12216 "Old_Value"=>$Value1,
12217 "New_Value"=>$Value2,
12218 "Target"=>get_Signature($Symbol, 1) );
12219 }
12220 }
12221 }
12222 }
12223 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +040012224
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040012225 if($CompleteSignature{2}{$PSymbol}{"Private"})
12226 {
12227 %{$CompatProblems{$Level}{$Symbol}{getSymKind($Symbol, 1)."_Became_Private"}{""}}=(
12228 "Target"=>get_Signature_M($PSymbol, 2) );
12229 }
12230 elsif(not $CompleteSignature{1}{$Symbol}{"Protected"}
12231 and $CompleteSignature{2}{$PSymbol}{"Protected"})
12232 {
12233 %{$CompatProblems{$Level}{$Symbol}{getSymKind($Symbol, 1)."_Became_Protected"}{""}}=(
12234 "Target"=>get_Signature_M($PSymbol, 2) );
12235 }
12236 elsif($CompleteSignature{1}{$Symbol}{"Protected"}
12237 and not $CompleteSignature{2}{$PSymbol}{"Protected"})
12238 {
12239 %{$CompatProblems{$Level}{$Symbol}{getSymKind($Symbol, 1)."_Became_Public"}{""}}=(
12240 "Target"=>get_Signature_M($PSymbol, 2) );
12241 }
12242
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012243 # checking virtual table
Andrey Ponomarenko16934472012-03-29 15:37:04 +040012244 mergeVirtualTables($Symbol, $Level);
12245
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012246 if($COMPILE_ERRORS)
12247 { # if some errors occurred at the compiling stage
12248 # then some false positives can be skipped here
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012249 if(not $CompleteSignature{1}{$Symbol}{"Data"} and $CompleteSignature{2}{$PSymbol}{"Data"}
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040012250 and not $GlobalDataObject{2}{$Symbol})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012251 { # missed information about parameters in newer version
12252 next;
12253 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040012254 if($CompleteSignature{1}{$Symbol}{"Data"} and not $GlobalDataObject{1}{$Symbol}
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012255 and not $CompleteSignature{2}{$PSymbol}{"Data"})
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040012256 { # missed information about parameters in older version
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012257 next;
12258 }
12259 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012260 my ($MnglName, $VersionSpec, $SymbolVersion) = separate_symbol($Symbol);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012261 # checking attributes
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012262 if($CompleteSignature{2}{$PSymbol}{"Static"}
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040012263 and not $CompleteSignature{1}{$Symbol}{"Static"} and $Symbol=~/\A(_Z|\?)/)
12264 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012265 %{$CompatProblems{$Level}{$Symbol}{"Method_Became_Static"}{""}}=(
12266 "Target"=>get_Signature($Symbol, 1)
12267 );
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012268 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012269 elsif(not $CompleteSignature{2}{$PSymbol}{"Static"}
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040012270 and $CompleteSignature{1}{$Symbol}{"Static"} and $Symbol=~/\A(_Z|\?)/)
12271 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012272 %{$CompatProblems{$Level}{$Symbol}{"Method_Became_NonStatic"}{""}}=(
12273 "Target"=>get_Signature($Symbol, 1)
12274 );
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012275 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012276 if(($CompleteSignature{1}{$Symbol}{"Virt"} and $CompleteSignature{2}{$PSymbol}{"Virt"})
12277 or ($CompleteSignature{1}{$Symbol}{"PureVirt"} and $CompleteSignature{2}{$PSymbol}{"PureVirt"}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012278 { # relative position of virtual and pure virtual methods
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012279 if($Level eq "Binary")
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012280 {
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040012281 if(defined $CompleteSignature{1}{$Symbol}{"RelPos"} and defined $CompleteSignature{2}{$PSymbol}{"RelPos"}
12282 and $CompleteSignature{1}{$Symbol}{"RelPos"}!=$CompleteSignature{2}{$PSymbol}{"RelPos"})
12283 { # top-level virtual methods only
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012284 my $Class_Id = $CompleteSignature{1}{$Symbol}{"Class"};
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040012285 my $Class_Name = $TypeInfo{1}{$Class_Id}{"Name"};
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040012286 if(defined $VirtualTable{1}{$Class_Name} and defined $VirtualTable{2}{$Class_Name}
12287 and $VirtualTable{1}{$Class_Name}{$Symbol}!=$VirtualTable{2}{$Class_Name}{$Symbol})
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012288 { # check the absolute position of virtual method (including added and removed methods)
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040012289 my %Class_Type = get_Type($Class_Id, 1);
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012290 my $ProblemType = "Virtual_Method_Position";
12291 if($CompleteSignature{1}{$Symbol}{"PureVirt"}) {
12292 $ProblemType = "Pure_Virtual_Method_Position";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012293 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012294 if(isUsedClass($Class_Id, 1, $Level))
12295 {
12296 my @Affected = ($Symbol, keys(%{$OverriddenMethods{1}{$Symbol}}));
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040012297 foreach my $ASymbol (@Affected)
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012298 {
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040012299 if(not symbolFilter($ASymbol, 1, "Affected", $Level)) {
12300 next;
12301 }
12302 %{$CompatProblems{$Level}{$ASymbol}{$ProblemType}{$tr_name{$MnglName}}}=(
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012303 "Type_Name"=>$Class_Type{"Name"},
12304 "Type_Type"=>"Class",
12305 "Old_Value"=>$CompleteSignature{1}{$Symbol}{"RelPos"},
12306 "New_Value"=>$CompleteSignature{2}{$PSymbol}{"RelPos"},
12307 "Target"=>get_Signature($Symbol, 1) );
12308 }
Andrey Ponomarenko16934472012-03-29 15:37:04 +040012309 $VTableChanged_M{$Class_Type{"Name"}} = 1;
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012310 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012311 }
12312 }
12313 }
12314 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012315 if($CompleteSignature{1}{$Symbol}{"PureVirt"}
12316 or $CompleteSignature{2}{$PSymbol}{"PureVirt"})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012317 { # do NOT check type changes in pure virtuals
12318 next;
12319 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012320 $CheckedSymbols{$Level}{$Symbol}=1;
12321 if($Symbol=~/\A(_Z|\?)/
12322 or keys(%{$CompleteSignature{1}{$Symbol}{"Param"}})==keys(%{$CompleteSignature{2}{$PSymbol}{"Param"}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012323 { # C/C++: changes in parameters
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012324 foreach my $ParamPos (sort {int($a) <=> int($b)} keys(%{$CompleteSignature{1}{$Symbol}{"Param"}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012325 { # checking parameters
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012326 mergeParameters($Symbol, $PSymbol, $ParamPos, $ParamPos, $Level);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012327 }
12328 }
12329 else
12330 { # C: added/removed parameters
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012331 foreach my $ParamPos (sort {int($a) <=> int($b)} keys(%{$CompleteSignature{2}{$PSymbol}{"Param"}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012332 { # checking added parameters
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040012333 my $PType2_Id = $CompleteSignature{2}{$PSymbol}{"Param"}{$ParamPos}{"type"};
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040012334 my $PType2_Name = $TypeInfo{2}{$PType2_Id}{"Name"};
12335 last if($PType2_Name eq "...");
12336 my $PName = $CompleteSignature{2}{$PSymbol}{"Param"}{$ParamPos}{"name"};
12337 my $PName_Old = (defined $CompleteSignature{1}{$Symbol}{"Param"}{$ParamPos})?$CompleteSignature{1}{$Symbol}{"Param"}{$ParamPos}{"name"}:"";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012338 my $ParamPos_Prev = "-1";
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040012339 if($PName=~/\Ap\d+\Z/i)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012340 { # added unnamed parameter ( pN )
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040012341 my @Positions1 = find_ParamPair_Pos_byTypeAndPos($PType2_Name, $ParamPos, "backward", $Symbol, 1);
12342 my @Positions2 = find_ParamPair_Pos_byTypeAndPos($PType2_Name, $ParamPos, "backward", $Symbol, 2);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012343 if($#Positions1==-1 or $#Positions2>$#Positions1) {
12344 $ParamPos_Prev = "lost";
12345 }
12346 }
12347 else {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040012348 $ParamPos_Prev = find_ParamPair_Pos_byName($PName, $Symbol, 1);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012349 }
12350 if($ParamPos_Prev eq "lost")
12351 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012352 if($ParamPos>keys(%{$CompleteSignature{1}{$Symbol}{"Param"}})-1)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012353 {
12354 my $ProblemType = "Added_Parameter";
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040012355 if($PName=~/\Ap\d+\Z/) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012356 $ProblemType = "Added_Unnamed_Parameter";
12357 }
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040012358 %{$CompatProblems{$Level}{$Symbol}{$ProblemType}{showPos($ParamPos)." Parameter"}}=(
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040012359 "Target"=>$PName,
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012360 "Param_Pos"=>$ParamPos,
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040012361 "Param_Type"=>$PType2_Name,
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012362 "New_Signature"=>get_Signature($Symbol, 2) );
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012363 }
12364 else
12365 {
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +040012366 my %ParamType_Pure = get_PureType($PType2_Id, $TypeInfo{2});
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040012367 my $PairType_Id = $CompleteSignature{1}{$Symbol}{"Param"}{$ParamPos}{"type"};
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +040012368 my %PairType_Pure = get_PureType($PairType_Id, $TypeInfo{1});
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040012369 if(($ParamType_Pure{"Name"} eq $PairType_Pure{"Name"} or $PType2_Name eq $TypeInfo{1}{$PairType_Id}{"Name"})
12370 and find_ParamPair_Pos_byName($PName_Old, $Symbol, 2) eq "lost")
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012371 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040012372 if($PName_Old!~/\Ap\d+\Z/ and $PName!~/\Ap\d+\Z/)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012373 {
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040012374 %{$CompatProblems{$Level}{$Symbol}{"Renamed_Parameter"}{showPos($ParamPos)." Parameter"}}=(
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040012375 "Target"=>$PName_Old,
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012376 "Param_Pos"=>$ParamPos,
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040012377 "Param_Type"=>$PType2_Name,
12378 "Old_Value"=>$PName_Old,
12379 "New_Value"=>$PName,
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012380 "New_Signature"=>get_Signature($Symbol, 2) );
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012381 }
12382 }
12383 else
12384 {
12385 my $ProblemType = "Added_Middle_Parameter";
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040012386 if($PName=~/\Ap\d+\Z/) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012387 $ProblemType = "Added_Middle_Unnamed_Parameter";
12388 }
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040012389 %{$CompatProblems{$Level}{$Symbol}{$ProblemType}{showPos($ParamPos)." Parameter"}}=(
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040012390 "Target"=>$PName,
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012391 "Param_Pos"=>$ParamPos,
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040012392 "Param_Type"=>$PType2_Name,
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012393 "New_Signature"=>get_Signature($Symbol, 2) );
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012394 }
12395 }
12396 }
12397 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012398 foreach my $ParamPos (sort {int($a) <=> int($b)} keys(%{$CompleteSignature{1}{$Symbol}{"Param"}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012399 { # check relevant parameters
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040012400 my $PType1_Id = $CompleteSignature{1}{$Symbol}{"Param"}{$ParamPos}{"type"};
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012401 my $ParamName1 = $CompleteSignature{1}{$Symbol}{"Param"}{$ParamPos}{"name"};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012402 # FIXME: find relevant parameter by name
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012403 if(defined $CompleteSignature{2}{$PSymbol}{"Param"}{$ParamPos})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012404 {
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040012405 my $PType2_Id = $CompleteSignature{2}{$PSymbol}{"Param"}{$ParamPos}{"type"};
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012406 my $ParamName2 = $CompleteSignature{2}{$PSymbol}{"Param"}{$ParamPos}{"name"};
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040012407 if($TypeInfo{1}{$PType1_Id}{"Name"} eq $TypeInfo{2}{$PType2_Id}{"Name"}
12408 or ($ParamName1!~/\Ap\d+\Z/i and $ParamName1 eq $ParamName2)) {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012409 mergeParameters($Symbol, $PSymbol, $ParamPos, $ParamPos, $Level);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012410 }
12411 }
12412 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012413 foreach my $ParamPos (sort {int($a) <=> int($b)} keys(%{$CompleteSignature{1}{$Symbol}{"Param"}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012414 { # checking removed parameters
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040012415 my $PType1_Id = $CompleteSignature{1}{$Symbol}{"Param"}{$ParamPos}{"type"};
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040012416 my $PType1_Name = $TypeInfo{1}{$PType1_Id}{"Name"};
12417 last if($PType1_Name eq "...");
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012418 my $Parameter_Name = $CompleteSignature{1}{$Symbol}{"Param"}{$ParamPos}{"name"};
12419 my $Parameter_NewName = (defined $CompleteSignature{2}{$PSymbol}{"Param"}{$ParamPos})?$CompleteSignature{2}{$PSymbol}{"Param"}{$ParamPos}{"name"}:"";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012420 my $ParamPos_New = "-1";
12421 if($Parameter_Name=~/\Ap\d+\Z/i)
12422 { # removed unnamed parameter ( pN )
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040012423 my @Positions1 = find_ParamPair_Pos_byTypeAndPos($PType1_Name, $ParamPos, "forward", $Symbol, 1);
12424 my @Positions2 = find_ParamPair_Pos_byTypeAndPos($PType1_Name, $ParamPos, "forward", $Symbol, 2);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012425 if($#Positions2==-1 or $#Positions2<$#Positions1) {
12426 $ParamPos_New = "lost";
12427 }
12428 }
12429 else {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012430 $ParamPos_New = find_ParamPair_Pos_byName($Parameter_Name, $Symbol, 2);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012431 }
12432 if($ParamPos_New eq "lost")
12433 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012434 if($ParamPos>keys(%{$CompleteSignature{2}{$PSymbol}{"Param"}})-1)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012435 {
12436 my $ProblemType = "Removed_Parameter";
12437 if($Parameter_Name=~/\Ap\d+\Z/) {
12438 $ProblemType = "Removed_Unnamed_Parameter";
12439 }
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040012440 %{$CompatProblems{$Level}{$Symbol}{$ProblemType}{showPos($ParamPos)." Parameter"}}=(
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012441 "Target"=>$Parameter_Name,
12442 "Param_Pos"=>$ParamPos,
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040012443 "Param_Type"=>$PType1_Name,
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012444 "New_Signature"=>get_Signature($Symbol, 2) );
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012445 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012446 elsif($ParamPos<keys(%{$CompleteSignature{1}{$Symbol}{"Param"}})-1)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012447 {
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +040012448 my %ParamType_Pure = get_PureType($PType1_Id, $TypeInfo{1});
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040012449 my $PairType_Id = $CompleteSignature{2}{$PSymbol}{"Param"}{$ParamPos}{"type"};
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +040012450 my %PairType_Pure = get_PureType($PairType_Id, $TypeInfo{2});
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040012451 if(($ParamType_Pure{"Name"} eq $PairType_Pure{"Name"} or $PType1_Name eq $TypeInfo{2}{$PairType_Id}{"Name"})
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012452 and find_ParamPair_Pos_byName($Parameter_NewName, $Symbol, 1) eq "lost")
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012453 {
12454 if($Parameter_NewName!~/\Ap\d+\Z/ and $Parameter_Name!~/\Ap\d+\Z/)
12455 {
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040012456 %{$CompatProblems{$Level}{$Symbol}{"Renamed_Parameter"}{showPos($ParamPos)." Parameter"}}=(
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012457 "Target"=>$Parameter_Name,
12458 "Param_Pos"=>$ParamPos,
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040012459 "Param_Type"=>$PType1_Name,
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012460 "Old_Value"=>$Parameter_Name,
12461 "New_Value"=>$Parameter_NewName,
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012462 "New_Signature"=>get_Signature($Symbol, 2) );
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012463 }
12464 }
12465 else
12466 {
12467 my $ProblemType = "Removed_Middle_Parameter";
12468 if($Parameter_Name=~/\Ap\d+\Z/) {
12469 $ProblemType = "Removed_Middle_Unnamed_Parameter";
12470 }
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040012471 %{$CompatProblems{$Level}{$Symbol}{$ProblemType}{showPos($ParamPos)." Parameter"}}=(
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012472 "Target"=>$Parameter_Name,
12473 "Param_Pos"=>$ParamPos,
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040012474 "Param_Type"=>$PType1_Name,
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012475 "New_Signature"=>get_Signature($Symbol, 2) );
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012476 }
12477 }
12478 }
12479 }
12480 }
12481 # checking return type
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012482 my $ReturnType1_Id = $CompleteSignature{1}{$Symbol}{"Return"};
12483 my $ReturnType2_Id = $CompleteSignature{2}{$PSymbol}{"Return"};
12484 %SubProblems = detectTypeChange($ReturnType1_Id, $ReturnType2_Id, "Return", $Level);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012485 foreach my $SubProblemType (keys(%SubProblems))
12486 {
12487 my $New_Value = $SubProblems{$SubProblemType}{"New_Value"};
12488 my $Old_Value = $SubProblems{$SubProblemType}{"Old_Value"};
12489 my $NewProblemType = $SubProblemType;
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040012490 my $AddProblemType = undef;
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +040012491
12492 if($SubProblemType eq "Return_Type_And_Size"
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012493 and $CompleteSignature{1}{$Symbol}{"Data"}) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012494 $NewProblemType = "Global_Data_Type_And_Size";
12495 }
12496 elsif($SubProblemType eq "Return_Type")
12497 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012498 if($CompleteSignature{1}{$Symbol}{"Data"})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012499 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012500 if(removedQual($Old_Value, $New_Value, "const"))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012501 { # const -> non-const global data
12502 $NewProblemType = "Global_Data_Became_Non_Const";
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040012503 $AddProblemType = "Global_Data_Type";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012504 }
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040012505 elsif(addedQual($Old_Value, $New_Value, "const"))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012506 { # non-const -> const global data
12507 $NewProblemType = "Global_Data_Became_Const";
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040012508 $AddProblemType = "Global_Data_Type";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012509 }
12510 else {
12511 $NewProblemType = "Global_Data_Type";
12512 }
12513 }
12514 else
12515 {
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040012516 if(addedQual($Old_Value, $New_Value, "const"))
12517 {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012518 $NewProblemType = "Return_Type_Became_Const";
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040012519 $AddProblemType = "Return_Type";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012520 }
12521 }
12522 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012523 elsif($SubProblemType eq "Return_Type_Format")
12524 {
12525 if($CompleteSignature{1}{$Symbol}{"Data"}) {
12526 $NewProblemType = "Global_Data_Type_Format";
12527 }
12528 }
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +040012529 if($Level eq "Binary"
12530 and not $CompleteSignature{1}{$Symbol}{"Data"})
12531 {
12532 my ($Arch1, $Arch2) = (getArch(1), getArch(2));
12533 if($Arch1 eq "unknown" or $Arch2 eq "unknown")
12534 { # if one of the architectures is unknown
12535 # then set other arhitecture to unknown too
12536 ($Arch1, $Arch2) = ("unknown", "unknown");
12537 }
12538 my (%Conv1, %Conv2) = ();
12539 if($UseConv_Real{1} and $UseConv_Real{1})
12540 {
12541 %Conv1 = callingConvention_R_Real($CompleteSignature{1}{$Symbol});
12542 %Conv2 = callingConvention_R_Real($CompleteSignature{2}{$PSymbol});
12543 }
12544 else
12545 {
12546 %Conv1 = callingConvention_R_Model($CompleteSignature{1}{$Symbol}, $TypeInfo{1}, $Arch1, $OStarget, $WORD_SIZE{1});
12547 %Conv2 = callingConvention_R_Model($CompleteSignature{2}{$PSymbol}, $TypeInfo{2}, $Arch2, $OStarget, $WORD_SIZE{2});
12548 }
12549
12550 if($SubProblemType eq "Return_Type_Became_Void")
12551 {
12552 if(keys(%{$CompleteSignature{1}{$Symbol}{"Param"}}))
12553 { # parameters stack has been affected
12554 if($Conv1{"Method"} eq "stack") {
12555 $NewProblemType = "Return_Type_Became_Void_And_Stack_Layout";
12556 }
12557 elsif($Conv1{"Hidden"}) {
12558 $NewProblemType = "Return_Type_Became_Void_And_Register";
12559 }
12560 }
12561 }
12562 elsif($SubProblemType eq "Return_Type_From_Void")
12563 {
12564 if(keys(%{$CompleteSignature{1}{$Symbol}{"Param"}}))
12565 { # parameters stack has been affected
12566 if($Conv2{"Method"} eq "stack") {
12567 $NewProblemType = "Return_Type_From_Void_And_Stack_Layout";
12568 }
12569 elsif($Conv2{"Hidden"}) {
12570 $NewProblemType = "Return_Type_From_Void_And_Register";
12571 }
12572 }
12573 }
12574 elsif($SubProblemType eq "Return_Type"
12575 or $SubProblemType eq "Return_Type_And_Size"
12576 or $SubProblemType eq "Return_Type_Format")
12577 {
12578 if($Conv1{"Method"} ne $Conv2{"Method"})
12579 {
12580 if($Conv1{"Method"} eq "stack")
12581 { # returns in a register instead of a hidden first parameter
12582 $NewProblemType = "Return_Type_From_Stack_To_Register";
12583 }
12584 else {
12585 $NewProblemType = "Return_Type_From_Register_To_Stack";
12586 }
12587 }
12588 else
12589 {
12590 if($Conv1{"Method"} eq "reg")
12591 {
12592 if($Conv1{"Registers"} ne $Conv2{"Registers"})
12593 {
12594 if($Conv1{"Hidden"}) {
12595 $NewProblemType = "Return_Type_And_Register_Was_Hidden_Parameter";
12596 }
12597 elsif($Conv2{"Hidden"}) {
12598 $NewProblemType = "Return_Type_And_Register_Became_Hidden_Parameter";
12599 }
12600 else {
12601 $NewProblemType = "Return_Type_And_Register";
12602 }
12603 }
12604 }
12605 }
12606 }
12607 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012608 @{$CompatProblems{$Level}{$Symbol}{$NewProblemType}{"retval"}}{keys(%{$SubProblems{$SubProblemType}})} = values %{$SubProblems{$SubProblemType}};
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040012609 if(defined $AddProblemType) {
12610 @{$CompatProblems{$Level}{$Symbol}{$AddProblemType}{"retval"}}{keys(%{$SubProblems{$SubProblemType}})} = values %{$SubProblems{$SubProblemType}};
12611 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012612 }
12613 if($ReturnType1_Id and $ReturnType2_Id)
12614 {
12615 @RecurTypes = ();
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040012616 %SubProblems = mergeTypes($ReturnType1_Id, $ReturnType2_Id, $Level);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012617 foreach my $SubProblemType (keys(%SubProblems))
12618 { # add "Global_Data_Size" problem
12619 my $New_Value = $SubProblems{$SubProblemType}{"New_Value"};
12620 my $Old_Value = $SubProblems{$SubProblemType}{"Old_Value"};
12621 if($SubProblemType eq "DataType_Size"
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012622 and $CompleteSignature{1}{$Symbol}{"Data"}
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040012623 and get_PLevel($ReturnType1_Id, 1)==0)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012624 { # add a new problem
12625 %{$SubProblems{"Global_Data_Size"}} = %{$SubProblems{$SubProblemType}};
12626 }
12627 }
12628 foreach my $SubProblemType (keys(%SubProblems))
12629 {
12630 foreach my $SubLocation (keys(%{$SubProblems{$SubProblemType}}))
12631 {
12632 my $NewLocation = ($SubLocation)?"retval->".$SubLocation:"retval";
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012633 %{$CompatProblems{$Level}{$Symbol}{$SubProblemType}{$NewLocation}}=(
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040012634 "Return_Type_Name"=>$TypeInfo{1}{$ReturnType1_Id}{"Name"} );
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012635 @{$CompatProblems{$Level}{$Symbol}{$SubProblemType}{$NewLocation}}{keys(%{$SubProblems{$SubProblemType}{$SubLocation}})} = values %{$SubProblems{$SubProblemType}{$SubLocation}};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012636 if($SubLocation!~/\-\>/) {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040012637 $CompatProblems{$Level}{$Symbol}{$SubProblemType}{$NewLocation}{"Start_Type_Name"} = $TypeInfo{1}{$ReturnType1_Id}{"Name"};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012638 }
12639 }
12640 }
12641 }
12642
12643 # checking object type
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040012644 my $ObjTId1 = $CompleteSignature{1}{$Symbol}{"Class"};
12645 my $ObjTId2 = $CompleteSignature{2}{$PSymbol}{"Class"};
12646 if($ObjTId1 and $ObjTId2
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012647 and not $CompleteSignature{1}{$Symbol}{"Static"})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012648 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040012649 my $ThisPtr1_Id = getTypeIdByName($TypeInfo{1}{$ObjTId1}{"Name"}."*const", 1);
12650 my $ThisPtr2_Id = getTypeIdByName($TypeInfo{2}{$ObjTId2}{"Name"}."*const", 2);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012651 if($ThisPtr1_Id and $ThisPtr2_Id)
12652 {
12653 @RecurTypes = ();
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040012654 %SubProblems = mergeTypes($ThisPtr1_Id, $ThisPtr2_Id, $Level);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012655 foreach my $SubProblemType (keys(%SubProblems))
12656 {
12657 foreach my $SubLocation (keys(%{$SubProblems{$SubProblemType}}))
12658 {
12659 my $NewLocation = ($SubLocation)?"this->".$SubLocation:"this";
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012660 %{$CompatProblems{$Level}{$Symbol}{$SubProblemType}{$NewLocation}}=(
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040012661 "Object_Type_Name"=>$TypeInfo{1}{$ObjTId1}{"Name"} );
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012662 @{$CompatProblems{$Level}{$Symbol}{$SubProblemType}{$NewLocation}}{keys(%{$SubProblems{$SubProblemType}{$SubLocation}})} = values %{$SubProblems{$SubProblemType}{$SubLocation}};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012663 if($SubLocation!~/\-\>/) {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040012664 $CompatProblems{$Level}{$Symbol}{$SubProblemType}{$NewLocation}{"Start_Type_Name"} = $TypeInfo{1}{$ObjTId1}{"Name"};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012665 }
12666 }
12667 }
12668 }
12669 }
12670 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012671 if($Level eq "Binary") {
12672 mergeVTables($Level);
12673 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +040012674 foreach my $Symbol (keys(%{$CompatProblems{$Level}})) {
12675 $CheckedSymbols{$Level}{$Symbol} = 1;
12676 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012677}
12678
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040012679sub rmQuals($$)
12680{
12681 my ($Value, $Qual) = @_;
12682 if(not $Qual) {
12683 return $Value;
12684 }
12685 if($Qual eq "all")
12686 { # all quals
12687 $Qual = "const|volatile|restrict";
12688 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040012689 while($Value=~s/\b$Qual\b//) {
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040012690 $Value = formatName($Value, "T");
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040012691 }
12692 return $Value;
12693}
12694
12695sub cmpBTypes($$$$)
12696{
12697 my ($T1, $T2, $V1, $V2) = @_;
12698 $T1 = uncover_typedefs($T1, $V1);
12699 $T2 = uncover_typedefs($T2, $V2);
12700 return (rmQuals($T1, "all") eq rmQuals($T2, "all"));
12701}
12702
12703sub addedQual($$$)
12704{
12705 my ($Old_Value, $New_Value, $Qual) = @_;
Andrey Ponomarenko85043792012-05-14 16:48:07 +040012706 return removedQual_($New_Value, $Old_Value, 2, 1, $Qual);
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040012707}
12708
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012709sub removedQual($$$)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012710{
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012711 my ($Old_Value, $New_Value, $Qual) = @_;
Andrey Ponomarenko85043792012-05-14 16:48:07 +040012712 return removedQual_($Old_Value, $New_Value, 1, 2, $Qual);
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040012713}
12714
12715sub removedQual_($$$$$)
12716{
12717 my ($Old_Value, $New_Value, $V1, $V2, $Qual) = @_;
12718 $Old_Value = uncover_typedefs($Old_Value, $V1);
12719 $New_Value = uncover_typedefs($New_Value, $V2);
12720 if($Old_Value eq $New_Value)
12721 { # equal types
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012722 return 0;
12723 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040012724 if($Old_Value!~/\b$Qual\b/)
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040012725 { # without a qual
12726 return 0;
12727 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040012728 elsif($New_Value!~/\b$Qual\b/)
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040012729 { # became non-qual
12730 return 1;
12731 }
12732 else
12733 {
12734 my @BQ1 = getQualModel($Old_Value, $Qual);
12735 my @BQ2 = getQualModel($New_Value, $Qual);
12736 foreach (0 .. $#BQ1)
12737 { # removed qual
12738 if($BQ1[$_]==1
12739 and $BQ2[$_]!=1)
12740 {
12741 return 2;
12742 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012743 }
12744 }
12745 return 0;
12746}
12747
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040012748sub getQualModel($$)
12749{
12750 my ($Value, $Qual) = @_;
12751 if(not $Qual) {
12752 return $Value;
12753 }
12754
12755 # cleaning
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040012756 while($Value=~/(\w+)/ and $1 ne $Qual) {
12757 $Value=~s/\b$1\b//g;
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040012758 }
12759 $Value=~s/[^\*\&\w]+//g;
12760
12761 # modeling
12762 # int*const*const == 011
12763 # int**const == 001
12764 my @Model = ();
12765 my @Elems = split(/[\*\&]/, $Value);
12766 if(not @Elems) {
12767 return (0);
12768 }
12769 foreach (@Elems)
12770 {
12771 if($_ eq $Qual) {
12772 push(@Model, 1);
12773 }
12774 else {
12775 push(@Model, 0);
12776 }
12777 }
12778
12779 return @Model;
12780}
12781
12782sub showVal($$$)
12783{
12784 my ($Value, $TypeId, $LibVersion) = @_;
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +040012785 my %PureType = get_PureType($TypeId, $TypeInfo{$LibVersion});
Andrey Ponomarenkoa01311b2012-06-08 17:20:02 +040012786 my $TName = uncover_typedefs($PureType{"Name"}, $LibVersion);
Andrey Ponomarenko01117f12012-06-26 12:23:02 +040012787 if(substr($Value, 0, 2) eq "_Z")
12788 {
12789 if(my $Unmangled = $tr_name{$Value}) {
12790 return $Unmangled;
12791 }
12792 }
Andrey Ponomarenko07aea072012-11-12 16:15:07 +040012793 elsif($TName=~/\A(char(| const)\*|std::(string(| const)|basic_string<char>(|const))(|&))\Z/)
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040012794 { # strings
12795 return "\"$Value\"";
12796 }
Andrey Ponomarenkoa01311b2012-06-08 17:20:02 +040012797 elsif($TName=~/\Achar(| const)\Z/)
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040012798 { # characters
12799 return "\'$Value\'";
12800 }
12801 return $Value;
12802}
12803
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012804sub mergeParameters($$$$$)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012805{
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012806 my ($Symbol, $PSymbol, $ParamPos1, $ParamPos2, $Level) = @_;
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040012807 if(not $Symbol) {
12808 return;
12809 }
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040012810 my $PType1_Id = $CompleteSignature{1}{$Symbol}{"Param"}{$ParamPos1}{"type"};
12811 my $PName1 = $CompleteSignature{1}{$Symbol}{"Param"}{$ParamPos1}{"name"};
12812 my $PType2_Id = $CompleteSignature{2}{$PSymbol}{"Param"}{$ParamPos2}{"type"};
12813 my $PName2 = $CompleteSignature{2}{$PSymbol}{"Param"}{$ParamPos2}{"name"};
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040012814 if(not $PType1_Id
12815 or not $PType2_Id) {
12816 return;
12817 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040012818 my %Type1 = get_Type($PType1_Id, 1);
12819 my %Type2 = get_Type($PType2_Id, 2);
12820 my %BaseType1 = get_BaseType($PType1_Id, 1);
12821 my %BaseType2 = get_BaseType($PType2_Id, 2);
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040012822 my $Parameter_Location = ($PName1)?$PName1:showPos($ParamPos1)." Parameter";
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012823 if($Level eq "Binary")
12824 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040012825 if(checkDump(1, "2.6.1") and checkDump(2, "2.6.1"))
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012826 { # "reg" attribute added in ACC 1.95.1 (dump 2.6.1 format)
12827 if($CompleteSignature{1}{$Symbol}{"Param"}{$ParamPos1}{"reg"}
12828 and not $CompleteSignature{2}{$PSymbol}{"Param"}{$ParamPos2}{"reg"})
12829 {
12830 %{$CompatProblems{$Level}{$Symbol}{"Parameter_Became_Non_Register"}{$Parameter_Location}}=(
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040012831 "Target"=>$PName1,
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012832 "Param_Pos"=>$ParamPos1 );
12833 }
12834 elsif(not $CompleteSignature{1}{$Symbol}{"Param"}{$ParamPos1}{"reg"}
12835 and $CompleteSignature{2}{$PSymbol}{"Param"}{$ParamPos2}{"reg"})
12836 {
12837 %{$CompatProblems{$Level}{$Symbol}{"Parameter_Became_Register"}{$Parameter_Location}}=(
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040012838 "Target"=>$PName1,
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012839 "Param_Pos"=>$ParamPos1 );
12840 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012841 }
12842 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040012843 if(checkDump(1, "2.0") and checkDump(2, "2.0"))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012844 { # "default" attribute added in ACC 1.22 (dump 2.0 format)
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040012845 my $Value_Old = $CompleteSignature{1}{$Symbol}{"Param"}{$ParamPos1}{"default"};
12846 my $Value_New = $CompleteSignature{2}{$PSymbol}{"Param"}{$ParamPos2}{"default"};
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040012847 if(not checkDump(1, "2.13")
12848 and checkDump(2, "2.13"))
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040012849 { # support for old ABI dumps
12850 if(defined $Value_Old and defined $Value_New)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012851 {
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040012852 if($Type1{"Name"} eq "bool"
12853 and $Value_Old eq "false" and $Value_New eq "0")
12854 { # int class::method ( bool p = 0 );
12855 # old ABI dumps: "false"
12856 # new ABI dumps: "0"
12857 $Value_Old = "0";
12858 }
12859 }
12860 }
Andrey Ponomarenko01117f12012-06-26 12:23:02 +040012861 if(not checkDump(1, "2.18")
12862 and checkDump(2, "2.18"))
12863 { # support for old ABI dumps
12864 if(not defined $Value_Old
12865 and substr($Value_New, 0, 2) eq "_Z") {
12866 $Value_Old = $Value_New;
12867 }
12868 }
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040012869 if(defined $Value_Old)
12870 {
12871 $Value_Old = showVal($Value_Old, $PType1_Id, 1);
12872 if(defined $Value_New)
12873 {
12874 $Value_New = showVal($Value_New, $PType2_Id, 2);
12875 if($Value_Old ne $Value_New)
12876 { # FIXME: how to distinguish "0" and 0 (NULL)
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012877 %{$CompatProblems{$Level}{$Symbol}{"Parameter_Default_Value_Changed"}{$Parameter_Location}}=(
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040012878 "Target"=>$PName1,
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012879 "Param_Pos"=>$ParamPos1,
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040012880 "Old_Value"=>$Value_Old,
12881 "New_Value"=>$Value_New );
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012882 }
12883 }
12884 else
12885 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012886 %{$CompatProblems{$Level}{$Symbol}{"Parameter_Default_Value_Removed"}{$Parameter_Location}}=(
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040012887 "Target"=>$PName1,
12888 "Param_Pos"=>$ParamPos1,
12889 "Old_Value"=>$Value_Old );
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012890 }
12891 }
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040012892 elsif(defined $Value_New)
12893 {
12894 $Value_New = showVal($Value_New, $PType2_Id, 2);
12895 %{$CompatProblems{$Level}{$Symbol}{"Parameter_Default_Value_Added"}{$Parameter_Location}}=(
12896 "Target"=>$PName1,
12897 "Param_Pos"=>$ParamPos1,
12898 "New_Value"=>$Value_New );
12899 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012900 }
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040012901 if($PName1 and $PName2 and $PName1 ne $PName2
12902 and $PType1_Id!=-1 and $PType2_Id!=-1
12903 and $PName1!~/\Ap\d+\Z/ and $PName2!~/\Ap\d+\Z/)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012904 { # except unnamed "..." value list (Id=-1)
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040012905 %{$CompatProblems{$Level}{$Symbol}{"Renamed_Parameter"}{showPos($ParamPos1)." Parameter"}}=(
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040012906 "Target"=>$PName1,
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012907 "Param_Pos"=>$ParamPos1,
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040012908 "Param_Type"=>$TypeInfo{1}{$PType1_Id}{"Name"},
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040012909 "Old_Value"=>$PName1,
12910 "New_Value"=>$PName2,
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012911 "New_Signature"=>get_Signature($Symbol, 2) );
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012912 }
12913 # checking type change (replace)
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040012914 my %SubProblems = detectTypeChange($PType1_Id, $PType2_Id, "Parameter", $Level);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012915 foreach my $SubProblemType (keys(%SubProblems))
12916 { # add new problems, remove false alarms
12917 my $New_Value = $SubProblems{$SubProblemType}{"New_Value"};
12918 my $Old_Value = $SubProblems{$SubProblemType}{"Old_Value"};
12919 if($SubProblemType eq "Parameter_Type")
12920 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040012921 if(checkDump(1, "2.6") and checkDump(2, "2.6"))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012922 {
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040012923 if(my $RA = addedQual($Old_Value, $New_Value, "restrict"))
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012924 {
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040012925 %{$SubProblems{"Parameter_Became_Restrict"}} = %{$SubProblems{$SubProblemType}};
12926 if($Level eq "Source"
12927 and cmpBTypes($Old_Value, $New_Value, 1, 2)) {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012928 delete($SubProblems{$SubProblemType});
12929 }
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040012930 }
12931 elsif(my $RR = removedQual($Old_Value, $New_Value, "restrict"))
12932 {
12933 %{$SubProblems{"Parameter_Became_NonRestrict"}} = %{$SubProblems{$SubProblemType}};
12934 if($Level eq "Source"
12935 and cmpBTypes($Old_Value, $New_Value, 1, 2)) {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012936 delete($SubProblems{$SubProblemType});
12937 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012938 }
12939 }
12940 if($Type2{"Type"} eq "Const" and $BaseType2{"Name"} eq $Type1{"Name"}
12941 and $Type1{"Type"}=~/Intrinsic|Class|Struct|Union|Enum/)
12942 { # int to "int const"
12943 delete($SubProblems{$SubProblemType});
12944 }
12945 if($Type1{"Type"} eq "Const" and $BaseType1{"Name"} eq $Type2{"Name"}
12946 and $Type2{"Type"}=~/Intrinsic|Class|Struct|Union|Enum/)
12947 { # "int const" to int
12948 delete($SubProblems{$SubProblemType});
12949 }
12950 }
12951 }
12952 foreach my $SubProblemType (keys(%SubProblems))
12953 { # modify/register problems
12954 my $New_Value = $SubProblems{$SubProblemType}{"New_Value"};
12955 my $Old_Value = $SubProblems{$SubProblemType}{"Old_Value"};
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +040012956 my $New_Size = $SubProblems{$SubProblemType}{"New_Size"};
12957 my $Old_Size = $SubProblems{$SubProblemType}{"Old_Size"};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012958 my $NewProblemType = $SubProblemType;
12959 if($Old_Value eq "..." and $New_Value ne "...")
12960 { # change from "..." to "int"
12961 if($ParamPos1==0)
12962 { # ISO C requires a named argument before "..."
12963 next;
12964 }
12965 $NewProblemType = "Parameter_Became_NonVaList";
12966 }
12967 elsif($New_Value eq "..." and $Old_Value ne "...")
12968 { # change from "int" to "..."
12969 if($ParamPos2==0)
12970 { # ISO C requires a named argument before "..."
12971 next;
12972 }
12973 $NewProblemType = "Parameter_Became_VaList";
12974 }
12975 elsif($SubProblemType eq "Parameter_Type"
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012976 and removedQual($Old_Value, $New_Value, "const"))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012977 { # parameter: "const" to non-"const"
12978 $NewProblemType = "Parameter_Became_Non_Const";
12979 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012980 elsif($Level eq "Binary" and ($SubProblemType eq "Parameter_Type_And_Size"
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +040012981 or $SubProblemType eq "Parameter_Type" or $SubProblemType eq "Parameter_Type_Format"))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012982 {
12983 my ($Arch1, $Arch2) = (getArch(1), getArch(2));
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +040012984 if($Arch1 eq "unknown"
12985 or $Arch2 eq "unknown")
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012986 { # if one of the architectures is unknown
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +040012987 # then set other arhitecture to unknown too
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012988 ($Arch1, $Arch2) = ("unknown", "unknown");
12989 }
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +040012990 my (%Conv1, %Conv2) = ();
12991 if($UseConv_Real{1} and $UseConv_Real{1})
12992 { # real
12993 %Conv1 = callingConvention_P_Real($CompleteSignature{1}{$Symbol}, $ParamPos1);
12994 %Conv2 = callingConvention_P_Real($CompleteSignature{2}{$Symbol}, $ParamPos2);
12995 }
12996 else
12997 { # model
12998 %Conv1 = callingConvention_P_Model($CompleteSignature{1}{$Symbol}, $ParamPos1, $TypeInfo{1}, $Arch1, $OStarget, $WORD_SIZE{1});
12999 %Conv2 = callingConvention_P_Model($CompleteSignature{2}{$Symbol}, $ParamPos2, $TypeInfo{2}, $Arch2, $OStarget, $WORD_SIZE{2});
13000 }
13001 if($Conv1{"Method"} eq $Conv2{"Method"})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013002 {
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +040013003 if($Conv1{"Method"} eq "stack")
13004 {
13005 if($Old_Size ne $New_Size) { # FIXME: isMemPadded, getOffset
13006 $NewProblemType = "Parameter_Type_And_Stack";
13007 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013008 }
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +040013009 elsif($Conv1{"Method"} eq "reg")
13010 {
13011 if($Conv1{"Registers"} ne $Conv2{"Registers"}) {
13012 $NewProblemType = "Parameter_Type_And_Register";
13013 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013014 }
13015 }
13016 else
13017 {
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +040013018 if($Conv1{"Method"} eq "stack") {
13019 $NewProblemType = "Parameter_Type_From_Stack_To_Register";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013020 }
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +040013021 elsif($Conv1{"Method"} eq "register") {
13022 $NewProblemType = "Parameter_Type_From_Register_To_Stack";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013023 }
13024 }
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +040013025 $SubProblems{$SubProblemType}{"Old_Reg"} = $Conv1{"Registers"};
13026 $SubProblems{$SubProblemType}{"New_Reg"} = $Conv2{"Registers"};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013027 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040013028 %{$CompatProblems{$Level}{$Symbol}{$NewProblemType}{$Parameter_Location}}=(
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040013029 "Target"=>$PName1,
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013030 "Param_Pos"=>$ParamPos1,
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040013031 "New_Signature"=>get_Signature($Symbol, 2) );
13032 @{$CompatProblems{$Level}{$Symbol}{$NewProblemType}{$Parameter_Location}}{keys(%{$SubProblems{$SubProblemType}})} = values %{$SubProblems{$SubProblemType}};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013033 }
13034 @RecurTypes = ();
13035 # checking type definition changes
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040013036 my %SubProblems_Merge = mergeTypes($PType1_Id, $PType2_Id, $Level);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013037 foreach my $SubProblemType (keys(%SubProblems_Merge))
13038 {
13039 foreach my $SubLocation (keys(%{$SubProblems_Merge{$SubProblemType}}))
13040 {
13041 my $NewProblemType = $SubProblemType;
13042 if($SubProblemType eq "DataType_Size")
13043 {
13044 my $InitialType_Type = $SubProblems_Merge{$SubProblemType}{$SubLocation}{"InitialType_Type"};
13045 if($InitialType_Type!~/\A(Pointer|Ref)\Z/ and $SubLocation!~/\-\>/)
13046 { # stack has been affected
13047 $NewProblemType = "DataType_Size_And_Stack";
13048 }
13049 }
13050 my $NewLocation = ($SubLocation)?$Parameter_Location."->".$SubLocation:$Parameter_Location;
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040013051 %{$CompatProblems{$Level}{$Symbol}{$NewProblemType}{$NewLocation}}=(
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040013052 "Param_Type"=>$TypeInfo{1}{$PType1_Id}{"Name"},
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013053 "Param_Pos"=>$ParamPos1,
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040013054 "Param_Name"=>$PName1 );
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040013055 @{$CompatProblems{$Level}{$Symbol}{$NewProblemType}{$NewLocation}}{keys(%{$SubProblems_Merge{$SubProblemType}{$SubLocation}})} = values %{$SubProblems_Merge{$SubProblemType}{$SubLocation}};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013056 if($SubLocation!~/\-\>/) {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040013057 $CompatProblems{$Level}{$Symbol}{$NewProblemType}{$NewLocation}{"Start_Type_Name"} = $TypeInfo{1}{$PType1_Id}{"Name"};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013058 }
13059 }
13060 }
13061}
13062
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013063sub find_ParamPair_Pos_byName($$$)
13064{
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040013065 my ($Name, $Symbol, $LibVersion) = @_;
13066 foreach my $ParamPos (sort {int($a)<=>int($b)} keys(%{$CompleteSignature{$LibVersion}{$Symbol}{"Param"}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013067 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040013068 next if(not defined $CompleteSignature{$LibVersion}{$Symbol}{"Param"}{$ParamPos});
13069 if($CompleteSignature{$LibVersion}{$Symbol}{"Param"}{$ParamPos}{"name"} eq $Name)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013070 {
13071 return $ParamPos;
13072 }
13073 }
13074 return "lost";
13075}
13076
13077sub find_ParamPair_Pos_byTypeAndPos($$$$$)
13078{
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040013079 my ($TypeName, $MediumPos, $Order, $Symbol, $LibVersion) = @_;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013080 my @Positions = ();
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040013081 foreach my $ParamPos (sort {int($a)<=>int($b)} keys(%{$CompleteSignature{$LibVersion}{$Symbol}{"Param"}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013082 {
13083 next if($Order eq "backward" and $ParamPos>$MediumPos);
13084 next if($Order eq "forward" and $ParamPos<$MediumPos);
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040013085 next if(not defined $CompleteSignature{$LibVersion}{$Symbol}{"Param"}{$ParamPos});
13086 my $PTypeId = $CompleteSignature{$LibVersion}{$Symbol}{"Param"}{$ParamPos}{"type"};
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040013087 if($TypeInfo{$LibVersion}{$PTypeId}{"Name"} eq $TypeName) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013088 push(@Positions, $ParamPos);
13089 }
13090 }
13091 return @Positions;
13092}
13093
13094sub getTypeIdByName($$)
13095{
13096 my ($TypeName, $Version) = @_;
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040013097 return $TName_Tid{$Version}{formatName($TypeName, "T")};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013098}
13099
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040013100sub checkFormatChange($$$)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013101{
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040013102 my ($Type1_Id, $Type2_Id, $Level) = @_;
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +040013103 my %Type1_Pure = get_PureType($Type1_Id, $TypeInfo{1});
13104 my %Type2_Pure = get_PureType($Type2_Id, $TypeInfo{2});
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013105 if($Type1_Pure{"Name"} eq $Type2_Pure{"Name"})
13106 { # equal types
13107 return 0;
13108 }
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040013109 if($Type1_Pure{"Name"} eq "void")
13110 { # from void* to something
13111 return 0;
13112 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013113 if($Type1_Pure{"Name"}=~/\*/
13114 or $Type2_Pure{"Name"}=~/\*/)
13115 { # compared in detectTypeChange()
13116 return 0;
13117 }
13118 my %FloatType = map {$_=>1} (
13119 "float",
13120 "double",
13121 "long double"
13122 );
13123 if($Type1_Pure{"Type"} ne $Type2_Pure{"Type"})
13124 { # different types
13125 if($Type1_Pure{"Type"} eq "Intrinsic"
13126 and $Type2_Pure{"Type"} eq "Enum")
13127 { # "int" to "enum"
13128 return 0;
13129 }
13130 elsif($Type2_Pure{"Type"} eq "Intrinsic"
13131 and $Type1_Pure{"Type"} eq "Enum")
13132 { # "enum" to "int"
13133 return 0;
13134 }
13135 else
13136 { # "union" to "struct"
13137 # ...
13138 return 1;
13139 }
13140 }
13141 else
13142 {
13143 if($Type1_Pure{"Type"} eq "Intrinsic")
13144 {
13145 if($FloatType{$Type1_Pure{"Name"}}
13146 or $FloatType{$Type2_Pure{"Name"}})
13147 { # "float" to "double"
13148 # "float" to "int"
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040013149 if($Level eq "Source")
13150 { # Safe
13151 return 0;
13152 }
13153 else {
13154 return 1;
13155 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013156 }
13157 }
13158 elsif($Type1_Pure{"Type"}=~/Class|Struct|Union|Enum/)
13159 {
13160 my @Membs1 = keys(%{$Type1_Pure{"Memb"}});
13161 my @Membs2 = keys(%{$Type2_Pure{"Memb"}});
13162 if($#Membs1!=$#Membs2)
13163 { # different number of elements
13164 return 1;
13165 }
13166 if($Type1_Pure{"Type"} eq "Enum")
13167 {
13168 foreach my $Pos (@Membs1)
13169 { # compare elements by name and value
13170 if($Type1_Pure{"Memb"}{$Pos}{"name"} ne $Type2_Pure{"Memb"}{$Pos}{"name"}
13171 or $Type1_Pure{"Memb"}{$Pos}{"value"} ne $Type2_Pure{"Memb"}{$Pos}{"value"})
13172 { # different names
13173 return 1;
13174 }
13175 }
13176 }
13177 else
13178 {
13179 foreach my $Pos (@Membs1)
13180 { # compare elements by type name
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040013181 my $MT1 = $TypeInfo{1}{$Type1_Pure{"Memb"}{$Pos}{"type"}}{"Name"};
13182 my $MT2 = $TypeInfo{2}{$Type2_Pure{"Memb"}{$Pos}{"type"}}{"Name"};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013183 if($MT1 ne $MT2)
13184 { # different types
13185 return 1;
13186 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040013187 if($Level eq "Source")
13188 {
13189 if($Type1_Pure{"Memb"}{$Pos}{"name"} ne $Type2_Pure{"Memb"}{$Pos}{"name"})
13190 { # different names
13191 return 1;
13192 }
13193 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013194 }
13195 }
13196 }
13197 }
13198 return 0;
13199}
13200
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040013201sub detectTypeChange($$$$)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013202{
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040013203 my ($Type1_Id, $Type2_Id, $Prefix, $Level) = @_;
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040013204 if(not $Type1_Id or not $Type2_Id) {
13205 return ();
13206 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013207 my %LocalProblems = ();
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040013208 my %Type1 = get_Type($Type1_Id, 1);
13209 my %Type2 = get_Type($Type2_Id, 2);
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +040013210 my %Type1_Pure = get_PureType($Type1_Id, $TypeInfo{1});
13211 my %Type2_Pure = get_PureType($Type2_Id, $TypeInfo{2});
13212 my %Type1_Base = ($Type1_Pure{"Type"} eq "Array")?get_OneStep_BaseType($Type1_Pure{"Tid"}, $TypeInfo{1}):get_BaseType($Type1_Id, 1);
13213 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 +040013214 my $Type1_PLevel = get_PLevel($Type1_Id, 1);
13215 my $Type2_PLevel = get_PLevel($Type2_Id, 2);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013216 return () if(not $Type1{"Name"} or not $Type2{"Name"});
13217 return () if(not $Type1_Base{"Name"} or not $Type2_Base{"Name"});
13218 return () if($Type1_PLevel eq "" or $Type2_PLevel eq "");
13219 if($Type1_Base{"Name"} ne $Type2_Base{"Name"}
13220 and ($Type1{"Name"} eq $Type2{"Name"} or ($Type1_PLevel>=1 and $Type1_PLevel==$Type2_PLevel
13221 and $Type1_Base{"Name"} ne "void" and $Type2_Base{"Name"} ne "void")))
13222 { # base type change
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040013223 if($Type1{"Name"} eq $Type2{"Name"})
13224 {
13225 if($Type1{"Type"} eq "Typedef" and $Type2{"Type"} eq "Typedef")
13226 { # will be reported in mergeTypes() as typedef problem
13227 return ();
13228 }
13229 my %Typedef_1 = goToFirst($Type1{"Tid"}, 1, "Typedef");
13230 my %Typedef_2 = goToFirst($Type2{"Tid"}, 2, "Typedef");
13231 if(%Typedef_1 and %Typedef_2)
13232 {
13233 if($Typedef_1{"Name"} eq $Typedef_2{"Name"}
13234 and $Typedef_1{"Type"} eq "Typedef" and $Typedef_2{"Type"} eq "Typedef")
13235 { # const Typedef
13236 return ();
13237 }
13238 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013239 }
13240 if($Type1_Base{"Name"}!~/anon\-/ and $Type2_Base{"Name"}!~/anon\-/)
13241 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040013242 if($Level eq "Binary"
13243 and $Type1_Base{"Size"} ne $Type2_Base{"Size"}
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013244 and $Type1_Base{"Size"} and $Type2_Base{"Size"})
13245 {
13246 %{$LocalProblems{$Prefix."_BaseType_And_Size"}}=(
13247 "Old_Value"=>$Type1_Base{"Name"},
13248 "New_Value"=>$Type2_Base{"Name"},
13249 "Old_Size"=>$Type1_Base{"Size"}*$BYTE_SIZE,
13250 "New_Size"=>$Type2_Base{"Size"}*$BYTE_SIZE,
13251 "InitialType_Type"=>$Type1_Pure{"Type"});
13252 }
13253 else
13254 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040013255 if(checkFormatChange($Type1_Base{"Tid"}, $Type2_Base{"Tid"}, $Level))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013256 { # format change
13257 %{$LocalProblems{$Prefix."_BaseType_Format"}}=(
13258 "Old_Value"=>$Type1_Base{"Name"},
13259 "New_Value"=>$Type2_Base{"Name"},
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +040013260 "Old_Size"=>$Type1_Base{"Size"}*$BYTE_SIZE,
13261 "New_Size"=>$Type2_Base{"Size"}*$BYTE_SIZE,
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013262 "InitialType_Type"=>$Type1_Pure{"Type"});
13263 }
13264 elsif(tNameLock($Type1_Base{"Tid"}, $Type2_Base{"Tid"}))
13265 {
13266 %{$LocalProblems{$Prefix."_BaseType"}}=(
13267 "Old_Value"=>$Type1_Base{"Name"},
13268 "New_Value"=>$Type2_Base{"Name"},
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +040013269 "Old_Size"=>$Type1_Base{"Size"}*$BYTE_SIZE,
13270 "New_Size"=>$Type2_Base{"Size"}*$BYTE_SIZE,
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013271 "InitialType_Type"=>$Type1_Pure{"Type"});
13272 }
13273 }
13274 }
13275 }
13276 elsif($Type1{"Name"} ne $Type2{"Name"})
13277 { # type change
13278 if($Type1{"Name"}!~/anon\-/ and $Type2{"Name"}!~/anon\-/)
13279 {
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +040013280 if($Prefix eq "Return"
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013281 and $Type1_Pure{"Name"} eq "void")
13282 {
13283 %{$LocalProblems{"Return_Type_From_Void"}}=(
13284 "New_Value"=>$Type2{"Name"},
13285 "New_Size"=>$Type2{"Size"}*$BYTE_SIZE,
13286 "InitialType_Type"=>$Type1_Pure{"Type"});
13287 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013288 elsif($Prefix eq "Return"
13289 and $Type2_Pure{"Name"} eq "void")
13290 {
13291 %{$LocalProblems{"Return_Type_Became_Void"}}=(
13292 "Old_Value"=>$Type1{"Name"},
13293 "Old_Size"=>$Type1{"Size"}*$BYTE_SIZE,
13294 "InitialType_Type"=>$Type1_Pure{"Type"});
13295 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013296 else
13297 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040013298 if($Level eq "Binary"
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040013299 and $Type1{"Size"} and $Type2{"Size"}
13300 and $Type1{"Size"} ne $Type2{"Size"})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013301 {
13302 %{$LocalProblems{$Prefix."_Type_And_Size"}}=(
13303 "Old_Value"=>$Type1{"Name"},
13304 "New_Value"=>$Type2{"Name"},
13305 "Old_Size"=>$Type1{"Size"}*$BYTE_SIZE,
13306 "New_Size"=>$Type2{"Size"}*$BYTE_SIZE,
13307 "InitialType_Type"=>$Type1_Pure{"Type"});
13308 }
13309 else
13310 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040013311 if(checkFormatChange($Type1_Id, $Type2_Id, $Level))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013312 { # format change
13313 %{$LocalProblems{$Prefix."_Type_Format"}}=(
13314 "Old_Value"=>$Type1{"Name"},
13315 "New_Value"=>$Type2{"Name"},
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +040013316 "Old_Size"=>$Type1{"Size"}*$BYTE_SIZE,
13317 "New_Size"=>$Type2{"Size"}*$BYTE_SIZE,
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013318 "InitialType_Type"=>$Type1_Pure{"Type"});
13319 }
13320 elsif(tNameLock($Type1_Id, $Type2_Id))
13321 { # FIXME: correct this condition
13322 %{$LocalProblems{$Prefix."_Type"}}=(
13323 "Old_Value"=>$Type1{"Name"},
13324 "New_Value"=>$Type2{"Name"},
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +040013325 "Old_Size"=>$Type1{"Size"}*$BYTE_SIZE,
13326 "New_Size"=>$Type2{"Size"}*$BYTE_SIZE,
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013327 "InitialType_Type"=>$Type1_Pure{"Type"});
13328 }
13329 }
13330 }
13331 }
13332 }
13333 if($Type1_PLevel!=$Type2_PLevel)
13334 {
13335 if($Type1{"Name"} ne "void" and $Type1{"Name"} ne "..."
13336 and $Type2{"Name"} ne "void" and $Type2{"Name"} ne "...")
13337 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040013338 if($Level eq "Source")
13339 {
13340 %{$LocalProblems{$Prefix."_PointerLevel"}}=(
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013341 "Old_Value"=>$Type1_PLevel,
13342 "New_Value"=>$Type2_PLevel);
13343 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040013344 else
13345 {
13346 if($Type2_PLevel>$Type1_PLevel) {
13347 %{$LocalProblems{$Prefix."_PointerLevel_Increased"}}=(
13348 "Old_Value"=>$Type1_PLevel,
13349 "New_Value"=>$Type2_PLevel);
13350 }
13351 else {
13352 %{$LocalProblems{$Prefix."_PointerLevel_Decreased"}}=(
13353 "Old_Value"=>$Type1_PLevel,
13354 "New_Value"=>$Type2_PLevel);
13355 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013356 }
13357 }
13358 }
13359 if($Type1_Pure{"Type"} eq "Array")
13360 { # base_type[N] -> base_type[N]
13361 # base_type: older_structure -> typedef to newer_structure
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040013362 my %SubProblems = detectTypeChange($Type1_Base{"Tid"}, $Type2_Base{"Tid"}, $Prefix, $Level);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013363 foreach my $SubProblemType (keys(%SubProblems))
13364 {
13365 $SubProblemType=~s/_Type/_BaseType/g;
13366 next if(defined $LocalProblems{$SubProblemType});
13367 foreach my $Attr (keys(%{$SubProblems{$SubProblemType}})) {
13368 $LocalProblems{$SubProblemType}{$Attr} = $SubProblems{$SubProblemType}{$Attr};
13369 }
13370 }
13371 }
13372 return %LocalProblems;
13373}
13374
13375sub tNameLock($$)
13376{
13377 my ($Tid1, $Tid2) = @_;
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040013378 my $Changed = 0;
13379 if(differentDumps("G"))
13380 { # different GCC versions
13381 $Changed = 1;
13382 }
13383 elsif(differentDumps("V"))
13384 { # different versions of ABI dumps
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040013385 if(not checkDump(1, "2.13")
13386 or not checkDump(2, "2.13"))
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040013387 { # latest names update
13388 # 2.6: added restrict qualifier
13389 # 2.13: added missed typedefs to qualified types
13390 $Changed = 1;
13391 }
13392 }
13393 if($Changed)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013394 { # different formats
13395 if($UseOldDumps)
13396 { # old dumps
13397 return 0;
13398 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040013399 my $TN1 = $TypeInfo{1}{$Tid1}{"Name"};
13400 my $TN2 = $TypeInfo{2}{$Tid2}{"Name"};
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040013401
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040013402 my $TT1 = $TypeInfo{1}{$Tid1}{"Type"};
13403 my $TT2 = $TypeInfo{2}{$Tid2}{"Type"};
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040013404
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040013405 my %Base1 = get_Type($Tid1, 1);
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040013406 while(defined $Base1{"Type"} and $Base1{"Type"} eq "Typedef") {
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +040013407 %Base1 = get_OneStep_BaseType($Base1{"Tid"}, $TypeInfo{1});
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013408 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040013409 my %Base2 = get_Type($Tid2, 2);
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040013410 while(defined $Base2{"Type"} and $Base2{"Type"} eq "Typedef") {
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +040013411 %Base2 = get_OneStep_BaseType($Base2{"Tid"}, $TypeInfo{2});
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013412 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +040013413 my $BName1 = uncover_typedefs($Base1{"Name"}, 1);
13414 my $BName2 = uncover_typedefs($Base2{"Name"}, 2);
13415 if($BName1 eq $BName2)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013416 { # equal base types
13417 return 0;
13418 }
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040013419
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040013420 if(not checkDump(1, "2.13")
13421 or not checkDump(2, "2.13"))
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040013422 { # broken array names in ABI dumps < 2.13
13423 if($TT1 eq "Array"
13424 and $TT2 eq "Array")
13425 {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013426 return 0;
13427 }
13428 }
13429
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040013430 if(not checkDump(1, "2.6")
13431 or not checkDump(2, "2.6"))
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040013432 { # added restrict attribute in 2.6
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040013433 if($TN1!~/\brestrict\b/
13434 and $TN2=~/\brestrict\b/)
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040013435 {
13436 return 0;
13437 }
13438 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013439 }
13440 return 1;
13441}
13442
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040013443sub differentDumps($)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013444{
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040013445 my $Check = $_[0];
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +040013446 if(defined $Cache{"differentDumps"}{$Check}) {
13447 return $Cache{"differentDumps"}{$Check};
13448 }
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040013449 if($UsedDump{1}{"V"} and $UsedDump{2}{"V"})
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040013450 {
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040013451 if($Check eq "G")
13452 {
13453 if(getGccVersion(1) ne getGccVersion(2))
13454 { # different GCC versions
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +040013455 return ($Cache{"differentDumps"}{$Check}=1);
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040013456 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040013457 }
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040013458 if($Check eq "V")
13459 {
13460 if(cmpVersions(formatVersion($UsedDump{1}{"V"}, 2),
13461 formatVersion($UsedDump{2}{"V"}, 2))!=0)
13462 { # different dump versions (skip micro version)
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +040013463 return ($Cache{"differentDumps"}{$Check}=1);
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040013464 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040013465 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013466 }
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +040013467 return ($Cache{"differentDumps"}{$Check}=0);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013468}
13469
13470sub formatVersion($$)
13471{ # cut off version digits
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040013472 my ($V, $Digits) = @_;
13473 my @Elems = split(/\./, $V);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013474 return join(".", splice(@Elems, 0, $Digits));
13475}
13476
13477sub htmlSpecChars($)
13478{
13479 my $Str = $_[0];
Andrey Ponomarenko5c09ef32012-06-14 18:17:33 +040013480 if(not $Str) {
13481 return $Str;
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040013482 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013483 $Str=~s/\&([^#]|\Z)/&amp;$1/g;
13484 $Str=~s/</&lt;/g;
13485 $Str=~s/\-\>/&#45;&gt;/g; # &minus;
13486 $Str=~s/>/&gt;/g;
13487 $Str=~s/([^ ])( )([^ ])/$1\@ALONE_SP\@$3/g;
13488 $Str=~s/ /&#160;/g; # &nbsp;
13489 $Str=~s/\@ALONE_SP\@/ /g;
13490 $Str=~s/\n/<br\/>/g;
13491 $Str=~s/\"/&quot;/g;
13492 $Str=~s/\'/&#39;/g;
13493 return $Str;
13494}
13495
Andrey Ponomarenko5c09ef32012-06-14 18:17:33 +040013496sub xmlSpecChars($)
13497{
13498 my $Str = $_[0];
13499 if(not $Str) {
13500 return $Str;
13501 }
13502
13503 $Str=~s/\&([^#]|\Z)/&amp;$1/g;
13504 $Str=~s/</&lt;/g;
13505 $Str=~s/>/&gt;/g;
13506
13507 $Str=~s/\"/&quot;/g;
13508 $Str=~s/\'/&#39;/g;
13509
13510 return $Str;
13511}
13512
Andrey Ponomarenko01117f12012-06-26 12:23:02 +040013513sub xmlSpecChars_R($)
13514{
13515 my $Str = $_[0];
13516 if(not $Str) {
13517 return $Str;
13518 }
13519
13520 $Str=~s/&amp;/&/g;
13521 $Str=~s/&lt;/</g;
13522 $Str=~s/&gt;/>/g;
13523
13524 $Str=~s/&quot;/"/g;
13525 $Str=~s/&#39;/'/g;
13526
13527 return $Str;
13528}
13529
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013530sub black_name($)
13531{
13532 my $Name = $_[0];
13533 return "<span class='iname_b'>".highLight_Signature($Name)."</span>";
13534}
13535
13536sub highLight_Signature($)
13537{
13538 my $Signature = $_[0];
13539 return highLight_Signature_PPos_Italic($Signature, "", 0, 0, 0);
13540}
13541
13542sub highLight_Signature_Italic_Color($)
13543{
13544 my $Signature = $_[0];
13545 return highLight_Signature_PPos_Italic($Signature, "", 1, 1, 1);
13546}
13547
13548sub separate_symbol($)
13549{
13550 my $Symbol = $_[0];
13551 my ($Name, $Spec, $Ver) = ($Symbol, "", "");
13552 if($Symbol=~/\A([^\@\$\?]+)([\@\$]+)([^\@\$]+)\Z/) {
13553 ($Name, $Spec, $Ver) = ($1, $2, $3);
13554 }
13555 return ($Name, $Spec, $Ver);
13556}
13557
13558sub cut_f_attrs($)
13559{
13560 if($_[0]=~s/(\))((| (const volatile|const|volatile))(| \[static\]))\Z/$1/) {
13561 return $2;
13562 }
13563 return "";
13564}
13565
13566sub highLight_Signature_PPos_Italic($$$$$)
13567{
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040013568 my ($FullSignature, $Param_Pos, $ItalicParams, $ColorParams, $ShowReturn) = @_;
13569 $Param_Pos = "" if(not defined $Param_Pos);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013570 if($CheckObjectsOnly) {
13571 $ItalicParams=$ColorParams=0;
13572 }
13573 my ($Signature, $VersionSpec, $SymbolVersion) = separate_symbol($FullSignature);
13574 my $Return = "";
13575 if($ShowRetVal and $Signature=~s/([^:]):([^:].+?)\Z/$1/g) {
13576 $Return = $2;
13577 }
Andrey Ponomarenko16934472012-03-29 15:37:04 +040013578 my $SCenter = find_center($Signature, "(");
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013579 if(not $SCenter)
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040013580 { # global data
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013581 $Signature = htmlSpecChars($Signature);
13582 $Signature=~s!(\[data\])!<span style='color:Black;font-weight:normal;'>$1</span>!g;
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040013583 $Signature .= (($SymbolVersion)?"<span class='sym_ver'>&#160;$VersionSpec&#160;$SymbolVersion</span>":"");
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013584 if($Return and $ShowReturn) {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040013585 $Signature .= "<span class='sym_p nowrap'> &#160;<b>:</b>&#160;&#160;".htmlSpecChars($Return)."</span>";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013586 }
13587 return $Signature;
13588 }
13589 my ($Begin, $End) = (substr($Signature, 0, $SCenter), "");
13590 $Begin.=" " if($Begin!~/ \Z/);
13591 $End = cut_f_attrs($Signature);
13592 my @Parts = ();
Andrey Ponomarenko07aea072012-11-12 16:15:07 +040013593 my ($Short, $Params) = split_Signature($Signature);
13594 my @SParts = separate_Params($Params, 1, 1);
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040013595 foreach my $Pos (0 .. $#SParts)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013596 {
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040013597 my $Part = $SParts[$Pos];
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013598 $Part=~s/\A\s+|\s+\Z//g;
13599 my ($Part_Styled, $ParamName) = (htmlSpecChars($Part), "");
13600 if($Part=~/\([\*]+(\w+)\)/i) {
13601 $ParamName = $1;#func-ptr
13602 }
13603 elsif($Part=~/(\w+)[\,\)]*\Z/i) {
13604 $ParamName = $1;
13605 }
13606 if(not $ParamName) {
13607 push(@Parts, $Part_Styled);
13608 next;
13609 }
13610 if($ItalicParams and not $TName_Tid{1}{$Part}
13611 and not $TName_Tid{2}{$Part})
13612 {
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040013613 my $Style = "param";
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040013614 if($Param_Pos ne ""
13615 and $Pos==$Param_Pos) {
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040013616 $Style = "focus_p";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013617 }
13618 elsif($ColorParams) {
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040013619 $Style = "color_p";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013620 }
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040013621 $Part_Styled =~ s!(\W)$ParamName([\,\)]|\Z)!$1<span class=\'$Style\'>$ParamName</span>$2!ig;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013622 }
13623 $Part_Styled=~s/,(\w)/, $1/g;
13624 push(@Parts, $Part_Styled);
13625 }
13626 if(@Parts)
13627 {
13628 foreach my $Num (0 .. $#Parts)
13629 {
13630 if($Num==$#Parts)
13631 { # add ")" to the last parameter
13632 $Parts[$Num] = "<span class='nowrap'>".$Parts[$Num]." )</span>";
13633 }
13634 elsif(length($Parts[$Num])<=45) {
13635 $Parts[$Num] = "<span class='nowrap'>".$Parts[$Num]."</span>";
13636 }
13637 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040013638 $Signature = htmlSpecChars($Begin)."<span class='sym_p'>(&#160;".join(" ", @Parts)."</span>".$End;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013639 }
13640 else {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040013641 $Signature = htmlSpecChars($Begin)."<span class='sym_p'>(&#160;)</span>".$End;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013642 }
13643 if($Return and $ShowReturn) {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040013644 $Signature .= "<span class='sym_p nowrap'> &#160;<b>:</b>&#160;&#160;".htmlSpecChars($Return)."</span>";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013645 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040013646 $Signature=~s!\[\]![&#160;]!g;
13647 $Signature=~s!operator=!operator&#160;=!g;
13648 $Signature=~s!(\[in-charge\]|\[not-in-charge\]|\[in-charge-deleting\]|\[static\])!<span class='sym_kind'>$1</span>!g;
13649 return $Signature.(($SymbolVersion)?"<span class='sym_ver'>&#160;$VersionSpec&#160;$SymbolVersion</span>":"");
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013650}
13651
Andrey Ponomarenko07aea072012-11-12 16:15:07 +040013652sub split_Signature($)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013653{
Andrey Ponomarenko07aea072012-11-12 16:15:07 +040013654 my $Signature = $_[0];
13655 if(my $ShortName = substr($Signature, 0, find_center($Signature, "(")))
13656 {
13657 $Signature=~s/\A\Q$ShortName\E\(//g;
13658 cut_f_attrs($Signature);
13659 $Signature=~s/\)\Z//;
13660 return ($ShortName, $Signature);
13661 }
13662
13663 # error
13664 return ($Signature, "");
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013665}
13666
Andrey Ponomarenko07aea072012-11-12 16:15:07 +040013667sub separate_Params($$$)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013668{
Andrey Ponomarenko07aea072012-11-12 16:15:07 +040013669 my ($Params, $Comma, $Sp) = @_;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013670 my @Parts = ();
Andrey Ponomarenko16934472012-03-29 15:37:04 +040013671 my %B = ( "("=>0, "<"=>0, ")"=>0, ">"=>0 );
13672 my $Part = 0;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013673 foreach my $Pos (0 .. length($Params) - 1)
13674 {
Andrey Ponomarenko16934472012-03-29 15:37:04 +040013675 my $S = substr($Params, $Pos, 1);
13676 if(defined $B{$S}) {
Andrey Ponomarenko07aea072012-11-12 16:15:07 +040013677 $B{$S} += 1;
Andrey Ponomarenko16934472012-03-29 15:37:04 +040013678 }
13679 if($S eq "," and
13680 $B{"("}==$B{")"} and $B{"<"}==$B{">"})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013681 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040013682 if($Comma)
13683 { # include comma
Andrey Ponomarenko16934472012-03-29 15:37:04 +040013684 $Parts[$Part] .= $S;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013685 }
Andrey Ponomarenko16934472012-03-29 15:37:04 +040013686 $Part += 1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013687 }
13688 else {
Andrey Ponomarenko16934472012-03-29 15:37:04 +040013689 $Parts[$Part] .= $S;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013690 }
13691 }
Andrey Ponomarenko07aea072012-11-12 16:15:07 +040013692 if(not $Sp)
13693 { # remove spaces
13694 foreach (@Parts)
13695 {
13696 s/\A //g;
13697 s/ \Z//g;
13698 }
13699 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013700 return @Parts;
13701}
13702
Andrey Ponomarenko16934472012-03-29 15:37:04 +040013703sub find_center($$)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013704{
13705 my ($Sign, $Target) = @_;
Andrey Ponomarenko16934472012-03-29 15:37:04 +040013706 my %B = ( "("=>0, "<"=>0, ")"=>0, ">"=>0 );
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013707 my $Center = 0;
Andrey Ponomarenko16934472012-03-29 15:37:04 +040013708 if($Sign=~s/(operator([^\w\s\(\)]+|\(\)))//g)
13709 { # operators
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013710 $Center+=length($1);
13711 }
13712 foreach my $Pos (0 .. length($Sign)-1)
13713 {
13714 my $S = substr($Sign, $Pos, 1);
13715 if($S eq $Target)
13716 {
13717 if($B{"("}==$B{")"}
13718 and $B{"<"}==$B{">"}) {
13719 return $Center;
13720 }
13721 }
13722 if(defined $B{$S}) {
13723 $B{$S}+=1;
13724 }
13725 $Center+=1;
13726 }
13727 return 0;
13728}
13729
13730sub appendFile($$)
13731{
13732 my ($Path, $Content) = @_;
13733 return if(not $Path);
13734 if(my $Dir = get_dirname($Path)) {
13735 mkpath($Dir);
13736 }
Andrey Ponomarenko16934472012-03-29 15:37:04 +040013737 open(FILE, ">>", $Path) || die ("can't open file \'$Path\': $!\n");
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013738 print FILE $Content;
13739 close(FILE);
13740}
13741
13742sub writeFile($$)
13743{
13744 my ($Path, $Content) = @_;
13745 return if(not $Path);
13746 if(my $Dir = get_dirname($Path)) {
13747 mkpath($Dir);
13748 }
Andrey Ponomarenko16934472012-03-29 15:37:04 +040013749 open(FILE, ">", $Path) || die ("can't open file \'$Path\': $!\n");
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013750 print FILE $Content;
13751 close(FILE);
13752}
13753
13754sub readFile($)
13755{
13756 my $Path = $_[0];
13757 return "" if(not $Path or not -f $Path);
Andrey Ponomarenko16934472012-03-29 15:37:04 +040013758 open(FILE, $Path);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013759 local $/ = undef;
13760 my $Content = <FILE>;
13761 close(FILE);
Andrey Ponomarenko85043792012-05-14 16:48:07 +040013762 if($Path!~/\.(tu|class|abi)\Z/) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013763 $Content=~s/\r/\n/g;
13764 }
13765 return $Content;
13766}
13767
13768sub get_filename($)
13769{ # much faster than basename() from File::Basename module
Andrey Ponomarenko85043792012-05-14 16:48:07 +040013770 if(defined $Cache{"get_filename"}{$_[0]}) {
13771 return $Cache{"get_filename"}{$_[0]};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013772 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +040013773 if($_[0] and $_[0]=~/([^\/\\]+)[\/\\]*\Z/) {
13774 return ($Cache{"get_filename"}{$_[0]}=$1);
13775 }
13776 return ($Cache{"get_filename"}{$_[0]}="");
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013777}
13778
13779sub get_dirname($)
13780{ # much faster than dirname() from File::Basename module
Andrey Ponomarenko85043792012-05-14 16:48:07 +040013781 if(defined $Cache{"get_dirname"}{$_[0]}) {
13782 return $Cache{"get_dirname"}{$_[0]};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013783 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +040013784 if($_[0] and $_[0]=~/\A(.*?)[\/\\]+[^\/\\]*[\/\\]*\Z/) {
13785 return ($Cache{"get_dirname"}{$_[0]}=$1);
13786 }
13787 return ($Cache{"get_dirname"}{$_[0]}="");
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013788}
13789
13790sub separate_path($) {
13791 return (get_dirname($_[0]), get_filename($_[0]));
13792}
13793
13794sub esc($)
13795{
13796 my $Str = $_[0];
13797 $Str=~s/([()\[\]{}$ &'"`;,<>\+])/\\$1/g;
13798 return $Str;
13799}
13800
13801sub readLineNum($$)
13802{
13803 my ($Path, $Num) = @_;
13804 return "" if(not $Path or not -f $Path);
Andrey Ponomarenko16934472012-03-29 15:37:04 +040013805 open(FILE, $Path);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013806 foreach (1 ... $Num) {
13807 <FILE>;
13808 }
13809 my $Line = <FILE>;
13810 close(FILE);
13811 return $Line;
13812}
13813
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040013814sub readAttributes($$)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013815{
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040013816 my ($Path, $Num) = @_;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013817 return () if(not $Path or not -f $Path);
13818 my %Attributes = ();
Andrey Ponomarenko85043792012-05-14 16:48:07 +040013819 if(readLineNum($Path, $Num)=~/<!--\s+(.+)\s+-->/)
13820 {
13821 foreach my $AttrVal (split(/;/, $1))
13822 {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013823 if($AttrVal=~/(.+):(.+)/)
13824 {
13825 my ($Name, $Value) = ($1, $2);
13826 $Attributes{$Name} = $Value;
13827 }
13828 }
13829 }
13830 return \%Attributes;
13831}
13832
13833sub is_abs($) {
13834 return ($_[0]=~/\A(\/|\w+:[\/\\])/);
13835}
13836
13837sub get_abs_path($)
13838{ # abs_path() should NOT be called for absolute inputs
13839 # because it can change them
13840 my $Path = $_[0];
13841 if(not is_abs($Path)) {
13842 $Path = abs_path($Path);
13843 }
13844 return $Path;
13845}
13846
13847sub get_OSgroup()
13848{
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +040013849 my $N = $Config{"osname"};
13850 if($N=~/macos|darwin|rhapsody/i) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013851 return "macos";
13852 }
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +040013853 elsif($N=~/freebsd|openbsd|netbsd/i) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013854 return "bsd";
13855 }
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +040013856 elsif($N=~/haiku|beos/i) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013857 return "beos";
13858 }
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +040013859 elsif($N=~/symbian|epoc/i) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013860 return "symbian";
13861 }
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +040013862 elsif($N=~/win/i) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013863 return "windows";
13864 }
13865 else {
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +040013866 return $N;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013867 }
13868}
13869
13870sub getGccVersion($)
13871{
13872 my $LibVersion = $_[0];
13873 if($GCC_VERSION{$LibVersion})
13874 { # dump version
13875 return $GCC_VERSION{$LibVersion};
13876 }
13877 elsif($UsedDump{$LibVersion}{"V"})
13878 { # old-version dumps
13879 return "unknown";
13880 }
13881 my $GccVersion = get_dumpversion($GCC_PATH); # host version
13882 if(not $GccVersion) {
13883 return "unknown";
13884 }
13885 return $GccVersion;
13886}
13887
13888sub showArch($)
13889{
13890 my $Arch = $_[0];
13891 if($Arch eq "arm"
13892 or $Arch eq "mips") {
13893 return uc($Arch);
13894 }
13895 return $Arch;
13896}
13897
13898sub getArch($)
13899{
13900 my $LibVersion = $_[0];
13901 if($CPU_ARCH{$LibVersion})
13902 { # dump version
13903 return $CPU_ARCH{$LibVersion};
13904 }
13905 elsif($UsedDump{$LibVersion}{"V"})
13906 { # old-version dumps
13907 return "unknown";
13908 }
13909 if(defined $Cache{"getArch"}{$LibVersion}) {
13910 return $Cache{"getArch"}{$LibVersion};
13911 }
13912 my $Arch = get_dumpmachine($GCC_PATH); # host version
13913 if(not $Arch) {
13914 return "unknown";
13915 }
13916 if($Arch=~/\A([\w]{3,})(-|\Z)/) {
13917 $Arch = $1;
13918 }
13919 $Arch = "x86" if($Arch=~/\Ai[3-7]86\Z/);
13920 if($OSgroup eq "windows") {
13921 $Arch = "x86" if($Arch=~/win32|mingw32/i);
13922 $Arch = "x86_64" if($Arch=~/win64|mingw64/i);
13923 }
13924 $Cache{"getArch"}{$LibVersion} = $Arch;
13925 return $Arch;
13926}
13927
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040013928sub get_Report_Header($)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013929{
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040013930 my $Level = $_[0];
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013931 my $ArchInfo = " on <span style='color:Blue;'>".showArch(getArch(1))."</span>";
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040013932 if(getArch(1) ne getArch(2)
13933 or getArch(1) eq "unknown"
13934 or $Level eq "Source")
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013935 { # don't show architecture in the header
13936 $ArchInfo="";
13937 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040013938 my $Report_Header = "<h1><span class='nowrap'>";
13939 if($Level eq "Source") {
13940 $Report_Header .= "Source compatibility";
13941 }
13942 elsif($Level eq "Binary") {
13943 $Report_Header .= "Binary compatibility";
13944 }
13945 else {
13946 $Report_Header .= "API compatibility";
13947 }
13948 $Report_Header .= " report for the <span style='color:Blue;'>$TargetLibraryFName</span> $TargetComponent</span>";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013949 $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>";
13950 if($AppPath) {
13951 $Report_Header .= " <span class='nowrap'>&#160;(relating to the portability of application <span style='color:Blue;'>".get_filename($AppPath)."</span>)</span>";
13952 }
13953 $Report_Header .= "</h1>\n";
13954 return $Report_Header;
13955}
13956
13957sub get_SourceInfo()
13958{
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040013959 my ($CheckedHeaders, $CheckedLibs) = ("", "");
13960 if(not $CheckObjectsOnly)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013961 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040013962 $CheckedHeaders = "<a name='Headers'></a><h2>Header Files (".keys(%{$Registered_Headers{1}}).")</h2><hr/>\n";
13963 $CheckedHeaders .= "<div class='h_list'>\n";
13964 foreach my $Header_Path (sort {lc($Registered_Headers{1}{$a}{"Identity"}) cmp lc($Registered_Headers{1}{$b}{"Identity"})} keys(%{$Registered_Headers{1}}))
13965 {
13966 my $Identity = $Registered_Headers{1}{$Header_Path}{"Identity"};
13967 my $Header_Name = get_filename($Identity);
13968 my $Dest_Comment = ($Identity=~/[\/\\]/)?" ($Identity)":"";
13969 $CheckedHeaders .= $Header_Name.$Dest_Comment."<br/>\n";
13970 }
13971 $CheckedHeaders .= "</div>\n";
13972 $CheckedHeaders .= "<br/>$TOP_REF<br/>\n";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013973 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040013974 if(not $CheckHeadersOnly)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013975 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040013976 $CheckedLibs = "<a name='Libs'></a><h2>".ucfirst($SLIB_TYPE)." Libraries (".keys(%{$Library_Symbol{1}}).")</h2><hr/>\n";
13977 $CheckedLibs .= "<div class='lib_list'>\n";
13978 foreach my $Library (sort {lc($a) cmp lc($b)} keys(%{$Library_Symbol{1}}))
13979 {
13980 $Library.=" (.$LIB_EXT)" if($Library!~/\.\w+\Z/);
13981 $CheckedLibs .= $Library."<br/>\n";
13982 }
13983 $CheckedLibs .= "</div>\n";
13984 $CheckedLibs .= "<br/>$TOP_REF<br/>\n";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013985 }
13986 return $CheckedHeaders.$CheckedLibs;
13987}
13988
13989sub get_TypeProblems_Count($$$)
13990{
13991 my ($TypeChanges, $TargetPriority, $Level) = @_;
13992 my $Type_Problems_Count = 0;
13993 foreach my $Type_Name (sort keys(%{$TypeChanges}))
13994 {
13995 my %Kinds_Target = ();
13996 foreach my $Kind (keys(%{$TypeChanges->{$Type_Name}}))
13997 {
13998 foreach my $Location (keys(%{$TypeChanges->{$Type_Name}{$Kind}}))
13999 {
14000 my $Target = $TypeChanges->{$Type_Name}{$Kind}{$Location}{"Target"};
14001 my $Priority = getProblemSeverity($Level, $Kind);
14002 next if($Priority ne $TargetPriority);
14003 if($Kinds_Target{$Kind}{$Target}) {
14004 next;
14005 }
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040014006 if(cmpSeverities($Type_MaxSeverity{$Level}{$Type_Name}{$Kind}{$Target}, $Priority))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014007 { # select a problem with the highest priority
14008 next;
14009 }
14010 $Kinds_Target{$Kind}{$Target} = 1;
14011 $Type_Problems_Count += 1;
14012 }
14013 }
14014 }
14015 return $Type_Problems_Count;
14016}
14017
14018sub get_Summary($)
14019{
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014020 my $Level = $_[0];
14021 my ($Added, $Removed, $I_Problems_High, $I_Problems_Medium, $I_Problems_Low, $T_Problems_High,
14022 $C_Problems_Low, $T_Problems_Medium, $T_Problems_Low, $I_Other, $T_Other) = (0,0,0,0,0,0,0,0,0,0,0);
14023 %{$RESULT{$Level}} = (
14024 "Problems"=>0,
14025 "Warnings"=>0,
14026 "Affected"=>0 );
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014027 # check rules
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014028 foreach my $Interface (sort keys(%{$CompatProblems{$Level}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014029 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014030 foreach my $Kind (keys(%{$CompatProblems{$Level}{$Interface}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014031 {
14032 if(not defined $CompatRules{$Level}{$Kind})
14033 { # unknown rule
14034 if(not $UnknownRules{$Level}{$Kind})
14035 { # only one warning
14036 printMsg("WARNING", "unknown rule \"$Kind\" (\"$Level\")");
14037 $UnknownRules{$Level}{$Kind}=1;
14038 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014039 delete($CompatProblems{$Level}{$Interface}{$Kind});
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014040 }
14041 }
14042 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014043 foreach my $Interface (sort keys(%{$CompatProblems{$Level}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014044 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014045 foreach my $Kind (sort keys(%{$CompatProblems{$Level}{$Interface}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014046 {
14047 if($CompatRules{$Level}{$Kind}{"Kind"} eq "Symbols")
14048 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014049 foreach my $Location (sort keys(%{$CompatProblems{$Level}{$Interface}{$Kind}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014050 {
14051 my $Priority = getProblemSeverity($Level, $Kind);
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014052 if($Kind eq "Added_Symbol") {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014053 $Added += 1;
14054 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014055 elsif($Kind eq "Removed_Symbol")
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014056 {
14057 $Removed += 1;
14058 $TotalAffected{$Level}{$Interface} = $Priority;
14059 }
14060 else
14061 {
14062 if($Priority eq "Safe") {
14063 $I_Other += 1;
14064 }
14065 elsif($Priority eq "High") {
14066 $I_Problems_High += 1;
14067 }
14068 elsif($Priority eq "Medium") {
14069 $I_Problems_Medium += 1;
14070 }
14071 elsif($Priority eq "Low") {
14072 $I_Problems_Low += 1;
14073 }
14074 if(($Priority ne "Low" or $StrictCompat)
14075 and $Priority ne "Safe") {
14076 $TotalAffected{$Level}{$Interface} = $Priority;
14077 }
14078 }
14079 }
14080 }
14081 }
14082 }
14083 my %TypeChanges = ();
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014084 foreach my $Interface (sort keys(%{$CompatProblems{$Level}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014085 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014086 foreach my $Kind (keys(%{$CompatProblems{$Level}{$Interface}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014087 {
14088 if($CompatRules{$Level}{$Kind}{"Kind"} eq "Types")
14089 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014090 foreach my $Location (sort {cmp_locations($b, $a)} sort keys(%{$CompatProblems{$Level}{$Interface}{$Kind}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014091 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014092 my $Type_Name = $CompatProblems{$Level}{$Interface}{$Kind}{$Location}{"Type_Name"};
14093 my $Target = $CompatProblems{$Level}{$Interface}{$Kind}{$Location}{"Target"};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014094 my $Priority = getProblemSeverity($Level, $Kind);
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040014095 if(cmpSeverities($Type_MaxSeverity{$Level}{$Type_Name}{$Kind}{$Target}, $Priority))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014096 { # select a problem with the highest priority
14097 next;
14098 }
14099 if(($Priority ne "Low" or $StrictCompat)
14100 and $Priority ne "Safe") {
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040014101 $TotalAffected{$Level}{$Interface} = maxSeverity($TotalAffected{$Level}{$Interface}, $Priority);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014102 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014103 %{$TypeChanges{$Type_Name}{$Kind}{$Location}} = %{$CompatProblems{$Level}{$Interface}{$Kind}{$Location}};
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040014104 $Type_MaxSeverity{$Level}{$Type_Name}{$Kind}{$Target} = maxSeverity($Type_MaxSeverity{$Level}{$Type_Name}{$Kind}{$Target}, $Priority);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014105 }
14106 }
14107 }
14108 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014109
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014110 $T_Problems_High = get_TypeProblems_Count(\%TypeChanges, "High", $Level);
14111 $T_Problems_Medium = get_TypeProblems_Count(\%TypeChanges, "Medium", $Level);
14112 $T_Problems_Low = get_TypeProblems_Count(\%TypeChanges, "Low", $Level);
14113 $T_Other = get_TypeProblems_Count(\%TypeChanges, "Safe", $Level);
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014114
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014115 if($CheckObjectsOnly)
14116 { # only removed exported symbols
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014117 $RESULT{$Level}{"Affected"} = $Removed*100/keys(%{$Symbol_Library{1}});
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014118 }
14119 else
14120 { # changed and removed public symbols
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014121 my $SCount = keys(%{$CheckedSymbols{$Level}});
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014122 if($ExtendedCheck)
14123 { # don't count external_func_0 for constants
14124 $SCount-=1;
14125 }
14126 if($SCount)
14127 {
14128 my %Weight = (
14129 "High" => 100,
14130 "Medium" => 50,
14131 "Low" => 25
14132 );
14133 foreach (keys(%{$TotalAffected{$Level}})) {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014134 $RESULT{$Level}{"Affected"}+=$Weight{$TotalAffected{$Level}{$_}};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014135 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014136 $RESULT{$Level}{"Affected"} = $RESULT{$Level}{"Affected"}/$SCount;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014137 }
14138 else {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014139 $RESULT{$Level}{"Affected"} = 0;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014140 }
14141 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014142 $RESULT{$Level}{"Affected"} = show_number($RESULT{$Level}{"Affected"});
14143 if($RESULT{$Level}{"Affected"}>=100) {
14144 $RESULT{$Level}{"Affected"} = 100;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014145 }
14146
Andrey Ponomarenko85043792012-05-14 16:48:07 +040014147 $RESULT{$Level}{"Problems"} += $Removed;
14148 $RESULT{$Level}{"Problems"} += $T_Problems_High + $I_Problems_High;
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014149 $RESULT{$Level}{"Problems"} += $T_Problems_Medium + $I_Problems_Medium;
Andrey Ponomarenko85043792012-05-14 16:48:07 +040014150 if($StrictCompat) {
14151 $RESULT{$Level}{"Problems"} += $T_Problems_Low + $I_Problems_Low;
14152 }
14153 else {
14154 $RESULT{$Level}{"Warnings"} += $T_Problems_Low + $I_Problems_Low;
14155 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014156
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014157 if($C_Problems_Low = keys(%{$ProblemsWithConstants{$Level}}))
14158 {
Andrey Ponomarenko85043792012-05-14 16:48:07 +040014159 if(defined $CompatRules{$Level}{"Changed_Constant"})
14160 {
14161 if($StrictCompat) {
14162 $RESULT{$Level}{"Problems"} += $C_Problems_Low;
14163 }
14164 else {
14165 $RESULT{$Level}{"Warnings"} += $C_Problems_Low;
14166 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014167 }
14168 else
14169 {
14170 printMsg("WARNING", "unknown rule \"Changed_Constant\" (\"$Level\")");
14171 $C_Problems_Low = 0;
14172 }
14173 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +040014174 if($CheckImpl and $Level eq "Binary")
14175 {
14176 if($StrictCompat) {
14177 $RESULT{$Level}{"Problems"} += keys(%ImplProblems);
14178 }
14179 else {
14180 $RESULT{$Level}{"Warnings"} += keys(%ImplProblems);
14181 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014182 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +040014183 if($RESULT{$Level}{"Problems"}
14184 and $RESULT{$Level}{"Affected"}) {
14185 $RESULT{$Level}{"Verdict"} = "incompatible";
14186 }
14187 else {
14188 $RESULT{$Level}{"Verdict"} = "compatible";
14189 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014190
14191 my $TotalTypes = keys(%{$CheckedTypes{$Level}});
14192 if(not $TotalTypes)
14193 { # list all the types
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014194 $TotalTypes = keys(%{$TName_Tid{1}});
14195 }
14196
14197 my ($Arch1, $Arch2) = (getArch(1), getArch(2));
14198 my ($GccV1, $GccV2) = (getGccVersion(1), getGccVersion(2));
14199
14200 my ($TestInfo, $TestResults, $Problem_Summary) = ();
14201
14202 if($ReportFormat eq "xml")
14203 { # XML
14204 # test info
14205 $TestInfo .= " <library>$TargetLibraryName</library>\n";
14206 $TestInfo .= " <version1>\n";
14207 $TestInfo .= " <number>".$Descriptor{1}{"Version"}."</number>\n";
14208 $TestInfo .= " <architecture>$Arch1</architecture>\n";
14209 $TestInfo .= " <gcc>$GccV1</gcc>\n";
14210 $TestInfo .= " </version1>\n";
14211
14212 $TestInfo .= " <version2>\n";
14213 $TestInfo .= " <number>".$Descriptor{2}{"Version"}."</number>\n";
14214 $TestInfo .= " <architecture>$Arch2</architecture>\n";
14215 $TestInfo .= " <gcc>$GccV2</gcc>\n";
14216 $TestInfo .= " </version2>\n";
14217 $TestInfo = "<test_info>\n".$TestInfo."</test_info>\n\n";
14218
14219 # test results
14220 $TestResults .= " <headers>\n";
14221 foreach my $Name (sort {lc($Registered_Headers{1}{$a}{"Identity"}) cmp lc($Registered_Headers{1}{$b}{"Identity"})} keys(%{$Registered_Headers{1}}))
14222 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014223 my $Identity = $Registered_Headers{1}{$Name}{"Identity"};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014224 my $Comment = ($Identity=~/[\/\\]/)?" ($Identity)":"";
14225 $TestResults .= " <name>".get_filename($Name).$Comment."</name>\n";
14226 }
14227 $TestResults .= " </headers>\n";
14228
14229 $TestResults .= " <libs>\n";
14230 foreach my $Library (sort {lc($a) cmp lc($b)} keys(%{$Library_Symbol{1}}))
14231 {
14232 $Library.=" (.$LIB_EXT)" if($Library!~/\.\w+\Z/);
14233 $TestResults .= " <name>$Library</name>\n";
14234 }
14235 $TestResults .= " </libs>\n";
14236
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040014237 $TestResults .= " <symbols>".(keys(%{$CheckedSymbols{$Level}}) - keys(%ExtendedSymbols))."</symbols>\n";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014238 $TestResults .= " <types>".$TotalTypes."</types>\n";
14239
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014240 $TestResults .= " <verdict>".$RESULT{$Level}{"Verdict"}."</verdict>\n";
14241 $TestResults .= " <affected>".$RESULT{$Level}{"Affected"}."</affected>\n";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014242 $TestResults = "<test_results>\n".$TestResults."</test_results>\n\n";
14243
14244 # problem summary
14245 $Problem_Summary .= " <added_symbols>".$Added."</added_symbols>\n";
14246 $Problem_Summary .= " <removed_symbols>".$Removed."</removed_symbols>\n";
14247
14248 $Problem_Summary .= " <problems_with_types>\n";
14249 $Problem_Summary .= " <high>$T_Problems_High</high>\n";
14250 $Problem_Summary .= " <medium>$T_Problems_Medium</medium>\n";
14251 $Problem_Summary .= " <low>$T_Problems_Low</low>\n";
14252 $Problem_Summary .= " <safe>$T_Other</safe>\n";
14253 $Problem_Summary .= " </problems_with_types>\n";
14254
14255 $Problem_Summary .= " <problems_with_symbols>\n";
14256 $Problem_Summary .= " <high>$I_Problems_High</high>\n";
14257 $Problem_Summary .= " <medium>$I_Problems_Medium</medium>\n";
14258 $Problem_Summary .= " <low>$I_Problems_Low</low>\n";
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014259 $Problem_Summary .= " <safe>$I_Other</safe>\n";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014260 $Problem_Summary .= " </problems_with_symbols>\n";
14261
14262 $Problem_Summary .= " <problems_with_constants>\n";
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014263 $Problem_Summary .= " <low>$C_Problems_Low</low>\n";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014264 $Problem_Summary .= " </problems_with_constants>\n";
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014265 if($CheckImpl and $Level eq "Binary")
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014266 {
14267 $Problem_Summary .= " <impl>\n";
14268 $Problem_Summary .= " <low>".keys(%ImplProblems)."</low>\n";
14269 $Problem_Summary .= " </impl>\n";
14270 }
14271 $Problem_Summary = "<problem_summary>\n".$Problem_Summary."</problem_summary>\n\n";
14272
14273 return ($TestInfo.$TestResults.$Problem_Summary, "");
14274 }
14275 else
14276 { # HTML
14277 # test info
14278 $TestInfo = "<h2>Test Info</h2><hr/>\n";
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014279 $TestInfo .= "<table class='summary'>\n";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014280 $TestInfo .= "<tr><th>".ucfirst($TargetComponent)." Name</th><td>$TargetLibraryFName</td></tr>\n";
14281
14282 my (@VInf1, @VInf2, $AddTestInfo) = ();
14283 if($Arch1 ne "unknown"
14284 and $Arch2 ne "unknown")
14285 { # CPU arch
14286 if($Arch1 eq $Arch2)
14287 { # go to the separate section
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014288 $AddTestInfo .= "<tr><th>CPU Type</th><td>".showArch($Arch1)."</td></tr>\n";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014289 }
14290 else
14291 { # go to the version number
14292 push(@VInf1, showArch($Arch1));
14293 push(@VInf2, showArch($Arch2));
14294 }
14295 }
14296 if($GccV1 ne "unknown"
14297 and $GccV2 ne "unknown"
14298 and $OStarget ne "windows")
14299 { # GCC version
14300 if($GccV1 eq $GccV2)
14301 { # go to the separate section
14302 $AddTestInfo .= "<tr><th>GCC Version</th><td>$GccV1</td></tr>\n";
14303 }
14304 else
14305 { # go to the version number
14306 push(@VInf1, "gcc ".$GccV1);
14307 push(@VInf2, "gcc ".$GccV2);
14308 }
14309 }
14310 # show long version names with GCC version and CPU architecture name (if different)
14311 $TestInfo .= "<tr><th>Version #1</th><td>".$Descriptor{1}{"Version"}.(@VInf1?" (".join(", ", reverse(@VInf1)).")":"")."</td></tr>\n";
14312 $TestInfo .= "<tr><th>Version #2</th><td>".$Descriptor{2}{"Version"}.(@VInf2?" (".join(", ", reverse(@VInf2)).")":"")."</td></tr>\n";
14313 $TestInfo .= $AddTestInfo;
14314 #if($COMMON_LANGUAGE{1}) {
14315 # $TestInfo .= "<tr><th>Language</th><td>".$COMMON_LANGUAGE{1}."</td></tr>\n";
14316 #}
14317 if($ExtendedCheck) {
14318 $TestInfo .= "<tr><th>Mode</th><td>Extended</td></tr>\n";
14319 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014320 if($JoinReport)
14321 {
14322 if($Level eq "Binary") {
Andrey Ponomarenko16934472012-03-29 15:37:04 +040014323 $TestInfo .= "<tr><th>Subject</th><td width='150px'>Binary Compatibility</td></tr>\n"; # Run-time
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014324 }
14325 if($Level eq "Source") {
Andrey Ponomarenko16934472012-03-29 15:37:04 +040014326 $TestInfo .= "<tr><th>Subject</th><td width='150px'>Source Compatibility</td></tr>\n"; # Build-time
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014327 }
14328 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014329 $TestInfo .= "</table>\n";
14330
14331 # test results
14332 $TestResults = "<h2>Test Results</h2><hr/>\n";
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014333 $TestResults .= "<table class='summary'>";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014334
14335 my $Headers_Link = "0";
14336 $Headers_Link = "<a href='#Headers' style='color:Blue;'>".keys(%{$Registered_Headers{1}})."</a>" if(keys(%{$Registered_Headers{1}})>0);
14337 $TestResults .= "<tr><th>Total Header Files</th><td>".($CheckObjectsOnly?"0&#160;(not&#160;analyzed)":$Headers_Link)."</td></tr>\n";
14338
14339 if(not $ExtendedCheck)
14340 {
14341 my $Libs_Link = "0";
14342 $Libs_Link = "<a href='#Libs' style='color:Blue;'>".keys(%{$Library_Symbol{1}})."</a>" if(keys(%{$Library_Symbol{1}})>0);
14343 $TestResults .= "<tr><th>Total ".ucfirst($SLIB_TYPE)." Libraries</th><td>".($CheckHeadersOnly?"0&#160;(not&#160;analyzed)":$Libs_Link)."</td></tr>\n";
14344 }
14345
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040014346 $TestResults .= "<tr><th>Total Symbols / Types</th><td>".(keys(%{$CheckedSymbols{$Level}}) - keys(%ExtendedSymbols))." / ".$TotalTypes."</td></tr>\n";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014347
Andrey Ponomarenko85043792012-05-14 16:48:07 +040014348 my $META_DATA = "verdict:".$RESULT{$Level}{"Verdict"}.";";
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014349 if($JoinReport) {
14350 $META_DATA = "kind:".lc($Level).";".$META_DATA;
14351 }
Andrey Ponomarenko16934472012-03-29 15:37:04 +040014352 $TestResults .= "<tr><th>Verdict</th>";
Andrey Ponomarenko85043792012-05-14 16:48:07 +040014353 if($RESULT{$Level}{"Verdict"} eq "incompatible") {
Andrey Ponomarenko16934472012-03-29 15:37:04 +040014354 $TestResults .= "<td><span style='color:Red;'><b>Incompatible<br/>(".$RESULT{$Level}{"Affected"}."%)</b></span></td>";
14355 }
14356 else {
14357 $TestResults .= "<td><span style='color:Green;'><b>Compatible</b></span></td>";
14358 }
14359 $TestResults .= "</tr>\n";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014360 $TestResults .= "</table>\n";
14361
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014362 $META_DATA .= "affected:".$RESULT{$Level}{"Affected"}.";";# in percents
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014363 # problem summary
14364 $Problem_Summary = "<h2>Problem Summary</h2><hr/>\n";
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014365 $Problem_Summary .= "<table class='summary'>";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014366 $Problem_Summary .= "<tr><th></th><th style='text-align:center;'>Severity</th><th style='text-align:center;'>Count</th></tr>";
14367
14368 my $Added_Link = "0";
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014369 if($Added>0)
14370 {
14371 if($JoinReport) {
14372 $Added_Link = "<a href='#".$Level."_Added' style='color:Blue;'>$Added</a>";
14373 }
14374 else {
14375 $Added_Link = "<a href='#Added' style='color:Blue;'>$Added</a>";
14376 }
14377 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014378 $META_DATA .= "added:$Added;";
Andrey Ponomarenko16934472012-03-29 15:37:04 +040014379 $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 +040014380
14381 my $Removed_Link = "0";
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014382 if($Removed>0)
14383 {
14384 if($JoinReport) {
14385 $Removed_Link = "<a href='#".$Level."_Removed' style='color:Blue;'>$Removed</a>"
14386 }
14387 else {
14388 $Removed_Link = "<a href='#Removed' style='color:Blue;'>$Removed</a>"
14389 }
14390 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014391 $META_DATA .= "removed:$Removed;";
Andrey Ponomarenko16934472012-03-29 15:37:04 +040014392 $Problem_Summary .= "<tr><th>Removed Symbols</th>";
14393 $Problem_Summary .= "<td>High</td><td".getStyle("I", "R", $Removed).">$Removed_Link</td></tr>\n";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014394
14395 my $TH_Link = "0";
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014396 $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 +040014397 $TH_Link = "n/a" if($CheckObjectsOnly);
14398 $META_DATA .= "type_problems_high:$T_Problems_High;";
Andrey Ponomarenko16934472012-03-29 15:37:04 +040014399 $Problem_Summary .= "<tr><th rowspan='3'>Problems with<br/>Data Types</th>";
14400 $Problem_Summary .= "<td>High</td><td".getStyle("T", "H", $T_Problems_High).">$TH_Link</td></tr>\n";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014401
14402 my $TM_Link = "0";
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014403 $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 +040014404 $TM_Link = "n/a" if($CheckObjectsOnly);
14405 $META_DATA .= "type_problems_medium:$T_Problems_Medium;";
Andrey Ponomarenko16934472012-03-29 15:37:04 +040014406 $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 +040014407
14408 my $TL_Link = "0";
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014409 $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 +040014410 $TL_Link = "n/a" if($CheckObjectsOnly);
14411 $META_DATA .= "type_problems_low:$T_Problems_Low;";
Andrey Ponomarenko16934472012-03-29 15:37:04 +040014412 $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 +040014413
14414 my $IH_Link = "0";
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014415 $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 +040014416 $IH_Link = "n/a" if($CheckObjectsOnly);
14417 $META_DATA .= "interface_problems_high:$I_Problems_High;";
Andrey Ponomarenko16934472012-03-29 15:37:04 +040014418 $Problem_Summary .= "<tr><th rowspan='3'>Problems with<br/>Symbols</th>";
14419 $Problem_Summary .= "<td>High</td><td".getStyle("I", "H", $I_Problems_High).">$IH_Link</td></tr>\n";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014420
14421 my $IM_Link = "0";
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014422 $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 +040014423 $IM_Link = "n/a" if($CheckObjectsOnly);
14424 $META_DATA .= "interface_problems_medium:$I_Problems_Medium;";
Andrey Ponomarenko16934472012-03-29 15:37:04 +040014425 $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 +040014426
14427 my $IL_Link = "0";
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014428 $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 +040014429 $IL_Link = "n/a" if($CheckObjectsOnly);
14430 $META_DATA .= "interface_problems_low:$I_Problems_Low;";
Andrey Ponomarenko16934472012-03-29 15:37:04 +040014431 $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 +040014432
14433 my $ChangedConstants_Link = "0";
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014434 if(keys(%{$CheckedSymbols{$Level}}) and $C_Problems_Low)
14435 {
14436 if($JoinReport) {
14437 $ChangedConstants_Link = "<a href='#".$Level."_Changed_Constants' style='color:Blue;'>$C_Problems_Low</a>";
14438 }
14439 else {
14440 $ChangedConstants_Link = "<a href='#Changed_Constants' style='color:Blue;'>$C_Problems_Low</a>";
14441 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014442 }
14443 $ChangedConstants_Link = "n/a" if($CheckObjectsOnly);
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014444 $META_DATA .= "changed_constants:$C_Problems_Low;";
Andrey Ponomarenko16934472012-03-29 15:37:04 +040014445 $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 +040014446
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014447 if($CheckImpl and $Level eq "Binary")
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014448 {
14449 my $ChangedImpl_Link = "0";
14450 $ChangedImpl_Link = "<a href='#Changed_Implementation' style='color:Blue;'>".keys(%ImplProblems)."</a>" if(keys(%ImplProblems)>0);
14451 $ChangedImpl_Link = "n/a" if($CheckHeadersOnly);
14452 $META_DATA .= "changed_implementation:".keys(%ImplProblems).";";
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040014453 $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 +040014454 }
14455 # Safe Changes
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014456 if($T_Other and not $CheckObjectsOnly)
14457 {
14458 my $TS_Link = "<a href='#".get_Anchor("Type", $Level, "Safe")."' style='color:Blue;'>$T_Other</a>";
Andrey Ponomarenko16934472012-03-29 15:37:04 +040014459 $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 +040014460 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014461
14462 if($I_Other and not $CheckObjectsOnly)
14463 {
14464 my $IS_Link = "<a href='#".get_Anchor("Symbol", $Level, "Safe")."' style='color:Blue;'>$I_Other</a>";
Andrey Ponomarenko16934472012-03-29 15:37:04 +040014465 $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 +040014466 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014467
14468 $META_DATA .= "tool_version:$TOOL_VERSION";
14469 $Problem_Summary .= "</table>\n";
Andrey Ponomarenko16934472012-03-29 15:37:04 +040014470 # $TestInfo = getLegend().$TestInfo;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014471 return ($TestInfo.$TestResults.$Problem_Summary, $META_DATA);
14472 }
14473}
14474
Andrey Ponomarenko16934472012-03-29 15:37:04 +040014475sub getStyle($$$)
14476{
14477 my ($Subj, $Act, $Num) = @_;
14478 my %Style = (
14479 "A"=>"new",
14480 "R"=>"failed",
14481 "S"=>"passed",
14482 "L"=>"warning",
14483 "M"=>"failed",
14484 "H"=>"failed"
14485 );
14486 if($Num>0) {
14487 return " class='".$Style{$Act}."'";
14488 }
14489 return "";
14490}
14491
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014492sub show_number($)
14493{
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014494 if($_[0])
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014495 {
Andrey Ponomarenko16934472012-03-29 15:37:04 +040014496 my $Num = cut_off_number($_[0], 2, 0);
14497 if($Num eq "0")
14498 {
14499 foreach my $P (3 .. 7)
14500 {
14501 $Num = cut_off_number($_[0], $P, 1);
14502 if($Num ne "0") {
14503 last;
14504 }
14505 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014506 }
14507 if($Num eq "0") {
14508 $Num = $_[0];
14509 }
14510 return $Num;
14511 }
14512 return $_[0];
14513}
14514
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014515sub cut_off_number($$$)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014516{
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014517 my ($num, $digs_to_cut, $z) = @_;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014518 if($num!~/\./)
14519 {
14520 $num .= ".";
14521 foreach (1 .. $digs_to_cut-1) {
14522 $num .= "0";
14523 }
14524 }
14525 elsif($num=~/\.(.+)\Z/ and length($1)<$digs_to_cut-1)
14526 {
14527 foreach (1 .. $digs_to_cut - 1 - length($1)) {
14528 $num .= "0";
14529 }
14530 }
14531 elsif($num=~/\d+\.(\d){$digs_to_cut,}/) {
14532 $num=sprintf("%.".($digs_to_cut-1)."f", $num);
14533 }
14534 $num=~s/\.[0]+\Z//g;
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014535 if($z) {
14536 $num=~s/(\.[1-9]+)[0]+\Z/$1/g;
14537 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014538 return $num;
14539}
14540
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014541sub get_Report_ChangedConstants($)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014542{
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014543 my $Level = $_[0];
Andrey Ponomarenko16934472012-03-29 15:37:04 +040014544 my $CHANGED_CONSTANTS = "";
14545 my %ReportMap = ();
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014546 foreach my $Constant (keys(%{$ProblemsWithConstants{$Level}})) {
Andrey Ponomarenko16934472012-03-29 15:37:04 +040014547 $ReportMap{$Constants{1}{$Constant}{"Header"}}{$Constant} = 1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014548 }
14549 my $Kind = "Changed_Constant";
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014550 if(not defined $CompatRules{$Level}{$Kind}) {
14551 return "";
14552 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014553 if($ReportFormat eq "xml")
14554 { # XML
Andrey Ponomarenko16934472012-03-29 15:37:04 +040014555 foreach my $HeaderName (sort {lc($a) cmp lc($b)} keys(%ReportMap))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014556 {
14557 $CHANGED_CONSTANTS .= " <header name=\"$HeaderName\">\n";
Andrey Ponomarenko16934472012-03-29 15:37:04 +040014558 foreach my $Constant (sort {lc($a) cmp lc($b)} keys(%{$ReportMap{$HeaderName}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014559 {
14560 $CHANGED_CONSTANTS .= " <constant name=\"$Constant\">\n";
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014561 my $Change = $CompatRules{$Level}{$Kind}{"Change"};
14562 my $Effect = $CompatRules{$Level}{$Kind}{"Effect"};
14563 my $Overcome = $CompatRules{$Level}{$Kind}{"Overcome"};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014564 $CHANGED_CONSTANTS .= " <problem id=\"$Kind\">\n";
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014565 $CHANGED_CONSTANTS .= " <change".getXmlParams($Change, $ProblemsWithConstants{$Level}{$Constant}).">$Change</change>\n";
14566 $CHANGED_CONSTANTS .= " <effect".getXmlParams($Effect, $ProblemsWithConstants{$Level}{$Constant}).">$Effect</effect>\n";
14567 $CHANGED_CONSTANTS .= " <overcome".getXmlParams($Overcome, $ProblemsWithConstants{$Level}{$Constant}).">$Overcome</overcome>\n";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014568 $CHANGED_CONSTANTS .= " </problem>\n";
14569 $CHANGED_CONSTANTS .= " </constant>\n";
14570 }
14571 $CHANGED_CONSTANTS .= " </header>\n";
14572 }
14573 $CHANGED_CONSTANTS = "<problems_with_constants severity=\"Low\">\n".$CHANGED_CONSTANTS."</problems_with_constants>\n\n";
14574 }
14575 else
14576 { # HTML
14577 my $Number = 0;
Andrey Ponomarenko16934472012-03-29 15:37:04 +040014578 foreach my $HeaderName (sort {lc($a) cmp lc($b)} keys(%ReportMap))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014579 {
14580 $CHANGED_CONSTANTS .= "<span class='h_name'>$HeaderName</span><br/>\n";
Andrey Ponomarenko16934472012-03-29 15:37:04 +040014581 foreach my $Name (sort {lc($a) cmp lc($b)} keys(%{$ReportMap{$HeaderName}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014582 {
14583 $Number += 1;
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014584 my $Change = applyMacroses($Level, $Kind, $CompatRules{$Level}{$Kind}{"Change"}, $ProblemsWithConstants{$Level}{$Name});
14585 my $Effect = $CompatRules{$Level}{$Kind}{"Effect"};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014586 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 +040014587 $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 +040014588 $Report = $ContentSpanStart."<span class='extendable'>[+]</span> ".$Name.$ContentSpanEnd."<br/>\n".$Report;
14589 $CHANGED_CONSTANTS .= insertIDs($Report);
14590 }
14591 $CHANGED_CONSTANTS .= "<br/>\n";
14592 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014593 if($CHANGED_CONSTANTS)
14594 {
14595 my $Anchor = "<a name='Changed_Constants'></a>";
14596 if($JoinReport) {
14597 $Anchor = "<a name='".$Level."_Changed_Constants'></a>";
14598 }
14599 $CHANGED_CONSTANTS = $Anchor."<h2>Problems with Constants ($Number)</h2><hr/>\n".$CHANGED_CONSTANTS.$TOP_REF."<br/>\n";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014600 }
14601 }
14602 return $CHANGED_CONSTANTS;
14603}
14604
14605sub get_Report_Impl()
14606{
Andrey Ponomarenko16934472012-03-29 15:37:04 +040014607 my $CHANGED_IMPLEMENTATION = "";
14608 my %ReportMap = ();
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014609 foreach my $Interface (sort keys(%ImplProblems))
14610 {
14611 my $HeaderName = $CompleteSignature{1}{$Interface}{"Header"};
14612 my $DyLib = $Symbol_Library{1}{$Interface};
Andrey Ponomarenko16934472012-03-29 15:37:04 +040014613 $ReportMap{$HeaderName}{$DyLib}{$Interface} = 1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014614 }
14615 my $Changed_Number = 0;
Andrey Ponomarenko16934472012-03-29 15:37:04 +040014616 foreach my $HeaderName (sort {lc($a) cmp lc($b)} keys(%ReportMap))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014617 {
Andrey Ponomarenko16934472012-03-29 15:37:04 +040014618 foreach my $DyLib (sort {lc($a) cmp lc($b)} keys(%{$ReportMap{$HeaderName}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014619 {
14620 my $FDyLib=$DyLib.($DyLib!~/\.\w+\Z/?" (.$LIB_EXT)":"");
14621 if($HeaderName) {
14622 $CHANGED_IMPLEMENTATION .= "<span class='h_name'>$HeaderName</span>, <span class='lib_name'>$FDyLib</span><br/>\n";
14623 }
14624 else {
14625 $CHANGED_IMPLEMENTATION .= "<span class='lib_name'>$DyLib</span><br/>\n";
14626 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014627 my %NameSpaceSymbols = ();
Andrey Ponomarenko16934472012-03-29 15:37:04 +040014628 foreach my $Interface (keys(%{$ReportMap{$HeaderName}{$DyLib}})) {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014629 $NameSpaceSymbols{get_IntNameSpace($Interface, 2)}{$Interface} = 1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014630 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014631 foreach my $NameSpace (sort keys(%NameSpaceSymbols))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014632 {
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040014633 $CHANGED_IMPLEMENTATION .= ($NameSpace)?"<span class='ns_title'>namespace</span> <span class='ns'>$NameSpace</span><br/>\n":"";
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014634 my @SortedInterfaces = sort {lc(get_Signature($a, 1)) cmp lc(get_Signature($b, 1))} keys(%{$NameSpaceSymbols{$NameSpace}});
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014635 foreach my $Interface (@SortedInterfaces)
14636 {
14637 $Changed_Number += 1;
14638 my $Signature = get_Signature($Interface, 1);
14639 if($NameSpace) {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040014640 $Signature=~s/\b\Q$NameSpace\E::\b//g;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014641 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014642 $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 +040014643 }
14644 }
14645 $CHANGED_IMPLEMENTATION .= "<br/>\n";
14646 }
14647 }
14648 if($CHANGED_IMPLEMENTATION) {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014649 $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 +040014650 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +040014651
14652 # clean memory
14653 %ImplProblems = ();
14654
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014655 return $CHANGED_IMPLEMENTATION;
14656}
14657
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014658sub getTitle($$$)
14659{
14660 my ($Header, $Library, $NameSpace) = @_;
14661 my $Title = "";
14662 if($Library and $Library!~/\.\w+\Z/) {
14663 $Library .= " (.$LIB_EXT)";
14664 }
14665 if($Header and $Library)
14666 {
14667 $Title .= "<span class='h_name'>$Header</span>";
14668 $Title .= ", <span class='lib_name'>$Library</span><br/>\n";
14669 }
14670 elsif($Library) {
14671 $Title .= "<span class='lib_name'>$Library</span><br/>\n";
14672 }
14673 elsif($Header) {
14674 $Title .= "<span class='h_name'>$Header</span><br/>\n";
14675 }
14676 if($NameSpace) {
14677 $Title .= "<span class='ns_title'>namespace</span> <span class='ns'>$NameSpace</span><br/>\n";
14678 }
14679 return $Title;
14680}
14681
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014682sub get_Report_Added($)
14683{
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014684 my $Level = $_[0];
Andrey Ponomarenko16934472012-03-29 15:37:04 +040014685 my $ADDED_INTERFACES = "";
14686 my %ReportMap = ();
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014687 foreach my $Interface (sort keys(%{$CompatProblems{$Level}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014688 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014689 foreach my $Kind (sort keys(%{$CompatProblems{$Level}{$Interface}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014690 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014691 if($Kind eq "Added_Symbol")
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014692 {
14693 my $HeaderName = $CompleteSignature{2}{$Interface}{"Header"};
14694 my $DyLib = $Symbol_Library{2}{$Interface};
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014695 if($Level eq "Source" and $ReportFormat eq "html")
14696 { # do not show library name in HTML report
14697 $DyLib = "";
14698 }
14699 $ReportMap{$HeaderName}{$DyLib}{$Interface} = 1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014700 }
14701 }
14702 }
14703 if($ReportFormat eq "xml")
14704 { # XML
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014705 foreach my $HeaderName (sort {lc($a) cmp lc($b)} keys(%ReportMap))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014706 {
14707 $ADDED_INTERFACES .= " <header name=\"$HeaderName\">\n";
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014708 foreach my $DyLib (sort {lc($a) cmp lc($b)} keys(%{$ReportMap{$HeaderName}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014709 {
14710 $ADDED_INTERFACES .= " <library name=\"$DyLib\">\n";
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014711 foreach my $Interface (keys(%{$ReportMap{$HeaderName}{$DyLib}})) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014712 $ADDED_INTERFACES .= " <name>$Interface</name>\n";
14713 }
14714 $ADDED_INTERFACES .= " </library>\n";
14715 }
14716 $ADDED_INTERFACES .= " </header>\n";
14717 }
14718 $ADDED_INTERFACES = "<added_symbols>\n".$ADDED_INTERFACES."</added_symbols>\n\n";
14719 }
14720 else
14721 { # HTML
14722 my $Added_Number = 0;
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014723 foreach my $HeaderName (sort {lc($a) cmp lc($b)} keys(%ReportMap))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014724 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014725 foreach my $DyLib (sort {lc($a) cmp lc($b)} keys(%{$ReportMap{$HeaderName}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014726 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014727 my %NameSpaceSymbols = ();
14728 foreach my $Interface (keys(%{$ReportMap{$HeaderName}{$DyLib}})) {
14729 $NameSpaceSymbols{get_IntNameSpace($Interface, 2)}{$Interface} = 1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014730 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014731 foreach my $NameSpace (sort keys(%NameSpaceSymbols))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014732 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014733 $ADDED_INTERFACES .= getTitle($HeaderName, $DyLib, $NameSpace);
14734 my @SortedInterfaces = sort {lc(get_Signature($a, 2)) cmp lc(get_Signature($b, 2))} keys(%{$NameSpaceSymbols{$NameSpace}});
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014735 foreach my $Interface (@SortedInterfaces)
14736 {
14737 $Added_Number += 1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014738 my $Signature = get_Signature($Interface, 2);
14739 if($NameSpace) {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040014740 $Signature=~s/\b\Q$NameSpace\E::\b//g;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014741 }
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040014742 if($Interface=~/\A(_Z|\?)/)
14743 {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014744 if($Signature) {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014745 $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 +040014746 }
14747 else {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014748 $ADDED_INTERFACES .= "<span class=\"iname\">".$Interface."</span><br/>\n";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014749 }
14750 }
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040014751 else
14752 {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014753 if($Signature) {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014754 $ADDED_INTERFACES .= "<span class=\"iname\">".highLight_Signature_Italic_Color($Signature)."</span><br/>\n";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014755 }
14756 else {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014757 $ADDED_INTERFACES .= "<span class=\"iname\">".$Interface."</span><br/>\n";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014758 }
14759 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014760 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014761 $ADDED_INTERFACES .= "<br/>\n";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014762 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014763 }
14764 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014765 if($ADDED_INTERFACES)
14766 {
14767 my $Anchor = "<a name='Added'></a>";
14768 if($JoinReport) {
14769 $Anchor = "<a name='".$Level."_Added'></a>";
14770 }
14771 $ADDED_INTERFACES = $Anchor."<h2>Added Symbols ($Added_Number)</h2><hr/>\n".$ADDED_INTERFACES.$TOP_REF."<br/>\n";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014772 }
14773 }
14774 return $ADDED_INTERFACES;
14775}
14776
14777sub get_Report_Removed($)
14778{
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014779 my $Level = $_[0];
Andrey Ponomarenko16934472012-03-29 15:37:04 +040014780 my $REMOVED_INTERFACES = "";
14781 my %ReportMap = ();
Andrey Ponomarenko85043792012-05-14 16:48:07 +040014782 foreach my $Symbol (sort keys(%{$CompatProblems{$Level}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014783 {
Andrey Ponomarenko85043792012-05-14 16:48:07 +040014784 foreach my $Kind (sort keys(%{$CompatProblems{$Level}{$Symbol}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014785 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014786 if($Kind eq "Removed_Symbol")
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014787 {
Andrey Ponomarenko85043792012-05-14 16:48:07 +040014788 my $HeaderName = $CompleteSignature{1}{$Symbol}{"Header"};
14789 my $DyLib = $Symbol_Library{1}{$Symbol};
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014790 if($Level eq "Source" and $ReportFormat eq "html")
14791 { # do not show library name in HTML report
14792 $DyLib = "";
14793 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +040014794 $ReportMap{$HeaderName}{$DyLib}{$Symbol} = 1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014795 }
14796 }
14797 }
14798 if($ReportFormat eq "xml")
14799 { # XML
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014800 foreach my $HeaderName (sort {lc($a) cmp lc($b)} keys(%ReportMap))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014801 {
14802 $REMOVED_INTERFACES .= " <header name=\"$HeaderName\">\n";
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014803 foreach my $DyLib (sort {lc($a) cmp lc($b)} keys(%{$ReportMap{$HeaderName}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014804 {
14805 $REMOVED_INTERFACES .= " <library name=\"$DyLib\">\n";
Andrey Ponomarenko85043792012-05-14 16:48:07 +040014806 foreach my $Symbol (keys(%{$ReportMap{$HeaderName}{$DyLib}})) {
14807 $REMOVED_INTERFACES .= " <name>$Symbol</name>\n";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014808 }
14809 $REMOVED_INTERFACES .= " </library>\n";
14810 }
14811 $REMOVED_INTERFACES .= " </header>\n";
14812 }
14813 $REMOVED_INTERFACES = "<removed_symbols>\n".$REMOVED_INTERFACES."</removed_symbols>\n\n";
14814 }
14815 else
14816 { # HTML
14817 my $Removed_Number = 0;
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014818 foreach my $HeaderName (sort {lc($a) cmp lc($b)} keys(%ReportMap))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014819 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014820 foreach my $DyLib (sort {lc($a) cmp lc($b)} keys(%{$ReportMap{$HeaderName}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014821 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014822 my %NameSpaceSymbols = ();
14823 foreach my $Interface (keys(%{$ReportMap{$HeaderName}{$DyLib}})) {
14824 $NameSpaceSymbols{get_IntNameSpace($Interface, 1)}{$Interface} = 1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014825 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014826 foreach my $NameSpace (sort keys(%NameSpaceSymbols))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014827 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014828 $REMOVED_INTERFACES .= getTitle($HeaderName, $DyLib, $NameSpace);
14829 my @SortedInterfaces = sort {lc(get_Signature($a, 1)) cmp lc(get_Signature($b, 1))} keys(%{$NameSpaceSymbols{$NameSpace}});
Andrey Ponomarenko85043792012-05-14 16:48:07 +040014830 foreach my $Symbol (@SortedInterfaces)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014831 {
14832 $Removed_Number += 1;
14833 my $SubReport = "";
Andrey Ponomarenko85043792012-05-14 16:48:07 +040014834 my $Signature = get_Signature($Symbol, 1);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014835 if($NameSpace) {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040014836 $Signature=~s/\b\Q$NameSpace\E::\b//g;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014837 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +040014838 if($Symbol=~/\A(_Z|\?)/)
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014839 {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014840 if($Signature) {
Andrey Ponomarenko85043792012-05-14 16:48:07 +040014841 $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 +040014842 }
14843 else {
Andrey Ponomarenko85043792012-05-14 16:48:07 +040014844 $REMOVED_INTERFACES .= "<span class=\"iname\">".$Symbol."</span><br/>\n";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014845 }
14846 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014847 else
14848 {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014849 if($Signature) {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014850 $REMOVED_INTERFACES .= "<span class=\"iname\">".highLight_Signature_Italic_Color($Signature)."</span><br/>\n";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014851 }
14852 else {
Andrey Ponomarenko85043792012-05-14 16:48:07 +040014853 $REMOVED_INTERFACES .= "<span class=\"iname\">".$Symbol."</span><br/>\n";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014854 }
14855 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014856 }
14857 }
14858 $REMOVED_INTERFACES .= "<br/>\n";
14859 }
14860 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014861 if($REMOVED_INTERFACES)
14862 {
14863 my $Anchor = "<a name='Removed'></a><a name='Withdrawn'></a>";
14864 if($JoinReport) {
14865 $Anchor = "<a name='".$Level."_Removed'></a><a name='".$Level."_Withdrawn'></a>";
14866 }
14867 $REMOVED_INTERFACES = $Anchor."<h2>Removed Symbols ($Removed_Number)</h2><hr/>\n".$REMOVED_INTERFACES.$TOP_REF."<br/>\n";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014868 }
14869 }
14870 return $REMOVED_INTERFACES;
14871}
14872
14873sub getXmlParams($$)
14874{
14875 my ($Content, $Problem) = @_;
14876 return "" if(not $Content or not $Problem);
14877 my %XMLparams = ();
14878 foreach my $Attr (sort {$b cmp $a} keys(%{$Problem}))
14879 {
14880 my $Macro = "\@".lc($Attr);
14881 if($Content=~/\Q$Macro\E/) {
14882 $XMLparams{lc($Attr)} = $Problem->{$Attr};
14883 }
14884 }
14885 my @PString = ();
14886 foreach my $P (sort {$b cmp $a} keys(%XMLparams)) {
Andrey Ponomarenko5c09ef32012-06-14 18:17:33 +040014887 push(@PString, $P."=\"".xmlSpecChars($XMLparams{$P})."\"");
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014888 }
14889 if(@PString) {
14890 return " ".join(" ", @PString);
14891 }
14892 else {
14893 return "";
14894 }
14895}
14896
14897sub addMarkup($)
14898{
14899 my $Content = $_[0];
14900 # auto-markup
14901 $Content=~s/\n[ ]*//; # spaces
14902 $Content=~s!(\@\w+\s*\(\@\w+\))!<nowrap>$1</nowrap>!g; # @old_type (@old_size)
14903 $Content=~s!(... \(\w+\))!<nowrap><b>$1</b></nowrap>!g; # ... (va_list)
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040014904 $Content=~s!<nowrap>(.+?)</nowrap>!<span class='nowrap'>$1</span>!g;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014905 $Content=~s!([2-9]\))!<br/>$1!g; # 1), 2), ...
14906 if($Content=~/\ANOTE:/)
14907 { # notes
14908 $Content=~s!(NOTE):!<b>$1</b>:!g;
14909 }
14910 else {
14911 $Content=~s!(NOTE):!<br/><b>$1</b>:!g;
14912 }
14913 $Content=~s! (out)-! <b>$1</b>-!g; # out-parameters
14914 my @Keywords = (
14915 "void",
14916 "const",
14917 "static",
14918 "restrict",
14919 "volatile",
14920 "register",
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040014921 "virtual"
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014922 );
14923 my $MKeys = join("|", @Keywords);
14924 foreach (@Keywords) {
14925 $MKeys .= "|non-".$_;
14926 }
14927 $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 +040014928
14929 # Markdown
14930 $Content=~s!\*\*([\w\-]+)\*\*!<b>$1</b>!ig;
14931 $Content=~s!\*([\w\-]+)\*!<i>$1</i>!ig;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014932 return $Content;
14933}
14934
14935sub applyMacroses($$$$)
14936{
14937 my ($Level, $Kind, $Content, $Problem) = @_;
14938 return "" if(not $Content or not $Problem);
14939 $Problem->{"Word_Size"} = $WORD_SIZE{2};
14940 $Content = addMarkup($Content);
14941 # macros
14942 foreach my $Attr (sort {$b cmp $a} keys(%{$Problem}))
14943 {
14944 my $Macro = "\@".lc($Attr);
14945 my $Value = $Problem->{$Attr};
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040014946 if(not defined $Value
14947 or $Value eq "") {
14948 next;
14949 }
Andrey Ponomarenko5c09ef32012-06-14 18:17:33 +040014950 if($Value=~/\s\(/ and $Value!~/['"]/)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014951 { # functions
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014952 $Value=~s/\s*\[[\w\-]+\]//g; # remove quals
14953 $Value=~s/\s\w+(\)|,)/$1/g; # remove parameter names
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014954 $Value = black_name($Value);
14955 }
14956 elsif($Value=~/\s/) {
14957 $Value = "<span class='value'>".htmlSpecChars($Value)."</span>";
14958 }
14959 elsif($Value=~/\A\d+\Z/
14960 and ($Attr eq "Old_Size" or $Attr eq "New_Size"))
14961 { # bits to bytes
14962 if($Value % $BYTE_SIZE)
14963 { # bits
14964 if($Value==1) {
14965 $Value = "<b>".$Value."</b> bit";
14966 }
14967 else {
14968 $Value = "<b>".$Value."</b> bits";
14969 }
14970 }
14971 else
14972 { # bytes
14973 $Value /= $BYTE_SIZE;
14974 if($Value==1) {
14975 $Value = "<b>".$Value."</b> byte";
14976 }
14977 else {
14978 $Value = "<b>".$Value."</b> bytes";
14979 }
14980 }
14981 }
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040014982 else
14983 {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014984 $Value = "<b>".htmlSpecChars($Value)."</b>";
14985 }
14986 $Content=~s/\Q$Macro\E/$Value/g;
14987 }
14988
14989 if($Content=~/(\A|[^\@\w])\@\w/)
14990 {
14991 if(not $IncompleteRules{$Level}{$Kind})
14992 { # only one warning
14993 printMsg("WARNING", "incomplete rule \"$Kind\" (\"$Level\")");
14994 $IncompleteRules{$Level}{$Kind} = 1;
14995 }
14996 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014997 return $Content;
14998}
14999
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040015000sub get_Report_SymbolProblems($$)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015001{
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015002 my ($TargetSeverity, $Level) = @_;
Andrey Ponomarenko16934472012-03-29 15:37:04 +040015003 my $INTERFACE_PROBLEMS = "";
15004 my (%ReportMap, %SymbolChanges) = ();
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015005 foreach my $Symbol (sort keys(%{$CompatProblems{$Level}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015006 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015007 my ($SN, $SS, $SV) = separate_symbol($Symbol);
15008 if($SV and defined $CompatProblems{$Level}{$SN}) {
15009 next;
15010 }
15011 foreach my $Kind (sort keys(%{$CompatProblems{$Level}{$Symbol}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015012 {
15013 if($CompatRules{$Level}{$Kind}{"Kind"} eq "Symbols"
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015014 and $Kind ne "Added_Symbol" and $Kind ne "Removed_Symbol")
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015015 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015016 my $HeaderName = $CompleteSignature{1}{$Symbol}{"Header"};
15017 my $DyLib = $Symbol_Library{1}{$Symbol};
15018 if(not $DyLib and my $VSym = $SymVer{1}{$Symbol})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015019 { # Symbol with Version
15020 $DyLib = $Symbol_Library{1}{$VSym};
15021 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040015022 if(not $DyLib)
15023 { # const global data
15024 $DyLib = "";
15025 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015026 if($Level eq "Source" and $ReportFormat eq "html")
15027 { # do not show library name in HTML report
15028 $DyLib = "";
15029 }
15030 %{$SymbolChanges{$Symbol}{$Kind}} = %{$CompatProblems{$Level}{$Symbol}{$Kind}};
15031 foreach my $Location (sort keys(%{$SymbolChanges{$Symbol}{$Kind}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015032 {
15033 my $Priority = getProblemSeverity($Level, $Kind);
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015034 if($Priority ne $TargetSeverity) {
15035 delete($SymbolChanges{$Symbol}{$Kind}{$Location});
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015036 }
15037 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015038 if(not keys(%{$SymbolChanges{$Symbol}{$Kind}}))
15039 {
15040 delete($SymbolChanges{$Symbol}{$Kind});
15041 next;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015042 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015043 $ReportMap{$HeaderName}{$DyLib}{$Symbol} = 1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015044 }
15045 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015046 if(not keys(%{$SymbolChanges{$Symbol}})) {
15047 delete($SymbolChanges{$Symbol});
15048 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015049 }
15050 if($ReportFormat eq "xml")
15051 { # XML
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015052 foreach my $HeaderName (sort {lc($a) cmp lc($b)} keys(%ReportMap))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015053 {
15054 $INTERFACE_PROBLEMS .= " <header name=\"$HeaderName\">\n";
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015055 foreach my $DyLib (sort {lc($a) cmp lc($b)} keys(%{$ReportMap{$HeaderName}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015056 {
15057 $INTERFACE_PROBLEMS .= " <library name=\"$DyLib\">\n";
15058 foreach my $Symbol (sort {lc($tr_name{$a}) cmp lc($tr_name{$b})} keys(%SymbolChanges))
15059 {
15060 $INTERFACE_PROBLEMS .= " <symbol name=\"$Symbol\">\n";
15061 foreach my $Kind (keys(%{$SymbolChanges{$Symbol}}))
15062 {
15063 foreach my $Location (sort keys(%{$SymbolChanges{$Symbol}{$Kind}}))
15064 {
15065 my %Problem = %{$SymbolChanges{$Symbol}{$Kind}{$Location}};
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040015066 $Problem{"Param_Pos"} = showPos($Problem{"Param_Pos"});
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015067 $INTERFACE_PROBLEMS .= " <problem id=\"$Kind\">\n";
15068 my $Change = $CompatRules{$Level}{$Kind}{"Change"};
15069 $INTERFACE_PROBLEMS .= " <change".getXmlParams($Change, \%Problem).">$Change</change>\n";
15070 my $Effect = $CompatRules{$Level}{$Kind}{"Effect"};
15071 $INTERFACE_PROBLEMS .= " <effect".getXmlParams($Effect, \%Problem).">$Effect</effect>\n";
15072 my $Overcome = $CompatRules{$Level}{$Kind}{"Overcome"};
15073 $INTERFACE_PROBLEMS .= " <overcome".getXmlParams($Overcome, \%Problem).">$Overcome</overcome>\n";
15074 $INTERFACE_PROBLEMS .= " </problem>\n";
15075 }
15076 }
15077 $INTERFACE_PROBLEMS .= " </symbol>\n";
15078 }
15079 $INTERFACE_PROBLEMS .= " </library>\n";
15080 }
15081 $INTERFACE_PROBLEMS .= " </header>\n";
15082 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015083 $INTERFACE_PROBLEMS = "<problems_with_symbols severity=\"$TargetSeverity\">\n".$INTERFACE_PROBLEMS."</problems_with_symbols>\n\n";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015084 }
15085 else
15086 { # HTML
15087 my $ProblemsNum = 0;
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015088 foreach my $HeaderName (sort {lc($a) cmp lc($b)} keys(%ReportMap))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015089 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015090 foreach my $DyLib (sort {lc($a) cmp lc($b)} keys(%{$ReportMap{$HeaderName}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015091 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015092 my (%NameSpaceSymbols, %NewSignature) = ();
15093 foreach my $Symbol (keys(%{$ReportMap{$HeaderName}{$DyLib}})) {
15094 $NameSpaceSymbols{get_IntNameSpace($Symbol, 1)}{$Symbol} = 1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015095 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015096 foreach my $NameSpace (sort keys(%NameSpaceSymbols))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015097 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015098 $INTERFACE_PROBLEMS .= getTitle($HeaderName, $DyLib, $NameSpace);
15099 my @SortedInterfaces = sort {lc($tr_name{$a}) cmp lc($tr_name{$b})} keys(%{$NameSpaceSymbols{$NameSpace}});
15100 foreach my $Symbol (@SortedInterfaces)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015101 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015102 my $Signature = get_Signature($Symbol, 1);
15103 my $SYMBOL_REPORT = "";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015104 my $ProblemNum = 1;
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015105 foreach my $Kind (keys(%{$SymbolChanges{$Symbol}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015106 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015107 foreach my $Location (sort keys(%{$SymbolChanges{$Symbol}{$Kind}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015108 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015109 my %Problem = %{$SymbolChanges{$Symbol}{$Kind}{$Location}};
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040015110 $Problem{"Param_Pos"} = showPos($Problem{"Param_Pos"});
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015111 if($Problem{"New_Signature"}) {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015112 $NewSignature{$Symbol} = $Problem{"New_Signature"};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015113 }
15114 if(my $Change = applyMacroses($Level, $Kind, $CompatRules{$Level}{$Kind}{"Change"}, \%Problem))
15115 {
15116 my $Effect = applyMacroses($Level, $Kind, $CompatRules{$Level}{$Kind}{"Effect"}, \%Problem);
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015117 $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 +040015118 $ProblemNum += 1;
15119 $ProblemsNum += 1;
15120 }
15121 }
15122 }
15123 $ProblemNum -= 1;
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015124 if($SYMBOL_REPORT)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015125 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015126 $INTERFACE_PROBLEMS .= $ContentSpanStart."<span class='extendable'>[+]</span> ";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015127 if($Signature) {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015128 $INTERFACE_PROBLEMS .= highLight_Signature_Italic_Color($Signature);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015129 }
15130 else {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015131 $INTERFACE_PROBLEMS .= $Symbol;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015132 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015133 $INTERFACE_PROBLEMS .= " ($ProblemNum)".$ContentSpanEnd."<br/>\n";
15134 $INTERFACE_PROBLEMS .= $ContentDivStart."\n";
15135 if($NewSignature{$Symbol})
15136 { # argument list changed to
15137 $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 +040015138 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015139 if($Symbol=~/\A(_Z|\?)/) {
15140 $INTERFACE_PROBLEMS .= "<span class='mangled'>&#160;&#160;&#160;&#160;[symbol: <b>$Symbol</b>]</span><br/>\n";
15141 }
15142 $INTERFACE_PROBLEMS .= "<table class='ptable'><tr><th width='2%'></th><th width='47%'>Change</th><th>Effect</th></tr>$SYMBOL_REPORT</table><br/>\n";
15143 $INTERFACE_PROBLEMS .= $ContentDivEnd;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015144 if($NameSpace) {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040015145 $INTERFACE_PROBLEMS=~s/\b\Q$NameSpace\E::\b//g;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015146 }
15147 }
15148 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015149 $INTERFACE_PROBLEMS .= "<br/>";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015150 }
15151 }
15152 }
15153 if($INTERFACE_PROBLEMS)
15154 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015155 $INTERFACE_PROBLEMS = insertIDs($INTERFACE_PROBLEMS);
15156 my $Title = "Problems with Symbols, $TargetSeverity Severity";
15157 if($TargetSeverity eq "Safe")
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015158 { # Safe Changes
15159 $Title = "Other Changes in Symbols";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015160 }
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040015161 $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 +040015162 }
15163 }
15164 return $INTERFACE_PROBLEMS;
15165}
15166
15167sub get_Report_TypeProblems($$)
15168{
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015169 my ($TargetSeverity, $Level) = @_;
Andrey Ponomarenko16934472012-03-29 15:37:04 +040015170 my $TYPE_PROBLEMS = "";
15171 my (%ReportMap, %TypeChanges, %TypeType) = ();
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015172 foreach my $Interface (sort keys(%{$CompatProblems{$Level}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015173 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015174 foreach my $Kind (keys(%{$CompatProblems{$Level}{$Interface}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015175 {
15176 if($CompatRules{$Level}{$Kind}{"Kind"} eq "Types")
15177 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015178 foreach my $Location (sort {cmp_locations($b, $a)} sort keys(%{$CompatProblems{$Level}{$Interface}{$Kind}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015179 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015180 my $TypeName = $CompatProblems{$Level}{$Interface}{$Kind}{$Location}{"Type_Name"};
15181 my $TypeType = $CompatProblems{$Level}{$Interface}{$Kind}{$Location}{"Type_Type"};
15182 my $Target = $CompatProblems{$Level}{$Interface}{$Kind}{$Location}{"Target"};
15183 $CompatProblems{$Level}{$Interface}{$Kind}{$Location}{"Type_Type"} = lc($TypeType);
15184 my $Severity = getProblemSeverity($Level, $Kind);
15185 if($Severity eq "Safe"
15186 and $TargetSeverity ne "Safe") {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015187 next;
15188 }
15189 if(not $TypeType{$TypeName}
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015190 or $TypeType{$TypeName} eq "struct")
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015191 { # register type of the type, select "class" if type has "class"- and "struct"-type changes
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015192 $TypeType{$TypeName} = $CompatProblems{$Level}{$Interface}{$Kind}{$Location}{"Type_Type"};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015193 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015194
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040015195 if(cmpSeverities($Type_MaxSeverity{$Level}{$TypeName}{$Kind}{$Target}, $Severity))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015196 { # select a problem with the highest priority
15197 next;
15198 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015199 %{$TypeChanges{$TypeName}{$Kind}{$Location}} = %{$CompatProblems{$Level}{$Interface}{$Kind}{$Location}};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015200 }
15201 }
15202 }
15203 }
15204 my %Kinds_Locations = ();
15205 foreach my $TypeName (keys(%TypeChanges))
15206 {
15207 my %Kinds_Target = ();
15208 foreach my $Kind (sort keys(%{$TypeChanges{$TypeName}}))
15209 {
15210 foreach my $Location (sort {cmp_locations($b, $a)} sort keys(%{$TypeChanges{$TypeName}{$Kind}}))
15211 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015212 my $Severity = getProblemSeverity($Level, $Kind);
15213 if($Severity ne $TargetSeverity)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015214 { # other priority
15215 delete($TypeChanges{$TypeName}{$Kind}{$Location});
15216 next;
15217 }
15218 $Kinds_Locations{$TypeName}{$Kind}{$Location} = 1;
15219 my $Target = $TypeChanges{$TypeName}{$Kind}{$Location}{"Target"};
15220 if($Kinds_Target{$Kind}{$Target})
15221 { # duplicate target
15222 delete($TypeChanges{$TypeName}{$Kind}{$Location});
15223 next;
15224 }
15225 $Kinds_Target{$Kind}{$Target} = 1;
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040015226 my $HeaderName = $TypeInfo{1}{$TName_Tid{1}{$TypeName}}{"Header"};
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015227 $ReportMap{$HeaderName}{$TypeName} = 1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015228 }
15229 if(not keys(%{$TypeChanges{$TypeName}{$Kind}})) {
15230 delete($TypeChanges{$TypeName}{$Kind});
15231 }
15232 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015233 if(not keys(%{$TypeChanges{$TypeName}})) {
15234 delete($TypeChanges{$TypeName});
15235 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015236 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +040015237 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 +040015238 if($ReportFormat eq "xml")
15239 { # XML
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015240 foreach my $HeaderName (sort {lc($a) cmp lc($b)} keys(%ReportMap))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015241 {
15242 $TYPE_PROBLEMS .= " <header name=\"$HeaderName\">\n";
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015243 foreach my $TypeName (keys(%{$ReportMap{$HeaderName}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015244 {
Andrey Ponomarenko5c09ef32012-06-14 18:17:33 +040015245 $TYPE_PROBLEMS .= " <type name=\"".xmlSpecChars($TypeName)."\">\n";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015246 foreach my $Kind (sort {$b=~/Size/ <=> $a=~/Size/} sort keys(%{$TypeChanges{$TypeName}}))
15247 {
15248 foreach my $Location (sort {cmp_locations($b, $a)} sort keys(%{$TypeChanges{$TypeName}{$Kind}}))
15249 {
15250 my %Problem = %{$TypeChanges{$TypeName}{$Kind}{$Location}};
15251 $TYPE_PROBLEMS .= " <problem id=\"$Kind\">\n";
15252 my $Change = $CompatRules{$Level}{$Kind}{"Change"};
15253 $TYPE_PROBLEMS .= " <change".getXmlParams($Change, \%Problem).">$Change</change>\n";
15254 my $Effect = $CompatRules{$Level}{$Kind}{"Effect"};
15255 $TYPE_PROBLEMS .= " <effect".getXmlParams($Effect, \%Problem).">$Effect</effect>\n";
15256 my $Overcome = $CompatRules{$Level}{$Kind}{"Overcome"};
15257 $TYPE_PROBLEMS .= " <overcome".getXmlParams($Overcome, \%Problem).">$Overcome</overcome>\n";
15258 $TYPE_PROBLEMS .= " </problem>\n";
15259 }
15260 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +040015261 $TYPE_PROBLEMS .= getAffectedSymbols($Level, $TypeName, $Kinds_Locations{$TypeName}, \@Symbols);
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015262 if($Level eq "Binary" and grep {$_=~/Virtual|Base_Class/} keys(%{$Kinds_Locations{$TypeName}})) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015263 $TYPE_PROBLEMS .= showVTables($TypeName);
15264 }
15265 $TYPE_PROBLEMS .= " </type>\n";
15266 }
15267 $TYPE_PROBLEMS .= " </header>\n";
15268 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015269 $TYPE_PROBLEMS = "<problems_with_types severity=\"$TargetSeverity\">\n".$TYPE_PROBLEMS."</problems_with_types>\n\n";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015270 }
15271 else
15272 { # HTML
15273 my $ProblemsNum = 0;
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015274 foreach my $HeaderName (sort {lc($a) cmp lc($b)} keys(%ReportMap))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015275 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015276 my (%NameSpace_Type) = ();
15277 foreach my $TypeName (keys(%{$ReportMap{$HeaderName}})) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015278 $NameSpace_Type{parse_TypeNameSpace($TypeName, 1)}{$TypeName} = 1;
15279 }
15280 foreach my $NameSpace (sort keys(%NameSpace_Type))
15281 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015282 $TYPE_PROBLEMS .= getTitle($HeaderName, "", $NameSpace);
15283 my @SortedTypes = sort {$TypeType{$a}." ".lc($a) cmp $TypeType{$b}." ".lc($b)} keys(%{$NameSpace_Type{$NameSpace}});
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015284 foreach my $TypeName (@SortedTypes)
15285 {
15286 my $ProblemNum = 1;
15287 my $TYPE_REPORT = "";
15288 foreach my $Kind (sort {$b=~/Size/ <=> $a=~/Size/} sort keys(%{$TypeChanges{$TypeName}}))
15289 {
15290 foreach my $Location (sort {cmp_locations($b, $a)} sort keys(%{$TypeChanges{$TypeName}{$Kind}}))
15291 {
15292 my %Problem = %{$TypeChanges{$TypeName}{$Kind}{$Location}};
15293 if(my $Change = applyMacroses($Level, $Kind, $CompatRules{$Level}{$Kind}{"Change"}, \%Problem))
15294 {
15295 my $Effect = applyMacroses($Level, $Kind, $CompatRules{$Level}{$Kind}{"Effect"}, \%Problem);
15296 $TYPE_REPORT .= "<tr><th>$ProblemNum</th><td align='left' valign='top'>".$Change."</td><td align='left' valign='top'>$Effect</td></tr>\n";
15297 $ProblemNum += 1;
15298 $ProblemsNum += 1;
15299 }
15300 }
15301 }
15302 $ProblemNum -= 1;
15303 if($TYPE_REPORT)
15304 {
Andrey Ponomarenko85043792012-05-14 16:48:07 +040015305 my $Affected = getAffectedSymbols($Level, $TypeName, $Kinds_Locations{$TypeName}, \@Symbols);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015306 my $ShowVTables = "";
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015307 if($Level eq "Binary" and grep {$_=~/Virtual|Base_Class/} keys(%{$Kinds_Locations{$TypeName}})) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015308 $ShowVTables = showVTables($TypeName);
15309 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015310 $TYPE_PROBLEMS .= $ContentSpanStart."<span class='extendable'>[+]</span> <span class='ttype'>".$TypeType{$TypeName}."</span> ".htmlSpecChars($TypeName)." ($ProblemNum)".$ContentSpanEnd;
15311 $TYPE_PROBLEMS .= "<br/>\n".$ContentDivStart."<table class='ptable'><tr>\n";
15312 $TYPE_PROBLEMS .= "<th width='2%'></th><th width='47%'>Change</th>\n";
15313 $TYPE_PROBLEMS .= "<th>Effect</th></tr>".$TYPE_REPORT."</table>\n";
15314 $TYPE_PROBLEMS .= $ShowVTables.$Affected."<br/><br/>".$ContentDivEnd."\n";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015315 if($NameSpace) {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040015316 $TYPE_PROBLEMS=~s/\b\Q$NameSpace\E::(\w|\~)/$1/g;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015317 }
15318 }
15319 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015320 $TYPE_PROBLEMS .= "<br/>";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015321 }
15322 }
15323 if($TYPE_PROBLEMS)
15324 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015325 $TYPE_PROBLEMS = insertIDs($TYPE_PROBLEMS);
15326 my $Title = "Problems with Data Types, $TargetSeverity Severity";
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015327 if($TargetSeverity eq "Safe")
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015328 { # Safe Changes
15329 $Title = "Other Changes in Data Types";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015330 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015331 $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 +040015332 }
15333 }
15334 return $TYPE_PROBLEMS;
15335}
15336
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015337sub get_Anchor($$$)
15338{
15339 my ($Kind, $Level, $Severity) = @_;
15340 if($JoinReport)
15341 {
15342 if($Severity eq "Safe") {
15343 return "Other_".$Level."_Changes_In_".$Kind."s";
15344 }
15345 else {
15346 return $Kind."_".$Level."_Problems_".$Severity;
15347 }
15348 }
15349 else
15350 {
15351 if($Severity eq "Safe") {
15352 return "Other_Changes_In_".$Kind."s";
15353 }
15354 else {
15355 return $Kind."_Problems_".$Severity;
15356 }
15357 }
15358}
15359
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015360sub showVTables($)
15361{
15362 my $TypeName = $_[0];
15363 my $TypeId1 = $TName_Tid{1}{$TypeName};
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040015364 my %Type1 = get_Type($TypeId1, 1);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015365 if(defined $Type1{"VTable"}
15366 and keys(%{$Type1{"VTable"}}))
15367 {
15368 my $TypeId2 = $TName_Tid{2}{$TypeName};
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040015369 my %Type2 = get_Type($TypeId2, 2);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015370 if(defined $Type2{"VTable"}
15371 and keys(%{$Type2{"VTable"}}))
15372 {
15373 my %Indexes = map {$_=>1} (keys(%{$Type1{"VTable"}}), keys(%{$Type2{"VTable"}}));
15374 my %Entries = ();
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015375 foreach my $Index (sort {int($a)<=>int($b)} (keys(%Indexes)))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015376 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015377 $Entries{$Index}{"E1"} = simpleVEntry($Type1{"VTable"}{$Index});
15378 $Entries{$Index}{"E2"} = simpleVEntry($Type2{"VTable"}{$Index});
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015379 }
15380 my $VTABLES = "";
15381 if($ReportFormat eq "xml")
15382 { # XML
15383 $VTABLES .= " <vtable>\n";
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015384 foreach my $Index (sort {int($a)<=>int($b)} (keys(%Entries)))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015385 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015386 $VTABLES .= " <entry offset=\"".$Index."\">\n";
Andrey Ponomarenko5c09ef32012-06-14 18:17:33 +040015387 $VTABLES .= " <old>".xmlSpecChars($Entries{$Index}{"E1"})."</old>\n";
15388 $VTABLES .= " <new>".xmlSpecChars($Entries{$Index}{"E2"})."</new>\n";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015389 $VTABLES .= " </entry>\n";
15390 }
15391 $VTABLES .= " </vtable>\n\n";
15392 }
15393 else
15394 { # HTML
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015395 $VTABLES .= "<table class='vtable'>";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015396 $VTABLES .= "<tr><th width='2%'>Offset</th>";
15397 $VTABLES .= "<th width='45%'>Virtual Table (Old) - ".(keys(%{$Type1{"VTable"}}))." entries</th>";
15398 $VTABLES .= "<th>Virtual Table (New) - ".(keys(%{$Type2{"VTable"}}))." entries</th></tr>";
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015399 foreach my $Index (sort {int($a)<=>int($b)} (keys(%Entries)))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015400 {
15401 my ($Color1, $Color2) = ("", "");
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015402 if($Entries{$Index}{"E1"} ne $Entries{$Index}{"E2"})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015403 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015404 if($Entries{$Index}{"E1"})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015405 {
Andrey Ponomarenko16934472012-03-29 15:37:04 +040015406 $Color1 = " class='failed'";
15407 $Color2 = " class='failed'";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015408 }
15409 else {
Andrey Ponomarenko16934472012-03-29 15:37:04 +040015410 $Color2 = " class='warning'";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015411 }
15412 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015413 $VTABLES .= "<tr><th>".$Index."</th>\n";
15414 $VTABLES .= "<td$Color1>".htmlSpecChars($Entries{$Index}{"E1"})."</td>\n";
15415 $VTABLES .= "<td$Color2>".htmlSpecChars($Entries{$Index}{"E2"})."</td></tr>\n";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015416 }
15417 $VTABLES .= "</table><br/>\n";
15418 $VTABLES = $ContentDivStart.$VTABLES.$ContentDivEnd;
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015419 $VTABLES = $ContentSpanStart_Info."[+] show v-table (old and new)".$ContentSpanEnd."<br/>\n".$VTABLES;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015420 }
15421 return $VTABLES;
15422 }
15423 }
15424 return "";
15425}
15426
15427sub simpleVEntry($)
15428{
15429 my $VEntry = $_[0];
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040015430 if(not defined $VEntry
15431 or $VEntry eq "") {
15432 return "";
15433 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015434 $VEntry=~s/\A(.+)::(_ZThn.+)\Z/$2/; # thunks
15435 $VEntry=~s/_ZTI\w+/typeinfo/g; # typeinfo
15436 if($VEntry=~/\A_ZThn.+\Z/) {
15437 $VEntry = "non-virtual thunk";
15438 }
15439 $VEntry=~s/\A\(int \(\*\)\(...\)\)([^\(\d])/$1/i;
15440 # support for old GCC versions
15441 $VEntry=~s/\A0u\Z/(int (*)(...))0/;
15442 $VEntry=~s/\A4294967268u\Z/(int (*)(...))-0x000000004/;
15443 $VEntry=~s/\A&_Z\Z/& _Z/;
15444 # templates
15445 if($VEntry=~s/ \[with (\w+) = (.+?)(, [^=]+ = .+|])\Z//g)
15446 { # std::basic_streambuf<_CharT, _Traits>::imbue [with _CharT = char, _Traits = std::char_traits<char>]
15447 # become std::basic_streambuf<char, ...>::imbue
15448 my ($Pname, $Pval) = ($1, $2);
15449 if($Pname eq "_CharT" and $VEntry=~/\Astd::/)
15450 { # stdc++ typedefs
15451 $VEntry=~s/<$Pname(, [^<>]+|)>/<$Pval>/g;
15452 # FIXME: simplify names using stdcxx typedefs (StdCxxTypedef)
15453 # The typedef info should be added to ABI dumps
15454 }
15455 else
15456 {
15457 $VEntry=~s/<$Pname>/<$Pval>/g;
15458 $VEntry=~s/<$Pname, [^<>]+>/<$Pval, ...>/g;
15459 }
15460 }
15461 $VEntry=~s/([^:]+)::\~([^:]+)\Z/~$1/; # destructors
15462 return $VEntry;
15463}
15464
Andrey Ponomarenko85043792012-05-14 16:48:07 +040015465sub getAffectedSymbols($$$$)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015466{
Andrey Ponomarenko85043792012-05-14 16:48:07 +040015467 my ($Level, $Target_TypeName, $Kinds_Locations, $Syms) = @_;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015468 my $LIMIT = 1000;
Andrey Ponomarenko85043792012-05-14 16:48:07 +040015469 if($#{$Syms}>=10000)
15470 { # reduce size of the report
15471 $LIMIT = 10;
15472 }
15473 my %SProblems = ();
15474 foreach my $Symbol (@{$Syms})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015475 {
Andrey Ponomarenko85043792012-05-14 16:48:07 +040015476 if(keys(%SProblems)>$LIMIT) {
15477 last;
15478 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015479 if(($Symbol=~/C2E|D2E|D0E/))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015480 { # duplicated problems for C2 constructors, D2 and D0 destructors
15481 next;
15482 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015483 my ($SN, $SS, $SV) = separate_symbol($Symbol);
15484 if($Level eq "Source")
15485 { # remove symbol version
15486 $Symbol=$SN;
15487 }
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040015488 my ($MinPath_Length, $ProblemLocation_Last) = (-1, "");
15489 my $Severity_Max = 0;
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015490 my $Signature = get_Signature($Symbol, 1);
15491 foreach my $Kind (keys(%{$CompatProblems{$Level}{$Symbol}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015492 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015493 foreach my $Location (keys(%{$CompatProblems{$Level}{$Symbol}{$Kind}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015494 {
15495 if(not defined $Kinds_Locations->{$Kind}
15496 or not $Kinds_Locations->{$Kind}{$Location}) {
15497 next;
15498 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015499 if($SV and defined $CompatProblems{$Level}{$SN}
15500 and defined $CompatProblems{$Level}{$SN}{$Kind}{$Location})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015501 { # duplicated problems for versioned symbols
15502 next;
15503 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015504 my $Type_Name = $CompatProblems{$Level}{$Symbol}{$Kind}{$Location}{"Type_Name"};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015505 next if($Type_Name ne $Target_TypeName);
15506
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015507 my $Position = $CompatProblems{$Level}{$Symbol}{$Kind}{$Location}{"Param_Pos"};
15508 my $Param_Name = $CompatProblems{$Level}{$Symbol}{$Kind}{$Location}{"Param_Name"};
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040015509 my $Severity = getProblemSeverity($Level, $Kind);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015510 my $Path_Length = 0;
15511 my $ProblemLocation = $Location;
15512 if($Type_Name) {
15513 $ProblemLocation=~s/->\Q$Type_Name\E\Z//g;
15514 }
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040015515 while($ProblemLocation=~/\-\>/g) {
15516 $Path_Length += 1;
15517 }
15518 if($MinPath_Length==-1 or ($Path_Length<=$MinPath_Length and $Severity_Val{$Severity}>$Severity_Max)
15519 or (cmp_locations($ProblemLocation, $ProblemLocation_Last) and $Severity_Val{$Severity}==$Severity_Max))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015520 {
15521 $MinPath_Length = $Path_Length;
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040015522 $Severity_Max = $Severity_Val{$Severity};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015523 $ProblemLocation_Last = $ProblemLocation;
Andrey Ponomarenko85043792012-05-14 16:48:07 +040015524 %{$SProblems{$Symbol}} = (
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040015525 "Descr"=>getAffectDescription($Level, $Symbol, $Kind, $Location),
15526 "Severity_Max"=>$Severity_Max,
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015527 "Signature"=>$Signature,
15528 "Position"=>$Position,
15529 "Param_Name"=>$Param_Name,
15530 "Location"=>$Location
15531 );
15532 }
15533 }
15534 }
15535 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +040015536 my @Symbols = keys(%SProblems);
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015537 @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 +040015538 @Symbols = sort {$SProblems{$b}{"Severity_Max"}<=>$SProblems{$a}{"Severity_Max"}} @Symbols;
15539 if($#Symbols+1>$LIMIT)
15540 { # remove last element
15541 pop(@Symbols);
15542 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015543 my $Affected = "";
15544 if($ReportFormat eq "xml")
15545 { # XML
15546 $Affected .= " <affected>\n";
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015547 foreach my $Symbol (@Symbols)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015548 {
Andrey Ponomarenko85043792012-05-14 16:48:07 +040015549 my $Param_Name = $SProblems{$Symbol}{"Param_Name"};
15550 my $Description = $SProblems{$Symbol}{"Descr"};
15551 my $Location = $SProblems{$Symbol}{"Location"};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015552 my $Target = "";
15553 if($Param_Name) {
15554 $Target = " affected=\"param\" param_name=\"$Param_Name\"";
15555 }
15556 elsif($Location=~/\Aretval(\-|\Z)/i) {
15557 $Target = " affected=\"retval\"";
15558 }
15559 elsif($Location=~/\Athis(\-|\Z)/i) {
15560 $Target = " affected=\"this\"";
15561 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015562 $Affected .= " <symbol$Target name=\"$Symbol\">\n";
Andrey Ponomarenko5c09ef32012-06-14 18:17:33 +040015563 $Affected .= " <comment>".xmlSpecChars($Description)."</comment>\n";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015564 $Affected .= " </symbol>\n";
15565 }
15566 $Affected .= " </affected>\n";
15567 }
15568 else
15569 { # HTML
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015570 foreach my $Symbol (@Symbols)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015571 {
Andrey Ponomarenko85043792012-05-14 16:48:07 +040015572 my $Description = $SProblems{$Symbol}{"Descr"};
15573 my $Signature = $SProblems{$Symbol}{"Signature"};
15574 my $Pos = $SProblems{$Symbol}{"Position"};
Andrey Ponomarenkoa01311b2012-06-08 17:20:02 +040015575 $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 +040015576 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +040015577 if(keys(%SProblems)>$LIMIT) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015578 $Affected .= "and others ...<br/>";
15579 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +040015580 $Affected = "<div class='affected'>".$Affected."</div>";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015581 if($Affected)
15582 {
15583 $Affected = $ContentDivStart.$Affected.$ContentDivEnd;
Andrey Ponomarenko85043792012-05-14 16:48:07 +040015584 $Affected = $ContentSpanStart_Affected."[+] affected symbols (".(keys(%SProblems)>$LIMIT?">".$LIMIT:keys(%SProblems)).")".$ContentSpanEnd.$Affected;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015585 }
15586 }
15587 return $Affected;
15588}
15589
15590sub cmp_locations($$)
15591{
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040015592 my ($L1, $L2) = @_;
15593 if($L2=~/\b(retval|this)\b/
15594 and $L1!~/\b(retval|this)\b/ and $L1!~/\-\>/) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015595 return 1;
15596 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040015597 if($L2=~/\b(retval|this)\b/ and $L2=~/\-\>/
15598 and $L1!~/\b(retval|this)\b/ and $L1=~/\-\>/) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015599 return 1;
15600 }
15601 return 0;
15602}
15603
15604sub getAffectDescription($$$$)
15605{
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015606 my ($Level, $Symbol, $Kind, $Location) = @_;
15607 my %Problem = %{$CompatProblems{$Level}{$Symbol}{$Kind}{$Location}};
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040015608 my $PPos = showPos($Problem{"Param_Pos"});
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015609 my @Sentence = ();
15610 $Location=~s/\A(.*)\-\>.+?\Z/$1/;
15611 if($Kind eq "Overridden_Virtual_Method"
15612 or $Kind eq "Overridden_Virtual_Method_B") {
15613 push(@Sentence, "The method '".$Problem{"New_Value"}."' will be called instead of this method.");
15614 }
15615 elsif($CompatRules{$Level}{$Kind}{"Kind"} eq "Types")
15616 {
15617 if($Location eq "this" or $Kind=~/(\A|_)Virtual(_|\Z)/)
15618 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015619 my $METHOD_TYPE = $CompleteSignature{1}{$Symbol}{"Constructor"}?"constructor":"method";
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040015620 my $ClassName = $TypeInfo{1}{$CompleteSignature{1}{$Symbol}{"Class"}}{"Name"};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015621 if($ClassName eq $Problem{"Type_Name"}) {
15622 push(@Sentence, "This $METHOD_TYPE is from \'".$Problem{"Type_Name"}."\' class.");
15623 }
15624 else {
15625 push(@Sentence, "This $METHOD_TYPE is from derived class \'".$ClassName."\'.");
15626 }
15627 }
15628 else
15629 {
15630 if($Location=~/retval/)
15631 { # return value
15632 if($Location=~/\-\>/) {
15633 push(@Sentence, "Field \'".$Location."\' in return value");
15634 }
15635 else {
15636 push(@Sentence, "Return value");
15637 }
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040015638 if(my $Init = $Problem{"InitialType_Type"})
15639 {
15640 if($Init eq "Pointer") {
15641 push(@Sentence, "(pointer)");
15642 }
15643 elsif($Init eq "Ref") {
15644 push(@Sentence, "(reference)");
15645 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015646 }
15647 }
15648 elsif($Location=~/this/)
15649 { # "this" pointer
15650 if($Location=~/\-\>/) {
15651 push(@Sentence, "Field \'".$Location."\' in the object of this method");
15652 }
15653 else {
15654 push(@Sentence, "\'this\' pointer");
15655 }
15656 }
15657 else
15658 { # parameters
15659 if($Location=~/\-\>/) {
15660 push(@Sentence, "Field \'".$Location."\' in $PPos parameter");
15661 }
15662 else {
15663 push(@Sentence, "$PPos parameter");
15664 }
15665 if($Problem{"Param_Name"}) {
15666 push(@Sentence, "\'".$Problem{"Param_Name"}."\'");
15667 }
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040015668 if(my $Init = $Problem{"InitialType_Type"})
15669 {
15670 if($Init eq "Pointer") {
15671 push(@Sentence, "(pointer)");
15672 }
15673 elsif($Init eq "Ref") {
15674 push(@Sentence, "(reference)");
15675 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015676 }
15677 }
15678 if($Location eq "this") {
15679 push(@Sentence, "has base type \'".$Problem{"Type_Name"}."\'.");
15680 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040015681 elsif(defined $Problem{"Start_Type_Name"}
15682 and $Problem{"Start_Type_Name"} eq $Problem{"Type_Name"}) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015683 push(@Sentence, "has type \'".$Problem{"Type_Name"}."\'.");
15684 }
15685 else {
15686 push(@Sentence, "has base type \'".$Problem{"Type_Name"}."\'.");
15687 }
15688 }
15689 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040015690 if($ExtendedSymbols{$Symbol}) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015691 push(@Sentence, " This is a symbol from an artificial external library that may use the \'$TargetLibraryName\' library and change its ABI after recompiling.");
15692 }
15693 return join(" ", @Sentence);
15694}
15695
15696sub get_XmlSign($$)
15697{
15698 my ($Symbol, $LibVersion) = @_;
15699 my $Info = $CompleteSignature{$LibVersion}{$Symbol};
15700 my $Report = "";
15701 foreach my $Pos (sort {int($a)<=>int($b)} keys(%{$Info->{"Param"}}))
15702 {
15703 my $Name = $Info->{"Param"}{$Pos}{"name"};
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040015704 my $Type = $Info->{"Param"}{$Pos}{"type"};
15705 my $TypeName = $TypeInfo{$LibVersion}{$Type}{"Name"};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015706 foreach my $Typedef (keys(%ChangedTypedef))
15707 {
15708 my $Base = $Typedef_BaseName{$LibVersion}{$Typedef};
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040015709 $TypeName=~s/\b\Q$Typedef\E\b/$Base/g;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015710 }
15711 $Report .= " <param pos=\"$Pos\">\n";
15712 $Report .= " <name>".$Name."</name>\n";
Andrey Ponomarenko5c09ef32012-06-14 18:17:33 +040015713 $Report .= " <type>".xmlSpecChars($TypeName)."</type>\n";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015714 $Report .= " </param>\n";
15715 }
15716 if(my $Return = $Info->{"Return"})
15717 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040015718 my $RTName = $TypeInfo{$LibVersion}{$Return}{"Name"};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015719 $Report .= " <retval>\n";
Andrey Ponomarenko5c09ef32012-06-14 18:17:33 +040015720 $Report .= " <type>".xmlSpecChars($RTName)."</type>\n";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015721 $Report .= " </retval>\n";
15722 }
15723 return $Report;
15724}
15725
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015726sub get_Report_SymbolsInfo($)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015727{
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015728 my $Level = $_[0];
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015729 my $Report = "<symbols_info>\n";
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015730 foreach my $Symbol (sort keys(%{$CompatProblems{$Level}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015731 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015732 my ($SN, $SS, $SV) = separate_symbol($Symbol);
15733 if($SV and defined $CompatProblems{$Level}{$SN}) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015734 next;
15735 }
15736 $Report .= " <symbol name=\"$Symbol\">\n";
15737 my ($S1, $P1, $S2, $P2) = ();
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015738 if(not $AddedInt{$Level}{$Symbol})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015739 {
15740 if(defined $CompleteSignature{1}{$Symbol}
15741 and defined $CompleteSignature{1}{$Symbol}{"Header"})
15742 {
15743 $P1 = get_XmlSign($Symbol, 1);
15744 $S1 = get_Signature($Symbol, 1);
15745 }
15746 elsif($Symbol=~/\A(_Z|\?)/) {
15747 $S1 = $tr_name{$Symbol};
15748 }
15749 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015750 if(not $RemovedInt{$Level}{$Symbol})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015751 {
15752 if(defined $CompleteSignature{2}{$Symbol}
15753 and defined $CompleteSignature{2}{$Symbol}{"Header"})
15754 {
15755 $P2 = get_XmlSign($Symbol, 2);
15756 $S2 = get_Signature($Symbol, 2);
15757 }
15758 elsif($Symbol=~/\A(_Z|\?)/) {
15759 $S2 = $tr_name{$Symbol};
15760 }
15761 }
15762 if($S1)
15763 {
Andrey Ponomarenko5c09ef32012-06-14 18:17:33 +040015764 $Report .= " <old signature=\"".xmlSpecChars($S1)."\">\n";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015765 $Report .= $P1;
15766 $Report .= " </old>\n";
15767 }
15768 if($S2 and $S2 ne $S1)
15769 {
Andrey Ponomarenko5c09ef32012-06-14 18:17:33 +040015770 $Report .= " <new signature=\"".xmlSpecChars($S2)."\">\n";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015771 $Report .= $P2;
15772 $Report .= " </new>\n";
15773 }
15774 $Report .= " </symbol>\n";
15775 }
15776 $Report .= "</symbols_info>\n";
15777 return $Report;
15778}
15779
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015780sub writeReport($$)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015781{
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015782 my ($Level, $Report) = @_;
15783 if($ReportFormat eq "xml") {
15784 $Report = "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n".$Report;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015785 }
15786 if($StdOut)
15787 { # --stdout option
15788 print STDOUT $Report;
15789 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015790 else
15791 {
15792 my $RPath = getReportPath($Level);
Andrey Ponomarenko85043792012-05-14 16:48:07 +040015793 mkpath(get_dirname($RPath));
15794
15795 open(REPORT, ">", $RPath) || die ("can't open file \'$RPath\': $!\n");
15796 print REPORT $Report;
15797 close(REPORT);
15798
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040015799 if($Browse or $OpenReport)
15800 { # open in browser
15801 openReport($RPath);
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015802 if($JoinReport or $DoubleReport)
15803 {
15804 if($Level eq "Binary")
15805 { # wait to open a browser
15806 sleep(1);
15807 }
15808 }
15809 }
15810 }
15811}
15812
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040015813sub openReport($)
15814{
15815 my $Path = $_[0];
15816 my $Cmd = "";
15817 if($Browse)
15818 { # user-defined browser
Andrey Ponomarenkoa01311b2012-06-08 17:20:02 +040015819 $Cmd = $Browse." \"$Path\"";
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040015820 }
15821 if(not $Cmd)
15822 { # default browser
15823 if($OSgroup eq "macos") {
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +040015824 $Cmd = "open \"$Path\"";
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040015825 }
15826 elsif($OSgroup eq "windows") {
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +040015827 $Cmd = "start ".path_format($Path, $OSgroup);
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040015828 }
15829 else
15830 { # linux, freebsd, solaris
15831 my @Browsers = (
15832 "x-www-browser",
15833 "sensible-browser",
15834 "firefox",
15835 "opera",
15836 "xdg-open",
15837 "lynx",
15838 "links"
15839 );
15840 foreach my $Br (@Browsers)
15841 {
15842 if($Br = get_CmdPath($Br))
15843 {
Andrey Ponomarenkoa01311b2012-06-08 17:20:02 +040015844 $Cmd = $Br." \"$Path\"";
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040015845 last;
15846 }
15847 }
15848 }
15849 }
15850 if($Cmd)
15851 {
15852 if($Debug) {
15853 printMsg("INFO", "running $Cmd");
15854 }
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +040015855 if($OSgroup ne "windows"
15856 and $OSgroup ne "macos")
15857 {
15858 if($Cmd!~/lynx|links/) {
15859 $Cmd .= " >\"$TMP_DIR/null\" 2>&1 &";
15860 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040015861 }
15862 system($Cmd);
15863 }
15864 else {
15865 printMsg("ERROR", "cannot open report in browser");
15866 }
15867}
15868
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015869sub getReport($)
15870{
15871 my $Level = $_[0];
15872 if($ReportFormat eq "xml")
15873 { # XML
15874
15875 if($Level eq "Join")
15876 {
15877 my $Report = "<reports>\n";
15878 $Report .= getReport("Binary");
15879 $Report .= getReport("Source");
15880 $Report .= "</reports>\n";
15881 return $Report;
15882 }
15883 else
15884 {
15885 my $Report = "<report kind=\"".lc($Level)."\" version=\"$XML_REPORT_VERSION\">\n\n";
15886 my ($Summary, $MetaData) = get_Summary($Level);
15887 $Report .= $Summary."\n";
15888 $Report .= get_Report_Added($Level).get_Report_Removed($Level);
15889 $Report .= get_Report_Problems("High", $Level).get_Report_Problems("Medium", $Level).get_Report_Problems("Low", $Level).get_Report_Problems("Safe", $Level);
15890 $Report .= get_Report_SymbolsInfo($Level);
15891 $Report .= "</report>\n";
15892 return $Report;
15893 }
15894 }
15895 else
15896 { # HTML
15897 my $CssStyles = readModule("Styles", "Report.css");
15898 my $JScripts = readModule("Scripts", "Sections.js");
15899 if($Level eq "Join")
15900 {
15901 $CssStyles .= "\n".readModule("Styles", "Tabs.css");
15902 $JScripts .= "\n".readModule("Scripts", "Tabs.js");
Andrey Ponomarenkob8d203d2012-05-25 18:11:07 +040015903 my $Title = $TargetLibraryFName.": ".$Descriptor{1}{"Version"}." to ".$Descriptor{2}{"Version"}." compatibility report";
15904 my $Keywords = $TargetLibraryFName.", compatibility, API, report";
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015905 my $Description = "Compatibility report for the $TargetLibraryFName $TargetComponent between ".$Descriptor{1}{"Version"}." and ".$Descriptor{2}{"Version"}." versions";
15906 my ($BSummary, $BMetaData) = get_Summary("Binary");
15907 my ($SSummary, $SMetaData) = get_Summary("Source");
15908 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>";
15909 $Report .= get_Report_Header("Join")."
15910 <br/><div class='tabset'>
Andrey Ponomarenko16934472012-03-29 15:37:04 +040015911 <a id='BinaryID' href='#BinaryTab' class='tab active'>Binary<br/>Compatibility</a>
15912 <a id='SourceID' href='#SourceTab' style='margin-left:3px' class='tab disabled'>Source<br/>Compatibility</a>
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015913 </div>";
15914 $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>";
15915 $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 +040015916 $Report .= getReportFooter($TargetLibraryFName, not $JoinReport);
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015917 $Report .= "\n<div style='height:999px;'></div>\n</body></html>";
15918 return $Report;
15919 }
15920 else
15921 {
15922 my ($Summary, $MetaData) = get_Summary($Level);
Andrey Ponomarenkob8d203d2012-05-25 18:11:07 +040015923 my $Title = $TargetLibraryFName.": ".$Descriptor{1}{"Version"}." to ".$Descriptor{2}{"Version"}." ".lc($Level)." compatibility report";
15924 my $Keywords = $TargetLibraryFName.", ".lc($Level)." compatibility, API, report";
15925 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 +040015926 if($Level eq "Binary")
15927 {
15928 if(getArch(1) eq getArch(2)
15929 and getArch(1) ne "unknown") {
15930 $Description .= " on ".showArch(getArch(1));
15931 }
15932 }
15933 my $Report = "<!-\- $MetaData -\->\n".composeHTML_Head($Title, $Keywords, $Description, $CssStyles, $JScripts)."\n<body>\n<div><a name='Top'></a>\n";
15934 $Report .= get_Report_Header($Level)."\n".$Summary."\n";
15935 $Report .= get_Report_Added($Level).get_Report_Removed($Level);
15936 $Report .= get_Report_Problems("High", $Level).get_Report_Problems("Medium", $Level).get_Report_Problems("Low", $Level).get_Report_Problems("Safe", $Level);
15937 $Report .= get_SourceInfo();
15938 $Report .= "</div>\n<br/><br/><br/><hr/>\n";
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040015939 $Report .= getReportFooter($TargetLibraryFName, not $JoinReport);
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015940 $Report .= "\n<div style='height:999px;'></div>\n</body></html>";
15941 return $Report;
15942 }
15943 }
15944}
15945
Andrey Ponomarenko16934472012-03-29 15:37:04 +040015946sub getLegend()
15947{
15948 return "<br/>
15949<table class='summary'>
15950<tr>
15951 <td class='new'>added</td>
15952 <td class='passed'>compatible</td>
15953</tr>
15954<tr>
15955 <td class='warning'>warning</td>
15956 <td class='failed'>incompatible</td>
15957</tr></table>\n";
15958}
15959
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015960sub createReport()
15961{
15962 if($JoinReport)
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040015963 { # --stdout
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015964 writeReport("Join", getReport("Join"));
15965 }
15966 elsif($DoubleReport)
15967 { # default
15968 writeReport("Binary", getReport("Binary"));
15969 writeReport("Source", getReport("Source"));
15970 }
15971 elsif($BinaryOnly)
15972 { # --binary
15973 writeReport("Binary", getReport("Binary"));
15974 }
15975 elsif($SourceOnly)
15976 { # --source
15977 writeReport("Source", getReport("Source"));
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015978 }
15979}
15980
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040015981sub getReportFooter($$)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015982{
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040015983 my ($LibName, $Wide) = @_;
15984 my $FooterStyle = $Wide?"width:99%":"width:97%;padding-top:3px";
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015985 my $Footer = "<div style='$FooterStyle;font-size:11px;' align='right'><i>Generated on ".(localtime time); # report date
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015986 $Footer .= " for <span style='font-weight:bold'>$LibName</span>"; # tested library/system name
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015987 $Footer .= " by <a href='".$HomePage{"Wiki"}."'>ABI Compliance Checker</a>"; # tool name
15988 my $ToolSummary = "<br/>A tool for checking backward compatibility of a C/C++ library API&#160;&#160;";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015989 $Footer .= " $TOOL_VERSION &#160;$ToolSummary</i></div>"; # tool version
15990 return $Footer;
15991}
15992
15993sub get_Report_Problems($$)
15994{
15995 my ($Priority, $Level) = @_;
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040015996 my $Report = get_Report_TypeProblems($Priority, $Level);
Andrey Ponomarenko16934472012-03-29 15:37:04 +040015997 if(my $SProblems = get_Report_SymbolProblems($Priority, $Level)) {
15998 $Report .= $SProblems;
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040015999 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040016000 if($Priority eq "Low")
16001 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040016002 $Report .= get_Report_ChangedConstants($Level);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040016003 if($ReportFormat eq "html") {
16004 if($CheckImpl and $Level eq "Binary") {
16005 $Report .= get_Report_Impl();
16006 }
16007 }
16008 }
16009 if($ReportFormat eq "html")
16010 {
16011 if($Report)
16012 { # add anchor
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040016013 if($JoinReport)
16014 {
16015 if($Priority eq "Safe") {
16016 $Report = "<a name=\'Other_".$Level."_Changes\'></a>".$Report;
16017 }
16018 else {
16019 $Report = "<a name=\'".$Priority."_Risk_".$Level."_Problems\'></a>".$Report;
16020 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040016021 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040016022 else
16023 {
16024 if($Priority eq "Safe") {
16025 $Report = "<a name=\'Other_Changes\'></a>".$Report;
16026 }
16027 else {
16028 $Report = "<a name=\'".$Priority."_Risk_Problems\'></a>".$Report;
16029 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040016030 }
16031 }
16032 }
16033 return $Report;
16034}
16035
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040016036sub composeHTML_Head($$$$$)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040016037{
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040016038 my ($Title, $Keywords, $Description, $Styles, $Scripts) = @_;
16039 return "<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.0 Transitional//EN\" \"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd\">
16040 <html xmlns=\"http://www.w3.org/1999/xhtml\" xml:lang=\"en\" lang=\"en\">
16041 <head>
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040016042 <meta http-equiv=\"Content-Type\" content=\"text/html; charset=utf-8\" />
16043 <meta name=\"keywords\" content=\"$Keywords\" />
16044 <meta name=\"description\" content=\"$Description\" />
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040016045 <title>
16046 $Title
16047 </title>
16048 <style type=\"text/css\">
16049 $Styles
16050 </style>
16051 <script type=\"text/javascript\" language=\"JavaScript\">
16052 <!--
16053 $Scripts
16054 -->
16055 </script>
16056 </head>";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040016057}
16058
16059sub insertIDs($)
16060{
16061 my $Text = $_[0];
16062 while($Text=~/CONTENT_ID/)
16063 {
16064 if(int($Content_Counter)%2) {
16065 $ContentID -= 1;
16066 }
16067 $Text=~s/CONTENT_ID/c_$ContentID/;
16068 $ContentID += 1;
16069 $Content_Counter += 1;
16070 }
16071 return $Text;
16072}
16073
16074sub checkPreprocessedUnit($)
16075{
16076 my $Path = $_[0];
Andrey Ponomarenkoa01311b2012-06-08 17:20:02 +040016077 my ($CurHeader, $CurHeaderName) = ("", "");
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040016078 open(PREPROC, $Path) || die ("can't open file \'$Path\': $!\n");
Andrey Ponomarenkoa01311b2012-06-08 17:20:02 +040016079 while(my $Line = <PREPROC>)
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040016080 { # detecting public and private constants
Andrey Ponomarenkoa01311b2012-06-08 17:20:02 +040016081
16082 if(substr($Line, 0, 1) eq "#")
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040016083 {
Andrey Ponomarenkoa01311b2012-06-08 17:20:02 +040016084 chomp($Line);
16085 if($Line=~/\A\#\s+\d+\s+\"(.+)\"/)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040016086 {
Andrey Ponomarenkoa01311b2012-06-08 17:20:02 +040016087 $CurHeader = path_format($1, $OSgroup);
16088 $CurHeaderName = get_filename($CurHeader);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040016089 }
Andrey Ponomarenkoa01311b2012-06-08 17:20:02 +040016090 if(not $Include_Neighbors{$Version}{$CurHeaderName}
16091 and not $Registered_Headers{$Version}{$CurHeader})
16092 { # not a target
16093 next;
16094 }
16095 if(not is_target_header($CurHeaderName, 1)
16096 and not is_target_header($CurHeaderName, 2))
16097 { # user-defined header
16098 next;
16099 }
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040016100 if($Line=~/\A\#\s*define\s+(\w+)\s+(.+)\s*\Z/)
Andrey Ponomarenkoa01311b2012-06-08 17:20:02 +040016101 {
16102 my ($Name, $Value) = ($1, $2);
16103 if(not $Constants{$Version}{$Name}{"Access"})
16104 {
16105 $Constants{$Version}{$Name}{"Access"} = "public";
16106 $Constants{$Version}{$Name}{"Value"} = $Value;
16107 $Constants{$Version}{$Name}{"Header"} = $CurHeaderName;
16108 }
16109 }
16110 elsif($Line=~/\A\#[ \t]*undef[ \t]+([_A-Z]+)[ \t]*/) {
16111 $Constants{$Version}{$1}{"Access"} = "private";
16112 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040016113 }
16114 }
16115 close(PREPROC);
16116 foreach my $Constant (keys(%{$Constants{$Version}}))
16117 {
Andrey Ponomarenkoa01311b2012-06-08 17:20:02 +040016118 if($Constants{$Version}{$Constant}{"Access"} eq "private"
16119 or $Constant=~/_h\Z/i
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040016120 or isBuiltIn($Constants{$Version}{$Constant}{"Header"}))
16121 { # skip private constants
16122 delete($Constants{$Version}{$Constant});
16123 }
16124 else {
16125 delete($Constants{$Version}{$Constant}{"Access"});
16126 }
16127 }
Andrey Ponomarenkoa01311b2012-06-08 17:20:02 +040016128 if($Debug)
16129 {
16130 mkpath($DEBUG_PATH{$Version});
16131 copy($Path, $DEBUG_PATH{$Version}."/preprocessor.txt");
16132 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040016133}
16134
Andrey Ponomarenko16934472012-03-29 15:37:04 +040016135sub uncoverConstant($$)
16136{
16137 my ($LibVersion, $Constant) = @_;
16138 return "" if(not $LibVersion or not $Constant);
16139 return $Constant if(isCyclical(\@RecurConstant, $Constant));
16140 if(defined $Cache{"uncoverConstant"}{$LibVersion}{$Constant}) {
16141 return $Cache{"uncoverConstant"}{$LibVersion}{$Constant};
16142 }
16143 my $Value = $Constants{$LibVersion}{$Constant}{"Value"};
16144 if(defined $Value)
16145 {
16146 if($Value=~/\A[A-Z0-9_]+\Z/ and $Value=~/[A-Z]/)
16147 {
16148 push(@RecurConstant, $Constant);
16149 my $Uncovered = uncoverConstant($LibVersion, $Value);
16150 if($Uncovered ne "") {
16151 $Value = $Uncovered;
16152 }
16153 pop(@RecurConstant);
16154 }
16155 # FIXME: uncover $Value using all the enum constants
16156 # USECASE: change of define NC_LONG from NC_INT (enum value) to NC_INT (define)
16157 return ($Cache{"uncoverConstant"}{$LibVersion}{$Constant} = $Value);
16158 }
16159 return ($Cache{"uncoverConstant"}{$LibVersion}{$Constant} = "");
16160}
16161
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040016162my %IgnoreConstant = map {$_=>1} (
16163 "VERSION",
16164 "VERSIONCODE",
16165 "VERNUM",
16166 "VERS_INFO",
16167 "PATCHLEVEL",
16168 "INSTALLPREFIX",
16169 "VBUILD",
16170 "VPATCH",
16171 "VMINOR",
16172 "BUILD_STRING",
16173 "BUILD_TIME",
16174 "PACKAGE_STRING",
16175 "PRODUCTION",
16176 "CONFIGURE_COMMAND",
16177 "INSTALLDIR",
16178 "BINDIR",
16179 "CONFIG_FILE_PATH",
16180 "DATADIR",
16181 "EXTENSION_DIR",
16182 "INCLUDE_PATH",
16183 "LIBDIR",
16184 "LOCALSTATEDIR",
16185 "SBINDIR",
16186 "SYSCONFDIR",
16187 "RELEASE",
16188 "SOURCE_ID",
16189 "SUBMINOR",
16190 "MINOR",
16191 "MINNOR",
16192 "MINORVERSION",
16193 "MAJOR",
16194 "MAJORVERSION",
16195 "MICRO",
16196 "MICROVERSION",
16197 "BINARY_AGE",
16198 "INTERFACE_AGE",
16199 "CORE_ABI",
16200 "PATCH",
16201 "COPYRIGHT",
16202 "TIMESTAMP",
16203 "REVISION",
16204 "PACKAGE_TAG",
16205 "PACKAGEDATE",
16206 "NUMVERSION",
16207 "Release",
16208 "Version"
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040016209);
16210
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040016211sub mergeConstants($)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040016212{
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040016213 my $Level = $_[0];
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040016214 foreach my $Constant (keys(%{$Constants{1}}))
16215 {
16216 if($SkipConstants{1}{$Constant})
16217 { # skipped by the user
16218 next;
16219 }
Andrey Ponomarenko16934472012-03-29 15:37:04 +040016220 if(not defined $Constants{2}{$Constant}{"Value"}
16221 or $Constants{2}{$Constant}{"Value"} eq "")
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040016222 { # empty value
16223 next;
16224 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +040016225 my $Header = $Constants{1}{$Constant}{"Header"};
16226 if(not is_target_header($Header, 1)
16227 and not is_target_header($Header, 2))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040016228 { # user-defined header
16229 next;
16230 }
16231 my ($Old_Value, $New_Value, $Old_Value_Pure, $New_Value_Pure);
Andrey Ponomarenko16934472012-03-29 15:37:04 +040016232 $Old_Value = $Old_Value_Pure = uncoverConstant(1, $Constant);
16233 $New_Value = $New_Value_Pure = uncoverConstant(2, $Constant);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040016234 $Old_Value_Pure=~s/(\W)\s+/$1/g;
16235 $Old_Value_Pure=~s/\s+(\W)/$1/g;
16236 $New_Value_Pure=~s/(\W)\s+/$1/g;
16237 $New_Value_Pure=~s/\s+(\W)/$1/g;
16238 next if($New_Value_Pure eq "" or $Old_Value_Pure eq "");
16239 if($New_Value_Pure ne $Old_Value_Pure)
16240 { # different values
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040016241 if($Level eq "Binary")
16242 {
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040016243 foreach (keys(%IgnoreConstant))
16244 {
16245 if($Constant=~/(\A|_)$_(_|\Z)/)
16246 { # ignore library version
16247 next;
16248 }
16249 if(/\A[A-Z].*[a-z]\Z/)
16250 {
16251 if($Constant=~/(\A|[a-z])$_([A-Z]|\Z)/)
16252 { # ignore library version
16253 next;
16254 }
16255 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040016256 }
16257 if($Constant=~/(\A|_)(lib|open|)$TargetLibraryShortName(_|)(VERSION|VER|DATE|API|PREFIX)(_|\Z)/i)
16258 { # ignore library version
16259 next;
16260 }
16261 if($Old_Value=~/\A('|"|)[\/\\]\w+([\/\\]|:|('|"|)\Z)/ or $Old_Value=~/[\/\\]\w+[\/\\]\w+/)
16262 { # ignoring path defines:
Andrey Ponomarenko85043792012-05-14 16:48:07 +040016263 # /lib64:/usr/lib64:/lib:/usr/lib:/usr/X11R6/lib/Xaw3d ...
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040016264 next;
16265 }
16266 if($Old_Value=~/\A\(*[a-z_]+(\s+|\|)/i)
16267 { # ignore source defines:
Andrey Ponomarenko85043792012-05-14 16:48:07 +040016268 # static int gcry_pth_init ( void) { return ...
16269 # (RE_BACKSLASH_ESCAPE_IN_LISTS | RE...
16270 next;
16271 }
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040016272 if($Old_Value=~/\(/i and $Old_Value!~/\A[\"\']/i)
Andrey Ponomarenko85043792012-05-14 16:48:07 +040016273 { # ignore source defines:
16274 # foo(p)
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040016275 next;
16276 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040016277 }
16278 if(convert_integer($Old_Value) eq convert_integer($New_Value))
16279 { # 0x0001 and 0x1, 0x1 and 1 equal constants
16280 next;
16281 }
16282 if($Old_Value eq "0" and $New_Value eq "NULL")
16283 { # 0 => NULL
16284 next;
16285 }
16286 if($Old_Value eq "NULL" and $New_Value eq "0")
16287 { # NULL => 0
16288 next;
16289 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040016290 %{$ProblemsWithConstants{$Level}{$Constant}} = (
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040016291 "Target"=>$Constant,
16292 "Old_Value"=>$Old_Value,
16293 "New_Value"=>$New_Value );
16294 }
16295 }
16296}
16297
16298sub convert_integer($)
16299{
16300 my $Value = $_[0];
16301 if($Value=~/\A0x[a-f0-9]+\Z/)
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040016302 { # hexadecimal
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040016303 return hex($Value);
16304 }
16305 elsif($Value=~/\A0[0-7]+\Z/)
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040016306 { # octal
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040016307 return oct($Value);
16308 }
16309 elsif($Value=~/\A0b[0-1]+\Z/)
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040016310 { # binary
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040016311 return oct($Value);
16312 }
16313 else {
16314 return $Value;
16315 }
16316}
16317
Andrey Ponomarenko16934472012-03-29 15:37:04 +040016318sub readSymbols($)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040016319{
16320 my $LibVersion = $_[0];
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040016321 my @LibPaths = getSOPaths($LibVersion);
Andrey Ponomarenko16934472012-03-29 15:37:04 +040016322 if($#LibPaths==-1 and not $CheckHeadersOnly)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040016323 {
16324 if($LibVersion==1)
16325 {
16326 printMsg("WARNING", "checking headers only");
16327 $CheckHeadersOnly = 1;
16328 }
16329 else {
16330 exitStatus("Error", "$SLIB_TYPE libraries are not found in ".$Descriptor{$LibVersion}{"Version"});
16331 }
16332 }
Andrey Ponomarenko16934472012-03-29 15:37:04 +040016333 foreach my $LibPath (sort {length($a)<=>length($b)} @LibPaths) {
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040016334 readSymbols_Lib($LibVersion, $LibPath, 0, "+Weak", 1, 1);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040016335 }
Andrey Ponomarenko16934472012-03-29 15:37:04 +040016336 if(not $CheckHeadersOnly)
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040016337 {
Andrey Ponomarenko16934472012-03-29 15:37:04 +040016338 if($#LibPaths!=-1)
16339 {
16340 if(not keys(%{$Symbol_Library{$LibVersion}}))
16341 {
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040016342 printMsg("WARNING", "the set of public symbols in library(ies) is empty ($LibVersion)");
Andrey Ponomarenko16934472012-03-29 15:37:04 +040016343 printMsg("WARNING", "checking headers only");
16344 $CheckHeadersOnly = 1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040016345 }
16346 }
16347 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +040016348
Andrey Ponomarenko07aea072012-11-12 16:15:07 +040016349 # clean memory
Andrey Ponomarenko85043792012-05-14 16:48:07 +040016350 %SystemObjects = ();
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040016351}
16352
Andrey Ponomarenko16934472012-03-29 15:37:04 +040016353sub getSymbolSize($$)
16354{ # size from the shared library
16355 my ($Symbol, $LibVersion) = @_;
16356 return 0 if(not $Symbol);
16357 if(defined $Symbol_Library{$LibVersion}{$Symbol}
16358 and my $LibName = $Symbol_Library{$LibVersion}{$Symbol})
16359 {
16360 if(defined $Library_Symbol{$LibVersion}{$LibName}{$Symbol}
16361 and my $Size = $Library_Symbol{$LibVersion}{$LibName}{$Symbol})
16362 {
16363 if($Size<0) {
16364 return -$Size;
16365 }
16366 }
16367 }
16368 return 0;
16369}
16370
Andrey Ponomarenko07aea072012-11-12 16:15:07 +040016371sub canonifyName($$)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040016372{ # make TIFFStreamOpen(char const*, std::basic_ostream<char, std::char_traits<char> >*)
16373 # to be TIFFStreamOpen(char const*, std::basic_ostream<char>*)
Andrey Ponomarenko07aea072012-11-12 16:15:07 +040016374 my ($Name, $Type) = @_;
16375
16376 # single
16377 while($Name=~/([^<>,]+),\s*$DEFAULT_STD_PARMS<([^<>,]+)>\s*/ and $1 eq $3)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040016378 {
Andrey Ponomarenko85043792012-05-14 16:48:07 +040016379 my $P = $1;
Andrey Ponomarenko07aea072012-11-12 16:15:07 +040016380 $Name=~s/\Q$P\E,\s*$DEFAULT_STD_PARMS<\Q$P\E>\s*/$P/g;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040016381 }
Andrey Ponomarenko07aea072012-11-12 16:15:07 +040016382
16383 # double
16384 if($Name=~/$DEFAULT_STD_PARMS/)
16385 {
16386 if($Type eq "F")
16387 {
16388 my ($ShortName, $FuncParams) = split_Signature($Name);
16389
16390 foreach my $FParam (separate_Params($FuncParams, 0, 0))
16391 {
16392 if(index($FParam, "<")!=-1)
16393 {
16394 $FParam=~s/>([^<>]+)\Z/>/; # remove quals
16395 my $FParam_N = canonifyName($FParam, "T");
16396 if($FParam_N ne $FParam) {
16397 $Name=~s/\Q$FParam\E/$FParam_N/g;
16398 }
16399 }
16400 }
16401 }
16402 elsif($Type eq "T")
16403 {
16404 my ($ShortTmpl, $TmplParams) = template_Base($Name);
16405
16406 my @TParams = separate_Params($TmplParams, 0, 0);
16407 my $Pos = 0;
16408 while($Pos <= $#TParams-1)
16409 {
16410 my $TParam1 = canonifyName($TParams[$Pos], "T");
16411 my $TParam2 = canonifyName($TParams[$Pos+1], "T");
16412
16413 if($TParam2=~/\A$DEFAULT_STD_PARMS<\Q$TParam1\E >\Z/) {
16414 $Name=~s/\Q$TParam1, $TParam2\E/$TParam1/g;
16415 }
16416
16417 $Pos+=2;
16418 }
16419 }
16420 }
16421
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040016422 return $Name;
16423}
16424
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040016425sub translateSymbols(@)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040016426{
16427 my $LibVersion = pop(@_);
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040016428 my (@MnglNames1, @MnglNames2, @UnmangledNames) = ();
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040016429 foreach my $Symbol (sort @_)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040016430 {
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040016431 if(index($Symbol, "_Z")==0)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040016432 {
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040016433 next if($tr_name{$Symbol});
16434 $Symbol=~s/[\@\$]+(.*)\Z//;
16435 push(@MnglNames1, $Symbol);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040016436 }
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040016437 elsif(index($Symbol, "?")==0) {
16438 push(@MnglNames2, $Symbol);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040016439 }
16440 else
16441 { # not mangled
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040016442 $tr_name{$Symbol} = $Symbol;
16443 $mangled_name_gcc{$Symbol} = $Symbol;
16444 $mangled_name{$LibVersion}{$Symbol} = $Symbol;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040016445 }
16446 }
16447 if($#MnglNames1 > -1)
16448 { # GCC names
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040016449 @UnmangledNames = reverse(unmangleArray(@MnglNames1));
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040016450 foreach my $MnglName (@MnglNames1)
16451 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040016452 if(my $Unmangled = pop(@UnmangledNames))
16453 {
Andrey Ponomarenko07aea072012-11-12 16:15:07 +040016454 $tr_name{$MnglName} = formatName(canonifyName($Unmangled, "F"), "S");
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040016455 if(not $mangled_name_gcc{$tr_name{$MnglName}}) {
16456 $mangled_name_gcc{$tr_name{$MnglName}} = $MnglName;
16457 }
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040016458 if(index($MnglName, "_ZTV")==0
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040016459 and $tr_name{$MnglName}=~/vtable for (.+)/)
16460 { # bind class name and v-table symbol
16461 my $ClassName = $1;
16462 $ClassVTable{$ClassName} = $MnglName;
16463 $VTableClass{$MnglName} = $ClassName;
16464 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040016465 }
16466 }
16467 }
16468 if($#MnglNames2 > -1)
16469 { # MSVC names
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040016470 @UnmangledNames = reverse(unmangleArray(@MnglNames2));
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040016471 foreach my $MnglName (@MnglNames2)
16472 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040016473 if(my $Unmangled = pop(@UnmangledNames))
16474 {
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040016475 $tr_name{$MnglName} = formatName($Unmangled, "S");
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040016476 $mangled_name{$LibVersion}{$tr_name{$MnglName}} = $MnglName;
16477 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040016478 }
16479 }
16480 return \%tr_name;
16481}
16482
16483sub link_symbol($$$)
16484{
16485 my ($Symbol, $RunWith, $Deps) = @_;
16486 if(link_symbol_internal($Symbol, $RunWith, \%Symbol_Library)) {
16487 return 1;
16488 }
16489 if($Deps eq "+Deps")
16490 { # check the dependencies
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040016491 if(link_symbol_internal($Symbol, $RunWith, \%DepSymbol_Library)) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040016492 return 1;
16493 }
16494 }
16495 return 0;
16496}
16497
16498sub link_symbol_internal($$$)
16499{
16500 my ($Symbol, $RunWith, $Where) = @_;
16501 return 0 if(not $Where or not $Symbol);
16502 if($Where->{$RunWith}{$Symbol})
16503 { # the exact match by symbol name
16504 return 1;
16505 }
16506 if(my $VSym = $SymVer{$RunWith}{$Symbol})
16507 { # indirect symbol version, i.e.
16508 # foo_old and its symlink foo@v (or foo@@v)
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040016509 # foo_old may be in symtab table
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040016510 if($Where->{$RunWith}{$VSym}) {
16511 return 1;
16512 }
16513 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040016514 my ($Sym, $Spec, $Ver) = separate_symbol($Symbol);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040016515 if($Sym and $Ver)
16516 { # search for the symbol with the same version
16517 # or without version
16518 if($Where->{$RunWith}{$Sym})
16519 { # old: foo@v|foo@@v
16520 # new: foo
16521 return 1;
16522 }
16523 if($Where->{$RunWith}{$Sym."\@".$Ver})
16524 { # old: foo|foo@@v
16525 # new: foo@v
16526 return 1;
16527 }
16528 if($Where->{$RunWith}{$Sym."\@\@".$Ver})
16529 { # old: foo|foo@v
16530 # new: foo@@v
16531 return 1;
16532 }
16533 }
16534 return 0;
16535}
16536
Andrey Ponomarenko16934472012-03-29 15:37:04 +040016537sub readSymbols_App($)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040016538{
16539 my $Path = $_[0];
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040016540 return () if(not $Path);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040016541 my @Imported = ();
16542 if($OSgroup eq "macos")
16543 {
Andrey Ponomarenko07aea072012-11-12 16:15:07 +040016544 my $NM = get_CmdPath("nm");
16545 if(not $NM) {
16546 exitStatus("Not_Found", "can't find \"nm\"");
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040016547 }
Andrey Ponomarenko07aea072012-11-12 16:15:07 +040016548 open(APP, "$NM -g \"$Path\" 2>\"$TMP_DIR/null\" |");
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040016549 while(<APP>)
16550 {
Andrey Ponomarenko07aea072012-11-12 16:15:07 +040016551 if(/ U _([\w\$]+)\s*\Z/) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040016552 push(@Imported, $1);
16553 }
16554 }
16555 close(APP);
16556 }
16557 elsif($OSgroup eq "windows")
16558 {
16559 my $DumpBinCmd = get_CmdPath("dumpbin");
16560 if(not $DumpBinCmd) {
16561 exitStatus("Not_Found", "can't find \"dumpbin.exe\"");
16562 }
Andrey Ponomarenkoa01311b2012-06-08 17:20:02 +040016563 open(APP, "$DumpBinCmd /IMPORTS \"$Path\" 2>\"$TMP_DIR/null\" |");
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040016564 while(<APP>)
16565 {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040016566 if(/\s*\w+\s+\w+\s+\w+\s+([\w\?\@]+)\s*/) {
16567 push(@Imported, $1);
16568 }
16569 }
16570 close(APP);
16571 }
16572 else
16573 {
16574 my $ReadelfCmd = get_CmdPath("readelf");
16575 if(not $ReadelfCmd) {
16576 exitStatus("Not_Found", "can't find \"readelf\"");
16577 }
Andrey Ponomarenkoa01311b2012-06-08 17:20:02 +040016578 open(APP, "$ReadelfCmd -WhlSsdA \"$Path\" 2>\"$TMP_DIR/null\" |");
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040016579 my $symtab = undef; # indicates that we are processing 'symtab' section of 'readelf' output
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040016580 while(<APP>)
16581 {
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040016582 if(defined $symtab)
16583 { # do nothing with symtab
16584 if(index($_, "'.dynsym'")!=-1)
16585 { # dynamic table
16586 $symtab = undef;
16587 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040016588 }
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040016589 elsif(index($_, "'.symtab'")!=-1)
16590 { # symbol table
16591 $symtab = 1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040016592 }
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040016593 elsif(my @Info = readline_ELF($_))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040016594 {
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040016595 my ($Ndx, $Symbol) = ($Info[5], $Info[6]);
16596 if($Ndx eq "UND")
16597 { # only imported symbols
16598 push(@Imported, $Symbol);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040016599 }
16600 }
16601 }
16602 close(APP);
16603 }
16604 return @Imported;
16605}
16606
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040016607my %ELF_BIND = map {$_=>1} (
16608 "WEAK",
16609 "GLOBAL"
16610);
16611
16612my %ELF_TYPE = map {$_=>1} (
16613 "FUNC",
16614 "IFUNC",
16615 "OBJECT",
16616 "COMMON"
16617);
16618
16619my %ELF_VIS = map {$_=>1} (
16620 "DEFAULT",
16621 "PROTECTED"
16622);
16623
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040016624sub readline_ELF($)
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040016625{ # read the line of 'readelf' output corresponding to the symbol
16626 my @Info = split(/\s+/, $_[0]);
16627 # Num: Value Size Type Bind Vis Ndx Name
16628 # 3629: 000b09c0 32 FUNC GLOBAL DEFAULT 13 _ZNSt12__basic_fileIcED1Ev@@GLIBCXX_3.4
16629 shift(@Info); # spaces
16630 shift(@Info); # num
16631 if($#Info!=6)
16632 { # other lines
16633 return ();
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040016634 }
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040016635 return () if(not defined $ELF_TYPE{$Info[2]});
16636 return () if(not defined $ELF_BIND{$Info[3]});
16637 return () if(not defined $ELF_VIS{$Info[4]});
16638 if($Info[5] eq "ABS" and $Info[0]=~/\A0+\Z/)
16639 { # 1272: 00000000 0 OBJECT GLOBAL DEFAULT ABS CXXABI_1.3
16640 return ();
16641 }
16642 if($OStarget eq "symbian")
16643 { # _ZN12CCTTokenType4NewLE4TUid3RFs@@ctfinder{000a0000}[102020e5].dll
16644 if(index($Info[6], "_._.absent_export_")!=-1)
16645 { # "_._.absent_export_111"@@libstdcpp{00010001}[10282872].dll
16646 return ();
16647 }
16648 $Info[6]=~s/\@.+//g; # remove version
16649 }
16650 if(index($Info[2], "0x") == 0)
16651 { # size == 0x3d158
16652 $Info[2] = hex($Info[2]);
16653 }
16654 return @Info;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040016655}
16656
Andrey Ponomarenko16934472012-03-29 15:37:04 +040016657sub read_symlink($)
16658{
16659 my $Path = $_[0];
Andrey Ponomarenko16934472012-03-29 15:37:04 +040016660 if(my $Res = readlink($Path)) {
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040016661 return $Res;
Andrey Ponomarenko16934472012-03-29 15:37:04 +040016662 }
16663 elsif(my $ReadlinkCmd = get_CmdPath("readlink")) {
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040016664 return `$ReadlinkCmd -n \"$Path\"`;
Andrey Ponomarenko16934472012-03-29 15:37:04 +040016665 }
16666 elsif(my $FileCmd = get_CmdPath("file"))
16667 {
Andrey Ponomarenkoa01311b2012-06-08 17:20:02 +040016668 my $Info = `$FileCmd \"$Path\"`;
Andrey Ponomarenko16934472012-03-29 15:37:04 +040016669 if($Info=~/symbolic\s+link\s+to\s+['`"]*([\w\d\.\-\/\\]+)['`"]*/i) {
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040016670 return $1;
Andrey Ponomarenko16934472012-03-29 15:37:04 +040016671 }
16672 }
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040016673
16674 # can't read
16675 return "";
Andrey Ponomarenko16934472012-03-29 15:37:04 +040016676}
16677
16678sub resolve_symlink($)
16679{
16680 my $Path = $_[0];
16681 return "" if(not $Path);
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040016682
Andrey Ponomarenko16934472012-03-29 15:37:04 +040016683 if(defined $Cache{"resolve_symlink"}{$Path}) {
16684 return $Cache{"resolve_symlink"}{$Path};
16685 }
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040016686 if(not -f $Path and not -l $Path)
16687 { # broken
16688 return ($Cache{"resolve_symlink"}{$Path} = "");
16689 }
16690 return ($Cache{"resolve_symlink"}{$Path} = resolve_symlink_I($Path));
16691}
16692
16693sub resolve_symlink_I($)
16694{
16695 my $Path = $_[0];
Andrey Ponomarenko16934472012-03-29 15:37:04 +040016696 return $Path if(isCyclical(\@RecurSymlink, $Path));
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040016697 my $Res = $Path;
Andrey Ponomarenko16934472012-03-29 15:37:04 +040016698 push(@RecurSymlink, $Path);
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040016699 if(-l $Path and my $Redirect = read_symlink($Path))
Andrey Ponomarenko16934472012-03-29 15:37:04 +040016700 {
16701 if(is_abs($Redirect))
16702 { # absolute path
16703 if($SystemRoot and $SystemRoot ne "/"
16704 and $Path=~/\A\Q$SystemRoot\E\//
16705 and (-f $SystemRoot.$Redirect or -l $SystemRoot.$Redirect))
16706 { # symbolic links from the sysroot
16707 # should be corrected to point to
16708 # the files inside sysroot
16709 $Redirect = $SystemRoot.$Redirect;
16710 }
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040016711 $Res = resolve_symlink($Redirect);
Andrey Ponomarenko16934472012-03-29 15:37:04 +040016712 }
16713 elsif($Redirect=~/\.\.[\/\\]/)
16714 { # relative path
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040016715 $Redirect = joinPath(get_dirname($Path), $Redirect);
Andrey Ponomarenko16934472012-03-29 15:37:04 +040016716 while($Redirect=~s&(/|\\)[^\/\\]+(\/|\\)\.\.(\/|\\)&$1&){};
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040016717 $Res = resolve_symlink($Redirect);
Andrey Ponomarenko16934472012-03-29 15:37:04 +040016718 }
16719 elsif(-f get_dirname($Path)."/".$Redirect)
16720 { # file name in the same directory
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040016721 $Res = resolve_symlink(joinPath(get_dirname($Path), $Redirect));
Andrey Ponomarenko16934472012-03-29 15:37:04 +040016722 }
16723 else
16724 { # broken link
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040016725 $Res = "";
Andrey Ponomarenko16934472012-03-29 15:37:04 +040016726 }
16727 }
16728 pop(@RecurSymlink);
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040016729 return $Res;
Andrey Ponomarenko16934472012-03-29 15:37:04 +040016730}
16731
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040016732sub get_LibPath($$)
Andrey Ponomarenko16934472012-03-29 15:37:04 +040016733{
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040016734 my ($LibVersion, $Name) = @_;
16735 return "" if(not $LibVersion or not $Name);
16736 if(defined $Cache{"get_LibPath"}{$LibVersion}{$Name}) {
16737 return $Cache{"get_LibPath"}{$LibVersion}{$Name};
Andrey Ponomarenko16934472012-03-29 15:37:04 +040016738 }
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040016739 return ($Cache{"get_LibPath"}{$LibVersion}{$Name} = get_LibPath_I($LibVersion, $Name));
16740}
16741
16742sub get_LibPath_I($$)
16743{
16744 my ($LibVersion, $Name) = @_;
16745 if(is_abs($Name))
Andrey Ponomarenko16934472012-03-29 15:37:04 +040016746 {
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040016747 if(-f $Name)
16748 { # absolute path
16749 return $Name;
16750 }
16751 else
16752 { # broken
16753 return "";
16754 }
16755 }
Andrey Ponomarenko07aea072012-11-12 16:15:07 +040016756 if(defined $RegisteredObjects{$LibVersion}{$Name})
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040016757 { # registered paths
Andrey Ponomarenko07aea072012-11-12 16:15:07 +040016758 return $RegisteredObjects{$LibVersion}{$Name};
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040016759 }
Andrey Ponomarenko07aea072012-11-12 16:15:07 +040016760 if(defined $RegisteredSONAMEs{$LibVersion}{$Name})
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040016761 { # registered paths
Andrey Ponomarenko07aea072012-11-12 16:15:07 +040016762 return $RegisteredSONAMEs{$LibVersion}{$Name};
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040016763 }
16764 if(my $DefaultPath = $DyLib_DefaultPath{$Name})
16765 { # ldconfig default paths
16766 return $DefaultPath;
16767 }
16768 foreach my $Dir (sort keys(%DefaultLibPaths), sort keys(%{$SystemPaths{"lib"}}))
16769 { # search in default linker directories
16770 # and then in all system paths
16771 if(-f $Dir."/".$Name) {
16772 return joinPath($Dir,$Name);
16773 }
16774 }
16775 detectSystemObjects() if(not keys(%SystemObjects));
16776 if(my @AllObjects = keys(%{$SystemObjects{$Name}})) {
16777 return $AllObjects[0];
16778 }
16779 if(my $ShortName = parse_libname($Name, "name+ext", $OStarget))
16780 {
16781 if($ShortName ne $Name)
16782 { # FIXME: check this case
16783 if(my $Path = get_LibPath($LibVersion, $ShortName)) {
16784 return $Path;
Andrey Ponomarenko16934472012-03-29 15:37:04 +040016785 }
16786 }
Andrey Ponomarenko16934472012-03-29 15:37:04 +040016787 }
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040016788 # can't find
16789 return "";
Andrey Ponomarenko16934472012-03-29 15:37:04 +040016790}
16791
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040016792sub readSymbols_Lib($$$$$$)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040016793{
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040016794 my ($LibVersion, $Lib_Path, $IsNeededLib, $Weak, $Deps, $Vers) = @_;
16795 return () if(not $LibVersion or not $Lib_Path);
16796 my $Lib_Name = get_filename(resolve_symlink($Lib_Path));
16797 if($IsNeededLib)
16798 {
16799 if($CheckedDyLib{$LibVersion}{$Lib_Name}) {
16800 return ();
16801 }
16802 }
16803 return () if(isCyclical(\@RecurLib, $Lib_Name) or $#RecurLib>=1);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040016804 $CheckedDyLib{$LibVersion}{$Lib_Name} = 1;
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040016805
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040016806 if($CheckImpl)
16807 {
16808 if(not $IsNeededLib) {
16809 getImplementations($LibVersion, $Lib_Path);
16810 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040016811 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040016812
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040016813 push(@RecurLib, $Lib_Name);
16814 my (%Value_Interface, %Interface_Value, %NeededLib) = ();
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040016815 my $Lib_ShortName = parse_libname($Lib_Name, "short", $OStarget);
16816 if($IsNeededLib)
16817 { # change short name to use later for needed libraries
16818 $Lib_ShortName = parse_libname($Lib_Name, "name+ext", $OStarget);
16819 }
16820 else
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040016821 { # libstdc++ and libc are always used by other libs
16822 # if you test one of these libs then you not need
16823 # to find them in the system for reusing
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040016824 if($Lib_ShortName eq "libstdc++")
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040016825 { # libstdc++.so.6
16826 $STDCXX_TESTING = 1;
16827 }
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040016828 elsif($Lib_ShortName eq "libc")
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040016829 { # libc-2.11.3.so
16830 $GLIBC_TESTING = 1;
16831 }
16832 }
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040016833 my $DebugPath = "";
Andrey Ponomarenkoa01311b2012-06-08 17:20:02 +040016834 if($Debug and not $DumpSystem)
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040016835 { # debug mode
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040016836 $DebugPath = $DEBUG_PATH{$LibVersion}."/libs/".get_filename($Lib_Path).".txt";
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040016837 mkpath(get_dirname($DebugPath));
16838 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040016839 if($OStarget eq "macos")
16840 { # Mac OS X: *.dylib, *.a
Andrey Ponomarenko07aea072012-11-12 16:15:07 +040016841 my $NM = get_CmdPath("nm");
16842 if(not $NM)
16843 {
16844 print STDERR "ERROR: can't find \"nm\"\n";
16845 exit(1);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040016846 }
Andrey Ponomarenko07aea072012-11-12 16:15:07 +040016847 $NM .= " -g \"$Lib_Path\" 2>\"$TMP_DIR/null\"";
Andrey Ponomarenkoa01311b2012-06-08 17:20:02 +040016848 if($DebugPath)
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040016849 { # debug mode
Andrey Ponomarenko16934472012-03-29 15:37:04 +040016850 # write to file
Andrey Ponomarenko07aea072012-11-12 16:15:07 +040016851 system($NM." >\"$DebugPath\"");
Andrey Ponomarenko16934472012-03-29 15:37:04 +040016852 open(LIB, $DebugPath);
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040016853 }
Andrey Ponomarenko16934472012-03-29 15:37:04 +040016854 else
16855 { # write to pipe
Andrey Ponomarenko07aea072012-11-12 16:15:07 +040016856 open(LIB, $NM." |");
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040016857 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040016858 while(<LIB>)
16859 {
Andrey Ponomarenko07aea072012-11-12 16:15:07 +040016860 if(/ [STD] _([\w\$]+)\s*\Z/)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040016861 {
16862 my $realname = $1;
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040016863 if($IsNeededLib)
16864 {
Andrey Ponomarenko07aea072012-11-12 16:15:07 +040016865 if(not defined $RegisteredObjects_Short{$Lib_ShortName})
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040016866 {
16867 $DepSymbol_Library{$LibVersion}{$realname} = $Lib_Name;
16868 $DepLibrary_Symbol{$LibVersion}{$Lib_Name}{$realname} = 1;
16869 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040016870 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040016871 else
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040016872 {
16873 $Symbol_Library{$LibVersion}{$realname} = $Lib_Name;
16874 $Library_Symbol{$LibVersion}{$Lib_Name}{$realname} = 1;
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040016875 if($COMMON_LANGUAGE{$LibVersion} ne "C++")
16876 {
16877 if(index($realname, "_Z")==0 or index($realname, "?")==0) {
16878 setLanguage($LibVersion, "C++");
16879 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040016880 }
16881 if($CheckObjectsOnly
16882 and $LibVersion==1) {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040016883 $CheckedSymbols{"Binary"}{$realname} = 1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040016884 }
16885 }
16886 }
16887 }
16888 close(LIB);
Andrey Ponomarenko07aea072012-11-12 16:15:07 +040016889
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040016890 if($Deps)
16891 {
16892 if($LIB_TYPE eq "dynamic")
16893 { # dependencies
Andrey Ponomarenko07aea072012-11-12 16:15:07 +040016894
16895 my $OtoolCmd = get_CmdPath("otool");
16896 if(not $OtoolCmd)
16897 {
16898 print STDERR "ERROR: can't find \"otool\"\n";
16899 exit(1);
16900 }
16901
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040016902 open(LIB, "$OtoolCmd -L \"$Lib_Path\" 2>\"$TMP_DIR/null\" |");
16903 while(<LIB>)
16904 {
16905 if(/\s*([\/\\].+\.$LIB_EXT)\s*/
16906 and $1 ne $Lib_Path) {
16907 $NeededLib{$1} = 1;
16908 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040016909 }
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040016910 close(LIB);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040016911 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040016912 }
16913 }
16914 elsif($OStarget eq "windows")
16915 { # Windows *.dll, *.lib
16916 my $DumpBinCmd = get_CmdPath("dumpbin");
16917 if(not $DumpBinCmd) {
16918 exitStatus("Not_Found", "can't find \"dumpbin\"");
16919 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040016920 $DumpBinCmd .= " /EXPORTS \"".$Lib_Path."\" 2>$TMP_DIR/null";
Andrey Ponomarenkoa01311b2012-06-08 17:20:02 +040016921 if($DebugPath)
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040016922 { # debug mode
Andrey Ponomarenko16934472012-03-29 15:37:04 +040016923 # write to file
Andrey Ponomarenkoa01311b2012-06-08 17:20:02 +040016924 system($DumpBinCmd." >\"$DebugPath\"");
Andrey Ponomarenko16934472012-03-29 15:37:04 +040016925 open(LIB, $DebugPath);
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040016926 }
Andrey Ponomarenko16934472012-03-29 15:37:04 +040016927 else
16928 { # write to pipe
16929 open(LIB, $DumpBinCmd." |");
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040016930 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040016931 while(<LIB>)
16932 { # 1197 4AC 0000A620 SetThreadStackGuarantee
16933 # 1198 4AD SetThreadToken (forwarded to ...)
16934 # 3368 _o2i_ECPublicKey
16935 if(/\A\s*\d+\s+[a-f\d]+\s+[a-f\d]+\s+([\w\?\@]+)\s*\Z/i
16936 or /\A\s*\d+\s+[a-f\d]+\s+([\w\?\@]+)\s*\(\s*forwarded\s+/
16937 or /\A\s*\d+\s+_([\w\?\@]+)\s*\Z/)
16938 { # dynamic, static and forwarded symbols
16939 my $realname = $1;
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040016940 if($IsNeededLib)
16941 {
Andrey Ponomarenko07aea072012-11-12 16:15:07 +040016942 if(not defined $RegisteredObjects_Short{$Lib_ShortName})
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040016943 {
16944 $DepSymbol_Library{$LibVersion}{$realname} = $Lib_Name;
16945 $DepLibrary_Symbol{$LibVersion}{$Lib_Name}{$realname} = 1;
16946 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040016947 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040016948 else
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040016949 {
16950 $Symbol_Library{$LibVersion}{$realname} = $Lib_Name;
16951 $Library_Symbol{$LibVersion}{$Lib_Name}{$realname} = 1;
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040016952 if($COMMON_LANGUAGE{$LibVersion} ne "C++")
16953 {
16954 if(index($realname, "_Z")==0 or index($realname, "?")==0) {
16955 setLanguage($LibVersion, "C++");
16956 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040016957 }
16958 if($CheckObjectsOnly
16959 and $LibVersion==1) {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040016960 $CheckedSymbols{"Binary"}{$realname} = 1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040016961 }
16962 }
16963 }
16964 }
16965 close(LIB);
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040016966 if($Deps)
16967 {
16968 if($LIB_TYPE eq "dynamic")
16969 { # dependencies
16970 open(LIB, "$DumpBinCmd /DEPENDENTS \"$Lib_Path\" 2>\"$TMP_DIR/null\" |");
16971 while(<LIB>)
16972 {
16973 if(/\s*([^\s]+?\.$LIB_EXT)\s*/i
16974 and $1 ne $Lib_Path) {
16975 $NeededLib{path_format($1, $OSgroup)} = 1;
16976 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040016977 }
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040016978 close(LIB);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040016979 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040016980 }
16981 }
16982 else
16983 { # Unix; *.so, *.a
16984 # Symbian: *.dso, *.lib
16985 my $ReadelfCmd = get_CmdPath("readelf");
16986 if(not $ReadelfCmd) {
16987 exitStatus("Not_Found", "can't find \"readelf\"");
16988 }
Andrey Ponomarenkoa01311b2012-06-08 17:20:02 +040016989 $ReadelfCmd .= " -WhlSsdA \"$Lib_Path\" 2>\"$TMP_DIR/null\"";
16990 if($DebugPath)
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040016991 { # debug mode
Andrey Ponomarenko16934472012-03-29 15:37:04 +040016992 # write to file
Andrey Ponomarenkoa01311b2012-06-08 17:20:02 +040016993 system($ReadelfCmd." >\"$DebugPath\"");
Andrey Ponomarenko16934472012-03-29 15:37:04 +040016994 open(LIB, $DebugPath);
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040016995 }
Andrey Ponomarenko16934472012-03-29 15:37:04 +040016996 else
16997 { # write to pipe
16998 open(LIB, $ReadelfCmd." |");
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040016999 }
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040017000 my $symtab = undef; # indicates that we are processing 'symtab' section of 'readelf' output
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017001 while(<LIB>)
17002 {
17003 if($LIB_TYPE eq "dynamic")
17004 { # dynamic library specifics
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040017005 if(defined $symtab)
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040017006 {
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040017007 if(index($_, "'.dynsym'")!=-1)
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040017008 { # dynamic table
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040017009 $symtab = undef;
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040017010 }
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040017011 # do nothing with symtab
17012 next;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017013 }
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040017014 elsif(index($_, "'.symtab'")!=-1)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017015 { # symbol table
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040017016 $symtab = 1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017017 next;
17018 }
17019 }
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040017020 if(my ($Value, $Size, $Type, $Bind, $Vis, $Ndx, $Symbol) = readline_ELF($_))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017021 { # read ELF entry
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040017022 if($Ndx eq "UND")
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017023 { # ignore interfaces that are imported from somewhere else
17024 next;
17025 }
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040017026 if($Bind eq "WEAK"
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017027 and $Weak eq "-Weak")
17028 { # skip WEAK symbols
Andrey Ponomarenko07aea072012-11-12 16:15:07 +040017029 $WeakSymbols{$LibVersion}{$Symbol} = 1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017030 next;
17031 }
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040017032 my $Short = $Symbol;
17033 $Short=~s/\@.+//g;
17034 if($Type eq "OBJECT")
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017035 { # global data
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040017036 $GlobalDataObject{$LibVersion}{$Symbol} = 1;
17037 $GlobalDataObject{$LibVersion}{$Short} = 1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017038 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040017039 if($IsNeededLib)
17040 {
Andrey Ponomarenko07aea072012-11-12 16:15:07 +040017041 if(not defined $RegisteredObjects_Short{$Lib_ShortName})
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040017042 {
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040017043 $DepSymbol_Library{$LibVersion}{$Symbol} = $Lib_Name;
17044 $DepLibrary_Symbol{$LibVersion}{$Lib_Name}{$Symbol} = ($Type eq "OBJECT")?-$Size:1;
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040017045 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017046 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040017047 else
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017048 {
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040017049 $Symbol_Library{$LibVersion}{$Symbol} = $Lib_Name;
17050 $Library_Symbol{$LibVersion}{$Lib_Name}{$Symbol} = ($Type eq "OBJECT")?-$Size:1;
17051 if($Vers)
17052 {
17053 if($LIB_EXT eq "so")
17054 { # value
17055 $Interface_Value{$LibVersion}{$Symbol} = $Value;
17056 $Value_Interface{$LibVersion}{$Value}{$Symbol} = 1;
17057 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017058 }
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040017059 if($COMMON_LANGUAGE{$LibVersion} ne "C++")
17060 {
17061 if(index($Symbol, "_Z")==0 or index($Symbol, "?")==0) {
17062 setLanguage($LibVersion, "C++");
17063 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017064 }
17065 if($CheckObjectsOnly
17066 and $LibVersion==1) {
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040017067 $CheckedSymbols{"Binary"}{$Symbol} = 1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017068 }
17069 }
17070 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040017071 elsif($LIB_TYPE eq "dynamic")
17072 { # dynamic library specifics
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040017073 if($Deps)
17074 {
17075 if(/NEEDED.+\[([^\[\]]+)\]/)
17076 { # dependencies:
17077 # 0x00000001 (NEEDED) Shared library: [libc.so.6]
17078 $NeededLib{$1} = 1;
17079 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040017080 }
17081 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017082 }
17083 close(LIB);
17084 }
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040017085 if($Vers)
17086 {
17087 if(not $IsNeededLib and $LIB_EXT eq "so")
17088 { # get symbol versions
17089 foreach my $Symbol (keys(%{$Symbol_Library{$LibVersion}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017090 {
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040017091 next if(index($Symbol,"\@")==-1);
17092 if(my $Value = $Interface_Value{$LibVersion}{$Symbol})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017093 {
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040017094 my $Interface_SymName = "";
17095 foreach my $Symbol_SameValue (keys(%{$Value_Interface{$LibVersion}{$Value}}))
Andrey Ponomarenkoa01311b2012-06-08 17:20:02 +040017096 {
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040017097 if($Symbol_SameValue ne $Symbol
17098 and index($Symbol_SameValue,"\@")==-1)
17099 {
17100 $SymVer{$LibVersion}{$Symbol_SameValue} = $Symbol;
17101 $Interface_SymName = $Symbol_SameValue;
17102 last;
17103 }
Andrey Ponomarenkoa01311b2012-06-08 17:20:02 +040017104 }
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040017105 if(not $Interface_SymName)
17106 {
17107 if($Symbol=~/\A([^\@\$\?]*)[\@\$]+([^\@\$]*)\Z/
17108 and not $SymVer{$LibVersion}{$1}) {
17109 $SymVer{$LibVersion}{$1} = $Symbol;
17110 }
Andrey Ponomarenkoa01311b2012-06-08 17:20:02 +040017111 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017112 }
17113 }
17114 }
17115 }
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040017116 if($Deps)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017117 {
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040017118 foreach my $DyLib (sort keys(%NeededLib))
17119 {
17120 if(my $DepPath = get_LibPath($LibVersion, $DyLib)) {
17121 readSymbols_Lib($LibVersion, $DepPath, 1, "+Weak", $Deps, $Vers);
17122 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017123 }
17124 }
17125 pop(@RecurLib);
17126 return $Library_Symbol{$LibVersion};
17127}
17128
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040017129sub get_prefixes($)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017130{
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017131 my %Prefixes = ();
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040017132 get_prefixes_I([$_[0]], \%Prefixes);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017133 return keys(%Prefixes);
17134}
17135
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040017136sub get_prefixes_I($$)
17137{
17138 foreach my $P (@{$_[0]})
17139 {
17140 my @Parts = reverse(split(/[\/\\]+/, $P));
17141 my $Name = $Parts[0];
17142 foreach (1 .. $#Parts)
17143 {
17144 $_[1]->{$Name}{$P} = 1;
17145 last if($_>4 or $Parts[$_] eq "include");
17146 $Name = $Parts[$_].$SLASH.$Name;
17147 }
17148 }
17149}
17150
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017151sub detectSystemHeaders()
17152{
17153 my @SysHeaders = ();
17154 foreach my $DevelPath (keys(%{$SystemPaths{"include"}}))
17155 {
17156 next if(not -d $DevelPath);
17157 # search for all header files in the /usr/include
17158 # with or without extension (ncurses.h, QtCore, ...)
17159 @SysHeaders = (@SysHeaders, cmd_find($DevelPath,"f","",""));
17160 foreach my $Link (cmd_find($DevelPath,"l","",""))
17161 { # add symbolic links
17162 if(-f $Link) {
17163 push(@SysHeaders, $Link);
17164 }
17165 }
17166 }
17167 foreach my $DevelPath (keys(%{$SystemPaths{"lib"}}))
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040017168 { # search for config headers in the /usr/lib
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017169 next if(not -d $DevelPath);
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040017170 foreach (cmd_find($DevelPath,"f","",""))
17171 {
17172 if(not /\/(gcc|jvm|syslinux|kbd|parrot|xemacs)/)
17173 {
17174 if(/\.h\Z|\/include\//) {
17175 push(@SysHeaders, $_);
17176 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017177 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017178 }
17179 }
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040017180 get_prefixes_I(\@SysHeaders, \%SystemHeaders);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017181}
17182
17183sub detectSystemObjects()
17184{
17185 foreach my $DevelPath (keys(%{$SystemPaths{"lib"}}))
17186 {
17187 next if(not -d $DevelPath);
17188 foreach my $Path (find_libs($DevelPath,"",""))
17189 { # search for shared libraries in the /usr/lib (including symbolic links)
17190 $SystemObjects{parse_libname(get_filename($Path), "name+ext", $OStarget)}{$Path}=1;
17191 }
17192 }
17193}
17194
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040017195sub getSOPaths($)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017196{
17197 my $LibVersion = $_[0];
17198 my @SoPaths = ();
17199 foreach my $Dest (split(/\s*\n\s*/, $Descriptor{$LibVersion}{"Libs"}))
17200 {
17201 if(not -e $Dest) {
17202 exitStatus("Access_Error", "can't access \'$Dest\'");
17203 }
17204 my @SoPaths_Dest = getSOPaths_Dest($Dest, $LibVersion);
17205 foreach (@SoPaths_Dest) {
17206 push(@SoPaths, $_);
17207 }
17208 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040017209 return sort @SoPaths;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017210}
17211
17212sub skip_lib($$)
17213{
17214 my ($Path, $LibVersion) = @_;
17215 return 1 if(not $Path or not $LibVersion);
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040017216 my $Name = get_filename($Path);
17217 if($SkipLibs{$LibVersion}{"Name"}{$Name}) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017218 return 1;
17219 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040017220 my $ShortName = parse_libname($Name, "name+ext", $OStarget);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017221 if($SkipLibs{$LibVersion}{"Name"}{$ShortName}) {
17222 return 1;
17223 }
17224 foreach my $Dir (keys(%{$SkipLibs{$LibVersion}{"Path"}}))
17225 {
17226 if($Path=~/\Q$Dir\E([\/\\]|\Z)/) {
17227 return 1;
17228 }
17229 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040017230 foreach my $P (keys(%{$SkipLibs{$LibVersion}{"Pattern"}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017231 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040017232 if($Name=~/$P/) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017233 return 1;
17234 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040017235 if($P=~/[\/\\]/ and $Path=~/$P/) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017236 return 1;
17237 }
17238 }
17239 return 0;
17240}
17241
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040017242sub skipHeader($$)
17243{
17244 my ($Path, $LibVersion) = @_;
17245 return 1 if(not $Path or not $LibVersion);
17246 if(not keys(%{$SkipHeaders{$LibVersion}})) {
17247 return 0;
17248 }
17249 if(defined $Cache{"skipHeader"}{$Path}) {
17250 return $Cache{"skipHeader"}{$Path};
17251 }
17252 return ($Cache{"skipHeader"}{$Path} = skipHeader_I(@_));
17253}
17254
17255sub skipHeader_I($$)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017256{ # returns:
17257 # 1 - if header should NOT be included and checked
17258 # 2 - if header should NOT be included, but should be checked
17259 my ($Path, $LibVersion) = @_;
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040017260 my $Name = get_filename($Path);
17261 if(my $Kind = $SkipHeaders{$LibVersion}{"Name"}{$Name}) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017262 return $Kind;
17263 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040017264 foreach my $D (keys(%{$SkipHeaders{$LibVersion}{"Path"}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017265 {
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040017266 if(index($Path, $D)!=-1)
17267 {
17268 if($Path=~/\Q$D\E([\/\\]|\Z)/) {
17269 return $SkipHeaders{$LibVersion}{"Path"}{$D};
17270 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017271 }
17272 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040017273 foreach my $P (keys(%{$SkipHeaders{$LibVersion}{"Pattern"}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017274 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040017275 if(my $Kind = $SkipHeaders{$LibVersion}{"Pattern"}{$P})
17276 {
17277 if($Name=~/$P/) {
17278 return $Kind;
17279 }
17280 if($P=~/[\/\\]/ and $Path=~/$P/) {
17281 return $Kind;
17282 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017283 }
17284 }
17285 return 0;
17286}
17287
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040017288sub registerObject_Dir($$)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017289{
17290 my ($Dir, $LibVersion) = @_;
17291 if($SystemPaths{"lib"}{$Dir})
17292 { # system directory
17293 return;
17294 }
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040017295 if($RegisteredObject_Dirs{$LibVersion}{$Dir})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017296 { # already registered
17297 return;
17298 }
17299 foreach my $Path (find_libs($Dir,"",1))
17300 {
17301 next if(ignore_path($Path));
17302 next if(skip_lib($Path, $LibVersion));
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040017303 registerObject($Path, $LibVersion);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017304 }
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040017305 $RegisteredObject_Dirs{$LibVersion}{$Dir} = 1;
17306}
17307
17308sub registerObject($$)
17309{
17310 my ($Path, $LibVersion) = @_;
17311 my $Name = get_filename($Path);
Andrey Ponomarenko07aea072012-11-12 16:15:07 +040017312 $RegisteredObjects{$LibVersion}{$Name} = $Path;
Andrey Ponomarenko27681702012-11-12 16:33:39 +040017313 if($OSgroup=~/linux|bsd/i)
17314 {
17315 if(my $SONAME = getSONAME($Path)) {
17316 $RegisteredSONAMEs{$LibVersion}{$SONAME} = $Path;
17317 }
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040017318 }
17319 if(my $SName = parse_libname($Name, "name", $OStarget)) {
Andrey Ponomarenko07aea072012-11-12 16:15:07 +040017320 $RegisteredObjects_Short{$LibVersion}{$SName} = $Path;
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040017321 }
17322}
17323
17324sub getSONAME($)
17325{
17326 my $Path = $_[0];
17327 return if(not $Path);
17328 if(defined $Cache{"getSONAME"}{$Path}) {
17329 return $Cache{"getSONAME"}{$Path};
17330 }
17331 my $ObjdumpCmd = get_CmdPath("objdump");
17332 if(not $ObjdumpCmd) {
17333 exitStatus("Not_Found", "can't find \"objdump\"");
17334 }
17335 my $SonameCmd = "$ObjdumpCmd -x $Path 2>$TMP_DIR/null";
17336 if($OSgroup eq "windows") {
17337 $SonameCmd .= " | find \"SONAME\"";
17338 }
17339 else {
17340 $SonameCmd .= " | grep SONAME";
17341 }
17342 if(my $SonameInfo = `$SonameCmd`) {
17343 if($SonameInfo=~/SONAME\s+([^\s]+)/) {
17344 return ($Cache{"getSONAME"}{$Path} = $1);
17345 }
17346 }
17347 return ($Cache{"getSONAME"}{$Path}="");
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017348}
17349
17350sub getSOPaths_Dest($$)
17351{
17352 my ($Dest, $LibVersion) = @_;
17353 if(skip_lib($Dest, $LibVersion)) {
17354 return ();
17355 }
17356 if(-f $Dest)
17357 {
17358 if(not parse_libname($Dest, "name", $OStarget)) {
17359 exitStatus("Error", "incorrect format of library (should be *.$LIB_EXT): \'$Dest\'");
17360 }
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040017361 registerObject($Dest, $LibVersion);
17362 registerObject_Dir(get_dirname($Dest), $LibVersion);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017363 return ($Dest);
17364 }
17365 elsif(-d $Dest)
17366 {
17367 $Dest=~s/[\/\\]+\Z//g;
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040017368 my %Libs = ();
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017369 if($SystemPaths{"lib"}{$Dest})
17370 { # you have specified /usr/lib as the search directory (<libs>) in the XML descriptor
17371 # and the real name of the library by -l option (bz2, stdc++, Xaw, ...)
17372 foreach my $Path (cmd_find($Dest,"","*".esc($TargetLibraryName)."*\.$LIB_EXT*",2))
17373 { # all files and symlinks that match the name of a library
17374 if(get_filename($Path)=~/\A(|lib)\Q$TargetLibraryName\E[\d\-]*\.$LIB_EXT[\d\.]*\Z/i)
17375 {
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040017376 registerObject($Path, $LibVersion);
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040017377 $Libs{resolve_symlink($Path)}=1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017378 }
17379 }
17380 }
17381 else
17382 { # search for all files and symlinks
17383 foreach my $Path (find_libs($Dest,"",""))
17384 {
17385 next if(ignore_path($Path));
17386 next if(skip_lib($Path, $LibVersion));
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040017387 registerObject($Path, $LibVersion);
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040017388 $Libs{resolve_symlink($Path)}=1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017389 }
17390 if($OSgroup eq "macos")
17391 { # shared libraries on MacOS X may have no extension
17392 foreach my $Path (cmd_find($Dest,"f","",""))
17393 {
17394 next if(ignore_path($Path));
17395 next if(skip_lib($Path, $LibVersion));
17396 if(get_filename($Path)!~/\./
Andrey Ponomarenko85043792012-05-14 16:48:07 +040017397 and cmd_file($Path)=~/(shared|dynamic)\s+library/i)
17398 {
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040017399 registerObject($Path, $LibVersion);
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040017400 $Libs{resolve_symlink($Path)}=1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017401 }
17402 }
17403 }
17404 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040017405 return keys(%Libs);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017406 }
17407 else {
17408 return ();
17409 }
17410}
17411
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040017412sub isCyclical($$)
17413{
17414 my ($Stack, $Value) = @_;
17415 return (grep {$_ eq $Value} @{$Stack});
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017416}
17417
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017418sub generateTemplate()
17419{
17420 writeFile("VERSION.xml", $DescriptorTemplate."\n");
17421 printMsg("INFO", "XML-descriptor template ./VERSION.xml has been generated");
17422}
17423
17424sub detectWordSize()
17425{
17426 return "" if(not $GCC_PATH);
17427 if($Cache{"detectWordSize"}) {
17428 return $Cache{"detectWordSize"};
17429 }
17430 writeFile("$TMP_DIR/empty.h", "");
Andrey Ponomarenkoa01311b2012-06-08 17:20:02 +040017431 my $Defines = `$GCC_PATH -E -dD \"$TMP_DIR/empty.h\"`;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017432 unlink("$TMP_DIR/empty.h");
17433 my $WSize = 0;
17434 if($Defines=~/ __SIZEOF_POINTER__\s+(\d+)/)
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040017435 { # GCC 4
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017436 $WSize = $1;
17437 }
17438 elsif($Defines=~/ __PTRDIFF_TYPE__\s+(\w+)/)
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040017439 { # GCC 3
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017440 my $PTRDIFF = $1;
17441 if($PTRDIFF=~/long/) {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040017442 $WSize = "8";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017443 }
17444 else {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040017445 $WSize = "4";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017446 }
17447 }
Andrey Ponomarenko01117f12012-06-26 12:23:02 +040017448 if(not $WSize) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017449 exitStatus("Error", "can't check WORD size");
17450 }
17451 return ($Cache{"detectWordSize"} = $WSize);
17452}
17453
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +040017454sub getWordSize($) {
17455 return $WORD_SIZE{$_[0]};
17456}
17457
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017458sub majorVersion($)
17459{
17460 my $V = $_[0];
17461 return 0 if(not $V);
17462 my @VParts = split(/\./, $V);
17463 return $VParts[0];
17464}
17465
17466sub cmpVersions($$)
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040017467{ # compare two versions in dotted-numeric format
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017468 my ($V1, $V2) = @_;
17469 return 0 if($V1 eq $V2);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017470 my @V1Parts = split(/\./, $V1);
17471 my @V2Parts = split(/\./, $V2);
17472 for (my $i = 0; $i <= $#V1Parts && $i <= $#V2Parts; $i++) {
17473 return -1 if(int($V1Parts[$i]) < int($V2Parts[$i]));
17474 return 1 if(int($V1Parts[$i]) > int($V2Parts[$i]));
17475 }
17476 return -1 if($#V1Parts < $#V2Parts);
17477 return 1 if($#V1Parts > $#V2Parts);
17478 return 0;
17479}
17480
17481sub read_ABI_Dump($$)
17482{
17483 my ($LibVersion, $Path) = @_;
17484 return if(not $LibVersion or not -e $Path);
17485 my $FilePath = "";
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040017486 if(isDump_U($Path))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017487 { # input *.abi
17488 $FilePath = $Path;
17489 }
17490 else
17491 { # input *.abi.tar.gz
17492 $FilePath = unpackDump($Path);
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040017493 if(not isDump_U($FilePath)) {
17494 exitStatus("Invalid_Dump", "specified ABI dump \'$Path\' is not valid, try to recreate it");
17495 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017496 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +040017497
Andrey Ponomarenko01117f12012-06-26 12:23:02 +040017498 my $ABI = {};
Andrey Ponomarenko5c09ef32012-06-14 18:17:33 +040017499
Andrey Ponomarenko01117f12012-06-26 12:23:02 +040017500 my $Line = readLineNum($FilePath, 0);
17501 if($Line=~/xml/)
17502 { # XML format
17503 loadModule("XmlDump");
17504 $ABI = readXmlDump($FilePath);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017505 }
Andrey Ponomarenko01117f12012-06-26 12:23:02 +040017506 else
17507 { # Perl Data::Dumper format (default)
17508 open(DUMP, $FilePath);
17509 local $/ = undef;
17510 my $Content = <DUMP>;
17511 close(DUMP);
17512
17513 if(get_dirname($FilePath) eq $TMP_DIR."/unpack")
17514 { # remove temp file
17515 unlink($FilePath);
17516 }
17517 if($Content!~/};\s*\Z/) {
17518 exitStatus("Invalid_Dump", "specified ABI dump \'$Path\' is not valid, try to recreate it");
17519 }
17520 $ABI = eval($Content);
17521 if(not $ABI) {
17522 exitStatus("Error", "internal error - eval() procedure seem to not working correctly, try to remove 'use strict' and try again");
17523 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017524 }
17525 # new dumps (>=1.22) have a personal versioning
Andrey Ponomarenko01117f12012-06-26 12:23:02 +040017526 my $DumpVersion = $ABI->{"ABI_DUMP_VERSION"};
17527 my $ToolVersion = $ABI->{"ABI_COMPLIANCE_CHECKER_VERSION"};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017528 if(not $DumpVersion)
17529 { # old dumps (<=1.21.6) have been marked by the tool version
17530 $DumpVersion = $ToolVersion;
17531 }
17532 $UsedDump{$LibVersion}{"V"} = $DumpVersion;
17533 if(majorVersion($DumpVersion) ne majorVersion($ABI_DUMP_VERSION))
17534 { # should be compatible with dumps of the same major version
17535 if(cmpVersions($DumpVersion, $ABI_DUMP_VERSION)>0)
17536 { # Don't know how to parse future dump formats
Andrey Ponomarenko01117f12012-06-26 12:23:02 +040017537 exitStatus("Dump_Version", "incompatible version \'$DumpVersion\' of specified ABI dump (newer than $ABI_DUMP_VERSION)");
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017538 }
Andrey Ponomarenko01117f12012-06-26 12:23:02 +040017539 elsif(cmpVersions($DumpVersion, $TOOL_VERSION)>0 and not $ABI->{"ABI_DUMP_VERSION"})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017540 { # Don't know how to parse future dump formats
Andrey Ponomarenko01117f12012-06-26 12:23:02 +040017541 exitStatus("Dump_Version", "incompatible version \'$DumpVersion\' of specified ABI dump (newer than $TOOL_VERSION)");
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017542 }
17543 if($UseOldDumps)
17544 {
17545 if(cmpVersions($DumpVersion, $OLDEST_SUPPORTED_VERSION)<0) {
Andrey Ponomarenko01117f12012-06-26 12:23:02 +040017546 exitStatus("Dump_Version", "incompatible version \'$DumpVersion\' of specified ABI dump (older than $OLDEST_SUPPORTED_VERSION)");
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017547 }
17548 }
17549 else
17550 {
Andrey Ponomarenko01117f12012-06-26 12:23:02 +040017551 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 +040017552 if(cmpVersions($DumpVersion, $OLDEST_SUPPORTED_VERSION)>=0) {
17553 $Msg .= "\nUse -old-dumps option to use old-version dumps ($OLDEST_SUPPORTED_VERSION<=V<".majorVersion($ABI_DUMP_VERSION).".0)";
17554 }
17555 exitStatus("Dump_Version", $Msg);
17556 }
17557 }
Andrey Ponomarenko5c09ef32012-06-14 18:17:33 +040017558 if(not checkDump($LibVersion, "2.11"))
17559 { # old ABI dumps
17560 $UsedDump{$LibVersion}{"BinOnly"} = 1;
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040017561 }
Andrey Ponomarenko01117f12012-06-26 12:23:02 +040017562 elsif($ABI->{"BinOnly"})
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040017563 { # ABI dump created with --binary option
17564 $UsedDump{$LibVersion}{"BinOnly"} = 1;
17565 }
Andrey Ponomarenko5c09ef32012-06-14 18:17:33 +040017566 else
17567 { # default
17568 $UsedDump{$LibVersion}{"SrcBin"} = 1;
17569 }
Andrey Ponomarenko01117f12012-06-26 12:23:02 +040017570 if(defined $ABI->{"Mode"}
17571 and $ABI->{"Mode"} eq "Extended")
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017572 { # --ext option
17573 $ExtendedCheck = 1;
17574 }
Andrey Ponomarenko01117f12012-06-26 12:23:02 +040017575 if(my $Lang = $ABI->{"Language"})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017576 {
17577 $UsedDump{$LibVersion}{"L"} = $Lang;
17578 setLanguage($LibVersion, $Lang);
17579 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040017580 if(checkDump($LibVersion, "2.15")) {
Andrey Ponomarenko01117f12012-06-26 12:23:02 +040017581 $TypeInfo{$LibVersion} = $ABI->{"TypeInfo"};
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040017582 }
17583 else
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017584 { # support for old ABI dumps
Andrey Ponomarenko01117f12012-06-26 12:23:02 +040017585 my $TInfo = $ABI->{"TypeInfo"};
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040017586 if(not $TInfo)
17587 { # support for older ABI dumps
Andrey Ponomarenko01117f12012-06-26 12:23:02 +040017588 $TInfo = $ABI->{"TypeDescr"};
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040017589 }
17590 my %Tid_TDid = ();
17591 foreach my $TDid (keys(%{$TInfo}))
17592 {
17593 foreach my $Tid (keys(%{$TInfo->{$TDid}}))
17594 {
17595 $MAX_ID = $Tid if($Tid>$MAX_ID);
17596 $MAX_ID = $TDid if($TDid and $TDid>$MAX_ID);
17597 $Tid_TDid{$Tid}{$TDid}=1;
17598 }
17599 }
17600 my %NewID = ();
17601 foreach my $Tid (keys(%Tid_TDid))
17602 {
17603 my @TDids = keys(%{$Tid_TDid{$Tid}});
17604 if($#TDids>=1)
17605 {
17606 foreach my $TDid (@TDids)
17607 {
17608 if($TDid) {
17609 %{$TypeInfo{$LibVersion}{$Tid}} = %{$TInfo->{$TDid}{$Tid}};
17610 }
17611 else
17612 {
17613 if(my $ID = ++$MAX_ID)
17614 {
17615 $NewID{$TDid}{$Tid} = $ID;
17616 %{$TypeInfo{$LibVersion}{$ID}} = %{$TInfo->{$TDid}{$Tid}};
17617 $TypeInfo{$LibVersion}{$ID}{"Tid"} = $ID;
17618 }
17619 }
17620 }
17621 }
17622 else
17623 {
17624 my $TDid = $TDids[0];
17625 %{$TypeInfo{$LibVersion}{$Tid}} = %{$TInfo->{$TDid}{$Tid}};
17626 }
17627 }
17628 foreach my $Tid (keys(%{$TypeInfo{$LibVersion}}))
17629 {
17630 my %Info = %{$TypeInfo{$LibVersion}{$Tid}};
17631 if(defined $Info{"BaseType"})
17632 {
17633 my $Bid = $Info{"BaseType"}{"Tid"};
17634 my $BDid = $Info{"BaseType"}{"TDid"};
17635 $BDid="" if(not defined $BDid);
17636 if(defined $NewID{$BDid} and my $ID = $NewID{$BDid}{$Bid}) {
17637 $TypeInfo{$LibVersion}{$Tid}{"BaseType"}{"Tid"} = $ID;
17638 }
17639 delete($TypeInfo{$LibVersion}{$Tid}{"BaseType"}{"TDid"});
17640 }
17641 delete($TypeInfo{$LibVersion}{$Tid}{"TDid"});
17642 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017643 }
Andrey Ponomarenko01117f12012-06-26 12:23:02 +040017644 read_Machine_DumpInfo($ABI, $LibVersion);
17645 $SymbolInfo{$LibVersion} = $ABI->{"SymbolInfo"};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017646 if(not $SymbolInfo{$LibVersion})
17647 { # support for old dumps
Andrey Ponomarenko01117f12012-06-26 12:23:02 +040017648 $SymbolInfo{$LibVersion} = $ABI->{"FuncDescr"};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017649 }
17650 if(not keys(%{$SymbolInfo{$LibVersion}}))
17651 { # validation of old-version dumps
17652 if(not $ExtendedCheck) {
17653 exitStatus("Invalid_Dump", "the input dump d$LibVersion is invalid");
17654 }
17655 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040017656 if(checkDump($LibVersion, "2.15")) {
Andrey Ponomarenko01117f12012-06-26 12:23:02 +040017657 $DepLibrary_Symbol{$LibVersion} = $ABI->{"DepSymbols"};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017658 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040017659 else
17660 { # support for old ABI dumps
Andrey Ponomarenko01117f12012-06-26 12:23:02 +040017661 my $DepSymbols = $ABI->{"DepSymbols"};
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040017662 if(not $DepSymbols) {
Andrey Ponomarenko01117f12012-06-26 12:23:02 +040017663 $DepSymbols = $ABI->{"DepInterfaces"};
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040017664 }
17665 if(not $DepSymbols)
17666 { # Cannot reconstruct DepSymbols. This may result in false
17667 # positives if the old dump is for library 2. Not a problem if
17668 # old dumps are only from old libraries.
17669 $DepSymbols = {};
17670 }
17671 foreach my $Symbol (keys(%{$DepSymbols})) {
17672 $DepSymbol_Library{$LibVersion}{$Symbol} = 1;
17673 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017674 }
Andrey Ponomarenko01117f12012-06-26 12:23:02 +040017675 $SymVer{$LibVersion} = $ABI->{"SymbolVersion"};
17676 $Descriptor{$LibVersion}{"Version"} = $ABI->{"LibraryVersion"};
17677 $SkipTypes{$LibVersion} = $ABI->{"SkipTypes"};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017678 if(not $SkipTypes{$LibVersion})
17679 { # support for old dumps
Andrey Ponomarenko01117f12012-06-26 12:23:02 +040017680 $SkipTypes{$LibVersion} = $ABI->{"OpaqueTypes"};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017681 }
Andrey Ponomarenko01117f12012-06-26 12:23:02 +040017682 $SkipSymbols{$LibVersion} = $ABI->{"SkipSymbols"};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017683 if(not $SkipSymbols{$LibVersion})
17684 { # support for old dumps
Andrey Ponomarenko01117f12012-06-26 12:23:02 +040017685 $SkipSymbols{$LibVersion} = $ABI->{"SkipInterfaces"};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017686 }
17687 if(not $SkipSymbols{$LibVersion})
17688 { # support for old dumps
Andrey Ponomarenko01117f12012-06-26 12:23:02 +040017689 $SkipSymbols{$LibVersion} = $ABI->{"InternalInterfaces"};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017690 }
Andrey Ponomarenko01117f12012-06-26 12:23:02 +040017691 $SkipNameSpaces{$LibVersion} = $ABI->{"SkipNameSpaces"};
17692 $TargetHeaders{$LibVersion} = $ABI->{"TargetHeaders"};
17693 foreach my $Path (keys(%{$ABI->{"SkipHeaders"}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017694 {
Andrey Ponomarenko01117f12012-06-26 12:23:02 +040017695 $SkipHeadersList{$LibVersion}{$Path} = $ABI->{"SkipHeaders"}{$Path};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017696 my ($CPath, $Type) = classifyPath($Path);
Andrey Ponomarenko01117f12012-06-26 12:23:02 +040017697 $SkipHeaders{$LibVersion}{$Type}{$CPath} = $ABI->{"SkipHeaders"}{$Path};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017698 }
Andrey Ponomarenko01117f12012-06-26 12:23:02 +040017699 read_Headers_DumpInfo($ABI, $LibVersion);
17700 read_Libs_DumpInfo($ABI, $LibVersion);
Andrey Ponomarenko5c09ef32012-06-14 18:17:33 +040017701 if(not checkDump($LibVersion, "2.10.1")
17702 or not $TargetHeaders{$LibVersion})
Andrey Ponomarenko85043792012-05-14 16:48:07 +040017703 { # support for old ABI dumps: added target headers
17704 foreach (keys(%{$Registered_Headers{$LibVersion}})) {
17705 $TargetHeaders{$LibVersion}{get_filename($_)}=1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017706 }
17707 }
Andrey Ponomarenko01117f12012-06-26 12:23:02 +040017708 $Constants{$LibVersion} = $ABI->{"Constants"};
17709 $NestedNameSpaces{$LibVersion} = $ABI->{"NameSpaces"};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017710 if(not $NestedNameSpaces{$LibVersion})
17711 { # support for old dumps
17712 # Cannot reconstruct NameSpaces. This may affect design
17713 # of the compatibility report.
17714 $NestedNameSpaces{$LibVersion} = {};
17715 }
17716 # target system type
17717 # needed to adopt HTML report
17718 if(not $DumpSystem)
17719 { # to use in createSymbolsList(...)
Andrey Ponomarenko01117f12012-06-26 12:23:02 +040017720 $OStarget = $ABI->{"Target"};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017721 }
17722 # recreate environment
17723 foreach my $Lib_Name (keys(%{$Library_Symbol{$LibVersion}}))
17724 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040017725 foreach my $Symbol (keys(%{$Library_Symbol{$LibVersion}{$Lib_Name}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017726 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040017727 $Symbol_Library{$LibVersion}{$Symbol} = $Lib_Name;
17728 if($Library_Symbol{$LibVersion}{$Lib_Name}{$Symbol}<=-1)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017729 { # data marked as -size in the dump
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040017730 $GlobalDataObject{$LibVersion}{$Symbol}=1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017731 }
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040017732 if($COMMON_LANGUAGE{$LibVersion} ne "C++")
17733 {
17734 if(index($Symbol, "_Z")==0 or index($Symbol, "?")==0) {
17735 setLanguage($LibVersion, "C++");
17736 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017737 }
17738 }
17739 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040017740 foreach my $Lib_Name (keys(%{$DepLibrary_Symbol{$LibVersion}}))
17741 {
17742 foreach my $Symbol (keys(%{$DepLibrary_Symbol{$LibVersion}{$Lib_Name}})) {
17743 $DepSymbol_Library{$LibVersion}{$Symbol} = $Lib_Name;
17744 }
17745 }
17746
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017747 my @VFunc = ();
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040017748 foreach my $InfoId (keys(%{$SymbolInfo{$LibVersion}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017749 {
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +040017750 if(my $MnglName = $SymbolInfo{$LibVersion}{$InfoId}{"MnglName"})
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040017751 {
17752 if(not $Symbol_Library{$LibVersion}{$MnglName}
17753 and not $DepSymbol_Library{$LibVersion}{$MnglName}) {
17754 push(@VFunc, $MnglName);
17755 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017756 }
17757 }
17758 translateSymbols(@VFunc, $LibVersion);
17759 translateSymbols(keys(%{$Symbol_Library{$LibVersion}}), $LibVersion);
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040017760 translateSymbols(keys(%{$DepSymbol_Library{$LibVersion}}), $LibVersion);
17761
17762 foreach my $TypeId (sort {int($a)<=>int($b)} keys(%{$TypeInfo{$LibVersion}}))
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +040017763 { # order is important
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040017764 if(defined $TypeInfo{$LibVersion}{$TypeId}{"BaseClass"})
17765 { # support for old ABI dumps < 2.0 (ACC 1.22)
17766 foreach my $BId (keys(%{$TypeInfo{$LibVersion}{$TypeId}{"BaseClass"}}))
17767 {
17768 if(my $Access = $TypeInfo{$LibVersion}{$TypeId}{"BaseClass"}{$BId})
17769 {
17770 if($Access ne "public") {
17771 $TypeInfo{$LibVersion}{$TypeId}{"Base"}{$BId}{"access"} = $Access;
17772 }
17773 }
17774 $TypeInfo{$LibVersion}{$TypeId}{"Base"}{$BId} = {};
17775 }
17776 delete($TypeInfo{$LibVersion}{$TypeId}{"BaseClass"});
17777 }
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040017778 if(my $Header = $TypeInfo{$LibVersion}{$TypeId}{"Header"})
17779 { # support for old ABI dumps
17780 $TypeInfo{$LibVersion}{$TypeId}{"Header"} = path_format($Header, $OSgroup);
17781 }
Andrey Ponomarenko01117f12012-06-26 12:23:02 +040017782 if(not defined $TypeInfo{$LibVersion}{$TypeId}{"Tid"}) {
17783 $TypeInfo{$LibVersion}{$TypeId}{"Tid"} = $TypeId;
17784 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040017785 my %TInfo = %{$TypeInfo{$LibVersion}{$TypeId}};
17786 if(defined $TInfo{"Base"})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017787 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040017788 foreach (keys(%{$TInfo{"Base"}})) {
17789 $Class_SubClasses{$LibVersion}{$_}{$TypeId}=1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017790 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040017791 }
Andrey Ponomarenko01117f12012-06-26 12:23:02 +040017792 if($TInfo{"Type"} eq "MethodPtr")
17793 {
17794 if(defined $TInfo{"Param"})
17795 { # support for old ABI dumps <= 1.17
17796 if(not defined $TInfo{"Param"}{"0"})
17797 {
17798 my $Max = keys(%{$TInfo{"Param"}});
17799 foreach my $Pos (1 .. $Max) {
17800 $TInfo{"Param"}{$Pos-1} = $TInfo{"Param"}{$Pos};
17801 }
17802 delete($TInfo{"Param"}{$Max});
17803 %{$TypeInfo{$LibVersion}{$TypeId}} = %TInfo;
17804 }
17805 }
17806 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040017807 if($TInfo{"Type"} eq "Typedef" and defined $TInfo{"BaseType"})
17808 {
17809 if(my $BTid = $TInfo{"BaseType"}{"Tid"})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017810 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040017811 my $BName = $TypeInfo{$LibVersion}{$BTid}{"Name"};
17812 if(not $BName)
17813 { # broken type
17814 next;
17815 }
17816 if($TInfo{"Name"} eq $BName)
17817 { # typedef to "class Class"
17818 # should not be registered in TName_Tid
17819 next;
17820 }
17821 if(not $Typedef_BaseName{$LibVersion}{$TInfo{"Name"}}) {
17822 $Typedef_BaseName{$LibVersion}{$TInfo{"Name"}} = $BName;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017823 }
17824 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040017825 }
17826 if(not $TName_Tid{$LibVersion}{$TInfo{"Name"}})
17827 { # classes: class (id1), typedef (artificial, id2 > id1)
17828 $TName_Tid{$LibVersion}{$TInfo{"Name"}} = $TypeId;
17829 }
17830 }
17831
17832 if(not checkDump($LibVersion, "2.15"))
17833 { # support for old ABI dumps
17834 my %Dups = ();
17835 foreach my $InfoId (keys(%{$SymbolInfo{$LibVersion}}))
17836 {
17837 if(my $ClassId = $SymbolInfo{$LibVersion}{$InfoId}{"Class"})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017838 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040017839 if(not defined $TypeInfo{$LibVersion}{$ClassId})
17840 { # remove template decls
17841 delete($SymbolInfo{$LibVersion}{$InfoId});
17842 next;
Andrey Ponomarenko16934472012-03-29 15:37:04 +040017843 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017844 }
Andrey Ponomarenkob8d203d2012-05-25 18:11:07 +040017845 my $MName = $SymbolInfo{$LibVersion}{$InfoId}{"MnglName"};
17846 if(not $MName and $SymbolInfo{$LibVersion}{$InfoId}{"Class"})
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040017847 { # templates
17848 delete($SymbolInfo{$LibVersion}{$InfoId});
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017849 }
17850 }
17851 }
17852
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +040017853 foreach my $InfoId (keys(%{$SymbolInfo{$LibVersion}}))
17854 {
17855 if(not $SymbolInfo{$LibVersion}{$InfoId}{"MnglName"})
17856 { # ABI dumps have no mangled names for C-functions
17857 $SymbolInfo{$LibVersion}{$InfoId}{"MnglName"} = $SymbolInfo{$LibVersion}{$InfoId}{"ShortName"};
17858 }
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040017859 if(my $Header = $SymbolInfo{$LibVersion}{$InfoId}{"Header"})
17860 { # support for old ABI dumps
17861 $SymbolInfo{$LibVersion}{$InfoId}{"Header"} = path_format($Header, $OSgroup);
17862 }
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +040017863 }
17864
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017865 $Descriptor{$LibVersion}{"Dump"} = 1;
17866}
17867
17868sub read_Machine_DumpInfo($$)
17869{
Andrey Ponomarenko01117f12012-06-26 12:23:02 +040017870 my ($ABI, $LibVersion) = @_;
17871 if($ABI->{"Arch"}) {
17872 $CPU_ARCH{$LibVersion} = $ABI->{"Arch"};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017873 }
Andrey Ponomarenko01117f12012-06-26 12:23:02 +040017874 if($ABI->{"WordSize"}) {
17875 $WORD_SIZE{$LibVersion} = $ABI->{"WordSize"};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017876 }
17877 else
17878 { # support for old dumps
Andrey Ponomarenko01117f12012-06-26 12:23:02 +040017879 $WORD_SIZE{$LibVersion} = $ABI->{"SizeOfPointer"};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017880 }
17881 if(not $WORD_SIZE{$LibVersion})
17882 { # support for old dumps (<1.23)
17883 if(my $Tid = getTypeIdByName("char*", $LibVersion))
17884 { # size of char*
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040017885 $WORD_SIZE{$LibVersion} = $TypeInfo{$LibVersion}{$Tid}{"Size"};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017886 }
17887 else
17888 {
17889 my $PSize = 0;
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040017890 foreach my $Tid (keys(%{$TypeInfo{$LibVersion}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017891 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040017892 if($TypeInfo{$LibVersion}{$Tid}{"Type"} eq "Pointer")
17893 { # any "pointer"-type
17894 $PSize = $TypeInfo{$LibVersion}{$Tid}{"Size"};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017895 last;
17896 }
17897 }
17898 if($PSize)
17899 { # a pointer type size
17900 $WORD_SIZE{$LibVersion} = $PSize;
17901 }
17902 else {
17903 printMsg("WARNING", "cannot identify a WORD size in the ABI dump (too old format)");
17904 }
17905 }
17906 }
Andrey Ponomarenko01117f12012-06-26 12:23:02 +040017907 if($ABI->{"GccVersion"}) {
17908 $GCC_VERSION{$LibVersion} = $ABI->{"GccVersion"};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017909 }
17910}
17911
17912sub read_Libs_DumpInfo($$)
17913{
Andrey Ponomarenko01117f12012-06-26 12:23:02 +040017914 my ($ABI, $LibVersion) = @_;
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040017915 $Library_Symbol{$LibVersion} = $ABI->{"Symbols"};
17916 if(not $Library_Symbol{$LibVersion})
17917 { # support for old dumps
17918 $Library_Symbol{$LibVersion} = $ABI->{"Interfaces"};
17919 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017920 if(keys(%{$Library_Symbol{$LibVersion}})
17921 and not $DumpAPI) {
17922 $Descriptor{$LibVersion}{"Libs"} = "OK";
17923 }
17924}
17925
17926sub read_Headers_DumpInfo($$)
17927{
Andrey Ponomarenko01117f12012-06-26 12:23:02 +040017928 my ($ABI, $LibVersion) = @_;
17929 if(keys(%{$ABI->{"Headers"}})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017930 and not $DumpAPI) {
17931 $Descriptor{$LibVersion}{"Headers"} = "OK";
17932 }
Andrey Ponomarenko01117f12012-06-26 12:23:02 +040017933 foreach my $Identity (sort {$ABI->{"Headers"}{$a}<=>$ABI->{"Headers"}{$b}} keys(%{$ABI->{"Headers"}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017934 { # headers info is stored in the old dumps in the different way
17935 if($UseOldDumps
Andrey Ponomarenko01117f12012-06-26 12:23:02 +040017936 and my $Name = $ABI->{"Headers"}{$Identity}{"Name"})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017937 { # support for old dumps: headers info corrected in 1.22
17938 $Identity = $Name;
17939 }
17940 $Registered_Headers{$LibVersion}{$Identity}{"Identity"} = $Identity;
Andrey Ponomarenko01117f12012-06-26 12:23:02 +040017941 $Registered_Headers{$LibVersion}{$Identity}{"Pos"} = $ABI->{"Headers"}{$Identity};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017942 }
17943}
17944
17945sub find_libs($$$)
17946{
17947 my ($Path, $Type, $MaxDepth) = @_;
17948 # FIXME: correct the search pattern
17949 return cmd_find($Path, $Type, ".*\\.$LIB_EXT\[0-9.]*", $MaxDepth);
17950}
17951
17952sub createDescriptor($$)
17953{
17954 my ($LibVersion, $Path) = @_;
17955 if(not $LibVersion or not $Path
17956 or not -e $Path) {
17957 return "";
17958 }
17959 if(-d $Path)
17960 { # directory with headers files and shared objects
17961 return "
17962 <version>
17963 ".$TargetVersion{$LibVersion}."
17964 </version>
17965
17966 <headers>
17967 $Path
17968 </headers>
17969
17970 <libs>
17971 $Path
17972 </libs>";
17973 }
17974 else
17975 { # files
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040017976 if($Path=~/\.(xml|desc)\Z/i)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017977 { # standard XML-descriptor
17978 return readFile($Path);
17979 }
17980 elsif(is_header($Path, 2, $LibVersion))
17981 { # header file
17982 return "
17983 <version>
17984 ".$TargetVersion{$LibVersion}."
17985 </version>
17986
17987 <headers>
17988 $Path
17989 </headers>
17990
17991 <libs>
17992 none
17993 </libs>";
17994 }
17995 elsif(parse_libname($Path, "name", $OStarget))
17996 { # shared object
17997 return "
17998 <version>
17999 ".$TargetVersion{$LibVersion}."
18000 </version>
18001
18002 <headers>
18003 none
18004 </headers>
18005
18006 <libs>
18007 $Path
18008 </libs>";
18009 }
18010 else
18011 { # standard XML-descriptor
18012 return readFile($Path);
18013 }
18014 }
18015}
18016
18017sub detect_lib_default_paths()
18018{
18019 my %LPaths = ();
18020 if($OSgroup eq "bsd")
18021 {
Andrey Ponomarenkoa01311b2012-06-08 17:20:02 +040018022 if(my $LdConfig = get_CmdPath("ldconfig"))
18023 {
18024 foreach my $Line (split(/\n/, `$LdConfig -r 2>\"$TMP_DIR/null\"`))
18025 {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040018026 if($Line=~/\A[ \t]*\d+:\-l(.+) \=\> (.+)\Z/) {
18027 $LPaths{"lib".$1} = $2;
18028 }
18029 }
18030 }
18031 else {
18032 printMsg("WARNING", "can't find ldconfig");
18033 }
18034 }
18035 else
18036 {
18037 if(my $LdConfig = get_CmdPath("ldconfig"))
18038 {
18039 if($SystemRoot and $OSgroup eq "linux")
18040 { # use host (x86) ldconfig with the target (arm) ld.so.conf
18041 if(-e $SystemRoot."/etc/ld.so.conf") {
18042 $LdConfig .= " -f ".$SystemRoot."/etc/ld.so.conf";
18043 }
18044 }
Andrey Ponomarenkoa01311b2012-06-08 17:20:02 +040018045 foreach my $Line (split(/\n/, `$LdConfig -p 2>\"$TMP_DIR/null\"`))
18046 {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040018047 if($Line=~/\A[ \t]*([^ \t]+) .* \=\> (.+)\Z/)
18048 {
18049 my ($Name, $Path) = ($1, $2);
18050 $Path=~s/[\/]{2,}/\//;
18051 $LPaths{$Name} = $Path;
18052 }
18053 }
18054 }
18055 elsif($OSgroup=~/linux/i) {
18056 printMsg("WARNING", "can't find ldconfig");
18057 }
18058 }
18059 return \%LPaths;
18060}
18061
18062sub detect_bin_default_paths()
18063{
18064 my $EnvPaths = $ENV{"PATH"};
18065 if($OSgroup eq "beos") {
18066 $EnvPaths.=":".$ENV{"BETOOLS"};
18067 }
18068 my $Sep = ($OSgroup eq "windows")?";":":|;";
18069 foreach my $Path (sort {length($a)<=>length($b)} split(/$Sep/, $EnvPaths))
18070 {
18071 $Path = path_format($Path, $OSgroup);
18072 $Path=~s/[\/\\]+\Z//g;
18073 next if(not $Path);
18074 if($SystemRoot
18075 and $Path=~/\A\Q$SystemRoot\E\//)
18076 { # do NOT use binaries from target system
18077 next;
18078 }
18079 $DefaultBinPaths{$Path} = 1;
18080 }
18081}
18082
18083sub detect_inc_default_paths()
18084{
18085 return () if(not $GCC_PATH);
18086 my %DPaths = ("Cpp"=>{},"Gcc"=>{},"Inc"=>{});
18087 writeFile("$TMP_DIR/empty.h", "");
Andrey Ponomarenkoa01311b2012-06-08 17:20:02 +040018088 foreach my $Line (split(/\n/, `$GCC_PATH -v -x c++ -E \"$TMP_DIR/empty.h\" 2>&1`))
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040018089 { # detecting GCC default include paths
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040018090 if($Line=~/\A[ \t]*((\/|\w+:\\).+)[ \t]*\Z/)
18091 {
18092 my $Path = simplify_path($1);
18093 $Path=~s/[\/\\]+\Z//g;
18094 $Path = path_format($Path, $OSgroup);
18095 if($Path=~/c\+\+|\/g\+\+\//)
18096 {
18097 $DPaths{"Cpp"}{$Path}=1;
18098 if(not defined $MAIN_CPP_DIR
18099 or get_depth($MAIN_CPP_DIR)>get_depth($Path)) {
18100 $MAIN_CPP_DIR = $Path;
18101 }
18102 }
18103 elsif($Path=~/gcc/) {
18104 $DPaths{"Gcc"}{$Path}=1;
18105 }
18106 else
18107 {
18108 next if($Path=~/local[\/\\]+include/);
18109 if($SystemRoot
18110 and $Path!~/\A\Q$SystemRoot\E(\/|\Z)/)
18111 { # The GCC include path for user headers is not a part of the system root
18112 # The reason: you are not specified the --cross-gcc option or selected a wrong compiler
18113 # or it is the internal cross-GCC path like arm-linux-gnueabi/include
18114 next;
18115 }
18116 $DPaths{"Inc"}{$Path}=1;
18117 }
18118 }
18119 }
18120 unlink("$TMP_DIR/empty.h");
18121 return %DPaths;
18122}
18123
18124sub detect_default_paths($)
18125{
18126 my ($HSearch, $LSearch, $BSearch, $GSearch) = (1, 1, 1, 1);
18127 my $Search = $_[0];
18128 if($Search!~/inc/) {
18129 $HSearch = 0;
18130 }
18131 if($Search!~/lib/) {
18132 $LSearch = 0;
18133 }
18134 if($Search!~/bin/) {
18135 $BSearch = 0;
18136 }
18137 if($Search!~/gcc/) {
18138 $GSearch = 0;
18139 }
18140 if(keys(%{$SystemPaths{"include"}}))
18141 { # <search_headers> section of the XML descriptor
18142 # do NOT search for systems headers
18143 $HSearch = 0;
18144 }
18145 if(keys(%{$SystemPaths{"lib"}}))
18146 { # <search_headers> section of the XML descriptor
18147 # do NOT search for systems headers
18148 $LSearch = 0;
18149 }
18150 foreach my $Type (keys(%{$OS_AddPath{$OSgroup}}))
18151 { # additional search paths
18152 next if($Type eq "include" and not $HSearch);
18153 next if($Type eq "lib" and not $LSearch);
18154 next if($Type eq "bin" and not $BSearch);
18155 foreach my $Path (keys(%{$OS_AddPath{$OSgroup}{$Type}}))
18156 {
18157 next if(not -d $Path);
18158 $SystemPaths{$Type}{$Path} = $OS_AddPath{$OSgroup}{$Type}{$Path};
18159 }
18160 }
18161 if($OSgroup ne "windows")
18162 { # unix-like
18163 foreach my $Type ("include", "lib", "bin")
18164 { # automatic detection of system "devel" directories
18165 next if($Type eq "include" and not $HSearch);
18166 next if($Type eq "lib" and not $LSearch);
18167 next if($Type eq "bin" and not $BSearch);
18168 my ($UsrDir, $RootDir) = ("/usr", "/");
18169 if($SystemRoot and $Type ne "bin")
18170 { # 1. search for target headers and libraries
18171 # 2. use host commands: ldconfig, readelf, etc.
18172 ($UsrDir, $RootDir) = ("$SystemRoot/usr", $SystemRoot);
18173 }
18174 foreach my $Path (cmd_find($RootDir,"d","*$Type*",1)) {
18175 $SystemPaths{$Type}{$Path} = 1;
18176 }
18177 if(-d $RootDir."/".$Type)
18178 { # if "/lib" is symbolic link
18179 if($RootDir eq "/") {
18180 $SystemPaths{$Type}{"/".$Type} = 1;
18181 }
18182 else {
18183 $SystemPaths{$Type}{$RootDir."/".$Type} = 1;
18184 }
18185 }
18186 if(-d $UsrDir) {
18187 foreach my $Path (cmd_find($UsrDir,"d","*$Type*",1)) {
18188 $SystemPaths{$Type}{$Path} = 1;
18189 }
18190 if(-d $UsrDir."/".$Type)
18191 { # if "/usr/lib" is symbolic link
18192 $SystemPaths{$Type}{$UsrDir."/".$Type} = 1;
18193 }
18194 }
18195 }
18196 }
18197 if($BSearch)
18198 {
18199 detect_bin_default_paths();
18200 foreach my $Path (keys(%DefaultBinPaths)) {
18201 $SystemPaths{"bin"}{$Path} = $DefaultBinPaths{$Path};
18202 }
18203 }
18204 # check environment variables
18205 if($OSgroup eq "beos")
18206 {
18207 foreach (keys(%{$SystemPaths{"bin"}}))
18208 {
18209 if($_ eq ".") {
18210 next;
18211 }
18212 foreach my $Path (cmd_find($_, "d", "bin", ""))
18213 { # search for /boot/develop/abi/x86/gcc4/tools/gcc-4.4.4-haiku-101111/bin/
18214 $SystemPaths{"bin"}{$Path} = 1;
18215 }
18216 }
18217 if($HSearch)
18218 {
18219 foreach my $Path (split(/:|;/, $ENV{"BEINCLUDES"}))
18220 {
18221 if(is_abs($Path)) {
18222 $DefaultIncPaths{$Path} = 1;
18223 }
18224 }
18225 }
18226 if($LSearch)
18227 {
18228 foreach my $Path (split(/:|;/, $ENV{"BELIBRARIES"}), split(/:|;/, $ENV{"LIBRARY_PATH"}))
18229 {
18230 if(is_abs($Path)) {
18231 $DefaultLibPaths{$Path} = 1;
18232 }
18233 }
18234 }
18235 }
18236 if($LSearch)
18237 { # using linker to get system paths
18238 if(my $LPaths = detect_lib_default_paths())
18239 { # unix-like
18240 foreach my $Name (keys(%{$LPaths}))
18241 {
18242 if($SystemRoot
18243 and $LPaths->{$Name}!~/\A\Q$SystemRoot\E\//)
18244 { # wrong ldconfig configuration
18245 # check your <sysroot>/etc/ld.so.conf
18246 next;
18247 }
18248 $DyLib_DefaultPath{$Name} = $LPaths->{$Name};
18249 $DefaultLibPaths{get_dirname($LPaths->{$Name})} = 1;
18250 }
18251 }
18252 foreach my $Path (keys(%DefaultLibPaths)) {
18253 $SystemPaths{"lib"}{$Path} = $DefaultLibPaths{$Path};
18254 }
18255 }
18256 if($BSearch)
18257 {
18258 if($CrossGcc)
18259 { # --cross-gcc=arm-linux-gcc
18260 if(-e $CrossGcc)
18261 { # absolute or relative path
18262 $GCC_PATH = get_abs_path($CrossGcc);
18263 }
18264 elsif($CrossGcc!~/\// and get_CmdPath($CrossGcc))
18265 { # command name
18266 $GCC_PATH = $CrossGcc;
18267 }
18268 else {
18269 exitStatus("Access_Error", "can't access \'$CrossGcc\'");
18270 }
18271 if($GCC_PATH=~/\s/) {
18272 $GCC_PATH = "\"".$GCC_PATH."\"";
18273 }
18274 }
18275 }
18276 if($GSearch)
18277 { # GCC path and default include dirs
18278 if(not $CrossGcc) {
18279 $GCC_PATH = get_CmdPath("gcc");
18280 }
Andrey Ponomarenko01117f12012-06-26 12:23:02 +040018281 if(not $GCC_PATH)
18282 { # try to find gcc-X.Y
18283 foreach my $Path (sort {$b=~/\/usr\/bin/ cmp $a=~/\/usr\/bin/}
18284 keys(%{$SystemPaths{"bin"}}))
18285 {
18286 if(my @GCCs = cmd_find($Path, "", ".*/gcc-[0-9.]*", 1))
18287 { # select the latest version
18288 @GCCs = sort {$b cmp $a} @GCCs;
18289 if(check_gcc($GCCs[0], "3"))
18290 {
18291 $GCC_PATH = $GCCs[0];
18292 last;
18293 }
18294 }
18295 }
18296 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040018297 if(not $GCC_PATH) {
18298 exitStatus("Not_Found", "can't find GCC>=3.0 in PATH");
18299 }
18300 if(not $CheckObjectsOnly_Opt)
18301 {
18302 if(my $GCC_Ver = get_dumpversion($GCC_PATH))
18303 {
18304 my $GccTarget = get_dumpmachine($GCC_PATH);
18305 printMsg("INFO", "Using GCC $GCC_Ver ($GccTarget)");
18306 if($GccTarget=~/symbian/)
18307 {
18308 $OStarget = "symbian";
18309 $LIB_EXT = $OS_LibExt{$LIB_TYPE}{$OStarget};
18310 }
18311 }
18312 else {
18313 exitStatus("Error", "something is going wrong with the GCC compiler");
18314 }
18315 }
18316 if(not $NoStdInc)
18317 { # do NOT search in GCC standard paths
18318 my %DPaths = detect_inc_default_paths();
18319 %DefaultCppPaths = %{$DPaths{"Cpp"}};
18320 %DefaultGccPaths = %{$DPaths{"Gcc"}};
18321 %DefaultIncPaths = %{$DPaths{"Inc"}};
18322 foreach my $Path (keys(%DefaultIncPaths)) {
18323 $SystemPaths{"include"}{$Path} = $DefaultIncPaths{$Path};
18324 }
18325 }
18326 }
18327 if($HSearch)
18328 { # user include paths
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040018329 my $IncPath = "/usr/include";
18330 if($SystemRoot) {
18331 $IncPath = $SystemRoot.$IncPath;
18332 }
18333 if(-d $IncPath) {
18334 $UserIncPath{$IncPath}=1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040018335 }
18336 }
18337}
18338
18339sub getLIB_EXT($)
18340{
18341 my $Target = $_[0];
18342 if(my $Ext = $OS_LibExt{$LIB_TYPE}{$Target}) {
18343 return $Ext;
18344 }
18345 return $OS_LibExt{$LIB_TYPE}{"default"};
18346}
18347
18348sub getAR_EXT($)
18349{
18350 my $Target = $_[0];
18351 if(my $Ext = $OS_Archive{$Target}) {
18352 return $Ext;
18353 }
18354 return $OS_Archive{"default"};
18355}
18356
18357sub get_dumpversion($)
18358{
18359 my $Cmd = $_[0];
18360 return "" if(not $Cmd);
18361 if($Cache{"get_dumpversion"}{$Cmd}) {
18362 return $Cache{"get_dumpversion"}{$Cmd};
18363 }
Andrey Ponomarenkoa01311b2012-06-08 17:20:02 +040018364 my $V = `$Cmd -dumpversion 2>\"$TMP_DIR/null\"`;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040018365 chomp($V);
18366 return ($Cache{"get_dumpversion"}{$Cmd} = $V);
18367}
18368
18369sub get_dumpmachine($)
18370{
18371 my $Cmd = $_[0];
18372 return "" if(not $Cmd);
18373 if($Cache{"get_dumpmachine"}{$Cmd}) {
18374 return $Cache{"get_dumpmachine"}{$Cmd};
18375 }
Andrey Ponomarenkoa01311b2012-06-08 17:20:02 +040018376 my $Machine = `$Cmd -dumpmachine 2>\"$TMP_DIR/null\"`;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040018377 chomp($Machine);
18378 return ($Cache{"get_dumpmachine"}{$Cmd} = $Machine);
18379}
18380
18381sub check_command($)
18382{
18383 my $Cmd = $_[0];
18384 return "" if(not $Cmd);
18385 my @Options = (
18386 "--version",
18387 "-help"
18388 );
18389 foreach my $Opt (@Options)
18390 {
Andrey Ponomarenkoa01311b2012-06-08 17:20:02 +040018391 my $Info = `$Cmd $Opt 2>\"$TMP_DIR/null\"`;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040018392 if($Info) {
18393 return 1;
18394 }
18395 }
18396 return 0;
18397}
18398
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040018399sub check_gcc($$)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040018400{
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040018401 my ($Cmd, $ReqVer) = @_;
18402 return 0 if(not $Cmd or not $ReqVer);
18403 if(defined $Cache{"check_gcc"}{$Cmd}{$ReqVer}) {
18404 return $Cache{"check_gcc"}{$Cmd}{$ReqVer};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040018405 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040018406 if(my $GccVer = get_dumpversion($Cmd))
18407 {
18408 $GccVer=~s/(-|_)[a-z_]+.*\Z//; # remove suffix (like "-haiku-100818")
18409 if(cmpVersions($GccVer, $ReqVer)>=0) {
18410 return ($Cache{"check_gcc"}{$Cmd}{$ReqVer} = $Cmd);
18411 }
18412 }
18413 return ($Cache{"check_gcc"}{$Cmd}{$ReqVer} = "");
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040018414}
18415
18416sub get_depth($)
18417{
18418 if(defined $Cache{"get_depth"}{$_[0]}) {
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040018419 return $Cache{"get_depth"}{$_[0]};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040018420 }
18421 return ($Cache{"get_depth"}{$_[0]} = ($_[0]=~tr![\/\\]|\:\:!!));
18422}
18423
18424sub find_gcc_cxx_headers($)
18425{
18426 my $LibVersion = $_[0];
18427 return if($Cache{"find_gcc_cxx_headers"});# this function should be called once
18428 # detecting system header paths
18429 foreach my $Path (sort {get_depth($b) <=> get_depth($a)} keys(%DefaultGccPaths))
18430 {
18431 foreach my $HeaderPath (sort {get_depth($a) <=> get_depth($b)} cmd_find($Path,"f","",""))
18432 {
18433 my $FileName = get_filename($HeaderPath);
18434 next if($DefaultGccHeader{$FileName});
18435 $DefaultGccHeader{$FileName} = $HeaderPath;
18436 }
18437 }
18438 if($COMMON_LANGUAGE{$LibVersion} eq "C++" and not $STDCXX_TESTING)
18439 {
18440 foreach my $CppDir (sort {get_depth($b)<=>get_depth($a)} keys(%DefaultCppPaths))
18441 {
18442 my @AllCppHeaders = cmd_find($CppDir,"f","","");
18443 foreach my $Path (sort {get_depth($a)<=>get_depth($b)} @AllCppHeaders)
18444 {
18445 my $FileName = get_filename($Path);
18446 next if($DefaultCppHeader{$FileName});
18447 $DefaultCppHeader{$FileName} = $Path;
18448 }
18449 }
18450 }
18451 $Cache{"find_gcc_cxx_headers"} = 1;
18452}
18453
18454sub parse_libname($$$)
18455{
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040018456 return "" if(not $_[0]);
18457 if(defined $Cache{"parse_libname"}{$_[2]}{$_[1]}{$_[0]}) {
18458 return $Cache{"parse_libname"}{$_[2]}{$_[1]}{$_[0]};
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040018459 }
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040018460 return ($Cache{"parse_libname"}{$_[2]}{$_[1]}{$_[0]} = parse_libname_I(@_));
18461}
18462
18463sub parse_libname_I($$$)
18464{
18465 my ($Name, $Type, $Target) = @_;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040018466 if($Target eq "symbian") {
18467 return parse_libname_symbian($Name, $Type);
18468 }
18469 elsif($Target eq "windows") {
18470 return parse_libname_windows($Name, $Type);
18471 }
18472 my $Ext = getLIB_EXT($Target);
Andrey Ponomarenkoa01311b2012-06-08 17:20:02 +040018473 if($Name=~/((((lib|).+?)([\-\_][\d\-\.\_]+.*?|))\.$Ext)(\.(.+)|)\Z/)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040018474 { # libSDL-1.2.so.0.7.1
18475 # libwbxml2.so.0.0.18
Andrey Ponomarenkoa01311b2012-06-08 17:20:02 +040018476 # libopcodes-2.21.53-system.20110810.so
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040018477 if($Type eq "name")
18478 { # libSDL-1.2
18479 # libwbxml2
18480 return $2;
18481 }
18482 elsif($Type eq "name+ext")
18483 { # libSDL-1.2.so
18484 # libwbxml2.so
18485 return $1;
18486 }
18487 elsif($Type eq "version")
18488 {
Andrey Ponomarenkoa01311b2012-06-08 17:20:02 +040018489 if(defined $7
18490 and $7 ne "")
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040018491 { # 0.7.1
18492 return $7;
18493 }
18494 else
18495 { # libc-2.5.so (=>2.5 version)
18496 my $MV = $5;
18497 $MV=~s/\A[\-\_]+//g;
18498 return $MV;
18499 }
18500 }
18501 elsif($Type eq "short")
18502 { # libSDL
18503 # libwbxml2
18504 return $3;
18505 }
18506 elsif($Type eq "shortest")
18507 { # SDL
18508 # wbxml
18509 return shortest_name($3);
18510 }
18511 }
18512 return "";# error
18513}
18514
18515sub parse_libname_symbian($$)
18516{
18517 my ($Name, $Type) = @_;
18518 my $Ext = getLIB_EXT("symbian");
18519 if($Name=~/(((.+?)(\{.+\}|))\.$Ext)\Z/)
18520 { # libpthread{00010001}.dso
18521 if($Type eq "name")
18522 { # libpthread{00010001}
18523 return $2;
18524 }
18525 elsif($Type eq "name+ext")
18526 { # libpthread{00010001}.dso
18527 return $1;
18528 }
18529 elsif($Type eq "version")
18530 { # 00010001
18531 my $V = $4;
18532 $V=~s/\{(.+)\}/$1/;
18533 return $V;
18534 }
18535 elsif($Type eq "short")
18536 { # libpthread
18537 return $3;
18538 }
18539 elsif($Type eq "shortest")
18540 { # pthread
18541 return shortest_name($3);
18542 }
18543 }
18544 return "";# error
18545}
18546
18547sub parse_libname_windows($$)
18548{
18549 my ($Name, $Type) = @_;
18550 my $Ext = getLIB_EXT("windows");
18551 if($Name=~/((.+?)\.$Ext)\Z/)
18552 { # netapi32.dll
18553 if($Type eq "name")
18554 { # netapi32
18555 return $2;
18556 }
18557 elsif($Type eq "name+ext")
18558 { # netapi32.dll
18559 return $1;
18560 }
18561 elsif($Type eq "version")
18562 { # DLL version embedded
18563 # at binary-level
18564 return "";
18565 }
18566 elsif($Type eq "short")
18567 { # netapi32
18568 return $2;
18569 }
18570 elsif($Type eq "shortest")
18571 { # netapi
18572 return shortest_name($2);
18573 }
18574 }
18575 return "";# error
18576}
18577
18578sub shortest_name($)
18579{
18580 my $Name = $_[0];
18581 # remove prefix
18582 $Name=~s/\A(lib|open)//;
18583 # remove suffix
18584 $Name=~s/[\W\d_]+\Z//i;
18585 $Name=~s/([a-z]{2,})(lib)\Z/$1/i;
18586 return $Name;
18587}
18588
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040018589sub createSymbolsList($$$$$)
18590{
18591 my ($DPath, $SaveTo, $LName, $LVersion, $ArchName) = @_;
18592 read_ABI_Dump(1, $DPath);
18593 if(not $CheckObjectsOnly) {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040018594 prepareSymbols(1);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040018595 }
18596 my %SymbolHeaderLib = ();
18597 my $Total = 0;
18598 # Get List
18599 foreach my $Symbol (sort keys(%{$CompleteSignature{1}}))
18600 {
18601 if(not link_symbol($Symbol, 1, "-Deps"))
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040018602 { # skip src only and all external functions
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040018603 next;
18604 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040018605 if(not symbolFilter($Symbol, 1, "Public", "Binary"))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040018606 { # skip other symbols
18607 next;
18608 }
18609 my $HeaderName = $CompleteSignature{1}{$Symbol}{"Header"};
18610 if(not $HeaderName)
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040018611 { # skip src only and all external functions
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040018612 next;
18613 }
18614 my $DyLib = $Symbol_Library{1}{$Symbol};
18615 if(not $DyLib)
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040018616 { # skip src only and all external functions
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040018617 next;
18618 }
18619 $SymbolHeaderLib{$HeaderName}{$DyLib}{$Symbol} = 1;
18620 $Total+=1;
18621 }
18622 # Draw List
18623 my $SYMBOLS_LIST = "<h1>Public symbols in <span style='color:Blue;'>$LName</span> (<span style='color:Red;'>$LVersion</span>)";
18624 $SYMBOLS_LIST .= " on <span style='color:Blue;'>".showArch($ArchName)."</span><br/>Total: $Total</h1><br/>";
18625 foreach my $HeaderName (sort {lc($a) cmp lc($b)} keys(%SymbolHeaderLib))
18626 {
18627 foreach my $DyLib (sort {lc($a) cmp lc($b)} keys(%{$SymbolHeaderLib{$HeaderName}}))
18628 {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040018629 my %NS_Symbol = ();
18630 foreach my $Symbol (keys(%{$SymbolHeaderLib{$HeaderName}{$DyLib}})) {
18631 $NS_Symbol{get_IntNameSpace($Symbol, 1)}{$Symbol} = 1;
18632 }
18633 foreach my $NameSpace (sort keys(%NS_Symbol))
18634 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040018635 $SYMBOLS_LIST .= getTitle($HeaderName, $DyLib, $NameSpace);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040018636 my @SortedInterfaces = sort {lc(get_Signature($a, 1)) cmp lc(get_Signature($b, 1))} keys(%{$NS_Symbol{$NameSpace}});
18637 foreach my $Symbol (@SortedInterfaces)
18638 {
18639 my $SubReport = "";
18640 my $Signature = get_Signature($Symbol, 1);
18641 if($NameSpace) {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040018642 $Signature=~s/\b\Q$NameSpace\E::\b//g;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040018643 }
18644 if($Symbol=~/\A(_Z|\?)/)
18645 {
18646 if($Signature) {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040018647 $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 +040018648 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040018649 else {
18650 $SubReport = "<span class='iname'>".$Symbol."</span><br/>\n";
18651 }
18652 }
18653 else
18654 {
18655 if($Signature) {
18656 $SubReport = "<span class='iname'>".highLight_Signature_Italic_Color($Signature)."</span><br/>\n";
18657 }
18658 else {
18659 $SubReport = "<span class='iname'>".$Symbol."</span><br/>\n";
18660 }
18661 }
18662 $SYMBOLS_LIST .= $SubReport;
18663 }
18664 }
18665 $SYMBOLS_LIST .= "<br/>\n";
18666 }
18667 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040018668 # clear info
18669 (%TypeInfo, %SymbolInfo, %Library_Symbol, %DepSymbol_Library,
18670 %DepLibrary_Symbol, %SymVer, %SkipTypes, %SkipSymbols,
18671 %NestedNameSpaces, %ClassMethods, %AllocableClass, %ClassNames,
18672 %CompleteSignature, %SkipNameSpaces, %Symbol_Library, %Library_Symbol) = ();
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040018673 ($Content_Counter, $ContentID) = (0, 0);
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040018674 # print report
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040018675 my $CssStyles = readModule("Styles", "SymbolsList.css");
18676 my $JScripts = readModule("Scripts", "Sections.js");
18677 $SYMBOLS_LIST = "<a name='Top'></a>".$SYMBOLS_LIST.$TOP_REF."<br/>\n";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040018678 my $Title = "$LName: public symbols";
18679 my $Keywords = "$LName, API, symbols";
18680 my $Description = "List of symbols in $LName ($LVersion) on ".showArch($ArchName);
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040018681 $SYMBOLS_LIST = composeHTML_Head($Title, $Keywords, $Description, $CssStyles, $JScripts)."
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040018682 <body><div>\n$SYMBOLS_LIST</div>
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040018683 <br/><br/><hr/>\n".getReportFooter($LName, 1)."
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040018684 <div style='height:999px;'></div></body></html>";
18685 writeFile($SaveTo, $SYMBOLS_LIST);
18686}
18687
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040018688sub readModule($$)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040018689{
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040018690 my ($Module, $Name) = @_;
18691 my $Path = $MODULES_DIR."/Internals/$Module/".$Name;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040018692 if(not -f $Path) {
18693 exitStatus("Module_Error", "can't access \'$Path\'");
18694 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040018695 return readFile($Path);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040018696}
18697
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040018698sub add_target_libs($)
18699{
18700 foreach (@{$_[0]}) {
18701 $TargetLibs{$_} = 1;
18702 }
18703}
18704
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040018705sub is_target_lib($)
18706{
18707 my $LName = $_[0];
Andrey Ponomarenkoa01311b2012-06-08 17:20:02 +040018708 if(not $LName) {
18709 return 0;
18710 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040018711 if($TargetLibraryName
18712 and $LName!~/\Q$TargetLibraryName\E/) {
18713 return 0;
18714 }
18715 if(keys(%TargetLibs)
18716 and not $TargetLibs{$LName}
18717 and not $TargetLibs{parse_libname($LName, "name+ext", $OStarget)}) {
18718 return 0;
18719 }
18720 return 1;
18721}
18722
Andrey Ponomarenko85043792012-05-14 16:48:07 +040018723sub is_target_header($$)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040018724{ # --header, --headers-list
Andrey Ponomarenko85043792012-05-14 16:48:07 +040018725 my ($H, $V) = @_;
18726 if(keys(%{$TargetHeaders{$V}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040018727 {
Andrey Ponomarenko85043792012-05-14 16:48:07 +040018728 if($TargetHeaders{$V}{$H}) {
18729 return 1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040018730 }
18731 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +040018732 return 0;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040018733}
18734
18735sub checkVersionNum($$)
18736{
18737 my ($LibVersion, $Path) = @_;
18738 if(my $VerNum = $TargetVersion{$LibVersion}) {
18739 return $VerNum;
18740 }
18741 my $UsedAltDescr = 0;
18742 foreach my $Part (split(/\s*,\s*/, $Path))
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040018743 { # try to get version string from file path
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040018744 next if(isDump($Part)); # ABI dump
18745 next if($Part=~/\.(xml|desc)\Z/i); # XML descriptor
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040018746 my $VerNum = "";
18747 if(parse_libname($Part, "name", $OStarget))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040018748 {
18749 $UsedAltDescr = 1;
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040018750 $VerNum = parse_libname($Part, "version", $OStarget);
18751 if(not $VerNum) {
Andrey Ponomarenko07aea072012-11-12 16:15:07 +040018752 $VerNum = readStrVer($Part);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040018753 }
18754 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040018755 elsif(is_header($Part, 2, $LibVersion) or -d $Part)
18756 {
18757 $UsedAltDescr = 1;
Andrey Ponomarenko07aea072012-11-12 16:15:07 +040018758 $VerNum = readStrVer($Part);
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040018759 }
18760 if($VerNum ne "")
18761 {
18762 $TargetVersion{$LibVersion} = $VerNum;
18763 if($DumpAPI) {
18764 printMsg("WARNING", "setting version number to $VerNum (use -vnum <num> option to change it)");
18765 }
18766 else {
18767 printMsg("WARNING", "setting ".($LibVersion==1?"1st":"2nd")." version number to \"$VerNum\" (use -v$LibVersion <num> option to change it)");
18768 }
18769 return $TargetVersion{$LibVersion};
18770 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040018771 }
18772 if($UsedAltDescr)
18773 {
18774 if($DumpAPI) {
18775 exitStatus("Error", "version number is not set (use -vnum <num> option)");
18776 }
18777 else {
18778 exitStatus("Error", ($LibVersion==1?"1st":"2nd")." version number is not set (use -v$LibVersion <num> option)");
18779 }
18780 }
18781}
18782
Andrey Ponomarenko07aea072012-11-12 16:15:07 +040018783sub readStrVer($)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040018784{
18785 my $Str = $_[0];
18786 return "" if(not $Str);
18787 $Str=~s/\Q$TargetLibraryName\E//g;
18788 if($Str=~/(\/|\\|\w|\A)[\-\_]*(\d+[\d\.\-]+\d+|\d+)/)
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040018789 { # .../libssh-0.4.0/...
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040018790 return $2;
18791 }
18792 elsif(my $V = parse_libname($Str, "version", $OStarget)) {
18793 return $V;
18794 }
18795 return "";
18796}
18797
18798sub readLibs($)
18799{
18800 my $LibVersion = $_[0];
18801 if($OStarget eq "windows")
18802 { # dumpbin.exe will crash
18803 # without VS Environment
18804 check_win32_env();
18805 }
Andrey Ponomarenko16934472012-03-29 15:37:04 +040018806 readSymbols($LibVersion);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040018807 translateSymbols(keys(%{$Symbol_Library{$LibVersion}}), $LibVersion);
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040018808 translateSymbols(keys(%{$DepSymbol_Library{$LibVersion}}), $LibVersion);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040018809}
18810
18811sub dump_sorting($)
18812{
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +040018813 my $Hash = $_[0];
18814 return [] if(not $Hash);
18815 my @Keys = keys(%{$Hash});
18816 return [] if($#Keys<0);
18817 if($Keys[0]=~/\A\d+\Z/)
18818 { # numbers
18819 return [sort {int($a)<=>int($b)} @Keys];
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040018820 }
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +040018821 else
18822 { # strings
18823 return [sort {$a cmp $b} @Keys];
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040018824 }
18825}
18826
18827sub printMsg($$)
18828{
18829 my ($Type, $Msg) = @_;
18830 if($Type!~/\AINFO/) {
18831 $Msg = $Type.": ".$Msg;
18832 }
18833 if($Type!~/_C\Z/) {
18834 $Msg .= "\n";
18835 }
18836 if($Quiet)
18837 { # --quiet option
18838 appendFile($COMMON_LOG_PATH, $Msg);
18839 }
18840 else
18841 {
18842 if($Type eq "ERROR") {
18843 print STDERR $Msg;
18844 }
18845 else {
18846 print $Msg;
18847 }
18848 }
18849}
18850
18851sub exitStatus($$)
18852{
18853 my ($Code, $Msg) = @_;
18854 printMsg("ERROR", $Msg);
18855 exit($ERROR_CODE{$Code});
18856}
18857
18858sub exitReport()
18859{ # the tool has run without any errors
18860 printReport();
18861 if($COMPILE_ERRORS)
18862 { # errors in headers may add false positives/negatives
18863 exit($ERROR_CODE{"Compile_Error"});
18864 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040018865 if($BinaryOnly and $RESULT{"Binary"}{"Problems"})
18866 { # --binary
18867 exit($ERROR_CODE{"Incompatible"});
18868 }
18869 elsif($SourceOnly and $RESULT{"Source"}{"Problems"})
18870 { # --source
18871 exit($ERROR_CODE{"Incompatible"});
18872 }
18873 elsif($RESULT{"Source"}{"Problems"}
18874 or $RESULT{"Binary"}{"Problems"})
18875 { # default
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040018876 exit($ERROR_CODE{"Incompatible"});
18877 }
18878 else {
18879 exit($ERROR_CODE{"Compatible"});
18880 }
18881}
18882
18883sub readRules($)
18884{
18885 my $Kind = $_[0];
18886 if(not -f $RULES_PATH{$Kind}) {
18887 exitStatus("Module_Error", "can't access \'".$RULES_PATH{$Kind}."\'");
18888 }
18889 my $Content = readFile($RULES_PATH{$Kind});
18890 while(my $Rule = parseTag(\$Content, "rule"))
18891 {
18892 my $RId = parseTag(\$Rule, "id");
18893 my @Properties = ("Severity", "Change", "Effect", "Overcome", "Kind");
18894 foreach my $Prop (@Properties) {
18895 if(my $Value = parseTag(\$Rule, lc($Prop)))
18896 {
18897 $Value=~s/\n[ ]*//;
18898 $CompatRules{$Kind}{$RId}{$Prop} = $Value;
18899 }
18900 }
18901 if($CompatRules{$Kind}{$RId}{"Kind"}=~/\A(Symbols|Parameters)\Z/) {
18902 $CompatRules{$Kind}{$RId}{"Kind"} = "Symbols";
18903 }
18904 else {
18905 $CompatRules{$Kind}{$RId}{"Kind"} = "Types";
18906 }
18907 }
18908}
18909
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040018910sub getReportPath($)
18911{
18912 my $Level = $_[0];
18913 my $Dir = "compat_reports/$TargetLibraryName/".$Descriptor{1}{"Version"}."_to_".$Descriptor{2}{"Version"};
18914 if($Level eq "Binary")
18915 {
18916 if($BinaryReportPath)
18917 { # --bin-report-path
18918 return $BinaryReportPath;
18919 }
18920 elsif($OutputReportPath)
18921 { # --report-path
18922 return $OutputReportPath;
18923 }
18924 else
18925 { # default
18926 return $Dir."/abi_compat_report.$ReportFormat";
18927 }
18928 }
18929 elsif($Level eq "Source")
18930 {
18931 if($SourceReportPath)
18932 { # --src-report-path
18933 return $SourceReportPath;
18934 }
18935 elsif($OutputReportPath)
18936 { # --report-path
18937 return $OutputReportPath;
18938 }
18939 else
18940 { # default
18941 return $Dir."/src_compat_report.$ReportFormat";
18942 }
18943 }
18944 else
18945 {
18946 if($OutputReportPath)
18947 { # --report-path
18948 return $OutputReportPath;
18949 }
18950 else
18951 { # default
18952 return $Dir."/compat_report.$ReportFormat";
18953 }
18954 }
18955}
18956
18957sub printStatMsg($)
18958{
18959 my $Level = $_[0];
18960 printMsg("INFO", "total \"$Level\" compatibility problems: ".$RESULT{$Level}{"Problems"}.", warnings: ".$RESULT{$Level}{"Warnings"});
18961}
18962
18963sub listAffected($)
18964{
18965 my $Level = $_[0];
18966 my $List = "";
18967 foreach (keys(%{$TotalAffected{$Level}}))
18968 {
18969 if($StrictCompat and $TotalAffected{$Level}{$_} eq "Low")
18970 { # skip "Low"-severity problems
18971 next;
18972 }
18973 $List .= "$_\n";
18974 }
18975 my $Dir = get_dirname(getReportPath($Level));
18976 if($Level eq "Binary") {
18977 writeFile($Dir."/abi_affected.txt", $List);
18978 }
18979 elsif($Level eq "Source") {
18980 writeFile($Dir."/src_affected.txt", $List);
18981 }
18982}
18983
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040018984sub printReport()
18985{
18986 printMsg("INFO", "creating compatibility report ...");
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040018987 createReport();
18988 if($JoinReport or $DoubleReport)
18989 {
18990 if($RESULT{"Binary"}{"Problems"}
18991 or $RESULT{"Source"}{"Problems"}) {
18992 printMsg("INFO", "result: INCOMPATIBLE (Binary: ".$RESULT{"Binary"}{"Affected"}."\%, Source: ".$RESULT{"Source"}{"Affected"}."\%)");
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040018993 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040018994 else {
18995 printMsg("INFO", "result: COMPATIBLE");
18996 }
18997 printStatMsg("Binary");
18998 printStatMsg("Source");
18999 if($ListAffected)
19000 { # --list-affected
19001 listAffected("Binary");
19002 listAffected("Source");
19003 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040019004 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040019005 elsif($BinaryOnly)
19006 {
19007 if($RESULT{"Binary"}{"Problems"}) {
19008 printMsg("INFO", "result: INCOMPATIBLE (".$RESULT{"Binary"}{"Affected"}."\%)");
19009 }
19010 else {
19011 printMsg("INFO", "result: COMPATIBLE");
19012 }
19013 printStatMsg("Binary");
19014 if($ListAffected)
19015 { # --list-affected
19016 listAffected("Binary");
19017 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040019018 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040019019 elsif($SourceOnly)
19020 {
19021 if($RESULT{"Source"}{"Problems"}) {
19022 printMsg("INFO", "result: INCOMPATIBLE (".$RESULT{"Source"}{"Affected"}."\%)");
19023 }
19024 else {
19025 printMsg("INFO", "result: COMPATIBLE");
19026 }
19027 printStatMsg("Source");
19028 if($ListAffected)
19029 { # --list-affected
19030 listAffected("Source");
19031 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040019032 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040019033 if($StdOut)
19034 {
19035 if($JoinReport or not $DoubleReport)
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040019036 { # --binary or --source
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040019037 printMsg("INFO", "compatibility report has been generated to stdout");
19038 }
19039 else
19040 { # default
19041 printMsg("INFO", "compatibility reports have been generated to stdout");
19042 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040019043 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040019044 else
19045 {
19046 if($JoinReport)
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040019047 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040019048 printMsg("INFO", "see detailed report:\n ".getReportPath("Join"));
19049 }
19050 elsif($DoubleReport)
19051 { # default
19052 printMsg("INFO", "see detailed reports:\n ".getReportPath("Binary")."\n ".getReportPath("Source"));
19053 }
19054 elsif($BinaryOnly)
19055 { # --binary
19056 printMsg("INFO", "see detailed report:\n ".getReportPath("Binary"));
19057 }
19058 elsif($SourceOnly)
19059 { # --source
19060 printMsg("INFO", "see detailed report:\n ".getReportPath("Source"));
19061 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040019062 }
19063}
19064
19065sub check_win32_env()
19066{
19067 if(not $ENV{"DevEnvDir"}
19068 or not $ENV{"LIB"}) {
19069 exitStatus("Error", "can't start without VS environment (vsvars32.bat)");
19070 }
19071}
19072
Andrey Ponomarenko5c09ef32012-06-14 18:17:33 +040019073sub diffSets($$)
19074{
19075 my ($S1, $S2) = @_;
19076 my @SK1 = keys(%{$S1});
19077 my @SK2 = keys(%{$S2});
19078 if($#SK1!=$#SK2) {
19079 return 1;
19080 }
19081 foreach my $K1 (@SK1)
19082 {
19083 if(not defined $S2->{$K1}) {
19084 return 1;
19085 }
19086 }
19087 return 0;
19088}
19089
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040019090sub create_ABI_Dump()
19091{
19092 if(not -e $DumpAPI) {
19093 exitStatus("Access_Error", "can't access \'$DumpAPI\'");
19094 }
19095 # check the archive utilities
19096 if($OSgroup eq "windows")
19097 { # using zip
19098 my $ZipCmd = get_CmdPath("zip");
19099 if(not $ZipCmd) {
19100 exitStatus("Not_Found", "can't find \"zip\"");
19101 }
19102 }
19103 else
19104 { # using tar and gzip
19105 my $TarCmd = get_CmdPath("tar");
19106 if(not $TarCmd) {
19107 exitStatus("Not_Found", "can't find \"tar\"");
19108 }
19109 my $GzipCmd = get_CmdPath("gzip");
19110 if(not $GzipCmd) {
19111 exitStatus("Not_Found", "can't find \"gzip\"");
19112 }
19113 }
19114 my @DParts = split(/\s*,\s*/, $DumpAPI);
19115 foreach my $Part (@DParts)
19116 {
19117 if(not -e $Part) {
19118 exitStatus("Access_Error", "can't access \'$Part\'");
19119 }
19120 }
19121 checkVersionNum(1, $DumpAPI);
19122 foreach my $Part (@DParts)
19123 {
19124 if(isDump($Part)) {
19125 read_ABI_Dump(1, $Part);
19126 }
19127 else {
19128 readDescriptor(1, createDescriptor(1, $Part));
19129 }
19130 }
19131 initLogging(1);
19132 detect_default_paths("inc|lib|bin|gcc"); # complete analysis
Andrey Ponomarenko01117f12012-06-26 12:23:02 +040019133 if(not $Descriptor{1}{"Dump"})
19134 {
19135 if(not $CheckHeadersOnly) {
19136 readLibs(1);
19137 }
19138 if($CheckHeadersOnly) {
19139 setLanguage(1, "C++");
19140 }
19141 if(not $CheckObjectsOnly) {
19142 searchForHeaders(1);
19143 }
19144 $WORD_SIZE{1} = detectWordSize();
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040019145 }
Andrey Ponomarenko01117f12012-06-26 12:23:02 +040019146 if(not $Descriptor{1}{"Dump"})
19147 {
19148 if($Descriptor{1}{"Headers"}) {
19149 readHeaders(1);
19150 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040019151 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +040019152 cleanDump(1);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040019153 if(not keys(%{$SymbolInfo{1}}))
19154 { # check if created dump is valid
19155 if(not $ExtendedCheck and not $CheckObjectsOnly)
19156 {
19157 if($CheckHeadersOnly) {
19158 exitStatus("Empty_Set", "the set of public symbols is empty");
19159 }
19160 else {
19161 exitStatus("Empty_Intersection", "the sets of public symbols in headers and libraries have empty intersection");
19162 }
19163 }
19164 }
19165 my %HeadersInfo = ();
19166 foreach my $HPath (keys(%{$Registered_Headers{1}}))
19167 { # headers info stored without paths in the dump
19168 $HeadersInfo{$Registered_Headers{1}{$HPath}{"Identity"}} = $Registered_Headers{1}{$HPath}{"Pos"};
19169 }
19170 printMsg("INFO", "creating library ABI dump ...");
Andrey Ponomarenko01117f12012-06-26 12:23:02 +040019171 my %ABI = (
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040019172 "TypeInfo" => $TypeInfo{1},
19173 "SymbolInfo" => $SymbolInfo{1},
19174 "Symbols" => $Library_Symbol{1},
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040019175 "DepSymbols" => $DepLibrary_Symbol{1},
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040019176 "SymbolVersion" => $SymVer{1},
19177 "LibraryVersion" => $Descriptor{1}{"Version"},
19178 "LibraryName" => $TargetLibraryName,
19179 "Language" => $COMMON_LANGUAGE{1},
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040019180 "SkipTypes" => $SkipTypes{1},
19181 "SkipSymbols" => $SkipSymbols{1},
19182 "SkipNameSpaces" => $SkipNameSpaces{1},
19183 "SkipHeaders" => $SkipHeadersList{1},
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040019184 "Headers" => \%HeadersInfo,
19185 "Constants" => $Constants{1},
19186 "NameSpaces" => $NestedNameSpaces{1},
19187 "Target" => $OStarget,
19188 "Arch" => getArch(1),
19189 "WordSize" => $WORD_SIZE{1},
19190 "GccVersion" => get_dumpversion($GCC_PATH),
19191 "ABI_DUMP_VERSION" => $ABI_DUMP_VERSION,
19192 "ABI_COMPLIANCE_CHECKER_VERSION" => $TOOL_VERSION
19193 );
Andrey Ponomarenko5c09ef32012-06-14 18:17:33 +040019194 if(diffSets($TargetHeaders{1}, \%HeadersInfo)) {
Andrey Ponomarenko01117f12012-06-26 12:23:02 +040019195 $ABI{"TargetHeaders"} = $TargetHeaders{1};
Andrey Ponomarenko5c09ef32012-06-14 18:17:33 +040019196 }
19197 if($UseXML) {
Andrey Ponomarenko01117f12012-06-26 12:23:02 +040019198 $ABI{"XML_ABI_DUMP_VERSION"} = $XML_ABI_DUMP_VERSION;
Andrey Ponomarenko5c09ef32012-06-14 18:17:33 +040019199 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040019200 if($ExtendedCheck)
19201 { # --ext option
Andrey Ponomarenko01117f12012-06-26 12:23:02 +040019202 $ABI{"Mode"} = "Extended";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040019203 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040019204 if($BinaryOnly)
19205 { # --binary
Andrey Ponomarenko01117f12012-06-26 12:23:02 +040019206 $ABI{"BinOnly"} = 1;
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040019207 }
Andrey Ponomarenko5c09ef32012-06-14 18:17:33 +040019208
19209 my $ABI_DUMP = "";
19210 if($UseXML)
19211 {
19212 loadModule("XmlDump");
Andrey Ponomarenko01117f12012-06-26 12:23:02 +040019213 $ABI_DUMP = createXmlDump(\%ABI);
Andrey Ponomarenko5c09ef32012-06-14 18:17:33 +040019214 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040019215 else
19216 { # default
Andrey Ponomarenko01117f12012-06-26 12:23:02 +040019217 $ABI_DUMP = Dumper(\%ABI);
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040019218 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040019219 if($StdOut)
19220 { # --stdout option
Andrey Ponomarenko5c09ef32012-06-14 18:17:33 +040019221 print STDOUT $ABI_DUMP;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040019222 printMsg("INFO", "ABI dump has been generated to stdout");
19223 return;
19224 }
19225 else
19226 { # write to gzipped file
Andrey Ponomarenko5c09ef32012-06-14 18:17:33 +040019227 my $DumpPath = "abi_dumps/$TargetLibraryName/".$TargetLibraryName."_".$Descriptor{1}{"Version"}.".abi";
19228 $DumpPath .= ".".$AR_EXT; # gzipped by default
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040019229 if($OutputDumpPath)
19230 { # user defined path
19231 $DumpPath = $OutputDumpPath;
19232 }
Andrey Ponomarenko5c09ef32012-06-14 18:17:33 +040019233 my $Archive = ($DumpPath=~s/\Q.$AR_EXT\E\Z//g);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040019234 my ($DDir, $DName) = separate_path($DumpPath);
19235 my $DPath = $TMP_DIR."/".$DName;
Andrey Ponomarenko5c09ef32012-06-14 18:17:33 +040019236 if(not $Archive) {
19237 $DPath = $DumpPath;
19238 }
19239
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040019240 mkpath($DDir);
Andrey Ponomarenko85043792012-05-14 16:48:07 +040019241
19242 open(DUMP, ">", $DPath) || die ("can't open file \'$DPath\': $!\n");
Andrey Ponomarenko5c09ef32012-06-14 18:17:33 +040019243 print DUMP $ABI_DUMP;
Andrey Ponomarenko85043792012-05-14 16:48:07 +040019244 close(DUMP);
19245
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040019246 if(not -s $DPath) {
19247 exitStatus("Error", "can't create ABI dump because something is going wrong with the Data::Dumper module");
19248 }
Andrey Ponomarenko07aea072012-11-12 16:15:07 +040019249 if($Archive) {
19250 $DumpPath = createArchive($DPath, $DDir);
Andrey Ponomarenko5c09ef32012-06-14 18:17:33 +040019251 }
19252
Andrey Ponomarenko07aea072012-11-12 16:15:07 +040019253 if(not $OutputDumpPath)
19254 {
19255 printMsg("INFO", "library ABI has been dumped to:\n $DumpPath");
19256 printMsg("INFO", "you can transfer this dump everywhere and use instead of the ".$Descriptor{1}{"Version"}." version descriptor");
19257 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040019258 }
19259}
19260
19261sub quickEmptyReports()
19262{ # Quick "empty" reports
19263 # 4 times faster than merging equal dumps
19264 # NOTE: the dump contains the "LibraryVersion" attribute
19265 # if you change the version, then your dump will be different
19266 # OVERCOME: use -v1 and v2 options for comparing dumps
19267 # and don't change version in the XML descriptor (and dumps)
19268 # OVERCOME 2: separate meta info from the dumps in ACC 2.0
19269 if(-s $Descriptor{1}{"Path"} == -s $Descriptor{2}{"Path"})
19270 {
19271 my $FilePath1 = unpackDump($Descriptor{1}{"Path"});
19272 my $FilePath2 = unpackDump($Descriptor{2}{"Path"});
19273 if($FilePath1 and $FilePath2)
19274 {
Andrey Ponomarenko01117f12012-06-26 12:23:02 +040019275 my $Line = readLineNum($FilePath1, 0);
19276 if($Line=~/xml/)
19277 { # XML format
19278 # is not supported yet
19279 return;
19280 }
19281
Andrey Ponomarenko85043792012-05-14 16:48:07 +040019282 local $/ = undef;
19283
19284 open(DUMP1, $FilePath1);
19285 my $Content1 = <DUMP1>;
19286 close(DUMP1);
19287
19288 open(DUMP2, $FilePath2);
19289 my $Content2 = <DUMP2>;
19290 close(DUMP2);
19291
19292 if($Content1 eq $Content2)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040019293 {
Andrey Ponomarenko85043792012-05-14 16:48:07 +040019294 # clean memory
19295 undef $Content2;
19296
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040019297 # read a number of headers, libs, symbols and types
Andrey Ponomarenko85043792012-05-14 16:48:07 +040019298 my $ABIdump = eval($Content1);
19299
19300 # clean memory
19301 undef $Content1;
19302
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040019303 if(not $ABIdump) {
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040019304 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 +040019305 }
19306 if(not $ABIdump->{"TypeInfo"})
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040019307 { # support for old dumps
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040019308 $ABIdump->{"TypeInfo"} = $ABIdump->{"TypeDescr"};
19309 }
19310 if(not $ABIdump->{"SymbolInfo"})
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040019311 { # support for old dumps
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040019312 $ABIdump->{"SymbolInfo"} = $ABIdump->{"FuncDescr"};
19313 }
19314 read_Headers_DumpInfo($ABIdump, 1);
19315 read_Libs_DumpInfo($ABIdump, 1);
19316 read_Machine_DumpInfo($ABIdump, 1);
19317 read_Machine_DumpInfo($ABIdump, 2);
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040019318
19319 %{$CheckedTypes{"Binary"}} = %{$ABIdump->{"TypeInfo"}};
19320 %{$CheckedTypes{"Source"}} = %{$ABIdump->{"TypeInfo"}};
19321
19322 %{$CheckedSymbols{"Binary"}} = %{$ABIdump->{"SymbolInfo"}};
19323 %{$CheckedSymbols{"Source"}} = %{$ABIdump->{"SymbolInfo"}};
19324
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040019325 $Descriptor{1}{"Version"} = $TargetVersion{1}?$TargetVersion{1}:$ABIdump->{"LibraryVersion"};
19326 $Descriptor{2}{"Version"} = $TargetVersion{2}?$TargetVersion{2}:$ABIdump->{"LibraryVersion"};
19327 exitReport();
19328 }
19329 }
19330 }
19331}
19332
19333sub initLogging($)
19334{
19335 my $LibVersion = $_[0];
19336 # create log directory
19337 my ($LOG_DIR, $LOG_FILE) = ("logs/$TargetLibraryName/".$Descriptor{$LibVersion}{"Version"}, "log.txt");
19338 if($OutputLogPath{$LibVersion})
19339 { # user-defined by -log-path option
19340 ($LOG_DIR, $LOG_FILE) = separate_path($OutputLogPath{$LibVersion});
19341 }
19342 if($LogMode ne "n") {
19343 mkpath($LOG_DIR);
19344 }
19345 $LOG_PATH{$LibVersion} = get_abs_path($LOG_DIR)."/".$LOG_FILE;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040019346 if($Debug)
19347 { # debug directory
19348 $DEBUG_PATH{$LibVersion} = "debug/$TargetLibraryName/".$Descriptor{$LibVersion}{"Version"};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040019349 }
Andrey Ponomarenko35c44fd2012-06-18 17:50:25 +040019350 resetLogging($LibVersion);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040019351}
19352
19353sub writeLog($$)
19354{
19355 my ($LibVersion, $Msg) = @_;
19356 if($LogMode ne "n") {
19357 appendFile($LOG_PATH{$LibVersion}, $Msg);
19358 }
19359}
19360
19361sub resetLogging($)
19362{
19363 my $LibVersion = $_[0];
19364 if($LogMode!~/a|n/)
19365 { # remove old log
19366 unlink($LOG_PATH{$LibVersion});
Andrey Ponomarenko35c44fd2012-06-18 17:50:25 +040019367 if($Debug) {
19368 rmtree($DEBUG_PATH{$LibVersion});
19369 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040019370 }
19371}
19372
19373sub printErrorLog($)
19374{
19375 my $LibVersion = $_[0];
19376 if($LogMode ne "n") {
19377 printMsg("ERROR", "see log for details:\n ".$LOG_PATH{$LibVersion}."\n");
19378 }
19379}
19380
19381sub isDump($)
19382{
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040019383 if(get_filename($_[0])=~/\A(.+)\.(abi|abidump)(\.tar\.gz|\.zip|\.xml|)\Z/) {
19384 return $1;
19385 }
19386 return 0;
19387}
19388
19389sub isDump_U($)
19390{
19391 if(get_filename($_[0])=~/\A(.+)\.(abi|abidump)(\.xml|)\Z/) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040019392 return $1;
19393 }
19394 return 0;
19395}
19396
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040019397sub compareInit()
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040019398{
19399 # read input XML descriptors or ABI dumps
19400 if(not $Descriptor{1}{"Path"}) {
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040019401 exitStatus("Error", "-old option is not specified");
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040019402 }
19403 my @DParts1 = split(/\s*,\s*/, $Descriptor{1}{"Path"});
19404 foreach my $Part (@DParts1)
19405 {
19406 if(not -e $Part) {
19407 exitStatus("Access_Error", "can't access \'$Part\'");
19408 }
19409 }
19410 if(not $Descriptor{2}{"Path"}) {
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040019411 exitStatus("Error", "-new option is not specified");
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040019412 }
19413 my @DParts2 = split(/\s*,\s*/, $Descriptor{2}{"Path"});
19414 foreach my $Part (@DParts2)
19415 {
19416 if(not -e $Part) {
19417 exitStatus("Access_Error", "can't access \'$Part\'");
19418 }
19419 }
19420 detect_default_paths("bin"); # to extract dumps
19421 if($#DParts1==0 and $#DParts2==0
19422 and isDump($Descriptor{1}{"Path"})
19423 and isDump($Descriptor{2}{"Path"}))
19424 { # optimization: equal ABI dumps
19425 quickEmptyReports();
19426 }
19427 checkVersionNum(1, $Descriptor{1}{"Path"});
19428 checkVersionNum(2, $Descriptor{2}{"Path"});
19429 printMsg("INFO", "preparation, please wait ...");
19430 foreach my $Part (@DParts1)
19431 {
19432 if(isDump($Part)) {
19433 read_ABI_Dump(1, $Part);
19434 }
19435 else {
19436 readDescriptor(1, createDescriptor(1, $Part));
19437 }
19438 }
19439 foreach my $Part (@DParts2)
19440 {
19441 if(isDump($Part)) {
19442 read_ABI_Dump(2, $Part);
19443 }
19444 else {
19445 readDescriptor(2, createDescriptor(2, $Part));
19446 }
19447 }
19448 initLogging(1);
19449 initLogging(2);
19450 # check consistency
19451 if(not $Descriptor{1}{"Headers"}
19452 and not $Descriptor{1}{"Libs"}) {
19453 exitStatus("Error", "descriptor d1 does not contain both header files and libraries info");
19454 }
19455 if(not $Descriptor{2}{"Headers"}
19456 and not $Descriptor{2}{"Libs"}) {
19457 exitStatus("Error", "descriptor d2 does not contain both header files and libraries info");
19458 }
19459 if($Descriptor{1}{"Headers"} and not $Descriptor{1}{"Libs"}
19460 and not $Descriptor{2}{"Headers"} and $Descriptor{2}{"Libs"}) {
19461 exitStatus("Error", "can't compare headers with $SLIB_TYPE libraries");
19462 }
19463 elsif(not $Descriptor{1}{"Headers"} and $Descriptor{1}{"Libs"}
19464 and $Descriptor{2}{"Headers"} and not $Descriptor{2}{"Libs"}) {
19465 exitStatus("Error", "can't compare $SLIB_TYPE libraries with headers");
19466 }
Andrey Ponomarenkobdc85a92012-11-12 17:28:12 +040019467 if(not $Descriptor{1}{"Headers"})
19468 {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040019469 if($CheckHeadersOnly_Opt) {
19470 exitStatus("Error", "can't find header files info in descriptor d1");
19471 }
19472 }
Andrey Ponomarenkobdc85a92012-11-12 17:28:12 +040019473 if(not $Descriptor{2}{"Headers"})
19474 {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040019475 if($CheckHeadersOnly_Opt) {
19476 exitStatus("Error", "can't find header files info in descriptor d2");
19477 }
19478 }
19479 if(not $Descriptor{1}{"Headers"}
Andrey Ponomarenkobdc85a92012-11-12 17:28:12 +040019480 or not $Descriptor{2}{"Headers"})
19481 {
19482 if(not $CheckObjectsOnly_Opt)
19483 {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040019484 printMsg("WARNING", "comparing $SLIB_TYPE libraries only");
19485 $CheckObjectsOnly = 1;
19486 }
19487 }
Andrey Ponomarenkobdc85a92012-11-12 17:28:12 +040019488 if(not $Descriptor{1}{"Libs"})
19489 {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040019490 if($CheckObjectsOnly_Opt) {
19491 exitStatus("Error", "can't find $SLIB_TYPE libraries info in descriptor d1");
19492 }
19493 }
Andrey Ponomarenkobdc85a92012-11-12 17:28:12 +040019494 if(not $Descriptor{2}{"Libs"})
19495 {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040019496 if($CheckObjectsOnly_Opt) {
19497 exitStatus("Error", "can't find $SLIB_TYPE libraries info in descriptor d2");
19498 }
19499 }
19500 if(not $Descriptor{1}{"Libs"}
19501 or not $Descriptor{2}{"Libs"})
19502 { # comparing standalone header files
19503 # comparing ABI dumps created with --headers-only
19504 if(not $CheckHeadersOnly_Opt)
19505 {
19506 printMsg("WARNING", "checking headers only");
19507 $CheckHeadersOnly = 1;
19508 }
19509 }
19510 if($UseDumps)
19511 { # --use-dumps
19512 # parallel processing
19513 my $pid = fork();
19514 if($pid)
19515 { # dump on two CPU cores
19516 my @PARAMS = ("-dump", $Descriptor{1}{"Path"}, "-l", $TargetLibraryName);
19517 if($RelativeDirectory{1}) {
19518 @PARAMS = (@PARAMS, "-relpath", $RelativeDirectory{1});
19519 }
19520 if($OutputLogPath{1}) {
19521 @PARAMS = (@PARAMS, "-log-path", $OutputLogPath{1});
19522 }
19523 if($CrossGcc) {
19524 @PARAMS = (@PARAMS, "-cross-gcc", $CrossGcc);
19525 }
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040019526 if($Quiet)
19527 {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040019528 @PARAMS = (@PARAMS, "-quiet");
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040019529 @PARAMS = (@PARAMS, "-logging-mode", "a");
19530 }
19531 elsif($LogMode and $LogMode ne "w")
19532 { # "w" is default
19533 @PARAMS = (@PARAMS, "-logging-mode", $LogMode);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040019534 }
19535 if($ExtendedCheck) {
19536 @PARAMS = (@PARAMS, "-extended");
19537 }
19538 if($UserLang) {
19539 @PARAMS = (@PARAMS, "-lang", $UserLang);
19540 }
19541 if($TargetVersion{1}) {
19542 @PARAMS = (@PARAMS, "-vnum", $TargetVersion{1});
19543 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +040019544 if($BinaryOnly) {
19545 @PARAMS = (@PARAMS, "-binary");
19546 }
19547 if($SourceOnly) {
19548 @PARAMS = (@PARAMS, "-source");
19549 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040019550 if($SortDump) {
19551 @PARAMS = (@PARAMS, "-sort");
19552 }
Andrey Ponomarenko01117f12012-06-26 12:23:02 +040019553 if($DumpFormat and $DumpFormat ne "perl") {
19554 @PARAMS = (@PARAMS, "-dump-format", $DumpFormat);
19555 }
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +040019556 if($CheckHeadersOnly) {
19557 @PARAMS = (@PARAMS, "-headers-only");
19558 }
19559 if($CheckObjectsOnly) {
19560 @PARAMS = (@PARAMS, "-objects-only");
19561 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +040019562 if($Debug)
19563 {
19564 @PARAMS = (@PARAMS, "-debug");
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040019565 printMsg("INFO", "running perl $0 @PARAMS");
Andrey Ponomarenko85043792012-05-14 16:48:07 +040019566 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040019567 system("perl", $0, @PARAMS);
19568 if($?) {
19569 exit(1);
19570 }
19571 }
19572 else
19573 { # child
19574 my @PARAMS = ("-dump", $Descriptor{2}{"Path"}, "-l", $TargetLibraryName);
19575 if($RelativeDirectory{2}) {
19576 @PARAMS = (@PARAMS, "-relpath", $RelativeDirectory{2});
19577 }
19578 if($OutputLogPath{2}) {
19579 @PARAMS = (@PARAMS, "-log-path", $OutputLogPath{2});
19580 }
19581 if($CrossGcc) {
19582 @PARAMS = (@PARAMS, "-cross-gcc", $CrossGcc);
19583 }
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040019584 if($Quiet)
19585 {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040019586 @PARAMS = (@PARAMS, "-quiet");
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040019587 @PARAMS = (@PARAMS, "-logging-mode", "a");
19588 }
19589 elsif($LogMode and $LogMode ne "w")
19590 { # "w" is default
19591 @PARAMS = (@PARAMS, "-logging-mode", $LogMode);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040019592 }
19593 if($ExtendedCheck) {
19594 @PARAMS = (@PARAMS, "-extended");
19595 }
19596 if($UserLang) {
19597 @PARAMS = (@PARAMS, "-lang", $UserLang);
19598 }
19599 if($TargetVersion{2}) {
19600 @PARAMS = (@PARAMS, "-vnum", $TargetVersion{2});
19601 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +040019602 if($BinaryOnly) {
19603 @PARAMS = (@PARAMS, "-binary");
19604 }
19605 if($SourceOnly) {
19606 @PARAMS = (@PARAMS, "-source");
19607 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040019608 if($SortDump) {
19609 @PARAMS = (@PARAMS, "-sort");
19610 }
Andrey Ponomarenko01117f12012-06-26 12:23:02 +040019611 if($DumpFormat and $DumpFormat ne "perl") {
19612 @PARAMS = (@PARAMS, "-dump-format", $DumpFormat);
19613 }
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +040019614 if($CheckHeadersOnly) {
19615 @PARAMS = (@PARAMS, "-headers-only");
19616 }
19617 if($CheckObjectsOnly) {
19618 @PARAMS = (@PARAMS, "-objects-only");
19619 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +040019620 if($Debug)
19621 {
19622 @PARAMS = (@PARAMS, "-debug");
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040019623 printMsg("INFO", "running perl $0 @PARAMS");
Andrey Ponomarenko85043792012-05-14 16:48:07 +040019624 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040019625 system("perl", $0, @PARAMS);
19626 if($?) {
19627 exit(1);
19628 }
19629 else {
19630 exit(0);
19631 }
19632 }
19633 waitpid($pid, 0);
19634 my @CMP_PARAMS = ("-l", $TargetLibraryName);
19635 @CMP_PARAMS = (@CMP_PARAMS, "-d1", "abi_dumps/$TargetLibraryName/".$TargetLibraryName."_".$Descriptor{1}{"Version"}.".abi.$AR_EXT");
19636 @CMP_PARAMS = (@CMP_PARAMS, "-d2", "abi_dumps/$TargetLibraryName/".$TargetLibraryName."_".$Descriptor{2}{"Version"}.".abi.$AR_EXT");
19637 if($TargetLibraryFName ne $TargetLibraryName) {
19638 @CMP_PARAMS = (@CMP_PARAMS, "-l-full", $TargetLibraryFName);
19639 }
19640 if($ShowRetVal) {
19641 @CMP_PARAMS = (@CMP_PARAMS, "-show-retval");
19642 }
19643 if($CrossGcc) {
19644 @CMP_PARAMS = (@CMP_PARAMS, "-cross-gcc", $CrossGcc);
19645 }
Andrey Ponomarenko35c44fd2012-06-18 17:50:25 +040019646 @CMP_PARAMS = (@CMP_PARAMS, "-logging-mode", "a");
19647 if($Quiet) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040019648 @CMP_PARAMS = (@CMP_PARAMS, "-quiet");
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040019649 }
19650 if($ReportFormat and $ReportFormat ne "html")
19651 { # HTML is default format
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040019652 @CMP_PARAMS = (@CMP_PARAMS, "-report-format", $ReportFormat);
19653 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040019654 if($OutputReportPath) {
19655 @CMP_PARAMS = (@CMP_PARAMS, "-report-path", $OutputReportPath);
19656 }
19657 if($BinaryReportPath) {
19658 @CMP_PARAMS = (@CMP_PARAMS, "-bin-report-path", $BinaryReportPath);
19659 }
19660 if($SourceReportPath) {
19661 @CMP_PARAMS = (@CMP_PARAMS, "-src-report-path", $SourceReportPath);
19662 }
19663 if($LoggingPath) {
19664 @CMP_PARAMS = (@CMP_PARAMS, "-log-path", $LoggingPath);
19665 }
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +040019666 if($CheckHeadersOnly) {
19667 @CMP_PARAMS = (@CMP_PARAMS, "-headers-only");
19668 }
19669 if($CheckObjectsOnly) {
19670 @CMP_PARAMS = (@CMP_PARAMS, "-objects-only");
19671 }
19672 if($BinaryOnly) {
19673 @CMP_PARAMS = (@CMP_PARAMS, "-binary");
19674 }
19675 if($SourceOnly) {
19676 @CMP_PARAMS = (@CMP_PARAMS, "-source");
19677 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +040019678 if($Browse) {
19679 @CMP_PARAMS = (@CMP_PARAMS, "-browse", $Browse);
19680 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040019681 if($OpenReport) {
19682 @CMP_PARAMS = (@CMP_PARAMS, "-open");
19683 }
19684 if($Debug)
19685 {
19686 @CMP_PARAMS = (@CMP_PARAMS, "-debug");
19687 printMsg("INFO", "running perl $0 @CMP_PARAMS");
Andrey Ponomarenko85043792012-05-14 16:48:07 +040019688 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040019689 system("perl", $0, @CMP_PARAMS);
19690 exit($?>>8);
19691 }
19692 if(not $Descriptor{1}{"Dump"}
19693 or not $Descriptor{2}{"Dump"})
19694 { # need GCC toolchain to analyze
19695 # header files and libraries
19696 detect_default_paths("inc|lib|gcc");
19697 }
19698 if(not $Descriptor{1}{"Dump"})
19699 {
19700 if(not $CheckHeadersOnly) {
19701 readLibs(1);
19702 }
19703 if($CheckHeadersOnly) {
19704 setLanguage(1, "C++");
19705 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +040019706 if(not $CheckObjectsOnly) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040019707 searchForHeaders(1);
19708 }
19709 $WORD_SIZE{1} = detectWordSize();
19710 }
19711 if(not $Descriptor{2}{"Dump"})
19712 {
19713 if(not $CheckHeadersOnly) {
19714 readLibs(2);
19715 }
19716 if($CheckHeadersOnly) {
19717 setLanguage(2, "C++");
19718 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +040019719 if(not $CheckObjectsOnly) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040019720 searchForHeaders(2);
19721 }
19722 $WORD_SIZE{2} = detectWordSize();
19723 }
19724 if($WORD_SIZE{1} ne $WORD_SIZE{2})
19725 { # support for old ABI dumps
19726 # try to synch different WORD sizes
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040019727 if(not checkDump(1, "2.1"))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040019728 {
19729 $WORD_SIZE{1} = $WORD_SIZE{2};
19730 printMsg("WARNING", "set WORD size to ".$WORD_SIZE{2}." bytes");
19731 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040019732 elsif(not checkDump(2, "2.1"))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040019733 {
19734 $WORD_SIZE{2} = $WORD_SIZE{1};
19735 printMsg("WARNING", "set WORD size to ".$WORD_SIZE{1}." bytes");
19736 }
19737 }
19738 elsif(not $WORD_SIZE{1}
19739 and not $WORD_SIZE{2})
19740 { # support for old ABI dumps
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040019741 $WORD_SIZE{1} = "4";
19742 $WORD_SIZE{2} = "4";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040019743 }
19744 if($Descriptor{1}{"Dump"})
19745 { # support for old ABI dumps
19746 prepareTypes(1);
19747 }
19748 if($Descriptor{2}{"Dump"})
19749 { # support for old ABI dumps
19750 prepareTypes(2);
19751 }
19752 if($AppPath and not keys(%{$Symbol_Library{1}})) {
19753 printMsg("WARNING", "the application ".get_filename($AppPath)." has no symbols imported from the $SLIB_TYPE libraries");
19754 }
19755 # started to process input data
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040019756 if(not $CheckObjectsOnly)
19757 {
19758 if($Descriptor{1}{"Headers"}
19759 and not $Descriptor{1}{"Dump"}) {
19760 readHeaders(1);
19761 }
19762 if($Descriptor{2}{"Headers"}
19763 and not $Descriptor{2}{"Dump"}) {
19764 readHeaders(2);
19765 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040019766 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +040019767
19768 # clean memory
19769 %SystemHeaders = ();
19770 %mangled_name_gcc = ();
19771
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040019772 prepareSymbols(1);
19773 prepareSymbols(2);
Andrey Ponomarenko16934472012-03-29 15:37:04 +040019774
Andrey Ponomarenko85043792012-05-14 16:48:07 +040019775 # clean memory
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040019776 %SymbolInfo = ();
Andrey Ponomarenko16934472012-03-29 15:37:04 +040019777
19778 # Virtual Tables
19779 registerVTable(1);
19780 registerVTable(2);
19781
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040019782 if(not checkDump(1, "1.22")
19783 and checkDump(2, "1.22"))
Andrey Ponomarenko16934472012-03-29 15:37:04 +040019784 { # support for old ABI dumps
19785 foreach my $ClassName (keys(%{$VirtualTable{2}}))
19786 {
19787 if($ClassName=~/</)
19788 { # templates
19789 if(not defined $VirtualTable{1}{$ClassName})
19790 { # synchronize
19791 delete($VirtualTable{2}{$ClassName});
19792 }
19793 }
19794 }
19795 }
19796
19797 registerOverriding(1);
19798 registerOverriding(2);
19799
19800 setVirtFuncPositions(1);
19801 setVirtFuncPositions(2);
19802
19803 # Other
19804 addParamNames(1);
19805 addParamNames(2);
19806
19807 detectChangedTypedefs();
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040019808}
19809
19810sub compareAPIs($)
19811{
19812 my $Level = $_[0];
19813 readRules($Level);
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +040019814 loadModule("CallConv");
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040019815 if($Level eq "Binary") {
19816 printMsg("INFO", "comparing ABIs ...");
19817 }
19818 else {
19819 printMsg("INFO", "comparing APIs ...");
19820 }
19821 if($CheckHeadersOnly
19822 or $Level eq "Source")
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040019823 { # added/removed in headers
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040019824 detectAdded_H($Level);
19825 detectRemoved_H($Level);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040019826 }
19827 else
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040019828 { # added/removed in libs
19829 detectAdded($Level);
19830 detectRemoved($Level);
19831 }
19832 if(not $CheckObjectsOnly)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040019833 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040019834 mergeSignatures($Level);
19835 if(keys(%{$CheckedSymbols{$Level}})) {
19836 mergeConstants($Level);
19837 }
19838 }
19839 if($CheckHeadersOnly
19840 or $Level eq "Source")
19841 { # added/removed in headers
19842 mergeHeaders($Level);
19843 }
19844 else
19845 { # added/removed in libs
19846 mergeLibs($Level);
19847 if($CheckImpl
19848 and $Level eq "Binary") {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040019849 mergeImpl();
19850 }
19851 }
19852}
19853
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040019854sub getSysOpts()
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040019855{
19856 my %Opts = (
19857 "OStarget"=>$OStarget,
19858 "Debug"=>$Debug,
19859 "Quiet"=>$Quiet,
19860 "LogMode"=>$LogMode,
19861 "CheckHeadersOnly"=>$CheckHeadersOnly,
19862
19863 "SystemRoot"=>$SystemRoot,
19864 "MODULES_DIR"=>$MODULES_DIR,
19865 "GCC_PATH"=>$GCC_PATH,
19866 "TargetSysInfo"=>$TargetSysInfo,
19867 "CrossPrefix"=>$CrossPrefix,
19868 "TargetLibraryName"=>$TargetLibraryName,
19869 "CrossGcc"=>$CrossGcc,
19870 "UseStaticLibs"=>$UseStaticLibs,
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040019871 "NoStdInc"=>$NoStdInc,
19872
19873 "BinaryOnly" => $BinaryOnly,
19874 "SourceOnly" => $SourceOnly
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040019875 );
19876 return \%Opts;
19877}
19878
19879sub get_CoreError($)
19880{
19881 my %CODE_ERROR = reverse(%ERROR_CODE);
19882 return $CODE_ERROR{$_[0]};
19883}
19884
19885sub scenario()
19886{
19887 if($StdOut)
19888 { # enable quiet mode
19889 $Quiet = 1;
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040019890 $JoinReport = 1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040019891 }
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040019892 if(not $LogMode)
19893 { # default
19894 $LogMode = "w";
19895 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040019896 if($UserLang)
19897 { # --lang=C++
19898 $UserLang = uc($UserLang);
19899 $COMMON_LANGUAGE{1}=$UserLang;
19900 $COMMON_LANGUAGE{2}=$UserLang;
19901 }
19902 if($LoggingPath)
19903 {
19904 $OutputLogPath{1} = $LoggingPath;
19905 $OutputLogPath{2} = $LoggingPath;
19906 if($Quiet) {
19907 $COMMON_LOG_PATH = $LoggingPath;
19908 }
19909 }
Andrey Ponomarenko5c09ef32012-06-14 18:17:33 +040019910 if($OutputDumpPath)
19911 { # validate
19912 if($OutputDumpPath!~/\.abi(\.\Q$AR_EXT\E|)\Z/) {
19913 exitStatus("Error", "the dump path should be a path to *.abi.$AR_EXT or *.abi file");
19914 }
19915 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040019916 if($BinaryOnly and $SourceOnly)
19917 { # both --binary and --source
19918 # is the default mode
19919 $DoubleReport = 1;
19920 $JoinReport = 0;
19921 $BinaryOnly = 0;
19922 $SourceOnly = 0;
19923 if($OutputReportPath)
19924 { # --report-path
19925 $DoubleReport = 0;
19926 $JoinReport = 1;
19927 }
19928 }
19929 elsif($BinaryOnly or $SourceOnly)
19930 { # --binary or --source
19931 $DoubleReport = 0;
19932 $JoinReport = 0;
19933 }
19934 if($UseXML)
19935 { # --xml option
19936 $ReportFormat = "xml";
Andrey Ponomarenko5c09ef32012-06-14 18:17:33 +040019937 $DumpFormat = "xml";
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040019938 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040019939 if($ReportFormat)
19940 { # validate
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040019941 $ReportFormat = lc($ReportFormat);
19942 if($ReportFormat!~/\A(xml|html|htm)\Z/) {
Andrey Ponomarenko5c09ef32012-06-14 18:17:33 +040019943 exitStatus("Error", "unknown report format \'$ReportFormat\'");
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040019944 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040019945 if($ReportFormat eq "htm")
19946 { # HTM == HTML
19947 $ReportFormat = "html";
19948 }
19949 elsif($ReportFormat eq "xml")
19950 { # --report-format=XML equal to --xml
19951 $UseXML = 1;
19952 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040019953 }
19954 else
19955 { # default: HTML
19956 $ReportFormat = "html";
19957 }
Andrey Ponomarenko5c09ef32012-06-14 18:17:33 +040019958 if($DumpFormat)
19959 { # validate
19960 $DumpFormat = lc($DumpFormat);
19961 if($DumpFormat!~/\A(xml|perl)\Z/) {
19962 exitStatus("Error", "unknown ABI dump format \'$DumpFormat\'");
19963 }
19964 if($DumpFormat eq "xml")
19965 { # --dump-format=XML equal to --xml
19966 $UseXML = 1;
19967 }
19968 }
19969 else
Andrey Ponomarenko01117f12012-06-26 12:23:02 +040019970 { # default: Perl Data::Dumper
Andrey Ponomarenko5c09ef32012-06-14 18:17:33 +040019971 $DumpFormat = "perl";
19972 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040019973 if($Quiet and $LogMode!~/a|n/)
19974 { # --quiet log
19975 if(-f $COMMON_LOG_PATH) {
19976 unlink($COMMON_LOG_PATH);
19977 }
19978 }
19979 if($TestTool and $UseDumps)
19980 { # --test && --use-dumps == --test-dump
19981 $TestDump = 1;
19982 }
19983 if($Help) {
19984 HELP_MESSAGE();
19985 exit(0);
19986 }
19987 if($InfoMsg) {
19988 INFO_MESSAGE();
19989 exit(0);
19990 }
19991 if($ShowVersion) {
19992 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.");
19993 exit(0);
19994 }
19995 if($DumpVersion) {
19996 printMsg("INFO", $TOOL_VERSION);
19997 exit(0);
19998 }
19999 if($ExtendedCheck) {
20000 $CheckHeadersOnly = 1;
20001 }
20002 if($SystemRoot_Opt)
20003 { # user defined root
20004 if(not -e $SystemRoot_Opt) {
20005 exitStatus("Access_Error", "can't access \'$SystemRoot\'");
20006 }
20007 $SystemRoot = $SystemRoot_Opt;
20008 $SystemRoot=~s/[\/]+\Z//g;
20009 if($SystemRoot) {
20010 $SystemRoot = get_abs_path($SystemRoot);
20011 }
20012 }
20013 $Data::Dumper::Sortkeys = 1;
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +040020014
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040020015 if($SortDump)
20016 {
20017 $Data::Dumper::Useperl = 1;
20018 $Data::Dumper::Sortkeys = \&dump_sorting;
20019 }
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +040020020
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040020021 if($TargetLibsPath)
20022 {
20023 if(not -f $TargetLibsPath) {
20024 exitStatus("Access_Error", "can't access file \'$TargetLibsPath\'");
20025 }
20026 foreach my $Lib (split(/\s*\n\s*/, readFile($TargetLibsPath))) {
20027 $TargetLibs{$Lib} = 1;
20028 }
20029 }
20030 if($TargetHeadersPath)
20031 { # --headers-list
20032 if(not -f $TargetHeadersPath) {
20033 exitStatus("Access_Error", "can't access file \'$TargetHeadersPath\'");
20034 }
20035 foreach my $Header (split(/\s*\n\s*/, readFile($TargetHeadersPath)))
20036 {
20037 $TargetHeaders{1}{$Header} = 1;
20038 $TargetHeaders{2}{$Header} = 1;
20039 }
20040 }
20041 if($TargetHeader)
20042 { # --header
20043 $TargetHeaders{1}{$TargetHeader} = 1;
20044 $TargetHeaders{2}{$TargetHeader} = 1;
20045 }
20046 if($TestTool
20047 or $TestDump)
20048 { # --test, --test-dump
20049 detect_default_paths("bin|gcc"); # to compile libs
20050 loadModule("RegTests");
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +040020051 testTool($TestDump, $Debug, $Quiet, $ExtendedCheck, $LogMode, $ReportFormat, $DumpFormat,
20052 $LIB_EXT, $GCC_PATH, $Browse, $OpenReport, $SortDump, $CheckHeadersOnly, $CheckObjectsOnly);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040020053 exit(0);
20054 }
20055 if($DumpSystem)
20056 { # --dump-system
20057 loadModule("SysCheck");
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040020058 if($DumpSystem=~/\.(xml|desc)\Z/)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040020059 { # system XML descriptor
20060 if(not -f $DumpSystem) {
20061 exitStatus("Access_Error", "can't access file \'$DumpSystem\'");
20062 }
20063 my $Ret = readSystemDescriptor(readFile($DumpSystem));
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040020064 foreach (@{$Ret->{"Tools"}})
20065 {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040020066 $SystemPaths{"bin"}{$_} = 1;
20067 $TargetTools{$_}=1;
20068 }
20069 if($Ret->{"CrossPrefix"}) {
20070 $CrossPrefix = $Ret->{"CrossPrefix"};
20071 }
20072 }
20073 elsif($SystemRoot_Opt)
20074 { # -sysroot "/" option
20075 # default target: /usr/lib, /usr/include
20076 # search libs: /usr/lib and /lib
20077 if(not -e $SystemRoot."/usr/lib") {
20078 exitStatus("Access_Error", "can't access '".$SystemRoot."/usr/lib'");
20079 }
20080 if(not -e $SystemRoot."/lib") {
20081 exitStatus("Access_Error", "can't access '".$SystemRoot."/lib'");
20082 }
20083 if(not -e $SystemRoot."/usr/include") {
20084 exitStatus("Access_Error", "can't access '".$SystemRoot."/usr/include'");
20085 }
20086 readSystemDescriptor("
20087 <name>
20088 $DumpSystem
20089 </name>
20090 <headers>
20091 $SystemRoot/usr/include
20092 </headers>
20093 <libs>
20094 $SystemRoot/usr/lib
20095 </libs>
20096 <search_libs>
20097 $SystemRoot/lib
20098 </search_libs>");
20099 }
20100 else {
20101 exitStatus("Error", "-sysroot <dirpath> option should be specified, usually it's \"/\"");
20102 }
20103 detect_default_paths("bin|gcc"); # to check symbols
20104 if($OStarget eq "windows")
20105 { # to run dumpbin.exe
20106 # and undname.exe
20107 check_win32_env();
20108 }
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040020109 dumpSystem(getSysOpts());
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040020110 exit(0);
20111 }
20112 if($CmpSystems)
20113 { # --cmp-systems
20114 detect_default_paths("bin"); # to extract dumps
20115 loadModule("SysCheck");
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040020116 cmpSystems($Descriptor{1}{"Path"}, $Descriptor{2}{"Path"}, getSysOpts());
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040020117 exit(0);
20118 }
20119 if($GenerateTemplate) {
20120 generateTemplate();
20121 exit(0);
20122 }
20123 if(not $TargetLibraryName) {
20124 exitStatus("Error", "library name is not selected (option -l <name>)");
20125 }
20126 else
20127 { # validate library name
20128 if($TargetLibraryName=~/[\*\/\\]/) {
20129 exitStatus("Error", "\"\\\", \"\/\" and \"*\" symbols are not allowed in the library name");
20130 }
20131 }
20132 if(not $TargetLibraryFName) {
20133 $TargetLibraryFName = $TargetLibraryName;
20134 }
20135 if($CheckHeadersOnly_Opt and $CheckObjectsOnly_Opt) {
20136 exitStatus("Error", "you can't specify both -headers-only and -objects-only options at the same time");
20137 }
20138 if($SymbolsListPath)
20139 {
20140 if(not -f $SymbolsListPath) {
20141 exitStatus("Access_Error", "can't access file \'$SymbolsListPath\'");
20142 }
20143 foreach my $Interface (split(/\s*\n\s*/, readFile($SymbolsListPath))) {
20144 $SymbolsList{$Interface} = 1;
20145 }
20146 }
20147 if($SkipHeadersPath)
20148 {
20149 if(not -f $SkipHeadersPath) {
20150 exitStatus("Access_Error", "can't access file \'$SkipHeadersPath\'");
20151 }
20152 foreach my $Path (split(/\s*\n\s*/, readFile($SkipHeadersPath)))
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040020153 { # register for both versions
20154 $SkipHeadersList{1}{$Path} = 1;
20155 $SkipHeadersList{2}{$Path} = 1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040020156 my ($CPath, $Type) = classifyPath($Path);
20157 $SkipHeaders{1}{$Type}{$CPath} = 1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040020158 $SkipHeaders{2}{$Type}{$CPath} = 1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040020159 }
20160 }
20161 if($ParamNamesPath)
20162 {
20163 if(not -f $ParamNamesPath) {
20164 exitStatus("Access_Error", "can't access file \'$ParamNamesPath\'");
20165 }
20166 foreach my $Line (split(/\n/, readFile($ParamNamesPath)))
20167 {
20168 if($Line=~s/\A(\w+)\;//)
20169 {
20170 my $Interface = $1;
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040020171 if($Line=~/;(\d+);/)
20172 {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040020173 while($Line=~s/(\d+);(\w+)//) {
20174 $AddIntParams{$Interface}{$1}=$2;
20175 }
20176 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040020177 else
20178 {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040020179 my $Num = 0;
20180 foreach my $Name (split(/;/, $Line)) {
20181 $AddIntParams{$Interface}{$Num++}=$Name;
20182 }
20183 }
20184 }
20185 }
20186 }
20187 if($AppPath)
20188 {
20189 if(not -f $AppPath) {
20190 exitStatus("Access_Error", "can't access file \'$AppPath\'");
20191 }
Andrey Ponomarenko16934472012-03-29 15:37:04 +040020192 foreach my $Interface (readSymbols_App($AppPath)) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040020193 $SymbolsList_App{$Interface} = 1;
20194 }
20195 }
20196 if($DumpAPI)
20197 { # --dump-abi
20198 # make an API dump
20199 create_ABI_Dump();
20200 exit($COMPILE_ERRORS);
20201 }
20202 # default: compare APIs
20203 # -d1 <path>
20204 # -d2 <path>
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040020205 compareInit();
20206 if($JoinReport or $DoubleReport)
20207 {
20208 compareAPIs("Binary");
20209 compareAPIs("Source");
20210 }
20211 elsif($BinaryOnly) {
20212 compareAPIs("Binary");
20213 }
20214 elsif($SourceOnly) {
20215 compareAPIs("Source");
20216 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040020217 exitReport();
20218}
20219
20220scenario();