blob: 843b3567d880ae17286b4ec32bae8f125b6f99b7 [file] [log] [blame]
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04001#!/usr/bin/perl
2###########################################################################
Andrey Ponomarenko07aea072012-11-12 16:15:07 +04003# ABI Compliance Checker (ACC) 1.98.5
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04004# A tool for checking backward compatibility of a C/C++ library API
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005#
Andrey Ponomarenko85043792012-05-14 16:48:07 +04006# Copyright (C) 2009-2010 The Linux Foundation
7# Copyright (C) 2009-2011 Institute for System Programming, RAS
8# Copyright (C) 2011-2012 Nokia Corporation and/or its subsidiary(-ies)
9# Copyright (C) 2011-2012 ROSA Laboratory
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010#
11# Written by Andrey Ponomarenko
12#
13# PLATFORMS
14# =========
15# Linux, FreeBSD, Mac OS X, Haiku, MS Windows, Symbian
16#
17# REQUIREMENTS
18# ============
19# Linux
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +040020# - G++ (3.0-4.7, recommended 4.5 or newer)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040021# - GNU Binutils (readelf, c++filt, objdump)
Andrey Ponomarenko85043792012-05-14 16:48:07 +040022# - Perl 5 (5.8 or newer)
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +040023# - Ctags (5.8 or newer)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040024#
25# Mac OS X
Andrey Ponomarenko07aea072012-11-12 16:15:07 +040026# - Xcode (g++, c++filt, nm)
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +040027# - Ctags (5.8 or newer)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040028#
29# MS Windows
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +040030# - MinGW (3.0-4.7, recommended 4.5 or newer)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040031# - MS Visual C++ (dumpbin, undname, cl)
Andrey Ponomarenko85043792012-05-14 16:48:07 +040032# - Active Perl 5 (5.8 or newer)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040033# - Sigcheck v1.71 or newer
34# - Info-ZIP 3.0 (zip, unzip)
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +040035# - Ctags (5.8 or newer)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040036# - Add gcc.exe path (C:\MinGW\bin\) to your system PATH variable
37# - Run vsvars32.bat (C:\Microsoft Visual Studio 9.0\Common7\Tools\)
38#
39# This program is free software: you can redistribute it and/or modify
40# it under the terms of the GNU General Public License or the GNU Lesser
41# General Public License as published by the Free Software Foundation.
42#
43# This program is distributed in the hope that it will be useful,
44# but WITHOUT ANY WARRANTY; without even the implied warranty of
45# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
46# GNU General Public License for more details.
47#
48# You should have received a copy of the GNU General Public License
49# and the GNU Lesser General Public License along with this program.
50# If not, see <http://www.gnu.org/licenses/>.
51###########################################################################
52use Getopt::Long;
53Getopt::Long::Configure ("posix_default", "no_ignore_case");
54use File::Path qw(mkpath rmtree);
55use File::Temp qw(tempdir);
56use File::Copy qw(copy move);
57use Cwd qw(abs_path cwd);
58use Data::Dumper;
Andrey Ponomarenko2fba6302012-03-29 17:44:47 +040059use Config;
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040060use Fcntl;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040061
Andrey Ponomarenko07aea072012-11-12 16:15:07 +040062my $TOOL_VERSION = "1.98.5";
63my $ABI_DUMP_VERSION = "2.19.2";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040064my $OLDEST_SUPPORTED_VERSION = "1.18";
65my $XML_REPORT_VERSION = "1.0";
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +040066my $XML_ABI_DUMP_VERSION = "1.2";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040067my $OSgroup = get_OSgroup();
68my $ORIG_DIR = cwd();
69my $TMP_DIR = tempdir(CLEANUP=>1);
70
71# Internal modules
72my $MODULES_DIR = get_Modules();
73push(@INC, get_dirname($MODULES_DIR));
74# Rules DB
75my %RULES_PATH = (
76 "Binary" => $MODULES_DIR."/RulesBin.xml",
77 "Source" => $MODULES_DIR."/RulesSrc.xml");
78
79my ($Help, $ShowVersion, %Descriptor, $TargetLibraryName, $GenerateTemplate,
80$TestTool, $DumpAPI, $SymbolsListPath, $CheckHeadersOnly_Opt, $UseDumps,
81$CheckObjectsOnly_Opt, $AppPath, $StrictCompat, $DumpVersion, $ParamNamesPath,
82%RelativeDirectory, $TargetLibraryFName, $TestDump, $CheckImpl, $LoggingPath,
83%TargetVersion, $InfoMsg, $UseOldDumps, %UsedDump, $CrossGcc, %OutputLogPath,
84$OutputReportPath, $OutputDumpPath, $ShowRetVal, $SystemRoot_Opt, $DumpSystem,
85$CmpSystems, $TargetLibsPath, $Debug, $CrossPrefix, $UseStaticLibs, $NoStdInc,
86$TargetComponent_Opt, $TargetSysInfo, $TargetHeader, $ExtendedCheck, $Quiet,
Andrey Ponomarenko07aea072012-11-12 16:15:07 +040087$SkipHeadersPath, $CppCompat, $LogMode, $StdOut, $ListAffected, $ReportFormat,
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040088$UserLang, $TargetHeadersPath, $BinaryOnly, $SourceOnly, $BinaryReportPath,
Andrey Ponomarenko07aea072012-11-12 16:15:07 +040089$SourceReportPath, $UseXML, $Browse, $OpenReport, $SortDump, $DumpFormat,
90$ExtraInfo);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040091
92my $CmdName = get_filename($0);
93my %OS_LibExt = (
94 "dynamic" => {
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040095 "linux"=>"so",
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040096 "macos"=>"dylib",
97 "windows"=>"dll",
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040098 "symbian"=>"dso",
99 "default"=>"so"
Andrey Ponomarenkoab282102012-03-11 11:57:02 +0400100 },
101 "static" => {
Andrey Ponomarenko9927e332012-10-19 10:50:48 +0400102 "linux"=>"a",
Andrey Ponomarenkoab282102012-03-11 11:57:02 +0400103 "windows"=>"lib",
Andrey Ponomarenko9927e332012-10-19 10:50:48 +0400104 "symbian"=>"lib",
105 "default"=>"a"
Andrey Ponomarenkoab282102012-03-11 11:57:02 +0400106 }
107);
108
109my %OS_Archive = (
110 "windows"=>"zip",
111 "default"=>"tar.gz"
112);
113
114my %ERROR_CODE = (
115 # Compatible verdict
116 "Compatible"=>0,
117 "Success"=>0,
118 # Incompatible verdict
119 "Incompatible"=>1,
120 # Undifferentiated error code
121 "Error"=>2,
122 # System command is not found
123 "Not_Found"=>3,
124 # Cannot access input files
125 "Access_Error"=>4,
126 # Cannot compile header files
127 "Cannot_Compile"=>5,
128 # Header compiled with errors
129 "Compile_Error"=>6,
130 # Invalid input ABI dump
131 "Invalid_Dump"=>7,
132 # Incompatible version of ABI dump
133 "Dump_Version"=>8,
134 # Cannot find a module
135 "Module_Error"=>9,
136 # Empty intersection between
137 # headers and shared objects
138 "Empty_Intersection"=>10,
139 # Empty set of symbols in headers
140 "Empty_Set"=>11
141);
142
143my %HomePage = (
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +0400144 "Wiki"=>"http://ispras.linuxbase.org/index.php/ABI_compliance_checker",
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +0400145 "Dev1"=>"https://github.com/lvc/abi-compliance-checker",
146 "Dev2"=>"http://forge.ispras.ru/projects/abi-compliance-checker"
Andrey Ponomarenkoab282102012-03-11 11:57:02 +0400147);
148
149my $ShortUsage = "ABI Compliance Checker (ACC) $TOOL_VERSION
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +0400150A tool for checking backward compatibility of a C/C++ library API
Andrey Ponomarenkoab282102012-03-11 11:57:02 +0400151Copyright (C) 2012 ROSA Laboratory
152License: GNU LGPL or GNU GPL
153
154Usage: $CmdName [options]
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +0400155Example: $CmdName -lib NAME -old OLD.xml -new NEW.xml
Andrey Ponomarenkoab282102012-03-11 11:57:02 +0400156
157OLD.xml and NEW.xml are XML-descriptors:
158
159 <version>
160 1.0
161 </version>
162
163 <headers>
164 /path/to/headers/
165 </headers>
166
167 <libs>
168 /path/to/libraries/
169 </libs>
170
171More info: $CmdName --help\n";
172
173if($#ARGV==-1) {
174 printMsg("INFO", $ShortUsage);
175 exit(0);
176}
177
178foreach (2 .. $#ARGV)
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +0400179{ # correct comma separated options
Andrey Ponomarenkoab282102012-03-11 11:57:02 +0400180 if($ARGV[$_-1] eq ",") {
181 $ARGV[$_-2].=",".$ARGV[$_];
182 splice(@ARGV, $_-1, 2);
183 }
184 elsif($ARGV[$_-1]=~/,\Z/) {
185 $ARGV[$_-1].=$ARGV[$_];
186 splice(@ARGV, $_, 1);
187 }
188 elsif($ARGV[$_]=~/\A,/
189 and $ARGV[$_] ne ",") {
190 $ARGV[$_-1].=$ARGV[$_];
191 splice(@ARGV, $_, 1);
192 }
193}
194
195GetOptions("h|help!" => \$Help,
196 "i|info!" => \$InfoMsg,
197 "v|version!" => \$ShowVersion,
198 "dumpversion!" => \$DumpVersion,
199# general options
200 "l|lib|library=s" => \$TargetLibraryName,
201 "d1|old|o=s" => \$Descriptor{1}{"Path"},
202 "d2|new|n=s" => \$Descriptor{2}{"Path"},
203 "dump|dump-abi|dump_abi=s" => \$DumpAPI,
204 "old-dumps!" => \$UseOldDumps,
205# extra options
206 "d|descriptor-template!" => \$GenerateTemplate,
207 "app|application=s" => \$AppPath,
208 "static-libs!" => \$UseStaticLibs,
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +0400209 "cross-gcc|gcc-path=s" => \$CrossGcc,
210 "cross-prefix|gcc-prefix=s" => \$CrossPrefix,
Andrey Ponomarenkoab282102012-03-11 11:57:02 +0400211 "sysroot=s" => \$SystemRoot_Opt,
212 "v1|version1|vnum=s" => \$TargetVersion{1},
213 "v2|version2=s" => \$TargetVersion{2},
214 "s|strict!" => \$StrictCompat,
215 "symbols-list=s" => \$SymbolsListPath,
216 "skip-headers=s" => \$SkipHeadersPath,
217 "headers-only|headers_only!" => \$CheckHeadersOnly_Opt,
218 "objects-only!" => \$CheckObjectsOnly_Opt,
219 "check-impl|check-implementation!" => \$CheckImpl,
220 "show-retval!" => \$ShowRetVal,
221 "use-dumps!" => \$UseDumps,
222 "nostdinc!" => \$NoStdInc,
223 "dump-system=s" => \$DumpSystem,
224 "sysinfo=s" => \$TargetSysInfo,
225 "cmp-systems!" => \$CmpSystems,
226 "libs-list=s" => \$TargetLibsPath,
227 "headers-list=s" => \$TargetHeadersPath,
228 "header=s" => \$TargetHeader,
229 "ext|extended!" => \$ExtendedCheck,
230 "q|quiet!" => \$Quiet,
231 "stdout!" => \$StdOut,
232 "report-format=s" => \$ReportFormat,
Andrey Ponomarenko5c09ef32012-06-14 18:17:33 +0400233 "dump-format=s" => \$DumpFormat,
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +0400234 "xml!" => \$UseXML,
Andrey Ponomarenkoab282102012-03-11 11:57:02 +0400235 "lang=s" => \$UserLang,
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +0400236 "binary|bin|abi!" => \$BinaryOnly,
237 "source|src|api!" => \$SourceOnly,
Andrey Ponomarenkoab282102012-03-11 11:57:02 +0400238# other options
239 "test!" => \$TestTool,
240 "test-dump!" => \$TestDump,
241 "debug!" => \$Debug,
Andrey Ponomarenko07aea072012-11-12 16:15:07 +0400242 "cpp-compatible!" => \$CppCompat,
Andrey Ponomarenkoab282102012-03-11 11:57:02 +0400243 "p|params=s" => \$ParamNamesPath,
244 "relpath1|relpath=s" => \$RelativeDirectory{1},
245 "relpath2=s" => \$RelativeDirectory{2},
246 "dump-path=s" => \$OutputDumpPath,
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +0400247 "sort!" => \$SortDump,
Andrey Ponomarenkoab282102012-03-11 11:57:02 +0400248 "report-path=s" => \$OutputReportPath,
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +0400249 "bin-report-path=s" => \$BinaryReportPath,
250 "src-report-path=s" => \$SourceReportPath,
Andrey Ponomarenkoab282102012-03-11 11:57:02 +0400251 "log-path=s" => \$LoggingPath,
252 "log1-path=s" => \$OutputLogPath{1},
253 "log2-path=s" => \$OutputLogPath{2},
254 "logging-mode=s" => \$LogMode,
255 "list-affected!" => \$ListAffected,
256 "l-full|lib-full=s" => \$TargetLibraryFName,
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +0400257 "component=s" => \$TargetComponent_Opt,
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +0400258 "b|browse=s" => \$Browse,
Andrey Ponomarenko07aea072012-11-12 16:15:07 +0400259 "open!" => \$OpenReport,
260 "extra-info=s" => \$ExtraInfo
Andrey Ponomarenkoab282102012-03-11 11:57:02 +0400261) or ERR_MESSAGE();
262
263sub ERR_MESSAGE()
264{
265 printMsg("INFO", "\n".$ShortUsage);
266 exit($ERROR_CODE{"Error"});
267}
268
269my $LIB_TYPE = $UseStaticLibs?"static":"dynamic";
270my $SLIB_TYPE = $LIB_TYPE;
271if($OSgroup!~/macos|windows/ and $SLIB_TYPE eq "dynamic")
272{ # show as "shared" library
273 $SLIB_TYPE = "shared";
274}
275my $LIB_EXT = getLIB_EXT($OSgroup);
276my $AR_EXT = getAR_EXT($OSgroup);
277my $BYTE_SIZE = 8;
278my $COMMON_LOG_PATH = "logs/run.log";
279
280my $HelpMessage="
281NAME:
282 ABI Compliance Checker ($CmdName)
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +0400283 Check backward compatibility of a C/C++ library API
Andrey Ponomarenkoab282102012-03-11 11:57:02 +0400284
285DESCRIPTION:
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +0400286 ABI Compliance Checker (ACC) is a tool for checking backward binary and
287 source-level compatibility of a $SLIB_TYPE C/C++ library. The tool checks
288 header files and $SLIB_TYPE libraries (*.$LIB_EXT) of old and new versions and
289 analyzes changes in API and ABI (ABI=API+compiler ABI) that may break binary
290 and/or source-level compatibility: changes in calling stack, v-table changes,
291 removed symbols, renamed fields, etc. Binary incompatibility may result in
292 crashing or incorrect behavior of applications built with an old version of
293 a library if they run on a new one. Source incompatibility may result in
294 recompilation errors with a new library version.
Andrey Ponomarenkoab282102012-03-11 11:57:02 +0400295
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +0400296 The tool is intended for developers of software libraries and maintainers
297 of operating systems who are interested in ensuring backward compatibility,
298 i.e. allow old applications to run or to be recompiled with newer library
299 versions.
300
301 Also the tool can be used by ISVs for checking applications portability to
302 new library versions. Found issues can be taken into account when adapting
303 the application to a new library version.
Andrey Ponomarenkoab282102012-03-11 11:57:02 +0400304
305 This tool is free software: you can redistribute it and/or modify it
306 under the terms of the GNU LGPL or GNU GPL.
307
308USAGE:
309 $CmdName [options]
310
311EXAMPLE:
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +0400312 $CmdName -lib NAME -old OLD.xml -new NEW.xml
Andrey Ponomarenkoab282102012-03-11 11:57:02 +0400313
314 OLD.xml and NEW.xml are XML-descriptors:
315
316 <version>
317 1.0
318 </version>
319
320 <headers>
321 /path1/to/header(s)/
322 /path2/to/header(s)/
323 ...
324 </headers>
325
326 <libs>
327 /path1/to/library(ies)/
328 /path2/to/library(ies)/
329 ...
330 </libs>
331
332INFORMATION OPTIONS:
333 -h|-help
334 Print this help.
335
336 -i|-info
337 Print complete info.
338
339 -v|-version
340 Print version information.
341
342 -dumpversion
343 Print the tool version ($TOOL_VERSION) and don't do anything else.
344
345GENERAL OPTIONS:
Andrey Ponomarenko07aea072012-11-12 16:15:07 +0400346 -l|-lib|-library NAME
Andrey Ponomarenkoab282102012-03-11 11:57:02 +0400347 Library name (without version).
Andrey Ponomarenkoab282102012-03-11 11:57:02 +0400348
Andrey Ponomarenko07aea072012-11-12 16:15:07 +0400349 -d1|-old|-o PATH
Andrey Ponomarenkoab282102012-03-11 11:57:02 +0400350 Descriptor of 1st (old) library version.
351 It may be one of the following:
352
353 1. XML-descriptor (VERSION.xml file):
354
355 <version>
356 1.0
357 </version>
358
359 <headers>
360 /path1/to/header(s)/
361 /path2/to/header(s)/
362 ...
363 </headers>
364
365 <libs>
366 /path1/to/library(ies)/
367 /path2/to/library(ies)/
368 ...
369 </libs>
370
371 ... (XML-descriptor template
372 can be generated by -d option)
373
374 2. ABI dump generated by -dump option
375 3. Directory with headers and/or $SLIB_TYPE libraries
376 4. Single header file
377 5. Single $SLIB_TYPE library
378 6. Comma separated list of headers and/or libraries
379
380 If you are using an 2-6 descriptor types then you should
381 specify version numbers with -v1 <num> and -v2 <num> options too.
382
383 For more information, please see:
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +0400384 http://ispras.linuxbase.org/index.php/Library_Descriptor
Andrey Ponomarenkoab282102012-03-11 11:57:02 +0400385
Andrey Ponomarenko07aea072012-11-12 16:15:07 +0400386 -d2|-new|-n PATH
Andrey Ponomarenkoab282102012-03-11 11:57:02 +0400387 Descriptor of 2nd (new) library version.
388
Andrey Ponomarenko07aea072012-11-12 16:15:07 +0400389 -dump|-dump-abi PATH
Andrey Ponomarenkoab282102012-03-11 11:57:02 +0400390 Dump library ABI to gzipped TXT format file. You can transfer it
391 anywhere and pass instead of the descriptor. Also it can be used
392 for debugging the tool. Compatible dump versions: ".majorVersion($ABI_DUMP_VERSION).".0<=V<=$ABI_DUMP_VERSION
393
394 -old-dumps
395 Enable support for old-version ABI dumps ($OLDEST_SUPPORTED_VERSION<=V<".majorVersion($ABI_DUMP_VERSION).".0).\n";
396
397sub HELP_MESSAGE() {
398 printMsg("INFO", $HelpMessage."
399MORE INFO:
400 $CmdName --info\n");
401}
402
403sub INFO_MESSAGE()
404{
405 printMsg("INFO", "$HelpMessage
406EXTRA OPTIONS:
407 -d|-descriptor-template
408 Create XML-descriptor template ./VERSION.xml
409
Andrey Ponomarenko07aea072012-11-12 16:15:07 +0400410 -app|-application PATH
Andrey Ponomarenkoab282102012-03-11 11:57:02 +0400411 This option allows to specify the application that should be checked
412 for portability to the new library version.
413
414 -static-libs
415 Check static libraries instead of the shared ones. The <libs> section
416 of the XML-descriptor should point to static libraries location.
417
Andrey Ponomarenko07aea072012-11-12 16:15:07 +0400418 -cross-gcc|-gcc-path PATH
Andrey Ponomarenkoab282102012-03-11 11:57:02 +0400419 Path to the cross GCC compiler to use instead of the usual (host) GCC.
420
Andrey Ponomarenko07aea072012-11-12 16:15:07 +0400421 -cross-prefix|-gcc-prefix PREFIX
Andrey Ponomarenkoab282102012-03-11 11:57:02 +0400422 GCC toolchain prefix.
423
Andrey Ponomarenko07aea072012-11-12 16:15:07 +0400424 -sysroot DIR
Andrey Ponomarenkoab282102012-03-11 11:57:02 +0400425 Specify the alternative root directory. The tool will search for include
Andrey Ponomarenko07aea072012-11-12 16:15:07 +0400426 paths in the DIR/usr/include and DIR/usr/lib directories.
Andrey Ponomarenkoab282102012-03-11 11:57:02 +0400427
Andrey Ponomarenko07aea072012-11-12 16:15:07 +0400428 -v1|-version1 NUM
Andrey Ponomarenkoab282102012-03-11 11:57:02 +0400429 Specify 1st library version outside the descriptor. This option is needed
430 if you have prefered an alternative descriptor type (see -d1 option).
431
432 In general case you should specify it in the XML-descriptor:
433 <version>
434 VERSION
435 </version>
436
Andrey Ponomarenko07aea072012-11-12 16:15:07 +0400437 -v2|-version2 NUM
Andrey Ponomarenkoab282102012-03-11 11:57:02 +0400438 Specify 2nd library version outside the descriptor.
439
440 -s|-strict
441 Treat all compatibility warnings as problems. Add a number of \"Low\"
442 severity problems to the return value of the tool.
443
444 -headers-only
445 Check header files without $SLIB_TYPE libraries. It is easy to run, but may
446 provide a low quality compatibility report with false positives and
447 without detecting of added/removed symbols.
448
449 Alternatively you can write \"none\" word to the <libs> section
450 in the XML-descriptor:
451 <libs>
452 none
453 </libs>
454
455 -objects-only
456 Check $SLIB_TYPE libraries without header files. It is easy to run, but may
457 provide a low quality compatibility report with false positives and
458 without analysis of changes in parameters and data types.
459
460 Alternatively you can write \"none\" word to the <headers> section
461 in the XML-descriptor:
462 <headers>
463 none
464 </headers>
465
466 -check-impl|-check-implementation
467 Compare canonified disassembled binary code of $SLIB_TYPE libraries to
468 detect changes in the implementation. Add \'Problems with Implementation\'
469 section to the report.
470
471 -show-retval
472 Show the symbol's return type in the report.
473
Andrey Ponomarenko07aea072012-11-12 16:15:07 +0400474 -symbols-list PATH
Andrey Ponomarenkoab282102012-03-11 11:57:02 +0400475 This option allows to specify a file with a list of symbols (mangled
476 names in C++) that should be checked, other symbols will not be checked.
477
Andrey Ponomarenko07aea072012-11-12 16:15:07 +0400478 -skip-headers PATH
Andrey Ponomarenkoab282102012-03-11 11:57:02 +0400479 The file with the list of header files, that should not be checked.
480
481 -use-dumps
482 Make dumps for two versions of a library and compare dumps. This should
483 increase the performance of the tool and decrease the system memory usage.
484
485 -nostdinc
486 Do not search the GCC standard system directories for header files.
487
Andrey Ponomarenko07aea072012-11-12 16:15:07 +0400488 -dump-system NAME -sysroot DIR
489 Find all the shared libraries and header files in DIR directory,
Andrey Ponomarenkoab282102012-03-11 11:57:02 +0400490 create XML descriptors and make ABI dumps for each library. The result
491 set of ABI dumps can be compared (--cmp-systems) with the other one
492 created for other version of operating system in order to check them for
493 compatibility. Do not forget to specify -cross-gcc option if your target
494 system requires some specific version of GCC compiler (different from
495 the host GCC). The system ABI dump will be generated to:
Andrey Ponomarenko07aea072012-11-12 16:15:07 +0400496 sys_dumps/NAME/ARCH
Andrey Ponomarenkoab282102012-03-11 11:57:02 +0400497
Andrey Ponomarenko07aea072012-11-12 16:15:07 +0400498 -dump-system DESCRIPTOR.xml
Andrey Ponomarenkoab282102012-03-11 11:57:02 +0400499 The same as the previous option but takes an XML descriptor of the target
500 system as input, where you should describe it:
501
502 /* Primary sections */
503
504 <name>
505 /* Name of the system */
506 </name>
507
508 <headers>
509 /* The list of paths to header files and/or
510 directories with header files, one per line */
511 </headers>
512
513 <libs>
514 /* The list of paths to shared libraries and/or
515 directories with shared libraries, one per line */
516 </libs>
517
518 /* Optional sections */
519
520 <search_headers>
521 /* List of directories to be searched
522 for header files to automatically
523 generate include paths, one per line */
524 </search_headers>
525
526 <search_libs>
527 /* List of directories to be searched
528 for shared libraries to resolve
529 dependencies, one per line */
530 </search_libs>
531
532 <tools>
533 /* List of directories with tools used
534 for analysis (GCC toolchain), one per line */
535 </tools>
536
537 <cross_prefix>
538 /* GCC toolchain prefix.
539 Examples:
540 arm-linux-gnueabi
541 arm-none-symbianelf */
542 </cross_prefix>
543
544 <gcc_options>
545 /* Additional GCC options, one per line */
546 </gcc_options>
547
Andrey Ponomarenko07aea072012-11-12 16:15:07 +0400548 -sysinfo DIR
Andrey Ponomarenkoab282102012-03-11 11:57:02 +0400549 This option may be used with -dump-system to dump ABI of operating
550 systems and configure the dumping process.
551 Default:
552 modules/Targets/{unix, symbian, windows}
553
Andrey Ponomarenko07aea072012-11-12 16:15:07 +0400554 -cmp-systems -d1 sys_dumps/NAME1/ARCH -d2 sys_dumps/NAME2/ARCH
Andrey Ponomarenkoab282102012-03-11 11:57:02 +0400555 Compare two system ABI dumps. Create compatibility reports for each
556 library and the common HTML report including the summary of test
557 results for all checked libraries. Report will be generated to:
Andrey Ponomarenko07aea072012-11-12 16:15:07 +0400558 sys_compat_reports/NAME1_to_NAME2/ARCH
Andrey Ponomarenkoab282102012-03-11 11:57:02 +0400559
Andrey Ponomarenko07aea072012-11-12 16:15:07 +0400560 -libs-list PATH
Andrey Ponomarenkoab282102012-03-11 11:57:02 +0400561 The file with a list of libraries, that should be dumped by
562 the -dump-system option or should be checked by the -cmp-systems option.
563
Andrey Ponomarenko07aea072012-11-12 16:15:07 +0400564 -header NAME
Andrey Ponomarenkoab282102012-03-11 11:57:02 +0400565 Check/Dump ABI of this header only.
566
Andrey Ponomarenko07aea072012-11-12 16:15:07 +0400567 -headers-list PATH
Andrey Ponomarenkoab282102012-03-11 11:57:02 +0400568 The file with a list of headers, that should be checked/dumped.
569
570 -ext|-extended
571 If your library A is supposed to be used by other library B and you
572 want to control the ABI of B, then you should enable this option. The
573 tool will check for changes in all data types, even if they are not
574 used by any function in the library A. Such data types are not part
575 of the A library ABI, but may be a part of the ABI of the B library.
576
577 The short scheme is:
578 app C (broken) -> lib B (broken ABI) -> lib A (stable ABI)
579
580 -q|-quiet
581 Print all messages to the file instead of stdout and stderr.
582 Default path (can be changed by -log-path option):
583 $COMMON_LOG_PATH
584
585 -stdout
586 Print analysis results (compatibility reports and ABI dumps) to stdout
587 instead of creating a file. This would allow piping data to other programs.
588
Andrey Ponomarenko07aea072012-11-12 16:15:07 +0400589 -report-format FMT
Andrey Ponomarenkoab282102012-03-11 11:57:02 +0400590 Change format of compatibility report.
591 Formats:
592 htm - HTML format (default)
593 xml - XML format
594
Andrey Ponomarenko07aea072012-11-12 16:15:07 +0400595 -dump-format FMT
Andrey Ponomarenko5c09ef32012-06-14 18:17:33 +0400596 Change format of ABI dump.
597 Formats:
598 perl - Data::Dumper format (default)
599 xml - XML format
600
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +0400601 -xml
Andrey Ponomarenko5c09ef32012-06-14 18:17:33 +0400602 Alias for: --report-format=xml or --dump-format=xml
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +0400603
Andrey Ponomarenko07aea072012-11-12 16:15:07 +0400604 -lang LANG
Andrey Ponomarenkoab282102012-03-11 11:57:02 +0400605 Set library language (C or C++). You can use this option if the tool
606 cannot auto-detect a language. This option may be useful for checking
607 C-library headers (--lang=C) in --headers-only or --extended modes.
608
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +0400609 -binary|-bin|-abi
610 Show \"Binary\" compatibility problems only.
611 Generate report to:
Andrey Ponomarenko07aea072012-11-12 16:15:07 +0400612 compat_reports/LIB_NAME/V1_to_V2/abi_compat_report.html
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +0400613
614 -source|-src|-api
615 Show \"Source\" compatibility problems only.
616 Generate report to:
Andrey Ponomarenko07aea072012-11-12 16:15:07 +0400617 compat_reports/LIB_NAME/V1_to_V2/src_compat_report.html
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +0400618
Andrey Ponomarenkoab282102012-03-11 11:57:02 +0400619OTHER OPTIONS:
620 -test
621 Run internal tests. Create two binary incompatible versions of a sample
622 library and run the tool to check them for compatibility. This option
623 allows to check if the tool works correctly in the current environment.
624
625 -test-dump
626 Test ability to create, read and compare ABI dumps.
627
628 -debug
629 Debugging mode. Print debug info on the screen. Save intermediate
630 analysis stages in the debug directory:
Andrey Ponomarenko07aea072012-11-12 16:15:07 +0400631 debug/LIB_NAME/VERSION/
Andrey Ponomarenkoab282102012-03-11 11:57:02 +0400632
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +0400633 Also consider using --dump option for debugging the tool.
634
Andrey Ponomarenkoab282102012-03-11 11:57:02 +0400635 -cpp-compatible
Andrey Ponomarenko07aea072012-11-12 16:15:07 +0400636 If your header files are written in C language and can be compiled
637 by the G++ compiler (i.e. don't use C++ keywords), then you can tell
638 the tool about this and speedup the analysis.
Andrey Ponomarenkoab282102012-03-11 11:57:02 +0400639
Andrey Ponomarenko07aea072012-11-12 16:15:07 +0400640 -p|-params PATH
Andrey Ponomarenkoab282102012-03-11 11:57:02 +0400641 Path to file with the function parameter names. It can be used
642 for improving report view if the library header files have no
643 parameter names. File format:
644
645 func1;param1;param2;param3 ...
646 func2;param1;param2;param3 ...
647 ...
648
Andrey Ponomarenko07aea072012-11-12 16:15:07 +0400649 -relpath PATH
650 Replace {RELPATH} macros to PATH in the XML-descriptor used
Andrey Ponomarenkoab282102012-03-11 11:57:02 +0400651 for dumping the library ABI (see -dump option).
652
Andrey Ponomarenko07aea072012-11-12 16:15:07 +0400653 -relpath1 PATH
654 Replace {RELPATH} macros to PATH in the 1st XML-descriptor (-d1).
Andrey Ponomarenkoab282102012-03-11 11:57:02 +0400655
Andrey Ponomarenko07aea072012-11-12 16:15:07 +0400656 -relpath2 PATH
657 Replace {RELPATH} macros to PATH in the 2nd XML-descriptor (-d2).
Andrey Ponomarenkoab282102012-03-11 11:57:02 +0400658
Andrey Ponomarenko07aea072012-11-12 16:15:07 +0400659 -dump-path PATH
Andrey Ponomarenko5c09ef32012-06-14 18:17:33 +0400660 Specify a *.abi.$AR_EXT or *.abi file path where to generate an ABI dump.
Andrey Ponomarenkoab282102012-03-11 11:57:02 +0400661 Default:
Andrey Ponomarenko07aea072012-11-12 16:15:07 +0400662 abi_dumps/LIB_NAME/LIB_NAME_VERSION.abi.$AR_EXT
Andrey Ponomarenkoab282102012-03-11 11:57:02 +0400663
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +0400664 -sort
665 Enable sorting of data in ABI dumps.
666
Andrey Ponomarenko07aea072012-11-12 16:15:07 +0400667 -report-path PATH
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +0400668 Path to compatibility report.
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +0400669 Default:
Andrey Ponomarenko07aea072012-11-12 16:15:07 +0400670 compat_reports/LIB_NAME/V1_to_V2/compat_report.html
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +0400671
Andrey Ponomarenko07aea072012-11-12 16:15:07 +0400672 -bin-report-path PATH
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +0400673 Path to \"Binary\" compatibility report.
Andrey Ponomarenkoab282102012-03-11 11:57:02 +0400674 Default:
Andrey Ponomarenko07aea072012-11-12 16:15:07 +0400675 compat_reports/LIB_NAME/V1_to_V2/abi_compat_report.html
Andrey Ponomarenkoab282102012-03-11 11:57:02 +0400676
Andrey Ponomarenko07aea072012-11-12 16:15:07 +0400677 -src-report-path PATH
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +0400678 Path to \"Source\" compatibility report.
679 Default:
Andrey Ponomarenko07aea072012-11-12 16:15:07 +0400680 compat_reports/LIB_NAME/V1_to_V2/src_compat_report.html
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +0400681
Andrey Ponomarenko07aea072012-11-12 16:15:07 +0400682 -log-path PATH
Andrey Ponomarenkoab282102012-03-11 11:57:02 +0400683 Log path for all messages.
684 Default:
Andrey Ponomarenko07aea072012-11-12 16:15:07 +0400685 logs/LIB_NAME/VERSION/log.txt
Andrey Ponomarenkoab282102012-03-11 11:57:02 +0400686
Andrey Ponomarenko07aea072012-11-12 16:15:07 +0400687 -log1-path PATH
Andrey Ponomarenkoab282102012-03-11 11:57:02 +0400688 Log path for 1st version of a library.
689 Default:
Andrey Ponomarenko07aea072012-11-12 16:15:07 +0400690 logs/LIB_NAME/V1/log.txt
Andrey Ponomarenkoab282102012-03-11 11:57:02 +0400691
Andrey Ponomarenko07aea072012-11-12 16:15:07 +0400692 -log2-path PATH
Andrey Ponomarenkoab282102012-03-11 11:57:02 +0400693 Log path for 2nd version of a library.
694 Default:
Andrey Ponomarenko07aea072012-11-12 16:15:07 +0400695 logs/LIB_NAME/V2/log.txt
Andrey Ponomarenkoab282102012-03-11 11:57:02 +0400696
Andrey Ponomarenko07aea072012-11-12 16:15:07 +0400697 -logging-mode MODE
Andrey Ponomarenkoab282102012-03-11 11:57:02 +0400698 Change logging mode.
699 Modes:
700 w - overwrite old logs (default)
701 a - append old logs
702 n - do not write any logs
703
704 -list-affected
705 Generate file with the list of incompatible
706 symbols beside the HTML compatibility report.
707 Use 'c++filt \@file' command from GNU binutils
708 to unmangle C++ symbols in the generated file.
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +0400709 Default names:
Andrey Ponomarenkoab282102012-03-11 11:57:02 +0400710 abi_affected.txt
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +0400711 src_affected.txt
Andrey Ponomarenkoab282102012-03-11 11:57:02 +0400712
Andrey Ponomarenko07aea072012-11-12 16:15:07 +0400713 -component NAME
Andrey Ponomarenkoab282102012-03-11 11:57:02 +0400714 The component name in the title and summary of the HTML report.
715 Default:
716 library
717
Andrey Ponomarenko07aea072012-11-12 16:15:07 +0400718 -l-full|-lib-full NAME
719 Change library name in the report title to NAME. By default
Andrey Ponomarenkoab282102012-03-11 11:57:02 +0400720 will be displayed a name specified by -l option.
721
Andrey Ponomarenko07aea072012-11-12 16:15:07 +0400722 -b|-browse PROGRAM
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +0400723 Open report(s) in the browser (firefox, opera, etc.).
724
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +0400725 -open
726 Open report(s) in the default browser.
Andrey Ponomarenko07aea072012-11-12 16:15:07 +0400727
728 -extra-info DIR
729 Dump extra info to DIR.
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +0400730
Andrey Ponomarenkoab282102012-03-11 11:57:02 +0400731REPORT:
732 Compatibility report will be generated to:
Andrey Ponomarenko07aea072012-11-12 16:15:07 +0400733 compat_reports/LIB_NAME/V1_to_V2/compat_report.html
Andrey Ponomarenkoab282102012-03-11 11:57:02 +0400734
735 Log will be generated to:
Andrey Ponomarenko07aea072012-11-12 16:15:07 +0400736 logs/LIB_NAME/V1/log.txt
737 logs/LIB_NAME/V2/log.txt
Andrey Ponomarenkoab282102012-03-11 11:57:02 +0400738
739EXIT CODES:
740 0 - Compatible. The tool has run without any errors.
741 non-zero - Incompatible or the tool has run with errors.
742
743REPORT BUGS TO:
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +0400744 Andrey Ponomarenko <aponomarenko\@rosalab.ru>
Andrey Ponomarenkoab282102012-03-11 11:57:02 +0400745
746MORE INFORMATION:
747 ".$HomePage{"Wiki"}."
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +0400748 ".$HomePage{"Dev1"}."\n");
Andrey Ponomarenkoab282102012-03-11 11:57:02 +0400749}
750
751my $DescriptorTemplate = "
752<?xml version=\"1.0\" encoding=\"utf-8\"?>
753<descriptor>
754
755/* Primary sections */
756
757<version>
758 /* Version of the library */
759</version>
760
761<headers>
762 /* The list of paths to header files and/or
763 directories with header files, one per line */
764</headers>
765
766<libs>
767 /* The list of paths to shared libraries (*.$LIB_EXT) and/or
768 directories with shared libraries, one per line */
769</libs>
770
771/* Optional sections */
772
773<include_paths>
774 /* The list of include paths that will be provided
775 to GCC to compile library headers, one per line.
776 NOTE: If you define this section then the tool
777 will not automatically generate include paths */
778</include_paths>
779
780<add_include_paths>
781 /* The list of include paths that will be added
782 to the automatically generated include paths, one per line */
783</add_include_paths>
784
785<skip_include_paths>
786 /* The list of include paths that will be removed from the
787 list of automatically generated include paths, one per line */
788</skip_include_paths>
789
790<gcc_options>
791 /* Additional GCC options, one per line */
792</gcc_options>
793
794<include_preamble>
795 /* The list of header files that will be
796 included before other headers, one per line.
797 Examples:
798 1) tree.h for libxml2
799 2) ft2build.h for freetype2 */
800</include_preamble>
801
802<defines>
803 /* The list of defines that will be added at the
804 headers compiling stage, one per line:
805 #define A B
806 #define C D */
807</defines>
808
Andrey Ponomarenkoa01311b2012-06-08 17:20:02 +0400809<add_namespaces>
810 /* The list of namespaces that should be added to the alanysis
811 if the tool cannot find them automatically, one per line */
812</add_namespaces>
813
Andrey Ponomarenkoab282102012-03-11 11:57:02 +0400814<skip_types>
815 /* The list of data types, that
816 should not be checked, one per line */
817</skip_types>
818
819<skip_symbols>
820 /* The list of functions (mangled/symbol names in C++),
821 that should not be checked, one per line */
822</skip_symbols>
823
824<skip_namespaces>
825 /* The list of C++ namespaces, that
826 should not be checked, one per line */
827</skip_namespaces>
828
829<skip_constants>
830 /* The list of constants that should
831 not be checked, one name per line */
832</skip_constants>
833
834<skip_headers>
835 /* The list of header files and/or directories
836 with header files that should not be checked, one per line */
837</skip_headers>
838
839<skip_libs>
840 /* The list of shared libraries and/or directories
841 with shared libraries that should not be checked, one per line */
842</skip_libs>
843
844<skip_including>
845 /* The list of header files, that cannot be included
846 directly (or non-self compiled ones), one per line */
847</skip_including>
848
849<search_headers>
850 /* List of directories to be searched
851 for header files to automatically
852 generate include paths, one per line. */
853</search_headers>
854
855<search_libs>
856 /* List of directories to be searched
857 for shared librariess to resolve
858 dependencies, one per line */
859</search_libs>
860
861<tools>
862 /* List of directories with tools used
863 for analysis (GCC toolchain), one per line */
864</tools>
865
866<cross_prefix>
867 /* GCC toolchain prefix.
868 Examples:
869 arm-linux-gnueabi
870 arm-none-symbianelf */
871</cross_prefix>
872
873</descriptor>";
874
875my %Operator_Indication = (
876 "not" => "~",
877 "assign" => "=",
878 "andassign" => "&=",
879 "orassign" => "|=",
880 "xorassign" => "^=",
881 "or" => "|",
882 "xor" => "^",
883 "addr" => "&",
884 "and" => "&",
885 "lnot" => "!",
886 "eq" => "==",
887 "ne" => "!=",
888 "lt" => "<",
889 "lshift" => "<<",
890 "lshiftassign" => "<<=",
891 "rshiftassign" => ">>=",
892 "call" => "()",
893 "mod" => "%",
894 "modassign" => "%=",
895 "subs" => "[]",
896 "land" => "&&",
897 "lor" => "||",
898 "rshift" => ">>",
899 "ref" => "->",
900 "le" => "<=",
901 "deref" => "*",
902 "mult" => "*",
903 "preinc" => "++",
904 "delete" => " delete",
905 "vecnew" => " new[]",
906 "vecdelete" => " delete[]",
907 "predec" => "--",
908 "postinc" => "++",
909 "postdec" => "--",
910 "plusassign" => "+=",
911 "plus" => "+",
912 "minus" => "-",
913 "minusassign" => "-=",
914 "gt" => ">",
915 "ge" => ">=",
916 "new" => " new",
917 "multassign" => "*=",
918 "divassign" => "/=",
919 "div" => "/",
920 "neg" => "-",
921 "pos" => "+",
922 "memref" => "->*",
923 "compound" => "," );
924
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +0400925my %UnknownOperator;
926
927my %NodeType= (
928 "array_type" => "Array",
929 "binfo" => "Other",
930 "boolean_type" => "Intrinsic",
931 "complex_type" => "Intrinsic",
932 "const_decl" => "Other",
933 "enumeral_type" => "Enum",
934 "field_decl" => "Other",
935 "function_decl" => "Other",
936 "function_type" => "FunctionType",
937 "identifier_node" => "Other",
938 "integer_cst" => "Other",
939 "integer_type" => "Intrinsic",
940 "method_type" => "MethodType",
941 "namespace_decl" => "Other",
942 "parm_decl" => "Other",
943 "pointer_type" => "Pointer",
944 "real_cst" => "Other",
945 "real_type" => "Intrinsic",
946 "record_type" => "Struct",
947 "reference_type" => "Ref",
948 "string_cst" => "Other",
949 "template_decl" => "Other",
950 "template_type_parm" => "Other",
951 "tree_list" => "Other",
952 "tree_vec" => "Other",
953 "type_decl" => "Other",
954 "union_type" => "Union",
955 "var_decl" => "Other",
956 "void_type" => "Intrinsic",
957 # "nop_expr" => "Other",
958 # "addr_expr" => "Other",
959 "offset_type" => "Other" );
960
Andrey Ponomarenkoab282102012-03-11 11:57:02 +0400961my %CppKeywords_C = map {$_=>1} (
962 # C++ 2003 keywords
963 "public",
964 "protected",
965 "private",
966 "default",
967 "template",
968 "new",
969 #"asm",
970 "dynamic_cast",
971 "auto",
972 "try",
973 "namespace",
974 "typename",
975 "using",
976 "reinterpret_cast",
977 "friend",
978 "class",
979 "virtual",
980 "const_cast",
981 "mutable",
982 "static_cast",
983 "export",
984 # C++0x keywords
985 "noexcept",
986 "nullptr",
987 "constexpr",
988 "static_assert",
989 "explicit",
990 # cannot be used as a macro name
991 # as it is an operator in C++
992 "and",
993 #"and_eq",
994 "not",
995 #"not_eq",
996 "or"
997 #"or_eq",
998 #"bitand",
999 #"bitor",
1000 #"xor",
1001 #"xor_eq",
1002 #"compl"
1003);
1004
1005my %CppKeywords_F = map {$_=>1} (
1006 "delete",
1007 "catch",
1008 "alignof",
1009 "thread_local",
1010 "decltype",
1011 "typeid"
1012);
1013
1014my %CppKeywords_O = map {$_=>1} (
1015 "bool",
1016 "register",
1017 "inline",
1018 "operator"
1019);
1020
1021my %CppKeywords_A = map {$_=>1} (
1022 "this",
1023 "throw"
1024);
1025
1026foreach (keys(%CppKeywords_C),
1027keys(%CppKeywords_F),
1028keys(%CppKeywords_O)) {
1029 $CppKeywords_A{$_}=1;
1030}
1031
1032# Header file extensions as described by gcc
1033my $HEADER_EXT = "h|hh|hp|hxx|hpp|h\\+\\+";
1034
1035my %IntrinsicMangling = (
1036 "void" => "v",
1037 "bool" => "b",
1038 "wchar_t" => "w",
1039 "char" => "c",
1040 "signed char" => "a",
1041 "unsigned char" => "h",
1042 "short" => "s",
1043 "unsigned short" => "t",
1044 "int" => "i",
1045 "unsigned int" => "j",
1046 "long" => "l",
1047 "unsigned long" => "m",
1048 "long long" => "x",
1049 "__int64" => "x",
1050 "unsigned long long" => "y",
1051 "__int128" => "n",
1052 "unsigned __int128" => "o",
1053 "float" => "f",
1054 "double" => "d",
1055 "long double" => "e",
1056 "__float80" => "e",
1057 "__float128" => "g",
1058 "..." => "z"
1059);
1060
1061my %StdcxxMangling = (
1062 "3std"=>"St",
1063 "3std9allocator"=>"Sa",
1064 "3std12basic_string"=>"Sb",
1065 "3std12basic_stringIcE"=>"Ss",
1066 "3std13basic_istreamIcE"=>"Si",
1067 "3std13basic_ostreamIcE"=>"So",
1068 "3std14basic_iostreamIcE"=>"Sd"
1069);
1070
Andrey Ponomarenkoe3d6bf02012-11-14 11:49:09 +04001071my $DEFAULT_STD_PARMS = "std::(allocator|less|char_traits|regex_traits|istreambuf_iterator|ostreambuf_iterator)";
Andrey Ponomarenko07aea072012-11-12 16:15:07 +04001072
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04001073my %ConstantSuffix = (
1074 "unsigned int"=>"u",
1075 "long"=>"l",
1076 "unsigned long"=>"ul",
1077 "long long"=>"ll",
1078 "unsigned long long"=>"ull"
1079);
1080
1081my %ConstantSuffixR =
1082reverse(%ConstantSuffix);
1083
1084my %OperatorMangling = (
1085 "~" => "co",
1086 "=" => "aS",
1087 "|" => "or",
1088 "^" => "eo",
1089 "&" => "an",#ad (addr)
1090 "==" => "eq",
1091 "!" => "nt",
1092 "!=" => "ne",
1093 "<" => "lt",
1094 "<=" => "le",
1095 "<<" => "ls",
1096 "<<=" => "lS",
1097 ">" => "gt",
1098 ">=" => "ge",
1099 ">>" => "rs",
1100 ">>=" => "rS",
1101 "()" => "cl",
1102 "%" => "rm",
1103 "[]" => "ix",
1104 "&&" => "aa",
1105 "||" => "oo",
1106 "*" => "ml",#de (deref)
1107 "++" => "pp",#
1108 "--" => "mm",#
1109 "new" => "nw",
1110 "delete" => "dl",
1111 "new[]" => "na",
1112 "delete[]" => "da",
1113 "+=" => "pL",
1114 "+" => "pl",#ps (pos)
1115 "-" => "mi",#ng (neg)
1116 "-=" => "mI",
1117 "*=" => "mL",
1118 "/=" => "dV",
1119 "&=" => "aN",
1120 "|=" => "oR",
1121 "%=" => "rM",
1122 "^=" => "eO",
1123 "/" => "dv",
1124 "->*" => "pm",
1125 "->" => "pt",#rf (ref)
1126 "," => "cm",
1127 "?" => "qu",
1128 "." => "dt",
1129 "sizeof"=> "sz"#st
1130);
1131
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04001132my %Intrinsic_Keywords = map {$_=>1} (
1133 "true",
1134 "false",
1135 "_Bool",
1136 "_Complex",
1137 "const",
1138 "int",
1139 "long",
1140 "void",
1141 "short",
1142 "float",
1143 "volatile",
1144 "restrict",
1145 "unsigned",
1146 "signed",
1147 "char",
1148 "double",
1149 "class",
1150 "struct",
1151 "union",
1152 "enum"
1153);
1154
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04001155my %GlibcHeader = map {$_=>1} (
1156 "aliases.h",
1157 "argp.h",
1158 "argz.h",
1159 "assert.h",
1160 "cpio.h",
1161 "ctype.h",
1162 "dirent.h",
1163 "envz.h",
1164 "errno.h",
1165 "error.h",
1166 "execinfo.h",
1167 "fcntl.h",
1168 "fstab.h",
1169 "ftw.h",
1170 "glob.h",
1171 "grp.h",
1172 "iconv.h",
1173 "ifaddrs.h",
1174 "inttypes.h",
1175 "langinfo.h",
1176 "limits.h",
1177 "link.h",
1178 "locale.h",
1179 "malloc.h",
1180 "math.h",
1181 "mntent.h",
1182 "monetary.h",
1183 "nl_types.h",
1184 "obstack.h",
1185 "printf.h",
1186 "pwd.h",
1187 "regex.h",
1188 "sched.h",
1189 "search.h",
1190 "setjmp.h",
1191 "shadow.h",
1192 "signal.h",
1193 "spawn.h",
1194 "stdarg.h",
1195 "stdint.h",
1196 "stdio.h",
1197 "stdlib.h",
1198 "string.h",
Andrey Ponomarenko9927e332012-10-19 10:50:48 +04001199 "strings.h",
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04001200 "tar.h",
1201 "termios.h",
1202 "time.h",
1203 "ulimit.h",
1204 "unistd.h",
1205 "utime.h",
1206 "wchar.h",
1207 "wctype.h",
1208 "wordexp.h" );
1209
1210my %GlibcDir = map {$_=>1} (
1211 "arpa",
1212 "bits",
1213 "gnu",
1214 "netinet",
1215 "net",
1216 "nfs",
1217 "rpc",
1218 "sys",
1219 "linux" );
1220
Andrey Ponomarenko9927e332012-10-19 10:50:48 +04001221my %WinHeaders = map {$_=>1} (
1222 "dos.h",
1223 "process.h",
1224 "winsock.h",
1225 "config-win.h",
1226 "mem.h",
1227 "windows.h",
1228 "winsock2.h",
1229 "crtdbg.h",
1230 "ws2tcpip.h"
1231);
1232
1233my %ObsoleteHeaders = map {$_=>1} (
1234 "iostream.h",
1235 "fstream.h"
1236);
1237
1238my %ConfHeaders = map {$_=>1} (
1239 "atomic",
1240 "conf.h",
1241 "config.h",
1242 "configure.h",
1243 "build.h",
1244 "setup.h"
1245);
1246
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04001247my %LocalIncludes = map {$_=>1} (
1248 "/usr/local/include",
1249 "/usr/local" );
1250
1251my %OS_AddPath=(
1252# These paths are needed if the tool cannot detect them automatically
1253 "macos"=>{
1254 "include"=>{
1255 "/Library"=>1,
1256 "/Developer/usr/include"=>1
1257 },
1258 "lib"=>{
1259 "/Library"=>1,
1260 "/Developer/usr/lib"=>1
1261 },
1262 "bin"=>{
1263 "/Developer/usr/bin"=>1
1264 }
1265 },
1266 "beos"=>{
1267 # Haiku has GCC 2.95.3 by default
1268 # try to find GCC>=3.0 in /boot/develop/abi
1269 "include"=>{
1270 "/boot/common"=>1,
1271 "/boot/develop"=>1},
1272 "lib"=>{
1273 "/boot/common/lib"=>1,
1274 "/boot/system/lib"=>1,
1275 "/boot/apps"=>1},
1276 "bin"=>{
1277 "/boot/common/bin"=>1,
1278 "/boot/system/bin"=>1,
1279 "/boot/develop/abi"=>1
1280 }
1281}
1282);
1283
1284my %Slash_Type=(
1285 "default"=>"/",
1286 "windows"=>"\\"
1287);
1288
1289my $SLASH = $Slash_Type{$OSgroup}?$Slash_Type{$OSgroup}:$Slash_Type{"default"};
1290
1291# Global Variables
1292my %COMMON_LANGUAGE=(
1293 1 => "C",
1294 2 => "C" );
1295
1296my $MAX_COMMAND_LINE_ARGUMENTS = 4096;
Andrey Ponomarenko9927e332012-10-19 10:50:48 +04001297my $MAX_CPPFILT_FILE_SIZE = 50000;
1298my $CPPFILT_SUPPORT_FILE;
1299
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04001300my (%WORD_SIZE, %CPU_ARCH, %GCC_VERSION);
1301
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04001302my $STDCXX_TESTING = 0;
1303my $GLIBC_TESTING = 0;
1304
1305my $CheckHeadersOnly = $CheckHeadersOnly_Opt;
1306my $CheckObjectsOnly = $CheckObjectsOnly_Opt;
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04001307my $TargetComponent;
1308
1309# Set Target Component Name
1310if($TargetComponent_Opt) {
1311 $TargetComponent = lc($TargetComponent_Opt);
1312}
1313else
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04001314{ # default: library
1315 # other components: header, system, ...
1316 $TargetComponent = "library";
1317}
1318
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04001319my $TOP_REF = "<a style='font-size:11px;' href='#Top'>to the top</a>";
1320
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04001321my $SystemRoot;
1322
1323my $MAIN_CPP_DIR;
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04001324my %RESULT;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04001325my %LOG_PATH;
1326my %DEBUG_PATH;
1327my %Cache;
1328my %LibInfo;
1329my $COMPILE_ERRORS = 0;
1330my %CompilerOptions;
1331my %CheckedDyLib;
1332my $TargetLibraryShortName = parse_libname($TargetLibraryName, "shortest", $OSgroup);
1333
1334# Constants (#defines)
1335my %Constants;
1336my %SkipConstants;
Andrey Ponomarenko82bc2572012-11-14 13:55:30 +04001337my %EnumConstants;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04001338
1339# Types
1340my %TypeInfo;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04001341my %TemplateInstance;
Andrey Ponomarenko85043792012-05-14 16:48:07 +04001342my %TemplateDecl;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04001343my %SkipTypes = (
1344 "1"=>{},
1345 "2"=>{} );
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04001346my %CheckedTypes;
1347my %TName_Tid;
1348my %EnumMembName_Id;
1349my %NestedNameSpaces = (
1350 "1"=>{},
1351 "2"=>{} );
1352my %UsedType;
1353my %VirtualTable;
Andrey Ponomarenko16934472012-03-29 15:37:04 +04001354my %VirtualTable_Model;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04001355my %ClassVTable;
1356my %ClassVTable_Content;
1357my %VTableClass;
1358my %AllocableClass;
1359my %ClassMethods;
Andrey Ponomarenko16934472012-03-29 15:37:04 +04001360my %ClassNames;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04001361my %Class_SubClasses;
1362my %OverriddenMethods;
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04001363my $MAX_ID = 0;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04001364
1365# Typedefs
1366my %Typedef_BaseName;
1367my %Typedef_Tr;
1368my %Typedef_Eq;
1369my %StdCxxTypedef;
1370my %MissedTypedef;
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04001371my %MissedBase;
1372my %MissedBase_R;
Andrey Ponomarenko9927e332012-10-19 10:50:48 +04001373my %TypeTypedef;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04001374
1375# Symbols
1376my %SymbolInfo;
1377my %tr_name;
1378my %mangled_name_gcc;
1379my %mangled_name;
1380my %SkipSymbols = (
1381 "1"=>{},
1382 "2"=>{} );
1383my %SkipNameSpaces = (
1384 "1"=>{},
1385 "2"=>{} );
Andrey Ponomarenkoa01311b2012-06-08 17:20:02 +04001386my %AddNameSpaces = (
1387 "1"=>{},
1388 "2"=>{} );
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04001389my %SymbolsList;
1390my %SymbolsList_App;
1391my %CheckedSymbols;
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04001392my %Symbol_Library = (
1393 "1"=>{},
1394 "2"=>{} );
1395my %Library_Symbol = (
1396 "1"=>{},
1397 "2"=>{} );
1398my %DepSymbol_Library = (
1399 "1"=>{},
1400 "2"=>{} );
1401my %DepLibrary_Symbol = (
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04001402 "1"=>{},
1403 "2"=>{} );
1404my %MangledNames;
Andrey Ponomarenko9927e332012-10-19 10:50:48 +04001405my %Func_ShortName;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04001406my %AddIntParams;
1407my %Interface_Impl;
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04001408my %GlobalDataObject;
Andrey Ponomarenko07aea072012-11-12 16:15:07 +04001409my %WeakSymbols;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04001410
1411# Headers
1412my %Include_Preamble;
1413my %Registered_Headers;
1414my %HeaderName_Paths;
1415my %Header_Dependency;
1416my %Include_Neighbors;
1417my %Include_Paths;
1418my %INC_PATH_AUTODETECT = (
1419 "1"=>1,
1420 "2"=>1 );
1421my %Add_Include_Paths;
1422my %Skip_Include_Paths;
1423my %RegisteredDirs;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04001424my %Header_ErrorRedirect;
1425my %Header_Includes;
1426my %Header_ShouldNotBeUsed;
1427my %RecursiveIncludes;
1428my %Header_Include_Prefix;
1429my %SkipHeaders;
1430my %SkipHeadersList=(
1431 "1"=>{},
1432 "2"=>{} );
1433my %SkipLibs;
1434my %Include_Order;
1435my %TUnit_NameSpaces;
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +04001436my %TUnit_Classes;
Andrey Ponomarenko9927e332012-10-19 10:50:48 +04001437my %TUnit_Funcs;
1438my %TUnit_Vars;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04001439
Andrey Ponomarenko07aea072012-11-12 16:15:07 +04001440my %CppMode = (
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04001441 "1"=>0,
1442 "2"=>0 );
1443my %AutoPreambleMode = (
1444 "1"=>0,
1445 "2"=>0 );
1446my %MinGWMode = (
1447 "1"=>0,
1448 "2"=>0 );
Andrey Ponomarenko01117f12012-06-26 12:23:02 +04001449my %Cpp0xMode = (
1450 "1"=>0,
1451 "2"=>0 );
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04001452
1453# Shared Objects
Andrey Ponomarenko9927e332012-10-19 10:50:48 +04001454my %RegisteredObjects;
Andrey Ponomarenko07aea072012-11-12 16:15:07 +04001455my %RegisteredObjects_Short;
Andrey Ponomarenko9927e332012-10-19 10:50:48 +04001456my %RegisteredSONAMEs;
1457my %RegisteredObject_Dirs;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04001458
1459# System Objects
1460my %SystemObjects;
1461my %DefaultLibPaths;
Andrey Ponomarenko9927e332012-10-19 10:50:48 +04001462my %DyLib_DefaultPath;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04001463
1464# System Headers
1465my %SystemHeaders;
1466my %DefaultCppPaths;
1467my %DefaultGccPaths;
1468my %DefaultIncPaths;
1469my %DefaultCppHeader;
1470my %DefaultGccHeader;
1471my %UserIncPath;
1472
1473# Merging
1474my %CompleteSignature;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04001475my $Version;
1476my %AddedInt;
1477my %RemovedInt;
1478my %AddedInt_Virt;
1479my %RemovedInt_Virt;
1480my %VirtualReplacement;
1481my %ChangedTypedef;
1482my %CompatRules;
1483my %IncompleteRules;
1484my %UnknownRules;
Andrey Ponomarenko16934472012-03-29 15:37:04 +04001485my %VTableChanged_M;
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04001486my %ExtendedSymbols;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04001487my %ReturnedClass;
1488my %ParamClass;
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04001489my %SourceAlternative;
1490my %SourceAlternative_B;
1491my %SourceReplacement;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04001492
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +04001493# Calling Conventions
1494my %UseConv_Real = (
1495 "1"=>0,
1496 "2"=>0 );
1497
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04001498# OS Compliance
1499my %TargetLibs;
1500my %TargetHeaders;
1501
1502# OS Specifics
1503my $OStarget = $OSgroup;
1504my %TargetTools;
1505
1506# Compliance Report
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04001507my %Type_MaxSeverity;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04001508
1509# Recursion locks
1510my @RecurLib;
1511my @RecurSymlink;
1512my @RecurTypes;
1513my @RecurInclude;
1514my @RecurConstant;
1515
1516# System
1517my %SystemPaths;
1518my %DefaultBinPaths;
1519my $GCC_PATH;
1520
1521# Symbols versioning
1522my %SymVer = (
1523 "1"=>{},
1524 "2"=>{} );
1525
1526# Problem descriptions
1527my %CompatProblems;
1528my %ProblemsWithConstants;
1529my %ImplProblems;
1530my %TotalAffected;
1531
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04001532# Reports
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04001533my $ContentID = 1;
1534my $ContentSpanStart = "<span class=\"section\" onclick=\"javascript:showContent(this, 'CONTENT_ID')\">\n";
1535my $ContentSpanStart_Affected = "<span class=\"section_affected\" onclick=\"javascript:showContent(this, 'CONTENT_ID')\">\n";
1536my $ContentSpanStart_Info = "<span class=\"section_info\" onclick=\"javascript:showContent(this, 'CONTENT_ID')\">\n";
1537my $ContentSpanEnd = "</span>\n";
1538my $ContentDivStart = "<div id=\"CONTENT_ID\" style=\"display:none;\">\n";
1539my $ContentDivEnd = "</div>\n";
1540my $Content_Counter = 0;
1541
Andrey Ponomarenko5c09ef32012-06-14 18:17:33 +04001542# XML Dump
1543my $TAG_ID = 0;
1544my $INDENT = " ";
1545
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04001546# Modes
1547my $JoinReport = 1;
1548my $DoubleReport = 0;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04001549
1550sub get_Modules()
1551{
1552 my $TOOL_DIR = get_dirname($0);
1553 if(not $TOOL_DIR)
1554 { # patch for MS Windows
1555 $TOOL_DIR = ".";
1556 }
1557 my @SEARCH_DIRS = (
1558 # tool's directory
1559 abs_path($TOOL_DIR),
1560 # relative path to modules
1561 abs_path($TOOL_DIR)."/../share/abi-compliance-checker",
1562 # system directory
1563 "ACC_MODULES_INSTALL_PATH"
1564 );
1565 foreach my $DIR (@SEARCH_DIRS)
1566 {
1567 if(not is_abs($DIR))
1568 { # relative path
1569 $DIR = abs_path($TOOL_DIR)."/".$DIR;
1570 }
1571 if(-d $DIR."/modules") {
1572 return $DIR."/modules";
1573 }
1574 }
1575 exitStatus("Module_Error", "can't find modules");
1576}
1577
Andrey Ponomarenko01117f12012-06-26 12:23:02 +04001578my %LoadedModules = ();
1579
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04001580sub loadModule($)
1581{
1582 my $Name = $_[0];
Andrey Ponomarenko01117f12012-06-26 12:23:02 +04001583 if(defined $LoadedModules{$Name}) {
1584 return;
1585 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04001586 my $Path = $MODULES_DIR."/Internals/$Name.pm";
1587 if(not -f $Path) {
1588 exitStatus("Module_Error", "can't access \'$Path\'");
1589 }
1590 require $Path;
Andrey Ponomarenko01117f12012-06-26 12:23:02 +04001591 $LoadedModules{$Name} = 1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04001592}
1593
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04001594sub showPos($)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04001595{
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04001596 my $Number = $_[0];
1597 if(not $Number) {
1598 $Number = 1;
1599 }
1600 else {
1601 $Number = int($Number)+1;
1602 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04001603 if($Number>3) {
1604 return $Number."th";
1605 }
1606 elsif($Number==1) {
1607 return "1st";
1608 }
1609 elsif($Number==2) {
1610 return "2nd";
1611 }
1612 elsif($Number==3) {
1613 return "3rd";
1614 }
1615 else {
1616 return $Number;
1617 }
1618}
1619
1620sub search_Tools($)
1621{
1622 my $Name = $_[0];
1623 return "" if(not $Name);
1624 if(my @Paths = keys(%TargetTools))
1625 {
1626 foreach my $Path (@Paths)
1627 {
1628 if(-f joinPath($Path, $Name)) {
1629 return joinPath($Path, $Name);
1630 }
1631 if($CrossPrefix)
1632 { # user-defined prefix (arm-none-symbianelf, ...)
1633 my $Candidate = joinPath($Path, $CrossPrefix."-".$Name);
1634 if(-f $Candidate) {
1635 return $Candidate;
1636 }
1637 }
1638 }
1639 }
1640 else {
1641 return "";
1642 }
1643}
1644
1645sub synch_Cmd($)
1646{
1647 my $Name = $_[0];
1648 if(not $GCC_PATH)
1649 { # GCC was not found yet
1650 return "";
1651 }
1652 my $Candidate = $GCC_PATH;
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04001653 if($Candidate=~s/\bgcc(|\.\w+)\Z/$Name$1/) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04001654 return $Candidate;
1655 }
1656 return "";
1657}
1658
1659sub get_CmdPath($)
1660{
1661 my $Name = $_[0];
1662 return "" if(not $Name);
1663 if(defined $Cache{"get_CmdPath"}{$Name}) {
1664 return $Cache{"get_CmdPath"}{$Name};
1665 }
1666 my %BinUtils = map {$_=>1} (
1667 "c++filt",
1668 "objdump",
1669 "readelf"
1670 );
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04001671 if($BinUtils{$Name} and $GCC_PATH)
1672 {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04001673 if(my $Dir = get_dirname($GCC_PATH)) {
1674 $TargetTools{$Dir}=1;
1675 }
1676 }
1677 my $Path = search_Tools($Name);
1678 if(not $Path and $OSgroup eq "windows") {
1679 $Path = search_Tools($Name.".exe");
1680 }
1681 if(not $Path and $BinUtils{$Name})
1682 {
1683 if($CrossPrefix)
1684 { # user-defined prefix
1685 $Path = search_Cmd($CrossPrefix."-".$Name);
1686 }
1687 }
1688 if(not $Path and $BinUtils{$Name})
1689 {
1690 if(my $Candidate = synch_Cmd($Name))
1691 { # synch with GCC
1692 if($Candidate=~/[\/\\]/)
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04001693 { # command path
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04001694 if(-f $Candidate) {
1695 $Path = $Candidate;
1696 }
1697 }
1698 elsif($Candidate = search_Cmd($Candidate))
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04001699 { # command name
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04001700 $Path = $Candidate;
1701 }
1702 }
1703 }
1704 if(not $Path) {
1705 $Path = search_Cmd($Name);
1706 }
1707 if(not $Path and $OSgroup eq "windows")
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04001708 { # search for *.exe file
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04001709 $Path=search_Cmd($Name.".exe");
1710 }
1711 if($Path=~/\s/) {
1712 $Path = "\"".$Path."\"";
1713 }
1714 return ($Cache{"get_CmdPath"}{$Name}=$Path);
1715}
1716
1717sub search_Cmd($)
1718{
1719 my $Name = $_[0];
1720 return "" if(not $Name);
1721 if(defined $Cache{"search_Cmd"}{$Name}) {
1722 return $Cache{"search_Cmd"}{$Name};
1723 }
1724 if(my $DefaultPath = get_CmdPath_Default($Name)) {
1725 return ($Cache{"search_Cmd"}{$Name} = $DefaultPath);
1726 }
1727 foreach my $Path (sort {length($a)<=>length($b)} keys(%{$SystemPaths{"bin"}}))
1728 {
1729 my $CmdPath = joinPath($Path,$Name);
1730 if(-f $CmdPath)
1731 {
1732 if($Name=~/gcc/) {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04001733 next if(not check_gcc($CmdPath, "3"));
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04001734 }
1735 return ($Cache{"search_Cmd"}{$Name} = $CmdPath);
1736 }
1737 }
1738 return ($Cache{"search_Cmd"}{$Name} = "");
1739}
1740
1741sub get_CmdPath_Default($)
1742{ # search in PATH
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04001743 return "" if(not $_[0]);
1744 if(defined $Cache{"get_CmdPath_Default"}{$_[0]}) {
1745 return $Cache{"get_CmdPath_Default"}{$_[0]};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04001746 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04001747 return ($Cache{"get_CmdPath_Default"}{$_[0]} = get_CmdPath_Default_I($_[0]));
1748}
1749
1750sub get_CmdPath_Default_I($)
1751{ # search in PATH
1752 my $Name = $_[0];
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04001753 if($Name=~/find/)
1754 { # special case: search for "find" utility
Andrey Ponomarenkoa01311b2012-06-08 17:20:02 +04001755 if(`find \"$TMP_DIR\" -maxdepth 0 2>\"$TMP_DIR/null\"`) {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04001756 return "find";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04001757 }
1758 }
1759 elsif($Name=~/gcc/) {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04001760 return check_gcc($Name, "3");
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04001761 }
1762 if(check_command($Name)) {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04001763 return $Name;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04001764 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04001765 if($OSgroup eq "windows")
1766 {
Andrey Ponomarenkoa01311b2012-06-08 17:20:02 +04001767 if(`$Name /? 2>\"$TMP_DIR/null\"`) {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04001768 return $Name;
1769 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04001770 }
1771 if($Name!~/which/)
1772 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04001773 if(my $WhichCmd = get_CmdPath("which"))
1774 {
Andrey Ponomarenkoa01311b2012-06-08 17:20:02 +04001775 if(`$WhichCmd $Name 2>\"$TMP_DIR/null\"`) {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04001776 return $Name;
1777 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04001778 }
1779 }
1780 foreach my $Path (sort {length($a)<=>length($b)} keys(%DefaultBinPaths))
1781 {
1782 if(-f $Path."/".$Name) {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04001783 return joinPath($Path,$Name);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04001784 }
1785 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04001786 return "";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04001787}
1788
1789sub clean_path($)
1790{
1791 my $Path = $_[0];
1792 $Path=~s/[\/\\]+\Z//g;
1793 return $Path;
1794}
1795
1796sub classifyPath($)
1797{
1798 my $Path = $_[0];
1799 if($Path=~/[\*\[]/)
1800 { # wildcard
1801 $Path=~s/\*/.*/g;
1802 $Path=~s/\\/\\\\/g;
1803 return ($Path, "Pattern");
1804 }
1805 elsif($Path=~/[\/\\]/)
1806 { # directory or relative path
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04001807 $Path=~s/[\/\\]+\Z//g;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04001808 return (path_format($Path, $OSgroup), "Path");
1809 }
1810 else {
1811 return ($Path, "Name");
1812 }
1813}
1814
1815sub readDescriptor($$)
1816{
1817 my ($LibVersion, $Content) = @_;
1818 return if(not $LibVersion);
1819 my $DName = $DumpAPI?"descriptor":"descriptor \"d$LibVersion\"";
1820 if(not $Content) {
1821 exitStatus("Error", "$DName is empty");
1822 }
1823 if($Content!~/\</) {
Andrey Ponomarenko5c09ef32012-06-14 18:17:33 +04001824 exitStatus("Error", "incorrect descriptor (see -d1 option)");
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04001825 }
1826 $Content=~s/\/\*(.|\n)+?\*\///g;
1827 $Content=~s/<\!--(.|\n)+?-->//g;
1828 $Descriptor{$LibVersion}{"Version"} = parseTag(\$Content, "version");
1829 if($TargetVersion{$LibVersion}) {
1830 $Descriptor{$LibVersion}{"Version"} = $TargetVersion{$LibVersion};
1831 }
1832 if(not $Descriptor{$LibVersion}{"Version"}) {
1833 exitStatus("Error", "version in the $DName is not specified (<version> section)");
1834 }
1835 if($Content=~/{RELPATH}/)
1836 {
1837 if(my $RelDir = $RelativeDirectory{$LibVersion}) {
1838 $Content =~ s/{RELPATH}/$RelDir/g;
1839 }
1840 else
1841 {
1842 my $NeedRelpath = $DumpAPI?"-relpath":"-relpath$LibVersion";
1843 exitStatus("Error", "you have not specified $NeedRelpath option, but the $DName contains {RELPATH} macro");
1844 }
1845 }
1846
1847 if(not $CheckObjectsOnly_Opt)
1848 {
1849 my $DHeaders = parseTag(\$Content, "headers");
1850 if(not $DHeaders) {
1851 exitStatus("Error", "header files in the $DName are not specified (<headers> section)");
1852 }
1853 elsif(lc($DHeaders) ne "none")
1854 { # append the descriptor headers list
1855 if($Descriptor{$LibVersion}{"Headers"})
1856 { # multiple descriptors
1857 $Descriptor{$LibVersion}{"Headers"} .= "\n".$DHeaders;
1858 }
1859 else {
1860 $Descriptor{$LibVersion}{"Headers"} = $DHeaders;
1861 }
1862 foreach my $Path (split(/\s*\n\s*/, $DHeaders))
1863 {
1864 if(not -e $Path) {
1865 exitStatus("Access_Error", "can't access \'$Path\'");
1866 }
1867 }
1868 }
1869 }
1870 if(not $CheckHeadersOnly_Opt)
1871 {
1872 my $DObjects = parseTag(\$Content, "libs");
1873 if(not $DObjects) {
1874 exitStatus("Error", "$SLIB_TYPE libraries in the $DName are not specified (<libs> section)");
1875 }
1876 elsif(lc($DObjects) ne "none")
1877 { # append the descriptor libraries list
1878 if($Descriptor{$LibVersion}{"Libs"})
1879 { # multiple descriptors
1880 $Descriptor{$LibVersion}{"Libs"} .= "\n".$DObjects;
1881 }
1882 else {
1883 $Descriptor{$LibVersion}{"Libs"} .= $DObjects;
1884 }
1885 foreach my $Path (split(/\s*\n\s*/, $DObjects))
1886 {
1887 if(not -e $Path) {
1888 exitStatus("Access_Error", "can't access \'$Path\'");
1889 }
1890 }
1891 }
1892 }
1893 foreach my $Path (split(/\s*\n\s*/, parseTag(\$Content, "search_headers")))
1894 {
1895 $Path = clean_path($Path);
1896 if(not -d $Path) {
1897 exitStatus("Access_Error", "can't access directory \'$Path\'");
1898 }
1899 $Path = path_format($Path, $OSgroup);
1900 $SystemPaths{"include"}{$Path}=1;
1901 }
1902 foreach my $Path (split(/\s*\n\s*/, parseTag(\$Content, "search_libs")))
1903 {
1904 $Path = clean_path($Path);
1905 if(not -d $Path) {
1906 exitStatus("Access_Error", "can't access directory \'$Path\'");
1907 }
1908 $Path = path_format($Path, $OSgroup);
1909 $SystemPaths{"lib"}{$Path}=1;
1910 }
1911 foreach my $Path (split(/\s*\n\s*/, parseTag(\$Content, "tools")))
1912 {
1913 $Path=clean_path($Path);
1914 if(not -d $Path) {
1915 exitStatus("Access_Error", "can't access directory \'$Path\'");
1916 }
1917 $Path = path_format($Path, $OSgroup);
1918 $SystemPaths{"bin"}{$Path}=1;
1919 $TargetTools{$Path}=1;
1920 }
1921 if(my $Prefix = parseTag(\$Content, "cross_prefix")) {
1922 $CrossPrefix = $Prefix;
1923 }
1924 foreach my $Path (split(/\s*\n\s*/, parseTag(\$Content, "include_paths")))
1925 {
1926 $Path=clean_path($Path);
1927 if(not -d $Path) {
1928 exitStatus("Access_Error", "can't access directory \'$Path\'");
1929 }
1930 $Path = path_format($Path, $OSgroup);
1931 $Descriptor{$LibVersion}{"IncludePaths"}{$Path} = 1;
1932 }
1933 foreach my $Path (split(/\s*\n\s*/, parseTag(\$Content, "add_include_paths")))
1934 {
1935 $Path=clean_path($Path);
1936 if(not -d $Path) {
1937 exitStatus("Access_Error", "can't access directory \'$Path\'");
1938 }
1939 $Path = path_format($Path, $OSgroup);
1940 $Descriptor{$LibVersion}{"AddIncludePaths"}{$Path} = 1;
1941 }
1942 foreach my $Path (split(/\s*\n\s*/, parseTag(\$Content, "skip_include_paths")))
1943 {
1944 # skip some auto-generated include paths
1945 $Skip_Include_Paths{$LibVersion}{path_format($Path)}=1;
1946 }
1947 foreach my $Path (split(/\s*\n\s*/, parseTag(\$Content, "skip_including")))
1948 {
1949 # skip direct including of some headers
1950 my ($CPath, $Type) = classifyPath($Path);
1951 $SkipHeaders{$LibVersion}{$Type}{$CPath} = 2;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04001952 }
1953 $Descriptor{$LibVersion}{"GccOptions"} = parseTag(\$Content, "gcc_options");
1954 foreach my $Option (split(/\s*\n\s*/, $Descriptor{$LibVersion}{"GccOptions"})) {
1955 $CompilerOptions{$LibVersion} .= " ".$Option;
1956 }
1957 $Descriptor{$LibVersion}{"SkipHeaders"} = parseTag(\$Content, "skip_headers");
1958 foreach my $Path (split(/\s*\n\s*/, $Descriptor{$LibVersion}{"SkipHeaders"}))
1959 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04001960 $SkipHeadersList{$LibVersion}{$Path} = 1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04001961 my ($CPath, $Type) = classifyPath($Path);
1962 $SkipHeaders{$LibVersion}{$Type}{$CPath} = 1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04001963 }
1964 $Descriptor{$LibVersion}{"SkipLibs"} = parseTag(\$Content, "skip_libs");
1965 foreach my $Path (split(/\s*\n\s*/, $Descriptor{$LibVersion}{"SkipLibs"}))
1966 {
1967 my ($CPath, $Type) = classifyPath($Path);
1968 $SkipLibs{$LibVersion}{$Type}{$CPath} = 1;
1969 }
1970 if(my $DDefines = parseTag(\$Content, "defines"))
1971 {
1972 if($Descriptor{$LibVersion}{"Defines"})
1973 { # multiple descriptors
1974 $Descriptor{$LibVersion}{"Defines"} .= "\n".$DDefines;
1975 }
1976 else {
1977 $Descriptor{$LibVersion}{"Defines"} = $DDefines;
1978 }
1979 }
1980 foreach my $Order (split(/\s*\n\s*/, parseTag(\$Content, "include_order")))
1981 {
1982 if($Order=~/\A(.+):(.+)\Z/) {
1983 $Include_Order{$LibVersion}{$1} = $2;
1984 }
1985 }
1986 foreach my $Type_Name (split(/\s*\n\s*/, parseTag(\$Content, "opaque_types")),
1987 split(/\s*\n\s*/, parseTag(\$Content, "skip_types")))
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04001988 { # opaque_types renamed to skip_types (1.23.4)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04001989 $SkipTypes{$LibVersion}{$Type_Name} = 1;
1990 }
1991 foreach my $Symbol (split(/\s*\n\s*/, parseTag(\$Content, "skip_interfaces")),
1992 split(/\s*\n\s*/, parseTag(\$Content, "skip_symbols")))
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04001993 { # skip_interfaces renamed to skip_symbols (1.22.1)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04001994 $SkipSymbols{$LibVersion}{$Symbol} = 1;
1995 }
1996 foreach my $NameSpace (split(/\s*\n\s*/, parseTag(\$Content, "skip_namespaces"))) {
1997 $SkipNameSpaces{$LibVersion}{$NameSpace} = 1;
1998 }
Andrey Ponomarenkoa01311b2012-06-08 17:20:02 +04001999 foreach my $NameSpace (split(/\s*\n\s*/, parseTag(\$Content, "add_namespaces"))) {
2000 $AddNameSpaces{$LibVersion}{$NameSpace} = 1;
2001 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002002 foreach my $Constant (split(/\s*\n\s*/, parseTag(\$Content, "skip_constants"))) {
2003 $SkipConstants{$LibVersion}{$Constant} = 1;
2004 }
2005 if(my $DIncPreamble = parseTag(\$Content, "include_preamble"))
2006 {
2007 if($Descriptor{$LibVersion}{"IncludePreamble"})
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04002008 { # multiple descriptors
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002009 $Descriptor{$LibVersion}{"IncludePreamble"} .= "\n".$DIncPreamble;
2010 }
2011 else {
2012 $Descriptor{$LibVersion}{"IncludePreamble"} = $DIncPreamble;
2013 }
2014 }
2015}
2016
Andrey Ponomarenko01117f12012-06-26 12:23:02 +04002017sub parseTag(@)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002018{
Andrey Ponomarenko01117f12012-06-26 12:23:02 +04002019 my $CodeRef = shift(@_);
2020 my $Tag = shift(@_);
2021 if(not $Tag or not $CodeRef) {
2022 return undef;
2023 }
2024 my $Sp = 0;
2025 if(@_) {
2026 $Sp = shift(@_);
2027 }
2028 my $Start = index(${$CodeRef}, "<$Tag>");
2029 if($Start!=-1)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002030 {
Andrey Ponomarenko01117f12012-06-26 12:23:02 +04002031 my $End = index(${$CodeRef}, "</$Tag>");
2032 if($End!=-1)
2033 {
2034 my $TS = length($Tag)+3;
2035 my $Content = substr(${$CodeRef}, $Start, $End-$Start+$TS, "");
2036 substr($Content, 0, $TS-1, ""); # cut start tag
2037 substr($Content, -$TS, $TS, ""); # cut end tag
2038 if(not $Sp)
2039 {
2040 $Content=~s/\A\s+//g;
2041 $Content=~s/\s+\Z//g;
2042 }
2043 if(substr($Content, 0, 1) ne "<") {
2044 $Content = xmlSpecChars_R($Content);
2045 }
2046 return $Content;
2047 }
2048 }
2049 return undef;
2050}
2051
2052sub parseTag_E($$$)
2053{
2054 my ($CodeRef, $Tag, $Info) = @_;
2055 if(not $Tag or not $CodeRef
2056 or not $Info) {
2057 return undef;
2058 }
2059 if(${$CodeRef}=~s/\<\Q$Tag\E(\s+([^<>]+)|)\>((.|\n)*?)\<\/\Q$Tag\E\>//)
2060 {
2061 my ($Ext, $Content) = ($2, $3);
2062 $Content=~s/\A\s+//g;
2063 $Content=~s/\s+\Z//g;
2064 if($Ext)
2065 {
2066 while($Ext=~s/(\w+)\=\"([^\"]*)\"//)
2067 {
2068 my ($K, $V) = ($1, $2);
2069 $Info->{$K} = xmlSpecChars_R($V);
2070 }
2071 }
2072 if(substr($Content, 0, 1) ne "<") {
2073 $Content = xmlSpecChars_R($Content);
2074 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002075 return $Content;
2076 }
Andrey Ponomarenko01117f12012-06-26 12:23:02 +04002077 return undef;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002078}
2079
Andrey Ponomarenko35c44fd2012-06-18 17:50:25 +04002080sub addTag(@)
Andrey Ponomarenko5c09ef32012-06-14 18:17:33 +04002081{
Andrey Ponomarenko35c44fd2012-06-18 17:50:25 +04002082 my $Tag = shift(@_);
2083 my $Val = shift(@_);
2084 my @Ext = @_;
2085 my $Content = openTag($Tag, @Ext);
2086 chomp($Content);
Andrey Ponomarenko5c09ef32012-06-14 18:17:33 +04002087 $Content .= xmlSpecChars($Val);
2088 $Content .= "</$Tag>\n";
Andrey Ponomarenko35c44fd2012-06-18 17:50:25 +04002089 $TAG_ID-=1;
Andrey Ponomarenko5c09ef32012-06-14 18:17:33 +04002090
2091 return $Content;
2092}
2093
Andrey Ponomarenko35c44fd2012-06-18 17:50:25 +04002094sub openTag(@)
Andrey Ponomarenko5c09ef32012-06-14 18:17:33 +04002095{
2096 my $Tag = shift(@_);
2097 my @Ext = @_;
2098 my $Content = "";
2099 foreach (1 .. $TAG_ID) {
2100 $Content .= $INDENT;
2101 }
2102 $TAG_ID+=1;
Andrey Ponomarenko35c44fd2012-06-18 17:50:25 +04002103 if(@Ext)
Andrey Ponomarenko5c09ef32012-06-14 18:17:33 +04002104 {
Andrey Ponomarenko35c44fd2012-06-18 17:50:25 +04002105 $Content .= "<".$Tag;
2106 my $P = 0;
2107 while($P<=$#Ext-1)
2108 {
2109 $Content .= " ".$Ext[$P];
2110 $Content .= "=\"".xmlSpecChars($Ext[$P+1])."\"";
2111 $P+=2;
2112 }
2113 $Content .= ">\n";
Andrey Ponomarenko5c09ef32012-06-14 18:17:33 +04002114 }
Andrey Ponomarenko35c44fd2012-06-18 17:50:25 +04002115 else {
2116 $Content .= "<".$Tag.">\n";
2117 }
Andrey Ponomarenko5c09ef32012-06-14 18:17:33 +04002118 return $Content;
2119}
2120
2121sub closeTag($)
2122{
2123 my $Tag = $_[0];
2124 my $Content = "";
2125 $TAG_ID-=1;
2126 foreach (1 .. $TAG_ID) {
2127 $Content .= $INDENT;
2128 }
2129 $Content .= "</".$Tag.">\n";
2130 return $Content;
2131}
2132
2133sub checkTags()
2134{
2135 if($TAG_ID!=0) {
2136 printMsg("WARNING", "the number of opened tags is not equal to number of closed tags");
2137 }
2138}
2139
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002140sub getInfo($)
2141{
Andrey Ponomarenko85043792012-05-14 16:48:07 +04002142 my $DumpPath = $_[0];
2143 return if(not $DumpPath or not -f $DumpPath);
2144
2145 readTUDump($DumpPath);
2146
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002147 # processing info
2148 setTemplateParams_All();
2149 getTypeInfo_All();
2150 simplifyNames();
Andrey Ponomarenko82bc2572012-11-14 13:55:30 +04002151 simplifyConstants();
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002152 getVarInfo_All();
Andrey Ponomarenko01117f12012-06-26 12:23:02 +04002153 getSymbolInfo_All();
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002154
Andrey Ponomarenko82bc2572012-11-14 13:55:30 +04002155
Andrey Ponomarenko85043792012-05-14 16:48:07 +04002156 # clean memory
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002157 %LibInfo = ();
2158 %TemplateInstance = ();
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002159 %MangledNames = ();
Andrey Ponomarenko85043792012-05-14 16:48:07 +04002160 %TemplateDecl = ();
2161 %StdCxxTypedef = ();
2162 %MissedTypedef = ();
2163 %Typedef_Tr = ();
2164 %Typedef_Eq = ();
2165
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04002166 # clean cache
2167 delete($Cache{"getTypeAttr"});
2168 delete($Cache{"getTypeDeclId"});
2169
2170 # remove unused types
2171 if($BinaryOnly and not $ExtendedCheck)
2172 { # --binary
2173 removeUnused($Version, "All");
2174 }
2175 else {
2176 removeUnused($Version, "Derived");
2177 }
2178
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002179 if($Debug) {
2180 # debugMangling($Version);
2181 }
2182}
2183
Andrey Ponomarenko85043792012-05-14 16:48:07 +04002184sub readTUDump($)
2185{
2186 my $DumpPath = $_[0];
2187
2188 open(TU_DUMP, $DumpPath);
2189 local $/ = undef;
2190 my $Content = <TU_DUMP>;
2191 close(TU_DUMP);
2192
2193 unlink($DumpPath);
2194
2195 $Content=~s/\n[ ]+/ /g;
2196 my @Lines = split("\n", $Content);
2197
2198 # clean memory
2199 undef $Content;
2200
2201 $MAX_ID = $#Lines+1;
2202
2203 foreach (0 .. $#Lines)
2204 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04002205 if($Lines[$_]=~/\A\@(\d+)[ ]+([a-z_]+)[ ]+(.+)\Z/i)
Andrey Ponomarenko85043792012-05-14 16:48:07 +04002206 { # get a number and attributes of a node
2207 next if(not $NodeType{$2});
2208 $LibInfo{$Version}{"info_type"}{$1}=$2;
2209 $LibInfo{$Version}{"info"}{$1}=$3;
2210 }
2211
2212 # clean memory
2213 delete($Lines[$_]);
2214 }
2215
2216 # clean memory
2217 undef @Lines;
2218}
2219
Andrey Ponomarenko82bc2572012-11-14 13:55:30 +04002220sub simplifyConstants()
2221{
2222 foreach my $Constant (keys(%{$Constants{$Version}}))
2223 {
2224 if($Constants{$Version}{$Constant}{"Value"} eq $Constant)
2225 {
2226 if(defined $EnumConstants{$Version}{$Constant}) {
2227 $Constants{$Version}{$Constant}{"Value"} = $EnumConstants{$Version}{$Constant}{"Value"};
2228 }
2229 }
2230 }
2231}
2232
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002233sub simplifyNames()
2234{
2235 foreach my $Base (keys(%{$Typedef_Tr{$Version}}))
2236 {
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +04002237 if($Typedef_Eq{$Version}{$Base}) {
2238 next;
2239 }
2240 my @Translations = sort keys(%{$Typedef_Tr{$Version}{$Base}});
2241 if($#Translations==0)
2242 {
2243 if(length($Translations[0])<=length($Base)) {
2244 $Typedef_Eq{$Version}{$Base} = $Translations[0];
2245 }
2246 }
2247 else
2248 { # select most appropriate
2249 foreach my $Tr (@Translations)
2250 {
2251 if($Base=~/\A\Q$Tr\E/)
2252 {
2253 $Typedef_Eq{$Version}{$Base} = $Tr;
2254 last;
2255 }
2256 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002257 }
2258 }
Andrey Ponomarenkob8d203d2012-05-25 18:11:07 +04002259 foreach my $TypeId (keys(%{$TypeInfo{$Version}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002260 {
Andrey Ponomarenkob8d203d2012-05-25 18:11:07 +04002261 my $TypeName = $TypeInfo{$Version}{$TypeId}{"Name"};
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04002262 if(not $TypeName) {
2263 next;
2264 }
2265 next if(index($TypeName,"<")==-1);# template instances only
2266 if($TypeName=~/>(::\w+)+\Z/)
2267 { # skip unused types
2268 next;
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +04002269 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04002270 foreach my $Base (sort {length($b)<=>length($a)}
2271 sort {$b cmp $a} keys(%{$Typedef_Eq{$Version}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002272 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04002273 next if(not $Base);
2274 next if(index($TypeName,$Base)==-1);
2275 next if(length($TypeName) - length($Base) <= 3);
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +04002276 if(my $Typedef = $Typedef_Eq{$Version}{$Base})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002277 {
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +04002278 $TypeName=~s/(\<|\,)\Q$Base\E(\W|\Z)/$1$Typedef$2/g;
2279 $TypeName=~s/(\<|\,)\Q$Base\E(\w|\Z)/$1$Typedef $2/g;
2280 if(defined $TypeInfo{$Version}{$TypeId}{"TParam"})
Andrey Ponomarenko85043792012-05-14 16:48:07 +04002281 {
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +04002282 foreach my $TPos (keys(%{$TypeInfo{$Version}{$TypeId}{"TParam"}}))
2283 {
2284 if(my $TPName = $TypeInfo{$Version}{$TypeId}{"TParam"}{$TPos}{"name"})
2285 {
2286 $TPName=~s/\A\Q$Base\E(\W|\Z)/$Typedef$1/g;
2287 $TPName=~s/\A\Q$Base\E(\w|\Z)/$Typedef $1/g;
Andrey Ponomarenko9927e332012-10-19 10:50:48 +04002288 $TypeInfo{$Version}{$TypeId}{"TParam"}{$TPos}{"name"} = formatName($TPName, "T");
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +04002289 }
2290 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +04002291 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002292 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002293 }
Andrey Ponomarenko9927e332012-10-19 10:50:48 +04002294 $TypeName = formatName($TypeName, "T");
Andrey Ponomarenkob8d203d2012-05-25 18:11:07 +04002295 $TypeInfo{$Version}{$TypeId}{"Name"} = $TypeName;
2296 $TName_Tid{$Version}{$TypeName} = $TypeId;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002297 }
2298}
2299
2300sub setTemplateParams_All()
2301{
2302 foreach (keys(%{$LibInfo{$Version}{"info"}}))
2303 {
2304 if($LibInfo{$Version}{"info_type"}{$_} eq "template_decl") {
2305 setTemplateParams($_);
2306 }
2307 }
2308}
2309
2310sub setTemplateParams($)
2311{
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04002312 if(my $Info = $LibInfo{$Version}{"info"}{$_[0]})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002313 {
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04002314 if($Info=~/(inst|spcs)[ ]*:[ ]*@(\d+) /)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002315 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04002316 my $TmplInst_Id = $2;
2317 setTemplateInstParams($TmplInst_Id);
2318 while($TmplInst_Id = getNextElem($TmplInst_Id)) {
2319 setTemplateInstParams($TmplInst_Id);
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04002320 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002321 }
2322 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04002323 if(my $TypeId = getTreeAttr_Type($_[0]))
Andrey Ponomarenko85043792012-05-14 16:48:07 +04002324 {
2325 if(my $IType = $LibInfo{$Version}{"info_type"}{$TypeId})
2326 {
2327 if($IType eq "record_type") {
2328 $TemplateDecl{$Version}{$TypeId}=1;
2329 }
2330 }
2331 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002332}
2333
2334sub setTemplateInstParams($)
2335{
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04002336 if(my $Info = $LibInfo{$Version}{"info"}{$_[0]})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002337 {
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04002338 my ($Params_InfoId, $ElemId) = ();
2339 if($Info=~/purp[ ]*:[ ]*@(\d+) /) {
2340 $Params_InfoId = $1;
2341 }
2342 if($Info=~/valu[ ]*:[ ]*@(\d+) /) {
2343 $ElemId = $1;
2344 }
2345 if($Params_InfoId and $ElemId)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002346 {
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04002347 my $Params_Info = $LibInfo{$Version}{"info"}{$Params_InfoId};
2348 while($Params_Info=~s/ (\d+)[ ]*:[ ]*\@(\d+) / /)
2349 {
2350 my ($PPos, $PTypeId) = ($1, $2);
2351 if(my $PType = $LibInfo{$Version}{"info_type"}{$PTypeId})
2352 {
Andrey Ponomarenko85043792012-05-14 16:48:07 +04002353 if($PType eq "template_type_parm")
2354 {
2355 $TemplateDecl{$Version}{$ElemId}=1;
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04002356 return;
2357 }
2358 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +04002359 if($LibInfo{$Version}{"info_type"}{$ElemId} eq "function_decl")
2360 { # functions
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04002361 $TemplateInstance{$Version}{"Func"}{$ElemId}{$PPos} = $PTypeId;
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04002362 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +04002363 else
2364 { # types
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04002365 $TemplateInstance{$Version}{"Type"}{$ElemId}{$PPos} = $PTypeId;
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04002366 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002367 }
2368 }
2369 }
2370}
2371
2372sub getTypeDeclId($)
2373{
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04002374 if($_[0])
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04002375 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04002376 if(defined $Cache{"getTypeDeclId"}{$Version}{$_[0]}) {
2377 return $Cache{"getTypeDeclId"}{$Version}{$_[0]};
2378 }
2379 if(my $Info = $LibInfo{$Version}{"info"}{$_[0]})
2380 {
2381 if($Info=~/name[ ]*:[ ]*@(\d+)/) {
2382 return ($Cache{"getTypeDeclId"}{$Version}{$_[0]} = $1);
2383 }
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04002384 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002385 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04002386 return ($Cache{"getTypeDeclId"}{$Version}{$_[0]} = 0);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002387}
2388
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002389sub getTypeInfo_All()
2390{
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04002391 if(not check_gcc($GCC_PATH, "4.5"))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002392 { # support for GCC < 4.5
2393 # missed typedefs: QStyle::State is typedef to QFlags<QStyle::StateFlag>
2394 # but QStyleOption.state is of type QFlags<QStyle::StateFlag> in the TU dump
2395 # FIXME: check GCC versions
2396 addMissedTypes_Pre();
2397 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04002398
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002399 foreach (sort {int($a)<=>int($b)} keys(%{$LibInfo{$Version}{"info"}}))
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04002400 { # forward order only
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002401 my $IType = $LibInfo{$Version}{"info_type"}{$_};
2402 if($IType=~/_type\Z/ and $IType ne "function_type"
2403 and $IType ne "method_type") {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04002404 getTypeInfo("$_");
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002405 }
2406 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04002407
2408 # add "..." type
Andrey Ponomarenko01117f12012-06-26 12:23:02 +04002409 $TypeInfo{$Version}{"-1"} = {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04002410 "Name" => "...",
2411 "Type" => "Intrinsic",
Andrey Ponomarenko01117f12012-06-26 12:23:02 +04002412 "Tid" => "-1"
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04002413 };
Andrey Ponomarenko01117f12012-06-26 12:23:02 +04002414 $TName_Tid{$Version}{"..."} = "-1";
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04002415
2416 if(not check_gcc($GCC_PATH, "4.5"))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002417 { # support for GCC < 4.5
2418 addMissedTypes_Post();
2419 }
2420}
2421
2422sub addMissedTypes_Pre()
2423{
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04002424 my %MissedTypes = ();
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002425 foreach my $MissedTDid (sort {int($a)<=>int($b)} keys(%{$LibInfo{$Version}{"info"}}))
2426 { # detecting missed typedefs
2427 if($LibInfo{$Version}{"info_type"}{$MissedTDid} eq "type_decl")
2428 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04002429 my $TypeId = getTreeAttr_Type($MissedTDid);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002430 next if(not $TypeId);
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04002431 my $TypeType = getTypeType($TypeId);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002432 if($TypeType eq "Unknown")
2433 { # template_type_parm
2434 next;
2435 }
2436 my $TypeDeclId = getTypeDeclId($TypeId);
2437 next if($TypeDeclId eq $MissedTDid);#or not $TypeDeclId
2438 my $TypedefName = getNameByInfo($MissedTDid);
2439 next if(not $TypedefName);
2440 next if($TypedefName eq "__float80");
2441 next if(isAnon($TypedefName));
2442 if(not $TypeDeclId
2443 or getNameByInfo($TypeDeclId) ne $TypedefName) {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04002444 $MissedTypes{$Version}{$TypeId}{$MissedTDid} = 1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002445 }
2446 }
2447 }
Andrey Ponomarenkob8d203d2012-05-25 18:11:07 +04002448 my %AddTypes = ();
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04002449 foreach my $Tid (keys(%{$MissedTypes{$Version}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002450 { # add missed typedefs
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04002451 my @Missed = keys(%{$MissedTypes{$Version}{$Tid}});
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002452 if(not @Missed or $#Missed>=1) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002453 next;
2454 }
2455 my $MissedTDid = $Missed[0];
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002456 my ($TypedefName, $TypedefNS) = getTrivialName($MissedTDid, $Tid);
Andrey Ponomarenkob8d203d2012-05-25 18:11:07 +04002457 if(not $TypedefName) {
2458 next;
2459 }
2460 $MAX_ID++;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002461 my %MissedInfo = ( # typedef info
2462 "Name" => $TypedefName,
2463 "NameSpace" => $TypedefNS,
2464 "BaseType" => {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002465 "Tid" => $Tid
2466 },
2467 "Type" => "Typedef",
Andrey Ponomarenkob8d203d2012-05-25 18:11:07 +04002468 "Tid" => "$MAX_ID" );
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002469 my ($H, $L) = getLocation($MissedTDid);
2470 $MissedInfo{"Header"} = $H;
2471 $MissedInfo{"Line"} = $L;
Andrey Ponomarenkob8d203d2012-05-25 18:11:07 +04002472 if($TypedefName=~/\*|\&|\s/)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002473 { # other types
2474 next;
2475 }
Andrey Ponomarenkob8d203d2012-05-25 18:11:07 +04002476 if($TypedefName=~/>(::\w+)+\Z/)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002477 { # QFlags<Qt::DropAction>::enum_type
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002478 next;
2479 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04002480 if(getTypeType($Tid)=~/\A(Intrinsic|Union|Struct|Enum|Class)\Z/)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002481 { # double-check for the name of typedef
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04002482 my ($TName, $TNS) = getTrivialName(getTypeDeclId($Tid), $Tid); # base type info
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002483 next if(not $TName);
Andrey Ponomarenkob8d203d2012-05-25 18:11:07 +04002484 if(length($TypedefName)>=length($TName))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002485 { # too long typedef
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002486 next;
2487 }
Andrey Ponomarenkob8d203d2012-05-25 18:11:07 +04002488 if($TName=~/\A\Q$TypedefName\E</) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002489 next;
2490 }
Andrey Ponomarenkob8d203d2012-05-25 18:11:07 +04002491 if($TypedefName=~/\A\Q$TName\E/)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002492 { # QDateTimeEdit::Section and QDateTimeEdit::Sections::enum_type
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002493 next;
2494 }
Andrey Ponomarenkob8d203d2012-05-25 18:11:07 +04002495 if(get_depth($TypedefName)==0 and get_depth($TName)!=0)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002496 { # std::_Vector_base and std::vector::_Base
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002497 next;
2498 }
2499 }
Andrey Ponomarenkob8d203d2012-05-25 18:11:07 +04002500
2501 $AddTypes{$MissedInfo{"Tid"}} = \%MissedInfo;
2502
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002503 # register typedef
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002504 $MissedTypedef{$Version}{$Tid}{"Tid"} = $MissedInfo{"Tid"};
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04002505 $MissedTypedef{$Version}{$Tid}{"TDid"} = $MissedTDid;
Andrey Ponomarenkob8d203d2012-05-25 18:11:07 +04002506 $TName_Tid{$Version}{$TypedefName} = $MissedInfo{"Tid"};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002507 }
Andrey Ponomarenkob8d203d2012-05-25 18:11:07 +04002508
2509 # add missed & remove other
2510 $TypeInfo{$Version} = \%AddTypes;
2511 delete($Cache{"getTypeAttr"}{$Version});
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002512}
2513
2514sub addMissedTypes_Post()
2515{
2516 foreach my $BaseId (keys(%{$MissedTypedef{$Version}}))
2517 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04002518 if(my $Tid = $MissedTypedef{$Version}{$BaseId}{"Tid"})
2519 {
2520 $TypeInfo{$Version}{$Tid}{"Size"} = $TypeInfo{$Version}{$BaseId}{"Size"};
2521 if(my $TName = $TypeInfo{$Version}{$Tid}{"Name"}) {
2522 $Typedef_BaseName{$Version}{$TName} = $TypeInfo{$Version}{$BaseId}{"Name"};
2523 }
2524 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002525 }
2526}
2527
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04002528sub getTypeInfo($)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002529{
Andrey Ponomarenkob8d203d2012-05-25 18:11:07 +04002530 my $TypeId = $_[0];
2531 %{$TypeInfo{$Version}{$TypeId}} = getTypeAttr($TypeId);
2532 my $TName = $TypeInfo{$Version}{$TypeId}{"Name"};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002533 if(not $TName) {
Andrey Ponomarenkob8d203d2012-05-25 18:11:07 +04002534 delete($TypeInfo{$Version}{$TypeId});
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002535 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002536}
2537
2538sub getArraySize($$)
2539{
2540 my ($TypeId, $BaseName) = @_;
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04002541 if(my $Size = getSize($TypeId))
2542 {
2543 my $Elems = $Size/$BYTE_SIZE;
2544 while($BaseName=~s/\s*\[(\d+)\]//) {
2545 $Elems/=$1;
2546 }
2547 if(my $BasicId = $TName_Tid{$Version}{$BaseName})
2548 {
2549 if(my $BasicSize = $TypeInfo{$Version}{$BasicId}{"Size"}) {
2550 $Elems/=$BasicSize;
2551 }
2552 }
2553 return $Elems;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002554 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04002555 return 0;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002556}
2557
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04002558sub getTParams($$)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002559{
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04002560 my ($TypeId, $Kind) = @_;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002561 my @TmplParams = ();
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04002562 my @Positions = sort {int($a)<=>int($b)} keys(%{$TemplateInstance{$Version}{$Kind}{$TypeId}});
2563 foreach my $Pos (@Positions)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002564 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04002565 my $Param_TypeId = $TemplateInstance{$Version}{$Kind}{$TypeId}{$Pos};
2566 my $NodeType = $LibInfo{$Version}{"info_type"}{$Param_TypeId};
2567 if(not $NodeType)
2568 { # typename_type
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002569 return ();
2570 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04002571 if($NodeType eq "tree_vec")
2572 {
2573 if($Pos!=$#Positions)
2574 { # select last vector of parameters ( ns<P1>::type<P2> )
2575 next;
2576 }
2577 }
2578 my @Params = get_TemplateParam($Pos, $Param_TypeId);
2579 foreach my $P (@Params)
2580 {
2581 if($P eq "") {
2582 return ();
2583 }
2584 elsif($P ne "\@skip\@") {
2585 @TmplParams = (@TmplParams, $P);
2586 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002587 }
2588 }
2589 return @TmplParams;
2590}
2591
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04002592sub getTypeAttr($)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002593{
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04002594 my $TypeId = $_[0];
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04002595 my %TypeAttr = ();
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04002596 if(defined $TypeInfo{$Version}{$TypeId}
2597 and $TypeInfo{$Version}{$TypeId}{"Name"})
2598 { # already created
2599 return %{$TypeInfo{$Version}{$TypeId}};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002600 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04002601 elsif($Cache{"getTypeAttr"}{$Version}{$TypeId})
2602 { # incomplete type
2603 return ();
2604 }
2605 $Cache{"getTypeAttr"}{$Version}{$TypeId} = 1;
2606
2607 my $TypeDeclId = getTypeDeclId($TypeId);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002608 $TypeAttr{"Tid"} = $TypeId;
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04002609
2610 if(not $MissedBase{$Version}{$TypeId} and isTypedef($TypeId))
2611 {
2612 if(my $Info = $LibInfo{$Version}{"info"}{$TypeId})
2613 {
2614 if($Info=~/qual[ ]*:/)
2615 {
2616 if(my $NID = ++$MAX_ID)
2617 {
2618 $MissedBase{$Version}{$TypeId}="$NID";
2619 $MissedBase_R{$Version}{$NID}=$TypeId;
2620 $LibInfo{$Version}{"info"}{$NID} = $LibInfo{$Version}{"info"}{$TypeId};
2621 $LibInfo{$Version}{"info_type"}{$NID} = $LibInfo{$Version}{"info_type"}{$TypeId};
2622 }
2623 }
2624 }
2625 $TypeAttr{"Type"} = "Typedef";
2626 }
2627 else {
2628 $TypeAttr{"Type"} = getTypeType($TypeId);
2629 }
2630
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002631 if($TypeAttr{"Type"} eq "Unknown") {
2632 return ();
2633 }
2634 elsif($TypeAttr{"Type"}=~/(Func|Method|Field)Ptr/)
2635 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04002636 %TypeAttr = getMemPtrAttr(pointTo($TypeId), $TypeId, $TypeAttr{"Type"});
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04002637 if(my $TName = $TypeAttr{"Name"})
2638 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04002639 %{$TypeInfo{$Version}{$TypeId}} = %TypeAttr;
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04002640 $TName_Tid{$Version}{$TName} = $TypeId;
2641 return %TypeAttr;
2642 }
2643 else {
2644 return ();
2645 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002646 }
2647 elsif($TypeAttr{"Type"} eq "Array")
2648 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04002649 my ($BTid, $BTSpec) = selectBaseType($TypeId);
2650 if(not $BTid) {
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04002651 return ();
2652 }
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +04002653 if(my $Algn = getAlgn($TypeId)) {
2654 $TypeAttr{"Algn"} = $Algn/$BYTE_SIZE;
2655 }
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04002656 $TypeAttr{"BaseType"}{"Tid"} = $BTid;
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04002657 if(my %BTAttr = getTypeAttr($BTid))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002658 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04002659 if(not $BTAttr{"Name"}) {
2660 return ();
2661 }
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04002662 if(my $NElems = getArraySize($TypeId, $BTAttr{"Name"}))
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04002663 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04002664 if(my $Size = getSize($TypeId)) {
2665 $TypeAttr{"Size"} = $Size/$BYTE_SIZE;
2666 }
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04002667 if($BTAttr{"Name"}=~/\A([^\[\]]+)(\[(\d+|)\].*)\Z/) {
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04002668 $TypeAttr{"Name"} = $1."[$NElems]".$2;
2669 }
2670 else {
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04002671 $TypeAttr{"Name"} = $BTAttr{"Name"}."[$NElems]";
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04002672 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002673 }
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04002674 else
2675 {
2676 $TypeAttr{"Size"} = $WORD_SIZE{$Version}; # pointer
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04002677 if($BTAttr{"Name"}=~/\A([^\[\]]+)(\[(\d+|)\].*)\Z/) {
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04002678 $TypeAttr{"Name"} = $1."[]".$2;
2679 }
2680 else {
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04002681 $TypeAttr{"Name"} = $BTAttr{"Name"}."[]";
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04002682 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002683 }
Andrey Ponomarenko9927e332012-10-19 10:50:48 +04002684 $TypeAttr{"Name"} = formatName($TypeAttr{"Name"}, "T");
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04002685 if($BTAttr{"Header"}) {
2686 $TypeAttr{"Header"} = $BTAttr{"Header"};
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04002687 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04002688 %{$TypeInfo{$Version}{$TypeId}} = %TypeAttr;
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04002689 $TName_Tid{$Version}{$TypeAttr{"Name"}} = $TypeId;
2690 return %TypeAttr;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002691 }
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04002692 return ();
2693 }
2694 elsif($TypeAttr{"Type"}=~/\A(Intrinsic|Union|Struct|Enum|Class)\Z/)
2695 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04002696 %TypeAttr = getTrivialTypeAttr($TypeId);
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04002697 if($TypeAttr{"Name"})
2698 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04002699 %{$TypeInfo{$Version}{$TypeId}} = %TypeAttr;
2700 if($TypeAttr{"Name"} ne "int" or getTypeDeclId($TypeAttr{"Tid"}))
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04002701 { # NOTE: register only one int: with built-in decl
2702 if(not $TName_Tid{$Version}{$TypeAttr{"Name"}}) {
2703 $TName_Tid{$Version}{$TypeAttr{"Name"}} = $TypeId;
2704 }
2705 }
2706 return %TypeAttr;
2707 }
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04002708 else {
2709 return ();
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002710 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002711 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002712 else
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04002713 { # derived types
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04002714 my ($BTid, $BTSpec) = selectBaseType($TypeId);
2715 if(not $BTid) {
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04002716 return ();
2717 }
2718 $TypeAttr{"BaseType"}{"Tid"} = $BTid;
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04002719 if(defined $MissedTypedef{$Version}{$BTid})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002720 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04002721 if(my $MissedTDid = $MissedTypedef{$Version}{$BTid}{"TDid"})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002722 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04002723 if($MissedTDid ne $TypeDeclId) {
2724 $TypeAttr{"BaseType"}{"Tid"} = $MissedTypedef{$Version}{$BTid}{"Tid"};
2725 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002726 }
2727 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04002728 my %BTAttr = getTypeAttr($TypeAttr{"BaseType"}{"Tid"});
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04002729 if(not $BTAttr{"Name"})
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04002730 { # templates
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002731 return ();
2732 }
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04002733 if($BTAttr{"Type"} eq "Typedef")
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002734 { # relinking typedefs
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04002735 my %BaseBase = get_Type($BTAttr{"BaseType"}{"Tid"}, $Version);
2736 if($BTAttr{"Name"} eq $BaseBase{"Name"}) {
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04002737 $TypeAttr{"BaseType"}{"Tid"} = $BaseBase{"Tid"};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002738 }
2739 }
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04002740 if($BTSpec)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002741 {
2742 if($TypeAttr{"Type"} eq "Pointer"
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04002743 and $BTAttr{"Name"}=~/\([\*]+\)/)
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04002744 {
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04002745 $TypeAttr{"Name"} = $BTAttr{"Name"};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002746 $TypeAttr{"Name"}=~s/\(([*]+)\)/($1*)/g;
2747 }
2748 else {
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04002749 $TypeAttr{"Name"} = $BTAttr{"Name"}." ".$BTSpec;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002750 }
2751 }
2752 else {
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04002753 $TypeAttr{"Name"} = $BTAttr{"Name"};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002754 }
2755 if($TypeAttr{"Type"} eq "Typedef")
2756 {
2757 $TypeAttr{"Name"} = getNameByInfo($TypeDeclId);
Andrey Ponomarenko85043792012-05-14 16:48:07 +04002758 if(isAnon($TypeAttr{"Name"}))
2759 { # anon typedef to anon type: ._N
2760 return ();
2761 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002762 if(my $NS = getNameSpace($TypeDeclId))
2763 {
2764 my $TypeName = $TypeAttr{"Name"};
2765 if($NS=~/\A(struct |union |class |)((.+)::|)\Q$TypeName\E\Z/)
2766 { # "some_type" is the typedef to "struct some_type" in C++
2767 if($3) {
2768 $TypeAttr{"Name"} = $3."::".$TypeName;
2769 }
2770 }
2771 else
2772 {
2773 $TypeAttr{"NameSpace"} = $NS;
2774 $TypeAttr{"Name"} = $TypeAttr{"NameSpace"}."::".$TypeAttr{"Name"};
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04002775
2776 if($TypeAttr{"NameSpace"}=~/\Astd(::|\Z)/
2777 and $TypeAttr{"Name"}!~/>(::\w+)+\Z/)
2778 {
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04002779 if($BTAttr{"NameSpace"}
2780 and $BTAttr{"NameSpace"}=~/\Astd(::|\Z)/ and $BTAttr{"Name"}=~/</)
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04002781 { # types like "std::fpos<__mbstate_t>" are
2782 # not covered by typedefs in the TU dump
2783 # so trying to add such typedefs manually
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04002784 $StdCxxTypedef{$Version}{$BTAttr{"Name"}}{$TypeAttr{"Name"}} = 1;
2785 if(length($TypeAttr{"Name"})<=length($BTAttr{"Name"}))
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04002786 {
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04002787 if(($BTAttr{"Name"}!~/\A(std|boost)::/ or $TypeAttr{"Name"}!~/\A[a-z]+\Z/))
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04002788 { # skip "other" in "std" and "type" in "boost"
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04002789 $Typedef_Eq{$Version}{$BTAttr{"Name"}} = $TypeAttr{"Name"};
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04002790 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002791 }
2792 }
2793 }
2794 }
2795 }
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04002796 if($TypeAttr{"Name"} ne $BTAttr{"Name"}
2797 and $TypeAttr{"Name"}!~/>(::\w+)+\Z/ and $BTAttr{"Name"}!~/>(::\w+)+\Z/)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002798 {
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04002799 if(not defined $Typedef_BaseName{$Version}{$TypeAttr{"Name"}})
2800 { # typedef int*const TYPEDEF; // first
2801 # int foo(TYPEDEF p); // const is optimized out
2802 $Typedef_BaseName{$Version}{$TypeAttr{"Name"}} = $BTAttr{"Name"};
2803 if($BTAttr{"Name"}=~/</)
2804 {
2805 if(($BTAttr{"Name"}!~/\A(std|boost)::/ or $TypeAttr{"Name"}!~/\A[a-z]+\Z/)) {
2806 $Typedef_Tr{$Version}{$BTAttr{"Name"}}{$TypeAttr{"Name"}} = 1;
2807 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002808 }
2809 }
2810 }
2811 ($TypeAttr{"Header"}, $TypeAttr{"Line"}) = getLocation($TypeDeclId);
2812 }
2813 if(not $TypeAttr{"Size"})
2814 {
2815 if($TypeAttr{"Type"} eq "Pointer") {
2816 $TypeAttr{"Size"} = $WORD_SIZE{$Version};
2817 }
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04002818 elsif($BTAttr{"Size"}) {
2819 $TypeAttr{"Size"} = $BTAttr{"Size"};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002820 }
2821 }
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +04002822 if(my $Algn = getAlgn($TypeId)) {
2823 $TypeAttr{"Algn"} = $Algn/$BYTE_SIZE;
2824 }
Andrey Ponomarenko9927e332012-10-19 10:50:48 +04002825 $TypeAttr{"Name"} = formatName($TypeAttr{"Name"}, "T");
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04002826 if(not $TypeAttr{"Header"} and $BTAttr{"Header"}) {
2827 $TypeAttr{"Header"} = $BTAttr{"Header"};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002828 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04002829 %{$TypeInfo{$Version}{$TypeId}} = %TypeAttr;
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04002830 if($TypeAttr{"Name"} ne $BTAttr{"Name"})
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04002831 { # typedef to "class Class"
2832 # should not be registered in TName_Tid
2833 if(not $TName_Tid{$Version}{$TypeAttr{"Name"}}) {
2834 $TName_Tid{$Version}{$TypeAttr{"Name"}} = $TypeId;
2835 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002836 }
2837 return %TypeAttr;
2838 }
2839}
2840
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04002841sub getTreeVec($)
2842{
2843 my %Vector = ();
2844 if($_[0] and my $Info = $LibInfo{$Version}{"info"}{$_[0]})
2845 {
2846 while($Info=~s/ (\d+)[ ]*:[ ]*\@(\d+) / /)
2847 { # string length is N-1 because of the null terminator
2848 $Vector{$1} = $2;
2849 }
2850 }
2851 return \%Vector;
2852}
2853
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002854sub get_TemplateParam($$)
2855{
2856 my ($Pos, $Type_Id) = @_;
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04002857 return () if(not $Type_Id);
2858 my $NodeType = $LibInfo{$Version}{"info_type"}{$Type_Id};
2859 return () if(not $NodeType);
2860 if($NodeType eq "integer_cst")
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002861 { # int (1), unsigned (2u), char ('c' as 99), ...
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04002862 my $CstTid = getTreeAttr_Type($Type_Id);
Andrey Ponomarenkob8d203d2012-05-25 18:11:07 +04002863 my %CstType = getTypeAttr($CstTid); # without recursion
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002864 my $Num = getNodeIntCst($Type_Id);
2865 if(my $CstSuffix = $ConstantSuffix{$CstType{"Name"}}) {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04002866 return ($Num.$CstSuffix);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002867 }
2868 else {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04002869 return ("(".$CstType{"Name"}.")".$Num);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002870 }
2871 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04002872 elsif($NodeType eq "string_cst") {
2873 return (getNodeStrCst($Type_Id));
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002874 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04002875 elsif($NodeType eq "tree_vec")
2876 {
2877 my $Vector = getTreeVec($Type_Id);
2878 my @Params = ();
2879 foreach my $P1 (sort {int($a)<=>int($b)} keys(%{$Vector}))
2880 {
2881 foreach my $P2 (get_TemplateParam($Pos, $Vector->{$P1})) {
2882 push(@Params, $P2);
2883 }
2884 }
2885 return @Params;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002886 }
2887 else
2888 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04002889 my %ParamAttr = getTypeAttr($Type_Id);
Andrey Ponomarenkob8d203d2012-05-25 18:11:07 +04002890 my $PName = $ParamAttr{"Name"};
2891 if(not $PName) {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04002892 return ();
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002893 }
Andrey Ponomarenkob8d203d2012-05-25 18:11:07 +04002894 if($PName=~/\>/)
2895 {
2896 if(my $Cover = cover_stdcxx_typedef($PName)) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002897 $PName = $Cover;
2898 }
2899 }
2900 if($Pos>=1 and
Andrey Ponomarenko1477d2c2012-11-12 18:55:45 +04002901 $PName=~/\A$DEFAULT_STD_PARMS\</)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002902 { # template<typename _Tp, typename _Alloc = std::allocator<_Tp> >
2903 # template<typename _Key, typename _Compare = std::less<_Key>
2904 # template<typename _CharT, typename _Traits = std::char_traits<_CharT> >
2905 # template<typename _Ch_type, typename _Rx_traits = regex_traits<_Ch_type> >
2906 # template<typename _CharT, typename _InIter = istreambuf_iterator<_CharT> >
2907 # template<typename _CharT, typename _OutIter = ostreambuf_iterator<_CharT> >
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04002908 return ("\@skip\@");
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002909 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04002910 return ($PName);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002911 }
2912}
2913
2914sub cover_stdcxx_typedef($)
2915{
2916 my $TypeName = $_[0];
2917 if(my @Covers = sort {length($a)<=>length($b)}
2918 sort keys(%{$StdCxxTypedef{$Version}{$TypeName}}))
2919 { # take the shortest typedef
2920 # FIXME: there may be more than
2921 # one typedefs to the same type
2922 return $Covers[0];
2923 }
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +04002924 my $Covered = $TypeName;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002925 while($TypeName=~s/(>)[ ]*(const|volatile|restrict| |\*|\&)\Z/$1/g){};
2926 if(my @Covers = sort {length($a)<=>length($b)} sort keys(%{$StdCxxTypedef{$Version}{$TypeName}}))
2927 {
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +04002928 if(my $Cover = $Covers[0])
2929 {
2930 $Covered=~s/\b\Q$TypeName\E(\W|\Z)/$Cover$1/g;
2931 $Covered=~s/\b\Q$TypeName\E(\w|\Z)/$Cover $1/g;
2932 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002933 }
Andrey Ponomarenko9927e332012-10-19 10:50:48 +04002934 return formatName($Covered, "T");
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002935}
2936
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002937sub getNodeIntCst($)
2938{
2939 my $CstId = $_[0];
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04002940 my $CstTypeId = getTreeAttr_Type($CstId);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002941 if($EnumMembName_Id{$Version}{$CstId}) {
2942 return $EnumMembName_Id{$Version}{$CstId};
2943 }
2944 elsif((my $Value = getTreeValue($CstId)) ne "")
2945 {
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04002946 if($Value eq "0")
2947 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04002948 if($LibInfo{$Version}{"info_type"}{$CstTypeId} eq "boolean_type") {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002949 return "false";
2950 }
2951 else {
2952 return "0";
2953 }
2954 }
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04002955 elsif($Value eq "1")
2956 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04002957 if($LibInfo{$Version}{"info_type"}{$CstTypeId} eq "boolean_type") {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002958 return "true";
2959 }
2960 else {
2961 return "1";
2962 }
2963 }
2964 else {
2965 return $Value;
2966 }
2967 }
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04002968 return "";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002969}
2970
2971sub getNodeStrCst($)
2972{
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04002973 if($_[0] and my $Info = $LibInfo{$Version}{"info"}{$_[0]})
2974 {
2975 if($Info=~/strg[ ]*: (.+) lngt:[ ]*(\d+)/)
Andrey Ponomarenko01117f12012-06-26 12:23:02 +04002976 {
2977 if($LibInfo{$Version}{"info_type"}{$_[0]} eq "string_cst")
2978 { # string length is N-1 because of the null terminator
2979 return substr($1, 0, $2-1);
2980 }
2981 else
2982 { # identifier_node
2983 return substr($1, 0, $2);
2984 }
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04002985 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002986 }
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04002987 return "";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002988}
2989
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04002990sub getMemPtrAttr($$$)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002991{ # function, method and field pointers
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04002992 my ($PtrId, $TypeId, $Type) = @_;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002993 my $MemInfo = $LibInfo{$Version}{"info"}{$PtrId};
2994 if($Type eq "FieldPtr") {
2995 $MemInfo = $LibInfo{$Version}{"info"}{$TypeId};
2996 }
2997 my $MemInfo_Type = $LibInfo{$Version}{"info_type"}{$PtrId};
2998 my $MemPtrName = "";
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04002999 my %TypeAttr = ("Size"=>$WORD_SIZE{$Version}, "Type"=>$Type, "Tid"=>$TypeId);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003000 if($Type eq "MethodPtr")
3001 { # size of "method pointer" may be greater than WORD size
Andrey Ponomarenko01117f12012-06-26 12:23:02 +04003002 if(my $Size = getSize($TypeId))
3003 {
3004 $Size/=$BYTE_SIZE;
3005 $TypeAttr{"Size"} = "$Size";
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04003006 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003007 }
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +04003008 if(my $Algn = getAlgn($TypeId)) {
3009 $TypeAttr{"Algn"} = $Algn/$BYTE_SIZE;
3010 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003011 # Return
3012 if($Type eq "FieldPtr")
3013 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04003014 my %ReturnAttr = getTypeAttr($PtrId);
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04003015 if($ReturnAttr{"Name"}) {
3016 $MemPtrName .= $ReturnAttr{"Name"};
3017 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003018 $TypeAttr{"Return"} = $PtrId;
3019 }
3020 else
3021 {
3022 if($MemInfo=~/retn[ ]*:[ ]*\@(\d+) /)
3023 {
3024 my $ReturnTypeId = $1;
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04003025 my %ReturnAttr = getTypeAttr($ReturnTypeId);
3026 if(not $ReturnAttr{"Name"})
3027 { # templates
3028 return ();
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04003029 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04003030 $MemPtrName .= $ReturnAttr{"Name"};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003031 $TypeAttr{"Return"} = $ReturnTypeId;
3032 }
3033 }
3034 # Class
3035 if($MemInfo=~/(clas|cls)[ ]*:[ ]*@(\d+) /)
3036 {
3037 $TypeAttr{"Class"} = $2;
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04003038 my %Class = getTypeAttr($TypeAttr{"Class"});
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003039 if($Class{"Name"}) {
3040 $MemPtrName .= " (".$Class{"Name"}."\:\:*)";
3041 }
3042 else {
3043 $MemPtrName .= " (*)";
3044 }
3045 }
3046 else {
3047 $MemPtrName .= " (*)";
3048 }
3049 # Parameters
3050 if($Type eq "FuncPtr"
3051 or $Type eq "MethodPtr")
3052 {
3053 my @ParamTypeName = ();
3054 if($MemInfo=~/prms[ ]*:[ ]*@(\d+) /)
3055 {
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04003056 my $PTypeInfoId = $1;
Andrey Ponomarenko01117f12012-06-26 12:23:02 +04003057 my ($Pos, $PPos) = (0, 0);
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04003058 while($PTypeInfoId)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003059 {
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04003060 my $PTypeInfo = $LibInfo{$Version}{"info"}{$PTypeInfoId};
3061 if($PTypeInfo=~/valu[ ]*:[ ]*@(\d+) /)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003062 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04003063 my $PTypeId = $1;
3064 my %ParamAttr = getTypeAttr($PTypeId);
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04003065 if(not $ParamAttr{"Name"})
3066 { # templates (template_type_parm), etc.
3067 return ();
3068 }
3069 if($ParamAttr{"Name"} eq "void") {
3070 last;
3071 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04003072 if($Pos!=0 or $Type ne "MethodPtr")
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04003073 {
Andrey Ponomarenko01117f12012-06-26 12:23:02 +04003074 $TypeAttr{"Param"}{$PPos++}{"type"} = $PTypeId;
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04003075 push(@ParamTypeName, $ParamAttr{"Name"});
3076 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04003077 if($PTypeInfoId = getNextElem($PTypeInfoId)) {
3078 $Pos+=1;
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04003079 }
3080 else {
3081 last;
3082 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003083 }
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04003084 else {
3085 last;
3086 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003087 }
3088 }
3089 $MemPtrName .= " (".join(", ", @ParamTypeName).")";
3090 }
Andrey Ponomarenko9927e332012-10-19 10:50:48 +04003091 $TypeAttr{"Name"} = formatName($MemPtrName, "T");
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003092 return %TypeAttr;
3093}
3094
3095sub getTreeTypeName($)
3096{
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04003097 my $TypeId = $_[0];
3098 if(my $Info = $LibInfo{$Version}{"info"}{$TypeId})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003099 {
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04003100 if($LibInfo{$Version}{"info_type"}{$_[0]} eq "integer_type")
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003101 {
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04003102 if(my $Name = getNameByInfo($TypeId))
3103 { # bit_size_type
3104 return $Name;
3105 }
3106 elsif($Info=~/unsigned/) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003107 return "unsigned int";
3108 }
3109 else {
3110 return "int";
3111 }
3112 }
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04003113 elsif($Info=~/name[ ]*:[ ]*@(\d+) /)
3114 {
3115 return getNameByInfo($1);
3116 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003117 }
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04003118 return "";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003119}
3120
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04003121sub isFuncPtr($)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003122{
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04003123 my $Ptd = pointTo($_[0]);
3124 return 0 if(not $Ptd);
3125 if(my $Info = $LibInfo{$Version}{"info"}{$_[0]})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003126 {
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04003127 if($Info=~/unql[ ]*:/ and $Info!~/qual[ ]*:/) {
3128 return 0;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003129 }
3130 }
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04003131 if(my $InfoT1 = $LibInfo{$Version}{"info_type"}{$_[0]}
3132 and my $InfoT2 = $LibInfo{$Version}{"info_type"}{$Ptd})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003133 {
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04003134 if($InfoT1 eq "pointer_type"
3135 and $InfoT2 eq "function_type") {
3136 return 1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003137 }
3138 }
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04003139 return 0;
3140}
3141
3142sub isMethodPtr($)
3143{
3144 my $Ptd = pointTo($_[0]);
3145 return 0 if(not $Ptd);
3146 if(my $Info = $LibInfo{$Version}{"info"}{$_[0]})
3147 {
3148 if($LibInfo{$Version}{"info_type"}{$_[0]} eq "record_type"
3149 and $LibInfo{$Version}{"info_type"}{$Ptd} eq "method_type"
3150 and $Info=~/ ptrmem /) {
3151 return 1;
3152 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003153 }
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04003154 return 0;
3155}
3156
3157sub isFieldPtr($)
3158{
3159 if($_[0] and my $Info = $LibInfo{$Version}{"info"}{$_[0]})
3160 {
3161 if($LibInfo{$Version}{"info_type"}{$_[0]} eq "offset_type"
3162 and $Info=~/ ptrmem /) {
3163 return 1;
3164 }
3165 }
3166 return 0;
3167}
3168
3169sub pointTo($)
3170{
3171 if($_[0] and my $Info = $LibInfo{$Version}{"info"}{$_[0]})
3172 {
3173 if($Info=~/ptd[ ]*:[ ]*@(\d+)/) {
3174 return $1;
3175 }
3176 }
3177 return "";
3178}
3179
3180sub getTypeTypeByTypeId($)
3181{
3182 my $TypeId = $_[0];
3183 if(my $TType = $LibInfo{$Version}{"info_type"}{$TypeId})
3184 {
3185 my $NType = $NodeType{$TType};
3186 if($NType eq "Intrinsic") {
3187 return $NType;
3188 }
3189 elsif(isFuncPtr($TypeId)) {
3190 return "FuncPtr";
3191 }
3192 elsif(isMethodPtr($TypeId)) {
3193 return "MethodPtr";
3194 }
3195 elsif(isFieldPtr($TypeId)) {
3196 return "FieldPtr";
3197 }
3198 elsif($NType ne "Other") {
3199 return $NType;
3200 }
3201 }
3202 return "Unknown";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003203}
3204
3205sub getQual($)
3206{
3207 my $TypeId = $_[0];
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003208 my %UnQual = (
3209 "r"=>"restrict",
3210 "v"=>"volatile",
3211 "c"=>"const",
3212 "cv"=>"const volatile"
3213 );
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04003214 if(my $Info = $LibInfo{$Version}{"info"}{$TypeId})
3215 {
3216 my ($Qual, $To) = ();
3217 if($Info=~/qual[ ]*:[ ]*(r|c|v|cv) /) {
3218 $Qual = $UnQual{$1};
3219 }
3220 if($Info=~/unql[ ]*:[ ]*\@(\d+)/) {
3221 $To = $1;
3222 }
3223 if($Qual and $To) {
3224 return ($Qual, $To);
3225 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003226 }
3227 return ();
3228}
3229
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04003230sub getQualType($)
3231{
3232 if($_[0] eq "const volatile") {
3233 return "ConstVolatile";
3234 }
3235 return ucfirst($_[0]);
3236}
3237
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04003238sub getTypeType($)
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04003239{
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04003240 my $TypeId = $_[0];
3241 my $TypeDeclId = getTypeDeclId($TypeId);
3242 if(defined $MissedTypedef{$Version}{$TypeId})
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04003243 { # support for old GCC versions
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04003244 if($MissedTypedef{$Version}{$TypeId}{"TDid"} eq $TypeDeclId) {
3245 return "Typedef";
3246 }
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04003247 }
3248 my $Info = $LibInfo{$Version}{"info"}{$TypeId};
3249 my ($Qual, $To) = getQual($TypeId);
Andrey Ponomarenko9927e332012-10-19 10:50:48 +04003250 if(($Qual or $To) and $TypeDeclId
3251 and (getTypeId($TypeDeclId) ne $TypeId))
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04003252 { # qualified types (special)
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04003253 return getQualType($Qual);
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04003254 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04003255 elsif(not $MissedBase_R{$Version}{$TypeId}
3256 and isTypedef($TypeId)) {
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04003257 return "Typedef";
3258 }
3259 elsif($Qual)
3260 { # qualified types
3261 return getQualType($Qual);
3262 }
Andrey Ponomarenko9927e332012-10-19 10:50:48 +04003263
3264 if($Info=~/unql[ ]*:[ ]*\@(\d+)/)
3265 { # typedef struct { ... } name
3266 $TypeTypedef{$Version}{$TypeId} = $1;
3267 }
3268
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04003269 my $TypeType = getTypeTypeByTypeId($TypeId);
3270 if($TypeType eq "Struct")
3271 {
3272 if($TypeDeclId
3273 and $LibInfo{$Version}{"info_type"}{$TypeDeclId} eq "template_decl") {
3274 return "Template";
3275 }
3276 }
3277 return $TypeType;
3278}
3279
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04003280sub isTypedef($)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003281{
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04003282 if($_[0] and my $Info = $LibInfo{$Version}{"info"}{$_[0]})
3283 {
3284 my $TDid = getTypeDeclId($_[0]);
3285 if(getNameByInfo($TDid)
3286 and $Info=~/unql[ ]*:[ ]*\@(\d+) /
3287 and getTypeId($TDid) eq $_[0]) {
3288 return $1;
3289 }
3290 }
3291 return 0;
3292}
3293
3294sub selectBaseType($)
3295{
3296 my $TypeId = $_[0];
3297 if(defined $MissedTypedef{$Version}{$TypeId})
3298 { # add missed typedefs
3299 if($MissedTypedef{$Version}{$TypeId}{"TDid"} eq getTypeDeclId($TypeId)) {
3300 return ($TypeId, "");
3301 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003302 }
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04003303 my $Info = $LibInfo{$Version}{"info"}{$TypeId};
3304 my $InfoType = $LibInfo{$Version}{"info_type"}{$TypeId};
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04003305
3306 my $MB_R = $MissedBase_R{$Version}{$TypeId};
3307 my $MB = $MissedBase{$Version}{$TypeId};
3308
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04003309 my ($Qual, $To) = getQual($TypeId);
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04003310 if(($Qual or $To) and $Info=~/name[ ]*:[ ]*\@(\d+) /
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04003311 and (getTypeId($1) ne $TypeId)
3312 and (not $MB_R or getTypeId($1) ne $MB_R))
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04003313 { # qualified types (special)
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04003314 return (getTypeId($1), $Qual);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003315 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04003316 elsif($MB)
3317 { # add base
3318 return ($MB, "");
3319 }
3320 elsif(not $MB_R and my $Bid = isTypedef($TypeId))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003321 { # typedefs
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04003322 return ($Bid, "");
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003323 }
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04003324 elsif($Qual or $To)
3325 { # qualified types
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04003326 return ($To, $Qual);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003327 }
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04003328 elsif($InfoType eq "reference_type")
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003329 {
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04003330 if($Info=~/refd[ ]*:[ ]*@(\d+) /) {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04003331 return ($1, "&");
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003332 }
3333 else {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04003334 return (0, "");
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003335 }
3336 }
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04003337 elsif($InfoType eq "array_type")
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003338 {
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04003339 if($Info=~/elts[ ]*:[ ]*@(\d+) /) {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04003340 return ($1, "");
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003341 }
3342 else {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04003343 return (0, "");
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003344 }
3345 }
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04003346 elsif($InfoType eq "pointer_type")
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003347 {
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04003348 if($Info=~/ptd[ ]*:[ ]*@(\d+) /) {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04003349 return ($1, "*");
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003350 }
3351 else {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04003352 return (0, "");
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003353 }
3354 }
3355 else {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04003356 return (0, "");
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003357 }
3358}
3359
3360sub getSymbolInfo_All()
3361{
3362 foreach (sort {int($b)<=>int($a)} keys(%{$LibInfo{$Version}{"info"}}))
3363 { # reverse order
3364 if($LibInfo{$Version}{"info_type"}{$_} eq "function_decl") {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04003365 getSymbolInfo($_);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003366 }
3367 }
3368}
3369
3370sub getVarInfo_All()
3371{
3372 foreach (sort {int($b)<=>int($a)} keys(%{$LibInfo{$Version}{"info"}}))
3373 { # reverse order
3374 if($LibInfo{$Version}{"info_type"}{$_} eq "var_decl") {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04003375 getVarInfo($_);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003376 }
3377 }
3378}
3379
3380sub isBuiltIn($) {
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04003381 return ($_[0] and $_[0]=~/\<built\-in\>|\<internal\>|\A\./);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003382}
3383
3384sub getVarInfo($)
3385{
3386 my $InfoId = $_[0];
Andrey Ponomarenko01117f12012-06-26 12:23:02 +04003387 if(my $NSid = getTreeAttr_Scpe($InfoId))
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04003388 {
3389 my $NSInfoType = $LibInfo{$Version}{"info_type"}{$NSid};
3390 if($NSInfoType and $NSInfoType eq "function_decl") {
3391 return;
3392 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003393 }
3394 ($SymbolInfo{$Version}{$InfoId}{"Header"}, $SymbolInfo{$Version}{$InfoId}{"Line"}) = getLocation($InfoId);
3395 if(not $SymbolInfo{$Version}{$InfoId}{"Header"}
3396 or isBuiltIn($SymbolInfo{$Version}{$InfoId}{"Header"})) {
3397 delete($SymbolInfo{$Version}{$InfoId});
3398 return;
3399 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04003400 my $ShortName = getTreeStr(getTreeAttr_Name($InfoId));
Andrey Ponomarenko85043792012-05-14 16:48:07 +04003401 if(not $ShortName) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003402 delete($SymbolInfo{$Version}{$InfoId});
3403 return;
3404 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +04003405 if($ShortName=~/\Atmp_add_class_\d+\Z/) {
3406 delete($SymbolInfo{$Version}{$InfoId});
3407 return;
3408 }
3409 $SymbolInfo{$Version}{$InfoId}{"ShortName"} = $ShortName;
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +04003410 if(my $MnglName = getTreeStr(getTreeAttr_Mngl($InfoId)))
3411 {
3412 if($OSgroup eq "windows")
3413 { # cut the offset
3414 $MnglName=~s/\@\d+\Z//g;
3415 }
3416 $SymbolInfo{$Version}{$InfoId}{"MnglName"} = $MnglName;
3417 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003418 if($SymbolInfo{$Version}{$InfoId}{"MnglName"}
Andrey Ponomarenko9927e332012-10-19 10:50:48 +04003419 and index($SymbolInfo{$Version}{$InfoId}{"MnglName"}, "_Z")!=0)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003420 { # validate mangled name
3421 delete($SymbolInfo{$Version}{$InfoId});
3422 return;
3423 }
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04003424 if(not $SymbolInfo{$Version}{$InfoId}{"MnglName"}
Andrey Ponomarenko9927e332012-10-19 10:50:48 +04003425 and index($ShortName, "_Z")==0)
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04003426 { # _ZTS, etc.
Andrey Ponomarenko85043792012-05-14 16:48:07 +04003427 $SymbolInfo{$Version}{$InfoId}{"MnglName"} = $ShortName;
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04003428 }
3429 if(isPrivateData($SymbolInfo{$Version}{$InfoId}{"MnglName"}))
3430 { # non-public global data
3431 delete($SymbolInfo{$Version}{$InfoId});
3432 return;
3433 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003434 $SymbolInfo{$Version}{$InfoId}{"Data"} = 1;
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04003435 if(my $Rid = getTypeId($InfoId))
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04003436 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04003437 if(not $TypeInfo{$Version}{$Rid}{"Name"})
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04003438 { # typename_type
3439 delete($SymbolInfo{$Version}{$InfoId});
3440 return;
3441 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04003442 $SymbolInfo{$Version}{$InfoId}{"Return"} = $Rid;
3443 my $Val = getDataVal($InfoId, $Rid);
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04003444 if(defined $Val) {
3445 $SymbolInfo{$Version}{$InfoId}{"Value"} = $Val;
3446 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003447 }
3448 set_Class_And_Namespace($InfoId);
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04003449 if(my $ClassId = $SymbolInfo{$Version}{$InfoId}{"Class"})
3450 {
3451 if(not $TypeInfo{$Version}{$ClassId}{"Name"})
3452 { # templates
3453 delete($SymbolInfo{$Version}{$InfoId});
3454 return;
3455 }
3456 }
Andrey Ponomarenko35c44fd2012-06-18 17:50:25 +04003457 if($LibInfo{$Version}{"info"}{$InfoId}=~/ lang:[ ]*C /i)
3458 { # extern "C"
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003459 $SymbolInfo{$Version}{$InfoId}{"Lang"} = "C";
Andrey Ponomarenko35c44fd2012-06-18 17:50:25 +04003460 $SymbolInfo{$Version}{$InfoId}{"MnglName"} = $ShortName;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003461 }
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04003462 if($UserLang and $UserLang eq "C")
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003463 { # --lang=C option
Andrey Ponomarenko85043792012-05-14 16:48:07 +04003464 $SymbolInfo{$Version}{$InfoId}{"MnglName"} = $ShortName;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003465 }
Andrey Ponomarenko5c09ef32012-06-14 18:17:33 +04003466 if(not $CheckHeadersOnly)
3467 {
3468 if(not $SymbolInfo{$Version}{$InfoId}{"Class"})
3469 {
3470 if(not $SymbolInfo{$Version}{$InfoId}{"MnglName"}
3471 or not link_symbol($SymbolInfo{$Version}{$InfoId}{"MnglName"}, $Version, "-Deps"))
3472 {
3473 if(link_symbol($ShortName, $Version, "-Deps"))
3474 { # "const" global data is mangled as _ZL... in the TU dump
3475 # but not mangled when compiling a C shared library
3476 $SymbolInfo{$Version}{$InfoId}{"MnglName"} = $ShortName;
3477 }
3478 }
3479 }
3480 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003481 if($COMMON_LANGUAGE{$Version} eq "C++")
3482 {
3483 if(not $SymbolInfo{$Version}{$InfoId}{"MnglName"})
3484 { # for some symbols (_ZTI) the short name is the mangled name
Andrey Ponomarenko9927e332012-10-19 10:50:48 +04003485 if(index($ShortName, "_Z")==0) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003486 $SymbolInfo{$Version}{$InfoId}{"MnglName"} = $ShortName;
3487 }
3488 }
3489 if(not $SymbolInfo{$Version}{$InfoId}{"MnglName"})
3490 { # try to mangle symbol (link with libraries)
3491 $SymbolInfo{$Version}{$InfoId}{"MnglName"} = linkSymbol($InfoId);
3492 }
3493 if($OStarget eq "windows")
3494 {
3495 if(my $Mangled = $mangled_name{$Version}{modelUnmangled($InfoId, "MSVC")})
3496 { # link MS C++ symbols from library with GCC symbols from headers
3497 $SymbolInfo{$Version}{$InfoId}{"MnglName"} = $Mangled;
3498 }
3499 }
3500 }
3501 if(not $SymbolInfo{$Version}{$InfoId}{"MnglName"}) {
3502 $SymbolInfo{$Version}{$InfoId}{"MnglName"} = $ShortName;
3503 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +04003504 if(my $Symbol = $SymbolInfo{$Version}{$InfoId}{"MnglName"})
3505 {
3506 if(not selectSymbol($Symbol, $SymbolInfo{$Version}{$InfoId}, "Dump", $Version))
3507 { # non-target symbols
3508 delete($SymbolInfo{$Version}{$InfoId});
3509 return;
3510 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003511 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04003512 if(my $Rid = $SymbolInfo{$Version}{$InfoId}{"Return"})
3513 {
3514 if(defined $MissedTypedef{$Version}{$Rid})
3515 {
3516 if(my $AddedTid = $MissedTypedef{$Version}{$Rid}{"Tid"}) {
3517 $SymbolInfo{$Version}{$InfoId}{"Return"} = $AddedTid;
3518 }
3519 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003520 }
3521 setFuncAccess($InfoId);
Andrey Ponomarenko9927e332012-10-19 10:50:48 +04003522 if(index($SymbolInfo{$Version}{$InfoId}{"MnglName"}, "_ZTV")==0) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003523 delete($SymbolInfo{$Version}{$InfoId}{"Return"});
3524 }
3525 if($ShortName=~/\A(_Z|\?)/) {
3526 delete($SymbolInfo{$Version}{$InfoId}{"ShortName"});
3527 }
3528}
3529
Andrey Ponomarenko85043792012-05-14 16:48:07 +04003530sub isConstType($$)
3531{
3532 my ($TypeId, $LibVersion) = @_;
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04003533 my %Base = get_Type($TypeId, $LibVersion);
Andrey Ponomarenko85043792012-05-14 16:48:07 +04003534 while(defined $Base{"Type"} and $Base{"Type"} eq "Typedef") {
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +04003535 %Base = get_OneStep_BaseType($Base{"Tid"}, $TypeInfo{$LibVersion});
Andrey Ponomarenko85043792012-05-14 16:48:07 +04003536 }
3537 return ($Base{"Type"} eq "Const");
3538}
3539
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003540sub getTrivialName($$)
3541{
3542 my ($TypeInfoId, $TypeId) = @_;
3543 my %TypeAttr = ();
3544 $TypeAttr{"Name"} = getNameByInfo($TypeInfoId);
3545 if(not $TypeAttr{"Name"}) {
3546 $TypeAttr{"Name"} = getTreeTypeName($TypeId);
3547 }
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04003548 ($TypeAttr{"Header"}, $TypeAttr{"Line"}) = getLocation($TypeInfoId);
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04003549 $TypeAttr{"Type"} = getTypeType($TypeId);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003550 $TypeAttr{"Name"}=~s/<(.+)\Z//g; # GCC 3.4.4 add template params to the name
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04003551 if(isAnon($TypeAttr{"Name"}))
3552 {
3553 my $NameSpaceId = $TypeId;
Andrey Ponomarenko01117f12012-06-26 12:23:02 +04003554 while(my $NSId = getTreeAttr_Scpe(getTypeDeclId($NameSpaceId)))
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04003555 { # searching for a first not anon scope
3556 if($NSId eq $NameSpaceId) {
3557 last;
3558 }
3559 else
3560 {
3561 $TypeAttr{"NameSpace"} = getNameSpace(getTypeDeclId($TypeId));
3562 if(not $TypeAttr{"NameSpace"}
3563 or isNotAnon($TypeAttr{"NameSpace"})) {
3564 last;
3565 }
3566 }
3567 $NameSpaceId=$NSId;
3568 }
3569 }
3570 else
3571 {
Andrey Ponomarenko01117f12012-06-26 12:23:02 +04003572 if(my $NameSpaceId = getTreeAttr_Scpe($TypeInfoId))
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04003573 {
3574 if($NameSpaceId ne $TypeId) {
3575 $TypeAttr{"NameSpace"} = getNameSpace($TypeInfoId);
3576 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003577 }
3578 }
3579 if($TypeAttr{"NameSpace"} and isNotAnon($TypeAttr{"Name"})) {
3580 $TypeAttr{"Name"} = $TypeAttr{"NameSpace"}."::".$TypeAttr{"Name"};
3581 }
Andrey Ponomarenko9927e332012-10-19 10:50:48 +04003582 $TypeAttr{"Name"} = formatName($TypeAttr{"Name"}, "T");
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003583 if(isAnon($TypeAttr{"Name"}))
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04003584 { # anon-struct-header.h-line
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04003585 $TypeAttr{"Name"} = "anon-".lc($TypeAttr{"Type"})."-";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003586 $TypeAttr{"Name"} .= $TypeAttr{"Header"}."-".$TypeAttr{"Line"};
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04003587 if($TypeAttr{"NameSpace"}) {
3588 $TypeAttr{"Name"} = $TypeAttr{"NameSpace"}."::".$TypeAttr{"Name"};
3589 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003590 }
Andrey Ponomarenkob8d203d2012-05-25 18:11:07 +04003591 if(defined $TemplateInstance{$Version}{"Type"}{$TypeId}
3592 and getTypeDeclId($TypeId) eq $TypeInfoId)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003593 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04003594 my @TParams = getTParams($TypeId, "Type");
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003595 if(not @TParams)
3596 { # template declarations with abstract params
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003597 return ("", "");
3598 }
Andrey Ponomarenko9927e332012-10-19 10:50:48 +04003599 $TypeAttr{"Name"} = formatName($TypeAttr{"Name"}."< ".join(", ", @TParams)." >", "T");
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003600 }
3601 return ($TypeAttr{"Name"}, $TypeAttr{"NameSpace"});
3602}
3603
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04003604sub getTrivialTypeAttr($)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003605{
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04003606 my $TypeId = $_[0];
3607 my $TypeInfoId = getTypeDeclId($_[0]);
Andrey Ponomarenko85043792012-05-14 16:48:07 +04003608
3609 if($TemplateDecl{$Version}{$TypeId})
3610 { # template_decl
3611 return ();
3612 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04003613 if(my $ScopeId = getTreeAttr_Scpe($TypeInfoId))
3614 {
3615 if($TemplateDecl{$Version}{$ScopeId})
3616 { # template_decl
3617 return ();
3618 }
3619 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +04003620
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003621 my %TypeAttr = ();
3622 if(getTypeTypeByTypeId($TypeId)!~/\A(Intrinsic|Union|Struct|Enum|Class)\Z/) {
3623 return ();
3624 }
3625 setTypeAccess($TypeId, \%TypeAttr);
3626 ($TypeAttr{"Header"}, $TypeAttr{"Line"}) = getLocation($TypeInfoId);
3627 if(isBuiltIn($TypeAttr{"Header"}))
3628 {
3629 delete($TypeAttr{"Header"});
3630 delete($TypeAttr{"Line"});
3631 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04003632 $TypeAttr{"Type"} = getTypeType($TypeId);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003633 ($TypeAttr{"Name"}, $TypeAttr{"NameSpace"}) = getTrivialName($TypeInfoId, $TypeId);
3634 if(not $TypeAttr{"Name"}) {
3635 return ();
3636 }
3637 if(not $TypeAttr{"NameSpace"}) {
3638 delete($TypeAttr{"NameSpace"});
3639 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04003640 if(defined $TemplateInstance{$Version}{"Type"}{$TypeId})
Andrey Ponomarenko16934472012-03-29 15:37:04 +04003641 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04003642 if(my @TParams = getTParams($TypeId, "Type"))
Andrey Ponomarenko16934472012-03-29 15:37:04 +04003643 {
3644 foreach my $Pos (0 .. $#TParams) {
3645 $TypeAttr{"TParam"}{$Pos}{"name"}=$TParams[$Pos];
3646 }
3647 }
3648 }
Andrey Ponomarenko01117f12012-06-26 12:23:02 +04003649 if(my $Size = getSize($TypeId))
3650 {
3651 $Size = $Size/$BYTE_SIZE;
3652 $TypeAttr{"Size"} = "$Size";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003653 }
Andrey Ponomarenko9927e332012-10-19 10:50:48 +04003654 else
3655 { # declaration only
3656 $TypeAttr{"Forward"} = 1;
3657 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003658 if($TypeAttr{"Type"} eq "Struct"
3659 and detect_lang($TypeId))
3660 {
3661 $TypeAttr{"Type"} = "Class";
Andrey Ponomarenko85043792012-05-14 16:48:07 +04003662 $TypeAttr{"Copied"} = 1; # default, will be changed in getSymbolInfo()
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003663 }
3664 if($TypeAttr{"Type"} eq "Struct"
Andrey Ponomarenko85043792012-05-14 16:48:07 +04003665 or $TypeAttr{"Type"} eq "Class")
3666 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04003667 my $Skip = setBaseClasses($TypeId, \%TypeAttr);
Andrey Ponomarenko85043792012-05-14 16:48:07 +04003668 if($Skip) {
3669 return ();
3670 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003671 }
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +04003672 if(my $Algn = getAlgn($TypeId)) {
3673 $TypeAttr{"Algn"} = $Algn/$BYTE_SIZE;
3674 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003675 setSpec($TypeId, \%TypeAttr);
3676 setTypeMemb($TypeId, \%TypeAttr);
3677 $TypeAttr{"Tid"} = $TypeId;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003678 if(my $VTable = $ClassVTable_Content{$Version}{$TypeAttr{"Name"}})
3679 {
3680 my @Entries = split(/\n/, $VTable);
3681 foreach (1 .. $#Entries)
3682 {
3683 my $Entry = $Entries[$_];
3684 if($Entry=~/\A(\d+)\s+(.+)\Z/) {
3685 $TypeAttr{"VTable"}{$1} = $2;
3686 }
3687 }
3688 }
Andrey Ponomarenko82bc2572012-11-14 13:55:30 +04003689
3690 if($TypeAttr{"Type"} eq "Enum")
3691 {
3692 if(not $TypeAttr{"NameSpace"})
3693 {
3694 foreach my $Pos (keys(%{$TypeAttr{"Memb"}}))
3695 {
3696 my $MName = $TypeAttr{"Memb"}{$Pos}{"name"};
3697 $EnumConstants{$Version}{$MName} = {
3698 "Value"=>$TypeAttr{"Memb"}{$Pos}{"value"},
3699 "Header"=>$TypeAttr{"Header"}
3700 };
3701 }
3702 }
3703 }
3704
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003705 return %TypeAttr;
3706}
3707
3708sub detect_lang($)
3709{
3710 my $TypeId = $_[0];
3711 my $Info = $LibInfo{$Version}{"info"}{$TypeId};
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04003712 if(check_gcc($GCC_PATH, "4"))
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04003713 { # GCC 4 fncs-node points to only non-artificial methods
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003714 return ($Info=~/(fncs)[ ]*:[ ]*@(\d+) /);
3715 }
3716 else
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04003717 { # GCC 3
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04003718 my $Fncs = getTreeAttr_Fncs($TypeId);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003719 while($Fncs)
3720 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04003721 if($LibInfo{$Version}{"info"}{$Fncs}!~/artificial/) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003722 return 1;
3723 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04003724 $Fncs = getTreeAttr_Chan($Fncs);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003725 }
3726 }
3727 return 0;
3728}
3729
3730sub setSpec($$)
3731{
3732 my ($TypeId, $TypeAttr) = @_;
3733 my $Info = $LibInfo{$Version}{"info"}{$TypeId};
3734 if($Info=~/\s+spec\s+/) {
3735 $TypeAttr->{"Spec"} = 1;
3736 }
3737}
3738
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04003739sub setBaseClasses($$)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003740{
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04003741 my ($TypeId, $TypeAttr) = @_;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003742 my $Info = $LibInfo{$Version}{"info"}{$TypeId};
3743 if($Info=~/binf[ ]*:[ ]*@(\d+) /)
3744 {
3745 $Info = $LibInfo{$Version}{"info"}{$1};
3746 my $Pos = 0;
3747 while($Info=~s/(pub|public|prot|protected|priv|private|)[ ]+binf[ ]*:[ ]*@(\d+) //)
3748 {
3749 my ($Access, $BInfoId) = ($1, $2);
3750 my $ClassId = getBinfClassId($BInfoId);
Andrey Ponomarenko85043792012-05-14 16:48:07 +04003751 my $CType = $LibInfo{$Version}{"info_type"}{$ClassId};
3752 if(not $CType or $CType eq "template_type_parm"
3753 or $CType eq "typename_type")
3754 { # skip
3755 return 1;
3756 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003757 my $BaseInfo = $LibInfo{$Version}{"info"}{$BInfoId};
3758 if($Access=~/prot/)
3759 {
3760 $TypeAttr->{"Base"}{$ClassId}{"access"} = "protected";
3761 }
3762 elsif($Access=~/priv/)
3763 {
3764 $TypeAttr->{"Base"}{$ClassId}{"access"} = "private";
3765 }
Andrey Ponomarenko01117f12012-06-26 12:23:02 +04003766 $TypeAttr->{"Base"}{$ClassId}{"pos"} = "$Pos";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003767 if($BaseInfo=~/virt/)
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04003768 { # virtual base
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003769 $TypeAttr->{"Base"}{$ClassId}{"virtual"} = 1;
3770 }
3771 $Class_SubClasses{$Version}{$ClassId}{$TypeId}=1;
Andrey Ponomarenko01117f12012-06-26 12:23:02 +04003772 $Pos+=1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003773 }
3774 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +04003775 return 0;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003776}
3777
3778sub getBinfClassId($)
3779{
3780 my $Info = $LibInfo{$Version}{"info"}{$_[0]};
3781 $Info=~/type[ ]*:[ ]*@(\d+) /;
3782 return $1;
3783}
3784
3785sub unmangledFormat($$)
3786{
3787 my ($Name, $LibVersion) = @_;
3788 $Name = uncover_typedefs($Name, $LibVersion);
3789 while($Name=~s/([^\w>*])(const|volatile)(,|>|\Z)/$1$3/g){};
3790 $Name=~s/\(\w+\)(\d)/$1/;
3791 return $Name;
3792}
3793
3794sub modelUnmangled($$)
3795{
3796 my ($InfoId, $Compiler) = @_;
3797 if($Cache{"modelUnmangled"}{$Version}{$Compiler}{$InfoId}) {
3798 return $Cache{"modelUnmangled"}{$Version}{$Compiler}{$InfoId};
3799 }
3800 my $PureSignature = $SymbolInfo{$Version}{$InfoId}{"ShortName"};
3801 if($SymbolInfo{$Version}{$InfoId}{"Destructor"}) {
3802 $PureSignature = "~".$PureSignature;
3803 }
3804 if(not $SymbolInfo{$Version}{$InfoId}{"Data"})
3805 {
3806 my (@Params, @ParamTypes) = ();
3807 if(defined $SymbolInfo{$Version}{$InfoId}{"Param"}
3808 and not $SymbolInfo{$Version}{$InfoId}{"Destructor"}) {
3809 @Params = keys(%{$SymbolInfo{$Version}{$InfoId}{"Param"}});
3810 }
3811 foreach my $ParamPos (sort {int($a) <=> int($b)} @Params)
3812 { # checking parameters
3813 my $PId = $SymbolInfo{$Version}{$InfoId}{"Param"}{$ParamPos}{"type"};
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +04003814 my %PType = get_PureType($PId, $TypeInfo{$Version});
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003815 my $PTName = unmangledFormat($PType{"Name"}, $Version);
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04003816 $PTName=~s/\b(restrict|register)\b//g;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003817 if($Compiler eq "MSVC") {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04003818 $PTName=~s/\blong long\b/__int64/;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003819 }
3820 @ParamTypes = (@ParamTypes, $PTName);
3821 }
3822 if(@ParamTypes) {
3823 $PureSignature .= "(".join(", ", @ParamTypes).")";
3824 }
3825 else
3826 {
3827 if($Compiler eq "MSVC")
3828 {
3829 $PureSignature .= "(void)";
3830 }
3831 else
3832 { # GCC
3833 $PureSignature .= "()";
3834 }
3835 }
3836 $PureSignature = delete_keywords($PureSignature);
3837 }
3838 if(my $ClassId = $SymbolInfo{$Version}{$InfoId}{"Class"})
3839 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04003840 my $ClassName = unmangledFormat($TypeInfo{$Version}{$ClassId}{"Name"}, $Version);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003841 $PureSignature = $ClassName."::".$PureSignature;
3842 }
3843 elsif(my $NS = $SymbolInfo{$Version}{$InfoId}{"NameSpace"}) {
3844 $PureSignature = $NS."::".$PureSignature;
3845 }
3846 if($SymbolInfo{$Version}{$InfoId}{"Const"}) {
3847 $PureSignature .= " const";
3848 }
3849 if($SymbolInfo{$Version}{$InfoId}{"Volatile"}) {
3850 $PureSignature .= " volatile";
3851 }
3852 my $ShowReturn = 0;
3853 if($Compiler eq "MSVC"
3854 and $SymbolInfo{$Version}{$InfoId}{"Data"})
3855 {
3856 $ShowReturn=1;
3857 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04003858 elsif(defined $TemplateInstance{$Version}{"Func"}{$InfoId}
3859 and keys(%{$TemplateInstance{$Version}{"Func"}{$InfoId}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003860 {
3861 $ShowReturn=1;
3862 }
3863 if($ShowReturn)
3864 { # mangled names for template function specializations include return value
3865 if(my $ReturnId = $SymbolInfo{$Version}{$InfoId}{"Return"})
3866 {
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +04003867 my %RType = get_PureType($ReturnId, $TypeInfo{$Version});
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003868 my $ReturnName = unmangledFormat($RType{"Name"}, $Version);
3869 $PureSignature = $ReturnName." ".$PureSignature;
3870 }
3871 }
Andrey Ponomarenko9927e332012-10-19 10:50:48 +04003872 return ($Cache{"modelUnmangled"}{$Version}{$Compiler}{$InfoId} = formatName($PureSignature, "S"));
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003873}
3874
3875sub mangle_symbol($$$)
3876{ # mangling for simple methods
3877 # see gcc-4.6.0/gcc/cp/mangle.c
3878 my ($InfoId, $LibVersion, $Compiler) = @_;
3879 if($Cache{"mangle_symbol"}{$LibVersion}{$InfoId}{$Compiler}) {
3880 return $Cache{"mangle_symbol"}{$LibVersion}{$InfoId}{$Compiler};
3881 }
3882 my $Mangled = "";
3883 if($Compiler eq "GCC") {
Andrey Ponomarenko16934472012-03-29 15:37:04 +04003884 $Mangled = mangle_symbol_GCC($InfoId, $LibVersion);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003885 }
3886 elsif($Compiler eq "MSVC") {
Andrey Ponomarenko16934472012-03-29 15:37:04 +04003887 $Mangled = mangle_symbol_MSVC($InfoId, $LibVersion);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003888 }
3889 return ($Cache{"mangle_symbol"}{$LibVersion}{$InfoId}{$Compiler} = $Mangled);
3890}
3891
Andrey Ponomarenko16934472012-03-29 15:37:04 +04003892sub mangle_symbol_MSVC($$)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003893{
3894 my ($InfoId, $LibVersion) = @_;
3895 return "";
3896}
3897
Andrey Ponomarenko16934472012-03-29 15:37:04 +04003898sub mangle_symbol_GCC($$)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003899{ # see gcc-4.6.0/gcc/cp/mangle.c
3900 my ($InfoId, $LibVersion) = @_;
3901 my ($Mangled, $ClassId, $NameSpace) = ("_Z", 0, "");
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04003902 my $Return = $SymbolInfo{$LibVersion}{$InfoId}{"Return"};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003903 my %Repl = ();# SN_ replacements
3904 if($ClassId = $SymbolInfo{$LibVersion}{$InfoId}{"Class"})
3905 {
3906 my $MangledClass = mangle_param($ClassId, $LibVersion, \%Repl);
3907 if($MangledClass!~/\AN/) {
3908 $MangledClass = "N".$MangledClass;
3909 }
3910 else {
3911 $MangledClass=~s/E\Z//;
3912 }
3913 if($SymbolInfo{$LibVersion}{$InfoId}{"Volatile"}) {
3914 $MangledClass=~s/\AN/NV/;
3915 }
3916 if($SymbolInfo{$LibVersion}{$InfoId}{"Const"}) {
3917 $MangledClass=~s/\AN/NK/;
3918 }
3919 $Mangled .= $MangledClass;
3920 }
3921 elsif($NameSpace = $SymbolInfo{$LibVersion}{$InfoId}{"NameSpace"})
3922 { # mangled by name due to the absence of structured info
3923 my $MangledNS = mangle_ns($NameSpace, $LibVersion, \%Repl);
3924 if($MangledNS!~/\AN/) {
3925 $MangledNS = "N".$MangledNS;
3926 }
3927 else {
3928 $MangledNS=~s/E\Z//;
3929 }
3930 $Mangled .= $MangledNS;
3931 }
Andrey Ponomarenko07aea072012-11-12 16:15:07 +04003932 my ($ShortName, $TmplParams) = template_Base($SymbolInfo{$LibVersion}{$InfoId}{"ShortName"});
Andrey Ponomarenko16934472012-03-29 15:37:04 +04003933 my @TParams = ();
Andrey Ponomarenko35c44fd2012-06-18 17:50:25 +04003934 if(my @TPos = keys(%{$SymbolInfo{$LibVersion}{$InfoId}{"TParam"}}))
Andrey Ponomarenko16934472012-03-29 15:37:04 +04003935 { # parsing mode
Andrey Ponomarenko35c44fd2012-06-18 17:50:25 +04003936 foreach (@TPos) {
3937 push(@TParams, $SymbolInfo{$LibVersion}{$InfoId}{"TParam"}{$_}{"name"});
3938 }
Andrey Ponomarenko16934472012-03-29 15:37:04 +04003939 }
3940 elsif($TmplParams)
3941 { # remangling mode
3942 # support for old ABI dumps
Andrey Ponomarenko07aea072012-11-12 16:15:07 +04003943 @TParams = separate_Params($TmplParams, 0, 0);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003944 }
3945 if($SymbolInfo{$LibVersion}{$InfoId}{"Constructor"}) {
3946 $Mangled .= "C1";
3947 }
3948 elsif($SymbolInfo{$LibVersion}{$InfoId}{"Destructor"}) {
3949 $Mangled .= "D0";
3950 }
3951 elsif($ShortName)
3952 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04003953 if($SymbolInfo{$LibVersion}{$InfoId}{"Data"})
3954 {
Andrey Ponomarenko16934472012-03-29 15:37:04 +04003955 if(not $SymbolInfo{$LibVersion}{$InfoId}{"Class"}
Andrey Ponomarenko85043792012-05-14 16:48:07 +04003956 and isConstType($Return, $LibVersion))
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04003957 { # "const" global data is mangled as _ZL...
3958 $Mangled .= "L";
3959 }
3960 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003961 if($ShortName=~/\Aoperator(\W.*)\Z/)
3962 {
3963 my $Op = $1;
3964 $Op=~s/\A[ ]+//g;
3965 if(my $OpMngl = $OperatorMangling{$Op}) {
3966 $Mangled .= $OpMngl;
3967 }
3968 else { # conversion operator
3969 $Mangled .= "cv".mangle_param(getTypeIdByName($Op, $LibVersion), $LibVersion, \%Repl);
3970 }
3971 }
3972 else {
3973 $Mangled .= length($ShortName).$ShortName;
3974 }
3975 if(@TParams)
3976 { # templates
3977 $Mangled .= "I";
Andrey Ponomarenko1477d2c2012-11-12 18:55:45 +04003978 foreach my $TParam (@TParams) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003979 $Mangled .= mangle_template_param($TParam, $LibVersion, \%Repl);
3980 }
3981 $Mangled .= "E";
3982 }
3983 if(not $ClassId and @TParams) {
3984 add_substitution($ShortName, \%Repl, 0);
3985 }
3986 }
3987 if($ClassId or $NameSpace) {
3988 $Mangled .= "E";
3989 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +04003990 if(@TParams)
3991 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04003992 if($Return) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003993 $Mangled .= mangle_param($Return, $LibVersion, \%Repl);
3994 }
3995 }
3996 if(not $SymbolInfo{$LibVersion}{$InfoId}{"Data"})
3997 {
3998 my @Params = ();
3999 if(defined $SymbolInfo{$LibVersion}{$InfoId}{"Param"}
4000 and not $SymbolInfo{$LibVersion}{$InfoId}{"Destructor"}) {
4001 @Params = keys(%{$SymbolInfo{$LibVersion}{$InfoId}{"Param"}});
4002 }
4003 foreach my $ParamPos (sort {int($a) <=> int($b)} @Params)
4004 { # checking parameters
4005 my $ParamType_Id = $SymbolInfo{$LibVersion}{$InfoId}{"Param"}{$ParamPos}{"type"};
4006 $Mangled .= mangle_param($ParamType_Id, $LibVersion, \%Repl);
4007 }
4008 if(not @Params) {
4009 $Mangled .= "v";
4010 }
4011 }
4012 $Mangled = correct_incharge($InfoId, $LibVersion, $Mangled);
4013 $Mangled = write_stdcxx_substitution($Mangled);
4014 if($Mangled eq "_Z") {
4015 return "";
4016 }
4017 return $Mangled;
4018}
4019
4020sub correct_incharge($$$)
4021{
4022 my ($InfoId, $LibVersion, $Mangled) = @_;
4023 if($SymbolInfo{$LibVersion}{$InfoId}{"Constructor"})
4024 {
4025 if($MangledNames{$LibVersion}{$Mangled}) {
4026 $Mangled=~s/C1E/C2E/;
4027 }
4028 }
4029 elsif($SymbolInfo{$LibVersion}{$InfoId}{"Destructor"})
4030 {
4031 if($MangledNames{$LibVersion}{$Mangled}) {
4032 $Mangled=~s/D0E/D1E/;
4033 }
4034 if($MangledNames{$LibVersion}{$Mangled}) {
4035 $Mangled=~s/D1E/D2E/;
4036 }
4037 }
4038 return $Mangled;
4039}
4040
Andrey Ponomarenko07aea072012-11-12 16:15:07 +04004041sub template_Base($)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004042{ # NOTE: std::_Vector_base<mysqlpp::mysql_type_info>::_Vector_impl
Andrey Ponomarenko16934472012-03-29 15:37:04 +04004043 # NOTE: operators: >>, <<
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004044 my $Name = $_[0];
Andrey Ponomarenko16934472012-03-29 15:37:04 +04004045 if($Name!~/>\Z/ or $Name!~/</) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004046 return $Name;
4047 }
4048 my $TParams = $Name;
Andrey Ponomarenko16934472012-03-29 15:37:04 +04004049 while(my $CPos = find_center($TParams, "<"))
4050 { # search for the last <T>
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004051 $TParams = substr($TParams, $CPos);
4052 }
Andrey Ponomarenko16934472012-03-29 15:37:04 +04004053 if($TParams=~s/\A<(.+)>\Z/$1/) {
4054 $Name=~s/<\Q$TParams\E>\Z//;
4055 }
4056 else
4057 { # error
4058 $TParams = "";
4059 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004060 return ($Name, $TParams);
4061}
4062
4063sub get_sub_ns($)
4064{
4065 my $Name = $_[0];
4066 my @NS = ();
Andrey Ponomarenko16934472012-03-29 15:37:04 +04004067 while(my $CPos = find_center($Name, ":"))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004068 {
4069 push(@NS, substr($Name, 0, $CPos));
4070 $Name = substr($Name, $CPos);
4071 $Name=~s/\A:://;
4072 }
4073 return (join("::", @NS), $Name);
4074}
4075
4076sub mangle_ns($$$)
4077{
4078 my ($Name, $LibVersion, $Repl) = @_;
4079 if(my $Tid = $TName_Tid{$LibVersion}{$Name})
4080 {
4081 my $Mangled = mangle_param($Tid, $LibVersion, $Repl);
4082 $Mangled=~s/\AN(.+)E\Z/$1/;
4083 return $Mangled;
4084
4085 }
4086 else
4087 {
4088 my ($MangledNS, $SubNS) = ("", "");
4089 ($SubNS, $Name) = get_sub_ns($Name);
4090 if($SubNS) {
4091 $MangledNS .= mangle_ns($SubNS, $LibVersion, $Repl);
4092 }
4093 $MangledNS .= length($Name).$Name;
4094 add_substitution($MangledNS, $Repl, 0);
4095 return $MangledNS;
4096 }
4097}
4098
4099sub mangle_param($$$)
4100{
4101 my ($PTid, $LibVersion, $Repl) = @_;
4102 my ($MPrefix, $Mangled) = ("", "");
4103 my %ReplCopy = %{$Repl};
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04004104 my %BaseType = get_BaseType($PTid, $LibVersion);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004105 my $BaseType_Name = $BaseType{"Name"};
4106 if(not $BaseType_Name) {
4107 return "";
4108 }
Andrey Ponomarenko07aea072012-11-12 16:15:07 +04004109 my ($ShortName, $TmplParams) = template_Base($BaseType_Name);
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04004110 my $Suffix = get_BaseTypeQual($PTid, $LibVersion);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004111 while($Suffix=~s/\s*(const|volatile|restrict)\Z//g){};
4112 while($Suffix=~/(&|\*|const)\Z/)
4113 {
4114 if($Suffix=~s/[ ]*&\Z//) {
4115 $MPrefix .= "R";
4116 }
4117 if($Suffix=~s/[ ]*\*\Z//) {
4118 $MPrefix .= "P";
4119 }
4120 if($Suffix=~s/[ ]*const\Z//)
4121 {
4122 if($MPrefix=~/R|P/
4123 or $Suffix=~/&|\*/) {
4124 $MPrefix .= "K";
4125 }
4126 }
4127 if($Suffix=~s/[ ]*volatile\Z//) {
4128 $MPrefix .= "V";
4129 }
4130 #if($Suffix=~s/[ ]*restrict\Z//) {
4131 #$MPrefix .= "r";
4132 #}
4133 }
4134 if(my $Token = $IntrinsicMangling{$BaseType_Name}) {
4135 $Mangled .= $Token;
4136 }
4137 elsif($BaseType{"Type"}=~/(Class|Struct|Union|Enum)/)
4138 {
Andrey Ponomarenko16934472012-03-29 15:37:04 +04004139 my @TParams = ();
Andrey Ponomarenko35c44fd2012-06-18 17:50:25 +04004140 if(my @TPos = keys(%{$BaseType{"TParam"}}))
Andrey Ponomarenko16934472012-03-29 15:37:04 +04004141 { # parsing mode
Andrey Ponomarenko35c44fd2012-06-18 17:50:25 +04004142 foreach (@TPos) {
4143 push(@TParams, $BaseType{"TParam"}{$_}{"name"});
4144 }
Andrey Ponomarenko16934472012-03-29 15:37:04 +04004145 }
4146 elsif($TmplParams)
4147 { # remangling mode
4148 # support for old ABI dumps
Andrey Ponomarenko07aea072012-11-12 16:15:07 +04004149 @TParams = separate_Params($TmplParams, 0, 0);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004150 }
4151 my $MangledNS = "";
4152 my ($SubNS, $SName) = get_sub_ns($ShortName);
4153 if($SubNS) {
4154 $MangledNS .= mangle_ns($SubNS, $LibVersion, $Repl);
4155 }
4156 $MangledNS .= length($SName).$SName;
4157 if(@TParams) {
4158 add_substitution($MangledNS, $Repl, 0);
4159 }
4160 $Mangled .= "N".$MangledNS;
4161 if(@TParams)
4162 { # templates
4163 $Mangled .= "I";
4164 foreach my $TParam (@TParams) {
4165 $Mangled .= mangle_template_param($TParam, $LibVersion, $Repl);
4166 }
4167 $Mangled .= "E";
4168 }
4169 $Mangled .= "E";
4170 }
4171 elsif($BaseType{"Type"}=~/(FuncPtr|MethodPtr)/)
4172 {
4173 if($BaseType{"Type"} eq "MethodPtr") {
4174 $Mangled .= "M".mangle_param($BaseType{"Class"}, $LibVersion, $Repl)."F";
4175 }
4176 else {
4177 $Mangled .= "PF";
4178 }
4179 $Mangled .= mangle_param($BaseType{"Return"}, $LibVersion, $Repl);
4180 my @Params = keys(%{$BaseType{"Param"}});
4181 foreach my $Num (sort {int($a)<=>int($b)} @Params) {
4182 $Mangled .= mangle_param($BaseType{"Param"}{$Num}{"type"}, $LibVersion, $Repl);
4183 }
4184 if(not @Params) {
4185 $Mangled .= "v";
4186 }
4187 $Mangled .= "E";
4188 }
4189 elsif($BaseType{"Type"} eq "FieldPtr")
4190 {
4191 $Mangled .= "M".mangle_param($BaseType{"Class"}, $LibVersion, $Repl);
4192 $Mangled .= mangle_param($BaseType{"Return"}, $LibVersion, $Repl);
4193 }
4194 $Mangled = $MPrefix.$Mangled;# add prefix (RPK)
4195 if(my $Optimized = write_substitution($Mangled, \%ReplCopy))
4196 {
4197 if($Mangled eq $Optimized)
4198 {
4199 if($ShortName!~/::/)
4200 { # remove "N ... E"
4201 if($MPrefix) {
4202 $Mangled=~s/\A($MPrefix)N(.+)E\Z/$1$2/g;
4203 }
4204 else {
4205 $Mangled=~s/\AN(.+)E\Z/$1/g;
4206 }
4207 }
4208 }
4209 else {
4210 $Mangled = $Optimized;
4211 }
4212 }
4213 add_substitution($Mangled, $Repl, 1);
4214 return $Mangled;
4215}
4216
4217sub mangle_template_param($$$)
4218{ # types + literals
4219 my ($TParam, $LibVersion, $Repl) = @_;
4220 if(my $TPTid = $TName_Tid{$LibVersion}{$TParam}) {
4221 return mangle_param($TPTid, $LibVersion, $Repl);
4222 }
4223 elsif($TParam=~/\A(\d+)(\w+)\Z/)
4224 { # class_name<1u>::method(...)
4225 return "L".$IntrinsicMangling{$ConstantSuffixR{$2}}.$1."E";
4226 }
4227 elsif($TParam=~/\A\(([\w ]+)\)(\d+)\Z/)
4228 { # class_name<(signed char)1>::method(...)
4229 return "L".$IntrinsicMangling{$1}.$2."E";
4230 }
4231 elsif($TParam eq "true")
4232 { # class_name<true>::method(...)
4233 return "Lb1E";
4234 }
4235 elsif($TParam eq "false")
4236 { # class_name<true>::method(...)
4237 return "Lb0E";
4238 }
4239 else { # internal error
4240 return length($TParam).$TParam;
4241 }
4242}
4243
4244sub add_substitution($$$)
4245{
4246 my ($Value, $Repl, $Rec) = @_;
4247 if($Rec)
4248 { # subtypes
4249 my @Subs = ($Value);
4250 while($Value=~s/\A(R|P|K)//) {
4251 push(@Subs, $Value);
4252 }
4253 foreach (reverse(@Subs)) {
4254 add_substitution($_, $Repl, 0);
4255 }
4256 return;
4257 }
4258 return if($Value=~/\AS(\d*)_\Z/);
4259 $Value=~s/\AN(.+)E\Z/$1/g;
4260 return if(defined $Repl->{$Value});
4261 return if(length($Value)<=1);
4262 return if($StdcxxMangling{$Value});
4263 # check for duplicates
4264 my $Base = $Value;
4265 foreach my $Type (sort {$Repl->{$a}<=>$Repl->{$b}} sort keys(%{$Repl}))
4266 {
4267 my $Num = $Repl->{$Type};
4268 my $Replace = macro_mangle($Num);
4269 $Base=~s/\Q$Replace\E/$Type/;
4270 }
4271 if(my $OldNum = $Repl->{$Base})
4272 {
4273 $Repl->{$Value} = $OldNum;
4274 return;
4275 }
4276 my @Repls = sort {$b<=>$a} values(%{$Repl});
4277 if(@Repls) {
4278 $Repl->{$Value} = $Repls[0]+1;
4279 }
4280 else {
4281 $Repl->{$Value} = -1;
4282 }
4283 # register duplicates
4284 # upward
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04004285 $Base = $Value;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004286 foreach my $Type (sort {$Repl->{$a}<=>$Repl->{$b}} sort keys(%{$Repl}))
4287 {
4288 next if($Base eq $Type);
4289 my $Num = $Repl->{$Type};
4290 my $Replace = macro_mangle($Num);
4291 $Base=~s/\Q$Type\E/$Replace/;
4292 $Repl->{$Base} = $Repl->{$Value};
4293 }
4294}
4295
4296sub macro_mangle($)
4297{
4298 my $Num = $_[0];
4299 if($Num==-1) {
4300 return "S_";
4301 }
4302 else
4303 {
4304 my $Code = "";
4305 if($Num<10)
4306 { # S0_, S1_, S2_, ...
4307 $Code = $Num;
4308 }
4309 elsif($Num>=10 and $Num<=35)
4310 { # SA_, SB_, SC_, ...
4311 $Code = chr(55+$Num);
4312 }
4313 else
4314 { # S10_, S11_, S12_
4315 $Code = $Num-26; # 26 is length of english alphabet
4316 }
4317 return "S".$Code."_";
4318 }
4319}
4320
4321sub write_stdcxx_substitution($)
4322{
4323 my $Mangled = $_[0];
4324 if($StdcxxMangling{$Mangled}) {
4325 return $StdcxxMangling{$Mangled};
4326 }
4327 else
4328 {
4329 my @Repls = keys(%StdcxxMangling);
4330 @Repls = sort {length($b)<=>length($a)} sort {$b cmp $a} @Repls;
4331 foreach my $MangledType (@Repls)
4332 {
4333 my $Replace = $StdcxxMangling{$MangledType};
4334 #if($Mangled!~/$Replace/) {
4335 $Mangled=~s/N\Q$MangledType\EE/$Replace/g;
4336 $Mangled=~s/\Q$MangledType\E/$Replace/g;
4337 #}
4338 }
4339 }
4340 return $Mangled;
4341}
4342
4343sub write_substitution($$)
4344{
4345 my ($Mangled, $Repl) = @_;
4346 if(defined $Repl->{$Mangled}
4347 and my $MnglNum = $Repl->{$Mangled}) {
4348 $Mangled = macro_mangle($MnglNum);
4349 }
4350 else
4351 {
4352 my @Repls = keys(%{$Repl});
4353 #@Repls = sort {$Repl->{$a}<=>$Repl->{$b}} @Repls;
4354 # FIXME: how to apply replacements? by num or by pos
4355 @Repls = sort {length($b)<=>length($a)} sort {$b cmp $a} @Repls;
4356 foreach my $MangledType (@Repls)
4357 {
4358 my $Replace = macro_mangle($Repl->{$MangledType});
4359 if($Mangled!~/$Replace/) {
4360 $Mangled=~s/N\Q$MangledType\EE/$Replace/g;
4361 $Mangled=~s/\Q$MangledType\E/$Replace/g;
4362 }
4363 }
4364 }
4365 return $Mangled;
4366}
4367
4368sub delete_keywords($)
4369{
4370 my $TypeName = $_[0];
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04004371 $TypeName=~s/\b(enum|struct|union|class) //g;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004372 return $TypeName;
4373}
4374
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004375sub uncover_typedefs($$)
4376{
4377 my ($TypeName, $LibVersion) = @_;
4378 return "" if(not $TypeName);
4379 if(defined $Cache{"uncover_typedefs"}{$LibVersion}{$TypeName}) {
4380 return $Cache{"uncover_typedefs"}{$LibVersion}{$TypeName};
4381 }
Andrey Ponomarenko9927e332012-10-19 10:50:48 +04004382 my ($TypeName_New, $TypeName_Pre) = (formatName($TypeName, "T"), "");
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004383 while($TypeName_New ne $TypeName_Pre)
4384 {
4385 $TypeName_Pre = $TypeName_New;
4386 my $TypeName_Copy = $TypeName_New;
4387 my %Words = ();
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04004388 while($TypeName_Copy=~s/\b([a-z_]([\w:]*\w|))\b//io)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004389 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04004390 if(not $Intrinsic_Keywords{$1}) {
4391 $Words{$1} = 1;
4392 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004393 }
4394 foreach my $Word (keys(%Words))
4395 {
4396 my $BaseType_Name = $Typedef_BaseName{$LibVersion}{$Word};
4397 next if(not $BaseType_Name);
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04004398 next if($TypeName_New=~/\b(struct|union|enum)\s\Q$Word\E\b/);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004399 if($BaseType_Name=~/\([\*]+\)/)
4400 { # FuncPtr
4401 if($TypeName_New=~/\Q$Word\E(.*)\Z/)
4402 {
4403 my $Type_Suffix = $1;
4404 $TypeName_New = $BaseType_Name;
4405 if($TypeName_New=~s/\(([\*]+)\)/($1 $Type_Suffix)/) {
Andrey Ponomarenko9927e332012-10-19 10:50:48 +04004406 $TypeName_New = formatName($TypeName_New, "T");
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004407 }
4408 }
4409 }
4410 else
4411 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04004412 if($TypeName_New=~s/\b\Q$Word\E\b/$BaseType_Name/g) {
Andrey Ponomarenko9927e332012-10-19 10:50:48 +04004413 $TypeName_New = formatName($TypeName_New, "T");
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004414 }
4415 }
4416 }
4417 }
4418 return ($Cache{"uncover_typedefs"}{$LibVersion}{$TypeName} = $TypeName_New);
4419}
4420
4421sub isInternal($)
4422{
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04004423 if($_[0] and my $Info = $LibInfo{$Version}{"info"}{$_[0]})
4424 {
4425 if($Info=~/mngl[ ]*:[ ]*@(\d+) /)
4426 {
4427 if($LibInfo{$Version}{"info"}{$1}=~/\*[ ]*INTERNAL[ ]*\*/)
4428 { # _ZN7mysqlpp8DateTimeC1ERKS0_ *INTERNAL*
4429 return 1;
4430 }
4431 }
4432 }
4433 return 0;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004434}
4435
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04004436sub getDataVal($$)
4437{
4438 my ($InfoId, $TypeId) = @_;
4439 if(my $Info = $LibInfo{$Version}{"info"}{$InfoId})
4440 {
4441 if($Info=~/init[ ]*:[ ]*@(\d+) /)
4442 {
4443 if(defined $LibInfo{$Version}{"info_type"}{$1}
4444 and $LibInfo{$Version}{"info_type"}{$1} eq "nop_expr")
4445 { # char const* data = "str"
4446 # NOTE: disabled
4447 if(my $NopExpr = $LibInfo{$Version}{"info"}{$1})
4448 {
4449 if($NopExpr=~/op 0[ ]*:[ ]*@(\d+) /)
4450 {
4451 if(defined $LibInfo{$Version}{"info_type"}{$1}
4452 and $LibInfo{$Version}{"info_type"}{$1} eq "addr_expr")
4453 {
4454 if(my $AddrExpr = $LibInfo{$Version}{"info"}{$1})
4455 {
4456 if($AddrExpr=~/op 0[ ]*:[ ]*@(\d+) /)
4457 {
4458 return getInitVal($1, $TypeId);
4459 }
4460 }
4461 }
4462 }
4463 }
4464 }
4465 else {
4466 return getInitVal($1, $TypeId);
4467 }
4468 }
4469 }
4470 return undef;
4471}
4472
4473sub getInitVal($$)
4474{
4475 my ($InfoId, $TypeId) = @_;
4476 if(my $Info = $LibInfo{$Version}{"info"}{$InfoId})
4477 {
4478 if(my $InfoType = $LibInfo{$Version}{"info_type"}{$InfoId})
4479 {
4480 if($InfoType eq "integer_cst")
4481 {
4482 my $Val = getNodeIntCst($InfoId);
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04004483 if($TypeId and $TypeInfo{$Version}{$TypeId}{"Name"}=~/\Achar(| const)\Z/)
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04004484 { # characters
4485 $Val = chr($Val);
4486 }
4487 return $Val;
4488 }
4489 elsif($InfoType eq "string_cst") {
4490 return getNodeStrCst($InfoId);
4491 }
Andrey Ponomarenko01117f12012-06-26 12:23:02 +04004492 elsif($InfoType eq "var_decl")
4493 {
4494 if(my $Name = getNodeStrCst(getTreeAttr_Mngl($InfoId))) {
4495 return $Name;
4496 }
4497 }
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04004498 }
4499 }
4500 return undef;
4501}
4502
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004503sub set_Class_And_Namespace($)
4504{
4505 my $InfoId = $_[0];
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04004506 if(my $Info = $LibInfo{$Version}{"info"}{$InfoId})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004507 {
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04004508 if($Info=~/scpe[ ]*:[ ]*@(\d+) /)
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04004509 {
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04004510 my $NSInfoId = $1;
4511 if(my $InfoType = $LibInfo{$Version}{"info_type"}{$NSInfoId})
4512 {
4513 if($InfoType eq "namespace_decl") {
4514 $SymbolInfo{$Version}{$InfoId}{"NameSpace"} = getNameSpace($InfoId);
4515 }
4516 elsif($InfoType eq "record_type") {
4517 $SymbolInfo{$Version}{$InfoId}{"Class"} = $NSInfoId;
4518 }
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04004519 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004520 }
4521 }
4522 if($SymbolInfo{$Version}{$InfoId}{"Class"}
4523 or $SymbolInfo{$Version}{$InfoId}{"NameSpace"})
4524 { # identify language
4525 setLanguage($Version, "C++");
4526 }
4527}
4528
4529sub debugType($$)
4530{
4531 my ($Tid, $LibVersion) = @_;
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04004532 my %Type = get_Type($Tid, $LibVersion);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004533 printMsg("INFO", Dumper(\%Type));
4534}
4535
4536sub debugMangling($)
4537{
4538 my $LibVersion = $_[0];
4539 my %Mangled = ();
4540 foreach my $InfoId (keys(%{$SymbolInfo{$LibVersion}}))
4541 {
4542 if(my $Mngl = $SymbolInfo{$LibVersion}{$InfoId}{"MnglName"})
4543 {
4544 if($Mngl=~/\A(_Z|\?)/) {
4545 $Mangled{$Mngl}=$InfoId;
4546 }
4547 }
4548 }
4549 translateSymbols(keys(%Mangled), $LibVersion);
4550 foreach my $Mngl (keys(%Mangled))
4551 {
Andrey Ponomarenko85043792012-05-14 16:48:07 +04004552 my $U1 = modelUnmangled($Mangled{$Mngl}, "GCC");
4553 my $U2 = $tr_name{$Mngl};
4554 if($U1 ne $U2) {
4555 printMsg("INFO", "INCORRECT MANGLING:\n $Mngl\n $U1\n $U2\n");
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004556 }
4557 }
4558}
4559
4560sub linkSymbol($)
4561{ # link symbols from shared libraries
4562 # with the symbols from header files
4563 my $InfoId = $_[0];
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004564 # try to mangle symbol
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04004565 if((not check_gcc($GCC_PATH, "4") and $SymbolInfo{$Version}{$InfoId}{"Class"})
4566 or (check_gcc($GCC_PATH, "4") and not $SymbolInfo{$Version}{$InfoId}{"Class"}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004567 { # 1. GCC 3.x doesn't mangle class methods names in the TU dump (only functions and global data)
4568 # 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 +04004569 if(not $CheckHeadersOnly)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004570 {
4571 if(my $Mangled = $mangled_name_gcc{modelUnmangled($InfoId, "GCC")}) {
4572 return correct_incharge($InfoId, $Version, $Mangled);
4573 }
4574 }
Andrey Ponomarenko16934472012-03-29 15:37:04 +04004575 if($CheckHeadersOnly
4576 or not $BinaryOnly)
4577 { # 1. --headers-only mode
4578 # 2. not mangled src-only symbols
4579 if(my $Mangled = mangle_symbol($InfoId, $Version, "GCC")) {
4580 return $Mangled;
4581 }
4582 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004583 }
4584 return "";
4585}
4586
4587sub setLanguage($$)
4588{
4589 my ($LibVersion, $Lang) = @_;
4590 if(not $UserLang) {
4591 $COMMON_LANGUAGE{$LibVersion} = $Lang;
4592 }
4593}
4594
4595sub getSymbolInfo($)
4596{
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04004597 my $InfoId = $_[0];
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04004598 if(isInternal($InfoId)) {
4599 return;
4600 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04004601 ($SymbolInfo{$Version}{$InfoId}{"Header"}, $SymbolInfo{$Version}{$InfoId}{"Line"}) = getLocation($InfoId);
4602 if(not $SymbolInfo{$Version}{$InfoId}{"Header"}
Andrey Ponomarenkoa01311b2012-06-08 17:20:02 +04004603 or isBuiltIn($SymbolInfo{$Version}{$InfoId}{"Header"}))
4604 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04004605 delete($SymbolInfo{$Version}{$InfoId});
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004606 return;
4607 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04004608 setFuncAccess($InfoId);
4609 setFuncKind($InfoId);
Andrey Ponomarenkoa01311b2012-06-08 17:20:02 +04004610 if($SymbolInfo{$Version}{$InfoId}{"PseudoTemplate"})
4611 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04004612 delete($SymbolInfo{$Version}{$InfoId});
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004613 return;
4614 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04004615 $SymbolInfo{$Version}{$InfoId}{"Type"} = getFuncType($InfoId);
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04004616 if($SymbolInfo{$Version}{$InfoId}{"Return"} = getFuncReturn($InfoId))
4617 {
4618 if(not $TypeInfo{$Version}{$SymbolInfo{$Version}{$InfoId}{"Return"}}{"Name"})
4619 { # templates
4620 delete($SymbolInfo{$Version}{$InfoId});
4621 return;
4622 }
4623 }
4624 if(my $Rid = $SymbolInfo{$Version}{$InfoId}{"Return"})
4625 {
4626 if(defined $MissedTypedef{$Version}{$Rid})
4627 {
4628 if(my $AddedTid = $MissedTypedef{$Version}{$Rid}{"Tid"}) {
4629 $SymbolInfo{$Version}{$InfoId}{"Return"} = $AddedTid;
4630 }
4631 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004632 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04004633 if(not $SymbolInfo{$Version}{$InfoId}{"Return"}) {
4634 delete($SymbolInfo{$Version}{$InfoId}{"Return"});
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004635 }
Andrey Ponomarenkoa01311b2012-06-08 17:20:02 +04004636 my $Orig = getFuncOrig($InfoId);
4637 $SymbolInfo{$Version}{$InfoId}{"ShortName"} = getFuncShortName($Orig);
4638 if($SymbolInfo{$Version}{$InfoId}{"ShortName"}=~/\._/)
4639 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04004640 delete($SymbolInfo{$Version}{$InfoId});
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004641 return;
4642 }
Andrey Ponomarenkoa01311b2012-06-08 17:20:02 +04004643
4644 if(defined $TemplateInstance{$Version}{"Func"}{$Orig})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004645 {
Andrey Ponomarenkoa01311b2012-06-08 17:20:02 +04004646 my @TParams = getTParams($Orig, "Func");
4647 if(not @TParams)
4648 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04004649 delete($SymbolInfo{$Version}{$InfoId});
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004650 return;
4651 }
Andrey Ponomarenko16934472012-03-29 15:37:04 +04004652 foreach my $Pos (0 .. $#TParams) {
4653 $SymbolInfo{$Version}{$InfoId}{"TParam"}{$Pos}{"name"}=$TParams[$Pos];
4654 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004655 my $PrmsInLine = join(", ", @TParams);
Andrey Ponomarenko16934472012-03-29 15:37:04 +04004656 if($SymbolInfo{$Version}{$InfoId}{"ShortName"}=~/\Aoperator\W+\Z/)
4657 { # operator<< <T>, operator>> <T>
4658 $SymbolInfo{$Version}{$InfoId}{"ShortName"} .= " ";
4659 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04004660 $SymbolInfo{$Version}{$InfoId}{"ShortName"} .= "<".$PrmsInLine.">";
Andrey Ponomarenko9927e332012-10-19 10:50:48 +04004661 $SymbolInfo{$Version}{$InfoId}{"ShortName"} = formatName($SymbolInfo{$Version}{$InfoId}{"ShortName"}, "S");
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004662 }
4663 else
4664 { # support for GCC 3.4
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04004665 $SymbolInfo{$Version}{$InfoId}{"ShortName"}=~s/<.+>\Z//;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004666 }
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +04004667 if(my $MnglName = getTreeStr(getTreeAttr_Mngl($InfoId)))
4668 {
4669 if($OSgroup eq "windows")
4670 { # cut the offset
4671 $MnglName=~s/\@\d+\Z//g;
4672 }
4673 $SymbolInfo{$Version}{$InfoId}{"MnglName"} = $MnglName;
4674
4675 # NOTE: mangling of some symbols may change depending on GCC version
4676 # GCC 4.6: _ZN28QExplicitlySharedDataPointerI11QPixmapDataEC2IT_EERKS_IT_E
4677 # GCC 4.7: _ZN28QExplicitlySharedDataPointerI11QPixmapDataEC2ERKS1_
4678 }
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04004679
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04004680 if($SymbolInfo{$Version}{$InfoId}{"MnglName"}
Andrey Ponomarenko9927e332012-10-19 10:50:48 +04004681 and index($SymbolInfo{$Version}{$InfoId}{"MnglName"}, "_Z")!=0)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004682 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04004683 delete($SymbolInfo{$Version}{$InfoId});
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004684 return;
4685 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04004686 if(not $SymbolInfo{$Version}{$InfoId}{"Destructor"})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004687 { # destructors have an empty parameter list
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04004688 my $Skip = setFuncParams($InfoId);
Andrey Ponomarenko07aea072012-11-12 16:15:07 +04004689 if($Skip)
4690 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04004691 delete($SymbolInfo{$Version}{$InfoId});
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004692 return;
4693 }
4694 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04004695 set_Class_And_Namespace($InfoId);
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04004696 if(my $ClassId = $SymbolInfo{$Version}{$InfoId}{"Class"})
4697 {
4698 if(not $TypeInfo{$Version}{$ClassId}{"Name"})
4699 { # templates
4700 delete($SymbolInfo{$Version}{$InfoId});
4701 return;
4702 }
4703 }
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04004704 if(not $CheckHeadersOnly)
4705 {
4706 if($SymbolInfo{$Version}{$InfoId}{"Type"} eq "Function"
4707 and not $SymbolInfo{$Version}{$InfoId}{"Class"}
4708 and link_symbol($SymbolInfo{$Version}{$InfoId}{"ShortName"}, $Version, "-Deps"))
4709 { # functions (C++): not mangled in library, but are mangled in TU dump
4710 if(not $SymbolInfo{$Version}{$InfoId}{"MnglName"}
4711 or not link_symbol($SymbolInfo{$Version}{$InfoId}{"MnglName"}, $Version, "-Deps")) {
4712 $SymbolInfo{$Version}{$InfoId}{"MnglName"} = $SymbolInfo{$Version}{$InfoId}{"ShortName"};
4713 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004714 }
4715 }
Andrey Ponomarenko35c44fd2012-06-18 17:50:25 +04004716 if($LibInfo{$Version}{"info"}{$InfoId}=~/ lang:[ ]*C /i)
4717 { # extern "C"
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04004718 $SymbolInfo{$Version}{$InfoId}{"Lang"} = "C";
Andrey Ponomarenko35c44fd2012-06-18 17:50:25 +04004719 $SymbolInfo{$Version}{$InfoId}{"MnglName"} = $SymbolInfo{$Version}{$InfoId}{"ShortName"};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004720 }
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04004721 if($UserLang and $UserLang eq "C")
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004722 { # --lang=C option
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04004723 $SymbolInfo{$Version}{$InfoId}{"MnglName"} = $SymbolInfo{$Version}{$InfoId}{"ShortName"};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004724 }
4725 if($COMMON_LANGUAGE{$Version} eq "C++")
4726 { # correct mangled & short names
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04004727 # C++ or --headers-only mode
4728 if($SymbolInfo{$Version}{$InfoId}{"ShortName"}=~/\A__(comp|base|deleting)_(c|d)tor\Z/)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004729 { # support for old GCC versions: reconstruct real names for constructors and destructors
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04004730 $SymbolInfo{$Version}{$InfoId}{"ShortName"} = getNameByInfo(getTypeDeclId($SymbolInfo{$Version}{$InfoId}{"Class"}));
4731 $SymbolInfo{$Version}{$InfoId}{"ShortName"}=~s/<.+>\Z//;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004732 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04004733 if(not $SymbolInfo{$Version}{$InfoId}{"MnglName"})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004734 { # try to mangle symbol (link with libraries)
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04004735 if(my $Mangled = linkSymbol($InfoId)) {
4736 $SymbolInfo{$Version}{$InfoId}{"MnglName"} = $Mangled;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004737 }
4738 }
4739 if($OStarget eq "windows")
4740 { # link MS C++ symbols from library with GCC symbols from headers
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04004741 if(my $Mangled1 = $mangled_name{$Version}{modelUnmangled($InfoId, "MSVC")})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004742 { # exported symbols
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04004743 $SymbolInfo{$Version}{$InfoId}{"MnglName"} = $Mangled1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004744 }
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04004745 elsif(my $Mangled2 = mangle_symbol($InfoId, $Version, "MSVC"))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004746 { # pure virtual symbols
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04004747 $SymbolInfo{$Version}{$InfoId}{"MnglName"} = $Mangled2;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004748 }
4749 }
4750 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04004751 if(not $SymbolInfo{$Version}{$InfoId}{"MnglName"})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004752 { # can't detect symbol name
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04004753 delete($SymbolInfo{$Version}{$InfoId});
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004754 return;
4755 }
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04004756 if(not $SymbolInfo{$Version}{$InfoId}{"Constructor"}
Andrey Ponomarenkoa01311b2012-06-08 17:20:02 +04004757 and my $Spec = getVirtSpec($Orig))
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04004758 { # identify virtual and pure virtual functions
4759 # NOTE: constructors cannot be virtual
4760 # NOTE: in GCC 4.7 D1 destructors have no virtual spec
4761 # in the TU dump, so taking it from the original symbol
4762 if(not ($SymbolInfo{$Version}{$InfoId}{"Destructor"}
4763 and $SymbolInfo{$Version}{$InfoId}{"MnglName"}=~/D2E/))
4764 { # NOTE: D2 destructors are not present in a v-table
4765 $SymbolInfo{$Version}{$InfoId}{$Spec} = 1;
4766 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004767 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04004768 if(isInline($InfoId)) {
4769 $SymbolInfo{$Version}{$InfoId}{"InLine"} = 1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004770 }
Andrey Ponomarenko82bc2572012-11-14 13:55:30 +04004771 if(hasThrow($InfoId)) {
Andrey Ponomarenkoe3d6bf02012-11-14 11:49:09 +04004772 $SymbolInfo{$Version}{$InfoId}{"Throw"} = 1;
4773 }
Andrey Ponomarenkob8d203d2012-05-25 18:11:07 +04004774 if($LibInfo{$Version}{"info"}{$InfoId}=~/ artificial /i) {
4775 $SymbolInfo{$Version}{$InfoId}{"Artificial"} = 1;
4776 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04004777 if($SymbolInfo{$Version}{$InfoId}{"Constructor"}
4778 and my $ClassId = $SymbolInfo{$Version}{$InfoId}{"Class"})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004779 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04004780 if(not $SymbolInfo{$Version}{$InfoId}{"InLine"}
Andrey Ponomarenkob8d203d2012-05-25 18:11:07 +04004781 and not $SymbolInfo{$Version}{$InfoId}{"Artificial"})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004782 { # inline or auto-generated constructor
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04004783 delete($TypeInfo{$Version}{$ClassId}{"Copied"});
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004784 }
4785 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +04004786 if(my $Symbol = $SymbolInfo{$Version}{$InfoId}{"MnglName"})
4787 {
Andrey Ponomarenko35c44fd2012-06-18 17:50:25 +04004788 if(not selectSymbol($Symbol, $SymbolInfo{$Version}{$InfoId}, "Dump", $Version))
4789 { # non-target symbols
4790 delete($SymbolInfo{$Version}{$InfoId});
4791 return;
Andrey Ponomarenko85043792012-05-14 16:48:07 +04004792 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004793 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04004794 if($SymbolInfo{$Version}{$InfoId}{"Type"} eq "Method"
4795 or $SymbolInfo{$Version}{$InfoId}{"Constructor"}
4796 or $SymbolInfo{$Version}{$InfoId}{"Destructor"}
4797 or $SymbolInfo{$Version}{$InfoId}{"Class"})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004798 {
Andrey Ponomarenko9927e332012-10-19 10:50:48 +04004799 if($SymbolInfo{$Version}{$InfoId}{"MnglName"}!~/\A(_Z|\?)/)
4800 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04004801 delete($SymbolInfo{$Version}{$InfoId});
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004802 return;
4803 }
4804 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04004805 if($SymbolInfo{$Version}{$InfoId}{"MnglName"})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004806 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04004807 if($MangledNames{$Version}{$SymbolInfo{$Version}{$InfoId}{"MnglName"}})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004808 { # one instance for one mangled name only
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04004809 delete($SymbolInfo{$Version}{$InfoId});
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004810 return;
4811 }
4812 else {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04004813 $MangledNames{$Version}{$SymbolInfo{$Version}{$InfoId}{"MnglName"}} = 1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004814 }
4815 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04004816 if($SymbolInfo{$Version}{$InfoId}{"Constructor"}
4817 or $SymbolInfo{$Version}{$InfoId}{"Destructor"}) {
4818 delete($SymbolInfo{$Version}{$InfoId}{"Return"});
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004819 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04004820 if($SymbolInfo{$Version}{$InfoId}{"MnglName"}=~/\A(_Z|\?)/
4821 and $SymbolInfo{$Version}{$InfoId}{"Class"})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004822 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04004823 if($SymbolInfo{$Version}{$InfoId}{"Type"} eq "Function")
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004824 { # static methods
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04004825 $SymbolInfo{$Version}{$InfoId}{"Static"} = 1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004826 }
4827 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04004828 if(getFuncLink($InfoId) eq "Static") {
4829 $SymbolInfo{$Version}{$InfoId}{"Static"} = 1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004830 }
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04004831 if($SymbolInfo{$Version}{$InfoId}{"MnglName"}=~/\A(_Z|\?)/)
4832 {
4833 if(my $Unmangled = $tr_name{$SymbolInfo{$Version}{$InfoId}{"MnglName"}})
4834 {
Andrey Ponomarenko9927e332012-10-19 10:50:48 +04004835 if($Unmangled=~/\.\_\d/)
4836 {
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04004837 delete($SymbolInfo{$Version}{$InfoId});
4838 return;
4839 }
4840 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004841 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04004842 delete($SymbolInfo{$Version}{$InfoId}{"Type"});
4843 if($SymbolInfo{$Version}{$InfoId}{"MnglName"}=~/\A_ZN(V|)K/) {
4844 $SymbolInfo{$Version}{$InfoId}{"Const"} = 1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004845 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04004846 if($SymbolInfo{$Version}{$InfoId}{"MnglName"}=~/\A_ZN(K|)V/) {
4847 $SymbolInfo{$Version}{$InfoId}{"Volatile"} = 1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004848 }
Andrey Ponomarenko07aea072012-11-12 16:15:07 +04004849
4850 if($WeakSymbols{$Version}{$SymbolInfo{$Version}{$InfoId}{"MnglName"}}) {
4851 $SymbolInfo{$Version}{$InfoId}{"Weak"} = 1;
4852 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004853}
4854
4855sub isInline($)
4856{ # "body: undefined" in the tree
4857 # -fkeep-inline-functions GCC option should be specified
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04004858 if($_[0] and my $Info = $LibInfo{$Version}{"info"}{$_[0]})
4859 {
4860 if($Info=~/ undefined /i) {
4861 return 0;
4862 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004863 }
4864 return 1;
4865}
4866
Andrey Ponomarenkoe3d6bf02012-11-14 11:49:09 +04004867sub hasThrow($)
4868{
4869 if($_[0] and my $Info = $LibInfo{$Version}{"info"}{$_[0]})
4870 {
4871 if($Info=~/type[ ]*:[ ]*@(\d+) /) {
4872 return getTreeAttr_Unql($1, "unql");
4873 }
4874 }
4875 return 1;
4876}
4877
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004878sub getTypeId($)
4879{
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04004880 if($_[0] and my $Info = $LibInfo{$Version}{"info"}{$_[0]})
4881 {
4882 if($Info=~/type[ ]*:[ ]*@(\d+) /) {
4883 return $1;
4884 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004885 }
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04004886 return "";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004887}
4888
4889sub setTypeMemb($$)
4890{
4891 my ($TypeId, $TypeAttr) = @_;
4892 my $TypeType = $TypeAttr->{"Type"};
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04004893 my ($Pos, $UnnamedPos) = (0, 0);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004894 if($TypeType eq "Enum")
4895 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04004896 my $TypeMembInfoId = getTreeAttr_Csts($TypeId);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004897 while($TypeMembInfoId)
4898 {
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04004899 $TypeAttr->{"Memb"}{$Pos}{"value"} = getEnumMembVal($TypeMembInfoId);
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04004900 my $MembName = getTreeStr(getTreeAttr_Purp($TypeMembInfoId));
4901 $TypeAttr->{"Memb"}{$Pos}{"name"} = $MembName;
4902 $EnumMembName_Id{$Version}{getTreeAttr_Valu($TypeMembInfoId)} = ($TypeAttr->{"NameSpace"})?$TypeAttr->{"NameSpace"}."::".$MembName:$MembName;
4903 $TypeMembInfoId = getNextElem($TypeMembInfoId);
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04004904 $Pos += 1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004905 }
4906 }
4907 elsif($TypeType=~/\A(Struct|Class|Union)\Z/)
4908 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04004909 my $TypeMembInfoId = getTreeAttr_Flds($TypeId);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004910 while($TypeMembInfoId)
4911 {
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04004912 my $IType = $LibInfo{$Version}{"info_type"}{$TypeMembInfoId};
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04004913 my $MInfo = $LibInfo{$Version}{"info"}{$TypeMembInfoId};
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04004914 if(not $IType or $IType ne "field_decl")
4915 { # search for fields, skip other stuff in the declaration
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04004916 $TypeMembInfoId = getNextElem($TypeMembInfoId);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004917 next;
4918 }
Andrey Ponomarenko01117f12012-06-26 12:23:02 +04004919 my $StructMembName = getTreeStr(getTreeAttr_Name($TypeMembInfoId));
4920 if(index($StructMembName, "_vptr.")!=-1)
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04004921 { # virtual tables
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04004922 $TypeMembInfoId = getNextElem($TypeMembInfoId);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004923 next;
4924 }
4925 if(not $StructMembName)
4926 { # unnamed fields
Andrey Ponomarenko01117f12012-06-26 12:23:02 +04004927 if(index($TypeAttr->{"Name"}, "_type_info_pseudo")==-1)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004928 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04004929 my $UnnamedTid = getTreeAttr_Type($TypeMembInfoId);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004930 my $UnnamedTName = getNameByInfo(getTypeDeclId($UnnamedTid));
4931 if(isAnon($UnnamedTName))
4932 { # rename unnamed fields to unnamed0, unnamed1, ...
4933 $StructMembName = "unnamed".($UnnamedPos++);
4934 }
4935 }
4936 }
4937 if(not $StructMembName)
4938 { # unnamed fields and base classes
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04004939 $TypeMembInfoId = getNextElem($TypeMembInfoId);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004940 next;
4941 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04004942 my $MembTypeId = getTreeAttr_Type($TypeMembInfoId);
4943 if(defined $MissedTypedef{$Version}{$MembTypeId})
4944 {
4945 if(my $AddedTid = $MissedTypedef{$Version}{$MembTypeId}{"Tid"}) {
4946 $MembTypeId = $AddedTid;
4947 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004948 }
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04004949 $TypeAttr->{"Memb"}{$Pos}{"type"} = $MembTypeId;
4950 $TypeAttr->{"Memb"}{$Pos}{"name"} = $StructMembName;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004951 if((my $Access = getTreeAccess($TypeMembInfoId)) ne "public")
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04004952 { # marked only protected and private, public by default
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04004953 $TypeAttr->{"Memb"}{$Pos}{"access"} = $Access;
4954 }
4955 if($MInfo=~/spec:\s*mutable /)
4956 { # mutable fields
4957 $TypeAttr->{"Memb"}{$Pos}{"mutable"} = 1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004958 }
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +04004959 if(my $Algn = getAlgn($TypeMembInfoId)) {
4960 $TypeAttr->{"Memb"}{$Pos}{"algn"} = $Algn;
4961 }
4962 if(my $BFSize = getBitField($TypeMembInfoId))
4963 { # in bits
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04004964 $TypeAttr->{"Memb"}{$Pos}{"bitfield"} = $BFSize;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004965 }
4966 else
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +04004967 { # in bytes
4968 $TypeAttr->{"Memb"}{$Pos}{"algn"} /= $BYTE_SIZE;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004969 }
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +04004970
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04004971 $TypeMembInfoId = getNextElem($TypeMembInfoId);
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04004972 $Pos += 1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004973 }
4974 }
4975}
4976
4977sub setFuncParams($)
4978{
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04004979 my $InfoId = $_[0];
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04004980 my $ParamInfoId = getTreeAttr_Args($InfoId);
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04004981 if(getFuncType($InfoId) eq "Method")
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004982 { # check type of "this" pointer
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04004983 my $ObjectTypeId = getTreeAttr_Type($ParamInfoId);
4984 if(my $ObjectName = $TypeInfo{$Version}{$ObjectTypeId}{"Name"})
Andrey Ponomarenko85043792012-05-14 16:48:07 +04004985 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04004986 if($ObjectName=~/\bconst(| volatile)\*const\b/) {
Andrey Ponomarenko85043792012-05-14 16:48:07 +04004987 $SymbolInfo{$Version}{$InfoId}{"Const"} = 1;
4988 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04004989 if($ObjectName=~/\bvolatile\b/) {
Andrey Ponomarenko85043792012-05-14 16:48:07 +04004990 $SymbolInfo{$Version}{$InfoId}{"Volatile"} = 1;
4991 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004992 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +04004993 else
4994 { # skip
4995 return 1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004996 }
4997 $ParamInfoId = getNextElem($ParamInfoId);
4998 }
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04004999 my ($Pos, $Vtt_Pos) = (0, -1);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005000 while($ParamInfoId)
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04005001 { # formal args
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04005002 my $ParamTypeId = getTreeAttr_Type($ParamInfoId);
5003 my $ParamName = getTreeStr(getTreeAttr_Name($ParamInfoId));
5004 if(not $ParamName)
5005 { # unnamed
5006 $ParamName = "p".($Pos+1);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005007 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04005008 if(defined $MissedTypedef{$Version}{$ParamTypeId})
5009 {
5010 if(my $AddedTid = $MissedTypedef{$Version}{$ParamTypeId}{"Tid"}) {
5011 $ParamTypeId = $AddedTid;
5012 }
5013 }
5014 my $PType = $TypeInfo{$Version}{$ParamTypeId}{"Type"};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005015 if(not $PType or $PType eq "Unknown") {
5016 return 1;
5017 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04005018 my $PTName = $TypeInfo{$Version}{$ParamTypeId}{"Name"};
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04005019 if(not $PTName) {
5020 return 1;
5021 }
5022 if($PTName eq "void") {
5023 last;
5024 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005025 if($ParamName eq "__vtt_parm"
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04005026 and $TypeInfo{$Version}{$ParamTypeId}{"Name"} eq "void const**")
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005027 {
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04005028 $Vtt_Pos = $Pos;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005029 $ParamInfoId = getNextElem($ParamInfoId);
5030 next;
5031 }
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04005032 $SymbolInfo{$Version}{$InfoId}{"Param"}{$Pos}{"type"} = $ParamTypeId;
5033 $SymbolInfo{$Version}{$InfoId}{"Param"}{$Pos}{"name"} = $ParamName;
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04005034 if(my $Algn = getAlgn($ParamInfoId)) {
5035 $SymbolInfo{$Version}{$InfoId}{"Param"}{$Pos}{"algn"} = $Algn/$BYTE_SIZE;
5036 }
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04005037 if(not $SymbolInfo{$Version}{$InfoId}{"Param"}{$Pos}{"name"}) {
5038 $SymbolInfo{$Version}{$InfoId}{"Param"}{$Pos}{"name"} = "p".($Pos+1);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005039 }
5040 if($LibInfo{$Version}{"info"}{$ParamInfoId}=~/spec:\s*register /)
5041 { # foo(register type arg)
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04005042 $SymbolInfo{$Version}{$InfoId}{"Param"}{$Pos}{"reg"} = 1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005043 }
5044 $ParamInfoId = getNextElem($ParamInfoId);
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04005045 $Pos += 1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005046 }
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04005047 if(setFuncArgs($InfoId, $Vtt_Pos)) {
Andrey Ponomarenko01117f12012-06-26 12:23:02 +04005048 $SymbolInfo{$Version}{$InfoId}{"Param"}{$Pos}{"type"} = "-1";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005049 }
5050 return 0;
5051}
5052
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04005053sub setFuncArgs($$)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005054{
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04005055 my ($InfoId, $Vtt_Pos) = @_;
5056 my $FuncTypeId = getFuncTypeId($InfoId);
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04005057 my $ParamListElemId = getTreeAttr_Prms($FuncTypeId);
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04005058 if(getFuncType($InfoId) eq "Method") {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005059 $ParamListElemId = getNextElem($ParamListElemId);
5060 }
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04005061 if(not $ParamListElemId)
5062 { # foo(...)
5063 return 1;
5064 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005065 my $HaveVoid = 0;
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04005066 my $Pos = 0;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005067 while($ParamListElemId)
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04005068 { # actual params: may differ from formal args
5069 # formal int*const
5070 # actual: int*
5071 if($Vtt_Pos!=-1 and $Pos==$Vtt_Pos)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005072 {
5073 $Vtt_Pos=-1;
5074 $ParamListElemId = getNextElem($ParamListElemId);
5075 next;
5076 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04005077 my $ParamTypeId = getTreeAttr_Valu($ParamListElemId);
5078 if($TypeInfo{$Version}{$ParamTypeId}{"Name"} eq "void")
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04005079 {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005080 $HaveVoid = 1;
5081 last;
5082 }
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04005083 elsif(not defined $SymbolInfo{$Version}{$InfoId}{"Param"}{$Pos}{"type"})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005084 {
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04005085 $SymbolInfo{$Version}{$InfoId}{"Param"}{$Pos}{"type"} = $ParamTypeId;
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04005086 if(not $SymbolInfo{$Version}{$InfoId}{"Param"}{$Pos}{"name"})
5087 { # unnamed
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04005088 $SymbolInfo{$Version}{$InfoId}{"Param"}{$Pos}{"name"} = "p".($Pos+1);
5089 }
5090 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04005091 if(my $PurpId = getTreeAttr_Purp($ParamListElemId))
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04005092 { # default arguments
Andrey Ponomarenko01117f12012-06-26 12:23:02 +04005093 if(my $PurpType = $LibInfo{$Version}{"info_type"}{$PurpId})
5094 {
5095 my $Val = getInitVal($PurpId, $ParamTypeId);
5096 if(defined $Val) {
5097 $SymbolInfo{$Version}{$InfoId}{"Param"}{$Pos}{"default"} = $Val;
5098 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005099 }
5100 }
5101 $ParamListElemId = getNextElem($ParamListElemId);
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04005102 $Pos += 1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005103 }
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04005104 return ($Pos>=1 and not $HaveVoid);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005105}
5106
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04005107sub getTreeAttr_Chan($)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005108{
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04005109 if($_[0] and my $Info = $LibInfo{$Version}{"info"}{$_[0]})
5110 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04005111 if($Info=~/chan[ ]*:[ ]*@(\d+) /) {
5112 return $1;
5113 }
5114 }
5115 return "";
5116}
5117
5118sub getTreeAttr_Chain($)
5119{
5120 if($_[0] and my $Info = $LibInfo{$Version}{"info"}{$_[0]})
5121 {
5122 if($Info=~/chain[ ]*:[ ]*@(\d+) /) {
5123 return $1;
5124 }
5125 }
5126 return "";
5127}
5128
Andrey Ponomarenkoe3d6bf02012-11-14 11:49:09 +04005129sub getTreeAttr_Unql($)
5130{
5131 if($_[0] and my $Info = $LibInfo{$Version}{"info"}{$_[0]})
5132 {
5133 if($Info=~/unql[ ]*:[ ]*@(\d+) /) {
5134 return $1;
5135 }
5136 }
5137 return "";
5138}
5139
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04005140sub getTreeAttr_Scpe($)
5141{
5142 if($_[0] and my $Info = $LibInfo{$Version}{"info"}{$_[0]})
5143 {
5144 if($Info=~/scpe[ ]*:[ ]*@(\d+) /) {
5145 return $1;
5146 }
5147 }
5148 return "";
5149}
5150
5151sub getTreeAttr_Type($)
5152{
5153 if($_[0] and my $Info = $LibInfo{$Version}{"info"}{$_[0]})
5154 {
5155 if($Info=~/type[ ]*:[ ]*@(\d+) /) {
5156 return $1;
5157 }
5158 }
5159 return "";
5160}
5161
5162sub getTreeAttr_Name($)
5163{
5164 if($_[0] and my $Info = $LibInfo{$Version}{"info"}{$_[0]})
5165 {
5166 if($Info=~/name[ ]*:[ ]*@(\d+) /) {
5167 return $1;
5168 }
5169 }
5170 return "";
5171}
5172
5173sub getTreeAttr_Mngl($)
5174{
5175 if($_[0] and my $Info = $LibInfo{$Version}{"info"}{$_[0]})
5176 {
5177 if($Info=~/mngl[ ]*:[ ]*@(\d+) /) {
5178 return $1;
5179 }
5180 }
5181 return "";
5182}
5183
5184sub getTreeAttr_Prms($)
5185{
5186 if($_[0] and my $Info = $LibInfo{$Version}{"info"}{$_[0]})
5187 {
5188 if($Info=~/prms[ ]*:[ ]*@(\d+) /) {
5189 return $1;
5190 }
5191 }
5192 return "";
5193}
5194
5195sub getTreeAttr_Fncs($)
5196{
5197 if($_[0] and my $Info = $LibInfo{$Version}{"info"}{$_[0]})
5198 {
5199 if($Info=~/fncs[ ]*:[ ]*@(\d+) /) {
5200 return $1;
5201 }
5202 }
5203 return "";
5204}
5205
5206sub getTreeAttr_Csts($)
5207{
5208 if($_[0] and my $Info = $LibInfo{$Version}{"info"}{$_[0]})
5209 {
5210 if($Info=~/csts[ ]*:[ ]*@(\d+) /) {
5211 return $1;
5212 }
5213 }
5214 return "";
5215}
5216
5217sub getTreeAttr_Purp($)
5218{
5219 if($_[0] and my $Info = $LibInfo{$Version}{"info"}{$_[0]})
5220 {
5221 if($Info=~/purp[ ]*:[ ]*@(\d+) /) {
5222 return $1;
5223 }
5224 }
5225 return "";
5226}
5227
5228sub getTreeAttr_Valu($)
5229{
5230 if($_[0] and my $Info = $LibInfo{$Version}{"info"}{$_[0]})
5231 {
5232 if($Info=~/valu[ ]*:[ ]*@(\d+) /) {
5233 return $1;
5234 }
5235 }
5236 return "";
5237}
5238
5239sub getTreeAttr_Flds($)
5240{
5241 if($_[0] and my $Info = $LibInfo{$Version}{"info"}{$_[0]})
5242 {
5243 if($Info=~/flds[ ]*:[ ]*@(\d+) /) {
5244 return $1;
5245 }
5246 }
5247 return "";
5248}
5249
5250sub getTreeAttr_Args($)
5251{
5252 if($_[0] and my $Info = $LibInfo{$Version}{"info"}{$_[0]})
5253 {
5254 if($Info=~/args[ ]*:[ ]*@(\d+) /) {
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04005255 return $1;
5256 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005257 }
5258 return "";
5259}
5260
5261sub getTreeValue($)
5262{
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04005263 if($_[0] and my $Info = $LibInfo{$Version}{"info"}{$_[0]})
5264 {
5265 if($Info=~/low[ ]*:[ ]*([^ ]+) /) {
5266 return $1;
5267 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005268 }
5269 return "";
5270}
5271
5272sub getTreeAccess($)
5273{
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04005274 if($_[0] and my $Info = $LibInfo{$Version}{"info"}{$_[0]})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005275 {
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04005276 if($Info=~/accs[ ]*:[ ]*([a-zA-Z]+) /)
5277 {
5278 my $Access = $1;
5279 if($Access eq "prot") {
5280 return "protected";
5281 }
5282 elsif($Access eq "priv") {
5283 return "private";
5284 }
5285 }
5286 elsif($Info=~/ protected /)
5287 { # support for old GCC versions
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005288 return "protected";
5289 }
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04005290 elsif($Info=~/ private /)
5291 { # support for old GCC versions
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005292 return "private";
5293 }
5294 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005295 return "public";
5296}
5297
5298sub setFuncAccess($)
5299{
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04005300 my $Access = getTreeAccess($_[0]);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005301 if($Access eq "protected") {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04005302 $SymbolInfo{$Version}{$_[0]}{"Protected"} = 1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005303 }
5304 elsif($Access eq "private") {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04005305 $SymbolInfo{$Version}{$_[0]}{"Private"} = 1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005306 }
5307}
5308
5309sub setTypeAccess($$)
5310{
5311 my ($TypeId, $TypeAttr) = @_;
5312 my $Access = getTreeAccess($TypeId);
5313 if($Access eq "protected") {
5314 $TypeAttr->{"Protected"} = 1;
5315 }
5316 elsif($Access eq "private") {
5317 $TypeAttr->{"Private"} = 1;
5318 }
5319}
5320
5321sub setFuncKind($)
5322{
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04005323 if($_[0] and my $Info = $LibInfo{$Version}{"info"}{$_[0]})
5324 {
5325 if($Info=~/pseudo tmpl/) {
5326 $SymbolInfo{$Version}{$_[0]}{"PseudoTemplate"} = 1;
5327 }
5328 elsif($Info=~/ constructor /) {
5329 $SymbolInfo{$Version}{$_[0]}{"Constructor"} = 1;
5330 }
5331 elsif($Info=~/ destructor /) {
5332 $SymbolInfo{$Version}{$_[0]}{"Destructor"} = 1;
5333 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005334 }
5335}
5336
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04005337sub getVirtSpec($)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005338{
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04005339 if($_[0] and my $Info = $LibInfo{$Version}{"info"}{$_[0]})
5340 {
5341 if($Info=~/spec[ ]*:[ ]*pure /) {
5342 return "PureVirt";
5343 }
5344 elsif($Info=~/spec[ ]*:[ ]*virt /) {
5345 return "Virt";
5346 }
5347 elsif($Info=~/ pure\s+virtual /)
5348 { # support for old GCC versions
5349 return "PureVirt";
5350 }
5351 elsif($Info=~/ virtual /)
5352 { # support for old GCC versions
5353 return "Virt";
5354 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005355 }
5356 return "";
5357}
5358
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005359sub getFuncLink($)
5360{
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04005361 if($_[0] and my $Info = $LibInfo{$Version}{"info"}{$_[0]})
5362 {
5363 if($Info=~/link[ ]*:[ ]*static /) {
5364 return "Static";
5365 }
5366 elsif($Info=~/link[ ]*:[ ]*([a-zA-Z]+) /) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005367 return $1;
5368 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005369 }
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04005370 return "";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005371}
5372
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005373sub get_IntNameSpace($$)
5374{
5375 my ($Interface, $LibVersion) = @_;
5376 return "" if(not $Interface or not $LibVersion);
5377 if(defined $Cache{"get_IntNameSpace"}{$Interface}{$LibVersion}) {
5378 return $Cache{"get_IntNameSpace"}{$Interface}{$LibVersion};
5379 }
5380 my $Signature = get_Signature($Interface, $LibVersion);
5381 if($Signature=~/\:\:/)
5382 {
5383 my $FounNameSpace = 0;
5384 foreach my $NameSpace (sort {get_depth($b)<=>get_depth($a)} keys(%{$NestedNameSpaces{$LibVersion}}))
5385 {
5386 if($Signature=~/(\A|\s+for\s+)\Q$NameSpace\E\:\:/) {
5387 return ($Cache{"get_IntNameSpace"}{$Interface}{$LibVersion} = $NameSpace);
5388 }
5389 }
5390 }
5391 else {
5392 return ($Cache{"get_IntNameSpace"}{$Interface}{$LibVersion} = "");
5393 }
5394}
5395
5396sub parse_TypeNameSpace($$)
5397{
5398 my ($TypeName, $LibVersion) = @_;
5399 return "" if(not $TypeName or not $LibVersion);
5400 if(defined $Cache{"parse_TypeNameSpace"}{$TypeName}{$LibVersion}) {
5401 return $Cache{"parse_TypeNameSpace"}{$TypeName}{$LibVersion};
5402 }
5403 if($TypeName=~/\:\:/)
5404 {
5405 my $FounNameSpace = 0;
5406 foreach my $NameSpace (sort {get_depth($b)<=>get_depth($a)} keys(%{$NestedNameSpaces{$LibVersion}}))
5407 {
5408 if($TypeName=~/\A\Q$NameSpace\E\:\:/) {
5409 return ($Cache{"parse_TypeNameSpace"}{$TypeName}{$LibVersion} = $NameSpace);
5410 }
5411 }
5412 }
5413 else {
5414 return ($Cache{"parse_TypeNameSpace"}{$TypeName}{$LibVersion} = "");
5415 }
5416}
5417
5418sub getNameSpace($)
5419{
5420 my $TypeInfoId = $_[0];
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04005421 if(my $NSInfoId = getTreeAttr_Scpe($TypeInfoId))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005422 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04005423 if(my $InfoType = $LibInfo{$Version}{"info_type"}{$NSInfoId})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005424 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04005425 if($InfoType eq "namespace_decl")
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04005426 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04005427 if($LibInfo{$Version}{"info"}{$NSInfoId}=~/name[ ]*:[ ]*@(\d+) /)
5428 {
5429 my $NameSpace = getTreeStr($1);
5430 if($NameSpace eq "::")
5431 { # global namespace
5432 return "";
5433 }
5434 if(my $BaseNameSpace = getNameSpace($NSInfoId)) {
5435 $NameSpace = $BaseNameSpace."::".$NameSpace;
5436 }
5437 $NestedNameSpaces{$Version}{$NameSpace} = 1;
5438 return $NameSpace;
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04005439 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04005440 else {
5441 return "";
5442 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005443 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04005444 elsif($InfoType eq "record_type")
5445 { # inside data type
5446 my ($Name, $NameNS) = getTrivialName(getTypeDeclId($NSInfoId), $NSInfoId);
5447 return $Name;
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04005448 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005449 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005450 }
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04005451 return "";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005452}
5453
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005454sub getEnumMembVal($)
5455{
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04005456 if($_[0] and my $Info = $LibInfo{$Version}{"info"}{$_[0]})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005457 {
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04005458 if($Info=~/valu[ ]*:[ ]*\@(\d+)/)
5459 {
5460 if(my $VInfo = $LibInfo{$Version}{"info"}{$1})
5461 {
5462 if($VInfo=~/cnst[ ]*:[ ]*\@(\d+)/)
5463 { # in newer versions of GCC the value is in the "const_decl->cnst" node
5464 return getTreeValue($1);
5465 }
5466 else
5467 { # some old versions of GCC (3.3) have the value in the "integer_cst" node
5468 return getTreeValue($1);
5469 }
5470 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005471 }
5472 }
5473 return "";
5474}
5475
5476sub getSize($)
5477{
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04005478 if($_[0] and my $Info = $LibInfo{$Version}{"info"}{$_[0]})
5479 {
5480 if($Info=~/size[ ]*:[ ]*\@(\d+)/) {
5481 return getTreeValue($1);
5482 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005483 }
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04005484 return 0;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005485}
5486
5487sub getAlgn($)
5488{
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04005489 if($_[0] and my $Info = $LibInfo{$Version}{"info"}{$_[0]})
5490 {
5491 if($Info=~/algn[ ]*:[ ]*(\d+) /) {
5492 return $1;
5493 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005494 }
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04005495 return "";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005496}
5497
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +04005498sub getBitField($)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005499{
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04005500 if($_[0] and my $Info = $LibInfo{$Version}{"info"}{$_[0]})
5501 {
5502 if($Info=~/ bitfield /) {
5503 return getSize($_[0]);
5504 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005505 }
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04005506 return 0;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005507}
5508
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04005509sub getNextElem($)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005510{
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04005511 if(my $Chan = getTreeAttr_Chan($_[0])) {
5512 return $Chan;
5513 }
5514 elsif(my $Chain = getTreeAttr_Chain($_[0])) {
5515 return $Chain;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005516 }
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04005517 return "";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005518}
5519
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04005520sub registerHeader($$)
5521{ # input: absolute path of header, relative path or name
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005522 my ($Header, $LibVersion) = @_;
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04005523 if(not $Header) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005524 return "";
5525 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04005526 if(is_abs($Header) and not -f $Header)
5527 { # incorrect absolute path
5528 exitStatus("Access_Error", "can't access \'$Header\'");
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005529 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04005530 if(skipHeader($Header, $LibVersion))
5531 { # skip
5532 return "";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005533 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04005534 if(my $Header_Path = identifyHeader($Header, $LibVersion))
5535 {
5536 detect_header_includes($Header_Path, $LibVersion);
5537
5538 if(my $RHeader_Path = $Header_ErrorRedirect{$LibVersion}{$Header_Path})
5539 { # redirect
5540 if($Registered_Headers{$LibVersion}{$RHeader_Path}{"Identity"}
5541 or skipHeader($RHeader_Path, $LibVersion))
5542 { # skip
5543 return "";
5544 }
5545 $Header_Path = $RHeader_Path;
5546 }
5547 elsif($Header_ShouldNotBeUsed{$LibVersion}{$Header_Path})
5548 { # skip
5549 return "";
5550 }
5551
5552 if(my $HName = get_filename($Header_Path))
5553 { # register
5554 $Registered_Headers{$LibVersion}{$Header_Path}{"Identity"} = $HName;
5555 $HeaderName_Paths{$LibVersion}{$HName}{$Header_Path} = 1;
5556 }
5557
5558 if(($Header=~/\.(\w+)\Z/ and $1 ne "h")
5559 or $Header!~/\.(\w+)\Z/)
5560 { # hpp, hh
5561 setLanguage($LibVersion, "C++");
5562 }
5563
5564 if($CheckHeadersOnly
5565 and $Header=~/(\A|\/)c\+\+(\/|\Z)/)
5566 { # /usr/include/c++/4.6.1/...
5567 $STDCXX_TESTING = 1;
5568 }
5569
5570 return $Header_Path;
5571 }
5572 return "";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005573}
5574
5575sub register_directory($$$)
5576{
5577 my ($Dir, $WithDeps, $LibVersion) = @_;
5578 $Dir=~s/[\/\\]+\Z//g;
5579 return if(not $LibVersion or not $Dir or not -d $Dir);
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04005580 return if(skipHeader($Dir, $LibVersion));
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005581 $Dir = get_abs_path($Dir);
5582 my $Mode = "All";
Andrey Ponomarenko85043792012-05-14 16:48:07 +04005583 if($WithDeps)
5584 {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005585 if($RegisteredDirs{$LibVersion}{$Dir}{1}) {
5586 return;
5587 }
5588 elsif($RegisteredDirs{$LibVersion}{$Dir}{0}) {
5589 $Mode = "DepsOnly";
5590 }
5591 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +04005592 else
5593 {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005594 if($RegisteredDirs{$LibVersion}{$Dir}{1}
5595 or $RegisteredDirs{$LibVersion}{$Dir}{0}) {
5596 return;
5597 }
5598 }
5599 $Header_Dependency{$LibVersion}{$Dir} = 1;
5600 $RegisteredDirs{$LibVersion}{$Dir}{$WithDeps} = 1;
5601 if($Mode eq "DepsOnly")
5602 {
5603 foreach my $Path (cmd_find($Dir,"d","","")) {
5604 $Header_Dependency{$LibVersion}{$Path} = 1;
5605 }
5606 return;
5607 }
5608 foreach my $Path (sort {length($b)<=>length($a)} cmd_find($Dir,"f","",""))
5609 {
5610 if($WithDeps)
5611 {
5612 my $SubDir = $Path;
5613 while(($SubDir = get_dirname($SubDir)) ne $Dir)
5614 { # register all sub directories
5615 $Header_Dependency{$LibVersion}{$SubDir} = 1;
5616 }
5617 }
5618 next if(is_not_header($Path));
5619 next if(ignore_path($Path));
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04005620 next if(skipHeader($Path, $LibVersion));
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005621 # Neighbors
Andrey Ponomarenko9927e332012-10-19 10:50:48 +04005622 foreach my $Part (get_prefixes($Path)) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005623 $Include_Neighbors{$LibVersion}{$Part} = $Path;
5624 }
5625 }
5626 if(get_filename($Dir) eq "include")
5627 { # search for "lib/include/" directory
5628 my $LibDir = $Dir;
5629 if($LibDir=~s/([\/\\])include\Z/$1lib/g and -d $LibDir) {
5630 register_directory($LibDir, $WithDeps, $LibVersion);
5631 }
5632 }
5633}
5634
5635sub parse_redirect($$$)
5636{
5637 my ($Content, $Path, $LibVersion) = @_;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005638 my @Errors = ();
5639 while($Content=~s/#\s*error\s+([^\n]+?)\s*(\n|\Z)//) {
5640 push(@Errors, $1);
5641 }
5642 my $Redirect = "";
5643 foreach (@Errors)
5644 {
5645 s/\s{2,}/ /g;
5646 if(/(only|must\ include
5647 |update\ to\ include
5648 |replaced\ with
5649 |replaced\ by|renamed\ to
Andrey Ponomarenko9927e332012-10-19 10:50:48 +04005650 |\ is\ in|\ use)\ (<[^<>]+>|[\w\-\/\\]+\.($HEADER_EXT))/ix)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005651 {
5652 $Redirect = $2;
5653 last;
5654 }
5655 elsif(/(include|use|is\ in)\ (<[^<>]+>|[\w\-\/\\]+\.($HEADER_EXT))\ instead/i)
5656 {
5657 $Redirect = $2;
5658 last;
5659 }
5660 elsif(/this\ header\ should\ not\ be\ used
5661 |programs\ should\ not\ directly\ include
5662 |you\ should\ not\ (include|be\ (including|using)\ this\ (file|header))
5663 |is\ not\ supported\ API\ for\ general\ use
5664 |do\ not\ use
Andrey Ponomarenko9927e332012-10-19 10:50:48 +04005665 |should\ not\ be\ (used|using)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005666 |cannot\ be\ included\ directly/ix and not /\ from\ /i) {
5667 $Header_ShouldNotBeUsed{$LibVersion}{$Path} = 1;
5668 }
5669 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +04005670 if($Redirect)
5671 {
5672 $Redirect=~s/\A<//g;
5673 $Redirect=~s/>\Z//g;
5674 }
5675 return $Redirect;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005676}
5677
5678sub parse_includes($$)
5679{
5680 my ($Content, $Path) = @_;
5681 my %Includes = ();
5682 while($Content=~s/#([ \t]*)(include|include_next|import)([ \t]*)(<|")([^<>"]+)(>|")//)
Andrey Ponomarenko85043792012-05-14 16:48:07 +04005683 { # C/C++: include, Objective C/C++: import directive
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005684 my ($Header, $Method) = ($5, $4);
5685 $Header = path_format($Header, $OSgroup);
Andrey Ponomarenko85043792012-05-14 16:48:07 +04005686 if($Method eq "\"" or is_abs($Header))
5687 {
5688 if(-e joinPath(get_dirname($Path), $Header))
5689 { # relative path exists
5690 $Includes{$Header} = -1;
5691 }
5692 else
5693 { # include "..." that doesn't exist is equal to include <...>
5694 $Includes{$Header} = 2;
5695 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005696 }
5697 else {
5698 $Includes{$Header} = 1;
5699 }
5700 }
5701 return \%Includes;
5702}
5703
5704sub ignore_path($)
5705{
5706 my $Path = $_[0];
5707 if($Path=~/\~\Z/)
5708 {# skipping system backup files
5709 return 1;
5710 }
5711 if($Path=~/(\A|[\/\\]+)(\.(svn|git|bzr|hg)|CVS)([\/\\]+|\Z)/)
5712 {# skipping hidden .svn, .git, .bzr, .hg and CVS directories
5713 return 1;
5714 }
5715 return 0;
5716}
5717
Andrey Ponomarenko9927e332012-10-19 10:50:48 +04005718sub sortByWord($$)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005719{
5720 my ($ArrRef, $W) = @_;
5721 return if(length($W)<2);
5722 @{$ArrRef} = sort {get_filename($b)=~/\Q$W\E/i<=>get_filename($a)=~/\Q$W\E/i} @{$ArrRef};
5723}
5724
Andrey Ponomarenko9927e332012-10-19 10:50:48 +04005725sub sortHeaders($$)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005726{
5727 my ($H1, $H2) = @_;
5728 $H1=~s/\.[a-z]+\Z//ig;
5729 $H2=~s/\.[a-z]+\Z//ig;
5730 my ($HDir1, $Hname1) = separate_path($H1);
5731 my ($HDir2, $Hname2) = separate_path($H2);
5732 my $Dirname1 = get_filename($HDir1);
5733 my $Dirname2 = get_filename($HDir2);
Andrey Ponomarenko9927e332012-10-19 10:50:48 +04005734 if($_[0] eq $_[1]
5735 or $H1 eq $H2) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005736 return 0;
5737 }
5738 elsif($H1=~/\A\Q$H2\E/) {
5739 return 1;
5740 }
5741 elsif($H2=~/\A\Q$H1\E/) {
5742 return -1;
5743 }
5744 elsif($HDir1=~/\Q$Hname1\E/i
5745 and $HDir2!~/\Q$Hname2\E/i)
Andrey Ponomarenko9927e332012-10-19 10:50:48 +04005746 { # include/glib-2.0/glib.h
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005747 return -1;
5748 }
5749 elsif($HDir2=~/\Q$Hname2\E/i
5750 and $HDir1!~/\Q$Hname1\E/i)
Andrey Ponomarenko9927e332012-10-19 10:50:48 +04005751 { # include/glib-2.0/glib.h
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005752 return 1;
5753 }
5754 elsif($Hname1=~/\Q$Dirname1\E/i
5755 and $Hname2!~/\Q$Dirname2\E/i)
Andrey Ponomarenko9927e332012-10-19 10:50:48 +04005756 { # include/hildon-thumbnail/hildon-thumbnail-factory.h
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005757 return -1;
5758 }
5759 elsif($Hname2=~/\Q$Dirname2\E/i
5760 and $Hname1!~/\Q$Dirname1\E/i)
Andrey Ponomarenko9927e332012-10-19 10:50:48 +04005761 { # include/hildon-thumbnail/hildon-thumbnail-factory.h
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005762 return 1;
5763 }
Andrey Ponomarenko9927e332012-10-19 10:50:48 +04005764 elsif($Hname1=~/(config|lib|util)/i
5765 and $Hname2!~/(config|lib|util)/i)
5766 { # include/alsa/asoundlib.h
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005767 return -1;
5768 }
Andrey Ponomarenko9927e332012-10-19 10:50:48 +04005769 elsif($Hname2=~/(config|lib|util)/i
5770 and $Hname1!~/(config|lib|util)/i)
5771 { # include/alsa/asoundlib.h
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005772 return 1;
5773 }
5774 elsif(checkRelevance($H1)
5775 and not checkRelevance($H2))
Andrey Ponomarenko9927e332012-10-19 10:50:48 +04005776 { # libebook/e-book.h
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005777 return -1;
5778 }
5779 elsif(checkRelevance($H2)
5780 and not checkRelevance($H1))
Andrey Ponomarenko9927e332012-10-19 10:50:48 +04005781 { # libebook/e-book.h
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005782 return 1;
5783 }
Andrey Ponomarenko9927e332012-10-19 10:50:48 +04005784 else
5785 {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005786 return (lc($H1) cmp lc($H2));
5787 }
5788}
5789
5790sub searchForHeaders($)
5791{
5792 my $LibVersion = $_[0];
5793 # gcc standard include paths
5794 find_gcc_cxx_headers($LibVersion);
5795 # processing header paths
5796 foreach my $Path (keys(%{$Descriptor{$LibVersion}{"IncludePaths"}}),
5797 keys(%{$Descriptor{$LibVersion}{"AddIncludePaths"}}))
5798 {
5799 my $IPath = $Path;
Andrey Ponomarenkoa01311b2012-06-08 17:20:02 +04005800 if($SystemRoot)
5801 {
5802 if(is_abs($Path)) {
5803 $Path = $SystemRoot.$Path;
5804 }
5805 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005806 if(not -e $Path) {
5807 exitStatus("Access_Error", "can't access \'$Path\'");
5808 }
5809 elsif(-f $Path) {
5810 exitStatus("Access_Error", "\'$Path\' - not a directory");
5811 }
5812 elsif(-d $Path)
5813 {
5814 $Path = get_abs_path($Path);
5815 register_directory($Path, 0, $LibVersion);
5816 if($Descriptor{$LibVersion}{"AddIncludePaths"}{$IPath}) {
5817 $Add_Include_Paths{$LibVersion}{$Path} = 1;
5818 }
5819 else {
5820 $Include_Paths{$LibVersion}{$Path} = 1;
5821 }
5822 }
5823 }
5824 if(keys(%{$Include_Paths{$LibVersion}})) {
5825 $INC_PATH_AUTODETECT{$LibVersion} = 0;
5826 }
5827 # registering directories
5828 foreach my $Path (split(/\s*\n\s*/, $Descriptor{$LibVersion}{"Headers"}))
5829 {
5830 next if(not -e $Path);
5831 $Path = get_abs_path($Path);
5832 $Path = path_format($Path, $OSgroup);
5833 if(-d $Path) {
5834 register_directory($Path, 1, $LibVersion);
5835 }
5836 elsif(-f $Path)
5837 {
5838 my $Dir = get_dirname($Path);
5839 if(not $SystemPaths{"include"}{$Dir}
5840 and not $LocalIncludes{$Dir})
5841 {
5842 register_directory($Dir, 1, $LibVersion);
5843 if(my $OutDir = get_dirname($Dir))
5844 { # registering the outer directory
5845 if(not $SystemPaths{"include"}{$OutDir}
5846 and not $LocalIncludes{$OutDir}) {
5847 register_directory($OutDir, 0, $LibVersion);
5848 }
5849 }
5850 }
5851 }
5852 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +04005853
5854 # clean memory
5855 %RegisteredDirs = ();
5856
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005857 # registering headers
5858 my $Position = 0;
5859 foreach my $Dest (split(/\s*\n\s*/, $Descriptor{$LibVersion}{"Headers"}))
5860 {
5861 if(is_abs($Dest) and not -e $Dest) {
5862 exitStatus("Access_Error", "can't access \'$Dest\'");
5863 }
5864 $Dest = path_format($Dest, $OSgroup);
5865 if(is_header($Dest, 1, $LibVersion))
5866 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04005867 if(my $HPath = registerHeader($Dest, $LibVersion)) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005868 $Registered_Headers{$LibVersion}{$HPath}{"Pos"} = $Position++;
5869 }
5870 }
5871 elsif(-d $Dest)
5872 {
5873 my @Registered = ();
5874 foreach my $Path (cmd_find($Dest,"f","",""))
5875 {
5876 next if(ignore_path($Path));
5877 next if(not is_header($Path, 0, $LibVersion));
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04005878 if(my $HPath = registerHeader($Path, $LibVersion)) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005879 push(@Registered, $HPath);
5880 }
5881 }
Andrey Ponomarenko9927e332012-10-19 10:50:48 +04005882 @Registered = sort {sortHeaders($a, $b)} @Registered;
5883 sortByWord(\@Registered, $TargetLibraryShortName);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005884 foreach my $Path (@Registered) {
5885 $Registered_Headers{$LibVersion}{$Path}{"Pos"} = $Position++;
5886 }
5887 }
5888 else {
5889 exitStatus("Access_Error", "can't identify \'$Dest\' as a header file");
5890 }
5891 }
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04005892 if(my $HList = $Descriptor{$LibVersion}{"IncludePreamble"})
5893 { # preparing preamble headers
5894 my $PPos=0;
5895 foreach my $Header (split(/\s*\n\s*/, $HList))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005896 {
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04005897 if(is_abs($Header) and not -f $Header) {
5898 exitStatus("Access_Error", "can't access file \'$Header\'");
5899 }
5900 $Header = path_format($Header, $OSgroup);
5901 if(my $Header_Path = is_header($Header, 1, $LibVersion))
5902 {
Andrey Ponomarenko9927e332012-10-19 10:50:48 +04005903 if(defined $Include_Preamble{$LibVersion}{$Header_Path})
5904 { # duplicate
5905 next;
5906 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04005907 next if(skipHeader($Header_Path, $LibVersion));
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04005908 $Include_Preamble{$LibVersion}{$Header_Path}{"Position"} = $PPos++;
5909 }
5910 else {
5911 exitStatus("Access_Error", "can't identify \'$Header\' as a header file");
5912 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005913 }
5914 }
5915 foreach my $Header_Name (keys(%{$HeaderName_Paths{$LibVersion}}))
5916 { # set relative paths (for duplicates)
5917 if(keys(%{$HeaderName_Paths{$LibVersion}{$Header_Name}})>=2)
5918 { # search for duplicates
5919 my $FirstPath = (keys(%{$HeaderName_Paths{$LibVersion}{$Header_Name}}))[0];
5920 my $Prefix = get_dirname($FirstPath);
5921 while($Prefix=~/\A(.+)[\/\\]+[^\/\\]+\Z/)
5922 { # detect a shortest distinguishing prefix
5923 my $NewPrefix = $1;
5924 my %Identity = ();
5925 foreach my $Path (keys(%{$HeaderName_Paths{$LibVersion}{$Header_Name}}))
5926 {
5927 if($Path=~/\A\Q$Prefix\E[\/\\]+(.*)\Z/) {
5928 $Identity{$Path} = $1;
5929 }
5930 }
5931 if(keys(%Identity)==keys(%{$HeaderName_Paths{$LibVersion}{$Header_Name}}))
5932 { # all names are differend with current prefix
5933 foreach my $Path (keys(%{$HeaderName_Paths{$LibVersion}{$Header_Name}})) {
5934 $Registered_Headers{$LibVersion}{$Path}{"Identity"} = $Identity{$Path};
5935 }
5936 last;
5937 }
5938 $Prefix = $NewPrefix; # increase prefix
5939 }
5940 }
5941 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +04005942
5943 # clean memory
5944 %HeaderName_Paths = ();
5945
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005946 foreach my $HeaderName (keys(%{$Include_Order{$LibVersion}}))
5947 { # ordering headers according to descriptor
5948 my $PairName=$Include_Order{$LibVersion}{$HeaderName};
5949 my ($Pos, $PairPos) = (-1, -1);
5950 my ($Path, $PairPath) = ();
5951 my @Paths = keys(%{$Registered_Headers{$LibVersion}});
5952 @Paths = sort {int($Registered_Headers{$LibVersion}{$a}{"Pos"})<=>int($Registered_Headers{$LibVersion}{$b}{"Pos"})} @Paths;
5953 foreach my $Header_Path (@Paths)
5954 {
5955 if(get_filename($Header_Path) eq $PairName)
5956 {
5957 $PairPos = $Registered_Headers{$LibVersion}{$Header_Path}{"Pos"};
5958 $PairPath = $Header_Path;
5959 }
5960 if(get_filename($Header_Path) eq $HeaderName)
5961 {
5962 $Pos = $Registered_Headers{$LibVersion}{$Header_Path}{"Pos"};
5963 $Path = $Header_Path;
5964 }
5965 }
5966 if($PairPos!=-1 and $Pos!=-1
5967 and int($PairPos)<int($Pos))
5968 {
5969 my %Tmp = %{$Registered_Headers{$LibVersion}{$Path}};
5970 %{$Registered_Headers{$LibVersion}{$Path}} = %{$Registered_Headers{$LibVersion}{$PairPath}};
5971 %{$Registered_Headers{$LibVersion}{$PairPath}} = %Tmp;
5972 }
5973 }
5974 if(not keys(%{$Registered_Headers{$LibVersion}})) {
5975 exitStatus("Error", "header files are not found in the ".$Descriptor{$LibVersion}{"Version"});
5976 }
5977}
5978
5979sub detect_real_includes($$)
5980{
5981 my ($AbsPath, $LibVersion) = @_;
5982 return () if(not $LibVersion or not $AbsPath or not -e $AbsPath);
5983 if($Cache{"detect_real_includes"}{$LibVersion}{$AbsPath}
5984 or keys(%{$RecursiveIncludes{$LibVersion}{$AbsPath}})) {
5985 return keys(%{$RecursiveIncludes{$LibVersion}{$AbsPath}});
5986 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +04005987 $Cache{"detect_real_includes"}{$LibVersion}{$AbsPath}=1;
5988
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005989 my $Path = callPreprocessor($AbsPath, "", $LibVersion);
5990 return () if(not $Path);
5991 open(PREPROC, $Path);
5992 while(<PREPROC>)
5993 {
5994 if(/#\s+\d+\s+"([^"]+)"[\s\d]*\n/)
5995 {
5996 my $Include = path_format($1, $OSgroup);
5997 if($Include=~/\<(built\-in|internal|command(\-|\s)line)\>|\A\./) {
5998 next;
5999 }
6000 if($Include eq $AbsPath) {
6001 next;
6002 }
6003 $RecursiveIncludes{$LibVersion}{$AbsPath}{$Include} = 1;
6004 }
6005 }
6006 close(PREPROC);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006007 return keys(%{$RecursiveIncludes{$LibVersion}{$AbsPath}});
6008}
6009
6010sub detect_header_includes($$)
6011{
6012 my ($Path, $LibVersion) = @_;
Andrey Ponomarenko85043792012-05-14 16:48:07 +04006013 return if(not $LibVersion or not $Path);
6014 if(defined $Cache{"detect_header_includes"}{$LibVersion}{$Path}) {
6015 return;
6016 }
6017 $Cache{"detect_header_includes"}{$LibVersion}{$Path}=1;
6018
6019 if(not -e $Path) {
6020 return;
6021 }
6022
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006023 my $Content = readFile($Path);
Andrey Ponomarenko85043792012-05-14 16:48:07 +04006024 if(my $Redirect = parse_redirect($Content, $Path, $LibVersion))
6025 { # detect error directive in headers
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04006026 if(my $RedirectPath = identifyHeader($Redirect, $LibVersion))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006027 {
6028 if($RedirectPath=~/\/usr\/include\// and $Path!~/\/usr\/include\//) {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04006029 $RedirectPath = identifyHeader(get_filename($Redirect), $LibVersion);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006030 }
6031 if($RedirectPath ne $Path) {
6032 $Header_ErrorRedirect{$LibVersion}{$Path} = $RedirectPath;
6033 }
6034 }
Andrey Ponomarenko9927e332012-10-19 10:50:48 +04006035 else
6036 { # can't find
6037 $Header_ShouldNotBeUsed{$LibVersion}{$Path} = 1;
6038 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006039 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +04006040 if(my $Inc = parse_includes($Content, $Path))
6041 {
6042 foreach my $Include (keys(%{$Inc}))
6043 { # detect includes
Andrey Ponomarenko85043792012-05-14 16:48:07 +04006044 $Header_Includes{$LibVersion}{$Path}{$Include} = $Inc->{$Include};
6045 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006046 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006047}
6048
6049sub simplify_path($)
6050{
6051 my $Path = $_[0];
6052 while($Path=~s&([\/\\])[^\/\\]+[\/\\]\.\.[\/\\]&$1&){};
6053 return $Path;
6054}
6055
6056sub fromLibc($)
6057{ # GLIBC header
6058 my $Path = $_[0];
6059 my ($Dir, $Name) = separate_path($Path);
6060 if(get_filename($Dir)=~/\A(include|libc)\Z/ and $GlibcHeader{$Name})
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04006061 { # /usr/include/{stdio, ...}.h
6062 # epoc32/include/libc/{stdio, ...}.h
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006063 return 1;
6064 }
6065 if(isLibcDir($Dir)) {
6066 return 1;
6067 }
6068 return 0;
6069}
6070
6071sub isLibcDir($)
6072{ # GLIBC directory
6073 my $Dir = $_[0];
6074 my ($OutDir, $Name) = separate_path($Dir);
6075 if(get_filename($OutDir)=~/\A(include|libc)\Z/
6076 and ($Name=~/\Aasm(|-.+)\Z/ or $GlibcDir{$Name}))
6077 { # /usr/include/{sys,bits,asm,asm-*}/*.h
6078 return 1;
6079 }
6080 return 0;
6081}
6082
6083sub detect_recursive_includes($$)
6084{
6085 my ($AbsPath, $LibVersion) = @_;
6086 return () if(not $AbsPath);
6087 if(isCyclical(\@RecurInclude, $AbsPath)) {
6088 return keys(%{$RecursiveIncludes{$LibVersion}{$AbsPath}});
6089 }
6090 my ($AbsDir, $Name) = separate_path($AbsPath);
6091 if(isLibcDir($AbsDir))
6092 { # GLIBC internals
6093 return ();
6094 }
6095 if(keys(%{$RecursiveIncludes{$LibVersion}{$AbsPath}})) {
6096 return keys(%{$RecursiveIncludes{$LibVersion}{$AbsPath}});
6097 }
6098 return () if($OSgroup ne "windows" and $Name=~/windows|win32|win64/i);
6099 return () if($MAIN_CPP_DIR and $AbsPath=~/\A\Q$MAIN_CPP_DIR\E/ and not $STDCXX_TESTING);
6100 push(@RecurInclude, $AbsPath);
6101 if($DefaultGccPaths{$AbsDir}
6102 or fromLibc($AbsPath))
6103 { # check "real" (non-"model") include paths
6104 my @Paths = detect_real_includes($AbsPath, $LibVersion);
6105 pop(@RecurInclude);
6106 return @Paths;
6107 }
6108 if(not keys(%{$Header_Includes{$LibVersion}{$AbsPath}})) {
6109 detect_header_includes($AbsPath, $LibVersion);
6110 }
6111 foreach my $Include (keys(%{$Header_Includes{$LibVersion}{$AbsPath}}))
6112 {
Andrey Ponomarenko85043792012-05-14 16:48:07 +04006113 my $IncType = $Header_Includes{$LibVersion}{$AbsPath}{$Include};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006114 my $HPath = "";
Andrey Ponomarenko85043792012-05-14 16:48:07 +04006115 if($IncType<0)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006116 { # for #include "..."
6117 my $Candidate = joinPath($AbsDir, $Include);
6118 if(-f $Candidate) {
6119 $HPath = simplify_path($Candidate);
6120 }
6121 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +04006122 elsif($IncType>0
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04006123 and $Include=~/[\/\\]/) # and not find_in_defaults($Include)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006124 { # search for the nearest header
6125 # QtCore/qabstractanimation.h includes <QtCore/qobject.h>
6126 my $Candidate = joinPath(get_dirname($AbsDir), $Include);
6127 if(-f $Candidate) {
6128 $HPath = $Candidate;
6129 }
6130 }
6131 if(not $HPath) {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04006132 $HPath = identifyHeader($Include, $LibVersion);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006133 }
6134 next if(not $HPath);
6135 if($HPath eq $AbsPath) {
6136 next;
6137 }
Andrey Ponomarenko9927e332012-10-19 10:50:48 +04006138
6139 if($Debug)
6140 { # boundary headers
6141 #if($HPath=~/vtk/ and $AbsPath!~/vtk/)
6142 #{
6143 # print STDERR "$AbsPath -> $HPath\n";
6144 #}
6145 }
6146
Andrey Ponomarenko85043792012-05-14 16:48:07 +04006147 $RecursiveIncludes{$LibVersion}{$AbsPath}{$HPath} = $IncType;
6148 if($IncType>0)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006149 { # only include <...>, skip include "..." prefixes
6150 $Header_Include_Prefix{$LibVersion}{$AbsPath}{$HPath}{get_dirname($Include)} = 1;
6151 }
6152 foreach my $IncPath (detect_recursive_includes($HPath, $LibVersion))
6153 {
6154 if($IncPath eq $AbsPath) {
6155 next;
6156 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +04006157 my $RIncType = $RecursiveIncludes{$LibVersion}{$HPath}{$IncPath};
6158 if($RIncType==-1)
6159 { # include "..."
6160 $RIncType = $IncType;
6161 }
6162 elsif($RIncType==2)
6163 {
6164 if($IncType!=-1) {
6165 $RIncType = $IncType;
6166 }
6167 }
6168 $RecursiveIncludes{$LibVersion}{$AbsPath}{$IncPath} = $RIncType;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006169 foreach my $Prefix (keys(%{$Header_Include_Prefix{$LibVersion}{$HPath}{$IncPath}})) {
6170 $Header_Include_Prefix{$LibVersion}{$AbsPath}{$IncPath}{$Prefix} = 1;
6171 }
6172 }
6173 foreach my $Dep (keys(%{$Header_Include_Prefix{$LibVersion}{$AbsPath}}))
6174 {
6175 if($GlibcHeader{get_filename($Dep)} and keys(%{$Header_Include_Prefix{$LibVersion}{$AbsPath}{$Dep}})>=2
6176 and defined $Header_Include_Prefix{$LibVersion}{$AbsPath}{$Dep}{""})
6177 { # distinguish math.h from glibc and math.h from the tested library
6178 delete($Header_Include_Prefix{$LibVersion}{$AbsPath}{$Dep}{""});
6179 last;
6180 }
6181 }
6182 }
6183 pop(@RecurInclude);
6184 return keys(%{$RecursiveIncludes{$LibVersion}{$AbsPath}});
6185}
6186
6187sub find_in_framework($$$)
6188{
6189 my ($Header, $Framework, $LibVersion) = @_;
6190 return "" if(not $Header or not $Framework or not $LibVersion);
6191 if(defined $Cache{"find_in_framework"}{$LibVersion}{$Framework}{$Header}) {
6192 return $Cache{"find_in_framework"}{$LibVersion}{$Framework}{$Header};
6193 }
6194 foreach my $Dependency (sort {get_depth($a)<=>get_depth($b)} keys(%{$Header_Dependency{$LibVersion}}))
6195 {
6196 if(get_filename($Dependency) eq $Framework
6197 and -f get_dirname($Dependency)."/".$Header) {
6198 return ($Cache{"find_in_framework"}{$LibVersion}{$Framework}{$Header} = get_dirname($Dependency));
6199 }
6200 }
6201 return ($Cache{"find_in_framework"}{$LibVersion}{$Framework}{$Header} = "");
6202}
6203
6204sub find_in_defaults($)
6205{
6206 my $Header = $_[0];
6207 return "" if(not $Header);
6208 if(defined $Cache{"find_in_defaults"}{$Header}) {
6209 return $Cache{"find_in_defaults"}{$Header};
6210 }
6211 foreach my $Dir (sort {get_depth($a)<=>get_depth($b)}
6212 (keys(%DefaultIncPaths), keys(%DefaultGccPaths), keys(%DefaultCppPaths), keys(%UserIncPath)))
6213 {
6214 next if(not $Dir);
6215 if(-f $Dir."/".$Header) {
6216 return ($Cache{"find_in_defaults"}{$Header}=$Dir);
6217 }
6218 }
6219 return ($Cache{"find_in_defaults"}{$Header}="");
6220}
6221
6222sub cmp_paths($$)
6223{
6224 my ($Path1, $Path2) = @_;
6225 my @Parts1 = split(/[\/\\]/, $Path1);
6226 my @Parts2 = split(/[\/\\]/, $Path2);
6227 foreach my $Num (0 .. $#Parts1)
6228 {
6229 my $Part1 = $Parts1[$Num];
6230 my $Part2 = $Parts2[$Num];
6231 if($GlibcDir{$Part1}
6232 and not $GlibcDir{$Part2}) {
6233 return 1;
6234 }
6235 elsif($GlibcDir{$Part2}
6236 and not $GlibcDir{$Part1}) {
6237 return -1;
6238 }
6239 elsif($Part1=~/glib/
6240 and $Part2!~/glib/) {
6241 return 1;
6242 }
6243 elsif($Part1!~/glib/
6244 and $Part2=~/glib/) {
6245 return -1;
6246 }
6247 elsif(my $CmpRes = ($Part1 cmp $Part2)) {
6248 return $CmpRes;
6249 }
6250 }
6251 return 0;
6252}
6253
6254sub checkRelevance($)
6255{
6256 my ($Path) = @_;
6257 return 0 if(not $Path);
6258 if($SystemRoot) {
Andrey Ponomarenkoa01311b2012-06-08 17:20:02 +04006259 $Path = cut_path_prefix($Path, $SystemRoot);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006260 }
6261 my ($Dir, $Name) = separate_path($Path);
Andrey Ponomarenkoa01311b2012-06-08 17:20:02 +04006262 $Name=~s/\.\w+\Z//g; # remove extension (.h)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006263 my @Tokens = split(/[_\d\W]+/, $Name);
6264 foreach (@Tokens)
6265 {
6266 next if(not $_);
6267 if($Dir=~/(\A|lib|[_\d\W])\Q$_\E([_\d\W]|lib|\Z)/i
6268 or length($_)>=4 and $Dir=~/\Q$_\E/i)
6269 { # include/gupnp-1.0/libgupnp/gupnp-context.h
6270 # include/evolution-data-server-1.4/libebook/e-book.h
6271 return 1;
6272 }
6273 }
6274 return 0;
6275}
6276
6277sub checkFamily(@)
6278{
6279 my @Paths = @_;
6280 return 1 if($#Paths<=0);
6281 my %Prefix = ();
6282 foreach my $Path (@Paths)
6283 {
6284 if($SystemRoot) {
6285 $Path = cut_path_prefix($Path, $SystemRoot);
6286 }
6287 if(my $Dir = get_dirname($Path))
6288 {
6289 $Dir=~s/(\/[^\/]+?)[\d\.\-\_]+\Z/$1/g; # remove version suffix
6290 $Prefix{$Dir} += 1;
6291 $Prefix{get_dirname($Dir)} += 1;
6292 }
6293 }
6294 foreach (sort keys(%Prefix))
6295 {
6296 if(get_depth($_)>=3
6297 and $Prefix{$_}==$#Paths+1) {
6298 return 1;
6299 }
6300 }
6301 return 0;
6302}
6303
6304sub isAcceptable($$$)
6305{
6306 my ($Header, $Candidate, $LibVersion) = @_;
6307 my $HName = get_filename($Header);
6308 if(get_dirname($Header))
6309 { # with prefix
6310 return 1;
6311 }
6312 if($HName=~/config|setup/i and $Candidate=~/[\/\\]lib\d*[\/\\]/)
6313 { # allow to search for glibconfig.h in /usr/lib/glib-2.0/include/
6314 return 1;
6315 }
6316 if(checkRelevance($Candidate))
6317 { # allow to search for atk.h in /usr/include/atk-1.0/atk/
6318 return 1;
6319 }
6320 if(checkFamily(getSystemHeaders($HName, $LibVersion)))
6321 { # /usr/include/qt4/QtNetwork/qsslconfiguration.h
6322 # /usr/include/qt4/Qt/qsslconfiguration.h
6323 return 1;
6324 }
6325 if($OStarget eq "symbian")
6326 {
6327 if($Candidate=~/[\/\\]stdapis[\/\\]/) {
6328 return 1;
6329 }
6330 }
6331 return 0;
6332}
6333
6334sub isRelevant($$$)
6335{ # disallow to search for "abstract" headers in too deep directories
6336 my ($Header, $Candidate, $LibVersion) = @_;
6337 my $HName = get_filename($Header);
6338 if($OStarget eq "symbian")
6339 {
6340 if($Candidate=~/[\/\\](tools|stlportv5)[\/\\]/) {
6341 return 0;
6342 }
6343 }
Andrey Ponomarenko9927e332012-10-19 10:50:48 +04006344 if($OStarget ne "bsd")
6345 {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006346 if($Candidate=~/[\/\\]include[\/\\]bsd[\/\\]/)
6347 { # openssh: skip /usr/lib/bcc/include/bsd/signal.h
6348 return 0;
6349 }
6350 }
Andrey Ponomarenko9927e332012-10-19 10:50:48 +04006351 if($OStarget ne "windows")
6352 {
6353 if($Candidate=~/[\/\\](wine|msvcrt|windows)[\/\\]/)
6354 { # skip /usr/include/wine/msvcrt
6355 return 0;
6356 }
6357 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006358 if(not get_dirname($Header)
6359 and $Candidate=~/[\/\\]wx[\/\\]/)
6360 { # do NOT search in system /wx/ directory
6361 # for headers without a prefix: sstream.h
6362 return 0;
6363 }
6364 if($Candidate=~/c\+\+[\/\\]\d+/ and $MAIN_CPP_DIR
6365 and $Candidate!~/\A\Q$MAIN_CPP_DIR\E/)
6366 { # skip ../c++/3.3.3/ if using ../c++/4.5/
6367 return 0;
6368 }
6369 if($Candidate=~/[\/\\]asm-/
6370 and (my $Arch = getArch($LibVersion)) ne "unknown")
6371 { # arch-specific header files
6372 if($Candidate!~/[\/\\]asm-\Q$Arch\E/)
6373 {# skip ../asm-arm/ if using x86 architecture
6374 return 0;
6375 }
6376 }
6377 my @Candidates = getSystemHeaders($HName, $LibVersion);
6378 if($#Candidates==1)
6379 { # unique header
6380 return 1;
6381 }
6382 my @SCandidates = getSystemHeaders($Header, $LibVersion);
6383 if($#SCandidates==1)
6384 { # unique name
6385 return 1;
6386 }
6387 my $SystemDepth = $SystemRoot?get_depth($SystemRoot):0;
6388 if(get_depth($Candidate)-$SystemDepth>=5)
6389 { # abstract headers in too deep directories
6390 # sstream.h or typeinfo.h in /usr/include/wx-2.9/wx/
6391 if(not isAcceptable($Header, $Candidate, $LibVersion)) {
6392 return 0;
6393 }
6394 }
6395 if($Header eq "parser.h"
6396 and $Candidate!~/\/libxml2\//)
6397 { # select parser.h from xml2 library
6398 return 0;
6399 }
6400 if(not get_dirname($Header)
6401 and keys(%{$SystemHeaders{$HName}})>=3)
6402 { # many headers with the same name
6403 # like thread.h included without a prefix
6404 if(not checkFamily(@Candidates)) {
6405 return 0;
6406 }
6407 }
6408 return 1;
6409}
6410
6411sub selectSystemHeader($$)
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04006412{ # cache function
6413 if(defined $Cache{"selectSystemHeader"}{$_[1]}{$_[0]}) {
6414 return $Cache{"selectSystemHeader"}{$_[1]}{$_[0]};
6415 }
6416 return ($Cache{"selectSystemHeader"}{$_[1]}{$_[0]} = selectSystemHeader_I(@_));
6417}
6418
6419sub selectSystemHeader_I($$)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006420{
6421 my ($Header, $LibVersion) = @_;
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04006422 if(-f $Header) {
6423 return $Header;
6424 }
6425 if(is_abs($Header) and not -f $Header)
6426 { # incorrect absolute path
6427 return "";
6428 }
Andrey Ponomarenko9927e332012-10-19 10:50:48 +04006429 if(defined $ConfHeaders{lc($Header)})
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04006430 { # too abstract configuration headers
6431 return "";
6432 }
Andrey Ponomarenko9927e332012-10-19 10:50:48 +04006433 my $HName = get_filename($Header);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006434 if($OSgroup ne "windows")
6435 {
Andrey Ponomarenko9927e332012-10-19 10:50:48 +04006436 if(defined $WinHeaders{lc($HName)}
6437 or $HName=~/windows|win32|win64/i)
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04006438 { # windows headers
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006439 return "";
6440 }
Andrey Ponomarenko9927e332012-10-19 10:50:48 +04006441 }
6442 if($OSgroup ne "macos")
6443 {
6444 if($HName eq "fp.h")
6445 { # pngconf.h includes fp.h for MACOS
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006446 return "";
6447 }
6448 }
6449 if($OSgroup ne "solaris")
6450 {
Andrey Ponomarenko9927e332012-10-19 10:50:48 +04006451 if($Header eq "thread.h") {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006452 return "";
6453 }
6454 }
Andrey Ponomarenko07aea072012-11-12 16:15:07 +04006455 if($OSgroup ne "hpux")
6456 {
6457 if($Header eq "sys/stream.h") {
6458 return "";
6459 }
6460 }
Andrey Ponomarenko9927e332012-10-19 10:50:48 +04006461 if($ObsoleteHeaders{$HName}) {
6462 return "";
6463 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04006464
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006465 foreach my $Path (keys(%{$SystemPaths{"include"}}))
6466 { # search in default paths
6467 if(-f $Path."/".$Header) {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04006468 return joinPath($Path,$Header);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006469 }
6470 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04006471 if(not keys(%SystemHeaders))
6472 { # register all headers in system include dirs
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006473 detectSystemHeaders();
6474 }
6475 foreach my $Candidate (sort {get_depth($a)<=>get_depth($b)}
6476 sort {cmp_paths($b, $a)} getSystemHeaders($Header, $LibVersion))
6477 {
6478 if(isRelevant($Header, $Candidate, $LibVersion)) {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04006479 return $Candidate;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006480 }
6481 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04006482 # error
6483 return "";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006484}
6485
6486sub getSystemHeaders($$)
6487{
6488 my ($Header, $LibVersion) = @_;
6489 my @Candidates = ();
6490 foreach my $Candidate (sort keys(%{$SystemHeaders{$Header}}))
6491 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04006492 if(skipHeader($Candidate, $LibVersion)) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006493 next;
6494 }
6495 push(@Candidates, $Candidate);
6496 }
6497 return @Candidates;
6498}
6499
6500sub cut_path_prefix($$)
6501{
6502 my ($Path, $Prefix) = @_;
6503 return $Path if(not $Prefix);
6504 $Prefix=~s/[\/\\]+\Z//;
6505 $Path=~s/\A\Q$Prefix\E([\/\\]+|\Z)//;
6506 return $Path;
6507}
6508
6509sub is_default_include_dir($)
6510{
6511 my $Dir = $_[0];
6512 $Dir=~s/[\/\\]+\Z//;
6513 return ($DefaultGccPaths{$Dir} or $DefaultCppPaths{$Dir} or $DefaultIncPaths{$Dir});
6514}
6515
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04006516sub identifyHeader($$)
6517{ # cache function
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006518 my ($Header, $LibVersion) = @_;
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04006519 if(not $Header) {
6520 return "";
6521 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006522 $Header=~s/\A(\.\.[\\\/])+//g;
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04006523 if(defined $Cache{"identifyHeader"}{$LibVersion}{$Header}) {
6524 return $Cache{"identifyHeader"}{$LibVersion}{$Header};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006525 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04006526 return ($Cache{"identifyHeader"}{$LibVersion}{$Header} = identifyHeader_I($Header, $LibVersion));
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006527}
6528
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04006529sub identifyHeader_I($$)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006530{ # search for header by absolute path, relative path or name
6531 my ($Header, $LibVersion) = @_;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006532 if(-f $Header)
6533 { # it's relative or absolute path
6534 return get_abs_path($Header);
6535 }
6536 elsif($GlibcHeader{$Header} and not $GLIBC_TESTING
6537 and my $HeaderDir = find_in_defaults($Header))
6538 { # search for libc headers in the /usr/include
6539 # for non-libc target library before searching
6540 # in the library paths
6541 return joinPath($HeaderDir,$Header);
6542 }
6543 elsif(my $Path = $Include_Neighbors{$LibVersion}{$Header})
6544 { # search in the target library paths
6545 return $Path;
6546 }
6547 elsif($DefaultGccHeader{$Header})
6548 { # search in the internal GCC include paths
6549 return $DefaultGccHeader{$Header};
6550 }
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04006551 elsif(my $DefaultDir = find_in_defaults($Header))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006552 { # search in the default GCC include paths
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04006553 return joinPath($DefaultDir,$Header);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006554 }
6555 elsif($DefaultCppHeader{$Header})
6556 { # search in the default G++ include paths
6557 return $DefaultCppHeader{$Header};
6558 }
6559 elsif(my $AnyPath = selectSystemHeader($Header, $LibVersion))
6560 { # search everywhere in the system
6561 return $AnyPath;
6562 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04006563 elsif($OSgroup eq "macos")
6564 { # search in frameworks: "OpenGL/gl.h" is "OpenGL.framework/Headers/gl.h"
6565 if(my $Dir = get_dirname($Header))
6566 {
6567 my $RelPath = "Headers\/".get_filename($Header);
6568 if(my $HeaderDir = find_in_framework($RelPath, $Dir.".framework", $LibVersion)) {
6569 return joinPath($HeaderDir, $RelPath);
6570 }
6571 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006572 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04006573 # cannot find anything
6574 return "";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006575}
6576
6577sub getLocation($)
6578{
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04006579 if($_[0] and my $Info = $LibInfo{$Version}{"info"}{$_[0]})
6580 {
6581 if($Info=~/srcp[ ]*:[ ]*([\w\-\<\>\.\+\/\\]+):(\d+) /) {
Andrey Ponomarenko9927e332012-10-19 10:50:48 +04006582 return (path_format($1, $OSgroup), $2);
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04006583 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006584 }
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04006585 return ();
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006586}
6587
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006588sub getNameByInfo($)
6589{
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04006590 if($_[0] and my $Info = $LibInfo{$Version}{"info"}{$_[0]})
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04006591 {
6592 if($Info=~/name[ ]*:[ ]*@(\d+) /)
6593 {
6594 if(my $NInfo = $LibInfo{$Version}{"info"}{$1})
6595 {
6596 if($NInfo=~/strg[ ]*:[ ]*(.*?)[ ]+lngt/)
6597 { # short unsigned int (may include spaces)
6598 return $1;
6599 }
6600 }
6601 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006602 }
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04006603 return "";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006604}
6605
6606sub getTreeStr($)
6607{
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04006608 if($_[0] and my $Info = $LibInfo{$Version}{"info"}{$_[0]})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006609 {
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04006610 if($Info=~/strg[ ]*:[ ]*([^ ]*)/)
6611 {
6612 my $Str = $1;
Andrey Ponomarenko07aea072012-11-12 16:15:07 +04006613 if($CppMode{$Version}
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04006614 and $Str=~/\Ac99_(.+)\Z/) {
6615 if($CppKeywords_A{$1}) {
6616 $Str=$1;
6617 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006618 }
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04006619 return $Str;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006620 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006621 }
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04006622 return "";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006623}
6624
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006625sub getFuncShortName($)
6626{
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04006627 if(my $Info = $LibInfo{$Version}{"info"}{$_[0]})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006628 {
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04006629 if($Info=~/ operator /)
6630 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04006631 if($Info=~/ conversion /)
6632 {
6633 if(my $Rid = $SymbolInfo{$Version}{$_[0]}{"Return"})
6634 {
6635 if(my $RName = $TypeInfo{$Version}{$Rid}{"Name"}) {
6636 return "operator ".$RName;
6637 }
6638 }
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04006639 }
6640 else
6641 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04006642 if($Info=~/ operator[ ]+([a-zA-Z]+) /)
6643 {
6644 if(my $Ind = $Operator_Indication{$1}) {
6645 return "operator".$Ind;
6646 }
6647 elsif(not $UnknownOperator{$1})
6648 {
6649 printMsg("WARNING", "unknown operator $1");
6650 $UnknownOperator{$1} = 1;
6651 }
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04006652 }
6653 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006654 }
6655 else
6656 {
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04006657 if($Info=~/name[ ]*:[ ]*@(\d+) /) {
6658 return getTreeStr($1);
6659 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006660 }
6661 }
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04006662 return "";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006663}
6664
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006665sub getFuncReturn($)
6666{
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04006667 if($_[0] and my $Info = $LibInfo{$Version}{"info"}{$_[0]})
6668 {
6669 if($Info=~/type[ ]*:[ ]*@(\d+) /)
6670 {
6671 if($LibInfo{$Version}{"info"}{$1}=~/retn[ ]*:[ ]*@(\d+) /) {
6672 return $1;
6673 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006674 }
6675 }
6676 return "";
6677}
6678
6679sub getFuncOrig($)
6680{
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04006681 if($_[0] and my $Info = $LibInfo{$Version}{"info"}{$_[0]})
6682 {
6683 if($Info=~/orig[ ]*:[ ]*@(\d+) /) {
6684 return $1;
6685 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006686 }
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04006687 return $_[0];
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006688}
6689
6690sub unmangleSymbol($)
6691{
6692 my $Symbol = $_[0];
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04006693 if(my @Unmngl = unmangleArray($Symbol)) {
6694 return $Unmngl[0];
6695 }
6696 return "";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006697}
6698
6699sub unmangleArray(@)
6700{
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04006701 if($_[0]=~/\A\?/)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006702 { # MSVC mangling
6703 my $UndNameCmd = get_CmdPath("undname");
6704 if(not $UndNameCmd) {
6705 exitStatus("Not_Found", "can't find \"undname\"");
6706 }
6707 writeFile("$TMP_DIR/unmangle", join("\n", @_));
Andrey Ponomarenkoa01311b2012-06-08 17:20:02 +04006708 return split(/\n/, `$UndNameCmd 0x8386 \"$TMP_DIR/unmangle\"`);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006709 }
6710 else
6711 { # GCC mangling
6712 my $CppFiltCmd = get_CmdPath("c++filt");
6713 if(not $CppFiltCmd) {
6714 exitStatus("Not_Found", "can't find c++filt in PATH");
6715 }
Andrey Ponomarenko9927e332012-10-19 10:50:48 +04006716 if(not defined $CPPFILT_SUPPORT_FILE)
6717 {
6718 my $Info = `$CppFiltCmd -h 2>&1`;
6719 $CPPFILT_SUPPORT_FILE = $Info=~/\@<file>/;
6720 }
6721 if($CPPFILT_SUPPORT_FILE)
6722 { # new versions of c++filt can take a file
6723 if($#_>$MAX_CPPFILT_FILE_SIZE)
6724 { # c++filt <= 2.22 may crash on large files (larger than 8mb)
6725 # this is fixed in the oncoming version of Binutils
6726 my @Half = splice(@_, 0, ($#_+1)/2);
6727 return (unmangleArray(@Half), unmangleArray(@_))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006728 }
Andrey Ponomarenko9927e332012-10-19 10:50:48 +04006729 else
6730 {
6731 my $NoStrip = "";
6732 if($OSgroup eq "macos"
6733 or $OSgroup eq "windows") {
6734 $NoStrip = "-n";
6735 }
6736 writeFile("$TMP_DIR/unmangle", join("\n", @_));
6737 my $Res = `$CppFiltCmd $NoStrip \@\"$TMP_DIR/unmangle\"`;
6738 if($?==139)
6739 { # segmentation fault
6740 printMsg("ERROR", "internal error - c++filt crashed, try to reduce MAX_CPPFILT_FILE_SIZE constant");
6741 }
6742 return split(/\n/, $Res);
6743 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006744 }
6745 else
6746 { # old-style unmangling
Andrey Ponomarenko9927e332012-10-19 10:50:48 +04006747 if($#_>$MAX_COMMAND_LINE_ARGUMENTS)
6748 {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006749 my @Half = splice(@_, 0, ($#_+1)/2);
6750 return (unmangleArray(@Half), unmangleArray(@_))
6751 }
6752 else
6753 {
6754 my $NoStrip = "";
6755 if($OSgroup eq "macos"
6756 or $OSgroup eq "windows") {
6757 $NoStrip = "-n";
6758 }
6759 my $Strings = join(" ", @_);
Andrey Ponomarenko9927e332012-10-19 10:50:48 +04006760 my $Res = `$CppFiltCmd $NoStrip $Strings`;
6761 if($?==139)
6762 { # segmentation fault
6763 printMsg("ERROR", "internal error - c++filt crashed, try to reduce MAX_COMMAND_LINE_ARGUMENTS constant");
6764 }
6765 return split(/\n/, $Res);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006766 }
6767 }
6768 }
6769}
6770
6771sub get_SignatureNoInfo($$)
6772{
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04006773 my ($Symbol, $LibVersion) = @_;
6774 if($Cache{"get_SignatureNoInfo"}{$LibVersion}{$Symbol}) {
6775 return $Cache{"get_SignatureNoInfo"}{$LibVersion}{$Symbol};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006776 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04006777 my ($MnglName, $VersionSpec, $SymbolVersion) = separate_symbol($Symbol);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006778 my $Signature = $tr_name{$MnglName}?$tr_name{$MnglName}:$MnglName;
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04006779 if($Symbol=~/\A(_Z|\?)/)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006780 { # C++
Andrey Ponomarenko1477d2c2012-11-12 18:55:45 +04006781 # some standard typedefs
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006782 $Signature=~s/\Qstd::basic_string<char, std::char_traits<char>, std::allocator<char> >\E/std::string/g;
6783 $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;
6784 }
Andrey Ponomarenko82b005f2012-11-12 17:58:14 +04006785 if(not $CheckObjectsOnly or $OSgroup=~/linux|bsd|beos/i)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006786 { # ELF format marks data as OBJECT
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04006787 if($GlobalDataObject{$LibVersion}{$Symbol}) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006788 $Signature .= " [data]";
6789 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04006790 elsif($Symbol!~/\A(_Z|\?)/) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006791 $Signature .= " (...)";
6792 }
6793 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04006794 if(my $ChargeLevel = get_ChargeLevel($Symbol, $LibVersion))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006795 {
Andrey Ponomarenko16934472012-03-29 15:37:04 +04006796 my $ShortName = substr($Signature, 0, find_center($Signature, "("));
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006797 $Signature=~s/\A\Q$ShortName\E/$ShortName $ChargeLevel/g;
6798 }
6799 if($SymbolVersion) {
6800 $Signature .= $VersionSpec.$SymbolVersion;
6801 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04006802 return ($Cache{"get_SignatureNoInfo"}{$LibVersion}{$Symbol} = $Signature);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006803}
6804
6805sub get_ChargeLevel($$)
6806{
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04006807 my ($Symbol, $LibVersion) = @_;
6808 return "" if($Symbol!~/\A(_Z|\?)/);
6809 if(defined $CompleteSignature{$LibVersion}{$Symbol}
6810 and $CompleteSignature{$LibVersion}{$Symbol}{"Header"})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006811 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04006812 if($CompleteSignature{$LibVersion}{$Symbol}{"Constructor"})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006813 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04006814 if($Symbol=~/C1E/) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006815 return "[in-charge]";
6816 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04006817 elsif($Symbol=~/C2E/) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006818 return "[not-in-charge]";
6819 }
6820 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04006821 elsif($CompleteSignature{$LibVersion}{$Symbol}{"Destructor"})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006822 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04006823 if($Symbol=~/D1E/) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006824 return "[in-charge]";
6825 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04006826 elsif($Symbol=~/D2E/) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006827 return "[not-in-charge]";
6828 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04006829 elsif($Symbol=~/D0E/) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006830 return "[in-charge-deleting]";
6831 }
6832 }
6833 }
6834 else
6835 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04006836 if($Symbol=~/C1E/) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006837 return "[in-charge]";
6838 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04006839 elsif($Symbol=~/C2E/) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006840 return "[not-in-charge]";
6841 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04006842 elsif($Symbol=~/D1E/) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006843 return "[in-charge]";
6844 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04006845 elsif($Symbol=~/D2E/) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006846 return "[not-in-charge]";
6847 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04006848 elsif($Symbol=~/D0E/) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006849 return "[in-charge-deleting]";
6850 }
6851 }
6852 return "";
6853}
6854
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04006855sub get_Signature_M($$)
6856{
6857 my ($Symbol, $LibVersion) = @_;
6858 my $Signature_M = $tr_name{$Symbol};
6859 if(my $RTid = $CompleteSignature{$LibVersion}{$Symbol}{"Return"})
6860 { # add return type name
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04006861 $Signature_M = $TypeInfo{$LibVersion}{$RTid}{"Name"}." ".$Signature_M;
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04006862 }
6863 return $Signature_M;
6864}
6865
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006866sub get_Signature($$)
6867{
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04006868 my ($Symbol, $LibVersion) = @_;
6869 if($Cache{"get_Signature"}{$LibVersion}{$Symbol}) {
6870 return $Cache{"get_Signature"}{$LibVersion}{$Symbol};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006871 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04006872 my ($MnglName, $VersionSpec, $SymbolVersion) = separate_symbol($Symbol);
6873 if(isPrivateData($MnglName) or not $CompleteSignature{$LibVersion}{$Symbol}{"Header"})
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04006874 { # non-public global data
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04006875 return get_SignatureNoInfo($Symbol, $LibVersion);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006876 }
6877 my ($Func_Signature, @Param_Types_FromUnmangledName) = ();
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04006878 my $ShortName = $CompleteSignature{$LibVersion}{$Symbol}{"ShortName"};
6879 if($Symbol=~/\A(_Z|\?)/)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006880 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04006881 if(my $ClassId = $CompleteSignature{$LibVersion}{$Symbol}{"Class"}) {
6882 $Func_Signature = $TypeInfo{$LibVersion}{$ClassId}{"Name"}."::".(($CompleteSignature{$LibVersion}{$Symbol}{"Destructor"})?"~":"").$ShortName;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006883 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04006884 elsif(my $NameSpace = $CompleteSignature{$LibVersion}{$Symbol}{"NameSpace"}) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006885 $Func_Signature = $NameSpace."::".$ShortName;
6886 }
6887 else {
6888 $Func_Signature = $ShortName;
6889 }
Andrey Ponomarenko07aea072012-11-12 16:15:07 +04006890 my ($Short, $Params) = split_Signature($tr_name{$MnglName});
6891 @Param_Types_FromUnmangledName = separate_Params($Params, 0, 1);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006892 }
6893 else {
6894 $Func_Signature = $MnglName;
6895 }
6896 my @ParamArray = ();
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04006897 foreach my $Pos (sort {int($a) <=> int($b)} keys(%{$CompleteSignature{$LibVersion}{$Symbol}{"Param"}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006898 {
6899 next if($Pos eq "");
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04006900 my $ParamTypeId = $CompleteSignature{$LibVersion}{$Symbol}{"Param"}{$Pos}{"type"};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006901 next if(not $ParamTypeId);
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04006902 my $ParamTypeName = $TypeInfo{$LibVersion}{$ParamTypeId}{"Name"};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006903 if(not $ParamTypeName) {
6904 $ParamTypeName = $Param_Types_FromUnmangledName[$Pos];
6905 }
6906 foreach my $Typedef (keys(%ChangedTypedef))
6907 {
6908 my $Base = $Typedef_BaseName{$LibVersion}{$Typedef};
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04006909 $ParamTypeName=~s/\b\Q$Typedef\E\b/$Base/g;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006910 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04006911 if(my $ParamName = $CompleteSignature{$LibVersion}{$Symbol}{"Param"}{$Pos}{"name"}) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006912 push(@ParamArray, create_member_decl($ParamTypeName, $ParamName));
6913 }
6914 else {
6915 push(@ParamArray, $ParamTypeName);
6916 }
6917 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04006918 if($CompleteSignature{$LibVersion}{$Symbol}{"Data"}
6919 or $GlobalDataObject{$LibVersion}{$Symbol}) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006920 $Func_Signature .= " [data]";
6921 }
6922 else
6923 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04006924 if(my $ChargeLevel = get_ChargeLevel($Symbol, $LibVersion))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006925 { # add [in-charge]
6926 $Func_Signature .= " ".$ChargeLevel;
6927 }
6928 $Func_Signature .= " (".join(", ", @ParamArray).")";
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04006929 if($CompleteSignature{$LibVersion}{$Symbol}{"Const"}
6930 or $Symbol=~/\A_ZN(V|)K/) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006931 $Func_Signature .= " const";
6932 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04006933 if($CompleteSignature{$LibVersion}{$Symbol}{"Volatile"}
6934 or $Symbol=~/\A_ZN(K|)V/) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006935 $Func_Signature .= " volatile";
6936 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04006937 if($CompleteSignature{$LibVersion}{$Symbol}{"Static"}
6938 and $Symbol=~/\A(_Z|\?)/)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006939 {# for static methods
6940 $Func_Signature .= " [static]";
6941 }
6942 }
6943 if(defined $ShowRetVal
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04006944 and my $ReturnTId = $CompleteSignature{$LibVersion}{$Symbol}{"Return"}) {
6945 $Func_Signature .= ":".$TypeInfo{$LibVersion}{$ReturnTId}{"Name"};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006946 }
6947 if($SymbolVersion) {
6948 $Func_Signature .= $VersionSpec.$SymbolVersion;
6949 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04006950 return ($Cache{"get_Signature"}{$LibVersion}{$Symbol} = $Func_Signature);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006951}
6952
6953sub create_member_decl($$)
6954{
6955 my ($TName, $Member) = @_;
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04006956 if($TName=~/\([\*]+\)/)
6957 {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006958 $TName=~s/\(([\*]+)\)/\($1$Member\)/;
6959 return $TName;
6960 }
6961 else
6962 {
6963 my @ArraySizes = ();
6964 while($TName=~s/(\[[^\[\]]*\])\Z//) {
6965 push(@ArraySizes, $1);
6966 }
6967 return $TName." ".$Member.join("", @ArraySizes);
6968 }
6969}
6970
6971sub getFuncType($)
6972{
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04006973 if($_[0] and my $Info = $LibInfo{$Version}{"info"}{$_[0]})
6974 {
6975 if($Info=~/type[ ]*:[ ]*@(\d+) /)
6976 {
6977 if(my $Type = $LibInfo{$Version}{"info_type"}{$1})
6978 {
6979 if($Type eq "method_type") {
6980 return "Method";
6981 }
6982 elsif($Type eq "function_type") {
6983 return "Function";
6984 }
6985 else {
6986 return "Other";
6987 }
6988 }
6989 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006990 }
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +04006991 return "";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006992}
6993
6994sub getFuncTypeId($)
6995{
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04006996 if($_[0] and my $Info = $LibInfo{$Version}{"info"}{$_[0]})
6997 {
6998 if($Info=~/type[ ]*:[ ]*@(\d+)( |\Z)/) {
6999 return $1;
7000 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007001 }
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04007002 return 0;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007003}
7004
7005sub isNotAnon($) {
7006 return (not isAnon($_[0]));
7007}
7008
7009sub isAnon($)
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04007010{ # "._N" or "$_N" in older GCC versions
7011 return ($_[0] and $_[0]=~/(\.|\$)\_\d+|anon\-/);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007012}
7013
Andrey Ponomarenko9927e332012-10-19 10:50:48 +04007014sub formatName($$)
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04007015{ # type name correction
Andrey Ponomarenko9927e332012-10-19 10:50:48 +04007016 if(defined $Cache{"formatName"}{$_[1]}{$_[0]}) {
7017 return $Cache{"formatName"}{$_[1]}{$_[0]};
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04007018 }
7019
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +04007020 my $N = $_[0];
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04007021
Andrey Ponomarenko9927e332012-10-19 10:50:48 +04007022 if($_[1] ne "S")
7023 {
7024 $N=~s/\A[ ]+//g;
7025 $N=~s/[ ]+\Z//g;
7026 $N=~s/[ ]{2,}/ /g;
7027 }
7028
7029 $N=~s/[ ]*(\W)[ ]*/$1/g; # std::basic_string<char> const
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04007030
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +04007031 $N=~s/\bvolatile const\b/const volatile/g;
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04007032
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +04007033 $N=~s/\b(long long|short|long) unsigned\b/unsigned $1/g;
7034 $N=~s/\b(short|long) int\b/$1/g;
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04007035
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +04007036 $N=~s/([\)\]])(const|volatile)\b/$1 $2/g;
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04007037
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +04007038 while($N=~s/>>/> >/g) {};
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04007039
Andrey Ponomarenko9927e332012-10-19 10:50:48 +04007040 if($_[1] eq "S")
7041 {
7042 if(index($N, "operator")!=-1) {
7043 $N=~s/\b(operator[ ]*)> >/$1>>/;
7044 }
7045 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04007046
Andrey Ponomarenko9927e332012-10-19 10:50:48 +04007047 return ($Cache{"formatName"}{$_[1]}{$_[0]} = $N);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007048}
7049
7050sub get_HeaderDeps($$)
7051{
7052 my ($AbsPath, $LibVersion) = @_;
7053 return () if(not $AbsPath or not $LibVersion);
7054 if(defined $Cache{"get_HeaderDeps"}{$LibVersion}{$AbsPath}) {
7055 return @{$Cache{"get_HeaderDeps"}{$LibVersion}{$AbsPath}};
7056 }
7057 my %IncDir = ();
7058 detect_recursive_includes($AbsPath, $LibVersion);
7059 foreach my $HeaderPath (keys(%{$RecursiveIncludes{$LibVersion}{$AbsPath}}))
7060 {
7061 next if(not $HeaderPath);
7062 next if($MAIN_CPP_DIR and $HeaderPath=~/\A\Q$MAIN_CPP_DIR\E([\/\\]|\Z)/);
7063 my $Dir = get_dirname($HeaderPath);
7064 foreach my $Prefix (keys(%{$Header_Include_Prefix{$LibVersion}{$AbsPath}{$HeaderPath}}))
7065 {
7066 my $Dep = $Dir;
7067 if($Prefix)
7068 {
7069 if($OSgroup eq "windows")
7070 { # case insensitive seach on windows
7071 if(not $Dep=~s/[\/\\]+\Q$Prefix\E\Z//ig) {
7072 next;
7073 }
7074 }
7075 elsif($OSgroup eq "macos")
7076 { # seach in frameworks
7077 if(not $Dep=~s/[\/\\]+\Q$Prefix\E\Z//g)
7078 {
7079 if($HeaderPath=~/(.+\.framework)\/Headers\/([^\/]+)/)
7080 {# frameworks
7081 my ($HFramework, $HName) = ($1, $2);
7082 $Dep = $HFramework;
7083 }
7084 else
7085 {# mismatch
7086 next;
7087 }
7088 }
7089 }
7090 elsif(not $Dep=~s/[\/\\]+\Q$Prefix\E\Z//g)
7091 { # Linux, FreeBSD
7092 next;
7093 }
7094 }
7095 if(not $Dep)
7096 { # nothing to include
7097 next;
7098 }
7099 if(is_default_include_dir($Dep))
7100 { # included by the compiler
7101 next;
7102 }
7103 if(get_depth($Dep)==1)
7104 { # too short
7105 next;
7106 }
7107 if(isLibcDir($Dep))
7108 { # do NOT include /usr/include/{sys,bits}
7109 next;
7110 }
7111 $IncDir{$Dep}=1;
7112 }
7113 }
7114 $Cache{"get_HeaderDeps"}{$LibVersion}{$AbsPath} = sortIncPaths([keys(%IncDir)], $LibVersion);
7115 return @{$Cache{"get_HeaderDeps"}{$LibVersion}{$AbsPath}};
7116}
7117
7118sub sortIncPaths($$)
7119{
7120 my ($ArrRef, $LibVersion) = @_;
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04007121 if(not $ArrRef or $#{$ArrRef}<0) {
7122 return $ArrRef;
7123 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007124 @{$ArrRef} = sort {$b cmp $a} @{$ArrRef};
7125 @{$ArrRef} = sort {get_depth($a)<=>get_depth($b)} @{$ArrRef};
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04007126 @{$ArrRef} = sort {sortDeps($b, $a, $LibVersion)} @{$ArrRef};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007127 return $ArrRef;
7128}
7129
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04007130sub sortDeps($$$)
7131{
7132 if($Header_Dependency{$_[2]}{$_[0]}
7133 and not $Header_Dependency{$_[2]}{$_[1]}) {
7134 return 1;
7135 }
7136 elsif(not $Header_Dependency{$_[2]}{$_[0]}
7137 and $Header_Dependency{$_[2]}{$_[1]}) {
7138 return -1;
7139 }
7140 return 0;
7141}
7142
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007143sub joinPath($$) {
7144 return join($SLASH, @_);
7145}
7146
7147sub get_namespace_additions($)
7148{
7149 my $NameSpaces = $_[0];
7150 my ($Additions, $AddNameSpaceId) = ("", 1);
7151 foreach my $NS (sort {$a=~/_/ <=> $b=~/_/} sort {lc($a) cmp lc($b)} keys(%{$NameSpaces}))
7152 {
7153 next if($SkipNameSpaces{$Version}{$NS});
7154 next if(not $NS or $NameSpaces->{$NS}==-1);
7155 next if($NS=~/(\A|::)iterator(::|\Z)/i);
7156 next if($NS=~/\A__/i);
7157 next if(($NS=~/\Astd::/ or $NS=~/\A(std|tr1|rel_ops|fcntl)\Z/) and not $STDCXX_TESTING);
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04007158 $NestedNameSpaces{$Version}{$NS} = 1; # for future use in reports
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007159 my ($TypeDecl_Prefix, $TypeDecl_Suffix) = ();
7160 my @NS_Parts = split(/::/, $NS);
7161 next if($#NS_Parts==-1);
7162 next if($NS_Parts[0]=~/\A(random|or)\Z/);
7163 foreach my $NS_Part (@NS_Parts)
7164 {
7165 $TypeDecl_Prefix .= "namespace $NS_Part\{";
7166 $TypeDecl_Suffix .= "}";
7167 }
7168 my $TypeDecl = $TypeDecl_Prefix."typedef int tmp_add_type_$AddNameSpaceId;".$TypeDecl_Suffix;
7169 my $FuncDecl = "$NS\:\:tmp_add_type_$AddNameSpaceId tmp_add_func_$AddNameSpaceId(){return 0;};";
7170 $Additions.=" $TypeDecl\n $FuncDecl\n";
7171 $AddNameSpaceId+=1;
7172 }
7173 return $Additions;
7174}
7175
7176sub path_format($$)
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04007177{ # forward slash to pass into MinGW GCC
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007178 my ($Path, $Fmt) = @_;
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04007179 if($Fmt eq "windows")
7180 {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007181 $Path=~s/\//\\/g;
7182 $Path=lc($Path);
7183 }
7184 else {
7185 $Path=~s/\\/\//g;
7186 }
7187 return $Path;
7188}
7189
7190sub inc_opt($$)
7191{
7192 my ($Path, $Style) = @_;
7193 if($Style eq "GCC")
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04007194 { # GCC options
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007195 if($OSgroup eq "windows")
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04007196 { # to MinGW GCC
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007197 return "-I\"".path_format($Path, "unix")."\"";
7198 }
7199 elsif($OSgroup eq "macos"
7200 and $Path=~/\.framework\Z/)
7201 {# to Apple's GCC
7202 return "-F".esc(get_dirname($Path));
7203 }
7204 else {
7205 return "-I".esc($Path);
7206 }
7207 }
7208 elsif($Style eq "CL") {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04007209 return "/I \"".$Path."\"";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007210 }
7211 return "";
7212}
7213
7214sub platformSpecs($)
7215{
7216 my $LibVersion = $_[0];
7217 my $Arch = getArch($LibVersion);
7218 if($OStarget eq "symbian")
7219 { # options for GCCE compiler
7220 my %Symbian_Opts = map {$_=>1} (
7221 "-D__GCCE__",
7222 "-DUNICODE",
7223 "-fexceptions",
7224 "-D__SYMBIAN32__",
7225 "-D__MARM_INTERWORK__",
7226 "-D_UNICODE",
7227 "-D__S60_50__",
7228 "-D__S60_3X__",
7229 "-D__SERIES60_3X__",
7230 "-D__EPOC32__",
7231 "-D__MARM__",
7232 "-D__EABI__",
7233 "-D__MARM_ARMV5__",
7234 "-D__SUPPORT_CPP_EXCEPTIONS__",
7235 "-march=armv5t",
7236 "-mapcs",
7237 "-mthumb-interwork",
7238 "-DEKA2",
7239 "-DSYMBIAN_ENABLE_SPLIT_HEADERS"
7240 );
7241 return join(" ", keys(%Symbian_Opts));
7242 }
7243 elsif($OSgroup eq "windows"
7244 and get_dumpmachine($GCC_PATH)=~/mingw/i)
7245 { # add options to MinGW compiler
7246 # to simulate the MSVC compiler
7247 my %MinGW_Opts = map {$_=>1} (
7248 "-D_WIN32",
7249 "-D_STDCALL_SUPPORTED",
7250 "-D__int64=\"long long\"",
7251 "-D__int32=int",
7252 "-D__int16=short",
7253 "-D__int8=char",
7254 "-D__possibly_notnullterminated=\" \"",
7255 "-D__nullterminated=\" \"",
7256 "-D__nullnullterminated=\" \"",
7257 "-D__w64=\" \"",
7258 "-D__ptr32=\" \"",
7259 "-D__ptr64=\" \"",
7260 "-D__forceinline=inline",
7261 "-D__inline=inline",
7262 "-D__uuidof(x)=IID()",
7263 "-D__try=",
7264 "-D__except(x)=",
7265 "-D__declspec(x)=__attribute__((x))",
7266 "-D__pragma(x)=",
7267 "-D_inline=inline",
7268 "-D__forceinline=__inline",
7269 "-D__stdcall=__attribute__((__stdcall__))",
7270 "-D__cdecl=__attribute__((__cdecl__))",
7271 "-D__fastcall=__attribute__((__fastcall__))",
7272 "-D__thiscall=__attribute__((__thiscall__))",
7273 "-D_stdcall=__attribute__((__stdcall__))",
7274 "-D_cdecl=__attribute__((__cdecl__))",
7275 "-D_fastcall=__attribute__((__fastcall__))",
7276 "-D_thiscall=__attribute__((__thiscall__))",
7277 "-DSHSTDAPI_(x)=x",
7278 "-D_MSC_EXTENSIONS",
7279 "-DSECURITY_WIN32",
7280 "-D_MSC_VER=1500",
7281 "-D_USE_DECLSPECS_FOR_SAL",
7282 "-D__noop=\" \"",
7283 "-DDECLSPEC_DEPRECATED=\" \"",
7284 "-D__builtin_alignof(x)=__alignof__(x)",
7285 "-DSORTPP_PASS");
7286 if($Arch eq "x86") {
7287 $MinGW_Opts{"-D_M_IX86=300"}=1;
7288 }
7289 elsif($Arch eq "x86_64") {
7290 $MinGW_Opts{"-D_M_AMD64=300"}=1;
7291 }
7292 elsif($Arch eq "ia64") {
7293 $MinGW_Opts{"-D_M_IA64=300"}=1;
7294 }
7295 return join(" ", keys(%MinGW_Opts));
7296 }
7297 return "";
7298}
7299
7300my %C_Structure = map {$_=>1} (
7301# FIXME: Can't separate union and struct data types before dumping,
7302# so it sometimes cause compilation errors for unknown reason
7303# when trying to declare TYPE* tmp_add_class_N
7304# This is a list of such structures + list of other C structures
7305 "sigval",
7306 "sigevent",
7307 "sigaction",
7308 "sigvec",
7309 "sigstack",
7310 "timeval",
7311 "timezone",
7312 "rusage",
7313 "rlimit",
7314 "wait",
7315 "flock",
7316 "stat",
7317 "_stat",
7318 "stat32",
7319 "_stat32",
7320 "stat64",
7321 "_stat64",
7322 "_stati64",
7323 "if_nameindex",
7324 "usb_device",
7325 "sigaltstack",
7326 "sysinfo",
7327 "timeLocale",
7328 "tcp_debug",
7329 "rpc_createerr",
Andrey Ponomarenko82b005f2012-11-12 17:58:14 +04007330 # Other
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007331 "timespec",
7332 "random_data",
7333 "drand48_data",
7334 "_IO_marker",
7335 "_IO_FILE",
7336 "lconv",
7337 "sched_param",
7338 "tm",
7339 "itimerspec",
7340 "_pthread_cleanup_buffer",
7341 "fd_set",
Andrey Ponomarenko01117f12012-06-26 12:23:02 +04007342 "siginfo",
Andrey Ponomarenko82b005f2012-11-12 17:58:14 +04007343 "mallinfo",
7344 # Mac
7345 "_timex",
7346 "_class_t",
7347 "_category_t",
7348 "_class_ro_t",
7349 "_protocol_t",
7350 "_message_ref_t",
7351 "_super_message_ref_t",
7352 "_ivar_t",
7353 "_ivar_list_t"
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007354);
7355
7356sub getCompileCmd($$$)
7357{
7358 my ($Path, $Opt, $Inc) = @_;
7359 my $GccCall = $GCC_PATH;
7360 if($Opt) {
7361 $GccCall .= " ".$Opt;
7362 }
7363 $GccCall .= " -x ";
7364 if($OSgroup eq "macos") {
7365 $GccCall .= "objective-";
7366 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04007367 if(check_gcc($GCC_PATH, "4"))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007368 { # compile as "C++" header
7369 # to obtain complete dump using GCC 4.0
7370 $GccCall .= "c++-header";
7371 }
7372 else
7373 { # compile as "C++" source
7374 # GCC 3.3 cannot compile headers
7375 $GccCall .= "c++";
7376 }
7377 if(my $Opts = platformSpecs($Version))
7378 {# platform-specific options
7379 $GccCall .= " ".$Opts;
7380 }
7381 # allow extra qualifications
7382 # and other nonconformant code
Andrey Ponomarenko01117f12012-06-26 12:23:02 +04007383 $GccCall .= " -fpermissive";
7384 $GccCall .= " -w";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007385 if($NoStdInc)
7386 {
7387 $GccCall .= " -nostdinc";
7388 $GccCall .= " -nostdinc++";
7389 }
7390 if($CompilerOptions{$Version})
7391 { # user-defined options
7392 $GccCall .= " ".$CompilerOptions{$Version};
7393 }
Andrey Ponomarenkoa01311b2012-06-08 17:20:02 +04007394 $GccCall .= " \"$Path\"";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007395 if($Inc)
7396 { # include paths
7397 $GccCall .= " ".$Inc;
7398 }
7399 return $GccCall;
7400}
7401
Andrey Ponomarenko01117f12012-06-26 12:23:02 +04007402sub detectPreamble($$)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007403{
Andrey Ponomarenko01117f12012-06-26 12:23:02 +04007404 my ($Content, $LibVersion) = @_;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007405 my %HeaderElems = (
7406 # Types
7407 "stdio.h" => ["FILE", "va_list"],
Andrey Ponomarenko85043792012-05-14 16:48:07 +04007408 "stddef.h" => ["NULL", "ptrdiff_t"],
Andrey Ponomarenko9927e332012-10-19 10:50:48 +04007409 "stdint.h" => ["uint8_t", "uint16_t", "uint32_t", "uint64_t",
7410 "int8_t", "int16_t", "int32_t", "int64_t"],
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007411 "time.h" => ["time_t"],
7412 "sys/types.h" => ["ssize_t", "u_int32_t", "u_short", "u_char",
Andrey Ponomarenko9927e332012-10-19 10:50:48 +04007413 "u_int", "off_t", "u_quad_t", "u_long", "mode_t"],
7414 "unistd.h" => ["gid_t", "uid_t", "socklen_t"],
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007415 "stdbool.h" => ["_Bool"],
7416 "rpc/xdr.h" => ["bool_t"],
7417 "in_systm.h" => ["n_long", "n_short"],
7418 # Fields
Andrey Ponomarenkobede8372012-03-29 17:43:21 +04007419 "arpa/inet.h" => ["fw_src", "ip_src"],
7420 # Functions
Andrey Ponomarenko9927e332012-10-19 10:50:48 +04007421 "stdlib.h" => ["free", "malloc", "size_t"],
Andrey Ponomarenko85043792012-05-14 16:48:07 +04007422 "string.h" => ["memmove", "strcmp"]
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007423 );
7424 my %AutoPreamble = ();
Andrey Ponomarenko85043792012-05-14 16:48:07 +04007425 foreach (keys(%HeaderElems))
7426 {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007427 foreach my $Elem (@{$HeaderElems{$_}}) {
Andrey Ponomarenko9927e332012-10-19 10:50:48 +04007428 $AutoPreamble{$Elem} = $_;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007429 }
7430 }
Andrey Ponomarenko01117f12012-06-26 12:23:02 +04007431 my %Types = ();
7432 while($Content=~s/error\:\s*(field\s*|)\W+(.+?)\W+//)
7433 { # error: 'FILE' has not been declared
Andrey Ponomarenko9927e332012-10-19 10:50:48 +04007434 $Types{$2} = 1;
Andrey Ponomarenko01117f12012-06-26 12:23:02 +04007435 }
7436 if(keys(%Types))
7437 {
7438 my %AddHeaders = ();
7439 foreach my $Type (keys(%Types))
7440 {
7441 if(my $Header = $AutoPreamble{$Type})
7442 {
Andrey Ponomarenko9927e332012-10-19 10:50:48 +04007443 if(my $Path = identifyHeader($Header, $LibVersion))
7444 {
7445 if(skipHeader($Path, $LibVersion)) {
7446 next;
7447 }
7448 $Path = path_format($Path, $OSgroup);
7449 $AddHeaders{$Path}{"Type"} = $Type;
7450 $AddHeaders{$Path}{"Header"} = $Header;
Andrey Ponomarenko01117f12012-06-26 12:23:02 +04007451 }
7452 }
7453 }
7454 if(keys(%AddHeaders)) {
Andrey Ponomarenko9927e332012-10-19 10:50:48 +04007455 return \%AddHeaders;
Andrey Ponomarenko01117f12012-06-26 12:23:02 +04007456 }
7457 }
Andrey Ponomarenko9927e332012-10-19 10:50:48 +04007458 return undef;
Andrey Ponomarenko01117f12012-06-26 12:23:02 +04007459}
7460
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +04007461sub checkCTags($)
7462{
7463 my $Path = $_[0];
7464 if(not $Path) {
7465 return;
7466 }
7467 my $CTags = get_CmdPath("ctags");
7468 if(not $CTags) {
7469 return;
7470 }
Andrey Ponomarenkobdc85a92012-11-12 17:28:12 +04007471
Andrey Ponomarenko82b005f2012-11-12 17:58:14 +04007472 if($OSgroup ne "linux")
7473 { # macos, freebsd, etc.
Andrey Ponomarenkobdc85a92012-11-12 17:28:12 +04007474 my $Info = `$CTags --version 2>\"$TMP_DIR/null\"`;
7475 if($Info!~/exuberant/i)
7476 {
7477 printMsg("WARNING", "incompatible version of \'ctags\' program");
7478 return;
7479 }
7480 }
7481
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +04007482 my $Out = $TMP_DIR."/ctags.txt";
Andrey Ponomarenkobdc85a92012-11-12 17:28:12 +04007483 system("$CTags --c-kinds=pxn -f \"$Out\" \"$Path\" 2>\"$TMP_DIR/null\"");
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +04007484 if($Debug) {
Andrey Ponomarenko9927e332012-10-19 10:50:48 +04007485 copy($Out, $DEBUG_PATH{$Version}."/ctags.txt");
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +04007486 }
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +04007487 open(CTAGS, "<", $Out);
7488 while(my $Line = <CTAGS>)
7489 {
7490 chomp($Line);
7491 my ($Name, $Header, $Def, $Type, $Scpe) = split(/\t/, $Line);
Andrey Ponomarenko9927e332012-10-19 10:50:48 +04007492 if(defined $Intrinsic_Keywords{$Name})
7493 { # noise
7494 next;
7495 }
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +04007496 if($Type eq "n")
7497 {
Andrey Ponomarenko9927e332012-10-19 10:50:48 +04007498 if(index($Scpe, "class:")==0) {
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +04007499 next;
7500 }
Andrey Ponomarenko9927e332012-10-19 10:50:48 +04007501 if(index($Scpe, "struct:")==0) {
7502 next;
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +04007503 }
Andrey Ponomarenko9927e332012-10-19 10:50:48 +04007504 if(index($Scpe, "namespace:")==0)
7505 {
7506 if($Scpe=~s/\Anamespace://) {
7507 $Name = $Scpe."::".$Name;
7508 }
7509 }
7510 $TUnit_NameSpaces{$Version}{$Name} = 1;
7511 }
7512 elsif($Type eq "p")
7513 {
7514 if(not $Scpe or index($Scpe, "namespace:")==0) {
7515 $TUnit_Funcs{$Version}{$Name} = 1;
7516 }
7517 }
7518 elsif($Type eq "x")
7519 {
7520 if(not $Scpe or index($Scpe, "namespace:")==0) {
7521 $TUnit_Vars{$Version}{$Name} = 1;
7522 }
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +04007523 }
7524 }
7525 close(CTAGS);
7526}
7527
Andrey Ponomarenko01117f12012-06-26 12:23:02 +04007528sub getDump()
7529{
7530 if(not $GCC_PATH) {
7531 exitStatus("Error", "internal error - GCC path is not set");
7532 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04007533 my $TmpHeaderPath = $TMP_DIR."/dump".$Version.".h";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007534 my $MHeaderPath = $TmpHeaderPath;
Andrey Ponomarenko85043792012-05-14 16:48:07 +04007535 open(TMP_HEADER, ">", $TmpHeaderPath) || die ("can't open file \'$TmpHeaderPath\': $!\n");
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007536 if(my $AddDefines = $Descriptor{$Version}{"Defines"})
7537 {
7538 $AddDefines=~s/\n\s+/\n /g;
Andrey Ponomarenko85043792012-05-14 16:48:07 +04007539 print TMP_HEADER "\n // add defines\n ".$AddDefines."\n";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007540 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +04007541 print TMP_HEADER "\n // add includes\n";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007542 my @PreambleHeaders = keys(%{$Include_Preamble{$Version}});
7543 @PreambleHeaders = sort {int($Include_Preamble{$Version}{$a}{"Position"})<=>int($Include_Preamble{$Version}{$b}{"Position"})} @PreambleHeaders;
7544 foreach my $Header_Path (@PreambleHeaders) {
Andrey Ponomarenko85043792012-05-14 16:48:07 +04007545 print TMP_HEADER " #include \"".path_format($Header_Path, "unix")."\"\n";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007546 }
7547 my @Headers = keys(%{$Registered_Headers{$Version}});
7548 @Headers = sort {int($Registered_Headers{$Version}{$a}{"Pos"})<=>int($Registered_Headers{$Version}{$b}{"Pos"})} @Headers;
7549 foreach my $Header_Path (@Headers)
7550 {
7551 next if($Include_Preamble{$Version}{$Header_Path});
Andrey Ponomarenko85043792012-05-14 16:48:07 +04007552 print TMP_HEADER " #include \"".path_format($Header_Path, "unix")."\"\n";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007553 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +04007554 close(TMP_HEADER);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007555 my $IncludeString = getIncString(getIncPaths(@PreambleHeaders, @Headers), "GCC");
Andrey Ponomarenko9927e332012-10-19 10:50:48 +04007556
Andrey Ponomarenko07aea072012-11-12 16:15:07 +04007557 if($ExtraInfo)
7558 { # extra information for other tools
7559 writeFile($ExtraInfo."/include-string", $IncludeString);
7560 }
7561
Andrey Ponomarenko9927e332012-10-19 10:50:48 +04007562 if(not keys(%{$TargetHeaders{$Version}}))
7563 { # Target headers
7564 addTargetHeaders($Version);
7565 }
7566
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007567 if($Debug)
7568 { # debug mode
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04007569 writeFile($DEBUG_PATH{$Version}."/headers/direct-includes.txt", Dumper($Header_Includes{$Version}));
7570 writeFile($DEBUG_PATH{$Version}."/headers/recursive-includes.txt", Dumper($RecursiveIncludes{$Version}));
7571 writeFile($DEBUG_PATH{$Version}."/headers/include-paths.txt", Dumper($Cache{"get_HeaderDeps"}{$Version}));
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04007572 writeFile($DEBUG_PATH{$Version}."/headers/default-paths.txt", Dumper(\%DefaultIncPaths));
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007573 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +04007574
Andrey Ponomarenko85043792012-05-14 16:48:07 +04007575 # clean memory
7576 %RecursiveIncludes = ();
7577 %Header_Include_Prefix = ();
7578 %Header_Includes = ();
7579
7580 # clean cache
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04007581 delete($Cache{"identifyHeader"});
Andrey Ponomarenko85043792012-05-14 16:48:07 +04007582 delete($Cache{"detect_header_includes"});
7583 delete($Cache{"selectSystemHeader"});
7584
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007585 # preprocessing stage
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +04007586 my $Pre = callPreprocessor($TmpHeaderPath, $IncludeString, $Version);
7587 checkPreprocessedUnit($Pre);
Andrey Ponomarenko85043792012-05-14 16:48:07 +04007588
7589 # clean memory
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04007590 delete($Include_Neighbors{$Version});
Andrey Ponomarenko85043792012-05-14 16:48:07 +04007591
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +04007592 if($COMMON_LANGUAGE{$Version} eq "C++") {
7593 checkCTags($Pre);
7594 }
7595
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007596 my $MContent = "";
7597 my $PreprocessCmd = getCompileCmd($TmpHeaderPath, "-E", $IncludeString);
7598 if($OStarget eq "windows"
7599 and get_dumpmachine($GCC_PATH)=~/mingw/i
7600 and $MinGWMode{$Version}!=-1)
7601 { # modify headers to compile by MinGW
7602 if(not $MContent)
7603 { # preprocessing
Andrey Ponomarenkoa01311b2012-06-08 17:20:02 +04007604 $MContent = `$PreprocessCmd 2>\"$TMP_DIR/null\"`;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007605 }
7606 if($MContent=~s/__asm\s*(\{[^{}]*?\}|[^{};]*)//g)
7607 { # __asm { ... }
7608 $MinGWMode{$Version}=1;
7609 }
7610 if($MContent=~s/\s+(\/ \/.*?)\n/\n/g)
7611 { # comments after preprocessing
7612 $MinGWMode{$Version}=1;
7613 }
7614 if($MContent=~s/(\W)(0x[a-f]+|\d+)(i|ui)(8|16|32|64)(\W)/$1$2$5/g)
7615 { # 0xffui8
7616 $MinGWMode{$Version}=1;
7617 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +04007618 if($MinGWMode{$Version})
7619 {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007620 printMsg("INFO", "Using MinGW compatibility mode");
Andrey Ponomarenkob8d203d2012-05-25 18:11:07 +04007621 $MHeaderPath = $TMP_DIR."/dump$Version.i";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007622 }
7623 }
7624 if(($COMMON_LANGUAGE{$Version} eq "C" or $CheckHeadersOnly)
Andrey Ponomarenko07aea072012-11-12 16:15:07 +04007625 and $CppMode{$Version}!=-1 and not $CppCompat)
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04007626 { # rename C++ keywords in C code
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007627 if(not $MContent)
7628 { # preprocessing
Andrey Ponomarenkoa01311b2012-06-08 17:20:02 +04007629 $MContent = `$PreprocessCmd 2>\"$TMP_DIR/null\"`;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007630 }
7631 my $RegExp_C = join("|", keys(%CppKeywords_C));
7632 my $RegExp_F = join("|", keys(%CppKeywords_F));
7633 my $RegExp_O = join("|", keys(%CppKeywords_O));
Andrey Ponomarenkobdc85a92012-11-12 17:28:12 +04007634
7635 my $Detected = undef;
7636
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007637 while($MContent=~s/(\A|\n[^\#\/\n][^\n]*?|\n)(\*\s*|\s+|\@|\,|\()($RegExp_C|$RegExp_F)(\s*(\,|\)|\;|\-\>|\.|\:\s*\d))/$1$2c99_$3$4/g)
7638 { # MATCH:
7639 # int foo(int new, int class, int (*new)(int));
7640 # unsigned private: 8;
7641 # DO NOT MATCH:
7642 # #pragma GCC visibility push(default)
Andrey Ponomarenko07aea072012-11-12 16:15:07 +04007643 $CppMode{$Version} = 1;
Andrey Ponomarenkobdc85a92012-11-12 17:28:12 +04007644 $Detected = "$1$2$3$4" if(not defined $Detected);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007645 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04007646 if($MContent=~s/([^\w\s]|\w\s+)(?<!operator )(delete)(\s*\()/$1c99_$2$3/g)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007647 { # MATCH:
7648 # int delete(...);
7649 # int explicit(...);
7650 # DO NOT MATCH:
7651 # void operator delete(...)
Andrey Ponomarenko07aea072012-11-12 16:15:07 +04007652 $CppMode{$Version} = 1;
Andrey Ponomarenkobdc85a92012-11-12 17:28:12 +04007653 $Detected = "$1$2$3" if(not defined $Detected);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007654 }
7655 if($MContent=~s/(\s+)($RegExp_O)(\s*(\;|\:))/$1c99_$2$3/g)
7656 { # MATCH:
7657 # int bool;
7658 # DO NOT MATCH:
7659 # bool X;
7660 # return *this;
7661 # throw;
Andrey Ponomarenko07aea072012-11-12 16:15:07 +04007662 $CppMode{$Version} = 1;
Andrey Ponomarenkobdc85a92012-11-12 17:28:12 +04007663 $Detected = "$1$2$3" if(not defined $Detected);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007664 }
7665 if($MContent=~s/(\s+)(operator)(\s*(\(\s*\)\s*[^\(\s]|\(\s*[^\)\s]))/$1c99_$2$3/g)
7666 { # MATCH:
7667 # int operator(...);
7668 # DO NOT MATCH:
7669 # int operator()(...);
Andrey Ponomarenko07aea072012-11-12 16:15:07 +04007670 $CppMode{$Version} = 1;
Andrey Ponomarenkobdc85a92012-11-12 17:28:12 +04007671 $Detected = "$1$2$3" if(not defined $Detected);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007672 }
7673 if($MContent=~s/([^\w\(\,\s]\s*|\s+)(operator)(\s*(\,\s*[^\(\s]|\)))/$1c99_$2$3/g)
7674 { # MATCH:
7675 # int foo(int operator);
7676 # int foo(int operator, int other);
7677 # DO NOT MATCH:
7678 # int operator,(...);
Andrey Ponomarenko07aea072012-11-12 16:15:07 +04007679 $CppMode{$Version} = 1;
Andrey Ponomarenkobdc85a92012-11-12 17:28:12 +04007680 $Detected = "$1$2$3" if(not defined $Detected);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007681 }
7682 if($MContent=~s/(\*\s*|\w\s+)(bool)(\s*(\,|\)))/$1c99_$2$3/g)
7683 { # MATCH:
7684 # int foo(gboolean *bool);
7685 # DO NOT MATCH:
7686 # void setTabEnabled(int index, bool);
Andrey Ponomarenko07aea072012-11-12 16:15:07 +04007687 $CppMode{$Version} = 1;
Andrey Ponomarenkobdc85a92012-11-12 17:28:12 +04007688 $Detected = "$1$2$3" if(not defined $Detected);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007689 }
Andrey Ponomarenko9927e332012-10-19 10:50:48 +04007690 if($MContent=~s/(\w)(\s*[^\w\(\,\s]\s*|\s+)(this|throw)(\s*[\,\)])/$1$2c99_$3$4/g)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007691 { # MATCH:
7692 # int foo(int* this);
7693 # int bar(int this);
Andrey Ponomarenko9927e332012-10-19 10:50:48 +04007694 # int baz(int throw);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007695 # DO NOT MATCH:
Andrey Ponomarenko9927e332012-10-19 10:50:48 +04007696 # foo(X, this);
Andrey Ponomarenko07aea072012-11-12 16:15:07 +04007697 $CppMode{$Version} = 1;
Andrey Ponomarenkobdc85a92012-11-12 17:28:12 +04007698 $Detected = "$1$2$3$4" if(not defined $Detected);
Andrey Ponomarenko07aea072012-11-12 16:15:07 +04007699 }
7700
7701 if($CppMode{$Version} == 1)
7702 {
Andrey Ponomarenkobdc85a92012-11-12 17:28:12 +04007703 if($Debug)
7704 {
7705 $Detected=~s/\A\s+//g;
7706 printMsg("INFO", "Detected code: \"$Detected\"");
Andrey Ponomarenko07aea072012-11-12 16:15:07 +04007707 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007708 }
Andrey Ponomarenko9927e332012-10-19 10:50:48 +04007709
7710 # remove typedef enum NAME NAME;
7711 my @FwdTypedefs = $MContent=~/typedef\s+enum\s+(\w+)\s+(\w+);/g;
7712 my $N = 0;
7713 while($N<=$#FwdTypedefs-1)
7714 {
7715 my $S = $FwdTypedefs[$N];
7716 if($S eq $FwdTypedefs[$N+1])
7717 {
7718 $MContent=~s/typedef\s+enum\s+\Q$S\E\s+\Q$S\E;//g;
Andrey Ponomarenko07aea072012-11-12 16:15:07 +04007719 $CppMode{$Version}=1;
Andrey Ponomarenko9927e332012-10-19 10:50:48 +04007720 }
7721 $N+=2;
7722 }
7723
Andrey Ponomarenko07aea072012-11-12 16:15:07 +04007724 if($CppMode{$Version}==1)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007725 { # try to change C++ "keyword" to "c99_keyword"
Andrey Ponomarenko07aea072012-11-12 16:15:07 +04007726 printMsg("INFO", "Using C++ compatibility mode");
Andrey Ponomarenkob8d203d2012-05-25 18:11:07 +04007727 $MHeaderPath = $TMP_DIR."/dump$Version.i";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007728 }
7729 }
Andrey Ponomarenko07aea072012-11-12 16:15:07 +04007730 if($CppMode{$Version}==1
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007731 or $MinGWMode{$Version}==1)
7732 { # compile the corrected preprocessor output
7733 writeFile($MHeaderPath, $MContent);
7734 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +04007735
7736 # clean memory
7737 undef $MContent;
7738
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007739 if($COMMON_LANGUAGE{$Version} eq "C++")
7740 { # add classes and namespaces to the dump
7741 my $CHdump = "-fdump-class-hierarchy -c";
Andrey Ponomarenko07aea072012-11-12 16:15:07 +04007742 if($CppMode{$Version}==1
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007743 or $MinGWMode{$Version}==1) {
7744 $CHdump .= " -fpreprocessed";
7745 }
7746 my $ClassHierarchyCmd = getCompileCmd($MHeaderPath, $CHdump, $IncludeString);
7747 chdir($TMP_DIR);
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04007748 system($ClassHierarchyCmd." >null 2>&1");
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007749 chdir($ORIG_DIR);
7750 if(my $ClassDump = (cmd_find($TMP_DIR,"f","*.class",1))[0])
7751 {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007752 my $Content = readFile($ClassDump);
7753 foreach my $ClassInfo (split(/\n\n/, $Content))
7754 {
7755 if($ClassInfo=~/\AClass\s+(.+)\s*/i)
7756 {
7757 my $CName = $1;
7758 next if($CName=~/\A(__|_objc_|_opaque_)/);
7759 $TUnit_NameSpaces{$Version}{$CName} = -1;
7760 if($CName=~/\A[\w:]+\Z/)
7761 { # classes
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +04007762 $TUnit_Classes{$Version}{$CName} = 1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007763 }
7764 if($CName=~/(\w[\w:]*)::/)
7765 { # namespaces
7766 my $NS = $1;
7767 if(not defined $TUnit_NameSpaces{$Version}{$NS}) {
7768 $TUnit_NameSpaces{$Version}{$NS} = 1;
7769 }
7770 }
7771 }
7772 elsif($ClassInfo=~/\AVtable\s+for\s+(.+)\n((.|\n)+)\Z/i)
7773 { # read v-tables (advanced approach)
7774 my ($CName, $VTable) = ($1, $2);
7775 $ClassVTable_Content{$Version}{$CName} = $VTable;
7776 }
7777 }
Andrey Ponomarenkoa01311b2012-06-08 17:20:02 +04007778 foreach my $NS (keys(%{$AddNameSpaces{$Version}}))
7779 { # add user-defined namespaces
7780 $TUnit_NameSpaces{$Version}{$NS} = 1;
7781 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007782 if($Debug)
7783 { # debug mode
7784 mkpath($DEBUG_PATH{$Version});
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04007785 copy($ClassDump, $DEBUG_PATH{$Version}."/class-hierarchy-dump.txt");
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007786 }
7787 unlink($ClassDump);
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +04007788 }
7789
7790 # add namespaces and classes
7791 if(my $NS_Add = get_namespace_additions($TUnit_NameSpaces{$Version}))
7792 { # GCC on all supported platforms does not include namespaces to the dump by default
7793 appendFile($MHeaderPath, "\n // add namespaces\n".$NS_Add);
7794 }
7795 # some GCC versions don't include class methods to the TU dump by default
7796 my ($AddClass, $ClassNum) = ("", 0);
7797 foreach my $CName (sort keys(%{$TUnit_Classes{$Version}}))
7798 {
7799 next if($C_Structure{$CName});
7800 next if(not $STDCXX_TESTING and $CName=~/\Astd::/);
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +04007801 next if($SkipTypes{$Version}{$CName});
Andrey Ponomarenko82b005f2012-11-12 17:58:14 +04007802 if($OSgroup eq "linux")
7803 {
7804 next if(($CName=~tr![:]!!)>2);
7805 if($CName=~/\A(.+)::[^:]+\Z/)
7806 { # will be added by name space
7807 next;
7808 }
7809 }
7810 else
7811 {
7812 if($CName=~/\A(.+)::[^:]+\Z/
7813 and $TUnit_Classes{$Version}{$1})
7814 { # classes inside other classes
7815 next;
7816 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007817 }
Andrey Ponomarenko9927e332012-10-19 10:50:48 +04007818 if(defined $TUnit_Funcs{$Version}{$CName})
7819 { # the same name for a function and type
7820 next;
7821 }
7822 if(defined $TUnit_Vars{$Version}{$CName})
7823 { # the same name for a variable and type
7824 next;
7825 }
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +04007826 $AddClass .= " $CName* tmp_add_class_".($ClassNum++).";\n";
7827 }
7828 if($AddClass) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007829 appendFile($MHeaderPath, "\n // add classes\n".$AddClass);
7830 }
7831 }
7832 writeLog($Version, "Temporary header file \'$TmpHeaderPath\' with the following content will be compiled to create GCC translation unit dump:\n".readFile($TmpHeaderPath)."\n");
7833 # create TU dump
7834 my $TUdump = "-fdump-translation-unit -fkeep-inline-functions -c";
Andrey Ponomarenko07aea072012-11-12 16:15:07 +04007835 if($CppMode{$Version}==1
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007836 or $MinGWMode{$Version}==1) {
7837 $TUdump .= " -fpreprocessed";
7838 }
7839 my $SyntaxTreeCmd = getCompileCmd($MHeaderPath, $TUdump, $IncludeString);
7840 writeLog($Version, "The GCC parameters:\n $SyntaxTreeCmd\n\n");
7841 chdir($TMP_DIR);
Andrey Ponomarenkoa01311b2012-06-08 17:20:02 +04007842 system($SyntaxTreeCmd." >\"$TMP_DIR/tu_errors\" 2>&1");
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007843 if($?)
7844 { # failed to compile, but the TU dump still can be created
Andrey Ponomarenko01117f12012-06-26 12:23:02 +04007845 if(my $Errors = readFile($TMP_DIR."/tu_errors"))
7846 { # try to recompile
7847 # FIXME: handle other errors and try to recompile
Andrey Ponomarenko07aea072012-11-12 16:15:07 +04007848 if($CppMode{$Version}==1
Andrey Ponomarenko01117f12012-06-26 12:23:02 +04007849 and $Errors=~/c99_/)
7850 { # disable c99 mode and try again
Andrey Ponomarenko07aea072012-11-12 16:15:07 +04007851 $CppMode{$Version}=-1;
7852 printMsg("INFO", "Disabling C++ compatibility mode");
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007853 resetLogging($Version);
7854 $TMP_DIR = tempdir(CLEANUP=>1);
7855 return getDump();
7856 }
Andrey Ponomarenko01117f12012-06-26 12:23:02 +04007857 elsif($AutoPreambleMode{$Version}!=-1
Andrey Ponomarenko9927e332012-10-19 10:50:48 +04007858 and my $AddHeaders = detectPreamble($Errors, $Version))
Andrey Ponomarenko01117f12012-06-26 12:23:02 +04007859 { # add auto preamble headers and try again
7860 $AutoPreambleMode{$Version}=-1;
Andrey Ponomarenko9927e332012-10-19 10:50:48 +04007861 my @Headers = sort {$b cmp $a} keys(%{$AddHeaders}); # sys/types.h should be the first
Andrey Ponomarenko01117f12012-06-26 12:23:02 +04007862 foreach my $Num (0 .. $#Headers)
7863 {
7864 my $Path = $Headers[$Num];
7865 if(defined $Include_Preamble{$Version}{$Path})
7866 { # already added
7867 next;
7868 }
7869 $Include_Preamble{$Version}{$Path}{"Position"} = keys(%{$Include_Preamble{$Version}});
Andrey Ponomarenko9927e332012-10-19 10:50:48 +04007870 printMsg("INFO", "Add \'".$AddHeaders->{$Path}{"Header"}."\' preamble header for \'".$AddHeaders->{$Path}{"Type"}."\'");
Andrey Ponomarenko01117f12012-06-26 12:23:02 +04007871 }
7872 resetLogging($Version);
7873 $TMP_DIR = tempdir(CLEANUP=>1);
7874 return getDump();
7875 }
7876 elsif($Cpp0xMode{$Version}!=-1
7877 and ($Errors=~/\Q-std=c++0x\E/
7878 or $Errors=~/is not a class or namespace/))
7879 { # c++0x: enum class
7880 $Cpp0xMode{$Version}=-1;
7881 printMsg("INFO", "Enabling c++0x mode");
7882 resetLogging($Version);
7883 $TMP_DIR = tempdir(CLEANUP=>1);
7884 $CompilerOptions{$Version} .= " -std=c++0x";
7885 return getDump();
7886 }
7887 elsif($MinGWMode{$Version}==1)
7888 { # disable MinGW mode and try again
7889 $MinGWMode{$Version}=-1;
7890 resetLogging($Version);
7891 $TMP_DIR = tempdir(CLEANUP=>1);
7892 return getDump();
7893 }
7894 writeLog($Version, $Errors);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007895 }
Andrey Ponomarenko01117f12012-06-26 12:23:02 +04007896 else {
7897 writeLog($Version, "$!: $?\n");
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007898 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007899 printMsg("ERROR", "some errors occurred when compiling headers");
7900 printErrorLog($Version);
7901 $COMPILE_ERRORS = $ERROR_CODE{"Compile_Error"};
7902 writeLog($Version, "\n");# new line
7903 }
7904 chdir($ORIG_DIR);
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +04007905 unlink($TmpHeaderPath);
7906 unlink($MHeaderPath);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007907 return (cmd_find($TMP_DIR,"f","*.tu",1))[0];
7908}
7909
7910sub cmd_file($)
7911{
7912 my $Path = $_[0];
7913 return "" if(not $Path or not -e $Path);
7914 if(my $CmdPath = get_CmdPath("file")) {
7915 return `$CmdPath -b \"$Path\"`;
7916 }
7917 return "";
7918}
7919
7920sub getIncString($$)
7921{
7922 my ($ArrRef, $Style) = @_;
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04007923 return "" if(not $ArrRef or $#{$ArrRef}<0);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007924 my $String = "";
7925 foreach (@{$ArrRef}) {
7926 $String .= " ".inc_opt($_, $Style);
7927 }
7928 return $String;
7929}
7930
7931sub getIncPaths(@)
7932{
7933 my @HeaderPaths = @_;
7934 my @IncPaths = ();
7935 if($INC_PATH_AUTODETECT{$Version})
7936 { # auto-detecting dependencies
7937 my %Includes = ();
7938 foreach my $HPath (@HeaderPaths)
7939 {
7940 foreach my $Dir (get_HeaderDeps($HPath, $Version))
7941 {
7942 if($Skip_Include_Paths{$Version}{$Dir}) {
7943 next;
7944 }
Andrey Ponomarenkoa01311b2012-06-08 17:20:02 +04007945 if($SystemRoot)
7946 {
7947 if($Skip_Include_Paths{$Version}{$SystemRoot.$Dir}) {
7948 next;
7949 }
7950 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007951 $Includes{$Dir}=1;
7952 }
7953 }
7954 foreach my $Dir (keys(%{$Add_Include_Paths{$Version}}))
7955 { # added by user
7956 next if($Includes{$Dir});
7957 push(@IncPaths, $Dir);
7958 }
7959 foreach my $Dir (@{sortIncPaths([keys(%Includes)], $Version)}) {
7960 push(@IncPaths, $Dir);
7961 }
7962 }
7963 else
7964 { # user-defined paths
7965 foreach my $Dir (sort {get_depth($a)<=>get_depth($b)}
7966 sort {$b cmp $a} keys(%{$Include_Paths{$Version}})) {
7967 push(@IncPaths, $Dir);
7968 }
7969 }
7970 return \@IncPaths;
7971}
7972
7973sub callPreprocessor($$$)
7974{
7975 my ($Path, $Inc, $LibVersion) = @_;
7976 return "" if(not $Path or not -f $Path);
7977 my $IncludeString=$Inc;
7978 if(not $Inc) {
7979 $IncludeString = getIncString(getIncPaths($Path), "GCC");
7980 }
7981 my $Cmd = getCompileCmd($Path, "-dD -E", $IncludeString);
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +04007982 my $Out = $TMP_DIR."/preprocessed.h";
Andrey Ponomarenkoa01311b2012-06-08 17:20:02 +04007983 system($Cmd." >\"$Out\" 2>\"$TMP_DIR/null\"");
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04007984 return $Out;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007985}
7986
7987sub cmd_find($$$$)
7988{ # native "find" is much faster than File::Find (~6x)
7989 # also the File::Find doesn't support --maxdepth N option
7990 # so using the cross-platform wrapper for the native one
7991 my ($Path, $Type, $Name, $MaxDepth) = @_;
7992 return () if(not $Path or not -e $Path);
7993 if($OSgroup eq "windows")
7994 {
7995 my $DirCmd = get_CmdPath("dir");
7996 if(not $DirCmd) {
7997 exitStatus("Not_Found", "can't find \"dir\" command");
7998 }
7999 $Path=~s/[\\]+\Z//;
8000 $Path = get_abs_path($Path);
8001 $Path = path_format($Path, $OSgroup);
8002 my $Cmd = $DirCmd." \"$Path\" /B /O";
8003 if($MaxDepth!=1) {
8004 $Cmd .= " /S";
8005 }
8006 if($Type eq "d") {
8007 $Cmd .= " /AD";
8008 }
8009 my @Files = ();
8010 if($Name)
8011 { # FIXME: how to search file names in MS shell?
8012 $Name=~s/\*/.*/g if($Name!~/\]/);
8013 foreach my $File (split(/\n/, `$Cmd`))
8014 {
8015 if($File=~/$Name\Z/i) {
8016 push(@Files, $File);
8017 }
8018 }
8019 }
8020 else {
Andrey Ponomarenkoa01311b2012-06-08 17:20:02 +04008021 @Files = split(/\n/, `$Cmd 2>\"$TMP_DIR/null\"`);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008022 }
8023 my @AbsPaths = ();
8024 foreach my $File (@Files)
8025 {
8026 if(not is_abs($File)) {
8027 $File = joinPath($Path, $File);
8028 }
8029 if($Type eq "f" and not -f $File)
8030 { # skip dirs
8031 next;
8032 }
8033 push(@AbsPaths, path_format($File, $OSgroup));
8034 }
8035 if($Type eq "d") {
8036 push(@AbsPaths, $Path);
8037 }
8038 return @AbsPaths;
8039 }
8040 else
8041 {
8042 my $FindCmd = get_CmdPath("find");
8043 if(not $FindCmd) {
8044 exitStatus("Not_Found", "can't find a \"find\" command");
8045 }
8046 $Path = get_abs_path($Path);
8047 if(-d $Path and -l $Path
8048 and $Path!~/\/\Z/)
8049 { # for directories that are symlinks
8050 $Path.="/";
8051 }
8052 my $Cmd = $FindCmd." \"$Path\"";
8053 if($MaxDepth) {
8054 $Cmd .= " -maxdepth $MaxDepth";
8055 }
8056 if($Type) {
8057 $Cmd .= " -type $Type";
8058 }
8059 if($Name)
8060 { # file name
8061 if($Name=~/\]/) {
8062 $Cmd .= " -regex \"$Name\"";
8063 }
8064 else {
8065 $Cmd .= " -name \"$Name\"";
8066 }
8067 }
Andrey Ponomarenko9927e332012-10-19 10:50:48 +04008068 my $Res = `$Cmd 2>\"$TMP_DIR/null\"`;
8069 if($?) {
8070 printMsg("ERROR", "problem with \'find\' utility ($?): $!");
8071 }
8072 return split(/\n/, $Res);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008073 }
8074}
8075
8076sub unpackDump($)
8077{
8078 my $Path = $_[0];
8079 return "" if(not $Path or not -e $Path);
8080 $Path = get_abs_path($Path);
8081 $Path = path_format($Path, $OSgroup);
8082 my ($Dir, $FileName) = separate_path($Path);
8083 my $UnpackDir = $TMP_DIR."/unpack";
8084 rmtree($UnpackDir);
8085 mkpath($UnpackDir);
8086 if($FileName=~s/\Q.zip\E\Z//g)
8087 { # *.zip
8088 my $UnzipCmd = get_CmdPath("unzip");
8089 if(not $UnzipCmd) {
8090 exitStatus("Not_Found", "can't find \"unzip\" command");
8091 }
8092 chdir($UnpackDir);
Andrey Ponomarenkoa01311b2012-06-08 17:20:02 +04008093 system("$UnzipCmd \"$Path\" >contents.txt");
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008094 if($?) {
8095 exitStatus("Error", "can't extract \'$Path\'");
8096 }
8097 chdir($ORIG_DIR);
8098 my @Contents = ();
8099 foreach (split("\n", readFile("$UnpackDir/contents.txt")))
8100 {
8101 if(/inflating:\s*([^\s]+)/) {
8102 push(@Contents, $1);
8103 }
8104 }
8105 if(not @Contents) {
8106 exitStatus("Error", "can't extract \'$Path\'");
8107 }
8108 return joinPath($UnpackDir, $Contents[0]);
8109 }
8110 elsif($FileName=~s/\Q.tar.gz\E\Z//g)
8111 { # *.tar.gz
8112 if($OSgroup eq "windows")
8113 { # -xvzf option is not implemented in tar.exe (2003)
8114 # use "gzip.exe -k -d -f" + "tar.exe -xvf" instead
8115 my $TarCmd = get_CmdPath("tar");
8116 if(not $TarCmd) {
8117 exitStatus("Not_Found", "can't find \"tar\" command");
8118 }
8119 my $GzipCmd = get_CmdPath("gzip");
8120 if(not $GzipCmd) {
8121 exitStatus("Not_Found", "can't find \"gzip\" command");
8122 }
8123 chdir($UnpackDir);
Andrey Ponomarenkoa01311b2012-06-08 17:20:02 +04008124 system("$GzipCmd -k -d -f \"$Path\""); # keep input files (-k)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008125 if($?) {
8126 exitStatus("Error", "can't extract \'$Path\'");
8127 }
Andrey Ponomarenkoa01311b2012-06-08 17:20:02 +04008128 system("$TarCmd -xvf \"$Dir\\$FileName.tar\" >contents.txt");
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008129 if($?) {
8130 exitStatus("Error", "can't extract \'$Path\'");
8131 }
8132 chdir($ORIG_DIR);
8133 unlink($Dir."/".$FileName.".tar");
8134 my @Contents = split("\n", readFile("$UnpackDir/contents.txt"));
8135 if(not @Contents) {
8136 exitStatus("Error", "can't extract \'$Path\'");
8137 }
8138 return joinPath($UnpackDir, $Contents[0]);
8139 }
8140 else
8141 { # Unix
8142 my $TarCmd = get_CmdPath("tar");
8143 if(not $TarCmd) {
8144 exitStatus("Not_Found", "can't find \"tar\" command");
8145 }
8146 chdir($UnpackDir);
Andrey Ponomarenkoa01311b2012-06-08 17:20:02 +04008147 system("$TarCmd -xvzf \"$Path\" >contents.txt");
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008148 if($?) {
8149 exitStatus("Error", "can't extract \'$Path\'");
8150 }
8151 chdir($ORIG_DIR);
8152 # The content file name may be different
8153 # from the package file name
8154 my @Contents = split("\n", readFile("$UnpackDir/contents.txt"));
8155 if(not @Contents) {
8156 exitStatus("Error", "can't extract \'$Path\'");
8157 }
8158 return joinPath($UnpackDir, $Contents[0]);
8159 }
8160 }
8161}
8162
8163sub createArchive($$)
8164{
8165 my ($Path, $To) = @_;
Andrey Ponomarenko5c09ef32012-06-14 18:17:33 +04008166 if(not $To) {
8167 $To = ".";
8168 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008169 if(not $Path or not -e $Path
8170 or not -d $To) {
8171 return "";
8172 }
8173 my ($From, $Name) = separate_path($Path);
8174 if($OSgroup eq "windows")
8175 { # *.zip
8176 my $ZipCmd = get_CmdPath("zip");
8177 if(not $ZipCmd) {
8178 exitStatus("Not_Found", "can't find \"zip\"");
8179 }
8180 my $Pkg = $To."/".$Name.".zip";
8181 unlink($Pkg);
8182 chdir($To);
Andrey Ponomarenkoa01311b2012-06-08 17:20:02 +04008183 system("$ZipCmd -j \"$Name.zip\" \"$Path\" >\"$TMP_DIR/null\"");
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008184 if($?)
8185 { # cannot allocate memory (or other problems with "zip")
8186 unlink($Path);
8187 exitStatus("Error", "can't pack the ABI dump: ".$!);
8188 }
8189 chdir($ORIG_DIR);
8190 unlink($Path);
8191 return $Pkg;
8192 }
8193 else
8194 { # *.tar.gz
8195 my $TarCmd = get_CmdPath("tar");
8196 if(not $TarCmd) {
8197 exitStatus("Not_Found", "can't find \"tar\"");
8198 }
8199 my $GzipCmd = get_CmdPath("gzip");
8200 if(not $GzipCmd) {
8201 exitStatus("Not_Found", "can't find \"gzip\"");
8202 }
8203 my $Pkg = abs_path($To)."/".$Name.".tar.gz";
8204 unlink($Pkg);
8205 chdir($From);
8206 system($TarCmd, "-czf", $Pkg, $Name);
8207 if($?)
8208 { # cannot allocate memory (or other problems with "tar")
8209 unlink($Path);
8210 exitStatus("Error", "can't pack the ABI dump: ".$!);
8211 }
8212 chdir($ORIG_DIR);
8213 unlink($Path);
8214 return $To."/".$Name.".tar.gz";
8215 }
8216}
8217
Andrey Ponomarenko9927e332012-10-19 10:50:48 +04008218sub readBytes($)
8219{
8220 sysopen(FILE, $_[0], O_RDONLY);
8221 sysread(FILE, my $Header, 4);
8222 close(FILE);
8223 my @Bytes = map { sprintf('%02x', ord($_)) } split (//, $Header);
8224 return join("", @Bytes);
8225}
8226
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008227sub is_header_file($)
8228{
8229 if($_[0]=~/\.($HEADER_EXT)\Z/i) {
8230 return $_[0];
8231 }
8232 return 0;
8233}
8234
8235sub is_not_header($)
8236{
8237 if($_[0]=~/\.\w+\Z/
8238 and $_[0]!~/\.($HEADER_EXT)\Z/i) {
8239 return 1;
8240 }
8241 return 0;
8242}
8243
8244sub is_header($$$)
8245{
8246 my ($Header, $UserDefined, $LibVersion) = @_;
8247 return 0 if(-d $Header);
8248 if(-f $Header) {
8249 $Header = get_abs_path($Header);
8250 }
8251 else
8252 {
8253 if(is_abs($Header))
8254 { # incorrect absolute path
8255 return 0;
8256 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04008257 if(my $HPath = identifyHeader($Header, $LibVersion)) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008258 $Header = $HPath;
8259 }
8260 else
8261 { # can't find header
8262 return 0;
8263 }
8264 }
8265 if($Header=~/\.\w+\Z/)
8266 { # have an extension
8267 return is_header_file($Header);
8268 }
8269 else
8270 {
8271 if($UserDefined==2)
8272 { # specified on the command line
8273 if(cmd_file($Header)!~/HTML|XML/i) {
8274 return $Header;
8275 }
8276 }
8277 elsif($UserDefined)
8278 { # specified in the XML-descriptor
8279 # header file without an extension
8280 return $Header;
8281 }
8282 else
8283 {
Andrey Ponomarenko85043792012-05-14 16:48:07 +04008284 if($Header=~/\/include\//
8285 or cmd_file($Header)=~/C[\+]*\s+program/i)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008286 { # !~/HTML|XML|shared|dynamic/i
8287 return $Header;
8288 }
8289 }
8290 }
8291 return 0;
8292}
8293
Andrey Ponomarenko16934472012-03-29 15:37:04 +04008294sub addTargetHeaders($)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008295{
8296 my $LibVersion = $_[0];
8297 foreach my $RegHeader (keys(%{$Registered_Headers{$LibVersion}}))
8298 {
8299 my $RegDir = get_dirname($RegHeader);
8300 $TargetHeaders{$LibVersion}{get_filename($RegHeader)}=1;
Andrey Ponomarenko9927e332012-10-19 10:50:48 +04008301
8302 if(not $INC_PATH_AUTODETECT{$LibVersion}) {
8303 detect_recursive_includes($RegHeader, $LibVersion);
8304 }
8305
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008306 foreach my $RecInc (keys(%{$RecursiveIncludes{$LibVersion}{$RegHeader}}))
8307 {
8308 my $Dir = get_dirname($RecInc);
Andrey Ponomarenko85043792012-05-14 16:48:07 +04008309 if($Dir=~/\A\Q$RegDir\E([\/\\]|\Z)/
8310 or $RecursiveIncludes{$LibVersion}{$RegHeader}{$RecInc}!=1)
8311 { # in the same directory or included by #include "..."
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008312 $TargetHeaders{$LibVersion}{get_filename($RecInc)}=1;
8313 }
8314 }
8315 }
8316}
8317
8318sub readHeaders($)
8319{
8320 $Version = $_[0];
8321 printMsg("INFO", "checking header(s) ".$Descriptor{$Version}{"Version"}." ...");
8322 my $DumpPath = getDump();
8323 if(not $DumpPath) {
8324 exitStatus("Cannot_Compile", "can't compile header(s)");
8325 }
8326 if($Debug)
8327 { # debug mode
8328 mkpath($DEBUG_PATH{$Version});
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04008329 copy($DumpPath, $DEBUG_PATH{$Version}."/translation-unit-dump.txt");
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008330 }
8331 getInfo($DumpPath);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008332}
8333
8334sub prepareTypes($)
8335{
8336 my $LibVersion = $_[0];
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04008337 if(not checkDump($LibVersion, "2.0"))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008338 { # support for old ABI dumps
8339 # type names have been corrected in ACC 1.22 (dump 2.0 format)
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04008340 foreach my $TypeId (keys(%{$TypeInfo{$LibVersion}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008341 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04008342 my $TName = $TypeInfo{$LibVersion}{$TypeId}{"Name"};
8343 if($TName=~/\A(\w+)::(\w+)/) {
8344 my ($P1, $P2) = ($1, $2);
8345 if($P1 eq $P2) {
8346 $TName=~s/\A$P1:\:$P1(\W)/$P1$1/;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008347 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04008348 else {
8349 $TName=~s/\A(\w+:\:)$P2:\:$P2(\W)/$1$P2$2/;
8350 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008351 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04008352 $TypeInfo{$LibVersion}{$TypeId}{"Name"} = $TName;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008353 }
8354 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04008355 if(not checkDump($LibVersion, "2.5"))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008356 { # support for old ABI dumps
8357 # V < 2.5: array size == "number of elements"
8358 # V >= 2.5: array size in bytes
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04008359 foreach my $TypeId (sort {int($a)<=>int($b)} keys(%{$TypeInfo{$LibVersion}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008360 {
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +04008361 my %Type = get_PureType($TypeId, $TypeInfo{$LibVersion});
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04008362 if($Type{"Type"} eq "Array")
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008363 {
Andrey Ponomarenko01117f12012-06-26 12:23:02 +04008364 if(my $Size = $Type{"Size"})
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04008365 { # array[N]
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +04008366 my %Base = get_OneStep_BaseType($Type{"Tid"}, $TypeInfo{$LibVersion});
Andrey Ponomarenko01117f12012-06-26 12:23:02 +04008367 $Size *= $Base{"Size"};
8368 $TypeInfo{$LibVersion}{$TypeId}{"Size"} = "$Size";
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04008369 }
8370 else
8371 { # array[] is a pointer
8372 $TypeInfo{$LibVersion}{$TypeId}{"Size"} = $WORD_SIZE{$LibVersion};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008373 }
8374 }
8375 }
8376 }
8377 my $V2 = ($LibVersion==1)?2:1;
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04008378 if(not checkDump($LibVersion, "2.7"))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008379 { # support for old ABI dumps
8380 # size of "method ptr" corrected in 2.7
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04008381 foreach my $TypeId (sort {int($a)<=>int($b)} keys(%{$TypeInfo{$LibVersion}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008382 {
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +04008383 my %PureType = get_PureType($TypeId, $TypeInfo{$LibVersion});
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04008384 if($PureType{"Type"} eq "MethodPtr")
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008385 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04008386 my %Type = get_Type($TypeId, $LibVersion);
8387 my $TypeId_2 = getTypeIdByName($PureType{"Name"}, $V2);
8388 my %Type2 = get_Type($TypeId_2, $V2);
8389 if($Type{"Size"} ne $Type2{"Size"}) {
8390 $TypeInfo{$LibVersion}{$TypeId}{"Size"} = $Type2{"Size"};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008391 }
8392 }
8393 }
8394 }
8395}
8396
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04008397sub prepareSymbols($)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008398{
8399 my $LibVersion = $_[0];
Andrey Ponomarenko16934472012-03-29 15:37:04 +04008400
8401 if(not keys(%{$SymbolInfo{$LibVersion}}))
8402 { # check if input is valid
8403 if(not $ExtendedCheck and not $CheckObjectsOnly)
8404 {
8405 if($CheckHeadersOnly) {
8406 exitStatus("Empty_Set", "the set of public symbols is empty (".$Descriptor{$LibVersion}{"Version"}.")");
8407 }
8408 else {
8409 exitStatus("Empty_Intersection", "the sets of public symbols in headers and libraries have empty intersection (".$Descriptor{$LibVersion}{"Version"}.")");
8410 }
8411 }
8412 }
8413
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008414 my $Remangle = 0;
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04008415 if(not checkDump(1, "2.10")
8416 or not checkDump(2, "2.10"))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008417 { # different formats
8418 $Remangle = 1;
8419 }
8420 if($CheckHeadersOnly)
8421 { # different languages
8422 if($UserLang)
8423 { # --lang=LANG for both versions
8424 if(($UsedDump{1}{"V"} and $UserLang ne $UsedDump{1}{"L"})
8425 or ($UsedDump{2}{"V"} and $UserLang ne $UsedDump{2}{"L"}))
8426 {
8427 if($UserLang eq "C++")
8428 { # remangle symbols
8429 $Remangle = 1;
8430 }
8431 elsif($UserLang eq "C")
8432 { # remove mangling
8433 $Remangle = -1;
8434 }
8435 }
8436 }
8437 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04008438
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04008439 foreach my $InfoId (sort {int($b)<=>int($a)} keys(%{$SymbolInfo{$LibVersion}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008440 { # reverse order: D0, D1, D2, D0 (artificial, GCC < 4.5), C1, C2
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04008441 if(not checkDump($LibVersion, "2.13"))
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04008442 { # support for old ABI dumps
8443 if(defined $SymbolInfo{$LibVersion}{$InfoId}{"Param"})
8444 {
8445 foreach my $P (keys(%{$SymbolInfo{$LibVersion}{$InfoId}{"Param"}}))
8446 {
8447 my $TypeId = $SymbolInfo{$LibVersion}{$InfoId}{"Param"}{$P}{"type"};
8448 my $DVal = $SymbolInfo{$LibVersion}{$InfoId}{"Param"}{$P}{"default"};
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04008449 my $TName = $TypeInfo{$LibVersion}{$TypeId}{"Name"};
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04008450 if(defined $DVal and $DVal ne "")
8451 {
8452 if($TName eq "char") {
8453 $SymbolInfo{$LibVersion}{$InfoId}{"Param"}{$P}{"default"} = chr($DVal);
8454 }
8455 elsif($TName eq "bool") {
8456 $SymbolInfo{$LibVersion}{$InfoId}{"Param"}{$P}{"default"} = $DVal?"true":"false";
8457 }
8458 }
8459 }
8460 }
8461 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04008462 if($SymbolInfo{$LibVersion}{$InfoId}{"Destructor"})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008463 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04008464 if(defined $SymbolInfo{$LibVersion}{$InfoId}{"Param"}
8465 and keys(%{$SymbolInfo{$LibVersion}{$InfoId}{"Param"}})
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04008466 and $SymbolInfo{$LibVersion}{$InfoId}{"Param"}{0}{"name"})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008467 { # support for old GCC < 4.5: skip artificial ~dtor(int __in_chrg)
8468 # + support for old ABI dumps
8469 next;
8470 }
8471 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04008472 my $MnglName = $SymbolInfo{$LibVersion}{$InfoId}{"MnglName"};
Andrey Ponomarenko85043792012-05-14 16:48:07 +04008473 my $ShortName = $SymbolInfo{$LibVersion}{$InfoId}{"ShortName"};
Andrey Ponomarenko16934472012-03-29 15:37:04 +04008474 my $ClassID = $SymbolInfo{$LibVersion}{$InfoId}{"Class"};
Andrey Ponomarenko85043792012-05-14 16:48:07 +04008475 my $Return = $SymbolInfo{$LibVersion}{$InfoId}{"Return"};
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04008476
Andrey Ponomarenko16934472012-03-29 15:37:04 +04008477 my $SRemangle = 0;
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04008478 if(not checkDump(1, "2.12")
8479 or not checkDump(2, "2.12"))
Andrey Ponomarenko16934472012-03-29 15:37:04 +04008480 { # support for old ABI dumps
Andrey Ponomarenko85043792012-05-14 16:48:07 +04008481 if($ShortName eq "operator>>")
8482 {
8483 if(not $SymbolInfo{$LibVersion}{$InfoId}{"Class"})
8484 { # corrected mangling of operator>>
8485 $SRemangle = 1;
8486 }
Andrey Ponomarenko16934472012-03-29 15:37:04 +04008487 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +04008488 if($SymbolInfo{$LibVersion}{$InfoId}{"Data"})
8489 {
8490 if(not $SymbolInfo{$LibVersion}{$InfoId}{"Class"}
8491 and isConstType($Return, $LibVersion) and $MnglName!~/L\d+$ShortName/)
8492 { # corrected mangling of const global data
8493 # some global data is not mangled in the TU dump: qt_sine_table (Qt 4.8)
8494 # and incorrectly mangled by old ACC versions
8495 $SRemangle = 1;
8496 }
Andrey Ponomarenko16934472012-03-29 15:37:04 +04008497 }
8498 }
Andrey Ponomarenko5c09ef32012-06-14 18:17:33 +04008499 if(not $CheckHeadersOnly)
8500 { # support for old ABI dumps
8501 if(not checkDump(1, "2.17")
8502 or not checkDump(2, "2.17"))
8503 {
8504 if($SymbolInfo{$LibVersion}{$InfoId}{"Data"})
8505 {
8506 if(not $SymbolInfo{$LibVersion}{$InfoId}{"Class"})
8507 {
8508 if(link_symbol($ShortName, $LibVersion, "-Deps"))
8509 {
8510 $MnglName = $ShortName;
8511 $SymbolInfo{$LibVersion}{$InfoId}{"MnglName"} = $MnglName;
8512 }
8513 }
8514 }
8515 }
8516 }
Andrey Ponomarenko16934472012-03-29 15:37:04 +04008517 if($Remangle==1 or $SRemangle==1)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008518 { # support for old ABI dumps: some symbols are not mangled in old dumps
8519 # mangle both sets of symbols (old and new)
8520 # NOTE: remangling all symbols by the same mangler
8521 if($MnglName=~/\A_ZN(V|)K/)
8522 { # mangling may be incorrect on old ABI dumps
8523 # because of absent "Const" attribute
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04008524 $SymbolInfo{$LibVersion}{$InfoId}{"Const"} = 1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008525 }
8526 if($MnglName=~/\A_ZN(K|)V/)
8527 { # mangling may be incorrect on old ABI dumps
8528 # because of absent "Volatile" attribute
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04008529 $SymbolInfo{$LibVersion}{$InfoId}{"Volatile"} = 1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008530 }
Andrey Ponomarenko16934472012-03-29 15:37:04 +04008531 if(($ClassID and $MnglName!~/\A(_Z|\?)/)
8532 or (not $ClassID and $CheckHeadersOnly)
8533 or (not $ClassID and not link_symbol($MnglName, $LibVersion, "-Deps")))
8534 { # support for old ABI dumps, GCC >= 4.0
8535 # remangling all manually mangled symbols
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04008536 if($MnglName = mangle_symbol($InfoId, $LibVersion, "GCC"))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008537 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04008538 $SymbolInfo{$LibVersion}{$InfoId}{"MnglName"} = $MnglName;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008539 $MangledNames{$LibVersion}{$MnglName} = 1;
8540 }
8541 }
8542 }
8543 elsif($Remangle==-1)
8544 { # remove mangling
8545 $MnglName = "";
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04008546 $SymbolInfo{$LibVersion}{$InfoId}{"MnglName"} = "";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008547 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008548 if(not $MnglName) {
8549 next;
8550 }
8551 if(not $CompleteSignature{$LibVersion}{$MnglName}{"MnglName"})
8552 { # NOTE: global data may enter here twice
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04008553 %{$CompleteSignature{$LibVersion}{$MnglName}} = %{$SymbolInfo{$LibVersion}{$InfoId}};
8554
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008555 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04008556 if(not checkDump($LibVersion, "2.6"))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008557 { # support for old dumps
8558 # add "Volatile" attribute
8559 if($MnglName=~/_Z(K|)V/) {
8560 $CompleteSignature{$LibVersion}{$MnglName}{"Volatile"}=1;
8561 }
8562 }
8563 # symbol and its symlink have same signatures
8564 if($SymVer{$LibVersion}{$MnglName}) {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04008565 %{$CompleteSignature{$LibVersion}{$SymVer{$LibVersion}{$MnglName}}} = %{$SymbolInfo{$LibVersion}{$InfoId}};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008566 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +04008567
8568 # clean memory
Andrey Ponomarenko16934472012-03-29 15:37:04 +04008569 delete($SymbolInfo{$LibVersion}{$InfoId});
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008570 }
8571 if($COMMON_LANGUAGE{$LibVersion} eq "C++" or $OSgroup eq "windows") {
8572 translateSymbols(keys(%{$CompleteSignature{$LibVersion}}), $LibVersion);
8573 }
8574 if($ExtendedCheck)
8575 { # --ext option
8576 addExtension($LibVersion);
8577 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +04008578
8579 # clean memory
8580 delete($SymbolInfo{$LibVersion});
8581
8582 foreach my $Symbol (keys(%{$CompleteSignature{$LibVersion}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008583 { # detect allocable classes with public exported constructors
8584 # or classes with auto-generated or inline-only constructors
Andrey Ponomarenko9927e332012-10-19 10:50:48 +04008585 # and other temp info
Andrey Ponomarenko85043792012-05-14 16:48:07 +04008586 if(my $ClassId = $CompleteSignature{$LibVersion}{$Symbol}{"Class"})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008587 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04008588 my $ClassName = $TypeInfo{$LibVersion}{$ClassId}{"Name"};
Andrey Ponomarenko85043792012-05-14 16:48:07 +04008589 if($CompleteSignature{$LibVersion}{$Symbol}{"Constructor"}
8590 and not $CompleteSignature{$LibVersion}{$Symbol}{"InLine"})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008591 { # Class() { ... } will not be exported
Andrey Ponomarenko85043792012-05-14 16:48:07 +04008592 if(not $CompleteSignature{$LibVersion}{$Symbol}{"Private"})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008593 {
Andrey Ponomarenko85043792012-05-14 16:48:07 +04008594 if($CheckHeadersOnly or link_symbol($Symbol, $LibVersion, "-Deps")) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008595 $AllocableClass{$LibVersion}{$ClassName} = 1;
8596 }
8597 }
8598 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +04008599 if(not $CompleteSignature{$LibVersion}{$Symbol}{"Private"})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008600 { # all imported class methods
Andrey Ponomarenko85043792012-05-14 16:48:07 +04008601 if(symbolFilter($Symbol, $LibVersion, "Affected", "Binary"))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008602 {
Andrey Ponomarenko85043792012-05-14 16:48:07 +04008603 if($CheckHeadersOnly)
8604 {
8605 if(not $CompleteSignature{$LibVersion}{$Symbol}{"InLine"}
8606 or $CompleteSignature{$LibVersion}{$Symbol}{"Virt"})
8607 { # all symbols except non-virtual inline
8608 $ClassMethods{"Binary"}{$LibVersion}{$ClassName}{$Symbol} = 1;
8609 }
8610 }
8611 else {
8612 $ClassMethods{"Binary"}{$LibVersion}{$ClassName}{$Symbol} = 1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008613 }
8614 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04008615 if(symbolFilter($Symbol, $LibVersion, "Affected", "Source")) {
Andrey Ponomarenko85043792012-05-14 16:48:07 +04008616 $ClassMethods{"Source"}{$LibVersion}{$ClassName}{$Symbol} = 1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008617 }
8618 }
Andrey Ponomarenko16934472012-03-29 15:37:04 +04008619 $ClassNames{$LibVersion}{$ClassName} = 1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008620 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +04008621 if(my $RetId = $CompleteSignature{$LibVersion}{$Symbol}{"Return"})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008622 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04008623 my %Base = get_BaseType($RetId, $LibVersion);
Andrey Ponomarenko85043792012-05-14 16:48:07 +04008624 if(defined $Base{"Type"}
8625 and $Base{"Type"}=~/Struct|Class/)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008626 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04008627 my $Name = $TypeInfo{$LibVersion}{$Base{"Tid"}}{"Name"};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008628 if($Name=~/<([^<>\s]+)>/)
8629 {
8630 if(my $Tid = getTypeIdByName($1, $LibVersion)) {
8631 $ReturnedClass{$LibVersion}{$Tid} = 1;
8632 }
8633 }
8634 else {
8635 $ReturnedClass{$LibVersion}{$Base{"Tid"}} = 1;
8636 }
8637 }
8638 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +04008639 foreach my $Num (keys(%{$CompleteSignature{$LibVersion}{$Symbol}{"Param"}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008640 {
Andrey Ponomarenko85043792012-05-14 16:48:07 +04008641 my $PId = $CompleteSignature{$LibVersion}{$Symbol}{"Param"}{$Num}{"type"};
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04008642 if(get_PLevel($PId, $LibVersion)>=1)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008643 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04008644 if(my %Base = get_BaseType($PId, $LibVersion))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008645 {
Andrey Ponomarenko16934472012-03-29 15:37:04 +04008646 if($Base{"Type"}=~/Struct|Class/)
8647 {
Andrey Ponomarenko85043792012-05-14 16:48:07 +04008648 $ParamClass{$LibVersion}{$Base{"Tid"}}{$Symbol} = 1;
Andrey Ponomarenko16934472012-03-29 15:37:04 +04008649 foreach my $SubId (get_sub_classes($Base{"Tid"}, $LibVersion, 1))
8650 { # mark all derived classes
Andrey Ponomarenko85043792012-05-14 16:48:07 +04008651 $ParamClass{$LibVersion}{$SubId}{$Symbol} = 1;
Andrey Ponomarenko16934472012-03-29 15:37:04 +04008652 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008653 }
8654 }
8655 }
8656 }
Andrey Ponomarenko9927e332012-10-19 10:50:48 +04008657
8658 # mapping {short name => symbols}
8659 $Func_ShortName{$LibVersion}{$CompleteSignature{$LibVersion}{$Symbol}{"ShortName"}}{$Symbol} = 1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008660 }
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04008661 foreach my $MnglName (keys(%VTableClass))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008662 { # reconstruct header name for v-tables
Andrey Ponomarenko9927e332012-10-19 10:50:48 +04008663 if(index($MnglName, "_ZTV")==0)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008664 {
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04008665 if(my $ClassName = $VTableClass{$MnglName})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008666 {
8667 if(my $ClassId = $TName_Tid{$LibVersion}{$ClassName}) {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04008668 $CompleteSignature{$LibVersion}{$MnglName}{"Header"} = $TypeInfo{$LibVersion}{$ClassId}{"Header"};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008669 }
8670 }
8671 }
8672 }
Andrey Ponomarenko16934472012-03-29 15:37:04 +04008673
8674 # types
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04008675 foreach my $TypeId (keys(%{$TypeInfo{$LibVersion}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008676 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04008677 if(my $TName = $TypeInfo{$LibVersion}{$TypeId}{"Name"})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008678 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04008679 if(defined $TypeInfo{$LibVersion}{$TypeId}{"VTable"}) {
8680 $ClassNames{$LibVersion}{$TName} = 1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008681 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04008682 if(defined $TypeInfo{$LibVersion}{$TypeId}{"Base"})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008683 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04008684 $ClassNames{$LibVersion}{$TName} = 1;
8685 foreach my $Bid (keys(%{$TypeInfo{$LibVersion}{$TypeId}{"Base"}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008686 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04008687 if(my $BName = $TypeInfo{$LibVersion}{$Bid}{"Name"}) {
8688 $ClassNames{$LibVersion}{$BName} = 1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008689 }
8690 }
8691 }
8692 }
8693 }
8694}
8695
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04008696sub register_TypeUsage($$)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008697{
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04008698 my ($TypeId, $LibVersion) = @_;
8699 if(not $TypeId) {
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04008700 return 0;
8701 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04008702 if($UsedType{$LibVersion}{$TypeId})
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04008703 { # already registered
8704 return 1;
8705 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04008706 my %TInfo = get_Type($TypeId, $LibVersion);
Andrey Ponomarenko85043792012-05-14 16:48:07 +04008707 if($TInfo{"Type"})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008708 {
Andrey Ponomarenko85043792012-05-14 16:48:07 +04008709 if($TInfo{"Type"}=~/\A(Struct|Union|Class|FuncPtr|MethodPtr|FieldPtr|Enum)\Z/)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008710 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04008711 $UsedType{$LibVersion}{$TypeId} = 1;
Andrey Ponomarenko85043792012-05-14 16:48:07 +04008712 if($TInfo{"Type"}=~/\A(Struct|Class)\Z/)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008713 {
Andrey Ponomarenko85043792012-05-14 16:48:07 +04008714 foreach my $BaseId (keys(%{$TInfo{"Base"}}))
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04008715 { # register base classes
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04008716 register_TypeUsage($BaseId, $LibVersion);
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04008717 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +04008718 foreach my $TPos (keys(%{$TInfo{"TParam"}}))
8719 {
8720 my $TPName = $TInfo{"TParam"}{$TPos}{"name"};
8721 if(my $TTid = $TName_Tid{$LibVersion}{$TPName}) {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04008722 register_TypeUsage($TTid, $LibVersion);
Andrey Ponomarenko85043792012-05-14 16:48:07 +04008723 }
8724 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008725 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +04008726 foreach my $Memb_Pos (keys(%{$TInfo{"Memb"}}))
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04008727 {
Andrey Ponomarenko85043792012-05-14 16:48:07 +04008728 if(my $MTid = $TInfo{"Memb"}{$Memb_Pos}{"type"}) {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04008729 register_TypeUsage($MTid, $LibVersion);
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04008730 }
8731 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +04008732 if($TInfo{"Type"} eq "FuncPtr"
8733 or $TInfo{"Type"} eq "MethodPtr")
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04008734 {
Andrey Ponomarenko85043792012-05-14 16:48:07 +04008735 if(my $RTid = $TInfo{"Return"}) {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04008736 register_TypeUsage($RTid, $LibVersion);
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04008737 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +04008738 foreach my $Memb_Pos (keys(%{$TInfo{"Param"}}))
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04008739 {
Andrey Ponomarenko85043792012-05-14 16:48:07 +04008740 if(my $MTid = $TInfo{"Param"}{$Memb_Pos}{"type"}) {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04008741 register_TypeUsage($MTid, $LibVersion);
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04008742 }
8743 }
8744 }
8745 return 1;
8746 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +04008747 elsif($TInfo{"Type"}=~/\A(Const|ConstVolatile|Volatile|Pointer|Ref|Restrict|Array|Typedef)\Z/)
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04008748 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04008749 $UsedType{$LibVersion}{$TypeId} = 1;
8750 register_TypeUsage($TInfo{"BaseType"}{"Tid"}, $LibVersion);
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04008751 return 1;
8752 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04008753 elsif($TInfo{"Type"} eq "Intrinsic")
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04008754 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04008755 $UsedType{$LibVersion}{$TypeId} = 1;
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04008756 return 1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008757 }
8758 }
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04008759 return 0;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008760}
8761
Andrey Ponomarenko85043792012-05-14 16:48:07 +04008762sub selectSymbol($$$$)
Andrey Ponomarenko35c44fd2012-06-18 17:50:25 +04008763{ # select symbol to check or to dump
Andrey Ponomarenko85043792012-05-14 16:48:07 +04008764 my ($Symbol, $SInfo, $Level, $LibVersion) = @_;
8765
Andrey Ponomarenko35c44fd2012-06-18 17:50:25 +04008766 if($Level eq "Dump")
8767 {
8768 if($SInfo->{"Virt"} or $SInfo->{"PureVirt"})
8769 { # TODO: check if this symbol is from
8770 # base classes of other target symbols
8771 return 1;
8772 }
8773 }
8774
Andrey Ponomarenko85043792012-05-14 16:48:07 +04008775 if(not $STDCXX_TESTING and $Symbol=~/\A(_ZS|_ZNS|_ZNKS)/)
8776 { # stdc++ interfaces
8777 return 0;
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04008778 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +04008779
8780 my $Target = 0;
8781 if(my $Header = $SInfo->{"Header"}) {
8782 $Target = (is_target_header($Header, 1) or is_target_header($Header, 2));
8783 }
8784 if($CheckHeadersOnly)
8785 {
8786 if($Target)
8787 {
8788 if($Level eq "Dump")
8789 { # dumped
8790 if($BinaryOnly)
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04008791 {
Andrey Ponomarenko85043792012-05-14 16:48:07 +04008792 if(not $SInfo->{"InLine"} or $SInfo->{"Data"}) {
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04008793 return 1;
8794 }
8795 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +04008796 else {
8797 return 1;
8798 }
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04008799 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +04008800 elsif($Level eq "Source")
8801 { # checked
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04008802 return 1;
8803 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +04008804 elsif($Level eq "Binary")
8805 { # checked
8806 if(not $SInfo->{"InLine"} or $SInfo->{"Data"}
8807 or $SInfo->{"Virt"} or $SInfo->{"PureVirt"}) {
8808 return 1;
8809 }
8810 }
8811 }
8812 }
8813 else
8814 { # library is available
8815 if(link_symbol($Symbol, $LibVersion, "-Deps"))
8816 { # exported symbols
8817 return 1;
8818 }
8819 if($Level eq "Dump")
8820 { # dumped
Andrey Ponomarenko35c44fd2012-06-18 17:50:25 +04008821 if($BinaryOnly)
8822 {
8823 if($SInfo->{"Data"})
8824 {
8825 if($Target) {
8826 return 1;
8827 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +04008828 }
8829 }
Andrey Ponomarenko35c44fd2012-06-18 17:50:25 +04008830 else
8831 { # SrcBin
Andrey Ponomarenko85043792012-05-14 16:48:07 +04008832 if($Target) {
8833 return 1;
8834 }
8835 }
8836 }
8837 elsif($Level eq "Source")
8838 { # checked
Andrey Ponomarenko01117f12012-06-26 12:23:02 +04008839 if($SInfo->{"PureVirt"} or $SInfo->{"Data"} or $SInfo->{"InLine"}
8840 or isInLineInst($Symbol, $SInfo, $LibVersion))
Andrey Ponomarenko35c44fd2012-06-18 17:50:25 +04008841 { # skip LOCAL symbols
8842 if($Target) {
8843 return 1;
8844 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +04008845 }
8846 }
8847 elsif($Level eq "Binary")
8848 { # checked
8849 if($SInfo->{"PureVirt"} or $SInfo->{"Data"})
8850 {
8851 if($Target) {
8852 return 1;
8853 }
8854 }
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04008855 }
8856 }
8857 return 0;
8858}
8859
Andrey Ponomarenko85043792012-05-14 16:48:07 +04008860sub cleanDump($)
8861{ # clean data
Andrey Ponomarenko16934472012-03-29 15:37:04 +04008862 my $LibVersion = $_[0];
8863 foreach my $InfoId (keys(%{$SymbolInfo{$LibVersion}}))
8864 {
8865 my $MnglName = $SymbolInfo{$LibVersion}{$InfoId}{"MnglName"};
8866 if(not $MnglName) {
8867 delete($SymbolInfo{$LibVersion}{$InfoId});
8868 next;
8869 }
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04008870 my $ShortName = $SymbolInfo{$LibVersion}{$InfoId}{"ShortName"};
Andrey Ponomarenko85043792012-05-14 16:48:07 +04008871 if(not $ShortName) {
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04008872 delete($SymbolInfo{$LibVersion}{$InfoId});
8873 next;
Andrey Ponomarenko16934472012-03-29 15:37:04 +04008874 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +04008875 if($MnglName eq $ShortName)
8876 { # remove duplicate data
8877 delete($SymbolInfo{$LibVersion}{$InfoId}{"MnglName"});
Andrey Ponomarenko16934472012-03-29 15:37:04 +04008878 }
8879 if(not keys(%{$SymbolInfo{$LibVersion}{$InfoId}{"Param"}})) {
8880 delete($SymbolInfo{$LibVersion}{$InfoId}{"Param"});
8881 }
Andrey Ponomarenko01117f12012-06-26 12:23:02 +04008882 if(not keys(%{$SymbolInfo{$LibVersion}{$InfoId}{"TParam"}})) {
8883 delete($SymbolInfo{$LibVersion}{$InfoId}{"TParam"});
8884 }
Andrey Ponomarenko16934472012-03-29 15:37:04 +04008885 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04008886 foreach my $Tid (keys(%{$TypeInfo{$LibVersion}}))
Andrey Ponomarenko85043792012-05-14 16:48:07 +04008887 {
Andrey Ponomarenko01117f12012-06-26 12:23:02 +04008888 delete($TypeInfo{$LibVersion}{$Tid}{"Tid"});
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04008889 foreach my $Attr ("Header", "Line", "Size", "NameSpace")
Andrey Ponomarenko16934472012-03-29 15:37:04 +04008890 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04008891 if(not $TypeInfo{$LibVersion}{$Tid}{$Attr}) {
8892 delete($TypeInfo{$LibVersion}{$Tid}{$Attr});
8893 }
8894 }
Andrey Ponomarenko01117f12012-06-26 12:23:02 +04008895 if(not keys(%{$TypeInfo{$LibVersion}{$Tid}{"TParam"}})) {
8896 delete($TypeInfo{$LibVersion}{$Tid}{"TParam"});
8897 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04008898 }
8899}
8900
8901sub selectType($$)
8902{
8903 my ($Tid, $LibVersion) = @_;
Andrey Ponomarenko9927e332012-10-19 10:50:48 +04008904
8905 if(my $Dupl = $TypeTypedef{$LibVersion}{$Tid})
8906 {
8907 if(defined $TypeInfo{$LibVersion}{$Dupl})
8908 {
8909 if($TypeInfo{$LibVersion}{$Dupl}{"Name"} eq $TypeInfo{$LibVersion}{$Tid}{"Name"})
8910 { # duplicate
8911 return 0;
8912 }
8913 }
8914 }
8915
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04008916 if(my $THeader = $TypeInfo{$LibVersion}{$Tid}{"Header"})
8917 {
8918 if(not isBuiltIn($THeader))
8919 {
8920 if($TypeInfo{$LibVersion}{$Tid}{"Type"}=~/Class|Struct|Union|Enum|Typedef/)
Andrey Ponomarenko16934472012-03-29 15:37:04 +04008921 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04008922 if(not isAnon($TypeInfo{$LibVersion}{$Tid}{"Name"}))
8923 {
8924 if(is_target_header($THeader, $LibVersion))
8925 { # from target headers
8926 if(not selfTypedef($Tid, $LibVersion)) {
8927 return 1;
8928 }
8929 }
Andrey Ponomarenko16934472012-03-29 15:37:04 +04008930 }
8931 }
8932 }
8933 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04008934 return 0;
Andrey Ponomarenko16934472012-03-29 15:37:04 +04008935}
8936
Andrey Ponomarenko85043792012-05-14 16:48:07 +04008937sub removeUnused($$)
8938{ # remove unused data types from the ABI dump
8939 my ($LibVersion, $Kind) = @_;
8940 foreach my $InfoId (keys(%{$SymbolInfo{$LibVersion}}))
8941 {
8942 my %FuncInfo = %{$SymbolInfo{$LibVersion}{$InfoId}};
8943 if(my $RTid = $FuncInfo{"Return"}) {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04008944 register_TypeUsage($RTid, $LibVersion);
Andrey Ponomarenko85043792012-05-14 16:48:07 +04008945 }
8946 if(my $FCid = $FuncInfo{"Class"})
8947 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04008948 register_TypeUsage($FCid, $LibVersion);
8949 if(my $ThisId = getTypeIdByName($TypeInfo{$LibVersion}{$FCid}{"Name"}."*const", $LibVersion))
Andrey Ponomarenko85043792012-05-14 16:48:07 +04008950 { # register "this" pointer
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04008951 $UsedType{$LibVersion}{$ThisId} = 1;
8952 if(my %ThisType = get_Type($ThisId, $LibVersion)) {
8953 register_TypeUsage($ThisType{"BaseType"}{"Tid"}, $LibVersion);
Andrey Ponomarenko85043792012-05-14 16:48:07 +04008954 }
8955 }
8956 }
8957 foreach my $PPos (keys(%{$FuncInfo{"Param"}}))
8958 {
8959 if(my $PTid = $FuncInfo{"Param"}{$PPos}{"type"}) {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04008960 register_TypeUsage($PTid, $LibVersion);
Andrey Ponomarenko85043792012-05-14 16:48:07 +04008961 }
8962 }
8963 foreach my $TPos (keys(%{$FuncInfo{"TParam"}}))
8964 {
8965 my $TPName = $FuncInfo{"TParam"}{$TPos}{"name"};
8966 if(my $TTid = $TName_Tid{$LibVersion}{$TPName}) {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04008967 register_TypeUsage($TTid, $LibVersion);
Andrey Ponomarenko85043792012-05-14 16:48:07 +04008968 }
8969 }
8970 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04008971 foreach my $Tid (keys(%{$TypeInfo{$LibVersion}}))
8972 {
8973 if($UsedType{$LibVersion}{$Tid})
8974 { # All & Derived
8975 next;
8976 }
8977
8978 if($Kind eq "Derived")
Andrey Ponomarenko85043792012-05-14 16:48:07 +04008979 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04008980 if(selectType($Tid, $LibVersion)) {
8981 register_TypeUsage($Tid, $LibVersion);
Andrey Ponomarenko85043792012-05-14 16:48:07 +04008982 }
8983 }
8984 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04008985 foreach my $Tid (keys(%{$TypeInfo{$LibVersion}}))
8986 { # remove unused types
8987 if($UsedType{$LibVersion}{$Tid})
8988 { # All & Derived
8989 next;
8990 }
8991 # remove type
8992 delete($TypeInfo{$LibVersion}{$Tid});
8993 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +04008994
8995 # clean memory
8996 %UsedType = ();
8997}
8998
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04008999sub selfTypedef($$)
Andrey Ponomarenko85043792012-05-14 16:48:07 +04009000{
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04009001 my ($TypeId, $LibVersion) = @_;
9002 my %Type = get_Type($TypeId, $LibVersion);
Andrey Ponomarenko85043792012-05-14 16:48:07 +04009003 if($Type{"Type"} eq "Typedef")
9004 {
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +04009005 my %Base = get_OneStep_BaseType($TypeId, $TypeInfo{$LibVersion});
Andrey Ponomarenko85043792012-05-14 16:48:07 +04009006 if($Base{"Type"}=~/Class|Struct/)
9007 {
9008 if($Type{"Name"} eq $Base{"Name"}) {
9009 return 1;
9010 }
9011 elsif($Type{"Name"}=~/::(\w+)\Z/)
9012 {
9013 if($Type{"Name"} eq $Base{"Name"}."::".$1)
9014 { # QPointer<QWidget>::QPointer
9015 return 1;
9016 }
9017 }
9018 }
9019 }
9020 return 0;
9021}
9022
Andrey Ponomarenko16934472012-03-29 15:37:04 +04009023sub addExtension($)
9024{
9025 my $LibVersion = $_[0];
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04009026 foreach my $Tid (keys(%{$TypeInfo{$LibVersion}}))
Andrey Ponomarenko16934472012-03-29 15:37:04 +04009027 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04009028 if(selectType($Tid, $LibVersion))
Andrey Ponomarenko16934472012-03-29 15:37:04 +04009029 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04009030 my $Symbol = "external_func_".$TypeInfo{$LibVersion}{$Tid}{"Name"};
9031
9032 %{$CompleteSignature{$LibVersion}{$Symbol}} = (
9033 "Header" => "extended.h",
9034 "ShortName" => $Symbol,
9035 "MnglName" => $Symbol,
9036 "Param" => { 0 => { "type"=>$Tid, "name"=>"p1" } }
9037 );
9038
9039 $ExtendedSymbols{$Symbol}=1;
9040 $CheckedSymbols{"Binary"}{$Symbol}=1;
9041 $CheckedSymbols{"Source"}{$Symbol}=1;
Andrey Ponomarenko16934472012-03-29 15:37:04 +04009042 }
9043 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04009044 $ExtendedSymbols{"external_func_0"}=1;
9045 $CheckedSymbols{"Binary"}{"external_func_0"}=1;
9046 $CheckedSymbols{"Source"}{"external_func_0"}=1;
Andrey Ponomarenko16934472012-03-29 15:37:04 +04009047}
9048
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009049sub findMethod($$$)
9050{
9051 my ($VirtFunc, $ClassId, $LibVersion) = @_;
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04009052 foreach my $BaseClass_Id (keys(%{$TypeInfo{$LibVersion}{$ClassId}{"Base"}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009053 {
9054 if(my $VirtMethodInClass = findMethod_Class($VirtFunc, $BaseClass_Id, $LibVersion)) {
9055 return $VirtMethodInClass;
9056 }
9057 elsif(my $VirtMethodInBaseClasses = findMethod($VirtFunc, $BaseClass_Id, $LibVersion)) {
9058 return $VirtMethodInBaseClasses;
9059 }
9060 }
9061 return "";
9062}
9063
9064sub findMethod_Class($$$)
9065{
9066 my ($VirtFunc, $ClassId, $LibVersion) = @_;
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04009067 my $ClassName = $TypeInfo{$LibVersion}{$ClassId}{"Name"};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009068 return "" if(not defined $VirtualTable{$LibVersion}{$ClassName});
9069 my $TargetSuffix = get_symbol_suffix($VirtFunc, 1);
9070 my $TargetShortName = $CompleteSignature{$LibVersion}{$VirtFunc}{"ShortName"};
9071 foreach my $Candidate (keys(%{$VirtualTable{$LibVersion}{$ClassName}}))
9072 { # search for interface with the same parameters suffix (overridden)
9073 if($TargetSuffix eq get_symbol_suffix($Candidate, 1))
9074 {
Andrey Ponomarenkoe3d6bf02012-11-14 11:49:09 +04009075 if($CompleteSignature{$LibVersion}{$VirtFunc}{"Destructor"})
9076 {
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04009077 if($CompleteSignature{$LibVersion}{$Candidate}{"Destructor"})
9078 {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009079 if(($VirtFunc=~/D0E/ and $Candidate=~/D0E/)
9080 or ($VirtFunc=~/D1E/ and $Candidate=~/D1E/)
9081 or ($VirtFunc=~/D2E/ and $Candidate=~/D2E/)) {
9082 return $Candidate;
9083 }
9084 }
9085 }
Andrey Ponomarenkoe3d6bf02012-11-14 11:49:09 +04009086 else
9087 {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009088 if($TargetShortName eq $CompleteSignature{$LibVersion}{$Candidate}{"ShortName"}) {
9089 return $Candidate;
9090 }
9091 }
9092 }
9093 }
9094 return "";
9095}
9096
Andrey Ponomarenko16934472012-03-29 15:37:04 +04009097sub registerVTable($)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009098{
Andrey Ponomarenko16934472012-03-29 15:37:04 +04009099 my $LibVersion = $_[0];
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04009100 foreach my $Symbol (keys(%{$CompleteSignature{$LibVersion}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009101 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04009102 if($CompleteSignature{$LibVersion}{$Symbol}{"Virt"}
9103 or $CompleteSignature{$LibVersion}{$Symbol}{"PureVirt"})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009104 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04009105 my $ClassName = $TypeInfo{$LibVersion}{$CompleteSignature{$LibVersion}{$Symbol}{"Class"}}{"Name"};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009106 next if(not $STDCXX_TESTING and $ClassName=~/\A(std::|__cxxabi)/);
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04009107 if($CompleteSignature{$LibVersion}{$Symbol}{"Destructor"}
9108 and $Symbol=~/D2E/)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009109 { # pure virtual D2-destructors are marked as "virt" in the dump
9110 # virtual D2-destructors are NOT marked as "virt" in the dump
9111 # both destructors are not presented in the v-table
9112 next;
9113 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04009114 my ($MnglName, $VersionSpec, $SymbolVersion) = separate_symbol($Symbol);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009115 $VirtualTable{$LibVersion}{$ClassName}{$MnglName} = 1;
9116 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009117 }
9118}
9119
9120sub registerOverriding($)
9121{
9122 my $LibVersion = $_[0];
9123 my @Classes = keys(%{$VirtualTable{$LibVersion}});
Andrey Ponomarenko85043792012-05-14 16:48:07 +04009124 @Classes = sort {int($TName_Tid{$LibVersion}{$a})<=>int($TName_Tid{$LibVersion}{$b})} @Classes;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009125 foreach my $ClassName (@Classes)
9126 {
9127 foreach my $VirtFunc (keys(%{$VirtualTable{$LibVersion}{$ClassName}}))
9128 {
Andrey Ponomarenko16934472012-03-29 15:37:04 +04009129 if($CompleteSignature{$LibVersion}{$VirtFunc}{"PureVirt"})
9130 { # pure virtuals
9131 next;
9132 }
9133 my $ClassId = $TName_Tid{$LibVersion}{$ClassName};
9134 if(my $Overridden = findMethod($VirtFunc, $ClassId, $LibVersion))
Andrey Ponomarenko85043792012-05-14 16:48:07 +04009135 {
9136 if($CompleteSignature{$LibVersion}{$Overridden}{"Virt"}
9137 or $CompleteSignature{$LibVersion}{$Overridden}{"PureVirt"})
9138 { # both overridden virtual methods
9139 # and implemented pure virtual methods
9140 $CompleteSignature{$LibVersion}{$VirtFunc}{"Override"} = $Overridden;
9141 $OverriddenMethods{$LibVersion}{$Overridden}{$VirtFunc} = 1;
9142 delete($VirtualTable{$LibVersion}{$ClassName}{$VirtFunc}); # remove from v-table model
9143 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009144 }
9145 }
9146 if(not keys(%{$VirtualTable{$LibVersion}{$ClassName}})) {
9147 delete($VirtualTable{$LibVersion}{$ClassName});
9148 }
9149 }
9150}
9151
9152sub setVirtFuncPositions($)
9153{
9154 my $LibVersion = $_[0];
9155 foreach my $ClassName (keys(%{$VirtualTable{$LibVersion}}))
9156 {
9157 my ($Num, $RelPos, $AbsNum) = (1, 0, 1);
9158 foreach my $VirtFunc (sort {int($CompleteSignature{$LibVersion}{$a}{"Line"}) <=> int($CompleteSignature{$LibVersion}{$b}{"Line"})}
9159 sort keys(%{$VirtualTable{$LibVersion}{$ClassName}}))
9160 {
Andrey Ponomarenko16934472012-03-29 15:37:04 +04009161 $VirtualTable{$LibVersion}{$ClassName}{$VirtFunc}=$Num++;
9162
9163 # set relative positions
9164 if(defined $VirtualTable{1}{$ClassName} and defined $VirtualTable{1}{$ClassName}{$VirtFunc}
9165 and defined $VirtualTable{2}{$ClassName} and defined $VirtualTable{2}{$ClassName}{$VirtFunc})
9166 { # relative position excluding added and removed virtual functions
9167 if(not $CompleteSignature{1}{$VirtFunc}{"Override"}
9168 and not $CompleteSignature{2}{$VirtFunc}{"Override"}) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009169 $CompleteSignature{$LibVersion}{$VirtFunc}{"RelPos"} = $RelPos++;
9170 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009171 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009172 }
9173 }
Andrey Ponomarenko16934472012-03-29 15:37:04 +04009174 foreach my $ClassName (keys(%{$ClassNames{$LibVersion}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009175 {
9176 my $AbsNum = 1;
Andrey Ponomarenko16934472012-03-29 15:37:04 +04009177 foreach my $VirtFunc (getVTable_Model($TName_Tid{$LibVersion}{$ClassName}, $LibVersion)) {
9178 $VirtualTable_Model{$LibVersion}{$ClassName}{$VirtFunc}=$AbsNum++;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009179 }
9180 }
9181}
9182
9183sub get_sub_classes($$$)
9184{
9185 my ($ClassId, $LibVersion, $Recursive) = @_;
9186 return () if(not defined $Class_SubClasses{$LibVersion}{$ClassId});
9187 my @Subs = ();
9188 foreach my $SubId (keys(%{$Class_SubClasses{$LibVersion}{$ClassId}}))
9189 {
Andrey Ponomarenko16934472012-03-29 15:37:04 +04009190 if($Recursive)
9191 {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009192 foreach my $SubSubId (get_sub_classes($SubId, $LibVersion, $Recursive)) {
9193 push(@Subs, $SubSubId);
9194 }
9195 }
9196 push(@Subs, $SubId);
9197 }
9198 return @Subs;
9199}
9200
9201sub get_base_classes($$$)
9202{
9203 my ($ClassId, $LibVersion, $Recursive) = @_;
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04009204 my %ClassType = get_Type($ClassId, $LibVersion);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009205 return () if(not defined $ClassType{"Base"});
9206 my @Bases = ();
9207 foreach my $BaseId (sort {int($ClassType{"Base"}{$a}{"pos"})<=>int($ClassType{"Base"}{$b}{"pos"})}
9208 keys(%{$ClassType{"Base"}}))
9209 {
Andrey Ponomarenko16934472012-03-29 15:37:04 +04009210 if($Recursive)
9211 {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009212 foreach my $SubBaseId (get_base_classes($BaseId, $LibVersion, $Recursive)) {
9213 push(@Bases, $SubBaseId);
9214 }
9215 }
9216 push(@Bases, $BaseId);
9217 }
9218 return @Bases;
9219}
9220
Andrey Ponomarenko16934472012-03-29 15:37:04 +04009221sub getVTable_Model($$)
9222{ # return an ordered list of v-table elements
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009223 my ($ClassId, $LibVersion) = @_;
9224 my @Bases = get_base_classes($ClassId, $LibVersion, 1);
9225 my @Elements = ();
9226 foreach my $BaseId (@Bases, $ClassId)
9227 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04009228 if(my $BName = $TypeInfo{$LibVersion}{$BaseId}{"Name"})
Andrey Ponomarenko85043792012-05-14 16:48:07 +04009229 {
9230 if(defined $VirtualTable{$LibVersion}{$BName})
9231 {
9232 my @VFunctions = keys(%{$VirtualTable{$LibVersion}{$BName}});
9233 @VFunctions = sort {int($CompleteSignature{$LibVersion}{$a}{"Line"}) <=> int($CompleteSignature{$LibVersion}{$b}{"Line"})} @VFunctions;
9234 foreach my $VFunc (@VFunctions) {
9235 push(@Elements, $VFunc);
9236 }
9237 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009238 }
9239 }
9240 return @Elements;
9241}
9242
9243sub getVShift($$)
9244{
9245 my ($ClassId, $LibVersion) = @_;
9246 my @Bases = get_base_classes($ClassId, $LibVersion, 1);
9247 my $VShift = 0;
9248 foreach my $BaseId (@Bases)
9249 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04009250 if(my $BName = $TypeInfo{$LibVersion}{$BaseId}{"Name"})
Andrey Ponomarenko85043792012-05-14 16:48:07 +04009251 {
9252 if(defined $VirtualTable{$LibVersion}{$BName}) {
9253 $VShift+=keys(%{$VirtualTable{$LibVersion}{$BName}});
9254 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009255 }
9256 }
9257 return $VShift;
9258}
9259
9260sub getShift($$)
9261{
9262 my ($ClassId, $LibVersion) = @_;
9263 my @Bases = get_base_classes($ClassId, $LibVersion, 0);
9264 my $Shift = 0;
9265 foreach my $BaseId (@Bases)
9266 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04009267 if(my $Size = $TypeInfo{$LibVersion}{$BaseId}{"Size"})
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04009268 {
9269 if($Size!=1)
9270 { # not empty base class
9271 $Shift+=$Size;
9272 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009273 }
9274 }
9275 return $Shift;
9276}
9277
Andrey Ponomarenko16934472012-03-29 15:37:04 +04009278sub getVTable_Size($$)
9279{ # number of v-table elements
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009280 my ($ClassName, $LibVersion) = @_;
Andrey Ponomarenko16934472012-03-29 15:37:04 +04009281 my $Size = 0;
9282 # three approaches
9283 if(not $Size)
9284 { # real size
9285 if(my %VTable = getVTable_Real($ClassName, $LibVersion)) {
9286 $Size = keys(%VTable);
9287 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009288 }
Andrey Ponomarenko16934472012-03-29 15:37:04 +04009289 if(not $Size)
9290 { # shared library symbol size
9291 if($Size = getSymbolSize($ClassVTable{$ClassName}, $LibVersion)) {
9292 $Size /= $WORD_SIZE{$LibVersion};
9293 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009294 }
Andrey Ponomarenko16934472012-03-29 15:37:04 +04009295 if(not $Size)
9296 { # model size
9297 if(defined $VirtualTable_Model{$LibVersion}{$ClassName}) {
9298 $Size = keys(%{$VirtualTable_Model{$LibVersion}{$ClassName}}) + 2;
9299 }
9300 }
9301 return $Size;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009302}
9303
9304sub isCopyingClass($$)
9305{
9306 my ($TypeId, $LibVersion) = @_;
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04009307 return $TypeInfo{$LibVersion}{$TypeId}{"Copied"};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009308}
9309
9310sub isLeafClass($$)
9311{
9312 my ($ClassId, $LibVersion) = @_;
9313 return (not keys(%{$Class_SubClasses{$LibVersion}{$ClassId}}));
9314}
9315
9316sub havePubFields($)
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04009317{ # check structured type for public fields
9318 return isAccessible($_[0], {}, 0, -1);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009319}
9320
9321sub isAccessible($$$$)
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04009322{ # check interval in structured type for public fields
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009323 my ($TypePtr, $Skip, $Start, $End) = @_;
9324 return 0 if(not $TypePtr);
9325 if($End==-1) {
9326 $End = keys(%{$TypePtr->{"Memb"}})-1;
9327 }
9328 foreach my $MemPos (keys(%{$TypePtr->{"Memb"}}))
9329 {
9330 if($Skip and $Skip->{$MemPos})
9331 { # skip removed/added fields
9332 next;
9333 }
9334 if(int($MemPos)>=$Start and int($MemPos)<=$End)
9335 {
9336 if(isPublic($TypePtr, $MemPos)) {
9337 return ($MemPos+1);
9338 }
9339 }
9340 }
9341 return 0;
9342}
9343
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009344sub isReserved($)
9345{ # reserved fields == private
9346 my $MName = $_[0];
9347 if($MName=~/reserved|padding|f_spare/i) {
9348 return 1;
9349 }
Andrey Ponomarenko9927e332012-10-19 10:50:48 +04009350 if($MName=~/\A[_]*(spare|pad|unused)[_\d]*\Z/i) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009351 return 1;
9352 }
9353 if($MName=~/(pad\d+)/i) {
9354 return 1;
9355 }
9356 return 0;
9357}
9358
9359sub isPublic($$)
9360{
9361 my ($TypePtr, $FieldPos) = @_;
9362 return 0 if(not $TypePtr);
9363 return 0 if(not defined $TypePtr->{"Memb"}{$FieldPos});
9364 return 0 if(not defined $TypePtr->{"Memb"}{$FieldPos}{"name"});
9365 if(not $TypePtr->{"Memb"}{$FieldPos}{"access"})
9366 { # by name in C language
9367 # FIXME: add other methods to detect private members
9368 my $MName = $TypePtr->{"Memb"}{$FieldPos}{"name"};
9369 if($MName=~/priv|abidata|parent_object/i)
9370 { # C-styled private data
9371 return 0;
9372 }
9373 if(lc($MName) eq "abi")
9374 { # ABI information/reserved field
9375 return 0;
9376 }
9377 if(isReserved($MName))
9378 { # reserved fields
9379 return 0;
9380 }
9381 return 1;
9382 }
9383 elsif($TypePtr->{"Memb"}{$FieldPos}{"access"} ne "private")
9384 { # by access in C++ language
9385 return 1;
9386 }
9387 return 0;
9388}
9389
Andrey Ponomarenko16934472012-03-29 15:37:04 +04009390sub getVTable_Real($$)
9391{
9392 my ($ClassName, $LibVersion) = @_;
9393 if(my $ClassId = $TName_Tid{$LibVersion}{$ClassName})
9394 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04009395 my %Type = get_Type($ClassId, $LibVersion);
Andrey Ponomarenko16934472012-03-29 15:37:04 +04009396 if(defined $Type{"VTable"}) {
9397 return %{$Type{"VTable"}};
9398 }
9399 }
9400 return ();
9401}
9402
9403sub cmpVTables($)
9404{
9405 my $ClassName = $_[0];
9406 my $Res = cmpVTables_Real($ClassName, 1);
9407 if($Res==-1) {
9408 $Res = cmpVTables_Model($ClassName);
9409 }
9410 return $Res;
9411}
9412
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009413sub cmpVTables_Model($)
9414{
9415 my $ClassName = $_[0];
Andrey Ponomarenko16934472012-03-29 15:37:04 +04009416 foreach my $Symbol (keys(%{$VirtualTable_Model{1}{$ClassName}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009417 {
Andrey Ponomarenko16934472012-03-29 15:37:04 +04009418 if(not defined $VirtualTable_Model{2}{$ClassName}{$Symbol}) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009419 return 1;
9420 }
9421 }
9422 return 0;
9423}
9424
Andrey Ponomarenko16934472012-03-29 15:37:04 +04009425sub cmpVTables_Real($$)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009426{
9427 my ($ClassName, $Strong) = @_;
Andrey Ponomarenko16934472012-03-29 15:37:04 +04009428 if(defined $Cache{"cmpVTables_Real"}{$Strong}{$ClassName}) {
9429 return $Cache{"cmpVTables_Real"}{$Strong}{$ClassName};
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04009430 }
Andrey Ponomarenko16934472012-03-29 15:37:04 +04009431 my %VTable_Old = getVTable_Real($ClassName, 1);
9432 my %VTable_New = getVTable_Real($ClassName, 2);
9433 if(not %VTable_Old or not %VTable_New)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009434 { # old ABI dumps
Andrey Ponomarenko16934472012-03-29 15:37:04 +04009435 return ($Cache{"cmpVTables_Real"}{$Strong}{$ClassName} = -1);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009436 }
Andrey Ponomarenko16934472012-03-29 15:37:04 +04009437 my %Indexes = map {$_=>1} (keys(%VTable_Old), keys(%VTable_New));
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009438 foreach my $Offset (sort {int($a)<=>int($b)} keys(%Indexes))
9439 {
Andrey Ponomarenko16934472012-03-29 15:37:04 +04009440 if(not defined $VTable_Old{$Offset})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009441 { # v-table v.1 < v-table v.2
Andrey Ponomarenko16934472012-03-29 15:37:04 +04009442 return ($Cache{"cmpVTables_Real"}{$Strong}{$ClassName} = $Strong);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009443 }
Andrey Ponomarenko16934472012-03-29 15:37:04 +04009444 my $Entry1 = $VTable_Old{$Offset};
9445 if(not defined $VTable_New{$Offset})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009446 { # v-table v.1 > v-table v.2
Andrey Ponomarenko16934472012-03-29 15:37:04 +04009447 return ($Cache{"cmpVTables_Real"}{$Strong}{$ClassName} = ($Strong or $Entry1!~/__cxa_pure_virtual/));
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009448 }
Andrey Ponomarenko16934472012-03-29 15:37:04 +04009449 my $Entry2 = $VTable_New{$Offset};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009450 $Entry1 = simpleVEntry($Entry1);
9451 $Entry2 = simpleVEntry($Entry2);
9452 if($Entry1 ne $Entry2)
9453 { # register as changed
9454 if($Entry1=~/::([^:]+)\Z/)
9455 {
9456 my $M1 = $1;
9457 if($Entry2=~/::([^:]+)\Z/)
9458 {
9459 my $M2 = $1;
9460 if($M1 eq $M2)
9461 { # overridden
9462 next;
9463 }
9464 }
9465 }
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04009466 if(differentDumps("G"))
9467 {
9468 if($Entry1=~/\A\-(0x|\d+)/ and $Entry2=~/\A\-(0x|\d+)/)
9469 {
9470 # GCC 4.6.1: -0x00000000000000010
9471 # GCC 4.7.0: -16
9472 next;
9473 }
9474 }
Andrey Ponomarenko16934472012-03-29 15:37:04 +04009475 return ($Cache{"cmpVTables_Real"}{$Strong}{$ClassName} = 1);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009476 }
9477 }
Andrey Ponomarenko16934472012-03-29 15:37:04 +04009478 return ($Cache{"cmpVTables_Real"}{$Strong}{$ClassName} = 0);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009479}
9480
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04009481sub mergeVTables($)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009482{ # merging v-tables without diagnostics
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04009483 my $Level = $_[0];
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009484 foreach my $ClassName (keys(%{$VirtualTable{1}}))
9485 {
Andrey Ponomarenko16934472012-03-29 15:37:04 +04009486 if($VTableChanged_M{$ClassName})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009487 { # already registered
9488 next;
9489 }
Andrey Ponomarenko16934472012-03-29 15:37:04 +04009490 if(cmpVTables_Real($ClassName, 0)==1)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009491 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04009492 my @Affected = (keys(%{$ClassMethods{$Level}{1}{$ClassName}}));
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009493 foreach my $Symbol (@Affected)
9494 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04009495 %{$CompatProblems{$Level}{$Symbol}{"Virtual_Table_Changed_Unknown"}{$ClassName}}=(
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009496 "Type_Name"=>$ClassName,
9497 "Type_Type"=>"Class",
9498 "Target"=>$ClassName);
9499 }
9500 }
9501 }
9502}
9503
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04009504sub mergeBases($)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009505{
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04009506 my $Level = $_[0];
Andrey Ponomarenko16934472012-03-29 15:37:04 +04009507 foreach my $ClassName (keys(%{$ClassNames{1}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009508 { # detect added and removed virtual functions
Andrey Ponomarenko16934472012-03-29 15:37:04 +04009509 my $ClassId = $TName_Tid{1}{$ClassName};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009510 next if(not $ClassId);
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04009511 if(defined $VirtualTable{2}{$ClassName})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009512 {
Andrey Ponomarenko16934472012-03-29 15:37:04 +04009513 foreach my $Symbol (keys(%{$VirtualTable{2}{$ClassName}}))
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04009514 {
Andrey Ponomarenko16934472012-03-29 15:37:04 +04009515 if($TName_Tid{1}{$ClassName}
9516 and not defined $VirtualTable{1}{$ClassName}{$Symbol})
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04009517 { # added to v-table
Andrey Ponomarenko16934472012-03-29 15:37:04 +04009518 if(defined $CompleteSignature{1}{$Symbol}
9519 and $CompleteSignature{1}{$Symbol}{"Virt"})
9520 { # override some method in v.1
9521 next;
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04009522 }
Andrey Ponomarenko16934472012-03-29 15:37:04 +04009523 $AddedInt_Virt{$Level}{$ClassName}{$Symbol} = 1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009524 }
9525 }
9526 }
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04009527 if(defined $VirtualTable{1}{$ClassName})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009528 {
Andrey Ponomarenko16934472012-03-29 15:37:04 +04009529 foreach my $Symbol (keys(%{$VirtualTable{1}{$ClassName}}))
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04009530 {
Andrey Ponomarenko16934472012-03-29 15:37:04 +04009531 if($TName_Tid{2}{$ClassName}
9532 and not defined $VirtualTable{2}{$ClassName}{$Symbol})
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04009533 { # removed from v-table
Andrey Ponomarenko16934472012-03-29 15:37:04 +04009534 if(defined $CompleteSignature{2}{$Symbol}
9535 and $CompleteSignature{2}{$Symbol}{"Virt"})
9536 { # override some method in v.2
9537 next;
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04009538 }
Andrey Ponomarenko16934472012-03-29 15:37:04 +04009539 $RemovedInt_Virt{$Level}{$ClassName}{$Symbol} = 1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009540 }
9541 }
9542 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04009543 if($Level eq "Binary")
9544 { # Binary-level
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04009545 my %Class_Type = get_Type($ClassId, 1);
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04009546 foreach my $AddedVFunc (keys(%{$AddedInt_Virt{$Level}{$ClassName}}))
9547 { # check replacements, including pure virtual methods
9548 my $AddedPos = $VirtualTable{2}{$ClassName}{$AddedVFunc};
9549 foreach my $RemovedVFunc (keys(%{$RemovedInt_Virt{$Level}{$ClassName}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009550 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04009551 my $RemovedPos = $VirtualTable{1}{$ClassName}{$RemovedVFunc};
9552 if($AddedPos==$RemovedPos)
9553 {
9554 $VirtualReplacement{$AddedVFunc} = $RemovedVFunc;
9555 $VirtualReplacement{$RemovedVFunc} = $AddedVFunc;
9556 last; # other methods will be reported as "added" or "removed"
9557 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009558 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04009559 if(my $RemovedVFunc = $VirtualReplacement{$AddedVFunc})
9560 {
9561 if(lc($AddedVFunc) eq lc($RemovedVFunc))
9562 { # skip: DomUi => DomUI parameter (Qt 4.2.3 to 4.3.0)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009563 next;
9564 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04009565 my $ProblemType = "Virtual_Replacement";
9566 my @Affected = ($RemovedVFunc);
9567 if($CompleteSignature{1}{$RemovedVFunc}{"PureVirt"})
9568 { # pure methods
9569 if(not isUsedClass($ClassId, 1, $Level))
9570 { # not a parameter of some exported method
9571 next;
9572 }
9573 $ProblemType = "Pure_Virtual_Replacement";
Andrey Ponomarenko9927e332012-10-19 10:50:48 +04009574
9575 # affected all methods (both virtual and non-virtual ones)
9576 @Affected = (keys(%{$ClassMethods{$Level}{1}{$ClassName}}));
9577 push(@Affected, keys(%{$OverriddenMethods{1}{$RemovedVFunc}}));
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009578 }
Andrey Ponomarenko9927e332012-10-19 10:50:48 +04009579 $VTableChanged_M{$ClassName}=1;
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04009580 foreach my $AffectedInt (@Affected)
9581 {
9582 if($CompleteSignature{1}{$AffectedInt}{"PureVirt"})
9583 { # affected exported methods only
9584 next;
9585 }
Andrey Ponomarenko9927e332012-10-19 10:50:48 +04009586 if(not symbolFilter($AffectedInt, 1, "Affected", $Level)) {
9587 next;
9588 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04009589 %{$CompatProblems{$Level}{$AffectedInt}{$ProblemType}{$tr_name{$AddedVFunc}}}=(
9590 "Type_Name"=>$Class_Type{"Name"},
9591 "Type_Type"=>"Class",
9592 "Target"=>get_Signature($AddedVFunc, 2),
9593 "Old_Value"=>get_Signature($RemovedVFunc, 1));
9594 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009595 }
9596 }
9597 }
9598 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04009599 if(not checkDump(1, "2.0")
9600 or not checkDump(2, "2.0"))
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04009601 { # support for old ABI dumps
Andrey Ponomarenko9927e332012-10-19 10:50:48 +04009602 # "Base" attribute introduced in ACC 1.22 (ABI dump 2.0 format)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009603 return;
9604 }
Andrey Ponomarenko16934472012-03-29 15:37:04 +04009605 foreach my $ClassName (sort keys(%{$ClassNames{1}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009606 {
Andrey Ponomarenko16934472012-03-29 15:37:04 +04009607 my $ClassId_Old = $TName_Tid{1}{$ClassName};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009608 next if(not $ClassId_Old);
9609 if(not isCreatable($ClassId_Old, 1))
9610 { # skip classes without public constructors (including auto-generated)
9611 # example: class has only a private exported or private inline constructor
9612 next;
9613 }
9614 if($ClassName=~/>/)
9615 { # skip affected template instances
9616 next;
9617 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04009618 my %Class_Old = get_Type($ClassId_Old, 1);
Andrey Ponomarenko16934472012-03-29 15:37:04 +04009619 my $ClassId_New = $TName_Tid{2}{$ClassName};
Andrey Ponomarenko85043792012-05-14 16:48:07 +04009620 if(not $ClassId_New) {
9621 next;
9622 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04009623 my %Class_New = get_Type($ClassId_New, 2);
Andrey Ponomarenko85043792012-05-14 16:48:07 +04009624 if($Class_New{"Type"}!~/Class|Struct/)
9625 { # became typedef
9626 if($Level eq "Binary") {
9627 next;
9628 }
9629 if($Level eq "Source")
9630 {
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +04009631 %Class_New = get_PureType($ClassId_New, $TypeInfo{2});
Andrey Ponomarenko85043792012-05-14 16:48:07 +04009632 if($Class_New{"Type"}!~/Class|Struct/) {
9633 next;
9634 }
9635 $ClassId_New = $Class_New{"Tid"};
9636 }
9637 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009638 my @Bases_Old = sort {$Class_Old{"Base"}{$a}{"pos"}<=>$Class_Old{"Base"}{$b}{"pos"}} keys(%{$Class_Old{"Base"}});
9639 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 +04009640
9641 my %Tr_Old = map {$TypeInfo{1}{$_}{"Name"} => uncover_typedefs($TypeInfo{1}{$_}{"Name"}, 1)} @Bases_Old;
9642 my %Tr_New = map {$TypeInfo{2}{$_}{"Name"} => uncover_typedefs($TypeInfo{2}{$_}{"Name"}, 2)} @Bases_New;
9643
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009644 my ($BNum1, $BNum2) = (1, 1);
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +04009645 my %BasePos_Old = map {$Tr_Old{$TypeInfo{1}{$_}{"Name"}} => $BNum1++} @Bases_Old;
9646 my %BasePos_New = map {$Tr_New{$TypeInfo{2}{$_}{"Name"}} => $BNum2++} @Bases_New;
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04009647 my %ShortBase_Old = map {get_ShortType($_, 1) => 1} @Bases_Old;
9648 my %ShortBase_New = map {get_ShortType($_, 2) => 1} @Bases_New;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009649 my $Shift_Old = getShift($ClassId_Old, 1);
9650 my $Shift_New = getShift($ClassId_New, 2);
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +04009651 my %BaseId_New = map {$Tr_New{$TypeInfo{2}{$_}{"Name"}} => $_} @Bases_New;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009652 my ($Added, $Removed) = (0, 0);
9653 my @StableBases_Old = ();
9654 foreach my $BaseId (@Bases_Old)
9655 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04009656 my $BaseName = $TypeInfo{1}{$BaseId}{"Name"};
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +04009657 if($BasePos_New{$Tr_Old{$BaseName}}) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009658 push(@StableBases_Old, $BaseId);
9659 }
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +04009660 elsif(not $ShortBase_New{$Tr_Old{$BaseName}}
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04009661 and not $ShortBase_New{get_ShortType($BaseId, 1)})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009662 { # removed base
9663 # excluding namespace::SomeClass to SomeClass renaming
9664 my $ProblemKind = "Removed_Base_Class";
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04009665 if($Level eq "Binary")
9666 { # Binary-level
9667 if($Shift_Old ne $Shift_New)
9668 { # affected fields
9669 if(havePubFields(\%Class_Old)) {
9670 $ProblemKind .= "_And_Shift";
9671 }
9672 elsif($Class_Old{"Size"} ne $Class_New{"Size"}) {
9673 $ProblemKind .= "_And_Size";
9674 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009675 }
Andrey Ponomarenko16934472012-03-29 15:37:04 +04009676 if(keys(%{$VirtualTable_Model{1}{$BaseName}})
9677 and cmpVTables($ClassName)==1)
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04009678 { # affected v-table
9679 $ProblemKind .= "_And_VTable";
Andrey Ponomarenko16934472012-03-29 15:37:04 +04009680 $VTableChanged_M{$ClassName}=1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009681 }
9682 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04009683 my @Affected = keys(%{$ClassMethods{$Level}{1}{$ClassName}});
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009684 foreach my $SubId (get_sub_classes($ClassId_Old, 1, 1))
9685 {
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +04009686 if(my $SubName = $TypeInfo{1}{$SubId}{"Name"})
9687 {
9688 push(@Affected, keys(%{$ClassMethods{$Level}{1}{$SubName}}));
9689 if($ProblemKind=~/VTable/) {
9690 $VTableChanged_M{$SubName}=1;
9691 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009692 }
9693 }
9694 foreach my $Interface (@Affected)
9695 {
Andrey Ponomarenko9927e332012-10-19 10:50:48 +04009696 if(not symbolFilter($Interface, 1, "Affected", $Level)) {
9697 next;
9698 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04009699 %{$CompatProblems{$Level}{$Interface}{$ProblemKind}{"this"}}=(
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009700 "Type_Name"=>$ClassName,
9701 "Type_Type"=>"Class",
9702 "Target"=>$BaseName,
9703 "Old_Size"=>$Class_Old{"Size"}*$BYTE_SIZE,
9704 "New_Size"=>$Class_New{"Size"}*$BYTE_SIZE,
9705 "Shift"=>abs($Shift_New-$Shift_Old) );
9706 }
9707 $Removed+=1;
9708 }
9709 }
9710 my @StableBases_New = ();
9711 foreach my $BaseId (@Bases_New)
9712 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04009713 my $BaseName = $TypeInfo{2}{$BaseId}{"Name"};
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +04009714 if($BasePos_Old{$Tr_New{$BaseName}}) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009715 push(@StableBases_New, $BaseId);
9716 }
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +04009717 elsif(not $ShortBase_Old{$Tr_New{$BaseName}}
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04009718 and not $ShortBase_Old{get_ShortType($BaseId, 2)})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009719 { # added base
9720 # excluding namespace::SomeClass to SomeClass renaming
9721 my $ProblemKind = "Added_Base_Class";
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04009722 if($Level eq "Binary")
9723 { # Binary-level
9724 if($Shift_Old ne $Shift_New)
9725 { # affected fields
9726 if(havePubFields(\%Class_Old)) {
9727 $ProblemKind .= "_And_Shift";
9728 }
9729 elsif($Class_Old{"Size"} ne $Class_New{"Size"}) {
9730 $ProblemKind .= "_And_Size";
9731 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009732 }
Andrey Ponomarenko16934472012-03-29 15:37:04 +04009733 if(keys(%{$VirtualTable_Model{2}{$BaseName}})
9734 and cmpVTables($ClassName)==1)
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04009735 { # affected v-table
9736 $ProblemKind .= "_And_VTable";
Andrey Ponomarenko16934472012-03-29 15:37:04 +04009737 $VTableChanged_M{$ClassName}=1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009738 }
9739 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04009740 my @Affected = keys(%{$ClassMethods{$Level}{1}{$ClassName}});
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009741 foreach my $SubId (get_sub_classes($ClassId_Old, 1, 1))
9742 {
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +04009743 if(my $SubName = $TypeInfo{1}{$SubId}{"Name"})
9744 {
9745 push(@Affected, keys(%{$ClassMethods{$Level}{1}{$SubName}}));
9746 if($ProblemKind=~/VTable/) {
9747 $VTableChanged_M{$SubName}=1;
9748 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009749 }
9750 }
9751 foreach my $Interface (@Affected)
9752 {
Andrey Ponomarenko9927e332012-10-19 10:50:48 +04009753 if(not symbolFilter($Interface, 1, "Affected", $Level)) {
9754 next;
9755 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04009756 %{$CompatProblems{$Level}{$Interface}{$ProblemKind}{"this"}}=(
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009757 "Type_Name"=>$ClassName,
9758 "Type_Type"=>"Class",
9759 "Target"=>$BaseName,
9760 "Old_Size"=>$Class_Old{"Size"}*$BYTE_SIZE,
9761 "New_Size"=>$Class_New{"Size"}*$BYTE_SIZE,
9762 "Shift"=>abs($Shift_New-$Shift_Old) );
9763 }
9764 $Added+=1;
9765 }
9766 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04009767 if($Level eq "Binary")
9768 { # Binary-level
9769 ($BNum1, $BNum2) = (1, 1);
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +04009770 my %BaseRelPos_Old = map {$Tr_Old{$TypeInfo{1}{$_}{"Name"}} => $BNum1++} @StableBases_Old;
9771 my %BaseRelPos_New = map {$Tr_New{$TypeInfo{2}{$_}{"Name"}} => $BNum2++} @StableBases_New;
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04009772 foreach my $BaseId (@Bases_Old)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009773 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04009774 my $BaseName = $TypeInfo{1}{$BaseId}{"Name"};
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +04009775 if(my $NewPos = $BaseRelPos_New{$Tr_Old{$BaseName}})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009776 {
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +04009777 my $BaseNewId = $BaseId_New{$Tr_Old{$BaseName}};
9778 my $OldPos = $BaseRelPos_Old{$Tr_Old{$BaseName}};
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04009779 if($NewPos!=$OldPos)
9780 { # changed position of the base class
9781 foreach my $Interface (keys(%{$ClassMethods{$Level}{1}{$ClassName}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009782 {
Andrey Ponomarenko9927e332012-10-19 10:50:48 +04009783 if(not symbolFilter($Interface, 1, "Affected", $Level)) {
9784 next;
9785 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04009786 %{$CompatProblems{$Level}{$Interface}{"Base_Class_Position"}{"this"}}=(
9787 "Type_Name"=>$ClassName,
9788 "Type_Type"=>"Class",
9789 "Target"=>$BaseName,
9790 "Old_Value"=>$OldPos-1,
9791 "New_Value"=>$NewPos-1 );
9792 }
9793 }
9794 if($Class_Old{"Base"}{$BaseId}{"virtual"}
9795 and not $Class_New{"Base"}{$BaseNewId}{"virtual"})
9796 { # became non-virtual base
9797 foreach my $Interface (keys(%{$ClassMethods{$Level}{1}{$ClassName}}))
9798 {
Andrey Ponomarenko9927e332012-10-19 10:50:48 +04009799 if(not symbolFilter($Interface, 1, "Affected", $Level)) {
9800 next;
9801 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04009802 %{$CompatProblems{$Level}{$Interface}{"Base_Class_Became_Non_Virtually_Inherited"}{"this->".$BaseName}}=(
9803 "Type_Name"=>$ClassName,
9804 "Type_Type"=>"Class",
9805 "Target"=>$BaseName );
9806 }
9807 }
9808 elsif(not $Class_Old{"Base"}{$BaseId}{"virtual"}
9809 and $Class_New{"Base"}{$BaseNewId}{"virtual"})
9810 { # became virtual base
9811 foreach my $Interface (keys(%{$ClassMethods{$Level}{1}{$ClassName}}))
9812 {
Andrey Ponomarenko9927e332012-10-19 10:50:48 +04009813 if(not symbolFilter($Interface, 1, "Affected", $Level)) {
9814 next;
9815 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04009816 %{$CompatProblems{$Level}{$Interface}{"Base_Class_Became_Virtually_Inherited"}{"this->".$BaseName}}=(
9817 "Type_Name"=>$ClassName,
9818 "Type_Type"=>"Class",
9819 "Target"=>$BaseName );
9820 }
9821 }
9822 }
9823 }
9824 # detect size changes in base classes
9825 if($Shift_Old!=$Shift_New)
9826 { # size of allocable class
9827 foreach my $BaseId (@StableBases_Old)
9828 { # search for changed base
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04009829 my %BaseType = get_Type($BaseId, 1);
9830 my $Size_Old = $TypeInfo{1}{$BaseId}{"Size"};
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +04009831 my $Size_New = $TypeInfo{2}{$BaseId_New{$Tr_Old{$BaseType{"Name"}}}}{"Size"};
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04009832 if($Size_Old ne $Size_New
9833 and $Size_Old and $Size_New)
9834 {
9835 my $ProblemType = "";
9836 if(isCopyingClass($BaseId, 1)) {
9837 $ProblemType = "Size_Of_Copying_Class";
9838 }
9839 elsif($AllocableClass{1}{$BaseType{"Name"}})
9840 {
9841 if($Size_New>$Size_Old)
9842 { # increased size
9843 $ProblemType = "Size_Of_Allocable_Class_Increased";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009844 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04009845 else
9846 { # decreased size
9847 $ProblemType = "Size_Of_Allocable_Class_Decreased";
9848 if(not havePubFields(\%Class_Old))
9849 { # affected class has no public members
9850 next;
9851 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009852 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04009853 }
9854 next if(not $ProblemType);
9855 foreach my $Interface (keys(%{$ClassMethods{$Level}{1}{$ClassName}}))
9856 { # base class size changes affecting current class
Andrey Ponomarenko9927e332012-10-19 10:50:48 +04009857 if(not symbolFilter($Interface, 1, "Affected", $Level)) {
9858 next;
9859 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04009860 %{$CompatProblems{$Level}{$Interface}{$ProblemType}{"this->".$BaseType{"Name"}}}=(
9861 "Type_Name"=>$BaseType{"Name"},
9862 "Type_Type"=>"Class",
9863 "Target"=>$BaseType{"Name"},
9864 "Old_Size"=>$Size_Old*$BYTE_SIZE,
9865 "New_Size"=>$Size_New*$BYTE_SIZE );
9866 }
9867 }
9868 }
9869 }
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +04009870 if(defined $VirtualTable_Model{1}{$ClassName}
Andrey Ponomarenko16934472012-03-29 15:37:04 +04009871 and cmpVTables_Real($ClassName, 1)==1
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +04009872 and my @VFunctions = keys(%{$VirtualTable_Model{1}{$ClassName}}))
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04009873 { # compare virtual tables size in base classes
9874 my $VShift_Old = getVShift($ClassId_Old, 1);
9875 my $VShift_New = getVShift($ClassId_New, 2);
9876 if($VShift_Old ne $VShift_New)
9877 { # changes in the base class or changes in the list of base classes
9878 my @AllBases_Old = get_base_classes($ClassId_Old, 1, 1);
9879 my @AllBases_New = get_base_classes($ClassId_New, 2, 1);
9880 ($BNum1, $BNum2) = (1, 1);
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +04009881 my %StableBase = map {$Tr_New{$TypeInfo{2}{$_}{"Name"}} => $_} @AllBases_New;
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04009882 foreach my $BaseId (@AllBases_Old)
9883 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04009884 my %BaseType = get_Type($BaseId, 1);
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +04009885 if(not $StableBase{$Tr_Old{$BaseType{"Name"}}})
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04009886 { # lost base
9887 next;
9888 }
Andrey Ponomarenko16934472012-03-29 15:37:04 +04009889 my $VSize_Old = getVTable_Size($BaseType{"Name"}, 1);
9890 my $VSize_New = getVTable_Size($BaseType{"Name"}, 2);
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04009891 if($VSize_Old!=$VSize_New)
9892 {
Andrey Ponomarenko85043792012-05-14 16:48:07 +04009893 foreach my $Symbol (@VFunctions)
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +04009894 { # TODO: affected non-virtual methods?
9895 if(not defined $VirtualTable_Model{2}{$ClassName}{$Symbol})
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04009896 { # Removed_Virtual_Method, will be registered in mergeVirtualTables()
9897 next;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009898 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +04009899 if($VirtualTable_Model{2}{$ClassName}{$Symbol}-$VirtualTable_Model{1}{$ClassName}{$Symbol}==0)
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04009900 { # skip interfaces that have not changed the absolute virtual position
9901 next;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009902 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +04009903 if(not symbolFilter($Symbol, 1, "Affected", $Level)) {
9904 next;
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04009905 }
Andrey Ponomarenko16934472012-03-29 15:37:04 +04009906 $VTableChanged_M{$BaseType{"Name"}} = 1;
9907 $VTableChanged_M{$ClassName} = 1;
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04009908 foreach my $VirtFunc (keys(%{$AddedInt_Virt{$Level}{$BaseType{"Name"}}}))
9909 { # the reason of the layout change: added virtual functions
9910 next if($VirtualReplacement{$VirtFunc});
9911 my $ProblemType = "Added_Virtual_Method";
9912 if($CompleteSignature{2}{$VirtFunc}{"PureVirt"}) {
9913 $ProblemType = "Added_Pure_Virtual_Method";
9914 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +04009915 %{$CompatProblems{$Level}{$Symbol}{$ProblemType}{get_Signature($VirtFunc, 2)}}=(
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04009916 "Type_Name"=>$BaseType{"Name"},
9917 "Type_Type"=>"Class",
9918 "Target"=>get_Signature($VirtFunc, 2) );
9919 }
9920 foreach my $VirtFunc (keys(%{$RemovedInt_Virt{$Level}{$BaseType{"Name"}}}))
9921 { # the reason of the layout change: removed virtual functions
9922 next if($VirtualReplacement{$VirtFunc});
9923 my $ProblemType = "Removed_Virtual_Method";
9924 if($CompleteSignature{1}{$VirtFunc}{"PureVirt"}) {
9925 $ProblemType = "Removed_Pure_Virtual_Method";
9926 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +04009927 %{$CompatProblems{$Level}{$Symbol}{$ProblemType}{get_Signature($VirtFunc, 1)}}=(
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04009928 "Type_Name"=>$BaseType{"Name"},
9929 "Type_Type"=>"Class",
9930 "Target"=>get_Signature($VirtFunc, 1) );
9931 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009932 }
9933 }
9934 }
9935 }
9936 }
9937 }
9938 }
9939}
9940
9941sub isCreatable($$)
9942{
9943 my ($ClassId, $LibVersion) = @_;
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04009944 if($AllocableClass{$LibVersion}{$TypeInfo{$LibVersion}{$ClassId}{"Name"}}
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009945 or isCopyingClass($ClassId, $LibVersion)) {
9946 return 1;
9947 }
9948 if(keys(%{$Class_SubClasses{$LibVersion}{$ClassId}}))
9949 { # Fix for incomplete data: if this class has
9950 # a base class then it should also has a constructor
9951 return 1;
9952 }
9953 if($ReturnedClass{$LibVersion}{$ClassId})
9954 { # returned by some method of this class
9955 # or any other class
9956 return 1;
9957 }
9958 return 0;
9959}
9960
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04009961sub isUsedClass($$$)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009962{
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04009963 my ($ClassId, $LibVersion, $Level) = @_;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009964 if(keys(%{$ParamClass{$LibVersion}{$ClassId}}))
9965 { # parameter of some exported method
9966 return 1;
9967 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04009968 my $CName = $TypeInfo{$LibVersion}{$ClassId}{"Name"};
9969 if(keys(%{$ClassMethods{$Level}{$LibVersion}{$CName}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009970 { # method from target class
9971 return 1;
9972 }
9973 return 0;
9974}
9975
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04009976sub mergeVirtualTables($$)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009977{ # check for changes in the virtual table
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04009978 my ($Interface, $Level) = @_;
Andrey Ponomarenko16934472012-03-29 15:37:04 +04009979 # affected methods:
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009980 # - virtual
9981 # - pure-virtual
9982 # - non-virtual
9983 if($CompleteSignature{1}{$Interface}{"Data"})
9984 { # global data is not affected
9985 return;
9986 }
9987 my $Class_Id = $CompleteSignature{1}{$Interface}{"Class"};
Andrey Ponomarenko16934472012-03-29 15:37:04 +04009988 if(not $Class_Id) {
9989 return;
9990 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04009991 my $CName = $TypeInfo{1}{$Class_Id}{"Name"};
Andrey Ponomarenko16934472012-03-29 15:37:04 +04009992 if(cmpVTables_Real($CName, 1)==0)
9993 { # no changes
9994 return;
9995 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04009996 $CheckedTypes{$Level}{$CName} = 1;
9997 if($Level eq "Binary")
9998 { # Binary-level
9999 if($CompleteSignature{1}{$Interface}{"PureVirt"}
10000 and not isUsedClass($Class_Id, 1, $Level))
10001 { # pure virtuals should not be affected
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040010002 # if there are no exported methods using this class
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040010003 return;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010004 }
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040010005 }
10006 foreach my $Func (keys(%{$VirtualTable{1}{$CName}}))
10007 {
10008 if(defined $VirtualTable{2}{$CName}{$Func}
10009 and defined $CompleteSignature{2}{$Func})
10010 {
10011 if(not $CompleteSignature{1}{$Func}{"PureVirt"}
10012 and $CompleteSignature{2}{$Func}{"PureVirt"})
10013 { # became pure virtual
10014 %{$CompatProblems{$Level}{$Interface}{"Virtual_Method_Became_Pure"}{$tr_name{$Func}}}=(
10015 "Type_Name"=>$CName,
10016 "Type_Type"=>"Class",
10017 "Target"=>get_Signature_M($Func, 1) );
10018 $VTableChanged_M{$CName} = 1;
10019 }
10020 elsif($CompleteSignature{1}{$Func}{"PureVirt"}
10021 and not $CompleteSignature{2}{$Func}{"PureVirt"})
10022 { # became non-pure virtual
10023 %{$CompatProblems{$Level}{$Interface}{"Virtual_Method_Became_Non_Pure"}{$tr_name{$Func}}}=(
10024 "Type_Name"=>$CName,
10025 "Type_Type"=>"Class",
10026 "Target"=>get_Signature_M($Func, 1) );
10027 $VTableChanged_M{$CName} = 1;
10028 }
10029 }
10030 }
10031 if($Level eq "Binary")
10032 { # Binary-level
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040010033 # check virtual table structure
10034 foreach my $AddedVFunc (keys(%{$AddedInt_Virt{$Level}{$CName}}))
10035 {
10036 next if($Interface eq $AddedVFunc);
10037 next if($VirtualReplacement{$AddedVFunc});
10038 my $VPos_Added = $VirtualTable{2}{$CName}{$AddedVFunc};
10039 if($CompleteSignature{2}{$AddedVFunc}{"PureVirt"})
10040 { # pure virtual methods affect all others (virtual and non-virtual)
10041 %{$CompatProblems{$Level}{$Interface}{"Added_Pure_Virtual_Method"}{$tr_name{$AddedVFunc}}}=(
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010042 "Type_Name"=>$CName,
10043 "Type_Type"=>"Class",
10044 "Target"=>get_Signature($AddedVFunc, 2) );
Andrey Ponomarenko16934472012-03-29 15:37:04 +040010045 $VTableChanged_M{$CName} = 1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010046 }
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040010047 elsif(not defined $VirtualTable{1}{$CName}
10048 or $VPos_Added>keys(%{$VirtualTable{1}{$CName}}))
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040010049 { # added virtual function at the end of v-table
Andrey Ponomarenko16934472012-03-29 15:37:04 +040010050 if(not keys(%{$VirtualTable_Model{1}{$CName}}))
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040010051 { # became polymorphous class, added v-table pointer
10052 %{$CompatProblems{$Level}{$Interface}{"Added_First_Virtual_Method"}{$tr_name{$AddedVFunc}}}=(
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010053 "Type_Name"=>$CName,
10054 "Type_Type"=>"Class",
10055 "Target"=>get_Signature($AddedVFunc, 2) );
Andrey Ponomarenko16934472012-03-29 15:37:04 +040010056 $VTableChanged_M{$CName} = 1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010057 }
10058 else
10059 {
Andrey Ponomarenko16934472012-03-29 15:37:04 +040010060 my $VSize_Old = getVTable_Size($CName, 1);
10061 my $VSize_New = getVTable_Size($CName, 2);
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040010062 next if($VSize_Old==$VSize_New); # exception: register as removed and added virtual method
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040010063 if(isCopyingClass($Class_Id, 1))
10064 { # class has no constructors and v-table will be copied by applications, this may affect all methods
10065 my $ProblemType = "Added_Virtual_Method";
10066 if(isLeafClass($Class_Id, 1)) {
10067 $ProblemType = "Added_Virtual_Method_At_End_Of_Leaf_Copying_Class";
10068 }
10069 %{$CompatProblems{$Level}{$Interface}{$ProblemType}{$tr_name{$AddedVFunc}}}=(
10070 "Type_Name"=>$CName,
10071 "Type_Type"=>"Class",
10072 "Target"=>get_Signature($AddedVFunc, 2) );
Andrey Ponomarenko16934472012-03-29 15:37:04 +040010073 $VTableChanged_M{$CName} = 1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010074 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040010075 else
10076 {
10077 my $ProblemType = "Added_Virtual_Method";
10078 if(isLeafClass($Class_Id, 1)) {
10079 $ProblemType = "Added_Virtual_Method_At_End_Of_Leaf_Allocable_Class";
10080 }
10081 %{$CompatProblems{$Level}{$Interface}{$ProblemType}{$tr_name{$AddedVFunc}}}=(
10082 "Type_Name"=>$CName,
10083 "Type_Type"=>"Class",
10084 "Target"=>get_Signature($AddedVFunc, 2) );
Andrey Ponomarenko16934472012-03-29 15:37:04 +040010085 $VTableChanged_M{$CName} = 1;
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040010086 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010087 }
10088 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040010089 elsif($CompleteSignature{1}{$Interface}{"Virt"}
10090 or $CompleteSignature{1}{$Interface}{"PureVirt"})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010091 {
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040010092 if(defined $VirtualTable{1}{$CName}
10093 and defined $VirtualTable{2}{$CName})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010094 {
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040010095 my $VPos_Old = $VirtualTable{1}{$CName}{$Interface};
10096 my $VPos_New = $VirtualTable{2}{$CName}{$Interface};
10097 if($VPos_Added<=$VPos_Old and $VPos_Old!=$VPos_New)
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040010098 {
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040010099 my @Affected = ($Interface, keys(%{$OverriddenMethods{1}{$Interface}}));
10100 foreach my $ASymbol (@Affected)
10101 {
Andrey Ponomarenko85043792012-05-14 16:48:07 +040010102 if(not $CompleteSignature{1}{$ASymbol}{"PureVirt"})
10103 {
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040010104 if(not symbolFilter($ASymbol, 1, "Affected", $Level)) {
Andrey Ponomarenko85043792012-05-14 16:48:07 +040010105 next;
10106 }
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040010107 }
10108 $CheckedSymbols{$Level}{$ASymbol} = 1;
10109 %{$CompatProblems{$Level}{$ASymbol}{"Added_Virtual_Method"}{$tr_name{$AddedVFunc}}}=(
10110 "Type_Name"=>$CName,
10111 "Type_Type"=>"Class",
10112 "Target"=>get_Signature($AddedVFunc, 2) );
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040010113 $VTableChanged_M{$TypeInfo{1}{$CompleteSignature{1}{$ASymbol}{"Class"}}{"Name"}} = 1;
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040010114 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010115 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010116 }
10117 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040010118 else {
10119 # safe
10120 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010121 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040010122 foreach my $RemovedVFunc (keys(%{$RemovedInt_Virt{$Level}{$CName}}))
10123 {
10124 next if($VirtualReplacement{$RemovedVFunc});
10125 if($RemovedVFunc eq $Interface
10126 and $CompleteSignature{1}{$RemovedVFunc}{"PureVirt"})
10127 { # This case is for removed virtual methods
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040010128 # implemented in both versions of a library
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040010129 next;
10130 }
Andrey Ponomarenko16934472012-03-29 15:37:04 +040010131 if(not keys(%{$VirtualTable_Model{2}{$CName}}))
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040010132 { # became non-polymorphous class, removed v-table pointer
10133 %{$CompatProblems{$Level}{$Interface}{"Removed_Last_Virtual_Method"}{$tr_name{$RemovedVFunc}}}=(
10134 "Type_Name"=>$CName,
10135 "Type_Type"=>"Class",
10136 "Target"=>get_Signature($RemovedVFunc, 1) );
Andrey Ponomarenko16934472012-03-29 15:37:04 +040010137 $VTableChanged_M{$CName} = 1;
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040010138 }
10139 elsif($CompleteSignature{1}{$Interface}{"Virt"}
10140 or $CompleteSignature{1}{$Interface}{"PureVirt"})
10141 {
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040010142 if(defined $VirtualTable{1}{$CName} and defined $VirtualTable{2}{$CName})
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040010143 {
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040010144 if(not defined $VirtualTable{1}{$CName}{$Interface}) {
10145 next;
10146 }
10147 my $VPos_New = -1;
10148 if(defined $VirtualTable{2}{$CName}{$Interface})
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040010149 {
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040010150 $VPos_New = $VirtualTable{2}{$CName}{$Interface};
10151 }
10152 else
10153 {
10154 if($Interface ne $RemovedVFunc) {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040010155 next;
10156 }
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040010157 }
10158 my $VPos_Removed = $VirtualTable{1}{$CName}{$RemovedVFunc};
10159 my $VPos_Old = $VirtualTable{1}{$CName}{$Interface};
10160 if($VPos_Removed<=$VPos_Old and $VPos_Old!=$VPos_New)
10161 {
10162 my @Affected = ($Interface, keys(%{$OverriddenMethods{1}{$Interface}}));
10163 foreach my $ASymbol (@Affected)
10164 {
Andrey Ponomarenko85043792012-05-14 16:48:07 +040010165 if(not $CompleteSignature{1}{$ASymbol}{"PureVirt"})
10166 {
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040010167 if(not symbolFilter($ASymbol, 1, "Affected", $Level)) {
Andrey Ponomarenko85043792012-05-14 16:48:07 +040010168 next;
10169 }
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040010170 }
10171 my $ProblemType = "Removed_Virtual_Method";
10172 if($CompleteSignature{1}{$RemovedVFunc}{"PureVirt"}) {
10173 $ProblemType = "Removed_Pure_Virtual_Method";
10174 }
10175 $CheckedSymbols{$Level}{$ASymbol} = 1;
10176 %{$CompatProblems{$Level}{$ASymbol}{$ProblemType}{$tr_name{$RemovedVFunc}}}=(
10177 "Type_Name"=>$CName,
10178 "Type_Type"=>"Class",
10179 "Target"=>get_Signature($RemovedVFunc, 1) );
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040010180 $VTableChanged_M{$TypeInfo{1}{$CompleteSignature{1}{$ASymbol}{"Class"}}{"Name"}} = 1;
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040010181 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040010182 }
10183 }
10184 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010185 }
10186 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040010187 else
10188 { # Source-level
10189 foreach my $AddedVFunc (keys(%{$AddedInt_Virt{$Level}{$CName}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010190 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040010191 next if($Interface eq $AddedVFunc);
10192 if($CompleteSignature{2}{$AddedVFunc}{"PureVirt"})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010193 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040010194 %{$CompatProblems{$Level}{$Interface}{"Added_Pure_Virtual_Method"}{$tr_name{$AddedVFunc}}}=(
10195 "Type_Name"=>$CName,
10196 "Type_Type"=>"Class",
10197 "Target"=>get_Signature($AddedVFunc, 2) );
10198 }
10199 }
10200 foreach my $RemovedVFunc (keys(%{$RemovedInt_Virt{$Level}{$CName}}))
10201 {
10202 if($CompleteSignature{1}{$RemovedVFunc}{"PureVirt"})
10203 {
10204 %{$CompatProblems{$Level}{$Interface}{"Removed_Pure_Virtual_Method"}{$tr_name{$RemovedVFunc}}}=(
10205 "Type_Name"=>$CName,
10206 "Type_Type"=>"Class",
10207 "Target"=>get_Signature($RemovedVFunc, 1) );
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010208 }
10209 }
10210 }
10211}
10212
10213sub find_MemberPair_Pos_byName($$)
10214{
10215 my ($Member_Name, $Pair_Type) = @_;
10216 $Member_Name=~s/\A[_]+|[_]+\Z//g;
10217 foreach my $MemberPair_Pos (sort {int($a)<=>int($b)} keys(%{$Pair_Type->{"Memb"}}))
10218 {
10219 if(defined $Pair_Type->{"Memb"}{$MemberPair_Pos})
10220 {
10221 my $Name = $Pair_Type->{"Memb"}{$MemberPair_Pos}{"name"};
10222 $Name=~s/\A[_]+|[_]+\Z//g;
10223 if($Name eq $Member_Name) {
10224 return $MemberPair_Pos;
10225 }
10226 }
10227 }
10228 return "lost";
10229}
10230
10231sub find_MemberPair_Pos_byVal($$)
10232{
10233 my ($Member_Value, $Pair_Type) = @_;
10234 foreach my $MemberPair_Pos (sort {int($a)<=>int($b)} keys(%{$Pair_Type->{"Memb"}}))
10235 {
10236 if(defined $Pair_Type->{"Memb"}{$MemberPair_Pos}
10237 and $Pair_Type->{"Memb"}{$MemberPair_Pos}{"value"} eq $Member_Value) {
10238 return $MemberPair_Pos;
10239 }
10240 }
10241 return "lost";
10242}
10243
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040010244my %Severity_Val=(
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010245 "High"=>3,
10246 "Medium"=>2,
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040010247 "Low"=>1,
10248 "Safe"=>-1
10249);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010250
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040010251sub maxSeverity($$)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010252{
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040010253 my ($S1, $S2) = @_;
10254 if(cmpSeverities($S1, $S2)) {
10255 return $S1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010256 }
10257 else {
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040010258 return $S2;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010259 }
10260}
10261
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040010262sub cmpSeverities($$)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010263{
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040010264 my ($S1, $S2) = @_;
10265 if(not $S1) {
10266 return 0;
10267 }
10268 elsif(not $S2) {
10269 return 1;
10270 }
10271 return ($Severity_Val{$S1}>$Severity_Val{$S2});
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010272}
10273
10274sub getProblemSeverity($$)
10275{
10276 my ($Level, $Kind) = @_;
10277 return $CompatRules{$Level}{$Kind}{"Severity"};
10278}
10279
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040010280sub isRecurType($$)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010281{
10282 foreach (@RecurTypes)
10283 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040010284 if( $_->{"T1"} eq $_[0]
10285 and $_->{"T2"} eq $_[1] )
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010286 {
10287 return 1;
10288 }
10289 }
10290 return 0;
10291}
10292
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040010293sub pushType($$)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010294{
10295 my %TypeIDs=(
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040010296 "T1" => $_[0], #Tid1
10297 "T2" => $_[1] #Tid2
Andrey Ponomarenko16934472012-03-29 15:37:04 +040010298 );
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010299 push(@RecurTypes, \%TypeIDs);
10300}
10301
10302sub isRenamed($$$$$)
10303{
10304 my ($MemPos, $Type1, $LVersion1, $Type2, $LVersion2) = @_;
10305 my $Member_Name = $Type1->{"Memb"}{$MemPos}{"name"};
10306 my $MemberType_Id = $Type1->{"Memb"}{$MemPos}{"type"};
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +040010307 my %MemberType_Pure = get_PureType($MemberType_Id, $TypeInfo{$LVersion1});
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010308 if(not defined $Type2->{"Memb"}{$MemPos}) {
10309 return "";
10310 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040010311 my $PairType_Id = $Type2->{"Memb"}{$MemPos}{"type"};
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +040010312 my %PairType_Pure = get_PureType($PairType_Id, $TypeInfo{$LVersion2});
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010313
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040010314 my $Pair_Name = $Type2->{"Memb"}{$MemPos}{"name"};
10315 my $MemberPair_Pos_Rev = ($Member_Name eq $Pair_Name)?$MemPos:find_MemberPair_Pos_byName($Pair_Name, $Type1);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010316 if($MemberPair_Pos_Rev eq "lost")
10317 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040010318 if($MemberType_Pure{"Name"} eq $PairType_Pure{"Name"})
10319 { # base type match
10320 return $Pair_Name;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010321 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040010322 if($TypeInfo{$LVersion1}{$MemberType_Id}{"Name"} eq $TypeInfo{$LVersion2}{$PairType_Id}{"Name"})
10323 { # exact type match
10324 return $Pair_Name;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010325 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040010326 if($MemberType_Pure{"Size"} eq $PairType_Pure{"Size"})
10327 { # size match
10328 return $Pair_Name;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010329 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040010330 if(isReserved($Pair_Name))
10331 { # reserved fields
10332 return $Pair_Name;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010333 }
10334 }
10335 return "";
10336}
10337
10338sub isLastElem($$)
10339{
10340 my ($Pos, $TypeRef) = @_;
10341 my $Name = $TypeRef->{"Memb"}{$Pos}{"name"};
10342 if($Name=~/last|count|max|total/i)
10343 { # GST_LEVEL_COUNT, GST_RTSP_ELAST
10344 return 1;
10345 }
10346 elsif($Name=~/END|NLIMITS\Z/)
10347 { # __RLIMIT_NLIMITS
10348 return 1;
10349 }
10350 elsif($Name=~/\AN[A-Z](.+)[a-z]+s\Z/
10351 and $Pos+1==keys(%{$TypeRef->{"Memb"}}))
10352 { # NImageFormats, NColorRoles
10353 return 1;
10354 }
10355 return 0;
10356}
10357
10358sub nonComparable($$)
10359{
10360 my ($T1, $T2) = @_;
10361 if($T1->{"Name"} ne $T2->{"Name"}
10362 and not isAnon($T1->{"Name"})
10363 and not isAnon($T2->{"Name"}))
10364 { # different names
10365 if($T1->{"Type"} ne "Pointer"
10366 or $T2->{"Type"} ne "Pointer")
10367 { # compare base types
10368 return 1;
10369 }
10370 if($T1->{"Name"}!~/\Avoid\s*\*/
10371 and $T2->{"Name"}=~/\Avoid\s*\*/)
10372 {
10373 return 1;
10374 }
10375 }
10376 elsif($T1->{"Type"} ne $T2->{"Type"})
10377 { # different types
10378 if($T1->{"Type"} eq "Class"
10379 and $T2->{"Type"} eq "Struct")
10380 { # "class" to "struct"
10381 return 0;
10382 }
10383 elsif($T2->{"Type"} eq "Class"
10384 and $T1->{"Type"} eq "Struct")
10385 { # "struct" to "class"
10386 return 0;
10387 }
10388 else
10389 { # "class" to "enum"
10390 # "union" to "class"
10391 # ...
10392 return 1;
10393 }
10394 }
10395 return 0;
10396}
10397
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040010398sub mergeTypes($$$)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010399{
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040010400 my ($Type1_Id, $Type2_Id, $Level) = @_;
10401 return () if(not $Type1_Id or not $Type2_Id);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010402 my (%Sub_SubProblems, %SubProblems) = ();
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040010403 if($Cache{"mergeTypes"}{$Level}{$Type1_Id}{$Type2_Id})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010404 { # already merged
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040010405 return %{$Cache{"mergeTypes"}{$Level}{$Type1_Id}{$Type2_Id}};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010406 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040010407 my %Type1 = get_Type($Type1_Id, 1);
10408 my %Type2 = get_Type($Type2_Id, 2);
Andrey Ponomarenko16934472012-03-29 15:37:04 +040010409 if(not $Type1{"Name"} or not $Type2{"Name"}) {
10410 return ();
10411 }
10412 $CheckedTypes{$Level}{$Type1{"Name"}}=1;
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +040010413 my %Type1_Pure = get_PureType($Type1_Id, $TypeInfo{1});
10414 my %Type2_Pure = get_PureType($Type2_Id, $TypeInfo{2});
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040010415 $CheckedTypes{$Level}{$Type1_Pure{"Name"}}=1;
Andrey Ponomarenko85043792012-05-14 16:48:07 +040010416 if(not $Type1_Pure{"Size"} or not $Type2_Pure{"Size"})
10417 { # including a case when "class Class { ... };" changed to "class Class;"
10418 return ();
10419 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040010420 if(isRecurType($Type1_Pure{"Tid"}, $Type2_Pure{"Tid"}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010421 { # skip recursive declarations
10422 return ();
10423 }
10424 return () if(not $Type1_Pure{"Name"} or not $Type2_Pure{"Name"});
10425 return () if($SkipTypes{1}{$Type1_Pure{"Name"}});
10426 return () if($SkipTypes{1}{$Type1{"Name"}});
10427
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040010428 my %Typedef_1 = goToFirst($Type1{"Tid"}, 1, "Typedef");
10429 my %Typedef_2 = goToFirst($Type2{"Tid"}, 2, "Typedef");
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040010430 if(not $UseOldDumps and %Typedef_1 and %Typedef_2
10431 and $Typedef_1{"Type"} eq "Typedef" and $Typedef_2{"Type"} eq "Typedef"
10432 and $Typedef_1{"Name"} eq $Typedef_2{"Name"})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010433 {
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +040010434 my %Base_1 = get_OneStep_BaseType($Typedef_1{"Tid"}, $TypeInfo{1});
10435 my %Base_2 = get_OneStep_BaseType($Typedef_2{"Tid"}, $TypeInfo{2});
Andrey Ponomarenko85043792012-05-14 16:48:07 +040010436 if($Base_1{"Name"} ne $Base_2{"Name"})
10437 {
10438 if(differentDumps("G")
10439 or differentDumps("V"))
10440 { # different GCC versions or different dumps
10441 $Base_1{"Name"} = uncover_typedefs($Base_1{"Name"}, 1);
10442 $Base_2{"Name"} = uncover_typedefs($Base_2{"Name"}, 2);
10443 # std::__va_list and __va_list
10444 $Base_1{"Name"}=~s/\A(\w+::)+//;
10445 $Base_2{"Name"}=~s/\A(\w+::)+//;
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040010446 $Base_1{"Name"} = formatName($Base_1{"Name"}, "T");
10447 $Base_2{"Name"} = formatName($Base_2{"Name"}, "T");
Andrey Ponomarenko85043792012-05-14 16:48:07 +040010448 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010449 }
10450 if($Base_1{"Name"}!~/anon\-/ and $Base_2{"Name"}!~/anon\-/
10451 and $Base_1{"Name"} ne $Base_2{"Name"})
10452 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040010453 if($Level eq "Binary"
10454 and $Type1{"Size"} ne $Type2{"Size"})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010455 {
10456 %{$SubProblems{"DataType_Size"}{$Typedef_1{"Name"}}}=(
10457 "Target"=>$Typedef_1{"Name"},
10458 "Type_Name"=>$Typedef_1{"Name"},
10459 "Type_Type"=>"Typedef",
10460 "Old_Size"=>$Type1{"Size"}*$BYTE_SIZE,
10461 "New_Size"=>$Type2{"Size"}*$BYTE_SIZE );
10462 }
10463 %{$SubProblems{"Typedef_BaseType"}{$Typedef_1{"Name"}}}=(
10464 "Target"=>$Typedef_1{"Name"},
10465 "Type_Name"=>$Typedef_1{"Name"},
10466 "Type_Type"=>"Typedef",
10467 "Old_Value"=>$Base_1{"Name"},
10468 "New_Value"=>$Base_2{"Name"} );
10469 }
10470 }
10471 if(nonComparable(\%Type1_Pure, \%Type2_Pure))
10472 { # different types (reported in detectTypeChange(...))
10473 if($Type1_Pure{"Name"} eq $Type2_Pure{"Name"}
10474 and $Type1_Pure{"Type"} ne $Type2_Pure{"Type"}
10475 and $Type1_Pure{"Type"}!~/Intrinsic|Pointer|Ref|Typedef/)
10476 { # different type of the type
10477 %{$SubProblems{"DataType_Type"}{$Type1_Pure{"Name"}}}=(
10478 "Target"=>$Type1_Pure{"Name"},
10479 "Type_Name"=>$Type1_Pure{"Name"},
10480 "Type_Type"=>$Type1_Pure{"Type"},
10481 "Old_Value"=>lc($Type1_Pure{"Type"}),
10482 "New_Value"=>lc($Type2_Pure{"Type"}) );
10483 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040010484 %{$Cache{"mergeTypes"}{$Level}{$Type1_Id}{$Type2_Id}} = %SubProblems;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010485 return %SubProblems;
10486 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040010487 pushType($Type1_Pure{"Tid"}, $Type2_Pure{"Tid"});
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010488 if(($Type1_Pure{"Name"} eq $Type2_Pure{"Name"}
10489 or (isAnon($Type1_Pure{"Name"}) and isAnon($Type2_Pure{"Name"})))
10490 and $Type1_Pure{"Type"}=~/\A(Struct|Class|Union)\Z/)
10491 { # checking size
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040010492 if($Level eq "Binary"
10493 and $Type1_Pure{"Size"} ne $Type2_Pure{"Size"})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010494 {
10495 my $ProblemKind = "DataType_Size";
10496 if($Type1_Pure{"Type"} eq "Class"
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040010497 and keys(%{$ClassMethods{$Level}{1}{$Type1_Pure{"Name"}}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010498 {
10499 if(isCopyingClass($Type1_Pure{"Tid"}, 1)) {
10500 $ProblemKind = "Size_Of_Copying_Class";
10501 }
10502 elsif($AllocableClass{1}{$Type1_Pure{"Name"}})
10503 {
10504 if(int($Type2_Pure{"Size"})>int($Type1_Pure{"Size"})) {
10505 $ProblemKind = "Size_Of_Allocable_Class_Increased";
10506 }
10507 else {
10508 # descreased size of allocable class
10509 # it has no special effects
10510 }
10511 }
10512 }
10513 %{$SubProblems{$ProblemKind}{$Type1_Pure{"Name"}}}=(
10514 "Target"=>$Type1_Pure{"Name"},
10515 "Type_Name"=>$Type1_Pure{"Name"},
10516 "Type_Type"=>$Type1_Pure{"Type"},
10517 "Old_Size"=>$Type1_Pure{"Size"}*$BYTE_SIZE,
10518 "New_Size"=>$Type2_Pure{"Size"}*$BYTE_SIZE,
10519 "InitialType_Type"=>$Type1_Pure{"Type"} );
10520 }
10521 }
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040010522 if(defined $Type1_Pure{"BaseType"} and $Type1_Pure{"BaseType"}{"Tid"}
10523 and defined $Type2_Pure{"BaseType"} and $Type2_Pure{"BaseType"}{"Tid"})
10524 { # checking base types
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040010525 %Sub_SubProblems = mergeTypes($Type1_Pure{"BaseType"}{"Tid"}, $Type2_Pure{"BaseType"}{"Tid"}, $Level);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010526 foreach my $Sub_SubProblemType (keys(%Sub_SubProblems))
10527 {
10528 foreach my $Sub_SubLocation (keys(%{$Sub_SubProblems{$Sub_SubProblemType}}))
10529 {
10530 foreach my $Attr (keys(%{$Sub_SubProblems{$Sub_SubProblemType}{$Sub_SubLocation}})) {
10531 $SubProblems{$Sub_SubProblemType}{$Sub_SubLocation}{$Attr} = $Sub_SubProblems{$Sub_SubProblemType}{$Sub_SubLocation}{$Attr};
10532 }
10533 $SubProblems{$Sub_SubProblemType}{$Sub_SubLocation}{"InitialType_Type"} = $Type1_Pure{"Type"};
10534 }
10535 }
10536 }
10537 my (%AddedField, %RemovedField, %RenamedField, %RenamedField_Rev, %RelatedField, %RelatedField_Rev) = ();
10538 my %NameToPosA = map {$Type1_Pure{"Memb"}{$_}{"name"}=>$_} keys(%{$Type1_Pure{"Memb"}});
10539 my %NameToPosB = map {$Type2_Pure{"Memb"}{$_}{"name"}=>$_} keys(%{$Type2_Pure{"Memb"}});
10540 foreach my $Member_Pos (sort {int($a) <=> int($b)} keys(%{$Type1_Pure{"Memb"}}))
10541 { # detect removed and renamed fields
10542 my $Member_Name = $Type1_Pure{"Memb"}{$Member_Pos}{"name"};
10543 next if(not $Member_Name);
10544 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);
10545 if($MemberPair_Pos eq "lost")
10546 {
10547 if($Type2_Pure{"Type"}=~/\A(Struct|Class|Union)\Z/)
10548 {
10549 if(isUnnamed($Member_Name))
10550 { # support for old-version dumps
10551 # unnamed fields have been introduced in the ACC 1.23 (dump 2.1 format)
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040010552 if(not checkDump(2, "2.1")) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010553 next;
10554 }
10555 }
10556 if(my $RenamedTo = isRenamed($Member_Pos, \%Type1_Pure, 1, \%Type2_Pure, 2))
10557 { # renamed
10558 $RenamedField{$Member_Pos}=$RenamedTo;
10559 $RenamedField_Rev{$NameToPosB{$RenamedTo}}=$Member_Name;
10560 }
10561 else
10562 { # removed
10563 $RemovedField{$Member_Pos}=1;
10564 }
10565 }
10566 elsif($Type1_Pure{"Type"} eq "Enum")
10567 {
10568 my $Member_Value1 = $Type1_Pure{"Memb"}{$Member_Pos}{"value"};
10569 next if($Member_Value1 eq "");
10570 $MemberPair_Pos = find_MemberPair_Pos_byVal($Member_Value1, \%Type2_Pure);
10571 if($MemberPair_Pos ne "lost")
10572 { # renamed
10573 my $RenamedTo = $Type2_Pure{"Memb"}{$MemberPair_Pos}{"name"};
10574 my $MemberPair_Pos_Rev = find_MemberPair_Pos_byName($RenamedTo, \%Type1_Pure);
10575 if($MemberPair_Pos_Rev eq "lost")
10576 {
10577 $RenamedField{$Member_Pos}=$RenamedTo;
10578 $RenamedField_Rev{$NameToPosB{$RenamedTo}}=$Member_Name;
10579 }
10580 else {
10581 $RemovedField{$Member_Pos}=1;
10582 }
10583 }
10584 else
10585 { # removed
10586 $RemovedField{$Member_Pos}=1;
10587 }
10588 }
10589 }
10590 else
10591 { # related
10592 $RelatedField{$Member_Pos} = $MemberPair_Pos;
10593 $RelatedField_Rev{$MemberPair_Pos} = $Member_Pos;
10594 }
10595 }
10596 foreach my $Member_Pos (sort {int($a) <=> int($b)} keys(%{$Type2_Pure{"Memb"}}))
10597 { # detect added fields
10598 my $Member_Name = $Type2_Pure{"Memb"}{$Member_Pos}{"name"};
10599 next if(not $Member_Name);
10600 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);
10601 if($MemberPair_Pos eq "lost")
10602 {
10603 if(isUnnamed($Member_Name))
10604 { # support for old-version dumps
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040010605 # unnamed fields have been introduced in the ACC 1.23 (dump 2.1 format)
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040010606 if(not checkDump(1, "2.1")) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010607 next;
10608 }
10609 }
10610 if($Type2_Pure{"Type"}=~/\A(Struct|Class|Union|Enum)\Z/)
10611 {
10612 if(not $RenamedField_Rev{$Member_Pos})
10613 { # added
10614 $AddedField{$Member_Pos}=1;
10615 }
10616 }
10617 }
10618 }
10619 if($Type2_Pure{"Type"}=~/\A(Struct|Class)\Z/)
10620 { # detect moved fields
10621 my (%RelPos, %RelPosName, %AbsPos) = ();
10622 my $Pos = 0;
10623 foreach my $Member_Pos (sort {int($a) <=> int($b)} keys(%{$Type1_Pure{"Memb"}}))
10624 { # relative positions in 1st version
10625 my $Member_Name = $Type1_Pure{"Memb"}{$Member_Pos}{"name"};
10626 next if(not $Member_Name);
10627 if(not $RemovedField{$Member_Pos})
10628 { # old type without removed fields
10629 $RelPos{1}{$Member_Name}=$Pos;
10630 $RelPosName{1}{$Pos} = $Member_Name;
10631 $AbsPos{1}{$Pos++} = $Member_Pos;
10632 }
10633 }
10634 $Pos = 0;
10635 foreach my $Member_Pos (sort {int($a) <=> int($b)} keys(%{$Type2_Pure{"Memb"}}))
10636 { # relative positions in 2nd version
10637 my $Member_Name = $Type2_Pure{"Memb"}{$Member_Pos}{"name"};
10638 next if(not $Member_Name);
10639 if(not $AddedField{$Member_Pos})
10640 { # new type without added fields
10641 $RelPos{2}{$Member_Name}=$Pos;
10642 $RelPosName{2}{$Pos} = $Member_Name;
10643 $AbsPos{2}{$Pos++} = $Member_Pos;
10644 }
10645 }
10646 foreach my $Member_Name (keys(%{$RelPos{1}}))
10647 {
10648 my $RPos1 = $RelPos{1}{$Member_Name};
10649 my $AbsPos1 = $NameToPosA{$Member_Name};
10650 my $Member_Name2 = $Member_Name;
10651 if(my $RenamedTo = $RenamedField{$AbsPos1})
10652 { # renamed
10653 $Member_Name2 = $RenamedTo;
10654 }
10655 my $RPos2 = $RelPos{2}{$Member_Name2};
10656 if($RPos2 ne "" and $RPos1 ne $RPos2)
10657 { # different relative positions
10658 my $AbsPos2 = $NameToPosB{$Member_Name2};
10659 if($AbsPos1 ne $AbsPos2)
10660 { # different absolute positions
10661 my $ProblemType = "Moved_Field";
10662 if(not isPublic(\%Type1_Pure, $AbsPos1))
10663 { # may change layout and size of type
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040010664 if($Level eq "Source") {
10665 next;
10666 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010667 $ProblemType = "Moved_Private_Field";
10668 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040010669 if($Level eq "Binary"
10670 and $Type1_Pure{"Size"} ne $Type2_Pure{"Size"})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010671 { # affected size
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040010672 my $MemSize1 = $TypeInfo{1}{$Type1_Pure{"Memb"}{$AbsPos1}{"type"}}{"Size"};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010673 my $MovedAbsPos = $AbsPos{1}{$RPos2};
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040010674 my $MemSize2 = $TypeInfo{1}{$Type1_Pure{"Memb"}{$MovedAbsPos}{"type"}}{"Size"};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010675 if($MemSize1 ne $MemSize2) {
10676 $ProblemType .= "_And_Size";
10677 }
10678 }
10679 if($ProblemType eq "Moved_Private_Field") {
10680 next;
10681 }
10682 %{$SubProblems{$ProblemType}{$Member_Name}}=(
10683 "Target"=>$Member_Name,
10684 "Type_Name"=>$Type1_Pure{"Name"},
10685 "Type_Type"=>$Type1_Pure{"Type"},
10686 "Old_Value"=>$RPos1,
10687 "New_Value"=>$RPos2 );
10688 }
10689 }
10690 }
10691 }
10692 foreach my $Member_Pos (sort {int($a) <=> int($b)} keys(%{$Type1_Pure{"Memb"}}))
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040010693 { # check older fields, public and private
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010694 my $Member_Name = $Type1_Pure{"Memb"}{$Member_Pos}{"name"};
10695 next if(not $Member_Name);
10696 if(my $RenamedTo = $RenamedField{$Member_Pos})
10697 { # renamed
10698 if($Type2_Pure{"Type"}=~/\A(Struct|Class|Union)\Z/)
10699 {
10700 if(isPublic(\%Type1_Pure, $Member_Pos))
10701 {
10702 %{$SubProblems{"Renamed_Field"}{$Member_Name}}=(
10703 "Target"=>$Member_Name,
10704 "Type_Name"=>$Type1_Pure{"Name"},
10705 "Type_Type"=>$Type1_Pure{"Type"},
10706 "Old_Value"=>$Member_Name,
10707 "New_Value"=>$RenamedTo );
10708 }
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040010709 elsif(isReserved($Member_Name))
10710 {
10711 %{$SubProblems{"Used_Reserved_Field"}{$Member_Name}}=(
10712 "Target"=>$Member_Name,
10713 "Type_Name"=>$Type1_Pure{"Name"},
10714 "Type_Type"=>$Type1_Pure{"Type"},
10715 "Old_Value"=>$Member_Name,
10716 "New_Value"=>$RenamedTo );
10717 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010718 }
10719 elsif($Type1_Pure{"Type"} eq "Enum")
10720 {
10721 %{$SubProblems{"Enum_Member_Name"}{$Type1_Pure{"Memb"}{$Member_Pos}{"value"}}}=(
10722 "Target"=>$Type1_Pure{"Memb"}{$Member_Pos}{"value"},
10723 "Type_Name"=>$Type1_Pure{"Name"},
10724 "Type_Type"=>$Type1_Pure{"Type"},
10725 "Old_Value"=>$Member_Name,
10726 "New_Value"=>$RenamedTo );
10727 }
10728 }
10729 elsif($RemovedField{$Member_Pos})
10730 { # removed
10731 if($Type2_Pure{"Type"}=~/\A(Struct|Class)\Z/)
10732 {
10733 my $ProblemType = "Removed_Field";
10734 if(not isPublic(\%Type1_Pure, $Member_Pos)
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040010735 or isUnnamed($Member_Name))
10736 {
10737 if($Level eq "Source") {
10738 next;
10739 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010740 $ProblemType = "Removed_Private_Field";
10741 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040010742 if($Level eq "Binary"
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +040010743 and not isMemPadded($Member_Pos, -1, \%Type1_Pure, \%RemovedField, $TypeInfo{1}, $WORD_SIZE{1}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010744 {
10745 if(my $MNum = isAccessible(\%Type1_Pure, \%RemovedField, $Member_Pos+1, -1))
10746 { # affected fields
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +040010747 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 +040010748 { # changed offset
10749 $ProblemType .= "_And_Layout";
10750 }
10751 }
10752 if($Type1_Pure{"Size"} ne $Type2_Pure{"Size"})
10753 { # affected size
10754 $ProblemType .= "_And_Size";
10755 }
10756 }
10757 if($ProblemType eq "Removed_Private_Field") {
10758 next;
10759 }
10760 %{$SubProblems{$ProblemType}{$Member_Name}}=(
10761 "Target"=>$Member_Name,
10762 "Type_Name"=>$Type1_Pure{"Name"},
10763 "Type_Type"=>$Type1_Pure{"Type"} );
10764 }
10765 elsif($Type2_Pure{"Type"} eq "Union")
10766 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040010767 if($Level eq "Binary"
10768 and $Type1_Pure{"Size"} ne $Type2_Pure{"Size"})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010769 {
10770 %{$SubProblems{"Removed_Union_Field_And_Size"}{$Member_Name}}=(
10771 "Target"=>$Member_Name,
10772 "Type_Name"=>$Type1_Pure{"Name"},
10773 "Type_Type"=>$Type1_Pure{"Type"} );
10774 }
10775 else
10776 {
10777 %{$SubProblems{"Removed_Union_Field"}{$Member_Name}}=(
10778 "Target"=>$Member_Name,
10779 "Type_Name"=>$Type1_Pure{"Name"},
10780 "Type_Type"=>$Type1_Pure{"Type"} );
10781 }
10782 }
10783 elsif($Type1_Pure{"Type"} eq "Enum")
10784 {
10785 %{$SubProblems{"Enum_Member_Removed"}{$Member_Name}}=(
10786 "Target"=>$Member_Name,
10787 "Type_Name"=>$Type1_Pure{"Name"},
10788 "Type_Type"=>$Type1_Pure{"Type"},
10789 "Old_Value"=>$Member_Name );
10790 }
10791 }
10792 else
10793 { # changed
10794 my $MemberPair_Pos = $RelatedField{$Member_Pos};
10795 if($Type1_Pure{"Type"} eq "Enum")
10796 {
10797 my $Member_Value1 = $Type1_Pure{"Memb"}{$Member_Pos}{"value"};
10798 next if($Member_Value1 eq "");
10799 my $Member_Value2 = $Type2_Pure{"Memb"}{$MemberPair_Pos}{"value"};
10800 next if($Member_Value2 eq "");
10801 if($Member_Value1 ne $Member_Value2)
10802 {
10803 my $ProblemType = "Enum_Member_Value";
10804 if(isLastElem($Member_Pos, \%Type1_Pure)) {
10805 $ProblemType = "Enum_Last_Member_Value";
10806 }
10807 %{$SubProblems{$ProblemType}{$Member_Name}}=(
10808 "Target"=>$Member_Name,
10809 "Type_Name"=>$Type1_Pure{"Name"},
10810 "Type_Type"=>$Type1_Pure{"Type"},
10811 "Old_Value"=>$Member_Value1,
10812 "New_Value"=>$Member_Value2 );
10813 }
10814 }
10815 elsif($Type2_Pure{"Type"}=~/\A(Struct|Class|Union)\Z/)
10816 {
10817 my $MemberType1_Id = $Type1_Pure{"Memb"}{$Member_Pos}{"type"};
10818 my $MemberType2_Id = $Type2_Pure{"Memb"}{$MemberPair_Pos}{"type"};
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040010819 my $SizeV1 = $TypeInfo{1}{$MemberType1_Id}{"Size"}*$BYTE_SIZE;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010820 if(my $BSize1 = $Type1_Pure{"Memb"}{$Member_Pos}{"bitfield"}) {
10821 $SizeV1 = $BSize1;
10822 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040010823 my $SizeV2 = $TypeInfo{2}{$MemberType2_Id}{"Size"}*$BYTE_SIZE;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010824 if(my $BSize2 = $Type2_Pure{"Memb"}{$MemberPair_Pos}{"bitfield"}) {
10825 $SizeV2 = $BSize2;
10826 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040010827 my $MemberType1_Name = $TypeInfo{1}{$MemberType1_Id}{"Name"};
10828 my $MemberType2_Name = $TypeInfo{2}{$MemberType2_Id}{"Name"};
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040010829 if($Level eq "Binary"
10830 and $SizeV1 ne $SizeV2)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010831 {
10832 if($MemberType1_Name eq $MemberType2_Name or (isAnon($MemberType1_Name) and isAnon($MemberType2_Name))
10833 or ($Type1_Pure{"Memb"}{$Member_Pos}{"bitfield"} and $Type2_Pure{"Memb"}{$MemberPair_Pos}{"bitfield"}))
10834 { # field size change (including anon-structures and unions)
10835 # - same types
10836 # - unnamed types
10837 # - bitfields
10838 my $ProblemType = "Field_Size";
10839 if(not isPublic(\%Type1_Pure, $Member_Pos)
10840 or isUnnamed($Member_Name))
10841 { # should not be accessed by applications, goes to "Low Severity"
10842 # example: "abidata" members in GStreamer types
10843 $ProblemType = "Private_".$ProblemType;
10844 }
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +040010845 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 +040010846 { # check an effect
10847 if(my $MNum = isAccessible(\%Type1_Pure, \%RemovedField, $Member_Pos+1, -1))
10848 { # public fields after the current
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +040010849 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 +040010850 { # changed offset
10851 $ProblemType .= "_And_Layout";
10852 }
10853 }
10854 if($Type1_Pure{"Size"} ne $Type2_Pure{"Size"}) {
10855 $ProblemType .= "_And_Type_Size";
10856 }
10857 }
10858 if($ProblemType eq "Private_Field_Size")
10859 { # private field size with no effect
10860 $ProblemType = "";
10861 }
10862 if($ProblemType)
10863 { # register a problem
10864 %{$SubProblems{$ProblemType}{$Member_Name}}=(
10865 "Target"=>$Member_Name,
10866 "Type_Name"=>$Type1_Pure{"Name"},
10867 "Type_Type"=>$Type1_Pure{"Type"},
10868 "Old_Size"=>$SizeV1,
10869 "New_Size"=>$SizeV2);
10870 }
10871 }
10872 }
10873 if($Type1_Pure{"Memb"}{$Member_Pos}{"bitfield"}
10874 or $Type2_Pure{"Memb"}{$MemberPair_Pos}{"bitfield"})
10875 { # do NOT check bitfield type changes
10876 next;
10877 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040010878 if(checkDump(1, "2.13") and checkDump(2, "2.13"))
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040010879 {
10880 if(not $Type1_Pure{"Memb"}{$Member_Pos}{"mutable"}
10881 and $Type2_Pure{"Memb"}{$MemberPair_Pos}{"mutable"})
10882 {
10883 %{$SubProblems{"Field_Became_Mutable"}{$Member_Name}}=(
10884 "Target"=>$Member_Name,
10885 "Type_Name"=>$Type1_Pure{"Name"},
10886 "Type_Type"=>$Type1_Pure{"Type"});
10887 }
10888 elsif($Type1_Pure{"Memb"}{$Member_Pos}{"mutable"}
10889 and not $Type2_Pure{"Memb"}{$MemberPair_Pos}{"mutable"})
10890 {
10891 %{$SubProblems{"Field_Became_NonMutable"}{$Member_Name}}=(
10892 "Target"=>$Member_Name,
10893 "Type_Name"=>$Type1_Pure{"Name"},
10894 "Type_Type"=>$Type1_Pure{"Type"});
10895 }
10896 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040010897 %Sub_SubProblems = detectTypeChange($MemberType1_Id, $MemberType2_Id, "Field", $Level);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010898 foreach my $ProblemType (keys(%Sub_SubProblems))
10899 {
10900 my $Old_Value = $Sub_SubProblems{$ProblemType}{"Old_Value"};
10901 my $New_Value = $Sub_SubProblems{$ProblemType}{"New_Value"};
10902 if($ProblemType eq "Field_Type"
10903 or $ProblemType eq "Field_Type_And_Size")
10904 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040010905 if(checkDump(1, "2.6") and checkDump(2, "2.6"))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010906 {
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040010907 if(my $RA = addedQual($Old_Value, $New_Value, "volatile"))
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040010908 {
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040010909 %{$Sub_SubProblems{"Field_Became_Volatile"}} = %{$Sub_SubProblems{$ProblemType}};
10910 if($Level eq "Source"
10911 and cmpBTypes($Old_Value, $New_Value, 1, 2)) {
10912 delete($Sub_SubProblems{$ProblemType});
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040010913 }
10914 }
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040010915 elsif(my $RR = removedQual($Old_Value, $New_Value, "volatile"))
10916 {
10917 %{$Sub_SubProblems{"Field_Became_NonVolatile"}} = %{$Sub_SubProblems{$ProblemType}};
10918 if($Level eq "Source"
10919 and cmpBTypes($Old_Value, $New_Value, 1, 2)) {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040010920 delete($Sub_SubProblems{$ProblemType});
10921 }
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040010922 }
10923 }
10924 if(my $RA = addedQual($Old_Value, $New_Value, "const"))
10925 {
10926 if($RA==2) {
10927 %{$Sub_SubProblems{"Field_Added_Const"}} = %{$Sub_SubProblems{$ProblemType}};
10928 }
10929 else {
10930 %{$Sub_SubProblems{"Field_Became_Const"}} = %{$Sub_SubProblems{$ProblemType}};
10931 }
10932 if($Level eq "Source"
10933 and cmpBTypes($Old_Value, $New_Value, 1, 2)) {
10934 delete($Sub_SubProblems{$ProblemType});
10935 }
10936 }
10937 elsif(my $RR = removedQual($Old_Value, $New_Value, "const"))
10938 {
10939 if($RR==2) {
10940 %{$Sub_SubProblems{"Field_Removed_Const"}} = %{$Sub_SubProblems{$ProblemType}};
10941 }
10942 else {
10943 %{$Sub_SubProblems{"Field_Became_NonConst"}} = %{$Sub_SubProblems{$ProblemType}};
10944 }
10945 if($Level eq "Source"
10946 and cmpBTypes($Old_Value, $New_Value, 1, 2)) {
10947 delete($Sub_SubProblems{$ProblemType});
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010948 }
10949 }
10950 }
10951 }
10952 foreach my $ProblemType (keys(%Sub_SubProblems))
10953 {
10954 my $ProblemType_Init = $ProblemType;
10955 if($ProblemType eq "Field_Type_And_Size")
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040010956 { # Binary
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010957 if(not isPublic(\%Type1_Pure, $Member_Pos)
10958 or isUnnamed($Member_Name)) {
10959 $ProblemType = "Private_".$ProblemType;
10960 }
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +040010961 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 +040010962 { # check an effect
10963 if(my $MNum = isAccessible(\%Type1_Pure, \%RemovedField, $Member_Pos+1, -1))
10964 { # public fields after the current
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +040010965 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 +040010966 { # changed offset
10967 $ProblemType .= "_And_Layout";
10968 }
10969 }
10970 if($Type1_Pure{"Size"} ne $Type2_Pure{"Size"}) {
10971 $ProblemType .= "_And_Type_Size";
10972 }
10973 }
10974 }
10975 else
10976 {
10977 if(not isPublic(\%Type1_Pure, $Member_Pos)
10978 or isUnnamed($Member_Name)) {
10979 next;
10980 }
10981 }
10982 if($ProblemType eq "Private_Field_Type_And_Size")
10983 { # private field change with no effect
10984 next;
10985 }
10986 %{$SubProblems{$ProblemType}{$Member_Name}}=(
10987 "Target"=>$Member_Name,
10988 "Type_Name"=>$Type1_Pure{"Name"},
10989 "Type_Type"=>$Type1_Pure{"Type"} );
10990 foreach my $Attr (keys(%{$Sub_SubProblems{$ProblemType_Init}}))
10991 { # other properties
10992 $SubProblems{$ProblemType}{$Member_Name}{$Attr} = $Sub_SubProblems{$ProblemType_Init}{$Attr};
10993 }
10994 }
10995 if(not isPublic(\%Type1_Pure, $Member_Pos))
10996 { # do NOT check internal type changes
10997 next;
10998 }
10999 if($MemberType1_Id and $MemberType2_Id)
11000 {# checking member type changes (replace)
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040011001 %Sub_SubProblems = mergeTypes($MemberType1_Id, $MemberType2_Id, $Level);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011002 foreach my $Sub_SubProblemType (keys(%Sub_SubProblems))
11003 {
11004 foreach my $Sub_SubLocation (keys(%{$Sub_SubProblems{$Sub_SubProblemType}}))
11005 {
11006 my $NewLocation = ($Sub_SubLocation)?$Member_Name."->".$Sub_SubLocation:$Member_Name;
11007 $SubProblems{$Sub_SubProblemType}{$NewLocation}{"IsInTypeInternals"}=1;
11008 foreach my $Attr (keys(%{$Sub_SubProblems{$Sub_SubProblemType}{$Sub_SubLocation}})) {
11009 $SubProblems{$Sub_SubProblemType}{$NewLocation}{$Attr} = $Sub_SubProblems{$Sub_SubProblemType}{$Sub_SubLocation}{$Attr};
11010 }
11011 if($Sub_SubLocation!~/\-\>/) {
11012 $SubProblems{$Sub_SubProblemType}{$NewLocation}{"Start_Type_Name"} = $MemberType1_Name;
11013 }
11014 }
11015 }
11016 }
11017 }
11018 }
11019 }
11020 foreach my $Member_Pos (sort {int($a) <=> int($b)} keys(%{$Type2_Pure{"Memb"}}))
11021 { # checking added members, public and private
11022 my $Member_Name = $Type2_Pure{"Memb"}{$Member_Pos}{"name"};
11023 next if(not $Member_Name);
11024 if($AddedField{$Member_Pos})
11025 { # added
11026 if($Type2_Pure{"Type"}=~/\A(Struct|Class)\Z/)
11027 {
11028 my $ProblemType = "Added_Field";
11029 if(not isPublic(\%Type2_Pure, $Member_Pos)
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011030 or isUnnamed($Member_Name))
11031 {
11032 if($Level eq "Source") {
11033 next;
11034 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011035 $ProblemType = "Added_Private_Field";
11036 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011037 if($Level eq "Binary"
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +040011038 and not isMemPadded($Member_Pos, -1, \%Type2_Pure, \%AddedField, $TypeInfo{2}, $WORD_SIZE{2}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011039 {
11040 if(my $MNum = isAccessible(\%Type2_Pure, \%AddedField, $Member_Pos, -1))
11041 { # public fields after the current
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +040011042 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 +040011043 { # changed offset
11044 $ProblemType .= "_And_Layout";
11045 }
11046 }
11047 if($Type1_Pure{"Size"} ne $Type2_Pure{"Size"}) {
11048 $ProblemType .= "_And_Size";
11049 }
11050 }
11051 if($ProblemType eq "Added_Private_Field")
11052 { # skip added private fields
11053 next;
11054 }
11055 %{$SubProblems{$ProblemType}{$Member_Name}}=(
11056 "Target"=>$Member_Name,
11057 "Type_Name"=>$Type1_Pure{"Name"},
11058 "Type_Type"=>$Type1_Pure{"Type"} );
11059 }
11060 elsif($Type2_Pure{"Type"} eq "Union")
11061 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011062 if($Level eq "Binary"
11063 and $Type1_Pure{"Size"} ne $Type2_Pure{"Size"})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011064 {
11065 %{$SubProblems{"Added_Union_Field_And_Size"}{$Member_Name}}=(
11066 "Target"=>$Member_Name,
11067 "Type_Name"=>$Type1_Pure{"Name"},
11068 "Type_Type"=>$Type1_Pure{"Type"} );
11069 }
11070 else
11071 {
11072 %{$SubProblems{"Added_Union_Field"}{$Member_Name}}=(
11073 "Target"=>$Member_Name,
11074 "Type_Name"=>$Type1_Pure{"Name"},
11075 "Type_Type"=>$Type1_Pure{"Type"} );
11076 }
11077 }
11078 elsif($Type2_Pure{"Type"} eq "Enum")
11079 {
11080 my $Member_Value = $Type2_Pure{"Memb"}{$Member_Pos}{"value"};
11081 next if($Member_Value eq "");
11082 %{$SubProblems{"Added_Enum_Member"}{$Member_Name}}=(
11083 "Target"=>$Member_Name,
11084 "Type_Name"=>$Type2_Pure{"Name"},
11085 "Type_Type"=>$Type2_Pure{"Type"},
11086 "New_Value"=>$Member_Value );
11087 }
11088 }
11089 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040011090 %{$Cache{"mergeTypes"}{$Level}{$Type1_Id}{$Type2_Id}} = %SubProblems;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011091 pop(@RecurTypes);
11092 return %SubProblems;
11093}
11094
11095sub isUnnamed($) {
11096 return $_[0]=~/\Aunnamed\d+\Z/;
11097}
11098
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040011099sub get_ShortType($$)
11100{
11101 my ($TypeId, $LibVersion) = @_;
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +040011102 my $TypeName = uncover_typedefs($TypeInfo{$LibVersion}{$TypeId}{"Name"}, $LibVersion);
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040011103 if(my $NameSpace = $TypeInfo{$LibVersion}{$TypeId}{"NameSpace"}) {
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040011104 $TypeName=~s/\A$NameSpace\:\://g;
11105 }
11106 return $TypeName;
11107}
11108
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040011109sub goToFirst($$$)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011110{
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040011111 my ($TypeId, $LibVersion, $Type_Type) = @_;
Andrey Ponomarenko16934472012-03-29 15:37:04 +040011112 return () if(not $TypeId);
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040011113 if(defined $Cache{"goToFirst"}{$TypeId}{$LibVersion}{$Type_Type}) {
11114 return %{$Cache{"goToFirst"}{$TypeId}{$LibVersion}{$Type_Type}};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011115 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040011116 return () if(not $TypeInfo{$LibVersion}{$TypeId});
11117 my %Type = %{$TypeInfo{$LibVersion}{$TypeId}};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011118 return () if(not $Type{"Type"});
11119 if($Type{"Type"} ne $Type_Type)
11120 {
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040011121 return () if(not defined $Type{"BaseType"});
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040011122 return () if(not $Type{"BaseType"}{"Tid"});
11123 %Type = goToFirst($Type{"BaseType"}{"Tid"}, $LibVersion, $Type_Type);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011124 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040011125 $Cache{"goToFirst"}{$TypeId}{$LibVersion}{$Type_Type} = \%Type;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011126 return %Type;
11127}
11128
11129my %TypeSpecAttributes = (
11130 "Const" => 1,
11131 "Volatile" => 1,
11132 "ConstVolatile" => 1,
11133 "Restrict" => 1,
11134 "Typedef" => 1
11135);
11136
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040011137sub get_PureType($$)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011138{
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +040011139 my ($TypeId, $Info) = @_;
11140 if(not $TypeId or not $Info
11141 or not $Info->{$TypeId}) {
11142 return ();
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011143 }
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +040011144 if(defined $Cache{"get_PureType"}{$TypeId}{$Info}) {
11145 return %{$Cache{"get_PureType"}{$TypeId}{$Info}};
11146 }
11147 my %Type = %{$Info->{$TypeId}};
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040011148 return %Type if(not defined $Type{"BaseType"});
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040011149 return %Type if(not $Type{"BaseType"}{"Tid"});
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011150 if($TypeSpecAttributes{$Type{"Type"}}) {
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +040011151 %Type = get_PureType($Type{"BaseType"}{"Tid"}, $Info);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011152 }
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +040011153 $Cache{"get_PureType"}{$TypeId}{$Info} = \%Type;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011154 return %Type;
11155}
11156
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040011157sub get_PLevel($$)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011158{
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040011159 my ($TypeId, $LibVersion) = @_;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011160 return 0 if(not $TypeId);
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040011161 if(defined $Cache{"get_PLevel"}{$TypeId}{$LibVersion}) {
11162 return $Cache{"get_PLevel"}{$TypeId}{$LibVersion};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011163 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040011164 return 0 if(not $TypeInfo{$LibVersion}{$TypeId});
11165 my %Type = %{$TypeInfo{$LibVersion}{$TypeId}};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011166 return 1 if($Type{"Type"}=~/FuncPtr|MethodPtr|FieldPtr/);
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040011167 return 0 if(not defined $Type{"BaseType"});
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040011168 return 0 if(not $Type{"BaseType"}{"Tid"});
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011169 my $PointerLevel = 0;
11170 if($Type{"Type"} =~/Pointer|Ref|FuncPtr|MethodPtr|FieldPtr/) {
11171 $PointerLevel += 1;
11172 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040011173 $PointerLevel += get_PLevel($Type{"BaseType"}{"Tid"}, $LibVersion);
11174 $Cache{"get_PLevel"}{$TypeId}{$LibVersion} = $PointerLevel;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011175 return $PointerLevel;
11176}
11177
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040011178sub get_BaseType($$)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011179{
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040011180 my ($TypeId, $LibVersion) = @_;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011181 return () if(not $TypeId);
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040011182 if(defined $Cache{"get_BaseType"}{$TypeId}{$LibVersion}) {
11183 return %{$Cache{"get_BaseType"}{$TypeId}{$LibVersion}};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011184 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040011185 return () if(not $TypeInfo{$LibVersion}{$TypeId});
11186 my %Type = %{$TypeInfo{$LibVersion}{$TypeId}};
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040011187 return %Type if(not defined $Type{"BaseType"});
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040011188 return %Type if(not $Type{"BaseType"}{"Tid"});
11189 %Type = get_BaseType($Type{"BaseType"}{"Tid"}, $LibVersion);
11190 $Cache{"get_BaseType"}{$TypeId}{$LibVersion} = \%Type;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011191 return %Type;
11192}
11193
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040011194sub get_BaseTypeQual($$)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011195{
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040011196 my ($TypeId, $LibVersion) = @_;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011197 return "" if(not $TypeId);
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040011198 return "" if(not $TypeInfo{$LibVersion}{$TypeId});
11199 my %Type = %{$TypeInfo{$LibVersion}{$TypeId}};
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040011200 return "" if(not defined $Type{"BaseType"});
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040011201 return "" if(not $Type{"BaseType"}{"Tid"});
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011202 my $Qual = "";
11203 if($Type{"Type"} eq "Pointer") {
11204 $Qual .= "*";
11205 }
11206 elsif($Type{"Type"} eq "Ref") {
11207 $Qual .= "&";
11208 }
11209 elsif($Type{"Type"} eq "ConstVolatile") {
11210 $Qual .= "const volatile";
11211 }
11212 elsif($Type{"Type"} eq "Const"
11213 or $Type{"Type"} eq "Volatile"
11214 or $Type{"Type"} eq "Restrict") {
11215 $Qual .= lc($Type{"Type"});
11216 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040011217 my $BQual = get_BaseTypeQual($Type{"BaseType"}{"Tid"}, $LibVersion);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011218 return $BQual.$Qual;
11219}
11220
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040011221sub get_OneStep_BaseType($$)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011222{
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +040011223 my ($TypeId, $Info) = @_;
11224 if(not $TypeId or not $Info
11225 or not $Info->{$TypeId}) {
11226 return ();
11227 }
11228 my %Type = %{$Info->{$TypeId}};
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040011229 return %Type if(not defined $Type{"BaseType"});
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +040011230 if(my $BTid = $Type{"BaseType"}{"Tid"})
11231 {
11232 if($Info->{$BTid}) {
11233 return %{$Info->{$BTid}};
11234 }
11235 else { # something is going wrong
11236 return ();
11237 }
11238 }
11239 else {
11240 return %Type;
11241 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011242}
11243
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040011244sub get_Type($$)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011245{
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040011246 my ($TypeId, $LibVersion) = @_;
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040011247 return () if(not $TypeId);
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040011248 return () if(not $TypeInfo{$LibVersion}{$TypeId});
11249 return %{$TypeInfo{$LibVersion}{$TypeId}};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011250}
11251
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +040011252sub isPrivateData($)
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040011253{ # non-public global data
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011254 my $Symbol = $_[0];
11255 return ($Symbol=~/\A(_ZGV|_ZTI|_ZTS|_ZTT|_ZTV|_ZTC|_ZThn|_ZTv0_n)/);
11256}
11257
Andrey Ponomarenko01117f12012-06-26 12:23:02 +040011258sub isInLineInst($$$) {
11259 return (isTemplateInstance(@_) and not isTemplateSpec(@_));
11260}
11261
11262sub isTemplateInstance($$$)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011263{
Andrey Ponomarenko01117f12012-06-26 12:23:02 +040011264 my ($Symbol, $SInfo, $LibVersion) = @_;
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040011265 if($CheckObjectsOnly)
11266 {
11267 if($Symbol!~/\A(_Z|\?)/) {
11268 return 0;
11269 }
11270 if(my $Signature = $tr_name{$Symbol})
11271 {
11272 if(index($Signature,">")==-1) {
11273 return 0;
11274 }
11275 if(my $ShortName = substr($Signature, 0, find_center($Signature, "(")))
11276 {
Andrey Ponomarenko01117f12012-06-26 12:23:02 +040011277 if(index($ShortName,"<")!=-1
11278 and index($ShortName,">")!=-1) {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040011279 return 1;
11280 }
11281 }
11282 }
11283 }
11284 else
11285 {
Andrey Ponomarenko01117f12012-06-26 12:23:02 +040011286 if(my $ClassId = $SInfo->{"Class"})
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040011287 {
11288 if(my $ClassName = $TypeInfo{$LibVersion}{$ClassId}{"Name"})
11289 {
11290 if(index($ClassName,"<")!=-1) {
11291 return 1;
11292 }
11293 }
11294 }
Andrey Ponomarenko01117f12012-06-26 12:23:02 +040011295 if(my $ShortName = $SInfo->{"ShortName"})
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040011296 {
Andrey Ponomarenko01117f12012-06-26 12:23:02 +040011297 if(index($ShortName,"<")!=-1
11298 and index($ShortName,">")!=-1) {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040011299 return 1;
11300 }
11301 }
11302 }
11303 return 0;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011304}
11305
Andrey Ponomarenko01117f12012-06-26 12:23:02 +040011306sub isTemplateSpec($$$)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011307{
Andrey Ponomarenko01117f12012-06-26 12:23:02 +040011308 my ($Symbol, $SInfo, $LibVersion) = @_;
11309 if(my $ClassId = $SInfo->{"Class"})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011310 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040011311 if($TypeInfo{$LibVersion}{$ClassId}{"Spec"})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011312 { # class specialization
11313 return 1;
11314 }
Andrey Ponomarenko01117f12012-06-26 12:23:02 +040011315 elsif($SInfo->{"Spec"})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011316 { # method specialization
11317 return 1;
11318 }
11319 }
11320 return 0;
11321}
11322
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011323sub symbolFilter($$$$)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011324{ # some special cases when the symbol cannot be imported
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011325 my ($Symbol, $LibVersion, $Type, $Level) = @_;
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +040011326 if(isPrivateData($Symbol))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011327 { # non-public global data
11328 return 0;
11329 }
11330 if($CheckObjectsOnly) {
11331 return 0 if($Symbol=~/\A(_init|_fini)\Z/);
11332 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040011333 if($CheckHeadersOnly and not checkDump($LibVersion, "2.7"))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011334 { # support for old ABI dumps in --headers-only mode
11335 foreach my $Pos (keys(%{$CompleteSignature{$LibVersion}{$Symbol}{"Param"}}))
11336 {
11337 if(my $Pid = $CompleteSignature{$LibVersion}{$Symbol}{"Param"}{$Pos}{"type"})
11338 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040011339 my $PType = $TypeInfo{$LibVersion}{$Pid}{"Type"};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011340 if(not $PType or $PType eq "Unknown") {
11341 return 0;
11342 }
11343 }
11344 }
11345 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +040011346 if($Type=~/Affected/)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011347 {
11348 my $ClassId = $CompleteSignature{$LibVersion}{$Symbol}{"Class"};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011349 if($SkipSymbols{$LibVersion}{$Symbol})
11350 { # user defined symbols to ignore
11351 return 0;
11352 }
11353 my $NameSpace = $CompleteSignature{$LibVersion}{$Symbol}{"NameSpace"};
11354 if(not $NameSpace and $ClassId)
11355 { # class methods have no "NameSpace" attribute
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040011356 $NameSpace = $TypeInfo{$LibVersion}{$ClassId}{"NameSpace"};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011357 }
11358 if($NameSpace)
11359 { # user defined namespaces to ignore
11360 if($SkipNameSpaces{$LibVersion}{$NameSpace}) {
11361 return 0;
11362 }
11363 foreach my $NS (keys(%{$SkipNameSpaces{$LibVersion}}))
11364 { # nested namespaces
11365 if($NameSpace=~/\A\Q$NS\E(\:\:|\Z)/) {
11366 return 0;
11367 }
11368 }
11369 }
11370 if(my $Header = $CompleteSignature{$LibVersion}{$Symbol}{"Header"})
11371 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040011372 if(my $Skip = skipHeader($Header, $LibVersion))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011373 { # --skip-headers or <skip_headers> (not <skip_including>)
11374 if($Skip==1) {
11375 return 0;
11376 }
11377 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011378 }
11379 if($SymbolsListPath and not $SymbolsList{$Symbol})
11380 { # user defined symbols
11381 return 0;
11382 }
11383 if($AppPath and not $SymbolsList_App{$Symbol})
11384 { # user defined symbols (in application)
11385 return 0;
11386 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +040011387 if(not selectSymbol($Symbol, $CompleteSignature{$LibVersion}{$Symbol}, $Level, $LibVersion))
11388 { # non-target symbols
11389 return 0;
11390 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011391 if($Level eq "Binary")
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011392 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040011393 if($CheckObjectsOnly)
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011394 {
Andrey Ponomarenko01117f12012-06-26 12:23:02 +040011395 if(isTemplateInstance($Symbol, $CompleteSignature{$LibVersion}{$Symbol}, $LibVersion)) {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040011396 return 0;
11397 }
11398 }
11399 else
11400 {
11401 if($CompleteSignature{$LibVersion}{$Symbol}{"InLine"}
Andrey Ponomarenko01117f12012-06-26 12:23:02 +040011402 or isInLineInst($Symbol, $CompleteSignature{$LibVersion}{$Symbol}, $LibVersion))
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040011403 {
11404 if($ClassId and $CompleteSignature{$LibVersion}{$Symbol}{"Virt"})
11405 { # inline virtual methods
11406 if($Type=~/InlineVirt/) {
11407 return 1;
11408 }
11409 my $Allocable = (not isCopyingClass($ClassId, $LibVersion));
11410 if(not $Allocable)
11411 { # check bases
11412 foreach my $DCId (get_sub_classes($ClassId, $LibVersion, 1))
11413 {
11414 if(not isCopyingClass($DCId, $LibVersion))
11415 { # exists a derived class without default c-tor
11416 $Allocable=1;
11417 last;
11418 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011419 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011420 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040011421 if(not $Allocable) {
11422 return 0;
11423 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011424 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040011425 else
11426 { # inline non-virtual methods
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011427 return 0;
11428 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011429 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011430 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011431 }
11432 }
11433 return 1;
11434}
11435
11436sub mergeImpl()
11437{
11438 my $DiffCmd = get_CmdPath("diff");
11439 if(not $DiffCmd) {
11440 exitStatus("Not_Found", "can't find \"diff\"");
11441 }
11442 foreach my $Interface (sort keys(%{$Symbol_Library{1}}))
11443 { # implementation changes
11444 next if($CompleteSignature{1}{$Interface}{"Private"});
11445 next if(not $CompleteSignature{1}{$Interface}{"Header"} and not $CheckObjectsOnly);
11446 next if(not $Symbol_Library{2}{$Interface} and not $Symbol_Library{2}{$SymVer{2}{$Interface}});
Andrey Ponomarenko85043792012-05-14 16:48:07 +040011447 if(not symbolFilter($Interface, 1, "Affected", "Binary")) {
11448 next;
11449 }
Andrey Ponomarenko16934472012-03-29 15:37:04 +040011450 my $Impl1 = canonifyImpl($Interface_Impl{1}{$Interface});
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011451 next if(not $Impl1);
Andrey Ponomarenko16934472012-03-29 15:37:04 +040011452 my $Impl2 = canonifyImpl($Interface_Impl{2}{$Interface});
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011453 next if(not $Impl2);
11454 if($Impl1 ne $Impl2)
11455 {
11456 writeFile("$TMP_DIR/impl1", $Impl1);
11457 writeFile("$TMP_DIR/impl2", $Impl2);
Andrey Ponomarenkoa01311b2012-06-08 17:20:02 +040011458 my $Diff = `$DiffCmd -rNau \"$TMP_DIR/impl1\" \"$TMP_DIR/impl2\"`;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011459 $Diff=~s/(---|\+\+\+).+\n//g;
11460 $Diff=~s/[ ]{3,}/ /g;
11461 $Diff=~s/\n\@\@/\n \n\@\@/g;
Andrey Ponomarenkoa01311b2012-06-08 17:20:02 +040011462 unlink("$TMP_DIR/impl1");
11463 unlink("$TMP_DIR/impl2");
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011464 %{$ImplProblems{$Interface}}=(
11465 "Diff" => get_CodeView($Diff) );
11466 }
11467 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +040011468
11469 # clean memory
11470 %Interface_Impl = ();
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011471}
11472
Andrey Ponomarenko16934472012-03-29 15:37:04 +040011473sub canonifyImpl($)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011474{
11475 my $FuncBody= $_[0];
11476 return "" if(not $FuncBody);
11477 $FuncBody=~s/0x[a-f\d]+/0x?/g;# addr
11478 $FuncBody=~s/((\A|\n)[a-z]+[\t ]+)[a-f\d]+([^x]|\Z)/$1?$3/g;# call, jump
11479 $FuncBody=~s/# [a-f\d]+ /# ? /g;# call, jump
11480 $FuncBody=~s/%([a-z]+[a-f\d]*)/\%reg/g;# registers
11481 while($FuncBody=~s/\nnop[ \t]*(\n|\Z)/$1/g){};# empty op
11482 $FuncBody=~s/<.+?\.cpp.+?>/<name.cpp>/g;
11483 $FuncBody=~s/(\A|\n)[a-f\d]+ </$1? </g;# 5e74 <_ZN...
11484 $FuncBody=~s/\.L\d+/.L/g;
11485 $FuncBody=~s/#(-?)\d+/#$1?/g;# r3, [r3, #120]
11486 $FuncBody=~s/[\n]{2,}/\n/g;
11487 return $FuncBody;
11488}
11489
11490sub get_CodeView($)
11491{
11492 my $Code = $_[0];
11493 my $View = "";
11494 foreach my $Line (split(/\n/, $Code))
11495 {
11496 if($Line=~s/\A(\+|-)/$1 /g)
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040011497 { # bold line
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011498 $View .= "<tr><td><b>".htmlSpecChars($Line)."</b></td></tr>\n";
11499 }
11500 else {
11501 $View .= "<tr><td>".htmlSpecChars($Line)."</td></tr>\n";
11502 }
11503 }
11504 return "<table class='code_view'>$View</table>\n";
11505}
11506
11507sub getImplementations($$)
11508{
11509 my ($LibVersion, $Path) = @_;
11510 return if(not $LibVersion or not -e $Path);
11511 if($OSgroup eq "macos")
11512 {
11513 my $OtoolCmd = get_CmdPath("otool");
11514 if(not $OtoolCmd) {
11515 exitStatus("Not_Found", "can't find \"otool\"");
11516 }
11517 my $CurInterface = "";
Andrey Ponomarenkoa01311b2012-06-08 17:20:02 +040011518 foreach my $Line (split(/\n/, `$OtoolCmd -tv \"$Path\" 2>\"$TMP_DIR/null\"`))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011519 {
11520 if($Line=~/\A\s*_(\w+)\s*:/i) {
11521 $CurInterface = $1;
11522 }
11523 elsif($Line=~/\A\s*[\da-z]+\s+(.+?)\Z/i) {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040011524 $Interface_Impl{$LibVersion}{$CurInterface} .= $1."\n";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011525 }
11526 }
11527 }
11528 else
11529 {
11530 my $ObjdumpCmd = get_CmdPath("objdump");
11531 if(not $ObjdumpCmd) {
11532 exitStatus("Not_Found", "can't find \"objdump\"");
11533 }
11534 my $CurInterface = "";
Andrey Ponomarenkoa01311b2012-06-08 17:20:02 +040011535 foreach my $Line (split(/\n/, `$ObjdumpCmd -d \"$Path\" 2>\"$TMP_DIR/null\"`))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011536 {
11537 if($Line=~/\A[\da-z]+\s+<(\w+)>/i) {
11538 $CurInterface = $1;
11539 }
11540 else
11541 { # x86: 51fa:(\t)89 e5 (\t)mov %esp,%ebp
11542 # arm: 5020:(\t)e24cb004(\t)sub(\t)fp, ip, #4(\t); 0x4
11543 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 +040011544 $Interface_Impl{$LibVersion}{$CurInterface} .= $2."\n";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011545 }
11546 }
11547 }
11548 }
11549}
11550
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011551sub detectAdded($)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011552{
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011553 my $Level = $_[0];
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011554 foreach my $Symbol (keys(%{$Symbol_Library{2}}))
11555 {
11556 if(link_symbol($Symbol, 1, "+Deps"))
11557 { # linker can find a new symbol
11558 # in the old-version library
11559 # So, it's not a new symbol
11560 next;
11561 }
11562 if(my $VSym = $SymVer{2}{$Symbol}
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040011563 and index($Symbol,"\@")==-1) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011564 next;
11565 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011566 $AddedInt{$Level}{$Symbol} = 1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011567 }
11568}
11569
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011570sub detectRemoved($)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011571{
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011572 my $Level = $_[0];
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011573 foreach my $Symbol (keys(%{$Symbol_Library{1}}))
11574 {
11575 if($CheckObjectsOnly) {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011576 $CheckedSymbols{"Binary"}{$Symbol} = 1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011577 }
11578 if(link_symbol($Symbol, 2, "+Deps"))
11579 { # linker can find an old symbol
11580 # in the new-version library
11581 next;
11582 }
11583 if(my $VSym = $SymVer{1}{$Symbol}
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040011584 and index($Symbol,"\@")==-1) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011585 next;
11586 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011587 $RemovedInt{$Level}{$Symbol} = 1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011588 }
11589}
11590
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011591sub mergeLibs($)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011592{
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011593 my $Level = $_[0];
11594 foreach my $Symbol (sort keys(%{$AddedInt{$Level}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011595 { # checking added symbols
11596 next if($CompleteSignature{2}{$Symbol}{"Private"});
11597 next if(not $CompleteSignature{2}{$Symbol}{"Header"} and not $CheckObjectsOnly);
Andrey Ponomarenko85043792012-05-14 16:48:07 +040011598 next if(not symbolFilter($Symbol, 2, "Affected", $Level));
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011599 %{$CompatProblems{$Level}{$Symbol}{"Added_Symbol"}{""}}=();
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011600 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011601 foreach my $Symbol (sort keys(%{$RemovedInt{$Level}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011602 { # checking removed symbols
11603 next if($CompleteSignature{1}{$Symbol}{"Private"});
11604 next if(not $CompleteSignature{1}{$Symbol}{"Header"} and not $CheckObjectsOnly);
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040011605 if(index($Symbol, "_ZTV")==0)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011606 { # skip v-tables for templates, that should not be imported by applications
11607 next if($tr_name{$Symbol}=~/</);
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040011608 if(my $CName = $VTableClass{$Symbol})
11609 {
11610 if(not keys(%{$ClassMethods{$Level}{1}{$CName}}))
11611 { # vtables for "private" classes
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040011612 # use case: vtable for QDragManager (Qt 4.5.3 to 4.6.0) became HIDDEN symbol
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040011613 next;
11614 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011615 }
11616 }
11617 else {
Andrey Ponomarenko85043792012-05-14 16:48:07 +040011618 next if(not symbolFilter($Symbol, 1, "Affected", $Level));
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011619 }
11620 if($CompleteSignature{1}{$Symbol}{"PureVirt"})
11621 { # symbols for pure virtual methods cannot be called by clients
11622 next;
11623 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011624 %{$CompatProblems{$Level}{$Symbol}{"Removed_Symbol"}{""}}=();
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011625 }
11626}
11627
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040011628sub checkDump($$)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011629{
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040011630 my ($LibVersion, $V) = @_;
11631 if(defined $Cache{"checkDump"}{$LibVersion}{$V}) {
11632 return $Cache{"checkDump"}{$LibVersion}{$V};
11633 }
11634 return ($Cache{"checkDump"}{$LibVersion}{$V} = (not $UsedDump{$LibVersion}{"V"} or cmpVersions($UsedDump{$LibVersion}{"V"}, $V)>=0));
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011635}
11636
11637sub detectAdded_H($)
11638{
11639 my $Level = $_[0];
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011640 foreach my $Symbol (sort keys(%{$CompleteSignature{2}}))
11641 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011642 if($Level eq "Source")
11643 { # remove symbol version
11644 my ($SN, $SS, $SV) = separate_symbol($Symbol);
11645 $Symbol=$SN;
Andrey Ponomarenkob8d203d2012-05-25 18:11:07 +040011646
11647 if($CompleteSignature{2}{$Symbol}{"Artificial"})
11648 { # skip artificial constructors
11649 next;
11650 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011651 }
Andrey Ponomarenko16934472012-03-29 15:37:04 +040011652 if(not $CompleteSignature{2}{$Symbol}{"Header"}
11653 or not $CompleteSignature{2}{$Symbol}{"MnglName"}) {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011654 next;
11655 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040011656 if($ExtendedSymbols{$Symbol}) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011657 next;
11658 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011659 if(not defined $CompleteSignature{1}{$Symbol}
11660 or not $CompleteSignature{1}{$Symbol}{"MnglName"})
11661 {
Andrey Ponomarenko16934472012-03-29 15:37:04 +040011662 if($UsedDump{2}{"SrcBin"})
11663 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040011664 if($UsedDump{1}{"BinOnly"} or not checkDump(1, "2.11"))
Andrey Ponomarenko16934472012-03-29 15:37:04 +040011665 { # support for old and different (!) ABI dumps
11666 if(not $CompleteSignature{2}{$Symbol}{"Virt"}
11667 and not $CompleteSignature{2}{$Symbol}{"PureVirt"})
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011668 {
Andrey Ponomarenko16934472012-03-29 15:37:04 +040011669 if($CheckHeadersOnly)
Andrey Ponomarenko85043792012-05-14 16:48:07 +040011670 {
11671 if(my $Lang = $CompleteSignature{2}{$Symbol}{"Lang"})
11672 {
11673 if($Lang eq "C")
11674 { # support for old ABI dumps: missed extern "C" functions
11675 next;
11676 }
11677 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011678 }
Andrey Ponomarenko16934472012-03-29 15:37:04 +040011679 else
11680 {
11681 if(not link_symbol($Symbol, 2, "-Deps"))
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040011682 { # skip added inline symbols and const global data
Andrey Ponomarenko16934472012-03-29 15:37:04 +040011683 next;
11684 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011685 }
11686 }
11687 }
11688 }
11689 $AddedInt{$Level}{$Symbol} = 1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011690 }
11691 }
11692}
11693
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011694sub detectRemoved_H($)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011695{
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011696 my $Level = $_[0];
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011697 foreach my $Symbol (sort keys(%{$CompleteSignature{1}}))
11698 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011699 if($Level eq "Source")
11700 { # remove symbol version
11701 my ($SN, $SS, $SV) = separate_symbol($Symbol);
11702 $Symbol=$SN;
11703 }
Andrey Ponomarenko16934472012-03-29 15:37:04 +040011704 if(not $CompleteSignature{1}{$Symbol}{"Header"}
11705 or not $CompleteSignature{1}{$Symbol}{"MnglName"}) {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011706 next;
11707 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040011708 if($ExtendedSymbols{$Symbol}) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011709 next;
11710 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011711 if(not defined $CompleteSignature{2}{$Symbol}
11712 or not $CompleteSignature{2}{$Symbol}{"MnglName"})
Andrey Ponomarenko85043792012-05-14 16:48:07 +040011713 {
Andrey Ponomarenko16934472012-03-29 15:37:04 +040011714 if($UsedDump{1}{"SrcBin"})
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011715 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040011716 if($UsedDump{2}{"BinOnly"} or not checkDump(2, "2.11"))
Andrey Ponomarenko85043792012-05-14 16:48:07 +040011717 { # support for old and different (!) ABI dumps
Andrey Ponomarenko16934472012-03-29 15:37:04 +040011718 if(not $CompleteSignature{1}{$Symbol}{"Virt"}
11719 and not $CompleteSignature{1}{$Symbol}{"PureVirt"})
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011720 {
Andrey Ponomarenko16934472012-03-29 15:37:04 +040011721 if($CheckHeadersOnly)
11722 { # skip all removed symbols
Andrey Ponomarenko85043792012-05-14 16:48:07 +040011723 if(my $Lang = $CompleteSignature{1}{$Symbol}{"Lang"})
11724 {
11725 if($Lang eq "C")
11726 { # support for old ABI dumps: missed extern "C" functions
11727 next;
11728 }
11729 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011730 }
Andrey Ponomarenko16934472012-03-29 15:37:04 +040011731 else
11732 {
11733 if(not link_symbol($Symbol, 1, "-Deps"))
11734 { # skip removed inline symbols
11735 next;
11736 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011737 }
11738 }
11739 }
11740 }
Andrey Ponomarenkob8d203d2012-05-25 18:11:07 +040011741 if(not checkDump(1, "2.15"))
11742 {
11743 if($Symbol=~/_IT_E\Z/)
11744 { # _ZN28QExplicitlySharedDataPointerI22QSslCertificatePrivateEC1IT_EERKS_IT_E
11745 next;
11746 }
11747 }
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040011748 if(not $CompleteSignature{1}{$Symbol}{"Class"})
11749 {
11750 if(my $Short = $CompleteSignature{1}{$Symbol}{"ShortName"})
11751 {
11752 if(defined $Constants{2}{$Short})
11753 {
11754 my $Val = $Constants{2}{$Short}{"Value"};
11755 if(defined $Func_ShortName{2}{$Val})
11756 { # old name defined to new
11757 next;
11758 }
11759 }
11760 }
11761
11762 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011763 $RemovedInt{$Level}{$Symbol} = 1;
11764 if($Level eq "Source")
11765 { # search for a source-compatible equivalent
11766 setAlternative($Symbol, $Level);
11767 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011768 }
11769 }
11770}
11771
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011772sub mergeHeaders($)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011773{
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011774 my $Level = $_[0];
11775 foreach my $Symbol (sort keys(%{$AddedInt{$Level}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011776 { # checking added symbols
11777 next if($CompleteSignature{2}{$Symbol}{"PureVirt"});
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040011778 next if($CompleteSignature{2}{$Symbol}{"Private"});
11779 next if(not symbolFilter($Symbol, 2, "Affected", $Level));
Andrey Ponomarenko85043792012-05-14 16:48:07 +040011780 if($Level eq "Binary")
11781 {
11782 if($CompleteSignature{2}{$Symbol}{"InLine"})
11783 {
11784 if(not $CompleteSignature{2}{$Symbol}{"Virt"})
11785 { # skip inline non-virtual functions
11786 next;
11787 }
11788 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011789 }
11790 else
11791 { # Source
11792 if($SourceAlternative_B{$Symbol}) {
11793 next;
11794 }
11795 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011796 %{$CompatProblems{$Level}{$Symbol}{"Added_Symbol"}{""}}=();
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011797 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011798 foreach my $Symbol (sort keys(%{$RemovedInt{$Level}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011799 { # checking removed symbols
11800 next if($CompleteSignature{1}{$Symbol}{"PureVirt"});
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040011801 next if($CompleteSignature{1}{$Symbol}{"Private"});
11802 next if(not symbolFilter($Symbol, 1, "Affected", $Level));
Andrey Ponomarenko85043792012-05-14 16:48:07 +040011803 if($Level eq "Binary")
11804 {
11805 if($CompleteSignature{1}{$Symbol}{"InLine"})
11806 {
11807 if(not $CompleteSignature{1}{$Symbol}{"Virt"})
11808 { # skip inline non-virtual functions
11809 next;
11810 }
11811 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011812 }
11813 else
11814 { # Source
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040011815 if(my $Alt = $SourceAlternative{$Symbol})
11816 {
11817 if(defined $CompleteSignature{1}{$Alt}
11818 and $CompleteSignature{1}{$Symbol}{"Const"})
11819 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040011820 my $Cid = $CompleteSignature{1}{$Symbol}{"Class"};
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040011821 %{$CompatProblems{$Level}{$Symbol}{"Removed_Const_Overload"}{$tr_name{$Symbol}}}=(
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040011822 "Type_Name"=>$TypeInfo{1}{$Cid}{"Name"},
Andrey Ponomarenko85043792012-05-14 16:48:07 +040011823 "Type_Type"=>"Class",
11824 "Target"=>get_Signature($Alt, 1) );
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040011825 }
11826 else
11827 { # do NOT show removed symbol
11828 next;
11829 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011830 }
11831 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011832 %{$CompatProblems{$Level}{$Symbol}{"Removed_Symbol"}{""}}=();
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011833 }
11834}
11835
11836sub addParamNames($)
11837{
11838 my $LibraryVersion = $_[0];
11839 return if(not keys(%AddIntParams));
11840 my $SecondVersion = $LibraryVersion==1?2:1;
11841 foreach my $Interface (sort keys(%{$CompleteSignature{$LibraryVersion}}))
11842 {
11843 next if(not keys(%{$AddIntParams{$Interface}}));
11844 foreach my $ParamPos (sort {int($a)<=>int($b)} keys(%{$CompleteSignature{$LibraryVersion}{$Interface}{"Param"}}))
Andrey Ponomarenko85043792012-05-14 16:48:07 +040011845 { # add absent parameter names
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011846 my $ParamName = $CompleteSignature{$LibraryVersion}{$Interface}{"Param"}{$ParamPos}{"name"};
11847 if($ParamName=~/\Ap\d+\Z/ and my $NewParamName = $AddIntParams{$Interface}{$ParamPos})
Andrey Ponomarenko85043792012-05-14 16:48:07 +040011848 { # names from the external file
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011849 if(defined $CompleteSignature{$SecondVersion}{$Interface}
11850 and defined $CompleteSignature{$SecondVersion}{$Interface}{"Param"}{$ParamPos})
11851 {
11852 if($CompleteSignature{$SecondVersion}{$Interface}{"Param"}{$ParamPos}{"name"}=~/\Ap\d+\Z/) {
11853 $CompleteSignature{$LibraryVersion}{$Interface}{"Param"}{$ParamPos}{"name"} = $NewParamName;
11854 }
11855 }
11856 else {
11857 $CompleteSignature{$LibraryVersion}{$Interface}{"Param"}{$ParamPos}{"name"} = $NewParamName;
11858 }
11859 }
11860 }
11861 }
11862}
11863
11864sub detectChangedTypedefs()
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +040011865{ # detect changed typedefs to show
11866 # correct function signatures
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011867 foreach my $Typedef (keys(%{$Typedef_BaseName{1}}))
11868 {
11869 next if(not $Typedef);
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +040011870 my $BName1 = $Typedef_BaseName{1}{$Typedef};
11871 if(not $BName1 or isAnon($BName1)) {
11872 next;
11873 }
11874 my $BName2 = $Typedef_BaseName{2}{$Typedef};
11875 if(not $BName2 or isAnon($BName2)) {
11876 next;
11877 }
11878 if($BName1 ne $BName2) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011879 $ChangedTypedef{$Typedef} = 1;
11880 }
11881 }
11882}
11883
11884sub get_symbol_suffix($$)
11885{
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011886 my ($Symbol, $Full) = @_;
11887 my ($SN, $SO, $SV) = separate_symbol($Symbol);
11888 $Symbol=$SN;# remove version
11889 my $Signature = $tr_name{$Symbol};
Andrey Ponomarenko16934472012-03-29 15:37:04 +040011890 my $Suffix = substr($Signature, find_center($Signature, "("));
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011891 if(not $Full) {
11892 $Suffix=~s/(\))\s*(const volatile|volatile const|const|volatile)\Z/$1/g;
11893 }
11894 return $Suffix;
11895}
11896
11897sub get_symbol_prefix($$)
11898{
11899 my ($Symbol, $LibVersion) = @_;
11900 my $ShortName = $CompleteSignature{$LibVersion}{$Symbol}{"ShortName"};
11901 if(my $ClassId = $CompleteSignature{$LibVersion}{$Symbol}{"Class"})
11902 { # methods
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040011903 $ShortName = $TypeInfo{$LibVersion}{$ClassId}{"Name"}."::".$ShortName;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011904 }
11905 return $ShortName;
11906}
11907
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011908sub setAlternative($)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011909{
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011910 my $Symbol = $_[0];
11911 my $PSymbol = $Symbol;
11912 if(not defined $CompleteSignature{2}{$PSymbol}
11913 or (not $CompleteSignature{2}{$PSymbol}{"MnglName"}
11914 and not $CompleteSignature{2}{$PSymbol}{"ShortName"}))
11915 { # search for a pair
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040011916 if(my $ShortName = $CompleteSignature{1}{$PSymbol}{"ShortName"})
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011917 {
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040011918 if($CompleteSignature{1}{$PSymbol}{"Data"})
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011919 {
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040011920 if($PSymbol=~s/L(\d+$ShortName(E)\Z)/$1/
11921 or $PSymbol=~s/(\d+$ShortName(E)\Z)/L$1/)
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011922 {
11923 if(defined $CompleteSignature{2}{$PSymbol}
11924 and $CompleteSignature{2}{$PSymbol}{"MnglName"})
11925 {
11926 $SourceAlternative{$Symbol} = $PSymbol;
11927 $SourceAlternative_B{$PSymbol} = $Symbol;
11928 if(not defined $CompleteSignature{1}{$PSymbol}
11929 or not $CompleteSignature{1}{$PSymbol}{"MnglName"}) {
11930 $SourceReplacement{$Symbol} = $PSymbol;
11931 }
11932 }
11933 }
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040011934 }
11935 else
11936 {
11937 foreach my $Sp ("KV", "VK", "K", "V")
11938 {
11939 if($PSymbol=~s/\A_ZN$Sp/_ZN/
11940 or $PSymbol=~s/\A_ZN/_ZN$Sp/)
11941 {
11942 if(defined $CompleteSignature{2}{$PSymbol}
11943 and $CompleteSignature{2}{$PSymbol}{"MnglName"})
11944 {
11945 $SourceAlternative{$Symbol} = $PSymbol;
11946 $SourceAlternative_B{$PSymbol} = $Symbol;
11947 if(not defined $CompleteSignature{1}{$PSymbol}
11948 or not $CompleteSignature{1}{$PSymbol}{"MnglName"}) {
11949 $SourceReplacement{$Symbol} = $PSymbol;
11950 }
11951 }
11952 }
11953 $PSymbol = $Symbol;
11954 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011955 }
11956 }
11957 }
11958 return "";
11959}
11960
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040011961sub getSymKind($$)
11962{
11963 my ($Symbol, $LibVersion) = @_;
11964 if($CompleteSignature{$LibVersion}{$Symbol}{"Data"})
11965 {
11966 return "Global_Data";
11967 }
11968 elsif($CompleteSignature{$LibVersion}{$Symbol}{"Class"})
11969 {
11970 return "Method";
11971 }
11972 return "Function";
11973}
11974
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011975sub mergeSignatures($)
11976{
11977 my $Level = $_[0];
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011978 my %SubProblems = ();
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011979
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011980 mergeBases($Level);
11981
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011982 my %AddedOverloads = ();
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011983 foreach my $Symbol (sort keys(%{$AddedInt{$Level}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011984 { # check all added exported symbols
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011985 if(not $CompleteSignature{2}{$Symbol}{"Header"}) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011986 next;
11987 }
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040011988 if(defined $CompleteSignature{1}{$Symbol}
11989 and $CompleteSignature{1}{$Symbol}{"Header"})
11990 { # double-check added symbol
11991 next;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011992 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +040011993 if(not symbolFilter($Symbol, 2, "Affected", $Level)) {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011994 next;
11995 }
11996 if($Symbol=~/\A(_Z|\?)/)
11997 { # C++
11998 $AddedOverloads{get_symbol_prefix($Symbol, 2)}{get_symbol_suffix($Symbol, 1)} = $Symbol;
11999 }
12000 if(my $OverriddenMethod = $CompleteSignature{2}{$Symbol}{"Override"})
12001 { # register virtual overridings
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040012002 my $Cid = $CompleteSignature{2}{$Symbol}{"Class"};
12003 my $AffectedClass_Name = $TypeInfo{2}{$Cid}{"Name"};
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040012004 if(defined $CompleteSignature{1}{$OverriddenMethod} and $CompleteSignature{1}{$OverriddenMethod}{"Virt"}
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012005 and not $CompleteSignature{1}{$OverriddenMethod}{"Private"})
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040012006 {
12007 if($TName_Tid{1}{$AffectedClass_Name})
12008 { # class should exist in previous version
12009 if(not isCopyingClass($TName_Tid{1}{$AffectedClass_Name}, 1))
12010 { # old v-table is NOT copied by old applications
12011 %{$CompatProblems{$Level}{$OverriddenMethod}{"Overridden_Virtual_Method"}{$tr_name{$Symbol}}}=(
12012 "Type_Name"=>$AffectedClass_Name,
12013 "Type_Type"=>"Class",
12014 "Target"=>get_Signature($Symbol, 2),
12015 "Old_Value"=>get_Signature($OverriddenMethod, 2),
12016 "New_Value"=>get_Signature($Symbol, 2) );
12017 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012018 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012019 }
12020 }
12021 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012022 foreach my $Symbol (sort keys(%{$RemovedInt{$Level}}))
12023 { # check all removed exported symbols
12024 if(not $CompleteSignature{1}{$Symbol}{"Header"}) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012025 next;
12026 }
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040012027 if(defined $CompleteSignature{2}{$Symbol}
12028 and $CompleteSignature{2}{$Symbol}{"Header"})
12029 { # double-check removed symbol
12030 next;
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012031 }
12032 if($CompleteSignature{1}{$Symbol}{"Private"})
12033 { # skip private methods
12034 next;
12035 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +040012036 if(not symbolFilter($Symbol, 1, "Affected", $Level)) {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012037 next;
12038 }
12039 $CheckedSymbols{$Level}{$Symbol} = 1;
12040 if(my $OverriddenMethod = $CompleteSignature{1}{$Symbol}{"Override"})
12041 { # register virtual overridings
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040012042 my $Cid = $CompleteSignature{1}{$Symbol}{"Class"};
12043 my $AffectedClass_Name = $TypeInfo{1}{$Cid}{"Name"};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012044 if(defined $CompleteSignature{2}{$OverriddenMethod}
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040012045 and $CompleteSignature{2}{$OverriddenMethod}{"Virt"})
12046 {
12047 if($TName_Tid{2}{$AffectedClass_Name})
12048 { # class should exist in newer version
12049 if(not isCopyingClass($CompleteSignature{1}{$Symbol}{"Class"}, 1))
12050 { # old v-table is NOT copied by old applications
12051 %{$CompatProblems{$Level}{$Symbol}{"Overridden_Virtual_Method_B"}{$tr_name{$OverriddenMethod}}}=(
12052 "Type_Name"=>$AffectedClass_Name,
12053 "Type_Type"=>"Class",
12054 "Target"=>get_Signature($OverriddenMethod, 1),
12055 "Old_Value"=>get_Signature($Symbol, 1),
12056 "New_Value"=>get_Signature($OverriddenMethod, 1) );
12057 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012058 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012059 }
12060 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012061 if($Level eq "Binary"
12062 and $OSgroup eq "windows")
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012063 { # register the reason of symbol name change
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040012064 if(my $NewSym = $mangled_name{2}{$tr_name{$Symbol}})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012065 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040012066 if($AddedInt{$Level}{$NewSym})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012067 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040012068 if($CompleteSignature{1}{$Symbol}{"Static"} ne $CompleteSignature{2}{$NewSym}{"Static"})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012069 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040012070 if($CompleteSignature{2}{$NewSym}{"Static"})
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012071 {
12072 %{$CompatProblems{$Level}{$Symbol}{"Symbol_Became_Static"}{$tr_name{$Symbol}}}=(
12073 "Target"=>$tr_name{$Symbol},
12074 "Old_Value"=>$Symbol,
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040012075 "New_Value"=>$NewSym );
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012076 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012077 else
12078 {
12079 %{$CompatProblems{$Level}{$Symbol}{"Symbol_Became_NonStatic"}{$tr_name{$Symbol}}}=(
12080 "Target"=>$tr_name{$Symbol},
12081 "Old_Value"=>$Symbol,
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040012082 "New_Value"=>$NewSym );
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012083 }
12084 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040012085 if($CompleteSignature{1}{$Symbol}{"Virt"} ne $CompleteSignature{2}{$NewSym}{"Virt"})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012086 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040012087 if($CompleteSignature{2}{$NewSym}{"Virt"})
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012088 {
12089 %{$CompatProblems{$Level}{$Symbol}{"Symbol_Became_Virtual"}{$tr_name{$Symbol}}}=(
12090 "Target"=>$tr_name{$Symbol},
12091 "Old_Value"=>$Symbol,
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040012092 "New_Value"=>$NewSym );
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012093 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012094 else
12095 {
12096 %{$CompatProblems{$Level}{$Symbol}{"Symbol_Became_NonVirtual"}{$tr_name{$Symbol}}}=(
12097 "Target"=>$tr_name{$Symbol},
12098 "Old_Value"=>$Symbol,
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040012099 "New_Value"=>$NewSym );
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012100 }
12101 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040012102 my $RTId1 = $CompleteSignature{1}{$Symbol}{"Return"};
12103 my $RTId2 = $CompleteSignature{2}{$NewSym}{"Return"};
12104 my $RTName1 = $TypeInfo{1}{$RTId1}{"Name"};
12105 my $RTName2 = $TypeInfo{2}{$RTId2}{"Name"};
12106 if($RTName1 ne $RTName2)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012107 {
12108 my $ProblemType = "Symbol_Changed_Return";
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012109 if($CompleteSignature{1}{$Symbol}{"Data"}) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012110 $ProblemType = "Global_Data_Symbol_Changed_Type";
12111 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012112 %{$CompatProblems{$Level}{$Symbol}{$ProblemType}{$tr_name{$Symbol}}}=(
12113 "Target"=>$tr_name{$Symbol},
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040012114 "Old_Type"=>$RTName1,
12115 "New_Type"=>$RTName2,
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012116 "Old_Value"=>$Symbol,
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040012117 "New_Value"=>$NewSym );
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012118 }
12119 }
12120 }
12121 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012122 if($Symbol=~/\A(_Z|\?)/)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012123 { # C++
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012124 my $Prefix = get_symbol_prefix($Symbol, 1);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012125 if(my @Overloads = sort keys(%{$AddedOverloads{$Prefix}})
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012126 and not $AddedOverloads{$Prefix}{get_symbol_suffix($Symbol, 1)})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012127 { # changed signature: params, "const"-qualifier
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040012128 my $NewSym = $AddedOverloads{$Prefix}{$Overloads[0]};
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012129 if($CompleteSignature{1}{$Symbol}{"Constructor"})
12130 {
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +040012131 if($Symbol=~/(C1E|C2E)/)
12132 {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012133 my $CtorType = $1;
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040012134 $NewSym=~s/(C1E|C2E)/$CtorType/g;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012135 }
12136 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012137 elsif($CompleteSignature{1}{$Symbol}{"Destructor"})
12138 {
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +040012139 if($Symbol=~/(D0E|D1E|D2E)/)
12140 {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012141 my $DtorType = $1;
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040012142 $NewSym=~s/(D0E|D1E|D2E)/$DtorType/g;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012143 }
12144 }
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040012145 my $NS1 = $CompleteSignature{1}{$Symbol}{"NameSpace"};
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040012146 my $NS2 = $CompleteSignature{2}{$NewSym}{"NameSpace"};
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040012147 if((not $NS1 and not $NS2) or ($NS1 and $NS2 and $NS1 eq $NS2))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012148 { # from the same class and namespace
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012149 if($CompleteSignature{1}{$Symbol}{"Const"}
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040012150 and not $CompleteSignature{2}{$NewSym}{"Const"})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012151 { # "const" to non-"const"
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040012152 %{$CompatProblems{$Level}{$Symbol}{"Method_Became_NonConst"}{$tr_name{$Symbol}}}=(
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040012153 "Type_Name"=>$TypeInfo{1}{$CompleteSignature{1}{$Symbol}{"Class"}}{"Name"},
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012154 "Target"=>$tr_name{$Symbol},
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040012155 "New_Signature"=>get_Signature($NewSym, 2),
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012156 "Old_Value"=>$Symbol,
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040012157 "New_Value"=>$NewSym );
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012158 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012159 elsif(not $CompleteSignature{1}{$Symbol}{"Const"}
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040012160 and $CompleteSignature{2}{$NewSym}{"Const"})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012161 { # non-"const" to "const"
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040012162 %{$CompatProblems{$Level}{$Symbol}{"Method_Became_Const"}{$tr_name{$Symbol}}}=(
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012163 "Target"=>$tr_name{$Symbol},
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040012164 "New_Signature"=>get_Signature($NewSym, 2),
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012165 "Old_Value"=>$Symbol,
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040012166 "New_Value"=>$NewSym );
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012167 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012168 if($CompleteSignature{1}{$Symbol}{"Volatile"}
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040012169 and not $CompleteSignature{2}{$NewSym}{"Volatile"})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012170 { # "volatile" to non-"volatile"
12171
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040012172 %{$CompatProblems{$Level}{$Symbol}{"Method_Became_NonVolatile"}{$tr_name{$Symbol}}}=(
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012173 "Target"=>$tr_name{$Symbol},
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040012174 "New_Signature"=>get_Signature($NewSym, 2),
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012175 "Old_Value"=>$Symbol,
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040012176 "New_Value"=>$NewSym );
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012177 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012178 elsif(not $CompleteSignature{1}{$Symbol}{"Volatile"}
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040012179 and $CompleteSignature{2}{$NewSym}{"Volatile"})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012180 { # non-"volatile" to "volatile"
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040012181 %{$CompatProblems{$Level}{$Symbol}{"Method_Became_Volatile"}{$tr_name{$Symbol}}}=(
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012182 "Target"=>$tr_name{$Symbol},
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040012183 "New_Signature"=>get_Signature($NewSym, 2),
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012184 "Old_Value"=>$Symbol,
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040012185 "New_Value"=>$NewSym );
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012186 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040012187 if(get_symbol_suffix($Symbol, 0) ne get_symbol_suffix($NewSym, 0))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012188 { # params list
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012189 %{$CompatProblems{$Level}{$Symbol}{"Symbol_Changed_Parameters"}{$tr_name{$Symbol}}}=(
12190 "Target"=>$tr_name{$Symbol},
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040012191 "New_Signature"=>get_Signature($NewSym, 2),
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012192 "Old_Value"=>$Symbol,
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040012193 "New_Value"=>$NewSym );
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012194 }
12195 }
12196 }
12197 }
12198 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012199 foreach my $Symbol (sort keys(%{$CompleteSignature{1}}))
12200 { # checking symbols
12201 my ($SN, $SS, $SV) = separate_symbol($Symbol);
12202 if($Level eq "Source")
12203 { # remove symbol version
12204 $Symbol=$SN;
12205 }
12206 else
12207 { # Binary
12208 if(not $SV)
12209 { # symbol without version
12210 if(my $VSym = $SymVer{1}{$Symbol})
12211 { # the symbol is linked with versioned symbol
12212 if($CompleteSignature{2}{$VSym}{"MnglName"})
12213 { # show report for symbol@ver only
12214 next;
12215 }
12216 elsif(not link_symbol($VSym, 2, "-Deps"))
12217 { # changed version: sym@v1 to sym@v2
12218 # do NOT show report for symbol
12219 next;
12220 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012221 }
12222 }
12223 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012224 my $PSymbol = $Symbol;
12225 if($Level eq "Source"
12226 and my $S = $SourceReplacement{$Symbol})
12227 { # take a source-compatible replacement function
12228 $PSymbol = $S;
12229 }
12230 if($CompleteSignature{1}{$Symbol}{"Private"})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012231 { # private symbols
12232 next;
12233 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012234 if(not defined $CompleteSignature{1}{$Symbol}
12235 or not defined $CompleteSignature{2}{$PSymbol})
12236 { # no info
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012237 next;
12238 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012239 if(not $CompleteSignature{1}{$Symbol}{"MnglName"}
12240 or not $CompleteSignature{2}{$PSymbol}{"MnglName"})
12241 { # no mangled name
12242 next;
12243 }
12244 if(not $CompleteSignature{1}{$Symbol}{"Header"}
12245 or not $CompleteSignature{2}{$PSymbol}{"Header"})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012246 { # without a header
12247 next;
12248 }
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040012249
12250 if(not $CompleteSignature{1}{$Symbol}{"PureVirt"}
12251 and $CompleteSignature{2}{$PSymbol}{"PureVirt"})
12252 { # became pure
12253 next;
12254 }
12255 if($CompleteSignature{1}{$Symbol}{"PureVirt"}
12256 and not $CompleteSignature{2}{$PSymbol}{"PureVirt"})
12257 { # became non-pure
12258 next;
12259 }
12260
12261 if(not symbolFilter($Symbol, 1, "Affected + InlineVirt", $Level))
12262 { # exported, target, inline virtual and pure virtual
12263 next;
12264 }
12265 if(not symbolFilter($PSymbol, 2, "Affected + InlineVirt", $Level))
12266 { # exported, target, inline virtual and pure virtual
12267 next;
12268 }
12269
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040012270 if(checkDump(1, "2.13") and checkDump(2, "2.13"))
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040012271 {
12272 if($CompleteSignature{1}{$Symbol}{"Data"}
12273 and $CompleteSignature{2}{$PSymbol}{"Data"})
12274 {
12275 my $Value1 = $CompleteSignature{1}{$Symbol}{"Value"};
12276 my $Value2 = $CompleteSignature{2}{$PSymbol}{"Value"};
12277 if(defined $Value1)
12278 {
12279 $Value1 = showVal($Value1, $CompleteSignature{1}{$Symbol}{"Return"}, 1);
12280 if(defined $Value2)
12281 {
12282 $Value2 = showVal($Value2, $CompleteSignature{2}{$PSymbol}{"Return"}, 2);
12283 if($Value1 ne $Value2)
12284 {
12285 %{$CompatProblems{$Level}{$Symbol}{"Global_Data_Value_Changed"}{""}}=(
12286 "Old_Value"=>$Value1,
12287 "New_Value"=>$Value2,
12288 "Target"=>get_Signature($Symbol, 1) );
12289 }
12290 }
12291 }
12292 }
12293 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +040012294
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040012295 if($CompleteSignature{2}{$PSymbol}{"Private"})
12296 {
12297 %{$CompatProblems{$Level}{$Symbol}{getSymKind($Symbol, 1)."_Became_Private"}{""}}=(
12298 "Target"=>get_Signature_M($PSymbol, 2) );
12299 }
12300 elsif(not $CompleteSignature{1}{$Symbol}{"Protected"}
12301 and $CompleteSignature{2}{$PSymbol}{"Protected"})
12302 {
12303 %{$CompatProblems{$Level}{$Symbol}{getSymKind($Symbol, 1)."_Became_Protected"}{""}}=(
12304 "Target"=>get_Signature_M($PSymbol, 2) );
12305 }
12306 elsif($CompleteSignature{1}{$Symbol}{"Protected"}
12307 and not $CompleteSignature{2}{$PSymbol}{"Protected"})
12308 {
12309 %{$CompatProblems{$Level}{$Symbol}{getSymKind($Symbol, 1)."_Became_Public"}{""}}=(
12310 "Target"=>get_Signature_M($PSymbol, 2) );
12311 }
12312
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012313 # checking virtual table
Andrey Ponomarenko16934472012-03-29 15:37:04 +040012314 mergeVirtualTables($Symbol, $Level);
12315
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012316 if($COMPILE_ERRORS)
12317 { # if some errors occurred at the compiling stage
12318 # then some false positives can be skipped here
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012319 if(not $CompleteSignature{1}{$Symbol}{"Data"} and $CompleteSignature{2}{$PSymbol}{"Data"}
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040012320 and not $GlobalDataObject{2}{$Symbol})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012321 { # missed information about parameters in newer version
12322 next;
12323 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040012324 if($CompleteSignature{1}{$Symbol}{"Data"} and not $GlobalDataObject{1}{$Symbol}
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012325 and not $CompleteSignature{2}{$PSymbol}{"Data"})
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040012326 { # missed information about parameters in older version
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012327 next;
12328 }
12329 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012330 my ($MnglName, $VersionSpec, $SymbolVersion) = separate_symbol($Symbol);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012331 # checking attributes
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012332 if($CompleteSignature{2}{$PSymbol}{"Static"}
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040012333 and not $CompleteSignature{1}{$Symbol}{"Static"} and $Symbol=~/\A(_Z|\?)/)
12334 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012335 %{$CompatProblems{$Level}{$Symbol}{"Method_Became_Static"}{""}}=(
12336 "Target"=>get_Signature($Symbol, 1)
12337 );
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012338 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012339 elsif(not $CompleteSignature{2}{$PSymbol}{"Static"}
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040012340 and $CompleteSignature{1}{$Symbol}{"Static"} and $Symbol=~/\A(_Z|\?)/)
12341 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012342 %{$CompatProblems{$Level}{$Symbol}{"Method_Became_NonStatic"}{""}}=(
12343 "Target"=>get_Signature($Symbol, 1)
12344 );
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012345 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012346 if(($CompleteSignature{1}{$Symbol}{"Virt"} and $CompleteSignature{2}{$PSymbol}{"Virt"})
12347 or ($CompleteSignature{1}{$Symbol}{"PureVirt"} and $CompleteSignature{2}{$PSymbol}{"PureVirt"}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012348 { # relative position of virtual and pure virtual methods
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012349 if($Level eq "Binary")
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012350 {
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040012351 if(defined $CompleteSignature{1}{$Symbol}{"RelPos"} and defined $CompleteSignature{2}{$PSymbol}{"RelPos"}
12352 and $CompleteSignature{1}{$Symbol}{"RelPos"}!=$CompleteSignature{2}{$PSymbol}{"RelPos"})
12353 { # top-level virtual methods only
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012354 my $Class_Id = $CompleteSignature{1}{$Symbol}{"Class"};
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040012355 my $Class_Name = $TypeInfo{1}{$Class_Id}{"Name"};
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040012356 if(defined $VirtualTable{1}{$Class_Name} and defined $VirtualTable{2}{$Class_Name}
12357 and $VirtualTable{1}{$Class_Name}{$Symbol}!=$VirtualTable{2}{$Class_Name}{$Symbol})
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012358 { # check the absolute position of virtual method (including added and removed methods)
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040012359 my %Class_Type = get_Type($Class_Id, 1);
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012360 my $ProblemType = "Virtual_Method_Position";
12361 if($CompleteSignature{1}{$Symbol}{"PureVirt"}) {
12362 $ProblemType = "Pure_Virtual_Method_Position";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012363 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012364 if(isUsedClass($Class_Id, 1, $Level))
12365 {
12366 my @Affected = ($Symbol, keys(%{$OverriddenMethods{1}{$Symbol}}));
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040012367 foreach my $ASymbol (@Affected)
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012368 {
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040012369 if(not symbolFilter($ASymbol, 1, "Affected", $Level)) {
12370 next;
12371 }
12372 %{$CompatProblems{$Level}{$ASymbol}{$ProblemType}{$tr_name{$MnglName}}}=(
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012373 "Type_Name"=>$Class_Type{"Name"},
12374 "Type_Type"=>"Class",
12375 "Old_Value"=>$CompleteSignature{1}{$Symbol}{"RelPos"},
12376 "New_Value"=>$CompleteSignature{2}{$PSymbol}{"RelPos"},
12377 "Target"=>get_Signature($Symbol, 1) );
12378 }
Andrey Ponomarenko16934472012-03-29 15:37:04 +040012379 $VTableChanged_M{$Class_Type{"Name"}} = 1;
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012380 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012381 }
12382 }
12383 }
12384 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012385 if($CompleteSignature{1}{$Symbol}{"PureVirt"}
12386 or $CompleteSignature{2}{$PSymbol}{"PureVirt"})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012387 { # do NOT check type changes in pure virtuals
12388 next;
12389 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012390 $CheckedSymbols{$Level}{$Symbol}=1;
12391 if($Symbol=~/\A(_Z|\?)/
12392 or keys(%{$CompleteSignature{1}{$Symbol}{"Param"}})==keys(%{$CompleteSignature{2}{$PSymbol}{"Param"}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012393 { # C/C++: changes in parameters
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012394 foreach my $ParamPos (sort {int($a) <=> int($b)} keys(%{$CompleteSignature{1}{$Symbol}{"Param"}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012395 { # checking parameters
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012396 mergeParameters($Symbol, $PSymbol, $ParamPos, $ParamPos, $Level);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012397 }
12398 }
12399 else
12400 { # C: added/removed parameters
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012401 foreach my $ParamPos (sort {int($a) <=> int($b)} keys(%{$CompleteSignature{2}{$PSymbol}{"Param"}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012402 { # checking added parameters
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040012403 my $PType2_Id = $CompleteSignature{2}{$PSymbol}{"Param"}{$ParamPos}{"type"};
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040012404 my $PType2_Name = $TypeInfo{2}{$PType2_Id}{"Name"};
12405 last if($PType2_Name eq "...");
12406 my $PName = $CompleteSignature{2}{$PSymbol}{"Param"}{$ParamPos}{"name"};
12407 my $PName_Old = (defined $CompleteSignature{1}{$Symbol}{"Param"}{$ParamPos})?$CompleteSignature{1}{$Symbol}{"Param"}{$ParamPos}{"name"}:"";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012408 my $ParamPos_Prev = "-1";
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040012409 if($PName=~/\Ap\d+\Z/i)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012410 { # added unnamed parameter ( pN )
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040012411 my @Positions1 = find_ParamPair_Pos_byTypeAndPos($PType2_Name, $ParamPos, "backward", $Symbol, 1);
12412 my @Positions2 = find_ParamPair_Pos_byTypeAndPos($PType2_Name, $ParamPos, "backward", $Symbol, 2);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012413 if($#Positions1==-1 or $#Positions2>$#Positions1) {
12414 $ParamPos_Prev = "lost";
12415 }
12416 }
12417 else {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040012418 $ParamPos_Prev = find_ParamPair_Pos_byName($PName, $Symbol, 1);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012419 }
12420 if($ParamPos_Prev eq "lost")
12421 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012422 if($ParamPos>keys(%{$CompleteSignature{1}{$Symbol}{"Param"}})-1)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012423 {
12424 my $ProblemType = "Added_Parameter";
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040012425 if($PName=~/\Ap\d+\Z/) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012426 $ProblemType = "Added_Unnamed_Parameter";
12427 }
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040012428 %{$CompatProblems{$Level}{$Symbol}{$ProblemType}{showPos($ParamPos)." Parameter"}}=(
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040012429 "Target"=>$PName,
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012430 "Param_Pos"=>$ParamPos,
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040012431 "Param_Type"=>$PType2_Name,
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012432 "New_Signature"=>get_Signature($Symbol, 2) );
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012433 }
12434 else
12435 {
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +040012436 my %ParamType_Pure = get_PureType($PType2_Id, $TypeInfo{2});
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040012437 my $PairType_Id = $CompleteSignature{1}{$Symbol}{"Param"}{$ParamPos}{"type"};
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +040012438 my %PairType_Pure = get_PureType($PairType_Id, $TypeInfo{1});
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040012439 if(($ParamType_Pure{"Name"} eq $PairType_Pure{"Name"} or $PType2_Name eq $TypeInfo{1}{$PairType_Id}{"Name"})
12440 and find_ParamPair_Pos_byName($PName_Old, $Symbol, 2) eq "lost")
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012441 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040012442 if($PName_Old!~/\Ap\d+\Z/ and $PName!~/\Ap\d+\Z/)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012443 {
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040012444 %{$CompatProblems{$Level}{$Symbol}{"Renamed_Parameter"}{showPos($ParamPos)." Parameter"}}=(
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040012445 "Target"=>$PName_Old,
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012446 "Param_Pos"=>$ParamPos,
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040012447 "Param_Type"=>$PType2_Name,
12448 "Old_Value"=>$PName_Old,
12449 "New_Value"=>$PName,
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012450 "New_Signature"=>get_Signature($Symbol, 2) );
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012451 }
12452 }
12453 else
12454 {
12455 my $ProblemType = "Added_Middle_Parameter";
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040012456 if($PName=~/\Ap\d+\Z/) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012457 $ProblemType = "Added_Middle_Unnamed_Parameter";
12458 }
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040012459 %{$CompatProblems{$Level}{$Symbol}{$ProblemType}{showPos($ParamPos)." Parameter"}}=(
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040012460 "Target"=>$PName,
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012461 "Param_Pos"=>$ParamPos,
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040012462 "Param_Type"=>$PType2_Name,
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012463 "New_Signature"=>get_Signature($Symbol, 2) );
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012464 }
12465 }
12466 }
12467 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012468 foreach my $ParamPos (sort {int($a) <=> int($b)} keys(%{$CompleteSignature{1}{$Symbol}{"Param"}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012469 { # check relevant parameters
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040012470 my $PType1_Id = $CompleteSignature{1}{$Symbol}{"Param"}{$ParamPos}{"type"};
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012471 my $ParamName1 = $CompleteSignature{1}{$Symbol}{"Param"}{$ParamPos}{"name"};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012472 # FIXME: find relevant parameter by name
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012473 if(defined $CompleteSignature{2}{$PSymbol}{"Param"}{$ParamPos})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012474 {
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040012475 my $PType2_Id = $CompleteSignature{2}{$PSymbol}{"Param"}{$ParamPos}{"type"};
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012476 my $ParamName2 = $CompleteSignature{2}{$PSymbol}{"Param"}{$ParamPos}{"name"};
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040012477 if($TypeInfo{1}{$PType1_Id}{"Name"} eq $TypeInfo{2}{$PType2_Id}{"Name"}
12478 or ($ParamName1!~/\Ap\d+\Z/i and $ParamName1 eq $ParamName2)) {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012479 mergeParameters($Symbol, $PSymbol, $ParamPos, $ParamPos, $Level);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012480 }
12481 }
12482 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012483 foreach my $ParamPos (sort {int($a) <=> int($b)} keys(%{$CompleteSignature{1}{$Symbol}{"Param"}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012484 { # checking removed parameters
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040012485 my $PType1_Id = $CompleteSignature{1}{$Symbol}{"Param"}{$ParamPos}{"type"};
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040012486 my $PType1_Name = $TypeInfo{1}{$PType1_Id}{"Name"};
12487 last if($PType1_Name eq "...");
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012488 my $Parameter_Name = $CompleteSignature{1}{$Symbol}{"Param"}{$ParamPos}{"name"};
12489 my $Parameter_NewName = (defined $CompleteSignature{2}{$PSymbol}{"Param"}{$ParamPos})?$CompleteSignature{2}{$PSymbol}{"Param"}{$ParamPos}{"name"}:"";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012490 my $ParamPos_New = "-1";
12491 if($Parameter_Name=~/\Ap\d+\Z/i)
12492 { # removed unnamed parameter ( pN )
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040012493 my @Positions1 = find_ParamPair_Pos_byTypeAndPos($PType1_Name, $ParamPos, "forward", $Symbol, 1);
12494 my @Positions2 = find_ParamPair_Pos_byTypeAndPos($PType1_Name, $ParamPos, "forward", $Symbol, 2);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012495 if($#Positions2==-1 or $#Positions2<$#Positions1) {
12496 $ParamPos_New = "lost";
12497 }
12498 }
12499 else {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012500 $ParamPos_New = find_ParamPair_Pos_byName($Parameter_Name, $Symbol, 2);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012501 }
12502 if($ParamPos_New eq "lost")
12503 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012504 if($ParamPos>keys(%{$CompleteSignature{2}{$PSymbol}{"Param"}})-1)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012505 {
12506 my $ProblemType = "Removed_Parameter";
12507 if($Parameter_Name=~/\Ap\d+\Z/) {
12508 $ProblemType = "Removed_Unnamed_Parameter";
12509 }
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040012510 %{$CompatProblems{$Level}{$Symbol}{$ProblemType}{showPos($ParamPos)." Parameter"}}=(
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012511 "Target"=>$Parameter_Name,
12512 "Param_Pos"=>$ParamPos,
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040012513 "Param_Type"=>$PType1_Name,
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012514 "New_Signature"=>get_Signature($Symbol, 2) );
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012515 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012516 elsif($ParamPos<keys(%{$CompleteSignature{1}{$Symbol}{"Param"}})-1)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012517 {
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +040012518 my %ParamType_Pure = get_PureType($PType1_Id, $TypeInfo{1});
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040012519 my $PairType_Id = $CompleteSignature{2}{$PSymbol}{"Param"}{$ParamPos}{"type"};
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +040012520 my %PairType_Pure = get_PureType($PairType_Id, $TypeInfo{2});
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040012521 if(($ParamType_Pure{"Name"} eq $PairType_Pure{"Name"} or $PType1_Name eq $TypeInfo{2}{$PairType_Id}{"Name"})
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012522 and find_ParamPair_Pos_byName($Parameter_NewName, $Symbol, 1) eq "lost")
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012523 {
12524 if($Parameter_NewName!~/\Ap\d+\Z/ and $Parameter_Name!~/\Ap\d+\Z/)
12525 {
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040012526 %{$CompatProblems{$Level}{$Symbol}{"Renamed_Parameter"}{showPos($ParamPos)." Parameter"}}=(
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012527 "Target"=>$Parameter_Name,
12528 "Param_Pos"=>$ParamPos,
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040012529 "Param_Type"=>$PType1_Name,
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012530 "Old_Value"=>$Parameter_Name,
12531 "New_Value"=>$Parameter_NewName,
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012532 "New_Signature"=>get_Signature($Symbol, 2) );
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012533 }
12534 }
12535 else
12536 {
12537 my $ProblemType = "Removed_Middle_Parameter";
12538 if($Parameter_Name=~/\Ap\d+\Z/) {
12539 $ProblemType = "Removed_Middle_Unnamed_Parameter";
12540 }
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040012541 %{$CompatProblems{$Level}{$Symbol}{$ProblemType}{showPos($ParamPos)." Parameter"}}=(
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012542 "Target"=>$Parameter_Name,
12543 "Param_Pos"=>$ParamPos,
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040012544 "Param_Type"=>$PType1_Name,
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012545 "New_Signature"=>get_Signature($Symbol, 2) );
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012546 }
12547 }
12548 }
12549 }
12550 }
12551 # checking return type
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012552 my $ReturnType1_Id = $CompleteSignature{1}{$Symbol}{"Return"};
12553 my $ReturnType2_Id = $CompleteSignature{2}{$PSymbol}{"Return"};
12554 %SubProblems = detectTypeChange($ReturnType1_Id, $ReturnType2_Id, "Return", $Level);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012555 foreach my $SubProblemType (keys(%SubProblems))
12556 {
12557 my $New_Value = $SubProblems{$SubProblemType}{"New_Value"};
12558 my $Old_Value = $SubProblems{$SubProblemType}{"Old_Value"};
12559 my $NewProblemType = $SubProblemType;
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040012560 my $AddProblemType = undef;
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +040012561
12562 if($SubProblemType eq "Return_Type_And_Size"
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012563 and $CompleteSignature{1}{$Symbol}{"Data"}) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012564 $NewProblemType = "Global_Data_Type_And_Size";
12565 }
12566 elsif($SubProblemType eq "Return_Type")
12567 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012568 if($CompleteSignature{1}{$Symbol}{"Data"})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012569 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012570 if(removedQual($Old_Value, $New_Value, "const"))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012571 { # const -> non-const global data
12572 $NewProblemType = "Global_Data_Became_Non_Const";
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040012573 $AddProblemType = "Global_Data_Type";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012574 }
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040012575 elsif(addedQual($Old_Value, $New_Value, "const"))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012576 { # non-const -> const global data
12577 $NewProblemType = "Global_Data_Became_Const";
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040012578 $AddProblemType = "Global_Data_Type";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012579 }
12580 else {
12581 $NewProblemType = "Global_Data_Type";
12582 }
12583 }
12584 else
12585 {
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040012586 if(addedQual($Old_Value, $New_Value, "const"))
12587 {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012588 $NewProblemType = "Return_Type_Became_Const";
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040012589 $AddProblemType = "Return_Type";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012590 }
12591 }
12592 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012593 elsif($SubProblemType eq "Return_Type_Format")
12594 {
12595 if($CompleteSignature{1}{$Symbol}{"Data"}) {
12596 $NewProblemType = "Global_Data_Type_Format";
12597 }
12598 }
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +040012599 if($Level eq "Binary"
12600 and not $CompleteSignature{1}{$Symbol}{"Data"})
12601 {
12602 my ($Arch1, $Arch2) = (getArch(1), getArch(2));
12603 if($Arch1 eq "unknown" or $Arch2 eq "unknown")
12604 { # if one of the architectures is unknown
12605 # then set other arhitecture to unknown too
12606 ($Arch1, $Arch2) = ("unknown", "unknown");
12607 }
12608 my (%Conv1, %Conv2) = ();
12609 if($UseConv_Real{1} and $UseConv_Real{1})
12610 {
12611 %Conv1 = callingConvention_R_Real($CompleteSignature{1}{$Symbol});
12612 %Conv2 = callingConvention_R_Real($CompleteSignature{2}{$PSymbol});
12613 }
12614 else
12615 {
12616 %Conv1 = callingConvention_R_Model($CompleteSignature{1}{$Symbol}, $TypeInfo{1}, $Arch1, $OStarget, $WORD_SIZE{1});
12617 %Conv2 = callingConvention_R_Model($CompleteSignature{2}{$PSymbol}, $TypeInfo{2}, $Arch2, $OStarget, $WORD_SIZE{2});
12618 }
12619
12620 if($SubProblemType eq "Return_Type_Became_Void")
12621 {
12622 if(keys(%{$CompleteSignature{1}{$Symbol}{"Param"}}))
12623 { # parameters stack has been affected
12624 if($Conv1{"Method"} eq "stack") {
12625 $NewProblemType = "Return_Type_Became_Void_And_Stack_Layout";
12626 }
12627 elsif($Conv1{"Hidden"}) {
12628 $NewProblemType = "Return_Type_Became_Void_And_Register";
12629 }
12630 }
12631 }
12632 elsif($SubProblemType eq "Return_Type_From_Void")
12633 {
12634 if(keys(%{$CompleteSignature{1}{$Symbol}{"Param"}}))
12635 { # parameters stack has been affected
12636 if($Conv2{"Method"} eq "stack") {
12637 $NewProblemType = "Return_Type_From_Void_And_Stack_Layout";
12638 }
12639 elsif($Conv2{"Hidden"}) {
12640 $NewProblemType = "Return_Type_From_Void_And_Register";
12641 }
12642 }
12643 }
12644 elsif($SubProblemType eq "Return_Type"
12645 or $SubProblemType eq "Return_Type_And_Size"
12646 or $SubProblemType eq "Return_Type_Format")
12647 {
12648 if($Conv1{"Method"} ne $Conv2{"Method"})
12649 {
12650 if($Conv1{"Method"} eq "stack")
12651 { # returns in a register instead of a hidden first parameter
12652 $NewProblemType = "Return_Type_From_Stack_To_Register";
12653 }
12654 else {
12655 $NewProblemType = "Return_Type_From_Register_To_Stack";
12656 }
12657 }
12658 else
12659 {
12660 if($Conv1{"Method"} eq "reg")
12661 {
12662 if($Conv1{"Registers"} ne $Conv2{"Registers"})
12663 {
12664 if($Conv1{"Hidden"}) {
12665 $NewProblemType = "Return_Type_And_Register_Was_Hidden_Parameter";
12666 }
12667 elsif($Conv2{"Hidden"}) {
12668 $NewProblemType = "Return_Type_And_Register_Became_Hidden_Parameter";
12669 }
12670 else {
12671 $NewProblemType = "Return_Type_And_Register";
12672 }
12673 }
12674 }
12675 }
12676 }
12677 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012678 @{$CompatProblems{$Level}{$Symbol}{$NewProblemType}{"retval"}}{keys(%{$SubProblems{$SubProblemType}})} = values %{$SubProblems{$SubProblemType}};
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040012679 if(defined $AddProblemType) {
12680 @{$CompatProblems{$Level}{$Symbol}{$AddProblemType}{"retval"}}{keys(%{$SubProblems{$SubProblemType}})} = values %{$SubProblems{$SubProblemType}};
12681 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012682 }
12683 if($ReturnType1_Id and $ReturnType2_Id)
12684 {
12685 @RecurTypes = ();
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040012686 %SubProblems = mergeTypes($ReturnType1_Id, $ReturnType2_Id, $Level);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012687 foreach my $SubProblemType (keys(%SubProblems))
12688 { # add "Global_Data_Size" problem
12689 my $New_Value = $SubProblems{$SubProblemType}{"New_Value"};
12690 my $Old_Value = $SubProblems{$SubProblemType}{"Old_Value"};
12691 if($SubProblemType eq "DataType_Size"
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012692 and $CompleteSignature{1}{$Symbol}{"Data"}
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040012693 and get_PLevel($ReturnType1_Id, 1)==0)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012694 { # add a new problem
12695 %{$SubProblems{"Global_Data_Size"}} = %{$SubProblems{$SubProblemType}};
12696 }
12697 }
12698 foreach my $SubProblemType (keys(%SubProblems))
12699 {
12700 foreach my $SubLocation (keys(%{$SubProblems{$SubProblemType}}))
12701 {
12702 my $NewLocation = ($SubLocation)?"retval->".$SubLocation:"retval";
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012703 %{$CompatProblems{$Level}{$Symbol}{$SubProblemType}{$NewLocation}}=(
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040012704 "Return_Type_Name"=>$TypeInfo{1}{$ReturnType1_Id}{"Name"} );
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012705 @{$CompatProblems{$Level}{$Symbol}{$SubProblemType}{$NewLocation}}{keys(%{$SubProblems{$SubProblemType}{$SubLocation}})} = values %{$SubProblems{$SubProblemType}{$SubLocation}};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012706 if($SubLocation!~/\-\>/) {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040012707 $CompatProblems{$Level}{$Symbol}{$SubProblemType}{$NewLocation}{"Start_Type_Name"} = $TypeInfo{1}{$ReturnType1_Id}{"Name"};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012708 }
12709 }
12710 }
12711 }
12712
12713 # checking object type
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040012714 my $ObjTId1 = $CompleteSignature{1}{$Symbol}{"Class"};
12715 my $ObjTId2 = $CompleteSignature{2}{$PSymbol}{"Class"};
12716 if($ObjTId1 and $ObjTId2
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012717 and not $CompleteSignature{1}{$Symbol}{"Static"})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012718 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040012719 my $ThisPtr1_Id = getTypeIdByName($TypeInfo{1}{$ObjTId1}{"Name"}."*const", 1);
12720 my $ThisPtr2_Id = getTypeIdByName($TypeInfo{2}{$ObjTId2}{"Name"}."*const", 2);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012721 if($ThisPtr1_Id and $ThisPtr2_Id)
12722 {
12723 @RecurTypes = ();
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040012724 %SubProblems = mergeTypes($ThisPtr1_Id, $ThisPtr2_Id, $Level);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012725 foreach my $SubProblemType (keys(%SubProblems))
12726 {
12727 foreach my $SubLocation (keys(%{$SubProblems{$SubProblemType}}))
12728 {
12729 my $NewLocation = ($SubLocation)?"this->".$SubLocation:"this";
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012730 %{$CompatProblems{$Level}{$Symbol}{$SubProblemType}{$NewLocation}}=(
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040012731 "Object_Type_Name"=>$TypeInfo{1}{$ObjTId1}{"Name"} );
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012732 @{$CompatProblems{$Level}{$Symbol}{$SubProblemType}{$NewLocation}}{keys(%{$SubProblems{$SubProblemType}{$SubLocation}})} = values %{$SubProblems{$SubProblemType}{$SubLocation}};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012733 if($SubLocation!~/\-\>/) {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040012734 $CompatProblems{$Level}{$Symbol}{$SubProblemType}{$NewLocation}{"Start_Type_Name"} = $TypeInfo{1}{$ObjTId1}{"Name"};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012735 }
12736 }
12737 }
12738 }
12739 }
12740 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012741 if($Level eq "Binary") {
12742 mergeVTables($Level);
12743 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +040012744 foreach my $Symbol (keys(%{$CompatProblems{$Level}})) {
12745 $CheckedSymbols{$Level}{$Symbol} = 1;
12746 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012747}
12748
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040012749sub rmQuals($$)
12750{
12751 my ($Value, $Qual) = @_;
12752 if(not $Qual) {
12753 return $Value;
12754 }
12755 if($Qual eq "all")
12756 { # all quals
12757 $Qual = "const|volatile|restrict";
12758 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040012759 while($Value=~s/\b$Qual\b//) {
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040012760 $Value = formatName($Value, "T");
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040012761 }
12762 return $Value;
12763}
12764
12765sub cmpBTypes($$$$)
12766{
12767 my ($T1, $T2, $V1, $V2) = @_;
12768 $T1 = uncover_typedefs($T1, $V1);
12769 $T2 = uncover_typedefs($T2, $V2);
12770 return (rmQuals($T1, "all") eq rmQuals($T2, "all"));
12771}
12772
12773sub addedQual($$$)
12774{
12775 my ($Old_Value, $New_Value, $Qual) = @_;
Andrey Ponomarenko85043792012-05-14 16:48:07 +040012776 return removedQual_($New_Value, $Old_Value, 2, 1, $Qual);
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040012777}
12778
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012779sub removedQual($$$)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012780{
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012781 my ($Old_Value, $New_Value, $Qual) = @_;
Andrey Ponomarenko85043792012-05-14 16:48:07 +040012782 return removedQual_($Old_Value, $New_Value, 1, 2, $Qual);
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040012783}
12784
12785sub removedQual_($$$$$)
12786{
12787 my ($Old_Value, $New_Value, $V1, $V2, $Qual) = @_;
12788 $Old_Value = uncover_typedefs($Old_Value, $V1);
12789 $New_Value = uncover_typedefs($New_Value, $V2);
12790 if($Old_Value eq $New_Value)
12791 { # equal types
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012792 return 0;
12793 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040012794 if($Old_Value!~/\b$Qual\b/)
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040012795 { # without a qual
12796 return 0;
12797 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040012798 elsif($New_Value!~/\b$Qual\b/)
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040012799 { # became non-qual
12800 return 1;
12801 }
12802 else
12803 {
12804 my @BQ1 = getQualModel($Old_Value, $Qual);
12805 my @BQ2 = getQualModel($New_Value, $Qual);
12806 foreach (0 .. $#BQ1)
12807 { # removed qual
12808 if($BQ1[$_]==1
12809 and $BQ2[$_]!=1)
12810 {
12811 return 2;
12812 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012813 }
12814 }
12815 return 0;
12816}
12817
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040012818sub getQualModel($$)
12819{
12820 my ($Value, $Qual) = @_;
12821 if(not $Qual) {
12822 return $Value;
12823 }
12824
12825 # cleaning
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040012826 while($Value=~/(\w+)/ and $1 ne $Qual) {
12827 $Value=~s/\b$1\b//g;
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040012828 }
12829 $Value=~s/[^\*\&\w]+//g;
12830
12831 # modeling
12832 # int*const*const == 011
12833 # int**const == 001
12834 my @Model = ();
12835 my @Elems = split(/[\*\&]/, $Value);
12836 if(not @Elems) {
12837 return (0);
12838 }
12839 foreach (@Elems)
12840 {
12841 if($_ eq $Qual) {
12842 push(@Model, 1);
12843 }
12844 else {
12845 push(@Model, 0);
12846 }
12847 }
12848
12849 return @Model;
12850}
12851
12852sub showVal($$$)
12853{
12854 my ($Value, $TypeId, $LibVersion) = @_;
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +040012855 my %PureType = get_PureType($TypeId, $TypeInfo{$LibVersion});
Andrey Ponomarenkoa01311b2012-06-08 17:20:02 +040012856 my $TName = uncover_typedefs($PureType{"Name"}, $LibVersion);
Andrey Ponomarenko01117f12012-06-26 12:23:02 +040012857 if(substr($Value, 0, 2) eq "_Z")
12858 {
12859 if(my $Unmangled = $tr_name{$Value}) {
12860 return $Unmangled;
12861 }
12862 }
Andrey Ponomarenko07aea072012-11-12 16:15:07 +040012863 elsif($TName=~/\A(char(| const)\*|std::(string(| const)|basic_string<char>(|const))(|&))\Z/)
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040012864 { # strings
12865 return "\"$Value\"";
12866 }
Andrey Ponomarenkoa01311b2012-06-08 17:20:02 +040012867 elsif($TName=~/\Achar(| const)\Z/)
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040012868 { # characters
12869 return "\'$Value\'";
12870 }
12871 return $Value;
12872}
12873
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012874sub mergeParameters($$$$$)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012875{
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012876 my ($Symbol, $PSymbol, $ParamPos1, $ParamPos2, $Level) = @_;
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040012877 if(not $Symbol) {
12878 return;
12879 }
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040012880 my $PType1_Id = $CompleteSignature{1}{$Symbol}{"Param"}{$ParamPos1}{"type"};
12881 my $PName1 = $CompleteSignature{1}{$Symbol}{"Param"}{$ParamPos1}{"name"};
12882 my $PType2_Id = $CompleteSignature{2}{$PSymbol}{"Param"}{$ParamPos2}{"type"};
12883 my $PName2 = $CompleteSignature{2}{$PSymbol}{"Param"}{$ParamPos2}{"name"};
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040012884 if(not $PType1_Id
12885 or not $PType2_Id) {
12886 return;
12887 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040012888 my %Type1 = get_Type($PType1_Id, 1);
12889 my %Type2 = get_Type($PType2_Id, 2);
12890 my %BaseType1 = get_BaseType($PType1_Id, 1);
12891 my %BaseType2 = get_BaseType($PType2_Id, 2);
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040012892 my $Parameter_Location = ($PName1)?$PName1:showPos($ParamPos1)." Parameter";
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012893 if($Level eq "Binary")
12894 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040012895 if(checkDump(1, "2.6.1") and checkDump(2, "2.6.1"))
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012896 { # "reg" attribute added in ACC 1.95.1 (dump 2.6.1 format)
12897 if($CompleteSignature{1}{$Symbol}{"Param"}{$ParamPos1}{"reg"}
12898 and not $CompleteSignature{2}{$PSymbol}{"Param"}{$ParamPos2}{"reg"})
12899 {
12900 %{$CompatProblems{$Level}{$Symbol}{"Parameter_Became_Non_Register"}{$Parameter_Location}}=(
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040012901 "Target"=>$PName1,
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012902 "Param_Pos"=>$ParamPos1 );
12903 }
12904 elsif(not $CompleteSignature{1}{$Symbol}{"Param"}{$ParamPos1}{"reg"}
12905 and $CompleteSignature{2}{$PSymbol}{"Param"}{$ParamPos2}{"reg"})
12906 {
12907 %{$CompatProblems{$Level}{$Symbol}{"Parameter_Became_Register"}{$Parameter_Location}}=(
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040012908 "Target"=>$PName1,
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012909 "Param_Pos"=>$ParamPos1 );
12910 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012911 }
12912 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040012913 if(checkDump(1, "2.0") and checkDump(2, "2.0"))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012914 { # "default" attribute added in ACC 1.22 (dump 2.0 format)
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040012915 my $Value_Old = $CompleteSignature{1}{$Symbol}{"Param"}{$ParamPos1}{"default"};
12916 my $Value_New = $CompleteSignature{2}{$PSymbol}{"Param"}{$ParamPos2}{"default"};
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040012917 if(not checkDump(1, "2.13")
12918 and checkDump(2, "2.13"))
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040012919 { # support for old ABI dumps
12920 if(defined $Value_Old and defined $Value_New)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012921 {
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040012922 if($Type1{"Name"} eq "bool"
12923 and $Value_Old eq "false" and $Value_New eq "0")
12924 { # int class::method ( bool p = 0 );
12925 # old ABI dumps: "false"
12926 # new ABI dumps: "0"
12927 $Value_Old = "0";
12928 }
12929 }
12930 }
Andrey Ponomarenko01117f12012-06-26 12:23:02 +040012931 if(not checkDump(1, "2.18")
12932 and checkDump(2, "2.18"))
12933 { # support for old ABI dumps
12934 if(not defined $Value_Old
12935 and substr($Value_New, 0, 2) eq "_Z") {
12936 $Value_Old = $Value_New;
12937 }
12938 }
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040012939 if(defined $Value_Old)
12940 {
12941 $Value_Old = showVal($Value_Old, $PType1_Id, 1);
12942 if(defined $Value_New)
12943 {
12944 $Value_New = showVal($Value_New, $PType2_Id, 2);
12945 if($Value_Old ne $Value_New)
12946 { # FIXME: how to distinguish "0" and 0 (NULL)
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012947 %{$CompatProblems{$Level}{$Symbol}{"Parameter_Default_Value_Changed"}{$Parameter_Location}}=(
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040012948 "Target"=>$PName1,
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012949 "Param_Pos"=>$ParamPos1,
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040012950 "Old_Value"=>$Value_Old,
12951 "New_Value"=>$Value_New );
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012952 }
12953 }
12954 else
12955 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012956 %{$CompatProblems{$Level}{$Symbol}{"Parameter_Default_Value_Removed"}{$Parameter_Location}}=(
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040012957 "Target"=>$PName1,
12958 "Param_Pos"=>$ParamPos1,
12959 "Old_Value"=>$Value_Old );
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012960 }
12961 }
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040012962 elsif(defined $Value_New)
12963 {
12964 $Value_New = showVal($Value_New, $PType2_Id, 2);
12965 %{$CompatProblems{$Level}{$Symbol}{"Parameter_Default_Value_Added"}{$Parameter_Location}}=(
12966 "Target"=>$PName1,
12967 "Param_Pos"=>$ParamPos1,
12968 "New_Value"=>$Value_New );
12969 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012970 }
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040012971 if($PName1 and $PName2 and $PName1 ne $PName2
12972 and $PType1_Id!=-1 and $PType2_Id!=-1
12973 and $PName1!~/\Ap\d+\Z/ and $PName2!~/\Ap\d+\Z/)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012974 { # except unnamed "..." value list (Id=-1)
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040012975 %{$CompatProblems{$Level}{$Symbol}{"Renamed_Parameter"}{showPos($ParamPos1)." Parameter"}}=(
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040012976 "Target"=>$PName1,
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012977 "Param_Pos"=>$ParamPos1,
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040012978 "Param_Type"=>$TypeInfo{1}{$PType1_Id}{"Name"},
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040012979 "Old_Value"=>$PName1,
12980 "New_Value"=>$PName2,
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012981 "New_Signature"=>get_Signature($Symbol, 2) );
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012982 }
12983 # checking type change (replace)
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040012984 my %SubProblems = detectTypeChange($PType1_Id, $PType2_Id, "Parameter", $Level);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012985 foreach my $SubProblemType (keys(%SubProblems))
12986 { # add new problems, remove false alarms
12987 my $New_Value = $SubProblems{$SubProblemType}{"New_Value"};
12988 my $Old_Value = $SubProblems{$SubProblemType}{"Old_Value"};
12989 if($SubProblemType eq "Parameter_Type")
12990 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040012991 if(checkDump(1, "2.6") and checkDump(2, "2.6"))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012992 {
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040012993 if(my $RA = addedQual($Old_Value, $New_Value, "restrict"))
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012994 {
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040012995 %{$SubProblems{"Parameter_Became_Restrict"}} = %{$SubProblems{$SubProblemType}};
12996 if($Level eq "Source"
12997 and cmpBTypes($Old_Value, $New_Value, 1, 2)) {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012998 delete($SubProblems{$SubProblemType});
12999 }
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040013000 }
13001 elsif(my $RR = removedQual($Old_Value, $New_Value, "restrict"))
13002 {
13003 %{$SubProblems{"Parameter_Became_NonRestrict"}} = %{$SubProblems{$SubProblemType}};
13004 if($Level eq "Source"
13005 and cmpBTypes($Old_Value, $New_Value, 1, 2)) {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040013006 delete($SubProblems{$SubProblemType});
13007 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013008 }
13009 }
13010 if($Type2{"Type"} eq "Const" and $BaseType2{"Name"} eq $Type1{"Name"}
13011 and $Type1{"Type"}=~/Intrinsic|Class|Struct|Union|Enum/)
13012 { # int to "int const"
13013 delete($SubProblems{$SubProblemType});
13014 }
13015 if($Type1{"Type"} eq "Const" and $BaseType1{"Name"} eq $Type2{"Name"}
13016 and $Type2{"Type"}=~/Intrinsic|Class|Struct|Union|Enum/)
13017 { # "int const" to int
13018 delete($SubProblems{$SubProblemType});
13019 }
13020 }
13021 }
13022 foreach my $SubProblemType (keys(%SubProblems))
13023 { # modify/register problems
13024 my $New_Value = $SubProblems{$SubProblemType}{"New_Value"};
13025 my $Old_Value = $SubProblems{$SubProblemType}{"Old_Value"};
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +040013026 my $New_Size = $SubProblems{$SubProblemType}{"New_Size"};
13027 my $Old_Size = $SubProblems{$SubProblemType}{"Old_Size"};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013028 my $NewProblemType = $SubProblemType;
13029 if($Old_Value eq "..." and $New_Value ne "...")
13030 { # change from "..." to "int"
13031 if($ParamPos1==0)
13032 { # ISO C requires a named argument before "..."
13033 next;
13034 }
13035 $NewProblemType = "Parameter_Became_NonVaList";
13036 }
13037 elsif($New_Value eq "..." and $Old_Value ne "...")
13038 { # change from "int" to "..."
13039 if($ParamPos2==0)
13040 { # ISO C requires a named argument before "..."
13041 next;
13042 }
13043 $NewProblemType = "Parameter_Became_VaList";
13044 }
13045 elsif($SubProblemType eq "Parameter_Type"
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040013046 and removedQual($Old_Value, $New_Value, "const"))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013047 { # parameter: "const" to non-"const"
13048 $NewProblemType = "Parameter_Became_Non_Const";
13049 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040013050 elsif($Level eq "Binary" and ($SubProblemType eq "Parameter_Type_And_Size"
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +040013051 or $SubProblemType eq "Parameter_Type" or $SubProblemType eq "Parameter_Type_Format"))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013052 {
13053 my ($Arch1, $Arch2) = (getArch(1), getArch(2));
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +040013054 if($Arch1 eq "unknown"
13055 or $Arch2 eq "unknown")
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013056 { # if one of the architectures is unknown
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +040013057 # then set other arhitecture to unknown too
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013058 ($Arch1, $Arch2) = ("unknown", "unknown");
13059 }
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +040013060 my (%Conv1, %Conv2) = ();
13061 if($UseConv_Real{1} and $UseConv_Real{1})
13062 { # real
13063 %Conv1 = callingConvention_P_Real($CompleteSignature{1}{$Symbol}, $ParamPos1);
13064 %Conv2 = callingConvention_P_Real($CompleteSignature{2}{$Symbol}, $ParamPos2);
13065 }
13066 else
13067 { # model
13068 %Conv1 = callingConvention_P_Model($CompleteSignature{1}{$Symbol}, $ParamPos1, $TypeInfo{1}, $Arch1, $OStarget, $WORD_SIZE{1});
13069 %Conv2 = callingConvention_P_Model($CompleteSignature{2}{$Symbol}, $ParamPos2, $TypeInfo{2}, $Arch2, $OStarget, $WORD_SIZE{2});
13070 }
13071 if($Conv1{"Method"} eq $Conv2{"Method"})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013072 {
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +040013073 if($Conv1{"Method"} eq "stack")
13074 {
13075 if($Old_Size ne $New_Size) { # FIXME: isMemPadded, getOffset
13076 $NewProblemType = "Parameter_Type_And_Stack";
13077 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013078 }
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +040013079 elsif($Conv1{"Method"} eq "reg")
13080 {
13081 if($Conv1{"Registers"} ne $Conv2{"Registers"}) {
13082 $NewProblemType = "Parameter_Type_And_Register";
13083 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013084 }
13085 }
13086 else
13087 {
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +040013088 if($Conv1{"Method"} eq "stack") {
13089 $NewProblemType = "Parameter_Type_From_Stack_To_Register";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013090 }
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +040013091 elsif($Conv1{"Method"} eq "register") {
13092 $NewProblemType = "Parameter_Type_From_Register_To_Stack";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013093 }
13094 }
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +040013095 $SubProblems{$SubProblemType}{"Old_Reg"} = $Conv1{"Registers"};
13096 $SubProblems{$SubProblemType}{"New_Reg"} = $Conv2{"Registers"};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013097 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040013098 %{$CompatProblems{$Level}{$Symbol}{$NewProblemType}{$Parameter_Location}}=(
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040013099 "Target"=>$PName1,
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013100 "Param_Pos"=>$ParamPos1,
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040013101 "New_Signature"=>get_Signature($Symbol, 2) );
13102 @{$CompatProblems{$Level}{$Symbol}{$NewProblemType}{$Parameter_Location}}{keys(%{$SubProblems{$SubProblemType}})} = values %{$SubProblems{$SubProblemType}};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013103 }
13104 @RecurTypes = ();
13105 # checking type definition changes
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040013106 my %SubProblems_Merge = mergeTypes($PType1_Id, $PType2_Id, $Level);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013107 foreach my $SubProblemType (keys(%SubProblems_Merge))
13108 {
13109 foreach my $SubLocation (keys(%{$SubProblems_Merge{$SubProblemType}}))
13110 {
13111 my $NewProblemType = $SubProblemType;
13112 if($SubProblemType eq "DataType_Size")
13113 {
13114 my $InitialType_Type = $SubProblems_Merge{$SubProblemType}{$SubLocation}{"InitialType_Type"};
13115 if($InitialType_Type!~/\A(Pointer|Ref)\Z/ and $SubLocation!~/\-\>/)
13116 { # stack has been affected
13117 $NewProblemType = "DataType_Size_And_Stack";
13118 }
13119 }
13120 my $NewLocation = ($SubLocation)?$Parameter_Location."->".$SubLocation:$Parameter_Location;
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040013121 %{$CompatProblems{$Level}{$Symbol}{$NewProblemType}{$NewLocation}}=(
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040013122 "Param_Type"=>$TypeInfo{1}{$PType1_Id}{"Name"},
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013123 "Param_Pos"=>$ParamPos1,
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040013124 "Param_Name"=>$PName1 );
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040013125 @{$CompatProblems{$Level}{$Symbol}{$NewProblemType}{$NewLocation}}{keys(%{$SubProblems_Merge{$SubProblemType}{$SubLocation}})} = values %{$SubProblems_Merge{$SubProblemType}{$SubLocation}};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013126 if($SubLocation!~/\-\>/) {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040013127 $CompatProblems{$Level}{$Symbol}{$NewProblemType}{$NewLocation}{"Start_Type_Name"} = $TypeInfo{1}{$PType1_Id}{"Name"};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013128 }
13129 }
13130 }
13131}
13132
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013133sub find_ParamPair_Pos_byName($$$)
13134{
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040013135 my ($Name, $Symbol, $LibVersion) = @_;
13136 foreach my $ParamPos (sort {int($a)<=>int($b)} keys(%{$CompleteSignature{$LibVersion}{$Symbol}{"Param"}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013137 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040013138 next if(not defined $CompleteSignature{$LibVersion}{$Symbol}{"Param"}{$ParamPos});
13139 if($CompleteSignature{$LibVersion}{$Symbol}{"Param"}{$ParamPos}{"name"} eq $Name)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013140 {
13141 return $ParamPos;
13142 }
13143 }
13144 return "lost";
13145}
13146
13147sub find_ParamPair_Pos_byTypeAndPos($$$$$)
13148{
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040013149 my ($TypeName, $MediumPos, $Order, $Symbol, $LibVersion) = @_;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013150 my @Positions = ();
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040013151 foreach my $ParamPos (sort {int($a)<=>int($b)} keys(%{$CompleteSignature{$LibVersion}{$Symbol}{"Param"}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013152 {
13153 next if($Order eq "backward" and $ParamPos>$MediumPos);
13154 next if($Order eq "forward" and $ParamPos<$MediumPos);
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040013155 next if(not defined $CompleteSignature{$LibVersion}{$Symbol}{"Param"}{$ParamPos});
13156 my $PTypeId = $CompleteSignature{$LibVersion}{$Symbol}{"Param"}{$ParamPos}{"type"};
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040013157 if($TypeInfo{$LibVersion}{$PTypeId}{"Name"} eq $TypeName) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013158 push(@Positions, $ParamPos);
13159 }
13160 }
13161 return @Positions;
13162}
13163
13164sub getTypeIdByName($$)
13165{
13166 my ($TypeName, $Version) = @_;
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040013167 return $TName_Tid{$Version}{formatName($TypeName, "T")};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013168}
13169
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040013170sub checkFormatChange($$$)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013171{
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040013172 my ($Type1_Id, $Type2_Id, $Level) = @_;
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +040013173 my %Type1_Pure = get_PureType($Type1_Id, $TypeInfo{1});
13174 my %Type2_Pure = get_PureType($Type2_Id, $TypeInfo{2});
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013175 if($Type1_Pure{"Name"} eq $Type2_Pure{"Name"})
13176 { # equal types
13177 return 0;
13178 }
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040013179 if($Type1_Pure{"Name"} eq "void")
13180 { # from void* to something
13181 return 0;
13182 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013183 if($Type1_Pure{"Name"}=~/\*/
13184 or $Type2_Pure{"Name"}=~/\*/)
13185 { # compared in detectTypeChange()
13186 return 0;
13187 }
13188 my %FloatType = map {$_=>1} (
13189 "float",
13190 "double",
13191 "long double"
13192 );
13193 if($Type1_Pure{"Type"} ne $Type2_Pure{"Type"})
13194 { # different types
13195 if($Type1_Pure{"Type"} eq "Intrinsic"
13196 and $Type2_Pure{"Type"} eq "Enum")
13197 { # "int" to "enum"
13198 return 0;
13199 }
13200 elsif($Type2_Pure{"Type"} eq "Intrinsic"
13201 and $Type1_Pure{"Type"} eq "Enum")
13202 { # "enum" to "int"
13203 return 0;
13204 }
13205 else
13206 { # "union" to "struct"
13207 # ...
13208 return 1;
13209 }
13210 }
13211 else
13212 {
13213 if($Type1_Pure{"Type"} eq "Intrinsic")
13214 {
13215 if($FloatType{$Type1_Pure{"Name"}}
13216 or $FloatType{$Type2_Pure{"Name"}})
13217 { # "float" to "double"
13218 # "float" to "int"
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040013219 if($Level eq "Source")
13220 { # Safe
13221 return 0;
13222 }
13223 else {
13224 return 1;
13225 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013226 }
13227 }
13228 elsif($Type1_Pure{"Type"}=~/Class|Struct|Union|Enum/)
13229 {
13230 my @Membs1 = keys(%{$Type1_Pure{"Memb"}});
13231 my @Membs2 = keys(%{$Type2_Pure{"Memb"}});
13232 if($#Membs1!=$#Membs2)
13233 { # different number of elements
13234 return 1;
13235 }
13236 if($Type1_Pure{"Type"} eq "Enum")
13237 {
13238 foreach my $Pos (@Membs1)
13239 { # compare elements by name and value
13240 if($Type1_Pure{"Memb"}{$Pos}{"name"} ne $Type2_Pure{"Memb"}{$Pos}{"name"}
13241 or $Type1_Pure{"Memb"}{$Pos}{"value"} ne $Type2_Pure{"Memb"}{$Pos}{"value"})
13242 { # different names
13243 return 1;
13244 }
13245 }
13246 }
13247 else
13248 {
13249 foreach my $Pos (@Membs1)
13250 { # compare elements by type name
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040013251 my $MT1 = $TypeInfo{1}{$Type1_Pure{"Memb"}{$Pos}{"type"}}{"Name"};
13252 my $MT2 = $TypeInfo{2}{$Type2_Pure{"Memb"}{$Pos}{"type"}}{"Name"};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013253 if($MT1 ne $MT2)
13254 { # different types
13255 return 1;
13256 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040013257 if($Level eq "Source")
13258 {
13259 if($Type1_Pure{"Memb"}{$Pos}{"name"} ne $Type2_Pure{"Memb"}{$Pos}{"name"})
13260 { # different names
13261 return 1;
13262 }
13263 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013264 }
13265 }
13266 }
13267 }
13268 return 0;
13269}
13270
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040013271sub detectTypeChange($$$$)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013272{
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040013273 my ($Type1_Id, $Type2_Id, $Prefix, $Level) = @_;
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040013274 if(not $Type1_Id or not $Type2_Id) {
13275 return ();
13276 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013277 my %LocalProblems = ();
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040013278 my %Type1 = get_Type($Type1_Id, 1);
13279 my %Type2 = get_Type($Type2_Id, 2);
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +040013280 my %Type1_Pure = get_PureType($Type1_Id, $TypeInfo{1});
13281 my %Type2_Pure = get_PureType($Type2_Id, $TypeInfo{2});
13282 my %Type1_Base = ($Type1_Pure{"Type"} eq "Array")?get_OneStep_BaseType($Type1_Pure{"Tid"}, $TypeInfo{1}):get_BaseType($Type1_Id, 1);
13283 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 +040013284 my $Type1_PLevel = get_PLevel($Type1_Id, 1);
13285 my $Type2_PLevel = get_PLevel($Type2_Id, 2);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013286 return () if(not $Type1{"Name"} or not $Type2{"Name"});
13287 return () if(not $Type1_Base{"Name"} or not $Type2_Base{"Name"});
13288 return () if($Type1_PLevel eq "" or $Type2_PLevel eq "");
13289 if($Type1_Base{"Name"} ne $Type2_Base{"Name"}
13290 and ($Type1{"Name"} eq $Type2{"Name"} or ($Type1_PLevel>=1 and $Type1_PLevel==$Type2_PLevel
13291 and $Type1_Base{"Name"} ne "void" and $Type2_Base{"Name"} ne "void")))
13292 { # base type change
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040013293 if($Type1{"Name"} eq $Type2{"Name"})
13294 {
13295 if($Type1{"Type"} eq "Typedef" and $Type2{"Type"} eq "Typedef")
13296 { # will be reported in mergeTypes() as typedef problem
13297 return ();
13298 }
13299 my %Typedef_1 = goToFirst($Type1{"Tid"}, 1, "Typedef");
13300 my %Typedef_2 = goToFirst($Type2{"Tid"}, 2, "Typedef");
13301 if(%Typedef_1 and %Typedef_2)
13302 {
13303 if($Typedef_1{"Name"} eq $Typedef_2{"Name"}
13304 and $Typedef_1{"Type"} eq "Typedef" and $Typedef_2{"Type"} eq "Typedef")
13305 { # const Typedef
13306 return ();
13307 }
13308 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013309 }
13310 if($Type1_Base{"Name"}!~/anon\-/ and $Type2_Base{"Name"}!~/anon\-/)
13311 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040013312 if($Level eq "Binary"
13313 and $Type1_Base{"Size"} ne $Type2_Base{"Size"}
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013314 and $Type1_Base{"Size"} and $Type2_Base{"Size"})
13315 {
13316 %{$LocalProblems{$Prefix."_BaseType_And_Size"}}=(
13317 "Old_Value"=>$Type1_Base{"Name"},
13318 "New_Value"=>$Type2_Base{"Name"},
13319 "Old_Size"=>$Type1_Base{"Size"}*$BYTE_SIZE,
13320 "New_Size"=>$Type2_Base{"Size"}*$BYTE_SIZE,
13321 "InitialType_Type"=>$Type1_Pure{"Type"});
13322 }
13323 else
13324 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040013325 if(checkFormatChange($Type1_Base{"Tid"}, $Type2_Base{"Tid"}, $Level))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013326 { # format change
13327 %{$LocalProblems{$Prefix."_BaseType_Format"}}=(
13328 "Old_Value"=>$Type1_Base{"Name"},
13329 "New_Value"=>$Type2_Base{"Name"},
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +040013330 "Old_Size"=>$Type1_Base{"Size"}*$BYTE_SIZE,
13331 "New_Size"=>$Type2_Base{"Size"}*$BYTE_SIZE,
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013332 "InitialType_Type"=>$Type1_Pure{"Type"});
13333 }
13334 elsif(tNameLock($Type1_Base{"Tid"}, $Type2_Base{"Tid"}))
13335 {
13336 %{$LocalProblems{$Prefix."_BaseType"}}=(
13337 "Old_Value"=>$Type1_Base{"Name"},
13338 "New_Value"=>$Type2_Base{"Name"},
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +040013339 "Old_Size"=>$Type1_Base{"Size"}*$BYTE_SIZE,
13340 "New_Size"=>$Type2_Base{"Size"}*$BYTE_SIZE,
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013341 "InitialType_Type"=>$Type1_Pure{"Type"});
13342 }
13343 }
13344 }
13345 }
13346 elsif($Type1{"Name"} ne $Type2{"Name"})
13347 { # type change
13348 if($Type1{"Name"}!~/anon\-/ and $Type2{"Name"}!~/anon\-/)
13349 {
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +040013350 if($Prefix eq "Return"
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013351 and $Type1_Pure{"Name"} eq "void")
13352 {
13353 %{$LocalProblems{"Return_Type_From_Void"}}=(
13354 "New_Value"=>$Type2{"Name"},
13355 "New_Size"=>$Type2{"Size"}*$BYTE_SIZE,
13356 "InitialType_Type"=>$Type1_Pure{"Type"});
13357 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013358 elsif($Prefix eq "Return"
13359 and $Type2_Pure{"Name"} eq "void")
13360 {
13361 %{$LocalProblems{"Return_Type_Became_Void"}}=(
13362 "Old_Value"=>$Type1{"Name"},
13363 "Old_Size"=>$Type1{"Size"}*$BYTE_SIZE,
13364 "InitialType_Type"=>$Type1_Pure{"Type"});
13365 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013366 else
13367 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040013368 if($Level eq "Binary"
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040013369 and $Type1{"Size"} and $Type2{"Size"}
13370 and $Type1{"Size"} ne $Type2{"Size"})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013371 {
13372 %{$LocalProblems{$Prefix."_Type_And_Size"}}=(
13373 "Old_Value"=>$Type1{"Name"},
13374 "New_Value"=>$Type2{"Name"},
13375 "Old_Size"=>$Type1{"Size"}*$BYTE_SIZE,
13376 "New_Size"=>$Type2{"Size"}*$BYTE_SIZE,
13377 "InitialType_Type"=>$Type1_Pure{"Type"});
13378 }
13379 else
13380 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040013381 if(checkFormatChange($Type1_Id, $Type2_Id, $Level))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013382 { # format change
13383 %{$LocalProblems{$Prefix."_Type_Format"}}=(
13384 "Old_Value"=>$Type1{"Name"},
13385 "New_Value"=>$Type2{"Name"},
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +040013386 "Old_Size"=>$Type1{"Size"}*$BYTE_SIZE,
13387 "New_Size"=>$Type2{"Size"}*$BYTE_SIZE,
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013388 "InitialType_Type"=>$Type1_Pure{"Type"});
13389 }
13390 elsif(tNameLock($Type1_Id, $Type2_Id))
13391 { # FIXME: correct this condition
13392 %{$LocalProblems{$Prefix."_Type"}}=(
13393 "Old_Value"=>$Type1{"Name"},
13394 "New_Value"=>$Type2{"Name"},
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +040013395 "Old_Size"=>$Type1{"Size"}*$BYTE_SIZE,
13396 "New_Size"=>$Type2{"Size"}*$BYTE_SIZE,
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013397 "InitialType_Type"=>$Type1_Pure{"Type"});
13398 }
13399 }
13400 }
13401 }
13402 }
13403 if($Type1_PLevel!=$Type2_PLevel)
13404 {
13405 if($Type1{"Name"} ne "void" and $Type1{"Name"} ne "..."
13406 and $Type2{"Name"} ne "void" and $Type2{"Name"} ne "...")
13407 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040013408 if($Level eq "Source")
13409 {
13410 %{$LocalProblems{$Prefix."_PointerLevel"}}=(
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013411 "Old_Value"=>$Type1_PLevel,
13412 "New_Value"=>$Type2_PLevel);
13413 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040013414 else
13415 {
13416 if($Type2_PLevel>$Type1_PLevel) {
13417 %{$LocalProblems{$Prefix."_PointerLevel_Increased"}}=(
13418 "Old_Value"=>$Type1_PLevel,
13419 "New_Value"=>$Type2_PLevel);
13420 }
13421 else {
13422 %{$LocalProblems{$Prefix."_PointerLevel_Decreased"}}=(
13423 "Old_Value"=>$Type1_PLevel,
13424 "New_Value"=>$Type2_PLevel);
13425 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013426 }
13427 }
13428 }
13429 if($Type1_Pure{"Type"} eq "Array")
13430 { # base_type[N] -> base_type[N]
13431 # base_type: older_structure -> typedef to newer_structure
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040013432 my %SubProblems = detectTypeChange($Type1_Base{"Tid"}, $Type2_Base{"Tid"}, $Prefix, $Level);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013433 foreach my $SubProblemType (keys(%SubProblems))
13434 {
13435 $SubProblemType=~s/_Type/_BaseType/g;
13436 next if(defined $LocalProblems{$SubProblemType});
13437 foreach my $Attr (keys(%{$SubProblems{$SubProblemType}})) {
13438 $LocalProblems{$SubProblemType}{$Attr} = $SubProblems{$SubProblemType}{$Attr};
13439 }
13440 }
13441 }
13442 return %LocalProblems;
13443}
13444
13445sub tNameLock($$)
13446{
13447 my ($Tid1, $Tid2) = @_;
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040013448 my $Changed = 0;
13449 if(differentDumps("G"))
13450 { # different GCC versions
13451 $Changed = 1;
13452 }
13453 elsif(differentDumps("V"))
13454 { # different versions of ABI dumps
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040013455 if(not checkDump(1, "2.13")
13456 or not checkDump(2, "2.13"))
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040013457 { # latest names update
13458 # 2.6: added restrict qualifier
13459 # 2.13: added missed typedefs to qualified types
13460 $Changed = 1;
13461 }
13462 }
13463 if($Changed)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013464 { # different formats
13465 if($UseOldDumps)
13466 { # old dumps
13467 return 0;
13468 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040013469 my $TN1 = $TypeInfo{1}{$Tid1}{"Name"};
13470 my $TN2 = $TypeInfo{2}{$Tid2}{"Name"};
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040013471
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040013472 my $TT1 = $TypeInfo{1}{$Tid1}{"Type"};
13473 my $TT2 = $TypeInfo{2}{$Tid2}{"Type"};
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040013474
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040013475 my %Base1 = get_Type($Tid1, 1);
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040013476 while(defined $Base1{"Type"} and $Base1{"Type"} eq "Typedef") {
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +040013477 %Base1 = get_OneStep_BaseType($Base1{"Tid"}, $TypeInfo{1});
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013478 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040013479 my %Base2 = get_Type($Tid2, 2);
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040013480 while(defined $Base2{"Type"} and $Base2{"Type"} eq "Typedef") {
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +040013481 %Base2 = get_OneStep_BaseType($Base2{"Tid"}, $TypeInfo{2});
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013482 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +040013483 my $BName1 = uncover_typedefs($Base1{"Name"}, 1);
13484 my $BName2 = uncover_typedefs($Base2{"Name"}, 2);
13485 if($BName1 eq $BName2)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013486 { # equal base types
13487 return 0;
13488 }
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040013489
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040013490 if(not checkDump(1, "2.13")
13491 or not checkDump(2, "2.13"))
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040013492 { # broken array names in ABI dumps < 2.13
13493 if($TT1 eq "Array"
13494 and $TT2 eq "Array")
13495 {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013496 return 0;
13497 }
13498 }
13499
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040013500 if(not checkDump(1, "2.6")
13501 or not checkDump(2, "2.6"))
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040013502 { # added restrict attribute in 2.6
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040013503 if($TN1!~/\brestrict\b/
13504 and $TN2=~/\brestrict\b/)
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040013505 {
13506 return 0;
13507 }
13508 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013509 }
13510 return 1;
13511}
13512
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040013513sub differentDumps($)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013514{
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040013515 my $Check = $_[0];
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +040013516 if(defined $Cache{"differentDumps"}{$Check}) {
13517 return $Cache{"differentDumps"}{$Check};
13518 }
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040013519 if($UsedDump{1}{"V"} and $UsedDump{2}{"V"})
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040013520 {
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040013521 if($Check eq "G")
13522 {
13523 if(getGccVersion(1) ne getGccVersion(2))
13524 { # different GCC versions
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +040013525 return ($Cache{"differentDumps"}{$Check}=1);
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040013526 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040013527 }
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040013528 if($Check eq "V")
13529 {
13530 if(cmpVersions(formatVersion($UsedDump{1}{"V"}, 2),
13531 formatVersion($UsedDump{2}{"V"}, 2))!=0)
13532 { # different dump versions (skip micro version)
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +040013533 return ($Cache{"differentDumps"}{$Check}=1);
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040013534 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040013535 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013536 }
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +040013537 return ($Cache{"differentDumps"}{$Check}=0);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013538}
13539
13540sub formatVersion($$)
13541{ # cut off version digits
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040013542 my ($V, $Digits) = @_;
13543 my @Elems = split(/\./, $V);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013544 return join(".", splice(@Elems, 0, $Digits));
13545}
13546
13547sub htmlSpecChars($)
13548{
13549 my $Str = $_[0];
Andrey Ponomarenko5c09ef32012-06-14 18:17:33 +040013550 if(not $Str) {
13551 return $Str;
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040013552 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013553 $Str=~s/\&([^#]|\Z)/&amp;$1/g;
13554 $Str=~s/</&lt;/g;
13555 $Str=~s/\-\>/&#45;&gt;/g; # &minus;
13556 $Str=~s/>/&gt;/g;
13557 $Str=~s/([^ ])( )([^ ])/$1\@ALONE_SP\@$3/g;
13558 $Str=~s/ /&#160;/g; # &nbsp;
13559 $Str=~s/\@ALONE_SP\@/ /g;
13560 $Str=~s/\n/<br\/>/g;
13561 $Str=~s/\"/&quot;/g;
13562 $Str=~s/\'/&#39;/g;
13563 return $Str;
13564}
13565
Andrey Ponomarenko5c09ef32012-06-14 18:17:33 +040013566sub xmlSpecChars($)
13567{
13568 my $Str = $_[0];
13569 if(not $Str) {
13570 return $Str;
13571 }
13572
13573 $Str=~s/\&([^#]|\Z)/&amp;$1/g;
13574 $Str=~s/</&lt;/g;
13575 $Str=~s/>/&gt;/g;
13576
13577 $Str=~s/\"/&quot;/g;
13578 $Str=~s/\'/&#39;/g;
13579
13580 return $Str;
13581}
13582
Andrey Ponomarenko01117f12012-06-26 12:23:02 +040013583sub xmlSpecChars_R($)
13584{
13585 my $Str = $_[0];
13586 if(not $Str) {
13587 return $Str;
13588 }
13589
13590 $Str=~s/&amp;/&/g;
13591 $Str=~s/&lt;/</g;
13592 $Str=~s/&gt;/>/g;
13593
13594 $Str=~s/&quot;/"/g;
13595 $Str=~s/&#39;/'/g;
13596
13597 return $Str;
13598}
13599
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013600sub black_name($)
13601{
13602 my $Name = $_[0];
13603 return "<span class='iname_b'>".highLight_Signature($Name)."</span>";
13604}
13605
13606sub highLight_Signature($)
13607{
13608 my $Signature = $_[0];
13609 return highLight_Signature_PPos_Italic($Signature, "", 0, 0, 0);
13610}
13611
13612sub highLight_Signature_Italic_Color($)
13613{
13614 my $Signature = $_[0];
13615 return highLight_Signature_PPos_Italic($Signature, "", 1, 1, 1);
13616}
13617
13618sub separate_symbol($)
13619{
13620 my $Symbol = $_[0];
13621 my ($Name, $Spec, $Ver) = ($Symbol, "", "");
13622 if($Symbol=~/\A([^\@\$\?]+)([\@\$]+)([^\@\$]+)\Z/) {
13623 ($Name, $Spec, $Ver) = ($1, $2, $3);
13624 }
13625 return ($Name, $Spec, $Ver);
13626}
13627
13628sub cut_f_attrs($)
13629{
13630 if($_[0]=~s/(\))((| (const volatile|const|volatile))(| \[static\]))\Z/$1/) {
13631 return $2;
13632 }
13633 return "";
13634}
13635
13636sub highLight_Signature_PPos_Italic($$$$$)
13637{
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040013638 my ($FullSignature, $Param_Pos, $ItalicParams, $ColorParams, $ShowReturn) = @_;
13639 $Param_Pos = "" if(not defined $Param_Pos);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013640 if($CheckObjectsOnly) {
13641 $ItalicParams=$ColorParams=0;
13642 }
13643 my ($Signature, $VersionSpec, $SymbolVersion) = separate_symbol($FullSignature);
13644 my $Return = "";
13645 if($ShowRetVal and $Signature=~s/([^:]):([^:].+?)\Z/$1/g) {
13646 $Return = $2;
13647 }
Andrey Ponomarenko16934472012-03-29 15:37:04 +040013648 my $SCenter = find_center($Signature, "(");
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013649 if(not $SCenter)
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040013650 { # global data
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013651 $Signature = htmlSpecChars($Signature);
13652 $Signature=~s!(\[data\])!<span style='color:Black;font-weight:normal;'>$1</span>!g;
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040013653 $Signature .= (($SymbolVersion)?"<span class='sym_ver'>&#160;$VersionSpec&#160;$SymbolVersion</span>":"");
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013654 if($Return and $ShowReturn) {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040013655 $Signature .= "<span class='sym_p nowrap'> &#160;<b>:</b>&#160;&#160;".htmlSpecChars($Return)."</span>";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013656 }
13657 return $Signature;
13658 }
13659 my ($Begin, $End) = (substr($Signature, 0, $SCenter), "");
13660 $Begin.=" " if($Begin!~/ \Z/);
13661 $End = cut_f_attrs($Signature);
13662 my @Parts = ();
Andrey Ponomarenko07aea072012-11-12 16:15:07 +040013663 my ($Short, $Params) = split_Signature($Signature);
13664 my @SParts = separate_Params($Params, 1, 1);
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040013665 foreach my $Pos (0 .. $#SParts)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013666 {
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040013667 my $Part = $SParts[$Pos];
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013668 $Part=~s/\A\s+|\s+\Z//g;
13669 my ($Part_Styled, $ParamName) = (htmlSpecChars($Part), "");
13670 if($Part=~/\([\*]+(\w+)\)/i) {
13671 $ParamName = $1;#func-ptr
13672 }
13673 elsif($Part=~/(\w+)[\,\)]*\Z/i) {
13674 $ParamName = $1;
13675 }
13676 if(not $ParamName) {
13677 push(@Parts, $Part_Styled);
13678 next;
13679 }
13680 if($ItalicParams and not $TName_Tid{1}{$Part}
13681 and not $TName_Tid{2}{$Part})
13682 {
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040013683 my $Style = "param";
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040013684 if($Param_Pos ne ""
13685 and $Pos==$Param_Pos) {
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040013686 $Style = "focus_p";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013687 }
13688 elsif($ColorParams) {
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040013689 $Style = "color_p";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013690 }
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040013691 $Part_Styled =~ s!(\W)$ParamName([\,\)]|\Z)!$1<span class=\'$Style\'>$ParamName</span>$2!ig;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013692 }
13693 $Part_Styled=~s/,(\w)/, $1/g;
13694 push(@Parts, $Part_Styled);
13695 }
13696 if(@Parts)
13697 {
13698 foreach my $Num (0 .. $#Parts)
13699 {
13700 if($Num==$#Parts)
13701 { # add ")" to the last parameter
13702 $Parts[$Num] = "<span class='nowrap'>".$Parts[$Num]." )</span>";
13703 }
13704 elsif(length($Parts[$Num])<=45) {
13705 $Parts[$Num] = "<span class='nowrap'>".$Parts[$Num]."</span>";
13706 }
13707 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040013708 $Signature = htmlSpecChars($Begin)."<span class='sym_p'>(&#160;".join(" ", @Parts)."</span>".$End;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013709 }
13710 else {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040013711 $Signature = htmlSpecChars($Begin)."<span class='sym_p'>(&#160;)</span>".$End;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013712 }
13713 if($Return and $ShowReturn) {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040013714 $Signature .= "<span class='sym_p nowrap'> &#160;<b>:</b>&#160;&#160;".htmlSpecChars($Return)."</span>";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013715 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040013716 $Signature=~s!\[\]![&#160;]!g;
13717 $Signature=~s!operator=!operator&#160;=!g;
13718 $Signature=~s!(\[in-charge\]|\[not-in-charge\]|\[in-charge-deleting\]|\[static\])!<span class='sym_kind'>$1</span>!g;
13719 return $Signature.(($SymbolVersion)?"<span class='sym_ver'>&#160;$VersionSpec&#160;$SymbolVersion</span>":"");
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013720}
13721
Andrey Ponomarenko07aea072012-11-12 16:15:07 +040013722sub split_Signature($)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013723{
Andrey Ponomarenko07aea072012-11-12 16:15:07 +040013724 my $Signature = $_[0];
13725 if(my $ShortName = substr($Signature, 0, find_center($Signature, "(")))
13726 {
13727 $Signature=~s/\A\Q$ShortName\E\(//g;
13728 cut_f_attrs($Signature);
13729 $Signature=~s/\)\Z//;
13730 return ($ShortName, $Signature);
13731 }
13732
13733 # error
13734 return ($Signature, "");
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013735}
13736
Andrey Ponomarenko07aea072012-11-12 16:15:07 +040013737sub separate_Params($$$)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013738{
Andrey Ponomarenko07aea072012-11-12 16:15:07 +040013739 my ($Params, $Comma, $Sp) = @_;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013740 my @Parts = ();
Andrey Ponomarenko16934472012-03-29 15:37:04 +040013741 my %B = ( "("=>0, "<"=>0, ")"=>0, ">"=>0 );
13742 my $Part = 0;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013743 foreach my $Pos (0 .. length($Params) - 1)
13744 {
Andrey Ponomarenko16934472012-03-29 15:37:04 +040013745 my $S = substr($Params, $Pos, 1);
13746 if(defined $B{$S}) {
Andrey Ponomarenko07aea072012-11-12 16:15:07 +040013747 $B{$S} += 1;
Andrey Ponomarenko16934472012-03-29 15:37:04 +040013748 }
13749 if($S eq "," and
13750 $B{"("}==$B{")"} and $B{"<"}==$B{">"})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013751 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040013752 if($Comma)
13753 { # include comma
Andrey Ponomarenko16934472012-03-29 15:37:04 +040013754 $Parts[$Part] .= $S;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013755 }
Andrey Ponomarenko16934472012-03-29 15:37:04 +040013756 $Part += 1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013757 }
13758 else {
Andrey Ponomarenko16934472012-03-29 15:37:04 +040013759 $Parts[$Part] .= $S;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013760 }
13761 }
Andrey Ponomarenko07aea072012-11-12 16:15:07 +040013762 if(not $Sp)
13763 { # remove spaces
13764 foreach (@Parts)
13765 {
13766 s/\A //g;
13767 s/ \Z//g;
13768 }
13769 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013770 return @Parts;
13771}
13772
Andrey Ponomarenko16934472012-03-29 15:37:04 +040013773sub find_center($$)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013774{
13775 my ($Sign, $Target) = @_;
Andrey Ponomarenko16934472012-03-29 15:37:04 +040013776 my %B = ( "("=>0, "<"=>0, ")"=>0, ">"=>0 );
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013777 my $Center = 0;
Andrey Ponomarenko16934472012-03-29 15:37:04 +040013778 if($Sign=~s/(operator([^\w\s\(\)]+|\(\)))//g)
13779 { # operators
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013780 $Center+=length($1);
13781 }
13782 foreach my $Pos (0 .. length($Sign)-1)
13783 {
13784 my $S = substr($Sign, $Pos, 1);
13785 if($S eq $Target)
13786 {
13787 if($B{"("}==$B{")"}
13788 and $B{"<"}==$B{">"}) {
13789 return $Center;
13790 }
13791 }
13792 if(defined $B{$S}) {
13793 $B{$S}+=1;
13794 }
13795 $Center+=1;
13796 }
13797 return 0;
13798}
13799
13800sub appendFile($$)
13801{
13802 my ($Path, $Content) = @_;
13803 return if(not $Path);
13804 if(my $Dir = get_dirname($Path)) {
13805 mkpath($Dir);
13806 }
Andrey Ponomarenko16934472012-03-29 15:37:04 +040013807 open(FILE, ">>", $Path) || die ("can't open file \'$Path\': $!\n");
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013808 print FILE $Content;
13809 close(FILE);
13810}
13811
13812sub writeFile($$)
13813{
13814 my ($Path, $Content) = @_;
13815 return if(not $Path);
13816 if(my $Dir = get_dirname($Path)) {
13817 mkpath($Dir);
13818 }
Andrey Ponomarenko16934472012-03-29 15:37:04 +040013819 open(FILE, ">", $Path) || die ("can't open file \'$Path\': $!\n");
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013820 print FILE $Content;
13821 close(FILE);
13822}
13823
13824sub readFile($)
13825{
13826 my $Path = $_[0];
13827 return "" if(not $Path or not -f $Path);
Andrey Ponomarenko16934472012-03-29 15:37:04 +040013828 open(FILE, $Path);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013829 local $/ = undef;
13830 my $Content = <FILE>;
13831 close(FILE);
Andrey Ponomarenko85043792012-05-14 16:48:07 +040013832 if($Path!~/\.(tu|class|abi)\Z/) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013833 $Content=~s/\r/\n/g;
13834 }
13835 return $Content;
13836}
13837
13838sub get_filename($)
13839{ # much faster than basename() from File::Basename module
Andrey Ponomarenko85043792012-05-14 16:48:07 +040013840 if(defined $Cache{"get_filename"}{$_[0]}) {
13841 return $Cache{"get_filename"}{$_[0]};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013842 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +040013843 if($_[0] and $_[0]=~/([^\/\\]+)[\/\\]*\Z/) {
13844 return ($Cache{"get_filename"}{$_[0]}=$1);
13845 }
13846 return ($Cache{"get_filename"}{$_[0]}="");
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013847}
13848
13849sub get_dirname($)
13850{ # much faster than dirname() from File::Basename module
Andrey Ponomarenko85043792012-05-14 16:48:07 +040013851 if(defined $Cache{"get_dirname"}{$_[0]}) {
13852 return $Cache{"get_dirname"}{$_[0]};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013853 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +040013854 if($_[0] and $_[0]=~/\A(.*?)[\/\\]+[^\/\\]*[\/\\]*\Z/) {
13855 return ($Cache{"get_dirname"}{$_[0]}=$1);
13856 }
13857 return ($Cache{"get_dirname"}{$_[0]}="");
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013858}
13859
13860sub separate_path($) {
13861 return (get_dirname($_[0]), get_filename($_[0]));
13862}
13863
13864sub esc($)
13865{
13866 my $Str = $_[0];
13867 $Str=~s/([()\[\]{}$ &'"`;,<>\+])/\\$1/g;
13868 return $Str;
13869}
13870
13871sub readLineNum($$)
13872{
13873 my ($Path, $Num) = @_;
13874 return "" if(not $Path or not -f $Path);
Andrey Ponomarenko16934472012-03-29 15:37:04 +040013875 open(FILE, $Path);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013876 foreach (1 ... $Num) {
13877 <FILE>;
13878 }
13879 my $Line = <FILE>;
13880 close(FILE);
13881 return $Line;
13882}
13883
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040013884sub readAttributes($$)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013885{
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040013886 my ($Path, $Num) = @_;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013887 return () if(not $Path or not -f $Path);
13888 my %Attributes = ();
Andrey Ponomarenko85043792012-05-14 16:48:07 +040013889 if(readLineNum($Path, $Num)=~/<!--\s+(.+)\s+-->/)
13890 {
13891 foreach my $AttrVal (split(/;/, $1))
13892 {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013893 if($AttrVal=~/(.+):(.+)/)
13894 {
13895 my ($Name, $Value) = ($1, $2);
13896 $Attributes{$Name} = $Value;
13897 }
13898 }
13899 }
13900 return \%Attributes;
13901}
13902
13903sub is_abs($) {
13904 return ($_[0]=~/\A(\/|\w+:[\/\\])/);
13905}
13906
13907sub get_abs_path($)
13908{ # abs_path() should NOT be called for absolute inputs
13909 # because it can change them
13910 my $Path = $_[0];
13911 if(not is_abs($Path)) {
13912 $Path = abs_path($Path);
13913 }
13914 return $Path;
13915}
13916
13917sub get_OSgroup()
13918{
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +040013919 my $N = $Config{"osname"};
13920 if($N=~/macos|darwin|rhapsody/i) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013921 return "macos";
13922 }
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +040013923 elsif($N=~/freebsd|openbsd|netbsd/i) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013924 return "bsd";
13925 }
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +040013926 elsif($N=~/haiku|beos/i) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013927 return "beos";
13928 }
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +040013929 elsif($N=~/symbian|epoc/i) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013930 return "symbian";
13931 }
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +040013932 elsif($N=~/win/i) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013933 return "windows";
13934 }
13935 else {
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +040013936 return $N;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013937 }
13938}
13939
13940sub getGccVersion($)
13941{
13942 my $LibVersion = $_[0];
13943 if($GCC_VERSION{$LibVersion})
13944 { # dump version
13945 return $GCC_VERSION{$LibVersion};
13946 }
13947 elsif($UsedDump{$LibVersion}{"V"})
13948 { # old-version dumps
13949 return "unknown";
13950 }
13951 my $GccVersion = get_dumpversion($GCC_PATH); # host version
13952 if(not $GccVersion) {
13953 return "unknown";
13954 }
13955 return $GccVersion;
13956}
13957
13958sub showArch($)
13959{
13960 my $Arch = $_[0];
13961 if($Arch eq "arm"
13962 or $Arch eq "mips") {
13963 return uc($Arch);
13964 }
13965 return $Arch;
13966}
13967
13968sub getArch($)
13969{
13970 my $LibVersion = $_[0];
13971 if($CPU_ARCH{$LibVersion})
13972 { # dump version
13973 return $CPU_ARCH{$LibVersion};
13974 }
13975 elsif($UsedDump{$LibVersion}{"V"})
13976 { # old-version dumps
13977 return "unknown";
13978 }
13979 if(defined $Cache{"getArch"}{$LibVersion}) {
13980 return $Cache{"getArch"}{$LibVersion};
13981 }
13982 my $Arch = get_dumpmachine($GCC_PATH); # host version
13983 if(not $Arch) {
13984 return "unknown";
13985 }
13986 if($Arch=~/\A([\w]{3,})(-|\Z)/) {
13987 $Arch = $1;
13988 }
13989 $Arch = "x86" if($Arch=~/\Ai[3-7]86\Z/);
13990 if($OSgroup eq "windows") {
13991 $Arch = "x86" if($Arch=~/win32|mingw32/i);
13992 $Arch = "x86_64" if($Arch=~/win64|mingw64/i);
13993 }
13994 $Cache{"getArch"}{$LibVersion} = $Arch;
13995 return $Arch;
13996}
13997
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040013998sub get_Report_Header($)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013999{
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014000 my $Level = $_[0];
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014001 my $ArchInfo = " on <span style='color:Blue;'>".showArch(getArch(1))."</span>";
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014002 if(getArch(1) ne getArch(2)
14003 or getArch(1) eq "unknown"
14004 or $Level eq "Source")
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014005 { # don't show architecture in the header
14006 $ArchInfo="";
14007 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014008 my $Report_Header = "<h1><span class='nowrap'>";
14009 if($Level eq "Source") {
14010 $Report_Header .= "Source compatibility";
14011 }
14012 elsif($Level eq "Binary") {
14013 $Report_Header .= "Binary compatibility";
14014 }
14015 else {
14016 $Report_Header .= "API compatibility";
14017 }
14018 $Report_Header .= " report for the <span style='color:Blue;'>$TargetLibraryFName</span> $TargetComponent</span>";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014019 $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>";
14020 if($AppPath) {
14021 $Report_Header .= " <span class='nowrap'>&#160;(relating to the portability of application <span style='color:Blue;'>".get_filename($AppPath)."</span>)</span>";
14022 }
14023 $Report_Header .= "</h1>\n";
14024 return $Report_Header;
14025}
14026
14027sub get_SourceInfo()
14028{
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040014029 my ($CheckedHeaders, $CheckedLibs) = ("", "");
14030 if(not $CheckObjectsOnly)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014031 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040014032 $CheckedHeaders = "<a name='Headers'></a><h2>Header Files (".keys(%{$Registered_Headers{1}}).")</h2><hr/>\n";
14033 $CheckedHeaders .= "<div class='h_list'>\n";
14034 foreach my $Header_Path (sort {lc($Registered_Headers{1}{$a}{"Identity"}) cmp lc($Registered_Headers{1}{$b}{"Identity"})} keys(%{$Registered_Headers{1}}))
14035 {
14036 my $Identity = $Registered_Headers{1}{$Header_Path}{"Identity"};
14037 my $Header_Name = get_filename($Identity);
14038 my $Dest_Comment = ($Identity=~/[\/\\]/)?" ($Identity)":"";
14039 $CheckedHeaders .= $Header_Name.$Dest_Comment."<br/>\n";
14040 }
14041 $CheckedHeaders .= "</div>\n";
14042 $CheckedHeaders .= "<br/>$TOP_REF<br/>\n";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014043 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040014044 if(not $CheckHeadersOnly)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014045 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040014046 $CheckedLibs = "<a name='Libs'></a><h2>".ucfirst($SLIB_TYPE)." Libraries (".keys(%{$Library_Symbol{1}}).")</h2><hr/>\n";
14047 $CheckedLibs .= "<div class='lib_list'>\n";
14048 foreach my $Library (sort {lc($a) cmp lc($b)} keys(%{$Library_Symbol{1}}))
14049 {
14050 $Library.=" (.$LIB_EXT)" if($Library!~/\.\w+\Z/);
14051 $CheckedLibs .= $Library."<br/>\n";
14052 }
14053 $CheckedLibs .= "</div>\n";
14054 $CheckedLibs .= "<br/>$TOP_REF<br/>\n";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014055 }
14056 return $CheckedHeaders.$CheckedLibs;
14057}
14058
14059sub get_TypeProblems_Count($$$)
14060{
14061 my ($TypeChanges, $TargetPriority, $Level) = @_;
14062 my $Type_Problems_Count = 0;
14063 foreach my $Type_Name (sort keys(%{$TypeChanges}))
14064 {
14065 my %Kinds_Target = ();
14066 foreach my $Kind (keys(%{$TypeChanges->{$Type_Name}}))
14067 {
14068 foreach my $Location (keys(%{$TypeChanges->{$Type_Name}{$Kind}}))
14069 {
14070 my $Target = $TypeChanges->{$Type_Name}{$Kind}{$Location}{"Target"};
14071 my $Priority = getProblemSeverity($Level, $Kind);
14072 next if($Priority ne $TargetPriority);
14073 if($Kinds_Target{$Kind}{$Target}) {
14074 next;
14075 }
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040014076 if(cmpSeverities($Type_MaxSeverity{$Level}{$Type_Name}{$Kind}{$Target}, $Priority))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014077 { # select a problem with the highest priority
14078 next;
14079 }
14080 $Kinds_Target{$Kind}{$Target} = 1;
14081 $Type_Problems_Count += 1;
14082 }
14083 }
14084 }
14085 return $Type_Problems_Count;
14086}
14087
14088sub get_Summary($)
14089{
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014090 my $Level = $_[0];
14091 my ($Added, $Removed, $I_Problems_High, $I_Problems_Medium, $I_Problems_Low, $T_Problems_High,
14092 $C_Problems_Low, $T_Problems_Medium, $T_Problems_Low, $I_Other, $T_Other) = (0,0,0,0,0,0,0,0,0,0,0);
14093 %{$RESULT{$Level}} = (
14094 "Problems"=>0,
14095 "Warnings"=>0,
14096 "Affected"=>0 );
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014097 # check rules
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014098 foreach my $Interface (sort keys(%{$CompatProblems{$Level}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014099 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014100 foreach my $Kind (keys(%{$CompatProblems{$Level}{$Interface}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014101 {
14102 if(not defined $CompatRules{$Level}{$Kind})
14103 { # unknown rule
14104 if(not $UnknownRules{$Level}{$Kind})
14105 { # only one warning
14106 printMsg("WARNING", "unknown rule \"$Kind\" (\"$Level\")");
14107 $UnknownRules{$Level}{$Kind}=1;
14108 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014109 delete($CompatProblems{$Level}{$Interface}{$Kind});
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014110 }
14111 }
14112 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014113 foreach my $Interface (sort keys(%{$CompatProblems{$Level}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014114 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014115 foreach my $Kind (sort keys(%{$CompatProblems{$Level}{$Interface}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014116 {
14117 if($CompatRules{$Level}{$Kind}{"Kind"} eq "Symbols")
14118 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014119 foreach my $Location (sort keys(%{$CompatProblems{$Level}{$Interface}{$Kind}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014120 {
14121 my $Priority = getProblemSeverity($Level, $Kind);
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014122 if($Kind eq "Added_Symbol") {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014123 $Added += 1;
14124 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014125 elsif($Kind eq "Removed_Symbol")
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014126 {
14127 $Removed += 1;
14128 $TotalAffected{$Level}{$Interface} = $Priority;
14129 }
14130 else
14131 {
14132 if($Priority eq "Safe") {
14133 $I_Other += 1;
14134 }
14135 elsif($Priority eq "High") {
14136 $I_Problems_High += 1;
14137 }
14138 elsif($Priority eq "Medium") {
14139 $I_Problems_Medium += 1;
14140 }
14141 elsif($Priority eq "Low") {
14142 $I_Problems_Low += 1;
14143 }
14144 if(($Priority ne "Low" or $StrictCompat)
14145 and $Priority ne "Safe") {
14146 $TotalAffected{$Level}{$Interface} = $Priority;
14147 }
14148 }
14149 }
14150 }
14151 }
14152 }
14153 my %TypeChanges = ();
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014154 foreach my $Interface (sort keys(%{$CompatProblems{$Level}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014155 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014156 foreach my $Kind (keys(%{$CompatProblems{$Level}{$Interface}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014157 {
14158 if($CompatRules{$Level}{$Kind}{"Kind"} eq "Types")
14159 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014160 foreach my $Location (sort {cmp_locations($b, $a)} sort keys(%{$CompatProblems{$Level}{$Interface}{$Kind}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014161 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014162 my $Type_Name = $CompatProblems{$Level}{$Interface}{$Kind}{$Location}{"Type_Name"};
14163 my $Target = $CompatProblems{$Level}{$Interface}{$Kind}{$Location}{"Target"};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014164 my $Priority = getProblemSeverity($Level, $Kind);
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040014165 if(cmpSeverities($Type_MaxSeverity{$Level}{$Type_Name}{$Kind}{$Target}, $Priority))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014166 { # select a problem with the highest priority
14167 next;
14168 }
14169 if(($Priority ne "Low" or $StrictCompat)
14170 and $Priority ne "Safe") {
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040014171 $TotalAffected{$Level}{$Interface} = maxSeverity($TotalAffected{$Level}{$Interface}, $Priority);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014172 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014173 %{$TypeChanges{$Type_Name}{$Kind}{$Location}} = %{$CompatProblems{$Level}{$Interface}{$Kind}{$Location}};
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040014174 $Type_MaxSeverity{$Level}{$Type_Name}{$Kind}{$Target} = maxSeverity($Type_MaxSeverity{$Level}{$Type_Name}{$Kind}{$Target}, $Priority);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014175 }
14176 }
14177 }
14178 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014179
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014180 $T_Problems_High = get_TypeProblems_Count(\%TypeChanges, "High", $Level);
14181 $T_Problems_Medium = get_TypeProblems_Count(\%TypeChanges, "Medium", $Level);
14182 $T_Problems_Low = get_TypeProblems_Count(\%TypeChanges, "Low", $Level);
14183 $T_Other = get_TypeProblems_Count(\%TypeChanges, "Safe", $Level);
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014184
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014185 if($CheckObjectsOnly)
14186 { # only removed exported symbols
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014187 $RESULT{$Level}{"Affected"} = $Removed*100/keys(%{$Symbol_Library{1}});
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014188 }
14189 else
14190 { # changed and removed public symbols
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014191 my $SCount = keys(%{$CheckedSymbols{$Level}});
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014192 if($ExtendedCheck)
14193 { # don't count external_func_0 for constants
14194 $SCount-=1;
14195 }
14196 if($SCount)
14197 {
14198 my %Weight = (
14199 "High" => 100,
14200 "Medium" => 50,
14201 "Low" => 25
14202 );
14203 foreach (keys(%{$TotalAffected{$Level}})) {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014204 $RESULT{$Level}{"Affected"}+=$Weight{$TotalAffected{$Level}{$_}};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014205 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014206 $RESULT{$Level}{"Affected"} = $RESULT{$Level}{"Affected"}/$SCount;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014207 }
14208 else {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014209 $RESULT{$Level}{"Affected"} = 0;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014210 }
14211 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014212 $RESULT{$Level}{"Affected"} = show_number($RESULT{$Level}{"Affected"});
14213 if($RESULT{$Level}{"Affected"}>=100) {
14214 $RESULT{$Level}{"Affected"} = 100;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014215 }
14216
Andrey Ponomarenko85043792012-05-14 16:48:07 +040014217 $RESULT{$Level}{"Problems"} += $Removed;
14218 $RESULT{$Level}{"Problems"} += $T_Problems_High + $I_Problems_High;
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014219 $RESULT{$Level}{"Problems"} += $T_Problems_Medium + $I_Problems_Medium;
Andrey Ponomarenko85043792012-05-14 16:48:07 +040014220 if($StrictCompat) {
14221 $RESULT{$Level}{"Problems"} += $T_Problems_Low + $I_Problems_Low;
14222 }
14223 else {
14224 $RESULT{$Level}{"Warnings"} += $T_Problems_Low + $I_Problems_Low;
14225 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014226
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014227 if($C_Problems_Low = keys(%{$ProblemsWithConstants{$Level}}))
14228 {
Andrey Ponomarenko85043792012-05-14 16:48:07 +040014229 if(defined $CompatRules{$Level}{"Changed_Constant"})
14230 {
14231 if($StrictCompat) {
14232 $RESULT{$Level}{"Problems"} += $C_Problems_Low;
14233 }
14234 else {
14235 $RESULT{$Level}{"Warnings"} += $C_Problems_Low;
14236 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014237 }
14238 else
14239 {
14240 printMsg("WARNING", "unknown rule \"Changed_Constant\" (\"$Level\")");
14241 $C_Problems_Low = 0;
14242 }
14243 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +040014244 if($CheckImpl and $Level eq "Binary")
14245 {
14246 if($StrictCompat) {
14247 $RESULT{$Level}{"Problems"} += keys(%ImplProblems);
14248 }
14249 else {
14250 $RESULT{$Level}{"Warnings"} += keys(%ImplProblems);
14251 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014252 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +040014253 if($RESULT{$Level}{"Problems"}
14254 and $RESULT{$Level}{"Affected"}) {
14255 $RESULT{$Level}{"Verdict"} = "incompatible";
14256 }
14257 else {
14258 $RESULT{$Level}{"Verdict"} = "compatible";
14259 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014260
14261 my $TotalTypes = keys(%{$CheckedTypes{$Level}});
14262 if(not $TotalTypes)
14263 { # list all the types
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014264 $TotalTypes = keys(%{$TName_Tid{1}});
14265 }
14266
14267 my ($Arch1, $Arch2) = (getArch(1), getArch(2));
14268 my ($GccV1, $GccV2) = (getGccVersion(1), getGccVersion(2));
14269
14270 my ($TestInfo, $TestResults, $Problem_Summary) = ();
14271
14272 if($ReportFormat eq "xml")
14273 { # XML
14274 # test info
14275 $TestInfo .= " <library>$TargetLibraryName</library>\n";
14276 $TestInfo .= " <version1>\n";
14277 $TestInfo .= " <number>".$Descriptor{1}{"Version"}."</number>\n";
14278 $TestInfo .= " <architecture>$Arch1</architecture>\n";
14279 $TestInfo .= " <gcc>$GccV1</gcc>\n";
14280 $TestInfo .= " </version1>\n";
14281
14282 $TestInfo .= " <version2>\n";
14283 $TestInfo .= " <number>".$Descriptor{2}{"Version"}."</number>\n";
14284 $TestInfo .= " <architecture>$Arch2</architecture>\n";
14285 $TestInfo .= " <gcc>$GccV2</gcc>\n";
14286 $TestInfo .= " </version2>\n";
14287 $TestInfo = "<test_info>\n".$TestInfo."</test_info>\n\n";
14288
14289 # test results
14290 $TestResults .= " <headers>\n";
14291 foreach my $Name (sort {lc($Registered_Headers{1}{$a}{"Identity"}) cmp lc($Registered_Headers{1}{$b}{"Identity"})} keys(%{$Registered_Headers{1}}))
14292 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014293 my $Identity = $Registered_Headers{1}{$Name}{"Identity"};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014294 my $Comment = ($Identity=~/[\/\\]/)?" ($Identity)":"";
14295 $TestResults .= " <name>".get_filename($Name).$Comment."</name>\n";
14296 }
14297 $TestResults .= " </headers>\n";
14298
14299 $TestResults .= " <libs>\n";
14300 foreach my $Library (sort {lc($a) cmp lc($b)} keys(%{$Library_Symbol{1}}))
14301 {
14302 $Library.=" (.$LIB_EXT)" if($Library!~/\.\w+\Z/);
14303 $TestResults .= " <name>$Library</name>\n";
14304 }
14305 $TestResults .= " </libs>\n";
14306
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040014307 $TestResults .= " <symbols>".(keys(%{$CheckedSymbols{$Level}}) - keys(%ExtendedSymbols))."</symbols>\n";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014308 $TestResults .= " <types>".$TotalTypes."</types>\n";
14309
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014310 $TestResults .= " <verdict>".$RESULT{$Level}{"Verdict"}."</verdict>\n";
14311 $TestResults .= " <affected>".$RESULT{$Level}{"Affected"}."</affected>\n";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014312 $TestResults = "<test_results>\n".$TestResults."</test_results>\n\n";
14313
14314 # problem summary
14315 $Problem_Summary .= " <added_symbols>".$Added."</added_symbols>\n";
14316 $Problem_Summary .= " <removed_symbols>".$Removed."</removed_symbols>\n";
14317
14318 $Problem_Summary .= " <problems_with_types>\n";
14319 $Problem_Summary .= " <high>$T_Problems_High</high>\n";
14320 $Problem_Summary .= " <medium>$T_Problems_Medium</medium>\n";
14321 $Problem_Summary .= " <low>$T_Problems_Low</low>\n";
14322 $Problem_Summary .= " <safe>$T_Other</safe>\n";
14323 $Problem_Summary .= " </problems_with_types>\n";
14324
14325 $Problem_Summary .= " <problems_with_symbols>\n";
14326 $Problem_Summary .= " <high>$I_Problems_High</high>\n";
14327 $Problem_Summary .= " <medium>$I_Problems_Medium</medium>\n";
14328 $Problem_Summary .= " <low>$I_Problems_Low</low>\n";
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014329 $Problem_Summary .= " <safe>$I_Other</safe>\n";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014330 $Problem_Summary .= " </problems_with_symbols>\n";
14331
14332 $Problem_Summary .= " <problems_with_constants>\n";
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014333 $Problem_Summary .= " <low>$C_Problems_Low</low>\n";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014334 $Problem_Summary .= " </problems_with_constants>\n";
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014335 if($CheckImpl and $Level eq "Binary")
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014336 {
14337 $Problem_Summary .= " <impl>\n";
14338 $Problem_Summary .= " <low>".keys(%ImplProblems)."</low>\n";
14339 $Problem_Summary .= " </impl>\n";
14340 }
14341 $Problem_Summary = "<problem_summary>\n".$Problem_Summary."</problem_summary>\n\n";
14342
14343 return ($TestInfo.$TestResults.$Problem_Summary, "");
14344 }
14345 else
14346 { # HTML
14347 # test info
14348 $TestInfo = "<h2>Test Info</h2><hr/>\n";
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014349 $TestInfo .= "<table class='summary'>\n";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014350 $TestInfo .= "<tr><th>".ucfirst($TargetComponent)." Name</th><td>$TargetLibraryFName</td></tr>\n";
14351
14352 my (@VInf1, @VInf2, $AddTestInfo) = ();
14353 if($Arch1 ne "unknown"
14354 and $Arch2 ne "unknown")
14355 { # CPU arch
14356 if($Arch1 eq $Arch2)
14357 { # go to the separate section
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014358 $AddTestInfo .= "<tr><th>CPU Type</th><td>".showArch($Arch1)."</td></tr>\n";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014359 }
14360 else
14361 { # go to the version number
14362 push(@VInf1, showArch($Arch1));
14363 push(@VInf2, showArch($Arch2));
14364 }
14365 }
14366 if($GccV1 ne "unknown"
14367 and $GccV2 ne "unknown"
14368 and $OStarget ne "windows")
14369 { # GCC version
14370 if($GccV1 eq $GccV2)
14371 { # go to the separate section
14372 $AddTestInfo .= "<tr><th>GCC Version</th><td>$GccV1</td></tr>\n";
14373 }
14374 else
14375 { # go to the version number
14376 push(@VInf1, "gcc ".$GccV1);
14377 push(@VInf2, "gcc ".$GccV2);
14378 }
14379 }
14380 # show long version names with GCC version and CPU architecture name (if different)
14381 $TestInfo .= "<tr><th>Version #1</th><td>".$Descriptor{1}{"Version"}.(@VInf1?" (".join(", ", reverse(@VInf1)).")":"")."</td></tr>\n";
14382 $TestInfo .= "<tr><th>Version #2</th><td>".$Descriptor{2}{"Version"}.(@VInf2?" (".join(", ", reverse(@VInf2)).")":"")."</td></tr>\n";
14383 $TestInfo .= $AddTestInfo;
14384 #if($COMMON_LANGUAGE{1}) {
14385 # $TestInfo .= "<tr><th>Language</th><td>".$COMMON_LANGUAGE{1}."</td></tr>\n";
14386 #}
14387 if($ExtendedCheck) {
14388 $TestInfo .= "<tr><th>Mode</th><td>Extended</td></tr>\n";
14389 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014390 if($JoinReport)
14391 {
14392 if($Level eq "Binary") {
Andrey Ponomarenko16934472012-03-29 15:37:04 +040014393 $TestInfo .= "<tr><th>Subject</th><td width='150px'>Binary Compatibility</td></tr>\n"; # Run-time
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014394 }
14395 if($Level eq "Source") {
Andrey Ponomarenko16934472012-03-29 15:37:04 +040014396 $TestInfo .= "<tr><th>Subject</th><td width='150px'>Source Compatibility</td></tr>\n"; # Build-time
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014397 }
14398 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014399 $TestInfo .= "</table>\n";
14400
14401 # test results
14402 $TestResults = "<h2>Test Results</h2><hr/>\n";
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014403 $TestResults .= "<table class='summary'>";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014404
14405 my $Headers_Link = "0";
14406 $Headers_Link = "<a href='#Headers' style='color:Blue;'>".keys(%{$Registered_Headers{1}})."</a>" if(keys(%{$Registered_Headers{1}})>0);
14407 $TestResults .= "<tr><th>Total Header Files</th><td>".($CheckObjectsOnly?"0&#160;(not&#160;analyzed)":$Headers_Link)."</td></tr>\n";
14408
14409 if(not $ExtendedCheck)
14410 {
14411 my $Libs_Link = "0";
14412 $Libs_Link = "<a href='#Libs' style='color:Blue;'>".keys(%{$Library_Symbol{1}})."</a>" if(keys(%{$Library_Symbol{1}})>0);
14413 $TestResults .= "<tr><th>Total ".ucfirst($SLIB_TYPE)." Libraries</th><td>".($CheckHeadersOnly?"0&#160;(not&#160;analyzed)":$Libs_Link)."</td></tr>\n";
14414 }
14415
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040014416 $TestResults .= "<tr><th>Total Symbols / Types</th><td>".(keys(%{$CheckedSymbols{$Level}}) - keys(%ExtendedSymbols))." / ".$TotalTypes."</td></tr>\n";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014417
Andrey Ponomarenko85043792012-05-14 16:48:07 +040014418 my $META_DATA = "verdict:".$RESULT{$Level}{"Verdict"}.";";
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014419 if($JoinReport) {
14420 $META_DATA = "kind:".lc($Level).";".$META_DATA;
14421 }
Andrey Ponomarenko16934472012-03-29 15:37:04 +040014422 $TestResults .= "<tr><th>Verdict</th>";
Andrey Ponomarenko85043792012-05-14 16:48:07 +040014423 if($RESULT{$Level}{"Verdict"} eq "incompatible") {
Andrey Ponomarenko16934472012-03-29 15:37:04 +040014424 $TestResults .= "<td><span style='color:Red;'><b>Incompatible<br/>(".$RESULT{$Level}{"Affected"}."%)</b></span></td>";
14425 }
14426 else {
14427 $TestResults .= "<td><span style='color:Green;'><b>Compatible</b></span></td>";
14428 }
14429 $TestResults .= "</tr>\n";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014430 $TestResults .= "</table>\n";
14431
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014432 $META_DATA .= "affected:".$RESULT{$Level}{"Affected"}.";";# in percents
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014433 # problem summary
14434 $Problem_Summary = "<h2>Problem Summary</h2><hr/>\n";
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014435 $Problem_Summary .= "<table class='summary'>";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014436 $Problem_Summary .= "<tr><th></th><th style='text-align:center;'>Severity</th><th style='text-align:center;'>Count</th></tr>";
14437
14438 my $Added_Link = "0";
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014439 if($Added>0)
14440 {
14441 if($JoinReport) {
14442 $Added_Link = "<a href='#".$Level."_Added' style='color:Blue;'>$Added</a>";
14443 }
14444 else {
14445 $Added_Link = "<a href='#Added' style='color:Blue;'>$Added</a>";
14446 }
14447 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014448 $META_DATA .= "added:$Added;";
Andrey Ponomarenko16934472012-03-29 15:37:04 +040014449 $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 +040014450
14451 my $Removed_Link = "0";
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014452 if($Removed>0)
14453 {
14454 if($JoinReport) {
14455 $Removed_Link = "<a href='#".$Level."_Removed' style='color:Blue;'>$Removed</a>"
14456 }
14457 else {
14458 $Removed_Link = "<a href='#Removed' style='color:Blue;'>$Removed</a>"
14459 }
14460 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014461 $META_DATA .= "removed:$Removed;";
Andrey Ponomarenko16934472012-03-29 15:37:04 +040014462 $Problem_Summary .= "<tr><th>Removed Symbols</th>";
14463 $Problem_Summary .= "<td>High</td><td".getStyle("I", "R", $Removed).">$Removed_Link</td></tr>\n";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014464
14465 my $TH_Link = "0";
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014466 $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 +040014467 $TH_Link = "n/a" if($CheckObjectsOnly);
14468 $META_DATA .= "type_problems_high:$T_Problems_High;";
Andrey Ponomarenko16934472012-03-29 15:37:04 +040014469 $Problem_Summary .= "<tr><th rowspan='3'>Problems with<br/>Data Types</th>";
14470 $Problem_Summary .= "<td>High</td><td".getStyle("T", "H", $T_Problems_High).">$TH_Link</td></tr>\n";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014471
14472 my $TM_Link = "0";
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014473 $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 +040014474 $TM_Link = "n/a" if($CheckObjectsOnly);
14475 $META_DATA .= "type_problems_medium:$T_Problems_Medium;";
Andrey Ponomarenko16934472012-03-29 15:37:04 +040014476 $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 +040014477
14478 my $TL_Link = "0";
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014479 $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 +040014480 $TL_Link = "n/a" if($CheckObjectsOnly);
14481 $META_DATA .= "type_problems_low:$T_Problems_Low;";
Andrey Ponomarenko16934472012-03-29 15:37:04 +040014482 $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 +040014483
14484 my $IH_Link = "0";
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014485 $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 +040014486 $IH_Link = "n/a" if($CheckObjectsOnly);
14487 $META_DATA .= "interface_problems_high:$I_Problems_High;";
Andrey Ponomarenko16934472012-03-29 15:37:04 +040014488 $Problem_Summary .= "<tr><th rowspan='3'>Problems with<br/>Symbols</th>";
14489 $Problem_Summary .= "<td>High</td><td".getStyle("I", "H", $I_Problems_High).">$IH_Link</td></tr>\n";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014490
14491 my $IM_Link = "0";
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014492 $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 +040014493 $IM_Link = "n/a" if($CheckObjectsOnly);
14494 $META_DATA .= "interface_problems_medium:$I_Problems_Medium;";
Andrey Ponomarenko16934472012-03-29 15:37:04 +040014495 $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 +040014496
14497 my $IL_Link = "0";
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014498 $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 +040014499 $IL_Link = "n/a" if($CheckObjectsOnly);
14500 $META_DATA .= "interface_problems_low:$I_Problems_Low;";
Andrey Ponomarenko16934472012-03-29 15:37:04 +040014501 $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 +040014502
14503 my $ChangedConstants_Link = "0";
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014504 if(keys(%{$CheckedSymbols{$Level}}) and $C_Problems_Low)
14505 {
14506 if($JoinReport) {
14507 $ChangedConstants_Link = "<a href='#".$Level."_Changed_Constants' style='color:Blue;'>$C_Problems_Low</a>";
14508 }
14509 else {
14510 $ChangedConstants_Link = "<a href='#Changed_Constants' style='color:Blue;'>$C_Problems_Low</a>";
14511 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014512 }
14513 $ChangedConstants_Link = "n/a" if($CheckObjectsOnly);
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014514 $META_DATA .= "changed_constants:$C_Problems_Low;";
Andrey Ponomarenko16934472012-03-29 15:37:04 +040014515 $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 +040014516
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014517 if($CheckImpl and $Level eq "Binary")
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014518 {
14519 my $ChangedImpl_Link = "0";
14520 $ChangedImpl_Link = "<a href='#Changed_Implementation' style='color:Blue;'>".keys(%ImplProblems)."</a>" if(keys(%ImplProblems)>0);
14521 $ChangedImpl_Link = "n/a" if($CheckHeadersOnly);
14522 $META_DATA .= "changed_implementation:".keys(%ImplProblems).";";
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040014523 $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 +040014524 }
14525 # Safe Changes
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014526 if($T_Other and not $CheckObjectsOnly)
14527 {
14528 my $TS_Link = "<a href='#".get_Anchor("Type", $Level, "Safe")."' style='color:Blue;'>$T_Other</a>";
Andrey Ponomarenko16934472012-03-29 15:37:04 +040014529 $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 +040014530 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014531
14532 if($I_Other and not $CheckObjectsOnly)
14533 {
14534 my $IS_Link = "<a href='#".get_Anchor("Symbol", $Level, "Safe")."' style='color:Blue;'>$I_Other</a>";
Andrey Ponomarenko16934472012-03-29 15:37:04 +040014535 $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 +040014536 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014537
14538 $META_DATA .= "tool_version:$TOOL_VERSION";
14539 $Problem_Summary .= "</table>\n";
Andrey Ponomarenko16934472012-03-29 15:37:04 +040014540 # $TestInfo = getLegend().$TestInfo;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014541 return ($TestInfo.$TestResults.$Problem_Summary, $META_DATA);
14542 }
14543}
14544
Andrey Ponomarenko16934472012-03-29 15:37:04 +040014545sub getStyle($$$)
14546{
14547 my ($Subj, $Act, $Num) = @_;
14548 my %Style = (
14549 "A"=>"new",
14550 "R"=>"failed",
14551 "S"=>"passed",
14552 "L"=>"warning",
14553 "M"=>"failed",
14554 "H"=>"failed"
14555 );
14556 if($Num>0) {
14557 return " class='".$Style{$Act}."'";
14558 }
14559 return "";
14560}
14561
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014562sub show_number($)
14563{
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014564 if($_[0])
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014565 {
Andrey Ponomarenko16934472012-03-29 15:37:04 +040014566 my $Num = cut_off_number($_[0], 2, 0);
14567 if($Num eq "0")
14568 {
14569 foreach my $P (3 .. 7)
14570 {
14571 $Num = cut_off_number($_[0], $P, 1);
14572 if($Num ne "0") {
14573 last;
14574 }
14575 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014576 }
14577 if($Num eq "0") {
14578 $Num = $_[0];
14579 }
14580 return $Num;
14581 }
14582 return $_[0];
14583}
14584
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014585sub cut_off_number($$$)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014586{
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014587 my ($num, $digs_to_cut, $z) = @_;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014588 if($num!~/\./)
14589 {
14590 $num .= ".";
14591 foreach (1 .. $digs_to_cut-1) {
14592 $num .= "0";
14593 }
14594 }
14595 elsif($num=~/\.(.+)\Z/ and length($1)<$digs_to_cut-1)
14596 {
14597 foreach (1 .. $digs_to_cut - 1 - length($1)) {
14598 $num .= "0";
14599 }
14600 }
14601 elsif($num=~/\d+\.(\d){$digs_to_cut,}/) {
14602 $num=sprintf("%.".($digs_to_cut-1)."f", $num);
14603 }
14604 $num=~s/\.[0]+\Z//g;
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014605 if($z) {
14606 $num=~s/(\.[1-9]+)[0]+\Z/$1/g;
14607 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014608 return $num;
14609}
14610
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014611sub get_Report_ChangedConstants($)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014612{
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014613 my $Level = $_[0];
Andrey Ponomarenko16934472012-03-29 15:37:04 +040014614 my $CHANGED_CONSTANTS = "";
14615 my %ReportMap = ();
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014616 foreach my $Constant (keys(%{$ProblemsWithConstants{$Level}})) {
Andrey Ponomarenko16934472012-03-29 15:37:04 +040014617 $ReportMap{$Constants{1}{$Constant}{"Header"}}{$Constant} = 1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014618 }
14619 my $Kind = "Changed_Constant";
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014620 if(not defined $CompatRules{$Level}{$Kind}) {
14621 return "";
14622 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014623 if($ReportFormat eq "xml")
14624 { # XML
Andrey Ponomarenko16934472012-03-29 15:37:04 +040014625 foreach my $HeaderName (sort {lc($a) cmp lc($b)} keys(%ReportMap))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014626 {
14627 $CHANGED_CONSTANTS .= " <header name=\"$HeaderName\">\n";
Andrey Ponomarenko16934472012-03-29 15:37:04 +040014628 foreach my $Constant (sort {lc($a) cmp lc($b)} keys(%{$ReportMap{$HeaderName}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014629 {
14630 $CHANGED_CONSTANTS .= " <constant name=\"$Constant\">\n";
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014631 my $Change = $CompatRules{$Level}{$Kind}{"Change"};
14632 my $Effect = $CompatRules{$Level}{$Kind}{"Effect"};
14633 my $Overcome = $CompatRules{$Level}{$Kind}{"Overcome"};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014634 $CHANGED_CONSTANTS .= " <problem id=\"$Kind\">\n";
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014635 $CHANGED_CONSTANTS .= " <change".getXmlParams($Change, $ProblemsWithConstants{$Level}{$Constant}).">$Change</change>\n";
14636 $CHANGED_CONSTANTS .= " <effect".getXmlParams($Effect, $ProblemsWithConstants{$Level}{$Constant}).">$Effect</effect>\n";
14637 $CHANGED_CONSTANTS .= " <overcome".getXmlParams($Overcome, $ProblemsWithConstants{$Level}{$Constant}).">$Overcome</overcome>\n";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014638 $CHANGED_CONSTANTS .= " </problem>\n";
14639 $CHANGED_CONSTANTS .= " </constant>\n";
14640 }
14641 $CHANGED_CONSTANTS .= " </header>\n";
14642 }
14643 $CHANGED_CONSTANTS = "<problems_with_constants severity=\"Low\">\n".$CHANGED_CONSTANTS."</problems_with_constants>\n\n";
14644 }
14645 else
14646 { # HTML
14647 my $Number = 0;
Andrey Ponomarenko16934472012-03-29 15:37:04 +040014648 foreach my $HeaderName (sort {lc($a) cmp lc($b)} keys(%ReportMap))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014649 {
14650 $CHANGED_CONSTANTS .= "<span class='h_name'>$HeaderName</span><br/>\n";
Andrey Ponomarenko16934472012-03-29 15:37:04 +040014651 foreach my $Name (sort {lc($a) cmp lc($b)} keys(%{$ReportMap{$HeaderName}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014652 {
14653 $Number += 1;
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014654 my $Change = applyMacroses($Level, $Kind, $CompatRules{$Level}{$Kind}{"Change"}, $ProblemsWithConstants{$Level}{$Name});
14655 my $Effect = $CompatRules{$Level}{$Kind}{"Effect"};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014656 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 +040014657 $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 +040014658 $Report = $ContentSpanStart."<span class='extendable'>[+]</span> ".$Name.$ContentSpanEnd."<br/>\n".$Report;
14659 $CHANGED_CONSTANTS .= insertIDs($Report);
14660 }
14661 $CHANGED_CONSTANTS .= "<br/>\n";
14662 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014663 if($CHANGED_CONSTANTS)
14664 {
14665 my $Anchor = "<a name='Changed_Constants'></a>";
14666 if($JoinReport) {
14667 $Anchor = "<a name='".$Level."_Changed_Constants'></a>";
14668 }
14669 $CHANGED_CONSTANTS = $Anchor."<h2>Problems with Constants ($Number)</h2><hr/>\n".$CHANGED_CONSTANTS.$TOP_REF."<br/>\n";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014670 }
14671 }
14672 return $CHANGED_CONSTANTS;
14673}
14674
14675sub get_Report_Impl()
14676{
Andrey Ponomarenko16934472012-03-29 15:37:04 +040014677 my $CHANGED_IMPLEMENTATION = "";
14678 my %ReportMap = ();
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014679 foreach my $Interface (sort keys(%ImplProblems))
14680 {
14681 my $HeaderName = $CompleteSignature{1}{$Interface}{"Header"};
14682 my $DyLib = $Symbol_Library{1}{$Interface};
Andrey Ponomarenko16934472012-03-29 15:37:04 +040014683 $ReportMap{$HeaderName}{$DyLib}{$Interface} = 1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014684 }
14685 my $Changed_Number = 0;
Andrey Ponomarenko16934472012-03-29 15:37:04 +040014686 foreach my $HeaderName (sort {lc($a) cmp lc($b)} keys(%ReportMap))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014687 {
Andrey Ponomarenko16934472012-03-29 15:37:04 +040014688 foreach my $DyLib (sort {lc($a) cmp lc($b)} keys(%{$ReportMap{$HeaderName}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014689 {
14690 my $FDyLib=$DyLib.($DyLib!~/\.\w+\Z/?" (.$LIB_EXT)":"");
14691 if($HeaderName) {
14692 $CHANGED_IMPLEMENTATION .= "<span class='h_name'>$HeaderName</span>, <span class='lib_name'>$FDyLib</span><br/>\n";
14693 }
14694 else {
14695 $CHANGED_IMPLEMENTATION .= "<span class='lib_name'>$DyLib</span><br/>\n";
14696 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014697 my %NameSpaceSymbols = ();
Andrey Ponomarenko16934472012-03-29 15:37:04 +040014698 foreach my $Interface (keys(%{$ReportMap{$HeaderName}{$DyLib}})) {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014699 $NameSpaceSymbols{get_IntNameSpace($Interface, 2)}{$Interface} = 1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014700 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014701 foreach my $NameSpace (sort keys(%NameSpaceSymbols))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014702 {
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040014703 $CHANGED_IMPLEMENTATION .= ($NameSpace)?"<span class='ns_title'>namespace</span> <span class='ns'>$NameSpace</span><br/>\n":"";
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014704 my @SortedInterfaces = sort {lc(get_Signature($a, 1)) cmp lc(get_Signature($b, 1))} keys(%{$NameSpaceSymbols{$NameSpace}});
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014705 foreach my $Interface (@SortedInterfaces)
14706 {
14707 $Changed_Number += 1;
14708 my $Signature = get_Signature($Interface, 1);
14709 if($NameSpace) {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040014710 $Signature=~s/\b\Q$NameSpace\E::\b//g;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014711 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014712 $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 +040014713 }
14714 }
14715 $CHANGED_IMPLEMENTATION .= "<br/>\n";
14716 }
14717 }
14718 if($CHANGED_IMPLEMENTATION) {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014719 $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 +040014720 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +040014721
14722 # clean memory
14723 %ImplProblems = ();
14724
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014725 return $CHANGED_IMPLEMENTATION;
14726}
14727
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014728sub getTitle($$$)
14729{
14730 my ($Header, $Library, $NameSpace) = @_;
14731 my $Title = "";
14732 if($Library and $Library!~/\.\w+\Z/) {
14733 $Library .= " (.$LIB_EXT)";
14734 }
14735 if($Header and $Library)
14736 {
14737 $Title .= "<span class='h_name'>$Header</span>";
14738 $Title .= ", <span class='lib_name'>$Library</span><br/>\n";
14739 }
14740 elsif($Library) {
14741 $Title .= "<span class='lib_name'>$Library</span><br/>\n";
14742 }
14743 elsif($Header) {
14744 $Title .= "<span class='h_name'>$Header</span><br/>\n";
14745 }
14746 if($NameSpace) {
14747 $Title .= "<span class='ns_title'>namespace</span> <span class='ns'>$NameSpace</span><br/>\n";
14748 }
14749 return $Title;
14750}
14751
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014752sub get_Report_Added($)
14753{
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014754 my $Level = $_[0];
Andrey Ponomarenko16934472012-03-29 15:37:04 +040014755 my $ADDED_INTERFACES = "";
14756 my %ReportMap = ();
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014757 foreach my $Interface (sort keys(%{$CompatProblems{$Level}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014758 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014759 foreach my $Kind (sort keys(%{$CompatProblems{$Level}{$Interface}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014760 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014761 if($Kind eq "Added_Symbol")
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014762 {
14763 my $HeaderName = $CompleteSignature{2}{$Interface}{"Header"};
14764 my $DyLib = $Symbol_Library{2}{$Interface};
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014765 if($Level eq "Source" and $ReportFormat eq "html")
14766 { # do not show library name in HTML report
14767 $DyLib = "";
14768 }
14769 $ReportMap{$HeaderName}{$DyLib}{$Interface} = 1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014770 }
14771 }
14772 }
14773 if($ReportFormat eq "xml")
14774 { # XML
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014775 foreach my $HeaderName (sort {lc($a) cmp lc($b)} keys(%ReportMap))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014776 {
14777 $ADDED_INTERFACES .= " <header name=\"$HeaderName\">\n";
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014778 foreach my $DyLib (sort {lc($a) cmp lc($b)} keys(%{$ReportMap{$HeaderName}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014779 {
14780 $ADDED_INTERFACES .= " <library name=\"$DyLib\">\n";
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014781 foreach my $Interface (keys(%{$ReportMap{$HeaderName}{$DyLib}})) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014782 $ADDED_INTERFACES .= " <name>$Interface</name>\n";
14783 }
14784 $ADDED_INTERFACES .= " </library>\n";
14785 }
14786 $ADDED_INTERFACES .= " </header>\n";
14787 }
14788 $ADDED_INTERFACES = "<added_symbols>\n".$ADDED_INTERFACES."</added_symbols>\n\n";
14789 }
14790 else
14791 { # HTML
14792 my $Added_Number = 0;
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014793 foreach my $HeaderName (sort {lc($a) cmp lc($b)} keys(%ReportMap))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014794 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014795 foreach my $DyLib (sort {lc($a) cmp lc($b)} keys(%{$ReportMap{$HeaderName}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014796 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014797 my %NameSpaceSymbols = ();
14798 foreach my $Interface (keys(%{$ReportMap{$HeaderName}{$DyLib}})) {
14799 $NameSpaceSymbols{get_IntNameSpace($Interface, 2)}{$Interface} = 1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014800 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014801 foreach my $NameSpace (sort keys(%NameSpaceSymbols))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014802 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014803 $ADDED_INTERFACES .= getTitle($HeaderName, $DyLib, $NameSpace);
14804 my @SortedInterfaces = sort {lc(get_Signature($a, 2)) cmp lc(get_Signature($b, 2))} keys(%{$NameSpaceSymbols{$NameSpace}});
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014805 foreach my $Interface (@SortedInterfaces)
14806 {
14807 $Added_Number += 1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014808 my $Signature = get_Signature($Interface, 2);
14809 if($NameSpace) {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040014810 $Signature=~s/\b\Q$NameSpace\E::\b//g;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014811 }
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040014812 if($Interface=~/\A(_Z|\?)/)
14813 {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014814 if($Signature) {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014815 $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 +040014816 }
14817 else {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014818 $ADDED_INTERFACES .= "<span class=\"iname\">".$Interface."</span><br/>\n";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014819 }
14820 }
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040014821 else
14822 {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014823 if($Signature) {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014824 $ADDED_INTERFACES .= "<span class=\"iname\">".highLight_Signature_Italic_Color($Signature)."</span><br/>\n";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014825 }
14826 else {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014827 $ADDED_INTERFACES .= "<span class=\"iname\">".$Interface."</span><br/>\n";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014828 }
14829 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014830 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014831 $ADDED_INTERFACES .= "<br/>\n";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014832 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014833 }
14834 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014835 if($ADDED_INTERFACES)
14836 {
14837 my $Anchor = "<a name='Added'></a>";
14838 if($JoinReport) {
14839 $Anchor = "<a name='".$Level."_Added'></a>";
14840 }
14841 $ADDED_INTERFACES = $Anchor."<h2>Added Symbols ($Added_Number)</h2><hr/>\n".$ADDED_INTERFACES.$TOP_REF."<br/>\n";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014842 }
14843 }
14844 return $ADDED_INTERFACES;
14845}
14846
14847sub get_Report_Removed($)
14848{
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014849 my $Level = $_[0];
Andrey Ponomarenko16934472012-03-29 15:37:04 +040014850 my $REMOVED_INTERFACES = "";
14851 my %ReportMap = ();
Andrey Ponomarenko85043792012-05-14 16:48:07 +040014852 foreach my $Symbol (sort keys(%{$CompatProblems{$Level}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014853 {
Andrey Ponomarenko85043792012-05-14 16:48:07 +040014854 foreach my $Kind (sort keys(%{$CompatProblems{$Level}{$Symbol}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014855 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014856 if($Kind eq "Removed_Symbol")
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014857 {
Andrey Ponomarenko85043792012-05-14 16:48:07 +040014858 my $HeaderName = $CompleteSignature{1}{$Symbol}{"Header"};
14859 my $DyLib = $Symbol_Library{1}{$Symbol};
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014860 if($Level eq "Source" and $ReportFormat eq "html")
14861 { # do not show library name in HTML report
14862 $DyLib = "";
14863 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +040014864 $ReportMap{$HeaderName}{$DyLib}{$Symbol} = 1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014865 }
14866 }
14867 }
14868 if($ReportFormat eq "xml")
14869 { # XML
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014870 foreach my $HeaderName (sort {lc($a) cmp lc($b)} keys(%ReportMap))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014871 {
14872 $REMOVED_INTERFACES .= " <header name=\"$HeaderName\">\n";
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014873 foreach my $DyLib (sort {lc($a) cmp lc($b)} keys(%{$ReportMap{$HeaderName}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014874 {
14875 $REMOVED_INTERFACES .= " <library name=\"$DyLib\">\n";
Andrey Ponomarenko85043792012-05-14 16:48:07 +040014876 foreach my $Symbol (keys(%{$ReportMap{$HeaderName}{$DyLib}})) {
14877 $REMOVED_INTERFACES .= " <name>$Symbol</name>\n";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014878 }
14879 $REMOVED_INTERFACES .= " </library>\n";
14880 }
14881 $REMOVED_INTERFACES .= " </header>\n";
14882 }
14883 $REMOVED_INTERFACES = "<removed_symbols>\n".$REMOVED_INTERFACES."</removed_symbols>\n\n";
14884 }
14885 else
14886 { # HTML
14887 my $Removed_Number = 0;
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014888 foreach my $HeaderName (sort {lc($a) cmp lc($b)} keys(%ReportMap))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014889 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014890 foreach my $DyLib (sort {lc($a) cmp lc($b)} keys(%{$ReportMap{$HeaderName}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014891 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014892 my %NameSpaceSymbols = ();
14893 foreach my $Interface (keys(%{$ReportMap{$HeaderName}{$DyLib}})) {
14894 $NameSpaceSymbols{get_IntNameSpace($Interface, 1)}{$Interface} = 1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014895 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014896 foreach my $NameSpace (sort keys(%NameSpaceSymbols))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014897 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014898 $REMOVED_INTERFACES .= getTitle($HeaderName, $DyLib, $NameSpace);
14899 my @SortedInterfaces = sort {lc(get_Signature($a, 1)) cmp lc(get_Signature($b, 1))} keys(%{$NameSpaceSymbols{$NameSpace}});
Andrey Ponomarenko85043792012-05-14 16:48:07 +040014900 foreach my $Symbol (@SortedInterfaces)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014901 {
14902 $Removed_Number += 1;
14903 my $SubReport = "";
Andrey Ponomarenko85043792012-05-14 16:48:07 +040014904 my $Signature = get_Signature($Symbol, 1);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014905 if($NameSpace) {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040014906 $Signature=~s/\b\Q$NameSpace\E::\b//g;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014907 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +040014908 if($Symbol=~/\A(_Z|\?)/)
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014909 {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014910 if($Signature) {
Andrey Ponomarenko85043792012-05-14 16:48:07 +040014911 $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 +040014912 }
14913 else {
Andrey Ponomarenko85043792012-05-14 16:48:07 +040014914 $REMOVED_INTERFACES .= "<span class=\"iname\">".$Symbol."</span><br/>\n";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014915 }
14916 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014917 else
14918 {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014919 if($Signature) {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014920 $REMOVED_INTERFACES .= "<span class=\"iname\">".highLight_Signature_Italic_Color($Signature)."</span><br/>\n";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014921 }
14922 else {
Andrey Ponomarenko85043792012-05-14 16:48:07 +040014923 $REMOVED_INTERFACES .= "<span class=\"iname\">".$Symbol."</span><br/>\n";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014924 }
14925 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014926 }
14927 }
14928 $REMOVED_INTERFACES .= "<br/>\n";
14929 }
14930 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014931 if($REMOVED_INTERFACES)
14932 {
14933 my $Anchor = "<a name='Removed'></a><a name='Withdrawn'></a>";
14934 if($JoinReport) {
14935 $Anchor = "<a name='".$Level."_Removed'></a><a name='".$Level."_Withdrawn'></a>";
14936 }
14937 $REMOVED_INTERFACES = $Anchor."<h2>Removed Symbols ($Removed_Number)</h2><hr/>\n".$REMOVED_INTERFACES.$TOP_REF."<br/>\n";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014938 }
14939 }
14940 return $REMOVED_INTERFACES;
14941}
14942
14943sub getXmlParams($$)
14944{
14945 my ($Content, $Problem) = @_;
14946 return "" if(not $Content or not $Problem);
14947 my %XMLparams = ();
14948 foreach my $Attr (sort {$b cmp $a} keys(%{$Problem}))
14949 {
14950 my $Macro = "\@".lc($Attr);
14951 if($Content=~/\Q$Macro\E/) {
14952 $XMLparams{lc($Attr)} = $Problem->{$Attr};
14953 }
14954 }
14955 my @PString = ();
14956 foreach my $P (sort {$b cmp $a} keys(%XMLparams)) {
Andrey Ponomarenko5c09ef32012-06-14 18:17:33 +040014957 push(@PString, $P."=\"".xmlSpecChars($XMLparams{$P})."\"");
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014958 }
14959 if(@PString) {
14960 return " ".join(" ", @PString);
14961 }
14962 else {
14963 return "";
14964 }
14965}
14966
14967sub addMarkup($)
14968{
14969 my $Content = $_[0];
14970 # auto-markup
14971 $Content=~s/\n[ ]*//; # spaces
14972 $Content=~s!(\@\w+\s*\(\@\w+\))!<nowrap>$1</nowrap>!g; # @old_type (@old_size)
14973 $Content=~s!(... \(\w+\))!<nowrap><b>$1</b></nowrap>!g; # ... (va_list)
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040014974 $Content=~s!<nowrap>(.+?)</nowrap>!<span class='nowrap'>$1</span>!g;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014975 $Content=~s!([2-9]\))!<br/>$1!g; # 1), 2), ...
14976 if($Content=~/\ANOTE:/)
14977 { # notes
14978 $Content=~s!(NOTE):!<b>$1</b>:!g;
14979 }
14980 else {
14981 $Content=~s!(NOTE):!<br/><b>$1</b>:!g;
14982 }
14983 $Content=~s! (out)-! <b>$1</b>-!g; # out-parameters
14984 my @Keywords = (
14985 "void",
14986 "const",
14987 "static",
14988 "restrict",
14989 "volatile",
14990 "register",
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040014991 "virtual"
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014992 );
14993 my $MKeys = join("|", @Keywords);
14994 foreach (@Keywords) {
14995 $MKeys .= "|non-".$_;
14996 }
14997 $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 +040014998
14999 # Markdown
15000 $Content=~s!\*\*([\w\-]+)\*\*!<b>$1</b>!ig;
15001 $Content=~s!\*([\w\-]+)\*!<i>$1</i>!ig;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015002 return $Content;
15003}
15004
15005sub applyMacroses($$$$)
15006{
15007 my ($Level, $Kind, $Content, $Problem) = @_;
15008 return "" if(not $Content or not $Problem);
15009 $Problem->{"Word_Size"} = $WORD_SIZE{2};
15010 $Content = addMarkup($Content);
15011 # macros
15012 foreach my $Attr (sort {$b cmp $a} keys(%{$Problem}))
15013 {
15014 my $Macro = "\@".lc($Attr);
15015 my $Value = $Problem->{$Attr};
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040015016 if(not defined $Value
15017 or $Value eq "") {
15018 next;
15019 }
Andrey Ponomarenko5c09ef32012-06-14 18:17:33 +040015020 if($Value=~/\s\(/ and $Value!~/['"]/)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015021 { # functions
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015022 $Value=~s/\s*\[[\w\-]+\]//g; # remove quals
15023 $Value=~s/\s\w+(\)|,)/$1/g; # remove parameter names
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015024 $Value = black_name($Value);
15025 }
15026 elsif($Value=~/\s/) {
15027 $Value = "<span class='value'>".htmlSpecChars($Value)."</span>";
15028 }
15029 elsif($Value=~/\A\d+\Z/
15030 and ($Attr eq "Old_Size" or $Attr eq "New_Size"))
15031 { # bits to bytes
15032 if($Value % $BYTE_SIZE)
15033 { # bits
15034 if($Value==1) {
15035 $Value = "<b>".$Value."</b> bit";
15036 }
15037 else {
15038 $Value = "<b>".$Value."</b> bits";
15039 }
15040 }
15041 else
15042 { # bytes
15043 $Value /= $BYTE_SIZE;
15044 if($Value==1) {
15045 $Value = "<b>".$Value."</b> byte";
15046 }
15047 else {
15048 $Value = "<b>".$Value."</b> bytes";
15049 }
15050 }
15051 }
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040015052 else
15053 {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015054 $Value = "<b>".htmlSpecChars($Value)."</b>";
15055 }
15056 $Content=~s/\Q$Macro\E/$Value/g;
15057 }
15058
15059 if($Content=~/(\A|[^\@\w])\@\w/)
15060 {
15061 if(not $IncompleteRules{$Level}{$Kind})
15062 { # only one warning
15063 printMsg("WARNING", "incomplete rule \"$Kind\" (\"$Level\")");
15064 $IncompleteRules{$Level}{$Kind} = 1;
15065 }
15066 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015067 return $Content;
15068}
15069
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040015070sub get_Report_SymbolProblems($$)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015071{
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015072 my ($TargetSeverity, $Level) = @_;
Andrey Ponomarenko16934472012-03-29 15:37:04 +040015073 my $INTERFACE_PROBLEMS = "";
15074 my (%ReportMap, %SymbolChanges) = ();
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015075 foreach my $Symbol (sort keys(%{$CompatProblems{$Level}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015076 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015077 my ($SN, $SS, $SV) = separate_symbol($Symbol);
15078 if($SV and defined $CompatProblems{$Level}{$SN}) {
15079 next;
15080 }
15081 foreach my $Kind (sort keys(%{$CompatProblems{$Level}{$Symbol}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015082 {
15083 if($CompatRules{$Level}{$Kind}{"Kind"} eq "Symbols"
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015084 and $Kind ne "Added_Symbol" and $Kind ne "Removed_Symbol")
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015085 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015086 my $HeaderName = $CompleteSignature{1}{$Symbol}{"Header"};
15087 my $DyLib = $Symbol_Library{1}{$Symbol};
15088 if(not $DyLib and my $VSym = $SymVer{1}{$Symbol})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015089 { # Symbol with Version
15090 $DyLib = $Symbol_Library{1}{$VSym};
15091 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040015092 if(not $DyLib)
15093 { # const global data
15094 $DyLib = "";
15095 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015096 if($Level eq "Source" and $ReportFormat eq "html")
15097 { # do not show library name in HTML report
15098 $DyLib = "";
15099 }
15100 %{$SymbolChanges{$Symbol}{$Kind}} = %{$CompatProblems{$Level}{$Symbol}{$Kind}};
15101 foreach my $Location (sort keys(%{$SymbolChanges{$Symbol}{$Kind}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015102 {
15103 my $Priority = getProblemSeverity($Level, $Kind);
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015104 if($Priority ne $TargetSeverity) {
15105 delete($SymbolChanges{$Symbol}{$Kind}{$Location});
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015106 }
15107 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015108 if(not keys(%{$SymbolChanges{$Symbol}{$Kind}}))
15109 {
15110 delete($SymbolChanges{$Symbol}{$Kind});
15111 next;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015112 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015113 $ReportMap{$HeaderName}{$DyLib}{$Symbol} = 1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015114 }
15115 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015116 if(not keys(%{$SymbolChanges{$Symbol}})) {
15117 delete($SymbolChanges{$Symbol});
15118 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015119 }
15120 if($ReportFormat eq "xml")
15121 { # XML
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015122 foreach my $HeaderName (sort {lc($a) cmp lc($b)} keys(%ReportMap))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015123 {
15124 $INTERFACE_PROBLEMS .= " <header name=\"$HeaderName\">\n";
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015125 foreach my $DyLib (sort {lc($a) cmp lc($b)} keys(%{$ReportMap{$HeaderName}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015126 {
15127 $INTERFACE_PROBLEMS .= " <library name=\"$DyLib\">\n";
15128 foreach my $Symbol (sort {lc($tr_name{$a}) cmp lc($tr_name{$b})} keys(%SymbolChanges))
15129 {
15130 $INTERFACE_PROBLEMS .= " <symbol name=\"$Symbol\">\n";
15131 foreach my $Kind (keys(%{$SymbolChanges{$Symbol}}))
15132 {
15133 foreach my $Location (sort keys(%{$SymbolChanges{$Symbol}{$Kind}}))
15134 {
15135 my %Problem = %{$SymbolChanges{$Symbol}{$Kind}{$Location}};
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040015136 $Problem{"Param_Pos"} = showPos($Problem{"Param_Pos"});
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015137 $INTERFACE_PROBLEMS .= " <problem id=\"$Kind\">\n";
15138 my $Change = $CompatRules{$Level}{$Kind}{"Change"};
15139 $INTERFACE_PROBLEMS .= " <change".getXmlParams($Change, \%Problem).">$Change</change>\n";
15140 my $Effect = $CompatRules{$Level}{$Kind}{"Effect"};
15141 $INTERFACE_PROBLEMS .= " <effect".getXmlParams($Effect, \%Problem).">$Effect</effect>\n";
15142 my $Overcome = $CompatRules{$Level}{$Kind}{"Overcome"};
15143 $INTERFACE_PROBLEMS .= " <overcome".getXmlParams($Overcome, \%Problem).">$Overcome</overcome>\n";
15144 $INTERFACE_PROBLEMS .= " </problem>\n";
15145 }
15146 }
15147 $INTERFACE_PROBLEMS .= " </symbol>\n";
15148 }
15149 $INTERFACE_PROBLEMS .= " </library>\n";
15150 }
15151 $INTERFACE_PROBLEMS .= " </header>\n";
15152 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015153 $INTERFACE_PROBLEMS = "<problems_with_symbols severity=\"$TargetSeverity\">\n".$INTERFACE_PROBLEMS."</problems_with_symbols>\n\n";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015154 }
15155 else
15156 { # HTML
15157 my $ProblemsNum = 0;
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015158 foreach my $HeaderName (sort {lc($a) cmp lc($b)} keys(%ReportMap))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015159 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015160 foreach my $DyLib (sort {lc($a) cmp lc($b)} keys(%{$ReportMap{$HeaderName}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015161 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015162 my (%NameSpaceSymbols, %NewSignature) = ();
15163 foreach my $Symbol (keys(%{$ReportMap{$HeaderName}{$DyLib}})) {
15164 $NameSpaceSymbols{get_IntNameSpace($Symbol, 1)}{$Symbol} = 1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015165 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015166 foreach my $NameSpace (sort keys(%NameSpaceSymbols))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015167 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015168 $INTERFACE_PROBLEMS .= getTitle($HeaderName, $DyLib, $NameSpace);
15169 my @SortedInterfaces = sort {lc($tr_name{$a}) cmp lc($tr_name{$b})} keys(%{$NameSpaceSymbols{$NameSpace}});
15170 foreach my $Symbol (@SortedInterfaces)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015171 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015172 my $Signature = get_Signature($Symbol, 1);
15173 my $SYMBOL_REPORT = "";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015174 my $ProblemNum = 1;
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015175 foreach my $Kind (keys(%{$SymbolChanges{$Symbol}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015176 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015177 foreach my $Location (sort keys(%{$SymbolChanges{$Symbol}{$Kind}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015178 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015179 my %Problem = %{$SymbolChanges{$Symbol}{$Kind}{$Location}};
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040015180 $Problem{"Param_Pos"} = showPos($Problem{"Param_Pos"});
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015181 if($Problem{"New_Signature"}) {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015182 $NewSignature{$Symbol} = $Problem{"New_Signature"};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015183 }
15184 if(my $Change = applyMacroses($Level, $Kind, $CompatRules{$Level}{$Kind}{"Change"}, \%Problem))
15185 {
15186 my $Effect = applyMacroses($Level, $Kind, $CompatRules{$Level}{$Kind}{"Effect"}, \%Problem);
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015187 $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 +040015188 $ProblemNum += 1;
15189 $ProblemsNum += 1;
15190 }
15191 }
15192 }
15193 $ProblemNum -= 1;
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015194 if($SYMBOL_REPORT)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015195 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015196 $INTERFACE_PROBLEMS .= $ContentSpanStart."<span class='extendable'>[+]</span> ";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015197 if($Signature) {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015198 $INTERFACE_PROBLEMS .= highLight_Signature_Italic_Color($Signature);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015199 }
15200 else {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015201 $INTERFACE_PROBLEMS .= $Symbol;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015202 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015203 $INTERFACE_PROBLEMS .= " ($ProblemNum)".$ContentSpanEnd."<br/>\n";
15204 $INTERFACE_PROBLEMS .= $ContentDivStart."\n";
15205 if($NewSignature{$Symbol})
15206 { # argument list changed to
15207 $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 +040015208 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015209 if($Symbol=~/\A(_Z|\?)/) {
15210 $INTERFACE_PROBLEMS .= "<span class='mangled'>&#160;&#160;&#160;&#160;[symbol: <b>$Symbol</b>]</span><br/>\n";
15211 }
15212 $INTERFACE_PROBLEMS .= "<table class='ptable'><tr><th width='2%'></th><th width='47%'>Change</th><th>Effect</th></tr>$SYMBOL_REPORT</table><br/>\n";
15213 $INTERFACE_PROBLEMS .= $ContentDivEnd;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015214 if($NameSpace) {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040015215 $INTERFACE_PROBLEMS=~s/\b\Q$NameSpace\E::\b//g;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015216 }
15217 }
15218 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015219 $INTERFACE_PROBLEMS .= "<br/>";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015220 }
15221 }
15222 }
15223 if($INTERFACE_PROBLEMS)
15224 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015225 $INTERFACE_PROBLEMS = insertIDs($INTERFACE_PROBLEMS);
15226 my $Title = "Problems with Symbols, $TargetSeverity Severity";
15227 if($TargetSeverity eq "Safe")
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015228 { # Safe Changes
15229 $Title = "Other Changes in Symbols";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015230 }
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040015231 $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 +040015232 }
15233 }
15234 return $INTERFACE_PROBLEMS;
15235}
15236
15237sub get_Report_TypeProblems($$)
15238{
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015239 my ($TargetSeverity, $Level) = @_;
Andrey Ponomarenko16934472012-03-29 15:37:04 +040015240 my $TYPE_PROBLEMS = "";
15241 my (%ReportMap, %TypeChanges, %TypeType) = ();
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015242 foreach my $Interface (sort keys(%{$CompatProblems{$Level}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015243 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015244 foreach my $Kind (keys(%{$CompatProblems{$Level}{$Interface}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015245 {
15246 if($CompatRules{$Level}{$Kind}{"Kind"} eq "Types")
15247 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015248 foreach my $Location (sort {cmp_locations($b, $a)} sort keys(%{$CompatProblems{$Level}{$Interface}{$Kind}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015249 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015250 my $TypeName = $CompatProblems{$Level}{$Interface}{$Kind}{$Location}{"Type_Name"};
15251 my $TypeType = $CompatProblems{$Level}{$Interface}{$Kind}{$Location}{"Type_Type"};
15252 my $Target = $CompatProblems{$Level}{$Interface}{$Kind}{$Location}{"Target"};
15253 $CompatProblems{$Level}{$Interface}{$Kind}{$Location}{"Type_Type"} = lc($TypeType);
15254 my $Severity = getProblemSeverity($Level, $Kind);
15255 if($Severity eq "Safe"
15256 and $TargetSeverity ne "Safe") {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015257 next;
15258 }
15259 if(not $TypeType{$TypeName}
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015260 or $TypeType{$TypeName} eq "struct")
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015261 { # register type of the type, select "class" if type has "class"- and "struct"-type changes
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015262 $TypeType{$TypeName} = $CompatProblems{$Level}{$Interface}{$Kind}{$Location}{"Type_Type"};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015263 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015264
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040015265 if(cmpSeverities($Type_MaxSeverity{$Level}{$TypeName}{$Kind}{$Target}, $Severity))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015266 { # select a problem with the highest priority
15267 next;
15268 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015269 %{$TypeChanges{$TypeName}{$Kind}{$Location}} = %{$CompatProblems{$Level}{$Interface}{$Kind}{$Location}};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015270 }
15271 }
15272 }
15273 }
15274 my %Kinds_Locations = ();
15275 foreach my $TypeName (keys(%TypeChanges))
15276 {
15277 my %Kinds_Target = ();
15278 foreach my $Kind (sort keys(%{$TypeChanges{$TypeName}}))
15279 {
15280 foreach my $Location (sort {cmp_locations($b, $a)} sort keys(%{$TypeChanges{$TypeName}{$Kind}}))
15281 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015282 my $Severity = getProblemSeverity($Level, $Kind);
15283 if($Severity ne $TargetSeverity)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015284 { # other priority
15285 delete($TypeChanges{$TypeName}{$Kind}{$Location});
15286 next;
15287 }
15288 $Kinds_Locations{$TypeName}{$Kind}{$Location} = 1;
15289 my $Target = $TypeChanges{$TypeName}{$Kind}{$Location}{"Target"};
15290 if($Kinds_Target{$Kind}{$Target})
15291 { # duplicate target
15292 delete($TypeChanges{$TypeName}{$Kind}{$Location});
15293 next;
15294 }
15295 $Kinds_Target{$Kind}{$Target} = 1;
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040015296 my $HeaderName = $TypeInfo{1}{$TName_Tid{1}{$TypeName}}{"Header"};
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015297 $ReportMap{$HeaderName}{$TypeName} = 1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015298 }
15299 if(not keys(%{$TypeChanges{$TypeName}{$Kind}})) {
15300 delete($TypeChanges{$TypeName}{$Kind});
15301 }
15302 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015303 if(not keys(%{$TypeChanges{$TypeName}})) {
15304 delete($TypeChanges{$TypeName});
15305 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015306 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +040015307 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 +040015308 if($ReportFormat eq "xml")
15309 { # XML
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015310 foreach my $HeaderName (sort {lc($a) cmp lc($b)} keys(%ReportMap))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015311 {
15312 $TYPE_PROBLEMS .= " <header name=\"$HeaderName\">\n";
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015313 foreach my $TypeName (keys(%{$ReportMap{$HeaderName}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015314 {
Andrey Ponomarenko5c09ef32012-06-14 18:17:33 +040015315 $TYPE_PROBLEMS .= " <type name=\"".xmlSpecChars($TypeName)."\">\n";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015316 foreach my $Kind (sort {$b=~/Size/ <=> $a=~/Size/} sort keys(%{$TypeChanges{$TypeName}}))
15317 {
15318 foreach my $Location (sort {cmp_locations($b, $a)} sort keys(%{$TypeChanges{$TypeName}{$Kind}}))
15319 {
15320 my %Problem = %{$TypeChanges{$TypeName}{$Kind}{$Location}};
15321 $TYPE_PROBLEMS .= " <problem id=\"$Kind\">\n";
15322 my $Change = $CompatRules{$Level}{$Kind}{"Change"};
15323 $TYPE_PROBLEMS .= " <change".getXmlParams($Change, \%Problem).">$Change</change>\n";
15324 my $Effect = $CompatRules{$Level}{$Kind}{"Effect"};
15325 $TYPE_PROBLEMS .= " <effect".getXmlParams($Effect, \%Problem).">$Effect</effect>\n";
15326 my $Overcome = $CompatRules{$Level}{$Kind}{"Overcome"};
15327 $TYPE_PROBLEMS .= " <overcome".getXmlParams($Overcome, \%Problem).">$Overcome</overcome>\n";
15328 $TYPE_PROBLEMS .= " </problem>\n";
15329 }
15330 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +040015331 $TYPE_PROBLEMS .= getAffectedSymbols($Level, $TypeName, $Kinds_Locations{$TypeName}, \@Symbols);
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015332 if($Level eq "Binary" and grep {$_=~/Virtual|Base_Class/} keys(%{$Kinds_Locations{$TypeName}})) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015333 $TYPE_PROBLEMS .= showVTables($TypeName);
15334 }
15335 $TYPE_PROBLEMS .= " </type>\n";
15336 }
15337 $TYPE_PROBLEMS .= " </header>\n";
15338 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015339 $TYPE_PROBLEMS = "<problems_with_types severity=\"$TargetSeverity\">\n".$TYPE_PROBLEMS."</problems_with_types>\n\n";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015340 }
15341 else
15342 { # HTML
15343 my $ProblemsNum = 0;
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015344 foreach my $HeaderName (sort {lc($a) cmp lc($b)} keys(%ReportMap))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015345 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015346 my (%NameSpace_Type) = ();
15347 foreach my $TypeName (keys(%{$ReportMap{$HeaderName}})) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015348 $NameSpace_Type{parse_TypeNameSpace($TypeName, 1)}{$TypeName} = 1;
15349 }
15350 foreach my $NameSpace (sort keys(%NameSpace_Type))
15351 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015352 $TYPE_PROBLEMS .= getTitle($HeaderName, "", $NameSpace);
15353 my @SortedTypes = sort {$TypeType{$a}." ".lc($a) cmp $TypeType{$b}." ".lc($b)} keys(%{$NameSpace_Type{$NameSpace}});
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015354 foreach my $TypeName (@SortedTypes)
15355 {
15356 my $ProblemNum = 1;
15357 my $TYPE_REPORT = "";
15358 foreach my $Kind (sort {$b=~/Size/ <=> $a=~/Size/} sort keys(%{$TypeChanges{$TypeName}}))
15359 {
15360 foreach my $Location (sort {cmp_locations($b, $a)} sort keys(%{$TypeChanges{$TypeName}{$Kind}}))
15361 {
15362 my %Problem = %{$TypeChanges{$TypeName}{$Kind}{$Location}};
15363 if(my $Change = applyMacroses($Level, $Kind, $CompatRules{$Level}{$Kind}{"Change"}, \%Problem))
15364 {
15365 my $Effect = applyMacroses($Level, $Kind, $CompatRules{$Level}{$Kind}{"Effect"}, \%Problem);
15366 $TYPE_REPORT .= "<tr><th>$ProblemNum</th><td align='left' valign='top'>".$Change."</td><td align='left' valign='top'>$Effect</td></tr>\n";
15367 $ProblemNum += 1;
15368 $ProblemsNum += 1;
15369 }
15370 }
15371 }
15372 $ProblemNum -= 1;
15373 if($TYPE_REPORT)
15374 {
Andrey Ponomarenko85043792012-05-14 16:48:07 +040015375 my $Affected = getAffectedSymbols($Level, $TypeName, $Kinds_Locations{$TypeName}, \@Symbols);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015376 my $ShowVTables = "";
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015377 if($Level eq "Binary" and grep {$_=~/Virtual|Base_Class/} keys(%{$Kinds_Locations{$TypeName}})) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015378 $ShowVTables = showVTables($TypeName);
15379 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015380 $TYPE_PROBLEMS .= $ContentSpanStart."<span class='extendable'>[+]</span> <span class='ttype'>".$TypeType{$TypeName}."</span> ".htmlSpecChars($TypeName)." ($ProblemNum)".$ContentSpanEnd;
15381 $TYPE_PROBLEMS .= "<br/>\n".$ContentDivStart."<table class='ptable'><tr>\n";
15382 $TYPE_PROBLEMS .= "<th width='2%'></th><th width='47%'>Change</th>\n";
15383 $TYPE_PROBLEMS .= "<th>Effect</th></tr>".$TYPE_REPORT."</table>\n";
15384 $TYPE_PROBLEMS .= $ShowVTables.$Affected."<br/><br/>".$ContentDivEnd."\n";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015385 if($NameSpace) {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040015386 $TYPE_PROBLEMS=~s/\b\Q$NameSpace\E::(\w|\~)/$1/g;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015387 }
15388 }
15389 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015390 $TYPE_PROBLEMS .= "<br/>";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015391 }
15392 }
15393 if($TYPE_PROBLEMS)
15394 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015395 $TYPE_PROBLEMS = insertIDs($TYPE_PROBLEMS);
15396 my $Title = "Problems with Data Types, $TargetSeverity Severity";
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015397 if($TargetSeverity eq "Safe")
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015398 { # Safe Changes
15399 $Title = "Other Changes in Data Types";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015400 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015401 $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 +040015402 }
15403 }
15404 return $TYPE_PROBLEMS;
15405}
15406
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015407sub get_Anchor($$$)
15408{
15409 my ($Kind, $Level, $Severity) = @_;
15410 if($JoinReport)
15411 {
15412 if($Severity eq "Safe") {
15413 return "Other_".$Level."_Changes_In_".$Kind."s";
15414 }
15415 else {
15416 return $Kind."_".$Level."_Problems_".$Severity;
15417 }
15418 }
15419 else
15420 {
15421 if($Severity eq "Safe") {
15422 return "Other_Changes_In_".$Kind."s";
15423 }
15424 else {
15425 return $Kind."_Problems_".$Severity;
15426 }
15427 }
15428}
15429
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015430sub showVTables($)
15431{
15432 my $TypeName = $_[0];
15433 my $TypeId1 = $TName_Tid{1}{$TypeName};
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040015434 my %Type1 = get_Type($TypeId1, 1);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015435 if(defined $Type1{"VTable"}
15436 and keys(%{$Type1{"VTable"}}))
15437 {
15438 my $TypeId2 = $TName_Tid{2}{$TypeName};
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040015439 my %Type2 = get_Type($TypeId2, 2);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015440 if(defined $Type2{"VTable"}
15441 and keys(%{$Type2{"VTable"}}))
15442 {
15443 my %Indexes = map {$_=>1} (keys(%{$Type1{"VTable"}}), keys(%{$Type2{"VTable"}}));
15444 my %Entries = ();
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015445 foreach my $Index (sort {int($a)<=>int($b)} (keys(%Indexes)))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015446 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015447 $Entries{$Index}{"E1"} = simpleVEntry($Type1{"VTable"}{$Index});
15448 $Entries{$Index}{"E2"} = simpleVEntry($Type2{"VTable"}{$Index});
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015449 }
15450 my $VTABLES = "";
15451 if($ReportFormat eq "xml")
15452 { # XML
15453 $VTABLES .= " <vtable>\n";
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015454 foreach my $Index (sort {int($a)<=>int($b)} (keys(%Entries)))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015455 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015456 $VTABLES .= " <entry offset=\"".$Index."\">\n";
Andrey Ponomarenko5c09ef32012-06-14 18:17:33 +040015457 $VTABLES .= " <old>".xmlSpecChars($Entries{$Index}{"E1"})."</old>\n";
15458 $VTABLES .= " <new>".xmlSpecChars($Entries{$Index}{"E2"})."</new>\n";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015459 $VTABLES .= " </entry>\n";
15460 }
15461 $VTABLES .= " </vtable>\n\n";
15462 }
15463 else
15464 { # HTML
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015465 $VTABLES .= "<table class='vtable'>";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015466 $VTABLES .= "<tr><th width='2%'>Offset</th>";
15467 $VTABLES .= "<th width='45%'>Virtual Table (Old) - ".(keys(%{$Type1{"VTable"}}))." entries</th>";
15468 $VTABLES .= "<th>Virtual Table (New) - ".(keys(%{$Type2{"VTable"}}))." entries</th></tr>";
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015469 foreach my $Index (sort {int($a)<=>int($b)} (keys(%Entries)))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015470 {
15471 my ($Color1, $Color2) = ("", "");
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015472 if($Entries{$Index}{"E1"} ne $Entries{$Index}{"E2"})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015473 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015474 if($Entries{$Index}{"E1"})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015475 {
Andrey Ponomarenko16934472012-03-29 15:37:04 +040015476 $Color1 = " class='failed'";
15477 $Color2 = " class='failed'";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015478 }
15479 else {
Andrey Ponomarenko16934472012-03-29 15:37:04 +040015480 $Color2 = " class='warning'";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015481 }
15482 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015483 $VTABLES .= "<tr><th>".$Index."</th>\n";
15484 $VTABLES .= "<td$Color1>".htmlSpecChars($Entries{$Index}{"E1"})."</td>\n";
15485 $VTABLES .= "<td$Color2>".htmlSpecChars($Entries{$Index}{"E2"})."</td></tr>\n";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015486 }
15487 $VTABLES .= "</table><br/>\n";
15488 $VTABLES = $ContentDivStart.$VTABLES.$ContentDivEnd;
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015489 $VTABLES = $ContentSpanStart_Info."[+] show v-table (old and new)".$ContentSpanEnd."<br/>\n".$VTABLES;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015490 }
15491 return $VTABLES;
15492 }
15493 }
15494 return "";
15495}
15496
15497sub simpleVEntry($)
15498{
15499 my $VEntry = $_[0];
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040015500 if(not defined $VEntry
15501 or $VEntry eq "") {
15502 return "";
15503 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015504 $VEntry=~s/\A(.+)::(_ZThn.+)\Z/$2/; # thunks
15505 $VEntry=~s/_ZTI\w+/typeinfo/g; # typeinfo
15506 if($VEntry=~/\A_ZThn.+\Z/) {
15507 $VEntry = "non-virtual thunk";
15508 }
15509 $VEntry=~s/\A\(int \(\*\)\(...\)\)([^\(\d])/$1/i;
15510 # support for old GCC versions
15511 $VEntry=~s/\A0u\Z/(int (*)(...))0/;
15512 $VEntry=~s/\A4294967268u\Z/(int (*)(...))-0x000000004/;
15513 $VEntry=~s/\A&_Z\Z/& _Z/;
15514 # templates
15515 if($VEntry=~s/ \[with (\w+) = (.+?)(, [^=]+ = .+|])\Z//g)
15516 { # std::basic_streambuf<_CharT, _Traits>::imbue [with _CharT = char, _Traits = std::char_traits<char>]
15517 # become std::basic_streambuf<char, ...>::imbue
15518 my ($Pname, $Pval) = ($1, $2);
15519 if($Pname eq "_CharT" and $VEntry=~/\Astd::/)
15520 { # stdc++ typedefs
15521 $VEntry=~s/<$Pname(, [^<>]+|)>/<$Pval>/g;
15522 # FIXME: simplify names using stdcxx typedefs (StdCxxTypedef)
15523 # The typedef info should be added to ABI dumps
15524 }
15525 else
15526 {
15527 $VEntry=~s/<$Pname>/<$Pval>/g;
15528 $VEntry=~s/<$Pname, [^<>]+>/<$Pval, ...>/g;
15529 }
15530 }
15531 $VEntry=~s/([^:]+)::\~([^:]+)\Z/~$1/; # destructors
15532 return $VEntry;
15533}
15534
Andrey Ponomarenko85043792012-05-14 16:48:07 +040015535sub getAffectedSymbols($$$$)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015536{
Andrey Ponomarenko85043792012-05-14 16:48:07 +040015537 my ($Level, $Target_TypeName, $Kinds_Locations, $Syms) = @_;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015538 my $LIMIT = 1000;
Andrey Ponomarenko85043792012-05-14 16:48:07 +040015539 if($#{$Syms}>=10000)
15540 { # reduce size of the report
15541 $LIMIT = 10;
15542 }
15543 my %SProblems = ();
15544 foreach my $Symbol (@{$Syms})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015545 {
Andrey Ponomarenko85043792012-05-14 16:48:07 +040015546 if(keys(%SProblems)>$LIMIT) {
15547 last;
15548 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015549 if(($Symbol=~/C2E|D2E|D0E/))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015550 { # duplicated problems for C2 constructors, D2 and D0 destructors
15551 next;
15552 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015553 my ($SN, $SS, $SV) = separate_symbol($Symbol);
15554 if($Level eq "Source")
15555 { # remove symbol version
15556 $Symbol=$SN;
15557 }
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040015558 my ($MinPath_Length, $ProblemLocation_Last) = (-1, "");
15559 my $Severity_Max = 0;
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015560 my $Signature = get_Signature($Symbol, 1);
15561 foreach my $Kind (keys(%{$CompatProblems{$Level}{$Symbol}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015562 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015563 foreach my $Location (keys(%{$CompatProblems{$Level}{$Symbol}{$Kind}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015564 {
15565 if(not defined $Kinds_Locations->{$Kind}
15566 or not $Kinds_Locations->{$Kind}{$Location}) {
15567 next;
15568 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015569 if($SV and defined $CompatProblems{$Level}{$SN}
15570 and defined $CompatProblems{$Level}{$SN}{$Kind}{$Location})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015571 { # duplicated problems for versioned symbols
15572 next;
15573 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015574 my $Type_Name = $CompatProblems{$Level}{$Symbol}{$Kind}{$Location}{"Type_Name"};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015575 next if($Type_Name ne $Target_TypeName);
15576
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015577 my $Position = $CompatProblems{$Level}{$Symbol}{$Kind}{$Location}{"Param_Pos"};
15578 my $Param_Name = $CompatProblems{$Level}{$Symbol}{$Kind}{$Location}{"Param_Name"};
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040015579 my $Severity = getProblemSeverity($Level, $Kind);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015580 my $Path_Length = 0;
15581 my $ProblemLocation = $Location;
15582 if($Type_Name) {
15583 $ProblemLocation=~s/->\Q$Type_Name\E\Z//g;
15584 }
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040015585 while($ProblemLocation=~/\-\>/g) {
15586 $Path_Length += 1;
15587 }
15588 if($MinPath_Length==-1 or ($Path_Length<=$MinPath_Length and $Severity_Val{$Severity}>$Severity_Max)
15589 or (cmp_locations($ProblemLocation, $ProblemLocation_Last) and $Severity_Val{$Severity}==$Severity_Max))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015590 {
15591 $MinPath_Length = $Path_Length;
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040015592 $Severity_Max = $Severity_Val{$Severity};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015593 $ProblemLocation_Last = $ProblemLocation;
Andrey Ponomarenko85043792012-05-14 16:48:07 +040015594 %{$SProblems{$Symbol}} = (
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040015595 "Descr"=>getAffectDescription($Level, $Symbol, $Kind, $Location),
15596 "Severity_Max"=>$Severity_Max,
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015597 "Signature"=>$Signature,
15598 "Position"=>$Position,
15599 "Param_Name"=>$Param_Name,
15600 "Location"=>$Location
15601 );
15602 }
15603 }
15604 }
15605 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +040015606 my @Symbols = keys(%SProblems);
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015607 @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 +040015608 @Symbols = sort {$SProblems{$b}{"Severity_Max"}<=>$SProblems{$a}{"Severity_Max"}} @Symbols;
15609 if($#Symbols+1>$LIMIT)
15610 { # remove last element
15611 pop(@Symbols);
15612 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015613 my $Affected = "";
15614 if($ReportFormat eq "xml")
15615 { # XML
15616 $Affected .= " <affected>\n";
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015617 foreach my $Symbol (@Symbols)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015618 {
Andrey Ponomarenko85043792012-05-14 16:48:07 +040015619 my $Param_Name = $SProblems{$Symbol}{"Param_Name"};
15620 my $Description = $SProblems{$Symbol}{"Descr"};
15621 my $Location = $SProblems{$Symbol}{"Location"};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015622 my $Target = "";
15623 if($Param_Name) {
15624 $Target = " affected=\"param\" param_name=\"$Param_Name\"";
15625 }
15626 elsif($Location=~/\Aretval(\-|\Z)/i) {
15627 $Target = " affected=\"retval\"";
15628 }
15629 elsif($Location=~/\Athis(\-|\Z)/i) {
15630 $Target = " affected=\"this\"";
15631 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015632 $Affected .= " <symbol$Target name=\"$Symbol\">\n";
Andrey Ponomarenko5c09ef32012-06-14 18:17:33 +040015633 $Affected .= " <comment>".xmlSpecChars($Description)."</comment>\n";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015634 $Affected .= " </symbol>\n";
15635 }
15636 $Affected .= " </affected>\n";
15637 }
15638 else
15639 { # HTML
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015640 foreach my $Symbol (@Symbols)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015641 {
Andrey Ponomarenko85043792012-05-14 16:48:07 +040015642 my $Description = $SProblems{$Symbol}{"Descr"};
15643 my $Signature = $SProblems{$Symbol}{"Signature"};
15644 my $Pos = $SProblems{$Symbol}{"Position"};
Andrey Ponomarenkoa01311b2012-06-08 17:20:02 +040015645 $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 +040015646 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +040015647 if(keys(%SProblems)>$LIMIT) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015648 $Affected .= "and others ...<br/>";
15649 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +040015650 $Affected = "<div class='affected'>".$Affected."</div>";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015651 if($Affected)
15652 {
15653 $Affected = $ContentDivStart.$Affected.$ContentDivEnd;
Andrey Ponomarenko85043792012-05-14 16:48:07 +040015654 $Affected = $ContentSpanStart_Affected."[+] affected symbols (".(keys(%SProblems)>$LIMIT?">".$LIMIT:keys(%SProblems)).")".$ContentSpanEnd.$Affected;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015655 }
15656 }
15657 return $Affected;
15658}
15659
15660sub cmp_locations($$)
15661{
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040015662 my ($L1, $L2) = @_;
15663 if($L2=~/\b(retval|this)\b/
15664 and $L1!~/\b(retval|this)\b/ and $L1!~/\-\>/) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015665 return 1;
15666 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040015667 if($L2=~/\b(retval|this)\b/ and $L2=~/\-\>/
15668 and $L1!~/\b(retval|this)\b/ and $L1=~/\-\>/) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015669 return 1;
15670 }
15671 return 0;
15672}
15673
15674sub getAffectDescription($$$$)
15675{
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015676 my ($Level, $Symbol, $Kind, $Location) = @_;
15677 my %Problem = %{$CompatProblems{$Level}{$Symbol}{$Kind}{$Location}};
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040015678 my $PPos = showPos($Problem{"Param_Pos"});
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015679 my @Sentence = ();
15680 $Location=~s/\A(.*)\-\>.+?\Z/$1/;
15681 if($Kind eq "Overridden_Virtual_Method"
15682 or $Kind eq "Overridden_Virtual_Method_B") {
15683 push(@Sentence, "The method '".$Problem{"New_Value"}."' will be called instead of this method.");
15684 }
15685 elsif($CompatRules{$Level}{$Kind}{"Kind"} eq "Types")
15686 {
15687 if($Location eq "this" or $Kind=~/(\A|_)Virtual(_|\Z)/)
15688 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015689 my $METHOD_TYPE = $CompleteSignature{1}{$Symbol}{"Constructor"}?"constructor":"method";
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040015690 my $ClassName = $TypeInfo{1}{$CompleteSignature{1}{$Symbol}{"Class"}}{"Name"};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015691 if($ClassName eq $Problem{"Type_Name"}) {
15692 push(@Sentence, "This $METHOD_TYPE is from \'".$Problem{"Type_Name"}."\' class.");
15693 }
15694 else {
15695 push(@Sentence, "This $METHOD_TYPE is from derived class \'".$ClassName."\'.");
15696 }
15697 }
15698 else
15699 {
15700 if($Location=~/retval/)
15701 { # return value
15702 if($Location=~/\-\>/) {
15703 push(@Sentence, "Field \'".$Location."\' in return value");
15704 }
15705 else {
15706 push(@Sentence, "Return value");
15707 }
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040015708 if(my $Init = $Problem{"InitialType_Type"})
15709 {
15710 if($Init eq "Pointer") {
15711 push(@Sentence, "(pointer)");
15712 }
15713 elsif($Init eq "Ref") {
15714 push(@Sentence, "(reference)");
15715 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015716 }
15717 }
15718 elsif($Location=~/this/)
15719 { # "this" pointer
15720 if($Location=~/\-\>/) {
15721 push(@Sentence, "Field \'".$Location."\' in the object of this method");
15722 }
15723 else {
15724 push(@Sentence, "\'this\' pointer");
15725 }
15726 }
15727 else
15728 { # parameters
15729 if($Location=~/\-\>/) {
15730 push(@Sentence, "Field \'".$Location."\' in $PPos parameter");
15731 }
15732 else {
15733 push(@Sentence, "$PPos parameter");
15734 }
15735 if($Problem{"Param_Name"}) {
15736 push(@Sentence, "\'".$Problem{"Param_Name"}."\'");
15737 }
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040015738 if(my $Init = $Problem{"InitialType_Type"})
15739 {
15740 if($Init eq "Pointer") {
15741 push(@Sentence, "(pointer)");
15742 }
15743 elsif($Init eq "Ref") {
15744 push(@Sentence, "(reference)");
15745 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015746 }
15747 }
15748 if($Location eq "this") {
15749 push(@Sentence, "has base type \'".$Problem{"Type_Name"}."\'.");
15750 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040015751 elsif(defined $Problem{"Start_Type_Name"}
15752 and $Problem{"Start_Type_Name"} eq $Problem{"Type_Name"}) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015753 push(@Sentence, "has type \'".$Problem{"Type_Name"}."\'.");
15754 }
15755 else {
15756 push(@Sentence, "has base type \'".$Problem{"Type_Name"}."\'.");
15757 }
15758 }
15759 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040015760 if($ExtendedSymbols{$Symbol}) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015761 push(@Sentence, " This is a symbol from an artificial external library that may use the \'$TargetLibraryName\' library and change its ABI after recompiling.");
15762 }
15763 return join(" ", @Sentence);
15764}
15765
15766sub get_XmlSign($$)
15767{
15768 my ($Symbol, $LibVersion) = @_;
15769 my $Info = $CompleteSignature{$LibVersion}{$Symbol};
15770 my $Report = "";
15771 foreach my $Pos (sort {int($a)<=>int($b)} keys(%{$Info->{"Param"}}))
15772 {
15773 my $Name = $Info->{"Param"}{$Pos}{"name"};
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040015774 my $Type = $Info->{"Param"}{$Pos}{"type"};
15775 my $TypeName = $TypeInfo{$LibVersion}{$Type}{"Name"};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015776 foreach my $Typedef (keys(%ChangedTypedef))
15777 {
15778 my $Base = $Typedef_BaseName{$LibVersion}{$Typedef};
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040015779 $TypeName=~s/\b\Q$Typedef\E\b/$Base/g;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015780 }
15781 $Report .= " <param pos=\"$Pos\">\n";
15782 $Report .= " <name>".$Name."</name>\n";
Andrey Ponomarenko5c09ef32012-06-14 18:17:33 +040015783 $Report .= " <type>".xmlSpecChars($TypeName)."</type>\n";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015784 $Report .= " </param>\n";
15785 }
15786 if(my $Return = $Info->{"Return"})
15787 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040015788 my $RTName = $TypeInfo{$LibVersion}{$Return}{"Name"};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015789 $Report .= " <retval>\n";
Andrey Ponomarenko5c09ef32012-06-14 18:17:33 +040015790 $Report .= " <type>".xmlSpecChars($RTName)."</type>\n";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015791 $Report .= " </retval>\n";
15792 }
15793 return $Report;
15794}
15795
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015796sub get_Report_SymbolsInfo($)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015797{
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015798 my $Level = $_[0];
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015799 my $Report = "<symbols_info>\n";
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015800 foreach my $Symbol (sort keys(%{$CompatProblems{$Level}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015801 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015802 my ($SN, $SS, $SV) = separate_symbol($Symbol);
15803 if($SV and defined $CompatProblems{$Level}{$SN}) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015804 next;
15805 }
15806 $Report .= " <symbol name=\"$Symbol\">\n";
15807 my ($S1, $P1, $S2, $P2) = ();
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015808 if(not $AddedInt{$Level}{$Symbol})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015809 {
15810 if(defined $CompleteSignature{1}{$Symbol}
15811 and defined $CompleteSignature{1}{$Symbol}{"Header"})
15812 {
15813 $P1 = get_XmlSign($Symbol, 1);
15814 $S1 = get_Signature($Symbol, 1);
15815 }
15816 elsif($Symbol=~/\A(_Z|\?)/) {
15817 $S1 = $tr_name{$Symbol};
15818 }
15819 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015820 if(not $RemovedInt{$Level}{$Symbol})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015821 {
15822 if(defined $CompleteSignature{2}{$Symbol}
15823 and defined $CompleteSignature{2}{$Symbol}{"Header"})
15824 {
15825 $P2 = get_XmlSign($Symbol, 2);
15826 $S2 = get_Signature($Symbol, 2);
15827 }
15828 elsif($Symbol=~/\A(_Z|\?)/) {
15829 $S2 = $tr_name{$Symbol};
15830 }
15831 }
15832 if($S1)
15833 {
Andrey Ponomarenko5c09ef32012-06-14 18:17:33 +040015834 $Report .= " <old signature=\"".xmlSpecChars($S1)."\">\n";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015835 $Report .= $P1;
15836 $Report .= " </old>\n";
15837 }
15838 if($S2 and $S2 ne $S1)
15839 {
Andrey Ponomarenko5c09ef32012-06-14 18:17:33 +040015840 $Report .= " <new signature=\"".xmlSpecChars($S2)."\">\n";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015841 $Report .= $P2;
15842 $Report .= " </new>\n";
15843 }
15844 $Report .= " </symbol>\n";
15845 }
15846 $Report .= "</symbols_info>\n";
15847 return $Report;
15848}
15849
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015850sub writeReport($$)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015851{
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015852 my ($Level, $Report) = @_;
15853 if($ReportFormat eq "xml") {
15854 $Report = "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n".$Report;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015855 }
15856 if($StdOut)
15857 { # --stdout option
15858 print STDOUT $Report;
15859 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015860 else
15861 {
15862 my $RPath = getReportPath($Level);
Andrey Ponomarenko85043792012-05-14 16:48:07 +040015863 mkpath(get_dirname($RPath));
15864
15865 open(REPORT, ">", $RPath) || die ("can't open file \'$RPath\': $!\n");
15866 print REPORT $Report;
15867 close(REPORT);
15868
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040015869 if($Browse or $OpenReport)
15870 { # open in browser
15871 openReport($RPath);
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015872 if($JoinReport or $DoubleReport)
15873 {
15874 if($Level eq "Binary")
15875 { # wait to open a browser
15876 sleep(1);
15877 }
15878 }
15879 }
15880 }
15881}
15882
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040015883sub openReport($)
15884{
15885 my $Path = $_[0];
15886 my $Cmd = "";
15887 if($Browse)
15888 { # user-defined browser
Andrey Ponomarenkoa01311b2012-06-08 17:20:02 +040015889 $Cmd = $Browse." \"$Path\"";
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040015890 }
15891 if(not $Cmd)
15892 { # default browser
15893 if($OSgroup eq "macos") {
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +040015894 $Cmd = "open \"$Path\"";
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040015895 }
15896 elsif($OSgroup eq "windows") {
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +040015897 $Cmd = "start ".path_format($Path, $OSgroup);
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040015898 }
15899 else
15900 { # linux, freebsd, solaris
15901 my @Browsers = (
15902 "x-www-browser",
15903 "sensible-browser",
15904 "firefox",
15905 "opera",
15906 "xdg-open",
15907 "lynx",
15908 "links"
15909 );
15910 foreach my $Br (@Browsers)
15911 {
15912 if($Br = get_CmdPath($Br))
15913 {
Andrey Ponomarenkoa01311b2012-06-08 17:20:02 +040015914 $Cmd = $Br." \"$Path\"";
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040015915 last;
15916 }
15917 }
15918 }
15919 }
15920 if($Cmd)
15921 {
15922 if($Debug) {
15923 printMsg("INFO", "running $Cmd");
15924 }
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +040015925 if($OSgroup ne "windows"
15926 and $OSgroup ne "macos")
15927 {
15928 if($Cmd!~/lynx|links/) {
15929 $Cmd .= " >\"$TMP_DIR/null\" 2>&1 &";
15930 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040015931 }
15932 system($Cmd);
15933 }
15934 else {
15935 printMsg("ERROR", "cannot open report in browser");
15936 }
15937}
15938
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015939sub getReport($)
15940{
15941 my $Level = $_[0];
15942 if($ReportFormat eq "xml")
15943 { # XML
15944
15945 if($Level eq "Join")
15946 {
15947 my $Report = "<reports>\n";
15948 $Report .= getReport("Binary");
15949 $Report .= getReport("Source");
15950 $Report .= "</reports>\n";
15951 return $Report;
15952 }
15953 else
15954 {
15955 my $Report = "<report kind=\"".lc($Level)."\" version=\"$XML_REPORT_VERSION\">\n\n";
15956 my ($Summary, $MetaData) = get_Summary($Level);
15957 $Report .= $Summary."\n";
15958 $Report .= get_Report_Added($Level).get_Report_Removed($Level);
15959 $Report .= get_Report_Problems("High", $Level).get_Report_Problems("Medium", $Level).get_Report_Problems("Low", $Level).get_Report_Problems("Safe", $Level);
15960 $Report .= get_Report_SymbolsInfo($Level);
15961 $Report .= "</report>\n";
15962 return $Report;
15963 }
15964 }
15965 else
15966 { # HTML
15967 my $CssStyles = readModule("Styles", "Report.css");
15968 my $JScripts = readModule("Scripts", "Sections.js");
15969 if($Level eq "Join")
15970 {
15971 $CssStyles .= "\n".readModule("Styles", "Tabs.css");
15972 $JScripts .= "\n".readModule("Scripts", "Tabs.js");
Andrey Ponomarenkob8d203d2012-05-25 18:11:07 +040015973 my $Title = $TargetLibraryFName.": ".$Descriptor{1}{"Version"}." to ".$Descriptor{2}{"Version"}." compatibility report";
15974 my $Keywords = $TargetLibraryFName.", compatibility, API, report";
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015975 my $Description = "Compatibility report for the $TargetLibraryFName $TargetComponent between ".$Descriptor{1}{"Version"}." and ".$Descriptor{2}{"Version"}." versions";
15976 my ($BSummary, $BMetaData) = get_Summary("Binary");
15977 my ($SSummary, $SMetaData) = get_Summary("Source");
15978 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>";
15979 $Report .= get_Report_Header("Join")."
15980 <br/><div class='tabset'>
Andrey Ponomarenko16934472012-03-29 15:37:04 +040015981 <a id='BinaryID' href='#BinaryTab' class='tab active'>Binary<br/>Compatibility</a>
15982 <a id='SourceID' href='#SourceTab' style='margin-left:3px' class='tab disabled'>Source<br/>Compatibility</a>
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015983 </div>";
15984 $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>";
15985 $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 +040015986 $Report .= getReportFooter($TargetLibraryFName, not $JoinReport);
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015987 $Report .= "\n<div style='height:999px;'></div>\n</body></html>";
15988 return $Report;
15989 }
15990 else
15991 {
15992 my ($Summary, $MetaData) = get_Summary($Level);
Andrey Ponomarenkob8d203d2012-05-25 18:11:07 +040015993 my $Title = $TargetLibraryFName.": ".$Descriptor{1}{"Version"}." to ".$Descriptor{2}{"Version"}." ".lc($Level)." compatibility report";
15994 my $Keywords = $TargetLibraryFName.", ".lc($Level)." compatibility, API, report";
15995 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 +040015996 if($Level eq "Binary")
15997 {
15998 if(getArch(1) eq getArch(2)
15999 and getArch(1) ne "unknown") {
16000 $Description .= " on ".showArch(getArch(1));
16001 }
16002 }
16003 my $Report = "<!-\- $MetaData -\->\n".composeHTML_Head($Title, $Keywords, $Description, $CssStyles, $JScripts)."\n<body>\n<div><a name='Top'></a>\n";
16004 $Report .= get_Report_Header($Level)."\n".$Summary."\n";
16005 $Report .= get_Report_Added($Level).get_Report_Removed($Level);
16006 $Report .= get_Report_Problems("High", $Level).get_Report_Problems("Medium", $Level).get_Report_Problems("Low", $Level).get_Report_Problems("Safe", $Level);
16007 $Report .= get_SourceInfo();
16008 $Report .= "</div>\n<br/><br/><br/><hr/>\n";
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040016009 $Report .= getReportFooter($TargetLibraryFName, not $JoinReport);
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040016010 $Report .= "\n<div style='height:999px;'></div>\n</body></html>";
16011 return $Report;
16012 }
16013 }
16014}
16015
Andrey Ponomarenko16934472012-03-29 15:37:04 +040016016sub getLegend()
16017{
16018 return "<br/>
16019<table class='summary'>
16020<tr>
16021 <td class='new'>added</td>
16022 <td class='passed'>compatible</td>
16023</tr>
16024<tr>
16025 <td class='warning'>warning</td>
16026 <td class='failed'>incompatible</td>
16027</tr></table>\n";
16028}
16029
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040016030sub createReport()
16031{
16032 if($JoinReport)
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040016033 { # --stdout
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040016034 writeReport("Join", getReport("Join"));
16035 }
16036 elsif($DoubleReport)
16037 { # default
16038 writeReport("Binary", getReport("Binary"));
16039 writeReport("Source", getReport("Source"));
16040 }
16041 elsif($BinaryOnly)
16042 { # --binary
16043 writeReport("Binary", getReport("Binary"));
16044 }
16045 elsif($SourceOnly)
16046 { # --source
16047 writeReport("Source", getReport("Source"));
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040016048 }
16049}
16050
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040016051sub getReportFooter($$)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040016052{
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040016053 my ($LibName, $Wide) = @_;
16054 my $FooterStyle = $Wide?"width:99%":"width:97%;padding-top:3px";
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040016055 my $Footer = "<div style='$FooterStyle;font-size:11px;' align='right'><i>Generated on ".(localtime time); # report date
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040016056 $Footer .= " for <span style='font-weight:bold'>$LibName</span>"; # tested library/system name
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040016057 $Footer .= " by <a href='".$HomePage{"Wiki"}."'>ABI Compliance Checker</a>"; # tool name
16058 my $ToolSummary = "<br/>A tool for checking backward compatibility of a C/C++ library API&#160;&#160;";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040016059 $Footer .= " $TOOL_VERSION &#160;$ToolSummary</i></div>"; # tool version
16060 return $Footer;
16061}
16062
16063sub get_Report_Problems($$)
16064{
16065 my ($Priority, $Level) = @_;
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040016066 my $Report = get_Report_TypeProblems($Priority, $Level);
Andrey Ponomarenko16934472012-03-29 15:37:04 +040016067 if(my $SProblems = get_Report_SymbolProblems($Priority, $Level)) {
16068 $Report .= $SProblems;
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040016069 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040016070 if($Priority eq "Low")
16071 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040016072 $Report .= get_Report_ChangedConstants($Level);
Andrey Ponomarenko82bc2572012-11-14 13:55:30 +040016073 if($ReportFormat eq "html")
16074 {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040016075 if($CheckImpl and $Level eq "Binary") {
16076 $Report .= get_Report_Impl();
16077 }
16078 }
16079 }
16080 if($ReportFormat eq "html")
16081 {
16082 if($Report)
16083 { # add anchor
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040016084 if($JoinReport)
16085 {
16086 if($Priority eq "Safe") {
16087 $Report = "<a name=\'Other_".$Level."_Changes\'></a>".$Report;
16088 }
16089 else {
16090 $Report = "<a name=\'".$Priority."_Risk_".$Level."_Problems\'></a>".$Report;
16091 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040016092 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040016093 else
16094 {
16095 if($Priority eq "Safe") {
16096 $Report = "<a name=\'Other_Changes\'></a>".$Report;
16097 }
16098 else {
16099 $Report = "<a name=\'".$Priority."_Risk_Problems\'></a>".$Report;
16100 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040016101 }
16102 }
16103 }
16104 return $Report;
16105}
16106
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040016107sub composeHTML_Head($$$$$)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040016108{
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040016109 my ($Title, $Keywords, $Description, $Styles, $Scripts) = @_;
16110 return "<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.0 Transitional//EN\" \"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd\">
16111 <html xmlns=\"http://www.w3.org/1999/xhtml\" xml:lang=\"en\" lang=\"en\">
16112 <head>
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040016113 <meta http-equiv=\"Content-Type\" content=\"text/html; charset=utf-8\" />
16114 <meta name=\"keywords\" content=\"$Keywords\" />
16115 <meta name=\"description\" content=\"$Description\" />
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040016116 <title>
16117 $Title
16118 </title>
16119 <style type=\"text/css\">
16120 $Styles
16121 </style>
16122 <script type=\"text/javascript\" language=\"JavaScript\">
16123 <!--
16124 $Scripts
16125 -->
16126 </script>
16127 </head>";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040016128}
16129
16130sub insertIDs($)
16131{
16132 my $Text = $_[0];
16133 while($Text=~/CONTENT_ID/)
16134 {
16135 if(int($Content_Counter)%2) {
16136 $ContentID -= 1;
16137 }
16138 $Text=~s/CONTENT_ID/c_$ContentID/;
16139 $ContentID += 1;
16140 $Content_Counter += 1;
16141 }
16142 return $Text;
16143}
16144
16145sub checkPreprocessedUnit($)
16146{
16147 my $Path = $_[0];
Andrey Ponomarenkoa01311b2012-06-08 17:20:02 +040016148 my ($CurHeader, $CurHeaderName) = ("", "");
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040016149 open(PREPROC, $Path) || die ("can't open file \'$Path\': $!\n");
Andrey Ponomarenkoa01311b2012-06-08 17:20:02 +040016150 while(my $Line = <PREPROC>)
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040016151 { # detecting public and private constants
Andrey Ponomarenkoa01311b2012-06-08 17:20:02 +040016152
16153 if(substr($Line, 0, 1) eq "#")
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040016154 {
Andrey Ponomarenkoa01311b2012-06-08 17:20:02 +040016155 chomp($Line);
16156 if($Line=~/\A\#\s+\d+\s+\"(.+)\"/)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040016157 {
Andrey Ponomarenkoa01311b2012-06-08 17:20:02 +040016158 $CurHeader = path_format($1, $OSgroup);
16159 $CurHeaderName = get_filename($CurHeader);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040016160 }
Andrey Ponomarenkoa01311b2012-06-08 17:20:02 +040016161 if(not $Include_Neighbors{$Version}{$CurHeaderName}
16162 and not $Registered_Headers{$Version}{$CurHeader})
16163 { # not a target
16164 next;
16165 }
16166 if(not is_target_header($CurHeaderName, 1)
16167 and not is_target_header($CurHeaderName, 2))
16168 { # user-defined header
16169 next;
16170 }
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040016171 if($Line=~/\A\#\s*define\s+(\w+)\s+(.+)\s*\Z/)
Andrey Ponomarenkoa01311b2012-06-08 17:20:02 +040016172 {
16173 my ($Name, $Value) = ($1, $2);
Andrey Ponomarenko82bc2572012-11-14 13:55:30 +040016174 # next if($Name eq $Value);
Andrey Ponomarenkoa01311b2012-06-08 17:20:02 +040016175 if(not $Constants{$Version}{$Name}{"Access"})
16176 {
16177 $Constants{$Version}{$Name}{"Access"} = "public";
16178 $Constants{$Version}{$Name}{"Value"} = $Value;
16179 $Constants{$Version}{$Name}{"Header"} = $CurHeaderName;
16180 }
16181 }
16182 elsif($Line=~/\A\#[ \t]*undef[ \t]+([_A-Z]+)[ \t]*/) {
16183 $Constants{$Version}{$1}{"Access"} = "private";
16184 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040016185 }
16186 }
16187 close(PREPROC);
16188 foreach my $Constant (keys(%{$Constants{$Version}}))
16189 {
Andrey Ponomarenkoa01311b2012-06-08 17:20:02 +040016190 if($Constants{$Version}{$Constant}{"Access"} eq "private"
16191 or $Constant=~/_h\Z/i
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040016192 or isBuiltIn($Constants{$Version}{$Constant}{"Header"}))
16193 { # skip private constants
16194 delete($Constants{$Version}{$Constant});
16195 }
16196 else {
16197 delete($Constants{$Version}{$Constant}{"Access"});
16198 }
16199 }
Andrey Ponomarenkoa01311b2012-06-08 17:20:02 +040016200 if($Debug)
16201 {
16202 mkpath($DEBUG_PATH{$Version});
16203 copy($Path, $DEBUG_PATH{$Version}."/preprocessor.txt");
16204 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040016205}
16206
Andrey Ponomarenko16934472012-03-29 15:37:04 +040016207sub uncoverConstant($$)
16208{
16209 my ($LibVersion, $Constant) = @_;
16210 return "" if(not $LibVersion or not $Constant);
16211 return $Constant if(isCyclical(\@RecurConstant, $Constant));
16212 if(defined $Cache{"uncoverConstant"}{$LibVersion}{$Constant}) {
16213 return $Cache{"uncoverConstant"}{$LibVersion}{$Constant};
16214 }
16215 my $Value = $Constants{$LibVersion}{$Constant}{"Value"};
16216 if(defined $Value)
16217 {
16218 if($Value=~/\A[A-Z0-9_]+\Z/ and $Value=~/[A-Z]/)
16219 {
16220 push(@RecurConstant, $Constant);
16221 my $Uncovered = uncoverConstant($LibVersion, $Value);
16222 if($Uncovered ne "") {
16223 $Value = $Uncovered;
16224 }
16225 pop(@RecurConstant);
16226 }
16227 # FIXME: uncover $Value using all the enum constants
16228 # USECASE: change of define NC_LONG from NC_INT (enum value) to NC_INT (define)
16229 return ($Cache{"uncoverConstant"}{$LibVersion}{$Constant} = $Value);
16230 }
16231 return ($Cache{"uncoverConstant"}{$LibVersion}{$Constant} = "");
16232}
16233
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040016234my %IgnoreConstant = map {$_=>1} (
16235 "VERSION",
16236 "VERSIONCODE",
16237 "VERNUM",
16238 "VERS_INFO",
16239 "PATCHLEVEL",
16240 "INSTALLPREFIX",
16241 "VBUILD",
16242 "VPATCH",
16243 "VMINOR",
16244 "BUILD_STRING",
16245 "BUILD_TIME",
16246 "PACKAGE_STRING",
16247 "PRODUCTION",
16248 "CONFIGURE_COMMAND",
16249 "INSTALLDIR",
16250 "BINDIR",
16251 "CONFIG_FILE_PATH",
16252 "DATADIR",
16253 "EXTENSION_DIR",
16254 "INCLUDE_PATH",
16255 "LIBDIR",
16256 "LOCALSTATEDIR",
16257 "SBINDIR",
16258 "SYSCONFDIR",
16259 "RELEASE",
16260 "SOURCE_ID",
16261 "SUBMINOR",
16262 "MINOR",
16263 "MINNOR",
16264 "MINORVERSION",
16265 "MAJOR",
16266 "MAJORVERSION",
16267 "MICRO",
16268 "MICROVERSION",
16269 "BINARY_AGE",
16270 "INTERFACE_AGE",
16271 "CORE_ABI",
16272 "PATCH",
16273 "COPYRIGHT",
16274 "TIMESTAMP",
16275 "REVISION",
16276 "PACKAGE_TAG",
16277 "PACKAGEDATE",
16278 "NUMVERSION",
16279 "Release",
16280 "Version"
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040016281);
16282
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040016283sub mergeConstants($)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040016284{
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040016285 my $Level = $_[0];
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040016286 foreach my $Constant (keys(%{$Constants{1}}))
16287 {
16288 if($SkipConstants{1}{$Constant})
16289 { # skipped by the user
16290 next;
16291 }
Andrey Ponomarenko16934472012-03-29 15:37:04 +040016292 if(not defined $Constants{2}{$Constant}{"Value"}
16293 or $Constants{2}{$Constant}{"Value"} eq "")
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040016294 { # empty value
16295 next;
16296 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +040016297 my $Header = $Constants{1}{$Constant}{"Header"};
16298 if(not is_target_header($Header, 1)
16299 and not is_target_header($Header, 2))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040016300 { # user-defined header
16301 next;
16302 }
16303 my ($Old_Value, $New_Value, $Old_Value_Pure, $New_Value_Pure);
Andrey Ponomarenko16934472012-03-29 15:37:04 +040016304 $Old_Value = $Old_Value_Pure = uncoverConstant(1, $Constant);
16305 $New_Value = $New_Value_Pure = uncoverConstant(2, $Constant);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040016306 $Old_Value_Pure=~s/(\W)\s+/$1/g;
16307 $Old_Value_Pure=~s/\s+(\W)/$1/g;
16308 $New_Value_Pure=~s/(\W)\s+/$1/g;
16309 $New_Value_Pure=~s/\s+(\W)/$1/g;
16310 next if($New_Value_Pure eq "" or $Old_Value_Pure eq "");
16311 if($New_Value_Pure ne $Old_Value_Pure)
16312 { # different values
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040016313 if($Level eq "Binary")
16314 {
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040016315 foreach (keys(%IgnoreConstant))
16316 {
16317 if($Constant=~/(\A|_)$_(_|\Z)/)
16318 { # ignore library version
16319 next;
16320 }
16321 if(/\A[A-Z].*[a-z]\Z/)
16322 {
16323 if($Constant=~/(\A|[a-z])$_([A-Z]|\Z)/)
16324 { # ignore library version
16325 next;
16326 }
16327 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040016328 }
16329 if($Constant=~/(\A|_)(lib|open|)$TargetLibraryShortName(_|)(VERSION|VER|DATE|API|PREFIX)(_|\Z)/i)
16330 { # ignore library version
16331 next;
16332 }
16333 if($Old_Value=~/\A('|"|)[\/\\]\w+([\/\\]|:|('|"|)\Z)/ or $Old_Value=~/[\/\\]\w+[\/\\]\w+/)
16334 { # ignoring path defines:
Andrey Ponomarenko85043792012-05-14 16:48:07 +040016335 # /lib64:/usr/lib64:/lib:/usr/lib:/usr/X11R6/lib/Xaw3d ...
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040016336 next;
16337 }
16338 if($Old_Value=~/\A\(*[a-z_]+(\s+|\|)/i)
16339 { # ignore source defines:
Andrey Ponomarenko85043792012-05-14 16:48:07 +040016340 # static int gcry_pth_init ( void) { return ...
16341 # (RE_BACKSLASH_ESCAPE_IN_LISTS | RE...
16342 next;
16343 }
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040016344 if($Old_Value=~/\(/i and $Old_Value!~/\A[\"\']/i)
Andrey Ponomarenko85043792012-05-14 16:48:07 +040016345 { # ignore source defines:
16346 # foo(p)
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040016347 next;
16348 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040016349 }
16350 if(convert_integer($Old_Value) eq convert_integer($New_Value))
16351 { # 0x0001 and 0x1, 0x1 and 1 equal constants
16352 next;
16353 }
16354 if($Old_Value eq "0" and $New_Value eq "NULL")
16355 { # 0 => NULL
16356 next;
16357 }
16358 if($Old_Value eq "NULL" and $New_Value eq "0")
16359 { # NULL => 0
16360 next;
16361 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040016362 %{$ProblemsWithConstants{$Level}{$Constant}} = (
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040016363 "Target"=>$Constant,
16364 "Old_Value"=>$Old_Value,
16365 "New_Value"=>$New_Value );
16366 }
16367 }
16368}
16369
16370sub convert_integer($)
16371{
16372 my $Value = $_[0];
16373 if($Value=~/\A0x[a-f0-9]+\Z/)
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040016374 { # hexadecimal
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040016375 return hex($Value);
16376 }
16377 elsif($Value=~/\A0[0-7]+\Z/)
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040016378 { # octal
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040016379 return oct($Value);
16380 }
16381 elsif($Value=~/\A0b[0-1]+\Z/)
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040016382 { # binary
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040016383 return oct($Value);
16384 }
16385 else {
16386 return $Value;
16387 }
16388}
16389
Andrey Ponomarenko16934472012-03-29 15:37:04 +040016390sub readSymbols($)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040016391{
16392 my $LibVersion = $_[0];
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040016393 my @LibPaths = getSOPaths($LibVersion);
Andrey Ponomarenko16934472012-03-29 15:37:04 +040016394 if($#LibPaths==-1 and not $CheckHeadersOnly)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040016395 {
16396 if($LibVersion==1)
16397 {
16398 printMsg("WARNING", "checking headers only");
16399 $CheckHeadersOnly = 1;
16400 }
16401 else {
16402 exitStatus("Error", "$SLIB_TYPE libraries are not found in ".$Descriptor{$LibVersion}{"Version"});
16403 }
16404 }
Andrey Ponomarenko16934472012-03-29 15:37:04 +040016405 foreach my $LibPath (sort {length($a)<=>length($b)} @LibPaths) {
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040016406 readSymbols_Lib($LibVersion, $LibPath, 0, "+Weak", 1, 1);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040016407 }
Andrey Ponomarenko16934472012-03-29 15:37:04 +040016408 if(not $CheckHeadersOnly)
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040016409 {
Andrey Ponomarenko16934472012-03-29 15:37:04 +040016410 if($#LibPaths!=-1)
16411 {
16412 if(not keys(%{$Symbol_Library{$LibVersion}}))
16413 {
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040016414 printMsg("WARNING", "the set of public symbols in library(ies) is empty ($LibVersion)");
Andrey Ponomarenko16934472012-03-29 15:37:04 +040016415 printMsg("WARNING", "checking headers only");
16416 $CheckHeadersOnly = 1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040016417 }
16418 }
16419 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +040016420
Andrey Ponomarenko07aea072012-11-12 16:15:07 +040016421 # clean memory
Andrey Ponomarenko85043792012-05-14 16:48:07 +040016422 %SystemObjects = ();
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040016423}
16424
Andrey Ponomarenko16934472012-03-29 15:37:04 +040016425sub getSymbolSize($$)
16426{ # size from the shared library
16427 my ($Symbol, $LibVersion) = @_;
16428 return 0 if(not $Symbol);
16429 if(defined $Symbol_Library{$LibVersion}{$Symbol}
16430 and my $LibName = $Symbol_Library{$LibVersion}{$Symbol})
16431 {
16432 if(defined $Library_Symbol{$LibVersion}{$LibName}{$Symbol}
16433 and my $Size = $Library_Symbol{$LibVersion}{$LibName}{$Symbol})
16434 {
16435 if($Size<0) {
16436 return -$Size;
16437 }
16438 }
16439 }
16440 return 0;
16441}
16442
Andrey Ponomarenko07aea072012-11-12 16:15:07 +040016443sub canonifyName($$)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040016444{ # make TIFFStreamOpen(char const*, std::basic_ostream<char, std::char_traits<char> >*)
16445 # to be TIFFStreamOpen(char const*, std::basic_ostream<char>*)
Andrey Ponomarenko07aea072012-11-12 16:15:07 +040016446 my ($Name, $Type) = @_;
16447
16448 # single
16449 while($Name=~/([^<>,]+),\s*$DEFAULT_STD_PARMS<([^<>,]+)>\s*/ and $1 eq $3)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040016450 {
Andrey Ponomarenko85043792012-05-14 16:48:07 +040016451 my $P = $1;
Andrey Ponomarenko07aea072012-11-12 16:15:07 +040016452 $Name=~s/\Q$P\E,\s*$DEFAULT_STD_PARMS<\Q$P\E>\s*/$P/g;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040016453 }
Andrey Ponomarenko07aea072012-11-12 16:15:07 +040016454
16455 # double
16456 if($Name=~/$DEFAULT_STD_PARMS/)
16457 {
Andrey Ponomarenkoe3d6bf02012-11-14 11:49:09 +040016458 if($Type eq "S")
Andrey Ponomarenko07aea072012-11-12 16:15:07 +040016459 {
16460 my ($ShortName, $FuncParams) = split_Signature($Name);
16461
16462 foreach my $FParam (separate_Params($FuncParams, 0, 0))
16463 {
16464 if(index($FParam, "<")!=-1)
16465 {
16466 $FParam=~s/>([^<>]+)\Z/>/; # remove quals
16467 my $FParam_N = canonifyName($FParam, "T");
16468 if($FParam_N ne $FParam) {
16469 $Name=~s/\Q$FParam\E/$FParam_N/g;
16470 }
16471 }
16472 }
16473 }
16474 elsif($Type eq "T")
16475 {
16476 my ($ShortTmpl, $TmplParams) = template_Base($Name);
16477
16478 my @TParams = separate_Params($TmplParams, 0, 0);
Andrey Ponomarenkoe3d6bf02012-11-14 11:49:09 +040016479 if($#TParams>=1)
Andrey Ponomarenko07aea072012-11-12 16:15:07 +040016480 {
Andrey Ponomarenkoe3d6bf02012-11-14 11:49:09 +040016481 my $FParam = $TParams[0];
16482 foreach my $Pos (1 .. $#TParams)
16483 {
16484 my $TParam = $TParams[$Pos];
16485 if($TParam=~/\A$DEFAULT_STD_PARMS<\Q$FParam\E\s*>\Z/) {
16486 $Name=~s/\Q$FParam, $TParam\E\s*/$FParam/g;
16487 }
Andrey Ponomarenko07aea072012-11-12 16:15:07 +040016488 }
Andrey Ponomarenko07aea072012-11-12 16:15:07 +040016489 }
16490 }
16491 }
Andrey Ponomarenkoe3d6bf02012-11-14 11:49:09 +040016492 if($Type eq "S") {
16493 return formatName($Name, "S");
16494 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040016495 return $Name;
16496}
16497
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040016498sub translateSymbols(@)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040016499{
16500 my $LibVersion = pop(@_);
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040016501 my (@MnglNames1, @MnglNames2, @UnmangledNames) = ();
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040016502 foreach my $Symbol (sort @_)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040016503 {
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040016504 if(index($Symbol, "_Z")==0)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040016505 {
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040016506 next if($tr_name{$Symbol});
16507 $Symbol=~s/[\@\$]+(.*)\Z//;
16508 push(@MnglNames1, $Symbol);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040016509 }
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040016510 elsif(index($Symbol, "?")==0) {
16511 push(@MnglNames2, $Symbol);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040016512 }
16513 else
16514 { # not mangled
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040016515 $tr_name{$Symbol} = $Symbol;
16516 $mangled_name_gcc{$Symbol} = $Symbol;
16517 $mangled_name{$LibVersion}{$Symbol} = $Symbol;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040016518 }
16519 }
16520 if($#MnglNames1 > -1)
16521 { # GCC names
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040016522 @UnmangledNames = reverse(unmangleArray(@MnglNames1));
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040016523 foreach my $MnglName (@MnglNames1)
16524 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040016525 if(my $Unmangled = pop(@UnmangledNames))
16526 {
Andrey Ponomarenko72930b92012-11-14 12:09:17 +040016527 $tr_name{$MnglName} = canonifyName($Unmangled, "S");
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040016528 if(not $mangled_name_gcc{$tr_name{$MnglName}}) {
16529 $mangled_name_gcc{$tr_name{$MnglName}} = $MnglName;
16530 }
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040016531 if(index($MnglName, "_ZTV")==0
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040016532 and $tr_name{$MnglName}=~/vtable for (.+)/)
16533 { # bind class name and v-table symbol
16534 my $ClassName = $1;
16535 $ClassVTable{$ClassName} = $MnglName;
16536 $VTableClass{$MnglName} = $ClassName;
16537 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040016538 }
16539 }
16540 }
16541 if($#MnglNames2 > -1)
16542 { # MSVC names
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040016543 @UnmangledNames = reverse(unmangleArray(@MnglNames2));
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040016544 foreach my $MnglName (@MnglNames2)
16545 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040016546 if(my $Unmangled = pop(@UnmangledNames))
16547 {
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040016548 $tr_name{$MnglName} = formatName($Unmangled, "S");
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040016549 $mangled_name{$LibVersion}{$tr_name{$MnglName}} = $MnglName;
16550 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040016551 }
16552 }
16553 return \%tr_name;
16554}
16555
16556sub link_symbol($$$)
16557{
16558 my ($Symbol, $RunWith, $Deps) = @_;
16559 if(link_symbol_internal($Symbol, $RunWith, \%Symbol_Library)) {
16560 return 1;
16561 }
16562 if($Deps eq "+Deps")
16563 { # check the dependencies
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040016564 if(link_symbol_internal($Symbol, $RunWith, \%DepSymbol_Library)) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040016565 return 1;
16566 }
16567 }
16568 return 0;
16569}
16570
16571sub link_symbol_internal($$$)
16572{
16573 my ($Symbol, $RunWith, $Where) = @_;
16574 return 0 if(not $Where or not $Symbol);
16575 if($Where->{$RunWith}{$Symbol})
16576 { # the exact match by symbol name
16577 return 1;
16578 }
16579 if(my $VSym = $SymVer{$RunWith}{$Symbol})
16580 { # indirect symbol version, i.e.
16581 # foo_old and its symlink foo@v (or foo@@v)
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040016582 # foo_old may be in symtab table
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040016583 if($Where->{$RunWith}{$VSym}) {
16584 return 1;
16585 }
16586 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040016587 my ($Sym, $Spec, $Ver) = separate_symbol($Symbol);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040016588 if($Sym and $Ver)
16589 { # search for the symbol with the same version
16590 # or without version
16591 if($Where->{$RunWith}{$Sym})
16592 { # old: foo@v|foo@@v
16593 # new: foo
16594 return 1;
16595 }
16596 if($Where->{$RunWith}{$Sym."\@".$Ver})
16597 { # old: foo|foo@@v
16598 # new: foo@v
16599 return 1;
16600 }
16601 if($Where->{$RunWith}{$Sym."\@\@".$Ver})
16602 { # old: foo|foo@v
16603 # new: foo@@v
16604 return 1;
16605 }
16606 }
16607 return 0;
16608}
16609
Andrey Ponomarenko16934472012-03-29 15:37:04 +040016610sub readSymbols_App($)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040016611{
16612 my $Path = $_[0];
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040016613 return () if(not $Path);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040016614 my @Imported = ();
16615 if($OSgroup eq "macos")
16616 {
Andrey Ponomarenko07aea072012-11-12 16:15:07 +040016617 my $NM = get_CmdPath("nm");
16618 if(not $NM) {
16619 exitStatus("Not_Found", "can't find \"nm\"");
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040016620 }
Andrey Ponomarenko07aea072012-11-12 16:15:07 +040016621 open(APP, "$NM -g \"$Path\" 2>\"$TMP_DIR/null\" |");
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040016622 while(<APP>)
16623 {
Andrey Ponomarenko07aea072012-11-12 16:15:07 +040016624 if(/ U _([\w\$]+)\s*\Z/) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040016625 push(@Imported, $1);
16626 }
16627 }
16628 close(APP);
16629 }
16630 elsif($OSgroup eq "windows")
16631 {
16632 my $DumpBinCmd = get_CmdPath("dumpbin");
16633 if(not $DumpBinCmd) {
16634 exitStatus("Not_Found", "can't find \"dumpbin.exe\"");
16635 }
Andrey Ponomarenkoa01311b2012-06-08 17:20:02 +040016636 open(APP, "$DumpBinCmd /IMPORTS \"$Path\" 2>\"$TMP_DIR/null\" |");
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040016637 while(<APP>)
16638 {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040016639 if(/\s*\w+\s+\w+\s+\w+\s+([\w\?\@]+)\s*/) {
16640 push(@Imported, $1);
16641 }
16642 }
16643 close(APP);
16644 }
16645 else
16646 {
16647 my $ReadelfCmd = get_CmdPath("readelf");
16648 if(not $ReadelfCmd) {
16649 exitStatus("Not_Found", "can't find \"readelf\"");
16650 }
Andrey Ponomarenkoa01311b2012-06-08 17:20:02 +040016651 open(APP, "$ReadelfCmd -WhlSsdA \"$Path\" 2>\"$TMP_DIR/null\" |");
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040016652 my $symtab = undef; # indicates that we are processing 'symtab' section of 'readelf' output
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040016653 while(<APP>)
16654 {
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040016655 if(defined $symtab)
16656 { # do nothing with symtab
16657 if(index($_, "'.dynsym'")!=-1)
16658 { # dynamic table
16659 $symtab = undef;
16660 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040016661 }
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040016662 elsif(index($_, "'.symtab'")!=-1)
16663 { # symbol table
16664 $symtab = 1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040016665 }
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040016666 elsif(my @Info = readline_ELF($_))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040016667 {
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040016668 my ($Ndx, $Symbol) = ($Info[5], $Info[6]);
16669 if($Ndx eq "UND")
16670 { # only imported symbols
16671 push(@Imported, $Symbol);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040016672 }
16673 }
16674 }
16675 close(APP);
16676 }
16677 return @Imported;
16678}
16679
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040016680my %ELF_BIND = map {$_=>1} (
16681 "WEAK",
16682 "GLOBAL"
16683);
16684
16685my %ELF_TYPE = map {$_=>1} (
16686 "FUNC",
16687 "IFUNC",
16688 "OBJECT",
16689 "COMMON"
16690);
16691
16692my %ELF_VIS = map {$_=>1} (
16693 "DEFAULT",
16694 "PROTECTED"
16695);
16696
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040016697sub readline_ELF($)
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040016698{ # read the line of 'readelf' output corresponding to the symbol
16699 my @Info = split(/\s+/, $_[0]);
16700 # Num: Value Size Type Bind Vis Ndx Name
16701 # 3629: 000b09c0 32 FUNC GLOBAL DEFAULT 13 _ZNSt12__basic_fileIcED1Ev@@GLIBCXX_3.4
16702 shift(@Info); # spaces
16703 shift(@Info); # num
16704 if($#Info!=6)
16705 { # other lines
16706 return ();
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040016707 }
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040016708 return () if(not defined $ELF_TYPE{$Info[2]});
16709 return () if(not defined $ELF_BIND{$Info[3]});
16710 return () if(not defined $ELF_VIS{$Info[4]});
16711 if($Info[5] eq "ABS" and $Info[0]=~/\A0+\Z/)
16712 { # 1272: 00000000 0 OBJECT GLOBAL DEFAULT ABS CXXABI_1.3
16713 return ();
16714 }
16715 if($OStarget eq "symbian")
16716 { # _ZN12CCTTokenType4NewLE4TUid3RFs@@ctfinder{000a0000}[102020e5].dll
16717 if(index($Info[6], "_._.absent_export_")!=-1)
16718 { # "_._.absent_export_111"@@libstdcpp{00010001}[10282872].dll
16719 return ();
16720 }
16721 $Info[6]=~s/\@.+//g; # remove version
16722 }
16723 if(index($Info[2], "0x") == 0)
16724 { # size == 0x3d158
16725 $Info[2] = hex($Info[2]);
16726 }
16727 return @Info;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040016728}
16729
Andrey Ponomarenko16934472012-03-29 15:37:04 +040016730sub read_symlink($)
16731{
16732 my $Path = $_[0];
Andrey Ponomarenko16934472012-03-29 15:37:04 +040016733 if(my $Res = readlink($Path)) {
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040016734 return $Res;
Andrey Ponomarenko16934472012-03-29 15:37:04 +040016735 }
16736 elsif(my $ReadlinkCmd = get_CmdPath("readlink")) {
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040016737 return `$ReadlinkCmd -n \"$Path\"`;
Andrey Ponomarenko16934472012-03-29 15:37:04 +040016738 }
16739 elsif(my $FileCmd = get_CmdPath("file"))
16740 {
Andrey Ponomarenkoa01311b2012-06-08 17:20:02 +040016741 my $Info = `$FileCmd \"$Path\"`;
Andrey Ponomarenko16934472012-03-29 15:37:04 +040016742 if($Info=~/symbolic\s+link\s+to\s+['`"]*([\w\d\.\-\/\\]+)['`"]*/i) {
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040016743 return $1;
Andrey Ponomarenko16934472012-03-29 15:37:04 +040016744 }
16745 }
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040016746
16747 # can't read
16748 return "";
Andrey Ponomarenko16934472012-03-29 15:37:04 +040016749}
16750
16751sub resolve_symlink($)
16752{
16753 my $Path = $_[0];
16754 return "" if(not $Path);
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040016755
Andrey Ponomarenko16934472012-03-29 15:37:04 +040016756 if(defined $Cache{"resolve_symlink"}{$Path}) {
16757 return $Cache{"resolve_symlink"}{$Path};
16758 }
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040016759 if(not -f $Path and not -l $Path)
16760 { # broken
16761 return ($Cache{"resolve_symlink"}{$Path} = "");
16762 }
16763 return ($Cache{"resolve_symlink"}{$Path} = resolve_symlink_I($Path));
16764}
16765
16766sub resolve_symlink_I($)
16767{
16768 my $Path = $_[0];
Andrey Ponomarenko16934472012-03-29 15:37:04 +040016769 return $Path if(isCyclical(\@RecurSymlink, $Path));
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040016770 my $Res = $Path;
Andrey Ponomarenko16934472012-03-29 15:37:04 +040016771 push(@RecurSymlink, $Path);
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040016772 if(-l $Path and my $Redirect = read_symlink($Path))
Andrey Ponomarenko16934472012-03-29 15:37:04 +040016773 {
16774 if(is_abs($Redirect))
16775 { # absolute path
16776 if($SystemRoot and $SystemRoot ne "/"
16777 and $Path=~/\A\Q$SystemRoot\E\//
16778 and (-f $SystemRoot.$Redirect or -l $SystemRoot.$Redirect))
16779 { # symbolic links from the sysroot
16780 # should be corrected to point to
16781 # the files inside sysroot
16782 $Redirect = $SystemRoot.$Redirect;
16783 }
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040016784 $Res = resolve_symlink($Redirect);
Andrey Ponomarenko16934472012-03-29 15:37:04 +040016785 }
16786 elsif($Redirect=~/\.\.[\/\\]/)
16787 { # relative path
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040016788 $Redirect = joinPath(get_dirname($Path), $Redirect);
Andrey Ponomarenko16934472012-03-29 15:37:04 +040016789 while($Redirect=~s&(/|\\)[^\/\\]+(\/|\\)\.\.(\/|\\)&$1&){};
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040016790 $Res = resolve_symlink($Redirect);
Andrey Ponomarenko16934472012-03-29 15:37:04 +040016791 }
16792 elsif(-f get_dirname($Path)."/".$Redirect)
16793 { # file name in the same directory
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040016794 $Res = resolve_symlink(joinPath(get_dirname($Path), $Redirect));
Andrey Ponomarenko16934472012-03-29 15:37:04 +040016795 }
16796 else
16797 { # broken link
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040016798 $Res = "";
Andrey Ponomarenko16934472012-03-29 15:37:04 +040016799 }
16800 }
16801 pop(@RecurSymlink);
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040016802 return $Res;
Andrey Ponomarenko16934472012-03-29 15:37:04 +040016803}
16804
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040016805sub get_LibPath($$)
Andrey Ponomarenko16934472012-03-29 15:37:04 +040016806{
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040016807 my ($LibVersion, $Name) = @_;
16808 return "" if(not $LibVersion or not $Name);
16809 if(defined $Cache{"get_LibPath"}{$LibVersion}{$Name}) {
16810 return $Cache{"get_LibPath"}{$LibVersion}{$Name};
Andrey Ponomarenko16934472012-03-29 15:37:04 +040016811 }
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040016812 return ($Cache{"get_LibPath"}{$LibVersion}{$Name} = get_LibPath_I($LibVersion, $Name));
16813}
16814
16815sub get_LibPath_I($$)
16816{
16817 my ($LibVersion, $Name) = @_;
16818 if(is_abs($Name))
Andrey Ponomarenko16934472012-03-29 15:37:04 +040016819 {
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040016820 if(-f $Name)
16821 { # absolute path
16822 return $Name;
16823 }
16824 else
16825 { # broken
16826 return "";
16827 }
16828 }
Andrey Ponomarenko07aea072012-11-12 16:15:07 +040016829 if(defined $RegisteredObjects{$LibVersion}{$Name})
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040016830 { # registered paths
Andrey Ponomarenko07aea072012-11-12 16:15:07 +040016831 return $RegisteredObjects{$LibVersion}{$Name};
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040016832 }
Andrey Ponomarenko07aea072012-11-12 16:15:07 +040016833 if(defined $RegisteredSONAMEs{$LibVersion}{$Name})
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040016834 { # registered paths
Andrey Ponomarenko07aea072012-11-12 16:15:07 +040016835 return $RegisteredSONAMEs{$LibVersion}{$Name};
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040016836 }
16837 if(my $DefaultPath = $DyLib_DefaultPath{$Name})
16838 { # ldconfig default paths
16839 return $DefaultPath;
16840 }
16841 foreach my $Dir (sort keys(%DefaultLibPaths), sort keys(%{$SystemPaths{"lib"}}))
16842 { # search in default linker directories
16843 # and then in all system paths
16844 if(-f $Dir."/".$Name) {
16845 return joinPath($Dir,$Name);
16846 }
16847 }
16848 detectSystemObjects() if(not keys(%SystemObjects));
16849 if(my @AllObjects = keys(%{$SystemObjects{$Name}})) {
16850 return $AllObjects[0];
16851 }
16852 if(my $ShortName = parse_libname($Name, "name+ext", $OStarget))
16853 {
16854 if($ShortName ne $Name)
16855 { # FIXME: check this case
16856 if(my $Path = get_LibPath($LibVersion, $ShortName)) {
16857 return $Path;
Andrey Ponomarenko16934472012-03-29 15:37:04 +040016858 }
16859 }
Andrey Ponomarenko16934472012-03-29 15:37:04 +040016860 }
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040016861 # can't find
16862 return "";
Andrey Ponomarenko16934472012-03-29 15:37:04 +040016863}
16864
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040016865sub readSymbols_Lib($$$$$$)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040016866{
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040016867 my ($LibVersion, $Lib_Path, $IsNeededLib, $Weak, $Deps, $Vers) = @_;
16868 return () if(not $LibVersion or not $Lib_Path);
16869 my $Lib_Name = get_filename(resolve_symlink($Lib_Path));
16870 if($IsNeededLib)
16871 {
16872 if($CheckedDyLib{$LibVersion}{$Lib_Name}) {
16873 return ();
16874 }
16875 }
16876 return () if(isCyclical(\@RecurLib, $Lib_Name) or $#RecurLib>=1);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040016877 $CheckedDyLib{$LibVersion}{$Lib_Name} = 1;
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040016878
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040016879 if($CheckImpl)
16880 {
16881 if(not $IsNeededLib) {
16882 getImplementations($LibVersion, $Lib_Path);
16883 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040016884 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040016885
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040016886 push(@RecurLib, $Lib_Name);
16887 my (%Value_Interface, %Interface_Value, %NeededLib) = ();
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040016888 my $Lib_ShortName = parse_libname($Lib_Name, "short", $OStarget);
16889 if($IsNeededLib)
16890 { # change short name to use later for needed libraries
16891 $Lib_ShortName = parse_libname($Lib_Name, "name+ext", $OStarget);
16892 }
16893 else
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040016894 { # libstdc++ and libc are always used by other libs
16895 # if you test one of these libs then you not need
16896 # to find them in the system for reusing
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040016897 if($Lib_ShortName eq "libstdc++")
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040016898 { # libstdc++.so.6
16899 $STDCXX_TESTING = 1;
16900 }
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040016901 elsif($Lib_ShortName eq "libc")
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040016902 { # libc-2.11.3.so
16903 $GLIBC_TESTING = 1;
16904 }
16905 }
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040016906 my $DebugPath = "";
Andrey Ponomarenkoa01311b2012-06-08 17:20:02 +040016907 if($Debug and not $DumpSystem)
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040016908 { # debug mode
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040016909 $DebugPath = $DEBUG_PATH{$LibVersion}."/libs/".get_filename($Lib_Path).".txt";
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040016910 mkpath(get_dirname($DebugPath));
16911 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040016912 if($OStarget eq "macos")
16913 { # Mac OS X: *.dylib, *.a
Andrey Ponomarenko07aea072012-11-12 16:15:07 +040016914 my $NM = get_CmdPath("nm");
16915 if(not $NM)
16916 {
16917 print STDERR "ERROR: can't find \"nm\"\n";
16918 exit(1);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040016919 }
Andrey Ponomarenko07aea072012-11-12 16:15:07 +040016920 $NM .= " -g \"$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 Ponomarenko07aea072012-11-12 16:15:07 +040016924 system($NM." >\"$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
Andrey Ponomarenko07aea072012-11-12 16:15:07 +040016929 open(LIB, $NM." |");
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040016930 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040016931 while(<LIB>)
16932 {
Andrey Ponomarenko07aea072012-11-12 16:15:07 +040016933 if(/ [STD] _([\w\$]+)\s*\Z/)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040016934 {
16935 my $realname = $1;
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040016936 if($IsNeededLib)
16937 {
Andrey Ponomarenko07aea072012-11-12 16:15:07 +040016938 if(not defined $RegisteredObjects_Short{$Lib_ShortName})
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040016939 {
16940 $DepSymbol_Library{$LibVersion}{$realname} = $Lib_Name;
16941 $DepLibrary_Symbol{$LibVersion}{$Lib_Name}{$realname} = 1;
16942 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040016943 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040016944 else
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040016945 {
16946 $Symbol_Library{$LibVersion}{$realname} = $Lib_Name;
16947 $Library_Symbol{$LibVersion}{$Lib_Name}{$realname} = 1;
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040016948 if($COMMON_LANGUAGE{$LibVersion} ne "C++")
16949 {
16950 if(index($realname, "_Z")==0 or index($realname, "?")==0) {
16951 setLanguage($LibVersion, "C++");
16952 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040016953 }
16954 if($CheckObjectsOnly
16955 and $LibVersion==1) {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040016956 $CheckedSymbols{"Binary"}{$realname} = 1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040016957 }
16958 }
16959 }
16960 }
16961 close(LIB);
Andrey Ponomarenko07aea072012-11-12 16:15:07 +040016962
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040016963 if($Deps)
16964 {
16965 if($LIB_TYPE eq "dynamic")
16966 { # dependencies
Andrey Ponomarenko07aea072012-11-12 16:15:07 +040016967
16968 my $OtoolCmd = get_CmdPath("otool");
16969 if(not $OtoolCmd)
16970 {
16971 print STDERR "ERROR: can't find \"otool\"\n";
16972 exit(1);
16973 }
16974
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040016975 open(LIB, "$OtoolCmd -L \"$Lib_Path\" 2>\"$TMP_DIR/null\" |");
16976 while(<LIB>)
16977 {
16978 if(/\s*([\/\\].+\.$LIB_EXT)\s*/
16979 and $1 ne $Lib_Path) {
16980 $NeededLib{$1} = 1;
16981 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040016982 }
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040016983 close(LIB);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040016984 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040016985 }
16986 }
16987 elsif($OStarget eq "windows")
16988 { # Windows *.dll, *.lib
16989 my $DumpBinCmd = get_CmdPath("dumpbin");
16990 if(not $DumpBinCmd) {
16991 exitStatus("Not_Found", "can't find \"dumpbin\"");
16992 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040016993 $DumpBinCmd .= " /EXPORTS \"".$Lib_Path."\" 2>$TMP_DIR/null";
Andrey Ponomarenkoa01311b2012-06-08 17:20:02 +040016994 if($DebugPath)
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040016995 { # debug mode
Andrey Ponomarenko16934472012-03-29 15:37:04 +040016996 # write to file
Andrey Ponomarenkoa01311b2012-06-08 17:20:02 +040016997 system($DumpBinCmd." >\"$DebugPath\"");
Andrey Ponomarenko16934472012-03-29 15:37:04 +040016998 open(LIB, $DebugPath);
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040016999 }
Andrey Ponomarenko16934472012-03-29 15:37:04 +040017000 else
17001 { # write to pipe
17002 open(LIB, $DumpBinCmd." |");
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040017003 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017004 while(<LIB>)
17005 { # 1197 4AC 0000A620 SetThreadStackGuarantee
17006 # 1198 4AD SetThreadToken (forwarded to ...)
17007 # 3368 _o2i_ECPublicKey
17008 if(/\A\s*\d+\s+[a-f\d]+\s+[a-f\d]+\s+([\w\?\@]+)\s*\Z/i
17009 or /\A\s*\d+\s+[a-f\d]+\s+([\w\?\@]+)\s*\(\s*forwarded\s+/
17010 or /\A\s*\d+\s+_([\w\?\@]+)\s*\Z/)
17011 { # dynamic, static and forwarded symbols
17012 my $realname = $1;
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040017013 if($IsNeededLib)
17014 {
Andrey Ponomarenko07aea072012-11-12 16:15:07 +040017015 if(not defined $RegisteredObjects_Short{$Lib_ShortName})
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040017016 {
17017 $DepSymbol_Library{$LibVersion}{$realname} = $Lib_Name;
17018 $DepLibrary_Symbol{$LibVersion}{$Lib_Name}{$realname} = 1;
17019 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017020 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040017021 else
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017022 {
17023 $Symbol_Library{$LibVersion}{$realname} = $Lib_Name;
17024 $Library_Symbol{$LibVersion}{$Lib_Name}{$realname} = 1;
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040017025 if($COMMON_LANGUAGE{$LibVersion} ne "C++")
17026 {
17027 if(index($realname, "_Z")==0 or index($realname, "?")==0) {
17028 setLanguage($LibVersion, "C++");
17029 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017030 }
17031 if($CheckObjectsOnly
17032 and $LibVersion==1) {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040017033 $CheckedSymbols{"Binary"}{$realname} = 1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017034 }
17035 }
17036 }
17037 }
17038 close(LIB);
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040017039 if($Deps)
17040 {
17041 if($LIB_TYPE eq "dynamic")
17042 { # dependencies
17043 open(LIB, "$DumpBinCmd /DEPENDENTS \"$Lib_Path\" 2>\"$TMP_DIR/null\" |");
17044 while(<LIB>)
17045 {
17046 if(/\s*([^\s]+?\.$LIB_EXT)\s*/i
17047 and $1 ne $Lib_Path) {
17048 $NeededLib{path_format($1, $OSgroup)} = 1;
17049 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017050 }
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040017051 close(LIB);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017052 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017053 }
17054 }
17055 else
17056 { # Unix; *.so, *.a
17057 # Symbian: *.dso, *.lib
17058 my $ReadelfCmd = get_CmdPath("readelf");
17059 if(not $ReadelfCmd) {
17060 exitStatus("Not_Found", "can't find \"readelf\"");
17061 }
Andrey Ponomarenkoa01311b2012-06-08 17:20:02 +040017062 $ReadelfCmd .= " -WhlSsdA \"$Lib_Path\" 2>\"$TMP_DIR/null\"";
17063 if($DebugPath)
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040017064 { # debug mode
Andrey Ponomarenko16934472012-03-29 15:37:04 +040017065 # write to file
Andrey Ponomarenkoa01311b2012-06-08 17:20:02 +040017066 system($ReadelfCmd." >\"$DebugPath\"");
Andrey Ponomarenko16934472012-03-29 15:37:04 +040017067 open(LIB, $DebugPath);
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040017068 }
Andrey Ponomarenko16934472012-03-29 15:37:04 +040017069 else
17070 { # write to pipe
17071 open(LIB, $ReadelfCmd." |");
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040017072 }
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040017073 my $symtab = undef; # indicates that we are processing 'symtab' section of 'readelf' output
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017074 while(<LIB>)
17075 {
17076 if($LIB_TYPE eq "dynamic")
17077 { # dynamic library specifics
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040017078 if(defined $symtab)
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040017079 {
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040017080 if(index($_, "'.dynsym'")!=-1)
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040017081 { # dynamic table
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040017082 $symtab = undef;
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040017083 }
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040017084 # do nothing with symtab
17085 next;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017086 }
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040017087 elsif(index($_, "'.symtab'")!=-1)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017088 { # symbol table
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040017089 $symtab = 1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017090 next;
17091 }
17092 }
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040017093 if(my ($Value, $Size, $Type, $Bind, $Vis, $Ndx, $Symbol) = readline_ELF($_))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017094 { # read ELF entry
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040017095 if($Ndx eq "UND")
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017096 { # ignore interfaces that are imported from somewhere else
17097 next;
17098 }
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040017099 if($Bind eq "WEAK"
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017100 and $Weak eq "-Weak")
17101 { # skip WEAK symbols
Andrey Ponomarenko07aea072012-11-12 16:15:07 +040017102 $WeakSymbols{$LibVersion}{$Symbol} = 1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017103 next;
17104 }
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040017105 my $Short = $Symbol;
17106 $Short=~s/\@.+//g;
17107 if($Type eq "OBJECT")
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017108 { # global data
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040017109 $GlobalDataObject{$LibVersion}{$Symbol} = 1;
17110 $GlobalDataObject{$LibVersion}{$Short} = 1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017111 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040017112 if($IsNeededLib)
17113 {
Andrey Ponomarenko07aea072012-11-12 16:15:07 +040017114 if(not defined $RegisteredObjects_Short{$Lib_ShortName})
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040017115 {
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040017116 $DepSymbol_Library{$LibVersion}{$Symbol} = $Lib_Name;
17117 $DepLibrary_Symbol{$LibVersion}{$Lib_Name}{$Symbol} = ($Type eq "OBJECT")?-$Size:1;
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040017118 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017119 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040017120 else
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017121 {
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040017122 $Symbol_Library{$LibVersion}{$Symbol} = $Lib_Name;
17123 $Library_Symbol{$LibVersion}{$Lib_Name}{$Symbol} = ($Type eq "OBJECT")?-$Size:1;
17124 if($Vers)
17125 {
17126 if($LIB_EXT eq "so")
17127 { # value
17128 $Interface_Value{$LibVersion}{$Symbol} = $Value;
17129 $Value_Interface{$LibVersion}{$Value}{$Symbol} = 1;
17130 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017131 }
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040017132 if($COMMON_LANGUAGE{$LibVersion} ne "C++")
17133 {
17134 if(index($Symbol, "_Z")==0 or index($Symbol, "?")==0) {
17135 setLanguage($LibVersion, "C++");
17136 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017137 }
17138 if($CheckObjectsOnly
17139 and $LibVersion==1) {
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040017140 $CheckedSymbols{"Binary"}{$Symbol} = 1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017141 }
17142 }
17143 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040017144 elsif($LIB_TYPE eq "dynamic")
17145 { # dynamic library specifics
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040017146 if($Deps)
17147 {
17148 if(/NEEDED.+\[([^\[\]]+)\]/)
17149 { # dependencies:
17150 # 0x00000001 (NEEDED) Shared library: [libc.so.6]
17151 $NeededLib{$1} = 1;
17152 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040017153 }
17154 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017155 }
17156 close(LIB);
17157 }
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040017158 if($Vers)
17159 {
17160 if(not $IsNeededLib and $LIB_EXT eq "so")
17161 { # get symbol versions
17162 foreach my $Symbol (keys(%{$Symbol_Library{$LibVersion}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017163 {
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040017164 next if(index($Symbol,"\@")==-1);
17165 if(my $Value = $Interface_Value{$LibVersion}{$Symbol})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017166 {
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040017167 my $Interface_SymName = "";
17168 foreach my $Symbol_SameValue (keys(%{$Value_Interface{$LibVersion}{$Value}}))
Andrey Ponomarenkoa01311b2012-06-08 17:20:02 +040017169 {
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040017170 if($Symbol_SameValue ne $Symbol
17171 and index($Symbol_SameValue,"\@")==-1)
17172 {
17173 $SymVer{$LibVersion}{$Symbol_SameValue} = $Symbol;
17174 $Interface_SymName = $Symbol_SameValue;
17175 last;
17176 }
Andrey Ponomarenkoa01311b2012-06-08 17:20:02 +040017177 }
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040017178 if(not $Interface_SymName)
17179 {
17180 if($Symbol=~/\A([^\@\$\?]*)[\@\$]+([^\@\$]*)\Z/
17181 and not $SymVer{$LibVersion}{$1}) {
17182 $SymVer{$LibVersion}{$1} = $Symbol;
17183 }
Andrey Ponomarenkoa01311b2012-06-08 17:20:02 +040017184 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017185 }
17186 }
17187 }
17188 }
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040017189 if($Deps)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017190 {
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040017191 foreach my $DyLib (sort keys(%NeededLib))
17192 {
17193 if(my $DepPath = get_LibPath($LibVersion, $DyLib)) {
17194 readSymbols_Lib($LibVersion, $DepPath, 1, "+Weak", $Deps, $Vers);
17195 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017196 }
17197 }
17198 pop(@RecurLib);
17199 return $Library_Symbol{$LibVersion};
17200}
17201
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040017202sub get_prefixes($)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017203{
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017204 my %Prefixes = ();
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040017205 get_prefixes_I([$_[0]], \%Prefixes);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017206 return keys(%Prefixes);
17207}
17208
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040017209sub get_prefixes_I($$)
17210{
17211 foreach my $P (@{$_[0]})
17212 {
17213 my @Parts = reverse(split(/[\/\\]+/, $P));
17214 my $Name = $Parts[0];
17215 foreach (1 .. $#Parts)
17216 {
17217 $_[1]->{$Name}{$P} = 1;
17218 last if($_>4 or $Parts[$_] eq "include");
17219 $Name = $Parts[$_].$SLASH.$Name;
17220 }
17221 }
17222}
17223
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017224sub detectSystemHeaders()
17225{
17226 my @SysHeaders = ();
17227 foreach my $DevelPath (keys(%{$SystemPaths{"include"}}))
17228 {
17229 next if(not -d $DevelPath);
17230 # search for all header files in the /usr/include
17231 # with or without extension (ncurses.h, QtCore, ...)
17232 @SysHeaders = (@SysHeaders, cmd_find($DevelPath,"f","",""));
17233 foreach my $Link (cmd_find($DevelPath,"l","",""))
17234 { # add symbolic links
17235 if(-f $Link) {
17236 push(@SysHeaders, $Link);
17237 }
17238 }
17239 }
17240 foreach my $DevelPath (keys(%{$SystemPaths{"lib"}}))
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040017241 { # search for config headers in the /usr/lib
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017242 next if(not -d $DevelPath);
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040017243 foreach (cmd_find($DevelPath,"f","",""))
17244 {
17245 if(not /\/(gcc|jvm|syslinux|kbd|parrot|xemacs)/)
17246 {
17247 if(/\.h\Z|\/include\//) {
17248 push(@SysHeaders, $_);
17249 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017250 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017251 }
17252 }
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040017253 get_prefixes_I(\@SysHeaders, \%SystemHeaders);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017254}
17255
17256sub detectSystemObjects()
17257{
17258 foreach my $DevelPath (keys(%{$SystemPaths{"lib"}}))
17259 {
17260 next if(not -d $DevelPath);
17261 foreach my $Path (find_libs($DevelPath,"",""))
17262 { # search for shared libraries in the /usr/lib (including symbolic links)
17263 $SystemObjects{parse_libname(get_filename($Path), "name+ext", $OStarget)}{$Path}=1;
17264 }
17265 }
17266}
17267
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040017268sub getSOPaths($)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017269{
17270 my $LibVersion = $_[0];
17271 my @SoPaths = ();
17272 foreach my $Dest (split(/\s*\n\s*/, $Descriptor{$LibVersion}{"Libs"}))
17273 {
17274 if(not -e $Dest) {
17275 exitStatus("Access_Error", "can't access \'$Dest\'");
17276 }
17277 my @SoPaths_Dest = getSOPaths_Dest($Dest, $LibVersion);
17278 foreach (@SoPaths_Dest) {
17279 push(@SoPaths, $_);
17280 }
17281 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040017282 return sort @SoPaths;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017283}
17284
17285sub skip_lib($$)
17286{
17287 my ($Path, $LibVersion) = @_;
17288 return 1 if(not $Path or not $LibVersion);
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040017289 my $Name = get_filename($Path);
17290 if($SkipLibs{$LibVersion}{"Name"}{$Name}) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017291 return 1;
17292 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040017293 my $ShortName = parse_libname($Name, "name+ext", $OStarget);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017294 if($SkipLibs{$LibVersion}{"Name"}{$ShortName}) {
17295 return 1;
17296 }
17297 foreach my $Dir (keys(%{$SkipLibs{$LibVersion}{"Path"}}))
17298 {
17299 if($Path=~/\Q$Dir\E([\/\\]|\Z)/) {
17300 return 1;
17301 }
17302 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040017303 foreach my $P (keys(%{$SkipLibs{$LibVersion}{"Pattern"}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017304 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040017305 if($Name=~/$P/) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017306 return 1;
17307 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040017308 if($P=~/[\/\\]/ and $Path=~/$P/) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017309 return 1;
17310 }
17311 }
17312 return 0;
17313}
17314
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040017315sub skipHeader($$)
17316{
17317 my ($Path, $LibVersion) = @_;
17318 return 1 if(not $Path or not $LibVersion);
17319 if(not keys(%{$SkipHeaders{$LibVersion}})) {
17320 return 0;
17321 }
17322 if(defined $Cache{"skipHeader"}{$Path}) {
17323 return $Cache{"skipHeader"}{$Path};
17324 }
17325 return ($Cache{"skipHeader"}{$Path} = skipHeader_I(@_));
17326}
17327
17328sub skipHeader_I($$)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017329{ # returns:
17330 # 1 - if header should NOT be included and checked
17331 # 2 - if header should NOT be included, but should be checked
17332 my ($Path, $LibVersion) = @_;
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040017333 my $Name = get_filename($Path);
17334 if(my $Kind = $SkipHeaders{$LibVersion}{"Name"}{$Name}) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017335 return $Kind;
17336 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040017337 foreach my $D (keys(%{$SkipHeaders{$LibVersion}{"Path"}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017338 {
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040017339 if(index($Path, $D)!=-1)
17340 {
17341 if($Path=~/\Q$D\E([\/\\]|\Z)/) {
17342 return $SkipHeaders{$LibVersion}{"Path"}{$D};
17343 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017344 }
17345 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040017346 foreach my $P (keys(%{$SkipHeaders{$LibVersion}{"Pattern"}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017347 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040017348 if(my $Kind = $SkipHeaders{$LibVersion}{"Pattern"}{$P})
17349 {
17350 if($Name=~/$P/) {
17351 return $Kind;
17352 }
17353 if($P=~/[\/\\]/ and $Path=~/$P/) {
17354 return $Kind;
17355 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017356 }
17357 }
17358 return 0;
17359}
17360
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040017361sub registerObject_Dir($$)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017362{
17363 my ($Dir, $LibVersion) = @_;
17364 if($SystemPaths{"lib"}{$Dir})
17365 { # system directory
17366 return;
17367 }
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040017368 if($RegisteredObject_Dirs{$LibVersion}{$Dir})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017369 { # already registered
17370 return;
17371 }
17372 foreach my $Path (find_libs($Dir,"",1))
17373 {
17374 next if(ignore_path($Path));
17375 next if(skip_lib($Path, $LibVersion));
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040017376 registerObject($Path, $LibVersion);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017377 }
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040017378 $RegisteredObject_Dirs{$LibVersion}{$Dir} = 1;
17379}
17380
17381sub registerObject($$)
17382{
17383 my ($Path, $LibVersion) = @_;
17384 my $Name = get_filename($Path);
Andrey Ponomarenko07aea072012-11-12 16:15:07 +040017385 $RegisteredObjects{$LibVersion}{$Name} = $Path;
Andrey Ponomarenko27681702012-11-12 16:33:39 +040017386 if($OSgroup=~/linux|bsd/i)
17387 {
17388 if(my $SONAME = getSONAME($Path)) {
17389 $RegisteredSONAMEs{$LibVersion}{$SONAME} = $Path;
17390 }
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040017391 }
17392 if(my $SName = parse_libname($Name, "name", $OStarget)) {
Andrey Ponomarenko07aea072012-11-12 16:15:07 +040017393 $RegisteredObjects_Short{$LibVersion}{$SName} = $Path;
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040017394 }
17395}
17396
17397sub getSONAME($)
17398{
17399 my $Path = $_[0];
17400 return if(not $Path);
17401 if(defined $Cache{"getSONAME"}{$Path}) {
17402 return $Cache{"getSONAME"}{$Path};
17403 }
17404 my $ObjdumpCmd = get_CmdPath("objdump");
17405 if(not $ObjdumpCmd) {
17406 exitStatus("Not_Found", "can't find \"objdump\"");
17407 }
17408 my $SonameCmd = "$ObjdumpCmd -x $Path 2>$TMP_DIR/null";
17409 if($OSgroup eq "windows") {
17410 $SonameCmd .= " | find \"SONAME\"";
17411 }
17412 else {
17413 $SonameCmd .= " | grep SONAME";
17414 }
17415 if(my $SonameInfo = `$SonameCmd`) {
17416 if($SonameInfo=~/SONAME\s+([^\s]+)/) {
17417 return ($Cache{"getSONAME"}{$Path} = $1);
17418 }
17419 }
17420 return ($Cache{"getSONAME"}{$Path}="");
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017421}
17422
17423sub getSOPaths_Dest($$)
17424{
17425 my ($Dest, $LibVersion) = @_;
17426 if(skip_lib($Dest, $LibVersion)) {
17427 return ();
17428 }
17429 if(-f $Dest)
17430 {
17431 if(not parse_libname($Dest, "name", $OStarget)) {
17432 exitStatus("Error", "incorrect format of library (should be *.$LIB_EXT): \'$Dest\'");
17433 }
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040017434 registerObject($Dest, $LibVersion);
17435 registerObject_Dir(get_dirname($Dest), $LibVersion);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017436 return ($Dest);
17437 }
17438 elsif(-d $Dest)
17439 {
17440 $Dest=~s/[\/\\]+\Z//g;
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040017441 my %Libs = ();
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017442 if($SystemPaths{"lib"}{$Dest})
17443 { # you have specified /usr/lib as the search directory (<libs>) in the XML descriptor
17444 # and the real name of the library by -l option (bz2, stdc++, Xaw, ...)
17445 foreach my $Path (cmd_find($Dest,"","*".esc($TargetLibraryName)."*\.$LIB_EXT*",2))
17446 { # all files and symlinks that match the name of a library
17447 if(get_filename($Path)=~/\A(|lib)\Q$TargetLibraryName\E[\d\-]*\.$LIB_EXT[\d\.]*\Z/i)
17448 {
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040017449 registerObject($Path, $LibVersion);
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040017450 $Libs{resolve_symlink($Path)}=1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017451 }
17452 }
17453 }
17454 else
17455 { # search for all files and symlinks
17456 foreach my $Path (find_libs($Dest,"",""))
17457 {
17458 next if(ignore_path($Path));
17459 next if(skip_lib($Path, $LibVersion));
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040017460 registerObject($Path, $LibVersion);
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040017461 $Libs{resolve_symlink($Path)}=1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017462 }
17463 if($OSgroup eq "macos")
17464 { # shared libraries on MacOS X may have no extension
17465 foreach my $Path (cmd_find($Dest,"f","",""))
17466 {
17467 next if(ignore_path($Path));
17468 next if(skip_lib($Path, $LibVersion));
17469 if(get_filename($Path)!~/\./
Andrey Ponomarenko85043792012-05-14 16:48:07 +040017470 and cmd_file($Path)=~/(shared|dynamic)\s+library/i)
17471 {
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040017472 registerObject($Path, $LibVersion);
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040017473 $Libs{resolve_symlink($Path)}=1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017474 }
17475 }
17476 }
17477 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040017478 return keys(%Libs);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017479 }
17480 else {
17481 return ();
17482 }
17483}
17484
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040017485sub isCyclical($$)
17486{
17487 my ($Stack, $Value) = @_;
17488 return (grep {$_ eq $Value} @{$Stack});
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017489}
17490
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017491sub generateTemplate()
17492{
17493 writeFile("VERSION.xml", $DescriptorTemplate."\n");
17494 printMsg("INFO", "XML-descriptor template ./VERSION.xml has been generated");
17495}
17496
17497sub detectWordSize()
17498{
17499 return "" if(not $GCC_PATH);
17500 if($Cache{"detectWordSize"}) {
17501 return $Cache{"detectWordSize"};
17502 }
17503 writeFile("$TMP_DIR/empty.h", "");
Andrey Ponomarenkoa01311b2012-06-08 17:20:02 +040017504 my $Defines = `$GCC_PATH -E -dD \"$TMP_DIR/empty.h\"`;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017505 unlink("$TMP_DIR/empty.h");
17506 my $WSize = 0;
17507 if($Defines=~/ __SIZEOF_POINTER__\s+(\d+)/)
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040017508 { # GCC 4
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017509 $WSize = $1;
17510 }
17511 elsif($Defines=~/ __PTRDIFF_TYPE__\s+(\w+)/)
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040017512 { # GCC 3
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017513 my $PTRDIFF = $1;
17514 if($PTRDIFF=~/long/) {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040017515 $WSize = "8";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017516 }
17517 else {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040017518 $WSize = "4";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017519 }
17520 }
Andrey Ponomarenko01117f12012-06-26 12:23:02 +040017521 if(not $WSize) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017522 exitStatus("Error", "can't check WORD size");
17523 }
17524 return ($Cache{"detectWordSize"} = $WSize);
17525}
17526
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +040017527sub getWordSize($) {
17528 return $WORD_SIZE{$_[0]};
17529}
17530
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017531sub majorVersion($)
17532{
17533 my $V = $_[0];
17534 return 0 if(not $V);
17535 my @VParts = split(/\./, $V);
17536 return $VParts[0];
17537}
17538
17539sub cmpVersions($$)
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040017540{ # compare two versions in dotted-numeric format
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017541 my ($V1, $V2) = @_;
17542 return 0 if($V1 eq $V2);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017543 my @V1Parts = split(/\./, $V1);
17544 my @V2Parts = split(/\./, $V2);
17545 for (my $i = 0; $i <= $#V1Parts && $i <= $#V2Parts; $i++) {
17546 return -1 if(int($V1Parts[$i]) < int($V2Parts[$i]));
17547 return 1 if(int($V1Parts[$i]) > int($V2Parts[$i]));
17548 }
17549 return -1 if($#V1Parts < $#V2Parts);
17550 return 1 if($#V1Parts > $#V2Parts);
17551 return 0;
17552}
17553
17554sub read_ABI_Dump($$)
17555{
17556 my ($LibVersion, $Path) = @_;
17557 return if(not $LibVersion or not -e $Path);
17558 my $FilePath = "";
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040017559 if(isDump_U($Path))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017560 { # input *.abi
17561 $FilePath = $Path;
17562 }
17563 else
17564 { # input *.abi.tar.gz
17565 $FilePath = unpackDump($Path);
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040017566 if(not isDump_U($FilePath)) {
17567 exitStatus("Invalid_Dump", "specified ABI dump \'$Path\' is not valid, try to recreate it");
17568 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017569 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +040017570
Andrey Ponomarenko01117f12012-06-26 12:23:02 +040017571 my $ABI = {};
Andrey Ponomarenko5c09ef32012-06-14 18:17:33 +040017572
Andrey Ponomarenko01117f12012-06-26 12:23:02 +040017573 my $Line = readLineNum($FilePath, 0);
17574 if($Line=~/xml/)
17575 { # XML format
17576 loadModule("XmlDump");
17577 $ABI = readXmlDump($FilePath);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017578 }
Andrey Ponomarenko01117f12012-06-26 12:23:02 +040017579 else
17580 { # Perl Data::Dumper format (default)
17581 open(DUMP, $FilePath);
17582 local $/ = undef;
17583 my $Content = <DUMP>;
17584 close(DUMP);
17585
17586 if(get_dirname($FilePath) eq $TMP_DIR."/unpack")
17587 { # remove temp file
17588 unlink($FilePath);
17589 }
17590 if($Content!~/};\s*\Z/) {
17591 exitStatus("Invalid_Dump", "specified ABI dump \'$Path\' is not valid, try to recreate it");
17592 }
17593 $ABI = eval($Content);
17594 if(not $ABI) {
17595 exitStatus("Error", "internal error - eval() procedure seem to not working correctly, try to remove 'use strict' and try again");
17596 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017597 }
17598 # new dumps (>=1.22) have a personal versioning
Andrey Ponomarenko01117f12012-06-26 12:23:02 +040017599 my $DumpVersion = $ABI->{"ABI_DUMP_VERSION"};
17600 my $ToolVersion = $ABI->{"ABI_COMPLIANCE_CHECKER_VERSION"};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017601 if(not $DumpVersion)
17602 { # old dumps (<=1.21.6) have been marked by the tool version
17603 $DumpVersion = $ToolVersion;
17604 }
17605 $UsedDump{$LibVersion}{"V"} = $DumpVersion;
17606 if(majorVersion($DumpVersion) ne majorVersion($ABI_DUMP_VERSION))
17607 { # should be compatible with dumps of the same major version
17608 if(cmpVersions($DumpVersion, $ABI_DUMP_VERSION)>0)
17609 { # Don't know how to parse future dump formats
Andrey Ponomarenko01117f12012-06-26 12:23:02 +040017610 exitStatus("Dump_Version", "incompatible version \'$DumpVersion\' of specified ABI dump (newer than $ABI_DUMP_VERSION)");
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017611 }
Andrey Ponomarenko01117f12012-06-26 12:23:02 +040017612 elsif(cmpVersions($DumpVersion, $TOOL_VERSION)>0 and not $ABI->{"ABI_DUMP_VERSION"})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017613 { # Don't know how to parse future dump formats
Andrey Ponomarenko01117f12012-06-26 12:23:02 +040017614 exitStatus("Dump_Version", "incompatible version \'$DumpVersion\' of specified ABI dump (newer than $TOOL_VERSION)");
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017615 }
17616 if($UseOldDumps)
17617 {
17618 if(cmpVersions($DumpVersion, $OLDEST_SUPPORTED_VERSION)<0) {
Andrey Ponomarenko01117f12012-06-26 12:23:02 +040017619 exitStatus("Dump_Version", "incompatible version \'$DumpVersion\' of specified ABI dump (older than $OLDEST_SUPPORTED_VERSION)");
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017620 }
17621 }
17622 else
17623 {
Andrey Ponomarenko01117f12012-06-26 12:23:02 +040017624 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 +040017625 if(cmpVersions($DumpVersion, $OLDEST_SUPPORTED_VERSION)>=0) {
17626 $Msg .= "\nUse -old-dumps option to use old-version dumps ($OLDEST_SUPPORTED_VERSION<=V<".majorVersion($ABI_DUMP_VERSION).".0)";
17627 }
17628 exitStatus("Dump_Version", $Msg);
17629 }
17630 }
Andrey Ponomarenko5c09ef32012-06-14 18:17:33 +040017631 if(not checkDump($LibVersion, "2.11"))
17632 { # old ABI dumps
17633 $UsedDump{$LibVersion}{"BinOnly"} = 1;
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040017634 }
Andrey Ponomarenko01117f12012-06-26 12:23:02 +040017635 elsif($ABI->{"BinOnly"})
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040017636 { # ABI dump created with --binary option
17637 $UsedDump{$LibVersion}{"BinOnly"} = 1;
17638 }
Andrey Ponomarenko5c09ef32012-06-14 18:17:33 +040017639 else
17640 { # default
17641 $UsedDump{$LibVersion}{"SrcBin"} = 1;
17642 }
Andrey Ponomarenko01117f12012-06-26 12:23:02 +040017643 if(defined $ABI->{"Mode"}
17644 and $ABI->{"Mode"} eq "Extended")
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017645 { # --ext option
17646 $ExtendedCheck = 1;
17647 }
Andrey Ponomarenko01117f12012-06-26 12:23:02 +040017648 if(my $Lang = $ABI->{"Language"})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017649 {
17650 $UsedDump{$LibVersion}{"L"} = $Lang;
17651 setLanguage($LibVersion, $Lang);
17652 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040017653 if(checkDump($LibVersion, "2.15")) {
Andrey Ponomarenko01117f12012-06-26 12:23:02 +040017654 $TypeInfo{$LibVersion} = $ABI->{"TypeInfo"};
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040017655 }
17656 else
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017657 { # support for old ABI dumps
Andrey Ponomarenko01117f12012-06-26 12:23:02 +040017658 my $TInfo = $ABI->{"TypeInfo"};
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040017659 if(not $TInfo)
17660 { # support for older ABI dumps
Andrey Ponomarenko01117f12012-06-26 12:23:02 +040017661 $TInfo = $ABI->{"TypeDescr"};
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040017662 }
17663 my %Tid_TDid = ();
17664 foreach my $TDid (keys(%{$TInfo}))
17665 {
17666 foreach my $Tid (keys(%{$TInfo->{$TDid}}))
17667 {
17668 $MAX_ID = $Tid if($Tid>$MAX_ID);
17669 $MAX_ID = $TDid if($TDid and $TDid>$MAX_ID);
17670 $Tid_TDid{$Tid}{$TDid}=1;
17671 }
17672 }
17673 my %NewID = ();
17674 foreach my $Tid (keys(%Tid_TDid))
17675 {
17676 my @TDids = keys(%{$Tid_TDid{$Tid}});
17677 if($#TDids>=1)
17678 {
17679 foreach my $TDid (@TDids)
17680 {
17681 if($TDid) {
17682 %{$TypeInfo{$LibVersion}{$Tid}} = %{$TInfo->{$TDid}{$Tid}};
17683 }
17684 else
17685 {
17686 if(my $ID = ++$MAX_ID)
17687 {
17688 $NewID{$TDid}{$Tid} = $ID;
17689 %{$TypeInfo{$LibVersion}{$ID}} = %{$TInfo->{$TDid}{$Tid}};
17690 $TypeInfo{$LibVersion}{$ID}{"Tid"} = $ID;
17691 }
17692 }
17693 }
17694 }
17695 else
17696 {
17697 my $TDid = $TDids[0];
17698 %{$TypeInfo{$LibVersion}{$Tid}} = %{$TInfo->{$TDid}{$Tid}};
17699 }
17700 }
17701 foreach my $Tid (keys(%{$TypeInfo{$LibVersion}}))
17702 {
17703 my %Info = %{$TypeInfo{$LibVersion}{$Tid}};
17704 if(defined $Info{"BaseType"})
17705 {
17706 my $Bid = $Info{"BaseType"}{"Tid"};
17707 my $BDid = $Info{"BaseType"}{"TDid"};
17708 $BDid="" if(not defined $BDid);
17709 if(defined $NewID{$BDid} and my $ID = $NewID{$BDid}{$Bid}) {
17710 $TypeInfo{$LibVersion}{$Tid}{"BaseType"}{"Tid"} = $ID;
17711 }
17712 delete($TypeInfo{$LibVersion}{$Tid}{"BaseType"}{"TDid"});
17713 }
17714 delete($TypeInfo{$LibVersion}{$Tid}{"TDid"});
17715 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017716 }
Andrey Ponomarenko01117f12012-06-26 12:23:02 +040017717 read_Machine_DumpInfo($ABI, $LibVersion);
17718 $SymbolInfo{$LibVersion} = $ABI->{"SymbolInfo"};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017719 if(not $SymbolInfo{$LibVersion})
17720 { # support for old dumps
Andrey Ponomarenko01117f12012-06-26 12:23:02 +040017721 $SymbolInfo{$LibVersion} = $ABI->{"FuncDescr"};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017722 }
17723 if(not keys(%{$SymbolInfo{$LibVersion}}))
17724 { # validation of old-version dumps
17725 if(not $ExtendedCheck) {
17726 exitStatus("Invalid_Dump", "the input dump d$LibVersion is invalid");
17727 }
17728 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040017729 if(checkDump($LibVersion, "2.15")) {
Andrey Ponomarenko01117f12012-06-26 12:23:02 +040017730 $DepLibrary_Symbol{$LibVersion} = $ABI->{"DepSymbols"};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017731 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040017732 else
17733 { # support for old ABI dumps
Andrey Ponomarenko01117f12012-06-26 12:23:02 +040017734 my $DepSymbols = $ABI->{"DepSymbols"};
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040017735 if(not $DepSymbols) {
Andrey Ponomarenko01117f12012-06-26 12:23:02 +040017736 $DepSymbols = $ABI->{"DepInterfaces"};
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040017737 }
17738 if(not $DepSymbols)
17739 { # Cannot reconstruct DepSymbols. This may result in false
17740 # positives if the old dump is for library 2. Not a problem if
17741 # old dumps are only from old libraries.
17742 $DepSymbols = {};
17743 }
17744 foreach my $Symbol (keys(%{$DepSymbols})) {
17745 $DepSymbol_Library{$LibVersion}{$Symbol} = 1;
17746 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017747 }
Andrey Ponomarenko01117f12012-06-26 12:23:02 +040017748 $SymVer{$LibVersion} = $ABI->{"SymbolVersion"};
17749 $Descriptor{$LibVersion}{"Version"} = $ABI->{"LibraryVersion"};
17750 $SkipTypes{$LibVersion} = $ABI->{"SkipTypes"};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017751 if(not $SkipTypes{$LibVersion})
17752 { # support for old dumps
Andrey Ponomarenko01117f12012-06-26 12:23:02 +040017753 $SkipTypes{$LibVersion} = $ABI->{"OpaqueTypes"};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017754 }
Andrey Ponomarenko01117f12012-06-26 12:23:02 +040017755 $SkipSymbols{$LibVersion} = $ABI->{"SkipSymbols"};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017756 if(not $SkipSymbols{$LibVersion})
17757 { # support for old dumps
Andrey Ponomarenko01117f12012-06-26 12:23:02 +040017758 $SkipSymbols{$LibVersion} = $ABI->{"SkipInterfaces"};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017759 }
17760 if(not $SkipSymbols{$LibVersion})
17761 { # support for old dumps
Andrey Ponomarenko01117f12012-06-26 12:23:02 +040017762 $SkipSymbols{$LibVersion} = $ABI->{"InternalInterfaces"};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017763 }
Andrey Ponomarenko01117f12012-06-26 12:23:02 +040017764 $SkipNameSpaces{$LibVersion} = $ABI->{"SkipNameSpaces"};
17765 $TargetHeaders{$LibVersion} = $ABI->{"TargetHeaders"};
17766 foreach my $Path (keys(%{$ABI->{"SkipHeaders"}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017767 {
Andrey Ponomarenko01117f12012-06-26 12:23:02 +040017768 $SkipHeadersList{$LibVersion}{$Path} = $ABI->{"SkipHeaders"}{$Path};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017769 my ($CPath, $Type) = classifyPath($Path);
Andrey Ponomarenko01117f12012-06-26 12:23:02 +040017770 $SkipHeaders{$LibVersion}{$Type}{$CPath} = $ABI->{"SkipHeaders"}{$Path};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017771 }
Andrey Ponomarenko01117f12012-06-26 12:23:02 +040017772 read_Headers_DumpInfo($ABI, $LibVersion);
17773 read_Libs_DumpInfo($ABI, $LibVersion);
Andrey Ponomarenko5c09ef32012-06-14 18:17:33 +040017774 if(not checkDump($LibVersion, "2.10.1")
17775 or not $TargetHeaders{$LibVersion})
Andrey Ponomarenko85043792012-05-14 16:48:07 +040017776 { # support for old ABI dumps: added target headers
17777 foreach (keys(%{$Registered_Headers{$LibVersion}})) {
17778 $TargetHeaders{$LibVersion}{get_filename($_)}=1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017779 }
17780 }
Andrey Ponomarenko01117f12012-06-26 12:23:02 +040017781 $Constants{$LibVersion} = $ABI->{"Constants"};
17782 $NestedNameSpaces{$LibVersion} = $ABI->{"NameSpaces"};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017783 if(not $NestedNameSpaces{$LibVersion})
17784 { # support for old dumps
17785 # Cannot reconstruct NameSpaces. This may affect design
17786 # of the compatibility report.
17787 $NestedNameSpaces{$LibVersion} = {};
17788 }
17789 # target system type
17790 # needed to adopt HTML report
17791 if(not $DumpSystem)
17792 { # to use in createSymbolsList(...)
Andrey Ponomarenko01117f12012-06-26 12:23:02 +040017793 $OStarget = $ABI->{"Target"};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017794 }
17795 # recreate environment
17796 foreach my $Lib_Name (keys(%{$Library_Symbol{$LibVersion}}))
17797 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040017798 foreach my $Symbol (keys(%{$Library_Symbol{$LibVersion}{$Lib_Name}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017799 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040017800 $Symbol_Library{$LibVersion}{$Symbol} = $Lib_Name;
17801 if($Library_Symbol{$LibVersion}{$Lib_Name}{$Symbol}<=-1)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017802 { # data marked as -size in the dump
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040017803 $GlobalDataObject{$LibVersion}{$Symbol}=1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017804 }
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040017805 if($COMMON_LANGUAGE{$LibVersion} ne "C++")
17806 {
17807 if(index($Symbol, "_Z")==0 or index($Symbol, "?")==0) {
17808 setLanguage($LibVersion, "C++");
17809 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017810 }
17811 }
17812 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040017813 foreach my $Lib_Name (keys(%{$DepLibrary_Symbol{$LibVersion}}))
17814 {
17815 foreach my $Symbol (keys(%{$DepLibrary_Symbol{$LibVersion}{$Lib_Name}})) {
17816 $DepSymbol_Library{$LibVersion}{$Symbol} = $Lib_Name;
17817 }
17818 }
17819
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017820 my @VFunc = ();
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040017821 foreach my $InfoId (keys(%{$SymbolInfo{$LibVersion}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017822 {
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +040017823 if(my $MnglName = $SymbolInfo{$LibVersion}{$InfoId}{"MnglName"})
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040017824 {
17825 if(not $Symbol_Library{$LibVersion}{$MnglName}
17826 and not $DepSymbol_Library{$LibVersion}{$MnglName}) {
17827 push(@VFunc, $MnglName);
17828 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017829 }
17830 }
17831 translateSymbols(@VFunc, $LibVersion);
17832 translateSymbols(keys(%{$Symbol_Library{$LibVersion}}), $LibVersion);
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040017833 translateSymbols(keys(%{$DepSymbol_Library{$LibVersion}}), $LibVersion);
17834
17835 foreach my $TypeId (sort {int($a)<=>int($b)} keys(%{$TypeInfo{$LibVersion}}))
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +040017836 { # order is important
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040017837 if(defined $TypeInfo{$LibVersion}{$TypeId}{"BaseClass"})
17838 { # support for old ABI dumps < 2.0 (ACC 1.22)
17839 foreach my $BId (keys(%{$TypeInfo{$LibVersion}{$TypeId}{"BaseClass"}}))
17840 {
17841 if(my $Access = $TypeInfo{$LibVersion}{$TypeId}{"BaseClass"}{$BId})
17842 {
17843 if($Access ne "public") {
17844 $TypeInfo{$LibVersion}{$TypeId}{"Base"}{$BId}{"access"} = $Access;
17845 }
17846 }
17847 $TypeInfo{$LibVersion}{$TypeId}{"Base"}{$BId} = {};
17848 }
17849 delete($TypeInfo{$LibVersion}{$TypeId}{"BaseClass"});
17850 }
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040017851 if(my $Header = $TypeInfo{$LibVersion}{$TypeId}{"Header"})
17852 { # support for old ABI dumps
17853 $TypeInfo{$LibVersion}{$TypeId}{"Header"} = path_format($Header, $OSgroup);
17854 }
Andrey Ponomarenko01117f12012-06-26 12:23:02 +040017855 if(not defined $TypeInfo{$LibVersion}{$TypeId}{"Tid"}) {
17856 $TypeInfo{$LibVersion}{$TypeId}{"Tid"} = $TypeId;
17857 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040017858 my %TInfo = %{$TypeInfo{$LibVersion}{$TypeId}};
17859 if(defined $TInfo{"Base"})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017860 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040017861 foreach (keys(%{$TInfo{"Base"}})) {
17862 $Class_SubClasses{$LibVersion}{$_}{$TypeId}=1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017863 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040017864 }
Andrey Ponomarenko01117f12012-06-26 12:23:02 +040017865 if($TInfo{"Type"} eq "MethodPtr")
17866 {
17867 if(defined $TInfo{"Param"})
17868 { # support for old ABI dumps <= 1.17
17869 if(not defined $TInfo{"Param"}{"0"})
17870 {
17871 my $Max = keys(%{$TInfo{"Param"}});
17872 foreach my $Pos (1 .. $Max) {
17873 $TInfo{"Param"}{$Pos-1} = $TInfo{"Param"}{$Pos};
17874 }
17875 delete($TInfo{"Param"}{$Max});
17876 %{$TypeInfo{$LibVersion}{$TypeId}} = %TInfo;
17877 }
17878 }
17879 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040017880 if($TInfo{"Type"} eq "Typedef" and defined $TInfo{"BaseType"})
17881 {
17882 if(my $BTid = $TInfo{"BaseType"}{"Tid"})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017883 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040017884 my $BName = $TypeInfo{$LibVersion}{$BTid}{"Name"};
17885 if(not $BName)
17886 { # broken type
17887 next;
17888 }
17889 if($TInfo{"Name"} eq $BName)
17890 { # typedef to "class Class"
17891 # should not be registered in TName_Tid
17892 next;
17893 }
17894 if(not $Typedef_BaseName{$LibVersion}{$TInfo{"Name"}}) {
17895 $Typedef_BaseName{$LibVersion}{$TInfo{"Name"}} = $BName;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017896 }
17897 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040017898 }
17899 if(not $TName_Tid{$LibVersion}{$TInfo{"Name"}})
17900 { # classes: class (id1), typedef (artificial, id2 > id1)
17901 $TName_Tid{$LibVersion}{$TInfo{"Name"}} = $TypeId;
17902 }
17903 }
17904
17905 if(not checkDump($LibVersion, "2.15"))
17906 { # support for old ABI dumps
17907 my %Dups = ();
17908 foreach my $InfoId (keys(%{$SymbolInfo{$LibVersion}}))
17909 {
17910 if(my $ClassId = $SymbolInfo{$LibVersion}{$InfoId}{"Class"})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017911 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040017912 if(not defined $TypeInfo{$LibVersion}{$ClassId})
17913 { # remove template decls
17914 delete($SymbolInfo{$LibVersion}{$InfoId});
17915 next;
Andrey Ponomarenko16934472012-03-29 15:37:04 +040017916 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017917 }
Andrey Ponomarenkob8d203d2012-05-25 18:11:07 +040017918 my $MName = $SymbolInfo{$LibVersion}{$InfoId}{"MnglName"};
17919 if(not $MName and $SymbolInfo{$LibVersion}{$InfoId}{"Class"})
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040017920 { # templates
17921 delete($SymbolInfo{$LibVersion}{$InfoId});
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017922 }
17923 }
17924 }
17925
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +040017926 foreach my $InfoId (keys(%{$SymbolInfo{$LibVersion}}))
17927 {
17928 if(not $SymbolInfo{$LibVersion}{$InfoId}{"MnglName"})
17929 { # ABI dumps have no mangled names for C-functions
17930 $SymbolInfo{$LibVersion}{$InfoId}{"MnglName"} = $SymbolInfo{$LibVersion}{$InfoId}{"ShortName"};
17931 }
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040017932 if(my $Header = $SymbolInfo{$LibVersion}{$InfoId}{"Header"})
17933 { # support for old ABI dumps
17934 $SymbolInfo{$LibVersion}{$InfoId}{"Header"} = path_format($Header, $OSgroup);
17935 }
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +040017936 }
17937
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017938 $Descriptor{$LibVersion}{"Dump"} = 1;
17939}
17940
17941sub read_Machine_DumpInfo($$)
17942{
Andrey Ponomarenko01117f12012-06-26 12:23:02 +040017943 my ($ABI, $LibVersion) = @_;
17944 if($ABI->{"Arch"}) {
17945 $CPU_ARCH{$LibVersion} = $ABI->{"Arch"};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017946 }
Andrey Ponomarenko01117f12012-06-26 12:23:02 +040017947 if($ABI->{"WordSize"}) {
17948 $WORD_SIZE{$LibVersion} = $ABI->{"WordSize"};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017949 }
17950 else
17951 { # support for old dumps
Andrey Ponomarenko01117f12012-06-26 12:23:02 +040017952 $WORD_SIZE{$LibVersion} = $ABI->{"SizeOfPointer"};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017953 }
17954 if(not $WORD_SIZE{$LibVersion})
17955 { # support for old dumps (<1.23)
17956 if(my $Tid = getTypeIdByName("char*", $LibVersion))
17957 { # size of char*
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040017958 $WORD_SIZE{$LibVersion} = $TypeInfo{$LibVersion}{$Tid}{"Size"};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017959 }
17960 else
17961 {
17962 my $PSize = 0;
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040017963 foreach my $Tid (keys(%{$TypeInfo{$LibVersion}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017964 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040017965 if($TypeInfo{$LibVersion}{$Tid}{"Type"} eq "Pointer")
17966 { # any "pointer"-type
17967 $PSize = $TypeInfo{$LibVersion}{$Tid}{"Size"};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017968 last;
17969 }
17970 }
17971 if($PSize)
17972 { # a pointer type size
17973 $WORD_SIZE{$LibVersion} = $PSize;
17974 }
17975 else {
17976 printMsg("WARNING", "cannot identify a WORD size in the ABI dump (too old format)");
17977 }
17978 }
17979 }
Andrey Ponomarenko01117f12012-06-26 12:23:02 +040017980 if($ABI->{"GccVersion"}) {
17981 $GCC_VERSION{$LibVersion} = $ABI->{"GccVersion"};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017982 }
17983}
17984
17985sub read_Libs_DumpInfo($$)
17986{
Andrey Ponomarenko01117f12012-06-26 12:23:02 +040017987 my ($ABI, $LibVersion) = @_;
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040017988 $Library_Symbol{$LibVersion} = $ABI->{"Symbols"};
17989 if(not $Library_Symbol{$LibVersion})
17990 { # support for old dumps
17991 $Library_Symbol{$LibVersion} = $ABI->{"Interfaces"};
17992 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017993 if(keys(%{$Library_Symbol{$LibVersion}})
17994 and not $DumpAPI) {
17995 $Descriptor{$LibVersion}{"Libs"} = "OK";
17996 }
17997}
17998
17999sub read_Headers_DumpInfo($$)
18000{
Andrey Ponomarenko01117f12012-06-26 12:23:02 +040018001 my ($ABI, $LibVersion) = @_;
18002 if(keys(%{$ABI->{"Headers"}})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040018003 and not $DumpAPI) {
18004 $Descriptor{$LibVersion}{"Headers"} = "OK";
18005 }
Andrey Ponomarenko01117f12012-06-26 12:23:02 +040018006 foreach my $Identity (sort {$ABI->{"Headers"}{$a}<=>$ABI->{"Headers"}{$b}} keys(%{$ABI->{"Headers"}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040018007 { # headers info is stored in the old dumps in the different way
18008 if($UseOldDumps
Andrey Ponomarenko01117f12012-06-26 12:23:02 +040018009 and my $Name = $ABI->{"Headers"}{$Identity}{"Name"})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040018010 { # support for old dumps: headers info corrected in 1.22
18011 $Identity = $Name;
18012 }
18013 $Registered_Headers{$LibVersion}{$Identity}{"Identity"} = $Identity;
Andrey Ponomarenko01117f12012-06-26 12:23:02 +040018014 $Registered_Headers{$LibVersion}{$Identity}{"Pos"} = $ABI->{"Headers"}{$Identity};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040018015 }
18016}
18017
18018sub find_libs($$$)
18019{
18020 my ($Path, $Type, $MaxDepth) = @_;
18021 # FIXME: correct the search pattern
18022 return cmd_find($Path, $Type, ".*\\.$LIB_EXT\[0-9.]*", $MaxDepth);
18023}
18024
18025sub createDescriptor($$)
18026{
18027 my ($LibVersion, $Path) = @_;
18028 if(not $LibVersion or not $Path
18029 or not -e $Path) {
18030 return "";
18031 }
18032 if(-d $Path)
18033 { # directory with headers files and shared objects
18034 return "
18035 <version>
18036 ".$TargetVersion{$LibVersion}."
18037 </version>
18038
18039 <headers>
18040 $Path
18041 </headers>
18042
18043 <libs>
18044 $Path
18045 </libs>";
18046 }
18047 else
18048 { # files
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040018049 if($Path=~/\.(xml|desc)\Z/i)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040018050 { # standard XML-descriptor
18051 return readFile($Path);
18052 }
18053 elsif(is_header($Path, 2, $LibVersion))
18054 { # header file
18055 return "
18056 <version>
18057 ".$TargetVersion{$LibVersion}."
18058 </version>
18059
18060 <headers>
18061 $Path
18062 </headers>
18063
18064 <libs>
18065 none
18066 </libs>";
18067 }
18068 elsif(parse_libname($Path, "name", $OStarget))
18069 { # shared object
18070 return "
18071 <version>
18072 ".$TargetVersion{$LibVersion}."
18073 </version>
18074
18075 <headers>
18076 none
18077 </headers>
18078
18079 <libs>
18080 $Path
18081 </libs>";
18082 }
18083 else
18084 { # standard XML-descriptor
18085 return readFile($Path);
18086 }
18087 }
18088}
18089
18090sub detect_lib_default_paths()
18091{
18092 my %LPaths = ();
18093 if($OSgroup eq "bsd")
18094 {
Andrey Ponomarenkoa01311b2012-06-08 17:20:02 +040018095 if(my $LdConfig = get_CmdPath("ldconfig"))
18096 {
18097 foreach my $Line (split(/\n/, `$LdConfig -r 2>\"$TMP_DIR/null\"`))
18098 {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040018099 if($Line=~/\A[ \t]*\d+:\-l(.+) \=\> (.+)\Z/) {
18100 $LPaths{"lib".$1} = $2;
18101 }
18102 }
18103 }
18104 else {
18105 printMsg("WARNING", "can't find ldconfig");
18106 }
18107 }
18108 else
18109 {
18110 if(my $LdConfig = get_CmdPath("ldconfig"))
18111 {
18112 if($SystemRoot and $OSgroup eq "linux")
18113 { # use host (x86) ldconfig with the target (arm) ld.so.conf
18114 if(-e $SystemRoot."/etc/ld.so.conf") {
18115 $LdConfig .= " -f ".$SystemRoot."/etc/ld.so.conf";
18116 }
18117 }
Andrey Ponomarenkoa01311b2012-06-08 17:20:02 +040018118 foreach my $Line (split(/\n/, `$LdConfig -p 2>\"$TMP_DIR/null\"`))
18119 {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040018120 if($Line=~/\A[ \t]*([^ \t]+) .* \=\> (.+)\Z/)
18121 {
18122 my ($Name, $Path) = ($1, $2);
18123 $Path=~s/[\/]{2,}/\//;
18124 $LPaths{$Name} = $Path;
18125 }
18126 }
18127 }
Andrey Ponomarenko82b005f2012-11-12 17:58:14 +040018128 elsif($OSgroup eq "linux") {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040018129 printMsg("WARNING", "can't find ldconfig");
18130 }
18131 }
18132 return \%LPaths;
18133}
18134
18135sub detect_bin_default_paths()
18136{
18137 my $EnvPaths = $ENV{"PATH"};
18138 if($OSgroup eq "beos") {
18139 $EnvPaths.=":".$ENV{"BETOOLS"};
18140 }
18141 my $Sep = ($OSgroup eq "windows")?";":":|;";
18142 foreach my $Path (sort {length($a)<=>length($b)} split(/$Sep/, $EnvPaths))
18143 {
18144 $Path = path_format($Path, $OSgroup);
18145 $Path=~s/[\/\\]+\Z//g;
18146 next if(not $Path);
18147 if($SystemRoot
18148 and $Path=~/\A\Q$SystemRoot\E\//)
18149 { # do NOT use binaries from target system
18150 next;
18151 }
18152 $DefaultBinPaths{$Path} = 1;
18153 }
18154}
18155
18156sub detect_inc_default_paths()
18157{
18158 return () if(not $GCC_PATH);
18159 my %DPaths = ("Cpp"=>{},"Gcc"=>{},"Inc"=>{});
18160 writeFile("$TMP_DIR/empty.h", "");
Andrey Ponomarenkoa01311b2012-06-08 17:20:02 +040018161 foreach my $Line (split(/\n/, `$GCC_PATH -v -x c++ -E \"$TMP_DIR/empty.h\" 2>&1`))
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040018162 { # detecting GCC default include paths
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040018163 if($Line=~/\A[ \t]*((\/|\w+:\\).+)[ \t]*\Z/)
18164 {
18165 my $Path = simplify_path($1);
18166 $Path=~s/[\/\\]+\Z//g;
18167 $Path = path_format($Path, $OSgroup);
18168 if($Path=~/c\+\+|\/g\+\+\//)
18169 {
18170 $DPaths{"Cpp"}{$Path}=1;
18171 if(not defined $MAIN_CPP_DIR
18172 or get_depth($MAIN_CPP_DIR)>get_depth($Path)) {
18173 $MAIN_CPP_DIR = $Path;
18174 }
18175 }
18176 elsif($Path=~/gcc/) {
18177 $DPaths{"Gcc"}{$Path}=1;
18178 }
18179 else
18180 {
18181 next if($Path=~/local[\/\\]+include/);
18182 if($SystemRoot
18183 and $Path!~/\A\Q$SystemRoot\E(\/|\Z)/)
18184 { # The GCC include path for user headers is not a part of the system root
18185 # The reason: you are not specified the --cross-gcc option or selected a wrong compiler
18186 # or it is the internal cross-GCC path like arm-linux-gnueabi/include
18187 next;
18188 }
18189 $DPaths{"Inc"}{$Path}=1;
18190 }
18191 }
18192 }
18193 unlink("$TMP_DIR/empty.h");
18194 return %DPaths;
18195}
18196
18197sub detect_default_paths($)
18198{
18199 my ($HSearch, $LSearch, $BSearch, $GSearch) = (1, 1, 1, 1);
18200 my $Search = $_[0];
18201 if($Search!~/inc/) {
18202 $HSearch = 0;
18203 }
18204 if($Search!~/lib/) {
18205 $LSearch = 0;
18206 }
18207 if($Search!~/bin/) {
18208 $BSearch = 0;
18209 }
18210 if($Search!~/gcc/) {
18211 $GSearch = 0;
18212 }
18213 if(keys(%{$SystemPaths{"include"}}))
18214 { # <search_headers> section of the XML descriptor
18215 # do NOT search for systems headers
18216 $HSearch = 0;
18217 }
18218 if(keys(%{$SystemPaths{"lib"}}))
18219 { # <search_headers> section of the XML descriptor
18220 # do NOT search for systems headers
18221 $LSearch = 0;
18222 }
18223 foreach my $Type (keys(%{$OS_AddPath{$OSgroup}}))
18224 { # additional search paths
18225 next if($Type eq "include" and not $HSearch);
18226 next if($Type eq "lib" and not $LSearch);
18227 next if($Type eq "bin" and not $BSearch);
18228 foreach my $Path (keys(%{$OS_AddPath{$OSgroup}{$Type}}))
18229 {
18230 next if(not -d $Path);
18231 $SystemPaths{$Type}{$Path} = $OS_AddPath{$OSgroup}{$Type}{$Path};
18232 }
18233 }
18234 if($OSgroup ne "windows")
18235 { # unix-like
18236 foreach my $Type ("include", "lib", "bin")
18237 { # automatic detection of system "devel" directories
18238 next if($Type eq "include" and not $HSearch);
18239 next if($Type eq "lib" and not $LSearch);
18240 next if($Type eq "bin" and not $BSearch);
18241 my ($UsrDir, $RootDir) = ("/usr", "/");
18242 if($SystemRoot and $Type ne "bin")
18243 { # 1. search for target headers and libraries
18244 # 2. use host commands: ldconfig, readelf, etc.
18245 ($UsrDir, $RootDir) = ("$SystemRoot/usr", $SystemRoot);
18246 }
18247 foreach my $Path (cmd_find($RootDir,"d","*$Type*",1)) {
18248 $SystemPaths{$Type}{$Path} = 1;
18249 }
18250 if(-d $RootDir."/".$Type)
18251 { # if "/lib" is symbolic link
18252 if($RootDir eq "/") {
18253 $SystemPaths{$Type}{"/".$Type} = 1;
18254 }
18255 else {
18256 $SystemPaths{$Type}{$RootDir."/".$Type} = 1;
18257 }
18258 }
18259 if(-d $UsrDir) {
18260 foreach my $Path (cmd_find($UsrDir,"d","*$Type*",1)) {
18261 $SystemPaths{$Type}{$Path} = 1;
18262 }
18263 if(-d $UsrDir."/".$Type)
18264 { # if "/usr/lib" is symbolic link
18265 $SystemPaths{$Type}{$UsrDir."/".$Type} = 1;
18266 }
18267 }
18268 }
18269 }
18270 if($BSearch)
18271 {
18272 detect_bin_default_paths();
18273 foreach my $Path (keys(%DefaultBinPaths)) {
18274 $SystemPaths{"bin"}{$Path} = $DefaultBinPaths{$Path};
18275 }
18276 }
18277 # check environment variables
18278 if($OSgroup eq "beos")
18279 {
18280 foreach (keys(%{$SystemPaths{"bin"}}))
18281 {
18282 if($_ eq ".") {
18283 next;
18284 }
18285 foreach my $Path (cmd_find($_, "d", "bin", ""))
18286 { # search for /boot/develop/abi/x86/gcc4/tools/gcc-4.4.4-haiku-101111/bin/
18287 $SystemPaths{"bin"}{$Path} = 1;
18288 }
18289 }
18290 if($HSearch)
18291 {
18292 foreach my $Path (split(/:|;/, $ENV{"BEINCLUDES"}))
18293 {
18294 if(is_abs($Path)) {
18295 $DefaultIncPaths{$Path} = 1;
18296 }
18297 }
18298 }
18299 if($LSearch)
18300 {
18301 foreach my $Path (split(/:|;/, $ENV{"BELIBRARIES"}), split(/:|;/, $ENV{"LIBRARY_PATH"}))
18302 {
18303 if(is_abs($Path)) {
18304 $DefaultLibPaths{$Path} = 1;
18305 }
18306 }
18307 }
18308 }
18309 if($LSearch)
18310 { # using linker to get system paths
18311 if(my $LPaths = detect_lib_default_paths())
18312 { # unix-like
18313 foreach my $Name (keys(%{$LPaths}))
18314 {
18315 if($SystemRoot
18316 and $LPaths->{$Name}!~/\A\Q$SystemRoot\E\//)
18317 { # wrong ldconfig configuration
18318 # check your <sysroot>/etc/ld.so.conf
18319 next;
18320 }
18321 $DyLib_DefaultPath{$Name} = $LPaths->{$Name};
18322 $DefaultLibPaths{get_dirname($LPaths->{$Name})} = 1;
18323 }
18324 }
18325 foreach my $Path (keys(%DefaultLibPaths)) {
18326 $SystemPaths{"lib"}{$Path} = $DefaultLibPaths{$Path};
18327 }
18328 }
18329 if($BSearch)
18330 {
18331 if($CrossGcc)
18332 { # --cross-gcc=arm-linux-gcc
18333 if(-e $CrossGcc)
18334 { # absolute or relative path
18335 $GCC_PATH = get_abs_path($CrossGcc);
18336 }
18337 elsif($CrossGcc!~/\// and get_CmdPath($CrossGcc))
18338 { # command name
18339 $GCC_PATH = $CrossGcc;
18340 }
18341 else {
18342 exitStatus("Access_Error", "can't access \'$CrossGcc\'");
18343 }
18344 if($GCC_PATH=~/\s/) {
18345 $GCC_PATH = "\"".$GCC_PATH."\"";
18346 }
18347 }
18348 }
18349 if($GSearch)
18350 { # GCC path and default include dirs
18351 if(not $CrossGcc) {
18352 $GCC_PATH = get_CmdPath("gcc");
18353 }
Andrey Ponomarenko01117f12012-06-26 12:23:02 +040018354 if(not $GCC_PATH)
18355 { # try to find gcc-X.Y
18356 foreach my $Path (sort {$b=~/\/usr\/bin/ cmp $a=~/\/usr\/bin/}
18357 keys(%{$SystemPaths{"bin"}}))
18358 {
18359 if(my @GCCs = cmd_find($Path, "", ".*/gcc-[0-9.]*", 1))
18360 { # select the latest version
18361 @GCCs = sort {$b cmp $a} @GCCs;
18362 if(check_gcc($GCCs[0], "3"))
18363 {
18364 $GCC_PATH = $GCCs[0];
18365 last;
18366 }
18367 }
18368 }
18369 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040018370 if(not $GCC_PATH) {
18371 exitStatus("Not_Found", "can't find GCC>=3.0 in PATH");
18372 }
18373 if(not $CheckObjectsOnly_Opt)
18374 {
18375 if(my $GCC_Ver = get_dumpversion($GCC_PATH))
18376 {
18377 my $GccTarget = get_dumpmachine($GCC_PATH);
18378 printMsg("INFO", "Using GCC $GCC_Ver ($GccTarget)");
18379 if($GccTarget=~/symbian/)
18380 {
18381 $OStarget = "symbian";
18382 $LIB_EXT = $OS_LibExt{$LIB_TYPE}{$OStarget};
18383 }
18384 }
18385 else {
18386 exitStatus("Error", "something is going wrong with the GCC compiler");
18387 }
18388 }
18389 if(not $NoStdInc)
18390 { # do NOT search in GCC standard paths
18391 my %DPaths = detect_inc_default_paths();
18392 %DefaultCppPaths = %{$DPaths{"Cpp"}};
18393 %DefaultGccPaths = %{$DPaths{"Gcc"}};
18394 %DefaultIncPaths = %{$DPaths{"Inc"}};
18395 foreach my $Path (keys(%DefaultIncPaths)) {
18396 $SystemPaths{"include"}{$Path} = $DefaultIncPaths{$Path};
18397 }
18398 }
18399 }
18400 if($HSearch)
18401 { # user include paths
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040018402 my $IncPath = "/usr/include";
18403 if($SystemRoot) {
18404 $IncPath = $SystemRoot.$IncPath;
18405 }
18406 if(-d $IncPath) {
18407 $UserIncPath{$IncPath}=1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040018408 }
18409 }
18410}
18411
18412sub getLIB_EXT($)
18413{
18414 my $Target = $_[0];
18415 if(my $Ext = $OS_LibExt{$LIB_TYPE}{$Target}) {
18416 return $Ext;
18417 }
18418 return $OS_LibExt{$LIB_TYPE}{"default"};
18419}
18420
18421sub getAR_EXT($)
18422{
18423 my $Target = $_[0];
18424 if(my $Ext = $OS_Archive{$Target}) {
18425 return $Ext;
18426 }
18427 return $OS_Archive{"default"};
18428}
18429
18430sub get_dumpversion($)
18431{
18432 my $Cmd = $_[0];
18433 return "" if(not $Cmd);
18434 if($Cache{"get_dumpversion"}{$Cmd}) {
18435 return $Cache{"get_dumpversion"}{$Cmd};
18436 }
Andrey Ponomarenkoa01311b2012-06-08 17:20:02 +040018437 my $V = `$Cmd -dumpversion 2>\"$TMP_DIR/null\"`;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040018438 chomp($V);
18439 return ($Cache{"get_dumpversion"}{$Cmd} = $V);
18440}
18441
18442sub get_dumpmachine($)
18443{
18444 my $Cmd = $_[0];
18445 return "" if(not $Cmd);
18446 if($Cache{"get_dumpmachine"}{$Cmd}) {
18447 return $Cache{"get_dumpmachine"}{$Cmd};
18448 }
Andrey Ponomarenkoa01311b2012-06-08 17:20:02 +040018449 my $Machine = `$Cmd -dumpmachine 2>\"$TMP_DIR/null\"`;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040018450 chomp($Machine);
18451 return ($Cache{"get_dumpmachine"}{$Cmd} = $Machine);
18452}
18453
18454sub check_command($)
18455{
18456 my $Cmd = $_[0];
18457 return "" if(not $Cmd);
18458 my @Options = (
18459 "--version",
18460 "-help"
18461 );
18462 foreach my $Opt (@Options)
18463 {
Andrey Ponomarenkoa01311b2012-06-08 17:20:02 +040018464 my $Info = `$Cmd $Opt 2>\"$TMP_DIR/null\"`;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040018465 if($Info) {
18466 return 1;
18467 }
18468 }
18469 return 0;
18470}
18471
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040018472sub check_gcc($$)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040018473{
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040018474 my ($Cmd, $ReqVer) = @_;
18475 return 0 if(not $Cmd or not $ReqVer);
18476 if(defined $Cache{"check_gcc"}{$Cmd}{$ReqVer}) {
18477 return $Cache{"check_gcc"}{$Cmd}{$ReqVer};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040018478 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040018479 if(my $GccVer = get_dumpversion($Cmd))
18480 {
18481 $GccVer=~s/(-|_)[a-z_]+.*\Z//; # remove suffix (like "-haiku-100818")
18482 if(cmpVersions($GccVer, $ReqVer)>=0) {
18483 return ($Cache{"check_gcc"}{$Cmd}{$ReqVer} = $Cmd);
18484 }
18485 }
18486 return ($Cache{"check_gcc"}{$Cmd}{$ReqVer} = "");
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040018487}
18488
18489sub get_depth($)
18490{
18491 if(defined $Cache{"get_depth"}{$_[0]}) {
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040018492 return $Cache{"get_depth"}{$_[0]};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040018493 }
18494 return ($Cache{"get_depth"}{$_[0]} = ($_[0]=~tr![\/\\]|\:\:!!));
18495}
18496
18497sub find_gcc_cxx_headers($)
18498{
18499 my $LibVersion = $_[0];
18500 return if($Cache{"find_gcc_cxx_headers"});# this function should be called once
18501 # detecting system header paths
18502 foreach my $Path (sort {get_depth($b) <=> get_depth($a)} keys(%DefaultGccPaths))
18503 {
18504 foreach my $HeaderPath (sort {get_depth($a) <=> get_depth($b)} cmd_find($Path,"f","",""))
18505 {
18506 my $FileName = get_filename($HeaderPath);
18507 next if($DefaultGccHeader{$FileName});
18508 $DefaultGccHeader{$FileName} = $HeaderPath;
18509 }
18510 }
18511 if($COMMON_LANGUAGE{$LibVersion} eq "C++" and not $STDCXX_TESTING)
18512 {
18513 foreach my $CppDir (sort {get_depth($b)<=>get_depth($a)} keys(%DefaultCppPaths))
18514 {
18515 my @AllCppHeaders = cmd_find($CppDir,"f","","");
18516 foreach my $Path (sort {get_depth($a)<=>get_depth($b)} @AllCppHeaders)
18517 {
18518 my $FileName = get_filename($Path);
18519 next if($DefaultCppHeader{$FileName});
18520 $DefaultCppHeader{$FileName} = $Path;
18521 }
18522 }
18523 }
18524 $Cache{"find_gcc_cxx_headers"} = 1;
18525}
18526
18527sub parse_libname($$$)
18528{
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040018529 return "" if(not $_[0]);
18530 if(defined $Cache{"parse_libname"}{$_[2]}{$_[1]}{$_[0]}) {
18531 return $Cache{"parse_libname"}{$_[2]}{$_[1]}{$_[0]};
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040018532 }
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040018533 return ($Cache{"parse_libname"}{$_[2]}{$_[1]}{$_[0]} = parse_libname_I(@_));
18534}
18535
18536sub parse_libname_I($$$)
18537{
18538 my ($Name, $Type, $Target) = @_;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040018539 if($Target eq "symbian") {
18540 return parse_libname_symbian($Name, $Type);
18541 }
18542 elsif($Target eq "windows") {
18543 return parse_libname_windows($Name, $Type);
18544 }
18545 my $Ext = getLIB_EXT($Target);
Andrey Ponomarenkoa01311b2012-06-08 17:20:02 +040018546 if($Name=~/((((lib|).+?)([\-\_][\d\-\.\_]+.*?|))\.$Ext)(\.(.+)|)\Z/)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040018547 { # libSDL-1.2.so.0.7.1
18548 # libwbxml2.so.0.0.18
Andrey Ponomarenkoa01311b2012-06-08 17:20:02 +040018549 # libopcodes-2.21.53-system.20110810.so
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040018550 if($Type eq "name")
18551 { # libSDL-1.2
18552 # libwbxml2
18553 return $2;
18554 }
18555 elsif($Type eq "name+ext")
18556 { # libSDL-1.2.so
18557 # libwbxml2.so
18558 return $1;
18559 }
18560 elsif($Type eq "version")
18561 {
Andrey Ponomarenkoa01311b2012-06-08 17:20:02 +040018562 if(defined $7
18563 and $7 ne "")
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040018564 { # 0.7.1
18565 return $7;
18566 }
18567 else
18568 { # libc-2.5.so (=>2.5 version)
18569 my $MV = $5;
18570 $MV=~s/\A[\-\_]+//g;
18571 return $MV;
18572 }
18573 }
18574 elsif($Type eq "short")
18575 { # libSDL
18576 # libwbxml2
18577 return $3;
18578 }
18579 elsif($Type eq "shortest")
18580 { # SDL
18581 # wbxml
18582 return shortest_name($3);
18583 }
18584 }
18585 return "";# error
18586}
18587
18588sub parse_libname_symbian($$)
18589{
18590 my ($Name, $Type) = @_;
18591 my $Ext = getLIB_EXT("symbian");
18592 if($Name=~/(((.+?)(\{.+\}|))\.$Ext)\Z/)
18593 { # libpthread{00010001}.dso
18594 if($Type eq "name")
18595 { # libpthread{00010001}
18596 return $2;
18597 }
18598 elsif($Type eq "name+ext")
18599 { # libpthread{00010001}.dso
18600 return $1;
18601 }
18602 elsif($Type eq "version")
18603 { # 00010001
18604 my $V = $4;
18605 $V=~s/\{(.+)\}/$1/;
18606 return $V;
18607 }
18608 elsif($Type eq "short")
18609 { # libpthread
18610 return $3;
18611 }
18612 elsif($Type eq "shortest")
18613 { # pthread
18614 return shortest_name($3);
18615 }
18616 }
18617 return "";# error
18618}
18619
18620sub parse_libname_windows($$)
18621{
18622 my ($Name, $Type) = @_;
18623 my $Ext = getLIB_EXT("windows");
18624 if($Name=~/((.+?)\.$Ext)\Z/)
18625 { # netapi32.dll
18626 if($Type eq "name")
18627 { # netapi32
18628 return $2;
18629 }
18630 elsif($Type eq "name+ext")
18631 { # netapi32.dll
18632 return $1;
18633 }
18634 elsif($Type eq "version")
18635 { # DLL version embedded
18636 # at binary-level
18637 return "";
18638 }
18639 elsif($Type eq "short")
18640 { # netapi32
18641 return $2;
18642 }
18643 elsif($Type eq "shortest")
18644 { # netapi
18645 return shortest_name($2);
18646 }
18647 }
18648 return "";# error
18649}
18650
18651sub shortest_name($)
18652{
18653 my $Name = $_[0];
18654 # remove prefix
18655 $Name=~s/\A(lib|open)//;
18656 # remove suffix
18657 $Name=~s/[\W\d_]+\Z//i;
18658 $Name=~s/([a-z]{2,})(lib)\Z/$1/i;
18659 return $Name;
18660}
18661
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040018662sub createSymbolsList($$$$$)
18663{
18664 my ($DPath, $SaveTo, $LName, $LVersion, $ArchName) = @_;
18665 read_ABI_Dump(1, $DPath);
18666 if(not $CheckObjectsOnly) {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040018667 prepareSymbols(1);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040018668 }
18669 my %SymbolHeaderLib = ();
18670 my $Total = 0;
18671 # Get List
18672 foreach my $Symbol (sort keys(%{$CompleteSignature{1}}))
18673 {
18674 if(not link_symbol($Symbol, 1, "-Deps"))
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040018675 { # skip src only and all external functions
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040018676 next;
18677 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040018678 if(not symbolFilter($Symbol, 1, "Public", "Binary"))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040018679 { # skip other symbols
18680 next;
18681 }
18682 my $HeaderName = $CompleteSignature{1}{$Symbol}{"Header"};
18683 if(not $HeaderName)
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040018684 { # skip src only and all external functions
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040018685 next;
18686 }
18687 my $DyLib = $Symbol_Library{1}{$Symbol};
18688 if(not $DyLib)
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040018689 { # skip src only and all external functions
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040018690 next;
18691 }
18692 $SymbolHeaderLib{$HeaderName}{$DyLib}{$Symbol} = 1;
18693 $Total+=1;
18694 }
18695 # Draw List
18696 my $SYMBOLS_LIST = "<h1>Public symbols in <span style='color:Blue;'>$LName</span> (<span style='color:Red;'>$LVersion</span>)";
18697 $SYMBOLS_LIST .= " on <span style='color:Blue;'>".showArch($ArchName)."</span><br/>Total: $Total</h1><br/>";
18698 foreach my $HeaderName (sort {lc($a) cmp lc($b)} keys(%SymbolHeaderLib))
18699 {
18700 foreach my $DyLib (sort {lc($a) cmp lc($b)} keys(%{$SymbolHeaderLib{$HeaderName}}))
18701 {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040018702 my %NS_Symbol = ();
18703 foreach my $Symbol (keys(%{$SymbolHeaderLib{$HeaderName}{$DyLib}})) {
18704 $NS_Symbol{get_IntNameSpace($Symbol, 1)}{$Symbol} = 1;
18705 }
18706 foreach my $NameSpace (sort keys(%NS_Symbol))
18707 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040018708 $SYMBOLS_LIST .= getTitle($HeaderName, $DyLib, $NameSpace);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040018709 my @SortedInterfaces = sort {lc(get_Signature($a, 1)) cmp lc(get_Signature($b, 1))} keys(%{$NS_Symbol{$NameSpace}});
18710 foreach my $Symbol (@SortedInterfaces)
18711 {
18712 my $SubReport = "";
18713 my $Signature = get_Signature($Symbol, 1);
18714 if($NameSpace) {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040018715 $Signature=~s/\b\Q$NameSpace\E::\b//g;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040018716 }
18717 if($Symbol=~/\A(_Z|\?)/)
18718 {
18719 if($Signature) {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040018720 $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 +040018721 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040018722 else {
18723 $SubReport = "<span class='iname'>".$Symbol."</span><br/>\n";
18724 }
18725 }
18726 else
18727 {
18728 if($Signature) {
18729 $SubReport = "<span class='iname'>".highLight_Signature_Italic_Color($Signature)."</span><br/>\n";
18730 }
18731 else {
18732 $SubReport = "<span class='iname'>".$Symbol."</span><br/>\n";
18733 }
18734 }
18735 $SYMBOLS_LIST .= $SubReport;
18736 }
18737 }
18738 $SYMBOLS_LIST .= "<br/>\n";
18739 }
18740 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040018741 # clear info
18742 (%TypeInfo, %SymbolInfo, %Library_Symbol, %DepSymbol_Library,
18743 %DepLibrary_Symbol, %SymVer, %SkipTypes, %SkipSymbols,
18744 %NestedNameSpaces, %ClassMethods, %AllocableClass, %ClassNames,
18745 %CompleteSignature, %SkipNameSpaces, %Symbol_Library, %Library_Symbol) = ();
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040018746 ($Content_Counter, $ContentID) = (0, 0);
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040018747 # print report
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040018748 my $CssStyles = readModule("Styles", "SymbolsList.css");
18749 my $JScripts = readModule("Scripts", "Sections.js");
18750 $SYMBOLS_LIST = "<a name='Top'></a>".$SYMBOLS_LIST.$TOP_REF."<br/>\n";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040018751 my $Title = "$LName: public symbols";
18752 my $Keywords = "$LName, API, symbols";
18753 my $Description = "List of symbols in $LName ($LVersion) on ".showArch($ArchName);
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040018754 $SYMBOLS_LIST = composeHTML_Head($Title, $Keywords, $Description, $CssStyles, $JScripts)."
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040018755 <body><div>\n$SYMBOLS_LIST</div>
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040018756 <br/><br/><hr/>\n".getReportFooter($LName, 1)."
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040018757 <div style='height:999px;'></div></body></html>";
18758 writeFile($SaveTo, $SYMBOLS_LIST);
18759}
18760
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040018761sub readModule($$)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040018762{
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040018763 my ($Module, $Name) = @_;
18764 my $Path = $MODULES_DIR."/Internals/$Module/".$Name;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040018765 if(not -f $Path) {
18766 exitStatus("Module_Error", "can't access \'$Path\'");
18767 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040018768 return readFile($Path);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040018769}
18770
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040018771sub add_target_libs($)
18772{
18773 foreach (@{$_[0]}) {
18774 $TargetLibs{$_} = 1;
18775 }
18776}
18777
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040018778sub is_target_lib($)
18779{
18780 my $LName = $_[0];
Andrey Ponomarenkoa01311b2012-06-08 17:20:02 +040018781 if(not $LName) {
18782 return 0;
18783 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040018784 if($TargetLibraryName
18785 and $LName!~/\Q$TargetLibraryName\E/) {
18786 return 0;
18787 }
18788 if(keys(%TargetLibs)
18789 and not $TargetLibs{$LName}
18790 and not $TargetLibs{parse_libname($LName, "name+ext", $OStarget)}) {
18791 return 0;
18792 }
18793 return 1;
18794}
18795
Andrey Ponomarenko85043792012-05-14 16:48:07 +040018796sub is_target_header($$)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040018797{ # --header, --headers-list
Andrey Ponomarenko85043792012-05-14 16:48:07 +040018798 my ($H, $V) = @_;
18799 if(keys(%{$TargetHeaders{$V}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040018800 {
Andrey Ponomarenko85043792012-05-14 16:48:07 +040018801 if($TargetHeaders{$V}{$H}) {
18802 return 1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040018803 }
18804 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +040018805 return 0;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040018806}
18807
18808sub checkVersionNum($$)
18809{
18810 my ($LibVersion, $Path) = @_;
18811 if(my $VerNum = $TargetVersion{$LibVersion}) {
18812 return $VerNum;
18813 }
18814 my $UsedAltDescr = 0;
18815 foreach my $Part (split(/\s*,\s*/, $Path))
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040018816 { # try to get version string from file path
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040018817 next if(isDump($Part)); # ABI dump
18818 next if($Part=~/\.(xml|desc)\Z/i); # XML descriptor
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040018819 my $VerNum = "";
18820 if(parse_libname($Part, "name", $OStarget))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040018821 {
18822 $UsedAltDescr = 1;
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040018823 $VerNum = parse_libname($Part, "version", $OStarget);
18824 if(not $VerNum) {
Andrey Ponomarenko07aea072012-11-12 16:15:07 +040018825 $VerNum = readStrVer($Part);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040018826 }
18827 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040018828 elsif(is_header($Part, 2, $LibVersion) or -d $Part)
18829 {
18830 $UsedAltDescr = 1;
Andrey Ponomarenko07aea072012-11-12 16:15:07 +040018831 $VerNum = readStrVer($Part);
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040018832 }
18833 if($VerNum ne "")
18834 {
18835 $TargetVersion{$LibVersion} = $VerNum;
18836 if($DumpAPI) {
18837 printMsg("WARNING", "setting version number to $VerNum (use -vnum <num> option to change it)");
18838 }
18839 else {
18840 printMsg("WARNING", "setting ".($LibVersion==1?"1st":"2nd")." version number to \"$VerNum\" (use -v$LibVersion <num> option to change it)");
18841 }
18842 return $TargetVersion{$LibVersion};
18843 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040018844 }
18845 if($UsedAltDescr)
18846 {
18847 if($DumpAPI) {
18848 exitStatus("Error", "version number is not set (use -vnum <num> option)");
18849 }
18850 else {
18851 exitStatus("Error", ($LibVersion==1?"1st":"2nd")." version number is not set (use -v$LibVersion <num> option)");
18852 }
18853 }
18854}
18855
Andrey Ponomarenko07aea072012-11-12 16:15:07 +040018856sub readStrVer($)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040018857{
18858 my $Str = $_[0];
18859 return "" if(not $Str);
18860 $Str=~s/\Q$TargetLibraryName\E//g;
18861 if($Str=~/(\/|\\|\w|\A)[\-\_]*(\d+[\d\.\-]+\d+|\d+)/)
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040018862 { # .../libssh-0.4.0/...
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040018863 return $2;
18864 }
18865 elsif(my $V = parse_libname($Str, "version", $OStarget)) {
18866 return $V;
18867 }
18868 return "";
18869}
18870
18871sub readLibs($)
18872{
18873 my $LibVersion = $_[0];
18874 if($OStarget eq "windows")
18875 { # dumpbin.exe will crash
18876 # without VS Environment
18877 check_win32_env();
18878 }
Andrey Ponomarenko16934472012-03-29 15:37:04 +040018879 readSymbols($LibVersion);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040018880 translateSymbols(keys(%{$Symbol_Library{$LibVersion}}), $LibVersion);
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040018881 translateSymbols(keys(%{$DepSymbol_Library{$LibVersion}}), $LibVersion);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040018882}
18883
18884sub dump_sorting($)
18885{
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +040018886 my $Hash = $_[0];
18887 return [] if(not $Hash);
18888 my @Keys = keys(%{$Hash});
18889 return [] if($#Keys<0);
18890 if($Keys[0]=~/\A\d+\Z/)
18891 { # numbers
18892 return [sort {int($a)<=>int($b)} @Keys];
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040018893 }
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +040018894 else
18895 { # strings
18896 return [sort {$a cmp $b} @Keys];
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040018897 }
18898}
18899
18900sub printMsg($$)
18901{
18902 my ($Type, $Msg) = @_;
18903 if($Type!~/\AINFO/) {
18904 $Msg = $Type.": ".$Msg;
18905 }
18906 if($Type!~/_C\Z/) {
18907 $Msg .= "\n";
18908 }
18909 if($Quiet)
18910 { # --quiet option
18911 appendFile($COMMON_LOG_PATH, $Msg);
18912 }
18913 else
18914 {
18915 if($Type eq "ERROR") {
18916 print STDERR $Msg;
18917 }
18918 else {
18919 print $Msg;
18920 }
18921 }
18922}
18923
18924sub exitStatus($$)
18925{
18926 my ($Code, $Msg) = @_;
18927 printMsg("ERROR", $Msg);
18928 exit($ERROR_CODE{$Code});
18929}
18930
18931sub exitReport()
18932{ # the tool has run without any errors
18933 printReport();
18934 if($COMPILE_ERRORS)
18935 { # errors in headers may add false positives/negatives
18936 exit($ERROR_CODE{"Compile_Error"});
18937 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040018938 if($BinaryOnly and $RESULT{"Binary"}{"Problems"})
18939 { # --binary
18940 exit($ERROR_CODE{"Incompatible"});
18941 }
18942 elsif($SourceOnly and $RESULT{"Source"}{"Problems"})
18943 { # --source
18944 exit($ERROR_CODE{"Incompatible"});
18945 }
18946 elsif($RESULT{"Source"}{"Problems"}
18947 or $RESULT{"Binary"}{"Problems"})
18948 { # default
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040018949 exit($ERROR_CODE{"Incompatible"});
18950 }
18951 else {
18952 exit($ERROR_CODE{"Compatible"});
18953 }
18954}
18955
18956sub readRules($)
18957{
18958 my $Kind = $_[0];
18959 if(not -f $RULES_PATH{$Kind}) {
18960 exitStatus("Module_Error", "can't access \'".$RULES_PATH{$Kind}."\'");
18961 }
18962 my $Content = readFile($RULES_PATH{$Kind});
18963 while(my $Rule = parseTag(\$Content, "rule"))
18964 {
18965 my $RId = parseTag(\$Rule, "id");
18966 my @Properties = ("Severity", "Change", "Effect", "Overcome", "Kind");
18967 foreach my $Prop (@Properties) {
18968 if(my $Value = parseTag(\$Rule, lc($Prop)))
18969 {
18970 $Value=~s/\n[ ]*//;
18971 $CompatRules{$Kind}{$RId}{$Prop} = $Value;
18972 }
18973 }
18974 if($CompatRules{$Kind}{$RId}{"Kind"}=~/\A(Symbols|Parameters)\Z/) {
18975 $CompatRules{$Kind}{$RId}{"Kind"} = "Symbols";
18976 }
18977 else {
18978 $CompatRules{$Kind}{$RId}{"Kind"} = "Types";
18979 }
18980 }
18981}
18982
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040018983sub getReportPath($)
18984{
18985 my $Level = $_[0];
18986 my $Dir = "compat_reports/$TargetLibraryName/".$Descriptor{1}{"Version"}."_to_".$Descriptor{2}{"Version"};
18987 if($Level eq "Binary")
18988 {
18989 if($BinaryReportPath)
18990 { # --bin-report-path
18991 return $BinaryReportPath;
18992 }
18993 elsif($OutputReportPath)
18994 { # --report-path
18995 return $OutputReportPath;
18996 }
18997 else
18998 { # default
18999 return $Dir."/abi_compat_report.$ReportFormat";
19000 }
19001 }
19002 elsif($Level eq "Source")
19003 {
19004 if($SourceReportPath)
19005 { # --src-report-path
19006 return $SourceReportPath;
19007 }
19008 elsif($OutputReportPath)
19009 { # --report-path
19010 return $OutputReportPath;
19011 }
19012 else
19013 { # default
19014 return $Dir."/src_compat_report.$ReportFormat";
19015 }
19016 }
19017 else
19018 {
19019 if($OutputReportPath)
19020 { # --report-path
19021 return $OutputReportPath;
19022 }
19023 else
19024 { # default
19025 return $Dir."/compat_report.$ReportFormat";
19026 }
19027 }
19028}
19029
19030sub printStatMsg($)
19031{
19032 my $Level = $_[0];
19033 printMsg("INFO", "total \"$Level\" compatibility problems: ".$RESULT{$Level}{"Problems"}.", warnings: ".$RESULT{$Level}{"Warnings"});
19034}
19035
19036sub listAffected($)
19037{
19038 my $Level = $_[0];
19039 my $List = "";
19040 foreach (keys(%{$TotalAffected{$Level}}))
19041 {
19042 if($StrictCompat and $TotalAffected{$Level}{$_} eq "Low")
19043 { # skip "Low"-severity problems
19044 next;
19045 }
19046 $List .= "$_\n";
19047 }
19048 my $Dir = get_dirname(getReportPath($Level));
19049 if($Level eq "Binary") {
19050 writeFile($Dir."/abi_affected.txt", $List);
19051 }
19052 elsif($Level eq "Source") {
19053 writeFile($Dir."/src_affected.txt", $List);
19054 }
19055}
19056
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040019057sub printReport()
19058{
19059 printMsg("INFO", "creating compatibility report ...");
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040019060 createReport();
19061 if($JoinReport or $DoubleReport)
19062 {
19063 if($RESULT{"Binary"}{"Problems"}
19064 or $RESULT{"Source"}{"Problems"}) {
19065 printMsg("INFO", "result: INCOMPATIBLE (Binary: ".$RESULT{"Binary"}{"Affected"}."\%, Source: ".$RESULT{"Source"}{"Affected"}."\%)");
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040019066 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040019067 else {
19068 printMsg("INFO", "result: COMPATIBLE");
19069 }
19070 printStatMsg("Binary");
19071 printStatMsg("Source");
19072 if($ListAffected)
19073 { # --list-affected
19074 listAffected("Binary");
19075 listAffected("Source");
19076 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040019077 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040019078 elsif($BinaryOnly)
19079 {
19080 if($RESULT{"Binary"}{"Problems"}) {
19081 printMsg("INFO", "result: INCOMPATIBLE (".$RESULT{"Binary"}{"Affected"}."\%)");
19082 }
19083 else {
19084 printMsg("INFO", "result: COMPATIBLE");
19085 }
19086 printStatMsg("Binary");
19087 if($ListAffected)
19088 { # --list-affected
19089 listAffected("Binary");
19090 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040019091 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040019092 elsif($SourceOnly)
19093 {
19094 if($RESULT{"Source"}{"Problems"}) {
19095 printMsg("INFO", "result: INCOMPATIBLE (".$RESULT{"Source"}{"Affected"}."\%)");
19096 }
19097 else {
19098 printMsg("INFO", "result: COMPATIBLE");
19099 }
19100 printStatMsg("Source");
19101 if($ListAffected)
19102 { # --list-affected
19103 listAffected("Source");
19104 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040019105 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040019106 if($StdOut)
19107 {
19108 if($JoinReport or not $DoubleReport)
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040019109 { # --binary or --source
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040019110 printMsg("INFO", "compatibility report has been generated to stdout");
19111 }
19112 else
19113 { # default
19114 printMsg("INFO", "compatibility reports have been generated to stdout");
19115 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040019116 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040019117 else
19118 {
19119 if($JoinReport)
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040019120 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040019121 printMsg("INFO", "see detailed report:\n ".getReportPath("Join"));
19122 }
19123 elsif($DoubleReport)
19124 { # default
19125 printMsg("INFO", "see detailed reports:\n ".getReportPath("Binary")."\n ".getReportPath("Source"));
19126 }
19127 elsif($BinaryOnly)
19128 { # --binary
19129 printMsg("INFO", "see detailed report:\n ".getReportPath("Binary"));
19130 }
19131 elsif($SourceOnly)
19132 { # --source
19133 printMsg("INFO", "see detailed report:\n ".getReportPath("Source"));
19134 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040019135 }
19136}
19137
19138sub check_win32_env()
19139{
19140 if(not $ENV{"DevEnvDir"}
19141 or not $ENV{"LIB"}) {
19142 exitStatus("Error", "can't start without VS environment (vsvars32.bat)");
19143 }
19144}
19145
Andrey Ponomarenko5c09ef32012-06-14 18:17:33 +040019146sub diffSets($$)
19147{
19148 my ($S1, $S2) = @_;
19149 my @SK1 = keys(%{$S1});
19150 my @SK2 = keys(%{$S2});
19151 if($#SK1!=$#SK2) {
19152 return 1;
19153 }
19154 foreach my $K1 (@SK1)
19155 {
19156 if(not defined $S2->{$K1}) {
19157 return 1;
19158 }
19159 }
19160 return 0;
19161}
19162
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040019163sub create_ABI_Dump()
19164{
19165 if(not -e $DumpAPI) {
19166 exitStatus("Access_Error", "can't access \'$DumpAPI\'");
19167 }
19168 # check the archive utilities
19169 if($OSgroup eq "windows")
19170 { # using zip
19171 my $ZipCmd = get_CmdPath("zip");
19172 if(not $ZipCmd) {
19173 exitStatus("Not_Found", "can't find \"zip\"");
19174 }
19175 }
19176 else
19177 { # using tar and gzip
19178 my $TarCmd = get_CmdPath("tar");
19179 if(not $TarCmd) {
19180 exitStatus("Not_Found", "can't find \"tar\"");
19181 }
19182 my $GzipCmd = get_CmdPath("gzip");
19183 if(not $GzipCmd) {
19184 exitStatus("Not_Found", "can't find \"gzip\"");
19185 }
19186 }
19187 my @DParts = split(/\s*,\s*/, $DumpAPI);
19188 foreach my $Part (@DParts)
19189 {
19190 if(not -e $Part) {
19191 exitStatus("Access_Error", "can't access \'$Part\'");
19192 }
19193 }
19194 checkVersionNum(1, $DumpAPI);
19195 foreach my $Part (@DParts)
19196 {
19197 if(isDump($Part)) {
19198 read_ABI_Dump(1, $Part);
19199 }
19200 else {
19201 readDescriptor(1, createDescriptor(1, $Part));
19202 }
19203 }
19204 initLogging(1);
19205 detect_default_paths("inc|lib|bin|gcc"); # complete analysis
Andrey Ponomarenko01117f12012-06-26 12:23:02 +040019206 if(not $Descriptor{1}{"Dump"})
19207 {
19208 if(not $CheckHeadersOnly) {
19209 readLibs(1);
19210 }
19211 if($CheckHeadersOnly) {
19212 setLanguage(1, "C++");
19213 }
19214 if(not $CheckObjectsOnly) {
19215 searchForHeaders(1);
19216 }
19217 $WORD_SIZE{1} = detectWordSize();
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040019218 }
Andrey Ponomarenko01117f12012-06-26 12:23:02 +040019219 if(not $Descriptor{1}{"Dump"})
19220 {
19221 if($Descriptor{1}{"Headers"}) {
19222 readHeaders(1);
19223 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040019224 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +040019225 cleanDump(1);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040019226 if(not keys(%{$SymbolInfo{1}}))
19227 { # check if created dump is valid
19228 if(not $ExtendedCheck and not $CheckObjectsOnly)
19229 {
19230 if($CheckHeadersOnly) {
19231 exitStatus("Empty_Set", "the set of public symbols is empty");
19232 }
19233 else {
19234 exitStatus("Empty_Intersection", "the sets of public symbols in headers and libraries have empty intersection");
19235 }
19236 }
19237 }
19238 my %HeadersInfo = ();
19239 foreach my $HPath (keys(%{$Registered_Headers{1}}))
19240 { # headers info stored without paths in the dump
19241 $HeadersInfo{$Registered_Headers{1}{$HPath}{"Identity"}} = $Registered_Headers{1}{$HPath}{"Pos"};
19242 }
19243 printMsg("INFO", "creating library ABI dump ...");
Andrey Ponomarenko01117f12012-06-26 12:23:02 +040019244 my %ABI = (
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040019245 "TypeInfo" => $TypeInfo{1},
19246 "SymbolInfo" => $SymbolInfo{1},
19247 "Symbols" => $Library_Symbol{1},
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040019248 "DepSymbols" => $DepLibrary_Symbol{1},
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040019249 "SymbolVersion" => $SymVer{1},
19250 "LibraryVersion" => $Descriptor{1}{"Version"},
19251 "LibraryName" => $TargetLibraryName,
19252 "Language" => $COMMON_LANGUAGE{1},
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040019253 "SkipTypes" => $SkipTypes{1},
19254 "SkipSymbols" => $SkipSymbols{1},
19255 "SkipNameSpaces" => $SkipNameSpaces{1},
19256 "SkipHeaders" => $SkipHeadersList{1},
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040019257 "Headers" => \%HeadersInfo,
19258 "Constants" => $Constants{1},
19259 "NameSpaces" => $NestedNameSpaces{1},
19260 "Target" => $OStarget,
19261 "Arch" => getArch(1),
19262 "WordSize" => $WORD_SIZE{1},
19263 "GccVersion" => get_dumpversion($GCC_PATH),
19264 "ABI_DUMP_VERSION" => $ABI_DUMP_VERSION,
19265 "ABI_COMPLIANCE_CHECKER_VERSION" => $TOOL_VERSION
19266 );
Andrey Ponomarenko5c09ef32012-06-14 18:17:33 +040019267 if(diffSets($TargetHeaders{1}, \%HeadersInfo)) {
Andrey Ponomarenko01117f12012-06-26 12:23:02 +040019268 $ABI{"TargetHeaders"} = $TargetHeaders{1};
Andrey Ponomarenko5c09ef32012-06-14 18:17:33 +040019269 }
19270 if($UseXML) {
Andrey Ponomarenko01117f12012-06-26 12:23:02 +040019271 $ABI{"XML_ABI_DUMP_VERSION"} = $XML_ABI_DUMP_VERSION;
Andrey Ponomarenko5c09ef32012-06-14 18:17:33 +040019272 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040019273 if($ExtendedCheck)
19274 { # --ext option
Andrey Ponomarenko01117f12012-06-26 12:23:02 +040019275 $ABI{"Mode"} = "Extended";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040019276 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040019277 if($BinaryOnly)
19278 { # --binary
Andrey Ponomarenko01117f12012-06-26 12:23:02 +040019279 $ABI{"BinOnly"} = 1;
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040019280 }
Andrey Ponomarenko5c09ef32012-06-14 18:17:33 +040019281
19282 my $ABI_DUMP = "";
19283 if($UseXML)
19284 {
19285 loadModule("XmlDump");
Andrey Ponomarenko01117f12012-06-26 12:23:02 +040019286 $ABI_DUMP = createXmlDump(\%ABI);
Andrey Ponomarenko5c09ef32012-06-14 18:17:33 +040019287 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040019288 else
19289 { # default
Andrey Ponomarenko01117f12012-06-26 12:23:02 +040019290 $ABI_DUMP = Dumper(\%ABI);
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040019291 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040019292 if($StdOut)
19293 { # --stdout option
Andrey Ponomarenko5c09ef32012-06-14 18:17:33 +040019294 print STDOUT $ABI_DUMP;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040019295 printMsg("INFO", "ABI dump has been generated to stdout");
19296 return;
19297 }
19298 else
19299 { # write to gzipped file
Andrey Ponomarenko5c09ef32012-06-14 18:17:33 +040019300 my $DumpPath = "abi_dumps/$TargetLibraryName/".$TargetLibraryName."_".$Descriptor{1}{"Version"}.".abi";
19301 $DumpPath .= ".".$AR_EXT; # gzipped by default
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040019302 if($OutputDumpPath)
19303 { # user defined path
19304 $DumpPath = $OutputDumpPath;
19305 }
Andrey Ponomarenko5c09ef32012-06-14 18:17:33 +040019306 my $Archive = ($DumpPath=~s/\Q.$AR_EXT\E\Z//g);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040019307 my ($DDir, $DName) = separate_path($DumpPath);
19308 my $DPath = $TMP_DIR."/".$DName;
Andrey Ponomarenko5c09ef32012-06-14 18:17:33 +040019309 if(not $Archive) {
19310 $DPath = $DumpPath;
19311 }
19312
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040019313 mkpath($DDir);
Andrey Ponomarenko85043792012-05-14 16:48:07 +040019314
19315 open(DUMP, ">", $DPath) || die ("can't open file \'$DPath\': $!\n");
Andrey Ponomarenko5c09ef32012-06-14 18:17:33 +040019316 print DUMP $ABI_DUMP;
Andrey Ponomarenko85043792012-05-14 16:48:07 +040019317 close(DUMP);
19318
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040019319 if(not -s $DPath) {
19320 exitStatus("Error", "can't create ABI dump because something is going wrong with the Data::Dumper module");
19321 }
Andrey Ponomarenko07aea072012-11-12 16:15:07 +040019322 if($Archive) {
19323 $DumpPath = createArchive($DPath, $DDir);
Andrey Ponomarenko5c09ef32012-06-14 18:17:33 +040019324 }
19325
Andrey Ponomarenko07aea072012-11-12 16:15:07 +040019326 if(not $OutputDumpPath)
19327 {
19328 printMsg("INFO", "library ABI has been dumped to:\n $DumpPath");
19329 printMsg("INFO", "you can transfer this dump everywhere and use instead of the ".$Descriptor{1}{"Version"}." version descriptor");
19330 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040019331 }
19332}
19333
19334sub quickEmptyReports()
19335{ # Quick "empty" reports
19336 # 4 times faster than merging equal dumps
19337 # NOTE: the dump contains the "LibraryVersion" attribute
19338 # if you change the version, then your dump will be different
19339 # OVERCOME: use -v1 and v2 options for comparing dumps
19340 # and don't change version in the XML descriptor (and dumps)
19341 # OVERCOME 2: separate meta info from the dumps in ACC 2.0
19342 if(-s $Descriptor{1}{"Path"} == -s $Descriptor{2}{"Path"})
19343 {
19344 my $FilePath1 = unpackDump($Descriptor{1}{"Path"});
19345 my $FilePath2 = unpackDump($Descriptor{2}{"Path"});
19346 if($FilePath1 and $FilePath2)
19347 {
Andrey Ponomarenko01117f12012-06-26 12:23:02 +040019348 my $Line = readLineNum($FilePath1, 0);
19349 if($Line=~/xml/)
19350 { # XML format
19351 # is not supported yet
19352 return;
19353 }
19354
Andrey Ponomarenko85043792012-05-14 16:48:07 +040019355 local $/ = undef;
19356
19357 open(DUMP1, $FilePath1);
19358 my $Content1 = <DUMP1>;
19359 close(DUMP1);
19360
19361 open(DUMP2, $FilePath2);
19362 my $Content2 = <DUMP2>;
19363 close(DUMP2);
19364
19365 if($Content1 eq $Content2)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040019366 {
Andrey Ponomarenko85043792012-05-14 16:48:07 +040019367 # clean memory
19368 undef $Content2;
19369
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040019370 # read a number of headers, libs, symbols and types
Andrey Ponomarenko85043792012-05-14 16:48:07 +040019371 my $ABIdump = eval($Content1);
19372
19373 # clean memory
19374 undef $Content1;
19375
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040019376 if(not $ABIdump) {
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040019377 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 +040019378 }
19379 if(not $ABIdump->{"TypeInfo"})
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040019380 { # support for old dumps
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040019381 $ABIdump->{"TypeInfo"} = $ABIdump->{"TypeDescr"};
19382 }
19383 if(not $ABIdump->{"SymbolInfo"})
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040019384 { # support for old dumps
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040019385 $ABIdump->{"SymbolInfo"} = $ABIdump->{"FuncDescr"};
19386 }
19387 read_Headers_DumpInfo($ABIdump, 1);
19388 read_Libs_DumpInfo($ABIdump, 1);
19389 read_Machine_DumpInfo($ABIdump, 1);
19390 read_Machine_DumpInfo($ABIdump, 2);
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040019391
19392 %{$CheckedTypes{"Binary"}} = %{$ABIdump->{"TypeInfo"}};
19393 %{$CheckedTypes{"Source"}} = %{$ABIdump->{"TypeInfo"}};
19394
19395 %{$CheckedSymbols{"Binary"}} = %{$ABIdump->{"SymbolInfo"}};
19396 %{$CheckedSymbols{"Source"}} = %{$ABIdump->{"SymbolInfo"}};
19397
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040019398 $Descriptor{1}{"Version"} = $TargetVersion{1}?$TargetVersion{1}:$ABIdump->{"LibraryVersion"};
19399 $Descriptor{2}{"Version"} = $TargetVersion{2}?$TargetVersion{2}:$ABIdump->{"LibraryVersion"};
19400 exitReport();
19401 }
19402 }
19403 }
19404}
19405
19406sub initLogging($)
19407{
19408 my $LibVersion = $_[0];
19409 # create log directory
19410 my ($LOG_DIR, $LOG_FILE) = ("logs/$TargetLibraryName/".$Descriptor{$LibVersion}{"Version"}, "log.txt");
19411 if($OutputLogPath{$LibVersion})
19412 { # user-defined by -log-path option
19413 ($LOG_DIR, $LOG_FILE) = separate_path($OutputLogPath{$LibVersion});
19414 }
19415 if($LogMode ne "n") {
19416 mkpath($LOG_DIR);
19417 }
19418 $LOG_PATH{$LibVersion} = get_abs_path($LOG_DIR)."/".$LOG_FILE;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040019419 if($Debug)
19420 { # debug directory
19421 $DEBUG_PATH{$LibVersion} = "debug/$TargetLibraryName/".$Descriptor{$LibVersion}{"Version"};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040019422 }
Andrey Ponomarenko35c44fd2012-06-18 17:50:25 +040019423 resetLogging($LibVersion);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040019424}
19425
19426sub writeLog($$)
19427{
19428 my ($LibVersion, $Msg) = @_;
19429 if($LogMode ne "n") {
19430 appendFile($LOG_PATH{$LibVersion}, $Msg);
19431 }
19432}
19433
19434sub resetLogging($)
19435{
19436 my $LibVersion = $_[0];
19437 if($LogMode!~/a|n/)
19438 { # remove old log
19439 unlink($LOG_PATH{$LibVersion});
Andrey Ponomarenko35c44fd2012-06-18 17:50:25 +040019440 if($Debug) {
19441 rmtree($DEBUG_PATH{$LibVersion});
19442 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040019443 }
19444}
19445
19446sub printErrorLog($)
19447{
19448 my $LibVersion = $_[0];
19449 if($LogMode ne "n") {
19450 printMsg("ERROR", "see log for details:\n ".$LOG_PATH{$LibVersion}."\n");
19451 }
19452}
19453
19454sub isDump($)
19455{
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040019456 if(get_filename($_[0])=~/\A(.+)\.(abi|abidump)(\.tar\.gz|\.zip|\.xml|)\Z/) {
19457 return $1;
19458 }
19459 return 0;
19460}
19461
19462sub isDump_U($)
19463{
19464 if(get_filename($_[0])=~/\A(.+)\.(abi|abidump)(\.xml|)\Z/) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040019465 return $1;
19466 }
19467 return 0;
19468}
19469
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040019470sub compareInit()
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040019471{
19472 # read input XML descriptors or ABI dumps
19473 if(not $Descriptor{1}{"Path"}) {
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040019474 exitStatus("Error", "-old option is not specified");
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040019475 }
19476 my @DParts1 = split(/\s*,\s*/, $Descriptor{1}{"Path"});
19477 foreach my $Part (@DParts1)
19478 {
19479 if(not -e $Part) {
19480 exitStatus("Access_Error", "can't access \'$Part\'");
19481 }
19482 }
19483 if(not $Descriptor{2}{"Path"}) {
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040019484 exitStatus("Error", "-new option is not specified");
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040019485 }
19486 my @DParts2 = split(/\s*,\s*/, $Descriptor{2}{"Path"});
19487 foreach my $Part (@DParts2)
19488 {
19489 if(not -e $Part) {
19490 exitStatus("Access_Error", "can't access \'$Part\'");
19491 }
19492 }
19493 detect_default_paths("bin"); # to extract dumps
19494 if($#DParts1==0 and $#DParts2==0
19495 and isDump($Descriptor{1}{"Path"})
19496 and isDump($Descriptor{2}{"Path"}))
19497 { # optimization: equal ABI dumps
19498 quickEmptyReports();
19499 }
19500 checkVersionNum(1, $Descriptor{1}{"Path"});
19501 checkVersionNum(2, $Descriptor{2}{"Path"});
19502 printMsg("INFO", "preparation, please wait ...");
19503 foreach my $Part (@DParts1)
19504 {
19505 if(isDump($Part)) {
19506 read_ABI_Dump(1, $Part);
19507 }
19508 else {
19509 readDescriptor(1, createDescriptor(1, $Part));
19510 }
19511 }
19512 foreach my $Part (@DParts2)
19513 {
19514 if(isDump($Part)) {
19515 read_ABI_Dump(2, $Part);
19516 }
19517 else {
19518 readDescriptor(2, createDescriptor(2, $Part));
19519 }
19520 }
19521 initLogging(1);
19522 initLogging(2);
19523 # check consistency
19524 if(not $Descriptor{1}{"Headers"}
19525 and not $Descriptor{1}{"Libs"}) {
19526 exitStatus("Error", "descriptor d1 does not contain both header files and libraries info");
19527 }
19528 if(not $Descriptor{2}{"Headers"}
19529 and not $Descriptor{2}{"Libs"}) {
19530 exitStatus("Error", "descriptor d2 does not contain both header files and libraries info");
19531 }
19532 if($Descriptor{1}{"Headers"} and not $Descriptor{1}{"Libs"}
19533 and not $Descriptor{2}{"Headers"} and $Descriptor{2}{"Libs"}) {
19534 exitStatus("Error", "can't compare headers with $SLIB_TYPE libraries");
19535 }
19536 elsif(not $Descriptor{1}{"Headers"} and $Descriptor{1}{"Libs"}
19537 and $Descriptor{2}{"Headers"} and not $Descriptor{2}{"Libs"}) {
19538 exitStatus("Error", "can't compare $SLIB_TYPE libraries with headers");
19539 }
Andrey Ponomarenkobdc85a92012-11-12 17:28:12 +040019540 if(not $Descriptor{1}{"Headers"})
19541 {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040019542 if($CheckHeadersOnly_Opt) {
19543 exitStatus("Error", "can't find header files info in descriptor d1");
19544 }
19545 }
Andrey Ponomarenkobdc85a92012-11-12 17:28:12 +040019546 if(not $Descriptor{2}{"Headers"})
19547 {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040019548 if($CheckHeadersOnly_Opt) {
19549 exitStatus("Error", "can't find header files info in descriptor d2");
19550 }
19551 }
19552 if(not $Descriptor{1}{"Headers"}
Andrey Ponomarenkobdc85a92012-11-12 17:28:12 +040019553 or not $Descriptor{2}{"Headers"})
19554 {
19555 if(not $CheckObjectsOnly_Opt)
19556 {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040019557 printMsg("WARNING", "comparing $SLIB_TYPE libraries only");
19558 $CheckObjectsOnly = 1;
19559 }
19560 }
Andrey Ponomarenkobdc85a92012-11-12 17:28:12 +040019561 if(not $Descriptor{1}{"Libs"})
19562 {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040019563 if($CheckObjectsOnly_Opt) {
19564 exitStatus("Error", "can't find $SLIB_TYPE libraries info in descriptor d1");
19565 }
19566 }
Andrey Ponomarenkobdc85a92012-11-12 17:28:12 +040019567 if(not $Descriptor{2}{"Libs"})
19568 {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040019569 if($CheckObjectsOnly_Opt) {
19570 exitStatus("Error", "can't find $SLIB_TYPE libraries info in descriptor d2");
19571 }
19572 }
19573 if(not $Descriptor{1}{"Libs"}
19574 or not $Descriptor{2}{"Libs"})
19575 { # comparing standalone header files
19576 # comparing ABI dumps created with --headers-only
19577 if(not $CheckHeadersOnly_Opt)
19578 {
19579 printMsg("WARNING", "checking headers only");
19580 $CheckHeadersOnly = 1;
19581 }
19582 }
19583 if($UseDumps)
19584 { # --use-dumps
19585 # parallel processing
19586 my $pid = fork();
19587 if($pid)
19588 { # dump on two CPU cores
19589 my @PARAMS = ("-dump", $Descriptor{1}{"Path"}, "-l", $TargetLibraryName);
19590 if($RelativeDirectory{1}) {
19591 @PARAMS = (@PARAMS, "-relpath", $RelativeDirectory{1});
19592 }
19593 if($OutputLogPath{1}) {
19594 @PARAMS = (@PARAMS, "-log-path", $OutputLogPath{1});
19595 }
19596 if($CrossGcc) {
19597 @PARAMS = (@PARAMS, "-cross-gcc", $CrossGcc);
19598 }
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040019599 if($Quiet)
19600 {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040019601 @PARAMS = (@PARAMS, "-quiet");
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040019602 @PARAMS = (@PARAMS, "-logging-mode", "a");
19603 }
19604 elsif($LogMode and $LogMode ne "w")
19605 { # "w" is default
19606 @PARAMS = (@PARAMS, "-logging-mode", $LogMode);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040019607 }
19608 if($ExtendedCheck) {
19609 @PARAMS = (@PARAMS, "-extended");
19610 }
19611 if($UserLang) {
19612 @PARAMS = (@PARAMS, "-lang", $UserLang);
19613 }
19614 if($TargetVersion{1}) {
19615 @PARAMS = (@PARAMS, "-vnum", $TargetVersion{1});
19616 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +040019617 if($BinaryOnly) {
19618 @PARAMS = (@PARAMS, "-binary");
19619 }
19620 if($SourceOnly) {
19621 @PARAMS = (@PARAMS, "-source");
19622 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040019623 if($SortDump) {
19624 @PARAMS = (@PARAMS, "-sort");
19625 }
Andrey Ponomarenko01117f12012-06-26 12:23:02 +040019626 if($DumpFormat and $DumpFormat ne "perl") {
19627 @PARAMS = (@PARAMS, "-dump-format", $DumpFormat);
19628 }
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +040019629 if($CheckHeadersOnly) {
19630 @PARAMS = (@PARAMS, "-headers-only");
19631 }
19632 if($CheckObjectsOnly) {
19633 @PARAMS = (@PARAMS, "-objects-only");
19634 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +040019635 if($Debug)
19636 {
19637 @PARAMS = (@PARAMS, "-debug");
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040019638 printMsg("INFO", "running perl $0 @PARAMS");
Andrey Ponomarenko85043792012-05-14 16:48:07 +040019639 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040019640 system("perl", $0, @PARAMS);
19641 if($?) {
19642 exit(1);
19643 }
19644 }
19645 else
19646 { # child
19647 my @PARAMS = ("-dump", $Descriptor{2}{"Path"}, "-l", $TargetLibraryName);
19648 if($RelativeDirectory{2}) {
19649 @PARAMS = (@PARAMS, "-relpath", $RelativeDirectory{2});
19650 }
19651 if($OutputLogPath{2}) {
19652 @PARAMS = (@PARAMS, "-log-path", $OutputLogPath{2});
19653 }
19654 if($CrossGcc) {
19655 @PARAMS = (@PARAMS, "-cross-gcc", $CrossGcc);
19656 }
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040019657 if($Quiet)
19658 {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040019659 @PARAMS = (@PARAMS, "-quiet");
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040019660 @PARAMS = (@PARAMS, "-logging-mode", "a");
19661 }
19662 elsif($LogMode and $LogMode ne "w")
19663 { # "w" is default
19664 @PARAMS = (@PARAMS, "-logging-mode", $LogMode);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040019665 }
19666 if($ExtendedCheck) {
19667 @PARAMS = (@PARAMS, "-extended");
19668 }
19669 if($UserLang) {
19670 @PARAMS = (@PARAMS, "-lang", $UserLang);
19671 }
19672 if($TargetVersion{2}) {
19673 @PARAMS = (@PARAMS, "-vnum", $TargetVersion{2});
19674 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +040019675 if($BinaryOnly) {
19676 @PARAMS = (@PARAMS, "-binary");
19677 }
19678 if($SourceOnly) {
19679 @PARAMS = (@PARAMS, "-source");
19680 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040019681 if($SortDump) {
19682 @PARAMS = (@PARAMS, "-sort");
19683 }
Andrey Ponomarenko01117f12012-06-26 12:23:02 +040019684 if($DumpFormat and $DumpFormat ne "perl") {
19685 @PARAMS = (@PARAMS, "-dump-format", $DumpFormat);
19686 }
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +040019687 if($CheckHeadersOnly) {
19688 @PARAMS = (@PARAMS, "-headers-only");
19689 }
19690 if($CheckObjectsOnly) {
19691 @PARAMS = (@PARAMS, "-objects-only");
19692 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +040019693 if($Debug)
19694 {
19695 @PARAMS = (@PARAMS, "-debug");
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040019696 printMsg("INFO", "running perl $0 @PARAMS");
Andrey Ponomarenko85043792012-05-14 16:48:07 +040019697 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040019698 system("perl", $0, @PARAMS);
19699 if($?) {
19700 exit(1);
19701 }
19702 else {
19703 exit(0);
19704 }
19705 }
19706 waitpid($pid, 0);
19707 my @CMP_PARAMS = ("-l", $TargetLibraryName);
19708 @CMP_PARAMS = (@CMP_PARAMS, "-d1", "abi_dumps/$TargetLibraryName/".$TargetLibraryName."_".$Descriptor{1}{"Version"}.".abi.$AR_EXT");
19709 @CMP_PARAMS = (@CMP_PARAMS, "-d2", "abi_dumps/$TargetLibraryName/".$TargetLibraryName."_".$Descriptor{2}{"Version"}.".abi.$AR_EXT");
19710 if($TargetLibraryFName ne $TargetLibraryName) {
19711 @CMP_PARAMS = (@CMP_PARAMS, "-l-full", $TargetLibraryFName);
19712 }
19713 if($ShowRetVal) {
19714 @CMP_PARAMS = (@CMP_PARAMS, "-show-retval");
19715 }
19716 if($CrossGcc) {
19717 @CMP_PARAMS = (@CMP_PARAMS, "-cross-gcc", $CrossGcc);
19718 }
Andrey Ponomarenko35c44fd2012-06-18 17:50:25 +040019719 @CMP_PARAMS = (@CMP_PARAMS, "-logging-mode", "a");
19720 if($Quiet) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040019721 @CMP_PARAMS = (@CMP_PARAMS, "-quiet");
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040019722 }
19723 if($ReportFormat and $ReportFormat ne "html")
19724 { # HTML is default format
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040019725 @CMP_PARAMS = (@CMP_PARAMS, "-report-format", $ReportFormat);
19726 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040019727 if($OutputReportPath) {
19728 @CMP_PARAMS = (@CMP_PARAMS, "-report-path", $OutputReportPath);
19729 }
19730 if($BinaryReportPath) {
19731 @CMP_PARAMS = (@CMP_PARAMS, "-bin-report-path", $BinaryReportPath);
19732 }
19733 if($SourceReportPath) {
19734 @CMP_PARAMS = (@CMP_PARAMS, "-src-report-path", $SourceReportPath);
19735 }
19736 if($LoggingPath) {
19737 @CMP_PARAMS = (@CMP_PARAMS, "-log-path", $LoggingPath);
19738 }
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +040019739 if($CheckHeadersOnly) {
19740 @CMP_PARAMS = (@CMP_PARAMS, "-headers-only");
19741 }
19742 if($CheckObjectsOnly) {
19743 @CMP_PARAMS = (@CMP_PARAMS, "-objects-only");
19744 }
19745 if($BinaryOnly) {
19746 @CMP_PARAMS = (@CMP_PARAMS, "-binary");
19747 }
19748 if($SourceOnly) {
19749 @CMP_PARAMS = (@CMP_PARAMS, "-source");
19750 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +040019751 if($Browse) {
19752 @CMP_PARAMS = (@CMP_PARAMS, "-browse", $Browse);
19753 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040019754 if($OpenReport) {
19755 @CMP_PARAMS = (@CMP_PARAMS, "-open");
19756 }
19757 if($Debug)
19758 {
19759 @CMP_PARAMS = (@CMP_PARAMS, "-debug");
19760 printMsg("INFO", "running perl $0 @CMP_PARAMS");
Andrey Ponomarenko85043792012-05-14 16:48:07 +040019761 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040019762 system("perl", $0, @CMP_PARAMS);
19763 exit($?>>8);
19764 }
19765 if(not $Descriptor{1}{"Dump"}
19766 or not $Descriptor{2}{"Dump"})
19767 { # need GCC toolchain to analyze
19768 # header files and libraries
19769 detect_default_paths("inc|lib|gcc");
19770 }
19771 if(not $Descriptor{1}{"Dump"})
19772 {
19773 if(not $CheckHeadersOnly) {
19774 readLibs(1);
19775 }
19776 if($CheckHeadersOnly) {
19777 setLanguage(1, "C++");
19778 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +040019779 if(not $CheckObjectsOnly) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040019780 searchForHeaders(1);
19781 }
19782 $WORD_SIZE{1} = detectWordSize();
19783 }
19784 if(not $Descriptor{2}{"Dump"})
19785 {
19786 if(not $CheckHeadersOnly) {
19787 readLibs(2);
19788 }
19789 if($CheckHeadersOnly) {
19790 setLanguage(2, "C++");
19791 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +040019792 if(not $CheckObjectsOnly) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040019793 searchForHeaders(2);
19794 }
19795 $WORD_SIZE{2} = detectWordSize();
19796 }
19797 if($WORD_SIZE{1} ne $WORD_SIZE{2})
19798 { # support for old ABI dumps
19799 # try to synch different WORD sizes
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040019800 if(not checkDump(1, "2.1"))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040019801 {
19802 $WORD_SIZE{1} = $WORD_SIZE{2};
19803 printMsg("WARNING", "set WORD size to ".$WORD_SIZE{2}." bytes");
19804 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040019805 elsif(not checkDump(2, "2.1"))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040019806 {
19807 $WORD_SIZE{2} = $WORD_SIZE{1};
19808 printMsg("WARNING", "set WORD size to ".$WORD_SIZE{1}." bytes");
19809 }
19810 }
19811 elsif(not $WORD_SIZE{1}
19812 and not $WORD_SIZE{2})
19813 { # support for old ABI dumps
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040019814 $WORD_SIZE{1} = "4";
19815 $WORD_SIZE{2} = "4";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040019816 }
19817 if($Descriptor{1}{"Dump"})
19818 { # support for old ABI dumps
19819 prepareTypes(1);
19820 }
19821 if($Descriptor{2}{"Dump"})
19822 { # support for old ABI dumps
19823 prepareTypes(2);
19824 }
19825 if($AppPath and not keys(%{$Symbol_Library{1}})) {
19826 printMsg("WARNING", "the application ".get_filename($AppPath)." has no symbols imported from the $SLIB_TYPE libraries");
19827 }
19828 # started to process input data
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040019829 if(not $CheckObjectsOnly)
19830 {
19831 if($Descriptor{1}{"Headers"}
19832 and not $Descriptor{1}{"Dump"}) {
19833 readHeaders(1);
19834 }
19835 if($Descriptor{2}{"Headers"}
19836 and not $Descriptor{2}{"Dump"}) {
19837 readHeaders(2);
19838 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040019839 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +040019840
19841 # clean memory
19842 %SystemHeaders = ();
19843 %mangled_name_gcc = ();
19844
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040019845 prepareSymbols(1);
19846 prepareSymbols(2);
Andrey Ponomarenko16934472012-03-29 15:37:04 +040019847
Andrey Ponomarenko85043792012-05-14 16:48:07 +040019848 # clean memory
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040019849 %SymbolInfo = ();
Andrey Ponomarenko16934472012-03-29 15:37:04 +040019850
19851 # Virtual Tables
19852 registerVTable(1);
19853 registerVTable(2);
19854
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040019855 if(not checkDump(1, "1.22")
19856 and checkDump(2, "1.22"))
Andrey Ponomarenko16934472012-03-29 15:37:04 +040019857 { # support for old ABI dumps
19858 foreach my $ClassName (keys(%{$VirtualTable{2}}))
19859 {
19860 if($ClassName=~/</)
19861 { # templates
19862 if(not defined $VirtualTable{1}{$ClassName})
19863 { # synchronize
19864 delete($VirtualTable{2}{$ClassName});
19865 }
19866 }
19867 }
19868 }
19869
19870 registerOverriding(1);
19871 registerOverriding(2);
19872
19873 setVirtFuncPositions(1);
19874 setVirtFuncPositions(2);
19875
19876 # Other
19877 addParamNames(1);
19878 addParamNames(2);
19879
19880 detectChangedTypedefs();
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040019881}
19882
19883sub compareAPIs($)
19884{
19885 my $Level = $_[0];
19886 readRules($Level);
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +040019887 loadModule("CallConv");
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040019888 if($Level eq "Binary") {
19889 printMsg("INFO", "comparing ABIs ...");
19890 }
19891 else {
19892 printMsg("INFO", "comparing APIs ...");
19893 }
19894 if($CheckHeadersOnly
19895 or $Level eq "Source")
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040019896 { # added/removed in headers
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040019897 detectAdded_H($Level);
19898 detectRemoved_H($Level);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040019899 }
19900 else
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040019901 { # added/removed in libs
19902 detectAdded($Level);
19903 detectRemoved($Level);
19904 }
19905 if(not $CheckObjectsOnly)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040019906 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040019907 mergeSignatures($Level);
19908 if(keys(%{$CheckedSymbols{$Level}})) {
19909 mergeConstants($Level);
19910 }
19911 }
19912 if($CheckHeadersOnly
19913 or $Level eq "Source")
19914 { # added/removed in headers
19915 mergeHeaders($Level);
19916 }
19917 else
19918 { # added/removed in libs
19919 mergeLibs($Level);
19920 if($CheckImpl
19921 and $Level eq "Binary") {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040019922 mergeImpl();
19923 }
19924 }
19925}
19926
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040019927sub getSysOpts()
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040019928{
19929 my %Opts = (
19930 "OStarget"=>$OStarget,
19931 "Debug"=>$Debug,
19932 "Quiet"=>$Quiet,
19933 "LogMode"=>$LogMode,
19934 "CheckHeadersOnly"=>$CheckHeadersOnly,
19935
19936 "SystemRoot"=>$SystemRoot,
19937 "MODULES_DIR"=>$MODULES_DIR,
19938 "GCC_PATH"=>$GCC_PATH,
19939 "TargetSysInfo"=>$TargetSysInfo,
19940 "CrossPrefix"=>$CrossPrefix,
19941 "TargetLibraryName"=>$TargetLibraryName,
19942 "CrossGcc"=>$CrossGcc,
19943 "UseStaticLibs"=>$UseStaticLibs,
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040019944 "NoStdInc"=>$NoStdInc,
19945
19946 "BinaryOnly" => $BinaryOnly,
19947 "SourceOnly" => $SourceOnly
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040019948 );
19949 return \%Opts;
19950}
19951
19952sub get_CoreError($)
19953{
19954 my %CODE_ERROR = reverse(%ERROR_CODE);
19955 return $CODE_ERROR{$_[0]};
19956}
19957
19958sub scenario()
19959{
19960 if($StdOut)
19961 { # enable quiet mode
19962 $Quiet = 1;
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040019963 $JoinReport = 1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040019964 }
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040019965 if(not $LogMode)
19966 { # default
19967 $LogMode = "w";
19968 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040019969 if($UserLang)
19970 { # --lang=C++
19971 $UserLang = uc($UserLang);
19972 $COMMON_LANGUAGE{1}=$UserLang;
19973 $COMMON_LANGUAGE{2}=$UserLang;
19974 }
19975 if($LoggingPath)
19976 {
19977 $OutputLogPath{1} = $LoggingPath;
19978 $OutputLogPath{2} = $LoggingPath;
19979 if($Quiet) {
19980 $COMMON_LOG_PATH = $LoggingPath;
19981 }
19982 }
Andrey Ponomarenko5c09ef32012-06-14 18:17:33 +040019983 if($OutputDumpPath)
19984 { # validate
19985 if($OutputDumpPath!~/\.abi(\.\Q$AR_EXT\E|)\Z/) {
19986 exitStatus("Error", "the dump path should be a path to *.abi.$AR_EXT or *.abi file");
19987 }
19988 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040019989 if($BinaryOnly and $SourceOnly)
19990 { # both --binary and --source
19991 # is the default mode
19992 $DoubleReport = 1;
19993 $JoinReport = 0;
19994 $BinaryOnly = 0;
19995 $SourceOnly = 0;
19996 if($OutputReportPath)
19997 { # --report-path
19998 $DoubleReport = 0;
19999 $JoinReport = 1;
20000 }
20001 }
20002 elsif($BinaryOnly or $SourceOnly)
20003 { # --binary or --source
20004 $DoubleReport = 0;
20005 $JoinReport = 0;
20006 }
20007 if($UseXML)
20008 { # --xml option
20009 $ReportFormat = "xml";
Andrey Ponomarenko5c09ef32012-06-14 18:17:33 +040020010 $DumpFormat = "xml";
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040020011 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040020012 if($ReportFormat)
20013 { # validate
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040020014 $ReportFormat = lc($ReportFormat);
20015 if($ReportFormat!~/\A(xml|html|htm)\Z/) {
Andrey Ponomarenko5c09ef32012-06-14 18:17:33 +040020016 exitStatus("Error", "unknown report format \'$ReportFormat\'");
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040020017 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040020018 if($ReportFormat eq "htm")
20019 { # HTM == HTML
20020 $ReportFormat = "html";
20021 }
20022 elsif($ReportFormat eq "xml")
20023 { # --report-format=XML equal to --xml
20024 $UseXML = 1;
20025 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040020026 }
20027 else
20028 { # default: HTML
20029 $ReportFormat = "html";
20030 }
Andrey Ponomarenko5c09ef32012-06-14 18:17:33 +040020031 if($DumpFormat)
20032 { # validate
20033 $DumpFormat = lc($DumpFormat);
20034 if($DumpFormat!~/\A(xml|perl)\Z/) {
20035 exitStatus("Error", "unknown ABI dump format \'$DumpFormat\'");
20036 }
20037 if($DumpFormat eq "xml")
20038 { # --dump-format=XML equal to --xml
20039 $UseXML = 1;
20040 }
20041 }
20042 else
Andrey Ponomarenko01117f12012-06-26 12:23:02 +040020043 { # default: Perl Data::Dumper
Andrey Ponomarenko5c09ef32012-06-14 18:17:33 +040020044 $DumpFormat = "perl";
20045 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040020046 if($Quiet and $LogMode!~/a|n/)
20047 { # --quiet log
20048 if(-f $COMMON_LOG_PATH) {
20049 unlink($COMMON_LOG_PATH);
20050 }
20051 }
20052 if($TestTool and $UseDumps)
20053 { # --test && --use-dumps == --test-dump
20054 $TestDump = 1;
20055 }
20056 if($Help) {
20057 HELP_MESSAGE();
20058 exit(0);
20059 }
20060 if($InfoMsg) {
20061 INFO_MESSAGE();
20062 exit(0);
20063 }
20064 if($ShowVersion) {
20065 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.");
20066 exit(0);
20067 }
20068 if($DumpVersion) {
20069 printMsg("INFO", $TOOL_VERSION);
20070 exit(0);
20071 }
20072 if($ExtendedCheck) {
20073 $CheckHeadersOnly = 1;
20074 }
20075 if($SystemRoot_Opt)
20076 { # user defined root
20077 if(not -e $SystemRoot_Opt) {
20078 exitStatus("Access_Error", "can't access \'$SystemRoot\'");
20079 }
20080 $SystemRoot = $SystemRoot_Opt;
20081 $SystemRoot=~s/[\/]+\Z//g;
20082 if($SystemRoot) {
20083 $SystemRoot = get_abs_path($SystemRoot);
20084 }
20085 }
20086 $Data::Dumper::Sortkeys = 1;
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +040020087
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040020088 if($SortDump)
20089 {
20090 $Data::Dumper::Useperl = 1;
20091 $Data::Dumper::Sortkeys = \&dump_sorting;
20092 }
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +040020093
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040020094 if($TargetLibsPath)
20095 {
20096 if(not -f $TargetLibsPath) {
20097 exitStatus("Access_Error", "can't access file \'$TargetLibsPath\'");
20098 }
20099 foreach my $Lib (split(/\s*\n\s*/, readFile($TargetLibsPath))) {
20100 $TargetLibs{$Lib} = 1;
20101 }
20102 }
20103 if($TargetHeadersPath)
20104 { # --headers-list
20105 if(not -f $TargetHeadersPath) {
20106 exitStatus("Access_Error", "can't access file \'$TargetHeadersPath\'");
20107 }
20108 foreach my $Header (split(/\s*\n\s*/, readFile($TargetHeadersPath)))
20109 {
20110 $TargetHeaders{1}{$Header} = 1;
20111 $TargetHeaders{2}{$Header} = 1;
20112 }
20113 }
20114 if($TargetHeader)
20115 { # --header
20116 $TargetHeaders{1}{$TargetHeader} = 1;
20117 $TargetHeaders{2}{$TargetHeader} = 1;
20118 }
20119 if($TestTool
20120 or $TestDump)
20121 { # --test, --test-dump
20122 detect_default_paths("bin|gcc"); # to compile libs
20123 loadModule("RegTests");
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +040020124 testTool($TestDump, $Debug, $Quiet, $ExtendedCheck, $LogMode, $ReportFormat, $DumpFormat,
20125 $LIB_EXT, $GCC_PATH, $Browse, $OpenReport, $SortDump, $CheckHeadersOnly, $CheckObjectsOnly);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040020126 exit(0);
20127 }
20128 if($DumpSystem)
20129 { # --dump-system
20130 loadModule("SysCheck");
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040020131 if($DumpSystem=~/\.(xml|desc)\Z/)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040020132 { # system XML descriptor
20133 if(not -f $DumpSystem) {
20134 exitStatus("Access_Error", "can't access file \'$DumpSystem\'");
20135 }
20136 my $Ret = readSystemDescriptor(readFile($DumpSystem));
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040020137 foreach (@{$Ret->{"Tools"}})
20138 {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040020139 $SystemPaths{"bin"}{$_} = 1;
20140 $TargetTools{$_}=1;
20141 }
20142 if($Ret->{"CrossPrefix"}) {
20143 $CrossPrefix = $Ret->{"CrossPrefix"};
20144 }
20145 }
20146 elsif($SystemRoot_Opt)
20147 { # -sysroot "/" option
20148 # default target: /usr/lib, /usr/include
20149 # search libs: /usr/lib and /lib
20150 if(not -e $SystemRoot."/usr/lib") {
20151 exitStatus("Access_Error", "can't access '".$SystemRoot."/usr/lib'");
20152 }
20153 if(not -e $SystemRoot."/lib") {
20154 exitStatus("Access_Error", "can't access '".$SystemRoot."/lib'");
20155 }
20156 if(not -e $SystemRoot."/usr/include") {
20157 exitStatus("Access_Error", "can't access '".$SystemRoot."/usr/include'");
20158 }
20159 readSystemDescriptor("
20160 <name>
20161 $DumpSystem
20162 </name>
20163 <headers>
20164 $SystemRoot/usr/include
20165 </headers>
20166 <libs>
20167 $SystemRoot/usr/lib
20168 </libs>
20169 <search_libs>
20170 $SystemRoot/lib
20171 </search_libs>");
20172 }
20173 else {
20174 exitStatus("Error", "-sysroot <dirpath> option should be specified, usually it's \"/\"");
20175 }
20176 detect_default_paths("bin|gcc"); # to check symbols
20177 if($OStarget eq "windows")
20178 { # to run dumpbin.exe
20179 # and undname.exe
20180 check_win32_env();
20181 }
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040020182 dumpSystem(getSysOpts());
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040020183 exit(0);
20184 }
20185 if($CmpSystems)
20186 { # --cmp-systems
20187 detect_default_paths("bin"); # to extract dumps
20188 loadModule("SysCheck");
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040020189 cmpSystems($Descriptor{1}{"Path"}, $Descriptor{2}{"Path"}, getSysOpts());
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040020190 exit(0);
20191 }
20192 if($GenerateTemplate) {
20193 generateTemplate();
20194 exit(0);
20195 }
20196 if(not $TargetLibraryName) {
20197 exitStatus("Error", "library name is not selected (option -l <name>)");
20198 }
20199 else
20200 { # validate library name
20201 if($TargetLibraryName=~/[\*\/\\]/) {
20202 exitStatus("Error", "\"\\\", \"\/\" and \"*\" symbols are not allowed in the library name");
20203 }
20204 }
20205 if(not $TargetLibraryFName) {
20206 $TargetLibraryFName = $TargetLibraryName;
20207 }
20208 if($CheckHeadersOnly_Opt and $CheckObjectsOnly_Opt) {
20209 exitStatus("Error", "you can't specify both -headers-only and -objects-only options at the same time");
20210 }
20211 if($SymbolsListPath)
20212 {
20213 if(not -f $SymbolsListPath) {
20214 exitStatus("Access_Error", "can't access file \'$SymbolsListPath\'");
20215 }
20216 foreach my $Interface (split(/\s*\n\s*/, readFile($SymbolsListPath))) {
20217 $SymbolsList{$Interface} = 1;
20218 }
20219 }
20220 if($SkipHeadersPath)
20221 {
20222 if(not -f $SkipHeadersPath) {
20223 exitStatus("Access_Error", "can't access file \'$SkipHeadersPath\'");
20224 }
20225 foreach my $Path (split(/\s*\n\s*/, readFile($SkipHeadersPath)))
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040020226 { # register for both versions
20227 $SkipHeadersList{1}{$Path} = 1;
20228 $SkipHeadersList{2}{$Path} = 1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040020229 my ($CPath, $Type) = classifyPath($Path);
20230 $SkipHeaders{1}{$Type}{$CPath} = 1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040020231 $SkipHeaders{2}{$Type}{$CPath} = 1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040020232 }
20233 }
20234 if($ParamNamesPath)
20235 {
20236 if(not -f $ParamNamesPath) {
20237 exitStatus("Access_Error", "can't access file \'$ParamNamesPath\'");
20238 }
20239 foreach my $Line (split(/\n/, readFile($ParamNamesPath)))
20240 {
20241 if($Line=~s/\A(\w+)\;//)
20242 {
20243 my $Interface = $1;
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040020244 if($Line=~/;(\d+);/)
20245 {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040020246 while($Line=~s/(\d+);(\w+)//) {
20247 $AddIntParams{$Interface}{$1}=$2;
20248 }
20249 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040020250 else
20251 {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040020252 my $Num = 0;
20253 foreach my $Name (split(/;/, $Line)) {
20254 $AddIntParams{$Interface}{$Num++}=$Name;
20255 }
20256 }
20257 }
20258 }
20259 }
20260 if($AppPath)
20261 {
20262 if(not -f $AppPath) {
20263 exitStatus("Access_Error", "can't access file \'$AppPath\'");
20264 }
Andrey Ponomarenko16934472012-03-29 15:37:04 +040020265 foreach my $Interface (readSymbols_App($AppPath)) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040020266 $SymbolsList_App{$Interface} = 1;
20267 }
20268 }
20269 if($DumpAPI)
20270 { # --dump-abi
20271 # make an API dump
20272 create_ABI_Dump();
20273 exit($COMPILE_ERRORS);
20274 }
20275 # default: compare APIs
20276 # -d1 <path>
20277 # -d2 <path>
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040020278 compareInit();
20279 if($JoinReport or $DoubleReport)
20280 {
20281 compareAPIs("Binary");
20282 compareAPIs("Source");
20283 }
20284 elsif($BinaryOnly) {
20285 compareAPIs("Binary");
20286 }
20287 elsif($SourceOnly) {
20288 compareAPIs("Source");
20289 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040020290 exitReport();
20291}
20292
20293scenario();