blob: 15885c856c021215a0041825217e51d6822a8966 [file] [log] [blame]
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04001#!/usr/bin/perl
2###########################################################################
Andrey Ponomarenko9927e332012-10-19 10:50:48 +04003# ABI Compliance Checker (ACC) 1.98.4
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
26# - Xcode (gcc, otool, c++filt)
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 Ponomarenko9927e332012-10-19 10:50:48 +040062my $TOOL_VERSION = "1.98.4";
63my $ABI_DUMP_VERSION = "2.19.1";
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,
87$SkipHeadersPath, $Cpp2003, $LogMode, $StdOut, $ListAffected, $ReportFormat,
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040088$UserLang, $TargetHeadersPath, $BinaryOnly, $SourceOnly, $BinaryReportPath,
Andrey Ponomarenko5c09ef32012-06-14 18:17:33 +040089$SourceReportPath, $UseXML, $Browse, $OpenReport, $SortDump, $DumpFormat);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040090
91my $CmdName = get_filename($0);
92my %OS_LibExt = (
93 "dynamic" => {
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040094 "linux"=>"so",
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040095 "macos"=>"dylib",
96 "windows"=>"dll",
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040097 "symbian"=>"dso",
98 "default"=>"so"
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040099 },
100 "static" => {
Andrey Ponomarenko9927e332012-10-19 10:50:48 +0400101 "linux"=>"a",
Andrey Ponomarenkoab282102012-03-11 11:57:02 +0400102 "windows"=>"lib",
Andrey Ponomarenko9927e332012-10-19 10:50:48 +0400103 "symbian"=>"lib",
104 "default"=>"a"
Andrey Ponomarenkoab282102012-03-11 11:57:02 +0400105 }
106);
107
108my %OS_Archive = (
109 "windows"=>"zip",
110 "default"=>"tar.gz"
111);
112
113my %ERROR_CODE = (
114 # Compatible verdict
115 "Compatible"=>0,
116 "Success"=>0,
117 # Incompatible verdict
118 "Incompatible"=>1,
119 # Undifferentiated error code
120 "Error"=>2,
121 # System command is not found
122 "Not_Found"=>3,
123 # Cannot access input files
124 "Access_Error"=>4,
125 # Cannot compile header files
126 "Cannot_Compile"=>5,
127 # Header compiled with errors
128 "Compile_Error"=>6,
129 # Invalid input ABI dump
130 "Invalid_Dump"=>7,
131 # Incompatible version of ABI dump
132 "Dump_Version"=>8,
133 # Cannot find a module
134 "Module_Error"=>9,
135 # Empty intersection between
136 # headers and shared objects
137 "Empty_Intersection"=>10,
138 # Empty set of symbols in headers
139 "Empty_Set"=>11
140);
141
142my %HomePage = (
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +0400143 "Wiki"=>"http://ispras.linuxbase.org/index.php/ABI_compliance_checker",
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +0400144 "Dev1"=>"https://github.com/lvc/abi-compliance-checker",
145 "Dev2"=>"http://forge.ispras.ru/projects/abi-compliance-checker"
Andrey Ponomarenkoab282102012-03-11 11:57:02 +0400146);
147
148my $ShortUsage = "ABI Compliance Checker (ACC) $TOOL_VERSION
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +0400149A tool for checking backward compatibility of a C/C++ library API
Andrey Ponomarenkoab282102012-03-11 11:57:02 +0400150Copyright (C) 2012 ROSA Laboratory
151License: GNU LGPL or GNU GPL
152
153Usage: $CmdName [options]
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +0400154Example: $CmdName -lib NAME -old OLD.xml -new NEW.xml
Andrey Ponomarenkoab282102012-03-11 11:57:02 +0400155
156OLD.xml and NEW.xml are XML-descriptors:
157
158 <version>
159 1.0
160 </version>
161
162 <headers>
163 /path/to/headers/
164 </headers>
165
166 <libs>
167 /path/to/libraries/
168 </libs>
169
170More info: $CmdName --help\n";
171
172if($#ARGV==-1) {
173 printMsg("INFO", $ShortUsage);
174 exit(0);
175}
176
177foreach (2 .. $#ARGV)
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +0400178{ # correct comma separated options
Andrey Ponomarenkoab282102012-03-11 11:57:02 +0400179 if($ARGV[$_-1] eq ",") {
180 $ARGV[$_-2].=",".$ARGV[$_];
181 splice(@ARGV, $_-1, 2);
182 }
183 elsif($ARGV[$_-1]=~/,\Z/) {
184 $ARGV[$_-1].=$ARGV[$_];
185 splice(@ARGV, $_, 1);
186 }
187 elsif($ARGV[$_]=~/\A,/
188 and $ARGV[$_] ne ",") {
189 $ARGV[$_-1].=$ARGV[$_];
190 splice(@ARGV, $_, 1);
191 }
192}
193
194GetOptions("h|help!" => \$Help,
195 "i|info!" => \$InfoMsg,
196 "v|version!" => \$ShowVersion,
197 "dumpversion!" => \$DumpVersion,
198# general options
199 "l|lib|library=s" => \$TargetLibraryName,
200 "d1|old|o=s" => \$Descriptor{1}{"Path"},
201 "d2|new|n=s" => \$Descriptor{2}{"Path"},
202 "dump|dump-abi|dump_abi=s" => \$DumpAPI,
203 "old-dumps!" => \$UseOldDumps,
204# extra options
205 "d|descriptor-template!" => \$GenerateTemplate,
206 "app|application=s" => \$AppPath,
207 "static-libs!" => \$UseStaticLibs,
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +0400208 "cross-gcc|gcc-path=s" => \$CrossGcc,
209 "cross-prefix|gcc-prefix=s" => \$CrossPrefix,
Andrey Ponomarenkoab282102012-03-11 11:57:02 +0400210 "sysroot=s" => \$SystemRoot_Opt,
211 "v1|version1|vnum=s" => \$TargetVersion{1},
212 "v2|version2=s" => \$TargetVersion{2},
213 "s|strict!" => \$StrictCompat,
214 "symbols-list=s" => \$SymbolsListPath,
215 "skip-headers=s" => \$SkipHeadersPath,
216 "headers-only|headers_only!" => \$CheckHeadersOnly_Opt,
217 "objects-only!" => \$CheckObjectsOnly_Opt,
218 "check-impl|check-implementation!" => \$CheckImpl,
219 "show-retval!" => \$ShowRetVal,
220 "use-dumps!" => \$UseDumps,
221 "nostdinc!" => \$NoStdInc,
222 "dump-system=s" => \$DumpSystem,
223 "sysinfo=s" => \$TargetSysInfo,
224 "cmp-systems!" => \$CmpSystems,
225 "libs-list=s" => \$TargetLibsPath,
226 "headers-list=s" => \$TargetHeadersPath,
227 "header=s" => \$TargetHeader,
228 "ext|extended!" => \$ExtendedCheck,
229 "q|quiet!" => \$Quiet,
230 "stdout!" => \$StdOut,
231 "report-format=s" => \$ReportFormat,
Andrey Ponomarenko5c09ef32012-06-14 18:17:33 +0400232 "dump-format=s" => \$DumpFormat,
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +0400233 "xml!" => \$UseXML,
Andrey Ponomarenkoab282102012-03-11 11:57:02 +0400234 "lang=s" => \$UserLang,
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +0400235 "binary|bin|abi!" => \$BinaryOnly,
236 "source|src|api!" => \$SourceOnly,
Andrey Ponomarenkoab282102012-03-11 11:57:02 +0400237# other options
238 "test!" => \$TestTool,
239 "test-dump!" => \$TestDump,
240 "debug!" => \$Debug,
241 "cpp-compatible!" => \$Cpp2003,
242 "p|params=s" => \$ParamNamesPath,
243 "relpath1|relpath=s" => \$RelativeDirectory{1},
244 "relpath2=s" => \$RelativeDirectory{2},
245 "dump-path=s" => \$OutputDumpPath,
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +0400246 "sort!" => \$SortDump,
Andrey Ponomarenkoab282102012-03-11 11:57:02 +0400247 "report-path=s" => \$OutputReportPath,
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +0400248 "bin-report-path=s" => \$BinaryReportPath,
249 "src-report-path=s" => \$SourceReportPath,
Andrey Ponomarenkoab282102012-03-11 11:57:02 +0400250 "log-path=s" => \$LoggingPath,
251 "log1-path=s" => \$OutputLogPath{1},
252 "log2-path=s" => \$OutputLogPath{2},
253 "logging-mode=s" => \$LogMode,
254 "list-affected!" => \$ListAffected,
255 "l-full|lib-full=s" => \$TargetLibraryFName,
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +0400256 "component=s" => \$TargetComponent_Opt,
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +0400257 "b|browse=s" => \$Browse,
258 "open!" => \$OpenReport
Andrey Ponomarenkoab282102012-03-11 11:57:02 +0400259) or ERR_MESSAGE();
260
261sub ERR_MESSAGE()
262{
263 printMsg("INFO", "\n".$ShortUsage);
264 exit($ERROR_CODE{"Error"});
265}
266
267my $LIB_TYPE = $UseStaticLibs?"static":"dynamic";
268my $SLIB_TYPE = $LIB_TYPE;
269if($OSgroup!~/macos|windows/ and $SLIB_TYPE eq "dynamic")
270{ # show as "shared" library
271 $SLIB_TYPE = "shared";
272}
273my $LIB_EXT = getLIB_EXT($OSgroup);
274my $AR_EXT = getAR_EXT($OSgroup);
275my $BYTE_SIZE = 8;
276my $COMMON_LOG_PATH = "logs/run.log";
277
278my $HelpMessage="
279NAME:
280 ABI Compliance Checker ($CmdName)
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +0400281 Check backward compatibility of a C/C++ library API
Andrey Ponomarenkoab282102012-03-11 11:57:02 +0400282
283DESCRIPTION:
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +0400284 ABI Compliance Checker (ACC) is a tool for checking backward binary and
285 source-level compatibility of a $SLIB_TYPE C/C++ library. The tool checks
286 header files and $SLIB_TYPE libraries (*.$LIB_EXT) of old and new versions and
287 analyzes changes in API and ABI (ABI=API+compiler ABI) that may break binary
288 and/or source-level compatibility: changes in calling stack, v-table changes,
289 removed symbols, renamed fields, etc. Binary incompatibility may result in
290 crashing or incorrect behavior of applications built with an old version of
291 a library if they run on a new one. Source incompatibility may result in
292 recompilation errors with a new library version.
Andrey Ponomarenkoab282102012-03-11 11:57:02 +0400293
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +0400294 The tool is intended for developers of software libraries and maintainers
295 of operating systems who are interested in ensuring backward compatibility,
296 i.e. allow old applications to run or to be recompiled with newer library
297 versions.
298
299 Also the tool can be used by ISVs for checking applications portability to
300 new library versions. Found issues can be taken into account when adapting
301 the application to a new library version.
Andrey Ponomarenkoab282102012-03-11 11:57:02 +0400302
303 This tool is free software: you can redistribute it and/or modify it
304 under the terms of the GNU LGPL or GNU GPL.
305
306USAGE:
307 $CmdName [options]
308
309EXAMPLE:
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +0400310 $CmdName -lib NAME -old OLD.xml -new NEW.xml
Andrey Ponomarenkoab282102012-03-11 11:57:02 +0400311
312 OLD.xml and NEW.xml are XML-descriptors:
313
314 <version>
315 1.0
316 </version>
317
318 <headers>
319 /path1/to/header(s)/
320 /path2/to/header(s)/
321 ...
322 </headers>
323
324 <libs>
325 /path1/to/library(ies)/
326 /path2/to/library(ies)/
327 ...
328 </libs>
329
330INFORMATION OPTIONS:
331 -h|-help
332 Print this help.
333
334 -i|-info
335 Print complete info.
336
337 -v|-version
338 Print version information.
339
340 -dumpversion
341 Print the tool version ($TOOL_VERSION) and don't do anything else.
342
343GENERAL OPTIONS:
344 -l|-lib|-library <name>
345 Library name (without version).
346 It affects only on the path and the title of the report.
347
348 -d1|-old|-o <path>
349 Descriptor of 1st (old) library version.
350 It may be one of the following:
351
352 1. XML-descriptor (VERSION.xml file):
353
354 <version>
355 1.0
356 </version>
357
358 <headers>
359 /path1/to/header(s)/
360 /path2/to/header(s)/
361 ...
362 </headers>
363
364 <libs>
365 /path1/to/library(ies)/
366 /path2/to/library(ies)/
367 ...
368 </libs>
369
370 ... (XML-descriptor template
371 can be generated by -d option)
372
373 2. ABI dump generated by -dump option
374 3. Directory with headers and/or $SLIB_TYPE libraries
375 4. Single header file
376 5. Single $SLIB_TYPE library
377 6. Comma separated list of headers and/or libraries
378
379 If you are using an 2-6 descriptor types then you should
380 specify version numbers with -v1 <num> and -v2 <num> options too.
381
382 For more information, please see:
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +0400383 http://ispras.linuxbase.org/index.php/Library_Descriptor
Andrey Ponomarenkoab282102012-03-11 11:57:02 +0400384
385 -d2|-new|-n <path>
386 Descriptor of 2nd (new) library version.
387
388 -dump|-dump-abi <descriptor path(s)>
389 Dump library ABI to gzipped TXT format file. You can transfer it
390 anywhere and pass instead of the descriptor. Also it can be used
391 for debugging the tool. Compatible dump versions: ".majorVersion($ABI_DUMP_VERSION).".0<=V<=$ABI_DUMP_VERSION
392
393 -old-dumps
394 Enable support for old-version ABI dumps ($OLDEST_SUPPORTED_VERSION<=V<".majorVersion($ABI_DUMP_VERSION).".0).\n";
395
396sub HELP_MESSAGE() {
397 printMsg("INFO", $HelpMessage."
398MORE INFO:
399 $CmdName --info\n");
400}
401
402sub INFO_MESSAGE()
403{
404 printMsg("INFO", "$HelpMessage
405EXTRA OPTIONS:
406 -d|-descriptor-template
407 Create XML-descriptor template ./VERSION.xml
408
409 -app|-application <path>
410 This option allows to specify the application that should be checked
411 for portability to the new library version.
412
413 -static-libs
414 Check static libraries instead of the shared ones. The <libs> section
415 of the XML-descriptor should point to static libraries location.
416
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +0400417 -cross-gcc|-gcc-path <path>
Andrey Ponomarenkoab282102012-03-11 11:57:02 +0400418 Path to the cross GCC compiler to use instead of the usual (host) GCC.
419
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +0400420 -cross-prefix|-gcc-prefix <prefix>
Andrey Ponomarenkoab282102012-03-11 11:57:02 +0400421 GCC toolchain prefix.
422
423 -sysroot <dirpath>
424 Specify the alternative root directory. The tool will search for include
425 paths in the <dirpath>/usr/include and <dirpath>/usr/lib directories.
426
427 -v1|-version1 <num>
428 Specify 1st library version outside the descriptor. This option is needed
429 if you have prefered an alternative descriptor type (see -d1 option).
430
431 In general case you should specify it in the XML-descriptor:
432 <version>
433 VERSION
434 </version>
435
436 -v2|-version2 <num>
437 Specify 2nd library version outside the descriptor.
438
439 -s|-strict
440 Treat all compatibility warnings as problems. Add a number of \"Low\"
441 severity problems to the return value of the tool.
442
443 -headers-only
444 Check header files without $SLIB_TYPE libraries. It is easy to run, but may
445 provide a low quality compatibility report with false positives and
446 without detecting of added/removed symbols.
447
448 Alternatively you can write \"none\" word to the <libs> section
449 in the XML-descriptor:
450 <libs>
451 none
452 </libs>
453
454 -objects-only
455 Check $SLIB_TYPE libraries without header files. It is easy to run, but may
456 provide a low quality compatibility report with false positives and
457 without analysis of changes in parameters and data types.
458
459 Alternatively you can write \"none\" word to the <headers> section
460 in the XML-descriptor:
461 <headers>
462 none
463 </headers>
464
465 -check-impl|-check-implementation
466 Compare canonified disassembled binary code of $SLIB_TYPE libraries to
467 detect changes in the implementation. Add \'Problems with Implementation\'
468 section to the report.
469
470 -show-retval
471 Show the symbol's return type in the report.
472
473 -symbols-list <path>
474 This option allows to specify a file with a list of symbols (mangled
475 names in C++) that should be checked, other symbols will not be checked.
476
477 -skip-headers <path>
478 The file with the list of header files, that should not be checked.
479
480 -use-dumps
481 Make dumps for two versions of a library and compare dumps. This should
482 increase the performance of the tool and decrease the system memory usage.
483
484 -nostdinc
485 Do not search the GCC standard system directories for header files.
486
487 -dump-system <name> -sysroot <dirpath>
488 Find all the shared libraries and header files in <dirpath> directory,
489 create XML descriptors and make ABI dumps for each library. The result
490 set of ABI dumps can be compared (--cmp-systems) with the other one
491 created for other version of operating system in order to check them for
492 compatibility. Do not forget to specify -cross-gcc option if your target
493 system requires some specific version of GCC compiler (different from
494 the host GCC). The system ABI dump will be generated to:
495 sys_dumps/<name>/<arch>
496
497 -dump-system <descriptor.xml>
498 The same as the previous option but takes an XML descriptor of the target
499 system as input, where you should describe it:
500
501 /* Primary sections */
502
503 <name>
504 /* Name of the system */
505 </name>
506
507 <headers>
508 /* The list of paths to header files and/or
509 directories with header files, one per line */
510 </headers>
511
512 <libs>
513 /* The list of paths to shared libraries and/or
514 directories with shared libraries, one per line */
515 </libs>
516
517 /* Optional sections */
518
519 <search_headers>
520 /* List of directories to be searched
521 for header files to automatically
522 generate include paths, one per line */
523 </search_headers>
524
525 <search_libs>
526 /* List of directories to be searched
527 for shared libraries to resolve
528 dependencies, one per line */
529 </search_libs>
530
531 <tools>
532 /* List of directories with tools used
533 for analysis (GCC toolchain), one per line */
534 </tools>
535
536 <cross_prefix>
537 /* GCC toolchain prefix.
538 Examples:
539 arm-linux-gnueabi
540 arm-none-symbianelf */
541 </cross_prefix>
542
543 <gcc_options>
544 /* Additional GCC options, one per line */
545 </gcc_options>
546
547 -sysinfo <dir>
548 This option may be used with -dump-system to dump ABI of operating
549 systems and configure the dumping process.
550 Default:
551 modules/Targets/{unix, symbian, windows}
552
553 -cmp-systems -d1 sys_dumps/<name1>/<arch> -d2 sys_dumps/<name2>/<arch>
554 Compare two system ABI dumps. Create compatibility reports for each
555 library and the common HTML report including the summary of test
556 results for all checked libraries. Report will be generated to:
557 sys_compat_reports/<name1>_to_<name2>/<arch>
558
559 -libs-list <path>
560 The file with a list of libraries, that should be dumped by
561 the -dump-system option or should be checked by the -cmp-systems option.
562
563 -header <name>
564 Check/Dump ABI of this header only.
565
566 -headers-list <path>
567 The file with a list of headers, that should be checked/dumped.
568
569 -ext|-extended
570 If your library A is supposed to be used by other library B and you
571 want to control the ABI of B, then you should enable this option. The
572 tool will check for changes in all data types, even if they are not
573 used by any function in the library A. Such data types are not part
574 of the A library ABI, but may be a part of the ABI of the B library.
575
576 The short scheme is:
577 app C (broken) -> lib B (broken ABI) -> lib A (stable ABI)
578
579 -q|-quiet
580 Print all messages to the file instead of stdout and stderr.
581 Default path (can be changed by -log-path option):
582 $COMMON_LOG_PATH
583
584 -stdout
585 Print analysis results (compatibility reports and ABI dumps) to stdout
586 instead of creating a file. This would allow piping data to other programs.
587
588 -report-format <fmt>
589 Change format of compatibility report.
590 Formats:
591 htm - HTML format (default)
592 xml - XML format
593
Andrey Ponomarenko5c09ef32012-06-14 18:17:33 +0400594 -dump-format <fmt>
595 Change format of ABI dump.
596 Formats:
597 perl - Data::Dumper format (default)
598 xml - XML format
599
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +0400600 -xml
Andrey Ponomarenko5c09ef32012-06-14 18:17:33 +0400601 Alias for: --report-format=xml or --dump-format=xml
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +0400602
Andrey Ponomarenkoab282102012-03-11 11:57:02 +0400603 -lang <lang>
604 Set library language (C or C++). You can use this option if the tool
605 cannot auto-detect a language. This option may be useful for checking
606 C-library headers (--lang=C) in --headers-only or --extended modes.
607
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +0400608 -binary|-bin|-abi
609 Show \"Binary\" compatibility problems only.
610 Generate report to:
611 compat_reports/<library name>/<v1>_to_<v2>/abi_compat_report.html
612
613 -source|-src|-api
614 Show \"Source\" compatibility problems only.
615 Generate report to:
616 compat_reports/<library name>/<v1>_to_<v2>/src_compat_report.html
617
Andrey Ponomarenkoab282102012-03-11 11:57:02 +0400618OTHER OPTIONS:
619 -test
620 Run internal tests. Create two binary incompatible versions of a sample
621 library and run the tool to check them for compatibility. This option
622 allows to check if the tool works correctly in the current environment.
623
624 -test-dump
625 Test ability to create, read and compare ABI dumps.
626
627 -debug
628 Debugging mode. Print debug info on the screen. Save intermediate
629 analysis stages in the debug directory:
630 debug/<library>/<version>/
631
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +0400632 Also consider using --dump option for debugging the tool.
633
Andrey Ponomarenkoab282102012-03-11 11:57:02 +0400634 -cpp-compatible
635 If your header file is written in C language and can be compiled by
636 the C++ compiler (i.e. doesn't contain C++-keywords and other bad
637 things), then you can tell ACC about this and speedup the analysis.
638
639 -p|-params <path>
640 Path to file with the function parameter names. It can be used
641 for improving report view if the library header files have no
642 parameter names. File format:
643
644 func1;param1;param2;param3 ...
645 func2;param1;param2;param3 ...
646 ...
647
648 -relpath <path>
649 Replace {RELPATH} macros to <path> in the XML-descriptor used
650 for dumping the library ABI (see -dump option).
651
652 -relpath1 <path>
653 Replace {RELPATH} macros to <path> in the 1st XML-descriptor (-d1).
654
655 -relpath2 <path>
656 Replace {RELPATH} macros to <path> in the 2nd XML-descriptor (-d2).
657
658 -dump-path <path>
Andrey Ponomarenko5c09ef32012-06-14 18:17:33 +0400659 Specify a *.abi.$AR_EXT or *.abi file path where to generate an ABI dump.
Andrey Ponomarenkoab282102012-03-11 11:57:02 +0400660 Default:
661 abi_dumps/<library>/<library>_<version>.abi.$AR_EXT
662
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +0400663 -sort
664 Enable sorting of data in ABI dumps.
665
Andrey Ponomarenkoab282102012-03-11 11:57:02 +0400666 -report-path <path>
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +0400667 Path to compatibility report.
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +0400668 Default:
669 compat_reports/<library name>/<v1>_to_<v2>/compat_report.html
670
671 -bin-report-path <path>
672 Path to \"Binary\" compatibility report.
Andrey Ponomarenkoab282102012-03-11 11:57:02 +0400673 Default:
674 compat_reports/<library name>/<v1>_to_<v2>/abi_compat_report.html
675
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +0400676 -src-report-path <path>
677 Path to \"Source\" compatibility report.
678 Default:
679 compat_reports/<library name>/<v1>_to_<v2>/src_compat_report.html
680
Andrey Ponomarenkoab282102012-03-11 11:57:02 +0400681 -log-path <path>
682 Log path for all messages.
683 Default:
684 logs/<library>/<version>/log.txt
685
686 -log1-path <path>
687 Log path for 1st version of a library.
688 Default:
689 logs/<library name>/<v1>/log.txt
690
691 -log2-path <path>
692 Log path for 2nd version of a library.
693 Default:
694 logs/<library name>/<v2>/log.txt
695
696 -logging-mode <mode>
697 Change logging mode.
698 Modes:
699 w - overwrite old logs (default)
700 a - append old logs
701 n - do not write any logs
702
703 -list-affected
704 Generate file with the list of incompatible
705 symbols beside the HTML compatibility report.
706 Use 'c++filt \@file' command from GNU binutils
707 to unmangle C++ symbols in the generated file.
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +0400708 Default names:
Andrey Ponomarenkoab282102012-03-11 11:57:02 +0400709 abi_affected.txt
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +0400710 src_affected.txt
Andrey Ponomarenkoab282102012-03-11 11:57:02 +0400711
712 -component <name>
713 The component name in the title and summary of the HTML report.
714 Default:
715 library
716
717 -l-full|-lib-full <name>
718 Change library name in the report title to <name>. By default
719 will be displayed a name specified by -l option.
720
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +0400721 -b|-browse <program>
722 Open report(s) in the browser (firefox, opera, etc.).
723
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +0400724 -open
725 Open report(s) in the default browser.
726
Andrey Ponomarenkoab282102012-03-11 11:57:02 +0400727REPORT:
728 Compatibility report will be generated to:
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +0400729 compat_reports/<library name>/<v1>_to_<v2>/compat_report.html
Andrey Ponomarenkoab282102012-03-11 11:57:02 +0400730
731 Log will be generated to:
732 logs/<library name>/<v1>/log.txt
733 logs/<library name>/<v2>/log.txt
734
735EXIT CODES:
736 0 - Compatible. The tool has run without any errors.
737 non-zero - Incompatible or the tool has run with errors.
738
739REPORT BUGS TO:
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +0400740 Andrey Ponomarenko <aponomarenko\@rosalab.ru>
Andrey Ponomarenkoab282102012-03-11 11:57:02 +0400741
742MORE INFORMATION:
743 ".$HomePage{"Wiki"}."
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +0400744 ".$HomePage{"Dev1"}."\n");
Andrey Ponomarenkoab282102012-03-11 11:57:02 +0400745}
746
747my $DescriptorTemplate = "
748<?xml version=\"1.0\" encoding=\"utf-8\"?>
749<descriptor>
750
751/* Primary sections */
752
753<version>
754 /* Version of the library */
755</version>
756
757<headers>
758 /* The list of paths to header files and/or
759 directories with header files, one per line */
760</headers>
761
762<libs>
763 /* The list of paths to shared libraries (*.$LIB_EXT) and/or
764 directories with shared libraries, one per line */
765</libs>
766
767/* Optional sections */
768
769<include_paths>
770 /* The list of include paths that will be provided
771 to GCC to compile library headers, one per line.
772 NOTE: If you define this section then the tool
773 will not automatically generate include paths */
774</include_paths>
775
776<add_include_paths>
777 /* The list of include paths that will be added
778 to the automatically generated include paths, one per line */
779</add_include_paths>
780
781<skip_include_paths>
782 /* The list of include paths that will be removed from the
783 list of automatically generated include paths, one per line */
784</skip_include_paths>
785
786<gcc_options>
787 /* Additional GCC options, one per line */
788</gcc_options>
789
790<include_preamble>
791 /* The list of header files that will be
792 included before other headers, one per line.
793 Examples:
794 1) tree.h for libxml2
795 2) ft2build.h for freetype2 */
796</include_preamble>
797
798<defines>
799 /* The list of defines that will be added at the
800 headers compiling stage, one per line:
801 #define A B
802 #define C D */
803</defines>
804
Andrey Ponomarenkoa01311b2012-06-08 17:20:02 +0400805<add_namespaces>
806 /* The list of namespaces that should be added to the alanysis
807 if the tool cannot find them automatically, one per line */
808</add_namespaces>
809
Andrey Ponomarenkoab282102012-03-11 11:57:02 +0400810<skip_types>
811 /* The list of data types, that
812 should not be checked, one per line */
813</skip_types>
814
815<skip_symbols>
816 /* The list of functions (mangled/symbol names in C++),
817 that should not be checked, one per line */
818</skip_symbols>
819
820<skip_namespaces>
821 /* The list of C++ namespaces, that
822 should not be checked, one per line */
823</skip_namespaces>
824
825<skip_constants>
826 /* The list of constants that should
827 not be checked, one name per line */
828</skip_constants>
829
830<skip_headers>
831 /* The list of header files and/or directories
832 with header files that should not be checked, one per line */
833</skip_headers>
834
835<skip_libs>
836 /* The list of shared libraries and/or directories
837 with shared libraries that should not be checked, one per line */
838</skip_libs>
839
840<skip_including>
841 /* The list of header files, that cannot be included
842 directly (or non-self compiled ones), one per line */
843</skip_including>
844
845<search_headers>
846 /* List of directories to be searched
847 for header files to automatically
848 generate include paths, one per line. */
849</search_headers>
850
851<search_libs>
852 /* List of directories to be searched
853 for shared librariess to resolve
854 dependencies, one per line */
855</search_libs>
856
857<tools>
858 /* List of directories with tools used
859 for analysis (GCC toolchain), one per line */
860</tools>
861
862<cross_prefix>
863 /* GCC toolchain prefix.
864 Examples:
865 arm-linux-gnueabi
866 arm-none-symbianelf */
867</cross_prefix>
868
869</descriptor>";
870
871my %Operator_Indication = (
872 "not" => "~",
873 "assign" => "=",
874 "andassign" => "&=",
875 "orassign" => "|=",
876 "xorassign" => "^=",
877 "or" => "|",
878 "xor" => "^",
879 "addr" => "&",
880 "and" => "&",
881 "lnot" => "!",
882 "eq" => "==",
883 "ne" => "!=",
884 "lt" => "<",
885 "lshift" => "<<",
886 "lshiftassign" => "<<=",
887 "rshiftassign" => ">>=",
888 "call" => "()",
889 "mod" => "%",
890 "modassign" => "%=",
891 "subs" => "[]",
892 "land" => "&&",
893 "lor" => "||",
894 "rshift" => ">>",
895 "ref" => "->",
896 "le" => "<=",
897 "deref" => "*",
898 "mult" => "*",
899 "preinc" => "++",
900 "delete" => " delete",
901 "vecnew" => " new[]",
902 "vecdelete" => " delete[]",
903 "predec" => "--",
904 "postinc" => "++",
905 "postdec" => "--",
906 "plusassign" => "+=",
907 "plus" => "+",
908 "minus" => "-",
909 "minusassign" => "-=",
910 "gt" => ">",
911 "ge" => ">=",
912 "new" => " new",
913 "multassign" => "*=",
914 "divassign" => "/=",
915 "div" => "/",
916 "neg" => "-",
917 "pos" => "+",
918 "memref" => "->*",
919 "compound" => "," );
920
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +0400921my %UnknownOperator;
922
923my %NodeType= (
924 "array_type" => "Array",
925 "binfo" => "Other",
926 "boolean_type" => "Intrinsic",
927 "complex_type" => "Intrinsic",
928 "const_decl" => "Other",
929 "enumeral_type" => "Enum",
930 "field_decl" => "Other",
931 "function_decl" => "Other",
932 "function_type" => "FunctionType",
933 "identifier_node" => "Other",
934 "integer_cst" => "Other",
935 "integer_type" => "Intrinsic",
936 "method_type" => "MethodType",
937 "namespace_decl" => "Other",
938 "parm_decl" => "Other",
939 "pointer_type" => "Pointer",
940 "real_cst" => "Other",
941 "real_type" => "Intrinsic",
942 "record_type" => "Struct",
943 "reference_type" => "Ref",
944 "string_cst" => "Other",
945 "template_decl" => "Other",
946 "template_type_parm" => "Other",
947 "tree_list" => "Other",
948 "tree_vec" => "Other",
949 "type_decl" => "Other",
950 "union_type" => "Union",
951 "var_decl" => "Other",
952 "void_type" => "Intrinsic",
953 # "nop_expr" => "Other",
954 # "addr_expr" => "Other",
955 "offset_type" => "Other" );
956
Andrey Ponomarenkoab282102012-03-11 11:57:02 +0400957my %CppKeywords_C = map {$_=>1} (
958 # C++ 2003 keywords
959 "public",
960 "protected",
961 "private",
962 "default",
963 "template",
964 "new",
965 #"asm",
966 "dynamic_cast",
967 "auto",
968 "try",
969 "namespace",
970 "typename",
971 "using",
972 "reinterpret_cast",
973 "friend",
974 "class",
975 "virtual",
976 "const_cast",
977 "mutable",
978 "static_cast",
979 "export",
980 # C++0x keywords
981 "noexcept",
982 "nullptr",
983 "constexpr",
984 "static_assert",
985 "explicit",
986 # cannot be used as a macro name
987 # as it is an operator in C++
988 "and",
989 #"and_eq",
990 "not",
991 #"not_eq",
992 "or"
993 #"or_eq",
994 #"bitand",
995 #"bitor",
996 #"xor",
997 #"xor_eq",
998 #"compl"
999);
1000
1001my %CppKeywords_F = map {$_=>1} (
1002 "delete",
1003 "catch",
1004 "alignof",
1005 "thread_local",
1006 "decltype",
1007 "typeid"
1008);
1009
1010my %CppKeywords_O = map {$_=>1} (
1011 "bool",
1012 "register",
1013 "inline",
1014 "operator"
1015);
1016
1017my %CppKeywords_A = map {$_=>1} (
1018 "this",
1019 "throw"
1020);
1021
1022foreach (keys(%CppKeywords_C),
1023keys(%CppKeywords_F),
1024keys(%CppKeywords_O)) {
1025 $CppKeywords_A{$_}=1;
1026}
1027
1028# Header file extensions as described by gcc
1029my $HEADER_EXT = "h|hh|hp|hxx|hpp|h\\+\\+";
1030
1031my %IntrinsicMangling = (
1032 "void" => "v",
1033 "bool" => "b",
1034 "wchar_t" => "w",
1035 "char" => "c",
1036 "signed char" => "a",
1037 "unsigned char" => "h",
1038 "short" => "s",
1039 "unsigned short" => "t",
1040 "int" => "i",
1041 "unsigned int" => "j",
1042 "long" => "l",
1043 "unsigned long" => "m",
1044 "long long" => "x",
1045 "__int64" => "x",
1046 "unsigned long long" => "y",
1047 "__int128" => "n",
1048 "unsigned __int128" => "o",
1049 "float" => "f",
1050 "double" => "d",
1051 "long double" => "e",
1052 "__float80" => "e",
1053 "__float128" => "g",
1054 "..." => "z"
1055);
1056
1057my %StdcxxMangling = (
1058 "3std"=>"St",
1059 "3std9allocator"=>"Sa",
1060 "3std12basic_string"=>"Sb",
1061 "3std12basic_stringIcE"=>"Ss",
1062 "3std13basic_istreamIcE"=>"Si",
1063 "3std13basic_ostreamIcE"=>"So",
1064 "3std14basic_iostreamIcE"=>"Sd"
1065);
1066
1067my %ConstantSuffix = (
1068 "unsigned int"=>"u",
1069 "long"=>"l",
1070 "unsigned long"=>"ul",
1071 "long long"=>"ll",
1072 "unsigned long long"=>"ull"
1073);
1074
1075my %ConstantSuffixR =
1076reverse(%ConstantSuffix);
1077
1078my %OperatorMangling = (
1079 "~" => "co",
1080 "=" => "aS",
1081 "|" => "or",
1082 "^" => "eo",
1083 "&" => "an",#ad (addr)
1084 "==" => "eq",
1085 "!" => "nt",
1086 "!=" => "ne",
1087 "<" => "lt",
1088 "<=" => "le",
1089 "<<" => "ls",
1090 "<<=" => "lS",
1091 ">" => "gt",
1092 ">=" => "ge",
1093 ">>" => "rs",
1094 ">>=" => "rS",
1095 "()" => "cl",
1096 "%" => "rm",
1097 "[]" => "ix",
1098 "&&" => "aa",
1099 "||" => "oo",
1100 "*" => "ml",#de (deref)
1101 "++" => "pp",#
1102 "--" => "mm",#
1103 "new" => "nw",
1104 "delete" => "dl",
1105 "new[]" => "na",
1106 "delete[]" => "da",
1107 "+=" => "pL",
1108 "+" => "pl",#ps (pos)
1109 "-" => "mi",#ng (neg)
1110 "-=" => "mI",
1111 "*=" => "mL",
1112 "/=" => "dV",
1113 "&=" => "aN",
1114 "|=" => "oR",
1115 "%=" => "rM",
1116 "^=" => "eO",
1117 "/" => "dv",
1118 "->*" => "pm",
1119 "->" => "pt",#rf (ref)
1120 "," => "cm",
1121 "?" => "qu",
1122 "." => "dt",
1123 "sizeof"=> "sz"#st
1124);
1125
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04001126my %Intrinsic_Keywords = map {$_=>1} (
1127 "true",
1128 "false",
1129 "_Bool",
1130 "_Complex",
1131 "const",
1132 "int",
1133 "long",
1134 "void",
1135 "short",
1136 "float",
1137 "volatile",
1138 "restrict",
1139 "unsigned",
1140 "signed",
1141 "char",
1142 "double",
1143 "class",
1144 "struct",
1145 "union",
1146 "enum"
1147);
1148
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04001149my %GlibcHeader = map {$_=>1} (
1150 "aliases.h",
1151 "argp.h",
1152 "argz.h",
1153 "assert.h",
1154 "cpio.h",
1155 "ctype.h",
1156 "dirent.h",
1157 "envz.h",
1158 "errno.h",
1159 "error.h",
1160 "execinfo.h",
1161 "fcntl.h",
1162 "fstab.h",
1163 "ftw.h",
1164 "glob.h",
1165 "grp.h",
1166 "iconv.h",
1167 "ifaddrs.h",
1168 "inttypes.h",
1169 "langinfo.h",
1170 "limits.h",
1171 "link.h",
1172 "locale.h",
1173 "malloc.h",
1174 "math.h",
1175 "mntent.h",
1176 "monetary.h",
1177 "nl_types.h",
1178 "obstack.h",
1179 "printf.h",
1180 "pwd.h",
1181 "regex.h",
1182 "sched.h",
1183 "search.h",
1184 "setjmp.h",
1185 "shadow.h",
1186 "signal.h",
1187 "spawn.h",
1188 "stdarg.h",
1189 "stdint.h",
1190 "stdio.h",
1191 "stdlib.h",
1192 "string.h",
Andrey Ponomarenko9927e332012-10-19 10:50:48 +04001193 "strings.h",
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04001194 "tar.h",
1195 "termios.h",
1196 "time.h",
1197 "ulimit.h",
1198 "unistd.h",
1199 "utime.h",
1200 "wchar.h",
1201 "wctype.h",
1202 "wordexp.h" );
1203
1204my %GlibcDir = map {$_=>1} (
1205 "arpa",
1206 "bits",
1207 "gnu",
1208 "netinet",
1209 "net",
1210 "nfs",
1211 "rpc",
1212 "sys",
1213 "linux" );
1214
Andrey Ponomarenko9927e332012-10-19 10:50:48 +04001215my %WinHeaders = map {$_=>1} (
1216 "dos.h",
1217 "process.h",
1218 "winsock.h",
1219 "config-win.h",
1220 "mem.h",
1221 "windows.h",
1222 "winsock2.h",
1223 "crtdbg.h",
1224 "ws2tcpip.h"
1225);
1226
1227my %ObsoleteHeaders = map {$_=>1} (
1228 "iostream.h",
1229 "fstream.h"
1230);
1231
1232my %ConfHeaders = map {$_=>1} (
1233 "atomic",
1234 "conf.h",
1235 "config.h",
1236 "configure.h",
1237 "build.h",
1238 "setup.h"
1239);
1240
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04001241my %LocalIncludes = map {$_=>1} (
1242 "/usr/local/include",
1243 "/usr/local" );
1244
1245my %OS_AddPath=(
1246# These paths are needed if the tool cannot detect them automatically
1247 "macos"=>{
1248 "include"=>{
1249 "/Library"=>1,
1250 "/Developer/usr/include"=>1
1251 },
1252 "lib"=>{
1253 "/Library"=>1,
1254 "/Developer/usr/lib"=>1
1255 },
1256 "bin"=>{
1257 "/Developer/usr/bin"=>1
1258 }
1259 },
1260 "beos"=>{
1261 # Haiku has GCC 2.95.3 by default
1262 # try to find GCC>=3.0 in /boot/develop/abi
1263 "include"=>{
1264 "/boot/common"=>1,
1265 "/boot/develop"=>1},
1266 "lib"=>{
1267 "/boot/common/lib"=>1,
1268 "/boot/system/lib"=>1,
1269 "/boot/apps"=>1},
1270 "bin"=>{
1271 "/boot/common/bin"=>1,
1272 "/boot/system/bin"=>1,
1273 "/boot/develop/abi"=>1
1274 }
1275}
1276);
1277
1278my %Slash_Type=(
1279 "default"=>"/",
1280 "windows"=>"\\"
1281);
1282
1283my $SLASH = $Slash_Type{$OSgroup}?$Slash_Type{$OSgroup}:$Slash_Type{"default"};
1284
1285# Global Variables
1286my %COMMON_LANGUAGE=(
1287 1 => "C",
1288 2 => "C" );
1289
1290my $MAX_COMMAND_LINE_ARGUMENTS = 4096;
Andrey Ponomarenko9927e332012-10-19 10:50:48 +04001291my $MAX_CPPFILT_FILE_SIZE = 50000;
1292my $CPPFILT_SUPPORT_FILE;
1293
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04001294my (%WORD_SIZE, %CPU_ARCH, %GCC_VERSION);
1295
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04001296my $STDCXX_TESTING = 0;
1297my $GLIBC_TESTING = 0;
1298
1299my $CheckHeadersOnly = $CheckHeadersOnly_Opt;
1300my $CheckObjectsOnly = $CheckObjectsOnly_Opt;
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04001301my $TargetComponent;
1302
1303# Set Target Component Name
1304if($TargetComponent_Opt) {
1305 $TargetComponent = lc($TargetComponent_Opt);
1306}
1307else
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04001308{ # default: library
1309 # other components: header, system, ...
1310 $TargetComponent = "library";
1311}
1312
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04001313my $TOP_REF = "<a style='font-size:11px;' href='#Top'>to the top</a>";
1314
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04001315my $SystemRoot;
1316
1317my $MAIN_CPP_DIR;
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04001318my %RESULT;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04001319my %LOG_PATH;
1320my %DEBUG_PATH;
1321my %Cache;
1322my %LibInfo;
1323my $COMPILE_ERRORS = 0;
1324my %CompilerOptions;
1325my %CheckedDyLib;
1326my $TargetLibraryShortName = parse_libname($TargetLibraryName, "shortest", $OSgroup);
1327
1328# Constants (#defines)
1329my %Constants;
1330my %SkipConstants;
1331
1332# Types
1333my %TypeInfo;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04001334my %TemplateInstance;
Andrey Ponomarenko85043792012-05-14 16:48:07 +04001335my %TemplateDecl;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04001336my %SkipTypes = (
1337 "1"=>{},
1338 "2"=>{} );
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04001339my %CheckedTypes;
1340my %TName_Tid;
1341my %EnumMembName_Id;
1342my %NestedNameSpaces = (
1343 "1"=>{},
1344 "2"=>{} );
1345my %UsedType;
1346my %VirtualTable;
Andrey Ponomarenko16934472012-03-29 15:37:04 +04001347my %VirtualTable_Model;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04001348my %ClassVTable;
1349my %ClassVTable_Content;
1350my %VTableClass;
1351my %AllocableClass;
1352my %ClassMethods;
Andrey Ponomarenko16934472012-03-29 15:37:04 +04001353my %ClassNames;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04001354my %Class_SubClasses;
1355my %OverriddenMethods;
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04001356my $MAX_ID = 0;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04001357
1358# Typedefs
1359my %Typedef_BaseName;
1360my %Typedef_Tr;
1361my %Typedef_Eq;
1362my %StdCxxTypedef;
1363my %MissedTypedef;
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04001364my %MissedBase;
1365my %MissedBase_R;
Andrey Ponomarenko9927e332012-10-19 10:50:48 +04001366my %TypeTypedef;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04001367
1368# Symbols
1369my %SymbolInfo;
1370my %tr_name;
1371my %mangled_name_gcc;
1372my %mangled_name;
1373my %SkipSymbols = (
1374 "1"=>{},
1375 "2"=>{} );
1376my %SkipNameSpaces = (
1377 "1"=>{},
1378 "2"=>{} );
Andrey Ponomarenkoa01311b2012-06-08 17:20:02 +04001379my %AddNameSpaces = (
1380 "1"=>{},
1381 "2"=>{} );
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04001382my %SymbolsList;
1383my %SymbolsList_App;
1384my %CheckedSymbols;
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04001385my %Symbol_Library = (
1386 "1"=>{},
1387 "2"=>{} );
1388my %Library_Symbol = (
1389 "1"=>{},
1390 "2"=>{} );
1391my %DepSymbol_Library = (
1392 "1"=>{},
1393 "2"=>{} );
1394my %DepLibrary_Symbol = (
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04001395 "1"=>{},
1396 "2"=>{} );
1397my %MangledNames;
Andrey Ponomarenko9927e332012-10-19 10:50:48 +04001398my %Func_ShortName;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04001399my %AddIntParams;
1400my %Interface_Impl;
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04001401my %GlobalDataObject;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04001402
1403# Headers
1404my %Include_Preamble;
1405my %Registered_Headers;
1406my %HeaderName_Paths;
1407my %Header_Dependency;
1408my %Include_Neighbors;
1409my %Include_Paths;
1410my %INC_PATH_AUTODETECT = (
1411 "1"=>1,
1412 "2"=>1 );
1413my %Add_Include_Paths;
1414my %Skip_Include_Paths;
1415my %RegisteredDirs;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04001416my %Header_ErrorRedirect;
1417my %Header_Includes;
1418my %Header_ShouldNotBeUsed;
1419my %RecursiveIncludes;
1420my %Header_Include_Prefix;
1421my %SkipHeaders;
1422my %SkipHeadersList=(
1423 "1"=>{},
1424 "2"=>{} );
1425my %SkipLibs;
1426my %Include_Order;
1427my %TUnit_NameSpaces;
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +04001428my %TUnit_Classes;
Andrey Ponomarenko9927e332012-10-19 10:50:48 +04001429my %TUnit_Funcs;
1430my %TUnit_Vars;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04001431
1432my %C99Mode = (
1433 "1"=>0,
1434 "2"=>0 );
1435my %AutoPreambleMode = (
1436 "1"=>0,
1437 "2"=>0 );
1438my %MinGWMode = (
1439 "1"=>0,
1440 "2"=>0 );
Andrey Ponomarenko01117f12012-06-26 12:23:02 +04001441my %Cpp0xMode = (
1442 "1"=>0,
1443 "2"=>0 );
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04001444
1445# Shared Objects
Andrey Ponomarenko9927e332012-10-19 10:50:48 +04001446my %RegisteredObjects;
1447my %RegisteredSONAMEs;
1448my %RegisteredObject_Dirs;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04001449
1450# System Objects
1451my %SystemObjects;
1452my %DefaultLibPaths;
Andrey Ponomarenko9927e332012-10-19 10:50:48 +04001453my %DyLib_DefaultPath;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04001454
1455# System Headers
1456my %SystemHeaders;
1457my %DefaultCppPaths;
1458my %DefaultGccPaths;
1459my %DefaultIncPaths;
1460my %DefaultCppHeader;
1461my %DefaultGccHeader;
1462my %UserIncPath;
1463
1464# Merging
1465my %CompleteSignature;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04001466my $Version;
1467my %AddedInt;
1468my %RemovedInt;
1469my %AddedInt_Virt;
1470my %RemovedInt_Virt;
1471my %VirtualReplacement;
1472my %ChangedTypedef;
1473my %CompatRules;
1474my %IncompleteRules;
1475my %UnknownRules;
Andrey Ponomarenko16934472012-03-29 15:37:04 +04001476my %VTableChanged_M;
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04001477my %ExtendedSymbols;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04001478my %ReturnedClass;
1479my %ParamClass;
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04001480my %SourceAlternative;
1481my %SourceAlternative_B;
1482my %SourceReplacement;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04001483
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +04001484# Calling Conventions
1485my %UseConv_Real = (
1486 "1"=>0,
1487 "2"=>0 );
1488
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04001489# OS Compliance
1490my %TargetLibs;
1491my %TargetHeaders;
1492
1493# OS Specifics
1494my $OStarget = $OSgroup;
1495my %TargetTools;
1496
1497# Compliance Report
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04001498my %Type_MaxSeverity;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04001499
1500# Recursion locks
1501my @RecurLib;
1502my @RecurSymlink;
1503my @RecurTypes;
1504my @RecurInclude;
1505my @RecurConstant;
1506
1507# System
1508my %SystemPaths;
1509my %DefaultBinPaths;
1510my $GCC_PATH;
1511
1512# Symbols versioning
1513my %SymVer = (
1514 "1"=>{},
1515 "2"=>{} );
1516
1517# Problem descriptions
1518my %CompatProblems;
1519my %ProblemsWithConstants;
1520my %ImplProblems;
1521my %TotalAffected;
1522
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04001523# Reports
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04001524my $ContentID = 1;
1525my $ContentSpanStart = "<span class=\"section\" onclick=\"javascript:showContent(this, 'CONTENT_ID')\">\n";
1526my $ContentSpanStart_Affected = "<span class=\"section_affected\" onclick=\"javascript:showContent(this, 'CONTENT_ID')\">\n";
1527my $ContentSpanStart_Info = "<span class=\"section_info\" onclick=\"javascript:showContent(this, 'CONTENT_ID')\">\n";
1528my $ContentSpanEnd = "</span>\n";
1529my $ContentDivStart = "<div id=\"CONTENT_ID\" style=\"display:none;\">\n";
1530my $ContentDivEnd = "</div>\n";
1531my $Content_Counter = 0;
1532
Andrey Ponomarenko5c09ef32012-06-14 18:17:33 +04001533# XML Dump
1534my $TAG_ID = 0;
1535my $INDENT = " ";
1536
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04001537# Modes
1538my $JoinReport = 1;
1539my $DoubleReport = 0;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04001540
1541sub get_Modules()
1542{
1543 my $TOOL_DIR = get_dirname($0);
1544 if(not $TOOL_DIR)
1545 { # patch for MS Windows
1546 $TOOL_DIR = ".";
1547 }
1548 my @SEARCH_DIRS = (
1549 # tool's directory
1550 abs_path($TOOL_DIR),
1551 # relative path to modules
1552 abs_path($TOOL_DIR)."/../share/abi-compliance-checker",
1553 # system directory
1554 "ACC_MODULES_INSTALL_PATH"
1555 );
1556 foreach my $DIR (@SEARCH_DIRS)
1557 {
1558 if(not is_abs($DIR))
1559 { # relative path
1560 $DIR = abs_path($TOOL_DIR)."/".$DIR;
1561 }
1562 if(-d $DIR."/modules") {
1563 return $DIR."/modules";
1564 }
1565 }
1566 exitStatus("Module_Error", "can't find modules");
1567}
1568
Andrey Ponomarenko01117f12012-06-26 12:23:02 +04001569my %LoadedModules = ();
1570
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04001571sub loadModule($)
1572{
1573 my $Name = $_[0];
Andrey Ponomarenko01117f12012-06-26 12:23:02 +04001574 if(defined $LoadedModules{$Name}) {
1575 return;
1576 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04001577 my $Path = $MODULES_DIR."/Internals/$Name.pm";
1578 if(not -f $Path) {
1579 exitStatus("Module_Error", "can't access \'$Path\'");
1580 }
1581 require $Path;
Andrey Ponomarenko01117f12012-06-26 12:23:02 +04001582 $LoadedModules{$Name} = 1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04001583}
1584
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04001585sub showPos($)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04001586{
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04001587 my $Number = $_[0];
1588 if(not $Number) {
1589 $Number = 1;
1590 }
1591 else {
1592 $Number = int($Number)+1;
1593 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04001594 if($Number>3) {
1595 return $Number."th";
1596 }
1597 elsif($Number==1) {
1598 return "1st";
1599 }
1600 elsif($Number==2) {
1601 return "2nd";
1602 }
1603 elsif($Number==3) {
1604 return "3rd";
1605 }
1606 else {
1607 return $Number;
1608 }
1609}
1610
1611sub search_Tools($)
1612{
1613 my $Name = $_[0];
1614 return "" if(not $Name);
1615 if(my @Paths = keys(%TargetTools))
1616 {
1617 foreach my $Path (@Paths)
1618 {
1619 if(-f joinPath($Path, $Name)) {
1620 return joinPath($Path, $Name);
1621 }
1622 if($CrossPrefix)
1623 { # user-defined prefix (arm-none-symbianelf, ...)
1624 my $Candidate = joinPath($Path, $CrossPrefix."-".$Name);
1625 if(-f $Candidate) {
1626 return $Candidate;
1627 }
1628 }
1629 }
1630 }
1631 else {
1632 return "";
1633 }
1634}
1635
1636sub synch_Cmd($)
1637{
1638 my $Name = $_[0];
1639 if(not $GCC_PATH)
1640 { # GCC was not found yet
1641 return "";
1642 }
1643 my $Candidate = $GCC_PATH;
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04001644 if($Candidate=~s/\bgcc(|\.\w+)\Z/$Name$1/) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04001645 return $Candidate;
1646 }
1647 return "";
1648}
1649
1650sub get_CmdPath($)
1651{
1652 my $Name = $_[0];
1653 return "" if(not $Name);
1654 if(defined $Cache{"get_CmdPath"}{$Name}) {
1655 return $Cache{"get_CmdPath"}{$Name};
1656 }
1657 my %BinUtils = map {$_=>1} (
1658 "c++filt",
1659 "objdump",
1660 "readelf"
1661 );
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04001662 if($BinUtils{$Name} and $GCC_PATH)
1663 {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04001664 if(my $Dir = get_dirname($GCC_PATH)) {
1665 $TargetTools{$Dir}=1;
1666 }
1667 }
1668 my $Path = search_Tools($Name);
1669 if(not $Path and $OSgroup eq "windows") {
1670 $Path = search_Tools($Name.".exe");
1671 }
1672 if(not $Path and $BinUtils{$Name})
1673 {
1674 if($CrossPrefix)
1675 { # user-defined prefix
1676 $Path = search_Cmd($CrossPrefix."-".$Name);
1677 }
1678 }
1679 if(not $Path and $BinUtils{$Name})
1680 {
1681 if(my $Candidate = synch_Cmd($Name))
1682 { # synch with GCC
1683 if($Candidate=~/[\/\\]/)
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04001684 { # command path
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04001685 if(-f $Candidate) {
1686 $Path = $Candidate;
1687 }
1688 }
1689 elsif($Candidate = search_Cmd($Candidate))
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04001690 { # command name
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04001691 $Path = $Candidate;
1692 }
1693 }
1694 }
1695 if(not $Path) {
1696 $Path = search_Cmd($Name);
1697 }
1698 if(not $Path and $OSgroup eq "windows")
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04001699 { # search for *.exe file
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04001700 $Path=search_Cmd($Name.".exe");
1701 }
1702 if($Path=~/\s/) {
1703 $Path = "\"".$Path."\"";
1704 }
1705 return ($Cache{"get_CmdPath"}{$Name}=$Path);
1706}
1707
1708sub search_Cmd($)
1709{
1710 my $Name = $_[0];
1711 return "" if(not $Name);
1712 if(defined $Cache{"search_Cmd"}{$Name}) {
1713 return $Cache{"search_Cmd"}{$Name};
1714 }
1715 if(my $DefaultPath = get_CmdPath_Default($Name)) {
1716 return ($Cache{"search_Cmd"}{$Name} = $DefaultPath);
1717 }
1718 foreach my $Path (sort {length($a)<=>length($b)} keys(%{$SystemPaths{"bin"}}))
1719 {
1720 my $CmdPath = joinPath($Path,$Name);
1721 if(-f $CmdPath)
1722 {
1723 if($Name=~/gcc/) {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04001724 next if(not check_gcc($CmdPath, "3"));
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04001725 }
1726 return ($Cache{"search_Cmd"}{$Name} = $CmdPath);
1727 }
1728 }
1729 return ($Cache{"search_Cmd"}{$Name} = "");
1730}
1731
1732sub get_CmdPath_Default($)
1733{ # search in PATH
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04001734 return "" if(not $_[0]);
1735 if(defined $Cache{"get_CmdPath_Default"}{$_[0]}) {
1736 return $Cache{"get_CmdPath_Default"}{$_[0]};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04001737 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04001738 return ($Cache{"get_CmdPath_Default"}{$_[0]} = get_CmdPath_Default_I($_[0]));
1739}
1740
1741sub get_CmdPath_Default_I($)
1742{ # search in PATH
1743 my $Name = $_[0];
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04001744 if($Name=~/find/)
1745 { # special case: search for "find" utility
Andrey Ponomarenkoa01311b2012-06-08 17:20:02 +04001746 if(`find \"$TMP_DIR\" -maxdepth 0 2>\"$TMP_DIR/null\"`) {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04001747 return "find";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04001748 }
1749 }
1750 elsif($Name=~/gcc/) {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04001751 return check_gcc($Name, "3");
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04001752 }
1753 if(check_command($Name)) {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04001754 return $Name;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04001755 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04001756 if($OSgroup eq "windows")
1757 {
Andrey Ponomarenkoa01311b2012-06-08 17:20:02 +04001758 if(`$Name /? 2>\"$TMP_DIR/null\"`) {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04001759 return $Name;
1760 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04001761 }
1762 if($Name!~/which/)
1763 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04001764 if(my $WhichCmd = get_CmdPath("which"))
1765 {
Andrey Ponomarenkoa01311b2012-06-08 17:20:02 +04001766 if(`$WhichCmd $Name 2>\"$TMP_DIR/null\"`) {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04001767 return $Name;
1768 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04001769 }
1770 }
1771 foreach my $Path (sort {length($a)<=>length($b)} keys(%DefaultBinPaths))
1772 {
1773 if(-f $Path."/".$Name) {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04001774 return joinPath($Path,$Name);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04001775 }
1776 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04001777 return "";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04001778}
1779
1780sub clean_path($)
1781{
1782 my $Path = $_[0];
1783 $Path=~s/[\/\\]+\Z//g;
1784 return $Path;
1785}
1786
1787sub classifyPath($)
1788{
1789 my $Path = $_[0];
1790 if($Path=~/[\*\[]/)
1791 { # wildcard
1792 $Path=~s/\*/.*/g;
1793 $Path=~s/\\/\\\\/g;
1794 return ($Path, "Pattern");
1795 }
1796 elsif($Path=~/[\/\\]/)
1797 { # directory or relative path
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04001798 $Path=~s/[\/\\]+\Z//g;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04001799 return (path_format($Path, $OSgroup), "Path");
1800 }
1801 else {
1802 return ($Path, "Name");
1803 }
1804}
1805
1806sub readDescriptor($$)
1807{
1808 my ($LibVersion, $Content) = @_;
1809 return if(not $LibVersion);
1810 my $DName = $DumpAPI?"descriptor":"descriptor \"d$LibVersion\"";
1811 if(not $Content) {
1812 exitStatus("Error", "$DName is empty");
1813 }
1814 if($Content!~/\</) {
Andrey Ponomarenko5c09ef32012-06-14 18:17:33 +04001815 exitStatus("Error", "incorrect descriptor (see -d1 option)");
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04001816 }
1817 $Content=~s/\/\*(.|\n)+?\*\///g;
1818 $Content=~s/<\!--(.|\n)+?-->//g;
1819 $Descriptor{$LibVersion}{"Version"} = parseTag(\$Content, "version");
1820 if($TargetVersion{$LibVersion}) {
1821 $Descriptor{$LibVersion}{"Version"} = $TargetVersion{$LibVersion};
1822 }
1823 if(not $Descriptor{$LibVersion}{"Version"}) {
1824 exitStatus("Error", "version in the $DName is not specified (<version> section)");
1825 }
1826 if($Content=~/{RELPATH}/)
1827 {
1828 if(my $RelDir = $RelativeDirectory{$LibVersion}) {
1829 $Content =~ s/{RELPATH}/$RelDir/g;
1830 }
1831 else
1832 {
1833 my $NeedRelpath = $DumpAPI?"-relpath":"-relpath$LibVersion";
1834 exitStatus("Error", "you have not specified $NeedRelpath option, but the $DName contains {RELPATH} macro");
1835 }
1836 }
1837
1838 if(not $CheckObjectsOnly_Opt)
1839 {
1840 my $DHeaders = parseTag(\$Content, "headers");
1841 if(not $DHeaders) {
1842 exitStatus("Error", "header files in the $DName are not specified (<headers> section)");
1843 }
1844 elsif(lc($DHeaders) ne "none")
1845 { # append the descriptor headers list
1846 if($Descriptor{$LibVersion}{"Headers"})
1847 { # multiple descriptors
1848 $Descriptor{$LibVersion}{"Headers"} .= "\n".$DHeaders;
1849 }
1850 else {
1851 $Descriptor{$LibVersion}{"Headers"} = $DHeaders;
1852 }
1853 foreach my $Path (split(/\s*\n\s*/, $DHeaders))
1854 {
1855 if(not -e $Path) {
1856 exitStatus("Access_Error", "can't access \'$Path\'");
1857 }
1858 }
1859 }
1860 }
1861 if(not $CheckHeadersOnly_Opt)
1862 {
1863 my $DObjects = parseTag(\$Content, "libs");
1864 if(not $DObjects) {
1865 exitStatus("Error", "$SLIB_TYPE libraries in the $DName are not specified (<libs> section)");
1866 }
1867 elsif(lc($DObjects) ne "none")
1868 { # append the descriptor libraries list
1869 if($Descriptor{$LibVersion}{"Libs"})
1870 { # multiple descriptors
1871 $Descriptor{$LibVersion}{"Libs"} .= "\n".$DObjects;
1872 }
1873 else {
1874 $Descriptor{$LibVersion}{"Libs"} .= $DObjects;
1875 }
1876 foreach my $Path (split(/\s*\n\s*/, $DObjects))
1877 {
1878 if(not -e $Path) {
1879 exitStatus("Access_Error", "can't access \'$Path\'");
1880 }
1881 }
1882 }
1883 }
1884 foreach my $Path (split(/\s*\n\s*/, parseTag(\$Content, "search_headers")))
1885 {
1886 $Path = clean_path($Path);
1887 if(not -d $Path) {
1888 exitStatus("Access_Error", "can't access directory \'$Path\'");
1889 }
1890 $Path = path_format($Path, $OSgroup);
1891 $SystemPaths{"include"}{$Path}=1;
1892 }
1893 foreach my $Path (split(/\s*\n\s*/, parseTag(\$Content, "search_libs")))
1894 {
1895 $Path = clean_path($Path);
1896 if(not -d $Path) {
1897 exitStatus("Access_Error", "can't access directory \'$Path\'");
1898 }
1899 $Path = path_format($Path, $OSgroup);
1900 $SystemPaths{"lib"}{$Path}=1;
1901 }
1902 foreach my $Path (split(/\s*\n\s*/, parseTag(\$Content, "tools")))
1903 {
1904 $Path=clean_path($Path);
1905 if(not -d $Path) {
1906 exitStatus("Access_Error", "can't access directory \'$Path\'");
1907 }
1908 $Path = path_format($Path, $OSgroup);
1909 $SystemPaths{"bin"}{$Path}=1;
1910 $TargetTools{$Path}=1;
1911 }
1912 if(my $Prefix = parseTag(\$Content, "cross_prefix")) {
1913 $CrossPrefix = $Prefix;
1914 }
1915 foreach my $Path (split(/\s*\n\s*/, parseTag(\$Content, "include_paths")))
1916 {
1917 $Path=clean_path($Path);
1918 if(not -d $Path) {
1919 exitStatus("Access_Error", "can't access directory \'$Path\'");
1920 }
1921 $Path = path_format($Path, $OSgroup);
1922 $Descriptor{$LibVersion}{"IncludePaths"}{$Path} = 1;
1923 }
1924 foreach my $Path (split(/\s*\n\s*/, parseTag(\$Content, "add_include_paths")))
1925 {
1926 $Path=clean_path($Path);
1927 if(not -d $Path) {
1928 exitStatus("Access_Error", "can't access directory \'$Path\'");
1929 }
1930 $Path = path_format($Path, $OSgroup);
1931 $Descriptor{$LibVersion}{"AddIncludePaths"}{$Path} = 1;
1932 }
1933 foreach my $Path (split(/\s*\n\s*/, parseTag(\$Content, "skip_include_paths")))
1934 {
1935 # skip some auto-generated include paths
1936 $Skip_Include_Paths{$LibVersion}{path_format($Path)}=1;
1937 }
1938 foreach my $Path (split(/\s*\n\s*/, parseTag(\$Content, "skip_including")))
1939 {
1940 # skip direct including of some headers
1941 my ($CPath, $Type) = classifyPath($Path);
1942 $SkipHeaders{$LibVersion}{$Type}{$CPath} = 2;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04001943 }
1944 $Descriptor{$LibVersion}{"GccOptions"} = parseTag(\$Content, "gcc_options");
1945 foreach my $Option (split(/\s*\n\s*/, $Descriptor{$LibVersion}{"GccOptions"})) {
1946 $CompilerOptions{$LibVersion} .= " ".$Option;
1947 }
1948 $Descriptor{$LibVersion}{"SkipHeaders"} = parseTag(\$Content, "skip_headers");
1949 foreach my $Path (split(/\s*\n\s*/, $Descriptor{$LibVersion}{"SkipHeaders"}))
1950 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04001951 $SkipHeadersList{$LibVersion}{$Path} = 1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04001952 my ($CPath, $Type) = classifyPath($Path);
1953 $SkipHeaders{$LibVersion}{$Type}{$CPath} = 1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04001954 }
1955 $Descriptor{$LibVersion}{"SkipLibs"} = parseTag(\$Content, "skip_libs");
1956 foreach my $Path (split(/\s*\n\s*/, $Descriptor{$LibVersion}{"SkipLibs"}))
1957 {
1958 my ($CPath, $Type) = classifyPath($Path);
1959 $SkipLibs{$LibVersion}{$Type}{$CPath} = 1;
1960 }
1961 if(my $DDefines = parseTag(\$Content, "defines"))
1962 {
1963 if($Descriptor{$LibVersion}{"Defines"})
1964 { # multiple descriptors
1965 $Descriptor{$LibVersion}{"Defines"} .= "\n".$DDefines;
1966 }
1967 else {
1968 $Descriptor{$LibVersion}{"Defines"} = $DDefines;
1969 }
1970 }
1971 foreach my $Order (split(/\s*\n\s*/, parseTag(\$Content, "include_order")))
1972 {
1973 if($Order=~/\A(.+):(.+)\Z/) {
1974 $Include_Order{$LibVersion}{$1} = $2;
1975 }
1976 }
1977 foreach my $Type_Name (split(/\s*\n\s*/, parseTag(\$Content, "opaque_types")),
1978 split(/\s*\n\s*/, parseTag(\$Content, "skip_types")))
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04001979 { # opaque_types renamed to skip_types (1.23.4)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04001980 $SkipTypes{$LibVersion}{$Type_Name} = 1;
1981 }
1982 foreach my $Symbol (split(/\s*\n\s*/, parseTag(\$Content, "skip_interfaces")),
1983 split(/\s*\n\s*/, parseTag(\$Content, "skip_symbols")))
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04001984 { # skip_interfaces renamed to skip_symbols (1.22.1)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04001985 $SkipSymbols{$LibVersion}{$Symbol} = 1;
1986 }
1987 foreach my $NameSpace (split(/\s*\n\s*/, parseTag(\$Content, "skip_namespaces"))) {
1988 $SkipNameSpaces{$LibVersion}{$NameSpace} = 1;
1989 }
Andrey Ponomarenkoa01311b2012-06-08 17:20:02 +04001990 foreach my $NameSpace (split(/\s*\n\s*/, parseTag(\$Content, "add_namespaces"))) {
1991 $AddNameSpaces{$LibVersion}{$NameSpace} = 1;
1992 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04001993 foreach my $Constant (split(/\s*\n\s*/, parseTag(\$Content, "skip_constants"))) {
1994 $SkipConstants{$LibVersion}{$Constant} = 1;
1995 }
1996 if(my $DIncPreamble = parseTag(\$Content, "include_preamble"))
1997 {
1998 if($Descriptor{$LibVersion}{"IncludePreamble"})
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04001999 { # multiple descriptors
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002000 $Descriptor{$LibVersion}{"IncludePreamble"} .= "\n".$DIncPreamble;
2001 }
2002 else {
2003 $Descriptor{$LibVersion}{"IncludePreamble"} = $DIncPreamble;
2004 }
2005 }
2006}
2007
Andrey Ponomarenko01117f12012-06-26 12:23:02 +04002008sub parseTag(@)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002009{
Andrey Ponomarenko01117f12012-06-26 12:23:02 +04002010 my $CodeRef = shift(@_);
2011 my $Tag = shift(@_);
2012 if(not $Tag or not $CodeRef) {
2013 return undef;
2014 }
2015 my $Sp = 0;
2016 if(@_) {
2017 $Sp = shift(@_);
2018 }
2019 my $Start = index(${$CodeRef}, "<$Tag>");
2020 if($Start!=-1)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002021 {
Andrey Ponomarenko01117f12012-06-26 12:23:02 +04002022 my $End = index(${$CodeRef}, "</$Tag>");
2023 if($End!=-1)
2024 {
2025 my $TS = length($Tag)+3;
2026 my $Content = substr(${$CodeRef}, $Start, $End-$Start+$TS, "");
2027 substr($Content, 0, $TS-1, ""); # cut start tag
2028 substr($Content, -$TS, $TS, ""); # cut end tag
2029 if(not $Sp)
2030 {
2031 $Content=~s/\A\s+//g;
2032 $Content=~s/\s+\Z//g;
2033 }
2034 if(substr($Content, 0, 1) ne "<") {
2035 $Content = xmlSpecChars_R($Content);
2036 }
2037 return $Content;
2038 }
2039 }
2040 return undef;
2041}
2042
2043sub parseTag_E($$$)
2044{
2045 my ($CodeRef, $Tag, $Info) = @_;
2046 if(not $Tag or not $CodeRef
2047 or not $Info) {
2048 return undef;
2049 }
2050 if(${$CodeRef}=~s/\<\Q$Tag\E(\s+([^<>]+)|)\>((.|\n)*?)\<\/\Q$Tag\E\>//)
2051 {
2052 my ($Ext, $Content) = ($2, $3);
2053 $Content=~s/\A\s+//g;
2054 $Content=~s/\s+\Z//g;
2055 if($Ext)
2056 {
2057 while($Ext=~s/(\w+)\=\"([^\"]*)\"//)
2058 {
2059 my ($K, $V) = ($1, $2);
2060 $Info->{$K} = xmlSpecChars_R($V);
2061 }
2062 }
2063 if(substr($Content, 0, 1) ne "<") {
2064 $Content = xmlSpecChars_R($Content);
2065 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002066 return $Content;
2067 }
Andrey Ponomarenko01117f12012-06-26 12:23:02 +04002068 return undef;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002069}
2070
Andrey Ponomarenko35c44fd2012-06-18 17:50:25 +04002071sub addTag(@)
Andrey Ponomarenko5c09ef32012-06-14 18:17:33 +04002072{
Andrey Ponomarenko35c44fd2012-06-18 17:50:25 +04002073 my $Tag = shift(@_);
2074 my $Val = shift(@_);
2075 my @Ext = @_;
2076 my $Content = openTag($Tag, @Ext);
2077 chomp($Content);
Andrey Ponomarenko5c09ef32012-06-14 18:17:33 +04002078 $Content .= xmlSpecChars($Val);
2079 $Content .= "</$Tag>\n";
Andrey Ponomarenko35c44fd2012-06-18 17:50:25 +04002080 $TAG_ID-=1;
Andrey Ponomarenko5c09ef32012-06-14 18:17:33 +04002081
2082 return $Content;
2083}
2084
Andrey Ponomarenko35c44fd2012-06-18 17:50:25 +04002085sub openTag(@)
Andrey Ponomarenko5c09ef32012-06-14 18:17:33 +04002086{
2087 my $Tag = shift(@_);
2088 my @Ext = @_;
2089 my $Content = "";
2090 foreach (1 .. $TAG_ID) {
2091 $Content .= $INDENT;
2092 }
2093 $TAG_ID+=1;
Andrey Ponomarenko35c44fd2012-06-18 17:50:25 +04002094 if(@Ext)
Andrey Ponomarenko5c09ef32012-06-14 18:17:33 +04002095 {
Andrey Ponomarenko35c44fd2012-06-18 17:50:25 +04002096 $Content .= "<".$Tag;
2097 my $P = 0;
2098 while($P<=$#Ext-1)
2099 {
2100 $Content .= " ".$Ext[$P];
2101 $Content .= "=\"".xmlSpecChars($Ext[$P+1])."\"";
2102 $P+=2;
2103 }
2104 $Content .= ">\n";
Andrey Ponomarenko5c09ef32012-06-14 18:17:33 +04002105 }
Andrey Ponomarenko35c44fd2012-06-18 17:50:25 +04002106 else {
2107 $Content .= "<".$Tag.">\n";
2108 }
Andrey Ponomarenko5c09ef32012-06-14 18:17:33 +04002109 return $Content;
2110}
2111
2112sub closeTag($)
2113{
2114 my $Tag = $_[0];
2115 my $Content = "";
2116 $TAG_ID-=1;
2117 foreach (1 .. $TAG_ID) {
2118 $Content .= $INDENT;
2119 }
2120 $Content .= "</".$Tag.">\n";
2121 return $Content;
2122}
2123
2124sub checkTags()
2125{
2126 if($TAG_ID!=0) {
2127 printMsg("WARNING", "the number of opened tags is not equal to number of closed tags");
2128 }
2129}
2130
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002131sub getInfo($)
2132{
Andrey Ponomarenko85043792012-05-14 16:48:07 +04002133 my $DumpPath = $_[0];
2134 return if(not $DumpPath or not -f $DumpPath);
2135
2136 readTUDump($DumpPath);
2137
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002138 # processing info
2139 setTemplateParams_All();
2140 getTypeInfo_All();
2141 simplifyNames();
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002142 getVarInfo_All();
Andrey Ponomarenko01117f12012-06-26 12:23:02 +04002143 getSymbolInfo_All();
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002144
Andrey Ponomarenko85043792012-05-14 16:48:07 +04002145 # clean memory
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002146 %LibInfo = ();
2147 %TemplateInstance = ();
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002148 %MangledNames = ();
Andrey Ponomarenko85043792012-05-14 16:48:07 +04002149 %TemplateDecl = ();
2150 %StdCxxTypedef = ();
2151 %MissedTypedef = ();
2152 %Typedef_Tr = ();
2153 %Typedef_Eq = ();
2154
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04002155 # clean cache
2156 delete($Cache{"getTypeAttr"});
2157 delete($Cache{"getTypeDeclId"});
2158
2159 # remove unused types
2160 if($BinaryOnly and not $ExtendedCheck)
2161 { # --binary
2162 removeUnused($Version, "All");
2163 }
2164 else {
2165 removeUnused($Version, "Derived");
2166 }
2167
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002168 if($Debug) {
2169 # debugMangling($Version);
2170 }
2171}
2172
Andrey Ponomarenko85043792012-05-14 16:48:07 +04002173sub readTUDump($)
2174{
2175 my $DumpPath = $_[0];
2176
2177 open(TU_DUMP, $DumpPath);
2178 local $/ = undef;
2179 my $Content = <TU_DUMP>;
2180 close(TU_DUMP);
2181
2182 unlink($DumpPath);
2183
2184 $Content=~s/\n[ ]+/ /g;
2185 my @Lines = split("\n", $Content);
2186
2187 # clean memory
2188 undef $Content;
2189
2190 $MAX_ID = $#Lines+1;
2191
2192 foreach (0 .. $#Lines)
2193 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04002194 if($Lines[$_]=~/\A\@(\d+)[ ]+([a-z_]+)[ ]+(.+)\Z/i)
Andrey Ponomarenko85043792012-05-14 16:48:07 +04002195 { # get a number and attributes of a node
2196 next if(not $NodeType{$2});
2197 $LibInfo{$Version}{"info_type"}{$1}=$2;
2198 $LibInfo{$Version}{"info"}{$1}=$3;
2199 }
2200
2201 # clean memory
2202 delete($Lines[$_]);
2203 }
2204
2205 # clean memory
2206 undef @Lines;
2207}
2208
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002209sub simplifyNames()
2210{
2211 foreach my $Base (keys(%{$Typedef_Tr{$Version}}))
2212 {
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +04002213 if($Typedef_Eq{$Version}{$Base}) {
2214 next;
2215 }
2216 my @Translations = sort keys(%{$Typedef_Tr{$Version}{$Base}});
2217 if($#Translations==0)
2218 {
2219 if(length($Translations[0])<=length($Base)) {
2220 $Typedef_Eq{$Version}{$Base} = $Translations[0];
2221 }
2222 }
2223 else
2224 { # select most appropriate
2225 foreach my $Tr (@Translations)
2226 {
2227 if($Base=~/\A\Q$Tr\E/)
2228 {
2229 $Typedef_Eq{$Version}{$Base} = $Tr;
2230 last;
2231 }
2232 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002233 }
2234 }
Andrey Ponomarenkob8d203d2012-05-25 18:11:07 +04002235 foreach my $TypeId (keys(%{$TypeInfo{$Version}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002236 {
Andrey Ponomarenkob8d203d2012-05-25 18:11:07 +04002237 my $TypeName = $TypeInfo{$Version}{$TypeId}{"Name"};
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04002238 if(not $TypeName) {
2239 next;
2240 }
2241 next if(index($TypeName,"<")==-1);# template instances only
2242 if($TypeName=~/>(::\w+)+\Z/)
2243 { # skip unused types
2244 next;
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +04002245 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04002246 foreach my $Base (sort {length($b)<=>length($a)}
2247 sort {$b cmp $a} keys(%{$Typedef_Eq{$Version}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002248 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04002249 next if(not $Base);
2250 next if(index($TypeName,$Base)==-1);
2251 next if(length($TypeName) - length($Base) <= 3);
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +04002252 if(my $Typedef = $Typedef_Eq{$Version}{$Base})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002253 {
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +04002254 $TypeName=~s/(\<|\,)\Q$Base\E(\W|\Z)/$1$Typedef$2/g;
2255 $TypeName=~s/(\<|\,)\Q$Base\E(\w|\Z)/$1$Typedef $2/g;
2256 if(defined $TypeInfo{$Version}{$TypeId}{"TParam"})
Andrey Ponomarenko85043792012-05-14 16:48:07 +04002257 {
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +04002258 foreach my $TPos (keys(%{$TypeInfo{$Version}{$TypeId}{"TParam"}}))
2259 {
2260 if(my $TPName = $TypeInfo{$Version}{$TypeId}{"TParam"}{$TPos}{"name"})
2261 {
2262 $TPName=~s/\A\Q$Base\E(\W|\Z)/$Typedef$1/g;
2263 $TPName=~s/\A\Q$Base\E(\w|\Z)/$Typedef $1/g;
Andrey Ponomarenko9927e332012-10-19 10:50:48 +04002264 $TypeInfo{$Version}{$TypeId}{"TParam"}{$TPos}{"name"} = formatName($TPName, "T");
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +04002265 }
2266 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +04002267 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002268 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002269 }
Andrey Ponomarenko9927e332012-10-19 10:50:48 +04002270 $TypeName = formatName($TypeName, "T");
Andrey Ponomarenkob8d203d2012-05-25 18:11:07 +04002271 $TypeInfo{$Version}{$TypeId}{"Name"} = $TypeName;
2272 $TName_Tid{$Version}{$TypeName} = $TypeId;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002273 }
2274}
2275
2276sub setTemplateParams_All()
2277{
2278 foreach (keys(%{$LibInfo{$Version}{"info"}}))
2279 {
2280 if($LibInfo{$Version}{"info_type"}{$_} eq "template_decl") {
2281 setTemplateParams($_);
2282 }
2283 }
2284}
2285
2286sub setTemplateParams($)
2287{
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04002288 if(my $Info = $LibInfo{$Version}{"info"}{$_[0]})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002289 {
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04002290 if($Info=~/(inst|spcs)[ ]*:[ ]*@(\d+) /)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002291 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04002292 my $TmplInst_Id = $2;
2293 setTemplateInstParams($TmplInst_Id);
2294 while($TmplInst_Id = getNextElem($TmplInst_Id)) {
2295 setTemplateInstParams($TmplInst_Id);
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04002296 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002297 }
2298 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04002299 if(my $TypeId = getTreeAttr_Type($_[0]))
Andrey Ponomarenko85043792012-05-14 16:48:07 +04002300 {
2301 if(my $IType = $LibInfo{$Version}{"info_type"}{$TypeId})
2302 {
2303 if($IType eq "record_type") {
2304 $TemplateDecl{$Version}{$TypeId}=1;
2305 }
2306 }
2307 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002308}
2309
2310sub setTemplateInstParams($)
2311{
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04002312 if(my $Info = $LibInfo{$Version}{"info"}{$_[0]})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002313 {
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04002314 my ($Params_InfoId, $ElemId) = ();
2315 if($Info=~/purp[ ]*:[ ]*@(\d+) /) {
2316 $Params_InfoId = $1;
2317 }
2318 if($Info=~/valu[ ]*:[ ]*@(\d+) /) {
2319 $ElemId = $1;
2320 }
2321 if($Params_InfoId and $ElemId)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002322 {
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04002323 my $Params_Info = $LibInfo{$Version}{"info"}{$Params_InfoId};
2324 while($Params_Info=~s/ (\d+)[ ]*:[ ]*\@(\d+) / /)
2325 {
2326 my ($PPos, $PTypeId) = ($1, $2);
2327 if(my $PType = $LibInfo{$Version}{"info_type"}{$PTypeId})
2328 {
Andrey Ponomarenko85043792012-05-14 16:48:07 +04002329 if($PType eq "template_type_parm")
2330 {
2331 $TemplateDecl{$Version}{$ElemId}=1;
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04002332 return;
2333 }
2334 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +04002335 if($LibInfo{$Version}{"info_type"}{$ElemId} eq "function_decl")
2336 { # functions
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04002337 $TemplateInstance{$Version}{"Func"}{$ElemId}{$PPos} = $PTypeId;
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04002338 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +04002339 else
2340 { # types
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04002341 $TemplateInstance{$Version}{"Type"}{$ElemId}{$PPos} = $PTypeId;
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04002342 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002343 }
2344 }
2345 }
2346}
2347
2348sub getTypeDeclId($)
2349{
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04002350 if($_[0])
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04002351 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04002352 if(defined $Cache{"getTypeDeclId"}{$Version}{$_[0]}) {
2353 return $Cache{"getTypeDeclId"}{$Version}{$_[0]};
2354 }
2355 if(my $Info = $LibInfo{$Version}{"info"}{$_[0]})
2356 {
2357 if($Info=~/name[ ]*:[ ]*@(\d+)/) {
2358 return ($Cache{"getTypeDeclId"}{$Version}{$_[0]} = $1);
2359 }
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04002360 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002361 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04002362 return ($Cache{"getTypeDeclId"}{$Version}{$_[0]} = 0);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002363}
2364
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002365sub getTypeInfo_All()
2366{
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04002367 if(not check_gcc($GCC_PATH, "4.5"))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002368 { # support for GCC < 4.5
2369 # missed typedefs: QStyle::State is typedef to QFlags<QStyle::StateFlag>
2370 # but QStyleOption.state is of type QFlags<QStyle::StateFlag> in the TU dump
2371 # FIXME: check GCC versions
2372 addMissedTypes_Pre();
2373 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04002374
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002375 foreach (sort {int($a)<=>int($b)} keys(%{$LibInfo{$Version}{"info"}}))
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04002376 { # forward order only
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002377 my $IType = $LibInfo{$Version}{"info_type"}{$_};
2378 if($IType=~/_type\Z/ and $IType ne "function_type"
2379 and $IType ne "method_type") {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04002380 getTypeInfo("$_");
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002381 }
2382 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04002383
2384 # add "..." type
Andrey Ponomarenko01117f12012-06-26 12:23:02 +04002385 $TypeInfo{$Version}{"-1"} = {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04002386 "Name" => "...",
2387 "Type" => "Intrinsic",
Andrey Ponomarenko01117f12012-06-26 12:23:02 +04002388 "Tid" => "-1"
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04002389 };
Andrey Ponomarenko01117f12012-06-26 12:23:02 +04002390 $TName_Tid{$Version}{"..."} = "-1";
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04002391
2392 if(not check_gcc($GCC_PATH, "4.5"))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002393 { # support for GCC < 4.5
2394 addMissedTypes_Post();
2395 }
2396}
2397
2398sub addMissedTypes_Pre()
2399{
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04002400 my %MissedTypes = ();
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002401 foreach my $MissedTDid (sort {int($a)<=>int($b)} keys(%{$LibInfo{$Version}{"info"}}))
2402 { # detecting missed typedefs
2403 if($LibInfo{$Version}{"info_type"}{$MissedTDid} eq "type_decl")
2404 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04002405 my $TypeId = getTreeAttr_Type($MissedTDid);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002406 next if(not $TypeId);
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04002407 my $TypeType = getTypeType($TypeId);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002408 if($TypeType eq "Unknown")
2409 { # template_type_parm
2410 next;
2411 }
2412 my $TypeDeclId = getTypeDeclId($TypeId);
2413 next if($TypeDeclId eq $MissedTDid);#or not $TypeDeclId
2414 my $TypedefName = getNameByInfo($MissedTDid);
2415 next if(not $TypedefName);
2416 next if($TypedefName eq "__float80");
2417 next if(isAnon($TypedefName));
2418 if(not $TypeDeclId
2419 or getNameByInfo($TypeDeclId) ne $TypedefName) {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04002420 $MissedTypes{$Version}{$TypeId}{$MissedTDid} = 1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002421 }
2422 }
2423 }
Andrey Ponomarenkob8d203d2012-05-25 18:11:07 +04002424 my %AddTypes = ();
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04002425 foreach my $Tid (keys(%{$MissedTypes{$Version}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002426 { # add missed typedefs
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04002427 my @Missed = keys(%{$MissedTypes{$Version}{$Tid}});
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002428 if(not @Missed or $#Missed>=1) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002429 next;
2430 }
2431 my $MissedTDid = $Missed[0];
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002432 my ($TypedefName, $TypedefNS) = getTrivialName($MissedTDid, $Tid);
Andrey Ponomarenkob8d203d2012-05-25 18:11:07 +04002433 if(not $TypedefName) {
2434 next;
2435 }
2436 $MAX_ID++;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002437 my %MissedInfo = ( # typedef info
2438 "Name" => $TypedefName,
2439 "NameSpace" => $TypedefNS,
2440 "BaseType" => {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002441 "Tid" => $Tid
2442 },
2443 "Type" => "Typedef",
Andrey Ponomarenkob8d203d2012-05-25 18:11:07 +04002444 "Tid" => "$MAX_ID" );
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002445 my ($H, $L) = getLocation($MissedTDid);
2446 $MissedInfo{"Header"} = $H;
2447 $MissedInfo{"Line"} = $L;
Andrey Ponomarenkob8d203d2012-05-25 18:11:07 +04002448 if($TypedefName=~/\*|\&|\s/)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002449 { # other types
2450 next;
2451 }
Andrey Ponomarenkob8d203d2012-05-25 18:11:07 +04002452 if($TypedefName=~/>(::\w+)+\Z/)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002453 { # QFlags<Qt::DropAction>::enum_type
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002454 next;
2455 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04002456 if(getTypeType($Tid)=~/\A(Intrinsic|Union|Struct|Enum|Class)\Z/)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002457 { # double-check for the name of typedef
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04002458 my ($TName, $TNS) = getTrivialName(getTypeDeclId($Tid), $Tid); # base type info
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002459 next if(not $TName);
Andrey Ponomarenkob8d203d2012-05-25 18:11:07 +04002460 if(length($TypedefName)>=length($TName))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002461 { # too long typedef
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002462 next;
2463 }
Andrey Ponomarenkob8d203d2012-05-25 18:11:07 +04002464 if($TName=~/\A\Q$TypedefName\E</) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002465 next;
2466 }
Andrey Ponomarenkob8d203d2012-05-25 18:11:07 +04002467 if($TypedefName=~/\A\Q$TName\E/)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002468 { # QDateTimeEdit::Section and QDateTimeEdit::Sections::enum_type
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002469 next;
2470 }
Andrey Ponomarenkob8d203d2012-05-25 18:11:07 +04002471 if(get_depth($TypedefName)==0 and get_depth($TName)!=0)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002472 { # std::_Vector_base and std::vector::_Base
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002473 next;
2474 }
2475 }
Andrey Ponomarenkob8d203d2012-05-25 18:11:07 +04002476
2477 $AddTypes{$MissedInfo{"Tid"}} = \%MissedInfo;
2478
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002479 # register typedef
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002480 $MissedTypedef{$Version}{$Tid}{"Tid"} = $MissedInfo{"Tid"};
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04002481 $MissedTypedef{$Version}{$Tid}{"TDid"} = $MissedTDid;
Andrey Ponomarenkob8d203d2012-05-25 18:11:07 +04002482 $TName_Tid{$Version}{$TypedefName} = $MissedInfo{"Tid"};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002483 }
Andrey Ponomarenkob8d203d2012-05-25 18:11:07 +04002484
2485 # add missed & remove other
2486 $TypeInfo{$Version} = \%AddTypes;
2487 delete($Cache{"getTypeAttr"}{$Version});
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002488}
2489
2490sub addMissedTypes_Post()
2491{
2492 foreach my $BaseId (keys(%{$MissedTypedef{$Version}}))
2493 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04002494 if(my $Tid = $MissedTypedef{$Version}{$BaseId}{"Tid"})
2495 {
2496 $TypeInfo{$Version}{$Tid}{"Size"} = $TypeInfo{$Version}{$BaseId}{"Size"};
2497 if(my $TName = $TypeInfo{$Version}{$Tid}{"Name"}) {
2498 $Typedef_BaseName{$Version}{$TName} = $TypeInfo{$Version}{$BaseId}{"Name"};
2499 }
2500 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002501 }
2502}
2503
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04002504sub getTypeInfo($)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002505{
Andrey Ponomarenkob8d203d2012-05-25 18:11:07 +04002506 my $TypeId = $_[0];
2507 %{$TypeInfo{$Version}{$TypeId}} = getTypeAttr($TypeId);
2508 my $TName = $TypeInfo{$Version}{$TypeId}{"Name"};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002509 if(not $TName) {
Andrey Ponomarenkob8d203d2012-05-25 18:11:07 +04002510 delete($TypeInfo{$Version}{$TypeId});
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002511 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002512}
2513
2514sub getArraySize($$)
2515{
2516 my ($TypeId, $BaseName) = @_;
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04002517 if(my $Size = getSize($TypeId))
2518 {
2519 my $Elems = $Size/$BYTE_SIZE;
2520 while($BaseName=~s/\s*\[(\d+)\]//) {
2521 $Elems/=$1;
2522 }
2523 if(my $BasicId = $TName_Tid{$Version}{$BaseName})
2524 {
2525 if(my $BasicSize = $TypeInfo{$Version}{$BasicId}{"Size"}) {
2526 $Elems/=$BasicSize;
2527 }
2528 }
2529 return $Elems;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002530 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04002531 return 0;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002532}
2533
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04002534sub getTParams($$)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002535{
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04002536 my ($TypeId, $Kind) = @_;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002537 my @TmplParams = ();
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04002538 my @Positions = sort {int($a)<=>int($b)} keys(%{$TemplateInstance{$Version}{$Kind}{$TypeId}});
2539 foreach my $Pos (@Positions)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002540 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04002541 my $Param_TypeId = $TemplateInstance{$Version}{$Kind}{$TypeId}{$Pos};
2542 my $NodeType = $LibInfo{$Version}{"info_type"}{$Param_TypeId};
2543 if(not $NodeType)
2544 { # typename_type
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002545 return ();
2546 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04002547 if($NodeType eq "tree_vec")
2548 {
2549 if($Pos!=$#Positions)
2550 { # select last vector of parameters ( ns<P1>::type<P2> )
2551 next;
2552 }
2553 }
2554 my @Params = get_TemplateParam($Pos, $Param_TypeId);
2555 foreach my $P (@Params)
2556 {
2557 if($P eq "") {
2558 return ();
2559 }
2560 elsif($P ne "\@skip\@") {
2561 @TmplParams = (@TmplParams, $P);
2562 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002563 }
2564 }
2565 return @TmplParams;
2566}
2567
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04002568sub getTypeAttr($)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002569{
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04002570 my $TypeId = $_[0];
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04002571 my %TypeAttr = ();
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04002572 if(defined $TypeInfo{$Version}{$TypeId}
2573 and $TypeInfo{$Version}{$TypeId}{"Name"})
2574 { # already created
2575 return %{$TypeInfo{$Version}{$TypeId}};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002576 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04002577 elsif($Cache{"getTypeAttr"}{$Version}{$TypeId})
2578 { # incomplete type
2579 return ();
2580 }
2581 $Cache{"getTypeAttr"}{$Version}{$TypeId} = 1;
2582
2583 my $TypeDeclId = getTypeDeclId($TypeId);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002584 $TypeAttr{"Tid"} = $TypeId;
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04002585
2586 if(not $MissedBase{$Version}{$TypeId} and isTypedef($TypeId))
2587 {
2588 if(my $Info = $LibInfo{$Version}{"info"}{$TypeId})
2589 {
2590 if($Info=~/qual[ ]*:/)
2591 {
2592 if(my $NID = ++$MAX_ID)
2593 {
2594 $MissedBase{$Version}{$TypeId}="$NID";
2595 $MissedBase_R{$Version}{$NID}=$TypeId;
2596 $LibInfo{$Version}{"info"}{$NID} = $LibInfo{$Version}{"info"}{$TypeId};
2597 $LibInfo{$Version}{"info_type"}{$NID} = $LibInfo{$Version}{"info_type"}{$TypeId};
2598 }
2599 }
2600 }
2601 $TypeAttr{"Type"} = "Typedef";
2602 }
2603 else {
2604 $TypeAttr{"Type"} = getTypeType($TypeId);
2605 }
2606
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002607 if($TypeAttr{"Type"} eq "Unknown") {
2608 return ();
2609 }
2610 elsif($TypeAttr{"Type"}=~/(Func|Method|Field)Ptr/)
2611 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04002612 %TypeAttr = getMemPtrAttr(pointTo($TypeId), $TypeId, $TypeAttr{"Type"});
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04002613 if(my $TName = $TypeAttr{"Name"})
2614 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04002615 %{$TypeInfo{$Version}{$TypeId}} = %TypeAttr;
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04002616 $TName_Tid{$Version}{$TName} = $TypeId;
2617 return %TypeAttr;
2618 }
2619 else {
2620 return ();
2621 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002622 }
2623 elsif($TypeAttr{"Type"} eq "Array")
2624 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04002625 my ($BTid, $BTSpec) = selectBaseType($TypeId);
2626 if(not $BTid) {
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04002627 return ();
2628 }
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +04002629 if(my $Algn = getAlgn($TypeId)) {
2630 $TypeAttr{"Algn"} = $Algn/$BYTE_SIZE;
2631 }
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04002632 $TypeAttr{"BaseType"}{"Tid"} = $BTid;
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04002633 if(my %BTAttr = getTypeAttr($BTid))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002634 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04002635 if(not $BTAttr{"Name"}) {
2636 return ();
2637 }
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04002638 if(my $NElems = getArraySize($TypeId, $BTAttr{"Name"}))
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04002639 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04002640 if(my $Size = getSize($TypeId)) {
2641 $TypeAttr{"Size"} = $Size/$BYTE_SIZE;
2642 }
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04002643 if($BTAttr{"Name"}=~/\A([^\[\]]+)(\[(\d+|)\].*)\Z/) {
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04002644 $TypeAttr{"Name"} = $1."[$NElems]".$2;
2645 }
2646 else {
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04002647 $TypeAttr{"Name"} = $BTAttr{"Name"}."[$NElems]";
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04002648 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002649 }
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04002650 else
2651 {
2652 $TypeAttr{"Size"} = $WORD_SIZE{$Version}; # pointer
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04002653 if($BTAttr{"Name"}=~/\A([^\[\]]+)(\[(\d+|)\].*)\Z/) {
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04002654 $TypeAttr{"Name"} = $1."[]".$2;
2655 }
2656 else {
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04002657 $TypeAttr{"Name"} = $BTAttr{"Name"}."[]";
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04002658 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002659 }
Andrey Ponomarenko9927e332012-10-19 10:50:48 +04002660 $TypeAttr{"Name"} = formatName($TypeAttr{"Name"}, "T");
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04002661 if($BTAttr{"Header"}) {
2662 $TypeAttr{"Header"} = $BTAttr{"Header"};
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04002663 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04002664 %{$TypeInfo{$Version}{$TypeId}} = %TypeAttr;
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04002665 $TName_Tid{$Version}{$TypeAttr{"Name"}} = $TypeId;
2666 return %TypeAttr;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002667 }
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04002668 return ();
2669 }
2670 elsif($TypeAttr{"Type"}=~/\A(Intrinsic|Union|Struct|Enum|Class)\Z/)
2671 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04002672 %TypeAttr = getTrivialTypeAttr($TypeId);
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04002673 if($TypeAttr{"Name"})
2674 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04002675 %{$TypeInfo{$Version}{$TypeId}} = %TypeAttr;
2676 if($TypeAttr{"Name"} ne "int" or getTypeDeclId($TypeAttr{"Tid"}))
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04002677 { # NOTE: register only one int: with built-in decl
2678 if(not $TName_Tid{$Version}{$TypeAttr{"Name"}}) {
2679 $TName_Tid{$Version}{$TypeAttr{"Name"}} = $TypeId;
2680 }
2681 }
2682 return %TypeAttr;
2683 }
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04002684 else {
2685 return ();
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002686 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002687 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002688 else
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04002689 { # derived types
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04002690 my ($BTid, $BTSpec) = selectBaseType($TypeId);
2691 if(not $BTid) {
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04002692 return ();
2693 }
2694 $TypeAttr{"BaseType"}{"Tid"} = $BTid;
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04002695 if(defined $MissedTypedef{$Version}{$BTid})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002696 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04002697 if(my $MissedTDid = $MissedTypedef{$Version}{$BTid}{"TDid"})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002698 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04002699 if($MissedTDid ne $TypeDeclId) {
2700 $TypeAttr{"BaseType"}{"Tid"} = $MissedTypedef{$Version}{$BTid}{"Tid"};
2701 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002702 }
2703 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04002704 my %BTAttr = getTypeAttr($TypeAttr{"BaseType"}{"Tid"});
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04002705 if(not $BTAttr{"Name"})
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04002706 { # templates
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002707 return ();
2708 }
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04002709 if($BTAttr{"Type"} eq "Typedef")
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002710 { # relinking typedefs
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04002711 my %BaseBase = get_Type($BTAttr{"BaseType"}{"Tid"}, $Version);
2712 if($BTAttr{"Name"} eq $BaseBase{"Name"}) {
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04002713 $TypeAttr{"BaseType"}{"Tid"} = $BaseBase{"Tid"};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002714 }
2715 }
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04002716 if($BTSpec)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002717 {
2718 if($TypeAttr{"Type"} eq "Pointer"
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04002719 and $BTAttr{"Name"}=~/\([\*]+\)/)
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04002720 {
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04002721 $TypeAttr{"Name"} = $BTAttr{"Name"};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002722 $TypeAttr{"Name"}=~s/\(([*]+)\)/($1*)/g;
2723 }
2724 else {
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04002725 $TypeAttr{"Name"} = $BTAttr{"Name"}." ".$BTSpec;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002726 }
2727 }
2728 else {
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04002729 $TypeAttr{"Name"} = $BTAttr{"Name"};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002730 }
2731 if($TypeAttr{"Type"} eq "Typedef")
2732 {
2733 $TypeAttr{"Name"} = getNameByInfo($TypeDeclId);
Andrey Ponomarenko85043792012-05-14 16:48:07 +04002734 if(isAnon($TypeAttr{"Name"}))
2735 { # anon typedef to anon type: ._N
2736 return ();
2737 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002738 if(my $NS = getNameSpace($TypeDeclId))
2739 {
2740 my $TypeName = $TypeAttr{"Name"};
2741 if($NS=~/\A(struct |union |class |)((.+)::|)\Q$TypeName\E\Z/)
2742 { # "some_type" is the typedef to "struct some_type" in C++
2743 if($3) {
2744 $TypeAttr{"Name"} = $3."::".$TypeName;
2745 }
2746 }
2747 else
2748 {
2749 $TypeAttr{"NameSpace"} = $NS;
2750 $TypeAttr{"Name"} = $TypeAttr{"NameSpace"}."::".$TypeAttr{"Name"};
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04002751
2752 if($TypeAttr{"NameSpace"}=~/\Astd(::|\Z)/
2753 and $TypeAttr{"Name"}!~/>(::\w+)+\Z/)
2754 {
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04002755 if($BTAttr{"NameSpace"}
2756 and $BTAttr{"NameSpace"}=~/\Astd(::|\Z)/ and $BTAttr{"Name"}=~/</)
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04002757 { # types like "std::fpos<__mbstate_t>" are
2758 # not covered by typedefs in the TU dump
2759 # so trying to add such typedefs manually
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04002760 $StdCxxTypedef{$Version}{$BTAttr{"Name"}}{$TypeAttr{"Name"}} = 1;
2761 if(length($TypeAttr{"Name"})<=length($BTAttr{"Name"}))
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04002762 {
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04002763 if(($BTAttr{"Name"}!~/\A(std|boost)::/ or $TypeAttr{"Name"}!~/\A[a-z]+\Z/))
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04002764 { # skip "other" in "std" and "type" in "boost"
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04002765 $Typedef_Eq{$Version}{$BTAttr{"Name"}} = $TypeAttr{"Name"};
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04002766 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002767 }
2768 }
2769 }
2770 }
2771 }
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04002772 if($TypeAttr{"Name"} ne $BTAttr{"Name"}
2773 and $TypeAttr{"Name"}!~/>(::\w+)+\Z/ and $BTAttr{"Name"}!~/>(::\w+)+\Z/)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002774 {
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04002775 if(not defined $Typedef_BaseName{$Version}{$TypeAttr{"Name"}})
2776 { # typedef int*const TYPEDEF; // first
2777 # int foo(TYPEDEF p); // const is optimized out
2778 $Typedef_BaseName{$Version}{$TypeAttr{"Name"}} = $BTAttr{"Name"};
2779 if($BTAttr{"Name"}=~/</)
2780 {
2781 if(($BTAttr{"Name"}!~/\A(std|boost)::/ or $TypeAttr{"Name"}!~/\A[a-z]+\Z/)) {
2782 $Typedef_Tr{$Version}{$BTAttr{"Name"}}{$TypeAttr{"Name"}} = 1;
2783 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002784 }
2785 }
2786 }
2787 ($TypeAttr{"Header"}, $TypeAttr{"Line"}) = getLocation($TypeDeclId);
2788 }
2789 if(not $TypeAttr{"Size"})
2790 {
2791 if($TypeAttr{"Type"} eq "Pointer") {
2792 $TypeAttr{"Size"} = $WORD_SIZE{$Version};
2793 }
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04002794 elsif($BTAttr{"Size"}) {
2795 $TypeAttr{"Size"} = $BTAttr{"Size"};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002796 }
2797 }
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +04002798 if(my $Algn = getAlgn($TypeId)) {
2799 $TypeAttr{"Algn"} = $Algn/$BYTE_SIZE;
2800 }
Andrey Ponomarenko9927e332012-10-19 10:50:48 +04002801 $TypeAttr{"Name"} = formatName($TypeAttr{"Name"}, "T");
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04002802 if(not $TypeAttr{"Header"} and $BTAttr{"Header"}) {
2803 $TypeAttr{"Header"} = $BTAttr{"Header"};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002804 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04002805 %{$TypeInfo{$Version}{$TypeId}} = %TypeAttr;
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04002806 if($TypeAttr{"Name"} ne $BTAttr{"Name"})
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04002807 { # typedef to "class Class"
2808 # should not be registered in TName_Tid
2809 if(not $TName_Tid{$Version}{$TypeAttr{"Name"}}) {
2810 $TName_Tid{$Version}{$TypeAttr{"Name"}} = $TypeId;
2811 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002812 }
2813 return %TypeAttr;
2814 }
2815}
2816
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04002817sub getTreeVec($)
2818{
2819 my %Vector = ();
2820 if($_[0] and my $Info = $LibInfo{$Version}{"info"}{$_[0]})
2821 {
2822 while($Info=~s/ (\d+)[ ]*:[ ]*\@(\d+) / /)
2823 { # string length is N-1 because of the null terminator
2824 $Vector{$1} = $2;
2825 }
2826 }
2827 return \%Vector;
2828}
2829
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002830sub get_TemplateParam($$)
2831{
2832 my ($Pos, $Type_Id) = @_;
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04002833 return () if(not $Type_Id);
2834 my $NodeType = $LibInfo{$Version}{"info_type"}{$Type_Id};
2835 return () if(not $NodeType);
2836 if($NodeType eq "integer_cst")
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002837 { # int (1), unsigned (2u), char ('c' as 99), ...
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04002838 my $CstTid = getTreeAttr_Type($Type_Id);
Andrey Ponomarenkob8d203d2012-05-25 18:11:07 +04002839 my %CstType = getTypeAttr($CstTid); # without recursion
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002840 my $Num = getNodeIntCst($Type_Id);
2841 if(my $CstSuffix = $ConstantSuffix{$CstType{"Name"}}) {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04002842 return ($Num.$CstSuffix);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002843 }
2844 else {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04002845 return ("(".$CstType{"Name"}.")".$Num);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002846 }
2847 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04002848 elsif($NodeType eq "string_cst") {
2849 return (getNodeStrCst($Type_Id));
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002850 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04002851 elsif($NodeType eq "tree_vec")
2852 {
2853 my $Vector = getTreeVec($Type_Id);
2854 my @Params = ();
2855 foreach my $P1 (sort {int($a)<=>int($b)} keys(%{$Vector}))
2856 {
2857 foreach my $P2 (get_TemplateParam($Pos, $Vector->{$P1})) {
2858 push(@Params, $P2);
2859 }
2860 }
2861 return @Params;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002862 }
2863 else
2864 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04002865 my %ParamAttr = getTypeAttr($Type_Id);
Andrey Ponomarenkob8d203d2012-05-25 18:11:07 +04002866 my $PName = $ParamAttr{"Name"};
2867 if(not $PName) {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04002868 return ();
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002869 }
Andrey Ponomarenkob8d203d2012-05-25 18:11:07 +04002870 if($PName=~/\>/)
2871 {
2872 if(my $Cover = cover_stdcxx_typedef($PName)) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002873 $PName = $Cover;
2874 }
2875 }
2876 if($Pos>=1 and
2877 $PName=~/\Astd::(allocator|less|((char|regex)_traits)|((i|o)streambuf_iterator))\</)
2878 { # template<typename _Tp, typename _Alloc = std::allocator<_Tp> >
2879 # template<typename _Key, typename _Compare = std::less<_Key>
2880 # template<typename _CharT, typename _Traits = std::char_traits<_CharT> >
2881 # template<typename _Ch_type, typename _Rx_traits = regex_traits<_Ch_type> >
2882 # template<typename _CharT, typename _InIter = istreambuf_iterator<_CharT> >
2883 # template<typename _CharT, typename _OutIter = ostreambuf_iterator<_CharT> >
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04002884 return ("\@skip\@");
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002885 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04002886 return ($PName);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002887 }
2888}
2889
2890sub cover_stdcxx_typedef($)
2891{
2892 my $TypeName = $_[0];
2893 if(my @Covers = sort {length($a)<=>length($b)}
2894 sort keys(%{$StdCxxTypedef{$Version}{$TypeName}}))
2895 { # take the shortest typedef
2896 # FIXME: there may be more than
2897 # one typedefs to the same type
2898 return $Covers[0];
2899 }
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +04002900 my $Covered = $TypeName;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002901 while($TypeName=~s/(>)[ ]*(const|volatile|restrict| |\*|\&)\Z/$1/g){};
2902 if(my @Covers = sort {length($a)<=>length($b)} sort keys(%{$StdCxxTypedef{$Version}{$TypeName}}))
2903 {
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +04002904 if(my $Cover = $Covers[0])
2905 {
2906 $Covered=~s/\b\Q$TypeName\E(\W|\Z)/$Cover$1/g;
2907 $Covered=~s/\b\Q$TypeName\E(\w|\Z)/$Cover $1/g;
2908 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002909 }
Andrey Ponomarenko9927e332012-10-19 10:50:48 +04002910 return formatName($Covered, "T");
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002911}
2912
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002913sub getNodeIntCst($)
2914{
2915 my $CstId = $_[0];
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04002916 my $CstTypeId = getTreeAttr_Type($CstId);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002917 if($EnumMembName_Id{$Version}{$CstId}) {
2918 return $EnumMembName_Id{$Version}{$CstId};
2919 }
2920 elsif((my $Value = getTreeValue($CstId)) ne "")
2921 {
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04002922 if($Value eq "0")
2923 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04002924 if($LibInfo{$Version}{"info_type"}{$CstTypeId} eq "boolean_type") {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002925 return "false";
2926 }
2927 else {
2928 return "0";
2929 }
2930 }
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04002931 elsif($Value eq "1")
2932 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04002933 if($LibInfo{$Version}{"info_type"}{$CstTypeId} eq "boolean_type") {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002934 return "true";
2935 }
2936 else {
2937 return "1";
2938 }
2939 }
2940 else {
2941 return $Value;
2942 }
2943 }
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04002944 return "";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002945}
2946
2947sub getNodeStrCst($)
2948{
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04002949 if($_[0] and my $Info = $LibInfo{$Version}{"info"}{$_[0]})
2950 {
2951 if($Info=~/strg[ ]*: (.+) lngt:[ ]*(\d+)/)
Andrey Ponomarenko01117f12012-06-26 12:23:02 +04002952 {
2953 if($LibInfo{$Version}{"info_type"}{$_[0]} eq "string_cst")
2954 { # string length is N-1 because of the null terminator
2955 return substr($1, 0, $2-1);
2956 }
2957 else
2958 { # identifier_node
2959 return substr($1, 0, $2);
2960 }
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04002961 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002962 }
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04002963 return "";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002964}
2965
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04002966sub getMemPtrAttr($$$)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002967{ # function, method and field pointers
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04002968 my ($PtrId, $TypeId, $Type) = @_;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002969 my $MemInfo = $LibInfo{$Version}{"info"}{$PtrId};
2970 if($Type eq "FieldPtr") {
2971 $MemInfo = $LibInfo{$Version}{"info"}{$TypeId};
2972 }
2973 my $MemInfo_Type = $LibInfo{$Version}{"info_type"}{$PtrId};
2974 my $MemPtrName = "";
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04002975 my %TypeAttr = ("Size"=>$WORD_SIZE{$Version}, "Type"=>$Type, "Tid"=>$TypeId);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002976 if($Type eq "MethodPtr")
2977 { # size of "method pointer" may be greater than WORD size
Andrey Ponomarenko01117f12012-06-26 12:23:02 +04002978 if(my $Size = getSize($TypeId))
2979 {
2980 $Size/=$BYTE_SIZE;
2981 $TypeAttr{"Size"} = "$Size";
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04002982 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002983 }
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +04002984 if(my $Algn = getAlgn($TypeId)) {
2985 $TypeAttr{"Algn"} = $Algn/$BYTE_SIZE;
2986 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002987 # Return
2988 if($Type eq "FieldPtr")
2989 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04002990 my %ReturnAttr = getTypeAttr($PtrId);
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04002991 if($ReturnAttr{"Name"}) {
2992 $MemPtrName .= $ReturnAttr{"Name"};
2993 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002994 $TypeAttr{"Return"} = $PtrId;
2995 }
2996 else
2997 {
2998 if($MemInfo=~/retn[ ]*:[ ]*\@(\d+) /)
2999 {
3000 my $ReturnTypeId = $1;
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04003001 my %ReturnAttr = getTypeAttr($ReturnTypeId);
3002 if(not $ReturnAttr{"Name"})
3003 { # templates
3004 return ();
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04003005 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04003006 $MemPtrName .= $ReturnAttr{"Name"};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003007 $TypeAttr{"Return"} = $ReturnTypeId;
3008 }
3009 }
3010 # Class
3011 if($MemInfo=~/(clas|cls)[ ]*:[ ]*@(\d+) /)
3012 {
3013 $TypeAttr{"Class"} = $2;
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04003014 my %Class = getTypeAttr($TypeAttr{"Class"});
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003015 if($Class{"Name"}) {
3016 $MemPtrName .= " (".$Class{"Name"}."\:\:*)";
3017 }
3018 else {
3019 $MemPtrName .= " (*)";
3020 }
3021 }
3022 else {
3023 $MemPtrName .= " (*)";
3024 }
3025 # Parameters
3026 if($Type eq "FuncPtr"
3027 or $Type eq "MethodPtr")
3028 {
3029 my @ParamTypeName = ();
3030 if($MemInfo=~/prms[ ]*:[ ]*@(\d+) /)
3031 {
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04003032 my $PTypeInfoId = $1;
Andrey Ponomarenko01117f12012-06-26 12:23:02 +04003033 my ($Pos, $PPos) = (0, 0);
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04003034 while($PTypeInfoId)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003035 {
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04003036 my $PTypeInfo = $LibInfo{$Version}{"info"}{$PTypeInfoId};
3037 if($PTypeInfo=~/valu[ ]*:[ ]*@(\d+) /)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003038 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04003039 my $PTypeId = $1;
3040 my %ParamAttr = getTypeAttr($PTypeId);
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04003041 if(not $ParamAttr{"Name"})
3042 { # templates (template_type_parm), etc.
3043 return ();
3044 }
3045 if($ParamAttr{"Name"} eq "void") {
3046 last;
3047 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04003048 if($Pos!=0 or $Type ne "MethodPtr")
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04003049 {
Andrey Ponomarenko01117f12012-06-26 12:23:02 +04003050 $TypeAttr{"Param"}{$PPos++}{"type"} = $PTypeId;
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04003051 push(@ParamTypeName, $ParamAttr{"Name"});
3052 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04003053 if($PTypeInfoId = getNextElem($PTypeInfoId)) {
3054 $Pos+=1;
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04003055 }
3056 else {
3057 last;
3058 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003059 }
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04003060 else {
3061 last;
3062 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003063 }
3064 }
3065 $MemPtrName .= " (".join(", ", @ParamTypeName).")";
3066 }
Andrey Ponomarenko9927e332012-10-19 10:50:48 +04003067 $TypeAttr{"Name"} = formatName($MemPtrName, "T");
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003068 return %TypeAttr;
3069}
3070
3071sub getTreeTypeName($)
3072{
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04003073 my $TypeId = $_[0];
3074 if(my $Info = $LibInfo{$Version}{"info"}{$TypeId})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003075 {
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04003076 if($LibInfo{$Version}{"info_type"}{$_[0]} eq "integer_type")
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003077 {
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04003078 if(my $Name = getNameByInfo($TypeId))
3079 { # bit_size_type
3080 return $Name;
3081 }
3082 elsif($Info=~/unsigned/) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003083 return "unsigned int";
3084 }
3085 else {
3086 return "int";
3087 }
3088 }
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04003089 elsif($Info=~/name[ ]*:[ ]*@(\d+) /)
3090 {
3091 return getNameByInfo($1);
3092 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003093 }
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04003094 return "";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003095}
3096
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04003097sub isFuncPtr($)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003098{
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04003099 my $Ptd = pointTo($_[0]);
3100 return 0 if(not $Ptd);
3101 if(my $Info = $LibInfo{$Version}{"info"}{$_[0]})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003102 {
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04003103 if($Info=~/unql[ ]*:/ and $Info!~/qual[ ]*:/) {
3104 return 0;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003105 }
3106 }
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04003107 if(my $InfoT1 = $LibInfo{$Version}{"info_type"}{$_[0]}
3108 and my $InfoT2 = $LibInfo{$Version}{"info_type"}{$Ptd})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003109 {
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04003110 if($InfoT1 eq "pointer_type"
3111 and $InfoT2 eq "function_type") {
3112 return 1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003113 }
3114 }
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04003115 return 0;
3116}
3117
3118sub isMethodPtr($)
3119{
3120 my $Ptd = pointTo($_[0]);
3121 return 0 if(not $Ptd);
3122 if(my $Info = $LibInfo{$Version}{"info"}{$_[0]})
3123 {
3124 if($LibInfo{$Version}{"info_type"}{$_[0]} eq "record_type"
3125 and $LibInfo{$Version}{"info_type"}{$Ptd} eq "method_type"
3126 and $Info=~/ ptrmem /) {
3127 return 1;
3128 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003129 }
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04003130 return 0;
3131}
3132
3133sub isFieldPtr($)
3134{
3135 if($_[0] and my $Info = $LibInfo{$Version}{"info"}{$_[0]})
3136 {
3137 if($LibInfo{$Version}{"info_type"}{$_[0]} eq "offset_type"
3138 and $Info=~/ ptrmem /) {
3139 return 1;
3140 }
3141 }
3142 return 0;
3143}
3144
3145sub pointTo($)
3146{
3147 if($_[0] and my $Info = $LibInfo{$Version}{"info"}{$_[0]})
3148 {
3149 if($Info=~/ptd[ ]*:[ ]*@(\d+)/) {
3150 return $1;
3151 }
3152 }
3153 return "";
3154}
3155
3156sub getTypeTypeByTypeId($)
3157{
3158 my $TypeId = $_[0];
3159 if(my $TType = $LibInfo{$Version}{"info_type"}{$TypeId})
3160 {
3161 my $NType = $NodeType{$TType};
3162 if($NType eq "Intrinsic") {
3163 return $NType;
3164 }
3165 elsif(isFuncPtr($TypeId)) {
3166 return "FuncPtr";
3167 }
3168 elsif(isMethodPtr($TypeId)) {
3169 return "MethodPtr";
3170 }
3171 elsif(isFieldPtr($TypeId)) {
3172 return "FieldPtr";
3173 }
3174 elsif($NType ne "Other") {
3175 return $NType;
3176 }
3177 }
3178 return "Unknown";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003179}
3180
3181sub getQual($)
3182{
3183 my $TypeId = $_[0];
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003184 my %UnQual = (
3185 "r"=>"restrict",
3186 "v"=>"volatile",
3187 "c"=>"const",
3188 "cv"=>"const volatile"
3189 );
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04003190 if(my $Info = $LibInfo{$Version}{"info"}{$TypeId})
3191 {
3192 my ($Qual, $To) = ();
3193 if($Info=~/qual[ ]*:[ ]*(r|c|v|cv) /) {
3194 $Qual = $UnQual{$1};
3195 }
3196 if($Info=~/unql[ ]*:[ ]*\@(\d+)/) {
3197 $To = $1;
3198 }
3199 if($Qual and $To) {
3200 return ($Qual, $To);
3201 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003202 }
3203 return ();
3204}
3205
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04003206sub getQualType($)
3207{
3208 if($_[0] eq "const volatile") {
3209 return "ConstVolatile";
3210 }
3211 return ucfirst($_[0]);
3212}
3213
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04003214sub getTypeType($)
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04003215{
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04003216 my $TypeId = $_[0];
3217 my $TypeDeclId = getTypeDeclId($TypeId);
3218 if(defined $MissedTypedef{$Version}{$TypeId})
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04003219 { # support for old GCC versions
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04003220 if($MissedTypedef{$Version}{$TypeId}{"TDid"} eq $TypeDeclId) {
3221 return "Typedef";
3222 }
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04003223 }
3224 my $Info = $LibInfo{$Version}{"info"}{$TypeId};
3225 my ($Qual, $To) = getQual($TypeId);
Andrey Ponomarenko9927e332012-10-19 10:50:48 +04003226 if(($Qual or $To) and $TypeDeclId
3227 and (getTypeId($TypeDeclId) ne $TypeId))
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04003228 { # qualified types (special)
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04003229 return getQualType($Qual);
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04003230 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04003231 elsif(not $MissedBase_R{$Version}{$TypeId}
3232 and isTypedef($TypeId)) {
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04003233 return "Typedef";
3234 }
3235 elsif($Qual)
3236 { # qualified types
3237 return getQualType($Qual);
3238 }
Andrey Ponomarenko9927e332012-10-19 10:50:48 +04003239
3240 if($Info=~/unql[ ]*:[ ]*\@(\d+)/)
3241 { # typedef struct { ... } name
3242 $TypeTypedef{$Version}{$TypeId} = $1;
3243 }
3244
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04003245 my $TypeType = getTypeTypeByTypeId($TypeId);
3246 if($TypeType eq "Struct")
3247 {
3248 if($TypeDeclId
3249 and $LibInfo{$Version}{"info_type"}{$TypeDeclId} eq "template_decl") {
3250 return "Template";
3251 }
3252 }
3253 return $TypeType;
3254}
3255
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04003256sub isTypedef($)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003257{
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04003258 if($_[0] and my $Info = $LibInfo{$Version}{"info"}{$_[0]})
3259 {
3260 my $TDid = getTypeDeclId($_[0]);
3261 if(getNameByInfo($TDid)
3262 and $Info=~/unql[ ]*:[ ]*\@(\d+) /
3263 and getTypeId($TDid) eq $_[0]) {
3264 return $1;
3265 }
3266 }
3267 return 0;
3268}
3269
3270sub selectBaseType($)
3271{
3272 my $TypeId = $_[0];
3273 if(defined $MissedTypedef{$Version}{$TypeId})
3274 { # add missed typedefs
3275 if($MissedTypedef{$Version}{$TypeId}{"TDid"} eq getTypeDeclId($TypeId)) {
3276 return ($TypeId, "");
3277 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003278 }
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04003279 my $Info = $LibInfo{$Version}{"info"}{$TypeId};
3280 my $InfoType = $LibInfo{$Version}{"info_type"}{$TypeId};
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04003281
3282 my $MB_R = $MissedBase_R{$Version}{$TypeId};
3283 my $MB = $MissedBase{$Version}{$TypeId};
3284
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04003285 my ($Qual, $To) = getQual($TypeId);
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04003286 if(($Qual or $To) and $Info=~/name[ ]*:[ ]*\@(\d+) /
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04003287 and (getTypeId($1) ne $TypeId)
3288 and (not $MB_R or getTypeId($1) ne $MB_R))
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04003289 { # qualified types (special)
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04003290 return (getTypeId($1), $Qual);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003291 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04003292 elsif($MB)
3293 { # add base
3294 return ($MB, "");
3295 }
3296 elsif(not $MB_R and my $Bid = isTypedef($TypeId))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003297 { # typedefs
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04003298 return ($Bid, "");
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003299 }
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04003300 elsif($Qual or $To)
3301 { # qualified types
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04003302 return ($To, $Qual);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003303 }
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04003304 elsif($InfoType eq "reference_type")
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003305 {
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04003306 if($Info=~/refd[ ]*:[ ]*@(\d+) /) {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04003307 return ($1, "&");
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003308 }
3309 else {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04003310 return (0, "");
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003311 }
3312 }
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04003313 elsif($InfoType eq "array_type")
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003314 {
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04003315 if($Info=~/elts[ ]*:[ ]*@(\d+) /) {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04003316 return ($1, "");
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003317 }
3318 else {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04003319 return (0, "");
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003320 }
3321 }
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04003322 elsif($InfoType eq "pointer_type")
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003323 {
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04003324 if($Info=~/ptd[ ]*:[ ]*@(\d+) /) {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04003325 return ($1, "*");
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003326 }
3327 else {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04003328 return (0, "");
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003329 }
3330 }
3331 else {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04003332 return (0, "");
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003333 }
3334}
3335
3336sub getSymbolInfo_All()
3337{
3338 foreach (sort {int($b)<=>int($a)} keys(%{$LibInfo{$Version}{"info"}}))
3339 { # reverse order
3340 if($LibInfo{$Version}{"info_type"}{$_} eq "function_decl") {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04003341 getSymbolInfo($_);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003342 }
3343 }
3344}
3345
3346sub getVarInfo_All()
3347{
3348 foreach (sort {int($b)<=>int($a)} keys(%{$LibInfo{$Version}{"info"}}))
3349 { # reverse order
3350 if($LibInfo{$Version}{"info_type"}{$_} eq "var_decl") {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04003351 getVarInfo($_);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003352 }
3353 }
3354}
3355
3356sub isBuiltIn($) {
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04003357 return ($_[0] and $_[0]=~/\<built\-in\>|\<internal\>|\A\./);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003358}
3359
3360sub getVarInfo($)
3361{
3362 my $InfoId = $_[0];
Andrey Ponomarenko01117f12012-06-26 12:23:02 +04003363 if(my $NSid = getTreeAttr_Scpe($InfoId))
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04003364 {
3365 my $NSInfoType = $LibInfo{$Version}{"info_type"}{$NSid};
3366 if($NSInfoType and $NSInfoType eq "function_decl") {
3367 return;
3368 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003369 }
3370 ($SymbolInfo{$Version}{$InfoId}{"Header"}, $SymbolInfo{$Version}{$InfoId}{"Line"}) = getLocation($InfoId);
3371 if(not $SymbolInfo{$Version}{$InfoId}{"Header"}
3372 or isBuiltIn($SymbolInfo{$Version}{$InfoId}{"Header"})) {
3373 delete($SymbolInfo{$Version}{$InfoId});
3374 return;
3375 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04003376 my $ShortName = getTreeStr(getTreeAttr_Name($InfoId));
Andrey Ponomarenko85043792012-05-14 16:48:07 +04003377 if(not $ShortName) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003378 delete($SymbolInfo{$Version}{$InfoId});
3379 return;
3380 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +04003381 if($ShortName=~/\Atmp_add_class_\d+\Z/) {
3382 delete($SymbolInfo{$Version}{$InfoId});
3383 return;
3384 }
3385 $SymbolInfo{$Version}{$InfoId}{"ShortName"} = $ShortName;
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +04003386 if(my $MnglName = getTreeStr(getTreeAttr_Mngl($InfoId)))
3387 {
3388 if($OSgroup eq "windows")
3389 { # cut the offset
3390 $MnglName=~s/\@\d+\Z//g;
3391 }
3392 $SymbolInfo{$Version}{$InfoId}{"MnglName"} = $MnglName;
3393 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003394 if($SymbolInfo{$Version}{$InfoId}{"MnglName"}
Andrey Ponomarenko9927e332012-10-19 10:50:48 +04003395 and index($SymbolInfo{$Version}{$InfoId}{"MnglName"}, "_Z")!=0)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003396 { # validate mangled name
3397 delete($SymbolInfo{$Version}{$InfoId});
3398 return;
3399 }
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04003400 if(not $SymbolInfo{$Version}{$InfoId}{"MnglName"}
Andrey Ponomarenko9927e332012-10-19 10:50:48 +04003401 and index($ShortName, "_Z")==0)
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04003402 { # _ZTS, etc.
Andrey Ponomarenko85043792012-05-14 16:48:07 +04003403 $SymbolInfo{$Version}{$InfoId}{"MnglName"} = $ShortName;
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04003404 }
3405 if(isPrivateData($SymbolInfo{$Version}{$InfoId}{"MnglName"}))
3406 { # non-public global data
3407 delete($SymbolInfo{$Version}{$InfoId});
3408 return;
3409 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003410 $SymbolInfo{$Version}{$InfoId}{"Data"} = 1;
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04003411 if(my $Rid = getTypeId($InfoId))
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04003412 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04003413 if(not $TypeInfo{$Version}{$Rid}{"Name"})
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04003414 { # typename_type
3415 delete($SymbolInfo{$Version}{$InfoId});
3416 return;
3417 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04003418 $SymbolInfo{$Version}{$InfoId}{"Return"} = $Rid;
3419 my $Val = getDataVal($InfoId, $Rid);
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04003420 if(defined $Val) {
3421 $SymbolInfo{$Version}{$InfoId}{"Value"} = $Val;
3422 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003423 }
3424 set_Class_And_Namespace($InfoId);
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04003425 if(my $ClassId = $SymbolInfo{$Version}{$InfoId}{"Class"})
3426 {
3427 if(not $TypeInfo{$Version}{$ClassId}{"Name"})
3428 { # templates
3429 delete($SymbolInfo{$Version}{$InfoId});
3430 return;
3431 }
3432 }
Andrey Ponomarenko35c44fd2012-06-18 17:50:25 +04003433 if($LibInfo{$Version}{"info"}{$InfoId}=~/ lang:[ ]*C /i)
3434 { # extern "C"
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003435 $SymbolInfo{$Version}{$InfoId}{"Lang"} = "C";
Andrey Ponomarenko35c44fd2012-06-18 17:50:25 +04003436 $SymbolInfo{$Version}{$InfoId}{"MnglName"} = $ShortName;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003437 }
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04003438 if($UserLang and $UserLang eq "C")
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003439 { # --lang=C option
Andrey Ponomarenko85043792012-05-14 16:48:07 +04003440 $SymbolInfo{$Version}{$InfoId}{"MnglName"} = $ShortName;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003441 }
Andrey Ponomarenko5c09ef32012-06-14 18:17:33 +04003442 if(not $CheckHeadersOnly)
3443 {
3444 if(not $SymbolInfo{$Version}{$InfoId}{"Class"})
3445 {
3446 if(not $SymbolInfo{$Version}{$InfoId}{"MnglName"}
3447 or not link_symbol($SymbolInfo{$Version}{$InfoId}{"MnglName"}, $Version, "-Deps"))
3448 {
3449 if(link_symbol($ShortName, $Version, "-Deps"))
3450 { # "const" global data is mangled as _ZL... in the TU dump
3451 # but not mangled when compiling a C shared library
3452 $SymbolInfo{$Version}{$InfoId}{"MnglName"} = $ShortName;
3453 }
3454 }
3455 }
3456 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003457 if($COMMON_LANGUAGE{$Version} eq "C++")
3458 {
3459 if(not $SymbolInfo{$Version}{$InfoId}{"MnglName"})
3460 { # for some symbols (_ZTI) the short name is the mangled name
Andrey Ponomarenko9927e332012-10-19 10:50:48 +04003461 if(index($ShortName, "_Z")==0) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003462 $SymbolInfo{$Version}{$InfoId}{"MnglName"} = $ShortName;
3463 }
3464 }
3465 if(not $SymbolInfo{$Version}{$InfoId}{"MnglName"})
3466 { # try to mangle symbol (link with libraries)
3467 $SymbolInfo{$Version}{$InfoId}{"MnglName"} = linkSymbol($InfoId);
3468 }
3469 if($OStarget eq "windows")
3470 {
3471 if(my $Mangled = $mangled_name{$Version}{modelUnmangled($InfoId, "MSVC")})
3472 { # link MS C++ symbols from library with GCC symbols from headers
3473 $SymbolInfo{$Version}{$InfoId}{"MnglName"} = $Mangled;
3474 }
3475 }
3476 }
3477 if(not $SymbolInfo{$Version}{$InfoId}{"MnglName"}) {
3478 $SymbolInfo{$Version}{$InfoId}{"MnglName"} = $ShortName;
3479 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +04003480 if(my $Symbol = $SymbolInfo{$Version}{$InfoId}{"MnglName"})
3481 {
3482 if(not selectSymbol($Symbol, $SymbolInfo{$Version}{$InfoId}, "Dump", $Version))
3483 { # non-target symbols
3484 delete($SymbolInfo{$Version}{$InfoId});
3485 return;
3486 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003487 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04003488 if(my $Rid = $SymbolInfo{$Version}{$InfoId}{"Return"})
3489 {
3490 if(defined $MissedTypedef{$Version}{$Rid})
3491 {
3492 if(my $AddedTid = $MissedTypedef{$Version}{$Rid}{"Tid"}) {
3493 $SymbolInfo{$Version}{$InfoId}{"Return"} = $AddedTid;
3494 }
3495 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003496 }
3497 setFuncAccess($InfoId);
Andrey Ponomarenko9927e332012-10-19 10:50:48 +04003498 if(index($SymbolInfo{$Version}{$InfoId}{"MnglName"}, "_ZTV")==0) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003499 delete($SymbolInfo{$Version}{$InfoId}{"Return"});
3500 }
3501 if($ShortName=~/\A(_Z|\?)/) {
3502 delete($SymbolInfo{$Version}{$InfoId}{"ShortName"});
3503 }
3504}
3505
Andrey Ponomarenko85043792012-05-14 16:48:07 +04003506sub isConstType($$)
3507{
3508 my ($TypeId, $LibVersion) = @_;
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04003509 my %Base = get_Type($TypeId, $LibVersion);
Andrey Ponomarenko85043792012-05-14 16:48:07 +04003510 while(defined $Base{"Type"} and $Base{"Type"} eq "Typedef") {
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +04003511 %Base = get_OneStep_BaseType($Base{"Tid"}, $TypeInfo{$LibVersion});
Andrey Ponomarenko85043792012-05-14 16:48:07 +04003512 }
3513 return ($Base{"Type"} eq "Const");
3514}
3515
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003516sub getTrivialName($$)
3517{
3518 my ($TypeInfoId, $TypeId) = @_;
3519 my %TypeAttr = ();
3520 $TypeAttr{"Name"} = getNameByInfo($TypeInfoId);
3521 if(not $TypeAttr{"Name"}) {
3522 $TypeAttr{"Name"} = getTreeTypeName($TypeId);
3523 }
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04003524 ($TypeAttr{"Header"}, $TypeAttr{"Line"}) = getLocation($TypeInfoId);
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04003525 $TypeAttr{"Type"} = getTypeType($TypeId);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003526 $TypeAttr{"Name"}=~s/<(.+)\Z//g; # GCC 3.4.4 add template params to the name
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04003527 if(isAnon($TypeAttr{"Name"}))
3528 {
3529 my $NameSpaceId = $TypeId;
Andrey Ponomarenko01117f12012-06-26 12:23:02 +04003530 while(my $NSId = getTreeAttr_Scpe(getTypeDeclId($NameSpaceId)))
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04003531 { # searching for a first not anon scope
3532 if($NSId eq $NameSpaceId) {
3533 last;
3534 }
3535 else
3536 {
3537 $TypeAttr{"NameSpace"} = getNameSpace(getTypeDeclId($TypeId));
3538 if(not $TypeAttr{"NameSpace"}
3539 or isNotAnon($TypeAttr{"NameSpace"})) {
3540 last;
3541 }
3542 }
3543 $NameSpaceId=$NSId;
3544 }
3545 }
3546 else
3547 {
Andrey Ponomarenko01117f12012-06-26 12:23:02 +04003548 if(my $NameSpaceId = getTreeAttr_Scpe($TypeInfoId))
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04003549 {
3550 if($NameSpaceId ne $TypeId) {
3551 $TypeAttr{"NameSpace"} = getNameSpace($TypeInfoId);
3552 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003553 }
3554 }
3555 if($TypeAttr{"NameSpace"} and isNotAnon($TypeAttr{"Name"})) {
3556 $TypeAttr{"Name"} = $TypeAttr{"NameSpace"}."::".$TypeAttr{"Name"};
3557 }
Andrey Ponomarenko9927e332012-10-19 10:50:48 +04003558 $TypeAttr{"Name"} = formatName($TypeAttr{"Name"}, "T");
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003559 if(isAnon($TypeAttr{"Name"}))
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04003560 { # anon-struct-header.h-line
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04003561 $TypeAttr{"Name"} = "anon-".lc($TypeAttr{"Type"})."-";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003562 $TypeAttr{"Name"} .= $TypeAttr{"Header"}."-".$TypeAttr{"Line"};
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04003563 if($TypeAttr{"NameSpace"}) {
3564 $TypeAttr{"Name"} = $TypeAttr{"NameSpace"}."::".$TypeAttr{"Name"};
3565 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003566 }
Andrey Ponomarenkob8d203d2012-05-25 18:11:07 +04003567 if(defined $TemplateInstance{$Version}{"Type"}{$TypeId}
3568 and getTypeDeclId($TypeId) eq $TypeInfoId)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003569 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04003570 my @TParams = getTParams($TypeId, "Type");
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003571 if(not @TParams)
3572 { # template declarations with abstract params
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003573 return ("", "");
3574 }
Andrey Ponomarenko9927e332012-10-19 10:50:48 +04003575 $TypeAttr{"Name"} = formatName($TypeAttr{"Name"}."< ".join(", ", @TParams)." >", "T");
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003576 }
3577 return ($TypeAttr{"Name"}, $TypeAttr{"NameSpace"});
3578}
3579
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04003580sub getTrivialTypeAttr($)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003581{
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04003582 my $TypeId = $_[0];
3583 my $TypeInfoId = getTypeDeclId($_[0]);
Andrey Ponomarenko85043792012-05-14 16:48:07 +04003584
3585 if($TemplateDecl{$Version}{$TypeId})
3586 { # template_decl
3587 return ();
3588 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04003589 if(my $ScopeId = getTreeAttr_Scpe($TypeInfoId))
3590 {
3591 if($TemplateDecl{$Version}{$ScopeId})
3592 { # template_decl
3593 return ();
3594 }
3595 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +04003596
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003597 my %TypeAttr = ();
3598 if(getTypeTypeByTypeId($TypeId)!~/\A(Intrinsic|Union|Struct|Enum|Class)\Z/) {
3599 return ();
3600 }
3601 setTypeAccess($TypeId, \%TypeAttr);
3602 ($TypeAttr{"Header"}, $TypeAttr{"Line"}) = getLocation($TypeInfoId);
3603 if(isBuiltIn($TypeAttr{"Header"}))
3604 {
3605 delete($TypeAttr{"Header"});
3606 delete($TypeAttr{"Line"});
3607 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04003608 $TypeAttr{"Type"} = getTypeType($TypeId);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003609 ($TypeAttr{"Name"}, $TypeAttr{"NameSpace"}) = getTrivialName($TypeInfoId, $TypeId);
3610 if(not $TypeAttr{"Name"}) {
3611 return ();
3612 }
3613 if(not $TypeAttr{"NameSpace"}) {
3614 delete($TypeAttr{"NameSpace"});
3615 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04003616 if(defined $TemplateInstance{$Version}{"Type"}{$TypeId})
Andrey Ponomarenko16934472012-03-29 15:37:04 +04003617 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04003618 if(my @TParams = getTParams($TypeId, "Type"))
Andrey Ponomarenko16934472012-03-29 15:37:04 +04003619 {
3620 foreach my $Pos (0 .. $#TParams) {
3621 $TypeAttr{"TParam"}{$Pos}{"name"}=$TParams[$Pos];
3622 }
3623 }
3624 }
Andrey Ponomarenko01117f12012-06-26 12:23:02 +04003625 if(my $Size = getSize($TypeId))
3626 {
3627 $Size = $Size/$BYTE_SIZE;
3628 $TypeAttr{"Size"} = "$Size";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003629 }
Andrey Ponomarenko9927e332012-10-19 10:50:48 +04003630 else
3631 { # declaration only
3632 $TypeAttr{"Forward"} = 1;
3633 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003634 if($TypeAttr{"Type"} eq "Struct"
3635 and detect_lang($TypeId))
3636 {
3637 $TypeAttr{"Type"} = "Class";
Andrey Ponomarenko85043792012-05-14 16:48:07 +04003638 $TypeAttr{"Copied"} = 1; # default, will be changed in getSymbolInfo()
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003639 }
3640 if($TypeAttr{"Type"} eq "Struct"
Andrey Ponomarenko85043792012-05-14 16:48:07 +04003641 or $TypeAttr{"Type"} eq "Class")
3642 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04003643 my $Skip = setBaseClasses($TypeId, \%TypeAttr);
Andrey Ponomarenko85043792012-05-14 16:48:07 +04003644 if($Skip) {
3645 return ();
3646 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003647 }
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +04003648 if(my $Algn = getAlgn($TypeId)) {
3649 $TypeAttr{"Algn"} = $Algn/$BYTE_SIZE;
3650 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003651 setSpec($TypeId, \%TypeAttr);
3652 setTypeMemb($TypeId, \%TypeAttr);
3653 $TypeAttr{"Tid"} = $TypeId;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003654 if(my $VTable = $ClassVTable_Content{$Version}{$TypeAttr{"Name"}})
3655 {
3656 my @Entries = split(/\n/, $VTable);
3657 foreach (1 .. $#Entries)
3658 {
3659 my $Entry = $Entries[$_];
3660 if($Entry=~/\A(\d+)\s+(.+)\Z/) {
3661 $TypeAttr{"VTable"}{$1} = $2;
3662 }
3663 }
3664 }
3665 return %TypeAttr;
3666}
3667
3668sub detect_lang($)
3669{
3670 my $TypeId = $_[0];
3671 my $Info = $LibInfo{$Version}{"info"}{$TypeId};
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04003672 if(check_gcc($GCC_PATH, "4"))
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04003673 { # GCC 4 fncs-node points to only non-artificial methods
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003674 return ($Info=~/(fncs)[ ]*:[ ]*@(\d+) /);
3675 }
3676 else
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04003677 { # GCC 3
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04003678 my $Fncs = getTreeAttr_Fncs($TypeId);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003679 while($Fncs)
3680 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04003681 if($LibInfo{$Version}{"info"}{$Fncs}!~/artificial/) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003682 return 1;
3683 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04003684 $Fncs = getTreeAttr_Chan($Fncs);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003685 }
3686 }
3687 return 0;
3688}
3689
3690sub setSpec($$)
3691{
3692 my ($TypeId, $TypeAttr) = @_;
3693 my $Info = $LibInfo{$Version}{"info"}{$TypeId};
3694 if($Info=~/\s+spec\s+/) {
3695 $TypeAttr->{"Spec"} = 1;
3696 }
3697}
3698
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04003699sub setBaseClasses($$)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003700{
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04003701 my ($TypeId, $TypeAttr) = @_;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003702 my $Info = $LibInfo{$Version}{"info"}{$TypeId};
3703 if($Info=~/binf[ ]*:[ ]*@(\d+) /)
3704 {
3705 $Info = $LibInfo{$Version}{"info"}{$1};
3706 my $Pos = 0;
3707 while($Info=~s/(pub|public|prot|protected|priv|private|)[ ]+binf[ ]*:[ ]*@(\d+) //)
3708 {
3709 my ($Access, $BInfoId) = ($1, $2);
3710 my $ClassId = getBinfClassId($BInfoId);
Andrey Ponomarenko85043792012-05-14 16:48:07 +04003711 my $CType = $LibInfo{$Version}{"info_type"}{$ClassId};
3712 if(not $CType or $CType eq "template_type_parm"
3713 or $CType eq "typename_type")
3714 { # skip
3715 return 1;
3716 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003717 my $BaseInfo = $LibInfo{$Version}{"info"}{$BInfoId};
3718 if($Access=~/prot/)
3719 {
3720 $TypeAttr->{"Base"}{$ClassId}{"access"} = "protected";
3721 }
3722 elsif($Access=~/priv/)
3723 {
3724 $TypeAttr->{"Base"}{$ClassId}{"access"} = "private";
3725 }
Andrey Ponomarenko01117f12012-06-26 12:23:02 +04003726 $TypeAttr->{"Base"}{$ClassId}{"pos"} = "$Pos";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003727 if($BaseInfo=~/virt/)
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04003728 { # virtual base
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003729 $TypeAttr->{"Base"}{$ClassId}{"virtual"} = 1;
3730 }
3731 $Class_SubClasses{$Version}{$ClassId}{$TypeId}=1;
Andrey Ponomarenko01117f12012-06-26 12:23:02 +04003732 $Pos+=1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003733 }
3734 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +04003735 return 0;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003736}
3737
3738sub getBinfClassId($)
3739{
3740 my $Info = $LibInfo{$Version}{"info"}{$_[0]};
3741 $Info=~/type[ ]*:[ ]*@(\d+) /;
3742 return $1;
3743}
3744
3745sub unmangledFormat($$)
3746{
3747 my ($Name, $LibVersion) = @_;
3748 $Name = uncover_typedefs($Name, $LibVersion);
3749 while($Name=~s/([^\w>*])(const|volatile)(,|>|\Z)/$1$3/g){};
3750 $Name=~s/\(\w+\)(\d)/$1/;
3751 return $Name;
3752}
3753
3754sub modelUnmangled($$)
3755{
3756 my ($InfoId, $Compiler) = @_;
3757 if($Cache{"modelUnmangled"}{$Version}{$Compiler}{$InfoId}) {
3758 return $Cache{"modelUnmangled"}{$Version}{$Compiler}{$InfoId};
3759 }
3760 my $PureSignature = $SymbolInfo{$Version}{$InfoId}{"ShortName"};
3761 if($SymbolInfo{$Version}{$InfoId}{"Destructor"}) {
3762 $PureSignature = "~".$PureSignature;
3763 }
3764 if(not $SymbolInfo{$Version}{$InfoId}{"Data"})
3765 {
3766 my (@Params, @ParamTypes) = ();
3767 if(defined $SymbolInfo{$Version}{$InfoId}{"Param"}
3768 and not $SymbolInfo{$Version}{$InfoId}{"Destructor"}) {
3769 @Params = keys(%{$SymbolInfo{$Version}{$InfoId}{"Param"}});
3770 }
3771 foreach my $ParamPos (sort {int($a) <=> int($b)} @Params)
3772 { # checking parameters
3773 my $PId = $SymbolInfo{$Version}{$InfoId}{"Param"}{$ParamPos}{"type"};
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +04003774 my %PType = get_PureType($PId, $TypeInfo{$Version});
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003775 my $PTName = unmangledFormat($PType{"Name"}, $Version);
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04003776 $PTName=~s/\b(restrict|register)\b//g;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003777 if($Compiler eq "MSVC") {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04003778 $PTName=~s/\blong long\b/__int64/;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003779 }
3780 @ParamTypes = (@ParamTypes, $PTName);
3781 }
3782 if(@ParamTypes) {
3783 $PureSignature .= "(".join(", ", @ParamTypes).")";
3784 }
3785 else
3786 {
3787 if($Compiler eq "MSVC")
3788 {
3789 $PureSignature .= "(void)";
3790 }
3791 else
3792 { # GCC
3793 $PureSignature .= "()";
3794 }
3795 }
3796 $PureSignature = delete_keywords($PureSignature);
3797 }
3798 if(my $ClassId = $SymbolInfo{$Version}{$InfoId}{"Class"})
3799 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04003800 my $ClassName = unmangledFormat($TypeInfo{$Version}{$ClassId}{"Name"}, $Version);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003801 $PureSignature = $ClassName."::".$PureSignature;
3802 }
3803 elsif(my $NS = $SymbolInfo{$Version}{$InfoId}{"NameSpace"}) {
3804 $PureSignature = $NS."::".$PureSignature;
3805 }
3806 if($SymbolInfo{$Version}{$InfoId}{"Const"}) {
3807 $PureSignature .= " const";
3808 }
3809 if($SymbolInfo{$Version}{$InfoId}{"Volatile"}) {
3810 $PureSignature .= " volatile";
3811 }
3812 my $ShowReturn = 0;
3813 if($Compiler eq "MSVC"
3814 and $SymbolInfo{$Version}{$InfoId}{"Data"})
3815 {
3816 $ShowReturn=1;
3817 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04003818 elsif(defined $TemplateInstance{$Version}{"Func"}{$InfoId}
3819 and keys(%{$TemplateInstance{$Version}{"Func"}{$InfoId}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003820 {
3821 $ShowReturn=1;
3822 }
3823 if($ShowReturn)
3824 { # mangled names for template function specializations include return value
3825 if(my $ReturnId = $SymbolInfo{$Version}{$InfoId}{"Return"})
3826 {
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +04003827 my %RType = get_PureType($ReturnId, $TypeInfo{$Version});
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003828 my $ReturnName = unmangledFormat($RType{"Name"}, $Version);
3829 $PureSignature = $ReturnName." ".$PureSignature;
3830 }
3831 }
Andrey Ponomarenko9927e332012-10-19 10:50:48 +04003832 return ($Cache{"modelUnmangled"}{$Version}{$Compiler}{$InfoId} = formatName($PureSignature, "S"));
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003833}
3834
3835sub mangle_symbol($$$)
3836{ # mangling for simple methods
3837 # see gcc-4.6.0/gcc/cp/mangle.c
3838 my ($InfoId, $LibVersion, $Compiler) = @_;
3839 if($Cache{"mangle_symbol"}{$LibVersion}{$InfoId}{$Compiler}) {
3840 return $Cache{"mangle_symbol"}{$LibVersion}{$InfoId}{$Compiler};
3841 }
3842 my $Mangled = "";
3843 if($Compiler eq "GCC") {
Andrey Ponomarenko16934472012-03-29 15:37:04 +04003844 $Mangled = mangle_symbol_GCC($InfoId, $LibVersion);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003845 }
3846 elsif($Compiler eq "MSVC") {
Andrey Ponomarenko16934472012-03-29 15:37:04 +04003847 $Mangled = mangle_symbol_MSVC($InfoId, $LibVersion);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003848 }
3849 return ($Cache{"mangle_symbol"}{$LibVersion}{$InfoId}{$Compiler} = $Mangled);
3850}
3851
Andrey Ponomarenko16934472012-03-29 15:37:04 +04003852sub mangle_symbol_MSVC($$)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003853{
3854 my ($InfoId, $LibVersion) = @_;
3855 return "";
3856}
3857
Andrey Ponomarenko16934472012-03-29 15:37:04 +04003858sub mangle_symbol_GCC($$)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003859{ # see gcc-4.6.0/gcc/cp/mangle.c
3860 my ($InfoId, $LibVersion) = @_;
3861 my ($Mangled, $ClassId, $NameSpace) = ("_Z", 0, "");
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04003862 my $Return = $SymbolInfo{$LibVersion}{$InfoId}{"Return"};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003863 my %Repl = ();# SN_ replacements
3864 if($ClassId = $SymbolInfo{$LibVersion}{$InfoId}{"Class"})
3865 {
3866 my $MangledClass = mangle_param($ClassId, $LibVersion, \%Repl);
3867 if($MangledClass!~/\AN/) {
3868 $MangledClass = "N".$MangledClass;
3869 }
3870 else {
3871 $MangledClass=~s/E\Z//;
3872 }
3873 if($SymbolInfo{$LibVersion}{$InfoId}{"Volatile"}) {
3874 $MangledClass=~s/\AN/NV/;
3875 }
3876 if($SymbolInfo{$LibVersion}{$InfoId}{"Const"}) {
3877 $MangledClass=~s/\AN/NK/;
3878 }
3879 $Mangled .= $MangledClass;
3880 }
3881 elsif($NameSpace = $SymbolInfo{$LibVersion}{$InfoId}{"NameSpace"})
3882 { # mangled by name due to the absence of structured info
3883 my $MangledNS = mangle_ns($NameSpace, $LibVersion, \%Repl);
3884 if($MangledNS!~/\AN/) {
3885 $MangledNS = "N".$MangledNS;
3886 }
3887 else {
3888 $MangledNS=~s/E\Z//;
3889 }
3890 $Mangled .= $MangledNS;
3891 }
3892 my ($ShortName, $TmplParams) = template_base($SymbolInfo{$LibVersion}{$InfoId}{"ShortName"});
Andrey Ponomarenko16934472012-03-29 15:37:04 +04003893 my @TParams = ();
Andrey Ponomarenko35c44fd2012-06-18 17:50:25 +04003894 if(my @TPos = keys(%{$SymbolInfo{$LibVersion}{$InfoId}{"TParam"}}))
Andrey Ponomarenko16934472012-03-29 15:37:04 +04003895 { # parsing mode
Andrey Ponomarenko35c44fd2012-06-18 17:50:25 +04003896 foreach (@TPos) {
3897 push(@TParams, $SymbolInfo{$LibVersion}{$InfoId}{"TParam"}{$_}{"name"});
3898 }
Andrey Ponomarenko16934472012-03-29 15:37:04 +04003899 }
3900 elsif($TmplParams)
3901 { # remangling mode
3902 # support for old ABI dumps
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003903 @TParams = separate_params($TmplParams, 0);
3904 }
3905 if($SymbolInfo{$LibVersion}{$InfoId}{"Constructor"}) {
3906 $Mangled .= "C1";
3907 }
3908 elsif($SymbolInfo{$LibVersion}{$InfoId}{"Destructor"}) {
3909 $Mangled .= "D0";
3910 }
3911 elsif($ShortName)
3912 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04003913 if($SymbolInfo{$LibVersion}{$InfoId}{"Data"})
3914 {
Andrey Ponomarenko16934472012-03-29 15:37:04 +04003915 if(not $SymbolInfo{$LibVersion}{$InfoId}{"Class"}
Andrey Ponomarenko85043792012-05-14 16:48:07 +04003916 and isConstType($Return, $LibVersion))
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04003917 { # "const" global data is mangled as _ZL...
3918 $Mangled .= "L";
3919 }
3920 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003921 if($ShortName=~/\Aoperator(\W.*)\Z/)
3922 {
3923 my $Op = $1;
3924 $Op=~s/\A[ ]+//g;
3925 if(my $OpMngl = $OperatorMangling{$Op}) {
3926 $Mangled .= $OpMngl;
3927 }
3928 else { # conversion operator
3929 $Mangled .= "cv".mangle_param(getTypeIdByName($Op, $LibVersion), $LibVersion, \%Repl);
3930 }
3931 }
3932 else {
3933 $Mangled .= length($ShortName).$ShortName;
3934 }
3935 if(@TParams)
3936 { # templates
3937 $Mangled .= "I";
3938 foreach my $TParam (@TParams) {
3939 $Mangled .= mangle_template_param($TParam, $LibVersion, \%Repl);
3940 }
3941 $Mangled .= "E";
3942 }
3943 if(not $ClassId and @TParams) {
3944 add_substitution($ShortName, \%Repl, 0);
3945 }
3946 }
3947 if($ClassId or $NameSpace) {
3948 $Mangled .= "E";
3949 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +04003950 if(@TParams)
3951 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04003952 if($Return) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003953 $Mangled .= mangle_param($Return, $LibVersion, \%Repl);
3954 }
3955 }
3956 if(not $SymbolInfo{$LibVersion}{$InfoId}{"Data"})
3957 {
3958 my @Params = ();
3959 if(defined $SymbolInfo{$LibVersion}{$InfoId}{"Param"}
3960 and not $SymbolInfo{$LibVersion}{$InfoId}{"Destructor"}) {
3961 @Params = keys(%{$SymbolInfo{$LibVersion}{$InfoId}{"Param"}});
3962 }
3963 foreach my $ParamPos (sort {int($a) <=> int($b)} @Params)
3964 { # checking parameters
3965 my $ParamType_Id = $SymbolInfo{$LibVersion}{$InfoId}{"Param"}{$ParamPos}{"type"};
3966 $Mangled .= mangle_param($ParamType_Id, $LibVersion, \%Repl);
3967 }
3968 if(not @Params) {
3969 $Mangled .= "v";
3970 }
3971 }
3972 $Mangled = correct_incharge($InfoId, $LibVersion, $Mangled);
3973 $Mangled = write_stdcxx_substitution($Mangled);
3974 if($Mangled eq "_Z") {
3975 return "";
3976 }
3977 return $Mangled;
3978}
3979
3980sub correct_incharge($$$)
3981{
3982 my ($InfoId, $LibVersion, $Mangled) = @_;
3983 if($SymbolInfo{$LibVersion}{$InfoId}{"Constructor"})
3984 {
3985 if($MangledNames{$LibVersion}{$Mangled}) {
3986 $Mangled=~s/C1E/C2E/;
3987 }
3988 }
3989 elsif($SymbolInfo{$LibVersion}{$InfoId}{"Destructor"})
3990 {
3991 if($MangledNames{$LibVersion}{$Mangled}) {
3992 $Mangled=~s/D0E/D1E/;
3993 }
3994 if($MangledNames{$LibVersion}{$Mangled}) {
3995 $Mangled=~s/D1E/D2E/;
3996 }
3997 }
3998 return $Mangled;
3999}
4000
4001sub template_base($)
4002{ # NOTE: std::_Vector_base<mysqlpp::mysql_type_info>::_Vector_impl
Andrey Ponomarenko16934472012-03-29 15:37:04 +04004003 # NOTE: operators: >>, <<
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004004 my $Name = $_[0];
Andrey Ponomarenko16934472012-03-29 15:37:04 +04004005 if($Name!~/>\Z/ or $Name!~/</) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004006 return $Name;
4007 }
4008 my $TParams = $Name;
Andrey Ponomarenko16934472012-03-29 15:37:04 +04004009 while(my $CPos = find_center($TParams, "<"))
4010 { # search for the last <T>
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004011 $TParams = substr($TParams, $CPos);
4012 }
Andrey Ponomarenko16934472012-03-29 15:37:04 +04004013 if($TParams=~s/\A<(.+)>\Z/$1/) {
4014 $Name=~s/<\Q$TParams\E>\Z//;
4015 }
4016 else
4017 { # error
4018 $TParams = "";
4019 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004020 return ($Name, $TParams);
4021}
4022
4023sub get_sub_ns($)
4024{
4025 my $Name = $_[0];
4026 my @NS = ();
Andrey Ponomarenko16934472012-03-29 15:37:04 +04004027 while(my $CPos = find_center($Name, ":"))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004028 {
4029 push(@NS, substr($Name, 0, $CPos));
4030 $Name = substr($Name, $CPos);
4031 $Name=~s/\A:://;
4032 }
4033 return (join("::", @NS), $Name);
4034}
4035
4036sub mangle_ns($$$)
4037{
4038 my ($Name, $LibVersion, $Repl) = @_;
4039 if(my $Tid = $TName_Tid{$LibVersion}{$Name})
4040 {
4041 my $Mangled = mangle_param($Tid, $LibVersion, $Repl);
4042 $Mangled=~s/\AN(.+)E\Z/$1/;
4043 return $Mangled;
4044
4045 }
4046 else
4047 {
4048 my ($MangledNS, $SubNS) = ("", "");
4049 ($SubNS, $Name) = get_sub_ns($Name);
4050 if($SubNS) {
4051 $MangledNS .= mangle_ns($SubNS, $LibVersion, $Repl);
4052 }
4053 $MangledNS .= length($Name).$Name;
4054 add_substitution($MangledNS, $Repl, 0);
4055 return $MangledNS;
4056 }
4057}
4058
4059sub mangle_param($$$)
4060{
4061 my ($PTid, $LibVersion, $Repl) = @_;
4062 my ($MPrefix, $Mangled) = ("", "");
4063 my %ReplCopy = %{$Repl};
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04004064 my %BaseType = get_BaseType($PTid, $LibVersion);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004065 my $BaseType_Name = $BaseType{"Name"};
4066 if(not $BaseType_Name) {
4067 return "";
4068 }
4069 my ($ShortName, $TmplParams) = template_base($BaseType_Name);
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04004070 my $Suffix = get_BaseTypeQual($PTid, $LibVersion);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004071 while($Suffix=~s/\s*(const|volatile|restrict)\Z//g){};
4072 while($Suffix=~/(&|\*|const)\Z/)
4073 {
4074 if($Suffix=~s/[ ]*&\Z//) {
4075 $MPrefix .= "R";
4076 }
4077 if($Suffix=~s/[ ]*\*\Z//) {
4078 $MPrefix .= "P";
4079 }
4080 if($Suffix=~s/[ ]*const\Z//)
4081 {
4082 if($MPrefix=~/R|P/
4083 or $Suffix=~/&|\*/) {
4084 $MPrefix .= "K";
4085 }
4086 }
4087 if($Suffix=~s/[ ]*volatile\Z//) {
4088 $MPrefix .= "V";
4089 }
4090 #if($Suffix=~s/[ ]*restrict\Z//) {
4091 #$MPrefix .= "r";
4092 #}
4093 }
4094 if(my $Token = $IntrinsicMangling{$BaseType_Name}) {
4095 $Mangled .= $Token;
4096 }
4097 elsif($BaseType{"Type"}=~/(Class|Struct|Union|Enum)/)
4098 {
Andrey Ponomarenko16934472012-03-29 15:37:04 +04004099 my @TParams = ();
Andrey Ponomarenko35c44fd2012-06-18 17:50:25 +04004100 if(my @TPos = keys(%{$BaseType{"TParam"}}))
Andrey Ponomarenko16934472012-03-29 15:37:04 +04004101 { # parsing mode
Andrey Ponomarenko35c44fd2012-06-18 17:50:25 +04004102 foreach (@TPos) {
4103 push(@TParams, $BaseType{"TParam"}{$_}{"name"});
4104 }
Andrey Ponomarenko16934472012-03-29 15:37:04 +04004105 }
4106 elsif($TmplParams)
4107 { # remangling mode
4108 # support for old ABI dumps
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004109 @TParams = separate_params($TmplParams, 0);
4110 }
4111 my $MangledNS = "";
4112 my ($SubNS, $SName) = get_sub_ns($ShortName);
4113 if($SubNS) {
4114 $MangledNS .= mangle_ns($SubNS, $LibVersion, $Repl);
4115 }
4116 $MangledNS .= length($SName).$SName;
4117 if(@TParams) {
4118 add_substitution($MangledNS, $Repl, 0);
4119 }
4120 $Mangled .= "N".$MangledNS;
4121 if(@TParams)
4122 { # templates
4123 $Mangled .= "I";
4124 foreach my $TParam (@TParams) {
4125 $Mangled .= mangle_template_param($TParam, $LibVersion, $Repl);
4126 }
4127 $Mangled .= "E";
4128 }
4129 $Mangled .= "E";
4130 }
4131 elsif($BaseType{"Type"}=~/(FuncPtr|MethodPtr)/)
4132 {
4133 if($BaseType{"Type"} eq "MethodPtr") {
4134 $Mangled .= "M".mangle_param($BaseType{"Class"}, $LibVersion, $Repl)."F";
4135 }
4136 else {
4137 $Mangled .= "PF";
4138 }
4139 $Mangled .= mangle_param($BaseType{"Return"}, $LibVersion, $Repl);
4140 my @Params = keys(%{$BaseType{"Param"}});
4141 foreach my $Num (sort {int($a)<=>int($b)} @Params) {
4142 $Mangled .= mangle_param($BaseType{"Param"}{$Num}{"type"}, $LibVersion, $Repl);
4143 }
4144 if(not @Params) {
4145 $Mangled .= "v";
4146 }
4147 $Mangled .= "E";
4148 }
4149 elsif($BaseType{"Type"} eq "FieldPtr")
4150 {
4151 $Mangled .= "M".mangle_param($BaseType{"Class"}, $LibVersion, $Repl);
4152 $Mangled .= mangle_param($BaseType{"Return"}, $LibVersion, $Repl);
4153 }
4154 $Mangled = $MPrefix.$Mangled;# add prefix (RPK)
4155 if(my $Optimized = write_substitution($Mangled, \%ReplCopy))
4156 {
4157 if($Mangled eq $Optimized)
4158 {
4159 if($ShortName!~/::/)
4160 { # remove "N ... E"
4161 if($MPrefix) {
4162 $Mangled=~s/\A($MPrefix)N(.+)E\Z/$1$2/g;
4163 }
4164 else {
4165 $Mangled=~s/\AN(.+)E\Z/$1/g;
4166 }
4167 }
4168 }
4169 else {
4170 $Mangled = $Optimized;
4171 }
4172 }
4173 add_substitution($Mangled, $Repl, 1);
4174 return $Mangled;
4175}
4176
4177sub mangle_template_param($$$)
4178{ # types + literals
4179 my ($TParam, $LibVersion, $Repl) = @_;
4180 if(my $TPTid = $TName_Tid{$LibVersion}{$TParam}) {
4181 return mangle_param($TPTid, $LibVersion, $Repl);
4182 }
4183 elsif($TParam=~/\A(\d+)(\w+)\Z/)
4184 { # class_name<1u>::method(...)
4185 return "L".$IntrinsicMangling{$ConstantSuffixR{$2}}.$1."E";
4186 }
4187 elsif($TParam=~/\A\(([\w ]+)\)(\d+)\Z/)
4188 { # class_name<(signed char)1>::method(...)
4189 return "L".$IntrinsicMangling{$1}.$2."E";
4190 }
4191 elsif($TParam eq "true")
4192 { # class_name<true>::method(...)
4193 return "Lb1E";
4194 }
4195 elsif($TParam eq "false")
4196 { # class_name<true>::method(...)
4197 return "Lb0E";
4198 }
4199 else { # internal error
4200 return length($TParam).$TParam;
4201 }
4202}
4203
4204sub add_substitution($$$)
4205{
4206 my ($Value, $Repl, $Rec) = @_;
4207 if($Rec)
4208 { # subtypes
4209 my @Subs = ($Value);
4210 while($Value=~s/\A(R|P|K)//) {
4211 push(@Subs, $Value);
4212 }
4213 foreach (reverse(@Subs)) {
4214 add_substitution($_, $Repl, 0);
4215 }
4216 return;
4217 }
4218 return if($Value=~/\AS(\d*)_\Z/);
4219 $Value=~s/\AN(.+)E\Z/$1/g;
4220 return if(defined $Repl->{$Value});
4221 return if(length($Value)<=1);
4222 return if($StdcxxMangling{$Value});
4223 # check for duplicates
4224 my $Base = $Value;
4225 foreach my $Type (sort {$Repl->{$a}<=>$Repl->{$b}} sort keys(%{$Repl}))
4226 {
4227 my $Num = $Repl->{$Type};
4228 my $Replace = macro_mangle($Num);
4229 $Base=~s/\Q$Replace\E/$Type/;
4230 }
4231 if(my $OldNum = $Repl->{$Base})
4232 {
4233 $Repl->{$Value} = $OldNum;
4234 return;
4235 }
4236 my @Repls = sort {$b<=>$a} values(%{$Repl});
4237 if(@Repls) {
4238 $Repl->{$Value} = $Repls[0]+1;
4239 }
4240 else {
4241 $Repl->{$Value} = -1;
4242 }
4243 # register duplicates
4244 # upward
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04004245 $Base = $Value;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004246 foreach my $Type (sort {$Repl->{$a}<=>$Repl->{$b}} sort keys(%{$Repl}))
4247 {
4248 next if($Base eq $Type);
4249 my $Num = $Repl->{$Type};
4250 my $Replace = macro_mangle($Num);
4251 $Base=~s/\Q$Type\E/$Replace/;
4252 $Repl->{$Base} = $Repl->{$Value};
4253 }
4254}
4255
4256sub macro_mangle($)
4257{
4258 my $Num = $_[0];
4259 if($Num==-1) {
4260 return "S_";
4261 }
4262 else
4263 {
4264 my $Code = "";
4265 if($Num<10)
4266 { # S0_, S1_, S2_, ...
4267 $Code = $Num;
4268 }
4269 elsif($Num>=10 and $Num<=35)
4270 { # SA_, SB_, SC_, ...
4271 $Code = chr(55+$Num);
4272 }
4273 else
4274 { # S10_, S11_, S12_
4275 $Code = $Num-26; # 26 is length of english alphabet
4276 }
4277 return "S".$Code."_";
4278 }
4279}
4280
4281sub write_stdcxx_substitution($)
4282{
4283 my $Mangled = $_[0];
4284 if($StdcxxMangling{$Mangled}) {
4285 return $StdcxxMangling{$Mangled};
4286 }
4287 else
4288 {
4289 my @Repls = keys(%StdcxxMangling);
4290 @Repls = sort {length($b)<=>length($a)} sort {$b cmp $a} @Repls;
4291 foreach my $MangledType (@Repls)
4292 {
4293 my $Replace = $StdcxxMangling{$MangledType};
4294 #if($Mangled!~/$Replace/) {
4295 $Mangled=~s/N\Q$MangledType\EE/$Replace/g;
4296 $Mangled=~s/\Q$MangledType\E/$Replace/g;
4297 #}
4298 }
4299 }
4300 return $Mangled;
4301}
4302
4303sub write_substitution($$)
4304{
4305 my ($Mangled, $Repl) = @_;
4306 if(defined $Repl->{$Mangled}
4307 and my $MnglNum = $Repl->{$Mangled}) {
4308 $Mangled = macro_mangle($MnglNum);
4309 }
4310 else
4311 {
4312 my @Repls = keys(%{$Repl});
4313 #@Repls = sort {$Repl->{$a}<=>$Repl->{$b}} @Repls;
4314 # FIXME: how to apply replacements? by num or by pos
4315 @Repls = sort {length($b)<=>length($a)} sort {$b cmp $a} @Repls;
4316 foreach my $MangledType (@Repls)
4317 {
4318 my $Replace = macro_mangle($Repl->{$MangledType});
4319 if($Mangled!~/$Replace/) {
4320 $Mangled=~s/N\Q$MangledType\EE/$Replace/g;
4321 $Mangled=~s/\Q$MangledType\E/$Replace/g;
4322 }
4323 }
4324 }
4325 return $Mangled;
4326}
4327
4328sub delete_keywords($)
4329{
4330 my $TypeName = $_[0];
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04004331 $TypeName=~s/\b(enum|struct|union|class) //g;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004332 return $TypeName;
4333}
4334
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004335sub uncover_typedefs($$)
4336{
4337 my ($TypeName, $LibVersion) = @_;
4338 return "" if(not $TypeName);
4339 if(defined $Cache{"uncover_typedefs"}{$LibVersion}{$TypeName}) {
4340 return $Cache{"uncover_typedefs"}{$LibVersion}{$TypeName};
4341 }
Andrey Ponomarenko9927e332012-10-19 10:50:48 +04004342 my ($TypeName_New, $TypeName_Pre) = (formatName($TypeName, "T"), "");
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004343 while($TypeName_New ne $TypeName_Pre)
4344 {
4345 $TypeName_Pre = $TypeName_New;
4346 my $TypeName_Copy = $TypeName_New;
4347 my %Words = ();
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04004348 while($TypeName_Copy=~s/\b([a-z_]([\w:]*\w|))\b//io)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004349 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04004350 if(not $Intrinsic_Keywords{$1}) {
4351 $Words{$1} = 1;
4352 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004353 }
4354 foreach my $Word (keys(%Words))
4355 {
4356 my $BaseType_Name = $Typedef_BaseName{$LibVersion}{$Word};
4357 next if(not $BaseType_Name);
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04004358 next if($TypeName_New=~/\b(struct|union|enum)\s\Q$Word\E\b/);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004359 if($BaseType_Name=~/\([\*]+\)/)
4360 { # FuncPtr
4361 if($TypeName_New=~/\Q$Word\E(.*)\Z/)
4362 {
4363 my $Type_Suffix = $1;
4364 $TypeName_New = $BaseType_Name;
4365 if($TypeName_New=~s/\(([\*]+)\)/($1 $Type_Suffix)/) {
Andrey Ponomarenko9927e332012-10-19 10:50:48 +04004366 $TypeName_New = formatName($TypeName_New, "T");
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004367 }
4368 }
4369 }
4370 else
4371 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04004372 if($TypeName_New=~s/\b\Q$Word\E\b/$BaseType_Name/g) {
Andrey Ponomarenko9927e332012-10-19 10:50:48 +04004373 $TypeName_New = formatName($TypeName_New, "T");
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004374 }
4375 }
4376 }
4377 }
4378 return ($Cache{"uncover_typedefs"}{$LibVersion}{$TypeName} = $TypeName_New);
4379}
4380
4381sub isInternal($)
4382{
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04004383 if($_[0] and my $Info = $LibInfo{$Version}{"info"}{$_[0]})
4384 {
4385 if($Info=~/mngl[ ]*:[ ]*@(\d+) /)
4386 {
4387 if($LibInfo{$Version}{"info"}{$1}=~/\*[ ]*INTERNAL[ ]*\*/)
4388 { # _ZN7mysqlpp8DateTimeC1ERKS0_ *INTERNAL*
4389 return 1;
4390 }
4391 }
4392 }
4393 return 0;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004394}
4395
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04004396sub getDataVal($$)
4397{
4398 my ($InfoId, $TypeId) = @_;
4399 if(my $Info = $LibInfo{$Version}{"info"}{$InfoId})
4400 {
4401 if($Info=~/init[ ]*:[ ]*@(\d+) /)
4402 {
4403 if(defined $LibInfo{$Version}{"info_type"}{$1}
4404 and $LibInfo{$Version}{"info_type"}{$1} eq "nop_expr")
4405 { # char const* data = "str"
4406 # NOTE: disabled
4407 if(my $NopExpr = $LibInfo{$Version}{"info"}{$1})
4408 {
4409 if($NopExpr=~/op 0[ ]*:[ ]*@(\d+) /)
4410 {
4411 if(defined $LibInfo{$Version}{"info_type"}{$1}
4412 and $LibInfo{$Version}{"info_type"}{$1} eq "addr_expr")
4413 {
4414 if(my $AddrExpr = $LibInfo{$Version}{"info"}{$1})
4415 {
4416 if($AddrExpr=~/op 0[ ]*:[ ]*@(\d+) /)
4417 {
4418 return getInitVal($1, $TypeId);
4419 }
4420 }
4421 }
4422 }
4423 }
4424 }
4425 else {
4426 return getInitVal($1, $TypeId);
4427 }
4428 }
4429 }
4430 return undef;
4431}
4432
4433sub getInitVal($$)
4434{
4435 my ($InfoId, $TypeId) = @_;
4436 if(my $Info = $LibInfo{$Version}{"info"}{$InfoId})
4437 {
4438 if(my $InfoType = $LibInfo{$Version}{"info_type"}{$InfoId})
4439 {
4440 if($InfoType eq "integer_cst")
4441 {
4442 my $Val = getNodeIntCst($InfoId);
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04004443 if($TypeId and $TypeInfo{$Version}{$TypeId}{"Name"}=~/\Achar(| const)\Z/)
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04004444 { # characters
4445 $Val = chr($Val);
4446 }
4447 return $Val;
4448 }
4449 elsif($InfoType eq "string_cst") {
4450 return getNodeStrCst($InfoId);
4451 }
Andrey Ponomarenko01117f12012-06-26 12:23:02 +04004452 elsif($InfoType eq "var_decl")
4453 {
4454 if(my $Name = getNodeStrCst(getTreeAttr_Mngl($InfoId))) {
4455 return $Name;
4456 }
4457 }
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04004458 }
4459 }
4460 return undef;
4461}
4462
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004463sub set_Class_And_Namespace($)
4464{
4465 my $InfoId = $_[0];
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04004466 if(my $Info = $LibInfo{$Version}{"info"}{$InfoId})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004467 {
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04004468 if($Info=~/scpe[ ]*:[ ]*@(\d+) /)
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04004469 {
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04004470 my $NSInfoId = $1;
4471 if(my $InfoType = $LibInfo{$Version}{"info_type"}{$NSInfoId})
4472 {
4473 if($InfoType eq "namespace_decl") {
4474 $SymbolInfo{$Version}{$InfoId}{"NameSpace"} = getNameSpace($InfoId);
4475 }
4476 elsif($InfoType eq "record_type") {
4477 $SymbolInfo{$Version}{$InfoId}{"Class"} = $NSInfoId;
4478 }
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04004479 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004480 }
4481 }
4482 if($SymbolInfo{$Version}{$InfoId}{"Class"}
4483 or $SymbolInfo{$Version}{$InfoId}{"NameSpace"})
4484 { # identify language
4485 setLanguage($Version, "C++");
4486 }
4487}
4488
4489sub debugType($$)
4490{
4491 my ($Tid, $LibVersion) = @_;
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04004492 my %Type = get_Type($Tid, $LibVersion);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004493 printMsg("INFO", Dumper(\%Type));
4494}
4495
4496sub debugMangling($)
4497{
4498 my $LibVersion = $_[0];
4499 my %Mangled = ();
4500 foreach my $InfoId (keys(%{$SymbolInfo{$LibVersion}}))
4501 {
4502 if(my $Mngl = $SymbolInfo{$LibVersion}{$InfoId}{"MnglName"})
4503 {
4504 if($Mngl=~/\A(_Z|\?)/) {
4505 $Mangled{$Mngl}=$InfoId;
4506 }
4507 }
4508 }
4509 translateSymbols(keys(%Mangled), $LibVersion);
4510 foreach my $Mngl (keys(%Mangled))
4511 {
Andrey Ponomarenko85043792012-05-14 16:48:07 +04004512 my $U1 = modelUnmangled($Mangled{$Mngl}, "GCC");
4513 my $U2 = $tr_name{$Mngl};
4514 if($U1 ne $U2) {
4515 printMsg("INFO", "INCORRECT MANGLING:\n $Mngl\n $U1\n $U2\n");
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004516 }
4517 }
4518}
4519
4520sub linkSymbol($)
4521{ # link symbols from shared libraries
4522 # with the symbols from header files
4523 my $InfoId = $_[0];
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004524 # try to mangle symbol
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04004525 if((not check_gcc($GCC_PATH, "4") and $SymbolInfo{$Version}{$InfoId}{"Class"})
4526 or (check_gcc($GCC_PATH, "4") and not $SymbolInfo{$Version}{$InfoId}{"Class"}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004527 { # 1. GCC 3.x doesn't mangle class methods names in the TU dump (only functions and global data)
4528 # 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 +04004529 if(not $CheckHeadersOnly)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004530 {
4531 if(my $Mangled = $mangled_name_gcc{modelUnmangled($InfoId, "GCC")}) {
4532 return correct_incharge($InfoId, $Version, $Mangled);
4533 }
4534 }
Andrey Ponomarenko16934472012-03-29 15:37:04 +04004535 if($CheckHeadersOnly
4536 or not $BinaryOnly)
4537 { # 1. --headers-only mode
4538 # 2. not mangled src-only symbols
4539 if(my $Mangled = mangle_symbol($InfoId, $Version, "GCC")) {
4540 return $Mangled;
4541 }
4542 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004543 }
4544 return "";
4545}
4546
4547sub setLanguage($$)
4548{
4549 my ($LibVersion, $Lang) = @_;
4550 if(not $UserLang) {
4551 $COMMON_LANGUAGE{$LibVersion} = $Lang;
4552 }
4553}
4554
4555sub getSymbolInfo($)
4556{
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04004557 my $InfoId = $_[0];
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04004558 if(isInternal($InfoId)) {
4559 return;
4560 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04004561 ($SymbolInfo{$Version}{$InfoId}{"Header"}, $SymbolInfo{$Version}{$InfoId}{"Line"}) = getLocation($InfoId);
4562 if(not $SymbolInfo{$Version}{$InfoId}{"Header"}
Andrey Ponomarenkoa01311b2012-06-08 17:20:02 +04004563 or isBuiltIn($SymbolInfo{$Version}{$InfoId}{"Header"}))
4564 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04004565 delete($SymbolInfo{$Version}{$InfoId});
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004566 return;
4567 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04004568 setFuncAccess($InfoId);
4569 setFuncKind($InfoId);
Andrey Ponomarenkoa01311b2012-06-08 17:20:02 +04004570 if($SymbolInfo{$Version}{$InfoId}{"PseudoTemplate"})
4571 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04004572 delete($SymbolInfo{$Version}{$InfoId});
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004573 return;
4574 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04004575 $SymbolInfo{$Version}{$InfoId}{"Type"} = getFuncType($InfoId);
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04004576 if($SymbolInfo{$Version}{$InfoId}{"Return"} = getFuncReturn($InfoId))
4577 {
4578 if(not $TypeInfo{$Version}{$SymbolInfo{$Version}{$InfoId}{"Return"}}{"Name"})
4579 { # templates
4580 delete($SymbolInfo{$Version}{$InfoId});
4581 return;
4582 }
4583 }
4584 if(my $Rid = $SymbolInfo{$Version}{$InfoId}{"Return"})
4585 {
4586 if(defined $MissedTypedef{$Version}{$Rid})
4587 {
4588 if(my $AddedTid = $MissedTypedef{$Version}{$Rid}{"Tid"}) {
4589 $SymbolInfo{$Version}{$InfoId}{"Return"} = $AddedTid;
4590 }
4591 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004592 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04004593 if(not $SymbolInfo{$Version}{$InfoId}{"Return"}) {
4594 delete($SymbolInfo{$Version}{$InfoId}{"Return"});
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004595 }
Andrey Ponomarenkoa01311b2012-06-08 17:20:02 +04004596 my $Orig = getFuncOrig($InfoId);
4597 $SymbolInfo{$Version}{$InfoId}{"ShortName"} = getFuncShortName($Orig);
4598 if($SymbolInfo{$Version}{$InfoId}{"ShortName"}=~/\._/)
4599 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04004600 delete($SymbolInfo{$Version}{$InfoId});
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004601 return;
4602 }
Andrey Ponomarenkoa01311b2012-06-08 17:20:02 +04004603
4604 if(defined $TemplateInstance{$Version}{"Func"}{$Orig})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004605 {
Andrey Ponomarenkoa01311b2012-06-08 17:20:02 +04004606 my @TParams = getTParams($Orig, "Func");
4607 if(not @TParams)
4608 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04004609 delete($SymbolInfo{$Version}{$InfoId});
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004610 return;
4611 }
Andrey Ponomarenko16934472012-03-29 15:37:04 +04004612 foreach my $Pos (0 .. $#TParams) {
4613 $SymbolInfo{$Version}{$InfoId}{"TParam"}{$Pos}{"name"}=$TParams[$Pos];
4614 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004615 my $PrmsInLine = join(", ", @TParams);
Andrey Ponomarenko16934472012-03-29 15:37:04 +04004616 if($SymbolInfo{$Version}{$InfoId}{"ShortName"}=~/\Aoperator\W+\Z/)
4617 { # operator<< <T>, operator>> <T>
4618 $SymbolInfo{$Version}{$InfoId}{"ShortName"} .= " ";
4619 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04004620 $SymbolInfo{$Version}{$InfoId}{"ShortName"} .= "<".$PrmsInLine.">";
Andrey Ponomarenko9927e332012-10-19 10:50:48 +04004621 $SymbolInfo{$Version}{$InfoId}{"ShortName"} = formatName($SymbolInfo{$Version}{$InfoId}{"ShortName"}, "S");
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004622 }
4623 else
4624 { # support for GCC 3.4
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04004625 $SymbolInfo{$Version}{$InfoId}{"ShortName"}=~s/<.+>\Z//;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004626 }
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +04004627 if(my $MnglName = getTreeStr(getTreeAttr_Mngl($InfoId)))
4628 {
4629 if($OSgroup eq "windows")
4630 { # cut the offset
4631 $MnglName=~s/\@\d+\Z//g;
4632 }
4633 $SymbolInfo{$Version}{$InfoId}{"MnglName"} = $MnglName;
4634
4635 # NOTE: mangling of some symbols may change depending on GCC version
4636 # GCC 4.6: _ZN28QExplicitlySharedDataPointerI11QPixmapDataEC2IT_EERKS_IT_E
4637 # GCC 4.7: _ZN28QExplicitlySharedDataPointerI11QPixmapDataEC2ERKS1_
4638 }
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04004639
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04004640 if($SymbolInfo{$Version}{$InfoId}{"MnglName"}
Andrey Ponomarenko9927e332012-10-19 10:50:48 +04004641 and index($SymbolInfo{$Version}{$InfoId}{"MnglName"}, "_Z")!=0)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004642 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04004643 delete($SymbolInfo{$Version}{$InfoId});
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004644 return;
4645 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04004646 if(not $SymbolInfo{$Version}{$InfoId}{"Destructor"})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004647 { # destructors have an empty parameter list
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04004648 my $Skip = setFuncParams($InfoId);
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04004649 if($Skip) {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04004650 delete($SymbolInfo{$Version}{$InfoId});
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004651 return;
4652 }
4653 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04004654 set_Class_And_Namespace($InfoId);
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04004655 if(my $ClassId = $SymbolInfo{$Version}{$InfoId}{"Class"})
4656 {
4657 if(not $TypeInfo{$Version}{$ClassId}{"Name"})
4658 { # templates
4659 delete($SymbolInfo{$Version}{$InfoId});
4660 return;
4661 }
4662 }
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04004663 if(not $CheckHeadersOnly)
4664 {
4665 if($SymbolInfo{$Version}{$InfoId}{"Type"} eq "Function"
4666 and not $SymbolInfo{$Version}{$InfoId}{"Class"}
4667 and link_symbol($SymbolInfo{$Version}{$InfoId}{"ShortName"}, $Version, "-Deps"))
4668 { # functions (C++): not mangled in library, but are mangled in TU dump
4669 if(not $SymbolInfo{$Version}{$InfoId}{"MnglName"}
4670 or not link_symbol($SymbolInfo{$Version}{$InfoId}{"MnglName"}, $Version, "-Deps")) {
4671 $SymbolInfo{$Version}{$InfoId}{"MnglName"} = $SymbolInfo{$Version}{$InfoId}{"ShortName"};
4672 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004673 }
4674 }
Andrey Ponomarenko35c44fd2012-06-18 17:50:25 +04004675 if($LibInfo{$Version}{"info"}{$InfoId}=~/ lang:[ ]*C /i)
4676 { # extern "C"
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04004677 $SymbolInfo{$Version}{$InfoId}{"Lang"} = "C";
Andrey Ponomarenko35c44fd2012-06-18 17:50:25 +04004678 $SymbolInfo{$Version}{$InfoId}{"MnglName"} = $SymbolInfo{$Version}{$InfoId}{"ShortName"};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004679 }
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04004680 if($UserLang and $UserLang eq "C")
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004681 { # --lang=C option
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04004682 $SymbolInfo{$Version}{$InfoId}{"MnglName"} = $SymbolInfo{$Version}{$InfoId}{"ShortName"};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004683 }
4684 if($COMMON_LANGUAGE{$Version} eq "C++")
4685 { # correct mangled & short names
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04004686 # C++ or --headers-only mode
4687 if($SymbolInfo{$Version}{$InfoId}{"ShortName"}=~/\A__(comp|base|deleting)_(c|d)tor\Z/)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004688 { # support for old GCC versions: reconstruct real names for constructors and destructors
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04004689 $SymbolInfo{$Version}{$InfoId}{"ShortName"} = getNameByInfo(getTypeDeclId($SymbolInfo{$Version}{$InfoId}{"Class"}));
4690 $SymbolInfo{$Version}{$InfoId}{"ShortName"}=~s/<.+>\Z//;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004691 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04004692 if(not $SymbolInfo{$Version}{$InfoId}{"MnglName"})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004693 { # try to mangle symbol (link with libraries)
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04004694 if(my $Mangled = linkSymbol($InfoId)) {
4695 $SymbolInfo{$Version}{$InfoId}{"MnglName"} = $Mangled;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004696 }
4697 }
4698 if($OStarget eq "windows")
4699 { # link MS C++ symbols from library with GCC symbols from headers
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04004700 if(my $Mangled1 = $mangled_name{$Version}{modelUnmangled($InfoId, "MSVC")})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004701 { # exported symbols
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04004702 $SymbolInfo{$Version}{$InfoId}{"MnglName"} = $Mangled1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004703 }
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04004704 elsif(my $Mangled2 = mangle_symbol($InfoId, $Version, "MSVC"))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004705 { # pure virtual symbols
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04004706 $SymbolInfo{$Version}{$InfoId}{"MnglName"} = $Mangled2;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004707 }
4708 }
4709 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04004710 if(not $SymbolInfo{$Version}{$InfoId}{"MnglName"})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004711 { # can't detect symbol name
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04004712 delete($SymbolInfo{$Version}{$InfoId});
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004713 return;
4714 }
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04004715 if(not $SymbolInfo{$Version}{$InfoId}{"Constructor"}
Andrey Ponomarenkoa01311b2012-06-08 17:20:02 +04004716 and my $Spec = getVirtSpec($Orig))
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04004717 { # identify virtual and pure virtual functions
4718 # NOTE: constructors cannot be virtual
4719 # NOTE: in GCC 4.7 D1 destructors have no virtual spec
4720 # in the TU dump, so taking it from the original symbol
4721 if(not ($SymbolInfo{$Version}{$InfoId}{"Destructor"}
4722 and $SymbolInfo{$Version}{$InfoId}{"MnglName"}=~/D2E/))
4723 { # NOTE: D2 destructors are not present in a v-table
4724 $SymbolInfo{$Version}{$InfoId}{$Spec} = 1;
4725 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004726 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04004727 if(isInline($InfoId)) {
4728 $SymbolInfo{$Version}{$InfoId}{"InLine"} = 1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004729 }
Andrey Ponomarenkob8d203d2012-05-25 18:11:07 +04004730 if($LibInfo{$Version}{"info"}{$InfoId}=~/ artificial /i) {
4731 $SymbolInfo{$Version}{$InfoId}{"Artificial"} = 1;
4732 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04004733 if($SymbolInfo{$Version}{$InfoId}{"Constructor"}
4734 and my $ClassId = $SymbolInfo{$Version}{$InfoId}{"Class"})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004735 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04004736 if(not $SymbolInfo{$Version}{$InfoId}{"InLine"}
Andrey Ponomarenkob8d203d2012-05-25 18:11:07 +04004737 and not $SymbolInfo{$Version}{$InfoId}{"Artificial"})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004738 { # inline or auto-generated constructor
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04004739 delete($TypeInfo{$Version}{$ClassId}{"Copied"});
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004740 }
4741 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +04004742 if(my $Symbol = $SymbolInfo{$Version}{$InfoId}{"MnglName"})
4743 {
Andrey Ponomarenko35c44fd2012-06-18 17:50:25 +04004744 if(not selectSymbol($Symbol, $SymbolInfo{$Version}{$InfoId}, "Dump", $Version))
4745 { # non-target symbols
4746 delete($SymbolInfo{$Version}{$InfoId});
4747 return;
Andrey Ponomarenko85043792012-05-14 16:48:07 +04004748 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004749 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04004750 if($SymbolInfo{$Version}{$InfoId}{"Type"} eq "Method"
4751 or $SymbolInfo{$Version}{$InfoId}{"Constructor"}
4752 or $SymbolInfo{$Version}{$InfoId}{"Destructor"}
4753 or $SymbolInfo{$Version}{$InfoId}{"Class"})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004754 {
Andrey Ponomarenko9927e332012-10-19 10:50:48 +04004755 if($SymbolInfo{$Version}{$InfoId}{"MnglName"}!~/\A(_Z|\?)/)
4756 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04004757 delete($SymbolInfo{$Version}{$InfoId});
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004758 return;
4759 }
4760 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04004761 if($SymbolInfo{$Version}{$InfoId}{"MnglName"})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004762 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04004763 if($MangledNames{$Version}{$SymbolInfo{$Version}{$InfoId}{"MnglName"}})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004764 { # one instance for one mangled name only
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04004765 delete($SymbolInfo{$Version}{$InfoId});
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004766 return;
4767 }
4768 else {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04004769 $MangledNames{$Version}{$SymbolInfo{$Version}{$InfoId}{"MnglName"}} = 1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004770 }
4771 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04004772 if($SymbolInfo{$Version}{$InfoId}{"Constructor"}
4773 or $SymbolInfo{$Version}{$InfoId}{"Destructor"}) {
4774 delete($SymbolInfo{$Version}{$InfoId}{"Return"});
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004775 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04004776 if($SymbolInfo{$Version}{$InfoId}{"MnglName"}=~/\A(_Z|\?)/
4777 and $SymbolInfo{$Version}{$InfoId}{"Class"})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004778 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04004779 if($SymbolInfo{$Version}{$InfoId}{"Type"} eq "Function")
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004780 { # static methods
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04004781 $SymbolInfo{$Version}{$InfoId}{"Static"} = 1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004782 }
4783 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04004784 if(getFuncLink($InfoId) eq "Static") {
4785 $SymbolInfo{$Version}{$InfoId}{"Static"} = 1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004786 }
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04004787 if($SymbolInfo{$Version}{$InfoId}{"MnglName"}=~/\A(_Z|\?)/)
4788 {
4789 if(my $Unmangled = $tr_name{$SymbolInfo{$Version}{$InfoId}{"MnglName"}})
4790 {
Andrey Ponomarenko9927e332012-10-19 10:50:48 +04004791 if($Unmangled=~/\.\_\d/)
4792 {
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04004793 delete($SymbolInfo{$Version}{$InfoId});
4794 return;
4795 }
4796 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004797 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04004798 delete($SymbolInfo{$Version}{$InfoId}{"Type"});
4799 if($SymbolInfo{$Version}{$InfoId}{"MnglName"}=~/\A_ZN(V|)K/) {
4800 $SymbolInfo{$Version}{$InfoId}{"Const"} = 1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004801 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04004802 if($SymbolInfo{$Version}{$InfoId}{"MnglName"}=~/\A_ZN(K|)V/) {
4803 $SymbolInfo{$Version}{$InfoId}{"Volatile"} = 1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004804 }
4805}
4806
4807sub isInline($)
4808{ # "body: undefined" in the tree
4809 # -fkeep-inline-functions GCC option should be specified
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04004810 if($_[0] and my $Info = $LibInfo{$Version}{"info"}{$_[0]})
4811 {
4812 if($Info=~/ undefined /i) {
4813 return 0;
4814 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004815 }
4816 return 1;
4817}
4818
4819sub getTypeId($)
4820{
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04004821 if($_[0] and my $Info = $LibInfo{$Version}{"info"}{$_[0]})
4822 {
4823 if($Info=~/type[ ]*:[ ]*@(\d+) /) {
4824 return $1;
4825 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004826 }
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04004827 return "";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004828}
4829
4830sub setTypeMemb($$)
4831{
4832 my ($TypeId, $TypeAttr) = @_;
4833 my $TypeType = $TypeAttr->{"Type"};
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04004834 my ($Pos, $UnnamedPos) = (0, 0);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004835 if($TypeType eq "Enum")
4836 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04004837 my $TypeMembInfoId = getTreeAttr_Csts($TypeId);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004838 while($TypeMembInfoId)
4839 {
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04004840 $TypeAttr->{"Memb"}{$Pos}{"value"} = getEnumMembVal($TypeMembInfoId);
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04004841 my $MembName = getTreeStr(getTreeAttr_Purp($TypeMembInfoId));
4842 $TypeAttr->{"Memb"}{$Pos}{"name"} = $MembName;
4843 $EnumMembName_Id{$Version}{getTreeAttr_Valu($TypeMembInfoId)} = ($TypeAttr->{"NameSpace"})?$TypeAttr->{"NameSpace"}."::".$MembName:$MembName;
4844 $TypeMembInfoId = getNextElem($TypeMembInfoId);
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04004845 $Pos += 1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004846 }
4847 }
4848 elsif($TypeType=~/\A(Struct|Class|Union)\Z/)
4849 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04004850 my $TypeMembInfoId = getTreeAttr_Flds($TypeId);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004851 while($TypeMembInfoId)
4852 {
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04004853 my $IType = $LibInfo{$Version}{"info_type"}{$TypeMembInfoId};
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04004854 my $MInfo = $LibInfo{$Version}{"info"}{$TypeMembInfoId};
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04004855 if(not $IType or $IType ne "field_decl")
4856 { # search for fields, skip other stuff in the declaration
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04004857 $TypeMembInfoId = getNextElem($TypeMembInfoId);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004858 next;
4859 }
Andrey Ponomarenko01117f12012-06-26 12:23:02 +04004860 my $StructMembName = getTreeStr(getTreeAttr_Name($TypeMembInfoId));
4861 if(index($StructMembName, "_vptr.")!=-1)
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04004862 { # virtual tables
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04004863 $TypeMembInfoId = getNextElem($TypeMembInfoId);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004864 next;
4865 }
4866 if(not $StructMembName)
4867 { # unnamed fields
Andrey Ponomarenko01117f12012-06-26 12:23:02 +04004868 if(index($TypeAttr->{"Name"}, "_type_info_pseudo")==-1)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004869 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04004870 my $UnnamedTid = getTreeAttr_Type($TypeMembInfoId);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004871 my $UnnamedTName = getNameByInfo(getTypeDeclId($UnnamedTid));
4872 if(isAnon($UnnamedTName))
4873 { # rename unnamed fields to unnamed0, unnamed1, ...
4874 $StructMembName = "unnamed".($UnnamedPos++);
4875 }
4876 }
4877 }
4878 if(not $StructMembName)
4879 { # unnamed fields and base classes
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04004880 $TypeMembInfoId = getNextElem($TypeMembInfoId);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004881 next;
4882 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04004883 my $MembTypeId = getTreeAttr_Type($TypeMembInfoId);
4884 if(defined $MissedTypedef{$Version}{$MembTypeId})
4885 {
4886 if(my $AddedTid = $MissedTypedef{$Version}{$MembTypeId}{"Tid"}) {
4887 $MembTypeId = $AddedTid;
4888 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004889 }
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04004890 $TypeAttr->{"Memb"}{$Pos}{"type"} = $MembTypeId;
4891 $TypeAttr->{"Memb"}{$Pos}{"name"} = $StructMembName;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004892 if((my $Access = getTreeAccess($TypeMembInfoId)) ne "public")
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04004893 { # marked only protected and private, public by default
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04004894 $TypeAttr->{"Memb"}{$Pos}{"access"} = $Access;
4895 }
4896 if($MInfo=~/spec:\s*mutable /)
4897 { # mutable fields
4898 $TypeAttr->{"Memb"}{$Pos}{"mutable"} = 1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004899 }
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +04004900 if(my $Algn = getAlgn($TypeMembInfoId)) {
4901 $TypeAttr->{"Memb"}{$Pos}{"algn"} = $Algn;
4902 }
4903 if(my $BFSize = getBitField($TypeMembInfoId))
4904 { # in bits
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04004905 $TypeAttr->{"Memb"}{$Pos}{"bitfield"} = $BFSize;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004906 }
4907 else
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +04004908 { # in bytes
4909 $TypeAttr->{"Memb"}{$Pos}{"algn"} /= $BYTE_SIZE;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004910 }
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +04004911
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04004912 $TypeMembInfoId = getNextElem($TypeMembInfoId);
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04004913 $Pos += 1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004914 }
4915 }
4916}
4917
4918sub setFuncParams($)
4919{
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04004920 my $InfoId = $_[0];
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04004921 my $ParamInfoId = getTreeAttr_Args($InfoId);
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04004922 if(getFuncType($InfoId) eq "Method")
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004923 { # check type of "this" pointer
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04004924 my $ObjectTypeId = getTreeAttr_Type($ParamInfoId);
4925 if(my $ObjectName = $TypeInfo{$Version}{$ObjectTypeId}{"Name"})
Andrey Ponomarenko85043792012-05-14 16:48:07 +04004926 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04004927 if($ObjectName=~/\bconst(| volatile)\*const\b/) {
Andrey Ponomarenko85043792012-05-14 16:48:07 +04004928 $SymbolInfo{$Version}{$InfoId}{"Const"} = 1;
4929 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04004930 if($ObjectName=~/\bvolatile\b/) {
Andrey Ponomarenko85043792012-05-14 16:48:07 +04004931 $SymbolInfo{$Version}{$InfoId}{"Volatile"} = 1;
4932 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004933 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +04004934 else
4935 { # skip
4936 return 1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004937 }
4938 $ParamInfoId = getNextElem($ParamInfoId);
4939 }
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04004940 my ($Pos, $Vtt_Pos) = (0, -1);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004941 while($ParamInfoId)
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04004942 { # formal args
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04004943 my $ParamTypeId = getTreeAttr_Type($ParamInfoId);
4944 my $ParamName = getTreeStr(getTreeAttr_Name($ParamInfoId));
4945 if(not $ParamName)
4946 { # unnamed
4947 $ParamName = "p".($Pos+1);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004948 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04004949 if(defined $MissedTypedef{$Version}{$ParamTypeId})
4950 {
4951 if(my $AddedTid = $MissedTypedef{$Version}{$ParamTypeId}{"Tid"}) {
4952 $ParamTypeId = $AddedTid;
4953 }
4954 }
4955 my $PType = $TypeInfo{$Version}{$ParamTypeId}{"Type"};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004956 if(not $PType or $PType eq "Unknown") {
4957 return 1;
4958 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04004959 my $PTName = $TypeInfo{$Version}{$ParamTypeId}{"Name"};
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04004960 if(not $PTName) {
4961 return 1;
4962 }
4963 if($PTName eq "void") {
4964 last;
4965 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004966 if($ParamName eq "__vtt_parm"
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04004967 and $TypeInfo{$Version}{$ParamTypeId}{"Name"} eq "void const**")
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004968 {
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04004969 $Vtt_Pos = $Pos;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004970 $ParamInfoId = getNextElem($ParamInfoId);
4971 next;
4972 }
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04004973 $SymbolInfo{$Version}{$InfoId}{"Param"}{$Pos}{"type"} = $ParamTypeId;
4974 $SymbolInfo{$Version}{$InfoId}{"Param"}{$Pos}{"name"} = $ParamName;
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04004975 if(my $Algn = getAlgn($ParamInfoId)) {
4976 $SymbolInfo{$Version}{$InfoId}{"Param"}{$Pos}{"algn"} = $Algn/$BYTE_SIZE;
4977 }
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04004978 if(not $SymbolInfo{$Version}{$InfoId}{"Param"}{$Pos}{"name"}) {
4979 $SymbolInfo{$Version}{$InfoId}{"Param"}{$Pos}{"name"} = "p".($Pos+1);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004980 }
4981 if($LibInfo{$Version}{"info"}{$ParamInfoId}=~/spec:\s*register /)
4982 { # foo(register type arg)
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04004983 $SymbolInfo{$Version}{$InfoId}{"Param"}{$Pos}{"reg"} = 1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004984 }
4985 $ParamInfoId = getNextElem($ParamInfoId);
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04004986 $Pos += 1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004987 }
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04004988 if(setFuncArgs($InfoId, $Vtt_Pos)) {
Andrey Ponomarenko01117f12012-06-26 12:23:02 +04004989 $SymbolInfo{$Version}{$InfoId}{"Param"}{$Pos}{"type"} = "-1";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004990 }
4991 return 0;
4992}
4993
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04004994sub setFuncArgs($$)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004995{
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04004996 my ($InfoId, $Vtt_Pos) = @_;
4997 my $FuncTypeId = getFuncTypeId($InfoId);
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04004998 my $ParamListElemId = getTreeAttr_Prms($FuncTypeId);
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04004999 if(getFuncType($InfoId) eq "Method") {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005000 $ParamListElemId = getNextElem($ParamListElemId);
5001 }
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04005002 if(not $ParamListElemId)
5003 { # foo(...)
5004 return 1;
5005 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005006 my $HaveVoid = 0;
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04005007 my $Pos = 0;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005008 while($ParamListElemId)
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04005009 { # actual params: may differ from formal args
5010 # formal int*const
5011 # actual: int*
5012 if($Vtt_Pos!=-1 and $Pos==$Vtt_Pos)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005013 {
5014 $Vtt_Pos=-1;
5015 $ParamListElemId = getNextElem($ParamListElemId);
5016 next;
5017 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04005018 my $ParamTypeId = getTreeAttr_Valu($ParamListElemId);
5019 if($TypeInfo{$Version}{$ParamTypeId}{"Name"} eq "void")
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04005020 {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005021 $HaveVoid = 1;
5022 last;
5023 }
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04005024 elsif(not defined $SymbolInfo{$Version}{$InfoId}{"Param"}{$Pos}{"type"})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005025 {
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04005026 $SymbolInfo{$Version}{$InfoId}{"Param"}{$Pos}{"type"} = $ParamTypeId;
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04005027 if(not $SymbolInfo{$Version}{$InfoId}{"Param"}{$Pos}{"name"})
5028 { # unnamed
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04005029 $SymbolInfo{$Version}{$InfoId}{"Param"}{$Pos}{"name"} = "p".($Pos+1);
5030 }
5031 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04005032 if(my $PurpId = getTreeAttr_Purp($ParamListElemId))
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04005033 { # default arguments
Andrey Ponomarenko01117f12012-06-26 12:23:02 +04005034 if(my $PurpType = $LibInfo{$Version}{"info_type"}{$PurpId})
5035 {
5036 my $Val = getInitVal($PurpId, $ParamTypeId);
5037 if(defined $Val) {
5038 $SymbolInfo{$Version}{$InfoId}{"Param"}{$Pos}{"default"} = $Val;
5039 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005040 }
5041 }
5042 $ParamListElemId = getNextElem($ParamListElemId);
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04005043 $Pos += 1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005044 }
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04005045 return ($Pos>=1 and not $HaveVoid);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005046}
5047
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04005048sub getTreeAttr_Chan($)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005049{
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04005050 if($_[0] and my $Info = $LibInfo{$Version}{"info"}{$_[0]})
5051 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04005052 if($Info=~/chan[ ]*:[ ]*@(\d+) /) {
5053 return $1;
5054 }
5055 }
5056 return "";
5057}
5058
5059sub getTreeAttr_Chain($)
5060{
5061 if($_[0] and my $Info = $LibInfo{$Version}{"info"}{$_[0]})
5062 {
5063 if($Info=~/chain[ ]*:[ ]*@(\d+) /) {
5064 return $1;
5065 }
5066 }
5067 return "";
5068}
5069
5070sub getTreeAttr_Scpe($)
5071{
5072 if($_[0] and my $Info = $LibInfo{$Version}{"info"}{$_[0]})
5073 {
5074 if($Info=~/scpe[ ]*:[ ]*@(\d+) /) {
5075 return $1;
5076 }
5077 }
5078 return "";
5079}
5080
5081sub getTreeAttr_Type($)
5082{
5083 if($_[0] and my $Info = $LibInfo{$Version}{"info"}{$_[0]})
5084 {
5085 if($Info=~/type[ ]*:[ ]*@(\d+) /) {
5086 return $1;
5087 }
5088 }
5089 return "";
5090}
5091
5092sub getTreeAttr_Name($)
5093{
5094 if($_[0] and my $Info = $LibInfo{$Version}{"info"}{$_[0]})
5095 {
5096 if($Info=~/name[ ]*:[ ]*@(\d+) /) {
5097 return $1;
5098 }
5099 }
5100 return "";
5101}
5102
5103sub getTreeAttr_Mngl($)
5104{
5105 if($_[0] and my $Info = $LibInfo{$Version}{"info"}{$_[0]})
5106 {
5107 if($Info=~/mngl[ ]*:[ ]*@(\d+) /) {
5108 return $1;
5109 }
5110 }
5111 return "";
5112}
5113
5114sub getTreeAttr_Prms($)
5115{
5116 if($_[0] and my $Info = $LibInfo{$Version}{"info"}{$_[0]})
5117 {
5118 if($Info=~/prms[ ]*:[ ]*@(\d+) /) {
5119 return $1;
5120 }
5121 }
5122 return "";
5123}
5124
5125sub getTreeAttr_Fncs($)
5126{
5127 if($_[0] and my $Info = $LibInfo{$Version}{"info"}{$_[0]})
5128 {
5129 if($Info=~/fncs[ ]*:[ ]*@(\d+) /) {
5130 return $1;
5131 }
5132 }
5133 return "";
5134}
5135
5136sub getTreeAttr_Csts($)
5137{
5138 if($_[0] and my $Info = $LibInfo{$Version}{"info"}{$_[0]})
5139 {
5140 if($Info=~/csts[ ]*:[ ]*@(\d+) /) {
5141 return $1;
5142 }
5143 }
5144 return "";
5145}
5146
5147sub getTreeAttr_Purp($)
5148{
5149 if($_[0] and my $Info = $LibInfo{$Version}{"info"}{$_[0]})
5150 {
5151 if($Info=~/purp[ ]*:[ ]*@(\d+) /) {
5152 return $1;
5153 }
5154 }
5155 return "";
5156}
5157
5158sub getTreeAttr_Valu($)
5159{
5160 if($_[0] and my $Info = $LibInfo{$Version}{"info"}{$_[0]})
5161 {
5162 if($Info=~/valu[ ]*:[ ]*@(\d+) /) {
5163 return $1;
5164 }
5165 }
5166 return "";
5167}
5168
5169sub getTreeAttr_Flds($)
5170{
5171 if($_[0] and my $Info = $LibInfo{$Version}{"info"}{$_[0]})
5172 {
5173 if($Info=~/flds[ ]*:[ ]*@(\d+) /) {
5174 return $1;
5175 }
5176 }
5177 return "";
5178}
5179
5180sub getTreeAttr_Args($)
5181{
5182 if($_[0] and my $Info = $LibInfo{$Version}{"info"}{$_[0]})
5183 {
5184 if($Info=~/args[ ]*:[ ]*@(\d+) /) {
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04005185 return $1;
5186 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005187 }
5188 return "";
5189}
5190
5191sub getTreeValue($)
5192{
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04005193 if($_[0] and my $Info = $LibInfo{$Version}{"info"}{$_[0]})
5194 {
5195 if($Info=~/low[ ]*:[ ]*([^ ]+) /) {
5196 return $1;
5197 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005198 }
5199 return "";
5200}
5201
5202sub getTreeAccess($)
5203{
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04005204 if($_[0] and my $Info = $LibInfo{$Version}{"info"}{$_[0]})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005205 {
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04005206 if($Info=~/accs[ ]*:[ ]*([a-zA-Z]+) /)
5207 {
5208 my $Access = $1;
5209 if($Access eq "prot") {
5210 return "protected";
5211 }
5212 elsif($Access eq "priv") {
5213 return "private";
5214 }
5215 }
5216 elsif($Info=~/ protected /)
5217 { # support for old GCC versions
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005218 return "protected";
5219 }
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04005220 elsif($Info=~/ private /)
5221 { # support for old GCC versions
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005222 return "private";
5223 }
5224 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005225 return "public";
5226}
5227
5228sub setFuncAccess($)
5229{
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04005230 my $Access = getTreeAccess($_[0]);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005231 if($Access eq "protected") {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04005232 $SymbolInfo{$Version}{$_[0]}{"Protected"} = 1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005233 }
5234 elsif($Access eq "private") {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04005235 $SymbolInfo{$Version}{$_[0]}{"Private"} = 1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005236 }
5237}
5238
5239sub setTypeAccess($$)
5240{
5241 my ($TypeId, $TypeAttr) = @_;
5242 my $Access = getTreeAccess($TypeId);
5243 if($Access eq "protected") {
5244 $TypeAttr->{"Protected"} = 1;
5245 }
5246 elsif($Access eq "private") {
5247 $TypeAttr->{"Private"} = 1;
5248 }
5249}
5250
5251sub setFuncKind($)
5252{
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04005253 if($_[0] and my $Info = $LibInfo{$Version}{"info"}{$_[0]})
5254 {
5255 if($Info=~/pseudo tmpl/) {
5256 $SymbolInfo{$Version}{$_[0]}{"PseudoTemplate"} = 1;
5257 }
5258 elsif($Info=~/ constructor /) {
5259 $SymbolInfo{$Version}{$_[0]}{"Constructor"} = 1;
5260 }
5261 elsif($Info=~/ destructor /) {
5262 $SymbolInfo{$Version}{$_[0]}{"Destructor"} = 1;
5263 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005264 }
5265}
5266
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04005267sub getVirtSpec($)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005268{
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04005269 if($_[0] and my $Info = $LibInfo{$Version}{"info"}{$_[0]})
5270 {
5271 if($Info=~/spec[ ]*:[ ]*pure /) {
5272 return "PureVirt";
5273 }
5274 elsif($Info=~/spec[ ]*:[ ]*virt /) {
5275 return "Virt";
5276 }
5277 elsif($Info=~/ pure\s+virtual /)
5278 { # support for old GCC versions
5279 return "PureVirt";
5280 }
5281 elsif($Info=~/ virtual /)
5282 { # support for old GCC versions
5283 return "Virt";
5284 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005285 }
5286 return "";
5287}
5288
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005289sub getFuncLink($)
5290{
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04005291 if($_[0] and my $Info = $LibInfo{$Version}{"info"}{$_[0]})
5292 {
5293 if($Info=~/link[ ]*:[ ]*static /) {
5294 return "Static";
5295 }
5296 elsif($Info=~/link[ ]*:[ ]*([a-zA-Z]+) /) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005297 return $1;
5298 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005299 }
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04005300 return "";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005301}
5302
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005303sub get_IntNameSpace($$)
5304{
5305 my ($Interface, $LibVersion) = @_;
5306 return "" if(not $Interface or not $LibVersion);
5307 if(defined $Cache{"get_IntNameSpace"}{$Interface}{$LibVersion}) {
5308 return $Cache{"get_IntNameSpace"}{$Interface}{$LibVersion};
5309 }
5310 my $Signature = get_Signature($Interface, $LibVersion);
5311 if($Signature=~/\:\:/)
5312 {
5313 my $FounNameSpace = 0;
5314 foreach my $NameSpace (sort {get_depth($b)<=>get_depth($a)} keys(%{$NestedNameSpaces{$LibVersion}}))
5315 {
5316 if($Signature=~/(\A|\s+for\s+)\Q$NameSpace\E\:\:/) {
5317 return ($Cache{"get_IntNameSpace"}{$Interface}{$LibVersion} = $NameSpace);
5318 }
5319 }
5320 }
5321 else {
5322 return ($Cache{"get_IntNameSpace"}{$Interface}{$LibVersion} = "");
5323 }
5324}
5325
5326sub parse_TypeNameSpace($$)
5327{
5328 my ($TypeName, $LibVersion) = @_;
5329 return "" if(not $TypeName or not $LibVersion);
5330 if(defined $Cache{"parse_TypeNameSpace"}{$TypeName}{$LibVersion}) {
5331 return $Cache{"parse_TypeNameSpace"}{$TypeName}{$LibVersion};
5332 }
5333 if($TypeName=~/\:\:/)
5334 {
5335 my $FounNameSpace = 0;
5336 foreach my $NameSpace (sort {get_depth($b)<=>get_depth($a)} keys(%{$NestedNameSpaces{$LibVersion}}))
5337 {
5338 if($TypeName=~/\A\Q$NameSpace\E\:\:/) {
5339 return ($Cache{"parse_TypeNameSpace"}{$TypeName}{$LibVersion} = $NameSpace);
5340 }
5341 }
5342 }
5343 else {
5344 return ($Cache{"parse_TypeNameSpace"}{$TypeName}{$LibVersion} = "");
5345 }
5346}
5347
5348sub getNameSpace($)
5349{
5350 my $TypeInfoId = $_[0];
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04005351 if(my $NSInfoId = getTreeAttr_Scpe($TypeInfoId))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005352 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04005353 if(my $InfoType = $LibInfo{$Version}{"info_type"}{$NSInfoId})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005354 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04005355 if($InfoType eq "namespace_decl")
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04005356 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04005357 if($LibInfo{$Version}{"info"}{$NSInfoId}=~/name[ ]*:[ ]*@(\d+) /)
5358 {
5359 my $NameSpace = getTreeStr($1);
5360 if($NameSpace eq "::")
5361 { # global namespace
5362 return "";
5363 }
5364 if(my $BaseNameSpace = getNameSpace($NSInfoId)) {
5365 $NameSpace = $BaseNameSpace."::".$NameSpace;
5366 }
5367 $NestedNameSpaces{$Version}{$NameSpace} = 1;
5368 return $NameSpace;
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04005369 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04005370 else {
5371 return "";
5372 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005373 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04005374 elsif($InfoType eq "record_type")
5375 { # inside data type
5376 my ($Name, $NameNS) = getTrivialName(getTypeDeclId($NSInfoId), $NSInfoId);
5377 return $Name;
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04005378 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005379 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005380 }
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04005381 return "";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005382}
5383
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005384sub getEnumMembVal($)
5385{
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04005386 if($_[0] and my $Info = $LibInfo{$Version}{"info"}{$_[0]})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005387 {
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04005388 if($Info=~/valu[ ]*:[ ]*\@(\d+)/)
5389 {
5390 if(my $VInfo = $LibInfo{$Version}{"info"}{$1})
5391 {
5392 if($VInfo=~/cnst[ ]*:[ ]*\@(\d+)/)
5393 { # in newer versions of GCC the value is in the "const_decl->cnst" node
5394 return getTreeValue($1);
5395 }
5396 else
5397 { # some old versions of GCC (3.3) have the value in the "integer_cst" node
5398 return getTreeValue($1);
5399 }
5400 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005401 }
5402 }
5403 return "";
5404}
5405
5406sub getSize($)
5407{
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04005408 if($_[0] and my $Info = $LibInfo{$Version}{"info"}{$_[0]})
5409 {
5410 if($Info=~/size[ ]*:[ ]*\@(\d+)/) {
5411 return getTreeValue($1);
5412 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005413 }
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04005414 return 0;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005415}
5416
5417sub getAlgn($)
5418{
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04005419 if($_[0] and my $Info = $LibInfo{$Version}{"info"}{$_[0]})
5420 {
5421 if($Info=~/algn[ ]*:[ ]*(\d+) /) {
5422 return $1;
5423 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005424 }
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04005425 return "";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005426}
5427
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +04005428sub getBitField($)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005429{
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04005430 if($_[0] and my $Info = $LibInfo{$Version}{"info"}{$_[0]})
5431 {
5432 if($Info=~/ bitfield /) {
5433 return getSize($_[0]);
5434 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005435 }
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04005436 return 0;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005437}
5438
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04005439sub getNextElem($)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005440{
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04005441 if(my $Chan = getTreeAttr_Chan($_[0])) {
5442 return $Chan;
5443 }
5444 elsif(my $Chain = getTreeAttr_Chain($_[0])) {
5445 return $Chain;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005446 }
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04005447 return "";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005448}
5449
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04005450sub registerHeader($$)
5451{ # input: absolute path of header, relative path or name
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005452 my ($Header, $LibVersion) = @_;
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04005453 if(not $Header) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005454 return "";
5455 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04005456 if(is_abs($Header) and not -f $Header)
5457 { # incorrect absolute path
5458 exitStatus("Access_Error", "can't access \'$Header\'");
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005459 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04005460 if(skipHeader($Header, $LibVersion))
5461 { # skip
5462 return "";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005463 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04005464 if(my $Header_Path = identifyHeader($Header, $LibVersion))
5465 {
5466 detect_header_includes($Header_Path, $LibVersion);
5467
5468 if(my $RHeader_Path = $Header_ErrorRedirect{$LibVersion}{$Header_Path})
5469 { # redirect
5470 if($Registered_Headers{$LibVersion}{$RHeader_Path}{"Identity"}
5471 or skipHeader($RHeader_Path, $LibVersion))
5472 { # skip
5473 return "";
5474 }
5475 $Header_Path = $RHeader_Path;
5476 }
5477 elsif($Header_ShouldNotBeUsed{$LibVersion}{$Header_Path})
5478 { # skip
5479 return "";
5480 }
5481
5482 if(my $HName = get_filename($Header_Path))
5483 { # register
5484 $Registered_Headers{$LibVersion}{$Header_Path}{"Identity"} = $HName;
5485 $HeaderName_Paths{$LibVersion}{$HName}{$Header_Path} = 1;
5486 }
5487
5488 if(($Header=~/\.(\w+)\Z/ and $1 ne "h")
5489 or $Header!~/\.(\w+)\Z/)
5490 { # hpp, hh
5491 setLanguage($LibVersion, "C++");
5492 }
5493
5494 if($CheckHeadersOnly
5495 and $Header=~/(\A|\/)c\+\+(\/|\Z)/)
5496 { # /usr/include/c++/4.6.1/...
5497 $STDCXX_TESTING = 1;
5498 }
5499
5500 return $Header_Path;
5501 }
5502 return "";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005503}
5504
5505sub register_directory($$$)
5506{
5507 my ($Dir, $WithDeps, $LibVersion) = @_;
5508 $Dir=~s/[\/\\]+\Z//g;
5509 return if(not $LibVersion or not $Dir or not -d $Dir);
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04005510 return if(skipHeader($Dir, $LibVersion));
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005511 $Dir = get_abs_path($Dir);
5512 my $Mode = "All";
Andrey Ponomarenko85043792012-05-14 16:48:07 +04005513 if($WithDeps)
5514 {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005515 if($RegisteredDirs{$LibVersion}{$Dir}{1}) {
5516 return;
5517 }
5518 elsif($RegisteredDirs{$LibVersion}{$Dir}{0}) {
5519 $Mode = "DepsOnly";
5520 }
5521 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +04005522 else
5523 {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005524 if($RegisteredDirs{$LibVersion}{$Dir}{1}
5525 or $RegisteredDirs{$LibVersion}{$Dir}{0}) {
5526 return;
5527 }
5528 }
5529 $Header_Dependency{$LibVersion}{$Dir} = 1;
5530 $RegisteredDirs{$LibVersion}{$Dir}{$WithDeps} = 1;
5531 if($Mode eq "DepsOnly")
5532 {
5533 foreach my $Path (cmd_find($Dir,"d","","")) {
5534 $Header_Dependency{$LibVersion}{$Path} = 1;
5535 }
5536 return;
5537 }
5538 foreach my $Path (sort {length($b)<=>length($a)} cmd_find($Dir,"f","",""))
5539 {
5540 if($WithDeps)
5541 {
5542 my $SubDir = $Path;
5543 while(($SubDir = get_dirname($SubDir)) ne $Dir)
5544 { # register all sub directories
5545 $Header_Dependency{$LibVersion}{$SubDir} = 1;
5546 }
5547 }
5548 next if(is_not_header($Path));
5549 next if(ignore_path($Path));
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04005550 next if(skipHeader($Path, $LibVersion));
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005551 # Neighbors
Andrey Ponomarenko9927e332012-10-19 10:50:48 +04005552 foreach my $Part (get_prefixes($Path)) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005553 $Include_Neighbors{$LibVersion}{$Part} = $Path;
5554 }
5555 }
5556 if(get_filename($Dir) eq "include")
5557 { # search for "lib/include/" directory
5558 my $LibDir = $Dir;
5559 if($LibDir=~s/([\/\\])include\Z/$1lib/g and -d $LibDir) {
5560 register_directory($LibDir, $WithDeps, $LibVersion);
5561 }
5562 }
5563}
5564
5565sub parse_redirect($$$)
5566{
5567 my ($Content, $Path, $LibVersion) = @_;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005568 my @Errors = ();
5569 while($Content=~s/#\s*error\s+([^\n]+?)\s*(\n|\Z)//) {
5570 push(@Errors, $1);
5571 }
5572 my $Redirect = "";
5573 foreach (@Errors)
5574 {
5575 s/\s{2,}/ /g;
5576 if(/(only|must\ include
5577 |update\ to\ include
5578 |replaced\ with
5579 |replaced\ by|renamed\ to
Andrey Ponomarenko9927e332012-10-19 10:50:48 +04005580 |\ is\ in|\ use)\ (<[^<>]+>|[\w\-\/\\]+\.($HEADER_EXT))/ix)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005581 {
5582 $Redirect = $2;
5583 last;
5584 }
5585 elsif(/(include|use|is\ in)\ (<[^<>]+>|[\w\-\/\\]+\.($HEADER_EXT))\ instead/i)
5586 {
5587 $Redirect = $2;
5588 last;
5589 }
5590 elsif(/this\ header\ should\ not\ be\ used
5591 |programs\ should\ not\ directly\ include
5592 |you\ should\ not\ (include|be\ (including|using)\ this\ (file|header))
5593 |is\ not\ supported\ API\ for\ general\ use
5594 |do\ not\ use
Andrey Ponomarenko9927e332012-10-19 10:50:48 +04005595 |should\ not\ be\ (used|using)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005596 |cannot\ be\ included\ directly/ix and not /\ from\ /i) {
5597 $Header_ShouldNotBeUsed{$LibVersion}{$Path} = 1;
5598 }
5599 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +04005600 if($Redirect)
5601 {
5602 $Redirect=~s/\A<//g;
5603 $Redirect=~s/>\Z//g;
5604 }
5605 return $Redirect;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005606}
5607
5608sub parse_includes($$)
5609{
5610 my ($Content, $Path) = @_;
5611 my %Includes = ();
5612 while($Content=~s/#([ \t]*)(include|include_next|import)([ \t]*)(<|")([^<>"]+)(>|")//)
Andrey Ponomarenko85043792012-05-14 16:48:07 +04005613 { # C/C++: include, Objective C/C++: import directive
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005614 my ($Header, $Method) = ($5, $4);
5615 $Header = path_format($Header, $OSgroup);
Andrey Ponomarenko85043792012-05-14 16:48:07 +04005616 if($Method eq "\"" or is_abs($Header))
5617 {
5618 if(-e joinPath(get_dirname($Path), $Header))
5619 { # relative path exists
5620 $Includes{$Header} = -1;
5621 }
5622 else
5623 { # include "..." that doesn't exist is equal to include <...>
5624 $Includes{$Header} = 2;
5625 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005626 }
5627 else {
5628 $Includes{$Header} = 1;
5629 }
5630 }
5631 return \%Includes;
5632}
5633
5634sub ignore_path($)
5635{
5636 my $Path = $_[0];
5637 if($Path=~/\~\Z/)
5638 {# skipping system backup files
5639 return 1;
5640 }
5641 if($Path=~/(\A|[\/\\]+)(\.(svn|git|bzr|hg)|CVS)([\/\\]+|\Z)/)
5642 {# skipping hidden .svn, .git, .bzr, .hg and CVS directories
5643 return 1;
5644 }
5645 return 0;
5646}
5647
Andrey Ponomarenko9927e332012-10-19 10:50:48 +04005648sub sortByWord($$)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005649{
5650 my ($ArrRef, $W) = @_;
5651 return if(length($W)<2);
5652 @{$ArrRef} = sort {get_filename($b)=~/\Q$W\E/i<=>get_filename($a)=~/\Q$W\E/i} @{$ArrRef};
5653}
5654
Andrey Ponomarenko9927e332012-10-19 10:50:48 +04005655sub sortHeaders($$)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005656{
5657 my ($H1, $H2) = @_;
5658 $H1=~s/\.[a-z]+\Z//ig;
5659 $H2=~s/\.[a-z]+\Z//ig;
5660 my ($HDir1, $Hname1) = separate_path($H1);
5661 my ($HDir2, $Hname2) = separate_path($H2);
5662 my $Dirname1 = get_filename($HDir1);
5663 my $Dirname2 = get_filename($HDir2);
Andrey Ponomarenko9927e332012-10-19 10:50:48 +04005664 if($_[0] eq $_[1]
5665 or $H1 eq $H2) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005666 return 0;
5667 }
5668 elsif($H1=~/\A\Q$H2\E/) {
5669 return 1;
5670 }
5671 elsif($H2=~/\A\Q$H1\E/) {
5672 return -1;
5673 }
5674 elsif($HDir1=~/\Q$Hname1\E/i
5675 and $HDir2!~/\Q$Hname2\E/i)
Andrey Ponomarenko9927e332012-10-19 10:50:48 +04005676 { # include/glib-2.0/glib.h
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005677 return -1;
5678 }
5679 elsif($HDir2=~/\Q$Hname2\E/i
5680 and $HDir1!~/\Q$Hname1\E/i)
Andrey Ponomarenko9927e332012-10-19 10:50:48 +04005681 { # include/glib-2.0/glib.h
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005682 return 1;
5683 }
5684 elsif($Hname1=~/\Q$Dirname1\E/i
5685 and $Hname2!~/\Q$Dirname2\E/i)
Andrey Ponomarenko9927e332012-10-19 10:50:48 +04005686 { # include/hildon-thumbnail/hildon-thumbnail-factory.h
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005687 return -1;
5688 }
5689 elsif($Hname2=~/\Q$Dirname2\E/i
5690 and $Hname1!~/\Q$Dirname1\E/i)
Andrey Ponomarenko9927e332012-10-19 10:50:48 +04005691 { # include/hildon-thumbnail/hildon-thumbnail-factory.h
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005692 return 1;
5693 }
Andrey Ponomarenko9927e332012-10-19 10:50:48 +04005694 elsif($Hname1=~/(config|lib|util)/i
5695 and $Hname2!~/(config|lib|util)/i)
5696 { # include/alsa/asoundlib.h
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005697 return -1;
5698 }
Andrey Ponomarenko9927e332012-10-19 10:50:48 +04005699 elsif($Hname2=~/(config|lib|util)/i
5700 and $Hname1!~/(config|lib|util)/i)
5701 { # include/alsa/asoundlib.h
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005702 return 1;
5703 }
5704 elsif(checkRelevance($H1)
5705 and not checkRelevance($H2))
Andrey Ponomarenko9927e332012-10-19 10:50:48 +04005706 { # libebook/e-book.h
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005707 return -1;
5708 }
5709 elsif(checkRelevance($H2)
5710 and not checkRelevance($H1))
Andrey Ponomarenko9927e332012-10-19 10:50:48 +04005711 { # libebook/e-book.h
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005712 return 1;
5713 }
Andrey Ponomarenko9927e332012-10-19 10:50:48 +04005714 else
5715 {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005716 return (lc($H1) cmp lc($H2));
5717 }
5718}
5719
5720sub searchForHeaders($)
5721{
5722 my $LibVersion = $_[0];
5723 # gcc standard include paths
5724 find_gcc_cxx_headers($LibVersion);
5725 # processing header paths
5726 foreach my $Path (keys(%{$Descriptor{$LibVersion}{"IncludePaths"}}),
5727 keys(%{$Descriptor{$LibVersion}{"AddIncludePaths"}}))
5728 {
5729 my $IPath = $Path;
Andrey Ponomarenkoa01311b2012-06-08 17:20:02 +04005730 if($SystemRoot)
5731 {
5732 if(is_abs($Path)) {
5733 $Path = $SystemRoot.$Path;
5734 }
5735 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005736 if(not -e $Path) {
5737 exitStatus("Access_Error", "can't access \'$Path\'");
5738 }
5739 elsif(-f $Path) {
5740 exitStatus("Access_Error", "\'$Path\' - not a directory");
5741 }
5742 elsif(-d $Path)
5743 {
5744 $Path = get_abs_path($Path);
5745 register_directory($Path, 0, $LibVersion);
5746 if($Descriptor{$LibVersion}{"AddIncludePaths"}{$IPath}) {
5747 $Add_Include_Paths{$LibVersion}{$Path} = 1;
5748 }
5749 else {
5750 $Include_Paths{$LibVersion}{$Path} = 1;
5751 }
5752 }
5753 }
5754 if(keys(%{$Include_Paths{$LibVersion}})) {
5755 $INC_PATH_AUTODETECT{$LibVersion} = 0;
5756 }
5757 # registering directories
5758 foreach my $Path (split(/\s*\n\s*/, $Descriptor{$LibVersion}{"Headers"}))
5759 {
5760 next if(not -e $Path);
5761 $Path = get_abs_path($Path);
5762 $Path = path_format($Path, $OSgroup);
5763 if(-d $Path) {
5764 register_directory($Path, 1, $LibVersion);
5765 }
5766 elsif(-f $Path)
5767 {
5768 my $Dir = get_dirname($Path);
5769 if(not $SystemPaths{"include"}{$Dir}
5770 and not $LocalIncludes{$Dir})
5771 {
5772 register_directory($Dir, 1, $LibVersion);
5773 if(my $OutDir = get_dirname($Dir))
5774 { # registering the outer directory
5775 if(not $SystemPaths{"include"}{$OutDir}
5776 and not $LocalIncludes{$OutDir}) {
5777 register_directory($OutDir, 0, $LibVersion);
5778 }
5779 }
5780 }
5781 }
5782 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +04005783
5784 # clean memory
5785 %RegisteredDirs = ();
5786
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005787 # registering headers
5788 my $Position = 0;
5789 foreach my $Dest (split(/\s*\n\s*/, $Descriptor{$LibVersion}{"Headers"}))
5790 {
5791 if(is_abs($Dest) and not -e $Dest) {
5792 exitStatus("Access_Error", "can't access \'$Dest\'");
5793 }
5794 $Dest = path_format($Dest, $OSgroup);
5795 if(is_header($Dest, 1, $LibVersion))
5796 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04005797 if(my $HPath = registerHeader($Dest, $LibVersion)) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005798 $Registered_Headers{$LibVersion}{$HPath}{"Pos"} = $Position++;
5799 }
5800 }
5801 elsif(-d $Dest)
5802 {
5803 my @Registered = ();
5804 foreach my $Path (cmd_find($Dest,"f","",""))
5805 {
5806 next if(ignore_path($Path));
5807 next if(not is_header($Path, 0, $LibVersion));
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04005808 if(my $HPath = registerHeader($Path, $LibVersion)) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005809 push(@Registered, $HPath);
5810 }
5811 }
Andrey Ponomarenko9927e332012-10-19 10:50:48 +04005812 @Registered = sort {sortHeaders($a, $b)} @Registered;
5813 sortByWord(\@Registered, $TargetLibraryShortName);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005814 foreach my $Path (@Registered) {
5815 $Registered_Headers{$LibVersion}{$Path}{"Pos"} = $Position++;
5816 }
5817 }
5818 else {
5819 exitStatus("Access_Error", "can't identify \'$Dest\' as a header file");
5820 }
5821 }
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04005822 if(my $HList = $Descriptor{$LibVersion}{"IncludePreamble"})
5823 { # preparing preamble headers
5824 my $PPos=0;
5825 foreach my $Header (split(/\s*\n\s*/, $HList))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005826 {
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04005827 if(is_abs($Header) and not -f $Header) {
5828 exitStatus("Access_Error", "can't access file \'$Header\'");
5829 }
5830 $Header = path_format($Header, $OSgroup);
5831 if(my $Header_Path = is_header($Header, 1, $LibVersion))
5832 {
Andrey Ponomarenko9927e332012-10-19 10:50:48 +04005833 if(defined $Include_Preamble{$LibVersion}{$Header_Path})
5834 { # duplicate
5835 next;
5836 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04005837 next if(skipHeader($Header_Path, $LibVersion));
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04005838 $Include_Preamble{$LibVersion}{$Header_Path}{"Position"} = $PPos++;
5839 }
5840 else {
5841 exitStatus("Access_Error", "can't identify \'$Header\' as a header file");
5842 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005843 }
5844 }
5845 foreach my $Header_Name (keys(%{$HeaderName_Paths{$LibVersion}}))
5846 { # set relative paths (for duplicates)
5847 if(keys(%{$HeaderName_Paths{$LibVersion}{$Header_Name}})>=2)
5848 { # search for duplicates
5849 my $FirstPath = (keys(%{$HeaderName_Paths{$LibVersion}{$Header_Name}}))[0];
5850 my $Prefix = get_dirname($FirstPath);
5851 while($Prefix=~/\A(.+)[\/\\]+[^\/\\]+\Z/)
5852 { # detect a shortest distinguishing prefix
5853 my $NewPrefix = $1;
5854 my %Identity = ();
5855 foreach my $Path (keys(%{$HeaderName_Paths{$LibVersion}{$Header_Name}}))
5856 {
5857 if($Path=~/\A\Q$Prefix\E[\/\\]+(.*)\Z/) {
5858 $Identity{$Path} = $1;
5859 }
5860 }
5861 if(keys(%Identity)==keys(%{$HeaderName_Paths{$LibVersion}{$Header_Name}}))
5862 { # all names are differend with current prefix
5863 foreach my $Path (keys(%{$HeaderName_Paths{$LibVersion}{$Header_Name}})) {
5864 $Registered_Headers{$LibVersion}{$Path}{"Identity"} = $Identity{$Path};
5865 }
5866 last;
5867 }
5868 $Prefix = $NewPrefix; # increase prefix
5869 }
5870 }
5871 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +04005872
5873 # clean memory
5874 %HeaderName_Paths = ();
5875
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005876 foreach my $HeaderName (keys(%{$Include_Order{$LibVersion}}))
5877 { # ordering headers according to descriptor
5878 my $PairName=$Include_Order{$LibVersion}{$HeaderName};
5879 my ($Pos, $PairPos) = (-1, -1);
5880 my ($Path, $PairPath) = ();
5881 my @Paths = keys(%{$Registered_Headers{$LibVersion}});
5882 @Paths = sort {int($Registered_Headers{$LibVersion}{$a}{"Pos"})<=>int($Registered_Headers{$LibVersion}{$b}{"Pos"})} @Paths;
5883 foreach my $Header_Path (@Paths)
5884 {
5885 if(get_filename($Header_Path) eq $PairName)
5886 {
5887 $PairPos = $Registered_Headers{$LibVersion}{$Header_Path}{"Pos"};
5888 $PairPath = $Header_Path;
5889 }
5890 if(get_filename($Header_Path) eq $HeaderName)
5891 {
5892 $Pos = $Registered_Headers{$LibVersion}{$Header_Path}{"Pos"};
5893 $Path = $Header_Path;
5894 }
5895 }
5896 if($PairPos!=-1 and $Pos!=-1
5897 and int($PairPos)<int($Pos))
5898 {
5899 my %Tmp = %{$Registered_Headers{$LibVersion}{$Path}};
5900 %{$Registered_Headers{$LibVersion}{$Path}} = %{$Registered_Headers{$LibVersion}{$PairPath}};
5901 %{$Registered_Headers{$LibVersion}{$PairPath}} = %Tmp;
5902 }
5903 }
5904 if(not keys(%{$Registered_Headers{$LibVersion}})) {
5905 exitStatus("Error", "header files are not found in the ".$Descriptor{$LibVersion}{"Version"});
5906 }
5907}
5908
5909sub detect_real_includes($$)
5910{
5911 my ($AbsPath, $LibVersion) = @_;
5912 return () if(not $LibVersion or not $AbsPath or not -e $AbsPath);
5913 if($Cache{"detect_real_includes"}{$LibVersion}{$AbsPath}
5914 or keys(%{$RecursiveIncludes{$LibVersion}{$AbsPath}})) {
5915 return keys(%{$RecursiveIncludes{$LibVersion}{$AbsPath}});
5916 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +04005917 $Cache{"detect_real_includes"}{$LibVersion}{$AbsPath}=1;
5918
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005919 my $Path = callPreprocessor($AbsPath, "", $LibVersion);
5920 return () if(not $Path);
5921 open(PREPROC, $Path);
5922 while(<PREPROC>)
5923 {
5924 if(/#\s+\d+\s+"([^"]+)"[\s\d]*\n/)
5925 {
5926 my $Include = path_format($1, $OSgroup);
5927 if($Include=~/\<(built\-in|internal|command(\-|\s)line)\>|\A\./) {
5928 next;
5929 }
5930 if($Include eq $AbsPath) {
5931 next;
5932 }
5933 $RecursiveIncludes{$LibVersion}{$AbsPath}{$Include} = 1;
5934 }
5935 }
5936 close(PREPROC);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005937 return keys(%{$RecursiveIncludes{$LibVersion}{$AbsPath}});
5938}
5939
5940sub detect_header_includes($$)
5941{
5942 my ($Path, $LibVersion) = @_;
Andrey Ponomarenko85043792012-05-14 16:48:07 +04005943 return if(not $LibVersion or not $Path);
5944 if(defined $Cache{"detect_header_includes"}{$LibVersion}{$Path}) {
5945 return;
5946 }
5947 $Cache{"detect_header_includes"}{$LibVersion}{$Path}=1;
5948
5949 if(not -e $Path) {
5950 return;
5951 }
5952
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005953 my $Content = readFile($Path);
Andrey Ponomarenko85043792012-05-14 16:48:07 +04005954 if(my $Redirect = parse_redirect($Content, $Path, $LibVersion))
5955 { # detect error directive in headers
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04005956 if(my $RedirectPath = identifyHeader($Redirect, $LibVersion))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005957 {
5958 if($RedirectPath=~/\/usr\/include\// and $Path!~/\/usr\/include\//) {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04005959 $RedirectPath = identifyHeader(get_filename($Redirect), $LibVersion);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005960 }
5961 if($RedirectPath ne $Path) {
5962 $Header_ErrorRedirect{$LibVersion}{$Path} = $RedirectPath;
5963 }
5964 }
Andrey Ponomarenko9927e332012-10-19 10:50:48 +04005965 else
5966 { # can't find
5967 $Header_ShouldNotBeUsed{$LibVersion}{$Path} = 1;
5968 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005969 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +04005970 if(my $Inc = parse_includes($Content, $Path))
5971 {
5972 foreach my $Include (keys(%{$Inc}))
5973 { # detect includes
Andrey Ponomarenko85043792012-05-14 16:48:07 +04005974 $Header_Includes{$LibVersion}{$Path}{$Include} = $Inc->{$Include};
5975 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005976 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005977}
5978
5979sub simplify_path($)
5980{
5981 my $Path = $_[0];
5982 while($Path=~s&([\/\\])[^\/\\]+[\/\\]\.\.[\/\\]&$1&){};
5983 return $Path;
5984}
5985
5986sub fromLibc($)
5987{ # GLIBC header
5988 my $Path = $_[0];
5989 my ($Dir, $Name) = separate_path($Path);
5990 if(get_filename($Dir)=~/\A(include|libc)\Z/ and $GlibcHeader{$Name})
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04005991 { # /usr/include/{stdio, ...}.h
5992 # epoc32/include/libc/{stdio, ...}.h
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005993 return 1;
5994 }
5995 if(isLibcDir($Dir)) {
5996 return 1;
5997 }
5998 return 0;
5999}
6000
6001sub isLibcDir($)
6002{ # GLIBC directory
6003 my $Dir = $_[0];
6004 my ($OutDir, $Name) = separate_path($Dir);
6005 if(get_filename($OutDir)=~/\A(include|libc)\Z/
6006 and ($Name=~/\Aasm(|-.+)\Z/ or $GlibcDir{$Name}))
6007 { # /usr/include/{sys,bits,asm,asm-*}/*.h
6008 return 1;
6009 }
6010 return 0;
6011}
6012
6013sub detect_recursive_includes($$)
6014{
6015 my ($AbsPath, $LibVersion) = @_;
6016 return () if(not $AbsPath);
6017 if(isCyclical(\@RecurInclude, $AbsPath)) {
6018 return keys(%{$RecursiveIncludes{$LibVersion}{$AbsPath}});
6019 }
6020 my ($AbsDir, $Name) = separate_path($AbsPath);
6021 if(isLibcDir($AbsDir))
6022 { # GLIBC internals
6023 return ();
6024 }
6025 if(keys(%{$RecursiveIncludes{$LibVersion}{$AbsPath}})) {
6026 return keys(%{$RecursiveIncludes{$LibVersion}{$AbsPath}});
6027 }
6028 return () if($OSgroup ne "windows" and $Name=~/windows|win32|win64/i);
6029 return () if($MAIN_CPP_DIR and $AbsPath=~/\A\Q$MAIN_CPP_DIR\E/ and not $STDCXX_TESTING);
6030 push(@RecurInclude, $AbsPath);
6031 if($DefaultGccPaths{$AbsDir}
6032 or fromLibc($AbsPath))
6033 { # check "real" (non-"model") include paths
6034 my @Paths = detect_real_includes($AbsPath, $LibVersion);
6035 pop(@RecurInclude);
6036 return @Paths;
6037 }
6038 if(not keys(%{$Header_Includes{$LibVersion}{$AbsPath}})) {
6039 detect_header_includes($AbsPath, $LibVersion);
6040 }
6041 foreach my $Include (keys(%{$Header_Includes{$LibVersion}{$AbsPath}}))
6042 {
Andrey Ponomarenko85043792012-05-14 16:48:07 +04006043 my $IncType = $Header_Includes{$LibVersion}{$AbsPath}{$Include};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006044 my $HPath = "";
Andrey Ponomarenko85043792012-05-14 16:48:07 +04006045 if($IncType<0)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006046 { # for #include "..."
6047 my $Candidate = joinPath($AbsDir, $Include);
6048 if(-f $Candidate) {
6049 $HPath = simplify_path($Candidate);
6050 }
6051 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +04006052 elsif($IncType>0
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04006053 and $Include=~/[\/\\]/) # and not find_in_defaults($Include)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006054 { # search for the nearest header
6055 # QtCore/qabstractanimation.h includes <QtCore/qobject.h>
6056 my $Candidate = joinPath(get_dirname($AbsDir), $Include);
6057 if(-f $Candidate) {
6058 $HPath = $Candidate;
6059 }
6060 }
6061 if(not $HPath) {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04006062 $HPath = identifyHeader($Include, $LibVersion);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006063 }
6064 next if(not $HPath);
6065 if($HPath eq $AbsPath) {
6066 next;
6067 }
Andrey Ponomarenko9927e332012-10-19 10:50:48 +04006068
6069 if($Debug)
6070 { # boundary headers
6071 #if($HPath=~/vtk/ and $AbsPath!~/vtk/)
6072 #{
6073 # print STDERR "$AbsPath -> $HPath\n";
6074 #}
6075 }
6076
Andrey Ponomarenko85043792012-05-14 16:48:07 +04006077 $RecursiveIncludes{$LibVersion}{$AbsPath}{$HPath} = $IncType;
6078 if($IncType>0)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006079 { # only include <...>, skip include "..." prefixes
6080 $Header_Include_Prefix{$LibVersion}{$AbsPath}{$HPath}{get_dirname($Include)} = 1;
6081 }
6082 foreach my $IncPath (detect_recursive_includes($HPath, $LibVersion))
6083 {
6084 if($IncPath eq $AbsPath) {
6085 next;
6086 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +04006087 my $RIncType = $RecursiveIncludes{$LibVersion}{$HPath}{$IncPath};
6088 if($RIncType==-1)
6089 { # include "..."
6090 $RIncType = $IncType;
6091 }
6092 elsif($RIncType==2)
6093 {
6094 if($IncType!=-1) {
6095 $RIncType = $IncType;
6096 }
6097 }
6098 $RecursiveIncludes{$LibVersion}{$AbsPath}{$IncPath} = $RIncType;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006099 foreach my $Prefix (keys(%{$Header_Include_Prefix{$LibVersion}{$HPath}{$IncPath}})) {
6100 $Header_Include_Prefix{$LibVersion}{$AbsPath}{$IncPath}{$Prefix} = 1;
6101 }
6102 }
6103 foreach my $Dep (keys(%{$Header_Include_Prefix{$LibVersion}{$AbsPath}}))
6104 {
6105 if($GlibcHeader{get_filename($Dep)} and keys(%{$Header_Include_Prefix{$LibVersion}{$AbsPath}{$Dep}})>=2
6106 and defined $Header_Include_Prefix{$LibVersion}{$AbsPath}{$Dep}{""})
6107 { # distinguish math.h from glibc and math.h from the tested library
6108 delete($Header_Include_Prefix{$LibVersion}{$AbsPath}{$Dep}{""});
6109 last;
6110 }
6111 }
6112 }
6113 pop(@RecurInclude);
6114 return keys(%{$RecursiveIncludes{$LibVersion}{$AbsPath}});
6115}
6116
6117sub find_in_framework($$$)
6118{
6119 my ($Header, $Framework, $LibVersion) = @_;
6120 return "" if(not $Header or not $Framework or not $LibVersion);
6121 if(defined $Cache{"find_in_framework"}{$LibVersion}{$Framework}{$Header}) {
6122 return $Cache{"find_in_framework"}{$LibVersion}{$Framework}{$Header};
6123 }
6124 foreach my $Dependency (sort {get_depth($a)<=>get_depth($b)} keys(%{$Header_Dependency{$LibVersion}}))
6125 {
6126 if(get_filename($Dependency) eq $Framework
6127 and -f get_dirname($Dependency)."/".$Header) {
6128 return ($Cache{"find_in_framework"}{$LibVersion}{$Framework}{$Header} = get_dirname($Dependency));
6129 }
6130 }
6131 return ($Cache{"find_in_framework"}{$LibVersion}{$Framework}{$Header} = "");
6132}
6133
6134sub find_in_defaults($)
6135{
6136 my $Header = $_[0];
6137 return "" if(not $Header);
6138 if(defined $Cache{"find_in_defaults"}{$Header}) {
6139 return $Cache{"find_in_defaults"}{$Header};
6140 }
6141 foreach my $Dir (sort {get_depth($a)<=>get_depth($b)}
6142 (keys(%DefaultIncPaths), keys(%DefaultGccPaths), keys(%DefaultCppPaths), keys(%UserIncPath)))
6143 {
6144 next if(not $Dir);
6145 if(-f $Dir."/".$Header) {
6146 return ($Cache{"find_in_defaults"}{$Header}=$Dir);
6147 }
6148 }
6149 return ($Cache{"find_in_defaults"}{$Header}="");
6150}
6151
6152sub cmp_paths($$)
6153{
6154 my ($Path1, $Path2) = @_;
6155 my @Parts1 = split(/[\/\\]/, $Path1);
6156 my @Parts2 = split(/[\/\\]/, $Path2);
6157 foreach my $Num (0 .. $#Parts1)
6158 {
6159 my $Part1 = $Parts1[$Num];
6160 my $Part2 = $Parts2[$Num];
6161 if($GlibcDir{$Part1}
6162 and not $GlibcDir{$Part2}) {
6163 return 1;
6164 }
6165 elsif($GlibcDir{$Part2}
6166 and not $GlibcDir{$Part1}) {
6167 return -1;
6168 }
6169 elsif($Part1=~/glib/
6170 and $Part2!~/glib/) {
6171 return 1;
6172 }
6173 elsif($Part1!~/glib/
6174 and $Part2=~/glib/) {
6175 return -1;
6176 }
6177 elsif(my $CmpRes = ($Part1 cmp $Part2)) {
6178 return $CmpRes;
6179 }
6180 }
6181 return 0;
6182}
6183
6184sub checkRelevance($)
6185{
6186 my ($Path) = @_;
6187 return 0 if(not $Path);
6188 if($SystemRoot) {
Andrey Ponomarenkoa01311b2012-06-08 17:20:02 +04006189 $Path = cut_path_prefix($Path, $SystemRoot);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006190 }
6191 my ($Dir, $Name) = separate_path($Path);
Andrey Ponomarenkoa01311b2012-06-08 17:20:02 +04006192 $Name=~s/\.\w+\Z//g; # remove extension (.h)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006193 my @Tokens = split(/[_\d\W]+/, $Name);
6194 foreach (@Tokens)
6195 {
6196 next if(not $_);
6197 if($Dir=~/(\A|lib|[_\d\W])\Q$_\E([_\d\W]|lib|\Z)/i
6198 or length($_)>=4 and $Dir=~/\Q$_\E/i)
6199 { # include/gupnp-1.0/libgupnp/gupnp-context.h
6200 # include/evolution-data-server-1.4/libebook/e-book.h
6201 return 1;
6202 }
6203 }
6204 return 0;
6205}
6206
6207sub checkFamily(@)
6208{
6209 my @Paths = @_;
6210 return 1 if($#Paths<=0);
6211 my %Prefix = ();
6212 foreach my $Path (@Paths)
6213 {
6214 if($SystemRoot) {
6215 $Path = cut_path_prefix($Path, $SystemRoot);
6216 }
6217 if(my $Dir = get_dirname($Path))
6218 {
6219 $Dir=~s/(\/[^\/]+?)[\d\.\-\_]+\Z/$1/g; # remove version suffix
6220 $Prefix{$Dir} += 1;
6221 $Prefix{get_dirname($Dir)} += 1;
6222 }
6223 }
6224 foreach (sort keys(%Prefix))
6225 {
6226 if(get_depth($_)>=3
6227 and $Prefix{$_}==$#Paths+1) {
6228 return 1;
6229 }
6230 }
6231 return 0;
6232}
6233
6234sub isAcceptable($$$)
6235{
6236 my ($Header, $Candidate, $LibVersion) = @_;
6237 my $HName = get_filename($Header);
6238 if(get_dirname($Header))
6239 { # with prefix
6240 return 1;
6241 }
6242 if($HName=~/config|setup/i and $Candidate=~/[\/\\]lib\d*[\/\\]/)
6243 { # allow to search for glibconfig.h in /usr/lib/glib-2.0/include/
6244 return 1;
6245 }
6246 if(checkRelevance($Candidate))
6247 { # allow to search for atk.h in /usr/include/atk-1.0/atk/
6248 return 1;
6249 }
6250 if(checkFamily(getSystemHeaders($HName, $LibVersion)))
6251 { # /usr/include/qt4/QtNetwork/qsslconfiguration.h
6252 # /usr/include/qt4/Qt/qsslconfiguration.h
6253 return 1;
6254 }
6255 if($OStarget eq "symbian")
6256 {
6257 if($Candidate=~/[\/\\]stdapis[\/\\]/) {
6258 return 1;
6259 }
6260 }
6261 return 0;
6262}
6263
6264sub isRelevant($$$)
6265{ # disallow to search for "abstract" headers in too deep directories
6266 my ($Header, $Candidate, $LibVersion) = @_;
6267 my $HName = get_filename($Header);
6268 if($OStarget eq "symbian")
6269 {
6270 if($Candidate=~/[\/\\](tools|stlportv5)[\/\\]/) {
6271 return 0;
6272 }
6273 }
Andrey Ponomarenko9927e332012-10-19 10:50:48 +04006274 if($OStarget ne "bsd")
6275 {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006276 if($Candidate=~/[\/\\]include[\/\\]bsd[\/\\]/)
6277 { # openssh: skip /usr/lib/bcc/include/bsd/signal.h
6278 return 0;
6279 }
6280 }
Andrey Ponomarenko9927e332012-10-19 10:50:48 +04006281 if($OStarget ne "windows")
6282 {
6283 if($Candidate=~/[\/\\](wine|msvcrt|windows)[\/\\]/)
6284 { # skip /usr/include/wine/msvcrt
6285 return 0;
6286 }
6287 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006288 if(not get_dirname($Header)
6289 and $Candidate=~/[\/\\]wx[\/\\]/)
6290 { # do NOT search in system /wx/ directory
6291 # for headers without a prefix: sstream.h
6292 return 0;
6293 }
6294 if($Candidate=~/c\+\+[\/\\]\d+/ and $MAIN_CPP_DIR
6295 and $Candidate!~/\A\Q$MAIN_CPP_DIR\E/)
6296 { # skip ../c++/3.3.3/ if using ../c++/4.5/
6297 return 0;
6298 }
6299 if($Candidate=~/[\/\\]asm-/
6300 and (my $Arch = getArch($LibVersion)) ne "unknown")
6301 { # arch-specific header files
6302 if($Candidate!~/[\/\\]asm-\Q$Arch\E/)
6303 {# skip ../asm-arm/ if using x86 architecture
6304 return 0;
6305 }
6306 }
6307 my @Candidates = getSystemHeaders($HName, $LibVersion);
6308 if($#Candidates==1)
6309 { # unique header
6310 return 1;
6311 }
6312 my @SCandidates = getSystemHeaders($Header, $LibVersion);
6313 if($#SCandidates==1)
6314 { # unique name
6315 return 1;
6316 }
6317 my $SystemDepth = $SystemRoot?get_depth($SystemRoot):0;
6318 if(get_depth($Candidate)-$SystemDepth>=5)
6319 { # abstract headers in too deep directories
6320 # sstream.h or typeinfo.h in /usr/include/wx-2.9/wx/
6321 if(not isAcceptable($Header, $Candidate, $LibVersion)) {
6322 return 0;
6323 }
6324 }
6325 if($Header eq "parser.h"
6326 and $Candidate!~/\/libxml2\//)
6327 { # select parser.h from xml2 library
6328 return 0;
6329 }
6330 if(not get_dirname($Header)
6331 and keys(%{$SystemHeaders{$HName}})>=3)
6332 { # many headers with the same name
6333 # like thread.h included without a prefix
6334 if(not checkFamily(@Candidates)) {
6335 return 0;
6336 }
6337 }
6338 return 1;
6339}
6340
6341sub selectSystemHeader($$)
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04006342{ # cache function
6343 if(defined $Cache{"selectSystemHeader"}{$_[1]}{$_[0]}) {
6344 return $Cache{"selectSystemHeader"}{$_[1]}{$_[0]};
6345 }
6346 return ($Cache{"selectSystemHeader"}{$_[1]}{$_[0]} = selectSystemHeader_I(@_));
6347}
6348
6349sub selectSystemHeader_I($$)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006350{
6351 my ($Header, $LibVersion) = @_;
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04006352 if(-f $Header) {
6353 return $Header;
6354 }
6355 if(is_abs($Header) and not -f $Header)
6356 { # incorrect absolute path
6357 return "";
6358 }
Andrey Ponomarenko9927e332012-10-19 10:50:48 +04006359 if(defined $ConfHeaders{lc($Header)})
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04006360 { # too abstract configuration headers
6361 return "";
6362 }
Andrey Ponomarenko9927e332012-10-19 10:50:48 +04006363 my $HName = get_filename($Header);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006364 if($OSgroup ne "windows")
6365 {
Andrey Ponomarenko9927e332012-10-19 10:50:48 +04006366 if(defined $WinHeaders{lc($HName)}
6367 or $HName=~/windows|win32|win64/i)
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04006368 { # windows headers
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006369 return "";
6370 }
Andrey Ponomarenko9927e332012-10-19 10:50:48 +04006371 }
6372 if($OSgroup ne "macos")
6373 {
6374 if($HName eq "fp.h")
6375 { # pngconf.h includes fp.h for MACOS
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006376 return "";
6377 }
6378 }
6379 if($OSgroup ne "solaris")
6380 {
Andrey Ponomarenko9927e332012-10-19 10:50:48 +04006381 if($Header eq "thread.h") {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006382 return "";
6383 }
6384 }
Andrey Ponomarenko9927e332012-10-19 10:50:48 +04006385 if($ObsoleteHeaders{$HName}) {
6386 return "";
6387 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04006388
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006389 foreach my $Path (keys(%{$SystemPaths{"include"}}))
6390 { # search in default paths
6391 if(-f $Path."/".$Header) {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04006392 return joinPath($Path,$Header);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006393 }
6394 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04006395 if(not keys(%SystemHeaders))
6396 { # register all headers in system include dirs
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006397 detectSystemHeaders();
6398 }
6399 foreach my $Candidate (sort {get_depth($a)<=>get_depth($b)}
6400 sort {cmp_paths($b, $a)} getSystemHeaders($Header, $LibVersion))
6401 {
6402 if(isRelevant($Header, $Candidate, $LibVersion)) {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04006403 return $Candidate;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006404 }
6405 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04006406 # error
6407 return "";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006408}
6409
6410sub getSystemHeaders($$)
6411{
6412 my ($Header, $LibVersion) = @_;
6413 my @Candidates = ();
6414 foreach my $Candidate (sort keys(%{$SystemHeaders{$Header}}))
6415 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04006416 if(skipHeader($Candidate, $LibVersion)) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006417 next;
6418 }
6419 push(@Candidates, $Candidate);
6420 }
6421 return @Candidates;
6422}
6423
6424sub cut_path_prefix($$)
6425{
6426 my ($Path, $Prefix) = @_;
6427 return $Path if(not $Prefix);
6428 $Prefix=~s/[\/\\]+\Z//;
6429 $Path=~s/\A\Q$Prefix\E([\/\\]+|\Z)//;
6430 return $Path;
6431}
6432
6433sub is_default_include_dir($)
6434{
6435 my $Dir = $_[0];
6436 $Dir=~s/[\/\\]+\Z//;
6437 return ($DefaultGccPaths{$Dir} or $DefaultCppPaths{$Dir} or $DefaultIncPaths{$Dir});
6438}
6439
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04006440sub identifyHeader($$)
6441{ # cache function
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006442 my ($Header, $LibVersion) = @_;
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04006443 if(not $Header) {
6444 return "";
6445 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006446 $Header=~s/\A(\.\.[\\\/])+//g;
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04006447 if(defined $Cache{"identifyHeader"}{$LibVersion}{$Header}) {
6448 return $Cache{"identifyHeader"}{$LibVersion}{$Header};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006449 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04006450 return ($Cache{"identifyHeader"}{$LibVersion}{$Header} = identifyHeader_I($Header, $LibVersion));
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006451}
6452
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04006453sub identifyHeader_I($$)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006454{ # search for header by absolute path, relative path or name
6455 my ($Header, $LibVersion) = @_;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006456 if(-f $Header)
6457 { # it's relative or absolute path
6458 return get_abs_path($Header);
6459 }
6460 elsif($GlibcHeader{$Header} and not $GLIBC_TESTING
6461 and my $HeaderDir = find_in_defaults($Header))
6462 { # search for libc headers in the /usr/include
6463 # for non-libc target library before searching
6464 # in the library paths
6465 return joinPath($HeaderDir,$Header);
6466 }
6467 elsif(my $Path = $Include_Neighbors{$LibVersion}{$Header})
6468 { # search in the target library paths
6469 return $Path;
6470 }
6471 elsif($DefaultGccHeader{$Header})
6472 { # search in the internal GCC include paths
6473 return $DefaultGccHeader{$Header};
6474 }
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04006475 elsif(my $DefaultDir = find_in_defaults($Header))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006476 { # search in the default GCC include paths
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04006477 return joinPath($DefaultDir,$Header);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006478 }
6479 elsif($DefaultCppHeader{$Header})
6480 { # search in the default G++ include paths
6481 return $DefaultCppHeader{$Header};
6482 }
6483 elsif(my $AnyPath = selectSystemHeader($Header, $LibVersion))
6484 { # search everywhere in the system
6485 return $AnyPath;
6486 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04006487 elsif($OSgroup eq "macos")
6488 { # search in frameworks: "OpenGL/gl.h" is "OpenGL.framework/Headers/gl.h"
6489 if(my $Dir = get_dirname($Header))
6490 {
6491 my $RelPath = "Headers\/".get_filename($Header);
6492 if(my $HeaderDir = find_in_framework($RelPath, $Dir.".framework", $LibVersion)) {
6493 return joinPath($HeaderDir, $RelPath);
6494 }
6495 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006496 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04006497 # cannot find anything
6498 return "";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006499}
6500
6501sub getLocation($)
6502{
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04006503 if($_[0] and my $Info = $LibInfo{$Version}{"info"}{$_[0]})
6504 {
6505 if($Info=~/srcp[ ]*:[ ]*([\w\-\<\>\.\+\/\\]+):(\d+) /) {
Andrey Ponomarenko9927e332012-10-19 10:50:48 +04006506 return (path_format($1, $OSgroup), $2);
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04006507 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006508 }
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04006509 return ();
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006510}
6511
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006512sub getNameByInfo($)
6513{
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04006514 if($_[0] and my $Info = $LibInfo{$Version}{"info"}{$_[0]})
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04006515 {
6516 if($Info=~/name[ ]*:[ ]*@(\d+) /)
6517 {
6518 if(my $NInfo = $LibInfo{$Version}{"info"}{$1})
6519 {
6520 if($NInfo=~/strg[ ]*:[ ]*(.*?)[ ]+lngt/)
6521 { # short unsigned int (may include spaces)
6522 return $1;
6523 }
6524 }
6525 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006526 }
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04006527 return "";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006528}
6529
6530sub getTreeStr($)
6531{
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04006532 if($_[0] and my $Info = $LibInfo{$Version}{"info"}{$_[0]})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006533 {
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04006534 if($Info=~/strg[ ]*:[ ]*([^ ]*)/)
6535 {
6536 my $Str = $1;
6537 if($C99Mode{$Version}
6538 and $Str=~/\Ac99_(.+)\Z/) {
6539 if($CppKeywords_A{$1}) {
6540 $Str=$1;
6541 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006542 }
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04006543 return $Str;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006544 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006545 }
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04006546 return "";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006547}
6548
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006549sub getFuncShortName($)
6550{
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04006551 if(my $Info = $LibInfo{$Version}{"info"}{$_[0]})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006552 {
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04006553 if($Info=~/ operator /)
6554 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04006555 if($Info=~/ conversion /)
6556 {
6557 if(my $Rid = $SymbolInfo{$Version}{$_[0]}{"Return"})
6558 {
6559 if(my $RName = $TypeInfo{$Version}{$Rid}{"Name"}) {
6560 return "operator ".$RName;
6561 }
6562 }
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04006563 }
6564 else
6565 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04006566 if($Info=~/ operator[ ]+([a-zA-Z]+) /)
6567 {
6568 if(my $Ind = $Operator_Indication{$1}) {
6569 return "operator".$Ind;
6570 }
6571 elsif(not $UnknownOperator{$1})
6572 {
6573 printMsg("WARNING", "unknown operator $1");
6574 $UnknownOperator{$1} = 1;
6575 }
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04006576 }
6577 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006578 }
6579 else
6580 {
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04006581 if($Info=~/name[ ]*:[ ]*@(\d+) /) {
6582 return getTreeStr($1);
6583 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006584 }
6585 }
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04006586 return "";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006587}
6588
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006589sub getFuncReturn($)
6590{
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04006591 if($_[0] and my $Info = $LibInfo{$Version}{"info"}{$_[0]})
6592 {
6593 if($Info=~/type[ ]*:[ ]*@(\d+) /)
6594 {
6595 if($LibInfo{$Version}{"info"}{$1}=~/retn[ ]*:[ ]*@(\d+) /) {
6596 return $1;
6597 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006598 }
6599 }
6600 return "";
6601}
6602
6603sub getFuncOrig($)
6604{
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04006605 if($_[0] and my $Info = $LibInfo{$Version}{"info"}{$_[0]})
6606 {
6607 if($Info=~/orig[ ]*:[ ]*@(\d+) /) {
6608 return $1;
6609 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006610 }
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04006611 return $_[0];
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006612}
6613
6614sub unmangleSymbol($)
6615{
6616 my $Symbol = $_[0];
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04006617 if(my @Unmngl = unmangleArray($Symbol)) {
6618 return $Unmngl[0];
6619 }
6620 return "";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006621}
6622
6623sub unmangleArray(@)
6624{
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04006625 if($_[0]=~/\A\?/)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006626 { # MSVC mangling
6627 my $UndNameCmd = get_CmdPath("undname");
6628 if(not $UndNameCmd) {
6629 exitStatus("Not_Found", "can't find \"undname\"");
6630 }
6631 writeFile("$TMP_DIR/unmangle", join("\n", @_));
Andrey Ponomarenkoa01311b2012-06-08 17:20:02 +04006632 return split(/\n/, `$UndNameCmd 0x8386 \"$TMP_DIR/unmangle\"`);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006633 }
6634 else
6635 { # GCC mangling
6636 my $CppFiltCmd = get_CmdPath("c++filt");
6637 if(not $CppFiltCmd) {
6638 exitStatus("Not_Found", "can't find c++filt in PATH");
6639 }
Andrey Ponomarenko9927e332012-10-19 10:50:48 +04006640 if(not defined $CPPFILT_SUPPORT_FILE)
6641 {
6642 my $Info = `$CppFiltCmd -h 2>&1`;
6643 $CPPFILT_SUPPORT_FILE = $Info=~/\@<file>/;
6644 }
6645 if($CPPFILT_SUPPORT_FILE)
6646 { # new versions of c++filt can take a file
6647 if($#_>$MAX_CPPFILT_FILE_SIZE)
6648 { # c++filt <= 2.22 may crash on large files (larger than 8mb)
6649 # this is fixed in the oncoming version of Binutils
6650 my @Half = splice(@_, 0, ($#_+1)/2);
6651 return (unmangleArray(@Half), unmangleArray(@_))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006652 }
Andrey Ponomarenko9927e332012-10-19 10:50:48 +04006653 else
6654 {
6655 my $NoStrip = "";
6656 if($OSgroup eq "macos"
6657 or $OSgroup eq "windows") {
6658 $NoStrip = "-n";
6659 }
6660 writeFile("$TMP_DIR/unmangle", join("\n", @_));
6661 my $Res = `$CppFiltCmd $NoStrip \@\"$TMP_DIR/unmangle\"`;
6662 if($?==139)
6663 { # segmentation fault
6664 printMsg("ERROR", "internal error - c++filt crashed, try to reduce MAX_CPPFILT_FILE_SIZE constant");
6665 }
6666 return split(/\n/, $Res);
6667 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006668 }
6669 else
6670 { # old-style unmangling
Andrey Ponomarenko9927e332012-10-19 10:50:48 +04006671 if($#_>$MAX_COMMAND_LINE_ARGUMENTS)
6672 {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006673 my @Half = splice(@_, 0, ($#_+1)/2);
6674 return (unmangleArray(@Half), unmangleArray(@_))
6675 }
6676 else
6677 {
6678 my $NoStrip = "";
6679 if($OSgroup eq "macos"
6680 or $OSgroup eq "windows") {
6681 $NoStrip = "-n";
6682 }
6683 my $Strings = join(" ", @_);
Andrey Ponomarenko9927e332012-10-19 10:50:48 +04006684 my $Res = `$CppFiltCmd $NoStrip $Strings`;
6685 if($?==139)
6686 { # segmentation fault
6687 printMsg("ERROR", "internal error - c++filt crashed, try to reduce MAX_COMMAND_LINE_ARGUMENTS constant");
6688 }
6689 return split(/\n/, $Res);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006690 }
6691 }
6692 }
6693}
6694
6695sub get_SignatureNoInfo($$)
6696{
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04006697 my ($Symbol, $LibVersion) = @_;
6698 if($Cache{"get_SignatureNoInfo"}{$LibVersion}{$Symbol}) {
6699 return $Cache{"get_SignatureNoInfo"}{$LibVersion}{$Symbol};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006700 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04006701 my ($MnglName, $VersionSpec, $SymbolVersion) = separate_symbol($Symbol);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006702 my $Signature = $tr_name{$MnglName}?$tr_name{$MnglName}:$MnglName;
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04006703 if($Symbol=~/\A(_Z|\?)/)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006704 { # C++
6705 $Signature=~s/\Qstd::basic_string<char, std::char_traits<char>, std::allocator<char> >\E/std::string/g;
6706 $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;
6707 }
6708 if(not $CheckObjectsOnly or $OSgroup=~/linux|bsd|beos/)
6709 { # ELF format marks data as OBJECT
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04006710 if($GlobalDataObject{$LibVersion}{$Symbol}) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006711 $Signature .= " [data]";
6712 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04006713 elsif($Symbol!~/\A(_Z|\?)/) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006714 $Signature .= " (...)";
6715 }
6716 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04006717 if(my $ChargeLevel = get_ChargeLevel($Symbol, $LibVersion))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006718 {
Andrey Ponomarenko16934472012-03-29 15:37:04 +04006719 my $ShortName = substr($Signature, 0, find_center($Signature, "("));
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006720 $Signature=~s/\A\Q$ShortName\E/$ShortName $ChargeLevel/g;
6721 }
6722 if($SymbolVersion) {
6723 $Signature .= $VersionSpec.$SymbolVersion;
6724 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04006725 return ($Cache{"get_SignatureNoInfo"}{$LibVersion}{$Symbol} = $Signature);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006726}
6727
6728sub get_ChargeLevel($$)
6729{
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04006730 my ($Symbol, $LibVersion) = @_;
6731 return "" if($Symbol!~/\A(_Z|\?)/);
6732 if(defined $CompleteSignature{$LibVersion}{$Symbol}
6733 and $CompleteSignature{$LibVersion}{$Symbol}{"Header"})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006734 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04006735 if($CompleteSignature{$LibVersion}{$Symbol}{"Constructor"})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006736 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04006737 if($Symbol=~/C1E/) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006738 return "[in-charge]";
6739 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04006740 elsif($Symbol=~/C2E/) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006741 return "[not-in-charge]";
6742 }
6743 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04006744 elsif($CompleteSignature{$LibVersion}{$Symbol}{"Destructor"})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006745 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04006746 if($Symbol=~/D1E/) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006747 return "[in-charge]";
6748 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04006749 elsif($Symbol=~/D2E/) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006750 return "[not-in-charge]";
6751 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04006752 elsif($Symbol=~/D0E/) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006753 return "[in-charge-deleting]";
6754 }
6755 }
6756 }
6757 else
6758 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04006759 if($Symbol=~/C1E/) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006760 return "[in-charge]";
6761 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04006762 elsif($Symbol=~/C2E/) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006763 return "[not-in-charge]";
6764 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04006765 elsif($Symbol=~/D1E/) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006766 return "[in-charge]";
6767 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04006768 elsif($Symbol=~/D2E/) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006769 return "[not-in-charge]";
6770 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04006771 elsif($Symbol=~/D0E/) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006772 return "[in-charge-deleting]";
6773 }
6774 }
6775 return "";
6776}
6777
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04006778sub get_Signature_M($$)
6779{
6780 my ($Symbol, $LibVersion) = @_;
6781 my $Signature_M = $tr_name{$Symbol};
6782 if(my $RTid = $CompleteSignature{$LibVersion}{$Symbol}{"Return"})
6783 { # add return type name
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04006784 $Signature_M = $TypeInfo{$LibVersion}{$RTid}{"Name"}." ".$Signature_M;
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04006785 }
6786 return $Signature_M;
6787}
6788
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006789sub get_Signature($$)
6790{
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04006791 my ($Symbol, $LibVersion) = @_;
6792 if($Cache{"get_Signature"}{$LibVersion}{$Symbol}) {
6793 return $Cache{"get_Signature"}{$LibVersion}{$Symbol};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006794 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04006795 my ($MnglName, $VersionSpec, $SymbolVersion) = separate_symbol($Symbol);
6796 if(isPrivateData($MnglName) or not $CompleteSignature{$LibVersion}{$Symbol}{"Header"})
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04006797 { # non-public global data
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04006798 return get_SignatureNoInfo($Symbol, $LibVersion);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006799 }
6800 my ($Func_Signature, @Param_Types_FromUnmangledName) = ();
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04006801 my $ShortName = $CompleteSignature{$LibVersion}{$Symbol}{"ShortName"};
6802 if($Symbol=~/\A(_Z|\?)/)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006803 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04006804 if(my $ClassId = $CompleteSignature{$LibVersion}{$Symbol}{"Class"}) {
6805 $Func_Signature = $TypeInfo{$LibVersion}{$ClassId}{"Name"}."::".(($CompleteSignature{$LibVersion}{$Symbol}{"Destructor"})?"~":"").$ShortName;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006806 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04006807 elsif(my $NameSpace = $CompleteSignature{$LibVersion}{$Symbol}{"NameSpace"}) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006808 $Func_Signature = $NameSpace."::".$ShortName;
6809 }
6810 else {
6811 $Func_Signature = $ShortName;
6812 }
6813 @Param_Types_FromUnmangledName = get_s_params($tr_name{$MnglName}, 0);
6814 }
6815 else {
6816 $Func_Signature = $MnglName;
6817 }
6818 my @ParamArray = ();
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04006819 foreach my $Pos (sort {int($a) <=> int($b)} keys(%{$CompleteSignature{$LibVersion}{$Symbol}{"Param"}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006820 {
6821 next if($Pos eq "");
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04006822 my $ParamTypeId = $CompleteSignature{$LibVersion}{$Symbol}{"Param"}{$Pos}{"type"};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006823 next if(not $ParamTypeId);
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04006824 my $ParamTypeName = $TypeInfo{$LibVersion}{$ParamTypeId}{"Name"};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006825 if(not $ParamTypeName) {
6826 $ParamTypeName = $Param_Types_FromUnmangledName[$Pos];
6827 }
6828 foreach my $Typedef (keys(%ChangedTypedef))
6829 {
6830 my $Base = $Typedef_BaseName{$LibVersion}{$Typedef};
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04006831 $ParamTypeName=~s/\b\Q$Typedef\E\b/$Base/g;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006832 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04006833 if(my $ParamName = $CompleteSignature{$LibVersion}{$Symbol}{"Param"}{$Pos}{"name"}) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006834 push(@ParamArray, create_member_decl($ParamTypeName, $ParamName));
6835 }
6836 else {
6837 push(@ParamArray, $ParamTypeName);
6838 }
6839 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04006840 if($CompleteSignature{$LibVersion}{$Symbol}{"Data"}
6841 or $GlobalDataObject{$LibVersion}{$Symbol}) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006842 $Func_Signature .= " [data]";
6843 }
6844 else
6845 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04006846 if(my $ChargeLevel = get_ChargeLevel($Symbol, $LibVersion))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006847 { # add [in-charge]
6848 $Func_Signature .= " ".$ChargeLevel;
6849 }
6850 $Func_Signature .= " (".join(", ", @ParamArray).")";
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04006851 if($CompleteSignature{$LibVersion}{$Symbol}{"Const"}
6852 or $Symbol=~/\A_ZN(V|)K/) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006853 $Func_Signature .= " const";
6854 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04006855 if($CompleteSignature{$LibVersion}{$Symbol}{"Volatile"}
6856 or $Symbol=~/\A_ZN(K|)V/) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006857 $Func_Signature .= " volatile";
6858 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04006859 if($CompleteSignature{$LibVersion}{$Symbol}{"Static"}
6860 and $Symbol=~/\A(_Z|\?)/)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006861 {# for static methods
6862 $Func_Signature .= " [static]";
6863 }
6864 }
6865 if(defined $ShowRetVal
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04006866 and my $ReturnTId = $CompleteSignature{$LibVersion}{$Symbol}{"Return"}) {
6867 $Func_Signature .= ":".$TypeInfo{$LibVersion}{$ReturnTId}{"Name"};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006868 }
6869 if($SymbolVersion) {
6870 $Func_Signature .= $VersionSpec.$SymbolVersion;
6871 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04006872 return ($Cache{"get_Signature"}{$LibVersion}{$Symbol} = $Func_Signature);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006873}
6874
6875sub create_member_decl($$)
6876{
6877 my ($TName, $Member) = @_;
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04006878 if($TName=~/\([\*]+\)/)
6879 {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006880 $TName=~s/\(([\*]+)\)/\($1$Member\)/;
6881 return $TName;
6882 }
6883 else
6884 {
6885 my @ArraySizes = ();
6886 while($TName=~s/(\[[^\[\]]*\])\Z//) {
6887 push(@ArraySizes, $1);
6888 }
6889 return $TName." ".$Member.join("", @ArraySizes);
6890 }
6891}
6892
6893sub getFuncType($)
6894{
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04006895 if($_[0] and my $Info = $LibInfo{$Version}{"info"}{$_[0]})
6896 {
6897 if($Info=~/type[ ]*:[ ]*@(\d+) /)
6898 {
6899 if(my $Type = $LibInfo{$Version}{"info_type"}{$1})
6900 {
6901 if($Type eq "method_type") {
6902 return "Method";
6903 }
6904 elsif($Type eq "function_type") {
6905 return "Function";
6906 }
6907 else {
6908 return "Other";
6909 }
6910 }
6911 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006912 }
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +04006913 return "";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006914}
6915
6916sub getFuncTypeId($)
6917{
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04006918 if($_[0] and my $Info = $LibInfo{$Version}{"info"}{$_[0]})
6919 {
6920 if($Info=~/type[ ]*:[ ]*@(\d+)( |\Z)/) {
6921 return $1;
6922 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006923 }
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04006924 return 0;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006925}
6926
6927sub isNotAnon($) {
6928 return (not isAnon($_[0]));
6929}
6930
6931sub isAnon($)
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04006932{ # "._N" or "$_N" in older GCC versions
6933 return ($_[0] and $_[0]=~/(\.|\$)\_\d+|anon\-/);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006934}
6935
Andrey Ponomarenko9927e332012-10-19 10:50:48 +04006936sub formatName($$)
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04006937{ # type name correction
Andrey Ponomarenko9927e332012-10-19 10:50:48 +04006938 if(defined $Cache{"formatName"}{$_[1]}{$_[0]}) {
6939 return $Cache{"formatName"}{$_[1]}{$_[0]};
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04006940 }
6941
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +04006942 my $N = $_[0];
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04006943
Andrey Ponomarenko9927e332012-10-19 10:50:48 +04006944 if($_[1] ne "S")
6945 {
6946 $N=~s/\A[ ]+//g;
6947 $N=~s/[ ]+\Z//g;
6948 $N=~s/[ ]{2,}/ /g;
6949 }
6950
6951 $N=~s/[ ]*(\W)[ ]*/$1/g; # std::basic_string<char> const
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04006952
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +04006953 $N=~s/\bvolatile const\b/const volatile/g;
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04006954
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +04006955 $N=~s/\b(long long|short|long) unsigned\b/unsigned $1/g;
6956 $N=~s/\b(short|long) int\b/$1/g;
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04006957
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +04006958 $N=~s/([\)\]])(const|volatile)\b/$1 $2/g;
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04006959
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +04006960 while($N=~s/>>/> >/g) {};
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04006961
Andrey Ponomarenko9927e332012-10-19 10:50:48 +04006962 if($_[1] eq "S")
6963 {
6964 if(index($N, "operator")!=-1) {
6965 $N=~s/\b(operator[ ]*)> >/$1>>/;
6966 }
6967 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04006968
Andrey Ponomarenko9927e332012-10-19 10:50:48 +04006969 return ($Cache{"formatName"}{$_[1]}{$_[0]} = $N);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006970}
6971
6972sub get_HeaderDeps($$)
6973{
6974 my ($AbsPath, $LibVersion) = @_;
6975 return () if(not $AbsPath or not $LibVersion);
6976 if(defined $Cache{"get_HeaderDeps"}{$LibVersion}{$AbsPath}) {
6977 return @{$Cache{"get_HeaderDeps"}{$LibVersion}{$AbsPath}};
6978 }
6979 my %IncDir = ();
6980 detect_recursive_includes($AbsPath, $LibVersion);
6981 foreach my $HeaderPath (keys(%{$RecursiveIncludes{$LibVersion}{$AbsPath}}))
6982 {
6983 next if(not $HeaderPath);
6984 next if($MAIN_CPP_DIR and $HeaderPath=~/\A\Q$MAIN_CPP_DIR\E([\/\\]|\Z)/);
6985 my $Dir = get_dirname($HeaderPath);
6986 foreach my $Prefix (keys(%{$Header_Include_Prefix{$LibVersion}{$AbsPath}{$HeaderPath}}))
6987 {
6988 my $Dep = $Dir;
6989 if($Prefix)
6990 {
6991 if($OSgroup eq "windows")
6992 { # case insensitive seach on windows
6993 if(not $Dep=~s/[\/\\]+\Q$Prefix\E\Z//ig) {
6994 next;
6995 }
6996 }
6997 elsif($OSgroup eq "macos")
6998 { # seach in frameworks
6999 if(not $Dep=~s/[\/\\]+\Q$Prefix\E\Z//g)
7000 {
7001 if($HeaderPath=~/(.+\.framework)\/Headers\/([^\/]+)/)
7002 {# frameworks
7003 my ($HFramework, $HName) = ($1, $2);
7004 $Dep = $HFramework;
7005 }
7006 else
7007 {# mismatch
7008 next;
7009 }
7010 }
7011 }
7012 elsif(not $Dep=~s/[\/\\]+\Q$Prefix\E\Z//g)
7013 { # Linux, FreeBSD
7014 next;
7015 }
7016 }
7017 if(not $Dep)
7018 { # nothing to include
7019 next;
7020 }
7021 if(is_default_include_dir($Dep))
7022 { # included by the compiler
7023 next;
7024 }
7025 if(get_depth($Dep)==1)
7026 { # too short
7027 next;
7028 }
7029 if(isLibcDir($Dep))
7030 { # do NOT include /usr/include/{sys,bits}
7031 next;
7032 }
7033 $IncDir{$Dep}=1;
7034 }
7035 }
7036 $Cache{"get_HeaderDeps"}{$LibVersion}{$AbsPath} = sortIncPaths([keys(%IncDir)], $LibVersion);
7037 return @{$Cache{"get_HeaderDeps"}{$LibVersion}{$AbsPath}};
7038}
7039
7040sub sortIncPaths($$)
7041{
7042 my ($ArrRef, $LibVersion) = @_;
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04007043 if(not $ArrRef or $#{$ArrRef}<0) {
7044 return $ArrRef;
7045 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007046 @{$ArrRef} = sort {$b cmp $a} @{$ArrRef};
7047 @{$ArrRef} = sort {get_depth($a)<=>get_depth($b)} @{$ArrRef};
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04007048 @{$ArrRef} = sort {sortDeps($b, $a, $LibVersion)} @{$ArrRef};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007049 return $ArrRef;
7050}
7051
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04007052sub sortDeps($$$)
7053{
7054 if($Header_Dependency{$_[2]}{$_[0]}
7055 and not $Header_Dependency{$_[2]}{$_[1]}) {
7056 return 1;
7057 }
7058 elsif(not $Header_Dependency{$_[2]}{$_[0]}
7059 and $Header_Dependency{$_[2]}{$_[1]}) {
7060 return -1;
7061 }
7062 return 0;
7063}
7064
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007065sub joinPath($$) {
7066 return join($SLASH, @_);
7067}
7068
7069sub get_namespace_additions($)
7070{
7071 my $NameSpaces = $_[0];
7072 my ($Additions, $AddNameSpaceId) = ("", 1);
7073 foreach my $NS (sort {$a=~/_/ <=> $b=~/_/} sort {lc($a) cmp lc($b)} keys(%{$NameSpaces}))
7074 {
7075 next if($SkipNameSpaces{$Version}{$NS});
7076 next if(not $NS or $NameSpaces->{$NS}==-1);
7077 next if($NS=~/(\A|::)iterator(::|\Z)/i);
7078 next if($NS=~/\A__/i);
7079 next if(($NS=~/\Astd::/ or $NS=~/\A(std|tr1|rel_ops|fcntl)\Z/) and not $STDCXX_TESTING);
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04007080 $NestedNameSpaces{$Version}{$NS} = 1; # for future use in reports
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007081 my ($TypeDecl_Prefix, $TypeDecl_Suffix) = ();
7082 my @NS_Parts = split(/::/, $NS);
7083 next if($#NS_Parts==-1);
7084 next if($NS_Parts[0]=~/\A(random|or)\Z/);
7085 foreach my $NS_Part (@NS_Parts)
7086 {
7087 $TypeDecl_Prefix .= "namespace $NS_Part\{";
7088 $TypeDecl_Suffix .= "}";
7089 }
7090 my $TypeDecl = $TypeDecl_Prefix."typedef int tmp_add_type_$AddNameSpaceId;".$TypeDecl_Suffix;
7091 my $FuncDecl = "$NS\:\:tmp_add_type_$AddNameSpaceId tmp_add_func_$AddNameSpaceId(){return 0;};";
7092 $Additions.=" $TypeDecl\n $FuncDecl\n";
7093 $AddNameSpaceId+=1;
7094 }
7095 return $Additions;
7096}
7097
7098sub path_format($$)
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04007099{ # forward slash to pass into MinGW GCC
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007100 my ($Path, $Fmt) = @_;
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04007101 if($Fmt eq "windows")
7102 {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007103 $Path=~s/\//\\/g;
7104 $Path=lc($Path);
7105 }
7106 else {
7107 $Path=~s/\\/\//g;
7108 }
7109 return $Path;
7110}
7111
7112sub inc_opt($$)
7113{
7114 my ($Path, $Style) = @_;
7115 if($Style eq "GCC")
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04007116 { # GCC options
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007117 if($OSgroup eq "windows")
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04007118 { # to MinGW GCC
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007119 return "-I\"".path_format($Path, "unix")."\"";
7120 }
7121 elsif($OSgroup eq "macos"
7122 and $Path=~/\.framework\Z/)
7123 {# to Apple's GCC
7124 return "-F".esc(get_dirname($Path));
7125 }
7126 else {
7127 return "-I".esc($Path);
7128 }
7129 }
7130 elsif($Style eq "CL") {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04007131 return "/I \"".$Path."\"";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007132 }
7133 return "";
7134}
7135
7136sub platformSpecs($)
7137{
7138 my $LibVersion = $_[0];
7139 my $Arch = getArch($LibVersion);
7140 if($OStarget eq "symbian")
7141 { # options for GCCE compiler
7142 my %Symbian_Opts = map {$_=>1} (
7143 "-D__GCCE__",
7144 "-DUNICODE",
7145 "-fexceptions",
7146 "-D__SYMBIAN32__",
7147 "-D__MARM_INTERWORK__",
7148 "-D_UNICODE",
7149 "-D__S60_50__",
7150 "-D__S60_3X__",
7151 "-D__SERIES60_3X__",
7152 "-D__EPOC32__",
7153 "-D__MARM__",
7154 "-D__EABI__",
7155 "-D__MARM_ARMV5__",
7156 "-D__SUPPORT_CPP_EXCEPTIONS__",
7157 "-march=armv5t",
7158 "-mapcs",
7159 "-mthumb-interwork",
7160 "-DEKA2",
7161 "-DSYMBIAN_ENABLE_SPLIT_HEADERS"
7162 );
7163 return join(" ", keys(%Symbian_Opts));
7164 }
7165 elsif($OSgroup eq "windows"
7166 and get_dumpmachine($GCC_PATH)=~/mingw/i)
7167 { # add options to MinGW compiler
7168 # to simulate the MSVC compiler
7169 my %MinGW_Opts = map {$_=>1} (
7170 "-D_WIN32",
7171 "-D_STDCALL_SUPPORTED",
7172 "-D__int64=\"long long\"",
7173 "-D__int32=int",
7174 "-D__int16=short",
7175 "-D__int8=char",
7176 "-D__possibly_notnullterminated=\" \"",
7177 "-D__nullterminated=\" \"",
7178 "-D__nullnullterminated=\" \"",
7179 "-D__w64=\" \"",
7180 "-D__ptr32=\" \"",
7181 "-D__ptr64=\" \"",
7182 "-D__forceinline=inline",
7183 "-D__inline=inline",
7184 "-D__uuidof(x)=IID()",
7185 "-D__try=",
7186 "-D__except(x)=",
7187 "-D__declspec(x)=__attribute__((x))",
7188 "-D__pragma(x)=",
7189 "-D_inline=inline",
7190 "-D__forceinline=__inline",
7191 "-D__stdcall=__attribute__((__stdcall__))",
7192 "-D__cdecl=__attribute__((__cdecl__))",
7193 "-D__fastcall=__attribute__((__fastcall__))",
7194 "-D__thiscall=__attribute__((__thiscall__))",
7195 "-D_stdcall=__attribute__((__stdcall__))",
7196 "-D_cdecl=__attribute__((__cdecl__))",
7197 "-D_fastcall=__attribute__((__fastcall__))",
7198 "-D_thiscall=__attribute__((__thiscall__))",
7199 "-DSHSTDAPI_(x)=x",
7200 "-D_MSC_EXTENSIONS",
7201 "-DSECURITY_WIN32",
7202 "-D_MSC_VER=1500",
7203 "-D_USE_DECLSPECS_FOR_SAL",
7204 "-D__noop=\" \"",
7205 "-DDECLSPEC_DEPRECATED=\" \"",
7206 "-D__builtin_alignof(x)=__alignof__(x)",
7207 "-DSORTPP_PASS");
7208 if($Arch eq "x86") {
7209 $MinGW_Opts{"-D_M_IX86=300"}=1;
7210 }
7211 elsif($Arch eq "x86_64") {
7212 $MinGW_Opts{"-D_M_AMD64=300"}=1;
7213 }
7214 elsif($Arch eq "ia64") {
7215 $MinGW_Opts{"-D_M_IA64=300"}=1;
7216 }
7217 return join(" ", keys(%MinGW_Opts));
7218 }
7219 return "";
7220}
7221
7222my %C_Structure = map {$_=>1} (
7223# FIXME: Can't separate union and struct data types before dumping,
7224# so it sometimes cause compilation errors for unknown reason
7225# when trying to declare TYPE* tmp_add_class_N
7226# This is a list of such structures + list of other C structures
7227 "sigval",
7228 "sigevent",
7229 "sigaction",
7230 "sigvec",
7231 "sigstack",
7232 "timeval",
7233 "timezone",
7234 "rusage",
7235 "rlimit",
7236 "wait",
7237 "flock",
7238 "stat",
7239 "_stat",
7240 "stat32",
7241 "_stat32",
7242 "stat64",
7243 "_stat64",
7244 "_stati64",
7245 "if_nameindex",
7246 "usb_device",
7247 "sigaltstack",
7248 "sysinfo",
7249 "timeLocale",
7250 "tcp_debug",
7251 "rpc_createerr",
7252# Other C structures appearing in every dump
7253 "timespec",
7254 "random_data",
7255 "drand48_data",
7256 "_IO_marker",
7257 "_IO_FILE",
7258 "lconv",
7259 "sched_param",
7260 "tm",
7261 "itimerspec",
7262 "_pthread_cleanup_buffer",
7263 "fd_set",
Andrey Ponomarenko01117f12012-06-26 12:23:02 +04007264 "siginfo",
7265 "mallinfo"
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007266);
7267
7268sub getCompileCmd($$$)
7269{
7270 my ($Path, $Opt, $Inc) = @_;
7271 my $GccCall = $GCC_PATH;
7272 if($Opt) {
7273 $GccCall .= " ".$Opt;
7274 }
7275 $GccCall .= " -x ";
7276 if($OSgroup eq "macos") {
7277 $GccCall .= "objective-";
7278 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04007279 if(check_gcc($GCC_PATH, "4"))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007280 { # compile as "C++" header
7281 # to obtain complete dump using GCC 4.0
7282 $GccCall .= "c++-header";
7283 }
7284 else
7285 { # compile as "C++" source
7286 # GCC 3.3 cannot compile headers
7287 $GccCall .= "c++";
7288 }
7289 if(my $Opts = platformSpecs($Version))
7290 {# platform-specific options
7291 $GccCall .= " ".$Opts;
7292 }
7293 # allow extra qualifications
7294 # and other nonconformant code
Andrey Ponomarenko01117f12012-06-26 12:23:02 +04007295 $GccCall .= " -fpermissive";
7296 $GccCall .= " -w";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007297 if($NoStdInc)
7298 {
7299 $GccCall .= " -nostdinc";
7300 $GccCall .= " -nostdinc++";
7301 }
7302 if($CompilerOptions{$Version})
7303 { # user-defined options
7304 $GccCall .= " ".$CompilerOptions{$Version};
7305 }
Andrey Ponomarenkoa01311b2012-06-08 17:20:02 +04007306 $GccCall .= " \"$Path\"";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007307 if($Inc)
7308 { # include paths
7309 $GccCall .= " ".$Inc;
7310 }
7311 return $GccCall;
7312}
7313
Andrey Ponomarenko01117f12012-06-26 12:23:02 +04007314sub detectPreamble($$)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007315{
Andrey Ponomarenko01117f12012-06-26 12:23:02 +04007316 my ($Content, $LibVersion) = @_;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007317 my %HeaderElems = (
7318 # Types
7319 "stdio.h" => ["FILE", "va_list"],
Andrey Ponomarenko85043792012-05-14 16:48:07 +04007320 "stddef.h" => ["NULL", "ptrdiff_t"],
Andrey Ponomarenko9927e332012-10-19 10:50:48 +04007321 "stdint.h" => ["uint8_t", "uint16_t", "uint32_t", "uint64_t",
7322 "int8_t", "int16_t", "int32_t", "int64_t"],
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007323 "time.h" => ["time_t"],
7324 "sys/types.h" => ["ssize_t", "u_int32_t", "u_short", "u_char",
Andrey Ponomarenko9927e332012-10-19 10:50:48 +04007325 "u_int", "off_t", "u_quad_t", "u_long", "mode_t"],
7326 "unistd.h" => ["gid_t", "uid_t", "socklen_t"],
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007327 "stdbool.h" => ["_Bool"],
7328 "rpc/xdr.h" => ["bool_t"],
7329 "in_systm.h" => ["n_long", "n_short"],
7330 # Fields
Andrey Ponomarenkobede8372012-03-29 17:43:21 +04007331 "arpa/inet.h" => ["fw_src", "ip_src"],
7332 # Functions
Andrey Ponomarenko9927e332012-10-19 10:50:48 +04007333 "stdlib.h" => ["free", "malloc", "size_t"],
Andrey Ponomarenko85043792012-05-14 16:48:07 +04007334 "string.h" => ["memmove", "strcmp"]
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007335 );
7336 my %AutoPreamble = ();
Andrey Ponomarenko85043792012-05-14 16:48:07 +04007337 foreach (keys(%HeaderElems))
7338 {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007339 foreach my $Elem (@{$HeaderElems{$_}}) {
Andrey Ponomarenko9927e332012-10-19 10:50:48 +04007340 $AutoPreamble{$Elem} = $_;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007341 }
7342 }
Andrey Ponomarenko01117f12012-06-26 12:23:02 +04007343 my %Types = ();
7344 while($Content=~s/error\:\s*(field\s*|)\W+(.+?)\W+//)
7345 { # error: 'FILE' has not been declared
Andrey Ponomarenko9927e332012-10-19 10:50:48 +04007346 $Types{$2} = 1;
Andrey Ponomarenko01117f12012-06-26 12:23:02 +04007347 }
7348 if(keys(%Types))
7349 {
7350 my %AddHeaders = ();
7351 foreach my $Type (keys(%Types))
7352 {
7353 if(my $Header = $AutoPreamble{$Type})
7354 {
Andrey Ponomarenko9927e332012-10-19 10:50:48 +04007355 if(my $Path = identifyHeader($Header, $LibVersion))
7356 {
7357 if(skipHeader($Path, $LibVersion)) {
7358 next;
7359 }
7360 $Path = path_format($Path, $OSgroup);
7361 $AddHeaders{$Path}{"Type"} = $Type;
7362 $AddHeaders{$Path}{"Header"} = $Header;
Andrey Ponomarenko01117f12012-06-26 12:23:02 +04007363 }
7364 }
7365 }
7366 if(keys(%AddHeaders)) {
Andrey Ponomarenko9927e332012-10-19 10:50:48 +04007367 return \%AddHeaders;
Andrey Ponomarenko01117f12012-06-26 12:23:02 +04007368 }
7369 }
Andrey Ponomarenko9927e332012-10-19 10:50:48 +04007370 return undef;
Andrey Ponomarenko01117f12012-06-26 12:23:02 +04007371}
7372
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +04007373sub checkCTags($)
7374{
7375 my $Path = $_[0];
7376 if(not $Path) {
7377 return;
7378 }
7379 my $CTags = get_CmdPath("ctags");
7380 if(not $CTags) {
7381 return;
7382 }
7383 my $Out = $TMP_DIR."/ctags.txt";
Andrey Ponomarenko9927e332012-10-19 10:50:48 +04007384 system("$CTags --c-kinds=pxn -f \"$Out\" \"$Path\"");
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +04007385 if($Debug) {
Andrey Ponomarenko9927e332012-10-19 10:50:48 +04007386 copy($Out, $DEBUG_PATH{$Version}."/ctags.txt");
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +04007387 }
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +04007388 open(CTAGS, "<", $Out);
7389 while(my $Line = <CTAGS>)
7390 {
7391 chomp($Line);
7392 my ($Name, $Header, $Def, $Type, $Scpe) = split(/\t/, $Line);
Andrey Ponomarenko9927e332012-10-19 10:50:48 +04007393 if(defined $Intrinsic_Keywords{$Name})
7394 { # noise
7395 next;
7396 }
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +04007397 if($Type eq "n")
7398 {
Andrey Ponomarenko9927e332012-10-19 10:50:48 +04007399 if(index($Scpe, "class:")==0) {
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +04007400 next;
7401 }
Andrey Ponomarenko9927e332012-10-19 10:50:48 +04007402 if(index($Scpe, "struct:")==0) {
7403 next;
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +04007404 }
Andrey Ponomarenko9927e332012-10-19 10:50:48 +04007405 if(index($Scpe, "namespace:")==0)
7406 {
7407 if($Scpe=~s/\Anamespace://) {
7408 $Name = $Scpe."::".$Name;
7409 }
7410 }
7411 $TUnit_NameSpaces{$Version}{$Name} = 1;
7412 }
7413 elsif($Type eq "p")
7414 {
7415 if(not $Scpe or index($Scpe, "namespace:")==0) {
7416 $TUnit_Funcs{$Version}{$Name} = 1;
7417 }
7418 }
7419 elsif($Type eq "x")
7420 {
7421 if(not $Scpe or index($Scpe, "namespace:")==0) {
7422 $TUnit_Vars{$Version}{$Name} = 1;
7423 }
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +04007424 }
7425 }
7426 close(CTAGS);
7427}
7428
Andrey Ponomarenko01117f12012-06-26 12:23:02 +04007429sub getDump()
7430{
7431 if(not $GCC_PATH) {
7432 exitStatus("Error", "internal error - GCC path is not set");
7433 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04007434 my $TmpHeaderPath = $TMP_DIR."/dump".$Version.".h";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007435 my $MHeaderPath = $TmpHeaderPath;
Andrey Ponomarenko85043792012-05-14 16:48:07 +04007436 open(TMP_HEADER, ">", $TmpHeaderPath) || die ("can't open file \'$TmpHeaderPath\': $!\n");
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007437 if(my $AddDefines = $Descriptor{$Version}{"Defines"})
7438 {
7439 $AddDefines=~s/\n\s+/\n /g;
Andrey Ponomarenko85043792012-05-14 16:48:07 +04007440 print TMP_HEADER "\n // add defines\n ".$AddDefines."\n";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007441 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +04007442 print TMP_HEADER "\n // add includes\n";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007443 my @PreambleHeaders = keys(%{$Include_Preamble{$Version}});
7444 @PreambleHeaders = sort {int($Include_Preamble{$Version}{$a}{"Position"})<=>int($Include_Preamble{$Version}{$b}{"Position"})} @PreambleHeaders;
7445 foreach my $Header_Path (@PreambleHeaders) {
Andrey Ponomarenko85043792012-05-14 16:48:07 +04007446 print TMP_HEADER " #include \"".path_format($Header_Path, "unix")."\"\n";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007447 }
7448 my @Headers = keys(%{$Registered_Headers{$Version}});
7449 @Headers = sort {int($Registered_Headers{$Version}{$a}{"Pos"})<=>int($Registered_Headers{$Version}{$b}{"Pos"})} @Headers;
7450 foreach my $Header_Path (@Headers)
7451 {
7452 next if($Include_Preamble{$Version}{$Header_Path});
Andrey Ponomarenko85043792012-05-14 16:48:07 +04007453 print TMP_HEADER " #include \"".path_format($Header_Path, "unix")."\"\n";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007454 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +04007455 close(TMP_HEADER);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007456 my $IncludeString = getIncString(getIncPaths(@PreambleHeaders, @Headers), "GCC");
Andrey Ponomarenko9927e332012-10-19 10:50:48 +04007457
7458 if(not keys(%{$TargetHeaders{$Version}}))
7459 { # Target headers
7460 addTargetHeaders($Version);
7461 }
7462
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007463 if($Debug)
7464 { # debug mode
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04007465 writeFile($DEBUG_PATH{$Version}."/headers/direct-includes.txt", Dumper($Header_Includes{$Version}));
7466 writeFile($DEBUG_PATH{$Version}."/headers/recursive-includes.txt", Dumper($RecursiveIncludes{$Version}));
7467 writeFile($DEBUG_PATH{$Version}."/headers/include-paths.txt", Dumper($Cache{"get_HeaderDeps"}{$Version}));
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04007468 writeFile($DEBUG_PATH{$Version}."/headers/default-paths.txt", Dumper(\%DefaultIncPaths));
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007469 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +04007470
Andrey Ponomarenko85043792012-05-14 16:48:07 +04007471 # clean memory
7472 %RecursiveIncludes = ();
7473 %Header_Include_Prefix = ();
7474 %Header_Includes = ();
7475
7476 # clean cache
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04007477 delete($Cache{"identifyHeader"});
Andrey Ponomarenko85043792012-05-14 16:48:07 +04007478 delete($Cache{"detect_header_includes"});
7479 delete($Cache{"selectSystemHeader"});
7480
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007481 # preprocessing stage
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +04007482 my $Pre = callPreprocessor($TmpHeaderPath, $IncludeString, $Version);
7483 checkPreprocessedUnit($Pre);
Andrey Ponomarenko85043792012-05-14 16:48:07 +04007484
7485 # clean memory
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04007486 delete($Include_Neighbors{$Version});
Andrey Ponomarenko85043792012-05-14 16:48:07 +04007487
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +04007488 if($COMMON_LANGUAGE{$Version} eq "C++") {
7489 checkCTags($Pre);
7490 }
7491
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007492 my $MContent = "";
7493 my $PreprocessCmd = getCompileCmd($TmpHeaderPath, "-E", $IncludeString);
7494 if($OStarget eq "windows"
7495 and get_dumpmachine($GCC_PATH)=~/mingw/i
7496 and $MinGWMode{$Version}!=-1)
7497 { # modify headers to compile by MinGW
7498 if(not $MContent)
7499 { # preprocessing
Andrey Ponomarenkoa01311b2012-06-08 17:20:02 +04007500 $MContent = `$PreprocessCmd 2>\"$TMP_DIR/null\"`;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007501 }
7502 if($MContent=~s/__asm\s*(\{[^{}]*?\}|[^{};]*)//g)
7503 { # __asm { ... }
7504 $MinGWMode{$Version}=1;
7505 }
7506 if($MContent=~s/\s+(\/ \/.*?)\n/\n/g)
7507 { # comments after preprocessing
7508 $MinGWMode{$Version}=1;
7509 }
7510 if($MContent=~s/(\W)(0x[a-f]+|\d+)(i|ui)(8|16|32|64)(\W)/$1$2$5/g)
7511 { # 0xffui8
7512 $MinGWMode{$Version}=1;
7513 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +04007514 if($MinGWMode{$Version})
7515 {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007516 printMsg("INFO", "Using MinGW compatibility mode");
Andrey Ponomarenkob8d203d2012-05-25 18:11:07 +04007517 $MHeaderPath = $TMP_DIR."/dump$Version.i";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007518 }
7519 }
7520 if(($COMMON_LANGUAGE{$Version} eq "C" or $CheckHeadersOnly)
7521 and $C99Mode{$Version}!=-1 and not $Cpp2003)
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04007522 { # rename C++ keywords in C code
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007523 if(not $MContent)
7524 { # preprocessing
Andrey Ponomarenkoa01311b2012-06-08 17:20:02 +04007525 $MContent = `$PreprocessCmd 2>\"$TMP_DIR/null\"`;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007526 }
7527 my $RegExp_C = join("|", keys(%CppKeywords_C));
7528 my $RegExp_F = join("|", keys(%CppKeywords_F));
7529 my $RegExp_O = join("|", keys(%CppKeywords_O));
7530 while($MContent=~s/(\A|\n[^\#\/\n][^\n]*?|\n)(\*\s*|\s+|\@|\,|\()($RegExp_C|$RegExp_F)(\s*(\,|\)|\;|\-\>|\.|\:\s*\d))/$1$2c99_$3$4/g)
7531 { # MATCH:
7532 # int foo(int new, int class, int (*new)(int));
7533 # unsigned private: 8;
7534 # DO NOT MATCH:
7535 # #pragma GCC visibility push(default)
7536 $C99Mode{$Version} = 1;
7537 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04007538 if($MContent=~s/([^\w\s]|\w\s+)(?<!operator )(delete)(\s*\()/$1c99_$2$3/g)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007539 { # MATCH:
7540 # int delete(...);
7541 # int explicit(...);
7542 # DO NOT MATCH:
7543 # void operator delete(...)
7544 $C99Mode{$Version} = 1;
7545 }
7546 if($MContent=~s/(\s+)($RegExp_O)(\s*(\;|\:))/$1c99_$2$3/g)
7547 { # MATCH:
7548 # int bool;
7549 # DO NOT MATCH:
7550 # bool X;
7551 # return *this;
7552 # throw;
7553 $C99Mode{$Version} = 1;
7554 }
7555 if($MContent=~s/(\s+)(operator)(\s*(\(\s*\)\s*[^\(\s]|\(\s*[^\)\s]))/$1c99_$2$3/g)
7556 { # MATCH:
7557 # int operator(...);
7558 # DO NOT MATCH:
7559 # int operator()(...);
7560 $C99Mode{$Version} = 1;
7561 }
7562 if($MContent=~s/([^\w\(\,\s]\s*|\s+)(operator)(\s*(\,\s*[^\(\s]|\)))/$1c99_$2$3/g)
7563 { # MATCH:
7564 # int foo(int operator);
7565 # int foo(int operator, int other);
7566 # DO NOT MATCH:
7567 # int operator,(...);
7568 $C99Mode{$Version} = 1;
7569 }
7570 if($MContent=~s/(\*\s*|\w\s+)(bool)(\s*(\,|\)))/$1c99_$2$3/g)
7571 { # MATCH:
7572 # int foo(gboolean *bool);
7573 # DO NOT MATCH:
7574 # void setTabEnabled(int index, bool);
7575 $C99Mode{$Version} = 1;
7576 }
Andrey Ponomarenko9927e332012-10-19 10:50:48 +04007577 if($MContent=~s/(\w)(\s*[^\w\(\,\s]\s*|\s+)(this|throw)(\s*[\,\)])/$1$2c99_$3$4/g)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007578 { # MATCH:
7579 # int foo(int* this);
7580 # int bar(int this);
Andrey Ponomarenko9927e332012-10-19 10:50:48 +04007581 # int baz(int throw);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007582 # DO NOT MATCH:
Andrey Ponomarenko9927e332012-10-19 10:50:48 +04007583 # foo(X, this);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007584 $C99Mode{$Version} = 1;
7585 }
Andrey Ponomarenko9927e332012-10-19 10:50:48 +04007586
7587 # remove typedef enum NAME NAME;
7588 my @FwdTypedefs = $MContent=~/typedef\s+enum\s+(\w+)\s+(\w+);/g;
7589 my $N = 0;
7590 while($N<=$#FwdTypedefs-1)
7591 {
7592 my $S = $FwdTypedefs[$N];
7593 if($S eq $FwdTypedefs[$N+1])
7594 {
7595 $MContent=~s/typedef\s+enum\s+\Q$S\E\s+\Q$S\E;//g;
7596 $C99Mode{$Version}=1;
7597 }
7598 $N+=2;
7599 }
7600
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007601 if($C99Mode{$Version}==1)
7602 { # try to change C++ "keyword" to "c99_keyword"
7603 printMsg("INFO", "Using C99 compatibility mode");
Andrey Ponomarenkob8d203d2012-05-25 18:11:07 +04007604 $MHeaderPath = $TMP_DIR."/dump$Version.i";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007605 }
7606 }
7607 if($C99Mode{$Version}==1
7608 or $MinGWMode{$Version}==1)
7609 { # compile the corrected preprocessor output
7610 writeFile($MHeaderPath, $MContent);
7611 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +04007612
7613 # clean memory
7614 undef $MContent;
7615
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007616 if($COMMON_LANGUAGE{$Version} eq "C++")
7617 { # add classes and namespaces to the dump
7618 my $CHdump = "-fdump-class-hierarchy -c";
7619 if($C99Mode{$Version}==1
7620 or $MinGWMode{$Version}==1) {
7621 $CHdump .= " -fpreprocessed";
7622 }
7623 my $ClassHierarchyCmd = getCompileCmd($MHeaderPath, $CHdump, $IncludeString);
7624 chdir($TMP_DIR);
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04007625 system($ClassHierarchyCmd." >null 2>&1");
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007626 chdir($ORIG_DIR);
7627 if(my $ClassDump = (cmd_find($TMP_DIR,"f","*.class",1))[0])
7628 {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007629 my $Content = readFile($ClassDump);
7630 foreach my $ClassInfo (split(/\n\n/, $Content))
7631 {
7632 if($ClassInfo=~/\AClass\s+(.+)\s*/i)
7633 {
7634 my $CName = $1;
7635 next if($CName=~/\A(__|_objc_|_opaque_)/);
7636 $TUnit_NameSpaces{$Version}{$CName} = -1;
7637 if($CName=~/\A[\w:]+\Z/)
7638 { # classes
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +04007639 $TUnit_Classes{$Version}{$CName} = 1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007640 }
7641 if($CName=~/(\w[\w:]*)::/)
7642 { # namespaces
7643 my $NS = $1;
7644 if(not defined $TUnit_NameSpaces{$Version}{$NS}) {
7645 $TUnit_NameSpaces{$Version}{$NS} = 1;
7646 }
7647 }
7648 }
7649 elsif($ClassInfo=~/\AVtable\s+for\s+(.+)\n((.|\n)+)\Z/i)
7650 { # read v-tables (advanced approach)
7651 my ($CName, $VTable) = ($1, $2);
7652 $ClassVTable_Content{$Version}{$CName} = $VTable;
7653 }
7654 }
Andrey Ponomarenkoa01311b2012-06-08 17:20:02 +04007655 foreach my $NS (keys(%{$AddNameSpaces{$Version}}))
7656 { # add user-defined namespaces
7657 $TUnit_NameSpaces{$Version}{$NS} = 1;
7658 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007659 if($Debug)
7660 { # debug mode
7661 mkpath($DEBUG_PATH{$Version});
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04007662 copy($ClassDump, $DEBUG_PATH{$Version}."/class-hierarchy-dump.txt");
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007663 }
7664 unlink($ClassDump);
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +04007665 }
7666
7667 # add namespaces and classes
7668 if(my $NS_Add = get_namespace_additions($TUnit_NameSpaces{$Version}))
7669 { # GCC on all supported platforms does not include namespaces to the dump by default
7670 appendFile($MHeaderPath, "\n // add namespaces\n".$NS_Add);
7671 }
7672 # some GCC versions don't include class methods to the TU dump by default
7673 my ($AddClass, $ClassNum) = ("", 0);
7674 foreach my $CName (sort keys(%{$TUnit_Classes{$Version}}))
7675 {
7676 next if($C_Structure{$CName});
7677 next if(not $STDCXX_TESTING and $CName=~/\Astd::/);
7678 next if(($CName=~tr![:]!!)>2);
7679 next if($SkipTypes{$Version}{$CName});
7680 if($CName=~/\A(.+)::[^:]+\Z/)
7681 { # will be added by name space
7682 next;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007683 }
Andrey Ponomarenko9927e332012-10-19 10:50:48 +04007684 if(defined $TUnit_Funcs{$Version}{$CName})
7685 { # the same name for a function and type
7686 next;
7687 }
7688 if(defined $TUnit_Vars{$Version}{$CName})
7689 { # the same name for a variable and type
7690 next;
7691 }
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +04007692 $AddClass .= " $CName* tmp_add_class_".($ClassNum++).";\n";
7693 }
7694 if($AddClass) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007695 appendFile($MHeaderPath, "\n // add classes\n".$AddClass);
7696 }
7697 }
7698 writeLog($Version, "Temporary header file \'$TmpHeaderPath\' with the following content will be compiled to create GCC translation unit dump:\n".readFile($TmpHeaderPath)."\n");
7699 # create TU dump
7700 my $TUdump = "-fdump-translation-unit -fkeep-inline-functions -c";
7701 if($C99Mode{$Version}==1
7702 or $MinGWMode{$Version}==1) {
7703 $TUdump .= " -fpreprocessed";
7704 }
7705 my $SyntaxTreeCmd = getCompileCmd($MHeaderPath, $TUdump, $IncludeString);
7706 writeLog($Version, "The GCC parameters:\n $SyntaxTreeCmd\n\n");
7707 chdir($TMP_DIR);
Andrey Ponomarenkoa01311b2012-06-08 17:20:02 +04007708 system($SyntaxTreeCmd." >\"$TMP_DIR/tu_errors\" 2>&1");
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007709 if($?)
7710 { # failed to compile, but the TU dump still can be created
Andrey Ponomarenko01117f12012-06-26 12:23:02 +04007711 if(my $Errors = readFile($TMP_DIR."/tu_errors"))
7712 { # try to recompile
7713 # FIXME: handle other errors and try to recompile
7714 if($C99Mode{$Version}==1
7715 and $Errors=~/c99_/)
7716 { # disable c99 mode and try again
7717 $C99Mode{$Version}=-1;
7718 printMsg("INFO", "Disabling C99 compatibility mode");
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007719 resetLogging($Version);
7720 $TMP_DIR = tempdir(CLEANUP=>1);
7721 return getDump();
7722 }
Andrey Ponomarenko01117f12012-06-26 12:23:02 +04007723 elsif($AutoPreambleMode{$Version}!=-1
Andrey Ponomarenko9927e332012-10-19 10:50:48 +04007724 and my $AddHeaders = detectPreamble($Errors, $Version))
Andrey Ponomarenko01117f12012-06-26 12:23:02 +04007725 { # add auto preamble headers and try again
7726 $AutoPreambleMode{$Version}=-1;
Andrey Ponomarenko9927e332012-10-19 10:50:48 +04007727 my @Headers = sort {$b cmp $a} keys(%{$AddHeaders}); # sys/types.h should be the first
Andrey Ponomarenko01117f12012-06-26 12:23:02 +04007728 foreach my $Num (0 .. $#Headers)
7729 {
7730 my $Path = $Headers[$Num];
7731 if(defined $Include_Preamble{$Version}{$Path})
7732 { # already added
7733 next;
7734 }
7735 $Include_Preamble{$Version}{$Path}{"Position"} = keys(%{$Include_Preamble{$Version}});
Andrey Ponomarenko9927e332012-10-19 10:50:48 +04007736 printMsg("INFO", "Add \'".$AddHeaders->{$Path}{"Header"}."\' preamble header for \'".$AddHeaders->{$Path}{"Type"}."\'");
Andrey Ponomarenko01117f12012-06-26 12:23:02 +04007737 }
7738 resetLogging($Version);
7739 $TMP_DIR = tempdir(CLEANUP=>1);
7740 return getDump();
7741 }
7742 elsif($Cpp0xMode{$Version}!=-1
7743 and ($Errors=~/\Q-std=c++0x\E/
7744 or $Errors=~/is not a class or namespace/))
7745 { # c++0x: enum class
7746 $Cpp0xMode{$Version}=-1;
7747 printMsg("INFO", "Enabling c++0x mode");
7748 resetLogging($Version);
7749 $TMP_DIR = tempdir(CLEANUP=>1);
7750 $CompilerOptions{$Version} .= " -std=c++0x";
7751 return getDump();
7752 }
7753 elsif($MinGWMode{$Version}==1)
7754 { # disable MinGW mode and try again
7755 $MinGWMode{$Version}=-1;
7756 resetLogging($Version);
7757 $TMP_DIR = tempdir(CLEANUP=>1);
7758 return getDump();
7759 }
7760 writeLog($Version, $Errors);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007761 }
Andrey Ponomarenko01117f12012-06-26 12:23:02 +04007762 else {
7763 writeLog($Version, "$!: $?\n");
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007764 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007765 printMsg("ERROR", "some errors occurred when compiling headers");
7766 printErrorLog($Version);
7767 $COMPILE_ERRORS = $ERROR_CODE{"Compile_Error"};
7768 writeLog($Version, "\n");# new line
7769 }
7770 chdir($ORIG_DIR);
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +04007771 unlink($TmpHeaderPath);
7772 unlink($MHeaderPath);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007773 return (cmd_find($TMP_DIR,"f","*.tu",1))[0];
7774}
7775
7776sub cmd_file($)
7777{
7778 my $Path = $_[0];
7779 return "" if(not $Path or not -e $Path);
7780 if(my $CmdPath = get_CmdPath("file")) {
7781 return `$CmdPath -b \"$Path\"`;
7782 }
7783 return "";
7784}
7785
7786sub getIncString($$)
7787{
7788 my ($ArrRef, $Style) = @_;
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04007789 return "" if(not $ArrRef or $#{$ArrRef}<0);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007790 my $String = "";
7791 foreach (@{$ArrRef}) {
7792 $String .= " ".inc_opt($_, $Style);
7793 }
7794 return $String;
7795}
7796
7797sub getIncPaths(@)
7798{
7799 my @HeaderPaths = @_;
7800 my @IncPaths = ();
7801 if($INC_PATH_AUTODETECT{$Version})
7802 { # auto-detecting dependencies
7803 my %Includes = ();
7804 foreach my $HPath (@HeaderPaths)
7805 {
7806 foreach my $Dir (get_HeaderDeps($HPath, $Version))
7807 {
7808 if($Skip_Include_Paths{$Version}{$Dir}) {
7809 next;
7810 }
Andrey Ponomarenkoa01311b2012-06-08 17:20:02 +04007811 if($SystemRoot)
7812 {
7813 if($Skip_Include_Paths{$Version}{$SystemRoot.$Dir}) {
7814 next;
7815 }
7816 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007817 $Includes{$Dir}=1;
7818 }
7819 }
7820 foreach my $Dir (keys(%{$Add_Include_Paths{$Version}}))
7821 { # added by user
7822 next if($Includes{$Dir});
7823 push(@IncPaths, $Dir);
7824 }
7825 foreach my $Dir (@{sortIncPaths([keys(%Includes)], $Version)}) {
7826 push(@IncPaths, $Dir);
7827 }
7828 }
7829 else
7830 { # user-defined paths
7831 foreach my $Dir (sort {get_depth($a)<=>get_depth($b)}
7832 sort {$b cmp $a} keys(%{$Include_Paths{$Version}})) {
7833 push(@IncPaths, $Dir);
7834 }
7835 }
7836 return \@IncPaths;
7837}
7838
7839sub callPreprocessor($$$)
7840{
7841 my ($Path, $Inc, $LibVersion) = @_;
7842 return "" if(not $Path or not -f $Path);
7843 my $IncludeString=$Inc;
7844 if(not $Inc) {
7845 $IncludeString = getIncString(getIncPaths($Path), "GCC");
7846 }
7847 my $Cmd = getCompileCmd($Path, "-dD -E", $IncludeString);
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +04007848 my $Out = $TMP_DIR."/preprocessed.h";
Andrey Ponomarenkoa01311b2012-06-08 17:20:02 +04007849 system($Cmd." >\"$Out\" 2>\"$TMP_DIR/null\"");
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04007850 return $Out;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007851}
7852
7853sub cmd_find($$$$)
7854{ # native "find" is much faster than File::Find (~6x)
7855 # also the File::Find doesn't support --maxdepth N option
7856 # so using the cross-platform wrapper for the native one
7857 my ($Path, $Type, $Name, $MaxDepth) = @_;
7858 return () if(not $Path or not -e $Path);
7859 if($OSgroup eq "windows")
7860 {
7861 my $DirCmd = get_CmdPath("dir");
7862 if(not $DirCmd) {
7863 exitStatus("Not_Found", "can't find \"dir\" command");
7864 }
7865 $Path=~s/[\\]+\Z//;
7866 $Path = get_abs_path($Path);
7867 $Path = path_format($Path, $OSgroup);
7868 my $Cmd = $DirCmd." \"$Path\" /B /O";
7869 if($MaxDepth!=1) {
7870 $Cmd .= " /S";
7871 }
7872 if($Type eq "d") {
7873 $Cmd .= " /AD";
7874 }
7875 my @Files = ();
7876 if($Name)
7877 { # FIXME: how to search file names in MS shell?
7878 $Name=~s/\*/.*/g if($Name!~/\]/);
7879 foreach my $File (split(/\n/, `$Cmd`))
7880 {
7881 if($File=~/$Name\Z/i) {
7882 push(@Files, $File);
7883 }
7884 }
7885 }
7886 else {
Andrey Ponomarenkoa01311b2012-06-08 17:20:02 +04007887 @Files = split(/\n/, `$Cmd 2>\"$TMP_DIR/null\"`);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007888 }
7889 my @AbsPaths = ();
7890 foreach my $File (@Files)
7891 {
7892 if(not is_abs($File)) {
7893 $File = joinPath($Path, $File);
7894 }
7895 if($Type eq "f" and not -f $File)
7896 { # skip dirs
7897 next;
7898 }
7899 push(@AbsPaths, path_format($File, $OSgroup));
7900 }
7901 if($Type eq "d") {
7902 push(@AbsPaths, $Path);
7903 }
7904 return @AbsPaths;
7905 }
7906 else
7907 {
7908 my $FindCmd = get_CmdPath("find");
7909 if(not $FindCmd) {
7910 exitStatus("Not_Found", "can't find a \"find\" command");
7911 }
7912 $Path = get_abs_path($Path);
7913 if(-d $Path and -l $Path
7914 and $Path!~/\/\Z/)
7915 { # for directories that are symlinks
7916 $Path.="/";
7917 }
7918 my $Cmd = $FindCmd." \"$Path\"";
7919 if($MaxDepth) {
7920 $Cmd .= " -maxdepth $MaxDepth";
7921 }
7922 if($Type) {
7923 $Cmd .= " -type $Type";
7924 }
7925 if($Name)
7926 { # file name
7927 if($Name=~/\]/) {
7928 $Cmd .= " -regex \"$Name\"";
7929 }
7930 else {
7931 $Cmd .= " -name \"$Name\"";
7932 }
7933 }
Andrey Ponomarenko9927e332012-10-19 10:50:48 +04007934 my $Res = `$Cmd 2>\"$TMP_DIR/null\"`;
7935 if($?) {
7936 printMsg("ERROR", "problem with \'find\' utility ($?): $!");
7937 }
7938 return split(/\n/, $Res);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007939 }
7940}
7941
7942sub unpackDump($)
7943{
7944 my $Path = $_[0];
7945 return "" if(not $Path or not -e $Path);
7946 $Path = get_abs_path($Path);
7947 $Path = path_format($Path, $OSgroup);
7948 my ($Dir, $FileName) = separate_path($Path);
7949 my $UnpackDir = $TMP_DIR."/unpack";
7950 rmtree($UnpackDir);
7951 mkpath($UnpackDir);
7952 if($FileName=~s/\Q.zip\E\Z//g)
7953 { # *.zip
7954 my $UnzipCmd = get_CmdPath("unzip");
7955 if(not $UnzipCmd) {
7956 exitStatus("Not_Found", "can't find \"unzip\" command");
7957 }
7958 chdir($UnpackDir);
Andrey Ponomarenkoa01311b2012-06-08 17:20:02 +04007959 system("$UnzipCmd \"$Path\" >contents.txt");
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007960 if($?) {
7961 exitStatus("Error", "can't extract \'$Path\'");
7962 }
7963 chdir($ORIG_DIR);
7964 my @Contents = ();
7965 foreach (split("\n", readFile("$UnpackDir/contents.txt")))
7966 {
7967 if(/inflating:\s*([^\s]+)/) {
7968 push(@Contents, $1);
7969 }
7970 }
7971 if(not @Contents) {
7972 exitStatus("Error", "can't extract \'$Path\'");
7973 }
7974 return joinPath($UnpackDir, $Contents[0]);
7975 }
7976 elsif($FileName=~s/\Q.tar.gz\E\Z//g)
7977 { # *.tar.gz
7978 if($OSgroup eq "windows")
7979 { # -xvzf option is not implemented in tar.exe (2003)
7980 # use "gzip.exe -k -d -f" + "tar.exe -xvf" instead
7981 my $TarCmd = get_CmdPath("tar");
7982 if(not $TarCmd) {
7983 exitStatus("Not_Found", "can't find \"tar\" command");
7984 }
7985 my $GzipCmd = get_CmdPath("gzip");
7986 if(not $GzipCmd) {
7987 exitStatus("Not_Found", "can't find \"gzip\" command");
7988 }
7989 chdir($UnpackDir);
Andrey Ponomarenkoa01311b2012-06-08 17:20:02 +04007990 system("$GzipCmd -k -d -f \"$Path\""); # keep input files (-k)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007991 if($?) {
7992 exitStatus("Error", "can't extract \'$Path\'");
7993 }
Andrey Ponomarenkoa01311b2012-06-08 17:20:02 +04007994 system("$TarCmd -xvf \"$Dir\\$FileName.tar\" >contents.txt");
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007995 if($?) {
7996 exitStatus("Error", "can't extract \'$Path\'");
7997 }
7998 chdir($ORIG_DIR);
7999 unlink($Dir."/".$FileName.".tar");
8000 my @Contents = split("\n", readFile("$UnpackDir/contents.txt"));
8001 if(not @Contents) {
8002 exitStatus("Error", "can't extract \'$Path\'");
8003 }
8004 return joinPath($UnpackDir, $Contents[0]);
8005 }
8006 else
8007 { # Unix
8008 my $TarCmd = get_CmdPath("tar");
8009 if(not $TarCmd) {
8010 exitStatus("Not_Found", "can't find \"tar\" command");
8011 }
8012 chdir($UnpackDir);
Andrey Ponomarenkoa01311b2012-06-08 17:20:02 +04008013 system("$TarCmd -xvzf \"$Path\" >contents.txt");
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008014 if($?) {
8015 exitStatus("Error", "can't extract \'$Path\'");
8016 }
8017 chdir($ORIG_DIR);
8018 # The content file name may be different
8019 # from the package file name
8020 my @Contents = split("\n", readFile("$UnpackDir/contents.txt"));
8021 if(not @Contents) {
8022 exitStatus("Error", "can't extract \'$Path\'");
8023 }
8024 return joinPath($UnpackDir, $Contents[0]);
8025 }
8026 }
8027}
8028
8029sub createArchive($$)
8030{
8031 my ($Path, $To) = @_;
Andrey Ponomarenko5c09ef32012-06-14 18:17:33 +04008032 if(not $To) {
8033 $To = ".";
8034 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008035 if(not $Path or not -e $Path
8036 or not -d $To) {
8037 return "";
8038 }
8039 my ($From, $Name) = separate_path($Path);
8040 if($OSgroup eq "windows")
8041 { # *.zip
8042 my $ZipCmd = get_CmdPath("zip");
8043 if(not $ZipCmd) {
8044 exitStatus("Not_Found", "can't find \"zip\"");
8045 }
8046 my $Pkg = $To."/".$Name.".zip";
8047 unlink($Pkg);
8048 chdir($To);
Andrey Ponomarenkoa01311b2012-06-08 17:20:02 +04008049 system("$ZipCmd -j \"$Name.zip\" \"$Path\" >\"$TMP_DIR/null\"");
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008050 if($?)
8051 { # cannot allocate memory (or other problems with "zip")
8052 unlink($Path);
8053 exitStatus("Error", "can't pack the ABI dump: ".$!);
8054 }
8055 chdir($ORIG_DIR);
8056 unlink($Path);
8057 return $Pkg;
8058 }
8059 else
8060 { # *.tar.gz
8061 my $TarCmd = get_CmdPath("tar");
8062 if(not $TarCmd) {
8063 exitStatus("Not_Found", "can't find \"tar\"");
8064 }
8065 my $GzipCmd = get_CmdPath("gzip");
8066 if(not $GzipCmd) {
8067 exitStatus("Not_Found", "can't find \"gzip\"");
8068 }
8069 my $Pkg = abs_path($To)."/".$Name.".tar.gz";
8070 unlink($Pkg);
8071 chdir($From);
8072 system($TarCmd, "-czf", $Pkg, $Name);
8073 if($?)
8074 { # cannot allocate memory (or other problems with "tar")
8075 unlink($Path);
8076 exitStatus("Error", "can't pack the ABI dump: ".$!);
8077 }
8078 chdir($ORIG_DIR);
8079 unlink($Path);
8080 return $To."/".$Name.".tar.gz";
8081 }
8082}
8083
Andrey Ponomarenko9927e332012-10-19 10:50:48 +04008084sub readBytes($)
8085{
8086 sysopen(FILE, $_[0], O_RDONLY);
8087 sysread(FILE, my $Header, 4);
8088 close(FILE);
8089 my @Bytes = map { sprintf('%02x', ord($_)) } split (//, $Header);
8090 return join("", @Bytes);
8091}
8092
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008093sub is_header_file($)
8094{
8095 if($_[0]=~/\.($HEADER_EXT)\Z/i) {
8096 return $_[0];
8097 }
8098 return 0;
8099}
8100
8101sub is_not_header($)
8102{
8103 if($_[0]=~/\.\w+\Z/
8104 and $_[0]!~/\.($HEADER_EXT)\Z/i) {
8105 return 1;
8106 }
8107 return 0;
8108}
8109
8110sub is_header($$$)
8111{
8112 my ($Header, $UserDefined, $LibVersion) = @_;
8113 return 0 if(-d $Header);
8114 if(-f $Header) {
8115 $Header = get_abs_path($Header);
8116 }
8117 else
8118 {
8119 if(is_abs($Header))
8120 { # incorrect absolute path
8121 return 0;
8122 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04008123 if(my $HPath = identifyHeader($Header, $LibVersion)) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008124 $Header = $HPath;
8125 }
8126 else
8127 { # can't find header
8128 return 0;
8129 }
8130 }
8131 if($Header=~/\.\w+\Z/)
8132 { # have an extension
8133 return is_header_file($Header);
8134 }
8135 else
8136 {
8137 if($UserDefined==2)
8138 { # specified on the command line
8139 if(cmd_file($Header)!~/HTML|XML/i) {
8140 return $Header;
8141 }
8142 }
8143 elsif($UserDefined)
8144 { # specified in the XML-descriptor
8145 # header file without an extension
8146 return $Header;
8147 }
8148 else
8149 {
Andrey Ponomarenko85043792012-05-14 16:48:07 +04008150 if($Header=~/\/include\//
8151 or cmd_file($Header)=~/C[\+]*\s+program/i)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008152 { # !~/HTML|XML|shared|dynamic/i
8153 return $Header;
8154 }
8155 }
8156 }
8157 return 0;
8158}
8159
Andrey Ponomarenko16934472012-03-29 15:37:04 +04008160sub addTargetHeaders($)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008161{
8162 my $LibVersion = $_[0];
8163 foreach my $RegHeader (keys(%{$Registered_Headers{$LibVersion}}))
8164 {
8165 my $RegDir = get_dirname($RegHeader);
8166 $TargetHeaders{$LibVersion}{get_filename($RegHeader)}=1;
Andrey Ponomarenko9927e332012-10-19 10:50:48 +04008167
8168 if(not $INC_PATH_AUTODETECT{$LibVersion}) {
8169 detect_recursive_includes($RegHeader, $LibVersion);
8170 }
8171
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008172 foreach my $RecInc (keys(%{$RecursiveIncludes{$LibVersion}{$RegHeader}}))
8173 {
8174 my $Dir = get_dirname($RecInc);
Andrey Ponomarenko85043792012-05-14 16:48:07 +04008175 if($Dir=~/\A\Q$RegDir\E([\/\\]|\Z)/
8176 or $RecursiveIncludes{$LibVersion}{$RegHeader}{$RecInc}!=1)
8177 { # in the same directory or included by #include "..."
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008178 $TargetHeaders{$LibVersion}{get_filename($RecInc)}=1;
8179 }
8180 }
8181 }
8182}
8183
8184sub readHeaders($)
8185{
8186 $Version = $_[0];
8187 printMsg("INFO", "checking header(s) ".$Descriptor{$Version}{"Version"}." ...");
8188 my $DumpPath = getDump();
8189 if(not $DumpPath) {
8190 exitStatus("Cannot_Compile", "can't compile header(s)");
8191 }
8192 if($Debug)
8193 { # debug mode
8194 mkpath($DEBUG_PATH{$Version});
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04008195 copy($DumpPath, $DEBUG_PATH{$Version}."/translation-unit-dump.txt");
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008196 }
8197 getInfo($DumpPath);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008198}
8199
8200sub prepareTypes($)
8201{
8202 my $LibVersion = $_[0];
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04008203 if(not checkDump($LibVersion, "2.0"))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008204 { # support for old ABI dumps
8205 # type names have been corrected in ACC 1.22 (dump 2.0 format)
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04008206 foreach my $TypeId (keys(%{$TypeInfo{$LibVersion}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008207 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04008208 my $TName = $TypeInfo{$LibVersion}{$TypeId}{"Name"};
8209 if($TName=~/\A(\w+)::(\w+)/) {
8210 my ($P1, $P2) = ($1, $2);
8211 if($P1 eq $P2) {
8212 $TName=~s/\A$P1:\:$P1(\W)/$P1$1/;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008213 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04008214 else {
8215 $TName=~s/\A(\w+:\:)$P2:\:$P2(\W)/$1$P2$2/;
8216 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008217 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04008218 $TypeInfo{$LibVersion}{$TypeId}{"Name"} = $TName;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008219 }
8220 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04008221 if(not checkDump($LibVersion, "2.5"))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008222 { # support for old ABI dumps
8223 # V < 2.5: array size == "number of elements"
8224 # V >= 2.5: array size in bytes
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04008225 foreach my $TypeId (sort {int($a)<=>int($b)} keys(%{$TypeInfo{$LibVersion}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008226 {
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +04008227 my %Type = get_PureType($TypeId, $TypeInfo{$LibVersion});
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04008228 if($Type{"Type"} eq "Array")
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008229 {
Andrey Ponomarenko01117f12012-06-26 12:23:02 +04008230 if(my $Size = $Type{"Size"})
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04008231 { # array[N]
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +04008232 my %Base = get_OneStep_BaseType($Type{"Tid"}, $TypeInfo{$LibVersion});
Andrey Ponomarenko01117f12012-06-26 12:23:02 +04008233 $Size *= $Base{"Size"};
8234 $TypeInfo{$LibVersion}{$TypeId}{"Size"} = "$Size";
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04008235 }
8236 else
8237 { # array[] is a pointer
8238 $TypeInfo{$LibVersion}{$TypeId}{"Size"} = $WORD_SIZE{$LibVersion};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008239 }
8240 }
8241 }
8242 }
8243 my $V2 = ($LibVersion==1)?2:1;
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04008244 if(not checkDump($LibVersion, "2.7"))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008245 { # support for old ABI dumps
8246 # size of "method ptr" corrected in 2.7
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04008247 foreach my $TypeId (sort {int($a)<=>int($b)} keys(%{$TypeInfo{$LibVersion}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008248 {
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +04008249 my %PureType = get_PureType($TypeId, $TypeInfo{$LibVersion});
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04008250 if($PureType{"Type"} eq "MethodPtr")
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008251 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04008252 my %Type = get_Type($TypeId, $LibVersion);
8253 my $TypeId_2 = getTypeIdByName($PureType{"Name"}, $V2);
8254 my %Type2 = get_Type($TypeId_2, $V2);
8255 if($Type{"Size"} ne $Type2{"Size"}) {
8256 $TypeInfo{$LibVersion}{$TypeId}{"Size"} = $Type2{"Size"};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008257 }
8258 }
8259 }
8260 }
8261}
8262
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04008263sub prepareSymbols($)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008264{
8265 my $LibVersion = $_[0];
Andrey Ponomarenko16934472012-03-29 15:37:04 +04008266
8267 if(not keys(%{$SymbolInfo{$LibVersion}}))
8268 { # check if input is valid
8269 if(not $ExtendedCheck and not $CheckObjectsOnly)
8270 {
8271 if($CheckHeadersOnly) {
8272 exitStatus("Empty_Set", "the set of public symbols is empty (".$Descriptor{$LibVersion}{"Version"}.")");
8273 }
8274 else {
8275 exitStatus("Empty_Intersection", "the sets of public symbols in headers and libraries have empty intersection (".$Descriptor{$LibVersion}{"Version"}.")");
8276 }
8277 }
8278 }
8279
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008280 my $Remangle = 0;
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04008281 if(not checkDump(1, "2.10")
8282 or not checkDump(2, "2.10"))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008283 { # different formats
8284 $Remangle = 1;
8285 }
8286 if($CheckHeadersOnly)
8287 { # different languages
8288 if($UserLang)
8289 { # --lang=LANG for both versions
8290 if(($UsedDump{1}{"V"} and $UserLang ne $UsedDump{1}{"L"})
8291 or ($UsedDump{2}{"V"} and $UserLang ne $UsedDump{2}{"L"}))
8292 {
8293 if($UserLang eq "C++")
8294 { # remangle symbols
8295 $Remangle = 1;
8296 }
8297 elsif($UserLang eq "C")
8298 { # remove mangling
8299 $Remangle = -1;
8300 }
8301 }
8302 }
8303 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04008304
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04008305 foreach my $InfoId (sort {int($b)<=>int($a)} keys(%{$SymbolInfo{$LibVersion}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008306 { # reverse order: D0, D1, D2, D0 (artificial, GCC < 4.5), C1, C2
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04008307 if(not checkDump($LibVersion, "2.13"))
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04008308 { # support for old ABI dumps
8309 if(defined $SymbolInfo{$LibVersion}{$InfoId}{"Param"})
8310 {
8311 foreach my $P (keys(%{$SymbolInfo{$LibVersion}{$InfoId}{"Param"}}))
8312 {
8313 my $TypeId = $SymbolInfo{$LibVersion}{$InfoId}{"Param"}{$P}{"type"};
8314 my $DVal = $SymbolInfo{$LibVersion}{$InfoId}{"Param"}{$P}{"default"};
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04008315 my $TName = $TypeInfo{$LibVersion}{$TypeId}{"Name"};
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04008316 if(defined $DVal and $DVal ne "")
8317 {
8318 if($TName eq "char") {
8319 $SymbolInfo{$LibVersion}{$InfoId}{"Param"}{$P}{"default"} = chr($DVal);
8320 }
8321 elsif($TName eq "bool") {
8322 $SymbolInfo{$LibVersion}{$InfoId}{"Param"}{$P}{"default"} = $DVal?"true":"false";
8323 }
8324 }
8325 }
8326 }
8327 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04008328 if($SymbolInfo{$LibVersion}{$InfoId}{"Destructor"})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008329 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04008330 if(defined $SymbolInfo{$LibVersion}{$InfoId}{"Param"}
8331 and keys(%{$SymbolInfo{$LibVersion}{$InfoId}{"Param"}})
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04008332 and $SymbolInfo{$LibVersion}{$InfoId}{"Param"}{0}{"name"})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008333 { # support for old GCC < 4.5: skip artificial ~dtor(int __in_chrg)
8334 # + support for old ABI dumps
8335 next;
8336 }
8337 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04008338 my $MnglName = $SymbolInfo{$LibVersion}{$InfoId}{"MnglName"};
Andrey Ponomarenko85043792012-05-14 16:48:07 +04008339 my $ShortName = $SymbolInfo{$LibVersion}{$InfoId}{"ShortName"};
Andrey Ponomarenko16934472012-03-29 15:37:04 +04008340 my $ClassID = $SymbolInfo{$LibVersion}{$InfoId}{"Class"};
Andrey Ponomarenko85043792012-05-14 16:48:07 +04008341 my $Return = $SymbolInfo{$LibVersion}{$InfoId}{"Return"};
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04008342
Andrey Ponomarenko16934472012-03-29 15:37:04 +04008343 my $SRemangle = 0;
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04008344 if(not checkDump(1, "2.12")
8345 or not checkDump(2, "2.12"))
Andrey Ponomarenko16934472012-03-29 15:37:04 +04008346 { # support for old ABI dumps
Andrey Ponomarenko85043792012-05-14 16:48:07 +04008347 if($ShortName eq "operator>>")
8348 {
8349 if(not $SymbolInfo{$LibVersion}{$InfoId}{"Class"})
8350 { # corrected mangling of operator>>
8351 $SRemangle = 1;
8352 }
Andrey Ponomarenko16934472012-03-29 15:37:04 +04008353 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +04008354 if($SymbolInfo{$LibVersion}{$InfoId}{"Data"})
8355 {
8356 if(not $SymbolInfo{$LibVersion}{$InfoId}{"Class"}
8357 and isConstType($Return, $LibVersion) and $MnglName!~/L\d+$ShortName/)
8358 { # corrected mangling of const global data
8359 # some global data is not mangled in the TU dump: qt_sine_table (Qt 4.8)
8360 # and incorrectly mangled by old ACC versions
8361 $SRemangle = 1;
8362 }
Andrey Ponomarenko16934472012-03-29 15:37:04 +04008363 }
8364 }
Andrey Ponomarenko5c09ef32012-06-14 18:17:33 +04008365 if(not $CheckHeadersOnly)
8366 { # support for old ABI dumps
8367 if(not checkDump(1, "2.17")
8368 or not checkDump(2, "2.17"))
8369 {
8370 if($SymbolInfo{$LibVersion}{$InfoId}{"Data"})
8371 {
8372 if(not $SymbolInfo{$LibVersion}{$InfoId}{"Class"})
8373 {
8374 if(link_symbol($ShortName, $LibVersion, "-Deps"))
8375 {
8376 $MnglName = $ShortName;
8377 $SymbolInfo{$LibVersion}{$InfoId}{"MnglName"} = $MnglName;
8378 }
8379 }
8380 }
8381 }
8382 }
Andrey Ponomarenko16934472012-03-29 15:37:04 +04008383 if($Remangle==1 or $SRemangle==1)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008384 { # support for old ABI dumps: some symbols are not mangled in old dumps
8385 # mangle both sets of symbols (old and new)
8386 # NOTE: remangling all symbols by the same mangler
8387 if($MnglName=~/\A_ZN(V|)K/)
8388 { # mangling may be incorrect on old ABI dumps
8389 # because of absent "Const" attribute
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04008390 $SymbolInfo{$LibVersion}{$InfoId}{"Const"} = 1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008391 }
8392 if($MnglName=~/\A_ZN(K|)V/)
8393 { # mangling may be incorrect on old ABI dumps
8394 # because of absent "Volatile" attribute
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04008395 $SymbolInfo{$LibVersion}{$InfoId}{"Volatile"} = 1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008396 }
Andrey Ponomarenko16934472012-03-29 15:37:04 +04008397 if(($ClassID and $MnglName!~/\A(_Z|\?)/)
8398 or (not $ClassID and $CheckHeadersOnly)
8399 or (not $ClassID and not link_symbol($MnglName, $LibVersion, "-Deps")))
8400 { # support for old ABI dumps, GCC >= 4.0
8401 # remangling all manually mangled symbols
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04008402 if($MnglName = mangle_symbol($InfoId, $LibVersion, "GCC"))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008403 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04008404 $SymbolInfo{$LibVersion}{$InfoId}{"MnglName"} = $MnglName;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008405 $MangledNames{$LibVersion}{$MnglName} = 1;
8406 }
8407 }
8408 }
8409 elsif($Remangle==-1)
8410 { # remove mangling
8411 $MnglName = "";
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04008412 $SymbolInfo{$LibVersion}{$InfoId}{"MnglName"} = "";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008413 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008414 if(not $MnglName) {
8415 next;
8416 }
8417 if(not $CompleteSignature{$LibVersion}{$MnglName}{"MnglName"})
8418 { # NOTE: global data may enter here twice
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04008419 %{$CompleteSignature{$LibVersion}{$MnglName}} = %{$SymbolInfo{$LibVersion}{$InfoId}};
8420
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008421 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04008422 if(not checkDump($LibVersion, "2.6"))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008423 { # support for old dumps
8424 # add "Volatile" attribute
8425 if($MnglName=~/_Z(K|)V/) {
8426 $CompleteSignature{$LibVersion}{$MnglName}{"Volatile"}=1;
8427 }
8428 }
8429 # symbol and its symlink have same signatures
8430 if($SymVer{$LibVersion}{$MnglName}) {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04008431 %{$CompleteSignature{$LibVersion}{$SymVer{$LibVersion}{$MnglName}}} = %{$SymbolInfo{$LibVersion}{$InfoId}};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008432 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +04008433
8434 # clean memory
Andrey Ponomarenko16934472012-03-29 15:37:04 +04008435 delete($SymbolInfo{$LibVersion}{$InfoId});
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008436 }
8437 if($COMMON_LANGUAGE{$LibVersion} eq "C++" or $OSgroup eq "windows") {
8438 translateSymbols(keys(%{$CompleteSignature{$LibVersion}}), $LibVersion);
8439 }
8440 if($ExtendedCheck)
8441 { # --ext option
8442 addExtension($LibVersion);
8443 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +04008444
8445 # clean memory
8446 delete($SymbolInfo{$LibVersion});
8447
8448 foreach my $Symbol (keys(%{$CompleteSignature{$LibVersion}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008449 { # detect allocable classes with public exported constructors
8450 # or classes with auto-generated or inline-only constructors
Andrey Ponomarenko9927e332012-10-19 10:50:48 +04008451 # and other temp info
Andrey Ponomarenko85043792012-05-14 16:48:07 +04008452 if(my $ClassId = $CompleteSignature{$LibVersion}{$Symbol}{"Class"})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008453 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04008454 my $ClassName = $TypeInfo{$LibVersion}{$ClassId}{"Name"};
Andrey Ponomarenko85043792012-05-14 16:48:07 +04008455 if($CompleteSignature{$LibVersion}{$Symbol}{"Constructor"}
8456 and not $CompleteSignature{$LibVersion}{$Symbol}{"InLine"})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008457 { # Class() { ... } will not be exported
Andrey Ponomarenko85043792012-05-14 16:48:07 +04008458 if(not $CompleteSignature{$LibVersion}{$Symbol}{"Private"})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008459 {
Andrey Ponomarenko85043792012-05-14 16:48:07 +04008460 if($CheckHeadersOnly or link_symbol($Symbol, $LibVersion, "-Deps")) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008461 $AllocableClass{$LibVersion}{$ClassName} = 1;
8462 }
8463 }
8464 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +04008465 if(not $CompleteSignature{$LibVersion}{$Symbol}{"Private"})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008466 { # all imported class methods
Andrey Ponomarenko85043792012-05-14 16:48:07 +04008467 if(symbolFilter($Symbol, $LibVersion, "Affected", "Binary"))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008468 {
Andrey Ponomarenko85043792012-05-14 16:48:07 +04008469 if($CheckHeadersOnly)
8470 {
8471 if(not $CompleteSignature{$LibVersion}{$Symbol}{"InLine"}
8472 or $CompleteSignature{$LibVersion}{$Symbol}{"Virt"})
8473 { # all symbols except non-virtual inline
8474 $ClassMethods{"Binary"}{$LibVersion}{$ClassName}{$Symbol} = 1;
8475 }
8476 }
8477 else {
8478 $ClassMethods{"Binary"}{$LibVersion}{$ClassName}{$Symbol} = 1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008479 }
8480 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04008481 if(symbolFilter($Symbol, $LibVersion, "Affected", "Source")) {
Andrey Ponomarenko85043792012-05-14 16:48:07 +04008482 $ClassMethods{"Source"}{$LibVersion}{$ClassName}{$Symbol} = 1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008483 }
8484 }
Andrey Ponomarenko16934472012-03-29 15:37:04 +04008485 $ClassNames{$LibVersion}{$ClassName} = 1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008486 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +04008487 if(my $RetId = $CompleteSignature{$LibVersion}{$Symbol}{"Return"})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008488 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04008489 my %Base = get_BaseType($RetId, $LibVersion);
Andrey Ponomarenko85043792012-05-14 16:48:07 +04008490 if(defined $Base{"Type"}
8491 and $Base{"Type"}=~/Struct|Class/)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008492 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04008493 my $Name = $TypeInfo{$LibVersion}{$Base{"Tid"}}{"Name"};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008494 if($Name=~/<([^<>\s]+)>/)
8495 {
8496 if(my $Tid = getTypeIdByName($1, $LibVersion)) {
8497 $ReturnedClass{$LibVersion}{$Tid} = 1;
8498 }
8499 }
8500 else {
8501 $ReturnedClass{$LibVersion}{$Base{"Tid"}} = 1;
8502 }
8503 }
8504 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +04008505 foreach my $Num (keys(%{$CompleteSignature{$LibVersion}{$Symbol}{"Param"}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008506 {
Andrey Ponomarenko85043792012-05-14 16:48:07 +04008507 my $PId = $CompleteSignature{$LibVersion}{$Symbol}{"Param"}{$Num}{"type"};
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04008508 if(get_PLevel($PId, $LibVersion)>=1)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008509 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04008510 if(my %Base = get_BaseType($PId, $LibVersion))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008511 {
Andrey Ponomarenko16934472012-03-29 15:37:04 +04008512 if($Base{"Type"}=~/Struct|Class/)
8513 {
Andrey Ponomarenko85043792012-05-14 16:48:07 +04008514 $ParamClass{$LibVersion}{$Base{"Tid"}}{$Symbol} = 1;
Andrey Ponomarenko16934472012-03-29 15:37:04 +04008515 foreach my $SubId (get_sub_classes($Base{"Tid"}, $LibVersion, 1))
8516 { # mark all derived classes
Andrey Ponomarenko85043792012-05-14 16:48:07 +04008517 $ParamClass{$LibVersion}{$SubId}{$Symbol} = 1;
Andrey Ponomarenko16934472012-03-29 15:37:04 +04008518 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008519 }
8520 }
8521 }
8522 }
Andrey Ponomarenko9927e332012-10-19 10:50:48 +04008523
8524 # mapping {short name => symbols}
8525 $Func_ShortName{$LibVersion}{$CompleteSignature{$LibVersion}{$Symbol}{"ShortName"}}{$Symbol} = 1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008526 }
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04008527 foreach my $MnglName (keys(%VTableClass))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008528 { # reconstruct header name for v-tables
Andrey Ponomarenko9927e332012-10-19 10:50:48 +04008529 if(index($MnglName, "_ZTV")==0)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008530 {
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04008531 if(my $ClassName = $VTableClass{$MnglName})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008532 {
8533 if(my $ClassId = $TName_Tid{$LibVersion}{$ClassName}) {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04008534 $CompleteSignature{$LibVersion}{$MnglName}{"Header"} = $TypeInfo{$LibVersion}{$ClassId}{"Header"};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008535 }
8536 }
8537 }
8538 }
Andrey Ponomarenko16934472012-03-29 15:37:04 +04008539
8540 # types
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04008541 foreach my $TypeId (keys(%{$TypeInfo{$LibVersion}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008542 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04008543 if(my $TName = $TypeInfo{$LibVersion}{$TypeId}{"Name"})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008544 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04008545 if(defined $TypeInfo{$LibVersion}{$TypeId}{"VTable"}) {
8546 $ClassNames{$LibVersion}{$TName} = 1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008547 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04008548 if(defined $TypeInfo{$LibVersion}{$TypeId}{"Base"})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008549 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04008550 $ClassNames{$LibVersion}{$TName} = 1;
8551 foreach my $Bid (keys(%{$TypeInfo{$LibVersion}{$TypeId}{"Base"}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008552 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04008553 if(my $BName = $TypeInfo{$LibVersion}{$Bid}{"Name"}) {
8554 $ClassNames{$LibVersion}{$BName} = 1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008555 }
8556 }
8557 }
8558 }
8559 }
8560}
8561
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04008562sub register_TypeUsage($$)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008563{
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04008564 my ($TypeId, $LibVersion) = @_;
8565 if(not $TypeId) {
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04008566 return 0;
8567 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04008568 if($UsedType{$LibVersion}{$TypeId})
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04008569 { # already registered
8570 return 1;
8571 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04008572 my %TInfo = get_Type($TypeId, $LibVersion);
Andrey Ponomarenko85043792012-05-14 16:48:07 +04008573 if($TInfo{"Type"})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008574 {
Andrey Ponomarenko85043792012-05-14 16:48:07 +04008575 if($TInfo{"Type"}=~/\A(Struct|Union|Class|FuncPtr|MethodPtr|FieldPtr|Enum)\Z/)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008576 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04008577 $UsedType{$LibVersion}{$TypeId} = 1;
Andrey Ponomarenko85043792012-05-14 16:48:07 +04008578 if($TInfo{"Type"}=~/\A(Struct|Class)\Z/)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008579 {
Andrey Ponomarenko85043792012-05-14 16:48:07 +04008580 foreach my $BaseId (keys(%{$TInfo{"Base"}}))
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04008581 { # register base classes
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04008582 register_TypeUsage($BaseId, $LibVersion);
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04008583 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +04008584 foreach my $TPos (keys(%{$TInfo{"TParam"}}))
8585 {
8586 my $TPName = $TInfo{"TParam"}{$TPos}{"name"};
8587 if(my $TTid = $TName_Tid{$LibVersion}{$TPName}) {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04008588 register_TypeUsage($TTid, $LibVersion);
Andrey Ponomarenko85043792012-05-14 16:48:07 +04008589 }
8590 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008591 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +04008592 foreach my $Memb_Pos (keys(%{$TInfo{"Memb"}}))
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04008593 {
Andrey Ponomarenko85043792012-05-14 16:48:07 +04008594 if(my $MTid = $TInfo{"Memb"}{$Memb_Pos}{"type"}) {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04008595 register_TypeUsage($MTid, $LibVersion);
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04008596 }
8597 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +04008598 if($TInfo{"Type"} eq "FuncPtr"
8599 or $TInfo{"Type"} eq "MethodPtr")
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04008600 {
Andrey Ponomarenko85043792012-05-14 16:48:07 +04008601 if(my $RTid = $TInfo{"Return"}) {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04008602 register_TypeUsage($RTid, $LibVersion);
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04008603 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +04008604 foreach my $Memb_Pos (keys(%{$TInfo{"Param"}}))
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04008605 {
Andrey Ponomarenko85043792012-05-14 16:48:07 +04008606 if(my $MTid = $TInfo{"Param"}{$Memb_Pos}{"type"}) {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04008607 register_TypeUsage($MTid, $LibVersion);
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04008608 }
8609 }
8610 }
8611 return 1;
8612 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +04008613 elsif($TInfo{"Type"}=~/\A(Const|ConstVolatile|Volatile|Pointer|Ref|Restrict|Array|Typedef)\Z/)
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04008614 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04008615 $UsedType{$LibVersion}{$TypeId} = 1;
8616 register_TypeUsage($TInfo{"BaseType"}{"Tid"}, $LibVersion);
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04008617 return 1;
8618 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04008619 elsif($TInfo{"Type"} eq "Intrinsic")
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04008620 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04008621 $UsedType{$LibVersion}{$TypeId} = 1;
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04008622 return 1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008623 }
8624 }
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04008625 return 0;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008626}
8627
Andrey Ponomarenko85043792012-05-14 16:48:07 +04008628sub selectSymbol($$$$)
Andrey Ponomarenko35c44fd2012-06-18 17:50:25 +04008629{ # select symbol to check or to dump
Andrey Ponomarenko85043792012-05-14 16:48:07 +04008630 my ($Symbol, $SInfo, $Level, $LibVersion) = @_;
8631
Andrey Ponomarenko35c44fd2012-06-18 17:50:25 +04008632 if($Level eq "Dump")
8633 {
8634 if($SInfo->{"Virt"} or $SInfo->{"PureVirt"})
8635 { # TODO: check if this symbol is from
8636 # base classes of other target symbols
8637 return 1;
8638 }
8639 }
8640
Andrey Ponomarenko85043792012-05-14 16:48:07 +04008641 if(not $STDCXX_TESTING and $Symbol=~/\A(_ZS|_ZNS|_ZNKS)/)
8642 { # stdc++ interfaces
8643 return 0;
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04008644 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +04008645
8646 my $Target = 0;
8647 if(my $Header = $SInfo->{"Header"}) {
8648 $Target = (is_target_header($Header, 1) or is_target_header($Header, 2));
8649 }
8650 if($CheckHeadersOnly)
8651 {
8652 if($Target)
8653 {
8654 if($Level eq "Dump")
8655 { # dumped
8656 if($BinaryOnly)
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04008657 {
Andrey Ponomarenko85043792012-05-14 16:48:07 +04008658 if(not $SInfo->{"InLine"} or $SInfo->{"Data"}) {
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04008659 return 1;
8660 }
8661 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +04008662 else {
8663 return 1;
8664 }
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04008665 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +04008666 elsif($Level eq "Source")
8667 { # checked
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04008668 return 1;
8669 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +04008670 elsif($Level eq "Binary")
8671 { # checked
8672 if(not $SInfo->{"InLine"} or $SInfo->{"Data"}
8673 or $SInfo->{"Virt"} or $SInfo->{"PureVirt"}) {
8674 return 1;
8675 }
8676 }
8677 }
8678 }
8679 else
8680 { # library is available
8681 if(link_symbol($Symbol, $LibVersion, "-Deps"))
8682 { # exported symbols
8683 return 1;
8684 }
8685 if($Level eq "Dump")
8686 { # dumped
Andrey Ponomarenko35c44fd2012-06-18 17:50:25 +04008687 if($BinaryOnly)
8688 {
8689 if($SInfo->{"Data"})
8690 {
8691 if($Target) {
8692 return 1;
8693 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +04008694 }
8695 }
Andrey Ponomarenko35c44fd2012-06-18 17:50:25 +04008696 else
8697 { # SrcBin
Andrey Ponomarenko85043792012-05-14 16:48:07 +04008698 if($Target) {
8699 return 1;
8700 }
8701 }
8702 }
8703 elsif($Level eq "Source")
8704 { # checked
Andrey Ponomarenko01117f12012-06-26 12:23:02 +04008705 if($SInfo->{"PureVirt"} or $SInfo->{"Data"} or $SInfo->{"InLine"}
8706 or isInLineInst($Symbol, $SInfo, $LibVersion))
Andrey Ponomarenko35c44fd2012-06-18 17:50:25 +04008707 { # skip LOCAL symbols
8708 if($Target) {
8709 return 1;
8710 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +04008711 }
8712 }
8713 elsif($Level eq "Binary")
8714 { # checked
8715 if($SInfo->{"PureVirt"} or $SInfo->{"Data"})
8716 {
8717 if($Target) {
8718 return 1;
8719 }
8720 }
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04008721 }
8722 }
8723 return 0;
8724}
8725
Andrey Ponomarenko85043792012-05-14 16:48:07 +04008726sub cleanDump($)
8727{ # clean data
Andrey Ponomarenko16934472012-03-29 15:37:04 +04008728 my $LibVersion = $_[0];
8729 foreach my $InfoId (keys(%{$SymbolInfo{$LibVersion}}))
8730 {
8731 my $MnglName = $SymbolInfo{$LibVersion}{$InfoId}{"MnglName"};
8732 if(not $MnglName) {
8733 delete($SymbolInfo{$LibVersion}{$InfoId});
8734 next;
8735 }
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04008736 my $ShortName = $SymbolInfo{$LibVersion}{$InfoId}{"ShortName"};
Andrey Ponomarenko85043792012-05-14 16:48:07 +04008737 if(not $ShortName) {
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04008738 delete($SymbolInfo{$LibVersion}{$InfoId});
8739 next;
Andrey Ponomarenko16934472012-03-29 15:37:04 +04008740 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +04008741 if($MnglName eq $ShortName)
8742 { # remove duplicate data
8743 delete($SymbolInfo{$LibVersion}{$InfoId}{"MnglName"});
Andrey Ponomarenko16934472012-03-29 15:37:04 +04008744 }
8745 if(not keys(%{$SymbolInfo{$LibVersion}{$InfoId}{"Param"}})) {
8746 delete($SymbolInfo{$LibVersion}{$InfoId}{"Param"});
8747 }
Andrey Ponomarenko01117f12012-06-26 12:23:02 +04008748 if(not keys(%{$SymbolInfo{$LibVersion}{$InfoId}{"TParam"}})) {
8749 delete($SymbolInfo{$LibVersion}{$InfoId}{"TParam"});
8750 }
Andrey Ponomarenko16934472012-03-29 15:37:04 +04008751 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04008752 foreach my $Tid (keys(%{$TypeInfo{$LibVersion}}))
Andrey Ponomarenko85043792012-05-14 16:48:07 +04008753 {
Andrey Ponomarenko01117f12012-06-26 12:23:02 +04008754 delete($TypeInfo{$LibVersion}{$Tid}{"Tid"});
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04008755 foreach my $Attr ("Header", "Line", "Size", "NameSpace")
Andrey Ponomarenko16934472012-03-29 15:37:04 +04008756 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04008757 if(not $TypeInfo{$LibVersion}{$Tid}{$Attr}) {
8758 delete($TypeInfo{$LibVersion}{$Tid}{$Attr});
8759 }
8760 }
Andrey Ponomarenko01117f12012-06-26 12:23:02 +04008761 if(not keys(%{$TypeInfo{$LibVersion}{$Tid}{"TParam"}})) {
8762 delete($TypeInfo{$LibVersion}{$Tid}{"TParam"});
8763 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04008764 }
8765}
8766
8767sub selectType($$)
8768{
8769 my ($Tid, $LibVersion) = @_;
Andrey Ponomarenko9927e332012-10-19 10:50:48 +04008770
8771 if(my $Dupl = $TypeTypedef{$LibVersion}{$Tid})
8772 {
8773 if(defined $TypeInfo{$LibVersion}{$Dupl})
8774 {
8775 if($TypeInfo{$LibVersion}{$Dupl}{"Name"} eq $TypeInfo{$LibVersion}{$Tid}{"Name"})
8776 { # duplicate
8777 return 0;
8778 }
8779 }
8780 }
8781
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04008782 if(my $THeader = $TypeInfo{$LibVersion}{$Tid}{"Header"})
8783 {
8784 if(not isBuiltIn($THeader))
8785 {
8786 if($TypeInfo{$LibVersion}{$Tid}{"Type"}=~/Class|Struct|Union|Enum|Typedef/)
Andrey Ponomarenko16934472012-03-29 15:37:04 +04008787 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04008788 if(not isAnon($TypeInfo{$LibVersion}{$Tid}{"Name"}))
8789 {
8790 if(is_target_header($THeader, $LibVersion))
8791 { # from target headers
8792 if(not selfTypedef($Tid, $LibVersion)) {
8793 return 1;
8794 }
8795 }
Andrey Ponomarenko16934472012-03-29 15:37:04 +04008796 }
8797 }
8798 }
8799 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04008800 return 0;
Andrey Ponomarenko16934472012-03-29 15:37:04 +04008801}
8802
Andrey Ponomarenko85043792012-05-14 16:48:07 +04008803sub removeUnused($$)
8804{ # remove unused data types from the ABI dump
8805 my ($LibVersion, $Kind) = @_;
8806 foreach my $InfoId (keys(%{$SymbolInfo{$LibVersion}}))
8807 {
8808 my %FuncInfo = %{$SymbolInfo{$LibVersion}{$InfoId}};
8809 if(my $RTid = $FuncInfo{"Return"}) {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04008810 register_TypeUsage($RTid, $LibVersion);
Andrey Ponomarenko85043792012-05-14 16:48:07 +04008811 }
8812 if(my $FCid = $FuncInfo{"Class"})
8813 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04008814 register_TypeUsage($FCid, $LibVersion);
8815 if(my $ThisId = getTypeIdByName($TypeInfo{$LibVersion}{$FCid}{"Name"}."*const", $LibVersion))
Andrey Ponomarenko85043792012-05-14 16:48:07 +04008816 { # register "this" pointer
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04008817 $UsedType{$LibVersion}{$ThisId} = 1;
8818 if(my %ThisType = get_Type($ThisId, $LibVersion)) {
8819 register_TypeUsage($ThisType{"BaseType"}{"Tid"}, $LibVersion);
Andrey Ponomarenko85043792012-05-14 16:48:07 +04008820 }
8821 }
8822 }
8823 foreach my $PPos (keys(%{$FuncInfo{"Param"}}))
8824 {
8825 if(my $PTid = $FuncInfo{"Param"}{$PPos}{"type"}) {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04008826 register_TypeUsage($PTid, $LibVersion);
Andrey Ponomarenko85043792012-05-14 16:48:07 +04008827 }
8828 }
8829 foreach my $TPos (keys(%{$FuncInfo{"TParam"}}))
8830 {
8831 my $TPName = $FuncInfo{"TParam"}{$TPos}{"name"};
8832 if(my $TTid = $TName_Tid{$LibVersion}{$TPName}) {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04008833 register_TypeUsage($TTid, $LibVersion);
Andrey Ponomarenko85043792012-05-14 16:48:07 +04008834 }
8835 }
8836 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04008837 foreach my $Tid (keys(%{$TypeInfo{$LibVersion}}))
8838 {
8839 if($UsedType{$LibVersion}{$Tid})
8840 { # All & Derived
8841 next;
8842 }
8843
8844 if($Kind eq "Derived")
Andrey Ponomarenko85043792012-05-14 16:48:07 +04008845 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04008846 if(selectType($Tid, $LibVersion)) {
8847 register_TypeUsage($Tid, $LibVersion);
Andrey Ponomarenko85043792012-05-14 16:48:07 +04008848 }
8849 }
8850 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04008851 foreach my $Tid (keys(%{$TypeInfo{$LibVersion}}))
8852 { # remove unused types
8853 if($UsedType{$LibVersion}{$Tid})
8854 { # All & Derived
8855 next;
8856 }
8857 # remove type
8858 delete($TypeInfo{$LibVersion}{$Tid});
8859 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +04008860
8861 # clean memory
8862 %UsedType = ();
8863}
8864
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04008865sub selfTypedef($$)
Andrey Ponomarenko85043792012-05-14 16:48:07 +04008866{
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04008867 my ($TypeId, $LibVersion) = @_;
8868 my %Type = get_Type($TypeId, $LibVersion);
Andrey Ponomarenko85043792012-05-14 16:48:07 +04008869 if($Type{"Type"} eq "Typedef")
8870 {
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +04008871 my %Base = get_OneStep_BaseType($TypeId, $TypeInfo{$LibVersion});
Andrey Ponomarenko85043792012-05-14 16:48:07 +04008872 if($Base{"Type"}=~/Class|Struct/)
8873 {
8874 if($Type{"Name"} eq $Base{"Name"}) {
8875 return 1;
8876 }
8877 elsif($Type{"Name"}=~/::(\w+)\Z/)
8878 {
8879 if($Type{"Name"} eq $Base{"Name"}."::".$1)
8880 { # QPointer<QWidget>::QPointer
8881 return 1;
8882 }
8883 }
8884 }
8885 }
8886 return 0;
8887}
8888
Andrey Ponomarenko16934472012-03-29 15:37:04 +04008889sub addExtension($)
8890{
8891 my $LibVersion = $_[0];
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04008892 foreach my $Tid (keys(%{$TypeInfo{$LibVersion}}))
Andrey Ponomarenko16934472012-03-29 15:37:04 +04008893 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04008894 if(selectType($Tid, $LibVersion))
Andrey Ponomarenko16934472012-03-29 15:37:04 +04008895 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04008896 my $Symbol = "external_func_".$TypeInfo{$LibVersion}{$Tid}{"Name"};
8897
8898 %{$CompleteSignature{$LibVersion}{$Symbol}} = (
8899 "Header" => "extended.h",
8900 "ShortName" => $Symbol,
8901 "MnglName" => $Symbol,
8902 "Param" => { 0 => { "type"=>$Tid, "name"=>"p1" } }
8903 );
8904
8905 $ExtendedSymbols{$Symbol}=1;
8906 $CheckedSymbols{"Binary"}{$Symbol}=1;
8907 $CheckedSymbols{"Source"}{$Symbol}=1;
Andrey Ponomarenko16934472012-03-29 15:37:04 +04008908 }
8909 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04008910 $ExtendedSymbols{"external_func_0"}=1;
8911 $CheckedSymbols{"Binary"}{"external_func_0"}=1;
8912 $CheckedSymbols{"Source"}{"external_func_0"}=1;
Andrey Ponomarenko16934472012-03-29 15:37:04 +04008913}
8914
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008915sub findMethod($$$)
8916{
8917 my ($VirtFunc, $ClassId, $LibVersion) = @_;
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04008918 foreach my $BaseClass_Id (keys(%{$TypeInfo{$LibVersion}{$ClassId}{"Base"}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008919 {
8920 if(my $VirtMethodInClass = findMethod_Class($VirtFunc, $BaseClass_Id, $LibVersion)) {
8921 return $VirtMethodInClass;
8922 }
8923 elsif(my $VirtMethodInBaseClasses = findMethod($VirtFunc, $BaseClass_Id, $LibVersion)) {
8924 return $VirtMethodInBaseClasses;
8925 }
8926 }
8927 return "";
8928}
8929
8930sub findMethod_Class($$$)
8931{
8932 my ($VirtFunc, $ClassId, $LibVersion) = @_;
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04008933 my $ClassName = $TypeInfo{$LibVersion}{$ClassId}{"Name"};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008934 return "" if(not defined $VirtualTable{$LibVersion}{$ClassName});
8935 my $TargetSuffix = get_symbol_suffix($VirtFunc, 1);
8936 my $TargetShortName = $CompleteSignature{$LibVersion}{$VirtFunc}{"ShortName"};
8937 foreach my $Candidate (keys(%{$VirtualTable{$LibVersion}{$ClassName}}))
8938 { # search for interface with the same parameters suffix (overridden)
8939 if($TargetSuffix eq get_symbol_suffix($Candidate, 1))
8940 {
8941 if($CompleteSignature{$LibVersion}{$VirtFunc}{"Destructor"}) {
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04008942 if($CompleteSignature{$LibVersion}{$Candidate}{"Destructor"})
8943 {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008944 if(($VirtFunc=~/D0E/ and $Candidate=~/D0E/)
8945 or ($VirtFunc=~/D1E/ and $Candidate=~/D1E/)
8946 or ($VirtFunc=~/D2E/ and $Candidate=~/D2E/)) {
8947 return $Candidate;
8948 }
8949 }
8950 }
8951 else {
8952 if($TargetShortName eq $CompleteSignature{$LibVersion}{$Candidate}{"ShortName"}) {
8953 return $Candidate;
8954 }
8955 }
8956 }
8957 }
8958 return "";
8959}
8960
Andrey Ponomarenko16934472012-03-29 15:37:04 +04008961sub registerVTable($)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008962{
Andrey Ponomarenko16934472012-03-29 15:37:04 +04008963 my $LibVersion = $_[0];
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04008964 foreach my $Symbol (keys(%{$CompleteSignature{$LibVersion}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008965 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04008966 if($CompleteSignature{$LibVersion}{$Symbol}{"Virt"}
8967 or $CompleteSignature{$LibVersion}{$Symbol}{"PureVirt"})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008968 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04008969 my $ClassName = $TypeInfo{$LibVersion}{$CompleteSignature{$LibVersion}{$Symbol}{"Class"}}{"Name"};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008970 next if(not $STDCXX_TESTING and $ClassName=~/\A(std::|__cxxabi)/);
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04008971 if($CompleteSignature{$LibVersion}{$Symbol}{"Destructor"}
8972 and $Symbol=~/D2E/)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008973 { # pure virtual D2-destructors are marked as "virt" in the dump
8974 # virtual D2-destructors are NOT marked as "virt" in the dump
8975 # both destructors are not presented in the v-table
8976 next;
8977 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04008978 my ($MnglName, $VersionSpec, $SymbolVersion) = separate_symbol($Symbol);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008979 $VirtualTable{$LibVersion}{$ClassName}{$MnglName} = 1;
8980 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008981 }
8982}
8983
8984sub registerOverriding($)
8985{
8986 my $LibVersion = $_[0];
8987 my @Classes = keys(%{$VirtualTable{$LibVersion}});
Andrey Ponomarenko85043792012-05-14 16:48:07 +04008988 @Classes = sort {int($TName_Tid{$LibVersion}{$a})<=>int($TName_Tid{$LibVersion}{$b})} @Classes;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008989 foreach my $ClassName (@Classes)
8990 {
8991 foreach my $VirtFunc (keys(%{$VirtualTable{$LibVersion}{$ClassName}}))
8992 {
Andrey Ponomarenko16934472012-03-29 15:37:04 +04008993 if($CompleteSignature{$LibVersion}{$VirtFunc}{"PureVirt"})
8994 { # pure virtuals
8995 next;
8996 }
8997 my $ClassId = $TName_Tid{$LibVersion}{$ClassName};
8998 if(my $Overridden = findMethod($VirtFunc, $ClassId, $LibVersion))
Andrey Ponomarenko85043792012-05-14 16:48:07 +04008999 {
9000 if($CompleteSignature{$LibVersion}{$Overridden}{"Virt"}
9001 or $CompleteSignature{$LibVersion}{$Overridden}{"PureVirt"})
9002 { # both overridden virtual methods
9003 # and implemented pure virtual methods
9004 $CompleteSignature{$LibVersion}{$VirtFunc}{"Override"} = $Overridden;
9005 $OverriddenMethods{$LibVersion}{$Overridden}{$VirtFunc} = 1;
9006 delete($VirtualTable{$LibVersion}{$ClassName}{$VirtFunc}); # remove from v-table model
9007 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009008 }
9009 }
9010 if(not keys(%{$VirtualTable{$LibVersion}{$ClassName}})) {
9011 delete($VirtualTable{$LibVersion}{$ClassName});
9012 }
9013 }
9014}
9015
9016sub setVirtFuncPositions($)
9017{
9018 my $LibVersion = $_[0];
9019 foreach my $ClassName (keys(%{$VirtualTable{$LibVersion}}))
9020 {
9021 my ($Num, $RelPos, $AbsNum) = (1, 0, 1);
9022 foreach my $VirtFunc (sort {int($CompleteSignature{$LibVersion}{$a}{"Line"}) <=> int($CompleteSignature{$LibVersion}{$b}{"Line"})}
9023 sort keys(%{$VirtualTable{$LibVersion}{$ClassName}}))
9024 {
Andrey Ponomarenko16934472012-03-29 15:37:04 +04009025 $VirtualTable{$LibVersion}{$ClassName}{$VirtFunc}=$Num++;
9026
9027 # set relative positions
9028 if(defined $VirtualTable{1}{$ClassName} and defined $VirtualTable{1}{$ClassName}{$VirtFunc}
9029 and defined $VirtualTable{2}{$ClassName} and defined $VirtualTable{2}{$ClassName}{$VirtFunc})
9030 { # relative position excluding added and removed virtual functions
9031 if(not $CompleteSignature{1}{$VirtFunc}{"Override"}
9032 and not $CompleteSignature{2}{$VirtFunc}{"Override"}) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009033 $CompleteSignature{$LibVersion}{$VirtFunc}{"RelPos"} = $RelPos++;
9034 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009035 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009036 }
9037 }
Andrey Ponomarenko16934472012-03-29 15:37:04 +04009038 foreach my $ClassName (keys(%{$ClassNames{$LibVersion}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009039 {
9040 my $AbsNum = 1;
Andrey Ponomarenko16934472012-03-29 15:37:04 +04009041 foreach my $VirtFunc (getVTable_Model($TName_Tid{$LibVersion}{$ClassName}, $LibVersion)) {
9042 $VirtualTable_Model{$LibVersion}{$ClassName}{$VirtFunc}=$AbsNum++;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009043 }
9044 }
9045}
9046
9047sub get_sub_classes($$$)
9048{
9049 my ($ClassId, $LibVersion, $Recursive) = @_;
9050 return () if(not defined $Class_SubClasses{$LibVersion}{$ClassId});
9051 my @Subs = ();
9052 foreach my $SubId (keys(%{$Class_SubClasses{$LibVersion}{$ClassId}}))
9053 {
Andrey Ponomarenko16934472012-03-29 15:37:04 +04009054 if($Recursive)
9055 {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009056 foreach my $SubSubId (get_sub_classes($SubId, $LibVersion, $Recursive)) {
9057 push(@Subs, $SubSubId);
9058 }
9059 }
9060 push(@Subs, $SubId);
9061 }
9062 return @Subs;
9063}
9064
9065sub get_base_classes($$$)
9066{
9067 my ($ClassId, $LibVersion, $Recursive) = @_;
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04009068 my %ClassType = get_Type($ClassId, $LibVersion);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009069 return () if(not defined $ClassType{"Base"});
9070 my @Bases = ();
9071 foreach my $BaseId (sort {int($ClassType{"Base"}{$a}{"pos"})<=>int($ClassType{"Base"}{$b}{"pos"})}
9072 keys(%{$ClassType{"Base"}}))
9073 {
Andrey Ponomarenko16934472012-03-29 15:37:04 +04009074 if($Recursive)
9075 {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009076 foreach my $SubBaseId (get_base_classes($BaseId, $LibVersion, $Recursive)) {
9077 push(@Bases, $SubBaseId);
9078 }
9079 }
9080 push(@Bases, $BaseId);
9081 }
9082 return @Bases;
9083}
9084
Andrey Ponomarenko16934472012-03-29 15:37:04 +04009085sub getVTable_Model($$)
9086{ # return an ordered list of v-table elements
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009087 my ($ClassId, $LibVersion) = @_;
9088 my @Bases = get_base_classes($ClassId, $LibVersion, 1);
9089 my @Elements = ();
9090 foreach my $BaseId (@Bases, $ClassId)
9091 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04009092 if(my $BName = $TypeInfo{$LibVersion}{$BaseId}{"Name"})
Andrey Ponomarenko85043792012-05-14 16:48:07 +04009093 {
9094 if(defined $VirtualTable{$LibVersion}{$BName})
9095 {
9096 my @VFunctions = keys(%{$VirtualTable{$LibVersion}{$BName}});
9097 @VFunctions = sort {int($CompleteSignature{$LibVersion}{$a}{"Line"}) <=> int($CompleteSignature{$LibVersion}{$b}{"Line"})} @VFunctions;
9098 foreach my $VFunc (@VFunctions) {
9099 push(@Elements, $VFunc);
9100 }
9101 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009102 }
9103 }
9104 return @Elements;
9105}
9106
9107sub getVShift($$)
9108{
9109 my ($ClassId, $LibVersion) = @_;
9110 my @Bases = get_base_classes($ClassId, $LibVersion, 1);
9111 my $VShift = 0;
9112 foreach my $BaseId (@Bases)
9113 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04009114 if(my $BName = $TypeInfo{$LibVersion}{$BaseId}{"Name"})
Andrey Ponomarenko85043792012-05-14 16:48:07 +04009115 {
9116 if(defined $VirtualTable{$LibVersion}{$BName}) {
9117 $VShift+=keys(%{$VirtualTable{$LibVersion}{$BName}});
9118 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009119 }
9120 }
9121 return $VShift;
9122}
9123
9124sub getShift($$)
9125{
9126 my ($ClassId, $LibVersion) = @_;
9127 my @Bases = get_base_classes($ClassId, $LibVersion, 0);
9128 my $Shift = 0;
9129 foreach my $BaseId (@Bases)
9130 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04009131 if(my $Size = $TypeInfo{$LibVersion}{$BaseId}{"Size"})
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04009132 {
9133 if($Size!=1)
9134 { # not empty base class
9135 $Shift+=$Size;
9136 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009137 }
9138 }
9139 return $Shift;
9140}
9141
Andrey Ponomarenko16934472012-03-29 15:37:04 +04009142sub getVTable_Size($$)
9143{ # number of v-table elements
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009144 my ($ClassName, $LibVersion) = @_;
Andrey Ponomarenko16934472012-03-29 15:37:04 +04009145 my $Size = 0;
9146 # three approaches
9147 if(not $Size)
9148 { # real size
9149 if(my %VTable = getVTable_Real($ClassName, $LibVersion)) {
9150 $Size = keys(%VTable);
9151 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009152 }
Andrey Ponomarenko16934472012-03-29 15:37:04 +04009153 if(not $Size)
9154 { # shared library symbol size
9155 if($Size = getSymbolSize($ClassVTable{$ClassName}, $LibVersion)) {
9156 $Size /= $WORD_SIZE{$LibVersion};
9157 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009158 }
Andrey Ponomarenko16934472012-03-29 15:37:04 +04009159 if(not $Size)
9160 { # model size
9161 if(defined $VirtualTable_Model{$LibVersion}{$ClassName}) {
9162 $Size = keys(%{$VirtualTable_Model{$LibVersion}{$ClassName}}) + 2;
9163 }
9164 }
9165 return $Size;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009166}
9167
9168sub isCopyingClass($$)
9169{
9170 my ($TypeId, $LibVersion) = @_;
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04009171 return $TypeInfo{$LibVersion}{$TypeId}{"Copied"};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009172}
9173
9174sub isLeafClass($$)
9175{
9176 my ($ClassId, $LibVersion) = @_;
9177 return (not keys(%{$Class_SubClasses{$LibVersion}{$ClassId}}));
9178}
9179
9180sub havePubFields($)
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04009181{ # check structured type for public fields
9182 return isAccessible($_[0], {}, 0, -1);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009183}
9184
9185sub isAccessible($$$$)
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04009186{ # check interval in structured type for public fields
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009187 my ($TypePtr, $Skip, $Start, $End) = @_;
9188 return 0 if(not $TypePtr);
9189 if($End==-1) {
9190 $End = keys(%{$TypePtr->{"Memb"}})-1;
9191 }
9192 foreach my $MemPos (keys(%{$TypePtr->{"Memb"}}))
9193 {
9194 if($Skip and $Skip->{$MemPos})
9195 { # skip removed/added fields
9196 next;
9197 }
9198 if(int($MemPos)>=$Start and int($MemPos)<=$End)
9199 {
9200 if(isPublic($TypePtr, $MemPos)) {
9201 return ($MemPos+1);
9202 }
9203 }
9204 }
9205 return 0;
9206}
9207
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009208sub isReserved($)
9209{ # reserved fields == private
9210 my $MName = $_[0];
9211 if($MName=~/reserved|padding|f_spare/i) {
9212 return 1;
9213 }
Andrey Ponomarenko9927e332012-10-19 10:50:48 +04009214 if($MName=~/\A[_]*(spare|pad|unused)[_\d]*\Z/i) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009215 return 1;
9216 }
9217 if($MName=~/(pad\d+)/i) {
9218 return 1;
9219 }
9220 return 0;
9221}
9222
9223sub isPublic($$)
9224{
9225 my ($TypePtr, $FieldPos) = @_;
9226 return 0 if(not $TypePtr);
9227 return 0 if(not defined $TypePtr->{"Memb"}{$FieldPos});
9228 return 0 if(not defined $TypePtr->{"Memb"}{$FieldPos}{"name"});
9229 if(not $TypePtr->{"Memb"}{$FieldPos}{"access"})
9230 { # by name in C language
9231 # FIXME: add other methods to detect private members
9232 my $MName = $TypePtr->{"Memb"}{$FieldPos}{"name"};
9233 if($MName=~/priv|abidata|parent_object/i)
9234 { # C-styled private data
9235 return 0;
9236 }
9237 if(lc($MName) eq "abi")
9238 { # ABI information/reserved field
9239 return 0;
9240 }
9241 if(isReserved($MName))
9242 { # reserved fields
9243 return 0;
9244 }
9245 return 1;
9246 }
9247 elsif($TypePtr->{"Memb"}{$FieldPos}{"access"} ne "private")
9248 { # by access in C++ language
9249 return 1;
9250 }
9251 return 0;
9252}
9253
Andrey Ponomarenko16934472012-03-29 15:37:04 +04009254sub getVTable_Real($$)
9255{
9256 my ($ClassName, $LibVersion) = @_;
9257 if(my $ClassId = $TName_Tid{$LibVersion}{$ClassName})
9258 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04009259 my %Type = get_Type($ClassId, $LibVersion);
Andrey Ponomarenko16934472012-03-29 15:37:04 +04009260 if(defined $Type{"VTable"}) {
9261 return %{$Type{"VTable"}};
9262 }
9263 }
9264 return ();
9265}
9266
9267sub cmpVTables($)
9268{
9269 my $ClassName = $_[0];
9270 my $Res = cmpVTables_Real($ClassName, 1);
9271 if($Res==-1) {
9272 $Res = cmpVTables_Model($ClassName);
9273 }
9274 return $Res;
9275}
9276
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009277sub cmpVTables_Model($)
9278{
9279 my $ClassName = $_[0];
Andrey Ponomarenko16934472012-03-29 15:37:04 +04009280 foreach my $Symbol (keys(%{$VirtualTable_Model{1}{$ClassName}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009281 {
Andrey Ponomarenko16934472012-03-29 15:37:04 +04009282 if(not defined $VirtualTable_Model{2}{$ClassName}{$Symbol}) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009283 return 1;
9284 }
9285 }
9286 return 0;
9287}
9288
Andrey Ponomarenko16934472012-03-29 15:37:04 +04009289sub cmpVTables_Real($$)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009290{
9291 my ($ClassName, $Strong) = @_;
Andrey Ponomarenko16934472012-03-29 15:37:04 +04009292 if(defined $Cache{"cmpVTables_Real"}{$Strong}{$ClassName}) {
9293 return $Cache{"cmpVTables_Real"}{$Strong}{$ClassName};
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04009294 }
Andrey Ponomarenko16934472012-03-29 15:37:04 +04009295 my %VTable_Old = getVTable_Real($ClassName, 1);
9296 my %VTable_New = getVTable_Real($ClassName, 2);
9297 if(not %VTable_Old or not %VTable_New)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009298 { # old ABI dumps
Andrey Ponomarenko16934472012-03-29 15:37:04 +04009299 return ($Cache{"cmpVTables_Real"}{$Strong}{$ClassName} = -1);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009300 }
Andrey Ponomarenko16934472012-03-29 15:37:04 +04009301 my %Indexes = map {$_=>1} (keys(%VTable_Old), keys(%VTable_New));
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009302 foreach my $Offset (sort {int($a)<=>int($b)} keys(%Indexes))
9303 {
Andrey Ponomarenko16934472012-03-29 15:37:04 +04009304 if(not defined $VTable_Old{$Offset})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009305 { # v-table v.1 < v-table v.2
Andrey Ponomarenko16934472012-03-29 15:37:04 +04009306 return ($Cache{"cmpVTables_Real"}{$Strong}{$ClassName} = $Strong);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009307 }
Andrey Ponomarenko16934472012-03-29 15:37:04 +04009308 my $Entry1 = $VTable_Old{$Offset};
9309 if(not defined $VTable_New{$Offset})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009310 { # v-table v.1 > v-table v.2
Andrey Ponomarenko16934472012-03-29 15:37:04 +04009311 return ($Cache{"cmpVTables_Real"}{$Strong}{$ClassName} = ($Strong or $Entry1!~/__cxa_pure_virtual/));
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009312 }
Andrey Ponomarenko16934472012-03-29 15:37:04 +04009313 my $Entry2 = $VTable_New{$Offset};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009314 $Entry1 = simpleVEntry($Entry1);
9315 $Entry2 = simpleVEntry($Entry2);
9316 if($Entry1 ne $Entry2)
9317 { # register as changed
9318 if($Entry1=~/::([^:]+)\Z/)
9319 {
9320 my $M1 = $1;
9321 if($Entry2=~/::([^:]+)\Z/)
9322 {
9323 my $M2 = $1;
9324 if($M1 eq $M2)
9325 { # overridden
9326 next;
9327 }
9328 }
9329 }
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04009330 if(differentDumps("G"))
9331 {
9332 if($Entry1=~/\A\-(0x|\d+)/ and $Entry2=~/\A\-(0x|\d+)/)
9333 {
9334 # GCC 4.6.1: -0x00000000000000010
9335 # GCC 4.7.0: -16
9336 next;
9337 }
9338 }
Andrey Ponomarenko16934472012-03-29 15:37:04 +04009339 return ($Cache{"cmpVTables_Real"}{$Strong}{$ClassName} = 1);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009340 }
9341 }
Andrey Ponomarenko16934472012-03-29 15:37:04 +04009342 return ($Cache{"cmpVTables_Real"}{$Strong}{$ClassName} = 0);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009343}
9344
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04009345sub mergeVTables($)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009346{ # merging v-tables without diagnostics
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04009347 my $Level = $_[0];
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009348 foreach my $ClassName (keys(%{$VirtualTable{1}}))
9349 {
Andrey Ponomarenko16934472012-03-29 15:37:04 +04009350 if($VTableChanged_M{$ClassName})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009351 { # already registered
9352 next;
9353 }
Andrey Ponomarenko16934472012-03-29 15:37:04 +04009354 if(cmpVTables_Real($ClassName, 0)==1)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009355 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04009356 my @Affected = (keys(%{$ClassMethods{$Level}{1}{$ClassName}}));
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009357 foreach my $Symbol (@Affected)
9358 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04009359 %{$CompatProblems{$Level}{$Symbol}{"Virtual_Table_Changed_Unknown"}{$ClassName}}=(
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009360 "Type_Name"=>$ClassName,
9361 "Type_Type"=>"Class",
9362 "Target"=>$ClassName);
9363 }
9364 }
9365 }
9366}
9367
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04009368sub mergeBases($)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009369{
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04009370 my $Level = $_[0];
Andrey Ponomarenko16934472012-03-29 15:37:04 +04009371 foreach my $ClassName (keys(%{$ClassNames{1}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009372 { # detect added and removed virtual functions
Andrey Ponomarenko16934472012-03-29 15:37:04 +04009373 my $ClassId = $TName_Tid{1}{$ClassName};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009374 next if(not $ClassId);
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04009375 if(defined $VirtualTable{2}{$ClassName})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009376 {
Andrey Ponomarenko16934472012-03-29 15:37:04 +04009377 foreach my $Symbol (keys(%{$VirtualTable{2}{$ClassName}}))
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04009378 {
Andrey Ponomarenko16934472012-03-29 15:37:04 +04009379 if($TName_Tid{1}{$ClassName}
9380 and not defined $VirtualTable{1}{$ClassName}{$Symbol})
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04009381 { # added to v-table
Andrey Ponomarenko16934472012-03-29 15:37:04 +04009382 if(defined $CompleteSignature{1}{$Symbol}
9383 and $CompleteSignature{1}{$Symbol}{"Virt"})
9384 { # override some method in v.1
9385 next;
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04009386 }
Andrey Ponomarenko16934472012-03-29 15:37:04 +04009387 $AddedInt_Virt{$Level}{$ClassName}{$Symbol} = 1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009388 }
9389 }
9390 }
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04009391 if(defined $VirtualTable{1}{$ClassName})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009392 {
Andrey Ponomarenko16934472012-03-29 15:37:04 +04009393 foreach my $Symbol (keys(%{$VirtualTable{1}{$ClassName}}))
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04009394 {
Andrey Ponomarenko16934472012-03-29 15:37:04 +04009395 if($TName_Tid{2}{$ClassName}
9396 and not defined $VirtualTable{2}{$ClassName}{$Symbol})
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04009397 { # removed from v-table
Andrey Ponomarenko16934472012-03-29 15:37:04 +04009398 if(defined $CompleteSignature{2}{$Symbol}
9399 and $CompleteSignature{2}{$Symbol}{"Virt"})
9400 { # override some method in v.2
9401 next;
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04009402 }
Andrey Ponomarenko16934472012-03-29 15:37:04 +04009403 $RemovedInt_Virt{$Level}{$ClassName}{$Symbol} = 1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009404 }
9405 }
9406 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04009407 if($Level eq "Binary")
9408 { # Binary-level
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04009409 my %Class_Type = get_Type($ClassId, 1);
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04009410 foreach my $AddedVFunc (keys(%{$AddedInt_Virt{$Level}{$ClassName}}))
9411 { # check replacements, including pure virtual methods
9412 my $AddedPos = $VirtualTable{2}{$ClassName}{$AddedVFunc};
9413 foreach my $RemovedVFunc (keys(%{$RemovedInt_Virt{$Level}{$ClassName}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009414 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04009415 my $RemovedPos = $VirtualTable{1}{$ClassName}{$RemovedVFunc};
9416 if($AddedPos==$RemovedPos)
9417 {
9418 $VirtualReplacement{$AddedVFunc} = $RemovedVFunc;
9419 $VirtualReplacement{$RemovedVFunc} = $AddedVFunc;
9420 last; # other methods will be reported as "added" or "removed"
9421 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009422 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04009423 if(my $RemovedVFunc = $VirtualReplacement{$AddedVFunc})
9424 {
9425 if(lc($AddedVFunc) eq lc($RemovedVFunc))
9426 { # skip: DomUi => DomUI parameter (Qt 4.2.3 to 4.3.0)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009427 next;
9428 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04009429 my $ProblemType = "Virtual_Replacement";
9430 my @Affected = ($RemovedVFunc);
9431 if($CompleteSignature{1}{$RemovedVFunc}{"PureVirt"})
9432 { # pure methods
9433 if(not isUsedClass($ClassId, 1, $Level))
9434 { # not a parameter of some exported method
9435 next;
9436 }
9437 $ProblemType = "Pure_Virtual_Replacement";
Andrey Ponomarenko9927e332012-10-19 10:50:48 +04009438
9439 # affected all methods (both virtual and non-virtual ones)
9440 @Affected = (keys(%{$ClassMethods{$Level}{1}{$ClassName}}));
9441 push(@Affected, keys(%{$OverriddenMethods{1}{$RemovedVFunc}}));
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009442 }
Andrey Ponomarenko9927e332012-10-19 10:50:48 +04009443 $VTableChanged_M{$ClassName}=1;
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04009444 foreach my $AffectedInt (@Affected)
9445 {
9446 if($CompleteSignature{1}{$AffectedInt}{"PureVirt"})
9447 { # affected exported methods only
9448 next;
9449 }
Andrey Ponomarenko9927e332012-10-19 10:50:48 +04009450 if(not symbolFilter($AffectedInt, 1, "Affected", $Level)) {
9451 next;
9452 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04009453 %{$CompatProblems{$Level}{$AffectedInt}{$ProblemType}{$tr_name{$AddedVFunc}}}=(
9454 "Type_Name"=>$Class_Type{"Name"},
9455 "Type_Type"=>"Class",
9456 "Target"=>get_Signature($AddedVFunc, 2),
9457 "Old_Value"=>get_Signature($RemovedVFunc, 1));
9458 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009459 }
9460 }
9461 }
9462 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04009463 if(not checkDump(1, "2.0")
9464 or not checkDump(2, "2.0"))
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04009465 { # support for old ABI dumps
Andrey Ponomarenko9927e332012-10-19 10:50:48 +04009466 # "Base" attribute introduced in ACC 1.22 (ABI dump 2.0 format)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009467 return;
9468 }
Andrey Ponomarenko16934472012-03-29 15:37:04 +04009469 foreach my $ClassName (sort keys(%{$ClassNames{1}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009470 {
Andrey Ponomarenko16934472012-03-29 15:37:04 +04009471 my $ClassId_Old = $TName_Tid{1}{$ClassName};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009472 next if(not $ClassId_Old);
9473 if(not isCreatable($ClassId_Old, 1))
9474 { # skip classes without public constructors (including auto-generated)
9475 # example: class has only a private exported or private inline constructor
9476 next;
9477 }
9478 if($ClassName=~/>/)
9479 { # skip affected template instances
9480 next;
9481 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04009482 my %Class_Old = get_Type($ClassId_Old, 1);
Andrey Ponomarenko16934472012-03-29 15:37:04 +04009483 my $ClassId_New = $TName_Tid{2}{$ClassName};
Andrey Ponomarenko85043792012-05-14 16:48:07 +04009484 if(not $ClassId_New) {
9485 next;
9486 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04009487 my %Class_New = get_Type($ClassId_New, 2);
Andrey Ponomarenko85043792012-05-14 16:48:07 +04009488 if($Class_New{"Type"}!~/Class|Struct/)
9489 { # became typedef
9490 if($Level eq "Binary") {
9491 next;
9492 }
9493 if($Level eq "Source")
9494 {
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +04009495 %Class_New = get_PureType($ClassId_New, $TypeInfo{2});
Andrey Ponomarenko85043792012-05-14 16:48:07 +04009496 if($Class_New{"Type"}!~/Class|Struct/) {
9497 next;
9498 }
9499 $ClassId_New = $Class_New{"Tid"};
9500 }
9501 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009502 my @Bases_Old = sort {$Class_Old{"Base"}{$a}{"pos"}<=>$Class_Old{"Base"}{$b}{"pos"}} keys(%{$Class_Old{"Base"}});
9503 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 +04009504
9505 my %Tr_Old = map {$TypeInfo{1}{$_}{"Name"} => uncover_typedefs($TypeInfo{1}{$_}{"Name"}, 1)} @Bases_Old;
9506 my %Tr_New = map {$TypeInfo{2}{$_}{"Name"} => uncover_typedefs($TypeInfo{2}{$_}{"Name"}, 2)} @Bases_New;
9507
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009508 my ($BNum1, $BNum2) = (1, 1);
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +04009509 my %BasePos_Old = map {$Tr_Old{$TypeInfo{1}{$_}{"Name"}} => $BNum1++} @Bases_Old;
9510 my %BasePos_New = map {$Tr_New{$TypeInfo{2}{$_}{"Name"}} => $BNum2++} @Bases_New;
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04009511 my %ShortBase_Old = map {get_ShortType($_, 1) => 1} @Bases_Old;
9512 my %ShortBase_New = map {get_ShortType($_, 2) => 1} @Bases_New;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009513 my $Shift_Old = getShift($ClassId_Old, 1);
9514 my $Shift_New = getShift($ClassId_New, 2);
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +04009515 my %BaseId_New = map {$Tr_New{$TypeInfo{2}{$_}{"Name"}} => $_} @Bases_New;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009516 my ($Added, $Removed) = (0, 0);
9517 my @StableBases_Old = ();
9518 foreach my $BaseId (@Bases_Old)
9519 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04009520 my $BaseName = $TypeInfo{1}{$BaseId}{"Name"};
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +04009521 if($BasePos_New{$Tr_Old{$BaseName}}) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009522 push(@StableBases_Old, $BaseId);
9523 }
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +04009524 elsif(not $ShortBase_New{$Tr_Old{$BaseName}}
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04009525 and not $ShortBase_New{get_ShortType($BaseId, 1)})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009526 { # removed base
9527 # excluding namespace::SomeClass to SomeClass renaming
9528 my $ProblemKind = "Removed_Base_Class";
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04009529 if($Level eq "Binary")
9530 { # Binary-level
9531 if($Shift_Old ne $Shift_New)
9532 { # affected fields
9533 if(havePubFields(\%Class_Old)) {
9534 $ProblemKind .= "_And_Shift";
9535 }
9536 elsif($Class_Old{"Size"} ne $Class_New{"Size"}) {
9537 $ProblemKind .= "_And_Size";
9538 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009539 }
Andrey Ponomarenko16934472012-03-29 15:37:04 +04009540 if(keys(%{$VirtualTable_Model{1}{$BaseName}})
9541 and cmpVTables($ClassName)==1)
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04009542 { # affected v-table
9543 $ProblemKind .= "_And_VTable";
Andrey Ponomarenko16934472012-03-29 15:37:04 +04009544 $VTableChanged_M{$ClassName}=1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009545 }
9546 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04009547 my @Affected = keys(%{$ClassMethods{$Level}{1}{$ClassName}});
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009548 foreach my $SubId (get_sub_classes($ClassId_Old, 1, 1))
9549 {
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +04009550 if(my $SubName = $TypeInfo{1}{$SubId}{"Name"})
9551 {
9552 push(@Affected, keys(%{$ClassMethods{$Level}{1}{$SubName}}));
9553 if($ProblemKind=~/VTable/) {
9554 $VTableChanged_M{$SubName}=1;
9555 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009556 }
9557 }
9558 foreach my $Interface (@Affected)
9559 {
Andrey Ponomarenko9927e332012-10-19 10:50:48 +04009560 if(not symbolFilter($Interface, 1, "Affected", $Level)) {
9561 next;
9562 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04009563 %{$CompatProblems{$Level}{$Interface}{$ProblemKind}{"this"}}=(
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009564 "Type_Name"=>$ClassName,
9565 "Type_Type"=>"Class",
9566 "Target"=>$BaseName,
9567 "Old_Size"=>$Class_Old{"Size"}*$BYTE_SIZE,
9568 "New_Size"=>$Class_New{"Size"}*$BYTE_SIZE,
9569 "Shift"=>abs($Shift_New-$Shift_Old) );
9570 }
9571 $Removed+=1;
9572 }
9573 }
9574 my @StableBases_New = ();
9575 foreach my $BaseId (@Bases_New)
9576 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04009577 my $BaseName = $TypeInfo{2}{$BaseId}{"Name"};
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +04009578 if($BasePos_Old{$Tr_New{$BaseName}}) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009579 push(@StableBases_New, $BaseId);
9580 }
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +04009581 elsif(not $ShortBase_Old{$Tr_New{$BaseName}}
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04009582 and not $ShortBase_Old{get_ShortType($BaseId, 2)})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009583 { # added base
9584 # excluding namespace::SomeClass to SomeClass renaming
9585 my $ProblemKind = "Added_Base_Class";
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04009586 if($Level eq "Binary")
9587 { # Binary-level
9588 if($Shift_Old ne $Shift_New)
9589 { # affected fields
9590 if(havePubFields(\%Class_Old)) {
9591 $ProblemKind .= "_And_Shift";
9592 }
9593 elsif($Class_Old{"Size"} ne $Class_New{"Size"}) {
9594 $ProblemKind .= "_And_Size";
9595 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009596 }
Andrey Ponomarenko16934472012-03-29 15:37:04 +04009597 if(keys(%{$VirtualTable_Model{2}{$BaseName}})
9598 and cmpVTables($ClassName)==1)
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04009599 { # affected v-table
9600 $ProblemKind .= "_And_VTable";
Andrey Ponomarenko16934472012-03-29 15:37:04 +04009601 $VTableChanged_M{$ClassName}=1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009602 }
9603 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04009604 my @Affected = keys(%{$ClassMethods{$Level}{1}{$ClassName}});
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009605 foreach my $SubId (get_sub_classes($ClassId_Old, 1, 1))
9606 {
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +04009607 if(my $SubName = $TypeInfo{1}{$SubId}{"Name"})
9608 {
9609 push(@Affected, keys(%{$ClassMethods{$Level}{1}{$SubName}}));
9610 if($ProblemKind=~/VTable/) {
9611 $VTableChanged_M{$SubName}=1;
9612 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009613 }
9614 }
9615 foreach my $Interface (@Affected)
9616 {
Andrey Ponomarenko9927e332012-10-19 10:50:48 +04009617 if(not symbolFilter($Interface, 1, "Affected", $Level)) {
9618 next;
9619 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04009620 %{$CompatProblems{$Level}{$Interface}{$ProblemKind}{"this"}}=(
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009621 "Type_Name"=>$ClassName,
9622 "Type_Type"=>"Class",
9623 "Target"=>$BaseName,
9624 "Old_Size"=>$Class_Old{"Size"}*$BYTE_SIZE,
9625 "New_Size"=>$Class_New{"Size"}*$BYTE_SIZE,
9626 "Shift"=>abs($Shift_New-$Shift_Old) );
9627 }
9628 $Added+=1;
9629 }
9630 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04009631 if($Level eq "Binary")
9632 { # Binary-level
9633 ($BNum1, $BNum2) = (1, 1);
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +04009634 my %BaseRelPos_Old = map {$Tr_Old{$TypeInfo{1}{$_}{"Name"}} => $BNum1++} @StableBases_Old;
9635 my %BaseRelPos_New = map {$Tr_New{$TypeInfo{2}{$_}{"Name"}} => $BNum2++} @StableBases_New;
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04009636 foreach my $BaseId (@Bases_Old)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009637 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04009638 my $BaseName = $TypeInfo{1}{$BaseId}{"Name"};
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +04009639 if(my $NewPos = $BaseRelPos_New{$Tr_Old{$BaseName}})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009640 {
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +04009641 my $BaseNewId = $BaseId_New{$Tr_Old{$BaseName}};
9642 my $OldPos = $BaseRelPos_Old{$Tr_Old{$BaseName}};
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04009643 if($NewPos!=$OldPos)
9644 { # changed position of the base class
9645 foreach my $Interface (keys(%{$ClassMethods{$Level}{1}{$ClassName}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009646 {
Andrey Ponomarenko9927e332012-10-19 10:50:48 +04009647 if(not symbolFilter($Interface, 1, "Affected", $Level)) {
9648 next;
9649 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04009650 %{$CompatProblems{$Level}{$Interface}{"Base_Class_Position"}{"this"}}=(
9651 "Type_Name"=>$ClassName,
9652 "Type_Type"=>"Class",
9653 "Target"=>$BaseName,
9654 "Old_Value"=>$OldPos-1,
9655 "New_Value"=>$NewPos-1 );
9656 }
9657 }
9658 if($Class_Old{"Base"}{$BaseId}{"virtual"}
9659 and not $Class_New{"Base"}{$BaseNewId}{"virtual"})
9660 { # became non-virtual base
9661 foreach my $Interface (keys(%{$ClassMethods{$Level}{1}{$ClassName}}))
9662 {
Andrey Ponomarenko9927e332012-10-19 10:50:48 +04009663 if(not symbolFilter($Interface, 1, "Affected", $Level)) {
9664 next;
9665 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04009666 %{$CompatProblems{$Level}{$Interface}{"Base_Class_Became_Non_Virtually_Inherited"}{"this->".$BaseName}}=(
9667 "Type_Name"=>$ClassName,
9668 "Type_Type"=>"Class",
9669 "Target"=>$BaseName );
9670 }
9671 }
9672 elsif(not $Class_Old{"Base"}{$BaseId}{"virtual"}
9673 and $Class_New{"Base"}{$BaseNewId}{"virtual"})
9674 { # became virtual base
9675 foreach my $Interface (keys(%{$ClassMethods{$Level}{1}{$ClassName}}))
9676 {
Andrey Ponomarenko9927e332012-10-19 10:50:48 +04009677 if(not symbolFilter($Interface, 1, "Affected", $Level)) {
9678 next;
9679 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04009680 %{$CompatProblems{$Level}{$Interface}{"Base_Class_Became_Virtually_Inherited"}{"this->".$BaseName}}=(
9681 "Type_Name"=>$ClassName,
9682 "Type_Type"=>"Class",
9683 "Target"=>$BaseName );
9684 }
9685 }
9686 }
9687 }
9688 # detect size changes in base classes
9689 if($Shift_Old!=$Shift_New)
9690 { # size of allocable class
9691 foreach my $BaseId (@StableBases_Old)
9692 { # search for changed base
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04009693 my %BaseType = get_Type($BaseId, 1);
9694 my $Size_Old = $TypeInfo{1}{$BaseId}{"Size"};
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +04009695 my $Size_New = $TypeInfo{2}{$BaseId_New{$Tr_Old{$BaseType{"Name"}}}}{"Size"};
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04009696 if($Size_Old ne $Size_New
9697 and $Size_Old and $Size_New)
9698 {
9699 my $ProblemType = "";
9700 if(isCopyingClass($BaseId, 1)) {
9701 $ProblemType = "Size_Of_Copying_Class";
9702 }
9703 elsif($AllocableClass{1}{$BaseType{"Name"}})
9704 {
9705 if($Size_New>$Size_Old)
9706 { # increased size
9707 $ProblemType = "Size_Of_Allocable_Class_Increased";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009708 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04009709 else
9710 { # decreased size
9711 $ProblemType = "Size_Of_Allocable_Class_Decreased";
9712 if(not havePubFields(\%Class_Old))
9713 { # affected class has no public members
9714 next;
9715 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009716 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04009717 }
9718 next if(not $ProblemType);
9719 foreach my $Interface (keys(%{$ClassMethods{$Level}{1}{$ClassName}}))
9720 { # base class size changes affecting current class
Andrey Ponomarenko9927e332012-10-19 10:50:48 +04009721 if(not symbolFilter($Interface, 1, "Affected", $Level)) {
9722 next;
9723 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04009724 %{$CompatProblems{$Level}{$Interface}{$ProblemType}{"this->".$BaseType{"Name"}}}=(
9725 "Type_Name"=>$BaseType{"Name"},
9726 "Type_Type"=>"Class",
9727 "Target"=>$BaseType{"Name"},
9728 "Old_Size"=>$Size_Old*$BYTE_SIZE,
9729 "New_Size"=>$Size_New*$BYTE_SIZE );
9730 }
9731 }
9732 }
9733 }
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +04009734 if(defined $VirtualTable_Model{1}{$ClassName}
Andrey Ponomarenko16934472012-03-29 15:37:04 +04009735 and cmpVTables_Real($ClassName, 1)==1
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +04009736 and my @VFunctions = keys(%{$VirtualTable_Model{1}{$ClassName}}))
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04009737 { # compare virtual tables size in base classes
9738 my $VShift_Old = getVShift($ClassId_Old, 1);
9739 my $VShift_New = getVShift($ClassId_New, 2);
9740 if($VShift_Old ne $VShift_New)
9741 { # changes in the base class or changes in the list of base classes
9742 my @AllBases_Old = get_base_classes($ClassId_Old, 1, 1);
9743 my @AllBases_New = get_base_classes($ClassId_New, 2, 1);
9744 ($BNum1, $BNum2) = (1, 1);
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +04009745 my %StableBase = map {$Tr_New{$TypeInfo{2}{$_}{"Name"}} => $_} @AllBases_New;
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04009746 foreach my $BaseId (@AllBases_Old)
9747 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04009748 my %BaseType = get_Type($BaseId, 1);
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +04009749 if(not $StableBase{$Tr_Old{$BaseType{"Name"}}})
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04009750 { # lost base
9751 next;
9752 }
Andrey Ponomarenko16934472012-03-29 15:37:04 +04009753 my $VSize_Old = getVTable_Size($BaseType{"Name"}, 1);
9754 my $VSize_New = getVTable_Size($BaseType{"Name"}, 2);
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04009755 if($VSize_Old!=$VSize_New)
9756 {
Andrey Ponomarenko85043792012-05-14 16:48:07 +04009757 foreach my $Symbol (@VFunctions)
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +04009758 { # TODO: affected non-virtual methods?
9759 if(not defined $VirtualTable_Model{2}{$ClassName}{$Symbol})
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04009760 { # Removed_Virtual_Method, will be registered in mergeVirtualTables()
9761 next;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009762 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +04009763 if($VirtualTable_Model{2}{$ClassName}{$Symbol}-$VirtualTable_Model{1}{$ClassName}{$Symbol}==0)
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04009764 { # skip interfaces that have not changed the absolute virtual position
9765 next;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009766 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +04009767 if(not symbolFilter($Symbol, 1, "Affected", $Level)) {
9768 next;
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04009769 }
Andrey Ponomarenko16934472012-03-29 15:37:04 +04009770 $VTableChanged_M{$BaseType{"Name"}} = 1;
9771 $VTableChanged_M{$ClassName} = 1;
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04009772 foreach my $VirtFunc (keys(%{$AddedInt_Virt{$Level}{$BaseType{"Name"}}}))
9773 { # the reason of the layout change: added virtual functions
9774 next if($VirtualReplacement{$VirtFunc});
9775 my $ProblemType = "Added_Virtual_Method";
9776 if($CompleteSignature{2}{$VirtFunc}{"PureVirt"}) {
9777 $ProblemType = "Added_Pure_Virtual_Method";
9778 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +04009779 %{$CompatProblems{$Level}{$Symbol}{$ProblemType}{get_Signature($VirtFunc, 2)}}=(
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04009780 "Type_Name"=>$BaseType{"Name"},
9781 "Type_Type"=>"Class",
9782 "Target"=>get_Signature($VirtFunc, 2) );
9783 }
9784 foreach my $VirtFunc (keys(%{$RemovedInt_Virt{$Level}{$BaseType{"Name"}}}))
9785 { # the reason of the layout change: removed virtual functions
9786 next if($VirtualReplacement{$VirtFunc});
9787 my $ProblemType = "Removed_Virtual_Method";
9788 if($CompleteSignature{1}{$VirtFunc}{"PureVirt"}) {
9789 $ProblemType = "Removed_Pure_Virtual_Method";
9790 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +04009791 %{$CompatProblems{$Level}{$Symbol}{$ProblemType}{get_Signature($VirtFunc, 1)}}=(
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04009792 "Type_Name"=>$BaseType{"Name"},
9793 "Type_Type"=>"Class",
9794 "Target"=>get_Signature($VirtFunc, 1) );
9795 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009796 }
9797 }
9798 }
9799 }
9800 }
9801 }
9802 }
9803}
9804
9805sub isCreatable($$)
9806{
9807 my ($ClassId, $LibVersion) = @_;
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04009808 if($AllocableClass{$LibVersion}{$TypeInfo{$LibVersion}{$ClassId}{"Name"}}
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009809 or isCopyingClass($ClassId, $LibVersion)) {
9810 return 1;
9811 }
9812 if(keys(%{$Class_SubClasses{$LibVersion}{$ClassId}}))
9813 { # Fix for incomplete data: if this class has
9814 # a base class then it should also has a constructor
9815 return 1;
9816 }
9817 if($ReturnedClass{$LibVersion}{$ClassId})
9818 { # returned by some method of this class
9819 # or any other class
9820 return 1;
9821 }
9822 return 0;
9823}
9824
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04009825sub isUsedClass($$$)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009826{
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04009827 my ($ClassId, $LibVersion, $Level) = @_;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009828 if(keys(%{$ParamClass{$LibVersion}{$ClassId}}))
9829 { # parameter of some exported method
9830 return 1;
9831 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04009832 my $CName = $TypeInfo{$LibVersion}{$ClassId}{"Name"};
9833 if(keys(%{$ClassMethods{$Level}{$LibVersion}{$CName}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009834 { # method from target class
9835 return 1;
9836 }
9837 return 0;
9838}
9839
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04009840sub mergeVirtualTables($$)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009841{ # check for changes in the virtual table
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04009842 my ($Interface, $Level) = @_;
Andrey Ponomarenko16934472012-03-29 15:37:04 +04009843 # affected methods:
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009844 # - virtual
9845 # - pure-virtual
9846 # - non-virtual
9847 if($CompleteSignature{1}{$Interface}{"Data"})
9848 { # global data is not affected
9849 return;
9850 }
9851 my $Class_Id = $CompleteSignature{1}{$Interface}{"Class"};
Andrey Ponomarenko16934472012-03-29 15:37:04 +04009852 if(not $Class_Id) {
9853 return;
9854 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04009855 my $CName = $TypeInfo{1}{$Class_Id}{"Name"};
Andrey Ponomarenko16934472012-03-29 15:37:04 +04009856 if(cmpVTables_Real($CName, 1)==0)
9857 { # no changes
9858 return;
9859 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04009860 $CheckedTypes{$Level}{$CName} = 1;
9861 if($Level eq "Binary")
9862 { # Binary-level
9863 if($CompleteSignature{1}{$Interface}{"PureVirt"}
9864 and not isUsedClass($Class_Id, 1, $Level))
9865 { # pure virtuals should not be affected
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04009866 # if there are no exported methods using this class
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04009867 return;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009868 }
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04009869 }
9870 foreach my $Func (keys(%{$VirtualTable{1}{$CName}}))
9871 {
9872 if(defined $VirtualTable{2}{$CName}{$Func}
9873 and defined $CompleteSignature{2}{$Func})
9874 {
9875 if(not $CompleteSignature{1}{$Func}{"PureVirt"}
9876 and $CompleteSignature{2}{$Func}{"PureVirt"})
9877 { # became pure virtual
9878 %{$CompatProblems{$Level}{$Interface}{"Virtual_Method_Became_Pure"}{$tr_name{$Func}}}=(
9879 "Type_Name"=>$CName,
9880 "Type_Type"=>"Class",
9881 "Target"=>get_Signature_M($Func, 1) );
9882 $VTableChanged_M{$CName} = 1;
9883 }
9884 elsif($CompleteSignature{1}{$Func}{"PureVirt"}
9885 and not $CompleteSignature{2}{$Func}{"PureVirt"})
9886 { # became non-pure virtual
9887 %{$CompatProblems{$Level}{$Interface}{"Virtual_Method_Became_Non_Pure"}{$tr_name{$Func}}}=(
9888 "Type_Name"=>$CName,
9889 "Type_Type"=>"Class",
9890 "Target"=>get_Signature_M($Func, 1) );
9891 $VTableChanged_M{$CName} = 1;
9892 }
9893 }
9894 }
9895 if($Level eq "Binary")
9896 { # Binary-level
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04009897 # check virtual table structure
9898 foreach my $AddedVFunc (keys(%{$AddedInt_Virt{$Level}{$CName}}))
9899 {
9900 next if($Interface eq $AddedVFunc);
9901 next if($VirtualReplacement{$AddedVFunc});
9902 my $VPos_Added = $VirtualTable{2}{$CName}{$AddedVFunc};
9903 if($CompleteSignature{2}{$AddedVFunc}{"PureVirt"})
9904 { # pure virtual methods affect all others (virtual and non-virtual)
9905 %{$CompatProblems{$Level}{$Interface}{"Added_Pure_Virtual_Method"}{$tr_name{$AddedVFunc}}}=(
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009906 "Type_Name"=>$CName,
9907 "Type_Type"=>"Class",
9908 "Target"=>get_Signature($AddedVFunc, 2) );
Andrey Ponomarenko16934472012-03-29 15:37:04 +04009909 $VTableChanged_M{$CName} = 1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009910 }
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04009911 elsif(not defined $VirtualTable{1}{$CName}
9912 or $VPos_Added>keys(%{$VirtualTable{1}{$CName}}))
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04009913 { # added virtual function at the end of v-table
Andrey Ponomarenko16934472012-03-29 15:37:04 +04009914 if(not keys(%{$VirtualTable_Model{1}{$CName}}))
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04009915 { # became polymorphous class, added v-table pointer
9916 %{$CompatProblems{$Level}{$Interface}{"Added_First_Virtual_Method"}{$tr_name{$AddedVFunc}}}=(
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009917 "Type_Name"=>$CName,
9918 "Type_Type"=>"Class",
9919 "Target"=>get_Signature($AddedVFunc, 2) );
Andrey Ponomarenko16934472012-03-29 15:37:04 +04009920 $VTableChanged_M{$CName} = 1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009921 }
9922 else
9923 {
Andrey Ponomarenko16934472012-03-29 15:37:04 +04009924 my $VSize_Old = getVTable_Size($CName, 1);
9925 my $VSize_New = getVTable_Size($CName, 2);
Andrey Ponomarenko9927e332012-10-19 10:50:48 +04009926 next if($VSize_Old==$VSize_New); # exception: register as removed and added virtual method
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04009927 if(isCopyingClass($Class_Id, 1))
9928 { # class has no constructors and v-table will be copied by applications, this may affect all methods
9929 my $ProblemType = "Added_Virtual_Method";
9930 if(isLeafClass($Class_Id, 1)) {
9931 $ProblemType = "Added_Virtual_Method_At_End_Of_Leaf_Copying_Class";
9932 }
9933 %{$CompatProblems{$Level}{$Interface}{$ProblemType}{$tr_name{$AddedVFunc}}}=(
9934 "Type_Name"=>$CName,
9935 "Type_Type"=>"Class",
9936 "Target"=>get_Signature($AddedVFunc, 2) );
Andrey Ponomarenko16934472012-03-29 15:37:04 +04009937 $VTableChanged_M{$CName} = 1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009938 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04009939 else
9940 {
9941 my $ProblemType = "Added_Virtual_Method";
9942 if(isLeafClass($Class_Id, 1)) {
9943 $ProblemType = "Added_Virtual_Method_At_End_Of_Leaf_Allocable_Class";
9944 }
9945 %{$CompatProblems{$Level}{$Interface}{$ProblemType}{$tr_name{$AddedVFunc}}}=(
9946 "Type_Name"=>$CName,
9947 "Type_Type"=>"Class",
9948 "Target"=>get_Signature($AddedVFunc, 2) );
Andrey Ponomarenko16934472012-03-29 15:37:04 +04009949 $VTableChanged_M{$CName} = 1;
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04009950 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009951 }
9952 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04009953 elsif($CompleteSignature{1}{$Interface}{"Virt"}
9954 or $CompleteSignature{1}{$Interface}{"PureVirt"})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009955 {
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04009956 if(defined $VirtualTable{1}{$CName}
9957 and defined $VirtualTable{2}{$CName})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009958 {
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04009959 my $VPos_Old = $VirtualTable{1}{$CName}{$Interface};
9960 my $VPos_New = $VirtualTable{2}{$CName}{$Interface};
9961 if($VPos_Added<=$VPos_Old and $VPos_Old!=$VPos_New)
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04009962 {
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04009963 my @Affected = ($Interface, keys(%{$OverriddenMethods{1}{$Interface}}));
9964 foreach my $ASymbol (@Affected)
9965 {
Andrey Ponomarenko85043792012-05-14 16:48:07 +04009966 if(not $CompleteSignature{1}{$ASymbol}{"PureVirt"})
9967 {
Andrey Ponomarenko9927e332012-10-19 10:50:48 +04009968 if(not symbolFilter($ASymbol, 1, "Affected", $Level)) {
Andrey Ponomarenko85043792012-05-14 16:48:07 +04009969 next;
9970 }
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04009971 }
9972 $CheckedSymbols{$Level}{$ASymbol} = 1;
9973 %{$CompatProblems{$Level}{$ASymbol}{"Added_Virtual_Method"}{$tr_name{$AddedVFunc}}}=(
9974 "Type_Name"=>$CName,
9975 "Type_Type"=>"Class",
9976 "Target"=>get_Signature($AddedVFunc, 2) );
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04009977 $VTableChanged_M{$TypeInfo{1}{$CompleteSignature{1}{$ASymbol}{"Class"}}{"Name"}} = 1;
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04009978 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009979 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009980 }
9981 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04009982 else {
9983 # safe
9984 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009985 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04009986 foreach my $RemovedVFunc (keys(%{$RemovedInt_Virt{$Level}{$CName}}))
9987 {
9988 next if($VirtualReplacement{$RemovedVFunc});
9989 if($RemovedVFunc eq $Interface
9990 and $CompleteSignature{1}{$RemovedVFunc}{"PureVirt"})
9991 { # This case is for removed virtual methods
Andrey Ponomarenko9927e332012-10-19 10:50:48 +04009992 # implemented in both versions of a library
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04009993 next;
9994 }
Andrey Ponomarenko16934472012-03-29 15:37:04 +04009995 if(not keys(%{$VirtualTable_Model{2}{$CName}}))
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04009996 { # became non-polymorphous class, removed v-table pointer
9997 %{$CompatProblems{$Level}{$Interface}{"Removed_Last_Virtual_Method"}{$tr_name{$RemovedVFunc}}}=(
9998 "Type_Name"=>$CName,
9999 "Type_Type"=>"Class",
10000 "Target"=>get_Signature($RemovedVFunc, 1) );
Andrey Ponomarenko16934472012-03-29 15:37:04 +040010001 $VTableChanged_M{$CName} = 1;
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040010002 }
10003 elsif($CompleteSignature{1}{$Interface}{"Virt"}
10004 or $CompleteSignature{1}{$Interface}{"PureVirt"})
10005 {
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040010006 if(defined $VirtualTable{1}{$CName} and defined $VirtualTable{2}{$CName})
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040010007 {
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040010008 if(not defined $VirtualTable{1}{$CName}{$Interface}) {
10009 next;
10010 }
10011 my $VPos_New = -1;
10012 if(defined $VirtualTable{2}{$CName}{$Interface})
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040010013 {
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040010014 $VPos_New = $VirtualTable{2}{$CName}{$Interface};
10015 }
10016 else
10017 {
10018 if($Interface ne $RemovedVFunc) {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040010019 next;
10020 }
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040010021 }
10022 my $VPos_Removed = $VirtualTable{1}{$CName}{$RemovedVFunc};
10023 my $VPos_Old = $VirtualTable{1}{$CName}{$Interface};
10024 if($VPos_Removed<=$VPos_Old and $VPos_Old!=$VPos_New)
10025 {
10026 my @Affected = ($Interface, keys(%{$OverriddenMethods{1}{$Interface}}));
10027 foreach my $ASymbol (@Affected)
10028 {
Andrey Ponomarenko85043792012-05-14 16:48:07 +040010029 if(not $CompleteSignature{1}{$ASymbol}{"PureVirt"})
10030 {
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040010031 if(not symbolFilter($ASymbol, 1, "Affected", $Level)) {
Andrey Ponomarenko85043792012-05-14 16:48:07 +040010032 next;
10033 }
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040010034 }
10035 my $ProblemType = "Removed_Virtual_Method";
10036 if($CompleteSignature{1}{$RemovedVFunc}{"PureVirt"}) {
10037 $ProblemType = "Removed_Pure_Virtual_Method";
10038 }
10039 $CheckedSymbols{$Level}{$ASymbol} = 1;
10040 %{$CompatProblems{$Level}{$ASymbol}{$ProblemType}{$tr_name{$RemovedVFunc}}}=(
10041 "Type_Name"=>$CName,
10042 "Type_Type"=>"Class",
10043 "Target"=>get_Signature($RemovedVFunc, 1) );
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040010044 $VTableChanged_M{$TypeInfo{1}{$CompleteSignature{1}{$ASymbol}{"Class"}}{"Name"}} = 1;
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040010045 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040010046 }
10047 }
10048 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010049 }
10050 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040010051 else
10052 { # Source-level
10053 foreach my $AddedVFunc (keys(%{$AddedInt_Virt{$Level}{$CName}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010054 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040010055 next if($Interface eq $AddedVFunc);
10056 if($CompleteSignature{2}{$AddedVFunc}{"PureVirt"})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010057 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040010058 %{$CompatProblems{$Level}{$Interface}{"Added_Pure_Virtual_Method"}{$tr_name{$AddedVFunc}}}=(
10059 "Type_Name"=>$CName,
10060 "Type_Type"=>"Class",
10061 "Target"=>get_Signature($AddedVFunc, 2) );
10062 }
10063 }
10064 foreach my $RemovedVFunc (keys(%{$RemovedInt_Virt{$Level}{$CName}}))
10065 {
10066 if($CompleteSignature{1}{$RemovedVFunc}{"PureVirt"})
10067 {
10068 %{$CompatProblems{$Level}{$Interface}{"Removed_Pure_Virtual_Method"}{$tr_name{$RemovedVFunc}}}=(
10069 "Type_Name"=>$CName,
10070 "Type_Type"=>"Class",
10071 "Target"=>get_Signature($RemovedVFunc, 1) );
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010072 }
10073 }
10074 }
10075}
10076
10077sub find_MemberPair_Pos_byName($$)
10078{
10079 my ($Member_Name, $Pair_Type) = @_;
10080 $Member_Name=~s/\A[_]+|[_]+\Z//g;
10081 foreach my $MemberPair_Pos (sort {int($a)<=>int($b)} keys(%{$Pair_Type->{"Memb"}}))
10082 {
10083 if(defined $Pair_Type->{"Memb"}{$MemberPair_Pos})
10084 {
10085 my $Name = $Pair_Type->{"Memb"}{$MemberPair_Pos}{"name"};
10086 $Name=~s/\A[_]+|[_]+\Z//g;
10087 if($Name eq $Member_Name) {
10088 return $MemberPair_Pos;
10089 }
10090 }
10091 }
10092 return "lost";
10093}
10094
10095sub find_MemberPair_Pos_byVal($$)
10096{
10097 my ($Member_Value, $Pair_Type) = @_;
10098 foreach my $MemberPair_Pos (sort {int($a)<=>int($b)} keys(%{$Pair_Type->{"Memb"}}))
10099 {
10100 if(defined $Pair_Type->{"Memb"}{$MemberPair_Pos}
10101 and $Pair_Type->{"Memb"}{$MemberPair_Pos}{"value"} eq $Member_Value) {
10102 return $MemberPair_Pos;
10103 }
10104 }
10105 return "lost";
10106}
10107
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040010108my %Severity_Val=(
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010109 "High"=>3,
10110 "Medium"=>2,
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040010111 "Low"=>1,
10112 "Safe"=>-1
10113);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010114
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040010115sub maxSeverity($$)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010116{
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040010117 my ($S1, $S2) = @_;
10118 if(cmpSeverities($S1, $S2)) {
10119 return $S1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010120 }
10121 else {
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040010122 return $S2;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010123 }
10124}
10125
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040010126sub cmpSeverities($$)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010127{
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040010128 my ($S1, $S2) = @_;
10129 if(not $S1) {
10130 return 0;
10131 }
10132 elsif(not $S2) {
10133 return 1;
10134 }
10135 return ($Severity_Val{$S1}>$Severity_Val{$S2});
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010136}
10137
10138sub getProblemSeverity($$)
10139{
10140 my ($Level, $Kind) = @_;
10141 return $CompatRules{$Level}{$Kind}{"Severity"};
10142}
10143
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040010144sub isRecurType($$)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010145{
10146 foreach (@RecurTypes)
10147 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040010148 if( $_->{"T1"} eq $_[0]
10149 and $_->{"T2"} eq $_[1] )
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010150 {
10151 return 1;
10152 }
10153 }
10154 return 0;
10155}
10156
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040010157sub pushType($$)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010158{
10159 my %TypeIDs=(
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040010160 "T1" => $_[0], #Tid1
10161 "T2" => $_[1] #Tid2
Andrey Ponomarenko16934472012-03-29 15:37:04 +040010162 );
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010163 push(@RecurTypes, \%TypeIDs);
10164}
10165
10166sub isRenamed($$$$$)
10167{
10168 my ($MemPos, $Type1, $LVersion1, $Type2, $LVersion2) = @_;
10169 my $Member_Name = $Type1->{"Memb"}{$MemPos}{"name"};
10170 my $MemberType_Id = $Type1->{"Memb"}{$MemPos}{"type"};
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +040010171 my %MemberType_Pure = get_PureType($MemberType_Id, $TypeInfo{$LVersion1});
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010172 if(not defined $Type2->{"Memb"}{$MemPos}) {
10173 return "";
10174 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040010175 my $PairType_Id = $Type2->{"Memb"}{$MemPos}{"type"};
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +040010176 my %PairType_Pure = get_PureType($PairType_Id, $TypeInfo{$LVersion2});
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010177
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040010178 my $Pair_Name = $Type2->{"Memb"}{$MemPos}{"name"};
10179 my $MemberPair_Pos_Rev = ($Member_Name eq $Pair_Name)?$MemPos:find_MemberPair_Pos_byName($Pair_Name, $Type1);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010180 if($MemberPair_Pos_Rev eq "lost")
10181 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040010182 if($MemberType_Pure{"Name"} eq $PairType_Pure{"Name"})
10183 { # base type match
10184 return $Pair_Name;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010185 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040010186 if($TypeInfo{$LVersion1}{$MemberType_Id}{"Name"} eq $TypeInfo{$LVersion2}{$PairType_Id}{"Name"})
10187 { # exact type match
10188 return $Pair_Name;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010189 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040010190 if($MemberType_Pure{"Size"} eq $PairType_Pure{"Size"})
10191 { # size match
10192 return $Pair_Name;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010193 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040010194 if(isReserved($Pair_Name))
10195 { # reserved fields
10196 return $Pair_Name;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010197 }
10198 }
10199 return "";
10200}
10201
10202sub isLastElem($$)
10203{
10204 my ($Pos, $TypeRef) = @_;
10205 my $Name = $TypeRef->{"Memb"}{$Pos}{"name"};
10206 if($Name=~/last|count|max|total/i)
10207 { # GST_LEVEL_COUNT, GST_RTSP_ELAST
10208 return 1;
10209 }
10210 elsif($Name=~/END|NLIMITS\Z/)
10211 { # __RLIMIT_NLIMITS
10212 return 1;
10213 }
10214 elsif($Name=~/\AN[A-Z](.+)[a-z]+s\Z/
10215 and $Pos+1==keys(%{$TypeRef->{"Memb"}}))
10216 { # NImageFormats, NColorRoles
10217 return 1;
10218 }
10219 return 0;
10220}
10221
10222sub nonComparable($$)
10223{
10224 my ($T1, $T2) = @_;
10225 if($T1->{"Name"} ne $T2->{"Name"}
10226 and not isAnon($T1->{"Name"})
10227 and not isAnon($T2->{"Name"}))
10228 { # different names
10229 if($T1->{"Type"} ne "Pointer"
10230 or $T2->{"Type"} ne "Pointer")
10231 { # compare base types
10232 return 1;
10233 }
10234 if($T1->{"Name"}!~/\Avoid\s*\*/
10235 and $T2->{"Name"}=~/\Avoid\s*\*/)
10236 {
10237 return 1;
10238 }
10239 }
10240 elsif($T1->{"Type"} ne $T2->{"Type"})
10241 { # different types
10242 if($T1->{"Type"} eq "Class"
10243 and $T2->{"Type"} eq "Struct")
10244 { # "class" to "struct"
10245 return 0;
10246 }
10247 elsif($T2->{"Type"} eq "Class"
10248 and $T1->{"Type"} eq "Struct")
10249 { # "struct" to "class"
10250 return 0;
10251 }
10252 else
10253 { # "class" to "enum"
10254 # "union" to "class"
10255 # ...
10256 return 1;
10257 }
10258 }
10259 return 0;
10260}
10261
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040010262sub mergeTypes($$$)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010263{
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040010264 my ($Type1_Id, $Type2_Id, $Level) = @_;
10265 return () if(not $Type1_Id or not $Type2_Id);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010266 my (%Sub_SubProblems, %SubProblems) = ();
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040010267 if($Cache{"mergeTypes"}{$Level}{$Type1_Id}{$Type2_Id})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010268 { # already merged
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040010269 return %{$Cache{"mergeTypes"}{$Level}{$Type1_Id}{$Type2_Id}};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010270 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040010271 my %Type1 = get_Type($Type1_Id, 1);
10272 my %Type2 = get_Type($Type2_Id, 2);
Andrey Ponomarenko16934472012-03-29 15:37:04 +040010273 if(not $Type1{"Name"} or not $Type2{"Name"}) {
10274 return ();
10275 }
10276 $CheckedTypes{$Level}{$Type1{"Name"}}=1;
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +040010277 my %Type1_Pure = get_PureType($Type1_Id, $TypeInfo{1});
10278 my %Type2_Pure = get_PureType($Type2_Id, $TypeInfo{2});
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040010279 $CheckedTypes{$Level}{$Type1_Pure{"Name"}}=1;
Andrey Ponomarenko85043792012-05-14 16:48:07 +040010280 if(not $Type1_Pure{"Size"} or not $Type2_Pure{"Size"})
10281 { # including a case when "class Class { ... };" changed to "class Class;"
10282 return ();
10283 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040010284 if(isRecurType($Type1_Pure{"Tid"}, $Type2_Pure{"Tid"}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010285 { # skip recursive declarations
10286 return ();
10287 }
10288 return () if(not $Type1_Pure{"Name"} or not $Type2_Pure{"Name"});
10289 return () if($SkipTypes{1}{$Type1_Pure{"Name"}});
10290 return () if($SkipTypes{1}{$Type1{"Name"}});
10291
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040010292 my %Typedef_1 = goToFirst($Type1{"Tid"}, 1, "Typedef");
10293 my %Typedef_2 = goToFirst($Type2{"Tid"}, 2, "Typedef");
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040010294 if(not $UseOldDumps and %Typedef_1 and %Typedef_2
10295 and $Typedef_1{"Type"} eq "Typedef" and $Typedef_2{"Type"} eq "Typedef"
10296 and $Typedef_1{"Name"} eq $Typedef_2{"Name"})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010297 {
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +040010298 my %Base_1 = get_OneStep_BaseType($Typedef_1{"Tid"}, $TypeInfo{1});
10299 my %Base_2 = get_OneStep_BaseType($Typedef_2{"Tid"}, $TypeInfo{2});
Andrey Ponomarenko85043792012-05-14 16:48:07 +040010300 if($Base_1{"Name"} ne $Base_2{"Name"})
10301 {
10302 if(differentDumps("G")
10303 or differentDumps("V"))
10304 { # different GCC versions or different dumps
10305 $Base_1{"Name"} = uncover_typedefs($Base_1{"Name"}, 1);
10306 $Base_2{"Name"} = uncover_typedefs($Base_2{"Name"}, 2);
10307 # std::__va_list and __va_list
10308 $Base_1{"Name"}=~s/\A(\w+::)+//;
10309 $Base_2{"Name"}=~s/\A(\w+::)+//;
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040010310 $Base_1{"Name"} = formatName($Base_1{"Name"}, "T");
10311 $Base_2{"Name"} = formatName($Base_2{"Name"}, "T");
Andrey Ponomarenko85043792012-05-14 16:48:07 +040010312 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010313 }
10314 if($Base_1{"Name"}!~/anon\-/ and $Base_2{"Name"}!~/anon\-/
10315 and $Base_1{"Name"} ne $Base_2{"Name"})
10316 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040010317 if($Level eq "Binary"
10318 and $Type1{"Size"} ne $Type2{"Size"})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010319 {
10320 %{$SubProblems{"DataType_Size"}{$Typedef_1{"Name"}}}=(
10321 "Target"=>$Typedef_1{"Name"},
10322 "Type_Name"=>$Typedef_1{"Name"},
10323 "Type_Type"=>"Typedef",
10324 "Old_Size"=>$Type1{"Size"}*$BYTE_SIZE,
10325 "New_Size"=>$Type2{"Size"}*$BYTE_SIZE );
10326 }
10327 %{$SubProblems{"Typedef_BaseType"}{$Typedef_1{"Name"}}}=(
10328 "Target"=>$Typedef_1{"Name"},
10329 "Type_Name"=>$Typedef_1{"Name"},
10330 "Type_Type"=>"Typedef",
10331 "Old_Value"=>$Base_1{"Name"},
10332 "New_Value"=>$Base_2{"Name"} );
10333 }
10334 }
10335 if(nonComparable(\%Type1_Pure, \%Type2_Pure))
10336 { # different types (reported in detectTypeChange(...))
10337 if($Type1_Pure{"Name"} eq $Type2_Pure{"Name"}
10338 and $Type1_Pure{"Type"} ne $Type2_Pure{"Type"}
10339 and $Type1_Pure{"Type"}!~/Intrinsic|Pointer|Ref|Typedef/)
10340 { # different type of the type
10341 %{$SubProblems{"DataType_Type"}{$Type1_Pure{"Name"}}}=(
10342 "Target"=>$Type1_Pure{"Name"},
10343 "Type_Name"=>$Type1_Pure{"Name"},
10344 "Type_Type"=>$Type1_Pure{"Type"},
10345 "Old_Value"=>lc($Type1_Pure{"Type"}),
10346 "New_Value"=>lc($Type2_Pure{"Type"}) );
10347 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040010348 %{$Cache{"mergeTypes"}{$Level}{$Type1_Id}{$Type2_Id}} = %SubProblems;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010349 return %SubProblems;
10350 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040010351 pushType($Type1_Pure{"Tid"}, $Type2_Pure{"Tid"});
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010352 if(($Type1_Pure{"Name"} eq $Type2_Pure{"Name"}
10353 or (isAnon($Type1_Pure{"Name"}) and isAnon($Type2_Pure{"Name"})))
10354 and $Type1_Pure{"Type"}=~/\A(Struct|Class|Union)\Z/)
10355 { # checking size
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040010356 if($Level eq "Binary"
10357 and $Type1_Pure{"Size"} ne $Type2_Pure{"Size"})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010358 {
10359 my $ProblemKind = "DataType_Size";
10360 if($Type1_Pure{"Type"} eq "Class"
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040010361 and keys(%{$ClassMethods{$Level}{1}{$Type1_Pure{"Name"}}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010362 {
10363 if(isCopyingClass($Type1_Pure{"Tid"}, 1)) {
10364 $ProblemKind = "Size_Of_Copying_Class";
10365 }
10366 elsif($AllocableClass{1}{$Type1_Pure{"Name"}})
10367 {
10368 if(int($Type2_Pure{"Size"})>int($Type1_Pure{"Size"})) {
10369 $ProblemKind = "Size_Of_Allocable_Class_Increased";
10370 }
10371 else {
10372 # descreased size of allocable class
10373 # it has no special effects
10374 }
10375 }
10376 }
10377 %{$SubProblems{$ProblemKind}{$Type1_Pure{"Name"}}}=(
10378 "Target"=>$Type1_Pure{"Name"},
10379 "Type_Name"=>$Type1_Pure{"Name"},
10380 "Type_Type"=>$Type1_Pure{"Type"},
10381 "Old_Size"=>$Type1_Pure{"Size"}*$BYTE_SIZE,
10382 "New_Size"=>$Type2_Pure{"Size"}*$BYTE_SIZE,
10383 "InitialType_Type"=>$Type1_Pure{"Type"} );
10384 }
10385 }
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040010386 if(defined $Type1_Pure{"BaseType"} and $Type1_Pure{"BaseType"}{"Tid"}
10387 and defined $Type2_Pure{"BaseType"} and $Type2_Pure{"BaseType"}{"Tid"})
10388 { # checking base types
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040010389 %Sub_SubProblems = mergeTypes($Type1_Pure{"BaseType"}{"Tid"}, $Type2_Pure{"BaseType"}{"Tid"}, $Level);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010390 foreach my $Sub_SubProblemType (keys(%Sub_SubProblems))
10391 {
10392 foreach my $Sub_SubLocation (keys(%{$Sub_SubProblems{$Sub_SubProblemType}}))
10393 {
10394 foreach my $Attr (keys(%{$Sub_SubProblems{$Sub_SubProblemType}{$Sub_SubLocation}})) {
10395 $SubProblems{$Sub_SubProblemType}{$Sub_SubLocation}{$Attr} = $Sub_SubProblems{$Sub_SubProblemType}{$Sub_SubLocation}{$Attr};
10396 }
10397 $SubProblems{$Sub_SubProblemType}{$Sub_SubLocation}{"InitialType_Type"} = $Type1_Pure{"Type"};
10398 }
10399 }
10400 }
10401 my (%AddedField, %RemovedField, %RenamedField, %RenamedField_Rev, %RelatedField, %RelatedField_Rev) = ();
10402 my %NameToPosA = map {$Type1_Pure{"Memb"}{$_}{"name"}=>$_} keys(%{$Type1_Pure{"Memb"}});
10403 my %NameToPosB = map {$Type2_Pure{"Memb"}{$_}{"name"}=>$_} keys(%{$Type2_Pure{"Memb"}});
10404 foreach my $Member_Pos (sort {int($a) <=> int($b)} keys(%{$Type1_Pure{"Memb"}}))
10405 { # detect removed and renamed fields
10406 my $Member_Name = $Type1_Pure{"Memb"}{$Member_Pos}{"name"};
10407 next if(not $Member_Name);
10408 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);
10409 if($MemberPair_Pos eq "lost")
10410 {
10411 if($Type2_Pure{"Type"}=~/\A(Struct|Class|Union)\Z/)
10412 {
10413 if(isUnnamed($Member_Name))
10414 { # support for old-version dumps
10415 # unnamed fields have been introduced in the ACC 1.23 (dump 2.1 format)
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040010416 if(not checkDump(2, "2.1")) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010417 next;
10418 }
10419 }
10420 if(my $RenamedTo = isRenamed($Member_Pos, \%Type1_Pure, 1, \%Type2_Pure, 2))
10421 { # renamed
10422 $RenamedField{$Member_Pos}=$RenamedTo;
10423 $RenamedField_Rev{$NameToPosB{$RenamedTo}}=$Member_Name;
10424 }
10425 else
10426 { # removed
10427 $RemovedField{$Member_Pos}=1;
10428 }
10429 }
10430 elsif($Type1_Pure{"Type"} eq "Enum")
10431 {
10432 my $Member_Value1 = $Type1_Pure{"Memb"}{$Member_Pos}{"value"};
10433 next if($Member_Value1 eq "");
10434 $MemberPair_Pos = find_MemberPair_Pos_byVal($Member_Value1, \%Type2_Pure);
10435 if($MemberPair_Pos ne "lost")
10436 { # renamed
10437 my $RenamedTo = $Type2_Pure{"Memb"}{$MemberPair_Pos}{"name"};
10438 my $MemberPair_Pos_Rev = find_MemberPair_Pos_byName($RenamedTo, \%Type1_Pure);
10439 if($MemberPair_Pos_Rev eq "lost")
10440 {
10441 $RenamedField{$Member_Pos}=$RenamedTo;
10442 $RenamedField_Rev{$NameToPosB{$RenamedTo}}=$Member_Name;
10443 }
10444 else {
10445 $RemovedField{$Member_Pos}=1;
10446 }
10447 }
10448 else
10449 { # removed
10450 $RemovedField{$Member_Pos}=1;
10451 }
10452 }
10453 }
10454 else
10455 { # related
10456 $RelatedField{$Member_Pos} = $MemberPair_Pos;
10457 $RelatedField_Rev{$MemberPair_Pos} = $Member_Pos;
10458 }
10459 }
10460 foreach my $Member_Pos (sort {int($a) <=> int($b)} keys(%{$Type2_Pure{"Memb"}}))
10461 { # detect added fields
10462 my $Member_Name = $Type2_Pure{"Memb"}{$Member_Pos}{"name"};
10463 next if(not $Member_Name);
10464 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);
10465 if($MemberPair_Pos eq "lost")
10466 {
10467 if(isUnnamed($Member_Name))
10468 { # support for old-version dumps
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040010469 # unnamed fields have been introduced in the ACC 1.23 (dump 2.1 format)
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040010470 if(not checkDump(1, "2.1")) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010471 next;
10472 }
10473 }
10474 if($Type2_Pure{"Type"}=~/\A(Struct|Class|Union|Enum)\Z/)
10475 {
10476 if(not $RenamedField_Rev{$Member_Pos})
10477 { # added
10478 $AddedField{$Member_Pos}=1;
10479 }
10480 }
10481 }
10482 }
10483 if($Type2_Pure{"Type"}=~/\A(Struct|Class)\Z/)
10484 { # detect moved fields
10485 my (%RelPos, %RelPosName, %AbsPos) = ();
10486 my $Pos = 0;
10487 foreach my $Member_Pos (sort {int($a) <=> int($b)} keys(%{$Type1_Pure{"Memb"}}))
10488 { # relative positions in 1st version
10489 my $Member_Name = $Type1_Pure{"Memb"}{$Member_Pos}{"name"};
10490 next if(not $Member_Name);
10491 if(not $RemovedField{$Member_Pos})
10492 { # old type without removed fields
10493 $RelPos{1}{$Member_Name}=$Pos;
10494 $RelPosName{1}{$Pos} = $Member_Name;
10495 $AbsPos{1}{$Pos++} = $Member_Pos;
10496 }
10497 }
10498 $Pos = 0;
10499 foreach my $Member_Pos (sort {int($a) <=> int($b)} keys(%{$Type2_Pure{"Memb"}}))
10500 { # relative positions in 2nd version
10501 my $Member_Name = $Type2_Pure{"Memb"}{$Member_Pos}{"name"};
10502 next if(not $Member_Name);
10503 if(not $AddedField{$Member_Pos})
10504 { # new type without added fields
10505 $RelPos{2}{$Member_Name}=$Pos;
10506 $RelPosName{2}{$Pos} = $Member_Name;
10507 $AbsPos{2}{$Pos++} = $Member_Pos;
10508 }
10509 }
10510 foreach my $Member_Name (keys(%{$RelPos{1}}))
10511 {
10512 my $RPos1 = $RelPos{1}{$Member_Name};
10513 my $AbsPos1 = $NameToPosA{$Member_Name};
10514 my $Member_Name2 = $Member_Name;
10515 if(my $RenamedTo = $RenamedField{$AbsPos1})
10516 { # renamed
10517 $Member_Name2 = $RenamedTo;
10518 }
10519 my $RPos2 = $RelPos{2}{$Member_Name2};
10520 if($RPos2 ne "" and $RPos1 ne $RPos2)
10521 { # different relative positions
10522 my $AbsPos2 = $NameToPosB{$Member_Name2};
10523 if($AbsPos1 ne $AbsPos2)
10524 { # different absolute positions
10525 my $ProblemType = "Moved_Field";
10526 if(not isPublic(\%Type1_Pure, $AbsPos1))
10527 { # may change layout and size of type
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040010528 if($Level eq "Source") {
10529 next;
10530 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010531 $ProblemType = "Moved_Private_Field";
10532 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040010533 if($Level eq "Binary"
10534 and $Type1_Pure{"Size"} ne $Type2_Pure{"Size"})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010535 { # affected size
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040010536 my $MemSize1 = $TypeInfo{1}{$Type1_Pure{"Memb"}{$AbsPos1}{"type"}}{"Size"};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010537 my $MovedAbsPos = $AbsPos{1}{$RPos2};
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040010538 my $MemSize2 = $TypeInfo{1}{$Type1_Pure{"Memb"}{$MovedAbsPos}{"type"}}{"Size"};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010539 if($MemSize1 ne $MemSize2) {
10540 $ProblemType .= "_And_Size";
10541 }
10542 }
10543 if($ProblemType eq "Moved_Private_Field") {
10544 next;
10545 }
10546 %{$SubProblems{$ProblemType}{$Member_Name}}=(
10547 "Target"=>$Member_Name,
10548 "Type_Name"=>$Type1_Pure{"Name"},
10549 "Type_Type"=>$Type1_Pure{"Type"},
10550 "Old_Value"=>$RPos1,
10551 "New_Value"=>$RPos2 );
10552 }
10553 }
10554 }
10555 }
10556 foreach my $Member_Pos (sort {int($a) <=> int($b)} keys(%{$Type1_Pure{"Memb"}}))
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040010557 { # check older fields, public and private
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010558 my $Member_Name = $Type1_Pure{"Memb"}{$Member_Pos}{"name"};
10559 next if(not $Member_Name);
10560 if(my $RenamedTo = $RenamedField{$Member_Pos})
10561 { # renamed
10562 if($Type2_Pure{"Type"}=~/\A(Struct|Class|Union)\Z/)
10563 {
10564 if(isPublic(\%Type1_Pure, $Member_Pos))
10565 {
10566 %{$SubProblems{"Renamed_Field"}{$Member_Name}}=(
10567 "Target"=>$Member_Name,
10568 "Type_Name"=>$Type1_Pure{"Name"},
10569 "Type_Type"=>$Type1_Pure{"Type"},
10570 "Old_Value"=>$Member_Name,
10571 "New_Value"=>$RenamedTo );
10572 }
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040010573 elsif(isReserved($Member_Name))
10574 {
10575 %{$SubProblems{"Used_Reserved_Field"}{$Member_Name}}=(
10576 "Target"=>$Member_Name,
10577 "Type_Name"=>$Type1_Pure{"Name"},
10578 "Type_Type"=>$Type1_Pure{"Type"},
10579 "Old_Value"=>$Member_Name,
10580 "New_Value"=>$RenamedTo );
10581 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010582 }
10583 elsif($Type1_Pure{"Type"} eq "Enum")
10584 {
10585 %{$SubProblems{"Enum_Member_Name"}{$Type1_Pure{"Memb"}{$Member_Pos}{"value"}}}=(
10586 "Target"=>$Type1_Pure{"Memb"}{$Member_Pos}{"value"},
10587 "Type_Name"=>$Type1_Pure{"Name"},
10588 "Type_Type"=>$Type1_Pure{"Type"},
10589 "Old_Value"=>$Member_Name,
10590 "New_Value"=>$RenamedTo );
10591 }
10592 }
10593 elsif($RemovedField{$Member_Pos})
10594 { # removed
10595 if($Type2_Pure{"Type"}=~/\A(Struct|Class)\Z/)
10596 {
10597 my $ProblemType = "Removed_Field";
10598 if(not isPublic(\%Type1_Pure, $Member_Pos)
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040010599 or isUnnamed($Member_Name))
10600 {
10601 if($Level eq "Source") {
10602 next;
10603 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010604 $ProblemType = "Removed_Private_Field";
10605 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040010606 if($Level eq "Binary"
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +040010607 and not isMemPadded($Member_Pos, -1, \%Type1_Pure, \%RemovedField, $TypeInfo{1}, $WORD_SIZE{1}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010608 {
10609 if(my $MNum = isAccessible(\%Type1_Pure, \%RemovedField, $Member_Pos+1, -1))
10610 { # affected fields
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +040010611 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 +040010612 { # changed offset
10613 $ProblemType .= "_And_Layout";
10614 }
10615 }
10616 if($Type1_Pure{"Size"} ne $Type2_Pure{"Size"})
10617 { # affected size
10618 $ProblemType .= "_And_Size";
10619 }
10620 }
10621 if($ProblemType eq "Removed_Private_Field") {
10622 next;
10623 }
10624 %{$SubProblems{$ProblemType}{$Member_Name}}=(
10625 "Target"=>$Member_Name,
10626 "Type_Name"=>$Type1_Pure{"Name"},
10627 "Type_Type"=>$Type1_Pure{"Type"} );
10628 }
10629 elsif($Type2_Pure{"Type"} eq "Union")
10630 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040010631 if($Level eq "Binary"
10632 and $Type1_Pure{"Size"} ne $Type2_Pure{"Size"})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010633 {
10634 %{$SubProblems{"Removed_Union_Field_And_Size"}{$Member_Name}}=(
10635 "Target"=>$Member_Name,
10636 "Type_Name"=>$Type1_Pure{"Name"},
10637 "Type_Type"=>$Type1_Pure{"Type"} );
10638 }
10639 else
10640 {
10641 %{$SubProblems{"Removed_Union_Field"}{$Member_Name}}=(
10642 "Target"=>$Member_Name,
10643 "Type_Name"=>$Type1_Pure{"Name"},
10644 "Type_Type"=>$Type1_Pure{"Type"} );
10645 }
10646 }
10647 elsif($Type1_Pure{"Type"} eq "Enum")
10648 {
10649 %{$SubProblems{"Enum_Member_Removed"}{$Member_Name}}=(
10650 "Target"=>$Member_Name,
10651 "Type_Name"=>$Type1_Pure{"Name"},
10652 "Type_Type"=>$Type1_Pure{"Type"},
10653 "Old_Value"=>$Member_Name );
10654 }
10655 }
10656 else
10657 { # changed
10658 my $MemberPair_Pos = $RelatedField{$Member_Pos};
10659 if($Type1_Pure{"Type"} eq "Enum")
10660 {
10661 my $Member_Value1 = $Type1_Pure{"Memb"}{$Member_Pos}{"value"};
10662 next if($Member_Value1 eq "");
10663 my $Member_Value2 = $Type2_Pure{"Memb"}{$MemberPair_Pos}{"value"};
10664 next if($Member_Value2 eq "");
10665 if($Member_Value1 ne $Member_Value2)
10666 {
10667 my $ProblemType = "Enum_Member_Value";
10668 if(isLastElem($Member_Pos, \%Type1_Pure)) {
10669 $ProblemType = "Enum_Last_Member_Value";
10670 }
10671 %{$SubProblems{$ProblemType}{$Member_Name}}=(
10672 "Target"=>$Member_Name,
10673 "Type_Name"=>$Type1_Pure{"Name"},
10674 "Type_Type"=>$Type1_Pure{"Type"},
10675 "Old_Value"=>$Member_Value1,
10676 "New_Value"=>$Member_Value2 );
10677 }
10678 }
10679 elsif($Type2_Pure{"Type"}=~/\A(Struct|Class|Union)\Z/)
10680 {
10681 my $MemberType1_Id = $Type1_Pure{"Memb"}{$Member_Pos}{"type"};
10682 my $MemberType2_Id = $Type2_Pure{"Memb"}{$MemberPair_Pos}{"type"};
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040010683 my $SizeV1 = $TypeInfo{1}{$MemberType1_Id}{"Size"}*$BYTE_SIZE;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010684 if(my $BSize1 = $Type1_Pure{"Memb"}{$Member_Pos}{"bitfield"}) {
10685 $SizeV1 = $BSize1;
10686 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040010687 my $SizeV2 = $TypeInfo{2}{$MemberType2_Id}{"Size"}*$BYTE_SIZE;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010688 if(my $BSize2 = $Type2_Pure{"Memb"}{$MemberPair_Pos}{"bitfield"}) {
10689 $SizeV2 = $BSize2;
10690 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040010691 my $MemberType1_Name = $TypeInfo{1}{$MemberType1_Id}{"Name"};
10692 my $MemberType2_Name = $TypeInfo{2}{$MemberType2_Id}{"Name"};
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040010693 if($Level eq "Binary"
10694 and $SizeV1 ne $SizeV2)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010695 {
10696 if($MemberType1_Name eq $MemberType2_Name or (isAnon($MemberType1_Name) and isAnon($MemberType2_Name))
10697 or ($Type1_Pure{"Memb"}{$Member_Pos}{"bitfield"} and $Type2_Pure{"Memb"}{$MemberPair_Pos}{"bitfield"}))
10698 { # field size change (including anon-structures and unions)
10699 # - same types
10700 # - unnamed types
10701 # - bitfields
10702 my $ProblemType = "Field_Size";
10703 if(not isPublic(\%Type1_Pure, $Member_Pos)
10704 or isUnnamed($Member_Name))
10705 { # should not be accessed by applications, goes to "Low Severity"
10706 # example: "abidata" members in GStreamer types
10707 $ProblemType = "Private_".$ProblemType;
10708 }
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +040010709 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 +040010710 { # check an effect
10711 if(my $MNum = isAccessible(\%Type1_Pure, \%RemovedField, $Member_Pos+1, -1))
10712 { # public fields after the current
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +040010713 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 +040010714 { # changed offset
10715 $ProblemType .= "_And_Layout";
10716 }
10717 }
10718 if($Type1_Pure{"Size"} ne $Type2_Pure{"Size"}) {
10719 $ProblemType .= "_And_Type_Size";
10720 }
10721 }
10722 if($ProblemType eq "Private_Field_Size")
10723 { # private field size with no effect
10724 $ProblemType = "";
10725 }
10726 if($ProblemType)
10727 { # register a problem
10728 %{$SubProblems{$ProblemType}{$Member_Name}}=(
10729 "Target"=>$Member_Name,
10730 "Type_Name"=>$Type1_Pure{"Name"},
10731 "Type_Type"=>$Type1_Pure{"Type"},
10732 "Old_Size"=>$SizeV1,
10733 "New_Size"=>$SizeV2);
10734 }
10735 }
10736 }
10737 if($Type1_Pure{"Memb"}{$Member_Pos}{"bitfield"}
10738 or $Type2_Pure{"Memb"}{$MemberPair_Pos}{"bitfield"})
10739 { # do NOT check bitfield type changes
10740 next;
10741 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040010742 if(checkDump(1, "2.13") and checkDump(2, "2.13"))
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040010743 {
10744 if(not $Type1_Pure{"Memb"}{$Member_Pos}{"mutable"}
10745 and $Type2_Pure{"Memb"}{$MemberPair_Pos}{"mutable"})
10746 {
10747 %{$SubProblems{"Field_Became_Mutable"}{$Member_Name}}=(
10748 "Target"=>$Member_Name,
10749 "Type_Name"=>$Type1_Pure{"Name"},
10750 "Type_Type"=>$Type1_Pure{"Type"});
10751 }
10752 elsif($Type1_Pure{"Memb"}{$Member_Pos}{"mutable"}
10753 and not $Type2_Pure{"Memb"}{$MemberPair_Pos}{"mutable"})
10754 {
10755 %{$SubProblems{"Field_Became_NonMutable"}{$Member_Name}}=(
10756 "Target"=>$Member_Name,
10757 "Type_Name"=>$Type1_Pure{"Name"},
10758 "Type_Type"=>$Type1_Pure{"Type"});
10759 }
10760 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040010761 %Sub_SubProblems = detectTypeChange($MemberType1_Id, $MemberType2_Id, "Field", $Level);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010762 foreach my $ProblemType (keys(%Sub_SubProblems))
10763 {
10764 my $Old_Value = $Sub_SubProblems{$ProblemType}{"Old_Value"};
10765 my $New_Value = $Sub_SubProblems{$ProblemType}{"New_Value"};
10766 if($ProblemType eq "Field_Type"
10767 or $ProblemType eq "Field_Type_And_Size")
10768 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040010769 if(checkDump(1, "2.6") and checkDump(2, "2.6"))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010770 {
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040010771 if(my $RA = addedQual($Old_Value, $New_Value, "volatile"))
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040010772 {
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040010773 %{$Sub_SubProblems{"Field_Became_Volatile"}} = %{$Sub_SubProblems{$ProblemType}};
10774 if($Level eq "Source"
10775 and cmpBTypes($Old_Value, $New_Value, 1, 2)) {
10776 delete($Sub_SubProblems{$ProblemType});
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040010777 }
10778 }
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040010779 elsif(my $RR = removedQual($Old_Value, $New_Value, "volatile"))
10780 {
10781 %{$Sub_SubProblems{"Field_Became_NonVolatile"}} = %{$Sub_SubProblems{$ProblemType}};
10782 if($Level eq "Source"
10783 and cmpBTypes($Old_Value, $New_Value, 1, 2)) {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040010784 delete($Sub_SubProblems{$ProblemType});
10785 }
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040010786 }
10787 }
10788 if(my $RA = addedQual($Old_Value, $New_Value, "const"))
10789 {
10790 if($RA==2) {
10791 %{$Sub_SubProblems{"Field_Added_Const"}} = %{$Sub_SubProblems{$ProblemType}};
10792 }
10793 else {
10794 %{$Sub_SubProblems{"Field_Became_Const"}} = %{$Sub_SubProblems{$ProblemType}};
10795 }
10796 if($Level eq "Source"
10797 and cmpBTypes($Old_Value, $New_Value, 1, 2)) {
10798 delete($Sub_SubProblems{$ProblemType});
10799 }
10800 }
10801 elsif(my $RR = removedQual($Old_Value, $New_Value, "const"))
10802 {
10803 if($RR==2) {
10804 %{$Sub_SubProblems{"Field_Removed_Const"}} = %{$Sub_SubProblems{$ProblemType}};
10805 }
10806 else {
10807 %{$Sub_SubProblems{"Field_Became_NonConst"}} = %{$Sub_SubProblems{$ProblemType}};
10808 }
10809 if($Level eq "Source"
10810 and cmpBTypes($Old_Value, $New_Value, 1, 2)) {
10811 delete($Sub_SubProblems{$ProblemType});
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010812 }
10813 }
10814 }
10815 }
10816 foreach my $ProblemType (keys(%Sub_SubProblems))
10817 {
10818 my $ProblemType_Init = $ProblemType;
10819 if($ProblemType eq "Field_Type_And_Size")
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040010820 { # Binary
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010821 if(not isPublic(\%Type1_Pure, $Member_Pos)
10822 or isUnnamed($Member_Name)) {
10823 $ProblemType = "Private_".$ProblemType;
10824 }
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +040010825 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 +040010826 { # check an effect
10827 if(my $MNum = isAccessible(\%Type1_Pure, \%RemovedField, $Member_Pos+1, -1))
10828 { # public fields after the current
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +040010829 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 +040010830 { # changed offset
10831 $ProblemType .= "_And_Layout";
10832 }
10833 }
10834 if($Type1_Pure{"Size"} ne $Type2_Pure{"Size"}) {
10835 $ProblemType .= "_And_Type_Size";
10836 }
10837 }
10838 }
10839 else
10840 {
10841 if(not isPublic(\%Type1_Pure, $Member_Pos)
10842 or isUnnamed($Member_Name)) {
10843 next;
10844 }
10845 }
10846 if($ProblemType eq "Private_Field_Type_And_Size")
10847 { # private field change with no effect
10848 next;
10849 }
10850 %{$SubProblems{$ProblemType}{$Member_Name}}=(
10851 "Target"=>$Member_Name,
10852 "Type_Name"=>$Type1_Pure{"Name"},
10853 "Type_Type"=>$Type1_Pure{"Type"} );
10854 foreach my $Attr (keys(%{$Sub_SubProblems{$ProblemType_Init}}))
10855 { # other properties
10856 $SubProblems{$ProblemType}{$Member_Name}{$Attr} = $Sub_SubProblems{$ProblemType_Init}{$Attr};
10857 }
10858 }
10859 if(not isPublic(\%Type1_Pure, $Member_Pos))
10860 { # do NOT check internal type changes
10861 next;
10862 }
10863 if($MemberType1_Id and $MemberType2_Id)
10864 {# checking member type changes (replace)
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040010865 %Sub_SubProblems = mergeTypes($MemberType1_Id, $MemberType2_Id, $Level);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010866 foreach my $Sub_SubProblemType (keys(%Sub_SubProblems))
10867 {
10868 foreach my $Sub_SubLocation (keys(%{$Sub_SubProblems{$Sub_SubProblemType}}))
10869 {
10870 my $NewLocation = ($Sub_SubLocation)?$Member_Name."->".$Sub_SubLocation:$Member_Name;
10871 $SubProblems{$Sub_SubProblemType}{$NewLocation}{"IsInTypeInternals"}=1;
10872 foreach my $Attr (keys(%{$Sub_SubProblems{$Sub_SubProblemType}{$Sub_SubLocation}})) {
10873 $SubProblems{$Sub_SubProblemType}{$NewLocation}{$Attr} = $Sub_SubProblems{$Sub_SubProblemType}{$Sub_SubLocation}{$Attr};
10874 }
10875 if($Sub_SubLocation!~/\-\>/) {
10876 $SubProblems{$Sub_SubProblemType}{$NewLocation}{"Start_Type_Name"} = $MemberType1_Name;
10877 }
10878 }
10879 }
10880 }
10881 }
10882 }
10883 }
10884 foreach my $Member_Pos (sort {int($a) <=> int($b)} keys(%{$Type2_Pure{"Memb"}}))
10885 { # checking added members, public and private
10886 my $Member_Name = $Type2_Pure{"Memb"}{$Member_Pos}{"name"};
10887 next if(not $Member_Name);
10888 if($AddedField{$Member_Pos})
10889 { # added
10890 if($Type2_Pure{"Type"}=~/\A(Struct|Class)\Z/)
10891 {
10892 my $ProblemType = "Added_Field";
10893 if(not isPublic(\%Type2_Pure, $Member_Pos)
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040010894 or isUnnamed($Member_Name))
10895 {
10896 if($Level eq "Source") {
10897 next;
10898 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010899 $ProblemType = "Added_Private_Field";
10900 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040010901 if($Level eq "Binary"
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +040010902 and not isMemPadded($Member_Pos, -1, \%Type2_Pure, \%AddedField, $TypeInfo{2}, $WORD_SIZE{2}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010903 {
10904 if(my $MNum = isAccessible(\%Type2_Pure, \%AddedField, $Member_Pos, -1))
10905 { # public fields after the current
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +040010906 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 +040010907 { # changed offset
10908 $ProblemType .= "_And_Layout";
10909 }
10910 }
10911 if($Type1_Pure{"Size"} ne $Type2_Pure{"Size"}) {
10912 $ProblemType .= "_And_Size";
10913 }
10914 }
10915 if($ProblemType eq "Added_Private_Field")
10916 { # skip added private fields
10917 next;
10918 }
10919 %{$SubProblems{$ProblemType}{$Member_Name}}=(
10920 "Target"=>$Member_Name,
10921 "Type_Name"=>$Type1_Pure{"Name"},
10922 "Type_Type"=>$Type1_Pure{"Type"} );
10923 }
10924 elsif($Type2_Pure{"Type"} eq "Union")
10925 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040010926 if($Level eq "Binary"
10927 and $Type1_Pure{"Size"} ne $Type2_Pure{"Size"})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010928 {
10929 %{$SubProblems{"Added_Union_Field_And_Size"}{$Member_Name}}=(
10930 "Target"=>$Member_Name,
10931 "Type_Name"=>$Type1_Pure{"Name"},
10932 "Type_Type"=>$Type1_Pure{"Type"} );
10933 }
10934 else
10935 {
10936 %{$SubProblems{"Added_Union_Field"}{$Member_Name}}=(
10937 "Target"=>$Member_Name,
10938 "Type_Name"=>$Type1_Pure{"Name"},
10939 "Type_Type"=>$Type1_Pure{"Type"} );
10940 }
10941 }
10942 elsif($Type2_Pure{"Type"} eq "Enum")
10943 {
10944 my $Member_Value = $Type2_Pure{"Memb"}{$Member_Pos}{"value"};
10945 next if($Member_Value eq "");
10946 %{$SubProblems{"Added_Enum_Member"}{$Member_Name}}=(
10947 "Target"=>$Member_Name,
10948 "Type_Name"=>$Type2_Pure{"Name"},
10949 "Type_Type"=>$Type2_Pure{"Type"},
10950 "New_Value"=>$Member_Value );
10951 }
10952 }
10953 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040010954 %{$Cache{"mergeTypes"}{$Level}{$Type1_Id}{$Type2_Id}} = %SubProblems;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010955 pop(@RecurTypes);
10956 return %SubProblems;
10957}
10958
10959sub isUnnamed($) {
10960 return $_[0]=~/\Aunnamed\d+\Z/;
10961}
10962
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040010963sub get_ShortType($$)
10964{
10965 my ($TypeId, $LibVersion) = @_;
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +040010966 my $TypeName = uncover_typedefs($TypeInfo{$LibVersion}{$TypeId}{"Name"}, $LibVersion);
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040010967 if(my $NameSpace = $TypeInfo{$LibVersion}{$TypeId}{"NameSpace"}) {
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040010968 $TypeName=~s/\A$NameSpace\:\://g;
10969 }
10970 return $TypeName;
10971}
10972
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040010973sub goToFirst($$$)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010974{
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040010975 my ($TypeId, $LibVersion, $Type_Type) = @_;
Andrey Ponomarenko16934472012-03-29 15:37:04 +040010976 return () if(not $TypeId);
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040010977 if(defined $Cache{"goToFirst"}{$TypeId}{$LibVersion}{$Type_Type}) {
10978 return %{$Cache{"goToFirst"}{$TypeId}{$LibVersion}{$Type_Type}};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010979 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040010980 return () if(not $TypeInfo{$LibVersion}{$TypeId});
10981 my %Type = %{$TypeInfo{$LibVersion}{$TypeId}};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010982 return () if(not $Type{"Type"});
10983 if($Type{"Type"} ne $Type_Type)
10984 {
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040010985 return () if(not defined $Type{"BaseType"});
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040010986 return () if(not $Type{"BaseType"}{"Tid"});
10987 %Type = goToFirst($Type{"BaseType"}{"Tid"}, $LibVersion, $Type_Type);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010988 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040010989 $Cache{"goToFirst"}{$TypeId}{$LibVersion}{$Type_Type} = \%Type;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010990 return %Type;
10991}
10992
10993my %TypeSpecAttributes = (
10994 "Const" => 1,
10995 "Volatile" => 1,
10996 "ConstVolatile" => 1,
10997 "Restrict" => 1,
10998 "Typedef" => 1
10999);
11000
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040011001sub get_PureType($$)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011002{
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +040011003 my ($TypeId, $Info) = @_;
11004 if(not $TypeId or not $Info
11005 or not $Info->{$TypeId}) {
11006 return ();
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011007 }
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +040011008 if(defined $Cache{"get_PureType"}{$TypeId}{$Info}) {
11009 return %{$Cache{"get_PureType"}{$TypeId}{$Info}};
11010 }
11011 my %Type = %{$Info->{$TypeId}};
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040011012 return %Type if(not defined $Type{"BaseType"});
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040011013 return %Type if(not $Type{"BaseType"}{"Tid"});
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011014 if($TypeSpecAttributes{$Type{"Type"}}) {
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +040011015 %Type = get_PureType($Type{"BaseType"}{"Tid"}, $Info);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011016 }
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +040011017 $Cache{"get_PureType"}{$TypeId}{$Info} = \%Type;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011018 return %Type;
11019}
11020
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040011021sub get_PLevel($$)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011022{
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040011023 my ($TypeId, $LibVersion) = @_;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011024 return 0 if(not $TypeId);
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040011025 if(defined $Cache{"get_PLevel"}{$TypeId}{$LibVersion}) {
11026 return $Cache{"get_PLevel"}{$TypeId}{$LibVersion};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011027 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040011028 return 0 if(not $TypeInfo{$LibVersion}{$TypeId});
11029 my %Type = %{$TypeInfo{$LibVersion}{$TypeId}};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011030 return 1 if($Type{"Type"}=~/FuncPtr|MethodPtr|FieldPtr/);
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040011031 return 0 if(not defined $Type{"BaseType"});
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040011032 return 0 if(not $Type{"BaseType"}{"Tid"});
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011033 my $PointerLevel = 0;
11034 if($Type{"Type"} =~/Pointer|Ref|FuncPtr|MethodPtr|FieldPtr/) {
11035 $PointerLevel += 1;
11036 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040011037 $PointerLevel += get_PLevel($Type{"BaseType"}{"Tid"}, $LibVersion);
11038 $Cache{"get_PLevel"}{$TypeId}{$LibVersion} = $PointerLevel;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011039 return $PointerLevel;
11040}
11041
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040011042sub get_BaseType($$)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011043{
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040011044 my ($TypeId, $LibVersion) = @_;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011045 return () if(not $TypeId);
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040011046 if(defined $Cache{"get_BaseType"}{$TypeId}{$LibVersion}) {
11047 return %{$Cache{"get_BaseType"}{$TypeId}{$LibVersion}};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011048 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040011049 return () if(not $TypeInfo{$LibVersion}{$TypeId});
11050 my %Type = %{$TypeInfo{$LibVersion}{$TypeId}};
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040011051 return %Type if(not defined $Type{"BaseType"});
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040011052 return %Type if(not $Type{"BaseType"}{"Tid"});
11053 %Type = get_BaseType($Type{"BaseType"}{"Tid"}, $LibVersion);
11054 $Cache{"get_BaseType"}{$TypeId}{$LibVersion} = \%Type;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011055 return %Type;
11056}
11057
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040011058sub get_BaseTypeQual($$)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011059{
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040011060 my ($TypeId, $LibVersion) = @_;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011061 return "" if(not $TypeId);
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040011062 return "" if(not $TypeInfo{$LibVersion}{$TypeId});
11063 my %Type = %{$TypeInfo{$LibVersion}{$TypeId}};
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040011064 return "" if(not defined $Type{"BaseType"});
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040011065 return "" if(not $Type{"BaseType"}{"Tid"});
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011066 my $Qual = "";
11067 if($Type{"Type"} eq "Pointer") {
11068 $Qual .= "*";
11069 }
11070 elsif($Type{"Type"} eq "Ref") {
11071 $Qual .= "&";
11072 }
11073 elsif($Type{"Type"} eq "ConstVolatile") {
11074 $Qual .= "const volatile";
11075 }
11076 elsif($Type{"Type"} eq "Const"
11077 or $Type{"Type"} eq "Volatile"
11078 or $Type{"Type"} eq "Restrict") {
11079 $Qual .= lc($Type{"Type"});
11080 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040011081 my $BQual = get_BaseTypeQual($Type{"BaseType"}{"Tid"}, $LibVersion);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011082 return $BQual.$Qual;
11083}
11084
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040011085sub get_OneStep_BaseType($$)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011086{
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +040011087 my ($TypeId, $Info) = @_;
11088 if(not $TypeId or not $Info
11089 or not $Info->{$TypeId}) {
11090 return ();
11091 }
11092 my %Type = %{$Info->{$TypeId}};
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040011093 return %Type if(not defined $Type{"BaseType"});
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +040011094 if(my $BTid = $Type{"BaseType"}{"Tid"})
11095 {
11096 if($Info->{$BTid}) {
11097 return %{$Info->{$BTid}};
11098 }
11099 else { # something is going wrong
11100 return ();
11101 }
11102 }
11103 else {
11104 return %Type;
11105 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011106}
11107
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040011108sub get_Type($$)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011109{
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040011110 my ($TypeId, $LibVersion) = @_;
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040011111 return () if(not $TypeId);
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040011112 return () if(not $TypeInfo{$LibVersion}{$TypeId});
11113 return %{$TypeInfo{$LibVersion}{$TypeId}};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011114}
11115
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +040011116sub isPrivateData($)
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040011117{ # non-public global data
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011118 my $Symbol = $_[0];
11119 return ($Symbol=~/\A(_ZGV|_ZTI|_ZTS|_ZTT|_ZTV|_ZTC|_ZThn|_ZTv0_n)/);
11120}
11121
Andrey Ponomarenko01117f12012-06-26 12:23:02 +040011122sub isInLineInst($$$) {
11123 return (isTemplateInstance(@_) and not isTemplateSpec(@_));
11124}
11125
11126sub isTemplateInstance($$$)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011127{
Andrey Ponomarenko01117f12012-06-26 12:23:02 +040011128 my ($Symbol, $SInfo, $LibVersion) = @_;
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040011129 if($CheckObjectsOnly)
11130 {
11131 if($Symbol!~/\A(_Z|\?)/) {
11132 return 0;
11133 }
11134 if(my $Signature = $tr_name{$Symbol})
11135 {
11136 if(index($Signature,">")==-1) {
11137 return 0;
11138 }
11139 if(my $ShortName = substr($Signature, 0, find_center($Signature, "(")))
11140 {
Andrey Ponomarenko01117f12012-06-26 12:23:02 +040011141 if(index($ShortName,"<")!=-1
11142 and index($ShortName,">")!=-1) {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040011143 return 1;
11144 }
11145 }
11146 }
11147 }
11148 else
11149 {
Andrey Ponomarenko01117f12012-06-26 12:23:02 +040011150 if(my $ClassId = $SInfo->{"Class"})
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040011151 {
11152 if(my $ClassName = $TypeInfo{$LibVersion}{$ClassId}{"Name"})
11153 {
11154 if(index($ClassName,"<")!=-1) {
11155 return 1;
11156 }
11157 }
11158 }
Andrey Ponomarenko01117f12012-06-26 12:23:02 +040011159 if(my $ShortName = $SInfo->{"ShortName"})
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040011160 {
Andrey Ponomarenko01117f12012-06-26 12:23:02 +040011161 if(index($ShortName,"<")!=-1
11162 and index($ShortName,">")!=-1) {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040011163 return 1;
11164 }
11165 }
11166 }
11167 return 0;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011168}
11169
Andrey Ponomarenko01117f12012-06-26 12:23:02 +040011170sub isTemplateSpec($$$)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011171{
Andrey Ponomarenko01117f12012-06-26 12:23:02 +040011172 my ($Symbol, $SInfo, $LibVersion) = @_;
11173 if(my $ClassId = $SInfo->{"Class"})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011174 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040011175 if($TypeInfo{$LibVersion}{$ClassId}{"Spec"})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011176 { # class specialization
11177 return 1;
11178 }
Andrey Ponomarenko01117f12012-06-26 12:23:02 +040011179 elsif($SInfo->{"Spec"})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011180 { # method specialization
11181 return 1;
11182 }
11183 }
11184 return 0;
11185}
11186
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011187sub symbolFilter($$$$)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011188{ # some special cases when the symbol cannot be imported
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011189 my ($Symbol, $LibVersion, $Type, $Level) = @_;
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +040011190 if(isPrivateData($Symbol))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011191 { # non-public global data
11192 return 0;
11193 }
11194 if($CheckObjectsOnly) {
11195 return 0 if($Symbol=~/\A(_init|_fini)\Z/);
11196 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040011197 if($CheckHeadersOnly and not checkDump($LibVersion, "2.7"))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011198 { # support for old ABI dumps in --headers-only mode
11199 foreach my $Pos (keys(%{$CompleteSignature{$LibVersion}{$Symbol}{"Param"}}))
11200 {
11201 if(my $Pid = $CompleteSignature{$LibVersion}{$Symbol}{"Param"}{$Pos}{"type"})
11202 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040011203 my $PType = $TypeInfo{$LibVersion}{$Pid}{"Type"};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011204 if(not $PType or $PType eq "Unknown") {
11205 return 0;
11206 }
11207 }
11208 }
11209 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +040011210 if($Type=~/Affected/)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011211 {
11212 my $ClassId = $CompleteSignature{$LibVersion}{$Symbol}{"Class"};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011213 if($SkipSymbols{$LibVersion}{$Symbol})
11214 { # user defined symbols to ignore
11215 return 0;
11216 }
11217 my $NameSpace = $CompleteSignature{$LibVersion}{$Symbol}{"NameSpace"};
11218 if(not $NameSpace and $ClassId)
11219 { # class methods have no "NameSpace" attribute
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040011220 $NameSpace = $TypeInfo{$LibVersion}{$ClassId}{"NameSpace"};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011221 }
11222 if($NameSpace)
11223 { # user defined namespaces to ignore
11224 if($SkipNameSpaces{$LibVersion}{$NameSpace}) {
11225 return 0;
11226 }
11227 foreach my $NS (keys(%{$SkipNameSpaces{$LibVersion}}))
11228 { # nested namespaces
11229 if($NameSpace=~/\A\Q$NS\E(\:\:|\Z)/) {
11230 return 0;
11231 }
11232 }
11233 }
11234 if(my $Header = $CompleteSignature{$LibVersion}{$Symbol}{"Header"})
11235 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040011236 if(my $Skip = skipHeader($Header, $LibVersion))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011237 { # --skip-headers or <skip_headers> (not <skip_including>)
11238 if($Skip==1) {
11239 return 0;
11240 }
11241 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011242 }
11243 if($SymbolsListPath and not $SymbolsList{$Symbol})
11244 { # user defined symbols
11245 return 0;
11246 }
11247 if($AppPath and not $SymbolsList_App{$Symbol})
11248 { # user defined symbols (in application)
11249 return 0;
11250 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +040011251 if(not selectSymbol($Symbol, $CompleteSignature{$LibVersion}{$Symbol}, $Level, $LibVersion))
11252 { # non-target symbols
11253 return 0;
11254 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011255 if($Level eq "Binary")
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011256 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040011257 if($CheckObjectsOnly)
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011258 {
Andrey Ponomarenko01117f12012-06-26 12:23:02 +040011259 if(isTemplateInstance($Symbol, $CompleteSignature{$LibVersion}{$Symbol}, $LibVersion)) {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040011260 return 0;
11261 }
11262 }
11263 else
11264 {
11265 if($CompleteSignature{$LibVersion}{$Symbol}{"InLine"}
Andrey Ponomarenko01117f12012-06-26 12:23:02 +040011266 or isInLineInst($Symbol, $CompleteSignature{$LibVersion}{$Symbol}, $LibVersion))
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040011267 {
11268 if($ClassId and $CompleteSignature{$LibVersion}{$Symbol}{"Virt"})
11269 { # inline virtual methods
11270 if($Type=~/InlineVirt/) {
11271 return 1;
11272 }
11273 my $Allocable = (not isCopyingClass($ClassId, $LibVersion));
11274 if(not $Allocable)
11275 { # check bases
11276 foreach my $DCId (get_sub_classes($ClassId, $LibVersion, 1))
11277 {
11278 if(not isCopyingClass($DCId, $LibVersion))
11279 { # exists a derived class without default c-tor
11280 $Allocable=1;
11281 last;
11282 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011283 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011284 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040011285 if(not $Allocable) {
11286 return 0;
11287 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011288 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040011289 else
11290 { # inline non-virtual methods
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011291 return 0;
11292 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011293 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011294 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011295 }
11296 }
11297 return 1;
11298}
11299
11300sub mergeImpl()
11301{
11302 my $DiffCmd = get_CmdPath("diff");
11303 if(not $DiffCmd) {
11304 exitStatus("Not_Found", "can't find \"diff\"");
11305 }
11306 foreach my $Interface (sort keys(%{$Symbol_Library{1}}))
11307 { # implementation changes
11308 next if($CompleteSignature{1}{$Interface}{"Private"});
11309 next if(not $CompleteSignature{1}{$Interface}{"Header"} and not $CheckObjectsOnly);
11310 next if(not $Symbol_Library{2}{$Interface} and not $Symbol_Library{2}{$SymVer{2}{$Interface}});
Andrey Ponomarenko85043792012-05-14 16:48:07 +040011311 if(not symbolFilter($Interface, 1, "Affected", "Binary")) {
11312 next;
11313 }
Andrey Ponomarenko16934472012-03-29 15:37:04 +040011314 my $Impl1 = canonifyImpl($Interface_Impl{1}{$Interface});
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011315 next if(not $Impl1);
Andrey Ponomarenko16934472012-03-29 15:37:04 +040011316 my $Impl2 = canonifyImpl($Interface_Impl{2}{$Interface});
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011317 next if(not $Impl2);
11318 if($Impl1 ne $Impl2)
11319 {
11320 writeFile("$TMP_DIR/impl1", $Impl1);
11321 writeFile("$TMP_DIR/impl2", $Impl2);
Andrey Ponomarenkoa01311b2012-06-08 17:20:02 +040011322 my $Diff = `$DiffCmd -rNau \"$TMP_DIR/impl1\" \"$TMP_DIR/impl2\"`;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011323 $Diff=~s/(---|\+\+\+).+\n//g;
11324 $Diff=~s/[ ]{3,}/ /g;
11325 $Diff=~s/\n\@\@/\n \n\@\@/g;
Andrey Ponomarenkoa01311b2012-06-08 17:20:02 +040011326 unlink("$TMP_DIR/impl1");
11327 unlink("$TMP_DIR/impl2");
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011328 %{$ImplProblems{$Interface}}=(
11329 "Diff" => get_CodeView($Diff) );
11330 }
11331 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +040011332
11333 # clean memory
11334 %Interface_Impl = ();
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011335}
11336
Andrey Ponomarenko16934472012-03-29 15:37:04 +040011337sub canonifyImpl($)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011338{
11339 my $FuncBody= $_[0];
11340 return "" if(not $FuncBody);
11341 $FuncBody=~s/0x[a-f\d]+/0x?/g;# addr
11342 $FuncBody=~s/((\A|\n)[a-z]+[\t ]+)[a-f\d]+([^x]|\Z)/$1?$3/g;# call, jump
11343 $FuncBody=~s/# [a-f\d]+ /# ? /g;# call, jump
11344 $FuncBody=~s/%([a-z]+[a-f\d]*)/\%reg/g;# registers
11345 while($FuncBody=~s/\nnop[ \t]*(\n|\Z)/$1/g){};# empty op
11346 $FuncBody=~s/<.+?\.cpp.+?>/<name.cpp>/g;
11347 $FuncBody=~s/(\A|\n)[a-f\d]+ </$1? </g;# 5e74 <_ZN...
11348 $FuncBody=~s/\.L\d+/.L/g;
11349 $FuncBody=~s/#(-?)\d+/#$1?/g;# r3, [r3, #120]
11350 $FuncBody=~s/[\n]{2,}/\n/g;
11351 return $FuncBody;
11352}
11353
11354sub get_CodeView($)
11355{
11356 my $Code = $_[0];
11357 my $View = "";
11358 foreach my $Line (split(/\n/, $Code))
11359 {
11360 if($Line=~s/\A(\+|-)/$1 /g)
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040011361 { # bold line
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011362 $View .= "<tr><td><b>".htmlSpecChars($Line)."</b></td></tr>\n";
11363 }
11364 else {
11365 $View .= "<tr><td>".htmlSpecChars($Line)."</td></tr>\n";
11366 }
11367 }
11368 return "<table class='code_view'>$View</table>\n";
11369}
11370
11371sub getImplementations($$)
11372{
11373 my ($LibVersion, $Path) = @_;
11374 return if(not $LibVersion or not -e $Path);
11375 if($OSgroup eq "macos")
11376 {
11377 my $OtoolCmd = get_CmdPath("otool");
11378 if(not $OtoolCmd) {
11379 exitStatus("Not_Found", "can't find \"otool\"");
11380 }
11381 my $CurInterface = "";
Andrey Ponomarenkoa01311b2012-06-08 17:20:02 +040011382 foreach my $Line (split(/\n/, `$OtoolCmd -tv \"$Path\" 2>\"$TMP_DIR/null\"`))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011383 {
11384 if($Line=~/\A\s*_(\w+)\s*:/i) {
11385 $CurInterface = $1;
11386 }
11387 elsif($Line=~/\A\s*[\da-z]+\s+(.+?)\Z/i) {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040011388 $Interface_Impl{$LibVersion}{$CurInterface} .= $1."\n";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011389 }
11390 }
11391 }
11392 else
11393 {
11394 my $ObjdumpCmd = get_CmdPath("objdump");
11395 if(not $ObjdumpCmd) {
11396 exitStatus("Not_Found", "can't find \"objdump\"");
11397 }
11398 my $CurInterface = "";
Andrey Ponomarenkoa01311b2012-06-08 17:20:02 +040011399 foreach my $Line (split(/\n/, `$ObjdumpCmd -d \"$Path\" 2>\"$TMP_DIR/null\"`))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011400 {
11401 if($Line=~/\A[\da-z]+\s+<(\w+)>/i) {
11402 $CurInterface = $1;
11403 }
11404 else
11405 { # x86: 51fa:(\t)89 e5 (\t)mov %esp,%ebp
11406 # arm: 5020:(\t)e24cb004(\t)sub(\t)fp, ip, #4(\t); 0x4
11407 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 +040011408 $Interface_Impl{$LibVersion}{$CurInterface} .= $2."\n";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011409 }
11410 }
11411 }
11412 }
11413}
11414
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011415sub detectAdded($)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011416{
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011417 my $Level = $_[0];
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011418 foreach my $Symbol (keys(%{$Symbol_Library{2}}))
11419 {
11420 if(link_symbol($Symbol, 1, "+Deps"))
11421 { # linker can find a new symbol
11422 # in the old-version library
11423 # So, it's not a new symbol
11424 next;
11425 }
11426 if(my $VSym = $SymVer{2}{$Symbol}
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040011427 and index($Symbol,"\@")==-1) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011428 next;
11429 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011430 $AddedInt{$Level}{$Symbol} = 1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011431 }
11432}
11433
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011434sub detectRemoved($)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011435{
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011436 my $Level = $_[0];
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011437 foreach my $Symbol (keys(%{$Symbol_Library{1}}))
11438 {
11439 if($CheckObjectsOnly) {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011440 $CheckedSymbols{"Binary"}{$Symbol} = 1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011441 }
11442 if(link_symbol($Symbol, 2, "+Deps"))
11443 { # linker can find an old symbol
11444 # in the new-version library
11445 next;
11446 }
11447 if(my $VSym = $SymVer{1}{$Symbol}
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040011448 and index($Symbol,"\@")==-1) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011449 next;
11450 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011451 $RemovedInt{$Level}{$Symbol} = 1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011452 }
11453}
11454
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011455sub mergeLibs($)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011456{
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011457 my $Level = $_[0];
11458 foreach my $Symbol (sort keys(%{$AddedInt{$Level}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011459 { # checking added symbols
11460 next if($CompleteSignature{2}{$Symbol}{"Private"});
11461 next if(not $CompleteSignature{2}{$Symbol}{"Header"} and not $CheckObjectsOnly);
Andrey Ponomarenko85043792012-05-14 16:48:07 +040011462 next if(not symbolFilter($Symbol, 2, "Affected", $Level));
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011463 %{$CompatProblems{$Level}{$Symbol}{"Added_Symbol"}{""}}=();
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011464 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011465 foreach my $Symbol (sort keys(%{$RemovedInt{$Level}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011466 { # checking removed symbols
11467 next if($CompleteSignature{1}{$Symbol}{"Private"});
11468 next if(not $CompleteSignature{1}{$Symbol}{"Header"} and not $CheckObjectsOnly);
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040011469 if(index($Symbol, "_ZTV")==0)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011470 { # skip v-tables for templates, that should not be imported by applications
11471 next if($tr_name{$Symbol}=~/</);
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040011472 if(my $CName = $VTableClass{$Symbol})
11473 {
11474 if(not keys(%{$ClassMethods{$Level}{1}{$CName}}))
11475 { # vtables for "private" classes
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040011476 # use case: vtable for QDragManager (Qt 4.5.3 to 4.6.0) became HIDDEN symbol
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040011477 next;
11478 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011479 }
11480 }
11481 else {
Andrey Ponomarenko85043792012-05-14 16:48:07 +040011482 next if(not symbolFilter($Symbol, 1, "Affected", $Level));
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011483 }
11484 if($CompleteSignature{1}{$Symbol}{"PureVirt"})
11485 { # symbols for pure virtual methods cannot be called by clients
11486 next;
11487 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011488 %{$CompatProblems{$Level}{$Symbol}{"Removed_Symbol"}{""}}=();
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011489 }
11490}
11491
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040011492sub checkDump($$)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011493{
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040011494 my ($LibVersion, $V) = @_;
11495 if(defined $Cache{"checkDump"}{$LibVersion}{$V}) {
11496 return $Cache{"checkDump"}{$LibVersion}{$V};
11497 }
11498 return ($Cache{"checkDump"}{$LibVersion}{$V} = (not $UsedDump{$LibVersion}{"V"} or cmpVersions($UsedDump{$LibVersion}{"V"}, $V)>=0));
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011499}
11500
11501sub detectAdded_H($)
11502{
11503 my $Level = $_[0];
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011504 foreach my $Symbol (sort keys(%{$CompleteSignature{2}}))
11505 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011506 if($Level eq "Source")
11507 { # remove symbol version
11508 my ($SN, $SS, $SV) = separate_symbol($Symbol);
11509 $Symbol=$SN;
Andrey Ponomarenkob8d203d2012-05-25 18:11:07 +040011510
11511 if($CompleteSignature{2}{$Symbol}{"Artificial"})
11512 { # skip artificial constructors
11513 next;
11514 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011515 }
Andrey Ponomarenko16934472012-03-29 15:37:04 +040011516 if(not $CompleteSignature{2}{$Symbol}{"Header"}
11517 or not $CompleteSignature{2}{$Symbol}{"MnglName"}) {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011518 next;
11519 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040011520 if($ExtendedSymbols{$Symbol}) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011521 next;
11522 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011523 if(not defined $CompleteSignature{1}{$Symbol}
11524 or not $CompleteSignature{1}{$Symbol}{"MnglName"})
11525 {
Andrey Ponomarenko16934472012-03-29 15:37:04 +040011526 if($UsedDump{2}{"SrcBin"})
11527 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040011528 if($UsedDump{1}{"BinOnly"} or not checkDump(1, "2.11"))
Andrey Ponomarenko16934472012-03-29 15:37:04 +040011529 { # support for old and different (!) ABI dumps
11530 if(not $CompleteSignature{2}{$Symbol}{"Virt"}
11531 and not $CompleteSignature{2}{$Symbol}{"PureVirt"})
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011532 {
Andrey Ponomarenko16934472012-03-29 15:37:04 +040011533 if($CheckHeadersOnly)
Andrey Ponomarenko85043792012-05-14 16:48:07 +040011534 {
11535 if(my $Lang = $CompleteSignature{2}{$Symbol}{"Lang"})
11536 {
11537 if($Lang eq "C")
11538 { # support for old ABI dumps: missed extern "C" functions
11539 next;
11540 }
11541 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011542 }
Andrey Ponomarenko16934472012-03-29 15:37:04 +040011543 else
11544 {
11545 if(not link_symbol($Symbol, 2, "-Deps"))
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040011546 { # skip added inline symbols and const global data
Andrey Ponomarenko16934472012-03-29 15:37:04 +040011547 next;
11548 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011549 }
11550 }
11551 }
11552 }
11553 $AddedInt{$Level}{$Symbol} = 1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011554 }
11555 }
11556}
11557
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011558sub detectRemoved_H($)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011559{
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011560 my $Level = $_[0];
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011561 foreach my $Symbol (sort keys(%{$CompleteSignature{1}}))
11562 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011563 if($Level eq "Source")
11564 { # remove symbol version
11565 my ($SN, $SS, $SV) = separate_symbol($Symbol);
11566 $Symbol=$SN;
11567 }
Andrey Ponomarenko16934472012-03-29 15:37:04 +040011568 if(not $CompleteSignature{1}{$Symbol}{"Header"}
11569 or not $CompleteSignature{1}{$Symbol}{"MnglName"}) {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011570 next;
11571 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040011572 if($ExtendedSymbols{$Symbol}) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011573 next;
11574 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011575 if(not defined $CompleteSignature{2}{$Symbol}
11576 or not $CompleteSignature{2}{$Symbol}{"MnglName"})
Andrey Ponomarenko85043792012-05-14 16:48:07 +040011577 {
Andrey Ponomarenko16934472012-03-29 15:37:04 +040011578 if($UsedDump{1}{"SrcBin"})
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011579 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040011580 if($UsedDump{2}{"BinOnly"} or not checkDump(2, "2.11"))
Andrey Ponomarenko85043792012-05-14 16:48:07 +040011581 { # support for old and different (!) ABI dumps
Andrey Ponomarenko16934472012-03-29 15:37:04 +040011582 if(not $CompleteSignature{1}{$Symbol}{"Virt"}
11583 and not $CompleteSignature{1}{$Symbol}{"PureVirt"})
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011584 {
Andrey Ponomarenko16934472012-03-29 15:37:04 +040011585 if($CheckHeadersOnly)
11586 { # skip all removed symbols
Andrey Ponomarenko85043792012-05-14 16:48:07 +040011587 if(my $Lang = $CompleteSignature{1}{$Symbol}{"Lang"})
11588 {
11589 if($Lang eq "C")
11590 { # support for old ABI dumps: missed extern "C" functions
11591 next;
11592 }
11593 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011594 }
Andrey Ponomarenko16934472012-03-29 15:37:04 +040011595 else
11596 {
11597 if(not link_symbol($Symbol, 1, "-Deps"))
11598 { # skip removed inline symbols
11599 next;
11600 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011601 }
11602 }
11603 }
11604 }
Andrey Ponomarenkob8d203d2012-05-25 18:11:07 +040011605 if(not checkDump(1, "2.15"))
11606 {
11607 if($Symbol=~/_IT_E\Z/)
11608 { # _ZN28QExplicitlySharedDataPointerI22QSslCertificatePrivateEC1IT_EERKS_IT_E
11609 next;
11610 }
11611 }
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040011612 if(not $CompleteSignature{1}{$Symbol}{"Class"})
11613 {
11614 if(my $Short = $CompleteSignature{1}{$Symbol}{"ShortName"})
11615 {
11616 if(defined $Constants{2}{$Short})
11617 {
11618 my $Val = $Constants{2}{$Short}{"Value"};
11619 if(defined $Func_ShortName{2}{$Val})
11620 { # old name defined to new
11621 next;
11622 }
11623 }
11624 }
11625
11626 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011627 $RemovedInt{$Level}{$Symbol} = 1;
11628 if($Level eq "Source")
11629 { # search for a source-compatible equivalent
11630 setAlternative($Symbol, $Level);
11631 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011632 }
11633 }
11634}
11635
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011636sub mergeHeaders($)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011637{
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011638 my $Level = $_[0];
11639 foreach my $Symbol (sort keys(%{$AddedInt{$Level}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011640 { # checking added symbols
11641 next if($CompleteSignature{2}{$Symbol}{"PureVirt"});
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040011642 next if($CompleteSignature{2}{$Symbol}{"Private"});
11643 next if(not symbolFilter($Symbol, 2, "Affected", $Level));
Andrey Ponomarenko85043792012-05-14 16:48:07 +040011644 if($Level eq "Binary")
11645 {
11646 if($CompleteSignature{2}{$Symbol}{"InLine"})
11647 {
11648 if(not $CompleteSignature{2}{$Symbol}{"Virt"})
11649 { # skip inline non-virtual functions
11650 next;
11651 }
11652 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011653 }
11654 else
11655 { # Source
11656 if($SourceAlternative_B{$Symbol}) {
11657 next;
11658 }
11659 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011660 %{$CompatProblems{$Level}{$Symbol}{"Added_Symbol"}{""}}=();
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011661 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011662 foreach my $Symbol (sort keys(%{$RemovedInt{$Level}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011663 { # checking removed symbols
11664 next if($CompleteSignature{1}{$Symbol}{"PureVirt"});
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040011665 next if($CompleteSignature{1}{$Symbol}{"Private"});
11666 next if(not symbolFilter($Symbol, 1, "Affected", $Level));
Andrey Ponomarenko85043792012-05-14 16:48:07 +040011667 if($Level eq "Binary")
11668 {
11669 if($CompleteSignature{1}{$Symbol}{"InLine"})
11670 {
11671 if(not $CompleteSignature{1}{$Symbol}{"Virt"})
11672 { # skip inline non-virtual functions
11673 next;
11674 }
11675 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011676 }
11677 else
11678 { # Source
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040011679 if(my $Alt = $SourceAlternative{$Symbol})
11680 {
11681 if(defined $CompleteSignature{1}{$Alt}
11682 and $CompleteSignature{1}{$Symbol}{"Const"})
11683 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040011684 my $Cid = $CompleteSignature{1}{$Symbol}{"Class"};
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040011685 %{$CompatProblems{$Level}{$Symbol}{"Removed_Const_Overload"}{$tr_name{$Symbol}}}=(
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040011686 "Type_Name"=>$TypeInfo{1}{$Cid}{"Name"},
Andrey Ponomarenko85043792012-05-14 16:48:07 +040011687 "Type_Type"=>"Class",
11688 "Target"=>get_Signature($Alt, 1) );
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040011689 }
11690 else
11691 { # do NOT show removed symbol
11692 next;
11693 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011694 }
11695 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011696 %{$CompatProblems{$Level}{$Symbol}{"Removed_Symbol"}{""}}=();
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011697 }
11698}
11699
11700sub addParamNames($)
11701{
11702 my $LibraryVersion = $_[0];
11703 return if(not keys(%AddIntParams));
11704 my $SecondVersion = $LibraryVersion==1?2:1;
11705 foreach my $Interface (sort keys(%{$CompleteSignature{$LibraryVersion}}))
11706 {
11707 next if(not keys(%{$AddIntParams{$Interface}}));
11708 foreach my $ParamPos (sort {int($a)<=>int($b)} keys(%{$CompleteSignature{$LibraryVersion}{$Interface}{"Param"}}))
Andrey Ponomarenko85043792012-05-14 16:48:07 +040011709 { # add absent parameter names
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011710 my $ParamName = $CompleteSignature{$LibraryVersion}{$Interface}{"Param"}{$ParamPos}{"name"};
11711 if($ParamName=~/\Ap\d+\Z/ and my $NewParamName = $AddIntParams{$Interface}{$ParamPos})
Andrey Ponomarenko85043792012-05-14 16:48:07 +040011712 { # names from the external file
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011713 if(defined $CompleteSignature{$SecondVersion}{$Interface}
11714 and defined $CompleteSignature{$SecondVersion}{$Interface}{"Param"}{$ParamPos})
11715 {
11716 if($CompleteSignature{$SecondVersion}{$Interface}{"Param"}{$ParamPos}{"name"}=~/\Ap\d+\Z/) {
11717 $CompleteSignature{$LibraryVersion}{$Interface}{"Param"}{$ParamPos}{"name"} = $NewParamName;
11718 }
11719 }
11720 else {
11721 $CompleteSignature{$LibraryVersion}{$Interface}{"Param"}{$ParamPos}{"name"} = $NewParamName;
11722 }
11723 }
11724 }
11725 }
11726}
11727
11728sub detectChangedTypedefs()
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +040011729{ # detect changed typedefs to show
11730 # correct function signatures
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011731 foreach my $Typedef (keys(%{$Typedef_BaseName{1}}))
11732 {
11733 next if(not $Typedef);
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +040011734 my $BName1 = $Typedef_BaseName{1}{$Typedef};
11735 if(not $BName1 or isAnon($BName1)) {
11736 next;
11737 }
11738 my $BName2 = $Typedef_BaseName{2}{$Typedef};
11739 if(not $BName2 or isAnon($BName2)) {
11740 next;
11741 }
11742 if($BName1 ne $BName2) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011743 $ChangedTypedef{$Typedef} = 1;
11744 }
11745 }
11746}
11747
11748sub get_symbol_suffix($$)
11749{
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011750 my ($Symbol, $Full) = @_;
11751 my ($SN, $SO, $SV) = separate_symbol($Symbol);
11752 $Symbol=$SN;# remove version
11753 my $Signature = $tr_name{$Symbol};
Andrey Ponomarenko16934472012-03-29 15:37:04 +040011754 my $Suffix = substr($Signature, find_center($Signature, "("));
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011755 if(not $Full) {
11756 $Suffix=~s/(\))\s*(const volatile|volatile const|const|volatile)\Z/$1/g;
11757 }
11758 return $Suffix;
11759}
11760
11761sub get_symbol_prefix($$)
11762{
11763 my ($Symbol, $LibVersion) = @_;
11764 my $ShortName = $CompleteSignature{$LibVersion}{$Symbol}{"ShortName"};
11765 if(my $ClassId = $CompleteSignature{$LibVersion}{$Symbol}{"Class"})
11766 { # methods
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040011767 $ShortName = $TypeInfo{$LibVersion}{$ClassId}{"Name"}."::".$ShortName;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011768 }
11769 return $ShortName;
11770}
11771
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011772sub setAlternative($)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011773{
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011774 my $Symbol = $_[0];
11775 my $PSymbol = $Symbol;
11776 if(not defined $CompleteSignature{2}{$PSymbol}
11777 or (not $CompleteSignature{2}{$PSymbol}{"MnglName"}
11778 and not $CompleteSignature{2}{$PSymbol}{"ShortName"}))
11779 { # search for a pair
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040011780 if(my $ShortName = $CompleteSignature{1}{$PSymbol}{"ShortName"})
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011781 {
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040011782 if($CompleteSignature{1}{$PSymbol}{"Data"})
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011783 {
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040011784 if($PSymbol=~s/L(\d+$ShortName(E)\Z)/$1/
11785 or $PSymbol=~s/(\d+$ShortName(E)\Z)/L$1/)
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011786 {
11787 if(defined $CompleteSignature{2}{$PSymbol}
11788 and $CompleteSignature{2}{$PSymbol}{"MnglName"})
11789 {
11790 $SourceAlternative{$Symbol} = $PSymbol;
11791 $SourceAlternative_B{$PSymbol} = $Symbol;
11792 if(not defined $CompleteSignature{1}{$PSymbol}
11793 or not $CompleteSignature{1}{$PSymbol}{"MnglName"}) {
11794 $SourceReplacement{$Symbol} = $PSymbol;
11795 }
11796 }
11797 }
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040011798 }
11799 else
11800 {
11801 foreach my $Sp ("KV", "VK", "K", "V")
11802 {
11803 if($PSymbol=~s/\A_ZN$Sp/_ZN/
11804 or $PSymbol=~s/\A_ZN/_ZN$Sp/)
11805 {
11806 if(defined $CompleteSignature{2}{$PSymbol}
11807 and $CompleteSignature{2}{$PSymbol}{"MnglName"})
11808 {
11809 $SourceAlternative{$Symbol} = $PSymbol;
11810 $SourceAlternative_B{$PSymbol} = $Symbol;
11811 if(not defined $CompleteSignature{1}{$PSymbol}
11812 or not $CompleteSignature{1}{$PSymbol}{"MnglName"}) {
11813 $SourceReplacement{$Symbol} = $PSymbol;
11814 }
11815 }
11816 }
11817 $PSymbol = $Symbol;
11818 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011819 }
11820 }
11821 }
11822 return "";
11823}
11824
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040011825sub getSymKind($$)
11826{
11827 my ($Symbol, $LibVersion) = @_;
11828 if($CompleteSignature{$LibVersion}{$Symbol}{"Data"})
11829 {
11830 return "Global_Data";
11831 }
11832 elsif($CompleteSignature{$LibVersion}{$Symbol}{"Class"})
11833 {
11834 return "Method";
11835 }
11836 return "Function";
11837}
11838
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011839sub mergeSignatures($)
11840{
11841 my $Level = $_[0];
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011842 my %SubProblems = ();
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011843
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011844 mergeBases($Level);
11845
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011846 my %AddedOverloads = ();
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011847 foreach my $Symbol (sort keys(%{$AddedInt{$Level}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011848 { # check all added exported symbols
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011849 if(not $CompleteSignature{2}{$Symbol}{"Header"}) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011850 next;
11851 }
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040011852 if(defined $CompleteSignature{1}{$Symbol}
11853 and $CompleteSignature{1}{$Symbol}{"Header"})
11854 { # double-check added symbol
11855 next;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011856 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +040011857 if(not symbolFilter($Symbol, 2, "Affected", $Level)) {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011858 next;
11859 }
11860 if($Symbol=~/\A(_Z|\?)/)
11861 { # C++
11862 $AddedOverloads{get_symbol_prefix($Symbol, 2)}{get_symbol_suffix($Symbol, 1)} = $Symbol;
11863 }
11864 if(my $OverriddenMethod = $CompleteSignature{2}{$Symbol}{"Override"})
11865 { # register virtual overridings
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040011866 my $Cid = $CompleteSignature{2}{$Symbol}{"Class"};
11867 my $AffectedClass_Name = $TypeInfo{2}{$Cid}{"Name"};
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040011868 if(defined $CompleteSignature{1}{$OverriddenMethod} and $CompleteSignature{1}{$OverriddenMethod}{"Virt"}
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011869 and not $CompleteSignature{1}{$OverriddenMethod}{"Private"})
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040011870 {
11871 if($TName_Tid{1}{$AffectedClass_Name})
11872 { # class should exist in previous version
11873 if(not isCopyingClass($TName_Tid{1}{$AffectedClass_Name}, 1))
11874 { # old v-table is NOT copied by old applications
11875 %{$CompatProblems{$Level}{$OverriddenMethod}{"Overridden_Virtual_Method"}{$tr_name{$Symbol}}}=(
11876 "Type_Name"=>$AffectedClass_Name,
11877 "Type_Type"=>"Class",
11878 "Target"=>get_Signature($Symbol, 2),
11879 "Old_Value"=>get_Signature($OverriddenMethod, 2),
11880 "New_Value"=>get_Signature($Symbol, 2) );
11881 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011882 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011883 }
11884 }
11885 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011886 foreach my $Symbol (sort keys(%{$RemovedInt{$Level}}))
11887 { # check all removed exported symbols
11888 if(not $CompleteSignature{1}{$Symbol}{"Header"}) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011889 next;
11890 }
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040011891 if(defined $CompleteSignature{2}{$Symbol}
11892 and $CompleteSignature{2}{$Symbol}{"Header"})
11893 { # double-check removed symbol
11894 next;
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011895 }
11896 if($CompleteSignature{1}{$Symbol}{"Private"})
11897 { # skip private methods
11898 next;
11899 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +040011900 if(not symbolFilter($Symbol, 1, "Affected", $Level)) {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011901 next;
11902 }
11903 $CheckedSymbols{$Level}{$Symbol} = 1;
11904 if(my $OverriddenMethod = $CompleteSignature{1}{$Symbol}{"Override"})
11905 { # register virtual overridings
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040011906 my $Cid = $CompleteSignature{1}{$Symbol}{"Class"};
11907 my $AffectedClass_Name = $TypeInfo{1}{$Cid}{"Name"};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011908 if(defined $CompleteSignature{2}{$OverriddenMethod}
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040011909 and $CompleteSignature{2}{$OverriddenMethod}{"Virt"})
11910 {
11911 if($TName_Tid{2}{$AffectedClass_Name})
11912 { # class should exist in newer version
11913 if(not isCopyingClass($CompleteSignature{1}{$Symbol}{"Class"}, 1))
11914 { # old v-table is NOT copied by old applications
11915 %{$CompatProblems{$Level}{$Symbol}{"Overridden_Virtual_Method_B"}{$tr_name{$OverriddenMethod}}}=(
11916 "Type_Name"=>$AffectedClass_Name,
11917 "Type_Type"=>"Class",
11918 "Target"=>get_Signature($OverriddenMethod, 1),
11919 "Old_Value"=>get_Signature($Symbol, 1),
11920 "New_Value"=>get_Signature($OverriddenMethod, 1) );
11921 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011922 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011923 }
11924 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011925 if($Level eq "Binary"
11926 and $OSgroup eq "windows")
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011927 { # register the reason of symbol name change
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040011928 if(my $NewSym = $mangled_name{2}{$tr_name{$Symbol}})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011929 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040011930 if($AddedInt{$Level}{$NewSym})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011931 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040011932 if($CompleteSignature{1}{$Symbol}{"Static"} ne $CompleteSignature{2}{$NewSym}{"Static"})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011933 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040011934 if($CompleteSignature{2}{$NewSym}{"Static"})
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011935 {
11936 %{$CompatProblems{$Level}{$Symbol}{"Symbol_Became_Static"}{$tr_name{$Symbol}}}=(
11937 "Target"=>$tr_name{$Symbol},
11938 "Old_Value"=>$Symbol,
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040011939 "New_Value"=>$NewSym );
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011940 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011941 else
11942 {
11943 %{$CompatProblems{$Level}{$Symbol}{"Symbol_Became_NonStatic"}{$tr_name{$Symbol}}}=(
11944 "Target"=>$tr_name{$Symbol},
11945 "Old_Value"=>$Symbol,
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040011946 "New_Value"=>$NewSym );
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011947 }
11948 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040011949 if($CompleteSignature{1}{$Symbol}{"Virt"} ne $CompleteSignature{2}{$NewSym}{"Virt"})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011950 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040011951 if($CompleteSignature{2}{$NewSym}{"Virt"})
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011952 {
11953 %{$CompatProblems{$Level}{$Symbol}{"Symbol_Became_Virtual"}{$tr_name{$Symbol}}}=(
11954 "Target"=>$tr_name{$Symbol},
11955 "Old_Value"=>$Symbol,
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040011956 "New_Value"=>$NewSym );
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011957 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011958 else
11959 {
11960 %{$CompatProblems{$Level}{$Symbol}{"Symbol_Became_NonVirtual"}{$tr_name{$Symbol}}}=(
11961 "Target"=>$tr_name{$Symbol},
11962 "Old_Value"=>$Symbol,
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040011963 "New_Value"=>$NewSym );
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011964 }
11965 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040011966 my $RTId1 = $CompleteSignature{1}{$Symbol}{"Return"};
11967 my $RTId2 = $CompleteSignature{2}{$NewSym}{"Return"};
11968 my $RTName1 = $TypeInfo{1}{$RTId1}{"Name"};
11969 my $RTName2 = $TypeInfo{2}{$RTId2}{"Name"};
11970 if($RTName1 ne $RTName2)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011971 {
11972 my $ProblemType = "Symbol_Changed_Return";
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011973 if($CompleteSignature{1}{$Symbol}{"Data"}) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011974 $ProblemType = "Global_Data_Symbol_Changed_Type";
11975 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011976 %{$CompatProblems{$Level}{$Symbol}{$ProblemType}{$tr_name{$Symbol}}}=(
11977 "Target"=>$tr_name{$Symbol},
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040011978 "Old_Type"=>$RTName1,
11979 "New_Type"=>$RTName2,
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011980 "Old_Value"=>$Symbol,
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040011981 "New_Value"=>$NewSym );
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011982 }
11983 }
11984 }
11985 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011986 if($Symbol=~/\A(_Z|\?)/)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011987 { # C++
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011988 my $Prefix = get_symbol_prefix($Symbol, 1);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011989 if(my @Overloads = sort keys(%{$AddedOverloads{$Prefix}})
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011990 and not $AddedOverloads{$Prefix}{get_symbol_suffix($Symbol, 1)})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011991 { # changed signature: params, "const"-qualifier
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040011992 my $NewSym = $AddedOverloads{$Prefix}{$Overloads[0]};
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011993 if($CompleteSignature{1}{$Symbol}{"Constructor"})
11994 {
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +040011995 if($Symbol=~/(C1E|C2E)/)
11996 {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011997 my $CtorType = $1;
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040011998 $NewSym=~s/(C1E|C2E)/$CtorType/g;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011999 }
12000 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012001 elsif($CompleteSignature{1}{$Symbol}{"Destructor"})
12002 {
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +040012003 if($Symbol=~/(D0E|D1E|D2E)/)
12004 {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012005 my $DtorType = $1;
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040012006 $NewSym=~s/(D0E|D1E|D2E)/$DtorType/g;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012007 }
12008 }
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040012009 my $NS1 = $CompleteSignature{1}{$Symbol}{"NameSpace"};
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040012010 my $NS2 = $CompleteSignature{2}{$NewSym}{"NameSpace"};
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040012011 if((not $NS1 and not $NS2) or ($NS1 and $NS2 and $NS1 eq $NS2))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012012 { # from the same class and namespace
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012013 if($CompleteSignature{1}{$Symbol}{"Const"}
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040012014 and not $CompleteSignature{2}{$NewSym}{"Const"})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012015 { # "const" to non-"const"
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040012016 %{$CompatProblems{$Level}{$Symbol}{"Method_Became_NonConst"}{$tr_name{$Symbol}}}=(
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040012017 "Type_Name"=>$TypeInfo{1}{$CompleteSignature{1}{$Symbol}{"Class"}}{"Name"},
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012018 "Target"=>$tr_name{$Symbol},
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040012019 "New_Signature"=>get_Signature($NewSym, 2),
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012020 "Old_Value"=>$Symbol,
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040012021 "New_Value"=>$NewSym );
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012022 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012023 elsif(not $CompleteSignature{1}{$Symbol}{"Const"}
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040012024 and $CompleteSignature{2}{$NewSym}{"Const"})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012025 { # non-"const" to "const"
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040012026 %{$CompatProblems{$Level}{$Symbol}{"Method_Became_Const"}{$tr_name{$Symbol}}}=(
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012027 "Target"=>$tr_name{$Symbol},
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040012028 "New_Signature"=>get_Signature($NewSym, 2),
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012029 "Old_Value"=>$Symbol,
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040012030 "New_Value"=>$NewSym );
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012031 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012032 if($CompleteSignature{1}{$Symbol}{"Volatile"}
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040012033 and not $CompleteSignature{2}{$NewSym}{"Volatile"})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012034 { # "volatile" to non-"volatile"
12035
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040012036 %{$CompatProblems{$Level}{$Symbol}{"Method_Became_NonVolatile"}{$tr_name{$Symbol}}}=(
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012037 "Target"=>$tr_name{$Symbol},
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040012038 "New_Signature"=>get_Signature($NewSym, 2),
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012039 "Old_Value"=>$Symbol,
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040012040 "New_Value"=>$NewSym );
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012041 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012042 elsif(not $CompleteSignature{1}{$Symbol}{"Volatile"}
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040012043 and $CompleteSignature{2}{$NewSym}{"Volatile"})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012044 { # non-"volatile" to "volatile"
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040012045 %{$CompatProblems{$Level}{$Symbol}{"Method_Became_Volatile"}{$tr_name{$Symbol}}}=(
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012046 "Target"=>$tr_name{$Symbol},
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040012047 "New_Signature"=>get_Signature($NewSym, 2),
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012048 "Old_Value"=>$Symbol,
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040012049 "New_Value"=>$NewSym );
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012050 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040012051 if(get_symbol_suffix($Symbol, 0) ne get_symbol_suffix($NewSym, 0))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012052 { # params list
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012053 %{$CompatProblems{$Level}{$Symbol}{"Symbol_Changed_Parameters"}{$tr_name{$Symbol}}}=(
12054 "Target"=>$tr_name{$Symbol},
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040012055 "New_Signature"=>get_Signature($NewSym, 2),
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012056 "Old_Value"=>$Symbol,
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040012057 "New_Value"=>$NewSym );
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012058 }
12059 }
12060 }
12061 }
12062 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012063 foreach my $Symbol (sort keys(%{$CompleteSignature{1}}))
12064 { # checking symbols
12065 my ($SN, $SS, $SV) = separate_symbol($Symbol);
12066 if($Level eq "Source")
12067 { # remove symbol version
12068 $Symbol=$SN;
12069 }
12070 else
12071 { # Binary
12072 if(not $SV)
12073 { # symbol without version
12074 if(my $VSym = $SymVer{1}{$Symbol})
12075 { # the symbol is linked with versioned symbol
12076 if($CompleteSignature{2}{$VSym}{"MnglName"})
12077 { # show report for symbol@ver only
12078 next;
12079 }
12080 elsif(not link_symbol($VSym, 2, "-Deps"))
12081 { # changed version: sym@v1 to sym@v2
12082 # do NOT show report for symbol
12083 next;
12084 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012085 }
12086 }
12087 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012088 my $PSymbol = $Symbol;
12089 if($Level eq "Source"
12090 and my $S = $SourceReplacement{$Symbol})
12091 { # take a source-compatible replacement function
12092 $PSymbol = $S;
12093 }
12094 if($CompleteSignature{1}{$Symbol}{"Private"})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012095 { # private symbols
12096 next;
12097 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012098 if(not defined $CompleteSignature{1}{$Symbol}
12099 or not defined $CompleteSignature{2}{$PSymbol})
12100 { # no info
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012101 next;
12102 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012103 if(not $CompleteSignature{1}{$Symbol}{"MnglName"}
12104 or not $CompleteSignature{2}{$PSymbol}{"MnglName"})
12105 { # no mangled name
12106 next;
12107 }
12108 if(not $CompleteSignature{1}{$Symbol}{"Header"}
12109 or not $CompleteSignature{2}{$PSymbol}{"Header"})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012110 { # without a header
12111 next;
12112 }
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040012113
12114 if(not $CompleteSignature{1}{$Symbol}{"PureVirt"}
12115 and $CompleteSignature{2}{$PSymbol}{"PureVirt"})
12116 { # became pure
12117 next;
12118 }
12119 if($CompleteSignature{1}{$Symbol}{"PureVirt"}
12120 and not $CompleteSignature{2}{$PSymbol}{"PureVirt"})
12121 { # became non-pure
12122 next;
12123 }
12124
12125 if(not symbolFilter($Symbol, 1, "Affected + InlineVirt", $Level))
12126 { # exported, target, inline virtual and pure virtual
12127 next;
12128 }
12129 if(not symbolFilter($PSymbol, 2, "Affected + InlineVirt", $Level))
12130 { # exported, target, inline virtual and pure virtual
12131 next;
12132 }
12133
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040012134 if(checkDump(1, "2.13") and checkDump(2, "2.13"))
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040012135 {
12136 if($CompleteSignature{1}{$Symbol}{"Data"}
12137 and $CompleteSignature{2}{$PSymbol}{"Data"})
12138 {
12139 my $Value1 = $CompleteSignature{1}{$Symbol}{"Value"};
12140 my $Value2 = $CompleteSignature{2}{$PSymbol}{"Value"};
12141 if(defined $Value1)
12142 {
12143 $Value1 = showVal($Value1, $CompleteSignature{1}{$Symbol}{"Return"}, 1);
12144 if(defined $Value2)
12145 {
12146 $Value2 = showVal($Value2, $CompleteSignature{2}{$PSymbol}{"Return"}, 2);
12147 if($Value1 ne $Value2)
12148 {
12149 %{$CompatProblems{$Level}{$Symbol}{"Global_Data_Value_Changed"}{""}}=(
12150 "Old_Value"=>$Value1,
12151 "New_Value"=>$Value2,
12152 "Target"=>get_Signature($Symbol, 1) );
12153 }
12154 }
12155 }
12156 }
12157 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +040012158
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040012159 if($CompleteSignature{2}{$PSymbol}{"Private"})
12160 {
12161 %{$CompatProblems{$Level}{$Symbol}{getSymKind($Symbol, 1)."_Became_Private"}{""}}=(
12162 "Target"=>get_Signature_M($PSymbol, 2) );
12163 }
12164 elsif(not $CompleteSignature{1}{$Symbol}{"Protected"}
12165 and $CompleteSignature{2}{$PSymbol}{"Protected"})
12166 {
12167 %{$CompatProblems{$Level}{$Symbol}{getSymKind($Symbol, 1)."_Became_Protected"}{""}}=(
12168 "Target"=>get_Signature_M($PSymbol, 2) );
12169 }
12170 elsif($CompleteSignature{1}{$Symbol}{"Protected"}
12171 and not $CompleteSignature{2}{$PSymbol}{"Protected"})
12172 {
12173 %{$CompatProblems{$Level}{$Symbol}{getSymKind($Symbol, 1)."_Became_Public"}{""}}=(
12174 "Target"=>get_Signature_M($PSymbol, 2) );
12175 }
12176
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012177 # checking virtual table
Andrey Ponomarenko16934472012-03-29 15:37:04 +040012178 mergeVirtualTables($Symbol, $Level);
12179
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012180 if($COMPILE_ERRORS)
12181 { # if some errors occurred at the compiling stage
12182 # then some false positives can be skipped here
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012183 if(not $CompleteSignature{1}{$Symbol}{"Data"} and $CompleteSignature{2}{$PSymbol}{"Data"}
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040012184 and not $GlobalDataObject{2}{$Symbol})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012185 { # missed information about parameters in newer version
12186 next;
12187 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040012188 if($CompleteSignature{1}{$Symbol}{"Data"} and not $GlobalDataObject{1}{$Symbol}
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012189 and not $CompleteSignature{2}{$PSymbol}{"Data"})
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040012190 { # missed information about parameters in older version
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012191 next;
12192 }
12193 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012194 my ($MnglName, $VersionSpec, $SymbolVersion) = separate_symbol($Symbol);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012195 # checking attributes
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012196 if($CompleteSignature{2}{$PSymbol}{"Static"}
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040012197 and not $CompleteSignature{1}{$Symbol}{"Static"} and $Symbol=~/\A(_Z|\?)/)
12198 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012199 %{$CompatProblems{$Level}{$Symbol}{"Method_Became_Static"}{""}}=(
12200 "Target"=>get_Signature($Symbol, 1)
12201 );
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012202 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012203 elsif(not $CompleteSignature{2}{$PSymbol}{"Static"}
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040012204 and $CompleteSignature{1}{$Symbol}{"Static"} and $Symbol=~/\A(_Z|\?)/)
12205 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012206 %{$CompatProblems{$Level}{$Symbol}{"Method_Became_NonStatic"}{""}}=(
12207 "Target"=>get_Signature($Symbol, 1)
12208 );
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012209 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012210 if(($CompleteSignature{1}{$Symbol}{"Virt"} and $CompleteSignature{2}{$PSymbol}{"Virt"})
12211 or ($CompleteSignature{1}{$Symbol}{"PureVirt"} and $CompleteSignature{2}{$PSymbol}{"PureVirt"}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012212 { # relative position of virtual and pure virtual methods
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012213 if($Level eq "Binary")
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012214 {
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040012215 if(defined $CompleteSignature{1}{$Symbol}{"RelPos"} and defined $CompleteSignature{2}{$PSymbol}{"RelPos"}
12216 and $CompleteSignature{1}{$Symbol}{"RelPos"}!=$CompleteSignature{2}{$PSymbol}{"RelPos"})
12217 { # top-level virtual methods only
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012218 my $Class_Id = $CompleteSignature{1}{$Symbol}{"Class"};
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040012219 my $Class_Name = $TypeInfo{1}{$Class_Id}{"Name"};
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040012220 if(defined $VirtualTable{1}{$Class_Name} and defined $VirtualTable{2}{$Class_Name}
12221 and $VirtualTable{1}{$Class_Name}{$Symbol}!=$VirtualTable{2}{$Class_Name}{$Symbol})
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012222 { # check the absolute position of virtual method (including added and removed methods)
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040012223 my %Class_Type = get_Type($Class_Id, 1);
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012224 my $ProblemType = "Virtual_Method_Position";
12225 if($CompleteSignature{1}{$Symbol}{"PureVirt"}) {
12226 $ProblemType = "Pure_Virtual_Method_Position";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012227 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012228 if(isUsedClass($Class_Id, 1, $Level))
12229 {
12230 my @Affected = ($Symbol, keys(%{$OverriddenMethods{1}{$Symbol}}));
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040012231 foreach my $ASymbol (@Affected)
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012232 {
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040012233 if(not symbolFilter($ASymbol, 1, "Affected", $Level)) {
12234 next;
12235 }
12236 %{$CompatProblems{$Level}{$ASymbol}{$ProblemType}{$tr_name{$MnglName}}}=(
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012237 "Type_Name"=>$Class_Type{"Name"},
12238 "Type_Type"=>"Class",
12239 "Old_Value"=>$CompleteSignature{1}{$Symbol}{"RelPos"},
12240 "New_Value"=>$CompleteSignature{2}{$PSymbol}{"RelPos"},
12241 "Target"=>get_Signature($Symbol, 1) );
12242 }
Andrey Ponomarenko16934472012-03-29 15:37:04 +040012243 $VTableChanged_M{$Class_Type{"Name"}} = 1;
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012244 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012245 }
12246 }
12247 }
12248 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012249 if($CompleteSignature{1}{$Symbol}{"PureVirt"}
12250 or $CompleteSignature{2}{$PSymbol}{"PureVirt"})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012251 { # do NOT check type changes in pure virtuals
12252 next;
12253 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012254 $CheckedSymbols{$Level}{$Symbol}=1;
12255 if($Symbol=~/\A(_Z|\?)/
12256 or keys(%{$CompleteSignature{1}{$Symbol}{"Param"}})==keys(%{$CompleteSignature{2}{$PSymbol}{"Param"}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012257 { # C/C++: changes in parameters
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012258 foreach my $ParamPos (sort {int($a) <=> int($b)} keys(%{$CompleteSignature{1}{$Symbol}{"Param"}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012259 { # checking parameters
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012260 mergeParameters($Symbol, $PSymbol, $ParamPos, $ParamPos, $Level);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012261 }
12262 }
12263 else
12264 { # C: added/removed parameters
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012265 foreach my $ParamPos (sort {int($a) <=> int($b)} keys(%{$CompleteSignature{2}{$PSymbol}{"Param"}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012266 { # checking added parameters
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040012267 my $PType2_Id = $CompleteSignature{2}{$PSymbol}{"Param"}{$ParamPos}{"type"};
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040012268 my $PType2_Name = $TypeInfo{2}{$PType2_Id}{"Name"};
12269 last if($PType2_Name eq "...");
12270 my $PName = $CompleteSignature{2}{$PSymbol}{"Param"}{$ParamPos}{"name"};
12271 my $PName_Old = (defined $CompleteSignature{1}{$Symbol}{"Param"}{$ParamPos})?$CompleteSignature{1}{$Symbol}{"Param"}{$ParamPos}{"name"}:"";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012272 my $ParamPos_Prev = "-1";
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040012273 if($PName=~/\Ap\d+\Z/i)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012274 { # added unnamed parameter ( pN )
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040012275 my @Positions1 = find_ParamPair_Pos_byTypeAndPos($PType2_Name, $ParamPos, "backward", $Symbol, 1);
12276 my @Positions2 = find_ParamPair_Pos_byTypeAndPos($PType2_Name, $ParamPos, "backward", $Symbol, 2);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012277 if($#Positions1==-1 or $#Positions2>$#Positions1) {
12278 $ParamPos_Prev = "lost";
12279 }
12280 }
12281 else {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040012282 $ParamPos_Prev = find_ParamPair_Pos_byName($PName, $Symbol, 1);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012283 }
12284 if($ParamPos_Prev eq "lost")
12285 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012286 if($ParamPos>keys(%{$CompleteSignature{1}{$Symbol}{"Param"}})-1)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012287 {
12288 my $ProblemType = "Added_Parameter";
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040012289 if($PName=~/\Ap\d+\Z/) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012290 $ProblemType = "Added_Unnamed_Parameter";
12291 }
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040012292 %{$CompatProblems{$Level}{$Symbol}{$ProblemType}{showPos($ParamPos)." Parameter"}}=(
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040012293 "Target"=>$PName,
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012294 "Param_Pos"=>$ParamPos,
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040012295 "Param_Type"=>$PType2_Name,
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012296 "New_Signature"=>get_Signature($Symbol, 2) );
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012297 }
12298 else
12299 {
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +040012300 my %ParamType_Pure = get_PureType($PType2_Id, $TypeInfo{2});
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040012301 my $PairType_Id = $CompleteSignature{1}{$Symbol}{"Param"}{$ParamPos}{"type"};
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +040012302 my %PairType_Pure = get_PureType($PairType_Id, $TypeInfo{1});
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040012303 if(($ParamType_Pure{"Name"} eq $PairType_Pure{"Name"} or $PType2_Name eq $TypeInfo{1}{$PairType_Id}{"Name"})
12304 and find_ParamPair_Pos_byName($PName_Old, $Symbol, 2) eq "lost")
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012305 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040012306 if($PName_Old!~/\Ap\d+\Z/ and $PName!~/\Ap\d+\Z/)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012307 {
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040012308 %{$CompatProblems{$Level}{$Symbol}{"Renamed_Parameter"}{showPos($ParamPos)." Parameter"}}=(
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040012309 "Target"=>$PName_Old,
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012310 "Param_Pos"=>$ParamPos,
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040012311 "Param_Type"=>$PType2_Name,
12312 "Old_Value"=>$PName_Old,
12313 "New_Value"=>$PName,
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012314 "New_Signature"=>get_Signature($Symbol, 2) );
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012315 }
12316 }
12317 else
12318 {
12319 my $ProblemType = "Added_Middle_Parameter";
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040012320 if($PName=~/\Ap\d+\Z/) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012321 $ProblemType = "Added_Middle_Unnamed_Parameter";
12322 }
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040012323 %{$CompatProblems{$Level}{$Symbol}{$ProblemType}{showPos($ParamPos)." Parameter"}}=(
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040012324 "Target"=>$PName,
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012325 "Param_Pos"=>$ParamPos,
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040012326 "Param_Type"=>$PType2_Name,
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012327 "New_Signature"=>get_Signature($Symbol, 2) );
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012328 }
12329 }
12330 }
12331 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012332 foreach my $ParamPos (sort {int($a) <=> int($b)} keys(%{$CompleteSignature{1}{$Symbol}{"Param"}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012333 { # check relevant parameters
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040012334 my $PType1_Id = $CompleteSignature{1}{$Symbol}{"Param"}{$ParamPos}{"type"};
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012335 my $ParamName1 = $CompleteSignature{1}{$Symbol}{"Param"}{$ParamPos}{"name"};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012336 # FIXME: find relevant parameter by name
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012337 if(defined $CompleteSignature{2}{$PSymbol}{"Param"}{$ParamPos})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012338 {
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040012339 my $PType2_Id = $CompleteSignature{2}{$PSymbol}{"Param"}{$ParamPos}{"type"};
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012340 my $ParamName2 = $CompleteSignature{2}{$PSymbol}{"Param"}{$ParamPos}{"name"};
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040012341 if($TypeInfo{1}{$PType1_Id}{"Name"} eq $TypeInfo{2}{$PType2_Id}{"Name"}
12342 or ($ParamName1!~/\Ap\d+\Z/i and $ParamName1 eq $ParamName2)) {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012343 mergeParameters($Symbol, $PSymbol, $ParamPos, $ParamPos, $Level);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012344 }
12345 }
12346 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012347 foreach my $ParamPos (sort {int($a) <=> int($b)} keys(%{$CompleteSignature{1}{$Symbol}{"Param"}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012348 { # checking removed parameters
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040012349 my $PType1_Id = $CompleteSignature{1}{$Symbol}{"Param"}{$ParamPos}{"type"};
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040012350 my $PType1_Name = $TypeInfo{1}{$PType1_Id}{"Name"};
12351 last if($PType1_Name eq "...");
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012352 my $Parameter_Name = $CompleteSignature{1}{$Symbol}{"Param"}{$ParamPos}{"name"};
12353 my $Parameter_NewName = (defined $CompleteSignature{2}{$PSymbol}{"Param"}{$ParamPos})?$CompleteSignature{2}{$PSymbol}{"Param"}{$ParamPos}{"name"}:"";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012354 my $ParamPos_New = "-1";
12355 if($Parameter_Name=~/\Ap\d+\Z/i)
12356 { # removed unnamed parameter ( pN )
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040012357 my @Positions1 = find_ParamPair_Pos_byTypeAndPos($PType1_Name, $ParamPos, "forward", $Symbol, 1);
12358 my @Positions2 = find_ParamPair_Pos_byTypeAndPos($PType1_Name, $ParamPos, "forward", $Symbol, 2);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012359 if($#Positions2==-1 or $#Positions2<$#Positions1) {
12360 $ParamPos_New = "lost";
12361 }
12362 }
12363 else {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012364 $ParamPos_New = find_ParamPair_Pos_byName($Parameter_Name, $Symbol, 2);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012365 }
12366 if($ParamPos_New eq "lost")
12367 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012368 if($ParamPos>keys(%{$CompleteSignature{2}{$PSymbol}{"Param"}})-1)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012369 {
12370 my $ProblemType = "Removed_Parameter";
12371 if($Parameter_Name=~/\Ap\d+\Z/) {
12372 $ProblemType = "Removed_Unnamed_Parameter";
12373 }
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040012374 %{$CompatProblems{$Level}{$Symbol}{$ProblemType}{showPos($ParamPos)." Parameter"}}=(
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012375 "Target"=>$Parameter_Name,
12376 "Param_Pos"=>$ParamPos,
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040012377 "Param_Type"=>$PType1_Name,
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012378 "New_Signature"=>get_Signature($Symbol, 2) );
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012379 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012380 elsif($ParamPos<keys(%{$CompleteSignature{1}{$Symbol}{"Param"}})-1)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012381 {
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +040012382 my %ParamType_Pure = get_PureType($PType1_Id, $TypeInfo{1});
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040012383 my $PairType_Id = $CompleteSignature{2}{$PSymbol}{"Param"}{$ParamPos}{"type"};
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +040012384 my %PairType_Pure = get_PureType($PairType_Id, $TypeInfo{2});
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040012385 if(($ParamType_Pure{"Name"} eq $PairType_Pure{"Name"} or $PType1_Name eq $TypeInfo{2}{$PairType_Id}{"Name"})
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012386 and find_ParamPair_Pos_byName($Parameter_NewName, $Symbol, 1) eq "lost")
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012387 {
12388 if($Parameter_NewName!~/\Ap\d+\Z/ and $Parameter_Name!~/\Ap\d+\Z/)
12389 {
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040012390 %{$CompatProblems{$Level}{$Symbol}{"Renamed_Parameter"}{showPos($ParamPos)." Parameter"}}=(
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012391 "Target"=>$Parameter_Name,
12392 "Param_Pos"=>$ParamPos,
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040012393 "Param_Type"=>$PType1_Name,
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012394 "Old_Value"=>$Parameter_Name,
12395 "New_Value"=>$Parameter_NewName,
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012396 "New_Signature"=>get_Signature($Symbol, 2) );
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012397 }
12398 }
12399 else
12400 {
12401 my $ProblemType = "Removed_Middle_Parameter";
12402 if($Parameter_Name=~/\Ap\d+\Z/) {
12403 $ProblemType = "Removed_Middle_Unnamed_Parameter";
12404 }
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040012405 %{$CompatProblems{$Level}{$Symbol}{$ProblemType}{showPos($ParamPos)." Parameter"}}=(
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012406 "Target"=>$Parameter_Name,
12407 "Param_Pos"=>$ParamPos,
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040012408 "Param_Type"=>$PType1_Name,
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012409 "New_Signature"=>get_Signature($Symbol, 2) );
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012410 }
12411 }
12412 }
12413 }
12414 }
12415 # checking return type
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012416 my $ReturnType1_Id = $CompleteSignature{1}{$Symbol}{"Return"};
12417 my $ReturnType2_Id = $CompleteSignature{2}{$PSymbol}{"Return"};
12418 %SubProblems = detectTypeChange($ReturnType1_Id, $ReturnType2_Id, "Return", $Level);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012419 foreach my $SubProblemType (keys(%SubProblems))
12420 {
12421 my $New_Value = $SubProblems{$SubProblemType}{"New_Value"};
12422 my $Old_Value = $SubProblems{$SubProblemType}{"Old_Value"};
12423 my $NewProblemType = $SubProblemType;
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040012424 my $AddProblemType = undef;
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +040012425
12426 if($SubProblemType eq "Return_Type_And_Size"
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012427 and $CompleteSignature{1}{$Symbol}{"Data"}) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012428 $NewProblemType = "Global_Data_Type_And_Size";
12429 }
12430 elsif($SubProblemType eq "Return_Type")
12431 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012432 if($CompleteSignature{1}{$Symbol}{"Data"})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012433 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012434 if(removedQual($Old_Value, $New_Value, "const"))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012435 { # const -> non-const global data
12436 $NewProblemType = "Global_Data_Became_Non_Const";
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040012437 $AddProblemType = "Global_Data_Type";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012438 }
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040012439 elsif(addedQual($Old_Value, $New_Value, "const"))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012440 { # non-const -> const global data
12441 $NewProblemType = "Global_Data_Became_Const";
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040012442 $AddProblemType = "Global_Data_Type";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012443 }
12444 else {
12445 $NewProblemType = "Global_Data_Type";
12446 }
12447 }
12448 else
12449 {
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040012450 if(addedQual($Old_Value, $New_Value, "const"))
12451 {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012452 $NewProblemType = "Return_Type_Became_Const";
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040012453 $AddProblemType = "Return_Type";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012454 }
12455 }
12456 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012457 elsif($SubProblemType eq "Return_Type_Format")
12458 {
12459 if($CompleteSignature{1}{$Symbol}{"Data"}) {
12460 $NewProblemType = "Global_Data_Type_Format";
12461 }
12462 }
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +040012463 if($Level eq "Binary"
12464 and not $CompleteSignature{1}{$Symbol}{"Data"})
12465 {
12466 my ($Arch1, $Arch2) = (getArch(1), getArch(2));
12467 if($Arch1 eq "unknown" or $Arch2 eq "unknown")
12468 { # if one of the architectures is unknown
12469 # then set other arhitecture to unknown too
12470 ($Arch1, $Arch2) = ("unknown", "unknown");
12471 }
12472 my (%Conv1, %Conv2) = ();
12473 if($UseConv_Real{1} and $UseConv_Real{1})
12474 {
12475 %Conv1 = callingConvention_R_Real($CompleteSignature{1}{$Symbol});
12476 %Conv2 = callingConvention_R_Real($CompleteSignature{2}{$PSymbol});
12477 }
12478 else
12479 {
12480 %Conv1 = callingConvention_R_Model($CompleteSignature{1}{$Symbol}, $TypeInfo{1}, $Arch1, $OStarget, $WORD_SIZE{1});
12481 %Conv2 = callingConvention_R_Model($CompleteSignature{2}{$PSymbol}, $TypeInfo{2}, $Arch2, $OStarget, $WORD_SIZE{2});
12482 }
12483
12484 if($SubProblemType eq "Return_Type_Became_Void")
12485 {
12486 if(keys(%{$CompleteSignature{1}{$Symbol}{"Param"}}))
12487 { # parameters stack has been affected
12488 if($Conv1{"Method"} eq "stack") {
12489 $NewProblemType = "Return_Type_Became_Void_And_Stack_Layout";
12490 }
12491 elsif($Conv1{"Hidden"}) {
12492 $NewProblemType = "Return_Type_Became_Void_And_Register";
12493 }
12494 }
12495 }
12496 elsif($SubProblemType eq "Return_Type_From_Void")
12497 {
12498 if(keys(%{$CompleteSignature{1}{$Symbol}{"Param"}}))
12499 { # parameters stack has been affected
12500 if($Conv2{"Method"} eq "stack") {
12501 $NewProblemType = "Return_Type_From_Void_And_Stack_Layout";
12502 }
12503 elsif($Conv2{"Hidden"}) {
12504 $NewProblemType = "Return_Type_From_Void_And_Register";
12505 }
12506 }
12507 }
12508 elsif($SubProblemType eq "Return_Type"
12509 or $SubProblemType eq "Return_Type_And_Size"
12510 or $SubProblemType eq "Return_Type_Format")
12511 {
12512 if($Conv1{"Method"} ne $Conv2{"Method"})
12513 {
12514 if($Conv1{"Method"} eq "stack")
12515 { # returns in a register instead of a hidden first parameter
12516 $NewProblemType = "Return_Type_From_Stack_To_Register";
12517 }
12518 else {
12519 $NewProblemType = "Return_Type_From_Register_To_Stack";
12520 }
12521 }
12522 else
12523 {
12524 if($Conv1{"Method"} eq "reg")
12525 {
12526 if($Conv1{"Registers"} ne $Conv2{"Registers"})
12527 {
12528 if($Conv1{"Hidden"}) {
12529 $NewProblemType = "Return_Type_And_Register_Was_Hidden_Parameter";
12530 }
12531 elsif($Conv2{"Hidden"}) {
12532 $NewProblemType = "Return_Type_And_Register_Became_Hidden_Parameter";
12533 }
12534 else {
12535 $NewProblemType = "Return_Type_And_Register";
12536 }
12537 }
12538 }
12539 }
12540 }
12541 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012542 @{$CompatProblems{$Level}{$Symbol}{$NewProblemType}{"retval"}}{keys(%{$SubProblems{$SubProblemType}})} = values %{$SubProblems{$SubProblemType}};
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040012543 if(defined $AddProblemType) {
12544 @{$CompatProblems{$Level}{$Symbol}{$AddProblemType}{"retval"}}{keys(%{$SubProblems{$SubProblemType}})} = values %{$SubProblems{$SubProblemType}};
12545 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012546 }
12547 if($ReturnType1_Id and $ReturnType2_Id)
12548 {
12549 @RecurTypes = ();
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040012550 %SubProblems = mergeTypes($ReturnType1_Id, $ReturnType2_Id, $Level);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012551 foreach my $SubProblemType (keys(%SubProblems))
12552 { # add "Global_Data_Size" problem
12553 my $New_Value = $SubProblems{$SubProblemType}{"New_Value"};
12554 my $Old_Value = $SubProblems{$SubProblemType}{"Old_Value"};
12555 if($SubProblemType eq "DataType_Size"
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012556 and $CompleteSignature{1}{$Symbol}{"Data"}
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040012557 and get_PLevel($ReturnType1_Id, 1)==0)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012558 { # add a new problem
12559 %{$SubProblems{"Global_Data_Size"}} = %{$SubProblems{$SubProblemType}};
12560 }
12561 }
12562 foreach my $SubProblemType (keys(%SubProblems))
12563 {
12564 foreach my $SubLocation (keys(%{$SubProblems{$SubProblemType}}))
12565 {
12566 my $NewLocation = ($SubLocation)?"retval->".$SubLocation:"retval";
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012567 %{$CompatProblems{$Level}{$Symbol}{$SubProblemType}{$NewLocation}}=(
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040012568 "Return_Type_Name"=>$TypeInfo{1}{$ReturnType1_Id}{"Name"} );
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012569 @{$CompatProblems{$Level}{$Symbol}{$SubProblemType}{$NewLocation}}{keys(%{$SubProblems{$SubProblemType}{$SubLocation}})} = values %{$SubProblems{$SubProblemType}{$SubLocation}};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012570 if($SubLocation!~/\-\>/) {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040012571 $CompatProblems{$Level}{$Symbol}{$SubProblemType}{$NewLocation}{"Start_Type_Name"} = $TypeInfo{1}{$ReturnType1_Id}{"Name"};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012572 }
12573 }
12574 }
12575 }
12576
12577 # checking object type
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040012578 my $ObjTId1 = $CompleteSignature{1}{$Symbol}{"Class"};
12579 my $ObjTId2 = $CompleteSignature{2}{$PSymbol}{"Class"};
12580 if($ObjTId1 and $ObjTId2
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012581 and not $CompleteSignature{1}{$Symbol}{"Static"})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012582 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040012583 my $ThisPtr1_Id = getTypeIdByName($TypeInfo{1}{$ObjTId1}{"Name"}."*const", 1);
12584 my $ThisPtr2_Id = getTypeIdByName($TypeInfo{2}{$ObjTId2}{"Name"}."*const", 2);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012585 if($ThisPtr1_Id and $ThisPtr2_Id)
12586 {
12587 @RecurTypes = ();
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040012588 %SubProblems = mergeTypes($ThisPtr1_Id, $ThisPtr2_Id, $Level);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012589 foreach my $SubProblemType (keys(%SubProblems))
12590 {
12591 foreach my $SubLocation (keys(%{$SubProblems{$SubProblemType}}))
12592 {
12593 my $NewLocation = ($SubLocation)?"this->".$SubLocation:"this";
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012594 %{$CompatProblems{$Level}{$Symbol}{$SubProblemType}{$NewLocation}}=(
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040012595 "Object_Type_Name"=>$TypeInfo{1}{$ObjTId1}{"Name"} );
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012596 @{$CompatProblems{$Level}{$Symbol}{$SubProblemType}{$NewLocation}}{keys(%{$SubProblems{$SubProblemType}{$SubLocation}})} = values %{$SubProblems{$SubProblemType}{$SubLocation}};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012597 if($SubLocation!~/\-\>/) {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040012598 $CompatProblems{$Level}{$Symbol}{$SubProblemType}{$NewLocation}{"Start_Type_Name"} = $TypeInfo{1}{$ObjTId1}{"Name"};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012599 }
12600 }
12601 }
12602 }
12603 }
12604 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012605 if($Level eq "Binary") {
12606 mergeVTables($Level);
12607 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +040012608 foreach my $Symbol (keys(%{$CompatProblems{$Level}})) {
12609 $CheckedSymbols{$Level}{$Symbol} = 1;
12610 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012611}
12612
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040012613sub rmQuals($$)
12614{
12615 my ($Value, $Qual) = @_;
12616 if(not $Qual) {
12617 return $Value;
12618 }
12619 if($Qual eq "all")
12620 { # all quals
12621 $Qual = "const|volatile|restrict";
12622 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040012623 while($Value=~s/\b$Qual\b//) {
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040012624 $Value = formatName($Value, "T");
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040012625 }
12626 return $Value;
12627}
12628
12629sub cmpBTypes($$$$)
12630{
12631 my ($T1, $T2, $V1, $V2) = @_;
12632 $T1 = uncover_typedefs($T1, $V1);
12633 $T2 = uncover_typedefs($T2, $V2);
12634 return (rmQuals($T1, "all") eq rmQuals($T2, "all"));
12635}
12636
12637sub addedQual($$$)
12638{
12639 my ($Old_Value, $New_Value, $Qual) = @_;
Andrey Ponomarenko85043792012-05-14 16:48:07 +040012640 return removedQual_($New_Value, $Old_Value, 2, 1, $Qual);
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040012641}
12642
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012643sub removedQual($$$)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012644{
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012645 my ($Old_Value, $New_Value, $Qual) = @_;
Andrey Ponomarenko85043792012-05-14 16:48:07 +040012646 return removedQual_($Old_Value, $New_Value, 1, 2, $Qual);
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040012647}
12648
12649sub removedQual_($$$$$)
12650{
12651 my ($Old_Value, $New_Value, $V1, $V2, $Qual) = @_;
12652 $Old_Value = uncover_typedefs($Old_Value, $V1);
12653 $New_Value = uncover_typedefs($New_Value, $V2);
12654 if($Old_Value eq $New_Value)
12655 { # equal types
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012656 return 0;
12657 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040012658 if($Old_Value!~/\b$Qual\b/)
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040012659 { # without a qual
12660 return 0;
12661 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040012662 elsif($New_Value!~/\b$Qual\b/)
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040012663 { # became non-qual
12664 return 1;
12665 }
12666 else
12667 {
12668 my @BQ1 = getQualModel($Old_Value, $Qual);
12669 my @BQ2 = getQualModel($New_Value, $Qual);
12670 foreach (0 .. $#BQ1)
12671 { # removed qual
12672 if($BQ1[$_]==1
12673 and $BQ2[$_]!=1)
12674 {
12675 return 2;
12676 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012677 }
12678 }
12679 return 0;
12680}
12681
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040012682sub getQualModel($$)
12683{
12684 my ($Value, $Qual) = @_;
12685 if(not $Qual) {
12686 return $Value;
12687 }
12688
12689 # cleaning
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040012690 while($Value=~/(\w+)/ and $1 ne $Qual) {
12691 $Value=~s/\b$1\b//g;
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040012692 }
12693 $Value=~s/[^\*\&\w]+//g;
12694
12695 # modeling
12696 # int*const*const == 011
12697 # int**const == 001
12698 my @Model = ();
12699 my @Elems = split(/[\*\&]/, $Value);
12700 if(not @Elems) {
12701 return (0);
12702 }
12703 foreach (@Elems)
12704 {
12705 if($_ eq $Qual) {
12706 push(@Model, 1);
12707 }
12708 else {
12709 push(@Model, 0);
12710 }
12711 }
12712
12713 return @Model;
12714}
12715
12716sub showVal($$$)
12717{
12718 my ($Value, $TypeId, $LibVersion) = @_;
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +040012719 my %PureType = get_PureType($TypeId, $TypeInfo{$LibVersion});
Andrey Ponomarenkoa01311b2012-06-08 17:20:02 +040012720 my $TName = uncover_typedefs($PureType{"Name"}, $LibVersion);
Andrey Ponomarenko01117f12012-06-26 12:23:02 +040012721 if(substr($Value, 0, 2) eq "_Z")
12722 {
12723 if(my $Unmangled = $tr_name{$Value}) {
12724 return $Unmangled;
12725 }
12726 }
12727 elsif($TName=~/\A(char(| const)\*|std::(string|basic_string<char>)(|&))\Z/)
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040012728 { # strings
12729 return "\"$Value\"";
12730 }
Andrey Ponomarenkoa01311b2012-06-08 17:20:02 +040012731 elsif($TName=~/\Achar(| const)\Z/)
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040012732 { # characters
12733 return "\'$Value\'";
12734 }
12735 return $Value;
12736}
12737
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012738sub mergeParameters($$$$$)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012739{
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012740 my ($Symbol, $PSymbol, $ParamPos1, $ParamPos2, $Level) = @_;
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040012741 if(not $Symbol) {
12742 return;
12743 }
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040012744 my $PType1_Id = $CompleteSignature{1}{$Symbol}{"Param"}{$ParamPos1}{"type"};
12745 my $PName1 = $CompleteSignature{1}{$Symbol}{"Param"}{$ParamPos1}{"name"};
12746 my $PType2_Id = $CompleteSignature{2}{$PSymbol}{"Param"}{$ParamPos2}{"type"};
12747 my $PName2 = $CompleteSignature{2}{$PSymbol}{"Param"}{$ParamPos2}{"name"};
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040012748 if(not $PType1_Id
12749 or not $PType2_Id) {
12750 return;
12751 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040012752 my %Type1 = get_Type($PType1_Id, 1);
12753 my %Type2 = get_Type($PType2_Id, 2);
12754 my %BaseType1 = get_BaseType($PType1_Id, 1);
12755 my %BaseType2 = get_BaseType($PType2_Id, 2);
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040012756 my $Parameter_Location = ($PName1)?$PName1:showPos($ParamPos1)." Parameter";
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012757 if($Level eq "Binary")
12758 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040012759 if(checkDump(1, "2.6.1") and checkDump(2, "2.6.1"))
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012760 { # "reg" attribute added in ACC 1.95.1 (dump 2.6.1 format)
12761 if($CompleteSignature{1}{$Symbol}{"Param"}{$ParamPos1}{"reg"}
12762 and not $CompleteSignature{2}{$PSymbol}{"Param"}{$ParamPos2}{"reg"})
12763 {
12764 %{$CompatProblems{$Level}{$Symbol}{"Parameter_Became_Non_Register"}{$Parameter_Location}}=(
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040012765 "Target"=>$PName1,
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012766 "Param_Pos"=>$ParamPos1 );
12767 }
12768 elsif(not $CompleteSignature{1}{$Symbol}{"Param"}{$ParamPos1}{"reg"}
12769 and $CompleteSignature{2}{$PSymbol}{"Param"}{$ParamPos2}{"reg"})
12770 {
12771 %{$CompatProblems{$Level}{$Symbol}{"Parameter_Became_Register"}{$Parameter_Location}}=(
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040012772 "Target"=>$PName1,
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012773 "Param_Pos"=>$ParamPos1 );
12774 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012775 }
12776 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040012777 if(checkDump(1, "2.0") and checkDump(2, "2.0"))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012778 { # "default" attribute added in ACC 1.22 (dump 2.0 format)
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040012779 my $Value_Old = $CompleteSignature{1}{$Symbol}{"Param"}{$ParamPos1}{"default"};
12780 my $Value_New = $CompleteSignature{2}{$PSymbol}{"Param"}{$ParamPos2}{"default"};
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040012781 if(not checkDump(1, "2.13")
12782 and checkDump(2, "2.13"))
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040012783 { # support for old ABI dumps
12784 if(defined $Value_Old and defined $Value_New)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012785 {
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040012786 if($Type1{"Name"} eq "bool"
12787 and $Value_Old eq "false" and $Value_New eq "0")
12788 { # int class::method ( bool p = 0 );
12789 # old ABI dumps: "false"
12790 # new ABI dumps: "0"
12791 $Value_Old = "0";
12792 }
12793 }
12794 }
Andrey Ponomarenko01117f12012-06-26 12:23:02 +040012795 if(not checkDump(1, "2.18")
12796 and checkDump(2, "2.18"))
12797 { # support for old ABI dumps
12798 if(not defined $Value_Old
12799 and substr($Value_New, 0, 2) eq "_Z") {
12800 $Value_Old = $Value_New;
12801 }
12802 }
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040012803 if(defined $Value_Old)
12804 {
12805 $Value_Old = showVal($Value_Old, $PType1_Id, 1);
12806 if(defined $Value_New)
12807 {
12808 $Value_New = showVal($Value_New, $PType2_Id, 2);
12809 if($Value_Old ne $Value_New)
12810 { # FIXME: how to distinguish "0" and 0 (NULL)
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012811 %{$CompatProblems{$Level}{$Symbol}{"Parameter_Default_Value_Changed"}{$Parameter_Location}}=(
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040012812 "Target"=>$PName1,
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012813 "Param_Pos"=>$ParamPos1,
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040012814 "Old_Value"=>$Value_Old,
12815 "New_Value"=>$Value_New );
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012816 }
12817 }
12818 else
12819 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012820 %{$CompatProblems{$Level}{$Symbol}{"Parameter_Default_Value_Removed"}{$Parameter_Location}}=(
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040012821 "Target"=>$PName1,
12822 "Param_Pos"=>$ParamPos1,
12823 "Old_Value"=>$Value_Old );
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012824 }
12825 }
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040012826 elsif(defined $Value_New)
12827 {
12828 $Value_New = showVal($Value_New, $PType2_Id, 2);
12829 %{$CompatProblems{$Level}{$Symbol}{"Parameter_Default_Value_Added"}{$Parameter_Location}}=(
12830 "Target"=>$PName1,
12831 "Param_Pos"=>$ParamPos1,
12832 "New_Value"=>$Value_New );
12833 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012834 }
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040012835 if($PName1 and $PName2 and $PName1 ne $PName2
12836 and $PType1_Id!=-1 and $PType2_Id!=-1
12837 and $PName1!~/\Ap\d+\Z/ and $PName2!~/\Ap\d+\Z/)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012838 { # except unnamed "..." value list (Id=-1)
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040012839 %{$CompatProblems{$Level}{$Symbol}{"Renamed_Parameter"}{showPos($ParamPos1)." Parameter"}}=(
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040012840 "Target"=>$PName1,
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012841 "Param_Pos"=>$ParamPos1,
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040012842 "Param_Type"=>$TypeInfo{1}{$PType1_Id}{"Name"},
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040012843 "Old_Value"=>$PName1,
12844 "New_Value"=>$PName2,
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012845 "New_Signature"=>get_Signature($Symbol, 2) );
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012846 }
12847 # checking type change (replace)
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040012848 my %SubProblems = detectTypeChange($PType1_Id, $PType2_Id, "Parameter", $Level);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012849 foreach my $SubProblemType (keys(%SubProblems))
12850 { # add new problems, remove false alarms
12851 my $New_Value = $SubProblems{$SubProblemType}{"New_Value"};
12852 my $Old_Value = $SubProblems{$SubProblemType}{"Old_Value"};
12853 if($SubProblemType eq "Parameter_Type")
12854 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040012855 if(checkDump(1, "2.6") and checkDump(2, "2.6"))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012856 {
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040012857 if(my $RA = addedQual($Old_Value, $New_Value, "restrict"))
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012858 {
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040012859 %{$SubProblems{"Parameter_Became_Restrict"}} = %{$SubProblems{$SubProblemType}};
12860 if($Level eq "Source"
12861 and cmpBTypes($Old_Value, $New_Value, 1, 2)) {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012862 delete($SubProblems{$SubProblemType});
12863 }
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040012864 }
12865 elsif(my $RR = removedQual($Old_Value, $New_Value, "restrict"))
12866 {
12867 %{$SubProblems{"Parameter_Became_NonRestrict"}} = %{$SubProblems{$SubProblemType}};
12868 if($Level eq "Source"
12869 and cmpBTypes($Old_Value, $New_Value, 1, 2)) {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012870 delete($SubProblems{$SubProblemType});
12871 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012872 }
12873 }
12874 if($Type2{"Type"} eq "Const" and $BaseType2{"Name"} eq $Type1{"Name"}
12875 and $Type1{"Type"}=~/Intrinsic|Class|Struct|Union|Enum/)
12876 { # int to "int const"
12877 delete($SubProblems{$SubProblemType});
12878 }
12879 if($Type1{"Type"} eq "Const" and $BaseType1{"Name"} eq $Type2{"Name"}
12880 and $Type2{"Type"}=~/Intrinsic|Class|Struct|Union|Enum/)
12881 { # "int const" to int
12882 delete($SubProblems{$SubProblemType});
12883 }
12884 }
12885 }
12886 foreach my $SubProblemType (keys(%SubProblems))
12887 { # modify/register problems
12888 my $New_Value = $SubProblems{$SubProblemType}{"New_Value"};
12889 my $Old_Value = $SubProblems{$SubProblemType}{"Old_Value"};
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +040012890 my $New_Size = $SubProblems{$SubProblemType}{"New_Size"};
12891 my $Old_Size = $SubProblems{$SubProblemType}{"Old_Size"};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012892 my $NewProblemType = $SubProblemType;
12893 if($Old_Value eq "..." and $New_Value ne "...")
12894 { # change from "..." to "int"
12895 if($ParamPos1==0)
12896 { # ISO C requires a named argument before "..."
12897 next;
12898 }
12899 $NewProblemType = "Parameter_Became_NonVaList";
12900 }
12901 elsif($New_Value eq "..." and $Old_Value ne "...")
12902 { # change from "int" to "..."
12903 if($ParamPos2==0)
12904 { # ISO C requires a named argument before "..."
12905 next;
12906 }
12907 $NewProblemType = "Parameter_Became_VaList";
12908 }
12909 elsif($SubProblemType eq "Parameter_Type"
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012910 and removedQual($Old_Value, $New_Value, "const"))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012911 { # parameter: "const" to non-"const"
12912 $NewProblemType = "Parameter_Became_Non_Const";
12913 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012914 elsif($Level eq "Binary" and ($SubProblemType eq "Parameter_Type_And_Size"
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +040012915 or $SubProblemType eq "Parameter_Type" or $SubProblemType eq "Parameter_Type_Format"))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012916 {
12917 my ($Arch1, $Arch2) = (getArch(1), getArch(2));
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +040012918 if($Arch1 eq "unknown"
12919 or $Arch2 eq "unknown")
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012920 { # if one of the architectures is unknown
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +040012921 # then set other arhitecture to unknown too
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012922 ($Arch1, $Arch2) = ("unknown", "unknown");
12923 }
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +040012924 my (%Conv1, %Conv2) = ();
12925 if($UseConv_Real{1} and $UseConv_Real{1})
12926 { # real
12927 %Conv1 = callingConvention_P_Real($CompleteSignature{1}{$Symbol}, $ParamPos1);
12928 %Conv2 = callingConvention_P_Real($CompleteSignature{2}{$Symbol}, $ParamPos2);
12929 }
12930 else
12931 { # model
12932 %Conv1 = callingConvention_P_Model($CompleteSignature{1}{$Symbol}, $ParamPos1, $TypeInfo{1}, $Arch1, $OStarget, $WORD_SIZE{1});
12933 %Conv2 = callingConvention_P_Model($CompleteSignature{2}{$Symbol}, $ParamPos2, $TypeInfo{2}, $Arch2, $OStarget, $WORD_SIZE{2});
12934 }
12935 if($Conv1{"Method"} eq $Conv2{"Method"})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012936 {
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +040012937 if($Conv1{"Method"} eq "stack")
12938 {
12939 if($Old_Size ne $New_Size) { # FIXME: isMemPadded, getOffset
12940 $NewProblemType = "Parameter_Type_And_Stack";
12941 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012942 }
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +040012943 elsif($Conv1{"Method"} eq "reg")
12944 {
12945 if($Conv1{"Registers"} ne $Conv2{"Registers"}) {
12946 $NewProblemType = "Parameter_Type_And_Register";
12947 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012948 }
12949 }
12950 else
12951 {
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +040012952 if($Conv1{"Method"} eq "stack") {
12953 $NewProblemType = "Parameter_Type_From_Stack_To_Register";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012954 }
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +040012955 elsif($Conv1{"Method"} eq "register") {
12956 $NewProblemType = "Parameter_Type_From_Register_To_Stack";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012957 }
12958 }
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +040012959 $SubProblems{$SubProblemType}{"Old_Reg"} = $Conv1{"Registers"};
12960 $SubProblems{$SubProblemType}{"New_Reg"} = $Conv2{"Registers"};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012961 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012962 %{$CompatProblems{$Level}{$Symbol}{$NewProblemType}{$Parameter_Location}}=(
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040012963 "Target"=>$PName1,
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012964 "Param_Pos"=>$ParamPos1,
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012965 "New_Signature"=>get_Signature($Symbol, 2) );
12966 @{$CompatProblems{$Level}{$Symbol}{$NewProblemType}{$Parameter_Location}}{keys(%{$SubProblems{$SubProblemType}})} = values %{$SubProblems{$SubProblemType}};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012967 }
12968 @RecurTypes = ();
12969 # checking type definition changes
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040012970 my %SubProblems_Merge = mergeTypes($PType1_Id, $PType2_Id, $Level);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012971 foreach my $SubProblemType (keys(%SubProblems_Merge))
12972 {
12973 foreach my $SubLocation (keys(%{$SubProblems_Merge{$SubProblemType}}))
12974 {
12975 my $NewProblemType = $SubProblemType;
12976 if($SubProblemType eq "DataType_Size")
12977 {
12978 my $InitialType_Type = $SubProblems_Merge{$SubProblemType}{$SubLocation}{"InitialType_Type"};
12979 if($InitialType_Type!~/\A(Pointer|Ref)\Z/ and $SubLocation!~/\-\>/)
12980 { # stack has been affected
12981 $NewProblemType = "DataType_Size_And_Stack";
12982 }
12983 }
12984 my $NewLocation = ($SubLocation)?$Parameter_Location."->".$SubLocation:$Parameter_Location;
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012985 %{$CompatProblems{$Level}{$Symbol}{$NewProblemType}{$NewLocation}}=(
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040012986 "Param_Type"=>$TypeInfo{1}{$PType1_Id}{"Name"},
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012987 "Param_Pos"=>$ParamPos1,
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040012988 "Param_Name"=>$PName1 );
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012989 @{$CompatProblems{$Level}{$Symbol}{$NewProblemType}{$NewLocation}}{keys(%{$SubProblems_Merge{$SubProblemType}{$SubLocation}})} = values %{$SubProblems_Merge{$SubProblemType}{$SubLocation}};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012990 if($SubLocation!~/\-\>/) {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040012991 $CompatProblems{$Level}{$Symbol}{$NewProblemType}{$NewLocation}{"Start_Type_Name"} = $TypeInfo{1}{$PType1_Id}{"Name"};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012992 }
12993 }
12994 }
12995}
12996
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012997sub find_ParamPair_Pos_byName($$$)
12998{
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012999 my ($Name, $Symbol, $LibVersion) = @_;
13000 foreach my $ParamPos (sort {int($a)<=>int($b)} keys(%{$CompleteSignature{$LibVersion}{$Symbol}{"Param"}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013001 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040013002 next if(not defined $CompleteSignature{$LibVersion}{$Symbol}{"Param"}{$ParamPos});
13003 if($CompleteSignature{$LibVersion}{$Symbol}{"Param"}{$ParamPos}{"name"} eq $Name)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013004 {
13005 return $ParamPos;
13006 }
13007 }
13008 return "lost";
13009}
13010
13011sub find_ParamPair_Pos_byTypeAndPos($$$$$)
13012{
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040013013 my ($TypeName, $MediumPos, $Order, $Symbol, $LibVersion) = @_;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013014 my @Positions = ();
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040013015 foreach my $ParamPos (sort {int($a)<=>int($b)} keys(%{$CompleteSignature{$LibVersion}{$Symbol}{"Param"}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013016 {
13017 next if($Order eq "backward" and $ParamPos>$MediumPos);
13018 next if($Order eq "forward" and $ParamPos<$MediumPos);
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040013019 next if(not defined $CompleteSignature{$LibVersion}{$Symbol}{"Param"}{$ParamPos});
13020 my $PTypeId = $CompleteSignature{$LibVersion}{$Symbol}{"Param"}{$ParamPos}{"type"};
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040013021 if($TypeInfo{$LibVersion}{$PTypeId}{"Name"} eq $TypeName) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013022 push(@Positions, $ParamPos);
13023 }
13024 }
13025 return @Positions;
13026}
13027
13028sub getTypeIdByName($$)
13029{
13030 my ($TypeName, $Version) = @_;
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040013031 return $TName_Tid{$Version}{formatName($TypeName, "T")};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013032}
13033
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040013034sub checkFormatChange($$$)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013035{
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040013036 my ($Type1_Id, $Type2_Id, $Level) = @_;
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +040013037 my %Type1_Pure = get_PureType($Type1_Id, $TypeInfo{1});
13038 my %Type2_Pure = get_PureType($Type2_Id, $TypeInfo{2});
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013039 if($Type1_Pure{"Name"} eq $Type2_Pure{"Name"})
13040 { # equal types
13041 return 0;
13042 }
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040013043 if($Type1_Pure{"Name"} eq "void")
13044 { # from void* to something
13045 return 0;
13046 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013047 if($Type1_Pure{"Name"}=~/\*/
13048 or $Type2_Pure{"Name"}=~/\*/)
13049 { # compared in detectTypeChange()
13050 return 0;
13051 }
13052 my %FloatType = map {$_=>1} (
13053 "float",
13054 "double",
13055 "long double"
13056 );
13057 if($Type1_Pure{"Type"} ne $Type2_Pure{"Type"})
13058 { # different types
13059 if($Type1_Pure{"Type"} eq "Intrinsic"
13060 and $Type2_Pure{"Type"} eq "Enum")
13061 { # "int" to "enum"
13062 return 0;
13063 }
13064 elsif($Type2_Pure{"Type"} eq "Intrinsic"
13065 and $Type1_Pure{"Type"} eq "Enum")
13066 { # "enum" to "int"
13067 return 0;
13068 }
13069 else
13070 { # "union" to "struct"
13071 # ...
13072 return 1;
13073 }
13074 }
13075 else
13076 {
13077 if($Type1_Pure{"Type"} eq "Intrinsic")
13078 {
13079 if($FloatType{$Type1_Pure{"Name"}}
13080 or $FloatType{$Type2_Pure{"Name"}})
13081 { # "float" to "double"
13082 # "float" to "int"
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040013083 if($Level eq "Source")
13084 { # Safe
13085 return 0;
13086 }
13087 else {
13088 return 1;
13089 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013090 }
13091 }
13092 elsif($Type1_Pure{"Type"}=~/Class|Struct|Union|Enum/)
13093 {
13094 my @Membs1 = keys(%{$Type1_Pure{"Memb"}});
13095 my @Membs2 = keys(%{$Type2_Pure{"Memb"}});
13096 if($#Membs1!=$#Membs2)
13097 { # different number of elements
13098 return 1;
13099 }
13100 if($Type1_Pure{"Type"} eq "Enum")
13101 {
13102 foreach my $Pos (@Membs1)
13103 { # compare elements by name and value
13104 if($Type1_Pure{"Memb"}{$Pos}{"name"} ne $Type2_Pure{"Memb"}{$Pos}{"name"}
13105 or $Type1_Pure{"Memb"}{$Pos}{"value"} ne $Type2_Pure{"Memb"}{$Pos}{"value"})
13106 { # different names
13107 return 1;
13108 }
13109 }
13110 }
13111 else
13112 {
13113 foreach my $Pos (@Membs1)
13114 { # compare elements by type name
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040013115 my $MT1 = $TypeInfo{1}{$Type1_Pure{"Memb"}{$Pos}{"type"}}{"Name"};
13116 my $MT2 = $TypeInfo{2}{$Type2_Pure{"Memb"}{$Pos}{"type"}}{"Name"};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013117 if($MT1 ne $MT2)
13118 { # different types
13119 return 1;
13120 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040013121 if($Level eq "Source")
13122 {
13123 if($Type1_Pure{"Memb"}{$Pos}{"name"} ne $Type2_Pure{"Memb"}{$Pos}{"name"})
13124 { # different names
13125 return 1;
13126 }
13127 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013128 }
13129 }
13130 }
13131 }
13132 return 0;
13133}
13134
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040013135sub detectTypeChange($$$$)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013136{
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040013137 my ($Type1_Id, $Type2_Id, $Prefix, $Level) = @_;
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040013138 if(not $Type1_Id or not $Type2_Id) {
13139 return ();
13140 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013141 my %LocalProblems = ();
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040013142 my %Type1 = get_Type($Type1_Id, 1);
13143 my %Type2 = get_Type($Type2_Id, 2);
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +040013144 my %Type1_Pure = get_PureType($Type1_Id, $TypeInfo{1});
13145 my %Type2_Pure = get_PureType($Type2_Id, $TypeInfo{2});
13146 my %Type1_Base = ($Type1_Pure{"Type"} eq "Array")?get_OneStep_BaseType($Type1_Pure{"Tid"}, $TypeInfo{1}):get_BaseType($Type1_Id, 1);
13147 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 +040013148 my $Type1_PLevel = get_PLevel($Type1_Id, 1);
13149 my $Type2_PLevel = get_PLevel($Type2_Id, 2);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013150 return () if(not $Type1{"Name"} or not $Type2{"Name"});
13151 return () if(not $Type1_Base{"Name"} or not $Type2_Base{"Name"});
13152 return () if($Type1_PLevel eq "" or $Type2_PLevel eq "");
13153 if($Type1_Base{"Name"} ne $Type2_Base{"Name"}
13154 and ($Type1{"Name"} eq $Type2{"Name"} or ($Type1_PLevel>=1 and $Type1_PLevel==$Type2_PLevel
13155 and $Type1_Base{"Name"} ne "void" and $Type2_Base{"Name"} ne "void")))
13156 { # base type change
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040013157 if($Type1{"Name"} eq $Type2{"Name"})
13158 {
13159 if($Type1{"Type"} eq "Typedef" and $Type2{"Type"} eq "Typedef")
13160 { # will be reported in mergeTypes() as typedef problem
13161 return ();
13162 }
13163 my %Typedef_1 = goToFirst($Type1{"Tid"}, 1, "Typedef");
13164 my %Typedef_2 = goToFirst($Type2{"Tid"}, 2, "Typedef");
13165 if(%Typedef_1 and %Typedef_2)
13166 {
13167 if($Typedef_1{"Name"} eq $Typedef_2{"Name"}
13168 and $Typedef_1{"Type"} eq "Typedef" and $Typedef_2{"Type"} eq "Typedef")
13169 { # const Typedef
13170 return ();
13171 }
13172 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013173 }
13174 if($Type1_Base{"Name"}!~/anon\-/ and $Type2_Base{"Name"}!~/anon\-/)
13175 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040013176 if($Level eq "Binary"
13177 and $Type1_Base{"Size"} ne $Type2_Base{"Size"}
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013178 and $Type1_Base{"Size"} and $Type2_Base{"Size"})
13179 {
13180 %{$LocalProblems{$Prefix."_BaseType_And_Size"}}=(
13181 "Old_Value"=>$Type1_Base{"Name"},
13182 "New_Value"=>$Type2_Base{"Name"},
13183 "Old_Size"=>$Type1_Base{"Size"}*$BYTE_SIZE,
13184 "New_Size"=>$Type2_Base{"Size"}*$BYTE_SIZE,
13185 "InitialType_Type"=>$Type1_Pure{"Type"});
13186 }
13187 else
13188 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040013189 if(checkFormatChange($Type1_Base{"Tid"}, $Type2_Base{"Tid"}, $Level))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013190 { # format change
13191 %{$LocalProblems{$Prefix."_BaseType_Format"}}=(
13192 "Old_Value"=>$Type1_Base{"Name"},
13193 "New_Value"=>$Type2_Base{"Name"},
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +040013194 "Old_Size"=>$Type1_Base{"Size"}*$BYTE_SIZE,
13195 "New_Size"=>$Type2_Base{"Size"}*$BYTE_SIZE,
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013196 "InitialType_Type"=>$Type1_Pure{"Type"});
13197 }
13198 elsif(tNameLock($Type1_Base{"Tid"}, $Type2_Base{"Tid"}))
13199 {
13200 %{$LocalProblems{$Prefix."_BaseType"}}=(
13201 "Old_Value"=>$Type1_Base{"Name"},
13202 "New_Value"=>$Type2_Base{"Name"},
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +040013203 "Old_Size"=>$Type1_Base{"Size"}*$BYTE_SIZE,
13204 "New_Size"=>$Type2_Base{"Size"}*$BYTE_SIZE,
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013205 "InitialType_Type"=>$Type1_Pure{"Type"});
13206 }
13207 }
13208 }
13209 }
13210 elsif($Type1{"Name"} ne $Type2{"Name"})
13211 { # type change
13212 if($Type1{"Name"}!~/anon\-/ and $Type2{"Name"}!~/anon\-/)
13213 {
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +040013214 if($Prefix eq "Return"
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013215 and $Type1_Pure{"Name"} eq "void")
13216 {
13217 %{$LocalProblems{"Return_Type_From_Void"}}=(
13218 "New_Value"=>$Type2{"Name"},
13219 "New_Size"=>$Type2{"Size"}*$BYTE_SIZE,
13220 "InitialType_Type"=>$Type1_Pure{"Type"});
13221 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013222 elsif($Prefix eq "Return"
13223 and $Type2_Pure{"Name"} eq "void")
13224 {
13225 %{$LocalProblems{"Return_Type_Became_Void"}}=(
13226 "Old_Value"=>$Type1{"Name"},
13227 "Old_Size"=>$Type1{"Size"}*$BYTE_SIZE,
13228 "InitialType_Type"=>$Type1_Pure{"Type"});
13229 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013230 else
13231 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040013232 if($Level eq "Binary"
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040013233 and $Type1{"Size"} and $Type2{"Size"}
13234 and $Type1{"Size"} ne $Type2{"Size"})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013235 {
13236 %{$LocalProblems{$Prefix."_Type_And_Size"}}=(
13237 "Old_Value"=>$Type1{"Name"},
13238 "New_Value"=>$Type2{"Name"},
13239 "Old_Size"=>$Type1{"Size"}*$BYTE_SIZE,
13240 "New_Size"=>$Type2{"Size"}*$BYTE_SIZE,
13241 "InitialType_Type"=>$Type1_Pure{"Type"});
13242 }
13243 else
13244 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040013245 if(checkFormatChange($Type1_Id, $Type2_Id, $Level))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013246 { # format change
13247 %{$LocalProblems{$Prefix."_Type_Format"}}=(
13248 "Old_Value"=>$Type1{"Name"},
13249 "New_Value"=>$Type2{"Name"},
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +040013250 "Old_Size"=>$Type1{"Size"}*$BYTE_SIZE,
13251 "New_Size"=>$Type2{"Size"}*$BYTE_SIZE,
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013252 "InitialType_Type"=>$Type1_Pure{"Type"});
13253 }
13254 elsif(tNameLock($Type1_Id, $Type2_Id))
13255 { # FIXME: correct this condition
13256 %{$LocalProblems{$Prefix."_Type"}}=(
13257 "Old_Value"=>$Type1{"Name"},
13258 "New_Value"=>$Type2{"Name"},
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +040013259 "Old_Size"=>$Type1{"Size"}*$BYTE_SIZE,
13260 "New_Size"=>$Type2{"Size"}*$BYTE_SIZE,
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013261 "InitialType_Type"=>$Type1_Pure{"Type"});
13262 }
13263 }
13264 }
13265 }
13266 }
13267 if($Type1_PLevel!=$Type2_PLevel)
13268 {
13269 if($Type1{"Name"} ne "void" and $Type1{"Name"} ne "..."
13270 and $Type2{"Name"} ne "void" and $Type2{"Name"} ne "...")
13271 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040013272 if($Level eq "Source")
13273 {
13274 %{$LocalProblems{$Prefix."_PointerLevel"}}=(
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013275 "Old_Value"=>$Type1_PLevel,
13276 "New_Value"=>$Type2_PLevel);
13277 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040013278 else
13279 {
13280 if($Type2_PLevel>$Type1_PLevel) {
13281 %{$LocalProblems{$Prefix."_PointerLevel_Increased"}}=(
13282 "Old_Value"=>$Type1_PLevel,
13283 "New_Value"=>$Type2_PLevel);
13284 }
13285 else {
13286 %{$LocalProblems{$Prefix."_PointerLevel_Decreased"}}=(
13287 "Old_Value"=>$Type1_PLevel,
13288 "New_Value"=>$Type2_PLevel);
13289 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013290 }
13291 }
13292 }
13293 if($Type1_Pure{"Type"} eq "Array")
13294 { # base_type[N] -> base_type[N]
13295 # base_type: older_structure -> typedef to newer_structure
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040013296 my %SubProblems = detectTypeChange($Type1_Base{"Tid"}, $Type2_Base{"Tid"}, $Prefix, $Level);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013297 foreach my $SubProblemType (keys(%SubProblems))
13298 {
13299 $SubProblemType=~s/_Type/_BaseType/g;
13300 next if(defined $LocalProblems{$SubProblemType});
13301 foreach my $Attr (keys(%{$SubProblems{$SubProblemType}})) {
13302 $LocalProblems{$SubProblemType}{$Attr} = $SubProblems{$SubProblemType}{$Attr};
13303 }
13304 }
13305 }
13306 return %LocalProblems;
13307}
13308
13309sub tNameLock($$)
13310{
13311 my ($Tid1, $Tid2) = @_;
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040013312 my $Changed = 0;
13313 if(differentDumps("G"))
13314 { # different GCC versions
13315 $Changed = 1;
13316 }
13317 elsif(differentDumps("V"))
13318 { # different versions of ABI dumps
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040013319 if(not checkDump(1, "2.13")
13320 or not checkDump(2, "2.13"))
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040013321 { # latest names update
13322 # 2.6: added restrict qualifier
13323 # 2.13: added missed typedefs to qualified types
13324 $Changed = 1;
13325 }
13326 }
13327 if($Changed)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013328 { # different formats
13329 if($UseOldDumps)
13330 { # old dumps
13331 return 0;
13332 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040013333 my $TN1 = $TypeInfo{1}{$Tid1}{"Name"};
13334 my $TN2 = $TypeInfo{2}{$Tid2}{"Name"};
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040013335
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040013336 my $TT1 = $TypeInfo{1}{$Tid1}{"Type"};
13337 my $TT2 = $TypeInfo{2}{$Tid2}{"Type"};
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040013338
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040013339 my %Base1 = get_Type($Tid1, 1);
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040013340 while(defined $Base1{"Type"} and $Base1{"Type"} eq "Typedef") {
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +040013341 %Base1 = get_OneStep_BaseType($Base1{"Tid"}, $TypeInfo{1});
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013342 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040013343 my %Base2 = get_Type($Tid2, 2);
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040013344 while(defined $Base2{"Type"} and $Base2{"Type"} eq "Typedef") {
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +040013345 %Base2 = get_OneStep_BaseType($Base2{"Tid"}, $TypeInfo{2});
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013346 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +040013347 my $BName1 = uncover_typedefs($Base1{"Name"}, 1);
13348 my $BName2 = uncover_typedefs($Base2{"Name"}, 2);
13349 if($BName1 eq $BName2)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013350 { # equal base types
13351 return 0;
13352 }
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040013353
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040013354 if(not checkDump(1, "2.13")
13355 or not checkDump(2, "2.13"))
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040013356 { # broken array names in ABI dumps < 2.13
13357 if($TT1 eq "Array"
13358 and $TT2 eq "Array")
13359 {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013360 return 0;
13361 }
13362 }
13363
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040013364 if(not checkDump(1, "2.6")
13365 or not checkDump(2, "2.6"))
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040013366 { # added restrict attribute in 2.6
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040013367 if($TN1!~/\brestrict\b/
13368 and $TN2=~/\brestrict\b/)
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040013369 {
13370 return 0;
13371 }
13372 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013373 }
13374 return 1;
13375}
13376
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040013377sub differentDumps($)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013378{
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040013379 my $Check = $_[0];
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +040013380 if(defined $Cache{"differentDumps"}{$Check}) {
13381 return $Cache{"differentDumps"}{$Check};
13382 }
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040013383 if($UsedDump{1}{"V"} and $UsedDump{2}{"V"})
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040013384 {
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040013385 if($Check eq "G")
13386 {
13387 if(getGccVersion(1) ne getGccVersion(2))
13388 { # different GCC versions
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +040013389 return ($Cache{"differentDumps"}{$Check}=1);
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040013390 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040013391 }
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040013392 if($Check eq "V")
13393 {
13394 if(cmpVersions(formatVersion($UsedDump{1}{"V"}, 2),
13395 formatVersion($UsedDump{2}{"V"}, 2))!=0)
13396 { # different dump versions (skip micro version)
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +040013397 return ($Cache{"differentDumps"}{$Check}=1);
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040013398 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040013399 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013400 }
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +040013401 return ($Cache{"differentDumps"}{$Check}=0);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013402}
13403
13404sub formatVersion($$)
13405{ # cut off version digits
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040013406 my ($V, $Digits) = @_;
13407 my @Elems = split(/\./, $V);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013408 return join(".", splice(@Elems, 0, $Digits));
13409}
13410
13411sub htmlSpecChars($)
13412{
13413 my $Str = $_[0];
Andrey Ponomarenko5c09ef32012-06-14 18:17:33 +040013414 if(not $Str) {
13415 return $Str;
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040013416 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013417 $Str=~s/\&([^#]|\Z)/&amp;$1/g;
13418 $Str=~s/</&lt;/g;
13419 $Str=~s/\-\>/&#45;&gt;/g; # &minus;
13420 $Str=~s/>/&gt;/g;
13421 $Str=~s/([^ ])( )([^ ])/$1\@ALONE_SP\@$3/g;
13422 $Str=~s/ /&#160;/g; # &nbsp;
13423 $Str=~s/\@ALONE_SP\@/ /g;
13424 $Str=~s/\n/<br\/>/g;
13425 $Str=~s/\"/&quot;/g;
13426 $Str=~s/\'/&#39;/g;
13427 return $Str;
13428}
13429
Andrey Ponomarenko5c09ef32012-06-14 18:17:33 +040013430sub xmlSpecChars($)
13431{
13432 my $Str = $_[0];
13433 if(not $Str) {
13434 return $Str;
13435 }
13436
13437 $Str=~s/\&([^#]|\Z)/&amp;$1/g;
13438 $Str=~s/</&lt;/g;
13439 $Str=~s/>/&gt;/g;
13440
13441 $Str=~s/\"/&quot;/g;
13442 $Str=~s/\'/&#39;/g;
13443
13444 return $Str;
13445}
13446
Andrey Ponomarenko01117f12012-06-26 12:23:02 +040013447sub xmlSpecChars_R($)
13448{
13449 my $Str = $_[0];
13450 if(not $Str) {
13451 return $Str;
13452 }
13453
13454 $Str=~s/&amp;/&/g;
13455 $Str=~s/&lt;/</g;
13456 $Str=~s/&gt;/>/g;
13457
13458 $Str=~s/&quot;/"/g;
13459 $Str=~s/&#39;/'/g;
13460
13461 return $Str;
13462}
13463
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013464sub black_name($)
13465{
13466 my $Name = $_[0];
13467 return "<span class='iname_b'>".highLight_Signature($Name)."</span>";
13468}
13469
13470sub highLight_Signature($)
13471{
13472 my $Signature = $_[0];
13473 return highLight_Signature_PPos_Italic($Signature, "", 0, 0, 0);
13474}
13475
13476sub highLight_Signature_Italic_Color($)
13477{
13478 my $Signature = $_[0];
13479 return highLight_Signature_PPos_Italic($Signature, "", 1, 1, 1);
13480}
13481
13482sub separate_symbol($)
13483{
13484 my $Symbol = $_[0];
13485 my ($Name, $Spec, $Ver) = ($Symbol, "", "");
13486 if($Symbol=~/\A([^\@\$\?]+)([\@\$]+)([^\@\$]+)\Z/) {
13487 ($Name, $Spec, $Ver) = ($1, $2, $3);
13488 }
13489 return ($Name, $Spec, $Ver);
13490}
13491
13492sub cut_f_attrs($)
13493{
13494 if($_[0]=~s/(\))((| (const volatile|const|volatile))(| \[static\]))\Z/$1/) {
13495 return $2;
13496 }
13497 return "";
13498}
13499
13500sub highLight_Signature_PPos_Italic($$$$$)
13501{
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040013502 my ($FullSignature, $Param_Pos, $ItalicParams, $ColorParams, $ShowReturn) = @_;
13503 $Param_Pos = "" if(not defined $Param_Pos);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013504 if($CheckObjectsOnly) {
13505 $ItalicParams=$ColorParams=0;
13506 }
13507 my ($Signature, $VersionSpec, $SymbolVersion) = separate_symbol($FullSignature);
13508 my $Return = "";
13509 if($ShowRetVal and $Signature=~s/([^:]):([^:].+?)\Z/$1/g) {
13510 $Return = $2;
13511 }
Andrey Ponomarenko16934472012-03-29 15:37:04 +040013512 my $SCenter = find_center($Signature, "(");
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013513 if(not $SCenter)
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040013514 { # global data
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013515 $Signature = htmlSpecChars($Signature);
13516 $Signature=~s!(\[data\])!<span style='color:Black;font-weight:normal;'>$1</span>!g;
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040013517 $Signature .= (($SymbolVersion)?"<span class='sym_ver'>&#160;$VersionSpec&#160;$SymbolVersion</span>":"");
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013518 if($Return and $ShowReturn) {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040013519 $Signature .= "<span class='sym_p nowrap'> &#160;<b>:</b>&#160;&#160;".htmlSpecChars($Return)."</span>";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013520 }
13521 return $Signature;
13522 }
13523 my ($Begin, $End) = (substr($Signature, 0, $SCenter), "");
13524 $Begin.=" " if($Begin!~/ \Z/);
13525 $End = cut_f_attrs($Signature);
13526 my @Parts = ();
13527 my @SParts = get_s_params($Signature, 1);
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040013528 foreach my $Pos (0 .. $#SParts)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013529 {
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040013530 my $Part = $SParts[$Pos];
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013531 $Part=~s/\A\s+|\s+\Z//g;
13532 my ($Part_Styled, $ParamName) = (htmlSpecChars($Part), "");
13533 if($Part=~/\([\*]+(\w+)\)/i) {
13534 $ParamName = $1;#func-ptr
13535 }
13536 elsif($Part=~/(\w+)[\,\)]*\Z/i) {
13537 $ParamName = $1;
13538 }
13539 if(not $ParamName) {
13540 push(@Parts, $Part_Styled);
13541 next;
13542 }
13543 if($ItalicParams and not $TName_Tid{1}{$Part}
13544 and not $TName_Tid{2}{$Part})
13545 {
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040013546 my $Style = "param";
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040013547 if($Param_Pos ne ""
13548 and $Pos==$Param_Pos) {
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040013549 $Style = "focus_p";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013550 }
13551 elsif($ColorParams) {
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040013552 $Style = "color_p";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013553 }
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040013554 $Part_Styled =~ s!(\W)$ParamName([\,\)]|\Z)!$1<span class=\'$Style\'>$ParamName</span>$2!ig;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013555 }
13556 $Part_Styled=~s/,(\w)/, $1/g;
13557 push(@Parts, $Part_Styled);
13558 }
13559 if(@Parts)
13560 {
13561 foreach my $Num (0 .. $#Parts)
13562 {
13563 if($Num==$#Parts)
13564 { # add ")" to the last parameter
13565 $Parts[$Num] = "<span class='nowrap'>".$Parts[$Num]." )</span>";
13566 }
13567 elsif(length($Parts[$Num])<=45) {
13568 $Parts[$Num] = "<span class='nowrap'>".$Parts[$Num]."</span>";
13569 }
13570 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040013571 $Signature = htmlSpecChars($Begin)."<span class='sym_p'>(&#160;".join(" ", @Parts)."</span>".$End;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013572 }
13573 else {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040013574 $Signature = htmlSpecChars($Begin)."<span class='sym_p'>(&#160;)</span>".$End;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013575 }
13576 if($Return and $ShowReturn) {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040013577 $Signature .= "<span class='sym_p nowrap'> &#160;<b>:</b>&#160;&#160;".htmlSpecChars($Return)."</span>";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013578 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040013579 $Signature=~s!\[\]![&#160;]!g;
13580 $Signature=~s!operator=!operator&#160;=!g;
13581 $Signature=~s!(\[in-charge\]|\[not-in-charge\]|\[in-charge-deleting\]|\[static\])!<span class='sym_kind'>$1</span>!g;
13582 return $Signature.(($SymbolVersion)?"<span class='sym_ver'>&#160;$VersionSpec&#160;$SymbolVersion</span>":"");
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013583}
13584
13585sub get_s_params($$)
13586{
13587 my ($Signature, $Comma) = @_;
13588 my @Parts = ();
Andrey Ponomarenko16934472012-03-29 15:37:04 +040013589 my $ShortName = substr($Signature, 0, find_center($Signature, "("));
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013590 $Signature=~s/\A\Q$ShortName\E\(//g;
13591 cut_f_attrs($Signature);
13592 $Signature=~s/\)\Z//;
13593 return separate_params($Signature, $Comma);
13594}
13595
13596sub separate_params($$)
13597{
13598 my ($Params, $Comma) = @_;
13599 my @Parts = ();
Andrey Ponomarenko16934472012-03-29 15:37:04 +040013600 my %B = ( "("=>0, "<"=>0, ")"=>0, ">"=>0 );
13601 my $Part = 0;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013602 foreach my $Pos (0 .. length($Params) - 1)
13603 {
Andrey Ponomarenko16934472012-03-29 15:37:04 +040013604 my $S = substr($Params, $Pos, 1);
13605 if(defined $B{$S}) {
13606 $B{$S}+=1;
13607 }
13608 if($S eq "," and
13609 $B{"("}==$B{")"} and $B{"<"}==$B{">"})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013610 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040013611 if($Comma)
13612 { # include comma
Andrey Ponomarenko16934472012-03-29 15:37:04 +040013613 $Parts[$Part] .= $S;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013614 }
Andrey Ponomarenko16934472012-03-29 15:37:04 +040013615 $Part += 1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013616 }
13617 else {
Andrey Ponomarenko16934472012-03-29 15:37:04 +040013618 $Parts[$Part] .= $S;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013619 }
13620 }
13621 return @Parts;
13622}
13623
Andrey Ponomarenko16934472012-03-29 15:37:04 +040013624sub find_center($$)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013625{
13626 my ($Sign, $Target) = @_;
Andrey Ponomarenko16934472012-03-29 15:37:04 +040013627 my %B = ( "("=>0, "<"=>0, ")"=>0, ">"=>0 );
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013628 my $Center = 0;
Andrey Ponomarenko16934472012-03-29 15:37:04 +040013629 if($Sign=~s/(operator([^\w\s\(\)]+|\(\)))//g)
13630 { # operators
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013631 $Center+=length($1);
13632 }
13633 foreach my $Pos (0 .. length($Sign)-1)
13634 {
13635 my $S = substr($Sign, $Pos, 1);
13636 if($S eq $Target)
13637 {
13638 if($B{"("}==$B{")"}
13639 and $B{"<"}==$B{">"}) {
13640 return $Center;
13641 }
13642 }
13643 if(defined $B{$S}) {
13644 $B{$S}+=1;
13645 }
13646 $Center+=1;
13647 }
13648 return 0;
13649}
13650
13651sub appendFile($$)
13652{
13653 my ($Path, $Content) = @_;
13654 return if(not $Path);
13655 if(my $Dir = get_dirname($Path)) {
13656 mkpath($Dir);
13657 }
Andrey Ponomarenko16934472012-03-29 15:37:04 +040013658 open(FILE, ">>", $Path) || die ("can't open file \'$Path\': $!\n");
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013659 print FILE $Content;
13660 close(FILE);
13661}
13662
13663sub writeFile($$)
13664{
13665 my ($Path, $Content) = @_;
13666 return if(not $Path);
13667 if(my $Dir = get_dirname($Path)) {
13668 mkpath($Dir);
13669 }
Andrey Ponomarenko16934472012-03-29 15:37:04 +040013670 open(FILE, ">", $Path) || die ("can't open file \'$Path\': $!\n");
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013671 print FILE $Content;
13672 close(FILE);
13673}
13674
13675sub readFile($)
13676{
13677 my $Path = $_[0];
13678 return "" if(not $Path or not -f $Path);
Andrey Ponomarenko16934472012-03-29 15:37:04 +040013679 open(FILE, $Path);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013680 local $/ = undef;
13681 my $Content = <FILE>;
13682 close(FILE);
Andrey Ponomarenko85043792012-05-14 16:48:07 +040013683 if($Path!~/\.(tu|class|abi)\Z/) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013684 $Content=~s/\r/\n/g;
13685 }
13686 return $Content;
13687}
13688
13689sub get_filename($)
13690{ # much faster than basename() from File::Basename module
Andrey Ponomarenko85043792012-05-14 16:48:07 +040013691 if(defined $Cache{"get_filename"}{$_[0]}) {
13692 return $Cache{"get_filename"}{$_[0]};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013693 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +040013694 if($_[0] and $_[0]=~/([^\/\\]+)[\/\\]*\Z/) {
13695 return ($Cache{"get_filename"}{$_[0]}=$1);
13696 }
13697 return ($Cache{"get_filename"}{$_[0]}="");
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013698}
13699
13700sub get_dirname($)
13701{ # much faster than dirname() from File::Basename module
Andrey Ponomarenko85043792012-05-14 16:48:07 +040013702 if(defined $Cache{"get_dirname"}{$_[0]}) {
13703 return $Cache{"get_dirname"}{$_[0]};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013704 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +040013705 if($_[0] and $_[0]=~/\A(.*?)[\/\\]+[^\/\\]*[\/\\]*\Z/) {
13706 return ($Cache{"get_dirname"}{$_[0]}=$1);
13707 }
13708 return ($Cache{"get_dirname"}{$_[0]}="");
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013709}
13710
13711sub separate_path($) {
13712 return (get_dirname($_[0]), get_filename($_[0]));
13713}
13714
13715sub esc($)
13716{
13717 my $Str = $_[0];
13718 $Str=~s/([()\[\]{}$ &'"`;,<>\+])/\\$1/g;
13719 return $Str;
13720}
13721
13722sub readLineNum($$)
13723{
13724 my ($Path, $Num) = @_;
13725 return "" if(not $Path or not -f $Path);
Andrey Ponomarenko16934472012-03-29 15:37:04 +040013726 open(FILE, $Path);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013727 foreach (1 ... $Num) {
13728 <FILE>;
13729 }
13730 my $Line = <FILE>;
13731 close(FILE);
13732 return $Line;
13733}
13734
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040013735sub readAttributes($$)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013736{
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040013737 my ($Path, $Num) = @_;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013738 return () if(not $Path or not -f $Path);
13739 my %Attributes = ();
Andrey Ponomarenko85043792012-05-14 16:48:07 +040013740 if(readLineNum($Path, $Num)=~/<!--\s+(.+)\s+-->/)
13741 {
13742 foreach my $AttrVal (split(/;/, $1))
13743 {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013744 if($AttrVal=~/(.+):(.+)/)
13745 {
13746 my ($Name, $Value) = ($1, $2);
13747 $Attributes{$Name} = $Value;
13748 }
13749 }
13750 }
13751 return \%Attributes;
13752}
13753
13754sub is_abs($) {
13755 return ($_[0]=~/\A(\/|\w+:[\/\\])/);
13756}
13757
13758sub get_abs_path($)
13759{ # abs_path() should NOT be called for absolute inputs
13760 # because it can change them
13761 my $Path = $_[0];
13762 if(not is_abs($Path)) {
13763 $Path = abs_path($Path);
13764 }
13765 return $Path;
13766}
13767
13768sub get_OSgroup()
13769{
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +040013770 my $N = $Config{"osname"};
13771 if($N=~/macos|darwin|rhapsody/i) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013772 return "macos";
13773 }
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +040013774 elsif($N=~/freebsd|openbsd|netbsd/i) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013775 return "bsd";
13776 }
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +040013777 elsif($N=~/haiku|beos/i) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013778 return "beos";
13779 }
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +040013780 elsif($N=~/symbian|epoc/i) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013781 return "symbian";
13782 }
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +040013783 elsif($N=~/win/i) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013784 return "windows";
13785 }
13786 else {
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +040013787 return $N;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013788 }
13789}
13790
13791sub getGccVersion($)
13792{
13793 my $LibVersion = $_[0];
13794 if($GCC_VERSION{$LibVersion})
13795 { # dump version
13796 return $GCC_VERSION{$LibVersion};
13797 }
13798 elsif($UsedDump{$LibVersion}{"V"})
13799 { # old-version dumps
13800 return "unknown";
13801 }
13802 my $GccVersion = get_dumpversion($GCC_PATH); # host version
13803 if(not $GccVersion) {
13804 return "unknown";
13805 }
13806 return $GccVersion;
13807}
13808
13809sub showArch($)
13810{
13811 my $Arch = $_[0];
13812 if($Arch eq "arm"
13813 or $Arch eq "mips") {
13814 return uc($Arch);
13815 }
13816 return $Arch;
13817}
13818
13819sub getArch($)
13820{
13821 my $LibVersion = $_[0];
13822 if($CPU_ARCH{$LibVersion})
13823 { # dump version
13824 return $CPU_ARCH{$LibVersion};
13825 }
13826 elsif($UsedDump{$LibVersion}{"V"})
13827 { # old-version dumps
13828 return "unknown";
13829 }
13830 if(defined $Cache{"getArch"}{$LibVersion}) {
13831 return $Cache{"getArch"}{$LibVersion};
13832 }
13833 my $Arch = get_dumpmachine($GCC_PATH); # host version
13834 if(not $Arch) {
13835 return "unknown";
13836 }
13837 if($Arch=~/\A([\w]{3,})(-|\Z)/) {
13838 $Arch = $1;
13839 }
13840 $Arch = "x86" if($Arch=~/\Ai[3-7]86\Z/);
13841 if($OSgroup eq "windows") {
13842 $Arch = "x86" if($Arch=~/win32|mingw32/i);
13843 $Arch = "x86_64" if($Arch=~/win64|mingw64/i);
13844 }
13845 $Cache{"getArch"}{$LibVersion} = $Arch;
13846 return $Arch;
13847}
13848
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040013849sub get_Report_Header($)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013850{
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040013851 my $Level = $_[0];
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013852 my $ArchInfo = " on <span style='color:Blue;'>".showArch(getArch(1))."</span>";
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040013853 if(getArch(1) ne getArch(2)
13854 or getArch(1) eq "unknown"
13855 or $Level eq "Source")
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013856 { # don't show architecture in the header
13857 $ArchInfo="";
13858 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040013859 my $Report_Header = "<h1><span class='nowrap'>";
13860 if($Level eq "Source") {
13861 $Report_Header .= "Source compatibility";
13862 }
13863 elsif($Level eq "Binary") {
13864 $Report_Header .= "Binary compatibility";
13865 }
13866 else {
13867 $Report_Header .= "API compatibility";
13868 }
13869 $Report_Header .= " report for the <span style='color:Blue;'>$TargetLibraryFName</span> $TargetComponent</span>";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013870 $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>";
13871 if($AppPath) {
13872 $Report_Header .= " <span class='nowrap'>&#160;(relating to the portability of application <span style='color:Blue;'>".get_filename($AppPath)."</span>)</span>";
13873 }
13874 $Report_Header .= "</h1>\n";
13875 return $Report_Header;
13876}
13877
13878sub get_SourceInfo()
13879{
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040013880 my ($CheckedHeaders, $CheckedLibs) = ("", "");
13881 if(not $CheckObjectsOnly)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013882 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040013883 $CheckedHeaders = "<a name='Headers'></a><h2>Header Files (".keys(%{$Registered_Headers{1}}).")</h2><hr/>\n";
13884 $CheckedHeaders .= "<div class='h_list'>\n";
13885 foreach my $Header_Path (sort {lc($Registered_Headers{1}{$a}{"Identity"}) cmp lc($Registered_Headers{1}{$b}{"Identity"})} keys(%{$Registered_Headers{1}}))
13886 {
13887 my $Identity = $Registered_Headers{1}{$Header_Path}{"Identity"};
13888 my $Header_Name = get_filename($Identity);
13889 my $Dest_Comment = ($Identity=~/[\/\\]/)?" ($Identity)":"";
13890 $CheckedHeaders .= $Header_Name.$Dest_Comment."<br/>\n";
13891 }
13892 $CheckedHeaders .= "</div>\n";
13893 $CheckedHeaders .= "<br/>$TOP_REF<br/>\n";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013894 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040013895 if(not $CheckHeadersOnly)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013896 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040013897 $CheckedLibs = "<a name='Libs'></a><h2>".ucfirst($SLIB_TYPE)." Libraries (".keys(%{$Library_Symbol{1}}).")</h2><hr/>\n";
13898 $CheckedLibs .= "<div class='lib_list'>\n";
13899 foreach my $Library (sort {lc($a) cmp lc($b)} keys(%{$Library_Symbol{1}}))
13900 {
13901 $Library.=" (.$LIB_EXT)" if($Library!~/\.\w+\Z/);
13902 $CheckedLibs .= $Library."<br/>\n";
13903 }
13904 $CheckedLibs .= "</div>\n";
13905 $CheckedLibs .= "<br/>$TOP_REF<br/>\n";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013906 }
13907 return $CheckedHeaders.$CheckedLibs;
13908}
13909
13910sub get_TypeProblems_Count($$$)
13911{
13912 my ($TypeChanges, $TargetPriority, $Level) = @_;
13913 my $Type_Problems_Count = 0;
13914 foreach my $Type_Name (sort keys(%{$TypeChanges}))
13915 {
13916 my %Kinds_Target = ();
13917 foreach my $Kind (keys(%{$TypeChanges->{$Type_Name}}))
13918 {
13919 foreach my $Location (keys(%{$TypeChanges->{$Type_Name}{$Kind}}))
13920 {
13921 my $Target = $TypeChanges->{$Type_Name}{$Kind}{$Location}{"Target"};
13922 my $Priority = getProblemSeverity($Level, $Kind);
13923 next if($Priority ne $TargetPriority);
13924 if($Kinds_Target{$Kind}{$Target}) {
13925 next;
13926 }
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040013927 if(cmpSeverities($Type_MaxSeverity{$Level}{$Type_Name}{$Kind}{$Target}, $Priority))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013928 { # select a problem with the highest priority
13929 next;
13930 }
13931 $Kinds_Target{$Kind}{$Target} = 1;
13932 $Type_Problems_Count += 1;
13933 }
13934 }
13935 }
13936 return $Type_Problems_Count;
13937}
13938
13939sub get_Summary($)
13940{
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040013941 my $Level = $_[0];
13942 my ($Added, $Removed, $I_Problems_High, $I_Problems_Medium, $I_Problems_Low, $T_Problems_High,
13943 $C_Problems_Low, $T_Problems_Medium, $T_Problems_Low, $I_Other, $T_Other) = (0,0,0,0,0,0,0,0,0,0,0);
13944 %{$RESULT{$Level}} = (
13945 "Problems"=>0,
13946 "Warnings"=>0,
13947 "Affected"=>0 );
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013948 # check rules
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040013949 foreach my $Interface (sort keys(%{$CompatProblems{$Level}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013950 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040013951 foreach my $Kind (keys(%{$CompatProblems{$Level}{$Interface}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013952 {
13953 if(not defined $CompatRules{$Level}{$Kind})
13954 { # unknown rule
13955 if(not $UnknownRules{$Level}{$Kind})
13956 { # only one warning
13957 printMsg("WARNING", "unknown rule \"$Kind\" (\"$Level\")");
13958 $UnknownRules{$Level}{$Kind}=1;
13959 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040013960 delete($CompatProblems{$Level}{$Interface}{$Kind});
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013961 }
13962 }
13963 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040013964 foreach my $Interface (sort keys(%{$CompatProblems{$Level}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013965 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040013966 foreach my $Kind (sort keys(%{$CompatProblems{$Level}{$Interface}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013967 {
13968 if($CompatRules{$Level}{$Kind}{"Kind"} eq "Symbols")
13969 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040013970 foreach my $Location (sort keys(%{$CompatProblems{$Level}{$Interface}{$Kind}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013971 {
13972 my $Priority = getProblemSeverity($Level, $Kind);
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040013973 if($Kind eq "Added_Symbol") {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013974 $Added += 1;
13975 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040013976 elsif($Kind eq "Removed_Symbol")
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013977 {
13978 $Removed += 1;
13979 $TotalAffected{$Level}{$Interface} = $Priority;
13980 }
13981 else
13982 {
13983 if($Priority eq "Safe") {
13984 $I_Other += 1;
13985 }
13986 elsif($Priority eq "High") {
13987 $I_Problems_High += 1;
13988 }
13989 elsif($Priority eq "Medium") {
13990 $I_Problems_Medium += 1;
13991 }
13992 elsif($Priority eq "Low") {
13993 $I_Problems_Low += 1;
13994 }
13995 if(($Priority ne "Low" or $StrictCompat)
13996 and $Priority ne "Safe") {
13997 $TotalAffected{$Level}{$Interface} = $Priority;
13998 }
13999 }
14000 }
14001 }
14002 }
14003 }
14004 my %TypeChanges = ();
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014005 foreach my $Interface (sort keys(%{$CompatProblems{$Level}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014006 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014007 foreach my $Kind (keys(%{$CompatProblems{$Level}{$Interface}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014008 {
14009 if($CompatRules{$Level}{$Kind}{"Kind"} eq "Types")
14010 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014011 foreach my $Location (sort {cmp_locations($b, $a)} sort keys(%{$CompatProblems{$Level}{$Interface}{$Kind}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014012 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014013 my $Type_Name = $CompatProblems{$Level}{$Interface}{$Kind}{$Location}{"Type_Name"};
14014 my $Target = $CompatProblems{$Level}{$Interface}{$Kind}{$Location}{"Target"};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014015 my $Priority = getProblemSeverity($Level, $Kind);
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040014016 if(cmpSeverities($Type_MaxSeverity{$Level}{$Type_Name}{$Kind}{$Target}, $Priority))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014017 { # select a problem with the highest priority
14018 next;
14019 }
14020 if(($Priority ne "Low" or $StrictCompat)
14021 and $Priority ne "Safe") {
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040014022 $TotalAffected{$Level}{$Interface} = maxSeverity($TotalAffected{$Level}{$Interface}, $Priority);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014023 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014024 %{$TypeChanges{$Type_Name}{$Kind}{$Location}} = %{$CompatProblems{$Level}{$Interface}{$Kind}{$Location}};
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040014025 $Type_MaxSeverity{$Level}{$Type_Name}{$Kind}{$Target} = maxSeverity($Type_MaxSeverity{$Level}{$Type_Name}{$Kind}{$Target}, $Priority);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014026 }
14027 }
14028 }
14029 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014030
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014031 $T_Problems_High = get_TypeProblems_Count(\%TypeChanges, "High", $Level);
14032 $T_Problems_Medium = get_TypeProblems_Count(\%TypeChanges, "Medium", $Level);
14033 $T_Problems_Low = get_TypeProblems_Count(\%TypeChanges, "Low", $Level);
14034 $T_Other = get_TypeProblems_Count(\%TypeChanges, "Safe", $Level);
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014035
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014036 if($CheckObjectsOnly)
14037 { # only removed exported symbols
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014038 $RESULT{$Level}{"Affected"} = $Removed*100/keys(%{$Symbol_Library{1}});
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014039 }
14040 else
14041 { # changed and removed public symbols
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014042 my $SCount = keys(%{$CheckedSymbols{$Level}});
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014043 if($ExtendedCheck)
14044 { # don't count external_func_0 for constants
14045 $SCount-=1;
14046 }
14047 if($SCount)
14048 {
14049 my %Weight = (
14050 "High" => 100,
14051 "Medium" => 50,
14052 "Low" => 25
14053 );
14054 foreach (keys(%{$TotalAffected{$Level}})) {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014055 $RESULT{$Level}{"Affected"}+=$Weight{$TotalAffected{$Level}{$_}};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014056 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014057 $RESULT{$Level}{"Affected"} = $RESULT{$Level}{"Affected"}/$SCount;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014058 }
14059 else {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014060 $RESULT{$Level}{"Affected"} = 0;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014061 }
14062 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014063 $RESULT{$Level}{"Affected"} = show_number($RESULT{$Level}{"Affected"});
14064 if($RESULT{$Level}{"Affected"}>=100) {
14065 $RESULT{$Level}{"Affected"} = 100;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014066 }
14067
Andrey Ponomarenko85043792012-05-14 16:48:07 +040014068 $RESULT{$Level}{"Problems"} += $Removed;
14069 $RESULT{$Level}{"Problems"} += $T_Problems_High + $I_Problems_High;
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014070 $RESULT{$Level}{"Problems"} += $T_Problems_Medium + $I_Problems_Medium;
Andrey Ponomarenko85043792012-05-14 16:48:07 +040014071 if($StrictCompat) {
14072 $RESULT{$Level}{"Problems"} += $T_Problems_Low + $I_Problems_Low;
14073 }
14074 else {
14075 $RESULT{$Level}{"Warnings"} += $T_Problems_Low + $I_Problems_Low;
14076 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014077
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014078 if($C_Problems_Low = keys(%{$ProblemsWithConstants{$Level}}))
14079 {
Andrey Ponomarenko85043792012-05-14 16:48:07 +040014080 if(defined $CompatRules{$Level}{"Changed_Constant"})
14081 {
14082 if($StrictCompat) {
14083 $RESULT{$Level}{"Problems"} += $C_Problems_Low;
14084 }
14085 else {
14086 $RESULT{$Level}{"Warnings"} += $C_Problems_Low;
14087 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014088 }
14089 else
14090 {
14091 printMsg("WARNING", "unknown rule \"Changed_Constant\" (\"$Level\")");
14092 $C_Problems_Low = 0;
14093 }
14094 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +040014095 if($CheckImpl and $Level eq "Binary")
14096 {
14097 if($StrictCompat) {
14098 $RESULT{$Level}{"Problems"} += keys(%ImplProblems);
14099 }
14100 else {
14101 $RESULT{$Level}{"Warnings"} += keys(%ImplProblems);
14102 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014103 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +040014104 if($RESULT{$Level}{"Problems"}
14105 and $RESULT{$Level}{"Affected"}) {
14106 $RESULT{$Level}{"Verdict"} = "incompatible";
14107 }
14108 else {
14109 $RESULT{$Level}{"Verdict"} = "compatible";
14110 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014111
14112 my $TotalTypes = keys(%{$CheckedTypes{$Level}});
14113 if(not $TotalTypes)
14114 { # list all the types
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014115 $TotalTypes = keys(%{$TName_Tid{1}});
14116 }
14117
14118 my ($Arch1, $Arch2) = (getArch(1), getArch(2));
14119 my ($GccV1, $GccV2) = (getGccVersion(1), getGccVersion(2));
14120
14121 my ($TestInfo, $TestResults, $Problem_Summary) = ();
14122
14123 if($ReportFormat eq "xml")
14124 { # XML
14125 # test info
14126 $TestInfo .= " <library>$TargetLibraryName</library>\n";
14127 $TestInfo .= " <version1>\n";
14128 $TestInfo .= " <number>".$Descriptor{1}{"Version"}."</number>\n";
14129 $TestInfo .= " <architecture>$Arch1</architecture>\n";
14130 $TestInfo .= " <gcc>$GccV1</gcc>\n";
14131 $TestInfo .= " </version1>\n";
14132
14133 $TestInfo .= " <version2>\n";
14134 $TestInfo .= " <number>".$Descriptor{2}{"Version"}."</number>\n";
14135 $TestInfo .= " <architecture>$Arch2</architecture>\n";
14136 $TestInfo .= " <gcc>$GccV2</gcc>\n";
14137 $TestInfo .= " </version2>\n";
14138 $TestInfo = "<test_info>\n".$TestInfo."</test_info>\n\n";
14139
14140 # test results
14141 $TestResults .= " <headers>\n";
14142 foreach my $Name (sort {lc($Registered_Headers{1}{$a}{"Identity"}) cmp lc($Registered_Headers{1}{$b}{"Identity"})} keys(%{$Registered_Headers{1}}))
14143 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014144 my $Identity = $Registered_Headers{1}{$Name}{"Identity"};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014145 my $Comment = ($Identity=~/[\/\\]/)?" ($Identity)":"";
14146 $TestResults .= " <name>".get_filename($Name).$Comment."</name>\n";
14147 }
14148 $TestResults .= " </headers>\n";
14149
14150 $TestResults .= " <libs>\n";
14151 foreach my $Library (sort {lc($a) cmp lc($b)} keys(%{$Library_Symbol{1}}))
14152 {
14153 $Library.=" (.$LIB_EXT)" if($Library!~/\.\w+\Z/);
14154 $TestResults .= " <name>$Library</name>\n";
14155 }
14156 $TestResults .= " </libs>\n";
14157
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040014158 $TestResults .= " <symbols>".(keys(%{$CheckedSymbols{$Level}}) - keys(%ExtendedSymbols))."</symbols>\n";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014159 $TestResults .= " <types>".$TotalTypes."</types>\n";
14160
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014161 $TestResults .= " <verdict>".$RESULT{$Level}{"Verdict"}."</verdict>\n";
14162 $TestResults .= " <affected>".$RESULT{$Level}{"Affected"}."</affected>\n";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014163 $TestResults = "<test_results>\n".$TestResults."</test_results>\n\n";
14164
14165 # problem summary
14166 $Problem_Summary .= " <added_symbols>".$Added."</added_symbols>\n";
14167 $Problem_Summary .= " <removed_symbols>".$Removed."</removed_symbols>\n";
14168
14169 $Problem_Summary .= " <problems_with_types>\n";
14170 $Problem_Summary .= " <high>$T_Problems_High</high>\n";
14171 $Problem_Summary .= " <medium>$T_Problems_Medium</medium>\n";
14172 $Problem_Summary .= " <low>$T_Problems_Low</low>\n";
14173 $Problem_Summary .= " <safe>$T_Other</safe>\n";
14174 $Problem_Summary .= " </problems_with_types>\n";
14175
14176 $Problem_Summary .= " <problems_with_symbols>\n";
14177 $Problem_Summary .= " <high>$I_Problems_High</high>\n";
14178 $Problem_Summary .= " <medium>$I_Problems_Medium</medium>\n";
14179 $Problem_Summary .= " <low>$I_Problems_Low</low>\n";
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014180 $Problem_Summary .= " <safe>$I_Other</safe>\n";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014181 $Problem_Summary .= " </problems_with_symbols>\n";
14182
14183 $Problem_Summary .= " <problems_with_constants>\n";
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014184 $Problem_Summary .= " <low>$C_Problems_Low</low>\n";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014185 $Problem_Summary .= " </problems_with_constants>\n";
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014186 if($CheckImpl and $Level eq "Binary")
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014187 {
14188 $Problem_Summary .= " <impl>\n";
14189 $Problem_Summary .= " <low>".keys(%ImplProblems)."</low>\n";
14190 $Problem_Summary .= " </impl>\n";
14191 }
14192 $Problem_Summary = "<problem_summary>\n".$Problem_Summary."</problem_summary>\n\n";
14193
14194 return ($TestInfo.$TestResults.$Problem_Summary, "");
14195 }
14196 else
14197 { # HTML
14198 # test info
14199 $TestInfo = "<h2>Test Info</h2><hr/>\n";
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014200 $TestInfo .= "<table class='summary'>\n";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014201 $TestInfo .= "<tr><th>".ucfirst($TargetComponent)." Name</th><td>$TargetLibraryFName</td></tr>\n";
14202
14203 my (@VInf1, @VInf2, $AddTestInfo) = ();
14204 if($Arch1 ne "unknown"
14205 and $Arch2 ne "unknown")
14206 { # CPU arch
14207 if($Arch1 eq $Arch2)
14208 { # go to the separate section
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014209 $AddTestInfo .= "<tr><th>CPU Type</th><td>".showArch($Arch1)."</td></tr>\n";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014210 }
14211 else
14212 { # go to the version number
14213 push(@VInf1, showArch($Arch1));
14214 push(@VInf2, showArch($Arch2));
14215 }
14216 }
14217 if($GccV1 ne "unknown"
14218 and $GccV2 ne "unknown"
14219 and $OStarget ne "windows")
14220 { # GCC version
14221 if($GccV1 eq $GccV2)
14222 { # go to the separate section
14223 $AddTestInfo .= "<tr><th>GCC Version</th><td>$GccV1</td></tr>\n";
14224 }
14225 else
14226 { # go to the version number
14227 push(@VInf1, "gcc ".$GccV1);
14228 push(@VInf2, "gcc ".$GccV2);
14229 }
14230 }
14231 # show long version names with GCC version and CPU architecture name (if different)
14232 $TestInfo .= "<tr><th>Version #1</th><td>".$Descriptor{1}{"Version"}.(@VInf1?" (".join(", ", reverse(@VInf1)).")":"")."</td></tr>\n";
14233 $TestInfo .= "<tr><th>Version #2</th><td>".$Descriptor{2}{"Version"}.(@VInf2?" (".join(", ", reverse(@VInf2)).")":"")."</td></tr>\n";
14234 $TestInfo .= $AddTestInfo;
14235 #if($COMMON_LANGUAGE{1}) {
14236 # $TestInfo .= "<tr><th>Language</th><td>".$COMMON_LANGUAGE{1}."</td></tr>\n";
14237 #}
14238 if($ExtendedCheck) {
14239 $TestInfo .= "<tr><th>Mode</th><td>Extended</td></tr>\n";
14240 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014241 if($JoinReport)
14242 {
14243 if($Level eq "Binary") {
Andrey Ponomarenko16934472012-03-29 15:37:04 +040014244 $TestInfo .= "<tr><th>Subject</th><td width='150px'>Binary Compatibility</td></tr>\n"; # Run-time
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014245 }
14246 if($Level eq "Source") {
Andrey Ponomarenko16934472012-03-29 15:37:04 +040014247 $TestInfo .= "<tr><th>Subject</th><td width='150px'>Source Compatibility</td></tr>\n"; # Build-time
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014248 }
14249 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014250 $TestInfo .= "</table>\n";
14251
14252 # test results
14253 $TestResults = "<h2>Test Results</h2><hr/>\n";
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014254 $TestResults .= "<table class='summary'>";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014255
14256 my $Headers_Link = "0";
14257 $Headers_Link = "<a href='#Headers' style='color:Blue;'>".keys(%{$Registered_Headers{1}})."</a>" if(keys(%{$Registered_Headers{1}})>0);
14258 $TestResults .= "<tr><th>Total Header Files</th><td>".($CheckObjectsOnly?"0&#160;(not&#160;analyzed)":$Headers_Link)."</td></tr>\n";
14259
14260 if(not $ExtendedCheck)
14261 {
14262 my $Libs_Link = "0";
14263 $Libs_Link = "<a href='#Libs' style='color:Blue;'>".keys(%{$Library_Symbol{1}})."</a>" if(keys(%{$Library_Symbol{1}})>0);
14264 $TestResults .= "<tr><th>Total ".ucfirst($SLIB_TYPE)." Libraries</th><td>".($CheckHeadersOnly?"0&#160;(not&#160;analyzed)":$Libs_Link)."</td></tr>\n";
14265 }
14266
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040014267 $TestResults .= "<tr><th>Total Symbols / Types</th><td>".(keys(%{$CheckedSymbols{$Level}}) - keys(%ExtendedSymbols))." / ".$TotalTypes."</td></tr>\n";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014268
Andrey Ponomarenko85043792012-05-14 16:48:07 +040014269 my $META_DATA = "verdict:".$RESULT{$Level}{"Verdict"}.";";
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014270 if($JoinReport) {
14271 $META_DATA = "kind:".lc($Level).";".$META_DATA;
14272 }
Andrey Ponomarenko16934472012-03-29 15:37:04 +040014273 $TestResults .= "<tr><th>Verdict</th>";
Andrey Ponomarenko85043792012-05-14 16:48:07 +040014274 if($RESULT{$Level}{"Verdict"} eq "incompatible") {
Andrey Ponomarenko16934472012-03-29 15:37:04 +040014275 $TestResults .= "<td><span style='color:Red;'><b>Incompatible<br/>(".$RESULT{$Level}{"Affected"}."%)</b></span></td>";
14276 }
14277 else {
14278 $TestResults .= "<td><span style='color:Green;'><b>Compatible</b></span></td>";
14279 }
14280 $TestResults .= "</tr>\n";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014281 $TestResults .= "</table>\n";
14282
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014283 $META_DATA .= "affected:".$RESULT{$Level}{"Affected"}.";";# in percents
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014284 # problem summary
14285 $Problem_Summary = "<h2>Problem Summary</h2><hr/>\n";
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014286 $Problem_Summary .= "<table class='summary'>";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014287 $Problem_Summary .= "<tr><th></th><th style='text-align:center;'>Severity</th><th style='text-align:center;'>Count</th></tr>";
14288
14289 my $Added_Link = "0";
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014290 if($Added>0)
14291 {
14292 if($JoinReport) {
14293 $Added_Link = "<a href='#".$Level."_Added' style='color:Blue;'>$Added</a>";
14294 }
14295 else {
14296 $Added_Link = "<a href='#Added' style='color:Blue;'>$Added</a>";
14297 }
14298 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014299 $META_DATA .= "added:$Added;";
Andrey Ponomarenko16934472012-03-29 15:37:04 +040014300 $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 +040014301
14302 my $Removed_Link = "0";
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014303 if($Removed>0)
14304 {
14305 if($JoinReport) {
14306 $Removed_Link = "<a href='#".$Level."_Removed' style='color:Blue;'>$Removed</a>"
14307 }
14308 else {
14309 $Removed_Link = "<a href='#Removed' style='color:Blue;'>$Removed</a>"
14310 }
14311 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014312 $META_DATA .= "removed:$Removed;";
Andrey Ponomarenko16934472012-03-29 15:37:04 +040014313 $Problem_Summary .= "<tr><th>Removed Symbols</th>";
14314 $Problem_Summary .= "<td>High</td><td".getStyle("I", "R", $Removed).">$Removed_Link</td></tr>\n";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014315
14316 my $TH_Link = "0";
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014317 $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 +040014318 $TH_Link = "n/a" if($CheckObjectsOnly);
14319 $META_DATA .= "type_problems_high:$T_Problems_High;";
Andrey Ponomarenko16934472012-03-29 15:37:04 +040014320 $Problem_Summary .= "<tr><th rowspan='3'>Problems with<br/>Data Types</th>";
14321 $Problem_Summary .= "<td>High</td><td".getStyle("T", "H", $T_Problems_High).">$TH_Link</td></tr>\n";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014322
14323 my $TM_Link = "0";
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014324 $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 +040014325 $TM_Link = "n/a" if($CheckObjectsOnly);
14326 $META_DATA .= "type_problems_medium:$T_Problems_Medium;";
Andrey Ponomarenko16934472012-03-29 15:37:04 +040014327 $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 +040014328
14329 my $TL_Link = "0";
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014330 $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 +040014331 $TL_Link = "n/a" if($CheckObjectsOnly);
14332 $META_DATA .= "type_problems_low:$T_Problems_Low;";
Andrey Ponomarenko16934472012-03-29 15:37:04 +040014333 $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 +040014334
14335 my $IH_Link = "0";
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014336 $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 +040014337 $IH_Link = "n/a" if($CheckObjectsOnly);
14338 $META_DATA .= "interface_problems_high:$I_Problems_High;";
Andrey Ponomarenko16934472012-03-29 15:37:04 +040014339 $Problem_Summary .= "<tr><th rowspan='3'>Problems with<br/>Symbols</th>";
14340 $Problem_Summary .= "<td>High</td><td".getStyle("I", "H", $I_Problems_High).">$IH_Link</td></tr>\n";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014341
14342 my $IM_Link = "0";
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014343 $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 +040014344 $IM_Link = "n/a" if($CheckObjectsOnly);
14345 $META_DATA .= "interface_problems_medium:$I_Problems_Medium;";
Andrey Ponomarenko16934472012-03-29 15:37:04 +040014346 $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 +040014347
14348 my $IL_Link = "0";
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014349 $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 +040014350 $IL_Link = "n/a" if($CheckObjectsOnly);
14351 $META_DATA .= "interface_problems_low:$I_Problems_Low;";
Andrey Ponomarenko16934472012-03-29 15:37:04 +040014352 $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 +040014353
14354 my $ChangedConstants_Link = "0";
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014355 if(keys(%{$CheckedSymbols{$Level}}) and $C_Problems_Low)
14356 {
14357 if($JoinReport) {
14358 $ChangedConstants_Link = "<a href='#".$Level."_Changed_Constants' style='color:Blue;'>$C_Problems_Low</a>";
14359 }
14360 else {
14361 $ChangedConstants_Link = "<a href='#Changed_Constants' style='color:Blue;'>$C_Problems_Low</a>";
14362 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014363 }
14364 $ChangedConstants_Link = "n/a" if($CheckObjectsOnly);
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014365 $META_DATA .= "changed_constants:$C_Problems_Low;";
Andrey Ponomarenko16934472012-03-29 15:37:04 +040014366 $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 +040014367
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014368 if($CheckImpl and $Level eq "Binary")
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014369 {
14370 my $ChangedImpl_Link = "0";
14371 $ChangedImpl_Link = "<a href='#Changed_Implementation' style='color:Blue;'>".keys(%ImplProblems)."</a>" if(keys(%ImplProblems)>0);
14372 $ChangedImpl_Link = "n/a" if($CheckHeadersOnly);
14373 $META_DATA .= "changed_implementation:".keys(%ImplProblems).";";
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040014374 $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 +040014375 }
14376 # Safe Changes
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014377 if($T_Other and not $CheckObjectsOnly)
14378 {
14379 my $TS_Link = "<a href='#".get_Anchor("Type", $Level, "Safe")."' style='color:Blue;'>$T_Other</a>";
Andrey Ponomarenko16934472012-03-29 15:37:04 +040014380 $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 +040014381 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014382
14383 if($I_Other and not $CheckObjectsOnly)
14384 {
14385 my $IS_Link = "<a href='#".get_Anchor("Symbol", $Level, "Safe")."' style='color:Blue;'>$I_Other</a>";
Andrey Ponomarenko16934472012-03-29 15:37:04 +040014386 $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 +040014387 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014388
14389 $META_DATA .= "tool_version:$TOOL_VERSION";
14390 $Problem_Summary .= "</table>\n";
Andrey Ponomarenko16934472012-03-29 15:37:04 +040014391 # $TestInfo = getLegend().$TestInfo;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014392 return ($TestInfo.$TestResults.$Problem_Summary, $META_DATA);
14393 }
14394}
14395
Andrey Ponomarenko16934472012-03-29 15:37:04 +040014396sub getStyle($$$)
14397{
14398 my ($Subj, $Act, $Num) = @_;
14399 my %Style = (
14400 "A"=>"new",
14401 "R"=>"failed",
14402 "S"=>"passed",
14403 "L"=>"warning",
14404 "M"=>"failed",
14405 "H"=>"failed"
14406 );
14407 if($Num>0) {
14408 return " class='".$Style{$Act}."'";
14409 }
14410 return "";
14411}
14412
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014413sub show_number($)
14414{
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014415 if($_[0])
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014416 {
Andrey Ponomarenko16934472012-03-29 15:37:04 +040014417 my $Num = cut_off_number($_[0], 2, 0);
14418 if($Num eq "0")
14419 {
14420 foreach my $P (3 .. 7)
14421 {
14422 $Num = cut_off_number($_[0], $P, 1);
14423 if($Num ne "0") {
14424 last;
14425 }
14426 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014427 }
14428 if($Num eq "0") {
14429 $Num = $_[0];
14430 }
14431 return $Num;
14432 }
14433 return $_[0];
14434}
14435
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014436sub cut_off_number($$$)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014437{
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014438 my ($num, $digs_to_cut, $z) = @_;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014439 if($num!~/\./)
14440 {
14441 $num .= ".";
14442 foreach (1 .. $digs_to_cut-1) {
14443 $num .= "0";
14444 }
14445 }
14446 elsif($num=~/\.(.+)\Z/ and length($1)<$digs_to_cut-1)
14447 {
14448 foreach (1 .. $digs_to_cut - 1 - length($1)) {
14449 $num .= "0";
14450 }
14451 }
14452 elsif($num=~/\d+\.(\d){$digs_to_cut,}/) {
14453 $num=sprintf("%.".($digs_to_cut-1)."f", $num);
14454 }
14455 $num=~s/\.[0]+\Z//g;
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014456 if($z) {
14457 $num=~s/(\.[1-9]+)[0]+\Z/$1/g;
14458 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014459 return $num;
14460}
14461
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014462sub get_Report_ChangedConstants($)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014463{
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014464 my $Level = $_[0];
Andrey Ponomarenko16934472012-03-29 15:37:04 +040014465 my $CHANGED_CONSTANTS = "";
14466 my %ReportMap = ();
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014467 foreach my $Constant (keys(%{$ProblemsWithConstants{$Level}})) {
Andrey Ponomarenko16934472012-03-29 15:37:04 +040014468 $ReportMap{$Constants{1}{$Constant}{"Header"}}{$Constant} = 1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014469 }
14470 my $Kind = "Changed_Constant";
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014471 if(not defined $CompatRules{$Level}{$Kind}) {
14472 return "";
14473 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014474 if($ReportFormat eq "xml")
14475 { # XML
Andrey Ponomarenko16934472012-03-29 15:37:04 +040014476 foreach my $HeaderName (sort {lc($a) cmp lc($b)} keys(%ReportMap))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014477 {
14478 $CHANGED_CONSTANTS .= " <header name=\"$HeaderName\">\n";
Andrey Ponomarenko16934472012-03-29 15:37:04 +040014479 foreach my $Constant (sort {lc($a) cmp lc($b)} keys(%{$ReportMap{$HeaderName}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014480 {
14481 $CHANGED_CONSTANTS .= " <constant name=\"$Constant\">\n";
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014482 my $Change = $CompatRules{$Level}{$Kind}{"Change"};
14483 my $Effect = $CompatRules{$Level}{$Kind}{"Effect"};
14484 my $Overcome = $CompatRules{$Level}{$Kind}{"Overcome"};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014485 $CHANGED_CONSTANTS .= " <problem id=\"$Kind\">\n";
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014486 $CHANGED_CONSTANTS .= " <change".getXmlParams($Change, $ProblemsWithConstants{$Level}{$Constant}).">$Change</change>\n";
14487 $CHANGED_CONSTANTS .= " <effect".getXmlParams($Effect, $ProblemsWithConstants{$Level}{$Constant}).">$Effect</effect>\n";
14488 $CHANGED_CONSTANTS .= " <overcome".getXmlParams($Overcome, $ProblemsWithConstants{$Level}{$Constant}).">$Overcome</overcome>\n";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014489 $CHANGED_CONSTANTS .= " </problem>\n";
14490 $CHANGED_CONSTANTS .= " </constant>\n";
14491 }
14492 $CHANGED_CONSTANTS .= " </header>\n";
14493 }
14494 $CHANGED_CONSTANTS = "<problems_with_constants severity=\"Low\">\n".$CHANGED_CONSTANTS."</problems_with_constants>\n\n";
14495 }
14496 else
14497 { # HTML
14498 my $Number = 0;
Andrey Ponomarenko16934472012-03-29 15:37:04 +040014499 foreach my $HeaderName (sort {lc($a) cmp lc($b)} keys(%ReportMap))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014500 {
14501 $CHANGED_CONSTANTS .= "<span class='h_name'>$HeaderName</span><br/>\n";
Andrey Ponomarenko16934472012-03-29 15:37:04 +040014502 foreach my $Name (sort {lc($a) cmp lc($b)} keys(%{$ReportMap{$HeaderName}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014503 {
14504 $Number += 1;
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014505 my $Change = applyMacroses($Level, $Kind, $CompatRules{$Level}{$Kind}{"Change"}, $ProblemsWithConstants{$Level}{$Name});
14506 my $Effect = $CompatRules{$Level}{$Kind}{"Effect"};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014507 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 +040014508 $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 +040014509 $Report = $ContentSpanStart."<span class='extendable'>[+]</span> ".$Name.$ContentSpanEnd."<br/>\n".$Report;
14510 $CHANGED_CONSTANTS .= insertIDs($Report);
14511 }
14512 $CHANGED_CONSTANTS .= "<br/>\n";
14513 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014514 if($CHANGED_CONSTANTS)
14515 {
14516 my $Anchor = "<a name='Changed_Constants'></a>";
14517 if($JoinReport) {
14518 $Anchor = "<a name='".$Level."_Changed_Constants'></a>";
14519 }
14520 $CHANGED_CONSTANTS = $Anchor."<h2>Problems with Constants ($Number)</h2><hr/>\n".$CHANGED_CONSTANTS.$TOP_REF."<br/>\n";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014521 }
14522 }
14523 return $CHANGED_CONSTANTS;
14524}
14525
14526sub get_Report_Impl()
14527{
Andrey Ponomarenko16934472012-03-29 15:37:04 +040014528 my $CHANGED_IMPLEMENTATION = "";
14529 my %ReportMap = ();
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014530 foreach my $Interface (sort keys(%ImplProblems))
14531 {
14532 my $HeaderName = $CompleteSignature{1}{$Interface}{"Header"};
14533 my $DyLib = $Symbol_Library{1}{$Interface};
Andrey Ponomarenko16934472012-03-29 15:37:04 +040014534 $ReportMap{$HeaderName}{$DyLib}{$Interface} = 1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014535 }
14536 my $Changed_Number = 0;
Andrey Ponomarenko16934472012-03-29 15:37:04 +040014537 foreach my $HeaderName (sort {lc($a) cmp lc($b)} keys(%ReportMap))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014538 {
Andrey Ponomarenko16934472012-03-29 15:37:04 +040014539 foreach my $DyLib (sort {lc($a) cmp lc($b)} keys(%{$ReportMap{$HeaderName}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014540 {
14541 my $FDyLib=$DyLib.($DyLib!~/\.\w+\Z/?" (.$LIB_EXT)":"");
14542 if($HeaderName) {
14543 $CHANGED_IMPLEMENTATION .= "<span class='h_name'>$HeaderName</span>, <span class='lib_name'>$FDyLib</span><br/>\n";
14544 }
14545 else {
14546 $CHANGED_IMPLEMENTATION .= "<span class='lib_name'>$DyLib</span><br/>\n";
14547 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014548 my %NameSpaceSymbols = ();
Andrey Ponomarenko16934472012-03-29 15:37:04 +040014549 foreach my $Interface (keys(%{$ReportMap{$HeaderName}{$DyLib}})) {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014550 $NameSpaceSymbols{get_IntNameSpace($Interface, 2)}{$Interface} = 1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014551 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014552 foreach my $NameSpace (sort keys(%NameSpaceSymbols))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014553 {
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040014554 $CHANGED_IMPLEMENTATION .= ($NameSpace)?"<span class='ns_title'>namespace</span> <span class='ns'>$NameSpace</span><br/>\n":"";
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014555 my @SortedInterfaces = sort {lc(get_Signature($a, 1)) cmp lc(get_Signature($b, 1))} keys(%{$NameSpaceSymbols{$NameSpace}});
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014556 foreach my $Interface (@SortedInterfaces)
14557 {
14558 $Changed_Number += 1;
14559 my $Signature = get_Signature($Interface, 1);
14560 if($NameSpace) {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040014561 $Signature=~s/\b\Q$NameSpace\E::\b//g;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014562 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014563 $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 +040014564 }
14565 }
14566 $CHANGED_IMPLEMENTATION .= "<br/>\n";
14567 }
14568 }
14569 if($CHANGED_IMPLEMENTATION) {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014570 $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 +040014571 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +040014572
14573 # clean memory
14574 %ImplProblems = ();
14575
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014576 return $CHANGED_IMPLEMENTATION;
14577}
14578
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014579sub getTitle($$$)
14580{
14581 my ($Header, $Library, $NameSpace) = @_;
14582 my $Title = "";
14583 if($Library and $Library!~/\.\w+\Z/) {
14584 $Library .= " (.$LIB_EXT)";
14585 }
14586 if($Header and $Library)
14587 {
14588 $Title .= "<span class='h_name'>$Header</span>";
14589 $Title .= ", <span class='lib_name'>$Library</span><br/>\n";
14590 }
14591 elsif($Library) {
14592 $Title .= "<span class='lib_name'>$Library</span><br/>\n";
14593 }
14594 elsif($Header) {
14595 $Title .= "<span class='h_name'>$Header</span><br/>\n";
14596 }
14597 if($NameSpace) {
14598 $Title .= "<span class='ns_title'>namespace</span> <span class='ns'>$NameSpace</span><br/>\n";
14599 }
14600 return $Title;
14601}
14602
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014603sub get_Report_Added($)
14604{
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014605 my $Level = $_[0];
Andrey Ponomarenko16934472012-03-29 15:37:04 +040014606 my $ADDED_INTERFACES = "";
14607 my %ReportMap = ();
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014608 foreach my $Interface (sort keys(%{$CompatProblems{$Level}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014609 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014610 foreach my $Kind (sort keys(%{$CompatProblems{$Level}{$Interface}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014611 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014612 if($Kind eq "Added_Symbol")
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014613 {
14614 my $HeaderName = $CompleteSignature{2}{$Interface}{"Header"};
14615 my $DyLib = $Symbol_Library{2}{$Interface};
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014616 if($Level eq "Source" and $ReportFormat eq "html")
14617 { # do not show library name in HTML report
14618 $DyLib = "";
14619 }
14620 $ReportMap{$HeaderName}{$DyLib}{$Interface} = 1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014621 }
14622 }
14623 }
14624 if($ReportFormat eq "xml")
14625 { # XML
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014626 foreach my $HeaderName (sort {lc($a) cmp lc($b)} keys(%ReportMap))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014627 {
14628 $ADDED_INTERFACES .= " <header name=\"$HeaderName\">\n";
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014629 foreach my $DyLib (sort {lc($a) cmp lc($b)} keys(%{$ReportMap{$HeaderName}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014630 {
14631 $ADDED_INTERFACES .= " <library name=\"$DyLib\">\n";
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014632 foreach my $Interface (keys(%{$ReportMap{$HeaderName}{$DyLib}})) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014633 $ADDED_INTERFACES .= " <name>$Interface</name>\n";
14634 }
14635 $ADDED_INTERFACES .= " </library>\n";
14636 }
14637 $ADDED_INTERFACES .= " </header>\n";
14638 }
14639 $ADDED_INTERFACES = "<added_symbols>\n".$ADDED_INTERFACES."</added_symbols>\n\n";
14640 }
14641 else
14642 { # HTML
14643 my $Added_Number = 0;
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014644 foreach my $HeaderName (sort {lc($a) cmp lc($b)} keys(%ReportMap))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014645 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014646 foreach my $DyLib (sort {lc($a) cmp lc($b)} keys(%{$ReportMap{$HeaderName}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014647 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014648 my %NameSpaceSymbols = ();
14649 foreach my $Interface (keys(%{$ReportMap{$HeaderName}{$DyLib}})) {
14650 $NameSpaceSymbols{get_IntNameSpace($Interface, 2)}{$Interface} = 1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014651 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014652 foreach my $NameSpace (sort keys(%NameSpaceSymbols))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014653 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014654 $ADDED_INTERFACES .= getTitle($HeaderName, $DyLib, $NameSpace);
14655 my @SortedInterfaces = sort {lc(get_Signature($a, 2)) cmp lc(get_Signature($b, 2))} keys(%{$NameSpaceSymbols{$NameSpace}});
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014656 foreach my $Interface (@SortedInterfaces)
14657 {
14658 $Added_Number += 1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014659 my $Signature = get_Signature($Interface, 2);
14660 if($NameSpace) {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040014661 $Signature=~s/\b\Q$NameSpace\E::\b//g;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014662 }
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040014663 if($Interface=~/\A(_Z|\?)/)
14664 {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014665 if($Signature) {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014666 $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 +040014667 }
14668 else {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014669 $ADDED_INTERFACES .= "<span class=\"iname\">".$Interface."</span><br/>\n";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014670 }
14671 }
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040014672 else
14673 {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014674 if($Signature) {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014675 $ADDED_INTERFACES .= "<span class=\"iname\">".highLight_Signature_Italic_Color($Signature)."</span><br/>\n";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014676 }
14677 else {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014678 $ADDED_INTERFACES .= "<span class=\"iname\">".$Interface."</span><br/>\n";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014679 }
14680 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014681 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014682 $ADDED_INTERFACES .= "<br/>\n";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014683 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014684 }
14685 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014686 if($ADDED_INTERFACES)
14687 {
14688 my $Anchor = "<a name='Added'></a>";
14689 if($JoinReport) {
14690 $Anchor = "<a name='".$Level."_Added'></a>";
14691 }
14692 $ADDED_INTERFACES = $Anchor."<h2>Added Symbols ($Added_Number)</h2><hr/>\n".$ADDED_INTERFACES.$TOP_REF."<br/>\n";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014693 }
14694 }
14695 return $ADDED_INTERFACES;
14696}
14697
14698sub get_Report_Removed($)
14699{
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014700 my $Level = $_[0];
Andrey Ponomarenko16934472012-03-29 15:37:04 +040014701 my $REMOVED_INTERFACES = "";
14702 my %ReportMap = ();
Andrey Ponomarenko85043792012-05-14 16:48:07 +040014703 foreach my $Symbol (sort keys(%{$CompatProblems{$Level}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014704 {
Andrey Ponomarenko85043792012-05-14 16:48:07 +040014705 foreach my $Kind (sort keys(%{$CompatProblems{$Level}{$Symbol}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014706 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014707 if($Kind eq "Removed_Symbol")
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014708 {
Andrey Ponomarenko85043792012-05-14 16:48:07 +040014709 my $HeaderName = $CompleteSignature{1}{$Symbol}{"Header"};
14710 my $DyLib = $Symbol_Library{1}{$Symbol};
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014711 if($Level eq "Source" and $ReportFormat eq "html")
14712 { # do not show library name in HTML report
14713 $DyLib = "";
14714 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +040014715 $ReportMap{$HeaderName}{$DyLib}{$Symbol} = 1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014716 }
14717 }
14718 }
14719 if($ReportFormat eq "xml")
14720 { # XML
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014721 foreach my $HeaderName (sort {lc($a) cmp lc($b)} keys(%ReportMap))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014722 {
14723 $REMOVED_INTERFACES .= " <header name=\"$HeaderName\">\n";
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014724 foreach my $DyLib (sort {lc($a) cmp lc($b)} keys(%{$ReportMap{$HeaderName}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014725 {
14726 $REMOVED_INTERFACES .= " <library name=\"$DyLib\">\n";
Andrey Ponomarenko85043792012-05-14 16:48:07 +040014727 foreach my $Symbol (keys(%{$ReportMap{$HeaderName}{$DyLib}})) {
14728 $REMOVED_INTERFACES .= " <name>$Symbol</name>\n";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014729 }
14730 $REMOVED_INTERFACES .= " </library>\n";
14731 }
14732 $REMOVED_INTERFACES .= " </header>\n";
14733 }
14734 $REMOVED_INTERFACES = "<removed_symbols>\n".$REMOVED_INTERFACES."</removed_symbols>\n\n";
14735 }
14736 else
14737 { # HTML
14738 my $Removed_Number = 0;
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014739 foreach my $HeaderName (sort {lc($a) cmp lc($b)} keys(%ReportMap))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014740 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014741 foreach my $DyLib (sort {lc($a) cmp lc($b)} keys(%{$ReportMap{$HeaderName}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014742 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014743 my %NameSpaceSymbols = ();
14744 foreach my $Interface (keys(%{$ReportMap{$HeaderName}{$DyLib}})) {
14745 $NameSpaceSymbols{get_IntNameSpace($Interface, 1)}{$Interface} = 1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014746 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014747 foreach my $NameSpace (sort keys(%NameSpaceSymbols))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014748 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014749 $REMOVED_INTERFACES .= getTitle($HeaderName, $DyLib, $NameSpace);
14750 my @SortedInterfaces = sort {lc(get_Signature($a, 1)) cmp lc(get_Signature($b, 1))} keys(%{$NameSpaceSymbols{$NameSpace}});
Andrey Ponomarenko85043792012-05-14 16:48:07 +040014751 foreach my $Symbol (@SortedInterfaces)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014752 {
14753 $Removed_Number += 1;
14754 my $SubReport = "";
Andrey Ponomarenko85043792012-05-14 16:48:07 +040014755 my $Signature = get_Signature($Symbol, 1);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014756 if($NameSpace) {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040014757 $Signature=~s/\b\Q$NameSpace\E::\b//g;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014758 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +040014759 if($Symbol=~/\A(_Z|\?)/)
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014760 {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014761 if($Signature) {
Andrey Ponomarenko85043792012-05-14 16:48:07 +040014762 $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 +040014763 }
14764 else {
Andrey Ponomarenko85043792012-05-14 16:48:07 +040014765 $REMOVED_INTERFACES .= "<span class=\"iname\">".$Symbol."</span><br/>\n";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014766 }
14767 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014768 else
14769 {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014770 if($Signature) {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014771 $REMOVED_INTERFACES .= "<span class=\"iname\">".highLight_Signature_Italic_Color($Signature)."</span><br/>\n";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014772 }
14773 else {
Andrey Ponomarenko85043792012-05-14 16:48:07 +040014774 $REMOVED_INTERFACES .= "<span class=\"iname\">".$Symbol."</span><br/>\n";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014775 }
14776 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014777 }
14778 }
14779 $REMOVED_INTERFACES .= "<br/>\n";
14780 }
14781 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014782 if($REMOVED_INTERFACES)
14783 {
14784 my $Anchor = "<a name='Removed'></a><a name='Withdrawn'></a>";
14785 if($JoinReport) {
14786 $Anchor = "<a name='".$Level."_Removed'></a><a name='".$Level."_Withdrawn'></a>";
14787 }
14788 $REMOVED_INTERFACES = $Anchor."<h2>Removed Symbols ($Removed_Number)</h2><hr/>\n".$REMOVED_INTERFACES.$TOP_REF."<br/>\n";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014789 }
14790 }
14791 return $REMOVED_INTERFACES;
14792}
14793
14794sub getXmlParams($$)
14795{
14796 my ($Content, $Problem) = @_;
14797 return "" if(not $Content or not $Problem);
14798 my %XMLparams = ();
14799 foreach my $Attr (sort {$b cmp $a} keys(%{$Problem}))
14800 {
14801 my $Macro = "\@".lc($Attr);
14802 if($Content=~/\Q$Macro\E/) {
14803 $XMLparams{lc($Attr)} = $Problem->{$Attr};
14804 }
14805 }
14806 my @PString = ();
14807 foreach my $P (sort {$b cmp $a} keys(%XMLparams)) {
Andrey Ponomarenko5c09ef32012-06-14 18:17:33 +040014808 push(@PString, $P."=\"".xmlSpecChars($XMLparams{$P})."\"");
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014809 }
14810 if(@PString) {
14811 return " ".join(" ", @PString);
14812 }
14813 else {
14814 return "";
14815 }
14816}
14817
14818sub addMarkup($)
14819{
14820 my $Content = $_[0];
14821 # auto-markup
14822 $Content=~s/\n[ ]*//; # spaces
14823 $Content=~s!(\@\w+\s*\(\@\w+\))!<nowrap>$1</nowrap>!g; # @old_type (@old_size)
14824 $Content=~s!(... \(\w+\))!<nowrap><b>$1</b></nowrap>!g; # ... (va_list)
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040014825 $Content=~s!<nowrap>(.+?)</nowrap>!<span class='nowrap'>$1</span>!g;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014826 $Content=~s!([2-9]\))!<br/>$1!g; # 1), 2), ...
14827 if($Content=~/\ANOTE:/)
14828 { # notes
14829 $Content=~s!(NOTE):!<b>$1</b>:!g;
14830 }
14831 else {
14832 $Content=~s!(NOTE):!<br/><b>$1</b>:!g;
14833 }
14834 $Content=~s! (out)-! <b>$1</b>-!g; # out-parameters
14835 my @Keywords = (
14836 "void",
14837 "const",
14838 "static",
14839 "restrict",
14840 "volatile",
14841 "register",
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040014842 "virtual"
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014843 );
14844 my $MKeys = join("|", @Keywords);
14845 foreach (@Keywords) {
14846 $MKeys .= "|non-".$_;
14847 }
14848 $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 +040014849
14850 # Markdown
14851 $Content=~s!\*\*([\w\-]+)\*\*!<b>$1</b>!ig;
14852 $Content=~s!\*([\w\-]+)\*!<i>$1</i>!ig;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014853 return $Content;
14854}
14855
14856sub applyMacroses($$$$)
14857{
14858 my ($Level, $Kind, $Content, $Problem) = @_;
14859 return "" if(not $Content or not $Problem);
14860 $Problem->{"Word_Size"} = $WORD_SIZE{2};
14861 $Content = addMarkup($Content);
14862 # macros
14863 foreach my $Attr (sort {$b cmp $a} keys(%{$Problem}))
14864 {
14865 my $Macro = "\@".lc($Attr);
14866 my $Value = $Problem->{$Attr};
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040014867 if(not defined $Value
14868 or $Value eq "") {
14869 next;
14870 }
Andrey Ponomarenko5c09ef32012-06-14 18:17:33 +040014871 if($Value=~/\s\(/ and $Value!~/['"]/)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014872 { # functions
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014873 $Value=~s/\s*\[[\w\-]+\]//g; # remove quals
14874 $Value=~s/\s\w+(\)|,)/$1/g; # remove parameter names
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014875 $Value = black_name($Value);
14876 }
14877 elsif($Value=~/\s/) {
14878 $Value = "<span class='value'>".htmlSpecChars($Value)."</span>";
14879 }
14880 elsif($Value=~/\A\d+\Z/
14881 and ($Attr eq "Old_Size" or $Attr eq "New_Size"))
14882 { # bits to bytes
14883 if($Value % $BYTE_SIZE)
14884 { # bits
14885 if($Value==1) {
14886 $Value = "<b>".$Value."</b> bit";
14887 }
14888 else {
14889 $Value = "<b>".$Value."</b> bits";
14890 }
14891 }
14892 else
14893 { # bytes
14894 $Value /= $BYTE_SIZE;
14895 if($Value==1) {
14896 $Value = "<b>".$Value."</b> byte";
14897 }
14898 else {
14899 $Value = "<b>".$Value."</b> bytes";
14900 }
14901 }
14902 }
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040014903 else
14904 {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014905 $Value = "<b>".htmlSpecChars($Value)."</b>";
14906 }
14907 $Content=~s/\Q$Macro\E/$Value/g;
14908 }
14909
14910 if($Content=~/(\A|[^\@\w])\@\w/)
14911 {
14912 if(not $IncompleteRules{$Level}{$Kind})
14913 { # only one warning
14914 printMsg("WARNING", "incomplete rule \"$Kind\" (\"$Level\")");
14915 $IncompleteRules{$Level}{$Kind} = 1;
14916 }
14917 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014918 return $Content;
14919}
14920
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040014921sub get_Report_SymbolProblems($$)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014922{
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014923 my ($TargetSeverity, $Level) = @_;
Andrey Ponomarenko16934472012-03-29 15:37:04 +040014924 my $INTERFACE_PROBLEMS = "";
14925 my (%ReportMap, %SymbolChanges) = ();
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014926 foreach my $Symbol (sort keys(%{$CompatProblems{$Level}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014927 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014928 my ($SN, $SS, $SV) = separate_symbol($Symbol);
14929 if($SV and defined $CompatProblems{$Level}{$SN}) {
14930 next;
14931 }
14932 foreach my $Kind (sort keys(%{$CompatProblems{$Level}{$Symbol}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014933 {
14934 if($CompatRules{$Level}{$Kind}{"Kind"} eq "Symbols"
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014935 and $Kind ne "Added_Symbol" and $Kind ne "Removed_Symbol")
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014936 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014937 my $HeaderName = $CompleteSignature{1}{$Symbol}{"Header"};
14938 my $DyLib = $Symbol_Library{1}{$Symbol};
14939 if(not $DyLib and my $VSym = $SymVer{1}{$Symbol})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014940 { # Symbol with Version
14941 $DyLib = $Symbol_Library{1}{$VSym};
14942 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040014943 if(not $DyLib)
14944 { # const global data
14945 $DyLib = "";
14946 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014947 if($Level eq "Source" and $ReportFormat eq "html")
14948 { # do not show library name in HTML report
14949 $DyLib = "";
14950 }
14951 %{$SymbolChanges{$Symbol}{$Kind}} = %{$CompatProblems{$Level}{$Symbol}{$Kind}};
14952 foreach my $Location (sort keys(%{$SymbolChanges{$Symbol}{$Kind}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014953 {
14954 my $Priority = getProblemSeverity($Level, $Kind);
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014955 if($Priority ne $TargetSeverity) {
14956 delete($SymbolChanges{$Symbol}{$Kind}{$Location});
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014957 }
14958 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014959 if(not keys(%{$SymbolChanges{$Symbol}{$Kind}}))
14960 {
14961 delete($SymbolChanges{$Symbol}{$Kind});
14962 next;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014963 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014964 $ReportMap{$HeaderName}{$DyLib}{$Symbol} = 1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014965 }
14966 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014967 if(not keys(%{$SymbolChanges{$Symbol}})) {
14968 delete($SymbolChanges{$Symbol});
14969 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014970 }
14971 if($ReportFormat eq "xml")
14972 { # XML
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014973 foreach my $HeaderName (sort {lc($a) cmp lc($b)} keys(%ReportMap))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014974 {
14975 $INTERFACE_PROBLEMS .= " <header name=\"$HeaderName\">\n";
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014976 foreach my $DyLib (sort {lc($a) cmp lc($b)} keys(%{$ReportMap{$HeaderName}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014977 {
14978 $INTERFACE_PROBLEMS .= " <library name=\"$DyLib\">\n";
14979 foreach my $Symbol (sort {lc($tr_name{$a}) cmp lc($tr_name{$b})} keys(%SymbolChanges))
14980 {
14981 $INTERFACE_PROBLEMS .= " <symbol name=\"$Symbol\">\n";
14982 foreach my $Kind (keys(%{$SymbolChanges{$Symbol}}))
14983 {
14984 foreach my $Location (sort keys(%{$SymbolChanges{$Symbol}{$Kind}}))
14985 {
14986 my %Problem = %{$SymbolChanges{$Symbol}{$Kind}{$Location}};
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040014987 $Problem{"Param_Pos"} = showPos($Problem{"Param_Pos"});
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014988 $INTERFACE_PROBLEMS .= " <problem id=\"$Kind\">\n";
14989 my $Change = $CompatRules{$Level}{$Kind}{"Change"};
14990 $INTERFACE_PROBLEMS .= " <change".getXmlParams($Change, \%Problem).">$Change</change>\n";
14991 my $Effect = $CompatRules{$Level}{$Kind}{"Effect"};
14992 $INTERFACE_PROBLEMS .= " <effect".getXmlParams($Effect, \%Problem).">$Effect</effect>\n";
14993 my $Overcome = $CompatRules{$Level}{$Kind}{"Overcome"};
14994 $INTERFACE_PROBLEMS .= " <overcome".getXmlParams($Overcome, \%Problem).">$Overcome</overcome>\n";
14995 $INTERFACE_PROBLEMS .= " </problem>\n";
14996 }
14997 }
14998 $INTERFACE_PROBLEMS .= " </symbol>\n";
14999 }
15000 $INTERFACE_PROBLEMS .= " </library>\n";
15001 }
15002 $INTERFACE_PROBLEMS .= " </header>\n";
15003 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015004 $INTERFACE_PROBLEMS = "<problems_with_symbols severity=\"$TargetSeverity\">\n".$INTERFACE_PROBLEMS."</problems_with_symbols>\n\n";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015005 }
15006 else
15007 { # HTML
15008 my $ProblemsNum = 0;
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015009 foreach my $HeaderName (sort {lc($a) cmp lc($b)} keys(%ReportMap))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015010 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015011 foreach my $DyLib (sort {lc($a) cmp lc($b)} keys(%{$ReportMap{$HeaderName}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015012 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015013 my (%NameSpaceSymbols, %NewSignature) = ();
15014 foreach my $Symbol (keys(%{$ReportMap{$HeaderName}{$DyLib}})) {
15015 $NameSpaceSymbols{get_IntNameSpace($Symbol, 1)}{$Symbol} = 1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015016 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015017 foreach my $NameSpace (sort keys(%NameSpaceSymbols))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015018 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015019 $INTERFACE_PROBLEMS .= getTitle($HeaderName, $DyLib, $NameSpace);
15020 my @SortedInterfaces = sort {lc($tr_name{$a}) cmp lc($tr_name{$b})} keys(%{$NameSpaceSymbols{$NameSpace}});
15021 foreach my $Symbol (@SortedInterfaces)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015022 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015023 my $Signature = get_Signature($Symbol, 1);
15024 my $SYMBOL_REPORT = "";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015025 my $ProblemNum = 1;
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015026 foreach my $Kind (keys(%{$SymbolChanges{$Symbol}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015027 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015028 foreach my $Location (sort keys(%{$SymbolChanges{$Symbol}{$Kind}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015029 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015030 my %Problem = %{$SymbolChanges{$Symbol}{$Kind}{$Location}};
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040015031 $Problem{"Param_Pos"} = showPos($Problem{"Param_Pos"});
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015032 if($Problem{"New_Signature"}) {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015033 $NewSignature{$Symbol} = $Problem{"New_Signature"};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015034 }
15035 if(my $Change = applyMacroses($Level, $Kind, $CompatRules{$Level}{$Kind}{"Change"}, \%Problem))
15036 {
15037 my $Effect = applyMacroses($Level, $Kind, $CompatRules{$Level}{$Kind}{"Effect"}, \%Problem);
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015038 $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 +040015039 $ProblemNum += 1;
15040 $ProblemsNum += 1;
15041 }
15042 }
15043 }
15044 $ProblemNum -= 1;
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015045 if($SYMBOL_REPORT)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015046 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015047 $INTERFACE_PROBLEMS .= $ContentSpanStart."<span class='extendable'>[+]</span> ";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015048 if($Signature) {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015049 $INTERFACE_PROBLEMS .= highLight_Signature_Italic_Color($Signature);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015050 }
15051 else {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015052 $INTERFACE_PROBLEMS .= $Symbol;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015053 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015054 $INTERFACE_PROBLEMS .= " ($ProblemNum)".$ContentSpanEnd."<br/>\n";
15055 $INTERFACE_PROBLEMS .= $ContentDivStart."\n";
15056 if($NewSignature{$Symbol})
15057 { # argument list changed to
15058 $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 +040015059 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015060 if($Symbol=~/\A(_Z|\?)/) {
15061 $INTERFACE_PROBLEMS .= "<span class='mangled'>&#160;&#160;&#160;&#160;[symbol: <b>$Symbol</b>]</span><br/>\n";
15062 }
15063 $INTERFACE_PROBLEMS .= "<table class='ptable'><tr><th width='2%'></th><th width='47%'>Change</th><th>Effect</th></tr>$SYMBOL_REPORT</table><br/>\n";
15064 $INTERFACE_PROBLEMS .= $ContentDivEnd;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015065 if($NameSpace) {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040015066 $INTERFACE_PROBLEMS=~s/\b\Q$NameSpace\E::\b//g;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015067 }
15068 }
15069 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015070 $INTERFACE_PROBLEMS .= "<br/>";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015071 }
15072 }
15073 }
15074 if($INTERFACE_PROBLEMS)
15075 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015076 $INTERFACE_PROBLEMS = insertIDs($INTERFACE_PROBLEMS);
15077 my $Title = "Problems with Symbols, $TargetSeverity Severity";
15078 if($TargetSeverity eq "Safe")
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015079 { # Safe Changes
15080 $Title = "Other Changes in Symbols";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015081 }
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040015082 $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 +040015083 }
15084 }
15085 return $INTERFACE_PROBLEMS;
15086}
15087
15088sub get_Report_TypeProblems($$)
15089{
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015090 my ($TargetSeverity, $Level) = @_;
Andrey Ponomarenko16934472012-03-29 15:37:04 +040015091 my $TYPE_PROBLEMS = "";
15092 my (%ReportMap, %TypeChanges, %TypeType) = ();
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015093 foreach my $Interface (sort keys(%{$CompatProblems{$Level}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015094 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015095 foreach my $Kind (keys(%{$CompatProblems{$Level}{$Interface}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015096 {
15097 if($CompatRules{$Level}{$Kind}{"Kind"} eq "Types")
15098 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015099 foreach my $Location (sort {cmp_locations($b, $a)} sort keys(%{$CompatProblems{$Level}{$Interface}{$Kind}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015100 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015101 my $TypeName = $CompatProblems{$Level}{$Interface}{$Kind}{$Location}{"Type_Name"};
15102 my $TypeType = $CompatProblems{$Level}{$Interface}{$Kind}{$Location}{"Type_Type"};
15103 my $Target = $CompatProblems{$Level}{$Interface}{$Kind}{$Location}{"Target"};
15104 $CompatProblems{$Level}{$Interface}{$Kind}{$Location}{"Type_Type"} = lc($TypeType);
15105 my $Severity = getProblemSeverity($Level, $Kind);
15106 if($Severity eq "Safe"
15107 and $TargetSeverity ne "Safe") {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015108 next;
15109 }
15110 if(not $TypeType{$TypeName}
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015111 or $TypeType{$TypeName} eq "struct")
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015112 { # register type of the type, select "class" if type has "class"- and "struct"-type changes
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015113 $TypeType{$TypeName} = $CompatProblems{$Level}{$Interface}{$Kind}{$Location}{"Type_Type"};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015114 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015115
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040015116 if(cmpSeverities($Type_MaxSeverity{$Level}{$TypeName}{$Kind}{$Target}, $Severity))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015117 { # select a problem with the highest priority
15118 next;
15119 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015120 %{$TypeChanges{$TypeName}{$Kind}{$Location}} = %{$CompatProblems{$Level}{$Interface}{$Kind}{$Location}};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015121 }
15122 }
15123 }
15124 }
15125 my %Kinds_Locations = ();
15126 foreach my $TypeName (keys(%TypeChanges))
15127 {
15128 my %Kinds_Target = ();
15129 foreach my $Kind (sort keys(%{$TypeChanges{$TypeName}}))
15130 {
15131 foreach my $Location (sort {cmp_locations($b, $a)} sort keys(%{$TypeChanges{$TypeName}{$Kind}}))
15132 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015133 my $Severity = getProblemSeverity($Level, $Kind);
15134 if($Severity ne $TargetSeverity)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015135 { # other priority
15136 delete($TypeChanges{$TypeName}{$Kind}{$Location});
15137 next;
15138 }
15139 $Kinds_Locations{$TypeName}{$Kind}{$Location} = 1;
15140 my $Target = $TypeChanges{$TypeName}{$Kind}{$Location}{"Target"};
15141 if($Kinds_Target{$Kind}{$Target})
15142 { # duplicate target
15143 delete($TypeChanges{$TypeName}{$Kind}{$Location});
15144 next;
15145 }
15146 $Kinds_Target{$Kind}{$Target} = 1;
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040015147 my $HeaderName = $TypeInfo{1}{$TName_Tid{1}{$TypeName}}{"Header"};
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015148 $ReportMap{$HeaderName}{$TypeName} = 1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015149 }
15150 if(not keys(%{$TypeChanges{$TypeName}{$Kind}})) {
15151 delete($TypeChanges{$TypeName}{$Kind});
15152 }
15153 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015154 if(not keys(%{$TypeChanges{$TypeName}})) {
15155 delete($TypeChanges{$TypeName});
15156 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015157 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +040015158 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 +040015159 if($ReportFormat eq "xml")
15160 { # XML
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015161 foreach my $HeaderName (sort {lc($a) cmp lc($b)} keys(%ReportMap))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015162 {
15163 $TYPE_PROBLEMS .= " <header name=\"$HeaderName\">\n";
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015164 foreach my $TypeName (keys(%{$ReportMap{$HeaderName}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015165 {
Andrey Ponomarenko5c09ef32012-06-14 18:17:33 +040015166 $TYPE_PROBLEMS .= " <type name=\"".xmlSpecChars($TypeName)."\">\n";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015167 foreach my $Kind (sort {$b=~/Size/ <=> $a=~/Size/} sort keys(%{$TypeChanges{$TypeName}}))
15168 {
15169 foreach my $Location (sort {cmp_locations($b, $a)} sort keys(%{$TypeChanges{$TypeName}{$Kind}}))
15170 {
15171 my %Problem = %{$TypeChanges{$TypeName}{$Kind}{$Location}};
15172 $TYPE_PROBLEMS .= " <problem id=\"$Kind\">\n";
15173 my $Change = $CompatRules{$Level}{$Kind}{"Change"};
15174 $TYPE_PROBLEMS .= " <change".getXmlParams($Change, \%Problem).">$Change</change>\n";
15175 my $Effect = $CompatRules{$Level}{$Kind}{"Effect"};
15176 $TYPE_PROBLEMS .= " <effect".getXmlParams($Effect, \%Problem).">$Effect</effect>\n";
15177 my $Overcome = $CompatRules{$Level}{$Kind}{"Overcome"};
15178 $TYPE_PROBLEMS .= " <overcome".getXmlParams($Overcome, \%Problem).">$Overcome</overcome>\n";
15179 $TYPE_PROBLEMS .= " </problem>\n";
15180 }
15181 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +040015182 $TYPE_PROBLEMS .= getAffectedSymbols($Level, $TypeName, $Kinds_Locations{$TypeName}, \@Symbols);
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015183 if($Level eq "Binary" and grep {$_=~/Virtual|Base_Class/} keys(%{$Kinds_Locations{$TypeName}})) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015184 $TYPE_PROBLEMS .= showVTables($TypeName);
15185 }
15186 $TYPE_PROBLEMS .= " </type>\n";
15187 }
15188 $TYPE_PROBLEMS .= " </header>\n";
15189 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015190 $TYPE_PROBLEMS = "<problems_with_types severity=\"$TargetSeverity\">\n".$TYPE_PROBLEMS."</problems_with_types>\n\n";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015191 }
15192 else
15193 { # HTML
15194 my $ProblemsNum = 0;
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015195 foreach my $HeaderName (sort {lc($a) cmp lc($b)} keys(%ReportMap))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015196 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015197 my (%NameSpace_Type) = ();
15198 foreach my $TypeName (keys(%{$ReportMap{$HeaderName}})) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015199 $NameSpace_Type{parse_TypeNameSpace($TypeName, 1)}{$TypeName} = 1;
15200 }
15201 foreach my $NameSpace (sort keys(%NameSpace_Type))
15202 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015203 $TYPE_PROBLEMS .= getTitle($HeaderName, "", $NameSpace);
15204 my @SortedTypes = sort {$TypeType{$a}." ".lc($a) cmp $TypeType{$b}." ".lc($b)} keys(%{$NameSpace_Type{$NameSpace}});
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015205 foreach my $TypeName (@SortedTypes)
15206 {
15207 my $ProblemNum = 1;
15208 my $TYPE_REPORT = "";
15209 foreach my $Kind (sort {$b=~/Size/ <=> $a=~/Size/} sort keys(%{$TypeChanges{$TypeName}}))
15210 {
15211 foreach my $Location (sort {cmp_locations($b, $a)} sort keys(%{$TypeChanges{$TypeName}{$Kind}}))
15212 {
15213 my %Problem = %{$TypeChanges{$TypeName}{$Kind}{$Location}};
15214 if(my $Change = applyMacroses($Level, $Kind, $CompatRules{$Level}{$Kind}{"Change"}, \%Problem))
15215 {
15216 my $Effect = applyMacroses($Level, $Kind, $CompatRules{$Level}{$Kind}{"Effect"}, \%Problem);
15217 $TYPE_REPORT .= "<tr><th>$ProblemNum</th><td align='left' valign='top'>".$Change."</td><td align='left' valign='top'>$Effect</td></tr>\n";
15218 $ProblemNum += 1;
15219 $ProblemsNum += 1;
15220 }
15221 }
15222 }
15223 $ProblemNum -= 1;
15224 if($TYPE_REPORT)
15225 {
Andrey Ponomarenko85043792012-05-14 16:48:07 +040015226 my $Affected = getAffectedSymbols($Level, $TypeName, $Kinds_Locations{$TypeName}, \@Symbols);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015227 my $ShowVTables = "";
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015228 if($Level eq "Binary" and grep {$_=~/Virtual|Base_Class/} keys(%{$Kinds_Locations{$TypeName}})) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015229 $ShowVTables = showVTables($TypeName);
15230 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015231 $TYPE_PROBLEMS .= $ContentSpanStart."<span class='extendable'>[+]</span> <span class='ttype'>".$TypeType{$TypeName}."</span> ".htmlSpecChars($TypeName)." ($ProblemNum)".$ContentSpanEnd;
15232 $TYPE_PROBLEMS .= "<br/>\n".$ContentDivStart."<table class='ptable'><tr>\n";
15233 $TYPE_PROBLEMS .= "<th width='2%'></th><th width='47%'>Change</th>\n";
15234 $TYPE_PROBLEMS .= "<th>Effect</th></tr>".$TYPE_REPORT."</table>\n";
15235 $TYPE_PROBLEMS .= $ShowVTables.$Affected."<br/><br/>".$ContentDivEnd."\n";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015236 if($NameSpace) {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040015237 $TYPE_PROBLEMS=~s/\b\Q$NameSpace\E::(\w|\~)/$1/g;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015238 }
15239 }
15240 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015241 $TYPE_PROBLEMS .= "<br/>";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015242 }
15243 }
15244 if($TYPE_PROBLEMS)
15245 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015246 $TYPE_PROBLEMS = insertIDs($TYPE_PROBLEMS);
15247 my $Title = "Problems with Data Types, $TargetSeverity Severity";
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015248 if($TargetSeverity eq "Safe")
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015249 { # Safe Changes
15250 $Title = "Other Changes in Data Types";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015251 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015252 $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 +040015253 }
15254 }
15255 return $TYPE_PROBLEMS;
15256}
15257
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015258sub get_Anchor($$$)
15259{
15260 my ($Kind, $Level, $Severity) = @_;
15261 if($JoinReport)
15262 {
15263 if($Severity eq "Safe") {
15264 return "Other_".$Level."_Changes_In_".$Kind."s";
15265 }
15266 else {
15267 return $Kind."_".$Level."_Problems_".$Severity;
15268 }
15269 }
15270 else
15271 {
15272 if($Severity eq "Safe") {
15273 return "Other_Changes_In_".$Kind."s";
15274 }
15275 else {
15276 return $Kind."_Problems_".$Severity;
15277 }
15278 }
15279}
15280
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015281sub showVTables($)
15282{
15283 my $TypeName = $_[0];
15284 my $TypeId1 = $TName_Tid{1}{$TypeName};
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040015285 my %Type1 = get_Type($TypeId1, 1);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015286 if(defined $Type1{"VTable"}
15287 and keys(%{$Type1{"VTable"}}))
15288 {
15289 my $TypeId2 = $TName_Tid{2}{$TypeName};
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040015290 my %Type2 = get_Type($TypeId2, 2);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015291 if(defined $Type2{"VTable"}
15292 and keys(%{$Type2{"VTable"}}))
15293 {
15294 my %Indexes = map {$_=>1} (keys(%{$Type1{"VTable"}}), keys(%{$Type2{"VTable"}}));
15295 my %Entries = ();
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015296 foreach my $Index (sort {int($a)<=>int($b)} (keys(%Indexes)))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015297 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015298 $Entries{$Index}{"E1"} = simpleVEntry($Type1{"VTable"}{$Index});
15299 $Entries{$Index}{"E2"} = simpleVEntry($Type2{"VTable"}{$Index});
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015300 }
15301 my $VTABLES = "";
15302 if($ReportFormat eq "xml")
15303 { # XML
15304 $VTABLES .= " <vtable>\n";
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015305 foreach my $Index (sort {int($a)<=>int($b)} (keys(%Entries)))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015306 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015307 $VTABLES .= " <entry offset=\"".$Index."\">\n";
Andrey Ponomarenko5c09ef32012-06-14 18:17:33 +040015308 $VTABLES .= " <old>".xmlSpecChars($Entries{$Index}{"E1"})."</old>\n";
15309 $VTABLES .= " <new>".xmlSpecChars($Entries{$Index}{"E2"})."</new>\n";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015310 $VTABLES .= " </entry>\n";
15311 }
15312 $VTABLES .= " </vtable>\n\n";
15313 }
15314 else
15315 { # HTML
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015316 $VTABLES .= "<table class='vtable'>";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015317 $VTABLES .= "<tr><th width='2%'>Offset</th>";
15318 $VTABLES .= "<th width='45%'>Virtual Table (Old) - ".(keys(%{$Type1{"VTable"}}))." entries</th>";
15319 $VTABLES .= "<th>Virtual Table (New) - ".(keys(%{$Type2{"VTable"}}))." entries</th></tr>";
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015320 foreach my $Index (sort {int($a)<=>int($b)} (keys(%Entries)))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015321 {
15322 my ($Color1, $Color2) = ("", "");
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015323 if($Entries{$Index}{"E1"} ne $Entries{$Index}{"E2"})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015324 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015325 if($Entries{$Index}{"E1"})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015326 {
Andrey Ponomarenko16934472012-03-29 15:37:04 +040015327 $Color1 = " class='failed'";
15328 $Color2 = " class='failed'";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015329 }
15330 else {
Andrey Ponomarenko16934472012-03-29 15:37:04 +040015331 $Color2 = " class='warning'";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015332 }
15333 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015334 $VTABLES .= "<tr><th>".$Index."</th>\n";
15335 $VTABLES .= "<td$Color1>".htmlSpecChars($Entries{$Index}{"E1"})."</td>\n";
15336 $VTABLES .= "<td$Color2>".htmlSpecChars($Entries{$Index}{"E2"})."</td></tr>\n";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015337 }
15338 $VTABLES .= "</table><br/>\n";
15339 $VTABLES = $ContentDivStart.$VTABLES.$ContentDivEnd;
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015340 $VTABLES = $ContentSpanStart_Info."[+] show v-table (old and new)".$ContentSpanEnd."<br/>\n".$VTABLES;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015341 }
15342 return $VTABLES;
15343 }
15344 }
15345 return "";
15346}
15347
15348sub simpleVEntry($)
15349{
15350 my $VEntry = $_[0];
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040015351 if(not defined $VEntry
15352 or $VEntry eq "") {
15353 return "";
15354 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015355 $VEntry=~s/\A(.+)::(_ZThn.+)\Z/$2/; # thunks
15356 $VEntry=~s/_ZTI\w+/typeinfo/g; # typeinfo
15357 if($VEntry=~/\A_ZThn.+\Z/) {
15358 $VEntry = "non-virtual thunk";
15359 }
15360 $VEntry=~s/\A\(int \(\*\)\(...\)\)([^\(\d])/$1/i;
15361 # support for old GCC versions
15362 $VEntry=~s/\A0u\Z/(int (*)(...))0/;
15363 $VEntry=~s/\A4294967268u\Z/(int (*)(...))-0x000000004/;
15364 $VEntry=~s/\A&_Z\Z/& _Z/;
15365 # templates
15366 if($VEntry=~s/ \[with (\w+) = (.+?)(, [^=]+ = .+|])\Z//g)
15367 { # std::basic_streambuf<_CharT, _Traits>::imbue [with _CharT = char, _Traits = std::char_traits<char>]
15368 # become std::basic_streambuf<char, ...>::imbue
15369 my ($Pname, $Pval) = ($1, $2);
15370 if($Pname eq "_CharT" and $VEntry=~/\Astd::/)
15371 { # stdc++ typedefs
15372 $VEntry=~s/<$Pname(, [^<>]+|)>/<$Pval>/g;
15373 # FIXME: simplify names using stdcxx typedefs (StdCxxTypedef)
15374 # The typedef info should be added to ABI dumps
15375 }
15376 else
15377 {
15378 $VEntry=~s/<$Pname>/<$Pval>/g;
15379 $VEntry=~s/<$Pname, [^<>]+>/<$Pval, ...>/g;
15380 }
15381 }
15382 $VEntry=~s/([^:]+)::\~([^:]+)\Z/~$1/; # destructors
15383 return $VEntry;
15384}
15385
Andrey Ponomarenko85043792012-05-14 16:48:07 +040015386sub getAffectedSymbols($$$$)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015387{
Andrey Ponomarenko85043792012-05-14 16:48:07 +040015388 my ($Level, $Target_TypeName, $Kinds_Locations, $Syms) = @_;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015389 my $LIMIT = 1000;
Andrey Ponomarenko85043792012-05-14 16:48:07 +040015390 if($#{$Syms}>=10000)
15391 { # reduce size of the report
15392 $LIMIT = 10;
15393 }
15394 my %SProblems = ();
15395 foreach my $Symbol (@{$Syms})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015396 {
Andrey Ponomarenko85043792012-05-14 16:48:07 +040015397 if(keys(%SProblems)>$LIMIT) {
15398 last;
15399 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015400 if(($Symbol=~/C2E|D2E|D0E/))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015401 { # duplicated problems for C2 constructors, D2 and D0 destructors
15402 next;
15403 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015404 my ($SN, $SS, $SV) = separate_symbol($Symbol);
15405 if($Level eq "Source")
15406 { # remove symbol version
15407 $Symbol=$SN;
15408 }
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040015409 my ($MinPath_Length, $ProblemLocation_Last) = (-1, "");
15410 my $Severity_Max = 0;
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015411 my $Signature = get_Signature($Symbol, 1);
15412 foreach my $Kind (keys(%{$CompatProblems{$Level}{$Symbol}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015413 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015414 foreach my $Location (keys(%{$CompatProblems{$Level}{$Symbol}{$Kind}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015415 {
15416 if(not defined $Kinds_Locations->{$Kind}
15417 or not $Kinds_Locations->{$Kind}{$Location}) {
15418 next;
15419 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015420 if($SV and defined $CompatProblems{$Level}{$SN}
15421 and defined $CompatProblems{$Level}{$SN}{$Kind}{$Location})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015422 { # duplicated problems for versioned symbols
15423 next;
15424 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015425 my $Type_Name = $CompatProblems{$Level}{$Symbol}{$Kind}{$Location}{"Type_Name"};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015426 next if($Type_Name ne $Target_TypeName);
15427
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015428 my $Position = $CompatProblems{$Level}{$Symbol}{$Kind}{$Location}{"Param_Pos"};
15429 my $Param_Name = $CompatProblems{$Level}{$Symbol}{$Kind}{$Location}{"Param_Name"};
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040015430 my $Severity = getProblemSeverity($Level, $Kind);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015431 my $Path_Length = 0;
15432 my $ProblemLocation = $Location;
15433 if($Type_Name) {
15434 $ProblemLocation=~s/->\Q$Type_Name\E\Z//g;
15435 }
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040015436 while($ProblemLocation=~/\-\>/g) {
15437 $Path_Length += 1;
15438 }
15439 if($MinPath_Length==-1 or ($Path_Length<=$MinPath_Length and $Severity_Val{$Severity}>$Severity_Max)
15440 or (cmp_locations($ProblemLocation, $ProblemLocation_Last) and $Severity_Val{$Severity}==$Severity_Max))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015441 {
15442 $MinPath_Length = $Path_Length;
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040015443 $Severity_Max = $Severity_Val{$Severity};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015444 $ProblemLocation_Last = $ProblemLocation;
Andrey Ponomarenko85043792012-05-14 16:48:07 +040015445 %{$SProblems{$Symbol}} = (
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040015446 "Descr"=>getAffectDescription($Level, $Symbol, $Kind, $Location),
15447 "Severity_Max"=>$Severity_Max,
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015448 "Signature"=>$Signature,
15449 "Position"=>$Position,
15450 "Param_Name"=>$Param_Name,
15451 "Location"=>$Location
15452 );
15453 }
15454 }
15455 }
15456 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +040015457 my @Symbols = keys(%SProblems);
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015458 @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 +040015459 @Symbols = sort {$SProblems{$b}{"Severity_Max"}<=>$SProblems{$a}{"Severity_Max"}} @Symbols;
15460 if($#Symbols+1>$LIMIT)
15461 { # remove last element
15462 pop(@Symbols);
15463 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015464 my $Affected = "";
15465 if($ReportFormat eq "xml")
15466 { # XML
15467 $Affected .= " <affected>\n";
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015468 foreach my $Symbol (@Symbols)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015469 {
Andrey Ponomarenko85043792012-05-14 16:48:07 +040015470 my $Param_Name = $SProblems{$Symbol}{"Param_Name"};
15471 my $Description = $SProblems{$Symbol}{"Descr"};
15472 my $Location = $SProblems{$Symbol}{"Location"};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015473 my $Target = "";
15474 if($Param_Name) {
15475 $Target = " affected=\"param\" param_name=\"$Param_Name\"";
15476 }
15477 elsif($Location=~/\Aretval(\-|\Z)/i) {
15478 $Target = " affected=\"retval\"";
15479 }
15480 elsif($Location=~/\Athis(\-|\Z)/i) {
15481 $Target = " affected=\"this\"";
15482 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015483 $Affected .= " <symbol$Target name=\"$Symbol\">\n";
Andrey Ponomarenko5c09ef32012-06-14 18:17:33 +040015484 $Affected .= " <comment>".xmlSpecChars($Description)."</comment>\n";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015485 $Affected .= " </symbol>\n";
15486 }
15487 $Affected .= " </affected>\n";
15488 }
15489 else
15490 { # HTML
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015491 foreach my $Symbol (@Symbols)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015492 {
Andrey Ponomarenko85043792012-05-14 16:48:07 +040015493 my $Description = $SProblems{$Symbol}{"Descr"};
15494 my $Signature = $SProblems{$Symbol}{"Signature"};
15495 my $Pos = $SProblems{$Symbol}{"Position"};
Andrey Ponomarenkoa01311b2012-06-08 17:20:02 +040015496 $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 +040015497 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +040015498 if(keys(%SProblems)>$LIMIT) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015499 $Affected .= "and others ...<br/>";
15500 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +040015501 $Affected = "<div class='affected'>".$Affected."</div>";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015502 if($Affected)
15503 {
15504 $Affected = $ContentDivStart.$Affected.$ContentDivEnd;
Andrey Ponomarenko85043792012-05-14 16:48:07 +040015505 $Affected = $ContentSpanStart_Affected."[+] affected symbols (".(keys(%SProblems)>$LIMIT?">".$LIMIT:keys(%SProblems)).")".$ContentSpanEnd.$Affected;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015506 }
15507 }
15508 return $Affected;
15509}
15510
15511sub cmp_locations($$)
15512{
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040015513 my ($L1, $L2) = @_;
15514 if($L2=~/\b(retval|this)\b/
15515 and $L1!~/\b(retval|this)\b/ and $L1!~/\-\>/) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015516 return 1;
15517 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040015518 if($L2=~/\b(retval|this)\b/ and $L2=~/\-\>/
15519 and $L1!~/\b(retval|this)\b/ and $L1=~/\-\>/) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015520 return 1;
15521 }
15522 return 0;
15523}
15524
15525sub getAffectDescription($$$$)
15526{
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015527 my ($Level, $Symbol, $Kind, $Location) = @_;
15528 my %Problem = %{$CompatProblems{$Level}{$Symbol}{$Kind}{$Location}};
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040015529 my $PPos = showPos($Problem{"Param_Pos"});
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015530 my @Sentence = ();
15531 $Location=~s/\A(.*)\-\>.+?\Z/$1/;
15532 if($Kind eq "Overridden_Virtual_Method"
15533 or $Kind eq "Overridden_Virtual_Method_B") {
15534 push(@Sentence, "The method '".$Problem{"New_Value"}."' will be called instead of this method.");
15535 }
15536 elsif($CompatRules{$Level}{$Kind}{"Kind"} eq "Types")
15537 {
15538 if($Location eq "this" or $Kind=~/(\A|_)Virtual(_|\Z)/)
15539 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015540 my $METHOD_TYPE = $CompleteSignature{1}{$Symbol}{"Constructor"}?"constructor":"method";
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040015541 my $ClassName = $TypeInfo{1}{$CompleteSignature{1}{$Symbol}{"Class"}}{"Name"};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015542 if($ClassName eq $Problem{"Type_Name"}) {
15543 push(@Sentence, "This $METHOD_TYPE is from \'".$Problem{"Type_Name"}."\' class.");
15544 }
15545 else {
15546 push(@Sentence, "This $METHOD_TYPE is from derived class \'".$ClassName."\'.");
15547 }
15548 }
15549 else
15550 {
15551 if($Location=~/retval/)
15552 { # return value
15553 if($Location=~/\-\>/) {
15554 push(@Sentence, "Field \'".$Location."\' in return value");
15555 }
15556 else {
15557 push(@Sentence, "Return value");
15558 }
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040015559 if(my $Init = $Problem{"InitialType_Type"})
15560 {
15561 if($Init eq "Pointer") {
15562 push(@Sentence, "(pointer)");
15563 }
15564 elsif($Init eq "Ref") {
15565 push(@Sentence, "(reference)");
15566 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015567 }
15568 }
15569 elsif($Location=~/this/)
15570 { # "this" pointer
15571 if($Location=~/\-\>/) {
15572 push(@Sentence, "Field \'".$Location."\' in the object of this method");
15573 }
15574 else {
15575 push(@Sentence, "\'this\' pointer");
15576 }
15577 }
15578 else
15579 { # parameters
15580 if($Location=~/\-\>/) {
15581 push(@Sentence, "Field \'".$Location."\' in $PPos parameter");
15582 }
15583 else {
15584 push(@Sentence, "$PPos parameter");
15585 }
15586 if($Problem{"Param_Name"}) {
15587 push(@Sentence, "\'".$Problem{"Param_Name"}."\'");
15588 }
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040015589 if(my $Init = $Problem{"InitialType_Type"})
15590 {
15591 if($Init eq "Pointer") {
15592 push(@Sentence, "(pointer)");
15593 }
15594 elsif($Init eq "Ref") {
15595 push(@Sentence, "(reference)");
15596 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015597 }
15598 }
15599 if($Location eq "this") {
15600 push(@Sentence, "has base type \'".$Problem{"Type_Name"}."\'.");
15601 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040015602 elsif(defined $Problem{"Start_Type_Name"}
15603 and $Problem{"Start_Type_Name"} eq $Problem{"Type_Name"}) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015604 push(@Sentence, "has type \'".$Problem{"Type_Name"}."\'.");
15605 }
15606 else {
15607 push(@Sentence, "has base type \'".$Problem{"Type_Name"}."\'.");
15608 }
15609 }
15610 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040015611 if($ExtendedSymbols{$Symbol}) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015612 push(@Sentence, " This is a symbol from an artificial external library that may use the \'$TargetLibraryName\' library and change its ABI after recompiling.");
15613 }
15614 return join(" ", @Sentence);
15615}
15616
15617sub get_XmlSign($$)
15618{
15619 my ($Symbol, $LibVersion) = @_;
15620 my $Info = $CompleteSignature{$LibVersion}{$Symbol};
15621 my $Report = "";
15622 foreach my $Pos (sort {int($a)<=>int($b)} keys(%{$Info->{"Param"}}))
15623 {
15624 my $Name = $Info->{"Param"}{$Pos}{"name"};
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040015625 my $Type = $Info->{"Param"}{$Pos}{"type"};
15626 my $TypeName = $TypeInfo{$LibVersion}{$Type}{"Name"};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015627 foreach my $Typedef (keys(%ChangedTypedef))
15628 {
15629 my $Base = $Typedef_BaseName{$LibVersion}{$Typedef};
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040015630 $TypeName=~s/\b\Q$Typedef\E\b/$Base/g;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015631 }
15632 $Report .= " <param pos=\"$Pos\">\n";
15633 $Report .= " <name>".$Name."</name>\n";
Andrey Ponomarenko5c09ef32012-06-14 18:17:33 +040015634 $Report .= " <type>".xmlSpecChars($TypeName)."</type>\n";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015635 $Report .= " </param>\n";
15636 }
15637 if(my $Return = $Info->{"Return"})
15638 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040015639 my $RTName = $TypeInfo{$LibVersion}{$Return}{"Name"};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015640 $Report .= " <retval>\n";
Andrey Ponomarenko5c09ef32012-06-14 18:17:33 +040015641 $Report .= " <type>".xmlSpecChars($RTName)."</type>\n";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015642 $Report .= " </retval>\n";
15643 }
15644 return $Report;
15645}
15646
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015647sub get_Report_SymbolsInfo($)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015648{
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015649 my $Level = $_[0];
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015650 my $Report = "<symbols_info>\n";
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015651 foreach my $Symbol (sort keys(%{$CompatProblems{$Level}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015652 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015653 my ($SN, $SS, $SV) = separate_symbol($Symbol);
15654 if($SV and defined $CompatProblems{$Level}{$SN}) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015655 next;
15656 }
15657 $Report .= " <symbol name=\"$Symbol\">\n";
15658 my ($S1, $P1, $S2, $P2) = ();
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015659 if(not $AddedInt{$Level}{$Symbol})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015660 {
15661 if(defined $CompleteSignature{1}{$Symbol}
15662 and defined $CompleteSignature{1}{$Symbol}{"Header"})
15663 {
15664 $P1 = get_XmlSign($Symbol, 1);
15665 $S1 = get_Signature($Symbol, 1);
15666 }
15667 elsif($Symbol=~/\A(_Z|\?)/) {
15668 $S1 = $tr_name{$Symbol};
15669 }
15670 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015671 if(not $RemovedInt{$Level}{$Symbol})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015672 {
15673 if(defined $CompleteSignature{2}{$Symbol}
15674 and defined $CompleteSignature{2}{$Symbol}{"Header"})
15675 {
15676 $P2 = get_XmlSign($Symbol, 2);
15677 $S2 = get_Signature($Symbol, 2);
15678 }
15679 elsif($Symbol=~/\A(_Z|\?)/) {
15680 $S2 = $tr_name{$Symbol};
15681 }
15682 }
15683 if($S1)
15684 {
Andrey Ponomarenko5c09ef32012-06-14 18:17:33 +040015685 $Report .= " <old signature=\"".xmlSpecChars($S1)."\">\n";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015686 $Report .= $P1;
15687 $Report .= " </old>\n";
15688 }
15689 if($S2 and $S2 ne $S1)
15690 {
Andrey Ponomarenko5c09ef32012-06-14 18:17:33 +040015691 $Report .= " <new signature=\"".xmlSpecChars($S2)."\">\n";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015692 $Report .= $P2;
15693 $Report .= " </new>\n";
15694 }
15695 $Report .= " </symbol>\n";
15696 }
15697 $Report .= "</symbols_info>\n";
15698 return $Report;
15699}
15700
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015701sub writeReport($$)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015702{
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015703 my ($Level, $Report) = @_;
15704 if($ReportFormat eq "xml") {
15705 $Report = "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n".$Report;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015706 }
15707 if($StdOut)
15708 { # --stdout option
15709 print STDOUT $Report;
15710 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015711 else
15712 {
15713 my $RPath = getReportPath($Level);
Andrey Ponomarenko85043792012-05-14 16:48:07 +040015714 mkpath(get_dirname($RPath));
15715
15716 open(REPORT, ">", $RPath) || die ("can't open file \'$RPath\': $!\n");
15717 print REPORT $Report;
15718 close(REPORT);
15719
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040015720 if($Browse or $OpenReport)
15721 { # open in browser
15722 openReport($RPath);
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015723 if($JoinReport or $DoubleReport)
15724 {
15725 if($Level eq "Binary")
15726 { # wait to open a browser
15727 sleep(1);
15728 }
15729 }
15730 }
15731 }
15732}
15733
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040015734sub openReport($)
15735{
15736 my $Path = $_[0];
15737 my $Cmd = "";
15738 if($Browse)
15739 { # user-defined browser
Andrey Ponomarenkoa01311b2012-06-08 17:20:02 +040015740 $Cmd = $Browse." \"$Path\"";
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040015741 }
15742 if(not $Cmd)
15743 { # default browser
15744 if($OSgroup eq "macos") {
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +040015745 $Cmd = "open \"$Path\"";
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040015746 }
15747 elsif($OSgroup eq "windows") {
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +040015748 $Cmd = "start ".path_format($Path, $OSgroup);
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040015749 }
15750 else
15751 { # linux, freebsd, solaris
15752 my @Browsers = (
15753 "x-www-browser",
15754 "sensible-browser",
15755 "firefox",
15756 "opera",
15757 "xdg-open",
15758 "lynx",
15759 "links"
15760 );
15761 foreach my $Br (@Browsers)
15762 {
15763 if($Br = get_CmdPath($Br))
15764 {
Andrey Ponomarenkoa01311b2012-06-08 17:20:02 +040015765 $Cmd = $Br." \"$Path\"";
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040015766 last;
15767 }
15768 }
15769 }
15770 }
15771 if($Cmd)
15772 {
15773 if($Debug) {
15774 printMsg("INFO", "running $Cmd");
15775 }
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +040015776 if($OSgroup ne "windows"
15777 and $OSgroup ne "macos")
15778 {
15779 if($Cmd!~/lynx|links/) {
15780 $Cmd .= " >\"$TMP_DIR/null\" 2>&1 &";
15781 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040015782 }
15783 system($Cmd);
15784 }
15785 else {
15786 printMsg("ERROR", "cannot open report in browser");
15787 }
15788}
15789
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015790sub getReport($)
15791{
15792 my $Level = $_[0];
15793 if($ReportFormat eq "xml")
15794 { # XML
15795
15796 if($Level eq "Join")
15797 {
15798 my $Report = "<reports>\n";
15799 $Report .= getReport("Binary");
15800 $Report .= getReport("Source");
15801 $Report .= "</reports>\n";
15802 return $Report;
15803 }
15804 else
15805 {
15806 my $Report = "<report kind=\"".lc($Level)."\" version=\"$XML_REPORT_VERSION\">\n\n";
15807 my ($Summary, $MetaData) = get_Summary($Level);
15808 $Report .= $Summary."\n";
15809 $Report .= get_Report_Added($Level).get_Report_Removed($Level);
15810 $Report .= get_Report_Problems("High", $Level).get_Report_Problems("Medium", $Level).get_Report_Problems("Low", $Level).get_Report_Problems("Safe", $Level);
15811 $Report .= get_Report_SymbolsInfo($Level);
15812 $Report .= "</report>\n";
15813 return $Report;
15814 }
15815 }
15816 else
15817 { # HTML
15818 my $CssStyles = readModule("Styles", "Report.css");
15819 my $JScripts = readModule("Scripts", "Sections.js");
15820 if($Level eq "Join")
15821 {
15822 $CssStyles .= "\n".readModule("Styles", "Tabs.css");
15823 $JScripts .= "\n".readModule("Scripts", "Tabs.js");
Andrey Ponomarenkob8d203d2012-05-25 18:11:07 +040015824 my $Title = $TargetLibraryFName.": ".$Descriptor{1}{"Version"}." to ".$Descriptor{2}{"Version"}." compatibility report";
15825 my $Keywords = $TargetLibraryFName.", compatibility, API, report";
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015826 my $Description = "Compatibility report for the $TargetLibraryFName $TargetComponent between ".$Descriptor{1}{"Version"}." and ".$Descriptor{2}{"Version"}." versions";
15827 my ($BSummary, $BMetaData) = get_Summary("Binary");
15828 my ($SSummary, $SMetaData) = get_Summary("Source");
15829 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>";
15830 $Report .= get_Report_Header("Join")."
15831 <br/><div class='tabset'>
Andrey Ponomarenko16934472012-03-29 15:37:04 +040015832 <a id='BinaryID' href='#BinaryTab' class='tab active'>Binary<br/>Compatibility</a>
15833 <a id='SourceID' href='#SourceTab' style='margin-left:3px' class='tab disabled'>Source<br/>Compatibility</a>
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015834 </div>";
15835 $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>";
15836 $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 +040015837 $Report .= getReportFooter($TargetLibraryFName, not $JoinReport);
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015838 $Report .= "\n<div style='height:999px;'></div>\n</body></html>";
15839 return $Report;
15840 }
15841 else
15842 {
15843 my ($Summary, $MetaData) = get_Summary($Level);
Andrey Ponomarenkob8d203d2012-05-25 18:11:07 +040015844 my $Title = $TargetLibraryFName.": ".$Descriptor{1}{"Version"}." to ".$Descriptor{2}{"Version"}." ".lc($Level)." compatibility report";
15845 my $Keywords = $TargetLibraryFName.", ".lc($Level)." compatibility, API, report";
15846 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 +040015847 if($Level eq "Binary")
15848 {
15849 if(getArch(1) eq getArch(2)
15850 and getArch(1) ne "unknown") {
15851 $Description .= " on ".showArch(getArch(1));
15852 }
15853 }
15854 my $Report = "<!-\- $MetaData -\->\n".composeHTML_Head($Title, $Keywords, $Description, $CssStyles, $JScripts)."\n<body>\n<div><a name='Top'></a>\n";
15855 $Report .= get_Report_Header($Level)."\n".$Summary."\n";
15856 $Report .= get_Report_Added($Level).get_Report_Removed($Level);
15857 $Report .= get_Report_Problems("High", $Level).get_Report_Problems("Medium", $Level).get_Report_Problems("Low", $Level).get_Report_Problems("Safe", $Level);
15858 $Report .= get_SourceInfo();
15859 $Report .= "</div>\n<br/><br/><br/><hr/>\n";
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040015860 $Report .= getReportFooter($TargetLibraryFName, not $JoinReport);
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015861 $Report .= "\n<div style='height:999px;'></div>\n</body></html>";
15862 return $Report;
15863 }
15864 }
15865}
15866
Andrey Ponomarenko16934472012-03-29 15:37:04 +040015867sub getLegend()
15868{
15869 return "<br/>
15870<table class='summary'>
15871<tr>
15872 <td class='new'>added</td>
15873 <td class='passed'>compatible</td>
15874</tr>
15875<tr>
15876 <td class='warning'>warning</td>
15877 <td class='failed'>incompatible</td>
15878</tr></table>\n";
15879}
15880
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015881sub createReport()
15882{
15883 if($JoinReport)
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040015884 { # --stdout
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015885 writeReport("Join", getReport("Join"));
15886 }
15887 elsif($DoubleReport)
15888 { # default
15889 writeReport("Binary", getReport("Binary"));
15890 writeReport("Source", getReport("Source"));
15891 }
15892 elsif($BinaryOnly)
15893 { # --binary
15894 writeReport("Binary", getReport("Binary"));
15895 }
15896 elsif($SourceOnly)
15897 { # --source
15898 writeReport("Source", getReport("Source"));
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015899 }
15900}
15901
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040015902sub getReportFooter($$)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015903{
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040015904 my ($LibName, $Wide) = @_;
15905 my $FooterStyle = $Wide?"width:99%":"width:97%;padding-top:3px";
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015906 my $Footer = "<div style='$FooterStyle;font-size:11px;' align='right'><i>Generated on ".(localtime time); # report date
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015907 $Footer .= " for <span style='font-weight:bold'>$LibName</span>"; # tested library/system name
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015908 $Footer .= " by <a href='".$HomePage{"Wiki"}."'>ABI Compliance Checker</a>"; # tool name
15909 my $ToolSummary = "<br/>A tool for checking backward compatibility of a C/C++ library API&#160;&#160;";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015910 $Footer .= " $TOOL_VERSION &#160;$ToolSummary</i></div>"; # tool version
15911 return $Footer;
15912}
15913
15914sub get_Report_Problems($$)
15915{
15916 my ($Priority, $Level) = @_;
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040015917 my $Report = get_Report_TypeProblems($Priority, $Level);
Andrey Ponomarenko16934472012-03-29 15:37:04 +040015918 if(my $SProblems = get_Report_SymbolProblems($Priority, $Level)) {
15919 $Report .= $SProblems;
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040015920 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015921 if($Priority eq "Low")
15922 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015923 $Report .= get_Report_ChangedConstants($Level);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015924 if($ReportFormat eq "html") {
15925 if($CheckImpl and $Level eq "Binary") {
15926 $Report .= get_Report_Impl();
15927 }
15928 }
15929 }
15930 if($ReportFormat eq "html")
15931 {
15932 if($Report)
15933 { # add anchor
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015934 if($JoinReport)
15935 {
15936 if($Priority eq "Safe") {
15937 $Report = "<a name=\'Other_".$Level."_Changes\'></a>".$Report;
15938 }
15939 else {
15940 $Report = "<a name=\'".$Priority."_Risk_".$Level."_Problems\'></a>".$Report;
15941 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015942 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015943 else
15944 {
15945 if($Priority eq "Safe") {
15946 $Report = "<a name=\'Other_Changes\'></a>".$Report;
15947 }
15948 else {
15949 $Report = "<a name=\'".$Priority."_Risk_Problems\'></a>".$Report;
15950 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015951 }
15952 }
15953 }
15954 return $Report;
15955}
15956
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015957sub composeHTML_Head($$$$$)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015958{
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015959 my ($Title, $Keywords, $Description, $Styles, $Scripts) = @_;
15960 return "<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.0 Transitional//EN\" \"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd\">
15961 <html xmlns=\"http://www.w3.org/1999/xhtml\" xml:lang=\"en\" lang=\"en\">
15962 <head>
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015963 <meta http-equiv=\"Content-Type\" content=\"text/html; charset=utf-8\" />
15964 <meta name=\"keywords\" content=\"$Keywords\" />
15965 <meta name=\"description\" content=\"$Description\" />
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015966 <title>
15967 $Title
15968 </title>
15969 <style type=\"text/css\">
15970 $Styles
15971 </style>
15972 <script type=\"text/javascript\" language=\"JavaScript\">
15973 <!--
15974 $Scripts
15975 -->
15976 </script>
15977 </head>";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015978}
15979
15980sub insertIDs($)
15981{
15982 my $Text = $_[0];
15983 while($Text=~/CONTENT_ID/)
15984 {
15985 if(int($Content_Counter)%2) {
15986 $ContentID -= 1;
15987 }
15988 $Text=~s/CONTENT_ID/c_$ContentID/;
15989 $ContentID += 1;
15990 $Content_Counter += 1;
15991 }
15992 return $Text;
15993}
15994
15995sub checkPreprocessedUnit($)
15996{
15997 my $Path = $_[0];
Andrey Ponomarenkoa01311b2012-06-08 17:20:02 +040015998 my ($CurHeader, $CurHeaderName) = ("", "");
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015999 open(PREPROC, $Path) || die ("can't open file \'$Path\': $!\n");
Andrey Ponomarenkoa01311b2012-06-08 17:20:02 +040016000 while(my $Line = <PREPROC>)
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040016001 { # detecting public and private constants
Andrey Ponomarenkoa01311b2012-06-08 17:20:02 +040016002
16003 if(substr($Line, 0, 1) eq "#")
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040016004 {
Andrey Ponomarenkoa01311b2012-06-08 17:20:02 +040016005 chomp($Line);
16006 if($Line=~/\A\#\s+\d+\s+\"(.+)\"/)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040016007 {
Andrey Ponomarenkoa01311b2012-06-08 17:20:02 +040016008 $CurHeader = path_format($1, $OSgroup);
16009 $CurHeaderName = get_filename($CurHeader);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040016010 }
Andrey Ponomarenkoa01311b2012-06-08 17:20:02 +040016011 if(not $Include_Neighbors{$Version}{$CurHeaderName}
16012 and not $Registered_Headers{$Version}{$CurHeader})
16013 { # not a target
16014 next;
16015 }
16016 if(not is_target_header($CurHeaderName, 1)
16017 and not is_target_header($CurHeaderName, 2))
16018 { # user-defined header
16019 next;
16020 }
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040016021 if($Line=~/\A\#\s*define\s+(\w+)\s+(.+)\s*\Z/)
Andrey Ponomarenkoa01311b2012-06-08 17:20:02 +040016022 {
16023 my ($Name, $Value) = ($1, $2);
16024 if(not $Constants{$Version}{$Name}{"Access"})
16025 {
16026 $Constants{$Version}{$Name}{"Access"} = "public";
16027 $Constants{$Version}{$Name}{"Value"} = $Value;
16028 $Constants{$Version}{$Name}{"Header"} = $CurHeaderName;
16029 }
16030 }
16031 elsif($Line=~/\A\#[ \t]*undef[ \t]+([_A-Z]+)[ \t]*/) {
16032 $Constants{$Version}{$1}{"Access"} = "private";
16033 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040016034 }
16035 }
16036 close(PREPROC);
16037 foreach my $Constant (keys(%{$Constants{$Version}}))
16038 {
Andrey Ponomarenkoa01311b2012-06-08 17:20:02 +040016039 if($Constants{$Version}{$Constant}{"Access"} eq "private"
16040 or $Constant=~/_h\Z/i
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040016041 or isBuiltIn($Constants{$Version}{$Constant}{"Header"}))
16042 { # skip private constants
16043 delete($Constants{$Version}{$Constant});
16044 }
16045 else {
16046 delete($Constants{$Version}{$Constant}{"Access"});
16047 }
16048 }
Andrey Ponomarenkoa01311b2012-06-08 17:20:02 +040016049 if($Debug)
16050 {
16051 mkpath($DEBUG_PATH{$Version});
16052 copy($Path, $DEBUG_PATH{$Version}."/preprocessor.txt");
16053 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040016054}
16055
Andrey Ponomarenko16934472012-03-29 15:37:04 +040016056sub uncoverConstant($$)
16057{
16058 my ($LibVersion, $Constant) = @_;
16059 return "" if(not $LibVersion or not $Constant);
16060 return $Constant if(isCyclical(\@RecurConstant, $Constant));
16061 if(defined $Cache{"uncoverConstant"}{$LibVersion}{$Constant}) {
16062 return $Cache{"uncoverConstant"}{$LibVersion}{$Constant};
16063 }
16064 my $Value = $Constants{$LibVersion}{$Constant}{"Value"};
16065 if(defined $Value)
16066 {
16067 if($Value=~/\A[A-Z0-9_]+\Z/ and $Value=~/[A-Z]/)
16068 {
16069 push(@RecurConstant, $Constant);
16070 my $Uncovered = uncoverConstant($LibVersion, $Value);
16071 if($Uncovered ne "") {
16072 $Value = $Uncovered;
16073 }
16074 pop(@RecurConstant);
16075 }
16076 # FIXME: uncover $Value using all the enum constants
16077 # USECASE: change of define NC_LONG from NC_INT (enum value) to NC_INT (define)
16078 return ($Cache{"uncoverConstant"}{$LibVersion}{$Constant} = $Value);
16079 }
16080 return ($Cache{"uncoverConstant"}{$LibVersion}{$Constant} = "");
16081}
16082
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040016083my %IgnoreConstant = map {$_=>1} (
16084 "VERSION",
16085 "VERSIONCODE",
16086 "VERNUM",
16087 "VERS_INFO",
16088 "PATCHLEVEL",
16089 "INSTALLPREFIX",
16090 "VBUILD",
16091 "VPATCH",
16092 "VMINOR",
16093 "BUILD_STRING",
16094 "BUILD_TIME",
16095 "PACKAGE_STRING",
16096 "PRODUCTION",
16097 "CONFIGURE_COMMAND",
16098 "INSTALLDIR",
16099 "BINDIR",
16100 "CONFIG_FILE_PATH",
16101 "DATADIR",
16102 "EXTENSION_DIR",
16103 "INCLUDE_PATH",
16104 "LIBDIR",
16105 "LOCALSTATEDIR",
16106 "SBINDIR",
16107 "SYSCONFDIR",
16108 "RELEASE",
16109 "SOURCE_ID",
16110 "SUBMINOR",
16111 "MINOR",
16112 "MINNOR",
16113 "MINORVERSION",
16114 "MAJOR",
16115 "MAJORVERSION",
16116 "MICRO",
16117 "MICROVERSION",
16118 "BINARY_AGE",
16119 "INTERFACE_AGE",
16120 "CORE_ABI",
16121 "PATCH",
16122 "COPYRIGHT",
16123 "TIMESTAMP",
16124 "REVISION",
16125 "PACKAGE_TAG",
16126 "PACKAGEDATE",
16127 "NUMVERSION",
16128 "Release",
16129 "Version"
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040016130);
16131
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040016132sub mergeConstants($)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040016133{
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040016134 my $Level = $_[0];
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040016135 foreach my $Constant (keys(%{$Constants{1}}))
16136 {
16137 if($SkipConstants{1}{$Constant})
16138 { # skipped by the user
16139 next;
16140 }
Andrey Ponomarenko16934472012-03-29 15:37:04 +040016141 if(not defined $Constants{2}{$Constant}{"Value"}
16142 or $Constants{2}{$Constant}{"Value"} eq "")
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040016143 { # empty value
16144 next;
16145 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +040016146 my $Header = $Constants{1}{$Constant}{"Header"};
16147 if(not is_target_header($Header, 1)
16148 and not is_target_header($Header, 2))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040016149 { # user-defined header
16150 next;
16151 }
16152 my ($Old_Value, $New_Value, $Old_Value_Pure, $New_Value_Pure);
Andrey Ponomarenko16934472012-03-29 15:37:04 +040016153 $Old_Value = $Old_Value_Pure = uncoverConstant(1, $Constant);
16154 $New_Value = $New_Value_Pure = uncoverConstant(2, $Constant);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040016155 $Old_Value_Pure=~s/(\W)\s+/$1/g;
16156 $Old_Value_Pure=~s/\s+(\W)/$1/g;
16157 $New_Value_Pure=~s/(\W)\s+/$1/g;
16158 $New_Value_Pure=~s/\s+(\W)/$1/g;
16159 next if($New_Value_Pure eq "" or $Old_Value_Pure eq "");
16160 if($New_Value_Pure ne $Old_Value_Pure)
16161 { # different values
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040016162 if($Level eq "Binary")
16163 {
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040016164 foreach (keys(%IgnoreConstant))
16165 {
16166 if($Constant=~/(\A|_)$_(_|\Z)/)
16167 { # ignore library version
16168 next;
16169 }
16170 if(/\A[A-Z].*[a-z]\Z/)
16171 {
16172 if($Constant=~/(\A|[a-z])$_([A-Z]|\Z)/)
16173 { # ignore library version
16174 next;
16175 }
16176 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040016177 }
16178 if($Constant=~/(\A|_)(lib|open|)$TargetLibraryShortName(_|)(VERSION|VER|DATE|API|PREFIX)(_|\Z)/i)
16179 { # ignore library version
16180 next;
16181 }
16182 if($Old_Value=~/\A('|"|)[\/\\]\w+([\/\\]|:|('|"|)\Z)/ or $Old_Value=~/[\/\\]\w+[\/\\]\w+/)
16183 { # ignoring path defines:
Andrey Ponomarenko85043792012-05-14 16:48:07 +040016184 # /lib64:/usr/lib64:/lib:/usr/lib:/usr/X11R6/lib/Xaw3d ...
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040016185 next;
16186 }
16187 if($Old_Value=~/\A\(*[a-z_]+(\s+|\|)/i)
16188 { # ignore source defines:
Andrey Ponomarenko85043792012-05-14 16:48:07 +040016189 # static int gcry_pth_init ( void) { return ...
16190 # (RE_BACKSLASH_ESCAPE_IN_LISTS | RE...
16191 next;
16192 }
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040016193 if($Old_Value=~/\(/i and $Old_Value!~/\A[\"\']/i)
Andrey Ponomarenko85043792012-05-14 16:48:07 +040016194 { # ignore source defines:
16195 # foo(p)
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040016196 next;
16197 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040016198 }
16199 if(convert_integer($Old_Value) eq convert_integer($New_Value))
16200 { # 0x0001 and 0x1, 0x1 and 1 equal constants
16201 next;
16202 }
16203 if($Old_Value eq "0" and $New_Value eq "NULL")
16204 { # 0 => NULL
16205 next;
16206 }
16207 if($Old_Value eq "NULL" and $New_Value eq "0")
16208 { # NULL => 0
16209 next;
16210 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040016211 %{$ProblemsWithConstants{$Level}{$Constant}} = (
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040016212 "Target"=>$Constant,
16213 "Old_Value"=>$Old_Value,
16214 "New_Value"=>$New_Value );
16215 }
16216 }
16217}
16218
16219sub convert_integer($)
16220{
16221 my $Value = $_[0];
16222 if($Value=~/\A0x[a-f0-9]+\Z/)
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040016223 { # hexadecimal
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040016224 return hex($Value);
16225 }
16226 elsif($Value=~/\A0[0-7]+\Z/)
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040016227 { # octal
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040016228 return oct($Value);
16229 }
16230 elsif($Value=~/\A0b[0-1]+\Z/)
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040016231 { # binary
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040016232 return oct($Value);
16233 }
16234 else {
16235 return $Value;
16236 }
16237}
16238
Andrey Ponomarenko16934472012-03-29 15:37:04 +040016239sub readSymbols($)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040016240{
16241 my $LibVersion = $_[0];
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040016242 my @LibPaths = getSOPaths($LibVersion);
Andrey Ponomarenko16934472012-03-29 15:37:04 +040016243 if($#LibPaths==-1 and not $CheckHeadersOnly)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040016244 {
16245 if($LibVersion==1)
16246 {
16247 printMsg("WARNING", "checking headers only");
16248 $CheckHeadersOnly = 1;
16249 }
16250 else {
16251 exitStatus("Error", "$SLIB_TYPE libraries are not found in ".$Descriptor{$LibVersion}{"Version"});
16252 }
16253 }
Andrey Ponomarenko16934472012-03-29 15:37:04 +040016254 foreach my $LibPath (sort {length($a)<=>length($b)} @LibPaths) {
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040016255 readSymbols_Lib($LibVersion, $LibPath, 0, "+Weak", 1, 1);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040016256 }
Andrey Ponomarenko16934472012-03-29 15:37:04 +040016257 if(not $CheckHeadersOnly)
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040016258 {
Andrey Ponomarenko16934472012-03-29 15:37:04 +040016259 if($#LibPaths!=-1)
16260 {
16261 if(not keys(%{$Symbol_Library{$LibVersion}}))
16262 {
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040016263 printMsg("WARNING", "the set of public symbols in library(ies) is empty ($LibVersion)");
Andrey Ponomarenko16934472012-03-29 15:37:04 +040016264 printMsg("WARNING", "checking headers only");
16265 $CheckHeadersOnly = 1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040016266 }
16267 }
16268 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +040016269
16270 # clean memory
16271 %SystemObjects = ();
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040016272}
16273
Andrey Ponomarenko16934472012-03-29 15:37:04 +040016274sub getSymbolSize($$)
16275{ # size from the shared library
16276 my ($Symbol, $LibVersion) = @_;
16277 return 0 if(not $Symbol);
16278 if(defined $Symbol_Library{$LibVersion}{$Symbol}
16279 and my $LibName = $Symbol_Library{$LibVersion}{$Symbol})
16280 {
16281 if(defined $Library_Symbol{$LibVersion}{$LibName}{$Symbol}
16282 and my $Size = $Library_Symbol{$LibVersion}{$LibName}{$Symbol})
16283 {
16284 if($Size<0) {
16285 return -$Size;
16286 }
16287 }
16288 }
16289 return 0;
16290}
16291
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040016292sub canonifyName($)
16293{ # make TIFFStreamOpen(char const*, std::basic_ostream<char, std::char_traits<char> >*)
16294 # to be TIFFStreamOpen(char const*, std::basic_ostream<char>*)
16295 my $Name = $_[0];
16296 my $Rem = "std::(allocator|less|char_traits|regex_traits)";
Andrey Ponomarenko85043792012-05-14 16:48:07 +040016297 while($Name=~/([^<>,]+),\s*$Rem<([^<>,]+)>\s*/ and $1 eq $3)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040016298 {
Andrey Ponomarenko85043792012-05-14 16:48:07 +040016299 my $P = $1;
16300 $Name=~s/\Q$P\E,\s*$Rem<\Q$P\E>\s*/$P/g;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040016301 }
16302 return $Name;
16303}
16304
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040016305sub translateSymbols(@)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040016306{
16307 my $LibVersion = pop(@_);
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040016308 my (@MnglNames1, @MnglNames2, @UnmangledNames) = ();
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040016309 foreach my $Symbol (sort @_)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040016310 {
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040016311 if(index($Symbol, "_Z")==0)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040016312 {
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040016313 next if($tr_name{$Symbol});
16314 $Symbol=~s/[\@\$]+(.*)\Z//;
16315 push(@MnglNames1, $Symbol);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040016316 }
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040016317 elsif(index($Symbol, "?")==0) {
16318 push(@MnglNames2, $Symbol);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040016319 }
16320 else
16321 { # not mangled
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040016322 $tr_name{$Symbol} = $Symbol;
16323 $mangled_name_gcc{$Symbol} = $Symbol;
16324 $mangled_name{$LibVersion}{$Symbol} = $Symbol;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040016325 }
16326 }
16327 if($#MnglNames1 > -1)
16328 { # GCC names
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040016329 @UnmangledNames = reverse(unmangleArray(@MnglNames1));
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040016330 foreach my $MnglName (@MnglNames1)
16331 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040016332 if(my $Unmangled = pop(@UnmangledNames))
16333 {
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040016334 $tr_name{$MnglName} = formatName(canonifyName($Unmangled), "S");
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040016335 if(not $mangled_name_gcc{$tr_name{$MnglName}}) {
16336 $mangled_name_gcc{$tr_name{$MnglName}} = $MnglName;
16337 }
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040016338 if(index($MnglName, "_ZTV")==0
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040016339 and $tr_name{$MnglName}=~/vtable for (.+)/)
16340 { # bind class name and v-table symbol
16341 my $ClassName = $1;
16342 $ClassVTable{$ClassName} = $MnglName;
16343 $VTableClass{$MnglName} = $ClassName;
16344 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040016345 }
16346 }
16347 }
16348 if($#MnglNames2 > -1)
16349 { # MSVC names
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040016350 @UnmangledNames = reverse(unmangleArray(@MnglNames2));
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040016351 foreach my $MnglName (@MnglNames2)
16352 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040016353 if(my $Unmangled = pop(@UnmangledNames))
16354 {
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040016355 $tr_name{$MnglName} = formatName($Unmangled, "S");
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040016356 $mangled_name{$LibVersion}{$tr_name{$MnglName}} = $MnglName;
16357 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040016358 }
16359 }
16360 return \%tr_name;
16361}
16362
16363sub link_symbol($$$)
16364{
16365 my ($Symbol, $RunWith, $Deps) = @_;
16366 if(link_symbol_internal($Symbol, $RunWith, \%Symbol_Library)) {
16367 return 1;
16368 }
16369 if($Deps eq "+Deps")
16370 { # check the dependencies
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040016371 if(link_symbol_internal($Symbol, $RunWith, \%DepSymbol_Library)) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040016372 return 1;
16373 }
16374 }
16375 return 0;
16376}
16377
16378sub link_symbol_internal($$$)
16379{
16380 my ($Symbol, $RunWith, $Where) = @_;
16381 return 0 if(not $Where or not $Symbol);
16382 if($Where->{$RunWith}{$Symbol})
16383 { # the exact match by symbol name
16384 return 1;
16385 }
16386 if(my $VSym = $SymVer{$RunWith}{$Symbol})
16387 { # indirect symbol version, i.e.
16388 # foo_old and its symlink foo@v (or foo@@v)
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040016389 # foo_old may be in symtab table
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040016390 if($Where->{$RunWith}{$VSym}) {
16391 return 1;
16392 }
16393 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040016394 my ($Sym, $Spec, $Ver) = separate_symbol($Symbol);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040016395 if($Sym and $Ver)
16396 { # search for the symbol with the same version
16397 # or without version
16398 if($Where->{$RunWith}{$Sym})
16399 { # old: foo@v|foo@@v
16400 # new: foo
16401 return 1;
16402 }
16403 if($Where->{$RunWith}{$Sym."\@".$Ver})
16404 { # old: foo|foo@@v
16405 # new: foo@v
16406 return 1;
16407 }
16408 if($Where->{$RunWith}{$Sym."\@\@".$Ver})
16409 { # old: foo|foo@v
16410 # new: foo@@v
16411 return 1;
16412 }
16413 }
16414 return 0;
16415}
16416
Andrey Ponomarenko16934472012-03-29 15:37:04 +040016417sub readSymbols_App($)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040016418{
16419 my $Path = $_[0];
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040016420 return () if(not $Path);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040016421 my @Imported = ();
16422 if($OSgroup eq "macos")
16423 {
16424 my $OtoolCmd = get_CmdPath("otool");
16425 if(not $OtoolCmd) {
16426 exitStatus("Not_Found", "can't find \"otool\"");
16427 }
Andrey Ponomarenkoa01311b2012-06-08 17:20:02 +040016428 open(APP, "$OtoolCmd -IV \"$Path\" 2>\"$TMP_DIR/null\" |");
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040016429 while(<APP>)
16430 {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040016431 if(/[^_]+\s+_?([\w\$]+)\s*\Z/) {
16432 push(@Imported, $1);
16433 }
16434 }
16435 close(APP);
16436 }
16437 elsif($OSgroup eq "windows")
16438 {
16439 my $DumpBinCmd = get_CmdPath("dumpbin");
16440 if(not $DumpBinCmd) {
16441 exitStatus("Not_Found", "can't find \"dumpbin.exe\"");
16442 }
Andrey Ponomarenkoa01311b2012-06-08 17:20:02 +040016443 open(APP, "$DumpBinCmd /IMPORTS \"$Path\" 2>\"$TMP_DIR/null\" |");
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040016444 while(<APP>)
16445 {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040016446 if(/\s*\w+\s+\w+\s+\w+\s+([\w\?\@]+)\s*/) {
16447 push(@Imported, $1);
16448 }
16449 }
16450 close(APP);
16451 }
16452 else
16453 {
16454 my $ReadelfCmd = get_CmdPath("readelf");
16455 if(not $ReadelfCmd) {
16456 exitStatus("Not_Found", "can't find \"readelf\"");
16457 }
Andrey Ponomarenkoa01311b2012-06-08 17:20:02 +040016458 open(APP, "$ReadelfCmd -WhlSsdA \"$Path\" 2>\"$TMP_DIR/null\" |");
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040016459 my $symtab = undef; # indicates that we are processing 'symtab' section of 'readelf' output
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040016460 while(<APP>)
16461 {
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040016462 if(defined $symtab)
16463 { # do nothing with symtab
16464 if(index($_, "'.dynsym'")!=-1)
16465 { # dynamic table
16466 $symtab = undef;
16467 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040016468 }
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040016469 elsif(index($_, "'.symtab'")!=-1)
16470 { # symbol table
16471 $symtab = 1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040016472 }
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040016473 elsif(my @Info = readline_ELF($_))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040016474 {
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040016475 my ($Ndx, $Symbol) = ($Info[5], $Info[6]);
16476 if($Ndx eq "UND")
16477 { # only imported symbols
16478 push(@Imported, $Symbol);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040016479 }
16480 }
16481 }
16482 close(APP);
16483 }
16484 return @Imported;
16485}
16486
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040016487my %ELF_BIND = map {$_=>1} (
16488 "WEAK",
16489 "GLOBAL"
16490);
16491
16492my %ELF_TYPE = map {$_=>1} (
16493 "FUNC",
16494 "IFUNC",
16495 "OBJECT",
16496 "COMMON"
16497);
16498
16499my %ELF_VIS = map {$_=>1} (
16500 "DEFAULT",
16501 "PROTECTED"
16502);
16503
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040016504sub readline_ELF($)
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040016505{ # read the line of 'readelf' output corresponding to the symbol
16506 my @Info = split(/\s+/, $_[0]);
16507 # Num: Value Size Type Bind Vis Ndx Name
16508 # 3629: 000b09c0 32 FUNC GLOBAL DEFAULT 13 _ZNSt12__basic_fileIcED1Ev@@GLIBCXX_3.4
16509 shift(@Info); # spaces
16510 shift(@Info); # num
16511 if($#Info!=6)
16512 { # other lines
16513 return ();
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040016514 }
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040016515 return () if(not defined $ELF_TYPE{$Info[2]});
16516 return () if(not defined $ELF_BIND{$Info[3]});
16517 return () if(not defined $ELF_VIS{$Info[4]});
16518 if($Info[5] eq "ABS" and $Info[0]=~/\A0+\Z/)
16519 { # 1272: 00000000 0 OBJECT GLOBAL DEFAULT ABS CXXABI_1.3
16520 return ();
16521 }
16522 if($OStarget eq "symbian")
16523 { # _ZN12CCTTokenType4NewLE4TUid3RFs@@ctfinder{000a0000}[102020e5].dll
16524 if(index($Info[6], "_._.absent_export_")!=-1)
16525 { # "_._.absent_export_111"@@libstdcpp{00010001}[10282872].dll
16526 return ();
16527 }
16528 $Info[6]=~s/\@.+//g; # remove version
16529 }
16530 if(index($Info[2], "0x") == 0)
16531 { # size == 0x3d158
16532 $Info[2] = hex($Info[2]);
16533 }
16534 return @Info;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040016535}
16536
Andrey Ponomarenko16934472012-03-29 15:37:04 +040016537sub read_symlink($)
16538{
16539 my $Path = $_[0];
Andrey Ponomarenko16934472012-03-29 15:37:04 +040016540 if(my $Res = readlink($Path)) {
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040016541 return $Res;
Andrey Ponomarenko16934472012-03-29 15:37:04 +040016542 }
16543 elsif(my $ReadlinkCmd = get_CmdPath("readlink")) {
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040016544 return `$ReadlinkCmd -n \"$Path\"`;
Andrey Ponomarenko16934472012-03-29 15:37:04 +040016545 }
16546 elsif(my $FileCmd = get_CmdPath("file"))
16547 {
Andrey Ponomarenkoa01311b2012-06-08 17:20:02 +040016548 my $Info = `$FileCmd \"$Path\"`;
Andrey Ponomarenko16934472012-03-29 15:37:04 +040016549 if($Info=~/symbolic\s+link\s+to\s+['`"]*([\w\d\.\-\/\\]+)['`"]*/i) {
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040016550 return $1;
Andrey Ponomarenko16934472012-03-29 15:37:04 +040016551 }
16552 }
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040016553
16554 # can't read
16555 return "";
Andrey Ponomarenko16934472012-03-29 15:37:04 +040016556}
16557
16558sub resolve_symlink($)
16559{
16560 my $Path = $_[0];
16561 return "" if(not $Path);
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040016562
Andrey Ponomarenko16934472012-03-29 15:37:04 +040016563 if(defined $Cache{"resolve_symlink"}{$Path}) {
16564 return $Cache{"resolve_symlink"}{$Path};
16565 }
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040016566 if(not -f $Path and not -l $Path)
16567 { # broken
16568 return ($Cache{"resolve_symlink"}{$Path} = "");
16569 }
16570 return ($Cache{"resolve_symlink"}{$Path} = resolve_symlink_I($Path));
16571}
16572
16573sub resolve_symlink_I($)
16574{
16575 my $Path = $_[0];
Andrey Ponomarenko16934472012-03-29 15:37:04 +040016576 return $Path if(isCyclical(\@RecurSymlink, $Path));
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040016577 my $Res = $Path;
Andrey Ponomarenko16934472012-03-29 15:37:04 +040016578 push(@RecurSymlink, $Path);
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040016579 if(-l $Path and my $Redirect = read_symlink($Path))
Andrey Ponomarenko16934472012-03-29 15:37:04 +040016580 {
16581 if(is_abs($Redirect))
16582 { # absolute path
16583 if($SystemRoot and $SystemRoot ne "/"
16584 and $Path=~/\A\Q$SystemRoot\E\//
16585 and (-f $SystemRoot.$Redirect or -l $SystemRoot.$Redirect))
16586 { # symbolic links from the sysroot
16587 # should be corrected to point to
16588 # the files inside sysroot
16589 $Redirect = $SystemRoot.$Redirect;
16590 }
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040016591 $Res = resolve_symlink($Redirect);
Andrey Ponomarenko16934472012-03-29 15:37:04 +040016592 }
16593 elsif($Redirect=~/\.\.[\/\\]/)
16594 { # relative path
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040016595 $Redirect = joinPath(get_dirname($Path), $Redirect);
Andrey Ponomarenko16934472012-03-29 15:37:04 +040016596 while($Redirect=~s&(/|\\)[^\/\\]+(\/|\\)\.\.(\/|\\)&$1&){};
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040016597 $Res = resolve_symlink($Redirect);
Andrey Ponomarenko16934472012-03-29 15:37:04 +040016598 }
16599 elsif(-f get_dirname($Path)."/".$Redirect)
16600 { # file name in the same directory
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040016601 $Res = resolve_symlink(joinPath(get_dirname($Path), $Redirect));
Andrey Ponomarenko16934472012-03-29 15:37:04 +040016602 }
16603 else
16604 { # broken link
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040016605 $Res = "";
Andrey Ponomarenko16934472012-03-29 15:37:04 +040016606 }
16607 }
16608 pop(@RecurSymlink);
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040016609 return $Res;
Andrey Ponomarenko16934472012-03-29 15:37:04 +040016610}
16611
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040016612sub get_LibPath($$)
Andrey Ponomarenko16934472012-03-29 15:37:04 +040016613{
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040016614 my ($LibVersion, $Name) = @_;
16615 return "" if(not $LibVersion or not $Name);
16616 if(defined $Cache{"get_LibPath"}{$LibVersion}{$Name}) {
16617 return $Cache{"get_LibPath"}{$LibVersion}{$Name};
Andrey Ponomarenko16934472012-03-29 15:37:04 +040016618 }
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040016619 return ($Cache{"get_LibPath"}{$LibVersion}{$Name} = get_LibPath_I($LibVersion, $Name));
16620}
16621
16622sub get_LibPath_I($$)
16623{
16624 my ($LibVersion, $Name) = @_;
16625 if(is_abs($Name))
Andrey Ponomarenko16934472012-03-29 15:37:04 +040016626 {
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040016627 if(-f $Name)
16628 { # absolute path
16629 return $Name;
16630 }
16631 else
16632 { # broken
16633 return "";
16634 }
16635 }
16636 if(my @Paths = sort keys(%{$RegisteredObjects{$LibVersion}{$Name}}))
16637 { # registered paths
16638 return $Paths[0];
16639 }
16640 if(my @Paths = sort keys(%{$RegisteredSONAMEs{$LibVersion}{$Name}}))
16641 { # registered paths
16642 return $Paths[0];
16643 }
16644 if(my $DefaultPath = $DyLib_DefaultPath{$Name})
16645 { # ldconfig default paths
16646 return $DefaultPath;
16647 }
16648 foreach my $Dir (sort keys(%DefaultLibPaths), sort keys(%{$SystemPaths{"lib"}}))
16649 { # search in default linker directories
16650 # and then in all system paths
16651 if(-f $Dir."/".$Name) {
16652 return joinPath($Dir,$Name);
16653 }
16654 }
16655 detectSystemObjects() if(not keys(%SystemObjects));
16656 if(my @AllObjects = keys(%{$SystemObjects{$Name}})) {
16657 return $AllObjects[0];
16658 }
16659 if(my $ShortName = parse_libname($Name, "name+ext", $OStarget))
16660 {
16661 if($ShortName ne $Name)
16662 { # FIXME: check this case
16663 if(my $Path = get_LibPath($LibVersion, $ShortName)) {
16664 return $Path;
Andrey Ponomarenko16934472012-03-29 15:37:04 +040016665 }
16666 }
Andrey Ponomarenko16934472012-03-29 15:37:04 +040016667 }
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040016668 # can't find
16669 return "";
Andrey Ponomarenko16934472012-03-29 15:37:04 +040016670}
16671
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040016672sub readSymbols_Lib($$$$$$)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040016673{
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040016674 my ($LibVersion, $Lib_Path, $IsNeededLib, $Weak, $Deps, $Vers) = @_;
16675 return () if(not $LibVersion or not $Lib_Path);
16676 my $Lib_Name = get_filename(resolve_symlink($Lib_Path));
16677 if($IsNeededLib)
16678 {
16679 if($CheckedDyLib{$LibVersion}{$Lib_Name}) {
16680 return ();
16681 }
16682 }
16683 return () if(isCyclical(\@RecurLib, $Lib_Name) or $#RecurLib>=1);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040016684 $CheckedDyLib{$LibVersion}{$Lib_Name} = 1;
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040016685
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040016686 if($CheckImpl)
16687 {
16688 if(not $IsNeededLib) {
16689 getImplementations($LibVersion, $Lib_Path);
16690 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040016691 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040016692
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040016693 push(@RecurLib, $Lib_Name);
16694 my (%Value_Interface, %Interface_Value, %NeededLib) = ();
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040016695 my $Lib_ShortName = parse_libname($Lib_Name, "short", $OStarget);
16696 if($IsNeededLib)
16697 { # change short name to use later for needed libraries
16698 $Lib_ShortName = parse_libname($Lib_Name, "name+ext", $OStarget);
16699 }
16700 else
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040016701 { # libstdc++ and libc are always used by other libs
16702 # if you test one of these libs then you not need
16703 # to find them in the system for reusing
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040016704 if($Lib_ShortName eq "libstdc++")
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040016705 { # libstdc++.so.6
16706 $STDCXX_TESTING = 1;
16707 }
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040016708 elsif($Lib_ShortName eq "libc")
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040016709 { # libc-2.11.3.so
16710 $GLIBC_TESTING = 1;
16711 }
16712 }
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040016713 my $DebugPath = "";
Andrey Ponomarenkoa01311b2012-06-08 17:20:02 +040016714 if($Debug and not $DumpSystem)
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040016715 { # debug mode
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040016716 $DebugPath = $DEBUG_PATH{$LibVersion}."/libs/".get_filename($Lib_Path).".txt";
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040016717 mkpath(get_dirname($DebugPath));
16718 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040016719 if($OStarget eq "macos")
16720 { # Mac OS X: *.dylib, *.a
16721 my $OtoolCmd = get_CmdPath("otool");
16722 if(not $OtoolCmd) {
16723 exitStatus("Not_Found", "can't find \"otool\"");
16724 }
Andrey Ponomarenkoa01311b2012-06-08 17:20:02 +040016725 $OtoolCmd .= " -TV \"$Lib_Path\" 2>\"$TMP_DIR/null\"";
16726 if($DebugPath)
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040016727 { # debug mode
Andrey Ponomarenko16934472012-03-29 15:37:04 +040016728 # write to file
Andrey Ponomarenkoa01311b2012-06-08 17:20:02 +040016729 system($OtoolCmd." >\"$DebugPath\"");
Andrey Ponomarenko16934472012-03-29 15:37:04 +040016730 open(LIB, $DebugPath);
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040016731 }
Andrey Ponomarenko16934472012-03-29 15:37:04 +040016732 else
16733 { # write to pipe
16734 open(LIB, $OtoolCmd." |");
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040016735 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040016736 while(<LIB>)
16737 {
16738 if(/[^_]+\s+_([\w\$]+)\s*\Z/)
16739 {
16740 my $realname = $1;
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040016741 if($IsNeededLib)
16742 {
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040016743 if(not defined $RegisteredObjects{$Lib_ShortName})
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040016744 {
16745 $DepSymbol_Library{$LibVersion}{$realname} = $Lib_Name;
16746 $DepLibrary_Symbol{$LibVersion}{$Lib_Name}{$realname} = 1;
16747 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040016748 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040016749 else
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040016750 {
16751 $Symbol_Library{$LibVersion}{$realname} = $Lib_Name;
16752 $Library_Symbol{$LibVersion}{$Lib_Name}{$realname} = 1;
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040016753 if($COMMON_LANGUAGE{$LibVersion} ne "C++")
16754 {
16755 if(index($realname, "_Z")==0 or index($realname, "?")==0) {
16756 setLanguage($LibVersion, "C++");
16757 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040016758 }
16759 if($CheckObjectsOnly
16760 and $LibVersion==1) {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040016761 $CheckedSymbols{"Binary"}{$realname} = 1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040016762 }
16763 }
16764 }
16765 }
16766 close(LIB);
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040016767 if($Deps)
16768 {
16769 if($LIB_TYPE eq "dynamic")
16770 { # dependencies
16771 open(LIB, "$OtoolCmd -L \"$Lib_Path\" 2>\"$TMP_DIR/null\" |");
16772 while(<LIB>)
16773 {
16774 if(/\s*([\/\\].+\.$LIB_EXT)\s*/
16775 and $1 ne $Lib_Path) {
16776 $NeededLib{$1} = 1;
16777 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040016778 }
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040016779 close(LIB);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040016780 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040016781 }
16782 }
16783 elsif($OStarget eq "windows")
16784 { # Windows *.dll, *.lib
16785 my $DumpBinCmd = get_CmdPath("dumpbin");
16786 if(not $DumpBinCmd) {
16787 exitStatus("Not_Found", "can't find \"dumpbin\"");
16788 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040016789 $DumpBinCmd .= " /EXPORTS \"".$Lib_Path."\" 2>$TMP_DIR/null";
Andrey Ponomarenkoa01311b2012-06-08 17:20:02 +040016790 if($DebugPath)
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040016791 { # debug mode
Andrey Ponomarenko16934472012-03-29 15:37:04 +040016792 # write to file
Andrey Ponomarenkoa01311b2012-06-08 17:20:02 +040016793 system($DumpBinCmd." >\"$DebugPath\"");
Andrey Ponomarenko16934472012-03-29 15:37:04 +040016794 open(LIB, $DebugPath);
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040016795 }
Andrey Ponomarenko16934472012-03-29 15:37:04 +040016796 else
16797 { # write to pipe
16798 open(LIB, $DumpBinCmd." |");
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040016799 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040016800 while(<LIB>)
16801 { # 1197 4AC 0000A620 SetThreadStackGuarantee
16802 # 1198 4AD SetThreadToken (forwarded to ...)
16803 # 3368 _o2i_ECPublicKey
16804 if(/\A\s*\d+\s+[a-f\d]+\s+[a-f\d]+\s+([\w\?\@]+)\s*\Z/i
16805 or /\A\s*\d+\s+[a-f\d]+\s+([\w\?\@]+)\s*\(\s*forwarded\s+/
16806 or /\A\s*\d+\s+_([\w\?\@]+)\s*\Z/)
16807 { # dynamic, static and forwarded symbols
16808 my $realname = $1;
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040016809 if($IsNeededLib)
16810 {
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040016811 if(not defined $RegisteredObjects{$Lib_ShortName})
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040016812 {
16813 $DepSymbol_Library{$LibVersion}{$realname} = $Lib_Name;
16814 $DepLibrary_Symbol{$LibVersion}{$Lib_Name}{$realname} = 1;
16815 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040016816 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040016817 else
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040016818 {
16819 $Symbol_Library{$LibVersion}{$realname} = $Lib_Name;
16820 $Library_Symbol{$LibVersion}{$Lib_Name}{$realname} = 1;
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040016821 if($COMMON_LANGUAGE{$LibVersion} ne "C++")
16822 {
16823 if(index($realname, "_Z")==0 or index($realname, "?")==0) {
16824 setLanguage($LibVersion, "C++");
16825 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040016826 }
16827 if($CheckObjectsOnly
16828 and $LibVersion==1) {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040016829 $CheckedSymbols{"Binary"}{$realname} = 1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040016830 }
16831 }
16832 }
16833 }
16834 close(LIB);
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040016835 if($Deps)
16836 {
16837 if($LIB_TYPE eq "dynamic")
16838 { # dependencies
16839 open(LIB, "$DumpBinCmd /DEPENDENTS \"$Lib_Path\" 2>\"$TMP_DIR/null\" |");
16840 while(<LIB>)
16841 {
16842 if(/\s*([^\s]+?\.$LIB_EXT)\s*/i
16843 and $1 ne $Lib_Path) {
16844 $NeededLib{path_format($1, $OSgroup)} = 1;
16845 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040016846 }
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040016847 close(LIB);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040016848 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040016849 }
16850 }
16851 else
16852 { # Unix; *.so, *.a
16853 # Symbian: *.dso, *.lib
16854 my $ReadelfCmd = get_CmdPath("readelf");
16855 if(not $ReadelfCmd) {
16856 exitStatus("Not_Found", "can't find \"readelf\"");
16857 }
Andrey Ponomarenkoa01311b2012-06-08 17:20:02 +040016858 $ReadelfCmd .= " -WhlSsdA \"$Lib_Path\" 2>\"$TMP_DIR/null\"";
16859 if($DebugPath)
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040016860 { # debug mode
Andrey Ponomarenko16934472012-03-29 15:37:04 +040016861 # write to file
Andrey Ponomarenkoa01311b2012-06-08 17:20:02 +040016862 system($ReadelfCmd." >\"$DebugPath\"");
Andrey Ponomarenko16934472012-03-29 15:37:04 +040016863 open(LIB, $DebugPath);
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040016864 }
Andrey Ponomarenko16934472012-03-29 15:37:04 +040016865 else
16866 { # write to pipe
16867 open(LIB, $ReadelfCmd." |");
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040016868 }
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040016869 my $symtab = undef; # indicates that we are processing 'symtab' section of 'readelf' output
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040016870 while(<LIB>)
16871 {
16872 if($LIB_TYPE eq "dynamic")
16873 { # dynamic library specifics
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040016874 if(defined $symtab)
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040016875 {
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040016876 if(index($_, "'.dynsym'")!=-1)
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040016877 { # dynamic table
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040016878 $symtab = undef;
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040016879 }
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040016880 # do nothing with symtab
16881 next;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040016882 }
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040016883 elsif(index($_, "'.symtab'")!=-1)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040016884 { # symbol table
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040016885 $symtab = 1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040016886 next;
16887 }
16888 }
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040016889 if(my ($Value, $Size, $Type, $Bind, $Vis, $Ndx, $Symbol) = readline_ELF($_))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040016890 { # read ELF entry
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040016891 if($Ndx eq "UND")
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040016892 { # ignore interfaces that are imported from somewhere else
16893 next;
16894 }
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040016895 if($Bind eq "WEAK"
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040016896 and $Weak eq "-Weak")
16897 { # skip WEAK symbols
16898 next;
16899 }
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040016900 my $Short = $Symbol;
16901 $Short=~s/\@.+//g;
16902 if($Type eq "OBJECT")
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040016903 { # global data
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040016904 $GlobalDataObject{$LibVersion}{$Symbol} = 1;
16905 $GlobalDataObject{$LibVersion}{$Short} = 1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040016906 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040016907 if($IsNeededLib)
16908 {
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040016909 if(not defined $RegisteredObjects{$Lib_ShortName})
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040016910 {
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040016911 $DepSymbol_Library{$LibVersion}{$Symbol} = $Lib_Name;
16912 $DepLibrary_Symbol{$LibVersion}{$Lib_Name}{$Symbol} = ($Type eq "OBJECT")?-$Size:1;
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040016913 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040016914 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040016915 else
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040016916 {
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040016917 $Symbol_Library{$LibVersion}{$Symbol} = $Lib_Name;
16918 $Library_Symbol{$LibVersion}{$Lib_Name}{$Symbol} = ($Type eq "OBJECT")?-$Size:1;
16919 if($Vers)
16920 {
16921 if($LIB_EXT eq "so")
16922 { # value
16923 $Interface_Value{$LibVersion}{$Symbol} = $Value;
16924 $Value_Interface{$LibVersion}{$Value}{$Symbol} = 1;
16925 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040016926 }
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040016927 if($COMMON_LANGUAGE{$LibVersion} ne "C++")
16928 {
16929 if(index($Symbol, "_Z")==0 or index($Symbol, "?")==0) {
16930 setLanguage($LibVersion, "C++");
16931 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040016932 }
16933 if($CheckObjectsOnly
16934 and $LibVersion==1) {
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040016935 $CheckedSymbols{"Binary"}{$Symbol} = 1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040016936 }
16937 }
16938 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040016939 elsif($LIB_TYPE eq "dynamic")
16940 { # dynamic library specifics
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040016941 if($Deps)
16942 {
16943 if(/NEEDED.+\[([^\[\]]+)\]/)
16944 { # dependencies:
16945 # 0x00000001 (NEEDED) Shared library: [libc.so.6]
16946 $NeededLib{$1} = 1;
16947 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040016948 }
16949 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040016950 }
16951 close(LIB);
16952 }
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040016953 if($Vers)
16954 {
16955 if(not $IsNeededLib and $LIB_EXT eq "so")
16956 { # get symbol versions
16957 foreach my $Symbol (keys(%{$Symbol_Library{$LibVersion}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040016958 {
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040016959 next if(index($Symbol,"\@")==-1);
16960 if(my $Value = $Interface_Value{$LibVersion}{$Symbol})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040016961 {
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040016962 my $Interface_SymName = "";
16963 foreach my $Symbol_SameValue (keys(%{$Value_Interface{$LibVersion}{$Value}}))
Andrey Ponomarenkoa01311b2012-06-08 17:20:02 +040016964 {
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040016965 if($Symbol_SameValue ne $Symbol
16966 and index($Symbol_SameValue,"\@")==-1)
16967 {
16968 $SymVer{$LibVersion}{$Symbol_SameValue} = $Symbol;
16969 $Interface_SymName = $Symbol_SameValue;
16970 last;
16971 }
Andrey Ponomarenkoa01311b2012-06-08 17:20:02 +040016972 }
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040016973 if(not $Interface_SymName)
16974 {
16975 if($Symbol=~/\A([^\@\$\?]*)[\@\$]+([^\@\$]*)\Z/
16976 and not $SymVer{$LibVersion}{$1}) {
16977 $SymVer{$LibVersion}{$1} = $Symbol;
16978 }
Andrey Ponomarenkoa01311b2012-06-08 17:20:02 +040016979 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040016980 }
16981 }
16982 }
16983 }
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040016984 if($Deps)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040016985 {
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040016986 foreach my $DyLib (sort keys(%NeededLib))
16987 {
16988 if(my $DepPath = get_LibPath($LibVersion, $DyLib)) {
16989 readSymbols_Lib($LibVersion, $DepPath, 1, "+Weak", $Deps, $Vers);
16990 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040016991 }
16992 }
16993 pop(@RecurLib);
16994 return $Library_Symbol{$LibVersion};
16995}
16996
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040016997sub get_prefixes($)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040016998{
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040016999 my %Prefixes = ();
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040017000 get_prefixes_I([$_[0]], \%Prefixes);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017001 return keys(%Prefixes);
17002}
17003
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040017004sub get_prefixes_I($$)
17005{
17006 foreach my $P (@{$_[0]})
17007 {
17008 my @Parts = reverse(split(/[\/\\]+/, $P));
17009 my $Name = $Parts[0];
17010 foreach (1 .. $#Parts)
17011 {
17012 $_[1]->{$Name}{$P} = 1;
17013 last if($_>4 or $Parts[$_] eq "include");
17014 $Name = $Parts[$_].$SLASH.$Name;
17015 }
17016 }
17017}
17018
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017019sub detectSystemHeaders()
17020{
17021 my @SysHeaders = ();
17022 foreach my $DevelPath (keys(%{$SystemPaths{"include"}}))
17023 {
17024 next if(not -d $DevelPath);
17025 # search for all header files in the /usr/include
17026 # with or without extension (ncurses.h, QtCore, ...)
17027 @SysHeaders = (@SysHeaders, cmd_find($DevelPath,"f","",""));
17028 foreach my $Link (cmd_find($DevelPath,"l","",""))
17029 { # add symbolic links
17030 if(-f $Link) {
17031 push(@SysHeaders, $Link);
17032 }
17033 }
17034 }
17035 foreach my $DevelPath (keys(%{$SystemPaths{"lib"}}))
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040017036 { # search for config headers in the /usr/lib
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017037 next if(not -d $DevelPath);
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040017038 foreach (cmd_find($DevelPath,"f","",""))
17039 {
17040 if(not /\/(gcc|jvm|syslinux|kbd|parrot|xemacs)/)
17041 {
17042 if(/\.h\Z|\/include\//) {
17043 push(@SysHeaders, $_);
17044 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017045 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017046 }
17047 }
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040017048 get_prefixes_I(\@SysHeaders, \%SystemHeaders);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017049}
17050
17051sub detectSystemObjects()
17052{
17053 foreach my $DevelPath (keys(%{$SystemPaths{"lib"}}))
17054 {
17055 next if(not -d $DevelPath);
17056 foreach my $Path (find_libs($DevelPath,"",""))
17057 { # search for shared libraries in the /usr/lib (including symbolic links)
17058 $SystemObjects{parse_libname(get_filename($Path), "name+ext", $OStarget)}{$Path}=1;
17059 }
17060 }
17061}
17062
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040017063sub getSOPaths($)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017064{
17065 my $LibVersion = $_[0];
17066 my @SoPaths = ();
17067 foreach my $Dest (split(/\s*\n\s*/, $Descriptor{$LibVersion}{"Libs"}))
17068 {
17069 if(not -e $Dest) {
17070 exitStatus("Access_Error", "can't access \'$Dest\'");
17071 }
17072 my @SoPaths_Dest = getSOPaths_Dest($Dest, $LibVersion);
17073 foreach (@SoPaths_Dest) {
17074 push(@SoPaths, $_);
17075 }
17076 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040017077 return sort @SoPaths;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017078}
17079
17080sub skip_lib($$)
17081{
17082 my ($Path, $LibVersion) = @_;
17083 return 1 if(not $Path or not $LibVersion);
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040017084 my $Name = get_filename($Path);
17085 if($SkipLibs{$LibVersion}{"Name"}{$Name}) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017086 return 1;
17087 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040017088 my $ShortName = parse_libname($Name, "name+ext", $OStarget);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017089 if($SkipLibs{$LibVersion}{"Name"}{$ShortName}) {
17090 return 1;
17091 }
17092 foreach my $Dir (keys(%{$SkipLibs{$LibVersion}{"Path"}}))
17093 {
17094 if($Path=~/\Q$Dir\E([\/\\]|\Z)/) {
17095 return 1;
17096 }
17097 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040017098 foreach my $P (keys(%{$SkipLibs{$LibVersion}{"Pattern"}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017099 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040017100 if($Name=~/$P/) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017101 return 1;
17102 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040017103 if($P=~/[\/\\]/ and $Path=~/$P/) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017104 return 1;
17105 }
17106 }
17107 return 0;
17108}
17109
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040017110sub skipHeader($$)
17111{
17112 my ($Path, $LibVersion) = @_;
17113 return 1 if(not $Path or not $LibVersion);
17114 if(not keys(%{$SkipHeaders{$LibVersion}})) {
17115 return 0;
17116 }
17117 if(defined $Cache{"skipHeader"}{$Path}) {
17118 return $Cache{"skipHeader"}{$Path};
17119 }
17120 return ($Cache{"skipHeader"}{$Path} = skipHeader_I(@_));
17121}
17122
17123sub skipHeader_I($$)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017124{ # returns:
17125 # 1 - if header should NOT be included and checked
17126 # 2 - if header should NOT be included, but should be checked
17127 my ($Path, $LibVersion) = @_;
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040017128 my $Name = get_filename($Path);
17129 if(my $Kind = $SkipHeaders{$LibVersion}{"Name"}{$Name}) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017130 return $Kind;
17131 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040017132 foreach my $D (keys(%{$SkipHeaders{$LibVersion}{"Path"}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017133 {
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040017134 if(index($Path, $D)!=-1)
17135 {
17136 if($Path=~/\Q$D\E([\/\\]|\Z)/) {
17137 return $SkipHeaders{$LibVersion}{"Path"}{$D};
17138 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017139 }
17140 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040017141 foreach my $P (keys(%{$SkipHeaders{$LibVersion}{"Pattern"}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017142 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040017143 if(my $Kind = $SkipHeaders{$LibVersion}{"Pattern"}{$P})
17144 {
17145 if($Name=~/$P/) {
17146 return $Kind;
17147 }
17148 if($P=~/[\/\\]/ and $Path=~/$P/) {
17149 return $Kind;
17150 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017151 }
17152 }
17153 return 0;
17154}
17155
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040017156sub registerObject_Dir($$)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017157{
17158 my ($Dir, $LibVersion) = @_;
17159 if($SystemPaths{"lib"}{$Dir})
17160 { # system directory
17161 return;
17162 }
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040017163 if($RegisteredObject_Dirs{$LibVersion}{$Dir})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017164 { # already registered
17165 return;
17166 }
17167 foreach my $Path (find_libs($Dir,"",1))
17168 {
17169 next if(ignore_path($Path));
17170 next if(skip_lib($Path, $LibVersion));
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040017171 registerObject($Path, $LibVersion);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017172 }
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040017173 $RegisteredObject_Dirs{$LibVersion}{$Dir} = 1;
17174}
17175
17176sub registerObject($$)
17177{
17178 my ($Path, $LibVersion) = @_;
17179 my $Name = get_filename($Path);
17180 $RegisteredObjects{$LibVersion}{$Name}{$Path} = 1;
17181 if(my $SONAME = getSONAME($Path)) {
17182 $RegisteredSONAMEs{$LibVersion}{$SONAME}{$Path} = 1;
17183 }
17184 if(my $SName = parse_libname($Name, "name", $OStarget)) {
17185 $RegisteredObjects{$LibVersion}{$SName}{$Path} = 1;
17186 }
17187}
17188
17189sub getSONAME($)
17190{
17191 my $Path = $_[0];
17192 return if(not $Path);
17193 if(defined $Cache{"getSONAME"}{$Path}) {
17194 return $Cache{"getSONAME"}{$Path};
17195 }
17196 my $ObjdumpCmd = get_CmdPath("objdump");
17197 if(not $ObjdumpCmd) {
17198 exitStatus("Not_Found", "can't find \"objdump\"");
17199 }
17200 my $SonameCmd = "$ObjdumpCmd -x $Path 2>$TMP_DIR/null";
17201 if($OSgroup eq "windows") {
17202 $SonameCmd .= " | find \"SONAME\"";
17203 }
17204 else {
17205 $SonameCmd .= " | grep SONAME";
17206 }
17207 if(my $SonameInfo = `$SonameCmd`) {
17208 if($SonameInfo=~/SONAME\s+([^\s]+)/) {
17209 return ($Cache{"getSONAME"}{$Path} = $1);
17210 }
17211 }
17212 return ($Cache{"getSONAME"}{$Path}="");
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017213}
17214
17215sub getSOPaths_Dest($$)
17216{
17217 my ($Dest, $LibVersion) = @_;
17218 if(skip_lib($Dest, $LibVersion)) {
17219 return ();
17220 }
17221 if(-f $Dest)
17222 {
17223 if(not parse_libname($Dest, "name", $OStarget)) {
17224 exitStatus("Error", "incorrect format of library (should be *.$LIB_EXT): \'$Dest\'");
17225 }
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040017226 registerObject($Dest, $LibVersion);
17227 registerObject_Dir(get_dirname($Dest), $LibVersion);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017228 return ($Dest);
17229 }
17230 elsif(-d $Dest)
17231 {
17232 $Dest=~s/[\/\\]+\Z//g;
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040017233 my %Libs = ();
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017234 if($SystemPaths{"lib"}{$Dest})
17235 { # you have specified /usr/lib as the search directory (<libs>) in the XML descriptor
17236 # and the real name of the library by -l option (bz2, stdc++, Xaw, ...)
17237 foreach my $Path (cmd_find($Dest,"","*".esc($TargetLibraryName)."*\.$LIB_EXT*",2))
17238 { # all files and symlinks that match the name of a library
17239 if(get_filename($Path)=~/\A(|lib)\Q$TargetLibraryName\E[\d\-]*\.$LIB_EXT[\d\.]*\Z/i)
17240 {
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040017241 registerObject($Path, $LibVersion);
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040017242 $Libs{resolve_symlink($Path)}=1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017243 }
17244 }
17245 }
17246 else
17247 { # search for all files and symlinks
17248 foreach my $Path (find_libs($Dest,"",""))
17249 {
17250 next if(ignore_path($Path));
17251 next if(skip_lib($Path, $LibVersion));
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040017252 registerObject($Path, $LibVersion);
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040017253 $Libs{resolve_symlink($Path)}=1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017254 }
17255 if($OSgroup eq "macos")
17256 { # shared libraries on MacOS X may have no extension
17257 foreach my $Path (cmd_find($Dest,"f","",""))
17258 {
17259 next if(ignore_path($Path));
17260 next if(skip_lib($Path, $LibVersion));
17261 if(get_filename($Path)!~/\./
Andrey Ponomarenko85043792012-05-14 16:48:07 +040017262 and cmd_file($Path)=~/(shared|dynamic)\s+library/i)
17263 {
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040017264 registerObject($Path, $LibVersion);
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040017265 $Libs{resolve_symlink($Path)}=1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017266 }
17267 }
17268 }
17269 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040017270 return keys(%Libs);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017271 }
17272 else {
17273 return ();
17274 }
17275}
17276
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040017277sub isCyclical($$)
17278{
17279 my ($Stack, $Value) = @_;
17280 return (grep {$_ eq $Value} @{$Stack});
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017281}
17282
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017283sub generateTemplate()
17284{
17285 writeFile("VERSION.xml", $DescriptorTemplate."\n");
17286 printMsg("INFO", "XML-descriptor template ./VERSION.xml has been generated");
17287}
17288
17289sub detectWordSize()
17290{
17291 return "" if(not $GCC_PATH);
17292 if($Cache{"detectWordSize"}) {
17293 return $Cache{"detectWordSize"};
17294 }
17295 writeFile("$TMP_DIR/empty.h", "");
Andrey Ponomarenkoa01311b2012-06-08 17:20:02 +040017296 my $Defines = `$GCC_PATH -E -dD \"$TMP_DIR/empty.h\"`;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017297 unlink("$TMP_DIR/empty.h");
17298 my $WSize = 0;
17299 if($Defines=~/ __SIZEOF_POINTER__\s+(\d+)/)
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040017300 { # GCC 4
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017301 $WSize = $1;
17302 }
17303 elsif($Defines=~/ __PTRDIFF_TYPE__\s+(\w+)/)
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040017304 { # GCC 3
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017305 my $PTRDIFF = $1;
17306 if($PTRDIFF=~/long/) {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040017307 $WSize = "8";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017308 }
17309 else {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040017310 $WSize = "4";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017311 }
17312 }
Andrey Ponomarenko01117f12012-06-26 12:23:02 +040017313 if(not $WSize) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017314 exitStatus("Error", "can't check WORD size");
17315 }
17316 return ($Cache{"detectWordSize"} = $WSize);
17317}
17318
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +040017319sub getWordSize($) {
17320 return $WORD_SIZE{$_[0]};
17321}
17322
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017323sub majorVersion($)
17324{
17325 my $V = $_[0];
17326 return 0 if(not $V);
17327 my @VParts = split(/\./, $V);
17328 return $VParts[0];
17329}
17330
17331sub cmpVersions($$)
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040017332{ # compare two versions in dotted-numeric format
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017333 my ($V1, $V2) = @_;
17334 return 0 if($V1 eq $V2);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017335 my @V1Parts = split(/\./, $V1);
17336 my @V2Parts = split(/\./, $V2);
17337 for (my $i = 0; $i <= $#V1Parts && $i <= $#V2Parts; $i++) {
17338 return -1 if(int($V1Parts[$i]) < int($V2Parts[$i]));
17339 return 1 if(int($V1Parts[$i]) > int($V2Parts[$i]));
17340 }
17341 return -1 if($#V1Parts < $#V2Parts);
17342 return 1 if($#V1Parts > $#V2Parts);
17343 return 0;
17344}
17345
17346sub read_ABI_Dump($$)
17347{
17348 my ($LibVersion, $Path) = @_;
17349 return if(not $LibVersion or not -e $Path);
17350 my $FilePath = "";
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040017351 if(isDump_U($Path))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017352 { # input *.abi
17353 $FilePath = $Path;
17354 }
17355 else
17356 { # input *.abi.tar.gz
17357 $FilePath = unpackDump($Path);
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040017358 if(not isDump_U($FilePath)) {
17359 exitStatus("Invalid_Dump", "specified ABI dump \'$Path\' is not valid, try to recreate it");
17360 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017361 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +040017362
Andrey Ponomarenko01117f12012-06-26 12:23:02 +040017363 my $ABI = {};
Andrey Ponomarenko5c09ef32012-06-14 18:17:33 +040017364
Andrey Ponomarenko01117f12012-06-26 12:23:02 +040017365 my $Line = readLineNum($FilePath, 0);
17366 if($Line=~/xml/)
17367 { # XML format
17368 loadModule("XmlDump");
17369 $ABI = readXmlDump($FilePath);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017370 }
Andrey Ponomarenko01117f12012-06-26 12:23:02 +040017371 else
17372 { # Perl Data::Dumper format (default)
17373 open(DUMP, $FilePath);
17374 local $/ = undef;
17375 my $Content = <DUMP>;
17376 close(DUMP);
17377
17378 if(get_dirname($FilePath) eq $TMP_DIR."/unpack")
17379 { # remove temp file
17380 unlink($FilePath);
17381 }
17382 if($Content!~/};\s*\Z/) {
17383 exitStatus("Invalid_Dump", "specified ABI dump \'$Path\' is not valid, try to recreate it");
17384 }
17385 $ABI = eval($Content);
17386 if(not $ABI) {
17387 exitStatus("Error", "internal error - eval() procedure seem to not working correctly, try to remove 'use strict' and try again");
17388 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017389 }
17390 # new dumps (>=1.22) have a personal versioning
Andrey Ponomarenko01117f12012-06-26 12:23:02 +040017391 my $DumpVersion = $ABI->{"ABI_DUMP_VERSION"};
17392 my $ToolVersion = $ABI->{"ABI_COMPLIANCE_CHECKER_VERSION"};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017393 if(not $DumpVersion)
17394 { # old dumps (<=1.21.6) have been marked by the tool version
17395 $DumpVersion = $ToolVersion;
17396 }
17397 $UsedDump{$LibVersion}{"V"} = $DumpVersion;
17398 if(majorVersion($DumpVersion) ne majorVersion($ABI_DUMP_VERSION))
17399 { # should be compatible with dumps of the same major version
17400 if(cmpVersions($DumpVersion, $ABI_DUMP_VERSION)>0)
17401 { # Don't know how to parse future dump formats
Andrey Ponomarenko01117f12012-06-26 12:23:02 +040017402 exitStatus("Dump_Version", "incompatible version \'$DumpVersion\' of specified ABI dump (newer than $ABI_DUMP_VERSION)");
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017403 }
Andrey Ponomarenko01117f12012-06-26 12:23:02 +040017404 elsif(cmpVersions($DumpVersion, $TOOL_VERSION)>0 and not $ABI->{"ABI_DUMP_VERSION"})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017405 { # Don't know how to parse future dump formats
Andrey Ponomarenko01117f12012-06-26 12:23:02 +040017406 exitStatus("Dump_Version", "incompatible version \'$DumpVersion\' of specified ABI dump (newer than $TOOL_VERSION)");
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017407 }
17408 if($UseOldDumps)
17409 {
17410 if(cmpVersions($DumpVersion, $OLDEST_SUPPORTED_VERSION)<0) {
Andrey Ponomarenko01117f12012-06-26 12:23:02 +040017411 exitStatus("Dump_Version", "incompatible version \'$DumpVersion\' of specified ABI dump (older than $OLDEST_SUPPORTED_VERSION)");
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017412 }
17413 }
17414 else
17415 {
Andrey Ponomarenko01117f12012-06-26 12:23:02 +040017416 my $Msg = "incompatible version \'$DumpVersion\' of specified ABI dump (allowed only ".majorVersion($ABI_DUMP_VERSION).".0<=V<=$ABI_DUMP_VERSION)";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017417 if(cmpVersions($DumpVersion, $OLDEST_SUPPORTED_VERSION)>=0) {
17418 $Msg .= "\nUse -old-dumps option to use old-version dumps ($OLDEST_SUPPORTED_VERSION<=V<".majorVersion($ABI_DUMP_VERSION).".0)";
17419 }
17420 exitStatus("Dump_Version", $Msg);
17421 }
17422 }
Andrey Ponomarenko5c09ef32012-06-14 18:17:33 +040017423 if(not checkDump($LibVersion, "2.11"))
17424 { # old ABI dumps
17425 $UsedDump{$LibVersion}{"BinOnly"} = 1;
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040017426 }
Andrey Ponomarenko01117f12012-06-26 12:23:02 +040017427 elsif($ABI->{"BinOnly"})
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040017428 { # ABI dump created with --binary option
17429 $UsedDump{$LibVersion}{"BinOnly"} = 1;
17430 }
Andrey Ponomarenko5c09ef32012-06-14 18:17:33 +040017431 else
17432 { # default
17433 $UsedDump{$LibVersion}{"SrcBin"} = 1;
17434 }
Andrey Ponomarenko01117f12012-06-26 12:23:02 +040017435 if(defined $ABI->{"Mode"}
17436 and $ABI->{"Mode"} eq "Extended")
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017437 { # --ext option
17438 $ExtendedCheck = 1;
17439 }
Andrey Ponomarenko01117f12012-06-26 12:23:02 +040017440 if(my $Lang = $ABI->{"Language"})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017441 {
17442 $UsedDump{$LibVersion}{"L"} = $Lang;
17443 setLanguage($LibVersion, $Lang);
17444 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040017445 if(checkDump($LibVersion, "2.15")) {
Andrey Ponomarenko01117f12012-06-26 12:23:02 +040017446 $TypeInfo{$LibVersion} = $ABI->{"TypeInfo"};
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040017447 }
17448 else
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017449 { # support for old ABI dumps
Andrey Ponomarenko01117f12012-06-26 12:23:02 +040017450 my $TInfo = $ABI->{"TypeInfo"};
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040017451 if(not $TInfo)
17452 { # support for older ABI dumps
Andrey Ponomarenko01117f12012-06-26 12:23:02 +040017453 $TInfo = $ABI->{"TypeDescr"};
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040017454 }
17455 my %Tid_TDid = ();
17456 foreach my $TDid (keys(%{$TInfo}))
17457 {
17458 foreach my $Tid (keys(%{$TInfo->{$TDid}}))
17459 {
17460 $MAX_ID = $Tid if($Tid>$MAX_ID);
17461 $MAX_ID = $TDid if($TDid and $TDid>$MAX_ID);
17462 $Tid_TDid{$Tid}{$TDid}=1;
17463 }
17464 }
17465 my %NewID = ();
17466 foreach my $Tid (keys(%Tid_TDid))
17467 {
17468 my @TDids = keys(%{$Tid_TDid{$Tid}});
17469 if($#TDids>=1)
17470 {
17471 foreach my $TDid (@TDids)
17472 {
17473 if($TDid) {
17474 %{$TypeInfo{$LibVersion}{$Tid}} = %{$TInfo->{$TDid}{$Tid}};
17475 }
17476 else
17477 {
17478 if(my $ID = ++$MAX_ID)
17479 {
17480 $NewID{$TDid}{$Tid} = $ID;
17481 %{$TypeInfo{$LibVersion}{$ID}} = %{$TInfo->{$TDid}{$Tid}};
17482 $TypeInfo{$LibVersion}{$ID}{"Tid"} = $ID;
17483 }
17484 }
17485 }
17486 }
17487 else
17488 {
17489 my $TDid = $TDids[0];
17490 %{$TypeInfo{$LibVersion}{$Tid}} = %{$TInfo->{$TDid}{$Tid}};
17491 }
17492 }
17493 foreach my $Tid (keys(%{$TypeInfo{$LibVersion}}))
17494 {
17495 my %Info = %{$TypeInfo{$LibVersion}{$Tid}};
17496 if(defined $Info{"BaseType"})
17497 {
17498 my $Bid = $Info{"BaseType"}{"Tid"};
17499 my $BDid = $Info{"BaseType"}{"TDid"};
17500 $BDid="" if(not defined $BDid);
17501 if(defined $NewID{$BDid} and my $ID = $NewID{$BDid}{$Bid}) {
17502 $TypeInfo{$LibVersion}{$Tid}{"BaseType"}{"Tid"} = $ID;
17503 }
17504 delete($TypeInfo{$LibVersion}{$Tid}{"BaseType"}{"TDid"});
17505 }
17506 delete($TypeInfo{$LibVersion}{$Tid}{"TDid"});
17507 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017508 }
Andrey Ponomarenko01117f12012-06-26 12:23:02 +040017509 read_Machine_DumpInfo($ABI, $LibVersion);
17510 $SymbolInfo{$LibVersion} = $ABI->{"SymbolInfo"};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017511 if(not $SymbolInfo{$LibVersion})
17512 { # support for old dumps
Andrey Ponomarenko01117f12012-06-26 12:23:02 +040017513 $SymbolInfo{$LibVersion} = $ABI->{"FuncDescr"};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017514 }
17515 if(not keys(%{$SymbolInfo{$LibVersion}}))
17516 { # validation of old-version dumps
17517 if(not $ExtendedCheck) {
17518 exitStatus("Invalid_Dump", "the input dump d$LibVersion is invalid");
17519 }
17520 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040017521 if(checkDump($LibVersion, "2.15")) {
Andrey Ponomarenko01117f12012-06-26 12:23:02 +040017522 $DepLibrary_Symbol{$LibVersion} = $ABI->{"DepSymbols"};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017523 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040017524 else
17525 { # support for old ABI dumps
Andrey Ponomarenko01117f12012-06-26 12:23:02 +040017526 my $DepSymbols = $ABI->{"DepSymbols"};
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040017527 if(not $DepSymbols) {
Andrey Ponomarenko01117f12012-06-26 12:23:02 +040017528 $DepSymbols = $ABI->{"DepInterfaces"};
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040017529 }
17530 if(not $DepSymbols)
17531 { # Cannot reconstruct DepSymbols. This may result in false
17532 # positives if the old dump is for library 2. Not a problem if
17533 # old dumps are only from old libraries.
17534 $DepSymbols = {};
17535 }
17536 foreach my $Symbol (keys(%{$DepSymbols})) {
17537 $DepSymbol_Library{$LibVersion}{$Symbol} = 1;
17538 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017539 }
Andrey Ponomarenko01117f12012-06-26 12:23:02 +040017540 $SymVer{$LibVersion} = $ABI->{"SymbolVersion"};
17541 $Descriptor{$LibVersion}{"Version"} = $ABI->{"LibraryVersion"};
17542 $SkipTypes{$LibVersion} = $ABI->{"SkipTypes"};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017543 if(not $SkipTypes{$LibVersion})
17544 { # support for old dumps
Andrey Ponomarenko01117f12012-06-26 12:23:02 +040017545 $SkipTypes{$LibVersion} = $ABI->{"OpaqueTypes"};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017546 }
Andrey Ponomarenko01117f12012-06-26 12:23:02 +040017547 $SkipSymbols{$LibVersion} = $ABI->{"SkipSymbols"};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017548 if(not $SkipSymbols{$LibVersion})
17549 { # support for old dumps
Andrey Ponomarenko01117f12012-06-26 12:23:02 +040017550 $SkipSymbols{$LibVersion} = $ABI->{"SkipInterfaces"};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017551 }
17552 if(not $SkipSymbols{$LibVersion})
17553 { # support for old dumps
Andrey Ponomarenko01117f12012-06-26 12:23:02 +040017554 $SkipSymbols{$LibVersion} = $ABI->{"InternalInterfaces"};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017555 }
Andrey Ponomarenko01117f12012-06-26 12:23:02 +040017556 $SkipNameSpaces{$LibVersion} = $ABI->{"SkipNameSpaces"};
17557 $TargetHeaders{$LibVersion} = $ABI->{"TargetHeaders"};
17558 foreach my $Path (keys(%{$ABI->{"SkipHeaders"}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017559 {
Andrey Ponomarenko01117f12012-06-26 12:23:02 +040017560 $SkipHeadersList{$LibVersion}{$Path} = $ABI->{"SkipHeaders"}{$Path};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017561 my ($CPath, $Type) = classifyPath($Path);
Andrey Ponomarenko01117f12012-06-26 12:23:02 +040017562 $SkipHeaders{$LibVersion}{$Type}{$CPath} = $ABI->{"SkipHeaders"}{$Path};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017563 }
Andrey Ponomarenko01117f12012-06-26 12:23:02 +040017564 read_Headers_DumpInfo($ABI, $LibVersion);
17565 read_Libs_DumpInfo($ABI, $LibVersion);
Andrey Ponomarenko5c09ef32012-06-14 18:17:33 +040017566 if(not checkDump($LibVersion, "2.10.1")
17567 or not $TargetHeaders{$LibVersion})
Andrey Ponomarenko85043792012-05-14 16:48:07 +040017568 { # support for old ABI dumps: added target headers
17569 foreach (keys(%{$Registered_Headers{$LibVersion}})) {
17570 $TargetHeaders{$LibVersion}{get_filename($_)}=1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017571 }
17572 }
Andrey Ponomarenko01117f12012-06-26 12:23:02 +040017573 $Constants{$LibVersion} = $ABI->{"Constants"};
17574 $NestedNameSpaces{$LibVersion} = $ABI->{"NameSpaces"};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017575 if(not $NestedNameSpaces{$LibVersion})
17576 { # support for old dumps
17577 # Cannot reconstruct NameSpaces. This may affect design
17578 # of the compatibility report.
17579 $NestedNameSpaces{$LibVersion} = {};
17580 }
17581 # target system type
17582 # needed to adopt HTML report
17583 if(not $DumpSystem)
17584 { # to use in createSymbolsList(...)
Andrey Ponomarenko01117f12012-06-26 12:23:02 +040017585 $OStarget = $ABI->{"Target"};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017586 }
17587 # recreate environment
17588 foreach my $Lib_Name (keys(%{$Library_Symbol{$LibVersion}}))
17589 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040017590 foreach my $Symbol (keys(%{$Library_Symbol{$LibVersion}{$Lib_Name}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017591 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040017592 $Symbol_Library{$LibVersion}{$Symbol} = $Lib_Name;
17593 if($Library_Symbol{$LibVersion}{$Lib_Name}{$Symbol}<=-1)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017594 { # data marked as -size in the dump
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040017595 $GlobalDataObject{$LibVersion}{$Symbol}=1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017596 }
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040017597 if($COMMON_LANGUAGE{$LibVersion} ne "C++")
17598 {
17599 if(index($Symbol, "_Z")==0 or index($Symbol, "?")==0) {
17600 setLanguage($LibVersion, "C++");
17601 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017602 }
17603 }
17604 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040017605 foreach my $Lib_Name (keys(%{$DepLibrary_Symbol{$LibVersion}}))
17606 {
17607 foreach my $Symbol (keys(%{$DepLibrary_Symbol{$LibVersion}{$Lib_Name}})) {
17608 $DepSymbol_Library{$LibVersion}{$Symbol} = $Lib_Name;
17609 }
17610 }
17611
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017612 my @VFunc = ();
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040017613 foreach my $InfoId (keys(%{$SymbolInfo{$LibVersion}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017614 {
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +040017615 if(my $MnglName = $SymbolInfo{$LibVersion}{$InfoId}{"MnglName"})
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040017616 {
17617 if(not $Symbol_Library{$LibVersion}{$MnglName}
17618 and not $DepSymbol_Library{$LibVersion}{$MnglName}) {
17619 push(@VFunc, $MnglName);
17620 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017621 }
17622 }
17623 translateSymbols(@VFunc, $LibVersion);
17624 translateSymbols(keys(%{$Symbol_Library{$LibVersion}}), $LibVersion);
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040017625 translateSymbols(keys(%{$DepSymbol_Library{$LibVersion}}), $LibVersion);
17626
17627 foreach my $TypeId (sort {int($a)<=>int($b)} keys(%{$TypeInfo{$LibVersion}}))
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +040017628 { # order is important
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040017629 if(defined $TypeInfo{$LibVersion}{$TypeId}{"BaseClass"})
17630 { # support for old ABI dumps < 2.0 (ACC 1.22)
17631 foreach my $BId (keys(%{$TypeInfo{$LibVersion}{$TypeId}{"BaseClass"}}))
17632 {
17633 if(my $Access = $TypeInfo{$LibVersion}{$TypeId}{"BaseClass"}{$BId})
17634 {
17635 if($Access ne "public") {
17636 $TypeInfo{$LibVersion}{$TypeId}{"Base"}{$BId}{"access"} = $Access;
17637 }
17638 }
17639 $TypeInfo{$LibVersion}{$TypeId}{"Base"}{$BId} = {};
17640 }
17641 delete($TypeInfo{$LibVersion}{$TypeId}{"BaseClass"});
17642 }
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040017643 if(my $Header = $TypeInfo{$LibVersion}{$TypeId}{"Header"})
17644 { # support for old ABI dumps
17645 $TypeInfo{$LibVersion}{$TypeId}{"Header"} = path_format($Header, $OSgroup);
17646 }
Andrey Ponomarenko01117f12012-06-26 12:23:02 +040017647 if(not defined $TypeInfo{$LibVersion}{$TypeId}{"Tid"}) {
17648 $TypeInfo{$LibVersion}{$TypeId}{"Tid"} = $TypeId;
17649 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040017650 my %TInfo = %{$TypeInfo{$LibVersion}{$TypeId}};
17651 if(defined $TInfo{"Base"})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017652 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040017653 foreach (keys(%{$TInfo{"Base"}})) {
17654 $Class_SubClasses{$LibVersion}{$_}{$TypeId}=1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017655 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040017656 }
Andrey Ponomarenko01117f12012-06-26 12:23:02 +040017657 if($TInfo{"Type"} eq "MethodPtr")
17658 {
17659 if(defined $TInfo{"Param"})
17660 { # support for old ABI dumps <= 1.17
17661 if(not defined $TInfo{"Param"}{"0"})
17662 {
17663 my $Max = keys(%{$TInfo{"Param"}});
17664 foreach my $Pos (1 .. $Max) {
17665 $TInfo{"Param"}{$Pos-1} = $TInfo{"Param"}{$Pos};
17666 }
17667 delete($TInfo{"Param"}{$Max});
17668 %{$TypeInfo{$LibVersion}{$TypeId}} = %TInfo;
17669 }
17670 }
17671 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040017672 if($TInfo{"Type"} eq "Typedef" and defined $TInfo{"BaseType"})
17673 {
17674 if(my $BTid = $TInfo{"BaseType"}{"Tid"})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017675 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040017676 my $BName = $TypeInfo{$LibVersion}{$BTid}{"Name"};
17677 if(not $BName)
17678 { # broken type
17679 next;
17680 }
17681 if($TInfo{"Name"} eq $BName)
17682 { # typedef to "class Class"
17683 # should not be registered in TName_Tid
17684 next;
17685 }
17686 if(not $Typedef_BaseName{$LibVersion}{$TInfo{"Name"}}) {
17687 $Typedef_BaseName{$LibVersion}{$TInfo{"Name"}} = $BName;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017688 }
17689 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040017690 }
17691 if(not $TName_Tid{$LibVersion}{$TInfo{"Name"}})
17692 { # classes: class (id1), typedef (artificial, id2 > id1)
17693 $TName_Tid{$LibVersion}{$TInfo{"Name"}} = $TypeId;
17694 }
17695 }
17696
17697 if(not checkDump($LibVersion, "2.15"))
17698 { # support for old ABI dumps
17699 my %Dups = ();
17700 foreach my $InfoId (keys(%{$SymbolInfo{$LibVersion}}))
17701 {
17702 if(my $ClassId = $SymbolInfo{$LibVersion}{$InfoId}{"Class"})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017703 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040017704 if(not defined $TypeInfo{$LibVersion}{$ClassId})
17705 { # remove template decls
17706 delete($SymbolInfo{$LibVersion}{$InfoId});
17707 next;
Andrey Ponomarenko16934472012-03-29 15:37:04 +040017708 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017709 }
Andrey Ponomarenkob8d203d2012-05-25 18:11:07 +040017710 my $MName = $SymbolInfo{$LibVersion}{$InfoId}{"MnglName"};
17711 if(not $MName and $SymbolInfo{$LibVersion}{$InfoId}{"Class"})
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040017712 { # templates
17713 delete($SymbolInfo{$LibVersion}{$InfoId});
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017714 }
17715 }
17716 }
17717
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +040017718 foreach my $InfoId (keys(%{$SymbolInfo{$LibVersion}}))
17719 {
17720 if(not $SymbolInfo{$LibVersion}{$InfoId}{"MnglName"})
17721 { # ABI dumps have no mangled names for C-functions
17722 $SymbolInfo{$LibVersion}{$InfoId}{"MnglName"} = $SymbolInfo{$LibVersion}{$InfoId}{"ShortName"};
17723 }
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040017724 if(my $Header = $SymbolInfo{$LibVersion}{$InfoId}{"Header"})
17725 { # support for old ABI dumps
17726 $SymbolInfo{$LibVersion}{$InfoId}{"Header"} = path_format($Header, $OSgroup);
17727 }
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +040017728 }
17729
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017730 $Descriptor{$LibVersion}{"Dump"} = 1;
17731}
17732
17733sub read_Machine_DumpInfo($$)
17734{
Andrey Ponomarenko01117f12012-06-26 12:23:02 +040017735 my ($ABI, $LibVersion) = @_;
17736 if($ABI->{"Arch"}) {
17737 $CPU_ARCH{$LibVersion} = $ABI->{"Arch"};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017738 }
Andrey Ponomarenko01117f12012-06-26 12:23:02 +040017739 if($ABI->{"WordSize"}) {
17740 $WORD_SIZE{$LibVersion} = $ABI->{"WordSize"};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017741 }
17742 else
17743 { # support for old dumps
Andrey Ponomarenko01117f12012-06-26 12:23:02 +040017744 $WORD_SIZE{$LibVersion} = $ABI->{"SizeOfPointer"};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017745 }
17746 if(not $WORD_SIZE{$LibVersion})
17747 { # support for old dumps (<1.23)
17748 if(my $Tid = getTypeIdByName("char*", $LibVersion))
17749 { # size of char*
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040017750 $WORD_SIZE{$LibVersion} = $TypeInfo{$LibVersion}{$Tid}{"Size"};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017751 }
17752 else
17753 {
17754 my $PSize = 0;
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040017755 foreach my $Tid (keys(%{$TypeInfo{$LibVersion}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017756 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040017757 if($TypeInfo{$LibVersion}{$Tid}{"Type"} eq "Pointer")
17758 { # any "pointer"-type
17759 $PSize = $TypeInfo{$LibVersion}{$Tid}{"Size"};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017760 last;
17761 }
17762 }
17763 if($PSize)
17764 { # a pointer type size
17765 $WORD_SIZE{$LibVersion} = $PSize;
17766 }
17767 else {
17768 printMsg("WARNING", "cannot identify a WORD size in the ABI dump (too old format)");
17769 }
17770 }
17771 }
Andrey Ponomarenko01117f12012-06-26 12:23:02 +040017772 if($ABI->{"GccVersion"}) {
17773 $GCC_VERSION{$LibVersion} = $ABI->{"GccVersion"};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017774 }
17775}
17776
17777sub read_Libs_DumpInfo($$)
17778{
Andrey Ponomarenko01117f12012-06-26 12:23:02 +040017779 my ($ABI, $LibVersion) = @_;
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040017780 $Library_Symbol{$LibVersion} = $ABI->{"Symbols"};
17781 if(not $Library_Symbol{$LibVersion})
17782 { # support for old dumps
17783 $Library_Symbol{$LibVersion} = $ABI->{"Interfaces"};
17784 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017785 if(keys(%{$Library_Symbol{$LibVersion}})
17786 and not $DumpAPI) {
17787 $Descriptor{$LibVersion}{"Libs"} = "OK";
17788 }
17789}
17790
17791sub read_Headers_DumpInfo($$)
17792{
Andrey Ponomarenko01117f12012-06-26 12:23:02 +040017793 my ($ABI, $LibVersion) = @_;
17794 if(keys(%{$ABI->{"Headers"}})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017795 and not $DumpAPI) {
17796 $Descriptor{$LibVersion}{"Headers"} = "OK";
17797 }
Andrey Ponomarenko01117f12012-06-26 12:23:02 +040017798 foreach my $Identity (sort {$ABI->{"Headers"}{$a}<=>$ABI->{"Headers"}{$b}} keys(%{$ABI->{"Headers"}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017799 { # headers info is stored in the old dumps in the different way
17800 if($UseOldDumps
Andrey Ponomarenko01117f12012-06-26 12:23:02 +040017801 and my $Name = $ABI->{"Headers"}{$Identity}{"Name"})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017802 { # support for old dumps: headers info corrected in 1.22
17803 $Identity = $Name;
17804 }
17805 $Registered_Headers{$LibVersion}{$Identity}{"Identity"} = $Identity;
Andrey Ponomarenko01117f12012-06-26 12:23:02 +040017806 $Registered_Headers{$LibVersion}{$Identity}{"Pos"} = $ABI->{"Headers"}{$Identity};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017807 }
17808}
17809
17810sub find_libs($$$)
17811{
17812 my ($Path, $Type, $MaxDepth) = @_;
17813 # FIXME: correct the search pattern
17814 return cmd_find($Path, $Type, ".*\\.$LIB_EXT\[0-9.]*", $MaxDepth);
17815}
17816
17817sub createDescriptor($$)
17818{
17819 my ($LibVersion, $Path) = @_;
17820 if(not $LibVersion or not $Path
17821 or not -e $Path) {
17822 return "";
17823 }
17824 if(-d $Path)
17825 { # directory with headers files and shared objects
17826 return "
17827 <version>
17828 ".$TargetVersion{$LibVersion}."
17829 </version>
17830
17831 <headers>
17832 $Path
17833 </headers>
17834
17835 <libs>
17836 $Path
17837 </libs>";
17838 }
17839 else
17840 { # files
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040017841 if($Path=~/\.(xml|desc)\Z/i)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017842 { # standard XML-descriptor
17843 return readFile($Path);
17844 }
17845 elsif(is_header($Path, 2, $LibVersion))
17846 { # header file
17847 return "
17848 <version>
17849 ".$TargetVersion{$LibVersion}."
17850 </version>
17851
17852 <headers>
17853 $Path
17854 </headers>
17855
17856 <libs>
17857 none
17858 </libs>";
17859 }
17860 elsif(parse_libname($Path, "name", $OStarget))
17861 { # shared object
17862 return "
17863 <version>
17864 ".$TargetVersion{$LibVersion}."
17865 </version>
17866
17867 <headers>
17868 none
17869 </headers>
17870
17871 <libs>
17872 $Path
17873 </libs>";
17874 }
17875 else
17876 { # standard XML-descriptor
17877 return readFile($Path);
17878 }
17879 }
17880}
17881
17882sub detect_lib_default_paths()
17883{
17884 my %LPaths = ();
17885 if($OSgroup eq "bsd")
17886 {
Andrey Ponomarenkoa01311b2012-06-08 17:20:02 +040017887 if(my $LdConfig = get_CmdPath("ldconfig"))
17888 {
17889 foreach my $Line (split(/\n/, `$LdConfig -r 2>\"$TMP_DIR/null\"`))
17890 {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017891 if($Line=~/\A[ \t]*\d+:\-l(.+) \=\> (.+)\Z/) {
17892 $LPaths{"lib".$1} = $2;
17893 }
17894 }
17895 }
17896 else {
17897 printMsg("WARNING", "can't find ldconfig");
17898 }
17899 }
17900 else
17901 {
17902 if(my $LdConfig = get_CmdPath("ldconfig"))
17903 {
17904 if($SystemRoot and $OSgroup eq "linux")
17905 { # use host (x86) ldconfig with the target (arm) ld.so.conf
17906 if(-e $SystemRoot."/etc/ld.so.conf") {
17907 $LdConfig .= " -f ".$SystemRoot."/etc/ld.so.conf";
17908 }
17909 }
Andrey Ponomarenkoa01311b2012-06-08 17:20:02 +040017910 foreach my $Line (split(/\n/, `$LdConfig -p 2>\"$TMP_DIR/null\"`))
17911 {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017912 if($Line=~/\A[ \t]*([^ \t]+) .* \=\> (.+)\Z/)
17913 {
17914 my ($Name, $Path) = ($1, $2);
17915 $Path=~s/[\/]{2,}/\//;
17916 $LPaths{$Name} = $Path;
17917 }
17918 }
17919 }
17920 elsif($OSgroup=~/linux/i) {
17921 printMsg("WARNING", "can't find ldconfig");
17922 }
17923 }
17924 return \%LPaths;
17925}
17926
17927sub detect_bin_default_paths()
17928{
17929 my $EnvPaths = $ENV{"PATH"};
17930 if($OSgroup eq "beos") {
17931 $EnvPaths.=":".$ENV{"BETOOLS"};
17932 }
17933 my $Sep = ($OSgroup eq "windows")?";":":|;";
17934 foreach my $Path (sort {length($a)<=>length($b)} split(/$Sep/, $EnvPaths))
17935 {
17936 $Path = path_format($Path, $OSgroup);
17937 $Path=~s/[\/\\]+\Z//g;
17938 next if(not $Path);
17939 if($SystemRoot
17940 and $Path=~/\A\Q$SystemRoot\E\//)
17941 { # do NOT use binaries from target system
17942 next;
17943 }
17944 $DefaultBinPaths{$Path} = 1;
17945 }
17946}
17947
17948sub detect_inc_default_paths()
17949{
17950 return () if(not $GCC_PATH);
17951 my %DPaths = ("Cpp"=>{},"Gcc"=>{},"Inc"=>{});
17952 writeFile("$TMP_DIR/empty.h", "");
Andrey Ponomarenkoa01311b2012-06-08 17:20:02 +040017953 foreach my $Line (split(/\n/, `$GCC_PATH -v -x c++ -E \"$TMP_DIR/empty.h\" 2>&1`))
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040017954 { # detecting GCC default include paths
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017955 if($Line=~/\A[ \t]*((\/|\w+:\\).+)[ \t]*\Z/)
17956 {
17957 my $Path = simplify_path($1);
17958 $Path=~s/[\/\\]+\Z//g;
17959 $Path = path_format($Path, $OSgroup);
17960 if($Path=~/c\+\+|\/g\+\+\//)
17961 {
17962 $DPaths{"Cpp"}{$Path}=1;
17963 if(not defined $MAIN_CPP_DIR
17964 or get_depth($MAIN_CPP_DIR)>get_depth($Path)) {
17965 $MAIN_CPP_DIR = $Path;
17966 }
17967 }
17968 elsif($Path=~/gcc/) {
17969 $DPaths{"Gcc"}{$Path}=1;
17970 }
17971 else
17972 {
17973 next if($Path=~/local[\/\\]+include/);
17974 if($SystemRoot
17975 and $Path!~/\A\Q$SystemRoot\E(\/|\Z)/)
17976 { # The GCC include path for user headers is not a part of the system root
17977 # The reason: you are not specified the --cross-gcc option or selected a wrong compiler
17978 # or it is the internal cross-GCC path like arm-linux-gnueabi/include
17979 next;
17980 }
17981 $DPaths{"Inc"}{$Path}=1;
17982 }
17983 }
17984 }
17985 unlink("$TMP_DIR/empty.h");
17986 return %DPaths;
17987}
17988
17989sub detect_default_paths($)
17990{
17991 my ($HSearch, $LSearch, $BSearch, $GSearch) = (1, 1, 1, 1);
17992 my $Search = $_[0];
17993 if($Search!~/inc/) {
17994 $HSearch = 0;
17995 }
17996 if($Search!~/lib/) {
17997 $LSearch = 0;
17998 }
17999 if($Search!~/bin/) {
18000 $BSearch = 0;
18001 }
18002 if($Search!~/gcc/) {
18003 $GSearch = 0;
18004 }
18005 if(keys(%{$SystemPaths{"include"}}))
18006 { # <search_headers> section of the XML descriptor
18007 # do NOT search for systems headers
18008 $HSearch = 0;
18009 }
18010 if(keys(%{$SystemPaths{"lib"}}))
18011 { # <search_headers> section of the XML descriptor
18012 # do NOT search for systems headers
18013 $LSearch = 0;
18014 }
18015 foreach my $Type (keys(%{$OS_AddPath{$OSgroup}}))
18016 { # additional search paths
18017 next if($Type eq "include" and not $HSearch);
18018 next if($Type eq "lib" and not $LSearch);
18019 next if($Type eq "bin" and not $BSearch);
18020 foreach my $Path (keys(%{$OS_AddPath{$OSgroup}{$Type}}))
18021 {
18022 next if(not -d $Path);
18023 $SystemPaths{$Type}{$Path} = $OS_AddPath{$OSgroup}{$Type}{$Path};
18024 }
18025 }
18026 if($OSgroup ne "windows")
18027 { # unix-like
18028 foreach my $Type ("include", "lib", "bin")
18029 { # automatic detection of system "devel" directories
18030 next if($Type eq "include" and not $HSearch);
18031 next if($Type eq "lib" and not $LSearch);
18032 next if($Type eq "bin" and not $BSearch);
18033 my ($UsrDir, $RootDir) = ("/usr", "/");
18034 if($SystemRoot and $Type ne "bin")
18035 { # 1. search for target headers and libraries
18036 # 2. use host commands: ldconfig, readelf, etc.
18037 ($UsrDir, $RootDir) = ("$SystemRoot/usr", $SystemRoot);
18038 }
18039 foreach my $Path (cmd_find($RootDir,"d","*$Type*",1)) {
18040 $SystemPaths{$Type}{$Path} = 1;
18041 }
18042 if(-d $RootDir."/".$Type)
18043 { # if "/lib" is symbolic link
18044 if($RootDir eq "/") {
18045 $SystemPaths{$Type}{"/".$Type} = 1;
18046 }
18047 else {
18048 $SystemPaths{$Type}{$RootDir."/".$Type} = 1;
18049 }
18050 }
18051 if(-d $UsrDir) {
18052 foreach my $Path (cmd_find($UsrDir,"d","*$Type*",1)) {
18053 $SystemPaths{$Type}{$Path} = 1;
18054 }
18055 if(-d $UsrDir."/".$Type)
18056 { # if "/usr/lib" is symbolic link
18057 $SystemPaths{$Type}{$UsrDir."/".$Type} = 1;
18058 }
18059 }
18060 }
18061 }
18062 if($BSearch)
18063 {
18064 detect_bin_default_paths();
18065 foreach my $Path (keys(%DefaultBinPaths)) {
18066 $SystemPaths{"bin"}{$Path} = $DefaultBinPaths{$Path};
18067 }
18068 }
18069 # check environment variables
18070 if($OSgroup eq "beos")
18071 {
18072 foreach (keys(%{$SystemPaths{"bin"}}))
18073 {
18074 if($_ eq ".") {
18075 next;
18076 }
18077 foreach my $Path (cmd_find($_, "d", "bin", ""))
18078 { # search for /boot/develop/abi/x86/gcc4/tools/gcc-4.4.4-haiku-101111/bin/
18079 $SystemPaths{"bin"}{$Path} = 1;
18080 }
18081 }
18082 if($HSearch)
18083 {
18084 foreach my $Path (split(/:|;/, $ENV{"BEINCLUDES"}))
18085 {
18086 if(is_abs($Path)) {
18087 $DefaultIncPaths{$Path} = 1;
18088 }
18089 }
18090 }
18091 if($LSearch)
18092 {
18093 foreach my $Path (split(/:|;/, $ENV{"BELIBRARIES"}), split(/:|;/, $ENV{"LIBRARY_PATH"}))
18094 {
18095 if(is_abs($Path)) {
18096 $DefaultLibPaths{$Path} = 1;
18097 }
18098 }
18099 }
18100 }
18101 if($LSearch)
18102 { # using linker to get system paths
18103 if(my $LPaths = detect_lib_default_paths())
18104 { # unix-like
18105 foreach my $Name (keys(%{$LPaths}))
18106 {
18107 if($SystemRoot
18108 and $LPaths->{$Name}!~/\A\Q$SystemRoot\E\//)
18109 { # wrong ldconfig configuration
18110 # check your <sysroot>/etc/ld.so.conf
18111 next;
18112 }
18113 $DyLib_DefaultPath{$Name} = $LPaths->{$Name};
18114 $DefaultLibPaths{get_dirname($LPaths->{$Name})} = 1;
18115 }
18116 }
18117 foreach my $Path (keys(%DefaultLibPaths)) {
18118 $SystemPaths{"lib"}{$Path} = $DefaultLibPaths{$Path};
18119 }
18120 }
18121 if($BSearch)
18122 {
18123 if($CrossGcc)
18124 { # --cross-gcc=arm-linux-gcc
18125 if(-e $CrossGcc)
18126 { # absolute or relative path
18127 $GCC_PATH = get_abs_path($CrossGcc);
18128 }
18129 elsif($CrossGcc!~/\// and get_CmdPath($CrossGcc))
18130 { # command name
18131 $GCC_PATH = $CrossGcc;
18132 }
18133 else {
18134 exitStatus("Access_Error", "can't access \'$CrossGcc\'");
18135 }
18136 if($GCC_PATH=~/\s/) {
18137 $GCC_PATH = "\"".$GCC_PATH."\"";
18138 }
18139 }
18140 }
18141 if($GSearch)
18142 { # GCC path and default include dirs
18143 if(not $CrossGcc) {
18144 $GCC_PATH = get_CmdPath("gcc");
18145 }
Andrey Ponomarenko01117f12012-06-26 12:23:02 +040018146 if(not $GCC_PATH)
18147 { # try to find gcc-X.Y
18148 foreach my $Path (sort {$b=~/\/usr\/bin/ cmp $a=~/\/usr\/bin/}
18149 keys(%{$SystemPaths{"bin"}}))
18150 {
18151 if(my @GCCs = cmd_find($Path, "", ".*/gcc-[0-9.]*", 1))
18152 { # select the latest version
18153 @GCCs = sort {$b cmp $a} @GCCs;
18154 if(check_gcc($GCCs[0], "3"))
18155 {
18156 $GCC_PATH = $GCCs[0];
18157 last;
18158 }
18159 }
18160 }
18161 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040018162 if(not $GCC_PATH) {
18163 exitStatus("Not_Found", "can't find GCC>=3.0 in PATH");
18164 }
18165 if(not $CheckObjectsOnly_Opt)
18166 {
18167 if(my $GCC_Ver = get_dumpversion($GCC_PATH))
18168 {
18169 my $GccTarget = get_dumpmachine($GCC_PATH);
18170 printMsg("INFO", "Using GCC $GCC_Ver ($GccTarget)");
18171 if($GccTarget=~/symbian/)
18172 {
18173 $OStarget = "symbian";
18174 $LIB_EXT = $OS_LibExt{$LIB_TYPE}{$OStarget};
18175 }
18176 }
18177 else {
18178 exitStatus("Error", "something is going wrong with the GCC compiler");
18179 }
18180 }
18181 if(not $NoStdInc)
18182 { # do NOT search in GCC standard paths
18183 my %DPaths = detect_inc_default_paths();
18184 %DefaultCppPaths = %{$DPaths{"Cpp"}};
18185 %DefaultGccPaths = %{$DPaths{"Gcc"}};
18186 %DefaultIncPaths = %{$DPaths{"Inc"}};
18187 foreach my $Path (keys(%DefaultIncPaths)) {
18188 $SystemPaths{"include"}{$Path} = $DefaultIncPaths{$Path};
18189 }
18190 }
18191 }
18192 if($HSearch)
18193 { # user include paths
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040018194 my $IncPath = "/usr/include";
18195 if($SystemRoot) {
18196 $IncPath = $SystemRoot.$IncPath;
18197 }
18198 if(-d $IncPath) {
18199 $UserIncPath{$IncPath}=1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040018200 }
18201 }
18202}
18203
18204sub getLIB_EXT($)
18205{
18206 my $Target = $_[0];
18207 if(my $Ext = $OS_LibExt{$LIB_TYPE}{$Target}) {
18208 return $Ext;
18209 }
18210 return $OS_LibExt{$LIB_TYPE}{"default"};
18211}
18212
18213sub getAR_EXT($)
18214{
18215 my $Target = $_[0];
18216 if(my $Ext = $OS_Archive{$Target}) {
18217 return $Ext;
18218 }
18219 return $OS_Archive{"default"};
18220}
18221
18222sub get_dumpversion($)
18223{
18224 my $Cmd = $_[0];
18225 return "" if(not $Cmd);
18226 if($Cache{"get_dumpversion"}{$Cmd}) {
18227 return $Cache{"get_dumpversion"}{$Cmd};
18228 }
Andrey Ponomarenkoa01311b2012-06-08 17:20:02 +040018229 my $V = `$Cmd -dumpversion 2>\"$TMP_DIR/null\"`;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040018230 chomp($V);
18231 return ($Cache{"get_dumpversion"}{$Cmd} = $V);
18232}
18233
18234sub get_dumpmachine($)
18235{
18236 my $Cmd = $_[0];
18237 return "" if(not $Cmd);
18238 if($Cache{"get_dumpmachine"}{$Cmd}) {
18239 return $Cache{"get_dumpmachine"}{$Cmd};
18240 }
Andrey Ponomarenkoa01311b2012-06-08 17:20:02 +040018241 my $Machine = `$Cmd -dumpmachine 2>\"$TMP_DIR/null\"`;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040018242 chomp($Machine);
18243 return ($Cache{"get_dumpmachine"}{$Cmd} = $Machine);
18244}
18245
18246sub check_command($)
18247{
18248 my $Cmd = $_[0];
18249 return "" if(not $Cmd);
18250 my @Options = (
18251 "--version",
18252 "-help"
18253 );
18254 foreach my $Opt (@Options)
18255 {
Andrey Ponomarenkoa01311b2012-06-08 17:20:02 +040018256 my $Info = `$Cmd $Opt 2>\"$TMP_DIR/null\"`;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040018257 if($Info) {
18258 return 1;
18259 }
18260 }
18261 return 0;
18262}
18263
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040018264sub check_gcc($$)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040018265{
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040018266 my ($Cmd, $ReqVer) = @_;
18267 return 0 if(not $Cmd or not $ReqVer);
18268 if(defined $Cache{"check_gcc"}{$Cmd}{$ReqVer}) {
18269 return $Cache{"check_gcc"}{$Cmd}{$ReqVer};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040018270 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040018271 if(my $GccVer = get_dumpversion($Cmd))
18272 {
18273 $GccVer=~s/(-|_)[a-z_]+.*\Z//; # remove suffix (like "-haiku-100818")
18274 if(cmpVersions($GccVer, $ReqVer)>=0) {
18275 return ($Cache{"check_gcc"}{$Cmd}{$ReqVer} = $Cmd);
18276 }
18277 }
18278 return ($Cache{"check_gcc"}{$Cmd}{$ReqVer} = "");
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040018279}
18280
18281sub get_depth($)
18282{
18283 if(defined $Cache{"get_depth"}{$_[0]}) {
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040018284 return $Cache{"get_depth"}{$_[0]};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040018285 }
18286 return ($Cache{"get_depth"}{$_[0]} = ($_[0]=~tr![\/\\]|\:\:!!));
18287}
18288
18289sub find_gcc_cxx_headers($)
18290{
18291 my $LibVersion = $_[0];
18292 return if($Cache{"find_gcc_cxx_headers"});# this function should be called once
18293 # detecting system header paths
18294 foreach my $Path (sort {get_depth($b) <=> get_depth($a)} keys(%DefaultGccPaths))
18295 {
18296 foreach my $HeaderPath (sort {get_depth($a) <=> get_depth($b)} cmd_find($Path,"f","",""))
18297 {
18298 my $FileName = get_filename($HeaderPath);
18299 next if($DefaultGccHeader{$FileName});
18300 $DefaultGccHeader{$FileName} = $HeaderPath;
18301 }
18302 }
18303 if($COMMON_LANGUAGE{$LibVersion} eq "C++" and not $STDCXX_TESTING)
18304 {
18305 foreach my $CppDir (sort {get_depth($b)<=>get_depth($a)} keys(%DefaultCppPaths))
18306 {
18307 my @AllCppHeaders = cmd_find($CppDir,"f","","");
18308 foreach my $Path (sort {get_depth($a)<=>get_depth($b)} @AllCppHeaders)
18309 {
18310 my $FileName = get_filename($Path);
18311 next if($DefaultCppHeader{$FileName});
18312 $DefaultCppHeader{$FileName} = $Path;
18313 }
18314 }
18315 }
18316 $Cache{"find_gcc_cxx_headers"} = 1;
18317}
18318
18319sub parse_libname($$$)
18320{
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040018321 return "" if(not $_[0]);
18322 if(defined $Cache{"parse_libname"}{$_[2]}{$_[1]}{$_[0]}) {
18323 return $Cache{"parse_libname"}{$_[2]}{$_[1]}{$_[0]};
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040018324 }
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040018325 return ($Cache{"parse_libname"}{$_[2]}{$_[1]}{$_[0]} = parse_libname_I(@_));
18326}
18327
18328sub parse_libname_I($$$)
18329{
18330 my ($Name, $Type, $Target) = @_;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040018331 if($Target eq "symbian") {
18332 return parse_libname_symbian($Name, $Type);
18333 }
18334 elsif($Target eq "windows") {
18335 return parse_libname_windows($Name, $Type);
18336 }
18337 my $Ext = getLIB_EXT($Target);
Andrey Ponomarenkoa01311b2012-06-08 17:20:02 +040018338 if($Name=~/((((lib|).+?)([\-\_][\d\-\.\_]+.*?|))\.$Ext)(\.(.+)|)\Z/)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040018339 { # libSDL-1.2.so.0.7.1
18340 # libwbxml2.so.0.0.18
Andrey Ponomarenkoa01311b2012-06-08 17:20:02 +040018341 # libopcodes-2.21.53-system.20110810.so
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040018342 if($Type eq "name")
18343 { # libSDL-1.2
18344 # libwbxml2
18345 return $2;
18346 }
18347 elsif($Type eq "name+ext")
18348 { # libSDL-1.2.so
18349 # libwbxml2.so
18350 return $1;
18351 }
18352 elsif($Type eq "version")
18353 {
Andrey Ponomarenkoa01311b2012-06-08 17:20:02 +040018354 if(defined $7
18355 and $7 ne "")
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040018356 { # 0.7.1
18357 return $7;
18358 }
18359 else
18360 { # libc-2.5.so (=>2.5 version)
18361 my $MV = $5;
18362 $MV=~s/\A[\-\_]+//g;
18363 return $MV;
18364 }
18365 }
18366 elsif($Type eq "short")
18367 { # libSDL
18368 # libwbxml2
18369 return $3;
18370 }
18371 elsif($Type eq "shortest")
18372 { # SDL
18373 # wbxml
18374 return shortest_name($3);
18375 }
18376 }
18377 return "";# error
18378}
18379
18380sub parse_libname_symbian($$)
18381{
18382 my ($Name, $Type) = @_;
18383 my $Ext = getLIB_EXT("symbian");
18384 if($Name=~/(((.+?)(\{.+\}|))\.$Ext)\Z/)
18385 { # libpthread{00010001}.dso
18386 if($Type eq "name")
18387 { # libpthread{00010001}
18388 return $2;
18389 }
18390 elsif($Type eq "name+ext")
18391 { # libpthread{00010001}.dso
18392 return $1;
18393 }
18394 elsif($Type eq "version")
18395 { # 00010001
18396 my $V = $4;
18397 $V=~s/\{(.+)\}/$1/;
18398 return $V;
18399 }
18400 elsif($Type eq "short")
18401 { # libpthread
18402 return $3;
18403 }
18404 elsif($Type eq "shortest")
18405 { # pthread
18406 return shortest_name($3);
18407 }
18408 }
18409 return "";# error
18410}
18411
18412sub parse_libname_windows($$)
18413{
18414 my ($Name, $Type) = @_;
18415 my $Ext = getLIB_EXT("windows");
18416 if($Name=~/((.+?)\.$Ext)\Z/)
18417 { # netapi32.dll
18418 if($Type eq "name")
18419 { # netapi32
18420 return $2;
18421 }
18422 elsif($Type eq "name+ext")
18423 { # netapi32.dll
18424 return $1;
18425 }
18426 elsif($Type eq "version")
18427 { # DLL version embedded
18428 # at binary-level
18429 return "";
18430 }
18431 elsif($Type eq "short")
18432 { # netapi32
18433 return $2;
18434 }
18435 elsif($Type eq "shortest")
18436 { # netapi
18437 return shortest_name($2);
18438 }
18439 }
18440 return "";# error
18441}
18442
18443sub shortest_name($)
18444{
18445 my $Name = $_[0];
18446 # remove prefix
18447 $Name=~s/\A(lib|open)//;
18448 # remove suffix
18449 $Name=~s/[\W\d_]+\Z//i;
18450 $Name=~s/([a-z]{2,})(lib)\Z/$1/i;
18451 return $Name;
18452}
18453
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040018454sub createSymbolsList($$$$$)
18455{
18456 my ($DPath, $SaveTo, $LName, $LVersion, $ArchName) = @_;
18457 read_ABI_Dump(1, $DPath);
18458 if(not $CheckObjectsOnly) {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040018459 prepareSymbols(1);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040018460 }
18461 my %SymbolHeaderLib = ();
18462 my $Total = 0;
18463 # Get List
18464 foreach my $Symbol (sort keys(%{$CompleteSignature{1}}))
18465 {
18466 if(not link_symbol($Symbol, 1, "-Deps"))
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040018467 { # skip src only and all external functions
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040018468 next;
18469 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040018470 if(not symbolFilter($Symbol, 1, "Public", "Binary"))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040018471 { # skip other symbols
18472 next;
18473 }
18474 my $HeaderName = $CompleteSignature{1}{$Symbol}{"Header"};
18475 if(not $HeaderName)
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040018476 { # skip src only and all external functions
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040018477 next;
18478 }
18479 my $DyLib = $Symbol_Library{1}{$Symbol};
18480 if(not $DyLib)
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040018481 { # skip src only and all external functions
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040018482 next;
18483 }
18484 $SymbolHeaderLib{$HeaderName}{$DyLib}{$Symbol} = 1;
18485 $Total+=1;
18486 }
18487 # Draw List
18488 my $SYMBOLS_LIST = "<h1>Public symbols in <span style='color:Blue;'>$LName</span> (<span style='color:Red;'>$LVersion</span>)";
18489 $SYMBOLS_LIST .= " on <span style='color:Blue;'>".showArch($ArchName)."</span><br/>Total: $Total</h1><br/>";
18490 foreach my $HeaderName (sort {lc($a) cmp lc($b)} keys(%SymbolHeaderLib))
18491 {
18492 foreach my $DyLib (sort {lc($a) cmp lc($b)} keys(%{$SymbolHeaderLib{$HeaderName}}))
18493 {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040018494 my %NS_Symbol = ();
18495 foreach my $Symbol (keys(%{$SymbolHeaderLib{$HeaderName}{$DyLib}})) {
18496 $NS_Symbol{get_IntNameSpace($Symbol, 1)}{$Symbol} = 1;
18497 }
18498 foreach my $NameSpace (sort keys(%NS_Symbol))
18499 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040018500 $SYMBOLS_LIST .= getTitle($HeaderName, $DyLib, $NameSpace);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040018501 my @SortedInterfaces = sort {lc(get_Signature($a, 1)) cmp lc(get_Signature($b, 1))} keys(%{$NS_Symbol{$NameSpace}});
18502 foreach my $Symbol (@SortedInterfaces)
18503 {
18504 my $SubReport = "";
18505 my $Signature = get_Signature($Symbol, 1);
18506 if($NameSpace) {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040018507 $Signature=~s/\b\Q$NameSpace\E::\b//g;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040018508 }
18509 if($Symbol=~/\A(_Z|\?)/)
18510 {
18511 if($Signature) {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040018512 $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 +040018513 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040018514 else {
18515 $SubReport = "<span class='iname'>".$Symbol."</span><br/>\n";
18516 }
18517 }
18518 else
18519 {
18520 if($Signature) {
18521 $SubReport = "<span class='iname'>".highLight_Signature_Italic_Color($Signature)."</span><br/>\n";
18522 }
18523 else {
18524 $SubReport = "<span class='iname'>".$Symbol."</span><br/>\n";
18525 }
18526 }
18527 $SYMBOLS_LIST .= $SubReport;
18528 }
18529 }
18530 $SYMBOLS_LIST .= "<br/>\n";
18531 }
18532 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040018533 # clear info
18534 (%TypeInfo, %SymbolInfo, %Library_Symbol, %DepSymbol_Library,
18535 %DepLibrary_Symbol, %SymVer, %SkipTypes, %SkipSymbols,
18536 %NestedNameSpaces, %ClassMethods, %AllocableClass, %ClassNames,
18537 %CompleteSignature, %SkipNameSpaces, %Symbol_Library, %Library_Symbol) = ();
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040018538 ($Content_Counter, $ContentID) = (0, 0);
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040018539 # print report
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040018540 my $CssStyles = readModule("Styles", "SymbolsList.css");
18541 my $JScripts = readModule("Scripts", "Sections.js");
18542 $SYMBOLS_LIST = "<a name='Top'></a>".$SYMBOLS_LIST.$TOP_REF."<br/>\n";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040018543 my $Title = "$LName: public symbols";
18544 my $Keywords = "$LName, API, symbols";
18545 my $Description = "List of symbols in $LName ($LVersion) on ".showArch($ArchName);
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040018546 $SYMBOLS_LIST = composeHTML_Head($Title, $Keywords, $Description, $CssStyles, $JScripts)."
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040018547 <body><div>\n$SYMBOLS_LIST</div>
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040018548 <br/><br/><hr/>\n".getReportFooter($LName, 1)."
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040018549 <div style='height:999px;'></div></body></html>";
18550 writeFile($SaveTo, $SYMBOLS_LIST);
18551}
18552
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040018553sub readModule($$)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040018554{
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040018555 my ($Module, $Name) = @_;
18556 my $Path = $MODULES_DIR."/Internals/$Module/".$Name;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040018557 if(not -f $Path) {
18558 exitStatus("Module_Error", "can't access \'$Path\'");
18559 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040018560 return readFile($Path);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040018561}
18562
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040018563sub add_target_libs($)
18564{
18565 foreach (@{$_[0]}) {
18566 $TargetLibs{$_} = 1;
18567 }
18568}
18569
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040018570sub is_target_lib($)
18571{
18572 my $LName = $_[0];
Andrey Ponomarenkoa01311b2012-06-08 17:20:02 +040018573 if(not $LName) {
18574 return 0;
18575 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040018576 if($TargetLibraryName
18577 and $LName!~/\Q$TargetLibraryName\E/) {
18578 return 0;
18579 }
18580 if(keys(%TargetLibs)
18581 and not $TargetLibs{$LName}
18582 and not $TargetLibs{parse_libname($LName, "name+ext", $OStarget)}) {
18583 return 0;
18584 }
18585 return 1;
18586}
18587
Andrey Ponomarenko85043792012-05-14 16:48:07 +040018588sub is_target_header($$)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040018589{ # --header, --headers-list
Andrey Ponomarenko85043792012-05-14 16:48:07 +040018590 my ($H, $V) = @_;
18591 if(keys(%{$TargetHeaders{$V}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040018592 {
Andrey Ponomarenko85043792012-05-14 16:48:07 +040018593 if($TargetHeaders{$V}{$H}) {
18594 return 1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040018595 }
18596 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +040018597 return 0;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040018598}
18599
18600sub checkVersionNum($$)
18601{
18602 my ($LibVersion, $Path) = @_;
18603 if(my $VerNum = $TargetVersion{$LibVersion}) {
18604 return $VerNum;
18605 }
18606 my $UsedAltDescr = 0;
18607 foreach my $Part (split(/\s*,\s*/, $Path))
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040018608 { # try to get version string from file path
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040018609 next if(isDump($Part)); # ABI dump
18610 next if($Part=~/\.(xml|desc)\Z/i); # XML descriptor
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040018611 my $VerNum = "";
18612 if(parse_libname($Part, "name", $OStarget))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040018613 {
18614 $UsedAltDescr = 1;
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040018615 $VerNum = parse_libname($Part, "version", $OStarget);
18616 if(not $VerNum) {
18617 $VerNum = readStringVersion($Part);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040018618 }
18619 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040018620 elsif(is_header($Part, 2, $LibVersion) or -d $Part)
18621 {
18622 $UsedAltDescr = 1;
18623 $VerNum = readStringVersion($Part);
18624 }
18625 if($VerNum ne "")
18626 {
18627 $TargetVersion{$LibVersion} = $VerNum;
18628 if($DumpAPI) {
18629 printMsg("WARNING", "setting version number to $VerNum (use -vnum <num> option to change it)");
18630 }
18631 else {
18632 printMsg("WARNING", "setting ".($LibVersion==1?"1st":"2nd")." version number to \"$VerNum\" (use -v$LibVersion <num> option to change it)");
18633 }
18634 return $TargetVersion{$LibVersion};
18635 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040018636 }
18637 if($UsedAltDescr)
18638 {
18639 if($DumpAPI) {
18640 exitStatus("Error", "version number is not set (use -vnum <num> option)");
18641 }
18642 else {
18643 exitStatus("Error", ($LibVersion==1?"1st":"2nd")." version number is not set (use -v$LibVersion <num> option)");
18644 }
18645 }
18646}
18647
18648sub readStringVersion($)
18649{
18650 my $Str = $_[0];
18651 return "" if(not $Str);
18652 $Str=~s/\Q$TargetLibraryName\E//g;
18653 if($Str=~/(\/|\\|\w|\A)[\-\_]*(\d+[\d\.\-]+\d+|\d+)/)
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040018654 { # .../libssh-0.4.0/...
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040018655 return $2;
18656 }
18657 elsif(my $V = parse_libname($Str, "version", $OStarget)) {
18658 return $V;
18659 }
18660 return "";
18661}
18662
18663sub readLibs($)
18664{
18665 my $LibVersion = $_[0];
18666 if($OStarget eq "windows")
18667 { # dumpbin.exe will crash
18668 # without VS Environment
18669 check_win32_env();
18670 }
Andrey Ponomarenko16934472012-03-29 15:37:04 +040018671 readSymbols($LibVersion);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040018672 translateSymbols(keys(%{$Symbol_Library{$LibVersion}}), $LibVersion);
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040018673 translateSymbols(keys(%{$DepSymbol_Library{$LibVersion}}), $LibVersion);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040018674}
18675
18676sub dump_sorting($)
18677{
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +040018678 my $Hash = $_[0];
18679 return [] if(not $Hash);
18680 my @Keys = keys(%{$Hash});
18681 return [] if($#Keys<0);
18682 if($Keys[0]=~/\A\d+\Z/)
18683 { # numbers
18684 return [sort {int($a)<=>int($b)} @Keys];
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040018685 }
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +040018686 else
18687 { # strings
18688 return [sort {$a cmp $b} @Keys];
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040018689 }
18690}
18691
18692sub printMsg($$)
18693{
18694 my ($Type, $Msg) = @_;
18695 if($Type!~/\AINFO/) {
18696 $Msg = $Type.": ".$Msg;
18697 }
18698 if($Type!~/_C\Z/) {
18699 $Msg .= "\n";
18700 }
18701 if($Quiet)
18702 { # --quiet option
18703 appendFile($COMMON_LOG_PATH, $Msg);
18704 }
18705 else
18706 {
18707 if($Type eq "ERROR") {
18708 print STDERR $Msg;
18709 }
18710 else {
18711 print $Msg;
18712 }
18713 }
18714}
18715
18716sub exitStatus($$)
18717{
18718 my ($Code, $Msg) = @_;
18719 printMsg("ERROR", $Msg);
18720 exit($ERROR_CODE{$Code});
18721}
18722
18723sub exitReport()
18724{ # the tool has run without any errors
18725 printReport();
18726 if($COMPILE_ERRORS)
18727 { # errors in headers may add false positives/negatives
18728 exit($ERROR_CODE{"Compile_Error"});
18729 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040018730 if($BinaryOnly and $RESULT{"Binary"}{"Problems"})
18731 { # --binary
18732 exit($ERROR_CODE{"Incompatible"});
18733 }
18734 elsif($SourceOnly and $RESULT{"Source"}{"Problems"})
18735 { # --source
18736 exit($ERROR_CODE{"Incompatible"});
18737 }
18738 elsif($RESULT{"Source"}{"Problems"}
18739 or $RESULT{"Binary"}{"Problems"})
18740 { # default
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040018741 exit($ERROR_CODE{"Incompatible"});
18742 }
18743 else {
18744 exit($ERROR_CODE{"Compatible"});
18745 }
18746}
18747
18748sub readRules($)
18749{
18750 my $Kind = $_[0];
18751 if(not -f $RULES_PATH{$Kind}) {
18752 exitStatus("Module_Error", "can't access \'".$RULES_PATH{$Kind}."\'");
18753 }
18754 my $Content = readFile($RULES_PATH{$Kind});
18755 while(my $Rule = parseTag(\$Content, "rule"))
18756 {
18757 my $RId = parseTag(\$Rule, "id");
18758 my @Properties = ("Severity", "Change", "Effect", "Overcome", "Kind");
18759 foreach my $Prop (@Properties) {
18760 if(my $Value = parseTag(\$Rule, lc($Prop)))
18761 {
18762 $Value=~s/\n[ ]*//;
18763 $CompatRules{$Kind}{$RId}{$Prop} = $Value;
18764 }
18765 }
18766 if($CompatRules{$Kind}{$RId}{"Kind"}=~/\A(Symbols|Parameters)\Z/) {
18767 $CompatRules{$Kind}{$RId}{"Kind"} = "Symbols";
18768 }
18769 else {
18770 $CompatRules{$Kind}{$RId}{"Kind"} = "Types";
18771 }
18772 }
18773}
18774
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040018775sub getReportPath($)
18776{
18777 my $Level = $_[0];
18778 my $Dir = "compat_reports/$TargetLibraryName/".$Descriptor{1}{"Version"}."_to_".$Descriptor{2}{"Version"};
18779 if($Level eq "Binary")
18780 {
18781 if($BinaryReportPath)
18782 { # --bin-report-path
18783 return $BinaryReportPath;
18784 }
18785 elsif($OutputReportPath)
18786 { # --report-path
18787 return $OutputReportPath;
18788 }
18789 else
18790 { # default
18791 return $Dir."/abi_compat_report.$ReportFormat";
18792 }
18793 }
18794 elsif($Level eq "Source")
18795 {
18796 if($SourceReportPath)
18797 { # --src-report-path
18798 return $SourceReportPath;
18799 }
18800 elsif($OutputReportPath)
18801 { # --report-path
18802 return $OutputReportPath;
18803 }
18804 else
18805 { # default
18806 return $Dir."/src_compat_report.$ReportFormat";
18807 }
18808 }
18809 else
18810 {
18811 if($OutputReportPath)
18812 { # --report-path
18813 return $OutputReportPath;
18814 }
18815 else
18816 { # default
18817 return $Dir."/compat_report.$ReportFormat";
18818 }
18819 }
18820}
18821
18822sub printStatMsg($)
18823{
18824 my $Level = $_[0];
18825 printMsg("INFO", "total \"$Level\" compatibility problems: ".$RESULT{$Level}{"Problems"}.", warnings: ".$RESULT{$Level}{"Warnings"});
18826}
18827
18828sub listAffected($)
18829{
18830 my $Level = $_[0];
18831 my $List = "";
18832 foreach (keys(%{$TotalAffected{$Level}}))
18833 {
18834 if($StrictCompat and $TotalAffected{$Level}{$_} eq "Low")
18835 { # skip "Low"-severity problems
18836 next;
18837 }
18838 $List .= "$_\n";
18839 }
18840 my $Dir = get_dirname(getReportPath($Level));
18841 if($Level eq "Binary") {
18842 writeFile($Dir."/abi_affected.txt", $List);
18843 }
18844 elsif($Level eq "Source") {
18845 writeFile($Dir."/src_affected.txt", $List);
18846 }
18847}
18848
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040018849sub printReport()
18850{
18851 printMsg("INFO", "creating compatibility report ...");
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040018852 createReport();
18853 if($JoinReport or $DoubleReport)
18854 {
18855 if($RESULT{"Binary"}{"Problems"}
18856 or $RESULT{"Source"}{"Problems"}) {
18857 printMsg("INFO", "result: INCOMPATIBLE (Binary: ".$RESULT{"Binary"}{"Affected"}."\%, Source: ".$RESULT{"Source"}{"Affected"}."\%)");
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040018858 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040018859 else {
18860 printMsg("INFO", "result: COMPATIBLE");
18861 }
18862 printStatMsg("Binary");
18863 printStatMsg("Source");
18864 if($ListAffected)
18865 { # --list-affected
18866 listAffected("Binary");
18867 listAffected("Source");
18868 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040018869 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040018870 elsif($BinaryOnly)
18871 {
18872 if($RESULT{"Binary"}{"Problems"}) {
18873 printMsg("INFO", "result: INCOMPATIBLE (".$RESULT{"Binary"}{"Affected"}."\%)");
18874 }
18875 else {
18876 printMsg("INFO", "result: COMPATIBLE");
18877 }
18878 printStatMsg("Binary");
18879 if($ListAffected)
18880 { # --list-affected
18881 listAffected("Binary");
18882 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040018883 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040018884 elsif($SourceOnly)
18885 {
18886 if($RESULT{"Source"}{"Problems"}) {
18887 printMsg("INFO", "result: INCOMPATIBLE (".$RESULT{"Source"}{"Affected"}."\%)");
18888 }
18889 else {
18890 printMsg("INFO", "result: COMPATIBLE");
18891 }
18892 printStatMsg("Source");
18893 if($ListAffected)
18894 { # --list-affected
18895 listAffected("Source");
18896 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040018897 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040018898 if($StdOut)
18899 {
18900 if($JoinReport or not $DoubleReport)
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040018901 { # --binary or --source
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040018902 printMsg("INFO", "compatibility report has been generated to stdout");
18903 }
18904 else
18905 { # default
18906 printMsg("INFO", "compatibility reports have been generated to stdout");
18907 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040018908 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040018909 else
18910 {
18911 if($JoinReport)
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040018912 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040018913 printMsg("INFO", "see detailed report:\n ".getReportPath("Join"));
18914 }
18915 elsif($DoubleReport)
18916 { # default
18917 printMsg("INFO", "see detailed reports:\n ".getReportPath("Binary")."\n ".getReportPath("Source"));
18918 }
18919 elsif($BinaryOnly)
18920 { # --binary
18921 printMsg("INFO", "see detailed report:\n ".getReportPath("Binary"));
18922 }
18923 elsif($SourceOnly)
18924 { # --source
18925 printMsg("INFO", "see detailed report:\n ".getReportPath("Source"));
18926 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040018927 }
18928}
18929
18930sub check_win32_env()
18931{
18932 if(not $ENV{"DevEnvDir"}
18933 or not $ENV{"LIB"}) {
18934 exitStatus("Error", "can't start without VS environment (vsvars32.bat)");
18935 }
18936}
18937
Andrey Ponomarenko5c09ef32012-06-14 18:17:33 +040018938sub diffSets($$)
18939{
18940 my ($S1, $S2) = @_;
18941 my @SK1 = keys(%{$S1});
18942 my @SK2 = keys(%{$S2});
18943 if($#SK1!=$#SK2) {
18944 return 1;
18945 }
18946 foreach my $K1 (@SK1)
18947 {
18948 if(not defined $S2->{$K1}) {
18949 return 1;
18950 }
18951 }
18952 return 0;
18953}
18954
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040018955sub create_ABI_Dump()
18956{
18957 if(not -e $DumpAPI) {
18958 exitStatus("Access_Error", "can't access \'$DumpAPI\'");
18959 }
18960 # check the archive utilities
18961 if($OSgroup eq "windows")
18962 { # using zip
18963 my $ZipCmd = get_CmdPath("zip");
18964 if(not $ZipCmd) {
18965 exitStatus("Not_Found", "can't find \"zip\"");
18966 }
18967 }
18968 else
18969 { # using tar and gzip
18970 my $TarCmd = get_CmdPath("tar");
18971 if(not $TarCmd) {
18972 exitStatus("Not_Found", "can't find \"tar\"");
18973 }
18974 my $GzipCmd = get_CmdPath("gzip");
18975 if(not $GzipCmd) {
18976 exitStatus("Not_Found", "can't find \"gzip\"");
18977 }
18978 }
18979 my @DParts = split(/\s*,\s*/, $DumpAPI);
18980 foreach my $Part (@DParts)
18981 {
18982 if(not -e $Part) {
18983 exitStatus("Access_Error", "can't access \'$Part\'");
18984 }
18985 }
18986 checkVersionNum(1, $DumpAPI);
18987 foreach my $Part (@DParts)
18988 {
18989 if(isDump($Part)) {
18990 read_ABI_Dump(1, $Part);
18991 }
18992 else {
18993 readDescriptor(1, createDescriptor(1, $Part));
18994 }
18995 }
18996 initLogging(1);
18997 detect_default_paths("inc|lib|bin|gcc"); # complete analysis
Andrey Ponomarenko01117f12012-06-26 12:23:02 +040018998 if(not $Descriptor{1}{"Dump"})
18999 {
19000 if(not $CheckHeadersOnly) {
19001 readLibs(1);
19002 }
19003 if($CheckHeadersOnly) {
19004 setLanguage(1, "C++");
19005 }
19006 if(not $CheckObjectsOnly) {
19007 searchForHeaders(1);
19008 }
19009 $WORD_SIZE{1} = detectWordSize();
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040019010 }
Andrey Ponomarenko01117f12012-06-26 12:23:02 +040019011 if(not $Descriptor{1}{"Dump"})
19012 {
19013 if($Descriptor{1}{"Headers"}) {
19014 readHeaders(1);
19015 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040019016 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +040019017 cleanDump(1);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040019018 if(not keys(%{$SymbolInfo{1}}))
19019 { # check if created dump is valid
19020 if(not $ExtendedCheck and not $CheckObjectsOnly)
19021 {
19022 if($CheckHeadersOnly) {
19023 exitStatus("Empty_Set", "the set of public symbols is empty");
19024 }
19025 else {
19026 exitStatus("Empty_Intersection", "the sets of public symbols in headers and libraries have empty intersection");
19027 }
19028 }
19029 }
19030 my %HeadersInfo = ();
19031 foreach my $HPath (keys(%{$Registered_Headers{1}}))
19032 { # headers info stored without paths in the dump
19033 $HeadersInfo{$Registered_Headers{1}{$HPath}{"Identity"}} = $Registered_Headers{1}{$HPath}{"Pos"};
19034 }
19035 printMsg("INFO", "creating library ABI dump ...");
Andrey Ponomarenko01117f12012-06-26 12:23:02 +040019036 my %ABI = (
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040019037 "TypeInfo" => $TypeInfo{1},
19038 "SymbolInfo" => $SymbolInfo{1},
19039 "Symbols" => $Library_Symbol{1},
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040019040 "DepSymbols" => $DepLibrary_Symbol{1},
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040019041 "SymbolVersion" => $SymVer{1},
19042 "LibraryVersion" => $Descriptor{1}{"Version"},
19043 "LibraryName" => $TargetLibraryName,
19044 "Language" => $COMMON_LANGUAGE{1},
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040019045 "SkipTypes" => $SkipTypes{1},
19046 "SkipSymbols" => $SkipSymbols{1},
19047 "SkipNameSpaces" => $SkipNameSpaces{1},
19048 "SkipHeaders" => $SkipHeadersList{1},
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040019049 "Headers" => \%HeadersInfo,
19050 "Constants" => $Constants{1},
19051 "NameSpaces" => $NestedNameSpaces{1},
19052 "Target" => $OStarget,
19053 "Arch" => getArch(1),
19054 "WordSize" => $WORD_SIZE{1},
19055 "GccVersion" => get_dumpversion($GCC_PATH),
19056 "ABI_DUMP_VERSION" => $ABI_DUMP_VERSION,
19057 "ABI_COMPLIANCE_CHECKER_VERSION" => $TOOL_VERSION
19058 );
Andrey Ponomarenko5c09ef32012-06-14 18:17:33 +040019059 if(diffSets($TargetHeaders{1}, \%HeadersInfo)) {
Andrey Ponomarenko01117f12012-06-26 12:23:02 +040019060 $ABI{"TargetHeaders"} = $TargetHeaders{1};
Andrey Ponomarenko5c09ef32012-06-14 18:17:33 +040019061 }
19062 if($UseXML) {
Andrey Ponomarenko01117f12012-06-26 12:23:02 +040019063 $ABI{"XML_ABI_DUMP_VERSION"} = $XML_ABI_DUMP_VERSION;
Andrey Ponomarenko5c09ef32012-06-14 18:17:33 +040019064 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040019065 if($ExtendedCheck)
19066 { # --ext option
Andrey Ponomarenko01117f12012-06-26 12:23:02 +040019067 $ABI{"Mode"} = "Extended";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040019068 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040019069 if($BinaryOnly)
19070 { # --binary
Andrey Ponomarenko01117f12012-06-26 12:23:02 +040019071 $ABI{"BinOnly"} = 1;
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040019072 }
Andrey Ponomarenko5c09ef32012-06-14 18:17:33 +040019073
19074 my $ABI_DUMP = "";
19075 if($UseXML)
19076 {
19077 loadModule("XmlDump");
Andrey Ponomarenko01117f12012-06-26 12:23:02 +040019078 $ABI_DUMP = createXmlDump(\%ABI);
Andrey Ponomarenko5c09ef32012-06-14 18:17:33 +040019079 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040019080 else
19081 { # default
Andrey Ponomarenko01117f12012-06-26 12:23:02 +040019082 $ABI_DUMP = Dumper(\%ABI);
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040019083 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040019084 if($StdOut)
19085 { # --stdout option
Andrey Ponomarenko5c09ef32012-06-14 18:17:33 +040019086 print STDOUT $ABI_DUMP;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040019087 printMsg("INFO", "ABI dump has been generated to stdout");
19088 return;
19089 }
19090 else
19091 { # write to gzipped file
Andrey Ponomarenko5c09ef32012-06-14 18:17:33 +040019092 my $DumpPath = "abi_dumps/$TargetLibraryName/".$TargetLibraryName."_".$Descriptor{1}{"Version"}.".abi";
19093 $DumpPath .= ".".$AR_EXT; # gzipped by default
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040019094 if($OutputDumpPath)
19095 { # user defined path
19096 $DumpPath = $OutputDumpPath;
19097 }
Andrey Ponomarenko5c09ef32012-06-14 18:17:33 +040019098 my $Archive = ($DumpPath=~s/\Q.$AR_EXT\E\Z//g);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040019099 my ($DDir, $DName) = separate_path($DumpPath);
19100 my $DPath = $TMP_DIR."/".$DName;
Andrey Ponomarenko5c09ef32012-06-14 18:17:33 +040019101 if(not $Archive) {
19102 $DPath = $DumpPath;
19103 }
19104
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040019105 mkpath($DDir);
Andrey Ponomarenko85043792012-05-14 16:48:07 +040019106
19107 open(DUMP, ">", $DPath) || die ("can't open file \'$DPath\': $!\n");
Andrey Ponomarenko5c09ef32012-06-14 18:17:33 +040019108 print DUMP $ABI_DUMP;
Andrey Ponomarenko85043792012-05-14 16:48:07 +040019109 close(DUMP);
19110
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040019111 if(not -s $DPath) {
19112 exitStatus("Error", "can't create ABI dump because something is going wrong with the Data::Dumper module");
19113 }
Andrey Ponomarenko5c09ef32012-06-14 18:17:33 +040019114 if($Archive)
19115 {
19116 my $PkgPath = createArchive($DPath, $DDir);
19117 printMsg("INFO", "library ABI has been dumped to:\n $PkgPath");
19118 }
19119 else {
19120 printMsg("INFO", "library ABI has been dumped to:\n $DumpPath");
19121 }
19122
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040019123 printMsg("INFO", "you can transfer this dump everywhere and use instead of the ".$Descriptor{1}{"Version"}." version descriptor");
19124 }
19125}
19126
19127sub quickEmptyReports()
19128{ # Quick "empty" reports
19129 # 4 times faster than merging equal dumps
19130 # NOTE: the dump contains the "LibraryVersion" attribute
19131 # if you change the version, then your dump will be different
19132 # OVERCOME: use -v1 and v2 options for comparing dumps
19133 # and don't change version in the XML descriptor (and dumps)
19134 # OVERCOME 2: separate meta info from the dumps in ACC 2.0
19135 if(-s $Descriptor{1}{"Path"} == -s $Descriptor{2}{"Path"})
19136 {
19137 my $FilePath1 = unpackDump($Descriptor{1}{"Path"});
19138 my $FilePath2 = unpackDump($Descriptor{2}{"Path"});
19139 if($FilePath1 and $FilePath2)
19140 {
Andrey Ponomarenko01117f12012-06-26 12:23:02 +040019141 my $Line = readLineNum($FilePath1, 0);
19142 if($Line=~/xml/)
19143 { # XML format
19144 # is not supported yet
19145 return;
19146 }
19147
Andrey Ponomarenko85043792012-05-14 16:48:07 +040019148 local $/ = undef;
19149
19150 open(DUMP1, $FilePath1);
19151 my $Content1 = <DUMP1>;
19152 close(DUMP1);
19153
19154 open(DUMP2, $FilePath2);
19155 my $Content2 = <DUMP2>;
19156 close(DUMP2);
19157
19158 if($Content1 eq $Content2)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040019159 {
Andrey Ponomarenko85043792012-05-14 16:48:07 +040019160 # clean memory
19161 undef $Content2;
19162
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040019163 # read a number of headers, libs, symbols and types
Andrey Ponomarenko85043792012-05-14 16:48:07 +040019164 my $ABIdump = eval($Content1);
19165
19166 # clean memory
19167 undef $Content1;
19168
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040019169 if(not $ABIdump) {
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040019170 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 +040019171 }
19172 if(not $ABIdump->{"TypeInfo"})
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040019173 { # support for old dumps
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040019174 $ABIdump->{"TypeInfo"} = $ABIdump->{"TypeDescr"};
19175 }
19176 if(not $ABIdump->{"SymbolInfo"})
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040019177 { # support for old dumps
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040019178 $ABIdump->{"SymbolInfo"} = $ABIdump->{"FuncDescr"};
19179 }
19180 read_Headers_DumpInfo($ABIdump, 1);
19181 read_Libs_DumpInfo($ABIdump, 1);
19182 read_Machine_DumpInfo($ABIdump, 1);
19183 read_Machine_DumpInfo($ABIdump, 2);
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040019184
19185 %{$CheckedTypes{"Binary"}} = %{$ABIdump->{"TypeInfo"}};
19186 %{$CheckedTypes{"Source"}} = %{$ABIdump->{"TypeInfo"}};
19187
19188 %{$CheckedSymbols{"Binary"}} = %{$ABIdump->{"SymbolInfo"}};
19189 %{$CheckedSymbols{"Source"}} = %{$ABIdump->{"SymbolInfo"}};
19190
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040019191 $Descriptor{1}{"Version"} = $TargetVersion{1}?$TargetVersion{1}:$ABIdump->{"LibraryVersion"};
19192 $Descriptor{2}{"Version"} = $TargetVersion{2}?$TargetVersion{2}:$ABIdump->{"LibraryVersion"};
19193 exitReport();
19194 }
19195 }
19196 }
19197}
19198
19199sub initLogging($)
19200{
19201 my $LibVersion = $_[0];
19202 # create log directory
19203 my ($LOG_DIR, $LOG_FILE) = ("logs/$TargetLibraryName/".$Descriptor{$LibVersion}{"Version"}, "log.txt");
19204 if($OutputLogPath{$LibVersion})
19205 { # user-defined by -log-path option
19206 ($LOG_DIR, $LOG_FILE) = separate_path($OutputLogPath{$LibVersion});
19207 }
19208 if($LogMode ne "n") {
19209 mkpath($LOG_DIR);
19210 }
19211 $LOG_PATH{$LibVersion} = get_abs_path($LOG_DIR)."/".$LOG_FILE;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040019212 if($Debug)
19213 { # debug directory
19214 $DEBUG_PATH{$LibVersion} = "debug/$TargetLibraryName/".$Descriptor{$LibVersion}{"Version"};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040019215 }
Andrey Ponomarenko35c44fd2012-06-18 17:50:25 +040019216 resetLogging($LibVersion);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040019217}
19218
19219sub writeLog($$)
19220{
19221 my ($LibVersion, $Msg) = @_;
19222 if($LogMode ne "n") {
19223 appendFile($LOG_PATH{$LibVersion}, $Msg);
19224 }
19225}
19226
19227sub resetLogging($)
19228{
19229 my $LibVersion = $_[0];
19230 if($LogMode!~/a|n/)
19231 { # remove old log
19232 unlink($LOG_PATH{$LibVersion});
Andrey Ponomarenko35c44fd2012-06-18 17:50:25 +040019233 if($Debug) {
19234 rmtree($DEBUG_PATH{$LibVersion});
19235 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040019236 }
19237}
19238
19239sub printErrorLog($)
19240{
19241 my $LibVersion = $_[0];
19242 if($LogMode ne "n") {
19243 printMsg("ERROR", "see log for details:\n ".$LOG_PATH{$LibVersion}."\n");
19244 }
19245}
19246
19247sub isDump($)
19248{
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040019249 if(get_filename($_[0])=~/\A(.+)\.(abi|abidump)(\.tar\.gz|\.zip|\.xml|)\Z/) {
19250 return $1;
19251 }
19252 return 0;
19253}
19254
19255sub isDump_U($)
19256{
19257 if(get_filename($_[0])=~/\A(.+)\.(abi|abidump)(\.xml|)\Z/) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040019258 return $1;
19259 }
19260 return 0;
19261}
19262
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040019263sub compareInit()
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040019264{
19265 # read input XML descriptors or ABI dumps
19266 if(not $Descriptor{1}{"Path"}) {
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040019267 exitStatus("Error", "-old option is not specified");
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040019268 }
19269 my @DParts1 = split(/\s*,\s*/, $Descriptor{1}{"Path"});
19270 foreach my $Part (@DParts1)
19271 {
19272 if(not -e $Part) {
19273 exitStatus("Access_Error", "can't access \'$Part\'");
19274 }
19275 }
19276 if(not $Descriptor{2}{"Path"}) {
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040019277 exitStatus("Error", "-new option is not specified");
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040019278 }
19279 my @DParts2 = split(/\s*,\s*/, $Descriptor{2}{"Path"});
19280 foreach my $Part (@DParts2)
19281 {
19282 if(not -e $Part) {
19283 exitStatus("Access_Error", "can't access \'$Part\'");
19284 }
19285 }
19286 detect_default_paths("bin"); # to extract dumps
19287 if($#DParts1==0 and $#DParts2==0
19288 and isDump($Descriptor{1}{"Path"})
19289 and isDump($Descriptor{2}{"Path"}))
19290 { # optimization: equal ABI dumps
19291 quickEmptyReports();
19292 }
19293 checkVersionNum(1, $Descriptor{1}{"Path"});
19294 checkVersionNum(2, $Descriptor{2}{"Path"});
19295 printMsg("INFO", "preparation, please wait ...");
19296 foreach my $Part (@DParts1)
19297 {
19298 if(isDump($Part)) {
19299 read_ABI_Dump(1, $Part);
19300 }
19301 else {
19302 readDescriptor(1, createDescriptor(1, $Part));
19303 }
19304 }
19305 foreach my $Part (@DParts2)
19306 {
19307 if(isDump($Part)) {
19308 read_ABI_Dump(2, $Part);
19309 }
19310 else {
19311 readDescriptor(2, createDescriptor(2, $Part));
19312 }
19313 }
19314 initLogging(1);
19315 initLogging(2);
19316 # check consistency
19317 if(not $Descriptor{1}{"Headers"}
19318 and not $Descriptor{1}{"Libs"}) {
19319 exitStatus("Error", "descriptor d1 does not contain both header files and libraries info");
19320 }
19321 if(not $Descriptor{2}{"Headers"}
19322 and not $Descriptor{2}{"Libs"}) {
19323 exitStatus("Error", "descriptor d2 does not contain both header files and libraries info");
19324 }
19325 if($Descriptor{1}{"Headers"} and not $Descriptor{1}{"Libs"}
19326 and not $Descriptor{2}{"Headers"} and $Descriptor{2}{"Libs"}) {
19327 exitStatus("Error", "can't compare headers with $SLIB_TYPE libraries");
19328 }
19329 elsif(not $Descriptor{1}{"Headers"} and $Descriptor{1}{"Libs"}
19330 and $Descriptor{2}{"Headers"} and not $Descriptor{2}{"Libs"}) {
19331 exitStatus("Error", "can't compare $SLIB_TYPE libraries with headers");
19332 }
19333 if(not $Descriptor{1}{"Headers"}) {
19334 if($CheckHeadersOnly_Opt) {
19335 exitStatus("Error", "can't find header files info in descriptor d1");
19336 }
19337 }
19338 if(not $Descriptor{2}{"Headers"}) {
19339 if($CheckHeadersOnly_Opt) {
19340 exitStatus("Error", "can't find header files info in descriptor d2");
19341 }
19342 }
19343 if(not $Descriptor{1}{"Headers"}
19344 or not $Descriptor{2}{"Headers"}) {
19345 if(not $CheckObjectsOnly_Opt) {
19346 printMsg("WARNING", "comparing $SLIB_TYPE libraries only");
19347 $CheckObjectsOnly = 1;
19348 }
19349 }
19350 if(not $Descriptor{1}{"Libs"}) {
19351 if($CheckObjectsOnly_Opt) {
19352 exitStatus("Error", "can't find $SLIB_TYPE libraries info in descriptor d1");
19353 }
19354 }
19355 if(not $Descriptor{2}{"Libs"}) {
19356 if($CheckObjectsOnly_Opt) {
19357 exitStatus("Error", "can't find $SLIB_TYPE libraries info in descriptor d2");
19358 }
19359 }
19360 if(not $Descriptor{1}{"Libs"}
19361 or not $Descriptor{2}{"Libs"})
19362 { # comparing standalone header files
19363 # comparing ABI dumps created with --headers-only
19364 if(not $CheckHeadersOnly_Opt)
19365 {
19366 printMsg("WARNING", "checking headers only");
19367 $CheckHeadersOnly = 1;
19368 }
19369 }
19370 if($UseDumps)
19371 { # --use-dumps
19372 # parallel processing
19373 my $pid = fork();
19374 if($pid)
19375 { # dump on two CPU cores
19376 my @PARAMS = ("-dump", $Descriptor{1}{"Path"}, "-l", $TargetLibraryName);
19377 if($RelativeDirectory{1}) {
19378 @PARAMS = (@PARAMS, "-relpath", $RelativeDirectory{1});
19379 }
19380 if($OutputLogPath{1}) {
19381 @PARAMS = (@PARAMS, "-log-path", $OutputLogPath{1});
19382 }
19383 if($CrossGcc) {
19384 @PARAMS = (@PARAMS, "-cross-gcc", $CrossGcc);
19385 }
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040019386 if($Quiet)
19387 {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040019388 @PARAMS = (@PARAMS, "-quiet");
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040019389 @PARAMS = (@PARAMS, "-logging-mode", "a");
19390 }
19391 elsif($LogMode and $LogMode ne "w")
19392 { # "w" is default
19393 @PARAMS = (@PARAMS, "-logging-mode", $LogMode);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040019394 }
19395 if($ExtendedCheck) {
19396 @PARAMS = (@PARAMS, "-extended");
19397 }
19398 if($UserLang) {
19399 @PARAMS = (@PARAMS, "-lang", $UserLang);
19400 }
19401 if($TargetVersion{1}) {
19402 @PARAMS = (@PARAMS, "-vnum", $TargetVersion{1});
19403 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +040019404 if($BinaryOnly) {
19405 @PARAMS = (@PARAMS, "-binary");
19406 }
19407 if($SourceOnly) {
19408 @PARAMS = (@PARAMS, "-source");
19409 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040019410 if($SortDump) {
19411 @PARAMS = (@PARAMS, "-sort");
19412 }
Andrey Ponomarenko01117f12012-06-26 12:23:02 +040019413 if($DumpFormat and $DumpFormat ne "perl") {
19414 @PARAMS = (@PARAMS, "-dump-format", $DumpFormat);
19415 }
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +040019416 if($CheckHeadersOnly) {
19417 @PARAMS = (@PARAMS, "-headers-only");
19418 }
19419 if($CheckObjectsOnly) {
19420 @PARAMS = (@PARAMS, "-objects-only");
19421 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +040019422 if($Debug)
19423 {
19424 @PARAMS = (@PARAMS, "-debug");
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040019425 printMsg("INFO", "running perl $0 @PARAMS");
Andrey Ponomarenko85043792012-05-14 16:48:07 +040019426 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040019427 system("perl", $0, @PARAMS);
19428 if($?) {
19429 exit(1);
19430 }
19431 }
19432 else
19433 { # child
19434 my @PARAMS = ("-dump", $Descriptor{2}{"Path"}, "-l", $TargetLibraryName);
19435 if($RelativeDirectory{2}) {
19436 @PARAMS = (@PARAMS, "-relpath", $RelativeDirectory{2});
19437 }
19438 if($OutputLogPath{2}) {
19439 @PARAMS = (@PARAMS, "-log-path", $OutputLogPath{2});
19440 }
19441 if($CrossGcc) {
19442 @PARAMS = (@PARAMS, "-cross-gcc", $CrossGcc);
19443 }
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040019444 if($Quiet)
19445 {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040019446 @PARAMS = (@PARAMS, "-quiet");
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040019447 @PARAMS = (@PARAMS, "-logging-mode", "a");
19448 }
19449 elsif($LogMode and $LogMode ne "w")
19450 { # "w" is default
19451 @PARAMS = (@PARAMS, "-logging-mode", $LogMode);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040019452 }
19453 if($ExtendedCheck) {
19454 @PARAMS = (@PARAMS, "-extended");
19455 }
19456 if($UserLang) {
19457 @PARAMS = (@PARAMS, "-lang", $UserLang);
19458 }
19459 if($TargetVersion{2}) {
19460 @PARAMS = (@PARAMS, "-vnum", $TargetVersion{2});
19461 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +040019462 if($BinaryOnly) {
19463 @PARAMS = (@PARAMS, "-binary");
19464 }
19465 if($SourceOnly) {
19466 @PARAMS = (@PARAMS, "-source");
19467 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040019468 if($SortDump) {
19469 @PARAMS = (@PARAMS, "-sort");
19470 }
Andrey Ponomarenko01117f12012-06-26 12:23:02 +040019471 if($DumpFormat and $DumpFormat ne "perl") {
19472 @PARAMS = (@PARAMS, "-dump-format", $DumpFormat);
19473 }
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +040019474 if($CheckHeadersOnly) {
19475 @PARAMS = (@PARAMS, "-headers-only");
19476 }
19477 if($CheckObjectsOnly) {
19478 @PARAMS = (@PARAMS, "-objects-only");
19479 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +040019480 if($Debug)
19481 {
19482 @PARAMS = (@PARAMS, "-debug");
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040019483 printMsg("INFO", "running perl $0 @PARAMS");
Andrey Ponomarenko85043792012-05-14 16:48:07 +040019484 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040019485 system("perl", $0, @PARAMS);
19486 if($?) {
19487 exit(1);
19488 }
19489 else {
19490 exit(0);
19491 }
19492 }
19493 waitpid($pid, 0);
19494 my @CMP_PARAMS = ("-l", $TargetLibraryName);
19495 @CMP_PARAMS = (@CMP_PARAMS, "-d1", "abi_dumps/$TargetLibraryName/".$TargetLibraryName."_".$Descriptor{1}{"Version"}.".abi.$AR_EXT");
19496 @CMP_PARAMS = (@CMP_PARAMS, "-d2", "abi_dumps/$TargetLibraryName/".$TargetLibraryName."_".$Descriptor{2}{"Version"}.".abi.$AR_EXT");
19497 if($TargetLibraryFName ne $TargetLibraryName) {
19498 @CMP_PARAMS = (@CMP_PARAMS, "-l-full", $TargetLibraryFName);
19499 }
19500 if($ShowRetVal) {
19501 @CMP_PARAMS = (@CMP_PARAMS, "-show-retval");
19502 }
19503 if($CrossGcc) {
19504 @CMP_PARAMS = (@CMP_PARAMS, "-cross-gcc", $CrossGcc);
19505 }
Andrey Ponomarenko35c44fd2012-06-18 17:50:25 +040019506 @CMP_PARAMS = (@CMP_PARAMS, "-logging-mode", "a");
19507 if($Quiet) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040019508 @CMP_PARAMS = (@CMP_PARAMS, "-quiet");
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040019509 }
19510 if($ReportFormat and $ReportFormat ne "html")
19511 { # HTML is default format
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040019512 @CMP_PARAMS = (@CMP_PARAMS, "-report-format", $ReportFormat);
19513 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040019514 if($OutputReportPath) {
19515 @CMP_PARAMS = (@CMP_PARAMS, "-report-path", $OutputReportPath);
19516 }
19517 if($BinaryReportPath) {
19518 @CMP_PARAMS = (@CMP_PARAMS, "-bin-report-path", $BinaryReportPath);
19519 }
19520 if($SourceReportPath) {
19521 @CMP_PARAMS = (@CMP_PARAMS, "-src-report-path", $SourceReportPath);
19522 }
19523 if($LoggingPath) {
19524 @CMP_PARAMS = (@CMP_PARAMS, "-log-path", $LoggingPath);
19525 }
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +040019526 if($CheckHeadersOnly) {
19527 @CMP_PARAMS = (@CMP_PARAMS, "-headers-only");
19528 }
19529 if($CheckObjectsOnly) {
19530 @CMP_PARAMS = (@CMP_PARAMS, "-objects-only");
19531 }
19532 if($BinaryOnly) {
19533 @CMP_PARAMS = (@CMP_PARAMS, "-binary");
19534 }
19535 if($SourceOnly) {
19536 @CMP_PARAMS = (@CMP_PARAMS, "-source");
19537 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +040019538 if($Browse) {
19539 @CMP_PARAMS = (@CMP_PARAMS, "-browse", $Browse);
19540 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040019541 if($OpenReport) {
19542 @CMP_PARAMS = (@CMP_PARAMS, "-open");
19543 }
19544 if($Debug)
19545 {
19546 @CMP_PARAMS = (@CMP_PARAMS, "-debug");
19547 printMsg("INFO", "running perl $0 @CMP_PARAMS");
Andrey Ponomarenko85043792012-05-14 16:48:07 +040019548 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040019549 system("perl", $0, @CMP_PARAMS);
19550 exit($?>>8);
19551 }
19552 if(not $Descriptor{1}{"Dump"}
19553 or not $Descriptor{2}{"Dump"})
19554 { # need GCC toolchain to analyze
19555 # header files and libraries
19556 detect_default_paths("inc|lib|gcc");
19557 }
19558 if(not $Descriptor{1}{"Dump"})
19559 {
19560 if(not $CheckHeadersOnly) {
19561 readLibs(1);
19562 }
19563 if($CheckHeadersOnly) {
19564 setLanguage(1, "C++");
19565 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +040019566 if(not $CheckObjectsOnly) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040019567 searchForHeaders(1);
19568 }
19569 $WORD_SIZE{1} = detectWordSize();
19570 }
19571 if(not $Descriptor{2}{"Dump"})
19572 {
19573 if(not $CheckHeadersOnly) {
19574 readLibs(2);
19575 }
19576 if($CheckHeadersOnly) {
19577 setLanguage(2, "C++");
19578 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +040019579 if(not $CheckObjectsOnly) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040019580 searchForHeaders(2);
19581 }
19582 $WORD_SIZE{2} = detectWordSize();
19583 }
19584 if($WORD_SIZE{1} ne $WORD_SIZE{2})
19585 { # support for old ABI dumps
19586 # try to synch different WORD sizes
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040019587 if(not checkDump(1, "2.1"))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040019588 {
19589 $WORD_SIZE{1} = $WORD_SIZE{2};
19590 printMsg("WARNING", "set WORD size to ".$WORD_SIZE{2}." bytes");
19591 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040019592 elsif(not checkDump(2, "2.1"))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040019593 {
19594 $WORD_SIZE{2} = $WORD_SIZE{1};
19595 printMsg("WARNING", "set WORD size to ".$WORD_SIZE{1}." bytes");
19596 }
19597 }
19598 elsif(not $WORD_SIZE{1}
19599 and not $WORD_SIZE{2})
19600 { # support for old ABI dumps
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040019601 $WORD_SIZE{1} = "4";
19602 $WORD_SIZE{2} = "4";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040019603 }
19604 if($Descriptor{1}{"Dump"})
19605 { # support for old ABI dumps
19606 prepareTypes(1);
19607 }
19608 if($Descriptor{2}{"Dump"})
19609 { # support for old ABI dumps
19610 prepareTypes(2);
19611 }
19612 if($AppPath and not keys(%{$Symbol_Library{1}})) {
19613 printMsg("WARNING", "the application ".get_filename($AppPath)." has no symbols imported from the $SLIB_TYPE libraries");
19614 }
19615 # started to process input data
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040019616 if(not $CheckObjectsOnly)
19617 {
19618 if($Descriptor{1}{"Headers"}
19619 and not $Descriptor{1}{"Dump"}) {
19620 readHeaders(1);
19621 }
19622 if($Descriptor{2}{"Headers"}
19623 and not $Descriptor{2}{"Dump"}) {
19624 readHeaders(2);
19625 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040019626 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +040019627
19628 # clean memory
19629 %SystemHeaders = ();
19630 %mangled_name_gcc = ();
19631
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040019632 prepareSymbols(1);
19633 prepareSymbols(2);
Andrey Ponomarenko16934472012-03-29 15:37:04 +040019634
Andrey Ponomarenko85043792012-05-14 16:48:07 +040019635 # clean memory
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040019636 %SymbolInfo = ();
Andrey Ponomarenko16934472012-03-29 15:37:04 +040019637
19638 # Virtual Tables
19639 registerVTable(1);
19640 registerVTable(2);
19641
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040019642 if(not checkDump(1, "1.22")
19643 and checkDump(2, "1.22"))
Andrey Ponomarenko16934472012-03-29 15:37:04 +040019644 { # support for old ABI dumps
19645 foreach my $ClassName (keys(%{$VirtualTable{2}}))
19646 {
19647 if($ClassName=~/</)
19648 { # templates
19649 if(not defined $VirtualTable{1}{$ClassName})
19650 { # synchronize
19651 delete($VirtualTable{2}{$ClassName});
19652 }
19653 }
19654 }
19655 }
19656
19657 registerOverriding(1);
19658 registerOverriding(2);
19659
19660 setVirtFuncPositions(1);
19661 setVirtFuncPositions(2);
19662
19663 # Other
19664 addParamNames(1);
19665 addParamNames(2);
19666
19667 detectChangedTypedefs();
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040019668}
19669
19670sub compareAPIs($)
19671{
19672 my $Level = $_[0];
19673 readRules($Level);
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +040019674 loadModule("CallConv");
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040019675 if($Level eq "Binary") {
19676 printMsg("INFO", "comparing ABIs ...");
19677 }
19678 else {
19679 printMsg("INFO", "comparing APIs ...");
19680 }
19681 if($CheckHeadersOnly
19682 or $Level eq "Source")
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040019683 { # added/removed in headers
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040019684 detectAdded_H($Level);
19685 detectRemoved_H($Level);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040019686 }
19687 else
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040019688 { # added/removed in libs
19689 detectAdded($Level);
19690 detectRemoved($Level);
19691 }
19692 if(not $CheckObjectsOnly)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040019693 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040019694 mergeSignatures($Level);
19695 if(keys(%{$CheckedSymbols{$Level}})) {
19696 mergeConstants($Level);
19697 }
19698 }
19699 if($CheckHeadersOnly
19700 or $Level eq "Source")
19701 { # added/removed in headers
19702 mergeHeaders($Level);
19703 }
19704 else
19705 { # added/removed in libs
19706 mergeLibs($Level);
19707 if($CheckImpl
19708 and $Level eq "Binary") {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040019709 mergeImpl();
19710 }
19711 }
19712}
19713
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040019714sub getSysOpts()
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040019715{
19716 my %Opts = (
19717 "OStarget"=>$OStarget,
19718 "Debug"=>$Debug,
19719 "Quiet"=>$Quiet,
19720 "LogMode"=>$LogMode,
19721 "CheckHeadersOnly"=>$CheckHeadersOnly,
19722
19723 "SystemRoot"=>$SystemRoot,
19724 "MODULES_DIR"=>$MODULES_DIR,
19725 "GCC_PATH"=>$GCC_PATH,
19726 "TargetSysInfo"=>$TargetSysInfo,
19727 "CrossPrefix"=>$CrossPrefix,
19728 "TargetLibraryName"=>$TargetLibraryName,
19729 "CrossGcc"=>$CrossGcc,
19730 "UseStaticLibs"=>$UseStaticLibs,
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040019731 "NoStdInc"=>$NoStdInc,
19732
19733 "BinaryOnly" => $BinaryOnly,
19734 "SourceOnly" => $SourceOnly
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040019735 );
19736 return \%Opts;
19737}
19738
19739sub get_CoreError($)
19740{
19741 my %CODE_ERROR = reverse(%ERROR_CODE);
19742 return $CODE_ERROR{$_[0]};
19743}
19744
19745sub scenario()
19746{
19747 if($StdOut)
19748 { # enable quiet mode
19749 $Quiet = 1;
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040019750 $JoinReport = 1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040019751 }
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040019752 if(not $LogMode)
19753 { # default
19754 $LogMode = "w";
19755 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040019756 if($UserLang)
19757 { # --lang=C++
19758 $UserLang = uc($UserLang);
19759 $COMMON_LANGUAGE{1}=$UserLang;
19760 $COMMON_LANGUAGE{2}=$UserLang;
19761 }
19762 if($LoggingPath)
19763 {
19764 $OutputLogPath{1} = $LoggingPath;
19765 $OutputLogPath{2} = $LoggingPath;
19766 if($Quiet) {
19767 $COMMON_LOG_PATH = $LoggingPath;
19768 }
19769 }
Andrey Ponomarenko5c09ef32012-06-14 18:17:33 +040019770 if($OutputDumpPath)
19771 { # validate
19772 if($OutputDumpPath!~/\.abi(\.\Q$AR_EXT\E|)\Z/) {
19773 exitStatus("Error", "the dump path should be a path to *.abi.$AR_EXT or *.abi file");
19774 }
19775 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040019776 if($BinaryOnly and $SourceOnly)
19777 { # both --binary and --source
19778 # is the default mode
19779 $DoubleReport = 1;
19780 $JoinReport = 0;
19781 $BinaryOnly = 0;
19782 $SourceOnly = 0;
19783 if($OutputReportPath)
19784 { # --report-path
19785 $DoubleReport = 0;
19786 $JoinReport = 1;
19787 }
19788 }
19789 elsif($BinaryOnly or $SourceOnly)
19790 { # --binary or --source
19791 $DoubleReport = 0;
19792 $JoinReport = 0;
19793 }
19794 if($UseXML)
19795 { # --xml option
19796 $ReportFormat = "xml";
Andrey Ponomarenko5c09ef32012-06-14 18:17:33 +040019797 $DumpFormat = "xml";
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040019798 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040019799 if($ReportFormat)
19800 { # validate
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040019801 $ReportFormat = lc($ReportFormat);
19802 if($ReportFormat!~/\A(xml|html|htm)\Z/) {
Andrey Ponomarenko5c09ef32012-06-14 18:17:33 +040019803 exitStatus("Error", "unknown report format \'$ReportFormat\'");
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040019804 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040019805 if($ReportFormat eq "htm")
19806 { # HTM == HTML
19807 $ReportFormat = "html";
19808 }
19809 elsif($ReportFormat eq "xml")
19810 { # --report-format=XML equal to --xml
19811 $UseXML = 1;
19812 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040019813 }
19814 else
19815 { # default: HTML
19816 $ReportFormat = "html";
19817 }
Andrey Ponomarenko5c09ef32012-06-14 18:17:33 +040019818 if($DumpFormat)
19819 { # validate
19820 $DumpFormat = lc($DumpFormat);
19821 if($DumpFormat!~/\A(xml|perl)\Z/) {
19822 exitStatus("Error", "unknown ABI dump format \'$DumpFormat\'");
19823 }
19824 if($DumpFormat eq "xml")
19825 { # --dump-format=XML equal to --xml
19826 $UseXML = 1;
19827 }
19828 }
19829 else
Andrey Ponomarenko01117f12012-06-26 12:23:02 +040019830 { # default: Perl Data::Dumper
Andrey Ponomarenko5c09ef32012-06-14 18:17:33 +040019831 $DumpFormat = "perl";
19832 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040019833 if($Quiet and $LogMode!~/a|n/)
19834 { # --quiet log
19835 if(-f $COMMON_LOG_PATH) {
19836 unlink($COMMON_LOG_PATH);
19837 }
19838 }
19839 if($TestTool and $UseDumps)
19840 { # --test && --use-dumps == --test-dump
19841 $TestDump = 1;
19842 }
19843 if($Help) {
19844 HELP_MESSAGE();
19845 exit(0);
19846 }
19847 if($InfoMsg) {
19848 INFO_MESSAGE();
19849 exit(0);
19850 }
19851 if($ShowVersion) {
19852 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.");
19853 exit(0);
19854 }
19855 if($DumpVersion) {
19856 printMsg("INFO", $TOOL_VERSION);
19857 exit(0);
19858 }
19859 if($ExtendedCheck) {
19860 $CheckHeadersOnly = 1;
19861 }
19862 if($SystemRoot_Opt)
19863 { # user defined root
19864 if(not -e $SystemRoot_Opt) {
19865 exitStatus("Access_Error", "can't access \'$SystemRoot\'");
19866 }
19867 $SystemRoot = $SystemRoot_Opt;
19868 $SystemRoot=~s/[\/]+\Z//g;
19869 if($SystemRoot) {
19870 $SystemRoot = get_abs_path($SystemRoot);
19871 }
19872 }
19873 $Data::Dumper::Sortkeys = 1;
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +040019874
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040019875 if($SortDump)
19876 {
19877 $Data::Dumper::Useperl = 1;
19878 $Data::Dumper::Sortkeys = \&dump_sorting;
19879 }
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +040019880
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040019881 if($TargetLibsPath)
19882 {
19883 if(not -f $TargetLibsPath) {
19884 exitStatus("Access_Error", "can't access file \'$TargetLibsPath\'");
19885 }
19886 foreach my $Lib (split(/\s*\n\s*/, readFile($TargetLibsPath))) {
19887 $TargetLibs{$Lib} = 1;
19888 }
19889 }
19890 if($TargetHeadersPath)
19891 { # --headers-list
19892 if(not -f $TargetHeadersPath) {
19893 exitStatus("Access_Error", "can't access file \'$TargetHeadersPath\'");
19894 }
19895 foreach my $Header (split(/\s*\n\s*/, readFile($TargetHeadersPath)))
19896 {
19897 $TargetHeaders{1}{$Header} = 1;
19898 $TargetHeaders{2}{$Header} = 1;
19899 }
19900 }
19901 if($TargetHeader)
19902 { # --header
19903 $TargetHeaders{1}{$TargetHeader} = 1;
19904 $TargetHeaders{2}{$TargetHeader} = 1;
19905 }
19906 if($TestTool
19907 or $TestDump)
19908 { # --test, --test-dump
19909 detect_default_paths("bin|gcc"); # to compile libs
19910 loadModule("RegTests");
Andrey Ponomarenkof48ec932012-07-19 18:57:20 +040019911 testTool($TestDump, $Debug, $Quiet, $ExtendedCheck, $LogMode, $ReportFormat, $DumpFormat,
19912 $LIB_EXT, $GCC_PATH, $Browse, $OpenReport, $SortDump, $CheckHeadersOnly, $CheckObjectsOnly);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040019913 exit(0);
19914 }
19915 if($DumpSystem)
19916 { # --dump-system
19917 loadModule("SysCheck");
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040019918 if($DumpSystem=~/\.(xml|desc)\Z/)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040019919 { # system XML descriptor
19920 if(not -f $DumpSystem) {
19921 exitStatus("Access_Error", "can't access file \'$DumpSystem\'");
19922 }
19923 my $Ret = readSystemDescriptor(readFile($DumpSystem));
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040019924 foreach (@{$Ret->{"Tools"}})
19925 {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040019926 $SystemPaths{"bin"}{$_} = 1;
19927 $TargetTools{$_}=1;
19928 }
19929 if($Ret->{"CrossPrefix"}) {
19930 $CrossPrefix = $Ret->{"CrossPrefix"};
19931 }
19932 }
19933 elsif($SystemRoot_Opt)
19934 { # -sysroot "/" option
19935 # default target: /usr/lib, /usr/include
19936 # search libs: /usr/lib and /lib
19937 if(not -e $SystemRoot."/usr/lib") {
19938 exitStatus("Access_Error", "can't access '".$SystemRoot."/usr/lib'");
19939 }
19940 if(not -e $SystemRoot."/lib") {
19941 exitStatus("Access_Error", "can't access '".$SystemRoot."/lib'");
19942 }
19943 if(not -e $SystemRoot."/usr/include") {
19944 exitStatus("Access_Error", "can't access '".$SystemRoot."/usr/include'");
19945 }
19946 readSystemDescriptor("
19947 <name>
19948 $DumpSystem
19949 </name>
19950 <headers>
19951 $SystemRoot/usr/include
19952 </headers>
19953 <libs>
19954 $SystemRoot/usr/lib
19955 </libs>
19956 <search_libs>
19957 $SystemRoot/lib
19958 </search_libs>");
19959 }
19960 else {
19961 exitStatus("Error", "-sysroot <dirpath> option should be specified, usually it's \"/\"");
19962 }
19963 detect_default_paths("bin|gcc"); # to check symbols
19964 if($OStarget eq "windows")
19965 { # to run dumpbin.exe
19966 # and undname.exe
19967 check_win32_env();
19968 }
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040019969 dumpSystem(getSysOpts());
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040019970 exit(0);
19971 }
19972 if($CmpSystems)
19973 { # --cmp-systems
19974 detect_default_paths("bin"); # to extract dumps
19975 loadModule("SysCheck");
Andrey Ponomarenko9927e332012-10-19 10:50:48 +040019976 cmpSystems($Descriptor{1}{"Path"}, $Descriptor{2}{"Path"}, getSysOpts());
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040019977 exit(0);
19978 }
19979 if($GenerateTemplate) {
19980 generateTemplate();
19981 exit(0);
19982 }
19983 if(not $TargetLibraryName) {
19984 exitStatus("Error", "library name is not selected (option -l <name>)");
19985 }
19986 else
19987 { # validate library name
19988 if($TargetLibraryName=~/[\*\/\\]/) {
19989 exitStatus("Error", "\"\\\", \"\/\" and \"*\" symbols are not allowed in the library name");
19990 }
19991 }
19992 if(not $TargetLibraryFName) {
19993 $TargetLibraryFName = $TargetLibraryName;
19994 }
19995 if($CheckHeadersOnly_Opt and $CheckObjectsOnly_Opt) {
19996 exitStatus("Error", "you can't specify both -headers-only and -objects-only options at the same time");
19997 }
19998 if($SymbolsListPath)
19999 {
20000 if(not -f $SymbolsListPath) {
20001 exitStatus("Access_Error", "can't access file \'$SymbolsListPath\'");
20002 }
20003 foreach my $Interface (split(/\s*\n\s*/, readFile($SymbolsListPath))) {
20004 $SymbolsList{$Interface} = 1;
20005 }
20006 }
20007 if($SkipHeadersPath)
20008 {
20009 if(not -f $SkipHeadersPath) {
20010 exitStatus("Access_Error", "can't access file \'$SkipHeadersPath\'");
20011 }
20012 foreach my $Path (split(/\s*\n\s*/, readFile($SkipHeadersPath)))
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040020013 { # register for both versions
20014 $SkipHeadersList{1}{$Path} = 1;
20015 $SkipHeadersList{2}{$Path} = 1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040020016 my ($CPath, $Type) = classifyPath($Path);
20017 $SkipHeaders{1}{$Type}{$CPath} = 1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040020018 $SkipHeaders{2}{$Type}{$CPath} = 1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040020019 }
20020 }
20021 if($ParamNamesPath)
20022 {
20023 if(not -f $ParamNamesPath) {
20024 exitStatus("Access_Error", "can't access file \'$ParamNamesPath\'");
20025 }
20026 foreach my $Line (split(/\n/, readFile($ParamNamesPath)))
20027 {
20028 if($Line=~s/\A(\w+)\;//)
20029 {
20030 my $Interface = $1;
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040020031 if($Line=~/;(\d+);/)
20032 {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040020033 while($Line=~s/(\d+);(\w+)//) {
20034 $AddIntParams{$Interface}{$1}=$2;
20035 }
20036 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040020037 else
20038 {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040020039 my $Num = 0;
20040 foreach my $Name (split(/;/, $Line)) {
20041 $AddIntParams{$Interface}{$Num++}=$Name;
20042 }
20043 }
20044 }
20045 }
20046 }
20047 if($AppPath)
20048 {
20049 if(not -f $AppPath) {
20050 exitStatus("Access_Error", "can't access file \'$AppPath\'");
20051 }
Andrey Ponomarenko16934472012-03-29 15:37:04 +040020052 foreach my $Interface (readSymbols_App($AppPath)) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040020053 $SymbolsList_App{$Interface} = 1;
20054 }
20055 }
20056 if($DumpAPI)
20057 { # --dump-abi
20058 # make an API dump
20059 create_ABI_Dump();
20060 exit($COMPILE_ERRORS);
20061 }
20062 # default: compare APIs
20063 # -d1 <path>
20064 # -d2 <path>
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040020065 compareInit();
20066 if($JoinReport or $DoubleReport)
20067 {
20068 compareAPIs("Binary");
20069 compareAPIs("Source");
20070 }
20071 elsif($BinaryOnly) {
20072 compareAPIs("Binary");
20073 }
20074 elsif($SourceOnly) {
20075 compareAPIs("Source");
20076 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040020077 exitReport();
20078}
20079
20080scenario();