blob: 921888d0a89e78e248864b2074f0b0697feb8806 [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;
1337
1338# Types
1339my %TypeInfo;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04001340my %TemplateInstance;
Andrey Ponomarenko85043792012-05-14 16:48:07 +04001341my %TemplateDecl;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04001342my %SkipTypes = (
1343 "1"=>{},
1344 "2"=>{} );
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04001345my %CheckedTypes;
1346my %TName_Tid;
1347my %EnumMembName_Id;
1348my %NestedNameSpaces = (
1349 "1"=>{},
1350 "2"=>{} );
1351my %UsedType;
1352my %VirtualTable;
Andrey Ponomarenko16934472012-03-29 15:37:04 +04001353my %VirtualTable_Model;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04001354my %ClassVTable;
1355my %ClassVTable_Content;
1356my %VTableClass;
1357my %AllocableClass;
1358my %ClassMethods;
Andrey Ponomarenko16934472012-03-29 15:37:04 +04001359my %ClassNames;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04001360my %Class_SubClasses;
1361my %OverriddenMethods;
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04001362my $MAX_ID = 0;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04001363
1364# Typedefs
1365my %Typedef_BaseName;
1366my %Typedef_Tr;
1367my %Typedef_Eq;
1368my %StdCxxTypedef;
1369my %MissedTypedef;
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04001370my %MissedBase;
1371my %MissedBase_R;
Andrey Ponomarenko9927e332012-10-19 10:50:48 +04001372my %TypeTypedef;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04001373
1374# Symbols
1375my %SymbolInfo;
1376my %tr_name;
1377my %mangled_name_gcc;
1378my %mangled_name;
1379my %SkipSymbols = (
1380 "1"=>{},
1381 "2"=>{} );
1382my %SkipNameSpaces = (
1383 "1"=>{},
1384 "2"=>{} );
Andrey Ponomarenkoa01311b2012-06-08 17:20:02 +04001385my %AddNameSpaces = (
1386 "1"=>{},
1387 "2"=>{} );
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04001388my %SymbolsList;
1389my %SymbolsList_App;
1390my %CheckedSymbols;
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04001391my %Symbol_Library = (
1392 "1"=>{},
1393 "2"=>{} );
1394my %Library_Symbol = (
1395 "1"=>{},
1396 "2"=>{} );
1397my %DepSymbol_Library = (
1398 "1"=>{},
1399 "2"=>{} );
1400my %DepLibrary_Symbol = (
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04001401 "1"=>{},
1402 "2"=>{} );
1403my %MangledNames;
Andrey Ponomarenko9927e332012-10-19 10:50:48 +04001404my %Func_ShortName;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04001405my %AddIntParams;
1406my %Interface_Impl;
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04001407my %GlobalDataObject;
Andrey Ponomarenko07aea072012-11-12 16:15:07 +04001408my %WeakSymbols;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04001409
1410# Headers
1411my %Include_Preamble;
1412my %Registered_Headers;
1413my %HeaderName_Paths;
1414my %Header_Dependency;
1415my %Include_Neighbors;
1416my %Include_Paths;
1417my %INC_PATH_AUTODETECT = (
1418 "1"=>1,
1419 "2"=>1 );
1420my %Add_Include_Paths;
1421my %Skip_Include_Paths;
1422my %RegisteredDirs;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04001423my %Header_ErrorRedirect;
1424my %Header_Includes;
1425my %Header_ShouldNotBeUsed;
1426my %RecursiveIncludes;
1427my %Header_Include_Prefix;
1428my %SkipHeaders;
1429my %SkipHeadersList=(
1430 "1"=>{},
1431 "2"=>{} );
1432my %SkipLibs;
1433my %Include_Order;
1434my %TUnit_NameSpaces;
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +04001435my %TUnit_Classes;
Andrey Ponomarenko9927e332012-10-19 10:50:48 +04001436my %TUnit_Funcs;
1437my %TUnit_Vars;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04001438
Andrey Ponomarenko07aea072012-11-12 16:15:07 +04001439my %CppMode = (
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04001440 "1"=>0,
1441 "2"=>0 );
1442my %AutoPreambleMode = (
1443 "1"=>0,
1444 "2"=>0 );
1445my %MinGWMode = (
1446 "1"=>0,
1447 "2"=>0 );
Andrey Ponomarenko01117f12012-06-26 12:23:02 +04001448my %Cpp0xMode = (
1449 "1"=>0,
1450 "2"=>0 );
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04001451
1452# Shared Objects
Andrey Ponomarenko9927e332012-10-19 10:50:48 +04001453my %RegisteredObjects;
Andrey Ponomarenko07aea072012-11-12 16:15:07 +04001454my %RegisteredObjects_Short;
Andrey Ponomarenko9927e332012-10-19 10:50:48 +04001455my %RegisteredSONAMEs;
1456my %RegisteredObject_Dirs;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04001457
1458# System Objects
1459my %SystemObjects;
1460my %DefaultLibPaths;
Andrey Ponomarenko9927e332012-10-19 10:50:48 +04001461my %DyLib_DefaultPath;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04001462
1463# System Headers
1464my %SystemHeaders;
1465my %DefaultCppPaths;
1466my %DefaultGccPaths;
1467my %DefaultIncPaths;
1468my %DefaultCppHeader;
1469my %DefaultGccHeader;
1470my %UserIncPath;
1471
1472# Merging
1473my %CompleteSignature;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04001474my $Version;
1475my %AddedInt;
1476my %RemovedInt;
1477my %AddedInt_Virt;
1478my %RemovedInt_Virt;
1479my %VirtualReplacement;
1480my %ChangedTypedef;
1481my %CompatRules;
1482my %IncompleteRules;
1483my %UnknownRules;
Andrey Ponomarenko16934472012-03-29 15:37:04 +04001484my %VTableChanged_M;
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04001485my %ExtendedSymbols;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04001486my %ReturnedClass;
1487my %ParamClass;
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04001488my %SourceAlternative;
1489my %SourceAlternative_B;
1490my %SourceReplacement;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04001491
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +04001492# Calling Conventions
1493my %UseConv_Real = (
1494 "1"=>0,
1495 "2"=>0 );
1496
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04001497# OS Compliance
1498my %TargetLibs;
1499my %TargetHeaders;
1500
1501# OS Specifics
1502my $OStarget = $OSgroup;
1503my %TargetTools;
1504
1505# Compliance Report
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04001506my %Type_MaxSeverity;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04001507
1508# Recursion locks
1509my @RecurLib;
1510my @RecurSymlink;
1511my @RecurTypes;
1512my @RecurInclude;
1513my @RecurConstant;
1514
1515# System
1516my %SystemPaths;
1517my %DefaultBinPaths;
1518my $GCC_PATH;
1519
1520# Symbols versioning
1521my %SymVer = (
1522 "1"=>{},
1523 "2"=>{} );
1524
1525# Problem descriptions
1526my %CompatProblems;
1527my %ProblemsWithConstants;
1528my %ImplProblems;
1529my %TotalAffected;
1530
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04001531# Reports
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04001532my $ContentID = 1;
1533my $ContentSpanStart = "<span class=\"section\" onclick=\"javascript:showContent(this, 'CONTENT_ID')\">\n";
1534my $ContentSpanStart_Affected = "<span class=\"section_affected\" onclick=\"javascript:showContent(this, 'CONTENT_ID')\">\n";
1535my $ContentSpanStart_Info = "<span class=\"section_info\" onclick=\"javascript:showContent(this, 'CONTENT_ID')\">\n";
1536my $ContentSpanEnd = "</span>\n";
1537my $ContentDivStart = "<div id=\"CONTENT_ID\" style=\"display:none;\">\n";
1538my $ContentDivEnd = "</div>\n";
1539my $Content_Counter = 0;
1540
Andrey Ponomarenko5c09ef32012-06-14 18:17:33 +04001541# XML Dump
1542my $TAG_ID = 0;
1543my $INDENT = " ";
1544
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04001545# Modes
1546my $JoinReport = 1;
1547my $DoubleReport = 0;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04001548
1549sub get_Modules()
1550{
1551 my $TOOL_DIR = get_dirname($0);
1552 if(not $TOOL_DIR)
1553 { # patch for MS Windows
1554 $TOOL_DIR = ".";
1555 }
1556 my @SEARCH_DIRS = (
1557 # tool's directory
1558 abs_path($TOOL_DIR),
1559 # relative path to modules
1560 abs_path($TOOL_DIR)."/../share/abi-compliance-checker",
1561 # system directory
1562 "ACC_MODULES_INSTALL_PATH"
1563 );
1564 foreach my $DIR (@SEARCH_DIRS)
1565 {
1566 if(not is_abs($DIR))
1567 { # relative path
1568 $DIR = abs_path($TOOL_DIR)."/".$DIR;
1569 }
1570 if(-d $DIR."/modules") {
1571 return $DIR."/modules";
1572 }
1573 }
1574 exitStatus("Module_Error", "can't find modules");
1575}
1576
Andrey Ponomarenko01117f12012-06-26 12:23:02 +04001577my %LoadedModules = ();
1578
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04001579sub loadModule($)
1580{
1581 my $Name = $_[0];
Andrey Ponomarenko01117f12012-06-26 12:23:02 +04001582 if(defined $LoadedModules{$Name}) {
1583 return;
1584 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04001585 my $Path = $MODULES_DIR."/Internals/$Name.pm";
1586 if(not -f $Path) {
1587 exitStatus("Module_Error", "can't access \'$Path\'");
1588 }
1589 require $Path;
Andrey Ponomarenko01117f12012-06-26 12:23:02 +04001590 $LoadedModules{$Name} = 1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04001591}
1592
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04001593sub showPos($)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04001594{
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04001595 my $Number = $_[0];
1596 if(not $Number) {
1597 $Number = 1;
1598 }
1599 else {
1600 $Number = int($Number)+1;
1601 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04001602 if($Number>3) {
1603 return $Number."th";
1604 }
1605 elsif($Number==1) {
1606 return "1st";
1607 }
1608 elsif($Number==2) {
1609 return "2nd";
1610 }
1611 elsif($Number==3) {
1612 return "3rd";
1613 }
1614 else {
1615 return $Number;
1616 }
1617}
1618
1619sub search_Tools($)
1620{
1621 my $Name = $_[0];
1622 return "" if(not $Name);
1623 if(my @Paths = keys(%TargetTools))
1624 {
1625 foreach my $Path (@Paths)
1626 {
1627 if(-f joinPath($Path, $Name)) {
1628 return joinPath($Path, $Name);
1629 }
1630 if($CrossPrefix)
1631 { # user-defined prefix (arm-none-symbianelf, ...)
1632 my $Candidate = joinPath($Path, $CrossPrefix."-".$Name);
1633 if(-f $Candidate) {
1634 return $Candidate;
1635 }
1636 }
1637 }
1638 }
1639 else {
1640 return "";
1641 }
1642}
1643
1644sub synch_Cmd($)
1645{
1646 my $Name = $_[0];
1647 if(not $GCC_PATH)
1648 { # GCC was not found yet
1649 return "";
1650 }
1651 my $Candidate = $GCC_PATH;
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04001652 if($Candidate=~s/\bgcc(|\.\w+)\Z/$Name$1/) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04001653 return $Candidate;
1654 }
1655 return "";
1656}
1657
1658sub get_CmdPath($)
1659{
1660 my $Name = $_[0];
1661 return "" if(not $Name);
1662 if(defined $Cache{"get_CmdPath"}{$Name}) {
1663 return $Cache{"get_CmdPath"}{$Name};
1664 }
1665 my %BinUtils = map {$_=>1} (
1666 "c++filt",
1667 "objdump",
1668 "readelf"
1669 );
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04001670 if($BinUtils{$Name} and $GCC_PATH)
1671 {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04001672 if(my $Dir = get_dirname($GCC_PATH)) {
1673 $TargetTools{$Dir}=1;
1674 }
1675 }
1676 my $Path = search_Tools($Name);
1677 if(not $Path and $OSgroup eq "windows") {
1678 $Path = search_Tools($Name.".exe");
1679 }
1680 if(not $Path and $BinUtils{$Name})
1681 {
1682 if($CrossPrefix)
1683 { # user-defined prefix
1684 $Path = search_Cmd($CrossPrefix."-".$Name);
1685 }
1686 }
1687 if(not $Path and $BinUtils{$Name})
1688 {
1689 if(my $Candidate = synch_Cmd($Name))
1690 { # synch with GCC
1691 if($Candidate=~/[\/\\]/)
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04001692 { # command path
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04001693 if(-f $Candidate) {
1694 $Path = $Candidate;
1695 }
1696 }
1697 elsif($Candidate = search_Cmd($Candidate))
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04001698 { # command name
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04001699 $Path = $Candidate;
1700 }
1701 }
1702 }
1703 if(not $Path) {
1704 $Path = search_Cmd($Name);
1705 }
1706 if(not $Path and $OSgroup eq "windows")
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04001707 { # search for *.exe file
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04001708 $Path=search_Cmd($Name.".exe");
1709 }
1710 if($Path=~/\s/) {
1711 $Path = "\"".$Path."\"";
1712 }
1713 return ($Cache{"get_CmdPath"}{$Name}=$Path);
1714}
1715
1716sub search_Cmd($)
1717{
1718 my $Name = $_[0];
1719 return "" if(not $Name);
1720 if(defined $Cache{"search_Cmd"}{$Name}) {
1721 return $Cache{"search_Cmd"}{$Name};
1722 }
1723 if(my $DefaultPath = get_CmdPath_Default($Name)) {
1724 return ($Cache{"search_Cmd"}{$Name} = $DefaultPath);
1725 }
1726 foreach my $Path (sort {length($a)<=>length($b)} keys(%{$SystemPaths{"bin"}}))
1727 {
1728 my $CmdPath = joinPath($Path,$Name);
1729 if(-f $CmdPath)
1730 {
1731 if($Name=~/gcc/) {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04001732 next if(not check_gcc($CmdPath, "3"));
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04001733 }
1734 return ($Cache{"search_Cmd"}{$Name} = $CmdPath);
1735 }
1736 }
1737 return ($Cache{"search_Cmd"}{$Name} = "");
1738}
1739
1740sub get_CmdPath_Default($)
1741{ # search in PATH
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04001742 return "" if(not $_[0]);
1743 if(defined $Cache{"get_CmdPath_Default"}{$_[0]}) {
1744 return $Cache{"get_CmdPath_Default"}{$_[0]};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04001745 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04001746 return ($Cache{"get_CmdPath_Default"}{$_[0]} = get_CmdPath_Default_I($_[0]));
1747}
1748
1749sub get_CmdPath_Default_I($)
1750{ # search in PATH
1751 my $Name = $_[0];
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04001752 if($Name=~/find/)
1753 { # special case: search for "find" utility
Andrey Ponomarenkoa01311b2012-06-08 17:20:02 +04001754 if(`find \"$TMP_DIR\" -maxdepth 0 2>\"$TMP_DIR/null\"`) {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04001755 return "find";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04001756 }
1757 }
1758 elsif($Name=~/gcc/) {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04001759 return check_gcc($Name, "3");
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04001760 }
1761 if(check_command($Name)) {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04001762 return $Name;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04001763 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04001764 if($OSgroup eq "windows")
1765 {
Andrey Ponomarenkoa01311b2012-06-08 17:20:02 +04001766 if(`$Name /? 2>\"$TMP_DIR/null\"`) {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04001767 return $Name;
1768 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04001769 }
1770 if($Name!~/which/)
1771 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04001772 if(my $WhichCmd = get_CmdPath("which"))
1773 {
Andrey Ponomarenkoa01311b2012-06-08 17:20:02 +04001774 if(`$WhichCmd $Name 2>\"$TMP_DIR/null\"`) {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04001775 return $Name;
1776 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04001777 }
1778 }
1779 foreach my $Path (sort {length($a)<=>length($b)} keys(%DefaultBinPaths))
1780 {
1781 if(-f $Path."/".$Name) {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04001782 return joinPath($Path,$Name);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04001783 }
1784 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04001785 return "";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04001786}
1787
1788sub clean_path($)
1789{
1790 my $Path = $_[0];
1791 $Path=~s/[\/\\]+\Z//g;
1792 return $Path;
1793}
1794
1795sub classifyPath($)
1796{
1797 my $Path = $_[0];
1798 if($Path=~/[\*\[]/)
1799 { # wildcard
1800 $Path=~s/\*/.*/g;
1801 $Path=~s/\\/\\\\/g;
1802 return ($Path, "Pattern");
1803 }
1804 elsif($Path=~/[\/\\]/)
1805 { # directory or relative path
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04001806 $Path=~s/[\/\\]+\Z//g;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04001807 return (path_format($Path, $OSgroup), "Path");
1808 }
1809 else {
1810 return ($Path, "Name");
1811 }
1812}
1813
1814sub readDescriptor($$)
1815{
1816 my ($LibVersion, $Content) = @_;
1817 return if(not $LibVersion);
1818 my $DName = $DumpAPI?"descriptor":"descriptor \"d$LibVersion\"";
1819 if(not $Content) {
1820 exitStatus("Error", "$DName is empty");
1821 }
1822 if($Content!~/\</) {
Andrey Ponomarenko5c09ef32012-06-14 18:17:33 +04001823 exitStatus("Error", "incorrect descriptor (see -d1 option)");
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04001824 }
1825 $Content=~s/\/\*(.|\n)+?\*\///g;
1826 $Content=~s/<\!--(.|\n)+?-->//g;
1827 $Descriptor{$LibVersion}{"Version"} = parseTag(\$Content, "version");
1828 if($TargetVersion{$LibVersion}) {
1829 $Descriptor{$LibVersion}{"Version"} = $TargetVersion{$LibVersion};
1830 }
1831 if(not $Descriptor{$LibVersion}{"Version"}) {
1832 exitStatus("Error", "version in the $DName is not specified (<version> section)");
1833 }
1834 if($Content=~/{RELPATH}/)
1835 {
1836 if(my $RelDir = $RelativeDirectory{$LibVersion}) {
1837 $Content =~ s/{RELPATH}/$RelDir/g;
1838 }
1839 else
1840 {
1841 my $NeedRelpath = $DumpAPI?"-relpath":"-relpath$LibVersion";
1842 exitStatus("Error", "you have not specified $NeedRelpath option, but the $DName contains {RELPATH} macro");
1843 }
1844 }
1845
1846 if(not $CheckObjectsOnly_Opt)
1847 {
1848 my $DHeaders = parseTag(\$Content, "headers");
1849 if(not $DHeaders) {
1850 exitStatus("Error", "header files in the $DName are not specified (<headers> section)");
1851 }
1852 elsif(lc($DHeaders) ne "none")
1853 { # append the descriptor headers list
1854 if($Descriptor{$LibVersion}{"Headers"})
1855 { # multiple descriptors
1856 $Descriptor{$LibVersion}{"Headers"} .= "\n".$DHeaders;
1857 }
1858 else {
1859 $Descriptor{$LibVersion}{"Headers"} = $DHeaders;
1860 }
1861 foreach my $Path (split(/\s*\n\s*/, $DHeaders))
1862 {
1863 if(not -e $Path) {
1864 exitStatus("Access_Error", "can't access \'$Path\'");
1865 }
1866 }
1867 }
1868 }
1869 if(not $CheckHeadersOnly_Opt)
1870 {
1871 my $DObjects = parseTag(\$Content, "libs");
1872 if(not $DObjects) {
1873 exitStatus("Error", "$SLIB_TYPE libraries in the $DName are not specified (<libs> section)");
1874 }
1875 elsif(lc($DObjects) ne "none")
1876 { # append the descriptor libraries list
1877 if($Descriptor{$LibVersion}{"Libs"})
1878 { # multiple descriptors
1879 $Descriptor{$LibVersion}{"Libs"} .= "\n".$DObjects;
1880 }
1881 else {
1882 $Descriptor{$LibVersion}{"Libs"} .= $DObjects;
1883 }
1884 foreach my $Path (split(/\s*\n\s*/, $DObjects))
1885 {
1886 if(not -e $Path) {
1887 exitStatus("Access_Error", "can't access \'$Path\'");
1888 }
1889 }
1890 }
1891 }
1892 foreach my $Path (split(/\s*\n\s*/, parseTag(\$Content, "search_headers")))
1893 {
1894 $Path = clean_path($Path);
1895 if(not -d $Path) {
1896 exitStatus("Access_Error", "can't access directory \'$Path\'");
1897 }
1898 $Path = path_format($Path, $OSgroup);
1899 $SystemPaths{"include"}{$Path}=1;
1900 }
1901 foreach my $Path (split(/\s*\n\s*/, parseTag(\$Content, "search_libs")))
1902 {
1903 $Path = clean_path($Path);
1904 if(not -d $Path) {
1905 exitStatus("Access_Error", "can't access directory \'$Path\'");
1906 }
1907 $Path = path_format($Path, $OSgroup);
1908 $SystemPaths{"lib"}{$Path}=1;
1909 }
1910 foreach my $Path (split(/\s*\n\s*/, parseTag(\$Content, "tools")))
1911 {
1912 $Path=clean_path($Path);
1913 if(not -d $Path) {
1914 exitStatus("Access_Error", "can't access directory \'$Path\'");
1915 }
1916 $Path = path_format($Path, $OSgroup);
1917 $SystemPaths{"bin"}{$Path}=1;
1918 $TargetTools{$Path}=1;
1919 }
1920 if(my $Prefix = parseTag(\$Content, "cross_prefix")) {
1921 $CrossPrefix = $Prefix;
1922 }
1923 foreach my $Path (split(/\s*\n\s*/, parseTag(\$Content, "include_paths")))
1924 {
1925 $Path=clean_path($Path);
1926 if(not -d $Path) {
1927 exitStatus("Access_Error", "can't access directory \'$Path\'");
1928 }
1929 $Path = path_format($Path, $OSgroup);
1930 $Descriptor{$LibVersion}{"IncludePaths"}{$Path} = 1;
1931 }
1932 foreach my $Path (split(/\s*\n\s*/, parseTag(\$Content, "add_include_paths")))
1933 {
1934 $Path=clean_path($Path);
1935 if(not -d $Path) {
1936 exitStatus("Access_Error", "can't access directory \'$Path\'");
1937 }
1938 $Path = path_format($Path, $OSgroup);
1939 $Descriptor{$LibVersion}{"AddIncludePaths"}{$Path} = 1;
1940 }
1941 foreach my $Path (split(/\s*\n\s*/, parseTag(\$Content, "skip_include_paths")))
1942 {
1943 # skip some auto-generated include paths
1944 $Skip_Include_Paths{$LibVersion}{path_format($Path)}=1;
1945 }
1946 foreach my $Path (split(/\s*\n\s*/, parseTag(\$Content, "skip_including")))
1947 {
1948 # skip direct including of some headers
1949 my ($CPath, $Type) = classifyPath($Path);
1950 $SkipHeaders{$LibVersion}{$Type}{$CPath} = 2;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04001951 }
1952 $Descriptor{$LibVersion}{"GccOptions"} = parseTag(\$Content, "gcc_options");
1953 foreach my $Option (split(/\s*\n\s*/, $Descriptor{$LibVersion}{"GccOptions"})) {
1954 $CompilerOptions{$LibVersion} .= " ".$Option;
1955 }
1956 $Descriptor{$LibVersion}{"SkipHeaders"} = parseTag(\$Content, "skip_headers");
1957 foreach my $Path (split(/\s*\n\s*/, $Descriptor{$LibVersion}{"SkipHeaders"}))
1958 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04001959 $SkipHeadersList{$LibVersion}{$Path} = 1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04001960 my ($CPath, $Type) = classifyPath($Path);
1961 $SkipHeaders{$LibVersion}{$Type}{$CPath} = 1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04001962 }
1963 $Descriptor{$LibVersion}{"SkipLibs"} = parseTag(\$Content, "skip_libs");
1964 foreach my $Path (split(/\s*\n\s*/, $Descriptor{$LibVersion}{"SkipLibs"}))
1965 {
1966 my ($CPath, $Type) = classifyPath($Path);
1967 $SkipLibs{$LibVersion}{$Type}{$CPath} = 1;
1968 }
1969 if(my $DDefines = parseTag(\$Content, "defines"))
1970 {
1971 if($Descriptor{$LibVersion}{"Defines"})
1972 { # multiple descriptors
1973 $Descriptor{$LibVersion}{"Defines"} .= "\n".$DDefines;
1974 }
1975 else {
1976 $Descriptor{$LibVersion}{"Defines"} = $DDefines;
1977 }
1978 }
1979 foreach my $Order (split(/\s*\n\s*/, parseTag(\$Content, "include_order")))
1980 {
1981 if($Order=~/\A(.+):(.+)\Z/) {
1982 $Include_Order{$LibVersion}{$1} = $2;
1983 }
1984 }
1985 foreach my $Type_Name (split(/\s*\n\s*/, parseTag(\$Content, "opaque_types")),
1986 split(/\s*\n\s*/, parseTag(\$Content, "skip_types")))
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04001987 { # opaque_types renamed to skip_types (1.23.4)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04001988 $SkipTypes{$LibVersion}{$Type_Name} = 1;
1989 }
1990 foreach my $Symbol (split(/\s*\n\s*/, parseTag(\$Content, "skip_interfaces")),
1991 split(/\s*\n\s*/, parseTag(\$Content, "skip_symbols")))
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04001992 { # skip_interfaces renamed to skip_symbols (1.22.1)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04001993 $SkipSymbols{$LibVersion}{$Symbol} = 1;
1994 }
1995 foreach my $NameSpace (split(/\s*\n\s*/, parseTag(\$Content, "skip_namespaces"))) {
1996 $SkipNameSpaces{$LibVersion}{$NameSpace} = 1;
1997 }
Andrey Ponomarenkoa01311b2012-06-08 17:20:02 +04001998 foreach my $NameSpace (split(/\s*\n\s*/, parseTag(\$Content, "add_namespaces"))) {
1999 $AddNameSpaces{$LibVersion}{$NameSpace} = 1;
2000 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002001 foreach my $Constant (split(/\s*\n\s*/, parseTag(\$Content, "skip_constants"))) {
2002 $SkipConstants{$LibVersion}{$Constant} = 1;
2003 }
2004 if(my $DIncPreamble = parseTag(\$Content, "include_preamble"))
2005 {
2006 if($Descriptor{$LibVersion}{"IncludePreamble"})
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04002007 { # multiple descriptors
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002008 $Descriptor{$LibVersion}{"IncludePreamble"} .= "\n".$DIncPreamble;
2009 }
2010 else {
2011 $Descriptor{$LibVersion}{"IncludePreamble"} = $DIncPreamble;
2012 }
2013 }
2014}
2015
Andrey Ponomarenko01117f12012-06-26 12:23:02 +04002016sub parseTag(@)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002017{
Andrey Ponomarenko01117f12012-06-26 12:23:02 +04002018 my $CodeRef = shift(@_);
2019 my $Tag = shift(@_);
2020 if(not $Tag or not $CodeRef) {
2021 return undef;
2022 }
2023 my $Sp = 0;
2024 if(@_) {
2025 $Sp = shift(@_);
2026 }
2027 my $Start = index(${$CodeRef}, "<$Tag>");
2028 if($Start!=-1)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002029 {
Andrey Ponomarenko01117f12012-06-26 12:23:02 +04002030 my $End = index(${$CodeRef}, "</$Tag>");
2031 if($End!=-1)
2032 {
2033 my $TS = length($Tag)+3;
2034 my $Content = substr(${$CodeRef}, $Start, $End-$Start+$TS, "");
2035 substr($Content, 0, $TS-1, ""); # cut start tag
2036 substr($Content, -$TS, $TS, ""); # cut end tag
2037 if(not $Sp)
2038 {
2039 $Content=~s/\A\s+//g;
2040 $Content=~s/\s+\Z//g;
2041 }
2042 if(substr($Content, 0, 1) ne "<") {
2043 $Content = xmlSpecChars_R($Content);
2044 }
2045 return $Content;
2046 }
2047 }
2048 return undef;
2049}
2050
2051sub parseTag_E($$$)
2052{
2053 my ($CodeRef, $Tag, $Info) = @_;
2054 if(not $Tag or not $CodeRef
2055 or not $Info) {
2056 return undef;
2057 }
2058 if(${$CodeRef}=~s/\<\Q$Tag\E(\s+([^<>]+)|)\>((.|\n)*?)\<\/\Q$Tag\E\>//)
2059 {
2060 my ($Ext, $Content) = ($2, $3);
2061 $Content=~s/\A\s+//g;
2062 $Content=~s/\s+\Z//g;
2063 if($Ext)
2064 {
2065 while($Ext=~s/(\w+)\=\"([^\"]*)\"//)
2066 {
2067 my ($K, $V) = ($1, $2);
2068 $Info->{$K} = xmlSpecChars_R($V);
2069 }
2070 }
2071 if(substr($Content, 0, 1) ne "<") {
2072 $Content = xmlSpecChars_R($Content);
2073 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002074 return $Content;
2075 }
Andrey Ponomarenko01117f12012-06-26 12:23:02 +04002076 return undef;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002077}
2078
Andrey Ponomarenko35c44fd2012-06-18 17:50:25 +04002079sub addTag(@)
Andrey Ponomarenko5c09ef32012-06-14 18:17:33 +04002080{
Andrey Ponomarenko35c44fd2012-06-18 17:50:25 +04002081 my $Tag = shift(@_);
2082 my $Val = shift(@_);
2083 my @Ext = @_;
2084 my $Content = openTag($Tag, @Ext);
2085 chomp($Content);
Andrey Ponomarenko5c09ef32012-06-14 18:17:33 +04002086 $Content .= xmlSpecChars($Val);
2087 $Content .= "</$Tag>\n";
Andrey Ponomarenko35c44fd2012-06-18 17:50:25 +04002088 $TAG_ID-=1;
Andrey Ponomarenko5c09ef32012-06-14 18:17:33 +04002089
2090 return $Content;
2091}
2092
Andrey Ponomarenko35c44fd2012-06-18 17:50:25 +04002093sub openTag(@)
Andrey Ponomarenko5c09ef32012-06-14 18:17:33 +04002094{
2095 my $Tag = shift(@_);
2096 my @Ext = @_;
2097 my $Content = "";
2098 foreach (1 .. $TAG_ID) {
2099 $Content .= $INDENT;
2100 }
2101 $TAG_ID+=1;
Andrey Ponomarenko35c44fd2012-06-18 17:50:25 +04002102 if(@Ext)
Andrey Ponomarenko5c09ef32012-06-14 18:17:33 +04002103 {
Andrey Ponomarenko35c44fd2012-06-18 17:50:25 +04002104 $Content .= "<".$Tag;
2105 my $P = 0;
2106 while($P<=$#Ext-1)
2107 {
2108 $Content .= " ".$Ext[$P];
2109 $Content .= "=\"".xmlSpecChars($Ext[$P+1])."\"";
2110 $P+=2;
2111 }
2112 $Content .= ">\n";
Andrey Ponomarenko5c09ef32012-06-14 18:17:33 +04002113 }
Andrey Ponomarenko35c44fd2012-06-18 17:50:25 +04002114 else {
2115 $Content .= "<".$Tag.">\n";
2116 }
Andrey Ponomarenko5c09ef32012-06-14 18:17:33 +04002117 return $Content;
2118}
2119
2120sub closeTag($)
2121{
2122 my $Tag = $_[0];
2123 my $Content = "";
2124 $TAG_ID-=1;
2125 foreach (1 .. $TAG_ID) {
2126 $Content .= $INDENT;
2127 }
2128 $Content .= "</".$Tag.">\n";
2129 return $Content;
2130}
2131
2132sub checkTags()
2133{
2134 if($TAG_ID!=0) {
2135 printMsg("WARNING", "the number of opened tags is not equal to number of closed tags");
2136 }
2137}
2138
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002139sub getInfo($)
2140{
Andrey Ponomarenko85043792012-05-14 16:48:07 +04002141 my $DumpPath = $_[0];
2142 return if(not $DumpPath or not -f $DumpPath);
2143
2144 readTUDump($DumpPath);
2145
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002146 # processing info
2147 setTemplateParams_All();
2148 getTypeInfo_All();
2149 simplifyNames();
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002150 getVarInfo_All();
Andrey Ponomarenko01117f12012-06-26 12:23:02 +04002151 getSymbolInfo_All();
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002152
Andrey Ponomarenko85043792012-05-14 16:48:07 +04002153 # clean memory
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002154 %LibInfo = ();
2155 %TemplateInstance = ();
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002156 %MangledNames = ();
Andrey Ponomarenko85043792012-05-14 16:48:07 +04002157 %TemplateDecl = ();
2158 %StdCxxTypedef = ();
2159 %MissedTypedef = ();
2160 %Typedef_Tr = ();
2161 %Typedef_Eq = ();
2162
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04002163 # clean cache
2164 delete($Cache{"getTypeAttr"});
2165 delete($Cache{"getTypeDeclId"});
2166
2167 # remove unused types
2168 if($BinaryOnly and not $ExtendedCheck)
2169 { # --binary
2170 removeUnused($Version, "All");
2171 }
2172 else {
2173 removeUnused($Version, "Derived");
2174 }
2175
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002176 if($Debug) {
2177 # debugMangling($Version);
2178 }
2179}
2180
Andrey Ponomarenko85043792012-05-14 16:48:07 +04002181sub readTUDump($)
2182{
2183 my $DumpPath = $_[0];
2184
2185 open(TU_DUMP, $DumpPath);
2186 local $/ = undef;
2187 my $Content = <TU_DUMP>;
2188 close(TU_DUMP);
2189
2190 unlink($DumpPath);
2191
2192 $Content=~s/\n[ ]+/ /g;
2193 my @Lines = split("\n", $Content);
2194
2195 # clean memory
2196 undef $Content;
2197
2198 $MAX_ID = $#Lines+1;
2199
2200 foreach (0 .. $#Lines)
2201 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04002202 if($Lines[$_]=~/\A\@(\d+)[ ]+([a-z_]+)[ ]+(.+)\Z/i)
Andrey Ponomarenko85043792012-05-14 16:48:07 +04002203 { # get a number and attributes of a node
2204 next if(not $NodeType{$2});
2205 $LibInfo{$Version}{"info_type"}{$1}=$2;
2206 $LibInfo{$Version}{"info"}{$1}=$3;
2207 }
2208
2209 # clean memory
2210 delete($Lines[$_]);
2211 }
2212
2213 # clean memory
2214 undef @Lines;
2215}
2216
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002217sub simplifyNames()
2218{
2219 foreach my $Base (keys(%{$Typedef_Tr{$Version}}))
2220 {
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +04002221 if($Typedef_Eq{$Version}{$Base}) {
2222 next;
2223 }
2224 my @Translations = sort keys(%{$Typedef_Tr{$Version}{$Base}});
2225 if($#Translations==0)
2226 {
2227 if(length($Translations[0])<=length($Base)) {
2228 $Typedef_Eq{$Version}{$Base} = $Translations[0];
2229 }
2230 }
2231 else
2232 { # select most appropriate
2233 foreach my $Tr (@Translations)
2234 {
2235 if($Base=~/\A\Q$Tr\E/)
2236 {
2237 $Typedef_Eq{$Version}{$Base} = $Tr;
2238 last;
2239 }
2240 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002241 }
2242 }
Andrey Ponomarenkob8d203d2012-05-25 18:11:07 +04002243 foreach my $TypeId (keys(%{$TypeInfo{$Version}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002244 {
Andrey Ponomarenkob8d203d2012-05-25 18:11:07 +04002245 my $TypeName = $TypeInfo{$Version}{$TypeId}{"Name"};
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04002246 if(not $TypeName) {
2247 next;
2248 }
2249 next if(index($TypeName,"<")==-1);# template instances only
2250 if($TypeName=~/>(::\w+)+\Z/)
2251 { # skip unused types
2252 next;
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +04002253 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04002254 foreach my $Base (sort {length($b)<=>length($a)}
2255 sort {$b cmp $a} keys(%{$Typedef_Eq{$Version}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002256 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04002257 next if(not $Base);
2258 next if(index($TypeName,$Base)==-1);
2259 next if(length($TypeName) - length($Base) <= 3);
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +04002260 if(my $Typedef = $Typedef_Eq{$Version}{$Base})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002261 {
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +04002262 $TypeName=~s/(\<|\,)\Q$Base\E(\W|\Z)/$1$Typedef$2/g;
2263 $TypeName=~s/(\<|\,)\Q$Base\E(\w|\Z)/$1$Typedef $2/g;
2264 if(defined $TypeInfo{$Version}{$TypeId}{"TParam"})
Andrey Ponomarenko85043792012-05-14 16:48:07 +04002265 {
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +04002266 foreach my $TPos (keys(%{$TypeInfo{$Version}{$TypeId}{"TParam"}}))
2267 {
2268 if(my $TPName = $TypeInfo{$Version}{$TypeId}{"TParam"}{$TPos}{"name"})
2269 {
2270 $TPName=~s/\A\Q$Base\E(\W|\Z)/$Typedef$1/g;
2271 $TPName=~s/\A\Q$Base\E(\w|\Z)/$Typedef $1/g;
Andrey Ponomarenko9927e332012-10-19 10:50:48 +04002272 $TypeInfo{$Version}{$TypeId}{"TParam"}{$TPos}{"name"} = formatName($TPName, "T");
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +04002273 }
2274 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +04002275 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002276 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002277 }
Andrey Ponomarenko9927e332012-10-19 10:50:48 +04002278 $TypeName = formatName($TypeName, "T");
Andrey Ponomarenkob8d203d2012-05-25 18:11:07 +04002279 $TypeInfo{$Version}{$TypeId}{"Name"} = $TypeName;
2280 $TName_Tid{$Version}{$TypeName} = $TypeId;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002281 }
2282}
2283
2284sub setTemplateParams_All()
2285{
2286 foreach (keys(%{$LibInfo{$Version}{"info"}}))
2287 {
2288 if($LibInfo{$Version}{"info_type"}{$_} eq "template_decl") {
2289 setTemplateParams($_);
2290 }
2291 }
2292}
2293
2294sub setTemplateParams($)
2295{
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04002296 if(my $Info = $LibInfo{$Version}{"info"}{$_[0]})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002297 {
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04002298 if($Info=~/(inst|spcs)[ ]*:[ ]*@(\d+) /)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002299 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04002300 my $TmplInst_Id = $2;
2301 setTemplateInstParams($TmplInst_Id);
2302 while($TmplInst_Id = getNextElem($TmplInst_Id)) {
2303 setTemplateInstParams($TmplInst_Id);
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04002304 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002305 }
2306 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04002307 if(my $TypeId = getTreeAttr_Type($_[0]))
Andrey Ponomarenko85043792012-05-14 16:48:07 +04002308 {
2309 if(my $IType = $LibInfo{$Version}{"info_type"}{$TypeId})
2310 {
2311 if($IType eq "record_type") {
2312 $TemplateDecl{$Version}{$TypeId}=1;
2313 }
2314 }
2315 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002316}
2317
2318sub setTemplateInstParams($)
2319{
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04002320 if(my $Info = $LibInfo{$Version}{"info"}{$_[0]})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002321 {
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04002322 my ($Params_InfoId, $ElemId) = ();
2323 if($Info=~/purp[ ]*:[ ]*@(\d+) /) {
2324 $Params_InfoId = $1;
2325 }
2326 if($Info=~/valu[ ]*:[ ]*@(\d+) /) {
2327 $ElemId = $1;
2328 }
2329 if($Params_InfoId and $ElemId)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002330 {
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04002331 my $Params_Info = $LibInfo{$Version}{"info"}{$Params_InfoId};
2332 while($Params_Info=~s/ (\d+)[ ]*:[ ]*\@(\d+) / /)
2333 {
2334 my ($PPos, $PTypeId) = ($1, $2);
2335 if(my $PType = $LibInfo{$Version}{"info_type"}{$PTypeId})
2336 {
Andrey Ponomarenko85043792012-05-14 16:48:07 +04002337 if($PType eq "template_type_parm")
2338 {
2339 $TemplateDecl{$Version}{$ElemId}=1;
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04002340 return;
2341 }
2342 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +04002343 if($LibInfo{$Version}{"info_type"}{$ElemId} eq "function_decl")
2344 { # functions
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04002345 $TemplateInstance{$Version}{"Func"}{$ElemId}{$PPos} = $PTypeId;
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04002346 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +04002347 else
2348 { # types
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04002349 $TemplateInstance{$Version}{"Type"}{$ElemId}{$PPos} = $PTypeId;
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04002350 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002351 }
2352 }
2353 }
2354}
2355
2356sub getTypeDeclId($)
2357{
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04002358 if($_[0])
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04002359 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04002360 if(defined $Cache{"getTypeDeclId"}{$Version}{$_[0]}) {
2361 return $Cache{"getTypeDeclId"}{$Version}{$_[0]};
2362 }
2363 if(my $Info = $LibInfo{$Version}{"info"}{$_[0]})
2364 {
2365 if($Info=~/name[ ]*:[ ]*@(\d+)/) {
2366 return ($Cache{"getTypeDeclId"}{$Version}{$_[0]} = $1);
2367 }
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04002368 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002369 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04002370 return ($Cache{"getTypeDeclId"}{$Version}{$_[0]} = 0);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002371}
2372
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002373sub getTypeInfo_All()
2374{
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04002375 if(not check_gcc($GCC_PATH, "4.5"))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002376 { # support for GCC < 4.5
2377 # missed typedefs: QStyle::State is typedef to QFlags<QStyle::StateFlag>
2378 # but QStyleOption.state is of type QFlags<QStyle::StateFlag> in the TU dump
2379 # FIXME: check GCC versions
2380 addMissedTypes_Pre();
2381 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04002382
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002383 foreach (sort {int($a)<=>int($b)} keys(%{$LibInfo{$Version}{"info"}}))
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04002384 { # forward order only
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002385 my $IType = $LibInfo{$Version}{"info_type"}{$_};
2386 if($IType=~/_type\Z/ and $IType ne "function_type"
2387 and $IType ne "method_type") {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04002388 getTypeInfo("$_");
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002389 }
2390 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04002391
2392 # add "..." type
Andrey Ponomarenko01117f12012-06-26 12:23:02 +04002393 $TypeInfo{$Version}{"-1"} = {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04002394 "Name" => "...",
2395 "Type" => "Intrinsic",
Andrey Ponomarenko01117f12012-06-26 12:23:02 +04002396 "Tid" => "-1"
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04002397 };
Andrey Ponomarenko01117f12012-06-26 12:23:02 +04002398 $TName_Tid{$Version}{"..."} = "-1";
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04002399
2400 if(not check_gcc($GCC_PATH, "4.5"))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002401 { # support for GCC < 4.5
2402 addMissedTypes_Post();
2403 }
2404}
2405
2406sub addMissedTypes_Pre()
2407{
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04002408 my %MissedTypes = ();
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002409 foreach my $MissedTDid (sort {int($a)<=>int($b)} keys(%{$LibInfo{$Version}{"info"}}))
2410 { # detecting missed typedefs
2411 if($LibInfo{$Version}{"info_type"}{$MissedTDid} eq "type_decl")
2412 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04002413 my $TypeId = getTreeAttr_Type($MissedTDid);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002414 next if(not $TypeId);
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04002415 my $TypeType = getTypeType($TypeId);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002416 if($TypeType eq "Unknown")
2417 { # template_type_parm
2418 next;
2419 }
2420 my $TypeDeclId = getTypeDeclId($TypeId);
2421 next if($TypeDeclId eq $MissedTDid);#or not $TypeDeclId
2422 my $TypedefName = getNameByInfo($MissedTDid);
2423 next if(not $TypedefName);
2424 next if($TypedefName eq "__float80");
2425 next if(isAnon($TypedefName));
2426 if(not $TypeDeclId
2427 or getNameByInfo($TypeDeclId) ne $TypedefName) {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04002428 $MissedTypes{$Version}{$TypeId}{$MissedTDid} = 1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002429 }
2430 }
2431 }
Andrey Ponomarenkob8d203d2012-05-25 18:11:07 +04002432 my %AddTypes = ();
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04002433 foreach my $Tid (keys(%{$MissedTypes{$Version}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002434 { # add missed typedefs
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04002435 my @Missed = keys(%{$MissedTypes{$Version}{$Tid}});
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002436 if(not @Missed or $#Missed>=1) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002437 next;
2438 }
2439 my $MissedTDid = $Missed[0];
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002440 my ($TypedefName, $TypedefNS) = getTrivialName($MissedTDid, $Tid);
Andrey Ponomarenkob8d203d2012-05-25 18:11:07 +04002441 if(not $TypedefName) {
2442 next;
2443 }
2444 $MAX_ID++;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002445 my %MissedInfo = ( # typedef info
2446 "Name" => $TypedefName,
2447 "NameSpace" => $TypedefNS,
2448 "BaseType" => {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002449 "Tid" => $Tid
2450 },
2451 "Type" => "Typedef",
Andrey Ponomarenkob8d203d2012-05-25 18:11:07 +04002452 "Tid" => "$MAX_ID" );
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002453 my ($H, $L) = getLocation($MissedTDid);
2454 $MissedInfo{"Header"} = $H;
2455 $MissedInfo{"Line"} = $L;
Andrey Ponomarenkob8d203d2012-05-25 18:11:07 +04002456 if($TypedefName=~/\*|\&|\s/)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002457 { # other types
2458 next;
2459 }
Andrey Ponomarenkob8d203d2012-05-25 18:11:07 +04002460 if($TypedefName=~/>(::\w+)+\Z/)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002461 { # QFlags<Qt::DropAction>::enum_type
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002462 next;
2463 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04002464 if(getTypeType($Tid)=~/\A(Intrinsic|Union|Struct|Enum|Class)\Z/)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002465 { # double-check for the name of typedef
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04002466 my ($TName, $TNS) = getTrivialName(getTypeDeclId($Tid), $Tid); # base type info
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002467 next if(not $TName);
Andrey Ponomarenkob8d203d2012-05-25 18:11:07 +04002468 if(length($TypedefName)>=length($TName))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002469 { # too long typedef
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002470 next;
2471 }
Andrey Ponomarenkob8d203d2012-05-25 18:11:07 +04002472 if($TName=~/\A\Q$TypedefName\E</) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002473 next;
2474 }
Andrey Ponomarenkob8d203d2012-05-25 18:11:07 +04002475 if($TypedefName=~/\A\Q$TName\E/)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002476 { # QDateTimeEdit::Section and QDateTimeEdit::Sections::enum_type
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002477 next;
2478 }
Andrey Ponomarenkob8d203d2012-05-25 18:11:07 +04002479 if(get_depth($TypedefName)==0 and get_depth($TName)!=0)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002480 { # std::_Vector_base and std::vector::_Base
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002481 next;
2482 }
2483 }
Andrey Ponomarenkob8d203d2012-05-25 18:11:07 +04002484
2485 $AddTypes{$MissedInfo{"Tid"}} = \%MissedInfo;
2486
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002487 # register typedef
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002488 $MissedTypedef{$Version}{$Tid}{"Tid"} = $MissedInfo{"Tid"};
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04002489 $MissedTypedef{$Version}{$Tid}{"TDid"} = $MissedTDid;
Andrey Ponomarenkob8d203d2012-05-25 18:11:07 +04002490 $TName_Tid{$Version}{$TypedefName} = $MissedInfo{"Tid"};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002491 }
Andrey Ponomarenkob8d203d2012-05-25 18:11:07 +04002492
2493 # add missed & remove other
2494 $TypeInfo{$Version} = \%AddTypes;
2495 delete($Cache{"getTypeAttr"}{$Version});
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002496}
2497
2498sub addMissedTypes_Post()
2499{
2500 foreach my $BaseId (keys(%{$MissedTypedef{$Version}}))
2501 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04002502 if(my $Tid = $MissedTypedef{$Version}{$BaseId}{"Tid"})
2503 {
2504 $TypeInfo{$Version}{$Tid}{"Size"} = $TypeInfo{$Version}{$BaseId}{"Size"};
2505 if(my $TName = $TypeInfo{$Version}{$Tid}{"Name"}) {
2506 $Typedef_BaseName{$Version}{$TName} = $TypeInfo{$Version}{$BaseId}{"Name"};
2507 }
2508 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002509 }
2510}
2511
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04002512sub getTypeInfo($)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002513{
Andrey Ponomarenkob8d203d2012-05-25 18:11:07 +04002514 my $TypeId = $_[0];
2515 %{$TypeInfo{$Version}{$TypeId}} = getTypeAttr($TypeId);
2516 my $TName = $TypeInfo{$Version}{$TypeId}{"Name"};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002517 if(not $TName) {
Andrey Ponomarenkob8d203d2012-05-25 18:11:07 +04002518 delete($TypeInfo{$Version}{$TypeId});
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002519 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002520}
2521
2522sub getArraySize($$)
2523{
2524 my ($TypeId, $BaseName) = @_;
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04002525 if(my $Size = getSize($TypeId))
2526 {
2527 my $Elems = $Size/$BYTE_SIZE;
2528 while($BaseName=~s/\s*\[(\d+)\]//) {
2529 $Elems/=$1;
2530 }
2531 if(my $BasicId = $TName_Tid{$Version}{$BaseName})
2532 {
2533 if(my $BasicSize = $TypeInfo{$Version}{$BasicId}{"Size"}) {
2534 $Elems/=$BasicSize;
2535 }
2536 }
2537 return $Elems;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002538 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04002539 return 0;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002540}
2541
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04002542sub getTParams($$)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002543{
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04002544 my ($TypeId, $Kind) = @_;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002545 my @TmplParams = ();
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04002546 my @Positions = sort {int($a)<=>int($b)} keys(%{$TemplateInstance{$Version}{$Kind}{$TypeId}});
2547 foreach my $Pos (@Positions)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002548 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04002549 my $Param_TypeId = $TemplateInstance{$Version}{$Kind}{$TypeId}{$Pos};
2550 my $NodeType = $LibInfo{$Version}{"info_type"}{$Param_TypeId};
2551 if(not $NodeType)
2552 { # typename_type
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002553 return ();
2554 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04002555 if($NodeType eq "tree_vec")
2556 {
2557 if($Pos!=$#Positions)
2558 { # select last vector of parameters ( ns<P1>::type<P2> )
2559 next;
2560 }
2561 }
2562 my @Params = get_TemplateParam($Pos, $Param_TypeId);
2563 foreach my $P (@Params)
2564 {
2565 if($P eq "") {
2566 return ();
2567 }
2568 elsif($P ne "\@skip\@") {
2569 @TmplParams = (@TmplParams, $P);
2570 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002571 }
2572 }
2573 return @TmplParams;
2574}
2575
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04002576sub getTypeAttr($)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002577{
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04002578 my $TypeId = $_[0];
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04002579 my %TypeAttr = ();
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04002580 if(defined $TypeInfo{$Version}{$TypeId}
2581 and $TypeInfo{$Version}{$TypeId}{"Name"})
2582 { # already created
2583 return %{$TypeInfo{$Version}{$TypeId}};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002584 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04002585 elsif($Cache{"getTypeAttr"}{$Version}{$TypeId})
2586 { # incomplete type
2587 return ();
2588 }
2589 $Cache{"getTypeAttr"}{$Version}{$TypeId} = 1;
2590
2591 my $TypeDeclId = getTypeDeclId($TypeId);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002592 $TypeAttr{"Tid"} = $TypeId;
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04002593
2594 if(not $MissedBase{$Version}{$TypeId} and isTypedef($TypeId))
2595 {
2596 if(my $Info = $LibInfo{$Version}{"info"}{$TypeId})
2597 {
2598 if($Info=~/qual[ ]*:/)
2599 {
2600 if(my $NID = ++$MAX_ID)
2601 {
2602 $MissedBase{$Version}{$TypeId}="$NID";
2603 $MissedBase_R{$Version}{$NID}=$TypeId;
2604 $LibInfo{$Version}{"info"}{$NID} = $LibInfo{$Version}{"info"}{$TypeId};
2605 $LibInfo{$Version}{"info_type"}{$NID} = $LibInfo{$Version}{"info_type"}{$TypeId};
2606 }
2607 }
2608 }
2609 $TypeAttr{"Type"} = "Typedef";
2610 }
2611 else {
2612 $TypeAttr{"Type"} = getTypeType($TypeId);
2613 }
2614
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002615 if($TypeAttr{"Type"} eq "Unknown") {
2616 return ();
2617 }
2618 elsif($TypeAttr{"Type"}=~/(Func|Method|Field)Ptr/)
2619 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04002620 %TypeAttr = getMemPtrAttr(pointTo($TypeId), $TypeId, $TypeAttr{"Type"});
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04002621 if(my $TName = $TypeAttr{"Name"})
2622 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04002623 %{$TypeInfo{$Version}{$TypeId}} = %TypeAttr;
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04002624 $TName_Tid{$Version}{$TName} = $TypeId;
2625 return %TypeAttr;
2626 }
2627 else {
2628 return ();
2629 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002630 }
2631 elsif($TypeAttr{"Type"} eq "Array")
2632 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04002633 my ($BTid, $BTSpec) = selectBaseType($TypeId);
2634 if(not $BTid) {
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04002635 return ();
2636 }
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +04002637 if(my $Algn = getAlgn($TypeId)) {
2638 $TypeAttr{"Algn"} = $Algn/$BYTE_SIZE;
2639 }
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04002640 $TypeAttr{"BaseType"}{"Tid"} = $BTid;
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04002641 if(my %BTAttr = getTypeAttr($BTid))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002642 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04002643 if(not $BTAttr{"Name"}) {
2644 return ();
2645 }
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04002646 if(my $NElems = getArraySize($TypeId, $BTAttr{"Name"}))
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04002647 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04002648 if(my $Size = getSize($TypeId)) {
2649 $TypeAttr{"Size"} = $Size/$BYTE_SIZE;
2650 }
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04002651 if($BTAttr{"Name"}=~/\A([^\[\]]+)(\[(\d+|)\].*)\Z/) {
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04002652 $TypeAttr{"Name"} = $1."[$NElems]".$2;
2653 }
2654 else {
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04002655 $TypeAttr{"Name"} = $BTAttr{"Name"}."[$NElems]";
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04002656 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002657 }
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04002658 else
2659 {
2660 $TypeAttr{"Size"} = $WORD_SIZE{$Version}; # pointer
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04002661 if($BTAttr{"Name"}=~/\A([^\[\]]+)(\[(\d+|)\].*)\Z/) {
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04002662 $TypeAttr{"Name"} = $1."[]".$2;
2663 }
2664 else {
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04002665 $TypeAttr{"Name"} = $BTAttr{"Name"}."[]";
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04002666 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002667 }
Andrey Ponomarenko9927e332012-10-19 10:50:48 +04002668 $TypeAttr{"Name"} = formatName($TypeAttr{"Name"}, "T");
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04002669 if($BTAttr{"Header"}) {
2670 $TypeAttr{"Header"} = $BTAttr{"Header"};
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04002671 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04002672 %{$TypeInfo{$Version}{$TypeId}} = %TypeAttr;
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04002673 $TName_Tid{$Version}{$TypeAttr{"Name"}} = $TypeId;
2674 return %TypeAttr;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002675 }
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04002676 return ();
2677 }
2678 elsif($TypeAttr{"Type"}=~/\A(Intrinsic|Union|Struct|Enum|Class)\Z/)
2679 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04002680 %TypeAttr = getTrivialTypeAttr($TypeId);
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04002681 if($TypeAttr{"Name"})
2682 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04002683 %{$TypeInfo{$Version}{$TypeId}} = %TypeAttr;
2684 if($TypeAttr{"Name"} ne "int" or getTypeDeclId($TypeAttr{"Tid"}))
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04002685 { # NOTE: register only one int: with built-in decl
2686 if(not $TName_Tid{$Version}{$TypeAttr{"Name"}}) {
2687 $TName_Tid{$Version}{$TypeAttr{"Name"}} = $TypeId;
2688 }
2689 }
2690 return %TypeAttr;
2691 }
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04002692 else {
2693 return ();
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002694 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002695 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002696 else
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04002697 { # derived types
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04002698 my ($BTid, $BTSpec) = selectBaseType($TypeId);
2699 if(not $BTid) {
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04002700 return ();
2701 }
2702 $TypeAttr{"BaseType"}{"Tid"} = $BTid;
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04002703 if(defined $MissedTypedef{$Version}{$BTid})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002704 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04002705 if(my $MissedTDid = $MissedTypedef{$Version}{$BTid}{"TDid"})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002706 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04002707 if($MissedTDid ne $TypeDeclId) {
2708 $TypeAttr{"BaseType"}{"Tid"} = $MissedTypedef{$Version}{$BTid}{"Tid"};
2709 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002710 }
2711 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04002712 my %BTAttr = getTypeAttr($TypeAttr{"BaseType"}{"Tid"});
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04002713 if(not $BTAttr{"Name"})
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04002714 { # templates
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002715 return ();
2716 }
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04002717 if($BTAttr{"Type"} eq "Typedef")
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002718 { # relinking typedefs
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04002719 my %BaseBase = get_Type($BTAttr{"BaseType"}{"Tid"}, $Version);
2720 if($BTAttr{"Name"} eq $BaseBase{"Name"}) {
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04002721 $TypeAttr{"BaseType"}{"Tid"} = $BaseBase{"Tid"};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002722 }
2723 }
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04002724 if($BTSpec)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002725 {
2726 if($TypeAttr{"Type"} eq "Pointer"
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04002727 and $BTAttr{"Name"}=~/\([\*]+\)/)
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04002728 {
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04002729 $TypeAttr{"Name"} = $BTAttr{"Name"};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002730 $TypeAttr{"Name"}=~s/\(([*]+)\)/($1*)/g;
2731 }
2732 else {
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04002733 $TypeAttr{"Name"} = $BTAttr{"Name"}." ".$BTSpec;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002734 }
2735 }
2736 else {
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04002737 $TypeAttr{"Name"} = $BTAttr{"Name"};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002738 }
2739 if($TypeAttr{"Type"} eq "Typedef")
2740 {
2741 $TypeAttr{"Name"} = getNameByInfo($TypeDeclId);
Andrey Ponomarenko85043792012-05-14 16:48:07 +04002742 if(isAnon($TypeAttr{"Name"}))
2743 { # anon typedef to anon type: ._N
2744 return ();
2745 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002746 if(my $NS = getNameSpace($TypeDeclId))
2747 {
2748 my $TypeName = $TypeAttr{"Name"};
2749 if($NS=~/\A(struct |union |class |)((.+)::|)\Q$TypeName\E\Z/)
2750 { # "some_type" is the typedef to "struct some_type" in C++
2751 if($3) {
2752 $TypeAttr{"Name"} = $3."::".$TypeName;
2753 }
2754 }
2755 else
2756 {
2757 $TypeAttr{"NameSpace"} = $NS;
2758 $TypeAttr{"Name"} = $TypeAttr{"NameSpace"}."::".$TypeAttr{"Name"};
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04002759
2760 if($TypeAttr{"NameSpace"}=~/\Astd(::|\Z)/
2761 and $TypeAttr{"Name"}!~/>(::\w+)+\Z/)
2762 {
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04002763 if($BTAttr{"NameSpace"}
2764 and $BTAttr{"NameSpace"}=~/\Astd(::|\Z)/ and $BTAttr{"Name"}=~/</)
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04002765 { # types like "std::fpos<__mbstate_t>" are
2766 # not covered by typedefs in the TU dump
2767 # so trying to add such typedefs manually
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04002768 $StdCxxTypedef{$Version}{$BTAttr{"Name"}}{$TypeAttr{"Name"}} = 1;
2769 if(length($TypeAttr{"Name"})<=length($BTAttr{"Name"}))
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04002770 {
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04002771 if(($BTAttr{"Name"}!~/\A(std|boost)::/ or $TypeAttr{"Name"}!~/\A[a-z]+\Z/))
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04002772 { # skip "other" in "std" and "type" in "boost"
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04002773 $Typedef_Eq{$Version}{$BTAttr{"Name"}} = $TypeAttr{"Name"};
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04002774 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002775 }
2776 }
2777 }
2778 }
2779 }
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04002780 if($TypeAttr{"Name"} ne $BTAttr{"Name"}
2781 and $TypeAttr{"Name"}!~/>(::\w+)+\Z/ and $BTAttr{"Name"}!~/>(::\w+)+\Z/)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002782 {
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04002783 if(not defined $Typedef_BaseName{$Version}{$TypeAttr{"Name"}})
2784 { # typedef int*const TYPEDEF; // first
2785 # int foo(TYPEDEF p); // const is optimized out
2786 $Typedef_BaseName{$Version}{$TypeAttr{"Name"}} = $BTAttr{"Name"};
2787 if($BTAttr{"Name"}=~/</)
2788 {
2789 if(($BTAttr{"Name"}!~/\A(std|boost)::/ or $TypeAttr{"Name"}!~/\A[a-z]+\Z/)) {
2790 $Typedef_Tr{$Version}{$BTAttr{"Name"}}{$TypeAttr{"Name"}} = 1;
2791 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002792 }
2793 }
2794 }
2795 ($TypeAttr{"Header"}, $TypeAttr{"Line"}) = getLocation($TypeDeclId);
2796 }
2797 if(not $TypeAttr{"Size"})
2798 {
2799 if($TypeAttr{"Type"} eq "Pointer") {
2800 $TypeAttr{"Size"} = $WORD_SIZE{$Version};
2801 }
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04002802 elsif($BTAttr{"Size"}) {
2803 $TypeAttr{"Size"} = $BTAttr{"Size"};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002804 }
2805 }
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +04002806 if(my $Algn = getAlgn($TypeId)) {
2807 $TypeAttr{"Algn"} = $Algn/$BYTE_SIZE;
2808 }
Andrey Ponomarenko9927e332012-10-19 10:50:48 +04002809 $TypeAttr{"Name"} = formatName($TypeAttr{"Name"}, "T");
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04002810 if(not $TypeAttr{"Header"} and $BTAttr{"Header"}) {
2811 $TypeAttr{"Header"} = $BTAttr{"Header"};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002812 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04002813 %{$TypeInfo{$Version}{$TypeId}} = %TypeAttr;
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04002814 if($TypeAttr{"Name"} ne $BTAttr{"Name"})
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04002815 { # typedef to "class Class"
2816 # should not be registered in TName_Tid
2817 if(not $TName_Tid{$Version}{$TypeAttr{"Name"}}) {
2818 $TName_Tid{$Version}{$TypeAttr{"Name"}} = $TypeId;
2819 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002820 }
2821 return %TypeAttr;
2822 }
2823}
2824
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04002825sub getTreeVec($)
2826{
2827 my %Vector = ();
2828 if($_[0] and my $Info = $LibInfo{$Version}{"info"}{$_[0]})
2829 {
2830 while($Info=~s/ (\d+)[ ]*:[ ]*\@(\d+) / /)
2831 { # string length is N-1 because of the null terminator
2832 $Vector{$1} = $2;
2833 }
2834 }
2835 return \%Vector;
2836}
2837
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002838sub get_TemplateParam($$)
2839{
2840 my ($Pos, $Type_Id) = @_;
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04002841 return () if(not $Type_Id);
2842 my $NodeType = $LibInfo{$Version}{"info_type"}{$Type_Id};
2843 return () if(not $NodeType);
2844 if($NodeType eq "integer_cst")
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002845 { # int (1), unsigned (2u), char ('c' as 99), ...
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04002846 my $CstTid = getTreeAttr_Type($Type_Id);
Andrey Ponomarenkob8d203d2012-05-25 18:11:07 +04002847 my %CstType = getTypeAttr($CstTid); # without recursion
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002848 my $Num = getNodeIntCst($Type_Id);
2849 if(my $CstSuffix = $ConstantSuffix{$CstType{"Name"}}) {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04002850 return ($Num.$CstSuffix);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002851 }
2852 else {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04002853 return ("(".$CstType{"Name"}.")".$Num);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002854 }
2855 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04002856 elsif($NodeType eq "string_cst") {
2857 return (getNodeStrCst($Type_Id));
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002858 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04002859 elsif($NodeType eq "tree_vec")
2860 {
2861 my $Vector = getTreeVec($Type_Id);
2862 my @Params = ();
2863 foreach my $P1 (sort {int($a)<=>int($b)} keys(%{$Vector}))
2864 {
2865 foreach my $P2 (get_TemplateParam($Pos, $Vector->{$P1})) {
2866 push(@Params, $P2);
2867 }
2868 }
2869 return @Params;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002870 }
2871 else
2872 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04002873 my %ParamAttr = getTypeAttr($Type_Id);
Andrey Ponomarenkob8d203d2012-05-25 18:11:07 +04002874 my $PName = $ParamAttr{"Name"};
2875 if(not $PName) {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04002876 return ();
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002877 }
Andrey Ponomarenkob8d203d2012-05-25 18:11:07 +04002878 if($PName=~/\>/)
2879 {
2880 if(my $Cover = cover_stdcxx_typedef($PName)) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002881 $PName = $Cover;
2882 }
2883 }
2884 if($Pos>=1 and
Andrey Ponomarenko1477d2c2012-11-12 18:55:45 +04002885 $PName=~/\A$DEFAULT_STD_PARMS\</)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002886 { # template<typename _Tp, typename _Alloc = std::allocator<_Tp> >
2887 # template<typename _Key, typename _Compare = std::less<_Key>
2888 # template<typename _CharT, typename _Traits = std::char_traits<_CharT> >
2889 # template<typename _Ch_type, typename _Rx_traits = regex_traits<_Ch_type> >
2890 # template<typename _CharT, typename _InIter = istreambuf_iterator<_CharT> >
2891 # template<typename _CharT, typename _OutIter = ostreambuf_iterator<_CharT> >
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04002892 return ("\@skip\@");
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002893 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04002894 return ($PName);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002895 }
2896}
2897
2898sub cover_stdcxx_typedef($)
2899{
2900 my $TypeName = $_[0];
2901 if(my @Covers = sort {length($a)<=>length($b)}
2902 sort keys(%{$StdCxxTypedef{$Version}{$TypeName}}))
2903 { # take the shortest typedef
2904 # FIXME: there may be more than
2905 # one typedefs to the same type
2906 return $Covers[0];
2907 }
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +04002908 my $Covered = $TypeName;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002909 while($TypeName=~s/(>)[ ]*(const|volatile|restrict| |\*|\&)\Z/$1/g){};
2910 if(my @Covers = sort {length($a)<=>length($b)} sort keys(%{$StdCxxTypedef{$Version}{$TypeName}}))
2911 {
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +04002912 if(my $Cover = $Covers[0])
2913 {
2914 $Covered=~s/\b\Q$TypeName\E(\W|\Z)/$Cover$1/g;
2915 $Covered=~s/\b\Q$TypeName\E(\w|\Z)/$Cover $1/g;
2916 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002917 }
Andrey Ponomarenko9927e332012-10-19 10:50:48 +04002918 return formatName($Covered, "T");
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002919}
2920
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002921sub getNodeIntCst($)
2922{
2923 my $CstId = $_[0];
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04002924 my $CstTypeId = getTreeAttr_Type($CstId);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002925 if($EnumMembName_Id{$Version}{$CstId}) {
2926 return $EnumMembName_Id{$Version}{$CstId};
2927 }
2928 elsif((my $Value = getTreeValue($CstId)) ne "")
2929 {
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04002930 if($Value eq "0")
2931 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04002932 if($LibInfo{$Version}{"info_type"}{$CstTypeId} eq "boolean_type") {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002933 return "false";
2934 }
2935 else {
2936 return "0";
2937 }
2938 }
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04002939 elsif($Value eq "1")
2940 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04002941 if($LibInfo{$Version}{"info_type"}{$CstTypeId} eq "boolean_type") {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002942 return "true";
2943 }
2944 else {
2945 return "1";
2946 }
2947 }
2948 else {
2949 return $Value;
2950 }
2951 }
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04002952 return "";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002953}
2954
2955sub getNodeStrCst($)
2956{
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04002957 if($_[0] and my $Info = $LibInfo{$Version}{"info"}{$_[0]})
2958 {
2959 if($Info=~/strg[ ]*: (.+) lngt:[ ]*(\d+)/)
Andrey Ponomarenko01117f12012-06-26 12:23:02 +04002960 {
2961 if($LibInfo{$Version}{"info_type"}{$_[0]} eq "string_cst")
2962 { # string length is N-1 because of the null terminator
2963 return substr($1, 0, $2-1);
2964 }
2965 else
2966 { # identifier_node
2967 return substr($1, 0, $2);
2968 }
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04002969 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002970 }
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04002971 return "";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002972}
2973
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04002974sub getMemPtrAttr($$$)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002975{ # function, method and field pointers
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04002976 my ($PtrId, $TypeId, $Type) = @_;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002977 my $MemInfo = $LibInfo{$Version}{"info"}{$PtrId};
2978 if($Type eq "FieldPtr") {
2979 $MemInfo = $LibInfo{$Version}{"info"}{$TypeId};
2980 }
2981 my $MemInfo_Type = $LibInfo{$Version}{"info_type"}{$PtrId};
2982 my $MemPtrName = "";
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04002983 my %TypeAttr = ("Size"=>$WORD_SIZE{$Version}, "Type"=>$Type, "Tid"=>$TypeId);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002984 if($Type eq "MethodPtr")
2985 { # size of "method pointer" may be greater than WORD size
Andrey Ponomarenko01117f12012-06-26 12:23:02 +04002986 if(my $Size = getSize($TypeId))
2987 {
2988 $Size/=$BYTE_SIZE;
2989 $TypeAttr{"Size"} = "$Size";
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04002990 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002991 }
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +04002992 if(my $Algn = getAlgn($TypeId)) {
2993 $TypeAttr{"Algn"} = $Algn/$BYTE_SIZE;
2994 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002995 # Return
2996 if($Type eq "FieldPtr")
2997 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04002998 my %ReturnAttr = getTypeAttr($PtrId);
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04002999 if($ReturnAttr{"Name"}) {
3000 $MemPtrName .= $ReturnAttr{"Name"};
3001 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003002 $TypeAttr{"Return"} = $PtrId;
3003 }
3004 else
3005 {
3006 if($MemInfo=~/retn[ ]*:[ ]*\@(\d+) /)
3007 {
3008 my $ReturnTypeId = $1;
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04003009 my %ReturnAttr = getTypeAttr($ReturnTypeId);
3010 if(not $ReturnAttr{"Name"})
3011 { # templates
3012 return ();
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04003013 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04003014 $MemPtrName .= $ReturnAttr{"Name"};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003015 $TypeAttr{"Return"} = $ReturnTypeId;
3016 }
3017 }
3018 # Class
3019 if($MemInfo=~/(clas|cls)[ ]*:[ ]*@(\d+) /)
3020 {
3021 $TypeAttr{"Class"} = $2;
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04003022 my %Class = getTypeAttr($TypeAttr{"Class"});
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003023 if($Class{"Name"}) {
3024 $MemPtrName .= " (".$Class{"Name"}."\:\:*)";
3025 }
3026 else {
3027 $MemPtrName .= " (*)";
3028 }
3029 }
3030 else {
3031 $MemPtrName .= " (*)";
3032 }
3033 # Parameters
3034 if($Type eq "FuncPtr"
3035 or $Type eq "MethodPtr")
3036 {
3037 my @ParamTypeName = ();
3038 if($MemInfo=~/prms[ ]*:[ ]*@(\d+) /)
3039 {
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04003040 my $PTypeInfoId = $1;
Andrey Ponomarenko01117f12012-06-26 12:23:02 +04003041 my ($Pos, $PPos) = (0, 0);
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04003042 while($PTypeInfoId)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003043 {
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04003044 my $PTypeInfo = $LibInfo{$Version}{"info"}{$PTypeInfoId};
3045 if($PTypeInfo=~/valu[ ]*:[ ]*@(\d+) /)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003046 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04003047 my $PTypeId = $1;
3048 my %ParamAttr = getTypeAttr($PTypeId);
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04003049 if(not $ParamAttr{"Name"})
3050 { # templates (template_type_parm), etc.
3051 return ();
3052 }
3053 if($ParamAttr{"Name"} eq "void") {
3054 last;
3055 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04003056 if($Pos!=0 or $Type ne "MethodPtr")
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04003057 {
Andrey Ponomarenko01117f12012-06-26 12:23:02 +04003058 $TypeAttr{"Param"}{$PPos++}{"type"} = $PTypeId;
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04003059 push(@ParamTypeName, $ParamAttr{"Name"});
3060 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04003061 if($PTypeInfoId = getNextElem($PTypeInfoId)) {
3062 $Pos+=1;
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04003063 }
3064 else {
3065 last;
3066 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003067 }
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04003068 else {
3069 last;
3070 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003071 }
3072 }
3073 $MemPtrName .= " (".join(", ", @ParamTypeName).")";
3074 }
Andrey Ponomarenko9927e332012-10-19 10:50:48 +04003075 $TypeAttr{"Name"} = formatName($MemPtrName, "T");
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003076 return %TypeAttr;
3077}
3078
3079sub getTreeTypeName($)
3080{
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04003081 my $TypeId = $_[0];
3082 if(my $Info = $LibInfo{$Version}{"info"}{$TypeId})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003083 {
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04003084 if($LibInfo{$Version}{"info_type"}{$_[0]} eq "integer_type")
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003085 {
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04003086 if(my $Name = getNameByInfo($TypeId))
3087 { # bit_size_type
3088 return $Name;
3089 }
3090 elsif($Info=~/unsigned/) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003091 return "unsigned int";
3092 }
3093 else {
3094 return "int";
3095 }
3096 }
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04003097 elsif($Info=~/name[ ]*:[ ]*@(\d+) /)
3098 {
3099 return getNameByInfo($1);
3100 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003101 }
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04003102 return "";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003103}
3104
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04003105sub isFuncPtr($)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003106{
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04003107 my $Ptd = pointTo($_[0]);
3108 return 0 if(not $Ptd);
3109 if(my $Info = $LibInfo{$Version}{"info"}{$_[0]})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003110 {
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04003111 if($Info=~/unql[ ]*:/ and $Info!~/qual[ ]*:/) {
3112 return 0;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003113 }
3114 }
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04003115 if(my $InfoT1 = $LibInfo{$Version}{"info_type"}{$_[0]}
3116 and my $InfoT2 = $LibInfo{$Version}{"info_type"}{$Ptd})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003117 {
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04003118 if($InfoT1 eq "pointer_type"
3119 and $InfoT2 eq "function_type") {
3120 return 1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003121 }
3122 }
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04003123 return 0;
3124}
3125
3126sub isMethodPtr($)
3127{
3128 my $Ptd = pointTo($_[0]);
3129 return 0 if(not $Ptd);
3130 if(my $Info = $LibInfo{$Version}{"info"}{$_[0]})
3131 {
3132 if($LibInfo{$Version}{"info_type"}{$_[0]} eq "record_type"
3133 and $LibInfo{$Version}{"info_type"}{$Ptd} eq "method_type"
3134 and $Info=~/ ptrmem /) {
3135 return 1;
3136 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003137 }
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04003138 return 0;
3139}
3140
3141sub isFieldPtr($)
3142{
3143 if($_[0] and my $Info = $LibInfo{$Version}{"info"}{$_[0]})
3144 {
3145 if($LibInfo{$Version}{"info_type"}{$_[0]} eq "offset_type"
3146 and $Info=~/ ptrmem /) {
3147 return 1;
3148 }
3149 }
3150 return 0;
3151}
3152
3153sub pointTo($)
3154{
3155 if($_[0] and my $Info = $LibInfo{$Version}{"info"}{$_[0]})
3156 {
3157 if($Info=~/ptd[ ]*:[ ]*@(\d+)/) {
3158 return $1;
3159 }
3160 }
3161 return "";
3162}
3163
3164sub getTypeTypeByTypeId($)
3165{
3166 my $TypeId = $_[0];
3167 if(my $TType = $LibInfo{$Version}{"info_type"}{$TypeId})
3168 {
3169 my $NType = $NodeType{$TType};
3170 if($NType eq "Intrinsic") {
3171 return $NType;
3172 }
3173 elsif(isFuncPtr($TypeId)) {
3174 return "FuncPtr";
3175 }
3176 elsif(isMethodPtr($TypeId)) {
3177 return "MethodPtr";
3178 }
3179 elsif(isFieldPtr($TypeId)) {
3180 return "FieldPtr";
3181 }
3182 elsif($NType ne "Other") {
3183 return $NType;
3184 }
3185 }
3186 return "Unknown";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003187}
3188
3189sub getQual($)
3190{
3191 my $TypeId = $_[0];
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003192 my %UnQual = (
3193 "r"=>"restrict",
3194 "v"=>"volatile",
3195 "c"=>"const",
3196 "cv"=>"const volatile"
3197 );
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04003198 if(my $Info = $LibInfo{$Version}{"info"}{$TypeId})
3199 {
3200 my ($Qual, $To) = ();
3201 if($Info=~/qual[ ]*:[ ]*(r|c|v|cv) /) {
3202 $Qual = $UnQual{$1};
3203 }
3204 if($Info=~/unql[ ]*:[ ]*\@(\d+)/) {
3205 $To = $1;
3206 }
3207 if($Qual and $To) {
3208 return ($Qual, $To);
3209 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003210 }
3211 return ();
3212}
3213
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04003214sub getQualType($)
3215{
3216 if($_[0] eq "const volatile") {
3217 return "ConstVolatile";
3218 }
3219 return ucfirst($_[0]);
3220}
3221
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04003222sub getTypeType($)
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04003223{
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04003224 my $TypeId = $_[0];
3225 my $TypeDeclId = getTypeDeclId($TypeId);
3226 if(defined $MissedTypedef{$Version}{$TypeId})
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04003227 { # support for old GCC versions
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04003228 if($MissedTypedef{$Version}{$TypeId}{"TDid"} eq $TypeDeclId) {
3229 return "Typedef";
3230 }
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04003231 }
3232 my $Info = $LibInfo{$Version}{"info"}{$TypeId};
3233 my ($Qual, $To) = getQual($TypeId);
Andrey Ponomarenko9927e332012-10-19 10:50:48 +04003234 if(($Qual or $To) and $TypeDeclId
3235 and (getTypeId($TypeDeclId) ne $TypeId))
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04003236 { # qualified types (special)
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04003237 return getQualType($Qual);
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04003238 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04003239 elsif(not $MissedBase_R{$Version}{$TypeId}
3240 and isTypedef($TypeId)) {
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04003241 return "Typedef";
3242 }
3243 elsif($Qual)
3244 { # qualified types
3245 return getQualType($Qual);
3246 }
Andrey Ponomarenko9927e332012-10-19 10:50:48 +04003247
3248 if($Info=~/unql[ ]*:[ ]*\@(\d+)/)
3249 { # typedef struct { ... } name
3250 $TypeTypedef{$Version}{$TypeId} = $1;
3251 }
3252
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04003253 my $TypeType = getTypeTypeByTypeId($TypeId);
3254 if($TypeType eq "Struct")
3255 {
3256 if($TypeDeclId
3257 and $LibInfo{$Version}{"info_type"}{$TypeDeclId} eq "template_decl") {
3258 return "Template";
3259 }
3260 }
3261 return $TypeType;
3262}
3263
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04003264sub isTypedef($)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003265{
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04003266 if($_[0] and my $Info = $LibInfo{$Version}{"info"}{$_[0]})
3267 {
3268 my $TDid = getTypeDeclId($_[0]);
3269 if(getNameByInfo($TDid)
3270 and $Info=~/unql[ ]*:[ ]*\@(\d+) /
3271 and getTypeId($TDid) eq $_[0]) {
3272 return $1;
3273 }
3274 }
3275 return 0;
3276}
3277
3278sub selectBaseType($)
3279{
3280 my $TypeId = $_[0];
3281 if(defined $MissedTypedef{$Version}{$TypeId})
3282 { # add missed typedefs
3283 if($MissedTypedef{$Version}{$TypeId}{"TDid"} eq getTypeDeclId($TypeId)) {
3284 return ($TypeId, "");
3285 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003286 }
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04003287 my $Info = $LibInfo{$Version}{"info"}{$TypeId};
3288 my $InfoType = $LibInfo{$Version}{"info_type"}{$TypeId};
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04003289
3290 my $MB_R = $MissedBase_R{$Version}{$TypeId};
3291 my $MB = $MissedBase{$Version}{$TypeId};
3292
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04003293 my ($Qual, $To) = getQual($TypeId);
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04003294 if(($Qual or $To) and $Info=~/name[ ]*:[ ]*\@(\d+) /
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04003295 and (getTypeId($1) ne $TypeId)
3296 and (not $MB_R or getTypeId($1) ne $MB_R))
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04003297 { # qualified types (special)
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04003298 return (getTypeId($1), $Qual);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003299 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04003300 elsif($MB)
3301 { # add base
3302 return ($MB, "");
3303 }
3304 elsif(not $MB_R and my $Bid = isTypedef($TypeId))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003305 { # typedefs
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04003306 return ($Bid, "");
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003307 }
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04003308 elsif($Qual or $To)
3309 { # qualified types
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04003310 return ($To, $Qual);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003311 }
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04003312 elsif($InfoType eq "reference_type")
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003313 {
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04003314 if($Info=~/refd[ ]*:[ ]*@(\d+) /) {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04003315 return ($1, "&");
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003316 }
3317 else {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04003318 return (0, "");
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003319 }
3320 }
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04003321 elsif($InfoType eq "array_type")
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003322 {
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04003323 if($Info=~/elts[ ]*:[ ]*@(\d+) /) {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04003324 return ($1, "");
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003325 }
3326 else {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04003327 return (0, "");
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003328 }
3329 }
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04003330 elsif($InfoType eq "pointer_type")
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003331 {
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04003332 if($Info=~/ptd[ ]*:[ ]*@(\d+) /) {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04003333 return ($1, "*");
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003334 }
3335 else {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04003336 return (0, "");
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003337 }
3338 }
3339 else {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04003340 return (0, "");
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003341 }
3342}
3343
3344sub getSymbolInfo_All()
3345{
3346 foreach (sort {int($b)<=>int($a)} keys(%{$LibInfo{$Version}{"info"}}))
3347 { # reverse order
3348 if($LibInfo{$Version}{"info_type"}{$_} eq "function_decl") {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04003349 getSymbolInfo($_);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003350 }
3351 }
3352}
3353
3354sub getVarInfo_All()
3355{
3356 foreach (sort {int($b)<=>int($a)} keys(%{$LibInfo{$Version}{"info"}}))
3357 { # reverse order
3358 if($LibInfo{$Version}{"info_type"}{$_} eq "var_decl") {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04003359 getVarInfo($_);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003360 }
3361 }
3362}
3363
3364sub isBuiltIn($) {
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04003365 return ($_[0] and $_[0]=~/\<built\-in\>|\<internal\>|\A\./);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003366}
3367
3368sub getVarInfo($)
3369{
3370 my $InfoId = $_[0];
Andrey Ponomarenko01117f12012-06-26 12:23:02 +04003371 if(my $NSid = getTreeAttr_Scpe($InfoId))
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04003372 {
3373 my $NSInfoType = $LibInfo{$Version}{"info_type"}{$NSid};
3374 if($NSInfoType and $NSInfoType eq "function_decl") {
3375 return;
3376 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003377 }
3378 ($SymbolInfo{$Version}{$InfoId}{"Header"}, $SymbolInfo{$Version}{$InfoId}{"Line"}) = getLocation($InfoId);
3379 if(not $SymbolInfo{$Version}{$InfoId}{"Header"}
3380 or isBuiltIn($SymbolInfo{$Version}{$InfoId}{"Header"})) {
3381 delete($SymbolInfo{$Version}{$InfoId});
3382 return;
3383 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04003384 my $ShortName = getTreeStr(getTreeAttr_Name($InfoId));
Andrey Ponomarenko85043792012-05-14 16:48:07 +04003385 if(not $ShortName) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003386 delete($SymbolInfo{$Version}{$InfoId});
3387 return;
3388 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +04003389 if($ShortName=~/\Atmp_add_class_\d+\Z/) {
3390 delete($SymbolInfo{$Version}{$InfoId});
3391 return;
3392 }
3393 $SymbolInfo{$Version}{$InfoId}{"ShortName"} = $ShortName;
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +04003394 if(my $MnglName = getTreeStr(getTreeAttr_Mngl($InfoId)))
3395 {
3396 if($OSgroup eq "windows")
3397 { # cut the offset
3398 $MnglName=~s/\@\d+\Z//g;
3399 }
3400 $SymbolInfo{$Version}{$InfoId}{"MnglName"} = $MnglName;
3401 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003402 if($SymbolInfo{$Version}{$InfoId}{"MnglName"}
Andrey Ponomarenko9927e332012-10-19 10:50:48 +04003403 and index($SymbolInfo{$Version}{$InfoId}{"MnglName"}, "_Z")!=0)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003404 { # validate mangled name
3405 delete($SymbolInfo{$Version}{$InfoId});
3406 return;
3407 }
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04003408 if(not $SymbolInfo{$Version}{$InfoId}{"MnglName"}
Andrey Ponomarenko9927e332012-10-19 10:50:48 +04003409 and index($ShortName, "_Z")==0)
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04003410 { # _ZTS, etc.
Andrey Ponomarenko85043792012-05-14 16:48:07 +04003411 $SymbolInfo{$Version}{$InfoId}{"MnglName"} = $ShortName;
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04003412 }
3413 if(isPrivateData($SymbolInfo{$Version}{$InfoId}{"MnglName"}))
3414 { # non-public global data
3415 delete($SymbolInfo{$Version}{$InfoId});
3416 return;
3417 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003418 $SymbolInfo{$Version}{$InfoId}{"Data"} = 1;
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04003419 if(my $Rid = getTypeId($InfoId))
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04003420 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04003421 if(not $TypeInfo{$Version}{$Rid}{"Name"})
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04003422 { # typename_type
3423 delete($SymbolInfo{$Version}{$InfoId});
3424 return;
3425 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04003426 $SymbolInfo{$Version}{$InfoId}{"Return"} = $Rid;
3427 my $Val = getDataVal($InfoId, $Rid);
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04003428 if(defined $Val) {
3429 $SymbolInfo{$Version}{$InfoId}{"Value"} = $Val;
3430 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003431 }
3432 set_Class_And_Namespace($InfoId);
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04003433 if(my $ClassId = $SymbolInfo{$Version}{$InfoId}{"Class"})
3434 {
3435 if(not $TypeInfo{$Version}{$ClassId}{"Name"})
3436 { # templates
3437 delete($SymbolInfo{$Version}{$InfoId});
3438 return;
3439 }
3440 }
Andrey Ponomarenko35c44fd2012-06-18 17:50:25 +04003441 if($LibInfo{$Version}{"info"}{$InfoId}=~/ lang:[ ]*C /i)
3442 { # extern "C"
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003443 $SymbolInfo{$Version}{$InfoId}{"Lang"} = "C";
Andrey Ponomarenko35c44fd2012-06-18 17:50:25 +04003444 $SymbolInfo{$Version}{$InfoId}{"MnglName"} = $ShortName;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003445 }
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04003446 if($UserLang and $UserLang eq "C")
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003447 { # --lang=C option
Andrey Ponomarenko85043792012-05-14 16:48:07 +04003448 $SymbolInfo{$Version}{$InfoId}{"MnglName"} = $ShortName;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003449 }
Andrey Ponomarenko5c09ef32012-06-14 18:17:33 +04003450 if(not $CheckHeadersOnly)
3451 {
3452 if(not $SymbolInfo{$Version}{$InfoId}{"Class"})
3453 {
3454 if(not $SymbolInfo{$Version}{$InfoId}{"MnglName"}
3455 or not link_symbol($SymbolInfo{$Version}{$InfoId}{"MnglName"}, $Version, "-Deps"))
3456 {
3457 if(link_symbol($ShortName, $Version, "-Deps"))
3458 { # "const" global data is mangled as _ZL... in the TU dump
3459 # but not mangled when compiling a C shared library
3460 $SymbolInfo{$Version}{$InfoId}{"MnglName"} = $ShortName;
3461 }
3462 }
3463 }
3464 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003465 if($COMMON_LANGUAGE{$Version} eq "C++")
3466 {
3467 if(not $SymbolInfo{$Version}{$InfoId}{"MnglName"})
3468 { # for some symbols (_ZTI) the short name is the mangled name
Andrey Ponomarenko9927e332012-10-19 10:50:48 +04003469 if(index($ShortName, "_Z")==0) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003470 $SymbolInfo{$Version}{$InfoId}{"MnglName"} = $ShortName;
3471 }
3472 }
3473 if(not $SymbolInfo{$Version}{$InfoId}{"MnglName"})
3474 { # try to mangle symbol (link with libraries)
3475 $SymbolInfo{$Version}{$InfoId}{"MnglName"} = linkSymbol($InfoId);
3476 }
3477 if($OStarget eq "windows")
3478 {
3479 if(my $Mangled = $mangled_name{$Version}{modelUnmangled($InfoId, "MSVC")})
3480 { # link MS C++ symbols from library with GCC symbols from headers
3481 $SymbolInfo{$Version}{$InfoId}{"MnglName"} = $Mangled;
3482 }
3483 }
3484 }
3485 if(not $SymbolInfo{$Version}{$InfoId}{"MnglName"}) {
3486 $SymbolInfo{$Version}{$InfoId}{"MnglName"} = $ShortName;
3487 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +04003488 if(my $Symbol = $SymbolInfo{$Version}{$InfoId}{"MnglName"})
3489 {
3490 if(not selectSymbol($Symbol, $SymbolInfo{$Version}{$InfoId}, "Dump", $Version))
3491 { # non-target symbols
3492 delete($SymbolInfo{$Version}{$InfoId});
3493 return;
3494 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003495 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04003496 if(my $Rid = $SymbolInfo{$Version}{$InfoId}{"Return"})
3497 {
3498 if(defined $MissedTypedef{$Version}{$Rid})
3499 {
3500 if(my $AddedTid = $MissedTypedef{$Version}{$Rid}{"Tid"}) {
3501 $SymbolInfo{$Version}{$InfoId}{"Return"} = $AddedTid;
3502 }
3503 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003504 }
3505 setFuncAccess($InfoId);
Andrey Ponomarenko9927e332012-10-19 10:50:48 +04003506 if(index($SymbolInfo{$Version}{$InfoId}{"MnglName"}, "_ZTV")==0) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003507 delete($SymbolInfo{$Version}{$InfoId}{"Return"});
3508 }
3509 if($ShortName=~/\A(_Z|\?)/) {
3510 delete($SymbolInfo{$Version}{$InfoId}{"ShortName"});
3511 }
3512}
3513
Andrey Ponomarenko85043792012-05-14 16:48:07 +04003514sub isConstType($$)
3515{
3516 my ($TypeId, $LibVersion) = @_;
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04003517 my %Base = get_Type($TypeId, $LibVersion);
Andrey Ponomarenko85043792012-05-14 16:48:07 +04003518 while(defined $Base{"Type"} and $Base{"Type"} eq "Typedef") {
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +04003519 %Base = get_OneStep_BaseType($Base{"Tid"}, $TypeInfo{$LibVersion});
Andrey Ponomarenko85043792012-05-14 16:48:07 +04003520 }
3521 return ($Base{"Type"} eq "Const");
3522}
3523
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003524sub getTrivialName($$)
3525{
3526 my ($TypeInfoId, $TypeId) = @_;
3527 my %TypeAttr = ();
3528 $TypeAttr{"Name"} = getNameByInfo($TypeInfoId);
3529 if(not $TypeAttr{"Name"}) {
3530 $TypeAttr{"Name"} = getTreeTypeName($TypeId);
3531 }
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04003532 ($TypeAttr{"Header"}, $TypeAttr{"Line"}) = getLocation($TypeInfoId);
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04003533 $TypeAttr{"Type"} = getTypeType($TypeId);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003534 $TypeAttr{"Name"}=~s/<(.+)\Z//g; # GCC 3.4.4 add template params to the name
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04003535 if(isAnon($TypeAttr{"Name"}))
3536 {
3537 my $NameSpaceId = $TypeId;
Andrey Ponomarenko01117f12012-06-26 12:23:02 +04003538 while(my $NSId = getTreeAttr_Scpe(getTypeDeclId($NameSpaceId)))
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04003539 { # searching for a first not anon scope
3540 if($NSId eq $NameSpaceId) {
3541 last;
3542 }
3543 else
3544 {
3545 $TypeAttr{"NameSpace"} = getNameSpace(getTypeDeclId($TypeId));
3546 if(not $TypeAttr{"NameSpace"}
3547 or isNotAnon($TypeAttr{"NameSpace"})) {
3548 last;
3549 }
3550 }
3551 $NameSpaceId=$NSId;
3552 }
3553 }
3554 else
3555 {
Andrey Ponomarenko01117f12012-06-26 12:23:02 +04003556 if(my $NameSpaceId = getTreeAttr_Scpe($TypeInfoId))
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04003557 {
3558 if($NameSpaceId ne $TypeId) {
3559 $TypeAttr{"NameSpace"} = getNameSpace($TypeInfoId);
3560 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003561 }
3562 }
3563 if($TypeAttr{"NameSpace"} and isNotAnon($TypeAttr{"Name"})) {
3564 $TypeAttr{"Name"} = $TypeAttr{"NameSpace"}."::".$TypeAttr{"Name"};
3565 }
Andrey Ponomarenko9927e332012-10-19 10:50:48 +04003566 $TypeAttr{"Name"} = formatName($TypeAttr{"Name"}, "T");
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003567 if(isAnon($TypeAttr{"Name"}))
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04003568 { # anon-struct-header.h-line
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04003569 $TypeAttr{"Name"} = "anon-".lc($TypeAttr{"Type"})."-";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003570 $TypeAttr{"Name"} .= $TypeAttr{"Header"}."-".$TypeAttr{"Line"};
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04003571 if($TypeAttr{"NameSpace"}) {
3572 $TypeAttr{"Name"} = $TypeAttr{"NameSpace"}."::".$TypeAttr{"Name"};
3573 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003574 }
Andrey Ponomarenkob8d203d2012-05-25 18:11:07 +04003575 if(defined $TemplateInstance{$Version}{"Type"}{$TypeId}
3576 and getTypeDeclId($TypeId) eq $TypeInfoId)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003577 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04003578 my @TParams = getTParams($TypeId, "Type");
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003579 if(not @TParams)
3580 { # template declarations with abstract params
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003581 return ("", "");
3582 }
Andrey Ponomarenko9927e332012-10-19 10:50:48 +04003583 $TypeAttr{"Name"} = formatName($TypeAttr{"Name"}."< ".join(", ", @TParams)." >", "T");
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003584 }
3585 return ($TypeAttr{"Name"}, $TypeAttr{"NameSpace"});
3586}
3587
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04003588sub getTrivialTypeAttr($)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003589{
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04003590 my $TypeId = $_[0];
3591 my $TypeInfoId = getTypeDeclId($_[0]);
Andrey Ponomarenko85043792012-05-14 16:48:07 +04003592
3593 if($TemplateDecl{$Version}{$TypeId})
3594 { # template_decl
3595 return ();
3596 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04003597 if(my $ScopeId = getTreeAttr_Scpe($TypeInfoId))
3598 {
3599 if($TemplateDecl{$Version}{$ScopeId})
3600 { # template_decl
3601 return ();
3602 }
3603 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +04003604
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003605 my %TypeAttr = ();
3606 if(getTypeTypeByTypeId($TypeId)!~/\A(Intrinsic|Union|Struct|Enum|Class)\Z/) {
3607 return ();
3608 }
3609 setTypeAccess($TypeId, \%TypeAttr);
3610 ($TypeAttr{"Header"}, $TypeAttr{"Line"}) = getLocation($TypeInfoId);
3611 if(isBuiltIn($TypeAttr{"Header"}))
3612 {
3613 delete($TypeAttr{"Header"});
3614 delete($TypeAttr{"Line"});
3615 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04003616 $TypeAttr{"Type"} = getTypeType($TypeId);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003617 ($TypeAttr{"Name"}, $TypeAttr{"NameSpace"}) = getTrivialName($TypeInfoId, $TypeId);
3618 if(not $TypeAttr{"Name"}) {
3619 return ();
3620 }
3621 if(not $TypeAttr{"NameSpace"}) {
3622 delete($TypeAttr{"NameSpace"});
3623 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04003624 if(defined $TemplateInstance{$Version}{"Type"}{$TypeId})
Andrey Ponomarenko16934472012-03-29 15:37:04 +04003625 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04003626 if(my @TParams = getTParams($TypeId, "Type"))
Andrey Ponomarenko16934472012-03-29 15:37:04 +04003627 {
3628 foreach my $Pos (0 .. $#TParams) {
3629 $TypeAttr{"TParam"}{$Pos}{"name"}=$TParams[$Pos];
3630 }
3631 }
3632 }
Andrey Ponomarenko01117f12012-06-26 12:23:02 +04003633 if(my $Size = getSize($TypeId))
3634 {
3635 $Size = $Size/$BYTE_SIZE;
3636 $TypeAttr{"Size"} = "$Size";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003637 }
Andrey Ponomarenko9927e332012-10-19 10:50:48 +04003638 else
3639 { # declaration only
3640 $TypeAttr{"Forward"} = 1;
3641 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003642 if($TypeAttr{"Type"} eq "Struct"
3643 and detect_lang($TypeId))
3644 {
3645 $TypeAttr{"Type"} = "Class";
Andrey Ponomarenko85043792012-05-14 16:48:07 +04003646 $TypeAttr{"Copied"} = 1; # default, will be changed in getSymbolInfo()
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003647 }
3648 if($TypeAttr{"Type"} eq "Struct"
Andrey Ponomarenko85043792012-05-14 16:48:07 +04003649 or $TypeAttr{"Type"} eq "Class")
3650 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04003651 my $Skip = setBaseClasses($TypeId, \%TypeAttr);
Andrey Ponomarenko85043792012-05-14 16:48:07 +04003652 if($Skip) {
3653 return ();
3654 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003655 }
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +04003656 if(my $Algn = getAlgn($TypeId)) {
3657 $TypeAttr{"Algn"} = $Algn/$BYTE_SIZE;
3658 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003659 setSpec($TypeId, \%TypeAttr);
3660 setTypeMemb($TypeId, \%TypeAttr);
3661 $TypeAttr{"Tid"} = $TypeId;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003662 if(my $VTable = $ClassVTable_Content{$Version}{$TypeAttr{"Name"}})
3663 {
3664 my @Entries = split(/\n/, $VTable);
3665 foreach (1 .. $#Entries)
3666 {
3667 my $Entry = $Entries[$_];
3668 if($Entry=~/\A(\d+)\s+(.+)\Z/) {
3669 $TypeAttr{"VTable"}{$1} = $2;
3670 }
3671 }
3672 }
3673 return %TypeAttr;
3674}
3675
3676sub detect_lang($)
3677{
3678 my $TypeId = $_[0];
3679 my $Info = $LibInfo{$Version}{"info"}{$TypeId};
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04003680 if(check_gcc($GCC_PATH, "4"))
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04003681 { # GCC 4 fncs-node points to only non-artificial methods
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003682 return ($Info=~/(fncs)[ ]*:[ ]*@(\d+) /);
3683 }
3684 else
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04003685 { # GCC 3
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04003686 my $Fncs = getTreeAttr_Fncs($TypeId);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003687 while($Fncs)
3688 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04003689 if($LibInfo{$Version}{"info"}{$Fncs}!~/artificial/) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003690 return 1;
3691 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04003692 $Fncs = getTreeAttr_Chan($Fncs);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003693 }
3694 }
3695 return 0;
3696}
3697
3698sub setSpec($$)
3699{
3700 my ($TypeId, $TypeAttr) = @_;
3701 my $Info = $LibInfo{$Version}{"info"}{$TypeId};
3702 if($Info=~/\s+spec\s+/) {
3703 $TypeAttr->{"Spec"} = 1;
3704 }
3705}
3706
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04003707sub setBaseClasses($$)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003708{
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04003709 my ($TypeId, $TypeAttr) = @_;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003710 my $Info = $LibInfo{$Version}{"info"}{$TypeId};
3711 if($Info=~/binf[ ]*:[ ]*@(\d+) /)
3712 {
3713 $Info = $LibInfo{$Version}{"info"}{$1};
3714 my $Pos = 0;
3715 while($Info=~s/(pub|public|prot|protected|priv|private|)[ ]+binf[ ]*:[ ]*@(\d+) //)
3716 {
3717 my ($Access, $BInfoId) = ($1, $2);
3718 my $ClassId = getBinfClassId($BInfoId);
Andrey Ponomarenko85043792012-05-14 16:48:07 +04003719 my $CType = $LibInfo{$Version}{"info_type"}{$ClassId};
3720 if(not $CType or $CType eq "template_type_parm"
3721 or $CType eq "typename_type")
3722 { # skip
3723 return 1;
3724 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003725 my $BaseInfo = $LibInfo{$Version}{"info"}{$BInfoId};
3726 if($Access=~/prot/)
3727 {
3728 $TypeAttr->{"Base"}{$ClassId}{"access"} = "protected";
3729 }
3730 elsif($Access=~/priv/)
3731 {
3732 $TypeAttr->{"Base"}{$ClassId}{"access"} = "private";
3733 }
Andrey Ponomarenko01117f12012-06-26 12:23:02 +04003734 $TypeAttr->{"Base"}{$ClassId}{"pos"} = "$Pos";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003735 if($BaseInfo=~/virt/)
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04003736 { # virtual base
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003737 $TypeAttr->{"Base"}{$ClassId}{"virtual"} = 1;
3738 }
3739 $Class_SubClasses{$Version}{$ClassId}{$TypeId}=1;
Andrey Ponomarenko01117f12012-06-26 12:23:02 +04003740 $Pos+=1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003741 }
3742 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +04003743 return 0;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003744}
3745
3746sub getBinfClassId($)
3747{
3748 my $Info = $LibInfo{$Version}{"info"}{$_[0]};
3749 $Info=~/type[ ]*:[ ]*@(\d+) /;
3750 return $1;
3751}
3752
3753sub unmangledFormat($$)
3754{
3755 my ($Name, $LibVersion) = @_;
3756 $Name = uncover_typedefs($Name, $LibVersion);
3757 while($Name=~s/([^\w>*])(const|volatile)(,|>|\Z)/$1$3/g){};
3758 $Name=~s/\(\w+\)(\d)/$1/;
3759 return $Name;
3760}
3761
3762sub modelUnmangled($$)
3763{
3764 my ($InfoId, $Compiler) = @_;
3765 if($Cache{"modelUnmangled"}{$Version}{$Compiler}{$InfoId}) {
3766 return $Cache{"modelUnmangled"}{$Version}{$Compiler}{$InfoId};
3767 }
3768 my $PureSignature = $SymbolInfo{$Version}{$InfoId}{"ShortName"};
3769 if($SymbolInfo{$Version}{$InfoId}{"Destructor"}) {
3770 $PureSignature = "~".$PureSignature;
3771 }
3772 if(not $SymbolInfo{$Version}{$InfoId}{"Data"})
3773 {
3774 my (@Params, @ParamTypes) = ();
3775 if(defined $SymbolInfo{$Version}{$InfoId}{"Param"}
3776 and not $SymbolInfo{$Version}{$InfoId}{"Destructor"}) {
3777 @Params = keys(%{$SymbolInfo{$Version}{$InfoId}{"Param"}});
3778 }
3779 foreach my $ParamPos (sort {int($a) <=> int($b)} @Params)
3780 { # checking parameters
3781 my $PId = $SymbolInfo{$Version}{$InfoId}{"Param"}{$ParamPos}{"type"};
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +04003782 my %PType = get_PureType($PId, $TypeInfo{$Version});
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003783 my $PTName = unmangledFormat($PType{"Name"}, $Version);
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04003784 $PTName=~s/\b(restrict|register)\b//g;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003785 if($Compiler eq "MSVC") {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04003786 $PTName=~s/\blong long\b/__int64/;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003787 }
3788 @ParamTypes = (@ParamTypes, $PTName);
3789 }
3790 if(@ParamTypes) {
3791 $PureSignature .= "(".join(", ", @ParamTypes).")";
3792 }
3793 else
3794 {
3795 if($Compiler eq "MSVC")
3796 {
3797 $PureSignature .= "(void)";
3798 }
3799 else
3800 { # GCC
3801 $PureSignature .= "()";
3802 }
3803 }
3804 $PureSignature = delete_keywords($PureSignature);
3805 }
3806 if(my $ClassId = $SymbolInfo{$Version}{$InfoId}{"Class"})
3807 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04003808 my $ClassName = unmangledFormat($TypeInfo{$Version}{$ClassId}{"Name"}, $Version);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003809 $PureSignature = $ClassName."::".$PureSignature;
3810 }
3811 elsif(my $NS = $SymbolInfo{$Version}{$InfoId}{"NameSpace"}) {
3812 $PureSignature = $NS."::".$PureSignature;
3813 }
3814 if($SymbolInfo{$Version}{$InfoId}{"Const"}) {
3815 $PureSignature .= " const";
3816 }
3817 if($SymbolInfo{$Version}{$InfoId}{"Volatile"}) {
3818 $PureSignature .= " volatile";
3819 }
3820 my $ShowReturn = 0;
3821 if($Compiler eq "MSVC"
3822 and $SymbolInfo{$Version}{$InfoId}{"Data"})
3823 {
3824 $ShowReturn=1;
3825 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04003826 elsif(defined $TemplateInstance{$Version}{"Func"}{$InfoId}
3827 and keys(%{$TemplateInstance{$Version}{"Func"}{$InfoId}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003828 {
3829 $ShowReturn=1;
3830 }
3831 if($ShowReturn)
3832 { # mangled names for template function specializations include return value
3833 if(my $ReturnId = $SymbolInfo{$Version}{$InfoId}{"Return"})
3834 {
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +04003835 my %RType = get_PureType($ReturnId, $TypeInfo{$Version});
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003836 my $ReturnName = unmangledFormat($RType{"Name"}, $Version);
3837 $PureSignature = $ReturnName." ".$PureSignature;
3838 }
3839 }
Andrey Ponomarenko9927e332012-10-19 10:50:48 +04003840 return ($Cache{"modelUnmangled"}{$Version}{$Compiler}{$InfoId} = formatName($PureSignature, "S"));
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003841}
3842
3843sub mangle_symbol($$$)
3844{ # mangling for simple methods
3845 # see gcc-4.6.0/gcc/cp/mangle.c
3846 my ($InfoId, $LibVersion, $Compiler) = @_;
3847 if($Cache{"mangle_symbol"}{$LibVersion}{$InfoId}{$Compiler}) {
3848 return $Cache{"mangle_symbol"}{$LibVersion}{$InfoId}{$Compiler};
3849 }
3850 my $Mangled = "";
3851 if($Compiler eq "GCC") {
Andrey Ponomarenko16934472012-03-29 15:37:04 +04003852 $Mangled = mangle_symbol_GCC($InfoId, $LibVersion);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003853 }
3854 elsif($Compiler eq "MSVC") {
Andrey Ponomarenko16934472012-03-29 15:37:04 +04003855 $Mangled = mangle_symbol_MSVC($InfoId, $LibVersion);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003856 }
3857 return ($Cache{"mangle_symbol"}{$LibVersion}{$InfoId}{$Compiler} = $Mangled);
3858}
3859
Andrey Ponomarenko16934472012-03-29 15:37:04 +04003860sub mangle_symbol_MSVC($$)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003861{
3862 my ($InfoId, $LibVersion) = @_;
3863 return "";
3864}
3865
Andrey Ponomarenko16934472012-03-29 15:37:04 +04003866sub mangle_symbol_GCC($$)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003867{ # see gcc-4.6.0/gcc/cp/mangle.c
3868 my ($InfoId, $LibVersion) = @_;
3869 my ($Mangled, $ClassId, $NameSpace) = ("_Z", 0, "");
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04003870 my $Return = $SymbolInfo{$LibVersion}{$InfoId}{"Return"};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003871 my %Repl = ();# SN_ replacements
3872 if($ClassId = $SymbolInfo{$LibVersion}{$InfoId}{"Class"})
3873 {
3874 my $MangledClass = mangle_param($ClassId, $LibVersion, \%Repl);
3875 if($MangledClass!~/\AN/) {
3876 $MangledClass = "N".$MangledClass;
3877 }
3878 else {
3879 $MangledClass=~s/E\Z//;
3880 }
3881 if($SymbolInfo{$LibVersion}{$InfoId}{"Volatile"}) {
3882 $MangledClass=~s/\AN/NV/;
3883 }
3884 if($SymbolInfo{$LibVersion}{$InfoId}{"Const"}) {
3885 $MangledClass=~s/\AN/NK/;
3886 }
3887 $Mangled .= $MangledClass;
3888 }
3889 elsif($NameSpace = $SymbolInfo{$LibVersion}{$InfoId}{"NameSpace"})
3890 { # mangled by name due to the absence of structured info
3891 my $MangledNS = mangle_ns($NameSpace, $LibVersion, \%Repl);
3892 if($MangledNS!~/\AN/) {
3893 $MangledNS = "N".$MangledNS;
3894 }
3895 else {
3896 $MangledNS=~s/E\Z//;
3897 }
3898 $Mangled .= $MangledNS;
3899 }
Andrey Ponomarenko07aea072012-11-12 16:15:07 +04003900 my ($ShortName, $TmplParams) = template_Base($SymbolInfo{$LibVersion}{$InfoId}{"ShortName"});
Andrey Ponomarenko16934472012-03-29 15:37:04 +04003901 my @TParams = ();
Andrey Ponomarenko35c44fd2012-06-18 17:50:25 +04003902 if(my @TPos = keys(%{$SymbolInfo{$LibVersion}{$InfoId}{"TParam"}}))
Andrey Ponomarenko16934472012-03-29 15:37:04 +04003903 { # parsing mode
Andrey Ponomarenko35c44fd2012-06-18 17:50:25 +04003904 foreach (@TPos) {
3905 push(@TParams, $SymbolInfo{$LibVersion}{$InfoId}{"TParam"}{$_}{"name"});
3906 }
Andrey Ponomarenko16934472012-03-29 15:37:04 +04003907 }
3908 elsif($TmplParams)
3909 { # remangling mode
3910 # support for old ABI dumps
Andrey Ponomarenko07aea072012-11-12 16:15:07 +04003911 @TParams = separate_Params($TmplParams, 0, 0);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003912 }
3913 if($SymbolInfo{$LibVersion}{$InfoId}{"Constructor"}) {
3914 $Mangled .= "C1";
3915 }
3916 elsif($SymbolInfo{$LibVersion}{$InfoId}{"Destructor"}) {
3917 $Mangled .= "D0";
3918 }
3919 elsif($ShortName)
3920 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04003921 if($SymbolInfo{$LibVersion}{$InfoId}{"Data"})
3922 {
Andrey Ponomarenko16934472012-03-29 15:37:04 +04003923 if(not $SymbolInfo{$LibVersion}{$InfoId}{"Class"}
Andrey Ponomarenko85043792012-05-14 16:48:07 +04003924 and isConstType($Return, $LibVersion))
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04003925 { # "const" global data is mangled as _ZL...
3926 $Mangled .= "L";
3927 }
3928 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003929 if($ShortName=~/\Aoperator(\W.*)\Z/)
3930 {
3931 my $Op = $1;
3932 $Op=~s/\A[ ]+//g;
3933 if(my $OpMngl = $OperatorMangling{$Op}) {
3934 $Mangled .= $OpMngl;
3935 }
3936 else { # conversion operator
3937 $Mangled .= "cv".mangle_param(getTypeIdByName($Op, $LibVersion), $LibVersion, \%Repl);
3938 }
3939 }
3940 else {
3941 $Mangled .= length($ShortName).$ShortName;
3942 }
3943 if(@TParams)
3944 { # templates
3945 $Mangled .= "I";
Andrey Ponomarenko1477d2c2012-11-12 18:55:45 +04003946 foreach my $TParam (@TParams) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003947 $Mangled .= mangle_template_param($TParam, $LibVersion, \%Repl);
3948 }
3949 $Mangled .= "E";
3950 }
3951 if(not $ClassId and @TParams) {
3952 add_substitution($ShortName, \%Repl, 0);
3953 }
3954 }
3955 if($ClassId or $NameSpace) {
3956 $Mangled .= "E";
3957 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +04003958 if(@TParams)
3959 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04003960 if($Return) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003961 $Mangled .= mangle_param($Return, $LibVersion, \%Repl);
3962 }
3963 }
3964 if(not $SymbolInfo{$LibVersion}{$InfoId}{"Data"})
3965 {
3966 my @Params = ();
3967 if(defined $SymbolInfo{$LibVersion}{$InfoId}{"Param"}
3968 and not $SymbolInfo{$LibVersion}{$InfoId}{"Destructor"}) {
3969 @Params = keys(%{$SymbolInfo{$LibVersion}{$InfoId}{"Param"}});
3970 }
3971 foreach my $ParamPos (sort {int($a) <=> int($b)} @Params)
3972 { # checking parameters
3973 my $ParamType_Id = $SymbolInfo{$LibVersion}{$InfoId}{"Param"}{$ParamPos}{"type"};
3974 $Mangled .= mangle_param($ParamType_Id, $LibVersion, \%Repl);
3975 }
3976 if(not @Params) {
3977 $Mangled .= "v";
3978 }
3979 }
3980 $Mangled = correct_incharge($InfoId, $LibVersion, $Mangled);
3981 $Mangled = write_stdcxx_substitution($Mangled);
3982 if($Mangled eq "_Z") {
3983 return "";
3984 }
3985 return $Mangled;
3986}
3987
3988sub correct_incharge($$$)
3989{
3990 my ($InfoId, $LibVersion, $Mangled) = @_;
3991 if($SymbolInfo{$LibVersion}{$InfoId}{"Constructor"})
3992 {
3993 if($MangledNames{$LibVersion}{$Mangled}) {
3994 $Mangled=~s/C1E/C2E/;
3995 }
3996 }
3997 elsif($SymbolInfo{$LibVersion}{$InfoId}{"Destructor"})
3998 {
3999 if($MangledNames{$LibVersion}{$Mangled}) {
4000 $Mangled=~s/D0E/D1E/;
4001 }
4002 if($MangledNames{$LibVersion}{$Mangled}) {
4003 $Mangled=~s/D1E/D2E/;
4004 }
4005 }
4006 return $Mangled;
4007}
4008
Andrey Ponomarenko07aea072012-11-12 16:15:07 +04004009sub template_Base($)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004010{ # NOTE: std::_Vector_base<mysqlpp::mysql_type_info>::_Vector_impl
Andrey Ponomarenko16934472012-03-29 15:37:04 +04004011 # NOTE: operators: >>, <<
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004012 my $Name = $_[0];
Andrey Ponomarenko16934472012-03-29 15:37:04 +04004013 if($Name!~/>\Z/ or $Name!~/</) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004014 return $Name;
4015 }
4016 my $TParams = $Name;
Andrey Ponomarenko16934472012-03-29 15:37:04 +04004017 while(my $CPos = find_center($TParams, "<"))
4018 { # search for the last <T>
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004019 $TParams = substr($TParams, $CPos);
4020 }
Andrey Ponomarenko16934472012-03-29 15:37:04 +04004021 if($TParams=~s/\A<(.+)>\Z/$1/) {
4022 $Name=~s/<\Q$TParams\E>\Z//;
4023 }
4024 else
4025 { # error
4026 $TParams = "";
4027 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004028 return ($Name, $TParams);
4029}
4030
4031sub get_sub_ns($)
4032{
4033 my $Name = $_[0];
4034 my @NS = ();
Andrey Ponomarenko16934472012-03-29 15:37:04 +04004035 while(my $CPos = find_center($Name, ":"))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004036 {
4037 push(@NS, substr($Name, 0, $CPos));
4038 $Name = substr($Name, $CPos);
4039 $Name=~s/\A:://;
4040 }
4041 return (join("::", @NS), $Name);
4042}
4043
4044sub mangle_ns($$$)
4045{
4046 my ($Name, $LibVersion, $Repl) = @_;
4047 if(my $Tid = $TName_Tid{$LibVersion}{$Name})
4048 {
4049 my $Mangled = mangle_param($Tid, $LibVersion, $Repl);
4050 $Mangled=~s/\AN(.+)E\Z/$1/;
4051 return $Mangled;
4052
4053 }
4054 else
4055 {
4056 my ($MangledNS, $SubNS) = ("", "");
4057 ($SubNS, $Name) = get_sub_ns($Name);
4058 if($SubNS) {
4059 $MangledNS .= mangle_ns($SubNS, $LibVersion, $Repl);
4060 }
4061 $MangledNS .= length($Name).$Name;
4062 add_substitution($MangledNS, $Repl, 0);
4063 return $MangledNS;
4064 }
4065}
4066
4067sub mangle_param($$$)
4068{
4069 my ($PTid, $LibVersion, $Repl) = @_;
4070 my ($MPrefix, $Mangled) = ("", "");
4071 my %ReplCopy = %{$Repl};
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04004072 my %BaseType = get_BaseType($PTid, $LibVersion);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004073 my $BaseType_Name = $BaseType{"Name"};
4074 if(not $BaseType_Name) {
4075 return "";
4076 }
Andrey Ponomarenko07aea072012-11-12 16:15:07 +04004077 my ($ShortName, $TmplParams) = template_Base($BaseType_Name);
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04004078 my $Suffix = get_BaseTypeQual($PTid, $LibVersion);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004079 while($Suffix=~s/\s*(const|volatile|restrict)\Z//g){};
4080 while($Suffix=~/(&|\*|const)\Z/)
4081 {
4082 if($Suffix=~s/[ ]*&\Z//) {
4083 $MPrefix .= "R";
4084 }
4085 if($Suffix=~s/[ ]*\*\Z//) {
4086 $MPrefix .= "P";
4087 }
4088 if($Suffix=~s/[ ]*const\Z//)
4089 {
4090 if($MPrefix=~/R|P/
4091 or $Suffix=~/&|\*/) {
4092 $MPrefix .= "K";
4093 }
4094 }
4095 if($Suffix=~s/[ ]*volatile\Z//) {
4096 $MPrefix .= "V";
4097 }
4098 #if($Suffix=~s/[ ]*restrict\Z//) {
4099 #$MPrefix .= "r";
4100 #}
4101 }
4102 if(my $Token = $IntrinsicMangling{$BaseType_Name}) {
4103 $Mangled .= $Token;
4104 }
4105 elsif($BaseType{"Type"}=~/(Class|Struct|Union|Enum)/)
4106 {
Andrey Ponomarenko16934472012-03-29 15:37:04 +04004107 my @TParams = ();
Andrey Ponomarenko35c44fd2012-06-18 17:50:25 +04004108 if(my @TPos = keys(%{$BaseType{"TParam"}}))
Andrey Ponomarenko16934472012-03-29 15:37:04 +04004109 { # parsing mode
Andrey Ponomarenko35c44fd2012-06-18 17:50:25 +04004110 foreach (@TPos) {
4111 push(@TParams, $BaseType{"TParam"}{$_}{"name"});
4112 }
Andrey Ponomarenko16934472012-03-29 15:37:04 +04004113 }
4114 elsif($TmplParams)
4115 { # remangling mode
4116 # support for old ABI dumps
Andrey Ponomarenko07aea072012-11-12 16:15:07 +04004117 @TParams = separate_Params($TmplParams, 0, 0);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004118 }
4119 my $MangledNS = "";
4120 my ($SubNS, $SName) = get_sub_ns($ShortName);
4121 if($SubNS) {
4122 $MangledNS .= mangle_ns($SubNS, $LibVersion, $Repl);
4123 }
4124 $MangledNS .= length($SName).$SName;
4125 if(@TParams) {
4126 add_substitution($MangledNS, $Repl, 0);
4127 }
4128 $Mangled .= "N".$MangledNS;
4129 if(@TParams)
4130 { # templates
4131 $Mangled .= "I";
4132 foreach my $TParam (@TParams) {
4133 $Mangled .= mangle_template_param($TParam, $LibVersion, $Repl);
4134 }
4135 $Mangled .= "E";
4136 }
4137 $Mangled .= "E";
4138 }
4139 elsif($BaseType{"Type"}=~/(FuncPtr|MethodPtr)/)
4140 {
4141 if($BaseType{"Type"} eq "MethodPtr") {
4142 $Mangled .= "M".mangle_param($BaseType{"Class"}, $LibVersion, $Repl)."F";
4143 }
4144 else {
4145 $Mangled .= "PF";
4146 }
4147 $Mangled .= mangle_param($BaseType{"Return"}, $LibVersion, $Repl);
4148 my @Params = keys(%{$BaseType{"Param"}});
4149 foreach my $Num (sort {int($a)<=>int($b)} @Params) {
4150 $Mangled .= mangle_param($BaseType{"Param"}{$Num}{"type"}, $LibVersion, $Repl);
4151 }
4152 if(not @Params) {
4153 $Mangled .= "v";
4154 }
4155 $Mangled .= "E";
4156 }
4157 elsif($BaseType{"Type"} eq "FieldPtr")
4158 {
4159 $Mangled .= "M".mangle_param($BaseType{"Class"}, $LibVersion, $Repl);
4160 $Mangled .= mangle_param($BaseType{"Return"}, $LibVersion, $Repl);
4161 }
4162 $Mangled = $MPrefix.$Mangled;# add prefix (RPK)
4163 if(my $Optimized = write_substitution($Mangled, \%ReplCopy))
4164 {
4165 if($Mangled eq $Optimized)
4166 {
4167 if($ShortName!~/::/)
4168 { # remove "N ... E"
4169 if($MPrefix) {
4170 $Mangled=~s/\A($MPrefix)N(.+)E\Z/$1$2/g;
4171 }
4172 else {
4173 $Mangled=~s/\AN(.+)E\Z/$1/g;
4174 }
4175 }
4176 }
4177 else {
4178 $Mangled = $Optimized;
4179 }
4180 }
4181 add_substitution($Mangled, $Repl, 1);
4182 return $Mangled;
4183}
4184
4185sub mangle_template_param($$$)
4186{ # types + literals
4187 my ($TParam, $LibVersion, $Repl) = @_;
4188 if(my $TPTid = $TName_Tid{$LibVersion}{$TParam}) {
4189 return mangle_param($TPTid, $LibVersion, $Repl);
4190 }
4191 elsif($TParam=~/\A(\d+)(\w+)\Z/)
4192 { # class_name<1u>::method(...)
4193 return "L".$IntrinsicMangling{$ConstantSuffixR{$2}}.$1."E";
4194 }
4195 elsif($TParam=~/\A\(([\w ]+)\)(\d+)\Z/)
4196 { # class_name<(signed char)1>::method(...)
4197 return "L".$IntrinsicMangling{$1}.$2."E";
4198 }
4199 elsif($TParam eq "true")
4200 { # class_name<true>::method(...)
4201 return "Lb1E";
4202 }
4203 elsif($TParam eq "false")
4204 { # class_name<true>::method(...)
4205 return "Lb0E";
4206 }
4207 else { # internal error
4208 return length($TParam).$TParam;
4209 }
4210}
4211
4212sub add_substitution($$$)
4213{
4214 my ($Value, $Repl, $Rec) = @_;
4215 if($Rec)
4216 { # subtypes
4217 my @Subs = ($Value);
4218 while($Value=~s/\A(R|P|K)//) {
4219 push(@Subs, $Value);
4220 }
4221 foreach (reverse(@Subs)) {
4222 add_substitution($_, $Repl, 0);
4223 }
4224 return;
4225 }
4226 return if($Value=~/\AS(\d*)_\Z/);
4227 $Value=~s/\AN(.+)E\Z/$1/g;
4228 return if(defined $Repl->{$Value});
4229 return if(length($Value)<=1);
4230 return if($StdcxxMangling{$Value});
4231 # check for duplicates
4232 my $Base = $Value;
4233 foreach my $Type (sort {$Repl->{$a}<=>$Repl->{$b}} sort keys(%{$Repl}))
4234 {
4235 my $Num = $Repl->{$Type};
4236 my $Replace = macro_mangle($Num);
4237 $Base=~s/\Q$Replace\E/$Type/;
4238 }
4239 if(my $OldNum = $Repl->{$Base})
4240 {
4241 $Repl->{$Value} = $OldNum;
4242 return;
4243 }
4244 my @Repls = sort {$b<=>$a} values(%{$Repl});
4245 if(@Repls) {
4246 $Repl->{$Value} = $Repls[0]+1;
4247 }
4248 else {
4249 $Repl->{$Value} = -1;
4250 }
4251 # register duplicates
4252 # upward
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04004253 $Base = $Value;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004254 foreach my $Type (sort {$Repl->{$a}<=>$Repl->{$b}} sort keys(%{$Repl}))
4255 {
4256 next if($Base eq $Type);
4257 my $Num = $Repl->{$Type};
4258 my $Replace = macro_mangle($Num);
4259 $Base=~s/\Q$Type\E/$Replace/;
4260 $Repl->{$Base} = $Repl->{$Value};
4261 }
4262}
4263
4264sub macro_mangle($)
4265{
4266 my $Num = $_[0];
4267 if($Num==-1) {
4268 return "S_";
4269 }
4270 else
4271 {
4272 my $Code = "";
4273 if($Num<10)
4274 { # S0_, S1_, S2_, ...
4275 $Code = $Num;
4276 }
4277 elsif($Num>=10 and $Num<=35)
4278 { # SA_, SB_, SC_, ...
4279 $Code = chr(55+$Num);
4280 }
4281 else
4282 { # S10_, S11_, S12_
4283 $Code = $Num-26; # 26 is length of english alphabet
4284 }
4285 return "S".$Code."_";
4286 }
4287}
4288
4289sub write_stdcxx_substitution($)
4290{
4291 my $Mangled = $_[0];
4292 if($StdcxxMangling{$Mangled}) {
4293 return $StdcxxMangling{$Mangled};
4294 }
4295 else
4296 {
4297 my @Repls = keys(%StdcxxMangling);
4298 @Repls = sort {length($b)<=>length($a)} sort {$b cmp $a} @Repls;
4299 foreach my $MangledType (@Repls)
4300 {
4301 my $Replace = $StdcxxMangling{$MangledType};
4302 #if($Mangled!~/$Replace/) {
4303 $Mangled=~s/N\Q$MangledType\EE/$Replace/g;
4304 $Mangled=~s/\Q$MangledType\E/$Replace/g;
4305 #}
4306 }
4307 }
4308 return $Mangled;
4309}
4310
4311sub write_substitution($$)
4312{
4313 my ($Mangled, $Repl) = @_;
4314 if(defined $Repl->{$Mangled}
4315 and my $MnglNum = $Repl->{$Mangled}) {
4316 $Mangled = macro_mangle($MnglNum);
4317 }
4318 else
4319 {
4320 my @Repls = keys(%{$Repl});
4321 #@Repls = sort {$Repl->{$a}<=>$Repl->{$b}} @Repls;
4322 # FIXME: how to apply replacements? by num or by pos
4323 @Repls = sort {length($b)<=>length($a)} sort {$b cmp $a} @Repls;
4324 foreach my $MangledType (@Repls)
4325 {
4326 my $Replace = macro_mangle($Repl->{$MangledType});
4327 if($Mangled!~/$Replace/) {
4328 $Mangled=~s/N\Q$MangledType\EE/$Replace/g;
4329 $Mangled=~s/\Q$MangledType\E/$Replace/g;
4330 }
4331 }
4332 }
4333 return $Mangled;
4334}
4335
4336sub delete_keywords($)
4337{
4338 my $TypeName = $_[0];
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04004339 $TypeName=~s/\b(enum|struct|union|class) //g;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004340 return $TypeName;
4341}
4342
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004343sub uncover_typedefs($$)
4344{
4345 my ($TypeName, $LibVersion) = @_;
4346 return "" if(not $TypeName);
4347 if(defined $Cache{"uncover_typedefs"}{$LibVersion}{$TypeName}) {
4348 return $Cache{"uncover_typedefs"}{$LibVersion}{$TypeName};
4349 }
Andrey Ponomarenko9927e332012-10-19 10:50:48 +04004350 my ($TypeName_New, $TypeName_Pre) = (formatName($TypeName, "T"), "");
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004351 while($TypeName_New ne $TypeName_Pre)
4352 {
4353 $TypeName_Pre = $TypeName_New;
4354 my $TypeName_Copy = $TypeName_New;
4355 my %Words = ();
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04004356 while($TypeName_Copy=~s/\b([a-z_]([\w:]*\w|))\b//io)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004357 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04004358 if(not $Intrinsic_Keywords{$1}) {
4359 $Words{$1} = 1;
4360 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004361 }
4362 foreach my $Word (keys(%Words))
4363 {
4364 my $BaseType_Name = $Typedef_BaseName{$LibVersion}{$Word};
4365 next if(not $BaseType_Name);
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04004366 next if($TypeName_New=~/\b(struct|union|enum)\s\Q$Word\E\b/);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004367 if($BaseType_Name=~/\([\*]+\)/)
4368 { # FuncPtr
4369 if($TypeName_New=~/\Q$Word\E(.*)\Z/)
4370 {
4371 my $Type_Suffix = $1;
4372 $TypeName_New = $BaseType_Name;
4373 if($TypeName_New=~s/\(([\*]+)\)/($1 $Type_Suffix)/) {
Andrey Ponomarenko9927e332012-10-19 10:50:48 +04004374 $TypeName_New = formatName($TypeName_New, "T");
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004375 }
4376 }
4377 }
4378 else
4379 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04004380 if($TypeName_New=~s/\b\Q$Word\E\b/$BaseType_Name/g) {
Andrey Ponomarenko9927e332012-10-19 10:50:48 +04004381 $TypeName_New = formatName($TypeName_New, "T");
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004382 }
4383 }
4384 }
4385 }
4386 return ($Cache{"uncover_typedefs"}{$LibVersion}{$TypeName} = $TypeName_New);
4387}
4388
4389sub isInternal($)
4390{
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04004391 if($_[0] and my $Info = $LibInfo{$Version}{"info"}{$_[0]})
4392 {
4393 if($Info=~/mngl[ ]*:[ ]*@(\d+) /)
4394 {
4395 if($LibInfo{$Version}{"info"}{$1}=~/\*[ ]*INTERNAL[ ]*\*/)
4396 { # _ZN7mysqlpp8DateTimeC1ERKS0_ *INTERNAL*
4397 return 1;
4398 }
4399 }
4400 }
4401 return 0;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004402}
4403
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04004404sub getDataVal($$)
4405{
4406 my ($InfoId, $TypeId) = @_;
4407 if(my $Info = $LibInfo{$Version}{"info"}{$InfoId})
4408 {
4409 if($Info=~/init[ ]*:[ ]*@(\d+) /)
4410 {
4411 if(defined $LibInfo{$Version}{"info_type"}{$1}
4412 and $LibInfo{$Version}{"info_type"}{$1} eq "nop_expr")
4413 { # char const* data = "str"
4414 # NOTE: disabled
4415 if(my $NopExpr = $LibInfo{$Version}{"info"}{$1})
4416 {
4417 if($NopExpr=~/op 0[ ]*:[ ]*@(\d+) /)
4418 {
4419 if(defined $LibInfo{$Version}{"info_type"}{$1}
4420 and $LibInfo{$Version}{"info_type"}{$1} eq "addr_expr")
4421 {
4422 if(my $AddrExpr = $LibInfo{$Version}{"info"}{$1})
4423 {
4424 if($AddrExpr=~/op 0[ ]*:[ ]*@(\d+) /)
4425 {
4426 return getInitVal($1, $TypeId);
4427 }
4428 }
4429 }
4430 }
4431 }
4432 }
4433 else {
4434 return getInitVal($1, $TypeId);
4435 }
4436 }
4437 }
4438 return undef;
4439}
4440
4441sub getInitVal($$)
4442{
4443 my ($InfoId, $TypeId) = @_;
4444 if(my $Info = $LibInfo{$Version}{"info"}{$InfoId})
4445 {
4446 if(my $InfoType = $LibInfo{$Version}{"info_type"}{$InfoId})
4447 {
4448 if($InfoType eq "integer_cst")
4449 {
4450 my $Val = getNodeIntCst($InfoId);
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04004451 if($TypeId and $TypeInfo{$Version}{$TypeId}{"Name"}=~/\Achar(| const)\Z/)
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04004452 { # characters
4453 $Val = chr($Val);
4454 }
4455 return $Val;
4456 }
4457 elsif($InfoType eq "string_cst") {
4458 return getNodeStrCst($InfoId);
4459 }
Andrey Ponomarenko01117f12012-06-26 12:23:02 +04004460 elsif($InfoType eq "var_decl")
4461 {
4462 if(my $Name = getNodeStrCst(getTreeAttr_Mngl($InfoId))) {
4463 return $Name;
4464 }
4465 }
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04004466 }
4467 }
4468 return undef;
4469}
4470
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004471sub set_Class_And_Namespace($)
4472{
4473 my $InfoId = $_[0];
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04004474 if(my $Info = $LibInfo{$Version}{"info"}{$InfoId})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004475 {
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04004476 if($Info=~/scpe[ ]*:[ ]*@(\d+) /)
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04004477 {
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04004478 my $NSInfoId = $1;
4479 if(my $InfoType = $LibInfo{$Version}{"info_type"}{$NSInfoId})
4480 {
4481 if($InfoType eq "namespace_decl") {
4482 $SymbolInfo{$Version}{$InfoId}{"NameSpace"} = getNameSpace($InfoId);
4483 }
4484 elsif($InfoType eq "record_type") {
4485 $SymbolInfo{$Version}{$InfoId}{"Class"} = $NSInfoId;
4486 }
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04004487 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004488 }
4489 }
4490 if($SymbolInfo{$Version}{$InfoId}{"Class"}
4491 or $SymbolInfo{$Version}{$InfoId}{"NameSpace"})
4492 { # identify language
4493 setLanguage($Version, "C++");
4494 }
4495}
4496
4497sub debugType($$)
4498{
4499 my ($Tid, $LibVersion) = @_;
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04004500 my %Type = get_Type($Tid, $LibVersion);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004501 printMsg("INFO", Dumper(\%Type));
4502}
4503
4504sub debugMangling($)
4505{
4506 my $LibVersion = $_[0];
4507 my %Mangled = ();
4508 foreach my $InfoId (keys(%{$SymbolInfo{$LibVersion}}))
4509 {
4510 if(my $Mngl = $SymbolInfo{$LibVersion}{$InfoId}{"MnglName"})
4511 {
4512 if($Mngl=~/\A(_Z|\?)/) {
4513 $Mangled{$Mngl}=$InfoId;
4514 }
4515 }
4516 }
4517 translateSymbols(keys(%Mangled), $LibVersion);
4518 foreach my $Mngl (keys(%Mangled))
4519 {
Andrey Ponomarenko85043792012-05-14 16:48:07 +04004520 my $U1 = modelUnmangled($Mangled{$Mngl}, "GCC");
4521 my $U2 = $tr_name{$Mngl};
4522 if($U1 ne $U2) {
4523 printMsg("INFO", "INCORRECT MANGLING:\n $Mngl\n $U1\n $U2\n");
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004524 }
4525 }
4526}
4527
4528sub linkSymbol($)
4529{ # link symbols from shared libraries
4530 # with the symbols from header files
4531 my $InfoId = $_[0];
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004532 # try to mangle symbol
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04004533 if((not check_gcc($GCC_PATH, "4") and $SymbolInfo{$Version}{$InfoId}{"Class"})
4534 or (check_gcc($GCC_PATH, "4") and not $SymbolInfo{$Version}{$InfoId}{"Class"}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004535 { # 1. GCC 3.x doesn't mangle class methods names in the TU dump (only functions and global data)
4536 # 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 +04004537 if(not $CheckHeadersOnly)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004538 {
4539 if(my $Mangled = $mangled_name_gcc{modelUnmangled($InfoId, "GCC")}) {
4540 return correct_incharge($InfoId, $Version, $Mangled);
4541 }
4542 }
Andrey Ponomarenko16934472012-03-29 15:37:04 +04004543 if($CheckHeadersOnly
4544 or not $BinaryOnly)
4545 { # 1. --headers-only mode
4546 # 2. not mangled src-only symbols
4547 if(my $Mangled = mangle_symbol($InfoId, $Version, "GCC")) {
4548 return $Mangled;
4549 }
4550 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004551 }
4552 return "";
4553}
4554
4555sub setLanguage($$)
4556{
4557 my ($LibVersion, $Lang) = @_;
4558 if(not $UserLang) {
4559 $COMMON_LANGUAGE{$LibVersion} = $Lang;
4560 }
4561}
4562
4563sub getSymbolInfo($)
4564{
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04004565 my $InfoId = $_[0];
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04004566 if(isInternal($InfoId)) {
4567 return;
4568 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04004569 ($SymbolInfo{$Version}{$InfoId}{"Header"}, $SymbolInfo{$Version}{$InfoId}{"Line"}) = getLocation($InfoId);
4570 if(not $SymbolInfo{$Version}{$InfoId}{"Header"}
Andrey Ponomarenkoa01311b2012-06-08 17:20:02 +04004571 or isBuiltIn($SymbolInfo{$Version}{$InfoId}{"Header"}))
4572 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04004573 delete($SymbolInfo{$Version}{$InfoId});
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004574 return;
4575 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04004576 setFuncAccess($InfoId);
4577 setFuncKind($InfoId);
Andrey Ponomarenkoa01311b2012-06-08 17:20:02 +04004578 if($SymbolInfo{$Version}{$InfoId}{"PseudoTemplate"})
4579 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04004580 delete($SymbolInfo{$Version}{$InfoId});
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004581 return;
4582 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04004583 $SymbolInfo{$Version}{$InfoId}{"Type"} = getFuncType($InfoId);
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04004584 if($SymbolInfo{$Version}{$InfoId}{"Return"} = getFuncReturn($InfoId))
4585 {
4586 if(not $TypeInfo{$Version}{$SymbolInfo{$Version}{$InfoId}{"Return"}}{"Name"})
4587 { # templates
4588 delete($SymbolInfo{$Version}{$InfoId});
4589 return;
4590 }
4591 }
4592 if(my $Rid = $SymbolInfo{$Version}{$InfoId}{"Return"})
4593 {
4594 if(defined $MissedTypedef{$Version}{$Rid})
4595 {
4596 if(my $AddedTid = $MissedTypedef{$Version}{$Rid}{"Tid"}) {
4597 $SymbolInfo{$Version}{$InfoId}{"Return"} = $AddedTid;
4598 }
4599 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004600 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04004601 if(not $SymbolInfo{$Version}{$InfoId}{"Return"}) {
4602 delete($SymbolInfo{$Version}{$InfoId}{"Return"});
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004603 }
Andrey Ponomarenkoa01311b2012-06-08 17:20:02 +04004604 my $Orig = getFuncOrig($InfoId);
4605 $SymbolInfo{$Version}{$InfoId}{"ShortName"} = getFuncShortName($Orig);
4606 if($SymbolInfo{$Version}{$InfoId}{"ShortName"}=~/\._/)
4607 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04004608 delete($SymbolInfo{$Version}{$InfoId});
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004609 return;
4610 }
Andrey Ponomarenkoa01311b2012-06-08 17:20:02 +04004611
4612 if(defined $TemplateInstance{$Version}{"Func"}{$Orig})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004613 {
Andrey Ponomarenkoa01311b2012-06-08 17:20:02 +04004614 my @TParams = getTParams($Orig, "Func");
4615 if(not @TParams)
4616 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04004617 delete($SymbolInfo{$Version}{$InfoId});
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004618 return;
4619 }
Andrey Ponomarenko16934472012-03-29 15:37:04 +04004620 foreach my $Pos (0 .. $#TParams) {
4621 $SymbolInfo{$Version}{$InfoId}{"TParam"}{$Pos}{"name"}=$TParams[$Pos];
4622 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004623 my $PrmsInLine = join(", ", @TParams);
Andrey Ponomarenko16934472012-03-29 15:37:04 +04004624 if($SymbolInfo{$Version}{$InfoId}{"ShortName"}=~/\Aoperator\W+\Z/)
4625 { # operator<< <T>, operator>> <T>
4626 $SymbolInfo{$Version}{$InfoId}{"ShortName"} .= " ";
4627 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04004628 $SymbolInfo{$Version}{$InfoId}{"ShortName"} .= "<".$PrmsInLine.">";
Andrey Ponomarenko9927e332012-10-19 10:50:48 +04004629 $SymbolInfo{$Version}{$InfoId}{"ShortName"} = formatName($SymbolInfo{$Version}{$InfoId}{"ShortName"}, "S");
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004630 }
4631 else
4632 { # support for GCC 3.4
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04004633 $SymbolInfo{$Version}{$InfoId}{"ShortName"}=~s/<.+>\Z//;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004634 }
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +04004635 if(my $MnglName = getTreeStr(getTreeAttr_Mngl($InfoId)))
4636 {
4637 if($OSgroup eq "windows")
4638 { # cut the offset
4639 $MnglName=~s/\@\d+\Z//g;
4640 }
4641 $SymbolInfo{$Version}{$InfoId}{"MnglName"} = $MnglName;
4642
4643 # NOTE: mangling of some symbols may change depending on GCC version
4644 # GCC 4.6: _ZN28QExplicitlySharedDataPointerI11QPixmapDataEC2IT_EERKS_IT_E
4645 # GCC 4.7: _ZN28QExplicitlySharedDataPointerI11QPixmapDataEC2ERKS1_
4646 }
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04004647
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04004648 if($SymbolInfo{$Version}{$InfoId}{"MnglName"}
Andrey Ponomarenko9927e332012-10-19 10:50:48 +04004649 and index($SymbolInfo{$Version}{$InfoId}{"MnglName"}, "_Z")!=0)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004650 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04004651 delete($SymbolInfo{$Version}{$InfoId});
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004652 return;
4653 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04004654 if(not $SymbolInfo{$Version}{$InfoId}{"Destructor"})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004655 { # destructors have an empty parameter list
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04004656 my $Skip = setFuncParams($InfoId);
Andrey Ponomarenko07aea072012-11-12 16:15:07 +04004657 if($Skip)
4658 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04004659 delete($SymbolInfo{$Version}{$InfoId});
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004660 return;
4661 }
4662 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04004663 set_Class_And_Namespace($InfoId);
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04004664 if(my $ClassId = $SymbolInfo{$Version}{$InfoId}{"Class"})
4665 {
4666 if(not $TypeInfo{$Version}{$ClassId}{"Name"})
4667 { # templates
4668 delete($SymbolInfo{$Version}{$InfoId});
4669 return;
4670 }
4671 }
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04004672 if(not $CheckHeadersOnly)
4673 {
4674 if($SymbolInfo{$Version}{$InfoId}{"Type"} eq "Function"
4675 and not $SymbolInfo{$Version}{$InfoId}{"Class"}
4676 and link_symbol($SymbolInfo{$Version}{$InfoId}{"ShortName"}, $Version, "-Deps"))
4677 { # functions (C++): not mangled in library, but are mangled in TU dump
4678 if(not $SymbolInfo{$Version}{$InfoId}{"MnglName"}
4679 or not link_symbol($SymbolInfo{$Version}{$InfoId}{"MnglName"}, $Version, "-Deps")) {
4680 $SymbolInfo{$Version}{$InfoId}{"MnglName"} = $SymbolInfo{$Version}{$InfoId}{"ShortName"};
4681 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004682 }
4683 }
Andrey Ponomarenko35c44fd2012-06-18 17:50:25 +04004684 if($LibInfo{$Version}{"info"}{$InfoId}=~/ lang:[ ]*C /i)
4685 { # extern "C"
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04004686 $SymbolInfo{$Version}{$InfoId}{"Lang"} = "C";
Andrey Ponomarenko35c44fd2012-06-18 17:50:25 +04004687 $SymbolInfo{$Version}{$InfoId}{"MnglName"} = $SymbolInfo{$Version}{$InfoId}{"ShortName"};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004688 }
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04004689 if($UserLang and $UserLang eq "C")
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004690 { # --lang=C option
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04004691 $SymbolInfo{$Version}{$InfoId}{"MnglName"} = $SymbolInfo{$Version}{$InfoId}{"ShortName"};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004692 }
4693 if($COMMON_LANGUAGE{$Version} eq "C++")
4694 { # correct mangled & short names
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04004695 # C++ or --headers-only mode
4696 if($SymbolInfo{$Version}{$InfoId}{"ShortName"}=~/\A__(comp|base|deleting)_(c|d)tor\Z/)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004697 { # support for old GCC versions: reconstruct real names for constructors and destructors
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04004698 $SymbolInfo{$Version}{$InfoId}{"ShortName"} = getNameByInfo(getTypeDeclId($SymbolInfo{$Version}{$InfoId}{"Class"}));
4699 $SymbolInfo{$Version}{$InfoId}{"ShortName"}=~s/<.+>\Z//;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004700 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04004701 if(not $SymbolInfo{$Version}{$InfoId}{"MnglName"})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004702 { # try to mangle symbol (link with libraries)
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04004703 if(my $Mangled = linkSymbol($InfoId)) {
4704 $SymbolInfo{$Version}{$InfoId}{"MnglName"} = $Mangled;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004705 }
4706 }
4707 if($OStarget eq "windows")
4708 { # link MS C++ symbols from library with GCC symbols from headers
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04004709 if(my $Mangled1 = $mangled_name{$Version}{modelUnmangled($InfoId, "MSVC")})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004710 { # exported symbols
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04004711 $SymbolInfo{$Version}{$InfoId}{"MnglName"} = $Mangled1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004712 }
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04004713 elsif(my $Mangled2 = mangle_symbol($InfoId, $Version, "MSVC"))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004714 { # pure virtual symbols
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04004715 $SymbolInfo{$Version}{$InfoId}{"MnglName"} = $Mangled2;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004716 }
4717 }
4718 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04004719 if(not $SymbolInfo{$Version}{$InfoId}{"MnglName"})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004720 { # can't detect symbol name
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04004721 delete($SymbolInfo{$Version}{$InfoId});
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004722 return;
4723 }
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04004724 if(not $SymbolInfo{$Version}{$InfoId}{"Constructor"}
Andrey Ponomarenkoa01311b2012-06-08 17:20:02 +04004725 and my $Spec = getVirtSpec($Orig))
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04004726 { # identify virtual and pure virtual functions
4727 # NOTE: constructors cannot be virtual
4728 # NOTE: in GCC 4.7 D1 destructors have no virtual spec
4729 # in the TU dump, so taking it from the original symbol
4730 if(not ($SymbolInfo{$Version}{$InfoId}{"Destructor"}
4731 and $SymbolInfo{$Version}{$InfoId}{"MnglName"}=~/D2E/))
4732 { # NOTE: D2 destructors are not present in a v-table
4733 $SymbolInfo{$Version}{$InfoId}{$Spec} = 1;
4734 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004735 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04004736 if(isInline($InfoId)) {
4737 $SymbolInfo{$Version}{$InfoId}{"InLine"} = 1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004738 }
Andrey Ponomarenkoe3d6bf02012-11-14 11:49:09 +04004739 if(hasThrow($FuncInfoId)) {
4740 $SymbolInfo{$Version}{$InfoId}{"Throw"} = 1;
4741 }
Andrey Ponomarenkob8d203d2012-05-25 18:11:07 +04004742 if($LibInfo{$Version}{"info"}{$InfoId}=~/ artificial /i) {
4743 $SymbolInfo{$Version}{$InfoId}{"Artificial"} = 1;
4744 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04004745 if($SymbolInfo{$Version}{$InfoId}{"Constructor"}
4746 and my $ClassId = $SymbolInfo{$Version}{$InfoId}{"Class"})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004747 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04004748 if(not $SymbolInfo{$Version}{$InfoId}{"InLine"}
Andrey Ponomarenkob8d203d2012-05-25 18:11:07 +04004749 and not $SymbolInfo{$Version}{$InfoId}{"Artificial"})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004750 { # inline or auto-generated constructor
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04004751 delete($TypeInfo{$Version}{$ClassId}{"Copied"});
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004752 }
4753 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +04004754 if(my $Symbol = $SymbolInfo{$Version}{$InfoId}{"MnglName"})
4755 {
Andrey Ponomarenko35c44fd2012-06-18 17:50:25 +04004756 if(not selectSymbol($Symbol, $SymbolInfo{$Version}{$InfoId}, "Dump", $Version))
4757 { # non-target symbols
4758 delete($SymbolInfo{$Version}{$InfoId});
4759 return;
Andrey Ponomarenko85043792012-05-14 16:48:07 +04004760 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004761 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04004762 if($SymbolInfo{$Version}{$InfoId}{"Type"} eq "Method"
4763 or $SymbolInfo{$Version}{$InfoId}{"Constructor"}
4764 or $SymbolInfo{$Version}{$InfoId}{"Destructor"}
4765 or $SymbolInfo{$Version}{$InfoId}{"Class"})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004766 {
Andrey Ponomarenko9927e332012-10-19 10:50:48 +04004767 if($SymbolInfo{$Version}{$InfoId}{"MnglName"}!~/\A(_Z|\?)/)
4768 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04004769 delete($SymbolInfo{$Version}{$InfoId});
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004770 return;
4771 }
4772 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04004773 if($SymbolInfo{$Version}{$InfoId}{"MnglName"})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004774 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04004775 if($MangledNames{$Version}{$SymbolInfo{$Version}{$InfoId}{"MnglName"}})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004776 { # one instance for one mangled name only
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04004777 delete($SymbolInfo{$Version}{$InfoId});
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004778 return;
4779 }
4780 else {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04004781 $MangledNames{$Version}{$SymbolInfo{$Version}{$InfoId}{"MnglName"}} = 1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004782 }
4783 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04004784 if($SymbolInfo{$Version}{$InfoId}{"Constructor"}
4785 or $SymbolInfo{$Version}{$InfoId}{"Destructor"}) {
4786 delete($SymbolInfo{$Version}{$InfoId}{"Return"});
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004787 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04004788 if($SymbolInfo{$Version}{$InfoId}{"MnglName"}=~/\A(_Z|\?)/
4789 and $SymbolInfo{$Version}{$InfoId}{"Class"})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004790 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04004791 if($SymbolInfo{$Version}{$InfoId}{"Type"} eq "Function")
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004792 { # static methods
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04004793 $SymbolInfo{$Version}{$InfoId}{"Static"} = 1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004794 }
4795 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04004796 if(getFuncLink($InfoId) eq "Static") {
4797 $SymbolInfo{$Version}{$InfoId}{"Static"} = 1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004798 }
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04004799 if($SymbolInfo{$Version}{$InfoId}{"MnglName"}=~/\A(_Z|\?)/)
4800 {
4801 if(my $Unmangled = $tr_name{$SymbolInfo{$Version}{$InfoId}{"MnglName"}})
4802 {
Andrey Ponomarenko9927e332012-10-19 10:50:48 +04004803 if($Unmangled=~/\.\_\d/)
4804 {
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04004805 delete($SymbolInfo{$Version}{$InfoId});
4806 return;
4807 }
4808 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004809 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04004810 delete($SymbolInfo{$Version}{$InfoId}{"Type"});
4811 if($SymbolInfo{$Version}{$InfoId}{"MnglName"}=~/\A_ZN(V|)K/) {
4812 $SymbolInfo{$Version}{$InfoId}{"Const"} = 1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004813 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04004814 if($SymbolInfo{$Version}{$InfoId}{"MnglName"}=~/\A_ZN(K|)V/) {
4815 $SymbolInfo{$Version}{$InfoId}{"Volatile"} = 1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004816 }
Andrey Ponomarenko07aea072012-11-12 16:15:07 +04004817
4818 if($WeakSymbols{$Version}{$SymbolInfo{$Version}{$InfoId}{"MnglName"}}) {
4819 $SymbolInfo{$Version}{$InfoId}{"Weak"} = 1;
4820 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004821}
4822
4823sub isInline($)
4824{ # "body: undefined" in the tree
4825 # -fkeep-inline-functions GCC option should be specified
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04004826 if($_[0] and my $Info = $LibInfo{$Version}{"info"}{$_[0]})
4827 {
4828 if($Info=~/ undefined /i) {
4829 return 0;
4830 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004831 }
4832 return 1;
4833}
4834
Andrey Ponomarenkoe3d6bf02012-11-14 11:49:09 +04004835sub hasThrow($)
4836{
4837 if($_[0] and my $Info = $LibInfo{$Version}{"info"}{$_[0]})
4838 {
4839 if($Info=~/type[ ]*:[ ]*@(\d+) /) {
4840 return getTreeAttr_Unql($1, "unql");
4841 }
4842 }
4843 return 1;
4844}
4845
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004846sub getTypeId($)
4847{
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04004848 if($_[0] and my $Info = $LibInfo{$Version}{"info"}{$_[0]})
4849 {
4850 if($Info=~/type[ ]*:[ ]*@(\d+) /) {
4851 return $1;
4852 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004853 }
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04004854 return "";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004855}
4856
4857sub setTypeMemb($$)
4858{
4859 my ($TypeId, $TypeAttr) = @_;
4860 my $TypeType = $TypeAttr->{"Type"};
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04004861 my ($Pos, $UnnamedPos) = (0, 0);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004862 if($TypeType eq "Enum")
4863 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04004864 my $TypeMembInfoId = getTreeAttr_Csts($TypeId);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004865 while($TypeMembInfoId)
4866 {
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04004867 $TypeAttr->{"Memb"}{$Pos}{"value"} = getEnumMembVal($TypeMembInfoId);
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04004868 my $MembName = getTreeStr(getTreeAttr_Purp($TypeMembInfoId));
4869 $TypeAttr->{"Memb"}{$Pos}{"name"} = $MembName;
4870 $EnumMembName_Id{$Version}{getTreeAttr_Valu($TypeMembInfoId)} = ($TypeAttr->{"NameSpace"})?$TypeAttr->{"NameSpace"}."::".$MembName:$MembName;
4871 $TypeMembInfoId = getNextElem($TypeMembInfoId);
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04004872 $Pos += 1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004873 }
4874 }
4875 elsif($TypeType=~/\A(Struct|Class|Union)\Z/)
4876 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04004877 my $TypeMembInfoId = getTreeAttr_Flds($TypeId);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004878 while($TypeMembInfoId)
4879 {
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04004880 my $IType = $LibInfo{$Version}{"info_type"}{$TypeMembInfoId};
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04004881 my $MInfo = $LibInfo{$Version}{"info"}{$TypeMembInfoId};
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04004882 if(not $IType or $IType ne "field_decl")
4883 { # search for fields, skip other stuff in the declaration
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04004884 $TypeMembInfoId = getNextElem($TypeMembInfoId);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004885 next;
4886 }
Andrey Ponomarenko01117f12012-06-26 12:23:02 +04004887 my $StructMembName = getTreeStr(getTreeAttr_Name($TypeMembInfoId));
4888 if(index($StructMembName, "_vptr.")!=-1)
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04004889 { # virtual tables
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04004890 $TypeMembInfoId = getNextElem($TypeMembInfoId);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004891 next;
4892 }
4893 if(not $StructMembName)
4894 { # unnamed fields
Andrey Ponomarenko01117f12012-06-26 12:23:02 +04004895 if(index($TypeAttr->{"Name"}, "_type_info_pseudo")==-1)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004896 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04004897 my $UnnamedTid = getTreeAttr_Type($TypeMembInfoId);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004898 my $UnnamedTName = getNameByInfo(getTypeDeclId($UnnamedTid));
4899 if(isAnon($UnnamedTName))
4900 { # rename unnamed fields to unnamed0, unnamed1, ...
4901 $StructMembName = "unnamed".($UnnamedPos++);
4902 }
4903 }
4904 }
4905 if(not $StructMembName)
4906 { # unnamed fields and base classes
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04004907 $TypeMembInfoId = getNextElem($TypeMembInfoId);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004908 next;
4909 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04004910 my $MembTypeId = getTreeAttr_Type($TypeMembInfoId);
4911 if(defined $MissedTypedef{$Version}{$MembTypeId})
4912 {
4913 if(my $AddedTid = $MissedTypedef{$Version}{$MembTypeId}{"Tid"}) {
4914 $MembTypeId = $AddedTid;
4915 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004916 }
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04004917 $TypeAttr->{"Memb"}{$Pos}{"type"} = $MembTypeId;
4918 $TypeAttr->{"Memb"}{$Pos}{"name"} = $StructMembName;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004919 if((my $Access = getTreeAccess($TypeMembInfoId)) ne "public")
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04004920 { # marked only protected and private, public by default
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04004921 $TypeAttr->{"Memb"}{$Pos}{"access"} = $Access;
4922 }
4923 if($MInfo=~/spec:\s*mutable /)
4924 { # mutable fields
4925 $TypeAttr->{"Memb"}{$Pos}{"mutable"} = 1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004926 }
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +04004927 if(my $Algn = getAlgn($TypeMembInfoId)) {
4928 $TypeAttr->{"Memb"}{$Pos}{"algn"} = $Algn;
4929 }
4930 if(my $BFSize = getBitField($TypeMembInfoId))
4931 { # in bits
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04004932 $TypeAttr->{"Memb"}{$Pos}{"bitfield"} = $BFSize;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004933 }
4934 else
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +04004935 { # in bytes
4936 $TypeAttr->{"Memb"}{$Pos}{"algn"} /= $BYTE_SIZE;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004937 }
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +04004938
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04004939 $TypeMembInfoId = getNextElem($TypeMembInfoId);
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04004940 $Pos += 1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004941 }
4942 }
4943}
4944
4945sub setFuncParams($)
4946{
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04004947 my $InfoId = $_[0];
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04004948 my $ParamInfoId = getTreeAttr_Args($InfoId);
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04004949 if(getFuncType($InfoId) eq "Method")
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004950 { # check type of "this" pointer
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04004951 my $ObjectTypeId = getTreeAttr_Type($ParamInfoId);
4952 if(my $ObjectName = $TypeInfo{$Version}{$ObjectTypeId}{"Name"})
Andrey Ponomarenko85043792012-05-14 16:48:07 +04004953 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04004954 if($ObjectName=~/\bconst(| volatile)\*const\b/) {
Andrey Ponomarenko85043792012-05-14 16:48:07 +04004955 $SymbolInfo{$Version}{$InfoId}{"Const"} = 1;
4956 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04004957 if($ObjectName=~/\bvolatile\b/) {
Andrey Ponomarenko85043792012-05-14 16:48:07 +04004958 $SymbolInfo{$Version}{$InfoId}{"Volatile"} = 1;
4959 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004960 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +04004961 else
4962 { # skip
4963 return 1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004964 }
4965 $ParamInfoId = getNextElem($ParamInfoId);
4966 }
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04004967 my ($Pos, $Vtt_Pos) = (0, -1);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004968 while($ParamInfoId)
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04004969 { # formal args
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04004970 my $ParamTypeId = getTreeAttr_Type($ParamInfoId);
4971 my $ParamName = getTreeStr(getTreeAttr_Name($ParamInfoId));
4972 if(not $ParamName)
4973 { # unnamed
4974 $ParamName = "p".($Pos+1);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004975 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04004976 if(defined $MissedTypedef{$Version}{$ParamTypeId})
4977 {
4978 if(my $AddedTid = $MissedTypedef{$Version}{$ParamTypeId}{"Tid"}) {
4979 $ParamTypeId = $AddedTid;
4980 }
4981 }
4982 my $PType = $TypeInfo{$Version}{$ParamTypeId}{"Type"};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004983 if(not $PType or $PType eq "Unknown") {
4984 return 1;
4985 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04004986 my $PTName = $TypeInfo{$Version}{$ParamTypeId}{"Name"};
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04004987 if(not $PTName) {
4988 return 1;
4989 }
4990 if($PTName eq "void") {
4991 last;
4992 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004993 if($ParamName eq "__vtt_parm"
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04004994 and $TypeInfo{$Version}{$ParamTypeId}{"Name"} eq "void const**")
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004995 {
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04004996 $Vtt_Pos = $Pos;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004997 $ParamInfoId = getNextElem($ParamInfoId);
4998 next;
4999 }
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04005000 $SymbolInfo{$Version}{$InfoId}{"Param"}{$Pos}{"type"} = $ParamTypeId;
5001 $SymbolInfo{$Version}{$InfoId}{"Param"}{$Pos}{"name"} = $ParamName;
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04005002 if(my $Algn = getAlgn($ParamInfoId)) {
5003 $SymbolInfo{$Version}{$InfoId}{"Param"}{$Pos}{"algn"} = $Algn/$BYTE_SIZE;
5004 }
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04005005 if(not $SymbolInfo{$Version}{$InfoId}{"Param"}{$Pos}{"name"}) {
5006 $SymbolInfo{$Version}{$InfoId}{"Param"}{$Pos}{"name"} = "p".($Pos+1);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005007 }
5008 if($LibInfo{$Version}{"info"}{$ParamInfoId}=~/spec:\s*register /)
5009 { # foo(register type arg)
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04005010 $SymbolInfo{$Version}{$InfoId}{"Param"}{$Pos}{"reg"} = 1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005011 }
5012 $ParamInfoId = getNextElem($ParamInfoId);
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04005013 $Pos += 1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005014 }
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04005015 if(setFuncArgs($InfoId, $Vtt_Pos)) {
Andrey Ponomarenko01117f12012-06-26 12:23:02 +04005016 $SymbolInfo{$Version}{$InfoId}{"Param"}{$Pos}{"type"} = "-1";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005017 }
5018 return 0;
5019}
5020
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04005021sub setFuncArgs($$)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005022{
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04005023 my ($InfoId, $Vtt_Pos) = @_;
5024 my $FuncTypeId = getFuncTypeId($InfoId);
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04005025 my $ParamListElemId = getTreeAttr_Prms($FuncTypeId);
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04005026 if(getFuncType($InfoId) eq "Method") {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005027 $ParamListElemId = getNextElem($ParamListElemId);
5028 }
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04005029 if(not $ParamListElemId)
5030 { # foo(...)
5031 return 1;
5032 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005033 my $HaveVoid = 0;
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04005034 my $Pos = 0;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005035 while($ParamListElemId)
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04005036 { # actual params: may differ from formal args
5037 # formal int*const
5038 # actual: int*
5039 if($Vtt_Pos!=-1 and $Pos==$Vtt_Pos)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005040 {
5041 $Vtt_Pos=-1;
5042 $ParamListElemId = getNextElem($ParamListElemId);
5043 next;
5044 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04005045 my $ParamTypeId = getTreeAttr_Valu($ParamListElemId);
5046 if($TypeInfo{$Version}{$ParamTypeId}{"Name"} eq "void")
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04005047 {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005048 $HaveVoid = 1;
5049 last;
5050 }
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04005051 elsif(not defined $SymbolInfo{$Version}{$InfoId}{"Param"}{$Pos}{"type"})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005052 {
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04005053 $SymbolInfo{$Version}{$InfoId}{"Param"}{$Pos}{"type"} = $ParamTypeId;
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04005054 if(not $SymbolInfo{$Version}{$InfoId}{"Param"}{$Pos}{"name"})
5055 { # unnamed
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04005056 $SymbolInfo{$Version}{$InfoId}{"Param"}{$Pos}{"name"} = "p".($Pos+1);
5057 }
5058 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04005059 if(my $PurpId = getTreeAttr_Purp($ParamListElemId))
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04005060 { # default arguments
Andrey Ponomarenko01117f12012-06-26 12:23:02 +04005061 if(my $PurpType = $LibInfo{$Version}{"info_type"}{$PurpId})
5062 {
5063 my $Val = getInitVal($PurpId, $ParamTypeId);
5064 if(defined $Val) {
5065 $SymbolInfo{$Version}{$InfoId}{"Param"}{$Pos}{"default"} = $Val;
5066 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005067 }
5068 }
5069 $ParamListElemId = getNextElem($ParamListElemId);
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04005070 $Pos += 1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005071 }
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04005072 return ($Pos>=1 and not $HaveVoid);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005073}
5074
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04005075sub getTreeAttr_Chan($)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005076{
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04005077 if($_[0] and my $Info = $LibInfo{$Version}{"info"}{$_[0]})
5078 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04005079 if($Info=~/chan[ ]*:[ ]*@(\d+) /) {
5080 return $1;
5081 }
5082 }
5083 return "";
5084}
5085
5086sub getTreeAttr_Chain($)
5087{
5088 if($_[0] and my $Info = $LibInfo{$Version}{"info"}{$_[0]})
5089 {
5090 if($Info=~/chain[ ]*:[ ]*@(\d+) /) {
5091 return $1;
5092 }
5093 }
5094 return "";
5095}
5096
Andrey Ponomarenkoe3d6bf02012-11-14 11:49:09 +04005097sub getTreeAttr_Unql($)
5098{
5099 if($_[0] and my $Info = $LibInfo{$Version}{"info"}{$_[0]})
5100 {
5101 if($Info=~/unql[ ]*:[ ]*@(\d+) /) {
5102 return $1;
5103 }
5104 }
5105 return "";
5106}
5107
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04005108sub getTreeAttr_Scpe($)
5109{
5110 if($_[0] and my $Info = $LibInfo{$Version}{"info"}{$_[0]})
5111 {
5112 if($Info=~/scpe[ ]*:[ ]*@(\d+) /) {
5113 return $1;
5114 }
5115 }
5116 return "";
5117}
5118
5119sub getTreeAttr_Type($)
5120{
5121 if($_[0] and my $Info = $LibInfo{$Version}{"info"}{$_[0]})
5122 {
5123 if($Info=~/type[ ]*:[ ]*@(\d+) /) {
5124 return $1;
5125 }
5126 }
5127 return "";
5128}
5129
5130sub getTreeAttr_Name($)
5131{
5132 if($_[0] and my $Info = $LibInfo{$Version}{"info"}{$_[0]})
5133 {
5134 if($Info=~/name[ ]*:[ ]*@(\d+) /) {
5135 return $1;
5136 }
5137 }
5138 return "";
5139}
5140
5141sub getTreeAttr_Mngl($)
5142{
5143 if($_[0] and my $Info = $LibInfo{$Version}{"info"}{$_[0]})
5144 {
5145 if($Info=~/mngl[ ]*:[ ]*@(\d+) /) {
5146 return $1;
5147 }
5148 }
5149 return "";
5150}
5151
5152sub getTreeAttr_Prms($)
5153{
5154 if($_[0] and my $Info = $LibInfo{$Version}{"info"}{$_[0]})
5155 {
5156 if($Info=~/prms[ ]*:[ ]*@(\d+) /) {
5157 return $1;
5158 }
5159 }
5160 return "";
5161}
5162
5163sub getTreeAttr_Fncs($)
5164{
5165 if($_[0] and my $Info = $LibInfo{$Version}{"info"}{$_[0]})
5166 {
5167 if($Info=~/fncs[ ]*:[ ]*@(\d+) /) {
5168 return $1;
5169 }
5170 }
5171 return "";
5172}
5173
5174sub getTreeAttr_Csts($)
5175{
5176 if($_[0] and my $Info = $LibInfo{$Version}{"info"}{$_[0]})
5177 {
5178 if($Info=~/csts[ ]*:[ ]*@(\d+) /) {
5179 return $1;
5180 }
5181 }
5182 return "";
5183}
5184
5185sub getTreeAttr_Purp($)
5186{
5187 if($_[0] and my $Info = $LibInfo{$Version}{"info"}{$_[0]})
5188 {
5189 if($Info=~/purp[ ]*:[ ]*@(\d+) /) {
5190 return $1;
5191 }
5192 }
5193 return "";
5194}
5195
5196sub getTreeAttr_Valu($)
5197{
5198 if($_[0] and my $Info = $LibInfo{$Version}{"info"}{$_[0]})
5199 {
5200 if($Info=~/valu[ ]*:[ ]*@(\d+) /) {
5201 return $1;
5202 }
5203 }
5204 return "";
5205}
5206
5207sub getTreeAttr_Flds($)
5208{
5209 if($_[0] and my $Info = $LibInfo{$Version}{"info"}{$_[0]})
5210 {
5211 if($Info=~/flds[ ]*:[ ]*@(\d+) /) {
5212 return $1;
5213 }
5214 }
5215 return "";
5216}
5217
5218sub getTreeAttr_Args($)
5219{
5220 if($_[0] and my $Info = $LibInfo{$Version}{"info"}{$_[0]})
5221 {
5222 if($Info=~/args[ ]*:[ ]*@(\d+) /) {
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04005223 return $1;
5224 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005225 }
5226 return "";
5227}
5228
5229sub getTreeValue($)
5230{
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04005231 if($_[0] and my $Info = $LibInfo{$Version}{"info"}{$_[0]})
5232 {
5233 if($Info=~/low[ ]*:[ ]*([^ ]+) /) {
5234 return $1;
5235 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005236 }
5237 return "";
5238}
5239
5240sub getTreeAccess($)
5241{
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04005242 if($_[0] and my $Info = $LibInfo{$Version}{"info"}{$_[0]})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005243 {
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04005244 if($Info=~/accs[ ]*:[ ]*([a-zA-Z]+) /)
5245 {
5246 my $Access = $1;
5247 if($Access eq "prot") {
5248 return "protected";
5249 }
5250 elsif($Access eq "priv") {
5251 return "private";
5252 }
5253 }
5254 elsif($Info=~/ protected /)
5255 { # support for old GCC versions
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005256 return "protected";
5257 }
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04005258 elsif($Info=~/ private /)
5259 { # support for old GCC versions
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005260 return "private";
5261 }
5262 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005263 return "public";
5264}
5265
5266sub setFuncAccess($)
5267{
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04005268 my $Access = getTreeAccess($_[0]);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005269 if($Access eq "protected") {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04005270 $SymbolInfo{$Version}{$_[0]}{"Protected"} = 1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005271 }
5272 elsif($Access eq "private") {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04005273 $SymbolInfo{$Version}{$_[0]}{"Private"} = 1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005274 }
5275}
5276
5277sub setTypeAccess($$)
5278{
5279 my ($TypeId, $TypeAttr) = @_;
5280 my $Access = getTreeAccess($TypeId);
5281 if($Access eq "protected") {
5282 $TypeAttr->{"Protected"} = 1;
5283 }
5284 elsif($Access eq "private") {
5285 $TypeAttr->{"Private"} = 1;
5286 }
5287}
5288
5289sub setFuncKind($)
5290{
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04005291 if($_[0] and my $Info = $LibInfo{$Version}{"info"}{$_[0]})
5292 {
5293 if($Info=~/pseudo tmpl/) {
5294 $SymbolInfo{$Version}{$_[0]}{"PseudoTemplate"} = 1;
5295 }
5296 elsif($Info=~/ constructor /) {
5297 $SymbolInfo{$Version}{$_[0]}{"Constructor"} = 1;
5298 }
5299 elsif($Info=~/ destructor /) {
5300 $SymbolInfo{$Version}{$_[0]}{"Destructor"} = 1;
5301 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005302 }
5303}
5304
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04005305sub getVirtSpec($)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005306{
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04005307 if($_[0] and my $Info = $LibInfo{$Version}{"info"}{$_[0]})
5308 {
5309 if($Info=~/spec[ ]*:[ ]*pure /) {
5310 return "PureVirt";
5311 }
5312 elsif($Info=~/spec[ ]*:[ ]*virt /) {
5313 return "Virt";
5314 }
5315 elsif($Info=~/ pure\s+virtual /)
5316 { # support for old GCC versions
5317 return "PureVirt";
5318 }
5319 elsif($Info=~/ virtual /)
5320 { # support for old GCC versions
5321 return "Virt";
5322 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005323 }
5324 return "";
5325}
5326
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005327sub getFuncLink($)
5328{
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04005329 if($_[0] and my $Info = $LibInfo{$Version}{"info"}{$_[0]})
5330 {
5331 if($Info=~/link[ ]*:[ ]*static /) {
5332 return "Static";
5333 }
5334 elsif($Info=~/link[ ]*:[ ]*([a-zA-Z]+) /) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005335 return $1;
5336 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005337 }
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04005338 return "";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005339}
5340
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005341sub get_IntNameSpace($$)
5342{
5343 my ($Interface, $LibVersion) = @_;
5344 return "" if(not $Interface or not $LibVersion);
5345 if(defined $Cache{"get_IntNameSpace"}{$Interface}{$LibVersion}) {
5346 return $Cache{"get_IntNameSpace"}{$Interface}{$LibVersion};
5347 }
5348 my $Signature = get_Signature($Interface, $LibVersion);
5349 if($Signature=~/\:\:/)
5350 {
5351 my $FounNameSpace = 0;
5352 foreach my $NameSpace (sort {get_depth($b)<=>get_depth($a)} keys(%{$NestedNameSpaces{$LibVersion}}))
5353 {
5354 if($Signature=~/(\A|\s+for\s+)\Q$NameSpace\E\:\:/) {
5355 return ($Cache{"get_IntNameSpace"}{$Interface}{$LibVersion} = $NameSpace);
5356 }
5357 }
5358 }
5359 else {
5360 return ($Cache{"get_IntNameSpace"}{$Interface}{$LibVersion} = "");
5361 }
5362}
5363
5364sub parse_TypeNameSpace($$)
5365{
5366 my ($TypeName, $LibVersion) = @_;
5367 return "" if(not $TypeName or not $LibVersion);
5368 if(defined $Cache{"parse_TypeNameSpace"}{$TypeName}{$LibVersion}) {
5369 return $Cache{"parse_TypeNameSpace"}{$TypeName}{$LibVersion};
5370 }
5371 if($TypeName=~/\:\:/)
5372 {
5373 my $FounNameSpace = 0;
5374 foreach my $NameSpace (sort {get_depth($b)<=>get_depth($a)} keys(%{$NestedNameSpaces{$LibVersion}}))
5375 {
5376 if($TypeName=~/\A\Q$NameSpace\E\:\:/) {
5377 return ($Cache{"parse_TypeNameSpace"}{$TypeName}{$LibVersion} = $NameSpace);
5378 }
5379 }
5380 }
5381 else {
5382 return ($Cache{"parse_TypeNameSpace"}{$TypeName}{$LibVersion} = "");
5383 }
5384}
5385
5386sub getNameSpace($)
5387{
5388 my $TypeInfoId = $_[0];
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04005389 if(my $NSInfoId = getTreeAttr_Scpe($TypeInfoId))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005390 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04005391 if(my $InfoType = $LibInfo{$Version}{"info_type"}{$NSInfoId})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005392 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04005393 if($InfoType eq "namespace_decl")
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04005394 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04005395 if($LibInfo{$Version}{"info"}{$NSInfoId}=~/name[ ]*:[ ]*@(\d+) /)
5396 {
5397 my $NameSpace = getTreeStr($1);
5398 if($NameSpace eq "::")
5399 { # global namespace
5400 return "";
5401 }
5402 if(my $BaseNameSpace = getNameSpace($NSInfoId)) {
5403 $NameSpace = $BaseNameSpace."::".$NameSpace;
5404 }
5405 $NestedNameSpaces{$Version}{$NameSpace} = 1;
5406 return $NameSpace;
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04005407 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04005408 else {
5409 return "";
5410 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005411 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04005412 elsif($InfoType eq "record_type")
5413 { # inside data type
5414 my ($Name, $NameNS) = getTrivialName(getTypeDeclId($NSInfoId), $NSInfoId);
5415 return $Name;
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04005416 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005417 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005418 }
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04005419 return "";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005420}
5421
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005422sub getEnumMembVal($)
5423{
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04005424 if($_[0] and my $Info = $LibInfo{$Version}{"info"}{$_[0]})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005425 {
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04005426 if($Info=~/valu[ ]*:[ ]*\@(\d+)/)
5427 {
5428 if(my $VInfo = $LibInfo{$Version}{"info"}{$1})
5429 {
5430 if($VInfo=~/cnst[ ]*:[ ]*\@(\d+)/)
5431 { # in newer versions of GCC the value is in the "const_decl->cnst" node
5432 return getTreeValue($1);
5433 }
5434 else
5435 { # some old versions of GCC (3.3) have the value in the "integer_cst" node
5436 return getTreeValue($1);
5437 }
5438 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005439 }
5440 }
5441 return "";
5442}
5443
5444sub getSize($)
5445{
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04005446 if($_[0] and my $Info = $LibInfo{$Version}{"info"}{$_[0]})
5447 {
5448 if($Info=~/size[ ]*:[ ]*\@(\d+)/) {
5449 return getTreeValue($1);
5450 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005451 }
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04005452 return 0;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005453}
5454
5455sub getAlgn($)
5456{
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04005457 if($_[0] and my $Info = $LibInfo{$Version}{"info"}{$_[0]})
5458 {
5459 if($Info=~/algn[ ]*:[ ]*(\d+) /) {
5460 return $1;
5461 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005462 }
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04005463 return "";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005464}
5465
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +04005466sub getBitField($)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005467{
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04005468 if($_[0] and my $Info = $LibInfo{$Version}{"info"}{$_[0]})
5469 {
5470 if($Info=~/ bitfield /) {
5471 return getSize($_[0]);
5472 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005473 }
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04005474 return 0;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005475}
5476
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04005477sub getNextElem($)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005478{
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04005479 if(my $Chan = getTreeAttr_Chan($_[0])) {
5480 return $Chan;
5481 }
5482 elsif(my $Chain = getTreeAttr_Chain($_[0])) {
5483 return $Chain;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005484 }
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04005485 return "";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005486}
5487
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04005488sub registerHeader($$)
5489{ # input: absolute path of header, relative path or name
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005490 my ($Header, $LibVersion) = @_;
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04005491 if(not $Header) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005492 return "";
5493 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04005494 if(is_abs($Header) and not -f $Header)
5495 { # incorrect absolute path
5496 exitStatus("Access_Error", "can't access \'$Header\'");
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005497 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04005498 if(skipHeader($Header, $LibVersion))
5499 { # skip
5500 return "";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005501 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04005502 if(my $Header_Path = identifyHeader($Header, $LibVersion))
5503 {
5504 detect_header_includes($Header_Path, $LibVersion);
5505
5506 if(my $RHeader_Path = $Header_ErrorRedirect{$LibVersion}{$Header_Path})
5507 { # redirect
5508 if($Registered_Headers{$LibVersion}{$RHeader_Path}{"Identity"}
5509 or skipHeader($RHeader_Path, $LibVersion))
5510 { # skip
5511 return "";
5512 }
5513 $Header_Path = $RHeader_Path;
5514 }
5515 elsif($Header_ShouldNotBeUsed{$LibVersion}{$Header_Path})
5516 { # skip
5517 return "";
5518 }
5519
5520 if(my $HName = get_filename($Header_Path))
5521 { # register
5522 $Registered_Headers{$LibVersion}{$Header_Path}{"Identity"} = $HName;
5523 $HeaderName_Paths{$LibVersion}{$HName}{$Header_Path} = 1;
5524 }
5525
5526 if(($Header=~/\.(\w+)\Z/ and $1 ne "h")
5527 or $Header!~/\.(\w+)\Z/)
5528 { # hpp, hh
5529 setLanguage($LibVersion, "C++");
5530 }
5531
5532 if($CheckHeadersOnly
5533 and $Header=~/(\A|\/)c\+\+(\/|\Z)/)
5534 { # /usr/include/c++/4.6.1/...
5535 $STDCXX_TESTING = 1;
5536 }
5537
5538 return $Header_Path;
5539 }
5540 return "";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005541}
5542
5543sub register_directory($$$)
5544{
5545 my ($Dir, $WithDeps, $LibVersion) = @_;
5546 $Dir=~s/[\/\\]+\Z//g;
5547 return if(not $LibVersion or not $Dir or not -d $Dir);
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04005548 return if(skipHeader($Dir, $LibVersion));
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005549 $Dir = get_abs_path($Dir);
5550 my $Mode = "All";
Andrey Ponomarenko85043792012-05-14 16:48:07 +04005551 if($WithDeps)
5552 {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005553 if($RegisteredDirs{$LibVersion}{$Dir}{1}) {
5554 return;
5555 }
5556 elsif($RegisteredDirs{$LibVersion}{$Dir}{0}) {
5557 $Mode = "DepsOnly";
5558 }
5559 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +04005560 else
5561 {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005562 if($RegisteredDirs{$LibVersion}{$Dir}{1}
5563 or $RegisteredDirs{$LibVersion}{$Dir}{0}) {
5564 return;
5565 }
5566 }
5567 $Header_Dependency{$LibVersion}{$Dir} = 1;
5568 $RegisteredDirs{$LibVersion}{$Dir}{$WithDeps} = 1;
5569 if($Mode eq "DepsOnly")
5570 {
5571 foreach my $Path (cmd_find($Dir,"d","","")) {
5572 $Header_Dependency{$LibVersion}{$Path} = 1;
5573 }
5574 return;
5575 }
5576 foreach my $Path (sort {length($b)<=>length($a)} cmd_find($Dir,"f","",""))
5577 {
5578 if($WithDeps)
5579 {
5580 my $SubDir = $Path;
5581 while(($SubDir = get_dirname($SubDir)) ne $Dir)
5582 { # register all sub directories
5583 $Header_Dependency{$LibVersion}{$SubDir} = 1;
5584 }
5585 }
5586 next if(is_not_header($Path));
5587 next if(ignore_path($Path));
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04005588 next if(skipHeader($Path, $LibVersion));
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005589 # Neighbors
Andrey Ponomarenko9927e332012-10-19 10:50:48 +04005590 foreach my $Part (get_prefixes($Path)) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005591 $Include_Neighbors{$LibVersion}{$Part} = $Path;
5592 }
5593 }
5594 if(get_filename($Dir) eq "include")
5595 { # search for "lib/include/" directory
5596 my $LibDir = $Dir;
5597 if($LibDir=~s/([\/\\])include\Z/$1lib/g and -d $LibDir) {
5598 register_directory($LibDir, $WithDeps, $LibVersion);
5599 }
5600 }
5601}
5602
5603sub parse_redirect($$$)
5604{
5605 my ($Content, $Path, $LibVersion) = @_;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005606 my @Errors = ();
5607 while($Content=~s/#\s*error\s+([^\n]+?)\s*(\n|\Z)//) {
5608 push(@Errors, $1);
5609 }
5610 my $Redirect = "";
5611 foreach (@Errors)
5612 {
5613 s/\s{2,}/ /g;
5614 if(/(only|must\ include
5615 |update\ to\ include
5616 |replaced\ with
5617 |replaced\ by|renamed\ to
Andrey Ponomarenko9927e332012-10-19 10:50:48 +04005618 |\ is\ in|\ use)\ (<[^<>]+>|[\w\-\/\\]+\.($HEADER_EXT))/ix)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005619 {
5620 $Redirect = $2;
5621 last;
5622 }
5623 elsif(/(include|use|is\ in)\ (<[^<>]+>|[\w\-\/\\]+\.($HEADER_EXT))\ instead/i)
5624 {
5625 $Redirect = $2;
5626 last;
5627 }
5628 elsif(/this\ header\ should\ not\ be\ used
5629 |programs\ should\ not\ directly\ include
5630 |you\ should\ not\ (include|be\ (including|using)\ this\ (file|header))
5631 |is\ not\ supported\ API\ for\ general\ use
5632 |do\ not\ use
Andrey Ponomarenko9927e332012-10-19 10:50:48 +04005633 |should\ not\ be\ (used|using)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005634 |cannot\ be\ included\ directly/ix and not /\ from\ /i) {
5635 $Header_ShouldNotBeUsed{$LibVersion}{$Path} = 1;
5636 }
5637 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +04005638 if($Redirect)
5639 {
5640 $Redirect=~s/\A<//g;
5641 $Redirect=~s/>\Z//g;
5642 }
5643 return $Redirect;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005644}
5645
5646sub parse_includes($$)
5647{
5648 my ($Content, $Path) = @_;
5649 my %Includes = ();
5650 while($Content=~s/#([ \t]*)(include|include_next|import)([ \t]*)(<|")([^<>"]+)(>|")//)
Andrey Ponomarenko85043792012-05-14 16:48:07 +04005651 { # C/C++: include, Objective C/C++: import directive
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005652 my ($Header, $Method) = ($5, $4);
5653 $Header = path_format($Header, $OSgroup);
Andrey Ponomarenko85043792012-05-14 16:48:07 +04005654 if($Method eq "\"" or is_abs($Header))
5655 {
5656 if(-e joinPath(get_dirname($Path), $Header))
5657 { # relative path exists
5658 $Includes{$Header} = -1;
5659 }
5660 else
5661 { # include "..." that doesn't exist is equal to include <...>
5662 $Includes{$Header} = 2;
5663 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005664 }
5665 else {
5666 $Includes{$Header} = 1;
5667 }
5668 }
5669 return \%Includes;
5670}
5671
5672sub ignore_path($)
5673{
5674 my $Path = $_[0];
5675 if($Path=~/\~\Z/)
5676 {# skipping system backup files
5677 return 1;
5678 }
5679 if($Path=~/(\A|[\/\\]+)(\.(svn|git|bzr|hg)|CVS)([\/\\]+|\Z)/)
5680 {# skipping hidden .svn, .git, .bzr, .hg and CVS directories
5681 return 1;
5682 }
5683 return 0;
5684}
5685
Andrey Ponomarenko9927e332012-10-19 10:50:48 +04005686sub sortByWord($$)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005687{
5688 my ($ArrRef, $W) = @_;
5689 return if(length($W)<2);
5690 @{$ArrRef} = sort {get_filename($b)=~/\Q$W\E/i<=>get_filename($a)=~/\Q$W\E/i} @{$ArrRef};
5691}
5692
Andrey Ponomarenko9927e332012-10-19 10:50:48 +04005693sub sortHeaders($$)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005694{
5695 my ($H1, $H2) = @_;
5696 $H1=~s/\.[a-z]+\Z//ig;
5697 $H2=~s/\.[a-z]+\Z//ig;
5698 my ($HDir1, $Hname1) = separate_path($H1);
5699 my ($HDir2, $Hname2) = separate_path($H2);
5700 my $Dirname1 = get_filename($HDir1);
5701 my $Dirname2 = get_filename($HDir2);
Andrey Ponomarenko9927e332012-10-19 10:50:48 +04005702 if($_[0] eq $_[1]
5703 or $H1 eq $H2) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005704 return 0;
5705 }
5706 elsif($H1=~/\A\Q$H2\E/) {
5707 return 1;
5708 }
5709 elsif($H2=~/\A\Q$H1\E/) {
5710 return -1;
5711 }
5712 elsif($HDir1=~/\Q$Hname1\E/i
5713 and $HDir2!~/\Q$Hname2\E/i)
Andrey Ponomarenko9927e332012-10-19 10:50:48 +04005714 { # include/glib-2.0/glib.h
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005715 return -1;
5716 }
5717 elsif($HDir2=~/\Q$Hname2\E/i
5718 and $HDir1!~/\Q$Hname1\E/i)
Andrey Ponomarenko9927e332012-10-19 10:50:48 +04005719 { # include/glib-2.0/glib.h
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005720 return 1;
5721 }
5722 elsif($Hname1=~/\Q$Dirname1\E/i
5723 and $Hname2!~/\Q$Dirname2\E/i)
Andrey Ponomarenko9927e332012-10-19 10:50:48 +04005724 { # include/hildon-thumbnail/hildon-thumbnail-factory.h
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005725 return -1;
5726 }
5727 elsif($Hname2=~/\Q$Dirname2\E/i
5728 and $Hname1!~/\Q$Dirname1\E/i)
Andrey Ponomarenko9927e332012-10-19 10:50:48 +04005729 { # include/hildon-thumbnail/hildon-thumbnail-factory.h
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005730 return 1;
5731 }
Andrey Ponomarenko9927e332012-10-19 10:50:48 +04005732 elsif($Hname1=~/(config|lib|util)/i
5733 and $Hname2!~/(config|lib|util)/i)
5734 { # include/alsa/asoundlib.h
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005735 return -1;
5736 }
Andrey Ponomarenko9927e332012-10-19 10:50:48 +04005737 elsif($Hname2=~/(config|lib|util)/i
5738 and $Hname1!~/(config|lib|util)/i)
5739 { # include/alsa/asoundlib.h
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005740 return 1;
5741 }
5742 elsif(checkRelevance($H1)
5743 and not checkRelevance($H2))
Andrey Ponomarenko9927e332012-10-19 10:50:48 +04005744 { # libebook/e-book.h
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005745 return -1;
5746 }
5747 elsif(checkRelevance($H2)
5748 and not checkRelevance($H1))
Andrey Ponomarenko9927e332012-10-19 10:50:48 +04005749 { # libebook/e-book.h
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005750 return 1;
5751 }
Andrey Ponomarenko9927e332012-10-19 10:50:48 +04005752 else
5753 {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005754 return (lc($H1) cmp lc($H2));
5755 }
5756}
5757
5758sub searchForHeaders($)
5759{
5760 my $LibVersion = $_[0];
5761 # gcc standard include paths
5762 find_gcc_cxx_headers($LibVersion);
5763 # processing header paths
5764 foreach my $Path (keys(%{$Descriptor{$LibVersion}{"IncludePaths"}}),
5765 keys(%{$Descriptor{$LibVersion}{"AddIncludePaths"}}))
5766 {
5767 my $IPath = $Path;
Andrey Ponomarenkoa01311b2012-06-08 17:20:02 +04005768 if($SystemRoot)
5769 {
5770 if(is_abs($Path)) {
5771 $Path = $SystemRoot.$Path;
5772 }
5773 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005774 if(not -e $Path) {
5775 exitStatus("Access_Error", "can't access \'$Path\'");
5776 }
5777 elsif(-f $Path) {
5778 exitStatus("Access_Error", "\'$Path\' - not a directory");
5779 }
5780 elsif(-d $Path)
5781 {
5782 $Path = get_abs_path($Path);
5783 register_directory($Path, 0, $LibVersion);
5784 if($Descriptor{$LibVersion}{"AddIncludePaths"}{$IPath}) {
5785 $Add_Include_Paths{$LibVersion}{$Path} = 1;
5786 }
5787 else {
5788 $Include_Paths{$LibVersion}{$Path} = 1;
5789 }
5790 }
5791 }
5792 if(keys(%{$Include_Paths{$LibVersion}})) {
5793 $INC_PATH_AUTODETECT{$LibVersion} = 0;
5794 }
5795 # registering directories
5796 foreach my $Path (split(/\s*\n\s*/, $Descriptor{$LibVersion}{"Headers"}))
5797 {
5798 next if(not -e $Path);
5799 $Path = get_abs_path($Path);
5800 $Path = path_format($Path, $OSgroup);
5801 if(-d $Path) {
5802 register_directory($Path, 1, $LibVersion);
5803 }
5804 elsif(-f $Path)
5805 {
5806 my $Dir = get_dirname($Path);
5807 if(not $SystemPaths{"include"}{$Dir}
5808 and not $LocalIncludes{$Dir})
5809 {
5810 register_directory($Dir, 1, $LibVersion);
5811 if(my $OutDir = get_dirname($Dir))
5812 { # registering the outer directory
5813 if(not $SystemPaths{"include"}{$OutDir}
5814 and not $LocalIncludes{$OutDir}) {
5815 register_directory($OutDir, 0, $LibVersion);
5816 }
5817 }
5818 }
5819 }
5820 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +04005821
5822 # clean memory
5823 %RegisteredDirs = ();
5824
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005825 # registering headers
5826 my $Position = 0;
5827 foreach my $Dest (split(/\s*\n\s*/, $Descriptor{$LibVersion}{"Headers"}))
5828 {
5829 if(is_abs($Dest) and not -e $Dest) {
5830 exitStatus("Access_Error", "can't access \'$Dest\'");
5831 }
5832 $Dest = path_format($Dest, $OSgroup);
5833 if(is_header($Dest, 1, $LibVersion))
5834 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04005835 if(my $HPath = registerHeader($Dest, $LibVersion)) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005836 $Registered_Headers{$LibVersion}{$HPath}{"Pos"} = $Position++;
5837 }
5838 }
5839 elsif(-d $Dest)
5840 {
5841 my @Registered = ();
5842 foreach my $Path (cmd_find($Dest,"f","",""))
5843 {
5844 next if(ignore_path($Path));
5845 next if(not is_header($Path, 0, $LibVersion));
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04005846 if(my $HPath = registerHeader($Path, $LibVersion)) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005847 push(@Registered, $HPath);
5848 }
5849 }
Andrey Ponomarenko9927e332012-10-19 10:50:48 +04005850 @Registered = sort {sortHeaders($a, $b)} @Registered;
5851 sortByWord(\@Registered, $TargetLibraryShortName);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005852 foreach my $Path (@Registered) {
5853 $Registered_Headers{$LibVersion}{$Path}{"Pos"} = $Position++;
5854 }
5855 }
5856 else {
5857 exitStatus("Access_Error", "can't identify \'$Dest\' as a header file");
5858 }
5859 }
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04005860 if(my $HList = $Descriptor{$LibVersion}{"IncludePreamble"})
5861 { # preparing preamble headers
5862 my $PPos=0;
5863 foreach my $Header (split(/\s*\n\s*/, $HList))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005864 {
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04005865 if(is_abs($Header) and not -f $Header) {
5866 exitStatus("Access_Error", "can't access file \'$Header\'");
5867 }
5868 $Header = path_format($Header, $OSgroup);
5869 if(my $Header_Path = is_header($Header, 1, $LibVersion))
5870 {
Andrey Ponomarenko9927e332012-10-19 10:50:48 +04005871 if(defined $Include_Preamble{$LibVersion}{$Header_Path})
5872 { # duplicate
5873 next;
5874 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04005875 next if(skipHeader($Header_Path, $LibVersion));
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04005876 $Include_Preamble{$LibVersion}{$Header_Path}{"Position"} = $PPos++;
5877 }
5878 else {
5879 exitStatus("Access_Error", "can't identify \'$Header\' as a header file");
5880 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005881 }
5882 }
5883 foreach my $Header_Name (keys(%{$HeaderName_Paths{$LibVersion}}))
5884 { # set relative paths (for duplicates)
5885 if(keys(%{$HeaderName_Paths{$LibVersion}{$Header_Name}})>=2)
5886 { # search for duplicates
5887 my $FirstPath = (keys(%{$HeaderName_Paths{$LibVersion}{$Header_Name}}))[0];
5888 my $Prefix = get_dirname($FirstPath);
5889 while($Prefix=~/\A(.+)[\/\\]+[^\/\\]+\Z/)
5890 { # detect a shortest distinguishing prefix
5891 my $NewPrefix = $1;
5892 my %Identity = ();
5893 foreach my $Path (keys(%{$HeaderName_Paths{$LibVersion}{$Header_Name}}))
5894 {
5895 if($Path=~/\A\Q$Prefix\E[\/\\]+(.*)\Z/) {
5896 $Identity{$Path} = $1;
5897 }
5898 }
5899 if(keys(%Identity)==keys(%{$HeaderName_Paths{$LibVersion}{$Header_Name}}))
5900 { # all names are differend with current prefix
5901 foreach my $Path (keys(%{$HeaderName_Paths{$LibVersion}{$Header_Name}})) {
5902 $Registered_Headers{$LibVersion}{$Path}{"Identity"} = $Identity{$Path};
5903 }
5904 last;
5905 }
5906 $Prefix = $NewPrefix; # increase prefix
5907 }
5908 }
5909 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +04005910
5911 # clean memory
5912 %HeaderName_Paths = ();
5913
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005914 foreach my $HeaderName (keys(%{$Include_Order{$LibVersion}}))
5915 { # ordering headers according to descriptor
5916 my $PairName=$Include_Order{$LibVersion}{$HeaderName};
5917 my ($Pos, $PairPos) = (-1, -1);
5918 my ($Path, $PairPath) = ();
5919 my @Paths = keys(%{$Registered_Headers{$LibVersion}});
5920 @Paths = sort {int($Registered_Headers{$LibVersion}{$a}{"Pos"})<=>int($Registered_Headers{$LibVersion}{$b}{"Pos"})} @Paths;
5921 foreach my $Header_Path (@Paths)
5922 {
5923 if(get_filename($Header_Path) eq $PairName)
5924 {
5925 $PairPos = $Registered_Headers{$LibVersion}{$Header_Path}{"Pos"};
5926 $PairPath = $Header_Path;
5927 }
5928 if(get_filename($Header_Path) eq $HeaderName)
5929 {
5930 $Pos = $Registered_Headers{$LibVersion}{$Header_Path}{"Pos"};
5931 $Path = $Header_Path;
5932 }
5933 }
5934 if($PairPos!=-1 and $Pos!=-1
5935 and int($PairPos)<int($Pos))
5936 {
5937 my %Tmp = %{$Registered_Headers{$LibVersion}{$Path}};
5938 %{$Registered_Headers{$LibVersion}{$Path}} = %{$Registered_Headers{$LibVersion}{$PairPath}};
5939 %{$Registered_Headers{$LibVersion}{$PairPath}} = %Tmp;
5940 }
5941 }
5942 if(not keys(%{$Registered_Headers{$LibVersion}})) {
5943 exitStatus("Error", "header files are not found in the ".$Descriptor{$LibVersion}{"Version"});
5944 }
5945}
5946
5947sub detect_real_includes($$)
5948{
5949 my ($AbsPath, $LibVersion) = @_;
5950 return () if(not $LibVersion or not $AbsPath or not -e $AbsPath);
5951 if($Cache{"detect_real_includes"}{$LibVersion}{$AbsPath}
5952 or keys(%{$RecursiveIncludes{$LibVersion}{$AbsPath}})) {
5953 return keys(%{$RecursiveIncludes{$LibVersion}{$AbsPath}});
5954 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +04005955 $Cache{"detect_real_includes"}{$LibVersion}{$AbsPath}=1;
5956
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005957 my $Path = callPreprocessor($AbsPath, "", $LibVersion);
5958 return () if(not $Path);
5959 open(PREPROC, $Path);
5960 while(<PREPROC>)
5961 {
5962 if(/#\s+\d+\s+"([^"]+)"[\s\d]*\n/)
5963 {
5964 my $Include = path_format($1, $OSgroup);
5965 if($Include=~/\<(built\-in|internal|command(\-|\s)line)\>|\A\./) {
5966 next;
5967 }
5968 if($Include eq $AbsPath) {
5969 next;
5970 }
5971 $RecursiveIncludes{$LibVersion}{$AbsPath}{$Include} = 1;
5972 }
5973 }
5974 close(PREPROC);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005975 return keys(%{$RecursiveIncludes{$LibVersion}{$AbsPath}});
5976}
5977
5978sub detect_header_includes($$)
5979{
5980 my ($Path, $LibVersion) = @_;
Andrey Ponomarenko85043792012-05-14 16:48:07 +04005981 return if(not $LibVersion or not $Path);
5982 if(defined $Cache{"detect_header_includes"}{$LibVersion}{$Path}) {
5983 return;
5984 }
5985 $Cache{"detect_header_includes"}{$LibVersion}{$Path}=1;
5986
5987 if(not -e $Path) {
5988 return;
5989 }
5990
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005991 my $Content = readFile($Path);
Andrey Ponomarenko85043792012-05-14 16:48:07 +04005992 if(my $Redirect = parse_redirect($Content, $Path, $LibVersion))
5993 { # detect error directive in headers
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04005994 if(my $RedirectPath = identifyHeader($Redirect, $LibVersion))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005995 {
5996 if($RedirectPath=~/\/usr\/include\// and $Path!~/\/usr\/include\//) {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04005997 $RedirectPath = identifyHeader(get_filename($Redirect), $LibVersion);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005998 }
5999 if($RedirectPath ne $Path) {
6000 $Header_ErrorRedirect{$LibVersion}{$Path} = $RedirectPath;
6001 }
6002 }
Andrey Ponomarenko9927e332012-10-19 10:50:48 +04006003 else
6004 { # can't find
6005 $Header_ShouldNotBeUsed{$LibVersion}{$Path} = 1;
6006 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006007 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +04006008 if(my $Inc = parse_includes($Content, $Path))
6009 {
6010 foreach my $Include (keys(%{$Inc}))
6011 { # detect includes
Andrey Ponomarenko85043792012-05-14 16:48:07 +04006012 $Header_Includes{$LibVersion}{$Path}{$Include} = $Inc->{$Include};
6013 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006014 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006015}
6016
6017sub simplify_path($)
6018{
6019 my $Path = $_[0];
6020 while($Path=~s&([\/\\])[^\/\\]+[\/\\]\.\.[\/\\]&$1&){};
6021 return $Path;
6022}
6023
6024sub fromLibc($)
6025{ # GLIBC header
6026 my $Path = $_[0];
6027 my ($Dir, $Name) = separate_path($Path);
6028 if(get_filename($Dir)=~/\A(include|libc)\Z/ and $GlibcHeader{$Name})
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04006029 { # /usr/include/{stdio, ...}.h
6030 # epoc32/include/libc/{stdio, ...}.h
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006031 return 1;
6032 }
6033 if(isLibcDir($Dir)) {
6034 return 1;
6035 }
6036 return 0;
6037}
6038
6039sub isLibcDir($)
6040{ # GLIBC directory
6041 my $Dir = $_[0];
6042 my ($OutDir, $Name) = separate_path($Dir);
6043 if(get_filename($OutDir)=~/\A(include|libc)\Z/
6044 and ($Name=~/\Aasm(|-.+)\Z/ or $GlibcDir{$Name}))
6045 { # /usr/include/{sys,bits,asm,asm-*}/*.h
6046 return 1;
6047 }
6048 return 0;
6049}
6050
6051sub detect_recursive_includes($$)
6052{
6053 my ($AbsPath, $LibVersion) = @_;
6054 return () if(not $AbsPath);
6055 if(isCyclical(\@RecurInclude, $AbsPath)) {
6056 return keys(%{$RecursiveIncludes{$LibVersion}{$AbsPath}});
6057 }
6058 my ($AbsDir, $Name) = separate_path($AbsPath);
6059 if(isLibcDir($AbsDir))
6060 { # GLIBC internals
6061 return ();
6062 }
6063 if(keys(%{$RecursiveIncludes{$LibVersion}{$AbsPath}})) {
6064 return keys(%{$RecursiveIncludes{$LibVersion}{$AbsPath}});
6065 }
6066 return () if($OSgroup ne "windows" and $Name=~/windows|win32|win64/i);
6067 return () if($MAIN_CPP_DIR and $AbsPath=~/\A\Q$MAIN_CPP_DIR\E/ and not $STDCXX_TESTING);
6068 push(@RecurInclude, $AbsPath);
6069 if($DefaultGccPaths{$AbsDir}
6070 or fromLibc($AbsPath))
6071 { # check "real" (non-"model") include paths
6072 my @Paths = detect_real_includes($AbsPath, $LibVersion);
6073 pop(@RecurInclude);
6074 return @Paths;
6075 }
6076 if(not keys(%{$Header_Includes{$LibVersion}{$AbsPath}})) {
6077 detect_header_includes($AbsPath, $LibVersion);
6078 }
6079 foreach my $Include (keys(%{$Header_Includes{$LibVersion}{$AbsPath}}))
6080 {
Andrey Ponomarenko85043792012-05-14 16:48:07 +04006081 my $IncType = $Header_Includes{$LibVersion}{$AbsPath}{$Include};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006082 my $HPath = "";
Andrey Ponomarenko85043792012-05-14 16:48:07 +04006083 if($IncType<0)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006084 { # for #include "..."
6085 my $Candidate = joinPath($AbsDir, $Include);
6086 if(-f $Candidate) {
6087 $HPath = simplify_path($Candidate);
6088 }
6089 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +04006090 elsif($IncType>0
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04006091 and $Include=~/[\/\\]/) # and not find_in_defaults($Include)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006092 { # search for the nearest header
6093 # QtCore/qabstractanimation.h includes <QtCore/qobject.h>
6094 my $Candidate = joinPath(get_dirname($AbsDir), $Include);
6095 if(-f $Candidate) {
6096 $HPath = $Candidate;
6097 }
6098 }
6099 if(not $HPath) {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04006100 $HPath = identifyHeader($Include, $LibVersion);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006101 }
6102 next if(not $HPath);
6103 if($HPath eq $AbsPath) {
6104 next;
6105 }
Andrey Ponomarenko9927e332012-10-19 10:50:48 +04006106
6107 if($Debug)
6108 { # boundary headers
6109 #if($HPath=~/vtk/ and $AbsPath!~/vtk/)
6110 #{
6111 # print STDERR "$AbsPath -> $HPath\n";
6112 #}
6113 }
6114
Andrey Ponomarenko85043792012-05-14 16:48:07 +04006115 $RecursiveIncludes{$LibVersion}{$AbsPath}{$HPath} = $IncType;
6116 if($IncType>0)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006117 { # only include <...>, skip include "..." prefixes
6118 $Header_Include_Prefix{$LibVersion}{$AbsPath}{$HPath}{get_dirname($Include)} = 1;
6119 }
6120 foreach my $IncPath (detect_recursive_includes($HPath, $LibVersion))
6121 {
6122 if($IncPath eq $AbsPath) {
6123 next;
6124 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +04006125 my $RIncType = $RecursiveIncludes{$LibVersion}{$HPath}{$IncPath};
6126 if($RIncType==-1)
6127 { # include "..."
6128 $RIncType = $IncType;
6129 }
6130 elsif($RIncType==2)
6131 {
6132 if($IncType!=-1) {
6133 $RIncType = $IncType;
6134 }
6135 }
6136 $RecursiveIncludes{$LibVersion}{$AbsPath}{$IncPath} = $RIncType;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006137 foreach my $Prefix (keys(%{$Header_Include_Prefix{$LibVersion}{$HPath}{$IncPath}})) {
6138 $Header_Include_Prefix{$LibVersion}{$AbsPath}{$IncPath}{$Prefix} = 1;
6139 }
6140 }
6141 foreach my $Dep (keys(%{$Header_Include_Prefix{$LibVersion}{$AbsPath}}))
6142 {
6143 if($GlibcHeader{get_filename($Dep)} and keys(%{$Header_Include_Prefix{$LibVersion}{$AbsPath}{$Dep}})>=2
6144 and defined $Header_Include_Prefix{$LibVersion}{$AbsPath}{$Dep}{""})
6145 { # distinguish math.h from glibc and math.h from the tested library
6146 delete($Header_Include_Prefix{$LibVersion}{$AbsPath}{$Dep}{""});
6147 last;
6148 }
6149 }
6150 }
6151 pop(@RecurInclude);
6152 return keys(%{$RecursiveIncludes{$LibVersion}{$AbsPath}});
6153}
6154
6155sub find_in_framework($$$)
6156{
6157 my ($Header, $Framework, $LibVersion) = @_;
6158 return "" if(not $Header or not $Framework or not $LibVersion);
6159 if(defined $Cache{"find_in_framework"}{$LibVersion}{$Framework}{$Header}) {
6160 return $Cache{"find_in_framework"}{$LibVersion}{$Framework}{$Header};
6161 }
6162 foreach my $Dependency (sort {get_depth($a)<=>get_depth($b)} keys(%{$Header_Dependency{$LibVersion}}))
6163 {
6164 if(get_filename($Dependency) eq $Framework
6165 and -f get_dirname($Dependency)."/".$Header) {
6166 return ($Cache{"find_in_framework"}{$LibVersion}{$Framework}{$Header} = get_dirname($Dependency));
6167 }
6168 }
6169 return ($Cache{"find_in_framework"}{$LibVersion}{$Framework}{$Header} = "");
6170}
6171
6172sub find_in_defaults($)
6173{
6174 my $Header = $_[0];
6175 return "" if(not $Header);
6176 if(defined $Cache{"find_in_defaults"}{$Header}) {
6177 return $Cache{"find_in_defaults"}{$Header};
6178 }
6179 foreach my $Dir (sort {get_depth($a)<=>get_depth($b)}
6180 (keys(%DefaultIncPaths), keys(%DefaultGccPaths), keys(%DefaultCppPaths), keys(%UserIncPath)))
6181 {
6182 next if(not $Dir);
6183 if(-f $Dir."/".$Header) {
6184 return ($Cache{"find_in_defaults"}{$Header}=$Dir);
6185 }
6186 }
6187 return ($Cache{"find_in_defaults"}{$Header}="");
6188}
6189
6190sub cmp_paths($$)
6191{
6192 my ($Path1, $Path2) = @_;
6193 my @Parts1 = split(/[\/\\]/, $Path1);
6194 my @Parts2 = split(/[\/\\]/, $Path2);
6195 foreach my $Num (0 .. $#Parts1)
6196 {
6197 my $Part1 = $Parts1[$Num];
6198 my $Part2 = $Parts2[$Num];
6199 if($GlibcDir{$Part1}
6200 and not $GlibcDir{$Part2}) {
6201 return 1;
6202 }
6203 elsif($GlibcDir{$Part2}
6204 and not $GlibcDir{$Part1}) {
6205 return -1;
6206 }
6207 elsif($Part1=~/glib/
6208 and $Part2!~/glib/) {
6209 return 1;
6210 }
6211 elsif($Part1!~/glib/
6212 and $Part2=~/glib/) {
6213 return -1;
6214 }
6215 elsif(my $CmpRes = ($Part1 cmp $Part2)) {
6216 return $CmpRes;
6217 }
6218 }
6219 return 0;
6220}
6221
6222sub checkRelevance($)
6223{
6224 my ($Path) = @_;
6225 return 0 if(not $Path);
6226 if($SystemRoot) {
Andrey Ponomarenkoa01311b2012-06-08 17:20:02 +04006227 $Path = cut_path_prefix($Path, $SystemRoot);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006228 }
6229 my ($Dir, $Name) = separate_path($Path);
Andrey Ponomarenkoa01311b2012-06-08 17:20:02 +04006230 $Name=~s/\.\w+\Z//g; # remove extension (.h)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006231 my @Tokens = split(/[_\d\W]+/, $Name);
6232 foreach (@Tokens)
6233 {
6234 next if(not $_);
6235 if($Dir=~/(\A|lib|[_\d\W])\Q$_\E([_\d\W]|lib|\Z)/i
6236 or length($_)>=4 and $Dir=~/\Q$_\E/i)
6237 { # include/gupnp-1.0/libgupnp/gupnp-context.h
6238 # include/evolution-data-server-1.4/libebook/e-book.h
6239 return 1;
6240 }
6241 }
6242 return 0;
6243}
6244
6245sub checkFamily(@)
6246{
6247 my @Paths = @_;
6248 return 1 if($#Paths<=0);
6249 my %Prefix = ();
6250 foreach my $Path (@Paths)
6251 {
6252 if($SystemRoot) {
6253 $Path = cut_path_prefix($Path, $SystemRoot);
6254 }
6255 if(my $Dir = get_dirname($Path))
6256 {
6257 $Dir=~s/(\/[^\/]+?)[\d\.\-\_]+\Z/$1/g; # remove version suffix
6258 $Prefix{$Dir} += 1;
6259 $Prefix{get_dirname($Dir)} += 1;
6260 }
6261 }
6262 foreach (sort keys(%Prefix))
6263 {
6264 if(get_depth($_)>=3
6265 and $Prefix{$_}==$#Paths+1) {
6266 return 1;
6267 }
6268 }
6269 return 0;
6270}
6271
6272sub isAcceptable($$$)
6273{
6274 my ($Header, $Candidate, $LibVersion) = @_;
6275 my $HName = get_filename($Header);
6276 if(get_dirname($Header))
6277 { # with prefix
6278 return 1;
6279 }
6280 if($HName=~/config|setup/i and $Candidate=~/[\/\\]lib\d*[\/\\]/)
6281 { # allow to search for glibconfig.h in /usr/lib/glib-2.0/include/
6282 return 1;
6283 }
6284 if(checkRelevance($Candidate))
6285 { # allow to search for atk.h in /usr/include/atk-1.0/atk/
6286 return 1;
6287 }
6288 if(checkFamily(getSystemHeaders($HName, $LibVersion)))
6289 { # /usr/include/qt4/QtNetwork/qsslconfiguration.h
6290 # /usr/include/qt4/Qt/qsslconfiguration.h
6291 return 1;
6292 }
6293 if($OStarget eq "symbian")
6294 {
6295 if($Candidate=~/[\/\\]stdapis[\/\\]/) {
6296 return 1;
6297 }
6298 }
6299 return 0;
6300}
6301
6302sub isRelevant($$$)
6303{ # disallow to search for "abstract" headers in too deep directories
6304 my ($Header, $Candidate, $LibVersion) = @_;
6305 my $HName = get_filename($Header);
6306 if($OStarget eq "symbian")
6307 {
6308 if($Candidate=~/[\/\\](tools|stlportv5)[\/\\]/) {
6309 return 0;
6310 }
6311 }
Andrey Ponomarenko9927e332012-10-19 10:50:48 +04006312 if($OStarget ne "bsd")
6313 {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006314 if($Candidate=~/[\/\\]include[\/\\]bsd[\/\\]/)
6315 { # openssh: skip /usr/lib/bcc/include/bsd/signal.h
6316 return 0;
6317 }
6318 }
Andrey Ponomarenko9927e332012-10-19 10:50:48 +04006319 if($OStarget ne "windows")
6320 {
6321 if($Candidate=~/[\/\\](wine|msvcrt|windows)[\/\\]/)
6322 { # skip /usr/include/wine/msvcrt
6323 return 0;
6324 }
6325 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006326 if(not get_dirname($Header)
6327 and $Candidate=~/[\/\\]wx[\/\\]/)
6328 { # do NOT search in system /wx/ directory
6329 # for headers without a prefix: sstream.h
6330 return 0;
6331 }
6332 if($Candidate=~/c\+\+[\/\\]\d+/ and $MAIN_CPP_DIR
6333 and $Candidate!~/\A\Q$MAIN_CPP_DIR\E/)
6334 { # skip ../c++/3.3.3/ if using ../c++/4.5/
6335 return 0;
6336 }
6337 if($Candidate=~/[\/\\]asm-/
6338 and (my $Arch = getArch($LibVersion)) ne "unknown")
6339 { # arch-specific header files
6340 if($Candidate!~/[\/\\]asm-\Q$Arch\E/)
6341 {# skip ../asm-arm/ if using x86 architecture
6342 return 0;
6343 }
6344 }
6345 my @Candidates = getSystemHeaders($HName, $LibVersion);
6346 if($#Candidates==1)
6347 { # unique header
6348 return 1;
6349 }
6350 my @SCandidates = getSystemHeaders($Header, $LibVersion);
6351 if($#SCandidates==1)
6352 { # unique name
6353 return 1;
6354 }
6355 my $SystemDepth = $SystemRoot?get_depth($SystemRoot):0;
6356 if(get_depth($Candidate)-$SystemDepth>=5)
6357 { # abstract headers in too deep directories
6358 # sstream.h or typeinfo.h in /usr/include/wx-2.9/wx/
6359 if(not isAcceptable($Header, $Candidate, $LibVersion)) {
6360 return 0;
6361 }
6362 }
6363 if($Header eq "parser.h"
6364 and $Candidate!~/\/libxml2\//)
6365 { # select parser.h from xml2 library
6366 return 0;
6367 }
6368 if(not get_dirname($Header)
6369 and keys(%{$SystemHeaders{$HName}})>=3)
6370 { # many headers with the same name
6371 # like thread.h included without a prefix
6372 if(not checkFamily(@Candidates)) {
6373 return 0;
6374 }
6375 }
6376 return 1;
6377}
6378
6379sub selectSystemHeader($$)
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04006380{ # cache function
6381 if(defined $Cache{"selectSystemHeader"}{$_[1]}{$_[0]}) {
6382 return $Cache{"selectSystemHeader"}{$_[1]}{$_[0]};
6383 }
6384 return ($Cache{"selectSystemHeader"}{$_[1]}{$_[0]} = selectSystemHeader_I(@_));
6385}
6386
6387sub selectSystemHeader_I($$)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006388{
6389 my ($Header, $LibVersion) = @_;
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04006390 if(-f $Header) {
6391 return $Header;
6392 }
6393 if(is_abs($Header) and not -f $Header)
6394 { # incorrect absolute path
6395 return "";
6396 }
Andrey Ponomarenko9927e332012-10-19 10:50:48 +04006397 if(defined $ConfHeaders{lc($Header)})
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04006398 { # too abstract configuration headers
6399 return "";
6400 }
Andrey Ponomarenko9927e332012-10-19 10:50:48 +04006401 my $HName = get_filename($Header);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006402 if($OSgroup ne "windows")
6403 {
Andrey Ponomarenko9927e332012-10-19 10:50:48 +04006404 if(defined $WinHeaders{lc($HName)}
6405 or $HName=~/windows|win32|win64/i)
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04006406 { # windows headers
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006407 return "";
6408 }
Andrey Ponomarenko9927e332012-10-19 10:50:48 +04006409 }
6410 if($OSgroup ne "macos")
6411 {
6412 if($HName eq "fp.h")
6413 { # pngconf.h includes fp.h for MACOS
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006414 return "";
6415 }
6416 }
6417 if($OSgroup ne "solaris")
6418 {
Andrey Ponomarenko9927e332012-10-19 10:50:48 +04006419 if($Header eq "thread.h") {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006420 return "";
6421 }
6422 }
Andrey Ponomarenko07aea072012-11-12 16:15:07 +04006423 if($OSgroup ne "hpux")
6424 {
6425 if($Header eq "sys/stream.h") {
6426 return "";
6427 }
6428 }
Andrey Ponomarenko9927e332012-10-19 10:50:48 +04006429 if($ObsoleteHeaders{$HName}) {
6430 return "";
6431 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04006432
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006433 foreach my $Path (keys(%{$SystemPaths{"include"}}))
6434 { # search in default paths
6435 if(-f $Path."/".$Header) {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04006436 return joinPath($Path,$Header);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006437 }
6438 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04006439 if(not keys(%SystemHeaders))
6440 { # register all headers in system include dirs
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006441 detectSystemHeaders();
6442 }
6443 foreach my $Candidate (sort {get_depth($a)<=>get_depth($b)}
6444 sort {cmp_paths($b, $a)} getSystemHeaders($Header, $LibVersion))
6445 {
6446 if(isRelevant($Header, $Candidate, $LibVersion)) {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04006447 return $Candidate;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006448 }
6449 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04006450 # error
6451 return "";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006452}
6453
6454sub getSystemHeaders($$)
6455{
6456 my ($Header, $LibVersion) = @_;
6457 my @Candidates = ();
6458 foreach my $Candidate (sort keys(%{$SystemHeaders{$Header}}))
6459 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04006460 if(skipHeader($Candidate, $LibVersion)) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006461 next;
6462 }
6463 push(@Candidates, $Candidate);
6464 }
6465 return @Candidates;
6466}
6467
6468sub cut_path_prefix($$)
6469{
6470 my ($Path, $Prefix) = @_;
6471 return $Path if(not $Prefix);
6472 $Prefix=~s/[\/\\]+\Z//;
6473 $Path=~s/\A\Q$Prefix\E([\/\\]+|\Z)//;
6474 return $Path;
6475}
6476
6477sub is_default_include_dir($)
6478{
6479 my $Dir = $_[0];
6480 $Dir=~s/[\/\\]+\Z//;
6481 return ($DefaultGccPaths{$Dir} or $DefaultCppPaths{$Dir} or $DefaultIncPaths{$Dir});
6482}
6483
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04006484sub identifyHeader($$)
6485{ # cache function
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006486 my ($Header, $LibVersion) = @_;
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04006487 if(not $Header) {
6488 return "";
6489 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006490 $Header=~s/\A(\.\.[\\\/])+//g;
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04006491 if(defined $Cache{"identifyHeader"}{$LibVersion}{$Header}) {
6492 return $Cache{"identifyHeader"}{$LibVersion}{$Header};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006493 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04006494 return ($Cache{"identifyHeader"}{$LibVersion}{$Header} = identifyHeader_I($Header, $LibVersion));
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006495}
6496
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04006497sub identifyHeader_I($$)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006498{ # search for header by absolute path, relative path or name
6499 my ($Header, $LibVersion) = @_;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006500 if(-f $Header)
6501 { # it's relative or absolute path
6502 return get_abs_path($Header);
6503 }
6504 elsif($GlibcHeader{$Header} and not $GLIBC_TESTING
6505 and my $HeaderDir = find_in_defaults($Header))
6506 { # search for libc headers in the /usr/include
6507 # for non-libc target library before searching
6508 # in the library paths
6509 return joinPath($HeaderDir,$Header);
6510 }
6511 elsif(my $Path = $Include_Neighbors{$LibVersion}{$Header})
6512 { # search in the target library paths
6513 return $Path;
6514 }
6515 elsif($DefaultGccHeader{$Header})
6516 { # search in the internal GCC include paths
6517 return $DefaultGccHeader{$Header};
6518 }
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04006519 elsif(my $DefaultDir = find_in_defaults($Header))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006520 { # search in the default GCC include paths
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04006521 return joinPath($DefaultDir,$Header);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006522 }
6523 elsif($DefaultCppHeader{$Header})
6524 { # search in the default G++ include paths
6525 return $DefaultCppHeader{$Header};
6526 }
6527 elsif(my $AnyPath = selectSystemHeader($Header, $LibVersion))
6528 { # search everywhere in the system
6529 return $AnyPath;
6530 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04006531 elsif($OSgroup eq "macos")
6532 { # search in frameworks: "OpenGL/gl.h" is "OpenGL.framework/Headers/gl.h"
6533 if(my $Dir = get_dirname($Header))
6534 {
6535 my $RelPath = "Headers\/".get_filename($Header);
6536 if(my $HeaderDir = find_in_framework($RelPath, $Dir.".framework", $LibVersion)) {
6537 return joinPath($HeaderDir, $RelPath);
6538 }
6539 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006540 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04006541 # cannot find anything
6542 return "";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006543}
6544
6545sub getLocation($)
6546{
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04006547 if($_[0] and my $Info = $LibInfo{$Version}{"info"}{$_[0]})
6548 {
6549 if($Info=~/srcp[ ]*:[ ]*([\w\-\<\>\.\+\/\\]+):(\d+) /) {
Andrey Ponomarenko9927e332012-10-19 10:50:48 +04006550 return (path_format($1, $OSgroup), $2);
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04006551 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006552 }
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04006553 return ();
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006554}
6555
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006556sub getNameByInfo($)
6557{
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04006558 if($_[0] and my $Info = $LibInfo{$Version}{"info"}{$_[0]})
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04006559 {
6560 if($Info=~/name[ ]*:[ ]*@(\d+) /)
6561 {
6562 if(my $NInfo = $LibInfo{$Version}{"info"}{$1})
6563 {
6564 if($NInfo=~/strg[ ]*:[ ]*(.*?)[ ]+lngt/)
6565 { # short unsigned int (may include spaces)
6566 return $1;
6567 }
6568 }
6569 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006570 }
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04006571 return "";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006572}
6573
6574sub getTreeStr($)
6575{
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04006576 if($_[0] and my $Info = $LibInfo{$Version}{"info"}{$_[0]})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006577 {
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04006578 if($Info=~/strg[ ]*:[ ]*([^ ]*)/)
6579 {
6580 my $Str = $1;
Andrey Ponomarenko07aea072012-11-12 16:15:07 +04006581 if($CppMode{$Version}
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04006582 and $Str=~/\Ac99_(.+)\Z/) {
6583 if($CppKeywords_A{$1}) {
6584 $Str=$1;
6585 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006586 }
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04006587 return $Str;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006588 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006589 }
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04006590 return "";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006591}
6592
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006593sub getFuncShortName($)
6594{
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04006595 if(my $Info = $LibInfo{$Version}{"info"}{$_[0]})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006596 {
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04006597 if($Info=~/ operator /)
6598 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04006599 if($Info=~/ conversion /)
6600 {
6601 if(my $Rid = $SymbolInfo{$Version}{$_[0]}{"Return"})
6602 {
6603 if(my $RName = $TypeInfo{$Version}{$Rid}{"Name"}) {
6604 return "operator ".$RName;
6605 }
6606 }
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04006607 }
6608 else
6609 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04006610 if($Info=~/ operator[ ]+([a-zA-Z]+) /)
6611 {
6612 if(my $Ind = $Operator_Indication{$1}) {
6613 return "operator".$Ind;
6614 }
6615 elsif(not $UnknownOperator{$1})
6616 {
6617 printMsg("WARNING", "unknown operator $1");
6618 $UnknownOperator{$1} = 1;
6619 }
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04006620 }
6621 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006622 }
6623 else
6624 {
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04006625 if($Info=~/name[ ]*:[ ]*@(\d+) /) {
6626 return getTreeStr($1);
6627 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006628 }
6629 }
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04006630 return "";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006631}
6632
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006633sub getFuncReturn($)
6634{
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04006635 if($_[0] and my $Info = $LibInfo{$Version}{"info"}{$_[0]})
6636 {
6637 if($Info=~/type[ ]*:[ ]*@(\d+) /)
6638 {
6639 if($LibInfo{$Version}{"info"}{$1}=~/retn[ ]*:[ ]*@(\d+) /) {
6640 return $1;
6641 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006642 }
6643 }
6644 return "";
6645}
6646
6647sub getFuncOrig($)
6648{
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04006649 if($_[0] and my $Info = $LibInfo{$Version}{"info"}{$_[0]})
6650 {
6651 if($Info=~/orig[ ]*:[ ]*@(\d+) /) {
6652 return $1;
6653 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006654 }
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04006655 return $_[0];
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006656}
6657
6658sub unmangleSymbol($)
6659{
6660 my $Symbol = $_[0];
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04006661 if(my @Unmngl = unmangleArray($Symbol)) {
6662 return $Unmngl[0];
6663 }
6664 return "";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006665}
6666
6667sub unmangleArray(@)
6668{
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04006669 if($_[0]=~/\A\?/)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006670 { # MSVC mangling
6671 my $UndNameCmd = get_CmdPath("undname");
6672 if(not $UndNameCmd) {
6673 exitStatus("Not_Found", "can't find \"undname\"");
6674 }
6675 writeFile("$TMP_DIR/unmangle", join("\n", @_));
Andrey Ponomarenkoa01311b2012-06-08 17:20:02 +04006676 return split(/\n/, `$UndNameCmd 0x8386 \"$TMP_DIR/unmangle\"`);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006677 }
6678 else
6679 { # GCC mangling
6680 my $CppFiltCmd = get_CmdPath("c++filt");
6681 if(not $CppFiltCmd) {
6682 exitStatus("Not_Found", "can't find c++filt in PATH");
6683 }
Andrey Ponomarenko9927e332012-10-19 10:50:48 +04006684 if(not defined $CPPFILT_SUPPORT_FILE)
6685 {
6686 my $Info = `$CppFiltCmd -h 2>&1`;
6687 $CPPFILT_SUPPORT_FILE = $Info=~/\@<file>/;
6688 }
6689 if($CPPFILT_SUPPORT_FILE)
6690 { # new versions of c++filt can take a file
6691 if($#_>$MAX_CPPFILT_FILE_SIZE)
6692 { # c++filt <= 2.22 may crash on large files (larger than 8mb)
6693 # this is fixed in the oncoming version of Binutils
6694 my @Half = splice(@_, 0, ($#_+1)/2);
6695 return (unmangleArray(@Half), unmangleArray(@_))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006696 }
Andrey Ponomarenko9927e332012-10-19 10:50:48 +04006697 else
6698 {
6699 my $NoStrip = "";
6700 if($OSgroup eq "macos"
6701 or $OSgroup eq "windows") {
6702 $NoStrip = "-n";
6703 }
6704 writeFile("$TMP_DIR/unmangle", join("\n", @_));
6705 my $Res = `$CppFiltCmd $NoStrip \@\"$TMP_DIR/unmangle\"`;
6706 if($?==139)
6707 { # segmentation fault
6708 printMsg("ERROR", "internal error - c++filt crashed, try to reduce MAX_CPPFILT_FILE_SIZE constant");
6709 }
6710 return split(/\n/, $Res);
6711 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006712 }
6713 else
6714 { # old-style unmangling
Andrey Ponomarenko9927e332012-10-19 10:50:48 +04006715 if($#_>$MAX_COMMAND_LINE_ARGUMENTS)
6716 {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006717 my @Half = splice(@_, 0, ($#_+1)/2);
6718 return (unmangleArray(@Half), unmangleArray(@_))
6719 }
6720 else
6721 {
6722 my $NoStrip = "";
6723 if($OSgroup eq "macos"
6724 or $OSgroup eq "windows") {
6725 $NoStrip = "-n";
6726 }
6727 my $Strings = join(" ", @_);
Andrey Ponomarenko9927e332012-10-19 10:50:48 +04006728 my $Res = `$CppFiltCmd $NoStrip $Strings`;
6729 if($?==139)
6730 { # segmentation fault
6731 printMsg("ERROR", "internal error - c++filt crashed, try to reduce MAX_COMMAND_LINE_ARGUMENTS constant");
6732 }
6733 return split(/\n/, $Res);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006734 }
6735 }
6736 }
6737}
6738
6739sub get_SignatureNoInfo($$)
6740{
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04006741 my ($Symbol, $LibVersion) = @_;
6742 if($Cache{"get_SignatureNoInfo"}{$LibVersion}{$Symbol}) {
6743 return $Cache{"get_SignatureNoInfo"}{$LibVersion}{$Symbol};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006744 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04006745 my ($MnglName, $VersionSpec, $SymbolVersion) = separate_symbol($Symbol);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006746 my $Signature = $tr_name{$MnglName}?$tr_name{$MnglName}:$MnglName;
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04006747 if($Symbol=~/\A(_Z|\?)/)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006748 { # C++
Andrey Ponomarenko1477d2c2012-11-12 18:55:45 +04006749 # some standard typedefs
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006750 $Signature=~s/\Qstd::basic_string<char, std::char_traits<char>, std::allocator<char> >\E/std::string/g;
6751 $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;
6752 }
Andrey Ponomarenko82b005f2012-11-12 17:58:14 +04006753 if(not $CheckObjectsOnly or $OSgroup=~/linux|bsd|beos/i)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006754 { # ELF format marks data as OBJECT
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04006755 if($GlobalDataObject{$LibVersion}{$Symbol}) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006756 $Signature .= " [data]";
6757 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04006758 elsif($Symbol!~/\A(_Z|\?)/) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006759 $Signature .= " (...)";
6760 }
6761 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04006762 if(my $ChargeLevel = get_ChargeLevel($Symbol, $LibVersion))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006763 {
Andrey Ponomarenko16934472012-03-29 15:37:04 +04006764 my $ShortName = substr($Signature, 0, find_center($Signature, "("));
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006765 $Signature=~s/\A\Q$ShortName\E/$ShortName $ChargeLevel/g;
6766 }
6767 if($SymbolVersion) {
6768 $Signature .= $VersionSpec.$SymbolVersion;
6769 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04006770 return ($Cache{"get_SignatureNoInfo"}{$LibVersion}{$Symbol} = $Signature);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006771}
6772
6773sub get_ChargeLevel($$)
6774{
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04006775 my ($Symbol, $LibVersion) = @_;
6776 return "" if($Symbol!~/\A(_Z|\?)/);
6777 if(defined $CompleteSignature{$LibVersion}{$Symbol}
6778 and $CompleteSignature{$LibVersion}{$Symbol}{"Header"})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006779 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04006780 if($CompleteSignature{$LibVersion}{$Symbol}{"Constructor"})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006781 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04006782 if($Symbol=~/C1E/) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006783 return "[in-charge]";
6784 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04006785 elsif($Symbol=~/C2E/) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006786 return "[not-in-charge]";
6787 }
6788 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04006789 elsif($CompleteSignature{$LibVersion}{$Symbol}{"Destructor"})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006790 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04006791 if($Symbol=~/D1E/) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006792 return "[in-charge]";
6793 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04006794 elsif($Symbol=~/D2E/) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006795 return "[not-in-charge]";
6796 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04006797 elsif($Symbol=~/D0E/) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006798 return "[in-charge-deleting]";
6799 }
6800 }
6801 }
6802 else
6803 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04006804 if($Symbol=~/C1E/) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006805 return "[in-charge]";
6806 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04006807 elsif($Symbol=~/C2E/) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006808 return "[not-in-charge]";
6809 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04006810 elsif($Symbol=~/D1E/) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006811 return "[in-charge]";
6812 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04006813 elsif($Symbol=~/D2E/) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006814 return "[not-in-charge]";
6815 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04006816 elsif($Symbol=~/D0E/) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006817 return "[in-charge-deleting]";
6818 }
6819 }
6820 return "";
6821}
6822
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04006823sub get_Signature_M($$)
6824{
6825 my ($Symbol, $LibVersion) = @_;
6826 my $Signature_M = $tr_name{$Symbol};
6827 if(my $RTid = $CompleteSignature{$LibVersion}{$Symbol}{"Return"})
6828 { # add return type name
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04006829 $Signature_M = $TypeInfo{$LibVersion}{$RTid}{"Name"}." ".$Signature_M;
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04006830 }
6831 return $Signature_M;
6832}
6833
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006834sub get_Signature($$)
6835{
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04006836 my ($Symbol, $LibVersion) = @_;
6837 if($Cache{"get_Signature"}{$LibVersion}{$Symbol}) {
6838 return $Cache{"get_Signature"}{$LibVersion}{$Symbol};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006839 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04006840 my ($MnglName, $VersionSpec, $SymbolVersion) = separate_symbol($Symbol);
6841 if(isPrivateData($MnglName) or not $CompleteSignature{$LibVersion}{$Symbol}{"Header"})
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04006842 { # non-public global data
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04006843 return get_SignatureNoInfo($Symbol, $LibVersion);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006844 }
6845 my ($Func_Signature, @Param_Types_FromUnmangledName) = ();
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04006846 my $ShortName = $CompleteSignature{$LibVersion}{$Symbol}{"ShortName"};
6847 if($Symbol=~/\A(_Z|\?)/)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006848 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04006849 if(my $ClassId = $CompleteSignature{$LibVersion}{$Symbol}{"Class"}) {
6850 $Func_Signature = $TypeInfo{$LibVersion}{$ClassId}{"Name"}."::".(($CompleteSignature{$LibVersion}{$Symbol}{"Destructor"})?"~":"").$ShortName;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006851 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04006852 elsif(my $NameSpace = $CompleteSignature{$LibVersion}{$Symbol}{"NameSpace"}) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006853 $Func_Signature = $NameSpace."::".$ShortName;
6854 }
6855 else {
6856 $Func_Signature = $ShortName;
6857 }
Andrey Ponomarenko07aea072012-11-12 16:15:07 +04006858 my ($Short, $Params) = split_Signature($tr_name{$MnglName});
6859 @Param_Types_FromUnmangledName = separate_Params($Params, 0, 1);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006860 }
6861 else {
6862 $Func_Signature = $MnglName;
6863 }
6864 my @ParamArray = ();
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04006865 foreach my $Pos (sort {int($a) <=> int($b)} keys(%{$CompleteSignature{$LibVersion}{$Symbol}{"Param"}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006866 {
6867 next if($Pos eq "");
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04006868 my $ParamTypeId = $CompleteSignature{$LibVersion}{$Symbol}{"Param"}{$Pos}{"type"};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006869 next if(not $ParamTypeId);
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04006870 my $ParamTypeName = $TypeInfo{$LibVersion}{$ParamTypeId}{"Name"};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006871 if(not $ParamTypeName) {
6872 $ParamTypeName = $Param_Types_FromUnmangledName[$Pos];
6873 }
6874 foreach my $Typedef (keys(%ChangedTypedef))
6875 {
6876 my $Base = $Typedef_BaseName{$LibVersion}{$Typedef};
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04006877 $ParamTypeName=~s/\b\Q$Typedef\E\b/$Base/g;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006878 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04006879 if(my $ParamName = $CompleteSignature{$LibVersion}{$Symbol}{"Param"}{$Pos}{"name"}) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006880 push(@ParamArray, create_member_decl($ParamTypeName, $ParamName));
6881 }
6882 else {
6883 push(@ParamArray, $ParamTypeName);
6884 }
6885 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04006886 if($CompleteSignature{$LibVersion}{$Symbol}{"Data"}
6887 or $GlobalDataObject{$LibVersion}{$Symbol}) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006888 $Func_Signature .= " [data]";
6889 }
6890 else
6891 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04006892 if(my $ChargeLevel = get_ChargeLevel($Symbol, $LibVersion))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006893 { # add [in-charge]
6894 $Func_Signature .= " ".$ChargeLevel;
6895 }
6896 $Func_Signature .= " (".join(", ", @ParamArray).")";
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04006897 if($CompleteSignature{$LibVersion}{$Symbol}{"Const"}
6898 or $Symbol=~/\A_ZN(V|)K/) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006899 $Func_Signature .= " const";
6900 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04006901 if($CompleteSignature{$LibVersion}{$Symbol}{"Volatile"}
6902 or $Symbol=~/\A_ZN(K|)V/) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006903 $Func_Signature .= " volatile";
6904 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04006905 if($CompleteSignature{$LibVersion}{$Symbol}{"Static"}
6906 and $Symbol=~/\A(_Z|\?)/)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006907 {# for static methods
6908 $Func_Signature .= " [static]";
6909 }
6910 }
6911 if(defined $ShowRetVal
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04006912 and my $ReturnTId = $CompleteSignature{$LibVersion}{$Symbol}{"Return"}) {
6913 $Func_Signature .= ":".$TypeInfo{$LibVersion}{$ReturnTId}{"Name"};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006914 }
6915 if($SymbolVersion) {
6916 $Func_Signature .= $VersionSpec.$SymbolVersion;
6917 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04006918 return ($Cache{"get_Signature"}{$LibVersion}{$Symbol} = $Func_Signature);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006919}
6920
6921sub create_member_decl($$)
6922{
6923 my ($TName, $Member) = @_;
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04006924 if($TName=~/\([\*]+\)/)
6925 {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006926 $TName=~s/\(([\*]+)\)/\($1$Member\)/;
6927 return $TName;
6928 }
6929 else
6930 {
6931 my @ArraySizes = ();
6932 while($TName=~s/(\[[^\[\]]*\])\Z//) {
6933 push(@ArraySizes, $1);
6934 }
6935 return $TName." ".$Member.join("", @ArraySizes);
6936 }
6937}
6938
6939sub getFuncType($)
6940{
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04006941 if($_[0] and my $Info = $LibInfo{$Version}{"info"}{$_[0]})
6942 {
6943 if($Info=~/type[ ]*:[ ]*@(\d+) /)
6944 {
6945 if(my $Type = $LibInfo{$Version}{"info_type"}{$1})
6946 {
6947 if($Type eq "method_type") {
6948 return "Method";
6949 }
6950 elsif($Type eq "function_type") {
6951 return "Function";
6952 }
6953 else {
6954 return "Other";
6955 }
6956 }
6957 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006958 }
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +04006959 return "";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006960}
6961
6962sub getFuncTypeId($)
6963{
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04006964 if($_[0] and my $Info = $LibInfo{$Version}{"info"}{$_[0]})
6965 {
6966 if($Info=~/type[ ]*:[ ]*@(\d+)( |\Z)/) {
6967 return $1;
6968 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006969 }
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04006970 return 0;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006971}
6972
6973sub isNotAnon($) {
6974 return (not isAnon($_[0]));
6975}
6976
6977sub isAnon($)
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04006978{ # "._N" or "$_N" in older GCC versions
6979 return ($_[0] and $_[0]=~/(\.|\$)\_\d+|anon\-/);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006980}
6981
Andrey Ponomarenko9927e332012-10-19 10:50:48 +04006982sub formatName($$)
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04006983{ # type name correction
Andrey Ponomarenko9927e332012-10-19 10:50:48 +04006984 if(defined $Cache{"formatName"}{$_[1]}{$_[0]}) {
6985 return $Cache{"formatName"}{$_[1]}{$_[0]};
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04006986 }
6987
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +04006988 my $N = $_[0];
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04006989
Andrey Ponomarenko9927e332012-10-19 10:50:48 +04006990 if($_[1] ne "S")
6991 {
6992 $N=~s/\A[ ]+//g;
6993 $N=~s/[ ]+\Z//g;
6994 $N=~s/[ ]{2,}/ /g;
6995 }
6996
6997 $N=~s/[ ]*(\W)[ ]*/$1/g; # std::basic_string<char> const
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04006998
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +04006999 $N=~s/\bvolatile const\b/const volatile/g;
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04007000
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +04007001 $N=~s/\b(long long|short|long) unsigned\b/unsigned $1/g;
7002 $N=~s/\b(short|long) int\b/$1/g;
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04007003
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +04007004 $N=~s/([\)\]])(const|volatile)\b/$1 $2/g;
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04007005
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +04007006 while($N=~s/>>/> >/g) {};
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04007007
Andrey Ponomarenko9927e332012-10-19 10:50:48 +04007008 if($_[1] eq "S")
7009 {
7010 if(index($N, "operator")!=-1) {
7011 $N=~s/\b(operator[ ]*)> >/$1>>/;
7012 }
7013 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04007014
Andrey Ponomarenko9927e332012-10-19 10:50:48 +04007015 return ($Cache{"formatName"}{$_[1]}{$_[0]} = $N);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007016}
7017
7018sub get_HeaderDeps($$)
7019{
7020 my ($AbsPath, $LibVersion) = @_;
7021 return () if(not $AbsPath or not $LibVersion);
7022 if(defined $Cache{"get_HeaderDeps"}{$LibVersion}{$AbsPath}) {
7023 return @{$Cache{"get_HeaderDeps"}{$LibVersion}{$AbsPath}};
7024 }
7025 my %IncDir = ();
7026 detect_recursive_includes($AbsPath, $LibVersion);
7027 foreach my $HeaderPath (keys(%{$RecursiveIncludes{$LibVersion}{$AbsPath}}))
7028 {
7029 next if(not $HeaderPath);
7030 next if($MAIN_CPP_DIR and $HeaderPath=~/\A\Q$MAIN_CPP_DIR\E([\/\\]|\Z)/);
7031 my $Dir = get_dirname($HeaderPath);
7032 foreach my $Prefix (keys(%{$Header_Include_Prefix{$LibVersion}{$AbsPath}{$HeaderPath}}))
7033 {
7034 my $Dep = $Dir;
7035 if($Prefix)
7036 {
7037 if($OSgroup eq "windows")
7038 { # case insensitive seach on windows
7039 if(not $Dep=~s/[\/\\]+\Q$Prefix\E\Z//ig) {
7040 next;
7041 }
7042 }
7043 elsif($OSgroup eq "macos")
7044 { # seach in frameworks
7045 if(not $Dep=~s/[\/\\]+\Q$Prefix\E\Z//g)
7046 {
7047 if($HeaderPath=~/(.+\.framework)\/Headers\/([^\/]+)/)
7048 {# frameworks
7049 my ($HFramework, $HName) = ($1, $2);
7050 $Dep = $HFramework;
7051 }
7052 else
7053 {# mismatch
7054 next;
7055 }
7056 }
7057 }
7058 elsif(not $Dep=~s/[\/\\]+\Q$Prefix\E\Z//g)
7059 { # Linux, FreeBSD
7060 next;
7061 }
7062 }
7063 if(not $Dep)
7064 { # nothing to include
7065 next;
7066 }
7067 if(is_default_include_dir($Dep))
7068 { # included by the compiler
7069 next;
7070 }
7071 if(get_depth($Dep)==1)
7072 { # too short
7073 next;
7074 }
7075 if(isLibcDir($Dep))
7076 { # do NOT include /usr/include/{sys,bits}
7077 next;
7078 }
7079 $IncDir{$Dep}=1;
7080 }
7081 }
7082 $Cache{"get_HeaderDeps"}{$LibVersion}{$AbsPath} = sortIncPaths([keys(%IncDir)], $LibVersion);
7083 return @{$Cache{"get_HeaderDeps"}{$LibVersion}{$AbsPath}};
7084}
7085
7086sub sortIncPaths($$)
7087{
7088 my ($ArrRef, $LibVersion) = @_;
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04007089 if(not $ArrRef or $#{$ArrRef}<0) {
7090 return $ArrRef;
7091 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007092 @{$ArrRef} = sort {$b cmp $a} @{$ArrRef};
7093 @{$ArrRef} = sort {get_depth($a)<=>get_depth($b)} @{$ArrRef};
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04007094 @{$ArrRef} = sort {sortDeps($b, $a, $LibVersion)} @{$ArrRef};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007095 return $ArrRef;
7096}
7097
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04007098sub sortDeps($$$)
7099{
7100 if($Header_Dependency{$_[2]}{$_[0]}
7101 and not $Header_Dependency{$_[2]}{$_[1]}) {
7102 return 1;
7103 }
7104 elsif(not $Header_Dependency{$_[2]}{$_[0]}
7105 and $Header_Dependency{$_[2]}{$_[1]}) {
7106 return -1;
7107 }
7108 return 0;
7109}
7110
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007111sub joinPath($$) {
7112 return join($SLASH, @_);
7113}
7114
7115sub get_namespace_additions($)
7116{
7117 my $NameSpaces = $_[0];
7118 my ($Additions, $AddNameSpaceId) = ("", 1);
7119 foreach my $NS (sort {$a=~/_/ <=> $b=~/_/} sort {lc($a) cmp lc($b)} keys(%{$NameSpaces}))
7120 {
7121 next if($SkipNameSpaces{$Version}{$NS});
7122 next if(not $NS or $NameSpaces->{$NS}==-1);
7123 next if($NS=~/(\A|::)iterator(::|\Z)/i);
7124 next if($NS=~/\A__/i);
7125 next if(($NS=~/\Astd::/ or $NS=~/\A(std|tr1|rel_ops|fcntl)\Z/) and not $STDCXX_TESTING);
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04007126 $NestedNameSpaces{$Version}{$NS} = 1; # for future use in reports
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007127 my ($TypeDecl_Prefix, $TypeDecl_Suffix) = ();
7128 my @NS_Parts = split(/::/, $NS);
7129 next if($#NS_Parts==-1);
7130 next if($NS_Parts[0]=~/\A(random|or)\Z/);
7131 foreach my $NS_Part (@NS_Parts)
7132 {
7133 $TypeDecl_Prefix .= "namespace $NS_Part\{";
7134 $TypeDecl_Suffix .= "}";
7135 }
7136 my $TypeDecl = $TypeDecl_Prefix."typedef int tmp_add_type_$AddNameSpaceId;".$TypeDecl_Suffix;
7137 my $FuncDecl = "$NS\:\:tmp_add_type_$AddNameSpaceId tmp_add_func_$AddNameSpaceId(){return 0;};";
7138 $Additions.=" $TypeDecl\n $FuncDecl\n";
7139 $AddNameSpaceId+=1;
7140 }
7141 return $Additions;
7142}
7143
7144sub path_format($$)
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04007145{ # forward slash to pass into MinGW GCC
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007146 my ($Path, $Fmt) = @_;
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04007147 if($Fmt eq "windows")
7148 {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007149 $Path=~s/\//\\/g;
7150 $Path=lc($Path);
7151 }
7152 else {
7153 $Path=~s/\\/\//g;
7154 }
7155 return $Path;
7156}
7157
7158sub inc_opt($$)
7159{
7160 my ($Path, $Style) = @_;
7161 if($Style eq "GCC")
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04007162 { # GCC options
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007163 if($OSgroup eq "windows")
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04007164 { # to MinGW GCC
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007165 return "-I\"".path_format($Path, "unix")."\"";
7166 }
7167 elsif($OSgroup eq "macos"
7168 and $Path=~/\.framework\Z/)
7169 {# to Apple's GCC
7170 return "-F".esc(get_dirname($Path));
7171 }
7172 else {
7173 return "-I".esc($Path);
7174 }
7175 }
7176 elsif($Style eq "CL") {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04007177 return "/I \"".$Path."\"";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007178 }
7179 return "";
7180}
7181
7182sub platformSpecs($)
7183{
7184 my $LibVersion = $_[0];
7185 my $Arch = getArch($LibVersion);
7186 if($OStarget eq "symbian")
7187 { # options for GCCE compiler
7188 my %Symbian_Opts = map {$_=>1} (
7189 "-D__GCCE__",
7190 "-DUNICODE",
7191 "-fexceptions",
7192 "-D__SYMBIAN32__",
7193 "-D__MARM_INTERWORK__",
7194 "-D_UNICODE",
7195 "-D__S60_50__",
7196 "-D__S60_3X__",
7197 "-D__SERIES60_3X__",
7198 "-D__EPOC32__",
7199 "-D__MARM__",
7200 "-D__EABI__",
7201 "-D__MARM_ARMV5__",
7202 "-D__SUPPORT_CPP_EXCEPTIONS__",
7203 "-march=armv5t",
7204 "-mapcs",
7205 "-mthumb-interwork",
7206 "-DEKA2",
7207 "-DSYMBIAN_ENABLE_SPLIT_HEADERS"
7208 );
7209 return join(" ", keys(%Symbian_Opts));
7210 }
7211 elsif($OSgroup eq "windows"
7212 and get_dumpmachine($GCC_PATH)=~/mingw/i)
7213 { # add options to MinGW compiler
7214 # to simulate the MSVC compiler
7215 my %MinGW_Opts = map {$_=>1} (
7216 "-D_WIN32",
7217 "-D_STDCALL_SUPPORTED",
7218 "-D__int64=\"long long\"",
7219 "-D__int32=int",
7220 "-D__int16=short",
7221 "-D__int8=char",
7222 "-D__possibly_notnullterminated=\" \"",
7223 "-D__nullterminated=\" \"",
7224 "-D__nullnullterminated=\" \"",
7225 "-D__w64=\" \"",
7226 "-D__ptr32=\" \"",
7227 "-D__ptr64=\" \"",
7228 "-D__forceinline=inline",
7229 "-D__inline=inline",
7230 "-D__uuidof(x)=IID()",
7231 "-D__try=",
7232 "-D__except(x)=",
7233 "-D__declspec(x)=__attribute__((x))",
7234 "-D__pragma(x)=",
7235 "-D_inline=inline",
7236 "-D__forceinline=__inline",
7237 "-D__stdcall=__attribute__((__stdcall__))",
7238 "-D__cdecl=__attribute__((__cdecl__))",
7239 "-D__fastcall=__attribute__((__fastcall__))",
7240 "-D__thiscall=__attribute__((__thiscall__))",
7241 "-D_stdcall=__attribute__((__stdcall__))",
7242 "-D_cdecl=__attribute__((__cdecl__))",
7243 "-D_fastcall=__attribute__((__fastcall__))",
7244 "-D_thiscall=__attribute__((__thiscall__))",
7245 "-DSHSTDAPI_(x)=x",
7246 "-D_MSC_EXTENSIONS",
7247 "-DSECURITY_WIN32",
7248 "-D_MSC_VER=1500",
7249 "-D_USE_DECLSPECS_FOR_SAL",
7250 "-D__noop=\" \"",
7251 "-DDECLSPEC_DEPRECATED=\" \"",
7252 "-D__builtin_alignof(x)=__alignof__(x)",
7253 "-DSORTPP_PASS");
7254 if($Arch eq "x86") {
7255 $MinGW_Opts{"-D_M_IX86=300"}=1;
7256 }
7257 elsif($Arch eq "x86_64") {
7258 $MinGW_Opts{"-D_M_AMD64=300"}=1;
7259 }
7260 elsif($Arch eq "ia64") {
7261 $MinGW_Opts{"-D_M_IA64=300"}=1;
7262 }
7263 return join(" ", keys(%MinGW_Opts));
7264 }
7265 return "";
7266}
7267
7268my %C_Structure = map {$_=>1} (
7269# FIXME: Can't separate union and struct data types before dumping,
7270# so it sometimes cause compilation errors for unknown reason
7271# when trying to declare TYPE* tmp_add_class_N
7272# This is a list of such structures + list of other C structures
7273 "sigval",
7274 "sigevent",
7275 "sigaction",
7276 "sigvec",
7277 "sigstack",
7278 "timeval",
7279 "timezone",
7280 "rusage",
7281 "rlimit",
7282 "wait",
7283 "flock",
7284 "stat",
7285 "_stat",
7286 "stat32",
7287 "_stat32",
7288 "stat64",
7289 "_stat64",
7290 "_stati64",
7291 "if_nameindex",
7292 "usb_device",
7293 "sigaltstack",
7294 "sysinfo",
7295 "timeLocale",
7296 "tcp_debug",
7297 "rpc_createerr",
Andrey Ponomarenko82b005f2012-11-12 17:58:14 +04007298 # Other
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007299 "timespec",
7300 "random_data",
7301 "drand48_data",
7302 "_IO_marker",
7303 "_IO_FILE",
7304 "lconv",
7305 "sched_param",
7306 "tm",
7307 "itimerspec",
7308 "_pthread_cleanup_buffer",
7309 "fd_set",
Andrey Ponomarenko01117f12012-06-26 12:23:02 +04007310 "siginfo",
Andrey Ponomarenko82b005f2012-11-12 17:58:14 +04007311 "mallinfo",
7312 # Mac
7313 "_timex",
7314 "_class_t",
7315 "_category_t",
7316 "_class_ro_t",
7317 "_protocol_t",
7318 "_message_ref_t",
7319 "_super_message_ref_t",
7320 "_ivar_t",
7321 "_ivar_list_t"
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007322);
7323
7324sub getCompileCmd($$$)
7325{
7326 my ($Path, $Opt, $Inc) = @_;
7327 my $GccCall = $GCC_PATH;
7328 if($Opt) {
7329 $GccCall .= " ".$Opt;
7330 }
7331 $GccCall .= " -x ";
7332 if($OSgroup eq "macos") {
7333 $GccCall .= "objective-";
7334 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04007335 if(check_gcc($GCC_PATH, "4"))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007336 { # compile as "C++" header
7337 # to obtain complete dump using GCC 4.0
7338 $GccCall .= "c++-header";
7339 }
7340 else
7341 { # compile as "C++" source
7342 # GCC 3.3 cannot compile headers
7343 $GccCall .= "c++";
7344 }
7345 if(my $Opts = platformSpecs($Version))
7346 {# platform-specific options
7347 $GccCall .= " ".$Opts;
7348 }
7349 # allow extra qualifications
7350 # and other nonconformant code
Andrey Ponomarenko01117f12012-06-26 12:23:02 +04007351 $GccCall .= " -fpermissive";
7352 $GccCall .= " -w";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007353 if($NoStdInc)
7354 {
7355 $GccCall .= " -nostdinc";
7356 $GccCall .= " -nostdinc++";
7357 }
7358 if($CompilerOptions{$Version})
7359 { # user-defined options
7360 $GccCall .= " ".$CompilerOptions{$Version};
7361 }
Andrey Ponomarenkoa01311b2012-06-08 17:20:02 +04007362 $GccCall .= " \"$Path\"";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007363 if($Inc)
7364 { # include paths
7365 $GccCall .= " ".$Inc;
7366 }
7367 return $GccCall;
7368}
7369
Andrey Ponomarenko01117f12012-06-26 12:23:02 +04007370sub detectPreamble($$)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007371{
Andrey Ponomarenko01117f12012-06-26 12:23:02 +04007372 my ($Content, $LibVersion) = @_;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007373 my %HeaderElems = (
7374 # Types
7375 "stdio.h" => ["FILE", "va_list"],
Andrey Ponomarenko85043792012-05-14 16:48:07 +04007376 "stddef.h" => ["NULL", "ptrdiff_t"],
Andrey Ponomarenko9927e332012-10-19 10:50:48 +04007377 "stdint.h" => ["uint8_t", "uint16_t", "uint32_t", "uint64_t",
7378 "int8_t", "int16_t", "int32_t", "int64_t"],
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007379 "time.h" => ["time_t"],
7380 "sys/types.h" => ["ssize_t", "u_int32_t", "u_short", "u_char",
Andrey Ponomarenko9927e332012-10-19 10:50:48 +04007381 "u_int", "off_t", "u_quad_t", "u_long", "mode_t"],
7382 "unistd.h" => ["gid_t", "uid_t", "socklen_t"],
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007383 "stdbool.h" => ["_Bool"],
7384 "rpc/xdr.h" => ["bool_t"],
7385 "in_systm.h" => ["n_long", "n_short"],
7386 # Fields
Andrey Ponomarenkobede8372012-03-29 17:43:21 +04007387 "arpa/inet.h" => ["fw_src", "ip_src"],
7388 # Functions
Andrey Ponomarenko9927e332012-10-19 10:50:48 +04007389 "stdlib.h" => ["free", "malloc", "size_t"],
Andrey Ponomarenko85043792012-05-14 16:48:07 +04007390 "string.h" => ["memmove", "strcmp"]
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007391 );
7392 my %AutoPreamble = ();
Andrey Ponomarenko85043792012-05-14 16:48:07 +04007393 foreach (keys(%HeaderElems))
7394 {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007395 foreach my $Elem (@{$HeaderElems{$_}}) {
Andrey Ponomarenko9927e332012-10-19 10:50:48 +04007396 $AutoPreamble{$Elem} = $_;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007397 }
7398 }
Andrey Ponomarenko01117f12012-06-26 12:23:02 +04007399 my %Types = ();
7400 while($Content=~s/error\:\s*(field\s*|)\W+(.+?)\W+//)
7401 { # error: 'FILE' has not been declared
Andrey Ponomarenko9927e332012-10-19 10:50:48 +04007402 $Types{$2} = 1;
Andrey Ponomarenko01117f12012-06-26 12:23:02 +04007403 }
7404 if(keys(%Types))
7405 {
7406 my %AddHeaders = ();
7407 foreach my $Type (keys(%Types))
7408 {
7409 if(my $Header = $AutoPreamble{$Type})
7410 {
Andrey Ponomarenko9927e332012-10-19 10:50:48 +04007411 if(my $Path = identifyHeader($Header, $LibVersion))
7412 {
7413 if(skipHeader($Path, $LibVersion)) {
7414 next;
7415 }
7416 $Path = path_format($Path, $OSgroup);
7417 $AddHeaders{$Path}{"Type"} = $Type;
7418 $AddHeaders{$Path}{"Header"} = $Header;
Andrey Ponomarenko01117f12012-06-26 12:23:02 +04007419 }
7420 }
7421 }
7422 if(keys(%AddHeaders)) {
Andrey Ponomarenko9927e332012-10-19 10:50:48 +04007423 return \%AddHeaders;
Andrey Ponomarenko01117f12012-06-26 12:23:02 +04007424 }
7425 }
Andrey Ponomarenko9927e332012-10-19 10:50:48 +04007426 return undef;
Andrey Ponomarenko01117f12012-06-26 12:23:02 +04007427}
7428
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +04007429sub checkCTags($)
7430{
7431 my $Path = $_[0];
7432 if(not $Path) {
7433 return;
7434 }
7435 my $CTags = get_CmdPath("ctags");
7436 if(not $CTags) {
7437 return;
7438 }
Andrey Ponomarenkobdc85a92012-11-12 17:28:12 +04007439
Andrey Ponomarenko82b005f2012-11-12 17:58:14 +04007440 if($OSgroup ne "linux")
7441 { # macos, freebsd, etc.
Andrey Ponomarenkobdc85a92012-11-12 17:28:12 +04007442 my $Info = `$CTags --version 2>\"$TMP_DIR/null\"`;
7443 if($Info!~/exuberant/i)
7444 {
7445 printMsg("WARNING", "incompatible version of \'ctags\' program");
7446 return;
7447 }
7448 }
7449
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +04007450 my $Out = $TMP_DIR."/ctags.txt";
Andrey Ponomarenkobdc85a92012-11-12 17:28:12 +04007451 system("$CTags --c-kinds=pxn -f \"$Out\" \"$Path\" 2>\"$TMP_DIR/null\"");
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +04007452 if($Debug) {
Andrey Ponomarenko9927e332012-10-19 10:50:48 +04007453 copy($Out, $DEBUG_PATH{$Version}."/ctags.txt");
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +04007454 }
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +04007455 open(CTAGS, "<", $Out);
7456 while(my $Line = <CTAGS>)
7457 {
7458 chomp($Line);
7459 my ($Name, $Header, $Def, $Type, $Scpe) = split(/\t/, $Line);
Andrey Ponomarenko9927e332012-10-19 10:50:48 +04007460 if(defined $Intrinsic_Keywords{$Name})
7461 { # noise
7462 next;
7463 }
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +04007464 if($Type eq "n")
7465 {
Andrey Ponomarenko9927e332012-10-19 10:50:48 +04007466 if(index($Scpe, "class:")==0) {
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +04007467 next;
7468 }
Andrey Ponomarenko9927e332012-10-19 10:50:48 +04007469 if(index($Scpe, "struct:")==0) {
7470 next;
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +04007471 }
Andrey Ponomarenko9927e332012-10-19 10:50:48 +04007472 if(index($Scpe, "namespace:")==0)
7473 {
7474 if($Scpe=~s/\Anamespace://) {
7475 $Name = $Scpe."::".$Name;
7476 }
7477 }
7478 $TUnit_NameSpaces{$Version}{$Name} = 1;
7479 }
7480 elsif($Type eq "p")
7481 {
7482 if(not $Scpe or index($Scpe, "namespace:")==0) {
7483 $TUnit_Funcs{$Version}{$Name} = 1;
7484 }
7485 }
7486 elsif($Type eq "x")
7487 {
7488 if(not $Scpe or index($Scpe, "namespace:")==0) {
7489 $TUnit_Vars{$Version}{$Name} = 1;
7490 }
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +04007491 }
7492 }
7493 close(CTAGS);
7494}
7495
Andrey Ponomarenko01117f12012-06-26 12:23:02 +04007496sub getDump()
7497{
7498 if(not $GCC_PATH) {
7499 exitStatus("Error", "internal error - GCC path is not set");
7500 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04007501 my $TmpHeaderPath = $TMP_DIR."/dump".$Version.".h";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007502 my $MHeaderPath = $TmpHeaderPath;
Andrey Ponomarenko85043792012-05-14 16:48:07 +04007503 open(TMP_HEADER, ">", $TmpHeaderPath) || die ("can't open file \'$TmpHeaderPath\': $!\n");
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007504 if(my $AddDefines = $Descriptor{$Version}{"Defines"})
7505 {
7506 $AddDefines=~s/\n\s+/\n /g;
Andrey Ponomarenko85043792012-05-14 16:48:07 +04007507 print TMP_HEADER "\n // add defines\n ".$AddDefines."\n";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007508 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +04007509 print TMP_HEADER "\n // add includes\n";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007510 my @PreambleHeaders = keys(%{$Include_Preamble{$Version}});
7511 @PreambleHeaders = sort {int($Include_Preamble{$Version}{$a}{"Position"})<=>int($Include_Preamble{$Version}{$b}{"Position"})} @PreambleHeaders;
7512 foreach my $Header_Path (@PreambleHeaders) {
Andrey Ponomarenko85043792012-05-14 16:48:07 +04007513 print TMP_HEADER " #include \"".path_format($Header_Path, "unix")."\"\n";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007514 }
7515 my @Headers = keys(%{$Registered_Headers{$Version}});
7516 @Headers = sort {int($Registered_Headers{$Version}{$a}{"Pos"})<=>int($Registered_Headers{$Version}{$b}{"Pos"})} @Headers;
7517 foreach my $Header_Path (@Headers)
7518 {
7519 next if($Include_Preamble{$Version}{$Header_Path});
Andrey Ponomarenko85043792012-05-14 16:48:07 +04007520 print TMP_HEADER " #include \"".path_format($Header_Path, "unix")."\"\n";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007521 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +04007522 close(TMP_HEADER);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007523 my $IncludeString = getIncString(getIncPaths(@PreambleHeaders, @Headers), "GCC");
Andrey Ponomarenko9927e332012-10-19 10:50:48 +04007524
Andrey Ponomarenko07aea072012-11-12 16:15:07 +04007525 if($ExtraInfo)
7526 { # extra information for other tools
7527 writeFile($ExtraInfo."/include-string", $IncludeString);
7528 }
7529
Andrey Ponomarenko9927e332012-10-19 10:50:48 +04007530 if(not keys(%{$TargetHeaders{$Version}}))
7531 { # Target headers
7532 addTargetHeaders($Version);
7533 }
7534
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007535 if($Debug)
7536 { # debug mode
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04007537 writeFile($DEBUG_PATH{$Version}."/headers/direct-includes.txt", Dumper($Header_Includes{$Version}));
7538 writeFile($DEBUG_PATH{$Version}."/headers/recursive-includes.txt", Dumper($RecursiveIncludes{$Version}));
7539 writeFile($DEBUG_PATH{$Version}."/headers/include-paths.txt", Dumper($Cache{"get_HeaderDeps"}{$Version}));
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04007540 writeFile($DEBUG_PATH{$Version}."/headers/default-paths.txt", Dumper(\%DefaultIncPaths));
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007541 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +04007542
Andrey Ponomarenko85043792012-05-14 16:48:07 +04007543 # clean memory
7544 %RecursiveIncludes = ();
7545 %Header_Include_Prefix = ();
7546 %Header_Includes = ();
7547
7548 # clean cache
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04007549 delete($Cache{"identifyHeader"});
Andrey Ponomarenko85043792012-05-14 16:48:07 +04007550 delete($Cache{"detect_header_includes"});
7551 delete($Cache{"selectSystemHeader"});
7552
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007553 # preprocessing stage
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +04007554 my $Pre = callPreprocessor($TmpHeaderPath, $IncludeString, $Version);
7555 checkPreprocessedUnit($Pre);
Andrey Ponomarenko85043792012-05-14 16:48:07 +04007556
7557 # clean memory
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04007558 delete($Include_Neighbors{$Version});
Andrey Ponomarenko85043792012-05-14 16:48:07 +04007559
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +04007560 if($COMMON_LANGUAGE{$Version} eq "C++") {
7561 checkCTags($Pre);
7562 }
7563
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007564 my $MContent = "";
7565 my $PreprocessCmd = getCompileCmd($TmpHeaderPath, "-E", $IncludeString);
7566 if($OStarget eq "windows"
7567 and get_dumpmachine($GCC_PATH)=~/mingw/i
7568 and $MinGWMode{$Version}!=-1)
7569 { # modify headers to compile by MinGW
7570 if(not $MContent)
7571 { # preprocessing
Andrey Ponomarenkoa01311b2012-06-08 17:20:02 +04007572 $MContent = `$PreprocessCmd 2>\"$TMP_DIR/null\"`;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007573 }
7574 if($MContent=~s/__asm\s*(\{[^{}]*?\}|[^{};]*)//g)
7575 { # __asm { ... }
7576 $MinGWMode{$Version}=1;
7577 }
7578 if($MContent=~s/\s+(\/ \/.*?)\n/\n/g)
7579 { # comments after preprocessing
7580 $MinGWMode{$Version}=1;
7581 }
7582 if($MContent=~s/(\W)(0x[a-f]+|\d+)(i|ui)(8|16|32|64)(\W)/$1$2$5/g)
7583 { # 0xffui8
7584 $MinGWMode{$Version}=1;
7585 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +04007586 if($MinGWMode{$Version})
7587 {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007588 printMsg("INFO", "Using MinGW compatibility mode");
Andrey Ponomarenkob8d203d2012-05-25 18:11:07 +04007589 $MHeaderPath = $TMP_DIR."/dump$Version.i";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007590 }
7591 }
7592 if(($COMMON_LANGUAGE{$Version} eq "C" or $CheckHeadersOnly)
Andrey Ponomarenko07aea072012-11-12 16:15:07 +04007593 and $CppMode{$Version}!=-1 and not $CppCompat)
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04007594 { # rename C++ keywords in C code
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007595 if(not $MContent)
7596 { # preprocessing
Andrey Ponomarenkoa01311b2012-06-08 17:20:02 +04007597 $MContent = `$PreprocessCmd 2>\"$TMP_DIR/null\"`;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007598 }
7599 my $RegExp_C = join("|", keys(%CppKeywords_C));
7600 my $RegExp_F = join("|", keys(%CppKeywords_F));
7601 my $RegExp_O = join("|", keys(%CppKeywords_O));
Andrey Ponomarenkobdc85a92012-11-12 17:28:12 +04007602
7603 my $Detected = undef;
7604
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007605 while($MContent=~s/(\A|\n[^\#\/\n][^\n]*?|\n)(\*\s*|\s+|\@|\,|\()($RegExp_C|$RegExp_F)(\s*(\,|\)|\;|\-\>|\.|\:\s*\d))/$1$2c99_$3$4/g)
7606 { # MATCH:
7607 # int foo(int new, int class, int (*new)(int));
7608 # unsigned private: 8;
7609 # DO NOT MATCH:
7610 # #pragma GCC visibility push(default)
Andrey Ponomarenko07aea072012-11-12 16:15:07 +04007611 $CppMode{$Version} = 1;
Andrey Ponomarenkobdc85a92012-11-12 17:28:12 +04007612 $Detected = "$1$2$3$4" if(not defined $Detected);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007613 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04007614 if($MContent=~s/([^\w\s]|\w\s+)(?<!operator )(delete)(\s*\()/$1c99_$2$3/g)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007615 { # MATCH:
7616 # int delete(...);
7617 # int explicit(...);
7618 # DO NOT MATCH:
7619 # void operator delete(...)
Andrey Ponomarenko07aea072012-11-12 16:15:07 +04007620 $CppMode{$Version} = 1;
Andrey Ponomarenkobdc85a92012-11-12 17:28:12 +04007621 $Detected = "$1$2$3" if(not defined $Detected);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007622 }
7623 if($MContent=~s/(\s+)($RegExp_O)(\s*(\;|\:))/$1c99_$2$3/g)
7624 { # MATCH:
7625 # int bool;
7626 # DO NOT MATCH:
7627 # bool X;
7628 # return *this;
7629 # throw;
Andrey Ponomarenko07aea072012-11-12 16:15:07 +04007630 $CppMode{$Version} = 1;
Andrey Ponomarenkobdc85a92012-11-12 17:28:12 +04007631 $Detected = "$1$2$3" if(not defined $Detected);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007632 }
7633 if($MContent=~s/(\s+)(operator)(\s*(\(\s*\)\s*[^\(\s]|\(\s*[^\)\s]))/$1c99_$2$3/g)
7634 { # MATCH:
7635 # int operator(...);
7636 # DO NOT MATCH:
7637 # int operator()(...);
Andrey Ponomarenko07aea072012-11-12 16:15:07 +04007638 $CppMode{$Version} = 1;
Andrey Ponomarenkobdc85a92012-11-12 17:28:12 +04007639 $Detected = "$1$2$3" if(not defined $Detected);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007640 }
7641 if($MContent=~s/([^\w\(\,\s]\s*|\s+)(operator)(\s*(\,\s*[^\(\s]|\)))/$1c99_$2$3/g)
7642 { # MATCH:
7643 # int foo(int operator);
7644 # int foo(int operator, int other);
7645 # DO NOT MATCH:
7646 # int operator,(...);
Andrey Ponomarenko07aea072012-11-12 16:15:07 +04007647 $CppMode{$Version} = 1;
Andrey Ponomarenkobdc85a92012-11-12 17:28:12 +04007648 $Detected = "$1$2$3" if(not defined $Detected);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007649 }
7650 if($MContent=~s/(\*\s*|\w\s+)(bool)(\s*(\,|\)))/$1c99_$2$3/g)
7651 { # MATCH:
7652 # int foo(gboolean *bool);
7653 # DO NOT MATCH:
7654 # void setTabEnabled(int index, bool);
Andrey Ponomarenko07aea072012-11-12 16:15:07 +04007655 $CppMode{$Version} = 1;
Andrey Ponomarenkobdc85a92012-11-12 17:28:12 +04007656 $Detected = "$1$2$3" if(not defined $Detected);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007657 }
Andrey Ponomarenko9927e332012-10-19 10:50:48 +04007658 if($MContent=~s/(\w)(\s*[^\w\(\,\s]\s*|\s+)(this|throw)(\s*[\,\)])/$1$2c99_$3$4/g)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007659 { # MATCH:
7660 # int foo(int* this);
7661 # int bar(int this);
Andrey Ponomarenko9927e332012-10-19 10:50:48 +04007662 # int baz(int throw);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007663 # DO NOT MATCH:
Andrey Ponomarenko9927e332012-10-19 10:50:48 +04007664 # foo(X, this);
Andrey Ponomarenko07aea072012-11-12 16:15:07 +04007665 $CppMode{$Version} = 1;
Andrey Ponomarenkobdc85a92012-11-12 17:28:12 +04007666 $Detected = "$1$2$3$4" if(not defined $Detected);
Andrey Ponomarenko07aea072012-11-12 16:15:07 +04007667 }
7668
7669 if($CppMode{$Version} == 1)
7670 {
Andrey Ponomarenkobdc85a92012-11-12 17:28:12 +04007671 if($Debug)
7672 {
7673 $Detected=~s/\A\s+//g;
7674 printMsg("INFO", "Detected code: \"$Detected\"");
Andrey Ponomarenko07aea072012-11-12 16:15:07 +04007675 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007676 }
Andrey Ponomarenko9927e332012-10-19 10:50:48 +04007677
7678 # remove typedef enum NAME NAME;
7679 my @FwdTypedefs = $MContent=~/typedef\s+enum\s+(\w+)\s+(\w+);/g;
7680 my $N = 0;
7681 while($N<=$#FwdTypedefs-1)
7682 {
7683 my $S = $FwdTypedefs[$N];
7684 if($S eq $FwdTypedefs[$N+1])
7685 {
7686 $MContent=~s/typedef\s+enum\s+\Q$S\E\s+\Q$S\E;//g;
Andrey Ponomarenko07aea072012-11-12 16:15:07 +04007687 $CppMode{$Version}=1;
Andrey Ponomarenko9927e332012-10-19 10:50:48 +04007688 }
7689 $N+=2;
7690 }
7691
Andrey Ponomarenko07aea072012-11-12 16:15:07 +04007692 if($CppMode{$Version}==1)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007693 { # try to change C++ "keyword" to "c99_keyword"
Andrey Ponomarenko07aea072012-11-12 16:15:07 +04007694 printMsg("INFO", "Using C++ compatibility mode");
Andrey Ponomarenkob8d203d2012-05-25 18:11:07 +04007695 $MHeaderPath = $TMP_DIR."/dump$Version.i";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007696 }
7697 }
Andrey Ponomarenko07aea072012-11-12 16:15:07 +04007698 if($CppMode{$Version}==1
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007699 or $MinGWMode{$Version}==1)
7700 { # compile the corrected preprocessor output
7701 writeFile($MHeaderPath, $MContent);
7702 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +04007703
7704 # clean memory
7705 undef $MContent;
7706
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007707 if($COMMON_LANGUAGE{$Version} eq "C++")
7708 { # add classes and namespaces to the dump
7709 my $CHdump = "-fdump-class-hierarchy -c";
Andrey Ponomarenko07aea072012-11-12 16:15:07 +04007710 if($CppMode{$Version}==1
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007711 or $MinGWMode{$Version}==1) {
7712 $CHdump .= " -fpreprocessed";
7713 }
7714 my $ClassHierarchyCmd = getCompileCmd($MHeaderPath, $CHdump, $IncludeString);
7715 chdir($TMP_DIR);
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04007716 system($ClassHierarchyCmd." >null 2>&1");
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007717 chdir($ORIG_DIR);
7718 if(my $ClassDump = (cmd_find($TMP_DIR,"f","*.class",1))[0])
7719 {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007720 my $Content = readFile($ClassDump);
7721 foreach my $ClassInfo (split(/\n\n/, $Content))
7722 {
7723 if($ClassInfo=~/\AClass\s+(.+)\s*/i)
7724 {
7725 my $CName = $1;
7726 next if($CName=~/\A(__|_objc_|_opaque_)/);
7727 $TUnit_NameSpaces{$Version}{$CName} = -1;
7728 if($CName=~/\A[\w:]+\Z/)
7729 { # classes
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +04007730 $TUnit_Classes{$Version}{$CName} = 1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007731 }
7732 if($CName=~/(\w[\w:]*)::/)
7733 { # namespaces
7734 my $NS = $1;
7735 if(not defined $TUnit_NameSpaces{$Version}{$NS}) {
7736 $TUnit_NameSpaces{$Version}{$NS} = 1;
7737 }
7738 }
7739 }
7740 elsif($ClassInfo=~/\AVtable\s+for\s+(.+)\n((.|\n)+)\Z/i)
7741 { # read v-tables (advanced approach)
7742 my ($CName, $VTable) = ($1, $2);
7743 $ClassVTable_Content{$Version}{$CName} = $VTable;
7744 }
7745 }
Andrey Ponomarenkoa01311b2012-06-08 17:20:02 +04007746 foreach my $NS (keys(%{$AddNameSpaces{$Version}}))
7747 { # add user-defined namespaces
7748 $TUnit_NameSpaces{$Version}{$NS} = 1;
7749 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007750 if($Debug)
7751 { # debug mode
7752 mkpath($DEBUG_PATH{$Version});
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04007753 copy($ClassDump, $DEBUG_PATH{$Version}."/class-hierarchy-dump.txt");
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007754 }
7755 unlink($ClassDump);
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +04007756 }
7757
7758 # add namespaces and classes
7759 if(my $NS_Add = get_namespace_additions($TUnit_NameSpaces{$Version}))
7760 { # GCC on all supported platforms does not include namespaces to the dump by default
7761 appendFile($MHeaderPath, "\n // add namespaces\n".$NS_Add);
7762 }
7763 # some GCC versions don't include class methods to the TU dump by default
7764 my ($AddClass, $ClassNum) = ("", 0);
7765 foreach my $CName (sort keys(%{$TUnit_Classes{$Version}}))
7766 {
7767 next if($C_Structure{$CName});
7768 next if(not $STDCXX_TESTING and $CName=~/\Astd::/);
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +04007769 next if($SkipTypes{$Version}{$CName});
Andrey Ponomarenko82b005f2012-11-12 17:58:14 +04007770 if($OSgroup eq "linux")
7771 {
7772 next if(($CName=~tr![:]!!)>2);
7773 if($CName=~/\A(.+)::[^:]+\Z/)
7774 { # will be added by name space
7775 next;
7776 }
7777 }
7778 else
7779 {
7780 if($CName=~/\A(.+)::[^:]+\Z/
7781 and $TUnit_Classes{$Version}{$1})
7782 { # classes inside other classes
7783 next;
7784 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007785 }
Andrey Ponomarenko9927e332012-10-19 10:50:48 +04007786 if(defined $TUnit_Funcs{$Version}{$CName})
7787 { # the same name for a function and type
7788 next;
7789 }
7790 if(defined $TUnit_Vars{$Version}{$CName})
7791 { # the same name for a variable and type
7792 next;
7793 }
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +04007794 $AddClass .= " $CName* tmp_add_class_".($ClassNum++).";\n";
7795 }
7796 if($AddClass) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007797 appendFile($MHeaderPath, "\n // add classes\n".$AddClass);
7798 }
7799 }
7800 writeLog($Version, "Temporary header file \'$TmpHeaderPath\' with the following content will be compiled to create GCC translation unit dump:\n".readFile($TmpHeaderPath)."\n");
7801 # create TU dump
7802 my $TUdump = "-fdump-translation-unit -fkeep-inline-functions -c";
Andrey Ponomarenko07aea072012-11-12 16:15:07 +04007803 if($CppMode{$Version}==1
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007804 or $MinGWMode{$Version}==1) {
7805 $TUdump .= " -fpreprocessed";
7806 }
7807 my $SyntaxTreeCmd = getCompileCmd($MHeaderPath, $TUdump, $IncludeString);
7808 writeLog($Version, "The GCC parameters:\n $SyntaxTreeCmd\n\n");
7809 chdir($TMP_DIR);
Andrey Ponomarenkoa01311b2012-06-08 17:20:02 +04007810 system($SyntaxTreeCmd." >\"$TMP_DIR/tu_errors\" 2>&1");
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007811 if($?)
7812 { # failed to compile, but the TU dump still can be created
Andrey Ponomarenko01117f12012-06-26 12:23:02 +04007813 if(my $Errors = readFile($TMP_DIR."/tu_errors"))
7814 { # try to recompile
7815 # FIXME: handle other errors and try to recompile
Andrey Ponomarenko07aea072012-11-12 16:15:07 +04007816 if($CppMode{$Version}==1
Andrey Ponomarenko01117f12012-06-26 12:23:02 +04007817 and $Errors=~/c99_/)
7818 { # disable c99 mode and try again
Andrey Ponomarenko07aea072012-11-12 16:15:07 +04007819 $CppMode{$Version}=-1;
7820 printMsg("INFO", "Disabling C++ compatibility mode");
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007821 resetLogging($Version);
7822 $TMP_DIR = tempdir(CLEANUP=>1);
7823 return getDump();
7824 }
Andrey Ponomarenko01117f12012-06-26 12:23:02 +04007825 elsif($AutoPreambleMode{$Version}!=-1
Andrey Ponomarenko9927e332012-10-19 10:50:48 +04007826 and my $AddHeaders = detectPreamble($Errors, $Version))
Andrey Ponomarenko01117f12012-06-26 12:23:02 +04007827 { # add auto preamble headers and try again
7828 $AutoPreambleMode{$Version}=-1;
Andrey Ponomarenko9927e332012-10-19 10:50:48 +04007829 my @Headers = sort {$b cmp $a} keys(%{$AddHeaders}); # sys/types.h should be the first
Andrey Ponomarenko01117f12012-06-26 12:23:02 +04007830 foreach my $Num (0 .. $#Headers)
7831 {
7832 my $Path = $Headers[$Num];
7833 if(defined $Include_Preamble{$Version}{$Path})
7834 { # already added
7835 next;
7836 }
7837 $Include_Preamble{$Version}{$Path}{"Position"} = keys(%{$Include_Preamble{$Version}});
Andrey Ponomarenko9927e332012-10-19 10:50:48 +04007838 printMsg("INFO", "Add \'".$AddHeaders->{$Path}{"Header"}."\' preamble header for \'".$AddHeaders->{$Path}{"Type"}."\'");
Andrey Ponomarenko01117f12012-06-26 12:23:02 +04007839 }
7840 resetLogging($Version);
7841 $TMP_DIR = tempdir(CLEANUP=>1);
7842 return getDump();
7843 }
7844 elsif($Cpp0xMode{$Version}!=-1
7845 and ($Errors=~/\Q-std=c++0x\E/
7846 or $Errors=~/is not a class or namespace/))
7847 { # c++0x: enum class
7848 $Cpp0xMode{$Version}=-1;
7849 printMsg("INFO", "Enabling c++0x mode");
7850 resetLogging($Version);
7851 $TMP_DIR = tempdir(CLEANUP=>1);
7852 $CompilerOptions{$Version} .= " -std=c++0x";
7853 return getDump();
7854 }
7855 elsif($MinGWMode{$Version}==1)
7856 { # disable MinGW mode and try again
7857 $MinGWMode{$Version}=-1;
7858 resetLogging($Version);
7859 $TMP_DIR = tempdir(CLEANUP=>1);
7860 return getDump();
7861 }
7862 writeLog($Version, $Errors);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007863 }
Andrey Ponomarenko01117f12012-06-26 12:23:02 +04007864 else {
7865 writeLog($Version, "$!: $?\n");
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007866 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007867 printMsg("ERROR", "some errors occurred when compiling headers");
7868 printErrorLog($Version);
7869 $COMPILE_ERRORS = $ERROR_CODE{"Compile_Error"};
7870 writeLog($Version, "\n");# new line
7871 }
7872 chdir($ORIG_DIR);
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +04007873 unlink($TmpHeaderPath);
7874 unlink($MHeaderPath);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007875 return (cmd_find($TMP_DIR,"f","*.tu",1))[0];
7876}
7877
7878sub cmd_file($)
7879{
7880 my $Path = $_[0];
7881 return "" if(not $Path or not -e $Path);
7882 if(my $CmdPath = get_CmdPath("file")) {
7883 return `$CmdPath -b \"$Path\"`;
7884 }
7885 return "";
7886}
7887
7888sub getIncString($$)
7889{
7890 my ($ArrRef, $Style) = @_;
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04007891 return "" if(not $ArrRef or $#{$ArrRef}<0);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007892 my $String = "";
7893 foreach (@{$ArrRef}) {
7894 $String .= " ".inc_opt($_, $Style);
7895 }
7896 return $String;
7897}
7898
7899sub getIncPaths(@)
7900{
7901 my @HeaderPaths = @_;
7902 my @IncPaths = ();
7903 if($INC_PATH_AUTODETECT{$Version})
7904 { # auto-detecting dependencies
7905 my %Includes = ();
7906 foreach my $HPath (@HeaderPaths)
7907 {
7908 foreach my $Dir (get_HeaderDeps($HPath, $Version))
7909 {
7910 if($Skip_Include_Paths{$Version}{$Dir}) {
7911 next;
7912 }
Andrey Ponomarenkoa01311b2012-06-08 17:20:02 +04007913 if($SystemRoot)
7914 {
7915 if($Skip_Include_Paths{$Version}{$SystemRoot.$Dir}) {
7916 next;
7917 }
7918 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007919 $Includes{$Dir}=1;
7920 }
7921 }
7922 foreach my $Dir (keys(%{$Add_Include_Paths{$Version}}))
7923 { # added by user
7924 next if($Includes{$Dir});
7925 push(@IncPaths, $Dir);
7926 }
7927 foreach my $Dir (@{sortIncPaths([keys(%Includes)], $Version)}) {
7928 push(@IncPaths, $Dir);
7929 }
7930 }
7931 else
7932 { # user-defined paths
7933 foreach my $Dir (sort {get_depth($a)<=>get_depth($b)}
7934 sort {$b cmp $a} keys(%{$Include_Paths{$Version}})) {
7935 push(@IncPaths, $Dir);
7936 }
7937 }
7938 return \@IncPaths;
7939}
7940
7941sub callPreprocessor($$$)
7942{
7943 my ($Path, $Inc, $LibVersion) = @_;
7944 return "" if(not $Path or not -f $Path);
7945 my $IncludeString=$Inc;
7946 if(not $Inc) {
7947 $IncludeString = getIncString(getIncPaths($Path), "GCC");
7948 }
7949 my $Cmd = getCompileCmd($Path, "-dD -E", $IncludeString);
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +04007950 my $Out = $TMP_DIR."/preprocessed.h";
Andrey Ponomarenkoa01311b2012-06-08 17:20:02 +04007951 system($Cmd." >\"$Out\" 2>\"$TMP_DIR/null\"");
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04007952 return $Out;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007953}
7954
7955sub cmd_find($$$$)
7956{ # native "find" is much faster than File::Find (~6x)
7957 # also the File::Find doesn't support --maxdepth N option
7958 # so using the cross-platform wrapper for the native one
7959 my ($Path, $Type, $Name, $MaxDepth) = @_;
7960 return () if(not $Path or not -e $Path);
7961 if($OSgroup eq "windows")
7962 {
7963 my $DirCmd = get_CmdPath("dir");
7964 if(not $DirCmd) {
7965 exitStatus("Not_Found", "can't find \"dir\" command");
7966 }
7967 $Path=~s/[\\]+\Z//;
7968 $Path = get_abs_path($Path);
7969 $Path = path_format($Path, $OSgroup);
7970 my $Cmd = $DirCmd." \"$Path\" /B /O";
7971 if($MaxDepth!=1) {
7972 $Cmd .= " /S";
7973 }
7974 if($Type eq "d") {
7975 $Cmd .= " /AD";
7976 }
7977 my @Files = ();
7978 if($Name)
7979 { # FIXME: how to search file names in MS shell?
7980 $Name=~s/\*/.*/g if($Name!~/\]/);
7981 foreach my $File (split(/\n/, `$Cmd`))
7982 {
7983 if($File=~/$Name\Z/i) {
7984 push(@Files, $File);
7985 }
7986 }
7987 }
7988 else {
Andrey Ponomarenkoa01311b2012-06-08 17:20:02 +04007989 @Files = split(/\n/, `$Cmd 2>\"$TMP_DIR/null\"`);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007990 }
7991 my @AbsPaths = ();
7992 foreach my $File (@Files)
7993 {
7994 if(not is_abs($File)) {
7995 $File = joinPath($Path, $File);
7996 }
7997 if($Type eq "f" and not -f $File)
7998 { # skip dirs
7999 next;
8000 }
8001 push(@AbsPaths, path_format($File, $OSgroup));
8002 }
8003 if($Type eq "d") {
8004 push(@AbsPaths, $Path);
8005 }
8006 return @AbsPaths;
8007 }
8008 else
8009 {
8010 my $FindCmd = get_CmdPath("find");
8011 if(not $FindCmd) {
8012 exitStatus("Not_Found", "can't find a \"find\" command");
8013 }
8014 $Path = get_abs_path($Path);
8015 if(-d $Path and -l $Path
8016 and $Path!~/\/\Z/)
8017 { # for directories that are symlinks
8018 $Path.="/";
8019 }
8020 my $Cmd = $FindCmd." \"$Path\"";
8021 if($MaxDepth) {
8022 $Cmd .= " -maxdepth $MaxDepth";
8023 }
8024 if($Type) {
8025 $Cmd .= " -type $Type";
8026 }
8027 if($Name)
8028 { # file name
8029 if($Name=~/\]/) {
8030 $Cmd .= " -regex \"$Name\"";
8031 }
8032 else {
8033 $Cmd .= " -name \"$Name\"";
8034 }
8035 }
Andrey Ponomarenko9927e332012-10-19 10:50:48 +04008036 my $Res = `$Cmd 2>\"$TMP_DIR/null\"`;
8037 if($?) {
8038 printMsg("ERROR", "problem with \'find\' utility ($?): $!");
8039 }
8040 return split(/\n/, $Res);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008041 }
8042}
8043
8044sub unpackDump($)
8045{
8046 my $Path = $_[0];
8047 return "" if(not $Path or not -e $Path);
8048 $Path = get_abs_path($Path);
8049 $Path = path_format($Path, $OSgroup);
8050 my ($Dir, $FileName) = separate_path($Path);
8051 my $UnpackDir = $TMP_DIR."/unpack";
8052 rmtree($UnpackDir);
8053 mkpath($UnpackDir);
8054 if($FileName=~s/\Q.zip\E\Z//g)
8055 { # *.zip
8056 my $UnzipCmd = get_CmdPath("unzip");
8057 if(not $UnzipCmd) {
8058 exitStatus("Not_Found", "can't find \"unzip\" command");
8059 }
8060 chdir($UnpackDir);
Andrey Ponomarenkoa01311b2012-06-08 17:20:02 +04008061 system("$UnzipCmd \"$Path\" >contents.txt");
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008062 if($?) {
8063 exitStatus("Error", "can't extract \'$Path\'");
8064 }
8065 chdir($ORIG_DIR);
8066 my @Contents = ();
8067 foreach (split("\n", readFile("$UnpackDir/contents.txt")))
8068 {
8069 if(/inflating:\s*([^\s]+)/) {
8070 push(@Contents, $1);
8071 }
8072 }
8073 if(not @Contents) {
8074 exitStatus("Error", "can't extract \'$Path\'");
8075 }
8076 return joinPath($UnpackDir, $Contents[0]);
8077 }
8078 elsif($FileName=~s/\Q.tar.gz\E\Z//g)
8079 { # *.tar.gz
8080 if($OSgroup eq "windows")
8081 { # -xvzf option is not implemented in tar.exe (2003)
8082 # use "gzip.exe -k -d -f" + "tar.exe -xvf" instead
8083 my $TarCmd = get_CmdPath("tar");
8084 if(not $TarCmd) {
8085 exitStatus("Not_Found", "can't find \"tar\" command");
8086 }
8087 my $GzipCmd = get_CmdPath("gzip");
8088 if(not $GzipCmd) {
8089 exitStatus("Not_Found", "can't find \"gzip\" command");
8090 }
8091 chdir($UnpackDir);
Andrey Ponomarenkoa01311b2012-06-08 17:20:02 +04008092 system("$GzipCmd -k -d -f \"$Path\""); # keep input files (-k)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008093 if($?) {
8094 exitStatus("Error", "can't extract \'$Path\'");
8095 }
Andrey Ponomarenkoa01311b2012-06-08 17:20:02 +04008096 system("$TarCmd -xvf \"$Dir\\$FileName.tar\" >contents.txt");
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008097 if($?) {
8098 exitStatus("Error", "can't extract \'$Path\'");
8099 }
8100 chdir($ORIG_DIR);
8101 unlink($Dir."/".$FileName.".tar");
8102 my @Contents = split("\n", readFile("$UnpackDir/contents.txt"));
8103 if(not @Contents) {
8104 exitStatus("Error", "can't extract \'$Path\'");
8105 }
8106 return joinPath($UnpackDir, $Contents[0]);
8107 }
8108 else
8109 { # Unix
8110 my $TarCmd = get_CmdPath("tar");
8111 if(not $TarCmd) {
8112 exitStatus("Not_Found", "can't find \"tar\" command");
8113 }
8114 chdir($UnpackDir);
Andrey Ponomarenkoa01311b2012-06-08 17:20:02 +04008115 system("$TarCmd -xvzf \"$Path\" >contents.txt");
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008116 if($?) {
8117 exitStatus("Error", "can't extract \'$Path\'");
8118 }
8119 chdir($ORIG_DIR);
8120 # The content file name may be different
8121 # from the package file name
8122 my @Contents = split("\n", readFile("$UnpackDir/contents.txt"));
8123 if(not @Contents) {
8124 exitStatus("Error", "can't extract \'$Path\'");
8125 }
8126 return joinPath($UnpackDir, $Contents[0]);
8127 }
8128 }
8129}
8130
8131sub createArchive($$)
8132{
8133 my ($Path, $To) = @_;
Andrey Ponomarenko5c09ef32012-06-14 18:17:33 +04008134 if(not $To) {
8135 $To = ".";
8136 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008137 if(not $Path or not -e $Path
8138 or not -d $To) {
8139 return "";
8140 }
8141 my ($From, $Name) = separate_path($Path);
8142 if($OSgroup eq "windows")
8143 { # *.zip
8144 my $ZipCmd = get_CmdPath("zip");
8145 if(not $ZipCmd) {
8146 exitStatus("Not_Found", "can't find \"zip\"");
8147 }
8148 my $Pkg = $To."/".$Name.".zip";
8149 unlink($Pkg);
8150 chdir($To);
Andrey Ponomarenkoa01311b2012-06-08 17:20:02 +04008151 system("$ZipCmd -j \"$Name.zip\" \"$Path\" >\"$TMP_DIR/null\"");
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008152 if($?)
8153 { # cannot allocate memory (or other problems with "zip")
8154 unlink($Path);
8155 exitStatus("Error", "can't pack the ABI dump: ".$!);
8156 }
8157 chdir($ORIG_DIR);
8158 unlink($Path);
8159 return $Pkg;
8160 }
8161 else
8162 { # *.tar.gz
8163 my $TarCmd = get_CmdPath("tar");
8164 if(not $TarCmd) {
8165 exitStatus("Not_Found", "can't find \"tar\"");
8166 }
8167 my $GzipCmd = get_CmdPath("gzip");
8168 if(not $GzipCmd) {
8169 exitStatus("Not_Found", "can't find \"gzip\"");
8170 }
8171 my $Pkg = abs_path($To)."/".$Name.".tar.gz";
8172 unlink($Pkg);
8173 chdir($From);
8174 system($TarCmd, "-czf", $Pkg, $Name);
8175 if($?)
8176 { # cannot allocate memory (or other problems with "tar")
8177 unlink($Path);
8178 exitStatus("Error", "can't pack the ABI dump: ".$!);
8179 }
8180 chdir($ORIG_DIR);
8181 unlink($Path);
8182 return $To."/".$Name.".tar.gz";
8183 }
8184}
8185
Andrey Ponomarenko9927e332012-10-19 10:50:48 +04008186sub readBytes($)
8187{
8188 sysopen(FILE, $_[0], O_RDONLY);
8189 sysread(FILE, my $Header, 4);
8190 close(FILE);
8191 my @Bytes = map { sprintf('%02x', ord($_)) } split (//, $Header);
8192 return join("", @Bytes);
8193}
8194
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008195sub is_header_file($)
8196{
8197 if($_[0]=~/\.($HEADER_EXT)\Z/i) {
8198 return $_[0];
8199 }
8200 return 0;
8201}
8202
8203sub is_not_header($)
8204{
8205 if($_[0]=~/\.\w+\Z/
8206 and $_[0]!~/\.($HEADER_EXT)\Z/i) {
8207 return 1;
8208 }
8209 return 0;
8210}
8211
8212sub is_header($$$)
8213{
8214 my ($Header, $UserDefined, $LibVersion) = @_;
8215 return 0 if(-d $Header);
8216 if(-f $Header) {
8217 $Header = get_abs_path($Header);
8218 }
8219 else
8220 {
8221 if(is_abs($Header))
8222 { # incorrect absolute path
8223 return 0;
8224 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04008225 if(my $HPath = identifyHeader($Header, $LibVersion)) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008226 $Header = $HPath;
8227 }
8228 else
8229 { # can't find header
8230 return 0;
8231 }
8232 }
8233 if($Header=~/\.\w+\Z/)
8234 { # have an extension
8235 return is_header_file($Header);
8236 }
8237 else
8238 {
8239 if($UserDefined==2)
8240 { # specified on the command line
8241 if(cmd_file($Header)!~/HTML|XML/i) {
8242 return $Header;
8243 }
8244 }
8245 elsif($UserDefined)
8246 { # specified in the XML-descriptor
8247 # header file without an extension
8248 return $Header;
8249 }
8250 else
8251 {
Andrey Ponomarenko85043792012-05-14 16:48:07 +04008252 if($Header=~/\/include\//
8253 or cmd_file($Header)=~/C[\+]*\s+program/i)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008254 { # !~/HTML|XML|shared|dynamic/i
8255 return $Header;
8256 }
8257 }
8258 }
8259 return 0;
8260}
8261
Andrey Ponomarenko16934472012-03-29 15:37:04 +04008262sub addTargetHeaders($)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008263{
8264 my $LibVersion = $_[0];
8265 foreach my $RegHeader (keys(%{$Registered_Headers{$LibVersion}}))
8266 {
8267 my $RegDir = get_dirname($RegHeader);
8268 $TargetHeaders{$LibVersion}{get_filename($RegHeader)}=1;
Andrey Ponomarenko9927e332012-10-19 10:50:48 +04008269
8270 if(not $INC_PATH_AUTODETECT{$LibVersion}) {
8271 detect_recursive_includes($RegHeader, $LibVersion);
8272 }
8273
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008274 foreach my $RecInc (keys(%{$RecursiveIncludes{$LibVersion}{$RegHeader}}))
8275 {
8276 my $Dir = get_dirname($RecInc);
Andrey Ponomarenko85043792012-05-14 16:48:07 +04008277 if($Dir=~/\A\Q$RegDir\E([\/\\]|\Z)/
8278 or $RecursiveIncludes{$LibVersion}{$RegHeader}{$RecInc}!=1)
8279 { # in the same directory or included by #include "..."
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008280 $TargetHeaders{$LibVersion}{get_filename($RecInc)}=1;
8281 }
8282 }
8283 }
8284}
8285
8286sub readHeaders($)
8287{
8288 $Version = $_[0];
8289 printMsg("INFO", "checking header(s) ".$Descriptor{$Version}{"Version"}." ...");
8290 my $DumpPath = getDump();
8291 if(not $DumpPath) {
8292 exitStatus("Cannot_Compile", "can't compile header(s)");
8293 }
8294 if($Debug)
8295 { # debug mode
8296 mkpath($DEBUG_PATH{$Version});
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04008297 copy($DumpPath, $DEBUG_PATH{$Version}."/translation-unit-dump.txt");
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008298 }
8299 getInfo($DumpPath);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008300}
8301
8302sub prepareTypes($)
8303{
8304 my $LibVersion = $_[0];
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04008305 if(not checkDump($LibVersion, "2.0"))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008306 { # support for old ABI dumps
8307 # type names have been corrected in ACC 1.22 (dump 2.0 format)
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04008308 foreach my $TypeId (keys(%{$TypeInfo{$LibVersion}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008309 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04008310 my $TName = $TypeInfo{$LibVersion}{$TypeId}{"Name"};
8311 if($TName=~/\A(\w+)::(\w+)/) {
8312 my ($P1, $P2) = ($1, $2);
8313 if($P1 eq $P2) {
8314 $TName=~s/\A$P1:\:$P1(\W)/$P1$1/;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008315 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04008316 else {
8317 $TName=~s/\A(\w+:\:)$P2:\:$P2(\W)/$1$P2$2/;
8318 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008319 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04008320 $TypeInfo{$LibVersion}{$TypeId}{"Name"} = $TName;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008321 }
8322 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04008323 if(not checkDump($LibVersion, "2.5"))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008324 { # support for old ABI dumps
8325 # V < 2.5: array size == "number of elements"
8326 # V >= 2.5: array size in bytes
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04008327 foreach my $TypeId (sort {int($a)<=>int($b)} keys(%{$TypeInfo{$LibVersion}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008328 {
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +04008329 my %Type = get_PureType($TypeId, $TypeInfo{$LibVersion});
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04008330 if($Type{"Type"} eq "Array")
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008331 {
Andrey Ponomarenko01117f12012-06-26 12:23:02 +04008332 if(my $Size = $Type{"Size"})
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04008333 { # array[N]
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +04008334 my %Base = get_OneStep_BaseType($Type{"Tid"}, $TypeInfo{$LibVersion});
Andrey Ponomarenko01117f12012-06-26 12:23:02 +04008335 $Size *= $Base{"Size"};
8336 $TypeInfo{$LibVersion}{$TypeId}{"Size"} = "$Size";
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04008337 }
8338 else
8339 { # array[] is a pointer
8340 $TypeInfo{$LibVersion}{$TypeId}{"Size"} = $WORD_SIZE{$LibVersion};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008341 }
8342 }
8343 }
8344 }
8345 my $V2 = ($LibVersion==1)?2:1;
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04008346 if(not checkDump($LibVersion, "2.7"))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008347 { # support for old ABI dumps
8348 # size of "method ptr" corrected in 2.7
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04008349 foreach my $TypeId (sort {int($a)<=>int($b)} keys(%{$TypeInfo{$LibVersion}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008350 {
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +04008351 my %PureType = get_PureType($TypeId, $TypeInfo{$LibVersion});
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04008352 if($PureType{"Type"} eq "MethodPtr")
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008353 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04008354 my %Type = get_Type($TypeId, $LibVersion);
8355 my $TypeId_2 = getTypeIdByName($PureType{"Name"}, $V2);
8356 my %Type2 = get_Type($TypeId_2, $V2);
8357 if($Type{"Size"} ne $Type2{"Size"}) {
8358 $TypeInfo{$LibVersion}{$TypeId}{"Size"} = $Type2{"Size"};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008359 }
8360 }
8361 }
8362 }
8363}
8364
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04008365sub prepareSymbols($)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008366{
8367 my $LibVersion = $_[0];
Andrey Ponomarenko16934472012-03-29 15:37:04 +04008368
8369 if(not keys(%{$SymbolInfo{$LibVersion}}))
8370 { # check if input is valid
8371 if(not $ExtendedCheck and not $CheckObjectsOnly)
8372 {
8373 if($CheckHeadersOnly) {
8374 exitStatus("Empty_Set", "the set of public symbols is empty (".$Descriptor{$LibVersion}{"Version"}.")");
8375 }
8376 else {
8377 exitStatus("Empty_Intersection", "the sets of public symbols in headers and libraries have empty intersection (".$Descriptor{$LibVersion}{"Version"}.")");
8378 }
8379 }
8380 }
8381
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008382 my $Remangle = 0;
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04008383 if(not checkDump(1, "2.10")
8384 or not checkDump(2, "2.10"))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008385 { # different formats
8386 $Remangle = 1;
8387 }
8388 if($CheckHeadersOnly)
8389 { # different languages
8390 if($UserLang)
8391 { # --lang=LANG for both versions
8392 if(($UsedDump{1}{"V"} and $UserLang ne $UsedDump{1}{"L"})
8393 or ($UsedDump{2}{"V"} and $UserLang ne $UsedDump{2}{"L"}))
8394 {
8395 if($UserLang eq "C++")
8396 { # remangle symbols
8397 $Remangle = 1;
8398 }
8399 elsif($UserLang eq "C")
8400 { # remove mangling
8401 $Remangle = -1;
8402 }
8403 }
8404 }
8405 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04008406
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04008407 foreach my $InfoId (sort {int($b)<=>int($a)} keys(%{$SymbolInfo{$LibVersion}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008408 { # reverse order: D0, D1, D2, D0 (artificial, GCC < 4.5), C1, C2
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04008409 if(not checkDump($LibVersion, "2.13"))
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04008410 { # support for old ABI dumps
8411 if(defined $SymbolInfo{$LibVersion}{$InfoId}{"Param"})
8412 {
8413 foreach my $P (keys(%{$SymbolInfo{$LibVersion}{$InfoId}{"Param"}}))
8414 {
8415 my $TypeId = $SymbolInfo{$LibVersion}{$InfoId}{"Param"}{$P}{"type"};
8416 my $DVal = $SymbolInfo{$LibVersion}{$InfoId}{"Param"}{$P}{"default"};
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04008417 my $TName = $TypeInfo{$LibVersion}{$TypeId}{"Name"};
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04008418 if(defined $DVal and $DVal ne "")
8419 {
8420 if($TName eq "char") {
8421 $SymbolInfo{$LibVersion}{$InfoId}{"Param"}{$P}{"default"} = chr($DVal);
8422 }
8423 elsif($TName eq "bool") {
8424 $SymbolInfo{$LibVersion}{$InfoId}{"Param"}{$P}{"default"} = $DVal?"true":"false";
8425 }
8426 }
8427 }
8428 }
8429 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04008430 if($SymbolInfo{$LibVersion}{$InfoId}{"Destructor"})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008431 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04008432 if(defined $SymbolInfo{$LibVersion}{$InfoId}{"Param"}
8433 and keys(%{$SymbolInfo{$LibVersion}{$InfoId}{"Param"}})
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04008434 and $SymbolInfo{$LibVersion}{$InfoId}{"Param"}{0}{"name"})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008435 { # support for old GCC < 4.5: skip artificial ~dtor(int __in_chrg)
8436 # + support for old ABI dumps
8437 next;
8438 }
8439 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04008440 my $MnglName = $SymbolInfo{$LibVersion}{$InfoId}{"MnglName"};
Andrey Ponomarenko85043792012-05-14 16:48:07 +04008441 my $ShortName = $SymbolInfo{$LibVersion}{$InfoId}{"ShortName"};
Andrey Ponomarenko16934472012-03-29 15:37:04 +04008442 my $ClassID = $SymbolInfo{$LibVersion}{$InfoId}{"Class"};
Andrey Ponomarenko85043792012-05-14 16:48:07 +04008443 my $Return = $SymbolInfo{$LibVersion}{$InfoId}{"Return"};
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04008444
Andrey Ponomarenko16934472012-03-29 15:37:04 +04008445 my $SRemangle = 0;
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04008446 if(not checkDump(1, "2.12")
8447 or not checkDump(2, "2.12"))
Andrey Ponomarenko16934472012-03-29 15:37:04 +04008448 { # support for old ABI dumps
Andrey Ponomarenko85043792012-05-14 16:48:07 +04008449 if($ShortName eq "operator>>")
8450 {
8451 if(not $SymbolInfo{$LibVersion}{$InfoId}{"Class"})
8452 { # corrected mangling of operator>>
8453 $SRemangle = 1;
8454 }
Andrey Ponomarenko16934472012-03-29 15:37:04 +04008455 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +04008456 if($SymbolInfo{$LibVersion}{$InfoId}{"Data"})
8457 {
8458 if(not $SymbolInfo{$LibVersion}{$InfoId}{"Class"}
8459 and isConstType($Return, $LibVersion) and $MnglName!~/L\d+$ShortName/)
8460 { # corrected mangling of const global data
8461 # some global data is not mangled in the TU dump: qt_sine_table (Qt 4.8)
8462 # and incorrectly mangled by old ACC versions
8463 $SRemangle = 1;
8464 }
Andrey Ponomarenko16934472012-03-29 15:37:04 +04008465 }
8466 }
Andrey Ponomarenko5c09ef32012-06-14 18:17:33 +04008467 if(not $CheckHeadersOnly)
8468 { # support for old ABI dumps
8469 if(not checkDump(1, "2.17")
8470 or not checkDump(2, "2.17"))
8471 {
8472 if($SymbolInfo{$LibVersion}{$InfoId}{"Data"})
8473 {
8474 if(not $SymbolInfo{$LibVersion}{$InfoId}{"Class"})
8475 {
8476 if(link_symbol($ShortName, $LibVersion, "-Deps"))
8477 {
8478 $MnglName = $ShortName;
8479 $SymbolInfo{$LibVersion}{$InfoId}{"MnglName"} = $MnglName;
8480 }
8481 }
8482 }
8483 }
8484 }
Andrey Ponomarenko16934472012-03-29 15:37:04 +04008485 if($Remangle==1 or $SRemangle==1)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008486 { # support for old ABI dumps: some symbols are not mangled in old dumps
8487 # mangle both sets of symbols (old and new)
8488 # NOTE: remangling all symbols by the same mangler
8489 if($MnglName=~/\A_ZN(V|)K/)
8490 { # mangling may be incorrect on old ABI dumps
8491 # because of absent "Const" attribute
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04008492 $SymbolInfo{$LibVersion}{$InfoId}{"Const"} = 1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008493 }
8494 if($MnglName=~/\A_ZN(K|)V/)
8495 { # mangling may be incorrect on old ABI dumps
8496 # because of absent "Volatile" attribute
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04008497 $SymbolInfo{$LibVersion}{$InfoId}{"Volatile"} = 1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008498 }
Andrey Ponomarenko16934472012-03-29 15:37:04 +04008499 if(($ClassID and $MnglName!~/\A(_Z|\?)/)
8500 or (not $ClassID and $CheckHeadersOnly)
8501 or (not $ClassID and not link_symbol($MnglName, $LibVersion, "-Deps")))
8502 { # support for old ABI dumps, GCC >= 4.0
8503 # remangling all manually mangled symbols
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04008504 if($MnglName = mangle_symbol($InfoId, $LibVersion, "GCC"))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008505 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04008506 $SymbolInfo{$LibVersion}{$InfoId}{"MnglName"} = $MnglName;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008507 $MangledNames{$LibVersion}{$MnglName} = 1;
8508 }
8509 }
8510 }
8511 elsif($Remangle==-1)
8512 { # remove mangling
8513 $MnglName = "";
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04008514 $SymbolInfo{$LibVersion}{$InfoId}{"MnglName"} = "";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008515 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008516 if(not $MnglName) {
8517 next;
8518 }
8519 if(not $CompleteSignature{$LibVersion}{$MnglName}{"MnglName"})
8520 { # NOTE: global data may enter here twice
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04008521 %{$CompleteSignature{$LibVersion}{$MnglName}} = %{$SymbolInfo{$LibVersion}{$InfoId}};
8522
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008523 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04008524 if(not checkDump($LibVersion, "2.6"))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008525 { # support for old dumps
8526 # add "Volatile" attribute
8527 if($MnglName=~/_Z(K|)V/) {
8528 $CompleteSignature{$LibVersion}{$MnglName}{"Volatile"}=1;
8529 }
8530 }
8531 # symbol and its symlink have same signatures
8532 if($SymVer{$LibVersion}{$MnglName}) {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04008533 %{$CompleteSignature{$LibVersion}{$SymVer{$LibVersion}{$MnglName}}} = %{$SymbolInfo{$LibVersion}{$InfoId}};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008534 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +04008535
8536 # clean memory
Andrey Ponomarenko16934472012-03-29 15:37:04 +04008537 delete($SymbolInfo{$LibVersion}{$InfoId});
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008538 }
8539 if($COMMON_LANGUAGE{$LibVersion} eq "C++" or $OSgroup eq "windows") {
8540 translateSymbols(keys(%{$CompleteSignature{$LibVersion}}), $LibVersion);
8541 }
8542 if($ExtendedCheck)
8543 { # --ext option
8544 addExtension($LibVersion);
8545 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +04008546
8547 # clean memory
8548 delete($SymbolInfo{$LibVersion});
8549
8550 foreach my $Symbol (keys(%{$CompleteSignature{$LibVersion}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008551 { # detect allocable classes with public exported constructors
8552 # or classes with auto-generated or inline-only constructors
Andrey Ponomarenko9927e332012-10-19 10:50:48 +04008553 # and other temp info
Andrey Ponomarenko85043792012-05-14 16:48:07 +04008554 if(my $ClassId = $CompleteSignature{$LibVersion}{$Symbol}{"Class"})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008555 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04008556 my $ClassName = $TypeInfo{$LibVersion}{$ClassId}{"Name"};
Andrey Ponomarenko85043792012-05-14 16:48:07 +04008557 if($CompleteSignature{$LibVersion}{$Symbol}{"Constructor"}
8558 and not $CompleteSignature{$LibVersion}{$Symbol}{"InLine"})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008559 { # Class() { ... } will not be exported
Andrey Ponomarenko85043792012-05-14 16:48:07 +04008560 if(not $CompleteSignature{$LibVersion}{$Symbol}{"Private"})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008561 {
Andrey Ponomarenko85043792012-05-14 16:48:07 +04008562 if($CheckHeadersOnly or link_symbol($Symbol, $LibVersion, "-Deps")) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008563 $AllocableClass{$LibVersion}{$ClassName} = 1;
8564 }
8565 }
8566 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +04008567 if(not $CompleteSignature{$LibVersion}{$Symbol}{"Private"})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008568 { # all imported class methods
Andrey Ponomarenko85043792012-05-14 16:48:07 +04008569 if(symbolFilter($Symbol, $LibVersion, "Affected", "Binary"))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008570 {
Andrey Ponomarenko85043792012-05-14 16:48:07 +04008571 if($CheckHeadersOnly)
8572 {
8573 if(not $CompleteSignature{$LibVersion}{$Symbol}{"InLine"}
8574 or $CompleteSignature{$LibVersion}{$Symbol}{"Virt"})
8575 { # all symbols except non-virtual inline
8576 $ClassMethods{"Binary"}{$LibVersion}{$ClassName}{$Symbol} = 1;
8577 }
8578 }
8579 else {
8580 $ClassMethods{"Binary"}{$LibVersion}{$ClassName}{$Symbol} = 1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008581 }
8582 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04008583 if(symbolFilter($Symbol, $LibVersion, "Affected", "Source")) {
Andrey Ponomarenko85043792012-05-14 16:48:07 +04008584 $ClassMethods{"Source"}{$LibVersion}{$ClassName}{$Symbol} = 1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008585 }
8586 }
Andrey Ponomarenko16934472012-03-29 15:37:04 +04008587 $ClassNames{$LibVersion}{$ClassName} = 1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008588 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +04008589 if(my $RetId = $CompleteSignature{$LibVersion}{$Symbol}{"Return"})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008590 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04008591 my %Base = get_BaseType($RetId, $LibVersion);
Andrey Ponomarenko85043792012-05-14 16:48:07 +04008592 if(defined $Base{"Type"}
8593 and $Base{"Type"}=~/Struct|Class/)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008594 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04008595 my $Name = $TypeInfo{$LibVersion}{$Base{"Tid"}}{"Name"};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008596 if($Name=~/<([^<>\s]+)>/)
8597 {
8598 if(my $Tid = getTypeIdByName($1, $LibVersion)) {
8599 $ReturnedClass{$LibVersion}{$Tid} = 1;
8600 }
8601 }
8602 else {
8603 $ReturnedClass{$LibVersion}{$Base{"Tid"}} = 1;
8604 }
8605 }
8606 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +04008607 foreach my $Num (keys(%{$CompleteSignature{$LibVersion}{$Symbol}{"Param"}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008608 {
Andrey Ponomarenko85043792012-05-14 16:48:07 +04008609 my $PId = $CompleteSignature{$LibVersion}{$Symbol}{"Param"}{$Num}{"type"};
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04008610 if(get_PLevel($PId, $LibVersion)>=1)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008611 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04008612 if(my %Base = get_BaseType($PId, $LibVersion))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008613 {
Andrey Ponomarenko16934472012-03-29 15:37:04 +04008614 if($Base{"Type"}=~/Struct|Class/)
8615 {
Andrey Ponomarenko85043792012-05-14 16:48:07 +04008616 $ParamClass{$LibVersion}{$Base{"Tid"}}{$Symbol} = 1;
Andrey Ponomarenko16934472012-03-29 15:37:04 +04008617 foreach my $SubId (get_sub_classes($Base{"Tid"}, $LibVersion, 1))
8618 { # mark all derived classes
Andrey Ponomarenko85043792012-05-14 16:48:07 +04008619 $ParamClass{$LibVersion}{$SubId}{$Symbol} = 1;
Andrey Ponomarenko16934472012-03-29 15:37:04 +04008620 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008621 }
8622 }
8623 }
8624 }
Andrey Ponomarenko9927e332012-10-19 10:50:48 +04008625
8626 # mapping {short name => symbols}
8627 $Func_ShortName{$LibVersion}{$CompleteSignature{$LibVersion}{$Symbol}{"ShortName"}}{$Symbol} = 1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008628 }
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04008629 foreach my $MnglName (keys(%VTableClass))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008630 { # reconstruct header name for v-tables
Andrey Ponomarenko9927e332012-10-19 10:50:48 +04008631 if(index($MnglName, "_ZTV")==0)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008632 {
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04008633 if(my $ClassName = $VTableClass{$MnglName})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008634 {
8635 if(my $ClassId = $TName_Tid{$LibVersion}{$ClassName}) {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04008636 $CompleteSignature{$LibVersion}{$MnglName}{"Header"} = $TypeInfo{$LibVersion}{$ClassId}{"Header"};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008637 }
8638 }
8639 }
8640 }
Andrey Ponomarenko16934472012-03-29 15:37:04 +04008641
8642 # types
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04008643 foreach my $TypeId (keys(%{$TypeInfo{$LibVersion}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008644 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04008645 if(my $TName = $TypeInfo{$LibVersion}{$TypeId}{"Name"})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008646 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04008647 if(defined $TypeInfo{$LibVersion}{$TypeId}{"VTable"}) {
8648 $ClassNames{$LibVersion}{$TName} = 1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008649 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04008650 if(defined $TypeInfo{$LibVersion}{$TypeId}{"Base"})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008651 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04008652 $ClassNames{$LibVersion}{$TName} = 1;
8653 foreach my $Bid (keys(%{$TypeInfo{$LibVersion}{$TypeId}{"Base"}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008654 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04008655 if(my $BName = $TypeInfo{$LibVersion}{$Bid}{"Name"}) {
8656 $ClassNames{$LibVersion}{$BName} = 1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008657 }
8658 }
8659 }
8660 }
8661 }
8662}
8663
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04008664sub register_TypeUsage($$)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008665{
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04008666 my ($TypeId, $LibVersion) = @_;
8667 if(not $TypeId) {
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04008668 return 0;
8669 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04008670 if($UsedType{$LibVersion}{$TypeId})
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04008671 { # already registered
8672 return 1;
8673 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04008674 my %TInfo = get_Type($TypeId, $LibVersion);
Andrey Ponomarenko85043792012-05-14 16:48:07 +04008675 if($TInfo{"Type"})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008676 {
Andrey Ponomarenko85043792012-05-14 16:48:07 +04008677 if($TInfo{"Type"}=~/\A(Struct|Union|Class|FuncPtr|MethodPtr|FieldPtr|Enum)\Z/)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008678 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04008679 $UsedType{$LibVersion}{$TypeId} = 1;
Andrey Ponomarenko85043792012-05-14 16:48:07 +04008680 if($TInfo{"Type"}=~/\A(Struct|Class)\Z/)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008681 {
Andrey Ponomarenko85043792012-05-14 16:48:07 +04008682 foreach my $BaseId (keys(%{$TInfo{"Base"}}))
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04008683 { # register base classes
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04008684 register_TypeUsage($BaseId, $LibVersion);
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04008685 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +04008686 foreach my $TPos (keys(%{$TInfo{"TParam"}}))
8687 {
8688 my $TPName = $TInfo{"TParam"}{$TPos}{"name"};
8689 if(my $TTid = $TName_Tid{$LibVersion}{$TPName}) {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04008690 register_TypeUsage($TTid, $LibVersion);
Andrey Ponomarenko85043792012-05-14 16:48:07 +04008691 }
8692 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008693 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +04008694 foreach my $Memb_Pos (keys(%{$TInfo{"Memb"}}))
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04008695 {
Andrey Ponomarenko85043792012-05-14 16:48:07 +04008696 if(my $MTid = $TInfo{"Memb"}{$Memb_Pos}{"type"}) {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04008697 register_TypeUsage($MTid, $LibVersion);
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04008698 }
8699 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +04008700 if($TInfo{"Type"} eq "FuncPtr"
8701 or $TInfo{"Type"} eq "MethodPtr")
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04008702 {
Andrey Ponomarenko85043792012-05-14 16:48:07 +04008703 if(my $RTid = $TInfo{"Return"}) {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04008704 register_TypeUsage($RTid, $LibVersion);
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04008705 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +04008706 foreach my $Memb_Pos (keys(%{$TInfo{"Param"}}))
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04008707 {
Andrey Ponomarenko85043792012-05-14 16:48:07 +04008708 if(my $MTid = $TInfo{"Param"}{$Memb_Pos}{"type"}) {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04008709 register_TypeUsage($MTid, $LibVersion);
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04008710 }
8711 }
8712 }
8713 return 1;
8714 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +04008715 elsif($TInfo{"Type"}=~/\A(Const|ConstVolatile|Volatile|Pointer|Ref|Restrict|Array|Typedef)\Z/)
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04008716 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04008717 $UsedType{$LibVersion}{$TypeId} = 1;
8718 register_TypeUsage($TInfo{"BaseType"}{"Tid"}, $LibVersion);
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04008719 return 1;
8720 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04008721 elsif($TInfo{"Type"} eq "Intrinsic")
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04008722 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04008723 $UsedType{$LibVersion}{$TypeId} = 1;
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04008724 return 1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008725 }
8726 }
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04008727 return 0;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008728}
8729
Andrey Ponomarenko85043792012-05-14 16:48:07 +04008730sub selectSymbol($$$$)
Andrey Ponomarenko35c44fd2012-06-18 17:50:25 +04008731{ # select symbol to check or to dump
Andrey Ponomarenko85043792012-05-14 16:48:07 +04008732 my ($Symbol, $SInfo, $Level, $LibVersion) = @_;
8733
Andrey Ponomarenko35c44fd2012-06-18 17:50:25 +04008734 if($Level eq "Dump")
8735 {
8736 if($SInfo->{"Virt"} or $SInfo->{"PureVirt"})
8737 { # TODO: check if this symbol is from
8738 # base classes of other target symbols
8739 return 1;
8740 }
8741 }
8742
Andrey Ponomarenko85043792012-05-14 16:48:07 +04008743 if(not $STDCXX_TESTING and $Symbol=~/\A(_ZS|_ZNS|_ZNKS)/)
8744 { # stdc++ interfaces
8745 return 0;
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04008746 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +04008747
8748 my $Target = 0;
8749 if(my $Header = $SInfo->{"Header"}) {
8750 $Target = (is_target_header($Header, 1) or is_target_header($Header, 2));
8751 }
8752 if($CheckHeadersOnly)
8753 {
8754 if($Target)
8755 {
8756 if($Level eq "Dump")
8757 { # dumped
8758 if($BinaryOnly)
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04008759 {
Andrey Ponomarenko85043792012-05-14 16:48:07 +04008760 if(not $SInfo->{"InLine"} or $SInfo->{"Data"}) {
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04008761 return 1;
8762 }
8763 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +04008764 else {
8765 return 1;
8766 }
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04008767 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +04008768 elsif($Level eq "Source")
8769 { # checked
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04008770 return 1;
8771 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +04008772 elsif($Level eq "Binary")
8773 { # checked
8774 if(not $SInfo->{"InLine"} or $SInfo->{"Data"}
8775 or $SInfo->{"Virt"} or $SInfo->{"PureVirt"}) {
8776 return 1;
8777 }
8778 }
8779 }
8780 }
8781 else
8782 { # library is available
8783 if(link_symbol($Symbol, $LibVersion, "-Deps"))
8784 { # exported symbols
8785 return 1;
8786 }
8787 if($Level eq "Dump")
8788 { # dumped
Andrey Ponomarenko35c44fd2012-06-18 17:50:25 +04008789 if($BinaryOnly)
8790 {
8791 if($SInfo->{"Data"})
8792 {
8793 if($Target) {
8794 return 1;
8795 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +04008796 }
8797 }
Andrey Ponomarenko35c44fd2012-06-18 17:50:25 +04008798 else
8799 { # SrcBin
Andrey Ponomarenko85043792012-05-14 16:48:07 +04008800 if($Target) {
8801 return 1;
8802 }
8803 }
8804 }
8805 elsif($Level eq "Source")
8806 { # checked
Andrey Ponomarenko01117f12012-06-26 12:23:02 +04008807 if($SInfo->{"PureVirt"} or $SInfo->{"Data"} or $SInfo->{"InLine"}
8808 or isInLineInst($Symbol, $SInfo, $LibVersion))
Andrey Ponomarenko35c44fd2012-06-18 17:50:25 +04008809 { # skip LOCAL symbols
8810 if($Target) {
8811 return 1;
8812 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +04008813 }
8814 }
8815 elsif($Level eq "Binary")
8816 { # checked
8817 if($SInfo->{"PureVirt"} or $SInfo->{"Data"})
8818 {
8819 if($Target) {
8820 return 1;
8821 }
8822 }
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04008823 }
8824 }
8825 return 0;
8826}
8827
Andrey Ponomarenko85043792012-05-14 16:48:07 +04008828sub cleanDump($)
8829{ # clean data
Andrey Ponomarenko16934472012-03-29 15:37:04 +04008830 my $LibVersion = $_[0];
8831 foreach my $InfoId (keys(%{$SymbolInfo{$LibVersion}}))
8832 {
8833 my $MnglName = $SymbolInfo{$LibVersion}{$InfoId}{"MnglName"};
8834 if(not $MnglName) {
8835 delete($SymbolInfo{$LibVersion}{$InfoId});
8836 next;
8837 }
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04008838 my $ShortName = $SymbolInfo{$LibVersion}{$InfoId}{"ShortName"};
Andrey Ponomarenko85043792012-05-14 16:48:07 +04008839 if(not $ShortName) {
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04008840 delete($SymbolInfo{$LibVersion}{$InfoId});
8841 next;
Andrey Ponomarenko16934472012-03-29 15:37:04 +04008842 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +04008843 if($MnglName eq $ShortName)
8844 { # remove duplicate data
8845 delete($SymbolInfo{$LibVersion}{$InfoId}{"MnglName"});
Andrey Ponomarenko16934472012-03-29 15:37:04 +04008846 }
8847 if(not keys(%{$SymbolInfo{$LibVersion}{$InfoId}{"Param"}})) {
8848 delete($SymbolInfo{$LibVersion}{$InfoId}{"Param"});
8849 }
Andrey Ponomarenko01117f12012-06-26 12:23:02 +04008850 if(not keys(%{$SymbolInfo{$LibVersion}{$InfoId}{"TParam"}})) {
8851 delete($SymbolInfo{$LibVersion}{$InfoId}{"TParam"});
8852 }
Andrey Ponomarenko16934472012-03-29 15:37:04 +04008853 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04008854 foreach my $Tid (keys(%{$TypeInfo{$LibVersion}}))
Andrey Ponomarenko85043792012-05-14 16:48:07 +04008855 {
Andrey Ponomarenko01117f12012-06-26 12:23:02 +04008856 delete($TypeInfo{$LibVersion}{$Tid}{"Tid"});
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04008857 foreach my $Attr ("Header", "Line", "Size", "NameSpace")
Andrey Ponomarenko16934472012-03-29 15:37:04 +04008858 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04008859 if(not $TypeInfo{$LibVersion}{$Tid}{$Attr}) {
8860 delete($TypeInfo{$LibVersion}{$Tid}{$Attr});
8861 }
8862 }
Andrey Ponomarenko01117f12012-06-26 12:23:02 +04008863 if(not keys(%{$TypeInfo{$LibVersion}{$Tid}{"TParam"}})) {
8864 delete($TypeInfo{$LibVersion}{$Tid}{"TParam"});
8865 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04008866 }
8867}
8868
8869sub selectType($$)
8870{
8871 my ($Tid, $LibVersion) = @_;
Andrey Ponomarenko9927e332012-10-19 10:50:48 +04008872
8873 if(my $Dupl = $TypeTypedef{$LibVersion}{$Tid})
8874 {
8875 if(defined $TypeInfo{$LibVersion}{$Dupl})
8876 {
8877 if($TypeInfo{$LibVersion}{$Dupl}{"Name"} eq $TypeInfo{$LibVersion}{$Tid}{"Name"})
8878 { # duplicate
8879 return 0;
8880 }
8881 }
8882 }
8883
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04008884 if(my $THeader = $TypeInfo{$LibVersion}{$Tid}{"Header"})
8885 {
8886 if(not isBuiltIn($THeader))
8887 {
8888 if($TypeInfo{$LibVersion}{$Tid}{"Type"}=~/Class|Struct|Union|Enum|Typedef/)
Andrey Ponomarenko16934472012-03-29 15:37:04 +04008889 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04008890 if(not isAnon($TypeInfo{$LibVersion}{$Tid}{"Name"}))
8891 {
8892 if(is_target_header($THeader, $LibVersion))
8893 { # from target headers
8894 if(not selfTypedef($Tid, $LibVersion)) {
8895 return 1;
8896 }
8897 }
Andrey Ponomarenko16934472012-03-29 15:37:04 +04008898 }
8899 }
8900 }
8901 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04008902 return 0;
Andrey Ponomarenko16934472012-03-29 15:37:04 +04008903}
8904
Andrey Ponomarenko85043792012-05-14 16:48:07 +04008905sub removeUnused($$)
8906{ # remove unused data types from the ABI dump
8907 my ($LibVersion, $Kind) = @_;
8908 foreach my $InfoId (keys(%{$SymbolInfo{$LibVersion}}))
8909 {
8910 my %FuncInfo = %{$SymbolInfo{$LibVersion}{$InfoId}};
8911 if(my $RTid = $FuncInfo{"Return"}) {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04008912 register_TypeUsage($RTid, $LibVersion);
Andrey Ponomarenko85043792012-05-14 16:48:07 +04008913 }
8914 if(my $FCid = $FuncInfo{"Class"})
8915 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04008916 register_TypeUsage($FCid, $LibVersion);
8917 if(my $ThisId = getTypeIdByName($TypeInfo{$LibVersion}{$FCid}{"Name"}."*const", $LibVersion))
Andrey Ponomarenko85043792012-05-14 16:48:07 +04008918 { # register "this" pointer
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04008919 $UsedType{$LibVersion}{$ThisId} = 1;
8920 if(my %ThisType = get_Type($ThisId, $LibVersion)) {
8921 register_TypeUsage($ThisType{"BaseType"}{"Tid"}, $LibVersion);
Andrey Ponomarenko85043792012-05-14 16:48:07 +04008922 }
8923 }
8924 }
8925 foreach my $PPos (keys(%{$FuncInfo{"Param"}}))
8926 {
8927 if(my $PTid = $FuncInfo{"Param"}{$PPos}{"type"}) {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04008928 register_TypeUsage($PTid, $LibVersion);
Andrey Ponomarenko85043792012-05-14 16:48:07 +04008929 }
8930 }
8931 foreach my $TPos (keys(%{$FuncInfo{"TParam"}}))
8932 {
8933 my $TPName = $FuncInfo{"TParam"}{$TPos}{"name"};
8934 if(my $TTid = $TName_Tid{$LibVersion}{$TPName}) {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04008935 register_TypeUsage($TTid, $LibVersion);
Andrey Ponomarenko85043792012-05-14 16:48:07 +04008936 }
8937 }
8938 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04008939 foreach my $Tid (keys(%{$TypeInfo{$LibVersion}}))
8940 {
8941 if($UsedType{$LibVersion}{$Tid})
8942 { # All & Derived
8943 next;
8944 }
8945
8946 if($Kind eq "Derived")
Andrey Ponomarenko85043792012-05-14 16:48:07 +04008947 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04008948 if(selectType($Tid, $LibVersion)) {
8949 register_TypeUsage($Tid, $LibVersion);
Andrey Ponomarenko85043792012-05-14 16:48:07 +04008950 }
8951 }
8952 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04008953 foreach my $Tid (keys(%{$TypeInfo{$LibVersion}}))
8954 { # remove unused types
8955 if($UsedType{$LibVersion}{$Tid})
8956 { # All & Derived
8957 next;
8958 }
8959 # remove type
8960 delete($TypeInfo{$LibVersion}{$Tid});
8961 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +04008962
8963 # clean memory
8964 %UsedType = ();
8965}
8966
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04008967sub selfTypedef($$)
Andrey Ponomarenko85043792012-05-14 16:48:07 +04008968{
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04008969 my ($TypeId, $LibVersion) = @_;
8970 my %Type = get_Type($TypeId, $LibVersion);
Andrey Ponomarenko85043792012-05-14 16:48:07 +04008971 if($Type{"Type"} eq "Typedef")
8972 {
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +04008973 my %Base = get_OneStep_BaseType($TypeId, $TypeInfo{$LibVersion});
Andrey Ponomarenko85043792012-05-14 16:48:07 +04008974 if($Base{"Type"}=~/Class|Struct/)
8975 {
8976 if($Type{"Name"} eq $Base{"Name"}) {
8977 return 1;
8978 }
8979 elsif($Type{"Name"}=~/::(\w+)\Z/)
8980 {
8981 if($Type{"Name"} eq $Base{"Name"}."::".$1)
8982 { # QPointer<QWidget>::QPointer
8983 return 1;
8984 }
8985 }
8986 }
8987 }
8988 return 0;
8989}
8990
Andrey Ponomarenko16934472012-03-29 15:37:04 +04008991sub addExtension($)
8992{
8993 my $LibVersion = $_[0];
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04008994 foreach my $Tid (keys(%{$TypeInfo{$LibVersion}}))
Andrey Ponomarenko16934472012-03-29 15:37:04 +04008995 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04008996 if(selectType($Tid, $LibVersion))
Andrey Ponomarenko16934472012-03-29 15:37:04 +04008997 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04008998 my $Symbol = "external_func_".$TypeInfo{$LibVersion}{$Tid}{"Name"};
8999
9000 %{$CompleteSignature{$LibVersion}{$Symbol}} = (
9001 "Header" => "extended.h",
9002 "ShortName" => $Symbol,
9003 "MnglName" => $Symbol,
9004 "Param" => { 0 => { "type"=>$Tid, "name"=>"p1" } }
9005 );
9006
9007 $ExtendedSymbols{$Symbol}=1;
9008 $CheckedSymbols{"Binary"}{$Symbol}=1;
9009 $CheckedSymbols{"Source"}{$Symbol}=1;
Andrey Ponomarenko16934472012-03-29 15:37:04 +04009010 }
9011 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04009012 $ExtendedSymbols{"external_func_0"}=1;
9013 $CheckedSymbols{"Binary"}{"external_func_0"}=1;
9014 $CheckedSymbols{"Source"}{"external_func_0"}=1;
Andrey Ponomarenko16934472012-03-29 15:37:04 +04009015}
9016
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009017sub findMethod($$$)
9018{
9019 my ($VirtFunc, $ClassId, $LibVersion) = @_;
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04009020 foreach my $BaseClass_Id (keys(%{$TypeInfo{$LibVersion}{$ClassId}{"Base"}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009021 {
9022 if(my $VirtMethodInClass = findMethod_Class($VirtFunc, $BaseClass_Id, $LibVersion)) {
9023 return $VirtMethodInClass;
9024 }
9025 elsif(my $VirtMethodInBaseClasses = findMethod($VirtFunc, $BaseClass_Id, $LibVersion)) {
9026 return $VirtMethodInBaseClasses;
9027 }
9028 }
9029 return "";
9030}
9031
9032sub findMethod_Class($$$)
9033{
9034 my ($VirtFunc, $ClassId, $LibVersion) = @_;
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04009035 my $ClassName = $TypeInfo{$LibVersion}{$ClassId}{"Name"};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009036 return "" if(not defined $VirtualTable{$LibVersion}{$ClassName});
9037 my $TargetSuffix = get_symbol_suffix($VirtFunc, 1);
9038 my $TargetShortName = $CompleteSignature{$LibVersion}{$VirtFunc}{"ShortName"};
9039 foreach my $Candidate (keys(%{$VirtualTable{$LibVersion}{$ClassName}}))
9040 { # search for interface with the same parameters suffix (overridden)
9041 if($TargetSuffix eq get_symbol_suffix($Candidate, 1))
9042 {
Andrey Ponomarenkoe3d6bf02012-11-14 11:49:09 +04009043 if($CompleteSignature{$LibVersion}{$VirtFunc}{"Destructor"})
9044 {
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04009045 if($CompleteSignature{$LibVersion}{$Candidate}{"Destructor"})
9046 {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009047 if(($VirtFunc=~/D0E/ and $Candidate=~/D0E/)
9048 or ($VirtFunc=~/D1E/ and $Candidate=~/D1E/)
9049 or ($VirtFunc=~/D2E/ and $Candidate=~/D2E/)) {
9050 return $Candidate;
9051 }
9052 }
9053 }
Andrey Ponomarenkoe3d6bf02012-11-14 11:49:09 +04009054 else
9055 {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009056 if($TargetShortName eq $CompleteSignature{$LibVersion}{$Candidate}{"ShortName"}) {
9057 return $Candidate;
9058 }
9059 }
9060 }
9061 }
9062 return "";
9063}
9064
Andrey Ponomarenko16934472012-03-29 15:37:04 +04009065sub registerVTable($)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009066{
Andrey Ponomarenko16934472012-03-29 15:37:04 +04009067 my $LibVersion = $_[0];
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04009068 foreach my $Symbol (keys(%{$CompleteSignature{$LibVersion}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009069 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04009070 if($CompleteSignature{$LibVersion}{$Symbol}{"Virt"}
9071 or $CompleteSignature{$LibVersion}{$Symbol}{"PureVirt"})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009072 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04009073 my $ClassName = $TypeInfo{$LibVersion}{$CompleteSignature{$LibVersion}{$Symbol}{"Class"}}{"Name"};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009074 next if(not $STDCXX_TESTING and $ClassName=~/\A(std::|__cxxabi)/);
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04009075 if($CompleteSignature{$LibVersion}{$Symbol}{"Destructor"}
9076 and $Symbol=~/D2E/)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009077 { # pure virtual D2-destructors are marked as "virt" in the dump
9078 # virtual D2-destructors are NOT marked as "virt" in the dump
9079 # both destructors are not presented in the v-table
9080 next;
9081 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04009082 my ($MnglName, $VersionSpec, $SymbolVersion) = separate_symbol($Symbol);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009083 $VirtualTable{$LibVersion}{$ClassName}{$MnglName} = 1;
9084 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009085 }
9086}
9087
9088sub registerOverriding($)
9089{
9090 my $LibVersion = $_[0];
9091 my @Classes = keys(%{$VirtualTable{$LibVersion}});
Andrey Ponomarenko85043792012-05-14 16:48:07 +04009092 @Classes = sort {int($TName_Tid{$LibVersion}{$a})<=>int($TName_Tid{$LibVersion}{$b})} @Classes;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009093 foreach my $ClassName (@Classes)
9094 {
9095 foreach my $VirtFunc (keys(%{$VirtualTable{$LibVersion}{$ClassName}}))
9096 {
Andrey Ponomarenko16934472012-03-29 15:37:04 +04009097 if($CompleteSignature{$LibVersion}{$VirtFunc}{"PureVirt"})
9098 { # pure virtuals
9099 next;
9100 }
9101 my $ClassId = $TName_Tid{$LibVersion}{$ClassName};
9102 if(my $Overridden = findMethod($VirtFunc, $ClassId, $LibVersion))
Andrey Ponomarenko85043792012-05-14 16:48:07 +04009103 {
9104 if($CompleteSignature{$LibVersion}{$Overridden}{"Virt"}
9105 or $CompleteSignature{$LibVersion}{$Overridden}{"PureVirt"})
9106 { # both overridden virtual methods
9107 # and implemented pure virtual methods
9108 $CompleteSignature{$LibVersion}{$VirtFunc}{"Override"} = $Overridden;
9109 $OverriddenMethods{$LibVersion}{$Overridden}{$VirtFunc} = 1;
9110 delete($VirtualTable{$LibVersion}{$ClassName}{$VirtFunc}); # remove from v-table model
9111 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009112 }
9113 }
9114 if(not keys(%{$VirtualTable{$LibVersion}{$ClassName}})) {
9115 delete($VirtualTable{$LibVersion}{$ClassName});
9116 }
9117 }
9118}
9119
9120sub setVirtFuncPositions($)
9121{
9122 my $LibVersion = $_[0];
9123 foreach my $ClassName (keys(%{$VirtualTable{$LibVersion}}))
9124 {
9125 my ($Num, $RelPos, $AbsNum) = (1, 0, 1);
9126 foreach my $VirtFunc (sort {int($CompleteSignature{$LibVersion}{$a}{"Line"}) <=> int($CompleteSignature{$LibVersion}{$b}{"Line"})}
9127 sort keys(%{$VirtualTable{$LibVersion}{$ClassName}}))
9128 {
Andrey Ponomarenko16934472012-03-29 15:37:04 +04009129 $VirtualTable{$LibVersion}{$ClassName}{$VirtFunc}=$Num++;
9130
9131 # set relative positions
9132 if(defined $VirtualTable{1}{$ClassName} and defined $VirtualTable{1}{$ClassName}{$VirtFunc}
9133 and defined $VirtualTable{2}{$ClassName} and defined $VirtualTable{2}{$ClassName}{$VirtFunc})
9134 { # relative position excluding added and removed virtual functions
9135 if(not $CompleteSignature{1}{$VirtFunc}{"Override"}
9136 and not $CompleteSignature{2}{$VirtFunc}{"Override"}) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009137 $CompleteSignature{$LibVersion}{$VirtFunc}{"RelPos"} = $RelPos++;
9138 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009139 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009140 }
9141 }
Andrey Ponomarenko16934472012-03-29 15:37:04 +04009142 foreach my $ClassName (keys(%{$ClassNames{$LibVersion}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009143 {
9144 my $AbsNum = 1;
Andrey Ponomarenko16934472012-03-29 15:37:04 +04009145 foreach my $VirtFunc (getVTable_Model($TName_Tid{$LibVersion}{$ClassName}, $LibVersion)) {
9146 $VirtualTable_Model{$LibVersion}{$ClassName}{$VirtFunc}=$AbsNum++;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009147 }
9148 }
9149}
9150
9151sub get_sub_classes($$$)
9152{
9153 my ($ClassId, $LibVersion, $Recursive) = @_;
9154 return () if(not defined $Class_SubClasses{$LibVersion}{$ClassId});
9155 my @Subs = ();
9156 foreach my $SubId (keys(%{$Class_SubClasses{$LibVersion}{$ClassId}}))
9157 {
Andrey Ponomarenko16934472012-03-29 15:37:04 +04009158 if($Recursive)
9159 {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009160 foreach my $SubSubId (get_sub_classes($SubId, $LibVersion, $Recursive)) {
9161 push(@Subs, $SubSubId);
9162 }
9163 }
9164 push(@Subs, $SubId);
9165 }
9166 return @Subs;
9167}
9168
9169sub get_base_classes($$$)
9170{
9171 my ($ClassId, $LibVersion, $Recursive) = @_;
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04009172 my %ClassType = get_Type($ClassId, $LibVersion);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009173 return () if(not defined $ClassType{"Base"});
9174 my @Bases = ();
9175 foreach my $BaseId (sort {int($ClassType{"Base"}{$a}{"pos"})<=>int($ClassType{"Base"}{$b}{"pos"})}
9176 keys(%{$ClassType{"Base"}}))
9177 {
Andrey Ponomarenko16934472012-03-29 15:37:04 +04009178 if($Recursive)
9179 {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009180 foreach my $SubBaseId (get_base_classes($BaseId, $LibVersion, $Recursive)) {
9181 push(@Bases, $SubBaseId);
9182 }
9183 }
9184 push(@Bases, $BaseId);
9185 }
9186 return @Bases;
9187}
9188
Andrey Ponomarenko16934472012-03-29 15:37:04 +04009189sub getVTable_Model($$)
9190{ # return an ordered list of v-table elements
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009191 my ($ClassId, $LibVersion) = @_;
9192 my @Bases = get_base_classes($ClassId, $LibVersion, 1);
9193 my @Elements = ();
9194 foreach my $BaseId (@Bases, $ClassId)
9195 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04009196 if(my $BName = $TypeInfo{$LibVersion}{$BaseId}{"Name"})
Andrey Ponomarenko85043792012-05-14 16:48:07 +04009197 {
9198 if(defined $VirtualTable{$LibVersion}{$BName})
9199 {
9200 my @VFunctions = keys(%{$VirtualTable{$LibVersion}{$BName}});
9201 @VFunctions = sort {int($CompleteSignature{$LibVersion}{$a}{"Line"}) <=> int($CompleteSignature{$LibVersion}{$b}{"Line"})} @VFunctions;
9202 foreach my $VFunc (@VFunctions) {
9203 push(@Elements, $VFunc);
9204 }
9205 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009206 }
9207 }
9208 return @Elements;
9209}
9210
9211sub getVShift($$)
9212{
9213 my ($ClassId, $LibVersion) = @_;
9214 my @Bases = get_base_classes($ClassId, $LibVersion, 1);
9215 my $VShift = 0;
9216 foreach my $BaseId (@Bases)
9217 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04009218 if(my $BName = $TypeInfo{$LibVersion}{$BaseId}{"Name"})
Andrey Ponomarenko85043792012-05-14 16:48:07 +04009219 {
9220 if(defined $VirtualTable{$LibVersion}{$BName}) {
9221 $VShift+=keys(%{$VirtualTable{$LibVersion}{$BName}});
9222 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009223 }
9224 }
9225 return $VShift;
9226}
9227
9228sub getShift($$)
9229{
9230 my ($ClassId, $LibVersion) = @_;
9231 my @Bases = get_base_classes($ClassId, $LibVersion, 0);
9232 my $Shift = 0;
9233 foreach my $BaseId (@Bases)
9234 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04009235 if(my $Size = $TypeInfo{$LibVersion}{$BaseId}{"Size"})
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04009236 {
9237 if($Size!=1)
9238 { # not empty base class
9239 $Shift+=$Size;
9240 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009241 }
9242 }
9243 return $Shift;
9244}
9245
Andrey Ponomarenko16934472012-03-29 15:37:04 +04009246sub getVTable_Size($$)
9247{ # number of v-table elements
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009248 my ($ClassName, $LibVersion) = @_;
Andrey Ponomarenko16934472012-03-29 15:37:04 +04009249 my $Size = 0;
9250 # three approaches
9251 if(not $Size)
9252 { # real size
9253 if(my %VTable = getVTable_Real($ClassName, $LibVersion)) {
9254 $Size = keys(%VTable);
9255 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009256 }
Andrey Ponomarenko16934472012-03-29 15:37:04 +04009257 if(not $Size)
9258 { # shared library symbol size
9259 if($Size = getSymbolSize($ClassVTable{$ClassName}, $LibVersion)) {
9260 $Size /= $WORD_SIZE{$LibVersion};
9261 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009262 }
Andrey Ponomarenko16934472012-03-29 15:37:04 +04009263 if(not $Size)
9264 { # model size
9265 if(defined $VirtualTable_Model{$LibVersion}{$ClassName}) {
9266 $Size = keys(%{$VirtualTable_Model{$LibVersion}{$ClassName}}) + 2;
9267 }
9268 }
9269 return $Size;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009270}
9271
9272sub isCopyingClass($$)
9273{
9274 my ($TypeId, $LibVersion) = @_;
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04009275 return $TypeInfo{$LibVersion}{$TypeId}{"Copied"};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009276}
9277
9278sub isLeafClass($$)
9279{
9280 my ($ClassId, $LibVersion) = @_;
9281 return (not keys(%{$Class_SubClasses{$LibVersion}{$ClassId}}));
9282}
9283
9284sub havePubFields($)
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04009285{ # check structured type for public fields
9286 return isAccessible($_[0], {}, 0, -1);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009287}
9288
9289sub isAccessible($$$$)
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04009290{ # check interval in structured type for public fields
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009291 my ($TypePtr, $Skip, $Start, $End) = @_;
9292 return 0 if(not $TypePtr);
9293 if($End==-1) {
9294 $End = keys(%{$TypePtr->{"Memb"}})-1;
9295 }
9296 foreach my $MemPos (keys(%{$TypePtr->{"Memb"}}))
9297 {
9298 if($Skip and $Skip->{$MemPos})
9299 { # skip removed/added fields
9300 next;
9301 }
9302 if(int($MemPos)>=$Start and int($MemPos)<=$End)
9303 {
9304 if(isPublic($TypePtr, $MemPos)) {
9305 return ($MemPos+1);
9306 }
9307 }
9308 }
9309 return 0;
9310}
9311
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009312sub isReserved($)
9313{ # reserved fields == private
9314 my $MName = $_[0];
9315 if($MName=~/reserved|padding|f_spare/i) {
9316 return 1;
9317 }
Andrey Ponomarenko9927e332012-10-19 10:50:48 +04009318 if($MName=~/\A[_]*(spare|pad|unused)[_\d]*\Z/i) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009319 return 1;
9320 }
9321 if($MName=~/(pad\d+)/i) {
9322 return 1;
9323 }
9324 return 0;
9325}
9326
9327sub isPublic($$)
9328{
9329 my ($TypePtr, $FieldPos) = @_;
9330 return 0 if(not $TypePtr);
9331 return 0 if(not defined $TypePtr->{"Memb"}{$FieldPos});
9332 return 0 if(not defined $TypePtr->{"Memb"}{$FieldPos}{"name"});
9333 if(not $TypePtr->{"Memb"}{$FieldPos}{"access"})
9334 { # by name in C language
9335 # FIXME: add other methods to detect private members
9336 my $MName = $TypePtr->{"Memb"}{$FieldPos}{"name"};
9337 if($MName=~/priv|abidata|parent_object/i)
9338 { # C-styled private data
9339 return 0;
9340 }
9341 if(lc($MName) eq "abi")
9342 { # ABI information/reserved field
9343 return 0;
9344 }
9345 if(isReserved($MName))
9346 { # reserved fields
9347 return 0;
9348 }
9349 return 1;
9350 }
9351 elsif($TypePtr->{"Memb"}{$FieldPos}{"access"} ne "private")
9352 { # by access in C++ language
9353 return 1;
9354 }
9355 return 0;
9356}
9357
Andrey Ponomarenko16934472012-03-29 15:37:04 +04009358sub getVTable_Real($$)
9359{
9360 my ($ClassName, $LibVersion) = @_;
9361 if(my $ClassId = $TName_Tid{$LibVersion}{$ClassName})
9362 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04009363 my %Type = get_Type($ClassId, $LibVersion);
Andrey Ponomarenko16934472012-03-29 15:37:04 +04009364 if(defined $Type{"VTable"}) {
9365 return %{$Type{"VTable"}};
9366 }
9367 }
9368 return ();
9369}
9370
9371sub cmpVTables($)
9372{
9373 my $ClassName = $_[0];
9374 my $Res = cmpVTables_Real($ClassName, 1);
9375 if($Res==-1) {
9376 $Res = cmpVTables_Model($ClassName);
9377 }
9378 return $Res;
9379}
9380
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009381sub cmpVTables_Model($)
9382{
9383 my $ClassName = $_[0];
Andrey Ponomarenko16934472012-03-29 15:37:04 +04009384 foreach my $Symbol (keys(%{$VirtualTable_Model{1}{$ClassName}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009385 {
Andrey Ponomarenko16934472012-03-29 15:37:04 +04009386 if(not defined $VirtualTable_Model{2}{$ClassName}{$Symbol}) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009387 return 1;
9388 }
9389 }
9390 return 0;
9391}
9392
Andrey Ponomarenko16934472012-03-29 15:37:04 +04009393sub cmpVTables_Real($$)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009394{
9395 my ($ClassName, $Strong) = @_;
Andrey Ponomarenko16934472012-03-29 15:37:04 +04009396 if(defined $Cache{"cmpVTables_Real"}{$Strong}{$ClassName}) {
9397 return $Cache{"cmpVTables_Real"}{$Strong}{$ClassName};
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04009398 }
Andrey Ponomarenko16934472012-03-29 15:37:04 +04009399 my %VTable_Old = getVTable_Real($ClassName, 1);
9400 my %VTable_New = getVTable_Real($ClassName, 2);
9401 if(not %VTable_Old or not %VTable_New)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009402 { # old ABI dumps
Andrey Ponomarenko16934472012-03-29 15:37:04 +04009403 return ($Cache{"cmpVTables_Real"}{$Strong}{$ClassName} = -1);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009404 }
Andrey Ponomarenko16934472012-03-29 15:37:04 +04009405 my %Indexes = map {$_=>1} (keys(%VTable_Old), keys(%VTable_New));
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009406 foreach my $Offset (sort {int($a)<=>int($b)} keys(%Indexes))
9407 {
Andrey Ponomarenko16934472012-03-29 15:37:04 +04009408 if(not defined $VTable_Old{$Offset})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009409 { # v-table v.1 < v-table v.2
Andrey Ponomarenko16934472012-03-29 15:37:04 +04009410 return ($Cache{"cmpVTables_Real"}{$Strong}{$ClassName} = $Strong);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009411 }
Andrey Ponomarenko16934472012-03-29 15:37:04 +04009412 my $Entry1 = $VTable_Old{$Offset};
9413 if(not defined $VTable_New{$Offset})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009414 { # v-table v.1 > v-table v.2
Andrey Ponomarenko16934472012-03-29 15:37:04 +04009415 return ($Cache{"cmpVTables_Real"}{$Strong}{$ClassName} = ($Strong or $Entry1!~/__cxa_pure_virtual/));
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009416 }
Andrey Ponomarenko16934472012-03-29 15:37:04 +04009417 my $Entry2 = $VTable_New{$Offset};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009418 $Entry1 = simpleVEntry($Entry1);
9419 $Entry2 = simpleVEntry($Entry2);
9420 if($Entry1 ne $Entry2)
9421 { # register as changed
9422 if($Entry1=~/::([^:]+)\Z/)
9423 {
9424 my $M1 = $1;
9425 if($Entry2=~/::([^:]+)\Z/)
9426 {
9427 my $M2 = $1;
9428 if($M1 eq $M2)
9429 { # overridden
9430 next;
9431 }
9432 }
9433 }
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04009434 if(differentDumps("G"))
9435 {
9436 if($Entry1=~/\A\-(0x|\d+)/ and $Entry2=~/\A\-(0x|\d+)/)
9437 {
9438 # GCC 4.6.1: -0x00000000000000010
9439 # GCC 4.7.0: -16
9440 next;
9441 }
9442 }
Andrey Ponomarenko16934472012-03-29 15:37:04 +04009443 return ($Cache{"cmpVTables_Real"}{$Strong}{$ClassName} = 1);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009444 }
9445 }
Andrey Ponomarenko16934472012-03-29 15:37:04 +04009446 return ($Cache{"cmpVTables_Real"}{$Strong}{$ClassName} = 0);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009447}
9448
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04009449sub mergeVTables($)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009450{ # merging v-tables without diagnostics
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04009451 my $Level = $_[0];
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009452 foreach my $ClassName (keys(%{$VirtualTable{1}}))
9453 {
Andrey Ponomarenko16934472012-03-29 15:37:04 +04009454 if($VTableChanged_M{$ClassName})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009455 { # already registered
9456 next;
9457 }
Andrey Ponomarenko16934472012-03-29 15:37:04 +04009458 if(cmpVTables_Real($ClassName, 0)==1)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009459 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04009460 my @Affected = (keys(%{$ClassMethods{$Level}{1}{$ClassName}}));
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009461 foreach my $Symbol (@Affected)
9462 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04009463 %{$CompatProblems{$Level}{$Symbol}{"Virtual_Table_Changed_Unknown"}{$ClassName}}=(
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009464 "Type_Name"=>$ClassName,
9465 "Type_Type"=>"Class",
9466 "Target"=>$ClassName);
9467 }
9468 }
9469 }
9470}
9471
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04009472sub mergeBases($)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009473{
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04009474 my $Level = $_[0];
Andrey Ponomarenko16934472012-03-29 15:37:04 +04009475 foreach my $ClassName (keys(%{$ClassNames{1}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009476 { # detect added and removed virtual functions
Andrey Ponomarenko16934472012-03-29 15:37:04 +04009477 my $ClassId = $TName_Tid{1}{$ClassName};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009478 next if(not $ClassId);
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04009479 if(defined $VirtualTable{2}{$ClassName})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009480 {
Andrey Ponomarenko16934472012-03-29 15:37:04 +04009481 foreach my $Symbol (keys(%{$VirtualTable{2}{$ClassName}}))
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04009482 {
Andrey Ponomarenko16934472012-03-29 15:37:04 +04009483 if($TName_Tid{1}{$ClassName}
9484 and not defined $VirtualTable{1}{$ClassName}{$Symbol})
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04009485 { # added to v-table
Andrey Ponomarenko16934472012-03-29 15:37:04 +04009486 if(defined $CompleteSignature{1}{$Symbol}
9487 and $CompleteSignature{1}{$Symbol}{"Virt"})
9488 { # override some method in v.1
9489 next;
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04009490 }
Andrey Ponomarenko16934472012-03-29 15:37:04 +04009491 $AddedInt_Virt{$Level}{$ClassName}{$Symbol} = 1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009492 }
9493 }
9494 }
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04009495 if(defined $VirtualTable{1}{$ClassName})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009496 {
Andrey Ponomarenko16934472012-03-29 15:37:04 +04009497 foreach my $Symbol (keys(%{$VirtualTable{1}{$ClassName}}))
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04009498 {
Andrey Ponomarenko16934472012-03-29 15:37:04 +04009499 if($TName_Tid{2}{$ClassName}
9500 and not defined $VirtualTable{2}{$ClassName}{$Symbol})
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04009501 { # removed from v-table
Andrey Ponomarenko16934472012-03-29 15:37:04 +04009502 if(defined $CompleteSignature{2}{$Symbol}
9503 and $CompleteSignature{2}{$Symbol}{"Virt"})
9504 { # override some method in v.2
9505 next;
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04009506 }
Andrey Ponomarenko16934472012-03-29 15:37:04 +04009507 $RemovedInt_Virt{$Level}{$ClassName}{$Symbol} = 1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009508 }
9509 }
9510 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04009511 if($Level eq "Binary")
9512 { # Binary-level
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04009513 my %Class_Type = get_Type($ClassId, 1);
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04009514 foreach my $AddedVFunc (keys(%{$AddedInt_Virt{$Level}{$ClassName}}))
9515 { # check replacements, including pure virtual methods
9516 my $AddedPos = $VirtualTable{2}{$ClassName}{$AddedVFunc};
9517 foreach my $RemovedVFunc (keys(%{$RemovedInt_Virt{$Level}{$ClassName}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009518 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04009519 my $RemovedPos = $VirtualTable{1}{$ClassName}{$RemovedVFunc};
9520 if($AddedPos==$RemovedPos)
9521 {
9522 $VirtualReplacement{$AddedVFunc} = $RemovedVFunc;
9523 $VirtualReplacement{$RemovedVFunc} = $AddedVFunc;
9524 last; # other methods will be reported as "added" or "removed"
9525 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009526 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04009527 if(my $RemovedVFunc = $VirtualReplacement{$AddedVFunc})
9528 {
9529 if(lc($AddedVFunc) eq lc($RemovedVFunc))
9530 { # skip: DomUi => DomUI parameter (Qt 4.2.3 to 4.3.0)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009531 next;
9532 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04009533 my $ProblemType = "Virtual_Replacement";
9534 my @Affected = ($RemovedVFunc);
9535 if($CompleteSignature{1}{$RemovedVFunc}{"PureVirt"})
9536 { # pure methods
9537 if(not isUsedClass($ClassId, 1, $Level))
9538 { # not a parameter of some exported method
9539 next;
9540 }
9541 $ProblemType = "Pure_Virtual_Replacement";
Andrey Ponomarenko9927e332012-10-19 10:50:48 +04009542
9543 # affected all methods (both virtual and non-virtual ones)
9544 @Affected = (keys(%{$ClassMethods{$Level}{1}{$ClassName}}));
9545 push(@Affected, keys(%{$OverriddenMethods{1}{$RemovedVFunc}}));
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009546 }
Andrey Ponomarenko9927e332012-10-19 10:50:48 +04009547 $VTableChanged_M{$ClassName}=1;
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04009548 foreach my $AffectedInt (@Affected)
9549 {
9550 if($CompleteSignature{1}{$AffectedInt}{"PureVirt"})
9551 { # affected exported methods only
9552 next;
9553 }
Andrey Ponomarenko9927e332012-10-19 10:50:48 +04009554 if(not symbolFilter($AffectedInt, 1, "Affected", $Level)) {
9555 next;
9556 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04009557 %{$CompatProblems{$Level}{$AffectedInt}{$ProblemType}{$tr_name{$AddedVFunc}}}=(
9558 "Type_Name"=>$Class_Type{"Name"},
9559 "Type_Type"=>"Class",
9560 "Target"=>get_Signature($AddedVFunc, 2),
9561 "Old_Value"=>get_Signature($RemovedVFunc, 1));
9562 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009563 }
9564 }
9565 }
9566 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04009567 if(not checkDump(1, "2.0")
9568 or not checkDump(2, "2.0"))
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04009569 { # support for old ABI dumps
Andrey Ponomarenko9927e332012-10-19 10:50:48 +04009570 # "Base" attribute introduced in ACC 1.22 (ABI dump 2.0 format)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009571 return;
9572 }
Andrey Ponomarenko16934472012-03-29 15:37:04 +04009573 foreach my $ClassName (sort keys(%{$ClassNames{1}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009574 {
Andrey Ponomarenko16934472012-03-29 15:37:04 +04009575 my $ClassId_Old = $TName_Tid{1}{$ClassName};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009576 next if(not $ClassId_Old);
9577 if(not isCreatable($ClassId_Old, 1))
9578 { # skip classes without public constructors (including auto-generated)
9579 # example: class has only a private exported or private inline constructor
9580 next;
9581 }
9582 if($ClassName=~/>/)
9583 { # skip affected template instances
9584 next;
9585 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04009586 my %Class_Old = get_Type($ClassId_Old, 1);
Andrey Ponomarenko16934472012-03-29 15:37:04 +04009587 my $ClassId_New = $TName_Tid{2}{$ClassName};
Andrey Ponomarenko85043792012-05-14 16:48:07 +04009588 if(not $ClassId_New) {
9589 next;
9590 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04009591 my %Class_New = get_Type($ClassId_New, 2);
Andrey Ponomarenko85043792012-05-14 16:48:07 +04009592 if($Class_New{"Type"}!~/Class|Struct/)
9593 { # became typedef
9594 if($Level eq "Binary") {
9595 next;
9596 }
9597 if($Level eq "Source")
9598 {
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +04009599 %Class_New = get_PureType($ClassId_New, $TypeInfo{2});
Andrey Ponomarenko85043792012-05-14 16:48:07 +04009600 if($Class_New{"Type"}!~/Class|Struct/) {
9601 next;
9602 }
9603 $ClassId_New = $Class_New{"Tid"};
9604 }
9605 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009606 my @Bases_Old = sort {$Class_Old{"Base"}{$a}{"pos"}<=>$Class_Old{"Base"}{$b}{"pos"}} keys(%{$Class_Old{"Base"}});
9607 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 +04009608
9609 my %Tr_Old = map {$TypeInfo{1}{$_}{"Name"} => uncover_typedefs($TypeInfo{1}{$_}{"Name"}, 1)} @Bases_Old;
9610 my %Tr_New = map {$TypeInfo{2}{$_}{"Name"} => uncover_typedefs($TypeInfo{2}{$_}{"Name"}, 2)} @Bases_New;
9611
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009612 my ($BNum1, $BNum2) = (1, 1);
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +04009613 my %BasePos_Old = map {$Tr_Old{$TypeInfo{1}{$_}{"Name"}} => $BNum1++} @Bases_Old;
9614 my %BasePos_New = map {$Tr_New{$TypeInfo{2}{$_}{"Name"}} => $BNum2++} @Bases_New;
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04009615 my %ShortBase_Old = map {get_ShortType($_, 1) => 1} @Bases_Old;
9616 my %ShortBase_New = map {get_ShortType($_, 2) => 1} @Bases_New;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009617 my $Shift_Old = getShift($ClassId_Old, 1);
9618 my $Shift_New = getShift($ClassId_New, 2);
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +04009619 my %BaseId_New = map {$Tr_New{$TypeInfo{2}{$_}{"Name"}} => $_} @Bases_New;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009620 my ($Added, $Removed) = (0, 0);
9621 my @StableBases_Old = ();
9622 foreach my $BaseId (@Bases_Old)
9623 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04009624 my $BaseName = $TypeInfo{1}{$BaseId}{"Name"};
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +04009625 if($BasePos_New{$Tr_Old{$BaseName}}) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009626 push(@StableBases_Old, $BaseId);
9627 }
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +04009628 elsif(not $ShortBase_New{$Tr_Old{$BaseName}}
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04009629 and not $ShortBase_New{get_ShortType($BaseId, 1)})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009630 { # removed base
9631 # excluding namespace::SomeClass to SomeClass renaming
9632 my $ProblemKind = "Removed_Base_Class";
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04009633 if($Level eq "Binary")
9634 { # Binary-level
9635 if($Shift_Old ne $Shift_New)
9636 { # affected fields
9637 if(havePubFields(\%Class_Old)) {
9638 $ProblemKind .= "_And_Shift";
9639 }
9640 elsif($Class_Old{"Size"} ne $Class_New{"Size"}) {
9641 $ProblemKind .= "_And_Size";
9642 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009643 }
Andrey Ponomarenko16934472012-03-29 15:37:04 +04009644 if(keys(%{$VirtualTable_Model{1}{$BaseName}})
9645 and cmpVTables($ClassName)==1)
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04009646 { # affected v-table
9647 $ProblemKind .= "_And_VTable";
Andrey Ponomarenko16934472012-03-29 15:37:04 +04009648 $VTableChanged_M{$ClassName}=1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009649 }
9650 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04009651 my @Affected = keys(%{$ClassMethods{$Level}{1}{$ClassName}});
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009652 foreach my $SubId (get_sub_classes($ClassId_Old, 1, 1))
9653 {
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +04009654 if(my $SubName = $TypeInfo{1}{$SubId}{"Name"})
9655 {
9656 push(@Affected, keys(%{$ClassMethods{$Level}{1}{$SubName}}));
9657 if($ProblemKind=~/VTable/) {
9658 $VTableChanged_M{$SubName}=1;
9659 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009660 }
9661 }
9662 foreach my $Interface (@Affected)
9663 {
Andrey Ponomarenko9927e332012-10-19 10:50:48 +04009664 if(not symbolFilter($Interface, 1, "Affected", $Level)) {
9665 next;
9666 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04009667 %{$CompatProblems{$Level}{$Interface}{$ProblemKind}{"this"}}=(
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009668 "Type_Name"=>$ClassName,
9669 "Type_Type"=>"Class",
9670 "Target"=>$BaseName,
9671 "Old_Size"=>$Class_Old{"Size"}*$BYTE_SIZE,
9672 "New_Size"=>$Class_New{"Size"}*$BYTE_SIZE,
9673 "Shift"=>abs($Shift_New-$Shift_Old) );
9674 }
9675 $Removed+=1;
9676 }
9677 }
9678 my @StableBases_New = ();
9679 foreach my $BaseId (@Bases_New)
9680 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04009681 my $BaseName = $TypeInfo{2}{$BaseId}{"Name"};
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +04009682 if($BasePos_Old{$Tr_New{$BaseName}}) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009683 push(@StableBases_New, $BaseId);
9684 }
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +04009685 elsif(not $ShortBase_Old{$Tr_New{$BaseName}}
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04009686 and not $ShortBase_Old{get_ShortType($BaseId, 2)})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009687 { # added base
9688 # excluding namespace::SomeClass to SomeClass renaming
9689 my $ProblemKind = "Added_Base_Class";
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04009690 if($Level eq "Binary")
9691 { # Binary-level
9692 if($Shift_Old ne $Shift_New)
9693 { # affected fields
9694 if(havePubFields(\%Class_Old)) {
9695 $ProblemKind .= "_And_Shift";
9696 }
9697 elsif($Class_Old{"Size"} ne $Class_New{"Size"}) {
9698 $ProblemKind .= "_And_Size";
9699 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009700 }
Andrey Ponomarenko16934472012-03-29 15:37:04 +04009701 if(keys(%{$VirtualTable_Model{2}{$BaseName}})
9702 and cmpVTables($ClassName)==1)
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04009703 { # affected v-table
9704 $ProblemKind .= "_And_VTable";
Andrey Ponomarenko16934472012-03-29 15:37:04 +04009705 $VTableChanged_M{$ClassName}=1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009706 }
9707 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04009708 my @Affected = keys(%{$ClassMethods{$Level}{1}{$ClassName}});
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009709 foreach my $SubId (get_sub_classes($ClassId_Old, 1, 1))
9710 {
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +04009711 if(my $SubName = $TypeInfo{1}{$SubId}{"Name"})
9712 {
9713 push(@Affected, keys(%{$ClassMethods{$Level}{1}{$SubName}}));
9714 if($ProblemKind=~/VTable/) {
9715 $VTableChanged_M{$SubName}=1;
9716 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009717 }
9718 }
9719 foreach my $Interface (@Affected)
9720 {
Andrey Ponomarenko9927e332012-10-19 10:50:48 +04009721 if(not symbolFilter($Interface, 1, "Affected", $Level)) {
9722 next;
9723 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04009724 %{$CompatProblems{$Level}{$Interface}{$ProblemKind}{"this"}}=(
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009725 "Type_Name"=>$ClassName,
9726 "Type_Type"=>"Class",
9727 "Target"=>$BaseName,
9728 "Old_Size"=>$Class_Old{"Size"}*$BYTE_SIZE,
9729 "New_Size"=>$Class_New{"Size"}*$BYTE_SIZE,
9730 "Shift"=>abs($Shift_New-$Shift_Old) );
9731 }
9732 $Added+=1;
9733 }
9734 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04009735 if($Level eq "Binary")
9736 { # Binary-level
9737 ($BNum1, $BNum2) = (1, 1);
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +04009738 my %BaseRelPos_Old = map {$Tr_Old{$TypeInfo{1}{$_}{"Name"}} => $BNum1++} @StableBases_Old;
9739 my %BaseRelPos_New = map {$Tr_New{$TypeInfo{2}{$_}{"Name"}} => $BNum2++} @StableBases_New;
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04009740 foreach my $BaseId (@Bases_Old)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009741 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04009742 my $BaseName = $TypeInfo{1}{$BaseId}{"Name"};
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +04009743 if(my $NewPos = $BaseRelPos_New{$Tr_Old{$BaseName}})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009744 {
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +04009745 my $BaseNewId = $BaseId_New{$Tr_Old{$BaseName}};
9746 my $OldPos = $BaseRelPos_Old{$Tr_Old{$BaseName}};
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04009747 if($NewPos!=$OldPos)
9748 { # changed position of the base class
9749 foreach my $Interface (keys(%{$ClassMethods{$Level}{1}{$ClassName}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009750 {
Andrey Ponomarenko9927e332012-10-19 10:50:48 +04009751 if(not symbolFilter($Interface, 1, "Affected", $Level)) {
9752 next;
9753 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04009754 %{$CompatProblems{$Level}{$Interface}{"Base_Class_Position"}{"this"}}=(
9755 "Type_Name"=>$ClassName,
9756 "Type_Type"=>"Class",
9757 "Target"=>$BaseName,
9758 "Old_Value"=>$OldPos-1,
9759 "New_Value"=>$NewPos-1 );
9760 }
9761 }
9762 if($Class_Old{"Base"}{$BaseId}{"virtual"}
9763 and not $Class_New{"Base"}{$BaseNewId}{"virtual"})
9764 { # became non-virtual base
9765 foreach my $Interface (keys(%{$ClassMethods{$Level}{1}{$ClassName}}))
9766 {
Andrey Ponomarenko9927e332012-10-19 10:50:48 +04009767 if(not symbolFilter($Interface, 1, "Affected", $Level)) {
9768 next;
9769 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04009770 %{$CompatProblems{$Level}{$Interface}{"Base_Class_Became_Non_Virtually_Inherited"}{"this->".$BaseName}}=(
9771 "Type_Name"=>$ClassName,
9772 "Type_Type"=>"Class",
9773 "Target"=>$BaseName );
9774 }
9775 }
9776 elsif(not $Class_Old{"Base"}{$BaseId}{"virtual"}
9777 and $Class_New{"Base"}{$BaseNewId}{"virtual"})
9778 { # became virtual base
9779 foreach my $Interface (keys(%{$ClassMethods{$Level}{1}{$ClassName}}))
9780 {
Andrey Ponomarenko9927e332012-10-19 10:50:48 +04009781 if(not symbolFilter($Interface, 1, "Affected", $Level)) {
9782 next;
9783 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04009784 %{$CompatProblems{$Level}{$Interface}{"Base_Class_Became_Virtually_Inherited"}{"this->".$BaseName}}=(
9785 "Type_Name"=>$ClassName,
9786 "Type_Type"=>"Class",
9787 "Target"=>$BaseName );
9788 }
9789 }
9790 }
9791 }
9792 # detect size changes in base classes
9793 if($Shift_Old!=$Shift_New)
9794 { # size of allocable class
9795 foreach my $BaseId (@StableBases_Old)
9796 { # search for changed base
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04009797 my %BaseType = get_Type($BaseId, 1);
9798 my $Size_Old = $TypeInfo{1}{$BaseId}{"Size"};
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +04009799 my $Size_New = $TypeInfo{2}{$BaseId_New{$Tr_Old{$BaseType{"Name"}}}}{"Size"};
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04009800 if($Size_Old ne $Size_New
9801 and $Size_Old and $Size_New)
9802 {
9803 my $ProblemType = "";
9804 if(isCopyingClass($BaseId, 1)) {
9805 $ProblemType = "Size_Of_Copying_Class";
9806 }
9807 elsif($AllocableClass{1}{$BaseType{"Name"}})
9808 {
9809 if($Size_New>$Size_Old)
9810 { # increased size
9811 $ProblemType = "Size_Of_Allocable_Class_Increased";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009812 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04009813 else
9814 { # decreased size
9815 $ProblemType = "Size_Of_Allocable_Class_Decreased";
9816 if(not havePubFields(\%Class_Old))
9817 { # affected class has no public members
9818 next;
9819 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009820 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04009821 }
9822 next if(not $ProblemType);
9823 foreach my $Interface (keys(%{$ClassMethods{$Level}{1}{$ClassName}}))
9824 { # base class size changes affecting current class
Andrey Ponomarenko9927e332012-10-19 10:50:48 +04009825 if(not symbolFilter($Interface, 1, "Affected", $Level)) {
9826 next;
9827 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04009828 %{$CompatProblems{$Level}{$Interface}{$ProblemType}{"this->".$BaseType{"Name"}}}=(
9829 "Type_Name"=>$BaseType{"Name"},
9830 "Type_Type"=>"Class",
9831 "Target"=>$BaseType{"Name"},
9832 "Old_Size"=>$Size_Old*$BYTE_SIZE,
9833 "New_Size"=>$Size_New*$BYTE_SIZE );
9834 }
9835 }
9836 }
9837 }
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +04009838 if(defined $VirtualTable_Model{1}{$ClassName}
Andrey Ponomarenko16934472012-03-29 15:37:04 +04009839 and cmpVTables_Real($ClassName, 1)==1
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +04009840 and my @VFunctions = keys(%{$VirtualTable_Model{1}{$ClassName}}))
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04009841 { # compare virtual tables size in base classes
9842 my $VShift_Old = getVShift($ClassId_Old, 1);
9843 my $VShift_New = getVShift($ClassId_New, 2);
9844 if($VShift_Old ne $VShift_New)
9845 { # changes in the base class or changes in the list of base classes
9846 my @AllBases_Old = get_base_classes($ClassId_Old, 1, 1);
9847 my @AllBases_New = get_base_classes($ClassId_New, 2, 1);
9848 ($BNum1, $BNum2) = (1, 1);
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +04009849 my %StableBase = map {$Tr_New{$TypeInfo{2}{$_}{"Name"}} => $_} @AllBases_New;
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04009850 foreach my $BaseId (@AllBases_Old)
9851 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04009852 my %BaseType = get_Type($BaseId, 1);
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +04009853 if(not $StableBase{$Tr_Old{$BaseType{"Name"}}})
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04009854 { # lost base
9855 next;
9856 }
Andrey Ponomarenko16934472012-03-29 15:37:04 +04009857 my $VSize_Old = getVTable_Size($BaseType{"Name"}, 1);
9858 my $VSize_New = getVTable_Size($BaseType{"Name"}, 2);
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04009859 if($VSize_Old!=$VSize_New)
9860 {
Andrey Ponomarenko85043792012-05-14 16:48:07 +04009861 foreach my $Symbol (@VFunctions)
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +04009862 { # TODO: affected non-virtual methods?
9863 if(not defined $VirtualTable_Model{2}{$ClassName}{$Symbol})
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04009864 { # Removed_Virtual_Method, will be registered in mergeVirtualTables()
9865 next;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009866 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +04009867 if($VirtualTable_Model{2}{$ClassName}{$Symbol}-$VirtualTable_Model{1}{$ClassName}{$Symbol}==0)
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04009868 { # skip interfaces that have not changed the absolute virtual position
9869 next;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009870 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +04009871 if(not symbolFilter($Symbol, 1, "Affected", $Level)) {
9872 next;
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04009873 }
Andrey Ponomarenko16934472012-03-29 15:37:04 +04009874 $VTableChanged_M{$BaseType{"Name"}} = 1;
9875 $VTableChanged_M{$ClassName} = 1;
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04009876 foreach my $VirtFunc (keys(%{$AddedInt_Virt{$Level}{$BaseType{"Name"}}}))
9877 { # the reason of the layout change: added virtual functions
9878 next if($VirtualReplacement{$VirtFunc});
9879 my $ProblemType = "Added_Virtual_Method";
9880 if($CompleteSignature{2}{$VirtFunc}{"PureVirt"}) {
9881 $ProblemType = "Added_Pure_Virtual_Method";
9882 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +04009883 %{$CompatProblems{$Level}{$Symbol}{$ProblemType}{get_Signature($VirtFunc, 2)}}=(
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04009884 "Type_Name"=>$BaseType{"Name"},
9885 "Type_Type"=>"Class",
9886 "Target"=>get_Signature($VirtFunc, 2) );
9887 }
9888 foreach my $VirtFunc (keys(%{$RemovedInt_Virt{$Level}{$BaseType{"Name"}}}))
9889 { # the reason of the layout change: removed virtual functions
9890 next if($VirtualReplacement{$VirtFunc});
9891 my $ProblemType = "Removed_Virtual_Method";
9892 if($CompleteSignature{1}{$VirtFunc}{"PureVirt"}) {
9893 $ProblemType = "Removed_Pure_Virtual_Method";
9894 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +04009895 %{$CompatProblems{$Level}{$Symbol}{$ProblemType}{get_Signature($VirtFunc, 1)}}=(
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04009896 "Type_Name"=>$BaseType{"Name"},
9897 "Type_Type"=>"Class",
9898 "Target"=>get_Signature($VirtFunc, 1) );
9899 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009900 }
9901 }
9902 }
9903 }
9904 }
9905 }
9906 }
9907}
9908
9909sub isCreatable($$)
9910{
9911 my ($ClassId, $LibVersion) = @_;
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04009912 if($AllocableClass{$LibVersion}{$TypeInfo{$LibVersion}{$ClassId}{"Name"}}
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009913 or isCopyingClass($ClassId, $LibVersion)) {
9914 return 1;
9915 }
9916 if(keys(%{$Class_SubClasses{$LibVersion}{$ClassId}}))
9917 { # Fix for incomplete data: if this class has
9918 # a base class then it should also has a constructor
9919 return 1;
9920 }
9921 if($ReturnedClass{$LibVersion}{$ClassId})
9922 { # returned by some method of this class
9923 # or any other class
9924 return 1;
9925 }
9926 return 0;
9927}
9928
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04009929sub isUsedClass($$$)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009930{
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04009931 my ($ClassId, $LibVersion, $Level) = @_;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009932 if(keys(%{$ParamClass{$LibVersion}{$ClassId}}))
9933 { # parameter of some exported method
9934 return 1;
9935 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04009936 my $CName = $TypeInfo{$LibVersion}{$ClassId}{"Name"};
9937 if(keys(%{$ClassMethods{$Level}{$LibVersion}{$CName}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009938 { # method from target class
9939 return 1;
9940 }
9941 return 0;
9942}
9943
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04009944sub mergeVirtualTables($$)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009945{ # check for changes in the virtual table
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04009946 my ($Interface, $Level) = @_;
Andrey Ponomarenko16934472012-03-29 15:37:04 +04009947 # affected methods:
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009948 # - virtual
9949 # - pure-virtual
9950 # - non-virtual
9951 if($CompleteSignature{1}{$Interface}{"Data"})
9952 { # global data is not affected
9953 return;
9954 }
9955 my $Class_Id = $CompleteSignature{1}{$Interface}{"Class"};
Andrey Ponomarenko16934472012-03-29 15:37:04 +04009956 if(not $Class_Id) {
9957 return;
9958 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04009959 my $CName = $TypeInfo{1}{$Class_Id}{"Name"};
Andrey Ponomarenko16934472012-03-29 15:37:04 +04009960 if(cmpVTables_Real($CName, 1)==0)
9961 { # no changes
9962 return;
9963 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04009964 $CheckedTypes{$Level}{$CName} = 1;
9965 if($Level eq "Binary")
9966 { # Binary-level
9967 if($CompleteSignature{1}{$Interface}{"PureVirt"}
9968 and not isUsedClass($Class_Id, 1, $Level))
9969 { # pure virtuals should not be affected
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04009970 # if there are no exported methods using this class
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04009971 return;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009972 }
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04009973 }
9974 foreach my $Func (keys(%{$VirtualTable{1}{$CName}}))
9975 {
9976 if(defined $VirtualTable{2}{$CName}{$Func}
9977 and defined $CompleteSignature{2}{$Func})
9978 {
9979 if(not $CompleteSignature{1}{$Func}{"PureVirt"}
9980 and $CompleteSignature{2}{$Func}{"PureVirt"})
9981 { # became pure virtual
9982 %{$CompatProblems{$Level}{$Interface}{"Virtual_Method_Became_Pure"}{$tr_name{$Func}}}=(
9983 "Type_Name"=>$CName,
9984 "Type_Type"=>"Class",
9985 "Target"=>get_Signature_M($Func, 1) );
9986 $VTableChanged_M{$CName} = 1;
9987 }
9988 elsif($CompleteSignature{1}{$Func}{"PureVirt"}
9989 and not $CompleteSignature{2}{$Func}{"PureVirt"})
9990 { # became non-pure virtual
9991 %{$CompatProblems{$Level}{$Interface}{"Virtual_Method_Became_Non_Pure"}{$tr_name{$Func}}}=(
9992 "Type_Name"=>$CName,
9993 "Type_Type"=>"Class",
9994 "Target"=>get_Signature_M($Func, 1) );
9995 $VTableChanged_M{$CName} = 1;
9996 }
9997 }
9998 }
9999 if($Level eq "Binary")
10000 { # Binary-level
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040010001 # check virtual table structure
10002 foreach my $AddedVFunc (keys(%{$AddedInt_Virt{$Level}{$CName}}))
10003 {
10004 next if($Interface eq $AddedVFunc);
10005 next if($VirtualReplacement{$AddedVFunc});
10006 my $VPos_Added = $VirtualTable{2}{$CName}{$AddedVFunc};
10007 if($CompleteSignature{2}{$AddedVFunc}{"PureVirt"})
10008 { # pure virtual methods affect all others (virtual and non-virtual)
10009 %{$CompatProblems{$Level}{$Interface}{"Added_Pure_Virtual_Method"}{$tr_name{$AddedVFunc}}}=(
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010010 "Type_Name"=>$CName,
10011 "Type_Type"=>"Class",
10012 "Target"=>get_Signature($AddedVFunc, 2) );
Andrey Ponomarenko16934472012-03-29 15:37:04 +040010013 $VTableChanged_M{$CName} = 1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010014 }
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040010015 elsif(not defined $VirtualTable{1}{$CName}
10016 or $VPos_Added>keys(%{$VirtualTable{1}{$CName}}))
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040010017 { # added virtual function at the end of v-table
Andrey Ponomarenko16934472012-03-29 15:37:04 +040010018 if(not keys(%{$VirtualTable_Model{1}{$CName}}))
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040010019 { # became polymorphous class, added v-table pointer
10020 %{$CompatProblems{$Level}{$Interface}{"Added_First_Virtual_Method"}{$tr_name{$AddedVFunc}}}=(
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010021 "Type_Name"=>$CName,
10022 "Type_Type"=>"Class",
10023 "Target"=>get_Signature($AddedVFunc, 2) );
Andrey Ponomarenko16934472012-03-29 15:37:04 +040010024 $VTableChanged_M{$CName} = 1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010025 }
10026 else
10027 {
Andrey Ponomarenko16934472012-03-29 15:37:04 +040010028 my $VSize_Old = getVTable_Size($CName, 1);
10029 my $VSize_New = getVTable_Size($CName, 2);
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040010030 next if($VSize_Old==$VSize_New); # exception: register as removed and added virtual method
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040010031 if(isCopyingClass($Class_Id, 1))
10032 { # class has no constructors and v-table will be copied by applications, this may affect all methods
10033 my $ProblemType = "Added_Virtual_Method";
10034 if(isLeafClass($Class_Id, 1)) {
10035 $ProblemType = "Added_Virtual_Method_At_End_Of_Leaf_Copying_Class";
10036 }
10037 %{$CompatProblems{$Level}{$Interface}{$ProblemType}{$tr_name{$AddedVFunc}}}=(
10038 "Type_Name"=>$CName,
10039 "Type_Type"=>"Class",
10040 "Target"=>get_Signature($AddedVFunc, 2) );
Andrey Ponomarenko16934472012-03-29 15:37:04 +040010041 $VTableChanged_M{$CName} = 1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010042 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040010043 else
10044 {
10045 my $ProblemType = "Added_Virtual_Method";
10046 if(isLeafClass($Class_Id, 1)) {
10047 $ProblemType = "Added_Virtual_Method_At_End_Of_Leaf_Allocable_Class";
10048 }
10049 %{$CompatProblems{$Level}{$Interface}{$ProblemType}{$tr_name{$AddedVFunc}}}=(
10050 "Type_Name"=>$CName,
10051 "Type_Type"=>"Class",
10052 "Target"=>get_Signature($AddedVFunc, 2) );
Andrey Ponomarenko16934472012-03-29 15:37:04 +040010053 $VTableChanged_M{$CName} = 1;
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040010054 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010055 }
10056 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040010057 elsif($CompleteSignature{1}{$Interface}{"Virt"}
10058 or $CompleteSignature{1}{$Interface}{"PureVirt"})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010059 {
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040010060 if(defined $VirtualTable{1}{$CName}
10061 and defined $VirtualTable{2}{$CName})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010062 {
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040010063 my $VPos_Old = $VirtualTable{1}{$CName}{$Interface};
10064 my $VPos_New = $VirtualTable{2}{$CName}{$Interface};
10065 if($VPos_Added<=$VPos_Old and $VPos_Old!=$VPos_New)
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040010066 {
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040010067 my @Affected = ($Interface, keys(%{$OverriddenMethods{1}{$Interface}}));
10068 foreach my $ASymbol (@Affected)
10069 {
Andrey Ponomarenko85043792012-05-14 16:48:07 +040010070 if(not $CompleteSignature{1}{$ASymbol}{"PureVirt"})
10071 {
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040010072 if(not symbolFilter($ASymbol, 1, "Affected", $Level)) {
Andrey Ponomarenko85043792012-05-14 16:48:07 +040010073 next;
10074 }
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040010075 }
10076 $CheckedSymbols{$Level}{$ASymbol} = 1;
10077 %{$CompatProblems{$Level}{$ASymbol}{"Added_Virtual_Method"}{$tr_name{$AddedVFunc}}}=(
10078 "Type_Name"=>$CName,
10079 "Type_Type"=>"Class",
10080 "Target"=>get_Signature($AddedVFunc, 2) );
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040010081 $VTableChanged_M{$TypeInfo{1}{$CompleteSignature{1}{$ASymbol}{"Class"}}{"Name"}} = 1;
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040010082 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010083 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010084 }
10085 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040010086 else {
10087 # safe
10088 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010089 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040010090 foreach my $RemovedVFunc (keys(%{$RemovedInt_Virt{$Level}{$CName}}))
10091 {
10092 next if($VirtualReplacement{$RemovedVFunc});
10093 if($RemovedVFunc eq $Interface
10094 and $CompleteSignature{1}{$RemovedVFunc}{"PureVirt"})
10095 { # This case is for removed virtual methods
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040010096 # implemented in both versions of a library
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040010097 next;
10098 }
Andrey Ponomarenko16934472012-03-29 15:37:04 +040010099 if(not keys(%{$VirtualTable_Model{2}{$CName}}))
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040010100 { # became non-polymorphous class, removed v-table pointer
10101 %{$CompatProblems{$Level}{$Interface}{"Removed_Last_Virtual_Method"}{$tr_name{$RemovedVFunc}}}=(
10102 "Type_Name"=>$CName,
10103 "Type_Type"=>"Class",
10104 "Target"=>get_Signature($RemovedVFunc, 1) );
Andrey Ponomarenko16934472012-03-29 15:37:04 +040010105 $VTableChanged_M{$CName} = 1;
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040010106 }
10107 elsif($CompleteSignature{1}{$Interface}{"Virt"}
10108 or $CompleteSignature{1}{$Interface}{"PureVirt"})
10109 {
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040010110 if(defined $VirtualTable{1}{$CName} and defined $VirtualTable{2}{$CName})
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040010111 {
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040010112 if(not defined $VirtualTable{1}{$CName}{$Interface}) {
10113 next;
10114 }
10115 my $VPos_New = -1;
10116 if(defined $VirtualTable{2}{$CName}{$Interface})
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040010117 {
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040010118 $VPos_New = $VirtualTable{2}{$CName}{$Interface};
10119 }
10120 else
10121 {
10122 if($Interface ne $RemovedVFunc) {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040010123 next;
10124 }
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040010125 }
10126 my $VPos_Removed = $VirtualTable{1}{$CName}{$RemovedVFunc};
10127 my $VPos_Old = $VirtualTable{1}{$CName}{$Interface};
10128 if($VPos_Removed<=$VPos_Old and $VPos_Old!=$VPos_New)
10129 {
10130 my @Affected = ($Interface, keys(%{$OverriddenMethods{1}{$Interface}}));
10131 foreach my $ASymbol (@Affected)
10132 {
Andrey Ponomarenko85043792012-05-14 16:48:07 +040010133 if(not $CompleteSignature{1}{$ASymbol}{"PureVirt"})
10134 {
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040010135 if(not symbolFilter($ASymbol, 1, "Affected", $Level)) {
Andrey Ponomarenko85043792012-05-14 16:48:07 +040010136 next;
10137 }
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040010138 }
10139 my $ProblemType = "Removed_Virtual_Method";
10140 if($CompleteSignature{1}{$RemovedVFunc}{"PureVirt"}) {
10141 $ProblemType = "Removed_Pure_Virtual_Method";
10142 }
10143 $CheckedSymbols{$Level}{$ASymbol} = 1;
10144 %{$CompatProblems{$Level}{$ASymbol}{$ProblemType}{$tr_name{$RemovedVFunc}}}=(
10145 "Type_Name"=>$CName,
10146 "Type_Type"=>"Class",
10147 "Target"=>get_Signature($RemovedVFunc, 1) );
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040010148 $VTableChanged_M{$TypeInfo{1}{$CompleteSignature{1}{$ASymbol}{"Class"}}{"Name"}} = 1;
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040010149 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040010150 }
10151 }
10152 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010153 }
10154 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040010155 else
10156 { # Source-level
10157 foreach my $AddedVFunc (keys(%{$AddedInt_Virt{$Level}{$CName}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010158 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040010159 next if($Interface eq $AddedVFunc);
10160 if($CompleteSignature{2}{$AddedVFunc}{"PureVirt"})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010161 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040010162 %{$CompatProblems{$Level}{$Interface}{"Added_Pure_Virtual_Method"}{$tr_name{$AddedVFunc}}}=(
10163 "Type_Name"=>$CName,
10164 "Type_Type"=>"Class",
10165 "Target"=>get_Signature($AddedVFunc, 2) );
10166 }
10167 }
10168 foreach my $RemovedVFunc (keys(%{$RemovedInt_Virt{$Level}{$CName}}))
10169 {
10170 if($CompleteSignature{1}{$RemovedVFunc}{"PureVirt"})
10171 {
10172 %{$CompatProblems{$Level}{$Interface}{"Removed_Pure_Virtual_Method"}{$tr_name{$RemovedVFunc}}}=(
10173 "Type_Name"=>$CName,
10174 "Type_Type"=>"Class",
10175 "Target"=>get_Signature($RemovedVFunc, 1) );
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010176 }
10177 }
10178 }
10179}
10180
10181sub find_MemberPair_Pos_byName($$)
10182{
10183 my ($Member_Name, $Pair_Type) = @_;
10184 $Member_Name=~s/\A[_]+|[_]+\Z//g;
10185 foreach my $MemberPair_Pos (sort {int($a)<=>int($b)} keys(%{$Pair_Type->{"Memb"}}))
10186 {
10187 if(defined $Pair_Type->{"Memb"}{$MemberPair_Pos})
10188 {
10189 my $Name = $Pair_Type->{"Memb"}{$MemberPair_Pos}{"name"};
10190 $Name=~s/\A[_]+|[_]+\Z//g;
10191 if($Name eq $Member_Name) {
10192 return $MemberPair_Pos;
10193 }
10194 }
10195 }
10196 return "lost";
10197}
10198
10199sub find_MemberPair_Pos_byVal($$)
10200{
10201 my ($Member_Value, $Pair_Type) = @_;
10202 foreach my $MemberPair_Pos (sort {int($a)<=>int($b)} keys(%{$Pair_Type->{"Memb"}}))
10203 {
10204 if(defined $Pair_Type->{"Memb"}{$MemberPair_Pos}
10205 and $Pair_Type->{"Memb"}{$MemberPair_Pos}{"value"} eq $Member_Value) {
10206 return $MemberPair_Pos;
10207 }
10208 }
10209 return "lost";
10210}
10211
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040010212my %Severity_Val=(
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010213 "High"=>3,
10214 "Medium"=>2,
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040010215 "Low"=>1,
10216 "Safe"=>-1
10217);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010218
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040010219sub maxSeverity($$)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010220{
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040010221 my ($S1, $S2) = @_;
10222 if(cmpSeverities($S1, $S2)) {
10223 return $S1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010224 }
10225 else {
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040010226 return $S2;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010227 }
10228}
10229
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040010230sub cmpSeverities($$)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010231{
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040010232 my ($S1, $S2) = @_;
10233 if(not $S1) {
10234 return 0;
10235 }
10236 elsif(not $S2) {
10237 return 1;
10238 }
10239 return ($Severity_Val{$S1}>$Severity_Val{$S2});
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010240}
10241
10242sub getProblemSeverity($$)
10243{
10244 my ($Level, $Kind) = @_;
10245 return $CompatRules{$Level}{$Kind}{"Severity"};
10246}
10247
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040010248sub isRecurType($$)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010249{
10250 foreach (@RecurTypes)
10251 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040010252 if( $_->{"T1"} eq $_[0]
10253 and $_->{"T2"} eq $_[1] )
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010254 {
10255 return 1;
10256 }
10257 }
10258 return 0;
10259}
10260
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040010261sub pushType($$)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010262{
10263 my %TypeIDs=(
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040010264 "T1" => $_[0], #Tid1
10265 "T2" => $_[1] #Tid2
Andrey Ponomarenko16934472012-03-29 15:37:04 +040010266 );
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010267 push(@RecurTypes, \%TypeIDs);
10268}
10269
10270sub isRenamed($$$$$)
10271{
10272 my ($MemPos, $Type1, $LVersion1, $Type2, $LVersion2) = @_;
10273 my $Member_Name = $Type1->{"Memb"}{$MemPos}{"name"};
10274 my $MemberType_Id = $Type1->{"Memb"}{$MemPos}{"type"};
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +040010275 my %MemberType_Pure = get_PureType($MemberType_Id, $TypeInfo{$LVersion1});
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010276 if(not defined $Type2->{"Memb"}{$MemPos}) {
10277 return "";
10278 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040010279 my $PairType_Id = $Type2->{"Memb"}{$MemPos}{"type"};
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +040010280 my %PairType_Pure = get_PureType($PairType_Id, $TypeInfo{$LVersion2});
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010281
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040010282 my $Pair_Name = $Type2->{"Memb"}{$MemPos}{"name"};
10283 my $MemberPair_Pos_Rev = ($Member_Name eq $Pair_Name)?$MemPos:find_MemberPair_Pos_byName($Pair_Name, $Type1);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010284 if($MemberPair_Pos_Rev eq "lost")
10285 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040010286 if($MemberType_Pure{"Name"} eq $PairType_Pure{"Name"})
10287 { # base type match
10288 return $Pair_Name;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010289 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040010290 if($TypeInfo{$LVersion1}{$MemberType_Id}{"Name"} eq $TypeInfo{$LVersion2}{$PairType_Id}{"Name"})
10291 { # exact type match
10292 return $Pair_Name;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010293 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040010294 if($MemberType_Pure{"Size"} eq $PairType_Pure{"Size"})
10295 { # size match
10296 return $Pair_Name;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010297 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040010298 if(isReserved($Pair_Name))
10299 { # reserved fields
10300 return $Pair_Name;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010301 }
10302 }
10303 return "";
10304}
10305
10306sub isLastElem($$)
10307{
10308 my ($Pos, $TypeRef) = @_;
10309 my $Name = $TypeRef->{"Memb"}{$Pos}{"name"};
10310 if($Name=~/last|count|max|total/i)
10311 { # GST_LEVEL_COUNT, GST_RTSP_ELAST
10312 return 1;
10313 }
10314 elsif($Name=~/END|NLIMITS\Z/)
10315 { # __RLIMIT_NLIMITS
10316 return 1;
10317 }
10318 elsif($Name=~/\AN[A-Z](.+)[a-z]+s\Z/
10319 and $Pos+1==keys(%{$TypeRef->{"Memb"}}))
10320 { # NImageFormats, NColorRoles
10321 return 1;
10322 }
10323 return 0;
10324}
10325
10326sub nonComparable($$)
10327{
10328 my ($T1, $T2) = @_;
10329 if($T1->{"Name"} ne $T2->{"Name"}
10330 and not isAnon($T1->{"Name"})
10331 and not isAnon($T2->{"Name"}))
10332 { # different names
10333 if($T1->{"Type"} ne "Pointer"
10334 or $T2->{"Type"} ne "Pointer")
10335 { # compare base types
10336 return 1;
10337 }
10338 if($T1->{"Name"}!~/\Avoid\s*\*/
10339 and $T2->{"Name"}=~/\Avoid\s*\*/)
10340 {
10341 return 1;
10342 }
10343 }
10344 elsif($T1->{"Type"} ne $T2->{"Type"})
10345 { # different types
10346 if($T1->{"Type"} eq "Class"
10347 and $T2->{"Type"} eq "Struct")
10348 { # "class" to "struct"
10349 return 0;
10350 }
10351 elsif($T2->{"Type"} eq "Class"
10352 and $T1->{"Type"} eq "Struct")
10353 { # "struct" to "class"
10354 return 0;
10355 }
10356 else
10357 { # "class" to "enum"
10358 # "union" to "class"
10359 # ...
10360 return 1;
10361 }
10362 }
10363 return 0;
10364}
10365
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040010366sub mergeTypes($$$)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010367{
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040010368 my ($Type1_Id, $Type2_Id, $Level) = @_;
10369 return () if(not $Type1_Id or not $Type2_Id);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010370 my (%Sub_SubProblems, %SubProblems) = ();
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040010371 if($Cache{"mergeTypes"}{$Level}{$Type1_Id}{$Type2_Id})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010372 { # already merged
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040010373 return %{$Cache{"mergeTypes"}{$Level}{$Type1_Id}{$Type2_Id}};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010374 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040010375 my %Type1 = get_Type($Type1_Id, 1);
10376 my %Type2 = get_Type($Type2_Id, 2);
Andrey Ponomarenko16934472012-03-29 15:37:04 +040010377 if(not $Type1{"Name"} or not $Type2{"Name"}) {
10378 return ();
10379 }
10380 $CheckedTypes{$Level}{$Type1{"Name"}}=1;
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +040010381 my %Type1_Pure = get_PureType($Type1_Id, $TypeInfo{1});
10382 my %Type2_Pure = get_PureType($Type2_Id, $TypeInfo{2});
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040010383 $CheckedTypes{$Level}{$Type1_Pure{"Name"}}=1;
Andrey Ponomarenko85043792012-05-14 16:48:07 +040010384 if(not $Type1_Pure{"Size"} or not $Type2_Pure{"Size"})
10385 { # including a case when "class Class { ... };" changed to "class Class;"
10386 return ();
10387 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040010388 if(isRecurType($Type1_Pure{"Tid"}, $Type2_Pure{"Tid"}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010389 { # skip recursive declarations
10390 return ();
10391 }
10392 return () if(not $Type1_Pure{"Name"} or not $Type2_Pure{"Name"});
10393 return () if($SkipTypes{1}{$Type1_Pure{"Name"}});
10394 return () if($SkipTypes{1}{$Type1{"Name"}});
10395
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040010396 my %Typedef_1 = goToFirst($Type1{"Tid"}, 1, "Typedef");
10397 my %Typedef_2 = goToFirst($Type2{"Tid"}, 2, "Typedef");
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040010398 if(not $UseOldDumps and %Typedef_1 and %Typedef_2
10399 and $Typedef_1{"Type"} eq "Typedef" and $Typedef_2{"Type"} eq "Typedef"
10400 and $Typedef_1{"Name"} eq $Typedef_2{"Name"})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010401 {
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +040010402 my %Base_1 = get_OneStep_BaseType($Typedef_1{"Tid"}, $TypeInfo{1});
10403 my %Base_2 = get_OneStep_BaseType($Typedef_2{"Tid"}, $TypeInfo{2});
Andrey Ponomarenko85043792012-05-14 16:48:07 +040010404 if($Base_1{"Name"} ne $Base_2{"Name"})
10405 {
10406 if(differentDumps("G")
10407 or differentDumps("V"))
10408 { # different GCC versions or different dumps
10409 $Base_1{"Name"} = uncover_typedefs($Base_1{"Name"}, 1);
10410 $Base_2{"Name"} = uncover_typedefs($Base_2{"Name"}, 2);
10411 # std::__va_list and __va_list
10412 $Base_1{"Name"}=~s/\A(\w+::)+//;
10413 $Base_2{"Name"}=~s/\A(\w+::)+//;
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040010414 $Base_1{"Name"} = formatName($Base_1{"Name"}, "T");
10415 $Base_2{"Name"} = formatName($Base_2{"Name"}, "T");
Andrey Ponomarenko85043792012-05-14 16:48:07 +040010416 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010417 }
10418 if($Base_1{"Name"}!~/anon\-/ and $Base_2{"Name"}!~/anon\-/
10419 and $Base_1{"Name"} ne $Base_2{"Name"})
10420 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040010421 if($Level eq "Binary"
10422 and $Type1{"Size"} ne $Type2{"Size"})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010423 {
10424 %{$SubProblems{"DataType_Size"}{$Typedef_1{"Name"}}}=(
10425 "Target"=>$Typedef_1{"Name"},
10426 "Type_Name"=>$Typedef_1{"Name"},
10427 "Type_Type"=>"Typedef",
10428 "Old_Size"=>$Type1{"Size"}*$BYTE_SIZE,
10429 "New_Size"=>$Type2{"Size"}*$BYTE_SIZE );
10430 }
10431 %{$SubProblems{"Typedef_BaseType"}{$Typedef_1{"Name"}}}=(
10432 "Target"=>$Typedef_1{"Name"},
10433 "Type_Name"=>$Typedef_1{"Name"},
10434 "Type_Type"=>"Typedef",
10435 "Old_Value"=>$Base_1{"Name"},
10436 "New_Value"=>$Base_2{"Name"} );
10437 }
10438 }
10439 if(nonComparable(\%Type1_Pure, \%Type2_Pure))
10440 { # different types (reported in detectTypeChange(...))
10441 if($Type1_Pure{"Name"} eq $Type2_Pure{"Name"}
10442 and $Type1_Pure{"Type"} ne $Type2_Pure{"Type"}
10443 and $Type1_Pure{"Type"}!~/Intrinsic|Pointer|Ref|Typedef/)
10444 { # different type of the type
10445 %{$SubProblems{"DataType_Type"}{$Type1_Pure{"Name"}}}=(
10446 "Target"=>$Type1_Pure{"Name"},
10447 "Type_Name"=>$Type1_Pure{"Name"},
10448 "Type_Type"=>$Type1_Pure{"Type"},
10449 "Old_Value"=>lc($Type1_Pure{"Type"}),
10450 "New_Value"=>lc($Type2_Pure{"Type"}) );
10451 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040010452 %{$Cache{"mergeTypes"}{$Level}{$Type1_Id}{$Type2_Id}} = %SubProblems;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010453 return %SubProblems;
10454 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040010455 pushType($Type1_Pure{"Tid"}, $Type2_Pure{"Tid"});
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010456 if(($Type1_Pure{"Name"} eq $Type2_Pure{"Name"}
10457 or (isAnon($Type1_Pure{"Name"}) and isAnon($Type2_Pure{"Name"})))
10458 and $Type1_Pure{"Type"}=~/\A(Struct|Class|Union)\Z/)
10459 { # checking size
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040010460 if($Level eq "Binary"
10461 and $Type1_Pure{"Size"} ne $Type2_Pure{"Size"})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010462 {
10463 my $ProblemKind = "DataType_Size";
10464 if($Type1_Pure{"Type"} eq "Class"
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040010465 and keys(%{$ClassMethods{$Level}{1}{$Type1_Pure{"Name"}}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010466 {
10467 if(isCopyingClass($Type1_Pure{"Tid"}, 1)) {
10468 $ProblemKind = "Size_Of_Copying_Class";
10469 }
10470 elsif($AllocableClass{1}{$Type1_Pure{"Name"}})
10471 {
10472 if(int($Type2_Pure{"Size"})>int($Type1_Pure{"Size"})) {
10473 $ProblemKind = "Size_Of_Allocable_Class_Increased";
10474 }
10475 else {
10476 # descreased size of allocable class
10477 # it has no special effects
10478 }
10479 }
10480 }
10481 %{$SubProblems{$ProblemKind}{$Type1_Pure{"Name"}}}=(
10482 "Target"=>$Type1_Pure{"Name"},
10483 "Type_Name"=>$Type1_Pure{"Name"},
10484 "Type_Type"=>$Type1_Pure{"Type"},
10485 "Old_Size"=>$Type1_Pure{"Size"}*$BYTE_SIZE,
10486 "New_Size"=>$Type2_Pure{"Size"}*$BYTE_SIZE,
10487 "InitialType_Type"=>$Type1_Pure{"Type"} );
10488 }
10489 }
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040010490 if(defined $Type1_Pure{"BaseType"} and $Type1_Pure{"BaseType"}{"Tid"}
10491 and defined $Type2_Pure{"BaseType"} and $Type2_Pure{"BaseType"}{"Tid"})
10492 { # checking base types
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040010493 %Sub_SubProblems = mergeTypes($Type1_Pure{"BaseType"}{"Tid"}, $Type2_Pure{"BaseType"}{"Tid"}, $Level);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010494 foreach my $Sub_SubProblemType (keys(%Sub_SubProblems))
10495 {
10496 foreach my $Sub_SubLocation (keys(%{$Sub_SubProblems{$Sub_SubProblemType}}))
10497 {
10498 foreach my $Attr (keys(%{$Sub_SubProblems{$Sub_SubProblemType}{$Sub_SubLocation}})) {
10499 $SubProblems{$Sub_SubProblemType}{$Sub_SubLocation}{$Attr} = $Sub_SubProblems{$Sub_SubProblemType}{$Sub_SubLocation}{$Attr};
10500 }
10501 $SubProblems{$Sub_SubProblemType}{$Sub_SubLocation}{"InitialType_Type"} = $Type1_Pure{"Type"};
10502 }
10503 }
10504 }
10505 my (%AddedField, %RemovedField, %RenamedField, %RenamedField_Rev, %RelatedField, %RelatedField_Rev) = ();
10506 my %NameToPosA = map {$Type1_Pure{"Memb"}{$_}{"name"}=>$_} keys(%{$Type1_Pure{"Memb"}});
10507 my %NameToPosB = map {$Type2_Pure{"Memb"}{$_}{"name"}=>$_} keys(%{$Type2_Pure{"Memb"}});
10508 foreach my $Member_Pos (sort {int($a) <=> int($b)} keys(%{$Type1_Pure{"Memb"}}))
10509 { # detect removed and renamed fields
10510 my $Member_Name = $Type1_Pure{"Memb"}{$Member_Pos}{"name"};
10511 next if(not $Member_Name);
10512 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);
10513 if($MemberPair_Pos eq "lost")
10514 {
10515 if($Type2_Pure{"Type"}=~/\A(Struct|Class|Union)\Z/)
10516 {
10517 if(isUnnamed($Member_Name))
10518 { # support for old-version dumps
10519 # unnamed fields have been introduced in the ACC 1.23 (dump 2.1 format)
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040010520 if(not checkDump(2, "2.1")) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010521 next;
10522 }
10523 }
10524 if(my $RenamedTo = isRenamed($Member_Pos, \%Type1_Pure, 1, \%Type2_Pure, 2))
10525 { # renamed
10526 $RenamedField{$Member_Pos}=$RenamedTo;
10527 $RenamedField_Rev{$NameToPosB{$RenamedTo}}=$Member_Name;
10528 }
10529 else
10530 { # removed
10531 $RemovedField{$Member_Pos}=1;
10532 }
10533 }
10534 elsif($Type1_Pure{"Type"} eq "Enum")
10535 {
10536 my $Member_Value1 = $Type1_Pure{"Memb"}{$Member_Pos}{"value"};
10537 next if($Member_Value1 eq "");
10538 $MemberPair_Pos = find_MemberPair_Pos_byVal($Member_Value1, \%Type2_Pure);
10539 if($MemberPair_Pos ne "lost")
10540 { # renamed
10541 my $RenamedTo = $Type2_Pure{"Memb"}{$MemberPair_Pos}{"name"};
10542 my $MemberPair_Pos_Rev = find_MemberPair_Pos_byName($RenamedTo, \%Type1_Pure);
10543 if($MemberPair_Pos_Rev eq "lost")
10544 {
10545 $RenamedField{$Member_Pos}=$RenamedTo;
10546 $RenamedField_Rev{$NameToPosB{$RenamedTo}}=$Member_Name;
10547 }
10548 else {
10549 $RemovedField{$Member_Pos}=1;
10550 }
10551 }
10552 else
10553 { # removed
10554 $RemovedField{$Member_Pos}=1;
10555 }
10556 }
10557 }
10558 else
10559 { # related
10560 $RelatedField{$Member_Pos} = $MemberPair_Pos;
10561 $RelatedField_Rev{$MemberPair_Pos} = $Member_Pos;
10562 }
10563 }
10564 foreach my $Member_Pos (sort {int($a) <=> int($b)} keys(%{$Type2_Pure{"Memb"}}))
10565 { # detect added fields
10566 my $Member_Name = $Type2_Pure{"Memb"}{$Member_Pos}{"name"};
10567 next if(not $Member_Name);
10568 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);
10569 if($MemberPair_Pos eq "lost")
10570 {
10571 if(isUnnamed($Member_Name))
10572 { # support for old-version dumps
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040010573 # unnamed fields have been introduced in the ACC 1.23 (dump 2.1 format)
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040010574 if(not checkDump(1, "2.1")) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010575 next;
10576 }
10577 }
10578 if($Type2_Pure{"Type"}=~/\A(Struct|Class|Union|Enum)\Z/)
10579 {
10580 if(not $RenamedField_Rev{$Member_Pos})
10581 { # added
10582 $AddedField{$Member_Pos}=1;
10583 }
10584 }
10585 }
10586 }
10587 if($Type2_Pure{"Type"}=~/\A(Struct|Class)\Z/)
10588 { # detect moved fields
10589 my (%RelPos, %RelPosName, %AbsPos) = ();
10590 my $Pos = 0;
10591 foreach my $Member_Pos (sort {int($a) <=> int($b)} keys(%{$Type1_Pure{"Memb"}}))
10592 { # relative positions in 1st version
10593 my $Member_Name = $Type1_Pure{"Memb"}{$Member_Pos}{"name"};
10594 next if(not $Member_Name);
10595 if(not $RemovedField{$Member_Pos})
10596 { # old type without removed fields
10597 $RelPos{1}{$Member_Name}=$Pos;
10598 $RelPosName{1}{$Pos} = $Member_Name;
10599 $AbsPos{1}{$Pos++} = $Member_Pos;
10600 }
10601 }
10602 $Pos = 0;
10603 foreach my $Member_Pos (sort {int($a) <=> int($b)} keys(%{$Type2_Pure{"Memb"}}))
10604 { # relative positions in 2nd version
10605 my $Member_Name = $Type2_Pure{"Memb"}{$Member_Pos}{"name"};
10606 next if(not $Member_Name);
10607 if(not $AddedField{$Member_Pos})
10608 { # new type without added fields
10609 $RelPos{2}{$Member_Name}=$Pos;
10610 $RelPosName{2}{$Pos} = $Member_Name;
10611 $AbsPos{2}{$Pos++} = $Member_Pos;
10612 }
10613 }
10614 foreach my $Member_Name (keys(%{$RelPos{1}}))
10615 {
10616 my $RPos1 = $RelPos{1}{$Member_Name};
10617 my $AbsPos1 = $NameToPosA{$Member_Name};
10618 my $Member_Name2 = $Member_Name;
10619 if(my $RenamedTo = $RenamedField{$AbsPos1})
10620 { # renamed
10621 $Member_Name2 = $RenamedTo;
10622 }
10623 my $RPos2 = $RelPos{2}{$Member_Name2};
10624 if($RPos2 ne "" and $RPos1 ne $RPos2)
10625 { # different relative positions
10626 my $AbsPos2 = $NameToPosB{$Member_Name2};
10627 if($AbsPos1 ne $AbsPos2)
10628 { # different absolute positions
10629 my $ProblemType = "Moved_Field";
10630 if(not isPublic(\%Type1_Pure, $AbsPos1))
10631 { # may change layout and size of type
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040010632 if($Level eq "Source") {
10633 next;
10634 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010635 $ProblemType = "Moved_Private_Field";
10636 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040010637 if($Level eq "Binary"
10638 and $Type1_Pure{"Size"} ne $Type2_Pure{"Size"})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010639 { # affected size
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040010640 my $MemSize1 = $TypeInfo{1}{$Type1_Pure{"Memb"}{$AbsPos1}{"type"}}{"Size"};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010641 my $MovedAbsPos = $AbsPos{1}{$RPos2};
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040010642 my $MemSize2 = $TypeInfo{1}{$Type1_Pure{"Memb"}{$MovedAbsPos}{"type"}}{"Size"};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010643 if($MemSize1 ne $MemSize2) {
10644 $ProblemType .= "_And_Size";
10645 }
10646 }
10647 if($ProblemType eq "Moved_Private_Field") {
10648 next;
10649 }
10650 %{$SubProblems{$ProblemType}{$Member_Name}}=(
10651 "Target"=>$Member_Name,
10652 "Type_Name"=>$Type1_Pure{"Name"},
10653 "Type_Type"=>$Type1_Pure{"Type"},
10654 "Old_Value"=>$RPos1,
10655 "New_Value"=>$RPos2 );
10656 }
10657 }
10658 }
10659 }
10660 foreach my $Member_Pos (sort {int($a) <=> int($b)} keys(%{$Type1_Pure{"Memb"}}))
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040010661 { # check older fields, public and private
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010662 my $Member_Name = $Type1_Pure{"Memb"}{$Member_Pos}{"name"};
10663 next if(not $Member_Name);
10664 if(my $RenamedTo = $RenamedField{$Member_Pos})
10665 { # renamed
10666 if($Type2_Pure{"Type"}=~/\A(Struct|Class|Union)\Z/)
10667 {
10668 if(isPublic(\%Type1_Pure, $Member_Pos))
10669 {
10670 %{$SubProblems{"Renamed_Field"}{$Member_Name}}=(
10671 "Target"=>$Member_Name,
10672 "Type_Name"=>$Type1_Pure{"Name"},
10673 "Type_Type"=>$Type1_Pure{"Type"},
10674 "Old_Value"=>$Member_Name,
10675 "New_Value"=>$RenamedTo );
10676 }
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040010677 elsif(isReserved($Member_Name))
10678 {
10679 %{$SubProblems{"Used_Reserved_Field"}{$Member_Name}}=(
10680 "Target"=>$Member_Name,
10681 "Type_Name"=>$Type1_Pure{"Name"},
10682 "Type_Type"=>$Type1_Pure{"Type"},
10683 "Old_Value"=>$Member_Name,
10684 "New_Value"=>$RenamedTo );
10685 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010686 }
10687 elsif($Type1_Pure{"Type"} eq "Enum")
10688 {
10689 %{$SubProblems{"Enum_Member_Name"}{$Type1_Pure{"Memb"}{$Member_Pos}{"value"}}}=(
10690 "Target"=>$Type1_Pure{"Memb"}{$Member_Pos}{"value"},
10691 "Type_Name"=>$Type1_Pure{"Name"},
10692 "Type_Type"=>$Type1_Pure{"Type"},
10693 "Old_Value"=>$Member_Name,
10694 "New_Value"=>$RenamedTo );
10695 }
10696 }
10697 elsif($RemovedField{$Member_Pos})
10698 { # removed
10699 if($Type2_Pure{"Type"}=~/\A(Struct|Class)\Z/)
10700 {
10701 my $ProblemType = "Removed_Field";
10702 if(not isPublic(\%Type1_Pure, $Member_Pos)
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040010703 or isUnnamed($Member_Name))
10704 {
10705 if($Level eq "Source") {
10706 next;
10707 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010708 $ProblemType = "Removed_Private_Field";
10709 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040010710 if($Level eq "Binary"
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +040010711 and not isMemPadded($Member_Pos, -1, \%Type1_Pure, \%RemovedField, $TypeInfo{1}, $WORD_SIZE{1}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010712 {
10713 if(my $MNum = isAccessible(\%Type1_Pure, \%RemovedField, $Member_Pos+1, -1))
10714 { # affected fields
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +040010715 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 +040010716 { # changed offset
10717 $ProblemType .= "_And_Layout";
10718 }
10719 }
10720 if($Type1_Pure{"Size"} ne $Type2_Pure{"Size"})
10721 { # affected size
10722 $ProblemType .= "_And_Size";
10723 }
10724 }
10725 if($ProblemType eq "Removed_Private_Field") {
10726 next;
10727 }
10728 %{$SubProblems{$ProblemType}{$Member_Name}}=(
10729 "Target"=>$Member_Name,
10730 "Type_Name"=>$Type1_Pure{"Name"},
10731 "Type_Type"=>$Type1_Pure{"Type"} );
10732 }
10733 elsif($Type2_Pure{"Type"} eq "Union")
10734 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040010735 if($Level eq "Binary"
10736 and $Type1_Pure{"Size"} ne $Type2_Pure{"Size"})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010737 {
10738 %{$SubProblems{"Removed_Union_Field_And_Size"}{$Member_Name}}=(
10739 "Target"=>$Member_Name,
10740 "Type_Name"=>$Type1_Pure{"Name"},
10741 "Type_Type"=>$Type1_Pure{"Type"} );
10742 }
10743 else
10744 {
10745 %{$SubProblems{"Removed_Union_Field"}{$Member_Name}}=(
10746 "Target"=>$Member_Name,
10747 "Type_Name"=>$Type1_Pure{"Name"},
10748 "Type_Type"=>$Type1_Pure{"Type"} );
10749 }
10750 }
10751 elsif($Type1_Pure{"Type"} eq "Enum")
10752 {
10753 %{$SubProblems{"Enum_Member_Removed"}{$Member_Name}}=(
10754 "Target"=>$Member_Name,
10755 "Type_Name"=>$Type1_Pure{"Name"},
10756 "Type_Type"=>$Type1_Pure{"Type"},
10757 "Old_Value"=>$Member_Name );
10758 }
10759 }
10760 else
10761 { # changed
10762 my $MemberPair_Pos = $RelatedField{$Member_Pos};
10763 if($Type1_Pure{"Type"} eq "Enum")
10764 {
10765 my $Member_Value1 = $Type1_Pure{"Memb"}{$Member_Pos}{"value"};
10766 next if($Member_Value1 eq "");
10767 my $Member_Value2 = $Type2_Pure{"Memb"}{$MemberPair_Pos}{"value"};
10768 next if($Member_Value2 eq "");
10769 if($Member_Value1 ne $Member_Value2)
10770 {
10771 my $ProblemType = "Enum_Member_Value";
10772 if(isLastElem($Member_Pos, \%Type1_Pure)) {
10773 $ProblemType = "Enum_Last_Member_Value";
10774 }
10775 %{$SubProblems{$ProblemType}{$Member_Name}}=(
10776 "Target"=>$Member_Name,
10777 "Type_Name"=>$Type1_Pure{"Name"},
10778 "Type_Type"=>$Type1_Pure{"Type"},
10779 "Old_Value"=>$Member_Value1,
10780 "New_Value"=>$Member_Value2 );
10781 }
10782 }
10783 elsif($Type2_Pure{"Type"}=~/\A(Struct|Class|Union)\Z/)
10784 {
10785 my $MemberType1_Id = $Type1_Pure{"Memb"}{$Member_Pos}{"type"};
10786 my $MemberType2_Id = $Type2_Pure{"Memb"}{$MemberPair_Pos}{"type"};
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040010787 my $SizeV1 = $TypeInfo{1}{$MemberType1_Id}{"Size"}*$BYTE_SIZE;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010788 if(my $BSize1 = $Type1_Pure{"Memb"}{$Member_Pos}{"bitfield"}) {
10789 $SizeV1 = $BSize1;
10790 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040010791 my $SizeV2 = $TypeInfo{2}{$MemberType2_Id}{"Size"}*$BYTE_SIZE;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010792 if(my $BSize2 = $Type2_Pure{"Memb"}{$MemberPair_Pos}{"bitfield"}) {
10793 $SizeV2 = $BSize2;
10794 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040010795 my $MemberType1_Name = $TypeInfo{1}{$MemberType1_Id}{"Name"};
10796 my $MemberType2_Name = $TypeInfo{2}{$MemberType2_Id}{"Name"};
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040010797 if($Level eq "Binary"
10798 and $SizeV1 ne $SizeV2)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010799 {
10800 if($MemberType1_Name eq $MemberType2_Name or (isAnon($MemberType1_Name) and isAnon($MemberType2_Name))
10801 or ($Type1_Pure{"Memb"}{$Member_Pos}{"bitfield"} and $Type2_Pure{"Memb"}{$MemberPair_Pos}{"bitfield"}))
10802 { # field size change (including anon-structures and unions)
10803 # - same types
10804 # - unnamed types
10805 # - bitfields
10806 my $ProblemType = "Field_Size";
10807 if(not isPublic(\%Type1_Pure, $Member_Pos)
10808 or isUnnamed($Member_Name))
10809 { # should not be accessed by applications, goes to "Low Severity"
10810 # example: "abidata" members in GStreamer types
10811 $ProblemType = "Private_".$ProblemType;
10812 }
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +040010813 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 +040010814 { # check an effect
10815 if(my $MNum = isAccessible(\%Type1_Pure, \%RemovedField, $Member_Pos+1, -1))
10816 { # public fields after the current
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +040010817 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 +040010818 { # changed offset
10819 $ProblemType .= "_And_Layout";
10820 }
10821 }
10822 if($Type1_Pure{"Size"} ne $Type2_Pure{"Size"}) {
10823 $ProblemType .= "_And_Type_Size";
10824 }
10825 }
10826 if($ProblemType eq "Private_Field_Size")
10827 { # private field size with no effect
10828 $ProblemType = "";
10829 }
10830 if($ProblemType)
10831 { # register a problem
10832 %{$SubProblems{$ProblemType}{$Member_Name}}=(
10833 "Target"=>$Member_Name,
10834 "Type_Name"=>$Type1_Pure{"Name"},
10835 "Type_Type"=>$Type1_Pure{"Type"},
10836 "Old_Size"=>$SizeV1,
10837 "New_Size"=>$SizeV2);
10838 }
10839 }
10840 }
10841 if($Type1_Pure{"Memb"}{$Member_Pos}{"bitfield"}
10842 or $Type2_Pure{"Memb"}{$MemberPair_Pos}{"bitfield"})
10843 { # do NOT check bitfield type changes
10844 next;
10845 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040010846 if(checkDump(1, "2.13") and checkDump(2, "2.13"))
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040010847 {
10848 if(not $Type1_Pure{"Memb"}{$Member_Pos}{"mutable"}
10849 and $Type2_Pure{"Memb"}{$MemberPair_Pos}{"mutable"})
10850 {
10851 %{$SubProblems{"Field_Became_Mutable"}{$Member_Name}}=(
10852 "Target"=>$Member_Name,
10853 "Type_Name"=>$Type1_Pure{"Name"},
10854 "Type_Type"=>$Type1_Pure{"Type"});
10855 }
10856 elsif($Type1_Pure{"Memb"}{$Member_Pos}{"mutable"}
10857 and not $Type2_Pure{"Memb"}{$MemberPair_Pos}{"mutable"})
10858 {
10859 %{$SubProblems{"Field_Became_NonMutable"}{$Member_Name}}=(
10860 "Target"=>$Member_Name,
10861 "Type_Name"=>$Type1_Pure{"Name"},
10862 "Type_Type"=>$Type1_Pure{"Type"});
10863 }
10864 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040010865 %Sub_SubProblems = detectTypeChange($MemberType1_Id, $MemberType2_Id, "Field", $Level);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010866 foreach my $ProblemType (keys(%Sub_SubProblems))
10867 {
10868 my $Old_Value = $Sub_SubProblems{$ProblemType}{"Old_Value"};
10869 my $New_Value = $Sub_SubProblems{$ProblemType}{"New_Value"};
10870 if($ProblemType eq "Field_Type"
10871 or $ProblemType eq "Field_Type_And_Size")
10872 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040010873 if(checkDump(1, "2.6") and checkDump(2, "2.6"))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010874 {
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040010875 if(my $RA = addedQual($Old_Value, $New_Value, "volatile"))
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040010876 {
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040010877 %{$Sub_SubProblems{"Field_Became_Volatile"}} = %{$Sub_SubProblems{$ProblemType}};
10878 if($Level eq "Source"
10879 and cmpBTypes($Old_Value, $New_Value, 1, 2)) {
10880 delete($Sub_SubProblems{$ProblemType});
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040010881 }
10882 }
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040010883 elsif(my $RR = removedQual($Old_Value, $New_Value, "volatile"))
10884 {
10885 %{$Sub_SubProblems{"Field_Became_NonVolatile"}} = %{$Sub_SubProblems{$ProblemType}};
10886 if($Level eq "Source"
10887 and cmpBTypes($Old_Value, $New_Value, 1, 2)) {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040010888 delete($Sub_SubProblems{$ProblemType});
10889 }
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040010890 }
10891 }
10892 if(my $RA = addedQual($Old_Value, $New_Value, "const"))
10893 {
10894 if($RA==2) {
10895 %{$Sub_SubProblems{"Field_Added_Const"}} = %{$Sub_SubProblems{$ProblemType}};
10896 }
10897 else {
10898 %{$Sub_SubProblems{"Field_Became_Const"}} = %{$Sub_SubProblems{$ProblemType}};
10899 }
10900 if($Level eq "Source"
10901 and cmpBTypes($Old_Value, $New_Value, 1, 2)) {
10902 delete($Sub_SubProblems{$ProblemType});
10903 }
10904 }
10905 elsif(my $RR = removedQual($Old_Value, $New_Value, "const"))
10906 {
10907 if($RR==2) {
10908 %{$Sub_SubProblems{"Field_Removed_Const"}} = %{$Sub_SubProblems{$ProblemType}};
10909 }
10910 else {
10911 %{$Sub_SubProblems{"Field_Became_NonConst"}} = %{$Sub_SubProblems{$ProblemType}};
10912 }
10913 if($Level eq "Source"
10914 and cmpBTypes($Old_Value, $New_Value, 1, 2)) {
10915 delete($Sub_SubProblems{$ProblemType});
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010916 }
10917 }
10918 }
10919 }
10920 foreach my $ProblemType (keys(%Sub_SubProblems))
10921 {
10922 my $ProblemType_Init = $ProblemType;
10923 if($ProblemType eq "Field_Type_And_Size")
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040010924 { # Binary
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010925 if(not isPublic(\%Type1_Pure, $Member_Pos)
10926 or isUnnamed($Member_Name)) {
10927 $ProblemType = "Private_".$ProblemType;
10928 }
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +040010929 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 +040010930 { # check an effect
10931 if(my $MNum = isAccessible(\%Type1_Pure, \%RemovedField, $Member_Pos+1, -1))
10932 { # public fields after the current
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +040010933 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 +040010934 { # changed offset
10935 $ProblemType .= "_And_Layout";
10936 }
10937 }
10938 if($Type1_Pure{"Size"} ne $Type2_Pure{"Size"}) {
10939 $ProblemType .= "_And_Type_Size";
10940 }
10941 }
10942 }
10943 else
10944 {
10945 if(not isPublic(\%Type1_Pure, $Member_Pos)
10946 or isUnnamed($Member_Name)) {
10947 next;
10948 }
10949 }
10950 if($ProblemType eq "Private_Field_Type_And_Size")
10951 { # private field change with no effect
10952 next;
10953 }
10954 %{$SubProblems{$ProblemType}{$Member_Name}}=(
10955 "Target"=>$Member_Name,
10956 "Type_Name"=>$Type1_Pure{"Name"},
10957 "Type_Type"=>$Type1_Pure{"Type"} );
10958 foreach my $Attr (keys(%{$Sub_SubProblems{$ProblemType_Init}}))
10959 { # other properties
10960 $SubProblems{$ProblemType}{$Member_Name}{$Attr} = $Sub_SubProblems{$ProblemType_Init}{$Attr};
10961 }
10962 }
10963 if(not isPublic(\%Type1_Pure, $Member_Pos))
10964 { # do NOT check internal type changes
10965 next;
10966 }
10967 if($MemberType1_Id and $MemberType2_Id)
10968 {# checking member type changes (replace)
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040010969 %Sub_SubProblems = mergeTypes($MemberType1_Id, $MemberType2_Id, $Level);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010970 foreach my $Sub_SubProblemType (keys(%Sub_SubProblems))
10971 {
10972 foreach my $Sub_SubLocation (keys(%{$Sub_SubProblems{$Sub_SubProblemType}}))
10973 {
10974 my $NewLocation = ($Sub_SubLocation)?$Member_Name."->".$Sub_SubLocation:$Member_Name;
10975 $SubProblems{$Sub_SubProblemType}{$NewLocation}{"IsInTypeInternals"}=1;
10976 foreach my $Attr (keys(%{$Sub_SubProblems{$Sub_SubProblemType}{$Sub_SubLocation}})) {
10977 $SubProblems{$Sub_SubProblemType}{$NewLocation}{$Attr} = $Sub_SubProblems{$Sub_SubProblemType}{$Sub_SubLocation}{$Attr};
10978 }
10979 if($Sub_SubLocation!~/\-\>/) {
10980 $SubProblems{$Sub_SubProblemType}{$NewLocation}{"Start_Type_Name"} = $MemberType1_Name;
10981 }
10982 }
10983 }
10984 }
10985 }
10986 }
10987 }
10988 foreach my $Member_Pos (sort {int($a) <=> int($b)} keys(%{$Type2_Pure{"Memb"}}))
10989 { # checking added members, public and private
10990 my $Member_Name = $Type2_Pure{"Memb"}{$Member_Pos}{"name"};
10991 next if(not $Member_Name);
10992 if($AddedField{$Member_Pos})
10993 { # added
10994 if($Type2_Pure{"Type"}=~/\A(Struct|Class)\Z/)
10995 {
10996 my $ProblemType = "Added_Field";
10997 if(not isPublic(\%Type2_Pure, $Member_Pos)
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040010998 or isUnnamed($Member_Name))
10999 {
11000 if($Level eq "Source") {
11001 next;
11002 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011003 $ProblemType = "Added_Private_Field";
11004 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011005 if($Level eq "Binary"
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +040011006 and not isMemPadded($Member_Pos, -1, \%Type2_Pure, \%AddedField, $TypeInfo{2}, $WORD_SIZE{2}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011007 {
11008 if(my $MNum = isAccessible(\%Type2_Pure, \%AddedField, $Member_Pos, -1))
11009 { # public fields after the current
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +040011010 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 +040011011 { # changed offset
11012 $ProblemType .= "_And_Layout";
11013 }
11014 }
11015 if($Type1_Pure{"Size"} ne $Type2_Pure{"Size"}) {
11016 $ProblemType .= "_And_Size";
11017 }
11018 }
11019 if($ProblemType eq "Added_Private_Field")
11020 { # skip added private fields
11021 next;
11022 }
11023 %{$SubProblems{$ProblemType}{$Member_Name}}=(
11024 "Target"=>$Member_Name,
11025 "Type_Name"=>$Type1_Pure{"Name"},
11026 "Type_Type"=>$Type1_Pure{"Type"} );
11027 }
11028 elsif($Type2_Pure{"Type"} eq "Union")
11029 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011030 if($Level eq "Binary"
11031 and $Type1_Pure{"Size"} ne $Type2_Pure{"Size"})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011032 {
11033 %{$SubProblems{"Added_Union_Field_And_Size"}{$Member_Name}}=(
11034 "Target"=>$Member_Name,
11035 "Type_Name"=>$Type1_Pure{"Name"},
11036 "Type_Type"=>$Type1_Pure{"Type"} );
11037 }
11038 else
11039 {
11040 %{$SubProblems{"Added_Union_Field"}{$Member_Name}}=(
11041 "Target"=>$Member_Name,
11042 "Type_Name"=>$Type1_Pure{"Name"},
11043 "Type_Type"=>$Type1_Pure{"Type"} );
11044 }
11045 }
11046 elsif($Type2_Pure{"Type"} eq "Enum")
11047 {
11048 my $Member_Value = $Type2_Pure{"Memb"}{$Member_Pos}{"value"};
11049 next if($Member_Value eq "");
11050 %{$SubProblems{"Added_Enum_Member"}{$Member_Name}}=(
11051 "Target"=>$Member_Name,
11052 "Type_Name"=>$Type2_Pure{"Name"},
11053 "Type_Type"=>$Type2_Pure{"Type"},
11054 "New_Value"=>$Member_Value );
11055 }
11056 }
11057 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040011058 %{$Cache{"mergeTypes"}{$Level}{$Type1_Id}{$Type2_Id}} = %SubProblems;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011059 pop(@RecurTypes);
11060 return %SubProblems;
11061}
11062
11063sub isUnnamed($) {
11064 return $_[0]=~/\Aunnamed\d+\Z/;
11065}
11066
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040011067sub get_ShortType($$)
11068{
11069 my ($TypeId, $LibVersion) = @_;
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +040011070 my $TypeName = uncover_typedefs($TypeInfo{$LibVersion}{$TypeId}{"Name"}, $LibVersion);
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040011071 if(my $NameSpace = $TypeInfo{$LibVersion}{$TypeId}{"NameSpace"}) {
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040011072 $TypeName=~s/\A$NameSpace\:\://g;
11073 }
11074 return $TypeName;
11075}
11076
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040011077sub goToFirst($$$)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011078{
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040011079 my ($TypeId, $LibVersion, $Type_Type) = @_;
Andrey Ponomarenko16934472012-03-29 15:37:04 +040011080 return () if(not $TypeId);
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040011081 if(defined $Cache{"goToFirst"}{$TypeId}{$LibVersion}{$Type_Type}) {
11082 return %{$Cache{"goToFirst"}{$TypeId}{$LibVersion}{$Type_Type}};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011083 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040011084 return () if(not $TypeInfo{$LibVersion}{$TypeId});
11085 my %Type = %{$TypeInfo{$LibVersion}{$TypeId}};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011086 return () if(not $Type{"Type"});
11087 if($Type{"Type"} ne $Type_Type)
11088 {
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040011089 return () if(not defined $Type{"BaseType"});
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040011090 return () if(not $Type{"BaseType"}{"Tid"});
11091 %Type = goToFirst($Type{"BaseType"}{"Tid"}, $LibVersion, $Type_Type);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011092 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040011093 $Cache{"goToFirst"}{$TypeId}{$LibVersion}{$Type_Type} = \%Type;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011094 return %Type;
11095}
11096
11097my %TypeSpecAttributes = (
11098 "Const" => 1,
11099 "Volatile" => 1,
11100 "ConstVolatile" => 1,
11101 "Restrict" => 1,
11102 "Typedef" => 1
11103);
11104
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040011105sub get_PureType($$)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011106{
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +040011107 my ($TypeId, $Info) = @_;
11108 if(not $TypeId or not $Info
11109 or not $Info->{$TypeId}) {
11110 return ();
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011111 }
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +040011112 if(defined $Cache{"get_PureType"}{$TypeId}{$Info}) {
11113 return %{$Cache{"get_PureType"}{$TypeId}{$Info}};
11114 }
11115 my %Type = %{$Info->{$TypeId}};
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040011116 return %Type if(not defined $Type{"BaseType"});
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040011117 return %Type if(not $Type{"BaseType"}{"Tid"});
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011118 if($TypeSpecAttributes{$Type{"Type"}}) {
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +040011119 %Type = get_PureType($Type{"BaseType"}{"Tid"}, $Info);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011120 }
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +040011121 $Cache{"get_PureType"}{$TypeId}{$Info} = \%Type;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011122 return %Type;
11123}
11124
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040011125sub get_PLevel($$)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011126{
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040011127 my ($TypeId, $LibVersion) = @_;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011128 return 0 if(not $TypeId);
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040011129 if(defined $Cache{"get_PLevel"}{$TypeId}{$LibVersion}) {
11130 return $Cache{"get_PLevel"}{$TypeId}{$LibVersion};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011131 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040011132 return 0 if(not $TypeInfo{$LibVersion}{$TypeId});
11133 my %Type = %{$TypeInfo{$LibVersion}{$TypeId}};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011134 return 1 if($Type{"Type"}=~/FuncPtr|MethodPtr|FieldPtr/);
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040011135 return 0 if(not defined $Type{"BaseType"});
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040011136 return 0 if(not $Type{"BaseType"}{"Tid"});
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011137 my $PointerLevel = 0;
11138 if($Type{"Type"} =~/Pointer|Ref|FuncPtr|MethodPtr|FieldPtr/) {
11139 $PointerLevel += 1;
11140 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040011141 $PointerLevel += get_PLevel($Type{"BaseType"}{"Tid"}, $LibVersion);
11142 $Cache{"get_PLevel"}{$TypeId}{$LibVersion} = $PointerLevel;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011143 return $PointerLevel;
11144}
11145
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040011146sub get_BaseType($$)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011147{
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040011148 my ($TypeId, $LibVersion) = @_;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011149 return () if(not $TypeId);
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040011150 if(defined $Cache{"get_BaseType"}{$TypeId}{$LibVersion}) {
11151 return %{$Cache{"get_BaseType"}{$TypeId}{$LibVersion}};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011152 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040011153 return () if(not $TypeInfo{$LibVersion}{$TypeId});
11154 my %Type = %{$TypeInfo{$LibVersion}{$TypeId}};
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040011155 return %Type if(not defined $Type{"BaseType"});
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040011156 return %Type if(not $Type{"BaseType"}{"Tid"});
11157 %Type = get_BaseType($Type{"BaseType"}{"Tid"}, $LibVersion);
11158 $Cache{"get_BaseType"}{$TypeId}{$LibVersion} = \%Type;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011159 return %Type;
11160}
11161
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040011162sub get_BaseTypeQual($$)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011163{
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040011164 my ($TypeId, $LibVersion) = @_;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011165 return "" if(not $TypeId);
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040011166 return "" if(not $TypeInfo{$LibVersion}{$TypeId});
11167 my %Type = %{$TypeInfo{$LibVersion}{$TypeId}};
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040011168 return "" if(not defined $Type{"BaseType"});
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040011169 return "" if(not $Type{"BaseType"}{"Tid"});
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011170 my $Qual = "";
11171 if($Type{"Type"} eq "Pointer") {
11172 $Qual .= "*";
11173 }
11174 elsif($Type{"Type"} eq "Ref") {
11175 $Qual .= "&";
11176 }
11177 elsif($Type{"Type"} eq "ConstVolatile") {
11178 $Qual .= "const volatile";
11179 }
11180 elsif($Type{"Type"} eq "Const"
11181 or $Type{"Type"} eq "Volatile"
11182 or $Type{"Type"} eq "Restrict") {
11183 $Qual .= lc($Type{"Type"});
11184 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040011185 my $BQual = get_BaseTypeQual($Type{"BaseType"}{"Tid"}, $LibVersion);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011186 return $BQual.$Qual;
11187}
11188
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040011189sub get_OneStep_BaseType($$)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011190{
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +040011191 my ($TypeId, $Info) = @_;
11192 if(not $TypeId or not $Info
11193 or not $Info->{$TypeId}) {
11194 return ();
11195 }
11196 my %Type = %{$Info->{$TypeId}};
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040011197 return %Type if(not defined $Type{"BaseType"});
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +040011198 if(my $BTid = $Type{"BaseType"}{"Tid"})
11199 {
11200 if($Info->{$BTid}) {
11201 return %{$Info->{$BTid}};
11202 }
11203 else { # something is going wrong
11204 return ();
11205 }
11206 }
11207 else {
11208 return %Type;
11209 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011210}
11211
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040011212sub get_Type($$)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011213{
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040011214 my ($TypeId, $LibVersion) = @_;
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040011215 return () if(not $TypeId);
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040011216 return () if(not $TypeInfo{$LibVersion}{$TypeId});
11217 return %{$TypeInfo{$LibVersion}{$TypeId}};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011218}
11219
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +040011220sub isPrivateData($)
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040011221{ # non-public global data
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011222 my $Symbol = $_[0];
11223 return ($Symbol=~/\A(_ZGV|_ZTI|_ZTS|_ZTT|_ZTV|_ZTC|_ZThn|_ZTv0_n)/);
11224}
11225
Andrey Ponomarenko01117f12012-06-26 12:23:02 +040011226sub isInLineInst($$$) {
11227 return (isTemplateInstance(@_) and not isTemplateSpec(@_));
11228}
11229
11230sub isTemplateInstance($$$)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011231{
Andrey Ponomarenko01117f12012-06-26 12:23:02 +040011232 my ($Symbol, $SInfo, $LibVersion) = @_;
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040011233 if($CheckObjectsOnly)
11234 {
11235 if($Symbol!~/\A(_Z|\?)/) {
11236 return 0;
11237 }
11238 if(my $Signature = $tr_name{$Symbol})
11239 {
11240 if(index($Signature,">")==-1) {
11241 return 0;
11242 }
11243 if(my $ShortName = substr($Signature, 0, find_center($Signature, "(")))
11244 {
Andrey Ponomarenko01117f12012-06-26 12:23:02 +040011245 if(index($ShortName,"<")!=-1
11246 and index($ShortName,">")!=-1) {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040011247 return 1;
11248 }
11249 }
11250 }
11251 }
11252 else
11253 {
Andrey Ponomarenko01117f12012-06-26 12:23:02 +040011254 if(my $ClassId = $SInfo->{"Class"})
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040011255 {
11256 if(my $ClassName = $TypeInfo{$LibVersion}{$ClassId}{"Name"})
11257 {
11258 if(index($ClassName,"<")!=-1) {
11259 return 1;
11260 }
11261 }
11262 }
Andrey Ponomarenko01117f12012-06-26 12:23:02 +040011263 if(my $ShortName = $SInfo->{"ShortName"})
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040011264 {
Andrey Ponomarenko01117f12012-06-26 12:23:02 +040011265 if(index($ShortName,"<")!=-1
11266 and index($ShortName,">")!=-1) {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040011267 return 1;
11268 }
11269 }
11270 }
11271 return 0;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011272}
11273
Andrey Ponomarenko01117f12012-06-26 12:23:02 +040011274sub isTemplateSpec($$$)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011275{
Andrey Ponomarenko01117f12012-06-26 12:23:02 +040011276 my ($Symbol, $SInfo, $LibVersion) = @_;
11277 if(my $ClassId = $SInfo->{"Class"})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011278 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040011279 if($TypeInfo{$LibVersion}{$ClassId}{"Spec"})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011280 { # class specialization
11281 return 1;
11282 }
Andrey Ponomarenko01117f12012-06-26 12:23:02 +040011283 elsif($SInfo->{"Spec"})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011284 { # method specialization
11285 return 1;
11286 }
11287 }
11288 return 0;
11289}
11290
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011291sub symbolFilter($$$$)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011292{ # some special cases when the symbol cannot be imported
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011293 my ($Symbol, $LibVersion, $Type, $Level) = @_;
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +040011294 if(isPrivateData($Symbol))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011295 { # non-public global data
11296 return 0;
11297 }
11298 if($CheckObjectsOnly) {
11299 return 0 if($Symbol=~/\A(_init|_fini)\Z/);
11300 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040011301 if($CheckHeadersOnly and not checkDump($LibVersion, "2.7"))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011302 { # support for old ABI dumps in --headers-only mode
11303 foreach my $Pos (keys(%{$CompleteSignature{$LibVersion}{$Symbol}{"Param"}}))
11304 {
11305 if(my $Pid = $CompleteSignature{$LibVersion}{$Symbol}{"Param"}{$Pos}{"type"})
11306 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040011307 my $PType = $TypeInfo{$LibVersion}{$Pid}{"Type"};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011308 if(not $PType or $PType eq "Unknown") {
11309 return 0;
11310 }
11311 }
11312 }
11313 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +040011314 if($Type=~/Affected/)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011315 {
11316 my $ClassId = $CompleteSignature{$LibVersion}{$Symbol}{"Class"};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011317 if($SkipSymbols{$LibVersion}{$Symbol})
11318 { # user defined symbols to ignore
11319 return 0;
11320 }
11321 my $NameSpace = $CompleteSignature{$LibVersion}{$Symbol}{"NameSpace"};
11322 if(not $NameSpace and $ClassId)
11323 { # class methods have no "NameSpace" attribute
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040011324 $NameSpace = $TypeInfo{$LibVersion}{$ClassId}{"NameSpace"};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011325 }
11326 if($NameSpace)
11327 { # user defined namespaces to ignore
11328 if($SkipNameSpaces{$LibVersion}{$NameSpace}) {
11329 return 0;
11330 }
11331 foreach my $NS (keys(%{$SkipNameSpaces{$LibVersion}}))
11332 { # nested namespaces
11333 if($NameSpace=~/\A\Q$NS\E(\:\:|\Z)/) {
11334 return 0;
11335 }
11336 }
11337 }
11338 if(my $Header = $CompleteSignature{$LibVersion}{$Symbol}{"Header"})
11339 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040011340 if(my $Skip = skipHeader($Header, $LibVersion))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011341 { # --skip-headers or <skip_headers> (not <skip_including>)
11342 if($Skip==1) {
11343 return 0;
11344 }
11345 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011346 }
11347 if($SymbolsListPath and not $SymbolsList{$Symbol})
11348 { # user defined symbols
11349 return 0;
11350 }
11351 if($AppPath and not $SymbolsList_App{$Symbol})
11352 { # user defined symbols (in application)
11353 return 0;
11354 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +040011355 if(not selectSymbol($Symbol, $CompleteSignature{$LibVersion}{$Symbol}, $Level, $LibVersion))
11356 { # non-target symbols
11357 return 0;
11358 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011359 if($Level eq "Binary")
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011360 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040011361 if($CheckObjectsOnly)
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011362 {
Andrey Ponomarenko01117f12012-06-26 12:23:02 +040011363 if(isTemplateInstance($Symbol, $CompleteSignature{$LibVersion}{$Symbol}, $LibVersion)) {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040011364 return 0;
11365 }
11366 }
11367 else
11368 {
11369 if($CompleteSignature{$LibVersion}{$Symbol}{"InLine"}
Andrey Ponomarenko01117f12012-06-26 12:23:02 +040011370 or isInLineInst($Symbol, $CompleteSignature{$LibVersion}{$Symbol}, $LibVersion))
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040011371 {
11372 if($ClassId and $CompleteSignature{$LibVersion}{$Symbol}{"Virt"})
11373 { # inline virtual methods
11374 if($Type=~/InlineVirt/) {
11375 return 1;
11376 }
11377 my $Allocable = (not isCopyingClass($ClassId, $LibVersion));
11378 if(not $Allocable)
11379 { # check bases
11380 foreach my $DCId (get_sub_classes($ClassId, $LibVersion, 1))
11381 {
11382 if(not isCopyingClass($DCId, $LibVersion))
11383 { # exists a derived class without default c-tor
11384 $Allocable=1;
11385 last;
11386 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011387 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011388 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040011389 if(not $Allocable) {
11390 return 0;
11391 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011392 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040011393 else
11394 { # inline non-virtual methods
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011395 return 0;
11396 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011397 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011398 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011399 }
11400 }
11401 return 1;
11402}
11403
11404sub mergeImpl()
11405{
11406 my $DiffCmd = get_CmdPath("diff");
11407 if(not $DiffCmd) {
11408 exitStatus("Not_Found", "can't find \"diff\"");
11409 }
11410 foreach my $Interface (sort keys(%{$Symbol_Library{1}}))
11411 { # implementation changes
11412 next if($CompleteSignature{1}{$Interface}{"Private"});
11413 next if(not $CompleteSignature{1}{$Interface}{"Header"} and not $CheckObjectsOnly);
11414 next if(not $Symbol_Library{2}{$Interface} and not $Symbol_Library{2}{$SymVer{2}{$Interface}});
Andrey Ponomarenko85043792012-05-14 16:48:07 +040011415 if(not symbolFilter($Interface, 1, "Affected", "Binary")) {
11416 next;
11417 }
Andrey Ponomarenko16934472012-03-29 15:37:04 +040011418 my $Impl1 = canonifyImpl($Interface_Impl{1}{$Interface});
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011419 next if(not $Impl1);
Andrey Ponomarenko16934472012-03-29 15:37:04 +040011420 my $Impl2 = canonifyImpl($Interface_Impl{2}{$Interface});
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011421 next if(not $Impl2);
11422 if($Impl1 ne $Impl2)
11423 {
11424 writeFile("$TMP_DIR/impl1", $Impl1);
11425 writeFile("$TMP_DIR/impl2", $Impl2);
Andrey Ponomarenkoa01311b2012-06-08 17:20:02 +040011426 my $Diff = `$DiffCmd -rNau \"$TMP_DIR/impl1\" \"$TMP_DIR/impl2\"`;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011427 $Diff=~s/(---|\+\+\+).+\n//g;
11428 $Diff=~s/[ ]{3,}/ /g;
11429 $Diff=~s/\n\@\@/\n \n\@\@/g;
Andrey Ponomarenkoa01311b2012-06-08 17:20:02 +040011430 unlink("$TMP_DIR/impl1");
11431 unlink("$TMP_DIR/impl2");
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011432 %{$ImplProblems{$Interface}}=(
11433 "Diff" => get_CodeView($Diff) );
11434 }
11435 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +040011436
11437 # clean memory
11438 %Interface_Impl = ();
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011439}
11440
Andrey Ponomarenko16934472012-03-29 15:37:04 +040011441sub canonifyImpl($)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011442{
11443 my $FuncBody= $_[0];
11444 return "" if(not $FuncBody);
11445 $FuncBody=~s/0x[a-f\d]+/0x?/g;# addr
11446 $FuncBody=~s/((\A|\n)[a-z]+[\t ]+)[a-f\d]+([^x]|\Z)/$1?$3/g;# call, jump
11447 $FuncBody=~s/# [a-f\d]+ /# ? /g;# call, jump
11448 $FuncBody=~s/%([a-z]+[a-f\d]*)/\%reg/g;# registers
11449 while($FuncBody=~s/\nnop[ \t]*(\n|\Z)/$1/g){};# empty op
11450 $FuncBody=~s/<.+?\.cpp.+?>/<name.cpp>/g;
11451 $FuncBody=~s/(\A|\n)[a-f\d]+ </$1? </g;# 5e74 <_ZN...
11452 $FuncBody=~s/\.L\d+/.L/g;
11453 $FuncBody=~s/#(-?)\d+/#$1?/g;# r3, [r3, #120]
11454 $FuncBody=~s/[\n]{2,}/\n/g;
11455 return $FuncBody;
11456}
11457
11458sub get_CodeView($)
11459{
11460 my $Code = $_[0];
11461 my $View = "";
11462 foreach my $Line (split(/\n/, $Code))
11463 {
11464 if($Line=~s/\A(\+|-)/$1 /g)
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040011465 { # bold line
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011466 $View .= "<tr><td><b>".htmlSpecChars($Line)."</b></td></tr>\n";
11467 }
11468 else {
11469 $View .= "<tr><td>".htmlSpecChars($Line)."</td></tr>\n";
11470 }
11471 }
11472 return "<table class='code_view'>$View</table>\n";
11473}
11474
11475sub getImplementations($$)
11476{
11477 my ($LibVersion, $Path) = @_;
11478 return if(not $LibVersion or not -e $Path);
11479 if($OSgroup eq "macos")
11480 {
11481 my $OtoolCmd = get_CmdPath("otool");
11482 if(not $OtoolCmd) {
11483 exitStatus("Not_Found", "can't find \"otool\"");
11484 }
11485 my $CurInterface = "";
Andrey Ponomarenkoa01311b2012-06-08 17:20:02 +040011486 foreach my $Line (split(/\n/, `$OtoolCmd -tv \"$Path\" 2>\"$TMP_DIR/null\"`))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011487 {
11488 if($Line=~/\A\s*_(\w+)\s*:/i) {
11489 $CurInterface = $1;
11490 }
11491 elsif($Line=~/\A\s*[\da-z]+\s+(.+?)\Z/i) {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040011492 $Interface_Impl{$LibVersion}{$CurInterface} .= $1."\n";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011493 }
11494 }
11495 }
11496 else
11497 {
11498 my $ObjdumpCmd = get_CmdPath("objdump");
11499 if(not $ObjdumpCmd) {
11500 exitStatus("Not_Found", "can't find \"objdump\"");
11501 }
11502 my $CurInterface = "";
Andrey Ponomarenkoa01311b2012-06-08 17:20:02 +040011503 foreach my $Line (split(/\n/, `$ObjdumpCmd -d \"$Path\" 2>\"$TMP_DIR/null\"`))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011504 {
11505 if($Line=~/\A[\da-z]+\s+<(\w+)>/i) {
11506 $CurInterface = $1;
11507 }
11508 else
11509 { # x86: 51fa:(\t)89 e5 (\t)mov %esp,%ebp
11510 # arm: 5020:(\t)e24cb004(\t)sub(\t)fp, ip, #4(\t); 0x4
11511 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 +040011512 $Interface_Impl{$LibVersion}{$CurInterface} .= $2."\n";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011513 }
11514 }
11515 }
11516 }
11517}
11518
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011519sub detectAdded($)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011520{
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011521 my $Level = $_[0];
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011522 foreach my $Symbol (keys(%{$Symbol_Library{2}}))
11523 {
11524 if(link_symbol($Symbol, 1, "+Deps"))
11525 { # linker can find a new symbol
11526 # in the old-version library
11527 # So, it's not a new symbol
11528 next;
11529 }
11530 if(my $VSym = $SymVer{2}{$Symbol}
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040011531 and index($Symbol,"\@")==-1) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011532 next;
11533 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011534 $AddedInt{$Level}{$Symbol} = 1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011535 }
11536}
11537
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011538sub detectRemoved($)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011539{
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011540 my $Level = $_[0];
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011541 foreach my $Symbol (keys(%{$Symbol_Library{1}}))
11542 {
11543 if($CheckObjectsOnly) {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011544 $CheckedSymbols{"Binary"}{$Symbol} = 1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011545 }
11546 if(link_symbol($Symbol, 2, "+Deps"))
11547 { # linker can find an old symbol
11548 # in the new-version library
11549 next;
11550 }
11551 if(my $VSym = $SymVer{1}{$Symbol}
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040011552 and index($Symbol,"\@")==-1) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011553 next;
11554 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011555 $RemovedInt{$Level}{$Symbol} = 1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011556 }
11557}
11558
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011559sub mergeLibs($)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011560{
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011561 my $Level = $_[0];
11562 foreach my $Symbol (sort keys(%{$AddedInt{$Level}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011563 { # checking added symbols
11564 next if($CompleteSignature{2}{$Symbol}{"Private"});
11565 next if(not $CompleteSignature{2}{$Symbol}{"Header"} and not $CheckObjectsOnly);
Andrey Ponomarenko85043792012-05-14 16:48:07 +040011566 next if(not symbolFilter($Symbol, 2, "Affected", $Level));
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011567 %{$CompatProblems{$Level}{$Symbol}{"Added_Symbol"}{""}}=();
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011568 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011569 foreach my $Symbol (sort keys(%{$RemovedInt{$Level}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011570 { # checking removed symbols
11571 next if($CompleteSignature{1}{$Symbol}{"Private"});
11572 next if(not $CompleteSignature{1}{$Symbol}{"Header"} and not $CheckObjectsOnly);
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040011573 if(index($Symbol, "_ZTV")==0)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011574 { # skip v-tables for templates, that should not be imported by applications
11575 next if($tr_name{$Symbol}=~/</);
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040011576 if(my $CName = $VTableClass{$Symbol})
11577 {
11578 if(not keys(%{$ClassMethods{$Level}{1}{$CName}}))
11579 { # vtables for "private" classes
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040011580 # use case: vtable for QDragManager (Qt 4.5.3 to 4.6.0) became HIDDEN symbol
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040011581 next;
11582 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011583 }
11584 }
11585 else {
Andrey Ponomarenko85043792012-05-14 16:48:07 +040011586 next if(not symbolFilter($Symbol, 1, "Affected", $Level));
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011587 }
11588 if($CompleteSignature{1}{$Symbol}{"PureVirt"})
11589 { # symbols for pure virtual methods cannot be called by clients
11590 next;
11591 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011592 %{$CompatProblems{$Level}{$Symbol}{"Removed_Symbol"}{""}}=();
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011593 }
11594}
11595
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040011596sub checkDump($$)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011597{
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040011598 my ($LibVersion, $V) = @_;
11599 if(defined $Cache{"checkDump"}{$LibVersion}{$V}) {
11600 return $Cache{"checkDump"}{$LibVersion}{$V};
11601 }
11602 return ($Cache{"checkDump"}{$LibVersion}{$V} = (not $UsedDump{$LibVersion}{"V"} or cmpVersions($UsedDump{$LibVersion}{"V"}, $V)>=0));
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011603}
11604
11605sub detectAdded_H($)
11606{
11607 my $Level = $_[0];
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011608 foreach my $Symbol (sort keys(%{$CompleteSignature{2}}))
11609 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011610 if($Level eq "Source")
11611 { # remove symbol version
11612 my ($SN, $SS, $SV) = separate_symbol($Symbol);
11613 $Symbol=$SN;
Andrey Ponomarenkob8d203d2012-05-25 18:11:07 +040011614
11615 if($CompleteSignature{2}{$Symbol}{"Artificial"})
11616 { # skip artificial constructors
11617 next;
11618 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011619 }
Andrey Ponomarenko16934472012-03-29 15:37:04 +040011620 if(not $CompleteSignature{2}{$Symbol}{"Header"}
11621 or not $CompleteSignature{2}{$Symbol}{"MnglName"}) {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011622 next;
11623 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040011624 if($ExtendedSymbols{$Symbol}) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011625 next;
11626 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011627 if(not defined $CompleteSignature{1}{$Symbol}
11628 or not $CompleteSignature{1}{$Symbol}{"MnglName"})
11629 {
Andrey Ponomarenko16934472012-03-29 15:37:04 +040011630 if($UsedDump{2}{"SrcBin"})
11631 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040011632 if($UsedDump{1}{"BinOnly"} or not checkDump(1, "2.11"))
Andrey Ponomarenko16934472012-03-29 15:37:04 +040011633 { # support for old and different (!) ABI dumps
11634 if(not $CompleteSignature{2}{$Symbol}{"Virt"}
11635 and not $CompleteSignature{2}{$Symbol}{"PureVirt"})
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011636 {
Andrey Ponomarenko16934472012-03-29 15:37:04 +040011637 if($CheckHeadersOnly)
Andrey Ponomarenko85043792012-05-14 16:48:07 +040011638 {
11639 if(my $Lang = $CompleteSignature{2}{$Symbol}{"Lang"})
11640 {
11641 if($Lang eq "C")
11642 { # support for old ABI dumps: missed extern "C" functions
11643 next;
11644 }
11645 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011646 }
Andrey Ponomarenko16934472012-03-29 15:37:04 +040011647 else
11648 {
11649 if(not link_symbol($Symbol, 2, "-Deps"))
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040011650 { # skip added inline symbols and const global data
Andrey Ponomarenko16934472012-03-29 15:37:04 +040011651 next;
11652 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011653 }
11654 }
11655 }
11656 }
11657 $AddedInt{$Level}{$Symbol} = 1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011658 }
11659 }
11660}
11661
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011662sub detectRemoved_H($)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011663{
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011664 my $Level = $_[0];
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011665 foreach my $Symbol (sort keys(%{$CompleteSignature{1}}))
11666 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011667 if($Level eq "Source")
11668 { # remove symbol version
11669 my ($SN, $SS, $SV) = separate_symbol($Symbol);
11670 $Symbol=$SN;
11671 }
Andrey Ponomarenko16934472012-03-29 15:37:04 +040011672 if(not $CompleteSignature{1}{$Symbol}{"Header"}
11673 or not $CompleteSignature{1}{$Symbol}{"MnglName"}) {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011674 next;
11675 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040011676 if($ExtendedSymbols{$Symbol}) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011677 next;
11678 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011679 if(not defined $CompleteSignature{2}{$Symbol}
11680 or not $CompleteSignature{2}{$Symbol}{"MnglName"})
Andrey Ponomarenko85043792012-05-14 16:48:07 +040011681 {
Andrey Ponomarenko16934472012-03-29 15:37:04 +040011682 if($UsedDump{1}{"SrcBin"})
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011683 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040011684 if($UsedDump{2}{"BinOnly"} or not checkDump(2, "2.11"))
Andrey Ponomarenko85043792012-05-14 16:48:07 +040011685 { # support for old and different (!) ABI dumps
Andrey Ponomarenko16934472012-03-29 15:37:04 +040011686 if(not $CompleteSignature{1}{$Symbol}{"Virt"}
11687 and not $CompleteSignature{1}{$Symbol}{"PureVirt"})
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011688 {
Andrey Ponomarenko16934472012-03-29 15:37:04 +040011689 if($CheckHeadersOnly)
11690 { # skip all removed symbols
Andrey Ponomarenko85043792012-05-14 16:48:07 +040011691 if(my $Lang = $CompleteSignature{1}{$Symbol}{"Lang"})
11692 {
11693 if($Lang eq "C")
11694 { # support for old ABI dumps: missed extern "C" functions
11695 next;
11696 }
11697 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011698 }
Andrey Ponomarenko16934472012-03-29 15:37:04 +040011699 else
11700 {
11701 if(not link_symbol($Symbol, 1, "-Deps"))
11702 { # skip removed inline symbols
11703 next;
11704 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011705 }
11706 }
11707 }
11708 }
Andrey Ponomarenkob8d203d2012-05-25 18:11:07 +040011709 if(not checkDump(1, "2.15"))
11710 {
11711 if($Symbol=~/_IT_E\Z/)
11712 { # _ZN28QExplicitlySharedDataPointerI22QSslCertificatePrivateEC1IT_EERKS_IT_E
11713 next;
11714 }
11715 }
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040011716 if(not $CompleteSignature{1}{$Symbol}{"Class"})
11717 {
11718 if(my $Short = $CompleteSignature{1}{$Symbol}{"ShortName"})
11719 {
11720 if(defined $Constants{2}{$Short})
11721 {
11722 my $Val = $Constants{2}{$Short}{"Value"};
11723 if(defined $Func_ShortName{2}{$Val})
11724 { # old name defined to new
11725 next;
11726 }
11727 }
11728 }
11729
11730 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011731 $RemovedInt{$Level}{$Symbol} = 1;
11732 if($Level eq "Source")
11733 { # search for a source-compatible equivalent
11734 setAlternative($Symbol, $Level);
11735 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011736 }
11737 }
11738}
11739
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011740sub mergeHeaders($)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011741{
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011742 my $Level = $_[0];
11743 foreach my $Symbol (sort keys(%{$AddedInt{$Level}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011744 { # checking added symbols
11745 next if($CompleteSignature{2}{$Symbol}{"PureVirt"});
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040011746 next if($CompleteSignature{2}{$Symbol}{"Private"});
11747 next if(not symbolFilter($Symbol, 2, "Affected", $Level));
Andrey Ponomarenko85043792012-05-14 16:48:07 +040011748 if($Level eq "Binary")
11749 {
11750 if($CompleteSignature{2}{$Symbol}{"InLine"})
11751 {
11752 if(not $CompleteSignature{2}{$Symbol}{"Virt"})
11753 { # skip inline non-virtual functions
11754 next;
11755 }
11756 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011757 }
11758 else
11759 { # Source
11760 if($SourceAlternative_B{$Symbol}) {
11761 next;
11762 }
11763 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011764 %{$CompatProblems{$Level}{$Symbol}{"Added_Symbol"}{""}}=();
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011765 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011766 foreach my $Symbol (sort keys(%{$RemovedInt{$Level}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011767 { # checking removed symbols
11768 next if($CompleteSignature{1}{$Symbol}{"PureVirt"});
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040011769 next if($CompleteSignature{1}{$Symbol}{"Private"});
11770 next if(not symbolFilter($Symbol, 1, "Affected", $Level));
Andrey Ponomarenko85043792012-05-14 16:48:07 +040011771 if($Level eq "Binary")
11772 {
11773 if($CompleteSignature{1}{$Symbol}{"InLine"})
11774 {
11775 if(not $CompleteSignature{1}{$Symbol}{"Virt"})
11776 { # skip inline non-virtual functions
11777 next;
11778 }
11779 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011780 }
11781 else
11782 { # Source
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040011783 if(my $Alt = $SourceAlternative{$Symbol})
11784 {
11785 if(defined $CompleteSignature{1}{$Alt}
11786 and $CompleteSignature{1}{$Symbol}{"Const"})
11787 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040011788 my $Cid = $CompleteSignature{1}{$Symbol}{"Class"};
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040011789 %{$CompatProblems{$Level}{$Symbol}{"Removed_Const_Overload"}{$tr_name{$Symbol}}}=(
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040011790 "Type_Name"=>$TypeInfo{1}{$Cid}{"Name"},
Andrey Ponomarenko85043792012-05-14 16:48:07 +040011791 "Type_Type"=>"Class",
11792 "Target"=>get_Signature($Alt, 1) );
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040011793 }
11794 else
11795 { # do NOT show removed symbol
11796 next;
11797 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011798 }
11799 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011800 %{$CompatProblems{$Level}{$Symbol}{"Removed_Symbol"}{""}}=();
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011801 }
11802}
11803
11804sub addParamNames($)
11805{
11806 my $LibraryVersion = $_[0];
11807 return if(not keys(%AddIntParams));
11808 my $SecondVersion = $LibraryVersion==1?2:1;
11809 foreach my $Interface (sort keys(%{$CompleteSignature{$LibraryVersion}}))
11810 {
11811 next if(not keys(%{$AddIntParams{$Interface}}));
11812 foreach my $ParamPos (sort {int($a)<=>int($b)} keys(%{$CompleteSignature{$LibraryVersion}{$Interface}{"Param"}}))
Andrey Ponomarenko85043792012-05-14 16:48:07 +040011813 { # add absent parameter names
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011814 my $ParamName = $CompleteSignature{$LibraryVersion}{$Interface}{"Param"}{$ParamPos}{"name"};
11815 if($ParamName=~/\Ap\d+\Z/ and my $NewParamName = $AddIntParams{$Interface}{$ParamPos})
Andrey Ponomarenko85043792012-05-14 16:48:07 +040011816 { # names from the external file
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011817 if(defined $CompleteSignature{$SecondVersion}{$Interface}
11818 and defined $CompleteSignature{$SecondVersion}{$Interface}{"Param"}{$ParamPos})
11819 {
11820 if($CompleteSignature{$SecondVersion}{$Interface}{"Param"}{$ParamPos}{"name"}=~/\Ap\d+\Z/) {
11821 $CompleteSignature{$LibraryVersion}{$Interface}{"Param"}{$ParamPos}{"name"} = $NewParamName;
11822 }
11823 }
11824 else {
11825 $CompleteSignature{$LibraryVersion}{$Interface}{"Param"}{$ParamPos}{"name"} = $NewParamName;
11826 }
11827 }
11828 }
11829 }
11830}
11831
11832sub detectChangedTypedefs()
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +040011833{ # detect changed typedefs to show
11834 # correct function signatures
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011835 foreach my $Typedef (keys(%{$Typedef_BaseName{1}}))
11836 {
11837 next if(not $Typedef);
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +040011838 my $BName1 = $Typedef_BaseName{1}{$Typedef};
11839 if(not $BName1 or isAnon($BName1)) {
11840 next;
11841 }
11842 my $BName2 = $Typedef_BaseName{2}{$Typedef};
11843 if(not $BName2 or isAnon($BName2)) {
11844 next;
11845 }
11846 if($BName1 ne $BName2) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011847 $ChangedTypedef{$Typedef} = 1;
11848 }
11849 }
11850}
11851
11852sub get_symbol_suffix($$)
11853{
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011854 my ($Symbol, $Full) = @_;
11855 my ($SN, $SO, $SV) = separate_symbol($Symbol);
11856 $Symbol=$SN;# remove version
11857 my $Signature = $tr_name{$Symbol};
Andrey Ponomarenko16934472012-03-29 15:37:04 +040011858 my $Suffix = substr($Signature, find_center($Signature, "("));
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011859 if(not $Full) {
11860 $Suffix=~s/(\))\s*(const volatile|volatile const|const|volatile)\Z/$1/g;
11861 }
11862 return $Suffix;
11863}
11864
11865sub get_symbol_prefix($$)
11866{
11867 my ($Symbol, $LibVersion) = @_;
11868 my $ShortName = $CompleteSignature{$LibVersion}{$Symbol}{"ShortName"};
11869 if(my $ClassId = $CompleteSignature{$LibVersion}{$Symbol}{"Class"})
11870 { # methods
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040011871 $ShortName = $TypeInfo{$LibVersion}{$ClassId}{"Name"}."::".$ShortName;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011872 }
11873 return $ShortName;
11874}
11875
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011876sub setAlternative($)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011877{
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011878 my $Symbol = $_[0];
11879 my $PSymbol = $Symbol;
11880 if(not defined $CompleteSignature{2}{$PSymbol}
11881 or (not $CompleteSignature{2}{$PSymbol}{"MnglName"}
11882 and not $CompleteSignature{2}{$PSymbol}{"ShortName"}))
11883 { # search for a pair
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040011884 if(my $ShortName = $CompleteSignature{1}{$PSymbol}{"ShortName"})
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011885 {
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040011886 if($CompleteSignature{1}{$PSymbol}{"Data"})
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011887 {
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040011888 if($PSymbol=~s/L(\d+$ShortName(E)\Z)/$1/
11889 or $PSymbol=~s/(\d+$ShortName(E)\Z)/L$1/)
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011890 {
11891 if(defined $CompleteSignature{2}{$PSymbol}
11892 and $CompleteSignature{2}{$PSymbol}{"MnglName"})
11893 {
11894 $SourceAlternative{$Symbol} = $PSymbol;
11895 $SourceAlternative_B{$PSymbol} = $Symbol;
11896 if(not defined $CompleteSignature{1}{$PSymbol}
11897 or not $CompleteSignature{1}{$PSymbol}{"MnglName"}) {
11898 $SourceReplacement{$Symbol} = $PSymbol;
11899 }
11900 }
11901 }
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040011902 }
11903 else
11904 {
11905 foreach my $Sp ("KV", "VK", "K", "V")
11906 {
11907 if($PSymbol=~s/\A_ZN$Sp/_ZN/
11908 or $PSymbol=~s/\A_ZN/_ZN$Sp/)
11909 {
11910 if(defined $CompleteSignature{2}{$PSymbol}
11911 and $CompleteSignature{2}{$PSymbol}{"MnglName"})
11912 {
11913 $SourceAlternative{$Symbol} = $PSymbol;
11914 $SourceAlternative_B{$PSymbol} = $Symbol;
11915 if(not defined $CompleteSignature{1}{$PSymbol}
11916 or not $CompleteSignature{1}{$PSymbol}{"MnglName"}) {
11917 $SourceReplacement{$Symbol} = $PSymbol;
11918 }
11919 }
11920 }
11921 $PSymbol = $Symbol;
11922 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011923 }
11924 }
11925 }
11926 return "";
11927}
11928
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040011929sub getSymKind($$)
11930{
11931 my ($Symbol, $LibVersion) = @_;
11932 if($CompleteSignature{$LibVersion}{$Symbol}{"Data"})
11933 {
11934 return "Global_Data";
11935 }
11936 elsif($CompleteSignature{$LibVersion}{$Symbol}{"Class"})
11937 {
11938 return "Method";
11939 }
11940 return "Function";
11941}
11942
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011943sub mergeSignatures($)
11944{
11945 my $Level = $_[0];
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011946 my %SubProblems = ();
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011947
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011948 mergeBases($Level);
11949
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011950 my %AddedOverloads = ();
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011951 foreach my $Symbol (sort keys(%{$AddedInt{$Level}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011952 { # check all added exported symbols
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011953 if(not $CompleteSignature{2}{$Symbol}{"Header"}) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011954 next;
11955 }
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040011956 if(defined $CompleteSignature{1}{$Symbol}
11957 and $CompleteSignature{1}{$Symbol}{"Header"})
11958 { # double-check added symbol
11959 next;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011960 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +040011961 if(not symbolFilter($Symbol, 2, "Affected", $Level)) {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011962 next;
11963 }
11964 if($Symbol=~/\A(_Z|\?)/)
11965 { # C++
11966 $AddedOverloads{get_symbol_prefix($Symbol, 2)}{get_symbol_suffix($Symbol, 1)} = $Symbol;
11967 }
11968 if(my $OverriddenMethod = $CompleteSignature{2}{$Symbol}{"Override"})
11969 { # register virtual overridings
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040011970 my $Cid = $CompleteSignature{2}{$Symbol}{"Class"};
11971 my $AffectedClass_Name = $TypeInfo{2}{$Cid}{"Name"};
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040011972 if(defined $CompleteSignature{1}{$OverriddenMethod} and $CompleteSignature{1}{$OverriddenMethod}{"Virt"}
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011973 and not $CompleteSignature{1}{$OverriddenMethod}{"Private"})
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040011974 {
11975 if($TName_Tid{1}{$AffectedClass_Name})
11976 { # class should exist in previous version
11977 if(not isCopyingClass($TName_Tid{1}{$AffectedClass_Name}, 1))
11978 { # old v-table is NOT copied by old applications
11979 %{$CompatProblems{$Level}{$OverriddenMethod}{"Overridden_Virtual_Method"}{$tr_name{$Symbol}}}=(
11980 "Type_Name"=>$AffectedClass_Name,
11981 "Type_Type"=>"Class",
11982 "Target"=>get_Signature($Symbol, 2),
11983 "Old_Value"=>get_Signature($OverriddenMethod, 2),
11984 "New_Value"=>get_Signature($Symbol, 2) );
11985 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011986 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011987 }
11988 }
11989 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011990 foreach my $Symbol (sort keys(%{$RemovedInt{$Level}}))
11991 { # check all removed exported symbols
11992 if(not $CompleteSignature{1}{$Symbol}{"Header"}) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011993 next;
11994 }
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040011995 if(defined $CompleteSignature{2}{$Symbol}
11996 and $CompleteSignature{2}{$Symbol}{"Header"})
11997 { # double-check removed symbol
11998 next;
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011999 }
12000 if($CompleteSignature{1}{$Symbol}{"Private"})
12001 { # skip private methods
12002 next;
12003 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +040012004 if(not symbolFilter($Symbol, 1, "Affected", $Level)) {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012005 next;
12006 }
12007 $CheckedSymbols{$Level}{$Symbol} = 1;
12008 if(my $OverriddenMethod = $CompleteSignature{1}{$Symbol}{"Override"})
12009 { # register virtual overridings
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040012010 my $Cid = $CompleteSignature{1}{$Symbol}{"Class"};
12011 my $AffectedClass_Name = $TypeInfo{1}{$Cid}{"Name"};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012012 if(defined $CompleteSignature{2}{$OverriddenMethod}
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040012013 and $CompleteSignature{2}{$OverriddenMethod}{"Virt"})
12014 {
12015 if($TName_Tid{2}{$AffectedClass_Name})
12016 { # class should exist in newer version
12017 if(not isCopyingClass($CompleteSignature{1}{$Symbol}{"Class"}, 1))
12018 { # old v-table is NOT copied by old applications
12019 %{$CompatProblems{$Level}{$Symbol}{"Overridden_Virtual_Method_B"}{$tr_name{$OverriddenMethod}}}=(
12020 "Type_Name"=>$AffectedClass_Name,
12021 "Type_Type"=>"Class",
12022 "Target"=>get_Signature($OverriddenMethod, 1),
12023 "Old_Value"=>get_Signature($Symbol, 1),
12024 "New_Value"=>get_Signature($OverriddenMethod, 1) );
12025 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012026 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012027 }
12028 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012029 if($Level eq "Binary"
12030 and $OSgroup eq "windows")
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012031 { # register the reason of symbol name change
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040012032 if(my $NewSym = $mangled_name{2}{$tr_name{$Symbol}})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012033 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040012034 if($AddedInt{$Level}{$NewSym})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012035 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040012036 if($CompleteSignature{1}{$Symbol}{"Static"} ne $CompleteSignature{2}{$NewSym}{"Static"})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012037 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040012038 if($CompleteSignature{2}{$NewSym}{"Static"})
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012039 {
12040 %{$CompatProblems{$Level}{$Symbol}{"Symbol_Became_Static"}{$tr_name{$Symbol}}}=(
12041 "Target"=>$tr_name{$Symbol},
12042 "Old_Value"=>$Symbol,
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040012043 "New_Value"=>$NewSym );
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012044 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012045 else
12046 {
12047 %{$CompatProblems{$Level}{$Symbol}{"Symbol_Became_NonStatic"}{$tr_name{$Symbol}}}=(
12048 "Target"=>$tr_name{$Symbol},
12049 "Old_Value"=>$Symbol,
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040012050 "New_Value"=>$NewSym );
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012051 }
12052 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040012053 if($CompleteSignature{1}{$Symbol}{"Virt"} ne $CompleteSignature{2}{$NewSym}{"Virt"})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012054 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040012055 if($CompleteSignature{2}{$NewSym}{"Virt"})
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012056 {
12057 %{$CompatProblems{$Level}{$Symbol}{"Symbol_Became_Virtual"}{$tr_name{$Symbol}}}=(
12058 "Target"=>$tr_name{$Symbol},
12059 "Old_Value"=>$Symbol,
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040012060 "New_Value"=>$NewSym );
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012061 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012062 else
12063 {
12064 %{$CompatProblems{$Level}{$Symbol}{"Symbol_Became_NonVirtual"}{$tr_name{$Symbol}}}=(
12065 "Target"=>$tr_name{$Symbol},
12066 "Old_Value"=>$Symbol,
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040012067 "New_Value"=>$NewSym );
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012068 }
12069 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040012070 my $RTId1 = $CompleteSignature{1}{$Symbol}{"Return"};
12071 my $RTId2 = $CompleteSignature{2}{$NewSym}{"Return"};
12072 my $RTName1 = $TypeInfo{1}{$RTId1}{"Name"};
12073 my $RTName2 = $TypeInfo{2}{$RTId2}{"Name"};
12074 if($RTName1 ne $RTName2)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012075 {
12076 my $ProblemType = "Symbol_Changed_Return";
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012077 if($CompleteSignature{1}{$Symbol}{"Data"}) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012078 $ProblemType = "Global_Data_Symbol_Changed_Type";
12079 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012080 %{$CompatProblems{$Level}{$Symbol}{$ProblemType}{$tr_name{$Symbol}}}=(
12081 "Target"=>$tr_name{$Symbol},
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040012082 "Old_Type"=>$RTName1,
12083 "New_Type"=>$RTName2,
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012084 "Old_Value"=>$Symbol,
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040012085 "New_Value"=>$NewSym );
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012086 }
12087 }
12088 }
12089 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012090 if($Symbol=~/\A(_Z|\?)/)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012091 { # C++
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012092 my $Prefix = get_symbol_prefix($Symbol, 1);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012093 if(my @Overloads = sort keys(%{$AddedOverloads{$Prefix}})
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012094 and not $AddedOverloads{$Prefix}{get_symbol_suffix($Symbol, 1)})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012095 { # changed signature: params, "const"-qualifier
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040012096 my $NewSym = $AddedOverloads{$Prefix}{$Overloads[0]};
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012097 if($CompleteSignature{1}{$Symbol}{"Constructor"})
12098 {
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +040012099 if($Symbol=~/(C1E|C2E)/)
12100 {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012101 my $CtorType = $1;
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040012102 $NewSym=~s/(C1E|C2E)/$CtorType/g;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012103 }
12104 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012105 elsif($CompleteSignature{1}{$Symbol}{"Destructor"})
12106 {
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +040012107 if($Symbol=~/(D0E|D1E|D2E)/)
12108 {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012109 my $DtorType = $1;
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040012110 $NewSym=~s/(D0E|D1E|D2E)/$DtorType/g;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012111 }
12112 }
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040012113 my $NS1 = $CompleteSignature{1}{$Symbol}{"NameSpace"};
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040012114 my $NS2 = $CompleteSignature{2}{$NewSym}{"NameSpace"};
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040012115 if((not $NS1 and not $NS2) or ($NS1 and $NS2 and $NS1 eq $NS2))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012116 { # from the same class and namespace
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012117 if($CompleteSignature{1}{$Symbol}{"Const"}
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040012118 and not $CompleteSignature{2}{$NewSym}{"Const"})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012119 { # "const" to non-"const"
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040012120 %{$CompatProblems{$Level}{$Symbol}{"Method_Became_NonConst"}{$tr_name{$Symbol}}}=(
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040012121 "Type_Name"=>$TypeInfo{1}{$CompleteSignature{1}{$Symbol}{"Class"}}{"Name"},
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012122 "Target"=>$tr_name{$Symbol},
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040012123 "New_Signature"=>get_Signature($NewSym, 2),
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012124 "Old_Value"=>$Symbol,
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040012125 "New_Value"=>$NewSym );
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012126 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012127 elsif(not $CompleteSignature{1}{$Symbol}{"Const"}
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040012128 and $CompleteSignature{2}{$NewSym}{"Const"})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012129 { # non-"const" to "const"
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040012130 %{$CompatProblems{$Level}{$Symbol}{"Method_Became_Const"}{$tr_name{$Symbol}}}=(
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012131 "Target"=>$tr_name{$Symbol},
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040012132 "New_Signature"=>get_Signature($NewSym, 2),
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012133 "Old_Value"=>$Symbol,
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040012134 "New_Value"=>$NewSym );
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012135 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012136 if($CompleteSignature{1}{$Symbol}{"Volatile"}
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040012137 and not $CompleteSignature{2}{$NewSym}{"Volatile"})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012138 { # "volatile" to non-"volatile"
12139
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040012140 %{$CompatProblems{$Level}{$Symbol}{"Method_Became_NonVolatile"}{$tr_name{$Symbol}}}=(
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012141 "Target"=>$tr_name{$Symbol},
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040012142 "New_Signature"=>get_Signature($NewSym, 2),
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012143 "Old_Value"=>$Symbol,
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040012144 "New_Value"=>$NewSym );
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012145 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012146 elsif(not $CompleteSignature{1}{$Symbol}{"Volatile"}
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040012147 and $CompleteSignature{2}{$NewSym}{"Volatile"})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012148 { # non-"volatile" to "volatile"
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040012149 %{$CompatProblems{$Level}{$Symbol}{"Method_Became_Volatile"}{$tr_name{$Symbol}}}=(
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012150 "Target"=>$tr_name{$Symbol},
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040012151 "New_Signature"=>get_Signature($NewSym, 2),
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012152 "Old_Value"=>$Symbol,
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040012153 "New_Value"=>$NewSym );
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012154 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040012155 if(get_symbol_suffix($Symbol, 0) ne get_symbol_suffix($NewSym, 0))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012156 { # params list
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012157 %{$CompatProblems{$Level}{$Symbol}{"Symbol_Changed_Parameters"}{$tr_name{$Symbol}}}=(
12158 "Target"=>$tr_name{$Symbol},
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040012159 "New_Signature"=>get_Signature($NewSym, 2),
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012160 "Old_Value"=>$Symbol,
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040012161 "New_Value"=>$NewSym );
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012162 }
12163 }
12164 }
12165 }
12166 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012167 foreach my $Symbol (sort keys(%{$CompleteSignature{1}}))
12168 { # checking symbols
12169 my ($SN, $SS, $SV) = separate_symbol($Symbol);
12170 if($Level eq "Source")
12171 { # remove symbol version
12172 $Symbol=$SN;
12173 }
12174 else
12175 { # Binary
12176 if(not $SV)
12177 { # symbol without version
12178 if(my $VSym = $SymVer{1}{$Symbol})
12179 { # the symbol is linked with versioned symbol
12180 if($CompleteSignature{2}{$VSym}{"MnglName"})
12181 { # show report for symbol@ver only
12182 next;
12183 }
12184 elsif(not link_symbol($VSym, 2, "-Deps"))
12185 { # changed version: sym@v1 to sym@v2
12186 # do NOT show report for symbol
12187 next;
12188 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012189 }
12190 }
12191 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012192 my $PSymbol = $Symbol;
12193 if($Level eq "Source"
12194 and my $S = $SourceReplacement{$Symbol})
12195 { # take a source-compatible replacement function
12196 $PSymbol = $S;
12197 }
12198 if($CompleteSignature{1}{$Symbol}{"Private"})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012199 { # private symbols
12200 next;
12201 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012202 if(not defined $CompleteSignature{1}{$Symbol}
12203 or not defined $CompleteSignature{2}{$PSymbol})
12204 { # no info
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012205 next;
12206 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012207 if(not $CompleteSignature{1}{$Symbol}{"MnglName"}
12208 or not $CompleteSignature{2}{$PSymbol}{"MnglName"})
12209 { # no mangled name
12210 next;
12211 }
12212 if(not $CompleteSignature{1}{$Symbol}{"Header"}
12213 or not $CompleteSignature{2}{$PSymbol}{"Header"})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012214 { # without a header
12215 next;
12216 }
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040012217
12218 if(not $CompleteSignature{1}{$Symbol}{"PureVirt"}
12219 and $CompleteSignature{2}{$PSymbol}{"PureVirt"})
12220 { # became pure
12221 next;
12222 }
12223 if($CompleteSignature{1}{$Symbol}{"PureVirt"}
12224 and not $CompleteSignature{2}{$PSymbol}{"PureVirt"})
12225 { # became non-pure
12226 next;
12227 }
12228
12229 if(not symbolFilter($Symbol, 1, "Affected + InlineVirt", $Level))
12230 { # exported, target, inline virtual and pure virtual
12231 next;
12232 }
12233 if(not symbolFilter($PSymbol, 2, "Affected + InlineVirt", $Level))
12234 { # exported, target, inline virtual and pure virtual
12235 next;
12236 }
12237
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040012238 if(checkDump(1, "2.13") and checkDump(2, "2.13"))
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040012239 {
12240 if($CompleteSignature{1}{$Symbol}{"Data"}
12241 and $CompleteSignature{2}{$PSymbol}{"Data"})
12242 {
12243 my $Value1 = $CompleteSignature{1}{$Symbol}{"Value"};
12244 my $Value2 = $CompleteSignature{2}{$PSymbol}{"Value"};
12245 if(defined $Value1)
12246 {
12247 $Value1 = showVal($Value1, $CompleteSignature{1}{$Symbol}{"Return"}, 1);
12248 if(defined $Value2)
12249 {
12250 $Value2 = showVal($Value2, $CompleteSignature{2}{$PSymbol}{"Return"}, 2);
12251 if($Value1 ne $Value2)
12252 {
12253 %{$CompatProblems{$Level}{$Symbol}{"Global_Data_Value_Changed"}{""}}=(
12254 "Old_Value"=>$Value1,
12255 "New_Value"=>$Value2,
12256 "Target"=>get_Signature($Symbol, 1) );
12257 }
12258 }
12259 }
12260 }
12261 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +040012262
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040012263 if($CompleteSignature{2}{$PSymbol}{"Private"})
12264 {
12265 %{$CompatProblems{$Level}{$Symbol}{getSymKind($Symbol, 1)."_Became_Private"}{""}}=(
12266 "Target"=>get_Signature_M($PSymbol, 2) );
12267 }
12268 elsif(not $CompleteSignature{1}{$Symbol}{"Protected"}
12269 and $CompleteSignature{2}{$PSymbol}{"Protected"})
12270 {
12271 %{$CompatProblems{$Level}{$Symbol}{getSymKind($Symbol, 1)."_Became_Protected"}{""}}=(
12272 "Target"=>get_Signature_M($PSymbol, 2) );
12273 }
12274 elsif($CompleteSignature{1}{$Symbol}{"Protected"}
12275 and not $CompleteSignature{2}{$PSymbol}{"Protected"})
12276 {
12277 %{$CompatProblems{$Level}{$Symbol}{getSymKind($Symbol, 1)."_Became_Public"}{""}}=(
12278 "Target"=>get_Signature_M($PSymbol, 2) );
12279 }
12280
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012281 # checking virtual table
Andrey Ponomarenko16934472012-03-29 15:37:04 +040012282 mergeVirtualTables($Symbol, $Level);
12283
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012284 if($COMPILE_ERRORS)
12285 { # if some errors occurred at the compiling stage
12286 # then some false positives can be skipped here
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012287 if(not $CompleteSignature{1}{$Symbol}{"Data"} and $CompleteSignature{2}{$PSymbol}{"Data"}
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040012288 and not $GlobalDataObject{2}{$Symbol})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012289 { # missed information about parameters in newer version
12290 next;
12291 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040012292 if($CompleteSignature{1}{$Symbol}{"Data"} and not $GlobalDataObject{1}{$Symbol}
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012293 and not $CompleteSignature{2}{$PSymbol}{"Data"})
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040012294 { # missed information about parameters in older version
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012295 next;
12296 }
12297 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012298 my ($MnglName, $VersionSpec, $SymbolVersion) = separate_symbol($Symbol);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012299 # checking attributes
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012300 if($CompleteSignature{2}{$PSymbol}{"Static"}
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040012301 and not $CompleteSignature{1}{$Symbol}{"Static"} and $Symbol=~/\A(_Z|\?)/)
12302 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012303 %{$CompatProblems{$Level}{$Symbol}{"Method_Became_Static"}{""}}=(
12304 "Target"=>get_Signature($Symbol, 1)
12305 );
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012306 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012307 elsif(not $CompleteSignature{2}{$PSymbol}{"Static"}
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040012308 and $CompleteSignature{1}{$Symbol}{"Static"} and $Symbol=~/\A(_Z|\?)/)
12309 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012310 %{$CompatProblems{$Level}{$Symbol}{"Method_Became_NonStatic"}{""}}=(
12311 "Target"=>get_Signature($Symbol, 1)
12312 );
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012313 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012314 if(($CompleteSignature{1}{$Symbol}{"Virt"} and $CompleteSignature{2}{$PSymbol}{"Virt"})
12315 or ($CompleteSignature{1}{$Symbol}{"PureVirt"} and $CompleteSignature{2}{$PSymbol}{"PureVirt"}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012316 { # relative position of virtual and pure virtual methods
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012317 if($Level eq "Binary")
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012318 {
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040012319 if(defined $CompleteSignature{1}{$Symbol}{"RelPos"} and defined $CompleteSignature{2}{$PSymbol}{"RelPos"}
12320 and $CompleteSignature{1}{$Symbol}{"RelPos"}!=$CompleteSignature{2}{$PSymbol}{"RelPos"})
12321 { # top-level virtual methods only
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012322 my $Class_Id = $CompleteSignature{1}{$Symbol}{"Class"};
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040012323 my $Class_Name = $TypeInfo{1}{$Class_Id}{"Name"};
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040012324 if(defined $VirtualTable{1}{$Class_Name} and defined $VirtualTable{2}{$Class_Name}
12325 and $VirtualTable{1}{$Class_Name}{$Symbol}!=$VirtualTable{2}{$Class_Name}{$Symbol})
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012326 { # check the absolute position of virtual method (including added and removed methods)
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040012327 my %Class_Type = get_Type($Class_Id, 1);
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012328 my $ProblemType = "Virtual_Method_Position";
12329 if($CompleteSignature{1}{$Symbol}{"PureVirt"}) {
12330 $ProblemType = "Pure_Virtual_Method_Position";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012331 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012332 if(isUsedClass($Class_Id, 1, $Level))
12333 {
12334 my @Affected = ($Symbol, keys(%{$OverriddenMethods{1}{$Symbol}}));
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040012335 foreach my $ASymbol (@Affected)
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012336 {
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040012337 if(not symbolFilter($ASymbol, 1, "Affected", $Level)) {
12338 next;
12339 }
12340 %{$CompatProblems{$Level}{$ASymbol}{$ProblemType}{$tr_name{$MnglName}}}=(
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012341 "Type_Name"=>$Class_Type{"Name"},
12342 "Type_Type"=>"Class",
12343 "Old_Value"=>$CompleteSignature{1}{$Symbol}{"RelPos"},
12344 "New_Value"=>$CompleteSignature{2}{$PSymbol}{"RelPos"},
12345 "Target"=>get_Signature($Symbol, 1) );
12346 }
Andrey Ponomarenko16934472012-03-29 15:37:04 +040012347 $VTableChanged_M{$Class_Type{"Name"}} = 1;
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012348 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012349 }
12350 }
12351 }
12352 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012353 if($CompleteSignature{1}{$Symbol}{"PureVirt"}
12354 or $CompleteSignature{2}{$PSymbol}{"PureVirt"})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012355 { # do NOT check type changes in pure virtuals
12356 next;
12357 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012358 $CheckedSymbols{$Level}{$Symbol}=1;
12359 if($Symbol=~/\A(_Z|\?)/
12360 or keys(%{$CompleteSignature{1}{$Symbol}{"Param"}})==keys(%{$CompleteSignature{2}{$PSymbol}{"Param"}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012361 { # C/C++: changes in parameters
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012362 foreach my $ParamPos (sort {int($a) <=> int($b)} keys(%{$CompleteSignature{1}{$Symbol}{"Param"}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012363 { # checking parameters
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012364 mergeParameters($Symbol, $PSymbol, $ParamPos, $ParamPos, $Level);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012365 }
12366 }
12367 else
12368 { # C: added/removed parameters
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012369 foreach my $ParamPos (sort {int($a) <=> int($b)} keys(%{$CompleteSignature{2}{$PSymbol}{"Param"}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012370 { # checking added parameters
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040012371 my $PType2_Id = $CompleteSignature{2}{$PSymbol}{"Param"}{$ParamPos}{"type"};
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040012372 my $PType2_Name = $TypeInfo{2}{$PType2_Id}{"Name"};
12373 last if($PType2_Name eq "...");
12374 my $PName = $CompleteSignature{2}{$PSymbol}{"Param"}{$ParamPos}{"name"};
12375 my $PName_Old = (defined $CompleteSignature{1}{$Symbol}{"Param"}{$ParamPos})?$CompleteSignature{1}{$Symbol}{"Param"}{$ParamPos}{"name"}:"";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012376 my $ParamPos_Prev = "-1";
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040012377 if($PName=~/\Ap\d+\Z/i)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012378 { # added unnamed parameter ( pN )
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040012379 my @Positions1 = find_ParamPair_Pos_byTypeAndPos($PType2_Name, $ParamPos, "backward", $Symbol, 1);
12380 my @Positions2 = find_ParamPair_Pos_byTypeAndPos($PType2_Name, $ParamPos, "backward", $Symbol, 2);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012381 if($#Positions1==-1 or $#Positions2>$#Positions1) {
12382 $ParamPos_Prev = "lost";
12383 }
12384 }
12385 else {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040012386 $ParamPos_Prev = find_ParamPair_Pos_byName($PName, $Symbol, 1);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012387 }
12388 if($ParamPos_Prev eq "lost")
12389 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012390 if($ParamPos>keys(%{$CompleteSignature{1}{$Symbol}{"Param"}})-1)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012391 {
12392 my $ProblemType = "Added_Parameter";
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040012393 if($PName=~/\Ap\d+\Z/) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012394 $ProblemType = "Added_Unnamed_Parameter";
12395 }
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040012396 %{$CompatProblems{$Level}{$Symbol}{$ProblemType}{showPos($ParamPos)." Parameter"}}=(
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040012397 "Target"=>$PName,
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012398 "Param_Pos"=>$ParamPos,
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040012399 "Param_Type"=>$PType2_Name,
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012400 "New_Signature"=>get_Signature($Symbol, 2) );
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012401 }
12402 else
12403 {
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +040012404 my %ParamType_Pure = get_PureType($PType2_Id, $TypeInfo{2});
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040012405 my $PairType_Id = $CompleteSignature{1}{$Symbol}{"Param"}{$ParamPos}{"type"};
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +040012406 my %PairType_Pure = get_PureType($PairType_Id, $TypeInfo{1});
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040012407 if(($ParamType_Pure{"Name"} eq $PairType_Pure{"Name"} or $PType2_Name eq $TypeInfo{1}{$PairType_Id}{"Name"})
12408 and find_ParamPair_Pos_byName($PName_Old, $Symbol, 2) eq "lost")
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012409 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040012410 if($PName_Old!~/\Ap\d+\Z/ and $PName!~/\Ap\d+\Z/)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012411 {
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040012412 %{$CompatProblems{$Level}{$Symbol}{"Renamed_Parameter"}{showPos($ParamPos)." Parameter"}}=(
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040012413 "Target"=>$PName_Old,
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012414 "Param_Pos"=>$ParamPos,
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040012415 "Param_Type"=>$PType2_Name,
12416 "Old_Value"=>$PName_Old,
12417 "New_Value"=>$PName,
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012418 "New_Signature"=>get_Signature($Symbol, 2) );
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012419 }
12420 }
12421 else
12422 {
12423 my $ProblemType = "Added_Middle_Parameter";
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040012424 if($PName=~/\Ap\d+\Z/) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012425 $ProblemType = "Added_Middle_Unnamed_Parameter";
12426 }
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040012427 %{$CompatProblems{$Level}{$Symbol}{$ProblemType}{showPos($ParamPos)." Parameter"}}=(
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040012428 "Target"=>$PName,
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012429 "Param_Pos"=>$ParamPos,
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040012430 "Param_Type"=>$PType2_Name,
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012431 "New_Signature"=>get_Signature($Symbol, 2) );
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012432 }
12433 }
12434 }
12435 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012436 foreach my $ParamPos (sort {int($a) <=> int($b)} keys(%{$CompleteSignature{1}{$Symbol}{"Param"}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012437 { # check relevant parameters
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040012438 my $PType1_Id = $CompleteSignature{1}{$Symbol}{"Param"}{$ParamPos}{"type"};
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012439 my $ParamName1 = $CompleteSignature{1}{$Symbol}{"Param"}{$ParamPos}{"name"};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012440 # FIXME: find relevant parameter by name
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012441 if(defined $CompleteSignature{2}{$PSymbol}{"Param"}{$ParamPos})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012442 {
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040012443 my $PType2_Id = $CompleteSignature{2}{$PSymbol}{"Param"}{$ParamPos}{"type"};
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012444 my $ParamName2 = $CompleteSignature{2}{$PSymbol}{"Param"}{$ParamPos}{"name"};
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040012445 if($TypeInfo{1}{$PType1_Id}{"Name"} eq $TypeInfo{2}{$PType2_Id}{"Name"}
12446 or ($ParamName1!~/\Ap\d+\Z/i and $ParamName1 eq $ParamName2)) {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012447 mergeParameters($Symbol, $PSymbol, $ParamPos, $ParamPos, $Level);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012448 }
12449 }
12450 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012451 foreach my $ParamPos (sort {int($a) <=> int($b)} keys(%{$CompleteSignature{1}{$Symbol}{"Param"}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012452 { # checking removed parameters
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040012453 my $PType1_Id = $CompleteSignature{1}{$Symbol}{"Param"}{$ParamPos}{"type"};
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040012454 my $PType1_Name = $TypeInfo{1}{$PType1_Id}{"Name"};
12455 last if($PType1_Name eq "...");
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012456 my $Parameter_Name = $CompleteSignature{1}{$Symbol}{"Param"}{$ParamPos}{"name"};
12457 my $Parameter_NewName = (defined $CompleteSignature{2}{$PSymbol}{"Param"}{$ParamPos})?$CompleteSignature{2}{$PSymbol}{"Param"}{$ParamPos}{"name"}:"";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012458 my $ParamPos_New = "-1";
12459 if($Parameter_Name=~/\Ap\d+\Z/i)
12460 { # removed unnamed parameter ( pN )
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040012461 my @Positions1 = find_ParamPair_Pos_byTypeAndPos($PType1_Name, $ParamPos, "forward", $Symbol, 1);
12462 my @Positions2 = find_ParamPair_Pos_byTypeAndPos($PType1_Name, $ParamPos, "forward", $Symbol, 2);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012463 if($#Positions2==-1 or $#Positions2<$#Positions1) {
12464 $ParamPos_New = "lost";
12465 }
12466 }
12467 else {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012468 $ParamPos_New = find_ParamPair_Pos_byName($Parameter_Name, $Symbol, 2);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012469 }
12470 if($ParamPos_New eq "lost")
12471 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012472 if($ParamPos>keys(%{$CompleteSignature{2}{$PSymbol}{"Param"}})-1)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012473 {
12474 my $ProblemType = "Removed_Parameter";
12475 if($Parameter_Name=~/\Ap\d+\Z/) {
12476 $ProblemType = "Removed_Unnamed_Parameter";
12477 }
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040012478 %{$CompatProblems{$Level}{$Symbol}{$ProblemType}{showPos($ParamPos)." Parameter"}}=(
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012479 "Target"=>$Parameter_Name,
12480 "Param_Pos"=>$ParamPos,
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040012481 "Param_Type"=>$PType1_Name,
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012482 "New_Signature"=>get_Signature($Symbol, 2) );
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012483 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012484 elsif($ParamPos<keys(%{$CompleteSignature{1}{$Symbol}{"Param"}})-1)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012485 {
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +040012486 my %ParamType_Pure = get_PureType($PType1_Id, $TypeInfo{1});
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040012487 my $PairType_Id = $CompleteSignature{2}{$PSymbol}{"Param"}{$ParamPos}{"type"};
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +040012488 my %PairType_Pure = get_PureType($PairType_Id, $TypeInfo{2});
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040012489 if(($ParamType_Pure{"Name"} eq $PairType_Pure{"Name"} or $PType1_Name eq $TypeInfo{2}{$PairType_Id}{"Name"})
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012490 and find_ParamPair_Pos_byName($Parameter_NewName, $Symbol, 1) eq "lost")
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012491 {
12492 if($Parameter_NewName!~/\Ap\d+\Z/ and $Parameter_Name!~/\Ap\d+\Z/)
12493 {
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040012494 %{$CompatProblems{$Level}{$Symbol}{"Renamed_Parameter"}{showPos($ParamPos)." Parameter"}}=(
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012495 "Target"=>$Parameter_Name,
12496 "Param_Pos"=>$ParamPos,
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040012497 "Param_Type"=>$PType1_Name,
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012498 "Old_Value"=>$Parameter_Name,
12499 "New_Value"=>$Parameter_NewName,
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012500 "New_Signature"=>get_Signature($Symbol, 2) );
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012501 }
12502 }
12503 else
12504 {
12505 my $ProblemType = "Removed_Middle_Parameter";
12506 if($Parameter_Name=~/\Ap\d+\Z/) {
12507 $ProblemType = "Removed_Middle_Unnamed_Parameter";
12508 }
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040012509 %{$CompatProblems{$Level}{$Symbol}{$ProblemType}{showPos($ParamPos)." Parameter"}}=(
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012510 "Target"=>$Parameter_Name,
12511 "Param_Pos"=>$ParamPos,
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040012512 "Param_Type"=>$PType1_Name,
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012513 "New_Signature"=>get_Signature($Symbol, 2) );
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012514 }
12515 }
12516 }
12517 }
12518 }
12519 # checking return type
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012520 my $ReturnType1_Id = $CompleteSignature{1}{$Symbol}{"Return"};
12521 my $ReturnType2_Id = $CompleteSignature{2}{$PSymbol}{"Return"};
12522 %SubProblems = detectTypeChange($ReturnType1_Id, $ReturnType2_Id, "Return", $Level);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012523 foreach my $SubProblemType (keys(%SubProblems))
12524 {
12525 my $New_Value = $SubProblems{$SubProblemType}{"New_Value"};
12526 my $Old_Value = $SubProblems{$SubProblemType}{"Old_Value"};
12527 my $NewProblemType = $SubProblemType;
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040012528 my $AddProblemType = undef;
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +040012529
12530 if($SubProblemType eq "Return_Type_And_Size"
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012531 and $CompleteSignature{1}{$Symbol}{"Data"}) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012532 $NewProblemType = "Global_Data_Type_And_Size";
12533 }
12534 elsif($SubProblemType eq "Return_Type")
12535 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012536 if($CompleteSignature{1}{$Symbol}{"Data"})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012537 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012538 if(removedQual($Old_Value, $New_Value, "const"))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012539 { # const -> non-const global data
12540 $NewProblemType = "Global_Data_Became_Non_Const";
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040012541 $AddProblemType = "Global_Data_Type";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012542 }
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040012543 elsif(addedQual($Old_Value, $New_Value, "const"))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012544 { # non-const -> const global data
12545 $NewProblemType = "Global_Data_Became_Const";
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040012546 $AddProblemType = "Global_Data_Type";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012547 }
12548 else {
12549 $NewProblemType = "Global_Data_Type";
12550 }
12551 }
12552 else
12553 {
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040012554 if(addedQual($Old_Value, $New_Value, "const"))
12555 {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012556 $NewProblemType = "Return_Type_Became_Const";
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040012557 $AddProblemType = "Return_Type";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012558 }
12559 }
12560 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012561 elsif($SubProblemType eq "Return_Type_Format")
12562 {
12563 if($CompleteSignature{1}{$Symbol}{"Data"}) {
12564 $NewProblemType = "Global_Data_Type_Format";
12565 }
12566 }
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +040012567 if($Level eq "Binary"
12568 and not $CompleteSignature{1}{$Symbol}{"Data"})
12569 {
12570 my ($Arch1, $Arch2) = (getArch(1), getArch(2));
12571 if($Arch1 eq "unknown" or $Arch2 eq "unknown")
12572 { # if one of the architectures is unknown
12573 # then set other arhitecture to unknown too
12574 ($Arch1, $Arch2) = ("unknown", "unknown");
12575 }
12576 my (%Conv1, %Conv2) = ();
12577 if($UseConv_Real{1} and $UseConv_Real{1})
12578 {
12579 %Conv1 = callingConvention_R_Real($CompleteSignature{1}{$Symbol});
12580 %Conv2 = callingConvention_R_Real($CompleteSignature{2}{$PSymbol});
12581 }
12582 else
12583 {
12584 %Conv1 = callingConvention_R_Model($CompleteSignature{1}{$Symbol}, $TypeInfo{1}, $Arch1, $OStarget, $WORD_SIZE{1});
12585 %Conv2 = callingConvention_R_Model($CompleteSignature{2}{$PSymbol}, $TypeInfo{2}, $Arch2, $OStarget, $WORD_SIZE{2});
12586 }
12587
12588 if($SubProblemType eq "Return_Type_Became_Void")
12589 {
12590 if(keys(%{$CompleteSignature{1}{$Symbol}{"Param"}}))
12591 { # parameters stack has been affected
12592 if($Conv1{"Method"} eq "stack") {
12593 $NewProblemType = "Return_Type_Became_Void_And_Stack_Layout";
12594 }
12595 elsif($Conv1{"Hidden"}) {
12596 $NewProblemType = "Return_Type_Became_Void_And_Register";
12597 }
12598 }
12599 }
12600 elsif($SubProblemType eq "Return_Type_From_Void")
12601 {
12602 if(keys(%{$CompleteSignature{1}{$Symbol}{"Param"}}))
12603 { # parameters stack has been affected
12604 if($Conv2{"Method"} eq "stack") {
12605 $NewProblemType = "Return_Type_From_Void_And_Stack_Layout";
12606 }
12607 elsif($Conv2{"Hidden"}) {
12608 $NewProblemType = "Return_Type_From_Void_And_Register";
12609 }
12610 }
12611 }
12612 elsif($SubProblemType eq "Return_Type"
12613 or $SubProblemType eq "Return_Type_And_Size"
12614 or $SubProblemType eq "Return_Type_Format")
12615 {
12616 if($Conv1{"Method"} ne $Conv2{"Method"})
12617 {
12618 if($Conv1{"Method"} eq "stack")
12619 { # returns in a register instead of a hidden first parameter
12620 $NewProblemType = "Return_Type_From_Stack_To_Register";
12621 }
12622 else {
12623 $NewProblemType = "Return_Type_From_Register_To_Stack";
12624 }
12625 }
12626 else
12627 {
12628 if($Conv1{"Method"} eq "reg")
12629 {
12630 if($Conv1{"Registers"} ne $Conv2{"Registers"})
12631 {
12632 if($Conv1{"Hidden"}) {
12633 $NewProblemType = "Return_Type_And_Register_Was_Hidden_Parameter";
12634 }
12635 elsif($Conv2{"Hidden"}) {
12636 $NewProblemType = "Return_Type_And_Register_Became_Hidden_Parameter";
12637 }
12638 else {
12639 $NewProblemType = "Return_Type_And_Register";
12640 }
12641 }
12642 }
12643 }
12644 }
12645 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012646 @{$CompatProblems{$Level}{$Symbol}{$NewProblemType}{"retval"}}{keys(%{$SubProblems{$SubProblemType}})} = values %{$SubProblems{$SubProblemType}};
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040012647 if(defined $AddProblemType) {
12648 @{$CompatProblems{$Level}{$Symbol}{$AddProblemType}{"retval"}}{keys(%{$SubProblems{$SubProblemType}})} = values %{$SubProblems{$SubProblemType}};
12649 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012650 }
12651 if($ReturnType1_Id and $ReturnType2_Id)
12652 {
12653 @RecurTypes = ();
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040012654 %SubProblems = mergeTypes($ReturnType1_Id, $ReturnType2_Id, $Level);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012655 foreach my $SubProblemType (keys(%SubProblems))
12656 { # add "Global_Data_Size" problem
12657 my $New_Value = $SubProblems{$SubProblemType}{"New_Value"};
12658 my $Old_Value = $SubProblems{$SubProblemType}{"Old_Value"};
12659 if($SubProblemType eq "DataType_Size"
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012660 and $CompleteSignature{1}{$Symbol}{"Data"}
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040012661 and get_PLevel($ReturnType1_Id, 1)==0)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012662 { # add a new problem
12663 %{$SubProblems{"Global_Data_Size"}} = %{$SubProblems{$SubProblemType}};
12664 }
12665 }
12666 foreach my $SubProblemType (keys(%SubProblems))
12667 {
12668 foreach my $SubLocation (keys(%{$SubProblems{$SubProblemType}}))
12669 {
12670 my $NewLocation = ($SubLocation)?"retval->".$SubLocation:"retval";
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012671 %{$CompatProblems{$Level}{$Symbol}{$SubProblemType}{$NewLocation}}=(
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040012672 "Return_Type_Name"=>$TypeInfo{1}{$ReturnType1_Id}{"Name"} );
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012673 @{$CompatProblems{$Level}{$Symbol}{$SubProblemType}{$NewLocation}}{keys(%{$SubProblems{$SubProblemType}{$SubLocation}})} = values %{$SubProblems{$SubProblemType}{$SubLocation}};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012674 if($SubLocation!~/\-\>/) {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040012675 $CompatProblems{$Level}{$Symbol}{$SubProblemType}{$NewLocation}{"Start_Type_Name"} = $TypeInfo{1}{$ReturnType1_Id}{"Name"};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012676 }
12677 }
12678 }
12679 }
12680
12681 # checking object type
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040012682 my $ObjTId1 = $CompleteSignature{1}{$Symbol}{"Class"};
12683 my $ObjTId2 = $CompleteSignature{2}{$PSymbol}{"Class"};
12684 if($ObjTId1 and $ObjTId2
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012685 and not $CompleteSignature{1}{$Symbol}{"Static"})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012686 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040012687 my $ThisPtr1_Id = getTypeIdByName($TypeInfo{1}{$ObjTId1}{"Name"}."*const", 1);
12688 my $ThisPtr2_Id = getTypeIdByName($TypeInfo{2}{$ObjTId2}{"Name"}."*const", 2);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012689 if($ThisPtr1_Id and $ThisPtr2_Id)
12690 {
12691 @RecurTypes = ();
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040012692 %SubProblems = mergeTypes($ThisPtr1_Id, $ThisPtr2_Id, $Level);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012693 foreach my $SubProblemType (keys(%SubProblems))
12694 {
12695 foreach my $SubLocation (keys(%{$SubProblems{$SubProblemType}}))
12696 {
12697 my $NewLocation = ($SubLocation)?"this->".$SubLocation:"this";
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012698 %{$CompatProblems{$Level}{$Symbol}{$SubProblemType}{$NewLocation}}=(
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040012699 "Object_Type_Name"=>$TypeInfo{1}{$ObjTId1}{"Name"} );
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012700 @{$CompatProblems{$Level}{$Symbol}{$SubProblemType}{$NewLocation}}{keys(%{$SubProblems{$SubProblemType}{$SubLocation}})} = values %{$SubProblems{$SubProblemType}{$SubLocation}};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012701 if($SubLocation!~/\-\>/) {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040012702 $CompatProblems{$Level}{$Symbol}{$SubProblemType}{$NewLocation}{"Start_Type_Name"} = $TypeInfo{1}{$ObjTId1}{"Name"};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012703 }
12704 }
12705 }
12706 }
12707 }
12708 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012709 if($Level eq "Binary") {
12710 mergeVTables($Level);
12711 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +040012712 foreach my $Symbol (keys(%{$CompatProblems{$Level}})) {
12713 $CheckedSymbols{$Level}{$Symbol} = 1;
12714 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012715}
12716
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040012717sub rmQuals($$)
12718{
12719 my ($Value, $Qual) = @_;
12720 if(not $Qual) {
12721 return $Value;
12722 }
12723 if($Qual eq "all")
12724 { # all quals
12725 $Qual = "const|volatile|restrict";
12726 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040012727 while($Value=~s/\b$Qual\b//) {
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040012728 $Value = formatName($Value, "T");
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040012729 }
12730 return $Value;
12731}
12732
12733sub cmpBTypes($$$$)
12734{
12735 my ($T1, $T2, $V1, $V2) = @_;
12736 $T1 = uncover_typedefs($T1, $V1);
12737 $T2 = uncover_typedefs($T2, $V2);
12738 return (rmQuals($T1, "all") eq rmQuals($T2, "all"));
12739}
12740
12741sub addedQual($$$)
12742{
12743 my ($Old_Value, $New_Value, $Qual) = @_;
Andrey Ponomarenko85043792012-05-14 16:48:07 +040012744 return removedQual_($New_Value, $Old_Value, 2, 1, $Qual);
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040012745}
12746
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012747sub removedQual($$$)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012748{
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012749 my ($Old_Value, $New_Value, $Qual) = @_;
Andrey Ponomarenko85043792012-05-14 16:48:07 +040012750 return removedQual_($Old_Value, $New_Value, 1, 2, $Qual);
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040012751}
12752
12753sub removedQual_($$$$$)
12754{
12755 my ($Old_Value, $New_Value, $V1, $V2, $Qual) = @_;
12756 $Old_Value = uncover_typedefs($Old_Value, $V1);
12757 $New_Value = uncover_typedefs($New_Value, $V2);
12758 if($Old_Value eq $New_Value)
12759 { # equal types
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012760 return 0;
12761 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040012762 if($Old_Value!~/\b$Qual\b/)
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040012763 { # without a qual
12764 return 0;
12765 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040012766 elsif($New_Value!~/\b$Qual\b/)
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040012767 { # became non-qual
12768 return 1;
12769 }
12770 else
12771 {
12772 my @BQ1 = getQualModel($Old_Value, $Qual);
12773 my @BQ2 = getQualModel($New_Value, $Qual);
12774 foreach (0 .. $#BQ1)
12775 { # removed qual
12776 if($BQ1[$_]==1
12777 and $BQ2[$_]!=1)
12778 {
12779 return 2;
12780 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012781 }
12782 }
12783 return 0;
12784}
12785
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040012786sub getQualModel($$)
12787{
12788 my ($Value, $Qual) = @_;
12789 if(not $Qual) {
12790 return $Value;
12791 }
12792
12793 # cleaning
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040012794 while($Value=~/(\w+)/ and $1 ne $Qual) {
12795 $Value=~s/\b$1\b//g;
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040012796 }
12797 $Value=~s/[^\*\&\w]+//g;
12798
12799 # modeling
12800 # int*const*const == 011
12801 # int**const == 001
12802 my @Model = ();
12803 my @Elems = split(/[\*\&]/, $Value);
12804 if(not @Elems) {
12805 return (0);
12806 }
12807 foreach (@Elems)
12808 {
12809 if($_ eq $Qual) {
12810 push(@Model, 1);
12811 }
12812 else {
12813 push(@Model, 0);
12814 }
12815 }
12816
12817 return @Model;
12818}
12819
12820sub showVal($$$)
12821{
12822 my ($Value, $TypeId, $LibVersion) = @_;
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +040012823 my %PureType = get_PureType($TypeId, $TypeInfo{$LibVersion});
Andrey Ponomarenkoa01311b2012-06-08 17:20:02 +040012824 my $TName = uncover_typedefs($PureType{"Name"}, $LibVersion);
Andrey Ponomarenko01117f12012-06-26 12:23:02 +040012825 if(substr($Value, 0, 2) eq "_Z")
12826 {
12827 if(my $Unmangled = $tr_name{$Value}) {
12828 return $Unmangled;
12829 }
12830 }
Andrey Ponomarenko07aea072012-11-12 16:15:07 +040012831 elsif($TName=~/\A(char(| const)\*|std::(string(| const)|basic_string<char>(|const))(|&))\Z/)
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040012832 { # strings
12833 return "\"$Value\"";
12834 }
Andrey Ponomarenkoa01311b2012-06-08 17:20:02 +040012835 elsif($TName=~/\Achar(| const)\Z/)
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040012836 { # characters
12837 return "\'$Value\'";
12838 }
12839 return $Value;
12840}
12841
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012842sub mergeParameters($$$$$)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012843{
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012844 my ($Symbol, $PSymbol, $ParamPos1, $ParamPos2, $Level) = @_;
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040012845 if(not $Symbol) {
12846 return;
12847 }
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040012848 my $PType1_Id = $CompleteSignature{1}{$Symbol}{"Param"}{$ParamPos1}{"type"};
12849 my $PName1 = $CompleteSignature{1}{$Symbol}{"Param"}{$ParamPos1}{"name"};
12850 my $PType2_Id = $CompleteSignature{2}{$PSymbol}{"Param"}{$ParamPos2}{"type"};
12851 my $PName2 = $CompleteSignature{2}{$PSymbol}{"Param"}{$ParamPos2}{"name"};
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040012852 if(not $PType1_Id
12853 or not $PType2_Id) {
12854 return;
12855 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040012856 my %Type1 = get_Type($PType1_Id, 1);
12857 my %Type2 = get_Type($PType2_Id, 2);
12858 my %BaseType1 = get_BaseType($PType1_Id, 1);
12859 my %BaseType2 = get_BaseType($PType2_Id, 2);
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040012860 my $Parameter_Location = ($PName1)?$PName1:showPos($ParamPos1)." Parameter";
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012861 if($Level eq "Binary")
12862 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040012863 if(checkDump(1, "2.6.1") and checkDump(2, "2.6.1"))
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012864 { # "reg" attribute added in ACC 1.95.1 (dump 2.6.1 format)
12865 if($CompleteSignature{1}{$Symbol}{"Param"}{$ParamPos1}{"reg"}
12866 and not $CompleteSignature{2}{$PSymbol}{"Param"}{$ParamPos2}{"reg"})
12867 {
12868 %{$CompatProblems{$Level}{$Symbol}{"Parameter_Became_Non_Register"}{$Parameter_Location}}=(
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040012869 "Target"=>$PName1,
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012870 "Param_Pos"=>$ParamPos1 );
12871 }
12872 elsif(not $CompleteSignature{1}{$Symbol}{"Param"}{$ParamPos1}{"reg"}
12873 and $CompleteSignature{2}{$PSymbol}{"Param"}{$ParamPos2}{"reg"})
12874 {
12875 %{$CompatProblems{$Level}{$Symbol}{"Parameter_Became_Register"}{$Parameter_Location}}=(
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040012876 "Target"=>$PName1,
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012877 "Param_Pos"=>$ParamPos1 );
12878 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012879 }
12880 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040012881 if(checkDump(1, "2.0") and checkDump(2, "2.0"))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012882 { # "default" attribute added in ACC 1.22 (dump 2.0 format)
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040012883 my $Value_Old = $CompleteSignature{1}{$Symbol}{"Param"}{$ParamPos1}{"default"};
12884 my $Value_New = $CompleteSignature{2}{$PSymbol}{"Param"}{$ParamPos2}{"default"};
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040012885 if(not checkDump(1, "2.13")
12886 and checkDump(2, "2.13"))
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040012887 { # support for old ABI dumps
12888 if(defined $Value_Old and defined $Value_New)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012889 {
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040012890 if($Type1{"Name"} eq "bool"
12891 and $Value_Old eq "false" and $Value_New eq "0")
12892 { # int class::method ( bool p = 0 );
12893 # old ABI dumps: "false"
12894 # new ABI dumps: "0"
12895 $Value_Old = "0";
12896 }
12897 }
12898 }
Andrey Ponomarenko01117f12012-06-26 12:23:02 +040012899 if(not checkDump(1, "2.18")
12900 and checkDump(2, "2.18"))
12901 { # support for old ABI dumps
12902 if(not defined $Value_Old
12903 and substr($Value_New, 0, 2) eq "_Z") {
12904 $Value_Old = $Value_New;
12905 }
12906 }
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040012907 if(defined $Value_Old)
12908 {
12909 $Value_Old = showVal($Value_Old, $PType1_Id, 1);
12910 if(defined $Value_New)
12911 {
12912 $Value_New = showVal($Value_New, $PType2_Id, 2);
12913 if($Value_Old ne $Value_New)
12914 { # FIXME: how to distinguish "0" and 0 (NULL)
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012915 %{$CompatProblems{$Level}{$Symbol}{"Parameter_Default_Value_Changed"}{$Parameter_Location}}=(
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040012916 "Target"=>$PName1,
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012917 "Param_Pos"=>$ParamPos1,
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040012918 "Old_Value"=>$Value_Old,
12919 "New_Value"=>$Value_New );
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012920 }
12921 }
12922 else
12923 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012924 %{$CompatProblems{$Level}{$Symbol}{"Parameter_Default_Value_Removed"}{$Parameter_Location}}=(
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040012925 "Target"=>$PName1,
12926 "Param_Pos"=>$ParamPos1,
12927 "Old_Value"=>$Value_Old );
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012928 }
12929 }
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040012930 elsif(defined $Value_New)
12931 {
12932 $Value_New = showVal($Value_New, $PType2_Id, 2);
12933 %{$CompatProblems{$Level}{$Symbol}{"Parameter_Default_Value_Added"}{$Parameter_Location}}=(
12934 "Target"=>$PName1,
12935 "Param_Pos"=>$ParamPos1,
12936 "New_Value"=>$Value_New );
12937 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012938 }
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040012939 if($PName1 and $PName2 and $PName1 ne $PName2
12940 and $PType1_Id!=-1 and $PType2_Id!=-1
12941 and $PName1!~/\Ap\d+\Z/ and $PName2!~/\Ap\d+\Z/)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012942 { # except unnamed "..." value list (Id=-1)
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040012943 %{$CompatProblems{$Level}{$Symbol}{"Renamed_Parameter"}{showPos($ParamPos1)." Parameter"}}=(
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040012944 "Target"=>$PName1,
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012945 "Param_Pos"=>$ParamPos1,
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040012946 "Param_Type"=>$TypeInfo{1}{$PType1_Id}{"Name"},
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040012947 "Old_Value"=>$PName1,
12948 "New_Value"=>$PName2,
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012949 "New_Signature"=>get_Signature($Symbol, 2) );
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012950 }
12951 # checking type change (replace)
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040012952 my %SubProblems = detectTypeChange($PType1_Id, $PType2_Id, "Parameter", $Level);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012953 foreach my $SubProblemType (keys(%SubProblems))
12954 { # add new problems, remove false alarms
12955 my $New_Value = $SubProblems{$SubProblemType}{"New_Value"};
12956 my $Old_Value = $SubProblems{$SubProblemType}{"Old_Value"};
12957 if($SubProblemType eq "Parameter_Type")
12958 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040012959 if(checkDump(1, "2.6") and checkDump(2, "2.6"))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012960 {
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040012961 if(my $RA = addedQual($Old_Value, $New_Value, "restrict"))
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012962 {
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040012963 %{$SubProblems{"Parameter_Became_Restrict"}} = %{$SubProblems{$SubProblemType}};
12964 if($Level eq "Source"
12965 and cmpBTypes($Old_Value, $New_Value, 1, 2)) {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012966 delete($SubProblems{$SubProblemType});
12967 }
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040012968 }
12969 elsif(my $RR = removedQual($Old_Value, $New_Value, "restrict"))
12970 {
12971 %{$SubProblems{"Parameter_Became_NonRestrict"}} = %{$SubProblems{$SubProblemType}};
12972 if($Level eq "Source"
12973 and cmpBTypes($Old_Value, $New_Value, 1, 2)) {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012974 delete($SubProblems{$SubProblemType});
12975 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012976 }
12977 }
12978 if($Type2{"Type"} eq "Const" and $BaseType2{"Name"} eq $Type1{"Name"}
12979 and $Type1{"Type"}=~/Intrinsic|Class|Struct|Union|Enum/)
12980 { # int to "int const"
12981 delete($SubProblems{$SubProblemType});
12982 }
12983 if($Type1{"Type"} eq "Const" and $BaseType1{"Name"} eq $Type2{"Name"}
12984 and $Type2{"Type"}=~/Intrinsic|Class|Struct|Union|Enum/)
12985 { # "int const" to int
12986 delete($SubProblems{$SubProblemType});
12987 }
12988 }
12989 }
12990 foreach my $SubProblemType (keys(%SubProblems))
12991 { # modify/register problems
12992 my $New_Value = $SubProblems{$SubProblemType}{"New_Value"};
12993 my $Old_Value = $SubProblems{$SubProblemType}{"Old_Value"};
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +040012994 my $New_Size = $SubProblems{$SubProblemType}{"New_Size"};
12995 my $Old_Size = $SubProblems{$SubProblemType}{"Old_Size"};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012996 my $NewProblemType = $SubProblemType;
12997 if($Old_Value eq "..." and $New_Value ne "...")
12998 { # change from "..." to "int"
12999 if($ParamPos1==0)
13000 { # ISO C requires a named argument before "..."
13001 next;
13002 }
13003 $NewProblemType = "Parameter_Became_NonVaList";
13004 }
13005 elsif($New_Value eq "..." and $Old_Value ne "...")
13006 { # change from "int" to "..."
13007 if($ParamPos2==0)
13008 { # ISO C requires a named argument before "..."
13009 next;
13010 }
13011 $NewProblemType = "Parameter_Became_VaList";
13012 }
13013 elsif($SubProblemType eq "Parameter_Type"
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040013014 and removedQual($Old_Value, $New_Value, "const"))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013015 { # parameter: "const" to non-"const"
13016 $NewProblemType = "Parameter_Became_Non_Const";
13017 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040013018 elsif($Level eq "Binary" and ($SubProblemType eq "Parameter_Type_And_Size"
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +040013019 or $SubProblemType eq "Parameter_Type" or $SubProblemType eq "Parameter_Type_Format"))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013020 {
13021 my ($Arch1, $Arch2) = (getArch(1), getArch(2));
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +040013022 if($Arch1 eq "unknown"
13023 or $Arch2 eq "unknown")
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013024 { # if one of the architectures is unknown
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +040013025 # then set other arhitecture to unknown too
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013026 ($Arch1, $Arch2) = ("unknown", "unknown");
13027 }
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +040013028 my (%Conv1, %Conv2) = ();
13029 if($UseConv_Real{1} and $UseConv_Real{1})
13030 { # real
13031 %Conv1 = callingConvention_P_Real($CompleteSignature{1}{$Symbol}, $ParamPos1);
13032 %Conv2 = callingConvention_P_Real($CompleteSignature{2}{$Symbol}, $ParamPos2);
13033 }
13034 else
13035 { # model
13036 %Conv1 = callingConvention_P_Model($CompleteSignature{1}{$Symbol}, $ParamPos1, $TypeInfo{1}, $Arch1, $OStarget, $WORD_SIZE{1});
13037 %Conv2 = callingConvention_P_Model($CompleteSignature{2}{$Symbol}, $ParamPos2, $TypeInfo{2}, $Arch2, $OStarget, $WORD_SIZE{2});
13038 }
13039 if($Conv1{"Method"} eq $Conv2{"Method"})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013040 {
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +040013041 if($Conv1{"Method"} eq "stack")
13042 {
13043 if($Old_Size ne $New_Size) { # FIXME: isMemPadded, getOffset
13044 $NewProblemType = "Parameter_Type_And_Stack";
13045 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013046 }
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +040013047 elsif($Conv1{"Method"} eq "reg")
13048 {
13049 if($Conv1{"Registers"} ne $Conv2{"Registers"}) {
13050 $NewProblemType = "Parameter_Type_And_Register";
13051 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013052 }
13053 }
13054 else
13055 {
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +040013056 if($Conv1{"Method"} eq "stack") {
13057 $NewProblemType = "Parameter_Type_From_Stack_To_Register";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013058 }
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +040013059 elsif($Conv1{"Method"} eq "register") {
13060 $NewProblemType = "Parameter_Type_From_Register_To_Stack";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013061 }
13062 }
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +040013063 $SubProblems{$SubProblemType}{"Old_Reg"} = $Conv1{"Registers"};
13064 $SubProblems{$SubProblemType}{"New_Reg"} = $Conv2{"Registers"};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013065 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040013066 %{$CompatProblems{$Level}{$Symbol}{$NewProblemType}{$Parameter_Location}}=(
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040013067 "Target"=>$PName1,
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013068 "Param_Pos"=>$ParamPos1,
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040013069 "New_Signature"=>get_Signature($Symbol, 2) );
13070 @{$CompatProblems{$Level}{$Symbol}{$NewProblemType}{$Parameter_Location}}{keys(%{$SubProblems{$SubProblemType}})} = values %{$SubProblems{$SubProblemType}};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013071 }
13072 @RecurTypes = ();
13073 # checking type definition changes
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040013074 my %SubProblems_Merge = mergeTypes($PType1_Id, $PType2_Id, $Level);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013075 foreach my $SubProblemType (keys(%SubProblems_Merge))
13076 {
13077 foreach my $SubLocation (keys(%{$SubProblems_Merge{$SubProblemType}}))
13078 {
13079 my $NewProblemType = $SubProblemType;
13080 if($SubProblemType eq "DataType_Size")
13081 {
13082 my $InitialType_Type = $SubProblems_Merge{$SubProblemType}{$SubLocation}{"InitialType_Type"};
13083 if($InitialType_Type!~/\A(Pointer|Ref)\Z/ and $SubLocation!~/\-\>/)
13084 { # stack has been affected
13085 $NewProblemType = "DataType_Size_And_Stack";
13086 }
13087 }
13088 my $NewLocation = ($SubLocation)?$Parameter_Location."->".$SubLocation:$Parameter_Location;
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040013089 %{$CompatProblems{$Level}{$Symbol}{$NewProblemType}{$NewLocation}}=(
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040013090 "Param_Type"=>$TypeInfo{1}{$PType1_Id}{"Name"},
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013091 "Param_Pos"=>$ParamPos1,
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040013092 "Param_Name"=>$PName1 );
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040013093 @{$CompatProblems{$Level}{$Symbol}{$NewProblemType}{$NewLocation}}{keys(%{$SubProblems_Merge{$SubProblemType}{$SubLocation}})} = values %{$SubProblems_Merge{$SubProblemType}{$SubLocation}};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013094 if($SubLocation!~/\-\>/) {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040013095 $CompatProblems{$Level}{$Symbol}{$NewProblemType}{$NewLocation}{"Start_Type_Name"} = $TypeInfo{1}{$PType1_Id}{"Name"};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013096 }
13097 }
13098 }
13099}
13100
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013101sub find_ParamPair_Pos_byName($$$)
13102{
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040013103 my ($Name, $Symbol, $LibVersion) = @_;
13104 foreach my $ParamPos (sort {int($a)<=>int($b)} keys(%{$CompleteSignature{$LibVersion}{$Symbol}{"Param"}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013105 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040013106 next if(not defined $CompleteSignature{$LibVersion}{$Symbol}{"Param"}{$ParamPos});
13107 if($CompleteSignature{$LibVersion}{$Symbol}{"Param"}{$ParamPos}{"name"} eq $Name)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013108 {
13109 return $ParamPos;
13110 }
13111 }
13112 return "lost";
13113}
13114
13115sub find_ParamPair_Pos_byTypeAndPos($$$$$)
13116{
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040013117 my ($TypeName, $MediumPos, $Order, $Symbol, $LibVersion) = @_;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013118 my @Positions = ();
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040013119 foreach my $ParamPos (sort {int($a)<=>int($b)} keys(%{$CompleteSignature{$LibVersion}{$Symbol}{"Param"}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013120 {
13121 next if($Order eq "backward" and $ParamPos>$MediumPos);
13122 next if($Order eq "forward" and $ParamPos<$MediumPos);
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040013123 next if(not defined $CompleteSignature{$LibVersion}{$Symbol}{"Param"}{$ParamPos});
13124 my $PTypeId = $CompleteSignature{$LibVersion}{$Symbol}{"Param"}{$ParamPos}{"type"};
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040013125 if($TypeInfo{$LibVersion}{$PTypeId}{"Name"} eq $TypeName) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013126 push(@Positions, $ParamPos);
13127 }
13128 }
13129 return @Positions;
13130}
13131
13132sub getTypeIdByName($$)
13133{
13134 my ($TypeName, $Version) = @_;
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040013135 return $TName_Tid{$Version}{formatName($TypeName, "T")};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013136}
13137
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040013138sub checkFormatChange($$$)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013139{
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040013140 my ($Type1_Id, $Type2_Id, $Level) = @_;
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +040013141 my %Type1_Pure = get_PureType($Type1_Id, $TypeInfo{1});
13142 my %Type2_Pure = get_PureType($Type2_Id, $TypeInfo{2});
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013143 if($Type1_Pure{"Name"} eq $Type2_Pure{"Name"})
13144 { # equal types
13145 return 0;
13146 }
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040013147 if($Type1_Pure{"Name"} eq "void")
13148 { # from void* to something
13149 return 0;
13150 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013151 if($Type1_Pure{"Name"}=~/\*/
13152 or $Type2_Pure{"Name"}=~/\*/)
13153 { # compared in detectTypeChange()
13154 return 0;
13155 }
13156 my %FloatType = map {$_=>1} (
13157 "float",
13158 "double",
13159 "long double"
13160 );
13161 if($Type1_Pure{"Type"} ne $Type2_Pure{"Type"})
13162 { # different types
13163 if($Type1_Pure{"Type"} eq "Intrinsic"
13164 and $Type2_Pure{"Type"} eq "Enum")
13165 { # "int" to "enum"
13166 return 0;
13167 }
13168 elsif($Type2_Pure{"Type"} eq "Intrinsic"
13169 and $Type1_Pure{"Type"} eq "Enum")
13170 { # "enum" to "int"
13171 return 0;
13172 }
13173 else
13174 { # "union" to "struct"
13175 # ...
13176 return 1;
13177 }
13178 }
13179 else
13180 {
13181 if($Type1_Pure{"Type"} eq "Intrinsic")
13182 {
13183 if($FloatType{$Type1_Pure{"Name"}}
13184 or $FloatType{$Type2_Pure{"Name"}})
13185 { # "float" to "double"
13186 # "float" to "int"
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040013187 if($Level eq "Source")
13188 { # Safe
13189 return 0;
13190 }
13191 else {
13192 return 1;
13193 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013194 }
13195 }
13196 elsif($Type1_Pure{"Type"}=~/Class|Struct|Union|Enum/)
13197 {
13198 my @Membs1 = keys(%{$Type1_Pure{"Memb"}});
13199 my @Membs2 = keys(%{$Type2_Pure{"Memb"}});
13200 if($#Membs1!=$#Membs2)
13201 { # different number of elements
13202 return 1;
13203 }
13204 if($Type1_Pure{"Type"} eq "Enum")
13205 {
13206 foreach my $Pos (@Membs1)
13207 { # compare elements by name and value
13208 if($Type1_Pure{"Memb"}{$Pos}{"name"} ne $Type2_Pure{"Memb"}{$Pos}{"name"}
13209 or $Type1_Pure{"Memb"}{$Pos}{"value"} ne $Type2_Pure{"Memb"}{$Pos}{"value"})
13210 { # different names
13211 return 1;
13212 }
13213 }
13214 }
13215 else
13216 {
13217 foreach my $Pos (@Membs1)
13218 { # compare elements by type name
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040013219 my $MT1 = $TypeInfo{1}{$Type1_Pure{"Memb"}{$Pos}{"type"}}{"Name"};
13220 my $MT2 = $TypeInfo{2}{$Type2_Pure{"Memb"}{$Pos}{"type"}}{"Name"};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013221 if($MT1 ne $MT2)
13222 { # different types
13223 return 1;
13224 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040013225 if($Level eq "Source")
13226 {
13227 if($Type1_Pure{"Memb"}{$Pos}{"name"} ne $Type2_Pure{"Memb"}{$Pos}{"name"})
13228 { # different names
13229 return 1;
13230 }
13231 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013232 }
13233 }
13234 }
13235 }
13236 return 0;
13237}
13238
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040013239sub detectTypeChange($$$$)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013240{
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040013241 my ($Type1_Id, $Type2_Id, $Prefix, $Level) = @_;
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040013242 if(not $Type1_Id or not $Type2_Id) {
13243 return ();
13244 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013245 my %LocalProblems = ();
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040013246 my %Type1 = get_Type($Type1_Id, 1);
13247 my %Type2 = get_Type($Type2_Id, 2);
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +040013248 my %Type1_Pure = get_PureType($Type1_Id, $TypeInfo{1});
13249 my %Type2_Pure = get_PureType($Type2_Id, $TypeInfo{2});
13250 my %Type1_Base = ($Type1_Pure{"Type"} eq "Array")?get_OneStep_BaseType($Type1_Pure{"Tid"}, $TypeInfo{1}):get_BaseType($Type1_Id, 1);
13251 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 +040013252 my $Type1_PLevel = get_PLevel($Type1_Id, 1);
13253 my $Type2_PLevel = get_PLevel($Type2_Id, 2);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013254 return () if(not $Type1{"Name"} or not $Type2{"Name"});
13255 return () if(not $Type1_Base{"Name"} or not $Type2_Base{"Name"});
13256 return () if($Type1_PLevel eq "" or $Type2_PLevel eq "");
13257 if($Type1_Base{"Name"} ne $Type2_Base{"Name"}
13258 and ($Type1{"Name"} eq $Type2{"Name"} or ($Type1_PLevel>=1 and $Type1_PLevel==$Type2_PLevel
13259 and $Type1_Base{"Name"} ne "void" and $Type2_Base{"Name"} ne "void")))
13260 { # base type change
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040013261 if($Type1{"Name"} eq $Type2{"Name"})
13262 {
13263 if($Type1{"Type"} eq "Typedef" and $Type2{"Type"} eq "Typedef")
13264 { # will be reported in mergeTypes() as typedef problem
13265 return ();
13266 }
13267 my %Typedef_1 = goToFirst($Type1{"Tid"}, 1, "Typedef");
13268 my %Typedef_2 = goToFirst($Type2{"Tid"}, 2, "Typedef");
13269 if(%Typedef_1 and %Typedef_2)
13270 {
13271 if($Typedef_1{"Name"} eq $Typedef_2{"Name"}
13272 and $Typedef_1{"Type"} eq "Typedef" and $Typedef_2{"Type"} eq "Typedef")
13273 { # const Typedef
13274 return ();
13275 }
13276 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013277 }
13278 if($Type1_Base{"Name"}!~/anon\-/ and $Type2_Base{"Name"}!~/anon\-/)
13279 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040013280 if($Level eq "Binary"
13281 and $Type1_Base{"Size"} ne $Type2_Base{"Size"}
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013282 and $Type1_Base{"Size"} and $Type2_Base{"Size"})
13283 {
13284 %{$LocalProblems{$Prefix."_BaseType_And_Size"}}=(
13285 "Old_Value"=>$Type1_Base{"Name"},
13286 "New_Value"=>$Type2_Base{"Name"},
13287 "Old_Size"=>$Type1_Base{"Size"}*$BYTE_SIZE,
13288 "New_Size"=>$Type2_Base{"Size"}*$BYTE_SIZE,
13289 "InitialType_Type"=>$Type1_Pure{"Type"});
13290 }
13291 else
13292 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040013293 if(checkFormatChange($Type1_Base{"Tid"}, $Type2_Base{"Tid"}, $Level))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013294 { # format change
13295 %{$LocalProblems{$Prefix."_BaseType_Format"}}=(
13296 "Old_Value"=>$Type1_Base{"Name"},
13297 "New_Value"=>$Type2_Base{"Name"},
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +040013298 "Old_Size"=>$Type1_Base{"Size"}*$BYTE_SIZE,
13299 "New_Size"=>$Type2_Base{"Size"}*$BYTE_SIZE,
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013300 "InitialType_Type"=>$Type1_Pure{"Type"});
13301 }
13302 elsif(tNameLock($Type1_Base{"Tid"}, $Type2_Base{"Tid"}))
13303 {
13304 %{$LocalProblems{$Prefix."_BaseType"}}=(
13305 "Old_Value"=>$Type1_Base{"Name"},
13306 "New_Value"=>$Type2_Base{"Name"},
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +040013307 "Old_Size"=>$Type1_Base{"Size"}*$BYTE_SIZE,
13308 "New_Size"=>$Type2_Base{"Size"}*$BYTE_SIZE,
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013309 "InitialType_Type"=>$Type1_Pure{"Type"});
13310 }
13311 }
13312 }
13313 }
13314 elsif($Type1{"Name"} ne $Type2{"Name"})
13315 { # type change
13316 if($Type1{"Name"}!~/anon\-/ and $Type2{"Name"}!~/anon\-/)
13317 {
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +040013318 if($Prefix eq "Return"
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013319 and $Type1_Pure{"Name"} eq "void")
13320 {
13321 %{$LocalProblems{"Return_Type_From_Void"}}=(
13322 "New_Value"=>$Type2{"Name"},
13323 "New_Size"=>$Type2{"Size"}*$BYTE_SIZE,
13324 "InitialType_Type"=>$Type1_Pure{"Type"});
13325 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013326 elsif($Prefix eq "Return"
13327 and $Type2_Pure{"Name"} eq "void")
13328 {
13329 %{$LocalProblems{"Return_Type_Became_Void"}}=(
13330 "Old_Value"=>$Type1{"Name"},
13331 "Old_Size"=>$Type1{"Size"}*$BYTE_SIZE,
13332 "InitialType_Type"=>$Type1_Pure{"Type"});
13333 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013334 else
13335 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040013336 if($Level eq "Binary"
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040013337 and $Type1{"Size"} and $Type2{"Size"}
13338 and $Type1{"Size"} ne $Type2{"Size"})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013339 {
13340 %{$LocalProblems{$Prefix."_Type_And_Size"}}=(
13341 "Old_Value"=>$Type1{"Name"},
13342 "New_Value"=>$Type2{"Name"},
13343 "Old_Size"=>$Type1{"Size"}*$BYTE_SIZE,
13344 "New_Size"=>$Type2{"Size"}*$BYTE_SIZE,
13345 "InitialType_Type"=>$Type1_Pure{"Type"});
13346 }
13347 else
13348 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040013349 if(checkFormatChange($Type1_Id, $Type2_Id, $Level))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013350 { # format change
13351 %{$LocalProblems{$Prefix."_Type_Format"}}=(
13352 "Old_Value"=>$Type1{"Name"},
13353 "New_Value"=>$Type2{"Name"},
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +040013354 "Old_Size"=>$Type1{"Size"}*$BYTE_SIZE,
13355 "New_Size"=>$Type2{"Size"}*$BYTE_SIZE,
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013356 "InitialType_Type"=>$Type1_Pure{"Type"});
13357 }
13358 elsif(tNameLock($Type1_Id, $Type2_Id))
13359 { # FIXME: correct this condition
13360 %{$LocalProblems{$Prefix."_Type"}}=(
13361 "Old_Value"=>$Type1{"Name"},
13362 "New_Value"=>$Type2{"Name"},
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +040013363 "Old_Size"=>$Type1{"Size"}*$BYTE_SIZE,
13364 "New_Size"=>$Type2{"Size"}*$BYTE_SIZE,
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013365 "InitialType_Type"=>$Type1_Pure{"Type"});
13366 }
13367 }
13368 }
13369 }
13370 }
13371 if($Type1_PLevel!=$Type2_PLevel)
13372 {
13373 if($Type1{"Name"} ne "void" and $Type1{"Name"} ne "..."
13374 and $Type2{"Name"} ne "void" and $Type2{"Name"} ne "...")
13375 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040013376 if($Level eq "Source")
13377 {
13378 %{$LocalProblems{$Prefix."_PointerLevel"}}=(
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013379 "Old_Value"=>$Type1_PLevel,
13380 "New_Value"=>$Type2_PLevel);
13381 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040013382 else
13383 {
13384 if($Type2_PLevel>$Type1_PLevel) {
13385 %{$LocalProblems{$Prefix."_PointerLevel_Increased"}}=(
13386 "Old_Value"=>$Type1_PLevel,
13387 "New_Value"=>$Type2_PLevel);
13388 }
13389 else {
13390 %{$LocalProblems{$Prefix."_PointerLevel_Decreased"}}=(
13391 "Old_Value"=>$Type1_PLevel,
13392 "New_Value"=>$Type2_PLevel);
13393 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013394 }
13395 }
13396 }
13397 if($Type1_Pure{"Type"} eq "Array")
13398 { # base_type[N] -> base_type[N]
13399 # base_type: older_structure -> typedef to newer_structure
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040013400 my %SubProblems = detectTypeChange($Type1_Base{"Tid"}, $Type2_Base{"Tid"}, $Prefix, $Level);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013401 foreach my $SubProblemType (keys(%SubProblems))
13402 {
13403 $SubProblemType=~s/_Type/_BaseType/g;
13404 next if(defined $LocalProblems{$SubProblemType});
13405 foreach my $Attr (keys(%{$SubProblems{$SubProblemType}})) {
13406 $LocalProblems{$SubProblemType}{$Attr} = $SubProblems{$SubProblemType}{$Attr};
13407 }
13408 }
13409 }
13410 return %LocalProblems;
13411}
13412
13413sub tNameLock($$)
13414{
13415 my ($Tid1, $Tid2) = @_;
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040013416 my $Changed = 0;
13417 if(differentDumps("G"))
13418 { # different GCC versions
13419 $Changed = 1;
13420 }
13421 elsif(differentDumps("V"))
13422 { # different versions of ABI dumps
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040013423 if(not checkDump(1, "2.13")
13424 or not checkDump(2, "2.13"))
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040013425 { # latest names update
13426 # 2.6: added restrict qualifier
13427 # 2.13: added missed typedefs to qualified types
13428 $Changed = 1;
13429 }
13430 }
13431 if($Changed)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013432 { # different formats
13433 if($UseOldDumps)
13434 { # old dumps
13435 return 0;
13436 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040013437 my $TN1 = $TypeInfo{1}{$Tid1}{"Name"};
13438 my $TN2 = $TypeInfo{2}{$Tid2}{"Name"};
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040013439
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040013440 my $TT1 = $TypeInfo{1}{$Tid1}{"Type"};
13441 my $TT2 = $TypeInfo{2}{$Tid2}{"Type"};
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040013442
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040013443 my %Base1 = get_Type($Tid1, 1);
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040013444 while(defined $Base1{"Type"} and $Base1{"Type"} eq "Typedef") {
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +040013445 %Base1 = get_OneStep_BaseType($Base1{"Tid"}, $TypeInfo{1});
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013446 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040013447 my %Base2 = get_Type($Tid2, 2);
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040013448 while(defined $Base2{"Type"} and $Base2{"Type"} eq "Typedef") {
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +040013449 %Base2 = get_OneStep_BaseType($Base2{"Tid"}, $TypeInfo{2});
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013450 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +040013451 my $BName1 = uncover_typedefs($Base1{"Name"}, 1);
13452 my $BName2 = uncover_typedefs($Base2{"Name"}, 2);
13453 if($BName1 eq $BName2)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013454 { # equal base types
13455 return 0;
13456 }
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040013457
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040013458 if(not checkDump(1, "2.13")
13459 or not checkDump(2, "2.13"))
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040013460 { # broken array names in ABI dumps < 2.13
13461 if($TT1 eq "Array"
13462 and $TT2 eq "Array")
13463 {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013464 return 0;
13465 }
13466 }
13467
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040013468 if(not checkDump(1, "2.6")
13469 or not checkDump(2, "2.6"))
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040013470 { # added restrict attribute in 2.6
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040013471 if($TN1!~/\brestrict\b/
13472 and $TN2=~/\brestrict\b/)
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040013473 {
13474 return 0;
13475 }
13476 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013477 }
13478 return 1;
13479}
13480
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040013481sub differentDumps($)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013482{
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040013483 my $Check = $_[0];
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +040013484 if(defined $Cache{"differentDumps"}{$Check}) {
13485 return $Cache{"differentDumps"}{$Check};
13486 }
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040013487 if($UsedDump{1}{"V"} and $UsedDump{2}{"V"})
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040013488 {
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040013489 if($Check eq "G")
13490 {
13491 if(getGccVersion(1) ne getGccVersion(2))
13492 { # different GCC versions
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +040013493 return ($Cache{"differentDumps"}{$Check}=1);
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040013494 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040013495 }
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040013496 if($Check eq "V")
13497 {
13498 if(cmpVersions(formatVersion($UsedDump{1}{"V"}, 2),
13499 formatVersion($UsedDump{2}{"V"}, 2))!=0)
13500 { # different dump versions (skip micro version)
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +040013501 return ($Cache{"differentDumps"}{$Check}=1);
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040013502 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040013503 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013504 }
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +040013505 return ($Cache{"differentDumps"}{$Check}=0);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013506}
13507
13508sub formatVersion($$)
13509{ # cut off version digits
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040013510 my ($V, $Digits) = @_;
13511 my @Elems = split(/\./, $V);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013512 return join(".", splice(@Elems, 0, $Digits));
13513}
13514
13515sub htmlSpecChars($)
13516{
13517 my $Str = $_[0];
Andrey Ponomarenko5c09ef32012-06-14 18:17:33 +040013518 if(not $Str) {
13519 return $Str;
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040013520 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013521 $Str=~s/\&([^#]|\Z)/&amp;$1/g;
13522 $Str=~s/</&lt;/g;
13523 $Str=~s/\-\>/&#45;&gt;/g; # &minus;
13524 $Str=~s/>/&gt;/g;
13525 $Str=~s/([^ ])( )([^ ])/$1\@ALONE_SP\@$3/g;
13526 $Str=~s/ /&#160;/g; # &nbsp;
13527 $Str=~s/\@ALONE_SP\@/ /g;
13528 $Str=~s/\n/<br\/>/g;
13529 $Str=~s/\"/&quot;/g;
13530 $Str=~s/\'/&#39;/g;
13531 return $Str;
13532}
13533
Andrey Ponomarenko5c09ef32012-06-14 18:17:33 +040013534sub xmlSpecChars($)
13535{
13536 my $Str = $_[0];
13537 if(not $Str) {
13538 return $Str;
13539 }
13540
13541 $Str=~s/\&([^#]|\Z)/&amp;$1/g;
13542 $Str=~s/</&lt;/g;
13543 $Str=~s/>/&gt;/g;
13544
13545 $Str=~s/\"/&quot;/g;
13546 $Str=~s/\'/&#39;/g;
13547
13548 return $Str;
13549}
13550
Andrey Ponomarenko01117f12012-06-26 12:23:02 +040013551sub xmlSpecChars_R($)
13552{
13553 my $Str = $_[0];
13554 if(not $Str) {
13555 return $Str;
13556 }
13557
13558 $Str=~s/&amp;/&/g;
13559 $Str=~s/&lt;/</g;
13560 $Str=~s/&gt;/>/g;
13561
13562 $Str=~s/&quot;/"/g;
13563 $Str=~s/&#39;/'/g;
13564
13565 return $Str;
13566}
13567
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013568sub black_name($)
13569{
13570 my $Name = $_[0];
13571 return "<span class='iname_b'>".highLight_Signature($Name)."</span>";
13572}
13573
13574sub highLight_Signature($)
13575{
13576 my $Signature = $_[0];
13577 return highLight_Signature_PPos_Italic($Signature, "", 0, 0, 0);
13578}
13579
13580sub highLight_Signature_Italic_Color($)
13581{
13582 my $Signature = $_[0];
13583 return highLight_Signature_PPos_Italic($Signature, "", 1, 1, 1);
13584}
13585
13586sub separate_symbol($)
13587{
13588 my $Symbol = $_[0];
13589 my ($Name, $Spec, $Ver) = ($Symbol, "", "");
13590 if($Symbol=~/\A([^\@\$\?]+)([\@\$]+)([^\@\$]+)\Z/) {
13591 ($Name, $Spec, $Ver) = ($1, $2, $3);
13592 }
13593 return ($Name, $Spec, $Ver);
13594}
13595
13596sub cut_f_attrs($)
13597{
13598 if($_[0]=~s/(\))((| (const volatile|const|volatile))(| \[static\]))\Z/$1/) {
13599 return $2;
13600 }
13601 return "";
13602}
13603
13604sub highLight_Signature_PPos_Italic($$$$$)
13605{
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040013606 my ($FullSignature, $Param_Pos, $ItalicParams, $ColorParams, $ShowReturn) = @_;
13607 $Param_Pos = "" if(not defined $Param_Pos);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013608 if($CheckObjectsOnly) {
13609 $ItalicParams=$ColorParams=0;
13610 }
13611 my ($Signature, $VersionSpec, $SymbolVersion) = separate_symbol($FullSignature);
13612 my $Return = "";
13613 if($ShowRetVal and $Signature=~s/([^:]):([^:].+?)\Z/$1/g) {
13614 $Return = $2;
13615 }
Andrey Ponomarenko16934472012-03-29 15:37:04 +040013616 my $SCenter = find_center($Signature, "(");
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013617 if(not $SCenter)
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040013618 { # global data
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013619 $Signature = htmlSpecChars($Signature);
13620 $Signature=~s!(\[data\])!<span style='color:Black;font-weight:normal;'>$1</span>!g;
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040013621 $Signature .= (($SymbolVersion)?"<span class='sym_ver'>&#160;$VersionSpec&#160;$SymbolVersion</span>":"");
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013622 if($Return and $ShowReturn) {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040013623 $Signature .= "<span class='sym_p nowrap'> &#160;<b>:</b>&#160;&#160;".htmlSpecChars($Return)."</span>";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013624 }
13625 return $Signature;
13626 }
13627 my ($Begin, $End) = (substr($Signature, 0, $SCenter), "");
13628 $Begin.=" " if($Begin!~/ \Z/);
13629 $End = cut_f_attrs($Signature);
13630 my @Parts = ();
Andrey Ponomarenko07aea072012-11-12 16:15:07 +040013631 my ($Short, $Params) = split_Signature($Signature);
13632 my @SParts = separate_Params($Params, 1, 1);
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040013633 foreach my $Pos (0 .. $#SParts)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013634 {
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040013635 my $Part = $SParts[$Pos];
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013636 $Part=~s/\A\s+|\s+\Z//g;
13637 my ($Part_Styled, $ParamName) = (htmlSpecChars($Part), "");
13638 if($Part=~/\([\*]+(\w+)\)/i) {
13639 $ParamName = $1;#func-ptr
13640 }
13641 elsif($Part=~/(\w+)[\,\)]*\Z/i) {
13642 $ParamName = $1;
13643 }
13644 if(not $ParamName) {
13645 push(@Parts, $Part_Styled);
13646 next;
13647 }
13648 if($ItalicParams and not $TName_Tid{1}{$Part}
13649 and not $TName_Tid{2}{$Part})
13650 {
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040013651 my $Style = "param";
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040013652 if($Param_Pos ne ""
13653 and $Pos==$Param_Pos) {
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040013654 $Style = "focus_p";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013655 }
13656 elsif($ColorParams) {
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040013657 $Style = "color_p";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013658 }
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040013659 $Part_Styled =~ s!(\W)$ParamName([\,\)]|\Z)!$1<span class=\'$Style\'>$ParamName</span>$2!ig;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013660 }
13661 $Part_Styled=~s/,(\w)/, $1/g;
13662 push(@Parts, $Part_Styled);
13663 }
13664 if(@Parts)
13665 {
13666 foreach my $Num (0 .. $#Parts)
13667 {
13668 if($Num==$#Parts)
13669 { # add ")" to the last parameter
13670 $Parts[$Num] = "<span class='nowrap'>".$Parts[$Num]." )</span>";
13671 }
13672 elsif(length($Parts[$Num])<=45) {
13673 $Parts[$Num] = "<span class='nowrap'>".$Parts[$Num]."</span>";
13674 }
13675 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040013676 $Signature = htmlSpecChars($Begin)."<span class='sym_p'>(&#160;".join(" ", @Parts)."</span>".$End;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013677 }
13678 else {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040013679 $Signature = htmlSpecChars($Begin)."<span class='sym_p'>(&#160;)</span>".$End;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013680 }
13681 if($Return and $ShowReturn) {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040013682 $Signature .= "<span class='sym_p nowrap'> &#160;<b>:</b>&#160;&#160;".htmlSpecChars($Return)."</span>";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013683 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040013684 $Signature=~s!\[\]![&#160;]!g;
13685 $Signature=~s!operator=!operator&#160;=!g;
13686 $Signature=~s!(\[in-charge\]|\[not-in-charge\]|\[in-charge-deleting\]|\[static\])!<span class='sym_kind'>$1</span>!g;
13687 return $Signature.(($SymbolVersion)?"<span class='sym_ver'>&#160;$VersionSpec&#160;$SymbolVersion</span>":"");
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013688}
13689
Andrey Ponomarenko07aea072012-11-12 16:15:07 +040013690sub split_Signature($)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013691{
Andrey Ponomarenko07aea072012-11-12 16:15:07 +040013692 my $Signature = $_[0];
13693 if(my $ShortName = substr($Signature, 0, find_center($Signature, "(")))
13694 {
13695 $Signature=~s/\A\Q$ShortName\E\(//g;
13696 cut_f_attrs($Signature);
13697 $Signature=~s/\)\Z//;
13698 return ($ShortName, $Signature);
13699 }
13700
13701 # error
13702 return ($Signature, "");
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013703}
13704
Andrey Ponomarenko07aea072012-11-12 16:15:07 +040013705sub separate_Params($$$)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013706{
Andrey Ponomarenko07aea072012-11-12 16:15:07 +040013707 my ($Params, $Comma, $Sp) = @_;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013708 my @Parts = ();
Andrey Ponomarenko16934472012-03-29 15:37:04 +040013709 my %B = ( "("=>0, "<"=>0, ")"=>0, ">"=>0 );
13710 my $Part = 0;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013711 foreach my $Pos (0 .. length($Params) - 1)
13712 {
Andrey Ponomarenko16934472012-03-29 15:37:04 +040013713 my $S = substr($Params, $Pos, 1);
13714 if(defined $B{$S}) {
Andrey Ponomarenko07aea072012-11-12 16:15:07 +040013715 $B{$S} += 1;
Andrey Ponomarenko16934472012-03-29 15:37:04 +040013716 }
13717 if($S eq "," and
13718 $B{"("}==$B{")"} and $B{"<"}==$B{">"})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013719 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040013720 if($Comma)
13721 { # include comma
Andrey Ponomarenko16934472012-03-29 15:37:04 +040013722 $Parts[$Part] .= $S;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013723 }
Andrey Ponomarenko16934472012-03-29 15:37:04 +040013724 $Part += 1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013725 }
13726 else {
Andrey Ponomarenko16934472012-03-29 15:37:04 +040013727 $Parts[$Part] .= $S;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013728 }
13729 }
Andrey Ponomarenko07aea072012-11-12 16:15:07 +040013730 if(not $Sp)
13731 { # remove spaces
13732 foreach (@Parts)
13733 {
13734 s/\A //g;
13735 s/ \Z//g;
13736 }
13737 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013738 return @Parts;
13739}
13740
Andrey Ponomarenko16934472012-03-29 15:37:04 +040013741sub find_center($$)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013742{
13743 my ($Sign, $Target) = @_;
Andrey Ponomarenko16934472012-03-29 15:37:04 +040013744 my %B = ( "("=>0, "<"=>0, ")"=>0, ">"=>0 );
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013745 my $Center = 0;
Andrey Ponomarenko16934472012-03-29 15:37:04 +040013746 if($Sign=~s/(operator([^\w\s\(\)]+|\(\)))//g)
13747 { # operators
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013748 $Center+=length($1);
13749 }
13750 foreach my $Pos (0 .. length($Sign)-1)
13751 {
13752 my $S = substr($Sign, $Pos, 1);
13753 if($S eq $Target)
13754 {
13755 if($B{"("}==$B{")"}
13756 and $B{"<"}==$B{">"}) {
13757 return $Center;
13758 }
13759 }
13760 if(defined $B{$S}) {
13761 $B{$S}+=1;
13762 }
13763 $Center+=1;
13764 }
13765 return 0;
13766}
13767
13768sub appendFile($$)
13769{
13770 my ($Path, $Content) = @_;
13771 return if(not $Path);
13772 if(my $Dir = get_dirname($Path)) {
13773 mkpath($Dir);
13774 }
Andrey Ponomarenko16934472012-03-29 15:37:04 +040013775 open(FILE, ">>", $Path) || die ("can't open file \'$Path\': $!\n");
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013776 print FILE $Content;
13777 close(FILE);
13778}
13779
13780sub writeFile($$)
13781{
13782 my ($Path, $Content) = @_;
13783 return if(not $Path);
13784 if(my $Dir = get_dirname($Path)) {
13785 mkpath($Dir);
13786 }
Andrey Ponomarenko16934472012-03-29 15:37:04 +040013787 open(FILE, ">", $Path) || die ("can't open file \'$Path\': $!\n");
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013788 print FILE $Content;
13789 close(FILE);
13790}
13791
13792sub readFile($)
13793{
13794 my $Path = $_[0];
13795 return "" if(not $Path or not -f $Path);
Andrey Ponomarenko16934472012-03-29 15:37:04 +040013796 open(FILE, $Path);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013797 local $/ = undef;
13798 my $Content = <FILE>;
13799 close(FILE);
Andrey Ponomarenko85043792012-05-14 16:48:07 +040013800 if($Path!~/\.(tu|class|abi)\Z/) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013801 $Content=~s/\r/\n/g;
13802 }
13803 return $Content;
13804}
13805
13806sub get_filename($)
13807{ # much faster than basename() from File::Basename module
Andrey Ponomarenko85043792012-05-14 16:48:07 +040013808 if(defined $Cache{"get_filename"}{$_[0]}) {
13809 return $Cache{"get_filename"}{$_[0]};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013810 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +040013811 if($_[0] and $_[0]=~/([^\/\\]+)[\/\\]*\Z/) {
13812 return ($Cache{"get_filename"}{$_[0]}=$1);
13813 }
13814 return ($Cache{"get_filename"}{$_[0]}="");
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013815}
13816
13817sub get_dirname($)
13818{ # much faster than dirname() from File::Basename module
Andrey Ponomarenko85043792012-05-14 16:48:07 +040013819 if(defined $Cache{"get_dirname"}{$_[0]}) {
13820 return $Cache{"get_dirname"}{$_[0]};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013821 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +040013822 if($_[0] and $_[0]=~/\A(.*?)[\/\\]+[^\/\\]*[\/\\]*\Z/) {
13823 return ($Cache{"get_dirname"}{$_[0]}=$1);
13824 }
13825 return ($Cache{"get_dirname"}{$_[0]}="");
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013826}
13827
13828sub separate_path($) {
13829 return (get_dirname($_[0]), get_filename($_[0]));
13830}
13831
13832sub esc($)
13833{
13834 my $Str = $_[0];
13835 $Str=~s/([()\[\]{}$ &'"`;,<>\+])/\\$1/g;
13836 return $Str;
13837}
13838
13839sub readLineNum($$)
13840{
13841 my ($Path, $Num) = @_;
13842 return "" if(not $Path or not -f $Path);
Andrey Ponomarenko16934472012-03-29 15:37:04 +040013843 open(FILE, $Path);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013844 foreach (1 ... $Num) {
13845 <FILE>;
13846 }
13847 my $Line = <FILE>;
13848 close(FILE);
13849 return $Line;
13850}
13851
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040013852sub readAttributes($$)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013853{
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040013854 my ($Path, $Num) = @_;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013855 return () if(not $Path or not -f $Path);
13856 my %Attributes = ();
Andrey Ponomarenko85043792012-05-14 16:48:07 +040013857 if(readLineNum($Path, $Num)=~/<!--\s+(.+)\s+-->/)
13858 {
13859 foreach my $AttrVal (split(/;/, $1))
13860 {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013861 if($AttrVal=~/(.+):(.+)/)
13862 {
13863 my ($Name, $Value) = ($1, $2);
13864 $Attributes{$Name} = $Value;
13865 }
13866 }
13867 }
13868 return \%Attributes;
13869}
13870
13871sub is_abs($) {
13872 return ($_[0]=~/\A(\/|\w+:[\/\\])/);
13873}
13874
13875sub get_abs_path($)
13876{ # abs_path() should NOT be called for absolute inputs
13877 # because it can change them
13878 my $Path = $_[0];
13879 if(not is_abs($Path)) {
13880 $Path = abs_path($Path);
13881 }
13882 return $Path;
13883}
13884
13885sub get_OSgroup()
13886{
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +040013887 my $N = $Config{"osname"};
13888 if($N=~/macos|darwin|rhapsody/i) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013889 return "macos";
13890 }
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +040013891 elsif($N=~/freebsd|openbsd|netbsd/i) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013892 return "bsd";
13893 }
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +040013894 elsif($N=~/haiku|beos/i) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013895 return "beos";
13896 }
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +040013897 elsif($N=~/symbian|epoc/i) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013898 return "symbian";
13899 }
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +040013900 elsif($N=~/win/i) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013901 return "windows";
13902 }
13903 else {
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +040013904 return $N;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013905 }
13906}
13907
13908sub getGccVersion($)
13909{
13910 my $LibVersion = $_[0];
13911 if($GCC_VERSION{$LibVersion})
13912 { # dump version
13913 return $GCC_VERSION{$LibVersion};
13914 }
13915 elsif($UsedDump{$LibVersion}{"V"})
13916 { # old-version dumps
13917 return "unknown";
13918 }
13919 my $GccVersion = get_dumpversion($GCC_PATH); # host version
13920 if(not $GccVersion) {
13921 return "unknown";
13922 }
13923 return $GccVersion;
13924}
13925
13926sub showArch($)
13927{
13928 my $Arch = $_[0];
13929 if($Arch eq "arm"
13930 or $Arch eq "mips") {
13931 return uc($Arch);
13932 }
13933 return $Arch;
13934}
13935
13936sub getArch($)
13937{
13938 my $LibVersion = $_[0];
13939 if($CPU_ARCH{$LibVersion})
13940 { # dump version
13941 return $CPU_ARCH{$LibVersion};
13942 }
13943 elsif($UsedDump{$LibVersion}{"V"})
13944 { # old-version dumps
13945 return "unknown";
13946 }
13947 if(defined $Cache{"getArch"}{$LibVersion}) {
13948 return $Cache{"getArch"}{$LibVersion};
13949 }
13950 my $Arch = get_dumpmachine($GCC_PATH); # host version
13951 if(not $Arch) {
13952 return "unknown";
13953 }
13954 if($Arch=~/\A([\w]{3,})(-|\Z)/) {
13955 $Arch = $1;
13956 }
13957 $Arch = "x86" if($Arch=~/\Ai[3-7]86\Z/);
13958 if($OSgroup eq "windows") {
13959 $Arch = "x86" if($Arch=~/win32|mingw32/i);
13960 $Arch = "x86_64" if($Arch=~/win64|mingw64/i);
13961 }
13962 $Cache{"getArch"}{$LibVersion} = $Arch;
13963 return $Arch;
13964}
13965
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040013966sub get_Report_Header($)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013967{
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040013968 my $Level = $_[0];
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013969 my $ArchInfo = " on <span style='color:Blue;'>".showArch(getArch(1))."</span>";
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040013970 if(getArch(1) ne getArch(2)
13971 or getArch(1) eq "unknown"
13972 or $Level eq "Source")
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013973 { # don't show architecture in the header
13974 $ArchInfo="";
13975 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040013976 my $Report_Header = "<h1><span class='nowrap'>";
13977 if($Level eq "Source") {
13978 $Report_Header .= "Source compatibility";
13979 }
13980 elsif($Level eq "Binary") {
13981 $Report_Header .= "Binary compatibility";
13982 }
13983 else {
13984 $Report_Header .= "API compatibility";
13985 }
13986 $Report_Header .= " report for the <span style='color:Blue;'>$TargetLibraryFName</span> $TargetComponent</span>";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013987 $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>";
13988 if($AppPath) {
13989 $Report_Header .= " <span class='nowrap'>&#160;(relating to the portability of application <span style='color:Blue;'>".get_filename($AppPath)."</span>)</span>";
13990 }
13991 $Report_Header .= "</h1>\n";
13992 return $Report_Header;
13993}
13994
13995sub get_SourceInfo()
13996{
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040013997 my ($CheckedHeaders, $CheckedLibs) = ("", "");
13998 if(not $CheckObjectsOnly)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013999 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040014000 $CheckedHeaders = "<a name='Headers'></a><h2>Header Files (".keys(%{$Registered_Headers{1}}).")</h2><hr/>\n";
14001 $CheckedHeaders .= "<div class='h_list'>\n";
14002 foreach my $Header_Path (sort {lc($Registered_Headers{1}{$a}{"Identity"}) cmp lc($Registered_Headers{1}{$b}{"Identity"})} keys(%{$Registered_Headers{1}}))
14003 {
14004 my $Identity = $Registered_Headers{1}{$Header_Path}{"Identity"};
14005 my $Header_Name = get_filename($Identity);
14006 my $Dest_Comment = ($Identity=~/[\/\\]/)?" ($Identity)":"";
14007 $CheckedHeaders .= $Header_Name.$Dest_Comment."<br/>\n";
14008 }
14009 $CheckedHeaders .= "</div>\n";
14010 $CheckedHeaders .= "<br/>$TOP_REF<br/>\n";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014011 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040014012 if(not $CheckHeadersOnly)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014013 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040014014 $CheckedLibs = "<a name='Libs'></a><h2>".ucfirst($SLIB_TYPE)." Libraries (".keys(%{$Library_Symbol{1}}).")</h2><hr/>\n";
14015 $CheckedLibs .= "<div class='lib_list'>\n";
14016 foreach my $Library (sort {lc($a) cmp lc($b)} keys(%{$Library_Symbol{1}}))
14017 {
14018 $Library.=" (.$LIB_EXT)" if($Library!~/\.\w+\Z/);
14019 $CheckedLibs .= $Library."<br/>\n";
14020 }
14021 $CheckedLibs .= "</div>\n";
14022 $CheckedLibs .= "<br/>$TOP_REF<br/>\n";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014023 }
14024 return $CheckedHeaders.$CheckedLibs;
14025}
14026
14027sub get_TypeProblems_Count($$$)
14028{
14029 my ($TypeChanges, $TargetPriority, $Level) = @_;
14030 my $Type_Problems_Count = 0;
14031 foreach my $Type_Name (sort keys(%{$TypeChanges}))
14032 {
14033 my %Kinds_Target = ();
14034 foreach my $Kind (keys(%{$TypeChanges->{$Type_Name}}))
14035 {
14036 foreach my $Location (keys(%{$TypeChanges->{$Type_Name}{$Kind}}))
14037 {
14038 my $Target = $TypeChanges->{$Type_Name}{$Kind}{$Location}{"Target"};
14039 my $Priority = getProblemSeverity($Level, $Kind);
14040 next if($Priority ne $TargetPriority);
14041 if($Kinds_Target{$Kind}{$Target}) {
14042 next;
14043 }
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040014044 if(cmpSeverities($Type_MaxSeverity{$Level}{$Type_Name}{$Kind}{$Target}, $Priority))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014045 { # select a problem with the highest priority
14046 next;
14047 }
14048 $Kinds_Target{$Kind}{$Target} = 1;
14049 $Type_Problems_Count += 1;
14050 }
14051 }
14052 }
14053 return $Type_Problems_Count;
14054}
14055
14056sub get_Summary($)
14057{
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014058 my $Level = $_[0];
14059 my ($Added, $Removed, $I_Problems_High, $I_Problems_Medium, $I_Problems_Low, $T_Problems_High,
14060 $C_Problems_Low, $T_Problems_Medium, $T_Problems_Low, $I_Other, $T_Other) = (0,0,0,0,0,0,0,0,0,0,0);
14061 %{$RESULT{$Level}} = (
14062 "Problems"=>0,
14063 "Warnings"=>0,
14064 "Affected"=>0 );
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014065 # check rules
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014066 foreach my $Interface (sort keys(%{$CompatProblems{$Level}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014067 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014068 foreach my $Kind (keys(%{$CompatProblems{$Level}{$Interface}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014069 {
14070 if(not defined $CompatRules{$Level}{$Kind})
14071 { # unknown rule
14072 if(not $UnknownRules{$Level}{$Kind})
14073 { # only one warning
14074 printMsg("WARNING", "unknown rule \"$Kind\" (\"$Level\")");
14075 $UnknownRules{$Level}{$Kind}=1;
14076 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014077 delete($CompatProblems{$Level}{$Interface}{$Kind});
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014078 }
14079 }
14080 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014081 foreach my $Interface (sort keys(%{$CompatProblems{$Level}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014082 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014083 foreach my $Kind (sort keys(%{$CompatProblems{$Level}{$Interface}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014084 {
14085 if($CompatRules{$Level}{$Kind}{"Kind"} eq "Symbols")
14086 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014087 foreach my $Location (sort keys(%{$CompatProblems{$Level}{$Interface}{$Kind}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014088 {
14089 my $Priority = getProblemSeverity($Level, $Kind);
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014090 if($Kind eq "Added_Symbol") {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014091 $Added += 1;
14092 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014093 elsif($Kind eq "Removed_Symbol")
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014094 {
14095 $Removed += 1;
14096 $TotalAffected{$Level}{$Interface} = $Priority;
14097 }
14098 else
14099 {
14100 if($Priority eq "Safe") {
14101 $I_Other += 1;
14102 }
14103 elsif($Priority eq "High") {
14104 $I_Problems_High += 1;
14105 }
14106 elsif($Priority eq "Medium") {
14107 $I_Problems_Medium += 1;
14108 }
14109 elsif($Priority eq "Low") {
14110 $I_Problems_Low += 1;
14111 }
14112 if(($Priority ne "Low" or $StrictCompat)
14113 and $Priority ne "Safe") {
14114 $TotalAffected{$Level}{$Interface} = $Priority;
14115 }
14116 }
14117 }
14118 }
14119 }
14120 }
14121 my %TypeChanges = ();
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014122 foreach my $Interface (sort keys(%{$CompatProblems{$Level}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014123 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014124 foreach my $Kind (keys(%{$CompatProblems{$Level}{$Interface}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014125 {
14126 if($CompatRules{$Level}{$Kind}{"Kind"} eq "Types")
14127 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014128 foreach my $Location (sort {cmp_locations($b, $a)} sort keys(%{$CompatProblems{$Level}{$Interface}{$Kind}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014129 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014130 my $Type_Name = $CompatProblems{$Level}{$Interface}{$Kind}{$Location}{"Type_Name"};
14131 my $Target = $CompatProblems{$Level}{$Interface}{$Kind}{$Location}{"Target"};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014132 my $Priority = getProblemSeverity($Level, $Kind);
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040014133 if(cmpSeverities($Type_MaxSeverity{$Level}{$Type_Name}{$Kind}{$Target}, $Priority))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014134 { # select a problem with the highest priority
14135 next;
14136 }
14137 if(($Priority ne "Low" or $StrictCompat)
14138 and $Priority ne "Safe") {
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040014139 $TotalAffected{$Level}{$Interface} = maxSeverity($TotalAffected{$Level}{$Interface}, $Priority);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014140 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014141 %{$TypeChanges{$Type_Name}{$Kind}{$Location}} = %{$CompatProblems{$Level}{$Interface}{$Kind}{$Location}};
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040014142 $Type_MaxSeverity{$Level}{$Type_Name}{$Kind}{$Target} = maxSeverity($Type_MaxSeverity{$Level}{$Type_Name}{$Kind}{$Target}, $Priority);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014143 }
14144 }
14145 }
14146 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014147
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014148 $T_Problems_High = get_TypeProblems_Count(\%TypeChanges, "High", $Level);
14149 $T_Problems_Medium = get_TypeProblems_Count(\%TypeChanges, "Medium", $Level);
14150 $T_Problems_Low = get_TypeProblems_Count(\%TypeChanges, "Low", $Level);
14151 $T_Other = get_TypeProblems_Count(\%TypeChanges, "Safe", $Level);
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014152
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014153 if($CheckObjectsOnly)
14154 { # only removed exported symbols
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014155 $RESULT{$Level}{"Affected"} = $Removed*100/keys(%{$Symbol_Library{1}});
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014156 }
14157 else
14158 { # changed and removed public symbols
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014159 my $SCount = keys(%{$CheckedSymbols{$Level}});
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014160 if($ExtendedCheck)
14161 { # don't count external_func_0 for constants
14162 $SCount-=1;
14163 }
14164 if($SCount)
14165 {
14166 my %Weight = (
14167 "High" => 100,
14168 "Medium" => 50,
14169 "Low" => 25
14170 );
14171 foreach (keys(%{$TotalAffected{$Level}})) {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014172 $RESULT{$Level}{"Affected"}+=$Weight{$TotalAffected{$Level}{$_}};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014173 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014174 $RESULT{$Level}{"Affected"} = $RESULT{$Level}{"Affected"}/$SCount;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014175 }
14176 else {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014177 $RESULT{$Level}{"Affected"} = 0;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014178 }
14179 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014180 $RESULT{$Level}{"Affected"} = show_number($RESULT{$Level}{"Affected"});
14181 if($RESULT{$Level}{"Affected"}>=100) {
14182 $RESULT{$Level}{"Affected"} = 100;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014183 }
14184
Andrey Ponomarenko85043792012-05-14 16:48:07 +040014185 $RESULT{$Level}{"Problems"} += $Removed;
14186 $RESULT{$Level}{"Problems"} += $T_Problems_High + $I_Problems_High;
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014187 $RESULT{$Level}{"Problems"} += $T_Problems_Medium + $I_Problems_Medium;
Andrey Ponomarenko85043792012-05-14 16:48:07 +040014188 if($StrictCompat) {
14189 $RESULT{$Level}{"Problems"} += $T_Problems_Low + $I_Problems_Low;
14190 }
14191 else {
14192 $RESULT{$Level}{"Warnings"} += $T_Problems_Low + $I_Problems_Low;
14193 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014194
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014195 if($C_Problems_Low = keys(%{$ProblemsWithConstants{$Level}}))
14196 {
Andrey Ponomarenko85043792012-05-14 16:48:07 +040014197 if(defined $CompatRules{$Level}{"Changed_Constant"})
14198 {
14199 if($StrictCompat) {
14200 $RESULT{$Level}{"Problems"} += $C_Problems_Low;
14201 }
14202 else {
14203 $RESULT{$Level}{"Warnings"} += $C_Problems_Low;
14204 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014205 }
14206 else
14207 {
14208 printMsg("WARNING", "unknown rule \"Changed_Constant\" (\"$Level\")");
14209 $C_Problems_Low = 0;
14210 }
14211 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +040014212 if($CheckImpl and $Level eq "Binary")
14213 {
14214 if($StrictCompat) {
14215 $RESULT{$Level}{"Problems"} += keys(%ImplProblems);
14216 }
14217 else {
14218 $RESULT{$Level}{"Warnings"} += keys(%ImplProblems);
14219 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014220 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +040014221 if($RESULT{$Level}{"Problems"}
14222 and $RESULT{$Level}{"Affected"}) {
14223 $RESULT{$Level}{"Verdict"} = "incompatible";
14224 }
14225 else {
14226 $RESULT{$Level}{"Verdict"} = "compatible";
14227 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014228
14229 my $TotalTypes = keys(%{$CheckedTypes{$Level}});
14230 if(not $TotalTypes)
14231 { # list all the types
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014232 $TotalTypes = keys(%{$TName_Tid{1}});
14233 }
14234
14235 my ($Arch1, $Arch2) = (getArch(1), getArch(2));
14236 my ($GccV1, $GccV2) = (getGccVersion(1), getGccVersion(2));
14237
14238 my ($TestInfo, $TestResults, $Problem_Summary) = ();
14239
14240 if($ReportFormat eq "xml")
14241 { # XML
14242 # test info
14243 $TestInfo .= " <library>$TargetLibraryName</library>\n";
14244 $TestInfo .= " <version1>\n";
14245 $TestInfo .= " <number>".$Descriptor{1}{"Version"}."</number>\n";
14246 $TestInfo .= " <architecture>$Arch1</architecture>\n";
14247 $TestInfo .= " <gcc>$GccV1</gcc>\n";
14248 $TestInfo .= " </version1>\n";
14249
14250 $TestInfo .= " <version2>\n";
14251 $TestInfo .= " <number>".$Descriptor{2}{"Version"}."</number>\n";
14252 $TestInfo .= " <architecture>$Arch2</architecture>\n";
14253 $TestInfo .= " <gcc>$GccV2</gcc>\n";
14254 $TestInfo .= " </version2>\n";
14255 $TestInfo = "<test_info>\n".$TestInfo."</test_info>\n\n";
14256
14257 # test results
14258 $TestResults .= " <headers>\n";
14259 foreach my $Name (sort {lc($Registered_Headers{1}{$a}{"Identity"}) cmp lc($Registered_Headers{1}{$b}{"Identity"})} keys(%{$Registered_Headers{1}}))
14260 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014261 my $Identity = $Registered_Headers{1}{$Name}{"Identity"};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014262 my $Comment = ($Identity=~/[\/\\]/)?" ($Identity)":"";
14263 $TestResults .= " <name>".get_filename($Name).$Comment."</name>\n";
14264 }
14265 $TestResults .= " </headers>\n";
14266
14267 $TestResults .= " <libs>\n";
14268 foreach my $Library (sort {lc($a) cmp lc($b)} keys(%{$Library_Symbol{1}}))
14269 {
14270 $Library.=" (.$LIB_EXT)" if($Library!~/\.\w+\Z/);
14271 $TestResults .= " <name>$Library</name>\n";
14272 }
14273 $TestResults .= " </libs>\n";
14274
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040014275 $TestResults .= " <symbols>".(keys(%{$CheckedSymbols{$Level}}) - keys(%ExtendedSymbols))."</symbols>\n";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014276 $TestResults .= " <types>".$TotalTypes."</types>\n";
14277
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014278 $TestResults .= " <verdict>".$RESULT{$Level}{"Verdict"}."</verdict>\n";
14279 $TestResults .= " <affected>".$RESULT{$Level}{"Affected"}."</affected>\n";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014280 $TestResults = "<test_results>\n".$TestResults."</test_results>\n\n";
14281
14282 # problem summary
14283 $Problem_Summary .= " <added_symbols>".$Added."</added_symbols>\n";
14284 $Problem_Summary .= " <removed_symbols>".$Removed."</removed_symbols>\n";
14285
14286 $Problem_Summary .= " <problems_with_types>\n";
14287 $Problem_Summary .= " <high>$T_Problems_High</high>\n";
14288 $Problem_Summary .= " <medium>$T_Problems_Medium</medium>\n";
14289 $Problem_Summary .= " <low>$T_Problems_Low</low>\n";
14290 $Problem_Summary .= " <safe>$T_Other</safe>\n";
14291 $Problem_Summary .= " </problems_with_types>\n";
14292
14293 $Problem_Summary .= " <problems_with_symbols>\n";
14294 $Problem_Summary .= " <high>$I_Problems_High</high>\n";
14295 $Problem_Summary .= " <medium>$I_Problems_Medium</medium>\n";
14296 $Problem_Summary .= " <low>$I_Problems_Low</low>\n";
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014297 $Problem_Summary .= " <safe>$I_Other</safe>\n";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014298 $Problem_Summary .= " </problems_with_symbols>\n";
14299
14300 $Problem_Summary .= " <problems_with_constants>\n";
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014301 $Problem_Summary .= " <low>$C_Problems_Low</low>\n";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014302 $Problem_Summary .= " </problems_with_constants>\n";
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014303 if($CheckImpl and $Level eq "Binary")
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014304 {
14305 $Problem_Summary .= " <impl>\n";
14306 $Problem_Summary .= " <low>".keys(%ImplProblems)."</low>\n";
14307 $Problem_Summary .= " </impl>\n";
14308 }
14309 $Problem_Summary = "<problem_summary>\n".$Problem_Summary."</problem_summary>\n\n";
14310
14311 return ($TestInfo.$TestResults.$Problem_Summary, "");
14312 }
14313 else
14314 { # HTML
14315 # test info
14316 $TestInfo = "<h2>Test Info</h2><hr/>\n";
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014317 $TestInfo .= "<table class='summary'>\n";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014318 $TestInfo .= "<tr><th>".ucfirst($TargetComponent)." Name</th><td>$TargetLibraryFName</td></tr>\n";
14319
14320 my (@VInf1, @VInf2, $AddTestInfo) = ();
14321 if($Arch1 ne "unknown"
14322 and $Arch2 ne "unknown")
14323 { # CPU arch
14324 if($Arch1 eq $Arch2)
14325 { # go to the separate section
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014326 $AddTestInfo .= "<tr><th>CPU Type</th><td>".showArch($Arch1)."</td></tr>\n";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014327 }
14328 else
14329 { # go to the version number
14330 push(@VInf1, showArch($Arch1));
14331 push(@VInf2, showArch($Arch2));
14332 }
14333 }
14334 if($GccV1 ne "unknown"
14335 and $GccV2 ne "unknown"
14336 and $OStarget ne "windows")
14337 { # GCC version
14338 if($GccV1 eq $GccV2)
14339 { # go to the separate section
14340 $AddTestInfo .= "<tr><th>GCC Version</th><td>$GccV1</td></tr>\n";
14341 }
14342 else
14343 { # go to the version number
14344 push(@VInf1, "gcc ".$GccV1);
14345 push(@VInf2, "gcc ".$GccV2);
14346 }
14347 }
14348 # show long version names with GCC version and CPU architecture name (if different)
14349 $TestInfo .= "<tr><th>Version #1</th><td>".$Descriptor{1}{"Version"}.(@VInf1?" (".join(", ", reverse(@VInf1)).")":"")."</td></tr>\n";
14350 $TestInfo .= "<tr><th>Version #2</th><td>".$Descriptor{2}{"Version"}.(@VInf2?" (".join(", ", reverse(@VInf2)).")":"")."</td></tr>\n";
14351 $TestInfo .= $AddTestInfo;
14352 #if($COMMON_LANGUAGE{1}) {
14353 # $TestInfo .= "<tr><th>Language</th><td>".$COMMON_LANGUAGE{1}."</td></tr>\n";
14354 #}
14355 if($ExtendedCheck) {
14356 $TestInfo .= "<tr><th>Mode</th><td>Extended</td></tr>\n";
14357 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014358 if($JoinReport)
14359 {
14360 if($Level eq "Binary") {
Andrey Ponomarenko16934472012-03-29 15:37:04 +040014361 $TestInfo .= "<tr><th>Subject</th><td width='150px'>Binary Compatibility</td></tr>\n"; # Run-time
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014362 }
14363 if($Level eq "Source") {
Andrey Ponomarenko16934472012-03-29 15:37:04 +040014364 $TestInfo .= "<tr><th>Subject</th><td width='150px'>Source Compatibility</td></tr>\n"; # Build-time
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014365 }
14366 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014367 $TestInfo .= "</table>\n";
14368
14369 # test results
14370 $TestResults = "<h2>Test Results</h2><hr/>\n";
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014371 $TestResults .= "<table class='summary'>";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014372
14373 my $Headers_Link = "0";
14374 $Headers_Link = "<a href='#Headers' style='color:Blue;'>".keys(%{$Registered_Headers{1}})."</a>" if(keys(%{$Registered_Headers{1}})>0);
14375 $TestResults .= "<tr><th>Total Header Files</th><td>".($CheckObjectsOnly?"0&#160;(not&#160;analyzed)":$Headers_Link)."</td></tr>\n";
14376
14377 if(not $ExtendedCheck)
14378 {
14379 my $Libs_Link = "0";
14380 $Libs_Link = "<a href='#Libs' style='color:Blue;'>".keys(%{$Library_Symbol{1}})."</a>" if(keys(%{$Library_Symbol{1}})>0);
14381 $TestResults .= "<tr><th>Total ".ucfirst($SLIB_TYPE)." Libraries</th><td>".($CheckHeadersOnly?"0&#160;(not&#160;analyzed)":$Libs_Link)."</td></tr>\n";
14382 }
14383
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040014384 $TestResults .= "<tr><th>Total Symbols / Types</th><td>".(keys(%{$CheckedSymbols{$Level}}) - keys(%ExtendedSymbols))." / ".$TotalTypes."</td></tr>\n";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014385
Andrey Ponomarenko85043792012-05-14 16:48:07 +040014386 my $META_DATA = "verdict:".$RESULT{$Level}{"Verdict"}.";";
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014387 if($JoinReport) {
14388 $META_DATA = "kind:".lc($Level).";".$META_DATA;
14389 }
Andrey Ponomarenko16934472012-03-29 15:37:04 +040014390 $TestResults .= "<tr><th>Verdict</th>";
Andrey Ponomarenko85043792012-05-14 16:48:07 +040014391 if($RESULT{$Level}{"Verdict"} eq "incompatible") {
Andrey Ponomarenko16934472012-03-29 15:37:04 +040014392 $TestResults .= "<td><span style='color:Red;'><b>Incompatible<br/>(".$RESULT{$Level}{"Affected"}."%)</b></span></td>";
14393 }
14394 else {
14395 $TestResults .= "<td><span style='color:Green;'><b>Compatible</b></span></td>";
14396 }
14397 $TestResults .= "</tr>\n";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014398 $TestResults .= "</table>\n";
14399
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014400 $META_DATA .= "affected:".$RESULT{$Level}{"Affected"}.";";# in percents
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014401 # problem summary
14402 $Problem_Summary = "<h2>Problem Summary</h2><hr/>\n";
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014403 $Problem_Summary .= "<table class='summary'>";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014404 $Problem_Summary .= "<tr><th></th><th style='text-align:center;'>Severity</th><th style='text-align:center;'>Count</th></tr>";
14405
14406 my $Added_Link = "0";
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014407 if($Added>0)
14408 {
14409 if($JoinReport) {
14410 $Added_Link = "<a href='#".$Level."_Added' style='color:Blue;'>$Added</a>";
14411 }
14412 else {
14413 $Added_Link = "<a href='#Added' style='color:Blue;'>$Added</a>";
14414 }
14415 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014416 $META_DATA .= "added:$Added;";
Andrey Ponomarenko16934472012-03-29 15:37:04 +040014417 $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 +040014418
14419 my $Removed_Link = "0";
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014420 if($Removed>0)
14421 {
14422 if($JoinReport) {
14423 $Removed_Link = "<a href='#".$Level."_Removed' style='color:Blue;'>$Removed</a>"
14424 }
14425 else {
14426 $Removed_Link = "<a href='#Removed' style='color:Blue;'>$Removed</a>"
14427 }
14428 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014429 $META_DATA .= "removed:$Removed;";
Andrey Ponomarenko16934472012-03-29 15:37:04 +040014430 $Problem_Summary .= "<tr><th>Removed Symbols</th>";
14431 $Problem_Summary .= "<td>High</td><td".getStyle("I", "R", $Removed).">$Removed_Link</td></tr>\n";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014432
14433 my $TH_Link = "0";
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014434 $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 +040014435 $TH_Link = "n/a" if($CheckObjectsOnly);
14436 $META_DATA .= "type_problems_high:$T_Problems_High;";
Andrey Ponomarenko16934472012-03-29 15:37:04 +040014437 $Problem_Summary .= "<tr><th rowspan='3'>Problems with<br/>Data Types</th>";
14438 $Problem_Summary .= "<td>High</td><td".getStyle("T", "H", $T_Problems_High).">$TH_Link</td></tr>\n";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014439
14440 my $TM_Link = "0";
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014441 $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 +040014442 $TM_Link = "n/a" if($CheckObjectsOnly);
14443 $META_DATA .= "type_problems_medium:$T_Problems_Medium;";
Andrey Ponomarenko16934472012-03-29 15:37:04 +040014444 $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 +040014445
14446 my $TL_Link = "0";
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014447 $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 +040014448 $TL_Link = "n/a" if($CheckObjectsOnly);
14449 $META_DATA .= "type_problems_low:$T_Problems_Low;";
Andrey Ponomarenko16934472012-03-29 15:37:04 +040014450 $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 +040014451
14452 my $IH_Link = "0";
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014453 $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 +040014454 $IH_Link = "n/a" if($CheckObjectsOnly);
14455 $META_DATA .= "interface_problems_high:$I_Problems_High;";
Andrey Ponomarenko16934472012-03-29 15:37:04 +040014456 $Problem_Summary .= "<tr><th rowspan='3'>Problems with<br/>Symbols</th>";
14457 $Problem_Summary .= "<td>High</td><td".getStyle("I", "H", $I_Problems_High).">$IH_Link</td></tr>\n";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014458
14459 my $IM_Link = "0";
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014460 $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 +040014461 $IM_Link = "n/a" if($CheckObjectsOnly);
14462 $META_DATA .= "interface_problems_medium:$I_Problems_Medium;";
Andrey Ponomarenko16934472012-03-29 15:37:04 +040014463 $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 +040014464
14465 my $IL_Link = "0";
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014466 $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 +040014467 $IL_Link = "n/a" if($CheckObjectsOnly);
14468 $META_DATA .= "interface_problems_low:$I_Problems_Low;";
Andrey Ponomarenko16934472012-03-29 15:37:04 +040014469 $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 +040014470
14471 my $ChangedConstants_Link = "0";
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014472 if(keys(%{$CheckedSymbols{$Level}}) and $C_Problems_Low)
14473 {
14474 if($JoinReport) {
14475 $ChangedConstants_Link = "<a href='#".$Level."_Changed_Constants' style='color:Blue;'>$C_Problems_Low</a>";
14476 }
14477 else {
14478 $ChangedConstants_Link = "<a href='#Changed_Constants' style='color:Blue;'>$C_Problems_Low</a>";
14479 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014480 }
14481 $ChangedConstants_Link = "n/a" if($CheckObjectsOnly);
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014482 $META_DATA .= "changed_constants:$C_Problems_Low;";
Andrey Ponomarenko16934472012-03-29 15:37:04 +040014483 $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 +040014484
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014485 if($CheckImpl and $Level eq "Binary")
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014486 {
14487 my $ChangedImpl_Link = "0";
14488 $ChangedImpl_Link = "<a href='#Changed_Implementation' style='color:Blue;'>".keys(%ImplProblems)."</a>" if(keys(%ImplProblems)>0);
14489 $ChangedImpl_Link = "n/a" if($CheckHeadersOnly);
14490 $META_DATA .= "changed_implementation:".keys(%ImplProblems).";";
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040014491 $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 +040014492 }
14493 # Safe Changes
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014494 if($T_Other and not $CheckObjectsOnly)
14495 {
14496 my $TS_Link = "<a href='#".get_Anchor("Type", $Level, "Safe")."' style='color:Blue;'>$T_Other</a>";
Andrey Ponomarenko16934472012-03-29 15:37:04 +040014497 $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 +040014498 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014499
14500 if($I_Other and not $CheckObjectsOnly)
14501 {
14502 my $IS_Link = "<a href='#".get_Anchor("Symbol", $Level, "Safe")."' style='color:Blue;'>$I_Other</a>";
Andrey Ponomarenko16934472012-03-29 15:37:04 +040014503 $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 +040014504 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014505
14506 $META_DATA .= "tool_version:$TOOL_VERSION";
14507 $Problem_Summary .= "</table>\n";
Andrey Ponomarenko16934472012-03-29 15:37:04 +040014508 # $TestInfo = getLegend().$TestInfo;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014509 return ($TestInfo.$TestResults.$Problem_Summary, $META_DATA);
14510 }
14511}
14512
Andrey Ponomarenko16934472012-03-29 15:37:04 +040014513sub getStyle($$$)
14514{
14515 my ($Subj, $Act, $Num) = @_;
14516 my %Style = (
14517 "A"=>"new",
14518 "R"=>"failed",
14519 "S"=>"passed",
14520 "L"=>"warning",
14521 "M"=>"failed",
14522 "H"=>"failed"
14523 );
14524 if($Num>0) {
14525 return " class='".$Style{$Act}."'";
14526 }
14527 return "";
14528}
14529
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014530sub show_number($)
14531{
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014532 if($_[0])
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014533 {
Andrey Ponomarenko16934472012-03-29 15:37:04 +040014534 my $Num = cut_off_number($_[0], 2, 0);
14535 if($Num eq "0")
14536 {
14537 foreach my $P (3 .. 7)
14538 {
14539 $Num = cut_off_number($_[0], $P, 1);
14540 if($Num ne "0") {
14541 last;
14542 }
14543 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014544 }
14545 if($Num eq "0") {
14546 $Num = $_[0];
14547 }
14548 return $Num;
14549 }
14550 return $_[0];
14551}
14552
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014553sub cut_off_number($$$)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014554{
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014555 my ($num, $digs_to_cut, $z) = @_;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014556 if($num!~/\./)
14557 {
14558 $num .= ".";
14559 foreach (1 .. $digs_to_cut-1) {
14560 $num .= "0";
14561 }
14562 }
14563 elsif($num=~/\.(.+)\Z/ and length($1)<$digs_to_cut-1)
14564 {
14565 foreach (1 .. $digs_to_cut - 1 - length($1)) {
14566 $num .= "0";
14567 }
14568 }
14569 elsif($num=~/\d+\.(\d){$digs_to_cut,}/) {
14570 $num=sprintf("%.".($digs_to_cut-1)."f", $num);
14571 }
14572 $num=~s/\.[0]+\Z//g;
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014573 if($z) {
14574 $num=~s/(\.[1-9]+)[0]+\Z/$1/g;
14575 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014576 return $num;
14577}
14578
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014579sub get_Report_ChangedConstants($)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014580{
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014581 my $Level = $_[0];
Andrey Ponomarenko16934472012-03-29 15:37:04 +040014582 my $CHANGED_CONSTANTS = "";
14583 my %ReportMap = ();
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014584 foreach my $Constant (keys(%{$ProblemsWithConstants{$Level}})) {
Andrey Ponomarenko16934472012-03-29 15:37:04 +040014585 $ReportMap{$Constants{1}{$Constant}{"Header"}}{$Constant} = 1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014586 }
14587 my $Kind = "Changed_Constant";
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014588 if(not defined $CompatRules{$Level}{$Kind}) {
14589 return "";
14590 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014591 if($ReportFormat eq "xml")
14592 { # XML
Andrey Ponomarenko16934472012-03-29 15:37:04 +040014593 foreach my $HeaderName (sort {lc($a) cmp lc($b)} keys(%ReportMap))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014594 {
14595 $CHANGED_CONSTANTS .= " <header name=\"$HeaderName\">\n";
Andrey Ponomarenko16934472012-03-29 15:37:04 +040014596 foreach my $Constant (sort {lc($a) cmp lc($b)} keys(%{$ReportMap{$HeaderName}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014597 {
14598 $CHANGED_CONSTANTS .= " <constant name=\"$Constant\">\n";
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014599 my $Change = $CompatRules{$Level}{$Kind}{"Change"};
14600 my $Effect = $CompatRules{$Level}{$Kind}{"Effect"};
14601 my $Overcome = $CompatRules{$Level}{$Kind}{"Overcome"};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014602 $CHANGED_CONSTANTS .= " <problem id=\"$Kind\">\n";
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014603 $CHANGED_CONSTANTS .= " <change".getXmlParams($Change, $ProblemsWithConstants{$Level}{$Constant}).">$Change</change>\n";
14604 $CHANGED_CONSTANTS .= " <effect".getXmlParams($Effect, $ProblemsWithConstants{$Level}{$Constant}).">$Effect</effect>\n";
14605 $CHANGED_CONSTANTS .= " <overcome".getXmlParams($Overcome, $ProblemsWithConstants{$Level}{$Constant}).">$Overcome</overcome>\n";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014606 $CHANGED_CONSTANTS .= " </problem>\n";
14607 $CHANGED_CONSTANTS .= " </constant>\n";
14608 }
14609 $CHANGED_CONSTANTS .= " </header>\n";
14610 }
14611 $CHANGED_CONSTANTS = "<problems_with_constants severity=\"Low\">\n".$CHANGED_CONSTANTS."</problems_with_constants>\n\n";
14612 }
14613 else
14614 { # HTML
14615 my $Number = 0;
Andrey Ponomarenko16934472012-03-29 15:37:04 +040014616 foreach my $HeaderName (sort {lc($a) cmp lc($b)} keys(%ReportMap))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014617 {
14618 $CHANGED_CONSTANTS .= "<span class='h_name'>$HeaderName</span><br/>\n";
Andrey Ponomarenko16934472012-03-29 15:37:04 +040014619 foreach my $Name (sort {lc($a) cmp lc($b)} keys(%{$ReportMap{$HeaderName}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014620 {
14621 $Number += 1;
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014622 my $Change = applyMacroses($Level, $Kind, $CompatRules{$Level}{$Kind}{"Change"}, $ProblemsWithConstants{$Level}{$Name});
14623 my $Effect = $CompatRules{$Level}{$Kind}{"Effect"};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014624 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 +040014625 $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 +040014626 $Report = $ContentSpanStart."<span class='extendable'>[+]</span> ".$Name.$ContentSpanEnd."<br/>\n".$Report;
14627 $CHANGED_CONSTANTS .= insertIDs($Report);
14628 }
14629 $CHANGED_CONSTANTS .= "<br/>\n";
14630 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014631 if($CHANGED_CONSTANTS)
14632 {
14633 my $Anchor = "<a name='Changed_Constants'></a>";
14634 if($JoinReport) {
14635 $Anchor = "<a name='".$Level."_Changed_Constants'></a>";
14636 }
14637 $CHANGED_CONSTANTS = $Anchor."<h2>Problems with Constants ($Number)</h2><hr/>\n".$CHANGED_CONSTANTS.$TOP_REF."<br/>\n";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014638 }
14639 }
14640 return $CHANGED_CONSTANTS;
14641}
14642
14643sub get_Report_Impl()
14644{
Andrey Ponomarenko16934472012-03-29 15:37:04 +040014645 my $CHANGED_IMPLEMENTATION = "";
14646 my %ReportMap = ();
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014647 foreach my $Interface (sort keys(%ImplProblems))
14648 {
14649 my $HeaderName = $CompleteSignature{1}{$Interface}{"Header"};
14650 my $DyLib = $Symbol_Library{1}{$Interface};
Andrey Ponomarenko16934472012-03-29 15:37:04 +040014651 $ReportMap{$HeaderName}{$DyLib}{$Interface} = 1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014652 }
14653 my $Changed_Number = 0;
Andrey Ponomarenko16934472012-03-29 15:37:04 +040014654 foreach my $HeaderName (sort {lc($a) cmp lc($b)} keys(%ReportMap))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014655 {
Andrey Ponomarenko16934472012-03-29 15:37:04 +040014656 foreach my $DyLib (sort {lc($a) cmp lc($b)} keys(%{$ReportMap{$HeaderName}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014657 {
14658 my $FDyLib=$DyLib.($DyLib!~/\.\w+\Z/?" (.$LIB_EXT)":"");
14659 if($HeaderName) {
14660 $CHANGED_IMPLEMENTATION .= "<span class='h_name'>$HeaderName</span>, <span class='lib_name'>$FDyLib</span><br/>\n";
14661 }
14662 else {
14663 $CHANGED_IMPLEMENTATION .= "<span class='lib_name'>$DyLib</span><br/>\n";
14664 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014665 my %NameSpaceSymbols = ();
Andrey Ponomarenko16934472012-03-29 15:37:04 +040014666 foreach my $Interface (keys(%{$ReportMap{$HeaderName}{$DyLib}})) {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014667 $NameSpaceSymbols{get_IntNameSpace($Interface, 2)}{$Interface} = 1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014668 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014669 foreach my $NameSpace (sort keys(%NameSpaceSymbols))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014670 {
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040014671 $CHANGED_IMPLEMENTATION .= ($NameSpace)?"<span class='ns_title'>namespace</span> <span class='ns'>$NameSpace</span><br/>\n":"";
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014672 my @SortedInterfaces = sort {lc(get_Signature($a, 1)) cmp lc(get_Signature($b, 1))} keys(%{$NameSpaceSymbols{$NameSpace}});
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014673 foreach my $Interface (@SortedInterfaces)
14674 {
14675 $Changed_Number += 1;
14676 my $Signature = get_Signature($Interface, 1);
14677 if($NameSpace) {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040014678 $Signature=~s/\b\Q$NameSpace\E::\b//g;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014679 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014680 $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 +040014681 }
14682 }
14683 $CHANGED_IMPLEMENTATION .= "<br/>\n";
14684 }
14685 }
14686 if($CHANGED_IMPLEMENTATION) {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014687 $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 +040014688 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +040014689
14690 # clean memory
14691 %ImplProblems = ();
14692
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014693 return $CHANGED_IMPLEMENTATION;
14694}
14695
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014696sub getTitle($$$)
14697{
14698 my ($Header, $Library, $NameSpace) = @_;
14699 my $Title = "";
14700 if($Library and $Library!~/\.\w+\Z/) {
14701 $Library .= " (.$LIB_EXT)";
14702 }
14703 if($Header and $Library)
14704 {
14705 $Title .= "<span class='h_name'>$Header</span>";
14706 $Title .= ", <span class='lib_name'>$Library</span><br/>\n";
14707 }
14708 elsif($Library) {
14709 $Title .= "<span class='lib_name'>$Library</span><br/>\n";
14710 }
14711 elsif($Header) {
14712 $Title .= "<span class='h_name'>$Header</span><br/>\n";
14713 }
14714 if($NameSpace) {
14715 $Title .= "<span class='ns_title'>namespace</span> <span class='ns'>$NameSpace</span><br/>\n";
14716 }
14717 return $Title;
14718}
14719
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014720sub get_Report_Added($)
14721{
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014722 my $Level = $_[0];
Andrey Ponomarenko16934472012-03-29 15:37:04 +040014723 my $ADDED_INTERFACES = "";
14724 my %ReportMap = ();
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014725 foreach my $Interface (sort keys(%{$CompatProblems{$Level}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014726 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014727 foreach my $Kind (sort keys(%{$CompatProblems{$Level}{$Interface}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014728 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014729 if($Kind eq "Added_Symbol")
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014730 {
14731 my $HeaderName = $CompleteSignature{2}{$Interface}{"Header"};
14732 my $DyLib = $Symbol_Library{2}{$Interface};
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014733 if($Level eq "Source" and $ReportFormat eq "html")
14734 { # do not show library name in HTML report
14735 $DyLib = "";
14736 }
14737 $ReportMap{$HeaderName}{$DyLib}{$Interface} = 1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014738 }
14739 }
14740 }
14741 if($ReportFormat eq "xml")
14742 { # XML
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014743 foreach my $HeaderName (sort {lc($a) cmp lc($b)} keys(%ReportMap))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014744 {
14745 $ADDED_INTERFACES .= " <header name=\"$HeaderName\">\n";
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014746 foreach my $DyLib (sort {lc($a) cmp lc($b)} keys(%{$ReportMap{$HeaderName}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014747 {
14748 $ADDED_INTERFACES .= " <library name=\"$DyLib\">\n";
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014749 foreach my $Interface (keys(%{$ReportMap{$HeaderName}{$DyLib}})) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014750 $ADDED_INTERFACES .= " <name>$Interface</name>\n";
14751 }
14752 $ADDED_INTERFACES .= " </library>\n";
14753 }
14754 $ADDED_INTERFACES .= " </header>\n";
14755 }
14756 $ADDED_INTERFACES = "<added_symbols>\n".$ADDED_INTERFACES."</added_symbols>\n\n";
14757 }
14758 else
14759 { # HTML
14760 my $Added_Number = 0;
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014761 foreach my $HeaderName (sort {lc($a) cmp lc($b)} keys(%ReportMap))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014762 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014763 foreach my $DyLib (sort {lc($a) cmp lc($b)} keys(%{$ReportMap{$HeaderName}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014764 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014765 my %NameSpaceSymbols = ();
14766 foreach my $Interface (keys(%{$ReportMap{$HeaderName}{$DyLib}})) {
14767 $NameSpaceSymbols{get_IntNameSpace($Interface, 2)}{$Interface} = 1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014768 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014769 foreach my $NameSpace (sort keys(%NameSpaceSymbols))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014770 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014771 $ADDED_INTERFACES .= getTitle($HeaderName, $DyLib, $NameSpace);
14772 my @SortedInterfaces = sort {lc(get_Signature($a, 2)) cmp lc(get_Signature($b, 2))} keys(%{$NameSpaceSymbols{$NameSpace}});
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014773 foreach my $Interface (@SortedInterfaces)
14774 {
14775 $Added_Number += 1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014776 my $Signature = get_Signature($Interface, 2);
14777 if($NameSpace) {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040014778 $Signature=~s/\b\Q$NameSpace\E::\b//g;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014779 }
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040014780 if($Interface=~/\A(_Z|\?)/)
14781 {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014782 if($Signature) {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014783 $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 +040014784 }
14785 else {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014786 $ADDED_INTERFACES .= "<span class=\"iname\">".$Interface."</span><br/>\n";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014787 }
14788 }
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040014789 else
14790 {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014791 if($Signature) {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014792 $ADDED_INTERFACES .= "<span class=\"iname\">".highLight_Signature_Italic_Color($Signature)."</span><br/>\n";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014793 }
14794 else {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014795 $ADDED_INTERFACES .= "<span class=\"iname\">".$Interface."</span><br/>\n";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014796 }
14797 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014798 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014799 $ADDED_INTERFACES .= "<br/>\n";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014800 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014801 }
14802 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014803 if($ADDED_INTERFACES)
14804 {
14805 my $Anchor = "<a name='Added'></a>";
14806 if($JoinReport) {
14807 $Anchor = "<a name='".$Level."_Added'></a>";
14808 }
14809 $ADDED_INTERFACES = $Anchor."<h2>Added Symbols ($Added_Number)</h2><hr/>\n".$ADDED_INTERFACES.$TOP_REF."<br/>\n";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014810 }
14811 }
14812 return $ADDED_INTERFACES;
14813}
14814
14815sub get_Report_Removed($)
14816{
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014817 my $Level = $_[0];
Andrey Ponomarenko16934472012-03-29 15:37:04 +040014818 my $REMOVED_INTERFACES = "";
14819 my %ReportMap = ();
Andrey Ponomarenko85043792012-05-14 16:48:07 +040014820 foreach my $Symbol (sort keys(%{$CompatProblems{$Level}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014821 {
Andrey Ponomarenko85043792012-05-14 16:48:07 +040014822 foreach my $Kind (sort keys(%{$CompatProblems{$Level}{$Symbol}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014823 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014824 if($Kind eq "Removed_Symbol")
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014825 {
Andrey Ponomarenko85043792012-05-14 16:48:07 +040014826 my $HeaderName = $CompleteSignature{1}{$Symbol}{"Header"};
14827 my $DyLib = $Symbol_Library{1}{$Symbol};
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014828 if($Level eq "Source" and $ReportFormat eq "html")
14829 { # do not show library name in HTML report
14830 $DyLib = "";
14831 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +040014832 $ReportMap{$HeaderName}{$DyLib}{$Symbol} = 1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014833 }
14834 }
14835 }
14836 if($ReportFormat eq "xml")
14837 { # XML
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014838 foreach my $HeaderName (sort {lc($a) cmp lc($b)} keys(%ReportMap))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014839 {
14840 $REMOVED_INTERFACES .= " <header name=\"$HeaderName\">\n";
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014841 foreach my $DyLib (sort {lc($a) cmp lc($b)} keys(%{$ReportMap{$HeaderName}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014842 {
14843 $REMOVED_INTERFACES .= " <library name=\"$DyLib\">\n";
Andrey Ponomarenko85043792012-05-14 16:48:07 +040014844 foreach my $Symbol (keys(%{$ReportMap{$HeaderName}{$DyLib}})) {
14845 $REMOVED_INTERFACES .= " <name>$Symbol</name>\n";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014846 }
14847 $REMOVED_INTERFACES .= " </library>\n";
14848 }
14849 $REMOVED_INTERFACES .= " </header>\n";
14850 }
14851 $REMOVED_INTERFACES = "<removed_symbols>\n".$REMOVED_INTERFACES."</removed_symbols>\n\n";
14852 }
14853 else
14854 { # HTML
14855 my $Removed_Number = 0;
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014856 foreach my $HeaderName (sort {lc($a) cmp lc($b)} keys(%ReportMap))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014857 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014858 foreach my $DyLib (sort {lc($a) cmp lc($b)} keys(%{$ReportMap{$HeaderName}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014859 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014860 my %NameSpaceSymbols = ();
14861 foreach my $Interface (keys(%{$ReportMap{$HeaderName}{$DyLib}})) {
14862 $NameSpaceSymbols{get_IntNameSpace($Interface, 1)}{$Interface} = 1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014863 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014864 foreach my $NameSpace (sort keys(%NameSpaceSymbols))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014865 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014866 $REMOVED_INTERFACES .= getTitle($HeaderName, $DyLib, $NameSpace);
14867 my @SortedInterfaces = sort {lc(get_Signature($a, 1)) cmp lc(get_Signature($b, 1))} keys(%{$NameSpaceSymbols{$NameSpace}});
Andrey Ponomarenko85043792012-05-14 16:48:07 +040014868 foreach my $Symbol (@SortedInterfaces)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014869 {
14870 $Removed_Number += 1;
14871 my $SubReport = "";
Andrey Ponomarenko85043792012-05-14 16:48:07 +040014872 my $Signature = get_Signature($Symbol, 1);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014873 if($NameSpace) {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040014874 $Signature=~s/\b\Q$NameSpace\E::\b//g;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014875 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +040014876 if($Symbol=~/\A(_Z|\?)/)
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014877 {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014878 if($Signature) {
Andrey Ponomarenko85043792012-05-14 16:48:07 +040014879 $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 +040014880 }
14881 else {
Andrey Ponomarenko85043792012-05-14 16:48:07 +040014882 $REMOVED_INTERFACES .= "<span class=\"iname\">".$Symbol."</span><br/>\n";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014883 }
14884 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014885 else
14886 {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014887 if($Signature) {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014888 $REMOVED_INTERFACES .= "<span class=\"iname\">".highLight_Signature_Italic_Color($Signature)."</span><br/>\n";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014889 }
14890 else {
Andrey Ponomarenko85043792012-05-14 16:48:07 +040014891 $REMOVED_INTERFACES .= "<span class=\"iname\">".$Symbol."</span><br/>\n";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014892 }
14893 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014894 }
14895 }
14896 $REMOVED_INTERFACES .= "<br/>\n";
14897 }
14898 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014899 if($REMOVED_INTERFACES)
14900 {
14901 my $Anchor = "<a name='Removed'></a><a name='Withdrawn'></a>";
14902 if($JoinReport) {
14903 $Anchor = "<a name='".$Level."_Removed'></a><a name='".$Level."_Withdrawn'></a>";
14904 }
14905 $REMOVED_INTERFACES = $Anchor."<h2>Removed Symbols ($Removed_Number)</h2><hr/>\n".$REMOVED_INTERFACES.$TOP_REF."<br/>\n";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014906 }
14907 }
14908 return $REMOVED_INTERFACES;
14909}
14910
14911sub getXmlParams($$)
14912{
14913 my ($Content, $Problem) = @_;
14914 return "" if(not $Content or not $Problem);
14915 my %XMLparams = ();
14916 foreach my $Attr (sort {$b cmp $a} keys(%{$Problem}))
14917 {
14918 my $Macro = "\@".lc($Attr);
14919 if($Content=~/\Q$Macro\E/) {
14920 $XMLparams{lc($Attr)} = $Problem->{$Attr};
14921 }
14922 }
14923 my @PString = ();
14924 foreach my $P (sort {$b cmp $a} keys(%XMLparams)) {
Andrey Ponomarenko5c09ef32012-06-14 18:17:33 +040014925 push(@PString, $P."=\"".xmlSpecChars($XMLparams{$P})."\"");
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014926 }
14927 if(@PString) {
14928 return " ".join(" ", @PString);
14929 }
14930 else {
14931 return "";
14932 }
14933}
14934
14935sub addMarkup($)
14936{
14937 my $Content = $_[0];
14938 # auto-markup
14939 $Content=~s/\n[ ]*//; # spaces
14940 $Content=~s!(\@\w+\s*\(\@\w+\))!<nowrap>$1</nowrap>!g; # @old_type (@old_size)
14941 $Content=~s!(... \(\w+\))!<nowrap><b>$1</b></nowrap>!g; # ... (va_list)
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040014942 $Content=~s!<nowrap>(.+?)</nowrap>!<span class='nowrap'>$1</span>!g;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014943 $Content=~s!([2-9]\))!<br/>$1!g; # 1), 2), ...
14944 if($Content=~/\ANOTE:/)
14945 { # notes
14946 $Content=~s!(NOTE):!<b>$1</b>:!g;
14947 }
14948 else {
14949 $Content=~s!(NOTE):!<br/><b>$1</b>:!g;
14950 }
14951 $Content=~s! (out)-! <b>$1</b>-!g; # out-parameters
14952 my @Keywords = (
14953 "void",
14954 "const",
14955 "static",
14956 "restrict",
14957 "volatile",
14958 "register",
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040014959 "virtual"
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014960 );
14961 my $MKeys = join("|", @Keywords);
14962 foreach (@Keywords) {
14963 $MKeys .= "|non-".$_;
14964 }
14965 $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 +040014966
14967 # Markdown
14968 $Content=~s!\*\*([\w\-]+)\*\*!<b>$1</b>!ig;
14969 $Content=~s!\*([\w\-]+)\*!<i>$1</i>!ig;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014970 return $Content;
14971}
14972
14973sub applyMacroses($$$$)
14974{
14975 my ($Level, $Kind, $Content, $Problem) = @_;
14976 return "" if(not $Content or not $Problem);
14977 $Problem->{"Word_Size"} = $WORD_SIZE{2};
14978 $Content = addMarkup($Content);
14979 # macros
14980 foreach my $Attr (sort {$b cmp $a} keys(%{$Problem}))
14981 {
14982 my $Macro = "\@".lc($Attr);
14983 my $Value = $Problem->{$Attr};
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040014984 if(not defined $Value
14985 or $Value eq "") {
14986 next;
14987 }
Andrey Ponomarenko5c09ef32012-06-14 18:17:33 +040014988 if($Value=~/\s\(/ and $Value!~/['"]/)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014989 { # functions
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014990 $Value=~s/\s*\[[\w\-]+\]//g; # remove quals
14991 $Value=~s/\s\w+(\)|,)/$1/g; # remove parameter names
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014992 $Value = black_name($Value);
14993 }
14994 elsif($Value=~/\s/) {
14995 $Value = "<span class='value'>".htmlSpecChars($Value)."</span>";
14996 }
14997 elsif($Value=~/\A\d+\Z/
14998 and ($Attr eq "Old_Size" or $Attr eq "New_Size"))
14999 { # bits to bytes
15000 if($Value % $BYTE_SIZE)
15001 { # bits
15002 if($Value==1) {
15003 $Value = "<b>".$Value."</b> bit";
15004 }
15005 else {
15006 $Value = "<b>".$Value."</b> bits";
15007 }
15008 }
15009 else
15010 { # bytes
15011 $Value /= $BYTE_SIZE;
15012 if($Value==1) {
15013 $Value = "<b>".$Value."</b> byte";
15014 }
15015 else {
15016 $Value = "<b>".$Value."</b> bytes";
15017 }
15018 }
15019 }
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040015020 else
15021 {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015022 $Value = "<b>".htmlSpecChars($Value)."</b>";
15023 }
15024 $Content=~s/\Q$Macro\E/$Value/g;
15025 }
15026
15027 if($Content=~/(\A|[^\@\w])\@\w/)
15028 {
15029 if(not $IncompleteRules{$Level}{$Kind})
15030 { # only one warning
15031 printMsg("WARNING", "incomplete rule \"$Kind\" (\"$Level\")");
15032 $IncompleteRules{$Level}{$Kind} = 1;
15033 }
15034 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015035 return $Content;
15036}
15037
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040015038sub get_Report_SymbolProblems($$)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015039{
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015040 my ($TargetSeverity, $Level) = @_;
Andrey Ponomarenko16934472012-03-29 15:37:04 +040015041 my $INTERFACE_PROBLEMS = "";
15042 my (%ReportMap, %SymbolChanges) = ();
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015043 foreach my $Symbol (sort keys(%{$CompatProblems{$Level}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015044 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015045 my ($SN, $SS, $SV) = separate_symbol($Symbol);
15046 if($SV and defined $CompatProblems{$Level}{$SN}) {
15047 next;
15048 }
15049 foreach my $Kind (sort keys(%{$CompatProblems{$Level}{$Symbol}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015050 {
15051 if($CompatRules{$Level}{$Kind}{"Kind"} eq "Symbols"
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015052 and $Kind ne "Added_Symbol" and $Kind ne "Removed_Symbol")
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015053 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015054 my $HeaderName = $CompleteSignature{1}{$Symbol}{"Header"};
15055 my $DyLib = $Symbol_Library{1}{$Symbol};
15056 if(not $DyLib and my $VSym = $SymVer{1}{$Symbol})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015057 { # Symbol with Version
15058 $DyLib = $Symbol_Library{1}{$VSym};
15059 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040015060 if(not $DyLib)
15061 { # const global data
15062 $DyLib = "";
15063 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015064 if($Level eq "Source" and $ReportFormat eq "html")
15065 { # do not show library name in HTML report
15066 $DyLib = "";
15067 }
15068 %{$SymbolChanges{$Symbol}{$Kind}} = %{$CompatProblems{$Level}{$Symbol}{$Kind}};
15069 foreach my $Location (sort keys(%{$SymbolChanges{$Symbol}{$Kind}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015070 {
15071 my $Priority = getProblemSeverity($Level, $Kind);
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015072 if($Priority ne $TargetSeverity) {
15073 delete($SymbolChanges{$Symbol}{$Kind}{$Location});
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015074 }
15075 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015076 if(not keys(%{$SymbolChanges{$Symbol}{$Kind}}))
15077 {
15078 delete($SymbolChanges{$Symbol}{$Kind});
15079 next;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015080 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015081 $ReportMap{$HeaderName}{$DyLib}{$Symbol} = 1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015082 }
15083 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015084 if(not keys(%{$SymbolChanges{$Symbol}})) {
15085 delete($SymbolChanges{$Symbol});
15086 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015087 }
15088 if($ReportFormat eq "xml")
15089 { # XML
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015090 foreach my $HeaderName (sort {lc($a) cmp lc($b)} keys(%ReportMap))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015091 {
15092 $INTERFACE_PROBLEMS .= " <header name=\"$HeaderName\">\n";
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015093 foreach my $DyLib (sort {lc($a) cmp lc($b)} keys(%{$ReportMap{$HeaderName}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015094 {
15095 $INTERFACE_PROBLEMS .= " <library name=\"$DyLib\">\n";
15096 foreach my $Symbol (sort {lc($tr_name{$a}) cmp lc($tr_name{$b})} keys(%SymbolChanges))
15097 {
15098 $INTERFACE_PROBLEMS .= " <symbol name=\"$Symbol\">\n";
15099 foreach my $Kind (keys(%{$SymbolChanges{$Symbol}}))
15100 {
15101 foreach my $Location (sort keys(%{$SymbolChanges{$Symbol}{$Kind}}))
15102 {
15103 my %Problem = %{$SymbolChanges{$Symbol}{$Kind}{$Location}};
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040015104 $Problem{"Param_Pos"} = showPos($Problem{"Param_Pos"});
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015105 $INTERFACE_PROBLEMS .= " <problem id=\"$Kind\">\n";
15106 my $Change = $CompatRules{$Level}{$Kind}{"Change"};
15107 $INTERFACE_PROBLEMS .= " <change".getXmlParams($Change, \%Problem).">$Change</change>\n";
15108 my $Effect = $CompatRules{$Level}{$Kind}{"Effect"};
15109 $INTERFACE_PROBLEMS .= " <effect".getXmlParams($Effect, \%Problem).">$Effect</effect>\n";
15110 my $Overcome = $CompatRules{$Level}{$Kind}{"Overcome"};
15111 $INTERFACE_PROBLEMS .= " <overcome".getXmlParams($Overcome, \%Problem).">$Overcome</overcome>\n";
15112 $INTERFACE_PROBLEMS .= " </problem>\n";
15113 }
15114 }
15115 $INTERFACE_PROBLEMS .= " </symbol>\n";
15116 }
15117 $INTERFACE_PROBLEMS .= " </library>\n";
15118 }
15119 $INTERFACE_PROBLEMS .= " </header>\n";
15120 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015121 $INTERFACE_PROBLEMS = "<problems_with_symbols severity=\"$TargetSeverity\">\n".$INTERFACE_PROBLEMS."</problems_with_symbols>\n\n";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015122 }
15123 else
15124 { # HTML
15125 my $ProblemsNum = 0;
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015126 foreach my $HeaderName (sort {lc($a) cmp lc($b)} keys(%ReportMap))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015127 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015128 foreach my $DyLib (sort {lc($a) cmp lc($b)} keys(%{$ReportMap{$HeaderName}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015129 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015130 my (%NameSpaceSymbols, %NewSignature) = ();
15131 foreach my $Symbol (keys(%{$ReportMap{$HeaderName}{$DyLib}})) {
15132 $NameSpaceSymbols{get_IntNameSpace($Symbol, 1)}{$Symbol} = 1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015133 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015134 foreach my $NameSpace (sort keys(%NameSpaceSymbols))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015135 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015136 $INTERFACE_PROBLEMS .= getTitle($HeaderName, $DyLib, $NameSpace);
15137 my @SortedInterfaces = sort {lc($tr_name{$a}) cmp lc($tr_name{$b})} keys(%{$NameSpaceSymbols{$NameSpace}});
15138 foreach my $Symbol (@SortedInterfaces)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015139 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015140 my $Signature = get_Signature($Symbol, 1);
15141 my $SYMBOL_REPORT = "";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015142 my $ProblemNum = 1;
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015143 foreach my $Kind (keys(%{$SymbolChanges{$Symbol}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015144 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015145 foreach my $Location (sort keys(%{$SymbolChanges{$Symbol}{$Kind}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015146 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015147 my %Problem = %{$SymbolChanges{$Symbol}{$Kind}{$Location}};
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040015148 $Problem{"Param_Pos"} = showPos($Problem{"Param_Pos"});
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015149 if($Problem{"New_Signature"}) {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015150 $NewSignature{$Symbol} = $Problem{"New_Signature"};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015151 }
15152 if(my $Change = applyMacroses($Level, $Kind, $CompatRules{$Level}{$Kind}{"Change"}, \%Problem))
15153 {
15154 my $Effect = applyMacroses($Level, $Kind, $CompatRules{$Level}{$Kind}{"Effect"}, \%Problem);
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015155 $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 +040015156 $ProblemNum += 1;
15157 $ProblemsNum += 1;
15158 }
15159 }
15160 }
15161 $ProblemNum -= 1;
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015162 if($SYMBOL_REPORT)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015163 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015164 $INTERFACE_PROBLEMS .= $ContentSpanStart."<span class='extendable'>[+]</span> ";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015165 if($Signature) {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015166 $INTERFACE_PROBLEMS .= highLight_Signature_Italic_Color($Signature);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015167 }
15168 else {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015169 $INTERFACE_PROBLEMS .= $Symbol;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015170 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015171 $INTERFACE_PROBLEMS .= " ($ProblemNum)".$ContentSpanEnd."<br/>\n";
15172 $INTERFACE_PROBLEMS .= $ContentDivStart."\n";
15173 if($NewSignature{$Symbol})
15174 { # argument list changed to
15175 $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 +040015176 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015177 if($Symbol=~/\A(_Z|\?)/) {
15178 $INTERFACE_PROBLEMS .= "<span class='mangled'>&#160;&#160;&#160;&#160;[symbol: <b>$Symbol</b>]</span><br/>\n";
15179 }
15180 $INTERFACE_PROBLEMS .= "<table class='ptable'><tr><th width='2%'></th><th width='47%'>Change</th><th>Effect</th></tr>$SYMBOL_REPORT</table><br/>\n";
15181 $INTERFACE_PROBLEMS .= $ContentDivEnd;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015182 if($NameSpace) {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040015183 $INTERFACE_PROBLEMS=~s/\b\Q$NameSpace\E::\b//g;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015184 }
15185 }
15186 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015187 $INTERFACE_PROBLEMS .= "<br/>";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015188 }
15189 }
15190 }
15191 if($INTERFACE_PROBLEMS)
15192 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015193 $INTERFACE_PROBLEMS = insertIDs($INTERFACE_PROBLEMS);
15194 my $Title = "Problems with Symbols, $TargetSeverity Severity";
15195 if($TargetSeverity eq "Safe")
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015196 { # Safe Changes
15197 $Title = "Other Changes in Symbols";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015198 }
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040015199 $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 +040015200 }
15201 }
15202 return $INTERFACE_PROBLEMS;
15203}
15204
15205sub get_Report_TypeProblems($$)
15206{
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015207 my ($TargetSeverity, $Level) = @_;
Andrey Ponomarenko16934472012-03-29 15:37:04 +040015208 my $TYPE_PROBLEMS = "";
15209 my (%ReportMap, %TypeChanges, %TypeType) = ();
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015210 foreach my $Interface (sort keys(%{$CompatProblems{$Level}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015211 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015212 foreach my $Kind (keys(%{$CompatProblems{$Level}{$Interface}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015213 {
15214 if($CompatRules{$Level}{$Kind}{"Kind"} eq "Types")
15215 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015216 foreach my $Location (sort {cmp_locations($b, $a)} sort keys(%{$CompatProblems{$Level}{$Interface}{$Kind}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015217 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015218 my $TypeName = $CompatProblems{$Level}{$Interface}{$Kind}{$Location}{"Type_Name"};
15219 my $TypeType = $CompatProblems{$Level}{$Interface}{$Kind}{$Location}{"Type_Type"};
15220 my $Target = $CompatProblems{$Level}{$Interface}{$Kind}{$Location}{"Target"};
15221 $CompatProblems{$Level}{$Interface}{$Kind}{$Location}{"Type_Type"} = lc($TypeType);
15222 my $Severity = getProblemSeverity($Level, $Kind);
15223 if($Severity eq "Safe"
15224 and $TargetSeverity ne "Safe") {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015225 next;
15226 }
15227 if(not $TypeType{$TypeName}
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015228 or $TypeType{$TypeName} eq "struct")
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015229 { # register type of the type, select "class" if type has "class"- and "struct"-type changes
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015230 $TypeType{$TypeName} = $CompatProblems{$Level}{$Interface}{$Kind}{$Location}{"Type_Type"};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015231 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015232
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040015233 if(cmpSeverities($Type_MaxSeverity{$Level}{$TypeName}{$Kind}{$Target}, $Severity))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015234 { # select a problem with the highest priority
15235 next;
15236 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015237 %{$TypeChanges{$TypeName}{$Kind}{$Location}} = %{$CompatProblems{$Level}{$Interface}{$Kind}{$Location}};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015238 }
15239 }
15240 }
15241 }
15242 my %Kinds_Locations = ();
15243 foreach my $TypeName (keys(%TypeChanges))
15244 {
15245 my %Kinds_Target = ();
15246 foreach my $Kind (sort keys(%{$TypeChanges{$TypeName}}))
15247 {
15248 foreach my $Location (sort {cmp_locations($b, $a)} sort keys(%{$TypeChanges{$TypeName}{$Kind}}))
15249 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015250 my $Severity = getProblemSeverity($Level, $Kind);
15251 if($Severity ne $TargetSeverity)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015252 { # other priority
15253 delete($TypeChanges{$TypeName}{$Kind}{$Location});
15254 next;
15255 }
15256 $Kinds_Locations{$TypeName}{$Kind}{$Location} = 1;
15257 my $Target = $TypeChanges{$TypeName}{$Kind}{$Location}{"Target"};
15258 if($Kinds_Target{$Kind}{$Target})
15259 { # duplicate target
15260 delete($TypeChanges{$TypeName}{$Kind}{$Location});
15261 next;
15262 }
15263 $Kinds_Target{$Kind}{$Target} = 1;
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040015264 my $HeaderName = $TypeInfo{1}{$TName_Tid{1}{$TypeName}}{"Header"};
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015265 $ReportMap{$HeaderName}{$TypeName} = 1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015266 }
15267 if(not keys(%{$TypeChanges{$TypeName}{$Kind}})) {
15268 delete($TypeChanges{$TypeName}{$Kind});
15269 }
15270 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015271 if(not keys(%{$TypeChanges{$TypeName}})) {
15272 delete($TypeChanges{$TypeName});
15273 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015274 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +040015275 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 +040015276 if($ReportFormat eq "xml")
15277 { # XML
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015278 foreach my $HeaderName (sort {lc($a) cmp lc($b)} keys(%ReportMap))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015279 {
15280 $TYPE_PROBLEMS .= " <header name=\"$HeaderName\">\n";
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015281 foreach my $TypeName (keys(%{$ReportMap{$HeaderName}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015282 {
Andrey Ponomarenko5c09ef32012-06-14 18:17:33 +040015283 $TYPE_PROBLEMS .= " <type name=\"".xmlSpecChars($TypeName)."\">\n";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015284 foreach my $Kind (sort {$b=~/Size/ <=> $a=~/Size/} sort keys(%{$TypeChanges{$TypeName}}))
15285 {
15286 foreach my $Location (sort {cmp_locations($b, $a)} sort keys(%{$TypeChanges{$TypeName}{$Kind}}))
15287 {
15288 my %Problem = %{$TypeChanges{$TypeName}{$Kind}{$Location}};
15289 $TYPE_PROBLEMS .= " <problem id=\"$Kind\">\n";
15290 my $Change = $CompatRules{$Level}{$Kind}{"Change"};
15291 $TYPE_PROBLEMS .= " <change".getXmlParams($Change, \%Problem).">$Change</change>\n";
15292 my $Effect = $CompatRules{$Level}{$Kind}{"Effect"};
15293 $TYPE_PROBLEMS .= " <effect".getXmlParams($Effect, \%Problem).">$Effect</effect>\n";
15294 my $Overcome = $CompatRules{$Level}{$Kind}{"Overcome"};
15295 $TYPE_PROBLEMS .= " <overcome".getXmlParams($Overcome, \%Problem).">$Overcome</overcome>\n";
15296 $TYPE_PROBLEMS .= " </problem>\n";
15297 }
15298 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +040015299 $TYPE_PROBLEMS .= getAffectedSymbols($Level, $TypeName, $Kinds_Locations{$TypeName}, \@Symbols);
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015300 if($Level eq "Binary" and grep {$_=~/Virtual|Base_Class/} keys(%{$Kinds_Locations{$TypeName}})) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015301 $TYPE_PROBLEMS .= showVTables($TypeName);
15302 }
15303 $TYPE_PROBLEMS .= " </type>\n";
15304 }
15305 $TYPE_PROBLEMS .= " </header>\n";
15306 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015307 $TYPE_PROBLEMS = "<problems_with_types severity=\"$TargetSeverity\">\n".$TYPE_PROBLEMS."</problems_with_types>\n\n";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015308 }
15309 else
15310 { # HTML
15311 my $ProblemsNum = 0;
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015312 foreach my $HeaderName (sort {lc($a) cmp lc($b)} keys(%ReportMap))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015313 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015314 my (%NameSpace_Type) = ();
15315 foreach my $TypeName (keys(%{$ReportMap{$HeaderName}})) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015316 $NameSpace_Type{parse_TypeNameSpace($TypeName, 1)}{$TypeName} = 1;
15317 }
15318 foreach my $NameSpace (sort keys(%NameSpace_Type))
15319 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015320 $TYPE_PROBLEMS .= getTitle($HeaderName, "", $NameSpace);
15321 my @SortedTypes = sort {$TypeType{$a}." ".lc($a) cmp $TypeType{$b}." ".lc($b)} keys(%{$NameSpace_Type{$NameSpace}});
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015322 foreach my $TypeName (@SortedTypes)
15323 {
15324 my $ProblemNum = 1;
15325 my $TYPE_REPORT = "";
15326 foreach my $Kind (sort {$b=~/Size/ <=> $a=~/Size/} sort keys(%{$TypeChanges{$TypeName}}))
15327 {
15328 foreach my $Location (sort {cmp_locations($b, $a)} sort keys(%{$TypeChanges{$TypeName}{$Kind}}))
15329 {
15330 my %Problem = %{$TypeChanges{$TypeName}{$Kind}{$Location}};
15331 if(my $Change = applyMacroses($Level, $Kind, $CompatRules{$Level}{$Kind}{"Change"}, \%Problem))
15332 {
15333 my $Effect = applyMacroses($Level, $Kind, $CompatRules{$Level}{$Kind}{"Effect"}, \%Problem);
15334 $TYPE_REPORT .= "<tr><th>$ProblemNum</th><td align='left' valign='top'>".$Change."</td><td align='left' valign='top'>$Effect</td></tr>\n";
15335 $ProblemNum += 1;
15336 $ProblemsNum += 1;
15337 }
15338 }
15339 }
15340 $ProblemNum -= 1;
15341 if($TYPE_REPORT)
15342 {
Andrey Ponomarenko85043792012-05-14 16:48:07 +040015343 my $Affected = getAffectedSymbols($Level, $TypeName, $Kinds_Locations{$TypeName}, \@Symbols);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015344 my $ShowVTables = "";
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015345 if($Level eq "Binary" and grep {$_=~/Virtual|Base_Class/} keys(%{$Kinds_Locations{$TypeName}})) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015346 $ShowVTables = showVTables($TypeName);
15347 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015348 $TYPE_PROBLEMS .= $ContentSpanStart."<span class='extendable'>[+]</span> <span class='ttype'>".$TypeType{$TypeName}."</span> ".htmlSpecChars($TypeName)." ($ProblemNum)".$ContentSpanEnd;
15349 $TYPE_PROBLEMS .= "<br/>\n".$ContentDivStart."<table class='ptable'><tr>\n";
15350 $TYPE_PROBLEMS .= "<th width='2%'></th><th width='47%'>Change</th>\n";
15351 $TYPE_PROBLEMS .= "<th>Effect</th></tr>".$TYPE_REPORT."</table>\n";
15352 $TYPE_PROBLEMS .= $ShowVTables.$Affected."<br/><br/>".$ContentDivEnd."\n";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015353 if($NameSpace) {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040015354 $TYPE_PROBLEMS=~s/\b\Q$NameSpace\E::(\w|\~)/$1/g;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015355 }
15356 }
15357 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015358 $TYPE_PROBLEMS .= "<br/>";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015359 }
15360 }
15361 if($TYPE_PROBLEMS)
15362 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015363 $TYPE_PROBLEMS = insertIDs($TYPE_PROBLEMS);
15364 my $Title = "Problems with Data Types, $TargetSeverity Severity";
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015365 if($TargetSeverity eq "Safe")
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015366 { # Safe Changes
15367 $Title = "Other Changes in Data Types";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015368 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015369 $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 +040015370 }
15371 }
15372 return $TYPE_PROBLEMS;
15373}
15374
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015375sub get_Anchor($$$)
15376{
15377 my ($Kind, $Level, $Severity) = @_;
15378 if($JoinReport)
15379 {
15380 if($Severity eq "Safe") {
15381 return "Other_".$Level."_Changes_In_".$Kind."s";
15382 }
15383 else {
15384 return $Kind."_".$Level."_Problems_".$Severity;
15385 }
15386 }
15387 else
15388 {
15389 if($Severity eq "Safe") {
15390 return "Other_Changes_In_".$Kind."s";
15391 }
15392 else {
15393 return $Kind."_Problems_".$Severity;
15394 }
15395 }
15396}
15397
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015398sub showVTables($)
15399{
15400 my $TypeName = $_[0];
15401 my $TypeId1 = $TName_Tid{1}{$TypeName};
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040015402 my %Type1 = get_Type($TypeId1, 1);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015403 if(defined $Type1{"VTable"}
15404 and keys(%{$Type1{"VTable"}}))
15405 {
15406 my $TypeId2 = $TName_Tid{2}{$TypeName};
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040015407 my %Type2 = get_Type($TypeId2, 2);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015408 if(defined $Type2{"VTable"}
15409 and keys(%{$Type2{"VTable"}}))
15410 {
15411 my %Indexes = map {$_=>1} (keys(%{$Type1{"VTable"}}), keys(%{$Type2{"VTable"}}));
15412 my %Entries = ();
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015413 foreach my $Index (sort {int($a)<=>int($b)} (keys(%Indexes)))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015414 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015415 $Entries{$Index}{"E1"} = simpleVEntry($Type1{"VTable"}{$Index});
15416 $Entries{$Index}{"E2"} = simpleVEntry($Type2{"VTable"}{$Index});
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015417 }
15418 my $VTABLES = "";
15419 if($ReportFormat eq "xml")
15420 { # XML
15421 $VTABLES .= " <vtable>\n";
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015422 foreach my $Index (sort {int($a)<=>int($b)} (keys(%Entries)))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015423 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015424 $VTABLES .= " <entry offset=\"".$Index."\">\n";
Andrey Ponomarenko5c09ef32012-06-14 18:17:33 +040015425 $VTABLES .= " <old>".xmlSpecChars($Entries{$Index}{"E1"})."</old>\n";
15426 $VTABLES .= " <new>".xmlSpecChars($Entries{$Index}{"E2"})."</new>\n";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015427 $VTABLES .= " </entry>\n";
15428 }
15429 $VTABLES .= " </vtable>\n\n";
15430 }
15431 else
15432 { # HTML
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015433 $VTABLES .= "<table class='vtable'>";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015434 $VTABLES .= "<tr><th width='2%'>Offset</th>";
15435 $VTABLES .= "<th width='45%'>Virtual Table (Old) - ".(keys(%{$Type1{"VTable"}}))." entries</th>";
15436 $VTABLES .= "<th>Virtual Table (New) - ".(keys(%{$Type2{"VTable"}}))." entries</th></tr>";
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015437 foreach my $Index (sort {int($a)<=>int($b)} (keys(%Entries)))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015438 {
15439 my ($Color1, $Color2) = ("", "");
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015440 if($Entries{$Index}{"E1"} ne $Entries{$Index}{"E2"})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015441 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015442 if($Entries{$Index}{"E1"})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015443 {
Andrey Ponomarenko16934472012-03-29 15:37:04 +040015444 $Color1 = " class='failed'";
15445 $Color2 = " class='failed'";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015446 }
15447 else {
Andrey Ponomarenko16934472012-03-29 15:37:04 +040015448 $Color2 = " class='warning'";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015449 }
15450 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015451 $VTABLES .= "<tr><th>".$Index."</th>\n";
15452 $VTABLES .= "<td$Color1>".htmlSpecChars($Entries{$Index}{"E1"})."</td>\n";
15453 $VTABLES .= "<td$Color2>".htmlSpecChars($Entries{$Index}{"E2"})."</td></tr>\n";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015454 }
15455 $VTABLES .= "</table><br/>\n";
15456 $VTABLES = $ContentDivStart.$VTABLES.$ContentDivEnd;
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015457 $VTABLES = $ContentSpanStart_Info."[+] show v-table (old and new)".$ContentSpanEnd."<br/>\n".$VTABLES;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015458 }
15459 return $VTABLES;
15460 }
15461 }
15462 return "";
15463}
15464
15465sub simpleVEntry($)
15466{
15467 my $VEntry = $_[0];
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040015468 if(not defined $VEntry
15469 or $VEntry eq "") {
15470 return "";
15471 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015472 $VEntry=~s/\A(.+)::(_ZThn.+)\Z/$2/; # thunks
15473 $VEntry=~s/_ZTI\w+/typeinfo/g; # typeinfo
15474 if($VEntry=~/\A_ZThn.+\Z/) {
15475 $VEntry = "non-virtual thunk";
15476 }
15477 $VEntry=~s/\A\(int \(\*\)\(...\)\)([^\(\d])/$1/i;
15478 # support for old GCC versions
15479 $VEntry=~s/\A0u\Z/(int (*)(...))0/;
15480 $VEntry=~s/\A4294967268u\Z/(int (*)(...))-0x000000004/;
15481 $VEntry=~s/\A&_Z\Z/& _Z/;
15482 # templates
15483 if($VEntry=~s/ \[with (\w+) = (.+?)(, [^=]+ = .+|])\Z//g)
15484 { # std::basic_streambuf<_CharT, _Traits>::imbue [with _CharT = char, _Traits = std::char_traits<char>]
15485 # become std::basic_streambuf<char, ...>::imbue
15486 my ($Pname, $Pval) = ($1, $2);
15487 if($Pname eq "_CharT" and $VEntry=~/\Astd::/)
15488 { # stdc++ typedefs
15489 $VEntry=~s/<$Pname(, [^<>]+|)>/<$Pval>/g;
15490 # FIXME: simplify names using stdcxx typedefs (StdCxxTypedef)
15491 # The typedef info should be added to ABI dumps
15492 }
15493 else
15494 {
15495 $VEntry=~s/<$Pname>/<$Pval>/g;
15496 $VEntry=~s/<$Pname, [^<>]+>/<$Pval, ...>/g;
15497 }
15498 }
15499 $VEntry=~s/([^:]+)::\~([^:]+)\Z/~$1/; # destructors
15500 return $VEntry;
15501}
15502
Andrey Ponomarenko85043792012-05-14 16:48:07 +040015503sub getAffectedSymbols($$$$)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015504{
Andrey Ponomarenko85043792012-05-14 16:48:07 +040015505 my ($Level, $Target_TypeName, $Kinds_Locations, $Syms) = @_;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015506 my $LIMIT = 1000;
Andrey Ponomarenko85043792012-05-14 16:48:07 +040015507 if($#{$Syms}>=10000)
15508 { # reduce size of the report
15509 $LIMIT = 10;
15510 }
15511 my %SProblems = ();
15512 foreach my $Symbol (@{$Syms})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015513 {
Andrey Ponomarenko85043792012-05-14 16:48:07 +040015514 if(keys(%SProblems)>$LIMIT) {
15515 last;
15516 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015517 if(($Symbol=~/C2E|D2E|D0E/))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015518 { # duplicated problems for C2 constructors, D2 and D0 destructors
15519 next;
15520 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015521 my ($SN, $SS, $SV) = separate_symbol($Symbol);
15522 if($Level eq "Source")
15523 { # remove symbol version
15524 $Symbol=$SN;
15525 }
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040015526 my ($MinPath_Length, $ProblemLocation_Last) = (-1, "");
15527 my $Severity_Max = 0;
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015528 my $Signature = get_Signature($Symbol, 1);
15529 foreach my $Kind (keys(%{$CompatProblems{$Level}{$Symbol}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015530 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015531 foreach my $Location (keys(%{$CompatProblems{$Level}{$Symbol}{$Kind}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015532 {
15533 if(not defined $Kinds_Locations->{$Kind}
15534 or not $Kinds_Locations->{$Kind}{$Location}) {
15535 next;
15536 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015537 if($SV and defined $CompatProblems{$Level}{$SN}
15538 and defined $CompatProblems{$Level}{$SN}{$Kind}{$Location})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015539 { # duplicated problems for versioned symbols
15540 next;
15541 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015542 my $Type_Name = $CompatProblems{$Level}{$Symbol}{$Kind}{$Location}{"Type_Name"};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015543 next if($Type_Name ne $Target_TypeName);
15544
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015545 my $Position = $CompatProblems{$Level}{$Symbol}{$Kind}{$Location}{"Param_Pos"};
15546 my $Param_Name = $CompatProblems{$Level}{$Symbol}{$Kind}{$Location}{"Param_Name"};
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040015547 my $Severity = getProblemSeverity($Level, $Kind);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015548 my $Path_Length = 0;
15549 my $ProblemLocation = $Location;
15550 if($Type_Name) {
15551 $ProblemLocation=~s/->\Q$Type_Name\E\Z//g;
15552 }
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040015553 while($ProblemLocation=~/\-\>/g) {
15554 $Path_Length += 1;
15555 }
15556 if($MinPath_Length==-1 or ($Path_Length<=$MinPath_Length and $Severity_Val{$Severity}>$Severity_Max)
15557 or (cmp_locations($ProblemLocation, $ProblemLocation_Last) and $Severity_Val{$Severity}==$Severity_Max))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015558 {
15559 $MinPath_Length = $Path_Length;
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040015560 $Severity_Max = $Severity_Val{$Severity};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015561 $ProblemLocation_Last = $ProblemLocation;
Andrey Ponomarenko85043792012-05-14 16:48:07 +040015562 %{$SProblems{$Symbol}} = (
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040015563 "Descr"=>getAffectDescription($Level, $Symbol, $Kind, $Location),
15564 "Severity_Max"=>$Severity_Max,
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015565 "Signature"=>$Signature,
15566 "Position"=>$Position,
15567 "Param_Name"=>$Param_Name,
15568 "Location"=>$Location
15569 );
15570 }
15571 }
15572 }
15573 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +040015574 my @Symbols = keys(%SProblems);
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015575 @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 +040015576 @Symbols = sort {$SProblems{$b}{"Severity_Max"}<=>$SProblems{$a}{"Severity_Max"}} @Symbols;
15577 if($#Symbols+1>$LIMIT)
15578 { # remove last element
15579 pop(@Symbols);
15580 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015581 my $Affected = "";
15582 if($ReportFormat eq "xml")
15583 { # XML
15584 $Affected .= " <affected>\n";
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015585 foreach my $Symbol (@Symbols)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015586 {
Andrey Ponomarenko85043792012-05-14 16:48:07 +040015587 my $Param_Name = $SProblems{$Symbol}{"Param_Name"};
15588 my $Description = $SProblems{$Symbol}{"Descr"};
15589 my $Location = $SProblems{$Symbol}{"Location"};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015590 my $Target = "";
15591 if($Param_Name) {
15592 $Target = " affected=\"param\" param_name=\"$Param_Name\"";
15593 }
15594 elsif($Location=~/\Aretval(\-|\Z)/i) {
15595 $Target = " affected=\"retval\"";
15596 }
15597 elsif($Location=~/\Athis(\-|\Z)/i) {
15598 $Target = " affected=\"this\"";
15599 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015600 $Affected .= " <symbol$Target name=\"$Symbol\">\n";
Andrey Ponomarenko5c09ef32012-06-14 18:17:33 +040015601 $Affected .= " <comment>".xmlSpecChars($Description)."</comment>\n";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015602 $Affected .= " </symbol>\n";
15603 }
15604 $Affected .= " </affected>\n";
15605 }
15606 else
15607 { # HTML
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015608 foreach my $Symbol (@Symbols)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015609 {
Andrey Ponomarenko85043792012-05-14 16:48:07 +040015610 my $Description = $SProblems{$Symbol}{"Descr"};
15611 my $Signature = $SProblems{$Symbol}{"Signature"};
15612 my $Pos = $SProblems{$Symbol}{"Position"};
Andrey Ponomarenkoa01311b2012-06-08 17:20:02 +040015613 $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 +040015614 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +040015615 if(keys(%SProblems)>$LIMIT) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015616 $Affected .= "and others ...<br/>";
15617 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +040015618 $Affected = "<div class='affected'>".$Affected."</div>";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015619 if($Affected)
15620 {
15621 $Affected = $ContentDivStart.$Affected.$ContentDivEnd;
Andrey Ponomarenko85043792012-05-14 16:48:07 +040015622 $Affected = $ContentSpanStart_Affected."[+] affected symbols (".(keys(%SProblems)>$LIMIT?">".$LIMIT:keys(%SProblems)).")".$ContentSpanEnd.$Affected;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015623 }
15624 }
15625 return $Affected;
15626}
15627
15628sub cmp_locations($$)
15629{
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040015630 my ($L1, $L2) = @_;
15631 if($L2=~/\b(retval|this)\b/
15632 and $L1!~/\b(retval|this)\b/ and $L1!~/\-\>/) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015633 return 1;
15634 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040015635 if($L2=~/\b(retval|this)\b/ and $L2=~/\-\>/
15636 and $L1!~/\b(retval|this)\b/ and $L1=~/\-\>/) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015637 return 1;
15638 }
15639 return 0;
15640}
15641
15642sub getAffectDescription($$$$)
15643{
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015644 my ($Level, $Symbol, $Kind, $Location) = @_;
15645 my %Problem = %{$CompatProblems{$Level}{$Symbol}{$Kind}{$Location}};
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040015646 my $PPos = showPos($Problem{"Param_Pos"});
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015647 my @Sentence = ();
15648 $Location=~s/\A(.*)\-\>.+?\Z/$1/;
15649 if($Kind eq "Overridden_Virtual_Method"
15650 or $Kind eq "Overridden_Virtual_Method_B") {
15651 push(@Sentence, "The method '".$Problem{"New_Value"}."' will be called instead of this method.");
15652 }
15653 elsif($CompatRules{$Level}{$Kind}{"Kind"} eq "Types")
15654 {
15655 if($Location eq "this" or $Kind=~/(\A|_)Virtual(_|\Z)/)
15656 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015657 my $METHOD_TYPE = $CompleteSignature{1}{$Symbol}{"Constructor"}?"constructor":"method";
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040015658 my $ClassName = $TypeInfo{1}{$CompleteSignature{1}{$Symbol}{"Class"}}{"Name"};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015659 if($ClassName eq $Problem{"Type_Name"}) {
15660 push(@Sentence, "This $METHOD_TYPE is from \'".$Problem{"Type_Name"}."\' class.");
15661 }
15662 else {
15663 push(@Sentence, "This $METHOD_TYPE is from derived class \'".$ClassName."\'.");
15664 }
15665 }
15666 else
15667 {
15668 if($Location=~/retval/)
15669 { # return value
15670 if($Location=~/\-\>/) {
15671 push(@Sentence, "Field \'".$Location."\' in return value");
15672 }
15673 else {
15674 push(@Sentence, "Return value");
15675 }
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040015676 if(my $Init = $Problem{"InitialType_Type"})
15677 {
15678 if($Init eq "Pointer") {
15679 push(@Sentence, "(pointer)");
15680 }
15681 elsif($Init eq "Ref") {
15682 push(@Sentence, "(reference)");
15683 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015684 }
15685 }
15686 elsif($Location=~/this/)
15687 { # "this" pointer
15688 if($Location=~/\-\>/) {
15689 push(@Sentence, "Field \'".$Location."\' in the object of this method");
15690 }
15691 else {
15692 push(@Sentence, "\'this\' pointer");
15693 }
15694 }
15695 else
15696 { # parameters
15697 if($Location=~/\-\>/) {
15698 push(@Sentence, "Field \'".$Location."\' in $PPos parameter");
15699 }
15700 else {
15701 push(@Sentence, "$PPos parameter");
15702 }
15703 if($Problem{"Param_Name"}) {
15704 push(@Sentence, "\'".$Problem{"Param_Name"}."\'");
15705 }
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040015706 if(my $Init = $Problem{"InitialType_Type"})
15707 {
15708 if($Init eq "Pointer") {
15709 push(@Sentence, "(pointer)");
15710 }
15711 elsif($Init eq "Ref") {
15712 push(@Sentence, "(reference)");
15713 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015714 }
15715 }
15716 if($Location eq "this") {
15717 push(@Sentence, "has base type \'".$Problem{"Type_Name"}."\'.");
15718 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040015719 elsif(defined $Problem{"Start_Type_Name"}
15720 and $Problem{"Start_Type_Name"} eq $Problem{"Type_Name"}) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015721 push(@Sentence, "has type \'".$Problem{"Type_Name"}."\'.");
15722 }
15723 else {
15724 push(@Sentence, "has base type \'".$Problem{"Type_Name"}."\'.");
15725 }
15726 }
15727 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040015728 if($ExtendedSymbols{$Symbol}) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015729 push(@Sentence, " This is a symbol from an artificial external library that may use the \'$TargetLibraryName\' library and change its ABI after recompiling.");
15730 }
15731 return join(" ", @Sentence);
15732}
15733
15734sub get_XmlSign($$)
15735{
15736 my ($Symbol, $LibVersion) = @_;
15737 my $Info = $CompleteSignature{$LibVersion}{$Symbol};
15738 my $Report = "";
15739 foreach my $Pos (sort {int($a)<=>int($b)} keys(%{$Info->{"Param"}}))
15740 {
15741 my $Name = $Info->{"Param"}{$Pos}{"name"};
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040015742 my $Type = $Info->{"Param"}{$Pos}{"type"};
15743 my $TypeName = $TypeInfo{$LibVersion}{$Type}{"Name"};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015744 foreach my $Typedef (keys(%ChangedTypedef))
15745 {
15746 my $Base = $Typedef_BaseName{$LibVersion}{$Typedef};
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040015747 $TypeName=~s/\b\Q$Typedef\E\b/$Base/g;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015748 }
15749 $Report .= " <param pos=\"$Pos\">\n";
15750 $Report .= " <name>".$Name."</name>\n";
Andrey Ponomarenko5c09ef32012-06-14 18:17:33 +040015751 $Report .= " <type>".xmlSpecChars($TypeName)."</type>\n";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015752 $Report .= " </param>\n";
15753 }
15754 if(my $Return = $Info->{"Return"})
15755 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040015756 my $RTName = $TypeInfo{$LibVersion}{$Return}{"Name"};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015757 $Report .= " <retval>\n";
Andrey Ponomarenko5c09ef32012-06-14 18:17:33 +040015758 $Report .= " <type>".xmlSpecChars($RTName)."</type>\n";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015759 $Report .= " </retval>\n";
15760 }
15761 return $Report;
15762}
15763
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015764sub get_Report_SymbolsInfo($)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015765{
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015766 my $Level = $_[0];
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015767 my $Report = "<symbols_info>\n";
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015768 foreach my $Symbol (sort keys(%{$CompatProblems{$Level}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015769 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015770 my ($SN, $SS, $SV) = separate_symbol($Symbol);
15771 if($SV and defined $CompatProblems{$Level}{$SN}) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015772 next;
15773 }
15774 $Report .= " <symbol name=\"$Symbol\">\n";
15775 my ($S1, $P1, $S2, $P2) = ();
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015776 if(not $AddedInt{$Level}{$Symbol})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015777 {
15778 if(defined $CompleteSignature{1}{$Symbol}
15779 and defined $CompleteSignature{1}{$Symbol}{"Header"})
15780 {
15781 $P1 = get_XmlSign($Symbol, 1);
15782 $S1 = get_Signature($Symbol, 1);
15783 }
15784 elsif($Symbol=~/\A(_Z|\?)/) {
15785 $S1 = $tr_name{$Symbol};
15786 }
15787 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015788 if(not $RemovedInt{$Level}{$Symbol})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015789 {
15790 if(defined $CompleteSignature{2}{$Symbol}
15791 and defined $CompleteSignature{2}{$Symbol}{"Header"})
15792 {
15793 $P2 = get_XmlSign($Symbol, 2);
15794 $S2 = get_Signature($Symbol, 2);
15795 }
15796 elsif($Symbol=~/\A(_Z|\?)/) {
15797 $S2 = $tr_name{$Symbol};
15798 }
15799 }
15800 if($S1)
15801 {
Andrey Ponomarenko5c09ef32012-06-14 18:17:33 +040015802 $Report .= " <old signature=\"".xmlSpecChars($S1)."\">\n";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015803 $Report .= $P1;
15804 $Report .= " </old>\n";
15805 }
15806 if($S2 and $S2 ne $S1)
15807 {
Andrey Ponomarenko5c09ef32012-06-14 18:17:33 +040015808 $Report .= " <new signature=\"".xmlSpecChars($S2)."\">\n";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015809 $Report .= $P2;
15810 $Report .= " </new>\n";
15811 }
15812 $Report .= " </symbol>\n";
15813 }
15814 $Report .= "</symbols_info>\n";
15815 return $Report;
15816}
15817
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015818sub writeReport($$)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015819{
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015820 my ($Level, $Report) = @_;
15821 if($ReportFormat eq "xml") {
15822 $Report = "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n".$Report;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015823 }
15824 if($StdOut)
15825 { # --stdout option
15826 print STDOUT $Report;
15827 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015828 else
15829 {
15830 my $RPath = getReportPath($Level);
Andrey Ponomarenko85043792012-05-14 16:48:07 +040015831 mkpath(get_dirname($RPath));
15832
15833 open(REPORT, ">", $RPath) || die ("can't open file \'$RPath\': $!\n");
15834 print REPORT $Report;
15835 close(REPORT);
15836
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040015837 if($Browse or $OpenReport)
15838 { # open in browser
15839 openReport($RPath);
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015840 if($JoinReport or $DoubleReport)
15841 {
15842 if($Level eq "Binary")
15843 { # wait to open a browser
15844 sleep(1);
15845 }
15846 }
15847 }
15848 }
15849}
15850
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040015851sub openReport($)
15852{
15853 my $Path = $_[0];
15854 my $Cmd = "";
15855 if($Browse)
15856 { # user-defined browser
Andrey Ponomarenkoa01311b2012-06-08 17:20:02 +040015857 $Cmd = $Browse." \"$Path\"";
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040015858 }
15859 if(not $Cmd)
15860 { # default browser
15861 if($OSgroup eq "macos") {
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +040015862 $Cmd = "open \"$Path\"";
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040015863 }
15864 elsif($OSgroup eq "windows") {
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +040015865 $Cmd = "start ".path_format($Path, $OSgroup);
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040015866 }
15867 else
15868 { # linux, freebsd, solaris
15869 my @Browsers = (
15870 "x-www-browser",
15871 "sensible-browser",
15872 "firefox",
15873 "opera",
15874 "xdg-open",
15875 "lynx",
15876 "links"
15877 );
15878 foreach my $Br (@Browsers)
15879 {
15880 if($Br = get_CmdPath($Br))
15881 {
Andrey Ponomarenkoa01311b2012-06-08 17:20:02 +040015882 $Cmd = $Br." \"$Path\"";
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040015883 last;
15884 }
15885 }
15886 }
15887 }
15888 if($Cmd)
15889 {
15890 if($Debug) {
15891 printMsg("INFO", "running $Cmd");
15892 }
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +040015893 if($OSgroup ne "windows"
15894 and $OSgroup ne "macos")
15895 {
15896 if($Cmd!~/lynx|links/) {
15897 $Cmd .= " >\"$TMP_DIR/null\" 2>&1 &";
15898 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040015899 }
15900 system($Cmd);
15901 }
15902 else {
15903 printMsg("ERROR", "cannot open report in browser");
15904 }
15905}
15906
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015907sub getReport($)
15908{
15909 my $Level = $_[0];
15910 if($ReportFormat eq "xml")
15911 { # XML
15912
15913 if($Level eq "Join")
15914 {
15915 my $Report = "<reports>\n";
15916 $Report .= getReport("Binary");
15917 $Report .= getReport("Source");
15918 $Report .= "</reports>\n";
15919 return $Report;
15920 }
15921 else
15922 {
15923 my $Report = "<report kind=\"".lc($Level)."\" version=\"$XML_REPORT_VERSION\">\n\n";
15924 my ($Summary, $MetaData) = get_Summary($Level);
15925 $Report .= $Summary."\n";
15926 $Report .= get_Report_Added($Level).get_Report_Removed($Level);
15927 $Report .= get_Report_Problems("High", $Level).get_Report_Problems("Medium", $Level).get_Report_Problems("Low", $Level).get_Report_Problems("Safe", $Level);
15928 $Report .= get_Report_SymbolsInfo($Level);
15929 $Report .= "</report>\n";
15930 return $Report;
15931 }
15932 }
15933 else
15934 { # HTML
15935 my $CssStyles = readModule("Styles", "Report.css");
15936 my $JScripts = readModule("Scripts", "Sections.js");
15937 if($Level eq "Join")
15938 {
15939 $CssStyles .= "\n".readModule("Styles", "Tabs.css");
15940 $JScripts .= "\n".readModule("Scripts", "Tabs.js");
Andrey Ponomarenkob8d203d2012-05-25 18:11:07 +040015941 my $Title = $TargetLibraryFName.": ".$Descriptor{1}{"Version"}." to ".$Descriptor{2}{"Version"}." compatibility report";
15942 my $Keywords = $TargetLibraryFName.", compatibility, API, report";
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015943 my $Description = "Compatibility report for the $TargetLibraryFName $TargetComponent between ".$Descriptor{1}{"Version"}." and ".$Descriptor{2}{"Version"}." versions";
15944 my ($BSummary, $BMetaData) = get_Summary("Binary");
15945 my ($SSummary, $SMetaData) = get_Summary("Source");
15946 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>";
15947 $Report .= get_Report_Header("Join")."
15948 <br/><div class='tabset'>
Andrey Ponomarenko16934472012-03-29 15:37:04 +040015949 <a id='BinaryID' href='#BinaryTab' class='tab active'>Binary<br/>Compatibility</a>
15950 <a id='SourceID' href='#SourceTab' style='margin-left:3px' class='tab disabled'>Source<br/>Compatibility</a>
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015951 </div>";
15952 $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>";
15953 $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 +040015954 $Report .= getReportFooter($TargetLibraryFName, not $JoinReport);
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015955 $Report .= "\n<div style='height:999px;'></div>\n</body></html>";
15956 return $Report;
15957 }
15958 else
15959 {
15960 my ($Summary, $MetaData) = get_Summary($Level);
Andrey Ponomarenkob8d203d2012-05-25 18:11:07 +040015961 my $Title = $TargetLibraryFName.": ".$Descriptor{1}{"Version"}." to ".$Descriptor{2}{"Version"}." ".lc($Level)." compatibility report";
15962 my $Keywords = $TargetLibraryFName.", ".lc($Level)." compatibility, API, report";
15963 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 +040015964 if($Level eq "Binary")
15965 {
15966 if(getArch(1) eq getArch(2)
15967 and getArch(1) ne "unknown") {
15968 $Description .= " on ".showArch(getArch(1));
15969 }
15970 }
15971 my $Report = "<!-\- $MetaData -\->\n".composeHTML_Head($Title, $Keywords, $Description, $CssStyles, $JScripts)."\n<body>\n<div><a name='Top'></a>\n";
15972 $Report .= get_Report_Header($Level)."\n".$Summary."\n";
15973 $Report .= get_Report_Added($Level).get_Report_Removed($Level);
15974 $Report .= get_Report_Problems("High", $Level).get_Report_Problems("Medium", $Level).get_Report_Problems("Low", $Level).get_Report_Problems("Safe", $Level);
15975 $Report .= get_SourceInfo();
15976 $Report .= "</div>\n<br/><br/><br/><hr/>\n";
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040015977 $Report .= getReportFooter($TargetLibraryFName, not $JoinReport);
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015978 $Report .= "\n<div style='height:999px;'></div>\n</body></html>";
15979 return $Report;
15980 }
15981 }
15982}
15983
Andrey Ponomarenko16934472012-03-29 15:37:04 +040015984sub getLegend()
15985{
15986 return "<br/>
15987<table class='summary'>
15988<tr>
15989 <td class='new'>added</td>
15990 <td class='passed'>compatible</td>
15991</tr>
15992<tr>
15993 <td class='warning'>warning</td>
15994 <td class='failed'>incompatible</td>
15995</tr></table>\n";
15996}
15997
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015998sub createReport()
15999{
16000 if($JoinReport)
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040016001 { # --stdout
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040016002 writeReport("Join", getReport("Join"));
16003 }
16004 elsif($DoubleReport)
16005 { # default
16006 writeReport("Binary", getReport("Binary"));
16007 writeReport("Source", getReport("Source"));
16008 }
16009 elsif($BinaryOnly)
16010 { # --binary
16011 writeReport("Binary", getReport("Binary"));
16012 }
16013 elsif($SourceOnly)
16014 { # --source
16015 writeReport("Source", getReport("Source"));
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040016016 }
16017}
16018
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040016019sub getReportFooter($$)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040016020{
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040016021 my ($LibName, $Wide) = @_;
16022 my $FooterStyle = $Wide?"width:99%":"width:97%;padding-top:3px";
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040016023 my $Footer = "<div style='$FooterStyle;font-size:11px;' align='right'><i>Generated on ".(localtime time); # report date
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040016024 $Footer .= " for <span style='font-weight:bold'>$LibName</span>"; # tested library/system name
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040016025 $Footer .= " by <a href='".$HomePage{"Wiki"}."'>ABI Compliance Checker</a>"; # tool name
16026 my $ToolSummary = "<br/>A tool for checking backward compatibility of a C/C++ library API&#160;&#160;";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040016027 $Footer .= " $TOOL_VERSION &#160;$ToolSummary</i></div>"; # tool version
16028 return $Footer;
16029}
16030
16031sub get_Report_Problems($$)
16032{
16033 my ($Priority, $Level) = @_;
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040016034 my $Report = get_Report_TypeProblems($Priority, $Level);
Andrey Ponomarenko16934472012-03-29 15:37:04 +040016035 if(my $SProblems = get_Report_SymbolProblems($Priority, $Level)) {
16036 $Report .= $SProblems;
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040016037 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040016038 if($Priority eq "Low")
16039 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040016040 $Report .= get_Report_ChangedConstants($Level);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040016041 if($ReportFormat eq "html") {
16042 if($CheckImpl and $Level eq "Binary") {
16043 $Report .= get_Report_Impl();
16044 }
16045 }
16046 }
16047 if($ReportFormat eq "html")
16048 {
16049 if($Report)
16050 { # add anchor
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040016051 if($JoinReport)
16052 {
16053 if($Priority eq "Safe") {
16054 $Report = "<a name=\'Other_".$Level."_Changes\'></a>".$Report;
16055 }
16056 else {
16057 $Report = "<a name=\'".$Priority."_Risk_".$Level."_Problems\'></a>".$Report;
16058 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040016059 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040016060 else
16061 {
16062 if($Priority eq "Safe") {
16063 $Report = "<a name=\'Other_Changes\'></a>".$Report;
16064 }
16065 else {
16066 $Report = "<a name=\'".$Priority."_Risk_Problems\'></a>".$Report;
16067 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040016068 }
16069 }
16070 }
16071 return $Report;
16072}
16073
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040016074sub composeHTML_Head($$$$$)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040016075{
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040016076 my ($Title, $Keywords, $Description, $Styles, $Scripts) = @_;
16077 return "<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.0 Transitional//EN\" \"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd\">
16078 <html xmlns=\"http://www.w3.org/1999/xhtml\" xml:lang=\"en\" lang=\"en\">
16079 <head>
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040016080 <meta http-equiv=\"Content-Type\" content=\"text/html; charset=utf-8\" />
16081 <meta name=\"keywords\" content=\"$Keywords\" />
16082 <meta name=\"description\" content=\"$Description\" />
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040016083 <title>
16084 $Title
16085 </title>
16086 <style type=\"text/css\">
16087 $Styles
16088 </style>
16089 <script type=\"text/javascript\" language=\"JavaScript\">
16090 <!--
16091 $Scripts
16092 -->
16093 </script>
16094 </head>";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040016095}
16096
16097sub insertIDs($)
16098{
16099 my $Text = $_[0];
16100 while($Text=~/CONTENT_ID/)
16101 {
16102 if(int($Content_Counter)%2) {
16103 $ContentID -= 1;
16104 }
16105 $Text=~s/CONTENT_ID/c_$ContentID/;
16106 $ContentID += 1;
16107 $Content_Counter += 1;
16108 }
16109 return $Text;
16110}
16111
16112sub checkPreprocessedUnit($)
16113{
16114 my $Path = $_[0];
Andrey Ponomarenkoa01311b2012-06-08 17:20:02 +040016115 my ($CurHeader, $CurHeaderName) = ("", "");
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040016116 open(PREPROC, $Path) || die ("can't open file \'$Path\': $!\n");
Andrey Ponomarenkoa01311b2012-06-08 17:20:02 +040016117 while(my $Line = <PREPROC>)
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040016118 { # detecting public and private constants
Andrey Ponomarenkoa01311b2012-06-08 17:20:02 +040016119
16120 if(substr($Line, 0, 1) eq "#")
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040016121 {
Andrey Ponomarenkoa01311b2012-06-08 17:20:02 +040016122 chomp($Line);
16123 if($Line=~/\A\#\s+\d+\s+\"(.+)\"/)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040016124 {
Andrey Ponomarenkoa01311b2012-06-08 17:20:02 +040016125 $CurHeader = path_format($1, $OSgroup);
16126 $CurHeaderName = get_filename($CurHeader);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040016127 }
Andrey Ponomarenkoa01311b2012-06-08 17:20:02 +040016128 if(not $Include_Neighbors{$Version}{$CurHeaderName}
16129 and not $Registered_Headers{$Version}{$CurHeader})
16130 { # not a target
16131 next;
16132 }
16133 if(not is_target_header($CurHeaderName, 1)
16134 and not is_target_header($CurHeaderName, 2))
16135 { # user-defined header
16136 next;
16137 }
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040016138 if($Line=~/\A\#\s*define\s+(\w+)\s+(.+)\s*\Z/)
Andrey Ponomarenkoa01311b2012-06-08 17:20:02 +040016139 {
16140 my ($Name, $Value) = ($1, $2);
16141 if(not $Constants{$Version}{$Name}{"Access"})
16142 {
16143 $Constants{$Version}{$Name}{"Access"} = "public";
16144 $Constants{$Version}{$Name}{"Value"} = $Value;
16145 $Constants{$Version}{$Name}{"Header"} = $CurHeaderName;
16146 }
16147 }
16148 elsif($Line=~/\A\#[ \t]*undef[ \t]+([_A-Z]+)[ \t]*/) {
16149 $Constants{$Version}{$1}{"Access"} = "private";
16150 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040016151 }
16152 }
16153 close(PREPROC);
16154 foreach my $Constant (keys(%{$Constants{$Version}}))
16155 {
Andrey Ponomarenkoa01311b2012-06-08 17:20:02 +040016156 if($Constants{$Version}{$Constant}{"Access"} eq "private"
16157 or $Constant=~/_h\Z/i
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040016158 or isBuiltIn($Constants{$Version}{$Constant}{"Header"}))
16159 { # skip private constants
16160 delete($Constants{$Version}{$Constant});
16161 }
16162 else {
16163 delete($Constants{$Version}{$Constant}{"Access"});
16164 }
16165 }
Andrey Ponomarenkoa01311b2012-06-08 17:20:02 +040016166 if($Debug)
16167 {
16168 mkpath($DEBUG_PATH{$Version});
16169 copy($Path, $DEBUG_PATH{$Version}."/preprocessor.txt");
16170 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040016171}
16172
Andrey Ponomarenko16934472012-03-29 15:37:04 +040016173sub uncoverConstant($$)
16174{
16175 my ($LibVersion, $Constant) = @_;
16176 return "" if(not $LibVersion or not $Constant);
16177 return $Constant if(isCyclical(\@RecurConstant, $Constant));
16178 if(defined $Cache{"uncoverConstant"}{$LibVersion}{$Constant}) {
16179 return $Cache{"uncoverConstant"}{$LibVersion}{$Constant};
16180 }
16181 my $Value = $Constants{$LibVersion}{$Constant}{"Value"};
16182 if(defined $Value)
16183 {
16184 if($Value=~/\A[A-Z0-9_]+\Z/ and $Value=~/[A-Z]/)
16185 {
16186 push(@RecurConstant, $Constant);
16187 my $Uncovered = uncoverConstant($LibVersion, $Value);
16188 if($Uncovered ne "") {
16189 $Value = $Uncovered;
16190 }
16191 pop(@RecurConstant);
16192 }
16193 # FIXME: uncover $Value using all the enum constants
16194 # USECASE: change of define NC_LONG from NC_INT (enum value) to NC_INT (define)
16195 return ($Cache{"uncoverConstant"}{$LibVersion}{$Constant} = $Value);
16196 }
16197 return ($Cache{"uncoverConstant"}{$LibVersion}{$Constant} = "");
16198}
16199
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040016200my %IgnoreConstant = map {$_=>1} (
16201 "VERSION",
16202 "VERSIONCODE",
16203 "VERNUM",
16204 "VERS_INFO",
16205 "PATCHLEVEL",
16206 "INSTALLPREFIX",
16207 "VBUILD",
16208 "VPATCH",
16209 "VMINOR",
16210 "BUILD_STRING",
16211 "BUILD_TIME",
16212 "PACKAGE_STRING",
16213 "PRODUCTION",
16214 "CONFIGURE_COMMAND",
16215 "INSTALLDIR",
16216 "BINDIR",
16217 "CONFIG_FILE_PATH",
16218 "DATADIR",
16219 "EXTENSION_DIR",
16220 "INCLUDE_PATH",
16221 "LIBDIR",
16222 "LOCALSTATEDIR",
16223 "SBINDIR",
16224 "SYSCONFDIR",
16225 "RELEASE",
16226 "SOURCE_ID",
16227 "SUBMINOR",
16228 "MINOR",
16229 "MINNOR",
16230 "MINORVERSION",
16231 "MAJOR",
16232 "MAJORVERSION",
16233 "MICRO",
16234 "MICROVERSION",
16235 "BINARY_AGE",
16236 "INTERFACE_AGE",
16237 "CORE_ABI",
16238 "PATCH",
16239 "COPYRIGHT",
16240 "TIMESTAMP",
16241 "REVISION",
16242 "PACKAGE_TAG",
16243 "PACKAGEDATE",
16244 "NUMVERSION",
16245 "Release",
16246 "Version"
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040016247);
16248
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040016249sub mergeConstants($)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040016250{
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040016251 my $Level = $_[0];
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040016252 foreach my $Constant (keys(%{$Constants{1}}))
16253 {
16254 if($SkipConstants{1}{$Constant})
16255 { # skipped by the user
16256 next;
16257 }
Andrey Ponomarenko16934472012-03-29 15:37:04 +040016258 if(not defined $Constants{2}{$Constant}{"Value"}
16259 or $Constants{2}{$Constant}{"Value"} eq "")
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040016260 { # empty value
16261 next;
16262 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +040016263 my $Header = $Constants{1}{$Constant}{"Header"};
16264 if(not is_target_header($Header, 1)
16265 and not is_target_header($Header, 2))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040016266 { # user-defined header
16267 next;
16268 }
16269 my ($Old_Value, $New_Value, $Old_Value_Pure, $New_Value_Pure);
Andrey Ponomarenko16934472012-03-29 15:37:04 +040016270 $Old_Value = $Old_Value_Pure = uncoverConstant(1, $Constant);
16271 $New_Value = $New_Value_Pure = uncoverConstant(2, $Constant);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040016272 $Old_Value_Pure=~s/(\W)\s+/$1/g;
16273 $Old_Value_Pure=~s/\s+(\W)/$1/g;
16274 $New_Value_Pure=~s/(\W)\s+/$1/g;
16275 $New_Value_Pure=~s/\s+(\W)/$1/g;
16276 next if($New_Value_Pure eq "" or $Old_Value_Pure eq "");
16277 if($New_Value_Pure ne $Old_Value_Pure)
16278 { # different values
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040016279 if($Level eq "Binary")
16280 {
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040016281 foreach (keys(%IgnoreConstant))
16282 {
16283 if($Constant=~/(\A|_)$_(_|\Z)/)
16284 { # ignore library version
16285 next;
16286 }
16287 if(/\A[A-Z].*[a-z]\Z/)
16288 {
16289 if($Constant=~/(\A|[a-z])$_([A-Z]|\Z)/)
16290 { # ignore library version
16291 next;
16292 }
16293 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040016294 }
16295 if($Constant=~/(\A|_)(lib|open|)$TargetLibraryShortName(_|)(VERSION|VER|DATE|API|PREFIX)(_|\Z)/i)
16296 { # ignore library version
16297 next;
16298 }
16299 if($Old_Value=~/\A('|"|)[\/\\]\w+([\/\\]|:|('|"|)\Z)/ or $Old_Value=~/[\/\\]\w+[\/\\]\w+/)
16300 { # ignoring path defines:
Andrey Ponomarenko85043792012-05-14 16:48:07 +040016301 # /lib64:/usr/lib64:/lib:/usr/lib:/usr/X11R6/lib/Xaw3d ...
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040016302 next;
16303 }
16304 if($Old_Value=~/\A\(*[a-z_]+(\s+|\|)/i)
16305 { # ignore source defines:
Andrey Ponomarenko85043792012-05-14 16:48:07 +040016306 # static int gcry_pth_init ( void) { return ...
16307 # (RE_BACKSLASH_ESCAPE_IN_LISTS | RE...
16308 next;
16309 }
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040016310 if($Old_Value=~/\(/i and $Old_Value!~/\A[\"\']/i)
Andrey Ponomarenko85043792012-05-14 16:48:07 +040016311 { # ignore source defines:
16312 # foo(p)
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040016313 next;
16314 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040016315 }
16316 if(convert_integer($Old_Value) eq convert_integer($New_Value))
16317 { # 0x0001 and 0x1, 0x1 and 1 equal constants
16318 next;
16319 }
16320 if($Old_Value eq "0" and $New_Value eq "NULL")
16321 { # 0 => NULL
16322 next;
16323 }
16324 if($Old_Value eq "NULL" and $New_Value eq "0")
16325 { # NULL => 0
16326 next;
16327 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040016328 %{$ProblemsWithConstants{$Level}{$Constant}} = (
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040016329 "Target"=>$Constant,
16330 "Old_Value"=>$Old_Value,
16331 "New_Value"=>$New_Value );
16332 }
16333 }
16334}
16335
16336sub convert_integer($)
16337{
16338 my $Value = $_[0];
16339 if($Value=~/\A0x[a-f0-9]+\Z/)
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040016340 { # hexadecimal
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040016341 return hex($Value);
16342 }
16343 elsif($Value=~/\A0[0-7]+\Z/)
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040016344 { # octal
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040016345 return oct($Value);
16346 }
16347 elsif($Value=~/\A0b[0-1]+\Z/)
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040016348 { # binary
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040016349 return oct($Value);
16350 }
16351 else {
16352 return $Value;
16353 }
16354}
16355
Andrey Ponomarenko16934472012-03-29 15:37:04 +040016356sub readSymbols($)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040016357{
16358 my $LibVersion = $_[0];
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040016359 my @LibPaths = getSOPaths($LibVersion);
Andrey Ponomarenko16934472012-03-29 15:37:04 +040016360 if($#LibPaths==-1 and not $CheckHeadersOnly)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040016361 {
16362 if($LibVersion==1)
16363 {
16364 printMsg("WARNING", "checking headers only");
16365 $CheckHeadersOnly = 1;
16366 }
16367 else {
16368 exitStatus("Error", "$SLIB_TYPE libraries are not found in ".$Descriptor{$LibVersion}{"Version"});
16369 }
16370 }
Andrey Ponomarenko16934472012-03-29 15:37:04 +040016371 foreach my $LibPath (sort {length($a)<=>length($b)} @LibPaths) {
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040016372 readSymbols_Lib($LibVersion, $LibPath, 0, "+Weak", 1, 1);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040016373 }
Andrey Ponomarenko16934472012-03-29 15:37:04 +040016374 if(not $CheckHeadersOnly)
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040016375 {
Andrey Ponomarenko16934472012-03-29 15:37:04 +040016376 if($#LibPaths!=-1)
16377 {
16378 if(not keys(%{$Symbol_Library{$LibVersion}}))
16379 {
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040016380 printMsg("WARNING", "the set of public symbols in library(ies) is empty ($LibVersion)");
Andrey Ponomarenko16934472012-03-29 15:37:04 +040016381 printMsg("WARNING", "checking headers only");
16382 $CheckHeadersOnly = 1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040016383 }
16384 }
16385 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +040016386
Andrey Ponomarenko07aea072012-11-12 16:15:07 +040016387 # clean memory
Andrey Ponomarenko85043792012-05-14 16:48:07 +040016388 %SystemObjects = ();
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040016389}
16390
Andrey Ponomarenko16934472012-03-29 15:37:04 +040016391sub getSymbolSize($$)
16392{ # size from the shared library
16393 my ($Symbol, $LibVersion) = @_;
16394 return 0 if(not $Symbol);
16395 if(defined $Symbol_Library{$LibVersion}{$Symbol}
16396 and my $LibName = $Symbol_Library{$LibVersion}{$Symbol})
16397 {
16398 if(defined $Library_Symbol{$LibVersion}{$LibName}{$Symbol}
16399 and my $Size = $Library_Symbol{$LibVersion}{$LibName}{$Symbol})
16400 {
16401 if($Size<0) {
16402 return -$Size;
16403 }
16404 }
16405 }
16406 return 0;
16407}
16408
Andrey Ponomarenko07aea072012-11-12 16:15:07 +040016409sub canonifyName($$)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040016410{ # make TIFFStreamOpen(char const*, std::basic_ostream<char, std::char_traits<char> >*)
16411 # to be TIFFStreamOpen(char const*, std::basic_ostream<char>*)
Andrey Ponomarenko07aea072012-11-12 16:15:07 +040016412 my ($Name, $Type) = @_;
16413
16414 # single
16415 while($Name=~/([^<>,]+),\s*$DEFAULT_STD_PARMS<([^<>,]+)>\s*/ and $1 eq $3)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040016416 {
Andrey Ponomarenko85043792012-05-14 16:48:07 +040016417 my $P = $1;
Andrey Ponomarenko07aea072012-11-12 16:15:07 +040016418 $Name=~s/\Q$P\E,\s*$DEFAULT_STD_PARMS<\Q$P\E>\s*/$P/g;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040016419 }
Andrey Ponomarenko07aea072012-11-12 16:15:07 +040016420
16421 # double
16422 if($Name=~/$DEFAULT_STD_PARMS/)
16423 {
Andrey Ponomarenkoe3d6bf02012-11-14 11:49:09 +040016424 if($Type eq "S")
Andrey Ponomarenko07aea072012-11-12 16:15:07 +040016425 {
16426 my ($ShortName, $FuncParams) = split_Signature($Name);
16427
16428 foreach my $FParam (separate_Params($FuncParams, 0, 0))
16429 {
16430 if(index($FParam, "<")!=-1)
16431 {
16432 $FParam=~s/>([^<>]+)\Z/>/; # remove quals
16433 my $FParam_N = canonifyName($FParam, "T");
16434 if($FParam_N ne $FParam) {
16435 $Name=~s/\Q$FParam\E/$FParam_N/g;
16436 }
16437 }
16438 }
16439 }
16440 elsif($Type eq "T")
16441 {
16442 my ($ShortTmpl, $TmplParams) = template_Base($Name);
16443
16444 my @TParams = separate_Params($TmplParams, 0, 0);
Andrey Ponomarenkoe3d6bf02012-11-14 11:49:09 +040016445 if($#TParams>=1)
Andrey Ponomarenko07aea072012-11-12 16:15:07 +040016446 {
Andrey Ponomarenkoe3d6bf02012-11-14 11:49:09 +040016447 my $FParam = $TParams[0];
16448 foreach my $Pos (1 .. $#TParams)
16449 {
16450 my $TParam = $TParams[$Pos];
16451 if($TParam=~/\A$DEFAULT_STD_PARMS<\Q$FParam\E\s*>\Z/) {
16452 $Name=~s/\Q$FParam, $TParam\E\s*/$FParam/g;
16453 }
Andrey Ponomarenko07aea072012-11-12 16:15:07 +040016454 }
Andrey Ponomarenko07aea072012-11-12 16:15:07 +040016455 }
16456 }
16457 }
Andrey Ponomarenkoe3d6bf02012-11-14 11:49:09 +040016458 if($Type eq "S") {
16459 return formatName($Name, "S");
16460 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040016461 return $Name;
16462}
16463
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040016464sub translateSymbols(@)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040016465{
16466 my $LibVersion = pop(@_);
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040016467 my (@MnglNames1, @MnglNames2, @UnmangledNames) = ();
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040016468 foreach my $Symbol (sort @_)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040016469 {
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040016470 if(index($Symbol, "_Z")==0)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040016471 {
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040016472 next if($tr_name{$Symbol});
16473 $Symbol=~s/[\@\$]+(.*)\Z//;
16474 push(@MnglNames1, $Symbol);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040016475 }
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040016476 elsif(index($Symbol, "?")==0) {
16477 push(@MnglNames2, $Symbol);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040016478 }
16479 else
16480 { # not mangled
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040016481 $tr_name{$Symbol} = $Symbol;
16482 $mangled_name_gcc{$Symbol} = $Symbol;
16483 $mangled_name{$LibVersion}{$Symbol} = $Symbol;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040016484 }
16485 }
16486 if($#MnglNames1 > -1)
16487 { # GCC names
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040016488 @UnmangledNames = reverse(unmangleArray(@MnglNames1));
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040016489 foreach my $MnglName (@MnglNames1)
16490 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040016491 if(my $Unmangled = pop(@UnmangledNames))
16492 {
Andrey Ponomarenkoe3d6bf02012-11-14 11:49:09 +040016493 $tr_name{$MnglName} = canonifyName($Unmangled, "F");
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040016494 if(not $mangled_name_gcc{$tr_name{$MnglName}}) {
16495 $mangled_name_gcc{$tr_name{$MnglName}} = $MnglName;
16496 }
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040016497 if(index($MnglName, "_ZTV")==0
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040016498 and $tr_name{$MnglName}=~/vtable for (.+)/)
16499 { # bind class name and v-table symbol
16500 my $ClassName = $1;
16501 $ClassVTable{$ClassName} = $MnglName;
16502 $VTableClass{$MnglName} = $ClassName;
16503 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040016504 }
16505 }
16506 }
16507 if($#MnglNames2 > -1)
16508 { # MSVC names
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040016509 @UnmangledNames = reverse(unmangleArray(@MnglNames2));
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040016510 foreach my $MnglName (@MnglNames2)
16511 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040016512 if(my $Unmangled = pop(@UnmangledNames))
16513 {
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040016514 $tr_name{$MnglName} = formatName($Unmangled, "S");
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040016515 $mangled_name{$LibVersion}{$tr_name{$MnglName}} = $MnglName;
16516 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040016517 }
16518 }
16519 return \%tr_name;
16520}
16521
16522sub link_symbol($$$)
16523{
16524 my ($Symbol, $RunWith, $Deps) = @_;
16525 if(link_symbol_internal($Symbol, $RunWith, \%Symbol_Library)) {
16526 return 1;
16527 }
16528 if($Deps eq "+Deps")
16529 { # check the dependencies
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040016530 if(link_symbol_internal($Symbol, $RunWith, \%DepSymbol_Library)) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040016531 return 1;
16532 }
16533 }
16534 return 0;
16535}
16536
16537sub link_symbol_internal($$$)
16538{
16539 my ($Symbol, $RunWith, $Where) = @_;
16540 return 0 if(not $Where or not $Symbol);
16541 if($Where->{$RunWith}{$Symbol})
16542 { # the exact match by symbol name
16543 return 1;
16544 }
16545 if(my $VSym = $SymVer{$RunWith}{$Symbol})
16546 { # indirect symbol version, i.e.
16547 # foo_old and its symlink foo@v (or foo@@v)
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040016548 # foo_old may be in symtab table
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040016549 if($Where->{$RunWith}{$VSym}) {
16550 return 1;
16551 }
16552 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040016553 my ($Sym, $Spec, $Ver) = separate_symbol($Symbol);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040016554 if($Sym and $Ver)
16555 { # search for the symbol with the same version
16556 # or without version
16557 if($Where->{$RunWith}{$Sym})
16558 { # old: foo@v|foo@@v
16559 # new: foo
16560 return 1;
16561 }
16562 if($Where->{$RunWith}{$Sym."\@".$Ver})
16563 { # old: foo|foo@@v
16564 # new: foo@v
16565 return 1;
16566 }
16567 if($Where->{$RunWith}{$Sym."\@\@".$Ver})
16568 { # old: foo|foo@v
16569 # new: foo@@v
16570 return 1;
16571 }
16572 }
16573 return 0;
16574}
16575
Andrey Ponomarenko16934472012-03-29 15:37:04 +040016576sub readSymbols_App($)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040016577{
16578 my $Path = $_[0];
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040016579 return () if(not $Path);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040016580 my @Imported = ();
16581 if($OSgroup eq "macos")
16582 {
Andrey Ponomarenko07aea072012-11-12 16:15:07 +040016583 my $NM = get_CmdPath("nm");
16584 if(not $NM) {
16585 exitStatus("Not_Found", "can't find \"nm\"");
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040016586 }
Andrey Ponomarenko07aea072012-11-12 16:15:07 +040016587 open(APP, "$NM -g \"$Path\" 2>\"$TMP_DIR/null\" |");
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040016588 while(<APP>)
16589 {
Andrey Ponomarenko07aea072012-11-12 16:15:07 +040016590 if(/ U _([\w\$]+)\s*\Z/) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040016591 push(@Imported, $1);
16592 }
16593 }
16594 close(APP);
16595 }
16596 elsif($OSgroup eq "windows")
16597 {
16598 my $DumpBinCmd = get_CmdPath("dumpbin");
16599 if(not $DumpBinCmd) {
16600 exitStatus("Not_Found", "can't find \"dumpbin.exe\"");
16601 }
Andrey Ponomarenkoa01311b2012-06-08 17:20:02 +040016602 open(APP, "$DumpBinCmd /IMPORTS \"$Path\" 2>\"$TMP_DIR/null\" |");
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040016603 while(<APP>)
16604 {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040016605 if(/\s*\w+\s+\w+\s+\w+\s+([\w\?\@]+)\s*/) {
16606 push(@Imported, $1);
16607 }
16608 }
16609 close(APP);
16610 }
16611 else
16612 {
16613 my $ReadelfCmd = get_CmdPath("readelf");
16614 if(not $ReadelfCmd) {
16615 exitStatus("Not_Found", "can't find \"readelf\"");
16616 }
Andrey Ponomarenkoa01311b2012-06-08 17:20:02 +040016617 open(APP, "$ReadelfCmd -WhlSsdA \"$Path\" 2>\"$TMP_DIR/null\" |");
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040016618 my $symtab = undef; # indicates that we are processing 'symtab' section of 'readelf' output
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040016619 while(<APP>)
16620 {
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040016621 if(defined $symtab)
16622 { # do nothing with symtab
16623 if(index($_, "'.dynsym'")!=-1)
16624 { # dynamic table
16625 $symtab = undef;
16626 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040016627 }
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040016628 elsif(index($_, "'.symtab'")!=-1)
16629 { # symbol table
16630 $symtab = 1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040016631 }
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040016632 elsif(my @Info = readline_ELF($_))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040016633 {
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040016634 my ($Ndx, $Symbol) = ($Info[5], $Info[6]);
16635 if($Ndx eq "UND")
16636 { # only imported symbols
16637 push(@Imported, $Symbol);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040016638 }
16639 }
16640 }
16641 close(APP);
16642 }
16643 return @Imported;
16644}
16645
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040016646my %ELF_BIND = map {$_=>1} (
16647 "WEAK",
16648 "GLOBAL"
16649);
16650
16651my %ELF_TYPE = map {$_=>1} (
16652 "FUNC",
16653 "IFUNC",
16654 "OBJECT",
16655 "COMMON"
16656);
16657
16658my %ELF_VIS = map {$_=>1} (
16659 "DEFAULT",
16660 "PROTECTED"
16661);
16662
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040016663sub readline_ELF($)
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040016664{ # read the line of 'readelf' output corresponding to the symbol
16665 my @Info = split(/\s+/, $_[0]);
16666 # Num: Value Size Type Bind Vis Ndx Name
16667 # 3629: 000b09c0 32 FUNC GLOBAL DEFAULT 13 _ZNSt12__basic_fileIcED1Ev@@GLIBCXX_3.4
16668 shift(@Info); # spaces
16669 shift(@Info); # num
16670 if($#Info!=6)
16671 { # other lines
16672 return ();
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040016673 }
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040016674 return () if(not defined $ELF_TYPE{$Info[2]});
16675 return () if(not defined $ELF_BIND{$Info[3]});
16676 return () if(not defined $ELF_VIS{$Info[4]});
16677 if($Info[5] eq "ABS" and $Info[0]=~/\A0+\Z/)
16678 { # 1272: 00000000 0 OBJECT GLOBAL DEFAULT ABS CXXABI_1.3
16679 return ();
16680 }
16681 if($OStarget eq "symbian")
16682 { # _ZN12CCTTokenType4NewLE4TUid3RFs@@ctfinder{000a0000}[102020e5].dll
16683 if(index($Info[6], "_._.absent_export_")!=-1)
16684 { # "_._.absent_export_111"@@libstdcpp{00010001}[10282872].dll
16685 return ();
16686 }
16687 $Info[6]=~s/\@.+//g; # remove version
16688 }
16689 if(index($Info[2], "0x") == 0)
16690 { # size == 0x3d158
16691 $Info[2] = hex($Info[2]);
16692 }
16693 return @Info;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040016694}
16695
Andrey Ponomarenko16934472012-03-29 15:37:04 +040016696sub read_symlink($)
16697{
16698 my $Path = $_[0];
Andrey Ponomarenko16934472012-03-29 15:37:04 +040016699 if(my $Res = readlink($Path)) {
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040016700 return $Res;
Andrey Ponomarenko16934472012-03-29 15:37:04 +040016701 }
16702 elsif(my $ReadlinkCmd = get_CmdPath("readlink")) {
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040016703 return `$ReadlinkCmd -n \"$Path\"`;
Andrey Ponomarenko16934472012-03-29 15:37:04 +040016704 }
16705 elsif(my $FileCmd = get_CmdPath("file"))
16706 {
Andrey Ponomarenkoa01311b2012-06-08 17:20:02 +040016707 my $Info = `$FileCmd \"$Path\"`;
Andrey Ponomarenko16934472012-03-29 15:37:04 +040016708 if($Info=~/symbolic\s+link\s+to\s+['`"]*([\w\d\.\-\/\\]+)['`"]*/i) {
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040016709 return $1;
Andrey Ponomarenko16934472012-03-29 15:37:04 +040016710 }
16711 }
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040016712
16713 # can't read
16714 return "";
Andrey Ponomarenko16934472012-03-29 15:37:04 +040016715}
16716
16717sub resolve_symlink($)
16718{
16719 my $Path = $_[0];
16720 return "" if(not $Path);
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040016721
Andrey Ponomarenko16934472012-03-29 15:37:04 +040016722 if(defined $Cache{"resolve_symlink"}{$Path}) {
16723 return $Cache{"resolve_symlink"}{$Path};
16724 }
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040016725 if(not -f $Path and not -l $Path)
16726 { # broken
16727 return ($Cache{"resolve_symlink"}{$Path} = "");
16728 }
16729 return ($Cache{"resolve_symlink"}{$Path} = resolve_symlink_I($Path));
16730}
16731
16732sub resolve_symlink_I($)
16733{
16734 my $Path = $_[0];
Andrey Ponomarenko16934472012-03-29 15:37:04 +040016735 return $Path if(isCyclical(\@RecurSymlink, $Path));
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040016736 my $Res = $Path;
Andrey Ponomarenko16934472012-03-29 15:37:04 +040016737 push(@RecurSymlink, $Path);
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040016738 if(-l $Path and my $Redirect = read_symlink($Path))
Andrey Ponomarenko16934472012-03-29 15:37:04 +040016739 {
16740 if(is_abs($Redirect))
16741 { # absolute path
16742 if($SystemRoot and $SystemRoot ne "/"
16743 and $Path=~/\A\Q$SystemRoot\E\//
16744 and (-f $SystemRoot.$Redirect or -l $SystemRoot.$Redirect))
16745 { # symbolic links from the sysroot
16746 # should be corrected to point to
16747 # the files inside sysroot
16748 $Redirect = $SystemRoot.$Redirect;
16749 }
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040016750 $Res = resolve_symlink($Redirect);
Andrey Ponomarenko16934472012-03-29 15:37:04 +040016751 }
16752 elsif($Redirect=~/\.\.[\/\\]/)
16753 { # relative path
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040016754 $Redirect = joinPath(get_dirname($Path), $Redirect);
Andrey Ponomarenko16934472012-03-29 15:37:04 +040016755 while($Redirect=~s&(/|\\)[^\/\\]+(\/|\\)\.\.(\/|\\)&$1&){};
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040016756 $Res = resolve_symlink($Redirect);
Andrey Ponomarenko16934472012-03-29 15:37:04 +040016757 }
16758 elsif(-f get_dirname($Path)."/".$Redirect)
16759 { # file name in the same directory
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040016760 $Res = resolve_symlink(joinPath(get_dirname($Path), $Redirect));
Andrey Ponomarenko16934472012-03-29 15:37:04 +040016761 }
16762 else
16763 { # broken link
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040016764 $Res = "";
Andrey Ponomarenko16934472012-03-29 15:37:04 +040016765 }
16766 }
16767 pop(@RecurSymlink);
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040016768 return $Res;
Andrey Ponomarenko16934472012-03-29 15:37:04 +040016769}
16770
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040016771sub get_LibPath($$)
Andrey Ponomarenko16934472012-03-29 15:37:04 +040016772{
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040016773 my ($LibVersion, $Name) = @_;
16774 return "" if(not $LibVersion or not $Name);
16775 if(defined $Cache{"get_LibPath"}{$LibVersion}{$Name}) {
16776 return $Cache{"get_LibPath"}{$LibVersion}{$Name};
Andrey Ponomarenko16934472012-03-29 15:37:04 +040016777 }
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040016778 return ($Cache{"get_LibPath"}{$LibVersion}{$Name} = get_LibPath_I($LibVersion, $Name));
16779}
16780
16781sub get_LibPath_I($$)
16782{
16783 my ($LibVersion, $Name) = @_;
16784 if(is_abs($Name))
Andrey Ponomarenko16934472012-03-29 15:37:04 +040016785 {
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040016786 if(-f $Name)
16787 { # absolute path
16788 return $Name;
16789 }
16790 else
16791 { # broken
16792 return "";
16793 }
16794 }
Andrey Ponomarenko07aea072012-11-12 16:15:07 +040016795 if(defined $RegisteredObjects{$LibVersion}{$Name})
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040016796 { # registered paths
Andrey Ponomarenko07aea072012-11-12 16:15:07 +040016797 return $RegisteredObjects{$LibVersion}{$Name};
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040016798 }
Andrey Ponomarenko07aea072012-11-12 16:15:07 +040016799 if(defined $RegisteredSONAMEs{$LibVersion}{$Name})
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040016800 { # registered paths
Andrey Ponomarenko07aea072012-11-12 16:15:07 +040016801 return $RegisteredSONAMEs{$LibVersion}{$Name};
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040016802 }
16803 if(my $DefaultPath = $DyLib_DefaultPath{$Name})
16804 { # ldconfig default paths
16805 return $DefaultPath;
16806 }
16807 foreach my $Dir (sort keys(%DefaultLibPaths), sort keys(%{$SystemPaths{"lib"}}))
16808 { # search in default linker directories
16809 # and then in all system paths
16810 if(-f $Dir."/".$Name) {
16811 return joinPath($Dir,$Name);
16812 }
16813 }
16814 detectSystemObjects() if(not keys(%SystemObjects));
16815 if(my @AllObjects = keys(%{$SystemObjects{$Name}})) {
16816 return $AllObjects[0];
16817 }
16818 if(my $ShortName = parse_libname($Name, "name+ext", $OStarget))
16819 {
16820 if($ShortName ne $Name)
16821 { # FIXME: check this case
16822 if(my $Path = get_LibPath($LibVersion, $ShortName)) {
16823 return $Path;
Andrey Ponomarenko16934472012-03-29 15:37:04 +040016824 }
16825 }
Andrey Ponomarenko16934472012-03-29 15:37:04 +040016826 }
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040016827 # can't find
16828 return "";
Andrey Ponomarenko16934472012-03-29 15:37:04 +040016829}
16830
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040016831sub readSymbols_Lib($$$$$$)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040016832{
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040016833 my ($LibVersion, $Lib_Path, $IsNeededLib, $Weak, $Deps, $Vers) = @_;
16834 return () if(not $LibVersion or not $Lib_Path);
16835 my $Lib_Name = get_filename(resolve_symlink($Lib_Path));
16836 if($IsNeededLib)
16837 {
16838 if($CheckedDyLib{$LibVersion}{$Lib_Name}) {
16839 return ();
16840 }
16841 }
16842 return () if(isCyclical(\@RecurLib, $Lib_Name) or $#RecurLib>=1);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040016843 $CheckedDyLib{$LibVersion}{$Lib_Name} = 1;
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040016844
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040016845 if($CheckImpl)
16846 {
16847 if(not $IsNeededLib) {
16848 getImplementations($LibVersion, $Lib_Path);
16849 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040016850 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040016851
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040016852 push(@RecurLib, $Lib_Name);
16853 my (%Value_Interface, %Interface_Value, %NeededLib) = ();
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040016854 my $Lib_ShortName = parse_libname($Lib_Name, "short", $OStarget);
16855 if($IsNeededLib)
16856 { # change short name to use later for needed libraries
16857 $Lib_ShortName = parse_libname($Lib_Name, "name+ext", $OStarget);
16858 }
16859 else
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040016860 { # libstdc++ and libc are always used by other libs
16861 # if you test one of these libs then you not need
16862 # to find them in the system for reusing
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040016863 if($Lib_ShortName eq "libstdc++")
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040016864 { # libstdc++.so.6
16865 $STDCXX_TESTING = 1;
16866 }
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040016867 elsif($Lib_ShortName eq "libc")
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040016868 { # libc-2.11.3.so
16869 $GLIBC_TESTING = 1;
16870 }
16871 }
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040016872 my $DebugPath = "";
Andrey Ponomarenkoa01311b2012-06-08 17:20:02 +040016873 if($Debug and not $DumpSystem)
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040016874 { # debug mode
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040016875 $DebugPath = $DEBUG_PATH{$LibVersion}."/libs/".get_filename($Lib_Path).".txt";
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040016876 mkpath(get_dirname($DebugPath));
16877 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040016878 if($OStarget eq "macos")
16879 { # Mac OS X: *.dylib, *.a
Andrey Ponomarenko07aea072012-11-12 16:15:07 +040016880 my $NM = get_CmdPath("nm");
16881 if(not $NM)
16882 {
16883 print STDERR "ERROR: can't find \"nm\"\n";
16884 exit(1);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040016885 }
Andrey Ponomarenko07aea072012-11-12 16:15:07 +040016886 $NM .= " -g \"$Lib_Path\" 2>\"$TMP_DIR/null\"";
Andrey Ponomarenkoa01311b2012-06-08 17:20:02 +040016887 if($DebugPath)
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040016888 { # debug mode
Andrey Ponomarenko16934472012-03-29 15:37:04 +040016889 # write to file
Andrey Ponomarenko07aea072012-11-12 16:15:07 +040016890 system($NM." >\"$DebugPath\"");
Andrey Ponomarenko16934472012-03-29 15:37:04 +040016891 open(LIB, $DebugPath);
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040016892 }
Andrey Ponomarenko16934472012-03-29 15:37:04 +040016893 else
16894 { # write to pipe
Andrey Ponomarenko07aea072012-11-12 16:15:07 +040016895 open(LIB, $NM." |");
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040016896 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040016897 while(<LIB>)
16898 {
Andrey Ponomarenko07aea072012-11-12 16:15:07 +040016899 if(/ [STD] _([\w\$]+)\s*\Z/)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040016900 {
16901 my $realname = $1;
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040016902 if($IsNeededLib)
16903 {
Andrey Ponomarenko07aea072012-11-12 16:15:07 +040016904 if(not defined $RegisteredObjects_Short{$Lib_ShortName})
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040016905 {
16906 $DepSymbol_Library{$LibVersion}{$realname} = $Lib_Name;
16907 $DepLibrary_Symbol{$LibVersion}{$Lib_Name}{$realname} = 1;
16908 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040016909 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040016910 else
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040016911 {
16912 $Symbol_Library{$LibVersion}{$realname} = $Lib_Name;
16913 $Library_Symbol{$LibVersion}{$Lib_Name}{$realname} = 1;
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040016914 if($COMMON_LANGUAGE{$LibVersion} ne "C++")
16915 {
16916 if(index($realname, "_Z")==0 or index($realname, "?")==0) {
16917 setLanguage($LibVersion, "C++");
16918 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040016919 }
16920 if($CheckObjectsOnly
16921 and $LibVersion==1) {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040016922 $CheckedSymbols{"Binary"}{$realname} = 1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040016923 }
16924 }
16925 }
16926 }
16927 close(LIB);
Andrey Ponomarenko07aea072012-11-12 16:15:07 +040016928
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040016929 if($Deps)
16930 {
16931 if($LIB_TYPE eq "dynamic")
16932 { # dependencies
Andrey Ponomarenko07aea072012-11-12 16:15:07 +040016933
16934 my $OtoolCmd = get_CmdPath("otool");
16935 if(not $OtoolCmd)
16936 {
16937 print STDERR "ERROR: can't find \"otool\"\n";
16938 exit(1);
16939 }
16940
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040016941 open(LIB, "$OtoolCmd -L \"$Lib_Path\" 2>\"$TMP_DIR/null\" |");
16942 while(<LIB>)
16943 {
16944 if(/\s*([\/\\].+\.$LIB_EXT)\s*/
16945 and $1 ne $Lib_Path) {
16946 $NeededLib{$1} = 1;
16947 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040016948 }
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040016949 close(LIB);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040016950 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040016951 }
16952 }
16953 elsif($OStarget eq "windows")
16954 { # Windows *.dll, *.lib
16955 my $DumpBinCmd = get_CmdPath("dumpbin");
16956 if(not $DumpBinCmd) {
16957 exitStatus("Not_Found", "can't find \"dumpbin\"");
16958 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040016959 $DumpBinCmd .= " /EXPORTS \"".$Lib_Path."\" 2>$TMP_DIR/null";
Andrey Ponomarenkoa01311b2012-06-08 17:20:02 +040016960 if($DebugPath)
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040016961 { # debug mode
Andrey Ponomarenko16934472012-03-29 15:37:04 +040016962 # write to file
Andrey Ponomarenkoa01311b2012-06-08 17:20:02 +040016963 system($DumpBinCmd." >\"$DebugPath\"");
Andrey Ponomarenko16934472012-03-29 15:37:04 +040016964 open(LIB, $DebugPath);
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040016965 }
Andrey Ponomarenko16934472012-03-29 15:37:04 +040016966 else
16967 { # write to pipe
16968 open(LIB, $DumpBinCmd." |");
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040016969 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040016970 while(<LIB>)
16971 { # 1197 4AC 0000A620 SetThreadStackGuarantee
16972 # 1198 4AD SetThreadToken (forwarded to ...)
16973 # 3368 _o2i_ECPublicKey
16974 if(/\A\s*\d+\s+[a-f\d]+\s+[a-f\d]+\s+([\w\?\@]+)\s*\Z/i
16975 or /\A\s*\d+\s+[a-f\d]+\s+([\w\?\@]+)\s*\(\s*forwarded\s+/
16976 or /\A\s*\d+\s+_([\w\?\@]+)\s*\Z/)
16977 { # dynamic, static and forwarded symbols
16978 my $realname = $1;
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040016979 if($IsNeededLib)
16980 {
Andrey Ponomarenko07aea072012-11-12 16:15:07 +040016981 if(not defined $RegisteredObjects_Short{$Lib_ShortName})
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040016982 {
16983 $DepSymbol_Library{$LibVersion}{$realname} = $Lib_Name;
16984 $DepLibrary_Symbol{$LibVersion}{$Lib_Name}{$realname} = 1;
16985 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040016986 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040016987 else
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040016988 {
16989 $Symbol_Library{$LibVersion}{$realname} = $Lib_Name;
16990 $Library_Symbol{$LibVersion}{$Lib_Name}{$realname} = 1;
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040016991 if($COMMON_LANGUAGE{$LibVersion} ne "C++")
16992 {
16993 if(index($realname, "_Z")==0 or index($realname, "?")==0) {
16994 setLanguage($LibVersion, "C++");
16995 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040016996 }
16997 if($CheckObjectsOnly
16998 and $LibVersion==1) {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040016999 $CheckedSymbols{"Binary"}{$realname} = 1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017000 }
17001 }
17002 }
17003 }
17004 close(LIB);
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040017005 if($Deps)
17006 {
17007 if($LIB_TYPE eq "dynamic")
17008 { # dependencies
17009 open(LIB, "$DumpBinCmd /DEPENDENTS \"$Lib_Path\" 2>\"$TMP_DIR/null\" |");
17010 while(<LIB>)
17011 {
17012 if(/\s*([^\s]+?\.$LIB_EXT)\s*/i
17013 and $1 ne $Lib_Path) {
17014 $NeededLib{path_format($1, $OSgroup)} = 1;
17015 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017016 }
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040017017 close(LIB);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017018 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017019 }
17020 }
17021 else
17022 { # Unix; *.so, *.a
17023 # Symbian: *.dso, *.lib
17024 my $ReadelfCmd = get_CmdPath("readelf");
17025 if(not $ReadelfCmd) {
17026 exitStatus("Not_Found", "can't find \"readelf\"");
17027 }
Andrey Ponomarenkoa01311b2012-06-08 17:20:02 +040017028 $ReadelfCmd .= " -WhlSsdA \"$Lib_Path\" 2>\"$TMP_DIR/null\"";
17029 if($DebugPath)
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040017030 { # debug mode
Andrey Ponomarenko16934472012-03-29 15:37:04 +040017031 # write to file
Andrey Ponomarenkoa01311b2012-06-08 17:20:02 +040017032 system($ReadelfCmd." >\"$DebugPath\"");
Andrey Ponomarenko16934472012-03-29 15:37:04 +040017033 open(LIB, $DebugPath);
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040017034 }
Andrey Ponomarenko16934472012-03-29 15:37:04 +040017035 else
17036 { # write to pipe
17037 open(LIB, $ReadelfCmd." |");
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040017038 }
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040017039 my $symtab = undef; # indicates that we are processing 'symtab' section of 'readelf' output
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017040 while(<LIB>)
17041 {
17042 if($LIB_TYPE eq "dynamic")
17043 { # dynamic library specifics
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040017044 if(defined $symtab)
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040017045 {
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040017046 if(index($_, "'.dynsym'")!=-1)
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040017047 { # dynamic table
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040017048 $symtab = undef;
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040017049 }
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040017050 # do nothing with symtab
17051 next;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017052 }
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040017053 elsif(index($_, "'.symtab'")!=-1)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017054 { # symbol table
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040017055 $symtab = 1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017056 next;
17057 }
17058 }
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040017059 if(my ($Value, $Size, $Type, $Bind, $Vis, $Ndx, $Symbol) = readline_ELF($_))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017060 { # read ELF entry
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040017061 if($Ndx eq "UND")
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017062 { # ignore interfaces that are imported from somewhere else
17063 next;
17064 }
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040017065 if($Bind eq "WEAK"
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017066 and $Weak eq "-Weak")
17067 { # skip WEAK symbols
Andrey Ponomarenko07aea072012-11-12 16:15:07 +040017068 $WeakSymbols{$LibVersion}{$Symbol} = 1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017069 next;
17070 }
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040017071 my $Short = $Symbol;
17072 $Short=~s/\@.+//g;
17073 if($Type eq "OBJECT")
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017074 { # global data
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040017075 $GlobalDataObject{$LibVersion}{$Symbol} = 1;
17076 $GlobalDataObject{$LibVersion}{$Short} = 1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017077 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040017078 if($IsNeededLib)
17079 {
Andrey Ponomarenko07aea072012-11-12 16:15:07 +040017080 if(not defined $RegisteredObjects_Short{$Lib_ShortName})
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040017081 {
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040017082 $DepSymbol_Library{$LibVersion}{$Symbol} = $Lib_Name;
17083 $DepLibrary_Symbol{$LibVersion}{$Lib_Name}{$Symbol} = ($Type eq "OBJECT")?-$Size:1;
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040017084 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017085 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040017086 else
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017087 {
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040017088 $Symbol_Library{$LibVersion}{$Symbol} = $Lib_Name;
17089 $Library_Symbol{$LibVersion}{$Lib_Name}{$Symbol} = ($Type eq "OBJECT")?-$Size:1;
17090 if($Vers)
17091 {
17092 if($LIB_EXT eq "so")
17093 { # value
17094 $Interface_Value{$LibVersion}{$Symbol} = $Value;
17095 $Value_Interface{$LibVersion}{$Value}{$Symbol} = 1;
17096 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017097 }
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040017098 if($COMMON_LANGUAGE{$LibVersion} ne "C++")
17099 {
17100 if(index($Symbol, "_Z")==0 or index($Symbol, "?")==0) {
17101 setLanguage($LibVersion, "C++");
17102 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017103 }
17104 if($CheckObjectsOnly
17105 and $LibVersion==1) {
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040017106 $CheckedSymbols{"Binary"}{$Symbol} = 1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017107 }
17108 }
17109 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040017110 elsif($LIB_TYPE eq "dynamic")
17111 { # dynamic library specifics
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040017112 if($Deps)
17113 {
17114 if(/NEEDED.+\[([^\[\]]+)\]/)
17115 { # dependencies:
17116 # 0x00000001 (NEEDED) Shared library: [libc.so.6]
17117 $NeededLib{$1} = 1;
17118 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040017119 }
17120 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017121 }
17122 close(LIB);
17123 }
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040017124 if($Vers)
17125 {
17126 if(not $IsNeededLib and $LIB_EXT eq "so")
17127 { # get symbol versions
17128 foreach my $Symbol (keys(%{$Symbol_Library{$LibVersion}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017129 {
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040017130 next if(index($Symbol,"\@")==-1);
17131 if(my $Value = $Interface_Value{$LibVersion}{$Symbol})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017132 {
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040017133 my $Interface_SymName = "";
17134 foreach my $Symbol_SameValue (keys(%{$Value_Interface{$LibVersion}{$Value}}))
Andrey Ponomarenkoa01311b2012-06-08 17:20:02 +040017135 {
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040017136 if($Symbol_SameValue ne $Symbol
17137 and index($Symbol_SameValue,"\@")==-1)
17138 {
17139 $SymVer{$LibVersion}{$Symbol_SameValue} = $Symbol;
17140 $Interface_SymName = $Symbol_SameValue;
17141 last;
17142 }
Andrey Ponomarenkoa01311b2012-06-08 17:20:02 +040017143 }
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040017144 if(not $Interface_SymName)
17145 {
17146 if($Symbol=~/\A([^\@\$\?]*)[\@\$]+([^\@\$]*)\Z/
17147 and not $SymVer{$LibVersion}{$1}) {
17148 $SymVer{$LibVersion}{$1} = $Symbol;
17149 }
Andrey Ponomarenkoa01311b2012-06-08 17:20:02 +040017150 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017151 }
17152 }
17153 }
17154 }
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040017155 if($Deps)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017156 {
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040017157 foreach my $DyLib (sort keys(%NeededLib))
17158 {
17159 if(my $DepPath = get_LibPath($LibVersion, $DyLib)) {
17160 readSymbols_Lib($LibVersion, $DepPath, 1, "+Weak", $Deps, $Vers);
17161 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017162 }
17163 }
17164 pop(@RecurLib);
17165 return $Library_Symbol{$LibVersion};
17166}
17167
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040017168sub get_prefixes($)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017169{
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017170 my %Prefixes = ();
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040017171 get_prefixes_I([$_[0]], \%Prefixes);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017172 return keys(%Prefixes);
17173}
17174
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040017175sub get_prefixes_I($$)
17176{
17177 foreach my $P (@{$_[0]})
17178 {
17179 my @Parts = reverse(split(/[\/\\]+/, $P));
17180 my $Name = $Parts[0];
17181 foreach (1 .. $#Parts)
17182 {
17183 $_[1]->{$Name}{$P} = 1;
17184 last if($_>4 or $Parts[$_] eq "include");
17185 $Name = $Parts[$_].$SLASH.$Name;
17186 }
17187 }
17188}
17189
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017190sub detectSystemHeaders()
17191{
17192 my @SysHeaders = ();
17193 foreach my $DevelPath (keys(%{$SystemPaths{"include"}}))
17194 {
17195 next if(not -d $DevelPath);
17196 # search for all header files in the /usr/include
17197 # with or without extension (ncurses.h, QtCore, ...)
17198 @SysHeaders = (@SysHeaders, cmd_find($DevelPath,"f","",""));
17199 foreach my $Link (cmd_find($DevelPath,"l","",""))
17200 { # add symbolic links
17201 if(-f $Link) {
17202 push(@SysHeaders, $Link);
17203 }
17204 }
17205 }
17206 foreach my $DevelPath (keys(%{$SystemPaths{"lib"}}))
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040017207 { # search for config headers in the /usr/lib
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017208 next if(not -d $DevelPath);
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040017209 foreach (cmd_find($DevelPath,"f","",""))
17210 {
17211 if(not /\/(gcc|jvm|syslinux|kbd|parrot|xemacs)/)
17212 {
17213 if(/\.h\Z|\/include\//) {
17214 push(@SysHeaders, $_);
17215 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017216 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017217 }
17218 }
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040017219 get_prefixes_I(\@SysHeaders, \%SystemHeaders);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017220}
17221
17222sub detectSystemObjects()
17223{
17224 foreach my $DevelPath (keys(%{$SystemPaths{"lib"}}))
17225 {
17226 next if(not -d $DevelPath);
17227 foreach my $Path (find_libs($DevelPath,"",""))
17228 { # search for shared libraries in the /usr/lib (including symbolic links)
17229 $SystemObjects{parse_libname(get_filename($Path), "name+ext", $OStarget)}{$Path}=1;
17230 }
17231 }
17232}
17233
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040017234sub getSOPaths($)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017235{
17236 my $LibVersion = $_[0];
17237 my @SoPaths = ();
17238 foreach my $Dest (split(/\s*\n\s*/, $Descriptor{$LibVersion}{"Libs"}))
17239 {
17240 if(not -e $Dest) {
17241 exitStatus("Access_Error", "can't access \'$Dest\'");
17242 }
17243 my @SoPaths_Dest = getSOPaths_Dest($Dest, $LibVersion);
17244 foreach (@SoPaths_Dest) {
17245 push(@SoPaths, $_);
17246 }
17247 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040017248 return sort @SoPaths;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017249}
17250
17251sub skip_lib($$)
17252{
17253 my ($Path, $LibVersion) = @_;
17254 return 1 if(not $Path or not $LibVersion);
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040017255 my $Name = get_filename($Path);
17256 if($SkipLibs{$LibVersion}{"Name"}{$Name}) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017257 return 1;
17258 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040017259 my $ShortName = parse_libname($Name, "name+ext", $OStarget);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017260 if($SkipLibs{$LibVersion}{"Name"}{$ShortName}) {
17261 return 1;
17262 }
17263 foreach my $Dir (keys(%{$SkipLibs{$LibVersion}{"Path"}}))
17264 {
17265 if($Path=~/\Q$Dir\E([\/\\]|\Z)/) {
17266 return 1;
17267 }
17268 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040017269 foreach my $P (keys(%{$SkipLibs{$LibVersion}{"Pattern"}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017270 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040017271 if($Name=~/$P/) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017272 return 1;
17273 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040017274 if($P=~/[\/\\]/ and $Path=~/$P/) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017275 return 1;
17276 }
17277 }
17278 return 0;
17279}
17280
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040017281sub skipHeader($$)
17282{
17283 my ($Path, $LibVersion) = @_;
17284 return 1 if(not $Path or not $LibVersion);
17285 if(not keys(%{$SkipHeaders{$LibVersion}})) {
17286 return 0;
17287 }
17288 if(defined $Cache{"skipHeader"}{$Path}) {
17289 return $Cache{"skipHeader"}{$Path};
17290 }
17291 return ($Cache{"skipHeader"}{$Path} = skipHeader_I(@_));
17292}
17293
17294sub skipHeader_I($$)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017295{ # returns:
17296 # 1 - if header should NOT be included and checked
17297 # 2 - if header should NOT be included, but should be checked
17298 my ($Path, $LibVersion) = @_;
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040017299 my $Name = get_filename($Path);
17300 if(my $Kind = $SkipHeaders{$LibVersion}{"Name"}{$Name}) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017301 return $Kind;
17302 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040017303 foreach my $D (keys(%{$SkipHeaders{$LibVersion}{"Path"}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017304 {
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040017305 if(index($Path, $D)!=-1)
17306 {
17307 if($Path=~/\Q$D\E([\/\\]|\Z)/) {
17308 return $SkipHeaders{$LibVersion}{"Path"}{$D};
17309 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017310 }
17311 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040017312 foreach my $P (keys(%{$SkipHeaders{$LibVersion}{"Pattern"}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017313 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040017314 if(my $Kind = $SkipHeaders{$LibVersion}{"Pattern"}{$P})
17315 {
17316 if($Name=~/$P/) {
17317 return $Kind;
17318 }
17319 if($P=~/[\/\\]/ and $Path=~/$P/) {
17320 return $Kind;
17321 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017322 }
17323 }
17324 return 0;
17325}
17326
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040017327sub registerObject_Dir($$)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017328{
17329 my ($Dir, $LibVersion) = @_;
17330 if($SystemPaths{"lib"}{$Dir})
17331 { # system directory
17332 return;
17333 }
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040017334 if($RegisteredObject_Dirs{$LibVersion}{$Dir})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017335 { # already registered
17336 return;
17337 }
17338 foreach my $Path (find_libs($Dir,"",1))
17339 {
17340 next if(ignore_path($Path));
17341 next if(skip_lib($Path, $LibVersion));
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040017342 registerObject($Path, $LibVersion);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017343 }
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040017344 $RegisteredObject_Dirs{$LibVersion}{$Dir} = 1;
17345}
17346
17347sub registerObject($$)
17348{
17349 my ($Path, $LibVersion) = @_;
17350 my $Name = get_filename($Path);
Andrey Ponomarenko07aea072012-11-12 16:15:07 +040017351 $RegisteredObjects{$LibVersion}{$Name} = $Path;
Andrey Ponomarenko27681702012-11-12 16:33:39 +040017352 if($OSgroup=~/linux|bsd/i)
17353 {
17354 if(my $SONAME = getSONAME($Path)) {
17355 $RegisteredSONAMEs{$LibVersion}{$SONAME} = $Path;
17356 }
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040017357 }
17358 if(my $SName = parse_libname($Name, "name", $OStarget)) {
Andrey Ponomarenko07aea072012-11-12 16:15:07 +040017359 $RegisteredObjects_Short{$LibVersion}{$SName} = $Path;
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040017360 }
17361}
17362
17363sub getSONAME($)
17364{
17365 my $Path = $_[0];
17366 return if(not $Path);
17367 if(defined $Cache{"getSONAME"}{$Path}) {
17368 return $Cache{"getSONAME"}{$Path};
17369 }
17370 my $ObjdumpCmd = get_CmdPath("objdump");
17371 if(not $ObjdumpCmd) {
17372 exitStatus("Not_Found", "can't find \"objdump\"");
17373 }
17374 my $SonameCmd = "$ObjdumpCmd -x $Path 2>$TMP_DIR/null";
17375 if($OSgroup eq "windows") {
17376 $SonameCmd .= " | find \"SONAME\"";
17377 }
17378 else {
17379 $SonameCmd .= " | grep SONAME";
17380 }
17381 if(my $SonameInfo = `$SonameCmd`) {
17382 if($SonameInfo=~/SONAME\s+([^\s]+)/) {
17383 return ($Cache{"getSONAME"}{$Path} = $1);
17384 }
17385 }
17386 return ($Cache{"getSONAME"}{$Path}="");
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017387}
17388
17389sub getSOPaths_Dest($$)
17390{
17391 my ($Dest, $LibVersion) = @_;
17392 if(skip_lib($Dest, $LibVersion)) {
17393 return ();
17394 }
17395 if(-f $Dest)
17396 {
17397 if(not parse_libname($Dest, "name", $OStarget)) {
17398 exitStatus("Error", "incorrect format of library (should be *.$LIB_EXT): \'$Dest\'");
17399 }
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040017400 registerObject($Dest, $LibVersion);
17401 registerObject_Dir(get_dirname($Dest), $LibVersion);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017402 return ($Dest);
17403 }
17404 elsif(-d $Dest)
17405 {
17406 $Dest=~s/[\/\\]+\Z//g;
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040017407 my %Libs = ();
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017408 if($SystemPaths{"lib"}{$Dest})
17409 { # you have specified /usr/lib as the search directory (<libs>) in the XML descriptor
17410 # and the real name of the library by -l option (bz2, stdc++, Xaw, ...)
17411 foreach my $Path (cmd_find($Dest,"","*".esc($TargetLibraryName)."*\.$LIB_EXT*",2))
17412 { # all files and symlinks that match the name of a library
17413 if(get_filename($Path)=~/\A(|lib)\Q$TargetLibraryName\E[\d\-]*\.$LIB_EXT[\d\.]*\Z/i)
17414 {
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040017415 registerObject($Path, $LibVersion);
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040017416 $Libs{resolve_symlink($Path)}=1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017417 }
17418 }
17419 }
17420 else
17421 { # search for all files and symlinks
17422 foreach my $Path (find_libs($Dest,"",""))
17423 {
17424 next if(ignore_path($Path));
17425 next if(skip_lib($Path, $LibVersion));
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040017426 registerObject($Path, $LibVersion);
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040017427 $Libs{resolve_symlink($Path)}=1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017428 }
17429 if($OSgroup eq "macos")
17430 { # shared libraries on MacOS X may have no extension
17431 foreach my $Path (cmd_find($Dest,"f","",""))
17432 {
17433 next if(ignore_path($Path));
17434 next if(skip_lib($Path, $LibVersion));
17435 if(get_filename($Path)!~/\./
Andrey Ponomarenko85043792012-05-14 16:48:07 +040017436 and cmd_file($Path)=~/(shared|dynamic)\s+library/i)
17437 {
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040017438 registerObject($Path, $LibVersion);
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040017439 $Libs{resolve_symlink($Path)}=1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017440 }
17441 }
17442 }
17443 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040017444 return keys(%Libs);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017445 }
17446 else {
17447 return ();
17448 }
17449}
17450
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040017451sub isCyclical($$)
17452{
17453 my ($Stack, $Value) = @_;
17454 return (grep {$_ eq $Value} @{$Stack});
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017455}
17456
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017457sub generateTemplate()
17458{
17459 writeFile("VERSION.xml", $DescriptorTemplate."\n");
17460 printMsg("INFO", "XML-descriptor template ./VERSION.xml has been generated");
17461}
17462
17463sub detectWordSize()
17464{
17465 return "" if(not $GCC_PATH);
17466 if($Cache{"detectWordSize"}) {
17467 return $Cache{"detectWordSize"};
17468 }
17469 writeFile("$TMP_DIR/empty.h", "");
Andrey Ponomarenkoa01311b2012-06-08 17:20:02 +040017470 my $Defines = `$GCC_PATH -E -dD \"$TMP_DIR/empty.h\"`;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017471 unlink("$TMP_DIR/empty.h");
17472 my $WSize = 0;
17473 if($Defines=~/ __SIZEOF_POINTER__\s+(\d+)/)
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040017474 { # GCC 4
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017475 $WSize = $1;
17476 }
17477 elsif($Defines=~/ __PTRDIFF_TYPE__\s+(\w+)/)
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040017478 { # GCC 3
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017479 my $PTRDIFF = $1;
17480 if($PTRDIFF=~/long/) {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040017481 $WSize = "8";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017482 }
17483 else {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040017484 $WSize = "4";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017485 }
17486 }
Andrey Ponomarenko01117f12012-06-26 12:23:02 +040017487 if(not $WSize) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017488 exitStatus("Error", "can't check WORD size");
17489 }
17490 return ($Cache{"detectWordSize"} = $WSize);
17491}
17492
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +040017493sub getWordSize($) {
17494 return $WORD_SIZE{$_[0]};
17495}
17496
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017497sub majorVersion($)
17498{
17499 my $V = $_[0];
17500 return 0 if(not $V);
17501 my @VParts = split(/\./, $V);
17502 return $VParts[0];
17503}
17504
17505sub cmpVersions($$)
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040017506{ # compare two versions in dotted-numeric format
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017507 my ($V1, $V2) = @_;
17508 return 0 if($V1 eq $V2);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017509 my @V1Parts = split(/\./, $V1);
17510 my @V2Parts = split(/\./, $V2);
17511 for (my $i = 0; $i <= $#V1Parts && $i <= $#V2Parts; $i++) {
17512 return -1 if(int($V1Parts[$i]) < int($V2Parts[$i]));
17513 return 1 if(int($V1Parts[$i]) > int($V2Parts[$i]));
17514 }
17515 return -1 if($#V1Parts < $#V2Parts);
17516 return 1 if($#V1Parts > $#V2Parts);
17517 return 0;
17518}
17519
17520sub read_ABI_Dump($$)
17521{
17522 my ($LibVersion, $Path) = @_;
17523 return if(not $LibVersion or not -e $Path);
17524 my $FilePath = "";
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040017525 if(isDump_U($Path))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017526 { # input *.abi
17527 $FilePath = $Path;
17528 }
17529 else
17530 { # input *.abi.tar.gz
17531 $FilePath = unpackDump($Path);
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040017532 if(not isDump_U($FilePath)) {
17533 exitStatus("Invalid_Dump", "specified ABI dump \'$Path\' is not valid, try to recreate it");
17534 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017535 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +040017536
Andrey Ponomarenko01117f12012-06-26 12:23:02 +040017537 my $ABI = {};
Andrey Ponomarenko5c09ef32012-06-14 18:17:33 +040017538
Andrey Ponomarenko01117f12012-06-26 12:23:02 +040017539 my $Line = readLineNum($FilePath, 0);
17540 if($Line=~/xml/)
17541 { # XML format
17542 loadModule("XmlDump");
17543 $ABI = readXmlDump($FilePath);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017544 }
Andrey Ponomarenko01117f12012-06-26 12:23:02 +040017545 else
17546 { # Perl Data::Dumper format (default)
17547 open(DUMP, $FilePath);
17548 local $/ = undef;
17549 my $Content = <DUMP>;
17550 close(DUMP);
17551
17552 if(get_dirname($FilePath) eq $TMP_DIR."/unpack")
17553 { # remove temp file
17554 unlink($FilePath);
17555 }
17556 if($Content!~/};\s*\Z/) {
17557 exitStatus("Invalid_Dump", "specified ABI dump \'$Path\' is not valid, try to recreate it");
17558 }
17559 $ABI = eval($Content);
17560 if(not $ABI) {
17561 exitStatus("Error", "internal error - eval() procedure seem to not working correctly, try to remove 'use strict' and try again");
17562 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017563 }
17564 # new dumps (>=1.22) have a personal versioning
Andrey Ponomarenko01117f12012-06-26 12:23:02 +040017565 my $DumpVersion = $ABI->{"ABI_DUMP_VERSION"};
17566 my $ToolVersion = $ABI->{"ABI_COMPLIANCE_CHECKER_VERSION"};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017567 if(not $DumpVersion)
17568 { # old dumps (<=1.21.6) have been marked by the tool version
17569 $DumpVersion = $ToolVersion;
17570 }
17571 $UsedDump{$LibVersion}{"V"} = $DumpVersion;
17572 if(majorVersion($DumpVersion) ne majorVersion($ABI_DUMP_VERSION))
17573 { # should be compatible with dumps of the same major version
17574 if(cmpVersions($DumpVersion, $ABI_DUMP_VERSION)>0)
17575 { # Don't know how to parse future dump formats
Andrey Ponomarenko01117f12012-06-26 12:23:02 +040017576 exitStatus("Dump_Version", "incompatible version \'$DumpVersion\' of specified ABI dump (newer than $ABI_DUMP_VERSION)");
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017577 }
Andrey Ponomarenko01117f12012-06-26 12:23:02 +040017578 elsif(cmpVersions($DumpVersion, $TOOL_VERSION)>0 and not $ABI->{"ABI_DUMP_VERSION"})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017579 { # Don't know how to parse future dump formats
Andrey Ponomarenko01117f12012-06-26 12:23:02 +040017580 exitStatus("Dump_Version", "incompatible version \'$DumpVersion\' of specified ABI dump (newer than $TOOL_VERSION)");
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017581 }
17582 if($UseOldDumps)
17583 {
17584 if(cmpVersions($DumpVersion, $OLDEST_SUPPORTED_VERSION)<0) {
Andrey Ponomarenko01117f12012-06-26 12:23:02 +040017585 exitStatus("Dump_Version", "incompatible version \'$DumpVersion\' of specified ABI dump (older than $OLDEST_SUPPORTED_VERSION)");
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017586 }
17587 }
17588 else
17589 {
Andrey Ponomarenko01117f12012-06-26 12:23:02 +040017590 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 +040017591 if(cmpVersions($DumpVersion, $OLDEST_SUPPORTED_VERSION)>=0) {
17592 $Msg .= "\nUse -old-dumps option to use old-version dumps ($OLDEST_SUPPORTED_VERSION<=V<".majorVersion($ABI_DUMP_VERSION).".0)";
17593 }
17594 exitStatus("Dump_Version", $Msg);
17595 }
17596 }
Andrey Ponomarenko5c09ef32012-06-14 18:17:33 +040017597 if(not checkDump($LibVersion, "2.11"))
17598 { # old ABI dumps
17599 $UsedDump{$LibVersion}{"BinOnly"} = 1;
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040017600 }
Andrey Ponomarenko01117f12012-06-26 12:23:02 +040017601 elsif($ABI->{"BinOnly"})
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040017602 { # ABI dump created with --binary option
17603 $UsedDump{$LibVersion}{"BinOnly"} = 1;
17604 }
Andrey Ponomarenko5c09ef32012-06-14 18:17:33 +040017605 else
17606 { # default
17607 $UsedDump{$LibVersion}{"SrcBin"} = 1;
17608 }
Andrey Ponomarenko01117f12012-06-26 12:23:02 +040017609 if(defined $ABI->{"Mode"}
17610 and $ABI->{"Mode"} eq "Extended")
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017611 { # --ext option
17612 $ExtendedCheck = 1;
17613 }
Andrey Ponomarenko01117f12012-06-26 12:23:02 +040017614 if(my $Lang = $ABI->{"Language"})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017615 {
17616 $UsedDump{$LibVersion}{"L"} = $Lang;
17617 setLanguage($LibVersion, $Lang);
17618 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040017619 if(checkDump($LibVersion, "2.15")) {
Andrey Ponomarenko01117f12012-06-26 12:23:02 +040017620 $TypeInfo{$LibVersion} = $ABI->{"TypeInfo"};
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040017621 }
17622 else
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017623 { # support for old ABI dumps
Andrey Ponomarenko01117f12012-06-26 12:23:02 +040017624 my $TInfo = $ABI->{"TypeInfo"};
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040017625 if(not $TInfo)
17626 { # support for older ABI dumps
Andrey Ponomarenko01117f12012-06-26 12:23:02 +040017627 $TInfo = $ABI->{"TypeDescr"};
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040017628 }
17629 my %Tid_TDid = ();
17630 foreach my $TDid (keys(%{$TInfo}))
17631 {
17632 foreach my $Tid (keys(%{$TInfo->{$TDid}}))
17633 {
17634 $MAX_ID = $Tid if($Tid>$MAX_ID);
17635 $MAX_ID = $TDid if($TDid and $TDid>$MAX_ID);
17636 $Tid_TDid{$Tid}{$TDid}=1;
17637 }
17638 }
17639 my %NewID = ();
17640 foreach my $Tid (keys(%Tid_TDid))
17641 {
17642 my @TDids = keys(%{$Tid_TDid{$Tid}});
17643 if($#TDids>=1)
17644 {
17645 foreach my $TDid (@TDids)
17646 {
17647 if($TDid) {
17648 %{$TypeInfo{$LibVersion}{$Tid}} = %{$TInfo->{$TDid}{$Tid}};
17649 }
17650 else
17651 {
17652 if(my $ID = ++$MAX_ID)
17653 {
17654 $NewID{$TDid}{$Tid} = $ID;
17655 %{$TypeInfo{$LibVersion}{$ID}} = %{$TInfo->{$TDid}{$Tid}};
17656 $TypeInfo{$LibVersion}{$ID}{"Tid"} = $ID;
17657 }
17658 }
17659 }
17660 }
17661 else
17662 {
17663 my $TDid = $TDids[0];
17664 %{$TypeInfo{$LibVersion}{$Tid}} = %{$TInfo->{$TDid}{$Tid}};
17665 }
17666 }
17667 foreach my $Tid (keys(%{$TypeInfo{$LibVersion}}))
17668 {
17669 my %Info = %{$TypeInfo{$LibVersion}{$Tid}};
17670 if(defined $Info{"BaseType"})
17671 {
17672 my $Bid = $Info{"BaseType"}{"Tid"};
17673 my $BDid = $Info{"BaseType"}{"TDid"};
17674 $BDid="" if(not defined $BDid);
17675 if(defined $NewID{$BDid} and my $ID = $NewID{$BDid}{$Bid}) {
17676 $TypeInfo{$LibVersion}{$Tid}{"BaseType"}{"Tid"} = $ID;
17677 }
17678 delete($TypeInfo{$LibVersion}{$Tid}{"BaseType"}{"TDid"});
17679 }
17680 delete($TypeInfo{$LibVersion}{$Tid}{"TDid"});
17681 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017682 }
Andrey Ponomarenko01117f12012-06-26 12:23:02 +040017683 read_Machine_DumpInfo($ABI, $LibVersion);
17684 $SymbolInfo{$LibVersion} = $ABI->{"SymbolInfo"};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017685 if(not $SymbolInfo{$LibVersion})
17686 { # support for old dumps
Andrey Ponomarenko01117f12012-06-26 12:23:02 +040017687 $SymbolInfo{$LibVersion} = $ABI->{"FuncDescr"};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017688 }
17689 if(not keys(%{$SymbolInfo{$LibVersion}}))
17690 { # validation of old-version dumps
17691 if(not $ExtendedCheck) {
17692 exitStatus("Invalid_Dump", "the input dump d$LibVersion is invalid");
17693 }
17694 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040017695 if(checkDump($LibVersion, "2.15")) {
Andrey Ponomarenko01117f12012-06-26 12:23:02 +040017696 $DepLibrary_Symbol{$LibVersion} = $ABI->{"DepSymbols"};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017697 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040017698 else
17699 { # support for old ABI dumps
Andrey Ponomarenko01117f12012-06-26 12:23:02 +040017700 my $DepSymbols = $ABI->{"DepSymbols"};
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040017701 if(not $DepSymbols) {
Andrey Ponomarenko01117f12012-06-26 12:23:02 +040017702 $DepSymbols = $ABI->{"DepInterfaces"};
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040017703 }
17704 if(not $DepSymbols)
17705 { # Cannot reconstruct DepSymbols. This may result in false
17706 # positives if the old dump is for library 2. Not a problem if
17707 # old dumps are only from old libraries.
17708 $DepSymbols = {};
17709 }
17710 foreach my $Symbol (keys(%{$DepSymbols})) {
17711 $DepSymbol_Library{$LibVersion}{$Symbol} = 1;
17712 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017713 }
Andrey Ponomarenko01117f12012-06-26 12:23:02 +040017714 $SymVer{$LibVersion} = $ABI->{"SymbolVersion"};
17715 $Descriptor{$LibVersion}{"Version"} = $ABI->{"LibraryVersion"};
17716 $SkipTypes{$LibVersion} = $ABI->{"SkipTypes"};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017717 if(not $SkipTypes{$LibVersion})
17718 { # support for old dumps
Andrey Ponomarenko01117f12012-06-26 12:23:02 +040017719 $SkipTypes{$LibVersion} = $ABI->{"OpaqueTypes"};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017720 }
Andrey Ponomarenko01117f12012-06-26 12:23:02 +040017721 $SkipSymbols{$LibVersion} = $ABI->{"SkipSymbols"};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017722 if(not $SkipSymbols{$LibVersion})
17723 { # support for old dumps
Andrey Ponomarenko01117f12012-06-26 12:23:02 +040017724 $SkipSymbols{$LibVersion} = $ABI->{"SkipInterfaces"};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017725 }
17726 if(not $SkipSymbols{$LibVersion})
17727 { # support for old dumps
Andrey Ponomarenko01117f12012-06-26 12:23:02 +040017728 $SkipSymbols{$LibVersion} = $ABI->{"InternalInterfaces"};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017729 }
Andrey Ponomarenko01117f12012-06-26 12:23:02 +040017730 $SkipNameSpaces{$LibVersion} = $ABI->{"SkipNameSpaces"};
17731 $TargetHeaders{$LibVersion} = $ABI->{"TargetHeaders"};
17732 foreach my $Path (keys(%{$ABI->{"SkipHeaders"}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017733 {
Andrey Ponomarenko01117f12012-06-26 12:23:02 +040017734 $SkipHeadersList{$LibVersion}{$Path} = $ABI->{"SkipHeaders"}{$Path};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017735 my ($CPath, $Type) = classifyPath($Path);
Andrey Ponomarenko01117f12012-06-26 12:23:02 +040017736 $SkipHeaders{$LibVersion}{$Type}{$CPath} = $ABI->{"SkipHeaders"}{$Path};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017737 }
Andrey Ponomarenko01117f12012-06-26 12:23:02 +040017738 read_Headers_DumpInfo($ABI, $LibVersion);
17739 read_Libs_DumpInfo($ABI, $LibVersion);
Andrey Ponomarenko5c09ef32012-06-14 18:17:33 +040017740 if(not checkDump($LibVersion, "2.10.1")
17741 or not $TargetHeaders{$LibVersion})
Andrey Ponomarenko85043792012-05-14 16:48:07 +040017742 { # support for old ABI dumps: added target headers
17743 foreach (keys(%{$Registered_Headers{$LibVersion}})) {
17744 $TargetHeaders{$LibVersion}{get_filename($_)}=1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017745 }
17746 }
Andrey Ponomarenko01117f12012-06-26 12:23:02 +040017747 $Constants{$LibVersion} = $ABI->{"Constants"};
17748 $NestedNameSpaces{$LibVersion} = $ABI->{"NameSpaces"};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017749 if(not $NestedNameSpaces{$LibVersion})
17750 { # support for old dumps
17751 # Cannot reconstruct NameSpaces. This may affect design
17752 # of the compatibility report.
17753 $NestedNameSpaces{$LibVersion} = {};
17754 }
17755 # target system type
17756 # needed to adopt HTML report
17757 if(not $DumpSystem)
17758 { # to use in createSymbolsList(...)
Andrey Ponomarenko01117f12012-06-26 12:23:02 +040017759 $OStarget = $ABI->{"Target"};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017760 }
17761 # recreate environment
17762 foreach my $Lib_Name (keys(%{$Library_Symbol{$LibVersion}}))
17763 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040017764 foreach my $Symbol (keys(%{$Library_Symbol{$LibVersion}{$Lib_Name}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017765 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040017766 $Symbol_Library{$LibVersion}{$Symbol} = $Lib_Name;
17767 if($Library_Symbol{$LibVersion}{$Lib_Name}{$Symbol}<=-1)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017768 { # data marked as -size in the dump
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040017769 $GlobalDataObject{$LibVersion}{$Symbol}=1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017770 }
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040017771 if($COMMON_LANGUAGE{$LibVersion} ne "C++")
17772 {
17773 if(index($Symbol, "_Z")==0 or index($Symbol, "?")==0) {
17774 setLanguage($LibVersion, "C++");
17775 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017776 }
17777 }
17778 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040017779 foreach my $Lib_Name (keys(%{$DepLibrary_Symbol{$LibVersion}}))
17780 {
17781 foreach my $Symbol (keys(%{$DepLibrary_Symbol{$LibVersion}{$Lib_Name}})) {
17782 $DepSymbol_Library{$LibVersion}{$Symbol} = $Lib_Name;
17783 }
17784 }
17785
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017786 my @VFunc = ();
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040017787 foreach my $InfoId (keys(%{$SymbolInfo{$LibVersion}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017788 {
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +040017789 if(my $MnglName = $SymbolInfo{$LibVersion}{$InfoId}{"MnglName"})
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040017790 {
17791 if(not $Symbol_Library{$LibVersion}{$MnglName}
17792 and not $DepSymbol_Library{$LibVersion}{$MnglName}) {
17793 push(@VFunc, $MnglName);
17794 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017795 }
17796 }
17797 translateSymbols(@VFunc, $LibVersion);
17798 translateSymbols(keys(%{$Symbol_Library{$LibVersion}}), $LibVersion);
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040017799 translateSymbols(keys(%{$DepSymbol_Library{$LibVersion}}), $LibVersion);
17800
17801 foreach my $TypeId (sort {int($a)<=>int($b)} keys(%{$TypeInfo{$LibVersion}}))
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +040017802 { # order is important
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040017803 if(defined $TypeInfo{$LibVersion}{$TypeId}{"BaseClass"})
17804 { # support for old ABI dumps < 2.0 (ACC 1.22)
17805 foreach my $BId (keys(%{$TypeInfo{$LibVersion}{$TypeId}{"BaseClass"}}))
17806 {
17807 if(my $Access = $TypeInfo{$LibVersion}{$TypeId}{"BaseClass"}{$BId})
17808 {
17809 if($Access ne "public") {
17810 $TypeInfo{$LibVersion}{$TypeId}{"Base"}{$BId}{"access"} = $Access;
17811 }
17812 }
17813 $TypeInfo{$LibVersion}{$TypeId}{"Base"}{$BId} = {};
17814 }
17815 delete($TypeInfo{$LibVersion}{$TypeId}{"BaseClass"});
17816 }
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040017817 if(my $Header = $TypeInfo{$LibVersion}{$TypeId}{"Header"})
17818 { # support for old ABI dumps
17819 $TypeInfo{$LibVersion}{$TypeId}{"Header"} = path_format($Header, $OSgroup);
17820 }
Andrey Ponomarenko01117f12012-06-26 12:23:02 +040017821 if(not defined $TypeInfo{$LibVersion}{$TypeId}{"Tid"}) {
17822 $TypeInfo{$LibVersion}{$TypeId}{"Tid"} = $TypeId;
17823 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040017824 my %TInfo = %{$TypeInfo{$LibVersion}{$TypeId}};
17825 if(defined $TInfo{"Base"})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017826 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040017827 foreach (keys(%{$TInfo{"Base"}})) {
17828 $Class_SubClasses{$LibVersion}{$_}{$TypeId}=1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017829 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040017830 }
Andrey Ponomarenko01117f12012-06-26 12:23:02 +040017831 if($TInfo{"Type"} eq "MethodPtr")
17832 {
17833 if(defined $TInfo{"Param"})
17834 { # support for old ABI dumps <= 1.17
17835 if(not defined $TInfo{"Param"}{"0"})
17836 {
17837 my $Max = keys(%{$TInfo{"Param"}});
17838 foreach my $Pos (1 .. $Max) {
17839 $TInfo{"Param"}{$Pos-1} = $TInfo{"Param"}{$Pos};
17840 }
17841 delete($TInfo{"Param"}{$Max});
17842 %{$TypeInfo{$LibVersion}{$TypeId}} = %TInfo;
17843 }
17844 }
17845 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040017846 if($TInfo{"Type"} eq "Typedef" and defined $TInfo{"BaseType"})
17847 {
17848 if(my $BTid = $TInfo{"BaseType"}{"Tid"})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017849 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040017850 my $BName = $TypeInfo{$LibVersion}{$BTid}{"Name"};
17851 if(not $BName)
17852 { # broken type
17853 next;
17854 }
17855 if($TInfo{"Name"} eq $BName)
17856 { # typedef to "class Class"
17857 # should not be registered in TName_Tid
17858 next;
17859 }
17860 if(not $Typedef_BaseName{$LibVersion}{$TInfo{"Name"}}) {
17861 $Typedef_BaseName{$LibVersion}{$TInfo{"Name"}} = $BName;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017862 }
17863 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040017864 }
17865 if(not $TName_Tid{$LibVersion}{$TInfo{"Name"}})
17866 { # classes: class (id1), typedef (artificial, id2 > id1)
17867 $TName_Tid{$LibVersion}{$TInfo{"Name"}} = $TypeId;
17868 }
17869 }
17870
17871 if(not checkDump($LibVersion, "2.15"))
17872 { # support for old ABI dumps
17873 my %Dups = ();
17874 foreach my $InfoId (keys(%{$SymbolInfo{$LibVersion}}))
17875 {
17876 if(my $ClassId = $SymbolInfo{$LibVersion}{$InfoId}{"Class"})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017877 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040017878 if(not defined $TypeInfo{$LibVersion}{$ClassId})
17879 { # remove template decls
17880 delete($SymbolInfo{$LibVersion}{$InfoId});
17881 next;
Andrey Ponomarenko16934472012-03-29 15:37:04 +040017882 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017883 }
Andrey Ponomarenkob8d203d2012-05-25 18:11:07 +040017884 my $MName = $SymbolInfo{$LibVersion}{$InfoId}{"MnglName"};
17885 if(not $MName and $SymbolInfo{$LibVersion}{$InfoId}{"Class"})
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040017886 { # templates
17887 delete($SymbolInfo{$LibVersion}{$InfoId});
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017888 }
17889 }
17890 }
17891
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +040017892 foreach my $InfoId (keys(%{$SymbolInfo{$LibVersion}}))
17893 {
17894 if(not $SymbolInfo{$LibVersion}{$InfoId}{"MnglName"})
17895 { # ABI dumps have no mangled names for C-functions
17896 $SymbolInfo{$LibVersion}{$InfoId}{"MnglName"} = $SymbolInfo{$LibVersion}{$InfoId}{"ShortName"};
17897 }
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040017898 if(my $Header = $SymbolInfo{$LibVersion}{$InfoId}{"Header"})
17899 { # support for old ABI dumps
17900 $SymbolInfo{$LibVersion}{$InfoId}{"Header"} = path_format($Header, $OSgroup);
17901 }
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +040017902 }
17903
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017904 $Descriptor{$LibVersion}{"Dump"} = 1;
17905}
17906
17907sub read_Machine_DumpInfo($$)
17908{
Andrey Ponomarenko01117f12012-06-26 12:23:02 +040017909 my ($ABI, $LibVersion) = @_;
17910 if($ABI->{"Arch"}) {
17911 $CPU_ARCH{$LibVersion} = $ABI->{"Arch"};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017912 }
Andrey Ponomarenko01117f12012-06-26 12:23:02 +040017913 if($ABI->{"WordSize"}) {
17914 $WORD_SIZE{$LibVersion} = $ABI->{"WordSize"};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017915 }
17916 else
17917 { # support for old dumps
Andrey Ponomarenko01117f12012-06-26 12:23:02 +040017918 $WORD_SIZE{$LibVersion} = $ABI->{"SizeOfPointer"};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017919 }
17920 if(not $WORD_SIZE{$LibVersion})
17921 { # support for old dumps (<1.23)
17922 if(my $Tid = getTypeIdByName("char*", $LibVersion))
17923 { # size of char*
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040017924 $WORD_SIZE{$LibVersion} = $TypeInfo{$LibVersion}{$Tid}{"Size"};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017925 }
17926 else
17927 {
17928 my $PSize = 0;
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040017929 foreach my $Tid (keys(%{$TypeInfo{$LibVersion}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017930 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040017931 if($TypeInfo{$LibVersion}{$Tid}{"Type"} eq "Pointer")
17932 { # any "pointer"-type
17933 $PSize = $TypeInfo{$LibVersion}{$Tid}{"Size"};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017934 last;
17935 }
17936 }
17937 if($PSize)
17938 { # a pointer type size
17939 $WORD_SIZE{$LibVersion} = $PSize;
17940 }
17941 else {
17942 printMsg("WARNING", "cannot identify a WORD size in the ABI dump (too old format)");
17943 }
17944 }
17945 }
Andrey Ponomarenko01117f12012-06-26 12:23:02 +040017946 if($ABI->{"GccVersion"}) {
17947 $GCC_VERSION{$LibVersion} = $ABI->{"GccVersion"};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017948 }
17949}
17950
17951sub read_Libs_DumpInfo($$)
17952{
Andrey Ponomarenko01117f12012-06-26 12:23:02 +040017953 my ($ABI, $LibVersion) = @_;
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040017954 $Library_Symbol{$LibVersion} = $ABI->{"Symbols"};
17955 if(not $Library_Symbol{$LibVersion})
17956 { # support for old dumps
17957 $Library_Symbol{$LibVersion} = $ABI->{"Interfaces"};
17958 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017959 if(keys(%{$Library_Symbol{$LibVersion}})
17960 and not $DumpAPI) {
17961 $Descriptor{$LibVersion}{"Libs"} = "OK";
17962 }
17963}
17964
17965sub read_Headers_DumpInfo($$)
17966{
Andrey Ponomarenko01117f12012-06-26 12:23:02 +040017967 my ($ABI, $LibVersion) = @_;
17968 if(keys(%{$ABI->{"Headers"}})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017969 and not $DumpAPI) {
17970 $Descriptor{$LibVersion}{"Headers"} = "OK";
17971 }
Andrey Ponomarenko01117f12012-06-26 12:23:02 +040017972 foreach my $Identity (sort {$ABI->{"Headers"}{$a}<=>$ABI->{"Headers"}{$b}} keys(%{$ABI->{"Headers"}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017973 { # headers info is stored in the old dumps in the different way
17974 if($UseOldDumps
Andrey Ponomarenko01117f12012-06-26 12:23:02 +040017975 and my $Name = $ABI->{"Headers"}{$Identity}{"Name"})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017976 { # support for old dumps: headers info corrected in 1.22
17977 $Identity = $Name;
17978 }
17979 $Registered_Headers{$LibVersion}{$Identity}{"Identity"} = $Identity;
Andrey Ponomarenko01117f12012-06-26 12:23:02 +040017980 $Registered_Headers{$LibVersion}{$Identity}{"Pos"} = $ABI->{"Headers"}{$Identity};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017981 }
17982}
17983
17984sub find_libs($$$)
17985{
17986 my ($Path, $Type, $MaxDepth) = @_;
17987 # FIXME: correct the search pattern
17988 return cmd_find($Path, $Type, ".*\\.$LIB_EXT\[0-9.]*", $MaxDepth);
17989}
17990
17991sub createDescriptor($$)
17992{
17993 my ($LibVersion, $Path) = @_;
17994 if(not $LibVersion or not $Path
17995 or not -e $Path) {
17996 return "";
17997 }
17998 if(-d $Path)
17999 { # directory with headers files and shared objects
18000 return "
18001 <version>
18002 ".$TargetVersion{$LibVersion}."
18003 </version>
18004
18005 <headers>
18006 $Path
18007 </headers>
18008
18009 <libs>
18010 $Path
18011 </libs>";
18012 }
18013 else
18014 { # files
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040018015 if($Path=~/\.(xml|desc)\Z/i)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040018016 { # standard XML-descriptor
18017 return readFile($Path);
18018 }
18019 elsif(is_header($Path, 2, $LibVersion))
18020 { # header file
18021 return "
18022 <version>
18023 ".$TargetVersion{$LibVersion}."
18024 </version>
18025
18026 <headers>
18027 $Path
18028 </headers>
18029
18030 <libs>
18031 none
18032 </libs>";
18033 }
18034 elsif(parse_libname($Path, "name", $OStarget))
18035 { # shared object
18036 return "
18037 <version>
18038 ".$TargetVersion{$LibVersion}."
18039 </version>
18040
18041 <headers>
18042 none
18043 </headers>
18044
18045 <libs>
18046 $Path
18047 </libs>";
18048 }
18049 else
18050 { # standard XML-descriptor
18051 return readFile($Path);
18052 }
18053 }
18054}
18055
18056sub detect_lib_default_paths()
18057{
18058 my %LPaths = ();
18059 if($OSgroup eq "bsd")
18060 {
Andrey Ponomarenkoa01311b2012-06-08 17:20:02 +040018061 if(my $LdConfig = get_CmdPath("ldconfig"))
18062 {
18063 foreach my $Line (split(/\n/, `$LdConfig -r 2>\"$TMP_DIR/null\"`))
18064 {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040018065 if($Line=~/\A[ \t]*\d+:\-l(.+) \=\> (.+)\Z/) {
18066 $LPaths{"lib".$1} = $2;
18067 }
18068 }
18069 }
18070 else {
18071 printMsg("WARNING", "can't find ldconfig");
18072 }
18073 }
18074 else
18075 {
18076 if(my $LdConfig = get_CmdPath("ldconfig"))
18077 {
18078 if($SystemRoot and $OSgroup eq "linux")
18079 { # use host (x86) ldconfig with the target (arm) ld.so.conf
18080 if(-e $SystemRoot."/etc/ld.so.conf") {
18081 $LdConfig .= " -f ".$SystemRoot."/etc/ld.so.conf";
18082 }
18083 }
Andrey Ponomarenkoa01311b2012-06-08 17:20:02 +040018084 foreach my $Line (split(/\n/, `$LdConfig -p 2>\"$TMP_DIR/null\"`))
18085 {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040018086 if($Line=~/\A[ \t]*([^ \t]+) .* \=\> (.+)\Z/)
18087 {
18088 my ($Name, $Path) = ($1, $2);
18089 $Path=~s/[\/]{2,}/\//;
18090 $LPaths{$Name} = $Path;
18091 }
18092 }
18093 }
Andrey Ponomarenko82b005f2012-11-12 17:58:14 +040018094 elsif($OSgroup eq "linux") {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040018095 printMsg("WARNING", "can't find ldconfig");
18096 }
18097 }
18098 return \%LPaths;
18099}
18100
18101sub detect_bin_default_paths()
18102{
18103 my $EnvPaths = $ENV{"PATH"};
18104 if($OSgroup eq "beos") {
18105 $EnvPaths.=":".$ENV{"BETOOLS"};
18106 }
18107 my $Sep = ($OSgroup eq "windows")?";":":|;";
18108 foreach my $Path (sort {length($a)<=>length($b)} split(/$Sep/, $EnvPaths))
18109 {
18110 $Path = path_format($Path, $OSgroup);
18111 $Path=~s/[\/\\]+\Z//g;
18112 next if(not $Path);
18113 if($SystemRoot
18114 and $Path=~/\A\Q$SystemRoot\E\//)
18115 { # do NOT use binaries from target system
18116 next;
18117 }
18118 $DefaultBinPaths{$Path} = 1;
18119 }
18120}
18121
18122sub detect_inc_default_paths()
18123{
18124 return () if(not $GCC_PATH);
18125 my %DPaths = ("Cpp"=>{},"Gcc"=>{},"Inc"=>{});
18126 writeFile("$TMP_DIR/empty.h", "");
Andrey Ponomarenkoa01311b2012-06-08 17:20:02 +040018127 foreach my $Line (split(/\n/, `$GCC_PATH -v -x c++ -E \"$TMP_DIR/empty.h\" 2>&1`))
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040018128 { # detecting GCC default include paths
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040018129 if($Line=~/\A[ \t]*((\/|\w+:\\).+)[ \t]*\Z/)
18130 {
18131 my $Path = simplify_path($1);
18132 $Path=~s/[\/\\]+\Z//g;
18133 $Path = path_format($Path, $OSgroup);
18134 if($Path=~/c\+\+|\/g\+\+\//)
18135 {
18136 $DPaths{"Cpp"}{$Path}=1;
18137 if(not defined $MAIN_CPP_DIR
18138 or get_depth($MAIN_CPP_DIR)>get_depth($Path)) {
18139 $MAIN_CPP_DIR = $Path;
18140 }
18141 }
18142 elsif($Path=~/gcc/) {
18143 $DPaths{"Gcc"}{$Path}=1;
18144 }
18145 else
18146 {
18147 next if($Path=~/local[\/\\]+include/);
18148 if($SystemRoot
18149 and $Path!~/\A\Q$SystemRoot\E(\/|\Z)/)
18150 { # The GCC include path for user headers is not a part of the system root
18151 # The reason: you are not specified the --cross-gcc option or selected a wrong compiler
18152 # or it is the internal cross-GCC path like arm-linux-gnueabi/include
18153 next;
18154 }
18155 $DPaths{"Inc"}{$Path}=1;
18156 }
18157 }
18158 }
18159 unlink("$TMP_DIR/empty.h");
18160 return %DPaths;
18161}
18162
18163sub detect_default_paths($)
18164{
18165 my ($HSearch, $LSearch, $BSearch, $GSearch) = (1, 1, 1, 1);
18166 my $Search = $_[0];
18167 if($Search!~/inc/) {
18168 $HSearch = 0;
18169 }
18170 if($Search!~/lib/) {
18171 $LSearch = 0;
18172 }
18173 if($Search!~/bin/) {
18174 $BSearch = 0;
18175 }
18176 if($Search!~/gcc/) {
18177 $GSearch = 0;
18178 }
18179 if(keys(%{$SystemPaths{"include"}}))
18180 { # <search_headers> section of the XML descriptor
18181 # do NOT search for systems headers
18182 $HSearch = 0;
18183 }
18184 if(keys(%{$SystemPaths{"lib"}}))
18185 { # <search_headers> section of the XML descriptor
18186 # do NOT search for systems headers
18187 $LSearch = 0;
18188 }
18189 foreach my $Type (keys(%{$OS_AddPath{$OSgroup}}))
18190 { # additional search paths
18191 next if($Type eq "include" and not $HSearch);
18192 next if($Type eq "lib" and not $LSearch);
18193 next if($Type eq "bin" and not $BSearch);
18194 foreach my $Path (keys(%{$OS_AddPath{$OSgroup}{$Type}}))
18195 {
18196 next if(not -d $Path);
18197 $SystemPaths{$Type}{$Path} = $OS_AddPath{$OSgroup}{$Type}{$Path};
18198 }
18199 }
18200 if($OSgroup ne "windows")
18201 { # unix-like
18202 foreach my $Type ("include", "lib", "bin")
18203 { # automatic detection of system "devel" directories
18204 next if($Type eq "include" and not $HSearch);
18205 next if($Type eq "lib" and not $LSearch);
18206 next if($Type eq "bin" and not $BSearch);
18207 my ($UsrDir, $RootDir) = ("/usr", "/");
18208 if($SystemRoot and $Type ne "bin")
18209 { # 1. search for target headers and libraries
18210 # 2. use host commands: ldconfig, readelf, etc.
18211 ($UsrDir, $RootDir) = ("$SystemRoot/usr", $SystemRoot);
18212 }
18213 foreach my $Path (cmd_find($RootDir,"d","*$Type*",1)) {
18214 $SystemPaths{$Type}{$Path} = 1;
18215 }
18216 if(-d $RootDir."/".$Type)
18217 { # if "/lib" is symbolic link
18218 if($RootDir eq "/") {
18219 $SystemPaths{$Type}{"/".$Type} = 1;
18220 }
18221 else {
18222 $SystemPaths{$Type}{$RootDir."/".$Type} = 1;
18223 }
18224 }
18225 if(-d $UsrDir) {
18226 foreach my $Path (cmd_find($UsrDir,"d","*$Type*",1)) {
18227 $SystemPaths{$Type}{$Path} = 1;
18228 }
18229 if(-d $UsrDir."/".$Type)
18230 { # if "/usr/lib" is symbolic link
18231 $SystemPaths{$Type}{$UsrDir."/".$Type} = 1;
18232 }
18233 }
18234 }
18235 }
18236 if($BSearch)
18237 {
18238 detect_bin_default_paths();
18239 foreach my $Path (keys(%DefaultBinPaths)) {
18240 $SystemPaths{"bin"}{$Path} = $DefaultBinPaths{$Path};
18241 }
18242 }
18243 # check environment variables
18244 if($OSgroup eq "beos")
18245 {
18246 foreach (keys(%{$SystemPaths{"bin"}}))
18247 {
18248 if($_ eq ".") {
18249 next;
18250 }
18251 foreach my $Path (cmd_find($_, "d", "bin", ""))
18252 { # search for /boot/develop/abi/x86/gcc4/tools/gcc-4.4.4-haiku-101111/bin/
18253 $SystemPaths{"bin"}{$Path} = 1;
18254 }
18255 }
18256 if($HSearch)
18257 {
18258 foreach my $Path (split(/:|;/, $ENV{"BEINCLUDES"}))
18259 {
18260 if(is_abs($Path)) {
18261 $DefaultIncPaths{$Path} = 1;
18262 }
18263 }
18264 }
18265 if($LSearch)
18266 {
18267 foreach my $Path (split(/:|;/, $ENV{"BELIBRARIES"}), split(/:|;/, $ENV{"LIBRARY_PATH"}))
18268 {
18269 if(is_abs($Path)) {
18270 $DefaultLibPaths{$Path} = 1;
18271 }
18272 }
18273 }
18274 }
18275 if($LSearch)
18276 { # using linker to get system paths
18277 if(my $LPaths = detect_lib_default_paths())
18278 { # unix-like
18279 foreach my $Name (keys(%{$LPaths}))
18280 {
18281 if($SystemRoot
18282 and $LPaths->{$Name}!~/\A\Q$SystemRoot\E\//)
18283 { # wrong ldconfig configuration
18284 # check your <sysroot>/etc/ld.so.conf
18285 next;
18286 }
18287 $DyLib_DefaultPath{$Name} = $LPaths->{$Name};
18288 $DefaultLibPaths{get_dirname($LPaths->{$Name})} = 1;
18289 }
18290 }
18291 foreach my $Path (keys(%DefaultLibPaths)) {
18292 $SystemPaths{"lib"}{$Path} = $DefaultLibPaths{$Path};
18293 }
18294 }
18295 if($BSearch)
18296 {
18297 if($CrossGcc)
18298 { # --cross-gcc=arm-linux-gcc
18299 if(-e $CrossGcc)
18300 { # absolute or relative path
18301 $GCC_PATH = get_abs_path($CrossGcc);
18302 }
18303 elsif($CrossGcc!~/\// and get_CmdPath($CrossGcc))
18304 { # command name
18305 $GCC_PATH = $CrossGcc;
18306 }
18307 else {
18308 exitStatus("Access_Error", "can't access \'$CrossGcc\'");
18309 }
18310 if($GCC_PATH=~/\s/) {
18311 $GCC_PATH = "\"".$GCC_PATH."\"";
18312 }
18313 }
18314 }
18315 if($GSearch)
18316 { # GCC path and default include dirs
18317 if(not $CrossGcc) {
18318 $GCC_PATH = get_CmdPath("gcc");
18319 }
Andrey Ponomarenko01117f12012-06-26 12:23:02 +040018320 if(not $GCC_PATH)
18321 { # try to find gcc-X.Y
18322 foreach my $Path (sort {$b=~/\/usr\/bin/ cmp $a=~/\/usr\/bin/}
18323 keys(%{$SystemPaths{"bin"}}))
18324 {
18325 if(my @GCCs = cmd_find($Path, "", ".*/gcc-[0-9.]*", 1))
18326 { # select the latest version
18327 @GCCs = sort {$b cmp $a} @GCCs;
18328 if(check_gcc($GCCs[0], "3"))
18329 {
18330 $GCC_PATH = $GCCs[0];
18331 last;
18332 }
18333 }
18334 }
18335 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040018336 if(not $GCC_PATH) {
18337 exitStatus("Not_Found", "can't find GCC>=3.0 in PATH");
18338 }
18339 if(not $CheckObjectsOnly_Opt)
18340 {
18341 if(my $GCC_Ver = get_dumpversion($GCC_PATH))
18342 {
18343 my $GccTarget = get_dumpmachine($GCC_PATH);
18344 printMsg("INFO", "Using GCC $GCC_Ver ($GccTarget)");
18345 if($GccTarget=~/symbian/)
18346 {
18347 $OStarget = "symbian";
18348 $LIB_EXT = $OS_LibExt{$LIB_TYPE}{$OStarget};
18349 }
18350 }
18351 else {
18352 exitStatus("Error", "something is going wrong with the GCC compiler");
18353 }
18354 }
18355 if(not $NoStdInc)
18356 { # do NOT search in GCC standard paths
18357 my %DPaths = detect_inc_default_paths();
18358 %DefaultCppPaths = %{$DPaths{"Cpp"}};
18359 %DefaultGccPaths = %{$DPaths{"Gcc"}};
18360 %DefaultIncPaths = %{$DPaths{"Inc"}};
18361 foreach my $Path (keys(%DefaultIncPaths)) {
18362 $SystemPaths{"include"}{$Path} = $DefaultIncPaths{$Path};
18363 }
18364 }
18365 }
18366 if($HSearch)
18367 { # user include paths
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040018368 my $IncPath = "/usr/include";
18369 if($SystemRoot) {
18370 $IncPath = $SystemRoot.$IncPath;
18371 }
18372 if(-d $IncPath) {
18373 $UserIncPath{$IncPath}=1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040018374 }
18375 }
18376}
18377
18378sub getLIB_EXT($)
18379{
18380 my $Target = $_[0];
18381 if(my $Ext = $OS_LibExt{$LIB_TYPE}{$Target}) {
18382 return $Ext;
18383 }
18384 return $OS_LibExt{$LIB_TYPE}{"default"};
18385}
18386
18387sub getAR_EXT($)
18388{
18389 my $Target = $_[0];
18390 if(my $Ext = $OS_Archive{$Target}) {
18391 return $Ext;
18392 }
18393 return $OS_Archive{"default"};
18394}
18395
18396sub get_dumpversion($)
18397{
18398 my $Cmd = $_[0];
18399 return "" if(not $Cmd);
18400 if($Cache{"get_dumpversion"}{$Cmd}) {
18401 return $Cache{"get_dumpversion"}{$Cmd};
18402 }
Andrey Ponomarenkoa01311b2012-06-08 17:20:02 +040018403 my $V = `$Cmd -dumpversion 2>\"$TMP_DIR/null\"`;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040018404 chomp($V);
18405 return ($Cache{"get_dumpversion"}{$Cmd} = $V);
18406}
18407
18408sub get_dumpmachine($)
18409{
18410 my $Cmd = $_[0];
18411 return "" if(not $Cmd);
18412 if($Cache{"get_dumpmachine"}{$Cmd}) {
18413 return $Cache{"get_dumpmachine"}{$Cmd};
18414 }
Andrey Ponomarenkoa01311b2012-06-08 17:20:02 +040018415 my $Machine = `$Cmd -dumpmachine 2>\"$TMP_DIR/null\"`;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040018416 chomp($Machine);
18417 return ($Cache{"get_dumpmachine"}{$Cmd} = $Machine);
18418}
18419
18420sub check_command($)
18421{
18422 my $Cmd = $_[0];
18423 return "" if(not $Cmd);
18424 my @Options = (
18425 "--version",
18426 "-help"
18427 );
18428 foreach my $Opt (@Options)
18429 {
Andrey Ponomarenkoa01311b2012-06-08 17:20:02 +040018430 my $Info = `$Cmd $Opt 2>\"$TMP_DIR/null\"`;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040018431 if($Info) {
18432 return 1;
18433 }
18434 }
18435 return 0;
18436}
18437
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040018438sub check_gcc($$)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040018439{
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040018440 my ($Cmd, $ReqVer) = @_;
18441 return 0 if(not $Cmd or not $ReqVer);
18442 if(defined $Cache{"check_gcc"}{$Cmd}{$ReqVer}) {
18443 return $Cache{"check_gcc"}{$Cmd}{$ReqVer};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040018444 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040018445 if(my $GccVer = get_dumpversion($Cmd))
18446 {
18447 $GccVer=~s/(-|_)[a-z_]+.*\Z//; # remove suffix (like "-haiku-100818")
18448 if(cmpVersions($GccVer, $ReqVer)>=0) {
18449 return ($Cache{"check_gcc"}{$Cmd}{$ReqVer} = $Cmd);
18450 }
18451 }
18452 return ($Cache{"check_gcc"}{$Cmd}{$ReqVer} = "");
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040018453}
18454
18455sub get_depth($)
18456{
18457 if(defined $Cache{"get_depth"}{$_[0]}) {
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040018458 return $Cache{"get_depth"}{$_[0]};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040018459 }
18460 return ($Cache{"get_depth"}{$_[0]} = ($_[0]=~tr![\/\\]|\:\:!!));
18461}
18462
18463sub find_gcc_cxx_headers($)
18464{
18465 my $LibVersion = $_[0];
18466 return if($Cache{"find_gcc_cxx_headers"});# this function should be called once
18467 # detecting system header paths
18468 foreach my $Path (sort {get_depth($b) <=> get_depth($a)} keys(%DefaultGccPaths))
18469 {
18470 foreach my $HeaderPath (sort {get_depth($a) <=> get_depth($b)} cmd_find($Path,"f","",""))
18471 {
18472 my $FileName = get_filename($HeaderPath);
18473 next if($DefaultGccHeader{$FileName});
18474 $DefaultGccHeader{$FileName} = $HeaderPath;
18475 }
18476 }
18477 if($COMMON_LANGUAGE{$LibVersion} eq "C++" and not $STDCXX_TESTING)
18478 {
18479 foreach my $CppDir (sort {get_depth($b)<=>get_depth($a)} keys(%DefaultCppPaths))
18480 {
18481 my @AllCppHeaders = cmd_find($CppDir,"f","","");
18482 foreach my $Path (sort {get_depth($a)<=>get_depth($b)} @AllCppHeaders)
18483 {
18484 my $FileName = get_filename($Path);
18485 next if($DefaultCppHeader{$FileName});
18486 $DefaultCppHeader{$FileName} = $Path;
18487 }
18488 }
18489 }
18490 $Cache{"find_gcc_cxx_headers"} = 1;
18491}
18492
18493sub parse_libname($$$)
18494{
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040018495 return "" if(not $_[0]);
18496 if(defined $Cache{"parse_libname"}{$_[2]}{$_[1]}{$_[0]}) {
18497 return $Cache{"parse_libname"}{$_[2]}{$_[1]}{$_[0]};
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040018498 }
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040018499 return ($Cache{"parse_libname"}{$_[2]}{$_[1]}{$_[0]} = parse_libname_I(@_));
18500}
18501
18502sub parse_libname_I($$$)
18503{
18504 my ($Name, $Type, $Target) = @_;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040018505 if($Target eq "symbian") {
18506 return parse_libname_symbian($Name, $Type);
18507 }
18508 elsif($Target eq "windows") {
18509 return parse_libname_windows($Name, $Type);
18510 }
18511 my $Ext = getLIB_EXT($Target);
Andrey Ponomarenkoa01311b2012-06-08 17:20:02 +040018512 if($Name=~/((((lib|).+?)([\-\_][\d\-\.\_]+.*?|))\.$Ext)(\.(.+)|)\Z/)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040018513 { # libSDL-1.2.so.0.7.1
18514 # libwbxml2.so.0.0.18
Andrey Ponomarenkoa01311b2012-06-08 17:20:02 +040018515 # libopcodes-2.21.53-system.20110810.so
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040018516 if($Type eq "name")
18517 { # libSDL-1.2
18518 # libwbxml2
18519 return $2;
18520 }
18521 elsif($Type eq "name+ext")
18522 { # libSDL-1.2.so
18523 # libwbxml2.so
18524 return $1;
18525 }
18526 elsif($Type eq "version")
18527 {
Andrey Ponomarenkoa01311b2012-06-08 17:20:02 +040018528 if(defined $7
18529 and $7 ne "")
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040018530 { # 0.7.1
18531 return $7;
18532 }
18533 else
18534 { # libc-2.5.so (=>2.5 version)
18535 my $MV = $5;
18536 $MV=~s/\A[\-\_]+//g;
18537 return $MV;
18538 }
18539 }
18540 elsif($Type eq "short")
18541 { # libSDL
18542 # libwbxml2
18543 return $3;
18544 }
18545 elsif($Type eq "shortest")
18546 { # SDL
18547 # wbxml
18548 return shortest_name($3);
18549 }
18550 }
18551 return "";# error
18552}
18553
18554sub parse_libname_symbian($$)
18555{
18556 my ($Name, $Type) = @_;
18557 my $Ext = getLIB_EXT("symbian");
18558 if($Name=~/(((.+?)(\{.+\}|))\.$Ext)\Z/)
18559 { # libpthread{00010001}.dso
18560 if($Type eq "name")
18561 { # libpthread{00010001}
18562 return $2;
18563 }
18564 elsif($Type eq "name+ext")
18565 { # libpthread{00010001}.dso
18566 return $1;
18567 }
18568 elsif($Type eq "version")
18569 { # 00010001
18570 my $V = $4;
18571 $V=~s/\{(.+)\}/$1/;
18572 return $V;
18573 }
18574 elsif($Type eq "short")
18575 { # libpthread
18576 return $3;
18577 }
18578 elsif($Type eq "shortest")
18579 { # pthread
18580 return shortest_name($3);
18581 }
18582 }
18583 return "";# error
18584}
18585
18586sub parse_libname_windows($$)
18587{
18588 my ($Name, $Type) = @_;
18589 my $Ext = getLIB_EXT("windows");
18590 if($Name=~/((.+?)\.$Ext)\Z/)
18591 { # netapi32.dll
18592 if($Type eq "name")
18593 { # netapi32
18594 return $2;
18595 }
18596 elsif($Type eq "name+ext")
18597 { # netapi32.dll
18598 return $1;
18599 }
18600 elsif($Type eq "version")
18601 { # DLL version embedded
18602 # at binary-level
18603 return "";
18604 }
18605 elsif($Type eq "short")
18606 { # netapi32
18607 return $2;
18608 }
18609 elsif($Type eq "shortest")
18610 { # netapi
18611 return shortest_name($2);
18612 }
18613 }
18614 return "";# error
18615}
18616
18617sub shortest_name($)
18618{
18619 my $Name = $_[0];
18620 # remove prefix
18621 $Name=~s/\A(lib|open)//;
18622 # remove suffix
18623 $Name=~s/[\W\d_]+\Z//i;
18624 $Name=~s/([a-z]{2,})(lib)\Z/$1/i;
18625 return $Name;
18626}
18627
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040018628sub createSymbolsList($$$$$)
18629{
18630 my ($DPath, $SaveTo, $LName, $LVersion, $ArchName) = @_;
18631 read_ABI_Dump(1, $DPath);
18632 if(not $CheckObjectsOnly) {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040018633 prepareSymbols(1);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040018634 }
18635 my %SymbolHeaderLib = ();
18636 my $Total = 0;
18637 # Get List
18638 foreach my $Symbol (sort keys(%{$CompleteSignature{1}}))
18639 {
18640 if(not link_symbol($Symbol, 1, "-Deps"))
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040018641 { # skip src only and all external functions
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040018642 next;
18643 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040018644 if(not symbolFilter($Symbol, 1, "Public", "Binary"))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040018645 { # skip other symbols
18646 next;
18647 }
18648 my $HeaderName = $CompleteSignature{1}{$Symbol}{"Header"};
18649 if(not $HeaderName)
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040018650 { # skip src only and all external functions
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040018651 next;
18652 }
18653 my $DyLib = $Symbol_Library{1}{$Symbol};
18654 if(not $DyLib)
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040018655 { # skip src only and all external functions
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040018656 next;
18657 }
18658 $SymbolHeaderLib{$HeaderName}{$DyLib}{$Symbol} = 1;
18659 $Total+=1;
18660 }
18661 # Draw List
18662 my $SYMBOLS_LIST = "<h1>Public symbols in <span style='color:Blue;'>$LName</span> (<span style='color:Red;'>$LVersion</span>)";
18663 $SYMBOLS_LIST .= " on <span style='color:Blue;'>".showArch($ArchName)."</span><br/>Total: $Total</h1><br/>";
18664 foreach my $HeaderName (sort {lc($a) cmp lc($b)} keys(%SymbolHeaderLib))
18665 {
18666 foreach my $DyLib (sort {lc($a) cmp lc($b)} keys(%{$SymbolHeaderLib{$HeaderName}}))
18667 {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040018668 my %NS_Symbol = ();
18669 foreach my $Symbol (keys(%{$SymbolHeaderLib{$HeaderName}{$DyLib}})) {
18670 $NS_Symbol{get_IntNameSpace($Symbol, 1)}{$Symbol} = 1;
18671 }
18672 foreach my $NameSpace (sort keys(%NS_Symbol))
18673 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040018674 $SYMBOLS_LIST .= getTitle($HeaderName, $DyLib, $NameSpace);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040018675 my @SortedInterfaces = sort {lc(get_Signature($a, 1)) cmp lc(get_Signature($b, 1))} keys(%{$NS_Symbol{$NameSpace}});
18676 foreach my $Symbol (@SortedInterfaces)
18677 {
18678 my $SubReport = "";
18679 my $Signature = get_Signature($Symbol, 1);
18680 if($NameSpace) {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040018681 $Signature=~s/\b\Q$NameSpace\E::\b//g;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040018682 }
18683 if($Symbol=~/\A(_Z|\?)/)
18684 {
18685 if($Signature) {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040018686 $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 +040018687 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040018688 else {
18689 $SubReport = "<span class='iname'>".$Symbol."</span><br/>\n";
18690 }
18691 }
18692 else
18693 {
18694 if($Signature) {
18695 $SubReport = "<span class='iname'>".highLight_Signature_Italic_Color($Signature)."</span><br/>\n";
18696 }
18697 else {
18698 $SubReport = "<span class='iname'>".$Symbol."</span><br/>\n";
18699 }
18700 }
18701 $SYMBOLS_LIST .= $SubReport;
18702 }
18703 }
18704 $SYMBOLS_LIST .= "<br/>\n";
18705 }
18706 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040018707 # clear info
18708 (%TypeInfo, %SymbolInfo, %Library_Symbol, %DepSymbol_Library,
18709 %DepLibrary_Symbol, %SymVer, %SkipTypes, %SkipSymbols,
18710 %NestedNameSpaces, %ClassMethods, %AllocableClass, %ClassNames,
18711 %CompleteSignature, %SkipNameSpaces, %Symbol_Library, %Library_Symbol) = ();
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040018712 ($Content_Counter, $ContentID) = (0, 0);
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040018713 # print report
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040018714 my $CssStyles = readModule("Styles", "SymbolsList.css");
18715 my $JScripts = readModule("Scripts", "Sections.js");
18716 $SYMBOLS_LIST = "<a name='Top'></a>".$SYMBOLS_LIST.$TOP_REF."<br/>\n";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040018717 my $Title = "$LName: public symbols";
18718 my $Keywords = "$LName, API, symbols";
18719 my $Description = "List of symbols in $LName ($LVersion) on ".showArch($ArchName);
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040018720 $SYMBOLS_LIST = composeHTML_Head($Title, $Keywords, $Description, $CssStyles, $JScripts)."
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040018721 <body><div>\n$SYMBOLS_LIST</div>
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040018722 <br/><br/><hr/>\n".getReportFooter($LName, 1)."
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040018723 <div style='height:999px;'></div></body></html>";
18724 writeFile($SaveTo, $SYMBOLS_LIST);
18725}
18726
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040018727sub readModule($$)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040018728{
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040018729 my ($Module, $Name) = @_;
18730 my $Path = $MODULES_DIR."/Internals/$Module/".$Name;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040018731 if(not -f $Path) {
18732 exitStatus("Module_Error", "can't access \'$Path\'");
18733 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040018734 return readFile($Path);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040018735}
18736
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040018737sub add_target_libs($)
18738{
18739 foreach (@{$_[0]}) {
18740 $TargetLibs{$_} = 1;
18741 }
18742}
18743
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040018744sub is_target_lib($)
18745{
18746 my $LName = $_[0];
Andrey Ponomarenkoa01311b2012-06-08 17:20:02 +040018747 if(not $LName) {
18748 return 0;
18749 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040018750 if($TargetLibraryName
18751 and $LName!~/\Q$TargetLibraryName\E/) {
18752 return 0;
18753 }
18754 if(keys(%TargetLibs)
18755 and not $TargetLibs{$LName}
18756 and not $TargetLibs{parse_libname($LName, "name+ext", $OStarget)}) {
18757 return 0;
18758 }
18759 return 1;
18760}
18761
Andrey Ponomarenko85043792012-05-14 16:48:07 +040018762sub is_target_header($$)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040018763{ # --header, --headers-list
Andrey Ponomarenko85043792012-05-14 16:48:07 +040018764 my ($H, $V) = @_;
18765 if(keys(%{$TargetHeaders{$V}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040018766 {
Andrey Ponomarenko85043792012-05-14 16:48:07 +040018767 if($TargetHeaders{$V}{$H}) {
18768 return 1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040018769 }
18770 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +040018771 return 0;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040018772}
18773
18774sub checkVersionNum($$)
18775{
18776 my ($LibVersion, $Path) = @_;
18777 if(my $VerNum = $TargetVersion{$LibVersion}) {
18778 return $VerNum;
18779 }
18780 my $UsedAltDescr = 0;
18781 foreach my $Part (split(/\s*,\s*/, $Path))
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040018782 { # try to get version string from file path
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040018783 next if(isDump($Part)); # ABI dump
18784 next if($Part=~/\.(xml|desc)\Z/i); # XML descriptor
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040018785 my $VerNum = "";
18786 if(parse_libname($Part, "name", $OStarget))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040018787 {
18788 $UsedAltDescr = 1;
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040018789 $VerNum = parse_libname($Part, "version", $OStarget);
18790 if(not $VerNum) {
Andrey Ponomarenko07aea072012-11-12 16:15:07 +040018791 $VerNum = readStrVer($Part);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040018792 }
18793 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040018794 elsif(is_header($Part, 2, $LibVersion) or -d $Part)
18795 {
18796 $UsedAltDescr = 1;
Andrey Ponomarenko07aea072012-11-12 16:15:07 +040018797 $VerNum = readStrVer($Part);
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040018798 }
18799 if($VerNum ne "")
18800 {
18801 $TargetVersion{$LibVersion} = $VerNum;
18802 if($DumpAPI) {
18803 printMsg("WARNING", "setting version number to $VerNum (use -vnum <num> option to change it)");
18804 }
18805 else {
18806 printMsg("WARNING", "setting ".($LibVersion==1?"1st":"2nd")." version number to \"$VerNum\" (use -v$LibVersion <num> option to change it)");
18807 }
18808 return $TargetVersion{$LibVersion};
18809 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040018810 }
18811 if($UsedAltDescr)
18812 {
18813 if($DumpAPI) {
18814 exitStatus("Error", "version number is not set (use -vnum <num> option)");
18815 }
18816 else {
18817 exitStatus("Error", ($LibVersion==1?"1st":"2nd")." version number is not set (use -v$LibVersion <num> option)");
18818 }
18819 }
18820}
18821
Andrey Ponomarenko07aea072012-11-12 16:15:07 +040018822sub readStrVer($)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040018823{
18824 my $Str = $_[0];
18825 return "" if(not $Str);
18826 $Str=~s/\Q$TargetLibraryName\E//g;
18827 if($Str=~/(\/|\\|\w|\A)[\-\_]*(\d+[\d\.\-]+\d+|\d+)/)
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040018828 { # .../libssh-0.4.0/...
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040018829 return $2;
18830 }
18831 elsif(my $V = parse_libname($Str, "version", $OStarget)) {
18832 return $V;
18833 }
18834 return "";
18835}
18836
18837sub readLibs($)
18838{
18839 my $LibVersion = $_[0];
18840 if($OStarget eq "windows")
18841 { # dumpbin.exe will crash
18842 # without VS Environment
18843 check_win32_env();
18844 }
Andrey Ponomarenko16934472012-03-29 15:37:04 +040018845 readSymbols($LibVersion);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040018846 translateSymbols(keys(%{$Symbol_Library{$LibVersion}}), $LibVersion);
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040018847 translateSymbols(keys(%{$DepSymbol_Library{$LibVersion}}), $LibVersion);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040018848}
18849
18850sub dump_sorting($)
18851{
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +040018852 my $Hash = $_[0];
18853 return [] if(not $Hash);
18854 my @Keys = keys(%{$Hash});
18855 return [] if($#Keys<0);
18856 if($Keys[0]=~/\A\d+\Z/)
18857 { # numbers
18858 return [sort {int($a)<=>int($b)} @Keys];
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040018859 }
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +040018860 else
18861 { # strings
18862 return [sort {$a cmp $b} @Keys];
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040018863 }
18864}
18865
18866sub printMsg($$)
18867{
18868 my ($Type, $Msg) = @_;
18869 if($Type!~/\AINFO/) {
18870 $Msg = $Type.": ".$Msg;
18871 }
18872 if($Type!~/_C\Z/) {
18873 $Msg .= "\n";
18874 }
18875 if($Quiet)
18876 { # --quiet option
18877 appendFile($COMMON_LOG_PATH, $Msg);
18878 }
18879 else
18880 {
18881 if($Type eq "ERROR") {
18882 print STDERR $Msg;
18883 }
18884 else {
18885 print $Msg;
18886 }
18887 }
18888}
18889
18890sub exitStatus($$)
18891{
18892 my ($Code, $Msg) = @_;
18893 printMsg("ERROR", $Msg);
18894 exit($ERROR_CODE{$Code});
18895}
18896
18897sub exitReport()
18898{ # the tool has run without any errors
18899 printReport();
18900 if($COMPILE_ERRORS)
18901 { # errors in headers may add false positives/negatives
18902 exit($ERROR_CODE{"Compile_Error"});
18903 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040018904 if($BinaryOnly and $RESULT{"Binary"}{"Problems"})
18905 { # --binary
18906 exit($ERROR_CODE{"Incompatible"});
18907 }
18908 elsif($SourceOnly and $RESULT{"Source"}{"Problems"})
18909 { # --source
18910 exit($ERROR_CODE{"Incompatible"});
18911 }
18912 elsif($RESULT{"Source"}{"Problems"}
18913 or $RESULT{"Binary"}{"Problems"})
18914 { # default
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040018915 exit($ERROR_CODE{"Incompatible"});
18916 }
18917 else {
18918 exit($ERROR_CODE{"Compatible"});
18919 }
18920}
18921
18922sub readRules($)
18923{
18924 my $Kind = $_[0];
18925 if(not -f $RULES_PATH{$Kind}) {
18926 exitStatus("Module_Error", "can't access \'".$RULES_PATH{$Kind}."\'");
18927 }
18928 my $Content = readFile($RULES_PATH{$Kind});
18929 while(my $Rule = parseTag(\$Content, "rule"))
18930 {
18931 my $RId = parseTag(\$Rule, "id");
18932 my @Properties = ("Severity", "Change", "Effect", "Overcome", "Kind");
18933 foreach my $Prop (@Properties) {
18934 if(my $Value = parseTag(\$Rule, lc($Prop)))
18935 {
18936 $Value=~s/\n[ ]*//;
18937 $CompatRules{$Kind}{$RId}{$Prop} = $Value;
18938 }
18939 }
18940 if($CompatRules{$Kind}{$RId}{"Kind"}=~/\A(Symbols|Parameters)\Z/) {
18941 $CompatRules{$Kind}{$RId}{"Kind"} = "Symbols";
18942 }
18943 else {
18944 $CompatRules{$Kind}{$RId}{"Kind"} = "Types";
18945 }
18946 }
18947}
18948
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040018949sub getReportPath($)
18950{
18951 my $Level = $_[0];
18952 my $Dir = "compat_reports/$TargetLibraryName/".$Descriptor{1}{"Version"}."_to_".$Descriptor{2}{"Version"};
18953 if($Level eq "Binary")
18954 {
18955 if($BinaryReportPath)
18956 { # --bin-report-path
18957 return $BinaryReportPath;
18958 }
18959 elsif($OutputReportPath)
18960 { # --report-path
18961 return $OutputReportPath;
18962 }
18963 else
18964 { # default
18965 return $Dir."/abi_compat_report.$ReportFormat";
18966 }
18967 }
18968 elsif($Level eq "Source")
18969 {
18970 if($SourceReportPath)
18971 { # --src-report-path
18972 return $SourceReportPath;
18973 }
18974 elsif($OutputReportPath)
18975 { # --report-path
18976 return $OutputReportPath;
18977 }
18978 else
18979 { # default
18980 return $Dir."/src_compat_report.$ReportFormat";
18981 }
18982 }
18983 else
18984 {
18985 if($OutputReportPath)
18986 { # --report-path
18987 return $OutputReportPath;
18988 }
18989 else
18990 { # default
18991 return $Dir."/compat_report.$ReportFormat";
18992 }
18993 }
18994}
18995
18996sub printStatMsg($)
18997{
18998 my $Level = $_[0];
18999 printMsg("INFO", "total \"$Level\" compatibility problems: ".$RESULT{$Level}{"Problems"}.", warnings: ".$RESULT{$Level}{"Warnings"});
19000}
19001
19002sub listAffected($)
19003{
19004 my $Level = $_[0];
19005 my $List = "";
19006 foreach (keys(%{$TotalAffected{$Level}}))
19007 {
19008 if($StrictCompat and $TotalAffected{$Level}{$_} eq "Low")
19009 { # skip "Low"-severity problems
19010 next;
19011 }
19012 $List .= "$_\n";
19013 }
19014 my $Dir = get_dirname(getReportPath($Level));
19015 if($Level eq "Binary") {
19016 writeFile($Dir."/abi_affected.txt", $List);
19017 }
19018 elsif($Level eq "Source") {
19019 writeFile($Dir."/src_affected.txt", $List);
19020 }
19021}
19022
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040019023sub printReport()
19024{
19025 printMsg("INFO", "creating compatibility report ...");
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040019026 createReport();
19027 if($JoinReport or $DoubleReport)
19028 {
19029 if($RESULT{"Binary"}{"Problems"}
19030 or $RESULT{"Source"}{"Problems"}) {
19031 printMsg("INFO", "result: INCOMPATIBLE (Binary: ".$RESULT{"Binary"}{"Affected"}."\%, Source: ".$RESULT{"Source"}{"Affected"}."\%)");
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040019032 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040019033 else {
19034 printMsg("INFO", "result: COMPATIBLE");
19035 }
19036 printStatMsg("Binary");
19037 printStatMsg("Source");
19038 if($ListAffected)
19039 { # --list-affected
19040 listAffected("Binary");
19041 listAffected("Source");
19042 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040019043 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040019044 elsif($BinaryOnly)
19045 {
19046 if($RESULT{"Binary"}{"Problems"}) {
19047 printMsg("INFO", "result: INCOMPATIBLE (".$RESULT{"Binary"}{"Affected"}."\%)");
19048 }
19049 else {
19050 printMsg("INFO", "result: COMPATIBLE");
19051 }
19052 printStatMsg("Binary");
19053 if($ListAffected)
19054 { # --list-affected
19055 listAffected("Binary");
19056 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040019057 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040019058 elsif($SourceOnly)
19059 {
19060 if($RESULT{"Source"}{"Problems"}) {
19061 printMsg("INFO", "result: INCOMPATIBLE (".$RESULT{"Source"}{"Affected"}."\%)");
19062 }
19063 else {
19064 printMsg("INFO", "result: COMPATIBLE");
19065 }
19066 printStatMsg("Source");
19067 if($ListAffected)
19068 { # --list-affected
19069 listAffected("Source");
19070 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040019071 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040019072 if($StdOut)
19073 {
19074 if($JoinReport or not $DoubleReport)
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040019075 { # --binary or --source
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040019076 printMsg("INFO", "compatibility report has been generated to stdout");
19077 }
19078 else
19079 { # default
19080 printMsg("INFO", "compatibility reports have been generated to stdout");
19081 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040019082 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040019083 else
19084 {
19085 if($JoinReport)
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040019086 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040019087 printMsg("INFO", "see detailed report:\n ".getReportPath("Join"));
19088 }
19089 elsif($DoubleReport)
19090 { # default
19091 printMsg("INFO", "see detailed reports:\n ".getReportPath("Binary")."\n ".getReportPath("Source"));
19092 }
19093 elsif($BinaryOnly)
19094 { # --binary
19095 printMsg("INFO", "see detailed report:\n ".getReportPath("Binary"));
19096 }
19097 elsif($SourceOnly)
19098 { # --source
19099 printMsg("INFO", "see detailed report:\n ".getReportPath("Source"));
19100 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040019101 }
19102}
19103
19104sub check_win32_env()
19105{
19106 if(not $ENV{"DevEnvDir"}
19107 or not $ENV{"LIB"}) {
19108 exitStatus("Error", "can't start without VS environment (vsvars32.bat)");
19109 }
19110}
19111
Andrey Ponomarenko5c09ef32012-06-14 18:17:33 +040019112sub diffSets($$)
19113{
19114 my ($S1, $S2) = @_;
19115 my @SK1 = keys(%{$S1});
19116 my @SK2 = keys(%{$S2});
19117 if($#SK1!=$#SK2) {
19118 return 1;
19119 }
19120 foreach my $K1 (@SK1)
19121 {
19122 if(not defined $S2->{$K1}) {
19123 return 1;
19124 }
19125 }
19126 return 0;
19127}
19128
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040019129sub create_ABI_Dump()
19130{
19131 if(not -e $DumpAPI) {
19132 exitStatus("Access_Error", "can't access \'$DumpAPI\'");
19133 }
19134 # check the archive utilities
19135 if($OSgroup eq "windows")
19136 { # using zip
19137 my $ZipCmd = get_CmdPath("zip");
19138 if(not $ZipCmd) {
19139 exitStatus("Not_Found", "can't find \"zip\"");
19140 }
19141 }
19142 else
19143 { # using tar and gzip
19144 my $TarCmd = get_CmdPath("tar");
19145 if(not $TarCmd) {
19146 exitStatus("Not_Found", "can't find \"tar\"");
19147 }
19148 my $GzipCmd = get_CmdPath("gzip");
19149 if(not $GzipCmd) {
19150 exitStatus("Not_Found", "can't find \"gzip\"");
19151 }
19152 }
19153 my @DParts = split(/\s*,\s*/, $DumpAPI);
19154 foreach my $Part (@DParts)
19155 {
19156 if(not -e $Part) {
19157 exitStatus("Access_Error", "can't access \'$Part\'");
19158 }
19159 }
19160 checkVersionNum(1, $DumpAPI);
19161 foreach my $Part (@DParts)
19162 {
19163 if(isDump($Part)) {
19164 read_ABI_Dump(1, $Part);
19165 }
19166 else {
19167 readDescriptor(1, createDescriptor(1, $Part));
19168 }
19169 }
19170 initLogging(1);
19171 detect_default_paths("inc|lib|bin|gcc"); # complete analysis
Andrey Ponomarenko01117f12012-06-26 12:23:02 +040019172 if(not $Descriptor{1}{"Dump"})
19173 {
19174 if(not $CheckHeadersOnly) {
19175 readLibs(1);
19176 }
19177 if($CheckHeadersOnly) {
19178 setLanguage(1, "C++");
19179 }
19180 if(not $CheckObjectsOnly) {
19181 searchForHeaders(1);
19182 }
19183 $WORD_SIZE{1} = detectWordSize();
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040019184 }
Andrey Ponomarenko01117f12012-06-26 12:23:02 +040019185 if(not $Descriptor{1}{"Dump"})
19186 {
19187 if($Descriptor{1}{"Headers"}) {
19188 readHeaders(1);
19189 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040019190 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +040019191 cleanDump(1);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040019192 if(not keys(%{$SymbolInfo{1}}))
19193 { # check if created dump is valid
19194 if(not $ExtendedCheck and not $CheckObjectsOnly)
19195 {
19196 if($CheckHeadersOnly) {
19197 exitStatus("Empty_Set", "the set of public symbols is empty");
19198 }
19199 else {
19200 exitStatus("Empty_Intersection", "the sets of public symbols in headers and libraries have empty intersection");
19201 }
19202 }
19203 }
19204 my %HeadersInfo = ();
19205 foreach my $HPath (keys(%{$Registered_Headers{1}}))
19206 { # headers info stored without paths in the dump
19207 $HeadersInfo{$Registered_Headers{1}{$HPath}{"Identity"}} = $Registered_Headers{1}{$HPath}{"Pos"};
19208 }
19209 printMsg("INFO", "creating library ABI dump ...");
Andrey Ponomarenko01117f12012-06-26 12:23:02 +040019210 my %ABI = (
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040019211 "TypeInfo" => $TypeInfo{1},
19212 "SymbolInfo" => $SymbolInfo{1},
19213 "Symbols" => $Library_Symbol{1},
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040019214 "DepSymbols" => $DepLibrary_Symbol{1},
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040019215 "SymbolVersion" => $SymVer{1},
19216 "LibraryVersion" => $Descriptor{1}{"Version"},
19217 "LibraryName" => $TargetLibraryName,
19218 "Language" => $COMMON_LANGUAGE{1},
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040019219 "SkipTypes" => $SkipTypes{1},
19220 "SkipSymbols" => $SkipSymbols{1},
19221 "SkipNameSpaces" => $SkipNameSpaces{1},
19222 "SkipHeaders" => $SkipHeadersList{1},
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040019223 "Headers" => \%HeadersInfo,
19224 "Constants" => $Constants{1},
19225 "NameSpaces" => $NestedNameSpaces{1},
19226 "Target" => $OStarget,
19227 "Arch" => getArch(1),
19228 "WordSize" => $WORD_SIZE{1},
19229 "GccVersion" => get_dumpversion($GCC_PATH),
19230 "ABI_DUMP_VERSION" => $ABI_DUMP_VERSION,
19231 "ABI_COMPLIANCE_CHECKER_VERSION" => $TOOL_VERSION
19232 );
Andrey Ponomarenko5c09ef32012-06-14 18:17:33 +040019233 if(diffSets($TargetHeaders{1}, \%HeadersInfo)) {
Andrey Ponomarenko01117f12012-06-26 12:23:02 +040019234 $ABI{"TargetHeaders"} = $TargetHeaders{1};
Andrey Ponomarenko5c09ef32012-06-14 18:17:33 +040019235 }
19236 if($UseXML) {
Andrey Ponomarenko01117f12012-06-26 12:23:02 +040019237 $ABI{"XML_ABI_DUMP_VERSION"} = $XML_ABI_DUMP_VERSION;
Andrey Ponomarenko5c09ef32012-06-14 18:17:33 +040019238 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040019239 if($ExtendedCheck)
19240 { # --ext option
Andrey Ponomarenko01117f12012-06-26 12:23:02 +040019241 $ABI{"Mode"} = "Extended";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040019242 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040019243 if($BinaryOnly)
19244 { # --binary
Andrey Ponomarenko01117f12012-06-26 12:23:02 +040019245 $ABI{"BinOnly"} = 1;
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040019246 }
Andrey Ponomarenko5c09ef32012-06-14 18:17:33 +040019247
19248 my $ABI_DUMP = "";
19249 if($UseXML)
19250 {
19251 loadModule("XmlDump");
Andrey Ponomarenko01117f12012-06-26 12:23:02 +040019252 $ABI_DUMP = createXmlDump(\%ABI);
Andrey Ponomarenko5c09ef32012-06-14 18:17:33 +040019253 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040019254 else
19255 { # default
Andrey Ponomarenko01117f12012-06-26 12:23:02 +040019256 $ABI_DUMP = Dumper(\%ABI);
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040019257 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040019258 if($StdOut)
19259 { # --stdout option
Andrey Ponomarenko5c09ef32012-06-14 18:17:33 +040019260 print STDOUT $ABI_DUMP;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040019261 printMsg("INFO", "ABI dump has been generated to stdout");
19262 return;
19263 }
19264 else
19265 { # write to gzipped file
Andrey Ponomarenko5c09ef32012-06-14 18:17:33 +040019266 my $DumpPath = "abi_dumps/$TargetLibraryName/".$TargetLibraryName."_".$Descriptor{1}{"Version"}.".abi";
19267 $DumpPath .= ".".$AR_EXT; # gzipped by default
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040019268 if($OutputDumpPath)
19269 { # user defined path
19270 $DumpPath = $OutputDumpPath;
19271 }
Andrey Ponomarenko5c09ef32012-06-14 18:17:33 +040019272 my $Archive = ($DumpPath=~s/\Q.$AR_EXT\E\Z//g);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040019273 my ($DDir, $DName) = separate_path($DumpPath);
19274 my $DPath = $TMP_DIR."/".$DName;
Andrey Ponomarenko5c09ef32012-06-14 18:17:33 +040019275 if(not $Archive) {
19276 $DPath = $DumpPath;
19277 }
19278
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040019279 mkpath($DDir);
Andrey Ponomarenko85043792012-05-14 16:48:07 +040019280
19281 open(DUMP, ">", $DPath) || die ("can't open file \'$DPath\': $!\n");
Andrey Ponomarenko5c09ef32012-06-14 18:17:33 +040019282 print DUMP $ABI_DUMP;
Andrey Ponomarenko85043792012-05-14 16:48:07 +040019283 close(DUMP);
19284
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040019285 if(not -s $DPath) {
19286 exitStatus("Error", "can't create ABI dump because something is going wrong with the Data::Dumper module");
19287 }
Andrey Ponomarenko07aea072012-11-12 16:15:07 +040019288 if($Archive) {
19289 $DumpPath = createArchive($DPath, $DDir);
Andrey Ponomarenko5c09ef32012-06-14 18:17:33 +040019290 }
19291
Andrey Ponomarenko07aea072012-11-12 16:15:07 +040019292 if(not $OutputDumpPath)
19293 {
19294 printMsg("INFO", "library ABI has been dumped to:\n $DumpPath");
19295 printMsg("INFO", "you can transfer this dump everywhere and use instead of the ".$Descriptor{1}{"Version"}." version descriptor");
19296 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040019297 }
19298}
19299
19300sub quickEmptyReports()
19301{ # Quick "empty" reports
19302 # 4 times faster than merging equal dumps
19303 # NOTE: the dump contains the "LibraryVersion" attribute
19304 # if you change the version, then your dump will be different
19305 # OVERCOME: use -v1 and v2 options for comparing dumps
19306 # and don't change version in the XML descriptor (and dumps)
19307 # OVERCOME 2: separate meta info from the dumps in ACC 2.0
19308 if(-s $Descriptor{1}{"Path"} == -s $Descriptor{2}{"Path"})
19309 {
19310 my $FilePath1 = unpackDump($Descriptor{1}{"Path"});
19311 my $FilePath2 = unpackDump($Descriptor{2}{"Path"});
19312 if($FilePath1 and $FilePath2)
19313 {
Andrey Ponomarenko01117f12012-06-26 12:23:02 +040019314 my $Line = readLineNum($FilePath1, 0);
19315 if($Line=~/xml/)
19316 { # XML format
19317 # is not supported yet
19318 return;
19319 }
19320
Andrey Ponomarenko85043792012-05-14 16:48:07 +040019321 local $/ = undef;
19322
19323 open(DUMP1, $FilePath1);
19324 my $Content1 = <DUMP1>;
19325 close(DUMP1);
19326
19327 open(DUMP2, $FilePath2);
19328 my $Content2 = <DUMP2>;
19329 close(DUMP2);
19330
19331 if($Content1 eq $Content2)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040019332 {
Andrey Ponomarenko85043792012-05-14 16:48:07 +040019333 # clean memory
19334 undef $Content2;
19335
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040019336 # read a number of headers, libs, symbols and types
Andrey Ponomarenko85043792012-05-14 16:48:07 +040019337 my $ABIdump = eval($Content1);
19338
19339 # clean memory
19340 undef $Content1;
19341
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040019342 if(not $ABIdump) {
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040019343 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 +040019344 }
19345 if(not $ABIdump->{"TypeInfo"})
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040019346 { # support for old dumps
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040019347 $ABIdump->{"TypeInfo"} = $ABIdump->{"TypeDescr"};
19348 }
19349 if(not $ABIdump->{"SymbolInfo"})
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040019350 { # support for old dumps
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040019351 $ABIdump->{"SymbolInfo"} = $ABIdump->{"FuncDescr"};
19352 }
19353 read_Headers_DumpInfo($ABIdump, 1);
19354 read_Libs_DumpInfo($ABIdump, 1);
19355 read_Machine_DumpInfo($ABIdump, 1);
19356 read_Machine_DumpInfo($ABIdump, 2);
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040019357
19358 %{$CheckedTypes{"Binary"}} = %{$ABIdump->{"TypeInfo"}};
19359 %{$CheckedTypes{"Source"}} = %{$ABIdump->{"TypeInfo"}};
19360
19361 %{$CheckedSymbols{"Binary"}} = %{$ABIdump->{"SymbolInfo"}};
19362 %{$CheckedSymbols{"Source"}} = %{$ABIdump->{"SymbolInfo"}};
19363
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040019364 $Descriptor{1}{"Version"} = $TargetVersion{1}?$TargetVersion{1}:$ABIdump->{"LibraryVersion"};
19365 $Descriptor{2}{"Version"} = $TargetVersion{2}?$TargetVersion{2}:$ABIdump->{"LibraryVersion"};
19366 exitReport();
19367 }
19368 }
19369 }
19370}
19371
19372sub initLogging($)
19373{
19374 my $LibVersion = $_[0];
19375 # create log directory
19376 my ($LOG_DIR, $LOG_FILE) = ("logs/$TargetLibraryName/".$Descriptor{$LibVersion}{"Version"}, "log.txt");
19377 if($OutputLogPath{$LibVersion})
19378 { # user-defined by -log-path option
19379 ($LOG_DIR, $LOG_FILE) = separate_path($OutputLogPath{$LibVersion});
19380 }
19381 if($LogMode ne "n") {
19382 mkpath($LOG_DIR);
19383 }
19384 $LOG_PATH{$LibVersion} = get_abs_path($LOG_DIR)."/".$LOG_FILE;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040019385 if($Debug)
19386 { # debug directory
19387 $DEBUG_PATH{$LibVersion} = "debug/$TargetLibraryName/".$Descriptor{$LibVersion}{"Version"};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040019388 }
Andrey Ponomarenko35c44fd2012-06-18 17:50:25 +040019389 resetLogging($LibVersion);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040019390}
19391
19392sub writeLog($$)
19393{
19394 my ($LibVersion, $Msg) = @_;
19395 if($LogMode ne "n") {
19396 appendFile($LOG_PATH{$LibVersion}, $Msg);
19397 }
19398}
19399
19400sub resetLogging($)
19401{
19402 my $LibVersion = $_[0];
19403 if($LogMode!~/a|n/)
19404 { # remove old log
19405 unlink($LOG_PATH{$LibVersion});
Andrey Ponomarenko35c44fd2012-06-18 17:50:25 +040019406 if($Debug) {
19407 rmtree($DEBUG_PATH{$LibVersion});
19408 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040019409 }
19410}
19411
19412sub printErrorLog($)
19413{
19414 my $LibVersion = $_[0];
19415 if($LogMode ne "n") {
19416 printMsg("ERROR", "see log for details:\n ".$LOG_PATH{$LibVersion}."\n");
19417 }
19418}
19419
19420sub isDump($)
19421{
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040019422 if(get_filename($_[0])=~/\A(.+)\.(abi|abidump)(\.tar\.gz|\.zip|\.xml|)\Z/) {
19423 return $1;
19424 }
19425 return 0;
19426}
19427
19428sub isDump_U($)
19429{
19430 if(get_filename($_[0])=~/\A(.+)\.(abi|abidump)(\.xml|)\Z/) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040019431 return $1;
19432 }
19433 return 0;
19434}
19435
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040019436sub compareInit()
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040019437{
19438 # read input XML descriptors or ABI dumps
19439 if(not $Descriptor{1}{"Path"}) {
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040019440 exitStatus("Error", "-old option is not specified");
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040019441 }
19442 my @DParts1 = split(/\s*,\s*/, $Descriptor{1}{"Path"});
19443 foreach my $Part (@DParts1)
19444 {
19445 if(not -e $Part) {
19446 exitStatus("Access_Error", "can't access \'$Part\'");
19447 }
19448 }
19449 if(not $Descriptor{2}{"Path"}) {
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040019450 exitStatus("Error", "-new option is not specified");
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040019451 }
19452 my @DParts2 = split(/\s*,\s*/, $Descriptor{2}{"Path"});
19453 foreach my $Part (@DParts2)
19454 {
19455 if(not -e $Part) {
19456 exitStatus("Access_Error", "can't access \'$Part\'");
19457 }
19458 }
19459 detect_default_paths("bin"); # to extract dumps
19460 if($#DParts1==0 and $#DParts2==0
19461 and isDump($Descriptor{1}{"Path"})
19462 and isDump($Descriptor{2}{"Path"}))
19463 { # optimization: equal ABI dumps
19464 quickEmptyReports();
19465 }
19466 checkVersionNum(1, $Descriptor{1}{"Path"});
19467 checkVersionNum(2, $Descriptor{2}{"Path"});
19468 printMsg("INFO", "preparation, please wait ...");
19469 foreach my $Part (@DParts1)
19470 {
19471 if(isDump($Part)) {
19472 read_ABI_Dump(1, $Part);
19473 }
19474 else {
19475 readDescriptor(1, createDescriptor(1, $Part));
19476 }
19477 }
19478 foreach my $Part (@DParts2)
19479 {
19480 if(isDump($Part)) {
19481 read_ABI_Dump(2, $Part);
19482 }
19483 else {
19484 readDescriptor(2, createDescriptor(2, $Part));
19485 }
19486 }
19487 initLogging(1);
19488 initLogging(2);
19489 # check consistency
19490 if(not $Descriptor{1}{"Headers"}
19491 and not $Descriptor{1}{"Libs"}) {
19492 exitStatus("Error", "descriptor d1 does not contain both header files and libraries info");
19493 }
19494 if(not $Descriptor{2}{"Headers"}
19495 and not $Descriptor{2}{"Libs"}) {
19496 exitStatus("Error", "descriptor d2 does not contain both header files and libraries info");
19497 }
19498 if($Descriptor{1}{"Headers"} and not $Descriptor{1}{"Libs"}
19499 and not $Descriptor{2}{"Headers"} and $Descriptor{2}{"Libs"}) {
19500 exitStatus("Error", "can't compare headers with $SLIB_TYPE libraries");
19501 }
19502 elsif(not $Descriptor{1}{"Headers"} and $Descriptor{1}{"Libs"}
19503 and $Descriptor{2}{"Headers"} and not $Descriptor{2}{"Libs"}) {
19504 exitStatus("Error", "can't compare $SLIB_TYPE libraries with headers");
19505 }
Andrey Ponomarenkobdc85a92012-11-12 17:28:12 +040019506 if(not $Descriptor{1}{"Headers"})
19507 {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040019508 if($CheckHeadersOnly_Opt) {
19509 exitStatus("Error", "can't find header files info in descriptor d1");
19510 }
19511 }
Andrey Ponomarenkobdc85a92012-11-12 17:28:12 +040019512 if(not $Descriptor{2}{"Headers"})
19513 {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040019514 if($CheckHeadersOnly_Opt) {
19515 exitStatus("Error", "can't find header files info in descriptor d2");
19516 }
19517 }
19518 if(not $Descriptor{1}{"Headers"}
Andrey Ponomarenkobdc85a92012-11-12 17:28:12 +040019519 or not $Descriptor{2}{"Headers"})
19520 {
19521 if(not $CheckObjectsOnly_Opt)
19522 {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040019523 printMsg("WARNING", "comparing $SLIB_TYPE libraries only");
19524 $CheckObjectsOnly = 1;
19525 }
19526 }
Andrey Ponomarenkobdc85a92012-11-12 17:28:12 +040019527 if(not $Descriptor{1}{"Libs"})
19528 {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040019529 if($CheckObjectsOnly_Opt) {
19530 exitStatus("Error", "can't find $SLIB_TYPE libraries info in descriptor d1");
19531 }
19532 }
Andrey Ponomarenkobdc85a92012-11-12 17:28:12 +040019533 if(not $Descriptor{2}{"Libs"})
19534 {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040019535 if($CheckObjectsOnly_Opt) {
19536 exitStatus("Error", "can't find $SLIB_TYPE libraries info in descriptor d2");
19537 }
19538 }
19539 if(not $Descriptor{1}{"Libs"}
19540 or not $Descriptor{2}{"Libs"})
19541 { # comparing standalone header files
19542 # comparing ABI dumps created with --headers-only
19543 if(not $CheckHeadersOnly_Opt)
19544 {
19545 printMsg("WARNING", "checking headers only");
19546 $CheckHeadersOnly = 1;
19547 }
19548 }
19549 if($UseDumps)
19550 { # --use-dumps
19551 # parallel processing
19552 my $pid = fork();
19553 if($pid)
19554 { # dump on two CPU cores
19555 my @PARAMS = ("-dump", $Descriptor{1}{"Path"}, "-l", $TargetLibraryName);
19556 if($RelativeDirectory{1}) {
19557 @PARAMS = (@PARAMS, "-relpath", $RelativeDirectory{1});
19558 }
19559 if($OutputLogPath{1}) {
19560 @PARAMS = (@PARAMS, "-log-path", $OutputLogPath{1});
19561 }
19562 if($CrossGcc) {
19563 @PARAMS = (@PARAMS, "-cross-gcc", $CrossGcc);
19564 }
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040019565 if($Quiet)
19566 {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040019567 @PARAMS = (@PARAMS, "-quiet");
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040019568 @PARAMS = (@PARAMS, "-logging-mode", "a");
19569 }
19570 elsif($LogMode and $LogMode ne "w")
19571 { # "w" is default
19572 @PARAMS = (@PARAMS, "-logging-mode", $LogMode);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040019573 }
19574 if($ExtendedCheck) {
19575 @PARAMS = (@PARAMS, "-extended");
19576 }
19577 if($UserLang) {
19578 @PARAMS = (@PARAMS, "-lang", $UserLang);
19579 }
19580 if($TargetVersion{1}) {
19581 @PARAMS = (@PARAMS, "-vnum", $TargetVersion{1});
19582 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +040019583 if($BinaryOnly) {
19584 @PARAMS = (@PARAMS, "-binary");
19585 }
19586 if($SourceOnly) {
19587 @PARAMS = (@PARAMS, "-source");
19588 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040019589 if($SortDump) {
19590 @PARAMS = (@PARAMS, "-sort");
19591 }
Andrey Ponomarenko01117f12012-06-26 12:23:02 +040019592 if($DumpFormat and $DumpFormat ne "perl") {
19593 @PARAMS = (@PARAMS, "-dump-format", $DumpFormat);
19594 }
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +040019595 if($CheckHeadersOnly) {
19596 @PARAMS = (@PARAMS, "-headers-only");
19597 }
19598 if($CheckObjectsOnly) {
19599 @PARAMS = (@PARAMS, "-objects-only");
19600 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +040019601 if($Debug)
19602 {
19603 @PARAMS = (@PARAMS, "-debug");
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040019604 printMsg("INFO", "running perl $0 @PARAMS");
Andrey Ponomarenko85043792012-05-14 16:48:07 +040019605 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040019606 system("perl", $0, @PARAMS);
19607 if($?) {
19608 exit(1);
19609 }
19610 }
19611 else
19612 { # child
19613 my @PARAMS = ("-dump", $Descriptor{2}{"Path"}, "-l", $TargetLibraryName);
19614 if($RelativeDirectory{2}) {
19615 @PARAMS = (@PARAMS, "-relpath", $RelativeDirectory{2});
19616 }
19617 if($OutputLogPath{2}) {
19618 @PARAMS = (@PARAMS, "-log-path", $OutputLogPath{2});
19619 }
19620 if($CrossGcc) {
19621 @PARAMS = (@PARAMS, "-cross-gcc", $CrossGcc);
19622 }
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040019623 if($Quiet)
19624 {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040019625 @PARAMS = (@PARAMS, "-quiet");
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040019626 @PARAMS = (@PARAMS, "-logging-mode", "a");
19627 }
19628 elsif($LogMode and $LogMode ne "w")
19629 { # "w" is default
19630 @PARAMS = (@PARAMS, "-logging-mode", $LogMode);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040019631 }
19632 if($ExtendedCheck) {
19633 @PARAMS = (@PARAMS, "-extended");
19634 }
19635 if($UserLang) {
19636 @PARAMS = (@PARAMS, "-lang", $UserLang);
19637 }
19638 if($TargetVersion{2}) {
19639 @PARAMS = (@PARAMS, "-vnum", $TargetVersion{2});
19640 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +040019641 if($BinaryOnly) {
19642 @PARAMS = (@PARAMS, "-binary");
19643 }
19644 if($SourceOnly) {
19645 @PARAMS = (@PARAMS, "-source");
19646 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040019647 if($SortDump) {
19648 @PARAMS = (@PARAMS, "-sort");
19649 }
Andrey Ponomarenko01117f12012-06-26 12:23:02 +040019650 if($DumpFormat and $DumpFormat ne "perl") {
19651 @PARAMS = (@PARAMS, "-dump-format", $DumpFormat);
19652 }
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +040019653 if($CheckHeadersOnly) {
19654 @PARAMS = (@PARAMS, "-headers-only");
19655 }
19656 if($CheckObjectsOnly) {
19657 @PARAMS = (@PARAMS, "-objects-only");
19658 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +040019659 if($Debug)
19660 {
19661 @PARAMS = (@PARAMS, "-debug");
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040019662 printMsg("INFO", "running perl $0 @PARAMS");
Andrey Ponomarenko85043792012-05-14 16:48:07 +040019663 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040019664 system("perl", $0, @PARAMS);
19665 if($?) {
19666 exit(1);
19667 }
19668 else {
19669 exit(0);
19670 }
19671 }
19672 waitpid($pid, 0);
19673 my @CMP_PARAMS = ("-l", $TargetLibraryName);
19674 @CMP_PARAMS = (@CMP_PARAMS, "-d1", "abi_dumps/$TargetLibraryName/".$TargetLibraryName."_".$Descriptor{1}{"Version"}.".abi.$AR_EXT");
19675 @CMP_PARAMS = (@CMP_PARAMS, "-d2", "abi_dumps/$TargetLibraryName/".$TargetLibraryName."_".$Descriptor{2}{"Version"}.".abi.$AR_EXT");
19676 if($TargetLibraryFName ne $TargetLibraryName) {
19677 @CMP_PARAMS = (@CMP_PARAMS, "-l-full", $TargetLibraryFName);
19678 }
19679 if($ShowRetVal) {
19680 @CMP_PARAMS = (@CMP_PARAMS, "-show-retval");
19681 }
19682 if($CrossGcc) {
19683 @CMP_PARAMS = (@CMP_PARAMS, "-cross-gcc", $CrossGcc);
19684 }
Andrey Ponomarenko35c44fd2012-06-18 17:50:25 +040019685 @CMP_PARAMS = (@CMP_PARAMS, "-logging-mode", "a");
19686 if($Quiet) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040019687 @CMP_PARAMS = (@CMP_PARAMS, "-quiet");
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040019688 }
19689 if($ReportFormat and $ReportFormat ne "html")
19690 { # HTML is default format
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040019691 @CMP_PARAMS = (@CMP_PARAMS, "-report-format", $ReportFormat);
19692 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040019693 if($OutputReportPath) {
19694 @CMP_PARAMS = (@CMP_PARAMS, "-report-path", $OutputReportPath);
19695 }
19696 if($BinaryReportPath) {
19697 @CMP_PARAMS = (@CMP_PARAMS, "-bin-report-path", $BinaryReportPath);
19698 }
19699 if($SourceReportPath) {
19700 @CMP_PARAMS = (@CMP_PARAMS, "-src-report-path", $SourceReportPath);
19701 }
19702 if($LoggingPath) {
19703 @CMP_PARAMS = (@CMP_PARAMS, "-log-path", $LoggingPath);
19704 }
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +040019705 if($CheckHeadersOnly) {
19706 @CMP_PARAMS = (@CMP_PARAMS, "-headers-only");
19707 }
19708 if($CheckObjectsOnly) {
19709 @CMP_PARAMS = (@CMP_PARAMS, "-objects-only");
19710 }
19711 if($BinaryOnly) {
19712 @CMP_PARAMS = (@CMP_PARAMS, "-binary");
19713 }
19714 if($SourceOnly) {
19715 @CMP_PARAMS = (@CMP_PARAMS, "-source");
19716 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +040019717 if($Browse) {
19718 @CMP_PARAMS = (@CMP_PARAMS, "-browse", $Browse);
19719 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040019720 if($OpenReport) {
19721 @CMP_PARAMS = (@CMP_PARAMS, "-open");
19722 }
19723 if($Debug)
19724 {
19725 @CMP_PARAMS = (@CMP_PARAMS, "-debug");
19726 printMsg("INFO", "running perl $0 @CMP_PARAMS");
Andrey Ponomarenko85043792012-05-14 16:48:07 +040019727 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040019728 system("perl", $0, @CMP_PARAMS);
19729 exit($?>>8);
19730 }
19731 if(not $Descriptor{1}{"Dump"}
19732 or not $Descriptor{2}{"Dump"})
19733 { # need GCC toolchain to analyze
19734 # header files and libraries
19735 detect_default_paths("inc|lib|gcc");
19736 }
19737 if(not $Descriptor{1}{"Dump"})
19738 {
19739 if(not $CheckHeadersOnly) {
19740 readLibs(1);
19741 }
19742 if($CheckHeadersOnly) {
19743 setLanguage(1, "C++");
19744 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +040019745 if(not $CheckObjectsOnly) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040019746 searchForHeaders(1);
19747 }
19748 $WORD_SIZE{1} = detectWordSize();
19749 }
19750 if(not $Descriptor{2}{"Dump"})
19751 {
19752 if(not $CheckHeadersOnly) {
19753 readLibs(2);
19754 }
19755 if($CheckHeadersOnly) {
19756 setLanguage(2, "C++");
19757 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +040019758 if(not $CheckObjectsOnly) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040019759 searchForHeaders(2);
19760 }
19761 $WORD_SIZE{2} = detectWordSize();
19762 }
19763 if($WORD_SIZE{1} ne $WORD_SIZE{2})
19764 { # support for old ABI dumps
19765 # try to synch different WORD sizes
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040019766 if(not checkDump(1, "2.1"))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040019767 {
19768 $WORD_SIZE{1} = $WORD_SIZE{2};
19769 printMsg("WARNING", "set WORD size to ".$WORD_SIZE{2}." bytes");
19770 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040019771 elsif(not checkDump(2, "2.1"))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040019772 {
19773 $WORD_SIZE{2} = $WORD_SIZE{1};
19774 printMsg("WARNING", "set WORD size to ".$WORD_SIZE{1}." bytes");
19775 }
19776 }
19777 elsif(not $WORD_SIZE{1}
19778 and not $WORD_SIZE{2})
19779 { # support for old ABI dumps
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040019780 $WORD_SIZE{1} = "4";
19781 $WORD_SIZE{2} = "4";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040019782 }
19783 if($Descriptor{1}{"Dump"})
19784 { # support for old ABI dumps
19785 prepareTypes(1);
19786 }
19787 if($Descriptor{2}{"Dump"})
19788 { # support for old ABI dumps
19789 prepareTypes(2);
19790 }
19791 if($AppPath and not keys(%{$Symbol_Library{1}})) {
19792 printMsg("WARNING", "the application ".get_filename($AppPath)." has no symbols imported from the $SLIB_TYPE libraries");
19793 }
19794 # started to process input data
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040019795 if(not $CheckObjectsOnly)
19796 {
19797 if($Descriptor{1}{"Headers"}
19798 and not $Descriptor{1}{"Dump"}) {
19799 readHeaders(1);
19800 }
19801 if($Descriptor{2}{"Headers"}
19802 and not $Descriptor{2}{"Dump"}) {
19803 readHeaders(2);
19804 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040019805 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +040019806
19807 # clean memory
19808 %SystemHeaders = ();
19809 %mangled_name_gcc = ();
19810
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040019811 prepareSymbols(1);
19812 prepareSymbols(2);
Andrey Ponomarenko16934472012-03-29 15:37:04 +040019813
Andrey Ponomarenko85043792012-05-14 16:48:07 +040019814 # clean memory
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040019815 %SymbolInfo = ();
Andrey Ponomarenko16934472012-03-29 15:37:04 +040019816
19817 # Virtual Tables
19818 registerVTable(1);
19819 registerVTable(2);
19820
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040019821 if(not checkDump(1, "1.22")
19822 and checkDump(2, "1.22"))
Andrey Ponomarenko16934472012-03-29 15:37:04 +040019823 { # support for old ABI dumps
19824 foreach my $ClassName (keys(%{$VirtualTable{2}}))
19825 {
19826 if($ClassName=~/</)
19827 { # templates
19828 if(not defined $VirtualTable{1}{$ClassName})
19829 { # synchronize
19830 delete($VirtualTable{2}{$ClassName});
19831 }
19832 }
19833 }
19834 }
19835
19836 registerOverriding(1);
19837 registerOverriding(2);
19838
19839 setVirtFuncPositions(1);
19840 setVirtFuncPositions(2);
19841
19842 # Other
19843 addParamNames(1);
19844 addParamNames(2);
19845
19846 detectChangedTypedefs();
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040019847}
19848
19849sub compareAPIs($)
19850{
19851 my $Level = $_[0];
19852 readRules($Level);
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +040019853 loadModule("CallConv");
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040019854 if($Level eq "Binary") {
19855 printMsg("INFO", "comparing ABIs ...");
19856 }
19857 else {
19858 printMsg("INFO", "comparing APIs ...");
19859 }
19860 if($CheckHeadersOnly
19861 or $Level eq "Source")
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040019862 { # added/removed in headers
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040019863 detectAdded_H($Level);
19864 detectRemoved_H($Level);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040019865 }
19866 else
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040019867 { # added/removed in libs
19868 detectAdded($Level);
19869 detectRemoved($Level);
19870 }
19871 if(not $CheckObjectsOnly)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040019872 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040019873 mergeSignatures($Level);
19874 if(keys(%{$CheckedSymbols{$Level}})) {
19875 mergeConstants($Level);
19876 }
19877 }
19878 if($CheckHeadersOnly
19879 or $Level eq "Source")
19880 { # added/removed in headers
19881 mergeHeaders($Level);
19882 }
19883 else
19884 { # added/removed in libs
19885 mergeLibs($Level);
19886 if($CheckImpl
19887 and $Level eq "Binary") {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040019888 mergeImpl();
19889 }
19890 }
19891}
19892
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040019893sub getSysOpts()
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040019894{
19895 my %Opts = (
19896 "OStarget"=>$OStarget,
19897 "Debug"=>$Debug,
19898 "Quiet"=>$Quiet,
19899 "LogMode"=>$LogMode,
19900 "CheckHeadersOnly"=>$CheckHeadersOnly,
19901
19902 "SystemRoot"=>$SystemRoot,
19903 "MODULES_DIR"=>$MODULES_DIR,
19904 "GCC_PATH"=>$GCC_PATH,
19905 "TargetSysInfo"=>$TargetSysInfo,
19906 "CrossPrefix"=>$CrossPrefix,
19907 "TargetLibraryName"=>$TargetLibraryName,
19908 "CrossGcc"=>$CrossGcc,
19909 "UseStaticLibs"=>$UseStaticLibs,
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040019910 "NoStdInc"=>$NoStdInc,
19911
19912 "BinaryOnly" => $BinaryOnly,
19913 "SourceOnly" => $SourceOnly
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040019914 );
19915 return \%Opts;
19916}
19917
19918sub get_CoreError($)
19919{
19920 my %CODE_ERROR = reverse(%ERROR_CODE);
19921 return $CODE_ERROR{$_[0]};
19922}
19923
19924sub scenario()
19925{
19926 if($StdOut)
19927 { # enable quiet mode
19928 $Quiet = 1;
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040019929 $JoinReport = 1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040019930 }
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040019931 if(not $LogMode)
19932 { # default
19933 $LogMode = "w";
19934 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040019935 if($UserLang)
19936 { # --lang=C++
19937 $UserLang = uc($UserLang);
19938 $COMMON_LANGUAGE{1}=$UserLang;
19939 $COMMON_LANGUAGE{2}=$UserLang;
19940 }
19941 if($LoggingPath)
19942 {
19943 $OutputLogPath{1} = $LoggingPath;
19944 $OutputLogPath{2} = $LoggingPath;
19945 if($Quiet) {
19946 $COMMON_LOG_PATH = $LoggingPath;
19947 }
19948 }
Andrey Ponomarenko5c09ef32012-06-14 18:17:33 +040019949 if($OutputDumpPath)
19950 { # validate
19951 if($OutputDumpPath!~/\.abi(\.\Q$AR_EXT\E|)\Z/) {
19952 exitStatus("Error", "the dump path should be a path to *.abi.$AR_EXT or *.abi file");
19953 }
19954 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040019955 if($BinaryOnly and $SourceOnly)
19956 { # both --binary and --source
19957 # is the default mode
19958 $DoubleReport = 1;
19959 $JoinReport = 0;
19960 $BinaryOnly = 0;
19961 $SourceOnly = 0;
19962 if($OutputReportPath)
19963 { # --report-path
19964 $DoubleReport = 0;
19965 $JoinReport = 1;
19966 }
19967 }
19968 elsif($BinaryOnly or $SourceOnly)
19969 { # --binary or --source
19970 $DoubleReport = 0;
19971 $JoinReport = 0;
19972 }
19973 if($UseXML)
19974 { # --xml option
19975 $ReportFormat = "xml";
Andrey Ponomarenko5c09ef32012-06-14 18:17:33 +040019976 $DumpFormat = "xml";
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040019977 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040019978 if($ReportFormat)
19979 { # validate
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040019980 $ReportFormat = lc($ReportFormat);
19981 if($ReportFormat!~/\A(xml|html|htm)\Z/) {
Andrey Ponomarenko5c09ef32012-06-14 18:17:33 +040019982 exitStatus("Error", "unknown report format \'$ReportFormat\'");
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040019983 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040019984 if($ReportFormat eq "htm")
19985 { # HTM == HTML
19986 $ReportFormat = "html";
19987 }
19988 elsif($ReportFormat eq "xml")
19989 { # --report-format=XML equal to --xml
19990 $UseXML = 1;
19991 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040019992 }
19993 else
19994 { # default: HTML
19995 $ReportFormat = "html";
19996 }
Andrey Ponomarenko5c09ef32012-06-14 18:17:33 +040019997 if($DumpFormat)
19998 { # validate
19999 $DumpFormat = lc($DumpFormat);
20000 if($DumpFormat!~/\A(xml|perl)\Z/) {
20001 exitStatus("Error", "unknown ABI dump format \'$DumpFormat\'");
20002 }
20003 if($DumpFormat eq "xml")
20004 { # --dump-format=XML equal to --xml
20005 $UseXML = 1;
20006 }
20007 }
20008 else
Andrey Ponomarenko01117f12012-06-26 12:23:02 +040020009 { # default: Perl Data::Dumper
Andrey Ponomarenko5c09ef32012-06-14 18:17:33 +040020010 $DumpFormat = "perl";
20011 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040020012 if($Quiet and $LogMode!~/a|n/)
20013 { # --quiet log
20014 if(-f $COMMON_LOG_PATH) {
20015 unlink($COMMON_LOG_PATH);
20016 }
20017 }
20018 if($TestTool and $UseDumps)
20019 { # --test && --use-dumps == --test-dump
20020 $TestDump = 1;
20021 }
20022 if($Help) {
20023 HELP_MESSAGE();
20024 exit(0);
20025 }
20026 if($InfoMsg) {
20027 INFO_MESSAGE();
20028 exit(0);
20029 }
20030 if($ShowVersion) {
20031 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.");
20032 exit(0);
20033 }
20034 if($DumpVersion) {
20035 printMsg("INFO", $TOOL_VERSION);
20036 exit(0);
20037 }
20038 if($ExtendedCheck) {
20039 $CheckHeadersOnly = 1;
20040 }
20041 if($SystemRoot_Opt)
20042 { # user defined root
20043 if(not -e $SystemRoot_Opt) {
20044 exitStatus("Access_Error", "can't access \'$SystemRoot\'");
20045 }
20046 $SystemRoot = $SystemRoot_Opt;
20047 $SystemRoot=~s/[\/]+\Z//g;
20048 if($SystemRoot) {
20049 $SystemRoot = get_abs_path($SystemRoot);
20050 }
20051 }
20052 $Data::Dumper::Sortkeys = 1;
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +040020053
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040020054 if($SortDump)
20055 {
20056 $Data::Dumper::Useperl = 1;
20057 $Data::Dumper::Sortkeys = \&dump_sorting;
20058 }
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +040020059
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040020060 if($TargetLibsPath)
20061 {
20062 if(not -f $TargetLibsPath) {
20063 exitStatus("Access_Error", "can't access file \'$TargetLibsPath\'");
20064 }
20065 foreach my $Lib (split(/\s*\n\s*/, readFile($TargetLibsPath))) {
20066 $TargetLibs{$Lib} = 1;
20067 }
20068 }
20069 if($TargetHeadersPath)
20070 { # --headers-list
20071 if(not -f $TargetHeadersPath) {
20072 exitStatus("Access_Error", "can't access file \'$TargetHeadersPath\'");
20073 }
20074 foreach my $Header (split(/\s*\n\s*/, readFile($TargetHeadersPath)))
20075 {
20076 $TargetHeaders{1}{$Header} = 1;
20077 $TargetHeaders{2}{$Header} = 1;
20078 }
20079 }
20080 if($TargetHeader)
20081 { # --header
20082 $TargetHeaders{1}{$TargetHeader} = 1;
20083 $TargetHeaders{2}{$TargetHeader} = 1;
20084 }
20085 if($TestTool
20086 or $TestDump)
20087 { # --test, --test-dump
20088 detect_default_paths("bin|gcc"); # to compile libs
20089 loadModule("RegTests");
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +040020090 testTool($TestDump, $Debug, $Quiet, $ExtendedCheck, $LogMode, $ReportFormat, $DumpFormat,
20091 $LIB_EXT, $GCC_PATH, $Browse, $OpenReport, $SortDump, $CheckHeadersOnly, $CheckObjectsOnly);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040020092 exit(0);
20093 }
20094 if($DumpSystem)
20095 { # --dump-system
20096 loadModule("SysCheck");
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040020097 if($DumpSystem=~/\.(xml|desc)\Z/)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040020098 { # system XML descriptor
20099 if(not -f $DumpSystem) {
20100 exitStatus("Access_Error", "can't access file \'$DumpSystem\'");
20101 }
20102 my $Ret = readSystemDescriptor(readFile($DumpSystem));
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040020103 foreach (@{$Ret->{"Tools"}})
20104 {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040020105 $SystemPaths{"bin"}{$_} = 1;
20106 $TargetTools{$_}=1;
20107 }
20108 if($Ret->{"CrossPrefix"}) {
20109 $CrossPrefix = $Ret->{"CrossPrefix"};
20110 }
20111 }
20112 elsif($SystemRoot_Opt)
20113 { # -sysroot "/" option
20114 # default target: /usr/lib, /usr/include
20115 # search libs: /usr/lib and /lib
20116 if(not -e $SystemRoot."/usr/lib") {
20117 exitStatus("Access_Error", "can't access '".$SystemRoot."/usr/lib'");
20118 }
20119 if(not -e $SystemRoot."/lib") {
20120 exitStatus("Access_Error", "can't access '".$SystemRoot."/lib'");
20121 }
20122 if(not -e $SystemRoot."/usr/include") {
20123 exitStatus("Access_Error", "can't access '".$SystemRoot."/usr/include'");
20124 }
20125 readSystemDescriptor("
20126 <name>
20127 $DumpSystem
20128 </name>
20129 <headers>
20130 $SystemRoot/usr/include
20131 </headers>
20132 <libs>
20133 $SystemRoot/usr/lib
20134 </libs>
20135 <search_libs>
20136 $SystemRoot/lib
20137 </search_libs>");
20138 }
20139 else {
20140 exitStatus("Error", "-sysroot <dirpath> option should be specified, usually it's \"/\"");
20141 }
20142 detect_default_paths("bin|gcc"); # to check symbols
20143 if($OStarget eq "windows")
20144 { # to run dumpbin.exe
20145 # and undname.exe
20146 check_win32_env();
20147 }
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040020148 dumpSystem(getSysOpts());
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040020149 exit(0);
20150 }
20151 if($CmpSystems)
20152 { # --cmp-systems
20153 detect_default_paths("bin"); # to extract dumps
20154 loadModule("SysCheck");
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040020155 cmpSystems($Descriptor{1}{"Path"}, $Descriptor{2}{"Path"}, getSysOpts());
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040020156 exit(0);
20157 }
20158 if($GenerateTemplate) {
20159 generateTemplate();
20160 exit(0);
20161 }
20162 if(not $TargetLibraryName) {
20163 exitStatus("Error", "library name is not selected (option -l <name>)");
20164 }
20165 else
20166 { # validate library name
20167 if($TargetLibraryName=~/[\*\/\\]/) {
20168 exitStatus("Error", "\"\\\", \"\/\" and \"*\" symbols are not allowed in the library name");
20169 }
20170 }
20171 if(not $TargetLibraryFName) {
20172 $TargetLibraryFName = $TargetLibraryName;
20173 }
20174 if($CheckHeadersOnly_Opt and $CheckObjectsOnly_Opt) {
20175 exitStatus("Error", "you can't specify both -headers-only and -objects-only options at the same time");
20176 }
20177 if($SymbolsListPath)
20178 {
20179 if(not -f $SymbolsListPath) {
20180 exitStatus("Access_Error", "can't access file \'$SymbolsListPath\'");
20181 }
20182 foreach my $Interface (split(/\s*\n\s*/, readFile($SymbolsListPath))) {
20183 $SymbolsList{$Interface} = 1;
20184 }
20185 }
20186 if($SkipHeadersPath)
20187 {
20188 if(not -f $SkipHeadersPath) {
20189 exitStatus("Access_Error", "can't access file \'$SkipHeadersPath\'");
20190 }
20191 foreach my $Path (split(/\s*\n\s*/, readFile($SkipHeadersPath)))
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040020192 { # register for both versions
20193 $SkipHeadersList{1}{$Path} = 1;
20194 $SkipHeadersList{2}{$Path} = 1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040020195 my ($CPath, $Type) = classifyPath($Path);
20196 $SkipHeaders{1}{$Type}{$CPath} = 1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040020197 $SkipHeaders{2}{$Type}{$CPath} = 1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040020198 }
20199 }
20200 if($ParamNamesPath)
20201 {
20202 if(not -f $ParamNamesPath) {
20203 exitStatus("Access_Error", "can't access file \'$ParamNamesPath\'");
20204 }
20205 foreach my $Line (split(/\n/, readFile($ParamNamesPath)))
20206 {
20207 if($Line=~s/\A(\w+)\;//)
20208 {
20209 my $Interface = $1;
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040020210 if($Line=~/;(\d+);/)
20211 {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040020212 while($Line=~s/(\d+);(\w+)//) {
20213 $AddIntParams{$Interface}{$1}=$2;
20214 }
20215 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040020216 else
20217 {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040020218 my $Num = 0;
20219 foreach my $Name (split(/;/, $Line)) {
20220 $AddIntParams{$Interface}{$Num++}=$Name;
20221 }
20222 }
20223 }
20224 }
20225 }
20226 if($AppPath)
20227 {
20228 if(not -f $AppPath) {
20229 exitStatus("Access_Error", "can't access file \'$AppPath\'");
20230 }
Andrey Ponomarenko16934472012-03-29 15:37:04 +040020231 foreach my $Interface (readSymbols_App($AppPath)) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040020232 $SymbolsList_App{$Interface} = 1;
20233 }
20234 }
20235 if($DumpAPI)
20236 { # --dump-abi
20237 # make an API dump
20238 create_ABI_Dump();
20239 exit($COMPILE_ERRORS);
20240 }
20241 # default: compare APIs
20242 # -d1 <path>
20243 # -d2 <path>
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040020244 compareInit();
20245 if($JoinReport or $DoubleReport)
20246 {
20247 compareAPIs("Binary");
20248 compareAPIs("Source");
20249 }
20250 elsif($BinaryOnly) {
20251 compareAPIs("Binary");
20252 }
20253 elsif($SourceOnly) {
20254 compareAPIs("Source");
20255 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040020256 exitReport();
20257}
20258
20259scenario();