blob: 53a79d897efb2dd20d92edafb41dcd1c052f5660 [file] [log] [blame]
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04001#!/usr/bin/perl
2###########################################################################
Andrey Ponomarenko4b077f82012-12-04 16:04:36 +04003# ABI Compliance Checker (ACC) 1.98.6
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 Ponomarenko570ece52012-11-30 16:36:44 +040026# - Xcode (g++, c++filt, otool, 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 Ponomarenko4b077f82012-12-04 16:04:36 +040062my $TOOL_VERSION = "1.98.6";
Andrey Ponomarenko07aea072012-11-12 16:15:07 +040063my $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,
Andrey Ponomarenko570ece52012-11-30 16:36:44 +040090$ExtraInfo, $ExtraDump, $Force);
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
Andrey Ponomarenko570ece52012-11-30 16:36:44 +0400173if($#ARGV==-1)
174{
Andrey Ponomarenkoab282102012-03-11 11:57:02 +0400175 printMsg("INFO", $ShortUsage);
176 exit(0);
177}
178
179foreach (2 .. $#ARGV)
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +0400180{ # correct comma separated options
Andrey Ponomarenko570ece52012-11-30 16:36:44 +0400181 if($ARGV[$_-1] eq ",")
182 {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +0400183 $ARGV[$_-2].=",".$ARGV[$_];
184 splice(@ARGV, $_-1, 2);
185 }
Andrey Ponomarenko570ece52012-11-30 16:36:44 +0400186 elsif($ARGV[$_-1]=~/,\Z/)
187 {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +0400188 $ARGV[$_-1].=$ARGV[$_];
189 splice(@ARGV, $_, 1);
190 }
191 elsif($ARGV[$_]=~/\A,/
Andrey Ponomarenko570ece52012-11-30 16:36:44 +0400192 and $ARGV[$_] ne ",")
193 {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +0400194 $ARGV[$_-1].=$ARGV[$_];
195 splice(@ARGV, $_, 1);
196 }
197}
198
199GetOptions("h|help!" => \$Help,
200 "i|info!" => \$InfoMsg,
201 "v|version!" => \$ShowVersion,
202 "dumpversion!" => \$DumpVersion,
203# general options
204 "l|lib|library=s" => \$TargetLibraryName,
205 "d1|old|o=s" => \$Descriptor{1}{"Path"},
206 "d2|new|n=s" => \$Descriptor{2}{"Path"},
207 "dump|dump-abi|dump_abi=s" => \$DumpAPI,
208 "old-dumps!" => \$UseOldDumps,
209# extra options
210 "d|descriptor-template!" => \$GenerateTemplate,
211 "app|application=s" => \$AppPath,
212 "static-libs!" => \$UseStaticLibs,
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +0400213 "cross-gcc|gcc-path=s" => \$CrossGcc,
214 "cross-prefix|gcc-prefix=s" => \$CrossPrefix,
Andrey Ponomarenkoab282102012-03-11 11:57:02 +0400215 "sysroot=s" => \$SystemRoot_Opt,
216 "v1|version1|vnum=s" => \$TargetVersion{1},
217 "v2|version2=s" => \$TargetVersion{2},
218 "s|strict!" => \$StrictCompat,
219 "symbols-list=s" => \$SymbolsListPath,
220 "skip-headers=s" => \$SkipHeadersPath,
221 "headers-only|headers_only!" => \$CheckHeadersOnly_Opt,
222 "objects-only!" => \$CheckObjectsOnly_Opt,
223 "check-impl|check-implementation!" => \$CheckImpl,
224 "show-retval!" => \$ShowRetVal,
225 "use-dumps!" => \$UseDumps,
226 "nostdinc!" => \$NoStdInc,
227 "dump-system=s" => \$DumpSystem,
228 "sysinfo=s" => \$TargetSysInfo,
229 "cmp-systems!" => \$CmpSystems,
230 "libs-list=s" => \$TargetLibsPath,
231 "headers-list=s" => \$TargetHeadersPath,
232 "header=s" => \$TargetHeader,
233 "ext|extended!" => \$ExtendedCheck,
234 "q|quiet!" => \$Quiet,
235 "stdout!" => \$StdOut,
236 "report-format=s" => \$ReportFormat,
Andrey Ponomarenko5c09ef32012-06-14 18:17:33 +0400237 "dump-format=s" => \$DumpFormat,
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +0400238 "xml!" => \$UseXML,
Andrey Ponomarenkoab282102012-03-11 11:57:02 +0400239 "lang=s" => \$UserLang,
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +0400240 "binary|bin|abi!" => \$BinaryOnly,
241 "source|src|api!" => \$SourceOnly,
Andrey Ponomarenkoab282102012-03-11 11:57:02 +0400242# other options
243 "test!" => \$TestTool,
244 "test-dump!" => \$TestDump,
245 "debug!" => \$Debug,
Andrey Ponomarenko07aea072012-11-12 16:15:07 +0400246 "cpp-compatible!" => \$CppCompat,
Andrey Ponomarenkoab282102012-03-11 11:57:02 +0400247 "p|params=s" => \$ParamNamesPath,
248 "relpath1|relpath=s" => \$RelativeDirectory{1},
249 "relpath2=s" => \$RelativeDirectory{2},
250 "dump-path=s" => \$OutputDumpPath,
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +0400251 "sort!" => \$SortDump,
Andrey Ponomarenkoab282102012-03-11 11:57:02 +0400252 "report-path=s" => \$OutputReportPath,
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +0400253 "bin-report-path=s" => \$BinaryReportPath,
254 "src-report-path=s" => \$SourceReportPath,
Andrey Ponomarenkoab282102012-03-11 11:57:02 +0400255 "log-path=s" => \$LoggingPath,
256 "log1-path=s" => \$OutputLogPath{1},
257 "log2-path=s" => \$OutputLogPath{2},
258 "logging-mode=s" => \$LogMode,
259 "list-affected!" => \$ListAffected,
260 "l-full|lib-full=s" => \$TargetLibraryFName,
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +0400261 "component=s" => \$TargetComponent_Opt,
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +0400262 "b|browse=s" => \$Browse,
Andrey Ponomarenko07aea072012-11-12 16:15:07 +0400263 "open!" => \$OpenReport,
Andrey Ponomarenko570ece52012-11-30 16:36:44 +0400264 "extra-info=s" => \$ExtraInfo,
265 "extra-dump!" => \$ExtraDump,
266 "force!" => \$Force
Andrey Ponomarenkoab282102012-03-11 11:57:02 +0400267) or ERR_MESSAGE();
268
269sub ERR_MESSAGE()
270{
271 printMsg("INFO", "\n".$ShortUsage);
272 exit($ERROR_CODE{"Error"});
273}
274
275my $LIB_TYPE = $UseStaticLibs?"static":"dynamic";
276my $SLIB_TYPE = $LIB_TYPE;
277if($OSgroup!~/macos|windows/ and $SLIB_TYPE eq "dynamic")
278{ # show as "shared" library
279 $SLIB_TYPE = "shared";
280}
281my $LIB_EXT = getLIB_EXT($OSgroup);
282my $AR_EXT = getAR_EXT($OSgroup);
283my $BYTE_SIZE = 8;
284my $COMMON_LOG_PATH = "logs/run.log";
285
286my $HelpMessage="
287NAME:
288 ABI Compliance Checker ($CmdName)
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +0400289 Check backward compatibility of a C/C++ library API
Andrey Ponomarenkoab282102012-03-11 11:57:02 +0400290
291DESCRIPTION:
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +0400292 ABI Compliance Checker (ACC) is a tool for checking backward binary and
293 source-level compatibility of a $SLIB_TYPE C/C++ library. The tool checks
294 header files and $SLIB_TYPE libraries (*.$LIB_EXT) of old and new versions and
295 analyzes changes in API and ABI (ABI=API+compiler ABI) that may break binary
296 and/or source-level compatibility: changes in calling stack, v-table changes,
297 removed symbols, renamed fields, etc. Binary incompatibility may result in
298 crashing or incorrect behavior of applications built with an old version of
299 a library if they run on a new one. Source incompatibility may result in
300 recompilation errors with a new library version.
Andrey Ponomarenkoab282102012-03-11 11:57:02 +0400301
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +0400302 The tool is intended for developers of software libraries and maintainers
303 of operating systems who are interested in ensuring backward compatibility,
304 i.e. allow old applications to run or to be recompiled with newer library
305 versions.
306
307 Also the tool can be used by ISVs for checking applications portability to
308 new library versions. Found issues can be taken into account when adapting
309 the application to a new library version.
Andrey Ponomarenkoab282102012-03-11 11:57:02 +0400310
311 This tool is free software: you can redistribute it and/or modify it
312 under the terms of the GNU LGPL or GNU GPL.
313
314USAGE:
315 $CmdName [options]
316
317EXAMPLE:
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +0400318 $CmdName -lib NAME -old OLD.xml -new NEW.xml
Andrey Ponomarenkoab282102012-03-11 11:57:02 +0400319
320 OLD.xml and NEW.xml are XML-descriptors:
321
322 <version>
323 1.0
324 </version>
325
326 <headers>
327 /path1/to/header(s)/
328 /path2/to/header(s)/
329 ...
330 </headers>
331
332 <libs>
333 /path1/to/library(ies)/
334 /path2/to/library(ies)/
335 ...
336 </libs>
337
338INFORMATION OPTIONS:
339 -h|-help
340 Print this help.
341
342 -i|-info
343 Print complete info.
344
345 -v|-version
346 Print version information.
347
348 -dumpversion
349 Print the tool version ($TOOL_VERSION) and don't do anything else.
350
351GENERAL OPTIONS:
Andrey Ponomarenko07aea072012-11-12 16:15:07 +0400352 -l|-lib|-library NAME
Andrey Ponomarenkoab282102012-03-11 11:57:02 +0400353 Library name (without version).
Andrey Ponomarenkoab282102012-03-11 11:57:02 +0400354
Andrey Ponomarenko07aea072012-11-12 16:15:07 +0400355 -d1|-old|-o PATH
Andrey Ponomarenkoab282102012-03-11 11:57:02 +0400356 Descriptor of 1st (old) library version.
357 It may be one of the following:
358
359 1. XML-descriptor (VERSION.xml file):
360
361 <version>
362 1.0
363 </version>
364
365 <headers>
366 /path1/to/header(s)/
367 /path2/to/header(s)/
368 ...
369 </headers>
370
371 <libs>
372 /path1/to/library(ies)/
373 /path2/to/library(ies)/
374 ...
375 </libs>
376
377 ... (XML-descriptor template
378 can be generated by -d option)
379
380 2. ABI dump generated by -dump option
381 3. Directory with headers and/or $SLIB_TYPE libraries
382 4. Single header file
383 5. Single $SLIB_TYPE library
384 6. Comma separated list of headers and/or libraries
385
386 If you are using an 2-6 descriptor types then you should
Andrey Ponomarenko570ece52012-11-30 16:36:44 +0400387 specify version numbers with -v1 and -v2 options too.
Andrey Ponomarenkoab282102012-03-11 11:57:02 +0400388
389 For more information, please see:
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +0400390 http://ispras.linuxbase.org/index.php/Library_Descriptor
Andrey Ponomarenkoab282102012-03-11 11:57:02 +0400391
Andrey Ponomarenko07aea072012-11-12 16:15:07 +0400392 -d2|-new|-n PATH
Andrey Ponomarenkoab282102012-03-11 11:57:02 +0400393 Descriptor of 2nd (new) library version.
394
Andrey Ponomarenko07aea072012-11-12 16:15:07 +0400395 -dump|-dump-abi PATH
Andrey Ponomarenko570ece52012-11-30 16:36:44 +0400396 Create library ABI dump for the input XML descriptor. You can
397 transfer it anywhere and pass instead of the descriptor. Also
398 it can be used for debugging the tool.
399
400 Supported ABI dump versions: ".majorVersion($ABI_DUMP_VERSION).".0<=V<=$ABI_DUMP_VERSION
Andrey Ponomarenkoab282102012-03-11 11:57:02 +0400401
402 -old-dumps
403 Enable support for old-version ABI dumps ($OLDEST_SUPPORTED_VERSION<=V<".majorVersion($ABI_DUMP_VERSION).".0).\n";
404
405sub HELP_MESSAGE() {
406 printMsg("INFO", $HelpMessage."
407MORE INFO:
408 $CmdName --info\n");
409}
410
411sub INFO_MESSAGE()
412{
413 printMsg("INFO", "$HelpMessage
414EXTRA OPTIONS:
415 -d|-descriptor-template
416 Create XML-descriptor template ./VERSION.xml
417
Andrey Ponomarenko07aea072012-11-12 16:15:07 +0400418 -app|-application PATH
Andrey Ponomarenkoab282102012-03-11 11:57:02 +0400419 This option allows to specify the application that should be checked
420 for portability to the new library version.
421
422 -static-libs
423 Check static libraries instead of the shared ones. The <libs> section
424 of the XML-descriptor should point to static libraries location.
425
Andrey Ponomarenko07aea072012-11-12 16:15:07 +0400426 -cross-gcc|-gcc-path PATH
Andrey Ponomarenkoab282102012-03-11 11:57:02 +0400427 Path to the cross GCC compiler to use instead of the usual (host) GCC.
428
Andrey Ponomarenko07aea072012-11-12 16:15:07 +0400429 -cross-prefix|-gcc-prefix PREFIX
Andrey Ponomarenkoab282102012-03-11 11:57:02 +0400430 GCC toolchain prefix.
431
Andrey Ponomarenko07aea072012-11-12 16:15:07 +0400432 -sysroot DIR
Andrey Ponomarenkoab282102012-03-11 11:57:02 +0400433 Specify the alternative root directory. The tool will search for include
Andrey Ponomarenko07aea072012-11-12 16:15:07 +0400434 paths in the DIR/usr/include and DIR/usr/lib directories.
Andrey Ponomarenkoab282102012-03-11 11:57:02 +0400435
Andrey Ponomarenko07aea072012-11-12 16:15:07 +0400436 -v1|-version1 NUM
Andrey Ponomarenkoab282102012-03-11 11:57:02 +0400437 Specify 1st library version outside the descriptor. This option is needed
438 if you have prefered an alternative descriptor type (see -d1 option).
439
440 In general case you should specify it in the XML-descriptor:
441 <version>
442 VERSION
443 </version>
444
Andrey Ponomarenko07aea072012-11-12 16:15:07 +0400445 -v2|-version2 NUM
Andrey Ponomarenkoab282102012-03-11 11:57:02 +0400446 Specify 2nd library version outside the descriptor.
447
448 -s|-strict
449 Treat all compatibility warnings as problems. Add a number of \"Low\"
450 severity problems to the return value of the tool.
451
452 -headers-only
453 Check header files without $SLIB_TYPE libraries. It is easy to run, but may
454 provide a low quality compatibility report with false positives and
455 without detecting of added/removed symbols.
456
457 Alternatively you can write \"none\" word to the <libs> section
458 in the XML-descriptor:
459 <libs>
460 none
461 </libs>
462
463 -objects-only
464 Check $SLIB_TYPE libraries without header files. It is easy to run, but may
465 provide a low quality compatibility report with false positives and
466 without analysis of changes in parameters and data types.
467
468 Alternatively you can write \"none\" word to the <headers> section
469 in the XML-descriptor:
470 <headers>
471 none
472 </headers>
473
474 -check-impl|-check-implementation
475 Compare canonified disassembled binary code of $SLIB_TYPE libraries to
476 detect changes in the implementation. Add \'Problems with Implementation\'
477 section to the report.
478
479 -show-retval
480 Show the symbol's return type in the report.
481
Andrey Ponomarenko07aea072012-11-12 16:15:07 +0400482 -symbols-list PATH
Andrey Ponomarenkoab282102012-03-11 11:57:02 +0400483 This option allows to specify a file with a list of symbols (mangled
484 names in C++) that should be checked, other symbols will not be checked.
485
Andrey Ponomarenko07aea072012-11-12 16:15:07 +0400486 -skip-headers PATH
Andrey Ponomarenkoab282102012-03-11 11:57:02 +0400487 The file with the list of header files, that should not be checked.
488
489 -use-dumps
490 Make dumps for two versions of a library and compare dumps. This should
491 increase the performance of the tool and decrease the system memory usage.
492
493 -nostdinc
Andrey Ponomarenko570ece52012-11-30 16:36:44 +0400494 Do not search in GCC standard system directories for header files.
Andrey Ponomarenkoab282102012-03-11 11:57:02 +0400495
Andrey Ponomarenko07aea072012-11-12 16:15:07 +0400496 -dump-system NAME -sysroot DIR
497 Find all the shared libraries and header files in DIR directory,
Andrey Ponomarenkoab282102012-03-11 11:57:02 +0400498 create XML descriptors and make ABI dumps for each library. The result
499 set of ABI dumps can be compared (--cmp-systems) with the other one
500 created for other version of operating system in order to check them for
501 compatibility. Do not forget to specify -cross-gcc option if your target
502 system requires some specific version of GCC compiler (different from
503 the host GCC). The system ABI dump will be generated to:
Andrey Ponomarenko07aea072012-11-12 16:15:07 +0400504 sys_dumps/NAME/ARCH
Andrey Ponomarenkoab282102012-03-11 11:57:02 +0400505
Andrey Ponomarenko07aea072012-11-12 16:15:07 +0400506 -dump-system DESCRIPTOR.xml
Andrey Ponomarenkoab282102012-03-11 11:57:02 +0400507 The same as the previous option but takes an XML descriptor of the target
508 system as input, where you should describe it:
509
510 /* Primary sections */
511
512 <name>
513 /* Name of the system */
514 </name>
515
516 <headers>
517 /* The list of paths to header files and/or
518 directories with header files, one per line */
519 </headers>
520
521 <libs>
522 /* The list of paths to shared libraries and/or
523 directories with shared libraries, one per line */
524 </libs>
525
526 /* Optional sections */
527
528 <search_headers>
529 /* List of directories to be searched
530 for header files to automatically
531 generate include paths, one per line */
532 </search_headers>
533
534 <search_libs>
535 /* List of directories to be searched
536 for shared libraries to resolve
537 dependencies, one per line */
538 </search_libs>
539
540 <tools>
541 /* List of directories with tools used
542 for analysis (GCC toolchain), one per line */
543 </tools>
544
545 <cross_prefix>
546 /* GCC toolchain prefix.
547 Examples:
548 arm-linux-gnueabi
549 arm-none-symbianelf */
550 </cross_prefix>
551
552 <gcc_options>
553 /* Additional GCC options, one per line */
554 </gcc_options>
555
Andrey Ponomarenko07aea072012-11-12 16:15:07 +0400556 -sysinfo DIR
Andrey Ponomarenkoab282102012-03-11 11:57:02 +0400557 This option may be used with -dump-system to dump ABI of operating
558 systems and configure the dumping process.
559 Default:
560 modules/Targets/{unix, symbian, windows}
561
Andrey Ponomarenko07aea072012-11-12 16:15:07 +0400562 -cmp-systems -d1 sys_dumps/NAME1/ARCH -d2 sys_dumps/NAME2/ARCH
Andrey Ponomarenkoab282102012-03-11 11:57:02 +0400563 Compare two system ABI dumps. Create compatibility reports for each
564 library and the common HTML report including the summary of test
565 results for all checked libraries. Report will be generated to:
Andrey Ponomarenko07aea072012-11-12 16:15:07 +0400566 sys_compat_reports/NAME1_to_NAME2/ARCH
Andrey Ponomarenkoab282102012-03-11 11:57:02 +0400567
Andrey Ponomarenko07aea072012-11-12 16:15:07 +0400568 -libs-list PATH
Andrey Ponomarenkoab282102012-03-11 11:57:02 +0400569 The file with a list of libraries, that should be dumped by
570 the -dump-system option or should be checked by the -cmp-systems option.
571
Andrey Ponomarenko07aea072012-11-12 16:15:07 +0400572 -header NAME
Andrey Ponomarenkoab282102012-03-11 11:57:02 +0400573 Check/Dump ABI of this header only.
574
Andrey Ponomarenko07aea072012-11-12 16:15:07 +0400575 -headers-list PATH
Andrey Ponomarenkoab282102012-03-11 11:57:02 +0400576 The file with a list of headers, that should be checked/dumped.
577
578 -ext|-extended
579 If your library A is supposed to be used by other library B and you
580 want to control the ABI of B, then you should enable this option. The
581 tool will check for changes in all data types, even if they are not
582 used by any function in the library A. Such data types are not part
583 of the A library ABI, but may be a part of the ABI of the B library.
584
585 The short scheme is:
586 app C (broken) -> lib B (broken ABI) -> lib A (stable ABI)
587
588 -q|-quiet
589 Print all messages to the file instead of stdout and stderr.
590 Default path (can be changed by -log-path option):
591 $COMMON_LOG_PATH
592
593 -stdout
594 Print analysis results (compatibility reports and ABI dumps) to stdout
595 instead of creating a file. This would allow piping data to other programs.
596
Andrey Ponomarenko07aea072012-11-12 16:15:07 +0400597 -report-format FMT
Andrey Ponomarenkoab282102012-03-11 11:57:02 +0400598 Change format of compatibility report.
599 Formats:
600 htm - HTML format (default)
601 xml - XML format
602
Andrey Ponomarenko07aea072012-11-12 16:15:07 +0400603 -dump-format FMT
Andrey Ponomarenko5c09ef32012-06-14 18:17:33 +0400604 Change format of ABI dump.
605 Formats:
606 perl - Data::Dumper format (default)
607 xml - XML format
608
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +0400609 -xml
Andrey Ponomarenko5c09ef32012-06-14 18:17:33 +0400610 Alias for: --report-format=xml or --dump-format=xml
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +0400611
Andrey Ponomarenko07aea072012-11-12 16:15:07 +0400612 -lang LANG
Andrey Ponomarenkoab282102012-03-11 11:57:02 +0400613 Set library language (C or C++). You can use this option if the tool
614 cannot auto-detect a language. This option may be useful for checking
615 C-library headers (--lang=C) in --headers-only or --extended modes.
616
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +0400617 -binary|-bin|-abi
618 Show \"Binary\" compatibility problems only.
619 Generate report to:
Andrey Ponomarenko07aea072012-11-12 16:15:07 +0400620 compat_reports/LIB_NAME/V1_to_V2/abi_compat_report.html
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +0400621
622 -source|-src|-api
623 Show \"Source\" compatibility problems only.
624 Generate report to:
Andrey Ponomarenko07aea072012-11-12 16:15:07 +0400625 compat_reports/LIB_NAME/V1_to_V2/src_compat_report.html
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +0400626
Andrey Ponomarenkoab282102012-03-11 11:57:02 +0400627OTHER OPTIONS:
628 -test
629 Run internal tests. Create two binary incompatible versions of a sample
630 library and run the tool to check them for compatibility. This option
631 allows to check if the tool works correctly in the current environment.
632
633 -test-dump
634 Test ability to create, read and compare ABI dumps.
635
636 -debug
637 Debugging mode. Print debug info on the screen. Save intermediate
638 analysis stages in the debug directory:
Andrey Ponomarenko07aea072012-11-12 16:15:07 +0400639 debug/LIB_NAME/VERSION/
Andrey Ponomarenkoab282102012-03-11 11:57:02 +0400640
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +0400641 Also consider using --dump option for debugging the tool.
642
Andrey Ponomarenkoab282102012-03-11 11:57:02 +0400643 -cpp-compatible
Andrey Ponomarenko07aea072012-11-12 16:15:07 +0400644 If your header files are written in C language and can be compiled
645 by the G++ compiler (i.e. don't use C++ keywords), then you can tell
646 the tool about this and speedup the analysis.
Andrey Ponomarenkoab282102012-03-11 11:57:02 +0400647
Andrey Ponomarenko07aea072012-11-12 16:15:07 +0400648 -p|-params PATH
Andrey Ponomarenkoab282102012-03-11 11:57:02 +0400649 Path to file with the function parameter names. It can be used
650 for improving report view if the library header files have no
651 parameter names. File format:
652
653 func1;param1;param2;param3 ...
654 func2;param1;param2;param3 ...
655 ...
656
Andrey Ponomarenko07aea072012-11-12 16:15:07 +0400657 -relpath PATH
658 Replace {RELPATH} macros to PATH in the XML-descriptor used
Andrey Ponomarenkoab282102012-03-11 11:57:02 +0400659 for dumping the library ABI (see -dump option).
660
Andrey Ponomarenko07aea072012-11-12 16:15:07 +0400661 -relpath1 PATH
662 Replace {RELPATH} macros to PATH in the 1st XML-descriptor (-d1).
Andrey Ponomarenkoab282102012-03-11 11:57:02 +0400663
Andrey Ponomarenko07aea072012-11-12 16:15:07 +0400664 -relpath2 PATH
665 Replace {RELPATH} macros to PATH in the 2nd XML-descriptor (-d2).
Andrey Ponomarenkoab282102012-03-11 11:57:02 +0400666
Andrey Ponomarenko07aea072012-11-12 16:15:07 +0400667 -dump-path PATH
Andrey Ponomarenko5c09ef32012-06-14 18:17:33 +0400668 Specify a *.abi.$AR_EXT or *.abi file path where to generate an ABI dump.
Andrey Ponomarenkoab282102012-03-11 11:57:02 +0400669 Default:
Andrey Ponomarenko07aea072012-11-12 16:15:07 +0400670 abi_dumps/LIB_NAME/LIB_NAME_VERSION.abi.$AR_EXT
Andrey Ponomarenkoab282102012-03-11 11:57:02 +0400671
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +0400672 -sort
673 Enable sorting of data in ABI dumps.
674
Andrey Ponomarenko07aea072012-11-12 16:15:07 +0400675 -report-path PATH
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +0400676 Path to compatibility report.
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +0400677 Default:
Andrey Ponomarenko07aea072012-11-12 16:15:07 +0400678 compat_reports/LIB_NAME/V1_to_V2/compat_report.html
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +0400679
Andrey Ponomarenko07aea072012-11-12 16:15:07 +0400680 -bin-report-path PATH
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +0400681 Path to \"Binary\" compatibility report.
Andrey Ponomarenkoab282102012-03-11 11:57:02 +0400682 Default:
Andrey Ponomarenko07aea072012-11-12 16:15:07 +0400683 compat_reports/LIB_NAME/V1_to_V2/abi_compat_report.html
Andrey Ponomarenkoab282102012-03-11 11:57:02 +0400684
Andrey Ponomarenko07aea072012-11-12 16:15:07 +0400685 -src-report-path PATH
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +0400686 Path to \"Source\" compatibility report.
687 Default:
Andrey Ponomarenko07aea072012-11-12 16:15:07 +0400688 compat_reports/LIB_NAME/V1_to_V2/src_compat_report.html
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +0400689
Andrey Ponomarenko07aea072012-11-12 16:15:07 +0400690 -log-path PATH
Andrey Ponomarenkoab282102012-03-11 11:57:02 +0400691 Log path for all messages.
692 Default:
Andrey Ponomarenko07aea072012-11-12 16:15:07 +0400693 logs/LIB_NAME/VERSION/log.txt
Andrey Ponomarenkoab282102012-03-11 11:57:02 +0400694
Andrey Ponomarenko07aea072012-11-12 16:15:07 +0400695 -log1-path PATH
Andrey Ponomarenkoab282102012-03-11 11:57:02 +0400696 Log path for 1st version of a library.
697 Default:
Andrey Ponomarenko07aea072012-11-12 16:15:07 +0400698 logs/LIB_NAME/V1/log.txt
Andrey Ponomarenkoab282102012-03-11 11:57:02 +0400699
Andrey Ponomarenko07aea072012-11-12 16:15:07 +0400700 -log2-path PATH
Andrey Ponomarenkoab282102012-03-11 11:57:02 +0400701 Log path for 2nd version of a library.
702 Default:
Andrey Ponomarenko07aea072012-11-12 16:15:07 +0400703 logs/LIB_NAME/V2/log.txt
Andrey Ponomarenkoab282102012-03-11 11:57:02 +0400704
Andrey Ponomarenko07aea072012-11-12 16:15:07 +0400705 -logging-mode MODE
Andrey Ponomarenkoab282102012-03-11 11:57:02 +0400706 Change logging mode.
707 Modes:
708 w - overwrite old logs (default)
709 a - append old logs
710 n - do not write any logs
711
712 -list-affected
713 Generate file with the list of incompatible
714 symbols beside the HTML compatibility report.
715 Use 'c++filt \@file' command from GNU binutils
716 to unmangle C++ symbols in the generated file.
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +0400717 Default names:
Andrey Ponomarenkoab282102012-03-11 11:57:02 +0400718 abi_affected.txt
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +0400719 src_affected.txt
Andrey Ponomarenkoab282102012-03-11 11:57:02 +0400720
Andrey Ponomarenko07aea072012-11-12 16:15:07 +0400721 -component NAME
Andrey Ponomarenkoab282102012-03-11 11:57:02 +0400722 The component name in the title and summary of the HTML report.
723 Default:
724 library
725
Andrey Ponomarenko07aea072012-11-12 16:15:07 +0400726 -l-full|-lib-full NAME
727 Change library name in the report title to NAME. By default
Andrey Ponomarenkoab282102012-03-11 11:57:02 +0400728 will be displayed a name specified by -l option.
729
Andrey Ponomarenko07aea072012-11-12 16:15:07 +0400730 -b|-browse PROGRAM
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +0400731 Open report(s) in the browser (firefox, opera, etc.).
732
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +0400733 -open
734 Open report(s) in the default browser.
Andrey Ponomarenko07aea072012-11-12 16:15:07 +0400735
736 -extra-info DIR
737 Dump extra info to DIR.
Andrey Ponomarenko570ece52012-11-30 16:36:44 +0400738
739 -extra-dump
740 Create extended ABI dump containing all symbols
741 from the translation unit.
742
743 -force
744 Try to use this option if the tool doesn't work.
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +0400745
Andrey Ponomarenkoab282102012-03-11 11:57:02 +0400746REPORT:
747 Compatibility report will be generated to:
Andrey Ponomarenko07aea072012-11-12 16:15:07 +0400748 compat_reports/LIB_NAME/V1_to_V2/compat_report.html
Andrey Ponomarenkoab282102012-03-11 11:57:02 +0400749
750 Log will be generated to:
Andrey Ponomarenko07aea072012-11-12 16:15:07 +0400751 logs/LIB_NAME/V1/log.txt
752 logs/LIB_NAME/V2/log.txt
Andrey Ponomarenkoab282102012-03-11 11:57:02 +0400753
754EXIT CODES:
755 0 - Compatible. The tool has run without any errors.
756 non-zero - Incompatible or the tool has run with errors.
757
758REPORT BUGS TO:
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +0400759 Andrey Ponomarenko <aponomarenko\@rosalab.ru>
Andrey Ponomarenkoab282102012-03-11 11:57:02 +0400760
761MORE INFORMATION:
762 ".$HomePage{"Wiki"}."
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +0400763 ".$HomePage{"Dev1"}."\n");
Andrey Ponomarenkoab282102012-03-11 11:57:02 +0400764}
765
766my $DescriptorTemplate = "
767<?xml version=\"1.0\" encoding=\"utf-8\"?>
768<descriptor>
769
770/* Primary sections */
771
772<version>
773 /* Version of the library */
774</version>
775
776<headers>
777 /* The list of paths to header files and/or
778 directories with header files, one per line */
779</headers>
780
781<libs>
782 /* The list of paths to shared libraries (*.$LIB_EXT) and/or
783 directories with shared libraries, one per line */
784</libs>
785
786/* Optional sections */
787
788<include_paths>
789 /* The list of include paths that will be provided
790 to GCC to compile library headers, one per line.
791 NOTE: If you define this section then the tool
792 will not automatically generate include paths */
793</include_paths>
794
795<add_include_paths>
796 /* The list of include paths that will be added
797 to the automatically generated include paths, one per line */
798</add_include_paths>
799
800<skip_include_paths>
801 /* The list of include paths that will be removed from the
802 list of automatically generated include paths, one per line */
803</skip_include_paths>
804
805<gcc_options>
806 /* Additional GCC options, one per line */
807</gcc_options>
808
809<include_preamble>
810 /* The list of header files that will be
811 included before other headers, one per line.
812 Examples:
813 1) tree.h for libxml2
814 2) ft2build.h for freetype2 */
815</include_preamble>
816
817<defines>
818 /* The list of defines that will be added at the
819 headers compiling stage, one per line:
820 #define A B
821 #define C D */
822</defines>
823
Andrey Ponomarenkoa01311b2012-06-08 17:20:02 +0400824<add_namespaces>
825 /* The list of namespaces that should be added to the alanysis
826 if the tool cannot find them automatically, one per line */
827</add_namespaces>
828
Andrey Ponomarenkoab282102012-03-11 11:57:02 +0400829<skip_types>
830 /* The list of data types, that
831 should not be checked, one per line */
832</skip_types>
833
834<skip_symbols>
835 /* The list of functions (mangled/symbol names in C++),
836 that should not be checked, one per line */
837</skip_symbols>
838
839<skip_namespaces>
840 /* The list of C++ namespaces, that
841 should not be checked, one per line */
842</skip_namespaces>
843
844<skip_constants>
845 /* The list of constants that should
846 not be checked, one name per line */
847</skip_constants>
848
849<skip_headers>
850 /* The list of header files and/or directories
851 with header files that should not be checked, one per line */
852</skip_headers>
853
854<skip_libs>
855 /* The list of shared libraries and/or directories
856 with shared libraries that should not be checked, one per line */
857</skip_libs>
858
859<skip_including>
860 /* The list of header files, that cannot be included
861 directly (or non-self compiled ones), one per line */
862</skip_including>
863
864<search_headers>
865 /* List of directories to be searched
866 for header files to automatically
867 generate include paths, one per line. */
868</search_headers>
869
870<search_libs>
871 /* List of directories to be searched
872 for shared librariess to resolve
873 dependencies, one per line */
874</search_libs>
875
876<tools>
877 /* List of directories with tools used
878 for analysis (GCC toolchain), one per line */
879</tools>
880
881<cross_prefix>
882 /* GCC toolchain prefix.
883 Examples:
884 arm-linux-gnueabi
885 arm-none-symbianelf */
886</cross_prefix>
887
888</descriptor>";
889
890my %Operator_Indication = (
891 "not" => "~",
892 "assign" => "=",
893 "andassign" => "&=",
894 "orassign" => "|=",
895 "xorassign" => "^=",
896 "or" => "|",
897 "xor" => "^",
898 "addr" => "&",
899 "and" => "&",
900 "lnot" => "!",
901 "eq" => "==",
902 "ne" => "!=",
903 "lt" => "<",
904 "lshift" => "<<",
905 "lshiftassign" => "<<=",
906 "rshiftassign" => ">>=",
907 "call" => "()",
908 "mod" => "%",
909 "modassign" => "%=",
910 "subs" => "[]",
911 "land" => "&&",
912 "lor" => "||",
913 "rshift" => ">>",
914 "ref" => "->",
915 "le" => "<=",
916 "deref" => "*",
917 "mult" => "*",
918 "preinc" => "++",
919 "delete" => " delete",
920 "vecnew" => " new[]",
921 "vecdelete" => " delete[]",
922 "predec" => "--",
923 "postinc" => "++",
924 "postdec" => "--",
925 "plusassign" => "+=",
926 "plus" => "+",
927 "minus" => "-",
928 "minusassign" => "-=",
929 "gt" => ">",
930 "ge" => ">=",
931 "new" => " new",
932 "multassign" => "*=",
933 "divassign" => "/=",
934 "div" => "/",
935 "neg" => "-",
936 "pos" => "+",
937 "memref" => "->*",
938 "compound" => "," );
939
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +0400940my %UnknownOperator;
941
942my %NodeType= (
943 "array_type" => "Array",
944 "binfo" => "Other",
945 "boolean_type" => "Intrinsic",
946 "complex_type" => "Intrinsic",
947 "const_decl" => "Other",
948 "enumeral_type" => "Enum",
949 "field_decl" => "Other",
950 "function_decl" => "Other",
951 "function_type" => "FunctionType",
952 "identifier_node" => "Other",
953 "integer_cst" => "Other",
954 "integer_type" => "Intrinsic",
955 "method_type" => "MethodType",
956 "namespace_decl" => "Other",
957 "parm_decl" => "Other",
958 "pointer_type" => "Pointer",
959 "real_cst" => "Other",
960 "real_type" => "Intrinsic",
961 "record_type" => "Struct",
962 "reference_type" => "Ref",
963 "string_cst" => "Other",
964 "template_decl" => "Other",
965 "template_type_parm" => "Other",
966 "tree_list" => "Other",
967 "tree_vec" => "Other",
968 "type_decl" => "Other",
969 "union_type" => "Union",
970 "var_decl" => "Other",
971 "void_type" => "Intrinsic",
972 # "nop_expr" => "Other",
973 # "addr_expr" => "Other",
974 "offset_type" => "Other" );
975
Andrey Ponomarenkoab282102012-03-11 11:57:02 +0400976my %CppKeywords_C = map {$_=>1} (
977 # C++ 2003 keywords
978 "public",
979 "protected",
980 "private",
981 "default",
982 "template",
983 "new",
984 #"asm",
985 "dynamic_cast",
986 "auto",
987 "try",
988 "namespace",
989 "typename",
990 "using",
991 "reinterpret_cast",
992 "friend",
993 "class",
994 "virtual",
995 "const_cast",
996 "mutable",
997 "static_cast",
998 "export",
999 # C++0x keywords
1000 "noexcept",
1001 "nullptr",
1002 "constexpr",
1003 "static_assert",
1004 "explicit",
1005 # cannot be used as a macro name
1006 # as it is an operator in C++
1007 "and",
1008 #"and_eq",
1009 "not",
1010 #"not_eq",
1011 "or"
1012 #"or_eq",
1013 #"bitand",
1014 #"bitor",
1015 #"xor",
1016 #"xor_eq",
1017 #"compl"
1018);
1019
1020my %CppKeywords_F = map {$_=>1} (
1021 "delete",
1022 "catch",
1023 "alignof",
1024 "thread_local",
1025 "decltype",
1026 "typeid"
1027);
1028
1029my %CppKeywords_O = map {$_=>1} (
1030 "bool",
1031 "register",
1032 "inline",
1033 "operator"
1034);
1035
1036my %CppKeywords_A = map {$_=>1} (
1037 "this",
1038 "throw"
1039);
1040
1041foreach (keys(%CppKeywords_C),
1042keys(%CppKeywords_F),
1043keys(%CppKeywords_O)) {
1044 $CppKeywords_A{$_}=1;
1045}
1046
1047# Header file extensions as described by gcc
1048my $HEADER_EXT = "h|hh|hp|hxx|hpp|h\\+\\+";
1049
1050my %IntrinsicMangling = (
1051 "void" => "v",
1052 "bool" => "b",
1053 "wchar_t" => "w",
1054 "char" => "c",
1055 "signed char" => "a",
1056 "unsigned char" => "h",
1057 "short" => "s",
1058 "unsigned short" => "t",
1059 "int" => "i",
1060 "unsigned int" => "j",
1061 "long" => "l",
1062 "unsigned long" => "m",
1063 "long long" => "x",
1064 "__int64" => "x",
1065 "unsigned long long" => "y",
1066 "__int128" => "n",
1067 "unsigned __int128" => "o",
1068 "float" => "f",
1069 "double" => "d",
1070 "long double" => "e",
1071 "__float80" => "e",
1072 "__float128" => "g",
1073 "..." => "z"
1074);
1075
1076my %StdcxxMangling = (
1077 "3std"=>"St",
1078 "3std9allocator"=>"Sa",
1079 "3std12basic_string"=>"Sb",
1080 "3std12basic_stringIcE"=>"Ss",
1081 "3std13basic_istreamIcE"=>"Si",
1082 "3std13basic_ostreamIcE"=>"So",
1083 "3std14basic_iostreamIcE"=>"Sd"
1084);
1085
Andrey Ponomarenkoe3d6bf02012-11-14 11:49:09 +04001086my $DEFAULT_STD_PARMS = "std::(allocator|less|char_traits|regex_traits|istreambuf_iterator|ostreambuf_iterator)";
Andrey Ponomarenko07aea072012-11-12 16:15:07 +04001087
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04001088my %ConstantSuffix = (
1089 "unsigned int"=>"u",
1090 "long"=>"l",
1091 "unsigned long"=>"ul",
1092 "long long"=>"ll",
1093 "unsigned long long"=>"ull"
1094);
1095
1096my %ConstantSuffixR =
1097reverse(%ConstantSuffix);
1098
1099my %OperatorMangling = (
1100 "~" => "co",
1101 "=" => "aS",
1102 "|" => "or",
1103 "^" => "eo",
1104 "&" => "an",#ad (addr)
1105 "==" => "eq",
1106 "!" => "nt",
1107 "!=" => "ne",
1108 "<" => "lt",
1109 "<=" => "le",
1110 "<<" => "ls",
1111 "<<=" => "lS",
1112 ">" => "gt",
1113 ">=" => "ge",
1114 ">>" => "rs",
1115 ">>=" => "rS",
1116 "()" => "cl",
1117 "%" => "rm",
1118 "[]" => "ix",
1119 "&&" => "aa",
1120 "||" => "oo",
1121 "*" => "ml",#de (deref)
1122 "++" => "pp",#
1123 "--" => "mm",#
1124 "new" => "nw",
1125 "delete" => "dl",
1126 "new[]" => "na",
1127 "delete[]" => "da",
1128 "+=" => "pL",
1129 "+" => "pl",#ps (pos)
1130 "-" => "mi",#ng (neg)
1131 "-=" => "mI",
1132 "*=" => "mL",
1133 "/=" => "dV",
1134 "&=" => "aN",
1135 "|=" => "oR",
1136 "%=" => "rM",
1137 "^=" => "eO",
1138 "/" => "dv",
1139 "->*" => "pm",
1140 "->" => "pt",#rf (ref)
1141 "," => "cm",
1142 "?" => "qu",
1143 "." => "dt",
1144 "sizeof"=> "sz"#st
1145);
1146
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04001147my %Intrinsic_Keywords = map {$_=>1} (
1148 "true",
1149 "false",
1150 "_Bool",
1151 "_Complex",
1152 "const",
1153 "int",
1154 "long",
1155 "void",
1156 "short",
1157 "float",
1158 "volatile",
1159 "restrict",
1160 "unsigned",
1161 "signed",
1162 "char",
1163 "double",
1164 "class",
1165 "struct",
1166 "union",
1167 "enum"
1168);
1169
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04001170my %GlibcHeader = map {$_=>1} (
1171 "aliases.h",
1172 "argp.h",
1173 "argz.h",
1174 "assert.h",
1175 "cpio.h",
1176 "ctype.h",
1177 "dirent.h",
1178 "envz.h",
1179 "errno.h",
1180 "error.h",
1181 "execinfo.h",
1182 "fcntl.h",
1183 "fstab.h",
1184 "ftw.h",
1185 "glob.h",
1186 "grp.h",
1187 "iconv.h",
1188 "ifaddrs.h",
1189 "inttypes.h",
1190 "langinfo.h",
1191 "limits.h",
1192 "link.h",
1193 "locale.h",
1194 "malloc.h",
1195 "math.h",
1196 "mntent.h",
1197 "monetary.h",
1198 "nl_types.h",
1199 "obstack.h",
1200 "printf.h",
1201 "pwd.h",
1202 "regex.h",
1203 "sched.h",
1204 "search.h",
1205 "setjmp.h",
1206 "shadow.h",
1207 "signal.h",
1208 "spawn.h",
1209 "stdarg.h",
1210 "stdint.h",
1211 "stdio.h",
1212 "stdlib.h",
1213 "string.h",
Andrey Ponomarenko9927e332012-10-19 10:50:48 +04001214 "strings.h",
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04001215 "tar.h",
1216 "termios.h",
1217 "time.h",
1218 "ulimit.h",
1219 "unistd.h",
1220 "utime.h",
1221 "wchar.h",
1222 "wctype.h",
1223 "wordexp.h" );
1224
1225my %GlibcDir = map {$_=>1} (
1226 "arpa",
1227 "bits",
1228 "gnu",
1229 "netinet",
1230 "net",
1231 "nfs",
1232 "rpc",
1233 "sys",
1234 "linux" );
1235
Andrey Ponomarenko9927e332012-10-19 10:50:48 +04001236my %WinHeaders = map {$_=>1} (
1237 "dos.h",
1238 "process.h",
1239 "winsock.h",
1240 "config-win.h",
1241 "mem.h",
1242 "windows.h",
1243 "winsock2.h",
1244 "crtdbg.h",
1245 "ws2tcpip.h"
1246);
1247
1248my %ObsoleteHeaders = map {$_=>1} (
1249 "iostream.h",
1250 "fstream.h"
1251);
1252
1253my %ConfHeaders = map {$_=>1} (
1254 "atomic",
1255 "conf.h",
1256 "config.h",
1257 "configure.h",
1258 "build.h",
1259 "setup.h"
1260);
1261
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04001262my %LocalIncludes = map {$_=>1} (
1263 "/usr/local/include",
1264 "/usr/local" );
1265
1266my %OS_AddPath=(
1267# These paths are needed if the tool cannot detect them automatically
1268 "macos"=>{
Andrey Ponomarenko570ece52012-11-30 16:36:44 +04001269 "include"=>[
1270 "/Library",
1271 "/Developer/usr/include"
1272 ],
1273 "lib"=>[
1274 "/Library",
1275 "/Developer/usr/lib"
1276 ],
1277 "bin"=>[
1278 "/Developer/usr/bin"
1279 ]
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04001280 },
1281 "beos"=>{
1282 # Haiku has GCC 2.95.3 by default
1283 # try to find GCC>=3.0 in /boot/develop/abi
Andrey Ponomarenko570ece52012-11-30 16:36:44 +04001284 "include"=>[
1285 "/boot/common",
1286 "/boot/develop"
1287 ],
1288 "lib"=>[
1289 "/boot/common/lib",
1290 "/boot/system/lib",
1291 "/boot/apps"
1292 ],
1293 "bin"=>[
1294 "/boot/common/bin",
1295 "/boot/system/bin",
1296 "/boot/develop/abi"
1297 ]
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04001298 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04001299);
1300
1301my %Slash_Type=(
1302 "default"=>"/",
1303 "windows"=>"\\"
1304);
1305
1306my $SLASH = $Slash_Type{$OSgroup}?$Slash_Type{$OSgroup}:$Slash_Type{"default"};
1307
1308# Global Variables
1309my %COMMON_LANGUAGE=(
1310 1 => "C",
1311 2 => "C" );
1312
1313my $MAX_COMMAND_LINE_ARGUMENTS = 4096;
Andrey Ponomarenko9927e332012-10-19 10:50:48 +04001314my $MAX_CPPFILT_FILE_SIZE = 50000;
1315my $CPPFILT_SUPPORT_FILE;
1316
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04001317my (%WORD_SIZE, %CPU_ARCH, %GCC_VERSION);
1318
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04001319my $STDCXX_TESTING = 0;
1320my $GLIBC_TESTING = 0;
1321
1322my $CheckHeadersOnly = $CheckHeadersOnly_Opt;
1323my $CheckObjectsOnly = $CheckObjectsOnly_Opt;
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04001324my $TargetComponent;
1325
Andrey Ponomarenko570ece52012-11-30 16:36:44 +04001326my $CheckUndefined = 0;
1327
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04001328# Set Target Component Name
1329if($TargetComponent_Opt) {
1330 $TargetComponent = lc($TargetComponent_Opt);
1331}
1332else
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04001333{ # default: library
1334 # other components: header, system, ...
1335 $TargetComponent = "library";
1336}
1337
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04001338my $TOP_REF = "<a style='font-size:11px;' href='#Top'>to the top</a>";
1339
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04001340my $SystemRoot;
1341
1342my $MAIN_CPP_DIR;
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04001343my %RESULT;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04001344my %LOG_PATH;
1345my %DEBUG_PATH;
1346my %Cache;
1347my %LibInfo;
1348my $COMPILE_ERRORS = 0;
1349my %CompilerOptions;
1350my %CheckedDyLib;
1351my $TargetLibraryShortName = parse_libname($TargetLibraryName, "shortest", $OSgroup);
1352
1353# Constants (#defines)
1354my %Constants;
1355my %SkipConstants;
Andrey Ponomarenko82bc2572012-11-14 13:55:30 +04001356my %EnumConstants;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04001357
1358# Types
1359my %TypeInfo;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04001360my %TemplateInstance;
Andrey Ponomarenko85043792012-05-14 16:48:07 +04001361my %TemplateDecl;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04001362my %SkipTypes = (
1363 "1"=>{},
1364 "2"=>{} );
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04001365my %CheckedTypes;
1366my %TName_Tid;
1367my %EnumMembName_Id;
1368my %NestedNameSpaces = (
1369 "1"=>{},
1370 "2"=>{} );
1371my %UsedType;
1372my %VirtualTable;
Andrey Ponomarenko16934472012-03-29 15:37:04 +04001373my %VirtualTable_Model;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04001374my %ClassVTable;
1375my %ClassVTable_Content;
1376my %VTableClass;
1377my %AllocableClass;
1378my %ClassMethods;
Andrey Ponomarenko16934472012-03-29 15:37:04 +04001379my %ClassNames;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04001380my %Class_SubClasses;
1381my %OverriddenMethods;
Andrey Ponomarenko4b077f82012-12-04 16:04:36 +04001382my %TypedefToAnon;
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04001383my $MAX_ID = 0;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04001384
1385# Typedefs
1386my %Typedef_BaseName;
1387my %Typedef_Tr;
1388my %Typedef_Eq;
1389my %StdCxxTypedef;
1390my %MissedTypedef;
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04001391my %MissedBase;
1392my %MissedBase_R;
Andrey Ponomarenko9927e332012-10-19 10:50:48 +04001393my %TypeTypedef;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04001394
1395# Symbols
1396my %SymbolInfo;
1397my %tr_name;
1398my %mangled_name_gcc;
1399my %mangled_name;
1400my %SkipSymbols = (
1401 "1"=>{},
1402 "2"=>{} );
1403my %SkipNameSpaces = (
1404 "1"=>{},
1405 "2"=>{} );
Andrey Ponomarenkoa01311b2012-06-08 17:20:02 +04001406my %AddNameSpaces = (
1407 "1"=>{},
1408 "2"=>{} );
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04001409my %SymbolsList;
1410my %SymbolsList_App;
1411my %CheckedSymbols;
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04001412my %Symbol_Library = (
1413 "1"=>{},
1414 "2"=>{} );
1415my %Library_Symbol = (
1416 "1"=>{},
1417 "2"=>{} );
1418my %DepSymbol_Library = (
1419 "1"=>{},
1420 "2"=>{} );
1421my %DepLibrary_Symbol = (
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04001422 "1"=>{},
1423 "2"=>{} );
1424my %MangledNames;
Andrey Ponomarenko9927e332012-10-19 10:50:48 +04001425my %Func_ShortName;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04001426my %AddIntParams;
1427my %Interface_Impl;
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04001428my %GlobalDataObject;
Andrey Ponomarenko07aea072012-11-12 16:15:07 +04001429my %WeakSymbols;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04001430
Andrey Ponomarenko570ece52012-11-30 16:36:44 +04001431# Extra Info
1432my %UndefinedSymbols;
1433
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04001434# Headers
Andrey Ponomarenko570ece52012-11-30 16:36:44 +04001435my %Include_Preamble = (
1436 "1"=>[],
1437 "2"=>[] );
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04001438my %Registered_Headers;
1439my %HeaderName_Paths;
1440my %Header_Dependency;
1441my %Include_Neighbors;
Andrey Ponomarenko570ece52012-11-30 16:36:44 +04001442my %Include_Paths = (
1443 "1"=>[],
1444 "2"=>[] );
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04001445my %INC_PATH_AUTODETECT = (
1446 "1"=>1,
1447 "2"=>1 );
Andrey Ponomarenko570ece52012-11-30 16:36:44 +04001448my %Add_Include_Paths = (
1449 "1"=>[],
1450 "2"=>[] );
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04001451my %Skip_Include_Paths;
1452my %RegisteredDirs;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04001453my %Header_ErrorRedirect;
1454my %Header_Includes;
1455my %Header_ShouldNotBeUsed;
1456my %RecursiveIncludes;
1457my %Header_Include_Prefix;
1458my %SkipHeaders;
1459my %SkipHeadersList=(
1460 "1"=>{},
1461 "2"=>{} );
1462my %SkipLibs;
1463my %Include_Order;
1464my %TUnit_NameSpaces;
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +04001465my %TUnit_Classes;
Andrey Ponomarenko9927e332012-10-19 10:50:48 +04001466my %TUnit_Funcs;
1467my %TUnit_Vars;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04001468
Andrey Ponomarenko07aea072012-11-12 16:15:07 +04001469my %CppMode = (
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04001470 "1"=>0,
1471 "2"=>0 );
1472my %AutoPreambleMode = (
1473 "1"=>0,
1474 "2"=>0 );
1475my %MinGWMode = (
1476 "1"=>0,
1477 "2"=>0 );
Andrey Ponomarenko01117f12012-06-26 12:23:02 +04001478my %Cpp0xMode = (
1479 "1"=>0,
1480 "2"=>0 );
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04001481
1482# Shared Objects
Andrey Ponomarenko9927e332012-10-19 10:50:48 +04001483my %RegisteredObjects;
Andrey Ponomarenko07aea072012-11-12 16:15:07 +04001484my %RegisteredObjects_Short;
Andrey Ponomarenko9927e332012-10-19 10:50:48 +04001485my %RegisteredSONAMEs;
1486my %RegisteredObject_Dirs;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04001487
1488# System Objects
1489my %SystemObjects;
Andrey Ponomarenko570ece52012-11-30 16:36:44 +04001490my @DefaultLibPaths;
Andrey Ponomarenko9927e332012-10-19 10:50:48 +04001491my %DyLib_DefaultPath;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04001492
1493# System Headers
1494my %SystemHeaders;
Andrey Ponomarenko570ece52012-11-30 16:36:44 +04001495my @DefaultCppPaths;
1496my @DefaultGccPaths;
1497my @DefaultIncPaths;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04001498my %DefaultCppHeader;
1499my %DefaultGccHeader;
Andrey Ponomarenko570ece52012-11-30 16:36:44 +04001500my @UsersIncPath;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04001501
1502# Merging
1503my %CompleteSignature;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04001504my $Version;
1505my %AddedInt;
1506my %RemovedInt;
1507my %AddedInt_Virt;
1508my %RemovedInt_Virt;
1509my %VirtualReplacement;
1510my %ChangedTypedef;
1511my %CompatRules;
1512my %IncompleteRules;
1513my %UnknownRules;
Andrey Ponomarenko16934472012-03-29 15:37:04 +04001514my %VTableChanged_M;
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04001515my %ExtendedSymbols;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04001516my %ReturnedClass;
1517my %ParamClass;
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04001518my %SourceAlternative;
1519my %SourceAlternative_B;
1520my %SourceReplacement;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04001521
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +04001522# Calling Conventions
1523my %UseConv_Real = (
1524 "1"=>0,
1525 "2"=>0 );
1526
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04001527# OS Compliance
1528my %TargetLibs;
1529my %TargetHeaders;
1530
1531# OS Specifics
1532my $OStarget = $OSgroup;
1533my %TargetTools;
1534
1535# Compliance Report
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04001536my %Type_MaxSeverity;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04001537
1538# Recursion locks
1539my @RecurLib;
1540my @RecurSymlink;
1541my @RecurTypes;
1542my @RecurInclude;
1543my @RecurConstant;
1544
1545# System
Andrey Ponomarenko570ece52012-11-30 16:36:44 +04001546my %SystemPaths = (
1547 "include"=>[],
1548 "lib"=>[],
1549 "bin"=>[]
1550);
1551my @DefaultBinPaths;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04001552my $GCC_PATH;
1553
1554# Symbols versioning
1555my %SymVer = (
1556 "1"=>{},
1557 "2"=>{} );
1558
1559# Problem descriptions
1560my %CompatProblems;
1561my %ProblemsWithConstants;
1562my %ImplProblems;
1563my %TotalAffected;
1564
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04001565# Reports
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04001566my $ContentID = 1;
1567my $ContentSpanStart = "<span class=\"section\" onclick=\"javascript:showContent(this, 'CONTENT_ID')\">\n";
1568my $ContentSpanStart_Affected = "<span class=\"section_affected\" onclick=\"javascript:showContent(this, 'CONTENT_ID')\">\n";
1569my $ContentSpanStart_Info = "<span class=\"section_info\" onclick=\"javascript:showContent(this, 'CONTENT_ID')\">\n";
1570my $ContentSpanEnd = "</span>\n";
1571my $ContentDivStart = "<div id=\"CONTENT_ID\" style=\"display:none;\">\n";
1572my $ContentDivEnd = "</div>\n";
1573my $Content_Counter = 0;
1574
Andrey Ponomarenko5c09ef32012-06-14 18:17:33 +04001575# XML Dump
1576my $TAG_ID = 0;
1577my $INDENT = " ";
1578
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04001579# Modes
1580my $JoinReport = 1;
1581my $DoubleReport = 0;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04001582
1583sub get_Modules()
1584{
1585 my $TOOL_DIR = get_dirname($0);
1586 if(not $TOOL_DIR)
1587 { # patch for MS Windows
1588 $TOOL_DIR = ".";
1589 }
1590 my @SEARCH_DIRS = (
1591 # tool's directory
1592 abs_path($TOOL_DIR),
1593 # relative path to modules
1594 abs_path($TOOL_DIR)."/../share/abi-compliance-checker",
1595 # system directory
1596 "ACC_MODULES_INSTALL_PATH"
1597 );
1598 foreach my $DIR (@SEARCH_DIRS)
1599 {
1600 if(not is_abs($DIR))
1601 { # relative path
1602 $DIR = abs_path($TOOL_DIR)."/".$DIR;
1603 }
1604 if(-d $DIR."/modules") {
1605 return $DIR."/modules";
1606 }
1607 }
1608 exitStatus("Module_Error", "can't find modules");
1609}
1610
Andrey Ponomarenko01117f12012-06-26 12:23:02 +04001611my %LoadedModules = ();
1612
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04001613sub loadModule($)
1614{
1615 my $Name = $_[0];
Andrey Ponomarenko01117f12012-06-26 12:23:02 +04001616 if(defined $LoadedModules{$Name}) {
1617 return;
1618 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04001619 my $Path = $MODULES_DIR."/Internals/$Name.pm";
1620 if(not -f $Path) {
1621 exitStatus("Module_Error", "can't access \'$Path\'");
1622 }
1623 require $Path;
Andrey Ponomarenko01117f12012-06-26 12:23:02 +04001624 $LoadedModules{$Name} = 1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04001625}
1626
Andrey Ponomarenko570ece52012-11-30 16:36:44 +04001627sub readModule($$)
1628{
1629 my ($Module, $Name) = @_;
1630 my $Path = $MODULES_DIR."/Internals/$Module/".$Name;
1631 if(not -f $Path) {
1632 exitStatus("Module_Error", "can't access \'$Path\'");
1633 }
1634 return readFile($Path);
1635}
1636
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04001637sub showPos($)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04001638{
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04001639 my $Number = $_[0];
1640 if(not $Number) {
1641 $Number = 1;
1642 }
1643 else {
1644 $Number = int($Number)+1;
1645 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04001646 if($Number>3) {
1647 return $Number."th";
1648 }
1649 elsif($Number==1) {
1650 return "1st";
1651 }
1652 elsif($Number==2) {
1653 return "2nd";
1654 }
1655 elsif($Number==3) {
1656 return "3rd";
1657 }
1658 else {
1659 return $Number;
1660 }
1661}
1662
1663sub search_Tools($)
1664{
1665 my $Name = $_[0];
1666 return "" if(not $Name);
1667 if(my @Paths = keys(%TargetTools))
1668 {
1669 foreach my $Path (@Paths)
1670 {
1671 if(-f joinPath($Path, $Name)) {
1672 return joinPath($Path, $Name);
1673 }
1674 if($CrossPrefix)
1675 { # user-defined prefix (arm-none-symbianelf, ...)
1676 my $Candidate = joinPath($Path, $CrossPrefix."-".$Name);
1677 if(-f $Candidate) {
1678 return $Candidate;
1679 }
1680 }
1681 }
1682 }
1683 else {
1684 return "";
1685 }
1686}
1687
1688sub synch_Cmd($)
1689{
1690 my $Name = $_[0];
1691 if(not $GCC_PATH)
1692 { # GCC was not found yet
1693 return "";
1694 }
1695 my $Candidate = $GCC_PATH;
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04001696 if($Candidate=~s/\bgcc(|\.\w+)\Z/$Name$1/) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04001697 return $Candidate;
1698 }
1699 return "";
1700}
1701
1702sub get_CmdPath($)
1703{
1704 my $Name = $_[0];
1705 return "" if(not $Name);
1706 if(defined $Cache{"get_CmdPath"}{$Name}) {
1707 return $Cache{"get_CmdPath"}{$Name};
1708 }
1709 my %BinUtils = map {$_=>1} (
1710 "c++filt",
1711 "objdump",
1712 "readelf"
1713 );
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04001714 if($BinUtils{$Name} and $GCC_PATH)
1715 {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04001716 if(my $Dir = get_dirname($GCC_PATH)) {
1717 $TargetTools{$Dir}=1;
1718 }
1719 }
1720 my $Path = search_Tools($Name);
1721 if(not $Path and $OSgroup eq "windows") {
1722 $Path = search_Tools($Name.".exe");
1723 }
1724 if(not $Path and $BinUtils{$Name})
1725 {
1726 if($CrossPrefix)
1727 { # user-defined prefix
1728 $Path = search_Cmd($CrossPrefix."-".$Name);
1729 }
1730 }
1731 if(not $Path and $BinUtils{$Name})
1732 {
1733 if(my $Candidate = synch_Cmd($Name))
1734 { # synch with GCC
1735 if($Candidate=~/[\/\\]/)
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04001736 { # command path
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04001737 if(-f $Candidate) {
1738 $Path = $Candidate;
1739 }
1740 }
1741 elsif($Candidate = search_Cmd($Candidate))
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04001742 { # command name
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04001743 $Path = $Candidate;
1744 }
1745 }
1746 }
1747 if(not $Path) {
1748 $Path = search_Cmd($Name);
1749 }
1750 if(not $Path and $OSgroup eq "windows")
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04001751 { # search for *.exe file
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04001752 $Path=search_Cmd($Name.".exe");
1753 }
1754 if($Path=~/\s/) {
1755 $Path = "\"".$Path."\"";
1756 }
1757 return ($Cache{"get_CmdPath"}{$Name}=$Path);
1758}
1759
1760sub search_Cmd($)
1761{
1762 my $Name = $_[0];
1763 return "" if(not $Name);
1764 if(defined $Cache{"search_Cmd"}{$Name}) {
1765 return $Cache{"search_Cmd"}{$Name};
1766 }
1767 if(my $DefaultPath = get_CmdPath_Default($Name)) {
1768 return ($Cache{"search_Cmd"}{$Name} = $DefaultPath);
1769 }
Andrey Ponomarenko570ece52012-11-30 16:36:44 +04001770 foreach my $Path (@{$SystemPaths{"bin"}})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04001771 {
1772 my $CmdPath = joinPath($Path,$Name);
1773 if(-f $CmdPath)
1774 {
1775 if($Name=~/gcc/) {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04001776 next if(not check_gcc($CmdPath, "3"));
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04001777 }
1778 return ($Cache{"search_Cmd"}{$Name} = $CmdPath);
1779 }
1780 }
1781 return ($Cache{"search_Cmd"}{$Name} = "");
1782}
1783
1784sub get_CmdPath_Default($)
1785{ # search in PATH
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04001786 return "" if(not $_[0]);
1787 if(defined $Cache{"get_CmdPath_Default"}{$_[0]}) {
1788 return $Cache{"get_CmdPath_Default"}{$_[0]};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04001789 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04001790 return ($Cache{"get_CmdPath_Default"}{$_[0]} = get_CmdPath_Default_I($_[0]));
1791}
1792
1793sub get_CmdPath_Default_I($)
1794{ # search in PATH
1795 my $Name = $_[0];
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04001796 if($Name=~/find/)
1797 { # special case: search for "find" utility
Andrey Ponomarenkoa01311b2012-06-08 17:20:02 +04001798 if(`find \"$TMP_DIR\" -maxdepth 0 2>\"$TMP_DIR/null\"`) {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04001799 return "find";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04001800 }
1801 }
1802 elsif($Name=~/gcc/) {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04001803 return check_gcc($Name, "3");
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04001804 }
Andrey Ponomarenko570ece52012-11-30 16:36:44 +04001805 if(checkCmd($Name)) {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04001806 return $Name;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04001807 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04001808 if($OSgroup eq "windows")
1809 {
Andrey Ponomarenkoa01311b2012-06-08 17:20:02 +04001810 if(`$Name /? 2>\"$TMP_DIR/null\"`) {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04001811 return $Name;
1812 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04001813 }
Andrey Ponomarenko570ece52012-11-30 16:36:44 +04001814 foreach my $Path (@DefaultBinPaths)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04001815 {
1816 if(-f $Path."/".$Name) {
Andrey Ponomarenko570ece52012-11-30 16:36:44 +04001817 return joinPath($Path, $Name);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04001818 }
1819 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04001820 return "";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04001821}
1822
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04001823sub classifyPath($)
1824{
1825 my $Path = $_[0];
1826 if($Path=~/[\*\[]/)
1827 { # wildcard
1828 $Path=~s/\*/.*/g;
1829 $Path=~s/\\/\\\\/g;
1830 return ($Path, "Pattern");
1831 }
1832 elsif($Path=~/[\/\\]/)
1833 { # directory or relative path
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04001834 $Path=~s/[\/\\]+\Z//g;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04001835 return (path_format($Path, $OSgroup), "Path");
1836 }
1837 else {
1838 return ($Path, "Name");
1839 }
1840}
1841
1842sub readDescriptor($$)
1843{
1844 my ($LibVersion, $Content) = @_;
1845 return if(not $LibVersion);
1846 my $DName = $DumpAPI?"descriptor":"descriptor \"d$LibVersion\"";
1847 if(not $Content) {
1848 exitStatus("Error", "$DName is empty");
1849 }
1850 if($Content!~/\</) {
Andrey Ponomarenko5c09ef32012-06-14 18:17:33 +04001851 exitStatus("Error", "incorrect descriptor (see -d1 option)");
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04001852 }
1853 $Content=~s/\/\*(.|\n)+?\*\///g;
1854 $Content=~s/<\!--(.|\n)+?-->//g;
Andrey Ponomarenko570ece52012-11-30 16:36:44 +04001855
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04001856 $Descriptor{$LibVersion}{"Version"} = parseTag(\$Content, "version");
1857 if($TargetVersion{$LibVersion}) {
1858 $Descriptor{$LibVersion}{"Version"} = $TargetVersion{$LibVersion};
1859 }
1860 if(not $Descriptor{$LibVersion}{"Version"}) {
1861 exitStatus("Error", "version in the $DName is not specified (<version> section)");
1862 }
1863 if($Content=~/{RELPATH}/)
1864 {
1865 if(my $RelDir = $RelativeDirectory{$LibVersion}) {
1866 $Content =~ s/{RELPATH}/$RelDir/g;
1867 }
1868 else
1869 {
1870 my $NeedRelpath = $DumpAPI?"-relpath":"-relpath$LibVersion";
1871 exitStatus("Error", "you have not specified $NeedRelpath option, but the $DName contains {RELPATH} macro");
1872 }
1873 }
1874
1875 if(not $CheckObjectsOnly_Opt)
1876 {
1877 my $DHeaders = parseTag(\$Content, "headers");
1878 if(not $DHeaders) {
1879 exitStatus("Error", "header files in the $DName are not specified (<headers> section)");
1880 }
1881 elsif(lc($DHeaders) ne "none")
1882 { # append the descriptor headers list
1883 if($Descriptor{$LibVersion}{"Headers"})
1884 { # multiple descriptors
1885 $Descriptor{$LibVersion}{"Headers"} .= "\n".$DHeaders;
1886 }
1887 else {
1888 $Descriptor{$LibVersion}{"Headers"} = $DHeaders;
1889 }
1890 foreach my $Path (split(/\s*\n\s*/, $DHeaders))
1891 {
1892 if(not -e $Path) {
1893 exitStatus("Access_Error", "can't access \'$Path\'");
1894 }
1895 }
1896 }
1897 }
1898 if(not $CheckHeadersOnly_Opt)
1899 {
1900 my $DObjects = parseTag(\$Content, "libs");
1901 if(not $DObjects) {
1902 exitStatus("Error", "$SLIB_TYPE libraries in the $DName are not specified (<libs> section)");
1903 }
1904 elsif(lc($DObjects) ne "none")
1905 { # append the descriptor libraries list
1906 if($Descriptor{$LibVersion}{"Libs"})
1907 { # multiple descriptors
1908 $Descriptor{$LibVersion}{"Libs"} .= "\n".$DObjects;
1909 }
1910 else {
1911 $Descriptor{$LibVersion}{"Libs"} .= $DObjects;
1912 }
1913 foreach my $Path (split(/\s*\n\s*/, $DObjects))
1914 {
1915 if(not -e $Path) {
1916 exitStatus("Access_Error", "can't access \'$Path\'");
1917 }
1918 }
1919 }
1920 }
1921 foreach my $Path (split(/\s*\n\s*/, parseTag(\$Content, "search_headers")))
1922 {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04001923 if(not -d $Path) {
1924 exitStatus("Access_Error", "can't access directory \'$Path\'");
1925 }
1926 $Path = path_format($Path, $OSgroup);
Andrey Ponomarenko570ece52012-11-30 16:36:44 +04001927 push_U($SystemPaths{"include"}, $Path);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04001928 }
1929 foreach my $Path (split(/\s*\n\s*/, parseTag(\$Content, "search_libs")))
1930 {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04001931 if(not -d $Path) {
1932 exitStatus("Access_Error", "can't access directory \'$Path\'");
1933 }
1934 $Path = path_format($Path, $OSgroup);
Andrey Ponomarenko570ece52012-11-30 16:36:44 +04001935 push_U($SystemPaths{"lib"}, $Path);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04001936 }
1937 foreach my $Path (split(/\s*\n\s*/, parseTag(\$Content, "tools")))
1938 {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04001939 if(not -d $Path) {
1940 exitStatus("Access_Error", "can't access directory \'$Path\'");
1941 }
1942 $Path = path_format($Path, $OSgroup);
Andrey Ponomarenko570ece52012-11-30 16:36:44 +04001943 push_U($SystemPaths{"bin"}, $Path);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04001944 $TargetTools{$Path}=1;
1945 }
1946 if(my $Prefix = parseTag(\$Content, "cross_prefix")) {
1947 $CrossPrefix = $Prefix;
1948 }
Andrey Ponomarenko570ece52012-11-30 16:36:44 +04001949 $Descriptor{$LibVersion}{"IncludePaths"} = [] if(not defined $Descriptor{$LibVersion}{"IncludePaths"}); # perl 5.8 doesn't support //=
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04001950 foreach my $Path (split(/\s*\n\s*/, parseTag(\$Content, "include_paths")))
1951 {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04001952 if(not -d $Path) {
1953 exitStatus("Access_Error", "can't access directory \'$Path\'");
1954 }
1955 $Path = path_format($Path, $OSgroup);
Andrey Ponomarenko570ece52012-11-30 16:36:44 +04001956 push(@{$Descriptor{$LibVersion}{"IncludePaths"}}, $Path);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04001957 }
Andrey Ponomarenko570ece52012-11-30 16:36:44 +04001958 $Descriptor{$LibVersion}{"AddIncludePaths"} = [] if(not defined $Descriptor{$LibVersion}{"AddIncludePaths"});
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04001959 foreach my $Path (split(/\s*\n\s*/, parseTag(\$Content, "add_include_paths")))
1960 {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04001961 if(not -d $Path) {
1962 exitStatus("Access_Error", "can't access directory \'$Path\'");
1963 }
1964 $Path = path_format($Path, $OSgroup);
Andrey Ponomarenko570ece52012-11-30 16:36:44 +04001965 push(@{$Descriptor{$LibVersion}{"AddIncludePaths"}}, $Path);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04001966 }
1967 foreach my $Path (split(/\s*\n\s*/, parseTag(\$Content, "skip_include_paths")))
1968 {
1969 # skip some auto-generated include paths
Andrey Ponomarenko570ece52012-11-30 16:36:44 +04001970 $Skip_Include_Paths{$LibVersion}{path_format($Path)} = 1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04001971 }
1972 foreach my $Path (split(/\s*\n\s*/, parseTag(\$Content, "skip_including")))
1973 {
1974 # skip direct including of some headers
1975 my ($CPath, $Type) = classifyPath($Path);
1976 $SkipHeaders{$LibVersion}{$Type}{$CPath} = 2;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04001977 }
1978 $Descriptor{$LibVersion}{"GccOptions"} = parseTag(\$Content, "gcc_options");
1979 foreach my $Option (split(/\s*\n\s*/, $Descriptor{$LibVersion}{"GccOptions"})) {
1980 $CompilerOptions{$LibVersion} .= " ".$Option;
1981 }
1982 $Descriptor{$LibVersion}{"SkipHeaders"} = parseTag(\$Content, "skip_headers");
1983 foreach my $Path (split(/\s*\n\s*/, $Descriptor{$LibVersion}{"SkipHeaders"}))
1984 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04001985 $SkipHeadersList{$LibVersion}{$Path} = 1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04001986 my ($CPath, $Type) = classifyPath($Path);
1987 $SkipHeaders{$LibVersion}{$Type}{$CPath} = 1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04001988 }
1989 $Descriptor{$LibVersion}{"SkipLibs"} = parseTag(\$Content, "skip_libs");
1990 foreach my $Path (split(/\s*\n\s*/, $Descriptor{$LibVersion}{"SkipLibs"}))
1991 {
1992 my ($CPath, $Type) = classifyPath($Path);
1993 $SkipLibs{$LibVersion}{$Type}{$CPath} = 1;
1994 }
1995 if(my $DDefines = parseTag(\$Content, "defines"))
1996 {
1997 if($Descriptor{$LibVersion}{"Defines"})
1998 { # multiple descriptors
1999 $Descriptor{$LibVersion}{"Defines"} .= "\n".$DDefines;
2000 }
2001 else {
2002 $Descriptor{$LibVersion}{"Defines"} = $DDefines;
2003 }
2004 }
2005 foreach my $Order (split(/\s*\n\s*/, parseTag(\$Content, "include_order")))
2006 {
2007 if($Order=~/\A(.+):(.+)\Z/) {
2008 $Include_Order{$LibVersion}{$1} = $2;
2009 }
2010 }
2011 foreach my $Type_Name (split(/\s*\n\s*/, parseTag(\$Content, "opaque_types")),
2012 split(/\s*\n\s*/, parseTag(\$Content, "skip_types")))
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04002013 { # opaque_types renamed to skip_types (1.23.4)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002014 $SkipTypes{$LibVersion}{$Type_Name} = 1;
2015 }
2016 foreach my $Symbol (split(/\s*\n\s*/, parseTag(\$Content, "skip_interfaces")),
2017 split(/\s*\n\s*/, parseTag(\$Content, "skip_symbols")))
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04002018 { # skip_interfaces renamed to skip_symbols (1.22.1)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002019 $SkipSymbols{$LibVersion}{$Symbol} = 1;
2020 }
2021 foreach my $NameSpace (split(/\s*\n\s*/, parseTag(\$Content, "skip_namespaces"))) {
2022 $SkipNameSpaces{$LibVersion}{$NameSpace} = 1;
2023 }
Andrey Ponomarenkoa01311b2012-06-08 17:20:02 +04002024 foreach my $NameSpace (split(/\s*\n\s*/, parseTag(\$Content, "add_namespaces"))) {
2025 $AddNameSpaces{$LibVersion}{$NameSpace} = 1;
2026 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002027 foreach my $Constant (split(/\s*\n\s*/, parseTag(\$Content, "skip_constants"))) {
2028 $SkipConstants{$LibVersion}{$Constant} = 1;
2029 }
2030 if(my $DIncPreamble = parseTag(\$Content, "include_preamble"))
2031 {
2032 if($Descriptor{$LibVersion}{"IncludePreamble"})
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04002033 { # multiple descriptors
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002034 $Descriptor{$LibVersion}{"IncludePreamble"} .= "\n".$DIncPreamble;
2035 }
2036 else {
2037 $Descriptor{$LibVersion}{"IncludePreamble"} = $DIncPreamble;
2038 }
2039 }
2040}
2041
Andrey Ponomarenko01117f12012-06-26 12:23:02 +04002042sub parseTag(@)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002043{
Andrey Ponomarenko01117f12012-06-26 12:23:02 +04002044 my $CodeRef = shift(@_);
2045 my $Tag = shift(@_);
2046 if(not $Tag or not $CodeRef) {
2047 return undef;
2048 }
2049 my $Sp = 0;
2050 if(@_) {
2051 $Sp = shift(@_);
2052 }
2053 my $Start = index(${$CodeRef}, "<$Tag>");
2054 if($Start!=-1)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002055 {
Andrey Ponomarenko01117f12012-06-26 12:23:02 +04002056 my $End = index(${$CodeRef}, "</$Tag>");
2057 if($End!=-1)
2058 {
2059 my $TS = length($Tag)+3;
2060 my $Content = substr(${$CodeRef}, $Start, $End-$Start+$TS, "");
2061 substr($Content, 0, $TS-1, ""); # cut start tag
2062 substr($Content, -$TS, $TS, ""); # cut end tag
2063 if(not $Sp)
2064 {
2065 $Content=~s/\A\s+//g;
2066 $Content=~s/\s+\Z//g;
2067 }
2068 if(substr($Content, 0, 1) ne "<") {
2069 $Content = xmlSpecChars_R($Content);
2070 }
2071 return $Content;
2072 }
2073 }
2074 return undef;
2075}
2076
2077sub parseTag_E($$$)
2078{
2079 my ($CodeRef, $Tag, $Info) = @_;
2080 if(not $Tag or not $CodeRef
2081 or not $Info) {
2082 return undef;
2083 }
2084 if(${$CodeRef}=~s/\<\Q$Tag\E(\s+([^<>]+)|)\>((.|\n)*?)\<\/\Q$Tag\E\>//)
2085 {
2086 my ($Ext, $Content) = ($2, $3);
2087 $Content=~s/\A\s+//g;
2088 $Content=~s/\s+\Z//g;
2089 if($Ext)
2090 {
2091 while($Ext=~s/(\w+)\=\"([^\"]*)\"//)
2092 {
2093 my ($K, $V) = ($1, $2);
2094 $Info->{$K} = xmlSpecChars_R($V);
2095 }
2096 }
2097 if(substr($Content, 0, 1) ne "<") {
2098 $Content = xmlSpecChars_R($Content);
2099 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002100 return $Content;
2101 }
Andrey Ponomarenko01117f12012-06-26 12:23:02 +04002102 return undef;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002103}
2104
Andrey Ponomarenko35c44fd2012-06-18 17:50:25 +04002105sub addTag(@)
Andrey Ponomarenko5c09ef32012-06-14 18:17:33 +04002106{
Andrey Ponomarenko35c44fd2012-06-18 17:50:25 +04002107 my $Tag = shift(@_);
2108 my $Val = shift(@_);
2109 my @Ext = @_;
2110 my $Content = openTag($Tag, @Ext);
2111 chomp($Content);
Andrey Ponomarenko5c09ef32012-06-14 18:17:33 +04002112 $Content .= xmlSpecChars($Val);
2113 $Content .= "</$Tag>\n";
Andrey Ponomarenko35c44fd2012-06-18 17:50:25 +04002114 $TAG_ID-=1;
Andrey Ponomarenko5c09ef32012-06-14 18:17:33 +04002115
2116 return $Content;
2117}
2118
Andrey Ponomarenko35c44fd2012-06-18 17:50:25 +04002119sub openTag(@)
Andrey Ponomarenko5c09ef32012-06-14 18:17:33 +04002120{
2121 my $Tag = shift(@_);
2122 my @Ext = @_;
2123 my $Content = "";
2124 foreach (1 .. $TAG_ID) {
2125 $Content .= $INDENT;
2126 }
2127 $TAG_ID+=1;
Andrey Ponomarenko35c44fd2012-06-18 17:50:25 +04002128 if(@Ext)
Andrey Ponomarenko5c09ef32012-06-14 18:17:33 +04002129 {
Andrey Ponomarenko35c44fd2012-06-18 17:50:25 +04002130 $Content .= "<".$Tag;
2131 my $P = 0;
2132 while($P<=$#Ext-1)
2133 {
2134 $Content .= " ".$Ext[$P];
2135 $Content .= "=\"".xmlSpecChars($Ext[$P+1])."\"";
2136 $P+=2;
2137 }
2138 $Content .= ">\n";
Andrey Ponomarenko5c09ef32012-06-14 18:17:33 +04002139 }
Andrey Ponomarenko35c44fd2012-06-18 17:50:25 +04002140 else {
2141 $Content .= "<".$Tag.">\n";
2142 }
Andrey Ponomarenko5c09ef32012-06-14 18:17:33 +04002143 return $Content;
2144}
2145
2146sub closeTag($)
2147{
2148 my $Tag = $_[0];
2149 my $Content = "";
2150 $TAG_ID-=1;
2151 foreach (1 .. $TAG_ID) {
2152 $Content .= $INDENT;
2153 }
2154 $Content .= "</".$Tag.">\n";
2155 return $Content;
2156}
2157
2158sub checkTags()
2159{
2160 if($TAG_ID!=0) {
2161 printMsg("WARNING", "the number of opened tags is not equal to number of closed tags");
2162 }
2163}
2164
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002165sub getInfo($)
2166{
Andrey Ponomarenko85043792012-05-14 16:48:07 +04002167 my $DumpPath = $_[0];
2168 return if(not $DumpPath or not -f $DumpPath);
2169
2170 readTUDump($DumpPath);
2171
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002172 # processing info
2173 setTemplateParams_All();
Andrey Ponomarenko4b077f82012-12-04 16:04:36 +04002174
2175 if($ExtraInfo) {
2176 setAnonTypedef_All();
2177 }
2178
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002179 getTypeInfo_All();
2180 simplifyNames();
Andrey Ponomarenko82bc2572012-11-14 13:55:30 +04002181 simplifyConstants();
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002182 getVarInfo_All();
Andrey Ponomarenko01117f12012-06-26 12:23:02 +04002183 getSymbolInfo_All();
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002184
Andrey Ponomarenko82bc2572012-11-14 13:55:30 +04002185
Andrey Ponomarenko85043792012-05-14 16:48:07 +04002186 # clean memory
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002187 %LibInfo = ();
2188 %TemplateInstance = ();
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002189 %MangledNames = ();
Andrey Ponomarenko85043792012-05-14 16:48:07 +04002190 %TemplateDecl = ();
2191 %StdCxxTypedef = ();
2192 %MissedTypedef = ();
2193 %Typedef_Tr = ();
2194 %Typedef_Eq = ();
Andrey Ponomarenko4b077f82012-12-04 16:04:36 +04002195 %TypedefToAnon = ();
Andrey Ponomarenko85043792012-05-14 16:48:07 +04002196
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04002197 # clean cache
2198 delete($Cache{"getTypeAttr"});
2199 delete($Cache{"getTypeDeclId"});
2200
Andrey Ponomarenko570ece52012-11-30 16:36:44 +04002201 if(not $ExtraInfo)
2202 {
2203 # remove unused types
2204 if($BinaryOnly and not $ExtendedCheck)
2205 { # --binary
2206 removeUnused($Version, "All");
2207 }
2208 else {
2209 removeUnused($Version, "Derived");
2210 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04002211 }
2212
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002213 if($Debug) {
2214 # debugMangling($Version);
2215 }
2216}
2217
Andrey Ponomarenko85043792012-05-14 16:48:07 +04002218sub readTUDump($)
2219{
2220 my $DumpPath = $_[0];
2221
2222 open(TU_DUMP, $DumpPath);
2223 local $/ = undef;
2224 my $Content = <TU_DUMP>;
2225 close(TU_DUMP);
2226
2227 unlink($DumpPath);
2228
2229 $Content=~s/\n[ ]+/ /g;
2230 my @Lines = split("\n", $Content);
2231
2232 # clean memory
2233 undef $Content;
2234
2235 $MAX_ID = $#Lines+1;
2236
2237 foreach (0 .. $#Lines)
2238 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04002239 if($Lines[$_]=~/\A\@(\d+)[ ]+([a-z_]+)[ ]+(.+)\Z/i)
Andrey Ponomarenko85043792012-05-14 16:48:07 +04002240 { # get a number and attributes of a node
2241 next if(not $NodeType{$2});
2242 $LibInfo{$Version}{"info_type"}{$1}=$2;
2243 $LibInfo{$Version}{"info"}{$1}=$3;
2244 }
2245
2246 # clean memory
2247 delete($Lines[$_]);
2248 }
2249
2250 # clean memory
2251 undef @Lines;
2252}
2253
Andrey Ponomarenko82bc2572012-11-14 13:55:30 +04002254sub simplifyConstants()
2255{
2256 foreach my $Constant (keys(%{$Constants{$Version}}))
2257 {
Andrey Ponomarenko2956b972012-11-14 19:16:16 +04002258 my $Value = $Constants{$Version}{$Constant}{"Value"};
2259 if(defined $EnumConstants{$Version}{$Value}) {
2260 $Constants{$Version}{$Constant}{"Value"} = $EnumConstants{$Version}{$Constant}{"Value"};
Andrey Ponomarenko82bc2572012-11-14 13:55:30 +04002261 }
2262 }
2263}
2264
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002265sub simplifyNames()
2266{
2267 foreach my $Base (keys(%{$Typedef_Tr{$Version}}))
2268 {
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +04002269 if($Typedef_Eq{$Version}{$Base}) {
2270 next;
2271 }
2272 my @Translations = sort keys(%{$Typedef_Tr{$Version}{$Base}});
2273 if($#Translations==0)
2274 {
2275 if(length($Translations[0])<=length($Base)) {
2276 $Typedef_Eq{$Version}{$Base} = $Translations[0];
2277 }
2278 }
2279 else
2280 { # select most appropriate
2281 foreach my $Tr (@Translations)
2282 {
2283 if($Base=~/\A\Q$Tr\E/)
2284 {
2285 $Typedef_Eq{$Version}{$Base} = $Tr;
2286 last;
2287 }
2288 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002289 }
2290 }
Andrey Ponomarenkob8d203d2012-05-25 18:11:07 +04002291 foreach my $TypeId (keys(%{$TypeInfo{$Version}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002292 {
Andrey Ponomarenkob8d203d2012-05-25 18:11:07 +04002293 my $TypeName = $TypeInfo{$Version}{$TypeId}{"Name"};
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04002294 if(not $TypeName) {
2295 next;
2296 }
2297 next if(index($TypeName,"<")==-1);# template instances only
2298 if($TypeName=~/>(::\w+)+\Z/)
2299 { # skip unused types
2300 next;
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +04002301 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04002302 foreach my $Base (sort {length($b)<=>length($a)}
2303 sort {$b cmp $a} keys(%{$Typedef_Eq{$Version}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002304 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04002305 next if(not $Base);
2306 next if(index($TypeName,$Base)==-1);
2307 next if(length($TypeName) - length($Base) <= 3);
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +04002308 if(my $Typedef = $Typedef_Eq{$Version}{$Base})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002309 {
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +04002310 $TypeName=~s/(\<|\,)\Q$Base\E(\W|\Z)/$1$Typedef$2/g;
2311 $TypeName=~s/(\<|\,)\Q$Base\E(\w|\Z)/$1$Typedef $2/g;
2312 if(defined $TypeInfo{$Version}{$TypeId}{"TParam"})
Andrey Ponomarenko85043792012-05-14 16:48:07 +04002313 {
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +04002314 foreach my $TPos (keys(%{$TypeInfo{$Version}{$TypeId}{"TParam"}}))
2315 {
2316 if(my $TPName = $TypeInfo{$Version}{$TypeId}{"TParam"}{$TPos}{"name"})
2317 {
2318 $TPName=~s/\A\Q$Base\E(\W|\Z)/$Typedef$1/g;
2319 $TPName=~s/\A\Q$Base\E(\w|\Z)/$Typedef $1/g;
Andrey Ponomarenko9927e332012-10-19 10:50:48 +04002320 $TypeInfo{$Version}{$TypeId}{"TParam"}{$TPos}{"name"} = formatName($TPName, "T");
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +04002321 }
2322 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +04002323 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002324 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002325 }
Andrey Ponomarenko9927e332012-10-19 10:50:48 +04002326 $TypeName = formatName($TypeName, "T");
Andrey Ponomarenkob8d203d2012-05-25 18:11:07 +04002327 $TypeInfo{$Version}{$TypeId}{"Name"} = $TypeName;
2328 $TName_Tid{$Version}{$TypeName} = $TypeId;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002329 }
2330}
2331
Andrey Ponomarenko4b077f82012-12-04 16:04:36 +04002332sub setAnonTypedef_All()
2333{
2334 foreach my $InfoId (keys(%{$LibInfo{$Version}{"info"}}))
2335 {
2336 if($LibInfo{$Version}{"info_type"}{$InfoId} eq "type_decl")
2337 {
2338 if(isAnon(getNameByInfo($InfoId))) {
2339 $TypedefToAnon{getTypeId($InfoId)} = 1;
2340 }
2341 }
2342 }
2343}
2344
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002345sub setTemplateParams_All()
2346{
2347 foreach (keys(%{$LibInfo{$Version}{"info"}}))
2348 {
2349 if($LibInfo{$Version}{"info_type"}{$_} eq "template_decl") {
2350 setTemplateParams($_);
2351 }
2352 }
2353}
2354
2355sub setTemplateParams($)
2356{
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04002357 if(my $Info = $LibInfo{$Version}{"info"}{$_[0]})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002358 {
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04002359 if($Info=~/(inst|spcs)[ ]*:[ ]*@(\d+) /)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002360 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04002361 my $TmplInst_Id = $2;
2362 setTemplateInstParams($TmplInst_Id);
2363 while($TmplInst_Id = getNextElem($TmplInst_Id)) {
2364 setTemplateInstParams($TmplInst_Id);
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04002365 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002366 }
2367 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04002368 if(my $TypeId = getTreeAttr_Type($_[0]))
Andrey Ponomarenko85043792012-05-14 16:48:07 +04002369 {
2370 if(my $IType = $LibInfo{$Version}{"info_type"}{$TypeId})
2371 {
2372 if($IType eq "record_type") {
2373 $TemplateDecl{$Version}{$TypeId}=1;
2374 }
2375 }
2376 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002377}
2378
2379sub setTemplateInstParams($)
2380{
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04002381 if(my $Info = $LibInfo{$Version}{"info"}{$_[0]})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002382 {
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04002383 my ($Params_InfoId, $ElemId) = ();
2384 if($Info=~/purp[ ]*:[ ]*@(\d+) /) {
2385 $Params_InfoId = $1;
2386 }
2387 if($Info=~/valu[ ]*:[ ]*@(\d+) /) {
2388 $ElemId = $1;
2389 }
2390 if($Params_InfoId and $ElemId)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002391 {
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04002392 my $Params_Info = $LibInfo{$Version}{"info"}{$Params_InfoId};
2393 while($Params_Info=~s/ (\d+)[ ]*:[ ]*\@(\d+) / /)
2394 {
2395 my ($PPos, $PTypeId) = ($1, $2);
2396 if(my $PType = $LibInfo{$Version}{"info_type"}{$PTypeId})
2397 {
Andrey Ponomarenko85043792012-05-14 16:48:07 +04002398 if($PType eq "template_type_parm")
2399 {
2400 $TemplateDecl{$Version}{$ElemId}=1;
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04002401 return;
2402 }
2403 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +04002404 if($LibInfo{$Version}{"info_type"}{$ElemId} eq "function_decl")
2405 { # functions
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04002406 $TemplateInstance{$Version}{"Func"}{$ElemId}{$PPos} = $PTypeId;
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04002407 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +04002408 else
2409 { # types
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04002410 $TemplateInstance{$Version}{"Type"}{$ElemId}{$PPos} = $PTypeId;
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04002411 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002412 }
2413 }
2414 }
2415}
2416
2417sub getTypeDeclId($)
2418{
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04002419 if($_[0])
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04002420 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04002421 if(defined $Cache{"getTypeDeclId"}{$Version}{$_[0]}) {
2422 return $Cache{"getTypeDeclId"}{$Version}{$_[0]};
2423 }
2424 if(my $Info = $LibInfo{$Version}{"info"}{$_[0]})
2425 {
2426 if($Info=~/name[ ]*:[ ]*@(\d+)/) {
2427 return ($Cache{"getTypeDeclId"}{$Version}{$_[0]} = $1);
2428 }
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04002429 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002430 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04002431 return ($Cache{"getTypeDeclId"}{$Version}{$_[0]} = 0);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002432}
2433
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002434sub getTypeInfo_All()
2435{
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04002436 if(not check_gcc($GCC_PATH, "4.5"))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002437 { # support for GCC < 4.5
2438 # missed typedefs: QStyle::State is typedef to QFlags<QStyle::StateFlag>
2439 # but QStyleOption.state is of type QFlags<QStyle::StateFlag> in the TU dump
2440 # FIXME: check GCC versions
2441 addMissedTypes_Pre();
2442 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04002443
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002444 foreach (sort {int($a)<=>int($b)} keys(%{$LibInfo{$Version}{"info"}}))
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04002445 { # forward order only
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002446 my $IType = $LibInfo{$Version}{"info_type"}{$_};
2447 if($IType=~/_type\Z/ and $IType ne "function_type"
2448 and $IType ne "method_type") {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04002449 getTypeInfo("$_");
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002450 }
2451 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04002452
2453 # add "..." type
Andrey Ponomarenko01117f12012-06-26 12:23:02 +04002454 $TypeInfo{$Version}{"-1"} = {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04002455 "Name" => "...",
2456 "Type" => "Intrinsic",
Andrey Ponomarenko01117f12012-06-26 12:23:02 +04002457 "Tid" => "-1"
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04002458 };
Andrey Ponomarenko01117f12012-06-26 12:23:02 +04002459 $TName_Tid{$Version}{"..."} = "-1";
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04002460
2461 if(not check_gcc($GCC_PATH, "4.5"))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002462 { # support for GCC < 4.5
2463 addMissedTypes_Post();
2464 }
2465}
2466
2467sub addMissedTypes_Pre()
2468{
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04002469 my %MissedTypes = ();
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002470 foreach my $MissedTDid (sort {int($a)<=>int($b)} keys(%{$LibInfo{$Version}{"info"}}))
2471 { # detecting missed typedefs
2472 if($LibInfo{$Version}{"info_type"}{$MissedTDid} eq "type_decl")
2473 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04002474 my $TypeId = getTreeAttr_Type($MissedTDid);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002475 next if(not $TypeId);
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04002476 my $TypeType = getTypeType($TypeId);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002477 if($TypeType eq "Unknown")
2478 { # template_type_parm
2479 next;
2480 }
2481 my $TypeDeclId = getTypeDeclId($TypeId);
2482 next if($TypeDeclId eq $MissedTDid);#or not $TypeDeclId
2483 my $TypedefName = getNameByInfo($MissedTDid);
2484 next if(not $TypedefName);
2485 next if($TypedefName eq "__float80");
2486 next if(isAnon($TypedefName));
2487 if(not $TypeDeclId
2488 or getNameByInfo($TypeDeclId) ne $TypedefName) {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04002489 $MissedTypes{$Version}{$TypeId}{$MissedTDid} = 1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002490 }
2491 }
2492 }
Andrey Ponomarenkob8d203d2012-05-25 18:11:07 +04002493 my %AddTypes = ();
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04002494 foreach my $Tid (keys(%{$MissedTypes{$Version}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002495 { # add missed typedefs
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04002496 my @Missed = keys(%{$MissedTypes{$Version}{$Tid}});
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002497 if(not @Missed or $#Missed>=1) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002498 next;
2499 }
2500 my $MissedTDid = $Missed[0];
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002501 my ($TypedefName, $TypedefNS) = getTrivialName($MissedTDid, $Tid);
Andrey Ponomarenkob8d203d2012-05-25 18:11:07 +04002502 if(not $TypedefName) {
2503 next;
2504 }
2505 $MAX_ID++;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002506 my %MissedInfo = ( # typedef info
2507 "Name" => $TypedefName,
2508 "NameSpace" => $TypedefNS,
2509 "BaseType" => {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002510 "Tid" => $Tid
2511 },
2512 "Type" => "Typedef",
Andrey Ponomarenkob8d203d2012-05-25 18:11:07 +04002513 "Tid" => "$MAX_ID" );
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002514 my ($H, $L) = getLocation($MissedTDid);
2515 $MissedInfo{"Header"} = $H;
2516 $MissedInfo{"Line"} = $L;
Andrey Ponomarenkob8d203d2012-05-25 18:11:07 +04002517 if($TypedefName=~/\*|\&|\s/)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002518 { # other types
2519 next;
2520 }
Andrey Ponomarenkob8d203d2012-05-25 18:11:07 +04002521 if($TypedefName=~/>(::\w+)+\Z/)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002522 { # QFlags<Qt::DropAction>::enum_type
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002523 next;
2524 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04002525 if(getTypeType($Tid)=~/\A(Intrinsic|Union|Struct|Enum|Class)\Z/)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002526 { # double-check for the name of typedef
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04002527 my ($TName, $TNS) = getTrivialName(getTypeDeclId($Tid), $Tid); # base type info
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002528 next if(not $TName);
Andrey Ponomarenkob8d203d2012-05-25 18:11:07 +04002529 if(length($TypedefName)>=length($TName))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002530 { # too long typedef
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002531 next;
2532 }
Andrey Ponomarenkob8d203d2012-05-25 18:11:07 +04002533 if($TName=~/\A\Q$TypedefName\E</) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002534 next;
2535 }
Andrey Ponomarenkob8d203d2012-05-25 18:11:07 +04002536 if($TypedefName=~/\A\Q$TName\E/)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002537 { # QDateTimeEdit::Section and QDateTimeEdit::Sections::enum_type
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002538 next;
2539 }
Andrey Ponomarenkob8d203d2012-05-25 18:11:07 +04002540 if(get_depth($TypedefName)==0 and get_depth($TName)!=0)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002541 { # std::_Vector_base and std::vector::_Base
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002542 next;
2543 }
2544 }
Andrey Ponomarenkob8d203d2012-05-25 18:11:07 +04002545
2546 $AddTypes{$MissedInfo{"Tid"}} = \%MissedInfo;
2547
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002548 # register typedef
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002549 $MissedTypedef{$Version}{$Tid}{"Tid"} = $MissedInfo{"Tid"};
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04002550 $MissedTypedef{$Version}{$Tid}{"TDid"} = $MissedTDid;
Andrey Ponomarenkob8d203d2012-05-25 18:11:07 +04002551 $TName_Tid{$Version}{$TypedefName} = $MissedInfo{"Tid"};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002552 }
Andrey Ponomarenkob8d203d2012-05-25 18:11:07 +04002553
2554 # add missed & remove other
2555 $TypeInfo{$Version} = \%AddTypes;
2556 delete($Cache{"getTypeAttr"}{$Version});
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002557}
2558
2559sub addMissedTypes_Post()
2560{
2561 foreach my $BaseId (keys(%{$MissedTypedef{$Version}}))
2562 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04002563 if(my $Tid = $MissedTypedef{$Version}{$BaseId}{"Tid"})
2564 {
2565 $TypeInfo{$Version}{$Tid}{"Size"} = $TypeInfo{$Version}{$BaseId}{"Size"};
2566 if(my $TName = $TypeInfo{$Version}{$Tid}{"Name"}) {
2567 $Typedef_BaseName{$Version}{$TName} = $TypeInfo{$Version}{$BaseId}{"Name"};
2568 }
2569 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002570 }
2571}
2572
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04002573sub getTypeInfo($)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002574{
Andrey Ponomarenkob8d203d2012-05-25 18:11:07 +04002575 my $TypeId = $_[0];
2576 %{$TypeInfo{$Version}{$TypeId}} = getTypeAttr($TypeId);
2577 my $TName = $TypeInfo{$Version}{$TypeId}{"Name"};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002578 if(not $TName) {
Andrey Ponomarenkob8d203d2012-05-25 18:11:07 +04002579 delete($TypeInfo{$Version}{$TypeId});
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002580 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002581}
2582
2583sub getArraySize($$)
2584{
2585 my ($TypeId, $BaseName) = @_;
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04002586 if(my $Size = getSize($TypeId))
2587 {
2588 my $Elems = $Size/$BYTE_SIZE;
2589 while($BaseName=~s/\s*\[(\d+)\]//) {
2590 $Elems/=$1;
2591 }
2592 if(my $BasicId = $TName_Tid{$Version}{$BaseName})
2593 {
2594 if(my $BasicSize = $TypeInfo{$Version}{$BasicId}{"Size"}) {
2595 $Elems/=$BasicSize;
2596 }
2597 }
2598 return $Elems;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002599 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04002600 return 0;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002601}
2602
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04002603sub getTParams($$)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002604{
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04002605 my ($TypeId, $Kind) = @_;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002606 my @TmplParams = ();
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04002607 my @Positions = sort {int($a)<=>int($b)} keys(%{$TemplateInstance{$Version}{$Kind}{$TypeId}});
2608 foreach my $Pos (@Positions)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002609 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04002610 my $Param_TypeId = $TemplateInstance{$Version}{$Kind}{$TypeId}{$Pos};
2611 my $NodeType = $LibInfo{$Version}{"info_type"}{$Param_TypeId};
2612 if(not $NodeType)
2613 { # typename_type
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002614 return ();
2615 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04002616 if($NodeType eq "tree_vec")
2617 {
2618 if($Pos!=$#Positions)
2619 { # select last vector of parameters ( ns<P1>::type<P2> )
2620 next;
2621 }
2622 }
2623 my @Params = get_TemplateParam($Pos, $Param_TypeId);
2624 foreach my $P (@Params)
2625 {
2626 if($P eq "") {
2627 return ();
2628 }
2629 elsif($P ne "\@skip\@") {
2630 @TmplParams = (@TmplParams, $P);
2631 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002632 }
2633 }
2634 return @TmplParams;
2635}
2636
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04002637sub getTypeAttr($)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002638{
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04002639 my $TypeId = $_[0];
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04002640 my %TypeAttr = ();
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04002641 if(defined $TypeInfo{$Version}{$TypeId}
2642 and $TypeInfo{$Version}{$TypeId}{"Name"})
2643 { # already created
2644 return %{$TypeInfo{$Version}{$TypeId}};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002645 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04002646 elsif($Cache{"getTypeAttr"}{$Version}{$TypeId})
2647 { # incomplete type
2648 return ();
2649 }
2650 $Cache{"getTypeAttr"}{$Version}{$TypeId} = 1;
2651
2652 my $TypeDeclId = getTypeDeclId($TypeId);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002653 $TypeAttr{"Tid"} = $TypeId;
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04002654
2655 if(not $MissedBase{$Version}{$TypeId} and isTypedef($TypeId))
2656 {
2657 if(my $Info = $LibInfo{$Version}{"info"}{$TypeId})
2658 {
2659 if($Info=~/qual[ ]*:/)
2660 {
2661 if(my $NID = ++$MAX_ID)
2662 {
2663 $MissedBase{$Version}{$TypeId}="$NID";
2664 $MissedBase_R{$Version}{$NID}=$TypeId;
2665 $LibInfo{$Version}{"info"}{$NID} = $LibInfo{$Version}{"info"}{$TypeId};
2666 $LibInfo{$Version}{"info_type"}{$NID} = $LibInfo{$Version}{"info_type"}{$TypeId};
2667 }
2668 }
2669 }
2670 $TypeAttr{"Type"} = "Typedef";
2671 }
2672 else {
2673 $TypeAttr{"Type"} = getTypeType($TypeId);
2674 }
2675
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002676 if($TypeAttr{"Type"} eq "Unknown") {
2677 return ();
2678 }
2679 elsif($TypeAttr{"Type"}=~/(Func|Method|Field)Ptr/)
2680 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04002681 %TypeAttr = getMemPtrAttr(pointTo($TypeId), $TypeId, $TypeAttr{"Type"});
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04002682 if(my $TName = $TypeAttr{"Name"})
2683 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04002684 %{$TypeInfo{$Version}{$TypeId}} = %TypeAttr;
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04002685 $TName_Tid{$Version}{$TName} = $TypeId;
2686 return %TypeAttr;
2687 }
2688 else {
2689 return ();
2690 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002691 }
2692 elsif($TypeAttr{"Type"} eq "Array")
2693 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04002694 my ($BTid, $BTSpec) = selectBaseType($TypeId);
2695 if(not $BTid) {
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04002696 return ();
2697 }
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +04002698 if(my $Algn = getAlgn($TypeId)) {
2699 $TypeAttr{"Algn"} = $Algn/$BYTE_SIZE;
2700 }
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04002701 $TypeAttr{"BaseType"}{"Tid"} = $BTid;
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04002702 if(my %BTAttr = getTypeAttr($BTid))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002703 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04002704 if(not $BTAttr{"Name"}) {
2705 return ();
2706 }
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04002707 if(my $NElems = getArraySize($TypeId, $BTAttr{"Name"}))
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04002708 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04002709 if(my $Size = getSize($TypeId)) {
2710 $TypeAttr{"Size"} = $Size/$BYTE_SIZE;
2711 }
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04002712 if($BTAttr{"Name"}=~/\A([^\[\]]+)(\[(\d+|)\].*)\Z/) {
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04002713 $TypeAttr{"Name"} = $1."[$NElems]".$2;
2714 }
2715 else {
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04002716 $TypeAttr{"Name"} = $BTAttr{"Name"}."[$NElems]";
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04002717 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002718 }
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04002719 else
2720 {
2721 $TypeAttr{"Size"} = $WORD_SIZE{$Version}; # pointer
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04002722 if($BTAttr{"Name"}=~/\A([^\[\]]+)(\[(\d+|)\].*)\Z/) {
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04002723 $TypeAttr{"Name"} = $1."[]".$2;
2724 }
2725 else {
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04002726 $TypeAttr{"Name"} = $BTAttr{"Name"}."[]";
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04002727 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002728 }
Andrey Ponomarenko9927e332012-10-19 10:50:48 +04002729 $TypeAttr{"Name"} = formatName($TypeAttr{"Name"}, "T");
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04002730 if($BTAttr{"Header"}) {
2731 $TypeAttr{"Header"} = $BTAttr{"Header"};
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04002732 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04002733 %{$TypeInfo{$Version}{$TypeId}} = %TypeAttr;
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04002734 $TName_Tid{$Version}{$TypeAttr{"Name"}} = $TypeId;
2735 return %TypeAttr;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002736 }
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04002737 return ();
2738 }
2739 elsif($TypeAttr{"Type"}=~/\A(Intrinsic|Union|Struct|Enum|Class)\Z/)
2740 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04002741 %TypeAttr = getTrivialTypeAttr($TypeId);
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04002742 if($TypeAttr{"Name"})
2743 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04002744 %{$TypeInfo{$Version}{$TypeId}} = %TypeAttr;
2745 if($TypeAttr{"Name"} ne "int" or getTypeDeclId($TypeAttr{"Tid"}))
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04002746 { # NOTE: register only one int: with built-in decl
2747 if(not $TName_Tid{$Version}{$TypeAttr{"Name"}}) {
2748 $TName_Tid{$Version}{$TypeAttr{"Name"}} = $TypeId;
2749 }
2750 }
2751 return %TypeAttr;
2752 }
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04002753 else {
2754 return ();
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002755 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002756 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002757 else
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04002758 { # derived types
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04002759 my ($BTid, $BTSpec) = selectBaseType($TypeId);
2760 if(not $BTid) {
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04002761 return ();
2762 }
2763 $TypeAttr{"BaseType"}{"Tid"} = $BTid;
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04002764 if(defined $MissedTypedef{$Version}{$BTid})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002765 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04002766 if(my $MissedTDid = $MissedTypedef{$Version}{$BTid}{"TDid"})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002767 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04002768 if($MissedTDid ne $TypeDeclId) {
2769 $TypeAttr{"BaseType"}{"Tid"} = $MissedTypedef{$Version}{$BTid}{"Tid"};
2770 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002771 }
2772 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04002773 my %BTAttr = getTypeAttr($TypeAttr{"BaseType"}{"Tid"});
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04002774 if(not $BTAttr{"Name"})
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04002775 { # templates
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002776 return ();
2777 }
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04002778 if($BTAttr{"Type"} eq "Typedef")
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002779 { # relinking typedefs
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04002780 my %BaseBase = get_Type($BTAttr{"BaseType"}{"Tid"}, $Version);
2781 if($BTAttr{"Name"} eq $BaseBase{"Name"}) {
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04002782 $TypeAttr{"BaseType"}{"Tid"} = $BaseBase{"Tid"};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002783 }
2784 }
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04002785 if($BTSpec)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002786 {
2787 if($TypeAttr{"Type"} eq "Pointer"
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04002788 and $BTAttr{"Name"}=~/\([\*]+\)/)
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04002789 {
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04002790 $TypeAttr{"Name"} = $BTAttr{"Name"};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002791 $TypeAttr{"Name"}=~s/\(([*]+)\)/($1*)/g;
2792 }
2793 else {
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04002794 $TypeAttr{"Name"} = $BTAttr{"Name"}." ".$BTSpec;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002795 }
2796 }
2797 else {
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04002798 $TypeAttr{"Name"} = $BTAttr{"Name"};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002799 }
2800 if($TypeAttr{"Type"} eq "Typedef")
2801 {
2802 $TypeAttr{"Name"} = getNameByInfo($TypeDeclId);
Andrey Ponomarenko85043792012-05-14 16:48:07 +04002803 if(isAnon($TypeAttr{"Name"}))
2804 { # anon typedef to anon type: ._N
2805 return ();
2806 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002807 if(my $NS = getNameSpace($TypeDeclId))
2808 {
2809 my $TypeName = $TypeAttr{"Name"};
2810 if($NS=~/\A(struct |union |class |)((.+)::|)\Q$TypeName\E\Z/)
2811 { # "some_type" is the typedef to "struct some_type" in C++
2812 if($3) {
2813 $TypeAttr{"Name"} = $3."::".$TypeName;
2814 }
2815 }
2816 else
2817 {
2818 $TypeAttr{"NameSpace"} = $NS;
2819 $TypeAttr{"Name"} = $TypeAttr{"NameSpace"}."::".$TypeAttr{"Name"};
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04002820
2821 if($TypeAttr{"NameSpace"}=~/\Astd(::|\Z)/
2822 and $TypeAttr{"Name"}!~/>(::\w+)+\Z/)
2823 {
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04002824 if($BTAttr{"NameSpace"}
2825 and $BTAttr{"NameSpace"}=~/\Astd(::|\Z)/ and $BTAttr{"Name"}=~/</)
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04002826 { # types like "std::fpos<__mbstate_t>" are
2827 # not covered by typedefs in the TU dump
2828 # so trying to add such typedefs manually
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04002829 $StdCxxTypedef{$Version}{$BTAttr{"Name"}}{$TypeAttr{"Name"}} = 1;
2830 if(length($TypeAttr{"Name"})<=length($BTAttr{"Name"}))
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04002831 {
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04002832 if(($BTAttr{"Name"}!~/\A(std|boost)::/ or $TypeAttr{"Name"}!~/\A[a-z]+\Z/))
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04002833 { # skip "other" in "std" and "type" in "boost"
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04002834 $Typedef_Eq{$Version}{$BTAttr{"Name"}} = $TypeAttr{"Name"};
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04002835 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002836 }
2837 }
2838 }
2839 }
2840 }
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04002841 if($TypeAttr{"Name"} ne $BTAttr{"Name"}
2842 and $TypeAttr{"Name"}!~/>(::\w+)+\Z/ and $BTAttr{"Name"}!~/>(::\w+)+\Z/)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002843 {
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04002844 if(not defined $Typedef_BaseName{$Version}{$TypeAttr{"Name"}})
2845 { # typedef int*const TYPEDEF; // first
2846 # int foo(TYPEDEF p); // const is optimized out
2847 $Typedef_BaseName{$Version}{$TypeAttr{"Name"}} = $BTAttr{"Name"};
2848 if($BTAttr{"Name"}=~/</)
2849 {
2850 if(($BTAttr{"Name"}!~/\A(std|boost)::/ or $TypeAttr{"Name"}!~/\A[a-z]+\Z/)) {
2851 $Typedef_Tr{$Version}{$BTAttr{"Name"}}{$TypeAttr{"Name"}} = 1;
2852 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002853 }
2854 }
2855 }
2856 ($TypeAttr{"Header"}, $TypeAttr{"Line"}) = getLocation($TypeDeclId);
2857 }
2858 if(not $TypeAttr{"Size"})
2859 {
2860 if($TypeAttr{"Type"} eq "Pointer") {
2861 $TypeAttr{"Size"} = $WORD_SIZE{$Version};
2862 }
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04002863 elsif($BTAttr{"Size"}) {
2864 $TypeAttr{"Size"} = $BTAttr{"Size"};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002865 }
2866 }
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +04002867 if(my $Algn = getAlgn($TypeId)) {
2868 $TypeAttr{"Algn"} = $Algn/$BYTE_SIZE;
2869 }
Andrey Ponomarenko9927e332012-10-19 10:50:48 +04002870 $TypeAttr{"Name"} = formatName($TypeAttr{"Name"}, "T");
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04002871 if(not $TypeAttr{"Header"} and $BTAttr{"Header"}) {
2872 $TypeAttr{"Header"} = $BTAttr{"Header"};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002873 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04002874 %{$TypeInfo{$Version}{$TypeId}} = %TypeAttr;
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04002875 if($TypeAttr{"Name"} ne $BTAttr{"Name"})
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04002876 { # typedef to "class Class"
2877 # should not be registered in TName_Tid
2878 if(not $TName_Tid{$Version}{$TypeAttr{"Name"}}) {
2879 $TName_Tid{$Version}{$TypeAttr{"Name"}} = $TypeId;
2880 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002881 }
2882 return %TypeAttr;
2883 }
2884}
2885
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04002886sub getTreeVec($)
2887{
2888 my %Vector = ();
2889 if($_[0] and my $Info = $LibInfo{$Version}{"info"}{$_[0]})
2890 {
2891 while($Info=~s/ (\d+)[ ]*:[ ]*\@(\d+) / /)
2892 { # string length is N-1 because of the null terminator
2893 $Vector{$1} = $2;
2894 }
2895 }
2896 return \%Vector;
2897}
2898
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002899sub get_TemplateParam($$)
2900{
2901 my ($Pos, $Type_Id) = @_;
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04002902 return () if(not $Type_Id);
2903 my $NodeType = $LibInfo{$Version}{"info_type"}{$Type_Id};
2904 return () if(not $NodeType);
2905 if($NodeType eq "integer_cst")
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002906 { # int (1), unsigned (2u), char ('c' as 99), ...
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04002907 my $CstTid = getTreeAttr_Type($Type_Id);
Andrey Ponomarenkob8d203d2012-05-25 18:11:07 +04002908 my %CstType = getTypeAttr($CstTid); # without recursion
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002909 my $Num = getNodeIntCst($Type_Id);
2910 if(my $CstSuffix = $ConstantSuffix{$CstType{"Name"}}) {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04002911 return ($Num.$CstSuffix);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002912 }
2913 else {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04002914 return ("(".$CstType{"Name"}.")".$Num);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002915 }
2916 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04002917 elsif($NodeType eq "string_cst") {
2918 return (getNodeStrCst($Type_Id));
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002919 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04002920 elsif($NodeType eq "tree_vec")
2921 {
2922 my $Vector = getTreeVec($Type_Id);
2923 my @Params = ();
2924 foreach my $P1 (sort {int($a)<=>int($b)} keys(%{$Vector}))
2925 {
2926 foreach my $P2 (get_TemplateParam($Pos, $Vector->{$P1})) {
2927 push(@Params, $P2);
2928 }
2929 }
2930 return @Params;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002931 }
2932 else
2933 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04002934 my %ParamAttr = getTypeAttr($Type_Id);
Andrey Ponomarenkob8d203d2012-05-25 18:11:07 +04002935 my $PName = $ParamAttr{"Name"};
2936 if(not $PName) {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04002937 return ();
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002938 }
Andrey Ponomarenkob8d203d2012-05-25 18:11:07 +04002939 if($PName=~/\>/)
2940 {
2941 if(my $Cover = cover_stdcxx_typedef($PName)) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002942 $PName = $Cover;
2943 }
2944 }
2945 if($Pos>=1 and
Andrey Ponomarenko1477d2c2012-11-12 18:55:45 +04002946 $PName=~/\A$DEFAULT_STD_PARMS\</)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002947 { # template<typename _Tp, typename _Alloc = std::allocator<_Tp> >
2948 # template<typename _Key, typename _Compare = std::less<_Key>
2949 # template<typename _CharT, typename _Traits = std::char_traits<_CharT> >
2950 # template<typename _Ch_type, typename _Rx_traits = regex_traits<_Ch_type> >
2951 # template<typename _CharT, typename _InIter = istreambuf_iterator<_CharT> >
2952 # template<typename _CharT, typename _OutIter = ostreambuf_iterator<_CharT> >
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04002953 return ("\@skip\@");
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002954 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04002955 return ($PName);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002956 }
2957}
2958
2959sub cover_stdcxx_typedef($)
2960{
2961 my $TypeName = $_[0];
2962 if(my @Covers = sort {length($a)<=>length($b)}
2963 sort keys(%{$StdCxxTypedef{$Version}{$TypeName}}))
2964 { # take the shortest typedef
2965 # FIXME: there may be more than
2966 # one typedefs to the same type
2967 return $Covers[0];
2968 }
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +04002969 my $Covered = $TypeName;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002970 while($TypeName=~s/(>)[ ]*(const|volatile|restrict| |\*|\&)\Z/$1/g){};
2971 if(my @Covers = sort {length($a)<=>length($b)} sort keys(%{$StdCxxTypedef{$Version}{$TypeName}}))
2972 {
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +04002973 if(my $Cover = $Covers[0])
2974 {
2975 $Covered=~s/\b\Q$TypeName\E(\W|\Z)/$Cover$1/g;
2976 $Covered=~s/\b\Q$TypeName\E(\w|\Z)/$Cover $1/g;
2977 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002978 }
Andrey Ponomarenko9927e332012-10-19 10:50:48 +04002979 return formatName($Covered, "T");
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002980}
2981
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002982sub getNodeIntCst($)
2983{
2984 my $CstId = $_[0];
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04002985 my $CstTypeId = getTreeAttr_Type($CstId);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002986 if($EnumMembName_Id{$Version}{$CstId}) {
2987 return $EnumMembName_Id{$Version}{$CstId};
2988 }
2989 elsif((my $Value = getTreeValue($CstId)) ne "")
2990 {
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04002991 if($Value eq "0")
2992 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04002993 if($LibInfo{$Version}{"info_type"}{$CstTypeId} eq "boolean_type") {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002994 return "false";
2995 }
2996 else {
2997 return "0";
2998 }
2999 }
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04003000 elsif($Value eq "1")
3001 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04003002 if($LibInfo{$Version}{"info_type"}{$CstTypeId} eq "boolean_type") {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003003 return "true";
3004 }
3005 else {
3006 return "1";
3007 }
3008 }
3009 else {
3010 return $Value;
3011 }
3012 }
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04003013 return "";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003014}
3015
3016sub getNodeStrCst($)
3017{
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04003018 if($_[0] and my $Info = $LibInfo{$Version}{"info"}{$_[0]})
3019 {
3020 if($Info=~/strg[ ]*: (.+) lngt:[ ]*(\d+)/)
Andrey Ponomarenko01117f12012-06-26 12:23:02 +04003021 {
3022 if($LibInfo{$Version}{"info_type"}{$_[0]} eq "string_cst")
3023 { # string length is N-1 because of the null terminator
3024 return substr($1, 0, $2-1);
3025 }
3026 else
3027 { # identifier_node
3028 return substr($1, 0, $2);
3029 }
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04003030 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003031 }
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04003032 return "";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003033}
3034
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04003035sub getMemPtrAttr($$$)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003036{ # function, method and field pointers
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04003037 my ($PtrId, $TypeId, $Type) = @_;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003038 my $MemInfo = $LibInfo{$Version}{"info"}{$PtrId};
3039 if($Type eq "FieldPtr") {
3040 $MemInfo = $LibInfo{$Version}{"info"}{$TypeId};
3041 }
3042 my $MemInfo_Type = $LibInfo{$Version}{"info_type"}{$PtrId};
3043 my $MemPtrName = "";
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04003044 my %TypeAttr = ("Size"=>$WORD_SIZE{$Version}, "Type"=>$Type, "Tid"=>$TypeId);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003045 if($Type eq "MethodPtr")
3046 { # size of "method pointer" may be greater than WORD size
Andrey Ponomarenko01117f12012-06-26 12:23:02 +04003047 if(my $Size = getSize($TypeId))
3048 {
3049 $Size/=$BYTE_SIZE;
3050 $TypeAttr{"Size"} = "$Size";
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04003051 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003052 }
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +04003053 if(my $Algn = getAlgn($TypeId)) {
3054 $TypeAttr{"Algn"} = $Algn/$BYTE_SIZE;
3055 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003056 # Return
3057 if($Type eq "FieldPtr")
3058 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04003059 my %ReturnAttr = getTypeAttr($PtrId);
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04003060 if($ReturnAttr{"Name"}) {
3061 $MemPtrName .= $ReturnAttr{"Name"};
3062 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003063 $TypeAttr{"Return"} = $PtrId;
3064 }
3065 else
3066 {
3067 if($MemInfo=~/retn[ ]*:[ ]*\@(\d+) /)
3068 {
3069 my $ReturnTypeId = $1;
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04003070 my %ReturnAttr = getTypeAttr($ReturnTypeId);
3071 if(not $ReturnAttr{"Name"})
3072 { # templates
3073 return ();
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04003074 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04003075 $MemPtrName .= $ReturnAttr{"Name"};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003076 $TypeAttr{"Return"} = $ReturnTypeId;
3077 }
3078 }
3079 # Class
3080 if($MemInfo=~/(clas|cls)[ ]*:[ ]*@(\d+) /)
3081 {
3082 $TypeAttr{"Class"} = $2;
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04003083 my %Class = getTypeAttr($TypeAttr{"Class"});
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003084 if($Class{"Name"}) {
3085 $MemPtrName .= " (".$Class{"Name"}."\:\:*)";
3086 }
3087 else {
3088 $MemPtrName .= " (*)";
3089 }
3090 }
3091 else {
3092 $MemPtrName .= " (*)";
3093 }
3094 # Parameters
3095 if($Type eq "FuncPtr"
3096 or $Type eq "MethodPtr")
3097 {
3098 my @ParamTypeName = ();
3099 if($MemInfo=~/prms[ ]*:[ ]*@(\d+) /)
3100 {
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04003101 my $PTypeInfoId = $1;
Andrey Ponomarenko01117f12012-06-26 12:23:02 +04003102 my ($Pos, $PPos) = (0, 0);
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04003103 while($PTypeInfoId)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003104 {
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04003105 my $PTypeInfo = $LibInfo{$Version}{"info"}{$PTypeInfoId};
3106 if($PTypeInfo=~/valu[ ]*:[ ]*@(\d+) /)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003107 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04003108 my $PTypeId = $1;
3109 my %ParamAttr = getTypeAttr($PTypeId);
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04003110 if(not $ParamAttr{"Name"})
3111 { # templates (template_type_parm), etc.
3112 return ();
3113 }
3114 if($ParamAttr{"Name"} eq "void") {
3115 last;
3116 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04003117 if($Pos!=0 or $Type ne "MethodPtr")
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04003118 {
Andrey Ponomarenko01117f12012-06-26 12:23:02 +04003119 $TypeAttr{"Param"}{$PPos++}{"type"} = $PTypeId;
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04003120 push(@ParamTypeName, $ParamAttr{"Name"});
3121 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04003122 if($PTypeInfoId = getNextElem($PTypeInfoId)) {
3123 $Pos+=1;
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04003124 }
3125 else {
3126 last;
3127 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003128 }
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04003129 else {
3130 last;
3131 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003132 }
3133 }
3134 $MemPtrName .= " (".join(", ", @ParamTypeName).")";
3135 }
Andrey Ponomarenko9927e332012-10-19 10:50:48 +04003136 $TypeAttr{"Name"} = formatName($MemPtrName, "T");
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003137 return %TypeAttr;
3138}
3139
3140sub getTreeTypeName($)
3141{
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04003142 my $TypeId = $_[0];
3143 if(my $Info = $LibInfo{$Version}{"info"}{$TypeId})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003144 {
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04003145 if($LibInfo{$Version}{"info_type"}{$_[0]} eq "integer_type")
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003146 {
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04003147 if(my $Name = getNameByInfo($TypeId))
3148 { # bit_size_type
3149 return $Name;
3150 }
3151 elsif($Info=~/unsigned/) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003152 return "unsigned int";
3153 }
3154 else {
3155 return "int";
3156 }
3157 }
Andrey Ponomarenko4b077f82012-12-04 16:04:36 +04003158 elsif($Info=~/name[ ]*:[ ]*@(\d+) /) {
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04003159 return getNameByInfo($1);
3160 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003161 }
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04003162 return "";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003163}
3164
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04003165sub isFuncPtr($)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003166{
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04003167 my $Ptd = pointTo($_[0]);
3168 return 0 if(not $Ptd);
3169 if(my $Info = $LibInfo{$Version}{"info"}{$_[0]})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003170 {
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04003171 if($Info=~/unql[ ]*:/ and $Info!~/qual[ ]*:/) {
3172 return 0;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003173 }
3174 }
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04003175 if(my $InfoT1 = $LibInfo{$Version}{"info_type"}{$_[0]}
3176 and my $InfoT2 = $LibInfo{$Version}{"info_type"}{$Ptd})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003177 {
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04003178 if($InfoT1 eq "pointer_type"
3179 and $InfoT2 eq "function_type") {
3180 return 1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003181 }
3182 }
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04003183 return 0;
3184}
3185
3186sub isMethodPtr($)
3187{
3188 my $Ptd = pointTo($_[0]);
3189 return 0 if(not $Ptd);
3190 if(my $Info = $LibInfo{$Version}{"info"}{$_[0]})
3191 {
3192 if($LibInfo{$Version}{"info_type"}{$_[0]} eq "record_type"
3193 and $LibInfo{$Version}{"info_type"}{$Ptd} eq "method_type"
3194 and $Info=~/ ptrmem /) {
3195 return 1;
3196 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003197 }
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04003198 return 0;
3199}
3200
3201sub isFieldPtr($)
3202{
3203 if($_[0] and my $Info = $LibInfo{$Version}{"info"}{$_[0]})
3204 {
3205 if($LibInfo{$Version}{"info_type"}{$_[0]} eq "offset_type"
3206 and $Info=~/ ptrmem /) {
3207 return 1;
3208 }
3209 }
3210 return 0;
3211}
3212
3213sub pointTo($)
3214{
3215 if($_[0] and my $Info = $LibInfo{$Version}{"info"}{$_[0]})
3216 {
3217 if($Info=~/ptd[ ]*:[ ]*@(\d+)/) {
3218 return $1;
3219 }
3220 }
3221 return "";
3222}
3223
3224sub getTypeTypeByTypeId($)
3225{
3226 my $TypeId = $_[0];
3227 if(my $TType = $LibInfo{$Version}{"info_type"}{$TypeId})
3228 {
3229 my $NType = $NodeType{$TType};
3230 if($NType eq "Intrinsic") {
3231 return $NType;
3232 }
3233 elsif(isFuncPtr($TypeId)) {
3234 return "FuncPtr";
3235 }
3236 elsif(isMethodPtr($TypeId)) {
3237 return "MethodPtr";
3238 }
3239 elsif(isFieldPtr($TypeId)) {
3240 return "FieldPtr";
3241 }
3242 elsif($NType ne "Other") {
3243 return $NType;
3244 }
3245 }
3246 return "Unknown";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003247}
3248
3249sub getQual($)
3250{
3251 my $TypeId = $_[0];
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003252 my %UnQual = (
3253 "r"=>"restrict",
3254 "v"=>"volatile",
3255 "c"=>"const",
3256 "cv"=>"const volatile"
3257 );
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04003258 if(my $Info = $LibInfo{$Version}{"info"}{$TypeId})
3259 {
3260 my ($Qual, $To) = ();
3261 if($Info=~/qual[ ]*:[ ]*(r|c|v|cv) /) {
3262 $Qual = $UnQual{$1};
3263 }
3264 if($Info=~/unql[ ]*:[ ]*\@(\d+)/) {
3265 $To = $1;
3266 }
3267 if($Qual and $To) {
3268 return ($Qual, $To);
3269 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003270 }
3271 return ();
3272}
3273
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04003274sub getQualType($)
3275{
3276 if($_[0] eq "const volatile") {
3277 return "ConstVolatile";
3278 }
3279 return ucfirst($_[0]);
3280}
3281
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04003282sub getTypeType($)
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04003283{
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04003284 my $TypeId = $_[0];
3285 my $TypeDeclId = getTypeDeclId($TypeId);
3286 if(defined $MissedTypedef{$Version}{$TypeId})
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04003287 { # support for old GCC versions
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04003288 if($MissedTypedef{$Version}{$TypeId}{"TDid"} eq $TypeDeclId) {
3289 return "Typedef";
3290 }
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04003291 }
3292 my $Info = $LibInfo{$Version}{"info"}{$TypeId};
3293 my ($Qual, $To) = getQual($TypeId);
Andrey Ponomarenko9927e332012-10-19 10:50:48 +04003294 if(($Qual or $To) and $TypeDeclId
3295 and (getTypeId($TypeDeclId) ne $TypeId))
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04003296 { # qualified types (special)
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04003297 return getQualType($Qual);
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04003298 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04003299 elsif(not $MissedBase_R{$Version}{$TypeId}
3300 and isTypedef($TypeId)) {
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04003301 return "Typedef";
3302 }
3303 elsif($Qual)
3304 { # qualified types
3305 return getQualType($Qual);
3306 }
Andrey Ponomarenko9927e332012-10-19 10:50:48 +04003307
3308 if($Info=~/unql[ ]*:[ ]*\@(\d+)/)
3309 { # typedef struct { ... } name
3310 $TypeTypedef{$Version}{$TypeId} = $1;
3311 }
3312
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04003313 my $TypeType = getTypeTypeByTypeId($TypeId);
3314 if($TypeType eq "Struct")
3315 {
3316 if($TypeDeclId
3317 and $LibInfo{$Version}{"info_type"}{$TypeDeclId} eq "template_decl") {
3318 return "Template";
3319 }
3320 }
3321 return $TypeType;
3322}
3323
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04003324sub isTypedef($)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003325{
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04003326 if($_[0] and my $Info = $LibInfo{$Version}{"info"}{$_[0]})
3327 {
3328 my $TDid = getTypeDeclId($_[0]);
3329 if(getNameByInfo($TDid)
3330 and $Info=~/unql[ ]*:[ ]*\@(\d+) /
3331 and getTypeId($TDid) eq $_[0]) {
3332 return $1;
3333 }
3334 }
3335 return 0;
3336}
3337
3338sub selectBaseType($)
3339{
3340 my $TypeId = $_[0];
3341 if(defined $MissedTypedef{$Version}{$TypeId})
3342 { # add missed typedefs
3343 if($MissedTypedef{$Version}{$TypeId}{"TDid"} eq getTypeDeclId($TypeId)) {
3344 return ($TypeId, "");
3345 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003346 }
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04003347 my $Info = $LibInfo{$Version}{"info"}{$TypeId};
3348 my $InfoType = $LibInfo{$Version}{"info_type"}{$TypeId};
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04003349
3350 my $MB_R = $MissedBase_R{$Version}{$TypeId};
3351 my $MB = $MissedBase{$Version}{$TypeId};
3352
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04003353 my ($Qual, $To) = getQual($TypeId);
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04003354 if(($Qual or $To) and $Info=~/name[ ]*:[ ]*\@(\d+) /
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04003355 and (getTypeId($1) ne $TypeId)
3356 and (not $MB_R or getTypeId($1) ne $MB_R))
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04003357 { # qualified types (special)
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04003358 return (getTypeId($1), $Qual);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003359 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04003360 elsif($MB)
3361 { # add base
3362 return ($MB, "");
3363 }
3364 elsif(not $MB_R and my $Bid = isTypedef($TypeId))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003365 { # typedefs
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04003366 return ($Bid, "");
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003367 }
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04003368 elsif($Qual or $To)
3369 { # qualified types
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04003370 return ($To, $Qual);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003371 }
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04003372 elsif($InfoType eq "reference_type")
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003373 {
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04003374 if($Info=~/refd[ ]*:[ ]*@(\d+) /) {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04003375 return ($1, "&");
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003376 }
3377 else {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04003378 return (0, "");
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003379 }
3380 }
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04003381 elsif($InfoType eq "array_type")
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003382 {
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04003383 if($Info=~/elts[ ]*:[ ]*@(\d+) /) {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04003384 return ($1, "");
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003385 }
3386 else {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04003387 return (0, "");
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003388 }
3389 }
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04003390 elsif($InfoType eq "pointer_type")
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003391 {
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04003392 if($Info=~/ptd[ ]*:[ ]*@(\d+) /) {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04003393 return ($1, "*");
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003394 }
3395 else {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04003396 return (0, "");
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003397 }
3398 }
3399 else {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04003400 return (0, "");
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003401 }
3402}
3403
3404sub getSymbolInfo_All()
3405{
3406 foreach (sort {int($b)<=>int($a)} keys(%{$LibInfo{$Version}{"info"}}))
3407 { # reverse order
3408 if($LibInfo{$Version}{"info_type"}{$_} eq "function_decl") {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04003409 getSymbolInfo($_);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003410 }
3411 }
3412}
3413
3414sub getVarInfo_All()
3415{
3416 foreach (sort {int($b)<=>int($a)} keys(%{$LibInfo{$Version}{"info"}}))
3417 { # reverse order
3418 if($LibInfo{$Version}{"info_type"}{$_} eq "var_decl") {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04003419 getVarInfo($_);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003420 }
3421 }
3422}
3423
3424sub isBuiltIn($) {
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04003425 return ($_[0] and $_[0]=~/\<built\-in\>|\<internal\>|\A\./);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003426}
3427
3428sub getVarInfo($)
3429{
3430 my $InfoId = $_[0];
Andrey Ponomarenko01117f12012-06-26 12:23:02 +04003431 if(my $NSid = getTreeAttr_Scpe($InfoId))
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04003432 {
3433 my $NSInfoType = $LibInfo{$Version}{"info_type"}{$NSid};
3434 if($NSInfoType and $NSInfoType eq "function_decl") {
3435 return;
3436 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003437 }
3438 ($SymbolInfo{$Version}{$InfoId}{"Header"}, $SymbolInfo{$Version}{$InfoId}{"Line"}) = getLocation($InfoId);
3439 if(not $SymbolInfo{$Version}{$InfoId}{"Header"}
3440 or isBuiltIn($SymbolInfo{$Version}{$InfoId}{"Header"})) {
3441 delete($SymbolInfo{$Version}{$InfoId});
3442 return;
3443 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04003444 my $ShortName = getTreeStr(getTreeAttr_Name($InfoId));
Andrey Ponomarenko85043792012-05-14 16:48:07 +04003445 if(not $ShortName) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003446 delete($SymbolInfo{$Version}{$InfoId});
3447 return;
3448 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +04003449 if($ShortName=~/\Atmp_add_class_\d+\Z/) {
3450 delete($SymbolInfo{$Version}{$InfoId});
3451 return;
3452 }
3453 $SymbolInfo{$Version}{$InfoId}{"ShortName"} = $ShortName;
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +04003454 if(my $MnglName = getTreeStr(getTreeAttr_Mngl($InfoId)))
3455 {
3456 if($OSgroup eq "windows")
3457 { # cut the offset
3458 $MnglName=~s/\@\d+\Z//g;
3459 }
3460 $SymbolInfo{$Version}{$InfoId}{"MnglName"} = $MnglName;
3461 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003462 if($SymbolInfo{$Version}{$InfoId}{"MnglName"}
Andrey Ponomarenko9927e332012-10-19 10:50:48 +04003463 and index($SymbolInfo{$Version}{$InfoId}{"MnglName"}, "_Z")!=0)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003464 { # validate mangled name
3465 delete($SymbolInfo{$Version}{$InfoId});
3466 return;
3467 }
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04003468 if(not $SymbolInfo{$Version}{$InfoId}{"MnglName"}
Andrey Ponomarenko9927e332012-10-19 10:50:48 +04003469 and index($ShortName, "_Z")==0)
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04003470 { # _ZTS, etc.
Andrey Ponomarenko85043792012-05-14 16:48:07 +04003471 $SymbolInfo{$Version}{$InfoId}{"MnglName"} = $ShortName;
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04003472 }
3473 if(isPrivateData($SymbolInfo{$Version}{$InfoId}{"MnglName"}))
3474 { # non-public global data
3475 delete($SymbolInfo{$Version}{$InfoId});
3476 return;
3477 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003478 $SymbolInfo{$Version}{$InfoId}{"Data"} = 1;
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04003479 if(my $Rid = getTypeId($InfoId))
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04003480 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04003481 if(not $TypeInfo{$Version}{$Rid}{"Name"})
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04003482 { # typename_type
3483 delete($SymbolInfo{$Version}{$InfoId});
3484 return;
3485 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04003486 $SymbolInfo{$Version}{$InfoId}{"Return"} = $Rid;
3487 my $Val = getDataVal($InfoId, $Rid);
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04003488 if(defined $Val) {
3489 $SymbolInfo{$Version}{$InfoId}{"Value"} = $Val;
3490 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003491 }
3492 set_Class_And_Namespace($InfoId);
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04003493 if(my $ClassId = $SymbolInfo{$Version}{$InfoId}{"Class"})
3494 {
3495 if(not $TypeInfo{$Version}{$ClassId}{"Name"})
3496 { # templates
3497 delete($SymbolInfo{$Version}{$InfoId});
3498 return;
3499 }
3500 }
Andrey Ponomarenko35c44fd2012-06-18 17:50:25 +04003501 if($LibInfo{$Version}{"info"}{$InfoId}=~/ lang:[ ]*C /i)
3502 { # extern "C"
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003503 $SymbolInfo{$Version}{$InfoId}{"Lang"} = "C";
Andrey Ponomarenko35c44fd2012-06-18 17:50:25 +04003504 $SymbolInfo{$Version}{$InfoId}{"MnglName"} = $ShortName;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003505 }
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04003506 if($UserLang and $UserLang eq "C")
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003507 { # --lang=C option
Andrey Ponomarenko85043792012-05-14 16:48:07 +04003508 $SymbolInfo{$Version}{$InfoId}{"MnglName"} = $ShortName;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003509 }
Andrey Ponomarenko5c09ef32012-06-14 18:17:33 +04003510 if(not $CheckHeadersOnly)
3511 {
3512 if(not $SymbolInfo{$Version}{$InfoId}{"Class"})
3513 {
3514 if(not $SymbolInfo{$Version}{$InfoId}{"MnglName"}
3515 or not link_symbol($SymbolInfo{$Version}{$InfoId}{"MnglName"}, $Version, "-Deps"))
3516 {
3517 if(link_symbol($ShortName, $Version, "-Deps"))
3518 { # "const" global data is mangled as _ZL... in the TU dump
3519 # but not mangled when compiling a C shared library
3520 $SymbolInfo{$Version}{$InfoId}{"MnglName"} = $ShortName;
3521 }
3522 }
3523 }
3524 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003525 if($COMMON_LANGUAGE{$Version} eq "C++")
3526 {
3527 if(not $SymbolInfo{$Version}{$InfoId}{"MnglName"})
3528 { # for some symbols (_ZTI) the short name is the mangled name
Andrey Ponomarenko9927e332012-10-19 10:50:48 +04003529 if(index($ShortName, "_Z")==0) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003530 $SymbolInfo{$Version}{$InfoId}{"MnglName"} = $ShortName;
3531 }
3532 }
3533 if(not $SymbolInfo{$Version}{$InfoId}{"MnglName"})
3534 { # try to mangle symbol (link with libraries)
3535 $SymbolInfo{$Version}{$InfoId}{"MnglName"} = linkSymbol($InfoId);
3536 }
3537 if($OStarget eq "windows")
3538 {
3539 if(my $Mangled = $mangled_name{$Version}{modelUnmangled($InfoId, "MSVC")})
3540 { # link MS C++ symbols from library with GCC symbols from headers
3541 $SymbolInfo{$Version}{$InfoId}{"MnglName"} = $Mangled;
3542 }
3543 }
3544 }
3545 if(not $SymbolInfo{$Version}{$InfoId}{"MnglName"}) {
3546 $SymbolInfo{$Version}{$InfoId}{"MnglName"} = $ShortName;
3547 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +04003548 if(my $Symbol = $SymbolInfo{$Version}{$InfoId}{"MnglName"})
3549 {
3550 if(not selectSymbol($Symbol, $SymbolInfo{$Version}{$InfoId}, "Dump", $Version))
3551 { # non-target symbols
3552 delete($SymbolInfo{$Version}{$InfoId});
3553 return;
3554 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003555 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04003556 if(my $Rid = $SymbolInfo{$Version}{$InfoId}{"Return"})
3557 {
3558 if(defined $MissedTypedef{$Version}{$Rid})
3559 {
3560 if(my $AddedTid = $MissedTypedef{$Version}{$Rid}{"Tid"}) {
3561 $SymbolInfo{$Version}{$InfoId}{"Return"} = $AddedTid;
3562 }
3563 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003564 }
3565 setFuncAccess($InfoId);
Andrey Ponomarenko9927e332012-10-19 10:50:48 +04003566 if(index($SymbolInfo{$Version}{$InfoId}{"MnglName"}, "_ZTV")==0) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003567 delete($SymbolInfo{$Version}{$InfoId}{"Return"});
3568 }
3569 if($ShortName=~/\A(_Z|\?)/) {
3570 delete($SymbolInfo{$Version}{$InfoId}{"ShortName"});
3571 }
3572}
3573
Andrey Ponomarenko85043792012-05-14 16:48:07 +04003574sub isConstType($$)
3575{
3576 my ($TypeId, $LibVersion) = @_;
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04003577 my %Base = get_Type($TypeId, $LibVersion);
Andrey Ponomarenko85043792012-05-14 16:48:07 +04003578 while(defined $Base{"Type"} and $Base{"Type"} eq "Typedef") {
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +04003579 %Base = get_OneStep_BaseType($Base{"Tid"}, $TypeInfo{$LibVersion});
Andrey Ponomarenko85043792012-05-14 16:48:07 +04003580 }
3581 return ($Base{"Type"} eq "Const");
3582}
3583
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003584sub getTrivialName($$)
3585{
3586 my ($TypeInfoId, $TypeId) = @_;
3587 my %TypeAttr = ();
3588 $TypeAttr{"Name"} = getNameByInfo($TypeInfoId);
3589 if(not $TypeAttr{"Name"}) {
3590 $TypeAttr{"Name"} = getTreeTypeName($TypeId);
3591 }
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04003592 ($TypeAttr{"Header"}, $TypeAttr{"Line"}) = getLocation($TypeInfoId);
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04003593 $TypeAttr{"Type"} = getTypeType($TypeId);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003594 $TypeAttr{"Name"}=~s/<(.+)\Z//g; # GCC 3.4.4 add template params to the name
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04003595 if(isAnon($TypeAttr{"Name"}))
3596 {
3597 my $NameSpaceId = $TypeId;
Andrey Ponomarenko01117f12012-06-26 12:23:02 +04003598 while(my $NSId = getTreeAttr_Scpe(getTypeDeclId($NameSpaceId)))
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04003599 { # searching for a first not anon scope
3600 if($NSId eq $NameSpaceId) {
3601 last;
3602 }
3603 else
3604 {
3605 $TypeAttr{"NameSpace"} = getNameSpace(getTypeDeclId($TypeId));
3606 if(not $TypeAttr{"NameSpace"}
Andrey Ponomarenko2956b972012-11-14 19:16:16 +04003607 or not isAnon($TypeAttr{"NameSpace"})) {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04003608 last;
3609 }
3610 }
3611 $NameSpaceId=$NSId;
3612 }
3613 }
3614 else
3615 {
Andrey Ponomarenko01117f12012-06-26 12:23:02 +04003616 if(my $NameSpaceId = getTreeAttr_Scpe($TypeInfoId))
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04003617 {
3618 if($NameSpaceId ne $TypeId) {
3619 $TypeAttr{"NameSpace"} = getNameSpace($TypeInfoId);
3620 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003621 }
3622 }
Andrey Ponomarenko2956b972012-11-14 19:16:16 +04003623 if($TypeAttr{"NameSpace"} and not isAnon($TypeAttr{"Name"})) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003624 $TypeAttr{"Name"} = $TypeAttr{"NameSpace"}."::".$TypeAttr{"Name"};
3625 }
Andrey Ponomarenko9927e332012-10-19 10:50:48 +04003626 $TypeAttr{"Name"} = formatName($TypeAttr{"Name"}, "T");
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003627 if(isAnon($TypeAttr{"Name"}))
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04003628 { # anon-struct-header.h-line
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04003629 $TypeAttr{"Name"} = "anon-".lc($TypeAttr{"Type"})."-";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003630 $TypeAttr{"Name"} .= $TypeAttr{"Header"}."-".$TypeAttr{"Line"};
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04003631 if($TypeAttr{"NameSpace"}) {
3632 $TypeAttr{"Name"} = $TypeAttr{"NameSpace"}."::".$TypeAttr{"Name"};
3633 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003634 }
Andrey Ponomarenkob8d203d2012-05-25 18:11:07 +04003635 if(defined $TemplateInstance{$Version}{"Type"}{$TypeId}
3636 and getTypeDeclId($TypeId) eq $TypeInfoId)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003637 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04003638 my @TParams = getTParams($TypeId, "Type");
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003639 if(not @TParams)
3640 { # template declarations with abstract params
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003641 return ("", "");
3642 }
Andrey Ponomarenko9927e332012-10-19 10:50:48 +04003643 $TypeAttr{"Name"} = formatName($TypeAttr{"Name"}."< ".join(", ", @TParams)." >", "T");
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003644 }
3645 return ($TypeAttr{"Name"}, $TypeAttr{"NameSpace"});
3646}
3647
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04003648sub getTrivialTypeAttr($)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003649{
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04003650 my $TypeId = $_[0];
3651 my $TypeInfoId = getTypeDeclId($_[0]);
Andrey Ponomarenko85043792012-05-14 16:48:07 +04003652
3653 if($TemplateDecl{$Version}{$TypeId})
3654 { # template_decl
3655 return ();
3656 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04003657 if(my $ScopeId = getTreeAttr_Scpe($TypeInfoId))
3658 {
3659 if($TemplateDecl{$Version}{$ScopeId})
3660 { # template_decl
3661 return ();
3662 }
3663 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +04003664
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003665 my %TypeAttr = ();
3666 if(getTypeTypeByTypeId($TypeId)!~/\A(Intrinsic|Union|Struct|Enum|Class)\Z/) {
3667 return ();
3668 }
3669 setTypeAccess($TypeId, \%TypeAttr);
3670 ($TypeAttr{"Header"}, $TypeAttr{"Line"}) = getLocation($TypeInfoId);
3671 if(isBuiltIn($TypeAttr{"Header"}))
3672 {
3673 delete($TypeAttr{"Header"});
3674 delete($TypeAttr{"Line"});
3675 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04003676 $TypeAttr{"Type"} = getTypeType($TypeId);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003677 ($TypeAttr{"Name"}, $TypeAttr{"NameSpace"}) = getTrivialName($TypeInfoId, $TypeId);
3678 if(not $TypeAttr{"Name"}) {
3679 return ();
3680 }
3681 if(not $TypeAttr{"NameSpace"}) {
3682 delete($TypeAttr{"NameSpace"});
3683 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04003684 if(defined $TemplateInstance{$Version}{"Type"}{$TypeId})
Andrey Ponomarenko16934472012-03-29 15:37:04 +04003685 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04003686 if(my @TParams = getTParams($TypeId, "Type"))
Andrey Ponomarenko16934472012-03-29 15:37:04 +04003687 {
3688 foreach my $Pos (0 .. $#TParams) {
3689 $TypeAttr{"TParam"}{$Pos}{"name"}=$TParams[$Pos];
3690 }
3691 }
3692 }
Andrey Ponomarenko01117f12012-06-26 12:23:02 +04003693 if(my $Size = getSize($TypeId))
3694 {
3695 $Size = $Size/$BYTE_SIZE;
3696 $TypeAttr{"Size"} = "$Size";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003697 }
Andrey Ponomarenko9927e332012-10-19 10:50:48 +04003698 else
3699 { # declaration only
3700 $TypeAttr{"Forward"} = 1;
3701 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003702 if($TypeAttr{"Type"} eq "Struct"
3703 and detect_lang($TypeId))
3704 {
3705 $TypeAttr{"Type"} = "Class";
Andrey Ponomarenko85043792012-05-14 16:48:07 +04003706 $TypeAttr{"Copied"} = 1; # default, will be changed in getSymbolInfo()
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003707 }
3708 if($TypeAttr{"Type"} eq "Struct"
Andrey Ponomarenko85043792012-05-14 16:48:07 +04003709 or $TypeAttr{"Type"} eq "Class")
3710 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04003711 my $Skip = setBaseClasses($TypeId, \%TypeAttr);
Andrey Ponomarenko85043792012-05-14 16:48:07 +04003712 if($Skip) {
3713 return ();
3714 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003715 }
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +04003716 if(my $Algn = getAlgn($TypeId)) {
3717 $TypeAttr{"Algn"} = $Algn/$BYTE_SIZE;
3718 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003719 setSpec($TypeId, \%TypeAttr);
3720 setTypeMemb($TypeId, \%TypeAttr);
3721 $TypeAttr{"Tid"} = $TypeId;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003722 if(my $VTable = $ClassVTable_Content{$Version}{$TypeAttr{"Name"}})
3723 {
3724 my @Entries = split(/\n/, $VTable);
3725 foreach (1 .. $#Entries)
3726 {
3727 my $Entry = $Entries[$_];
3728 if($Entry=~/\A(\d+)\s+(.+)\Z/) {
3729 $TypeAttr{"VTable"}{$1} = $2;
3730 }
3731 }
3732 }
Andrey Ponomarenko82bc2572012-11-14 13:55:30 +04003733
3734 if($TypeAttr{"Type"} eq "Enum")
3735 {
3736 if(not $TypeAttr{"NameSpace"})
3737 {
3738 foreach my $Pos (keys(%{$TypeAttr{"Memb"}}))
3739 {
3740 my $MName = $TypeAttr{"Memb"}{$Pos}{"name"};
3741 $EnumConstants{$Version}{$MName} = {
3742 "Value"=>$TypeAttr{"Memb"}{$Pos}{"value"},
3743 "Header"=>$TypeAttr{"Header"}
3744 };
3745 }
3746 }
3747 }
Andrey Ponomarenko4b077f82012-12-04 16:04:36 +04003748 if($ExtraInfo)
3749 {
3750 if(defined $TypedefToAnon{$TypeId}) {
3751 $TypeAttr{"AnonTypedef"} = 1;
3752 }
3753 }
Andrey Ponomarenko82bc2572012-11-14 13:55:30 +04003754
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003755 return %TypeAttr;
3756}
3757
3758sub detect_lang($)
3759{
3760 my $TypeId = $_[0];
3761 my $Info = $LibInfo{$Version}{"info"}{$TypeId};
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04003762 if(check_gcc($GCC_PATH, "4"))
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04003763 { # GCC 4 fncs-node points to only non-artificial methods
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003764 return ($Info=~/(fncs)[ ]*:[ ]*@(\d+) /);
3765 }
3766 else
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04003767 { # GCC 3
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04003768 my $Fncs = getTreeAttr_Fncs($TypeId);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003769 while($Fncs)
3770 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04003771 if($LibInfo{$Version}{"info"}{$Fncs}!~/artificial/) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003772 return 1;
3773 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04003774 $Fncs = getTreeAttr_Chan($Fncs);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003775 }
3776 }
3777 return 0;
3778}
3779
3780sub setSpec($$)
3781{
3782 my ($TypeId, $TypeAttr) = @_;
3783 my $Info = $LibInfo{$Version}{"info"}{$TypeId};
3784 if($Info=~/\s+spec\s+/) {
3785 $TypeAttr->{"Spec"} = 1;
3786 }
3787}
3788
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04003789sub setBaseClasses($$)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003790{
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04003791 my ($TypeId, $TypeAttr) = @_;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003792 my $Info = $LibInfo{$Version}{"info"}{$TypeId};
3793 if($Info=~/binf[ ]*:[ ]*@(\d+) /)
3794 {
3795 $Info = $LibInfo{$Version}{"info"}{$1};
3796 my $Pos = 0;
3797 while($Info=~s/(pub|public|prot|protected|priv|private|)[ ]+binf[ ]*:[ ]*@(\d+) //)
3798 {
3799 my ($Access, $BInfoId) = ($1, $2);
3800 my $ClassId = getBinfClassId($BInfoId);
Andrey Ponomarenko85043792012-05-14 16:48:07 +04003801 my $CType = $LibInfo{$Version}{"info_type"}{$ClassId};
3802 if(not $CType or $CType eq "template_type_parm"
3803 or $CType eq "typename_type")
3804 { # skip
3805 return 1;
3806 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003807 my $BaseInfo = $LibInfo{$Version}{"info"}{$BInfoId};
Andrey Ponomarenko4b077f82012-12-04 16:04:36 +04003808 if($Access=~/prot/) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003809 $TypeAttr->{"Base"}{$ClassId}{"access"} = "protected";
3810 }
Andrey Ponomarenko4b077f82012-12-04 16:04:36 +04003811 elsif($Access=~/priv/) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003812 $TypeAttr->{"Base"}{$ClassId}{"access"} = "private";
3813 }
Andrey Ponomarenko01117f12012-06-26 12:23:02 +04003814 $TypeAttr->{"Base"}{$ClassId}{"pos"} = "$Pos";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003815 if($BaseInfo=~/virt/)
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04003816 { # virtual base
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003817 $TypeAttr->{"Base"}{$ClassId}{"virtual"} = 1;
3818 }
3819 $Class_SubClasses{$Version}{$ClassId}{$TypeId}=1;
Andrey Ponomarenko4b077f82012-12-04 16:04:36 +04003820 $Pos += 1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003821 }
3822 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +04003823 return 0;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003824}
3825
3826sub getBinfClassId($)
3827{
3828 my $Info = $LibInfo{$Version}{"info"}{$_[0]};
3829 $Info=~/type[ ]*:[ ]*@(\d+) /;
3830 return $1;
3831}
3832
3833sub unmangledFormat($$)
3834{
3835 my ($Name, $LibVersion) = @_;
3836 $Name = uncover_typedefs($Name, $LibVersion);
3837 while($Name=~s/([^\w>*])(const|volatile)(,|>|\Z)/$1$3/g){};
3838 $Name=~s/\(\w+\)(\d)/$1/;
3839 return $Name;
3840}
3841
3842sub modelUnmangled($$)
3843{
3844 my ($InfoId, $Compiler) = @_;
3845 if($Cache{"modelUnmangled"}{$Version}{$Compiler}{$InfoId}) {
3846 return $Cache{"modelUnmangled"}{$Version}{$Compiler}{$InfoId};
3847 }
3848 my $PureSignature = $SymbolInfo{$Version}{$InfoId}{"ShortName"};
3849 if($SymbolInfo{$Version}{$InfoId}{"Destructor"}) {
3850 $PureSignature = "~".$PureSignature;
3851 }
3852 if(not $SymbolInfo{$Version}{$InfoId}{"Data"})
3853 {
3854 my (@Params, @ParamTypes) = ();
3855 if(defined $SymbolInfo{$Version}{$InfoId}{"Param"}
3856 and not $SymbolInfo{$Version}{$InfoId}{"Destructor"}) {
3857 @Params = keys(%{$SymbolInfo{$Version}{$InfoId}{"Param"}});
3858 }
3859 foreach my $ParamPos (sort {int($a) <=> int($b)} @Params)
3860 { # checking parameters
3861 my $PId = $SymbolInfo{$Version}{$InfoId}{"Param"}{$ParamPos}{"type"};
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +04003862 my %PType = get_PureType($PId, $TypeInfo{$Version});
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003863 my $PTName = unmangledFormat($PType{"Name"}, $Version);
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04003864 $PTName=~s/\b(restrict|register)\b//g;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003865 if($Compiler eq "MSVC") {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04003866 $PTName=~s/\blong long\b/__int64/;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003867 }
3868 @ParamTypes = (@ParamTypes, $PTName);
3869 }
3870 if(@ParamTypes) {
3871 $PureSignature .= "(".join(", ", @ParamTypes).")";
3872 }
3873 else
3874 {
3875 if($Compiler eq "MSVC")
3876 {
3877 $PureSignature .= "(void)";
3878 }
3879 else
3880 { # GCC
3881 $PureSignature .= "()";
3882 }
3883 }
3884 $PureSignature = delete_keywords($PureSignature);
3885 }
3886 if(my $ClassId = $SymbolInfo{$Version}{$InfoId}{"Class"})
3887 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04003888 my $ClassName = unmangledFormat($TypeInfo{$Version}{$ClassId}{"Name"}, $Version);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003889 $PureSignature = $ClassName."::".$PureSignature;
3890 }
3891 elsif(my $NS = $SymbolInfo{$Version}{$InfoId}{"NameSpace"}) {
3892 $PureSignature = $NS."::".$PureSignature;
3893 }
3894 if($SymbolInfo{$Version}{$InfoId}{"Const"}) {
3895 $PureSignature .= " const";
3896 }
3897 if($SymbolInfo{$Version}{$InfoId}{"Volatile"}) {
3898 $PureSignature .= " volatile";
3899 }
3900 my $ShowReturn = 0;
3901 if($Compiler eq "MSVC"
3902 and $SymbolInfo{$Version}{$InfoId}{"Data"})
3903 {
3904 $ShowReturn=1;
3905 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04003906 elsif(defined $TemplateInstance{$Version}{"Func"}{$InfoId}
3907 and keys(%{$TemplateInstance{$Version}{"Func"}{$InfoId}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003908 {
3909 $ShowReturn=1;
3910 }
3911 if($ShowReturn)
3912 { # mangled names for template function specializations include return value
3913 if(my $ReturnId = $SymbolInfo{$Version}{$InfoId}{"Return"})
3914 {
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +04003915 my %RType = get_PureType($ReturnId, $TypeInfo{$Version});
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003916 my $ReturnName = unmangledFormat($RType{"Name"}, $Version);
3917 $PureSignature = $ReturnName." ".$PureSignature;
3918 }
3919 }
Andrey Ponomarenko9927e332012-10-19 10:50:48 +04003920 return ($Cache{"modelUnmangled"}{$Version}{$Compiler}{$InfoId} = formatName($PureSignature, "S"));
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003921}
3922
3923sub mangle_symbol($$$)
3924{ # mangling for simple methods
3925 # see gcc-4.6.0/gcc/cp/mangle.c
3926 my ($InfoId, $LibVersion, $Compiler) = @_;
3927 if($Cache{"mangle_symbol"}{$LibVersion}{$InfoId}{$Compiler}) {
3928 return $Cache{"mangle_symbol"}{$LibVersion}{$InfoId}{$Compiler};
3929 }
3930 my $Mangled = "";
3931 if($Compiler eq "GCC") {
Andrey Ponomarenko16934472012-03-29 15:37:04 +04003932 $Mangled = mangle_symbol_GCC($InfoId, $LibVersion);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003933 }
3934 elsif($Compiler eq "MSVC") {
Andrey Ponomarenko16934472012-03-29 15:37:04 +04003935 $Mangled = mangle_symbol_MSVC($InfoId, $LibVersion);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003936 }
3937 return ($Cache{"mangle_symbol"}{$LibVersion}{$InfoId}{$Compiler} = $Mangled);
3938}
3939
Andrey Ponomarenko16934472012-03-29 15:37:04 +04003940sub mangle_symbol_MSVC($$)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003941{
3942 my ($InfoId, $LibVersion) = @_;
3943 return "";
3944}
3945
Andrey Ponomarenko16934472012-03-29 15:37:04 +04003946sub mangle_symbol_GCC($$)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003947{ # see gcc-4.6.0/gcc/cp/mangle.c
3948 my ($InfoId, $LibVersion) = @_;
3949 my ($Mangled, $ClassId, $NameSpace) = ("_Z", 0, "");
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04003950 my $Return = $SymbolInfo{$LibVersion}{$InfoId}{"Return"};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003951 my %Repl = ();# SN_ replacements
3952 if($ClassId = $SymbolInfo{$LibVersion}{$InfoId}{"Class"})
3953 {
3954 my $MangledClass = mangle_param($ClassId, $LibVersion, \%Repl);
3955 if($MangledClass!~/\AN/) {
3956 $MangledClass = "N".$MangledClass;
3957 }
3958 else {
3959 $MangledClass=~s/E\Z//;
3960 }
3961 if($SymbolInfo{$LibVersion}{$InfoId}{"Volatile"}) {
3962 $MangledClass=~s/\AN/NV/;
3963 }
3964 if($SymbolInfo{$LibVersion}{$InfoId}{"Const"}) {
3965 $MangledClass=~s/\AN/NK/;
3966 }
3967 $Mangled .= $MangledClass;
3968 }
3969 elsif($NameSpace = $SymbolInfo{$LibVersion}{$InfoId}{"NameSpace"})
3970 { # mangled by name due to the absence of structured info
3971 my $MangledNS = mangle_ns($NameSpace, $LibVersion, \%Repl);
3972 if($MangledNS!~/\AN/) {
3973 $MangledNS = "N".$MangledNS;
3974 }
3975 else {
3976 $MangledNS=~s/E\Z//;
3977 }
3978 $Mangled .= $MangledNS;
3979 }
Andrey Ponomarenko07aea072012-11-12 16:15:07 +04003980 my ($ShortName, $TmplParams) = template_Base($SymbolInfo{$LibVersion}{$InfoId}{"ShortName"});
Andrey Ponomarenko16934472012-03-29 15:37:04 +04003981 my @TParams = ();
Andrey Ponomarenko35c44fd2012-06-18 17:50:25 +04003982 if(my @TPos = keys(%{$SymbolInfo{$LibVersion}{$InfoId}{"TParam"}}))
Andrey Ponomarenko16934472012-03-29 15:37:04 +04003983 { # parsing mode
Andrey Ponomarenko35c44fd2012-06-18 17:50:25 +04003984 foreach (@TPos) {
3985 push(@TParams, $SymbolInfo{$LibVersion}{$InfoId}{"TParam"}{$_}{"name"});
3986 }
Andrey Ponomarenko16934472012-03-29 15:37:04 +04003987 }
3988 elsif($TmplParams)
3989 { # remangling mode
3990 # support for old ABI dumps
Andrey Ponomarenko07aea072012-11-12 16:15:07 +04003991 @TParams = separate_Params($TmplParams, 0, 0);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003992 }
3993 if($SymbolInfo{$LibVersion}{$InfoId}{"Constructor"}) {
3994 $Mangled .= "C1";
3995 }
3996 elsif($SymbolInfo{$LibVersion}{$InfoId}{"Destructor"}) {
3997 $Mangled .= "D0";
3998 }
3999 elsif($ShortName)
4000 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04004001 if($SymbolInfo{$LibVersion}{$InfoId}{"Data"})
4002 {
Andrey Ponomarenko16934472012-03-29 15:37:04 +04004003 if(not $SymbolInfo{$LibVersion}{$InfoId}{"Class"}
Andrey Ponomarenko85043792012-05-14 16:48:07 +04004004 and isConstType($Return, $LibVersion))
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04004005 { # "const" global data is mangled as _ZL...
4006 $Mangled .= "L";
4007 }
4008 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004009 if($ShortName=~/\Aoperator(\W.*)\Z/)
4010 {
4011 my $Op = $1;
4012 $Op=~s/\A[ ]+//g;
4013 if(my $OpMngl = $OperatorMangling{$Op}) {
4014 $Mangled .= $OpMngl;
4015 }
4016 else { # conversion operator
4017 $Mangled .= "cv".mangle_param(getTypeIdByName($Op, $LibVersion), $LibVersion, \%Repl);
4018 }
4019 }
4020 else {
4021 $Mangled .= length($ShortName).$ShortName;
4022 }
4023 if(@TParams)
4024 { # templates
4025 $Mangled .= "I";
Andrey Ponomarenko1477d2c2012-11-12 18:55:45 +04004026 foreach my $TParam (@TParams) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004027 $Mangled .= mangle_template_param($TParam, $LibVersion, \%Repl);
4028 }
4029 $Mangled .= "E";
4030 }
4031 if(not $ClassId and @TParams) {
4032 add_substitution($ShortName, \%Repl, 0);
4033 }
4034 }
4035 if($ClassId or $NameSpace) {
4036 $Mangled .= "E";
4037 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +04004038 if(@TParams)
4039 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04004040 if($Return) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004041 $Mangled .= mangle_param($Return, $LibVersion, \%Repl);
4042 }
4043 }
4044 if(not $SymbolInfo{$LibVersion}{$InfoId}{"Data"})
4045 {
4046 my @Params = ();
4047 if(defined $SymbolInfo{$LibVersion}{$InfoId}{"Param"}
4048 and not $SymbolInfo{$LibVersion}{$InfoId}{"Destructor"}) {
4049 @Params = keys(%{$SymbolInfo{$LibVersion}{$InfoId}{"Param"}});
4050 }
4051 foreach my $ParamPos (sort {int($a) <=> int($b)} @Params)
4052 { # checking parameters
4053 my $ParamType_Id = $SymbolInfo{$LibVersion}{$InfoId}{"Param"}{$ParamPos}{"type"};
4054 $Mangled .= mangle_param($ParamType_Id, $LibVersion, \%Repl);
4055 }
4056 if(not @Params) {
4057 $Mangled .= "v";
4058 }
4059 }
4060 $Mangled = correct_incharge($InfoId, $LibVersion, $Mangled);
4061 $Mangled = write_stdcxx_substitution($Mangled);
4062 if($Mangled eq "_Z") {
4063 return "";
4064 }
4065 return $Mangled;
4066}
4067
4068sub correct_incharge($$$)
4069{
4070 my ($InfoId, $LibVersion, $Mangled) = @_;
4071 if($SymbolInfo{$LibVersion}{$InfoId}{"Constructor"})
4072 {
4073 if($MangledNames{$LibVersion}{$Mangled}) {
4074 $Mangled=~s/C1E/C2E/;
4075 }
4076 }
4077 elsif($SymbolInfo{$LibVersion}{$InfoId}{"Destructor"})
4078 {
4079 if($MangledNames{$LibVersion}{$Mangled}) {
4080 $Mangled=~s/D0E/D1E/;
4081 }
4082 if($MangledNames{$LibVersion}{$Mangled}) {
4083 $Mangled=~s/D1E/D2E/;
4084 }
4085 }
4086 return $Mangled;
4087}
4088
Andrey Ponomarenko07aea072012-11-12 16:15:07 +04004089sub template_Base($)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004090{ # NOTE: std::_Vector_base<mysqlpp::mysql_type_info>::_Vector_impl
Andrey Ponomarenko16934472012-03-29 15:37:04 +04004091 # NOTE: operators: >>, <<
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004092 my $Name = $_[0];
Andrey Ponomarenko16934472012-03-29 15:37:04 +04004093 if($Name!~/>\Z/ or $Name!~/</) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004094 return $Name;
4095 }
4096 my $TParams = $Name;
Andrey Ponomarenko16934472012-03-29 15:37:04 +04004097 while(my $CPos = find_center($TParams, "<"))
4098 { # search for the last <T>
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004099 $TParams = substr($TParams, $CPos);
4100 }
Andrey Ponomarenko16934472012-03-29 15:37:04 +04004101 if($TParams=~s/\A<(.+)>\Z/$1/) {
4102 $Name=~s/<\Q$TParams\E>\Z//;
4103 }
4104 else
4105 { # error
4106 $TParams = "";
4107 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004108 return ($Name, $TParams);
4109}
4110
4111sub get_sub_ns($)
4112{
4113 my $Name = $_[0];
4114 my @NS = ();
Andrey Ponomarenko16934472012-03-29 15:37:04 +04004115 while(my $CPos = find_center($Name, ":"))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004116 {
4117 push(@NS, substr($Name, 0, $CPos));
4118 $Name = substr($Name, $CPos);
4119 $Name=~s/\A:://;
4120 }
4121 return (join("::", @NS), $Name);
4122}
4123
4124sub mangle_ns($$$)
4125{
4126 my ($Name, $LibVersion, $Repl) = @_;
4127 if(my $Tid = $TName_Tid{$LibVersion}{$Name})
4128 {
4129 my $Mangled = mangle_param($Tid, $LibVersion, $Repl);
4130 $Mangled=~s/\AN(.+)E\Z/$1/;
4131 return $Mangled;
4132
4133 }
4134 else
4135 {
4136 my ($MangledNS, $SubNS) = ("", "");
4137 ($SubNS, $Name) = get_sub_ns($Name);
4138 if($SubNS) {
4139 $MangledNS .= mangle_ns($SubNS, $LibVersion, $Repl);
4140 }
4141 $MangledNS .= length($Name).$Name;
4142 add_substitution($MangledNS, $Repl, 0);
4143 return $MangledNS;
4144 }
4145}
4146
4147sub mangle_param($$$)
4148{
4149 my ($PTid, $LibVersion, $Repl) = @_;
4150 my ($MPrefix, $Mangled) = ("", "");
4151 my %ReplCopy = %{$Repl};
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04004152 my %BaseType = get_BaseType($PTid, $LibVersion);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004153 my $BaseType_Name = $BaseType{"Name"};
4154 if(not $BaseType_Name) {
4155 return "";
4156 }
Andrey Ponomarenko07aea072012-11-12 16:15:07 +04004157 my ($ShortName, $TmplParams) = template_Base($BaseType_Name);
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04004158 my $Suffix = get_BaseTypeQual($PTid, $LibVersion);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004159 while($Suffix=~s/\s*(const|volatile|restrict)\Z//g){};
4160 while($Suffix=~/(&|\*|const)\Z/)
4161 {
4162 if($Suffix=~s/[ ]*&\Z//) {
4163 $MPrefix .= "R";
4164 }
4165 if($Suffix=~s/[ ]*\*\Z//) {
4166 $MPrefix .= "P";
4167 }
4168 if($Suffix=~s/[ ]*const\Z//)
4169 {
4170 if($MPrefix=~/R|P/
4171 or $Suffix=~/&|\*/) {
4172 $MPrefix .= "K";
4173 }
4174 }
4175 if($Suffix=~s/[ ]*volatile\Z//) {
4176 $MPrefix .= "V";
4177 }
4178 #if($Suffix=~s/[ ]*restrict\Z//) {
4179 #$MPrefix .= "r";
4180 #}
4181 }
4182 if(my $Token = $IntrinsicMangling{$BaseType_Name}) {
4183 $Mangled .= $Token;
4184 }
4185 elsif($BaseType{"Type"}=~/(Class|Struct|Union|Enum)/)
4186 {
Andrey Ponomarenko16934472012-03-29 15:37:04 +04004187 my @TParams = ();
Andrey Ponomarenko35c44fd2012-06-18 17:50:25 +04004188 if(my @TPos = keys(%{$BaseType{"TParam"}}))
Andrey Ponomarenko16934472012-03-29 15:37:04 +04004189 { # parsing mode
Andrey Ponomarenko35c44fd2012-06-18 17:50:25 +04004190 foreach (@TPos) {
4191 push(@TParams, $BaseType{"TParam"}{$_}{"name"});
4192 }
Andrey Ponomarenko16934472012-03-29 15:37:04 +04004193 }
4194 elsif($TmplParams)
4195 { # remangling mode
4196 # support for old ABI dumps
Andrey Ponomarenko07aea072012-11-12 16:15:07 +04004197 @TParams = separate_Params($TmplParams, 0, 0);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004198 }
4199 my $MangledNS = "";
4200 my ($SubNS, $SName) = get_sub_ns($ShortName);
4201 if($SubNS) {
4202 $MangledNS .= mangle_ns($SubNS, $LibVersion, $Repl);
4203 }
4204 $MangledNS .= length($SName).$SName;
4205 if(@TParams) {
4206 add_substitution($MangledNS, $Repl, 0);
4207 }
4208 $Mangled .= "N".$MangledNS;
4209 if(@TParams)
4210 { # templates
4211 $Mangled .= "I";
4212 foreach my $TParam (@TParams) {
4213 $Mangled .= mangle_template_param($TParam, $LibVersion, $Repl);
4214 }
4215 $Mangled .= "E";
4216 }
4217 $Mangled .= "E";
4218 }
4219 elsif($BaseType{"Type"}=~/(FuncPtr|MethodPtr)/)
4220 {
4221 if($BaseType{"Type"} eq "MethodPtr") {
4222 $Mangled .= "M".mangle_param($BaseType{"Class"}, $LibVersion, $Repl)."F";
4223 }
4224 else {
4225 $Mangled .= "PF";
4226 }
4227 $Mangled .= mangle_param($BaseType{"Return"}, $LibVersion, $Repl);
4228 my @Params = keys(%{$BaseType{"Param"}});
4229 foreach my $Num (sort {int($a)<=>int($b)} @Params) {
4230 $Mangled .= mangle_param($BaseType{"Param"}{$Num}{"type"}, $LibVersion, $Repl);
4231 }
4232 if(not @Params) {
4233 $Mangled .= "v";
4234 }
4235 $Mangled .= "E";
4236 }
4237 elsif($BaseType{"Type"} eq "FieldPtr")
4238 {
4239 $Mangled .= "M".mangle_param($BaseType{"Class"}, $LibVersion, $Repl);
4240 $Mangled .= mangle_param($BaseType{"Return"}, $LibVersion, $Repl);
4241 }
4242 $Mangled = $MPrefix.$Mangled;# add prefix (RPK)
4243 if(my $Optimized = write_substitution($Mangled, \%ReplCopy))
4244 {
4245 if($Mangled eq $Optimized)
4246 {
4247 if($ShortName!~/::/)
4248 { # remove "N ... E"
4249 if($MPrefix) {
4250 $Mangled=~s/\A($MPrefix)N(.+)E\Z/$1$2/g;
4251 }
4252 else {
4253 $Mangled=~s/\AN(.+)E\Z/$1/g;
4254 }
4255 }
4256 }
4257 else {
4258 $Mangled = $Optimized;
4259 }
4260 }
4261 add_substitution($Mangled, $Repl, 1);
4262 return $Mangled;
4263}
4264
4265sub mangle_template_param($$$)
4266{ # types + literals
4267 my ($TParam, $LibVersion, $Repl) = @_;
4268 if(my $TPTid = $TName_Tid{$LibVersion}{$TParam}) {
4269 return mangle_param($TPTid, $LibVersion, $Repl);
4270 }
4271 elsif($TParam=~/\A(\d+)(\w+)\Z/)
4272 { # class_name<1u>::method(...)
4273 return "L".$IntrinsicMangling{$ConstantSuffixR{$2}}.$1."E";
4274 }
4275 elsif($TParam=~/\A\(([\w ]+)\)(\d+)\Z/)
4276 { # class_name<(signed char)1>::method(...)
4277 return "L".$IntrinsicMangling{$1}.$2."E";
4278 }
4279 elsif($TParam eq "true")
4280 { # class_name<true>::method(...)
4281 return "Lb1E";
4282 }
4283 elsif($TParam eq "false")
4284 { # class_name<true>::method(...)
4285 return "Lb0E";
4286 }
4287 else { # internal error
4288 return length($TParam).$TParam;
4289 }
4290}
4291
4292sub add_substitution($$$)
4293{
4294 my ($Value, $Repl, $Rec) = @_;
4295 if($Rec)
4296 { # subtypes
4297 my @Subs = ($Value);
4298 while($Value=~s/\A(R|P|K)//) {
4299 push(@Subs, $Value);
4300 }
4301 foreach (reverse(@Subs)) {
4302 add_substitution($_, $Repl, 0);
4303 }
4304 return;
4305 }
4306 return if($Value=~/\AS(\d*)_\Z/);
4307 $Value=~s/\AN(.+)E\Z/$1/g;
4308 return if(defined $Repl->{$Value});
4309 return if(length($Value)<=1);
4310 return if($StdcxxMangling{$Value});
4311 # check for duplicates
4312 my $Base = $Value;
4313 foreach my $Type (sort {$Repl->{$a}<=>$Repl->{$b}} sort keys(%{$Repl}))
4314 {
4315 my $Num = $Repl->{$Type};
4316 my $Replace = macro_mangle($Num);
4317 $Base=~s/\Q$Replace\E/$Type/;
4318 }
4319 if(my $OldNum = $Repl->{$Base})
4320 {
4321 $Repl->{$Value} = $OldNum;
4322 return;
4323 }
4324 my @Repls = sort {$b<=>$a} values(%{$Repl});
4325 if(@Repls) {
4326 $Repl->{$Value} = $Repls[0]+1;
4327 }
4328 else {
4329 $Repl->{$Value} = -1;
4330 }
4331 # register duplicates
4332 # upward
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04004333 $Base = $Value;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004334 foreach my $Type (sort {$Repl->{$a}<=>$Repl->{$b}} sort keys(%{$Repl}))
4335 {
4336 next if($Base eq $Type);
4337 my $Num = $Repl->{$Type};
4338 my $Replace = macro_mangle($Num);
4339 $Base=~s/\Q$Type\E/$Replace/;
4340 $Repl->{$Base} = $Repl->{$Value};
4341 }
4342}
4343
4344sub macro_mangle($)
4345{
4346 my $Num = $_[0];
4347 if($Num==-1) {
4348 return "S_";
4349 }
4350 else
4351 {
4352 my $Code = "";
4353 if($Num<10)
4354 { # S0_, S1_, S2_, ...
4355 $Code = $Num;
4356 }
4357 elsif($Num>=10 and $Num<=35)
4358 { # SA_, SB_, SC_, ...
4359 $Code = chr(55+$Num);
4360 }
4361 else
4362 { # S10_, S11_, S12_
4363 $Code = $Num-26; # 26 is length of english alphabet
4364 }
4365 return "S".$Code."_";
4366 }
4367}
4368
4369sub write_stdcxx_substitution($)
4370{
4371 my $Mangled = $_[0];
4372 if($StdcxxMangling{$Mangled}) {
4373 return $StdcxxMangling{$Mangled};
4374 }
4375 else
4376 {
4377 my @Repls = keys(%StdcxxMangling);
4378 @Repls = sort {length($b)<=>length($a)} sort {$b cmp $a} @Repls;
4379 foreach my $MangledType (@Repls)
4380 {
4381 my $Replace = $StdcxxMangling{$MangledType};
4382 #if($Mangled!~/$Replace/) {
4383 $Mangled=~s/N\Q$MangledType\EE/$Replace/g;
4384 $Mangled=~s/\Q$MangledType\E/$Replace/g;
4385 #}
4386 }
4387 }
4388 return $Mangled;
4389}
4390
4391sub write_substitution($$)
4392{
4393 my ($Mangled, $Repl) = @_;
4394 if(defined $Repl->{$Mangled}
4395 and my $MnglNum = $Repl->{$Mangled}) {
4396 $Mangled = macro_mangle($MnglNum);
4397 }
4398 else
4399 {
4400 my @Repls = keys(%{$Repl});
4401 #@Repls = sort {$Repl->{$a}<=>$Repl->{$b}} @Repls;
4402 # FIXME: how to apply replacements? by num or by pos
4403 @Repls = sort {length($b)<=>length($a)} sort {$b cmp $a} @Repls;
4404 foreach my $MangledType (@Repls)
4405 {
4406 my $Replace = macro_mangle($Repl->{$MangledType});
4407 if($Mangled!~/$Replace/) {
4408 $Mangled=~s/N\Q$MangledType\EE/$Replace/g;
4409 $Mangled=~s/\Q$MangledType\E/$Replace/g;
4410 }
4411 }
4412 }
4413 return $Mangled;
4414}
4415
4416sub delete_keywords($)
4417{
4418 my $TypeName = $_[0];
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04004419 $TypeName=~s/\b(enum|struct|union|class) //g;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004420 return $TypeName;
4421}
4422
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004423sub uncover_typedefs($$)
4424{
4425 my ($TypeName, $LibVersion) = @_;
4426 return "" if(not $TypeName);
4427 if(defined $Cache{"uncover_typedefs"}{$LibVersion}{$TypeName}) {
4428 return $Cache{"uncover_typedefs"}{$LibVersion}{$TypeName};
4429 }
Andrey Ponomarenko9927e332012-10-19 10:50:48 +04004430 my ($TypeName_New, $TypeName_Pre) = (formatName($TypeName, "T"), "");
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004431 while($TypeName_New ne $TypeName_Pre)
4432 {
4433 $TypeName_Pre = $TypeName_New;
4434 my $TypeName_Copy = $TypeName_New;
4435 my %Words = ();
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04004436 while($TypeName_Copy=~s/\b([a-z_]([\w:]*\w|))\b//io)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004437 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04004438 if(not $Intrinsic_Keywords{$1}) {
4439 $Words{$1} = 1;
4440 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004441 }
4442 foreach my $Word (keys(%Words))
4443 {
4444 my $BaseType_Name = $Typedef_BaseName{$LibVersion}{$Word};
4445 next if(not $BaseType_Name);
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04004446 next if($TypeName_New=~/\b(struct|union|enum)\s\Q$Word\E\b/);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004447 if($BaseType_Name=~/\([\*]+\)/)
4448 { # FuncPtr
4449 if($TypeName_New=~/\Q$Word\E(.*)\Z/)
4450 {
4451 my $Type_Suffix = $1;
4452 $TypeName_New = $BaseType_Name;
4453 if($TypeName_New=~s/\(([\*]+)\)/($1 $Type_Suffix)/) {
Andrey Ponomarenko9927e332012-10-19 10:50:48 +04004454 $TypeName_New = formatName($TypeName_New, "T");
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004455 }
4456 }
4457 }
4458 else
4459 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04004460 if($TypeName_New=~s/\b\Q$Word\E\b/$BaseType_Name/g) {
Andrey Ponomarenko9927e332012-10-19 10:50:48 +04004461 $TypeName_New = formatName($TypeName_New, "T");
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004462 }
4463 }
4464 }
4465 }
4466 return ($Cache{"uncover_typedefs"}{$LibVersion}{$TypeName} = $TypeName_New);
4467}
4468
4469sub isInternal($)
4470{
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04004471 if($_[0] and my $Info = $LibInfo{$Version}{"info"}{$_[0]})
4472 {
4473 if($Info=~/mngl[ ]*:[ ]*@(\d+) /)
4474 {
4475 if($LibInfo{$Version}{"info"}{$1}=~/\*[ ]*INTERNAL[ ]*\*/)
4476 { # _ZN7mysqlpp8DateTimeC1ERKS0_ *INTERNAL*
4477 return 1;
4478 }
4479 }
4480 }
4481 return 0;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004482}
4483
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04004484sub getDataVal($$)
4485{
4486 my ($InfoId, $TypeId) = @_;
4487 if(my $Info = $LibInfo{$Version}{"info"}{$InfoId})
4488 {
4489 if($Info=~/init[ ]*:[ ]*@(\d+) /)
4490 {
4491 if(defined $LibInfo{$Version}{"info_type"}{$1}
4492 and $LibInfo{$Version}{"info_type"}{$1} eq "nop_expr")
4493 { # char const* data = "str"
4494 # NOTE: disabled
4495 if(my $NopExpr = $LibInfo{$Version}{"info"}{$1})
4496 {
4497 if($NopExpr=~/op 0[ ]*:[ ]*@(\d+) /)
4498 {
4499 if(defined $LibInfo{$Version}{"info_type"}{$1}
4500 and $LibInfo{$Version}{"info_type"}{$1} eq "addr_expr")
4501 {
4502 if(my $AddrExpr = $LibInfo{$Version}{"info"}{$1})
4503 {
4504 if($AddrExpr=~/op 0[ ]*:[ ]*@(\d+) /)
4505 {
4506 return getInitVal($1, $TypeId);
4507 }
4508 }
4509 }
4510 }
4511 }
4512 }
4513 else {
4514 return getInitVal($1, $TypeId);
4515 }
4516 }
4517 }
4518 return undef;
4519}
4520
4521sub getInitVal($$)
4522{
4523 my ($InfoId, $TypeId) = @_;
4524 if(my $Info = $LibInfo{$Version}{"info"}{$InfoId})
4525 {
4526 if(my $InfoType = $LibInfo{$Version}{"info_type"}{$InfoId})
4527 {
4528 if($InfoType eq "integer_cst")
4529 {
4530 my $Val = getNodeIntCst($InfoId);
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04004531 if($TypeId and $TypeInfo{$Version}{$TypeId}{"Name"}=~/\Achar(| const)\Z/)
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04004532 { # characters
4533 $Val = chr($Val);
4534 }
4535 return $Val;
4536 }
4537 elsif($InfoType eq "string_cst") {
4538 return getNodeStrCst($InfoId);
4539 }
Andrey Ponomarenko01117f12012-06-26 12:23:02 +04004540 elsif($InfoType eq "var_decl")
4541 {
4542 if(my $Name = getNodeStrCst(getTreeAttr_Mngl($InfoId))) {
4543 return $Name;
4544 }
4545 }
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04004546 }
4547 }
4548 return undef;
4549}
4550
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004551sub set_Class_And_Namespace($)
4552{
4553 my $InfoId = $_[0];
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04004554 if(my $Info = $LibInfo{$Version}{"info"}{$InfoId})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004555 {
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04004556 if($Info=~/scpe[ ]*:[ ]*@(\d+) /)
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04004557 {
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04004558 my $NSInfoId = $1;
4559 if(my $InfoType = $LibInfo{$Version}{"info_type"}{$NSInfoId})
4560 {
4561 if($InfoType eq "namespace_decl") {
4562 $SymbolInfo{$Version}{$InfoId}{"NameSpace"} = getNameSpace($InfoId);
4563 }
4564 elsif($InfoType eq "record_type") {
4565 $SymbolInfo{$Version}{$InfoId}{"Class"} = $NSInfoId;
4566 }
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04004567 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004568 }
4569 }
4570 if($SymbolInfo{$Version}{$InfoId}{"Class"}
4571 or $SymbolInfo{$Version}{$InfoId}{"NameSpace"})
4572 { # identify language
Andrey Ponomarenko570ece52012-11-30 16:36:44 +04004573 if($COMMON_LANGUAGE{$Version} ne "C++")
4574 {
4575 if(my $ShortName = $SymbolInfo{$Version}{$InfoId}{"ShortName"})
4576 {
4577 if(index($ShortName, "__")!=0)
4578 { # skip C++ symbols from pthread.h:
4579 # __pthread_cleanup_class, __restore, __defer, __setdoit, etc.
4580 setLanguage($Version, "C++");
4581 }
4582 }
4583 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004584 }
4585}
4586
4587sub debugType($$)
4588{
4589 my ($Tid, $LibVersion) = @_;
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04004590 my %Type = get_Type($Tid, $LibVersion);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004591 printMsg("INFO", Dumper(\%Type));
4592}
4593
4594sub debugMangling($)
4595{
4596 my $LibVersion = $_[0];
4597 my %Mangled = ();
4598 foreach my $InfoId (keys(%{$SymbolInfo{$LibVersion}}))
4599 {
4600 if(my $Mngl = $SymbolInfo{$LibVersion}{$InfoId}{"MnglName"})
4601 {
4602 if($Mngl=~/\A(_Z|\?)/) {
4603 $Mangled{$Mngl}=$InfoId;
4604 }
4605 }
4606 }
4607 translateSymbols(keys(%Mangled), $LibVersion);
4608 foreach my $Mngl (keys(%Mangled))
4609 {
Andrey Ponomarenko85043792012-05-14 16:48:07 +04004610 my $U1 = modelUnmangled($Mangled{$Mngl}, "GCC");
4611 my $U2 = $tr_name{$Mngl};
4612 if($U1 ne $U2) {
4613 printMsg("INFO", "INCORRECT MANGLING:\n $Mngl\n $U1\n $U2\n");
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004614 }
4615 }
4616}
4617
4618sub linkSymbol($)
4619{ # link symbols from shared libraries
4620 # with the symbols from header files
4621 my $InfoId = $_[0];
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004622 # try to mangle symbol
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04004623 if((not check_gcc($GCC_PATH, "4") and $SymbolInfo{$Version}{$InfoId}{"Class"})
4624 or (check_gcc($GCC_PATH, "4") and not $SymbolInfo{$Version}{$InfoId}{"Class"}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004625 { # 1. GCC 3.x doesn't mangle class methods names in the TU dump (only functions and global data)
4626 # 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 +04004627 if(not $CheckHeadersOnly)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004628 {
4629 if(my $Mangled = $mangled_name_gcc{modelUnmangled($InfoId, "GCC")}) {
4630 return correct_incharge($InfoId, $Version, $Mangled);
4631 }
4632 }
Andrey Ponomarenko16934472012-03-29 15:37:04 +04004633 if($CheckHeadersOnly
4634 or not $BinaryOnly)
4635 { # 1. --headers-only mode
4636 # 2. not mangled src-only symbols
4637 if(my $Mangled = mangle_symbol($InfoId, $Version, "GCC")) {
4638 return $Mangled;
4639 }
4640 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004641 }
4642 return "";
4643}
4644
4645sub setLanguage($$)
4646{
4647 my ($LibVersion, $Lang) = @_;
4648 if(not $UserLang) {
4649 $COMMON_LANGUAGE{$LibVersion} = $Lang;
4650 }
4651}
4652
4653sub getSymbolInfo($)
4654{
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04004655 my $InfoId = $_[0];
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04004656 if(isInternal($InfoId)) {
4657 return;
4658 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04004659 ($SymbolInfo{$Version}{$InfoId}{"Header"}, $SymbolInfo{$Version}{$InfoId}{"Line"}) = getLocation($InfoId);
4660 if(not $SymbolInfo{$Version}{$InfoId}{"Header"}
Andrey Ponomarenkoa01311b2012-06-08 17:20:02 +04004661 or isBuiltIn($SymbolInfo{$Version}{$InfoId}{"Header"}))
4662 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04004663 delete($SymbolInfo{$Version}{$InfoId});
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004664 return;
4665 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04004666 setFuncAccess($InfoId);
4667 setFuncKind($InfoId);
Andrey Ponomarenkoa01311b2012-06-08 17:20:02 +04004668 if($SymbolInfo{$Version}{$InfoId}{"PseudoTemplate"})
4669 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04004670 delete($SymbolInfo{$Version}{$InfoId});
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004671 return;
4672 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04004673 $SymbolInfo{$Version}{$InfoId}{"Type"} = getFuncType($InfoId);
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04004674 if($SymbolInfo{$Version}{$InfoId}{"Return"} = getFuncReturn($InfoId))
4675 {
4676 if(not $TypeInfo{$Version}{$SymbolInfo{$Version}{$InfoId}{"Return"}}{"Name"})
4677 { # templates
4678 delete($SymbolInfo{$Version}{$InfoId});
4679 return;
4680 }
4681 }
4682 if(my $Rid = $SymbolInfo{$Version}{$InfoId}{"Return"})
4683 {
4684 if(defined $MissedTypedef{$Version}{$Rid})
4685 {
4686 if(my $AddedTid = $MissedTypedef{$Version}{$Rid}{"Tid"}) {
4687 $SymbolInfo{$Version}{$InfoId}{"Return"} = $AddedTid;
4688 }
4689 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004690 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04004691 if(not $SymbolInfo{$Version}{$InfoId}{"Return"}) {
4692 delete($SymbolInfo{$Version}{$InfoId}{"Return"});
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004693 }
Andrey Ponomarenkoa01311b2012-06-08 17:20:02 +04004694 my $Orig = getFuncOrig($InfoId);
4695 $SymbolInfo{$Version}{$InfoId}{"ShortName"} = getFuncShortName($Orig);
4696 if($SymbolInfo{$Version}{$InfoId}{"ShortName"}=~/\._/)
4697 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04004698 delete($SymbolInfo{$Version}{$InfoId});
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004699 return;
4700 }
Andrey Ponomarenkoa01311b2012-06-08 17:20:02 +04004701
4702 if(defined $TemplateInstance{$Version}{"Func"}{$Orig})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004703 {
Andrey Ponomarenkoa01311b2012-06-08 17:20:02 +04004704 my @TParams = getTParams($Orig, "Func");
4705 if(not @TParams)
4706 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04004707 delete($SymbolInfo{$Version}{$InfoId});
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004708 return;
4709 }
Andrey Ponomarenko16934472012-03-29 15:37:04 +04004710 foreach my $Pos (0 .. $#TParams) {
4711 $SymbolInfo{$Version}{$InfoId}{"TParam"}{$Pos}{"name"}=$TParams[$Pos];
4712 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004713 my $PrmsInLine = join(", ", @TParams);
Andrey Ponomarenko16934472012-03-29 15:37:04 +04004714 if($SymbolInfo{$Version}{$InfoId}{"ShortName"}=~/\Aoperator\W+\Z/)
4715 { # operator<< <T>, operator>> <T>
4716 $SymbolInfo{$Version}{$InfoId}{"ShortName"} .= " ";
4717 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04004718 $SymbolInfo{$Version}{$InfoId}{"ShortName"} .= "<".$PrmsInLine.">";
Andrey Ponomarenko9927e332012-10-19 10:50:48 +04004719 $SymbolInfo{$Version}{$InfoId}{"ShortName"} = formatName($SymbolInfo{$Version}{$InfoId}{"ShortName"}, "S");
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004720 }
4721 else
4722 { # support for GCC 3.4
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04004723 $SymbolInfo{$Version}{$InfoId}{"ShortName"}=~s/<.+>\Z//;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004724 }
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +04004725 if(my $MnglName = getTreeStr(getTreeAttr_Mngl($InfoId)))
4726 {
4727 if($OSgroup eq "windows")
4728 { # cut the offset
4729 $MnglName=~s/\@\d+\Z//g;
4730 }
4731 $SymbolInfo{$Version}{$InfoId}{"MnglName"} = $MnglName;
4732
4733 # NOTE: mangling of some symbols may change depending on GCC version
4734 # GCC 4.6: _ZN28QExplicitlySharedDataPointerI11QPixmapDataEC2IT_EERKS_IT_E
4735 # GCC 4.7: _ZN28QExplicitlySharedDataPointerI11QPixmapDataEC2ERKS1_
4736 }
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04004737
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04004738 if($SymbolInfo{$Version}{$InfoId}{"MnglName"}
Andrey Ponomarenko9927e332012-10-19 10:50:48 +04004739 and index($SymbolInfo{$Version}{$InfoId}{"MnglName"}, "_Z")!=0)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004740 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04004741 delete($SymbolInfo{$Version}{$InfoId});
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004742 return;
4743 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04004744 if(not $SymbolInfo{$Version}{$InfoId}{"Destructor"})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004745 { # destructors have an empty parameter list
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04004746 my $Skip = setFuncParams($InfoId);
Andrey Ponomarenko07aea072012-11-12 16:15:07 +04004747 if($Skip)
4748 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04004749 delete($SymbolInfo{$Version}{$InfoId});
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004750 return;
4751 }
4752 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04004753 set_Class_And_Namespace($InfoId);
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04004754 if(my $ClassId = $SymbolInfo{$Version}{$InfoId}{"Class"})
4755 {
4756 if(not $TypeInfo{$Version}{$ClassId}{"Name"})
4757 { # templates
4758 delete($SymbolInfo{$Version}{$InfoId});
4759 return;
4760 }
4761 }
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04004762 if(not $CheckHeadersOnly)
4763 {
4764 if($SymbolInfo{$Version}{$InfoId}{"Type"} eq "Function"
4765 and not $SymbolInfo{$Version}{$InfoId}{"Class"}
4766 and link_symbol($SymbolInfo{$Version}{$InfoId}{"ShortName"}, $Version, "-Deps"))
4767 { # functions (C++): not mangled in library, but are mangled in TU dump
4768 if(not $SymbolInfo{$Version}{$InfoId}{"MnglName"}
4769 or not link_symbol($SymbolInfo{$Version}{$InfoId}{"MnglName"}, $Version, "-Deps")) {
4770 $SymbolInfo{$Version}{$InfoId}{"MnglName"} = $SymbolInfo{$Version}{$InfoId}{"ShortName"};
4771 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004772 }
4773 }
Andrey Ponomarenko35c44fd2012-06-18 17:50:25 +04004774 if($LibInfo{$Version}{"info"}{$InfoId}=~/ lang:[ ]*C /i)
4775 { # extern "C"
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04004776 $SymbolInfo{$Version}{$InfoId}{"Lang"} = "C";
Andrey Ponomarenko35c44fd2012-06-18 17:50:25 +04004777 $SymbolInfo{$Version}{$InfoId}{"MnglName"} = $SymbolInfo{$Version}{$InfoId}{"ShortName"};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004778 }
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04004779 if($UserLang and $UserLang eq "C")
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004780 { # --lang=C option
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04004781 $SymbolInfo{$Version}{$InfoId}{"MnglName"} = $SymbolInfo{$Version}{$InfoId}{"ShortName"};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004782 }
4783 if($COMMON_LANGUAGE{$Version} eq "C++")
4784 { # correct mangled & short names
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04004785 # C++ or --headers-only mode
4786 if($SymbolInfo{$Version}{$InfoId}{"ShortName"}=~/\A__(comp|base|deleting)_(c|d)tor\Z/)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004787 { # support for old GCC versions: reconstruct real names for constructors and destructors
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04004788 $SymbolInfo{$Version}{$InfoId}{"ShortName"} = getNameByInfo(getTypeDeclId($SymbolInfo{$Version}{$InfoId}{"Class"}));
4789 $SymbolInfo{$Version}{$InfoId}{"ShortName"}=~s/<.+>\Z//;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004790 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04004791 if(not $SymbolInfo{$Version}{$InfoId}{"MnglName"})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004792 { # try to mangle symbol (link with libraries)
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04004793 if(my $Mangled = linkSymbol($InfoId)) {
4794 $SymbolInfo{$Version}{$InfoId}{"MnglName"} = $Mangled;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004795 }
4796 }
4797 if($OStarget eq "windows")
4798 { # link MS C++ symbols from library with GCC symbols from headers
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04004799 if(my $Mangled1 = $mangled_name{$Version}{modelUnmangled($InfoId, "MSVC")})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004800 { # exported symbols
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04004801 $SymbolInfo{$Version}{$InfoId}{"MnglName"} = $Mangled1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004802 }
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04004803 elsif(my $Mangled2 = mangle_symbol($InfoId, $Version, "MSVC"))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004804 { # pure virtual symbols
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04004805 $SymbolInfo{$Version}{$InfoId}{"MnglName"} = $Mangled2;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004806 }
4807 }
4808 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04004809 if(not $SymbolInfo{$Version}{$InfoId}{"MnglName"})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004810 { # can't detect symbol name
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04004811 delete($SymbolInfo{$Version}{$InfoId});
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004812 return;
4813 }
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04004814 if(not $SymbolInfo{$Version}{$InfoId}{"Constructor"}
Andrey Ponomarenkoa01311b2012-06-08 17:20:02 +04004815 and my $Spec = getVirtSpec($Orig))
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04004816 { # identify virtual and pure virtual functions
4817 # NOTE: constructors cannot be virtual
4818 # NOTE: in GCC 4.7 D1 destructors have no virtual spec
4819 # in the TU dump, so taking it from the original symbol
4820 if(not ($SymbolInfo{$Version}{$InfoId}{"Destructor"}
4821 and $SymbolInfo{$Version}{$InfoId}{"MnglName"}=~/D2E/))
4822 { # NOTE: D2 destructors are not present in a v-table
4823 $SymbolInfo{$Version}{$InfoId}{$Spec} = 1;
4824 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004825 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04004826 if(isInline($InfoId)) {
4827 $SymbolInfo{$Version}{$InfoId}{"InLine"} = 1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004828 }
Andrey Ponomarenko82bc2572012-11-14 13:55:30 +04004829 if(hasThrow($InfoId)) {
Andrey Ponomarenkoe3d6bf02012-11-14 11:49:09 +04004830 $SymbolInfo{$Version}{$InfoId}{"Throw"} = 1;
4831 }
Andrey Ponomarenkob8d203d2012-05-25 18:11:07 +04004832 if($LibInfo{$Version}{"info"}{$InfoId}=~/ artificial /i) {
4833 $SymbolInfo{$Version}{$InfoId}{"Artificial"} = 1;
4834 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04004835 if($SymbolInfo{$Version}{$InfoId}{"Constructor"}
4836 and my $ClassId = $SymbolInfo{$Version}{$InfoId}{"Class"})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004837 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04004838 if(not $SymbolInfo{$Version}{$InfoId}{"InLine"}
Andrey Ponomarenkob8d203d2012-05-25 18:11:07 +04004839 and not $SymbolInfo{$Version}{$InfoId}{"Artificial"})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004840 { # inline or auto-generated constructor
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04004841 delete($TypeInfo{$Version}{$ClassId}{"Copied"});
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004842 }
4843 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +04004844 if(my $Symbol = $SymbolInfo{$Version}{$InfoId}{"MnglName"})
4845 {
Andrey Ponomarenko570ece52012-11-30 16:36:44 +04004846 if(not $ExtraDump)
4847 {
4848 if(not selectSymbol($Symbol, $SymbolInfo{$Version}{$InfoId}, "Dump", $Version))
4849 { # non-target symbols
4850 delete($SymbolInfo{$Version}{$InfoId});
4851 return;
4852 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +04004853 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004854 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04004855 if($SymbolInfo{$Version}{$InfoId}{"Type"} eq "Method"
4856 or $SymbolInfo{$Version}{$InfoId}{"Constructor"}
4857 or $SymbolInfo{$Version}{$InfoId}{"Destructor"}
4858 or $SymbolInfo{$Version}{$InfoId}{"Class"})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004859 {
Andrey Ponomarenko9927e332012-10-19 10:50:48 +04004860 if($SymbolInfo{$Version}{$InfoId}{"MnglName"}!~/\A(_Z|\?)/)
4861 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04004862 delete($SymbolInfo{$Version}{$InfoId});
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004863 return;
4864 }
4865 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04004866 if($SymbolInfo{$Version}{$InfoId}{"MnglName"})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004867 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04004868 if($MangledNames{$Version}{$SymbolInfo{$Version}{$InfoId}{"MnglName"}})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004869 { # one instance for one mangled name only
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04004870 delete($SymbolInfo{$Version}{$InfoId});
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004871 return;
4872 }
4873 else {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04004874 $MangledNames{$Version}{$SymbolInfo{$Version}{$InfoId}{"MnglName"}} = 1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004875 }
4876 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04004877 if($SymbolInfo{$Version}{$InfoId}{"Constructor"}
4878 or $SymbolInfo{$Version}{$InfoId}{"Destructor"}) {
4879 delete($SymbolInfo{$Version}{$InfoId}{"Return"});
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004880 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04004881 if($SymbolInfo{$Version}{$InfoId}{"MnglName"}=~/\A(_Z|\?)/
4882 and $SymbolInfo{$Version}{$InfoId}{"Class"})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004883 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04004884 if($SymbolInfo{$Version}{$InfoId}{"Type"} eq "Function")
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004885 { # static methods
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04004886 $SymbolInfo{$Version}{$InfoId}{"Static"} = 1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004887 }
4888 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04004889 if(getFuncLink($InfoId) eq "Static") {
4890 $SymbolInfo{$Version}{$InfoId}{"Static"} = 1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004891 }
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04004892 if($SymbolInfo{$Version}{$InfoId}{"MnglName"}=~/\A(_Z|\?)/)
4893 {
4894 if(my $Unmangled = $tr_name{$SymbolInfo{$Version}{$InfoId}{"MnglName"}})
4895 {
Andrey Ponomarenko9927e332012-10-19 10:50:48 +04004896 if($Unmangled=~/\.\_\d/)
4897 {
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04004898 delete($SymbolInfo{$Version}{$InfoId});
4899 return;
4900 }
4901 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004902 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04004903 delete($SymbolInfo{$Version}{$InfoId}{"Type"});
4904 if($SymbolInfo{$Version}{$InfoId}{"MnglName"}=~/\A_ZN(V|)K/) {
4905 $SymbolInfo{$Version}{$InfoId}{"Const"} = 1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004906 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04004907 if($SymbolInfo{$Version}{$InfoId}{"MnglName"}=~/\A_ZN(K|)V/) {
4908 $SymbolInfo{$Version}{$InfoId}{"Volatile"} = 1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004909 }
Andrey Ponomarenko07aea072012-11-12 16:15:07 +04004910
4911 if($WeakSymbols{$Version}{$SymbolInfo{$Version}{$InfoId}{"MnglName"}}) {
4912 $SymbolInfo{$Version}{$InfoId}{"Weak"} = 1;
4913 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004914}
4915
4916sub isInline($)
4917{ # "body: undefined" in the tree
4918 # -fkeep-inline-functions GCC option should be specified
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04004919 if($_[0] and my $Info = $LibInfo{$Version}{"info"}{$_[0]})
4920 {
4921 if($Info=~/ undefined /i) {
4922 return 0;
4923 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004924 }
4925 return 1;
4926}
4927
Andrey Ponomarenkoe3d6bf02012-11-14 11:49:09 +04004928sub hasThrow($)
4929{
4930 if($_[0] and my $Info = $LibInfo{$Version}{"info"}{$_[0]})
4931 {
4932 if($Info=~/type[ ]*:[ ]*@(\d+) /) {
4933 return getTreeAttr_Unql($1, "unql");
4934 }
4935 }
4936 return 1;
4937}
4938
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004939sub getTypeId($)
4940{
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04004941 if($_[0] and my $Info = $LibInfo{$Version}{"info"}{$_[0]})
4942 {
4943 if($Info=~/type[ ]*:[ ]*@(\d+) /) {
4944 return $1;
4945 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004946 }
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04004947 return "";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004948}
4949
4950sub setTypeMemb($$)
4951{
4952 my ($TypeId, $TypeAttr) = @_;
4953 my $TypeType = $TypeAttr->{"Type"};
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04004954 my ($Pos, $UnnamedPos) = (0, 0);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004955 if($TypeType eq "Enum")
4956 {
Andrey Ponomarenko4b077f82012-12-04 16:04:36 +04004957 my $MInfoId = getTreeAttr_Csts($TypeId);
4958 while($MInfoId)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004959 {
Andrey Ponomarenko4b077f82012-12-04 16:04:36 +04004960 $TypeAttr->{"Memb"}{$Pos}{"value"} = getEnumMembVal($MInfoId);
4961 my $MembName = getTreeStr(getTreeAttr_Purp($MInfoId));
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04004962 $TypeAttr->{"Memb"}{$Pos}{"name"} = $MembName;
Andrey Ponomarenko4b077f82012-12-04 16:04:36 +04004963 $EnumMembName_Id{$Version}{getTreeAttr_Valu($MInfoId)} = ($TypeAttr->{"NameSpace"})?$TypeAttr->{"NameSpace"}."::".$MembName:$MembName;
4964 $MInfoId = getNextElem($MInfoId);
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04004965 $Pos += 1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004966 }
4967 }
4968 elsif($TypeType=~/\A(Struct|Class|Union)\Z/)
4969 {
Andrey Ponomarenko4b077f82012-12-04 16:04:36 +04004970 my $MInfoId = getTreeAttr_Flds($TypeId);
4971 while($MInfoId)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004972 {
Andrey Ponomarenko4b077f82012-12-04 16:04:36 +04004973 my $IType = $LibInfo{$Version}{"info_type"}{$MInfoId};
4974 my $MInfo = $LibInfo{$Version}{"info"}{$MInfoId};
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04004975 if(not $IType or $IType ne "field_decl")
4976 { # search for fields, skip other stuff in the declaration
Andrey Ponomarenko4b077f82012-12-04 16:04:36 +04004977 $MInfoId = getNextElem($MInfoId);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004978 next;
4979 }
Andrey Ponomarenko4b077f82012-12-04 16:04:36 +04004980 my $StructMembName = getTreeStr(getTreeAttr_Name($MInfoId));
Andrey Ponomarenko01117f12012-06-26 12:23:02 +04004981 if(index($StructMembName, "_vptr.")!=-1)
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04004982 { # virtual tables
Andrey Ponomarenko4b077f82012-12-04 16:04:36 +04004983 $MInfoId = getNextElem($MInfoId);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004984 next;
4985 }
4986 if(not $StructMembName)
4987 { # unnamed fields
Andrey Ponomarenko01117f12012-06-26 12:23:02 +04004988 if(index($TypeAttr->{"Name"}, "_type_info_pseudo")==-1)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004989 {
Andrey Ponomarenko4b077f82012-12-04 16:04:36 +04004990 my $UnnamedTid = getTreeAttr_Type($MInfoId);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004991 my $UnnamedTName = getNameByInfo(getTypeDeclId($UnnamedTid));
4992 if(isAnon($UnnamedTName))
4993 { # rename unnamed fields to unnamed0, unnamed1, ...
4994 $StructMembName = "unnamed".($UnnamedPos++);
4995 }
4996 }
4997 }
4998 if(not $StructMembName)
4999 { # unnamed fields and base classes
Andrey Ponomarenko4b077f82012-12-04 16:04:36 +04005000 $MInfoId = getNextElem($MInfoId);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005001 next;
5002 }
Andrey Ponomarenko4b077f82012-12-04 16:04:36 +04005003 my $MembTypeId = getTreeAttr_Type($MInfoId);
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04005004 if(defined $MissedTypedef{$Version}{$MembTypeId})
5005 {
5006 if(my $AddedTid = $MissedTypedef{$Version}{$MembTypeId}{"Tid"}) {
5007 $MembTypeId = $AddedTid;
5008 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005009 }
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04005010 $TypeAttr->{"Memb"}{$Pos}{"type"} = $MembTypeId;
5011 $TypeAttr->{"Memb"}{$Pos}{"name"} = $StructMembName;
Andrey Ponomarenko4b077f82012-12-04 16:04:36 +04005012 if((my $Access = getTreeAccess($MInfoId)) ne "public")
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04005013 { # marked only protected and private, public by default
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04005014 $TypeAttr->{"Memb"}{$Pos}{"access"} = $Access;
5015 }
5016 if($MInfo=~/spec:\s*mutable /)
5017 { # mutable fields
5018 $TypeAttr->{"Memb"}{$Pos}{"mutable"} = 1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005019 }
Andrey Ponomarenko4b077f82012-12-04 16:04:36 +04005020 if(my $Algn = getAlgn($MInfoId)) {
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +04005021 $TypeAttr->{"Memb"}{$Pos}{"algn"} = $Algn;
5022 }
Andrey Ponomarenko4b077f82012-12-04 16:04:36 +04005023 if(my $BFSize = getBitField($MInfoId))
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +04005024 { # in bits
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04005025 $TypeAttr->{"Memb"}{$Pos}{"bitfield"} = $BFSize;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005026 }
5027 else
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +04005028 { # in bytes
5029 $TypeAttr->{"Memb"}{$Pos}{"algn"} /= $BYTE_SIZE;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005030 }
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +04005031
Andrey Ponomarenko4b077f82012-12-04 16:04:36 +04005032 $MInfoId = getNextElem($MInfoId);
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04005033 $Pos += 1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005034 }
5035 }
5036}
5037
5038sub setFuncParams($)
5039{
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04005040 my $InfoId = $_[0];
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04005041 my $ParamInfoId = getTreeAttr_Args($InfoId);
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04005042 if(getFuncType($InfoId) eq "Method")
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005043 { # check type of "this" pointer
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04005044 my $ObjectTypeId = getTreeAttr_Type($ParamInfoId);
5045 if(my $ObjectName = $TypeInfo{$Version}{$ObjectTypeId}{"Name"})
Andrey Ponomarenko85043792012-05-14 16:48:07 +04005046 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04005047 if($ObjectName=~/\bconst(| volatile)\*const\b/) {
Andrey Ponomarenko85043792012-05-14 16:48:07 +04005048 $SymbolInfo{$Version}{$InfoId}{"Const"} = 1;
5049 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04005050 if($ObjectName=~/\bvolatile\b/) {
Andrey Ponomarenko85043792012-05-14 16:48:07 +04005051 $SymbolInfo{$Version}{$InfoId}{"Volatile"} = 1;
5052 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005053 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +04005054 else
5055 { # skip
5056 return 1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005057 }
5058 $ParamInfoId = getNextElem($ParamInfoId);
5059 }
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04005060 my ($Pos, $Vtt_Pos) = (0, -1);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005061 while($ParamInfoId)
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04005062 { # formal args
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04005063 my $ParamTypeId = getTreeAttr_Type($ParamInfoId);
5064 my $ParamName = getTreeStr(getTreeAttr_Name($ParamInfoId));
5065 if(not $ParamName)
5066 { # unnamed
5067 $ParamName = "p".($Pos+1);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005068 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04005069 if(defined $MissedTypedef{$Version}{$ParamTypeId})
5070 {
5071 if(my $AddedTid = $MissedTypedef{$Version}{$ParamTypeId}{"Tid"}) {
5072 $ParamTypeId = $AddedTid;
5073 }
5074 }
5075 my $PType = $TypeInfo{$Version}{$ParamTypeId}{"Type"};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005076 if(not $PType or $PType eq "Unknown") {
5077 return 1;
5078 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04005079 my $PTName = $TypeInfo{$Version}{$ParamTypeId}{"Name"};
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04005080 if(not $PTName) {
5081 return 1;
5082 }
5083 if($PTName eq "void") {
5084 last;
5085 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005086 if($ParamName eq "__vtt_parm"
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04005087 and $TypeInfo{$Version}{$ParamTypeId}{"Name"} eq "void const**")
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005088 {
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04005089 $Vtt_Pos = $Pos;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005090 $ParamInfoId = getNextElem($ParamInfoId);
5091 next;
5092 }
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04005093 $SymbolInfo{$Version}{$InfoId}{"Param"}{$Pos}{"type"} = $ParamTypeId;
5094 $SymbolInfo{$Version}{$InfoId}{"Param"}{$Pos}{"name"} = $ParamName;
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04005095 if(my $Algn = getAlgn($ParamInfoId)) {
5096 $SymbolInfo{$Version}{$InfoId}{"Param"}{$Pos}{"algn"} = $Algn/$BYTE_SIZE;
5097 }
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04005098 if(not $SymbolInfo{$Version}{$InfoId}{"Param"}{$Pos}{"name"}) {
5099 $SymbolInfo{$Version}{$InfoId}{"Param"}{$Pos}{"name"} = "p".($Pos+1);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005100 }
5101 if($LibInfo{$Version}{"info"}{$ParamInfoId}=~/spec:\s*register /)
5102 { # foo(register type arg)
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04005103 $SymbolInfo{$Version}{$InfoId}{"Param"}{$Pos}{"reg"} = 1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005104 }
5105 $ParamInfoId = getNextElem($ParamInfoId);
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04005106 $Pos += 1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005107 }
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04005108 if(setFuncArgs($InfoId, $Vtt_Pos)) {
Andrey Ponomarenko01117f12012-06-26 12:23:02 +04005109 $SymbolInfo{$Version}{$InfoId}{"Param"}{$Pos}{"type"} = "-1";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005110 }
5111 return 0;
5112}
5113
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04005114sub setFuncArgs($$)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005115{
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04005116 my ($InfoId, $Vtt_Pos) = @_;
5117 my $FuncTypeId = getFuncTypeId($InfoId);
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04005118 my $ParamListElemId = getTreeAttr_Prms($FuncTypeId);
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04005119 if(getFuncType($InfoId) eq "Method") {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005120 $ParamListElemId = getNextElem($ParamListElemId);
5121 }
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04005122 if(not $ParamListElemId)
5123 { # foo(...)
5124 return 1;
5125 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005126 my $HaveVoid = 0;
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04005127 my $Pos = 0;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005128 while($ParamListElemId)
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04005129 { # actual params: may differ from formal args
5130 # formal int*const
5131 # actual: int*
5132 if($Vtt_Pos!=-1 and $Pos==$Vtt_Pos)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005133 {
5134 $Vtt_Pos=-1;
5135 $ParamListElemId = getNextElem($ParamListElemId);
5136 next;
5137 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04005138 my $ParamTypeId = getTreeAttr_Valu($ParamListElemId);
5139 if($TypeInfo{$Version}{$ParamTypeId}{"Name"} eq "void")
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04005140 {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005141 $HaveVoid = 1;
5142 last;
5143 }
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04005144 elsif(not defined $SymbolInfo{$Version}{$InfoId}{"Param"}{$Pos}{"type"})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005145 {
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04005146 $SymbolInfo{$Version}{$InfoId}{"Param"}{$Pos}{"type"} = $ParamTypeId;
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04005147 if(not $SymbolInfo{$Version}{$InfoId}{"Param"}{$Pos}{"name"})
5148 { # unnamed
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04005149 $SymbolInfo{$Version}{$InfoId}{"Param"}{$Pos}{"name"} = "p".($Pos+1);
5150 }
5151 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04005152 if(my $PurpId = getTreeAttr_Purp($ParamListElemId))
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04005153 { # default arguments
Andrey Ponomarenko01117f12012-06-26 12:23:02 +04005154 if(my $PurpType = $LibInfo{$Version}{"info_type"}{$PurpId})
5155 {
5156 my $Val = getInitVal($PurpId, $ParamTypeId);
5157 if(defined $Val) {
5158 $SymbolInfo{$Version}{$InfoId}{"Param"}{$Pos}{"default"} = $Val;
5159 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005160 }
5161 }
5162 $ParamListElemId = getNextElem($ParamListElemId);
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04005163 $Pos += 1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005164 }
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04005165 return ($Pos>=1 and not $HaveVoid);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005166}
5167
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04005168sub getTreeAttr_Chan($)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005169{
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04005170 if($_[0] and my $Info = $LibInfo{$Version}{"info"}{$_[0]})
5171 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04005172 if($Info=~/chan[ ]*:[ ]*@(\d+) /) {
5173 return $1;
5174 }
5175 }
5176 return "";
5177}
5178
5179sub getTreeAttr_Chain($)
5180{
5181 if($_[0] and my $Info = $LibInfo{$Version}{"info"}{$_[0]})
5182 {
5183 if($Info=~/chain[ ]*:[ ]*@(\d+) /) {
5184 return $1;
5185 }
5186 }
5187 return "";
5188}
5189
Andrey Ponomarenkoe3d6bf02012-11-14 11:49:09 +04005190sub getTreeAttr_Unql($)
5191{
5192 if($_[0] and my $Info = $LibInfo{$Version}{"info"}{$_[0]})
5193 {
5194 if($Info=~/unql[ ]*:[ ]*@(\d+) /) {
5195 return $1;
5196 }
5197 }
5198 return "";
5199}
5200
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04005201sub getTreeAttr_Scpe($)
5202{
5203 if($_[0] and my $Info = $LibInfo{$Version}{"info"}{$_[0]})
5204 {
5205 if($Info=~/scpe[ ]*:[ ]*@(\d+) /) {
5206 return $1;
5207 }
5208 }
5209 return "";
5210}
5211
5212sub getTreeAttr_Type($)
5213{
5214 if($_[0] and my $Info = $LibInfo{$Version}{"info"}{$_[0]})
5215 {
5216 if($Info=~/type[ ]*:[ ]*@(\d+) /) {
5217 return $1;
5218 }
5219 }
5220 return "";
5221}
5222
5223sub getTreeAttr_Name($)
5224{
5225 if($_[0] and my $Info = $LibInfo{$Version}{"info"}{$_[0]})
5226 {
5227 if($Info=~/name[ ]*:[ ]*@(\d+) /) {
5228 return $1;
5229 }
5230 }
5231 return "";
5232}
5233
5234sub getTreeAttr_Mngl($)
5235{
5236 if($_[0] and my $Info = $LibInfo{$Version}{"info"}{$_[0]})
5237 {
5238 if($Info=~/mngl[ ]*:[ ]*@(\d+) /) {
5239 return $1;
5240 }
5241 }
5242 return "";
5243}
5244
5245sub getTreeAttr_Prms($)
5246{
5247 if($_[0] and my $Info = $LibInfo{$Version}{"info"}{$_[0]})
5248 {
5249 if($Info=~/prms[ ]*:[ ]*@(\d+) /) {
5250 return $1;
5251 }
5252 }
5253 return "";
5254}
5255
5256sub getTreeAttr_Fncs($)
5257{
5258 if($_[0] and my $Info = $LibInfo{$Version}{"info"}{$_[0]})
5259 {
5260 if($Info=~/fncs[ ]*:[ ]*@(\d+) /) {
5261 return $1;
5262 }
5263 }
5264 return "";
5265}
5266
5267sub getTreeAttr_Csts($)
5268{
5269 if($_[0] and my $Info = $LibInfo{$Version}{"info"}{$_[0]})
5270 {
5271 if($Info=~/csts[ ]*:[ ]*@(\d+) /) {
5272 return $1;
5273 }
5274 }
5275 return "";
5276}
5277
5278sub getTreeAttr_Purp($)
5279{
5280 if($_[0] and my $Info = $LibInfo{$Version}{"info"}{$_[0]})
5281 {
5282 if($Info=~/purp[ ]*:[ ]*@(\d+) /) {
5283 return $1;
5284 }
5285 }
5286 return "";
5287}
5288
5289sub getTreeAttr_Valu($)
5290{
5291 if($_[0] and my $Info = $LibInfo{$Version}{"info"}{$_[0]})
5292 {
5293 if($Info=~/valu[ ]*:[ ]*@(\d+) /) {
5294 return $1;
5295 }
5296 }
5297 return "";
5298}
5299
5300sub getTreeAttr_Flds($)
5301{
5302 if($_[0] and my $Info = $LibInfo{$Version}{"info"}{$_[0]})
5303 {
5304 if($Info=~/flds[ ]*:[ ]*@(\d+) /) {
5305 return $1;
5306 }
5307 }
5308 return "";
5309}
5310
5311sub getTreeAttr_Args($)
5312{
5313 if($_[0] and my $Info = $LibInfo{$Version}{"info"}{$_[0]})
5314 {
5315 if($Info=~/args[ ]*:[ ]*@(\d+) /) {
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04005316 return $1;
5317 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005318 }
5319 return "";
5320}
5321
5322sub getTreeValue($)
5323{
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04005324 if($_[0] and my $Info = $LibInfo{$Version}{"info"}{$_[0]})
5325 {
5326 if($Info=~/low[ ]*:[ ]*([^ ]+) /) {
5327 return $1;
5328 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005329 }
5330 return "";
5331}
5332
5333sub getTreeAccess($)
5334{
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04005335 if($_[0] and my $Info = $LibInfo{$Version}{"info"}{$_[0]})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005336 {
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04005337 if($Info=~/accs[ ]*:[ ]*([a-zA-Z]+) /)
5338 {
5339 my $Access = $1;
5340 if($Access eq "prot") {
5341 return "protected";
5342 }
5343 elsif($Access eq "priv") {
5344 return "private";
5345 }
5346 }
5347 elsif($Info=~/ protected /)
5348 { # support for old GCC versions
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005349 return "protected";
5350 }
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04005351 elsif($Info=~/ private /)
5352 { # support for old GCC versions
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005353 return "private";
5354 }
5355 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005356 return "public";
5357}
5358
5359sub setFuncAccess($)
5360{
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04005361 my $Access = getTreeAccess($_[0]);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005362 if($Access eq "protected") {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04005363 $SymbolInfo{$Version}{$_[0]}{"Protected"} = 1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005364 }
5365 elsif($Access eq "private") {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04005366 $SymbolInfo{$Version}{$_[0]}{"Private"} = 1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005367 }
5368}
5369
5370sub setTypeAccess($$)
5371{
5372 my ($TypeId, $TypeAttr) = @_;
5373 my $Access = getTreeAccess($TypeId);
5374 if($Access eq "protected") {
5375 $TypeAttr->{"Protected"} = 1;
5376 }
5377 elsif($Access eq "private") {
5378 $TypeAttr->{"Private"} = 1;
5379 }
5380}
5381
5382sub setFuncKind($)
5383{
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04005384 if($_[0] and my $Info = $LibInfo{$Version}{"info"}{$_[0]})
5385 {
5386 if($Info=~/pseudo tmpl/) {
5387 $SymbolInfo{$Version}{$_[0]}{"PseudoTemplate"} = 1;
5388 }
5389 elsif($Info=~/ constructor /) {
5390 $SymbolInfo{$Version}{$_[0]}{"Constructor"} = 1;
5391 }
5392 elsif($Info=~/ destructor /) {
5393 $SymbolInfo{$Version}{$_[0]}{"Destructor"} = 1;
5394 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005395 }
5396}
5397
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04005398sub getVirtSpec($)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005399{
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04005400 if($_[0] and my $Info = $LibInfo{$Version}{"info"}{$_[0]})
5401 {
5402 if($Info=~/spec[ ]*:[ ]*pure /) {
5403 return "PureVirt";
5404 }
5405 elsif($Info=~/spec[ ]*:[ ]*virt /) {
5406 return "Virt";
5407 }
5408 elsif($Info=~/ pure\s+virtual /)
5409 { # support for old GCC versions
5410 return "PureVirt";
5411 }
5412 elsif($Info=~/ virtual /)
5413 { # support for old GCC versions
5414 return "Virt";
5415 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005416 }
5417 return "";
5418}
5419
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005420sub getFuncLink($)
5421{
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04005422 if($_[0] and my $Info = $LibInfo{$Version}{"info"}{$_[0]})
5423 {
5424 if($Info=~/link[ ]*:[ ]*static /) {
5425 return "Static";
5426 }
5427 elsif($Info=~/link[ ]*:[ ]*([a-zA-Z]+) /) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005428 return $1;
5429 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005430 }
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04005431 return "";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005432}
5433
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005434sub get_IntNameSpace($$)
5435{
5436 my ($Interface, $LibVersion) = @_;
5437 return "" if(not $Interface or not $LibVersion);
5438 if(defined $Cache{"get_IntNameSpace"}{$Interface}{$LibVersion}) {
5439 return $Cache{"get_IntNameSpace"}{$Interface}{$LibVersion};
5440 }
5441 my $Signature = get_Signature($Interface, $LibVersion);
5442 if($Signature=~/\:\:/)
5443 {
5444 my $FounNameSpace = 0;
5445 foreach my $NameSpace (sort {get_depth($b)<=>get_depth($a)} keys(%{$NestedNameSpaces{$LibVersion}}))
5446 {
5447 if($Signature=~/(\A|\s+for\s+)\Q$NameSpace\E\:\:/) {
5448 return ($Cache{"get_IntNameSpace"}{$Interface}{$LibVersion} = $NameSpace);
5449 }
5450 }
5451 }
5452 else {
5453 return ($Cache{"get_IntNameSpace"}{$Interface}{$LibVersion} = "");
5454 }
5455}
5456
5457sub parse_TypeNameSpace($$)
5458{
5459 my ($TypeName, $LibVersion) = @_;
5460 return "" if(not $TypeName or not $LibVersion);
5461 if(defined $Cache{"parse_TypeNameSpace"}{$TypeName}{$LibVersion}) {
5462 return $Cache{"parse_TypeNameSpace"}{$TypeName}{$LibVersion};
5463 }
5464 if($TypeName=~/\:\:/)
5465 {
5466 my $FounNameSpace = 0;
5467 foreach my $NameSpace (sort {get_depth($b)<=>get_depth($a)} keys(%{$NestedNameSpaces{$LibVersion}}))
5468 {
5469 if($TypeName=~/\A\Q$NameSpace\E\:\:/) {
5470 return ($Cache{"parse_TypeNameSpace"}{$TypeName}{$LibVersion} = $NameSpace);
5471 }
5472 }
5473 }
5474 else {
5475 return ($Cache{"parse_TypeNameSpace"}{$TypeName}{$LibVersion} = "");
5476 }
5477}
5478
5479sub getNameSpace($)
5480{
5481 my $TypeInfoId = $_[0];
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04005482 if(my $NSInfoId = getTreeAttr_Scpe($TypeInfoId))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005483 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04005484 if(my $InfoType = $LibInfo{$Version}{"info_type"}{$NSInfoId})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005485 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04005486 if($InfoType eq "namespace_decl")
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04005487 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04005488 if($LibInfo{$Version}{"info"}{$NSInfoId}=~/name[ ]*:[ ]*@(\d+) /)
5489 {
5490 my $NameSpace = getTreeStr($1);
5491 if($NameSpace eq "::")
5492 { # global namespace
5493 return "";
5494 }
5495 if(my $BaseNameSpace = getNameSpace($NSInfoId)) {
5496 $NameSpace = $BaseNameSpace."::".$NameSpace;
5497 }
5498 $NestedNameSpaces{$Version}{$NameSpace} = 1;
5499 return $NameSpace;
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04005500 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04005501 else {
5502 return "";
5503 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005504 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04005505 elsif($InfoType eq "record_type")
5506 { # inside data type
5507 my ($Name, $NameNS) = getTrivialName(getTypeDeclId($NSInfoId), $NSInfoId);
5508 return $Name;
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04005509 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005510 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005511 }
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04005512 return "";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005513}
5514
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005515sub getEnumMembVal($)
5516{
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04005517 if($_[0] and my $Info = $LibInfo{$Version}{"info"}{$_[0]})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005518 {
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04005519 if($Info=~/valu[ ]*:[ ]*\@(\d+)/)
5520 {
5521 if(my $VInfo = $LibInfo{$Version}{"info"}{$1})
5522 {
5523 if($VInfo=~/cnst[ ]*:[ ]*\@(\d+)/)
5524 { # in newer versions of GCC the value is in the "const_decl->cnst" node
5525 return getTreeValue($1);
5526 }
5527 else
5528 { # some old versions of GCC (3.3) have the value in the "integer_cst" node
5529 return getTreeValue($1);
5530 }
5531 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005532 }
5533 }
5534 return "";
5535}
5536
5537sub getSize($)
5538{
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04005539 if($_[0] and my $Info = $LibInfo{$Version}{"info"}{$_[0]})
5540 {
5541 if($Info=~/size[ ]*:[ ]*\@(\d+)/) {
5542 return getTreeValue($1);
5543 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005544 }
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04005545 return 0;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005546}
5547
5548sub getAlgn($)
5549{
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04005550 if($_[0] and my $Info = $LibInfo{$Version}{"info"}{$_[0]})
5551 {
5552 if($Info=~/algn[ ]*:[ ]*(\d+) /) {
5553 return $1;
5554 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005555 }
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04005556 return "";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005557}
5558
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +04005559sub getBitField($)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005560{
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04005561 if($_[0] and my $Info = $LibInfo{$Version}{"info"}{$_[0]})
5562 {
5563 if($Info=~/ bitfield /) {
5564 return getSize($_[0]);
5565 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005566 }
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04005567 return 0;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005568}
5569
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04005570sub getNextElem($)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005571{
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04005572 if(my $Chan = getTreeAttr_Chan($_[0])) {
5573 return $Chan;
5574 }
5575 elsif(my $Chain = getTreeAttr_Chain($_[0])) {
5576 return $Chain;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005577 }
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04005578 return "";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005579}
5580
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04005581sub registerHeader($$)
5582{ # input: absolute path of header, relative path or name
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005583 my ($Header, $LibVersion) = @_;
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04005584 if(not $Header) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005585 return "";
5586 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04005587 if(is_abs($Header) and not -f $Header)
5588 { # incorrect absolute path
5589 exitStatus("Access_Error", "can't access \'$Header\'");
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005590 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04005591 if(skipHeader($Header, $LibVersion))
5592 { # skip
5593 return "";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005594 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04005595 if(my $Header_Path = identifyHeader($Header, $LibVersion))
5596 {
5597 detect_header_includes($Header_Path, $LibVersion);
5598
5599 if(my $RHeader_Path = $Header_ErrorRedirect{$LibVersion}{$Header_Path})
5600 { # redirect
5601 if($Registered_Headers{$LibVersion}{$RHeader_Path}{"Identity"}
5602 or skipHeader($RHeader_Path, $LibVersion))
5603 { # skip
5604 return "";
5605 }
5606 $Header_Path = $RHeader_Path;
5607 }
5608 elsif($Header_ShouldNotBeUsed{$LibVersion}{$Header_Path})
5609 { # skip
5610 return "";
5611 }
5612
5613 if(my $HName = get_filename($Header_Path))
5614 { # register
5615 $Registered_Headers{$LibVersion}{$Header_Path}{"Identity"} = $HName;
5616 $HeaderName_Paths{$LibVersion}{$HName}{$Header_Path} = 1;
5617 }
5618
5619 if(($Header=~/\.(\w+)\Z/ and $1 ne "h")
5620 or $Header!~/\.(\w+)\Z/)
5621 { # hpp, hh
5622 setLanguage($LibVersion, "C++");
5623 }
5624
5625 if($CheckHeadersOnly
5626 and $Header=~/(\A|\/)c\+\+(\/|\Z)/)
5627 { # /usr/include/c++/4.6.1/...
5628 $STDCXX_TESTING = 1;
5629 }
5630
5631 return $Header_Path;
5632 }
5633 return "";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005634}
5635
5636sub register_directory($$$)
5637{
5638 my ($Dir, $WithDeps, $LibVersion) = @_;
5639 $Dir=~s/[\/\\]+\Z//g;
5640 return if(not $LibVersion or not $Dir or not -d $Dir);
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04005641 return if(skipHeader($Dir, $LibVersion));
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005642 $Dir = get_abs_path($Dir);
5643 my $Mode = "All";
Andrey Ponomarenko85043792012-05-14 16:48:07 +04005644 if($WithDeps)
5645 {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005646 if($RegisteredDirs{$LibVersion}{$Dir}{1}) {
5647 return;
5648 }
5649 elsif($RegisteredDirs{$LibVersion}{$Dir}{0}) {
5650 $Mode = "DepsOnly";
5651 }
5652 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +04005653 else
5654 {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005655 if($RegisteredDirs{$LibVersion}{$Dir}{1}
5656 or $RegisteredDirs{$LibVersion}{$Dir}{0}) {
5657 return;
5658 }
5659 }
5660 $Header_Dependency{$LibVersion}{$Dir} = 1;
5661 $RegisteredDirs{$LibVersion}{$Dir}{$WithDeps} = 1;
5662 if($Mode eq "DepsOnly")
5663 {
Andrey Ponomarenko570ece52012-11-30 16:36:44 +04005664 foreach my $Path (cmd_find($Dir,"d")) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005665 $Header_Dependency{$LibVersion}{$Path} = 1;
5666 }
5667 return;
5668 }
Andrey Ponomarenko570ece52012-11-30 16:36:44 +04005669 foreach my $Path (sort {length($b)<=>length($a)} cmd_find($Dir,"f"))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005670 {
5671 if($WithDeps)
5672 {
5673 my $SubDir = $Path;
5674 while(($SubDir = get_dirname($SubDir)) ne $Dir)
5675 { # register all sub directories
5676 $Header_Dependency{$LibVersion}{$SubDir} = 1;
5677 }
5678 }
5679 next if(is_not_header($Path));
5680 next if(ignore_path($Path));
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04005681 next if(skipHeader($Path, $LibVersion));
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005682 # Neighbors
Andrey Ponomarenko9927e332012-10-19 10:50:48 +04005683 foreach my $Part (get_prefixes($Path)) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005684 $Include_Neighbors{$LibVersion}{$Part} = $Path;
5685 }
5686 }
5687 if(get_filename($Dir) eq "include")
5688 { # search for "lib/include/" directory
5689 my $LibDir = $Dir;
5690 if($LibDir=~s/([\/\\])include\Z/$1lib/g and -d $LibDir) {
5691 register_directory($LibDir, $WithDeps, $LibVersion);
5692 }
5693 }
5694}
5695
5696sub parse_redirect($$$)
5697{
5698 my ($Content, $Path, $LibVersion) = @_;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005699 my @Errors = ();
5700 while($Content=~s/#\s*error\s+([^\n]+?)\s*(\n|\Z)//) {
5701 push(@Errors, $1);
5702 }
5703 my $Redirect = "";
5704 foreach (@Errors)
5705 {
5706 s/\s{2,}/ /g;
5707 if(/(only|must\ include
5708 |update\ to\ include
5709 |replaced\ with
5710 |replaced\ by|renamed\ to
Andrey Ponomarenko9927e332012-10-19 10:50:48 +04005711 |\ is\ in|\ use)\ (<[^<>]+>|[\w\-\/\\]+\.($HEADER_EXT))/ix)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005712 {
5713 $Redirect = $2;
5714 last;
5715 }
5716 elsif(/(include|use|is\ in)\ (<[^<>]+>|[\w\-\/\\]+\.($HEADER_EXT))\ instead/i)
5717 {
5718 $Redirect = $2;
5719 last;
5720 }
5721 elsif(/this\ header\ should\ not\ be\ used
5722 |programs\ should\ not\ directly\ include
5723 |you\ should\ not\ (include|be\ (including|using)\ this\ (file|header))
5724 |is\ not\ supported\ API\ for\ general\ use
5725 |do\ not\ use
Andrey Ponomarenko9927e332012-10-19 10:50:48 +04005726 |should\ not\ be\ (used|using)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005727 |cannot\ be\ included\ directly/ix and not /\ from\ /i) {
5728 $Header_ShouldNotBeUsed{$LibVersion}{$Path} = 1;
5729 }
5730 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +04005731 if($Redirect)
5732 {
5733 $Redirect=~s/\A<//g;
5734 $Redirect=~s/>\Z//g;
5735 }
5736 return $Redirect;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005737}
5738
5739sub parse_includes($$)
5740{
5741 my ($Content, $Path) = @_;
5742 my %Includes = ();
Andrey Ponomarenko4b077f82012-12-04 16:04:36 +04005743 while($Content=~s/^[ \t]*#[ \t]*(include|include_next|import)[ \t]*(.+?)[ \t]*$//m)
Andrey Ponomarenko85043792012-05-14 16:48:07 +04005744 { # C/C++: include, Objective C/C++: import directive
Andrey Ponomarenko4b077f82012-12-04 16:04:36 +04005745 my $Header = $2;
5746 my $Method = substr($Header, 0, 1);
5747 if($Method eq "\"" or $Method eq "<")
5748 { # default
5749 substr($Header, 0, 1, "");
5750 substr($Header, length($Header)-1, 1, "");
5751 $Header = path_format($Header, $OSgroup);
5752 if($Method eq "\"" or is_abs($Header))
5753 {
5754 if(-e joinPath(get_dirname($Path), $Header))
5755 { # relative path exists
5756 $Includes{$Header} = -1;
5757 }
5758 else
5759 { # include "..." that doesn't exist is equal to include <...>
5760 $Includes{$Header} = 2;
5761 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +04005762 }
Andrey Ponomarenko4b077f82012-12-04 16:04:36 +04005763 else {
5764 $Includes{$Header} = 1;
Andrey Ponomarenko85043792012-05-14 16:48:07 +04005765 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005766 }
Andrey Ponomarenko4b077f82012-12-04 16:04:36 +04005767 else
5768 {
5769 if($ExtraInfo) {
5770 $Includes{$Header} = 0;
5771 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005772 }
5773 }
5774 return \%Includes;
5775}
5776
5777sub ignore_path($)
5778{
5779 my $Path = $_[0];
5780 if($Path=~/\~\Z/)
5781 {# skipping system backup files
5782 return 1;
5783 }
5784 if($Path=~/(\A|[\/\\]+)(\.(svn|git|bzr|hg)|CVS)([\/\\]+|\Z)/)
5785 {# skipping hidden .svn, .git, .bzr, .hg and CVS directories
5786 return 1;
5787 }
5788 return 0;
5789}
5790
Andrey Ponomarenko9927e332012-10-19 10:50:48 +04005791sub sortByWord($$)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005792{
5793 my ($ArrRef, $W) = @_;
5794 return if(length($W)<2);
5795 @{$ArrRef} = sort {get_filename($b)=~/\Q$W\E/i<=>get_filename($a)=~/\Q$W\E/i} @{$ArrRef};
5796}
5797
Andrey Ponomarenko9927e332012-10-19 10:50:48 +04005798sub sortHeaders($$)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005799{
5800 my ($H1, $H2) = @_;
5801 $H1=~s/\.[a-z]+\Z//ig;
5802 $H2=~s/\.[a-z]+\Z//ig;
5803 my ($HDir1, $Hname1) = separate_path($H1);
5804 my ($HDir2, $Hname2) = separate_path($H2);
5805 my $Dirname1 = get_filename($HDir1);
5806 my $Dirname2 = get_filename($HDir2);
Andrey Ponomarenko9927e332012-10-19 10:50:48 +04005807 if($_[0] eq $_[1]
5808 or $H1 eq $H2) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005809 return 0;
5810 }
5811 elsif($H1=~/\A\Q$H2\E/) {
5812 return 1;
5813 }
5814 elsif($H2=~/\A\Q$H1\E/) {
5815 return -1;
5816 }
5817 elsif($HDir1=~/\Q$Hname1\E/i
5818 and $HDir2!~/\Q$Hname2\E/i)
Andrey Ponomarenko9927e332012-10-19 10:50:48 +04005819 { # include/glib-2.0/glib.h
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005820 return -1;
5821 }
5822 elsif($HDir2=~/\Q$Hname2\E/i
5823 and $HDir1!~/\Q$Hname1\E/i)
Andrey Ponomarenko9927e332012-10-19 10:50:48 +04005824 { # include/glib-2.0/glib.h
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005825 return 1;
5826 }
5827 elsif($Hname1=~/\Q$Dirname1\E/i
5828 and $Hname2!~/\Q$Dirname2\E/i)
Andrey Ponomarenko9927e332012-10-19 10:50:48 +04005829 { # include/hildon-thumbnail/hildon-thumbnail-factory.h
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005830 return -1;
5831 }
5832 elsif($Hname2=~/\Q$Dirname2\E/i
5833 and $Hname1!~/\Q$Dirname1\E/i)
Andrey Ponomarenko9927e332012-10-19 10:50:48 +04005834 { # include/hildon-thumbnail/hildon-thumbnail-factory.h
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005835 return 1;
5836 }
Andrey Ponomarenko9927e332012-10-19 10:50:48 +04005837 elsif($Hname1=~/(config|lib|util)/i
5838 and $Hname2!~/(config|lib|util)/i)
5839 { # include/alsa/asoundlib.h
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005840 return -1;
5841 }
Andrey Ponomarenko9927e332012-10-19 10:50:48 +04005842 elsif($Hname2=~/(config|lib|util)/i
5843 and $Hname1!~/(config|lib|util)/i)
5844 { # include/alsa/asoundlib.h
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005845 return 1;
5846 }
5847 elsif(checkRelevance($H1)
5848 and not checkRelevance($H2))
Andrey Ponomarenko9927e332012-10-19 10:50:48 +04005849 { # libebook/e-book.h
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005850 return -1;
5851 }
5852 elsif(checkRelevance($H2)
5853 and not checkRelevance($H1))
Andrey Ponomarenko9927e332012-10-19 10:50:48 +04005854 { # libebook/e-book.h
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005855 return 1;
5856 }
Andrey Ponomarenko9927e332012-10-19 10:50:48 +04005857 else
5858 {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005859 return (lc($H1) cmp lc($H2));
5860 }
5861}
5862
5863sub searchForHeaders($)
5864{
5865 my $LibVersion = $_[0];
Andrey Ponomarenko570ece52012-11-30 16:36:44 +04005866
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005867 # gcc standard include paths
Andrey Ponomarenko570ece52012-11-30 16:36:44 +04005868 registerGccHeaders();
5869
5870 if($COMMON_LANGUAGE{$LibVersion} eq "C++" and not $STDCXX_TESTING)
5871 { # c++ standard include paths
5872 registerCppHeaders();
5873 }
5874
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005875 # processing header paths
Andrey Ponomarenko570ece52012-11-30 16:36:44 +04005876 foreach my $Path (@{$Descriptor{$LibVersion}{"IncludePaths"}},
5877 @{$Descriptor{$LibVersion}{"AddIncludePaths"}})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005878 {
5879 my $IPath = $Path;
Andrey Ponomarenkoa01311b2012-06-08 17:20:02 +04005880 if($SystemRoot)
5881 {
5882 if(is_abs($Path)) {
5883 $Path = $SystemRoot.$Path;
5884 }
5885 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005886 if(not -e $Path) {
5887 exitStatus("Access_Error", "can't access \'$Path\'");
5888 }
5889 elsif(-f $Path) {
5890 exitStatus("Access_Error", "\'$Path\' - not a directory");
5891 }
5892 elsif(-d $Path)
5893 {
5894 $Path = get_abs_path($Path);
5895 register_directory($Path, 0, $LibVersion);
Andrey Ponomarenko570ece52012-11-30 16:36:44 +04005896 if(grep {$IPath eq $_} @{$Descriptor{$LibVersion}{"AddIncludePaths"}}) {
5897 push(@{$Add_Include_Paths{$LibVersion}}, $Path);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005898 }
5899 else {
Andrey Ponomarenko570ece52012-11-30 16:36:44 +04005900 push(@{$Include_Paths{$LibVersion}}, $Path);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005901 }
5902 }
5903 }
Andrey Ponomarenko570ece52012-11-30 16:36:44 +04005904 if(@{$Include_Paths{$LibVersion}}) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005905 $INC_PATH_AUTODETECT{$LibVersion} = 0;
5906 }
Andrey Ponomarenko570ece52012-11-30 16:36:44 +04005907
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005908 # registering directories
5909 foreach my $Path (split(/\s*\n\s*/, $Descriptor{$LibVersion}{"Headers"}))
5910 {
5911 next if(not -e $Path);
5912 $Path = get_abs_path($Path);
5913 $Path = path_format($Path, $OSgroup);
5914 if(-d $Path) {
5915 register_directory($Path, 1, $LibVersion);
5916 }
5917 elsif(-f $Path)
5918 {
5919 my $Dir = get_dirname($Path);
Andrey Ponomarenko570ece52012-11-30 16:36:44 +04005920 if(not grep { $Dir eq $_ } (@{$SystemPaths{"include"}})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005921 and not $LocalIncludes{$Dir})
5922 {
5923 register_directory($Dir, 1, $LibVersion);
5924 if(my $OutDir = get_dirname($Dir))
5925 { # registering the outer directory
Andrey Ponomarenko570ece52012-11-30 16:36:44 +04005926 if(not grep { $OutDir eq $_ } (@{$SystemPaths{"include"}})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005927 and not $LocalIncludes{$OutDir}) {
5928 register_directory($OutDir, 0, $LibVersion);
5929 }
5930 }
5931 }
5932 }
5933 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +04005934
5935 # clean memory
5936 %RegisteredDirs = ();
5937
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005938 # registering headers
5939 my $Position = 0;
5940 foreach my $Dest (split(/\s*\n\s*/, $Descriptor{$LibVersion}{"Headers"}))
5941 {
5942 if(is_abs($Dest) and not -e $Dest) {
5943 exitStatus("Access_Error", "can't access \'$Dest\'");
5944 }
5945 $Dest = path_format($Dest, $OSgroup);
5946 if(is_header($Dest, 1, $LibVersion))
5947 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04005948 if(my $HPath = registerHeader($Dest, $LibVersion)) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005949 $Registered_Headers{$LibVersion}{$HPath}{"Pos"} = $Position++;
5950 }
5951 }
5952 elsif(-d $Dest)
5953 {
5954 my @Registered = ();
Andrey Ponomarenko570ece52012-11-30 16:36:44 +04005955 foreach my $Path (cmd_find($Dest,"f"))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005956 {
5957 next if(ignore_path($Path));
5958 next if(not is_header($Path, 0, $LibVersion));
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04005959 if(my $HPath = registerHeader($Path, $LibVersion)) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005960 push(@Registered, $HPath);
5961 }
5962 }
Andrey Ponomarenko9927e332012-10-19 10:50:48 +04005963 @Registered = sort {sortHeaders($a, $b)} @Registered;
5964 sortByWord(\@Registered, $TargetLibraryShortName);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005965 foreach my $Path (@Registered) {
5966 $Registered_Headers{$LibVersion}{$Path}{"Pos"} = $Position++;
5967 }
5968 }
5969 else {
5970 exitStatus("Access_Error", "can't identify \'$Dest\' as a header file");
5971 }
5972 }
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04005973 if(my $HList = $Descriptor{$LibVersion}{"IncludePreamble"})
5974 { # preparing preamble headers
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04005975 foreach my $Header (split(/\s*\n\s*/, $HList))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005976 {
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04005977 if(is_abs($Header) and not -f $Header) {
5978 exitStatus("Access_Error", "can't access file \'$Header\'");
5979 }
5980 $Header = path_format($Header, $OSgroup);
5981 if(my $Header_Path = is_header($Header, 1, $LibVersion))
5982 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04005983 next if(skipHeader($Header_Path, $LibVersion));
Andrey Ponomarenko570ece52012-11-30 16:36:44 +04005984 push_U($Include_Preamble{$LibVersion}, $Header_Path);
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04005985 }
5986 else {
5987 exitStatus("Access_Error", "can't identify \'$Header\' as a header file");
5988 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005989 }
5990 }
5991 foreach my $Header_Name (keys(%{$HeaderName_Paths{$LibVersion}}))
5992 { # set relative paths (for duplicates)
5993 if(keys(%{$HeaderName_Paths{$LibVersion}{$Header_Name}})>=2)
5994 { # search for duplicates
5995 my $FirstPath = (keys(%{$HeaderName_Paths{$LibVersion}{$Header_Name}}))[0];
5996 my $Prefix = get_dirname($FirstPath);
5997 while($Prefix=~/\A(.+)[\/\\]+[^\/\\]+\Z/)
5998 { # detect a shortest distinguishing prefix
5999 my $NewPrefix = $1;
6000 my %Identity = ();
6001 foreach my $Path (keys(%{$HeaderName_Paths{$LibVersion}{$Header_Name}}))
6002 {
6003 if($Path=~/\A\Q$Prefix\E[\/\\]+(.*)\Z/) {
6004 $Identity{$Path} = $1;
6005 }
6006 }
6007 if(keys(%Identity)==keys(%{$HeaderName_Paths{$LibVersion}{$Header_Name}}))
6008 { # all names are differend with current prefix
6009 foreach my $Path (keys(%{$HeaderName_Paths{$LibVersion}{$Header_Name}})) {
6010 $Registered_Headers{$LibVersion}{$Path}{"Identity"} = $Identity{$Path};
6011 }
6012 last;
6013 }
6014 $Prefix = $NewPrefix; # increase prefix
6015 }
6016 }
6017 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +04006018
6019 # clean memory
6020 %HeaderName_Paths = ();
6021
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006022 foreach my $HeaderName (keys(%{$Include_Order{$LibVersion}}))
6023 { # ordering headers according to descriptor
6024 my $PairName=$Include_Order{$LibVersion}{$HeaderName};
6025 my ($Pos, $PairPos) = (-1, -1);
6026 my ($Path, $PairPath) = ();
6027 my @Paths = keys(%{$Registered_Headers{$LibVersion}});
6028 @Paths = sort {int($Registered_Headers{$LibVersion}{$a}{"Pos"})<=>int($Registered_Headers{$LibVersion}{$b}{"Pos"})} @Paths;
6029 foreach my $Header_Path (@Paths)
6030 {
6031 if(get_filename($Header_Path) eq $PairName)
6032 {
6033 $PairPos = $Registered_Headers{$LibVersion}{$Header_Path}{"Pos"};
6034 $PairPath = $Header_Path;
6035 }
6036 if(get_filename($Header_Path) eq $HeaderName)
6037 {
6038 $Pos = $Registered_Headers{$LibVersion}{$Header_Path}{"Pos"};
6039 $Path = $Header_Path;
6040 }
6041 }
6042 if($PairPos!=-1 and $Pos!=-1
6043 and int($PairPos)<int($Pos))
6044 {
6045 my %Tmp = %{$Registered_Headers{$LibVersion}{$Path}};
6046 %{$Registered_Headers{$LibVersion}{$Path}} = %{$Registered_Headers{$LibVersion}{$PairPath}};
6047 %{$Registered_Headers{$LibVersion}{$PairPath}} = %Tmp;
6048 }
6049 }
6050 if(not keys(%{$Registered_Headers{$LibVersion}})) {
6051 exitStatus("Error", "header files are not found in the ".$Descriptor{$LibVersion}{"Version"});
6052 }
6053}
6054
6055sub detect_real_includes($$)
6056{
6057 my ($AbsPath, $LibVersion) = @_;
6058 return () if(not $LibVersion or not $AbsPath or not -e $AbsPath);
6059 if($Cache{"detect_real_includes"}{$LibVersion}{$AbsPath}
6060 or keys(%{$RecursiveIncludes{$LibVersion}{$AbsPath}})) {
6061 return keys(%{$RecursiveIncludes{$LibVersion}{$AbsPath}});
6062 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +04006063 $Cache{"detect_real_includes"}{$LibVersion}{$AbsPath}=1;
6064
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006065 my $Path = callPreprocessor($AbsPath, "", $LibVersion);
6066 return () if(not $Path);
6067 open(PREPROC, $Path);
6068 while(<PREPROC>)
6069 {
6070 if(/#\s+\d+\s+"([^"]+)"[\s\d]*\n/)
6071 {
6072 my $Include = path_format($1, $OSgroup);
6073 if($Include=~/\<(built\-in|internal|command(\-|\s)line)\>|\A\./) {
6074 next;
6075 }
6076 if($Include eq $AbsPath) {
6077 next;
6078 }
6079 $RecursiveIncludes{$LibVersion}{$AbsPath}{$Include} = 1;
6080 }
6081 }
6082 close(PREPROC);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006083 return keys(%{$RecursiveIncludes{$LibVersion}{$AbsPath}});
6084}
6085
6086sub detect_header_includes($$)
6087{
6088 my ($Path, $LibVersion) = @_;
Andrey Ponomarenko85043792012-05-14 16:48:07 +04006089 return if(not $LibVersion or not $Path);
6090 if(defined $Cache{"detect_header_includes"}{$LibVersion}{$Path}) {
6091 return;
6092 }
6093 $Cache{"detect_header_includes"}{$LibVersion}{$Path}=1;
6094
6095 if(not -e $Path) {
6096 return;
6097 }
6098
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006099 my $Content = readFile($Path);
Andrey Ponomarenko85043792012-05-14 16:48:07 +04006100 if(my $Redirect = parse_redirect($Content, $Path, $LibVersion))
6101 { # detect error directive in headers
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04006102 if(my $RedirectPath = identifyHeader($Redirect, $LibVersion))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006103 {
6104 if($RedirectPath=~/\/usr\/include\// and $Path!~/\/usr\/include\//) {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04006105 $RedirectPath = identifyHeader(get_filename($Redirect), $LibVersion);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006106 }
6107 if($RedirectPath ne $Path) {
6108 $Header_ErrorRedirect{$LibVersion}{$Path} = $RedirectPath;
6109 }
6110 }
Andrey Ponomarenko9927e332012-10-19 10:50:48 +04006111 else
6112 { # can't find
6113 $Header_ShouldNotBeUsed{$LibVersion}{$Path} = 1;
6114 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006115 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +04006116 if(my $Inc = parse_includes($Content, $Path))
6117 {
6118 foreach my $Include (keys(%{$Inc}))
6119 { # detect includes
Andrey Ponomarenko85043792012-05-14 16:48:07 +04006120 $Header_Includes{$LibVersion}{$Path}{$Include} = $Inc->{$Include};
6121 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006122 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006123}
6124
6125sub simplify_path($)
6126{
6127 my $Path = $_[0];
6128 while($Path=~s&([\/\\])[^\/\\]+[\/\\]\.\.[\/\\]&$1&){};
6129 return $Path;
6130}
6131
6132sub fromLibc($)
6133{ # GLIBC header
6134 my $Path = $_[0];
6135 my ($Dir, $Name) = separate_path($Path);
6136 if(get_filename($Dir)=~/\A(include|libc)\Z/ and $GlibcHeader{$Name})
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04006137 { # /usr/include/{stdio, ...}.h
6138 # epoc32/include/libc/{stdio, ...}.h
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006139 return 1;
6140 }
6141 if(isLibcDir($Dir)) {
6142 return 1;
6143 }
6144 return 0;
6145}
6146
6147sub isLibcDir($)
6148{ # GLIBC directory
6149 my $Dir = $_[0];
6150 my ($OutDir, $Name) = separate_path($Dir);
6151 if(get_filename($OutDir)=~/\A(include|libc)\Z/
6152 and ($Name=~/\Aasm(|-.+)\Z/ or $GlibcDir{$Name}))
6153 { # /usr/include/{sys,bits,asm,asm-*}/*.h
6154 return 1;
6155 }
6156 return 0;
6157}
6158
6159sub detect_recursive_includes($$)
6160{
6161 my ($AbsPath, $LibVersion) = @_;
6162 return () if(not $AbsPath);
6163 if(isCyclical(\@RecurInclude, $AbsPath)) {
6164 return keys(%{$RecursiveIncludes{$LibVersion}{$AbsPath}});
6165 }
6166 my ($AbsDir, $Name) = separate_path($AbsPath);
6167 if(isLibcDir($AbsDir))
6168 { # GLIBC internals
6169 return ();
6170 }
6171 if(keys(%{$RecursiveIncludes{$LibVersion}{$AbsPath}})) {
6172 return keys(%{$RecursiveIncludes{$LibVersion}{$AbsPath}});
6173 }
6174 return () if($OSgroup ne "windows" and $Name=~/windows|win32|win64/i);
Andrey Ponomarenko570ece52012-11-30 16:36:44 +04006175
6176 if($MAIN_CPP_DIR and $AbsPath=~/\A\Q$MAIN_CPP_DIR\E/ and not $STDCXX_TESTING)
6177 { # skip /usr/include/c++/*/ headers
6178 return () if(not $ExtraInfo);
6179 }
6180
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006181 push(@RecurInclude, $AbsPath);
Andrey Ponomarenko570ece52012-11-30 16:36:44 +04006182 if(grep { $AbsDir eq $_ } @DefaultGccPaths
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006183 or fromLibc($AbsPath))
6184 { # check "real" (non-"model") include paths
6185 my @Paths = detect_real_includes($AbsPath, $LibVersion);
6186 pop(@RecurInclude);
6187 return @Paths;
6188 }
6189 if(not keys(%{$Header_Includes{$LibVersion}{$AbsPath}})) {
6190 detect_header_includes($AbsPath, $LibVersion);
6191 }
6192 foreach my $Include (keys(%{$Header_Includes{$LibVersion}{$AbsPath}}))
6193 {
Andrey Ponomarenko85043792012-05-14 16:48:07 +04006194 my $IncType = $Header_Includes{$LibVersion}{$AbsPath}{$Include};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006195 my $HPath = "";
Andrey Ponomarenko85043792012-05-14 16:48:07 +04006196 if($IncType<0)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006197 { # for #include "..."
6198 my $Candidate = joinPath($AbsDir, $Include);
6199 if(-f $Candidate) {
6200 $HPath = simplify_path($Candidate);
6201 }
6202 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +04006203 elsif($IncType>0
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04006204 and $Include=~/[\/\\]/) # and not find_in_defaults($Include)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006205 { # search for the nearest header
6206 # QtCore/qabstractanimation.h includes <QtCore/qobject.h>
6207 my $Candidate = joinPath(get_dirname($AbsDir), $Include);
6208 if(-f $Candidate) {
6209 $HPath = $Candidate;
6210 }
6211 }
6212 if(not $HPath) {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04006213 $HPath = identifyHeader($Include, $LibVersion);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006214 }
6215 next if(not $HPath);
6216 if($HPath eq $AbsPath) {
6217 next;
6218 }
Andrey Ponomarenko9927e332012-10-19 10:50:48 +04006219
6220 if($Debug)
6221 { # boundary headers
6222 #if($HPath=~/vtk/ and $AbsPath!~/vtk/)
6223 #{
6224 # print STDERR "$AbsPath -> $HPath\n";
6225 #}
6226 }
6227
Andrey Ponomarenko85043792012-05-14 16:48:07 +04006228 $RecursiveIncludes{$LibVersion}{$AbsPath}{$HPath} = $IncType;
6229 if($IncType>0)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006230 { # only include <...>, skip include "..." prefixes
6231 $Header_Include_Prefix{$LibVersion}{$AbsPath}{$HPath}{get_dirname($Include)} = 1;
6232 }
6233 foreach my $IncPath (detect_recursive_includes($HPath, $LibVersion))
6234 {
6235 if($IncPath eq $AbsPath) {
6236 next;
6237 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +04006238 my $RIncType = $RecursiveIncludes{$LibVersion}{$HPath}{$IncPath};
6239 if($RIncType==-1)
6240 { # include "..."
6241 $RIncType = $IncType;
6242 }
6243 elsif($RIncType==2)
6244 {
6245 if($IncType!=-1) {
6246 $RIncType = $IncType;
6247 }
6248 }
6249 $RecursiveIncludes{$LibVersion}{$AbsPath}{$IncPath} = $RIncType;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006250 foreach my $Prefix (keys(%{$Header_Include_Prefix{$LibVersion}{$HPath}{$IncPath}})) {
6251 $Header_Include_Prefix{$LibVersion}{$AbsPath}{$IncPath}{$Prefix} = 1;
6252 }
6253 }
6254 foreach my $Dep (keys(%{$Header_Include_Prefix{$LibVersion}{$AbsPath}}))
6255 {
6256 if($GlibcHeader{get_filename($Dep)} and keys(%{$Header_Include_Prefix{$LibVersion}{$AbsPath}{$Dep}})>=2
6257 and defined $Header_Include_Prefix{$LibVersion}{$AbsPath}{$Dep}{""})
6258 { # distinguish math.h from glibc and math.h from the tested library
6259 delete($Header_Include_Prefix{$LibVersion}{$AbsPath}{$Dep}{""});
6260 last;
6261 }
6262 }
6263 }
6264 pop(@RecurInclude);
6265 return keys(%{$RecursiveIncludes{$LibVersion}{$AbsPath}});
6266}
6267
6268sub find_in_framework($$$)
6269{
6270 my ($Header, $Framework, $LibVersion) = @_;
6271 return "" if(not $Header or not $Framework or not $LibVersion);
6272 if(defined $Cache{"find_in_framework"}{$LibVersion}{$Framework}{$Header}) {
6273 return $Cache{"find_in_framework"}{$LibVersion}{$Framework}{$Header};
6274 }
6275 foreach my $Dependency (sort {get_depth($a)<=>get_depth($b)} keys(%{$Header_Dependency{$LibVersion}}))
6276 {
6277 if(get_filename($Dependency) eq $Framework
6278 and -f get_dirname($Dependency)."/".$Header) {
6279 return ($Cache{"find_in_framework"}{$LibVersion}{$Framework}{$Header} = get_dirname($Dependency));
6280 }
6281 }
6282 return ($Cache{"find_in_framework"}{$LibVersion}{$Framework}{$Header} = "");
6283}
6284
6285sub find_in_defaults($)
6286{
6287 my $Header = $_[0];
6288 return "" if(not $Header);
6289 if(defined $Cache{"find_in_defaults"}{$Header}) {
6290 return $Cache{"find_in_defaults"}{$Header};
6291 }
Andrey Ponomarenko570ece52012-11-30 16:36:44 +04006292 foreach my $Dir (@DefaultIncPaths,
6293 @DefaultGccPaths,
6294 @DefaultCppPaths,
6295 @UsersIncPath)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006296 {
6297 next if(not $Dir);
6298 if(-f $Dir."/".$Header) {
6299 return ($Cache{"find_in_defaults"}{$Header}=$Dir);
6300 }
6301 }
6302 return ($Cache{"find_in_defaults"}{$Header}="");
6303}
6304
6305sub cmp_paths($$)
6306{
6307 my ($Path1, $Path2) = @_;
6308 my @Parts1 = split(/[\/\\]/, $Path1);
6309 my @Parts2 = split(/[\/\\]/, $Path2);
6310 foreach my $Num (0 .. $#Parts1)
6311 {
6312 my $Part1 = $Parts1[$Num];
6313 my $Part2 = $Parts2[$Num];
6314 if($GlibcDir{$Part1}
6315 and not $GlibcDir{$Part2}) {
6316 return 1;
6317 }
6318 elsif($GlibcDir{$Part2}
6319 and not $GlibcDir{$Part1}) {
6320 return -1;
6321 }
6322 elsif($Part1=~/glib/
6323 and $Part2!~/glib/) {
6324 return 1;
6325 }
6326 elsif($Part1!~/glib/
6327 and $Part2=~/glib/) {
6328 return -1;
6329 }
6330 elsif(my $CmpRes = ($Part1 cmp $Part2)) {
6331 return $CmpRes;
6332 }
6333 }
6334 return 0;
6335}
6336
6337sub checkRelevance($)
6338{
6339 my ($Path) = @_;
6340 return 0 if(not $Path);
6341 if($SystemRoot) {
Andrey Ponomarenkoa01311b2012-06-08 17:20:02 +04006342 $Path = cut_path_prefix($Path, $SystemRoot);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006343 }
6344 my ($Dir, $Name) = separate_path($Path);
Andrey Ponomarenkoa01311b2012-06-08 17:20:02 +04006345 $Name=~s/\.\w+\Z//g; # remove extension (.h)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006346 my @Tokens = split(/[_\d\W]+/, $Name);
6347 foreach (@Tokens)
6348 {
6349 next if(not $_);
6350 if($Dir=~/(\A|lib|[_\d\W])\Q$_\E([_\d\W]|lib|\Z)/i
6351 or length($_)>=4 and $Dir=~/\Q$_\E/i)
6352 { # include/gupnp-1.0/libgupnp/gupnp-context.h
6353 # include/evolution-data-server-1.4/libebook/e-book.h
6354 return 1;
6355 }
6356 }
6357 return 0;
6358}
6359
6360sub checkFamily(@)
6361{
6362 my @Paths = @_;
6363 return 1 if($#Paths<=0);
6364 my %Prefix = ();
6365 foreach my $Path (@Paths)
6366 {
6367 if($SystemRoot) {
6368 $Path = cut_path_prefix($Path, $SystemRoot);
6369 }
6370 if(my $Dir = get_dirname($Path))
6371 {
6372 $Dir=~s/(\/[^\/]+?)[\d\.\-\_]+\Z/$1/g; # remove version suffix
6373 $Prefix{$Dir} += 1;
6374 $Prefix{get_dirname($Dir)} += 1;
6375 }
6376 }
6377 foreach (sort keys(%Prefix))
6378 {
6379 if(get_depth($_)>=3
6380 and $Prefix{$_}==$#Paths+1) {
6381 return 1;
6382 }
6383 }
6384 return 0;
6385}
6386
6387sub isAcceptable($$$)
6388{
6389 my ($Header, $Candidate, $LibVersion) = @_;
6390 my $HName = get_filename($Header);
6391 if(get_dirname($Header))
6392 { # with prefix
6393 return 1;
6394 }
6395 if($HName=~/config|setup/i and $Candidate=~/[\/\\]lib\d*[\/\\]/)
6396 { # allow to search for glibconfig.h in /usr/lib/glib-2.0/include/
6397 return 1;
6398 }
6399 if(checkRelevance($Candidate))
6400 { # allow to search for atk.h in /usr/include/atk-1.0/atk/
6401 return 1;
6402 }
6403 if(checkFamily(getSystemHeaders($HName, $LibVersion)))
6404 { # /usr/include/qt4/QtNetwork/qsslconfiguration.h
6405 # /usr/include/qt4/Qt/qsslconfiguration.h
6406 return 1;
6407 }
6408 if($OStarget eq "symbian")
6409 {
6410 if($Candidate=~/[\/\\]stdapis[\/\\]/) {
6411 return 1;
6412 }
6413 }
6414 return 0;
6415}
6416
6417sub isRelevant($$$)
6418{ # disallow to search for "abstract" headers in too deep directories
6419 my ($Header, $Candidate, $LibVersion) = @_;
6420 my $HName = get_filename($Header);
6421 if($OStarget eq "symbian")
6422 {
6423 if($Candidate=~/[\/\\](tools|stlportv5)[\/\\]/) {
6424 return 0;
6425 }
6426 }
Andrey Ponomarenko9927e332012-10-19 10:50:48 +04006427 if($OStarget ne "bsd")
6428 {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006429 if($Candidate=~/[\/\\]include[\/\\]bsd[\/\\]/)
6430 { # openssh: skip /usr/lib/bcc/include/bsd/signal.h
6431 return 0;
6432 }
6433 }
Andrey Ponomarenko9927e332012-10-19 10:50:48 +04006434 if($OStarget ne "windows")
6435 {
6436 if($Candidate=~/[\/\\](wine|msvcrt|windows)[\/\\]/)
6437 { # skip /usr/include/wine/msvcrt
6438 return 0;
6439 }
6440 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006441 if(not get_dirname($Header)
6442 and $Candidate=~/[\/\\]wx[\/\\]/)
6443 { # do NOT search in system /wx/ directory
6444 # for headers without a prefix: sstream.h
6445 return 0;
6446 }
6447 if($Candidate=~/c\+\+[\/\\]\d+/ and $MAIN_CPP_DIR
6448 and $Candidate!~/\A\Q$MAIN_CPP_DIR\E/)
6449 { # skip ../c++/3.3.3/ if using ../c++/4.5/
6450 return 0;
6451 }
6452 if($Candidate=~/[\/\\]asm-/
6453 and (my $Arch = getArch($LibVersion)) ne "unknown")
6454 { # arch-specific header files
6455 if($Candidate!~/[\/\\]asm-\Q$Arch\E/)
6456 {# skip ../asm-arm/ if using x86 architecture
6457 return 0;
6458 }
6459 }
6460 my @Candidates = getSystemHeaders($HName, $LibVersion);
6461 if($#Candidates==1)
6462 { # unique header
6463 return 1;
6464 }
6465 my @SCandidates = getSystemHeaders($Header, $LibVersion);
6466 if($#SCandidates==1)
6467 { # unique name
6468 return 1;
6469 }
6470 my $SystemDepth = $SystemRoot?get_depth($SystemRoot):0;
6471 if(get_depth($Candidate)-$SystemDepth>=5)
6472 { # abstract headers in too deep directories
6473 # sstream.h or typeinfo.h in /usr/include/wx-2.9/wx/
6474 if(not isAcceptable($Header, $Candidate, $LibVersion)) {
6475 return 0;
6476 }
6477 }
6478 if($Header eq "parser.h"
6479 and $Candidate!~/\/libxml2\//)
6480 { # select parser.h from xml2 library
6481 return 0;
6482 }
6483 if(not get_dirname($Header)
6484 and keys(%{$SystemHeaders{$HName}})>=3)
6485 { # many headers with the same name
6486 # like thread.h included without a prefix
6487 if(not checkFamily(@Candidates)) {
6488 return 0;
6489 }
6490 }
6491 return 1;
6492}
6493
6494sub selectSystemHeader($$)
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04006495{ # cache function
6496 if(defined $Cache{"selectSystemHeader"}{$_[1]}{$_[0]}) {
6497 return $Cache{"selectSystemHeader"}{$_[1]}{$_[0]};
6498 }
6499 return ($Cache{"selectSystemHeader"}{$_[1]}{$_[0]} = selectSystemHeader_I(@_));
6500}
6501
6502sub selectSystemHeader_I($$)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006503{
6504 my ($Header, $LibVersion) = @_;
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04006505 if(-f $Header) {
6506 return $Header;
6507 }
6508 if(is_abs($Header) and not -f $Header)
6509 { # incorrect absolute path
6510 return "";
6511 }
Andrey Ponomarenko9927e332012-10-19 10:50:48 +04006512 if(defined $ConfHeaders{lc($Header)})
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04006513 { # too abstract configuration headers
6514 return "";
6515 }
Andrey Ponomarenko9927e332012-10-19 10:50:48 +04006516 my $HName = get_filename($Header);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006517 if($OSgroup ne "windows")
6518 {
Andrey Ponomarenko9927e332012-10-19 10:50:48 +04006519 if(defined $WinHeaders{lc($HName)}
6520 or $HName=~/windows|win32|win64/i)
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04006521 { # windows headers
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006522 return "";
6523 }
Andrey Ponomarenko9927e332012-10-19 10:50:48 +04006524 }
6525 if($OSgroup ne "macos")
6526 {
6527 if($HName eq "fp.h")
6528 { # pngconf.h includes fp.h for MACOS
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006529 return "";
6530 }
6531 }
6532 if($OSgroup ne "solaris")
6533 {
Andrey Ponomarenko9927e332012-10-19 10:50:48 +04006534 if($Header eq "thread.h") {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006535 return "";
6536 }
Andrey Ponomarenko570ece52012-11-30 16:36:44 +04006537 if($Header eq "sys/atomic.h") {
6538 return "";
6539 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006540 }
Andrey Ponomarenko07aea072012-11-12 16:15:07 +04006541 if($OSgroup ne "hpux")
6542 {
6543 if($Header eq "sys/stream.h") {
6544 return "";
6545 }
6546 }
Andrey Ponomarenko9927e332012-10-19 10:50:48 +04006547 if($ObsoleteHeaders{$HName}) {
6548 return "";
6549 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04006550
Andrey Ponomarenko570ece52012-11-30 16:36:44 +04006551 foreach my $Path (@{$SystemPaths{"include"}})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006552 { # search in default paths
6553 if(-f $Path."/".$Header) {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04006554 return joinPath($Path,$Header);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006555 }
6556 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04006557 if(not keys(%SystemHeaders))
6558 { # register all headers in system include dirs
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006559 detectSystemHeaders();
6560 }
6561 foreach my $Candidate (sort {get_depth($a)<=>get_depth($b)}
6562 sort {cmp_paths($b, $a)} getSystemHeaders($Header, $LibVersion))
6563 {
6564 if(isRelevant($Header, $Candidate, $LibVersion)) {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04006565 return $Candidate;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006566 }
6567 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04006568 # error
6569 return "";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006570}
6571
6572sub getSystemHeaders($$)
6573{
6574 my ($Header, $LibVersion) = @_;
6575 my @Candidates = ();
6576 foreach my $Candidate (sort keys(%{$SystemHeaders{$Header}}))
6577 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04006578 if(skipHeader($Candidate, $LibVersion)) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006579 next;
6580 }
6581 push(@Candidates, $Candidate);
6582 }
6583 return @Candidates;
6584}
6585
6586sub cut_path_prefix($$)
6587{
6588 my ($Path, $Prefix) = @_;
6589 return $Path if(not $Prefix);
6590 $Prefix=~s/[\/\\]+\Z//;
6591 $Path=~s/\A\Q$Prefix\E([\/\\]+|\Z)//;
6592 return $Path;
6593}
6594
6595sub is_default_include_dir($)
6596{
6597 my $Dir = $_[0];
6598 $Dir=~s/[\/\\]+\Z//;
Andrey Ponomarenko570ece52012-11-30 16:36:44 +04006599 return grep { $Dir eq $_ } (@DefaultGccPaths, @DefaultCppPaths, @DefaultIncPaths);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006600}
6601
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04006602sub identifyHeader($$)
6603{ # cache function
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006604 my ($Header, $LibVersion) = @_;
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04006605 if(not $Header) {
6606 return "";
6607 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006608 $Header=~s/\A(\.\.[\\\/])+//g;
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04006609 if(defined $Cache{"identifyHeader"}{$LibVersion}{$Header}) {
6610 return $Cache{"identifyHeader"}{$LibVersion}{$Header};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006611 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04006612 return ($Cache{"identifyHeader"}{$LibVersion}{$Header} = identifyHeader_I($Header, $LibVersion));
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006613}
6614
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04006615sub identifyHeader_I($$)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006616{ # search for header by absolute path, relative path or name
6617 my ($Header, $LibVersion) = @_;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006618 if(-f $Header)
6619 { # it's relative or absolute path
6620 return get_abs_path($Header);
6621 }
6622 elsif($GlibcHeader{$Header} and not $GLIBC_TESTING
6623 and my $HeaderDir = find_in_defaults($Header))
6624 { # search for libc headers in the /usr/include
6625 # for non-libc target library before searching
6626 # in the library paths
6627 return joinPath($HeaderDir,$Header);
6628 }
6629 elsif(my $Path = $Include_Neighbors{$LibVersion}{$Header})
6630 { # search in the target library paths
6631 return $Path;
6632 }
Andrey Ponomarenko570ece52012-11-30 16:36:44 +04006633 elsif(defined $DefaultGccHeader{$Header})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006634 { # search in the internal GCC include paths
6635 return $DefaultGccHeader{$Header};
6636 }
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04006637 elsif(my $DefaultDir = find_in_defaults($Header))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006638 { # search in the default GCC include paths
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04006639 return joinPath($DefaultDir,$Header);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006640 }
Andrey Ponomarenko570ece52012-11-30 16:36:44 +04006641 elsif(defined $DefaultCppHeader{$Header})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006642 { # search in the default G++ include paths
6643 return $DefaultCppHeader{$Header};
6644 }
6645 elsif(my $AnyPath = selectSystemHeader($Header, $LibVersion))
6646 { # search everywhere in the system
6647 return $AnyPath;
6648 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04006649 elsif($OSgroup eq "macos")
6650 { # search in frameworks: "OpenGL/gl.h" is "OpenGL.framework/Headers/gl.h"
6651 if(my $Dir = get_dirname($Header))
6652 {
6653 my $RelPath = "Headers\/".get_filename($Header);
6654 if(my $HeaderDir = find_in_framework($RelPath, $Dir.".framework", $LibVersion)) {
6655 return joinPath($HeaderDir, $RelPath);
6656 }
6657 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006658 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04006659 # cannot find anything
6660 return "";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006661}
6662
6663sub getLocation($)
6664{
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04006665 if($_[0] and my $Info = $LibInfo{$Version}{"info"}{$_[0]})
6666 {
6667 if($Info=~/srcp[ ]*:[ ]*([\w\-\<\>\.\+\/\\]+):(\d+) /) {
Andrey Ponomarenko9927e332012-10-19 10:50:48 +04006668 return (path_format($1, $OSgroup), $2);
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04006669 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006670 }
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04006671 return ();
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006672}
6673
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006674sub getNameByInfo($)
6675{
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04006676 if($_[0] and my $Info = $LibInfo{$Version}{"info"}{$_[0]})
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04006677 {
6678 if($Info=~/name[ ]*:[ ]*@(\d+) /)
6679 {
6680 if(my $NInfo = $LibInfo{$Version}{"info"}{$1})
6681 {
6682 if($NInfo=~/strg[ ]*:[ ]*(.*?)[ ]+lngt/)
6683 { # short unsigned int (may include spaces)
6684 return $1;
6685 }
6686 }
6687 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006688 }
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04006689 return "";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006690}
6691
6692sub getTreeStr($)
6693{
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04006694 if($_[0] and my $Info = $LibInfo{$Version}{"info"}{$_[0]})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006695 {
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04006696 if($Info=~/strg[ ]*:[ ]*([^ ]*)/)
6697 {
6698 my $Str = $1;
Andrey Ponomarenko07aea072012-11-12 16:15:07 +04006699 if($CppMode{$Version}
Andrey Ponomarenko570ece52012-11-30 16:36:44 +04006700 and $Str=~/\Ac99_(.+)\Z/)
6701 {
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04006702 if($CppKeywords_A{$1}) {
6703 $Str=$1;
6704 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006705 }
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04006706 return $Str;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006707 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006708 }
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04006709 return "";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006710}
6711
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006712sub getFuncShortName($)
6713{
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04006714 if(my $Info = $LibInfo{$Version}{"info"}{$_[0]})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006715 {
Andrey Ponomarenko570ece52012-11-30 16:36:44 +04006716 if(index($Info, " operator ")!=-1)
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04006717 {
Andrey Ponomarenko570ece52012-11-30 16:36:44 +04006718 if(index($Info, " conversion ")!=-1)
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04006719 {
6720 if(my $Rid = $SymbolInfo{$Version}{$_[0]}{"Return"})
6721 {
6722 if(my $RName = $TypeInfo{$Version}{$Rid}{"Name"}) {
6723 return "operator ".$RName;
6724 }
6725 }
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04006726 }
6727 else
6728 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04006729 if($Info=~/ operator[ ]+([a-zA-Z]+) /)
6730 {
6731 if(my $Ind = $Operator_Indication{$1}) {
6732 return "operator".$Ind;
6733 }
6734 elsif(not $UnknownOperator{$1})
6735 {
6736 printMsg("WARNING", "unknown operator $1");
6737 $UnknownOperator{$1} = 1;
6738 }
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04006739 }
6740 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006741 }
6742 else
6743 {
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04006744 if($Info=~/name[ ]*:[ ]*@(\d+) /) {
6745 return getTreeStr($1);
6746 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006747 }
6748 }
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04006749 return "";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006750}
6751
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006752sub getFuncReturn($)
6753{
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04006754 if($_[0] and my $Info = $LibInfo{$Version}{"info"}{$_[0]})
6755 {
6756 if($Info=~/type[ ]*:[ ]*@(\d+) /)
6757 {
6758 if($LibInfo{$Version}{"info"}{$1}=~/retn[ ]*:[ ]*@(\d+) /) {
6759 return $1;
6760 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006761 }
6762 }
6763 return "";
6764}
6765
6766sub getFuncOrig($)
6767{
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04006768 if($_[0] and my $Info = $LibInfo{$Version}{"info"}{$_[0]})
6769 {
6770 if($Info=~/orig[ ]*:[ ]*@(\d+) /) {
6771 return $1;
6772 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006773 }
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04006774 return $_[0];
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006775}
6776
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006777sub unmangleArray(@)
6778{
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04006779 if($_[0]=~/\A\?/)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006780 { # MSVC mangling
6781 my $UndNameCmd = get_CmdPath("undname");
6782 if(not $UndNameCmd) {
6783 exitStatus("Not_Found", "can't find \"undname\"");
6784 }
6785 writeFile("$TMP_DIR/unmangle", join("\n", @_));
Andrey Ponomarenkoa01311b2012-06-08 17:20:02 +04006786 return split(/\n/, `$UndNameCmd 0x8386 \"$TMP_DIR/unmangle\"`);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006787 }
6788 else
6789 { # GCC mangling
6790 my $CppFiltCmd = get_CmdPath("c++filt");
6791 if(not $CppFiltCmd) {
6792 exitStatus("Not_Found", "can't find c++filt in PATH");
6793 }
Andrey Ponomarenko9927e332012-10-19 10:50:48 +04006794 if(not defined $CPPFILT_SUPPORT_FILE)
6795 {
6796 my $Info = `$CppFiltCmd -h 2>&1`;
6797 $CPPFILT_SUPPORT_FILE = $Info=~/\@<file>/;
6798 }
Andrey Ponomarenko570ece52012-11-30 16:36:44 +04006799 my $NoStrip = ($OSgroup=~/macos|windows/)?"-n":"";
Andrey Ponomarenko9927e332012-10-19 10:50:48 +04006800 if($CPPFILT_SUPPORT_FILE)
6801 { # new versions of c++filt can take a file
6802 if($#_>$MAX_CPPFILT_FILE_SIZE)
6803 { # c++filt <= 2.22 may crash on large files (larger than 8mb)
6804 # this is fixed in the oncoming version of Binutils
6805 my @Half = splice(@_, 0, ($#_+1)/2);
6806 return (unmangleArray(@Half), unmangleArray(@_))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006807 }
Andrey Ponomarenko9927e332012-10-19 10:50:48 +04006808 else
6809 {
Andrey Ponomarenko9927e332012-10-19 10:50:48 +04006810 writeFile("$TMP_DIR/unmangle", join("\n", @_));
6811 my $Res = `$CppFiltCmd $NoStrip \@\"$TMP_DIR/unmangle\"`;
6812 if($?==139)
6813 { # segmentation fault
6814 printMsg("ERROR", "internal error - c++filt crashed, try to reduce MAX_CPPFILT_FILE_SIZE constant");
6815 }
6816 return split(/\n/, $Res);
6817 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006818 }
6819 else
6820 { # old-style unmangling
Andrey Ponomarenko9927e332012-10-19 10:50:48 +04006821 if($#_>$MAX_COMMAND_LINE_ARGUMENTS)
6822 {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006823 my @Half = splice(@_, 0, ($#_+1)/2);
6824 return (unmangleArray(@Half), unmangleArray(@_))
6825 }
6826 else
6827 {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006828 my $Strings = join(" ", @_);
Andrey Ponomarenko9927e332012-10-19 10:50:48 +04006829 my $Res = `$CppFiltCmd $NoStrip $Strings`;
6830 if($?==139)
6831 { # segmentation fault
6832 printMsg("ERROR", "internal error - c++filt crashed, try to reduce MAX_COMMAND_LINE_ARGUMENTS constant");
6833 }
6834 return split(/\n/, $Res);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006835 }
6836 }
6837 }
6838}
6839
6840sub get_SignatureNoInfo($$)
6841{
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04006842 my ($Symbol, $LibVersion) = @_;
6843 if($Cache{"get_SignatureNoInfo"}{$LibVersion}{$Symbol}) {
6844 return $Cache{"get_SignatureNoInfo"}{$LibVersion}{$Symbol};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006845 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04006846 my ($MnglName, $VersionSpec, $SymbolVersion) = separate_symbol($Symbol);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006847 my $Signature = $tr_name{$MnglName}?$tr_name{$MnglName}:$MnglName;
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04006848 if($Symbol=~/\A(_Z|\?)/)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006849 { # C++
Andrey Ponomarenko1477d2c2012-11-12 18:55:45 +04006850 # some standard typedefs
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006851 $Signature=~s/\Qstd::basic_string<char, std::char_traits<char>, std::allocator<char> >\E/std::string/g;
6852 $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;
6853 }
Andrey Ponomarenko82b005f2012-11-12 17:58:14 +04006854 if(not $CheckObjectsOnly or $OSgroup=~/linux|bsd|beos/i)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006855 { # ELF format marks data as OBJECT
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04006856 if($GlobalDataObject{$LibVersion}{$Symbol}) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006857 $Signature .= " [data]";
6858 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04006859 elsif($Symbol!~/\A(_Z|\?)/) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006860 $Signature .= " (...)";
6861 }
6862 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04006863 if(my $ChargeLevel = get_ChargeLevel($Symbol, $LibVersion))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006864 {
Andrey Ponomarenko16934472012-03-29 15:37:04 +04006865 my $ShortName = substr($Signature, 0, find_center($Signature, "("));
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006866 $Signature=~s/\A\Q$ShortName\E/$ShortName $ChargeLevel/g;
6867 }
6868 if($SymbolVersion) {
6869 $Signature .= $VersionSpec.$SymbolVersion;
6870 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04006871 return ($Cache{"get_SignatureNoInfo"}{$LibVersion}{$Symbol} = $Signature);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006872}
6873
6874sub get_ChargeLevel($$)
6875{
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04006876 my ($Symbol, $LibVersion) = @_;
6877 return "" if($Symbol!~/\A(_Z|\?)/);
6878 if(defined $CompleteSignature{$LibVersion}{$Symbol}
6879 and $CompleteSignature{$LibVersion}{$Symbol}{"Header"})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006880 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04006881 if($CompleteSignature{$LibVersion}{$Symbol}{"Constructor"})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006882 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04006883 if($Symbol=~/C1E/) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006884 return "[in-charge]";
6885 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04006886 elsif($Symbol=~/C2E/) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006887 return "[not-in-charge]";
6888 }
6889 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04006890 elsif($CompleteSignature{$LibVersion}{$Symbol}{"Destructor"})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006891 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04006892 if($Symbol=~/D1E/) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006893 return "[in-charge]";
6894 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04006895 elsif($Symbol=~/D2E/) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006896 return "[not-in-charge]";
6897 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04006898 elsif($Symbol=~/D0E/) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006899 return "[in-charge-deleting]";
6900 }
6901 }
6902 }
6903 else
6904 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04006905 if($Symbol=~/C1E/) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006906 return "[in-charge]";
6907 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04006908 elsif($Symbol=~/C2E/) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006909 return "[not-in-charge]";
6910 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04006911 elsif($Symbol=~/D1E/) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006912 return "[in-charge]";
6913 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04006914 elsif($Symbol=~/D2E/) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006915 return "[not-in-charge]";
6916 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04006917 elsif($Symbol=~/D0E/) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006918 return "[in-charge-deleting]";
6919 }
6920 }
6921 return "";
6922}
6923
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04006924sub get_Signature_M($$)
6925{
6926 my ($Symbol, $LibVersion) = @_;
6927 my $Signature_M = $tr_name{$Symbol};
6928 if(my $RTid = $CompleteSignature{$LibVersion}{$Symbol}{"Return"})
6929 { # add return type name
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04006930 $Signature_M = $TypeInfo{$LibVersion}{$RTid}{"Name"}." ".$Signature_M;
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04006931 }
6932 return $Signature_M;
6933}
6934
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006935sub get_Signature($$)
6936{
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04006937 my ($Symbol, $LibVersion) = @_;
6938 if($Cache{"get_Signature"}{$LibVersion}{$Symbol}) {
6939 return $Cache{"get_Signature"}{$LibVersion}{$Symbol};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006940 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04006941 my ($MnglName, $VersionSpec, $SymbolVersion) = separate_symbol($Symbol);
6942 if(isPrivateData($MnglName) or not $CompleteSignature{$LibVersion}{$Symbol}{"Header"})
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04006943 { # non-public global data
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04006944 return get_SignatureNoInfo($Symbol, $LibVersion);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006945 }
6946 my ($Func_Signature, @Param_Types_FromUnmangledName) = ();
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04006947 my $ShortName = $CompleteSignature{$LibVersion}{$Symbol}{"ShortName"};
6948 if($Symbol=~/\A(_Z|\?)/)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006949 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04006950 if(my $ClassId = $CompleteSignature{$LibVersion}{$Symbol}{"Class"}) {
6951 $Func_Signature = $TypeInfo{$LibVersion}{$ClassId}{"Name"}."::".(($CompleteSignature{$LibVersion}{$Symbol}{"Destructor"})?"~":"").$ShortName;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006952 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04006953 elsif(my $NameSpace = $CompleteSignature{$LibVersion}{$Symbol}{"NameSpace"}) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006954 $Func_Signature = $NameSpace."::".$ShortName;
6955 }
6956 else {
6957 $Func_Signature = $ShortName;
6958 }
Andrey Ponomarenko07aea072012-11-12 16:15:07 +04006959 my ($Short, $Params) = split_Signature($tr_name{$MnglName});
6960 @Param_Types_FromUnmangledName = separate_Params($Params, 0, 1);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006961 }
6962 else {
6963 $Func_Signature = $MnglName;
6964 }
6965 my @ParamArray = ();
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04006966 foreach my $Pos (sort {int($a) <=> int($b)} keys(%{$CompleteSignature{$LibVersion}{$Symbol}{"Param"}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006967 {
6968 next if($Pos eq "");
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04006969 my $ParamTypeId = $CompleteSignature{$LibVersion}{$Symbol}{"Param"}{$Pos}{"type"};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006970 next if(not $ParamTypeId);
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04006971 my $ParamTypeName = $TypeInfo{$LibVersion}{$ParamTypeId}{"Name"};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006972 if(not $ParamTypeName) {
6973 $ParamTypeName = $Param_Types_FromUnmangledName[$Pos];
6974 }
6975 foreach my $Typedef (keys(%ChangedTypedef))
6976 {
6977 my $Base = $Typedef_BaseName{$LibVersion}{$Typedef};
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04006978 $ParamTypeName=~s/\b\Q$Typedef\E\b/$Base/g;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006979 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04006980 if(my $ParamName = $CompleteSignature{$LibVersion}{$Symbol}{"Param"}{$Pos}{"name"}) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006981 push(@ParamArray, create_member_decl($ParamTypeName, $ParamName));
6982 }
6983 else {
6984 push(@ParamArray, $ParamTypeName);
6985 }
6986 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04006987 if($CompleteSignature{$LibVersion}{$Symbol}{"Data"}
6988 or $GlobalDataObject{$LibVersion}{$Symbol}) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006989 $Func_Signature .= " [data]";
6990 }
6991 else
6992 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04006993 if(my $ChargeLevel = get_ChargeLevel($Symbol, $LibVersion))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006994 { # add [in-charge]
6995 $Func_Signature .= " ".$ChargeLevel;
6996 }
6997 $Func_Signature .= " (".join(", ", @ParamArray).")";
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04006998 if($CompleteSignature{$LibVersion}{$Symbol}{"Const"}
6999 or $Symbol=~/\A_ZN(V|)K/) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007000 $Func_Signature .= " const";
7001 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04007002 if($CompleteSignature{$LibVersion}{$Symbol}{"Volatile"}
7003 or $Symbol=~/\A_ZN(K|)V/) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007004 $Func_Signature .= " volatile";
7005 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04007006 if($CompleteSignature{$LibVersion}{$Symbol}{"Static"}
7007 and $Symbol=~/\A(_Z|\?)/)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007008 {# for static methods
7009 $Func_Signature .= " [static]";
7010 }
7011 }
7012 if(defined $ShowRetVal
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04007013 and my $ReturnTId = $CompleteSignature{$LibVersion}{$Symbol}{"Return"}) {
7014 $Func_Signature .= ":".$TypeInfo{$LibVersion}{$ReturnTId}{"Name"};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007015 }
7016 if($SymbolVersion) {
7017 $Func_Signature .= $VersionSpec.$SymbolVersion;
7018 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04007019 return ($Cache{"get_Signature"}{$LibVersion}{$Symbol} = $Func_Signature);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007020}
7021
7022sub create_member_decl($$)
7023{
7024 my ($TName, $Member) = @_;
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04007025 if($TName=~/\([\*]+\)/)
7026 {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007027 $TName=~s/\(([\*]+)\)/\($1$Member\)/;
7028 return $TName;
7029 }
7030 else
7031 {
7032 my @ArraySizes = ();
7033 while($TName=~s/(\[[^\[\]]*\])\Z//) {
7034 push(@ArraySizes, $1);
7035 }
7036 return $TName." ".$Member.join("", @ArraySizes);
7037 }
7038}
7039
7040sub getFuncType($)
7041{
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04007042 if($_[0] and my $Info = $LibInfo{$Version}{"info"}{$_[0]})
7043 {
7044 if($Info=~/type[ ]*:[ ]*@(\d+) /)
7045 {
7046 if(my $Type = $LibInfo{$Version}{"info_type"}{$1})
7047 {
7048 if($Type eq "method_type") {
7049 return "Method";
7050 }
7051 elsif($Type eq "function_type") {
7052 return "Function";
7053 }
7054 else {
7055 return "Other";
7056 }
7057 }
7058 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007059 }
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +04007060 return "";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007061}
7062
7063sub getFuncTypeId($)
7064{
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04007065 if($_[0] and my $Info = $LibInfo{$Version}{"info"}{$_[0]})
7066 {
7067 if($Info=~/type[ ]*:[ ]*@(\d+)( |\Z)/) {
7068 return $1;
7069 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007070 }
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04007071 return 0;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007072}
7073
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007074sub isAnon($)
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04007075{ # "._N" or "$_N" in older GCC versions
7076 return ($_[0] and $_[0]=~/(\.|\$)\_\d+|anon\-/);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007077}
7078
Andrey Ponomarenko9927e332012-10-19 10:50:48 +04007079sub formatName($$)
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04007080{ # type name correction
Andrey Ponomarenko9927e332012-10-19 10:50:48 +04007081 if(defined $Cache{"formatName"}{$_[1]}{$_[0]}) {
7082 return $Cache{"formatName"}{$_[1]}{$_[0]};
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04007083 }
7084
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +04007085 my $N = $_[0];
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04007086
Andrey Ponomarenko9927e332012-10-19 10:50:48 +04007087 if($_[1] ne "S")
7088 {
7089 $N=~s/\A[ ]+//g;
7090 $N=~s/[ ]+\Z//g;
7091 $N=~s/[ ]{2,}/ /g;
7092 }
7093
7094 $N=~s/[ ]*(\W)[ ]*/$1/g; # std::basic_string<char> const
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04007095
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +04007096 $N=~s/\bvolatile const\b/const volatile/g;
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04007097
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +04007098 $N=~s/\b(long long|short|long) unsigned\b/unsigned $1/g;
7099 $N=~s/\b(short|long) int\b/$1/g;
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04007100
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +04007101 $N=~s/([\)\]])(const|volatile)\b/$1 $2/g;
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04007102
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +04007103 while($N=~s/>>/> >/g) {};
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04007104
Andrey Ponomarenko9927e332012-10-19 10:50:48 +04007105 if($_[1] eq "S")
7106 {
7107 if(index($N, "operator")!=-1) {
7108 $N=~s/\b(operator[ ]*)> >/$1>>/;
7109 }
7110 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04007111
Andrey Ponomarenko9927e332012-10-19 10:50:48 +04007112 return ($Cache{"formatName"}{$_[1]}{$_[0]} = $N);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007113}
7114
7115sub get_HeaderDeps($$)
7116{
7117 my ($AbsPath, $LibVersion) = @_;
7118 return () if(not $AbsPath or not $LibVersion);
7119 if(defined $Cache{"get_HeaderDeps"}{$LibVersion}{$AbsPath}) {
7120 return @{$Cache{"get_HeaderDeps"}{$LibVersion}{$AbsPath}};
7121 }
7122 my %IncDir = ();
7123 detect_recursive_includes($AbsPath, $LibVersion);
7124 foreach my $HeaderPath (keys(%{$RecursiveIncludes{$LibVersion}{$AbsPath}}))
7125 {
7126 next if(not $HeaderPath);
7127 next if($MAIN_CPP_DIR and $HeaderPath=~/\A\Q$MAIN_CPP_DIR\E([\/\\]|\Z)/);
7128 my $Dir = get_dirname($HeaderPath);
7129 foreach my $Prefix (keys(%{$Header_Include_Prefix{$LibVersion}{$AbsPath}{$HeaderPath}}))
7130 {
7131 my $Dep = $Dir;
7132 if($Prefix)
7133 {
7134 if($OSgroup eq "windows")
7135 { # case insensitive seach on windows
7136 if(not $Dep=~s/[\/\\]+\Q$Prefix\E\Z//ig) {
7137 next;
7138 }
7139 }
7140 elsif($OSgroup eq "macos")
7141 { # seach in frameworks
7142 if(not $Dep=~s/[\/\\]+\Q$Prefix\E\Z//g)
7143 {
7144 if($HeaderPath=~/(.+\.framework)\/Headers\/([^\/]+)/)
7145 {# frameworks
7146 my ($HFramework, $HName) = ($1, $2);
7147 $Dep = $HFramework;
7148 }
7149 else
7150 {# mismatch
7151 next;
7152 }
7153 }
7154 }
7155 elsif(not $Dep=~s/[\/\\]+\Q$Prefix\E\Z//g)
7156 { # Linux, FreeBSD
7157 next;
7158 }
7159 }
7160 if(not $Dep)
7161 { # nothing to include
7162 next;
7163 }
7164 if(is_default_include_dir($Dep))
7165 { # included by the compiler
7166 next;
7167 }
7168 if(get_depth($Dep)==1)
7169 { # too short
7170 next;
7171 }
7172 if(isLibcDir($Dep))
7173 { # do NOT include /usr/include/{sys,bits}
7174 next;
7175 }
Andrey Ponomarenko570ece52012-11-30 16:36:44 +04007176 $IncDir{$Dep} = 1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007177 }
7178 }
7179 $Cache{"get_HeaderDeps"}{$LibVersion}{$AbsPath} = sortIncPaths([keys(%IncDir)], $LibVersion);
7180 return @{$Cache{"get_HeaderDeps"}{$LibVersion}{$AbsPath}};
7181}
7182
7183sub sortIncPaths($$)
7184{
7185 my ($ArrRef, $LibVersion) = @_;
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04007186 if(not $ArrRef or $#{$ArrRef}<0) {
7187 return $ArrRef;
7188 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007189 @{$ArrRef} = sort {$b cmp $a} @{$ArrRef};
7190 @{$ArrRef} = sort {get_depth($a)<=>get_depth($b)} @{$ArrRef};
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04007191 @{$ArrRef} = sort {sortDeps($b, $a, $LibVersion)} @{$ArrRef};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007192 return $ArrRef;
7193}
7194
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04007195sub sortDeps($$$)
7196{
7197 if($Header_Dependency{$_[2]}{$_[0]}
7198 and not $Header_Dependency{$_[2]}{$_[1]}) {
7199 return 1;
7200 }
7201 elsif(not $Header_Dependency{$_[2]}{$_[0]}
7202 and $Header_Dependency{$_[2]}{$_[1]}) {
7203 return -1;
7204 }
7205 return 0;
7206}
7207
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007208sub joinPath($$) {
7209 return join($SLASH, @_);
7210}
7211
7212sub get_namespace_additions($)
7213{
7214 my $NameSpaces = $_[0];
7215 my ($Additions, $AddNameSpaceId) = ("", 1);
7216 foreach my $NS (sort {$a=~/_/ <=> $b=~/_/} sort {lc($a) cmp lc($b)} keys(%{$NameSpaces}))
7217 {
7218 next if($SkipNameSpaces{$Version}{$NS});
7219 next if(not $NS or $NameSpaces->{$NS}==-1);
7220 next if($NS=~/(\A|::)iterator(::|\Z)/i);
7221 next if($NS=~/\A__/i);
7222 next if(($NS=~/\Astd::/ or $NS=~/\A(std|tr1|rel_ops|fcntl)\Z/) and not $STDCXX_TESTING);
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04007223 $NestedNameSpaces{$Version}{$NS} = 1; # for future use in reports
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007224 my ($TypeDecl_Prefix, $TypeDecl_Suffix) = ();
7225 my @NS_Parts = split(/::/, $NS);
7226 next if($#NS_Parts==-1);
7227 next if($NS_Parts[0]=~/\A(random|or)\Z/);
7228 foreach my $NS_Part (@NS_Parts)
7229 {
7230 $TypeDecl_Prefix .= "namespace $NS_Part\{";
7231 $TypeDecl_Suffix .= "}";
7232 }
7233 my $TypeDecl = $TypeDecl_Prefix."typedef int tmp_add_type_$AddNameSpaceId;".$TypeDecl_Suffix;
7234 my $FuncDecl = "$NS\:\:tmp_add_type_$AddNameSpaceId tmp_add_func_$AddNameSpaceId(){return 0;};";
7235 $Additions.=" $TypeDecl\n $FuncDecl\n";
7236 $AddNameSpaceId+=1;
7237 }
7238 return $Additions;
7239}
7240
7241sub path_format($$)
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04007242{ # forward slash to pass into MinGW GCC
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007243 my ($Path, $Fmt) = @_;
Andrey Ponomarenko570ece52012-11-30 16:36:44 +04007244 $Path=~s/[\/\\]+\Z//;
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04007245 if($Fmt eq "windows")
7246 {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007247 $Path=~s/\//\\/g;
7248 $Path=lc($Path);
7249 }
7250 else {
7251 $Path=~s/\\/\//g;
7252 }
7253 return $Path;
7254}
7255
7256sub inc_opt($$)
7257{
7258 my ($Path, $Style) = @_;
7259 if($Style eq "GCC")
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04007260 { # GCC options
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007261 if($OSgroup eq "windows")
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04007262 { # to MinGW GCC
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007263 return "-I\"".path_format($Path, "unix")."\"";
7264 }
7265 elsif($OSgroup eq "macos"
7266 and $Path=~/\.framework\Z/)
Andrey Ponomarenko570ece52012-11-30 16:36:44 +04007267 { # to Apple's GCC
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007268 return "-F".esc(get_dirname($Path));
7269 }
7270 else {
7271 return "-I".esc($Path);
7272 }
7273 }
7274 elsif($Style eq "CL") {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04007275 return "/I \"".$Path."\"";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007276 }
7277 return "";
7278}
7279
7280sub platformSpecs($)
7281{
7282 my $LibVersion = $_[0];
7283 my $Arch = getArch($LibVersion);
7284 if($OStarget eq "symbian")
7285 { # options for GCCE compiler
7286 my %Symbian_Opts = map {$_=>1} (
7287 "-D__GCCE__",
7288 "-DUNICODE",
7289 "-fexceptions",
7290 "-D__SYMBIAN32__",
7291 "-D__MARM_INTERWORK__",
7292 "-D_UNICODE",
7293 "-D__S60_50__",
7294 "-D__S60_3X__",
7295 "-D__SERIES60_3X__",
7296 "-D__EPOC32__",
7297 "-D__MARM__",
7298 "-D__EABI__",
7299 "-D__MARM_ARMV5__",
7300 "-D__SUPPORT_CPP_EXCEPTIONS__",
7301 "-march=armv5t",
7302 "-mapcs",
7303 "-mthumb-interwork",
7304 "-DEKA2",
7305 "-DSYMBIAN_ENABLE_SPLIT_HEADERS"
7306 );
7307 return join(" ", keys(%Symbian_Opts));
7308 }
7309 elsif($OSgroup eq "windows"
7310 and get_dumpmachine($GCC_PATH)=~/mingw/i)
7311 { # add options to MinGW compiler
7312 # to simulate the MSVC compiler
7313 my %MinGW_Opts = map {$_=>1} (
7314 "-D_WIN32",
7315 "-D_STDCALL_SUPPORTED",
7316 "-D__int64=\"long long\"",
7317 "-D__int32=int",
7318 "-D__int16=short",
7319 "-D__int8=char",
7320 "-D__possibly_notnullterminated=\" \"",
7321 "-D__nullterminated=\" \"",
7322 "-D__nullnullterminated=\" \"",
7323 "-D__w64=\" \"",
7324 "-D__ptr32=\" \"",
7325 "-D__ptr64=\" \"",
7326 "-D__forceinline=inline",
7327 "-D__inline=inline",
7328 "-D__uuidof(x)=IID()",
7329 "-D__try=",
7330 "-D__except(x)=",
7331 "-D__declspec(x)=__attribute__((x))",
7332 "-D__pragma(x)=",
7333 "-D_inline=inline",
7334 "-D__forceinline=__inline",
7335 "-D__stdcall=__attribute__((__stdcall__))",
7336 "-D__cdecl=__attribute__((__cdecl__))",
7337 "-D__fastcall=__attribute__((__fastcall__))",
7338 "-D__thiscall=__attribute__((__thiscall__))",
7339 "-D_stdcall=__attribute__((__stdcall__))",
7340 "-D_cdecl=__attribute__((__cdecl__))",
7341 "-D_fastcall=__attribute__((__fastcall__))",
7342 "-D_thiscall=__attribute__((__thiscall__))",
7343 "-DSHSTDAPI_(x)=x",
7344 "-D_MSC_EXTENSIONS",
7345 "-DSECURITY_WIN32",
7346 "-D_MSC_VER=1500",
7347 "-D_USE_DECLSPECS_FOR_SAL",
7348 "-D__noop=\" \"",
7349 "-DDECLSPEC_DEPRECATED=\" \"",
7350 "-D__builtin_alignof(x)=__alignof__(x)",
7351 "-DSORTPP_PASS");
7352 if($Arch eq "x86") {
7353 $MinGW_Opts{"-D_M_IX86=300"}=1;
7354 }
7355 elsif($Arch eq "x86_64") {
7356 $MinGW_Opts{"-D_M_AMD64=300"}=1;
7357 }
7358 elsif($Arch eq "ia64") {
7359 $MinGW_Opts{"-D_M_IA64=300"}=1;
7360 }
7361 return join(" ", keys(%MinGW_Opts));
7362 }
7363 return "";
7364}
7365
7366my %C_Structure = map {$_=>1} (
7367# FIXME: Can't separate union and struct data types before dumping,
7368# so it sometimes cause compilation errors for unknown reason
7369# when trying to declare TYPE* tmp_add_class_N
7370# This is a list of such structures + list of other C structures
7371 "sigval",
7372 "sigevent",
7373 "sigaction",
7374 "sigvec",
7375 "sigstack",
7376 "timeval",
7377 "timezone",
7378 "rusage",
7379 "rlimit",
7380 "wait",
7381 "flock",
7382 "stat",
7383 "_stat",
7384 "stat32",
7385 "_stat32",
7386 "stat64",
7387 "_stat64",
7388 "_stati64",
7389 "if_nameindex",
7390 "usb_device",
7391 "sigaltstack",
7392 "sysinfo",
7393 "timeLocale",
7394 "tcp_debug",
7395 "rpc_createerr",
Andrey Ponomarenko82b005f2012-11-12 17:58:14 +04007396 # Other
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007397 "timespec",
7398 "random_data",
7399 "drand48_data",
7400 "_IO_marker",
7401 "_IO_FILE",
7402 "lconv",
7403 "sched_param",
7404 "tm",
7405 "itimerspec",
7406 "_pthread_cleanup_buffer",
7407 "fd_set",
Andrey Ponomarenko01117f12012-06-26 12:23:02 +04007408 "siginfo",
Andrey Ponomarenko82b005f2012-11-12 17:58:14 +04007409 "mallinfo",
Andrey Ponomarenko570ece52012-11-30 16:36:44 +04007410 "timex",
Andrey Ponomarenko82b005f2012-11-12 17:58:14 +04007411 # Mac
7412 "_timex",
7413 "_class_t",
7414 "_category_t",
7415 "_class_ro_t",
7416 "_protocol_t",
7417 "_message_ref_t",
7418 "_super_message_ref_t",
7419 "_ivar_t",
7420 "_ivar_list_t"
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007421);
7422
7423sub getCompileCmd($$$)
7424{
7425 my ($Path, $Opt, $Inc) = @_;
7426 my $GccCall = $GCC_PATH;
7427 if($Opt) {
7428 $GccCall .= " ".$Opt;
7429 }
7430 $GccCall .= " -x ";
7431 if($OSgroup eq "macos") {
7432 $GccCall .= "objective-";
7433 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04007434 if(check_gcc($GCC_PATH, "4"))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007435 { # compile as "C++" header
7436 # to obtain complete dump using GCC 4.0
7437 $GccCall .= "c++-header";
7438 }
7439 else
7440 { # compile as "C++" source
7441 # GCC 3.3 cannot compile headers
7442 $GccCall .= "c++";
7443 }
7444 if(my $Opts = platformSpecs($Version))
7445 {# platform-specific options
7446 $GccCall .= " ".$Opts;
7447 }
7448 # allow extra qualifications
7449 # and other nonconformant code
Andrey Ponomarenko01117f12012-06-26 12:23:02 +04007450 $GccCall .= " -fpermissive";
7451 $GccCall .= " -w";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007452 if($NoStdInc)
7453 {
7454 $GccCall .= " -nostdinc";
7455 $GccCall .= " -nostdinc++";
7456 }
7457 if($CompilerOptions{$Version})
7458 { # user-defined options
7459 $GccCall .= " ".$CompilerOptions{$Version};
7460 }
Andrey Ponomarenkoa01311b2012-06-08 17:20:02 +04007461 $GccCall .= " \"$Path\"";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007462 if($Inc)
7463 { # include paths
7464 $GccCall .= " ".$Inc;
7465 }
7466 return $GccCall;
7467}
7468
Andrey Ponomarenko01117f12012-06-26 12:23:02 +04007469sub detectPreamble($$)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007470{
Andrey Ponomarenko01117f12012-06-26 12:23:02 +04007471 my ($Content, $LibVersion) = @_;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007472 my %HeaderElems = (
7473 # Types
7474 "stdio.h" => ["FILE", "va_list"],
Andrey Ponomarenko85043792012-05-14 16:48:07 +04007475 "stddef.h" => ["NULL", "ptrdiff_t"],
Andrey Ponomarenko9927e332012-10-19 10:50:48 +04007476 "stdint.h" => ["uint8_t", "uint16_t", "uint32_t", "uint64_t",
7477 "int8_t", "int16_t", "int32_t", "int64_t"],
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007478 "time.h" => ["time_t"],
7479 "sys/types.h" => ["ssize_t", "u_int32_t", "u_short", "u_char",
Andrey Ponomarenko9927e332012-10-19 10:50:48 +04007480 "u_int", "off_t", "u_quad_t", "u_long", "mode_t"],
7481 "unistd.h" => ["gid_t", "uid_t", "socklen_t"],
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007482 "stdbool.h" => ["_Bool"],
7483 "rpc/xdr.h" => ["bool_t"],
7484 "in_systm.h" => ["n_long", "n_short"],
7485 # Fields
Andrey Ponomarenkobede8372012-03-29 17:43:21 +04007486 "arpa/inet.h" => ["fw_src", "ip_src"],
7487 # Functions
Andrey Ponomarenko9927e332012-10-19 10:50:48 +04007488 "stdlib.h" => ["free", "malloc", "size_t"],
Andrey Ponomarenko85043792012-05-14 16:48:07 +04007489 "string.h" => ["memmove", "strcmp"]
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007490 );
7491 my %AutoPreamble = ();
Andrey Ponomarenko85043792012-05-14 16:48:07 +04007492 foreach (keys(%HeaderElems))
7493 {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007494 foreach my $Elem (@{$HeaderElems{$_}}) {
Andrey Ponomarenko9927e332012-10-19 10:50:48 +04007495 $AutoPreamble{$Elem} = $_;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007496 }
7497 }
Andrey Ponomarenko01117f12012-06-26 12:23:02 +04007498 my %Types = ();
7499 while($Content=~s/error\:\s*(field\s*|)\W+(.+?)\W+//)
7500 { # error: 'FILE' has not been declared
Andrey Ponomarenko9927e332012-10-19 10:50:48 +04007501 $Types{$2} = 1;
Andrey Ponomarenko01117f12012-06-26 12:23:02 +04007502 }
7503 if(keys(%Types))
7504 {
7505 my %AddHeaders = ();
7506 foreach my $Type (keys(%Types))
7507 {
7508 if(my $Header = $AutoPreamble{$Type})
7509 {
Andrey Ponomarenko9927e332012-10-19 10:50:48 +04007510 if(my $Path = identifyHeader($Header, $LibVersion))
7511 {
7512 if(skipHeader($Path, $LibVersion)) {
7513 next;
7514 }
7515 $Path = path_format($Path, $OSgroup);
7516 $AddHeaders{$Path}{"Type"} = $Type;
7517 $AddHeaders{$Path}{"Header"} = $Header;
Andrey Ponomarenko01117f12012-06-26 12:23:02 +04007518 }
7519 }
7520 }
7521 if(keys(%AddHeaders)) {
Andrey Ponomarenko9927e332012-10-19 10:50:48 +04007522 return \%AddHeaders;
Andrey Ponomarenko01117f12012-06-26 12:23:02 +04007523 }
7524 }
Andrey Ponomarenko9927e332012-10-19 10:50:48 +04007525 return undef;
Andrey Ponomarenko01117f12012-06-26 12:23:02 +04007526}
7527
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +04007528sub checkCTags($)
7529{
7530 my $Path = $_[0];
7531 if(not $Path) {
7532 return;
7533 }
Andrey Ponomarenko570ece52012-11-30 16:36:44 +04007534 my $CTags = undef;
7535
7536 if($OSgroup eq "bsd")
7537 { # use ectags on BSD
7538 $CTags = get_CmdPath("ectags");
7539 if(not $CTags) {
7540 printMsg("WARNING", "can't find \'ectags\' program");
7541 }
7542 }
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +04007543 if(not $CTags) {
Andrey Ponomarenko570ece52012-11-30 16:36:44 +04007544 $CTags = get_CmdPath("ctags");
7545 }
7546 if(not $CTags)
7547 {
7548 printMsg("WARNING", "can't find \'ctags\' program");
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +04007549 return;
7550 }
Andrey Ponomarenkobdc85a92012-11-12 17:28:12 +04007551
Andrey Ponomarenko82b005f2012-11-12 17:58:14 +04007552 if($OSgroup ne "linux")
7553 { # macos, freebsd, etc.
Andrey Ponomarenkobdc85a92012-11-12 17:28:12 +04007554 my $Info = `$CTags --version 2>\"$TMP_DIR/null\"`;
7555 if($Info!~/exuberant/i)
7556 {
7557 printMsg("WARNING", "incompatible version of \'ctags\' program");
7558 return;
7559 }
7560 }
7561
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +04007562 my $Out = $TMP_DIR."/ctags.txt";
Andrey Ponomarenkobdc85a92012-11-12 17:28:12 +04007563 system("$CTags --c-kinds=pxn -f \"$Out\" \"$Path\" 2>\"$TMP_DIR/null\"");
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +04007564 if($Debug) {
Andrey Ponomarenko9927e332012-10-19 10:50:48 +04007565 copy($Out, $DEBUG_PATH{$Version}."/ctags.txt");
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +04007566 }
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +04007567 open(CTAGS, "<", $Out);
7568 while(my $Line = <CTAGS>)
7569 {
7570 chomp($Line);
7571 my ($Name, $Header, $Def, $Type, $Scpe) = split(/\t/, $Line);
Andrey Ponomarenko9927e332012-10-19 10:50:48 +04007572 if(defined $Intrinsic_Keywords{$Name})
7573 { # noise
7574 next;
7575 }
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +04007576 if($Type eq "n")
7577 {
Andrey Ponomarenko9927e332012-10-19 10:50:48 +04007578 if(index($Scpe, "class:")==0) {
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +04007579 next;
7580 }
Andrey Ponomarenko9927e332012-10-19 10:50:48 +04007581 if(index($Scpe, "struct:")==0) {
7582 next;
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +04007583 }
Andrey Ponomarenko9927e332012-10-19 10:50:48 +04007584 if(index($Scpe, "namespace:")==0)
7585 {
7586 if($Scpe=~s/\Anamespace://) {
7587 $Name = $Scpe."::".$Name;
7588 }
7589 }
7590 $TUnit_NameSpaces{$Version}{$Name} = 1;
7591 }
7592 elsif($Type eq "p")
7593 {
7594 if(not $Scpe or index($Scpe, "namespace:")==0) {
7595 $TUnit_Funcs{$Version}{$Name} = 1;
7596 }
7597 }
7598 elsif($Type eq "x")
7599 {
7600 if(not $Scpe or index($Scpe, "namespace:")==0) {
7601 $TUnit_Vars{$Version}{$Name} = 1;
7602 }
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +04007603 }
7604 }
7605 close(CTAGS);
7606}
7607
Andrey Ponomarenko01117f12012-06-26 12:23:02 +04007608sub getDump()
7609{
7610 if(not $GCC_PATH) {
7611 exitStatus("Error", "internal error - GCC path is not set");
7612 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04007613 my $TmpHeaderPath = $TMP_DIR."/dump".$Version.".h";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007614 my $MHeaderPath = $TmpHeaderPath;
Andrey Ponomarenko85043792012-05-14 16:48:07 +04007615 open(TMP_HEADER, ">", $TmpHeaderPath) || die ("can't open file \'$TmpHeaderPath\': $!\n");
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007616 if(my $AddDefines = $Descriptor{$Version}{"Defines"})
7617 {
7618 $AddDefines=~s/\n\s+/\n /g;
Andrey Ponomarenko85043792012-05-14 16:48:07 +04007619 print TMP_HEADER "\n // add defines\n ".$AddDefines."\n";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007620 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +04007621 print TMP_HEADER "\n // add includes\n";
Andrey Ponomarenko570ece52012-11-30 16:36:44 +04007622 foreach my $HPath (@{$Include_Preamble{$Version}}) {
7623 print TMP_HEADER " #include \"".path_format($HPath, "unix")."\"\n";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007624 }
7625 my @Headers = keys(%{$Registered_Headers{$Version}});
7626 @Headers = sort {int($Registered_Headers{$Version}{$a}{"Pos"})<=>int($Registered_Headers{$Version}{$b}{"Pos"})} @Headers;
Andrey Ponomarenko570ece52012-11-30 16:36:44 +04007627 foreach my $HPath (@Headers)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007628 {
Andrey Ponomarenko570ece52012-11-30 16:36:44 +04007629 if(not grep {$HPath eq $_} (@{$Include_Preamble{$Version}})) {
7630 print TMP_HEADER " #include \"".path_format($HPath, "unix")."\"\n";
7631 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007632 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +04007633 close(TMP_HEADER);
Andrey Ponomarenko570ece52012-11-30 16:36:44 +04007634 my $IncludeString = getIncString(getIncPaths(@{$Include_Preamble{$Version}}, @Headers), "GCC");
Andrey Ponomarenko9927e332012-10-19 10:50:48 +04007635
Andrey Ponomarenko07aea072012-11-12 16:15:07 +04007636 if($ExtraInfo)
7637 { # extra information for other tools
Andrey Ponomarenko570ece52012-11-30 16:36:44 +04007638 if($IncludeString) {
7639 writeFile($ExtraInfo."/include-string", $IncludeString);
7640 }
Andrey Ponomarenko4b077f82012-12-04 16:04:36 +04007641 writeFile($ExtraInfo."/recursive-includes", Dumper($RecursiveIncludes{$Version}));
7642 writeFile($ExtraInfo."/direct-includes", Dumper($Header_Includes{$Version}));
Andrey Ponomarenko07aea072012-11-12 16:15:07 +04007643 }
7644
Andrey Ponomarenko9927e332012-10-19 10:50:48 +04007645 if(not keys(%{$TargetHeaders{$Version}}))
7646 { # Target headers
7647 addTargetHeaders($Version);
7648 }
7649
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007650 if($Debug)
7651 { # debug mode
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04007652 writeFile($DEBUG_PATH{$Version}."/headers/direct-includes.txt", Dumper($Header_Includes{$Version}));
7653 writeFile($DEBUG_PATH{$Version}."/headers/recursive-includes.txt", Dumper($RecursiveIncludes{$Version}));
7654 writeFile($DEBUG_PATH{$Version}."/headers/include-paths.txt", Dumper($Cache{"get_HeaderDeps"}{$Version}));
Andrey Ponomarenko570ece52012-11-30 16:36:44 +04007655 writeFile($DEBUG_PATH{$Version}."/headers/default-paths.txt", Dumper(\@DefaultIncPaths));
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007656 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +04007657
Andrey Ponomarenko85043792012-05-14 16:48:07 +04007658 # clean memory
7659 %RecursiveIncludes = ();
7660 %Header_Include_Prefix = ();
7661 %Header_Includes = ();
7662
7663 # clean cache
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04007664 delete($Cache{"identifyHeader"});
Andrey Ponomarenko85043792012-05-14 16:48:07 +04007665 delete($Cache{"detect_header_includes"});
7666 delete($Cache{"selectSystemHeader"});
7667
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007668 # preprocessing stage
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +04007669 my $Pre = callPreprocessor($TmpHeaderPath, $IncludeString, $Version);
7670 checkPreprocessedUnit($Pre);
Andrey Ponomarenko85043792012-05-14 16:48:07 +04007671
7672 # clean memory
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04007673 delete($Include_Neighbors{$Version});
Andrey Ponomarenko85043792012-05-14 16:48:07 +04007674
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +04007675 if($COMMON_LANGUAGE{$Version} eq "C++") {
7676 checkCTags($Pre);
7677 }
7678
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007679 my $MContent = "";
7680 my $PreprocessCmd = getCompileCmd($TmpHeaderPath, "-E", $IncludeString);
7681 if($OStarget eq "windows"
7682 and get_dumpmachine($GCC_PATH)=~/mingw/i
7683 and $MinGWMode{$Version}!=-1)
7684 { # modify headers to compile by MinGW
7685 if(not $MContent)
7686 { # preprocessing
Andrey Ponomarenkoa01311b2012-06-08 17:20:02 +04007687 $MContent = `$PreprocessCmd 2>\"$TMP_DIR/null\"`;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007688 }
7689 if($MContent=~s/__asm\s*(\{[^{}]*?\}|[^{};]*)//g)
7690 { # __asm { ... }
7691 $MinGWMode{$Version}=1;
7692 }
7693 if($MContent=~s/\s+(\/ \/.*?)\n/\n/g)
7694 { # comments after preprocessing
7695 $MinGWMode{$Version}=1;
7696 }
7697 if($MContent=~s/(\W)(0x[a-f]+|\d+)(i|ui)(8|16|32|64)(\W)/$1$2$5/g)
7698 { # 0xffui8
7699 $MinGWMode{$Version}=1;
7700 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +04007701 if($MinGWMode{$Version})
7702 {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007703 printMsg("INFO", "Using MinGW compatibility mode");
Andrey Ponomarenkob8d203d2012-05-25 18:11:07 +04007704 $MHeaderPath = $TMP_DIR."/dump$Version.i";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007705 }
7706 }
7707 if(($COMMON_LANGUAGE{$Version} eq "C" or $CheckHeadersOnly)
Andrey Ponomarenko07aea072012-11-12 16:15:07 +04007708 and $CppMode{$Version}!=-1 and not $CppCompat)
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04007709 { # rename C++ keywords in C code
Andrey Ponomarenko570ece52012-11-30 16:36:44 +04007710 # disable this code by -cpp-compatible option
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007711 if(not $MContent)
7712 { # preprocessing
Andrey Ponomarenkoa01311b2012-06-08 17:20:02 +04007713 $MContent = `$PreprocessCmd 2>\"$TMP_DIR/null\"`;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007714 }
7715 my $RegExp_C = join("|", keys(%CppKeywords_C));
7716 my $RegExp_F = join("|", keys(%CppKeywords_F));
7717 my $RegExp_O = join("|", keys(%CppKeywords_O));
Andrey Ponomarenkobdc85a92012-11-12 17:28:12 +04007718
7719 my $Detected = undef;
7720
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007721 while($MContent=~s/(\A|\n[^\#\/\n][^\n]*?|\n)(\*\s*|\s+|\@|\,|\()($RegExp_C|$RegExp_F)(\s*(\,|\)|\;|\-\>|\.|\:\s*\d))/$1$2c99_$3$4/g)
7722 { # MATCH:
7723 # int foo(int new, int class, int (*new)(int));
7724 # unsigned private: 8;
7725 # DO NOT MATCH:
7726 # #pragma GCC visibility push(default)
Andrey Ponomarenko07aea072012-11-12 16:15:07 +04007727 $CppMode{$Version} = 1;
Andrey Ponomarenkobdc85a92012-11-12 17:28:12 +04007728 $Detected = "$1$2$3$4" if(not defined $Detected);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007729 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04007730 if($MContent=~s/([^\w\s]|\w\s+)(?<!operator )(delete)(\s*\()/$1c99_$2$3/g)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007731 { # MATCH:
7732 # int delete(...);
7733 # int explicit(...);
7734 # DO NOT MATCH:
7735 # void operator delete(...)
Andrey Ponomarenko07aea072012-11-12 16:15:07 +04007736 $CppMode{$Version} = 1;
Andrey Ponomarenkobdc85a92012-11-12 17:28:12 +04007737 $Detected = "$1$2$3" if(not defined $Detected);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007738 }
7739 if($MContent=~s/(\s+)($RegExp_O)(\s*(\;|\:))/$1c99_$2$3/g)
7740 { # MATCH:
7741 # int bool;
7742 # DO NOT MATCH:
7743 # bool X;
7744 # return *this;
7745 # throw;
Andrey Ponomarenko07aea072012-11-12 16:15:07 +04007746 $CppMode{$Version} = 1;
Andrey Ponomarenkobdc85a92012-11-12 17:28:12 +04007747 $Detected = "$1$2$3" if(not defined $Detected);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007748 }
7749 if($MContent=~s/(\s+)(operator)(\s*(\(\s*\)\s*[^\(\s]|\(\s*[^\)\s]))/$1c99_$2$3/g)
7750 { # MATCH:
7751 # int operator(...);
7752 # DO NOT MATCH:
7753 # int operator()(...);
Andrey Ponomarenko07aea072012-11-12 16:15:07 +04007754 $CppMode{$Version} = 1;
Andrey Ponomarenkobdc85a92012-11-12 17:28:12 +04007755 $Detected = "$1$2$3" if(not defined $Detected);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007756 }
7757 if($MContent=~s/([^\w\(\,\s]\s*|\s+)(operator)(\s*(\,\s*[^\(\s]|\)))/$1c99_$2$3/g)
7758 { # MATCH:
7759 # int foo(int operator);
7760 # int foo(int operator, int other);
7761 # DO NOT MATCH:
7762 # int operator,(...);
Andrey Ponomarenko07aea072012-11-12 16:15:07 +04007763 $CppMode{$Version} = 1;
Andrey Ponomarenkobdc85a92012-11-12 17:28:12 +04007764 $Detected = "$1$2$3" if(not defined $Detected);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007765 }
7766 if($MContent=~s/(\*\s*|\w\s+)(bool)(\s*(\,|\)))/$1c99_$2$3/g)
7767 { # MATCH:
7768 # int foo(gboolean *bool);
7769 # DO NOT MATCH:
7770 # void setTabEnabled(int index, bool);
Andrey Ponomarenko07aea072012-11-12 16:15:07 +04007771 $CppMode{$Version} = 1;
Andrey Ponomarenkobdc85a92012-11-12 17:28:12 +04007772 $Detected = "$1$2$3" if(not defined $Detected);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007773 }
Andrey Ponomarenko9927e332012-10-19 10:50:48 +04007774 if($MContent=~s/(\w)(\s*[^\w\(\,\s]\s*|\s+)(this|throw)(\s*[\,\)])/$1$2c99_$3$4/g)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007775 { # MATCH:
7776 # int foo(int* this);
7777 # int bar(int this);
Andrey Ponomarenko9927e332012-10-19 10:50:48 +04007778 # int baz(int throw);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007779 # DO NOT MATCH:
Andrey Ponomarenko9927e332012-10-19 10:50:48 +04007780 # foo(X, this);
Andrey Ponomarenko07aea072012-11-12 16:15:07 +04007781 $CppMode{$Version} = 1;
Andrey Ponomarenkobdc85a92012-11-12 17:28:12 +04007782 $Detected = "$1$2$3$4" if(not defined $Detected);
Andrey Ponomarenko07aea072012-11-12 16:15:07 +04007783 }
7784
7785 if($CppMode{$Version} == 1)
7786 {
Andrey Ponomarenkobdc85a92012-11-12 17:28:12 +04007787 if($Debug)
7788 {
7789 $Detected=~s/\A\s+//g;
7790 printMsg("INFO", "Detected code: \"$Detected\"");
Andrey Ponomarenko07aea072012-11-12 16:15:07 +04007791 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007792 }
Andrey Ponomarenko9927e332012-10-19 10:50:48 +04007793
7794 # remove typedef enum NAME NAME;
7795 my @FwdTypedefs = $MContent=~/typedef\s+enum\s+(\w+)\s+(\w+);/g;
7796 my $N = 0;
7797 while($N<=$#FwdTypedefs-1)
7798 {
7799 my $S = $FwdTypedefs[$N];
7800 if($S eq $FwdTypedefs[$N+1])
7801 {
7802 $MContent=~s/typedef\s+enum\s+\Q$S\E\s+\Q$S\E;//g;
Andrey Ponomarenko07aea072012-11-12 16:15:07 +04007803 $CppMode{$Version}=1;
Andrey Ponomarenko9927e332012-10-19 10:50:48 +04007804 }
7805 $N+=2;
7806 }
7807
Andrey Ponomarenko07aea072012-11-12 16:15:07 +04007808 if($CppMode{$Version}==1)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007809 { # try to change C++ "keyword" to "c99_keyword"
Andrey Ponomarenko07aea072012-11-12 16:15:07 +04007810 printMsg("INFO", "Using C++ compatibility mode");
Andrey Ponomarenkob8d203d2012-05-25 18:11:07 +04007811 $MHeaderPath = $TMP_DIR."/dump$Version.i";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007812 }
7813 }
Andrey Ponomarenko07aea072012-11-12 16:15:07 +04007814 if($CppMode{$Version}==1
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007815 or $MinGWMode{$Version}==1)
7816 { # compile the corrected preprocessor output
7817 writeFile($MHeaderPath, $MContent);
7818 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +04007819
7820 # clean memory
7821 undef $MContent;
7822
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007823 if($COMMON_LANGUAGE{$Version} eq "C++")
7824 { # add classes and namespaces to the dump
7825 my $CHdump = "-fdump-class-hierarchy -c";
Andrey Ponomarenko07aea072012-11-12 16:15:07 +04007826 if($CppMode{$Version}==1
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007827 or $MinGWMode{$Version}==1) {
7828 $CHdump .= " -fpreprocessed";
7829 }
7830 my $ClassHierarchyCmd = getCompileCmd($MHeaderPath, $CHdump, $IncludeString);
7831 chdir($TMP_DIR);
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04007832 system($ClassHierarchyCmd." >null 2>&1");
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007833 chdir($ORIG_DIR);
7834 if(my $ClassDump = (cmd_find($TMP_DIR,"f","*.class",1))[0])
7835 {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007836 my $Content = readFile($ClassDump);
7837 foreach my $ClassInfo (split(/\n\n/, $Content))
7838 {
7839 if($ClassInfo=~/\AClass\s+(.+)\s*/i)
7840 {
7841 my $CName = $1;
7842 next if($CName=~/\A(__|_objc_|_opaque_)/);
7843 $TUnit_NameSpaces{$Version}{$CName} = -1;
7844 if($CName=~/\A[\w:]+\Z/)
7845 { # classes
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +04007846 $TUnit_Classes{$Version}{$CName} = 1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007847 }
7848 if($CName=~/(\w[\w:]*)::/)
7849 { # namespaces
7850 my $NS = $1;
7851 if(not defined $TUnit_NameSpaces{$Version}{$NS}) {
7852 $TUnit_NameSpaces{$Version}{$NS} = 1;
7853 }
7854 }
7855 }
7856 elsif($ClassInfo=~/\AVtable\s+for\s+(.+)\n((.|\n)+)\Z/i)
7857 { # read v-tables (advanced approach)
7858 my ($CName, $VTable) = ($1, $2);
7859 $ClassVTable_Content{$Version}{$CName} = $VTable;
7860 }
7861 }
Andrey Ponomarenkoa01311b2012-06-08 17:20:02 +04007862 foreach my $NS (keys(%{$AddNameSpaces{$Version}}))
7863 { # add user-defined namespaces
7864 $TUnit_NameSpaces{$Version}{$NS} = 1;
7865 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007866 if($Debug)
7867 { # debug mode
7868 mkpath($DEBUG_PATH{$Version});
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04007869 copy($ClassDump, $DEBUG_PATH{$Version}."/class-hierarchy-dump.txt");
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007870 }
7871 unlink($ClassDump);
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +04007872 }
7873
7874 # add namespaces and classes
7875 if(my $NS_Add = get_namespace_additions($TUnit_NameSpaces{$Version}))
7876 { # GCC on all supported platforms does not include namespaces to the dump by default
7877 appendFile($MHeaderPath, "\n // add namespaces\n".$NS_Add);
7878 }
7879 # some GCC versions don't include class methods to the TU dump by default
7880 my ($AddClass, $ClassNum) = ("", 0);
Andrey Ponomarenko570ece52012-11-30 16:36:44 +04007881 my $GCC_44 = check_gcc($GCC_PATH, "4.4"); # support for old GCC versions
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +04007882 foreach my $CName (sort keys(%{$TUnit_Classes{$Version}}))
7883 {
7884 next if($C_Structure{$CName});
7885 next if(not $STDCXX_TESTING and $CName=~/\Astd::/);
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +04007886 next if($SkipTypes{$Version}{$CName});
Andrey Ponomarenko570ece52012-11-30 16:36:44 +04007887 if(not $Force and $GCC_44
7888 and $OSgroup eq "linux")
7889 { # optimization for linux with GCC >= 4.4
7890 # disable this code by -force option
7891 if(index($CName, "::")!=-1)
7892 { # should be added by name space
Andrey Ponomarenko82b005f2012-11-12 17:58:14 +04007893 next;
7894 }
7895 }
7896 else
7897 {
7898 if($CName=~/\A(.+)::[^:]+\Z/
7899 and $TUnit_Classes{$Version}{$1})
7900 { # classes inside other classes
7901 next;
7902 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007903 }
Andrey Ponomarenko9927e332012-10-19 10:50:48 +04007904 if(defined $TUnit_Funcs{$Version}{$CName})
7905 { # the same name for a function and type
7906 next;
7907 }
7908 if(defined $TUnit_Vars{$Version}{$CName})
7909 { # the same name for a variable and type
7910 next;
7911 }
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +04007912 $AddClass .= " $CName* tmp_add_class_".($ClassNum++).";\n";
7913 }
7914 if($AddClass) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007915 appendFile($MHeaderPath, "\n // add classes\n".$AddClass);
7916 }
7917 }
7918 writeLog($Version, "Temporary header file \'$TmpHeaderPath\' with the following content will be compiled to create GCC translation unit dump:\n".readFile($TmpHeaderPath)."\n");
7919 # create TU dump
7920 my $TUdump = "-fdump-translation-unit -fkeep-inline-functions -c";
Andrey Ponomarenko07aea072012-11-12 16:15:07 +04007921 if($CppMode{$Version}==1
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007922 or $MinGWMode{$Version}==1) {
7923 $TUdump .= " -fpreprocessed";
7924 }
7925 my $SyntaxTreeCmd = getCompileCmd($MHeaderPath, $TUdump, $IncludeString);
7926 writeLog($Version, "The GCC parameters:\n $SyntaxTreeCmd\n\n");
7927 chdir($TMP_DIR);
Andrey Ponomarenkoa01311b2012-06-08 17:20:02 +04007928 system($SyntaxTreeCmd." >\"$TMP_DIR/tu_errors\" 2>&1");
Andrey Ponomarenko570ece52012-11-30 16:36:44 +04007929 my $Errors = "";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007930 if($?)
7931 { # failed to compile, but the TU dump still can be created
Andrey Ponomarenko570ece52012-11-30 16:36:44 +04007932 if($Errors = readFile($TMP_DIR."/tu_errors"))
Andrey Ponomarenko01117f12012-06-26 12:23:02 +04007933 { # try to recompile
7934 # FIXME: handle other errors and try to recompile
Andrey Ponomarenko07aea072012-11-12 16:15:07 +04007935 if($CppMode{$Version}==1
Andrey Ponomarenko570ece52012-11-30 16:36:44 +04007936 and index($Errors, "c99_")!=-1)
Andrey Ponomarenko01117f12012-06-26 12:23:02 +04007937 { # disable c99 mode and try again
Andrey Ponomarenko07aea072012-11-12 16:15:07 +04007938 $CppMode{$Version}=-1;
7939 printMsg("INFO", "Disabling C++ compatibility mode");
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007940 resetLogging($Version);
7941 $TMP_DIR = tempdir(CLEANUP=>1);
7942 return getDump();
7943 }
Andrey Ponomarenko01117f12012-06-26 12:23:02 +04007944 elsif($AutoPreambleMode{$Version}!=-1
Andrey Ponomarenko9927e332012-10-19 10:50:48 +04007945 and my $AddHeaders = detectPreamble($Errors, $Version))
Andrey Ponomarenko01117f12012-06-26 12:23:02 +04007946 { # add auto preamble headers and try again
7947 $AutoPreambleMode{$Version}=-1;
Andrey Ponomarenko9927e332012-10-19 10:50:48 +04007948 my @Headers = sort {$b cmp $a} keys(%{$AddHeaders}); # sys/types.h should be the first
Andrey Ponomarenko01117f12012-06-26 12:23:02 +04007949 foreach my $Num (0 .. $#Headers)
7950 {
7951 my $Path = $Headers[$Num];
Andrey Ponomarenko570ece52012-11-30 16:36:44 +04007952 if(not grep {$Path eq $_} (@{$Include_Preamble{$Version}}))
7953 {
7954 push_U($Include_Preamble{$Version}, $Path);
7955 printMsg("INFO", "Add \'".$AddHeaders->{$Path}{"Header"}."\' preamble header for \'".$AddHeaders->{$Path}{"Type"}."\'");
Andrey Ponomarenko01117f12012-06-26 12:23:02 +04007956 }
Andrey Ponomarenko01117f12012-06-26 12:23:02 +04007957 }
7958 resetLogging($Version);
7959 $TMP_DIR = tempdir(CLEANUP=>1);
7960 return getDump();
7961 }
7962 elsif($Cpp0xMode{$Version}!=-1
7963 and ($Errors=~/\Q-std=c++0x\E/
7964 or $Errors=~/is not a class or namespace/))
7965 { # c++0x: enum class
Andrey Ponomarenko570ece52012-11-30 16:36:44 +04007966 if(check_gcc($GCC_PATH, "4.6"))
7967 {
7968 $Cpp0xMode{$Version}=-1;
7969 printMsg("INFO", "Enabling c++0x mode");
7970 resetLogging($Version);
7971 $TMP_DIR = tempdir(CLEANUP=>1);
7972 $CompilerOptions{$Version} .= " -std=c++0x";
7973 return getDump();
7974 }
7975 else {
7976 printMsg("WARNING", "Probably c++0x construction detected");
7977 }
7978
Andrey Ponomarenko01117f12012-06-26 12:23:02 +04007979 }
7980 elsif($MinGWMode{$Version}==1)
7981 { # disable MinGW mode and try again
7982 $MinGWMode{$Version}=-1;
7983 resetLogging($Version);
7984 $TMP_DIR = tempdir(CLEANUP=>1);
7985 return getDump();
7986 }
7987 writeLog($Version, $Errors);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007988 }
Andrey Ponomarenko01117f12012-06-26 12:23:02 +04007989 else {
7990 writeLog($Version, "$!: $?\n");
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007991 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007992 printMsg("ERROR", "some errors occurred when compiling headers");
7993 printErrorLog($Version);
7994 $COMPILE_ERRORS = $ERROR_CODE{"Compile_Error"};
Andrey Ponomarenko570ece52012-11-30 16:36:44 +04007995 writeLog($Version, "\n"); # new line
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007996 }
7997 chdir($ORIG_DIR);
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +04007998 unlink($TmpHeaderPath);
7999 unlink($MHeaderPath);
Andrey Ponomarenko570ece52012-11-30 16:36:44 +04008000
8001 if(my @TUs = cmd_find($TMP_DIR,"f","*.tu",1)) {
8002 return $TUs[0];
8003 }
8004 else
8005 {
8006 my $Msg = "can't compile header(s)";
8007 if($Errors=~/error trying to exec \W+cc1plus\W+/) {
8008 $Msg .= "\nDid you install G++?";
8009 }
8010 exitStatus("Cannot_Compile", $Msg);
8011 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008012}
8013
8014sub cmd_file($)
8015{
8016 my $Path = $_[0];
8017 return "" if(not $Path or not -e $Path);
8018 if(my $CmdPath = get_CmdPath("file")) {
8019 return `$CmdPath -b \"$Path\"`;
8020 }
8021 return "";
8022}
8023
8024sub getIncString($$)
8025{
8026 my ($ArrRef, $Style) = @_;
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04008027 return "" if(not $ArrRef or $#{$ArrRef}<0);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008028 my $String = "";
8029 foreach (@{$ArrRef}) {
8030 $String .= " ".inc_opt($_, $Style);
8031 }
8032 return $String;
8033}
8034
8035sub getIncPaths(@)
8036{
8037 my @HeaderPaths = @_;
Andrey Ponomarenko570ece52012-11-30 16:36:44 +04008038 my @IncPaths = @{$Add_Include_Paths{$Version}};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008039 if($INC_PATH_AUTODETECT{$Version})
8040 { # auto-detecting dependencies
8041 my %Includes = ();
8042 foreach my $HPath (@HeaderPaths)
8043 {
8044 foreach my $Dir (get_HeaderDeps($HPath, $Version))
8045 {
8046 if($Skip_Include_Paths{$Version}{$Dir}) {
8047 next;
8048 }
Andrey Ponomarenkoa01311b2012-06-08 17:20:02 +04008049 if($SystemRoot)
8050 {
8051 if($Skip_Include_Paths{$Version}{$SystemRoot.$Dir}) {
8052 next;
8053 }
8054 }
Andrey Ponomarenko570ece52012-11-30 16:36:44 +04008055 $Includes{$Dir} = 1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008056 }
8057 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008058 foreach my $Dir (@{sortIncPaths([keys(%Includes)], $Version)}) {
Andrey Ponomarenko570ece52012-11-30 16:36:44 +04008059 push_U(\@IncPaths, $Dir);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008060 }
8061 }
8062 else
8063 { # user-defined paths
Andrey Ponomarenko570ece52012-11-30 16:36:44 +04008064 @IncPaths = @{$Include_Paths{$Version}};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008065 }
8066 return \@IncPaths;
8067}
8068
Andrey Ponomarenko570ece52012-11-30 16:36:44 +04008069sub push_U($@)
8070{ # push unique
8071 if(my $Array = shift @_)
8072 {
8073 if(@_)
8074 {
8075 my %Exist = map {$_=>1} @{$Array};
8076 foreach my $Elem (@_)
8077 {
8078 if(not defined $Exist{$Elem})
8079 {
8080 push(@{$Array}, $Elem);
8081 $Exist{$Elem} = 1;
8082 }
8083 }
8084 }
8085 }
8086}
8087
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008088sub callPreprocessor($$$)
8089{
8090 my ($Path, $Inc, $LibVersion) = @_;
8091 return "" if(not $Path or not -f $Path);
8092 my $IncludeString=$Inc;
8093 if(not $Inc) {
8094 $IncludeString = getIncString(getIncPaths($Path), "GCC");
8095 }
8096 my $Cmd = getCompileCmd($Path, "-dD -E", $IncludeString);
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +04008097 my $Out = $TMP_DIR."/preprocessed.h";
Andrey Ponomarenkoa01311b2012-06-08 17:20:02 +04008098 system($Cmd." >\"$Out\" 2>\"$TMP_DIR/null\"");
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04008099 return $Out;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008100}
8101
Andrey Ponomarenko4b077f82012-12-04 16:04:36 +04008102sub cmd_find($;$$$$)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008103{ # native "find" is much faster than File::Find (~6x)
8104 # also the File::Find doesn't support --maxdepth N option
8105 # so using the cross-platform wrapper for the native one
Andrey Ponomarenko570ece52012-11-30 16:36:44 +04008106 my ($Path, $Type, $Name, $MaxDepth, $UseRegex) = @_;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008107 return () if(not $Path or not -e $Path);
8108 if($OSgroup eq "windows")
8109 {
8110 my $DirCmd = get_CmdPath("dir");
8111 if(not $DirCmd) {
8112 exitStatus("Not_Found", "can't find \"dir\" command");
8113 }
8114 $Path=~s/[\\]+\Z//;
8115 $Path = get_abs_path($Path);
8116 $Path = path_format($Path, $OSgroup);
8117 my $Cmd = $DirCmd." \"$Path\" /B /O";
8118 if($MaxDepth!=1) {
8119 $Cmd .= " /S";
8120 }
8121 if($Type eq "d") {
8122 $Cmd .= " /AD";
8123 }
Andrey Ponomarenko570ece52012-11-30 16:36:44 +04008124 my @Files = split(/\n/, `$Cmd 2>\"$TMP_DIR/null\"`);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008125 if($Name)
8126 { # FIXME: how to search file names in MS shell?
Andrey Ponomarenko570ece52012-11-30 16:36:44 +04008127 if(not $UseRegex) {
8128 $Name=~s/\*/.*/g;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008129 }
Andrey Ponomarenko570ece52012-11-30 16:36:44 +04008130 @Files = grep { /\A$Name\Z/i } @Files;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008131 }
8132 my @AbsPaths = ();
8133 foreach my $File (@Files)
8134 {
8135 if(not is_abs($File)) {
8136 $File = joinPath($Path, $File);
8137 }
8138 if($Type eq "f" and not -f $File)
8139 { # skip dirs
8140 next;
8141 }
8142 push(@AbsPaths, path_format($File, $OSgroup));
8143 }
8144 if($Type eq "d") {
8145 push(@AbsPaths, $Path);
8146 }
8147 return @AbsPaths;
8148 }
8149 else
8150 {
8151 my $FindCmd = get_CmdPath("find");
8152 if(not $FindCmd) {
8153 exitStatus("Not_Found", "can't find a \"find\" command");
8154 }
8155 $Path = get_abs_path($Path);
8156 if(-d $Path and -l $Path
8157 and $Path!~/\/\Z/)
8158 { # for directories that are symlinks
8159 $Path.="/";
8160 }
8161 my $Cmd = $FindCmd." \"$Path\"";
8162 if($MaxDepth) {
8163 $Cmd .= " -maxdepth $MaxDepth";
8164 }
8165 if($Type) {
8166 $Cmd .= " -type $Type";
8167 }
Andrey Ponomarenko570ece52012-11-30 16:36:44 +04008168 if($Name and not $UseRegex)
8169 { # wildcards
8170 $Cmd .= " -name \"$Name\"";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008171 }
Andrey Ponomarenko9927e332012-10-19 10:50:48 +04008172 my $Res = `$Cmd 2>\"$TMP_DIR/null\"`;
8173 if($?) {
8174 printMsg("ERROR", "problem with \'find\' utility ($?): $!");
8175 }
Andrey Ponomarenko570ece52012-11-30 16:36:44 +04008176 my @Files = split(/\n/, $Res);
8177 if($Name and $UseRegex)
8178 { # regex
8179 @Files = grep { /\A$Name\Z/ } @Files;
8180 }
Andrey Ponomarenko4b077f82012-12-04 16:04:36 +04008181 return @Files;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008182 }
8183}
8184
8185sub unpackDump($)
8186{
8187 my $Path = $_[0];
8188 return "" if(not $Path or not -e $Path);
8189 $Path = get_abs_path($Path);
8190 $Path = path_format($Path, $OSgroup);
8191 my ($Dir, $FileName) = separate_path($Path);
8192 my $UnpackDir = $TMP_DIR."/unpack";
8193 rmtree($UnpackDir);
8194 mkpath($UnpackDir);
8195 if($FileName=~s/\Q.zip\E\Z//g)
8196 { # *.zip
8197 my $UnzipCmd = get_CmdPath("unzip");
8198 if(not $UnzipCmd) {
8199 exitStatus("Not_Found", "can't find \"unzip\" command");
8200 }
8201 chdir($UnpackDir);
Andrey Ponomarenkoa01311b2012-06-08 17:20:02 +04008202 system("$UnzipCmd \"$Path\" >contents.txt");
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008203 if($?) {
8204 exitStatus("Error", "can't extract \'$Path\'");
8205 }
8206 chdir($ORIG_DIR);
8207 my @Contents = ();
8208 foreach (split("\n", readFile("$UnpackDir/contents.txt")))
8209 {
8210 if(/inflating:\s*([^\s]+)/) {
8211 push(@Contents, $1);
8212 }
8213 }
8214 if(not @Contents) {
8215 exitStatus("Error", "can't extract \'$Path\'");
8216 }
8217 return joinPath($UnpackDir, $Contents[0]);
8218 }
8219 elsif($FileName=~s/\Q.tar.gz\E\Z//g)
8220 { # *.tar.gz
8221 if($OSgroup eq "windows")
8222 { # -xvzf option is not implemented in tar.exe (2003)
8223 # use "gzip.exe -k -d -f" + "tar.exe -xvf" instead
8224 my $TarCmd = get_CmdPath("tar");
8225 if(not $TarCmd) {
8226 exitStatus("Not_Found", "can't find \"tar\" command");
8227 }
8228 my $GzipCmd = get_CmdPath("gzip");
8229 if(not $GzipCmd) {
8230 exitStatus("Not_Found", "can't find \"gzip\" command");
8231 }
8232 chdir($UnpackDir);
Andrey Ponomarenkoa01311b2012-06-08 17:20:02 +04008233 system("$GzipCmd -k -d -f \"$Path\""); # keep input files (-k)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008234 if($?) {
8235 exitStatus("Error", "can't extract \'$Path\'");
8236 }
Andrey Ponomarenkoa01311b2012-06-08 17:20:02 +04008237 system("$TarCmd -xvf \"$Dir\\$FileName.tar\" >contents.txt");
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008238 if($?) {
8239 exitStatus("Error", "can't extract \'$Path\'");
8240 }
8241 chdir($ORIG_DIR);
8242 unlink($Dir."/".$FileName.".tar");
8243 my @Contents = split("\n", readFile("$UnpackDir/contents.txt"));
8244 if(not @Contents) {
8245 exitStatus("Error", "can't extract \'$Path\'");
8246 }
8247 return joinPath($UnpackDir, $Contents[0]);
8248 }
8249 else
8250 { # Unix
8251 my $TarCmd = get_CmdPath("tar");
8252 if(not $TarCmd) {
8253 exitStatus("Not_Found", "can't find \"tar\" command");
8254 }
8255 chdir($UnpackDir);
Andrey Ponomarenkoa01311b2012-06-08 17:20:02 +04008256 system("$TarCmd -xvzf \"$Path\" >contents.txt");
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008257 if($?) {
8258 exitStatus("Error", "can't extract \'$Path\'");
8259 }
8260 chdir($ORIG_DIR);
8261 # The content file name may be different
8262 # from the package file name
8263 my @Contents = split("\n", readFile("$UnpackDir/contents.txt"));
8264 if(not @Contents) {
8265 exitStatus("Error", "can't extract \'$Path\'");
8266 }
8267 return joinPath($UnpackDir, $Contents[0]);
8268 }
8269 }
8270}
8271
8272sub createArchive($$)
8273{
8274 my ($Path, $To) = @_;
Andrey Ponomarenko5c09ef32012-06-14 18:17:33 +04008275 if(not $To) {
8276 $To = ".";
8277 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008278 if(not $Path or not -e $Path
8279 or not -d $To) {
8280 return "";
8281 }
8282 my ($From, $Name) = separate_path($Path);
8283 if($OSgroup eq "windows")
8284 { # *.zip
8285 my $ZipCmd = get_CmdPath("zip");
8286 if(not $ZipCmd) {
8287 exitStatus("Not_Found", "can't find \"zip\"");
8288 }
8289 my $Pkg = $To."/".$Name.".zip";
8290 unlink($Pkg);
8291 chdir($To);
Andrey Ponomarenkoa01311b2012-06-08 17:20:02 +04008292 system("$ZipCmd -j \"$Name.zip\" \"$Path\" >\"$TMP_DIR/null\"");
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008293 if($?)
8294 { # cannot allocate memory (or other problems with "zip")
8295 unlink($Path);
8296 exitStatus("Error", "can't pack the ABI dump: ".$!);
8297 }
8298 chdir($ORIG_DIR);
8299 unlink($Path);
8300 return $Pkg;
8301 }
8302 else
8303 { # *.tar.gz
8304 my $TarCmd = get_CmdPath("tar");
8305 if(not $TarCmd) {
8306 exitStatus("Not_Found", "can't find \"tar\"");
8307 }
8308 my $GzipCmd = get_CmdPath("gzip");
8309 if(not $GzipCmd) {
8310 exitStatus("Not_Found", "can't find \"gzip\"");
8311 }
8312 my $Pkg = abs_path($To)."/".$Name.".tar.gz";
8313 unlink($Pkg);
8314 chdir($From);
8315 system($TarCmd, "-czf", $Pkg, $Name);
8316 if($?)
8317 { # cannot allocate memory (or other problems with "tar")
8318 unlink($Path);
8319 exitStatus("Error", "can't pack the ABI dump: ".$!);
8320 }
8321 chdir($ORIG_DIR);
8322 unlink($Path);
8323 return $To."/".$Name.".tar.gz";
8324 }
8325}
8326
Andrey Ponomarenko9927e332012-10-19 10:50:48 +04008327sub readBytes($)
8328{
8329 sysopen(FILE, $_[0], O_RDONLY);
8330 sysread(FILE, my $Header, 4);
8331 close(FILE);
8332 my @Bytes = map { sprintf('%02x', ord($_)) } split (//, $Header);
8333 return join("", @Bytes);
8334}
8335
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008336sub is_header_file($)
8337{
8338 if($_[0]=~/\.($HEADER_EXT)\Z/i) {
8339 return $_[0];
8340 }
8341 return 0;
8342}
8343
8344sub is_not_header($)
8345{
8346 if($_[0]=~/\.\w+\Z/
8347 and $_[0]!~/\.($HEADER_EXT)\Z/i) {
8348 return 1;
8349 }
8350 return 0;
8351}
8352
8353sub is_header($$$)
8354{
8355 my ($Header, $UserDefined, $LibVersion) = @_;
8356 return 0 if(-d $Header);
8357 if(-f $Header) {
8358 $Header = get_abs_path($Header);
8359 }
8360 else
8361 {
8362 if(is_abs($Header))
8363 { # incorrect absolute path
8364 return 0;
8365 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04008366 if(my $HPath = identifyHeader($Header, $LibVersion)) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008367 $Header = $HPath;
8368 }
8369 else
8370 { # can't find header
8371 return 0;
8372 }
8373 }
8374 if($Header=~/\.\w+\Z/)
8375 { # have an extension
8376 return is_header_file($Header);
8377 }
8378 else
8379 {
8380 if($UserDefined==2)
8381 { # specified on the command line
8382 if(cmd_file($Header)!~/HTML|XML/i) {
8383 return $Header;
8384 }
8385 }
8386 elsif($UserDefined)
8387 { # specified in the XML-descriptor
8388 # header file without an extension
8389 return $Header;
8390 }
8391 else
8392 {
Andrey Ponomarenko570ece52012-11-30 16:36:44 +04008393 if(index($Header, "/include/")!=-1
Andrey Ponomarenko85043792012-05-14 16:48:07 +04008394 or cmd_file($Header)=~/C[\+]*\s+program/i)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008395 { # !~/HTML|XML|shared|dynamic/i
8396 return $Header;
8397 }
8398 }
8399 }
8400 return 0;
8401}
8402
Andrey Ponomarenko16934472012-03-29 15:37:04 +04008403sub addTargetHeaders($)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008404{
8405 my $LibVersion = $_[0];
8406 foreach my $RegHeader (keys(%{$Registered_Headers{$LibVersion}}))
8407 {
8408 my $RegDir = get_dirname($RegHeader);
8409 $TargetHeaders{$LibVersion}{get_filename($RegHeader)}=1;
Andrey Ponomarenko9927e332012-10-19 10:50:48 +04008410
8411 if(not $INC_PATH_AUTODETECT{$LibVersion}) {
8412 detect_recursive_includes($RegHeader, $LibVersion);
8413 }
8414
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008415 foreach my $RecInc (keys(%{$RecursiveIncludes{$LibVersion}{$RegHeader}}))
8416 {
8417 my $Dir = get_dirname($RecInc);
Andrey Ponomarenko85043792012-05-14 16:48:07 +04008418 if($Dir=~/\A\Q$RegDir\E([\/\\]|\Z)/
8419 or $RecursiveIncludes{$LibVersion}{$RegHeader}{$RecInc}!=1)
8420 { # in the same directory or included by #include "..."
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008421 $TargetHeaders{$LibVersion}{get_filename($RecInc)}=1;
8422 }
8423 }
8424 }
8425}
8426
8427sub readHeaders($)
8428{
8429 $Version = $_[0];
8430 printMsg("INFO", "checking header(s) ".$Descriptor{$Version}{"Version"}." ...");
8431 my $DumpPath = getDump();
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008432 if($Debug)
8433 { # debug mode
8434 mkpath($DEBUG_PATH{$Version});
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04008435 copy($DumpPath, $DEBUG_PATH{$Version}."/translation-unit-dump.txt");
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008436 }
8437 getInfo($DumpPath);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008438}
8439
8440sub prepareTypes($)
8441{
8442 my $LibVersion = $_[0];
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04008443 if(not checkDump($LibVersion, "2.0"))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008444 { # support for old ABI dumps
8445 # type names have been corrected in ACC 1.22 (dump 2.0 format)
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04008446 foreach my $TypeId (keys(%{$TypeInfo{$LibVersion}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008447 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04008448 my $TName = $TypeInfo{$LibVersion}{$TypeId}{"Name"};
8449 if($TName=~/\A(\w+)::(\w+)/) {
8450 my ($P1, $P2) = ($1, $2);
8451 if($P1 eq $P2) {
8452 $TName=~s/\A$P1:\:$P1(\W)/$P1$1/;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008453 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04008454 else {
8455 $TName=~s/\A(\w+:\:)$P2:\:$P2(\W)/$1$P2$2/;
8456 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008457 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04008458 $TypeInfo{$LibVersion}{$TypeId}{"Name"} = $TName;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008459 }
8460 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04008461 if(not checkDump($LibVersion, "2.5"))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008462 { # support for old ABI dumps
8463 # V < 2.5: array size == "number of elements"
8464 # V >= 2.5: array size in bytes
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04008465 foreach my $TypeId (sort {int($a)<=>int($b)} keys(%{$TypeInfo{$LibVersion}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008466 {
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +04008467 my %Type = get_PureType($TypeId, $TypeInfo{$LibVersion});
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04008468 if($Type{"Type"} eq "Array")
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008469 {
Andrey Ponomarenko01117f12012-06-26 12:23:02 +04008470 if(my $Size = $Type{"Size"})
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04008471 { # array[N]
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +04008472 my %Base = get_OneStep_BaseType($Type{"Tid"}, $TypeInfo{$LibVersion});
Andrey Ponomarenko01117f12012-06-26 12:23:02 +04008473 $Size *= $Base{"Size"};
8474 $TypeInfo{$LibVersion}{$TypeId}{"Size"} = "$Size";
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04008475 }
8476 else
8477 { # array[] is a pointer
8478 $TypeInfo{$LibVersion}{$TypeId}{"Size"} = $WORD_SIZE{$LibVersion};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008479 }
8480 }
8481 }
8482 }
8483 my $V2 = ($LibVersion==1)?2:1;
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04008484 if(not checkDump($LibVersion, "2.7"))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008485 { # support for old ABI dumps
8486 # size of "method ptr" corrected in 2.7
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04008487 foreach my $TypeId (sort {int($a)<=>int($b)} keys(%{$TypeInfo{$LibVersion}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008488 {
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +04008489 my %PureType = get_PureType($TypeId, $TypeInfo{$LibVersion});
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04008490 if($PureType{"Type"} eq "MethodPtr")
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008491 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04008492 my %Type = get_Type($TypeId, $LibVersion);
8493 my $TypeId_2 = getTypeIdByName($PureType{"Name"}, $V2);
8494 my %Type2 = get_Type($TypeId_2, $V2);
8495 if($Type{"Size"} ne $Type2{"Size"}) {
8496 $TypeInfo{$LibVersion}{$TypeId}{"Size"} = $Type2{"Size"};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008497 }
8498 }
8499 }
8500 }
8501}
8502
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04008503sub prepareSymbols($)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008504{
8505 my $LibVersion = $_[0];
Andrey Ponomarenko16934472012-03-29 15:37:04 +04008506
8507 if(not keys(%{$SymbolInfo{$LibVersion}}))
8508 { # check if input is valid
8509 if(not $ExtendedCheck and not $CheckObjectsOnly)
8510 {
8511 if($CheckHeadersOnly) {
8512 exitStatus("Empty_Set", "the set of public symbols is empty (".$Descriptor{$LibVersion}{"Version"}.")");
8513 }
8514 else {
8515 exitStatus("Empty_Intersection", "the sets of public symbols in headers and libraries have empty intersection (".$Descriptor{$LibVersion}{"Version"}.")");
8516 }
8517 }
8518 }
8519
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008520 my $Remangle = 0;
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04008521 if(not checkDump(1, "2.10")
8522 or not checkDump(2, "2.10"))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008523 { # different formats
8524 $Remangle = 1;
8525 }
8526 if($CheckHeadersOnly)
8527 { # different languages
8528 if($UserLang)
8529 { # --lang=LANG for both versions
8530 if(($UsedDump{1}{"V"} and $UserLang ne $UsedDump{1}{"L"})
8531 or ($UsedDump{2}{"V"} and $UserLang ne $UsedDump{2}{"L"}))
8532 {
8533 if($UserLang eq "C++")
8534 { # remangle symbols
8535 $Remangle = 1;
8536 }
8537 elsif($UserLang eq "C")
8538 { # remove mangling
8539 $Remangle = -1;
8540 }
8541 }
8542 }
8543 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04008544
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04008545 foreach my $InfoId (sort {int($b)<=>int($a)} keys(%{$SymbolInfo{$LibVersion}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008546 { # reverse order: D0, D1, D2, D0 (artificial, GCC < 4.5), C1, C2
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04008547 if(not checkDump($LibVersion, "2.13"))
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04008548 { # support for old ABI dumps
8549 if(defined $SymbolInfo{$LibVersion}{$InfoId}{"Param"})
8550 {
8551 foreach my $P (keys(%{$SymbolInfo{$LibVersion}{$InfoId}{"Param"}}))
8552 {
8553 my $TypeId = $SymbolInfo{$LibVersion}{$InfoId}{"Param"}{$P}{"type"};
8554 my $DVal = $SymbolInfo{$LibVersion}{$InfoId}{"Param"}{$P}{"default"};
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04008555 my $TName = $TypeInfo{$LibVersion}{$TypeId}{"Name"};
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04008556 if(defined $DVal and $DVal ne "")
8557 {
8558 if($TName eq "char") {
8559 $SymbolInfo{$LibVersion}{$InfoId}{"Param"}{$P}{"default"} = chr($DVal);
8560 }
8561 elsif($TName eq "bool") {
8562 $SymbolInfo{$LibVersion}{$InfoId}{"Param"}{$P}{"default"} = $DVal?"true":"false";
8563 }
8564 }
8565 }
8566 }
8567 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04008568 if($SymbolInfo{$LibVersion}{$InfoId}{"Destructor"})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008569 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04008570 if(defined $SymbolInfo{$LibVersion}{$InfoId}{"Param"}
8571 and keys(%{$SymbolInfo{$LibVersion}{$InfoId}{"Param"}})
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04008572 and $SymbolInfo{$LibVersion}{$InfoId}{"Param"}{0}{"name"})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008573 { # support for old GCC < 4.5: skip artificial ~dtor(int __in_chrg)
8574 # + support for old ABI dumps
8575 next;
8576 }
8577 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04008578 my $MnglName = $SymbolInfo{$LibVersion}{$InfoId}{"MnglName"};
Andrey Ponomarenko85043792012-05-14 16:48:07 +04008579 my $ShortName = $SymbolInfo{$LibVersion}{$InfoId}{"ShortName"};
Andrey Ponomarenko16934472012-03-29 15:37:04 +04008580 my $ClassID = $SymbolInfo{$LibVersion}{$InfoId}{"Class"};
Andrey Ponomarenko85043792012-05-14 16:48:07 +04008581 my $Return = $SymbolInfo{$LibVersion}{$InfoId}{"Return"};
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04008582
Andrey Ponomarenko16934472012-03-29 15:37:04 +04008583 my $SRemangle = 0;
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04008584 if(not checkDump(1, "2.12")
8585 or not checkDump(2, "2.12"))
Andrey Ponomarenko16934472012-03-29 15:37:04 +04008586 { # support for old ABI dumps
Andrey Ponomarenko85043792012-05-14 16:48:07 +04008587 if($ShortName eq "operator>>")
8588 {
8589 if(not $SymbolInfo{$LibVersion}{$InfoId}{"Class"})
8590 { # corrected mangling of operator>>
8591 $SRemangle = 1;
8592 }
Andrey Ponomarenko16934472012-03-29 15:37:04 +04008593 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +04008594 if($SymbolInfo{$LibVersion}{$InfoId}{"Data"})
8595 {
8596 if(not $SymbolInfo{$LibVersion}{$InfoId}{"Class"}
8597 and isConstType($Return, $LibVersion) and $MnglName!~/L\d+$ShortName/)
8598 { # corrected mangling of const global data
8599 # some global data is not mangled in the TU dump: qt_sine_table (Qt 4.8)
8600 # and incorrectly mangled by old ACC versions
8601 $SRemangle = 1;
8602 }
Andrey Ponomarenko16934472012-03-29 15:37:04 +04008603 }
8604 }
Andrey Ponomarenko5c09ef32012-06-14 18:17:33 +04008605 if(not $CheckHeadersOnly)
8606 { # support for old ABI dumps
8607 if(not checkDump(1, "2.17")
8608 or not checkDump(2, "2.17"))
8609 {
8610 if($SymbolInfo{$LibVersion}{$InfoId}{"Data"})
8611 {
8612 if(not $SymbolInfo{$LibVersion}{$InfoId}{"Class"})
8613 {
8614 if(link_symbol($ShortName, $LibVersion, "-Deps"))
8615 {
8616 $MnglName = $ShortName;
8617 $SymbolInfo{$LibVersion}{$InfoId}{"MnglName"} = $MnglName;
8618 }
8619 }
8620 }
8621 }
8622 }
Andrey Ponomarenko16934472012-03-29 15:37:04 +04008623 if($Remangle==1 or $SRemangle==1)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008624 { # support for old ABI dumps: some symbols are not mangled in old dumps
8625 # mangle both sets of symbols (old and new)
8626 # NOTE: remangling all symbols by the same mangler
8627 if($MnglName=~/\A_ZN(V|)K/)
8628 { # mangling may be incorrect on old ABI dumps
8629 # because of absent "Const" attribute
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04008630 $SymbolInfo{$LibVersion}{$InfoId}{"Const"} = 1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008631 }
8632 if($MnglName=~/\A_ZN(K|)V/)
8633 { # mangling may be incorrect on old ABI dumps
8634 # because of absent "Volatile" attribute
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04008635 $SymbolInfo{$LibVersion}{$InfoId}{"Volatile"} = 1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008636 }
Andrey Ponomarenko16934472012-03-29 15:37:04 +04008637 if(($ClassID and $MnglName!~/\A(_Z|\?)/)
8638 or (not $ClassID and $CheckHeadersOnly)
8639 or (not $ClassID and not link_symbol($MnglName, $LibVersion, "-Deps")))
8640 { # support for old ABI dumps, GCC >= 4.0
8641 # remangling all manually mangled symbols
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04008642 if($MnglName = mangle_symbol($InfoId, $LibVersion, "GCC"))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008643 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04008644 $SymbolInfo{$LibVersion}{$InfoId}{"MnglName"} = $MnglName;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008645 $MangledNames{$LibVersion}{$MnglName} = 1;
8646 }
8647 }
8648 }
8649 elsif($Remangle==-1)
8650 { # remove mangling
8651 $MnglName = "";
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04008652 $SymbolInfo{$LibVersion}{$InfoId}{"MnglName"} = "";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008653 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008654 if(not $MnglName) {
8655 next;
8656 }
8657 if(not $CompleteSignature{$LibVersion}{$MnglName}{"MnglName"})
8658 { # NOTE: global data may enter here twice
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04008659 %{$CompleteSignature{$LibVersion}{$MnglName}} = %{$SymbolInfo{$LibVersion}{$InfoId}};
8660
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008661 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04008662 if(not checkDump($LibVersion, "2.6"))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008663 { # support for old dumps
8664 # add "Volatile" attribute
8665 if($MnglName=~/_Z(K|)V/) {
8666 $CompleteSignature{$LibVersion}{$MnglName}{"Volatile"}=1;
8667 }
8668 }
8669 # symbol and its symlink have same signatures
8670 if($SymVer{$LibVersion}{$MnglName}) {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04008671 %{$CompleteSignature{$LibVersion}{$SymVer{$LibVersion}{$MnglName}}} = %{$SymbolInfo{$LibVersion}{$InfoId}};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008672 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +04008673
8674 # clean memory
Andrey Ponomarenko16934472012-03-29 15:37:04 +04008675 delete($SymbolInfo{$LibVersion}{$InfoId});
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008676 }
8677 if($COMMON_LANGUAGE{$LibVersion} eq "C++" or $OSgroup eq "windows") {
8678 translateSymbols(keys(%{$CompleteSignature{$LibVersion}}), $LibVersion);
8679 }
8680 if($ExtendedCheck)
8681 { # --ext option
8682 addExtension($LibVersion);
8683 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +04008684
8685 # clean memory
8686 delete($SymbolInfo{$LibVersion});
8687
8688 foreach my $Symbol (keys(%{$CompleteSignature{$LibVersion}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008689 { # detect allocable classes with public exported constructors
8690 # or classes with auto-generated or inline-only constructors
Andrey Ponomarenko9927e332012-10-19 10:50:48 +04008691 # and other temp info
Andrey Ponomarenko85043792012-05-14 16:48:07 +04008692 if(my $ClassId = $CompleteSignature{$LibVersion}{$Symbol}{"Class"})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008693 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04008694 my $ClassName = $TypeInfo{$LibVersion}{$ClassId}{"Name"};
Andrey Ponomarenko85043792012-05-14 16:48:07 +04008695 if($CompleteSignature{$LibVersion}{$Symbol}{"Constructor"}
8696 and not $CompleteSignature{$LibVersion}{$Symbol}{"InLine"})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008697 { # Class() { ... } will not be exported
Andrey Ponomarenko85043792012-05-14 16:48:07 +04008698 if(not $CompleteSignature{$LibVersion}{$Symbol}{"Private"})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008699 {
Andrey Ponomarenko85043792012-05-14 16:48:07 +04008700 if($CheckHeadersOnly or link_symbol($Symbol, $LibVersion, "-Deps")) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008701 $AllocableClass{$LibVersion}{$ClassName} = 1;
8702 }
8703 }
8704 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +04008705 if(not $CompleteSignature{$LibVersion}{$Symbol}{"Private"})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008706 { # all imported class methods
Andrey Ponomarenko85043792012-05-14 16:48:07 +04008707 if(symbolFilter($Symbol, $LibVersion, "Affected", "Binary"))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008708 {
Andrey Ponomarenko85043792012-05-14 16:48:07 +04008709 if($CheckHeadersOnly)
8710 {
8711 if(not $CompleteSignature{$LibVersion}{$Symbol}{"InLine"}
8712 or $CompleteSignature{$LibVersion}{$Symbol}{"Virt"})
8713 { # all symbols except non-virtual inline
8714 $ClassMethods{"Binary"}{$LibVersion}{$ClassName}{$Symbol} = 1;
8715 }
8716 }
8717 else {
8718 $ClassMethods{"Binary"}{$LibVersion}{$ClassName}{$Symbol} = 1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008719 }
8720 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04008721 if(symbolFilter($Symbol, $LibVersion, "Affected", "Source")) {
Andrey Ponomarenko85043792012-05-14 16:48:07 +04008722 $ClassMethods{"Source"}{$LibVersion}{$ClassName}{$Symbol} = 1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008723 }
8724 }
Andrey Ponomarenko16934472012-03-29 15:37:04 +04008725 $ClassNames{$LibVersion}{$ClassName} = 1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008726 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +04008727 if(my $RetId = $CompleteSignature{$LibVersion}{$Symbol}{"Return"})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008728 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04008729 my %Base = get_BaseType($RetId, $LibVersion);
Andrey Ponomarenko85043792012-05-14 16:48:07 +04008730 if(defined $Base{"Type"}
8731 and $Base{"Type"}=~/Struct|Class/)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008732 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04008733 my $Name = $TypeInfo{$LibVersion}{$Base{"Tid"}}{"Name"};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008734 if($Name=~/<([^<>\s]+)>/)
8735 {
8736 if(my $Tid = getTypeIdByName($1, $LibVersion)) {
8737 $ReturnedClass{$LibVersion}{$Tid} = 1;
8738 }
8739 }
8740 else {
8741 $ReturnedClass{$LibVersion}{$Base{"Tid"}} = 1;
8742 }
8743 }
8744 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +04008745 foreach my $Num (keys(%{$CompleteSignature{$LibVersion}{$Symbol}{"Param"}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008746 {
Andrey Ponomarenko85043792012-05-14 16:48:07 +04008747 my $PId = $CompleteSignature{$LibVersion}{$Symbol}{"Param"}{$Num}{"type"};
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04008748 if(get_PLevel($PId, $LibVersion)>=1)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008749 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04008750 if(my %Base = get_BaseType($PId, $LibVersion))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008751 {
Andrey Ponomarenko16934472012-03-29 15:37:04 +04008752 if($Base{"Type"}=~/Struct|Class/)
8753 {
Andrey Ponomarenko85043792012-05-14 16:48:07 +04008754 $ParamClass{$LibVersion}{$Base{"Tid"}}{$Symbol} = 1;
Andrey Ponomarenko16934472012-03-29 15:37:04 +04008755 foreach my $SubId (get_sub_classes($Base{"Tid"}, $LibVersion, 1))
8756 { # mark all derived classes
Andrey Ponomarenko85043792012-05-14 16:48:07 +04008757 $ParamClass{$LibVersion}{$SubId}{$Symbol} = 1;
Andrey Ponomarenko16934472012-03-29 15:37:04 +04008758 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008759 }
8760 }
8761 }
8762 }
Andrey Ponomarenko9927e332012-10-19 10:50:48 +04008763
8764 # mapping {short name => symbols}
8765 $Func_ShortName{$LibVersion}{$CompleteSignature{$LibVersion}{$Symbol}{"ShortName"}}{$Symbol} = 1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008766 }
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04008767 foreach my $MnglName (keys(%VTableClass))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008768 { # reconstruct header name for v-tables
Andrey Ponomarenko9927e332012-10-19 10:50:48 +04008769 if(index($MnglName, "_ZTV")==0)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008770 {
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04008771 if(my $ClassName = $VTableClass{$MnglName})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008772 {
8773 if(my $ClassId = $TName_Tid{$LibVersion}{$ClassName}) {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04008774 $CompleteSignature{$LibVersion}{$MnglName}{"Header"} = $TypeInfo{$LibVersion}{$ClassId}{"Header"};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008775 }
8776 }
8777 }
8778 }
Andrey Ponomarenko16934472012-03-29 15:37:04 +04008779
8780 # types
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04008781 foreach my $TypeId (keys(%{$TypeInfo{$LibVersion}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008782 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04008783 if(my $TName = $TypeInfo{$LibVersion}{$TypeId}{"Name"})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008784 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04008785 if(defined $TypeInfo{$LibVersion}{$TypeId}{"VTable"}) {
8786 $ClassNames{$LibVersion}{$TName} = 1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008787 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04008788 if(defined $TypeInfo{$LibVersion}{$TypeId}{"Base"})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008789 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04008790 $ClassNames{$LibVersion}{$TName} = 1;
8791 foreach my $Bid (keys(%{$TypeInfo{$LibVersion}{$TypeId}{"Base"}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008792 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04008793 if(my $BName = $TypeInfo{$LibVersion}{$Bid}{"Name"}) {
8794 $ClassNames{$LibVersion}{$BName} = 1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008795 }
8796 }
8797 }
8798 }
8799 }
8800}
8801
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04008802sub register_TypeUsage($$)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008803{
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04008804 my ($TypeId, $LibVersion) = @_;
8805 if(not $TypeId) {
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04008806 return 0;
8807 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04008808 if($UsedType{$LibVersion}{$TypeId})
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04008809 { # already registered
8810 return 1;
8811 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04008812 my %TInfo = get_Type($TypeId, $LibVersion);
Andrey Ponomarenko85043792012-05-14 16:48:07 +04008813 if($TInfo{"Type"})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008814 {
Andrey Ponomarenko85043792012-05-14 16:48:07 +04008815 if($TInfo{"Type"}=~/\A(Struct|Union|Class|FuncPtr|MethodPtr|FieldPtr|Enum)\Z/)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008816 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04008817 $UsedType{$LibVersion}{$TypeId} = 1;
Andrey Ponomarenko85043792012-05-14 16:48:07 +04008818 if($TInfo{"Type"}=~/\A(Struct|Class)\Z/)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008819 {
Andrey Ponomarenko85043792012-05-14 16:48:07 +04008820 foreach my $BaseId (keys(%{$TInfo{"Base"}}))
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04008821 { # register base classes
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04008822 register_TypeUsage($BaseId, $LibVersion);
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04008823 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +04008824 foreach my $TPos (keys(%{$TInfo{"TParam"}}))
8825 {
8826 my $TPName = $TInfo{"TParam"}{$TPos}{"name"};
8827 if(my $TTid = $TName_Tid{$LibVersion}{$TPName}) {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04008828 register_TypeUsage($TTid, $LibVersion);
Andrey Ponomarenko85043792012-05-14 16:48:07 +04008829 }
8830 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008831 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +04008832 foreach my $Memb_Pos (keys(%{$TInfo{"Memb"}}))
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04008833 {
Andrey Ponomarenko85043792012-05-14 16:48:07 +04008834 if(my $MTid = $TInfo{"Memb"}{$Memb_Pos}{"type"}) {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04008835 register_TypeUsage($MTid, $LibVersion);
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04008836 }
8837 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +04008838 if($TInfo{"Type"} eq "FuncPtr"
8839 or $TInfo{"Type"} eq "MethodPtr")
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04008840 {
Andrey Ponomarenko85043792012-05-14 16:48:07 +04008841 if(my $RTid = $TInfo{"Return"}) {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04008842 register_TypeUsage($RTid, $LibVersion);
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04008843 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +04008844 foreach my $Memb_Pos (keys(%{$TInfo{"Param"}}))
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04008845 {
Andrey Ponomarenko85043792012-05-14 16:48:07 +04008846 if(my $MTid = $TInfo{"Param"}{$Memb_Pos}{"type"}) {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04008847 register_TypeUsage($MTid, $LibVersion);
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04008848 }
8849 }
8850 }
8851 return 1;
8852 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +04008853 elsif($TInfo{"Type"}=~/\A(Const|ConstVolatile|Volatile|Pointer|Ref|Restrict|Array|Typedef)\Z/)
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04008854 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04008855 $UsedType{$LibVersion}{$TypeId} = 1;
8856 register_TypeUsage($TInfo{"BaseType"}{"Tid"}, $LibVersion);
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04008857 return 1;
8858 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04008859 elsif($TInfo{"Type"} eq "Intrinsic")
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04008860 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04008861 $UsedType{$LibVersion}{$TypeId} = 1;
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04008862 return 1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008863 }
8864 }
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04008865 return 0;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008866}
8867
Andrey Ponomarenko85043792012-05-14 16:48:07 +04008868sub selectSymbol($$$$)
Andrey Ponomarenko35c44fd2012-06-18 17:50:25 +04008869{ # select symbol to check or to dump
Andrey Ponomarenko85043792012-05-14 16:48:07 +04008870 my ($Symbol, $SInfo, $Level, $LibVersion) = @_;
8871
Andrey Ponomarenko35c44fd2012-06-18 17:50:25 +04008872 if($Level eq "Dump")
8873 {
8874 if($SInfo->{"Virt"} or $SInfo->{"PureVirt"})
8875 { # TODO: check if this symbol is from
8876 # base classes of other target symbols
8877 return 1;
8878 }
8879 }
8880
Andrey Ponomarenko85043792012-05-14 16:48:07 +04008881 if(not $STDCXX_TESTING and $Symbol=~/\A(_ZS|_ZNS|_ZNKS)/)
8882 { # stdc++ interfaces
8883 return 0;
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04008884 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +04008885
8886 my $Target = 0;
8887 if(my $Header = $SInfo->{"Header"}) {
8888 $Target = (is_target_header($Header, 1) or is_target_header($Header, 2));
8889 }
8890 if($CheckHeadersOnly)
8891 {
8892 if($Target)
8893 {
8894 if($Level eq "Dump")
8895 { # dumped
8896 if($BinaryOnly)
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04008897 {
Andrey Ponomarenko85043792012-05-14 16:48:07 +04008898 if(not $SInfo->{"InLine"} or $SInfo->{"Data"}) {
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04008899 return 1;
8900 }
8901 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +04008902 else {
8903 return 1;
8904 }
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04008905 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +04008906 elsif($Level eq "Source")
8907 { # checked
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04008908 return 1;
8909 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +04008910 elsif($Level eq "Binary")
8911 { # checked
8912 if(not $SInfo->{"InLine"} or $SInfo->{"Data"}
8913 or $SInfo->{"Virt"} or $SInfo->{"PureVirt"}) {
8914 return 1;
8915 }
8916 }
8917 }
8918 }
8919 else
8920 { # library is available
8921 if(link_symbol($Symbol, $LibVersion, "-Deps"))
8922 { # exported symbols
8923 return 1;
8924 }
8925 if($Level eq "Dump")
8926 { # dumped
Andrey Ponomarenko35c44fd2012-06-18 17:50:25 +04008927 if($BinaryOnly)
8928 {
8929 if($SInfo->{"Data"})
8930 {
8931 if($Target) {
8932 return 1;
8933 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +04008934 }
8935 }
Andrey Ponomarenko35c44fd2012-06-18 17:50:25 +04008936 else
8937 { # SrcBin
Andrey Ponomarenko85043792012-05-14 16:48:07 +04008938 if($Target) {
8939 return 1;
8940 }
8941 }
8942 }
8943 elsif($Level eq "Source")
8944 { # checked
Andrey Ponomarenko01117f12012-06-26 12:23:02 +04008945 if($SInfo->{"PureVirt"} or $SInfo->{"Data"} or $SInfo->{"InLine"}
8946 or isInLineInst($Symbol, $SInfo, $LibVersion))
Andrey Ponomarenko35c44fd2012-06-18 17:50:25 +04008947 { # skip LOCAL symbols
8948 if($Target) {
8949 return 1;
8950 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +04008951 }
8952 }
8953 elsif($Level eq "Binary")
8954 { # checked
8955 if($SInfo->{"PureVirt"} or $SInfo->{"Data"})
8956 {
8957 if($Target) {
8958 return 1;
8959 }
8960 }
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04008961 }
8962 }
8963 return 0;
8964}
8965
Andrey Ponomarenko85043792012-05-14 16:48:07 +04008966sub cleanDump($)
8967{ # clean data
Andrey Ponomarenko16934472012-03-29 15:37:04 +04008968 my $LibVersion = $_[0];
8969 foreach my $InfoId (keys(%{$SymbolInfo{$LibVersion}}))
8970 {
8971 my $MnglName = $SymbolInfo{$LibVersion}{$InfoId}{"MnglName"};
8972 if(not $MnglName) {
8973 delete($SymbolInfo{$LibVersion}{$InfoId});
8974 next;
8975 }
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04008976 my $ShortName = $SymbolInfo{$LibVersion}{$InfoId}{"ShortName"};
Andrey Ponomarenko85043792012-05-14 16:48:07 +04008977 if(not $ShortName) {
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04008978 delete($SymbolInfo{$LibVersion}{$InfoId});
8979 next;
Andrey Ponomarenko16934472012-03-29 15:37:04 +04008980 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +04008981 if($MnglName eq $ShortName)
8982 { # remove duplicate data
8983 delete($SymbolInfo{$LibVersion}{$InfoId}{"MnglName"});
Andrey Ponomarenko16934472012-03-29 15:37:04 +04008984 }
8985 if(not keys(%{$SymbolInfo{$LibVersion}{$InfoId}{"Param"}})) {
8986 delete($SymbolInfo{$LibVersion}{$InfoId}{"Param"});
8987 }
Andrey Ponomarenko01117f12012-06-26 12:23:02 +04008988 if(not keys(%{$SymbolInfo{$LibVersion}{$InfoId}{"TParam"}})) {
8989 delete($SymbolInfo{$LibVersion}{$InfoId}{"TParam"});
8990 }
Andrey Ponomarenko16934472012-03-29 15:37:04 +04008991 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04008992 foreach my $Tid (keys(%{$TypeInfo{$LibVersion}}))
Andrey Ponomarenko85043792012-05-14 16:48:07 +04008993 {
Andrey Ponomarenko01117f12012-06-26 12:23:02 +04008994 delete($TypeInfo{$LibVersion}{$Tid}{"Tid"});
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04008995 foreach my $Attr ("Header", "Line", "Size", "NameSpace")
Andrey Ponomarenko16934472012-03-29 15:37:04 +04008996 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04008997 if(not $TypeInfo{$LibVersion}{$Tid}{$Attr}) {
8998 delete($TypeInfo{$LibVersion}{$Tid}{$Attr});
8999 }
9000 }
Andrey Ponomarenko01117f12012-06-26 12:23:02 +04009001 if(not keys(%{$TypeInfo{$LibVersion}{$Tid}{"TParam"}})) {
9002 delete($TypeInfo{$LibVersion}{$Tid}{"TParam"});
9003 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04009004 }
9005}
9006
9007sub selectType($$)
9008{
9009 my ($Tid, $LibVersion) = @_;
Andrey Ponomarenko9927e332012-10-19 10:50:48 +04009010
9011 if(my $Dupl = $TypeTypedef{$LibVersion}{$Tid})
9012 {
9013 if(defined $TypeInfo{$LibVersion}{$Dupl})
9014 {
9015 if($TypeInfo{$LibVersion}{$Dupl}{"Name"} eq $TypeInfo{$LibVersion}{$Tid}{"Name"})
9016 { # duplicate
9017 return 0;
9018 }
9019 }
9020 }
9021
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04009022 if(my $THeader = $TypeInfo{$LibVersion}{$Tid}{"Header"})
9023 {
9024 if(not isBuiltIn($THeader))
9025 {
9026 if($TypeInfo{$LibVersion}{$Tid}{"Type"}=~/Class|Struct|Union|Enum|Typedef/)
Andrey Ponomarenko16934472012-03-29 15:37:04 +04009027 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04009028 if(not isAnon($TypeInfo{$LibVersion}{$Tid}{"Name"}))
9029 {
9030 if(is_target_header($THeader, $LibVersion))
9031 { # from target headers
9032 if(not selfTypedef($Tid, $LibVersion)) {
9033 return 1;
9034 }
9035 }
Andrey Ponomarenko16934472012-03-29 15:37:04 +04009036 }
9037 }
9038 }
9039 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04009040 return 0;
Andrey Ponomarenko16934472012-03-29 15:37:04 +04009041}
9042
Andrey Ponomarenko85043792012-05-14 16:48:07 +04009043sub removeUnused($$)
9044{ # remove unused data types from the ABI dump
9045 my ($LibVersion, $Kind) = @_;
9046 foreach my $InfoId (keys(%{$SymbolInfo{$LibVersion}}))
9047 {
9048 my %FuncInfo = %{$SymbolInfo{$LibVersion}{$InfoId}};
9049 if(my $RTid = $FuncInfo{"Return"}) {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04009050 register_TypeUsage($RTid, $LibVersion);
Andrey Ponomarenko85043792012-05-14 16:48:07 +04009051 }
9052 if(my $FCid = $FuncInfo{"Class"})
9053 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04009054 register_TypeUsage($FCid, $LibVersion);
9055 if(my $ThisId = getTypeIdByName($TypeInfo{$LibVersion}{$FCid}{"Name"}."*const", $LibVersion))
Andrey Ponomarenko85043792012-05-14 16:48:07 +04009056 { # register "this" pointer
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04009057 $UsedType{$LibVersion}{$ThisId} = 1;
9058 if(my %ThisType = get_Type($ThisId, $LibVersion)) {
9059 register_TypeUsage($ThisType{"BaseType"}{"Tid"}, $LibVersion);
Andrey Ponomarenko85043792012-05-14 16:48:07 +04009060 }
9061 }
9062 }
9063 foreach my $PPos (keys(%{$FuncInfo{"Param"}}))
9064 {
9065 if(my $PTid = $FuncInfo{"Param"}{$PPos}{"type"}) {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04009066 register_TypeUsage($PTid, $LibVersion);
Andrey Ponomarenko85043792012-05-14 16:48:07 +04009067 }
9068 }
9069 foreach my $TPos (keys(%{$FuncInfo{"TParam"}}))
9070 {
9071 my $TPName = $FuncInfo{"TParam"}{$TPos}{"name"};
9072 if(my $TTid = $TName_Tid{$LibVersion}{$TPName}) {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04009073 register_TypeUsage($TTid, $LibVersion);
Andrey Ponomarenko85043792012-05-14 16:48:07 +04009074 }
9075 }
9076 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04009077 foreach my $Tid (keys(%{$TypeInfo{$LibVersion}}))
9078 {
9079 if($UsedType{$LibVersion}{$Tid})
9080 { # All & Derived
9081 next;
9082 }
9083
9084 if($Kind eq "Derived")
Andrey Ponomarenko85043792012-05-14 16:48:07 +04009085 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04009086 if(selectType($Tid, $LibVersion)) {
9087 register_TypeUsage($Tid, $LibVersion);
Andrey Ponomarenko85043792012-05-14 16:48:07 +04009088 }
9089 }
9090 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04009091 foreach my $Tid (keys(%{$TypeInfo{$LibVersion}}))
9092 { # remove unused types
9093 if($UsedType{$LibVersion}{$Tid})
9094 { # All & Derived
9095 next;
9096 }
9097 # remove type
9098 delete($TypeInfo{$LibVersion}{$Tid});
9099 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +04009100
9101 # clean memory
9102 %UsedType = ();
9103}
9104
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04009105sub selfTypedef($$)
Andrey Ponomarenko85043792012-05-14 16:48:07 +04009106{
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04009107 my ($TypeId, $LibVersion) = @_;
9108 my %Type = get_Type($TypeId, $LibVersion);
Andrey Ponomarenko85043792012-05-14 16:48:07 +04009109 if($Type{"Type"} eq "Typedef")
9110 {
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +04009111 my %Base = get_OneStep_BaseType($TypeId, $TypeInfo{$LibVersion});
Andrey Ponomarenko85043792012-05-14 16:48:07 +04009112 if($Base{"Type"}=~/Class|Struct/)
9113 {
9114 if($Type{"Name"} eq $Base{"Name"}) {
9115 return 1;
9116 }
9117 elsif($Type{"Name"}=~/::(\w+)\Z/)
9118 {
9119 if($Type{"Name"} eq $Base{"Name"}."::".$1)
9120 { # QPointer<QWidget>::QPointer
9121 return 1;
9122 }
9123 }
9124 }
9125 }
9126 return 0;
9127}
9128
Andrey Ponomarenko16934472012-03-29 15:37:04 +04009129sub addExtension($)
9130{
9131 my $LibVersion = $_[0];
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04009132 foreach my $Tid (keys(%{$TypeInfo{$LibVersion}}))
Andrey Ponomarenko16934472012-03-29 15:37:04 +04009133 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04009134 if(selectType($Tid, $LibVersion))
Andrey Ponomarenko16934472012-03-29 15:37:04 +04009135 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04009136 my $Symbol = "external_func_".$TypeInfo{$LibVersion}{$Tid}{"Name"};
9137
9138 %{$CompleteSignature{$LibVersion}{$Symbol}} = (
9139 "Header" => "extended.h",
9140 "ShortName" => $Symbol,
9141 "MnglName" => $Symbol,
9142 "Param" => { 0 => { "type"=>$Tid, "name"=>"p1" } }
9143 );
9144
9145 $ExtendedSymbols{$Symbol}=1;
9146 $CheckedSymbols{"Binary"}{$Symbol}=1;
9147 $CheckedSymbols{"Source"}{$Symbol}=1;
Andrey Ponomarenko16934472012-03-29 15:37:04 +04009148 }
9149 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04009150 $ExtendedSymbols{"external_func_0"}=1;
9151 $CheckedSymbols{"Binary"}{"external_func_0"}=1;
9152 $CheckedSymbols{"Source"}{"external_func_0"}=1;
Andrey Ponomarenko16934472012-03-29 15:37:04 +04009153}
9154
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009155sub findMethod($$$)
9156{
9157 my ($VirtFunc, $ClassId, $LibVersion) = @_;
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04009158 foreach my $BaseClass_Id (keys(%{$TypeInfo{$LibVersion}{$ClassId}{"Base"}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009159 {
9160 if(my $VirtMethodInClass = findMethod_Class($VirtFunc, $BaseClass_Id, $LibVersion)) {
9161 return $VirtMethodInClass;
9162 }
9163 elsif(my $VirtMethodInBaseClasses = findMethod($VirtFunc, $BaseClass_Id, $LibVersion)) {
9164 return $VirtMethodInBaseClasses;
9165 }
9166 }
9167 return "";
9168}
9169
9170sub findMethod_Class($$$)
9171{
9172 my ($VirtFunc, $ClassId, $LibVersion) = @_;
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04009173 my $ClassName = $TypeInfo{$LibVersion}{$ClassId}{"Name"};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009174 return "" if(not defined $VirtualTable{$LibVersion}{$ClassName});
9175 my $TargetSuffix = get_symbol_suffix($VirtFunc, 1);
9176 my $TargetShortName = $CompleteSignature{$LibVersion}{$VirtFunc}{"ShortName"};
9177 foreach my $Candidate (keys(%{$VirtualTable{$LibVersion}{$ClassName}}))
9178 { # search for interface with the same parameters suffix (overridden)
9179 if($TargetSuffix eq get_symbol_suffix($Candidate, 1))
9180 {
Andrey Ponomarenkoe3d6bf02012-11-14 11:49:09 +04009181 if($CompleteSignature{$LibVersion}{$VirtFunc}{"Destructor"})
9182 {
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04009183 if($CompleteSignature{$LibVersion}{$Candidate}{"Destructor"})
9184 {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009185 if(($VirtFunc=~/D0E/ and $Candidate=~/D0E/)
9186 or ($VirtFunc=~/D1E/ and $Candidate=~/D1E/)
9187 or ($VirtFunc=~/D2E/ and $Candidate=~/D2E/)) {
9188 return $Candidate;
9189 }
9190 }
9191 }
Andrey Ponomarenkoe3d6bf02012-11-14 11:49:09 +04009192 else
9193 {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009194 if($TargetShortName eq $CompleteSignature{$LibVersion}{$Candidate}{"ShortName"}) {
9195 return $Candidate;
9196 }
9197 }
9198 }
9199 }
9200 return "";
9201}
9202
Andrey Ponomarenko16934472012-03-29 15:37:04 +04009203sub registerVTable($)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009204{
Andrey Ponomarenko16934472012-03-29 15:37:04 +04009205 my $LibVersion = $_[0];
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04009206 foreach my $Symbol (keys(%{$CompleteSignature{$LibVersion}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009207 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04009208 if($CompleteSignature{$LibVersion}{$Symbol}{"Virt"}
9209 or $CompleteSignature{$LibVersion}{$Symbol}{"PureVirt"})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009210 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04009211 my $ClassName = $TypeInfo{$LibVersion}{$CompleteSignature{$LibVersion}{$Symbol}{"Class"}}{"Name"};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009212 next if(not $STDCXX_TESTING and $ClassName=~/\A(std::|__cxxabi)/);
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04009213 if($CompleteSignature{$LibVersion}{$Symbol}{"Destructor"}
9214 and $Symbol=~/D2E/)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009215 { # pure virtual D2-destructors are marked as "virt" in the dump
9216 # virtual D2-destructors are NOT marked as "virt" in the dump
9217 # both destructors are not presented in the v-table
9218 next;
9219 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04009220 my ($MnglName, $VersionSpec, $SymbolVersion) = separate_symbol($Symbol);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009221 $VirtualTable{$LibVersion}{$ClassName}{$MnglName} = 1;
9222 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009223 }
9224}
9225
9226sub registerOverriding($)
9227{
9228 my $LibVersion = $_[0];
9229 my @Classes = keys(%{$VirtualTable{$LibVersion}});
Andrey Ponomarenko85043792012-05-14 16:48:07 +04009230 @Classes = sort {int($TName_Tid{$LibVersion}{$a})<=>int($TName_Tid{$LibVersion}{$b})} @Classes;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009231 foreach my $ClassName (@Classes)
9232 {
9233 foreach my $VirtFunc (keys(%{$VirtualTable{$LibVersion}{$ClassName}}))
9234 {
Andrey Ponomarenko16934472012-03-29 15:37:04 +04009235 if($CompleteSignature{$LibVersion}{$VirtFunc}{"PureVirt"})
9236 { # pure virtuals
9237 next;
9238 }
9239 my $ClassId = $TName_Tid{$LibVersion}{$ClassName};
9240 if(my $Overridden = findMethod($VirtFunc, $ClassId, $LibVersion))
Andrey Ponomarenko85043792012-05-14 16:48:07 +04009241 {
9242 if($CompleteSignature{$LibVersion}{$Overridden}{"Virt"}
9243 or $CompleteSignature{$LibVersion}{$Overridden}{"PureVirt"})
9244 { # both overridden virtual methods
9245 # and implemented pure virtual methods
9246 $CompleteSignature{$LibVersion}{$VirtFunc}{"Override"} = $Overridden;
9247 $OverriddenMethods{$LibVersion}{$Overridden}{$VirtFunc} = 1;
9248 delete($VirtualTable{$LibVersion}{$ClassName}{$VirtFunc}); # remove from v-table model
9249 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009250 }
9251 }
9252 if(not keys(%{$VirtualTable{$LibVersion}{$ClassName}})) {
9253 delete($VirtualTable{$LibVersion}{$ClassName});
9254 }
9255 }
9256}
9257
9258sub setVirtFuncPositions($)
9259{
9260 my $LibVersion = $_[0];
9261 foreach my $ClassName (keys(%{$VirtualTable{$LibVersion}}))
9262 {
9263 my ($Num, $RelPos, $AbsNum) = (1, 0, 1);
9264 foreach my $VirtFunc (sort {int($CompleteSignature{$LibVersion}{$a}{"Line"}) <=> int($CompleteSignature{$LibVersion}{$b}{"Line"})}
9265 sort keys(%{$VirtualTable{$LibVersion}{$ClassName}}))
9266 {
Andrey Ponomarenko16934472012-03-29 15:37:04 +04009267 $VirtualTable{$LibVersion}{$ClassName}{$VirtFunc}=$Num++;
9268
9269 # set relative positions
9270 if(defined $VirtualTable{1}{$ClassName} and defined $VirtualTable{1}{$ClassName}{$VirtFunc}
9271 and defined $VirtualTable{2}{$ClassName} and defined $VirtualTable{2}{$ClassName}{$VirtFunc})
9272 { # relative position excluding added and removed virtual functions
9273 if(not $CompleteSignature{1}{$VirtFunc}{"Override"}
9274 and not $CompleteSignature{2}{$VirtFunc}{"Override"}) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009275 $CompleteSignature{$LibVersion}{$VirtFunc}{"RelPos"} = $RelPos++;
9276 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009277 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009278 }
9279 }
Andrey Ponomarenko16934472012-03-29 15:37:04 +04009280 foreach my $ClassName (keys(%{$ClassNames{$LibVersion}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009281 {
9282 my $AbsNum = 1;
Andrey Ponomarenko16934472012-03-29 15:37:04 +04009283 foreach my $VirtFunc (getVTable_Model($TName_Tid{$LibVersion}{$ClassName}, $LibVersion)) {
9284 $VirtualTable_Model{$LibVersion}{$ClassName}{$VirtFunc}=$AbsNum++;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009285 }
9286 }
9287}
9288
9289sub get_sub_classes($$$)
9290{
9291 my ($ClassId, $LibVersion, $Recursive) = @_;
9292 return () if(not defined $Class_SubClasses{$LibVersion}{$ClassId});
9293 my @Subs = ();
9294 foreach my $SubId (keys(%{$Class_SubClasses{$LibVersion}{$ClassId}}))
9295 {
Andrey Ponomarenko16934472012-03-29 15:37:04 +04009296 if($Recursive)
9297 {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009298 foreach my $SubSubId (get_sub_classes($SubId, $LibVersion, $Recursive)) {
9299 push(@Subs, $SubSubId);
9300 }
9301 }
9302 push(@Subs, $SubId);
9303 }
9304 return @Subs;
9305}
9306
9307sub get_base_classes($$$)
9308{
9309 my ($ClassId, $LibVersion, $Recursive) = @_;
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04009310 my %ClassType = get_Type($ClassId, $LibVersion);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009311 return () if(not defined $ClassType{"Base"});
9312 my @Bases = ();
9313 foreach my $BaseId (sort {int($ClassType{"Base"}{$a}{"pos"})<=>int($ClassType{"Base"}{$b}{"pos"})}
9314 keys(%{$ClassType{"Base"}}))
9315 {
Andrey Ponomarenko16934472012-03-29 15:37:04 +04009316 if($Recursive)
9317 {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009318 foreach my $SubBaseId (get_base_classes($BaseId, $LibVersion, $Recursive)) {
9319 push(@Bases, $SubBaseId);
9320 }
9321 }
9322 push(@Bases, $BaseId);
9323 }
9324 return @Bases;
9325}
9326
Andrey Ponomarenko16934472012-03-29 15:37:04 +04009327sub getVTable_Model($$)
9328{ # return an ordered list of v-table elements
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009329 my ($ClassId, $LibVersion) = @_;
9330 my @Bases = get_base_classes($ClassId, $LibVersion, 1);
9331 my @Elements = ();
9332 foreach my $BaseId (@Bases, $ClassId)
9333 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04009334 if(my $BName = $TypeInfo{$LibVersion}{$BaseId}{"Name"})
Andrey Ponomarenko85043792012-05-14 16:48:07 +04009335 {
9336 if(defined $VirtualTable{$LibVersion}{$BName})
9337 {
9338 my @VFunctions = keys(%{$VirtualTable{$LibVersion}{$BName}});
9339 @VFunctions = sort {int($CompleteSignature{$LibVersion}{$a}{"Line"}) <=> int($CompleteSignature{$LibVersion}{$b}{"Line"})} @VFunctions;
9340 foreach my $VFunc (@VFunctions) {
9341 push(@Elements, $VFunc);
9342 }
9343 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009344 }
9345 }
9346 return @Elements;
9347}
9348
9349sub getVShift($$)
9350{
9351 my ($ClassId, $LibVersion) = @_;
9352 my @Bases = get_base_classes($ClassId, $LibVersion, 1);
9353 my $VShift = 0;
9354 foreach my $BaseId (@Bases)
9355 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04009356 if(my $BName = $TypeInfo{$LibVersion}{$BaseId}{"Name"})
Andrey Ponomarenko85043792012-05-14 16:48:07 +04009357 {
9358 if(defined $VirtualTable{$LibVersion}{$BName}) {
9359 $VShift+=keys(%{$VirtualTable{$LibVersion}{$BName}});
9360 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009361 }
9362 }
9363 return $VShift;
9364}
9365
9366sub getShift($$)
9367{
9368 my ($ClassId, $LibVersion) = @_;
9369 my @Bases = get_base_classes($ClassId, $LibVersion, 0);
9370 my $Shift = 0;
9371 foreach my $BaseId (@Bases)
9372 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04009373 if(my $Size = $TypeInfo{$LibVersion}{$BaseId}{"Size"})
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04009374 {
9375 if($Size!=1)
9376 { # not empty base class
9377 $Shift+=$Size;
9378 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009379 }
9380 }
9381 return $Shift;
9382}
9383
Andrey Ponomarenko16934472012-03-29 15:37:04 +04009384sub getVTable_Size($$)
9385{ # number of v-table elements
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009386 my ($ClassName, $LibVersion) = @_;
Andrey Ponomarenko16934472012-03-29 15:37:04 +04009387 my $Size = 0;
9388 # three approaches
9389 if(not $Size)
9390 { # real size
9391 if(my %VTable = getVTable_Real($ClassName, $LibVersion)) {
9392 $Size = keys(%VTable);
9393 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009394 }
Andrey Ponomarenko16934472012-03-29 15:37:04 +04009395 if(not $Size)
9396 { # shared library symbol size
9397 if($Size = getSymbolSize($ClassVTable{$ClassName}, $LibVersion)) {
9398 $Size /= $WORD_SIZE{$LibVersion};
9399 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009400 }
Andrey Ponomarenko16934472012-03-29 15:37:04 +04009401 if(not $Size)
9402 { # model size
9403 if(defined $VirtualTable_Model{$LibVersion}{$ClassName}) {
9404 $Size = keys(%{$VirtualTable_Model{$LibVersion}{$ClassName}}) + 2;
9405 }
9406 }
9407 return $Size;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009408}
9409
9410sub isCopyingClass($$)
9411{
9412 my ($TypeId, $LibVersion) = @_;
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04009413 return $TypeInfo{$LibVersion}{$TypeId}{"Copied"};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009414}
9415
9416sub isLeafClass($$)
9417{
9418 my ($ClassId, $LibVersion) = @_;
9419 return (not keys(%{$Class_SubClasses{$LibVersion}{$ClassId}}));
9420}
9421
9422sub havePubFields($)
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04009423{ # check structured type for public fields
9424 return isAccessible($_[0], {}, 0, -1);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009425}
9426
9427sub isAccessible($$$$)
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04009428{ # check interval in structured type for public fields
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009429 my ($TypePtr, $Skip, $Start, $End) = @_;
9430 return 0 if(not $TypePtr);
9431 if($End==-1) {
9432 $End = keys(%{$TypePtr->{"Memb"}})-1;
9433 }
9434 foreach my $MemPos (keys(%{$TypePtr->{"Memb"}}))
9435 {
9436 if($Skip and $Skip->{$MemPos})
9437 { # skip removed/added fields
9438 next;
9439 }
9440 if(int($MemPos)>=$Start and int($MemPos)<=$End)
9441 {
9442 if(isPublic($TypePtr, $MemPos)) {
9443 return ($MemPos+1);
9444 }
9445 }
9446 }
9447 return 0;
9448}
9449
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009450sub isReserved($)
9451{ # reserved fields == private
9452 my $MName = $_[0];
9453 if($MName=~/reserved|padding|f_spare/i) {
9454 return 1;
9455 }
Andrey Ponomarenko9927e332012-10-19 10:50:48 +04009456 if($MName=~/\A[_]*(spare|pad|unused)[_\d]*\Z/i) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009457 return 1;
9458 }
9459 if($MName=~/(pad\d+)/i) {
9460 return 1;
9461 }
9462 return 0;
9463}
9464
9465sub isPublic($$)
9466{
9467 my ($TypePtr, $FieldPos) = @_;
9468 return 0 if(not $TypePtr);
9469 return 0 if(not defined $TypePtr->{"Memb"}{$FieldPos});
9470 return 0 if(not defined $TypePtr->{"Memb"}{$FieldPos}{"name"});
9471 if(not $TypePtr->{"Memb"}{$FieldPos}{"access"})
9472 { # by name in C language
9473 # FIXME: add other methods to detect private members
9474 my $MName = $TypePtr->{"Memb"}{$FieldPos}{"name"};
9475 if($MName=~/priv|abidata|parent_object/i)
9476 { # C-styled private data
9477 return 0;
9478 }
9479 if(lc($MName) eq "abi")
9480 { # ABI information/reserved field
9481 return 0;
9482 }
9483 if(isReserved($MName))
9484 { # reserved fields
9485 return 0;
9486 }
9487 return 1;
9488 }
9489 elsif($TypePtr->{"Memb"}{$FieldPos}{"access"} ne "private")
9490 { # by access in C++ language
9491 return 1;
9492 }
9493 return 0;
9494}
9495
Andrey Ponomarenko16934472012-03-29 15:37:04 +04009496sub getVTable_Real($$)
9497{
9498 my ($ClassName, $LibVersion) = @_;
9499 if(my $ClassId = $TName_Tid{$LibVersion}{$ClassName})
9500 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04009501 my %Type = get_Type($ClassId, $LibVersion);
Andrey Ponomarenko16934472012-03-29 15:37:04 +04009502 if(defined $Type{"VTable"}) {
9503 return %{$Type{"VTable"}};
9504 }
9505 }
9506 return ();
9507}
9508
9509sub cmpVTables($)
9510{
9511 my $ClassName = $_[0];
9512 my $Res = cmpVTables_Real($ClassName, 1);
9513 if($Res==-1) {
9514 $Res = cmpVTables_Model($ClassName);
9515 }
9516 return $Res;
9517}
9518
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009519sub cmpVTables_Model($)
9520{
9521 my $ClassName = $_[0];
Andrey Ponomarenko16934472012-03-29 15:37:04 +04009522 foreach my $Symbol (keys(%{$VirtualTable_Model{1}{$ClassName}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009523 {
Andrey Ponomarenko16934472012-03-29 15:37:04 +04009524 if(not defined $VirtualTable_Model{2}{$ClassName}{$Symbol}) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009525 return 1;
9526 }
9527 }
9528 return 0;
9529}
9530
Andrey Ponomarenko16934472012-03-29 15:37:04 +04009531sub cmpVTables_Real($$)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009532{
9533 my ($ClassName, $Strong) = @_;
Andrey Ponomarenko16934472012-03-29 15:37:04 +04009534 if(defined $Cache{"cmpVTables_Real"}{$Strong}{$ClassName}) {
9535 return $Cache{"cmpVTables_Real"}{$Strong}{$ClassName};
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04009536 }
Andrey Ponomarenko16934472012-03-29 15:37:04 +04009537 my %VTable_Old = getVTable_Real($ClassName, 1);
9538 my %VTable_New = getVTable_Real($ClassName, 2);
9539 if(not %VTable_Old or not %VTable_New)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009540 { # old ABI dumps
Andrey Ponomarenko16934472012-03-29 15:37:04 +04009541 return ($Cache{"cmpVTables_Real"}{$Strong}{$ClassName} = -1);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009542 }
Andrey Ponomarenko16934472012-03-29 15:37:04 +04009543 my %Indexes = map {$_=>1} (keys(%VTable_Old), keys(%VTable_New));
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009544 foreach my $Offset (sort {int($a)<=>int($b)} keys(%Indexes))
9545 {
Andrey Ponomarenko16934472012-03-29 15:37:04 +04009546 if(not defined $VTable_Old{$Offset})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009547 { # v-table v.1 < v-table v.2
Andrey Ponomarenko16934472012-03-29 15:37:04 +04009548 return ($Cache{"cmpVTables_Real"}{$Strong}{$ClassName} = $Strong);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009549 }
Andrey Ponomarenko16934472012-03-29 15:37:04 +04009550 my $Entry1 = $VTable_Old{$Offset};
9551 if(not defined $VTable_New{$Offset})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009552 { # v-table v.1 > v-table v.2
Andrey Ponomarenko16934472012-03-29 15:37:04 +04009553 return ($Cache{"cmpVTables_Real"}{$Strong}{$ClassName} = ($Strong or $Entry1!~/__cxa_pure_virtual/));
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009554 }
Andrey Ponomarenko16934472012-03-29 15:37:04 +04009555 my $Entry2 = $VTable_New{$Offset};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009556 $Entry1 = simpleVEntry($Entry1);
9557 $Entry2 = simpleVEntry($Entry2);
9558 if($Entry1 ne $Entry2)
9559 { # register as changed
9560 if($Entry1=~/::([^:]+)\Z/)
9561 {
9562 my $M1 = $1;
9563 if($Entry2=~/::([^:]+)\Z/)
9564 {
9565 my $M2 = $1;
9566 if($M1 eq $M2)
9567 { # overridden
9568 next;
9569 }
9570 }
9571 }
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04009572 if(differentDumps("G"))
9573 {
9574 if($Entry1=~/\A\-(0x|\d+)/ and $Entry2=~/\A\-(0x|\d+)/)
9575 {
9576 # GCC 4.6.1: -0x00000000000000010
9577 # GCC 4.7.0: -16
9578 next;
9579 }
9580 }
Andrey Ponomarenko16934472012-03-29 15:37:04 +04009581 return ($Cache{"cmpVTables_Real"}{$Strong}{$ClassName} = 1);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009582 }
9583 }
Andrey Ponomarenko16934472012-03-29 15:37:04 +04009584 return ($Cache{"cmpVTables_Real"}{$Strong}{$ClassName} = 0);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009585}
9586
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04009587sub mergeVTables($)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009588{ # merging v-tables without diagnostics
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04009589 my $Level = $_[0];
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009590 foreach my $ClassName (keys(%{$VirtualTable{1}}))
9591 {
Andrey Ponomarenko16934472012-03-29 15:37:04 +04009592 if($VTableChanged_M{$ClassName})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009593 { # already registered
9594 next;
9595 }
Andrey Ponomarenko16934472012-03-29 15:37:04 +04009596 if(cmpVTables_Real($ClassName, 0)==1)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009597 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04009598 my @Affected = (keys(%{$ClassMethods{$Level}{1}{$ClassName}}));
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009599 foreach my $Symbol (@Affected)
9600 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04009601 %{$CompatProblems{$Level}{$Symbol}{"Virtual_Table_Changed_Unknown"}{$ClassName}}=(
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009602 "Type_Name"=>$ClassName,
9603 "Type_Type"=>"Class",
9604 "Target"=>$ClassName);
9605 }
9606 }
9607 }
9608}
9609
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04009610sub mergeBases($)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009611{
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04009612 my $Level = $_[0];
Andrey Ponomarenko16934472012-03-29 15:37:04 +04009613 foreach my $ClassName (keys(%{$ClassNames{1}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009614 { # detect added and removed virtual functions
Andrey Ponomarenko16934472012-03-29 15:37:04 +04009615 my $ClassId = $TName_Tid{1}{$ClassName};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009616 next if(not $ClassId);
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04009617 if(defined $VirtualTable{2}{$ClassName})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009618 {
Andrey Ponomarenko16934472012-03-29 15:37:04 +04009619 foreach my $Symbol (keys(%{$VirtualTable{2}{$ClassName}}))
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04009620 {
Andrey Ponomarenko16934472012-03-29 15:37:04 +04009621 if($TName_Tid{1}{$ClassName}
9622 and not defined $VirtualTable{1}{$ClassName}{$Symbol})
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04009623 { # added to v-table
Andrey Ponomarenko16934472012-03-29 15:37:04 +04009624 if(defined $CompleteSignature{1}{$Symbol}
9625 and $CompleteSignature{1}{$Symbol}{"Virt"})
9626 { # override some method in v.1
9627 next;
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04009628 }
Andrey Ponomarenko16934472012-03-29 15:37:04 +04009629 $AddedInt_Virt{$Level}{$ClassName}{$Symbol} = 1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009630 }
9631 }
9632 }
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04009633 if(defined $VirtualTable{1}{$ClassName})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009634 {
Andrey Ponomarenko16934472012-03-29 15:37:04 +04009635 foreach my $Symbol (keys(%{$VirtualTable{1}{$ClassName}}))
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04009636 {
Andrey Ponomarenko16934472012-03-29 15:37:04 +04009637 if($TName_Tid{2}{$ClassName}
9638 and not defined $VirtualTable{2}{$ClassName}{$Symbol})
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04009639 { # removed from v-table
Andrey Ponomarenko16934472012-03-29 15:37:04 +04009640 if(defined $CompleteSignature{2}{$Symbol}
9641 and $CompleteSignature{2}{$Symbol}{"Virt"})
9642 { # override some method in v.2
9643 next;
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04009644 }
Andrey Ponomarenko16934472012-03-29 15:37:04 +04009645 $RemovedInt_Virt{$Level}{$ClassName}{$Symbol} = 1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009646 }
9647 }
9648 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04009649 if($Level eq "Binary")
9650 { # Binary-level
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04009651 my %Class_Type = get_Type($ClassId, 1);
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04009652 foreach my $AddedVFunc (keys(%{$AddedInt_Virt{$Level}{$ClassName}}))
9653 { # check replacements, including pure virtual methods
9654 my $AddedPos = $VirtualTable{2}{$ClassName}{$AddedVFunc};
9655 foreach my $RemovedVFunc (keys(%{$RemovedInt_Virt{$Level}{$ClassName}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009656 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04009657 my $RemovedPos = $VirtualTable{1}{$ClassName}{$RemovedVFunc};
9658 if($AddedPos==$RemovedPos)
9659 {
9660 $VirtualReplacement{$AddedVFunc} = $RemovedVFunc;
9661 $VirtualReplacement{$RemovedVFunc} = $AddedVFunc;
9662 last; # other methods will be reported as "added" or "removed"
9663 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009664 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04009665 if(my $RemovedVFunc = $VirtualReplacement{$AddedVFunc})
9666 {
9667 if(lc($AddedVFunc) eq lc($RemovedVFunc))
9668 { # skip: DomUi => DomUI parameter (Qt 4.2.3 to 4.3.0)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009669 next;
9670 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04009671 my $ProblemType = "Virtual_Replacement";
9672 my @Affected = ($RemovedVFunc);
9673 if($CompleteSignature{1}{$RemovedVFunc}{"PureVirt"})
9674 { # pure methods
9675 if(not isUsedClass($ClassId, 1, $Level))
9676 { # not a parameter of some exported method
9677 next;
9678 }
9679 $ProblemType = "Pure_Virtual_Replacement";
Andrey Ponomarenko9927e332012-10-19 10:50:48 +04009680
9681 # affected all methods (both virtual and non-virtual ones)
9682 @Affected = (keys(%{$ClassMethods{$Level}{1}{$ClassName}}));
9683 push(@Affected, keys(%{$OverriddenMethods{1}{$RemovedVFunc}}));
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009684 }
Andrey Ponomarenko9927e332012-10-19 10:50:48 +04009685 $VTableChanged_M{$ClassName}=1;
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04009686 foreach my $AffectedInt (@Affected)
9687 {
9688 if($CompleteSignature{1}{$AffectedInt}{"PureVirt"})
9689 { # affected exported methods only
9690 next;
9691 }
Andrey Ponomarenko9927e332012-10-19 10:50:48 +04009692 if(not symbolFilter($AffectedInt, 1, "Affected", $Level)) {
9693 next;
9694 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04009695 %{$CompatProblems{$Level}{$AffectedInt}{$ProblemType}{$tr_name{$AddedVFunc}}}=(
9696 "Type_Name"=>$Class_Type{"Name"},
9697 "Type_Type"=>"Class",
9698 "Target"=>get_Signature($AddedVFunc, 2),
9699 "Old_Value"=>get_Signature($RemovedVFunc, 1));
9700 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009701 }
9702 }
9703 }
9704 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04009705 if(not checkDump(1, "2.0")
9706 or not checkDump(2, "2.0"))
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04009707 { # support for old ABI dumps
Andrey Ponomarenko9927e332012-10-19 10:50:48 +04009708 # "Base" attribute introduced in ACC 1.22 (ABI dump 2.0 format)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009709 return;
9710 }
Andrey Ponomarenko16934472012-03-29 15:37:04 +04009711 foreach my $ClassName (sort keys(%{$ClassNames{1}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009712 {
Andrey Ponomarenko16934472012-03-29 15:37:04 +04009713 my $ClassId_Old = $TName_Tid{1}{$ClassName};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009714 next if(not $ClassId_Old);
9715 if(not isCreatable($ClassId_Old, 1))
9716 { # skip classes without public constructors (including auto-generated)
9717 # example: class has only a private exported or private inline constructor
9718 next;
9719 }
9720 if($ClassName=~/>/)
9721 { # skip affected template instances
9722 next;
9723 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04009724 my %Class_Old = get_Type($ClassId_Old, 1);
Andrey Ponomarenko16934472012-03-29 15:37:04 +04009725 my $ClassId_New = $TName_Tid{2}{$ClassName};
Andrey Ponomarenko85043792012-05-14 16:48:07 +04009726 if(not $ClassId_New) {
9727 next;
9728 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04009729 my %Class_New = get_Type($ClassId_New, 2);
Andrey Ponomarenko85043792012-05-14 16:48:07 +04009730 if($Class_New{"Type"}!~/Class|Struct/)
9731 { # became typedef
9732 if($Level eq "Binary") {
9733 next;
9734 }
9735 if($Level eq "Source")
9736 {
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +04009737 %Class_New = get_PureType($ClassId_New, $TypeInfo{2});
Andrey Ponomarenko85043792012-05-14 16:48:07 +04009738 if($Class_New{"Type"}!~/Class|Struct/) {
9739 next;
9740 }
9741 $ClassId_New = $Class_New{"Tid"};
9742 }
9743 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009744 my @Bases_Old = sort {$Class_Old{"Base"}{$a}{"pos"}<=>$Class_Old{"Base"}{$b}{"pos"}} keys(%{$Class_Old{"Base"}});
9745 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 +04009746
9747 my %Tr_Old = map {$TypeInfo{1}{$_}{"Name"} => uncover_typedefs($TypeInfo{1}{$_}{"Name"}, 1)} @Bases_Old;
9748 my %Tr_New = map {$TypeInfo{2}{$_}{"Name"} => uncover_typedefs($TypeInfo{2}{$_}{"Name"}, 2)} @Bases_New;
9749
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009750 my ($BNum1, $BNum2) = (1, 1);
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +04009751 my %BasePos_Old = map {$Tr_Old{$TypeInfo{1}{$_}{"Name"}} => $BNum1++} @Bases_Old;
9752 my %BasePos_New = map {$Tr_New{$TypeInfo{2}{$_}{"Name"}} => $BNum2++} @Bases_New;
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04009753 my %ShortBase_Old = map {get_ShortType($_, 1) => 1} @Bases_Old;
9754 my %ShortBase_New = map {get_ShortType($_, 2) => 1} @Bases_New;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009755 my $Shift_Old = getShift($ClassId_Old, 1);
9756 my $Shift_New = getShift($ClassId_New, 2);
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +04009757 my %BaseId_New = map {$Tr_New{$TypeInfo{2}{$_}{"Name"}} => $_} @Bases_New;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009758 my ($Added, $Removed) = (0, 0);
9759 my @StableBases_Old = ();
9760 foreach my $BaseId (@Bases_Old)
9761 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04009762 my $BaseName = $TypeInfo{1}{$BaseId}{"Name"};
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +04009763 if($BasePos_New{$Tr_Old{$BaseName}}) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009764 push(@StableBases_Old, $BaseId);
9765 }
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +04009766 elsif(not $ShortBase_New{$Tr_Old{$BaseName}}
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04009767 and not $ShortBase_New{get_ShortType($BaseId, 1)})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009768 { # removed base
9769 # excluding namespace::SomeClass to SomeClass renaming
9770 my $ProblemKind = "Removed_Base_Class";
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04009771 if($Level eq "Binary")
9772 { # Binary-level
9773 if($Shift_Old ne $Shift_New)
9774 { # affected fields
9775 if(havePubFields(\%Class_Old)) {
9776 $ProblemKind .= "_And_Shift";
9777 }
9778 elsif($Class_Old{"Size"} ne $Class_New{"Size"}) {
9779 $ProblemKind .= "_And_Size";
9780 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009781 }
Andrey Ponomarenko16934472012-03-29 15:37:04 +04009782 if(keys(%{$VirtualTable_Model{1}{$BaseName}})
9783 and cmpVTables($ClassName)==1)
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04009784 { # affected v-table
9785 $ProblemKind .= "_And_VTable";
Andrey Ponomarenko16934472012-03-29 15:37:04 +04009786 $VTableChanged_M{$ClassName}=1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009787 }
9788 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04009789 my @Affected = keys(%{$ClassMethods{$Level}{1}{$ClassName}});
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009790 foreach my $SubId (get_sub_classes($ClassId_Old, 1, 1))
9791 {
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +04009792 if(my $SubName = $TypeInfo{1}{$SubId}{"Name"})
9793 {
9794 push(@Affected, keys(%{$ClassMethods{$Level}{1}{$SubName}}));
9795 if($ProblemKind=~/VTable/) {
9796 $VTableChanged_M{$SubName}=1;
9797 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009798 }
9799 }
9800 foreach my $Interface (@Affected)
9801 {
Andrey Ponomarenko9927e332012-10-19 10:50:48 +04009802 if(not symbolFilter($Interface, 1, "Affected", $Level)) {
9803 next;
9804 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04009805 %{$CompatProblems{$Level}{$Interface}{$ProblemKind}{"this"}}=(
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009806 "Type_Name"=>$ClassName,
9807 "Type_Type"=>"Class",
9808 "Target"=>$BaseName,
9809 "Old_Size"=>$Class_Old{"Size"}*$BYTE_SIZE,
9810 "New_Size"=>$Class_New{"Size"}*$BYTE_SIZE,
9811 "Shift"=>abs($Shift_New-$Shift_Old) );
9812 }
9813 $Removed+=1;
9814 }
9815 }
9816 my @StableBases_New = ();
9817 foreach my $BaseId (@Bases_New)
9818 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04009819 my $BaseName = $TypeInfo{2}{$BaseId}{"Name"};
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +04009820 if($BasePos_Old{$Tr_New{$BaseName}}) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009821 push(@StableBases_New, $BaseId);
9822 }
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +04009823 elsif(not $ShortBase_Old{$Tr_New{$BaseName}}
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04009824 and not $ShortBase_Old{get_ShortType($BaseId, 2)})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009825 { # added base
9826 # excluding namespace::SomeClass to SomeClass renaming
9827 my $ProblemKind = "Added_Base_Class";
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04009828 if($Level eq "Binary")
9829 { # Binary-level
9830 if($Shift_Old ne $Shift_New)
9831 { # affected fields
9832 if(havePubFields(\%Class_Old)) {
9833 $ProblemKind .= "_And_Shift";
9834 }
9835 elsif($Class_Old{"Size"} ne $Class_New{"Size"}) {
9836 $ProblemKind .= "_And_Size";
9837 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009838 }
Andrey Ponomarenko16934472012-03-29 15:37:04 +04009839 if(keys(%{$VirtualTable_Model{2}{$BaseName}})
9840 and cmpVTables($ClassName)==1)
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04009841 { # affected v-table
9842 $ProblemKind .= "_And_VTable";
Andrey Ponomarenko16934472012-03-29 15:37:04 +04009843 $VTableChanged_M{$ClassName}=1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009844 }
9845 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04009846 my @Affected = keys(%{$ClassMethods{$Level}{1}{$ClassName}});
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009847 foreach my $SubId (get_sub_classes($ClassId_Old, 1, 1))
9848 {
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +04009849 if(my $SubName = $TypeInfo{1}{$SubId}{"Name"})
9850 {
9851 push(@Affected, keys(%{$ClassMethods{$Level}{1}{$SubName}}));
9852 if($ProblemKind=~/VTable/) {
9853 $VTableChanged_M{$SubName}=1;
9854 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009855 }
9856 }
9857 foreach my $Interface (@Affected)
9858 {
Andrey Ponomarenko9927e332012-10-19 10:50:48 +04009859 if(not symbolFilter($Interface, 1, "Affected", $Level)) {
9860 next;
9861 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04009862 %{$CompatProblems{$Level}{$Interface}{$ProblemKind}{"this"}}=(
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009863 "Type_Name"=>$ClassName,
9864 "Type_Type"=>"Class",
9865 "Target"=>$BaseName,
9866 "Old_Size"=>$Class_Old{"Size"}*$BYTE_SIZE,
9867 "New_Size"=>$Class_New{"Size"}*$BYTE_SIZE,
9868 "Shift"=>abs($Shift_New-$Shift_Old) );
9869 }
9870 $Added+=1;
9871 }
9872 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04009873 if($Level eq "Binary")
9874 { # Binary-level
9875 ($BNum1, $BNum2) = (1, 1);
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +04009876 my %BaseRelPos_Old = map {$Tr_Old{$TypeInfo{1}{$_}{"Name"}} => $BNum1++} @StableBases_Old;
9877 my %BaseRelPos_New = map {$Tr_New{$TypeInfo{2}{$_}{"Name"}} => $BNum2++} @StableBases_New;
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04009878 foreach my $BaseId (@Bases_Old)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009879 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04009880 my $BaseName = $TypeInfo{1}{$BaseId}{"Name"};
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +04009881 if(my $NewPos = $BaseRelPos_New{$Tr_Old{$BaseName}})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009882 {
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +04009883 my $BaseNewId = $BaseId_New{$Tr_Old{$BaseName}};
9884 my $OldPos = $BaseRelPos_Old{$Tr_Old{$BaseName}};
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04009885 if($NewPos!=$OldPos)
9886 { # changed position of the base class
9887 foreach my $Interface (keys(%{$ClassMethods{$Level}{1}{$ClassName}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009888 {
Andrey Ponomarenko9927e332012-10-19 10:50:48 +04009889 if(not symbolFilter($Interface, 1, "Affected", $Level)) {
9890 next;
9891 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04009892 %{$CompatProblems{$Level}{$Interface}{"Base_Class_Position"}{"this"}}=(
9893 "Type_Name"=>$ClassName,
9894 "Type_Type"=>"Class",
9895 "Target"=>$BaseName,
9896 "Old_Value"=>$OldPos-1,
9897 "New_Value"=>$NewPos-1 );
9898 }
9899 }
9900 if($Class_Old{"Base"}{$BaseId}{"virtual"}
9901 and not $Class_New{"Base"}{$BaseNewId}{"virtual"})
9902 { # became non-virtual base
9903 foreach my $Interface (keys(%{$ClassMethods{$Level}{1}{$ClassName}}))
9904 {
Andrey Ponomarenko9927e332012-10-19 10:50:48 +04009905 if(not symbolFilter($Interface, 1, "Affected", $Level)) {
9906 next;
9907 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04009908 %{$CompatProblems{$Level}{$Interface}{"Base_Class_Became_Non_Virtually_Inherited"}{"this->".$BaseName}}=(
9909 "Type_Name"=>$ClassName,
9910 "Type_Type"=>"Class",
9911 "Target"=>$BaseName );
9912 }
9913 }
9914 elsif(not $Class_Old{"Base"}{$BaseId}{"virtual"}
9915 and $Class_New{"Base"}{$BaseNewId}{"virtual"})
9916 { # became virtual base
9917 foreach my $Interface (keys(%{$ClassMethods{$Level}{1}{$ClassName}}))
9918 {
Andrey Ponomarenko9927e332012-10-19 10:50:48 +04009919 if(not symbolFilter($Interface, 1, "Affected", $Level)) {
9920 next;
9921 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04009922 %{$CompatProblems{$Level}{$Interface}{"Base_Class_Became_Virtually_Inherited"}{"this->".$BaseName}}=(
9923 "Type_Name"=>$ClassName,
9924 "Type_Type"=>"Class",
9925 "Target"=>$BaseName );
9926 }
9927 }
9928 }
9929 }
9930 # detect size changes in base classes
9931 if($Shift_Old!=$Shift_New)
9932 { # size of allocable class
9933 foreach my $BaseId (@StableBases_Old)
9934 { # search for changed base
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04009935 my %BaseType = get_Type($BaseId, 1);
9936 my $Size_Old = $TypeInfo{1}{$BaseId}{"Size"};
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +04009937 my $Size_New = $TypeInfo{2}{$BaseId_New{$Tr_Old{$BaseType{"Name"}}}}{"Size"};
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04009938 if($Size_Old ne $Size_New
9939 and $Size_Old and $Size_New)
9940 {
9941 my $ProblemType = "";
9942 if(isCopyingClass($BaseId, 1)) {
9943 $ProblemType = "Size_Of_Copying_Class";
9944 }
9945 elsif($AllocableClass{1}{$BaseType{"Name"}})
9946 {
9947 if($Size_New>$Size_Old)
9948 { # increased size
9949 $ProblemType = "Size_Of_Allocable_Class_Increased";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009950 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04009951 else
9952 { # decreased size
9953 $ProblemType = "Size_Of_Allocable_Class_Decreased";
9954 if(not havePubFields(\%Class_Old))
9955 { # affected class has no public members
9956 next;
9957 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009958 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04009959 }
9960 next if(not $ProblemType);
9961 foreach my $Interface (keys(%{$ClassMethods{$Level}{1}{$ClassName}}))
9962 { # base class size changes affecting current class
Andrey Ponomarenko9927e332012-10-19 10:50:48 +04009963 if(not symbolFilter($Interface, 1, "Affected", $Level)) {
9964 next;
9965 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04009966 %{$CompatProblems{$Level}{$Interface}{$ProblemType}{"this->".$BaseType{"Name"}}}=(
9967 "Type_Name"=>$BaseType{"Name"},
9968 "Type_Type"=>"Class",
9969 "Target"=>$BaseType{"Name"},
9970 "Old_Size"=>$Size_Old*$BYTE_SIZE,
9971 "New_Size"=>$Size_New*$BYTE_SIZE );
9972 }
9973 }
9974 }
9975 }
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +04009976 if(defined $VirtualTable_Model{1}{$ClassName}
Andrey Ponomarenko16934472012-03-29 15:37:04 +04009977 and cmpVTables_Real($ClassName, 1)==1
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +04009978 and my @VFunctions = keys(%{$VirtualTable_Model{1}{$ClassName}}))
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04009979 { # compare virtual tables size in base classes
9980 my $VShift_Old = getVShift($ClassId_Old, 1);
9981 my $VShift_New = getVShift($ClassId_New, 2);
9982 if($VShift_Old ne $VShift_New)
9983 { # changes in the base class or changes in the list of base classes
9984 my @AllBases_Old = get_base_classes($ClassId_Old, 1, 1);
9985 my @AllBases_New = get_base_classes($ClassId_New, 2, 1);
9986 ($BNum1, $BNum2) = (1, 1);
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +04009987 my %StableBase = map {$Tr_New{$TypeInfo{2}{$_}{"Name"}} => $_} @AllBases_New;
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04009988 foreach my $BaseId (@AllBases_Old)
9989 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04009990 my %BaseType = get_Type($BaseId, 1);
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +04009991 if(not $StableBase{$Tr_Old{$BaseType{"Name"}}})
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04009992 { # lost base
9993 next;
9994 }
Andrey Ponomarenko16934472012-03-29 15:37:04 +04009995 my $VSize_Old = getVTable_Size($BaseType{"Name"}, 1);
9996 my $VSize_New = getVTable_Size($BaseType{"Name"}, 2);
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04009997 if($VSize_Old!=$VSize_New)
9998 {
Andrey Ponomarenko85043792012-05-14 16:48:07 +04009999 foreach my $Symbol (@VFunctions)
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +040010000 { # TODO: affected non-virtual methods?
10001 if(not defined $VirtualTable_Model{2}{$ClassName}{$Symbol})
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040010002 { # Removed_Virtual_Method, will be registered in mergeVirtualTables()
10003 next;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010004 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +040010005 if($VirtualTable_Model{2}{$ClassName}{$Symbol}-$VirtualTable_Model{1}{$ClassName}{$Symbol}==0)
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040010006 { # skip interfaces that have not changed the absolute virtual position
10007 next;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010008 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +040010009 if(not symbolFilter($Symbol, 1, "Affected", $Level)) {
10010 next;
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040010011 }
Andrey Ponomarenko16934472012-03-29 15:37:04 +040010012 $VTableChanged_M{$BaseType{"Name"}} = 1;
10013 $VTableChanged_M{$ClassName} = 1;
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040010014 foreach my $VirtFunc (keys(%{$AddedInt_Virt{$Level}{$BaseType{"Name"}}}))
10015 { # the reason of the layout change: added virtual functions
10016 next if($VirtualReplacement{$VirtFunc});
10017 my $ProblemType = "Added_Virtual_Method";
10018 if($CompleteSignature{2}{$VirtFunc}{"PureVirt"}) {
10019 $ProblemType = "Added_Pure_Virtual_Method";
10020 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +040010021 %{$CompatProblems{$Level}{$Symbol}{$ProblemType}{get_Signature($VirtFunc, 2)}}=(
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040010022 "Type_Name"=>$BaseType{"Name"},
10023 "Type_Type"=>"Class",
10024 "Target"=>get_Signature($VirtFunc, 2) );
10025 }
10026 foreach my $VirtFunc (keys(%{$RemovedInt_Virt{$Level}{$BaseType{"Name"}}}))
10027 { # the reason of the layout change: removed virtual functions
10028 next if($VirtualReplacement{$VirtFunc});
10029 my $ProblemType = "Removed_Virtual_Method";
10030 if($CompleteSignature{1}{$VirtFunc}{"PureVirt"}) {
10031 $ProblemType = "Removed_Pure_Virtual_Method";
10032 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +040010033 %{$CompatProblems{$Level}{$Symbol}{$ProblemType}{get_Signature($VirtFunc, 1)}}=(
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040010034 "Type_Name"=>$BaseType{"Name"},
10035 "Type_Type"=>"Class",
10036 "Target"=>get_Signature($VirtFunc, 1) );
10037 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010038 }
10039 }
10040 }
10041 }
10042 }
10043 }
10044 }
10045}
10046
10047sub isCreatable($$)
10048{
10049 my ($ClassId, $LibVersion) = @_;
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040010050 if($AllocableClass{$LibVersion}{$TypeInfo{$LibVersion}{$ClassId}{"Name"}}
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010051 or isCopyingClass($ClassId, $LibVersion)) {
10052 return 1;
10053 }
10054 if(keys(%{$Class_SubClasses{$LibVersion}{$ClassId}}))
10055 { # Fix for incomplete data: if this class has
10056 # a base class then it should also has a constructor
10057 return 1;
10058 }
10059 if($ReturnedClass{$LibVersion}{$ClassId})
10060 { # returned by some method of this class
10061 # or any other class
10062 return 1;
10063 }
10064 return 0;
10065}
10066
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040010067sub isUsedClass($$$)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010068{
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040010069 my ($ClassId, $LibVersion, $Level) = @_;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010070 if(keys(%{$ParamClass{$LibVersion}{$ClassId}}))
10071 { # parameter of some exported method
10072 return 1;
10073 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040010074 my $CName = $TypeInfo{$LibVersion}{$ClassId}{"Name"};
10075 if(keys(%{$ClassMethods{$Level}{$LibVersion}{$CName}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010076 { # method from target class
10077 return 1;
10078 }
10079 return 0;
10080}
10081
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040010082sub mergeVirtualTables($$)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010083{ # check for changes in the virtual table
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040010084 my ($Interface, $Level) = @_;
Andrey Ponomarenko16934472012-03-29 15:37:04 +040010085 # affected methods:
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010086 # - virtual
10087 # - pure-virtual
10088 # - non-virtual
10089 if($CompleteSignature{1}{$Interface}{"Data"})
10090 { # global data is not affected
10091 return;
10092 }
10093 my $Class_Id = $CompleteSignature{1}{$Interface}{"Class"};
Andrey Ponomarenko16934472012-03-29 15:37:04 +040010094 if(not $Class_Id) {
10095 return;
10096 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040010097 my $CName = $TypeInfo{1}{$Class_Id}{"Name"};
Andrey Ponomarenko16934472012-03-29 15:37:04 +040010098 if(cmpVTables_Real($CName, 1)==0)
10099 { # no changes
10100 return;
10101 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040010102 $CheckedTypes{$Level}{$CName} = 1;
10103 if($Level eq "Binary")
10104 { # Binary-level
10105 if($CompleteSignature{1}{$Interface}{"PureVirt"}
10106 and not isUsedClass($Class_Id, 1, $Level))
10107 { # pure virtuals should not be affected
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040010108 # if there are no exported methods using this class
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040010109 return;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010110 }
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040010111 }
10112 foreach my $Func (keys(%{$VirtualTable{1}{$CName}}))
10113 {
10114 if(defined $VirtualTable{2}{$CName}{$Func}
10115 and defined $CompleteSignature{2}{$Func})
10116 {
10117 if(not $CompleteSignature{1}{$Func}{"PureVirt"}
10118 and $CompleteSignature{2}{$Func}{"PureVirt"})
10119 { # became pure virtual
10120 %{$CompatProblems{$Level}{$Interface}{"Virtual_Method_Became_Pure"}{$tr_name{$Func}}}=(
10121 "Type_Name"=>$CName,
10122 "Type_Type"=>"Class",
10123 "Target"=>get_Signature_M($Func, 1) );
10124 $VTableChanged_M{$CName} = 1;
10125 }
10126 elsif($CompleteSignature{1}{$Func}{"PureVirt"}
10127 and not $CompleteSignature{2}{$Func}{"PureVirt"})
10128 { # became non-pure virtual
10129 %{$CompatProblems{$Level}{$Interface}{"Virtual_Method_Became_Non_Pure"}{$tr_name{$Func}}}=(
10130 "Type_Name"=>$CName,
10131 "Type_Type"=>"Class",
10132 "Target"=>get_Signature_M($Func, 1) );
10133 $VTableChanged_M{$CName} = 1;
10134 }
10135 }
10136 }
10137 if($Level eq "Binary")
10138 { # Binary-level
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040010139 # check virtual table structure
10140 foreach my $AddedVFunc (keys(%{$AddedInt_Virt{$Level}{$CName}}))
10141 {
10142 next if($Interface eq $AddedVFunc);
10143 next if($VirtualReplacement{$AddedVFunc});
10144 my $VPos_Added = $VirtualTable{2}{$CName}{$AddedVFunc};
10145 if($CompleteSignature{2}{$AddedVFunc}{"PureVirt"})
10146 { # pure virtual methods affect all others (virtual and non-virtual)
10147 %{$CompatProblems{$Level}{$Interface}{"Added_Pure_Virtual_Method"}{$tr_name{$AddedVFunc}}}=(
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010148 "Type_Name"=>$CName,
10149 "Type_Type"=>"Class",
10150 "Target"=>get_Signature($AddedVFunc, 2) );
Andrey Ponomarenko16934472012-03-29 15:37:04 +040010151 $VTableChanged_M{$CName} = 1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010152 }
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040010153 elsif(not defined $VirtualTable{1}{$CName}
10154 or $VPos_Added>keys(%{$VirtualTable{1}{$CName}}))
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040010155 { # added virtual function at the end of v-table
Andrey Ponomarenko16934472012-03-29 15:37:04 +040010156 if(not keys(%{$VirtualTable_Model{1}{$CName}}))
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040010157 { # became polymorphous class, added v-table pointer
10158 %{$CompatProblems{$Level}{$Interface}{"Added_First_Virtual_Method"}{$tr_name{$AddedVFunc}}}=(
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010159 "Type_Name"=>$CName,
10160 "Type_Type"=>"Class",
10161 "Target"=>get_Signature($AddedVFunc, 2) );
Andrey Ponomarenko16934472012-03-29 15:37:04 +040010162 $VTableChanged_M{$CName} = 1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010163 }
10164 else
10165 {
Andrey Ponomarenko16934472012-03-29 15:37:04 +040010166 my $VSize_Old = getVTable_Size($CName, 1);
10167 my $VSize_New = getVTable_Size($CName, 2);
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040010168 next if($VSize_Old==$VSize_New); # exception: register as removed and added virtual method
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040010169 if(isCopyingClass($Class_Id, 1))
10170 { # class has no constructors and v-table will be copied by applications, this may affect all methods
10171 my $ProblemType = "Added_Virtual_Method";
10172 if(isLeafClass($Class_Id, 1)) {
10173 $ProblemType = "Added_Virtual_Method_At_End_Of_Leaf_Copying_Class";
10174 }
10175 %{$CompatProblems{$Level}{$Interface}{$ProblemType}{$tr_name{$AddedVFunc}}}=(
10176 "Type_Name"=>$CName,
10177 "Type_Type"=>"Class",
10178 "Target"=>get_Signature($AddedVFunc, 2) );
Andrey Ponomarenko16934472012-03-29 15:37:04 +040010179 $VTableChanged_M{$CName} = 1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010180 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040010181 else
10182 {
10183 my $ProblemType = "Added_Virtual_Method";
10184 if(isLeafClass($Class_Id, 1)) {
10185 $ProblemType = "Added_Virtual_Method_At_End_Of_Leaf_Allocable_Class";
10186 }
10187 %{$CompatProblems{$Level}{$Interface}{$ProblemType}{$tr_name{$AddedVFunc}}}=(
10188 "Type_Name"=>$CName,
10189 "Type_Type"=>"Class",
10190 "Target"=>get_Signature($AddedVFunc, 2) );
Andrey Ponomarenko16934472012-03-29 15:37:04 +040010191 $VTableChanged_M{$CName} = 1;
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040010192 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010193 }
10194 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040010195 elsif($CompleteSignature{1}{$Interface}{"Virt"}
10196 or $CompleteSignature{1}{$Interface}{"PureVirt"})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010197 {
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040010198 if(defined $VirtualTable{1}{$CName}
10199 and defined $VirtualTable{2}{$CName})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010200 {
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040010201 my $VPos_Old = $VirtualTable{1}{$CName}{$Interface};
10202 my $VPos_New = $VirtualTable{2}{$CName}{$Interface};
10203 if($VPos_Added<=$VPos_Old and $VPos_Old!=$VPos_New)
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040010204 {
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040010205 my @Affected = ($Interface, keys(%{$OverriddenMethods{1}{$Interface}}));
10206 foreach my $ASymbol (@Affected)
10207 {
Andrey Ponomarenko85043792012-05-14 16:48:07 +040010208 if(not $CompleteSignature{1}{$ASymbol}{"PureVirt"})
10209 {
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040010210 if(not symbolFilter($ASymbol, 1, "Affected", $Level)) {
Andrey Ponomarenko85043792012-05-14 16:48:07 +040010211 next;
10212 }
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040010213 }
10214 $CheckedSymbols{$Level}{$ASymbol} = 1;
10215 %{$CompatProblems{$Level}{$ASymbol}{"Added_Virtual_Method"}{$tr_name{$AddedVFunc}}}=(
10216 "Type_Name"=>$CName,
10217 "Type_Type"=>"Class",
10218 "Target"=>get_Signature($AddedVFunc, 2) );
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040010219 $VTableChanged_M{$TypeInfo{1}{$CompleteSignature{1}{$ASymbol}{"Class"}}{"Name"}} = 1;
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040010220 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010221 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010222 }
10223 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040010224 else {
10225 # safe
10226 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010227 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040010228 foreach my $RemovedVFunc (keys(%{$RemovedInt_Virt{$Level}{$CName}}))
10229 {
10230 next if($VirtualReplacement{$RemovedVFunc});
10231 if($RemovedVFunc eq $Interface
10232 and $CompleteSignature{1}{$RemovedVFunc}{"PureVirt"})
10233 { # This case is for removed virtual methods
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040010234 # implemented in both versions of a library
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040010235 next;
10236 }
Andrey Ponomarenko16934472012-03-29 15:37:04 +040010237 if(not keys(%{$VirtualTable_Model{2}{$CName}}))
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040010238 { # became non-polymorphous class, removed v-table pointer
10239 %{$CompatProblems{$Level}{$Interface}{"Removed_Last_Virtual_Method"}{$tr_name{$RemovedVFunc}}}=(
10240 "Type_Name"=>$CName,
10241 "Type_Type"=>"Class",
10242 "Target"=>get_Signature($RemovedVFunc, 1) );
Andrey Ponomarenko16934472012-03-29 15:37:04 +040010243 $VTableChanged_M{$CName} = 1;
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040010244 }
10245 elsif($CompleteSignature{1}{$Interface}{"Virt"}
10246 or $CompleteSignature{1}{$Interface}{"PureVirt"})
10247 {
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040010248 if(defined $VirtualTable{1}{$CName} and defined $VirtualTable{2}{$CName})
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040010249 {
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040010250 if(not defined $VirtualTable{1}{$CName}{$Interface}) {
10251 next;
10252 }
10253 my $VPos_New = -1;
10254 if(defined $VirtualTable{2}{$CName}{$Interface})
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040010255 {
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040010256 $VPos_New = $VirtualTable{2}{$CName}{$Interface};
10257 }
10258 else
10259 {
10260 if($Interface ne $RemovedVFunc) {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040010261 next;
10262 }
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040010263 }
10264 my $VPos_Removed = $VirtualTable{1}{$CName}{$RemovedVFunc};
10265 my $VPos_Old = $VirtualTable{1}{$CName}{$Interface};
10266 if($VPos_Removed<=$VPos_Old and $VPos_Old!=$VPos_New)
10267 {
10268 my @Affected = ($Interface, keys(%{$OverriddenMethods{1}{$Interface}}));
10269 foreach my $ASymbol (@Affected)
10270 {
Andrey Ponomarenko85043792012-05-14 16:48:07 +040010271 if(not $CompleteSignature{1}{$ASymbol}{"PureVirt"})
10272 {
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040010273 if(not symbolFilter($ASymbol, 1, "Affected", $Level)) {
Andrey Ponomarenko85043792012-05-14 16:48:07 +040010274 next;
10275 }
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040010276 }
10277 my $ProblemType = "Removed_Virtual_Method";
10278 if($CompleteSignature{1}{$RemovedVFunc}{"PureVirt"}) {
10279 $ProblemType = "Removed_Pure_Virtual_Method";
10280 }
10281 $CheckedSymbols{$Level}{$ASymbol} = 1;
10282 %{$CompatProblems{$Level}{$ASymbol}{$ProblemType}{$tr_name{$RemovedVFunc}}}=(
10283 "Type_Name"=>$CName,
10284 "Type_Type"=>"Class",
10285 "Target"=>get_Signature($RemovedVFunc, 1) );
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040010286 $VTableChanged_M{$TypeInfo{1}{$CompleteSignature{1}{$ASymbol}{"Class"}}{"Name"}} = 1;
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040010287 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040010288 }
10289 }
10290 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010291 }
10292 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040010293 else
10294 { # Source-level
10295 foreach my $AddedVFunc (keys(%{$AddedInt_Virt{$Level}{$CName}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010296 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040010297 next if($Interface eq $AddedVFunc);
10298 if($CompleteSignature{2}{$AddedVFunc}{"PureVirt"})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010299 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040010300 %{$CompatProblems{$Level}{$Interface}{"Added_Pure_Virtual_Method"}{$tr_name{$AddedVFunc}}}=(
10301 "Type_Name"=>$CName,
10302 "Type_Type"=>"Class",
10303 "Target"=>get_Signature($AddedVFunc, 2) );
10304 }
10305 }
10306 foreach my $RemovedVFunc (keys(%{$RemovedInt_Virt{$Level}{$CName}}))
10307 {
10308 if($CompleteSignature{1}{$RemovedVFunc}{"PureVirt"})
10309 {
10310 %{$CompatProblems{$Level}{$Interface}{"Removed_Pure_Virtual_Method"}{$tr_name{$RemovedVFunc}}}=(
10311 "Type_Name"=>$CName,
10312 "Type_Type"=>"Class",
10313 "Target"=>get_Signature($RemovedVFunc, 1) );
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010314 }
10315 }
10316 }
10317}
10318
10319sub find_MemberPair_Pos_byName($$)
10320{
10321 my ($Member_Name, $Pair_Type) = @_;
10322 $Member_Name=~s/\A[_]+|[_]+\Z//g;
10323 foreach my $MemberPair_Pos (sort {int($a)<=>int($b)} keys(%{$Pair_Type->{"Memb"}}))
10324 {
10325 if(defined $Pair_Type->{"Memb"}{$MemberPair_Pos})
10326 {
10327 my $Name = $Pair_Type->{"Memb"}{$MemberPair_Pos}{"name"};
10328 $Name=~s/\A[_]+|[_]+\Z//g;
10329 if($Name eq $Member_Name) {
10330 return $MemberPair_Pos;
10331 }
10332 }
10333 }
10334 return "lost";
10335}
10336
10337sub find_MemberPair_Pos_byVal($$)
10338{
10339 my ($Member_Value, $Pair_Type) = @_;
10340 foreach my $MemberPair_Pos (sort {int($a)<=>int($b)} keys(%{$Pair_Type->{"Memb"}}))
10341 {
10342 if(defined $Pair_Type->{"Memb"}{$MemberPair_Pos}
10343 and $Pair_Type->{"Memb"}{$MemberPair_Pos}{"value"} eq $Member_Value) {
10344 return $MemberPair_Pos;
10345 }
10346 }
10347 return "lost";
10348}
10349
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040010350my %Severity_Val=(
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010351 "High"=>3,
10352 "Medium"=>2,
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040010353 "Low"=>1,
10354 "Safe"=>-1
10355);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010356
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040010357sub maxSeverity($$)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010358{
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040010359 my ($S1, $S2) = @_;
10360 if(cmpSeverities($S1, $S2)) {
10361 return $S1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010362 }
10363 else {
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040010364 return $S2;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010365 }
10366}
10367
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040010368sub cmpSeverities($$)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010369{
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040010370 my ($S1, $S2) = @_;
10371 if(not $S1) {
10372 return 0;
10373 }
10374 elsif(not $S2) {
10375 return 1;
10376 }
10377 return ($Severity_Val{$S1}>$Severity_Val{$S2});
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010378}
10379
10380sub getProblemSeverity($$)
10381{
10382 my ($Level, $Kind) = @_;
10383 return $CompatRules{$Level}{$Kind}{"Severity"};
10384}
10385
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040010386sub isRecurType($$)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010387{
10388 foreach (@RecurTypes)
10389 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040010390 if( $_->{"T1"} eq $_[0]
10391 and $_->{"T2"} eq $_[1] )
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010392 {
10393 return 1;
10394 }
10395 }
10396 return 0;
10397}
10398
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040010399sub pushType($$)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010400{
10401 my %TypeIDs=(
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040010402 "T1" => $_[0], #Tid1
10403 "T2" => $_[1] #Tid2
Andrey Ponomarenko16934472012-03-29 15:37:04 +040010404 );
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010405 push(@RecurTypes, \%TypeIDs);
10406}
10407
10408sub isRenamed($$$$$)
10409{
10410 my ($MemPos, $Type1, $LVersion1, $Type2, $LVersion2) = @_;
10411 my $Member_Name = $Type1->{"Memb"}{$MemPos}{"name"};
10412 my $MemberType_Id = $Type1->{"Memb"}{$MemPos}{"type"};
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +040010413 my %MemberType_Pure = get_PureType($MemberType_Id, $TypeInfo{$LVersion1});
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010414 if(not defined $Type2->{"Memb"}{$MemPos}) {
10415 return "";
10416 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040010417 my $PairType_Id = $Type2->{"Memb"}{$MemPos}{"type"};
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +040010418 my %PairType_Pure = get_PureType($PairType_Id, $TypeInfo{$LVersion2});
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010419
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040010420 my $Pair_Name = $Type2->{"Memb"}{$MemPos}{"name"};
10421 my $MemberPair_Pos_Rev = ($Member_Name eq $Pair_Name)?$MemPos:find_MemberPair_Pos_byName($Pair_Name, $Type1);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010422 if($MemberPair_Pos_Rev eq "lost")
10423 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040010424 if($MemberType_Pure{"Name"} eq $PairType_Pure{"Name"})
10425 { # base type match
10426 return $Pair_Name;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010427 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040010428 if($TypeInfo{$LVersion1}{$MemberType_Id}{"Name"} eq $TypeInfo{$LVersion2}{$PairType_Id}{"Name"})
10429 { # exact type match
10430 return $Pair_Name;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010431 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040010432 if($MemberType_Pure{"Size"} eq $PairType_Pure{"Size"})
10433 { # size match
10434 return $Pair_Name;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010435 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040010436 if(isReserved($Pair_Name))
10437 { # reserved fields
10438 return $Pair_Name;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010439 }
10440 }
10441 return "";
10442}
10443
10444sub isLastElem($$)
10445{
10446 my ($Pos, $TypeRef) = @_;
10447 my $Name = $TypeRef->{"Memb"}{$Pos}{"name"};
10448 if($Name=~/last|count|max|total/i)
10449 { # GST_LEVEL_COUNT, GST_RTSP_ELAST
10450 return 1;
10451 }
10452 elsif($Name=~/END|NLIMITS\Z/)
10453 { # __RLIMIT_NLIMITS
10454 return 1;
10455 }
10456 elsif($Name=~/\AN[A-Z](.+)[a-z]+s\Z/
10457 and $Pos+1==keys(%{$TypeRef->{"Memb"}}))
10458 { # NImageFormats, NColorRoles
10459 return 1;
10460 }
10461 return 0;
10462}
10463
10464sub nonComparable($$)
10465{
10466 my ($T1, $T2) = @_;
10467 if($T1->{"Name"} ne $T2->{"Name"}
10468 and not isAnon($T1->{"Name"})
10469 and not isAnon($T2->{"Name"}))
10470 { # different names
10471 if($T1->{"Type"} ne "Pointer"
10472 or $T2->{"Type"} ne "Pointer")
10473 { # compare base types
10474 return 1;
10475 }
10476 if($T1->{"Name"}!~/\Avoid\s*\*/
10477 and $T2->{"Name"}=~/\Avoid\s*\*/)
10478 {
10479 return 1;
10480 }
10481 }
10482 elsif($T1->{"Type"} ne $T2->{"Type"})
10483 { # different types
10484 if($T1->{"Type"} eq "Class"
10485 and $T2->{"Type"} eq "Struct")
10486 { # "class" to "struct"
10487 return 0;
10488 }
10489 elsif($T2->{"Type"} eq "Class"
10490 and $T1->{"Type"} eq "Struct")
10491 { # "struct" to "class"
10492 return 0;
10493 }
10494 else
10495 { # "class" to "enum"
10496 # "union" to "class"
10497 # ...
10498 return 1;
10499 }
10500 }
10501 return 0;
10502}
10503
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040010504sub mergeTypes($$$)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010505{
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040010506 my ($Type1_Id, $Type2_Id, $Level) = @_;
10507 return () if(not $Type1_Id or not $Type2_Id);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010508 my (%Sub_SubProblems, %SubProblems) = ();
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040010509 if($Cache{"mergeTypes"}{$Level}{$Type1_Id}{$Type2_Id})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010510 { # already merged
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040010511 return %{$Cache{"mergeTypes"}{$Level}{$Type1_Id}{$Type2_Id}};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010512 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040010513 my %Type1 = get_Type($Type1_Id, 1);
10514 my %Type2 = get_Type($Type2_Id, 2);
Andrey Ponomarenko16934472012-03-29 15:37:04 +040010515 if(not $Type1{"Name"} or not $Type2{"Name"}) {
10516 return ();
10517 }
10518 $CheckedTypes{$Level}{$Type1{"Name"}}=1;
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +040010519 my %Type1_Pure = get_PureType($Type1_Id, $TypeInfo{1});
10520 my %Type2_Pure = get_PureType($Type2_Id, $TypeInfo{2});
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040010521 $CheckedTypes{$Level}{$Type1_Pure{"Name"}}=1;
Andrey Ponomarenko85043792012-05-14 16:48:07 +040010522 if(not $Type1_Pure{"Size"} or not $Type2_Pure{"Size"})
10523 { # including a case when "class Class { ... };" changed to "class Class;"
10524 return ();
10525 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040010526 if(isRecurType($Type1_Pure{"Tid"}, $Type2_Pure{"Tid"}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010527 { # skip recursive declarations
10528 return ();
10529 }
10530 return () if(not $Type1_Pure{"Name"} or not $Type2_Pure{"Name"});
10531 return () if($SkipTypes{1}{$Type1_Pure{"Name"}});
10532 return () if($SkipTypes{1}{$Type1{"Name"}});
10533
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040010534 my %Typedef_1 = goToFirst($Type1{"Tid"}, 1, "Typedef");
10535 my %Typedef_2 = goToFirst($Type2{"Tid"}, 2, "Typedef");
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040010536 if(not $UseOldDumps and %Typedef_1 and %Typedef_2
10537 and $Typedef_1{"Type"} eq "Typedef" and $Typedef_2{"Type"} eq "Typedef"
10538 and $Typedef_1{"Name"} eq $Typedef_2{"Name"})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010539 {
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +040010540 my %Base_1 = get_OneStep_BaseType($Typedef_1{"Tid"}, $TypeInfo{1});
10541 my %Base_2 = get_OneStep_BaseType($Typedef_2{"Tid"}, $TypeInfo{2});
Andrey Ponomarenko85043792012-05-14 16:48:07 +040010542 if($Base_1{"Name"} ne $Base_2{"Name"})
10543 {
10544 if(differentDumps("G")
10545 or differentDumps("V"))
10546 { # different GCC versions or different dumps
10547 $Base_1{"Name"} = uncover_typedefs($Base_1{"Name"}, 1);
10548 $Base_2{"Name"} = uncover_typedefs($Base_2{"Name"}, 2);
10549 # std::__va_list and __va_list
10550 $Base_1{"Name"}=~s/\A(\w+::)+//;
10551 $Base_2{"Name"}=~s/\A(\w+::)+//;
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040010552 $Base_1{"Name"} = formatName($Base_1{"Name"}, "T");
10553 $Base_2{"Name"} = formatName($Base_2{"Name"}, "T");
Andrey Ponomarenko85043792012-05-14 16:48:07 +040010554 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010555 }
10556 if($Base_1{"Name"}!~/anon\-/ and $Base_2{"Name"}!~/anon\-/
10557 and $Base_1{"Name"} ne $Base_2{"Name"})
10558 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040010559 if($Level eq "Binary"
10560 and $Type1{"Size"} ne $Type2{"Size"})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010561 {
10562 %{$SubProblems{"DataType_Size"}{$Typedef_1{"Name"}}}=(
10563 "Target"=>$Typedef_1{"Name"},
10564 "Type_Name"=>$Typedef_1{"Name"},
10565 "Type_Type"=>"Typedef",
10566 "Old_Size"=>$Type1{"Size"}*$BYTE_SIZE,
10567 "New_Size"=>$Type2{"Size"}*$BYTE_SIZE );
10568 }
10569 %{$SubProblems{"Typedef_BaseType"}{$Typedef_1{"Name"}}}=(
10570 "Target"=>$Typedef_1{"Name"},
10571 "Type_Name"=>$Typedef_1{"Name"},
10572 "Type_Type"=>"Typedef",
10573 "Old_Value"=>$Base_1{"Name"},
10574 "New_Value"=>$Base_2{"Name"} );
10575 }
10576 }
10577 if(nonComparable(\%Type1_Pure, \%Type2_Pure))
10578 { # different types (reported in detectTypeChange(...))
10579 if($Type1_Pure{"Name"} eq $Type2_Pure{"Name"}
10580 and $Type1_Pure{"Type"} ne $Type2_Pure{"Type"}
10581 and $Type1_Pure{"Type"}!~/Intrinsic|Pointer|Ref|Typedef/)
10582 { # different type of the type
10583 %{$SubProblems{"DataType_Type"}{$Type1_Pure{"Name"}}}=(
10584 "Target"=>$Type1_Pure{"Name"},
10585 "Type_Name"=>$Type1_Pure{"Name"},
10586 "Type_Type"=>$Type1_Pure{"Type"},
10587 "Old_Value"=>lc($Type1_Pure{"Type"}),
10588 "New_Value"=>lc($Type2_Pure{"Type"}) );
10589 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040010590 %{$Cache{"mergeTypes"}{$Level}{$Type1_Id}{$Type2_Id}} = %SubProblems;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010591 return %SubProblems;
10592 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040010593 pushType($Type1_Pure{"Tid"}, $Type2_Pure{"Tid"});
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010594 if(($Type1_Pure{"Name"} eq $Type2_Pure{"Name"}
10595 or (isAnon($Type1_Pure{"Name"}) and isAnon($Type2_Pure{"Name"})))
10596 and $Type1_Pure{"Type"}=~/\A(Struct|Class|Union)\Z/)
10597 { # checking size
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040010598 if($Level eq "Binary"
10599 and $Type1_Pure{"Size"} ne $Type2_Pure{"Size"})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010600 {
10601 my $ProblemKind = "DataType_Size";
10602 if($Type1_Pure{"Type"} eq "Class"
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040010603 and keys(%{$ClassMethods{$Level}{1}{$Type1_Pure{"Name"}}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010604 {
10605 if(isCopyingClass($Type1_Pure{"Tid"}, 1)) {
10606 $ProblemKind = "Size_Of_Copying_Class";
10607 }
10608 elsif($AllocableClass{1}{$Type1_Pure{"Name"}})
10609 {
10610 if(int($Type2_Pure{"Size"})>int($Type1_Pure{"Size"})) {
10611 $ProblemKind = "Size_Of_Allocable_Class_Increased";
10612 }
10613 else {
10614 # descreased size of allocable class
10615 # it has no special effects
10616 }
10617 }
10618 }
10619 %{$SubProblems{$ProblemKind}{$Type1_Pure{"Name"}}}=(
10620 "Target"=>$Type1_Pure{"Name"},
10621 "Type_Name"=>$Type1_Pure{"Name"},
10622 "Type_Type"=>$Type1_Pure{"Type"},
10623 "Old_Size"=>$Type1_Pure{"Size"}*$BYTE_SIZE,
10624 "New_Size"=>$Type2_Pure{"Size"}*$BYTE_SIZE,
10625 "InitialType_Type"=>$Type1_Pure{"Type"} );
10626 }
10627 }
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040010628 if(defined $Type1_Pure{"BaseType"} and $Type1_Pure{"BaseType"}{"Tid"}
10629 and defined $Type2_Pure{"BaseType"} and $Type2_Pure{"BaseType"}{"Tid"})
10630 { # checking base types
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040010631 %Sub_SubProblems = mergeTypes($Type1_Pure{"BaseType"}{"Tid"}, $Type2_Pure{"BaseType"}{"Tid"}, $Level);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010632 foreach my $Sub_SubProblemType (keys(%Sub_SubProblems))
10633 {
10634 foreach my $Sub_SubLocation (keys(%{$Sub_SubProblems{$Sub_SubProblemType}}))
10635 {
10636 foreach my $Attr (keys(%{$Sub_SubProblems{$Sub_SubProblemType}{$Sub_SubLocation}})) {
10637 $SubProblems{$Sub_SubProblemType}{$Sub_SubLocation}{$Attr} = $Sub_SubProblems{$Sub_SubProblemType}{$Sub_SubLocation}{$Attr};
10638 }
10639 $SubProblems{$Sub_SubProblemType}{$Sub_SubLocation}{"InitialType_Type"} = $Type1_Pure{"Type"};
10640 }
10641 }
10642 }
10643 my (%AddedField, %RemovedField, %RenamedField, %RenamedField_Rev, %RelatedField, %RelatedField_Rev) = ();
10644 my %NameToPosA = map {$Type1_Pure{"Memb"}{$_}{"name"}=>$_} keys(%{$Type1_Pure{"Memb"}});
10645 my %NameToPosB = map {$Type2_Pure{"Memb"}{$_}{"name"}=>$_} keys(%{$Type2_Pure{"Memb"}});
10646 foreach my $Member_Pos (sort {int($a) <=> int($b)} keys(%{$Type1_Pure{"Memb"}}))
10647 { # detect removed and renamed fields
10648 my $Member_Name = $Type1_Pure{"Memb"}{$Member_Pos}{"name"};
10649 next if(not $Member_Name);
10650 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);
10651 if($MemberPair_Pos eq "lost")
10652 {
10653 if($Type2_Pure{"Type"}=~/\A(Struct|Class|Union)\Z/)
10654 {
10655 if(isUnnamed($Member_Name))
10656 { # support for old-version dumps
10657 # unnamed fields have been introduced in the ACC 1.23 (dump 2.1 format)
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040010658 if(not checkDump(2, "2.1")) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010659 next;
10660 }
10661 }
10662 if(my $RenamedTo = isRenamed($Member_Pos, \%Type1_Pure, 1, \%Type2_Pure, 2))
10663 { # renamed
10664 $RenamedField{$Member_Pos}=$RenamedTo;
10665 $RenamedField_Rev{$NameToPosB{$RenamedTo}}=$Member_Name;
10666 }
10667 else
10668 { # removed
10669 $RemovedField{$Member_Pos}=1;
10670 }
10671 }
10672 elsif($Type1_Pure{"Type"} eq "Enum")
10673 {
10674 my $Member_Value1 = $Type1_Pure{"Memb"}{$Member_Pos}{"value"};
10675 next if($Member_Value1 eq "");
10676 $MemberPair_Pos = find_MemberPair_Pos_byVal($Member_Value1, \%Type2_Pure);
10677 if($MemberPair_Pos ne "lost")
10678 { # renamed
10679 my $RenamedTo = $Type2_Pure{"Memb"}{$MemberPair_Pos}{"name"};
10680 my $MemberPair_Pos_Rev = find_MemberPair_Pos_byName($RenamedTo, \%Type1_Pure);
10681 if($MemberPair_Pos_Rev eq "lost")
10682 {
10683 $RenamedField{$Member_Pos}=$RenamedTo;
10684 $RenamedField_Rev{$NameToPosB{$RenamedTo}}=$Member_Name;
10685 }
10686 else {
10687 $RemovedField{$Member_Pos}=1;
10688 }
10689 }
10690 else
10691 { # removed
10692 $RemovedField{$Member_Pos}=1;
10693 }
10694 }
10695 }
10696 else
10697 { # related
10698 $RelatedField{$Member_Pos} = $MemberPair_Pos;
10699 $RelatedField_Rev{$MemberPair_Pos} = $Member_Pos;
10700 }
10701 }
10702 foreach my $Member_Pos (sort {int($a) <=> int($b)} keys(%{$Type2_Pure{"Memb"}}))
10703 { # detect added fields
10704 my $Member_Name = $Type2_Pure{"Memb"}{$Member_Pos}{"name"};
10705 next if(not $Member_Name);
10706 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);
10707 if($MemberPair_Pos eq "lost")
10708 {
10709 if(isUnnamed($Member_Name))
10710 { # support for old-version dumps
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040010711 # unnamed fields have been introduced in the ACC 1.23 (dump 2.1 format)
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040010712 if(not checkDump(1, "2.1")) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010713 next;
10714 }
10715 }
10716 if($Type2_Pure{"Type"}=~/\A(Struct|Class|Union|Enum)\Z/)
10717 {
10718 if(not $RenamedField_Rev{$Member_Pos})
10719 { # added
10720 $AddedField{$Member_Pos}=1;
10721 }
10722 }
10723 }
10724 }
10725 if($Type2_Pure{"Type"}=~/\A(Struct|Class)\Z/)
10726 { # detect moved fields
10727 my (%RelPos, %RelPosName, %AbsPos) = ();
10728 my $Pos = 0;
10729 foreach my $Member_Pos (sort {int($a) <=> int($b)} keys(%{$Type1_Pure{"Memb"}}))
10730 { # relative positions in 1st version
10731 my $Member_Name = $Type1_Pure{"Memb"}{$Member_Pos}{"name"};
10732 next if(not $Member_Name);
10733 if(not $RemovedField{$Member_Pos})
10734 { # old type without removed fields
10735 $RelPos{1}{$Member_Name}=$Pos;
10736 $RelPosName{1}{$Pos} = $Member_Name;
10737 $AbsPos{1}{$Pos++} = $Member_Pos;
10738 }
10739 }
10740 $Pos = 0;
10741 foreach my $Member_Pos (sort {int($a) <=> int($b)} keys(%{$Type2_Pure{"Memb"}}))
10742 { # relative positions in 2nd version
10743 my $Member_Name = $Type2_Pure{"Memb"}{$Member_Pos}{"name"};
10744 next if(not $Member_Name);
10745 if(not $AddedField{$Member_Pos})
10746 { # new type without added fields
10747 $RelPos{2}{$Member_Name}=$Pos;
10748 $RelPosName{2}{$Pos} = $Member_Name;
10749 $AbsPos{2}{$Pos++} = $Member_Pos;
10750 }
10751 }
10752 foreach my $Member_Name (keys(%{$RelPos{1}}))
10753 {
10754 my $RPos1 = $RelPos{1}{$Member_Name};
10755 my $AbsPos1 = $NameToPosA{$Member_Name};
10756 my $Member_Name2 = $Member_Name;
10757 if(my $RenamedTo = $RenamedField{$AbsPos1})
10758 { # renamed
10759 $Member_Name2 = $RenamedTo;
10760 }
10761 my $RPos2 = $RelPos{2}{$Member_Name2};
10762 if($RPos2 ne "" and $RPos1 ne $RPos2)
10763 { # different relative positions
10764 my $AbsPos2 = $NameToPosB{$Member_Name2};
10765 if($AbsPos1 ne $AbsPos2)
10766 { # different absolute positions
10767 my $ProblemType = "Moved_Field";
10768 if(not isPublic(\%Type1_Pure, $AbsPos1))
10769 { # may change layout and size of type
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040010770 if($Level eq "Source") {
10771 next;
10772 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010773 $ProblemType = "Moved_Private_Field";
10774 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040010775 if($Level eq "Binary"
10776 and $Type1_Pure{"Size"} ne $Type2_Pure{"Size"})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010777 { # affected size
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040010778 my $MemSize1 = $TypeInfo{1}{$Type1_Pure{"Memb"}{$AbsPos1}{"type"}}{"Size"};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010779 my $MovedAbsPos = $AbsPos{1}{$RPos2};
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040010780 my $MemSize2 = $TypeInfo{1}{$Type1_Pure{"Memb"}{$MovedAbsPos}{"type"}}{"Size"};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010781 if($MemSize1 ne $MemSize2) {
10782 $ProblemType .= "_And_Size";
10783 }
10784 }
10785 if($ProblemType eq "Moved_Private_Field") {
10786 next;
10787 }
10788 %{$SubProblems{$ProblemType}{$Member_Name}}=(
10789 "Target"=>$Member_Name,
10790 "Type_Name"=>$Type1_Pure{"Name"},
10791 "Type_Type"=>$Type1_Pure{"Type"},
10792 "Old_Value"=>$RPos1,
10793 "New_Value"=>$RPos2 );
10794 }
10795 }
10796 }
10797 }
10798 foreach my $Member_Pos (sort {int($a) <=> int($b)} keys(%{$Type1_Pure{"Memb"}}))
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040010799 { # check older fields, public and private
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010800 my $Member_Name = $Type1_Pure{"Memb"}{$Member_Pos}{"name"};
10801 next if(not $Member_Name);
10802 if(my $RenamedTo = $RenamedField{$Member_Pos})
10803 { # renamed
10804 if($Type2_Pure{"Type"}=~/\A(Struct|Class|Union)\Z/)
10805 {
10806 if(isPublic(\%Type1_Pure, $Member_Pos))
10807 {
10808 %{$SubProblems{"Renamed_Field"}{$Member_Name}}=(
10809 "Target"=>$Member_Name,
10810 "Type_Name"=>$Type1_Pure{"Name"},
10811 "Type_Type"=>$Type1_Pure{"Type"},
10812 "Old_Value"=>$Member_Name,
10813 "New_Value"=>$RenamedTo );
10814 }
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040010815 elsif(isReserved($Member_Name))
10816 {
10817 %{$SubProblems{"Used_Reserved_Field"}{$Member_Name}}=(
10818 "Target"=>$Member_Name,
10819 "Type_Name"=>$Type1_Pure{"Name"},
10820 "Type_Type"=>$Type1_Pure{"Type"},
10821 "Old_Value"=>$Member_Name,
10822 "New_Value"=>$RenamedTo );
10823 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010824 }
10825 elsif($Type1_Pure{"Type"} eq "Enum")
10826 {
10827 %{$SubProblems{"Enum_Member_Name"}{$Type1_Pure{"Memb"}{$Member_Pos}{"value"}}}=(
10828 "Target"=>$Type1_Pure{"Memb"}{$Member_Pos}{"value"},
10829 "Type_Name"=>$Type1_Pure{"Name"},
10830 "Type_Type"=>$Type1_Pure{"Type"},
10831 "Old_Value"=>$Member_Name,
10832 "New_Value"=>$RenamedTo );
10833 }
10834 }
10835 elsif($RemovedField{$Member_Pos})
10836 { # removed
10837 if($Type2_Pure{"Type"}=~/\A(Struct|Class)\Z/)
10838 {
10839 my $ProblemType = "Removed_Field";
10840 if(not isPublic(\%Type1_Pure, $Member_Pos)
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040010841 or isUnnamed($Member_Name))
10842 {
10843 if($Level eq "Source") {
10844 next;
10845 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010846 $ProblemType = "Removed_Private_Field";
10847 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040010848 if($Level eq "Binary"
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +040010849 and not isMemPadded($Member_Pos, -1, \%Type1_Pure, \%RemovedField, $TypeInfo{1}, $WORD_SIZE{1}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010850 {
10851 if(my $MNum = isAccessible(\%Type1_Pure, \%RemovedField, $Member_Pos+1, -1))
10852 { # affected fields
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +040010853 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 +040010854 { # changed offset
10855 $ProblemType .= "_And_Layout";
10856 }
10857 }
10858 if($Type1_Pure{"Size"} ne $Type2_Pure{"Size"})
10859 { # affected size
10860 $ProblemType .= "_And_Size";
10861 }
10862 }
10863 if($ProblemType eq "Removed_Private_Field") {
10864 next;
10865 }
10866 %{$SubProblems{$ProblemType}{$Member_Name}}=(
10867 "Target"=>$Member_Name,
10868 "Type_Name"=>$Type1_Pure{"Name"},
10869 "Type_Type"=>$Type1_Pure{"Type"} );
10870 }
10871 elsif($Type2_Pure{"Type"} eq "Union")
10872 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040010873 if($Level eq "Binary"
10874 and $Type1_Pure{"Size"} ne $Type2_Pure{"Size"})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010875 {
10876 %{$SubProblems{"Removed_Union_Field_And_Size"}{$Member_Name}}=(
10877 "Target"=>$Member_Name,
10878 "Type_Name"=>$Type1_Pure{"Name"},
10879 "Type_Type"=>$Type1_Pure{"Type"} );
10880 }
10881 else
10882 {
10883 %{$SubProblems{"Removed_Union_Field"}{$Member_Name}}=(
10884 "Target"=>$Member_Name,
10885 "Type_Name"=>$Type1_Pure{"Name"},
10886 "Type_Type"=>$Type1_Pure{"Type"} );
10887 }
10888 }
10889 elsif($Type1_Pure{"Type"} eq "Enum")
10890 {
10891 %{$SubProblems{"Enum_Member_Removed"}{$Member_Name}}=(
10892 "Target"=>$Member_Name,
10893 "Type_Name"=>$Type1_Pure{"Name"},
10894 "Type_Type"=>$Type1_Pure{"Type"},
10895 "Old_Value"=>$Member_Name );
10896 }
10897 }
10898 else
10899 { # changed
10900 my $MemberPair_Pos = $RelatedField{$Member_Pos};
10901 if($Type1_Pure{"Type"} eq "Enum")
10902 {
10903 my $Member_Value1 = $Type1_Pure{"Memb"}{$Member_Pos}{"value"};
10904 next if($Member_Value1 eq "");
10905 my $Member_Value2 = $Type2_Pure{"Memb"}{$MemberPair_Pos}{"value"};
10906 next if($Member_Value2 eq "");
10907 if($Member_Value1 ne $Member_Value2)
10908 {
10909 my $ProblemType = "Enum_Member_Value";
10910 if(isLastElem($Member_Pos, \%Type1_Pure)) {
10911 $ProblemType = "Enum_Last_Member_Value";
10912 }
10913 %{$SubProblems{$ProblemType}{$Member_Name}}=(
10914 "Target"=>$Member_Name,
10915 "Type_Name"=>$Type1_Pure{"Name"},
10916 "Type_Type"=>$Type1_Pure{"Type"},
10917 "Old_Value"=>$Member_Value1,
10918 "New_Value"=>$Member_Value2 );
10919 }
10920 }
10921 elsif($Type2_Pure{"Type"}=~/\A(Struct|Class|Union)\Z/)
10922 {
10923 my $MemberType1_Id = $Type1_Pure{"Memb"}{$Member_Pos}{"type"};
10924 my $MemberType2_Id = $Type2_Pure{"Memb"}{$MemberPair_Pos}{"type"};
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040010925 my $SizeV1 = $TypeInfo{1}{$MemberType1_Id}{"Size"}*$BYTE_SIZE;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010926 if(my $BSize1 = $Type1_Pure{"Memb"}{$Member_Pos}{"bitfield"}) {
10927 $SizeV1 = $BSize1;
10928 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040010929 my $SizeV2 = $TypeInfo{2}{$MemberType2_Id}{"Size"}*$BYTE_SIZE;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010930 if(my $BSize2 = $Type2_Pure{"Memb"}{$MemberPair_Pos}{"bitfield"}) {
10931 $SizeV2 = $BSize2;
10932 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040010933 my $MemberType1_Name = $TypeInfo{1}{$MemberType1_Id}{"Name"};
10934 my $MemberType2_Name = $TypeInfo{2}{$MemberType2_Id}{"Name"};
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040010935 if($Level eq "Binary"
10936 and $SizeV1 ne $SizeV2)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010937 {
10938 if($MemberType1_Name eq $MemberType2_Name or (isAnon($MemberType1_Name) and isAnon($MemberType2_Name))
10939 or ($Type1_Pure{"Memb"}{$Member_Pos}{"bitfield"} and $Type2_Pure{"Memb"}{$MemberPair_Pos}{"bitfield"}))
10940 { # field size change (including anon-structures and unions)
10941 # - same types
10942 # - unnamed types
10943 # - bitfields
10944 my $ProblemType = "Field_Size";
10945 if(not isPublic(\%Type1_Pure, $Member_Pos)
10946 or isUnnamed($Member_Name))
10947 { # should not be accessed by applications, goes to "Low Severity"
10948 # example: "abidata" members in GStreamer types
10949 $ProblemType = "Private_".$ProblemType;
10950 }
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +040010951 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 +040010952 { # check an effect
10953 if(my $MNum = isAccessible(\%Type1_Pure, \%RemovedField, $Member_Pos+1, -1))
10954 { # public fields after the current
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +040010955 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 +040010956 { # changed offset
10957 $ProblemType .= "_And_Layout";
10958 }
10959 }
10960 if($Type1_Pure{"Size"} ne $Type2_Pure{"Size"}) {
10961 $ProblemType .= "_And_Type_Size";
10962 }
10963 }
10964 if($ProblemType eq "Private_Field_Size")
10965 { # private field size with no effect
10966 $ProblemType = "";
10967 }
10968 if($ProblemType)
10969 { # register a problem
10970 %{$SubProblems{$ProblemType}{$Member_Name}}=(
10971 "Target"=>$Member_Name,
10972 "Type_Name"=>$Type1_Pure{"Name"},
10973 "Type_Type"=>$Type1_Pure{"Type"},
10974 "Old_Size"=>$SizeV1,
10975 "New_Size"=>$SizeV2);
10976 }
10977 }
10978 }
10979 if($Type1_Pure{"Memb"}{$Member_Pos}{"bitfield"}
10980 or $Type2_Pure{"Memb"}{$MemberPair_Pos}{"bitfield"})
10981 { # do NOT check bitfield type changes
10982 next;
10983 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040010984 if(checkDump(1, "2.13") and checkDump(2, "2.13"))
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040010985 {
10986 if(not $Type1_Pure{"Memb"}{$Member_Pos}{"mutable"}
10987 and $Type2_Pure{"Memb"}{$MemberPair_Pos}{"mutable"})
10988 {
10989 %{$SubProblems{"Field_Became_Mutable"}{$Member_Name}}=(
10990 "Target"=>$Member_Name,
10991 "Type_Name"=>$Type1_Pure{"Name"},
10992 "Type_Type"=>$Type1_Pure{"Type"});
10993 }
10994 elsif($Type1_Pure{"Memb"}{$Member_Pos}{"mutable"}
10995 and not $Type2_Pure{"Memb"}{$MemberPair_Pos}{"mutable"})
10996 {
10997 %{$SubProblems{"Field_Became_NonMutable"}{$Member_Name}}=(
10998 "Target"=>$Member_Name,
10999 "Type_Name"=>$Type1_Pure{"Name"},
11000 "Type_Type"=>$Type1_Pure{"Type"});
11001 }
11002 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011003 %Sub_SubProblems = detectTypeChange($MemberType1_Id, $MemberType2_Id, "Field", $Level);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011004 foreach my $ProblemType (keys(%Sub_SubProblems))
11005 {
11006 my $Old_Value = $Sub_SubProblems{$ProblemType}{"Old_Value"};
11007 my $New_Value = $Sub_SubProblems{$ProblemType}{"New_Value"};
11008 if($ProblemType eq "Field_Type"
11009 or $ProblemType eq "Field_Type_And_Size")
11010 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040011011 if(checkDump(1, "2.6") and checkDump(2, "2.6"))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011012 {
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040011013 if(my $RA = addedQual($Old_Value, $New_Value, "volatile"))
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011014 {
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040011015 %{$Sub_SubProblems{"Field_Became_Volatile"}} = %{$Sub_SubProblems{$ProblemType}};
11016 if($Level eq "Source"
11017 and cmpBTypes($Old_Value, $New_Value, 1, 2)) {
11018 delete($Sub_SubProblems{$ProblemType});
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011019 }
11020 }
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040011021 elsif(my $RR = removedQual($Old_Value, $New_Value, "volatile"))
11022 {
11023 %{$Sub_SubProblems{"Field_Became_NonVolatile"}} = %{$Sub_SubProblems{$ProblemType}};
11024 if($Level eq "Source"
11025 and cmpBTypes($Old_Value, $New_Value, 1, 2)) {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011026 delete($Sub_SubProblems{$ProblemType});
11027 }
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040011028 }
11029 }
11030 if(my $RA = addedQual($Old_Value, $New_Value, "const"))
11031 {
11032 if($RA==2) {
11033 %{$Sub_SubProblems{"Field_Added_Const"}} = %{$Sub_SubProblems{$ProblemType}};
11034 }
11035 else {
11036 %{$Sub_SubProblems{"Field_Became_Const"}} = %{$Sub_SubProblems{$ProblemType}};
11037 }
11038 if($Level eq "Source"
11039 and cmpBTypes($Old_Value, $New_Value, 1, 2)) {
11040 delete($Sub_SubProblems{$ProblemType});
11041 }
11042 }
11043 elsif(my $RR = removedQual($Old_Value, $New_Value, "const"))
11044 {
11045 if($RR==2) {
11046 %{$Sub_SubProblems{"Field_Removed_Const"}} = %{$Sub_SubProblems{$ProblemType}};
11047 }
11048 else {
11049 %{$Sub_SubProblems{"Field_Became_NonConst"}} = %{$Sub_SubProblems{$ProblemType}};
11050 }
11051 if($Level eq "Source"
11052 and cmpBTypes($Old_Value, $New_Value, 1, 2)) {
11053 delete($Sub_SubProblems{$ProblemType});
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011054 }
11055 }
11056 }
11057 }
11058 foreach my $ProblemType (keys(%Sub_SubProblems))
11059 {
11060 my $ProblemType_Init = $ProblemType;
11061 if($ProblemType eq "Field_Type_And_Size")
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011062 { # Binary
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011063 if(not isPublic(\%Type1_Pure, $Member_Pos)
11064 or isUnnamed($Member_Name)) {
11065 $ProblemType = "Private_".$ProblemType;
11066 }
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +040011067 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 +040011068 { # check an effect
11069 if(my $MNum = isAccessible(\%Type1_Pure, \%RemovedField, $Member_Pos+1, -1))
11070 { # public fields after the current
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +040011071 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 +040011072 { # changed offset
11073 $ProblemType .= "_And_Layout";
11074 }
11075 }
11076 if($Type1_Pure{"Size"} ne $Type2_Pure{"Size"}) {
11077 $ProblemType .= "_And_Type_Size";
11078 }
11079 }
11080 }
11081 else
11082 {
11083 if(not isPublic(\%Type1_Pure, $Member_Pos)
11084 or isUnnamed($Member_Name)) {
11085 next;
11086 }
11087 }
11088 if($ProblemType eq "Private_Field_Type_And_Size")
11089 { # private field change with no effect
11090 next;
11091 }
11092 %{$SubProblems{$ProblemType}{$Member_Name}}=(
11093 "Target"=>$Member_Name,
11094 "Type_Name"=>$Type1_Pure{"Name"},
11095 "Type_Type"=>$Type1_Pure{"Type"} );
11096 foreach my $Attr (keys(%{$Sub_SubProblems{$ProblemType_Init}}))
11097 { # other properties
11098 $SubProblems{$ProblemType}{$Member_Name}{$Attr} = $Sub_SubProblems{$ProblemType_Init}{$Attr};
11099 }
11100 }
11101 if(not isPublic(\%Type1_Pure, $Member_Pos))
11102 { # do NOT check internal type changes
11103 next;
11104 }
11105 if($MemberType1_Id and $MemberType2_Id)
11106 {# checking member type changes (replace)
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040011107 %Sub_SubProblems = mergeTypes($MemberType1_Id, $MemberType2_Id, $Level);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011108 foreach my $Sub_SubProblemType (keys(%Sub_SubProblems))
11109 {
11110 foreach my $Sub_SubLocation (keys(%{$Sub_SubProblems{$Sub_SubProblemType}}))
11111 {
11112 my $NewLocation = ($Sub_SubLocation)?$Member_Name."->".$Sub_SubLocation:$Member_Name;
11113 $SubProblems{$Sub_SubProblemType}{$NewLocation}{"IsInTypeInternals"}=1;
11114 foreach my $Attr (keys(%{$Sub_SubProblems{$Sub_SubProblemType}{$Sub_SubLocation}})) {
11115 $SubProblems{$Sub_SubProblemType}{$NewLocation}{$Attr} = $Sub_SubProblems{$Sub_SubProblemType}{$Sub_SubLocation}{$Attr};
11116 }
11117 if($Sub_SubLocation!~/\-\>/) {
11118 $SubProblems{$Sub_SubProblemType}{$NewLocation}{"Start_Type_Name"} = $MemberType1_Name;
11119 }
11120 }
11121 }
11122 }
11123 }
11124 }
11125 }
11126 foreach my $Member_Pos (sort {int($a) <=> int($b)} keys(%{$Type2_Pure{"Memb"}}))
11127 { # checking added members, public and private
11128 my $Member_Name = $Type2_Pure{"Memb"}{$Member_Pos}{"name"};
11129 next if(not $Member_Name);
11130 if($AddedField{$Member_Pos})
11131 { # added
11132 if($Type2_Pure{"Type"}=~/\A(Struct|Class)\Z/)
11133 {
11134 my $ProblemType = "Added_Field";
11135 if(not isPublic(\%Type2_Pure, $Member_Pos)
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011136 or isUnnamed($Member_Name))
11137 {
11138 if($Level eq "Source") {
11139 next;
11140 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011141 $ProblemType = "Added_Private_Field";
11142 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011143 if($Level eq "Binary"
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +040011144 and not isMemPadded($Member_Pos, -1, \%Type2_Pure, \%AddedField, $TypeInfo{2}, $WORD_SIZE{2}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011145 {
11146 if(my $MNum = isAccessible(\%Type2_Pure, \%AddedField, $Member_Pos, -1))
11147 { # public fields after the current
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +040011148 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 +040011149 { # changed offset
11150 $ProblemType .= "_And_Layout";
11151 }
11152 }
11153 if($Type1_Pure{"Size"} ne $Type2_Pure{"Size"}) {
11154 $ProblemType .= "_And_Size";
11155 }
11156 }
11157 if($ProblemType eq "Added_Private_Field")
11158 { # skip added private fields
11159 next;
11160 }
11161 %{$SubProblems{$ProblemType}{$Member_Name}}=(
11162 "Target"=>$Member_Name,
11163 "Type_Name"=>$Type1_Pure{"Name"},
11164 "Type_Type"=>$Type1_Pure{"Type"} );
11165 }
11166 elsif($Type2_Pure{"Type"} eq "Union")
11167 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011168 if($Level eq "Binary"
11169 and $Type1_Pure{"Size"} ne $Type2_Pure{"Size"})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011170 {
11171 %{$SubProblems{"Added_Union_Field_And_Size"}{$Member_Name}}=(
11172 "Target"=>$Member_Name,
11173 "Type_Name"=>$Type1_Pure{"Name"},
11174 "Type_Type"=>$Type1_Pure{"Type"} );
11175 }
11176 else
11177 {
11178 %{$SubProblems{"Added_Union_Field"}{$Member_Name}}=(
11179 "Target"=>$Member_Name,
11180 "Type_Name"=>$Type1_Pure{"Name"},
11181 "Type_Type"=>$Type1_Pure{"Type"} );
11182 }
11183 }
11184 elsif($Type2_Pure{"Type"} eq "Enum")
11185 {
11186 my $Member_Value = $Type2_Pure{"Memb"}{$Member_Pos}{"value"};
11187 next if($Member_Value eq "");
11188 %{$SubProblems{"Added_Enum_Member"}{$Member_Name}}=(
11189 "Target"=>$Member_Name,
11190 "Type_Name"=>$Type2_Pure{"Name"},
11191 "Type_Type"=>$Type2_Pure{"Type"},
11192 "New_Value"=>$Member_Value );
11193 }
11194 }
11195 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040011196 %{$Cache{"mergeTypes"}{$Level}{$Type1_Id}{$Type2_Id}} = %SubProblems;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011197 pop(@RecurTypes);
11198 return %SubProblems;
11199}
11200
11201sub isUnnamed($) {
11202 return $_[0]=~/\Aunnamed\d+\Z/;
11203}
11204
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040011205sub get_ShortType($$)
11206{
11207 my ($TypeId, $LibVersion) = @_;
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +040011208 my $TypeName = uncover_typedefs($TypeInfo{$LibVersion}{$TypeId}{"Name"}, $LibVersion);
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040011209 if(my $NameSpace = $TypeInfo{$LibVersion}{$TypeId}{"NameSpace"}) {
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040011210 $TypeName=~s/\A$NameSpace\:\://g;
11211 }
11212 return $TypeName;
11213}
11214
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040011215sub goToFirst($$$)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011216{
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040011217 my ($TypeId, $LibVersion, $Type_Type) = @_;
Andrey Ponomarenko16934472012-03-29 15:37:04 +040011218 return () if(not $TypeId);
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040011219 if(defined $Cache{"goToFirst"}{$TypeId}{$LibVersion}{$Type_Type}) {
11220 return %{$Cache{"goToFirst"}{$TypeId}{$LibVersion}{$Type_Type}};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011221 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040011222 return () if(not $TypeInfo{$LibVersion}{$TypeId});
11223 my %Type = %{$TypeInfo{$LibVersion}{$TypeId}};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011224 return () if(not $Type{"Type"});
11225 if($Type{"Type"} ne $Type_Type)
11226 {
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040011227 return () if(not defined $Type{"BaseType"});
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040011228 return () if(not $Type{"BaseType"}{"Tid"});
11229 %Type = goToFirst($Type{"BaseType"}{"Tid"}, $LibVersion, $Type_Type);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011230 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040011231 $Cache{"goToFirst"}{$TypeId}{$LibVersion}{$Type_Type} = \%Type;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011232 return %Type;
11233}
11234
11235my %TypeSpecAttributes = (
11236 "Const" => 1,
11237 "Volatile" => 1,
11238 "ConstVolatile" => 1,
11239 "Restrict" => 1,
11240 "Typedef" => 1
11241);
11242
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040011243sub get_PureType($$)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011244{
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +040011245 my ($TypeId, $Info) = @_;
11246 if(not $TypeId or not $Info
11247 or not $Info->{$TypeId}) {
11248 return ();
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011249 }
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +040011250 if(defined $Cache{"get_PureType"}{$TypeId}{$Info}) {
11251 return %{$Cache{"get_PureType"}{$TypeId}{$Info}};
11252 }
11253 my %Type = %{$Info->{$TypeId}};
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040011254 return %Type if(not defined $Type{"BaseType"});
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040011255 return %Type if(not $Type{"BaseType"}{"Tid"});
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011256 if($TypeSpecAttributes{$Type{"Type"}}) {
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +040011257 %Type = get_PureType($Type{"BaseType"}{"Tid"}, $Info);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011258 }
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +040011259 $Cache{"get_PureType"}{$TypeId}{$Info} = \%Type;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011260 return %Type;
11261}
11262
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040011263sub get_PLevel($$)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011264{
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040011265 my ($TypeId, $LibVersion) = @_;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011266 return 0 if(not $TypeId);
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040011267 if(defined $Cache{"get_PLevel"}{$TypeId}{$LibVersion}) {
11268 return $Cache{"get_PLevel"}{$TypeId}{$LibVersion};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011269 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040011270 return 0 if(not $TypeInfo{$LibVersion}{$TypeId});
11271 my %Type = %{$TypeInfo{$LibVersion}{$TypeId}};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011272 return 1 if($Type{"Type"}=~/FuncPtr|MethodPtr|FieldPtr/);
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040011273 return 0 if(not defined $Type{"BaseType"});
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040011274 return 0 if(not $Type{"BaseType"}{"Tid"});
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011275 my $PointerLevel = 0;
11276 if($Type{"Type"} =~/Pointer|Ref|FuncPtr|MethodPtr|FieldPtr/) {
11277 $PointerLevel += 1;
11278 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040011279 $PointerLevel += get_PLevel($Type{"BaseType"}{"Tid"}, $LibVersion);
11280 $Cache{"get_PLevel"}{$TypeId}{$LibVersion} = $PointerLevel;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011281 return $PointerLevel;
11282}
11283
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040011284sub get_BaseType($$)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011285{
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040011286 my ($TypeId, $LibVersion) = @_;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011287 return () if(not $TypeId);
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040011288 if(defined $Cache{"get_BaseType"}{$TypeId}{$LibVersion}) {
11289 return %{$Cache{"get_BaseType"}{$TypeId}{$LibVersion}};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011290 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040011291 return () if(not $TypeInfo{$LibVersion}{$TypeId});
11292 my %Type = %{$TypeInfo{$LibVersion}{$TypeId}};
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040011293 return %Type if(not defined $Type{"BaseType"});
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040011294 return %Type if(not $Type{"BaseType"}{"Tid"});
11295 %Type = get_BaseType($Type{"BaseType"}{"Tid"}, $LibVersion);
11296 $Cache{"get_BaseType"}{$TypeId}{$LibVersion} = \%Type;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011297 return %Type;
11298}
11299
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040011300sub get_BaseTypeQual($$)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011301{
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040011302 my ($TypeId, $LibVersion) = @_;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011303 return "" if(not $TypeId);
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040011304 return "" if(not $TypeInfo{$LibVersion}{$TypeId});
11305 my %Type = %{$TypeInfo{$LibVersion}{$TypeId}};
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040011306 return "" if(not defined $Type{"BaseType"});
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040011307 return "" if(not $Type{"BaseType"}{"Tid"});
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011308 my $Qual = "";
11309 if($Type{"Type"} eq "Pointer") {
11310 $Qual .= "*";
11311 }
11312 elsif($Type{"Type"} eq "Ref") {
11313 $Qual .= "&";
11314 }
11315 elsif($Type{"Type"} eq "ConstVolatile") {
11316 $Qual .= "const volatile";
11317 }
11318 elsif($Type{"Type"} eq "Const"
11319 or $Type{"Type"} eq "Volatile"
11320 or $Type{"Type"} eq "Restrict") {
11321 $Qual .= lc($Type{"Type"});
11322 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040011323 my $BQual = get_BaseTypeQual($Type{"BaseType"}{"Tid"}, $LibVersion);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011324 return $BQual.$Qual;
11325}
11326
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040011327sub get_OneStep_BaseType($$)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011328{
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +040011329 my ($TypeId, $Info) = @_;
11330 if(not $TypeId or not $Info
11331 or not $Info->{$TypeId}) {
11332 return ();
11333 }
11334 my %Type = %{$Info->{$TypeId}};
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040011335 return %Type if(not defined $Type{"BaseType"});
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +040011336 if(my $BTid = $Type{"BaseType"}{"Tid"})
11337 {
11338 if($Info->{$BTid}) {
11339 return %{$Info->{$BTid}};
11340 }
11341 else { # something is going wrong
11342 return ();
11343 }
11344 }
11345 else {
11346 return %Type;
11347 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011348}
11349
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040011350sub get_Type($$)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011351{
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040011352 my ($TypeId, $LibVersion) = @_;
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040011353 return () if(not $TypeId);
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040011354 return () if(not $TypeInfo{$LibVersion}{$TypeId});
11355 return %{$TypeInfo{$LibVersion}{$TypeId}};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011356}
11357
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +040011358sub isPrivateData($)
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040011359{ # non-public global data
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011360 my $Symbol = $_[0];
11361 return ($Symbol=~/\A(_ZGV|_ZTI|_ZTS|_ZTT|_ZTV|_ZTC|_ZThn|_ZTv0_n)/);
11362}
11363
Andrey Ponomarenko01117f12012-06-26 12:23:02 +040011364sub isInLineInst($$$) {
11365 return (isTemplateInstance(@_) and not isTemplateSpec(@_));
11366}
11367
11368sub isTemplateInstance($$$)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011369{
Andrey Ponomarenko01117f12012-06-26 12:23:02 +040011370 my ($Symbol, $SInfo, $LibVersion) = @_;
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040011371 if($CheckObjectsOnly)
11372 {
11373 if($Symbol!~/\A(_Z|\?)/) {
11374 return 0;
11375 }
11376 if(my $Signature = $tr_name{$Symbol})
11377 {
11378 if(index($Signature,">")==-1) {
11379 return 0;
11380 }
11381 if(my $ShortName = substr($Signature, 0, find_center($Signature, "(")))
11382 {
Andrey Ponomarenko01117f12012-06-26 12:23:02 +040011383 if(index($ShortName,"<")!=-1
11384 and index($ShortName,">")!=-1) {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040011385 return 1;
11386 }
11387 }
11388 }
11389 }
11390 else
11391 {
Andrey Ponomarenko01117f12012-06-26 12:23:02 +040011392 if(my $ClassId = $SInfo->{"Class"})
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040011393 {
11394 if(my $ClassName = $TypeInfo{$LibVersion}{$ClassId}{"Name"})
11395 {
11396 if(index($ClassName,"<")!=-1) {
11397 return 1;
11398 }
11399 }
11400 }
Andrey Ponomarenko01117f12012-06-26 12:23:02 +040011401 if(my $ShortName = $SInfo->{"ShortName"})
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040011402 {
Andrey Ponomarenko01117f12012-06-26 12:23:02 +040011403 if(index($ShortName,"<")!=-1
11404 and index($ShortName,">")!=-1) {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040011405 return 1;
11406 }
11407 }
11408 }
11409 return 0;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011410}
11411
Andrey Ponomarenko01117f12012-06-26 12:23:02 +040011412sub isTemplateSpec($$$)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011413{
Andrey Ponomarenko01117f12012-06-26 12:23:02 +040011414 my ($Symbol, $SInfo, $LibVersion) = @_;
11415 if(my $ClassId = $SInfo->{"Class"})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011416 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040011417 if($TypeInfo{$LibVersion}{$ClassId}{"Spec"})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011418 { # class specialization
11419 return 1;
11420 }
Andrey Ponomarenko01117f12012-06-26 12:23:02 +040011421 elsif($SInfo->{"Spec"})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011422 { # method specialization
11423 return 1;
11424 }
11425 }
11426 return 0;
11427}
11428
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011429sub symbolFilter($$$$)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011430{ # some special cases when the symbol cannot be imported
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011431 my ($Symbol, $LibVersion, $Type, $Level) = @_;
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +040011432 if(isPrivateData($Symbol))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011433 { # non-public global data
11434 return 0;
11435 }
11436 if($CheckObjectsOnly) {
11437 return 0 if($Symbol=~/\A(_init|_fini)\Z/);
11438 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040011439 if($CheckHeadersOnly and not checkDump($LibVersion, "2.7"))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011440 { # support for old ABI dumps in --headers-only mode
11441 foreach my $Pos (keys(%{$CompleteSignature{$LibVersion}{$Symbol}{"Param"}}))
11442 {
11443 if(my $Pid = $CompleteSignature{$LibVersion}{$Symbol}{"Param"}{$Pos}{"type"})
11444 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040011445 my $PType = $TypeInfo{$LibVersion}{$Pid}{"Type"};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011446 if(not $PType or $PType eq "Unknown") {
11447 return 0;
11448 }
11449 }
11450 }
11451 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +040011452 if($Type=~/Affected/)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011453 {
11454 my $ClassId = $CompleteSignature{$LibVersion}{$Symbol}{"Class"};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011455 if($SkipSymbols{$LibVersion}{$Symbol})
11456 { # user defined symbols to ignore
11457 return 0;
11458 }
11459 my $NameSpace = $CompleteSignature{$LibVersion}{$Symbol}{"NameSpace"};
11460 if(not $NameSpace and $ClassId)
11461 { # class methods have no "NameSpace" attribute
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040011462 $NameSpace = $TypeInfo{$LibVersion}{$ClassId}{"NameSpace"};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011463 }
11464 if($NameSpace)
11465 { # user defined namespaces to ignore
11466 if($SkipNameSpaces{$LibVersion}{$NameSpace}) {
11467 return 0;
11468 }
11469 foreach my $NS (keys(%{$SkipNameSpaces{$LibVersion}}))
11470 { # nested namespaces
11471 if($NameSpace=~/\A\Q$NS\E(\:\:|\Z)/) {
11472 return 0;
11473 }
11474 }
11475 }
11476 if(my $Header = $CompleteSignature{$LibVersion}{$Symbol}{"Header"})
11477 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040011478 if(my $Skip = skipHeader($Header, $LibVersion))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011479 { # --skip-headers or <skip_headers> (not <skip_including>)
11480 if($Skip==1) {
11481 return 0;
11482 }
11483 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011484 }
11485 if($SymbolsListPath and not $SymbolsList{$Symbol})
11486 { # user defined symbols
11487 return 0;
11488 }
11489 if($AppPath and not $SymbolsList_App{$Symbol})
11490 { # user defined symbols (in application)
11491 return 0;
11492 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +040011493 if(not selectSymbol($Symbol, $CompleteSignature{$LibVersion}{$Symbol}, $Level, $LibVersion))
11494 { # non-target symbols
11495 return 0;
11496 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011497 if($Level eq "Binary")
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011498 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040011499 if($CheckObjectsOnly)
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011500 {
Andrey Ponomarenko01117f12012-06-26 12:23:02 +040011501 if(isTemplateInstance($Symbol, $CompleteSignature{$LibVersion}{$Symbol}, $LibVersion)) {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040011502 return 0;
11503 }
11504 }
11505 else
11506 {
11507 if($CompleteSignature{$LibVersion}{$Symbol}{"InLine"}
Andrey Ponomarenko01117f12012-06-26 12:23:02 +040011508 or isInLineInst($Symbol, $CompleteSignature{$LibVersion}{$Symbol}, $LibVersion))
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040011509 {
11510 if($ClassId and $CompleteSignature{$LibVersion}{$Symbol}{"Virt"})
11511 { # inline virtual methods
11512 if($Type=~/InlineVirt/) {
11513 return 1;
11514 }
11515 my $Allocable = (not isCopyingClass($ClassId, $LibVersion));
11516 if(not $Allocable)
11517 { # check bases
11518 foreach my $DCId (get_sub_classes($ClassId, $LibVersion, 1))
11519 {
11520 if(not isCopyingClass($DCId, $LibVersion))
11521 { # exists a derived class without default c-tor
11522 $Allocable=1;
11523 last;
11524 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011525 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011526 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040011527 if(not $Allocable) {
11528 return 0;
11529 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011530 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040011531 else
11532 { # inline non-virtual methods
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011533 return 0;
11534 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011535 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011536 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011537 }
11538 }
11539 return 1;
11540}
11541
11542sub mergeImpl()
11543{
11544 my $DiffCmd = get_CmdPath("diff");
11545 if(not $DiffCmd) {
11546 exitStatus("Not_Found", "can't find \"diff\"");
11547 }
11548 foreach my $Interface (sort keys(%{$Symbol_Library{1}}))
11549 { # implementation changes
11550 next if($CompleteSignature{1}{$Interface}{"Private"});
11551 next if(not $CompleteSignature{1}{$Interface}{"Header"} and not $CheckObjectsOnly);
11552 next if(not $Symbol_Library{2}{$Interface} and not $Symbol_Library{2}{$SymVer{2}{$Interface}});
Andrey Ponomarenko85043792012-05-14 16:48:07 +040011553 if(not symbolFilter($Interface, 1, "Affected", "Binary")) {
11554 next;
11555 }
Andrey Ponomarenko16934472012-03-29 15:37:04 +040011556 my $Impl1 = canonifyImpl($Interface_Impl{1}{$Interface});
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011557 next if(not $Impl1);
Andrey Ponomarenko16934472012-03-29 15:37:04 +040011558 my $Impl2 = canonifyImpl($Interface_Impl{2}{$Interface});
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011559 next if(not $Impl2);
11560 if($Impl1 ne $Impl2)
11561 {
11562 writeFile("$TMP_DIR/impl1", $Impl1);
11563 writeFile("$TMP_DIR/impl2", $Impl2);
Andrey Ponomarenkoa01311b2012-06-08 17:20:02 +040011564 my $Diff = `$DiffCmd -rNau \"$TMP_DIR/impl1\" \"$TMP_DIR/impl2\"`;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011565 $Diff=~s/(---|\+\+\+).+\n//g;
11566 $Diff=~s/[ ]{3,}/ /g;
11567 $Diff=~s/\n\@\@/\n \n\@\@/g;
Andrey Ponomarenkoa01311b2012-06-08 17:20:02 +040011568 unlink("$TMP_DIR/impl1");
11569 unlink("$TMP_DIR/impl2");
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011570 %{$ImplProblems{$Interface}}=(
11571 "Diff" => get_CodeView($Diff) );
11572 }
11573 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +040011574
11575 # clean memory
11576 %Interface_Impl = ();
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011577}
11578
Andrey Ponomarenko16934472012-03-29 15:37:04 +040011579sub canonifyImpl($)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011580{
11581 my $FuncBody= $_[0];
11582 return "" if(not $FuncBody);
11583 $FuncBody=~s/0x[a-f\d]+/0x?/g;# addr
11584 $FuncBody=~s/((\A|\n)[a-z]+[\t ]+)[a-f\d]+([^x]|\Z)/$1?$3/g;# call, jump
11585 $FuncBody=~s/# [a-f\d]+ /# ? /g;# call, jump
11586 $FuncBody=~s/%([a-z]+[a-f\d]*)/\%reg/g;# registers
11587 while($FuncBody=~s/\nnop[ \t]*(\n|\Z)/$1/g){};# empty op
11588 $FuncBody=~s/<.+?\.cpp.+?>/<name.cpp>/g;
11589 $FuncBody=~s/(\A|\n)[a-f\d]+ </$1? </g;# 5e74 <_ZN...
11590 $FuncBody=~s/\.L\d+/.L/g;
11591 $FuncBody=~s/#(-?)\d+/#$1?/g;# r3, [r3, #120]
11592 $FuncBody=~s/[\n]{2,}/\n/g;
11593 return $FuncBody;
11594}
11595
11596sub get_CodeView($)
11597{
11598 my $Code = $_[0];
11599 my $View = "";
11600 foreach my $Line (split(/\n/, $Code))
11601 {
11602 if($Line=~s/\A(\+|-)/$1 /g)
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040011603 { # bold line
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011604 $View .= "<tr><td><b>".htmlSpecChars($Line)."</b></td></tr>\n";
11605 }
11606 else {
11607 $View .= "<tr><td>".htmlSpecChars($Line)."</td></tr>\n";
11608 }
11609 }
11610 return "<table class='code_view'>$View</table>\n";
11611}
11612
11613sub getImplementations($$)
11614{
11615 my ($LibVersion, $Path) = @_;
11616 return if(not $LibVersion or not -e $Path);
11617 if($OSgroup eq "macos")
11618 {
11619 my $OtoolCmd = get_CmdPath("otool");
11620 if(not $OtoolCmd) {
11621 exitStatus("Not_Found", "can't find \"otool\"");
11622 }
11623 my $CurInterface = "";
Andrey Ponomarenkoa01311b2012-06-08 17:20:02 +040011624 foreach my $Line (split(/\n/, `$OtoolCmd -tv \"$Path\" 2>\"$TMP_DIR/null\"`))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011625 {
11626 if($Line=~/\A\s*_(\w+)\s*:/i) {
11627 $CurInterface = $1;
11628 }
11629 elsif($Line=~/\A\s*[\da-z]+\s+(.+?)\Z/i) {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040011630 $Interface_Impl{$LibVersion}{$CurInterface} .= $1."\n";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011631 }
11632 }
11633 }
11634 else
11635 {
11636 my $ObjdumpCmd = get_CmdPath("objdump");
11637 if(not $ObjdumpCmd) {
11638 exitStatus("Not_Found", "can't find \"objdump\"");
11639 }
11640 my $CurInterface = "";
Andrey Ponomarenkoa01311b2012-06-08 17:20:02 +040011641 foreach my $Line (split(/\n/, `$ObjdumpCmd -d \"$Path\" 2>\"$TMP_DIR/null\"`))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011642 {
11643 if($Line=~/\A[\da-z]+\s+<(\w+)>/i) {
11644 $CurInterface = $1;
11645 }
11646 else
11647 { # x86: 51fa:(\t)89 e5 (\t)mov %esp,%ebp
11648 # arm: 5020:(\t)e24cb004(\t)sub(\t)fp, ip, #4(\t); 0x4
11649 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 +040011650 $Interface_Impl{$LibVersion}{$CurInterface} .= $2."\n";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011651 }
11652 }
11653 }
11654 }
11655}
11656
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011657sub detectAdded($)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011658{
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011659 my $Level = $_[0];
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011660 foreach my $Symbol (keys(%{$Symbol_Library{2}}))
11661 {
11662 if(link_symbol($Symbol, 1, "+Deps"))
11663 { # linker can find a new symbol
11664 # in the old-version library
11665 # So, it's not a new symbol
11666 next;
11667 }
11668 if(my $VSym = $SymVer{2}{$Symbol}
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040011669 and index($Symbol,"\@")==-1) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011670 next;
11671 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011672 $AddedInt{$Level}{$Symbol} = 1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011673 }
11674}
11675
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011676sub detectRemoved($)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011677{
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011678 my $Level = $_[0];
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011679 foreach my $Symbol (keys(%{$Symbol_Library{1}}))
11680 {
11681 if($CheckObjectsOnly) {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011682 $CheckedSymbols{"Binary"}{$Symbol} = 1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011683 }
11684 if(link_symbol($Symbol, 2, "+Deps"))
11685 { # linker can find an old symbol
11686 # in the new-version library
11687 next;
11688 }
11689 if(my $VSym = $SymVer{1}{$Symbol}
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040011690 and index($Symbol,"\@")==-1) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011691 next;
11692 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011693 $RemovedInt{$Level}{$Symbol} = 1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011694 }
11695}
11696
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011697sub mergeLibs($)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011698{
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011699 my $Level = $_[0];
11700 foreach my $Symbol (sort keys(%{$AddedInt{$Level}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011701 { # checking added symbols
11702 next if($CompleteSignature{2}{$Symbol}{"Private"});
11703 next if(not $CompleteSignature{2}{$Symbol}{"Header"} and not $CheckObjectsOnly);
Andrey Ponomarenko85043792012-05-14 16:48:07 +040011704 next if(not symbolFilter($Symbol, 2, "Affected", $Level));
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011705 %{$CompatProblems{$Level}{$Symbol}{"Added_Symbol"}{""}}=();
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011706 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011707 foreach my $Symbol (sort keys(%{$RemovedInt{$Level}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011708 { # checking removed symbols
11709 next if($CompleteSignature{1}{$Symbol}{"Private"});
11710 next if(not $CompleteSignature{1}{$Symbol}{"Header"} and not $CheckObjectsOnly);
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040011711 if(index($Symbol, "_ZTV")==0)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011712 { # skip v-tables for templates, that should not be imported by applications
11713 next if($tr_name{$Symbol}=~/</);
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040011714 if(my $CName = $VTableClass{$Symbol})
11715 {
11716 if(not keys(%{$ClassMethods{$Level}{1}{$CName}}))
11717 { # vtables for "private" classes
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040011718 # use case: vtable for QDragManager (Qt 4.5.3 to 4.6.0) became HIDDEN symbol
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040011719 next;
11720 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011721 }
11722 }
11723 else {
Andrey Ponomarenko85043792012-05-14 16:48:07 +040011724 next if(not symbolFilter($Symbol, 1, "Affected", $Level));
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011725 }
11726 if($CompleteSignature{1}{$Symbol}{"PureVirt"})
11727 { # symbols for pure virtual methods cannot be called by clients
11728 next;
11729 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011730 %{$CompatProblems{$Level}{$Symbol}{"Removed_Symbol"}{""}}=();
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011731 }
11732}
11733
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040011734sub checkDump($$)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011735{
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040011736 my ($LibVersion, $V) = @_;
11737 if(defined $Cache{"checkDump"}{$LibVersion}{$V}) {
11738 return $Cache{"checkDump"}{$LibVersion}{$V};
11739 }
11740 return ($Cache{"checkDump"}{$LibVersion}{$V} = (not $UsedDump{$LibVersion}{"V"} or cmpVersions($UsedDump{$LibVersion}{"V"}, $V)>=0));
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011741}
11742
11743sub detectAdded_H($)
11744{
11745 my $Level = $_[0];
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011746 foreach my $Symbol (sort keys(%{$CompleteSignature{2}}))
11747 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011748 if($Level eq "Source")
11749 { # remove symbol version
11750 my ($SN, $SS, $SV) = separate_symbol($Symbol);
11751 $Symbol=$SN;
Andrey Ponomarenkob8d203d2012-05-25 18:11:07 +040011752
11753 if($CompleteSignature{2}{$Symbol}{"Artificial"})
11754 { # skip artificial constructors
11755 next;
11756 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011757 }
Andrey Ponomarenko16934472012-03-29 15:37:04 +040011758 if(not $CompleteSignature{2}{$Symbol}{"Header"}
11759 or not $CompleteSignature{2}{$Symbol}{"MnglName"}) {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011760 next;
11761 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040011762 if($ExtendedSymbols{$Symbol}) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011763 next;
11764 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011765 if(not defined $CompleteSignature{1}{$Symbol}
11766 or not $CompleteSignature{1}{$Symbol}{"MnglName"})
11767 {
Andrey Ponomarenko16934472012-03-29 15:37:04 +040011768 if($UsedDump{2}{"SrcBin"})
11769 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040011770 if($UsedDump{1}{"BinOnly"} or not checkDump(1, "2.11"))
Andrey Ponomarenko16934472012-03-29 15:37:04 +040011771 { # support for old and different (!) ABI dumps
11772 if(not $CompleteSignature{2}{$Symbol}{"Virt"}
11773 and not $CompleteSignature{2}{$Symbol}{"PureVirt"})
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011774 {
Andrey Ponomarenko16934472012-03-29 15:37:04 +040011775 if($CheckHeadersOnly)
Andrey Ponomarenko85043792012-05-14 16:48:07 +040011776 {
11777 if(my $Lang = $CompleteSignature{2}{$Symbol}{"Lang"})
11778 {
11779 if($Lang eq "C")
11780 { # support for old ABI dumps: missed extern "C" functions
11781 next;
11782 }
11783 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011784 }
Andrey Ponomarenko16934472012-03-29 15:37:04 +040011785 else
11786 {
11787 if(not link_symbol($Symbol, 2, "-Deps"))
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040011788 { # skip added inline symbols and const global data
Andrey Ponomarenko16934472012-03-29 15:37:04 +040011789 next;
11790 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011791 }
11792 }
11793 }
11794 }
11795 $AddedInt{$Level}{$Symbol} = 1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011796 }
11797 }
11798}
11799
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011800sub detectRemoved_H($)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011801{
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011802 my $Level = $_[0];
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011803 foreach my $Symbol (sort keys(%{$CompleteSignature{1}}))
11804 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011805 if($Level eq "Source")
11806 { # remove symbol version
11807 my ($SN, $SS, $SV) = separate_symbol($Symbol);
11808 $Symbol=$SN;
11809 }
Andrey Ponomarenko16934472012-03-29 15:37:04 +040011810 if(not $CompleteSignature{1}{$Symbol}{"Header"}
11811 or not $CompleteSignature{1}{$Symbol}{"MnglName"}) {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011812 next;
11813 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040011814 if($ExtendedSymbols{$Symbol}) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011815 next;
11816 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011817 if(not defined $CompleteSignature{2}{$Symbol}
11818 or not $CompleteSignature{2}{$Symbol}{"MnglName"})
Andrey Ponomarenko85043792012-05-14 16:48:07 +040011819 {
Andrey Ponomarenko16934472012-03-29 15:37:04 +040011820 if($UsedDump{1}{"SrcBin"})
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011821 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040011822 if($UsedDump{2}{"BinOnly"} or not checkDump(2, "2.11"))
Andrey Ponomarenko85043792012-05-14 16:48:07 +040011823 { # support for old and different (!) ABI dumps
Andrey Ponomarenko16934472012-03-29 15:37:04 +040011824 if(not $CompleteSignature{1}{$Symbol}{"Virt"}
11825 and not $CompleteSignature{1}{$Symbol}{"PureVirt"})
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011826 {
Andrey Ponomarenko16934472012-03-29 15:37:04 +040011827 if($CheckHeadersOnly)
11828 { # skip all removed symbols
Andrey Ponomarenko85043792012-05-14 16:48:07 +040011829 if(my $Lang = $CompleteSignature{1}{$Symbol}{"Lang"})
11830 {
11831 if($Lang eq "C")
11832 { # support for old ABI dumps: missed extern "C" functions
11833 next;
11834 }
11835 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011836 }
Andrey Ponomarenko16934472012-03-29 15:37:04 +040011837 else
11838 {
11839 if(not link_symbol($Symbol, 1, "-Deps"))
11840 { # skip removed inline symbols
11841 next;
11842 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011843 }
11844 }
11845 }
11846 }
Andrey Ponomarenkob8d203d2012-05-25 18:11:07 +040011847 if(not checkDump(1, "2.15"))
11848 {
11849 if($Symbol=~/_IT_E\Z/)
11850 { # _ZN28QExplicitlySharedDataPointerI22QSslCertificatePrivateEC1IT_EERKS_IT_E
11851 next;
11852 }
11853 }
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040011854 if(not $CompleteSignature{1}{$Symbol}{"Class"})
11855 {
11856 if(my $Short = $CompleteSignature{1}{$Symbol}{"ShortName"})
11857 {
11858 if(defined $Constants{2}{$Short})
11859 {
11860 my $Val = $Constants{2}{$Short}{"Value"};
11861 if(defined $Func_ShortName{2}{$Val})
11862 { # old name defined to new
11863 next;
11864 }
11865 }
11866 }
11867
11868 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011869 $RemovedInt{$Level}{$Symbol} = 1;
11870 if($Level eq "Source")
11871 { # search for a source-compatible equivalent
11872 setAlternative($Symbol, $Level);
11873 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011874 }
11875 }
11876}
11877
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011878sub mergeHeaders($)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011879{
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011880 my $Level = $_[0];
11881 foreach my $Symbol (sort keys(%{$AddedInt{$Level}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011882 { # checking added symbols
11883 next if($CompleteSignature{2}{$Symbol}{"PureVirt"});
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040011884 next if($CompleteSignature{2}{$Symbol}{"Private"});
11885 next if(not symbolFilter($Symbol, 2, "Affected", $Level));
Andrey Ponomarenko85043792012-05-14 16:48:07 +040011886 if($Level eq "Binary")
11887 {
11888 if($CompleteSignature{2}{$Symbol}{"InLine"})
11889 {
11890 if(not $CompleteSignature{2}{$Symbol}{"Virt"})
11891 { # skip inline non-virtual functions
11892 next;
11893 }
11894 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011895 }
11896 else
11897 { # Source
11898 if($SourceAlternative_B{$Symbol}) {
11899 next;
11900 }
11901 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011902 %{$CompatProblems{$Level}{$Symbol}{"Added_Symbol"}{""}}=();
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011903 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011904 foreach my $Symbol (sort keys(%{$RemovedInt{$Level}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011905 { # checking removed symbols
11906 next if($CompleteSignature{1}{$Symbol}{"PureVirt"});
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040011907 next if($CompleteSignature{1}{$Symbol}{"Private"});
11908 next if(not symbolFilter($Symbol, 1, "Affected", $Level));
Andrey Ponomarenko85043792012-05-14 16:48:07 +040011909 if($Level eq "Binary")
11910 {
11911 if($CompleteSignature{1}{$Symbol}{"InLine"})
11912 {
11913 if(not $CompleteSignature{1}{$Symbol}{"Virt"})
11914 { # skip inline non-virtual functions
11915 next;
11916 }
11917 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011918 }
11919 else
11920 { # Source
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040011921 if(my $Alt = $SourceAlternative{$Symbol})
11922 {
11923 if(defined $CompleteSignature{1}{$Alt}
11924 and $CompleteSignature{1}{$Symbol}{"Const"})
11925 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040011926 my $Cid = $CompleteSignature{1}{$Symbol}{"Class"};
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040011927 %{$CompatProblems{$Level}{$Symbol}{"Removed_Const_Overload"}{$tr_name{$Symbol}}}=(
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040011928 "Type_Name"=>$TypeInfo{1}{$Cid}{"Name"},
Andrey Ponomarenko85043792012-05-14 16:48:07 +040011929 "Type_Type"=>"Class",
11930 "Target"=>get_Signature($Alt, 1) );
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040011931 }
11932 else
11933 { # do NOT show removed symbol
11934 next;
11935 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011936 }
11937 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011938 %{$CompatProblems{$Level}{$Symbol}{"Removed_Symbol"}{""}}=();
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011939 }
11940}
11941
11942sub addParamNames($)
11943{
11944 my $LibraryVersion = $_[0];
11945 return if(not keys(%AddIntParams));
11946 my $SecondVersion = $LibraryVersion==1?2:1;
11947 foreach my $Interface (sort keys(%{$CompleteSignature{$LibraryVersion}}))
11948 {
11949 next if(not keys(%{$AddIntParams{$Interface}}));
11950 foreach my $ParamPos (sort {int($a)<=>int($b)} keys(%{$CompleteSignature{$LibraryVersion}{$Interface}{"Param"}}))
Andrey Ponomarenko85043792012-05-14 16:48:07 +040011951 { # add absent parameter names
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011952 my $ParamName = $CompleteSignature{$LibraryVersion}{$Interface}{"Param"}{$ParamPos}{"name"};
11953 if($ParamName=~/\Ap\d+\Z/ and my $NewParamName = $AddIntParams{$Interface}{$ParamPos})
Andrey Ponomarenko85043792012-05-14 16:48:07 +040011954 { # names from the external file
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011955 if(defined $CompleteSignature{$SecondVersion}{$Interface}
11956 and defined $CompleteSignature{$SecondVersion}{$Interface}{"Param"}{$ParamPos})
11957 {
11958 if($CompleteSignature{$SecondVersion}{$Interface}{"Param"}{$ParamPos}{"name"}=~/\Ap\d+\Z/) {
11959 $CompleteSignature{$LibraryVersion}{$Interface}{"Param"}{$ParamPos}{"name"} = $NewParamName;
11960 }
11961 }
11962 else {
11963 $CompleteSignature{$LibraryVersion}{$Interface}{"Param"}{$ParamPos}{"name"} = $NewParamName;
11964 }
11965 }
11966 }
11967 }
11968}
11969
11970sub detectChangedTypedefs()
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +040011971{ # detect changed typedefs to show
11972 # correct function signatures
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011973 foreach my $Typedef (keys(%{$Typedef_BaseName{1}}))
11974 {
11975 next if(not $Typedef);
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +040011976 my $BName1 = $Typedef_BaseName{1}{$Typedef};
11977 if(not $BName1 or isAnon($BName1)) {
11978 next;
11979 }
11980 my $BName2 = $Typedef_BaseName{2}{$Typedef};
11981 if(not $BName2 or isAnon($BName2)) {
11982 next;
11983 }
11984 if($BName1 ne $BName2) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011985 $ChangedTypedef{$Typedef} = 1;
11986 }
11987 }
11988}
11989
11990sub get_symbol_suffix($$)
11991{
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011992 my ($Symbol, $Full) = @_;
11993 my ($SN, $SO, $SV) = separate_symbol($Symbol);
Andrey Ponomarenko570ece52012-11-30 16:36:44 +040011994 $Symbol=$SN; # remove version
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011995 my $Signature = $tr_name{$Symbol};
Andrey Ponomarenko16934472012-03-29 15:37:04 +040011996 my $Suffix = substr($Signature, find_center($Signature, "("));
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011997 if(not $Full) {
11998 $Suffix=~s/(\))\s*(const volatile|volatile const|const|volatile)\Z/$1/g;
11999 }
12000 return $Suffix;
12001}
12002
12003sub get_symbol_prefix($$)
12004{
12005 my ($Symbol, $LibVersion) = @_;
12006 my $ShortName = $CompleteSignature{$LibVersion}{$Symbol}{"ShortName"};
12007 if(my $ClassId = $CompleteSignature{$LibVersion}{$Symbol}{"Class"})
12008 { # methods
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040012009 $ShortName = $TypeInfo{$LibVersion}{$ClassId}{"Name"}."::".$ShortName;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012010 }
12011 return $ShortName;
12012}
12013
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012014sub setAlternative($)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012015{
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012016 my $Symbol = $_[0];
12017 my $PSymbol = $Symbol;
12018 if(not defined $CompleteSignature{2}{$PSymbol}
12019 or (not $CompleteSignature{2}{$PSymbol}{"MnglName"}
12020 and not $CompleteSignature{2}{$PSymbol}{"ShortName"}))
12021 { # search for a pair
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040012022 if(my $ShortName = $CompleteSignature{1}{$PSymbol}{"ShortName"})
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012023 {
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040012024 if($CompleteSignature{1}{$PSymbol}{"Data"})
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012025 {
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040012026 if($PSymbol=~s/L(\d+$ShortName(E)\Z)/$1/
12027 or $PSymbol=~s/(\d+$ShortName(E)\Z)/L$1/)
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012028 {
12029 if(defined $CompleteSignature{2}{$PSymbol}
12030 and $CompleteSignature{2}{$PSymbol}{"MnglName"})
12031 {
12032 $SourceAlternative{$Symbol} = $PSymbol;
12033 $SourceAlternative_B{$PSymbol} = $Symbol;
12034 if(not defined $CompleteSignature{1}{$PSymbol}
12035 or not $CompleteSignature{1}{$PSymbol}{"MnglName"}) {
12036 $SourceReplacement{$Symbol} = $PSymbol;
12037 }
12038 }
12039 }
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040012040 }
12041 else
12042 {
12043 foreach my $Sp ("KV", "VK", "K", "V")
12044 {
12045 if($PSymbol=~s/\A_ZN$Sp/_ZN/
12046 or $PSymbol=~s/\A_ZN/_ZN$Sp/)
12047 {
12048 if(defined $CompleteSignature{2}{$PSymbol}
12049 and $CompleteSignature{2}{$PSymbol}{"MnglName"})
12050 {
12051 $SourceAlternative{$Symbol} = $PSymbol;
12052 $SourceAlternative_B{$PSymbol} = $Symbol;
12053 if(not defined $CompleteSignature{1}{$PSymbol}
12054 or not $CompleteSignature{1}{$PSymbol}{"MnglName"}) {
12055 $SourceReplacement{$Symbol} = $PSymbol;
12056 }
12057 }
12058 }
12059 $PSymbol = $Symbol;
12060 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012061 }
12062 }
12063 }
12064 return "";
12065}
12066
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040012067sub getSymKind($$)
12068{
12069 my ($Symbol, $LibVersion) = @_;
12070 if($CompleteSignature{$LibVersion}{$Symbol}{"Data"})
12071 {
12072 return "Global_Data";
12073 }
12074 elsif($CompleteSignature{$LibVersion}{$Symbol}{"Class"})
12075 {
12076 return "Method";
12077 }
12078 return "Function";
12079}
12080
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012081sub mergeSignatures($)
12082{
12083 my $Level = $_[0];
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012084 my %SubProblems = ();
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012085
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012086 mergeBases($Level);
12087
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012088 my %AddedOverloads = ();
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012089 foreach my $Symbol (sort keys(%{$AddedInt{$Level}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012090 { # check all added exported symbols
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012091 if(not $CompleteSignature{2}{$Symbol}{"Header"}) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012092 next;
12093 }
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040012094 if(defined $CompleteSignature{1}{$Symbol}
12095 and $CompleteSignature{1}{$Symbol}{"Header"})
12096 { # double-check added symbol
12097 next;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012098 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +040012099 if(not symbolFilter($Symbol, 2, "Affected", $Level)) {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012100 next;
12101 }
12102 if($Symbol=~/\A(_Z|\?)/)
12103 { # C++
12104 $AddedOverloads{get_symbol_prefix($Symbol, 2)}{get_symbol_suffix($Symbol, 1)} = $Symbol;
12105 }
12106 if(my $OverriddenMethod = $CompleteSignature{2}{$Symbol}{"Override"})
12107 { # register virtual overridings
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040012108 my $Cid = $CompleteSignature{2}{$Symbol}{"Class"};
12109 my $AffectedClass_Name = $TypeInfo{2}{$Cid}{"Name"};
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040012110 if(defined $CompleteSignature{1}{$OverriddenMethod} and $CompleteSignature{1}{$OverriddenMethod}{"Virt"}
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012111 and not $CompleteSignature{1}{$OverriddenMethod}{"Private"})
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040012112 {
12113 if($TName_Tid{1}{$AffectedClass_Name})
12114 { # class should exist in previous version
12115 if(not isCopyingClass($TName_Tid{1}{$AffectedClass_Name}, 1))
12116 { # old v-table is NOT copied by old applications
12117 %{$CompatProblems{$Level}{$OverriddenMethod}{"Overridden_Virtual_Method"}{$tr_name{$Symbol}}}=(
12118 "Type_Name"=>$AffectedClass_Name,
12119 "Type_Type"=>"Class",
12120 "Target"=>get_Signature($Symbol, 2),
12121 "Old_Value"=>get_Signature($OverriddenMethod, 2),
12122 "New_Value"=>get_Signature($Symbol, 2) );
12123 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012124 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012125 }
12126 }
12127 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012128 foreach my $Symbol (sort keys(%{$RemovedInt{$Level}}))
12129 { # check all removed exported symbols
12130 if(not $CompleteSignature{1}{$Symbol}{"Header"}) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012131 next;
12132 }
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040012133 if(defined $CompleteSignature{2}{$Symbol}
12134 and $CompleteSignature{2}{$Symbol}{"Header"})
12135 { # double-check removed symbol
12136 next;
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012137 }
12138 if($CompleteSignature{1}{$Symbol}{"Private"})
12139 { # skip private methods
12140 next;
12141 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +040012142 if(not symbolFilter($Symbol, 1, "Affected", $Level)) {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012143 next;
12144 }
12145 $CheckedSymbols{$Level}{$Symbol} = 1;
12146 if(my $OverriddenMethod = $CompleteSignature{1}{$Symbol}{"Override"})
12147 { # register virtual overridings
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040012148 my $Cid = $CompleteSignature{1}{$Symbol}{"Class"};
12149 my $AffectedClass_Name = $TypeInfo{1}{$Cid}{"Name"};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012150 if(defined $CompleteSignature{2}{$OverriddenMethod}
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040012151 and $CompleteSignature{2}{$OverriddenMethod}{"Virt"})
12152 {
12153 if($TName_Tid{2}{$AffectedClass_Name})
12154 { # class should exist in newer version
12155 if(not isCopyingClass($CompleteSignature{1}{$Symbol}{"Class"}, 1))
12156 { # old v-table is NOT copied by old applications
12157 %{$CompatProblems{$Level}{$Symbol}{"Overridden_Virtual_Method_B"}{$tr_name{$OverriddenMethod}}}=(
12158 "Type_Name"=>$AffectedClass_Name,
12159 "Type_Type"=>"Class",
12160 "Target"=>get_Signature($OverriddenMethod, 1),
12161 "Old_Value"=>get_Signature($Symbol, 1),
12162 "New_Value"=>get_Signature($OverriddenMethod, 1) );
12163 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012164 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012165 }
12166 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012167 if($Level eq "Binary"
12168 and $OSgroup eq "windows")
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012169 { # register the reason of symbol name change
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040012170 if(my $NewSym = $mangled_name{2}{$tr_name{$Symbol}})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012171 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040012172 if($AddedInt{$Level}{$NewSym})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012173 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040012174 if($CompleteSignature{1}{$Symbol}{"Static"} ne $CompleteSignature{2}{$NewSym}{"Static"})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012175 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040012176 if($CompleteSignature{2}{$NewSym}{"Static"})
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012177 {
12178 %{$CompatProblems{$Level}{$Symbol}{"Symbol_Became_Static"}{$tr_name{$Symbol}}}=(
12179 "Target"=>$tr_name{$Symbol},
12180 "Old_Value"=>$Symbol,
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040012181 "New_Value"=>$NewSym );
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012182 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012183 else
12184 {
12185 %{$CompatProblems{$Level}{$Symbol}{"Symbol_Became_NonStatic"}{$tr_name{$Symbol}}}=(
12186 "Target"=>$tr_name{$Symbol},
12187 "Old_Value"=>$Symbol,
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040012188 "New_Value"=>$NewSym );
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012189 }
12190 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040012191 if($CompleteSignature{1}{$Symbol}{"Virt"} ne $CompleteSignature{2}{$NewSym}{"Virt"})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012192 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040012193 if($CompleteSignature{2}{$NewSym}{"Virt"})
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012194 {
12195 %{$CompatProblems{$Level}{$Symbol}{"Symbol_Became_Virtual"}{$tr_name{$Symbol}}}=(
12196 "Target"=>$tr_name{$Symbol},
12197 "Old_Value"=>$Symbol,
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040012198 "New_Value"=>$NewSym );
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012199 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012200 else
12201 {
12202 %{$CompatProblems{$Level}{$Symbol}{"Symbol_Became_NonVirtual"}{$tr_name{$Symbol}}}=(
12203 "Target"=>$tr_name{$Symbol},
12204 "Old_Value"=>$Symbol,
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040012205 "New_Value"=>$NewSym );
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012206 }
12207 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040012208 my $RTId1 = $CompleteSignature{1}{$Symbol}{"Return"};
12209 my $RTId2 = $CompleteSignature{2}{$NewSym}{"Return"};
12210 my $RTName1 = $TypeInfo{1}{$RTId1}{"Name"};
12211 my $RTName2 = $TypeInfo{2}{$RTId2}{"Name"};
12212 if($RTName1 ne $RTName2)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012213 {
12214 my $ProblemType = "Symbol_Changed_Return";
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012215 if($CompleteSignature{1}{$Symbol}{"Data"}) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012216 $ProblemType = "Global_Data_Symbol_Changed_Type";
12217 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012218 %{$CompatProblems{$Level}{$Symbol}{$ProblemType}{$tr_name{$Symbol}}}=(
12219 "Target"=>$tr_name{$Symbol},
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040012220 "Old_Type"=>$RTName1,
12221 "New_Type"=>$RTName2,
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012222 "Old_Value"=>$Symbol,
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040012223 "New_Value"=>$NewSym );
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012224 }
12225 }
12226 }
12227 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012228 if($Symbol=~/\A(_Z|\?)/)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012229 { # C++
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012230 my $Prefix = get_symbol_prefix($Symbol, 1);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012231 if(my @Overloads = sort keys(%{$AddedOverloads{$Prefix}})
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012232 and not $AddedOverloads{$Prefix}{get_symbol_suffix($Symbol, 1)})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012233 { # changed signature: params, "const"-qualifier
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040012234 my $NewSym = $AddedOverloads{$Prefix}{$Overloads[0]};
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012235 if($CompleteSignature{1}{$Symbol}{"Constructor"})
12236 {
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +040012237 if($Symbol=~/(C1E|C2E)/)
12238 {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012239 my $CtorType = $1;
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040012240 $NewSym=~s/(C1E|C2E)/$CtorType/g;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012241 }
12242 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012243 elsif($CompleteSignature{1}{$Symbol}{"Destructor"})
12244 {
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +040012245 if($Symbol=~/(D0E|D1E|D2E)/)
12246 {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012247 my $DtorType = $1;
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040012248 $NewSym=~s/(D0E|D1E|D2E)/$DtorType/g;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012249 }
12250 }
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040012251 my $NS1 = $CompleteSignature{1}{$Symbol}{"NameSpace"};
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040012252 my $NS2 = $CompleteSignature{2}{$NewSym}{"NameSpace"};
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040012253 if((not $NS1 and not $NS2) or ($NS1 and $NS2 and $NS1 eq $NS2))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012254 { # from the same class and namespace
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012255 if($CompleteSignature{1}{$Symbol}{"Const"}
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040012256 and not $CompleteSignature{2}{$NewSym}{"Const"})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012257 { # "const" to non-"const"
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040012258 %{$CompatProblems{$Level}{$Symbol}{"Method_Became_NonConst"}{$tr_name{$Symbol}}}=(
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040012259 "Type_Name"=>$TypeInfo{1}{$CompleteSignature{1}{$Symbol}{"Class"}}{"Name"},
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012260 "Target"=>$tr_name{$Symbol},
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040012261 "New_Signature"=>get_Signature($NewSym, 2),
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012262 "Old_Value"=>$Symbol,
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040012263 "New_Value"=>$NewSym );
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012264 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012265 elsif(not $CompleteSignature{1}{$Symbol}{"Const"}
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040012266 and $CompleteSignature{2}{$NewSym}{"Const"})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012267 { # non-"const" to "const"
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040012268 %{$CompatProblems{$Level}{$Symbol}{"Method_Became_Const"}{$tr_name{$Symbol}}}=(
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012269 "Target"=>$tr_name{$Symbol},
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040012270 "New_Signature"=>get_Signature($NewSym, 2),
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012271 "Old_Value"=>$Symbol,
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040012272 "New_Value"=>$NewSym );
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012273 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012274 if($CompleteSignature{1}{$Symbol}{"Volatile"}
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040012275 and not $CompleteSignature{2}{$NewSym}{"Volatile"})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012276 { # "volatile" to non-"volatile"
12277
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040012278 %{$CompatProblems{$Level}{$Symbol}{"Method_Became_NonVolatile"}{$tr_name{$Symbol}}}=(
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012279 "Target"=>$tr_name{$Symbol},
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040012280 "New_Signature"=>get_Signature($NewSym, 2),
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012281 "Old_Value"=>$Symbol,
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040012282 "New_Value"=>$NewSym );
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012283 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012284 elsif(not $CompleteSignature{1}{$Symbol}{"Volatile"}
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040012285 and $CompleteSignature{2}{$NewSym}{"Volatile"})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012286 { # non-"volatile" to "volatile"
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040012287 %{$CompatProblems{$Level}{$Symbol}{"Method_Became_Volatile"}{$tr_name{$Symbol}}}=(
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012288 "Target"=>$tr_name{$Symbol},
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040012289 "New_Signature"=>get_Signature($NewSym, 2),
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012290 "Old_Value"=>$Symbol,
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040012291 "New_Value"=>$NewSym );
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012292 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040012293 if(get_symbol_suffix($Symbol, 0) ne get_symbol_suffix($NewSym, 0))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012294 { # params list
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012295 %{$CompatProblems{$Level}{$Symbol}{"Symbol_Changed_Parameters"}{$tr_name{$Symbol}}}=(
12296 "Target"=>$tr_name{$Symbol},
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040012297 "New_Signature"=>get_Signature($NewSym, 2),
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012298 "Old_Value"=>$Symbol,
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040012299 "New_Value"=>$NewSym );
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012300 }
12301 }
12302 }
12303 }
12304 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012305 foreach my $Symbol (sort keys(%{$CompleteSignature{1}}))
12306 { # checking symbols
12307 my ($SN, $SS, $SV) = separate_symbol($Symbol);
12308 if($Level eq "Source")
12309 { # remove symbol version
12310 $Symbol=$SN;
12311 }
12312 else
12313 { # Binary
12314 if(not $SV)
12315 { # symbol without version
12316 if(my $VSym = $SymVer{1}{$Symbol})
12317 { # the symbol is linked with versioned symbol
12318 if($CompleteSignature{2}{$VSym}{"MnglName"})
12319 { # show report for symbol@ver only
12320 next;
12321 }
12322 elsif(not link_symbol($VSym, 2, "-Deps"))
12323 { # changed version: sym@v1 to sym@v2
12324 # do NOT show report for symbol
12325 next;
12326 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012327 }
12328 }
12329 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012330 my $PSymbol = $Symbol;
12331 if($Level eq "Source"
12332 and my $S = $SourceReplacement{$Symbol})
12333 { # take a source-compatible replacement function
12334 $PSymbol = $S;
12335 }
12336 if($CompleteSignature{1}{$Symbol}{"Private"})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012337 { # private symbols
12338 next;
12339 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012340 if(not defined $CompleteSignature{1}{$Symbol}
12341 or not defined $CompleteSignature{2}{$PSymbol})
12342 { # no info
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012343 next;
12344 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012345 if(not $CompleteSignature{1}{$Symbol}{"MnglName"}
12346 or not $CompleteSignature{2}{$PSymbol}{"MnglName"})
12347 { # no mangled name
12348 next;
12349 }
12350 if(not $CompleteSignature{1}{$Symbol}{"Header"}
12351 or not $CompleteSignature{2}{$PSymbol}{"Header"})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012352 { # without a header
12353 next;
12354 }
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040012355
12356 if(not $CompleteSignature{1}{$Symbol}{"PureVirt"}
12357 and $CompleteSignature{2}{$PSymbol}{"PureVirt"})
12358 { # became pure
12359 next;
12360 }
12361 if($CompleteSignature{1}{$Symbol}{"PureVirt"}
12362 and not $CompleteSignature{2}{$PSymbol}{"PureVirt"})
12363 { # became non-pure
12364 next;
12365 }
12366
12367 if(not symbolFilter($Symbol, 1, "Affected + InlineVirt", $Level))
12368 { # exported, target, inline virtual and pure virtual
12369 next;
12370 }
12371 if(not symbolFilter($PSymbol, 2, "Affected + InlineVirt", $Level))
12372 { # exported, target, inline virtual and pure virtual
12373 next;
12374 }
12375
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040012376 if(checkDump(1, "2.13") and checkDump(2, "2.13"))
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040012377 {
12378 if($CompleteSignature{1}{$Symbol}{"Data"}
12379 and $CompleteSignature{2}{$PSymbol}{"Data"})
12380 {
12381 my $Value1 = $CompleteSignature{1}{$Symbol}{"Value"};
12382 my $Value2 = $CompleteSignature{2}{$PSymbol}{"Value"};
12383 if(defined $Value1)
12384 {
12385 $Value1 = showVal($Value1, $CompleteSignature{1}{$Symbol}{"Return"}, 1);
12386 if(defined $Value2)
12387 {
12388 $Value2 = showVal($Value2, $CompleteSignature{2}{$PSymbol}{"Return"}, 2);
12389 if($Value1 ne $Value2)
12390 {
12391 %{$CompatProblems{$Level}{$Symbol}{"Global_Data_Value_Changed"}{""}}=(
12392 "Old_Value"=>$Value1,
12393 "New_Value"=>$Value2,
12394 "Target"=>get_Signature($Symbol, 1) );
12395 }
12396 }
12397 }
12398 }
12399 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +040012400
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040012401 if($CompleteSignature{2}{$PSymbol}{"Private"})
12402 {
12403 %{$CompatProblems{$Level}{$Symbol}{getSymKind($Symbol, 1)."_Became_Private"}{""}}=(
12404 "Target"=>get_Signature_M($PSymbol, 2) );
12405 }
12406 elsif(not $CompleteSignature{1}{$Symbol}{"Protected"}
12407 and $CompleteSignature{2}{$PSymbol}{"Protected"})
12408 {
12409 %{$CompatProblems{$Level}{$Symbol}{getSymKind($Symbol, 1)."_Became_Protected"}{""}}=(
12410 "Target"=>get_Signature_M($PSymbol, 2) );
12411 }
12412 elsif($CompleteSignature{1}{$Symbol}{"Protected"}
12413 and not $CompleteSignature{2}{$PSymbol}{"Protected"})
12414 {
12415 %{$CompatProblems{$Level}{$Symbol}{getSymKind($Symbol, 1)."_Became_Public"}{""}}=(
12416 "Target"=>get_Signature_M($PSymbol, 2) );
12417 }
12418
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012419 # checking virtual table
Andrey Ponomarenko16934472012-03-29 15:37:04 +040012420 mergeVirtualTables($Symbol, $Level);
12421
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012422 if($COMPILE_ERRORS)
12423 { # if some errors occurred at the compiling stage
12424 # then some false positives can be skipped here
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012425 if(not $CompleteSignature{1}{$Symbol}{"Data"} and $CompleteSignature{2}{$PSymbol}{"Data"}
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040012426 and not $GlobalDataObject{2}{$Symbol})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012427 { # missed information about parameters in newer version
12428 next;
12429 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040012430 if($CompleteSignature{1}{$Symbol}{"Data"} and not $GlobalDataObject{1}{$Symbol}
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012431 and not $CompleteSignature{2}{$PSymbol}{"Data"})
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040012432 { # missed information about parameters in older version
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012433 next;
12434 }
12435 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012436 my ($MnglName, $VersionSpec, $SymbolVersion) = separate_symbol($Symbol);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012437 # checking attributes
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012438 if($CompleteSignature{2}{$PSymbol}{"Static"}
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040012439 and not $CompleteSignature{1}{$Symbol}{"Static"} and $Symbol=~/\A(_Z|\?)/)
12440 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012441 %{$CompatProblems{$Level}{$Symbol}{"Method_Became_Static"}{""}}=(
12442 "Target"=>get_Signature($Symbol, 1)
12443 );
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012444 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012445 elsif(not $CompleteSignature{2}{$PSymbol}{"Static"}
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040012446 and $CompleteSignature{1}{$Symbol}{"Static"} and $Symbol=~/\A(_Z|\?)/)
12447 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012448 %{$CompatProblems{$Level}{$Symbol}{"Method_Became_NonStatic"}{""}}=(
12449 "Target"=>get_Signature($Symbol, 1)
12450 );
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012451 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012452 if(($CompleteSignature{1}{$Symbol}{"Virt"} and $CompleteSignature{2}{$PSymbol}{"Virt"})
12453 or ($CompleteSignature{1}{$Symbol}{"PureVirt"} and $CompleteSignature{2}{$PSymbol}{"PureVirt"}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012454 { # relative position of virtual and pure virtual methods
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012455 if($Level eq "Binary")
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012456 {
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040012457 if(defined $CompleteSignature{1}{$Symbol}{"RelPos"} and defined $CompleteSignature{2}{$PSymbol}{"RelPos"}
12458 and $CompleteSignature{1}{$Symbol}{"RelPos"}!=$CompleteSignature{2}{$PSymbol}{"RelPos"})
12459 { # top-level virtual methods only
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012460 my $Class_Id = $CompleteSignature{1}{$Symbol}{"Class"};
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040012461 my $Class_Name = $TypeInfo{1}{$Class_Id}{"Name"};
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040012462 if(defined $VirtualTable{1}{$Class_Name} and defined $VirtualTable{2}{$Class_Name}
12463 and $VirtualTable{1}{$Class_Name}{$Symbol}!=$VirtualTable{2}{$Class_Name}{$Symbol})
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012464 { # check the absolute position of virtual method (including added and removed methods)
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040012465 my %Class_Type = get_Type($Class_Id, 1);
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012466 my $ProblemType = "Virtual_Method_Position";
12467 if($CompleteSignature{1}{$Symbol}{"PureVirt"}) {
12468 $ProblemType = "Pure_Virtual_Method_Position";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012469 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012470 if(isUsedClass($Class_Id, 1, $Level))
12471 {
12472 my @Affected = ($Symbol, keys(%{$OverriddenMethods{1}{$Symbol}}));
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040012473 foreach my $ASymbol (@Affected)
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012474 {
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040012475 if(not symbolFilter($ASymbol, 1, "Affected", $Level)) {
12476 next;
12477 }
12478 %{$CompatProblems{$Level}{$ASymbol}{$ProblemType}{$tr_name{$MnglName}}}=(
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012479 "Type_Name"=>$Class_Type{"Name"},
12480 "Type_Type"=>"Class",
12481 "Old_Value"=>$CompleteSignature{1}{$Symbol}{"RelPos"},
12482 "New_Value"=>$CompleteSignature{2}{$PSymbol}{"RelPos"},
12483 "Target"=>get_Signature($Symbol, 1) );
12484 }
Andrey Ponomarenko16934472012-03-29 15:37:04 +040012485 $VTableChanged_M{$Class_Type{"Name"}} = 1;
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012486 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012487 }
12488 }
12489 }
12490 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012491 if($CompleteSignature{1}{$Symbol}{"PureVirt"}
12492 or $CompleteSignature{2}{$PSymbol}{"PureVirt"})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012493 { # do NOT check type changes in pure virtuals
12494 next;
12495 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012496 $CheckedSymbols{$Level}{$Symbol}=1;
12497 if($Symbol=~/\A(_Z|\?)/
12498 or keys(%{$CompleteSignature{1}{$Symbol}{"Param"}})==keys(%{$CompleteSignature{2}{$PSymbol}{"Param"}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012499 { # C/C++: changes in parameters
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012500 foreach my $ParamPos (sort {int($a) <=> int($b)} keys(%{$CompleteSignature{1}{$Symbol}{"Param"}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012501 { # checking parameters
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012502 mergeParameters($Symbol, $PSymbol, $ParamPos, $ParamPos, $Level);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012503 }
12504 }
12505 else
12506 { # C: added/removed parameters
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012507 foreach my $ParamPos (sort {int($a) <=> int($b)} keys(%{$CompleteSignature{2}{$PSymbol}{"Param"}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012508 { # checking added parameters
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040012509 my $PType2_Id = $CompleteSignature{2}{$PSymbol}{"Param"}{$ParamPos}{"type"};
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040012510 my $PType2_Name = $TypeInfo{2}{$PType2_Id}{"Name"};
12511 last if($PType2_Name eq "...");
12512 my $PName = $CompleteSignature{2}{$PSymbol}{"Param"}{$ParamPos}{"name"};
12513 my $PName_Old = (defined $CompleteSignature{1}{$Symbol}{"Param"}{$ParamPos})?$CompleteSignature{1}{$Symbol}{"Param"}{$ParamPos}{"name"}:"";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012514 my $ParamPos_Prev = "-1";
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040012515 if($PName=~/\Ap\d+\Z/i)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012516 { # added unnamed parameter ( pN )
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040012517 my @Positions1 = find_ParamPair_Pos_byTypeAndPos($PType2_Name, $ParamPos, "backward", $Symbol, 1);
12518 my @Positions2 = find_ParamPair_Pos_byTypeAndPos($PType2_Name, $ParamPos, "backward", $Symbol, 2);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012519 if($#Positions1==-1 or $#Positions2>$#Positions1) {
12520 $ParamPos_Prev = "lost";
12521 }
12522 }
12523 else {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040012524 $ParamPos_Prev = find_ParamPair_Pos_byName($PName, $Symbol, 1);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012525 }
12526 if($ParamPos_Prev eq "lost")
12527 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012528 if($ParamPos>keys(%{$CompleteSignature{1}{$Symbol}{"Param"}})-1)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012529 {
12530 my $ProblemType = "Added_Parameter";
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040012531 if($PName=~/\Ap\d+\Z/) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012532 $ProblemType = "Added_Unnamed_Parameter";
12533 }
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040012534 %{$CompatProblems{$Level}{$Symbol}{$ProblemType}{showPos($ParamPos)." Parameter"}}=(
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040012535 "Target"=>$PName,
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012536 "Param_Pos"=>$ParamPos,
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040012537 "Param_Type"=>$PType2_Name,
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012538 "New_Signature"=>get_Signature($Symbol, 2) );
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012539 }
12540 else
12541 {
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +040012542 my %ParamType_Pure = get_PureType($PType2_Id, $TypeInfo{2});
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040012543 my $PairType_Id = $CompleteSignature{1}{$Symbol}{"Param"}{$ParamPos}{"type"};
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +040012544 my %PairType_Pure = get_PureType($PairType_Id, $TypeInfo{1});
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040012545 if(($ParamType_Pure{"Name"} eq $PairType_Pure{"Name"} or $PType2_Name eq $TypeInfo{1}{$PairType_Id}{"Name"})
12546 and find_ParamPair_Pos_byName($PName_Old, $Symbol, 2) eq "lost")
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012547 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040012548 if($PName_Old!~/\Ap\d+\Z/ and $PName!~/\Ap\d+\Z/)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012549 {
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040012550 %{$CompatProblems{$Level}{$Symbol}{"Renamed_Parameter"}{showPos($ParamPos)." Parameter"}}=(
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040012551 "Target"=>$PName_Old,
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012552 "Param_Pos"=>$ParamPos,
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040012553 "Param_Type"=>$PType2_Name,
12554 "Old_Value"=>$PName_Old,
12555 "New_Value"=>$PName,
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012556 "New_Signature"=>get_Signature($Symbol, 2) );
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012557 }
12558 }
12559 else
12560 {
12561 my $ProblemType = "Added_Middle_Parameter";
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040012562 if($PName=~/\Ap\d+\Z/) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012563 $ProblemType = "Added_Middle_Unnamed_Parameter";
12564 }
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040012565 %{$CompatProblems{$Level}{$Symbol}{$ProblemType}{showPos($ParamPos)." Parameter"}}=(
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040012566 "Target"=>$PName,
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012567 "Param_Pos"=>$ParamPos,
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040012568 "Param_Type"=>$PType2_Name,
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012569 "New_Signature"=>get_Signature($Symbol, 2) );
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012570 }
12571 }
12572 }
12573 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012574 foreach my $ParamPos (sort {int($a) <=> int($b)} keys(%{$CompleteSignature{1}{$Symbol}{"Param"}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012575 { # check relevant parameters
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040012576 my $PType1_Id = $CompleteSignature{1}{$Symbol}{"Param"}{$ParamPos}{"type"};
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012577 my $ParamName1 = $CompleteSignature{1}{$Symbol}{"Param"}{$ParamPos}{"name"};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012578 # FIXME: find relevant parameter by name
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012579 if(defined $CompleteSignature{2}{$PSymbol}{"Param"}{$ParamPos})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012580 {
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040012581 my $PType2_Id = $CompleteSignature{2}{$PSymbol}{"Param"}{$ParamPos}{"type"};
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012582 my $ParamName2 = $CompleteSignature{2}{$PSymbol}{"Param"}{$ParamPos}{"name"};
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040012583 if($TypeInfo{1}{$PType1_Id}{"Name"} eq $TypeInfo{2}{$PType2_Id}{"Name"}
12584 or ($ParamName1!~/\Ap\d+\Z/i and $ParamName1 eq $ParamName2)) {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012585 mergeParameters($Symbol, $PSymbol, $ParamPos, $ParamPos, $Level);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012586 }
12587 }
12588 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012589 foreach my $ParamPos (sort {int($a) <=> int($b)} keys(%{$CompleteSignature{1}{$Symbol}{"Param"}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012590 { # checking removed parameters
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040012591 my $PType1_Id = $CompleteSignature{1}{$Symbol}{"Param"}{$ParamPos}{"type"};
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040012592 my $PType1_Name = $TypeInfo{1}{$PType1_Id}{"Name"};
12593 last if($PType1_Name eq "...");
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012594 my $Parameter_Name = $CompleteSignature{1}{$Symbol}{"Param"}{$ParamPos}{"name"};
12595 my $Parameter_NewName = (defined $CompleteSignature{2}{$PSymbol}{"Param"}{$ParamPos})?$CompleteSignature{2}{$PSymbol}{"Param"}{$ParamPos}{"name"}:"";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012596 my $ParamPos_New = "-1";
12597 if($Parameter_Name=~/\Ap\d+\Z/i)
12598 { # removed unnamed parameter ( pN )
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040012599 my @Positions1 = find_ParamPair_Pos_byTypeAndPos($PType1_Name, $ParamPos, "forward", $Symbol, 1);
12600 my @Positions2 = find_ParamPair_Pos_byTypeAndPos($PType1_Name, $ParamPos, "forward", $Symbol, 2);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012601 if($#Positions2==-1 or $#Positions2<$#Positions1) {
12602 $ParamPos_New = "lost";
12603 }
12604 }
12605 else {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012606 $ParamPos_New = find_ParamPair_Pos_byName($Parameter_Name, $Symbol, 2);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012607 }
12608 if($ParamPos_New eq "lost")
12609 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012610 if($ParamPos>keys(%{$CompleteSignature{2}{$PSymbol}{"Param"}})-1)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012611 {
12612 my $ProblemType = "Removed_Parameter";
12613 if($Parameter_Name=~/\Ap\d+\Z/) {
12614 $ProblemType = "Removed_Unnamed_Parameter";
12615 }
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040012616 %{$CompatProblems{$Level}{$Symbol}{$ProblemType}{showPos($ParamPos)." Parameter"}}=(
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012617 "Target"=>$Parameter_Name,
12618 "Param_Pos"=>$ParamPos,
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040012619 "Param_Type"=>$PType1_Name,
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012620 "New_Signature"=>get_Signature($Symbol, 2) );
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012621 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012622 elsif($ParamPos<keys(%{$CompleteSignature{1}{$Symbol}{"Param"}})-1)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012623 {
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +040012624 my %ParamType_Pure = get_PureType($PType1_Id, $TypeInfo{1});
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040012625 my $PairType_Id = $CompleteSignature{2}{$PSymbol}{"Param"}{$ParamPos}{"type"};
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +040012626 my %PairType_Pure = get_PureType($PairType_Id, $TypeInfo{2});
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040012627 if(($ParamType_Pure{"Name"} eq $PairType_Pure{"Name"} or $PType1_Name eq $TypeInfo{2}{$PairType_Id}{"Name"})
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012628 and find_ParamPair_Pos_byName($Parameter_NewName, $Symbol, 1) eq "lost")
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012629 {
12630 if($Parameter_NewName!~/\Ap\d+\Z/ and $Parameter_Name!~/\Ap\d+\Z/)
12631 {
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040012632 %{$CompatProblems{$Level}{$Symbol}{"Renamed_Parameter"}{showPos($ParamPos)." Parameter"}}=(
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012633 "Target"=>$Parameter_Name,
12634 "Param_Pos"=>$ParamPos,
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040012635 "Param_Type"=>$PType1_Name,
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012636 "Old_Value"=>$Parameter_Name,
12637 "New_Value"=>$Parameter_NewName,
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012638 "New_Signature"=>get_Signature($Symbol, 2) );
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012639 }
12640 }
12641 else
12642 {
12643 my $ProblemType = "Removed_Middle_Parameter";
12644 if($Parameter_Name=~/\Ap\d+\Z/) {
12645 $ProblemType = "Removed_Middle_Unnamed_Parameter";
12646 }
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040012647 %{$CompatProblems{$Level}{$Symbol}{$ProblemType}{showPos($ParamPos)." Parameter"}}=(
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012648 "Target"=>$Parameter_Name,
12649 "Param_Pos"=>$ParamPos,
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040012650 "Param_Type"=>$PType1_Name,
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012651 "New_Signature"=>get_Signature($Symbol, 2) );
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012652 }
12653 }
12654 }
12655 }
12656 }
12657 # checking return type
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012658 my $ReturnType1_Id = $CompleteSignature{1}{$Symbol}{"Return"};
12659 my $ReturnType2_Id = $CompleteSignature{2}{$PSymbol}{"Return"};
12660 %SubProblems = detectTypeChange($ReturnType1_Id, $ReturnType2_Id, "Return", $Level);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012661 foreach my $SubProblemType (keys(%SubProblems))
12662 {
12663 my $New_Value = $SubProblems{$SubProblemType}{"New_Value"};
12664 my $Old_Value = $SubProblems{$SubProblemType}{"Old_Value"};
12665 my $NewProblemType = $SubProblemType;
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040012666 my $AddProblemType = undef;
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +040012667
12668 if($SubProblemType eq "Return_Type_And_Size"
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012669 and $CompleteSignature{1}{$Symbol}{"Data"}) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012670 $NewProblemType = "Global_Data_Type_And_Size";
12671 }
12672 elsif($SubProblemType eq "Return_Type")
12673 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012674 if($CompleteSignature{1}{$Symbol}{"Data"})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012675 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012676 if(removedQual($Old_Value, $New_Value, "const"))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012677 { # const -> non-const global data
12678 $NewProblemType = "Global_Data_Became_Non_Const";
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040012679 $AddProblemType = "Global_Data_Type";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012680 }
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040012681 elsif(addedQual($Old_Value, $New_Value, "const"))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012682 { # non-const -> const global data
12683 $NewProblemType = "Global_Data_Became_Const";
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040012684 $AddProblemType = "Global_Data_Type";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012685 }
12686 else {
12687 $NewProblemType = "Global_Data_Type";
12688 }
12689 }
12690 else
12691 {
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040012692 if(addedQual($Old_Value, $New_Value, "const"))
12693 {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012694 $NewProblemType = "Return_Type_Became_Const";
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040012695 $AddProblemType = "Return_Type";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012696 }
12697 }
12698 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012699 elsif($SubProblemType eq "Return_Type_Format")
12700 {
12701 if($CompleteSignature{1}{$Symbol}{"Data"}) {
12702 $NewProblemType = "Global_Data_Type_Format";
12703 }
12704 }
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +040012705 if($Level eq "Binary"
12706 and not $CompleteSignature{1}{$Symbol}{"Data"})
12707 {
12708 my ($Arch1, $Arch2) = (getArch(1), getArch(2));
12709 if($Arch1 eq "unknown" or $Arch2 eq "unknown")
12710 { # if one of the architectures is unknown
12711 # then set other arhitecture to unknown too
12712 ($Arch1, $Arch2) = ("unknown", "unknown");
12713 }
12714 my (%Conv1, %Conv2) = ();
12715 if($UseConv_Real{1} and $UseConv_Real{1})
12716 {
12717 %Conv1 = callingConvention_R_Real($CompleteSignature{1}{$Symbol});
12718 %Conv2 = callingConvention_R_Real($CompleteSignature{2}{$PSymbol});
12719 }
12720 else
12721 {
12722 %Conv1 = callingConvention_R_Model($CompleteSignature{1}{$Symbol}, $TypeInfo{1}, $Arch1, $OStarget, $WORD_SIZE{1});
12723 %Conv2 = callingConvention_R_Model($CompleteSignature{2}{$PSymbol}, $TypeInfo{2}, $Arch2, $OStarget, $WORD_SIZE{2});
12724 }
12725
12726 if($SubProblemType eq "Return_Type_Became_Void")
12727 {
12728 if(keys(%{$CompleteSignature{1}{$Symbol}{"Param"}}))
12729 { # parameters stack has been affected
12730 if($Conv1{"Method"} eq "stack") {
12731 $NewProblemType = "Return_Type_Became_Void_And_Stack_Layout";
12732 }
12733 elsif($Conv1{"Hidden"}) {
12734 $NewProblemType = "Return_Type_Became_Void_And_Register";
12735 }
12736 }
12737 }
12738 elsif($SubProblemType eq "Return_Type_From_Void")
12739 {
12740 if(keys(%{$CompleteSignature{1}{$Symbol}{"Param"}}))
12741 { # parameters stack has been affected
12742 if($Conv2{"Method"} eq "stack") {
12743 $NewProblemType = "Return_Type_From_Void_And_Stack_Layout";
12744 }
12745 elsif($Conv2{"Hidden"}) {
12746 $NewProblemType = "Return_Type_From_Void_And_Register";
12747 }
12748 }
12749 }
12750 elsif($SubProblemType eq "Return_Type"
12751 or $SubProblemType eq "Return_Type_And_Size"
12752 or $SubProblemType eq "Return_Type_Format")
12753 {
12754 if($Conv1{"Method"} ne $Conv2{"Method"})
12755 {
12756 if($Conv1{"Method"} eq "stack")
12757 { # returns in a register instead of a hidden first parameter
12758 $NewProblemType = "Return_Type_From_Stack_To_Register";
12759 }
12760 else {
12761 $NewProblemType = "Return_Type_From_Register_To_Stack";
12762 }
12763 }
12764 else
12765 {
12766 if($Conv1{"Method"} eq "reg")
12767 {
12768 if($Conv1{"Registers"} ne $Conv2{"Registers"})
12769 {
12770 if($Conv1{"Hidden"}) {
12771 $NewProblemType = "Return_Type_And_Register_Was_Hidden_Parameter";
12772 }
12773 elsif($Conv2{"Hidden"}) {
12774 $NewProblemType = "Return_Type_And_Register_Became_Hidden_Parameter";
12775 }
12776 else {
12777 $NewProblemType = "Return_Type_And_Register";
12778 }
12779 }
12780 }
12781 }
12782 }
12783 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012784 @{$CompatProblems{$Level}{$Symbol}{$NewProblemType}{"retval"}}{keys(%{$SubProblems{$SubProblemType}})} = values %{$SubProblems{$SubProblemType}};
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040012785 if(defined $AddProblemType) {
12786 @{$CompatProblems{$Level}{$Symbol}{$AddProblemType}{"retval"}}{keys(%{$SubProblems{$SubProblemType}})} = values %{$SubProblems{$SubProblemType}};
12787 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012788 }
12789 if($ReturnType1_Id and $ReturnType2_Id)
12790 {
12791 @RecurTypes = ();
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040012792 %SubProblems = mergeTypes($ReturnType1_Id, $ReturnType2_Id, $Level);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012793 foreach my $SubProblemType (keys(%SubProblems))
12794 { # add "Global_Data_Size" problem
12795 my $New_Value = $SubProblems{$SubProblemType}{"New_Value"};
12796 my $Old_Value = $SubProblems{$SubProblemType}{"Old_Value"};
12797 if($SubProblemType eq "DataType_Size"
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012798 and $CompleteSignature{1}{$Symbol}{"Data"}
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040012799 and get_PLevel($ReturnType1_Id, 1)==0)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012800 { # add a new problem
12801 %{$SubProblems{"Global_Data_Size"}} = %{$SubProblems{$SubProblemType}};
12802 }
12803 }
12804 foreach my $SubProblemType (keys(%SubProblems))
12805 {
12806 foreach my $SubLocation (keys(%{$SubProblems{$SubProblemType}}))
12807 {
12808 my $NewLocation = ($SubLocation)?"retval->".$SubLocation:"retval";
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012809 %{$CompatProblems{$Level}{$Symbol}{$SubProblemType}{$NewLocation}}=(
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040012810 "Return_Type_Name"=>$TypeInfo{1}{$ReturnType1_Id}{"Name"} );
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012811 @{$CompatProblems{$Level}{$Symbol}{$SubProblemType}{$NewLocation}}{keys(%{$SubProblems{$SubProblemType}{$SubLocation}})} = values %{$SubProblems{$SubProblemType}{$SubLocation}};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012812 if($SubLocation!~/\-\>/) {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040012813 $CompatProblems{$Level}{$Symbol}{$SubProblemType}{$NewLocation}{"Start_Type_Name"} = $TypeInfo{1}{$ReturnType1_Id}{"Name"};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012814 }
12815 }
12816 }
12817 }
12818
12819 # checking object type
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040012820 my $ObjTId1 = $CompleteSignature{1}{$Symbol}{"Class"};
12821 my $ObjTId2 = $CompleteSignature{2}{$PSymbol}{"Class"};
12822 if($ObjTId1 and $ObjTId2
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012823 and not $CompleteSignature{1}{$Symbol}{"Static"})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012824 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040012825 my $ThisPtr1_Id = getTypeIdByName($TypeInfo{1}{$ObjTId1}{"Name"}."*const", 1);
12826 my $ThisPtr2_Id = getTypeIdByName($TypeInfo{2}{$ObjTId2}{"Name"}."*const", 2);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012827 if($ThisPtr1_Id and $ThisPtr2_Id)
12828 {
12829 @RecurTypes = ();
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040012830 %SubProblems = mergeTypes($ThisPtr1_Id, $ThisPtr2_Id, $Level);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012831 foreach my $SubProblemType (keys(%SubProblems))
12832 {
12833 foreach my $SubLocation (keys(%{$SubProblems{$SubProblemType}}))
12834 {
12835 my $NewLocation = ($SubLocation)?"this->".$SubLocation:"this";
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012836 %{$CompatProblems{$Level}{$Symbol}{$SubProblemType}{$NewLocation}}=(
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040012837 "Object_Type_Name"=>$TypeInfo{1}{$ObjTId1}{"Name"} );
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012838 @{$CompatProblems{$Level}{$Symbol}{$SubProblemType}{$NewLocation}}{keys(%{$SubProblems{$SubProblemType}{$SubLocation}})} = values %{$SubProblems{$SubProblemType}{$SubLocation}};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012839 if($SubLocation!~/\-\>/) {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040012840 $CompatProblems{$Level}{$Symbol}{$SubProblemType}{$NewLocation}{"Start_Type_Name"} = $TypeInfo{1}{$ObjTId1}{"Name"};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012841 }
12842 }
12843 }
12844 }
12845 }
12846 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012847 if($Level eq "Binary") {
12848 mergeVTables($Level);
12849 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +040012850 foreach my $Symbol (keys(%{$CompatProblems{$Level}})) {
12851 $CheckedSymbols{$Level}{$Symbol} = 1;
12852 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012853}
12854
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040012855sub rmQuals($$)
12856{
12857 my ($Value, $Qual) = @_;
12858 if(not $Qual) {
12859 return $Value;
12860 }
12861 if($Qual eq "all")
12862 { # all quals
12863 $Qual = "const|volatile|restrict";
12864 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040012865 while($Value=~s/\b$Qual\b//) {
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040012866 $Value = formatName($Value, "T");
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040012867 }
12868 return $Value;
12869}
12870
12871sub cmpBTypes($$$$)
12872{
12873 my ($T1, $T2, $V1, $V2) = @_;
12874 $T1 = uncover_typedefs($T1, $V1);
12875 $T2 = uncover_typedefs($T2, $V2);
12876 return (rmQuals($T1, "all") eq rmQuals($T2, "all"));
12877}
12878
12879sub addedQual($$$)
12880{
12881 my ($Old_Value, $New_Value, $Qual) = @_;
Andrey Ponomarenko85043792012-05-14 16:48:07 +040012882 return removedQual_($New_Value, $Old_Value, 2, 1, $Qual);
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040012883}
12884
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012885sub removedQual($$$)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012886{
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012887 my ($Old_Value, $New_Value, $Qual) = @_;
Andrey Ponomarenko85043792012-05-14 16:48:07 +040012888 return removedQual_($Old_Value, $New_Value, 1, 2, $Qual);
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040012889}
12890
12891sub removedQual_($$$$$)
12892{
12893 my ($Old_Value, $New_Value, $V1, $V2, $Qual) = @_;
12894 $Old_Value = uncover_typedefs($Old_Value, $V1);
12895 $New_Value = uncover_typedefs($New_Value, $V2);
12896 if($Old_Value eq $New_Value)
12897 { # equal types
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012898 return 0;
12899 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040012900 if($Old_Value!~/\b$Qual\b/)
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040012901 { # without a qual
12902 return 0;
12903 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040012904 elsif($New_Value!~/\b$Qual\b/)
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040012905 { # became non-qual
12906 return 1;
12907 }
12908 else
12909 {
12910 my @BQ1 = getQualModel($Old_Value, $Qual);
12911 my @BQ2 = getQualModel($New_Value, $Qual);
12912 foreach (0 .. $#BQ1)
12913 { # removed qual
12914 if($BQ1[$_]==1
12915 and $BQ2[$_]!=1)
12916 {
12917 return 2;
12918 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012919 }
12920 }
12921 return 0;
12922}
12923
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040012924sub getQualModel($$)
12925{
12926 my ($Value, $Qual) = @_;
12927 if(not $Qual) {
12928 return $Value;
12929 }
12930
12931 # cleaning
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040012932 while($Value=~/(\w+)/ and $1 ne $Qual) {
12933 $Value=~s/\b$1\b//g;
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040012934 }
12935 $Value=~s/[^\*\&\w]+//g;
12936
12937 # modeling
12938 # int*const*const == 011
12939 # int**const == 001
12940 my @Model = ();
12941 my @Elems = split(/[\*\&]/, $Value);
12942 if(not @Elems) {
12943 return (0);
12944 }
12945 foreach (@Elems)
12946 {
12947 if($_ eq $Qual) {
12948 push(@Model, 1);
12949 }
12950 else {
12951 push(@Model, 0);
12952 }
12953 }
12954
12955 return @Model;
12956}
12957
Andrey Ponomarenko4b077f82012-12-04 16:04:36 +040012958my %StringTypes = map {$_=>1} (
12959 "char*",
12960 "char const*"
12961);
12962
12963my %CharTypes = map {$_=>1} (
12964 "char",
12965 "char const"
12966);
12967
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040012968sub showVal($$$)
12969{
12970 my ($Value, $TypeId, $LibVersion) = @_;
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +040012971 my %PureType = get_PureType($TypeId, $TypeInfo{$LibVersion});
Andrey Ponomarenkoa01311b2012-06-08 17:20:02 +040012972 my $TName = uncover_typedefs($PureType{"Name"}, $LibVersion);
Andrey Ponomarenko01117f12012-06-26 12:23:02 +040012973 if(substr($Value, 0, 2) eq "_Z")
12974 {
12975 if(my $Unmangled = $tr_name{$Value}) {
12976 return $Unmangled;
12977 }
12978 }
Andrey Ponomarenko4b077f82012-12-04 16:04:36 +040012979 elsif(defined $StringTypes{$TName} or $TName=~/string/i)
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040012980 { # strings
12981 return "\"$Value\"";
12982 }
Andrey Ponomarenko4b077f82012-12-04 16:04:36 +040012983 elsif(defined $CharTypes{$TName})
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040012984 { # characters
12985 return "\'$Value\'";
12986 }
Andrey Ponomarenko4b077f82012-12-04 16:04:36 +040012987 if($Value eq "")
12988 { # other
12989 return "\'\'";
12990 }
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040012991 return $Value;
12992}
12993
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012994sub mergeParameters($$$$$)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012995{
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012996 my ($Symbol, $PSymbol, $ParamPos1, $ParamPos2, $Level) = @_;
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040012997 if(not $Symbol) {
12998 return;
12999 }
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040013000 my $PType1_Id = $CompleteSignature{1}{$Symbol}{"Param"}{$ParamPos1}{"type"};
13001 my $PName1 = $CompleteSignature{1}{$Symbol}{"Param"}{$ParamPos1}{"name"};
13002 my $PType2_Id = $CompleteSignature{2}{$PSymbol}{"Param"}{$ParamPos2}{"type"};
13003 my $PName2 = $CompleteSignature{2}{$PSymbol}{"Param"}{$ParamPos2}{"name"};
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040013004 if(not $PType1_Id
13005 or not $PType2_Id) {
13006 return;
13007 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040013008 my %Type1 = get_Type($PType1_Id, 1);
13009 my %Type2 = get_Type($PType2_Id, 2);
13010 my %BaseType1 = get_BaseType($PType1_Id, 1);
13011 my %BaseType2 = get_BaseType($PType2_Id, 2);
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040013012 my $Parameter_Location = ($PName1)?$PName1:showPos($ParamPos1)." Parameter";
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040013013 if($Level eq "Binary")
13014 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040013015 if(checkDump(1, "2.6.1") and checkDump(2, "2.6.1"))
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040013016 { # "reg" attribute added in ACC 1.95.1 (dump 2.6.1 format)
13017 if($CompleteSignature{1}{$Symbol}{"Param"}{$ParamPos1}{"reg"}
13018 and not $CompleteSignature{2}{$PSymbol}{"Param"}{$ParamPos2}{"reg"})
13019 {
13020 %{$CompatProblems{$Level}{$Symbol}{"Parameter_Became_Non_Register"}{$Parameter_Location}}=(
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040013021 "Target"=>$PName1,
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040013022 "Param_Pos"=>$ParamPos1 );
13023 }
13024 elsif(not $CompleteSignature{1}{$Symbol}{"Param"}{$ParamPos1}{"reg"}
13025 and $CompleteSignature{2}{$PSymbol}{"Param"}{$ParamPos2}{"reg"})
13026 {
13027 %{$CompatProblems{$Level}{$Symbol}{"Parameter_Became_Register"}{$Parameter_Location}}=(
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040013028 "Target"=>$PName1,
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040013029 "Param_Pos"=>$ParamPos1 );
13030 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013031 }
13032 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040013033 if(checkDump(1, "2.0") and checkDump(2, "2.0"))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013034 { # "default" attribute added in ACC 1.22 (dump 2.0 format)
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040013035 my $Value_Old = $CompleteSignature{1}{$Symbol}{"Param"}{$ParamPos1}{"default"};
13036 my $Value_New = $CompleteSignature{2}{$PSymbol}{"Param"}{$ParamPos2}{"default"};
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040013037 if(not checkDump(1, "2.13")
13038 and checkDump(2, "2.13"))
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040013039 { # support for old ABI dumps
13040 if(defined $Value_Old and defined $Value_New)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013041 {
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040013042 if($Type1{"Name"} eq "bool"
13043 and $Value_Old eq "false" and $Value_New eq "0")
13044 { # int class::method ( bool p = 0 );
13045 # old ABI dumps: "false"
13046 # new ABI dumps: "0"
13047 $Value_Old = "0";
13048 }
13049 }
13050 }
Andrey Ponomarenko01117f12012-06-26 12:23:02 +040013051 if(not checkDump(1, "2.18")
13052 and checkDump(2, "2.18"))
13053 { # support for old ABI dumps
13054 if(not defined $Value_Old
13055 and substr($Value_New, 0, 2) eq "_Z") {
13056 $Value_Old = $Value_New;
13057 }
13058 }
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040013059 if(defined $Value_Old)
13060 {
13061 $Value_Old = showVal($Value_Old, $PType1_Id, 1);
13062 if(defined $Value_New)
13063 {
13064 $Value_New = showVal($Value_New, $PType2_Id, 2);
13065 if($Value_Old ne $Value_New)
13066 { # FIXME: how to distinguish "0" and 0 (NULL)
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040013067 %{$CompatProblems{$Level}{$Symbol}{"Parameter_Default_Value_Changed"}{$Parameter_Location}}=(
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040013068 "Target"=>$PName1,
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013069 "Param_Pos"=>$ParamPos1,
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040013070 "Old_Value"=>$Value_Old,
13071 "New_Value"=>$Value_New );
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013072 }
13073 }
13074 else
13075 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040013076 %{$CompatProblems{$Level}{$Symbol}{"Parameter_Default_Value_Removed"}{$Parameter_Location}}=(
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040013077 "Target"=>$PName1,
13078 "Param_Pos"=>$ParamPos1,
13079 "Old_Value"=>$Value_Old );
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013080 }
13081 }
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040013082 elsif(defined $Value_New)
13083 {
13084 $Value_New = showVal($Value_New, $PType2_Id, 2);
13085 %{$CompatProblems{$Level}{$Symbol}{"Parameter_Default_Value_Added"}{$Parameter_Location}}=(
13086 "Target"=>$PName1,
13087 "Param_Pos"=>$ParamPos1,
13088 "New_Value"=>$Value_New );
13089 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013090 }
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040013091 if($PName1 and $PName2 and $PName1 ne $PName2
13092 and $PType1_Id!=-1 and $PType2_Id!=-1
13093 and $PName1!~/\Ap\d+\Z/ and $PName2!~/\Ap\d+\Z/)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013094 { # except unnamed "..." value list (Id=-1)
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040013095 %{$CompatProblems{$Level}{$Symbol}{"Renamed_Parameter"}{showPos($ParamPos1)." Parameter"}}=(
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040013096 "Target"=>$PName1,
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013097 "Param_Pos"=>$ParamPos1,
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040013098 "Param_Type"=>$TypeInfo{1}{$PType1_Id}{"Name"},
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040013099 "Old_Value"=>$PName1,
13100 "New_Value"=>$PName2,
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040013101 "New_Signature"=>get_Signature($Symbol, 2) );
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013102 }
13103 # checking type change (replace)
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040013104 my %SubProblems = detectTypeChange($PType1_Id, $PType2_Id, "Parameter", $Level);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013105 foreach my $SubProblemType (keys(%SubProblems))
13106 { # add new problems, remove false alarms
13107 my $New_Value = $SubProblems{$SubProblemType}{"New_Value"};
13108 my $Old_Value = $SubProblems{$SubProblemType}{"Old_Value"};
13109 if($SubProblemType eq "Parameter_Type")
13110 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040013111 if(checkDump(1, "2.6") and checkDump(2, "2.6"))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013112 {
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040013113 if(my $RA = addedQual($Old_Value, $New_Value, "restrict"))
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040013114 {
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040013115 %{$SubProblems{"Parameter_Became_Restrict"}} = %{$SubProblems{$SubProblemType}};
13116 if($Level eq "Source"
13117 and cmpBTypes($Old_Value, $New_Value, 1, 2)) {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040013118 delete($SubProblems{$SubProblemType});
13119 }
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040013120 }
13121 elsif(my $RR = removedQual($Old_Value, $New_Value, "restrict"))
13122 {
13123 %{$SubProblems{"Parameter_Became_NonRestrict"}} = %{$SubProblems{$SubProblemType}};
13124 if($Level eq "Source"
13125 and cmpBTypes($Old_Value, $New_Value, 1, 2)) {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040013126 delete($SubProblems{$SubProblemType});
13127 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013128 }
13129 }
13130 if($Type2{"Type"} eq "Const" and $BaseType2{"Name"} eq $Type1{"Name"}
13131 and $Type1{"Type"}=~/Intrinsic|Class|Struct|Union|Enum/)
13132 { # int to "int const"
13133 delete($SubProblems{$SubProblemType});
13134 }
13135 if($Type1{"Type"} eq "Const" and $BaseType1{"Name"} eq $Type2{"Name"}
13136 and $Type2{"Type"}=~/Intrinsic|Class|Struct|Union|Enum/)
13137 { # "int const" to int
13138 delete($SubProblems{$SubProblemType});
13139 }
13140 }
13141 }
13142 foreach my $SubProblemType (keys(%SubProblems))
13143 { # modify/register problems
13144 my $New_Value = $SubProblems{$SubProblemType}{"New_Value"};
13145 my $Old_Value = $SubProblems{$SubProblemType}{"Old_Value"};
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +040013146 my $New_Size = $SubProblems{$SubProblemType}{"New_Size"};
13147 my $Old_Size = $SubProblems{$SubProblemType}{"Old_Size"};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013148 my $NewProblemType = $SubProblemType;
13149 if($Old_Value eq "..." and $New_Value ne "...")
13150 { # change from "..." to "int"
13151 if($ParamPos1==0)
13152 { # ISO C requires a named argument before "..."
13153 next;
13154 }
13155 $NewProblemType = "Parameter_Became_NonVaList";
13156 }
13157 elsif($New_Value eq "..." and $Old_Value ne "...")
13158 { # change from "int" to "..."
13159 if($ParamPos2==0)
13160 { # ISO C requires a named argument before "..."
13161 next;
13162 }
13163 $NewProblemType = "Parameter_Became_VaList";
13164 }
13165 elsif($SubProblemType eq "Parameter_Type"
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040013166 and removedQual($Old_Value, $New_Value, "const"))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013167 { # parameter: "const" to non-"const"
13168 $NewProblemType = "Parameter_Became_Non_Const";
13169 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040013170 elsif($Level eq "Binary" and ($SubProblemType eq "Parameter_Type_And_Size"
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +040013171 or $SubProblemType eq "Parameter_Type" or $SubProblemType eq "Parameter_Type_Format"))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013172 {
13173 my ($Arch1, $Arch2) = (getArch(1), getArch(2));
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +040013174 if($Arch1 eq "unknown"
13175 or $Arch2 eq "unknown")
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013176 { # if one of the architectures is unknown
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +040013177 # then set other arhitecture to unknown too
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013178 ($Arch1, $Arch2) = ("unknown", "unknown");
13179 }
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +040013180 my (%Conv1, %Conv2) = ();
13181 if($UseConv_Real{1} and $UseConv_Real{1})
13182 { # real
13183 %Conv1 = callingConvention_P_Real($CompleteSignature{1}{$Symbol}, $ParamPos1);
13184 %Conv2 = callingConvention_P_Real($CompleteSignature{2}{$Symbol}, $ParamPos2);
13185 }
13186 else
13187 { # model
13188 %Conv1 = callingConvention_P_Model($CompleteSignature{1}{$Symbol}, $ParamPos1, $TypeInfo{1}, $Arch1, $OStarget, $WORD_SIZE{1});
13189 %Conv2 = callingConvention_P_Model($CompleteSignature{2}{$Symbol}, $ParamPos2, $TypeInfo{2}, $Arch2, $OStarget, $WORD_SIZE{2});
13190 }
13191 if($Conv1{"Method"} eq $Conv2{"Method"})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013192 {
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +040013193 if($Conv1{"Method"} eq "stack")
13194 {
13195 if($Old_Size ne $New_Size) { # FIXME: isMemPadded, getOffset
13196 $NewProblemType = "Parameter_Type_And_Stack";
13197 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013198 }
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +040013199 elsif($Conv1{"Method"} eq "reg")
13200 {
13201 if($Conv1{"Registers"} ne $Conv2{"Registers"}) {
13202 $NewProblemType = "Parameter_Type_And_Register";
13203 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013204 }
13205 }
13206 else
13207 {
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +040013208 if($Conv1{"Method"} eq "stack") {
13209 $NewProblemType = "Parameter_Type_From_Stack_To_Register";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013210 }
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +040013211 elsif($Conv1{"Method"} eq "register") {
13212 $NewProblemType = "Parameter_Type_From_Register_To_Stack";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013213 }
13214 }
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +040013215 $SubProblems{$SubProblemType}{"Old_Reg"} = $Conv1{"Registers"};
13216 $SubProblems{$SubProblemType}{"New_Reg"} = $Conv2{"Registers"};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013217 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040013218 %{$CompatProblems{$Level}{$Symbol}{$NewProblemType}{$Parameter_Location}}=(
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040013219 "Target"=>$PName1,
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013220 "Param_Pos"=>$ParamPos1,
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040013221 "New_Signature"=>get_Signature($Symbol, 2) );
13222 @{$CompatProblems{$Level}{$Symbol}{$NewProblemType}{$Parameter_Location}}{keys(%{$SubProblems{$SubProblemType}})} = values %{$SubProblems{$SubProblemType}};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013223 }
13224 @RecurTypes = ();
13225 # checking type definition changes
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040013226 my %SubProblems_Merge = mergeTypes($PType1_Id, $PType2_Id, $Level);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013227 foreach my $SubProblemType (keys(%SubProblems_Merge))
13228 {
13229 foreach my $SubLocation (keys(%{$SubProblems_Merge{$SubProblemType}}))
13230 {
13231 my $NewProblemType = $SubProblemType;
13232 if($SubProblemType eq "DataType_Size")
13233 {
13234 my $InitialType_Type = $SubProblems_Merge{$SubProblemType}{$SubLocation}{"InitialType_Type"};
13235 if($InitialType_Type!~/\A(Pointer|Ref)\Z/ and $SubLocation!~/\-\>/)
13236 { # stack has been affected
13237 $NewProblemType = "DataType_Size_And_Stack";
13238 }
13239 }
13240 my $NewLocation = ($SubLocation)?$Parameter_Location."->".$SubLocation:$Parameter_Location;
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040013241 %{$CompatProblems{$Level}{$Symbol}{$NewProblemType}{$NewLocation}}=(
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040013242 "Param_Type"=>$TypeInfo{1}{$PType1_Id}{"Name"},
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013243 "Param_Pos"=>$ParamPos1,
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040013244 "Param_Name"=>$PName1 );
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040013245 @{$CompatProblems{$Level}{$Symbol}{$NewProblemType}{$NewLocation}}{keys(%{$SubProblems_Merge{$SubProblemType}{$SubLocation}})} = values %{$SubProblems_Merge{$SubProblemType}{$SubLocation}};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013246 if($SubLocation!~/\-\>/) {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040013247 $CompatProblems{$Level}{$Symbol}{$NewProblemType}{$NewLocation}{"Start_Type_Name"} = $TypeInfo{1}{$PType1_Id}{"Name"};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013248 }
13249 }
13250 }
13251}
13252
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013253sub find_ParamPair_Pos_byName($$$)
13254{
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040013255 my ($Name, $Symbol, $LibVersion) = @_;
13256 foreach my $ParamPos (sort {int($a)<=>int($b)} keys(%{$CompleteSignature{$LibVersion}{$Symbol}{"Param"}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013257 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040013258 next if(not defined $CompleteSignature{$LibVersion}{$Symbol}{"Param"}{$ParamPos});
13259 if($CompleteSignature{$LibVersion}{$Symbol}{"Param"}{$ParamPos}{"name"} eq $Name)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013260 {
13261 return $ParamPos;
13262 }
13263 }
13264 return "lost";
13265}
13266
13267sub find_ParamPair_Pos_byTypeAndPos($$$$$)
13268{
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040013269 my ($TypeName, $MediumPos, $Order, $Symbol, $LibVersion) = @_;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013270 my @Positions = ();
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040013271 foreach my $ParamPos (sort {int($a)<=>int($b)} keys(%{$CompleteSignature{$LibVersion}{$Symbol}{"Param"}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013272 {
13273 next if($Order eq "backward" and $ParamPos>$MediumPos);
13274 next if($Order eq "forward" and $ParamPos<$MediumPos);
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040013275 next if(not defined $CompleteSignature{$LibVersion}{$Symbol}{"Param"}{$ParamPos});
13276 my $PTypeId = $CompleteSignature{$LibVersion}{$Symbol}{"Param"}{$ParamPos}{"type"};
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040013277 if($TypeInfo{$LibVersion}{$PTypeId}{"Name"} eq $TypeName) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013278 push(@Positions, $ParamPos);
13279 }
13280 }
13281 return @Positions;
13282}
13283
13284sub getTypeIdByName($$)
13285{
13286 my ($TypeName, $Version) = @_;
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040013287 return $TName_Tid{$Version}{formatName($TypeName, "T")};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013288}
13289
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040013290sub checkFormatChange($$$)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013291{
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040013292 my ($Type1_Id, $Type2_Id, $Level) = @_;
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +040013293 my %Type1_Pure = get_PureType($Type1_Id, $TypeInfo{1});
13294 my %Type2_Pure = get_PureType($Type2_Id, $TypeInfo{2});
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013295 if($Type1_Pure{"Name"} eq $Type2_Pure{"Name"})
13296 { # equal types
13297 return 0;
13298 }
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040013299 if($Type1_Pure{"Name"} eq "void")
13300 { # from void* to something
13301 return 0;
13302 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013303 if($Type1_Pure{"Name"}=~/\*/
13304 or $Type2_Pure{"Name"}=~/\*/)
13305 { # compared in detectTypeChange()
13306 return 0;
13307 }
13308 my %FloatType = map {$_=>1} (
13309 "float",
13310 "double",
13311 "long double"
13312 );
13313 if($Type1_Pure{"Type"} ne $Type2_Pure{"Type"})
13314 { # different types
13315 if($Type1_Pure{"Type"} eq "Intrinsic"
13316 and $Type2_Pure{"Type"} eq "Enum")
13317 { # "int" to "enum"
13318 return 0;
13319 }
13320 elsif($Type2_Pure{"Type"} eq "Intrinsic"
13321 and $Type1_Pure{"Type"} eq "Enum")
13322 { # "enum" to "int"
13323 return 0;
13324 }
13325 else
13326 { # "union" to "struct"
13327 # ...
13328 return 1;
13329 }
13330 }
13331 else
13332 {
13333 if($Type1_Pure{"Type"} eq "Intrinsic")
13334 {
13335 if($FloatType{$Type1_Pure{"Name"}}
13336 or $FloatType{$Type2_Pure{"Name"}})
13337 { # "float" to "double"
13338 # "float" to "int"
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040013339 if($Level eq "Source")
13340 { # Safe
13341 return 0;
13342 }
13343 else {
13344 return 1;
13345 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013346 }
13347 }
13348 elsif($Type1_Pure{"Type"}=~/Class|Struct|Union|Enum/)
13349 {
13350 my @Membs1 = keys(%{$Type1_Pure{"Memb"}});
13351 my @Membs2 = keys(%{$Type2_Pure{"Memb"}});
Andrey Ponomarenko570ece52012-11-30 16:36:44 +040013352 if(not @Membs2)
13353 { # private
13354 return 0;
13355 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013356 if($#Membs1!=$#Membs2)
13357 { # different number of elements
13358 return 1;
13359 }
13360 if($Type1_Pure{"Type"} eq "Enum")
13361 {
13362 foreach my $Pos (@Membs1)
13363 { # compare elements by name and value
13364 if($Type1_Pure{"Memb"}{$Pos}{"name"} ne $Type2_Pure{"Memb"}{$Pos}{"name"}
13365 or $Type1_Pure{"Memb"}{$Pos}{"value"} ne $Type2_Pure{"Memb"}{$Pos}{"value"})
13366 { # different names
13367 return 1;
13368 }
13369 }
13370 }
13371 else
13372 {
13373 foreach my $Pos (@Membs1)
13374 { # compare elements by type name
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040013375 my $MT1 = $TypeInfo{1}{$Type1_Pure{"Memb"}{$Pos}{"type"}}{"Name"};
13376 my $MT2 = $TypeInfo{2}{$Type2_Pure{"Memb"}{$Pos}{"type"}}{"Name"};
Andrey Ponomarenko570ece52012-11-30 16:36:44 +040013377
13378 $MT1 = uncover_typedefs($MT1, 1);
13379 $MT2 = uncover_typedefs($MT2, 2);
13380
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013381 if($MT1 ne $MT2)
13382 { # different types
Andrey Ponomarenko2956b972012-11-14 19:16:16 +040013383 if(not isAnon($MT1) and not isAnon($MT2)) {
13384 return 1;
13385 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013386 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040013387 if($Level eq "Source")
13388 {
13389 if($Type1_Pure{"Memb"}{$Pos}{"name"} ne $Type2_Pure{"Memb"}{$Pos}{"name"})
13390 { # different names
13391 return 1;
13392 }
13393 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013394 }
13395 }
13396 }
13397 }
13398 return 0;
13399}
13400
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040013401sub detectTypeChange($$$$)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013402{
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040013403 my ($Type1_Id, $Type2_Id, $Prefix, $Level) = @_;
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040013404 if(not $Type1_Id or not $Type2_Id) {
13405 return ();
13406 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013407 my %LocalProblems = ();
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040013408 my %Type1 = get_Type($Type1_Id, 1);
13409 my %Type2 = get_Type($Type2_Id, 2);
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +040013410 my %Type1_Pure = get_PureType($Type1_Id, $TypeInfo{1});
13411 my %Type2_Pure = get_PureType($Type2_Id, $TypeInfo{2});
13412 my %Type1_Base = ($Type1_Pure{"Type"} eq "Array")?get_OneStep_BaseType($Type1_Pure{"Tid"}, $TypeInfo{1}):get_BaseType($Type1_Id, 1);
13413 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 +040013414 my $Type1_PLevel = get_PLevel($Type1_Id, 1);
13415 my $Type2_PLevel = get_PLevel($Type2_Id, 2);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013416 return () if(not $Type1{"Name"} or not $Type2{"Name"});
13417 return () if(not $Type1_Base{"Name"} or not $Type2_Base{"Name"});
13418 return () if($Type1_PLevel eq "" or $Type2_PLevel eq "");
13419 if($Type1_Base{"Name"} ne $Type2_Base{"Name"}
13420 and ($Type1{"Name"} eq $Type2{"Name"} or ($Type1_PLevel>=1 and $Type1_PLevel==$Type2_PLevel
13421 and $Type1_Base{"Name"} ne "void" and $Type2_Base{"Name"} ne "void")))
13422 { # base type change
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040013423 if($Type1{"Name"} eq $Type2{"Name"})
13424 {
13425 if($Type1{"Type"} eq "Typedef" and $Type2{"Type"} eq "Typedef")
13426 { # will be reported in mergeTypes() as typedef problem
13427 return ();
13428 }
13429 my %Typedef_1 = goToFirst($Type1{"Tid"}, 1, "Typedef");
13430 my %Typedef_2 = goToFirst($Type2{"Tid"}, 2, "Typedef");
13431 if(%Typedef_1 and %Typedef_2)
13432 {
13433 if($Typedef_1{"Name"} eq $Typedef_2{"Name"}
13434 and $Typedef_1{"Type"} eq "Typedef" and $Typedef_2{"Type"} eq "Typedef")
13435 { # const Typedef
13436 return ();
13437 }
13438 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013439 }
13440 if($Type1_Base{"Name"}!~/anon\-/ and $Type2_Base{"Name"}!~/anon\-/)
13441 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040013442 if($Level eq "Binary"
13443 and $Type1_Base{"Size"} ne $Type2_Base{"Size"}
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013444 and $Type1_Base{"Size"} and $Type2_Base{"Size"})
13445 {
13446 %{$LocalProblems{$Prefix."_BaseType_And_Size"}}=(
13447 "Old_Value"=>$Type1_Base{"Name"},
13448 "New_Value"=>$Type2_Base{"Name"},
13449 "Old_Size"=>$Type1_Base{"Size"}*$BYTE_SIZE,
13450 "New_Size"=>$Type2_Base{"Size"}*$BYTE_SIZE,
13451 "InitialType_Type"=>$Type1_Pure{"Type"});
13452 }
13453 else
13454 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040013455 if(checkFormatChange($Type1_Base{"Tid"}, $Type2_Base{"Tid"}, $Level))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013456 { # format change
13457 %{$LocalProblems{$Prefix."_BaseType_Format"}}=(
13458 "Old_Value"=>$Type1_Base{"Name"},
13459 "New_Value"=>$Type2_Base{"Name"},
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +040013460 "Old_Size"=>$Type1_Base{"Size"}*$BYTE_SIZE,
13461 "New_Size"=>$Type2_Base{"Size"}*$BYTE_SIZE,
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013462 "InitialType_Type"=>$Type1_Pure{"Type"});
13463 }
13464 elsif(tNameLock($Type1_Base{"Tid"}, $Type2_Base{"Tid"}))
13465 {
13466 %{$LocalProblems{$Prefix."_BaseType"}}=(
13467 "Old_Value"=>$Type1_Base{"Name"},
13468 "New_Value"=>$Type2_Base{"Name"},
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +040013469 "Old_Size"=>$Type1_Base{"Size"}*$BYTE_SIZE,
13470 "New_Size"=>$Type2_Base{"Size"}*$BYTE_SIZE,
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013471 "InitialType_Type"=>$Type1_Pure{"Type"});
13472 }
13473 }
13474 }
13475 }
13476 elsif($Type1{"Name"} ne $Type2{"Name"})
13477 { # type change
13478 if($Type1{"Name"}!~/anon\-/ and $Type2{"Name"}!~/anon\-/)
13479 {
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +040013480 if($Prefix eq "Return"
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013481 and $Type1_Pure{"Name"} eq "void")
13482 {
13483 %{$LocalProblems{"Return_Type_From_Void"}}=(
13484 "New_Value"=>$Type2{"Name"},
13485 "New_Size"=>$Type2{"Size"}*$BYTE_SIZE,
13486 "InitialType_Type"=>$Type1_Pure{"Type"});
13487 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013488 elsif($Prefix eq "Return"
13489 and $Type2_Pure{"Name"} eq "void")
13490 {
13491 %{$LocalProblems{"Return_Type_Became_Void"}}=(
13492 "Old_Value"=>$Type1{"Name"},
13493 "Old_Size"=>$Type1{"Size"}*$BYTE_SIZE,
13494 "InitialType_Type"=>$Type1_Pure{"Type"});
13495 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013496 else
13497 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040013498 if($Level eq "Binary"
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040013499 and $Type1{"Size"} and $Type2{"Size"}
13500 and $Type1{"Size"} ne $Type2{"Size"})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013501 {
13502 %{$LocalProblems{$Prefix."_Type_And_Size"}}=(
13503 "Old_Value"=>$Type1{"Name"},
13504 "New_Value"=>$Type2{"Name"},
13505 "Old_Size"=>$Type1{"Size"}*$BYTE_SIZE,
13506 "New_Size"=>$Type2{"Size"}*$BYTE_SIZE,
13507 "InitialType_Type"=>$Type1_Pure{"Type"});
13508 }
13509 else
13510 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040013511 if(checkFormatChange($Type1_Id, $Type2_Id, $Level))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013512 { # format change
13513 %{$LocalProblems{$Prefix."_Type_Format"}}=(
13514 "Old_Value"=>$Type1{"Name"},
13515 "New_Value"=>$Type2{"Name"},
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +040013516 "Old_Size"=>$Type1{"Size"}*$BYTE_SIZE,
13517 "New_Size"=>$Type2{"Size"}*$BYTE_SIZE,
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013518 "InitialType_Type"=>$Type1_Pure{"Type"});
13519 }
13520 elsif(tNameLock($Type1_Id, $Type2_Id))
13521 { # FIXME: correct this condition
13522 %{$LocalProblems{$Prefix."_Type"}}=(
13523 "Old_Value"=>$Type1{"Name"},
13524 "New_Value"=>$Type2{"Name"},
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +040013525 "Old_Size"=>$Type1{"Size"}*$BYTE_SIZE,
13526 "New_Size"=>$Type2{"Size"}*$BYTE_SIZE,
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013527 "InitialType_Type"=>$Type1_Pure{"Type"});
13528 }
13529 }
13530 }
13531 }
13532 }
13533 if($Type1_PLevel!=$Type2_PLevel)
13534 {
13535 if($Type1{"Name"} ne "void" and $Type1{"Name"} ne "..."
13536 and $Type2{"Name"} ne "void" and $Type2{"Name"} ne "...")
13537 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040013538 if($Level eq "Source")
13539 {
13540 %{$LocalProblems{$Prefix."_PointerLevel"}}=(
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013541 "Old_Value"=>$Type1_PLevel,
13542 "New_Value"=>$Type2_PLevel);
13543 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040013544 else
13545 {
13546 if($Type2_PLevel>$Type1_PLevel) {
13547 %{$LocalProblems{$Prefix."_PointerLevel_Increased"}}=(
13548 "Old_Value"=>$Type1_PLevel,
13549 "New_Value"=>$Type2_PLevel);
13550 }
13551 else {
13552 %{$LocalProblems{$Prefix."_PointerLevel_Decreased"}}=(
13553 "Old_Value"=>$Type1_PLevel,
13554 "New_Value"=>$Type2_PLevel);
13555 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013556 }
13557 }
13558 }
13559 if($Type1_Pure{"Type"} eq "Array")
13560 { # base_type[N] -> base_type[N]
13561 # base_type: older_structure -> typedef to newer_structure
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040013562 my %SubProblems = detectTypeChange($Type1_Base{"Tid"}, $Type2_Base{"Tid"}, $Prefix, $Level);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013563 foreach my $SubProblemType (keys(%SubProblems))
13564 {
13565 $SubProblemType=~s/_Type/_BaseType/g;
13566 next if(defined $LocalProblems{$SubProblemType});
13567 foreach my $Attr (keys(%{$SubProblems{$SubProblemType}})) {
13568 $LocalProblems{$SubProblemType}{$Attr} = $SubProblems{$SubProblemType}{$Attr};
13569 }
13570 }
13571 }
13572 return %LocalProblems;
13573}
13574
13575sub tNameLock($$)
13576{
13577 my ($Tid1, $Tid2) = @_;
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040013578 my $Changed = 0;
13579 if(differentDumps("G"))
13580 { # different GCC versions
13581 $Changed = 1;
13582 }
13583 elsif(differentDumps("V"))
13584 { # different versions of ABI dumps
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040013585 if(not checkDump(1, "2.13")
13586 or not checkDump(2, "2.13"))
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040013587 { # latest names update
13588 # 2.6: added restrict qualifier
13589 # 2.13: added missed typedefs to qualified types
13590 $Changed = 1;
13591 }
13592 }
13593 if($Changed)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013594 { # different formats
13595 if($UseOldDumps)
13596 { # old dumps
13597 return 0;
13598 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040013599 my $TN1 = $TypeInfo{1}{$Tid1}{"Name"};
13600 my $TN2 = $TypeInfo{2}{$Tid2}{"Name"};
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040013601
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040013602 my $TT1 = $TypeInfo{1}{$Tid1}{"Type"};
13603 my $TT2 = $TypeInfo{2}{$Tid2}{"Type"};
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040013604
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040013605 my %Base1 = get_Type($Tid1, 1);
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040013606 while(defined $Base1{"Type"} and $Base1{"Type"} eq "Typedef") {
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +040013607 %Base1 = get_OneStep_BaseType($Base1{"Tid"}, $TypeInfo{1});
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013608 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040013609 my %Base2 = get_Type($Tid2, 2);
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040013610 while(defined $Base2{"Type"} and $Base2{"Type"} eq "Typedef") {
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +040013611 %Base2 = get_OneStep_BaseType($Base2{"Tid"}, $TypeInfo{2});
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013612 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +040013613 my $BName1 = uncover_typedefs($Base1{"Name"}, 1);
13614 my $BName2 = uncover_typedefs($Base2{"Name"}, 2);
13615 if($BName1 eq $BName2)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013616 { # equal base types
13617 return 0;
13618 }
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040013619
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040013620 if(not checkDump(1, "2.13")
13621 or not checkDump(2, "2.13"))
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040013622 { # broken array names in ABI dumps < 2.13
13623 if($TT1 eq "Array"
13624 and $TT2 eq "Array")
13625 {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013626 return 0;
13627 }
13628 }
13629
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040013630 if(not checkDump(1, "2.6")
13631 or not checkDump(2, "2.6"))
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040013632 { # added restrict attribute in 2.6
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040013633 if($TN1!~/\brestrict\b/
13634 and $TN2=~/\brestrict\b/)
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040013635 {
13636 return 0;
13637 }
13638 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013639 }
13640 return 1;
13641}
13642
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040013643sub differentDumps($)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013644{
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040013645 my $Check = $_[0];
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +040013646 if(defined $Cache{"differentDumps"}{$Check}) {
13647 return $Cache{"differentDumps"}{$Check};
13648 }
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040013649 if($UsedDump{1}{"V"} and $UsedDump{2}{"V"})
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040013650 {
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040013651 if($Check eq "G")
13652 {
13653 if(getGccVersion(1) ne getGccVersion(2))
13654 { # different GCC versions
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +040013655 return ($Cache{"differentDumps"}{$Check}=1);
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040013656 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040013657 }
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040013658 if($Check eq "V")
13659 {
13660 if(cmpVersions(formatVersion($UsedDump{1}{"V"}, 2),
13661 formatVersion($UsedDump{2}{"V"}, 2))!=0)
13662 { # different dump versions (skip micro version)
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +040013663 return ($Cache{"differentDumps"}{$Check}=1);
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040013664 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040013665 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013666 }
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +040013667 return ($Cache{"differentDumps"}{$Check}=0);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013668}
13669
13670sub formatVersion($$)
13671{ # cut off version digits
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040013672 my ($V, $Digits) = @_;
13673 my @Elems = split(/\./, $V);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013674 return join(".", splice(@Elems, 0, $Digits));
13675}
13676
13677sub htmlSpecChars($)
13678{
13679 my $Str = $_[0];
Andrey Ponomarenko5c09ef32012-06-14 18:17:33 +040013680 if(not $Str) {
13681 return $Str;
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040013682 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013683 $Str=~s/\&([^#]|\Z)/&amp;$1/g;
13684 $Str=~s/</&lt;/g;
13685 $Str=~s/\-\>/&#45;&gt;/g; # &minus;
13686 $Str=~s/>/&gt;/g;
13687 $Str=~s/([^ ])( )([^ ])/$1\@ALONE_SP\@$3/g;
13688 $Str=~s/ /&#160;/g; # &nbsp;
13689 $Str=~s/\@ALONE_SP\@/ /g;
13690 $Str=~s/\n/<br\/>/g;
13691 $Str=~s/\"/&quot;/g;
13692 $Str=~s/\'/&#39;/g;
13693 return $Str;
13694}
13695
Andrey Ponomarenko5c09ef32012-06-14 18:17:33 +040013696sub xmlSpecChars($)
13697{
13698 my $Str = $_[0];
13699 if(not $Str) {
13700 return $Str;
13701 }
13702
13703 $Str=~s/\&([^#]|\Z)/&amp;$1/g;
13704 $Str=~s/</&lt;/g;
13705 $Str=~s/>/&gt;/g;
13706
13707 $Str=~s/\"/&quot;/g;
13708 $Str=~s/\'/&#39;/g;
13709
13710 return $Str;
13711}
13712
Andrey Ponomarenko01117f12012-06-26 12:23:02 +040013713sub xmlSpecChars_R($)
13714{
13715 my $Str = $_[0];
13716 if(not $Str) {
13717 return $Str;
13718 }
13719
13720 $Str=~s/&amp;/&/g;
13721 $Str=~s/&lt;/</g;
13722 $Str=~s/&gt;/>/g;
13723
13724 $Str=~s/&quot;/"/g;
13725 $Str=~s/&#39;/'/g;
13726
13727 return $Str;
13728}
13729
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013730sub black_name($)
13731{
13732 my $Name = $_[0];
13733 return "<span class='iname_b'>".highLight_Signature($Name)."</span>";
13734}
13735
13736sub highLight_Signature($)
13737{
13738 my $Signature = $_[0];
13739 return highLight_Signature_PPos_Italic($Signature, "", 0, 0, 0);
13740}
13741
13742sub highLight_Signature_Italic_Color($)
13743{
13744 my $Signature = $_[0];
13745 return highLight_Signature_PPos_Italic($Signature, "", 1, 1, 1);
13746}
13747
13748sub separate_symbol($)
13749{
13750 my $Symbol = $_[0];
13751 my ($Name, $Spec, $Ver) = ($Symbol, "", "");
13752 if($Symbol=~/\A([^\@\$\?]+)([\@\$]+)([^\@\$]+)\Z/) {
13753 ($Name, $Spec, $Ver) = ($1, $2, $3);
13754 }
13755 return ($Name, $Spec, $Ver);
13756}
13757
13758sub cut_f_attrs($)
13759{
13760 if($_[0]=~s/(\))((| (const volatile|const|volatile))(| \[static\]))\Z/$1/) {
13761 return $2;
13762 }
13763 return "";
13764}
13765
13766sub highLight_Signature_PPos_Italic($$$$$)
13767{
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040013768 my ($FullSignature, $Param_Pos, $ItalicParams, $ColorParams, $ShowReturn) = @_;
13769 $Param_Pos = "" if(not defined $Param_Pos);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013770 if($CheckObjectsOnly) {
13771 $ItalicParams=$ColorParams=0;
13772 }
13773 my ($Signature, $VersionSpec, $SymbolVersion) = separate_symbol($FullSignature);
13774 my $Return = "";
13775 if($ShowRetVal and $Signature=~s/([^:]):([^:].+?)\Z/$1/g) {
13776 $Return = $2;
13777 }
Andrey Ponomarenko16934472012-03-29 15:37:04 +040013778 my $SCenter = find_center($Signature, "(");
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013779 if(not $SCenter)
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040013780 { # global data
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013781 $Signature = htmlSpecChars($Signature);
13782 $Signature=~s!(\[data\])!<span style='color:Black;font-weight:normal;'>$1</span>!g;
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040013783 $Signature .= (($SymbolVersion)?"<span class='sym_ver'>&#160;$VersionSpec&#160;$SymbolVersion</span>":"");
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013784 if($Return and $ShowReturn) {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040013785 $Signature .= "<span class='sym_p nowrap'> &#160;<b>:</b>&#160;&#160;".htmlSpecChars($Return)."</span>";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013786 }
13787 return $Signature;
13788 }
13789 my ($Begin, $End) = (substr($Signature, 0, $SCenter), "");
13790 $Begin.=" " if($Begin!~/ \Z/);
13791 $End = cut_f_attrs($Signature);
13792 my @Parts = ();
Andrey Ponomarenko07aea072012-11-12 16:15:07 +040013793 my ($Short, $Params) = split_Signature($Signature);
13794 my @SParts = separate_Params($Params, 1, 1);
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040013795 foreach my $Pos (0 .. $#SParts)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013796 {
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040013797 my $Part = $SParts[$Pos];
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013798 $Part=~s/\A\s+|\s+\Z//g;
13799 my ($Part_Styled, $ParamName) = (htmlSpecChars($Part), "");
13800 if($Part=~/\([\*]+(\w+)\)/i) {
13801 $ParamName = $1;#func-ptr
13802 }
13803 elsif($Part=~/(\w+)[\,\)]*\Z/i) {
13804 $ParamName = $1;
13805 }
13806 if(not $ParamName) {
13807 push(@Parts, $Part_Styled);
13808 next;
13809 }
13810 if($ItalicParams and not $TName_Tid{1}{$Part}
13811 and not $TName_Tid{2}{$Part})
13812 {
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040013813 my $Style = "param";
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040013814 if($Param_Pos ne ""
13815 and $Pos==$Param_Pos) {
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040013816 $Style = "focus_p";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013817 }
13818 elsif($ColorParams) {
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040013819 $Style = "color_p";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013820 }
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040013821 $Part_Styled =~ s!(\W)$ParamName([\,\)]|\Z)!$1<span class=\'$Style\'>$ParamName</span>$2!ig;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013822 }
13823 $Part_Styled=~s/,(\w)/, $1/g;
13824 push(@Parts, $Part_Styled);
13825 }
13826 if(@Parts)
13827 {
13828 foreach my $Num (0 .. $#Parts)
13829 {
13830 if($Num==$#Parts)
13831 { # add ")" to the last parameter
13832 $Parts[$Num] = "<span class='nowrap'>".$Parts[$Num]." )</span>";
13833 }
13834 elsif(length($Parts[$Num])<=45) {
13835 $Parts[$Num] = "<span class='nowrap'>".$Parts[$Num]."</span>";
13836 }
13837 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040013838 $Signature = htmlSpecChars($Begin)."<span class='sym_p'>(&#160;".join(" ", @Parts)."</span>".$End;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013839 }
13840 else {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040013841 $Signature = htmlSpecChars($Begin)."<span class='sym_p'>(&#160;)</span>".$End;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013842 }
13843 if($Return and $ShowReturn) {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040013844 $Signature .= "<span class='sym_p nowrap'> &#160;<b>:</b>&#160;&#160;".htmlSpecChars($Return)."</span>";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013845 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040013846 $Signature=~s!\[\]![&#160;]!g;
13847 $Signature=~s!operator=!operator&#160;=!g;
13848 $Signature=~s!(\[in-charge\]|\[not-in-charge\]|\[in-charge-deleting\]|\[static\])!<span class='sym_kind'>$1</span>!g;
13849 return $Signature.(($SymbolVersion)?"<span class='sym_ver'>&#160;$VersionSpec&#160;$SymbolVersion</span>":"");
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013850}
13851
Andrey Ponomarenko07aea072012-11-12 16:15:07 +040013852sub split_Signature($)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013853{
Andrey Ponomarenko07aea072012-11-12 16:15:07 +040013854 my $Signature = $_[0];
13855 if(my $ShortName = substr($Signature, 0, find_center($Signature, "(")))
13856 {
13857 $Signature=~s/\A\Q$ShortName\E\(//g;
13858 cut_f_attrs($Signature);
13859 $Signature=~s/\)\Z//;
13860 return ($ShortName, $Signature);
13861 }
13862
13863 # error
13864 return ($Signature, "");
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013865}
13866
Andrey Ponomarenko07aea072012-11-12 16:15:07 +040013867sub separate_Params($$$)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013868{
Andrey Ponomarenko07aea072012-11-12 16:15:07 +040013869 my ($Params, $Comma, $Sp) = @_;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013870 my @Parts = ();
Andrey Ponomarenko16934472012-03-29 15:37:04 +040013871 my %B = ( "("=>0, "<"=>0, ")"=>0, ">"=>0 );
13872 my $Part = 0;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013873 foreach my $Pos (0 .. length($Params) - 1)
13874 {
Andrey Ponomarenko16934472012-03-29 15:37:04 +040013875 my $S = substr($Params, $Pos, 1);
13876 if(defined $B{$S}) {
Andrey Ponomarenko07aea072012-11-12 16:15:07 +040013877 $B{$S} += 1;
Andrey Ponomarenko16934472012-03-29 15:37:04 +040013878 }
13879 if($S eq "," and
13880 $B{"("}==$B{")"} and $B{"<"}==$B{">"})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013881 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040013882 if($Comma)
13883 { # include comma
Andrey Ponomarenko16934472012-03-29 15:37:04 +040013884 $Parts[$Part] .= $S;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013885 }
Andrey Ponomarenko16934472012-03-29 15:37:04 +040013886 $Part += 1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013887 }
13888 else {
Andrey Ponomarenko16934472012-03-29 15:37:04 +040013889 $Parts[$Part] .= $S;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013890 }
13891 }
Andrey Ponomarenko07aea072012-11-12 16:15:07 +040013892 if(not $Sp)
13893 { # remove spaces
13894 foreach (@Parts)
13895 {
13896 s/\A //g;
13897 s/ \Z//g;
13898 }
13899 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013900 return @Parts;
13901}
13902
Andrey Ponomarenko16934472012-03-29 15:37:04 +040013903sub find_center($$)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013904{
13905 my ($Sign, $Target) = @_;
Andrey Ponomarenko16934472012-03-29 15:37:04 +040013906 my %B = ( "("=>0, "<"=>0, ")"=>0, ">"=>0 );
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013907 my $Center = 0;
Andrey Ponomarenko16934472012-03-29 15:37:04 +040013908 if($Sign=~s/(operator([^\w\s\(\)]+|\(\)))//g)
13909 { # operators
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013910 $Center+=length($1);
13911 }
13912 foreach my $Pos (0 .. length($Sign)-1)
13913 {
13914 my $S = substr($Sign, $Pos, 1);
13915 if($S eq $Target)
13916 {
13917 if($B{"("}==$B{")"}
13918 and $B{"<"}==$B{">"}) {
13919 return $Center;
13920 }
13921 }
13922 if(defined $B{$S}) {
13923 $B{$S}+=1;
13924 }
13925 $Center+=1;
13926 }
13927 return 0;
13928}
13929
13930sub appendFile($$)
13931{
13932 my ($Path, $Content) = @_;
13933 return if(not $Path);
13934 if(my $Dir = get_dirname($Path)) {
13935 mkpath($Dir);
13936 }
Andrey Ponomarenko16934472012-03-29 15:37:04 +040013937 open(FILE, ">>", $Path) || die ("can't open file \'$Path\': $!\n");
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013938 print FILE $Content;
13939 close(FILE);
13940}
13941
13942sub writeFile($$)
13943{
13944 my ($Path, $Content) = @_;
13945 return if(not $Path);
13946 if(my $Dir = get_dirname($Path)) {
13947 mkpath($Dir);
13948 }
Andrey Ponomarenko16934472012-03-29 15:37:04 +040013949 open(FILE, ">", $Path) || die ("can't open file \'$Path\': $!\n");
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013950 print FILE $Content;
13951 close(FILE);
13952}
13953
13954sub readFile($)
13955{
13956 my $Path = $_[0];
13957 return "" if(not $Path or not -f $Path);
Andrey Ponomarenko16934472012-03-29 15:37:04 +040013958 open(FILE, $Path);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013959 local $/ = undef;
13960 my $Content = <FILE>;
13961 close(FILE);
Andrey Ponomarenko85043792012-05-14 16:48:07 +040013962 if($Path!~/\.(tu|class|abi)\Z/) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013963 $Content=~s/\r/\n/g;
13964 }
13965 return $Content;
13966}
13967
13968sub get_filename($)
13969{ # much faster than basename() from File::Basename module
Andrey Ponomarenko85043792012-05-14 16:48:07 +040013970 if(defined $Cache{"get_filename"}{$_[0]}) {
13971 return $Cache{"get_filename"}{$_[0]};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013972 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +040013973 if($_[0] and $_[0]=~/([^\/\\]+)[\/\\]*\Z/) {
13974 return ($Cache{"get_filename"}{$_[0]}=$1);
13975 }
13976 return ($Cache{"get_filename"}{$_[0]}="");
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013977}
13978
13979sub get_dirname($)
13980{ # much faster than dirname() from File::Basename module
Andrey Ponomarenko85043792012-05-14 16:48:07 +040013981 if(defined $Cache{"get_dirname"}{$_[0]}) {
13982 return $Cache{"get_dirname"}{$_[0]};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013983 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +040013984 if($_[0] and $_[0]=~/\A(.*?)[\/\\]+[^\/\\]*[\/\\]*\Z/) {
13985 return ($Cache{"get_dirname"}{$_[0]}=$1);
13986 }
13987 return ($Cache{"get_dirname"}{$_[0]}="");
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013988}
13989
13990sub separate_path($) {
13991 return (get_dirname($_[0]), get_filename($_[0]));
13992}
13993
13994sub esc($)
13995{
13996 my $Str = $_[0];
13997 $Str=~s/([()\[\]{}$ &'"`;,<>\+])/\\$1/g;
13998 return $Str;
13999}
14000
14001sub readLineNum($$)
14002{
14003 my ($Path, $Num) = @_;
14004 return "" if(not $Path or not -f $Path);
Andrey Ponomarenko16934472012-03-29 15:37:04 +040014005 open(FILE, $Path);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014006 foreach (1 ... $Num) {
14007 <FILE>;
14008 }
14009 my $Line = <FILE>;
14010 close(FILE);
14011 return $Line;
14012}
14013
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040014014sub readAttributes($$)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014015{
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040014016 my ($Path, $Num) = @_;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014017 return () if(not $Path or not -f $Path);
14018 my %Attributes = ();
Andrey Ponomarenko85043792012-05-14 16:48:07 +040014019 if(readLineNum($Path, $Num)=~/<!--\s+(.+)\s+-->/)
14020 {
14021 foreach my $AttrVal (split(/;/, $1))
14022 {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014023 if($AttrVal=~/(.+):(.+)/)
14024 {
14025 my ($Name, $Value) = ($1, $2);
14026 $Attributes{$Name} = $Value;
14027 }
14028 }
14029 }
14030 return \%Attributes;
14031}
14032
14033sub is_abs($) {
14034 return ($_[0]=~/\A(\/|\w+:[\/\\])/);
14035}
14036
14037sub get_abs_path($)
14038{ # abs_path() should NOT be called for absolute inputs
14039 # because it can change them
14040 my $Path = $_[0];
14041 if(not is_abs($Path)) {
14042 $Path = abs_path($Path);
14043 }
14044 return $Path;
14045}
14046
14047sub get_OSgroup()
14048{
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +040014049 my $N = $Config{"osname"};
14050 if($N=~/macos|darwin|rhapsody/i) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014051 return "macos";
14052 }
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +040014053 elsif($N=~/freebsd|openbsd|netbsd/i) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014054 return "bsd";
14055 }
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +040014056 elsif($N=~/haiku|beos/i) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014057 return "beos";
14058 }
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +040014059 elsif($N=~/symbian|epoc/i) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014060 return "symbian";
14061 }
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +040014062 elsif($N=~/win/i) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014063 return "windows";
14064 }
14065 else {
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +040014066 return $N;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014067 }
14068}
14069
14070sub getGccVersion($)
14071{
14072 my $LibVersion = $_[0];
14073 if($GCC_VERSION{$LibVersion})
14074 { # dump version
14075 return $GCC_VERSION{$LibVersion};
14076 }
14077 elsif($UsedDump{$LibVersion}{"V"})
14078 { # old-version dumps
14079 return "unknown";
14080 }
14081 my $GccVersion = get_dumpversion($GCC_PATH); # host version
14082 if(not $GccVersion) {
14083 return "unknown";
14084 }
14085 return $GccVersion;
14086}
14087
14088sub showArch($)
14089{
14090 my $Arch = $_[0];
14091 if($Arch eq "arm"
14092 or $Arch eq "mips") {
14093 return uc($Arch);
14094 }
14095 return $Arch;
14096}
14097
14098sub getArch($)
14099{
14100 my $LibVersion = $_[0];
14101 if($CPU_ARCH{$LibVersion})
14102 { # dump version
14103 return $CPU_ARCH{$LibVersion};
14104 }
14105 elsif($UsedDump{$LibVersion}{"V"})
14106 { # old-version dumps
14107 return "unknown";
14108 }
14109 if(defined $Cache{"getArch"}{$LibVersion}) {
14110 return $Cache{"getArch"}{$LibVersion};
14111 }
14112 my $Arch = get_dumpmachine($GCC_PATH); # host version
14113 if(not $Arch) {
14114 return "unknown";
14115 }
14116 if($Arch=~/\A([\w]{3,})(-|\Z)/) {
14117 $Arch = $1;
14118 }
14119 $Arch = "x86" if($Arch=~/\Ai[3-7]86\Z/);
14120 if($OSgroup eq "windows") {
14121 $Arch = "x86" if($Arch=~/win32|mingw32/i);
14122 $Arch = "x86_64" if($Arch=~/win64|mingw64/i);
14123 }
14124 $Cache{"getArch"}{$LibVersion} = $Arch;
14125 return $Arch;
14126}
14127
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014128sub get_Report_Header($)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014129{
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014130 my $Level = $_[0];
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014131 my $ArchInfo = " on <span style='color:Blue;'>".showArch(getArch(1))."</span>";
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014132 if(getArch(1) ne getArch(2)
14133 or getArch(1) eq "unknown"
14134 or $Level eq "Source")
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014135 { # don't show architecture in the header
14136 $ArchInfo="";
14137 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014138 my $Report_Header = "<h1><span class='nowrap'>";
14139 if($Level eq "Source") {
14140 $Report_Header .= "Source compatibility";
14141 }
14142 elsif($Level eq "Binary") {
14143 $Report_Header .= "Binary compatibility";
14144 }
14145 else {
14146 $Report_Header .= "API compatibility";
14147 }
14148 $Report_Header .= " report for the <span style='color:Blue;'>$TargetLibraryFName</span> $TargetComponent</span>";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014149 $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>";
14150 if($AppPath) {
14151 $Report_Header .= " <span class='nowrap'>&#160;(relating to the portability of application <span style='color:Blue;'>".get_filename($AppPath)."</span>)</span>";
14152 }
14153 $Report_Header .= "</h1>\n";
14154 return $Report_Header;
14155}
14156
14157sub get_SourceInfo()
14158{
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040014159 my ($CheckedHeaders, $CheckedLibs) = ("", "");
14160 if(not $CheckObjectsOnly)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014161 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040014162 $CheckedHeaders = "<a name='Headers'></a><h2>Header Files (".keys(%{$Registered_Headers{1}}).")</h2><hr/>\n";
14163 $CheckedHeaders .= "<div class='h_list'>\n";
14164 foreach my $Header_Path (sort {lc($Registered_Headers{1}{$a}{"Identity"}) cmp lc($Registered_Headers{1}{$b}{"Identity"})} keys(%{$Registered_Headers{1}}))
14165 {
14166 my $Identity = $Registered_Headers{1}{$Header_Path}{"Identity"};
14167 my $Header_Name = get_filename($Identity);
14168 my $Dest_Comment = ($Identity=~/[\/\\]/)?" ($Identity)":"";
14169 $CheckedHeaders .= $Header_Name.$Dest_Comment."<br/>\n";
14170 }
14171 $CheckedHeaders .= "</div>\n";
14172 $CheckedHeaders .= "<br/>$TOP_REF<br/>\n";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014173 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040014174 if(not $CheckHeadersOnly)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014175 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040014176 $CheckedLibs = "<a name='Libs'></a><h2>".ucfirst($SLIB_TYPE)." Libraries (".keys(%{$Library_Symbol{1}}).")</h2><hr/>\n";
14177 $CheckedLibs .= "<div class='lib_list'>\n";
14178 foreach my $Library (sort {lc($a) cmp lc($b)} keys(%{$Library_Symbol{1}}))
14179 {
14180 $Library.=" (.$LIB_EXT)" if($Library!~/\.\w+\Z/);
14181 $CheckedLibs .= $Library."<br/>\n";
14182 }
14183 $CheckedLibs .= "</div>\n";
14184 $CheckedLibs .= "<br/>$TOP_REF<br/>\n";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014185 }
14186 return $CheckedHeaders.$CheckedLibs;
14187}
14188
14189sub get_TypeProblems_Count($$$)
14190{
14191 my ($TypeChanges, $TargetPriority, $Level) = @_;
14192 my $Type_Problems_Count = 0;
14193 foreach my $Type_Name (sort keys(%{$TypeChanges}))
14194 {
14195 my %Kinds_Target = ();
14196 foreach my $Kind (keys(%{$TypeChanges->{$Type_Name}}))
14197 {
14198 foreach my $Location (keys(%{$TypeChanges->{$Type_Name}{$Kind}}))
14199 {
14200 my $Target = $TypeChanges->{$Type_Name}{$Kind}{$Location}{"Target"};
14201 my $Priority = getProblemSeverity($Level, $Kind);
14202 next if($Priority ne $TargetPriority);
14203 if($Kinds_Target{$Kind}{$Target}) {
14204 next;
14205 }
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040014206 if(cmpSeverities($Type_MaxSeverity{$Level}{$Type_Name}{$Kind}{$Target}, $Priority))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014207 { # select a problem with the highest priority
14208 next;
14209 }
14210 $Kinds_Target{$Kind}{$Target} = 1;
14211 $Type_Problems_Count += 1;
14212 }
14213 }
14214 }
14215 return $Type_Problems_Count;
14216}
14217
14218sub get_Summary($)
14219{
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014220 my $Level = $_[0];
14221 my ($Added, $Removed, $I_Problems_High, $I_Problems_Medium, $I_Problems_Low, $T_Problems_High,
14222 $C_Problems_Low, $T_Problems_Medium, $T_Problems_Low, $I_Other, $T_Other) = (0,0,0,0,0,0,0,0,0,0,0);
14223 %{$RESULT{$Level}} = (
14224 "Problems"=>0,
14225 "Warnings"=>0,
14226 "Affected"=>0 );
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014227 # check rules
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014228 foreach my $Interface (sort keys(%{$CompatProblems{$Level}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014229 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014230 foreach my $Kind (keys(%{$CompatProblems{$Level}{$Interface}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014231 {
14232 if(not defined $CompatRules{$Level}{$Kind})
14233 { # unknown rule
14234 if(not $UnknownRules{$Level}{$Kind})
14235 { # only one warning
14236 printMsg("WARNING", "unknown rule \"$Kind\" (\"$Level\")");
14237 $UnknownRules{$Level}{$Kind}=1;
14238 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014239 delete($CompatProblems{$Level}{$Interface}{$Kind});
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014240 }
14241 }
14242 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014243 foreach my $Interface (sort keys(%{$CompatProblems{$Level}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014244 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014245 foreach my $Kind (sort keys(%{$CompatProblems{$Level}{$Interface}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014246 {
14247 if($CompatRules{$Level}{$Kind}{"Kind"} eq "Symbols")
14248 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014249 foreach my $Location (sort keys(%{$CompatProblems{$Level}{$Interface}{$Kind}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014250 {
14251 my $Priority = getProblemSeverity($Level, $Kind);
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014252 if($Kind eq "Added_Symbol") {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014253 $Added += 1;
14254 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014255 elsif($Kind eq "Removed_Symbol")
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014256 {
14257 $Removed += 1;
14258 $TotalAffected{$Level}{$Interface} = $Priority;
14259 }
14260 else
14261 {
14262 if($Priority eq "Safe") {
14263 $I_Other += 1;
14264 }
14265 elsif($Priority eq "High") {
14266 $I_Problems_High += 1;
14267 }
14268 elsif($Priority eq "Medium") {
14269 $I_Problems_Medium += 1;
14270 }
14271 elsif($Priority eq "Low") {
14272 $I_Problems_Low += 1;
14273 }
14274 if(($Priority ne "Low" or $StrictCompat)
14275 and $Priority ne "Safe") {
14276 $TotalAffected{$Level}{$Interface} = $Priority;
14277 }
14278 }
14279 }
14280 }
14281 }
14282 }
14283 my %TypeChanges = ();
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014284 foreach my $Interface (sort keys(%{$CompatProblems{$Level}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014285 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014286 foreach my $Kind (keys(%{$CompatProblems{$Level}{$Interface}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014287 {
14288 if($CompatRules{$Level}{$Kind}{"Kind"} eq "Types")
14289 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014290 foreach my $Location (sort {cmp_locations($b, $a)} sort keys(%{$CompatProblems{$Level}{$Interface}{$Kind}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014291 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014292 my $Type_Name = $CompatProblems{$Level}{$Interface}{$Kind}{$Location}{"Type_Name"};
14293 my $Target = $CompatProblems{$Level}{$Interface}{$Kind}{$Location}{"Target"};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014294 my $Priority = getProblemSeverity($Level, $Kind);
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040014295 if(cmpSeverities($Type_MaxSeverity{$Level}{$Type_Name}{$Kind}{$Target}, $Priority))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014296 { # select a problem with the highest priority
14297 next;
14298 }
14299 if(($Priority ne "Low" or $StrictCompat)
14300 and $Priority ne "Safe") {
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040014301 $TotalAffected{$Level}{$Interface} = maxSeverity($TotalAffected{$Level}{$Interface}, $Priority);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014302 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014303 %{$TypeChanges{$Type_Name}{$Kind}{$Location}} = %{$CompatProblems{$Level}{$Interface}{$Kind}{$Location}};
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040014304 $Type_MaxSeverity{$Level}{$Type_Name}{$Kind}{$Target} = maxSeverity($Type_MaxSeverity{$Level}{$Type_Name}{$Kind}{$Target}, $Priority);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014305 }
14306 }
14307 }
14308 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014309
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014310 $T_Problems_High = get_TypeProblems_Count(\%TypeChanges, "High", $Level);
14311 $T_Problems_Medium = get_TypeProblems_Count(\%TypeChanges, "Medium", $Level);
14312 $T_Problems_Low = get_TypeProblems_Count(\%TypeChanges, "Low", $Level);
14313 $T_Other = get_TypeProblems_Count(\%TypeChanges, "Safe", $Level);
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014314
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014315 if($CheckObjectsOnly)
14316 { # only removed exported symbols
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014317 $RESULT{$Level}{"Affected"} = $Removed*100/keys(%{$Symbol_Library{1}});
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014318 }
14319 else
14320 { # changed and removed public symbols
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014321 my $SCount = keys(%{$CheckedSymbols{$Level}});
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014322 if($ExtendedCheck)
14323 { # don't count external_func_0 for constants
14324 $SCount-=1;
14325 }
14326 if($SCount)
14327 {
14328 my %Weight = (
14329 "High" => 100,
14330 "Medium" => 50,
14331 "Low" => 25
14332 );
14333 foreach (keys(%{$TotalAffected{$Level}})) {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014334 $RESULT{$Level}{"Affected"}+=$Weight{$TotalAffected{$Level}{$_}};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014335 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014336 $RESULT{$Level}{"Affected"} = $RESULT{$Level}{"Affected"}/$SCount;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014337 }
14338 else {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014339 $RESULT{$Level}{"Affected"} = 0;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014340 }
14341 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014342 $RESULT{$Level}{"Affected"} = show_number($RESULT{$Level}{"Affected"});
14343 if($RESULT{$Level}{"Affected"}>=100) {
14344 $RESULT{$Level}{"Affected"} = 100;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014345 }
14346
Andrey Ponomarenko85043792012-05-14 16:48:07 +040014347 $RESULT{$Level}{"Problems"} += $Removed;
14348 $RESULT{$Level}{"Problems"} += $T_Problems_High + $I_Problems_High;
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014349 $RESULT{$Level}{"Problems"} += $T_Problems_Medium + $I_Problems_Medium;
Andrey Ponomarenko85043792012-05-14 16:48:07 +040014350 if($StrictCompat) {
14351 $RESULT{$Level}{"Problems"} += $T_Problems_Low + $I_Problems_Low;
14352 }
14353 else {
14354 $RESULT{$Level}{"Warnings"} += $T_Problems_Low + $I_Problems_Low;
14355 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014356
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014357 if($C_Problems_Low = keys(%{$ProblemsWithConstants{$Level}}))
14358 {
Andrey Ponomarenko85043792012-05-14 16:48:07 +040014359 if(defined $CompatRules{$Level}{"Changed_Constant"})
14360 {
14361 if($StrictCompat) {
14362 $RESULT{$Level}{"Problems"} += $C_Problems_Low;
14363 }
14364 else {
14365 $RESULT{$Level}{"Warnings"} += $C_Problems_Low;
14366 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014367 }
14368 else
14369 {
14370 printMsg("WARNING", "unknown rule \"Changed_Constant\" (\"$Level\")");
14371 $C_Problems_Low = 0;
14372 }
14373 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +040014374 if($CheckImpl and $Level eq "Binary")
14375 {
14376 if($StrictCompat) {
14377 $RESULT{$Level}{"Problems"} += keys(%ImplProblems);
14378 }
14379 else {
14380 $RESULT{$Level}{"Warnings"} += keys(%ImplProblems);
14381 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014382 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +040014383 if($RESULT{$Level}{"Problems"}
14384 and $RESULT{$Level}{"Affected"}) {
14385 $RESULT{$Level}{"Verdict"} = "incompatible";
14386 }
14387 else {
14388 $RESULT{$Level}{"Verdict"} = "compatible";
14389 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014390
14391 my $TotalTypes = keys(%{$CheckedTypes{$Level}});
14392 if(not $TotalTypes)
14393 { # list all the types
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014394 $TotalTypes = keys(%{$TName_Tid{1}});
14395 }
14396
14397 my ($Arch1, $Arch2) = (getArch(1), getArch(2));
14398 my ($GccV1, $GccV2) = (getGccVersion(1), getGccVersion(2));
14399
14400 my ($TestInfo, $TestResults, $Problem_Summary) = ();
14401
14402 if($ReportFormat eq "xml")
14403 { # XML
14404 # test info
14405 $TestInfo .= " <library>$TargetLibraryName</library>\n";
14406 $TestInfo .= " <version1>\n";
14407 $TestInfo .= " <number>".$Descriptor{1}{"Version"}."</number>\n";
14408 $TestInfo .= " <architecture>$Arch1</architecture>\n";
14409 $TestInfo .= " <gcc>$GccV1</gcc>\n";
14410 $TestInfo .= " </version1>\n";
14411
14412 $TestInfo .= " <version2>\n";
14413 $TestInfo .= " <number>".$Descriptor{2}{"Version"}."</number>\n";
14414 $TestInfo .= " <architecture>$Arch2</architecture>\n";
14415 $TestInfo .= " <gcc>$GccV2</gcc>\n";
14416 $TestInfo .= " </version2>\n";
14417 $TestInfo = "<test_info>\n".$TestInfo."</test_info>\n\n";
14418
14419 # test results
14420 $TestResults .= " <headers>\n";
14421 foreach my $Name (sort {lc($Registered_Headers{1}{$a}{"Identity"}) cmp lc($Registered_Headers{1}{$b}{"Identity"})} keys(%{$Registered_Headers{1}}))
14422 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014423 my $Identity = $Registered_Headers{1}{$Name}{"Identity"};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014424 my $Comment = ($Identity=~/[\/\\]/)?" ($Identity)":"";
14425 $TestResults .= " <name>".get_filename($Name).$Comment."</name>\n";
14426 }
14427 $TestResults .= " </headers>\n";
14428
14429 $TestResults .= " <libs>\n";
14430 foreach my $Library (sort {lc($a) cmp lc($b)} keys(%{$Library_Symbol{1}}))
14431 {
14432 $Library.=" (.$LIB_EXT)" if($Library!~/\.\w+\Z/);
14433 $TestResults .= " <name>$Library</name>\n";
14434 }
14435 $TestResults .= " </libs>\n";
14436
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040014437 $TestResults .= " <symbols>".(keys(%{$CheckedSymbols{$Level}}) - keys(%ExtendedSymbols))."</symbols>\n";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014438 $TestResults .= " <types>".$TotalTypes."</types>\n";
14439
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014440 $TestResults .= " <verdict>".$RESULT{$Level}{"Verdict"}."</verdict>\n";
14441 $TestResults .= " <affected>".$RESULT{$Level}{"Affected"}."</affected>\n";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014442 $TestResults = "<test_results>\n".$TestResults."</test_results>\n\n";
14443
14444 # problem summary
14445 $Problem_Summary .= " <added_symbols>".$Added."</added_symbols>\n";
14446 $Problem_Summary .= " <removed_symbols>".$Removed."</removed_symbols>\n";
14447
14448 $Problem_Summary .= " <problems_with_types>\n";
14449 $Problem_Summary .= " <high>$T_Problems_High</high>\n";
14450 $Problem_Summary .= " <medium>$T_Problems_Medium</medium>\n";
14451 $Problem_Summary .= " <low>$T_Problems_Low</low>\n";
14452 $Problem_Summary .= " <safe>$T_Other</safe>\n";
14453 $Problem_Summary .= " </problems_with_types>\n";
14454
14455 $Problem_Summary .= " <problems_with_symbols>\n";
14456 $Problem_Summary .= " <high>$I_Problems_High</high>\n";
14457 $Problem_Summary .= " <medium>$I_Problems_Medium</medium>\n";
14458 $Problem_Summary .= " <low>$I_Problems_Low</low>\n";
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014459 $Problem_Summary .= " <safe>$I_Other</safe>\n";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014460 $Problem_Summary .= " </problems_with_symbols>\n";
14461
14462 $Problem_Summary .= " <problems_with_constants>\n";
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014463 $Problem_Summary .= " <low>$C_Problems_Low</low>\n";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014464 $Problem_Summary .= " </problems_with_constants>\n";
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014465 if($CheckImpl and $Level eq "Binary")
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014466 {
14467 $Problem_Summary .= " <impl>\n";
14468 $Problem_Summary .= " <low>".keys(%ImplProblems)."</low>\n";
14469 $Problem_Summary .= " </impl>\n";
14470 }
14471 $Problem_Summary = "<problem_summary>\n".$Problem_Summary."</problem_summary>\n\n";
14472
14473 return ($TestInfo.$TestResults.$Problem_Summary, "");
14474 }
14475 else
14476 { # HTML
14477 # test info
14478 $TestInfo = "<h2>Test Info</h2><hr/>\n";
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014479 $TestInfo .= "<table class='summary'>\n";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014480 $TestInfo .= "<tr><th>".ucfirst($TargetComponent)." Name</th><td>$TargetLibraryFName</td></tr>\n";
14481
14482 my (@VInf1, @VInf2, $AddTestInfo) = ();
14483 if($Arch1 ne "unknown"
14484 and $Arch2 ne "unknown")
14485 { # CPU arch
14486 if($Arch1 eq $Arch2)
14487 { # go to the separate section
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014488 $AddTestInfo .= "<tr><th>CPU Type</th><td>".showArch($Arch1)."</td></tr>\n";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014489 }
14490 else
14491 { # go to the version number
14492 push(@VInf1, showArch($Arch1));
14493 push(@VInf2, showArch($Arch2));
14494 }
14495 }
14496 if($GccV1 ne "unknown"
14497 and $GccV2 ne "unknown"
14498 and $OStarget ne "windows")
14499 { # GCC version
14500 if($GccV1 eq $GccV2)
14501 { # go to the separate section
14502 $AddTestInfo .= "<tr><th>GCC Version</th><td>$GccV1</td></tr>\n";
14503 }
14504 else
14505 { # go to the version number
14506 push(@VInf1, "gcc ".$GccV1);
14507 push(@VInf2, "gcc ".$GccV2);
14508 }
14509 }
14510 # show long version names with GCC version and CPU architecture name (if different)
14511 $TestInfo .= "<tr><th>Version #1</th><td>".$Descriptor{1}{"Version"}.(@VInf1?" (".join(", ", reverse(@VInf1)).")":"")."</td></tr>\n";
14512 $TestInfo .= "<tr><th>Version #2</th><td>".$Descriptor{2}{"Version"}.(@VInf2?" (".join(", ", reverse(@VInf2)).")":"")."</td></tr>\n";
14513 $TestInfo .= $AddTestInfo;
14514 #if($COMMON_LANGUAGE{1}) {
14515 # $TestInfo .= "<tr><th>Language</th><td>".$COMMON_LANGUAGE{1}."</td></tr>\n";
14516 #}
14517 if($ExtendedCheck) {
14518 $TestInfo .= "<tr><th>Mode</th><td>Extended</td></tr>\n";
14519 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014520 if($JoinReport)
14521 {
14522 if($Level eq "Binary") {
Andrey Ponomarenko16934472012-03-29 15:37:04 +040014523 $TestInfo .= "<tr><th>Subject</th><td width='150px'>Binary Compatibility</td></tr>\n"; # Run-time
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014524 }
14525 if($Level eq "Source") {
Andrey Ponomarenko16934472012-03-29 15:37:04 +040014526 $TestInfo .= "<tr><th>Subject</th><td width='150px'>Source Compatibility</td></tr>\n"; # Build-time
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014527 }
14528 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014529 $TestInfo .= "</table>\n";
14530
14531 # test results
14532 $TestResults = "<h2>Test Results</h2><hr/>\n";
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014533 $TestResults .= "<table class='summary'>";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014534
14535 my $Headers_Link = "0";
14536 $Headers_Link = "<a href='#Headers' style='color:Blue;'>".keys(%{$Registered_Headers{1}})."</a>" if(keys(%{$Registered_Headers{1}})>0);
14537 $TestResults .= "<tr><th>Total Header Files</th><td>".($CheckObjectsOnly?"0&#160;(not&#160;analyzed)":$Headers_Link)."</td></tr>\n";
14538
14539 if(not $ExtendedCheck)
14540 {
14541 my $Libs_Link = "0";
14542 $Libs_Link = "<a href='#Libs' style='color:Blue;'>".keys(%{$Library_Symbol{1}})."</a>" if(keys(%{$Library_Symbol{1}})>0);
14543 $TestResults .= "<tr><th>Total ".ucfirst($SLIB_TYPE)." Libraries</th><td>".($CheckHeadersOnly?"0&#160;(not&#160;analyzed)":$Libs_Link)."</td></tr>\n";
14544 }
14545
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040014546 $TestResults .= "<tr><th>Total Symbols / Types</th><td>".(keys(%{$CheckedSymbols{$Level}}) - keys(%ExtendedSymbols))." / ".$TotalTypes."</td></tr>\n";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014547
Andrey Ponomarenko85043792012-05-14 16:48:07 +040014548 my $META_DATA = "verdict:".$RESULT{$Level}{"Verdict"}.";";
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014549 if($JoinReport) {
14550 $META_DATA = "kind:".lc($Level).";".$META_DATA;
14551 }
Andrey Ponomarenko16934472012-03-29 15:37:04 +040014552 $TestResults .= "<tr><th>Verdict</th>";
Andrey Ponomarenko85043792012-05-14 16:48:07 +040014553 if($RESULT{$Level}{"Verdict"} eq "incompatible") {
Andrey Ponomarenko16934472012-03-29 15:37:04 +040014554 $TestResults .= "<td><span style='color:Red;'><b>Incompatible<br/>(".$RESULT{$Level}{"Affected"}."%)</b></span></td>";
14555 }
14556 else {
14557 $TestResults .= "<td><span style='color:Green;'><b>Compatible</b></span></td>";
14558 }
14559 $TestResults .= "</tr>\n";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014560 $TestResults .= "</table>\n";
14561
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014562 $META_DATA .= "affected:".$RESULT{$Level}{"Affected"}.";";# in percents
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014563 # problem summary
14564 $Problem_Summary = "<h2>Problem Summary</h2><hr/>\n";
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014565 $Problem_Summary .= "<table class='summary'>";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014566 $Problem_Summary .= "<tr><th></th><th style='text-align:center;'>Severity</th><th style='text-align:center;'>Count</th></tr>";
14567
14568 my $Added_Link = "0";
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014569 if($Added>0)
14570 {
14571 if($JoinReport) {
14572 $Added_Link = "<a href='#".$Level."_Added' style='color:Blue;'>$Added</a>";
14573 }
14574 else {
14575 $Added_Link = "<a href='#Added' style='color:Blue;'>$Added</a>";
14576 }
14577 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014578 $META_DATA .= "added:$Added;";
Andrey Ponomarenko16934472012-03-29 15:37:04 +040014579 $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 +040014580
14581 my $Removed_Link = "0";
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014582 if($Removed>0)
14583 {
14584 if($JoinReport) {
14585 $Removed_Link = "<a href='#".$Level."_Removed' style='color:Blue;'>$Removed</a>"
14586 }
14587 else {
14588 $Removed_Link = "<a href='#Removed' style='color:Blue;'>$Removed</a>"
14589 }
14590 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014591 $META_DATA .= "removed:$Removed;";
Andrey Ponomarenko16934472012-03-29 15:37:04 +040014592 $Problem_Summary .= "<tr><th>Removed Symbols</th>";
14593 $Problem_Summary .= "<td>High</td><td".getStyle("I", "R", $Removed).">$Removed_Link</td></tr>\n";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014594
14595 my $TH_Link = "0";
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014596 $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 +040014597 $TH_Link = "n/a" if($CheckObjectsOnly);
14598 $META_DATA .= "type_problems_high:$T_Problems_High;";
Andrey Ponomarenko16934472012-03-29 15:37:04 +040014599 $Problem_Summary .= "<tr><th rowspan='3'>Problems with<br/>Data Types</th>";
14600 $Problem_Summary .= "<td>High</td><td".getStyle("T", "H", $T_Problems_High).">$TH_Link</td></tr>\n";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014601
14602 my $TM_Link = "0";
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014603 $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 +040014604 $TM_Link = "n/a" if($CheckObjectsOnly);
14605 $META_DATA .= "type_problems_medium:$T_Problems_Medium;";
Andrey Ponomarenko16934472012-03-29 15:37:04 +040014606 $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 +040014607
14608 my $TL_Link = "0";
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014609 $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 +040014610 $TL_Link = "n/a" if($CheckObjectsOnly);
14611 $META_DATA .= "type_problems_low:$T_Problems_Low;";
Andrey Ponomarenko16934472012-03-29 15:37:04 +040014612 $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 +040014613
14614 my $IH_Link = "0";
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014615 $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 +040014616 $IH_Link = "n/a" if($CheckObjectsOnly);
14617 $META_DATA .= "interface_problems_high:$I_Problems_High;";
Andrey Ponomarenko16934472012-03-29 15:37:04 +040014618 $Problem_Summary .= "<tr><th rowspan='3'>Problems with<br/>Symbols</th>";
14619 $Problem_Summary .= "<td>High</td><td".getStyle("I", "H", $I_Problems_High).">$IH_Link</td></tr>\n";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014620
14621 my $IM_Link = "0";
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014622 $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 +040014623 $IM_Link = "n/a" if($CheckObjectsOnly);
14624 $META_DATA .= "interface_problems_medium:$I_Problems_Medium;";
Andrey Ponomarenko16934472012-03-29 15:37:04 +040014625 $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 +040014626
14627 my $IL_Link = "0";
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014628 $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 +040014629 $IL_Link = "n/a" if($CheckObjectsOnly);
14630 $META_DATA .= "interface_problems_low:$I_Problems_Low;";
Andrey Ponomarenko16934472012-03-29 15:37:04 +040014631 $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 +040014632
14633 my $ChangedConstants_Link = "0";
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014634 if(keys(%{$CheckedSymbols{$Level}}) and $C_Problems_Low)
14635 {
14636 if($JoinReport) {
14637 $ChangedConstants_Link = "<a href='#".$Level."_Changed_Constants' style='color:Blue;'>$C_Problems_Low</a>";
14638 }
14639 else {
14640 $ChangedConstants_Link = "<a href='#Changed_Constants' style='color:Blue;'>$C_Problems_Low</a>";
14641 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014642 }
14643 $ChangedConstants_Link = "n/a" if($CheckObjectsOnly);
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014644 $META_DATA .= "changed_constants:$C_Problems_Low;";
Andrey Ponomarenko16934472012-03-29 15:37:04 +040014645 $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 +040014646
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014647 if($CheckImpl and $Level eq "Binary")
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014648 {
14649 my $ChangedImpl_Link = "0";
14650 $ChangedImpl_Link = "<a href='#Changed_Implementation' style='color:Blue;'>".keys(%ImplProblems)."</a>" if(keys(%ImplProblems)>0);
14651 $ChangedImpl_Link = "n/a" if($CheckHeadersOnly);
14652 $META_DATA .= "changed_implementation:".keys(%ImplProblems).";";
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040014653 $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 +040014654 }
14655 # Safe Changes
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014656 if($T_Other and not $CheckObjectsOnly)
14657 {
14658 my $TS_Link = "<a href='#".get_Anchor("Type", $Level, "Safe")."' style='color:Blue;'>$T_Other</a>";
Andrey Ponomarenko16934472012-03-29 15:37:04 +040014659 $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 +040014660 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014661
14662 if($I_Other and not $CheckObjectsOnly)
14663 {
14664 my $IS_Link = "<a href='#".get_Anchor("Symbol", $Level, "Safe")."' style='color:Blue;'>$I_Other</a>";
Andrey Ponomarenko16934472012-03-29 15:37:04 +040014665 $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 +040014666 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014667
14668 $META_DATA .= "tool_version:$TOOL_VERSION";
14669 $Problem_Summary .= "</table>\n";
Andrey Ponomarenko16934472012-03-29 15:37:04 +040014670 # $TestInfo = getLegend().$TestInfo;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014671 return ($TestInfo.$TestResults.$Problem_Summary, $META_DATA);
14672 }
14673}
14674
Andrey Ponomarenko16934472012-03-29 15:37:04 +040014675sub getStyle($$$)
14676{
14677 my ($Subj, $Act, $Num) = @_;
14678 my %Style = (
14679 "A"=>"new",
14680 "R"=>"failed",
14681 "S"=>"passed",
14682 "L"=>"warning",
14683 "M"=>"failed",
14684 "H"=>"failed"
14685 );
14686 if($Num>0) {
14687 return " class='".$Style{$Act}."'";
14688 }
14689 return "";
14690}
14691
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014692sub show_number($)
14693{
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014694 if($_[0])
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014695 {
Andrey Ponomarenko16934472012-03-29 15:37:04 +040014696 my $Num = cut_off_number($_[0], 2, 0);
14697 if($Num eq "0")
14698 {
14699 foreach my $P (3 .. 7)
14700 {
14701 $Num = cut_off_number($_[0], $P, 1);
14702 if($Num ne "0") {
14703 last;
14704 }
14705 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014706 }
14707 if($Num eq "0") {
14708 $Num = $_[0];
14709 }
14710 return $Num;
14711 }
14712 return $_[0];
14713}
14714
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014715sub cut_off_number($$$)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014716{
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014717 my ($num, $digs_to_cut, $z) = @_;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014718 if($num!~/\./)
14719 {
14720 $num .= ".";
14721 foreach (1 .. $digs_to_cut-1) {
14722 $num .= "0";
14723 }
14724 }
14725 elsif($num=~/\.(.+)\Z/ and length($1)<$digs_to_cut-1)
14726 {
14727 foreach (1 .. $digs_to_cut - 1 - length($1)) {
14728 $num .= "0";
14729 }
14730 }
14731 elsif($num=~/\d+\.(\d){$digs_to_cut,}/) {
14732 $num=sprintf("%.".($digs_to_cut-1)."f", $num);
14733 }
14734 $num=~s/\.[0]+\Z//g;
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014735 if($z) {
14736 $num=~s/(\.[1-9]+)[0]+\Z/$1/g;
14737 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014738 return $num;
14739}
14740
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014741sub get_Report_ChangedConstants($)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014742{
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014743 my $Level = $_[0];
Andrey Ponomarenko16934472012-03-29 15:37:04 +040014744 my $CHANGED_CONSTANTS = "";
14745 my %ReportMap = ();
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014746 foreach my $Constant (keys(%{$ProblemsWithConstants{$Level}})) {
Andrey Ponomarenko16934472012-03-29 15:37:04 +040014747 $ReportMap{$Constants{1}{$Constant}{"Header"}}{$Constant} = 1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014748 }
14749 my $Kind = "Changed_Constant";
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014750 if(not defined $CompatRules{$Level}{$Kind}) {
14751 return "";
14752 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014753 if($ReportFormat eq "xml")
14754 { # XML
Andrey Ponomarenko16934472012-03-29 15:37:04 +040014755 foreach my $HeaderName (sort {lc($a) cmp lc($b)} keys(%ReportMap))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014756 {
14757 $CHANGED_CONSTANTS .= " <header name=\"$HeaderName\">\n";
Andrey Ponomarenko16934472012-03-29 15:37:04 +040014758 foreach my $Constant (sort {lc($a) cmp lc($b)} keys(%{$ReportMap{$HeaderName}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014759 {
14760 $CHANGED_CONSTANTS .= " <constant name=\"$Constant\">\n";
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014761 my $Change = $CompatRules{$Level}{$Kind}{"Change"};
14762 my $Effect = $CompatRules{$Level}{$Kind}{"Effect"};
14763 my $Overcome = $CompatRules{$Level}{$Kind}{"Overcome"};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014764 $CHANGED_CONSTANTS .= " <problem id=\"$Kind\">\n";
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014765 $CHANGED_CONSTANTS .= " <change".getXmlParams($Change, $ProblemsWithConstants{$Level}{$Constant}).">$Change</change>\n";
14766 $CHANGED_CONSTANTS .= " <effect".getXmlParams($Effect, $ProblemsWithConstants{$Level}{$Constant}).">$Effect</effect>\n";
14767 $CHANGED_CONSTANTS .= " <overcome".getXmlParams($Overcome, $ProblemsWithConstants{$Level}{$Constant}).">$Overcome</overcome>\n";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014768 $CHANGED_CONSTANTS .= " </problem>\n";
14769 $CHANGED_CONSTANTS .= " </constant>\n";
14770 }
14771 $CHANGED_CONSTANTS .= " </header>\n";
14772 }
14773 $CHANGED_CONSTANTS = "<problems_with_constants severity=\"Low\">\n".$CHANGED_CONSTANTS."</problems_with_constants>\n\n";
14774 }
14775 else
14776 { # HTML
14777 my $Number = 0;
Andrey Ponomarenko16934472012-03-29 15:37:04 +040014778 foreach my $HeaderName (sort {lc($a) cmp lc($b)} keys(%ReportMap))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014779 {
14780 $CHANGED_CONSTANTS .= "<span class='h_name'>$HeaderName</span><br/>\n";
Andrey Ponomarenko16934472012-03-29 15:37:04 +040014781 foreach my $Name (sort {lc($a) cmp lc($b)} keys(%{$ReportMap{$HeaderName}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014782 {
14783 $Number += 1;
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014784 my $Change = applyMacroses($Level, $Kind, $CompatRules{$Level}{$Kind}{"Change"}, $ProblemsWithConstants{$Level}{$Name});
14785 my $Effect = $CompatRules{$Level}{$Kind}{"Effect"};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014786 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 +040014787 $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 +040014788 $Report = $ContentSpanStart."<span class='extendable'>[+]</span> ".$Name.$ContentSpanEnd."<br/>\n".$Report;
14789 $CHANGED_CONSTANTS .= insertIDs($Report);
14790 }
14791 $CHANGED_CONSTANTS .= "<br/>\n";
14792 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014793 if($CHANGED_CONSTANTS)
14794 {
14795 my $Anchor = "<a name='Changed_Constants'></a>";
14796 if($JoinReport) {
14797 $Anchor = "<a name='".$Level."_Changed_Constants'></a>";
14798 }
14799 $CHANGED_CONSTANTS = $Anchor."<h2>Problems with Constants ($Number)</h2><hr/>\n".$CHANGED_CONSTANTS.$TOP_REF."<br/>\n";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014800 }
14801 }
14802 return $CHANGED_CONSTANTS;
14803}
14804
14805sub get_Report_Impl()
14806{
Andrey Ponomarenko16934472012-03-29 15:37:04 +040014807 my $CHANGED_IMPLEMENTATION = "";
14808 my %ReportMap = ();
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014809 foreach my $Interface (sort keys(%ImplProblems))
14810 {
14811 my $HeaderName = $CompleteSignature{1}{$Interface}{"Header"};
14812 my $DyLib = $Symbol_Library{1}{$Interface};
Andrey Ponomarenko16934472012-03-29 15:37:04 +040014813 $ReportMap{$HeaderName}{$DyLib}{$Interface} = 1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014814 }
14815 my $Changed_Number = 0;
Andrey Ponomarenko16934472012-03-29 15:37:04 +040014816 foreach my $HeaderName (sort {lc($a) cmp lc($b)} keys(%ReportMap))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014817 {
Andrey Ponomarenko16934472012-03-29 15:37:04 +040014818 foreach my $DyLib (sort {lc($a) cmp lc($b)} keys(%{$ReportMap{$HeaderName}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014819 {
14820 my $FDyLib=$DyLib.($DyLib!~/\.\w+\Z/?" (.$LIB_EXT)":"");
14821 if($HeaderName) {
14822 $CHANGED_IMPLEMENTATION .= "<span class='h_name'>$HeaderName</span>, <span class='lib_name'>$FDyLib</span><br/>\n";
14823 }
14824 else {
14825 $CHANGED_IMPLEMENTATION .= "<span class='lib_name'>$DyLib</span><br/>\n";
14826 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014827 my %NameSpaceSymbols = ();
Andrey Ponomarenko16934472012-03-29 15:37:04 +040014828 foreach my $Interface (keys(%{$ReportMap{$HeaderName}{$DyLib}})) {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014829 $NameSpaceSymbols{get_IntNameSpace($Interface, 2)}{$Interface} = 1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014830 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014831 foreach my $NameSpace (sort keys(%NameSpaceSymbols))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014832 {
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040014833 $CHANGED_IMPLEMENTATION .= ($NameSpace)?"<span class='ns_title'>namespace</span> <span class='ns'>$NameSpace</span><br/>\n":"";
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014834 my @SortedInterfaces = sort {lc(get_Signature($a, 1)) cmp lc(get_Signature($b, 1))} keys(%{$NameSpaceSymbols{$NameSpace}});
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014835 foreach my $Interface (@SortedInterfaces)
14836 {
14837 $Changed_Number += 1;
14838 my $Signature = get_Signature($Interface, 1);
14839 if($NameSpace) {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040014840 $Signature=~s/\b\Q$NameSpace\E::\b//g;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014841 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014842 $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 +040014843 }
14844 }
14845 $CHANGED_IMPLEMENTATION .= "<br/>\n";
14846 }
14847 }
14848 if($CHANGED_IMPLEMENTATION) {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014849 $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 +040014850 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +040014851
14852 # clean memory
14853 %ImplProblems = ();
14854
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014855 return $CHANGED_IMPLEMENTATION;
14856}
14857
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014858sub getTitle($$$)
14859{
14860 my ($Header, $Library, $NameSpace) = @_;
14861 my $Title = "";
14862 if($Library and $Library!~/\.\w+\Z/) {
14863 $Library .= " (.$LIB_EXT)";
14864 }
14865 if($Header and $Library)
14866 {
14867 $Title .= "<span class='h_name'>$Header</span>";
14868 $Title .= ", <span class='lib_name'>$Library</span><br/>\n";
14869 }
14870 elsif($Library) {
14871 $Title .= "<span class='lib_name'>$Library</span><br/>\n";
14872 }
14873 elsif($Header) {
14874 $Title .= "<span class='h_name'>$Header</span><br/>\n";
14875 }
14876 if($NameSpace) {
14877 $Title .= "<span class='ns_title'>namespace</span> <span class='ns'>$NameSpace</span><br/>\n";
14878 }
14879 return $Title;
14880}
14881
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014882sub get_Report_Added($)
14883{
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014884 my $Level = $_[0];
Andrey Ponomarenko16934472012-03-29 15:37:04 +040014885 my $ADDED_INTERFACES = "";
14886 my %ReportMap = ();
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014887 foreach my $Interface (sort keys(%{$CompatProblems{$Level}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014888 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014889 foreach my $Kind (sort keys(%{$CompatProblems{$Level}{$Interface}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014890 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014891 if($Kind eq "Added_Symbol")
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014892 {
14893 my $HeaderName = $CompleteSignature{2}{$Interface}{"Header"};
14894 my $DyLib = $Symbol_Library{2}{$Interface};
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014895 if($Level eq "Source" and $ReportFormat eq "html")
14896 { # do not show library name in HTML report
14897 $DyLib = "";
14898 }
14899 $ReportMap{$HeaderName}{$DyLib}{$Interface} = 1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014900 }
14901 }
14902 }
14903 if($ReportFormat eq "xml")
14904 { # XML
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014905 foreach my $HeaderName (sort {lc($a) cmp lc($b)} keys(%ReportMap))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014906 {
14907 $ADDED_INTERFACES .= " <header name=\"$HeaderName\">\n";
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014908 foreach my $DyLib (sort {lc($a) cmp lc($b)} keys(%{$ReportMap{$HeaderName}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014909 {
14910 $ADDED_INTERFACES .= " <library name=\"$DyLib\">\n";
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014911 foreach my $Interface (keys(%{$ReportMap{$HeaderName}{$DyLib}})) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014912 $ADDED_INTERFACES .= " <name>$Interface</name>\n";
14913 }
14914 $ADDED_INTERFACES .= " </library>\n";
14915 }
14916 $ADDED_INTERFACES .= " </header>\n";
14917 }
14918 $ADDED_INTERFACES = "<added_symbols>\n".$ADDED_INTERFACES."</added_symbols>\n\n";
14919 }
14920 else
14921 { # HTML
14922 my $Added_Number = 0;
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014923 foreach my $HeaderName (sort {lc($a) cmp lc($b)} keys(%ReportMap))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014924 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014925 foreach my $DyLib (sort {lc($a) cmp lc($b)} keys(%{$ReportMap{$HeaderName}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014926 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014927 my %NameSpaceSymbols = ();
14928 foreach my $Interface (keys(%{$ReportMap{$HeaderName}{$DyLib}})) {
14929 $NameSpaceSymbols{get_IntNameSpace($Interface, 2)}{$Interface} = 1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014930 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014931 foreach my $NameSpace (sort keys(%NameSpaceSymbols))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014932 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014933 $ADDED_INTERFACES .= getTitle($HeaderName, $DyLib, $NameSpace);
14934 my @SortedInterfaces = sort {lc(get_Signature($a, 2)) cmp lc(get_Signature($b, 2))} keys(%{$NameSpaceSymbols{$NameSpace}});
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014935 foreach my $Interface (@SortedInterfaces)
14936 {
14937 $Added_Number += 1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014938 my $Signature = get_Signature($Interface, 2);
14939 if($NameSpace) {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040014940 $Signature=~s/\b\Q$NameSpace\E::\b//g;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014941 }
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040014942 if($Interface=~/\A(_Z|\?)/)
14943 {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014944 if($Signature) {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014945 $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 +040014946 }
14947 else {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014948 $ADDED_INTERFACES .= "<span class=\"iname\">".$Interface."</span><br/>\n";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014949 }
14950 }
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040014951 else
14952 {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014953 if($Signature) {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014954 $ADDED_INTERFACES .= "<span class=\"iname\">".highLight_Signature_Italic_Color($Signature)."</span><br/>\n";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014955 }
14956 else {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014957 $ADDED_INTERFACES .= "<span class=\"iname\">".$Interface."</span><br/>\n";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014958 }
14959 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014960 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014961 $ADDED_INTERFACES .= "<br/>\n";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014962 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014963 }
14964 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014965 if($ADDED_INTERFACES)
14966 {
14967 my $Anchor = "<a name='Added'></a>";
14968 if($JoinReport) {
14969 $Anchor = "<a name='".$Level."_Added'></a>";
14970 }
14971 $ADDED_INTERFACES = $Anchor."<h2>Added Symbols ($Added_Number)</h2><hr/>\n".$ADDED_INTERFACES.$TOP_REF."<br/>\n";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014972 }
14973 }
14974 return $ADDED_INTERFACES;
14975}
14976
14977sub get_Report_Removed($)
14978{
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014979 my $Level = $_[0];
Andrey Ponomarenko16934472012-03-29 15:37:04 +040014980 my $REMOVED_INTERFACES = "";
14981 my %ReportMap = ();
Andrey Ponomarenko85043792012-05-14 16:48:07 +040014982 foreach my $Symbol (sort keys(%{$CompatProblems{$Level}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014983 {
Andrey Ponomarenko85043792012-05-14 16:48:07 +040014984 foreach my $Kind (sort keys(%{$CompatProblems{$Level}{$Symbol}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014985 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014986 if($Kind eq "Removed_Symbol")
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014987 {
Andrey Ponomarenko85043792012-05-14 16:48:07 +040014988 my $HeaderName = $CompleteSignature{1}{$Symbol}{"Header"};
14989 my $DyLib = $Symbol_Library{1}{$Symbol};
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014990 if($Level eq "Source" and $ReportFormat eq "html")
14991 { # do not show library name in HTML report
14992 $DyLib = "";
14993 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +040014994 $ReportMap{$HeaderName}{$DyLib}{$Symbol} = 1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014995 }
14996 }
14997 }
14998 if($ReportFormat eq "xml")
14999 { # XML
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015000 foreach my $HeaderName (sort {lc($a) cmp lc($b)} keys(%ReportMap))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015001 {
15002 $REMOVED_INTERFACES .= " <header name=\"$HeaderName\">\n";
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015003 foreach my $DyLib (sort {lc($a) cmp lc($b)} keys(%{$ReportMap{$HeaderName}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015004 {
15005 $REMOVED_INTERFACES .= " <library name=\"$DyLib\">\n";
Andrey Ponomarenko85043792012-05-14 16:48:07 +040015006 foreach my $Symbol (keys(%{$ReportMap{$HeaderName}{$DyLib}})) {
15007 $REMOVED_INTERFACES .= " <name>$Symbol</name>\n";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015008 }
15009 $REMOVED_INTERFACES .= " </library>\n";
15010 }
15011 $REMOVED_INTERFACES .= " </header>\n";
15012 }
15013 $REMOVED_INTERFACES = "<removed_symbols>\n".$REMOVED_INTERFACES."</removed_symbols>\n\n";
15014 }
15015 else
15016 { # HTML
15017 my $Removed_Number = 0;
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015018 foreach my $HeaderName (sort {lc($a) cmp lc($b)} keys(%ReportMap))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015019 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015020 foreach my $DyLib (sort {lc($a) cmp lc($b)} keys(%{$ReportMap{$HeaderName}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015021 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015022 my %NameSpaceSymbols = ();
15023 foreach my $Interface (keys(%{$ReportMap{$HeaderName}{$DyLib}})) {
15024 $NameSpaceSymbols{get_IntNameSpace($Interface, 1)}{$Interface} = 1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015025 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015026 foreach my $NameSpace (sort keys(%NameSpaceSymbols))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015027 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015028 $REMOVED_INTERFACES .= getTitle($HeaderName, $DyLib, $NameSpace);
15029 my @SortedInterfaces = sort {lc(get_Signature($a, 1)) cmp lc(get_Signature($b, 1))} keys(%{$NameSpaceSymbols{$NameSpace}});
Andrey Ponomarenko85043792012-05-14 16:48:07 +040015030 foreach my $Symbol (@SortedInterfaces)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015031 {
15032 $Removed_Number += 1;
15033 my $SubReport = "";
Andrey Ponomarenko85043792012-05-14 16:48:07 +040015034 my $Signature = get_Signature($Symbol, 1);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015035 if($NameSpace) {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040015036 $Signature=~s/\b\Q$NameSpace\E::\b//g;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015037 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +040015038 if($Symbol=~/\A(_Z|\?)/)
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015039 {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015040 if($Signature) {
Andrey Ponomarenko85043792012-05-14 16:48:07 +040015041 $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 +040015042 }
15043 else {
Andrey Ponomarenko85043792012-05-14 16:48:07 +040015044 $REMOVED_INTERFACES .= "<span class=\"iname\">".$Symbol."</span><br/>\n";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015045 }
15046 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015047 else
15048 {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015049 if($Signature) {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015050 $REMOVED_INTERFACES .= "<span class=\"iname\">".highLight_Signature_Italic_Color($Signature)."</span><br/>\n";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015051 }
15052 else {
Andrey Ponomarenko85043792012-05-14 16:48:07 +040015053 $REMOVED_INTERFACES .= "<span class=\"iname\">".$Symbol."</span><br/>\n";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015054 }
15055 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015056 }
15057 }
15058 $REMOVED_INTERFACES .= "<br/>\n";
15059 }
15060 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015061 if($REMOVED_INTERFACES)
15062 {
15063 my $Anchor = "<a name='Removed'></a><a name='Withdrawn'></a>";
15064 if($JoinReport) {
15065 $Anchor = "<a name='".$Level."_Removed'></a><a name='".$Level."_Withdrawn'></a>";
15066 }
15067 $REMOVED_INTERFACES = $Anchor."<h2>Removed Symbols ($Removed_Number)</h2><hr/>\n".$REMOVED_INTERFACES.$TOP_REF."<br/>\n";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015068 }
15069 }
15070 return $REMOVED_INTERFACES;
15071}
15072
15073sub getXmlParams($$)
15074{
15075 my ($Content, $Problem) = @_;
15076 return "" if(not $Content or not $Problem);
15077 my %XMLparams = ();
15078 foreach my $Attr (sort {$b cmp $a} keys(%{$Problem}))
15079 {
15080 my $Macro = "\@".lc($Attr);
15081 if($Content=~/\Q$Macro\E/) {
15082 $XMLparams{lc($Attr)} = $Problem->{$Attr};
15083 }
15084 }
15085 my @PString = ();
15086 foreach my $P (sort {$b cmp $a} keys(%XMLparams)) {
Andrey Ponomarenko5c09ef32012-06-14 18:17:33 +040015087 push(@PString, $P."=\"".xmlSpecChars($XMLparams{$P})."\"");
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015088 }
15089 if(@PString) {
15090 return " ".join(" ", @PString);
15091 }
15092 else {
15093 return "";
15094 }
15095}
15096
15097sub addMarkup($)
15098{
15099 my $Content = $_[0];
15100 # auto-markup
15101 $Content=~s/\n[ ]*//; # spaces
15102 $Content=~s!(\@\w+\s*\(\@\w+\))!<nowrap>$1</nowrap>!g; # @old_type (@old_size)
15103 $Content=~s!(... \(\w+\))!<nowrap><b>$1</b></nowrap>!g; # ... (va_list)
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040015104 $Content=~s!<nowrap>(.+?)</nowrap>!<span class='nowrap'>$1</span>!g;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015105 $Content=~s!([2-9]\))!<br/>$1!g; # 1), 2), ...
15106 if($Content=~/\ANOTE:/)
15107 { # notes
15108 $Content=~s!(NOTE):!<b>$1</b>:!g;
15109 }
15110 else {
15111 $Content=~s!(NOTE):!<br/><b>$1</b>:!g;
15112 }
15113 $Content=~s! (out)-! <b>$1</b>-!g; # out-parameters
15114 my @Keywords = (
15115 "void",
15116 "const",
15117 "static",
15118 "restrict",
15119 "volatile",
15120 "register",
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040015121 "virtual"
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015122 );
15123 my $MKeys = join("|", @Keywords);
15124 foreach (@Keywords) {
15125 $MKeys .= "|non-".$_;
15126 }
15127 $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 +040015128
15129 # Markdown
15130 $Content=~s!\*\*([\w\-]+)\*\*!<b>$1</b>!ig;
15131 $Content=~s!\*([\w\-]+)\*!<i>$1</i>!ig;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015132 return $Content;
15133}
15134
15135sub applyMacroses($$$$)
15136{
15137 my ($Level, $Kind, $Content, $Problem) = @_;
15138 return "" if(not $Content or not $Problem);
15139 $Problem->{"Word_Size"} = $WORD_SIZE{2};
15140 $Content = addMarkup($Content);
15141 # macros
15142 foreach my $Attr (sort {$b cmp $a} keys(%{$Problem}))
15143 {
15144 my $Macro = "\@".lc($Attr);
15145 my $Value = $Problem->{$Attr};
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040015146 if(not defined $Value
15147 or $Value eq "") {
15148 next;
15149 }
Andrey Ponomarenko5c09ef32012-06-14 18:17:33 +040015150 if($Value=~/\s\(/ and $Value!~/['"]/)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015151 { # functions
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015152 $Value=~s/\s*\[[\w\-]+\]//g; # remove quals
15153 $Value=~s/\s\w+(\)|,)/$1/g; # remove parameter names
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015154 $Value = black_name($Value);
15155 }
15156 elsif($Value=~/\s/) {
15157 $Value = "<span class='value'>".htmlSpecChars($Value)."</span>";
15158 }
15159 elsif($Value=~/\A\d+\Z/
15160 and ($Attr eq "Old_Size" or $Attr eq "New_Size"))
15161 { # bits to bytes
15162 if($Value % $BYTE_SIZE)
15163 { # bits
15164 if($Value==1) {
15165 $Value = "<b>".$Value."</b> bit";
15166 }
15167 else {
15168 $Value = "<b>".$Value."</b> bits";
15169 }
15170 }
15171 else
15172 { # bytes
15173 $Value /= $BYTE_SIZE;
15174 if($Value==1) {
15175 $Value = "<b>".$Value."</b> byte";
15176 }
15177 else {
15178 $Value = "<b>".$Value."</b> bytes";
15179 }
15180 }
15181 }
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040015182 else
15183 {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015184 $Value = "<b>".htmlSpecChars($Value)."</b>";
15185 }
15186 $Content=~s/\Q$Macro\E/$Value/g;
15187 }
15188
15189 if($Content=~/(\A|[^\@\w])\@\w/)
15190 {
15191 if(not $IncompleteRules{$Level}{$Kind})
15192 { # only one warning
15193 printMsg("WARNING", "incomplete rule \"$Kind\" (\"$Level\")");
15194 $IncompleteRules{$Level}{$Kind} = 1;
15195 }
15196 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015197 return $Content;
15198}
15199
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040015200sub get_Report_SymbolProblems($$)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015201{
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015202 my ($TargetSeverity, $Level) = @_;
Andrey Ponomarenko16934472012-03-29 15:37:04 +040015203 my $INTERFACE_PROBLEMS = "";
15204 my (%ReportMap, %SymbolChanges) = ();
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015205 foreach my $Symbol (sort keys(%{$CompatProblems{$Level}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015206 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015207 my ($SN, $SS, $SV) = separate_symbol($Symbol);
15208 if($SV and defined $CompatProblems{$Level}{$SN}) {
15209 next;
15210 }
15211 foreach my $Kind (sort keys(%{$CompatProblems{$Level}{$Symbol}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015212 {
15213 if($CompatRules{$Level}{$Kind}{"Kind"} eq "Symbols"
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015214 and $Kind ne "Added_Symbol" and $Kind ne "Removed_Symbol")
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015215 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015216 my $HeaderName = $CompleteSignature{1}{$Symbol}{"Header"};
15217 my $DyLib = $Symbol_Library{1}{$Symbol};
15218 if(not $DyLib and my $VSym = $SymVer{1}{$Symbol})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015219 { # Symbol with Version
15220 $DyLib = $Symbol_Library{1}{$VSym};
15221 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040015222 if(not $DyLib)
15223 { # const global data
15224 $DyLib = "";
15225 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015226 if($Level eq "Source" and $ReportFormat eq "html")
15227 { # do not show library name in HTML report
15228 $DyLib = "";
15229 }
15230 %{$SymbolChanges{$Symbol}{$Kind}} = %{$CompatProblems{$Level}{$Symbol}{$Kind}};
15231 foreach my $Location (sort keys(%{$SymbolChanges{$Symbol}{$Kind}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015232 {
15233 my $Priority = getProblemSeverity($Level, $Kind);
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015234 if($Priority ne $TargetSeverity) {
15235 delete($SymbolChanges{$Symbol}{$Kind}{$Location});
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015236 }
15237 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015238 if(not keys(%{$SymbolChanges{$Symbol}{$Kind}}))
15239 {
15240 delete($SymbolChanges{$Symbol}{$Kind});
15241 next;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015242 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015243 $ReportMap{$HeaderName}{$DyLib}{$Symbol} = 1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015244 }
15245 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015246 if(not keys(%{$SymbolChanges{$Symbol}})) {
15247 delete($SymbolChanges{$Symbol});
15248 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015249 }
15250 if($ReportFormat eq "xml")
15251 { # XML
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015252 foreach my $HeaderName (sort {lc($a) cmp lc($b)} keys(%ReportMap))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015253 {
15254 $INTERFACE_PROBLEMS .= " <header name=\"$HeaderName\">\n";
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015255 foreach my $DyLib (sort {lc($a) cmp lc($b)} keys(%{$ReportMap{$HeaderName}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015256 {
15257 $INTERFACE_PROBLEMS .= " <library name=\"$DyLib\">\n";
15258 foreach my $Symbol (sort {lc($tr_name{$a}) cmp lc($tr_name{$b})} keys(%SymbolChanges))
15259 {
15260 $INTERFACE_PROBLEMS .= " <symbol name=\"$Symbol\">\n";
15261 foreach my $Kind (keys(%{$SymbolChanges{$Symbol}}))
15262 {
15263 foreach my $Location (sort keys(%{$SymbolChanges{$Symbol}{$Kind}}))
15264 {
15265 my %Problem = %{$SymbolChanges{$Symbol}{$Kind}{$Location}};
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040015266 $Problem{"Param_Pos"} = showPos($Problem{"Param_Pos"});
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015267 $INTERFACE_PROBLEMS .= " <problem id=\"$Kind\">\n";
15268 my $Change = $CompatRules{$Level}{$Kind}{"Change"};
15269 $INTERFACE_PROBLEMS .= " <change".getXmlParams($Change, \%Problem).">$Change</change>\n";
15270 my $Effect = $CompatRules{$Level}{$Kind}{"Effect"};
15271 $INTERFACE_PROBLEMS .= " <effect".getXmlParams($Effect, \%Problem).">$Effect</effect>\n";
15272 my $Overcome = $CompatRules{$Level}{$Kind}{"Overcome"};
15273 $INTERFACE_PROBLEMS .= " <overcome".getXmlParams($Overcome, \%Problem).">$Overcome</overcome>\n";
15274 $INTERFACE_PROBLEMS .= " </problem>\n";
15275 }
15276 }
15277 $INTERFACE_PROBLEMS .= " </symbol>\n";
15278 }
15279 $INTERFACE_PROBLEMS .= " </library>\n";
15280 }
15281 $INTERFACE_PROBLEMS .= " </header>\n";
15282 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015283 $INTERFACE_PROBLEMS = "<problems_with_symbols severity=\"$TargetSeverity\">\n".$INTERFACE_PROBLEMS."</problems_with_symbols>\n\n";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015284 }
15285 else
15286 { # HTML
15287 my $ProblemsNum = 0;
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015288 foreach my $HeaderName (sort {lc($a) cmp lc($b)} keys(%ReportMap))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015289 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015290 foreach my $DyLib (sort {lc($a) cmp lc($b)} keys(%{$ReportMap{$HeaderName}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015291 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015292 my (%NameSpaceSymbols, %NewSignature) = ();
15293 foreach my $Symbol (keys(%{$ReportMap{$HeaderName}{$DyLib}})) {
15294 $NameSpaceSymbols{get_IntNameSpace($Symbol, 1)}{$Symbol} = 1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015295 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015296 foreach my $NameSpace (sort keys(%NameSpaceSymbols))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015297 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015298 $INTERFACE_PROBLEMS .= getTitle($HeaderName, $DyLib, $NameSpace);
15299 my @SortedInterfaces = sort {lc($tr_name{$a}) cmp lc($tr_name{$b})} keys(%{$NameSpaceSymbols{$NameSpace}});
15300 foreach my $Symbol (@SortedInterfaces)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015301 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015302 my $Signature = get_Signature($Symbol, 1);
15303 my $SYMBOL_REPORT = "";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015304 my $ProblemNum = 1;
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015305 foreach my $Kind (keys(%{$SymbolChanges{$Symbol}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015306 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015307 foreach my $Location (sort keys(%{$SymbolChanges{$Symbol}{$Kind}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015308 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015309 my %Problem = %{$SymbolChanges{$Symbol}{$Kind}{$Location}};
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040015310 $Problem{"Param_Pos"} = showPos($Problem{"Param_Pos"});
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015311 if($Problem{"New_Signature"}) {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015312 $NewSignature{$Symbol} = $Problem{"New_Signature"};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015313 }
15314 if(my $Change = applyMacroses($Level, $Kind, $CompatRules{$Level}{$Kind}{"Change"}, \%Problem))
15315 {
15316 my $Effect = applyMacroses($Level, $Kind, $CompatRules{$Level}{$Kind}{"Effect"}, \%Problem);
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015317 $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 +040015318 $ProblemNum += 1;
15319 $ProblemsNum += 1;
15320 }
15321 }
15322 }
15323 $ProblemNum -= 1;
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015324 if($SYMBOL_REPORT)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015325 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015326 $INTERFACE_PROBLEMS .= $ContentSpanStart."<span class='extendable'>[+]</span> ";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015327 if($Signature) {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015328 $INTERFACE_PROBLEMS .= highLight_Signature_Italic_Color($Signature);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015329 }
15330 else {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015331 $INTERFACE_PROBLEMS .= $Symbol;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015332 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015333 $INTERFACE_PROBLEMS .= " ($ProblemNum)".$ContentSpanEnd."<br/>\n";
15334 $INTERFACE_PROBLEMS .= $ContentDivStart."\n";
15335 if($NewSignature{$Symbol})
15336 { # argument list changed to
15337 $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 +040015338 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015339 if($Symbol=~/\A(_Z|\?)/) {
15340 $INTERFACE_PROBLEMS .= "<span class='mangled'>&#160;&#160;&#160;&#160;[symbol: <b>$Symbol</b>]</span><br/>\n";
15341 }
15342 $INTERFACE_PROBLEMS .= "<table class='ptable'><tr><th width='2%'></th><th width='47%'>Change</th><th>Effect</th></tr>$SYMBOL_REPORT</table><br/>\n";
15343 $INTERFACE_PROBLEMS .= $ContentDivEnd;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015344 if($NameSpace) {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040015345 $INTERFACE_PROBLEMS=~s/\b\Q$NameSpace\E::\b//g;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015346 }
15347 }
15348 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015349 $INTERFACE_PROBLEMS .= "<br/>";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015350 }
15351 }
15352 }
15353 if($INTERFACE_PROBLEMS)
15354 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015355 $INTERFACE_PROBLEMS = insertIDs($INTERFACE_PROBLEMS);
15356 my $Title = "Problems with Symbols, $TargetSeverity Severity";
15357 if($TargetSeverity eq "Safe")
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015358 { # Safe Changes
15359 $Title = "Other Changes in Symbols";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015360 }
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040015361 $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 +040015362 }
15363 }
15364 return $INTERFACE_PROBLEMS;
15365}
15366
15367sub get_Report_TypeProblems($$)
15368{
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015369 my ($TargetSeverity, $Level) = @_;
Andrey Ponomarenko16934472012-03-29 15:37:04 +040015370 my $TYPE_PROBLEMS = "";
15371 my (%ReportMap, %TypeChanges, %TypeType) = ();
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015372 foreach my $Interface (sort keys(%{$CompatProblems{$Level}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015373 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015374 foreach my $Kind (keys(%{$CompatProblems{$Level}{$Interface}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015375 {
15376 if($CompatRules{$Level}{$Kind}{"Kind"} eq "Types")
15377 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015378 foreach my $Location (sort {cmp_locations($b, $a)} sort keys(%{$CompatProblems{$Level}{$Interface}{$Kind}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015379 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015380 my $TypeName = $CompatProblems{$Level}{$Interface}{$Kind}{$Location}{"Type_Name"};
15381 my $TypeType = $CompatProblems{$Level}{$Interface}{$Kind}{$Location}{"Type_Type"};
15382 my $Target = $CompatProblems{$Level}{$Interface}{$Kind}{$Location}{"Target"};
15383 $CompatProblems{$Level}{$Interface}{$Kind}{$Location}{"Type_Type"} = lc($TypeType);
15384 my $Severity = getProblemSeverity($Level, $Kind);
15385 if($Severity eq "Safe"
15386 and $TargetSeverity ne "Safe") {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015387 next;
15388 }
15389 if(not $TypeType{$TypeName}
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015390 or $TypeType{$TypeName} eq "struct")
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015391 { # register type of the type, select "class" if type has "class"- and "struct"-type changes
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015392 $TypeType{$TypeName} = $CompatProblems{$Level}{$Interface}{$Kind}{$Location}{"Type_Type"};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015393 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015394
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040015395 if(cmpSeverities($Type_MaxSeverity{$Level}{$TypeName}{$Kind}{$Target}, $Severity))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015396 { # select a problem with the highest priority
15397 next;
15398 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015399 %{$TypeChanges{$TypeName}{$Kind}{$Location}} = %{$CompatProblems{$Level}{$Interface}{$Kind}{$Location}};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015400 }
15401 }
15402 }
15403 }
15404 my %Kinds_Locations = ();
15405 foreach my $TypeName (keys(%TypeChanges))
15406 {
15407 my %Kinds_Target = ();
15408 foreach my $Kind (sort keys(%{$TypeChanges{$TypeName}}))
15409 {
15410 foreach my $Location (sort {cmp_locations($b, $a)} sort keys(%{$TypeChanges{$TypeName}{$Kind}}))
15411 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015412 my $Severity = getProblemSeverity($Level, $Kind);
15413 if($Severity ne $TargetSeverity)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015414 { # other priority
15415 delete($TypeChanges{$TypeName}{$Kind}{$Location});
15416 next;
15417 }
15418 $Kinds_Locations{$TypeName}{$Kind}{$Location} = 1;
15419 my $Target = $TypeChanges{$TypeName}{$Kind}{$Location}{"Target"};
15420 if($Kinds_Target{$Kind}{$Target})
15421 { # duplicate target
15422 delete($TypeChanges{$TypeName}{$Kind}{$Location});
15423 next;
15424 }
15425 $Kinds_Target{$Kind}{$Target} = 1;
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040015426 my $HeaderName = $TypeInfo{1}{$TName_Tid{1}{$TypeName}}{"Header"};
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015427 $ReportMap{$HeaderName}{$TypeName} = 1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015428 }
15429 if(not keys(%{$TypeChanges{$TypeName}{$Kind}})) {
15430 delete($TypeChanges{$TypeName}{$Kind});
15431 }
15432 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015433 if(not keys(%{$TypeChanges{$TypeName}})) {
15434 delete($TypeChanges{$TypeName});
15435 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015436 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +040015437 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 +040015438 if($ReportFormat eq "xml")
15439 { # XML
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015440 foreach my $HeaderName (sort {lc($a) cmp lc($b)} keys(%ReportMap))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015441 {
15442 $TYPE_PROBLEMS .= " <header name=\"$HeaderName\">\n";
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015443 foreach my $TypeName (keys(%{$ReportMap{$HeaderName}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015444 {
Andrey Ponomarenko5c09ef32012-06-14 18:17:33 +040015445 $TYPE_PROBLEMS .= " <type name=\"".xmlSpecChars($TypeName)."\">\n";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015446 foreach my $Kind (sort {$b=~/Size/ <=> $a=~/Size/} sort keys(%{$TypeChanges{$TypeName}}))
15447 {
15448 foreach my $Location (sort {cmp_locations($b, $a)} sort keys(%{$TypeChanges{$TypeName}{$Kind}}))
15449 {
15450 my %Problem = %{$TypeChanges{$TypeName}{$Kind}{$Location}};
15451 $TYPE_PROBLEMS .= " <problem id=\"$Kind\">\n";
15452 my $Change = $CompatRules{$Level}{$Kind}{"Change"};
15453 $TYPE_PROBLEMS .= " <change".getXmlParams($Change, \%Problem).">$Change</change>\n";
15454 my $Effect = $CompatRules{$Level}{$Kind}{"Effect"};
15455 $TYPE_PROBLEMS .= " <effect".getXmlParams($Effect, \%Problem).">$Effect</effect>\n";
15456 my $Overcome = $CompatRules{$Level}{$Kind}{"Overcome"};
15457 $TYPE_PROBLEMS .= " <overcome".getXmlParams($Overcome, \%Problem).">$Overcome</overcome>\n";
15458 $TYPE_PROBLEMS .= " </problem>\n";
15459 }
15460 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +040015461 $TYPE_PROBLEMS .= getAffectedSymbols($Level, $TypeName, $Kinds_Locations{$TypeName}, \@Symbols);
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015462 if($Level eq "Binary" and grep {$_=~/Virtual|Base_Class/} keys(%{$Kinds_Locations{$TypeName}})) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015463 $TYPE_PROBLEMS .= showVTables($TypeName);
15464 }
15465 $TYPE_PROBLEMS .= " </type>\n";
15466 }
15467 $TYPE_PROBLEMS .= " </header>\n";
15468 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015469 $TYPE_PROBLEMS = "<problems_with_types severity=\"$TargetSeverity\">\n".$TYPE_PROBLEMS."</problems_with_types>\n\n";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015470 }
15471 else
15472 { # HTML
15473 my $ProblemsNum = 0;
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015474 foreach my $HeaderName (sort {lc($a) cmp lc($b)} keys(%ReportMap))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015475 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015476 my (%NameSpace_Type) = ();
15477 foreach my $TypeName (keys(%{$ReportMap{$HeaderName}})) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015478 $NameSpace_Type{parse_TypeNameSpace($TypeName, 1)}{$TypeName} = 1;
15479 }
15480 foreach my $NameSpace (sort keys(%NameSpace_Type))
15481 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015482 $TYPE_PROBLEMS .= getTitle($HeaderName, "", $NameSpace);
15483 my @SortedTypes = sort {$TypeType{$a}." ".lc($a) cmp $TypeType{$b}." ".lc($b)} keys(%{$NameSpace_Type{$NameSpace}});
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015484 foreach my $TypeName (@SortedTypes)
15485 {
15486 my $ProblemNum = 1;
15487 my $TYPE_REPORT = "";
15488 foreach my $Kind (sort {$b=~/Size/ <=> $a=~/Size/} sort keys(%{$TypeChanges{$TypeName}}))
15489 {
15490 foreach my $Location (sort {cmp_locations($b, $a)} sort keys(%{$TypeChanges{$TypeName}{$Kind}}))
15491 {
15492 my %Problem = %{$TypeChanges{$TypeName}{$Kind}{$Location}};
15493 if(my $Change = applyMacroses($Level, $Kind, $CompatRules{$Level}{$Kind}{"Change"}, \%Problem))
15494 {
15495 my $Effect = applyMacroses($Level, $Kind, $CompatRules{$Level}{$Kind}{"Effect"}, \%Problem);
15496 $TYPE_REPORT .= "<tr><th>$ProblemNum</th><td align='left' valign='top'>".$Change."</td><td align='left' valign='top'>$Effect</td></tr>\n";
15497 $ProblemNum += 1;
15498 $ProblemsNum += 1;
15499 }
15500 }
15501 }
15502 $ProblemNum -= 1;
15503 if($TYPE_REPORT)
15504 {
Andrey Ponomarenko85043792012-05-14 16:48:07 +040015505 my $Affected = getAffectedSymbols($Level, $TypeName, $Kinds_Locations{$TypeName}, \@Symbols);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015506 my $ShowVTables = "";
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015507 if($Level eq "Binary" and grep {$_=~/Virtual|Base_Class/} keys(%{$Kinds_Locations{$TypeName}})) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015508 $ShowVTables = showVTables($TypeName);
15509 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015510 $TYPE_PROBLEMS .= $ContentSpanStart."<span class='extendable'>[+]</span> <span class='ttype'>".$TypeType{$TypeName}."</span> ".htmlSpecChars($TypeName)." ($ProblemNum)".$ContentSpanEnd;
15511 $TYPE_PROBLEMS .= "<br/>\n".$ContentDivStart."<table class='ptable'><tr>\n";
15512 $TYPE_PROBLEMS .= "<th width='2%'></th><th width='47%'>Change</th>\n";
15513 $TYPE_PROBLEMS .= "<th>Effect</th></tr>".$TYPE_REPORT."</table>\n";
15514 $TYPE_PROBLEMS .= $ShowVTables.$Affected."<br/><br/>".$ContentDivEnd."\n";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015515 if($NameSpace) {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040015516 $TYPE_PROBLEMS=~s/\b\Q$NameSpace\E::(\w|\~)/$1/g;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015517 }
15518 }
15519 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015520 $TYPE_PROBLEMS .= "<br/>";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015521 }
15522 }
15523 if($TYPE_PROBLEMS)
15524 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015525 $TYPE_PROBLEMS = insertIDs($TYPE_PROBLEMS);
15526 my $Title = "Problems with Data Types, $TargetSeverity Severity";
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015527 if($TargetSeverity eq "Safe")
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015528 { # Safe Changes
15529 $Title = "Other Changes in Data Types";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015530 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015531 $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 +040015532 }
15533 }
15534 return $TYPE_PROBLEMS;
15535}
15536
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015537sub get_Anchor($$$)
15538{
15539 my ($Kind, $Level, $Severity) = @_;
15540 if($JoinReport)
15541 {
15542 if($Severity eq "Safe") {
15543 return "Other_".$Level."_Changes_In_".$Kind."s";
15544 }
15545 else {
15546 return $Kind."_".$Level."_Problems_".$Severity;
15547 }
15548 }
15549 else
15550 {
15551 if($Severity eq "Safe") {
15552 return "Other_Changes_In_".$Kind."s";
15553 }
15554 else {
15555 return $Kind."_Problems_".$Severity;
15556 }
15557 }
15558}
15559
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015560sub showVTables($)
15561{
15562 my $TypeName = $_[0];
15563 my $TypeId1 = $TName_Tid{1}{$TypeName};
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040015564 my %Type1 = get_Type($TypeId1, 1);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015565 if(defined $Type1{"VTable"}
15566 and keys(%{$Type1{"VTable"}}))
15567 {
15568 my $TypeId2 = $TName_Tid{2}{$TypeName};
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040015569 my %Type2 = get_Type($TypeId2, 2);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015570 if(defined $Type2{"VTable"}
15571 and keys(%{$Type2{"VTable"}}))
15572 {
15573 my %Indexes = map {$_=>1} (keys(%{$Type1{"VTable"}}), keys(%{$Type2{"VTable"}}));
15574 my %Entries = ();
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015575 foreach my $Index (sort {int($a)<=>int($b)} (keys(%Indexes)))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015576 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015577 $Entries{$Index}{"E1"} = simpleVEntry($Type1{"VTable"}{$Index});
15578 $Entries{$Index}{"E2"} = simpleVEntry($Type2{"VTable"}{$Index});
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015579 }
15580 my $VTABLES = "";
15581 if($ReportFormat eq "xml")
15582 { # XML
15583 $VTABLES .= " <vtable>\n";
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015584 foreach my $Index (sort {int($a)<=>int($b)} (keys(%Entries)))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015585 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015586 $VTABLES .= " <entry offset=\"".$Index."\">\n";
Andrey Ponomarenko5c09ef32012-06-14 18:17:33 +040015587 $VTABLES .= " <old>".xmlSpecChars($Entries{$Index}{"E1"})."</old>\n";
15588 $VTABLES .= " <new>".xmlSpecChars($Entries{$Index}{"E2"})."</new>\n";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015589 $VTABLES .= " </entry>\n";
15590 }
15591 $VTABLES .= " </vtable>\n\n";
15592 }
15593 else
15594 { # HTML
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015595 $VTABLES .= "<table class='vtable'>";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015596 $VTABLES .= "<tr><th width='2%'>Offset</th>";
15597 $VTABLES .= "<th width='45%'>Virtual Table (Old) - ".(keys(%{$Type1{"VTable"}}))." entries</th>";
15598 $VTABLES .= "<th>Virtual Table (New) - ".(keys(%{$Type2{"VTable"}}))." entries</th></tr>";
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015599 foreach my $Index (sort {int($a)<=>int($b)} (keys(%Entries)))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015600 {
15601 my ($Color1, $Color2) = ("", "");
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015602 if($Entries{$Index}{"E1"} ne $Entries{$Index}{"E2"})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015603 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015604 if($Entries{$Index}{"E1"})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015605 {
Andrey Ponomarenko16934472012-03-29 15:37:04 +040015606 $Color1 = " class='failed'";
15607 $Color2 = " class='failed'";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015608 }
15609 else {
Andrey Ponomarenko16934472012-03-29 15:37:04 +040015610 $Color2 = " class='warning'";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015611 }
15612 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015613 $VTABLES .= "<tr><th>".$Index."</th>\n";
15614 $VTABLES .= "<td$Color1>".htmlSpecChars($Entries{$Index}{"E1"})."</td>\n";
15615 $VTABLES .= "<td$Color2>".htmlSpecChars($Entries{$Index}{"E2"})."</td></tr>\n";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015616 }
15617 $VTABLES .= "</table><br/>\n";
15618 $VTABLES = $ContentDivStart.$VTABLES.$ContentDivEnd;
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015619 $VTABLES = $ContentSpanStart_Info."[+] show v-table (old and new)".$ContentSpanEnd."<br/>\n".$VTABLES;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015620 }
15621 return $VTABLES;
15622 }
15623 }
15624 return "";
15625}
15626
15627sub simpleVEntry($)
15628{
15629 my $VEntry = $_[0];
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040015630 if(not defined $VEntry
15631 or $VEntry eq "") {
15632 return "";
15633 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015634 $VEntry=~s/\A(.+)::(_ZThn.+)\Z/$2/; # thunks
15635 $VEntry=~s/_ZTI\w+/typeinfo/g; # typeinfo
15636 if($VEntry=~/\A_ZThn.+\Z/) {
15637 $VEntry = "non-virtual thunk";
15638 }
15639 $VEntry=~s/\A\(int \(\*\)\(...\)\)([^\(\d])/$1/i;
15640 # support for old GCC versions
15641 $VEntry=~s/\A0u\Z/(int (*)(...))0/;
15642 $VEntry=~s/\A4294967268u\Z/(int (*)(...))-0x000000004/;
15643 $VEntry=~s/\A&_Z\Z/& _Z/;
15644 # templates
15645 if($VEntry=~s/ \[with (\w+) = (.+?)(, [^=]+ = .+|])\Z//g)
15646 { # std::basic_streambuf<_CharT, _Traits>::imbue [with _CharT = char, _Traits = std::char_traits<char>]
15647 # become std::basic_streambuf<char, ...>::imbue
15648 my ($Pname, $Pval) = ($1, $2);
15649 if($Pname eq "_CharT" and $VEntry=~/\Astd::/)
15650 { # stdc++ typedefs
15651 $VEntry=~s/<$Pname(, [^<>]+|)>/<$Pval>/g;
15652 # FIXME: simplify names using stdcxx typedefs (StdCxxTypedef)
15653 # The typedef info should be added to ABI dumps
15654 }
15655 else
15656 {
15657 $VEntry=~s/<$Pname>/<$Pval>/g;
15658 $VEntry=~s/<$Pname, [^<>]+>/<$Pval, ...>/g;
15659 }
15660 }
15661 $VEntry=~s/([^:]+)::\~([^:]+)\Z/~$1/; # destructors
15662 return $VEntry;
15663}
15664
Andrey Ponomarenko85043792012-05-14 16:48:07 +040015665sub getAffectedSymbols($$$$)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015666{
Andrey Ponomarenko85043792012-05-14 16:48:07 +040015667 my ($Level, $Target_TypeName, $Kinds_Locations, $Syms) = @_;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015668 my $LIMIT = 1000;
Andrey Ponomarenko85043792012-05-14 16:48:07 +040015669 if($#{$Syms}>=10000)
15670 { # reduce size of the report
15671 $LIMIT = 10;
15672 }
15673 my %SProblems = ();
15674 foreach my $Symbol (@{$Syms})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015675 {
Andrey Ponomarenko85043792012-05-14 16:48:07 +040015676 if(keys(%SProblems)>$LIMIT) {
15677 last;
15678 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015679 if(($Symbol=~/C2E|D2E|D0E/))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015680 { # duplicated problems for C2 constructors, D2 and D0 destructors
15681 next;
15682 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015683 my ($SN, $SS, $SV) = separate_symbol($Symbol);
15684 if($Level eq "Source")
15685 { # remove symbol version
15686 $Symbol=$SN;
15687 }
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040015688 my ($MinPath_Length, $ProblemLocation_Last) = (-1, "");
15689 my $Severity_Max = 0;
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015690 my $Signature = get_Signature($Symbol, 1);
15691 foreach my $Kind (keys(%{$CompatProblems{$Level}{$Symbol}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015692 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015693 foreach my $Location (keys(%{$CompatProblems{$Level}{$Symbol}{$Kind}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015694 {
15695 if(not defined $Kinds_Locations->{$Kind}
15696 or not $Kinds_Locations->{$Kind}{$Location}) {
15697 next;
15698 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015699 if($SV and defined $CompatProblems{$Level}{$SN}
15700 and defined $CompatProblems{$Level}{$SN}{$Kind}{$Location})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015701 { # duplicated problems for versioned symbols
15702 next;
15703 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015704 my $Type_Name = $CompatProblems{$Level}{$Symbol}{$Kind}{$Location}{"Type_Name"};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015705 next if($Type_Name ne $Target_TypeName);
15706
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015707 my $Position = $CompatProblems{$Level}{$Symbol}{$Kind}{$Location}{"Param_Pos"};
15708 my $Param_Name = $CompatProblems{$Level}{$Symbol}{$Kind}{$Location}{"Param_Name"};
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040015709 my $Severity = getProblemSeverity($Level, $Kind);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015710 my $Path_Length = 0;
15711 my $ProblemLocation = $Location;
15712 if($Type_Name) {
15713 $ProblemLocation=~s/->\Q$Type_Name\E\Z//g;
15714 }
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040015715 while($ProblemLocation=~/\-\>/g) {
15716 $Path_Length += 1;
15717 }
15718 if($MinPath_Length==-1 or ($Path_Length<=$MinPath_Length and $Severity_Val{$Severity}>$Severity_Max)
15719 or (cmp_locations($ProblemLocation, $ProblemLocation_Last) and $Severity_Val{$Severity}==$Severity_Max))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015720 {
15721 $MinPath_Length = $Path_Length;
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040015722 $Severity_Max = $Severity_Val{$Severity};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015723 $ProblemLocation_Last = $ProblemLocation;
Andrey Ponomarenko85043792012-05-14 16:48:07 +040015724 %{$SProblems{$Symbol}} = (
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040015725 "Descr"=>getAffectDescription($Level, $Symbol, $Kind, $Location),
15726 "Severity_Max"=>$Severity_Max,
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015727 "Signature"=>$Signature,
15728 "Position"=>$Position,
15729 "Param_Name"=>$Param_Name,
15730 "Location"=>$Location
15731 );
15732 }
15733 }
15734 }
15735 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +040015736 my @Symbols = keys(%SProblems);
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015737 @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 +040015738 @Symbols = sort {$SProblems{$b}{"Severity_Max"}<=>$SProblems{$a}{"Severity_Max"}} @Symbols;
15739 if($#Symbols+1>$LIMIT)
15740 { # remove last element
15741 pop(@Symbols);
15742 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015743 my $Affected = "";
15744 if($ReportFormat eq "xml")
15745 { # XML
15746 $Affected .= " <affected>\n";
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015747 foreach my $Symbol (@Symbols)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015748 {
Andrey Ponomarenko85043792012-05-14 16:48:07 +040015749 my $Param_Name = $SProblems{$Symbol}{"Param_Name"};
15750 my $Description = $SProblems{$Symbol}{"Descr"};
15751 my $Location = $SProblems{$Symbol}{"Location"};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015752 my $Target = "";
15753 if($Param_Name) {
15754 $Target = " affected=\"param\" param_name=\"$Param_Name\"";
15755 }
15756 elsif($Location=~/\Aretval(\-|\Z)/i) {
15757 $Target = " affected=\"retval\"";
15758 }
15759 elsif($Location=~/\Athis(\-|\Z)/i) {
15760 $Target = " affected=\"this\"";
15761 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015762 $Affected .= " <symbol$Target name=\"$Symbol\">\n";
Andrey Ponomarenko5c09ef32012-06-14 18:17:33 +040015763 $Affected .= " <comment>".xmlSpecChars($Description)."</comment>\n";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015764 $Affected .= " </symbol>\n";
15765 }
15766 $Affected .= " </affected>\n";
15767 }
15768 else
15769 { # HTML
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015770 foreach my $Symbol (@Symbols)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015771 {
Andrey Ponomarenko85043792012-05-14 16:48:07 +040015772 my $Description = $SProblems{$Symbol}{"Descr"};
15773 my $Signature = $SProblems{$Symbol}{"Signature"};
15774 my $Pos = $SProblems{$Symbol}{"Position"};
Andrey Ponomarenkoa01311b2012-06-08 17:20:02 +040015775 $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 +040015776 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +040015777 if(keys(%SProblems)>$LIMIT) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015778 $Affected .= "and others ...<br/>";
15779 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +040015780 $Affected = "<div class='affected'>".$Affected."</div>";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015781 if($Affected)
15782 {
15783 $Affected = $ContentDivStart.$Affected.$ContentDivEnd;
Andrey Ponomarenko85043792012-05-14 16:48:07 +040015784 $Affected = $ContentSpanStart_Affected."[+] affected symbols (".(keys(%SProblems)>$LIMIT?">".$LIMIT:keys(%SProblems)).")".$ContentSpanEnd.$Affected;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015785 }
15786 }
15787 return $Affected;
15788}
15789
15790sub cmp_locations($$)
15791{
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040015792 my ($L1, $L2) = @_;
15793 if($L2=~/\b(retval|this)\b/
15794 and $L1!~/\b(retval|this)\b/ and $L1!~/\-\>/) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015795 return 1;
15796 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040015797 if($L2=~/\b(retval|this)\b/ and $L2=~/\-\>/
15798 and $L1!~/\b(retval|this)\b/ and $L1=~/\-\>/) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015799 return 1;
15800 }
15801 return 0;
15802}
15803
15804sub getAffectDescription($$$$)
15805{
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015806 my ($Level, $Symbol, $Kind, $Location) = @_;
15807 my %Problem = %{$CompatProblems{$Level}{$Symbol}{$Kind}{$Location}};
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040015808 my $PPos = showPos($Problem{"Param_Pos"});
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015809 my @Sentence = ();
15810 $Location=~s/\A(.*)\-\>.+?\Z/$1/;
15811 if($Kind eq "Overridden_Virtual_Method"
15812 or $Kind eq "Overridden_Virtual_Method_B") {
15813 push(@Sentence, "The method '".$Problem{"New_Value"}."' will be called instead of this method.");
15814 }
15815 elsif($CompatRules{$Level}{$Kind}{"Kind"} eq "Types")
15816 {
15817 if($Location eq "this" or $Kind=~/(\A|_)Virtual(_|\Z)/)
15818 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015819 my $METHOD_TYPE = $CompleteSignature{1}{$Symbol}{"Constructor"}?"constructor":"method";
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040015820 my $ClassName = $TypeInfo{1}{$CompleteSignature{1}{$Symbol}{"Class"}}{"Name"};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015821 if($ClassName eq $Problem{"Type_Name"}) {
15822 push(@Sentence, "This $METHOD_TYPE is from \'".$Problem{"Type_Name"}."\' class.");
15823 }
15824 else {
15825 push(@Sentence, "This $METHOD_TYPE is from derived class \'".$ClassName."\'.");
15826 }
15827 }
15828 else
15829 {
15830 if($Location=~/retval/)
15831 { # return value
15832 if($Location=~/\-\>/) {
15833 push(@Sentence, "Field \'".$Location."\' in return value");
15834 }
15835 else {
15836 push(@Sentence, "Return value");
15837 }
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040015838 if(my $Init = $Problem{"InitialType_Type"})
15839 {
15840 if($Init eq "Pointer") {
15841 push(@Sentence, "(pointer)");
15842 }
15843 elsif($Init eq "Ref") {
15844 push(@Sentence, "(reference)");
15845 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015846 }
15847 }
15848 elsif($Location=~/this/)
15849 { # "this" pointer
15850 if($Location=~/\-\>/) {
15851 push(@Sentence, "Field \'".$Location."\' in the object of this method");
15852 }
15853 else {
15854 push(@Sentence, "\'this\' pointer");
15855 }
15856 }
15857 else
15858 { # parameters
15859 if($Location=~/\-\>/) {
15860 push(@Sentence, "Field \'".$Location."\' in $PPos parameter");
15861 }
15862 else {
15863 push(@Sentence, "$PPos parameter");
15864 }
15865 if($Problem{"Param_Name"}) {
15866 push(@Sentence, "\'".$Problem{"Param_Name"}."\'");
15867 }
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040015868 if(my $Init = $Problem{"InitialType_Type"})
15869 {
15870 if($Init eq "Pointer") {
15871 push(@Sentence, "(pointer)");
15872 }
15873 elsif($Init eq "Ref") {
15874 push(@Sentence, "(reference)");
15875 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015876 }
15877 }
15878 if($Location eq "this") {
15879 push(@Sentence, "has base type \'".$Problem{"Type_Name"}."\'.");
15880 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040015881 elsif(defined $Problem{"Start_Type_Name"}
15882 and $Problem{"Start_Type_Name"} eq $Problem{"Type_Name"}) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015883 push(@Sentence, "has type \'".$Problem{"Type_Name"}."\'.");
15884 }
15885 else {
15886 push(@Sentence, "has base type \'".$Problem{"Type_Name"}."\'.");
15887 }
15888 }
15889 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040015890 if($ExtendedSymbols{$Symbol}) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015891 push(@Sentence, " This is a symbol from an artificial external library that may use the \'$TargetLibraryName\' library and change its ABI after recompiling.");
15892 }
15893 return join(" ", @Sentence);
15894}
15895
15896sub get_XmlSign($$)
15897{
15898 my ($Symbol, $LibVersion) = @_;
15899 my $Info = $CompleteSignature{$LibVersion}{$Symbol};
15900 my $Report = "";
15901 foreach my $Pos (sort {int($a)<=>int($b)} keys(%{$Info->{"Param"}}))
15902 {
15903 my $Name = $Info->{"Param"}{$Pos}{"name"};
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040015904 my $Type = $Info->{"Param"}{$Pos}{"type"};
15905 my $TypeName = $TypeInfo{$LibVersion}{$Type}{"Name"};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015906 foreach my $Typedef (keys(%ChangedTypedef))
15907 {
15908 my $Base = $Typedef_BaseName{$LibVersion}{$Typedef};
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040015909 $TypeName=~s/\b\Q$Typedef\E\b/$Base/g;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015910 }
15911 $Report .= " <param pos=\"$Pos\">\n";
15912 $Report .= " <name>".$Name."</name>\n";
Andrey Ponomarenko5c09ef32012-06-14 18:17:33 +040015913 $Report .= " <type>".xmlSpecChars($TypeName)."</type>\n";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015914 $Report .= " </param>\n";
15915 }
15916 if(my $Return = $Info->{"Return"})
15917 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040015918 my $RTName = $TypeInfo{$LibVersion}{$Return}{"Name"};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015919 $Report .= " <retval>\n";
Andrey Ponomarenko5c09ef32012-06-14 18:17:33 +040015920 $Report .= " <type>".xmlSpecChars($RTName)."</type>\n";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015921 $Report .= " </retval>\n";
15922 }
15923 return $Report;
15924}
15925
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015926sub get_Report_SymbolsInfo($)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015927{
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015928 my $Level = $_[0];
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015929 my $Report = "<symbols_info>\n";
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015930 foreach my $Symbol (sort keys(%{$CompatProblems{$Level}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015931 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015932 my ($SN, $SS, $SV) = separate_symbol($Symbol);
15933 if($SV and defined $CompatProblems{$Level}{$SN}) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015934 next;
15935 }
15936 $Report .= " <symbol name=\"$Symbol\">\n";
15937 my ($S1, $P1, $S2, $P2) = ();
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015938 if(not $AddedInt{$Level}{$Symbol})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015939 {
15940 if(defined $CompleteSignature{1}{$Symbol}
15941 and defined $CompleteSignature{1}{$Symbol}{"Header"})
15942 {
15943 $P1 = get_XmlSign($Symbol, 1);
15944 $S1 = get_Signature($Symbol, 1);
15945 }
15946 elsif($Symbol=~/\A(_Z|\?)/) {
15947 $S1 = $tr_name{$Symbol};
15948 }
15949 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015950 if(not $RemovedInt{$Level}{$Symbol})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015951 {
15952 if(defined $CompleteSignature{2}{$Symbol}
15953 and defined $CompleteSignature{2}{$Symbol}{"Header"})
15954 {
15955 $P2 = get_XmlSign($Symbol, 2);
15956 $S2 = get_Signature($Symbol, 2);
15957 }
15958 elsif($Symbol=~/\A(_Z|\?)/) {
15959 $S2 = $tr_name{$Symbol};
15960 }
15961 }
15962 if($S1)
15963 {
Andrey Ponomarenko5c09ef32012-06-14 18:17:33 +040015964 $Report .= " <old signature=\"".xmlSpecChars($S1)."\">\n";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015965 $Report .= $P1;
15966 $Report .= " </old>\n";
15967 }
15968 if($S2 and $S2 ne $S1)
15969 {
Andrey Ponomarenko5c09ef32012-06-14 18:17:33 +040015970 $Report .= " <new signature=\"".xmlSpecChars($S2)."\">\n";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015971 $Report .= $P2;
15972 $Report .= " </new>\n";
15973 }
15974 $Report .= " </symbol>\n";
15975 }
15976 $Report .= "</symbols_info>\n";
15977 return $Report;
15978}
15979
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015980sub writeReport($$)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015981{
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015982 my ($Level, $Report) = @_;
15983 if($ReportFormat eq "xml") {
15984 $Report = "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n".$Report;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015985 }
15986 if($StdOut)
15987 { # --stdout option
15988 print STDOUT $Report;
15989 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015990 else
15991 {
15992 my $RPath = getReportPath($Level);
Andrey Ponomarenko85043792012-05-14 16:48:07 +040015993 mkpath(get_dirname($RPath));
15994
15995 open(REPORT, ">", $RPath) || die ("can't open file \'$RPath\': $!\n");
15996 print REPORT $Report;
15997 close(REPORT);
15998
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040015999 if($Browse or $OpenReport)
16000 { # open in browser
16001 openReport($RPath);
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040016002 if($JoinReport or $DoubleReport)
16003 {
16004 if($Level eq "Binary")
16005 { # wait to open a browser
16006 sleep(1);
16007 }
16008 }
16009 }
16010 }
16011}
16012
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040016013sub openReport($)
16014{
16015 my $Path = $_[0];
16016 my $Cmd = "";
16017 if($Browse)
16018 { # user-defined browser
Andrey Ponomarenkoa01311b2012-06-08 17:20:02 +040016019 $Cmd = $Browse." \"$Path\"";
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040016020 }
16021 if(not $Cmd)
16022 { # default browser
16023 if($OSgroup eq "macos") {
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +040016024 $Cmd = "open \"$Path\"";
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040016025 }
16026 elsif($OSgroup eq "windows") {
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +040016027 $Cmd = "start ".path_format($Path, $OSgroup);
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040016028 }
16029 else
16030 { # linux, freebsd, solaris
16031 my @Browsers = (
16032 "x-www-browser",
16033 "sensible-browser",
16034 "firefox",
16035 "opera",
16036 "xdg-open",
16037 "lynx",
16038 "links"
16039 );
16040 foreach my $Br (@Browsers)
16041 {
16042 if($Br = get_CmdPath($Br))
16043 {
Andrey Ponomarenkoa01311b2012-06-08 17:20:02 +040016044 $Cmd = $Br." \"$Path\"";
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040016045 last;
16046 }
16047 }
16048 }
16049 }
16050 if($Cmd)
16051 {
16052 if($Debug) {
16053 printMsg("INFO", "running $Cmd");
16054 }
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +040016055 if($OSgroup ne "windows"
16056 and $OSgroup ne "macos")
16057 {
16058 if($Cmd!~/lynx|links/) {
16059 $Cmd .= " >\"$TMP_DIR/null\" 2>&1 &";
16060 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040016061 }
16062 system($Cmd);
16063 }
16064 else {
16065 printMsg("ERROR", "cannot open report in browser");
16066 }
16067}
16068
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040016069sub getReport($)
16070{
16071 my $Level = $_[0];
16072 if($ReportFormat eq "xml")
16073 { # XML
16074
16075 if($Level eq "Join")
16076 {
16077 my $Report = "<reports>\n";
16078 $Report .= getReport("Binary");
16079 $Report .= getReport("Source");
16080 $Report .= "</reports>\n";
16081 return $Report;
16082 }
16083 else
16084 {
16085 my $Report = "<report kind=\"".lc($Level)."\" version=\"$XML_REPORT_VERSION\">\n\n";
16086 my ($Summary, $MetaData) = get_Summary($Level);
16087 $Report .= $Summary."\n";
16088 $Report .= get_Report_Added($Level).get_Report_Removed($Level);
16089 $Report .= get_Report_Problems("High", $Level).get_Report_Problems("Medium", $Level).get_Report_Problems("Low", $Level).get_Report_Problems("Safe", $Level);
16090 $Report .= get_Report_SymbolsInfo($Level);
16091 $Report .= "</report>\n";
16092 return $Report;
16093 }
16094 }
16095 else
16096 { # HTML
16097 my $CssStyles = readModule("Styles", "Report.css");
16098 my $JScripts = readModule("Scripts", "Sections.js");
16099 if($Level eq "Join")
16100 {
16101 $CssStyles .= "\n".readModule("Styles", "Tabs.css");
16102 $JScripts .= "\n".readModule("Scripts", "Tabs.js");
Andrey Ponomarenkob8d203d2012-05-25 18:11:07 +040016103 my $Title = $TargetLibraryFName.": ".$Descriptor{1}{"Version"}." to ".$Descriptor{2}{"Version"}." compatibility report";
16104 my $Keywords = $TargetLibraryFName.", compatibility, API, report";
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040016105 my $Description = "Compatibility report for the $TargetLibraryFName $TargetComponent between ".$Descriptor{1}{"Version"}." and ".$Descriptor{2}{"Version"}." versions";
16106 my ($BSummary, $BMetaData) = get_Summary("Binary");
16107 my ($SSummary, $SMetaData) = get_Summary("Source");
16108 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>";
16109 $Report .= get_Report_Header("Join")."
16110 <br/><div class='tabset'>
Andrey Ponomarenko16934472012-03-29 15:37:04 +040016111 <a id='BinaryID' href='#BinaryTab' class='tab active'>Binary<br/>Compatibility</a>
16112 <a id='SourceID' href='#SourceTab' style='margin-left:3px' class='tab disabled'>Source<br/>Compatibility</a>
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040016113 </div>";
16114 $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>";
16115 $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 +040016116 $Report .= getReportFooter($TargetLibraryFName, not $JoinReport);
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040016117 $Report .= "\n<div style='height:999px;'></div>\n</body></html>";
16118 return $Report;
16119 }
16120 else
16121 {
16122 my ($Summary, $MetaData) = get_Summary($Level);
Andrey Ponomarenkob8d203d2012-05-25 18:11:07 +040016123 my $Title = $TargetLibraryFName.": ".$Descriptor{1}{"Version"}." to ".$Descriptor{2}{"Version"}." ".lc($Level)." compatibility report";
16124 my $Keywords = $TargetLibraryFName.", ".lc($Level)." compatibility, API, report";
16125 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 +040016126 if($Level eq "Binary")
16127 {
16128 if(getArch(1) eq getArch(2)
16129 and getArch(1) ne "unknown") {
16130 $Description .= " on ".showArch(getArch(1));
16131 }
16132 }
16133 my $Report = "<!-\- $MetaData -\->\n".composeHTML_Head($Title, $Keywords, $Description, $CssStyles, $JScripts)."\n<body>\n<div><a name='Top'></a>\n";
16134 $Report .= get_Report_Header($Level)."\n".$Summary."\n";
16135 $Report .= get_Report_Added($Level).get_Report_Removed($Level);
16136 $Report .= get_Report_Problems("High", $Level).get_Report_Problems("Medium", $Level).get_Report_Problems("Low", $Level).get_Report_Problems("Safe", $Level);
16137 $Report .= get_SourceInfo();
16138 $Report .= "</div>\n<br/><br/><br/><hr/>\n";
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040016139 $Report .= getReportFooter($TargetLibraryFName, not $JoinReport);
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040016140 $Report .= "\n<div style='height:999px;'></div>\n</body></html>";
16141 return $Report;
16142 }
16143 }
16144}
16145
Andrey Ponomarenko16934472012-03-29 15:37:04 +040016146sub getLegend()
16147{
16148 return "<br/>
16149<table class='summary'>
16150<tr>
16151 <td class='new'>added</td>
16152 <td class='passed'>compatible</td>
16153</tr>
16154<tr>
16155 <td class='warning'>warning</td>
16156 <td class='failed'>incompatible</td>
16157</tr></table>\n";
16158}
16159
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040016160sub createReport()
16161{
16162 if($JoinReport)
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040016163 { # --stdout
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040016164 writeReport("Join", getReport("Join"));
16165 }
16166 elsif($DoubleReport)
16167 { # default
16168 writeReport("Binary", getReport("Binary"));
16169 writeReport("Source", getReport("Source"));
16170 }
16171 elsif($BinaryOnly)
16172 { # --binary
16173 writeReport("Binary", getReport("Binary"));
16174 }
16175 elsif($SourceOnly)
16176 { # --source
16177 writeReport("Source", getReport("Source"));
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040016178 }
16179}
16180
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040016181sub getReportFooter($$)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040016182{
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040016183 my ($LibName, $Wide) = @_;
16184 my $FooterStyle = $Wide?"width:99%":"width:97%;padding-top:3px";
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040016185 my $Footer = "<div style='$FooterStyle;font-size:11px;' align='right'><i>Generated on ".(localtime time); # report date
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040016186 $Footer .= " for <span style='font-weight:bold'>$LibName</span>"; # tested library/system name
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040016187 $Footer .= " by <a href='".$HomePage{"Wiki"}."'>ABI Compliance Checker</a>"; # tool name
16188 my $ToolSummary = "<br/>A tool for checking backward compatibility of a C/C++ library API&#160;&#160;";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040016189 $Footer .= " $TOOL_VERSION &#160;$ToolSummary</i></div>"; # tool version
16190 return $Footer;
16191}
16192
16193sub get_Report_Problems($$)
16194{
16195 my ($Priority, $Level) = @_;
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040016196 my $Report = get_Report_TypeProblems($Priority, $Level);
Andrey Ponomarenko16934472012-03-29 15:37:04 +040016197 if(my $SProblems = get_Report_SymbolProblems($Priority, $Level)) {
16198 $Report .= $SProblems;
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040016199 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040016200 if($Priority eq "Low")
16201 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040016202 $Report .= get_Report_ChangedConstants($Level);
Andrey Ponomarenko82bc2572012-11-14 13:55:30 +040016203 if($ReportFormat eq "html")
16204 {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040016205 if($CheckImpl and $Level eq "Binary") {
16206 $Report .= get_Report_Impl();
16207 }
16208 }
16209 }
16210 if($ReportFormat eq "html")
16211 {
16212 if($Report)
16213 { # add anchor
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040016214 if($JoinReport)
16215 {
16216 if($Priority eq "Safe") {
16217 $Report = "<a name=\'Other_".$Level."_Changes\'></a>".$Report;
16218 }
16219 else {
16220 $Report = "<a name=\'".$Priority."_Risk_".$Level."_Problems\'></a>".$Report;
16221 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040016222 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040016223 else
16224 {
16225 if($Priority eq "Safe") {
16226 $Report = "<a name=\'Other_Changes\'></a>".$Report;
16227 }
16228 else {
16229 $Report = "<a name=\'".$Priority."_Risk_Problems\'></a>".$Report;
16230 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040016231 }
16232 }
16233 }
16234 return $Report;
16235}
16236
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040016237sub composeHTML_Head($$$$$)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040016238{
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040016239 my ($Title, $Keywords, $Description, $Styles, $Scripts) = @_;
16240 return "<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.0 Transitional//EN\" \"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd\">
16241 <html xmlns=\"http://www.w3.org/1999/xhtml\" xml:lang=\"en\" lang=\"en\">
16242 <head>
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040016243 <meta http-equiv=\"Content-Type\" content=\"text/html; charset=utf-8\" />
16244 <meta name=\"keywords\" content=\"$Keywords\" />
16245 <meta name=\"description\" content=\"$Description\" />
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040016246 <title>
16247 $Title
16248 </title>
16249 <style type=\"text/css\">
16250 $Styles
16251 </style>
16252 <script type=\"text/javascript\" language=\"JavaScript\">
16253 <!--
16254 $Scripts
16255 -->
16256 </script>
16257 </head>";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040016258}
16259
16260sub insertIDs($)
16261{
16262 my $Text = $_[0];
16263 while($Text=~/CONTENT_ID/)
16264 {
16265 if(int($Content_Counter)%2) {
16266 $ContentID -= 1;
16267 }
16268 $Text=~s/CONTENT_ID/c_$ContentID/;
16269 $ContentID += 1;
16270 $Content_Counter += 1;
16271 }
16272 return $Text;
16273}
16274
16275sub checkPreprocessedUnit($)
16276{
16277 my $Path = $_[0];
Andrey Ponomarenkoa01311b2012-06-08 17:20:02 +040016278 my ($CurHeader, $CurHeaderName) = ("", "");
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040016279 open(PREPROC, $Path) || die ("can't open file \'$Path\': $!\n");
Andrey Ponomarenkoa01311b2012-06-08 17:20:02 +040016280 while(my $Line = <PREPROC>)
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040016281 { # detecting public and private constants
Andrey Ponomarenkoa01311b2012-06-08 17:20:02 +040016282
16283 if(substr($Line, 0, 1) eq "#")
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040016284 {
Andrey Ponomarenkoa01311b2012-06-08 17:20:02 +040016285 chomp($Line);
16286 if($Line=~/\A\#\s+\d+\s+\"(.+)\"/)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040016287 {
Andrey Ponomarenkoa01311b2012-06-08 17:20:02 +040016288 $CurHeader = path_format($1, $OSgroup);
16289 $CurHeaderName = get_filename($CurHeader);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040016290 }
Andrey Ponomarenko4b077f82012-12-04 16:04:36 +040016291 if(not $ExtraInfo)
16292 {
16293 if(not $Include_Neighbors{$Version}{$CurHeaderName}
16294 and not $Registered_Headers{$Version}{$CurHeader})
16295 { # not a target
16296 next;
16297 }
16298 if(not is_target_header($CurHeaderName, 1)
16299 and not is_target_header($CurHeaderName, 2))
16300 { # user-defined header
16301 next;
16302 }
Andrey Ponomarenkoa01311b2012-06-08 17:20:02 +040016303 }
Andrey Ponomarenko4b077f82012-12-04 16:04:36 +040016304
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040016305 if($Line=~/\A\#\s*define\s+(\w+)\s+(.+)\s*\Z/)
Andrey Ponomarenkoa01311b2012-06-08 17:20:02 +040016306 {
16307 my ($Name, $Value) = ($1, $2);
16308 if(not $Constants{$Version}{$Name}{"Access"})
16309 {
16310 $Constants{$Version}{$Name}{"Access"} = "public";
16311 $Constants{$Version}{$Name}{"Value"} = $Value;
16312 $Constants{$Version}{$Name}{"Header"} = $CurHeaderName;
16313 }
16314 }
16315 elsif($Line=~/\A\#[ \t]*undef[ \t]+([_A-Z]+)[ \t]*/) {
16316 $Constants{$Version}{$1}{"Access"} = "private";
16317 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040016318 }
16319 }
16320 close(PREPROC);
16321 foreach my $Constant (keys(%{$Constants{$Version}}))
16322 {
Andrey Ponomarenkoa01311b2012-06-08 17:20:02 +040016323 if($Constants{$Version}{$Constant}{"Access"} eq "private"
16324 or $Constant=~/_h\Z/i
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040016325 or isBuiltIn($Constants{$Version}{$Constant}{"Header"}))
16326 { # skip private constants
Andrey Ponomarenko4b077f82012-12-04 16:04:36 +040016327 if($ExtraInfo)
16328 { # save
16329 delete($Constants{$Version}{$Constant}{"Access"});
16330 }
16331 else {
16332 delete($Constants{$Version}{$Constant});
16333 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040016334 }
16335 else {
16336 delete($Constants{$Version}{$Constant}{"Access"});
16337 }
16338 }
Andrey Ponomarenkoa01311b2012-06-08 17:20:02 +040016339 if($Debug)
16340 {
16341 mkpath($DEBUG_PATH{$Version});
16342 copy($Path, $DEBUG_PATH{$Version}."/preprocessor.txt");
16343 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040016344}
16345
Andrey Ponomarenko16934472012-03-29 15:37:04 +040016346sub uncoverConstant($$)
16347{
16348 my ($LibVersion, $Constant) = @_;
16349 return "" if(not $LibVersion or not $Constant);
16350 return $Constant if(isCyclical(\@RecurConstant, $Constant));
16351 if(defined $Cache{"uncoverConstant"}{$LibVersion}{$Constant}) {
16352 return $Cache{"uncoverConstant"}{$LibVersion}{$Constant};
16353 }
16354 my $Value = $Constants{$LibVersion}{$Constant}{"Value"};
16355 if(defined $Value)
16356 {
16357 if($Value=~/\A[A-Z0-9_]+\Z/ and $Value=~/[A-Z]/)
16358 {
16359 push(@RecurConstant, $Constant);
16360 my $Uncovered = uncoverConstant($LibVersion, $Value);
16361 if($Uncovered ne "") {
16362 $Value = $Uncovered;
16363 }
16364 pop(@RecurConstant);
16365 }
16366 # FIXME: uncover $Value using all the enum constants
16367 # USECASE: change of define NC_LONG from NC_INT (enum value) to NC_INT (define)
16368 return ($Cache{"uncoverConstant"}{$LibVersion}{$Constant} = $Value);
16369 }
16370 return ($Cache{"uncoverConstant"}{$LibVersion}{$Constant} = "");
16371}
16372
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040016373my %IgnoreConstant = map {$_=>1} (
16374 "VERSION",
16375 "VERSIONCODE",
16376 "VERNUM",
16377 "VERS_INFO",
16378 "PATCHLEVEL",
16379 "INSTALLPREFIX",
16380 "VBUILD",
16381 "VPATCH",
16382 "VMINOR",
16383 "BUILD_STRING",
16384 "BUILD_TIME",
16385 "PACKAGE_STRING",
16386 "PRODUCTION",
16387 "CONFIGURE_COMMAND",
16388 "INSTALLDIR",
16389 "BINDIR",
16390 "CONFIG_FILE_PATH",
16391 "DATADIR",
16392 "EXTENSION_DIR",
16393 "INCLUDE_PATH",
16394 "LIBDIR",
16395 "LOCALSTATEDIR",
16396 "SBINDIR",
16397 "SYSCONFDIR",
16398 "RELEASE",
16399 "SOURCE_ID",
16400 "SUBMINOR",
16401 "MINOR",
16402 "MINNOR",
16403 "MINORVERSION",
16404 "MAJOR",
16405 "MAJORVERSION",
16406 "MICRO",
16407 "MICROVERSION",
16408 "BINARY_AGE",
16409 "INTERFACE_AGE",
16410 "CORE_ABI",
16411 "PATCH",
16412 "COPYRIGHT",
16413 "TIMESTAMP",
16414 "REVISION",
16415 "PACKAGE_TAG",
16416 "PACKAGEDATE",
16417 "NUMVERSION",
16418 "Release",
16419 "Version"
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040016420);
16421
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040016422sub mergeConstants($)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040016423{
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040016424 my $Level = $_[0];
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040016425 foreach my $Constant (keys(%{$Constants{1}}))
16426 {
16427 if($SkipConstants{1}{$Constant})
16428 { # skipped by the user
16429 next;
16430 }
Andrey Ponomarenko16934472012-03-29 15:37:04 +040016431 if(not defined $Constants{2}{$Constant}{"Value"}
16432 or $Constants{2}{$Constant}{"Value"} eq "")
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040016433 { # empty value
16434 next;
16435 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +040016436 my $Header = $Constants{1}{$Constant}{"Header"};
16437 if(not is_target_header($Header, 1)
16438 and not is_target_header($Header, 2))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040016439 { # user-defined header
16440 next;
16441 }
16442 my ($Old_Value, $New_Value, $Old_Value_Pure, $New_Value_Pure);
Andrey Ponomarenko16934472012-03-29 15:37:04 +040016443 $Old_Value = $Old_Value_Pure = uncoverConstant(1, $Constant);
16444 $New_Value = $New_Value_Pure = uncoverConstant(2, $Constant);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040016445 $Old_Value_Pure=~s/(\W)\s+/$1/g;
16446 $Old_Value_Pure=~s/\s+(\W)/$1/g;
16447 $New_Value_Pure=~s/(\W)\s+/$1/g;
16448 $New_Value_Pure=~s/\s+(\W)/$1/g;
16449 next if($New_Value_Pure eq "" or $Old_Value_Pure eq "");
16450 if($New_Value_Pure ne $Old_Value_Pure)
16451 { # different values
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040016452 if($Level eq "Binary")
16453 {
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040016454 foreach (keys(%IgnoreConstant))
16455 {
16456 if($Constant=~/(\A|_)$_(_|\Z)/)
16457 { # ignore library version
16458 next;
16459 }
16460 if(/\A[A-Z].*[a-z]\Z/)
16461 {
16462 if($Constant=~/(\A|[a-z])$_([A-Z]|\Z)/)
16463 { # ignore library version
16464 next;
16465 }
16466 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040016467 }
16468 if($Constant=~/(\A|_)(lib|open|)$TargetLibraryShortName(_|)(VERSION|VER|DATE|API|PREFIX)(_|\Z)/i)
16469 { # ignore library version
16470 next;
16471 }
16472 if($Old_Value=~/\A('|"|)[\/\\]\w+([\/\\]|:|('|"|)\Z)/ or $Old_Value=~/[\/\\]\w+[\/\\]\w+/)
16473 { # ignoring path defines:
Andrey Ponomarenko85043792012-05-14 16:48:07 +040016474 # /lib64:/usr/lib64:/lib:/usr/lib:/usr/X11R6/lib/Xaw3d ...
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040016475 next;
16476 }
16477 if($Old_Value=~/\A\(*[a-z_]+(\s+|\|)/i)
16478 { # ignore source defines:
Andrey Ponomarenko85043792012-05-14 16:48:07 +040016479 # static int gcry_pth_init ( void) { return ...
16480 # (RE_BACKSLASH_ESCAPE_IN_LISTS | RE...
16481 next;
16482 }
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040016483 if($Old_Value=~/\(/i and $Old_Value!~/\A[\"\']/i)
Andrey Ponomarenko85043792012-05-14 16:48:07 +040016484 { # ignore source defines:
16485 # foo(p)
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040016486 next;
16487 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040016488 }
16489 if(convert_integer($Old_Value) eq convert_integer($New_Value))
16490 { # 0x0001 and 0x1, 0x1 and 1 equal constants
16491 next;
16492 }
16493 if($Old_Value eq "0" and $New_Value eq "NULL")
16494 { # 0 => NULL
16495 next;
16496 }
16497 if($Old_Value eq "NULL" and $New_Value eq "0")
16498 { # NULL => 0
16499 next;
16500 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040016501 %{$ProblemsWithConstants{$Level}{$Constant}} = (
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040016502 "Target"=>$Constant,
16503 "Old_Value"=>$Old_Value,
16504 "New_Value"=>$New_Value );
16505 }
16506 }
16507}
16508
16509sub convert_integer($)
16510{
16511 my $Value = $_[0];
16512 if($Value=~/\A0x[a-f0-9]+\Z/)
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040016513 { # hexadecimal
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040016514 return hex($Value);
16515 }
16516 elsif($Value=~/\A0[0-7]+\Z/)
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040016517 { # octal
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040016518 return oct($Value);
16519 }
16520 elsif($Value=~/\A0b[0-1]+\Z/)
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040016521 { # binary
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040016522 return oct($Value);
16523 }
16524 else {
16525 return $Value;
16526 }
16527}
16528
Andrey Ponomarenko16934472012-03-29 15:37:04 +040016529sub readSymbols($)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040016530{
16531 my $LibVersion = $_[0];
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040016532 my @LibPaths = getSOPaths($LibVersion);
Andrey Ponomarenko16934472012-03-29 15:37:04 +040016533 if($#LibPaths==-1 and not $CheckHeadersOnly)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040016534 {
16535 if($LibVersion==1)
16536 {
16537 printMsg("WARNING", "checking headers only");
16538 $CheckHeadersOnly = 1;
16539 }
16540 else {
16541 exitStatus("Error", "$SLIB_TYPE libraries are not found in ".$Descriptor{$LibVersion}{"Version"});
16542 }
16543 }
Andrey Ponomarenko570ece52012-11-30 16:36:44 +040016544
Andrey Ponomarenko4b077f82012-12-04 16:04:36 +040016545 foreach my $LibPath (@LibPaths) {
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040016546 readSymbols_Lib($LibVersion, $LibPath, 0, "+Weak", 1, 1);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040016547 }
Andrey Ponomarenko570ece52012-11-30 16:36:44 +040016548
16549 if($CheckUndefined)
16550 {
16551 my %UndefinedLibs = ();
16552
16553 foreach my $LibPath (sort {length($a)<=>length($b)} @LibPaths)
16554 {
16555 my $LibName = get_filename($LibPath);
16556 foreach my $Symbol (keys(%{$UndefinedSymbols{$LibVersion}{$LibPath}}))
16557 {
16558 if(not $Symbol_Library{$LibVersion}{$Symbol} and not $DepSymbol_Library{$LibVersion}{$Symbol})
16559 {
16560 foreach my $Path (find_SymbolLibs($LibVersion, $Symbol)) {
16561 $UndefinedLibs{$Path} = 1;
16562 }
16563 }
16564 }
16565 }
16566 if($ExtraInfo)
16567 { # extra information for other tools
16568 if(my @Paths = keys(%UndefinedLibs))
16569 {
16570 my $LibString = "";
16571 foreach (@Paths)
16572 {
16573 my ($Dir, $Name) = separate_path($_);
16574
16575 if(not grep {$Dir eq $_} (@{$SystemPaths{"lib"}})) {
16576 $LibString .= "-L".esc($Dir);
16577 }
16578
16579 $Name = parse_libname($Name, "name", $OStarget);
16580 $Name=~s/\Alib//;
16581
16582 $LibString .= "-l$Name";
16583 }
16584 writeFile($ExtraInfo."/libs-string", $LibString);
16585 }
16586 }
16587 }
16588
Andrey Ponomarenko16934472012-03-29 15:37:04 +040016589 if(not $CheckHeadersOnly)
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040016590 {
Andrey Ponomarenko16934472012-03-29 15:37:04 +040016591 if($#LibPaths!=-1)
16592 {
16593 if(not keys(%{$Symbol_Library{$LibVersion}}))
16594 {
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040016595 printMsg("WARNING", "the set of public symbols in library(ies) is empty ($LibVersion)");
Andrey Ponomarenko16934472012-03-29 15:37:04 +040016596 printMsg("WARNING", "checking headers only");
16597 $CheckHeadersOnly = 1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040016598 }
16599 }
16600 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +040016601
Andrey Ponomarenko07aea072012-11-12 16:15:07 +040016602 # clean memory
Andrey Ponomarenko85043792012-05-14 16:48:07 +040016603 %SystemObjects = ();
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040016604}
16605
Andrey Ponomarenko570ece52012-11-30 16:36:44 +040016606my %Prefix_Lib_Map=(
16607 # symbols for autodetecting library dependencies (by prefix)
16608 "pthread_" => ["libpthread"],
16609 "g_" => ["libglib-2.0", "libgobject-2.0", "libgio-2.0"],
16610 "cairo_" => ["libcairo"],
16611 "gtk_" => ["libgtk-x11-2.0"],
16612 "atk_" => ["libatk-1.0"],
16613 "gdk_" => ["libgdk-x11-2.0"],
16614 "gl" => ["libGL"],
16615 "glu" => ["libGLU"],
16616 "popt" => ["libpopt"],
16617 "Py" => ["libpython"],
16618 "jpeg_" => ["libjpeg"],
16619 "BZ2_" => ["libbz2"],
16620 "Fc" => ["libfontconfig"],
16621 "Xft" => ["libXft"],
16622 "SSL_" => ["libssl"],
16623 "sem_" => ["libpthread"],
16624 "snd_" => ["libasound"],
16625 "art_" => ["libart_lgpl_2"],
16626 "dbus_g" => ["libdbus-glib-1"],
16627 "GOMP_" => ["libgomp"],
16628 "omp_" => ["libgomp"],
16629 "cms" => ["liblcms"]
16630);
16631
16632my %Pattern_Lib_Map=(
16633 "SL[a-z]" => ["libslang"]
16634);
16635
16636my %Symbol_Lib_Map=(
16637 # symbols for autodetecting library dependencies (by name)
16638 "pow" => "libm",
16639 "fmod" => "libm",
16640 "sin" => "libm",
16641 "floor" => "libm",
16642 "cos" => "libm",
16643 "dlopen" => "libdl",
16644 "deflate" => "libz",
16645 "inflate" => "libz",
16646 "move_panel" => "libpanel",
16647 "XOpenDisplay" => "libX11",
16648 "resize_term" => "libncurses",
16649 "clock_gettime" => "librt"
16650);
16651
16652sub find_SymbolLibs($$)
16653{
16654 my ($LibVersion, $Symbol) = @_;
16655
16656 if(index($Symbol, "g_")==0 and $Symbol=~/[A-Z]/)
16657 { # debug symbols
16658 return ();
16659 }
16660
16661 my %Paths = ();
16662
16663 if(my $LibName = $Symbol_Lib_Map{$Symbol})
16664 {
16665 if(my $Path = get_LibPath($LibVersion, $LibName.".".$LIB_EXT)) {
16666 $Paths{$Path} = 1;
16667 }
16668 }
16669
16670 if(my $SymbolPrefix = getPrefix($Symbol))
16671 {
16672 if(defined $Cache{"find_SymbolLibs"}{$SymbolPrefix}) {
16673 return @{$Cache{"find_SymbolLibs"}{$SymbolPrefix}};
16674 }
16675
16676 if(not keys(%Paths))
16677 {
16678 if(defined $Prefix_Lib_Map{$SymbolPrefix})
16679 {
16680 foreach my $LibName (@{$Prefix_Lib_Map{$SymbolPrefix}})
16681 {
16682 if(my $Path = get_LibPath($LibVersion, $LibName.".".$LIB_EXT)) {
16683 $Paths{$Path} = 1;
16684 }
16685 }
16686 }
16687 }
16688
16689 if(not keys(%Paths))
16690 {
16691 foreach my $Prefix (sort keys(%Pattern_Lib_Map))
16692 {
16693 if($Symbol=~/\A$Prefix/)
16694 {
16695 foreach my $LibName (@{$Pattern_Lib_Map{$Prefix}})
16696 {
16697 if(my $Path = get_LibPath($LibVersion, $LibName.".".$LIB_EXT)) {
16698 $Paths{$Path} = 1;
16699 }
16700 }
16701 }
16702 }
16703 }
16704
16705 if(not keys(%Paths))
16706 {
16707 if($SymbolPrefix)
16708 { # try to find a library by symbol prefix
16709 if($SymbolPrefix eq "inotify" and
16710 index($Symbol, "\@GLIBC")!=-1)
16711 {
16712 if(my $Path = get_LibPath($LibVersion, "libc.$LIB_EXT")) {
16713 $Paths{$Path} = 1;
16714 }
16715 }
16716 else
16717 {
16718 if(my $Path = get_LibPath_Prefix($LibVersion, $SymbolPrefix)) {
16719 $Paths{$Path} = 1;
16720 }
16721 }
16722 }
16723 }
16724
16725 if(my @Paths = keys(%Paths)) {
16726 $Cache{"find_SymbolLibs"}{$SymbolPrefix} = \@Paths;
16727 }
16728 }
16729 return keys(%Paths);
16730}
16731
16732sub get_LibPath_Prefix($$)
16733{
16734 my ($LibVersion, $Prefix) = @_;
16735
16736 $Prefix = lc($Prefix);
16737 $Prefix=~s/[_]+\Z//g;
16738
16739 foreach ("-2", "2", "-1", "1", "")
16740 { # libgnome-2.so
16741 # libxml2.so
16742 # libdbus-1.so
16743 if(my $Path = get_LibPath($LibVersion, "lib".$Prefix.$_.".".$LIB_EXT)) {
16744 return $Path;
16745 }
16746 }
16747 return "";
16748}
16749
16750sub getPrefix($)
16751{
16752 my $Str = $_[0];
16753 if($Str=~/\A([_]*[A-Z][a-z]{1,5})[A-Z]/)
16754 { # XmuValidArea: Xmu
16755 return $1;
16756 }
16757 elsif($Str=~/\A([_]*[a-z]+)[A-Z]/)
16758 { # snfReadFont: snf
16759 return $1;
16760 }
16761 elsif($Str=~/\A([_]*[A-Z]{2,})[A-Z][a-z]+([A-Z][a-z]+|\Z)/)
16762 { # XRRTimes: XRR
16763 return $1;
16764 }
16765 elsif($Str=~/\A([_]*[a-z]{1,2}\d+)[a-z\d]*_[a-z]+/i)
16766 { # H5HF_delete: H5
16767 return $1;
16768 }
16769 elsif($Str=~/\A([_]*[a-z0-9]{2,}_)[a-z]+/i)
16770 { # alarm_event_add: alarm_
16771 return $1;
16772 }
16773 elsif($Str=~/\A(([a-z])\2{1,})/i)
16774 { # ffopen
16775 return $1;
16776 }
16777 return "";
16778}
16779
Andrey Ponomarenko16934472012-03-29 15:37:04 +040016780sub getSymbolSize($$)
16781{ # size from the shared library
16782 my ($Symbol, $LibVersion) = @_;
16783 return 0 if(not $Symbol);
16784 if(defined $Symbol_Library{$LibVersion}{$Symbol}
16785 and my $LibName = $Symbol_Library{$LibVersion}{$Symbol})
16786 {
16787 if(defined $Library_Symbol{$LibVersion}{$LibName}{$Symbol}
16788 and my $Size = $Library_Symbol{$LibVersion}{$LibName}{$Symbol})
16789 {
16790 if($Size<0) {
16791 return -$Size;
16792 }
16793 }
16794 }
16795 return 0;
16796}
16797
Andrey Ponomarenko07aea072012-11-12 16:15:07 +040016798sub canonifyName($$)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040016799{ # make TIFFStreamOpen(char const*, std::basic_ostream<char, std::char_traits<char> >*)
16800 # to be TIFFStreamOpen(char const*, std::basic_ostream<char>*)
Andrey Ponomarenko07aea072012-11-12 16:15:07 +040016801 my ($Name, $Type) = @_;
16802
16803 # single
16804 while($Name=~/([^<>,]+),\s*$DEFAULT_STD_PARMS<([^<>,]+)>\s*/ and $1 eq $3)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040016805 {
Andrey Ponomarenko85043792012-05-14 16:48:07 +040016806 my $P = $1;
Andrey Ponomarenko07aea072012-11-12 16:15:07 +040016807 $Name=~s/\Q$P\E,\s*$DEFAULT_STD_PARMS<\Q$P\E>\s*/$P/g;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040016808 }
Andrey Ponomarenko07aea072012-11-12 16:15:07 +040016809
16810 # double
16811 if($Name=~/$DEFAULT_STD_PARMS/)
16812 {
Andrey Ponomarenkoe3d6bf02012-11-14 11:49:09 +040016813 if($Type eq "S")
Andrey Ponomarenko07aea072012-11-12 16:15:07 +040016814 {
16815 my ($ShortName, $FuncParams) = split_Signature($Name);
16816
16817 foreach my $FParam (separate_Params($FuncParams, 0, 0))
16818 {
16819 if(index($FParam, "<")!=-1)
16820 {
16821 $FParam=~s/>([^<>]+)\Z/>/; # remove quals
16822 my $FParam_N = canonifyName($FParam, "T");
16823 if($FParam_N ne $FParam) {
16824 $Name=~s/\Q$FParam\E/$FParam_N/g;
16825 }
16826 }
16827 }
16828 }
16829 elsif($Type eq "T")
16830 {
16831 my ($ShortTmpl, $TmplParams) = template_Base($Name);
16832
16833 my @TParams = separate_Params($TmplParams, 0, 0);
Andrey Ponomarenkoe3d6bf02012-11-14 11:49:09 +040016834 if($#TParams>=1)
Andrey Ponomarenko07aea072012-11-12 16:15:07 +040016835 {
Andrey Ponomarenkoe3d6bf02012-11-14 11:49:09 +040016836 my $FParam = $TParams[0];
16837 foreach my $Pos (1 .. $#TParams)
16838 {
16839 my $TParam = $TParams[$Pos];
16840 if($TParam=~/\A$DEFAULT_STD_PARMS<\Q$FParam\E\s*>\Z/) {
16841 $Name=~s/\Q$FParam, $TParam\E\s*/$FParam/g;
16842 }
Andrey Ponomarenko07aea072012-11-12 16:15:07 +040016843 }
Andrey Ponomarenko07aea072012-11-12 16:15:07 +040016844 }
16845 }
16846 }
Andrey Ponomarenkoe3d6bf02012-11-14 11:49:09 +040016847 if($Type eq "S") {
16848 return formatName($Name, "S");
16849 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040016850 return $Name;
16851}
16852
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040016853sub translateSymbols(@)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040016854{
16855 my $LibVersion = pop(@_);
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040016856 my (@MnglNames1, @MnglNames2, @UnmangledNames) = ();
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040016857 foreach my $Symbol (sort @_)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040016858 {
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040016859 if(index($Symbol, "_Z")==0)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040016860 {
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040016861 next if($tr_name{$Symbol});
16862 $Symbol=~s/[\@\$]+(.*)\Z//;
16863 push(@MnglNames1, $Symbol);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040016864 }
Andrey Ponomarenko570ece52012-11-30 16:36:44 +040016865 elsif(index($Symbol, "?")==0)
16866 {
16867 next if($tr_name{$Symbol});
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040016868 push(@MnglNames2, $Symbol);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040016869 }
16870 else
16871 { # not mangled
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040016872 $tr_name{$Symbol} = $Symbol;
16873 $mangled_name_gcc{$Symbol} = $Symbol;
16874 $mangled_name{$LibVersion}{$Symbol} = $Symbol;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040016875 }
16876 }
16877 if($#MnglNames1 > -1)
16878 { # GCC names
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040016879 @UnmangledNames = reverse(unmangleArray(@MnglNames1));
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040016880 foreach my $MnglName (@MnglNames1)
16881 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040016882 if(my $Unmangled = pop(@UnmangledNames))
16883 {
Andrey Ponomarenko72930b92012-11-14 12:09:17 +040016884 $tr_name{$MnglName} = canonifyName($Unmangled, "S");
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040016885 if(not $mangled_name_gcc{$tr_name{$MnglName}}) {
16886 $mangled_name_gcc{$tr_name{$MnglName}} = $MnglName;
16887 }
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040016888 if(index($MnglName, "_ZTV")==0
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040016889 and $tr_name{$MnglName}=~/vtable for (.+)/)
16890 { # bind class name and v-table symbol
16891 my $ClassName = $1;
16892 $ClassVTable{$ClassName} = $MnglName;
16893 $VTableClass{$MnglName} = $ClassName;
16894 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040016895 }
16896 }
16897 }
16898 if($#MnglNames2 > -1)
16899 { # MSVC names
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040016900 @UnmangledNames = reverse(unmangleArray(@MnglNames2));
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040016901 foreach my $MnglName (@MnglNames2)
16902 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040016903 if(my $Unmangled = pop(@UnmangledNames))
16904 {
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040016905 $tr_name{$MnglName} = formatName($Unmangled, "S");
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040016906 $mangled_name{$LibVersion}{$tr_name{$MnglName}} = $MnglName;
16907 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040016908 }
16909 }
16910 return \%tr_name;
16911}
16912
16913sub link_symbol($$$)
16914{
16915 my ($Symbol, $RunWith, $Deps) = @_;
16916 if(link_symbol_internal($Symbol, $RunWith, \%Symbol_Library)) {
16917 return 1;
16918 }
16919 if($Deps eq "+Deps")
16920 { # check the dependencies
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040016921 if(link_symbol_internal($Symbol, $RunWith, \%DepSymbol_Library)) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040016922 return 1;
16923 }
16924 }
16925 return 0;
16926}
16927
16928sub link_symbol_internal($$$)
16929{
16930 my ($Symbol, $RunWith, $Where) = @_;
16931 return 0 if(not $Where or not $Symbol);
16932 if($Where->{$RunWith}{$Symbol})
16933 { # the exact match by symbol name
16934 return 1;
16935 }
16936 if(my $VSym = $SymVer{$RunWith}{$Symbol})
16937 { # indirect symbol version, i.e.
16938 # foo_old and its symlink foo@v (or foo@@v)
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040016939 # foo_old may be in symtab table
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040016940 if($Where->{$RunWith}{$VSym}) {
16941 return 1;
16942 }
16943 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040016944 my ($Sym, $Spec, $Ver) = separate_symbol($Symbol);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040016945 if($Sym and $Ver)
16946 { # search for the symbol with the same version
16947 # or without version
16948 if($Where->{$RunWith}{$Sym})
16949 { # old: foo@v|foo@@v
16950 # new: foo
16951 return 1;
16952 }
16953 if($Where->{$RunWith}{$Sym."\@".$Ver})
16954 { # old: foo|foo@@v
16955 # new: foo@v
16956 return 1;
16957 }
16958 if($Where->{$RunWith}{$Sym."\@\@".$Ver})
16959 { # old: foo|foo@v
16960 # new: foo@@v
16961 return 1;
16962 }
16963 }
16964 return 0;
16965}
16966
Andrey Ponomarenko16934472012-03-29 15:37:04 +040016967sub readSymbols_App($)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040016968{
16969 my $Path = $_[0];
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040016970 return () if(not $Path);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040016971 my @Imported = ();
16972 if($OSgroup eq "macos")
16973 {
Andrey Ponomarenko07aea072012-11-12 16:15:07 +040016974 my $NM = get_CmdPath("nm");
16975 if(not $NM) {
16976 exitStatus("Not_Found", "can't find \"nm\"");
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040016977 }
Andrey Ponomarenko07aea072012-11-12 16:15:07 +040016978 open(APP, "$NM -g \"$Path\" 2>\"$TMP_DIR/null\" |");
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040016979 while(<APP>)
16980 {
Andrey Ponomarenko07aea072012-11-12 16:15:07 +040016981 if(/ U _([\w\$]+)\s*\Z/) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040016982 push(@Imported, $1);
16983 }
16984 }
16985 close(APP);
16986 }
16987 elsif($OSgroup eq "windows")
16988 {
16989 my $DumpBinCmd = get_CmdPath("dumpbin");
16990 if(not $DumpBinCmd) {
16991 exitStatus("Not_Found", "can't find \"dumpbin.exe\"");
16992 }
Andrey Ponomarenkoa01311b2012-06-08 17:20:02 +040016993 open(APP, "$DumpBinCmd /IMPORTS \"$Path\" 2>\"$TMP_DIR/null\" |");
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040016994 while(<APP>)
16995 {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040016996 if(/\s*\w+\s+\w+\s+\w+\s+([\w\?\@]+)\s*/) {
16997 push(@Imported, $1);
16998 }
16999 }
17000 close(APP);
17001 }
17002 else
17003 {
17004 my $ReadelfCmd = get_CmdPath("readelf");
17005 if(not $ReadelfCmd) {
17006 exitStatus("Not_Found", "can't find \"readelf\"");
17007 }
Andrey Ponomarenkoa01311b2012-06-08 17:20:02 +040017008 open(APP, "$ReadelfCmd -WhlSsdA \"$Path\" 2>\"$TMP_DIR/null\" |");
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040017009 my $symtab = undef; # indicates that we are processing 'symtab' section of 'readelf' output
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017010 while(<APP>)
17011 {
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040017012 if(defined $symtab)
17013 { # do nothing with symtab
17014 if(index($_, "'.dynsym'")!=-1)
17015 { # dynamic table
17016 $symtab = undef;
17017 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017018 }
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040017019 elsif(index($_, "'.symtab'")!=-1)
17020 { # symbol table
17021 $symtab = 1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017022 }
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040017023 elsif(my @Info = readline_ELF($_))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017024 {
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040017025 my ($Ndx, $Symbol) = ($Info[5], $Info[6]);
17026 if($Ndx eq "UND")
17027 { # only imported symbols
17028 push(@Imported, $Symbol);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017029 }
17030 }
17031 }
17032 close(APP);
17033 }
17034 return @Imported;
17035}
17036
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040017037my %ELF_BIND = map {$_=>1} (
17038 "WEAK",
17039 "GLOBAL"
17040);
17041
17042my %ELF_TYPE = map {$_=>1} (
17043 "FUNC",
17044 "IFUNC",
17045 "OBJECT",
17046 "COMMON"
17047);
17048
17049my %ELF_VIS = map {$_=>1} (
17050 "DEFAULT",
17051 "PROTECTED"
17052);
17053
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017054sub readline_ELF($)
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040017055{ # read the line of 'readelf' output corresponding to the symbol
17056 my @Info = split(/\s+/, $_[0]);
17057 # Num: Value Size Type Bind Vis Ndx Name
17058 # 3629: 000b09c0 32 FUNC GLOBAL DEFAULT 13 _ZNSt12__basic_fileIcED1Ev@@GLIBCXX_3.4
17059 shift(@Info); # spaces
17060 shift(@Info); # num
17061 if($#Info!=6)
17062 { # other lines
17063 return ();
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017064 }
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040017065 return () if(not defined $ELF_TYPE{$Info[2]});
17066 return () if(not defined $ELF_BIND{$Info[3]});
17067 return () if(not defined $ELF_VIS{$Info[4]});
17068 if($Info[5] eq "ABS" and $Info[0]=~/\A0+\Z/)
17069 { # 1272: 00000000 0 OBJECT GLOBAL DEFAULT ABS CXXABI_1.3
17070 return ();
17071 }
17072 if($OStarget eq "symbian")
17073 { # _ZN12CCTTokenType4NewLE4TUid3RFs@@ctfinder{000a0000}[102020e5].dll
17074 if(index($Info[6], "_._.absent_export_")!=-1)
17075 { # "_._.absent_export_111"@@libstdcpp{00010001}[10282872].dll
17076 return ();
17077 }
17078 $Info[6]=~s/\@.+//g; # remove version
17079 }
17080 if(index($Info[2], "0x") == 0)
17081 { # size == 0x3d158
17082 $Info[2] = hex($Info[2]);
17083 }
17084 return @Info;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017085}
17086
Andrey Ponomarenko16934472012-03-29 15:37:04 +040017087sub read_symlink($)
17088{
17089 my $Path = $_[0];
Andrey Ponomarenko16934472012-03-29 15:37:04 +040017090 if(my $Res = readlink($Path)) {
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040017091 return $Res;
Andrey Ponomarenko16934472012-03-29 15:37:04 +040017092 }
17093 elsif(my $ReadlinkCmd = get_CmdPath("readlink")) {
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040017094 return `$ReadlinkCmd -n \"$Path\"`;
Andrey Ponomarenko16934472012-03-29 15:37:04 +040017095 }
17096 elsif(my $FileCmd = get_CmdPath("file"))
17097 {
Andrey Ponomarenkoa01311b2012-06-08 17:20:02 +040017098 my $Info = `$FileCmd \"$Path\"`;
Andrey Ponomarenko16934472012-03-29 15:37:04 +040017099 if($Info=~/symbolic\s+link\s+to\s+['`"]*([\w\d\.\-\/\\]+)['`"]*/i) {
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040017100 return $1;
Andrey Ponomarenko16934472012-03-29 15:37:04 +040017101 }
17102 }
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040017103
17104 # can't read
17105 return "";
Andrey Ponomarenko16934472012-03-29 15:37:04 +040017106}
17107
17108sub resolve_symlink($)
17109{
17110 my $Path = $_[0];
17111 return "" if(not $Path);
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040017112
Andrey Ponomarenko16934472012-03-29 15:37:04 +040017113 if(defined $Cache{"resolve_symlink"}{$Path}) {
17114 return $Cache{"resolve_symlink"}{$Path};
17115 }
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040017116 if(not -f $Path and not -l $Path)
17117 { # broken
17118 return ($Cache{"resolve_symlink"}{$Path} = "");
17119 }
17120 return ($Cache{"resolve_symlink"}{$Path} = resolve_symlink_I($Path));
17121}
17122
17123sub resolve_symlink_I($)
17124{
17125 my $Path = $_[0];
Andrey Ponomarenko16934472012-03-29 15:37:04 +040017126 return $Path if(isCyclical(\@RecurSymlink, $Path));
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040017127 my $Res = $Path;
Andrey Ponomarenko16934472012-03-29 15:37:04 +040017128 push(@RecurSymlink, $Path);
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040017129 if(-l $Path and my $Redirect = read_symlink($Path))
Andrey Ponomarenko16934472012-03-29 15:37:04 +040017130 {
17131 if(is_abs($Redirect))
17132 { # absolute path
17133 if($SystemRoot and $SystemRoot ne "/"
17134 and $Path=~/\A\Q$SystemRoot\E\//
17135 and (-f $SystemRoot.$Redirect or -l $SystemRoot.$Redirect))
17136 { # symbolic links from the sysroot
17137 # should be corrected to point to
17138 # the files inside sysroot
17139 $Redirect = $SystemRoot.$Redirect;
17140 }
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040017141 $Res = resolve_symlink($Redirect);
Andrey Ponomarenko16934472012-03-29 15:37:04 +040017142 }
17143 elsif($Redirect=~/\.\.[\/\\]/)
17144 { # relative path
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040017145 $Redirect = joinPath(get_dirname($Path), $Redirect);
Andrey Ponomarenko16934472012-03-29 15:37:04 +040017146 while($Redirect=~s&(/|\\)[^\/\\]+(\/|\\)\.\.(\/|\\)&$1&){};
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040017147 $Res = resolve_symlink($Redirect);
Andrey Ponomarenko16934472012-03-29 15:37:04 +040017148 }
17149 elsif(-f get_dirname($Path)."/".$Redirect)
17150 { # file name in the same directory
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040017151 $Res = resolve_symlink(joinPath(get_dirname($Path), $Redirect));
Andrey Ponomarenko16934472012-03-29 15:37:04 +040017152 }
17153 else
17154 { # broken link
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040017155 $Res = "";
Andrey Ponomarenko16934472012-03-29 15:37:04 +040017156 }
17157 }
17158 pop(@RecurSymlink);
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040017159 return $Res;
Andrey Ponomarenko16934472012-03-29 15:37:04 +040017160}
17161
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040017162sub get_LibPath($$)
Andrey Ponomarenko16934472012-03-29 15:37:04 +040017163{
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040017164 my ($LibVersion, $Name) = @_;
17165 return "" if(not $LibVersion or not $Name);
17166 if(defined $Cache{"get_LibPath"}{$LibVersion}{$Name}) {
17167 return $Cache{"get_LibPath"}{$LibVersion}{$Name};
Andrey Ponomarenko16934472012-03-29 15:37:04 +040017168 }
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040017169 return ($Cache{"get_LibPath"}{$LibVersion}{$Name} = get_LibPath_I($LibVersion, $Name));
17170}
17171
17172sub get_LibPath_I($$)
17173{
17174 my ($LibVersion, $Name) = @_;
17175 if(is_abs($Name))
Andrey Ponomarenko16934472012-03-29 15:37:04 +040017176 {
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040017177 if(-f $Name)
17178 { # absolute path
17179 return $Name;
17180 }
17181 else
17182 { # broken
17183 return "";
17184 }
17185 }
Andrey Ponomarenko07aea072012-11-12 16:15:07 +040017186 if(defined $RegisteredObjects{$LibVersion}{$Name})
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040017187 { # registered paths
Andrey Ponomarenko07aea072012-11-12 16:15:07 +040017188 return $RegisteredObjects{$LibVersion}{$Name};
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040017189 }
Andrey Ponomarenko07aea072012-11-12 16:15:07 +040017190 if(defined $RegisteredSONAMEs{$LibVersion}{$Name})
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040017191 { # registered paths
Andrey Ponomarenko07aea072012-11-12 16:15:07 +040017192 return $RegisteredSONAMEs{$LibVersion}{$Name};
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040017193 }
17194 if(my $DefaultPath = $DyLib_DefaultPath{$Name})
17195 { # ldconfig default paths
17196 return $DefaultPath;
17197 }
Andrey Ponomarenko570ece52012-11-30 16:36:44 +040017198 foreach my $Dir (@DefaultLibPaths, @{$SystemPaths{"lib"}})
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040017199 { # search in default linker directories
17200 # and then in all system paths
17201 if(-f $Dir."/".$Name) {
17202 return joinPath($Dir,$Name);
17203 }
17204 }
17205 detectSystemObjects() if(not keys(%SystemObjects));
17206 if(my @AllObjects = keys(%{$SystemObjects{$Name}})) {
17207 return $AllObjects[0];
17208 }
17209 if(my $ShortName = parse_libname($Name, "name+ext", $OStarget))
17210 {
17211 if($ShortName ne $Name)
17212 { # FIXME: check this case
17213 if(my $Path = get_LibPath($LibVersion, $ShortName)) {
17214 return $Path;
Andrey Ponomarenko16934472012-03-29 15:37:04 +040017215 }
17216 }
Andrey Ponomarenko16934472012-03-29 15:37:04 +040017217 }
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040017218 # can't find
17219 return "";
Andrey Ponomarenko16934472012-03-29 15:37:04 +040017220}
17221
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040017222sub readSymbols_Lib($$$$$$)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017223{
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040017224 my ($LibVersion, $Lib_Path, $IsNeededLib, $Weak, $Deps, $Vers) = @_;
17225 return () if(not $LibVersion or not $Lib_Path);
17226 my $Lib_Name = get_filename(resolve_symlink($Lib_Path));
17227 if($IsNeededLib)
17228 {
17229 if($CheckedDyLib{$LibVersion}{$Lib_Name}) {
17230 return ();
17231 }
17232 }
17233 return () if(isCyclical(\@RecurLib, $Lib_Name) or $#RecurLib>=1);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017234 $CheckedDyLib{$LibVersion}{$Lib_Name} = 1;
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040017235
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040017236 if($CheckImpl)
17237 {
17238 if(not $IsNeededLib) {
17239 getImplementations($LibVersion, $Lib_Path);
17240 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040017241 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040017242
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017243 push(@RecurLib, $Lib_Name);
17244 my (%Value_Interface, %Interface_Value, %NeededLib) = ();
Andrey Ponomarenko57a405d2012-11-15 11:34:08 +040017245 my $Lib_ShortName = parse_libname($Lib_Name, "name+ext", $OStarget);
17246
17247 if(not $IsNeededLib)
17248 { # special cases: libstdc++ and libc
17249 if(my $ShortName = parse_libname($Lib_Name, "short", $OStarget))
17250 {
17251 if($ShortName eq "libstdc++")
17252 { # libstdc++.so.6
17253 $STDCXX_TESTING = 1;
17254 }
17255 elsif($ShortName eq "libc")
17256 { # libc-2.11.3.so
17257 $GLIBC_TESTING = 1;
17258 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017259 }
17260 }
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040017261 my $DebugPath = "";
Andrey Ponomarenkoa01311b2012-06-08 17:20:02 +040017262 if($Debug and not $DumpSystem)
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040017263 { # debug mode
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040017264 $DebugPath = $DEBUG_PATH{$LibVersion}."/libs/".get_filename($Lib_Path).".txt";
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040017265 mkpath(get_dirname($DebugPath));
17266 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017267 if($OStarget eq "macos")
17268 { # Mac OS X: *.dylib, *.a
Andrey Ponomarenko07aea072012-11-12 16:15:07 +040017269 my $NM = get_CmdPath("nm");
Andrey Ponomarenko4b077f82012-12-04 16:04:36 +040017270 if(not $NM) {
17271 exitStatus("Not_Found", "can't find \"nm\"");
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017272 }
Andrey Ponomarenko07aea072012-11-12 16:15:07 +040017273 $NM .= " -g \"$Lib_Path\" 2>\"$TMP_DIR/null\"";
Andrey Ponomarenkoa01311b2012-06-08 17:20:02 +040017274 if($DebugPath)
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040017275 { # debug mode
Andrey Ponomarenko16934472012-03-29 15:37:04 +040017276 # write to file
Andrey Ponomarenko07aea072012-11-12 16:15:07 +040017277 system($NM." >\"$DebugPath\"");
Andrey Ponomarenko16934472012-03-29 15:37:04 +040017278 open(LIB, $DebugPath);
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040017279 }
Andrey Ponomarenko16934472012-03-29 15:37:04 +040017280 else
17281 { # write to pipe
Andrey Ponomarenko07aea072012-11-12 16:15:07 +040017282 open(LIB, $NM." |");
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040017283 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017284 while(<LIB>)
17285 {
Andrey Ponomarenko570ece52012-11-30 16:36:44 +040017286 if($CheckUndefined)
17287 {
17288 if(not $IsNeededLib)
17289 {
17290 if(/ U _([\w\$]+)\s*\Z/)
17291 {
17292 $UndefinedSymbols{$LibVersion}{$Lib_Path}{$1} = 1;
17293 next;
17294 }
17295 }
17296 }
17297
Andrey Ponomarenko07aea072012-11-12 16:15:07 +040017298 if(/ [STD] _([\w\$]+)\s*\Z/)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017299 {
Andrey Ponomarenko570ece52012-11-30 16:36:44 +040017300 my $Symbol = $1;
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040017301 if($IsNeededLib)
17302 {
Andrey Ponomarenko57a405d2012-11-15 11:34:08 +040017303 if(not defined $RegisteredObjects_Short{$LibVersion}{$Lib_ShortName})
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040017304 {
Andrey Ponomarenko570ece52012-11-30 16:36:44 +040017305 $DepSymbol_Library{$LibVersion}{$Symbol} = $Lib_Name;
17306 $DepLibrary_Symbol{$LibVersion}{$Lib_Name}{$Symbol} = 1;
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040017307 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017308 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040017309 else
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017310 {
Andrey Ponomarenko570ece52012-11-30 16:36:44 +040017311 $Symbol_Library{$LibVersion}{$Symbol} = $Lib_Name;
17312 $Library_Symbol{$LibVersion}{$Lib_Name}{$Symbol} = 1;
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040017313 if($COMMON_LANGUAGE{$LibVersion} ne "C++")
17314 {
Andrey Ponomarenko570ece52012-11-30 16:36:44 +040017315 if(index($Symbol, "_Z")==0 or index($Symbol, "?")==0) {
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040017316 setLanguage($LibVersion, "C++");
17317 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017318 }
17319 if($CheckObjectsOnly
17320 and $LibVersion==1) {
Andrey Ponomarenko570ece52012-11-30 16:36:44 +040017321 $CheckedSymbols{"Binary"}{$Symbol} = 1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017322 }
17323 }
17324 }
17325 }
17326 close(LIB);
Andrey Ponomarenko07aea072012-11-12 16:15:07 +040017327
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040017328 if($Deps)
17329 {
17330 if($LIB_TYPE eq "dynamic")
17331 { # dependencies
Andrey Ponomarenko07aea072012-11-12 16:15:07 +040017332
17333 my $OtoolCmd = get_CmdPath("otool");
Andrey Ponomarenko4b077f82012-12-04 16:04:36 +040017334 if(not $OtoolCmd) {
17335 exitStatus("Not_Found", "can't find \"otool\"");
Andrey Ponomarenko07aea072012-11-12 16:15:07 +040017336 }
17337
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040017338 open(LIB, "$OtoolCmd -L \"$Lib_Path\" 2>\"$TMP_DIR/null\" |");
17339 while(<LIB>)
17340 {
17341 if(/\s*([\/\\].+\.$LIB_EXT)\s*/
17342 and $1 ne $Lib_Path) {
17343 $NeededLib{$1} = 1;
17344 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017345 }
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040017346 close(LIB);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017347 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017348 }
17349 }
17350 elsif($OStarget eq "windows")
17351 { # Windows *.dll, *.lib
17352 my $DumpBinCmd = get_CmdPath("dumpbin");
17353 if(not $DumpBinCmd) {
17354 exitStatus("Not_Found", "can't find \"dumpbin\"");
17355 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040017356 $DumpBinCmd .= " /EXPORTS \"".$Lib_Path."\" 2>$TMP_DIR/null";
Andrey Ponomarenkoa01311b2012-06-08 17:20:02 +040017357 if($DebugPath)
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040017358 { # debug mode
Andrey Ponomarenko16934472012-03-29 15:37:04 +040017359 # write to file
Andrey Ponomarenkoa01311b2012-06-08 17:20:02 +040017360 system($DumpBinCmd." >\"$DebugPath\"");
Andrey Ponomarenko16934472012-03-29 15:37:04 +040017361 open(LIB, $DebugPath);
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040017362 }
Andrey Ponomarenko16934472012-03-29 15:37:04 +040017363 else
17364 { # write to pipe
17365 open(LIB, $DumpBinCmd." |");
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040017366 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017367 while(<LIB>)
17368 { # 1197 4AC 0000A620 SetThreadStackGuarantee
17369 # 1198 4AD SetThreadToken (forwarded to ...)
17370 # 3368 _o2i_ECPublicKey
17371 if(/\A\s*\d+\s+[a-f\d]+\s+[a-f\d]+\s+([\w\?\@]+)\s*\Z/i
17372 or /\A\s*\d+\s+[a-f\d]+\s+([\w\?\@]+)\s*\(\s*forwarded\s+/
17373 or /\A\s*\d+\s+_([\w\?\@]+)\s*\Z/)
17374 { # dynamic, static and forwarded symbols
17375 my $realname = $1;
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040017376 if($IsNeededLib)
17377 {
Andrey Ponomarenko57a405d2012-11-15 11:34:08 +040017378 if(not defined $RegisteredObjects_Short{$LibVersion}{$Lib_ShortName})
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040017379 {
17380 $DepSymbol_Library{$LibVersion}{$realname} = $Lib_Name;
17381 $DepLibrary_Symbol{$LibVersion}{$Lib_Name}{$realname} = 1;
17382 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017383 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040017384 else
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017385 {
17386 $Symbol_Library{$LibVersion}{$realname} = $Lib_Name;
17387 $Library_Symbol{$LibVersion}{$Lib_Name}{$realname} = 1;
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040017388 if($COMMON_LANGUAGE{$LibVersion} ne "C++")
17389 {
17390 if(index($realname, "_Z")==0 or index($realname, "?")==0) {
17391 setLanguage($LibVersion, "C++");
17392 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017393 }
17394 if($CheckObjectsOnly
17395 and $LibVersion==1) {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040017396 $CheckedSymbols{"Binary"}{$realname} = 1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017397 }
17398 }
17399 }
17400 }
17401 close(LIB);
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040017402 if($Deps)
17403 {
17404 if($LIB_TYPE eq "dynamic")
17405 { # dependencies
17406 open(LIB, "$DumpBinCmd /DEPENDENTS \"$Lib_Path\" 2>\"$TMP_DIR/null\" |");
17407 while(<LIB>)
17408 {
17409 if(/\s*([^\s]+?\.$LIB_EXT)\s*/i
17410 and $1 ne $Lib_Path) {
17411 $NeededLib{path_format($1, $OSgroup)} = 1;
17412 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017413 }
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040017414 close(LIB);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017415 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017416 }
17417 }
17418 else
17419 { # Unix; *.so, *.a
17420 # Symbian: *.dso, *.lib
17421 my $ReadelfCmd = get_CmdPath("readelf");
17422 if(not $ReadelfCmd) {
17423 exitStatus("Not_Found", "can't find \"readelf\"");
17424 }
Andrey Ponomarenkoa01311b2012-06-08 17:20:02 +040017425 $ReadelfCmd .= " -WhlSsdA \"$Lib_Path\" 2>\"$TMP_DIR/null\"";
17426 if($DebugPath)
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040017427 { # debug mode
Andrey Ponomarenko16934472012-03-29 15:37:04 +040017428 # write to file
Andrey Ponomarenkoa01311b2012-06-08 17:20:02 +040017429 system($ReadelfCmd." >\"$DebugPath\"");
Andrey Ponomarenko16934472012-03-29 15:37:04 +040017430 open(LIB, $DebugPath);
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040017431 }
Andrey Ponomarenko16934472012-03-29 15:37:04 +040017432 else
17433 { # write to pipe
17434 open(LIB, $ReadelfCmd." |");
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040017435 }
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040017436 my $symtab = undef; # indicates that we are processing 'symtab' section of 'readelf' output
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017437 while(<LIB>)
17438 {
17439 if($LIB_TYPE eq "dynamic")
17440 { # dynamic library specifics
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040017441 if(defined $symtab)
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040017442 {
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040017443 if(index($_, "'.dynsym'")!=-1)
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040017444 { # dynamic table
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040017445 $symtab = undef;
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040017446 }
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040017447 # do nothing with symtab
17448 next;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017449 }
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040017450 elsif(index($_, "'.symtab'")!=-1)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017451 { # symbol table
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040017452 $symtab = 1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017453 next;
17454 }
17455 }
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040017456 if(my ($Value, $Size, $Type, $Bind, $Vis, $Ndx, $Symbol) = readline_ELF($_))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017457 { # read ELF entry
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040017458 if($Ndx eq "UND")
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017459 { # ignore interfaces that are imported from somewhere else
Andrey Ponomarenko570ece52012-11-30 16:36:44 +040017460 if($CheckUndefined)
17461 {
17462 if(not $IsNeededLib) {
17463 $UndefinedSymbols{$LibVersion}{$Lib_Path}{$Symbol} = 1;
17464 }
17465 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017466 next;
17467 }
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040017468 if($Bind eq "WEAK"
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017469 and $Weak eq "-Weak")
17470 { # skip WEAK symbols
Andrey Ponomarenko07aea072012-11-12 16:15:07 +040017471 $WeakSymbols{$LibVersion}{$Symbol} = 1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017472 next;
17473 }
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040017474 my $Short = $Symbol;
17475 $Short=~s/\@.+//g;
17476 if($Type eq "OBJECT")
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017477 { # global data
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040017478 $GlobalDataObject{$LibVersion}{$Symbol} = 1;
17479 $GlobalDataObject{$LibVersion}{$Short} = 1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017480 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040017481 if($IsNeededLib)
17482 {
Andrey Ponomarenko57a405d2012-11-15 11:34:08 +040017483 if(not defined $RegisteredObjects_Short{$LibVersion}{$Lib_ShortName})
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040017484 {
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040017485 $DepSymbol_Library{$LibVersion}{$Symbol} = $Lib_Name;
17486 $DepLibrary_Symbol{$LibVersion}{$Lib_Name}{$Symbol} = ($Type eq "OBJECT")?-$Size:1;
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040017487 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017488 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040017489 else
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017490 {
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040017491 $Symbol_Library{$LibVersion}{$Symbol} = $Lib_Name;
17492 $Library_Symbol{$LibVersion}{$Lib_Name}{$Symbol} = ($Type eq "OBJECT")?-$Size:1;
17493 if($Vers)
17494 {
17495 if($LIB_EXT eq "so")
17496 { # value
17497 $Interface_Value{$LibVersion}{$Symbol} = $Value;
17498 $Value_Interface{$LibVersion}{$Value}{$Symbol} = 1;
17499 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017500 }
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040017501 if($COMMON_LANGUAGE{$LibVersion} ne "C++")
17502 {
17503 if(index($Symbol, "_Z")==0 or index($Symbol, "?")==0) {
17504 setLanguage($LibVersion, "C++");
17505 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017506 }
17507 if($CheckObjectsOnly
17508 and $LibVersion==1) {
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040017509 $CheckedSymbols{"Binary"}{$Symbol} = 1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017510 }
17511 }
17512 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040017513 elsif($LIB_TYPE eq "dynamic")
17514 { # dynamic library specifics
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040017515 if($Deps)
17516 {
17517 if(/NEEDED.+\[([^\[\]]+)\]/)
17518 { # dependencies:
17519 # 0x00000001 (NEEDED) Shared library: [libc.so.6]
17520 $NeededLib{$1} = 1;
17521 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040017522 }
17523 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017524 }
17525 close(LIB);
17526 }
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040017527 if($Vers)
17528 {
17529 if(not $IsNeededLib and $LIB_EXT eq "so")
17530 { # get symbol versions
17531 foreach my $Symbol (keys(%{$Symbol_Library{$LibVersion}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017532 {
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040017533 next if(index($Symbol,"\@")==-1);
17534 if(my $Value = $Interface_Value{$LibVersion}{$Symbol})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017535 {
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040017536 my $Interface_SymName = "";
17537 foreach my $Symbol_SameValue (keys(%{$Value_Interface{$LibVersion}{$Value}}))
Andrey Ponomarenkoa01311b2012-06-08 17:20:02 +040017538 {
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040017539 if($Symbol_SameValue ne $Symbol
17540 and index($Symbol_SameValue,"\@")==-1)
17541 {
17542 $SymVer{$LibVersion}{$Symbol_SameValue} = $Symbol;
17543 $Interface_SymName = $Symbol_SameValue;
17544 last;
17545 }
Andrey Ponomarenkoa01311b2012-06-08 17:20:02 +040017546 }
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040017547 if(not $Interface_SymName)
17548 {
17549 if($Symbol=~/\A([^\@\$\?]*)[\@\$]+([^\@\$]*)\Z/
17550 and not $SymVer{$LibVersion}{$1}) {
17551 $SymVer{$LibVersion}{$1} = $Symbol;
17552 }
Andrey Ponomarenkoa01311b2012-06-08 17:20:02 +040017553 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017554 }
17555 }
17556 }
17557 }
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040017558 if($Deps)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017559 {
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040017560 foreach my $DyLib (sort keys(%NeededLib))
17561 {
17562 if(my $DepPath = get_LibPath($LibVersion, $DyLib)) {
17563 readSymbols_Lib($LibVersion, $DepPath, 1, "+Weak", $Deps, $Vers);
17564 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017565 }
17566 }
17567 pop(@RecurLib);
17568 return $Library_Symbol{$LibVersion};
17569}
17570
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040017571sub get_prefixes($)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017572{
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017573 my %Prefixes = ();
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040017574 get_prefixes_I([$_[0]], \%Prefixes);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017575 return keys(%Prefixes);
17576}
17577
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040017578sub get_prefixes_I($$)
17579{
17580 foreach my $P (@{$_[0]})
17581 {
17582 my @Parts = reverse(split(/[\/\\]+/, $P));
17583 my $Name = $Parts[0];
17584 foreach (1 .. $#Parts)
17585 {
17586 $_[1]->{$Name}{$P} = 1;
17587 last if($_>4 or $Parts[$_] eq "include");
17588 $Name = $Parts[$_].$SLASH.$Name;
17589 }
17590 }
17591}
17592
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017593sub detectSystemHeaders()
17594{
17595 my @SysHeaders = ();
Andrey Ponomarenko570ece52012-11-30 16:36:44 +040017596 foreach my $DevelPath (@{$SystemPaths{"include"}})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017597 {
17598 next if(not -d $DevelPath);
17599 # search for all header files in the /usr/include
17600 # with or without extension (ncurses.h, QtCore, ...)
Andrey Ponomarenko570ece52012-11-30 16:36:44 +040017601 @SysHeaders = (@SysHeaders, cmd_find($DevelPath,"f"));
17602 foreach my $Link (cmd_find($DevelPath,"l"))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017603 { # add symbolic links
17604 if(-f $Link) {
17605 push(@SysHeaders, $Link);
17606 }
17607 }
17608 }
Andrey Ponomarenko570ece52012-11-30 16:36:44 +040017609 foreach my $DevelPath (@{$SystemPaths{"lib"}})
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040017610 { # search for config headers in the /usr/lib
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017611 next if(not -d $DevelPath);
Andrey Ponomarenko570ece52012-11-30 16:36:44 +040017612 foreach (cmd_find($DevelPath,"f"))
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040017613 {
17614 if(not /\/(gcc|jvm|syslinux|kbd|parrot|xemacs)/)
17615 {
17616 if(/\.h\Z|\/include\//) {
17617 push(@SysHeaders, $_);
17618 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017619 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017620 }
17621 }
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040017622 get_prefixes_I(\@SysHeaders, \%SystemHeaders);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017623}
17624
17625sub detectSystemObjects()
17626{
Andrey Ponomarenko570ece52012-11-30 16:36:44 +040017627 foreach my $DevelPath (@{$SystemPaths{"lib"}})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017628 {
17629 next if(not -d $DevelPath);
17630 foreach my $Path (find_libs($DevelPath,"",""))
17631 { # search for shared libraries in the /usr/lib (including symbolic links)
17632 $SystemObjects{parse_libname(get_filename($Path), "name+ext", $OStarget)}{$Path}=1;
17633 }
17634 }
17635}
17636
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040017637sub getSOPaths($)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017638{
17639 my $LibVersion = $_[0];
Andrey Ponomarenko4b077f82012-12-04 16:04:36 +040017640 my @Paths = ();
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017641 foreach my $Dest (split(/\s*\n\s*/, $Descriptor{$LibVersion}{"Libs"}))
17642 {
17643 if(not -e $Dest) {
17644 exitStatus("Access_Error", "can't access \'$Dest\'");
17645 }
17646 my @SoPaths_Dest = getSOPaths_Dest($Dest, $LibVersion);
17647 foreach (@SoPaths_Dest) {
Andrey Ponomarenko4b077f82012-12-04 16:04:36 +040017648 push(@Paths, $_);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017649 }
17650 }
Andrey Ponomarenko4b077f82012-12-04 16:04:36 +040017651 return sort @Paths;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017652}
17653
17654sub skip_lib($$)
17655{
17656 my ($Path, $LibVersion) = @_;
17657 return 1 if(not $Path or not $LibVersion);
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040017658 my $Name = get_filename($Path);
17659 if($SkipLibs{$LibVersion}{"Name"}{$Name}) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017660 return 1;
17661 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040017662 my $ShortName = parse_libname($Name, "name+ext", $OStarget);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017663 if($SkipLibs{$LibVersion}{"Name"}{$ShortName}) {
17664 return 1;
17665 }
17666 foreach my $Dir (keys(%{$SkipLibs{$LibVersion}{"Path"}}))
17667 {
17668 if($Path=~/\Q$Dir\E([\/\\]|\Z)/) {
17669 return 1;
17670 }
17671 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040017672 foreach my $P (keys(%{$SkipLibs{$LibVersion}{"Pattern"}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017673 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040017674 if($Name=~/$P/) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017675 return 1;
17676 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040017677 if($P=~/[\/\\]/ and $Path=~/$P/) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017678 return 1;
17679 }
17680 }
17681 return 0;
17682}
17683
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040017684sub skipHeader($$)
17685{
17686 my ($Path, $LibVersion) = @_;
17687 return 1 if(not $Path or not $LibVersion);
17688 if(not keys(%{$SkipHeaders{$LibVersion}})) {
17689 return 0;
17690 }
17691 if(defined $Cache{"skipHeader"}{$Path}) {
17692 return $Cache{"skipHeader"}{$Path};
17693 }
17694 return ($Cache{"skipHeader"}{$Path} = skipHeader_I(@_));
17695}
17696
17697sub skipHeader_I($$)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017698{ # returns:
17699 # 1 - if header should NOT be included and checked
17700 # 2 - if header should NOT be included, but should be checked
17701 my ($Path, $LibVersion) = @_;
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040017702 my $Name = get_filename($Path);
17703 if(my $Kind = $SkipHeaders{$LibVersion}{"Name"}{$Name}) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017704 return $Kind;
17705 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040017706 foreach my $D (keys(%{$SkipHeaders{$LibVersion}{"Path"}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017707 {
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040017708 if(index($Path, $D)!=-1)
17709 {
17710 if($Path=~/\Q$D\E([\/\\]|\Z)/) {
17711 return $SkipHeaders{$LibVersion}{"Path"}{$D};
17712 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017713 }
17714 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040017715 foreach my $P (keys(%{$SkipHeaders{$LibVersion}{"Pattern"}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017716 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040017717 if(my $Kind = $SkipHeaders{$LibVersion}{"Pattern"}{$P})
17718 {
17719 if($Name=~/$P/) {
17720 return $Kind;
17721 }
17722 if($P=~/[\/\\]/ and $Path=~/$P/) {
17723 return $Kind;
17724 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017725 }
17726 }
17727 return 0;
17728}
17729
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040017730sub registerObject_Dir($$)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017731{
17732 my ($Dir, $LibVersion) = @_;
Andrey Ponomarenko570ece52012-11-30 16:36:44 +040017733 if(grep {$_ eq $Dir} @{$SystemPaths{"lib"}})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017734 { # system directory
17735 return;
17736 }
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040017737 if($RegisteredObject_Dirs{$LibVersion}{$Dir})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017738 { # already registered
17739 return;
17740 }
17741 foreach my $Path (find_libs($Dir,"",1))
17742 {
17743 next if(ignore_path($Path));
17744 next if(skip_lib($Path, $LibVersion));
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040017745 registerObject($Path, $LibVersion);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017746 }
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040017747 $RegisteredObject_Dirs{$LibVersion}{$Dir} = 1;
17748}
17749
17750sub registerObject($$)
17751{
17752 my ($Path, $LibVersion) = @_;
17753 my $Name = get_filename($Path);
Andrey Ponomarenko07aea072012-11-12 16:15:07 +040017754 $RegisteredObjects{$LibVersion}{$Name} = $Path;
Andrey Ponomarenko27681702012-11-12 16:33:39 +040017755 if($OSgroup=~/linux|bsd/i)
17756 {
17757 if(my $SONAME = getSONAME($Path)) {
17758 $RegisteredSONAMEs{$LibVersion}{$SONAME} = $Path;
17759 }
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040017760 }
Andrey Ponomarenko57a405d2012-11-15 11:34:08 +040017761 if(my $Short = parse_libname($Name, "name+ext", $OStarget)) {
17762 $RegisteredObjects_Short{$LibVersion}{$Short} = $Path;
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040017763 }
17764}
17765
17766sub getSONAME($)
17767{
17768 my $Path = $_[0];
17769 return if(not $Path);
17770 if(defined $Cache{"getSONAME"}{$Path}) {
17771 return $Cache{"getSONAME"}{$Path};
17772 }
17773 my $ObjdumpCmd = get_CmdPath("objdump");
17774 if(not $ObjdumpCmd) {
17775 exitStatus("Not_Found", "can't find \"objdump\"");
17776 }
17777 my $SonameCmd = "$ObjdumpCmd -x $Path 2>$TMP_DIR/null";
17778 if($OSgroup eq "windows") {
17779 $SonameCmd .= " | find \"SONAME\"";
17780 }
17781 else {
17782 $SonameCmd .= " | grep SONAME";
17783 }
17784 if(my $SonameInfo = `$SonameCmd`) {
17785 if($SonameInfo=~/SONAME\s+([^\s]+)/) {
17786 return ($Cache{"getSONAME"}{$Path} = $1);
17787 }
17788 }
17789 return ($Cache{"getSONAME"}{$Path}="");
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017790}
17791
17792sub getSOPaths_Dest($$)
17793{
17794 my ($Dest, $LibVersion) = @_;
17795 if(skip_lib($Dest, $LibVersion)) {
17796 return ();
17797 }
17798 if(-f $Dest)
17799 {
17800 if(not parse_libname($Dest, "name", $OStarget)) {
17801 exitStatus("Error", "incorrect format of library (should be *.$LIB_EXT): \'$Dest\'");
17802 }
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040017803 registerObject($Dest, $LibVersion);
17804 registerObject_Dir(get_dirname($Dest), $LibVersion);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017805 return ($Dest);
17806 }
17807 elsif(-d $Dest)
17808 {
17809 $Dest=~s/[\/\\]+\Z//g;
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040017810 my %Libs = ();
Andrey Ponomarenko570ece52012-11-30 16:36:44 +040017811 if(grep { $Dest eq $_ } @{$SystemPaths{"lib"}})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017812 { # you have specified /usr/lib as the search directory (<libs>) in the XML descriptor
17813 # and the real name of the library by -l option (bz2, stdc++, Xaw, ...)
Andrey Ponomarenko570ece52012-11-30 16:36:44 +040017814 foreach my $Path (cmd_find($Dest,"","*".esc($TargetLibraryName)."*.$LIB_EXT*",2))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017815 { # all files and symlinks that match the name of a library
17816 if(get_filename($Path)=~/\A(|lib)\Q$TargetLibraryName\E[\d\-]*\.$LIB_EXT[\d\.]*\Z/i)
17817 {
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040017818 registerObject($Path, $LibVersion);
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040017819 $Libs{resolve_symlink($Path)}=1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017820 }
17821 }
17822 }
17823 else
17824 { # search for all files and symlinks
17825 foreach my $Path (find_libs($Dest,"",""))
17826 {
17827 next if(ignore_path($Path));
17828 next if(skip_lib($Path, $LibVersion));
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040017829 registerObject($Path, $LibVersion);
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040017830 $Libs{resolve_symlink($Path)}=1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017831 }
17832 if($OSgroup eq "macos")
17833 { # shared libraries on MacOS X may have no extension
Andrey Ponomarenko570ece52012-11-30 16:36:44 +040017834 foreach my $Path (cmd_find($Dest,"f"))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017835 {
17836 next if(ignore_path($Path));
17837 next if(skip_lib($Path, $LibVersion));
17838 if(get_filename($Path)!~/\./
Andrey Ponomarenko85043792012-05-14 16:48:07 +040017839 and cmd_file($Path)=~/(shared|dynamic)\s+library/i)
17840 {
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040017841 registerObject($Path, $LibVersion);
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040017842 $Libs{resolve_symlink($Path)}=1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017843 }
17844 }
17845 }
17846 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040017847 return keys(%Libs);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017848 }
17849 else {
17850 return ();
17851 }
17852}
17853
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040017854sub isCyclical($$)
17855{
17856 my ($Stack, $Value) = @_;
17857 return (grep {$_ eq $Value} @{$Stack});
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017858}
17859
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017860sub detectWordSize()
17861{
17862 return "" if(not $GCC_PATH);
17863 if($Cache{"detectWordSize"}) {
17864 return $Cache{"detectWordSize"};
17865 }
17866 writeFile("$TMP_DIR/empty.h", "");
Andrey Ponomarenkoa01311b2012-06-08 17:20:02 +040017867 my $Defines = `$GCC_PATH -E -dD \"$TMP_DIR/empty.h\"`;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017868 unlink("$TMP_DIR/empty.h");
17869 my $WSize = 0;
17870 if($Defines=~/ __SIZEOF_POINTER__\s+(\d+)/)
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040017871 { # GCC 4
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017872 $WSize = $1;
17873 }
17874 elsif($Defines=~/ __PTRDIFF_TYPE__\s+(\w+)/)
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040017875 { # GCC 3
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017876 my $PTRDIFF = $1;
17877 if($PTRDIFF=~/long/) {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040017878 $WSize = "8";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017879 }
17880 else {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040017881 $WSize = "4";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017882 }
17883 }
Andrey Ponomarenko01117f12012-06-26 12:23:02 +040017884 if(not $WSize) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017885 exitStatus("Error", "can't check WORD size");
17886 }
17887 return ($Cache{"detectWordSize"} = $WSize);
17888}
17889
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +040017890sub getWordSize($) {
17891 return $WORD_SIZE{$_[0]};
17892}
17893
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017894sub majorVersion($)
17895{
17896 my $V = $_[0];
17897 return 0 if(not $V);
17898 my @VParts = split(/\./, $V);
17899 return $VParts[0];
17900}
17901
17902sub cmpVersions($$)
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040017903{ # compare two versions in dotted-numeric format
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017904 my ($V1, $V2) = @_;
17905 return 0 if($V1 eq $V2);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017906 my @V1Parts = split(/\./, $V1);
17907 my @V2Parts = split(/\./, $V2);
Andrey Ponomarenko570ece52012-11-30 16:36:44 +040017908 for (my $i = 0; $i <= $#V1Parts && $i <= $#V2Parts; $i++)
17909 {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017910 return -1 if(int($V1Parts[$i]) < int($V2Parts[$i]));
17911 return 1 if(int($V1Parts[$i]) > int($V2Parts[$i]));
17912 }
17913 return -1 if($#V1Parts < $#V2Parts);
17914 return 1 if($#V1Parts > $#V2Parts);
17915 return 0;
17916}
17917
17918sub read_ABI_Dump($$)
17919{
17920 my ($LibVersion, $Path) = @_;
17921 return if(not $LibVersion or not -e $Path);
17922 my $FilePath = "";
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040017923 if(isDump_U($Path))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017924 { # input *.abi
17925 $FilePath = $Path;
17926 }
17927 else
17928 { # input *.abi.tar.gz
17929 $FilePath = unpackDump($Path);
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040017930 if(not isDump_U($FilePath)) {
17931 exitStatus("Invalid_Dump", "specified ABI dump \'$Path\' is not valid, try to recreate it");
17932 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017933 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +040017934
Andrey Ponomarenko01117f12012-06-26 12:23:02 +040017935 my $ABI = {};
Andrey Ponomarenko5c09ef32012-06-14 18:17:33 +040017936
Andrey Ponomarenko01117f12012-06-26 12:23:02 +040017937 my $Line = readLineNum($FilePath, 0);
17938 if($Line=~/xml/)
17939 { # XML format
17940 loadModule("XmlDump");
17941 $ABI = readXmlDump($FilePath);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017942 }
Andrey Ponomarenko01117f12012-06-26 12:23:02 +040017943 else
17944 { # Perl Data::Dumper format (default)
17945 open(DUMP, $FilePath);
17946 local $/ = undef;
17947 my $Content = <DUMP>;
17948 close(DUMP);
17949
17950 if(get_dirname($FilePath) eq $TMP_DIR."/unpack")
17951 { # remove temp file
17952 unlink($FilePath);
17953 }
17954 if($Content!~/};\s*\Z/) {
17955 exitStatus("Invalid_Dump", "specified ABI dump \'$Path\' is not valid, try to recreate it");
17956 }
17957 $ABI = eval($Content);
17958 if(not $ABI) {
17959 exitStatus("Error", "internal error - eval() procedure seem to not working correctly, try to remove 'use strict' and try again");
17960 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017961 }
17962 # new dumps (>=1.22) have a personal versioning
Andrey Ponomarenko570ece52012-11-30 16:36:44 +040017963 my $DVersion = $ABI->{"ABI_DUMP_VERSION"};
Andrey Ponomarenko01117f12012-06-26 12:23:02 +040017964 my $ToolVersion = $ABI->{"ABI_COMPLIANCE_CHECKER_VERSION"};
Andrey Ponomarenko570ece52012-11-30 16:36:44 +040017965 if(not $DVersion)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017966 { # old dumps (<=1.21.6) have been marked by the tool version
Andrey Ponomarenko570ece52012-11-30 16:36:44 +040017967 $DVersion = $ToolVersion;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017968 }
Andrey Ponomarenko570ece52012-11-30 16:36:44 +040017969 $UsedDump{$LibVersion}{"V"} = $DVersion;
17970 if(majorVersion($DVersion) ne majorVersion($ABI_DUMP_VERSION))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017971 { # should be compatible with dumps of the same major version
Andrey Ponomarenko570ece52012-11-30 16:36:44 +040017972 if(cmpVersions($DVersion, $ABI_DUMP_VERSION)>0)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017973 { # Don't know how to parse future dump formats
Andrey Ponomarenko570ece52012-11-30 16:36:44 +040017974 exitStatus("Dump_Version", "incompatible version \'$DVersion\' of specified ABI dump (newer than $ABI_DUMP_VERSION)");
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017975 }
Andrey Ponomarenko570ece52012-11-30 16:36:44 +040017976 elsif(cmpVersions($DVersion, $TOOL_VERSION)>0 and not $ABI->{"ABI_DUMP_VERSION"})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017977 { # Don't know how to parse future dump formats
Andrey Ponomarenko570ece52012-11-30 16:36:44 +040017978 exitStatus("Dump_Version", "incompatible version \'$DVersion\' of specified ABI dump (newer than $TOOL_VERSION)");
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017979 }
17980 if($UseOldDumps)
17981 {
Andrey Ponomarenko570ece52012-11-30 16:36:44 +040017982 if(cmpVersions($DVersion, $OLDEST_SUPPORTED_VERSION)<0) {
17983 exitStatus("Dump_Version", "incompatible version \'$DVersion\' of specified ABI dump (older than $OLDEST_SUPPORTED_VERSION)");
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017984 }
17985 }
17986 else
17987 {
Andrey Ponomarenko570ece52012-11-30 16:36:44 +040017988 my $Msg = "incompatible version \'$DVersion\' of specified ABI dump (allowed only ".majorVersion($ABI_DUMP_VERSION).".0<=V<=$ABI_DUMP_VERSION)";
17989 if(cmpVersions($DVersion, $OLDEST_SUPPORTED_VERSION)>=0) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017990 $Msg .= "\nUse -old-dumps option to use old-version dumps ($OLDEST_SUPPORTED_VERSION<=V<".majorVersion($ABI_DUMP_VERSION).".0)";
17991 }
17992 exitStatus("Dump_Version", $Msg);
17993 }
17994 }
Andrey Ponomarenko5c09ef32012-06-14 18:17:33 +040017995 if(not checkDump($LibVersion, "2.11"))
17996 { # old ABI dumps
17997 $UsedDump{$LibVersion}{"BinOnly"} = 1;
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040017998 }
Andrey Ponomarenko01117f12012-06-26 12:23:02 +040017999 elsif($ABI->{"BinOnly"})
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040018000 { # ABI dump created with --binary option
18001 $UsedDump{$LibVersion}{"BinOnly"} = 1;
18002 }
Andrey Ponomarenko5c09ef32012-06-14 18:17:33 +040018003 else
18004 { # default
18005 $UsedDump{$LibVersion}{"SrcBin"} = 1;
18006 }
Andrey Ponomarenko01117f12012-06-26 12:23:02 +040018007 if(defined $ABI->{"Mode"}
18008 and $ABI->{"Mode"} eq "Extended")
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040018009 { # --ext option
18010 $ExtendedCheck = 1;
18011 }
Andrey Ponomarenko01117f12012-06-26 12:23:02 +040018012 if(my $Lang = $ABI->{"Language"})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040018013 {
18014 $UsedDump{$LibVersion}{"L"} = $Lang;
18015 setLanguage($LibVersion, $Lang);
18016 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040018017 if(checkDump($LibVersion, "2.15")) {
Andrey Ponomarenko01117f12012-06-26 12:23:02 +040018018 $TypeInfo{$LibVersion} = $ABI->{"TypeInfo"};
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040018019 }
18020 else
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040018021 { # support for old ABI dumps
Andrey Ponomarenko01117f12012-06-26 12:23:02 +040018022 my $TInfo = $ABI->{"TypeInfo"};
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040018023 if(not $TInfo)
18024 { # support for older ABI dumps
Andrey Ponomarenko01117f12012-06-26 12:23:02 +040018025 $TInfo = $ABI->{"TypeDescr"};
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040018026 }
18027 my %Tid_TDid = ();
18028 foreach my $TDid (keys(%{$TInfo}))
18029 {
18030 foreach my $Tid (keys(%{$TInfo->{$TDid}}))
18031 {
18032 $MAX_ID = $Tid if($Tid>$MAX_ID);
18033 $MAX_ID = $TDid if($TDid and $TDid>$MAX_ID);
18034 $Tid_TDid{$Tid}{$TDid}=1;
18035 }
18036 }
18037 my %NewID = ();
18038 foreach my $Tid (keys(%Tid_TDid))
18039 {
18040 my @TDids = keys(%{$Tid_TDid{$Tid}});
18041 if($#TDids>=1)
18042 {
18043 foreach my $TDid (@TDids)
18044 {
18045 if($TDid) {
18046 %{$TypeInfo{$LibVersion}{$Tid}} = %{$TInfo->{$TDid}{$Tid}};
18047 }
18048 else
18049 {
18050 if(my $ID = ++$MAX_ID)
18051 {
18052 $NewID{$TDid}{$Tid} = $ID;
18053 %{$TypeInfo{$LibVersion}{$ID}} = %{$TInfo->{$TDid}{$Tid}};
18054 $TypeInfo{$LibVersion}{$ID}{"Tid"} = $ID;
18055 }
18056 }
18057 }
18058 }
18059 else
18060 {
18061 my $TDid = $TDids[0];
18062 %{$TypeInfo{$LibVersion}{$Tid}} = %{$TInfo->{$TDid}{$Tid}};
18063 }
18064 }
18065 foreach my $Tid (keys(%{$TypeInfo{$LibVersion}}))
18066 {
18067 my %Info = %{$TypeInfo{$LibVersion}{$Tid}};
18068 if(defined $Info{"BaseType"})
18069 {
18070 my $Bid = $Info{"BaseType"}{"Tid"};
18071 my $BDid = $Info{"BaseType"}{"TDid"};
18072 $BDid="" if(not defined $BDid);
18073 if(defined $NewID{$BDid} and my $ID = $NewID{$BDid}{$Bid}) {
18074 $TypeInfo{$LibVersion}{$Tid}{"BaseType"}{"Tid"} = $ID;
18075 }
18076 delete($TypeInfo{$LibVersion}{$Tid}{"BaseType"}{"TDid"});
18077 }
18078 delete($TypeInfo{$LibVersion}{$Tid}{"TDid"});
18079 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040018080 }
Andrey Ponomarenko01117f12012-06-26 12:23:02 +040018081 read_Machine_DumpInfo($ABI, $LibVersion);
18082 $SymbolInfo{$LibVersion} = $ABI->{"SymbolInfo"};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040018083 if(not $SymbolInfo{$LibVersion})
18084 { # support for old dumps
Andrey Ponomarenko01117f12012-06-26 12:23:02 +040018085 $SymbolInfo{$LibVersion} = $ABI->{"FuncDescr"};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040018086 }
18087 if(not keys(%{$SymbolInfo{$LibVersion}}))
18088 { # validation of old-version dumps
18089 if(not $ExtendedCheck) {
18090 exitStatus("Invalid_Dump", "the input dump d$LibVersion is invalid");
18091 }
18092 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040018093 if(checkDump($LibVersion, "2.15")) {
Andrey Ponomarenko01117f12012-06-26 12:23:02 +040018094 $DepLibrary_Symbol{$LibVersion} = $ABI->{"DepSymbols"};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040018095 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040018096 else
18097 { # support for old ABI dumps
Andrey Ponomarenko01117f12012-06-26 12:23:02 +040018098 my $DepSymbols = $ABI->{"DepSymbols"};
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040018099 if(not $DepSymbols) {
Andrey Ponomarenko01117f12012-06-26 12:23:02 +040018100 $DepSymbols = $ABI->{"DepInterfaces"};
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040018101 }
18102 if(not $DepSymbols)
18103 { # Cannot reconstruct DepSymbols. This may result in false
18104 # positives if the old dump is for library 2. Not a problem if
18105 # old dumps are only from old libraries.
18106 $DepSymbols = {};
18107 }
18108 foreach my $Symbol (keys(%{$DepSymbols})) {
18109 $DepSymbol_Library{$LibVersion}{$Symbol} = 1;
18110 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040018111 }
Andrey Ponomarenko01117f12012-06-26 12:23:02 +040018112 $SymVer{$LibVersion} = $ABI->{"SymbolVersion"};
18113 $Descriptor{$LibVersion}{"Version"} = $ABI->{"LibraryVersion"};
18114 $SkipTypes{$LibVersion} = $ABI->{"SkipTypes"};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040018115 if(not $SkipTypes{$LibVersion})
18116 { # support for old dumps
Andrey Ponomarenko01117f12012-06-26 12:23:02 +040018117 $SkipTypes{$LibVersion} = $ABI->{"OpaqueTypes"};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040018118 }
Andrey Ponomarenko01117f12012-06-26 12:23:02 +040018119 $SkipSymbols{$LibVersion} = $ABI->{"SkipSymbols"};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040018120 if(not $SkipSymbols{$LibVersion})
18121 { # support for old dumps
Andrey Ponomarenko01117f12012-06-26 12:23:02 +040018122 $SkipSymbols{$LibVersion} = $ABI->{"SkipInterfaces"};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040018123 }
18124 if(not $SkipSymbols{$LibVersion})
18125 { # support for old dumps
Andrey Ponomarenko01117f12012-06-26 12:23:02 +040018126 $SkipSymbols{$LibVersion} = $ABI->{"InternalInterfaces"};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040018127 }
Andrey Ponomarenko01117f12012-06-26 12:23:02 +040018128 $SkipNameSpaces{$LibVersion} = $ABI->{"SkipNameSpaces"};
18129 $TargetHeaders{$LibVersion} = $ABI->{"TargetHeaders"};
18130 foreach my $Path (keys(%{$ABI->{"SkipHeaders"}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040018131 {
Andrey Ponomarenko01117f12012-06-26 12:23:02 +040018132 $SkipHeadersList{$LibVersion}{$Path} = $ABI->{"SkipHeaders"}{$Path};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040018133 my ($CPath, $Type) = classifyPath($Path);
Andrey Ponomarenko01117f12012-06-26 12:23:02 +040018134 $SkipHeaders{$LibVersion}{$Type}{$CPath} = $ABI->{"SkipHeaders"}{$Path};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040018135 }
Andrey Ponomarenko01117f12012-06-26 12:23:02 +040018136 read_Headers_DumpInfo($ABI, $LibVersion);
18137 read_Libs_DumpInfo($ABI, $LibVersion);
Andrey Ponomarenko5c09ef32012-06-14 18:17:33 +040018138 if(not checkDump($LibVersion, "2.10.1")
18139 or not $TargetHeaders{$LibVersion})
Andrey Ponomarenko85043792012-05-14 16:48:07 +040018140 { # support for old ABI dumps: added target headers
18141 foreach (keys(%{$Registered_Headers{$LibVersion}})) {
18142 $TargetHeaders{$LibVersion}{get_filename($_)}=1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040018143 }
18144 }
Andrey Ponomarenko01117f12012-06-26 12:23:02 +040018145 $Constants{$LibVersion} = $ABI->{"Constants"};
18146 $NestedNameSpaces{$LibVersion} = $ABI->{"NameSpaces"};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040018147 if(not $NestedNameSpaces{$LibVersion})
18148 { # support for old dumps
18149 # Cannot reconstruct NameSpaces. This may affect design
18150 # of the compatibility report.
18151 $NestedNameSpaces{$LibVersion} = {};
18152 }
18153 # target system type
18154 # needed to adopt HTML report
18155 if(not $DumpSystem)
18156 { # to use in createSymbolsList(...)
Andrey Ponomarenko01117f12012-06-26 12:23:02 +040018157 $OStarget = $ABI->{"Target"};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040018158 }
18159 # recreate environment
18160 foreach my $Lib_Name (keys(%{$Library_Symbol{$LibVersion}}))
18161 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040018162 foreach my $Symbol (keys(%{$Library_Symbol{$LibVersion}{$Lib_Name}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040018163 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040018164 $Symbol_Library{$LibVersion}{$Symbol} = $Lib_Name;
18165 if($Library_Symbol{$LibVersion}{$Lib_Name}{$Symbol}<=-1)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040018166 { # data marked as -size in the dump
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040018167 $GlobalDataObject{$LibVersion}{$Symbol}=1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040018168 }
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040018169 if($COMMON_LANGUAGE{$LibVersion} ne "C++")
18170 {
18171 if(index($Symbol, "_Z")==0 or index($Symbol, "?")==0) {
18172 setLanguage($LibVersion, "C++");
18173 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040018174 }
18175 }
18176 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040018177 foreach my $Lib_Name (keys(%{$DepLibrary_Symbol{$LibVersion}}))
18178 {
18179 foreach my $Symbol (keys(%{$DepLibrary_Symbol{$LibVersion}{$Lib_Name}})) {
18180 $DepSymbol_Library{$LibVersion}{$Symbol} = $Lib_Name;
18181 }
18182 }
18183
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040018184 my @VFunc = ();
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040018185 foreach my $InfoId (keys(%{$SymbolInfo{$LibVersion}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040018186 {
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +040018187 if(my $MnglName = $SymbolInfo{$LibVersion}{$InfoId}{"MnglName"})
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040018188 {
18189 if(not $Symbol_Library{$LibVersion}{$MnglName}
18190 and not $DepSymbol_Library{$LibVersion}{$MnglName}) {
18191 push(@VFunc, $MnglName);
18192 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040018193 }
18194 }
18195 translateSymbols(@VFunc, $LibVersion);
18196 translateSymbols(keys(%{$Symbol_Library{$LibVersion}}), $LibVersion);
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040018197 translateSymbols(keys(%{$DepSymbol_Library{$LibVersion}}), $LibVersion);
18198
18199 foreach my $TypeId (sort {int($a)<=>int($b)} keys(%{$TypeInfo{$LibVersion}}))
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +040018200 { # order is important
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040018201 if(defined $TypeInfo{$LibVersion}{$TypeId}{"BaseClass"})
18202 { # support for old ABI dumps < 2.0 (ACC 1.22)
18203 foreach my $BId (keys(%{$TypeInfo{$LibVersion}{$TypeId}{"BaseClass"}}))
18204 {
18205 if(my $Access = $TypeInfo{$LibVersion}{$TypeId}{"BaseClass"}{$BId})
18206 {
18207 if($Access ne "public") {
18208 $TypeInfo{$LibVersion}{$TypeId}{"Base"}{$BId}{"access"} = $Access;
18209 }
18210 }
18211 $TypeInfo{$LibVersion}{$TypeId}{"Base"}{$BId} = {};
18212 }
18213 delete($TypeInfo{$LibVersion}{$TypeId}{"BaseClass"});
18214 }
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040018215 if(my $Header = $TypeInfo{$LibVersion}{$TypeId}{"Header"})
18216 { # support for old ABI dumps
18217 $TypeInfo{$LibVersion}{$TypeId}{"Header"} = path_format($Header, $OSgroup);
18218 }
Andrey Ponomarenko01117f12012-06-26 12:23:02 +040018219 if(not defined $TypeInfo{$LibVersion}{$TypeId}{"Tid"}) {
18220 $TypeInfo{$LibVersion}{$TypeId}{"Tid"} = $TypeId;
18221 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040018222 my %TInfo = %{$TypeInfo{$LibVersion}{$TypeId}};
18223 if(defined $TInfo{"Base"})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040018224 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040018225 foreach (keys(%{$TInfo{"Base"}})) {
18226 $Class_SubClasses{$LibVersion}{$_}{$TypeId}=1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040018227 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040018228 }
Andrey Ponomarenko01117f12012-06-26 12:23:02 +040018229 if($TInfo{"Type"} eq "MethodPtr")
18230 {
18231 if(defined $TInfo{"Param"})
18232 { # support for old ABI dumps <= 1.17
18233 if(not defined $TInfo{"Param"}{"0"})
18234 {
18235 my $Max = keys(%{$TInfo{"Param"}});
18236 foreach my $Pos (1 .. $Max) {
18237 $TInfo{"Param"}{$Pos-1} = $TInfo{"Param"}{$Pos};
18238 }
18239 delete($TInfo{"Param"}{$Max});
18240 %{$TypeInfo{$LibVersion}{$TypeId}} = %TInfo;
18241 }
18242 }
18243 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040018244 if($TInfo{"Type"} eq "Typedef" and defined $TInfo{"BaseType"})
18245 {
18246 if(my $BTid = $TInfo{"BaseType"}{"Tid"})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040018247 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040018248 my $BName = $TypeInfo{$LibVersion}{$BTid}{"Name"};
18249 if(not $BName)
18250 { # broken type
18251 next;
18252 }
18253 if($TInfo{"Name"} eq $BName)
18254 { # typedef to "class Class"
18255 # should not be registered in TName_Tid
18256 next;
18257 }
18258 if(not $Typedef_BaseName{$LibVersion}{$TInfo{"Name"}}) {
18259 $Typedef_BaseName{$LibVersion}{$TInfo{"Name"}} = $BName;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040018260 }
18261 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040018262 }
18263 if(not $TName_Tid{$LibVersion}{$TInfo{"Name"}})
18264 { # classes: class (id1), typedef (artificial, id2 > id1)
18265 $TName_Tid{$LibVersion}{$TInfo{"Name"}} = $TypeId;
18266 }
18267 }
18268
18269 if(not checkDump($LibVersion, "2.15"))
18270 { # support for old ABI dumps
18271 my %Dups = ();
18272 foreach my $InfoId (keys(%{$SymbolInfo{$LibVersion}}))
18273 {
18274 if(my $ClassId = $SymbolInfo{$LibVersion}{$InfoId}{"Class"})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040018275 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040018276 if(not defined $TypeInfo{$LibVersion}{$ClassId})
18277 { # remove template decls
18278 delete($SymbolInfo{$LibVersion}{$InfoId});
18279 next;
Andrey Ponomarenko16934472012-03-29 15:37:04 +040018280 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040018281 }
Andrey Ponomarenkob8d203d2012-05-25 18:11:07 +040018282 my $MName = $SymbolInfo{$LibVersion}{$InfoId}{"MnglName"};
18283 if(not $MName and $SymbolInfo{$LibVersion}{$InfoId}{"Class"})
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040018284 { # templates
18285 delete($SymbolInfo{$LibVersion}{$InfoId});
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040018286 }
18287 }
18288 }
18289
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +040018290 foreach my $InfoId (keys(%{$SymbolInfo{$LibVersion}}))
18291 {
18292 if(not $SymbolInfo{$LibVersion}{$InfoId}{"MnglName"})
18293 { # ABI dumps have no mangled names for C-functions
18294 $SymbolInfo{$LibVersion}{$InfoId}{"MnglName"} = $SymbolInfo{$LibVersion}{$InfoId}{"ShortName"};
18295 }
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040018296 if(my $Header = $SymbolInfo{$LibVersion}{$InfoId}{"Header"})
18297 { # support for old ABI dumps
18298 $SymbolInfo{$LibVersion}{$InfoId}{"Header"} = path_format($Header, $OSgroup);
18299 }
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +040018300 }
18301
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040018302 $Descriptor{$LibVersion}{"Dump"} = 1;
18303}
18304
18305sub read_Machine_DumpInfo($$)
18306{
Andrey Ponomarenko01117f12012-06-26 12:23:02 +040018307 my ($ABI, $LibVersion) = @_;
18308 if($ABI->{"Arch"}) {
18309 $CPU_ARCH{$LibVersion} = $ABI->{"Arch"};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040018310 }
Andrey Ponomarenko01117f12012-06-26 12:23:02 +040018311 if($ABI->{"WordSize"}) {
18312 $WORD_SIZE{$LibVersion} = $ABI->{"WordSize"};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040018313 }
18314 else
18315 { # support for old dumps
Andrey Ponomarenko01117f12012-06-26 12:23:02 +040018316 $WORD_SIZE{$LibVersion} = $ABI->{"SizeOfPointer"};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040018317 }
18318 if(not $WORD_SIZE{$LibVersion})
18319 { # support for old dumps (<1.23)
18320 if(my $Tid = getTypeIdByName("char*", $LibVersion))
18321 { # size of char*
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040018322 $WORD_SIZE{$LibVersion} = $TypeInfo{$LibVersion}{$Tid}{"Size"};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040018323 }
18324 else
18325 {
18326 my $PSize = 0;
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040018327 foreach my $Tid (keys(%{$TypeInfo{$LibVersion}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040018328 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040018329 if($TypeInfo{$LibVersion}{$Tid}{"Type"} eq "Pointer")
18330 { # any "pointer"-type
18331 $PSize = $TypeInfo{$LibVersion}{$Tid}{"Size"};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040018332 last;
18333 }
18334 }
18335 if($PSize)
18336 { # a pointer type size
18337 $WORD_SIZE{$LibVersion} = $PSize;
18338 }
18339 else {
18340 printMsg("WARNING", "cannot identify a WORD size in the ABI dump (too old format)");
18341 }
18342 }
18343 }
Andrey Ponomarenko01117f12012-06-26 12:23:02 +040018344 if($ABI->{"GccVersion"}) {
18345 $GCC_VERSION{$LibVersion} = $ABI->{"GccVersion"};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040018346 }
18347}
18348
18349sub read_Libs_DumpInfo($$)
18350{
Andrey Ponomarenko01117f12012-06-26 12:23:02 +040018351 my ($ABI, $LibVersion) = @_;
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040018352 $Library_Symbol{$LibVersion} = $ABI->{"Symbols"};
18353 if(not $Library_Symbol{$LibVersion})
18354 { # support for old dumps
18355 $Library_Symbol{$LibVersion} = $ABI->{"Interfaces"};
18356 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040018357 if(keys(%{$Library_Symbol{$LibVersion}})
18358 and not $DumpAPI) {
18359 $Descriptor{$LibVersion}{"Libs"} = "OK";
18360 }
18361}
18362
18363sub read_Headers_DumpInfo($$)
18364{
Andrey Ponomarenko01117f12012-06-26 12:23:02 +040018365 my ($ABI, $LibVersion) = @_;
18366 if(keys(%{$ABI->{"Headers"}})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040018367 and not $DumpAPI) {
18368 $Descriptor{$LibVersion}{"Headers"} = "OK";
18369 }
Andrey Ponomarenko01117f12012-06-26 12:23:02 +040018370 foreach my $Identity (sort {$ABI->{"Headers"}{$a}<=>$ABI->{"Headers"}{$b}} keys(%{$ABI->{"Headers"}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040018371 { # headers info is stored in the old dumps in the different way
18372 if($UseOldDumps
Andrey Ponomarenko01117f12012-06-26 12:23:02 +040018373 and my $Name = $ABI->{"Headers"}{$Identity}{"Name"})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040018374 { # support for old dumps: headers info corrected in 1.22
18375 $Identity = $Name;
18376 }
18377 $Registered_Headers{$LibVersion}{$Identity}{"Identity"} = $Identity;
Andrey Ponomarenko01117f12012-06-26 12:23:02 +040018378 $Registered_Headers{$LibVersion}{$Identity}{"Pos"} = $ABI->{"Headers"}{$Identity};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040018379 }
18380}
18381
18382sub find_libs($$$)
18383{
18384 my ($Path, $Type, $MaxDepth) = @_;
18385 # FIXME: correct the search pattern
Andrey Ponomarenko570ece52012-11-30 16:36:44 +040018386 return cmd_find($Path, $Type, ".*\\.".$LIB_EXT."[0-9.]*", $MaxDepth, 1);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040018387}
18388
18389sub createDescriptor($$)
18390{
18391 my ($LibVersion, $Path) = @_;
18392 if(not $LibVersion or not $Path
18393 or not -e $Path) {
18394 return "";
18395 }
18396 if(-d $Path)
18397 { # directory with headers files and shared objects
18398 return "
18399 <version>
18400 ".$TargetVersion{$LibVersion}."
18401 </version>
18402
18403 <headers>
18404 $Path
18405 </headers>
18406
18407 <libs>
18408 $Path
18409 </libs>";
18410 }
18411 else
18412 { # files
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040018413 if($Path=~/\.(xml|desc)\Z/i)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040018414 { # standard XML-descriptor
18415 return readFile($Path);
18416 }
18417 elsif(is_header($Path, 2, $LibVersion))
18418 { # header file
18419 return "
18420 <version>
18421 ".$TargetVersion{$LibVersion}."
18422 </version>
18423
18424 <headers>
18425 $Path
18426 </headers>
18427
18428 <libs>
18429 none
18430 </libs>";
18431 }
18432 elsif(parse_libname($Path, "name", $OStarget))
18433 { # shared object
18434 return "
18435 <version>
18436 ".$TargetVersion{$LibVersion}."
18437 </version>
18438
18439 <headers>
18440 none
18441 </headers>
18442
18443 <libs>
18444 $Path
18445 </libs>";
18446 }
18447 else
18448 { # standard XML-descriptor
18449 return readFile($Path);
18450 }
18451 }
18452}
18453
18454sub detect_lib_default_paths()
18455{
18456 my %LPaths = ();
18457 if($OSgroup eq "bsd")
18458 {
Andrey Ponomarenkoa01311b2012-06-08 17:20:02 +040018459 if(my $LdConfig = get_CmdPath("ldconfig"))
18460 {
18461 foreach my $Line (split(/\n/, `$LdConfig -r 2>\"$TMP_DIR/null\"`))
18462 {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040018463 if($Line=~/\A[ \t]*\d+:\-l(.+) \=\> (.+)\Z/) {
18464 $LPaths{"lib".$1} = $2;
18465 }
18466 }
18467 }
18468 else {
18469 printMsg("WARNING", "can't find ldconfig");
18470 }
18471 }
18472 else
18473 {
18474 if(my $LdConfig = get_CmdPath("ldconfig"))
18475 {
18476 if($SystemRoot and $OSgroup eq "linux")
18477 { # use host (x86) ldconfig with the target (arm) ld.so.conf
18478 if(-e $SystemRoot."/etc/ld.so.conf") {
18479 $LdConfig .= " -f ".$SystemRoot."/etc/ld.so.conf";
18480 }
18481 }
Andrey Ponomarenkoa01311b2012-06-08 17:20:02 +040018482 foreach my $Line (split(/\n/, `$LdConfig -p 2>\"$TMP_DIR/null\"`))
18483 {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040018484 if($Line=~/\A[ \t]*([^ \t]+) .* \=\> (.+)\Z/)
18485 {
18486 my ($Name, $Path) = ($1, $2);
18487 $Path=~s/[\/]{2,}/\//;
18488 $LPaths{$Name} = $Path;
18489 }
18490 }
18491 }
Andrey Ponomarenko82b005f2012-11-12 17:58:14 +040018492 elsif($OSgroup eq "linux") {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040018493 printMsg("WARNING", "can't find ldconfig");
18494 }
18495 }
18496 return \%LPaths;
18497}
18498
18499sub detect_bin_default_paths()
18500{
18501 my $EnvPaths = $ENV{"PATH"};
18502 if($OSgroup eq "beos") {
18503 $EnvPaths.=":".$ENV{"BETOOLS"};
18504 }
18505 my $Sep = ($OSgroup eq "windows")?";":":|;";
Andrey Ponomarenko570ece52012-11-30 16:36:44 +040018506 foreach my $Path (split(/$Sep/, $EnvPaths))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040018507 {
18508 $Path = path_format($Path, $OSgroup);
18509 $Path=~s/[\/\\]+\Z//g;
18510 next if(not $Path);
18511 if($SystemRoot
18512 and $Path=~/\A\Q$SystemRoot\E\//)
18513 { # do NOT use binaries from target system
18514 next;
18515 }
Andrey Ponomarenko570ece52012-11-30 16:36:44 +040018516 push_U(\@DefaultBinPaths, $Path);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040018517 }
18518}
18519
18520sub detect_inc_default_paths()
18521{
18522 return () if(not $GCC_PATH);
Andrey Ponomarenko570ece52012-11-30 16:36:44 +040018523 my %DPaths = ("Cpp"=>[],"Gcc"=>[],"Inc"=>[]);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040018524 writeFile("$TMP_DIR/empty.h", "");
Andrey Ponomarenkoa01311b2012-06-08 17:20:02 +040018525 foreach my $Line (split(/\n/, `$GCC_PATH -v -x c++ -E \"$TMP_DIR/empty.h\" 2>&1`))
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040018526 { # detecting GCC default include paths
Andrey Ponomarenko570ece52012-11-30 16:36:44 +040018527 next if(index($Line, "/cc1plus ")!=-1);
18528
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040018529 if($Line=~/\A[ \t]*((\/|\w+:\\).+)[ \t]*\Z/)
18530 {
18531 my $Path = simplify_path($1);
Andrey Ponomarenko570ece52012-11-30 16:36:44 +040018532 $Path=~s/[\/\\]+\.?\Z//g;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040018533 $Path = path_format($Path, $OSgroup);
Andrey Ponomarenko570ece52012-11-30 16:36:44 +040018534 if(index($Path, "c++")!=-1
18535 or index($Path, "/g++/")!=-1)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040018536 {
Andrey Ponomarenko570ece52012-11-30 16:36:44 +040018537 push_U($DPaths{"Cpp"}, $Path);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040018538 if(not defined $MAIN_CPP_DIR
18539 or get_depth($MAIN_CPP_DIR)>get_depth($Path)) {
18540 $MAIN_CPP_DIR = $Path;
18541 }
18542 }
Andrey Ponomarenko570ece52012-11-30 16:36:44 +040018543 elsif(index($Path, "gcc")!=-1) {
18544 push_U($DPaths{"Gcc"}, $Path);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040018545 }
18546 else
18547 {
Andrey Ponomarenko570ece52012-11-30 16:36:44 +040018548 if($Path=~/local[\/\\]+include/)
18549 { # local paths
18550 next;
18551 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040018552 if($SystemRoot
18553 and $Path!~/\A\Q$SystemRoot\E(\/|\Z)/)
18554 { # The GCC include path for user headers is not a part of the system root
18555 # The reason: you are not specified the --cross-gcc option or selected a wrong compiler
18556 # or it is the internal cross-GCC path like arm-linux-gnueabi/include
18557 next;
18558 }
Andrey Ponomarenko570ece52012-11-30 16:36:44 +040018559 push_U($DPaths{"Inc"}, $Path);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040018560 }
18561 }
18562 }
18563 unlink("$TMP_DIR/empty.h");
18564 return %DPaths;
18565}
18566
18567sub detect_default_paths($)
18568{
18569 my ($HSearch, $LSearch, $BSearch, $GSearch) = (1, 1, 1, 1);
18570 my $Search = $_[0];
18571 if($Search!~/inc/) {
18572 $HSearch = 0;
18573 }
18574 if($Search!~/lib/) {
18575 $LSearch = 0;
18576 }
18577 if($Search!~/bin/) {
18578 $BSearch = 0;
18579 }
18580 if($Search!~/gcc/) {
18581 $GSearch = 0;
18582 }
Andrey Ponomarenko570ece52012-11-30 16:36:44 +040018583 if(@{$SystemPaths{"include"}})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040018584 { # <search_headers> section of the XML descriptor
18585 # do NOT search for systems headers
18586 $HSearch = 0;
18587 }
Andrey Ponomarenko570ece52012-11-30 16:36:44 +040018588 if(@{$SystemPaths{"lib"}})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040018589 { # <search_headers> section of the XML descriptor
18590 # do NOT search for systems headers
18591 $LSearch = 0;
18592 }
18593 foreach my $Type (keys(%{$OS_AddPath{$OSgroup}}))
18594 { # additional search paths
18595 next if($Type eq "include" and not $HSearch);
18596 next if($Type eq "lib" and not $LSearch);
18597 next if($Type eq "bin" and not $BSearch);
Andrey Ponomarenko570ece52012-11-30 16:36:44 +040018598 push_U($SystemPaths{$Type}, grep { -d $_ } @{$OS_AddPath{$OSgroup}{$Type}});
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040018599 }
18600 if($OSgroup ne "windows")
18601 { # unix-like
18602 foreach my $Type ("include", "lib", "bin")
18603 { # automatic detection of system "devel" directories
18604 next if($Type eq "include" and not $HSearch);
18605 next if($Type eq "lib" and not $LSearch);
18606 next if($Type eq "bin" and not $BSearch);
18607 my ($UsrDir, $RootDir) = ("/usr", "/");
18608 if($SystemRoot and $Type ne "bin")
18609 { # 1. search for target headers and libraries
18610 # 2. use host commands: ldconfig, readelf, etc.
18611 ($UsrDir, $RootDir) = ("$SystemRoot/usr", $SystemRoot);
18612 }
Andrey Ponomarenko570ece52012-11-30 16:36:44 +040018613 push_U($SystemPaths{$Type}, cmd_find($RootDir,"d","*$Type*",1));
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040018614 if(-d $RootDir."/".$Type)
18615 { # if "/lib" is symbolic link
18616 if($RootDir eq "/") {
Andrey Ponomarenko570ece52012-11-30 16:36:44 +040018617 push_U($SystemPaths{$Type}, "/".$Type);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040018618 }
18619 else {
Andrey Ponomarenko570ece52012-11-30 16:36:44 +040018620 push_U($SystemPaths{$Type}, $RootDir."/".$Type);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040018621 }
18622 }
Andrey Ponomarenko570ece52012-11-30 16:36:44 +040018623 if(-d $UsrDir)
18624 {
18625 push_U($SystemPaths{$Type}, cmd_find($UsrDir,"d","*$Type*",1));
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040018626 if(-d $UsrDir."/".$Type)
18627 { # if "/usr/lib" is symbolic link
Andrey Ponomarenko570ece52012-11-30 16:36:44 +040018628 push_U($SystemPaths{$Type}, $UsrDir."/".$Type);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040018629 }
18630 }
18631 }
18632 }
18633 if($BSearch)
18634 {
18635 detect_bin_default_paths();
Andrey Ponomarenko570ece52012-11-30 16:36:44 +040018636 push_U($SystemPaths{"bin"}, @DefaultBinPaths);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040018637 }
18638 # check environment variables
18639 if($OSgroup eq "beos")
18640 {
Andrey Ponomarenko4b077f82012-12-04 16:04:36 +040018641 foreach (my @Paths = @{$SystemPaths{"bin"}})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040018642 {
Andrey Ponomarenko4b077f82012-12-04 16:04:36 +040018643 if($_ eq ".") {
18644 next;
18645 }
18646 # search for /boot/develop/abi/x86/gcc4/tools/gcc-4.4.4-haiku-101111/bin/
18647 if(my @Dirs = sort cmd_find($_, "d", "bin")) {
18648 push_U($SystemPaths{"bin"}, sort {get_depth($a)<=>get_depth($b)} @Dirs);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040018649 }
18650 }
18651 if($HSearch)
18652 {
Andrey Ponomarenko570ece52012-11-30 16:36:44 +040018653 push_U(\@DefaultIncPaths, grep { is_abs($_) } (
18654 split(/:|;/, $ENV{"BEINCLUDES"})
18655 ));
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040018656 }
18657 if($LSearch)
18658 {
Andrey Ponomarenko570ece52012-11-30 16:36:44 +040018659 push_U(\@DefaultLibPaths, grep { is_abs($_) } (
18660 split(/:|;/, $ENV{"BELIBRARIES"}),
18661 split(/:|;/, $ENV{"LIBRARY_PATH"})
18662 ));
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040018663 }
18664 }
18665 if($LSearch)
18666 { # using linker to get system paths
18667 if(my $LPaths = detect_lib_default_paths())
18668 { # unix-like
Andrey Ponomarenko570ece52012-11-30 16:36:44 +040018669 my %Dirs = ();
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040018670 foreach my $Name (keys(%{$LPaths}))
18671 {
18672 if($SystemRoot
18673 and $LPaths->{$Name}!~/\A\Q$SystemRoot\E\//)
18674 { # wrong ldconfig configuration
18675 # check your <sysroot>/etc/ld.so.conf
18676 next;
18677 }
18678 $DyLib_DefaultPath{$Name} = $LPaths->{$Name};
Andrey Ponomarenko570ece52012-11-30 16:36:44 +040018679 if(my $Dir = get_dirname($LPaths->{$Name})) {
18680 $Dirs{$Dir} = 1;
18681 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040018682 }
Andrey Ponomarenko570ece52012-11-30 16:36:44 +040018683 push_U(\@DefaultLibPaths, sort {get_depth($a)<=>get_depth($b)} sort keys(%Dirs));
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040018684 }
Andrey Ponomarenko570ece52012-11-30 16:36:44 +040018685 push_U($SystemPaths{"lib"}, @DefaultLibPaths);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040018686 }
18687 if($BSearch)
18688 {
18689 if($CrossGcc)
18690 { # --cross-gcc=arm-linux-gcc
18691 if(-e $CrossGcc)
18692 { # absolute or relative path
18693 $GCC_PATH = get_abs_path($CrossGcc);
18694 }
18695 elsif($CrossGcc!~/\// and get_CmdPath($CrossGcc))
18696 { # command name
18697 $GCC_PATH = $CrossGcc;
18698 }
18699 else {
18700 exitStatus("Access_Error", "can't access \'$CrossGcc\'");
18701 }
18702 if($GCC_PATH=~/\s/) {
18703 $GCC_PATH = "\"".$GCC_PATH."\"";
18704 }
18705 }
18706 }
18707 if($GSearch)
18708 { # GCC path and default include dirs
Andrey Ponomarenko570ece52012-11-30 16:36:44 +040018709 if(not $CrossGcc)
18710 { # try default gcc
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040018711 $GCC_PATH = get_CmdPath("gcc");
18712 }
Andrey Ponomarenko01117f12012-06-26 12:23:02 +040018713 if(not $GCC_PATH)
18714 { # try to find gcc-X.Y
Andrey Ponomarenko570ece52012-11-30 16:36:44 +040018715 foreach my $Path (@{$SystemPaths{"bin"}})
Andrey Ponomarenko01117f12012-06-26 12:23:02 +040018716 {
Andrey Ponomarenko570ece52012-11-30 16:36:44 +040018717 if(my @GCCs = cmd_find($Path, "", ".*/gcc-[0-9.]*", 1, 1))
Andrey Ponomarenko01117f12012-06-26 12:23:02 +040018718 { # select the latest version
18719 @GCCs = sort {$b cmp $a} @GCCs;
18720 if(check_gcc($GCCs[0], "3"))
18721 {
18722 $GCC_PATH = $GCCs[0];
18723 last;
18724 }
18725 }
18726 }
18727 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040018728 if(not $GCC_PATH) {
18729 exitStatus("Not_Found", "can't find GCC>=3.0 in PATH");
18730 }
18731 if(not $CheckObjectsOnly_Opt)
18732 {
18733 if(my $GCC_Ver = get_dumpversion($GCC_PATH))
18734 {
18735 my $GccTarget = get_dumpmachine($GCC_PATH);
18736 printMsg("INFO", "Using GCC $GCC_Ver ($GccTarget)");
18737 if($GccTarget=~/symbian/)
18738 {
18739 $OStarget = "symbian";
18740 $LIB_EXT = $OS_LibExt{$LIB_TYPE}{$OStarget};
18741 }
18742 }
18743 else {
18744 exitStatus("Error", "something is going wrong with the GCC compiler");
18745 }
18746 }
Andrey Ponomarenko570ece52012-11-30 16:36:44 +040018747 if($HSearch)
18748 {
18749 if(not $NoStdInc)
18750 { # do NOT search in GCC standard paths
18751 my %DPaths = detect_inc_default_paths();
18752 @DefaultCppPaths = @{$DPaths{"Cpp"}};
18753 @DefaultGccPaths = @{$DPaths{"Gcc"}};
18754 @DefaultIncPaths = @{$DPaths{"Inc"}};
18755 push_U($SystemPaths{"include"}, @DefaultIncPaths);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040018756 }
18757 }
18758 }
18759 if($HSearch)
Andrey Ponomarenko570ece52012-11-30 16:36:44 +040018760 { # users include paths
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040018761 my $IncPath = "/usr/include";
18762 if($SystemRoot) {
18763 $IncPath = $SystemRoot.$IncPath;
18764 }
18765 if(-d $IncPath) {
Andrey Ponomarenko570ece52012-11-30 16:36:44 +040018766 push_U(\@UsersIncPath, $IncPath);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040018767 }
18768 }
18769}
18770
18771sub getLIB_EXT($)
18772{
18773 my $Target = $_[0];
18774 if(my $Ext = $OS_LibExt{$LIB_TYPE}{$Target}) {
18775 return $Ext;
18776 }
18777 return $OS_LibExt{$LIB_TYPE}{"default"};
18778}
18779
18780sub getAR_EXT($)
18781{
18782 my $Target = $_[0];
18783 if(my $Ext = $OS_Archive{$Target}) {
18784 return $Ext;
18785 }
18786 return $OS_Archive{"default"};
18787}
18788
18789sub get_dumpversion($)
18790{
18791 my $Cmd = $_[0];
18792 return "" if(not $Cmd);
18793 if($Cache{"get_dumpversion"}{$Cmd}) {
18794 return $Cache{"get_dumpversion"}{$Cmd};
18795 }
Andrey Ponomarenkoa01311b2012-06-08 17:20:02 +040018796 my $V = `$Cmd -dumpversion 2>\"$TMP_DIR/null\"`;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040018797 chomp($V);
18798 return ($Cache{"get_dumpversion"}{$Cmd} = $V);
18799}
18800
18801sub get_dumpmachine($)
18802{
18803 my $Cmd = $_[0];
18804 return "" if(not $Cmd);
18805 if($Cache{"get_dumpmachine"}{$Cmd}) {
18806 return $Cache{"get_dumpmachine"}{$Cmd};
18807 }
Andrey Ponomarenkoa01311b2012-06-08 17:20:02 +040018808 my $Machine = `$Cmd -dumpmachine 2>\"$TMP_DIR/null\"`;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040018809 chomp($Machine);
18810 return ($Cache{"get_dumpmachine"}{$Cmd} = $Machine);
18811}
18812
Andrey Ponomarenko570ece52012-11-30 16:36:44 +040018813sub checkCmd($)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040018814{
18815 my $Cmd = $_[0];
18816 return "" if(not $Cmd);
18817 my @Options = (
18818 "--version",
18819 "-help"
18820 );
18821 foreach my $Opt (@Options)
18822 {
Andrey Ponomarenkoa01311b2012-06-08 17:20:02 +040018823 my $Info = `$Cmd $Opt 2>\"$TMP_DIR/null\"`;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040018824 if($Info) {
18825 return 1;
18826 }
18827 }
18828 return 0;
18829}
18830
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040018831sub check_gcc($$)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040018832{
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040018833 my ($Cmd, $ReqVer) = @_;
18834 return 0 if(not $Cmd or not $ReqVer);
18835 if(defined $Cache{"check_gcc"}{$Cmd}{$ReqVer}) {
18836 return $Cache{"check_gcc"}{$Cmd}{$ReqVer};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040018837 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040018838 if(my $GccVer = get_dumpversion($Cmd))
18839 {
18840 $GccVer=~s/(-|_)[a-z_]+.*\Z//; # remove suffix (like "-haiku-100818")
18841 if(cmpVersions($GccVer, $ReqVer)>=0) {
18842 return ($Cache{"check_gcc"}{$Cmd}{$ReqVer} = $Cmd);
18843 }
18844 }
18845 return ($Cache{"check_gcc"}{$Cmd}{$ReqVer} = "");
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040018846}
18847
18848sub get_depth($)
18849{
18850 if(defined $Cache{"get_depth"}{$_[0]}) {
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040018851 return $Cache{"get_depth"}{$_[0]};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040018852 }
18853 return ($Cache{"get_depth"}{$_[0]} = ($_[0]=~tr![\/\\]|\:\:!!));
18854}
18855
Andrey Ponomarenko570ece52012-11-30 16:36:44 +040018856sub registerGccHeaders()
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040018857{
Andrey Ponomarenko570ece52012-11-30 16:36:44 +040018858 return if($Cache{"registerGccHeaders"}); # this function should be called once
18859
18860 foreach my $Path (@DefaultGccPaths)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040018861 {
Andrey Ponomarenko570ece52012-11-30 16:36:44 +040018862 my @Headers = cmd_find($Path,"f");
18863 @Headers = sort {get_depth($a)<=>get_depth($b)} @Headers;
18864 foreach my $HPath (@Headers)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040018865 {
Andrey Ponomarenko570ece52012-11-30 16:36:44 +040018866 my $FileName = get_filename($HPath);
18867 if(not defined $DefaultGccHeader{$FileName})
18868 { # skip duplicated
18869 $DefaultGccHeader{$FileName} = $HPath;
18870 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040018871 }
18872 }
Andrey Ponomarenko570ece52012-11-30 16:36:44 +040018873 $Cache{"registerGccHeaders"} = 1;
18874}
18875
18876sub registerCppHeaders()
18877{
18878 return if($Cache{"registerCppHeaders"}); # this function should be called once
18879
18880 foreach my $CppDir (@DefaultCppPaths)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040018881 {
Andrey Ponomarenko570ece52012-11-30 16:36:44 +040018882 my @Headers = cmd_find($CppDir,"f");
18883 @Headers = sort {get_depth($a)<=>get_depth($b)} @Headers;
18884 foreach my $Path (@Headers)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040018885 {
Andrey Ponomarenko570ece52012-11-30 16:36:44 +040018886 my $FileName = get_filename($Path);
18887 if(not defined $DefaultCppHeader{$FileName})
18888 { # skip duplicated
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040018889 $DefaultCppHeader{$FileName} = $Path;
18890 }
18891 }
18892 }
Andrey Ponomarenko570ece52012-11-30 16:36:44 +040018893 $Cache{"registerCppHeaders"} = 1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040018894}
18895
18896sub parse_libname($$$)
18897{
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040018898 return "" if(not $_[0]);
18899 if(defined $Cache{"parse_libname"}{$_[2]}{$_[1]}{$_[0]}) {
18900 return $Cache{"parse_libname"}{$_[2]}{$_[1]}{$_[0]};
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040018901 }
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040018902 return ($Cache{"parse_libname"}{$_[2]}{$_[1]}{$_[0]} = parse_libname_I(@_));
18903}
18904
18905sub parse_libname_I($$$)
18906{
18907 my ($Name, $Type, $Target) = @_;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040018908 if($Target eq "symbian") {
18909 return parse_libname_symbian($Name, $Type);
18910 }
18911 elsif($Target eq "windows") {
18912 return parse_libname_windows($Name, $Type);
18913 }
18914 my $Ext = getLIB_EXT($Target);
Andrey Ponomarenkoa01311b2012-06-08 17:20:02 +040018915 if($Name=~/((((lib|).+?)([\-\_][\d\-\.\_]+.*?|))\.$Ext)(\.(.+)|)\Z/)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040018916 { # libSDL-1.2.so.0.7.1
18917 # libwbxml2.so.0.0.18
Andrey Ponomarenkoa01311b2012-06-08 17:20:02 +040018918 # libopcodes-2.21.53-system.20110810.so
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040018919 if($Type eq "name")
18920 { # libSDL-1.2
18921 # libwbxml2
18922 return $2;
18923 }
18924 elsif($Type eq "name+ext")
18925 { # libSDL-1.2.so
18926 # libwbxml2.so
18927 return $1;
18928 }
18929 elsif($Type eq "version")
18930 {
Andrey Ponomarenkoa01311b2012-06-08 17:20:02 +040018931 if(defined $7
18932 and $7 ne "")
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040018933 { # 0.7.1
18934 return $7;
18935 }
18936 else
18937 { # libc-2.5.so (=>2.5 version)
18938 my $MV = $5;
18939 $MV=~s/\A[\-\_]+//g;
18940 return $MV;
18941 }
18942 }
18943 elsif($Type eq "short")
18944 { # libSDL
18945 # libwbxml2
18946 return $3;
18947 }
18948 elsif($Type eq "shortest")
18949 { # SDL
18950 # wbxml
18951 return shortest_name($3);
18952 }
18953 }
18954 return "";# error
18955}
18956
18957sub parse_libname_symbian($$)
18958{
18959 my ($Name, $Type) = @_;
18960 my $Ext = getLIB_EXT("symbian");
18961 if($Name=~/(((.+?)(\{.+\}|))\.$Ext)\Z/)
18962 { # libpthread{00010001}.dso
18963 if($Type eq "name")
18964 { # libpthread{00010001}
18965 return $2;
18966 }
18967 elsif($Type eq "name+ext")
18968 { # libpthread{00010001}.dso
18969 return $1;
18970 }
18971 elsif($Type eq "version")
18972 { # 00010001
18973 my $V = $4;
18974 $V=~s/\{(.+)\}/$1/;
18975 return $V;
18976 }
18977 elsif($Type eq "short")
18978 { # libpthread
18979 return $3;
18980 }
18981 elsif($Type eq "shortest")
18982 { # pthread
18983 return shortest_name($3);
18984 }
18985 }
18986 return "";# error
18987}
18988
18989sub parse_libname_windows($$)
18990{
18991 my ($Name, $Type) = @_;
18992 my $Ext = getLIB_EXT("windows");
18993 if($Name=~/((.+?)\.$Ext)\Z/)
18994 { # netapi32.dll
18995 if($Type eq "name")
18996 { # netapi32
18997 return $2;
18998 }
18999 elsif($Type eq "name+ext")
19000 { # netapi32.dll
19001 return $1;
19002 }
19003 elsif($Type eq "version")
19004 { # DLL version embedded
19005 # at binary-level
19006 return "";
19007 }
19008 elsif($Type eq "short")
19009 { # netapi32
19010 return $2;
19011 }
19012 elsif($Type eq "shortest")
19013 { # netapi
19014 return shortest_name($2);
19015 }
19016 }
19017 return "";# error
19018}
19019
19020sub shortest_name($)
19021{
19022 my $Name = $_[0];
19023 # remove prefix
19024 $Name=~s/\A(lib|open)//;
19025 # remove suffix
19026 $Name=~s/[\W\d_]+\Z//i;
19027 $Name=~s/([a-z]{2,})(lib)\Z/$1/i;
19028 return $Name;
19029}
19030
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040019031sub createSymbolsList($$$$$)
19032{
19033 my ($DPath, $SaveTo, $LName, $LVersion, $ArchName) = @_;
19034 read_ABI_Dump(1, $DPath);
19035 if(not $CheckObjectsOnly) {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040019036 prepareSymbols(1);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040019037 }
19038 my %SymbolHeaderLib = ();
19039 my $Total = 0;
19040 # Get List
19041 foreach my $Symbol (sort keys(%{$CompleteSignature{1}}))
19042 {
19043 if(not link_symbol($Symbol, 1, "-Deps"))
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040019044 { # skip src only and all external functions
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040019045 next;
19046 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040019047 if(not symbolFilter($Symbol, 1, "Public", "Binary"))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040019048 { # skip other symbols
19049 next;
19050 }
19051 my $HeaderName = $CompleteSignature{1}{$Symbol}{"Header"};
19052 if(not $HeaderName)
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040019053 { # skip src only and all external functions
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040019054 next;
19055 }
19056 my $DyLib = $Symbol_Library{1}{$Symbol};
19057 if(not $DyLib)
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040019058 { # skip src only and all external functions
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040019059 next;
19060 }
19061 $SymbolHeaderLib{$HeaderName}{$DyLib}{$Symbol} = 1;
19062 $Total+=1;
19063 }
19064 # Draw List
19065 my $SYMBOLS_LIST = "<h1>Public symbols in <span style='color:Blue;'>$LName</span> (<span style='color:Red;'>$LVersion</span>)";
19066 $SYMBOLS_LIST .= " on <span style='color:Blue;'>".showArch($ArchName)."</span><br/>Total: $Total</h1><br/>";
19067 foreach my $HeaderName (sort {lc($a) cmp lc($b)} keys(%SymbolHeaderLib))
19068 {
19069 foreach my $DyLib (sort {lc($a) cmp lc($b)} keys(%{$SymbolHeaderLib{$HeaderName}}))
19070 {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040019071 my %NS_Symbol = ();
19072 foreach my $Symbol (keys(%{$SymbolHeaderLib{$HeaderName}{$DyLib}})) {
19073 $NS_Symbol{get_IntNameSpace($Symbol, 1)}{$Symbol} = 1;
19074 }
19075 foreach my $NameSpace (sort keys(%NS_Symbol))
19076 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040019077 $SYMBOLS_LIST .= getTitle($HeaderName, $DyLib, $NameSpace);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040019078 my @SortedInterfaces = sort {lc(get_Signature($a, 1)) cmp lc(get_Signature($b, 1))} keys(%{$NS_Symbol{$NameSpace}});
19079 foreach my $Symbol (@SortedInterfaces)
19080 {
19081 my $SubReport = "";
19082 my $Signature = get_Signature($Symbol, 1);
19083 if($NameSpace) {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040019084 $Signature=~s/\b\Q$NameSpace\E::\b//g;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040019085 }
19086 if($Symbol=~/\A(_Z|\?)/)
19087 {
19088 if($Signature) {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040019089 $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 +040019090 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040019091 else {
19092 $SubReport = "<span class='iname'>".$Symbol."</span><br/>\n";
19093 }
19094 }
19095 else
19096 {
19097 if($Signature) {
19098 $SubReport = "<span class='iname'>".highLight_Signature_Italic_Color($Signature)."</span><br/>\n";
19099 }
19100 else {
19101 $SubReport = "<span class='iname'>".$Symbol."</span><br/>\n";
19102 }
19103 }
19104 $SYMBOLS_LIST .= $SubReport;
19105 }
19106 }
19107 $SYMBOLS_LIST .= "<br/>\n";
19108 }
19109 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040019110 # clear info
19111 (%TypeInfo, %SymbolInfo, %Library_Symbol, %DepSymbol_Library,
19112 %DepLibrary_Symbol, %SymVer, %SkipTypes, %SkipSymbols,
19113 %NestedNameSpaces, %ClassMethods, %AllocableClass, %ClassNames,
19114 %CompleteSignature, %SkipNameSpaces, %Symbol_Library, %Library_Symbol) = ();
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040019115 ($Content_Counter, $ContentID) = (0, 0);
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040019116 # print report
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040019117 my $CssStyles = readModule("Styles", "SymbolsList.css");
19118 my $JScripts = readModule("Scripts", "Sections.js");
19119 $SYMBOLS_LIST = "<a name='Top'></a>".$SYMBOLS_LIST.$TOP_REF."<br/>\n";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040019120 my $Title = "$LName: public symbols";
19121 my $Keywords = "$LName, API, symbols";
19122 my $Description = "List of symbols in $LName ($LVersion) on ".showArch($ArchName);
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040019123 $SYMBOLS_LIST = composeHTML_Head($Title, $Keywords, $Description, $CssStyles, $JScripts)."
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040019124 <body><div>\n$SYMBOLS_LIST</div>
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040019125 <br/><br/><hr/>\n".getReportFooter($LName, 1)."
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040019126 <div style='height:999px;'></div></body></html>";
19127 writeFile($SaveTo, $SYMBOLS_LIST);
19128}
19129
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040019130sub add_target_libs($)
19131{
19132 foreach (@{$_[0]}) {
19133 $TargetLibs{$_} = 1;
19134 }
19135}
19136
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040019137sub is_target_lib($)
19138{
19139 my $LName = $_[0];
Andrey Ponomarenkoa01311b2012-06-08 17:20:02 +040019140 if(not $LName) {
19141 return 0;
19142 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040019143 if($TargetLibraryName
19144 and $LName!~/\Q$TargetLibraryName\E/) {
19145 return 0;
19146 }
19147 if(keys(%TargetLibs)
19148 and not $TargetLibs{$LName}
19149 and not $TargetLibs{parse_libname($LName, "name+ext", $OStarget)}) {
19150 return 0;
19151 }
19152 return 1;
19153}
19154
Andrey Ponomarenko85043792012-05-14 16:48:07 +040019155sub is_target_header($$)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040019156{ # --header, --headers-list
Andrey Ponomarenko85043792012-05-14 16:48:07 +040019157 my ($H, $V) = @_;
19158 if(keys(%{$TargetHeaders{$V}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040019159 {
Andrey Ponomarenko85043792012-05-14 16:48:07 +040019160 if($TargetHeaders{$V}{$H}) {
19161 return 1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040019162 }
19163 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +040019164 return 0;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040019165}
19166
19167sub checkVersionNum($$)
19168{
19169 my ($LibVersion, $Path) = @_;
19170 if(my $VerNum = $TargetVersion{$LibVersion}) {
19171 return $VerNum;
19172 }
19173 my $UsedAltDescr = 0;
19174 foreach my $Part (split(/\s*,\s*/, $Path))
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040019175 { # try to get version string from file path
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040019176 next if(isDump($Part)); # ABI dump
19177 next if($Part=~/\.(xml|desc)\Z/i); # XML descriptor
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040019178 my $VerNum = "";
19179 if(parse_libname($Part, "name", $OStarget))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040019180 {
19181 $UsedAltDescr = 1;
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040019182 $VerNum = parse_libname($Part, "version", $OStarget);
19183 if(not $VerNum) {
Andrey Ponomarenko07aea072012-11-12 16:15:07 +040019184 $VerNum = readStrVer($Part);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040019185 }
19186 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040019187 elsif(is_header($Part, 2, $LibVersion) or -d $Part)
19188 {
19189 $UsedAltDescr = 1;
Andrey Ponomarenko07aea072012-11-12 16:15:07 +040019190 $VerNum = readStrVer($Part);
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040019191 }
19192 if($VerNum ne "")
19193 {
19194 $TargetVersion{$LibVersion} = $VerNum;
19195 if($DumpAPI) {
Andrey Ponomarenko570ece52012-11-30 16:36:44 +040019196 printMsg("WARNING", "setting version number to $VerNum (use -vnum option to change it)");
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040019197 }
19198 else {
Andrey Ponomarenko570ece52012-11-30 16:36:44 +040019199 printMsg("WARNING", "setting ".($LibVersion==1?"1st":"2nd")." version number to \"$VerNum\" (use -v$LibVersion option to change it)");
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040019200 }
19201 return $TargetVersion{$LibVersion};
19202 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040019203 }
19204 if($UsedAltDescr)
19205 {
19206 if($DumpAPI) {
Andrey Ponomarenko570ece52012-11-30 16:36:44 +040019207 exitStatus("Error", "version number is not set (use -vnum option)");
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040019208 }
19209 else {
Andrey Ponomarenko570ece52012-11-30 16:36:44 +040019210 exitStatus("Error", ($LibVersion==1?"1st":"2nd")." version number is not set (use -v$LibVersion option)");
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040019211 }
19212 }
19213}
19214
Andrey Ponomarenko07aea072012-11-12 16:15:07 +040019215sub readStrVer($)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040019216{
19217 my $Str = $_[0];
19218 return "" if(not $Str);
19219 $Str=~s/\Q$TargetLibraryName\E//g;
19220 if($Str=~/(\/|\\|\w|\A)[\-\_]*(\d+[\d\.\-]+\d+|\d+)/)
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040019221 { # .../libssh-0.4.0/...
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040019222 return $2;
19223 }
19224 elsif(my $V = parse_libname($Str, "version", $OStarget)) {
19225 return $V;
19226 }
19227 return "";
19228}
19229
19230sub readLibs($)
19231{
19232 my $LibVersion = $_[0];
19233 if($OStarget eq "windows")
19234 { # dumpbin.exe will crash
19235 # without VS Environment
19236 check_win32_env();
19237 }
Andrey Ponomarenko16934472012-03-29 15:37:04 +040019238 readSymbols($LibVersion);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040019239 translateSymbols(keys(%{$Symbol_Library{$LibVersion}}), $LibVersion);
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040019240 translateSymbols(keys(%{$DepSymbol_Library{$LibVersion}}), $LibVersion);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040019241}
19242
19243sub dump_sorting($)
19244{
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +040019245 my $Hash = $_[0];
19246 return [] if(not $Hash);
19247 my @Keys = keys(%{$Hash});
19248 return [] if($#Keys<0);
19249 if($Keys[0]=~/\A\d+\Z/)
19250 { # numbers
19251 return [sort {int($a)<=>int($b)} @Keys];
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040019252 }
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +040019253 else
19254 { # strings
19255 return [sort {$a cmp $b} @Keys];
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040019256 }
19257}
19258
19259sub printMsg($$)
19260{
19261 my ($Type, $Msg) = @_;
19262 if($Type!~/\AINFO/) {
19263 $Msg = $Type.": ".$Msg;
19264 }
19265 if($Type!~/_C\Z/) {
19266 $Msg .= "\n";
19267 }
19268 if($Quiet)
19269 { # --quiet option
19270 appendFile($COMMON_LOG_PATH, $Msg);
19271 }
19272 else
19273 {
19274 if($Type eq "ERROR") {
19275 print STDERR $Msg;
19276 }
19277 else {
19278 print $Msg;
19279 }
19280 }
19281}
19282
19283sub exitStatus($$)
19284{
19285 my ($Code, $Msg) = @_;
19286 printMsg("ERROR", $Msg);
19287 exit($ERROR_CODE{$Code});
19288}
19289
19290sub exitReport()
19291{ # the tool has run without any errors
19292 printReport();
19293 if($COMPILE_ERRORS)
19294 { # errors in headers may add false positives/negatives
19295 exit($ERROR_CODE{"Compile_Error"});
19296 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040019297 if($BinaryOnly and $RESULT{"Binary"}{"Problems"})
19298 { # --binary
19299 exit($ERROR_CODE{"Incompatible"});
19300 }
19301 elsif($SourceOnly and $RESULT{"Source"}{"Problems"})
19302 { # --source
19303 exit($ERROR_CODE{"Incompatible"});
19304 }
19305 elsif($RESULT{"Source"}{"Problems"}
19306 or $RESULT{"Binary"}{"Problems"})
19307 { # default
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040019308 exit($ERROR_CODE{"Incompatible"});
19309 }
19310 else {
19311 exit($ERROR_CODE{"Compatible"});
19312 }
19313}
19314
19315sub readRules($)
19316{
19317 my $Kind = $_[0];
19318 if(not -f $RULES_PATH{$Kind}) {
19319 exitStatus("Module_Error", "can't access \'".$RULES_PATH{$Kind}."\'");
19320 }
19321 my $Content = readFile($RULES_PATH{$Kind});
19322 while(my $Rule = parseTag(\$Content, "rule"))
19323 {
19324 my $RId = parseTag(\$Rule, "id");
19325 my @Properties = ("Severity", "Change", "Effect", "Overcome", "Kind");
19326 foreach my $Prop (@Properties) {
19327 if(my $Value = parseTag(\$Rule, lc($Prop)))
19328 {
19329 $Value=~s/\n[ ]*//;
19330 $CompatRules{$Kind}{$RId}{$Prop} = $Value;
19331 }
19332 }
19333 if($CompatRules{$Kind}{$RId}{"Kind"}=~/\A(Symbols|Parameters)\Z/) {
19334 $CompatRules{$Kind}{$RId}{"Kind"} = "Symbols";
19335 }
19336 else {
19337 $CompatRules{$Kind}{$RId}{"Kind"} = "Types";
19338 }
19339 }
19340}
19341
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040019342sub getReportPath($)
19343{
19344 my $Level = $_[0];
19345 my $Dir = "compat_reports/$TargetLibraryName/".$Descriptor{1}{"Version"}."_to_".$Descriptor{2}{"Version"};
19346 if($Level eq "Binary")
19347 {
19348 if($BinaryReportPath)
19349 { # --bin-report-path
19350 return $BinaryReportPath;
19351 }
19352 elsif($OutputReportPath)
19353 { # --report-path
19354 return $OutputReportPath;
19355 }
19356 else
19357 { # default
19358 return $Dir."/abi_compat_report.$ReportFormat";
19359 }
19360 }
19361 elsif($Level eq "Source")
19362 {
19363 if($SourceReportPath)
19364 { # --src-report-path
19365 return $SourceReportPath;
19366 }
19367 elsif($OutputReportPath)
19368 { # --report-path
19369 return $OutputReportPath;
19370 }
19371 else
19372 { # default
19373 return $Dir."/src_compat_report.$ReportFormat";
19374 }
19375 }
19376 else
19377 {
19378 if($OutputReportPath)
19379 { # --report-path
19380 return $OutputReportPath;
19381 }
19382 else
19383 { # default
19384 return $Dir."/compat_report.$ReportFormat";
19385 }
19386 }
19387}
19388
19389sub printStatMsg($)
19390{
19391 my $Level = $_[0];
19392 printMsg("INFO", "total \"$Level\" compatibility problems: ".$RESULT{$Level}{"Problems"}.", warnings: ".$RESULT{$Level}{"Warnings"});
19393}
19394
19395sub listAffected($)
19396{
19397 my $Level = $_[0];
19398 my $List = "";
19399 foreach (keys(%{$TotalAffected{$Level}}))
19400 {
19401 if($StrictCompat and $TotalAffected{$Level}{$_} eq "Low")
19402 { # skip "Low"-severity problems
19403 next;
19404 }
19405 $List .= "$_\n";
19406 }
19407 my $Dir = get_dirname(getReportPath($Level));
19408 if($Level eq "Binary") {
19409 writeFile($Dir."/abi_affected.txt", $List);
19410 }
19411 elsif($Level eq "Source") {
19412 writeFile($Dir."/src_affected.txt", $List);
19413 }
19414}
19415
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040019416sub printReport()
19417{
19418 printMsg("INFO", "creating compatibility report ...");
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040019419 createReport();
19420 if($JoinReport or $DoubleReport)
19421 {
19422 if($RESULT{"Binary"}{"Problems"}
19423 or $RESULT{"Source"}{"Problems"}) {
19424 printMsg("INFO", "result: INCOMPATIBLE (Binary: ".$RESULT{"Binary"}{"Affected"}."\%, Source: ".$RESULT{"Source"}{"Affected"}."\%)");
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040019425 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040019426 else {
19427 printMsg("INFO", "result: COMPATIBLE");
19428 }
19429 printStatMsg("Binary");
19430 printStatMsg("Source");
19431 if($ListAffected)
19432 { # --list-affected
19433 listAffected("Binary");
19434 listAffected("Source");
19435 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040019436 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040019437 elsif($BinaryOnly)
19438 {
19439 if($RESULT{"Binary"}{"Problems"}) {
19440 printMsg("INFO", "result: INCOMPATIBLE (".$RESULT{"Binary"}{"Affected"}."\%)");
19441 }
19442 else {
19443 printMsg("INFO", "result: COMPATIBLE");
19444 }
19445 printStatMsg("Binary");
19446 if($ListAffected)
19447 { # --list-affected
19448 listAffected("Binary");
19449 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040019450 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040019451 elsif($SourceOnly)
19452 {
19453 if($RESULT{"Source"}{"Problems"}) {
19454 printMsg("INFO", "result: INCOMPATIBLE (".$RESULT{"Source"}{"Affected"}."\%)");
19455 }
19456 else {
19457 printMsg("INFO", "result: COMPATIBLE");
19458 }
19459 printStatMsg("Source");
19460 if($ListAffected)
19461 { # --list-affected
19462 listAffected("Source");
19463 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040019464 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040019465 if($StdOut)
19466 {
19467 if($JoinReport or not $DoubleReport)
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040019468 { # --binary or --source
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040019469 printMsg("INFO", "compatibility report has been generated to stdout");
19470 }
19471 else
19472 { # default
19473 printMsg("INFO", "compatibility reports have been generated to stdout");
19474 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040019475 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040019476 else
19477 {
19478 if($JoinReport)
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040019479 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040019480 printMsg("INFO", "see detailed report:\n ".getReportPath("Join"));
19481 }
19482 elsif($DoubleReport)
19483 { # default
19484 printMsg("INFO", "see detailed reports:\n ".getReportPath("Binary")."\n ".getReportPath("Source"));
19485 }
19486 elsif($BinaryOnly)
19487 { # --binary
19488 printMsg("INFO", "see detailed report:\n ".getReportPath("Binary"));
19489 }
19490 elsif($SourceOnly)
19491 { # --source
19492 printMsg("INFO", "see detailed report:\n ".getReportPath("Source"));
19493 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040019494 }
19495}
19496
19497sub check_win32_env()
19498{
19499 if(not $ENV{"DevEnvDir"}
19500 or not $ENV{"LIB"}) {
19501 exitStatus("Error", "can't start without VS environment (vsvars32.bat)");
19502 }
19503}
19504
Andrey Ponomarenko5c09ef32012-06-14 18:17:33 +040019505sub diffSets($$)
19506{
19507 my ($S1, $S2) = @_;
19508 my @SK1 = keys(%{$S1});
19509 my @SK2 = keys(%{$S2});
19510 if($#SK1!=$#SK2) {
19511 return 1;
19512 }
19513 foreach my $K1 (@SK1)
19514 {
19515 if(not defined $S2->{$K1}) {
19516 return 1;
19517 }
19518 }
19519 return 0;
19520}
19521
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040019522sub create_ABI_Dump()
19523{
19524 if(not -e $DumpAPI) {
19525 exitStatus("Access_Error", "can't access \'$DumpAPI\'");
19526 }
19527 # check the archive utilities
19528 if($OSgroup eq "windows")
19529 { # using zip
19530 my $ZipCmd = get_CmdPath("zip");
19531 if(not $ZipCmd) {
19532 exitStatus("Not_Found", "can't find \"zip\"");
19533 }
19534 }
19535 else
19536 { # using tar and gzip
19537 my $TarCmd = get_CmdPath("tar");
19538 if(not $TarCmd) {
19539 exitStatus("Not_Found", "can't find \"tar\"");
19540 }
19541 my $GzipCmd = get_CmdPath("gzip");
19542 if(not $GzipCmd) {
19543 exitStatus("Not_Found", "can't find \"gzip\"");
19544 }
19545 }
19546 my @DParts = split(/\s*,\s*/, $DumpAPI);
19547 foreach my $Part (@DParts)
19548 {
19549 if(not -e $Part) {
19550 exitStatus("Access_Error", "can't access \'$Part\'");
19551 }
19552 }
19553 checkVersionNum(1, $DumpAPI);
19554 foreach my $Part (@DParts)
19555 {
19556 if(isDump($Part)) {
19557 read_ABI_Dump(1, $Part);
19558 }
19559 else {
19560 readDescriptor(1, createDescriptor(1, $Part));
19561 }
19562 }
19563 initLogging(1);
19564 detect_default_paths("inc|lib|bin|gcc"); # complete analysis
Andrey Ponomarenko01117f12012-06-26 12:23:02 +040019565 if(not $Descriptor{1}{"Dump"})
19566 {
19567 if(not $CheckHeadersOnly) {
19568 readLibs(1);
19569 }
19570 if($CheckHeadersOnly) {
19571 setLanguage(1, "C++");
19572 }
19573 if(not $CheckObjectsOnly) {
19574 searchForHeaders(1);
19575 }
19576 $WORD_SIZE{1} = detectWordSize();
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040019577 }
Andrey Ponomarenko01117f12012-06-26 12:23:02 +040019578 if(not $Descriptor{1}{"Dump"})
19579 {
19580 if($Descriptor{1}{"Headers"}) {
19581 readHeaders(1);
19582 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040019583 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +040019584 cleanDump(1);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040019585 if(not keys(%{$SymbolInfo{1}}))
19586 { # check if created dump is valid
19587 if(not $ExtendedCheck and not $CheckObjectsOnly)
19588 {
19589 if($CheckHeadersOnly) {
19590 exitStatus("Empty_Set", "the set of public symbols is empty");
19591 }
19592 else {
19593 exitStatus("Empty_Intersection", "the sets of public symbols in headers and libraries have empty intersection");
19594 }
19595 }
19596 }
19597 my %HeadersInfo = ();
19598 foreach my $HPath (keys(%{$Registered_Headers{1}}))
19599 { # headers info stored without paths in the dump
19600 $HeadersInfo{$Registered_Headers{1}{$HPath}{"Identity"}} = $Registered_Headers{1}{$HPath}{"Pos"};
19601 }
Andrey Ponomarenko570ece52012-11-30 16:36:44 +040019602 if($ExtraDump)
19603 { # add unmangled names to the ABI dump
19604 my @Names = ();
19605 foreach my $InfoId (keys(%{$SymbolInfo{1}}))
19606 {
19607 if(my $MnglName = $SymbolInfo{1}{$InfoId}{"MnglName"}) {
19608 push(@Names, $MnglName);
19609 }
19610 }
19611 translateSymbols(@Names, 1);
19612 foreach my $InfoId (keys(%{$SymbolInfo{1}}))
19613 {
19614 if(my $MnglName = $SymbolInfo{1}{$InfoId}{"MnglName"})
19615 {
19616 if(my $Unmangled = $tr_name{$MnglName})
19617 {
19618 if($MnglName ne $Unmangled) {
19619 $SymbolInfo{1}{$InfoId}{"Unmangled"} = $Unmangled;
19620 }
19621 }
19622 }
19623 }
19624 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040019625 printMsg("INFO", "creating library ABI dump ...");
Andrey Ponomarenko01117f12012-06-26 12:23:02 +040019626 my %ABI = (
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040019627 "TypeInfo" => $TypeInfo{1},
19628 "SymbolInfo" => $SymbolInfo{1},
19629 "Symbols" => $Library_Symbol{1},
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040019630 "DepSymbols" => $DepLibrary_Symbol{1},
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040019631 "SymbolVersion" => $SymVer{1},
19632 "LibraryVersion" => $Descriptor{1}{"Version"},
19633 "LibraryName" => $TargetLibraryName,
19634 "Language" => $COMMON_LANGUAGE{1},
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040019635 "SkipTypes" => $SkipTypes{1},
19636 "SkipSymbols" => $SkipSymbols{1},
19637 "SkipNameSpaces" => $SkipNameSpaces{1},
19638 "SkipHeaders" => $SkipHeadersList{1},
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040019639 "Headers" => \%HeadersInfo,
19640 "Constants" => $Constants{1},
19641 "NameSpaces" => $NestedNameSpaces{1},
19642 "Target" => $OStarget,
19643 "Arch" => getArch(1),
19644 "WordSize" => $WORD_SIZE{1},
19645 "GccVersion" => get_dumpversion($GCC_PATH),
19646 "ABI_DUMP_VERSION" => $ABI_DUMP_VERSION,
19647 "ABI_COMPLIANCE_CHECKER_VERSION" => $TOOL_VERSION
19648 );
Andrey Ponomarenko5c09ef32012-06-14 18:17:33 +040019649 if(diffSets($TargetHeaders{1}, \%HeadersInfo)) {
Andrey Ponomarenko01117f12012-06-26 12:23:02 +040019650 $ABI{"TargetHeaders"} = $TargetHeaders{1};
Andrey Ponomarenko5c09ef32012-06-14 18:17:33 +040019651 }
19652 if($UseXML) {
Andrey Ponomarenko01117f12012-06-26 12:23:02 +040019653 $ABI{"XML_ABI_DUMP_VERSION"} = $XML_ABI_DUMP_VERSION;
Andrey Ponomarenko5c09ef32012-06-14 18:17:33 +040019654 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040019655 if($ExtendedCheck)
19656 { # --ext option
Andrey Ponomarenko01117f12012-06-26 12:23:02 +040019657 $ABI{"Mode"} = "Extended";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040019658 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040019659 if($BinaryOnly)
19660 { # --binary
Andrey Ponomarenko01117f12012-06-26 12:23:02 +040019661 $ABI{"BinOnly"} = 1;
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040019662 }
Andrey Ponomarenko5c09ef32012-06-14 18:17:33 +040019663
19664 my $ABI_DUMP = "";
19665 if($UseXML)
19666 {
19667 loadModule("XmlDump");
Andrey Ponomarenko01117f12012-06-26 12:23:02 +040019668 $ABI_DUMP = createXmlDump(\%ABI);
Andrey Ponomarenko5c09ef32012-06-14 18:17:33 +040019669 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040019670 else
19671 { # default
Andrey Ponomarenko01117f12012-06-26 12:23:02 +040019672 $ABI_DUMP = Dumper(\%ABI);
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040019673 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040019674 if($StdOut)
19675 { # --stdout option
Andrey Ponomarenko5c09ef32012-06-14 18:17:33 +040019676 print STDOUT $ABI_DUMP;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040019677 printMsg("INFO", "ABI dump has been generated to stdout");
19678 return;
19679 }
19680 else
19681 { # write to gzipped file
Andrey Ponomarenko5c09ef32012-06-14 18:17:33 +040019682 my $DumpPath = "abi_dumps/$TargetLibraryName/".$TargetLibraryName."_".$Descriptor{1}{"Version"}.".abi";
19683 $DumpPath .= ".".$AR_EXT; # gzipped by default
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040019684 if($OutputDumpPath)
19685 { # user defined path
19686 $DumpPath = $OutputDumpPath;
19687 }
Andrey Ponomarenko5c09ef32012-06-14 18:17:33 +040019688 my $Archive = ($DumpPath=~s/\Q.$AR_EXT\E\Z//g);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040019689 my ($DDir, $DName) = separate_path($DumpPath);
19690 my $DPath = $TMP_DIR."/".$DName;
Andrey Ponomarenko5c09ef32012-06-14 18:17:33 +040019691 if(not $Archive) {
19692 $DPath = $DumpPath;
19693 }
19694
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040019695 mkpath($DDir);
Andrey Ponomarenko85043792012-05-14 16:48:07 +040019696
19697 open(DUMP, ">", $DPath) || die ("can't open file \'$DPath\': $!\n");
Andrey Ponomarenko5c09ef32012-06-14 18:17:33 +040019698 print DUMP $ABI_DUMP;
Andrey Ponomarenko85043792012-05-14 16:48:07 +040019699 close(DUMP);
19700
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040019701 if(not -s $DPath) {
19702 exitStatus("Error", "can't create ABI dump because something is going wrong with the Data::Dumper module");
19703 }
Andrey Ponomarenko07aea072012-11-12 16:15:07 +040019704 if($Archive) {
19705 $DumpPath = createArchive($DPath, $DDir);
Andrey Ponomarenko5c09ef32012-06-14 18:17:33 +040019706 }
19707
Andrey Ponomarenko07aea072012-11-12 16:15:07 +040019708 if(not $OutputDumpPath)
19709 {
19710 printMsg("INFO", "library ABI has been dumped to:\n $DumpPath");
19711 printMsg("INFO", "you can transfer this dump everywhere and use instead of the ".$Descriptor{1}{"Version"}." version descriptor");
19712 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040019713 }
19714}
19715
19716sub quickEmptyReports()
19717{ # Quick "empty" reports
19718 # 4 times faster than merging equal dumps
19719 # NOTE: the dump contains the "LibraryVersion" attribute
19720 # if you change the version, then your dump will be different
19721 # OVERCOME: use -v1 and v2 options for comparing dumps
19722 # and don't change version in the XML descriptor (and dumps)
19723 # OVERCOME 2: separate meta info from the dumps in ACC 2.0
19724 if(-s $Descriptor{1}{"Path"} == -s $Descriptor{2}{"Path"})
19725 {
19726 my $FilePath1 = unpackDump($Descriptor{1}{"Path"});
19727 my $FilePath2 = unpackDump($Descriptor{2}{"Path"});
19728 if($FilePath1 and $FilePath2)
19729 {
Andrey Ponomarenko01117f12012-06-26 12:23:02 +040019730 my $Line = readLineNum($FilePath1, 0);
19731 if($Line=~/xml/)
19732 { # XML format
19733 # is not supported yet
19734 return;
19735 }
19736
Andrey Ponomarenko85043792012-05-14 16:48:07 +040019737 local $/ = undef;
19738
19739 open(DUMP1, $FilePath1);
19740 my $Content1 = <DUMP1>;
19741 close(DUMP1);
19742
19743 open(DUMP2, $FilePath2);
19744 my $Content2 = <DUMP2>;
19745 close(DUMP2);
19746
19747 if($Content1 eq $Content2)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040019748 {
Andrey Ponomarenko85043792012-05-14 16:48:07 +040019749 # clean memory
19750 undef $Content2;
19751
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040019752 # read a number of headers, libs, symbols and types
Andrey Ponomarenko85043792012-05-14 16:48:07 +040019753 my $ABIdump = eval($Content1);
19754
19755 # clean memory
19756 undef $Content1;
19757
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040019758 if(not $ABIdump) {
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040019759 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 +040019760 }
19761 if(not $ABIdump->{"TypeInfo"})
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040019762 { # support for old dumps
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040019763 $ABIdump->{"TypeInfo"} = $ABIdump->{"TypeDescr"};
19764 }
19765 if(not $ABIdump->{"SymbolInfo"})
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040019766 { # support for old dumps
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040019767 $ABIdump->{"SymbolInfo"} = $ABIdump->{"FuncDescr"};
19768 }
19769 read_Headers_DumpInfo($ABIdump, 1);
19770 read_Libs_DumpInfo($ABIdump, 1);
19771 read_Machine_DumpInfo($ABIdump, 1);
19772 read_Machine_DumpInfo($ABIdump, 2);
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040019773
19774 %{$CheckedTypes{"Binary"}} = %{$ABIdump->{"TypeInfo"}};
19775 %{$CheckedTypes{"Source"}} = %{$ABIdump->{"TypeInfo"}};
19776
19777 %{$CheckedSymbols{"Binary"}} = %{$ABIdump->{"SymbolInfo"}};
19778 %{$CheckedSymbols{"Source"}} = %{$ABIdump->{"SymbolInfo"}};
19779
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040019780 $Descriptor{1}{"Version"} = $TargetVersion{1}?$TargetVersion{1}:$ABIdump->{"LibraryVersion"};
19781 $Descriptor{2}{"Version"} = $TargetVersion{2}?$TargetVersion{2}:$ABIdump->{"LibraryVersion"};
19782 exitReport();
19783 }
19784 }
19785 }
19786}
19787
19788sub initLogging($)
19789{
19790 my $LibVersion = $_[0];
19791 # create log directory
19792 my ($LOG_DIR, $LOG_FILE) = ("logs/$TargetLibraryName/".$Descriptor{$LibVersion}{"Version"}, "log.txt");
19793 if($OutputLogPath{$LibVersion})
19794 { # user-defined by -log-path option
19795 ($LOG_DIR, $LOG_FILE) = separate_path($OutputLogPath{$LibVersion});
19796 }
19797 if($LogMode ne "n") {
19798 mkpath($LOG_DIR);
19799 }
19800 $LOG_PATH{$LibVersion} = get_abs_path($LOG_DIR)."/".$LOG_FILE;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040019801 if($Debug)
19802 { # debug directory
19803 $DEBUG_PATH{$LibVersion} = "debug/$TargetLibraryName/".$Descriptor{$LibVersion}{"Version"};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040019804 }
Andrey Ponomarenko35c44fd2012-06-18 17:50:25 +040019805 resetLogging($LibVersion);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040019806}
19807
19808sub writeLog($$)
19809{
19810 my ($LibVersion, $Msg) = @_;
19811 if($LogMode ne "n") {
19812 appendFile($LOG_PATH{$LibVersion}, $Msg);
19813 }
19814}
19815
19816sub resetLogging($)
19817{
19818 my $LibVersion = $_[0];
19819 if($LogMode!~/a|n/)
19820 { # remove old log
19821 unlink($LOG_PATH{$LibVersion});
Andrey Ponomarenko35c44fd2012-06-18 17:50:25 +040019822 if($Debug) {
19823 rmtree($DEBUG_PATH{$LibVersion});
19824 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040019825 }
19826}
19827
19828sub printErrorLog($)
19829{
19830 my $LibVersion = $_[0];
19831 if($LogMode ne "n") {
19832 printMsg("ERROR", "see log for details:\n ".$LOG_PATH{$LibVersion}."\n");
19833 }
19834}
19835
19836sub isDump($)
19837{
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040019838 if(get_filename($_[0])=~/\A(.+)\.(abi|abidump)(\.tar\.gz|\.zip|\.xml|)\Z/) {
19839 return $1;
19840 }
19841 return 0;
19842}
19843
19844sub isDump_U($)
19845{
19846 if(get_filename($_[0])=~/\A(.+)\.(abi|abidump)(\.xml|)\Z/) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040019847 return $1;
19848 }
19849 return 0;
19850}
19851
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040019852sub compareInit()
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040019853{
19854 # read input XML descriptors or ABI dumps
19855 if(not $Descriptor{1}{"Path"}) {
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040019856 exitStatus("Error", "-old option is not specified");
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040019857 }
19858 my @DParts1 = split(/\s*,\s*/, $Descriptor{1}{"Path"});
19859 foreach my $Part (@DParts1)
19860 {
19861 if(not -e $Part) {
19862 exitStatus("Access_Error", "can't access \'$Part\'");
19863 }
19864 }
19865 if(not $Descriptor{2}{"Path"}) {
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040019866 exitStatus("Error", "-new option is not specified");
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040019867 }
19868 my @DParts2 = split(/\s*,\s*/, $Descriptor{2}{"Path"});
19869 foreach my $Part (@DParts2)
19870 {
19871 if(not -e $Part) {
19872 exitStatus("Access_Error", "can't access \'$Part\'");
19873 }
19874 }
19875 detect_default_paths("bin"); # to extract dumps
19876 if($#DParts1==0 and $#DParts2==0
19877 and isDump($Descriptor{1}{"Path"})
19878 and isDump($Descriptor{2}{"Path"}))
19879 { # optimization: equal ABI dumps
19880 quickEmptyReports();
19881 }
19882 checkVersionNum(1, $Descriptor{1}{"Path"});
19883 checkVersionNum(2, $Descriptor{2}{"Path"});
19884 printMsg("INFO", "preparation, please wait ...");
19885 foreach my $Part (@DParts1)
19886 {
19887 if(isDump($Part)) {
19888 read_ABI_Dump(1, $Part);
19889 }
19890 else {
19891 readDescriptor(1, createDescriptor(1, $Part));
19892 }
19893 }
19894 foreach my $Part (@DParts2)
19895 {
19896 if(isDump($Part)) {
19897 read_ABI_Dump(2, $Part);
19898 }
19899 else {
19900 readDescriptor(2, createDescriptor(2, $Part));
19901 }
19902 }
19903 initLogging(1);
19904 initLogging(2);
19905 # check consistency
19906 if(not $Descriptor{1}{"Headers"}
19907 and not $Descriptor{1}{"Libs"}) {
19908 exitStatus("Error", "descriptor d1 does not contain both header files and libraries info");
19909 }
19910 if(not $Descriptor{2}{"Headers"}
19911 and not $Descriptor{2}{"Libs"}) {
19912 exitStatus("Error", "descriptor d2 does not contain both header files and libraries info");
19913 }
19914 if($Descriptor{1}{"Headers"} and not $Descriptor{1}{"Libs"}
19915 and not $Descriptor{2}{"Headers"} and $Descriptor{2}{"Libs"}) {
19916 exitStatus("Error", "can't compare headers with $SLIB_TYPE libraries");
19917 }
19918 elsif(not $Descriptor{1}{"Headers"} and $Descriptor{1}{"Libs"}
19919 and $Descriptor{2}{"Headers"} and not $Descriptor{2}{"Libs"}) {
19920 exitStatus("Error", "can't compare $SLIB_TYPE libraries with headers");
19921 }
Andrey Ponomarenkobdc85a92012-11-12 17:28:12 +040019922 if(not $Descriptor{1}{"Headers"})
19923 {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040019924 if($CheckHeadersOnly_Opt) {
19925 exitStatus("Error", "can't find header files info in descriptor d1");
19926 }
19927 }
Andrey Ponomarenkobdc85a92012-11-12 17:28:12 +040019928 if(not $Descriptor{2}{"Headers"})
19929 {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040019930 if($CheckHeadersOnly_Opt) {
19931 exitStatus("Error", "can't find header files info in descriptor d2");
19932 }
19933 }
19934 if(not $Descriptor{1}{"Headers"}
Andrey Ponomarenkobdc85a92012-11-12 17:28:12 +040019935 or not $Descriptor{2}{"Headers"})
19936 {
19937 if(not $CheckObjectsOnly_Opt)
19938 {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040019939 printMsg("WARNING", "comparing $SLIB_TYPE libraries only");
19940 $CheckObjectsOnly = 1;
19941 }
19942 }
Andrey Ponomarenkobdc85a92012-11-12 17:28:12 +040019943 if(not $Descriptor{1}{"Libs"})
19944 {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040019945 if($CheckObjectsOnly_Opt) {
19946 exitStatus("Error", "can't find $SLIB_TYPE libraries info in descriptor d1");
19947 }
19948 }
Andrey Ponomarenkobdc85a92012-11-12 17:28:12 +040019949 if(not $Descriptor{2}{"Libs"})
19950 {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040019951 if($CheckObjectsOnly_Opt) {
19952 exitStatus("Error", "can't find $SLIB_TYPE libraries info in descriptor d2");
19953 }
19954 }
19955 if(not $Descriptor{1}{"Libs"}
19956 or not $Descriptor{2}{"Libs"})
19957 { # comparing standalone header files
19958 # comparing ABI dumps created with --headers-only
19959 if(not $CheckHeadersOnly_Opt)
19960 {
19961 printMsg("WARNING", "checking headers only");
19962 $CheckHeadersOnly = 1;
19963 }
19964 }
19965 if($UseDumps)
19966 { # --use-dumps
19967 # parallel processing
19968 my $pid = fork();
19969 if($pid)
19970 { # dump on two CPU cores
19971 my @PARAMS = ("-dump", $Descriptor{1}{"Path"}, "-l", $TargetLibraryName);
19972 if($RelativeDirectory{1}) {
19973 @PARAMS = (@PARAMS, "-relpath", $RelativeDirectory{1});
19974 }
19975 if($OutputLogPath{1}) {
19976 @PARAMS = (@PARAMS, "-log-path", $OutputLogPath{1});
19977 }
19978 if($CrossGcc) {
19979 @PARAMS = (@PARAMS, "-cross-gcc", $CrossGcc);
19980 }
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040019981 if($Quiet)
19982 {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040019983 @PARAMS = (@PARAMS, "-quiet");
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040019984 @PARAMS = (@PARAMS, "-logging-mode", "a");
19985 }
19986 elsif($LogMode and $LogMode ne "w")
19987 { # "w" is default
19988 @PARAMS = (@PARAMS, "-logging-mode", $LogMode);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040019989 }
19990 if($ExtendedCheck) {
19991 @PARAMS = (@PARAMS, "-extended");
19992 }
19993 if($UserLang) {
19994 @PARAMS = (@PARAMS, "-lang", $UserLang);
19995 }
19996 if($TargetVersion{1}) {
19997 @PARAMS = (@PARAMS, "-vnum", $TargetVersion{1});
19998 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +040019999 if($BinaryOnly) {
20000 @PARAMS = (@PARAMS, "-binary");
20001 }
20002 if($SourceOnly) {
20003 @PARAMS = (@PARAMS, "-source");
20004 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040020005 if($SortDump) {
20006 @PARAMS = (@PARAMS, "-sort");
20007 }
Andrey Ponomarenko01117f12012-06-26 12:23:02 +040020008 if($DumpFormat and $DumpFormat ne "perl") {
20009 @PARAMS = (@PARAMS, "-dump-format", $DumpFormat);
20010 }
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +040020011 if($CheckHeadersOnly) {
20012 @PARAMS = (@PARAMS, "-headers-only");
20013 }
20014 if($CheckObjectsOnly) {
20015 @PARAMS = (@PARAMS, "-objects-only");
20016 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +040020017 if($Debug)
20018 {
20019 @PARAMS = (@PARAMS, "-debug");
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040020020 printMsg("INFO", "running perl $0 @PARAMS");
Andrey Ponomarenko85043792012-05-14 16:48:07 +040020021 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040020022 system("perl", $0, @PARAMS);
20023 if($?) {
20024 exit(1);
20025 }
20026 }
20027 else
20028 { # child
20029 my @PARAMS = ("-dump", $Descriptor{2}{"Path"}, "-l", $TargetLibraryName);
20030 if($RelativeDirectory{2}) {
20031 @PARAMS = (@PARAMS, "-relpath", $RelativeDirectory{2});
20032 }
20033 if($OutputLogPath{2}) {
20034 @PARAMS = (@PARAMS, "-log-path", $OutputLogPath{2});
20035 }
20036 if($CrossGcc) {
20037 @PARAMS = (@PARAMS, "-cross-gcc", $CrossGcc);
20038 }
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040020039 if($Quiet)
20040 {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040020041 @PARAMS = (@PARAMS, "-quiet");
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040020042 @PARAMS = (@PARAMS, "-logging-mode", "a");
20043 }
20044 elsif($LogMode and $LogMode ne "w")
20045 { # "w" is default
20046 @PARAMS = (@PARAMS, "-logging-mode", $LogMode);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040020047 }
20048 if($ExtendedCheck) {
20049 @PARAMS = (@PARAMS, "-extended");
20050 }
20051 if($UserLang) {
20052 @PARAMS = (@PARAMS, "-lang", $UserLang);
20053 }
20054 if($TargetVersion{2}) {
20055 @PARAMS = (@PARAMS, "-vnum", $TargetVersion{2});
20056 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +040020057 if($BinaryOnly) {
20058 @PARAMS = (@PARAMS, "-binary");
20059 }
20060 if($SourceOnly) {
20061 @PARAMS = (@PARAMS, "-source");
20062 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040020063 if($SortDump) {
20064 @PARAMS = (@PARAMS, "-sort");
20065 }
Andrey Ponomarenko01117f12012-06-26 12:23:02 +040020066 if($DumpFormat and $DumpFormat ne "perl") {
20067 @PARAMS = (@PARAMS, "-dump-format", $DumpFormat);
20068 }
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +040020069 if($CheckHeadersOnly) {
20070 @PARAMS = (@PARAMS, "-headers-only");
20071 }
20072 if($CheckObjectsOnly) {
20073 @PARAMS = (@PARAMS, "-objects-only");
20074 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +040020075 if($Debug)
20076 {
20077 @PARAMS = (@PARAMS, "-debug");
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040020078 printMsg("INFO", "running perl $0 @PARAMS");
Andrey Ponomarenko85043792012-05-14 16:48:07 +040020079 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040020080 system("perl", $0, @PARAMS);
20081 if($?) {
20082 exit(1);
20083 }
20084 else {
20085 exit(0);
20086 }
20087 }
20088 waitpid($pid, 0);
20089 my @CMP_PARAMS = ("-l", $TargetLibraryName);
20090 @CMP_PARAMS = (@CMP_PARAMS, "-d1", "abi_dumps/$TargetLibraryName/".$TargetLibraryName."_".$Descriptor{1}{"Version"}.".abi.$AR_EXT");
20091 @CMP_PARAMS = (@CMP_PARAMS, "-d2", "abi_dumps/$TargetLibraryName/".$TargetLibraryName."_".$Descriptor{2}{"Version"}.".abi.$AR_EXT");
20092 if($TargetLibraryFName ne $TargetLibraryName) {
20093 @CMP_PARAMS = (@CMP_PARAMS, "-l-full", $TargetLibraryFName);
20094 }
20095 if($ShowRetVal) {
20096 @CMP_PARAMS = (@CMP_PARAMS, "-show-retval");
20097 }
20098 if($CrossGcc) {
20099 @CMP_PARAMS = (@CMP_PARAMS, "-cross-gcc", $CrossGcc);
20100 }
Andrey Ponomarenko35c44fd2012-06-18 17:50:25 +040020101 @CMP_PARAMS = (@CMP_PARAMS, "-logging-mode", "a");
20102 if($Quiet) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040020103 @CMP_PARAMS = (@CMP_PARAMS, "-quiet");
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040020104 }
20105 if($ReportFormat and $ReportFormat ne "html")
20106 { # HTML is default format
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040020107 @CMP_PARAMS = (@CMP_PARAMS, "-report-format", $ReportFormat);
20108 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040020109 if($OutputReportPath) {
20110 @CMP_PARAMS = (@CMP_PARAMS, "-report-path", $OutputReportPath);
20111 }
20112 if($BinaryReportPath) {
20113 @CMP_PARAMS = (@CMP_PARAMS, "-bin-report-path", $BinaryReportPath);
20114 }
20115 if($SourceReportPath) {
20116 @CMP_PARAMS = (@CMP_PARAMS, "-src-report-path", $SourceReportPath);
20117 }
20118 if($LoggingPath) {
20119 @CMP_PARAMS = (@CMP_PARAMS, "-log-path", $LoggingPath);
20120 }
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +040020121 if($CheckHeadersOnly) {
20122 @CMP_PARAMS = (@CMP_PARAMS, "-headers-only");
20123 }
20124 if($CheckObjectsOnly) {
20125 @CMP_PARAMS = (@CMP_PARAMS, "-objects-only");
20126 }
20127 if($BinaryOnly) {
20128 @CMP_PARAMS = (@CMP_PARAMS, "-binary");
20129 }
20130 if($SourceOnly) {
20131 @CMP_PARAMS = (@CMP_PARAMS, "-source");
20132 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +040020133 if($Browse) {
20134 @CMP_PARAMS = (@CMP_PARAMS, "-browse", $Browse);
20135 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040020136 if($OpenReport) {
20137 @CMP_PARAMS = (@CMP_PARAMS, "-open");
20138 }
20139 if($Debug)
20140 {
20141 @CMP_PARAMS = (@CMP_PARAMS, "-debug");
20142 printMsg("INFO", "running perl $0 @CMP_PARAMS");
Andrey Ponomarenko85043792012-05-14 16:48:07 +040020143 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040020144 system("perl", $0, @CMP_PARAMS);
20145 exit($?>>8);
20146 }
20147 if(not $Descriptor{1}{"Dump"}
20148 or not $Descriptor{2}{"Dump"})
20149 { # need GCC toolchain to analyze
20150 # header files and libraries
20151 detect_default_paths("inc|lib|gcc");
20152 }
20153 if(not $Descriptor{1}{"Dump"})
20154 {
20155 if(not $CheckHeadersOnly) {
20156 readLibs(1);
20157 }
20158 if($CheckHeadersOnly) {
20159 setLanguage(1, "C++");
20160 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +040020161 if(not $CheckObjectsOnly) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040020162 searchForHeaders(1);
20163 }
20164 $WORD_SIZE{1} = detectWordSize();
20165 }
20166 if(not $Descriptor{2}{"Dump"})
20167 {
20168 if(not $CheckHeadersOnly) {
20169 readLibs(2);
20170 }
20171 if($CheckHeadersOnly) {
20172 setLanguage(2, "C++");
20173 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +040020174 if(not $CheckObjectsOnly) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040020175 searchForHeaders(2);
20176 }
20177 $WORD_SIZE{2} = detectWordSize();
20178 }
20179 if($WORD_SIZE{1} ne $WORD_SIZE{2})
20180 { # support for old ABI dumps
20181 # try to synch different WORD sizes
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040020182 if(not checkDump(1, "2.1"))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040020183 {
20184 $WORD_SIZE{1} = $WORD_SIZE{2};
20185 printMsg("WARNING", "set WORD size to ".$WORD_SIZE{2}." bytes");
20186 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040020187 elsif(not checkDump(2, "2.1"))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040020188 {
20189 $WORD_SIZE{2} = $WORD_SIZE{1};
20190 printMsg("WARNING", "set WORD size to ".$WORD_SIZE{1}." bytes");
20191 }
20192 }
20193 elsif(not $WORD_SIZE{1}
20194 and not $WORD_SIZE{2})
20195 { # support for old ABI dumps
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040020196 $WORD_SIZE{1} = "4";
20197 $WORD_SIZE{2} = "4";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040020198 }
20199 if($Descriptor{1}{"Dump"})
20200 { # support for old ABI dumps
20201 prepareTypes(1);
20202 }
20203 if($Descriptor{2}{"Dump"})
20204 { # support for old ABI dumps
20205 prepareTypes(2);
20206 }
20207 if($AppPath and not keys(%{$Symbol_Library{1}})) {
20208 printMsg("WARNING", "the application ".get_filename($AppPath)." has no symbols imported from the $SLIB_TYPE libraries");
20209 }
20210 # started to process input data
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040020211 if(not $CheckObjectsOnly)
20212 {
20213 if($Descriptor{1}{"Headers"}
20214 and not $Descriptor{1}{"Dump"}) {
20215 readHeaders(1);
20216 }
20217 if($Descriptor{2}{"Headers"}
20218 and not $Descriptor{2}{"Dump"}) {
20219 readHeaders(2);
20220 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040020221 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +040020222
20223 # clean memory
20224 %SystemHeaders = ();
20225 %mangled_name_gcc = ();
20226
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040020227 prepareSymbols(1);
20228 prepareSymbols(2);
Andrey Ponomarenko16934472012-03-29 15:37:04 +040020229
Andrey Ponomarenko85043792012-05-14 16:48:07 +040020230 # clean memory
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040020231 %SymbolInfo = ();
Andrey Ponomarenko16934472012-03-29 15:37:04 +040020232
20233 # Virtual Tables
20234 registerVTable(1);
20235 registerVTable(2);
20236
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040020237 if(not checkDump(1, "1.22")
20238 and checkDump(2, "1.22"))
Andrey Ponomarenko16934472012-03-29 15:37:04 +040020239 { # support for old ABI dumps
20240 foreach my $ClassName (keys(%{$VirtualTable{2}}))
20241 {
20242 if($ClassName=~/</)
20243 { # templates
20244 if(not defined $VirtualTable{1}{$ClassName})
20245 { # synchronize
20246 delete($VirtualTable{2}{$ClassName});
20247 }
20248 }
20249 }
20250 }
20251
20252 registerOverriding(1);
20253 registerOverriding(2);
20254
20255 setVirtFuncPositions(1);
20256 setVirtFuncPositions(2);
20257
20258 # Other
20259 addParamNames(1);
20260 addParamNames(2);
20261
20262 detectChangedTypedefs();
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040020263}
20264
20265sub compareAPIs($)
20266{
20267 my $Level = $_[0];
20268 readRules($Level);
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +040020269 loadModule("CallConv");
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040020270 if($Level eq "Binary") {
20271 printMsg("INFO", "comparing ABIs ...");
20272 }
20273 else {
20274 printMsg("INFO", "comparing APIs ...");
20275 }
20276 if($CheckHeadersOnly
20277 or $Level eq "Source")
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040020278 { # added/removed in headers
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040020279 detectAdded_H($Level);
20280 detectRemoved_H($Level);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040020281 }
20282 else
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040020283 { # added/removed in libs
20284 detectAdded($Level);
20285 detectRemoved($Level);
20286 }
20287 if(not $CheckObjectsOnly)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040020288 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040020289 mergeSignatures($Level);
20290 if(keys(%{$CheckedSymbols{$Level}})) {
20291 mergeConstants($Level);
20292 }
20293 }
20294 if($CheckHeadersOnly
20295 or $Level eq "Source")
20296 { # added/removed in headers
20297 mergeHeaders($Level);
20298 }
20299 else
20300 { # added/removed in libs
20301 mergeLibs($Level);
20302 if($CheckImpl
20303 and $Level eq "Binary") {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040020304 mergeImpl();
20305 }
20306 }
20307}
20308
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040020309sub getSysOpts()
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040020310{
20311 my %Opts = (
20312 "OStarget"=>$OStarget,
20313 "Debug"=>$Debug,
20314 "Quiet"=>$Quiet,
20315 "LogMode"=>$LogMode,
20316 "CheckHeadersOnly"=>$CheckHeadersOnly,
20317
20318 "SystemRoot"=>$SystemRoot,
20319 "MODULES_DIR"=>$MODULES_DIR,
20320 "GCC_PATH"=>$GCC_PATH,
20321 "TargetSysInfo"=>$TargetSysInfo,
20322 "CrossPrefix"=>$CrossPrefix,
20323 "TargetLibraryName"=>$TargetLibraryName,
20324 "CrossGcc"=>$CrossGcc,
20325 "UseStaticLibs"=>$UseStaticLibs,
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040020326 "NoStdInc"=>$NoStdInc,
20327
20328 "BinaryOnly" => $BinaryOnly,
20329 "SourceOnly" => $SourceOnly
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040020330 );
20331 return \%Opts;
20332}
20333
20334sub get_CoreError($)
20335{
20336 my %CODE_ERROR = reverse(%ERROR_CODE);
20337 return $CODE_ERROR{$_[0]};
20338}
20339
20340sub scenario()
20341{
20342 if($StdOut)
20343 { # enable quiet mode
20344 $Quiet = 1;
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040020345 $JoinReport = 1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040020346 }
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040020347 if(not $LogMode)
20348 { # default
20349 $LogMode = "w";
20350 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040020351 if($UserLang)
20352 { # --lang=C++
20353 $UserLang = uc($UserLang);
20354 $COMMON_LANGUAGE{1}=$UserLang;
20355 $COMMON_LANGUAGE{2}=$UserLang;
20356 }
20357 if($LoggingPath)
20358 {
20359 $OutputLogPath{1} = $LoggingPath;
20360 $OutputLogPath{2} = $LoggingPath;
20361 if($Quiet) {
20362 $COMMON_LOG_PATH = $LoggingPath;
20363 }
20364 }
Andrey Ponomarenko5c09ef32012-06-14 18:17:33 +040020365 if($OutputDumpPath)
20366 { # validate
20367 if($OutputDumpPath!~/\.abi(\.\Q$AR_EXT\E|)\Z/) {
20368 exitStatus("Error", "the dump path should be a path to *.abi.$AR_EXT or *.abi file");
20369 }
20370 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040020371 if($BinaryOnly and $SourceOnly)
20372 { # both --binary and --source
20373 # is the default mode
20374 $DoubleReport = 1;
20375 $JoinReport = 0;
20376 $BinaryOnly = 0;
20377 $SourceOnly = 0;
20378 if($OutputReportPath)
20379 { # --report-path
20380 $DoubleReport = 0;
20381 $JoinReport = 1;
20382 }
20383 }
20384 elsif($BinaryOnly or $SourceOnly)
20385 { # --binary or --source
20386 $DoubleReport = 0;
20387 $JoinReport = 0;
20388 }
20389 if($UseXML)
20390 { # --xml option
20391 $ReportFormat = "xml";
Andrey Ponomarenko5c09ef32012-06-14 18:17:33 +040020392 $DumpFormat = "xml";
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040020393 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040020394 if($ReportFormat)
20395 { # validate
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040020396 $ReportFormat = lc($ReportFormat);
20397 if($ReportFormat!~/\A(xml|html|htm)\Z/) {
Andrey Ponomarenko5c09ef32012-06-14 18:17:33 +040020398 exitStatus("Error", "unknown report format \'$ReportFormat\'");
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040020399 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040020400 if($ReportFormat eq "htm")
20401 { # HTM == HTML
20402 $ReportFormat = "html";
20403 }
20404 elsif($ReportFormat eq "xml")
20405 { # --report-format=XML equal to --xml
20406 $UseXML = 1;
20407 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040020408 }
20409 else
20410 { # default: HTML
20411 $ReportFormat = "html";
20412 }
Andrey Ponomarenko5c09ef32012-06-14 18:17:33 +040020413 if($DumpFormat)
20414 { # validate
20415 $DumpFormat = lc($DumpFormat);
20416 if($DumpFormat!~/\A(xml|perl)\Z/) {
20417 exitStatus("Error", "unknown ABI dump format \'$DumpFormat\'");
20418 }
20419 if($DumpFormat eq "xml")
20420 { # --dump-format=XML equal to --xml
20421 $UseXML = 1;
20422 }
20423 }
20424 else
Andrey Ponomarenko01117f12012-06-26 12:23:02 +040020425 { # default: Perl Data::Dumper
Andrey Ponomarenko5c09ef32012-06-14 18:17:33 +040020426 $DumpFormat = "perl";
20427 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040020428 if($Quiet and $LogMode!~/a|n/)
20429 { # --quiet log
20430 if(-f $COMMON_LOG_PATH) {
20431 unlink($COMMON_LOG_PATH);
20432 }
20433 }
Andrey Ponomarenko4b077f82012-12-04 16:04:36 +040020434 if($ExtraInfo) {
Andrey Ponomarenko570ece52012-11-30 16:36:44 +040020435 $CheckUndefined = 1;
20436 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040020437 if($TestTool and $UseDumps)
20438 { # --test && --use-dumps == --test-dump
20439 $TestDump = 1;
20440 }
Andrey Ponomarenko570ece52012-11-30 16:36:44 +040020441 if($Help)
20442 {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040020443 HELP_MESSAGE();
20444 exit(0);
20445 }
20446 if($InfoMsg) {
20447 INFO_MESSAGE();
20448 exit(0);
20449 }
Andrey Ponomarenko570ece52012-11-30 16:36:44 +040020450 if($ShowVersion)
20451 {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040020452 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.");
20453 exit(0);
20454 }
Andrey Ponomarenko570ece52012-11-30 16:36:44 +040020455 if($DumpVersion)
20456 {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040020457 printMsg("INFO", $TOOL_VERSION);
20458 exit(0);
20459 }
20460 if($ExtendedCheck) {
20461 $CheckHeadersOnly = 1;
20462 }
20463 if($SystemRoot_Opt)
20464 { # user defined root
20465 if(not -e $SystemRoot_Opt) {
20466 exitStatus("Access_Error", "can't access \'$SystemRoot\'");
20467 }
20468 $SystemRoot = $SystemRoot_Opt;
20469 $SystemRoot=~s/[\/]+\Z//g;
20470 if($SystemRoot) {
20471 $SystemRoot = get_abs_path($SystemRoot);
20472 }
20473 }
20474 $Data::Dumper::Sortkeys = 1;
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +040020475
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040020476 if($SortDump)
20477 {
20478 $Data::Dumper::Useperl = 1;
20479 $Data::Dumper::Sortkeys = \&dump_sorting;
20480 }
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +040020481
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040020482 if($TargetLibsPath)
20483 {
20484 if(not -f $TargetLibsPath) {
20485 exitStatus("Access_Error", "can't access file \'$TargetLibsPath\'");
20486 }
20487 foreach my $Lib (split(/\s*\n\s*/, readFile($TargetLibsPath))) {
20488 $TargetLibs{$Lib} = 1;
20489 }
20490 }
20491 if($TargetHeadersPath)
20492 { # --headers-list
20493 if(not -f $TargetHeadersPath) {
20494 exitStatus("Access_Error", "can't access file \'$TargetHeadersPath\'");
20495 }
20496 foreach my $Header (split(/\s*\n\s*/, readFile($TargetHeadersPath)))
20497 {
20498 $TargetHeaders{1}{$Header} = 1;
20499 $TargetHeaders{2}{$Header} = 1;
20500 }
20501 }
20502 if($TargetHeader)
20503 { # --header
20504 $TargetHeaders{1}{$TargetHeader} = 1;
20505 $TargetHeaders{2}{$TargetHeader} = 1;
20506 }
20507 if($TestTool
20508 or $TestDump)
20509 { # --test, --test-dump
20510 detect_default_paths("bin|gcc"); # to compile libs
20511 loadModule("RegTests");
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +040020512 testTool($TestDump, $Debug, $Quiet, $ExtendedCheck, $LogMode, $ReportFormat, $DumpFormat,
20513 $LIB_EXT, $GCC_PATH, $Browse, $OpenReport, $SortDump, $CheckHeadersOnly, $CheckObjectsOnly);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040020514 exit(0);
20515 }
20516 if($DumpSystem)
20517 { # --dump-system
20518 loadModule("SysCheck");
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040020519 if($DumpSystem=~/\.(xml|desc)\Z/)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040020520 { # system XML descriptor
20521 if(not -f $DumpSystem) {
20522 exitStatus("Access_Error", "can't access file \'$DumpSystem\'");
20523 }
20524 my $Ret = readSystemDescriptor(readFile($DumpSystem));
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040020525 foreach (@{$Ret->{"Tools"}})
20526 {
Andrey Ponomarenko570ece52012-11-30 16:36:44 +040020527 push_U($SystemPaths{"bin"}, $_);
20528 $TargetTools{$_} = 1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040020529 }
20530 if($Ret->{"CrossPrefix"}) {
20531 $CrossPrefix = $Ret->{"CrossPrefix"};
20532 }
20533 }
20534 elsif($SystemRoot_Opt)
20535 { # -sysroot "/" option
20536 # default target: /usr/lib, /usr/include
20537 # search libs: /usr/lib and /lib
20538 if(not -e $SystemRoot."/usr/lib") {
20539 exitStatus("Access_Error", "can't access '".$SystemRoot."/usr/lib'");
20540 }
20541 if(not -e $SystemRoot."/lib") {
20542 exitStatus("Access_Error", "can't access '".$SystemRoot."/lib'");
20543 }
20544 if(not -e $SystemRoot."/usr/include") {
20545 exitStatus("Access_Error", "can't access '".$SystemRoot."/usr/include'");
20546 }
20547 readSystemDescriptor("
20548 <name>
20549 $DumpSystem
20550 </name>
20551 <headers>
20552 $SystemRoot/usr/include
20553 </headers>
20554 <libs>
20555 $SystemRoot/usr/lib
20556 </libs>
20557 <search_libs>
20558 $SystemRoot/lib
20559 </search_libs>");
20560 }
20561 else {
20562 exitStatus("Error", "-sysroot <dirpath> option should be specified, usually it's \"/\"");
20563 }
20564 detect_default_paths("bin|gcc"); # to check symbols
20565 if($OStarget eq "windows")
20566 { # to run dumpbin.exe
20567 # and undname.exe
20568 check_win32_env();
20569 }
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040020570 dumpSystem(getSysOpts());
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040020571 exit(0);
20572 }
20573 if($CmpSystems)
20574 { # --cmp-systems
20575 detect_default_paths("bin"); # to extract dumps
20576 loadModule("SysCheck");
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040020577 cmpSystems($Descriptor{1}{"Path"}, $Descriptor{2}{"Path"}, getSysOpts());
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040020578 exit(0);
20579 }
Andrey Ponomarenko570ece52012-11-30 16:36:44 +040020580 if($GenerateTemplate)
20581 {
20582 writeFile("VERSION.xml", $DescriptorTemplate."\n");
20583 printMsg("INFO", "XML-descriptor template ./VERSION.xml has been generated");
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040020584 exit(0);
20585 }
20586 if(not $TargetLibraryName) {
Andrey Ponomarenko570ece52012-11-30 16:36:44 +040020587 exitStatus("Error", "library name is not selected (-l option)");
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040020588 }
20589 else
20590 { # validate library name
20591 if($TargetLibraryName=~/[\*\/\\]/) {
20592 exitStatus("Error", "\"\\\", \"\/\" and \"*\" symbols are not allowed in the library name");
20593 }
20594 }
20595 if(not $TargetLibraryFName) {
20596 $TargetLibraryFName = $TargetLibraryName;
20597 }
20598 if($CheckHeadersOnly_Opt and $CheckObjectsOnly_Opt) {
20599 exitStatus("Error", "you can't specify both -headers-only and -objects-only options at the same time");
20600 }
20601 if($SymbolsListPath)
20602 {
20603 if(not -f $SymbolsListPath) {
20604 exitStatus("Access_Error", "can't access file \'$SymbolsListPath\'");
20605 }
20606 foreach my $Interface (split(/\s*\n\s*/, readFile($SymbolsListPath))) {
20607 $SymbolsList{$Interface} = 1;
20608 }
20609 }
20610 if($SkipHeadersPath)
20611 {
20612 if(not -f $SkipHeadersPath) {
20613 exitStatus("Access_Error", "can't access file \'$SkipHeadersPath\'");
20614 }
20615 foreach my $Path (split(/\s*\n\s*/, readFile($SkipHeadersPath)))
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040020616 { # register for both versions
20617 $SkipHeadersList{1}{$Path} = 1;
20618 $SkipHeadersList{2}{$Path} = 1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040020619 my ($CPath, $Type) = classifyPath($Path);
20620 $SkipHeaders{1}{$Type}{$CPath} = 1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040020621 $SkipHeaders{2}{$Type}{$CPath} = 1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040020622 }
20623 }
20624 if($ParamNamesPath)
20625 {
20626 if(not -f $ParamNamesPath) {
20627 exitStatus("Access_Error", "can't access file \'$ParamNamesPath\'");
20628 }
20629 foreach my $Line (split(/\n/, readFile($ParamNamesPath)))
20630 {
20631 if($Line=~s/\A(\w+)\;//)
20632 {
20633 my $Interface = $1;
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040020634 if($Line=~/;(\d+);/)
20635 {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040020636 while($Line=~s/(\d+);(\w+)//) {
20637 $AddIntParams{$Interface}{$1}=$2;
20638 }
20639 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040020640 else
20641 {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040020642 my $Num = 0;
20643 foreach my $Name (split(/;/, $Line)) {
20644 $AddIntParams{$Interface}{$Num++}=$Name;
20645 }
20646 }
20647 }
20648 }
20649 }
20650 if($AppPath)
20651 {
20652 if(not -f $AppPath) {
20653 exitStatus("Access_Error", "can't access file \'$AppPath\'");
20654 }
Andrey Ponomarenko16934472012-03-29 15:37:04 +040020655 foreach my $Interface (readSymbols_App($AppPath)) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040020656 $SymbolsList_App{$Interface} = 1;
20657 }
20658 }
20659 if($DumpAPI)
20660 { # --dump-abi
20661 # make an API dump
20662 create_ABI_Dump();
20663 exit($COMPILE_ERRORS);
20664 }
20665 # default: compare APIs
20666 # -d1 <path>
20667 # -d2 <path>
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040020668 compareInit();
20669 if($JoinReport or $DoubleReport)
20670 {
20671 compareAPIs("Binary");
20672 compareAPIs("Source");
20673 }
20674 elsif($BinaryOnly) {
20675 compareAPIs("Binary");
20676 }
20677 elsif($SourceOnly) {
20678 compareAPIs("Source");
20679 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040020680 exitReport();
20681}
20682
20683scenario();