blob: bfcb916451e472fefe82943cab46c389631ee7d0 [file] [log] [blame]
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04001#!/usr/bin/perl
2###########################################################################
Andrey Ponomarenkob8d203d2012-05-25 18:11:07 +04003# ABI Compliance Checker (ACC) 1.97.7
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 Ponomarenkoab282102012-03-11 11:57:02 +040023#
24# Mac OS X
25# - Xcode (gcc, otool, c++filt)
26#
27# MS Windows
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +040028# - MinGW (3.0-4.7, recommended 4.5 or newer)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040029# - MS Visual C++ (dumpbin, undname, cl)
Andrey Ponomarenko85043792012-05-14 16:48:07 +040030# - Active Perl 5 (5.8 or newer)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040031# - Sigcheck v1.71 or newer
32# - Info-ZIP 3.0 (zip, unzip)
33# - Add gcc.exe path (C:\MinGW\bin\) to your system PATH variable
34# - Run vsvars32.bat (C:\Microsoft Visual Studio 9.0\Common7\Tools\)
35#
36# This program is free software: you can redistribute it and/or modify
37# it under the terms of the GNU General Public License or the GNU Lesser
38# General Public License as published by the Free Software Foundation.
39#
40# This program is distributed in the hope that it will be useful,
41# but WITHOUT ANY WARRANTY; without even the implied warranty of
42# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
43# GNU General Public License for more details.
44#
45# You should have received a copy of the GNU General Public License
46# and the GNU Lesser General Public License along with this program.
47# If not, see <http://www.gnu.org/licenses/>.
48###########################################################################
49use Getopt::Long;
50Getopt::Long::Configure ("posix_default", "no_ignore_case");
51use File::Path qw(mkpath rmtree);
52use File::Temp qw(tempdir);
53use File::Copy qw(copy move);
54use Cwd qw(abs_path cwd);
55use Data::Dumper;
Andrey Ponomarenko2fba6302012-03-29 17:44:47 +040056use Config;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040057
Andrey Ponomarenkob8d203d2012-05-25 18:11:07 +040058my $TOOL_VERSION = "1.97.7";
59my $ABI_DUMP_VERSION = "2.16";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040060my $OLDEST_SUPPORTED_VERSION = "1.18";
61my $XML_REPORT_VERSION = "1.0";
62my $OSgroup = get_OSgroup();
63my $ORIG_DIR = cwd();
64my $TMP_DIR = tempdir(CLEANUP=>1);
65
66# Internal modules
67my $MODULES_DIR = get_Modules();
68push(@INC, get_dirname($MODULES_DIR));
69# Rules DB
70my %RULES_PATH = (
71 "Binary" => $MODULES_DIR."/RulesBin.xml",
72 "Source" => $MODULES_DIR."/RulesSrc.xml");
73
74my ($Help, $ShowVersion, %Descriptor, $TargetLibraryName, $GenerateTemplate,
75$TestTool, $DumpAPI, $SymbolsListPath, $CheckHeadersOnly_Opt, $UseDumps,
76$CheckObjectsOnly_Opt, $AppPath, $StrictCompat, $DumpVersion, $ParamNamesPath,
77%RelativeDirectory, $TargetLibraryFName, $TestDump, $CheckImpl, $LoggingPath,
78%TargetVersion, $InfoMsg, $UseOldDumps, %UsedDump, $CrossGcc, %OutputLogPath,
79$OutputReportPath, $OutputDumpPath, $ShowRetVal, $SystemRoot_Opt, $DumpSystem,
80$CmpSystems, $TargetLibsPath, $Debug, $CrossPrefix, $UseStaticLibs, $NoStdInc,
81$TargetComponent_Opt, $TargetSysInfo, $TargetHeader, $ExtendedCheck, $Quiet,
82$SkipHeadersPath, $Cpp2003, $LogMode, $StdOut, $ListAffected, $ReportFormat,
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040083$UserLang, $TargetHeadersPath, $BinaryOnly, $SourceOnly, $BinaryReportPath,
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040084$SourceReportPath, $UseXML, $Browse, $OpenReport, $SortDump);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040085
86my $CmdName = get_filename($0);
87my %OS_LibExt = (
88 "dynamic" => {
89 "default"=>"so",
90 "macos"=>"dylib",
91 "windows"=>"dll",
92 "symbian"=>"dso"
93 },
94 "static" => {
95 "default"=>"a",
96 "windows"=>"lib",
97 "symbian"=>"lib"
98 }
99);
100
101my %OS_Archive = (
102 "windows"=>"zip",
103 "default"=>"tar.gz"
104);
105
106my %ERROR_CODE = (
107 # Compatible verdict
108 "Compatible"=>0,
109 "Success"=>0,
110 # Incompatible verdict
111 "Incompatible"=>1,
112 # Undifferentiated error code
113 "Error"=>2,
114 # System command is not found
115 "Not_Found"=>3,
116 # Cannot access input files
117 "Access_Error"=>4,
118 # Cannot compile header files
119 "Cannot_Compile"=>5,
120 # Header compiled with errors
121 "Compile_Error"=>6,
122 # Invalid input ABI dump
123 "Invalid_Dump"=>7,
124 # Incompatible version of ABI dump
125 "Dump_Version"=>8,
126 # Cannot find a module
127 "Module_Error"=>9,
128 # Empty intersection between
129 # headers and shared objects
130 "Empty_Intersection"=>10,
131 # Empty set of symbols in headers
132 "Empty_Set"=>11
133);
134
135my %HomePage = (
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +0400136 "Wiki"=>"http://ispras.linuxbase.org/index.php/ABI_compliance_checker",
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +0400137 "Dev1"=>"https://github.com/lvc/abi-compliance-checker",
138 "Dev2"=>"http://forge.ispras.ru/projects/abi-compliance-checker"
Andrey Ponomarenkoab282102012-03-11 11:57:02 +0400139);
140
141my $ShortUsage = "ABI Compliance Checker (ACC) $TOOL_VERSION
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +0400142A tool for checking backward compatibility of a C/C++ library API
Andrey Ponomarenkoab282102012-03-11 11:57:02 +0400143Copyright (C) 2012 ROSA Laboratory
144License: GNU LGPL or GNU GPL
145
146Usage: $CmdName [options]
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +0400147Example: $CmdName -lib NAME -old OLD.xml -new NEW.xml
Andrey Ponomarenkoab282102012-03-11 11:57:02 +0400148
149OLD.xml and NEW.xml are XML-descriptors:
150
151 <version>
152 1.0
153 </version>
154
155 <headers>
156 /path/to/headers/
157 </headers>
158
159 <libs>
160 /path/to/libraries/
161 </libs>
162
163More info: $CmdName --help\n";
164
165if($#ARGV==-1) {
166 printMsg("INFO", $ShortUsage);
167 exit(0);
168}
169
170foreach (2 .. $#ARGV)
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +0400171{ # correct comma separated options
Andrey Ponomarenkoab282102012-03-11 11:57:02 +0400172 if($ARGV[$_-1] eq ",") {
173 $ARGV[$_-2].=",".$ARGV[$_];
174 splice(@ARGV, $_-1, 2);
175 }
176 elsif($ARGV[$_-1]=~/,\Z/) {
177 $ARGV[$_-1].=$ARGV[$_];
178 splice(@ARGV, $_, 1);
179 }
180 elsif($ARGV[$_]=~/\A,/
181 and $ARGV[$_] ne ",") {
182 $ARGV[$_-1].=$ARGV[$_];
183 splice(@ARGV, $_, 1);
184 }
185}
186
187GetOptions("h|help!" => \$Help,
188 "i|info!" => \$InfoMsg,
189 "v|version!" => \$ShowVersion,
190 "dumpversion!" => \$DumpVersion,
191# general options
192 "l|lib|library=s" => \$TargetLibraryName,
193 "d1|old|o=s" => \$Descriptor{1}{"Path"},
194 "d2|new|n=s" => \$Descriptor{2}{"Path"},
195 "dump|dump-abi|dump_abi=s" => \$DumpAPI,
196 "old-dumps!" => \$UseOldDumps,
197# extra options
198 "d|descriptor-template!" => \$GenerateTemplate,
199 "app|application=s" => \$AppPath,
200 "static-libs!" => \$UseStaticLibs,
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +0400201 "cross-gcc|gcc-path=s" => \$CrossGcc,
202 "cross-prefix|gcc-prefix=s" => \$CrossPrefix,
Andrey Ponomarenkoab282102012-03-11 11:57:02 +0400203 "sysroot=s" => \$SystemRoot_Opt,
204 "v1|version1|vnum=s" => \$TargetVersion{1},
205 "v2|version2=s" => \$TargetVersion{2},
206 "s|strict!" => \$StrictCompat,
207 "symbols-list=s" => \$SymbolsListPath,
208 "skip-headers=s" => \$SkipHeadersPath,
209 "headers-only|headers_only!" => \$CheckHeadersOnly_Opt,
210 "objects-only!" => \$CheckObjectsOnly_Opt,
211 "check-impl|check-implementation!" => \$CheckImpl,
212 "show-retval!" => \$ShowRetVal,
213 "use-dumps!" => \$UseDumps,
214 "nostdinc!" => \$NoStdInc,
215 "dump-system=s" => \$DumpSystem,
216 "sysinfo=s" => \$TargetSysInfo,
217 "cmp-systems!" => \$CmpSystems,
218 "libs-list=s" => \$TargetLibsPath,
219 "headers-list=s" => \$TargetHeadersPath,
220 "header=s" => \$TargetHeader,
221 "ext|extended!" => \$ExtendedCheck,
222 "q|quiet!" => \$Quiet,
223 "stdout!" => \$StdOut,
224 "report-format=s" => \$ReportFormat,
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +0400225 "xml!" => \$UseXML,
Andrey Ponomarenkoab282102012-03-11 11:57:02 +0400226 "lang=s" => \$UserLang,
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +0400227 "binary|bin|abi!" => \$BinaryOnly,
228 "source|src|api!" => \$SourceOnly,
Andrey Ponomarenkoab282102012-03-11 11:57:02 +0400229# other options
230 "test!" => \$TestTool,
231 "test-dump!" => \$TestDump,
232 "debug!" => \$Debug,
233 "cpp-compatible!" => \$Cpp2003,
234 "p|params=s" => \$ParamNamesPath,
235 "relpath1|relpath=s" => \$RelativeDirectory{1},
236 "relpath2=s" => \$RelativeDirectory{2},
237 "dump-path=s" => \$OutputDumpPath,
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +0400238 "sort!" => \$SortDump,
Andrey Ponomarenkoab282102012-03-11 11:57:02 +0400239 "report-path=s" => \$OutputReportPath,
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +0400240 "bin-report-path=s" => \$BinaryReportPath,
241 "src-report-path=s" => \$SourceReportPath,
Andrey Ponomarenkoab282102012-03-11 11:57:02 +0400242 "log-path=s" => \$LoggingPath,
243 "log1-path=s" => \$OutputLogPath{1},
244 "log2-path=s" => \$OutputLogPath{2},
245 "logging-mode=s" => \$LogMode,
246 "list-affected!" => \$ListAffected,
247 "l-full|lib-full=s" => \$TargetLibraryFName,
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +0400248 "component=s" => \$TargetComponent_Opt,
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +0400249 "b|browse=s" => \$Browse,
250 "open!" => \$OpenReport
Andrey Ponomarenkoab282102012-03-11 11:57:02 +0400251) or ERR_MESSAGE();
252
253sub ERR_MESSAGE()
254{
255 printMsg("INFO", "\n".$ShortUsage);
256 exit($ERROR_CODE{"Error"});
257}
258
259my $LIB_TYPE = $UseStaticLibs?"static":"dynamic";
260my $SLIB_TYPE = $LIB_TYPE;
261if($OSgroup!~/macos|windows/ and $SLIB_TYPE eq "dynamic")
262{ # show as "shared" library
263 $SLIB_TYPE = "shared";
264}
265my $LIB_EXT = getLIB_EXT($OSgroup);
266my $AR_EXT = getAR_EXT($OSgroup);
267my $BYTE_SIZE = 8;
268my $COMMON_LOG_PATH = "logs/run.log";
269
270my $HelpMessage="
271NAME:
272 ABI Compliance Checker ($CmdName)
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +0400273 Check backward compatibility of a C/C++ library API
Andrey Ponomarenkoab282102012-03-11 11:57:02 +0400274
275DESCRIPTION:
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +0400276 ABI Compliance Checker (ACC) is a tool for checking backward binary and
277 source-level compatibility of a $SLIB_TYPE C/C++ library. The tool checks
278 header files and $SLIB_TYPE libraries (*.$LIB_EXT) of old and new versions and
279 analyzes changes in API and ABI (ABI=API+compiler ABI) that may break binary
280 and/or source-level compatibility: changes in calling stack, v-table changes,
281 removed symbols, renamed fields, etc. Binary incompatibility may result in
282 crashing or incorrect behavior of applications built with an old version of
283 a library if they run on a new one. Source incompatibility may result in
284 recompilation errors with a new library version.
Andrey Ponomarenkoab282102012-03-11 11:57:02 +0400285
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +0400286 The tool is intended for developers of software libraries and maintainers
287 of operating systems who are interested in ensuring backward compatibility,
288 i.e. allow old applications to run or to be recompiled with newer library
289 versions.
290
291 Also the tool can be used by ISVs for checking applications portability to
292 new library versions. Found issues can be taken into account when adapting
293 the application to a new library version.
Andrey Ponomarenkoab282102012-03-11 11:57:02 +0400294
295 This tool is free software: you can redistribute it and/or modify it
296 under the terms of the GNU LGPL or GNU GPL.
297
298USAGE:
299 $CmdName [options]
300
301EXAMPLE:
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +0400302 $CmdName -lib NAME -old OLD.xml -new NEW.xml
Andrey Ponomarenkoab282102012-03-11 11:57:02 +0400303
304 OLD.xml and NEW.xml are XML-descriptors:
305
306 <version>
307 1.0
308 </version>
309
310 <headers>
311 /path1/to/header(s)/
312 /path2/to/header(s)/
313 ...
314 </headers>
315
316 <libs>
317 /path1/to/library(ies)/
318 /path2/to/library(ies)/
319 ...
320 </libs>
321
322INFORMATION OPTIONS:
323 -h|-help
324 Print this help.
325
326 -i|-info
327 Print complete info.
328
329 -v|-version
330 Print version information.
331
332 -dumpversion
333 Print the tool version ($TOOL_VERSION) and don't do anything else.
334
335GENERAL OPTIONS:
336 -l|-lib|-library <name>
337 Library name (without version).
338 It affects only on the path and the title of the report.
339
340 -d1|-old|-o <path>
341 Descriptor of 1st (old) library version.
342 It may be one of the following:
343
344 1. XML-descriptor (VERSION.xml file):
345
346 <version>
347 1.0
348 </version>
349
350 <headers>
351 /path1/to/header(s)/
352 /path2/to/header(s)/
353 ...
354 </headers>
355
356 <libs>
357 /path1/to/library(ies)/
358 /path2/to/library(ies)/
359 ...
360 </libs>
361
362 ... (XML-descriptor template
363 can be generated by -d option)
364
365 2. ABI dump generated by -dump option
366 3. Directory with headers and/or $SLIB_TYPE libraries
367 4. Single header file
368 5. Single $SLIB_TYPE library
369 6. Comma separated list of headers and/or libraries
370
371 If you are using an 2-6 descriptor types then you should
372 specify version numbers with -v1 <num> and -v2 <num> options too.
373
374 For more information, please see:
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +0400375 http://ispras.linuxbase.org/index.php/Library_Descriptor
Andrey Ponomarenkoab282102012-03-11 11:57:02 +0400376
377 -d2|-new|-n <path>
378 Descriptor of 2nd (new) library version.
379
380 -dump|-dump-abi <descriptor path(s)>
381 Dump library ABI to gzipped TXT format file. You can transfer it
382 anywhere and pass instead of the descriptor. Also it can be used
383 for debugging the tool. Compatible dump versions: ".majorVersion($ABI_DUMP_VERSION).".0<=V<=$ABI_DUMP_VERSION
384
385 -old-dumps
386 Enable support for old-version ABI dumps ($OLDEST_SUPPORTED_VERSION<=V<".majorVersion($ABI_DUMP_VERSION).".0).\n";
387
388sub HELP_MESSAGE() {
389 printMsg("INFO", $HelpMessage."
390MORE INFO:
391 $CmdName --info\n");
392}
393
394sub INFO_MESSAGE()
395{
396 printMsg("INFO", "$HelpMessage
397EXTRA OPTIONS:
398 -d|-descriptor-template
399 Create XML-descriptor template ./VERSION.xml
400
401 -app|-application <path>
402 This option allows to specify the application that should be checked
403 for portability to the new library version.
404
405 -static-libs
406 Check static libraries instead of the shared ones. The <libs> section
407 of the XML-descriptor should point to static libraries location.
408
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +0400409 -cross-gcc|-gcc-path <path>
Andrey Ponomarenkoab282102012-03-11 11:57:02 +0400410 Path to the cross GCC compiler to use instead of the usual (host) GCC.
411
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +0400412 -cross-prefix|-gcc-prefix <prefix>
Andrey Ponomarenkoab282102012-03-11 11:57:02 +0400413 GCC toolchain prefix.
414
415 -sysroot <dirpath>
416 Specify the alternative root directory. The tool will search for include
417 paths in the <dirpath>/usr/include and <dirpath>/usr/lib directories.
418
419 -v1|-version1 <num>
420 Specify 1st library version outside the descriptor. This option is needed
421 if you have prefered an alternative descriptor type (see -d1 option).
422
423 In general case you should specify it in the XML-descriptor:
424 <version>
425 VERSION
426 </version>
427
428 -v2|-version2 <num>
429 Specify 2nd library version outside the descriptor.
430
431 -s|-strict
432 Treat all compatibility warnings as problems. Add a number of \"Low\"
433 severity problems to the return value of the tool.
434
435 -headers-only
436 Check header files without $SLIB_TYPE libraries. It is easy to run, but may
437 provide a low quality compatibility report with false positives and
438 without detecting of added/removed symbols.
439
440 Alternatively you can write \"none\" word to the <libs> section
441 in the XML-descriptor:
442 <libs>
443 none
444 </libs>
445
446 -objects-only
447 Check $SLIB_TYPE libraries without header files. It is easy to run, but may
448 provide a low quality compatibility report with false positives and
449 without analysis of changes in parameters and data types.
450
451 Alternatively you can write \"none\" word to the <headers> section
452 in the XML-descriptor:
453 <headers>
454 none
455 </headers>
456
457 -check-impl|-check-implementation
458 Compare canonified disassembled binary code of $SLIB_TYPE libraries to
459 detect changes in the implementation. Add \'Problems with Implementation\'
460 section to the report.
461
462 -show-retval
463 Show the symbol's return type in the report.
464
465 -symbols-list <path>
466 This option allows to specify a file with a list of symbols (mangled
467 names in C++) that should be checked, other symbols will not be checked.
468
469 -skip-headers <path>
470 The file with the list of header files, that should not be checked.
471
472 -use-dumps
473 Make dumps for two versions of a library and compare dumps. This should
474 increase the performance of the tool and decrease the system memory usage.
475
476 -nostdinc
477 Do not search the GCC standard system directories for header files.
478
479 -dump-system <name> -sysroot <dirpath>
480 Find all the shared libraries and header files in <dirpath> directory,
481 create XML descriptors and make ABI dumps for each library. The result
482 set of ABI dumps can be compared (--cmp-systems) with the other one
483 created for other version of operating system in order to check them for
484 compatibility. Do not forget to specify -cross-gcc option if your target
485 system requires some specific version of GCC compiler (different from
486 the host GCC). The system ABI dump will be generated to:
487 sys_dumps/<name>/<arch>
488
489 -dump-system <descriptor.xml>
490 The same as the previous option but takes an XML descriptor of the target
491 system as input, where you should describe it:
492
493 /* Primary sections */
494
495 <name>
496 /* Name of the system */
497 </name>
498
499 <headers>
500 /* The list of paths to header files and/or
501 directories with header files, one per line */
502 </headers>
503
504 <libs>
505 /* The list of paths to shared libraries and/or
506 directories with shared libraries, one per line */
507 </libs>
508
509 /* Optional sections */
510
511 <search_headers>
512 /* List of directories to be searched
513 for header files to automatically
514 generate include paths, one per line */
515 </search_headers>
516
517 <search_libs>
518 /* List of directories to be searched
519 for shared libraries to resolve
520 dependencies, one per line */
521 </search_libs>
522
523 <tools>
524 /* List of directories with tools used
525 for analysis (GCC toolchain), one per line */
526 </tools>
527
528 <cross_prefix>
529 /* GCC toolchain prefix.
530 Examples:
531 arm-linux-gnueabi
532 arm-none-symbianelf */
533 </cross_prefix>
534
535 <gcc_options>
536 /* Additional GCC options, one per line */
537 </gcc_options>
538
539 -sysinfo <dir>
540 This option may be used with -dump-system to dump ABI of operating
541 systems and configure the dumping process.
542 Default:
543 modules/Targets/{unix, symbian, windows}
544
545 -cmp-systems -d1 sys_dumps/<name1>/<arch> -d2 sys_dumps/<name2>/<arch>
546 Compare two system ABI dumps. Create compatibility reports for each
547 library and the common HTML report including the summary of test
548 results for all checked libraries. Report will be generated to:
549 sys_compat_reports/<name1>_to_<name2>/<arch>
550
551 -libs-list <path>
552 The file with a list of libraries, that should be dumped by
553 the -dump-system option or should be checked by the -cmp-systems option.
554
555 -header <name>
556 Check/Dump ABI of this header only.
557
558 -headers-list <path>
559 The file with a list of headers, that should be checked/dumped.
560
561 -ext|-extended
562 If your library A is supposed to be used by other library B and you
563 want to control the ABI of B, then you should enable this option. The
564 tool will check for changes in all data types, even if they are not
565 used by any function in the library A. Such data types are not part
566 of the A library ABI, but may be a part of the ABI of the B library.
567
568 The short scheme is:
569 app C (broken) -> lib B (broken ABI) -> lib A (stable ABI)
570
571 -q|-quiet
572 Print all messages to the file instead of stdout and stderr.
573 Default path (can be changed by -log-path option):
574 $COMMON_LOG_PATH
575
576 -stdout
577 Print analysis results (compatibility reports and ABI dumps) to stdout
578 instead of creating a file. This would allow piping data to other programs.
579
580 -report-format <fmt>
581 Change format of compatibility report.
582 Formats:
583 htm - HTML format (default)
584 xml - XML format
585
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +0400586 -xml
587 Alias for: --report-format=xml
588
Andrey Ponomarenkoab282102012-03-11 11:57:02 +0400589 -lang <lang>
590 Set library language (C or C++). You can use this option if the tool
591 cannot auto-detect a language. This option may be useful for checking
592 C-library headers (--lang=C) in --headers-only or --extended modes.
593
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +0400594 -binary|-bin|-abi
595 Show \"Binary\" compatibility problems only.
596 Generate report to:
597 compat_reports/<library name>/<v1>_to_<v2>/abi_compat_report.html
598
599 -source|-src|-api
600 Show \"Source\" compatibility problems only.
601 Generate report to:
602 compat_reports/<library name>/<v1>_to_<v2>/src_compat_report.html
603
Andrey Ponomarenkoab282102012-03-11 11:57:02 +0400604OTHER OPTIONS:
605 -test
606 Run internal tests. Create two binary incompatible versions of a sample
607 library and run the tool to check them for compatibility. This option
608 allows to check if the tool works correctly in the current environment.
609
610 -test-dump
611 Test ability to create, read and compare ABI dumps.
612
613 -debug
614 Debugging mode. Print debug info on the screen. Save intermediate
615 analysis stages in the debug directory:
616 debug/<library>/<version>/
617
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +0400618 Also consider using --dump option for debugging the tool.
619
Andrey Ponomarenkoab282102012-03-11 11:57:02 +0400620 -cpp-compatible
621 If your header file is written in C language and can be compiled by
622 the C++ compiler (i.e. doesn't contain C++-keywords and other bad
623 things), then you can tell ACC about this and speedup the analysis.
624
625 -p|-params <path>
626 Path to file with the function parameter names. It can be used
627 for improving report view if the library header files have no
628 parameter names. File format:
629
630 func1;param1;param2;param3 ...
631 func2;param1;param2;param3 ...
632 ...
633
634 -relpath <path>
635 Replace {RELPATH} macros to <path> in the XML-descriptor used
636 for dumping the library ABI (see -dump option).
637
638 -relpath1 <path>
639 Replace {RELPATH} macros to <path> in the 1st XML-descriptor (-d1).
640
641 -relpath2 <path>
642 Replace {RELPATH} macros to <path> in the 2nd XML-descriptor (-d2).
643
644 -dump-path <path>
645 Specify a file path (*.abi.$AR_EXT) where to generate an ABI dump.
646 Default:
647 abi_dumps/<library>/<library>_<version>.abi.$AR_EXT
648
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +0400649 -sort
650 Enable sorting of data in ABI dumps.
651
Andrey Ponomarenkoab282102012-03-11 11:57:02 +0400652 -report-path <path>
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +0400653 Path to compatibility report.
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +0400654 Default:
655 compat_reports/<library name>/<v1>_to_<v2>/compat_report.html
656
657 -bin-report-path <path>
658 Path to \"Binary\" compatibility report.
Andrey Ponomarenkoab282102012-03-11 11:57:02 +0400659 Default:
660 compat_reports/<library name>/<v1>_to_<v2>/abi_compat_report.html
661
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +0400662 -src-report-path <path>
663 Path to \"Source\" compatibility report.
664 Default:
665 compat_reports/<library name>/<v1>_to_<v2>/src_compat_report.html
666
Andrey Ponomarenkoab282102012-03-11 11:57:02 +0400667 -log-path <path>
668 Log path for all messages.
669 Default:
670 logs/<library>/<version>/log.txt
671
672 -log1-path <path>
673 Log path for 1st version of a library.
674 Default:
675 logs/<library name>/<v1>/log.txt
676
677 -log2-path <path>
678 Log path for 2nd version of a library.
679 Default:
680 logs/<library name>/<v2>/log.txt
681
682 -logging-mode <mode>
683 Change logging mode.
684 Modes:
685 w - overwrite old logs (default)
686 a - append old logs
687 n - do not write any logs
688
689 -list-affected
690 Generate file with the list of incompatible
691 symbols beside the HTML compatibility report.
692 Use 'c++filt \@file' command from GNU binutils
693 to unmangle C++ symbols in the generated file.
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +0400694 Default names:
Andrey Ponomarenkoab282102012-03-11 11:57:02 +0400695 abi_affected.txt
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +0400696 src_affected.txt
Andrey Ponomarenkoab282102012-03-11 11:57:02 +0400697
698 -component <name>
699 The component name in the title and summary of the HTML report.
700 Default:
701 library
702
703 -l-full|-lib-full <name>
704 Change library name in the report title to <name>. By default
705 will be displayed a name specified by -l option.
706
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +0400707 -b|-browse <program>
708 Open report(s) in the browser (firefox, opera, etc.).
709
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +0400710 -open
711 Open report(s) in the default browser.
712
Andrey Ponomarenkoab282102012-03-11 11:57:02 +0400713REPORT:
714 Compatibility report will be generated to:
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +0400715 compat_reports/<library name>/<v1>_to_<v2>/compat_report.html
Andrey Ponomarenkoab282102012-03-11 11:57:02 +0400716
717 Log will be generated to:
718 logs/<library name>/<v1>/log.txt
719 logs/<library name>/<v2>/log.txt
720
721EXIT CODES:
722 0 - Compatible. The tool has run without any errors.
723 non-zero - Incompatible or the tool has run with errors.
724
725REPORT BUGS TO:
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +0400726 Andrey Ponomarenko <aponomarenko\@rosalab.ru>
Andrey Ponomarenkoab282102012-03-11 11:57:02 +0400727
728MORE INFORMATION:
729 ".$HomePage{"Wiki"}."
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +0400730 ".$HomePage{"Dev1"}."\n");
Andrey Ponomarenkoab282102012-03-11 11:57:02 +0400731}
732
733my $DescriptorTemplate = "
734<?xml version=\"1.0\" encoding=\"utf-8\"?>
735<descriptor>
736
737/* Primary sections */
738
739<version>
740 /* Version of the library */
741</version>
742
743<headers>
744 /* The list of paths to header files and/or
745 directories with header files, one per line */
746</headers>
747
748<libs>
749 /* The list of paths to shared libraries (*.$LIB_EXT) and/or
750 directories with shared libraries, one per line */
751</libs>
752
753/* Optional sections */
754
755<include_paths>
756 /* The list of include paths that will be provided
757 to GCC to compile library headers, one per line.
758 NOTE: If you define this section then the tool
759 will not automatically generate include paths */
760</include_paths>
761
762<add_include_paths>
763 /* The list of include paths that will be added
764 to the automatically generated include paths, one per line */
765</add_include_paths>
766
767<skip_include_paths>
768 /* The list of include paths that will be removed from the
769 list of automatically generated include paths, one per line */
770</skip_include_paths>
771
772<gcc_options>
773 /* Additional GCC options, one per line */
774</gcc_options>
775
776<include_preamble>
777 /* The list of header files that will be
778 included before other headers, one per line.
779 Examples:
780 1) tree.h for libxml2
781 2) ft2build.h for freetype2 */
782</include_preamble>
783
784<defines>
785 /* The list of defines that will be added at the
786 headers compiling stage, one per line:
787 #define A B
788 #define C D */
789</defines>
790
791<skip_types>
792 /* The list of data types, that
793 should not be checked, one per line */
794</skip_types>
795
796<skip_symbols>
797 /* The list of functions (mangled/symbol names in C++),
798 that should not be checked, one per line */
799</skip_symbols>
800
801<skip_namespaces>
802 /* The list of C++ namespaces, that
803 should not be checked, one per line */
804</skip_namespaces>
805
806<skip_constants>
807 /* The list of constants that should
808 not be checked, one name per line */
809</skip_constants>
810
811<skip_headers>
812 /* The list of header files and/or directories
813 with header files that should not be checked, one per line */
814</skip_headers>
815
816<skip_libs>
817 /* The list of shared libraries and/or directories
818 with shared libraries that should not be checked, one per line */
819</skip_libs>
820
821<skip_including>
822 /* The list of header files, that cannot be included
823 directly (or non-self compiled ones), one per line */
824</skip_including>
825
826<search_headers>
827 /* List of directories to be searched
828 for header files to automatically
829 generate include paths, one per line. */
830</search_headers>
831
832<search_libs>
833 /* List of directories to be searched
834 for shared librariess to resolve
835 dependencies, one per line */
836</search_libs>
837
838<tools>
839 /* List of directories with tools used
840 for analysis (GCC toolchain), one per line */
841</tools>
842
843<cross_prefix>
844 /* GCC toolchain prefix.
845 Examples:
846 arm-linux-gnueabi
847 arm-none-symbianelf */
848</cross_prefix>
849
850</descriptor>";
851
852my %Operator_Indication = (
853 "not" => "~",
854 "assign" => "=",
855 "andassign" => "&=",
856 "orassign" => "|=",
857 "xorassign" => "^=",
858 "or" => "|",
859 "xor" => "^",
860 "addr" => "&",
861 "and" => "&",
862 "lnot" => "!",
863 "eq" => "==",
864 "ne" => "!=",
865 "lt" => "<",
866 "lshift" => "<<",
867 "lshiftassign" => "<<=",
868 "rshiftassign" => ">>=",
869 "call" => "()",
870 "mod" => "%",
871 "modassign" => "%=",
872 "subs" => "[]",
873 "land" => "&&",
874 "lor" => "||",
875 "rshift" => ">>",
876 "ref" => "->",
877 "le" => "<=",
878 "deref" => "*",
879 "mult" => "*",
880 "preinc" => "++",
881 "delete" => " delete",
882 "vecnew" => " new[]",
883 "vecdelete" => " delete[]",
884 "predec" => "--",
885 "postinc" => "++",
886 "postdec" => "--",
887 "plusassign" => "+=",
888 "plus" => "+",
889 "minus" => "-",
890 "minusassign" => "-=",
891 "gt" => ">",
892 "ge" => ">=",
893 "new" => " new",
894 "multassign" => "*=",
895 "divassign" => "/=",
896 "div" => "/",
897 "neg" => "-",
898 "pos" => "+",
899 "memref" => "->*",
900 "compound" => "," );
901
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +0400902my %UnknownOperator;
903
904my %NodeType= (
905 "array_type" => "Array",
906 "binfo" => "Other",
907 "boolean_type" => "Intrinsic",
908 "complex_type" => "Intrinsic",
909 "const_decl" => "Other",
910 "enumeral_type" => "Enum",
911 "field_decl" => "Other",
912 "function_decl" => "Other",
913 "function_type" => "FunctionType",
914 "identifier_node" => "Other",
915 "integer_cst" => "Other",
916 "integer_type" => "Intrinsic",
917 "method_type" => "MethodType",
918 "namespace_decl" => "Other",
919 "parm_decl" => "Other",
920 "pointer_type" => "Pointer",
921 "real_cst" => "Other",
922 "real_type" => "Intrinsic",
923 "record_type" => "Struct",
924 "reference_type" => "Ref",
925 "string_cst" => "Other",
926 "template_decl" => "Other",
927 "template_type_parm" => "Other",
928 "tree_list" => "Other",
929 "tree_vec" => "Other",
930 "type_decl" => "Other",
931 "union_type" => "Union",
932 "var_decl" => "Other",
933 "void_type" => "Intrinsic",
934 # "nop_expr" => "Other",
935 # "addr_expr" => "Other",
936 "offset_type" => "Other" );
937
Andrey Ponomarenkoab282102012-03-11 11:57:02 +0400938my %CppKeywords_C = map {$_=>1} (
939 # C++ 2003 keywords
940 "public",
941 "protected",
942 "private",
943 "default",
944 "template",
945 "new",
946 #"asm",
947 "dynamic_cast",
948 "auto",
949 "try",
950 "namespace",
951 "typename",
952 "using",
953 "reinterpret_cast",
954 "friend",
955 "class",
956 "virtual",
957 "const_cast",
958 "mutable",
959 "static_cast",
960 "export",
961 # C++0x keywords
962 "noexcept",
963 "nullptr",
964 "constexpr",
965 "static_assert",
966 "explicit",
967 # cannot be used as a macro name
968 # as it is an operator in C++
969 "and",
970 #"and_eq",
971 "not",
972 #"not_eq",
973 "or"
974 #"or_eq",
975 #"bitand",
976 #"bitor",
977 #"xor",
978 #"xor_eq",
979 #"compl"
980);
981
982my %CppKeywords_F = map {$_=>1} (
983 "delete",
984 "catch",
985 "alignof",
986 "thread_local",
987 "decltype",
988 "typeid"
989);
990
991my %CppKeywords_O = map {$_=>1} (
992 "bool",
993 "register",
994 "inline",
995 "operator"
996);
997
998my %CppKeywords_A = map {$_=>1} (
999 "this",
1000 "throw"
1001);
1002
1003foreach (keys(%CppKeywords_C),
1004keys(%CppKeywords_F),
1005keys(%CppKeywords_O)) {
1006 $CppKeywords_A{$_}=1;
1007}
1008
1009# Header file extensions as described by gcc
1010my $HEADER_EXT = "h|hh|hp|hxx|hpp|h\\+\\+";
1011
1012my %IntrinsicMangling = (
1013 "void" => "v",
1014 "bool" => "b",
1015 "wchar_t" => "w",
1016 "char" => "c",
1017 "signed char" => "a",
1018 "unsigned char" => "h",
1019 "short" => "s",
1020 "unsigned short" => "t",
1021 "int" => "i",
1022 "unsigned int" => "j",
1023 "long" => "l",
1024 "unsigned long" => "m",
1025 "long long" => "x",
1026 "__int64" => "x",
1027 "unsigned long long" => "y",
1028 "__int128" => "n",
1029 "unsigned __int128" => "o",
1030 "float" => "f",
1031 "double" => "d",
1032 "long double" => "e",
1033 "__float80" => "e",
1034 "__float128" => "g",
1035 "..." => "z"
1036);
1037
1038my %StdcxxMangling = (
1039 "3std"=>"St",
1040 "3std9allocator"=>"Sa",
1041 "3std12basic_string"=>"Sb",
1042 "3std12basic_stringIcE"=>"Ss",
1043 "3std13basic_istreamIcE"=>"Si",
1044 "3std13basic_ostreamIcE"=>"So",
1045 "3std14basic_iostreamIcE"=>"Sd"
1046);
1047
1048my %ConstantSuffix = (
1049 "unsigned int"=>"u",
1050 "long"=>"l",
1051 "unsigned long"=>"ul",
1052 "long long"=>"ll",
1053 "unsigned long long"=>"ull"
1054);
1055
1056my %ConstantSuffixR =
1057reverse(%ConstantSuffix);
1058
1059my %OperatorMangling = (
1060 "~" => "co",
1061 "=" => "aS",
1062 "|" => "or",
1063 "^" => "eo",
1064 "&" => "an",#ad (addr)
1065 "==" => "eq",
1066 "!" => "nt",
1067 "!=" => "ne",
1068 "<" => "lt",
1069 "<=" => "le",
1070 "<<" => "ls",
1071 "<<=" => "lS",
1072 ">" => "gt",
1073 ">=" => "ge",
1074 ">>" => "rs",
1075 ">>=" => "rS",
1076 "()" => "cl",
1077 "%" => "rm",
1078 "[]" => "ix",
1079 "&&" => "aa",
1080 "||" => "oo",
1081 "*" => "ml",#de (deref)
1082 "++" => "pp",#
1083 "--" => "mm",#
1084 "new" => "nw",
1085 "delete" => "dl",
1086 "new[]" => "na",
1087 "delete[]" => "da",
1088 "+=" => "pL",
1089 "+" => "pl",#ps (pos)
1090 "-" => "mi",#ng (neg)
1091 "-=" => "mI",
1092 "*=" => "mL",
1093 "/=" => "dV",
1094 "&=" => "aN",
1095 "|=" => "oR",
1096 "%=" => "rM",
1097 "^=" => "eO",
1098 "/" => "dv",
1099 "->*" => "pm",
1100 "->" => "pt",#rf (ref)
1101 "," => "cm",
1102 "?" => "qu",
1103 "." => "dt",
1104 "sizeof"=> "sz"#st
1105);
1106
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04001107my %Intrinsic_Keywords = map {$_=>1} (
1108 "true",
1109 "false",
1110 "_Bool",
1111 "_Complex",
1112 "const",
1113 "int",
1114 "long",
1115 "void",
1116 "short",
1117 "float",
1118 "volatile",
1119 "restrict",
1120 "unsigned",
1121 "signed",
1122 "char",
1123 "double",
1124 "class",
1125 "struct",
1126 "union",
1127 "enum"
1128);
1129
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04001130my %GlibcHeader = map {$_=>1} (
1131 "aliases.h",
1132 "argp.h",
1133 "argz.h",
1134 "assert.h",
1135 "cpio.h",
1136 "ctype.h",
1137 "dirent.h",
1138 "envz.h",
1139 "errno.h",
1140 "error.h",
1141 "execinfo.h",
1142 "fcntl.h",
1143 "fstab.h",
1144 "ftw.h",
1145 "glob.h",
1146 "grp.h",
1147 "iconv.h",
1148 "ifaddrs.h",
1149 "inttypes.h",
1150 "langinfo.h",
1151 "limits.h",
1152 "link.h",
1153 "locale.h",
1154 "malloc.h",
1155 "math.h",
1156 "mntent.h",
1157 "monetary.h",
1158 "nl_types.h",
1159 "obstack.h",
1160 "printf.h",
1161 "pwd.h",
1162 "regex.h",
1163 "sched.h",
1164 "search.h",
1165 "setjmp.h",
1166 "shadow.h",
1167 "signal.h",
1168 "spawn.h",
1169 "stdarg.h",
1170 "stdint.h",
1171 "stdio.h",
1172 "stdlib.h",
1173 "string.h",
1174 "tar.h",
1175 "termios.h",
1176 "time.h",
1177 "ulimit.h",
1178 "unistd.h",
1179 "utime.h",
1180 "wchar.h",
1181 "wctype.h",
1182 "wordexp.h" );
1183
1184my %GlibcDir = map {$_=>1} (
1185 "arpa",
1186 "bits",
1187 "gnu",
1188 "netinet",
1189 "net",
1190 "nfs",
1191 "rpc",
1192 "sys",
1193 "linux" );
1194
1195my %LocalIncludes = map {$_=>1} (
1196 "/usr/local/include",
1197 "/usr/local" );
1198
1199my %OS_AddPath=(
1200# These paths are needed if the tool cannot detect them automatically
1201 "macos"=>{
1202 "include"=>{
1203 "/Library"=>1,
1204 "/Developer/usr/include"=>1
1205 },
1206 "lib"=>{
1207 "/Library"=>1,
1208 "/Developer/usr/lib"=>1
1209 },
1210 "bin"=>{
1211 "/Developer/usr/bin"=>1
1212 }
1213 },
1214 "beos"=>{
1215 # Haiku has GCC 2.95.3 by default
1216 # try to find GCC>=3.0 in /boot/develop/abi
1217 "include"=>{
1218 "/boot/common"=>1,
1219 "/boot/develop"=>1},
1220 "lib"=>{
1221 "/boot/common/lib"=>1,
1222 "/boot/system/lib"=>1,
1223 "/boot/apps"=>1},
1224 "bin"=>{
1225 "/boot/common/bin"=>1,
1226 "/boot/system/bin"=>1,
1227 "/boot/develop/abi"=>1
1228 }
1229}
1230);
1231
1232my %Slash_Type=(
1233 "default"=>"/",
1234 "windows"=>"\\"
1235);
1236
1237my $SLASH = $Slash_Type{$OSgroup}?$Slash_Type{$OSgroup}:$Slash_Type{"default"};
1238
1239# Global Variables
1240my %COMMON_LANGUAGE=(
1241 1 => "C",
1242 2 => "C" );
1243
1244my $MAX_COMMAND_LINE_ARGUMENTS = 4096;
1245my (%WORD_SIZE, %CPU_ARCH, %GCC_VERSION);
1246
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04001247my $STDCXX_TESTING = 0;
1248my $GLIBC_TESTING = 0;
1249
1250my $CheckHeadersOnly = $CheckHeadersOnly_Opt;
1251my $CheckObjectsOnly = $CheckObjectsOnly_Opt;
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04001252my $TargetComponent;
1253
1254# Set Target Component Name
1255if($TargetComponent_Opt) {
1256 $TargetComponent = lc($TargetComponent_Opt);
1257}
1258else
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04001259{ # default: library
1260 # other components: header, system, ...
1261 $TargetComponent = "library";
1262}
1263
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04001264my $TOP_REF = "<a style='font-size:11px;' href='#Top'>to the top</a>";
1265
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04001266my $SystemRoot;
1267
1268my $MAIN_CPP_DIR;
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04001269my %RESULT;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04001270my %LOG_PATH;
1271my %DEBUG_PATH;
1272my %Cache;
1273my %LibInfo;
1274my $COMPILE_ERRORS = 0;
1275my %CompilerOptions;
1276my %CheckedDyLib;
1277my $TargetLibraryShortName = parse_libname($TargetLibraryName, "shortest", $OSgroup);
1278
1279# Constants (#defines)
1280my %Constants;
1281my %SkipConstants;
1282
1283# Types
1284my %TypeInfo;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04001285my %TemplateInstance;
Andrey Ponomarenko85043792012-05-14 16:48:07 +04001286my %TemplateDecl;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04001287my %SkipTypes = (
1288 "1"=>{},
1289 "2"=>{} );
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04001290my %CheckedTypes;
1291my %TName_Tid;
1292my %EnumMembName_Id;
1293my %NestedNameSpaces = (
1294 "1"=>{},
1295 "2"=>{} );
1296my %UsedType;
1297my %VirtualTable;
Andrey Ponomarenko16934472012-03-29 15:37:04 +04001298my %VirtualTable_Model;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04001299my %ClassVTable;
1300my %ClassVTable_Content;
1301my %VTableClass;
1302my %AllocableClass;
1303my %ClassMethods;
Andrey Ponomarenko16934472012-03-29 15:37:04 +04001304my %ClassNames;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04001305my %Class_SubClasses;
1306my %OverriddenMethods;
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04001307my $MAX_ID = 0;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04001308
1309# Typedefs
1310my %Typedef_BaseName;
1311my %Typedef_Tr;
1312my %Typedef_Eq;
1313my %StdCxxTypedef;
1314my %MissedTypedef;
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04001315my %MissedBase;
1316my %MissedBase_R;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04001317
1318# Symbols
1319my %SymbolInfo;
1320my %tr_name;
1321my %mangled_name_gcc;
1322my %mangled_name;
1323my %SkipSymbols = (
1324 "1"=>{},
1325 "2"=>{} );
1326my %SkipNameSpaces = (
1327 "1"=>{},
1328 "2"=>{} );
1329my %SymbolsList;
1330my %SymbolsList_App;
1331my %CheckedSymbols;
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04001332my %Symbol_Library = (
1333 "1"=>{},
1334 "2"=>{} );
1335my %Library_Symbol = (
1336 "1"=>{},
1337 "2"=>{} );
1338my %DepSymbol_Library = (
1339 "1"=>{},
1340 "2"=>{} );
1341my %DepLibrary_Symbol = (
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04001342 "1"=>{},
1343 "2"=>{} );
1344my %MangledNames;
1345my %AddIntParams;
1346my %Interface_Impl;
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04001347my %GlobalDataObject;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04001348
1349# Headers
1350my %Include_Preamble;
1351my %Registered_Headers;
1352my %HeaderName_Paths;
1353my %Header_Dependency;
1354my %Include_Neighbors;
1355my %Include_Paths;
1356my %INC_PATH_AUTODETECT = (
1357 "1"=>1,
1358 "2"=>1 );
1359my %Add_Include_Paths;
1360my %Skip_Include_Paths;
1361my %RegisteredDirs;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04001362my %Header_ErrorRedirect;
1363my %Header_Includes;
1364my %Header_ShouldNotBeUsed;
1365my %RecursiveIncludes;
1366my %Header_Include_Prefix;
1367my %SkipHeaders;
1368my %SkipHeadersList=(
1369 "1"=>{},
1370 "2"=>{} );
1371my %SkipLibs;
1372my %Include_Order;
1373my %TUnit_NameSpaces;
1374
1375my %C99Mode = (
1376 "1"=>0,
1377 "2"=>0 );
1378my %AutoPreambleMode = (
1379 "1"=>0,
1380 "2"=>0 );
1381my %MinGWMode = (
1382 "1"=>0,
1383 "2"=>0 );
1384
1385# Shared Objects
1386my %DyLib_DefaultPath;
1387my %InputObject_Paths;
1388my %RegisteredObjDirs;
1389
1390# System Objects
1391my %SystemObjects;
1392my %DefaultLibPaths;
1393
1394# System Headers
1395my %SystemHeaders;
1396my %DefaultCppPaths;
1397my %DefaultGccPaths;
1398my %DefaultIncPaths;
1399my %DefaultCppHeader;
1400my %DefaultGccHeader;
1401my %UserIncPath;
1402
1403# Merging
1404my %CompleteSignature;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04001405my $Version;
1406my %AddedInt;
1407my %RemovedInt;
1408my %AddedInt_Virt;
1409my %RemovedInt_Virt;
1410my %VirtualReplacement;
1411my %ChangedTypedef;
1412my %CompatRules;
1413my %IncompleteRules;
1414my %UnknownRules;
Andrey Ponomarenko16934472012-03-29 15:37:04 +04001415my %VTableChanged_M;
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04001416my %ExtendedSymbols;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04001417my %ReturnedClass;
1418my %ParamClass;
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04001419my %SourceAlternative;
1420my %SourceAlternative_B;
1421my %SourceReplacement;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04001422
1423# OS Compliance
1424my %TargetLibs;
1425my %TargetHeaders;
1426
1427# OS Specifics
1428my $OStarget = $OSgroup;
1429my %TargetTools;
1430
1431# Compliance Report
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04001432my %Type_MaxSeverity;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04001433
1434# Recursion locks
1435my @RecurLib;
1436my @RecurSymlink;
1437my @RecurTypes;
1438my @RecurInclude;
1439my @RecurConstant;
1440
1441# System
1442my %SystemPaths;
1443my %DefaultBinPaths;
1444my $GCC_PATH;
1445
1446# Symbols versioning
1447my %SymVer = (
1448 "1"=>{},
1449 "2"=>{} );
1450
1451# Problem descriptions
1452my %CompatProblems;
1453my %ProblemsWithConstants;
1454my %ImplProblems;
1455my %TotalAffected;
1456
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04001457# Reports
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04001458my $ContentID = 1;
1459my $ContentSpanStart = "<span class=\"section\" onclick=\"javascript:showContent(this, 'CONTENT_ID')\">\n";
1460my $ContentSpanStart_Affected = "<span class=\"section_affected\" onclick=\"javascript:showContent(this, 'CONTENT_ID')\">\n";
1461my $ContentSpanStart_Info = "<span class=\"section_info\" onclick=\"javascript:showContent(this, 'CONTENT_ID')\">\n";
1462my $ContentSpanEnd = "</span>\n";
1463my $ContentDivStart = "<div id=\"CONTENT_ID\" style=\"display:none;\">\n";
1464my $ContentDivEnd = "</div>\n";
1465my $Content_Counter = 0;
1466
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04001467# Modes
1468my $JoinReport = 1;
1469my $DoubleReport = 0;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04001470
1471sub get_Modules()
1472{
1473 my $TOOL_DIR = get_dirname($0);
1474 if(not $TOOL_DIR)
1475 { # patch for MS Windows
1476 $TOOL_DIR = ".";
1477 }
1478 my @SEARCH_DIRS = (
1479 # tool's directory
1480 abs_path($TOOL_DIR),
1481 # relative path to modules
1482 abs_path($TOOL_DIR)."/../share/abi-compliance-checker",
1483 # system directory
1484 "ACC_MODULES_INSTALL_PATH"
1485 );
1486 foreach my $DIR (@SEARCH_DIRS)
1487 {
1488 if(not is_abs($DIR))
1489 { # relative path
1490 $DIR = abs_path($TOOL_DIR)."/".$DIR;
1491 }
1492 if(-d $DIR."/modules") {
1493 return $DIR."/modules";
1494 }
1495 }
1496 exitStatus("Module_Error", "can't find modules");
1497}
1498
1499sub loadModule($)
1500{
1501 my $Name = $_[0];
1502 my $Path = $MODULES_DIR."/Internals/$Name.pm";
1503 if(not -f $Path) {
1504 exitStatus("Module_Error", "can't access \'$Path\'");
1505 }
1506 require $Path;
1507}
1508
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04001509sub showPos($)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04001510{
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04001511 my $Number = $_[0];
1512 if(not $Number) {
1513 $Number = 1;
1514 }
1515 else {
1516 $Number = int($Number)+1;
1517 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04001518 if($Number>3) {
1519 return $Number."th";
1520 }
1521 elsif($Number==1) {
1522 return "1st";
1523 }
1524 elsif($Number==2) {
1525 return "2nd";
1526 }
1527 elsif($Number==3) {
1528 return "3rd";
1529 }
1530 else {
1531 return $Number;
1532 }
1533}
1534
1535sub search_Tools($)
1536{
1537 my $Name = $_[0];
1538 return "" if(not $Name);
1539 if(my @Paths = keys(%TargetTools))
1540 {
1541 foreach my $Path (@Paths)
1542 {
1543 if(-f joinPath($Path, $Name)) {
1544 return joinPath($Path, $Name);
1545 }
1546 if($CrossPrefix)
1547 { # user-defined prefix (arm-none-symbianelf, ...)
1548 my $Candidate = joinPath($Path, $CrossPrefix."-".$Name);
1549 if(-f $Candidate) {
1550 return $Candidate;
1551 }
1552 }
1553 }
1554 }
1555 else {
1556 return "";
1557 }
1558}
1559
1560sub synch_Cmd($)
1561{
1562 my $Name = $_[0];
1563 if(not $GCC_PATH)
1564 { # GCC was not found yet
1565 return "";
1566 }
1567 my $Candidate = $GCC_PATH;
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04001568 if($Candidate=~s/\bgcc(|\.\w+)\Z/$Name$1/) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04001569 return $Candidate;
1570 }
1571 return "";
1572}
1573
1574sub get_CmdPath($)
1575{
1576 my $Name = $_[0];
1577 return "" if(not $Name);
1578 if(defined $Cache{"get_CmdPath"}{$Name}) {
1579 return $Cache{"get_CmdPath"}{$Name};
1580 }
1581 my %BinUtils = map {$_=>1} (
1582 "c++filt",
1583 "objdump",
1584 "readelf"
1585 );
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04001586 if($BinUtils{$Name} and $GCC_PATH)
1587 {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04001588 if(my $Dir = get_dirname($GCC_PATH)) {
1589 $TargetTools{$Dir}=1;
1590 }
1591 }
1592 my $Path = search_Tools($Name);
1593 if(not $Path and $OSgroup eq "windows") {
1594 $Path = search_Tools($Name.".exe");
1595 }
1596 if(not $Path and $BinUtils{$Name})
1597 {
1598 if($CrossPrefix)
1599 { # user-defined prefix
1600 $Path = search_Cmd($CrossPrefix."-".$Name);
1601 }
1602 }
1603 if(not $Path and $BinUtils{$Name})
1604 {
1605 if(my $Candidate = synch_Cmd($Name))
1606 { # synch with GCC
1607 if($Candidate=~/[\/\\]/)
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04001608 { # command path
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04001609 if(-f $Candidate) {
1610 $Path = $Candidate;
1611 }
1612 }
1613 elsif($Candidate = search_Cmd($Candidate))
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04001614 { # command name
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04001615 $Path = $Candidate;
1616 }
1617 }
1618 }
1619 if(not $Path) {
1620 $Path = search_Cmd($Name);
1621 }
1622 if(not $Path and $OSgroup eq "windows")
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04001623 { # search for *.exe file
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04001624 $Path=search_Cmd($Name.".exe");
1625 }
1626 if($Path=~/\s/) {
1627 $Path = "\"".$Path."\"";
1628 }
1629 return ($Cache{"get_CmdPath"}{$Name}=$Path);
1630}
1631
1632sub search_Cmd($)
1633{
1634 my $Name = $_[0];
1635 return "" if(not $Name);
1636 if(defined $Cache{"search_Cmd"}{$Name}) {
1637 return $Cache{"search_Cmd"}{$Name};
1638 }
1639 if(my $DefaultPath = get_CmdPath_Default($Name)) {
1640 return ($Cache{"search_Cmd"}{$Name} = $DefaultPath);
1641 }
1642 foreach my $Path (sort {length($a)<=>length($b)} keys(%{$SystemPaths{"bin"}}))
1643 {
1644 my $CmdPath = joinPath($Path,$Name);
1645 if(-f $CmdPath)
1646 {
1647 if($Name=~/gcc/) {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04001648 next if(not check_gcc($CmdPath, "3"));
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04001649 }
1650 return ($Cache{"search_Cmd"}{$Name} = $CmdPath);
1651 }
1652 }
1653 return ($Cache{"search_Cmd"}{$Name} = "");
1654}
1655
1656sub get_CmdPath_Default($)
1657{ # search in PATH
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04001658 return "" if(not $_[0]);
1659 if(defined $Cache{"get_CmdPath_Default"}{$_[0]}) {
1660 return $Cache{"get_CmdPath_Default"}{$_[0]};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04001661 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04001662 return ($Cache{"get_CmdPath_Default"}{$_[0]} = get_CmdPath_Default_I($_[0]));
1663}
1664
1665sub get_CmdPath_Default_I($)
1666{ # search in PATH
1667 my $Name = $_[0];
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04001668 if($Name=~/find/)
1669 { # special case: search for "find" utility
1670 if(`find . -maxdepth 0 2>$TMP_DIR/null`) {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04001671 return "find";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04001672 }
1673 }
1674 elsif($Name=~/gcc/) {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04001675 return check_gcc($Name, "3");
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04001676 }
1677 if(check_command($Name)) {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04001678 return $Name;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04001679 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04001680 if($OSgroup eq "windows")
1681 {
1682 if(`$Name /? 2>$TMP_DIR/null`) {
1683 return $Name;
1684 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04001685 }
1686 if($Name!~/which/)
1687 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04001688 if(my $WhichCmd = get_CmdPath("which"))
1689 {
1690 if(`$WhichCmd $Name 2>$TMP_DIR/null`) {
1691 return $Name;
1692 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04001693 }
1694 }
1695 foreach my $Path (sort {length($a)<=>length($b)} keys(%DefaultBinPaths))
1696 {
1697 if(-f $Path."/".$Name) {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04001698 return joinPath($Path,$Name);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04001699 }
1700 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04001701 return "";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04001702}
1703
1704sub clean_path($)
1705{
1706 my $Path = $_[0];
1707 $Path=~s/[\/\\]+\Z//g;
1708 return $Path;
1709}
1710
1711sub classifyPath($)
1712{
1713 my $Path = $_[0];
1714 if($Path=~/[\*\[]/)
1715 { # wildcard
1716 $Path=~s/\*/.*/g;
1717 $Path=~s/\\/\\\\/g;
1718 return ($Path, "Pattern");
1719 }
1720 elsif($Path=~/[\/\\]/)
1721 { # directory or relative path
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04001722 $Path=~s/[\/\\]+\Z//g;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04001723 return (path_format($Path, $OSgroup), "Path");
1724 }
1725 else {
1726 return ($Path, "Name");
1727 }
1728}
1729
1730sub readDescriptor($$)
1731{
1732 my ($LibVersion, $Content) = @_;
1733 return if(not $LibVersion);
1734 my $DName = $DumpAPI?"descriptor":"descriptor \"d$LibVersion\"";
1735 if(not $Content) {
1736 exitStatus("Error", "$DName is empty");
1737 }
1738 if($Content!~/\</) {
1739 exitStatus("Error", "$DName is not a descriptor (see -d1 option)");
1740 }
1741 $Content=~s/\/\*(.|\n)+?\*\///g;
1742 $Content=~s/<\!--(.|\n)+?-->//g;
1743 $Descriptor{$LibVersion}{"Version"} = parseTag(\$Content, "version");
1744 if($TargetVersion{$LibVersion}) {
1745 $Descriptor{$LibVersion}{"Version"} = $TargetVersion{$LibVersion};
1746 }
1747 if(not $Descriptor{$LibVersion}{"Version"}) {
1748 exitStatus("Error", "version in the $DName is not specified (<version> section)");
1749 }
1750 if($Content=~/{RELPATH}/)
1751 {
1752 if(my $RelDir = $RelativeDirectory{$LibVersion}) {
1753 $Content =~ s/{RELPATH}/$RelDir/g;
1754 }
1755 else
1756 {
1757 my $NeedRelpath = $DumpAPI?"-relpath":"-relpath$LibVersion";
1758 exitStatus("Error", "you have not specified $NeedRelpath option, but the $DName contains {RELPATH} macro");
1759 }
1760 }
1761
1762 if(not $CheckObjectsOnly_Opt)
1763 {
1764 my $DHeaders = parseTag(\$Content, "headers");
1765 if(not $DHeaders) {
1766 exitStatus("Error", "header files in the $DName are not specified (<headers> section)");
1767 }
1768 elsif(lc($DHeaders) ne "none")
1769 { # append the descriptor headers list
1770 if($Descriptor{$LibVersion}{"Headers"})
1771 { # multiple descriptors
1772 $Descriptor{$LibVersion}{"Headers"} .= "\n".$DHeaders;
1773 }
1774 else {
1775 $Descriptor{$LibVersion}{"Headers"} = $DHeaders;
1776 }
1777 foreach my $Path (split(/\s*\n\s*/, $DHeaders))
1778 {
1779 if(not -e $Path) {
1780 exitStatus("Access_Error", "can't access \'$Path\'");
1781 }
1782 }
1783 }
1784 }
1785 if(not $CheckHeadersOnly_Opt)
1786 {
1787 my $DObjects = parseTag(\$Content, "libs");
1788 if(not $DObjects) {
1789 exitStatus("Error", "$SLIB_TYPE libraries in the $DName are not specified (<libs> section)");
1790 }
1791 elsif(lc($DObjects) ne "none")
1792 { # append the descriptor libraries list
1793 if($Descriptor{$LibVersion}{"Libs"})
1794 { # multiple descriptors
1795 $Descriptor{$LibVersion}{"Libs"} .= "\n".$DObjects;
1796 }
1797 else {
1798 $Descriptor{$LibVersion}{"Libs"} .= $DObjects;
1799 }
1800 foreach my $Path (split(/\s*\n\s*/, $DObjects))
1801 {
1802 if(not -e $Path) {
1803 exitStatus("Access_Error", "can't access \'$Path\'");
1804 }
1805 }
1806 }
1807 }
1808 foreach my $Path (split(/\s*\n\s*/, parseTag(\$Content, "search_headers")))
1809 {
1810 $Path = clean_path($Path);
1811 if(not -d $Path) {
1812 exitStatus("Access_Error", "can't access directory \'$Path\'");
1813 }
1814 $Path = path_format($Path, $OSgroup);
1815 $SystemPaths{"include"}{$Path}=1;
1816 }
1817 foreach my $Path (split(/\s*\n\s*/, parseTag(\$Content, "search_libs")))
1818 {
1819 $Path = clean_path($Path);
1820 if(not -d $Path) {
1821 exitStatus("Access_Error", "can't access directory \'$Path\'");
1822 }
1823 $Path = path_format($Path, $OSgroup);
1824 $SystemPaths{"lib"}{$Path}=1;
1825 }
1826 foreach my $Path (split(/\s*\n\s*/, parseTag(\$Content, "tools")))
1827 {
1828 $Path=clean_path($Path);
1829 if(not -d $Path) {
1830 exitStatus("Access_Error", "can't access directory \'$Path\'");
1831 }
1832 $Path = path_format($Path, $OSgroup);
1833 $SystemPaths{"bin"}{$Path}=1;
1834 $TargetTools{$Path}=1;
1835 }
1836 if(my $Prefix = parseTag(\$Content, "cross_prefix")) {
1837 $CrossPrefix = $Prefix;
1838 }
1839 foreach my $Path (split(/\s*\n\s*/, parseTag(\$Content, "include_paths")))
1840 {
1841 $Path=clean_path($Path);
1842 if(not -d $Path) {
1843 exitStatus("Access_Error", "can't access directory \'$Path\'");
1844 }
1845 $Path = path_format($Path, $OSgroup);
1846 $Descriptor{$LibVersion}{"IncludePaths"}{$Path} = 1;
1847 }
1848 foreach my $Path (split(/\s*\n\s*/, parseTag(\$Content, "add_include_paths")))
1849 {
1850 $Path=clean_path($Path);
1851 if(not -d $Path) {
1852 exitStatus("Access_Error", "can't access directory \'$Path\'");
1853 }
1854 $Path = path_format($Path, $OSgroup);
1855 $Descriptor{$LibVersion}{"AddIncludePaths"}{$Path} = 1;
1856 }
1857 foreach my $Path (split(/\s*\n\s*/, parseTag(\$Content, "skip_include_paths")))
1858 {
1859 # skip some auto-generated include paths
1860 $Skip_Include_Paths{$LibVersion}{path_format($Path)}=1;
1861 }
1862 foreach my $Path (split(/\s*\n\s*/, parseTag(\$Content, "skip_including")))
1863 {
1864 # skip direct including of some headers
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04001865 $SkipHeadersList{$LibVersion}{$Path} = 2;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04001866 my ($CPath, $Type) = classifyPath($Path);
1867 $SkipHeaders{$LibVersion}{$Type}{$CPath} = 2;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04001868 }
1869 $Descriptor{$LibVersion}{"GccOptions"} = parseTag(\$Content, "gcc_options");
1870 foreach my $Option (split(/\s*\n\s*/, $Descriptor{$LibVersion}{"GccOptions"})) {
1871 $CompilerOptions{$LibVersion} .= " ".$Option;
1872 }
1873 $Descriptor{$LibVersion}{"SkipHeaders"} = parseTag(\$Content, "skip_headers");
1874 foreach my $Path (split(/\s*\n\s*/, $Descriptor{$LibVersion}{"SkipHeaders"}))
1875 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04001876 $SkipHeadersList{$LibVersion}{$Path} = 1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04001877 my ($CPath, $Type) = classifyPath($Path);
1878 $SkipHeaders{$LibVersion}{$Type}{$CPath} = 1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04001879 }
1880 $Descriptor{$LibVersion}{"SkipLibs"} = parseTag(\$Content, "skip_libs");
1881 foreach my $Path (split(/\s*\n\s*/, $Descriptor{$LibVersion}{"SkipLibs"}))
1882 {
1883 my ($CPath, $Type) = classifyPath($Path);
1884 $SkipLibs{$LibVersion}{$Type}{$CPath} = 1;
1885 }
1886 if(my $DDefines = parseTag(\$Content, "defines"))
1887 {
1888 if($Descriptor{$LibVersion}{"Defines"})
1889 { # multiple descriptors
1890 $Descriptor{$LibVersion}{"Defines"} .= "\n".$DDefines;
1891 }
1892 else {
1893 $Descriptor{$LibVersion}{"Defines"} = $DDefines;
1894 }
1895 }
1896 foreach my $Order (split(/\s*\n\s*/, parseTag(\$Content, "include_order")))
1897 {
1898 if($Order=~/\A(.+):(.+)\Z/) {
1899 $Include_Order{$LibVersion}{$1} = $2;
1900 }
1901 }
1902 foreach my $Type_Name (split(/\s*\n\s*/, parseTag(\$Content, "opaque_types")),
1903 split(/\s*\n\s*/, parseTag(\$Content, "skip_types")))
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04001904 { # opaque_types renamed to skip_types (1.23.4)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04001905 $SkipTypes{$LibVersion}{$Type_Name} = 1;
1906 }
1907 foreach my $Symbol (split(/\s*\n\s*/, parseTag(\$Content, "skip_interfaces")),
1908 split(/\s*\n\s*/, parseTag(\$Content, "skip_symbols")))
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04001909 { # skip_interfaces renamed to skip_symbols (1.22.1)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04001910 $SkipSymbols{$LibVersion}{$Symbol} = 1;
1911 }
1912 foreach my $NameSpace (split(/\s*\n\s*/, parseTag(\$Content, "skip_namespaces"))) {
1913 $SkipNameSpaces{$LibVersion}{$NameSpace} = 1;
1914 }
1915 foreach my $Constant (split(/\s*\n\s*/, parseTag(\$Content, "skip_constants"))) {
1916 $SkipConstants{$LibVersion}{$Constant} = 1;
1917 }
1918 if(my $DIncPreamble = parseTag(\$Content, "include_preamble"))
1919 {
1920 if($Descriptor{$LibVersion}{"IncludePreamble"})
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04001921 { # multiple descriptors
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04001922 $Descriptor{$LibVersion}{"IncludePreamble"} .= "\n".$DIncPreamble;
1923 }
1924 else {
1925 $Descriptor{$LibVersion}{"IncludePreamble"} = $DIncPreamble;
1926 }
1927 }
1928}
1929
1930sub parseTag($$)
1931{
1932 my ($CodeRef, $Tag) = @_;
1933 return "" if(not $CodeRef or not ${$CodeRef} or not $Tag);
1934 if(${$CodeRef}=~s/\<\Q$Tag\E\>((.|\n)+?)\<\/\Q$Tag\E\>//)
1935 {
1936 my $Content = $1;
1937 $Content=~s/(\A\s+|\s+\Z)//g;
1938 return $Content;
1939 }
1940 else {
1941 return "";
1942 }
1943}
1944
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04001945sub getInfo($)
1946{
Andrey Ponomarenko85043792012-05-14 16:48:07 +04001947 my $DumpPath = $_[0];
1948 return if(not $DumpPath or not -f $DumpPath);
1949
1950 readTUDump($DumpPath);
1951
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04001952 # processing info
1953 setTemplateParams_All();
1954 getTypeInfo_All();
1955 simplifyNames();
1956 getSymbolInfo_All();
1957 getVarInfo_All();
1958
Andrey Ponomarenko85043792012-05-14 16:48:07 +04001959 # clean memory
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04001960 %LibInfo = ();
1961 %TemplateInstance = ();
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04001962 %MangledNames = ();
Andrey Ponomarenko85043792012-05-14 16:48:07 +04001963 %TemplateDecl = ();
1964 %StdCxxTypedef = ();
1965 %MissedTypedef = ();
1966 %Typedef_Tr = ();
1967 %Typedef_Eq = ();
1968
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04001969 # clean cache
1970 delete($Cache{"getTypeAttr"});
1971 delete($Cache{"getTypeDeclId"});
1972
1973 # remove unused types
1974 if($BinaryOnly and not $ExtendedCheck)
1975 { # --binary
1976 removeUnused($Version, "All");
1977 }
1978 else {
1979 removeUnused($Version, "Derived");
1980 }
1981
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04001982 if($Debug) {
1983 # debugMangling($Version);
1984 }
1985}
1986
Andrey Ponomarenko85043792012-05-14 16:48:07 +04001987sub readTUDump($)
1988{
1989 my $DumpPath = $_[0];
1990
1991 open(TU_DUMP, $DumpPath);
1992 local $/ = undef;
1993 my $Content = <TU_DUMP>;
1994 close(TU_DUMP);
1995
1996 unlink($DumpPath);
1997
1998 $Content=~s/\n[ ]+/ /g;
1999 my @Lines = split("\n", $Content);
2000
2001 # clean memory
2002 undef $Content;
2003
2004 $MAX_ID = $#Lines+1;
2005
2006 foreach (0 .. $#Lines)
2007 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04002008 if($Lines[$_]=~/\A\@(\d+)[ ]+([a-z_]+)[ ]+(.+)\Z/i)
Andrey Ponomarenko85043792012-05-14 16:48:07 +04002009 { # get a number and attributes of a node
2010 next if(not $NodeType{$2});
2011 $LibInfo{$Version}{"info_type"}{$1}=$2;
2012 $LibInfo{$Version}{"info"}{$1}=$3;
2013 }
2014
2015 # clean memory
2016 delete($Lines[$_]);
2017 }
2018
2019 # clean memory
2020 undef @Lines;
2021}
2022
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002023sub simplifyNames()
2024{
2025 foreach my $Base (keys(%{$Typedef_Tr{$Version}}))
2026 {
2027 my @Translations = keys(%{$Typedef_Tr{$Version}{$Base}});
2028 if($#Translations==0 and length($Translations[0])<=length($Base)) {
2029 $Typedef_Eq{$Version}{$Base} = $Translations[0];
2030 }
2031 }
Andrey Ponomarenkob8d203d2012-05-25 18:11:07 +04002032 foreach my $TypeId (keys(%{$TypeInfo{$Version}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002033 {
Andrey Ponomarenkob8d203d2012-05-25 18:11:07 +04002034 my $TypeName = $TypeInfo{$Version}{$TypeId}{"Name"};
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04002035 if(not $TypeName) {
2036 next;
2037 }
2038 next if(index($TypeName,"<")==-1);# template instances only
2039 if($TypeName=~/>(::\w+)+\Z/)
2040 { # skip unused types
2041 next;
2042 };
2043 foreach my $Base (sort {length($b)<=>length($a)}
2044 sort {$b cmp $a} keys(%{$Typedef_Eq{$Version}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002045 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04002046 next if(not $Base);
2047 next if(index($TypeName,$Base)==-1);
2048 next if(length($TypeName) - length($Base) <= 3);
2049 my $Typedef = $Typedef_Eq{$Version}{$Base};
2050 $TypeName=~s/(\<|\,)\Q$Base\E(\W|\Z)/$1$Typedef$2/g;
2051 $TypeName=~s/(\<|\,)\Q$Base\E(\w|\Z)/$1$Typedef $2/g;
Andrey Ponomarenkob8d203d2012-05-25 18:11:07 +04002052 if(defined $TypeInfo{$Version}{$TypeId}{"TParam"})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002053 {
Andrey Ponomarenkob8d203d2012-05-25 18:11:07 +04002054 foreach my $TPos (keys(%{$TypeInfo{$Version}{$TypeId}{"TParam"}}))
Andrey Ponomarenko85043792012-05-14 16:48:07 +04002055 {
Andrey Ponomarenkob8d203d2012-05-25 18:11:07 +04002056 my $TPName = $TypeInfo{$Version}{$TypeId}{"TParam"}{$TPos}{"name"};
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04002057 $TPName=~s/\A\Q$Base\E(\W|\Z)/$Typedef$1/g;
Andrey Ponomarenkob8d203d2012-05-25 18:11:07 +04002058 $TypeInfo{$Version}{$TypeId}{"TParam"}{$TPos}{"name"} = formatName($TPName);
Andrey Ponomarenko85043792012-05-14 16:48:07 +04002059 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002060 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002061 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04002062 $TypeName = formatName($TypeName);
Andrey Ponomarenkob8d203d2012-05-25 18:11:07 +04002063 $TypeInfo{$Version}{$TypeId}{"Name"} = $TypeName;
2064 $TName_Tid{$Version}{$TypeName} = $TypeId;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002065 }
2066}
2067
2068sub setTemplateParams_All()
2069{
2070 foreach (keys(%{$LibInfo{$Version}{"info"}}))
2071 {
2072 if($LibInfo{$Version}{"info_type"}{$_} eq "template_decl") {
2073 setTemplateParams($_);
2074 }
2075 }
2076}
2077
2078sub setTemplateParams($)
2079{
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04002080 if(my $Info = $LibInfo{$Version}{"info"}{$_[0]})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002081 {
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04002082 if($Info=~/(inst|spcs)[ ]*:[ ]*@(\d+) /)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002083 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04002084 my $TmplInst_Id = $2;
2085 setTemplateInstParams($TmplInst_Id);
2086 while($TmplInst_Id = getNextElem($TmplInst_Id)) {
2087 setTemplateInstParams($TmplInst_Id);
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04002088 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002089 }
2090 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04002091 if(my $TypeId = getTreeAttr_Type($_[0]))
Andrey Ponomarenko85043792012-05-14 16:48:07 +04002092 {
2093 if(my $IType = $LibInfo{$Version}{"info_type"}{$TypeId})
2094 {
2095 if($IType eq "record_type") {
2096 $TemplateDecl{$Version}{$TypeId}=1;
2097 }
2098 }
2099 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002100}
2101
2102sub setTemplateInstParams($)
2103{
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04002104 if(my $Info = $LibInfo{$Version}{"info"}{$_[0]})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002105 {
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04002106 my ($Params_InfoId, $ElemId) = ();
2107 if($Info=~/purp[ ]*:[ ]*@(\d+) /) {
2108 $Params_InfoId = $1;
2109 }
2110 if($Info=~/valu[ ]*:[ ]*@(\d+) /) {
2111 $ElemId = $1;
2112 }
2113 if($Params_InfoId and $ElemId)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002114 {
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04002115 my $Params_Info = $LibInfo{$Version}{"info"}{$Params_InfoId};
2116 while($Params_Info=~s/ (\d+)[ ]*:[ ]*\@(\d+) / /)
2117 {
2118 my ($PPos, $PTypeId) = ($1, $2);
2119 if(my $PType = $LibInfo{$Version}{"info_type"}{$PTypeId})
2120 {
Andrey Ponomarenko85043792012-05-14 16:48:07 +04002121 if($PType eq "template_type_parm")
2122 {
2123 $TemplateDecl{$Version}{$ElemId}=1;
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04002124 return;
2125 }
2126 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +04002127 if($LibInfo{$Version}{"info_type"}{$ElemId} eq "function_decl")
2128 { # functions
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04002129 $TemplateInstance{$Version}{"Func"}{$ElemId}{$PPos} = $PTypeId;
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04002130 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +04002131 else
2132 { # types
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04002133 $TemplateInstance{$Version}{"Type"}{$ElemId}{$PPos} = $PTypeId;
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04002134 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002135 }
2136 }
2137 }
2138}
2139
2140sub getTypeDeclId($)
2141{
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04002142 if($_[0])
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04002143 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04002144 if(defined $Cache{"getTypeDeclId"}{$Version}{$_[0]}) {
2145 return $Cache{"getTypeDeclId"}{$Version}{$_[0]};
2146 }
2147 if(my $Info = $LibInfo{$Version}{"info"}{$_[0]})
2148 {
2149 if($Info=~/name[ ]*:[ ]*@(\d+)/) {
2150 return ($Cache{"getTypeDeclId"}{$Version}{$_[0]} = $1);
2151 }
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04002152 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002153 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04002154 return ($Cache{"getTypeDeclId"}{$Version}{$_[0]} = 0);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002155}
2156
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002157sub getTypeInfo_All()
2158{
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04002159 if(not check_gcc($GCC_PATH, "4.5"))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002160 { # support for GCC < 4.5
2161 # missed typedefs: QStyle::State is typedef to QFlags<QStyle::StateFlag>
2162 # but QStyleOption.state is of type QFlags<QStyle::StateFlag> in the TU dump
2163 # FIXME: check GCC versions
2164 addMissedTypes_Pre();
2165 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04002166
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002167 foreach (sort {int($a)<=>int($b)} keys(%{$LibInfo{$Version}{"info"}}))
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04002168 { # forward order only
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002169 my $IType = $LibInfo{$Version}{"info_type"}{$_};
2170 if($IType=~/_type\Z/ and $IType ne "function_type"
2171 and $IType ne "method_type") {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04002172 getTypeInfo("$_");
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002173 }
2174 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04002175
2176 # add "..." type
2177 $TypeInfo{$Version}{-1} = {
2178 "Name" => "...",
2179 "Type" => "Intrinsic",
2180 "Tid" => -1
2181 };
2182 $TName_Tid{$Version}{"..."} = -1;
2183
2184 if(not check_gcc($GCC_PATH, "4.5"))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002185 { # support for GCC < 4.5
2186 addMissedTypes_Post();
2187 }
2188}
2189
2190sub addMissedTypes_Pre()
2191{
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04002192 my %MissedTypes = ();
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002193 foreach my $MissedTDid (sort {int($a)<=>int($b)} keys(%{$LibInfo{$Version}{"info"}}))
2194 { # detecting missed typedefs
2195 if($LibInfo{$Version}{"info_type"}{$MissedTDid} eq "type_decl")
2196 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04002197 my $TypeId = getTreeAttr_Type($MissedTDid);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002198 next if(not $TypeId);
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04002199 my $TypeType = getTypeType($TypeId);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002200 if($TypeType eq "Unknown")
2201 { # template_type_parm
2202 next;
2203 }
2204 my $TypeDeclId = getTypeDeclId($TypeId);
2205 next if($TypeDeclId eq $MissedTDid);#or not $TypeDeclId
2206 my $TypedefName = getNameByInfo($MissedTDid);
2207 next if(not $TypedefName);
2208 next if($TypedefName eq "__float80");
2209 next if(isAnon($TypedefName));
2210 if(not $TypeDeclId
2211 or getNameByInfo($TypeDeclId) ne $TypedefName) {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04002212 $MissedTypes{$Version}{$TypeId}{$MissedTDid} = 1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002213 }
2214 }
2215 }
Andrey Ponomarenkob8d203d2012-05-25 18:11:07 +04002216 my %AddTypes = ();
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04002217 foreach my $Tid (keys(%{$MissedTypes{$Version}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002218 { # add missed typedefs
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04002219 my @Missed = keys(%{$MissedTypes{$Version}{$Tid}});
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002220 if(not @Missed or $#Missed>=1) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002221 next;
2222 }
2223 my $MissedTDid = $Missed[0];
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002224 my ($TypedefName, $TypedefNS) = getTrivialName($MissedTDid, $Tid);
Andrey Ponomarenkob8d203d2012-05-25 18:11:07 +04002225 if(not $TypedefName) {
2226 next;
2227 }
2228 $MAX_ID++;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002229 my %MissedInfo = ( # typedef info
2230 "Name" => $TypedefName,
2231 "NameSpace" => $TypedefNS,
2232 "BaseType" => {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002233 "Tid" => $Tid
2234 },
2235 "Type" => "Typedef",
Andrey Ponomarenkob8d203d2012-05-25 18:11:07 +04002236 "Tid" => "$MAX_ID" );
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002237 my ($H, $L) = getLocation($MissedTDid);
2238 $MissedInfo{"Header"} = $H;
2239 $MissedInfo{"Line"} = $L;
Andrey Ponomarenkob8d203d2012-05-25 18:11:07 +04002240 if($TypedefName=~/\*|\&|\s/)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002241 { # other types
2242 next;
2243 }
Andrey Ponomarenkob8d203d2012-05-25 18:11:07 +04002244 if($TypedefName=~/>(::\w+)+\Z/)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002245 { # QFlags<Qt::DropAction>::enum_type
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002246 next;
2247 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04002248 if(getTypeType($Tid)=~/\A(Intrinsic|Union|Struct|Enum|Class)\Z/)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002249 { # double-check for the name of typedef
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04002250 my ($TName, $TNS) = getTrivialName(getTypeDeclId($Tid), $Tid); # base type info
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002251 next if(not $TName);
Andrey Ponomarenkob8d203d2012-05-25 18:11:07 +04002252 if(length($TypedefName)>=length($TName))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002253 { # too long typedef
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002254 next;
2255 }
Andrey Ponomarenkob8d203d2012-05-25 18:11:07 +04002256 if($TName=~/\A\Q$TypedefName\E</) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002257 next;
2258 }
Andrey Ponomarenkob8d203d2012-05-25 18:11:07 +04002259 if($TypedefName=~/\A\Q$TName\E/)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002260 { # QDateTimeEdit::Section and QDateTimeEdit::Sections::enum_type
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002261 next;
2262 }
Andrey Ponomarenkob8d203d2012-05-25 18:11:07 +04002263 if(get_depth($TypedefName)==0 and get_depth($TName)!=0)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002264 { # std::_Vector_base and std::vector::_Base
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002265 next;
2266 }
2267 }
Andrey Ponomarenkob8d203d2012-05-25 18:11:07 +04002268
2269 $AddTypes{$MissedInfo{"Tid"}} = \%MissedInfo;
2270
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002271 # register typedef
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002272 $MissedTypedef{$Version}{$Tid}{"Tid"} = $MissedInfo{"Tid"};
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04002273 $MissedTypedef{$Version}{$Tid}{"TDid"} = $MissedTDid;
Andrey Ponomarenkob8d203d2012-05-25 18:11:07 +04002274 $TName_Tid{$Version}{$TypedefName} = $MissedInfo{"Tid"};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002275 }
Andrey Ponomarenkob8d203d2012-05-25 18:11:07 +04002276
2277 # add missed & remove other
2278 $TypeInfo{$Version} = \%AddTypes;
2279 delete($Cache{"getTypeAttr"}{$Version});
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002280}
2281
2282sub addMissedTypes_Post()
2283{
2284 foreach my $BaseId (keys(%{$MissedTypedef{$Version}}))
2285 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04002286 if(my $Tid = $MissedTypedef{$Version}{$BaseId}{"Tid"})
2287 {
2288 $TypeInfo{$Version}{$Tid}{"Size"} = $TypeInfo{$Version}{$BaseId}{"Size"};
2289 if(my $TName = $TypeInfo{$Version}{$Tid}{"Name"}) {
2290 $Typedef_BaseName{$Version}{$TName} = $TypeInfo{$Version}{$BaseId}{"Name"};
2291 }
2292 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002293 }
2294}
2295
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04002296sub getTypeInfo($)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002297{
Andrey Ponomarenkob8d203d2012-05-25 18:11:07 +04002298 my $TypeId = $_[0];
2299 %{$TypeInfo{$Version}{$TypeId}} = getTypeAttr($TypeId);
2300 my $TName = $TypeInfo{$Version}{$TypeId}{"Name"};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002301 if(not $TName) {
Andrey Ponomarenkob8d203d2012-05-25 18:11:07 +04002302 delete($TypeInfo{$Version}{$TypeId});
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002303 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002304}
2305
2306sub getArraySize($$)
2307{
2308 my ($TypeId, $BaseName) = @_;
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04002309 if(my $Size = getSize($TypeId))
2310 {
2311 my $Elems = $Size/$BYTE_SIZE;
2312 while($BaseName=~s/\s*\[(\d+)\]//) {
2313 $Elems/=$1;
2314 }
2315 if(my $BasicId = $TName_Tid{$Version}{$BaseName})
2316 {
2317 if(my $BasicSize = $TypeInfo{$Version}{$BasicId}{"Size"}) {
2318 $Elems/=$BasicSize;
2319 }
2320 }
2321 return $Elems;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002322 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04002323 return 0;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002324}
2325
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04002326sub getTParams($$)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002327{
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04002328 my ($TypeId, $Kind) = @_;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002329 my @TmplParams = ();
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04002330 my @Positions = sort {int($a)<=>int($b)} keys(%{$TemplateInstance{$Version}{$Kind}{$TypeId}});
2331 foreach my $Pos (@Positions)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002332 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04002333 my $Param_TypeId = $TemplateInstance{$Version}{$Kind}{$TypeId}{$Pos};
2334 my $NodeType = $LibInfo{$Version}{"info_type"}{$Param_TypeId};
2335 if(not $NodeType)
2336 { # typename_type
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002337 return ();
2338 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04002339 if($NodeType eq "tree_vec")
2340 {
2341 if($Pos!=$#Positions)
2342 { # select last vector of parameters ( ns<P1>::type<P2> )
2343 next;
2344 }
2345 }
2346 my @Params = get_TemplateParam($Pos, $Param_TypeId);
2347 foreach my $P (@Params)
2348 {
2349 if($P eq "") {
2350 return ();
2351 }
2352 elsif($P ne "\@skip\@") {
2353 @TmplParams = (@TmplParams, $P);
2354 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002355 }
2356 }
2357 return @TmplParams;
2358}
2359
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04002360sub getTypeAttr($)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002361{
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04002362 my $TypeId = $_[0];
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04002363 my %TypeAttr = ();
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04002364 if(defined $TypeInfo{$Version}{$TypeId}
2365 and $TypeInfo{$Version}{$TypeId}{"Name"})
2366 { # already created
2367 return %{$TypeInfo{$Version}{$TypeId}};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002368 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04002369 elsif($Cache{"getTypeAttr"}{$Version}{$TypeId})
2370 { # incomplete type
2371 return ();
2372 }
2373 $Cache{"getTypeAttr"}{$Version}{$TypeId} = 1;
2374
2375 my $TypeDeclId = getTypeDeclId($TypeId);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002376 $TypeAttr{"Tid"} = $TypeId;
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04002377
2378 if(not $MissedBase{$Version}{$TypeId} and isTypedef($TypeId))
2379 {
2380 if(my $Info = $LibInfo{$Version}{"info"}{$TypeId})
2381 {
2382 if($Info=~/qual[ ]*:/)
2383 {
2384 if(my $NID = ++$MAX_ID)
2385 {
2386 $MissedBase{$Version}{$TypeId}="$NID";
2387 $MissedBase_R{$Version}{$NID}=$TypeId;
2388 $LibInfo{$Version}{"info"}{$NID} = $LibInfo{$Version}{"info"}{$TypeId};
2389 $LibInfo{$Version}{"info_type"}{$NID} = $LibInfo{$Version}{"info_type"}{$TypeId};
2390 }
2391 }
2392 }
2393 $TypeAttr{"Type"} = "Typedef";
2394 }
2395 else {
2396 $TypeAttr{"Type"} = getTypeType($TypeId);
2397 }
2398
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002399 if($TypeAttr{"Type"} eq "Unknown") {
2400 return ();
2401 }
2402 elsif($TypeAttr{"Type"}=~/(Func|Method|Field)Ptr/)
2403 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04002404 %TypeAttr = getMemPtrAttr(pointTo($TypeId), $TypeId, $TypeAttr{"Type"});
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04002405 if(my $TName = $TypeAttr{"Name"})
2406 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04002407 %{$TypeInfo{$Version}{$TypeId}} = %TypeAttr;
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04002408 $TName_Tid{$Version}{$TName} = $TypeId;
2409 return %TypeAttr;
2410 }
2411 else {
2412 return ();
2413 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002414 }
2415 elsif($TypeAttr{"Type"} eq "Array")
2416 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04002417 my ($BTid, $BTSpec) = selectBaseType($TypeId);
2418 if(not $BTid) {
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04002419 return ();
2420 }
2421 $TypeAttr{"BaseType"}{"Tid"} = $BTid;
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04002422 if(my %BTAttr = getTypeAttr($BTid))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002423 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04002424 if(not $BTAttr{"Name"}) {
2425 return ();
2426 }
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04002427 if(my $NElems = getArraySize($TypeId, $BTAttr{"Name"}))
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04002428 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04002429 if(my $Size = getSize($TypeId)) {
2430 $TypeAttr{"Size"} = $Size/$BYTE_SIZE;
2431 }
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04002432 if($BTAttr{"Name"}=~/\A([^\[\]]+)(\[(\d+|)\].*)\Z/) {
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04002433 $TypeAttr{"Name"} = $1."[$NElems]".$2;
2434 }
2435 else {
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04002436 $TypeAttr{"Name"} = $BTAttr{"Name"}."[$NElems]";
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04002437 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002438 }
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04002439 else
2440 {
2441 $TypeAttr{"Size"} = $WORD_SIZE{$Version}; # pointer
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04002442 if($BTAttr{"Name"}=~/\A([^\[\]]+)(\[(\d+|)\].*)\Z/) {
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04002443 $TypeAttr{"Name"} = $1."[]".$2;
2444 }
2445 else {
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04002446 $TypeAttr{"Name"} = $BTAttr{"Name"}."[]";
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04002447 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002448 }
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04002449 $TypeAttr{"Name"} = formatName($TypeAttr{"Name"});
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04002450 if($BTAttr{"Header"}) {
2451 $TypeAttr{"Header"} = $BTAttr{"Header"};
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04002452 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04002453 %{$TypeInfo{$Version}{$TypeId}} = %TypeAttr;
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04002454 $TName_Tid{$Version}{$TypeAttr{"Name"}} = $TypeId;
2455 return %TypeAttr;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002456 }
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04002457 return ();
2458 }
2459 elsif($TypeAttr{"Type"}=~/\A(Intrinsic|Union|Struct|Enum|Class)\Z/)
2460 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04002461 %TypeAttr = getTrivialTypeAttr($TypeId);
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04002462 if($TypeAttr{"Name"})
2463 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04002464 %{$TypeInfo{$Version}{$TypeId}} = %TypeAttr;
2465 if($TypeAttr{"Name"} ne "int" or getTypeDeclId($TypeAttr{"Tid"}))
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04002466 { # NOTE: register only one int: with built-in decl
2467 if(not $TName_Tid{$Version}{$TypeAttr{"Name"}}) {
2468 $TName_Tid{$Version}{$TypeAttr{"Name"}} = $TypeId;
2469 }
2470 }
2471 return %TypeAttr;
2472 }
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04002473 else {
2474 return ();
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002475 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002476 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002477 else
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04002478 { # derived types
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04002479 my ($BTid, $BTSpec) = selectBaseType($TypeId);
2480 if(not $BTid) {
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04002481 return ();
2482 }
2483 $TypeAttr{"BaseType"}{"Tid"} = $BTid;
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04002484 if(defined $MissedTypedef{$Version}{$BTid})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002485 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04002486 if(my $MissedTDid = $MissedTypedef{$Version}{$BTid}{"TDid"})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002487 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04002488 if($MissedTDid ne $TypeDeclId) {
2489 $TypeAttr{"BaseType"}{"Tid"} = $MissedTypedef{$Version}{$BTid}{"Tid"};
2490 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002491 }
2492 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04002493 my %BTAttr = getTypeAttr($TypeAttr{"BaseType"}{"Tid"});
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04002494 if(not $BTAttr{"Name"})
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04002495 { # templates
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002496 return ();
2497 }
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04002498 if($BTAttr{"Type"} eq "Typedef")
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002499 { # relinking typedefs
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04002500 my %BaseBase = get_Type($BTAttr{"BaseType"}{"Tid"}, $Version);
2501 if($BTAttr{"Name"} eq $BaseBase{"Name"}) {
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04002502 $TypeAttr{"BaseType"}{"Tid"} = $BaseBase{"Tid"};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002503 }
2504 }
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04002505 if($BTSpec)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002506 {
2507 if($TypeAttr{"Type"} eq "Pointer"
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04002508 and $BTAttr{"Name"}=~/\([\*]+\)/)
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04002509 {
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04002510 $TypeAttr{"Name"} = $BTAttr{"Name"};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002511 $TypeAttr{"Name"}=~s/\(([*]+)\)/($1*)/g;
2512 }
2513 else {
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04002514 $TypeAttr{"Name"} = $BTAttr{"Name"}." ".$BTSpec;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002515 }
2516 }
2517 else {
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04002518 $TypeAttr{"Name"} = $BTAttr{"Name"};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002519 }
2520 if($TypeAttr{"Type"} eq "Typedef")
2521 {
2522 $TypeAttr{"Name"} = getNameByInfo($TypeDeclId);
Andrey Ponomarenko85043792012-05-14 16:48:07 +04002523 if(isAnon($TypeAttr{"Name"}))
2524 { # anon typedef to anon type: ._N
2525 return ();
2526 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002527 if(my $NS = getNameSpace($TypeDeclId))
2528 {
2529 my $TypeName = $TypeAttr{"Name"};
2530 if($NS=~/\A(struct |union |class |)((.+)::|)\Q$TypeName\E\Z/)
2531 { # "some_type" is the typedef to "struct some_type" in C++
2532 if($3) {
2533 $TypeAttr{"Name"} = $3."::".$TypeName;
2534 }
2535 }
2536 else
2537 {
2538 $TypeAttr{"NameSpace"} = $NS;
2539 $TypeAttr{"Name"} = $TypeAttr{"NameSpace"}."::".$TypeAttr{"Name"};
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04002540
2541 if($TypeAttr{"NameSpace"}=~/\Astd(::|\Z)/
2542 and $TypeAttr{"Name"}!~/>(::\w+)+\Z/)
2543 {
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04002544 if($BTAttr{"NameSpace"}
2545 and $BTAttr{"NameSpace"}=~/\Astd(::|\Z)/ and $BTAttr{"Name"}=~/</)
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04002546 { # types like "std::fpos<__mbstate_t>" are
2547 # not covered by typedefs in the TU dump
2548 # so trying to add such typedefs manually
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04002549 $StdCxxTypedef{$Version}{$BTAttr{"Name"}}{$TypeAttr{"Name"}} = 1;
2550 if(length($TypeAttr{"Name"})<=length($BTAttr{"Name"}))
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04002551 {
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04002552 if(($BTAttr{"Name"}!~/\A(std|boost)::/ or $TypeAttr{"Name"}!~/\A[a-z]+\Z/))
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04002553 { # skip "other" in "std" and "type" in "boost"
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04002554 $Typedef_Eq{$Version}{$BTAttr{"Name"}} = $TypeAttr{"Name"};
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04002555 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002556 }
2557 }
2558 }
2559 }
2560 }
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04002561 if($TypeAttr{"Name"} ne $BTAttr{"Name"}
2562 and $TypeAttr{"Name"}!~/>(::\w+)+\Z/ and $BTAttr{"Name"}!~/>(::\w+)+\Z/)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002563 {
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04002564 if(not defined $Typedef_BaseName{$Version}{$TypeAttr{"Name"}})
2565 { # typedef int*const TYPEDEF; // first
2566 # int foo(TYPEDEF p); // const is optimized out
2567 $Typedef_BaseName{$Version}{$TypeAttr{"Name"}} = $BTAttr{"Name"};
2568 if($BTAttr{"Name"}=~/</)
2569 {
2570 if(($BTAttr{"Name"}!~/\A(std|boost)::/ or $TypeAttr{"Name"}!~/\A[a-z]+\Z/)) {
2571 $Typedef_Tr{$Version}{$BTAttr{"Name"}}{$TypeAttr{"Name"}} = 1;
2572 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002573 }
2574 }
2575 }
2576 ($TypeAttr{"Header"}, $TypeAttr{"Line"}) = getLocation($TypeDeclId);
2577 }
2578 if(not $TypeAttr{"Size"})
2579 {
2580 if($TypeAttr{"Type"} eq "Pointer") {
2581 $TypeAttr{"Size"} = $WORD_SIZE{$Version};
2582 }
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04002583 elsif($BTAttr{"Size"}) {
2584 $TypeAttr{"Size"} = $BTAttr{"Size"};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002585 }
2586 }
2587 $TypeAttr{"Name"} = formatName($TypeAttr{"Name"});
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04002588 if(not $TypeAttr{"Header"} and $BTAttr{"Header"}) {
2589 $TypeAttr{"Header"} = $BTAttr{"Header"};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002590 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04002591 %{$TypeInfo{$Version}{$TypeId}} = %TypeAttr;
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04002592 if($TypeAttr{"Name"} ne $BTAttr{"Name"})
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04002593 { # typedef to "class Class"
2594 # should not be registered in TName_Tid
2595 if(not $TName_Tid{$Version}{$TypeAttr{"Name"}}) {
2596 $TName_Tid{$Version}{$TypeAttr{"Name"}} = $TypeId;
2597 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002598 }
2599 return %TypeAttr;
2600 }
2601}
2602
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04002603sub getTreeVec($)
2604{
2605 my %Vector = ();
2606 if($_[0] and my $Info = $LibInfo{$Version}{"info"}{$_[0]})
2607 {
2608 while($Info=~s/ (\d+)[ ]*:[ ]*\@(\d+) / /)
2609 { # string length is N-1 because of the null terminator
2610 $Vector{$1} = $2;
2611 }
2612 }
2613 return \%Vector;
2614}
2615
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002616sub get_TemplateParam($$)
2617{
2618 my ($Pos, $Type_Id) = @_;
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04002619 return () if(not $Type_Id);
2620 my $NodeType = $LibInfo{$Version}{"info_type"}{$Type_Id};
2621 return () if(not $NodeType);
2622 if($NodeType eq "integer_cst")
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002623 { # int (1), unsigned (2u), char ('c' as 99), ...
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04002624 my $CstTid = getTreeAttr_Type($Type_Id);
Andrey Ponomarenkob8d203d2012-05-25 18:11:07 +04002625 my %CstType = getTypeAttr($CstTid); # without recursion
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002626 my $Num = getNodeIntCst($Type_Id);
2627 if(my $CstSuffix = $ConstantSuffix{$CstType{"Name"}}) {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04002628 return ($Num.$CstSuffix);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002629 }
2630 else {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04002631 return ("(".$CstType{"Name"}.")".$Num);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002632 }
2633 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04002634 elsif($NodeType eq "string_cst") {
2635 return (getNodeStrCst($Type_Id));
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002636 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04002637 elsif($NodeType eq "tree_vec")
2638 {
2639 my $Vector = getTreeVec($Type_Id);
2640 my @Params = ();
2641 foreach my $P1 (sort {int($a)<=>int($b)} keys(%{$Vector}))
2642 {
2643 foreach my $P2 (get_TemplateParam($Pos, $Vector->{$P1})) {
2644 push(@Params, $P2);
2645 }
2646 }
2647 return @Params;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002648 }
2649 else
2650 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04002651 my %ParamAttr = getTypeAttr($Type_Id);
Andrey Ponomarenkob8d203d2012-05-25 18:11:07 +04002652 my $PName = $ParamAttr{"Name"};
2653 if(not $PName) {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04002654 return ();
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002655 }
Andrey Ponomarenkob8d203d2012-05-25 18:11:07 +04002656 if($PName=~/\>/)
2657 {
2658 if(my $Cover = cover_stdcxx_typedef($PName)) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002659 $PName = $Cover;
2660 }
2661 }
2662 if($Pos>=1 and
2663 $PName=~/\Astd::(allocator|less|((char|regex)_traits)|((i|o)streambuf_iterator))\</)
2664 { # template<typename _Tp, typename _Alloc = std::allocator<_Tp> >
2665 # template<typename _Key, typename _Compare = std::less<_Key>
2666 # template<typename _CharT, typename _Traits = std::char_traits<_CharT> >
2667 # template<typename _Ch_type, typename _Rx_traits = regex_traits<_Ch_type> >
2668 # template<typename _CharT, typename _InIter = istreambuf_iterator<_CharT> >
2669 # template<typename _CharT, typename _OutIter = ostreambuf_iterator<_CharT> >
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04002670 return ("\@skip\@");
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002671 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04002672 return ($PName);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002673 }
2674}
2675
2676sub cover_stdcxx_typedef($)
2677{
2678 my $TypeName = $_[0];
2679 if(my @Covers = sort {length($a)<=>length($b)}
2680 sort keys(%{$StdCxxTypedef{$Version}{$TypeName}}))
2681 { # take the shortest typedef
2682 # FIXME: there may be more than
2683 # one typedefs to the same type
2684 return $Covers[0];
2685 }
2686 my $TypeName_Covered = $TypeName;
2687 while($TypeName=~s/(>)[ ]*(const|volatile|restrict| |\*|\&)\Z/$1/g){};
2688 if(my @Covers = sort {length($a)<=>length($b)} sort keys(%{$StdCxxTypedef{$Version}{$TypeName}}))
2689 {
2690 my $Cover = $Covers[0];
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04002691 $TypeName_Covered=~s/\b\Q$TypeName\E(\W|\Z)/$Cover$1/g;
2692 $TypeName_Covered=~s/\b\Q$TypeName\E(\w|\Z)/$Cover $1/g;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002693 }
2694 return formatName($TypeName_Covered);
2695}
2696
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002697sub getNodeIntCst($)
2698{
2699 my $CstId = $_[0];
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04002700 my $CstTypeId = getTreeAttr_Type($CstId);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002701 if($EnumMembName_Id{$Version}{$CstId}) {
2702 return $EnumMembName_Id{$Version}{$CstId};
2703 }
2704 elsif((my $Value = getTreeValue($CstId)) ne "")
2705 {
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04002706 if($Value eq "0")
2707 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04002708 if($LibInfo{$Version}{"info_type"}{$CstTypeId} eq "boolean_type") {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002709 return "false";
2710 }
2711 else {
2712 return "0";
2713 }
2714 }
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04002715 elsif($Value eq "1")
2716 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04002717 if($LibInfo{$Version}{"info_type"}{$CstTypeId} eq "boolean_type") {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002718 return "true";
2719 }
2720 else {
2721 return "1";
2722 }
2723 }
2724 else {
2725 return $Value;
2726 }
2727 }
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04002728 return "";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002729}
2730
2731sub getNodeStrCst($)
2732{
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04002733 if($_[0] and my $Info = $LibInfo{$Version}{"info"}{$_[0]})
2734 {
2735 if($Info=~/strg[ ]*: (.+) lngt:[ ]*(\d+)/)
2736 { # string length is N-1 because of the null terminator
2737 return substr($1, 0, $2-1);
2738 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002739 }
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04002740 return "";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002741}
2742
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04002743sub getMemPtrAttr($$$)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002744{ # function, method and field pointers
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04002745 my ($PtrId, $TypeId, $Type) = @_;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002746 my $MemInfo = $LibInfo{$Version}{"info"}{$PtrId};
2747 if($Type eq "FieldPtr") {
2748 $MemInfo = $LibInfo{$Version}{"info"}{$TypeId};
2749 }
2750 my $MemInfo_Type = $LibInfo{$Version}{"info_type"}{$PtrId};
2751 my $MemPtrName = "";
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04002752 my %TypeAttr = ("Size"=>$WORD_SIZE{$Version}, "Type"=>$Type, "Tid"=>$TypeId);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002753 if($Type eq "MethodPtr")
2754 { # size of "method pointer" may be greater than WORD size
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04002755 if(my $Size = getSize($TypeId)) {
2756 $TypeAttr{"Size"} = $Size/$BYTE_SIZE;
2757 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002758 }
2759 # Return
2760 if($Type eq "FieldPtr")
2761 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04002762 my %ReturnAttr = getTypeAttr($PtrId);
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04002763 if($ReturnAttr{"Name"}) {
2764 $MemPtrName .= $ReturnAttr{"Name"};
2765 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002766 $TypeAttr{"Return"} = $PtrId;
2767 }
2768 else
2769 {
2770 if($MemInfo=~/retn[ ]*:[ ]*\@(\d+) /)
2771 {
2772 my $ReturnTypeId = $1;
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04002773 my %ReturnAttr = getTypeAttr($ReturnTypeId);
2774 if(not $ReturnAttr{"Name"})
2775 { # templates
2776 return ();
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04002777 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04002778 $MemPtrName .= $ReturnAttr{"Name"};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002779 $TypeAttr{"Return"} = $ReturnTypeId;
2780 }
2781 }
2782 # Class
2783 if($MemInfo=~/(clas|cls)[ ]*:[ ]*@(\d+) /)
2784 {
2785 $TypeAttr{"Class"} = $2;
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04002786 my %Class = getTypeAttr($TypeAttr{"Class"});
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002787 if($Class{"Name"}) {
2788 $MemPtrName .= " (".$Class{"Name"}."\:\:*)";
2789 }
2790 else {
2791 $MemPtrName .= " (*)";
2792 }
2793 }
2794 else {
2795 $MemPtrName .= " (*)";
2796 }
2797 # Parameters
2798 if($Type eq "FuncPtr"
2799 or $Type eq "MethodPtr")
2800 {
2801 my @ParamTypeName = ();
2802 if($MemInfo=~/prms[ ]*:[ ]*@(\d+) /)
2803 {
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04002804 my $PTypeInfoId = $1;
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04002805 my $Pos = 0;
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04002806 while($PTypeInfoId)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002807 {
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04002808 my $PTypeInfo = $LibInfo{$Version}{"info"}{$PTypeInfoId};
2809 if($PTypeInfo=~/valu[ ]*:[ ]*@(\d+) /)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002810 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04002811 my $PTypeId = $1;
2812 my %ParamAttr = getTypeAttr($PTypeId);
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04002813 if(not $ParamAttr{"Name"})
2814 { # templates (template_type_parm), etc.
2815 return ();
2816 }
2817 if($ParamAttr{"Name"} eq "void") {
2818 last;
2819 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04002820 if($Pos!=0 or $Type ne "MethodPtr")
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04002821 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04002822 $TypeAttr{"Param"}{$Pos}{"type"} = $PTypeId;
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04002823 push(@ParamTypeName, $ParamAttr{"Name"});
2824 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04002825 if($PTypeInfoId = getNextElem($PTypeInfoId)) {
2826 $Pos+=1;
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04002827 }
2828 else {
2829 last;
2830 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002831 }
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04002832 else {
2833 last;
2834 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002835 }
2836 }
2837 $MemPtrName .= " (".join(", ", @ParamTypeName).")";
2838 }
2839 $TypeAttr{"Name"} = formatName($MemPtrName);
2840 return %TypeAttr;
2841}
2842
2843sub getTreeTypeName($)
2844{
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04002845 my $TypeId = $_[0];
2846 if(my $Info = $LibInfo{$Version}{"info"}{$TypeId})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002847 {
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04002848 if($LibInfo{$Version}{"info_type"}{$_[0]} eq "integer_type")
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002849 {
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04002850 if(my $Name = getNameByInfo($TypeId))
2851 { # bit_size_type
2852 return $Name;
2853 }
2854 elsif($Info=~/unsigned/) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002855 return "unsigned int";
2856 }
2857 else {
2858 return "int";
2859 }
2860 }
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04002861 elsif($Info=~/name[ ]*:[ ]*@(\d+) /)
2862 {
2863 return getNameByInfo($1);
2864 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002865 }
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04002866 return "";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002867}
2868
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04002869sub isFuncPtr($)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002870{
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04002871 my $Ptd = pointTo($_[0]);
2872 return 0 if(not $Ptd);
2873 if(my $Info = $LibInfo{$Version}{"info"}{$_[0]})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002874 {
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04002875 if($Info=~/unql[ ]*:/ and $Info!~/qual[ ]*:/) {
2876 return 0;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002877 }
2878 }
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04002879 if(my $InfoT1 = $LibInfo{$Version}{"info_type"}{$_[0]}
2880 and my $InfoT2 = $LibInfo{$Version}{"info_type"}{$Ptd})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002881 {
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04002882 if($InfoT1 eq "pointer_type"
2883 and $InfoT2 eq "function_type") {
2884 return 1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002885 }
2886 }
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04002887 return 0;
2888}
2889
2890sub isMethodPtr($)
2891{
2892 my $Ptd = pointTo($_[0]);
2893 return 0 if(not $Ptd);
2894 if(my $Info = $LibInfo{$Version}{"info"}{$_[0]})
2895 {
2896 if($LibInfo{$Version}{"info_type"}{$_[0]} eq "record_type"
2897 and $LibInfo{$Version}{"info_type"}{$Ptd} eq "method_type"
2898 and $Info=~/ ptrmem /) {
2899 return 1;
2900 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002901 }
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04002902 return 0;
2903}
2904
2905sub isFieldPtr($)
2906{
2907 if($_[0] and my $Info = $LibInfo{$Version}{"info"}{$_[0]})
2908 {
2909 if($LibInfo{$Version}{"info_type"}{$_[0]} eq "offset_type"
2910 and $Info=~/ ptrmem /) {
2911 return 1;
2912 }
2913 }
2914 return 0;
2915}
2916
2917sub pointTo($)
2918{
2919 if($_[0] and my $Info = $LibInfo{$Version}{"info"}{$_[0]})
2920 {
2921 if($Info=~/ptd[ ]*:[ ]*@(\d+)/) {
2922 return $1;
2923 }
2924 }
2925 return "";
2926}
2927
2928sub getTypeTypeByTypeId($)
2929{
2930 my $TypeId = $_[0];
2931 if(my $TType = $LibInfo{$Version}{"info_type"}{$TypeId})
2932 {
2933 my $NType = $NodeType{$TType};
2934 if($NType eq "Intrinsic") {
2935 return $NType;
2936 }
2937 elsif(isFuncPtr($TypeId)) {
2938 return "FuncPtr";
2939 }
2940 elsif(isMethodPtr($TypeId)) {
2941 return "MethodPtr";
2942 }
2943 elsif(isFieldPtr($TypeId)) {
2944 return "FieldPtr";
2945 }
2946 elsif($NType ne "Other") {
2947 return $NType;
2948 }
2949 }
2950 return "Unknown";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002951}
2952
2953sub getQual($)
2954{
2955 my $TypeId = $_[0];
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002956 my %UnQual = (
2957 "r"=>"restrict",
2958 "v"=>"volatile",
2959 "c"=>"const",
2960 "cv"=>"const volatile"
2961 );
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04002962 if(my $Info = $LibInfo{$Version}{"info"}{$TypeId})
2963 {
2964 my ($Qual, $To) = ();
2965 if($Info=~/qual[ ]*:[ ]*(r|c|v|cv) /) {
2966 $Qual = $UnQual{$1};
2967 }
2968 if($Info=~/unql[ ]*:[ ]*\@(\d+)/) {
2969 $To = $1;
2970 }
2971 if($Qual and $To) {
2972 return ($Qual, $To);
2973 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002974 }
2975 return ();
2976}
2977
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04002978sub getQualType($)
2979{
2980 if($_[0] eq "const volatile") {
2981 return "ConstVolatile";
2982 }
2983 return ucfirst($_[0]);
2984}
2985
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04002986sub getTypeType($)
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04002987{
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04002988 my $TypeId = $_[0];
2989 my $TypeDeclId = getTypeDeclId($TypeId);
2990 if(defined $MissedTypedef{$Version}{$TypeId})
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04002991 { # support for old GCC versions
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04002992 if($MissedTypedef{$Version}{$TypeId}{"TDid"} eq $TypeDeclId) {
2993 return "Typedef";
2994 }
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04002995 }
2996 my $Info = $LibInfo{$Version}{"info"}{$TypeId};
2997 my ($Qual, $To) = getQual($TypeId);
2998 if(($Qual or $To) and $Info=~/name[ ]*:[ ]*\@(\d+) /
2999 and (getTypeId($1) ne $TypeId))
3000 { # qualified types (special)
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04003001 return getQualType($Qual);
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04003002 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04003003 elsif(not $MissedBase_R{$Version}{$TypeId}
3004 and isTypedef($TypeId)) {
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04003005 return "Typedef";
3006 }
3007 elsif($Qual)
3008 { # qualified types
3009 return getQualType($Qual);
3010 }
3011 my $TypeType = getTypeTypeByTypeId($TypeId);
3012 if($TypeType eq "Struct")
3013 {
3014 if($TypeDeclId
3015 and $LibInfo{$Version}{"info_type"}{$TypeDeclId} eq "template_decl") {
3016 return "Template";
3017 }
3018 }
3019 return $TypeType;
3020}
3021
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04003022sub isTypedef($)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003023{
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04003024 if($_[0] and my $Info = $LibInfo{$Version}{"info"}{$_[0]})
3025 {
3026 my $TDid = getTypeDeclId($_[0]);
3027 if(getNameByInfo($TDid)
3028 and $Info=~/unql[ ]*:[ ]*\@(\d+) /
3029 and getTypeId($TDid) eq $_[0]) {
3030 return $1;
3031 }
3032 }
3033 return 0;
3034}
3035
3036sub selectBaseType($)
3037{
3038 my $TypeId = $_[0];
3039 if(defined $MissedTypedef{$Version}{$TypeId})
3040 { # add missed typedefs
3041 if($MissedTypedef{$Version}{$TypeId}{"TDid"} eq getTypeDeclId($TypeId)) {
3042 return ($TypeId, "");
3043 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003044 }
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04003045 my $Info = $LibInfo{$Version}{"info"}{$TypeId};
3046 my $InfoType = $LibInfo{$Version}{"info_type"}{$TypeId};
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04003047
3048 my $MB_R = $MissedBase_R{$Version}{$TypeId};
3049 my $MB = $MissedBase{$Version}{$TypeId};
3050
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04003051 my ($Qual, $To) = getQual($TypeId);
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04003052 if(($Qual or $To) and $Info=~/name[ ]*:[ ]*\@(\d+) /
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04003053 and (getTypeId($1) ne $TypeId)
3054 and (not $MB_R or getTypeId($1) ne $MB_R))
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04003055 { # qualified types (special)
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04003056 return (getTypeId($1), $Qual);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003057 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04003058 elsif($MB)
3059 { # add base
3060 return ($MB, "");
3061 }
3062 elsif(not $MB_R and my $Bid = isTypedef($TypeId))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003063 { # typedefs
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04003064 return ($Bid, "");
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003065 }
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04003066 elsif($Qual or $To)
3067 { # qualified types
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04003068 return ($To, $Qual);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003069 }
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04003070 elsif($InfoType eq "reference_type")
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003071 {
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04003072 if($Info=~/refd[ ]*:[ ]*@(\d+) /) {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04003073 return ($1, "&");
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003074 }
3075 else {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04003076 return (0, "");
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003077 }
3078 }
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04003079 elsif($InfoType eq "array_type")
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003080 {
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04003081 if($Info=~/elts[ ]*:[ ]*@(\d+) /) {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04003082 return ($1, "");
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003083 }
3084 else {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04003085 return (0, "");
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003086 }
3087 }
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04003088 elsif($InfoType eq "pointer_type")
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003089 {
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04003090 if($Info=~/ptd[ ]*:[ ]*@(\d+) /) {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04003091 return ($1, "*");
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003092 }
3093 else {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04003094 return (0, "");
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003095 }
3096 }
3097 else {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04003098 return (0, "");
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003099 }
3100}
3101
3102sub getSymbolInfo_All()
3103{
3104 foreach (sort {int($b)<=>int($a)} keys(%{$LibInfo{$Version}{"info"}}))
3105 { # reverse order
3106 if($LibInfo{$Version}{"info_type"}{$_} eq "function_decl") {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04003107 getSymbolInfo($_);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003108 }
3109 }
3110}
3111
3112sub getVarInfo_All()
3113{
3114 foreach (sort {int($b)<=>int($a)} keys(%{$LibInfo{$Version}{"info"}}))
3115 { # reverse order
3116 if($LibInfo{$Version}{"info_type"}{$_} eq "var_decl") {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04003117 getVarInfo($_);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003118 }
3119 }
3120}
3121
3122sub isBuiltIn($) {
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04003123 return ($_[0] and $_[0]=~/\<built\-in\>|\<internal\>|\A\./);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003124}
3125
3126sub getVarInfo($)
3127{
3128 my $InfoId = $_[0];
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04003129 if(my $NSid = getNameSpaceId($InfoId))
3130 {
3131 my $NSInfoType = $LibInfo{$Version}{"info_type"}{$NSid};
3132 if($NSInfoType and $NSInfoType eq "function_decl") {
3133 return;
3134 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003135 }
3136 ($SymbolInfo{$Version}{$InfoId}{"Header"}, $SymbolInfo{$Version}{$InfoId}{"Line"}) = getLocation($InfoId);
3137 if(not $SymbolInfo{$Version}{$InfoId}{"Header"}
3138 or isBuiltIn($SymbolInfo{$Version}{$InfoId}{"Header"})) {
3139 delete($SymbolInfo{$Version}{$InfoId});
3140 return;
3141 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04003142 my $ShortName = getTreeStr(getTreeAttr_Name($InfoId));
Andrey Ponomarenko85043792012-05-14 16:48:07 +04003143 if(not $ShortName) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003144 delete($SymbolInfo{$Version}{$InfoId});
3145 return;
3146 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +04003147 if($ShortName=~/\Atmp_add_class_\d+\Z/) {
3148 delete($SymbolInfo{$Version}{$InfoId});
3149 return;
3150 }
3151 $SymbolInfo{$Version}{$InfoId}{"ShortName"} = $ShortName;
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04003152 $SymbolInfo{$Version}{$InfoId}{"MnglName"} = getTreeStr(getTreeAttr_Mngl($InfoId));
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003153 if($SymbolInfo{$Version}{$InfoId}{"MnglName"}
3154 and $SymbolInfo{$Version}{$InfoId}{"MnglName"}!~/\A_Z/)
3155 { # validate mangled name
3156 delete($SymbolInfo{$Version}{$InfoId});
3157 return;
3158 }
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04003159 if(not $SymbolInfo{$Version}{$InfoId}{"MnglName"}
Andrey Ponomarenko85043792012-05-14 16:48:07 +04003160 and $ShortName=~/\A_Z/)
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04003161 { # _ZTS, etc.
Andrey Ponomarenko85043792012-05-14 16:48:07 +04003162 $SymbolInfo{$Version}{$InfoId}{"MnglName"} = $ShortName;
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04003163 }
3164 if(isPrivateData($SymbolInfo{$Version}{$InfoId}{"MnglName"}))
3165 { # non-public global data
3166 delete($SymbolInfo{$Version}{$InfoId});
3167 return;
3168 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003169 $SymbolInfo{$Version}{$InfoId}{"Data"} = 1;
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04003170 if(my $Rid = getTypeId($InfoId))
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04003171 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04003172 if(not $TypeInfo{$Version}{$Rid}{"Name"})
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04003173 { # typename_type
3174 delete($SymbolInfo{$Version}{$InfoId});
3175 return;
3176 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04003177 $SymbolInfo{$Version}{$InfoId}{"Return"} = $Rid;
3178 my $Val = getDataVal($InfoId, $Rid);
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04003179 if(defined $Val) {
3180 $SymbolInfo{$Version}{$InfoId}{"Value"} = $Val;
3181 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003182 }
3183 set_Class_And_Namespace($InfoId);
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04003184 if(my $ClassId = $SymbolInfo{$Version}{$InfoId}{"Class"})
3185 {
3186 if(not $TypeInfo{$Version}{$ClassId}{"Name"})
3187 { # templates
3188 delete($SymbolInfo{$Version}{$InfoId});
3189 return;
3190 }
3191 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003192 if($LibInfo{$Version}{"info"}{$InfoId}=~/ lang:[ ]*C /i) {
3193 $SymbolInfo{$Version}{$InfoId}{"Lang"} = "C";
3194 }
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04003195 if($UserLang and $UserLang eq "C")
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003196 { # --lang=C option
Andrey Ponomarenko85043792012-05-14 16:48:07 +04003197 $SymbolInfo{$Version}{$InfoId}{"MnglName"} = $ShortName;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003198 }
3199 if($COMMON_LANGUAGE{$Version} eq "C++")
3200 {
3201 if(not $SymbolInfo{$Version}{$InfoId}{"MnglName"})
3202 { # for some symbols (_ZTI) the short name is the mangled name
3203 if($ShortName=~/\A_Z/) {
3204 $SymbolInfo{$Version}{$InfoId}{"MnglName"} = $ShortName;
3205 }
3206 }
3207 if(not $SymbolInfo{$Version}{$InfoId}{"MnglName"})
3208 { # try to mangle symbol (link with libraries)
3209 $SymbolInfo{$Version}{$InfoId}{"MnglName"} = linkSymbol($InfoId);
3210 }
3211 if($OStarget eq "windows")
3212 {
3213 if(my $Mangled = $mangled_name{$Version}{modelUnmangled($InfoId, "MSVC")})
3214 { # link MS C++ symbols from library with GCC symbols from headers
3215 $SymbolInfo{$Version}{$InfoId}{"MnglName"} = $Mangled;
3216 }
3217 }
3218 }
3219 if(not $SymbolInfo{$Version}{$InfoId}{"MnglName"}) {
3220 $SymbolInfo{$Version}{$InfoId}{"MnglName"} = $ShortName;
3221 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04003222 if(not $CheckHeadersOnly
3223 and not link_symbol($SymbolInfo{$Version}{$InfoId}{"MnglName"}, $Version, "-Deps"))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003224 {
Andrey Ponomarenko85043792012-05-14 16:48:07 +04003225 if(link_symbol($ShortName, $Version, "-Deps"))
3226 {
3227 if(not $SymbolInfo{$Version}{$InfoId}{"Class"}
3228 and isConstType($SymbolInfo{$Version}{$InfoId}{"Return"}, $Version)
3229 and $SymbolInfo{$Version}{$InfoId}{"MnglName"}=~/L\d+$ShortName/)
3230 { # "const" global data is mangled as _ZL... in the TU dump
3231 # but not mangled when compiling a C shared library
3232 $SymbolInfo{$Version}{$InfoId}{"MnglName"} = $ShortName;
3233 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003234 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003235 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +04003236 if(my $Symbol = $SymbolInfo{$Version}{$InfoId}{"MnglName"})
3237 {
3238 if(not selectSymbol($Symbol, $SymbolInfo{$Version}{$InfoId}, "Dump", $Version))
3239 { # non-target symbols
3240 delete($SymbolInfo{$Version}{$InfoId});
3241 return;
3242 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003243 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04003244 if(my $Rid = $SymbolInfo{$Version}{$InfoId}{"Return"})
3245 {
3246 if(defined $MissedTypedef{$Version}{$Rid})
3247 {
3248 if(my $AddedTid = $MissedTypedef{$Version}{$Rid}{"Tid"}) {
3249 $SymbolInfo{$Version}{$InfoId}{"Return"} = $AddedTid;
3250 }
3251 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003252 }
3253 setFuncAccess($InfoId);
3254 if($SymbolInfo{$Version}{$InfoId}{"MnglName"}=~/\A_ZTV/) {
3255 delete($SymbolInfo{$Version}{$InfoId}{"Return"});
3256 }
3257 if($ShortName=~/\A(_Z|\?)/) {
3258 delete($SymbolInfo{$Version}{$InfoId}{"ShortName"});
3259 }
3260}
3261
Andrey Ponomarenko85043792012-05-14 16:48:07 +04003262sub isConstType($$)
3263{
3264 my ($TypeId, $LibVersion) = @_;
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04003265 my %Base = get_Type($TypeId, $LibVersion);
Andrey Ponomarenko85043792012-05-14 16:48:07 +04003266 while(defined $Base{"Type"} and $Base{"Type"} eq "Typedef") {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04003267 %Base = get_OneStep_BaseType($Base{"Tid"}, $LibVersion);
Andrey Ponomarenko85043792012-05-14 16:48:07 +04003268 }
3269 return ($Base{"Type"} eq "Const");
3270}
3271
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003272sub getTrivialName($$)
3273{
3274 my ($TypeInfoId, $TypeId) = @_;
3275 my %TypeAttr = ();
3276 $TypeAttr{"Name"} = getNameByInfo($TypeInfoId);
3277 if(not $TypeAttr{"Name"}) {
3278 $TypeAttr{"Name"} = getTreeTypeName($TypeId);
3279 }
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04003280 ($TypeAttr{"Header"}, $TypeAttr{"Line"}) = getLocation($TypeInfoId);
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04003281 $TypeAttr{"Type"} = getTypeType($TypeId);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003282 $TypeAttr{"Name"}=~s/<(.+)\Z//g; # GCC 3.4.4 add template params to the name
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04003283 if(isAnon($TypeAttr{"Name"}))
3284 {
3285 my $NameSpaceId = $TypeId;
3286 while(my $NSId = getNameSpaceId(getTypeDeclId($NameSpaceId)))
3287 { # searching for a first not anon scope
3288 if($NSId eq $NameSpaceId) {
3289 last;
3290 }
3291 else
3292 {
3293 $TypeAttr{"NameSpace"} = getNameSpace(getTypeDeclId($TypeId));
3294 if(not $TypeAttr{"NameSpace"}
3295 or isNotAnon($TypeAttr{"NameSpace"})) {
3296 last;
3297 }
3298 }
3299 $NameSpaceId=$NSId;
3300 }
3301 }
3302 else
3303 {
3304 if(my $NameSpaceId = getNameSpaceId($TypeInfoId))
3305 {
3306 if($NameSpaceId ne $TypeId) {
3307 $TypeAttr{"NameSpace"} = getNameSpace($TypeInfoId);
3308 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003309 }
3310 }
3311 if($TypeAttr{"NameSpace"} and isNotAnon($TypeAttr{"Name"})) {
3312 $TypeAttr{"Name"} = $TypeAttr{"NameSpace"}."::".$TypeAttr{"Name"};
3313 }
3314 $TypeAttr{"Name"} = formatName($TypeAttr{"Name"});
3315 if(isAnon($TypeAttr{"Name"}))
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04003316 { # anon-struct-header.h-line
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04003317 $TypeAttr{"Name"} = "anon-".lc($TypeAttr{"Type"})."-";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003318 $TypeAttr{"Name"} .= $TypeAttr{"Header"}."-".$TypeAttr{"Line"};
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04003319 if($TypeAttr{"NameSpace"}) {
3320 $TypeAttr{"Name"} = $TypeAttr{"NameSpace"}."::".$TypeAttr{"Name"};
3321 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003322 }
Andrey Ponomarenkob8d203d2012-05-25 18:11:07 +04003323 if(defined $TemplateInstance{$Version}{"Type"}{$TypeId}
3324 and getTypeDeclId($TypeId) eq $TypeInfoId)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003325 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04003326 my @TParams = getTParams($TypeId, "Type");
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003327 if(not @TParams)
3328 { # template declarations with abstract params
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003329 return ("", "");
3330 }
3331 $TypeAttr{"Name"} = formatName($TypeAttr{"Name"}."< ".join(", ", @TParams)." >");
3332 }
3333 return ($TypeAttr{"Name"}, $TypeAttr{"NameSpace"});
3334}
3335
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04003336sub getTrivialTypeAttr($)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003337{
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04003338 my $TypeId = $_[0];
3339 my $TypeInfoId = getTypeDeclId($_[0]);
Andrey Ponomarenko85043792012-05-14 16:48:07 +04003340
3341 if($TemplateDecl{$Version}{$TypeId})
3342 { # template_decl
3343 return ();
3344 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04003345 if(my $ScopeId = getTreeAttr_Scpe($TypeInfoId))
3346 {
3347 if($TemplateDecl{$Version}{$ScopeId})
3348 { # template_decl
3349 return ();
3350 }
3351 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +04003352
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003353 my %TypeAttr = ();
3354 if(getTypeTypeByTypeId($TypeId)!~/\A(Intrinsic|Union|Struct|Enum|Class)\Z/) {
3355 return ();
3356 }
3357 setTypeAccess($TypeId, \%TypeAttr);
3358 ($TypeAttr{"Header"}, $TypeAttr{"Line"}) = getLocation($TypeInfoId);
3359 if(isBuiltIn($TypeAttr{"Header"}))
3360 {
3361 delete($TypeAttr{"Header"});
3362 delete($TypeAttr{"Line"});
3363 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04003364 $TypeAttr{"Type"} = getTypeType($TypeId);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003365 ($TypeAttr{"Name"}, $TypeAttr{"NameSpace"}) = getTrivialName($TypeInfoId, $TypeId);
3366 if(not $TypeAttr{"Name"}) {
3367 return ();
3368 }
3369 if(not $TypeAttr{"NameSpace"}) {
3370 delete($TypeAttr{"NameSpace"});
3371 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04003372 if(defined $TemplateInstance{$Version}{"Type"}{$TypeId})
Andrey Ponomarenko16934472012-03-29 15:37:04 +04003373 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04003374 if(my @TParams = getTParams($TypeId, "Type"))
Andrey Ponomarenko16934472012-03-29 15:37:04 +04003375 {
3376 foreach my $Pos (0 .. $#TParams) {
3377 $TypeAttr{"TParam"}{$Pos}{"name"}=$TParams[$Pos];
3378 }
3379 }
3380 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003381 if(my $Size = getSize($TypeId)) {
3382 $TypeAttr{"Size"} = $Size/$BYTE_SIZE;
3383 }
3384 if($TypeAttr{"Type"} eq "Struct"
3385 and detect_lang($TypeId))
3386 {
3387 $TypeAttr{"Type"} = "Class";
Andrey Ponomarenko85043792012-05-14 16:48:07 +04003388 $TypeAttr{"Copied"} = 1; # default, will be changed in getSymbolInfo()
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003389 }
3390 if($TypeAttr{"Type"} eq "Struct"
Andrey Ponomarenko85043792012-05-14 16:48:07 +04003391 or $TypeAttr{"Type"} eq "Class")
3392 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04003393 my $Skip = setBaseClasses($TypeId, \%TypeAttr);
Andrey Ponomarenko85043792012-05-14 16:48:07 +04003394 if($Skip) {
3395 return ();
3396 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003397 }
3398 setSpec($TypeId, \%TypeAttr);
3399 setTypeMemb($TypeId, \%TypeAttr);
3400 $TypeAttr{"Tid"} = $TypeId;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003401 if(my $VTable = $ClassVTable_Content{$Version}{$TypeAttr{"Name"}})
3402 {
3403 my @Entries = split(/\n/, $VTable);
3404 foreach (1 .. $#Entries)
3405 {
3406 my $Entry = $Entries[$_];
3407 if($Entry=~/\A(\d+)\s+(.+)\Z/) {
3408 $TypeAttr{"VTable"}{$1} = $2;
3409 }
3410 }
3411 }
3412 return %TypeAttr;
3413}
3414
3415sub detect_lang($)
3416{
3417 my $TypeId = $_[0];
3418 my $Info = $LibInfo{$Version}{"info"}{$TypeId};
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04003419 if(check_gcc($GCC_PATH, "4"))
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04003420 { # GCC 4 fncs-node points to only non-artificial methods
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003421 return ($Info=~/(fncs)[ ]*:[ ]*@(\d+) /);
3422 }
3423 else
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04003424 { # GCC 3
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04003425 my $Fncs = getTreeAttr_Fncs($TypeId);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003426 while($Fncs)
3427 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04003428 if($LibInfo{$Version}{"info"}{$Fncs}!~/artificial/) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003429 return 1;
3430 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04003431 $Fncs = getTreeAttr_Chan($Fncs);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003432 }
3433 }
3434 return 0;
3435}
3436
3437sub setSpec($$)
3438{
3439 my ($TypeId, $TypeAttr) = @_;
3440 my $Info = $LibInfo{$Version}{"info"}{$TypeId};
3441 if($Info=~/\s+spec\s+/) {
3442 $TypeAttr->{"Spec"} = 1;
3443 }
3444}
3445
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04003446sub setBaseClasses($$)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003447{
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04003448 my ($TypeId, $TypeAttr) = @_;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003449 my $Info = $LibInfo{$Version}{"info"}{$TypeId};
3450 if($Info=~/binf[ ]*:[ ]*@(\d+) /)
3451 {
3452 $Info = $LibInfo{$Version}{"info"}{$1};
3453 my $Pos = 0;
3454 while($Info=~s/(pub|public|prot|protected|priv|private|)[ ]+binf[ ]*:[ ]*@(\d+) //)
3455 {
3456 my ($Access, $BInfoId) = ($1, $2);
3457 my $ClassId = getBinfClassId($BInfoId);
Andrey Ponomarenko85043792012-05-14 16:48:07 +04003458 my $CType = $LibInfo{$Version}{"info_type"}{$ClassId};
3459 if(not $CType or $CType eq "template_type_parm"
3460 or $CType eq "typename_type")
3461 { # skip
3462 return 1;
3463 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003464 my $BaseInfo = $LibInfo{$Version}{"info"}{$BInfoId};
3465 if($Access=~/prot/)
3466 {
3467 $TypeAttr->{"Base"}{$ClassId}{"access"} = "protected";
3468 }
3469 elsif($Access=~/priv/)
3470 {
3471 $TypeAttr->{"Base"}{$ClassId}{"access"} = "private";
3472 }
3473 $TypeAttr->{"Base"}{$ClassId}{"pos"} = $Pos++;
3474 if($BaseInfo=~/virt/)
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04003475 { # virtual base
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003476 $TypeAttr->{"Base"}{$ClassId}{"virtual"} = 1;
3477 }
3478 $Class_SubClasses{$Version}{$ClassId}{$TypeId}=1;
3479 }
3480 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +04003481 return 0;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003482}
3483
3484sub getBinfClassId($)
3485{
3486 my $Info = $LibInfo{$Version}{"info"}{$_[0]};
3487 $Info=~/type[ ]*:[ ]*@(\d+) /;
3488 return $1;
3489}
3490
3491sub unmangledFormat($$)
3492{
3493 my ($Name, $LibVersion) = @_;
3494 $Name = uncover_typedefs($Name, $LibVersion);
3495 while($Name=~s/([^\w>*])(const|volatile)(,|>|\Z)/$1$3/g){};
3496 $Name=~s/\(\w+\)(\d)/$1/;
3497 return $Name;
3498}
3499
3500sub modelUnmangled($$)
3501{
3502 my ($InfoId, $Compiler) = @_;
3503 if($Cache{"modelUnmangled"}{$Version}{$Compiler}{$InfoId}) {
3504 return $Cache{"modelUnmangled"}{$Version}{$Compiler}{$InfoId};
3505 }
3506 my $PureSignature = $SymbolInfo{$Version}{$InfoId}{"ShortName"};
3507 if($SymbolInfo{$Version}{$InfoId}{"Destructor"}) {
3508 $PureSignature = "~".$PureSignature;
3509 }
3510 if(not $SymbolInfo{$Version}{$InfoId}{"Data"})
3511 {
3512 my (@Params, @ParamTypes) = ();
3513 if(defined $SymbolInfo{$Version}{$InfoId}{"Param"}
3514 and not $SymbolInfo{$Version}{$InfoId}{"Destructor"}) {
3515 @Params = keys(%{$SymbolInfo{$Version}{$InfoId}{"Param"}});
3516 }
3517 foreach my $ParamPos (sort {int($a) <=> int($b)} @Params)
3518 { # checking parameters
3519 my $PId = $SymbolInfo{$Version}{$InfoId}{"Param"}{$ParamPos}{"type"};
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04003520 my %PType = get_PureType($PId, $Version);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003521 my $PTName = unmangledFormat($PType{"Name"}, $Version);
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04003522 $PTName=~s/\b(restrict|register)\b//g;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003523 if($Compiler eq "MSVC") {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04003524 $PTName=~s/\blong long\b/__int64/;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003525 }
3526 @ParamTypes = (@ParamTypes, $PTName);
3527 }
3528 if(@ParamTypes) {
3529 $PureSignature .= "(".join(", ", @ParamTypes).")";
3530 }
3531 else
3532 {
3533 if($Compiler eq "MSVC")
3534 {
3535 $PureSignature .= "(void)";
3536 }
3537 else
3538 { # GCC
3539 $PureSignature .= "()";
3540 }
3541 }
3542 $PureSignature = delete_keywords($PureSignature);
3543 }
3544 if(my $ClassId = $SymbolInfo{$Version}{$InfoId}{"Class"})
3545 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04003546 my $ClassName = unmangledFormat($TypeInfo{$Version}{$ClassId}{"Name"}, $Version);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003547 $PureSignature = $ClassName."::".$PureSignature;
3548 }
3549 elsif(my $NS = $SymbolInfo{$Version}{$InfoId}{"NameSpace"}) {
3550 $PureSignature = $NS."::".$PureSignature;
3551 }
3552 if($SymbolInfo{$Version}{$InfoId}{"Const"}) {
3553 $PureSignature .= " const";
3554 }
3555 if($SymbolInfo{$Version}{$InfoId}{"Volatile"}) {
3556 $PureSignature .= " volatile";
3557 }
3558 my $ShowReturn = 0;
3559 if($Compiler eq "MSVC"
3560 and $SymbolInfo{$Version}{$InfoId}{"Data"})
3561 {
3562 $ShowReturn=1;
3563 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04003564 elsif(defined $TemplateInstance{$Version}{"Func"}{$InfoId}
3565 and keys(%{$TemplateInstance{$Version}{"Func"}{$InfoId}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003566 {
3567 $ShowReturn=1;
3568 }
3569 if($ShowReturn)
3570 { # mangled names for template function specializations include return value
3571 if(my $ReturnId = $SymbolInfo{$Version}{$InfoId}{"Return"})
3572 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04003573 my %RType = get_PureType($ReturnId, $Version);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003574 my $ReturnName = unmangledFormat($RType{"Name"}, $Version);
3575 $PureSignature = $ReturnName." ".$PureSignature;
3576 }
3577 }
3578 return ($Cache{"modelUnmangled"}{$Version}{$Compiler}{$InfoId} = formatName($PureSignature));
3579}
3580
3581sub mangle_symbol($$$)
3582{ # mangling for simple methods
3583 # see gcc-4.6.0/gcc/cp/mangle.c
3584 my ($InfoId, $LibVersion, $Compiler) = @_;
3585 if($Cache{"mangle_symbol"}{$LibVersion}{$InfoId}{$Compiler}) {
3586 return $Cache{"mangle_symbol"}{$LibVersion}{$InfoId}{$Compiler};
3587 }
3588 my $Mangled = "";
3589 if($Compiler eq "GCC") {
Andrey Ponomarenko16934472012-03-29 15:37:04 +04003590 $Mangled = mangle_symbol_GCC($InfoId, $LibVersion);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003591 }
3592 elsif($Compiler eq "MSVC") {
Andrey Ponomarenko16934472012-03-29 15:37:04 +04003593 $Mangled = mangle_symbol_MSVC($InfoId, $LibVersion);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003594 }
3595 return ($Cache{"mangle_symbol"}{$LibVersion}{$InfoId}{$Compiler} = $Mangled);
3596}
3597
Andrey Ponomarenko16934472012-03-29 15:37:04 +04003598sub mangle_symbol_MSVC($$)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003599{
3600 my ($InfoId, $LibVersion) = @_;
3601 return "";
3602}
3603
Andrey Ponomarenko16934472012-03-29 15:37:04 +04003604sub mangle_symbol_GCC($$)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003605{ # see gcc-4.6.0/gcc/cp/mangle.c
3606 my ($InfoId, $LibVersion) = @_;
3607 my ($Mangled, $ClassId, $NameSpace) = ("_Z", 0, "");
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04003608 my $Return = $SymbolInfo{$LibVersion}{$InfoId}{"Return"};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003609 my %Repl = ();# SN_ replacements
3610 if($ClassId = $SymbolInfo{$LibVersion}{$InfoId}{"Class"})
3611 {
3612 my $MangledClass = mangle_param($ClassId, $LibVersion, \%Repl);
3613 if($MangledClass!~/\AN/) {
3614 $MangledClass = "N".$MangledClass;
3615 }
3616 else {
3617 $MangledClass=~s/E\Z//;
3618 }
3619 if($SymbolInfo{$LibVersion}{$InfoId}{"Volatile"}) {
3620 $MangledClass=~s/\AN/NV/;
3621 }
3622 if($SymbolInfo{$LibVersion}{$InfoId}{"Const"}) {
3623 $MangledClass=~s/\AN/NK/;
3624 }
3625 $Mangled .= $MangledClass;
3626 }
3627 elsif($NameSpace = $SymbolInfo{$LibVersion}{$InfoId}{"NameSpace"})
3628 { # mangled by name due to the absence of structured info
3629 my $MangledNS = mangle_ns($NameSpace, $LibVersion, \%Repl);
3630 if($MangledNS!~/\AN/) {
3631 $MangledNS = "N".$MangledNS;
3632 }
3633 else {
3634 $MangledNS=~s/E\Z//;
3635 }
3636 $Mangled .= $MangledNS;
3637 }
3638 my ($ShortName, $TmplParams) = template_base($SymbolInfo{$LibVersion}{$InfoId}{"ShortName"});
Andrey Ponomarenko16934472012-03-29 15:37:04 +04003639 my @TParams = ();
3640 if($Version)
3641 { # parsing mode
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04003642 @TParams = getTParams($InfoId, "Func");
Andrey Ponomarenko16934472012-03-29 15:37:04 +04003643 }
3644 elsif($TmplParams)
3645 { # remangling mode
3646 # support for old ABI dumps
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003647 @TParams = separate_params($TmplParams, 0);
3648 }
3649 if($SymbolInfo{$LibVersion}{$InfoId}{"Constructor"}) {
3650 $Mangled .= "C1";
3651 }
3652 elsif($SymbolInfo{$LibVersion}{$InfoId}{"Destructor"}) {
3653 $Mangled .= "D0";
3654 }
3655 elsif($ShortName)
3656 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04003657 if($SymbolInfo{$LibVersion}{$InfoId}{"Data"})
3658 {
Andrey Ponomarenko16934472012-03-29 15:37:04 +04003659 if(not $SymbolInfo{$LibVersion}{$InfoId}{"Class"}
Andrey Ponomarenko85043792012-05-14 16:48:07 +04003660 and isConstType($Return, $LibVersion))
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04003661 { # "const" global data is mangled as _ZL...
3662 $Mangled .= "L";
3663 }
3664 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003665 if($ShortName=~/\Aoperator(\W.*)\Z/)
3666 {
3667 my $Op = $1;
3668 $Op=~s/\A[ ]+//g;
3669 if(my $OpMngl = $OperatorMangling{$Op}) {
3670 $Mangled .= $OpMngl;
3671 }
3672 else { # conversion operator
3673 $Mangled .= "cv".mangle_param(getTypeIdByName($Op, $LibVersion), $LibVersion, \%Repl);
3674 }
3675 }
3676 else {
3677 $Mangled .= length($ShortName).$ShortName;
3678 }
3679 if(@TParams)
3680 { # templates
3681 $Mangled .= "I";
3682 foreach my $TParam (@TParams) {
3683 $Mangled .= mangle_template_param($TParam, $LibVersion, \%Repl);
3684 }
3685 $Mangled .= "E";
3686 }
3687 if(not $ClassId and @TParams) {
3688 add_substitution($ShortName, \%Repl, 0);
3689 }
3690 }
3691 if($ClassId or $NameSpace) {
3692 $Mangled .= "E";
3693 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +04003694 if(@TParams)
3695 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04003696 if($Return) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003697 $Mangled .= mangle_param($Return, $LibVersion, \%Repl);
3698 }
3699 }
3700 if(not $SymbolInfo{$LibVersion}{$InfoId}{"Data"})
3701 {
3702 my @Params = ();
3703 if(defined $SymbolInfo{$LibVersion}{$InfoId}{"Param"}
3704 and not $SymbolInfo{$LibVersion}{$InfoId}{"Destructor"}) {
3705 @Params = keys(%{$SymbolInfo{$LibVersion}{$InfoId}{"Param"}});
3706 }
3707 foreach my $ParamPos (sort {int($a) <=> int($b)} @Params)
3708 { # checking parameters
3709 my $ParamType_Id = $SymbolInfo{$LibVersion}{$InfoId}{"Param"}{$ParamPos}{"type"};
3710 $Mangled .= mangle_param($ParamType_Id, $LibVersion, \%Repl);
3711 }
3712 if(not @Params) {
3713 $Mangled .= "v";
3714 }
3715 }
3716 $Mangled = correct_incharge($InfoId, $LibVersion, $Mangled);
3717 $Mangled = write_stdcxx_substitution($Mangled);
3718 if($Mangled eq "_Z") {
3719 return "";
3720 }
3721 return $Mangled;
3722}
3723
3724sub correct_incharge($$$)
3725{
3726 my ($InfoId, $LibVersion, $Mangled) = @_;
3727 if($SymbolInfo{$LibVersion}{$InfoId}{"Constructor"})
3728 {
3729 if($MangledNames{$LibVersion}{$Mangled}) {
3730 $Mangled=~s/C1E/C2E/;
3731 }
3732 }
3733 elsif($SymbolInfo{$LibVersion}{$InfoId}{"Destructor"})
3734 {
3735 if($MangledNames{$LibVersion}{$Mangled}) {
3736 $Mangled=~s/D0E/D1E/;
3737 }
3738 if($MangledNames{$LibVersion}{$Mangled}) {
3739 $Mangled=~s/D1E/D2E/;
3740 }
3741 }
3742 return $Mangled;
3743}
3744
3745sub template_base($)
3746{ # NOTE: std::_Vector_base<mysqlpp::mysql_type_info>::_Vector_impl
Andrey Ponomarenko16934472012-03-29 15:37:04 +04003747 # NOTE: operators: >>, <<
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003748 my $Name = $_[0];
Andrey Ponomarenko16934472012-03-29 15:37:04 +04003749 if($Name!~/>\Z/ or $Name!~/</) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003750 return $Name;
3751 }
3752 my $TParams = $Name;
Andrey Ponomarenko16934472012-03-29 15:37:04 +04003753 while(my $CPos = find_center($TParams, "<"))
3754 { # search for the last <T>
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003755 $TParams = substr($TParams, $CPos);
3756 }
Andrey Ponomarenko16934472012-03-29 15:37:04 +04003757 if($TParams=~s/\A<(.+)>\Z/$1/) {
3758 $Name=~s/<\Q$TParams\E>\Z//;
3759 }
3760 else
3761 { # error
3762 $TParams = "";
3763 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003764 return ($Name, $TParams);
3765}
3766
3767sub get_sub_ns($)
3768{
3769 my $Name = $_[0];
3770 my @NS = ();
Andrey Ponomarenko16934472012-03-29 15:37:04 +04003771 while(my $CPos = find_center($Name, ":"))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003772 {
3773 push(@NS, substr($Name, 0, $CPos));
3774 $Name = substr($Name, $CPos);
3775 $Name=~s/\A:://;
3776 }
3777 return (join("::", @NS), $Name);
3778}
3779
3780sub mangle_ns($$$)
3781{
3782 my ($Name, $LibVersion, $Repl) = @_;
3783 if(my $Tid = $TName_Tid{$LibVersion}{$Name})
3784 {
3785 my $Mangled = mangle_param($Tid, $LibVersion, $Repl);
3786 $Mangled=~s/\AN(.+)E\Z/$1/;
3787 return $Mangled;
3788
3789 }
3790 else
3791 {
3792 my ($MangledNS, $SubNS) = ("", "");
3793 ($SubNS, $Name) = get_sub_ns($Name);
3794 if($SubNS) {
3795 $MangledNS .= mangle_ns($SubNS, $LibVersion, $Repl);
3796 }
3797 $MangledNS .= length($Name).$Name;
3798 add_substitution($MangledNS, $Repl, 0);
3799 return $MangledNS;
3800 }
3801}
3802
3803sub mangle_param($$$)
3804{
3805 my ($PTid, $LibVersion, $Repl) = @_;
3806 my ($MPrefix, $Mangled) = ("", "");
3807 my %ReplCopy = %{$Repl};
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04003808 my %BaseType = get_BaseType($PTid, $LibVersion);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003809 my $BaseType_Name = $BaseType{"Name"};
3810 if(not $BaseType_Name) {
3811 return "";
3812 }
3813 my ($ShortName, $TmplParams) = template_base($BaseType_Name);
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04003814 my $Suffix = get_BaseTypeQual($PTid, $LibVersion);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003815 while($Suffix=~s/\s*(const|volatile|restrict)\Z//g){};
3816 while($Suffix=~/(&|\*|const)\Z/)
3817 {
3818 if($Suffix=~s/[ ]*&\Z//) {
3819 $MPrefix .= "R";
3820 }
3821 if($Suffix=~s/[ ]*\*\Z//) {
3822 $MPrefix .= "P";
3823 }
3824 if($Suffix=~s/[ ]*const\Z//)
3825 {
3826 if($MPrefix=~/R|P/
3827 or $Suffix=~/&|\*/) {
3828 $MPrefix .= "K";
3829 }
3830 }
3831 if($Suffix=~s/[ ]*volatile\Z//) {
3832 $MPrefix .= "V";
3833 }
3834 #if($Suffix=~s/[ ]*restrict\Z//) {
3835 #$MPrefix .= "r";
3836 #}
3837 }
3838 if(my $Token = $IntrinsicMangling{$BaseType_Name}) {
3839 $Mangled .= $Token;
3840 }
3841 elsif($BaseType{"Type"}=~/(Class|Struct|Union|Enum)/)
3842 {
Andrey Ponomarenko16934472012-03-29 15:37:04 +04003843 my @TParams = ();
3844 if($Version)
3845 { # parsing mode
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04003846 @TParams = getTParams($BaseType{"Tid"}, "Type");
Andrey Ponomarenko16934472012-03-29 15:37:04 +04003847 }
3848 elsif($TmplParams)
3849 { # remangling mode
3850 # support for old ABI dumps
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003851 @TParams = separate_params($TmplParams, 0);
3852 }
3853 my $MangledNS = "";
3854 my ($SubNS, $SName) = get_sub_ns($ShortName);
3855 if($SubNS) {
3856 $MangledNS .= mangle_ns($SubNS, $LibVersion, $Repl);
3857 }
3858 $MangledNS .= length($SName).$SName;
3859 if(@TParams) {
3860 add_substitution($MangledNS, $Repl, 0);
3861 }
3862 $Mangled .= "N".$MangledNS;
3863 if(@TParams)
3864 { # templates
3865 $Mangled .= "I";
3866 foreach my $TParam (@TParams) {
3867 $Mangled .= mangle_template_param($TParam, $LibVersion, $Repl);
3868 }
3869 $Mangled .= "E";
3870 }
3871 $Mangled .= "E";
3872 }
3873 elsif($BaseType{"Type"}=~/(FuncPtr|MethodPtr)/)
3874 {
3875 if($BaseType{"Type"} eq "MethodPtr") {
3876 $Mangled .= "M".mangle_param($BaseType{"Class"}, $LibVersion, $Repl)."F";
3877 }
3878 else {
3879 $Mangled .= "PF";
3880 }
3881 $Mangled .= mangle_param($BaseType{"Return"}, $LibVersion, $Repl);
3882 my @Params = keys(%{$BaseType{"Param"}});
3883 foreach my $Num (sort {int($a)<=>int($b)} @Params) {
3884 $Mangled .= mangle_param($BaseType{"Param"}{$Num}{"type"}, $LibVersion, $Repl);
3885 }
3886 if(not @Params) {
3887 $Mangled .= "v";
3888 }
3889 $Mangled .= "E";
3890 }
3891 elsif($BaseType{"Type"} eq "FieldPtr")
3892 {
3893 $Mangled .= "M".mangle_param($BaseType{"Class"}, $LibVersion, $Repl);
3894 $Mangled .= mangle_param($BaseType{"Return"}, $LibVersion, $Repl);
3895 }
3896 $Mangled = $MPrefix.$Mangled;# add prefix (RPK)
3897 if(my $Optimized = write_substitution($Mangled, \%ReplCopy))
3898 {
3899 if($Mangled eq $Optimized)
3900 {
3901 if($ShortName!~/::/)
3902 { # remove "N ... E"
3903 if($MPrefix) {
3904 $Mangled=~s/\A($MPrefix)N(.+)E\Z/$1$2/g;
3905 }
3906 else {
3907 $Mangled=~s/\AN(.+)E\Z/$1/g;
3908 }
3909 }
3910 }
3911 else {
3912 $Mangled = $Optimized;
3913 }
3914 }
3915 add_substitution($Mangled, $Repl, 1);
3916 return $Mangled;
3917}
3918
3919sub mangle_template_param($$$)
3920{ # types + literals
3921 my ($TParam, $LibVersion, $Repl) = @_;
3922 if(my $TPTid = $TName_Tid{$LibVersion}{$TParam}) {
3923 return mangle_param($TPTid, $LibVersion, $Repl);
3924 }
3925 elsif($TParam=~/\A(\d+)(\w+)\Z/)
3926 { # class_name<1u>::method(...)
3927 return "L".$IntrinsicMangling{$ConstantSuffixR{$2}}.$1."E";
3928 }
3929 elsif($TParam=~/\A\(([\w ]+)\)(\d+)\Z/)
3930 { # class_name<(signed char)1>::method(...)
3931 return "L".$IntrinsicMangling{$1}.$2."E";
3932 }
3933 elsif($TParam eq "true")
3934 { # class_name<true>::method(...)
3935 return "Lb1E";
3936 }
3937 elsif($TParam eq "false")
3938 { # class_name<true>::method(...)
3939 return "Lb0E";
3940 }
3941 else { # internal error
3942 return length($TParam).$TParam;
3943 }
3944}
3945
3946sub add_substitution($$$)
3947{
3948 my ($Value, $Repl, $Rec) = @_;
3949 if($Rec)
3950 { # subtypes
3951 my @Subs = ($Value);
3952 while($Value=~s/\A(R|P|K)//) {
3953 push(@Subs, $Value);
3954 }
3955 foreach (reverse(@Subs)) {
3956 add_substitution($_, $Repl, 0);
3957 }
3958 return;
3959 }
3960 return if($Value=~/\AS(\d*)_\Z/);
3961 $Value=~s/\AN(.+)E\Z/$1/g;
3962 return if(defined $Repl->{$Value});
3963 return if(length($Value)<=1);
3964 return if($StdcxxMangling{$Value});
3965 # check for duplicates
3966 my $Base = $Value;
3967 foreach my $Type (sort {$Repl->{$a}<=>$Repl->{$b}} sort keys(%{$Repl}))
3968 {
3969 my $Num = $Repl->{$Type};
3970 my $Replace = macro_mangle($Num);
3971 $Base=~s/\Q$Replace\E/$Type/;
3972 }
3973 if(my $OldNum = $Repl->{$Base})
3974 {
3975 $Repl->{$Value} = $OldNum;
3976 return;
3977 }
3978 my @Repls = sort {$b<=>$a} values(%{$Repl});
3979 if(@Repls) {
3980 $Repl->{$Value} = $Repls[0]+1;
3981 }
3982 else {
3983 $Repl->{$Value} = -1;
3984 }
3985 # register duplicates
3986 # upward
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04003987 $Base = $Value;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003988 foreach my $Type (sort {$Repl->{$a}<=>$Repl->{$b}} sort keys(%{$Repl}))
3989 {
3990 next if($Base eq $Type);
3991 my $Num = $Repl->{$Type};
3992 my $Replace = macro_mangle($Num);
3993 $Base=~s/\Q$Type\E/$Replace/;
3994 $Repl->{$Base} = $Repl->{$Value};
3995 }
3996}
3997
3998sub macro_mangle($)
3999{
4000 my $Num = $_[0];
4001 if($Num==-1) {
4002 return "S_";
4003 }
4004 else
4005 {
4006 my $Code = "";
4007 if($Num<10)
4008 { # S0_, S1_, S2_, ...
4009 $Code = $Num;
4010 }
4011 elsif($Num>=10 and $Num<=35)
4012 { # SA_, SB_, SC_, ...
4013 $Code = chr(55+$Num);
4014 }
4015 else
4016 { # S10_, S11_, S12_
4017 $Code = $Num-26; # 26 is length of english alphabet
4018 }
4019 return "S".$Code."_";
4020 }
4021}
4022
4023sub write_stdcxx_substitution($)
4024{
4025 my $Mangled = $_[0];
4026 if($StdcxxMangling{$Mangled}) {
4027 return $StdcxxMangling{$Mangled};
4028 }
4029 else
4030 {
4031 my @Repls = keys(%StdcxxMangling);
4032 @Repls = sort {length($b)<=>length($a)} sort {$b cmp $a} @Repls;
4033 foreach my $MangledType (@Repls)
4034 {
4035 my $Replace = $StdcxxMangling{$MangledType};
4036 #if($Mangled!~/$Replace/) {
4037 $Mangled=~s/N\Q$MangledType\EE/$Replace/g;
4038 $Mangled=~s/\Q$MangledType\E/$Replace/g;
4039 #}
4040 }
4041 }
4042 return $Mangled;
4043}
4044
4045sub write_substitution($$)
4046{
4047 my ($Mangled, $Repl) = @_;
4048 if(defined $Repl->{$Mangled}
4049 and my $MnglNum = $Repl->{$Mangled}) {
4050 $Mangled = macro_mangle($MnglNum);
4051 }
4052 else
4053 {
4054 my @Repls = keys(%{$Repl});
4055 #@Repls = sort {$Repl->{$a}<=>$Repl->{$b}} @Repls;
4056 # FIXME: how to apply replacements? by num or by pos
4057 @Repls = sort {length($b)<=>length($a)} sort {$b cmp $a} @Repls;
4058 foreach my $MangledType (@Repls)
4059 {
4060 my $Replace = macro_mangle($Repl->{$MangledType});
4061 if($Mangled!~/$Replace/) {
4062 $Mangled=~s/N\Q$MangledType\EE/$Replace/g;
4063 $Mangled=~s/\Q$MangledType\E/$Replace/g;
4064 }
4065 }
4066 }
4067 return $Mangled;
4068}
4069
4070sub delete_keywords($)
4071{
4072 my $TypeName = $_[0];
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04004073 $TypeName=~s/\b(enum|struct|union|class) //g;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004074 return $TypeName;
4075}
4076
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004077sub uncover_typedefs($$)
4078{
4079 my ($TypeName, $LibVersion) = @_;
4080 return "" if(not $TypeName);
4081 if(defined $Cache{"uncover_typedefs"}{$LibVersion}{$TypeName}) {
4082 return $Cache{"uncover_typedefs"}{$LibVersion}{$TypeName};
4083 }
4084 my ($TypeName_New, $TypeName_Pre) = (formatName($TypeName), "");
4085 while($TypeName_New ne $TypeName_Pre)
4086 {
4087 $TypeName_Pre = $TypeName_New;
4088 my $TypeName_Copy = $TypeName_New;
4089 my %Words = ();
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04004090 while($TypeName_Copy=~s/\b([a-z_]([\w:]*\w|))\b//io)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004091 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04004092 if(not $Intrinsic_Keywords{$1}) {
4093 $Words{$1} = 1;
4094 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004095 }
4096 foreach my $Word (keys(%Words))
4097 {
4098 my $BaseType_Name = $Typedef_BaseName{$LibVersion}{$Word};
4099 next if(not $BaseType_Name);
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04004100 next if($TypeName_New=~/\b(struct|union|enum)\s\Q$Word\E\b/);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004101 if($BaseType_Name=~/\([\*]+\)/)
4102 { # FuncPtr
4103 if($TypeName_New=~/\Q$Word\E(.*)\Z/)
4104 {
4105 my $Type_Suffix = $1;
4106 $TypeName_New = $BaseType_Name;
4107 if($TypeName_New=~s/\(([\*]+)\)/($1 $Type_Suffix)/) {
4108 $TypeName_New = formatName($TypeName_New);
4109 }
4110 }
4111 }
4112 else
4113 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04004114 if($TypeName_New=~s/\b\Q$Word\E\b/$BaseType_Name/g) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004115 $TypeName_New = formatName($TypeName_New);
4116 }
4117 }
4118 }
4119 }
4120 return ($Cache{"uncover_typedefs"}{$LibVersion}{$TypeName} = $TypeName_New);
4121}
4122
4123sub isInternal($)
4124{
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04004125 if($_[0] and my $Info = $LibInfo{$Version}{"info"}{$_[0]})
4126 {
4127 if($Info=~/mngl[ ]*:[ ]*@(\d+) /)
4128 {
4129 if($LibInfo{$Version}{"info"}{$1}=~/\*[ ]*INTERNAL[ ]*\*/)
4130 { # _ZN7mysqlpp8DateTimeC1ERKS0_ *INTERNAL*
4131 return 1;
4132 }
4133 }
4134 }
4135 return 0;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004136}
4137
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04004138sub getDataVal($$)
4139{
4140 my ($InfoId, $TypeId) = @_;
4141 if(my $Info = $LibInfo{$Version}{"info"}{$InfoId})
4142 {
4143 if($Info=~/init[ ]*:[ ]*@(\d+) /)
4144 {
4145 if(defined $LibInfo{$Version}{"info_type"}{$1}
4146 and $LibInfo{$Version}{"info_type"}{$1} eq "nop_expr")
4147 { # char const* data = "str"
4148 # NOTE: disabled
4149 if(my $NopExpr = $LibInfo{$Version}{"info"}{$1})
4150 {
4151 if($NopExpr=~/op 0[ ]*:[ ]*@(\d+) /)
4152 {
4153 if(defined $LibInfo{$Version}{"info_type"}{$1}
4154 and $LibInfo{$Version}{"info_type"}{$1} eq "addr_expr")
4155 {
4156 if(my $AddrExpr = $LibInfo{$Version}{"info"}{$1})
4157 {
4158 if($AddrExpr=~/op 0[ ]*:[ ]*@(\d+) /)
4159 {
4160 return getInitVal($1, $TypeId);
4161 }
4162 }
4163 }
4164 }
4165 }
4166 }
4167 else {
4168 return getInitVal($1, $TypeId);
4169 }
4170 }
4171 }
4172 return undef;
4173}
4174
4175sub getInitVal($$)
4176{
4177 my ($InfoId, $TypeId) = @_;
4178 if(my $Info = $LibInfo{$Version}{"info"}{$InfoId})
4179 {
4180 if(my $InfoType = $LibInfo{$Version}{"info_type"}{$InfoId})
4181 {
4182 if($InfoType eq "integer_cst")
4183 {
4184 my $Val = getNodeIntCst($InfoId);
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04004185 if($TypeId and $TypeInfo{$Version}{$TypeId}{"Name"}=~/\Achar(| const)\Z/)
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04004186 { # characters
4187 $Val = chr($Val);
4188 }
4189 return $Val;
4190 }
4191 elsif($InfoType eq "string_cst") {
4192 return getNodeStrCst($InfoId);
4193 }
4194 }
4195 }
4196 return undef;
4197}
4198
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004199sub set_Class_And_Namespace($)
4200{
4201 my $InfoId = $_[0];
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04004202 if(my $Info = $LibInfo{$Version}{"info"}{$InfoId})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004203 {
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04004204 if($Info=~/scpe[ ]*:[ ]*@(\d+) /)
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04004205 {
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04004206 my $NSInfoId = $1;
4207 if(my $InfoType = $LibInfo{$Version}{"info_type"}{$NSInfoId})
4208 {
4209 if($InfoType eq "namespace_decl") {
4210 $SymbolInfo{$Version}{$InfoId}{"NameSpace"} = getNameSpace($InfoId);
4211 }
4212 elsif($InfoType eq "record_type") {
4213 $SymbolInfo{$Version}{$InfoId}{"Class"} = $NSInfoId;
4214 }
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04004215 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004216 }
4217 }
4218 if($SymbolInfo{$Version}{$InfoId}{"Class"}
4219 or $SymbolInfo{$Version}{$InfoId}{"NameSpace"})
4220 { # identify language
4221 setLanguage($Version, "C++");
4222 }
4223}
4224
4225sub debugType($$)
4226{
4227 my ($Tid, $LibVersion) = @_;
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04004228 my %Type = get_Type($Tid, $LibVersion);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004229 printMsg("INFO", Dumper(\%Type));
4230}
4231
4232sub debugMangling($)
4233{
4234 my $LibVersion = $_[0];
4235 my %Mangled = ();
4236 foreach my $InfoId (keys(%{$SymbolInfo{$LibVersion}}))
4237 {
4238 if(my $Mngl = $SymbolInfo{$LibVersion}{$InfoId}{"MnglName"})
4239 {
4240 if($Mngl=~/\A(_Z|\?)/) {
4241 $Mangled{$Mngl}=$InfoId;
4242 }
4243 }
4244 }
4245 translateSymbols(keys(%Mangled), $LibVersion);
4246 foreach my $Mngl (keys(%Mangled))
4247 {
Andrey Ponomarenko85043792012-05-14 16:48:07 +04004248 my $U1 = modelUnmangled($Mangled{$Mngl}, "GCC");
4249 my $U2 = $tr_name{$Mngl};
4250 if($U1 ne $U2) {
4251 printMsg("INFO", "INCORRECT MANGLING:\n $Mngl\n $U1\n $U2\n");
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004252 }
4253 }
4254}
4255
4256sub linkSymbol($)
4257{ # link symbols from shared libraries
4258 # with the symbols from header files
4259 my $InfoId = $_[0];
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04004260 if(my $Lang = $SymbolInfo{$Version}{$InfoId}{"Lang"})
4261 {
4262 if($Lang eq "C")
4263 { # extern "C"
4264 return $SymbolInfo{$Version}{$InfoId}{"ShortName"};
4265 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004266 }
4267 # try to mangle symbol
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04004268 if((not check_gcc($GCC_PATH, "4") and $SymbolInfo{$Version}{$InfoId}{"Class"})
4269 or (check_gcc($GCC_PATH, "4") and not $SymbolInfo{$Version}{$InfoId}{"Class"}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004270 { # 1. GCC 3.x doesn't mangle class methods names in the TU dump (only functions and global data)
4271 # 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 +04004272 if(not $CheckHeadersOnly)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004273 {
4274 if(my $Mangled = $mangled_name_gcc{modelUnmangled($InfoId, "GCC")}) {
4275 return correct_incharge($InfoId, $Version, $Mangled);
4276 }
4277 }
Andrey Ponomarenko16934472012-03-29 15:37:04 +04004278 if($CheckHeadersOnly
4279 or not $BinaryOnly)
4280 { # 1. --headers-only mode
4281 # 2. not mangled src-only symbols
4282 if(my $Mangled = mangle_symbol($InfoId, $Version, "GCC")) {
4283 return $Mangled;
4284 }
4285 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004286 }
4287 return "";
4288}
4289
4290sub setLanguage($$)
4291{
4292 my ($LibVersion, $Lang) = @_;
4293 if(not $UserLang) {
4294 $COMMON_LANGUAGE{$LibVersion} = $Lang;
4295 }
4296}
4297
4298sub getSymbolInfo($)
4299{
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04004300 my $InfoId = $_[0];
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04004301 if(isInternal($InfoId)) {
4302 return;
4303 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04004304 ($SymbolInfo{$Version}{$InfoId}{"Header"}, $SymbolInfo{$Version}{$InfoId}{"Line"}) = getLocation($InfoId);
4305 if(not $SymbolInfo{$Version}{$InfoId}{"Header"}
4306 or isBuiltIn($SymbolInfo{$Version}{$InfoId}{"Header"})) {
4307 delete($SymbolInfo{$Version}{$InfoId});
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004308 return;
4309 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04004310 setFuncAccess($InfoId);
4311 setFuncKind($InfoId);
4312 if($SymbolInfo{$Version}{$InfoId}{"PseudoTemplate"}) {
4313 delete($SymbolInfo{$Version}{$InfoId});
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004314 return;
4315 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04004316 $SymbolInfo{$Version}{$InfoId}{"Type"} = getFuncType($InfoId);
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04004317 if($SymbolInfo{$Version}{$InfoId}{"Return"} = getFuncReturn($InfoId))
4318 {
4319 if(not $TypeInfo{$Version}{$SymbolInfo{$Version}{$InfoId}{"Return"}}{"Name"})
4320 { # templates
4321 delete($SymbolInfo{$Version}{$InfoId});
4322 return;
4323 }
4324 }
4325 if(my $Rid = $SymbolInfo{$Version}{$InfoId}{"Return"})
4326 {
4327 if(defined $MissedTypedef{$Version}{$Rid})
4328 {
4329 if(my $AddedTid = $MissedTypedef{$Version}{$Rid}{"Tid"}) {
4330 $SymbolInfo{$Version}{$InfoId}{"Return"} = $AddedTid;
4331 }
4332 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004333 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04004334 if(not $SymbolInfo{$Version}{$InfoId}{"Return"}) {
4335 delete($SymbolInfo{$Version}{$InfoId}{"Return"});
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004336 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04004337 $SymbolInfo{$Version}{$InfoId}{"ShortName"} = getFuncShortName(getFuncOrig($InfoId));
4338 if($SymbolInfo{$Version}{$InfoId}{"ShortName"}=~/\._/) {
4339 delete($SymbolInfo{$Version}{$InfoId});
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004340 return;
4341 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04004342 if(defined $TemplateInstance{$Version}{"Func"}{$InfoId})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004343 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04004344 my @TParams = getTParams($InfoId, "Func");
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004345 if(not @TParams) {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04004346 delete($SymbolInfo{$Version}{$InfoId});
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004347 return;
4348 }
Andrey Ponomarenko16934472012-03-29 15:37:04 +04004349 foreach my $Pos (0 .. $#TParams) {
4350 $SymbolInfo{$Version}{$InfoId}{"TParam"}{$Pos}{"name"}=$TParams[$Pos];
4351 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004352 my $PrmsInLine = join(", ", @TParams);
Andrey Ponomarenko16934472012-03-29 15:37:04 +04004353 if($SymbolInfo{$Version}{$InfoId}{"ShortName"}=~/\Aoperator\W+\Z/)
4354 { # operator<< <T>, operator>> <T>
4355 $SymbolInfo{$Version}{$InfoId}{"ShortName"} .= " ";
4356 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04004357 $SymbolInfo{$Version}{$InfoId}{"ShortName"} .= "<".$PrmsInLine.">";
4358 $SymbolInfo{$Version}{$InfoId}{"ShortName"} = formatName($SymbolInfo{$Version}{$InfoId}{"ShortName"});
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004359 }
4360 else
4361 { # support for GCC 3.4
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04004362 $SymbolInfo{$Version}{$InfoId}{"ShortName"}=~s/<.+>\Z//;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004363 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04004364 $SymbolInfo{$Version}{$InfoId}{"MnglName"} = getTreeStr(getTreeAttr_Mngl($InfoId));
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04004365 # NOTE: mangling of some symbols may change depending on GCC version
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04004366 # GCC 4.6: _ZN28QExplicitlySharedDataPointerI11QPixmapDataEC2IT_EERKS_IT_E
4367 # GCC 4.7: _ZN28QExplicitlySharedDataPointerI11QPixmapDataEC2ERKS1_
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04004368
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04004369 if($SymbolInfo{$Version}{$InfoId}{"MnglName"}
4370 and $SymbolInfo{$Version}{$InfoId}{"MnglName"}!~/\A_Z/)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004371 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04004372 delete($SymbolInfo{$Version}{$InfoId});
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004373 return;
4374 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04004375 if(not $SymbolInfo{$Version}{$InfoId}{"Destructor"})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004376 { # destructors have an empty parameter list
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04004377 my $Skip = setFuncParams($InfoId);
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04004378 if($Skip) {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04004379 delete($SymbolInfo{$Version}{$InfoId});
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004380 return;
4381 }
4382 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04004383 set_Class_And_Namespace($InfoId);
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04004384 if(my $ClassId = $SymbolInfo{$Version}{$InfoId}{"Class"})
4385 {
4386 if(not $TypeInfo{$Version}{$ClassId}{"Name"})
4387 { # templates
4388 delete($SymbolInfo{$Version}{$InfoId});
4389 return;
4390 }
4391 }
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04004392 if(not $CheckHeadersOnly)
4393 {
4394 if($SymbolInfo{$Version}{$InfoId}{"Type"} eq "Function"
4395 and not $SymbolInfo{$Version}{$InfoId}{"Class"}
4396 and link_symbol($SymbolInfo{$Version}{$InfoId}{"ShortName"}, $Version, "-Deps"))
4397 { # functions (C++): not mangled in library, but are mangled in TU dump
4398 if(not $SymbolInfo{$Version}{$InfoId}{"MnglName"}
4399 or not link_symbol($SymbolInfo{$Version}{$InfoId}{"MnglName"}, $Version, "-Deps")) {
4400 $SymbolInfo{$Version}{$InfoId}{"MnglName"} = $SymbolInfo{$Version}{$InfoId}{"ShortName"};
4401 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004402 }
4403 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04004404 if($LibInfo{$Version}{"info"}{$InfoId}=~/ lang:[ ]*C /i) {
4405 $SymbolInfo{$Version}{$InfoId}{"Lang"} = "C";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004406 }
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04004407 if($UserLang and $UserLang eq "C")
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004408 { # --lang=C option
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04004409 $SymbolInfo{$Version}{$InfoId}{"MnglName"} = $SymbolInfo{$Version}{$InfoId}{"ShortName"};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004410 }
4411 if($COMMON_LANGUAGE{$Version} eq "C++")
4412 { # correct mangled & short names
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04004413 # C++ or --headers-only mode
4414 if($SymbolInfo{$Version}{$InfoId}{"ShortName"}=~/\A__(comp|base|deleting)_(c|d)tor\Z/)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004415 { # support for old GCC versions: reconstruct real names for constructors and destructors
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04004416 $SymbolInfo{$Version}{$InfoId}{"ShortName"} = getNameByInfo(getTypeDeclId($SymbolInfo{$Version}{$InfoId}{"Class"}));
4417 $SymbolInfo{$Version}{$InfoId}{"ShortName"}=~s/<.+>\Z//;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004418 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04004419 if(not $SymbolInfo{$Version}{$InfoId}{"MnglName"})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004420 { # try to mangle symbol (link with libraries)
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04004421 if(my $Mangled = linkSymbol($InfoId)) {
4422 $SymbolInfo{$Version}{$InfoId}{"MnglName"} = $Mangled;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004423 }
4424 }
4425 if($OStarget eq "windows")
4426 { # link MS C++ symbols from library with GCC symbols from headers
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04004427 if(my $Mangled1 = $mangled_name{$Version}{modelUnmangled($InfoId, "MSVC")})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004428 { # exported symbols
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04004429 $SymbolInfo{$Version}{$InfoId}{"MnglName"} = $Mangled1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004430 }
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04004431 elsif(my $Mangled2 = mangle_symbol($InfoId, $Version, "MSVC"))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004432 { # pure virtual symbols
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04004433 $SymbolInfo{$Version}{$InfoId}{"MnglName"} = $Mangled2;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004434 }
4435 }
4436 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04004437 if(not $SymbolInfo{$Version}{$InfoId}{"MnglName"})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004438 { # can't detect symbol name
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04004439 delete($SymbolInfo{$Version}{$InfoId});
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004440 return;
4441 }
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04004442 if(not $SymbolInfo{$Version}{$InfoId}{"Constructor"}
4443 and my $Spec = getVirtSpec(getFuncOrig($InfoId)))
4444 { # identify virtual and pure virtual functions
4445 # NOTE: constructors cannot be virtual
4446 # NOTE: in GCC 4.7 D1 destructors have no virtual spec
4447 # in the TU dump, so taking it from the original symbol
4448 if(not ($SymbolInfo{$Version}{$InfoId}{"Destructor"}
4449 and $SymbolInfo{$Version}{$InfoId}{"MnglName"}=~/D2E/))
4450 { # NOTE: D2 destructors are not present in a v-table
4451 $SymbolInfo{$Version}{$InfoId}{$Spec} = 1;
4452 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004453 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04004454 if(isInline($InfoId)) {
4455 $SymbolInfo{$Version}{$InfoId}{"InLine"} = 1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004456 }
Andrey Ponomarenkob8d203d2012-05-25 18:11:07 +04004457 if($LibInfo{$Version}{"info"}{$InfoId}=~/ artificial /i) {
4458 $SymbolInfo{$Version}{$InfoId}{"Artificial"} = 1;
4459 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04004460 if($SymbolInfo{$Version}{$InfoId}{"Constructor"}
4461 and my $ClassId = $SymbolInfo{$Version}{$InfoId}{"Class"})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004462 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04004463 if(not $SymbolInfo{$Version}{$InfoId}{"InLine"}
Andrey Ponomarenkob8d203d2012-05-25 18:11:07 +04004464 and not $SymbolInfo{$Version}{$InfoId}{"Artificial"})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004465 { # inline or auto-generated constructor
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04004466 delete($TypeInfo{$Version}{$ClassId}{"Copied"});
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004467 }
4468 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +04004469 if(my $Symbol = $SymbolInfo{$Version}{$InfoId}{"MnglName"})
4470 {
4471 if(not $SymbolInfo{$Version}{$InfoId}{"Virt"}
4472 and not $SymbolInfo{$Version}{$InfoId}{"PureVirt"})
4473 {
4474 if(not selectSymbol($Symbol, $SymbolInfo{$Version}{$InfoId}, "Dump", $Version))
4475 { # non-target symbols
4476 delete($SymbolInfo{$Version}{$InfoId});
4477 return;
4478 }
4479 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004480 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04004481 if($SymbolInfo{$Version}{$InfoId}{"Type"} eq "Method"
4482 or $SymbolInfo{$Version}{$InfoId}{"Constructor"}
4483 or $SymbolInfo{$Version}{$InfoId}{"Destructor"}
4484 or $SymbolInfo{$Version}{$InfoId}{"Class"})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004485 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04004486 if($SymbolInfo{$Version}{$InfoId}{"MnglName"}!~/\A(_Z|\?)/) {
4487 delete($SymbolInfo{$Version}{$InfoId});
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004488 return;
4489 }
4490 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04004491 if($SymbolInfo{$Version}{$InfoId}{"MnglName"})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004492 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04004493 if($MangledNames{$Version}{$SymbolInfo{$Version}{$InfoId}{"MnglName"}})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004494 { # one instance for one mangled name only
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04004495 delete($SymbolInfo{$Version}{$InfoId});
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004496 return;
4497 }
4498 else {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04004499 $MangledNames{$Version}{$SymbolInfo{$Version}{$InfoId}{"MnglName"}} = 1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004500 }
4501 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04004502 if($SymbolInfo{$Version}{$InfoId}{"Constructor"}
4503 or $SymbolInfo{$Version}{$InfoId}{"Destructor"}) {
4504 delete($SymbolInfo{$Version}{$InfoId}{"Return"});
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004505 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04004506 if($SymbolInfo{$Version}{$InfoId}{"MnglName"}=~/\A(_Z|\?)/
4507 and $SymbolInfo{$Version}{$InfoId}{"Class"})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004508 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04004509 if($SymbolInfo{$Version}{$InfoId}{"Type"} eq "Function")
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004510 { # static methods
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04004511 $SymbolInfo{$Version}{$InfoId}{"Static"} = 1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004512 }
4513 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04004514 if(getFuncLink($InfoId) eq "Static") {
4515 $SymbolInfo{$Version}{$InfoId}{"Static"} = 1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004516 }
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04004517 if($SymbolInfo{$Version}{$InfoId}{"MnglName"}=~/\A(_Z|\?)/)
4518 {
4519 if(my $Unmangled = $tr_name{$SymbolInfo{$Version}{$InfoId}{"MnglName"}})
4520 {
4521 if($Unmangled=~/\.\_\d/) {
4522 delete($SymbolInfo{$Version}{$InfoId});
4523 return;
4524 }
4525 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004526 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04004527 delete($SymbolInfo{$Version}{$InfoId}{"Type"});
4528 if($SymbolInfo{$Version}{$InfoId}{"MnglName"}=~/\A_ZN(V|)K/) {
4529 $SymbolInfo{$Version}{$InfoId}{"Const"} = 1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004530 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04004531 if($SymbolInfo{$Version}{$InfoId}{"MnglName"}=~/\A_ZN(K|)V/) {
4532 $SymbolInfo{$Version}{$InfoId}{"Volatile"} = 1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004533 }
4534}
4535
4536sub isInline($)
4537{ # "body: undefined" in the tree
4538 # -fkeep-inline-functions GCC option should be specified
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04004539 if($_[0] and my $Info = $LibInfo{$Version}{"info"}{$_[0]})
4540 {
4541 if($Info=~/ undefined /i) {
4542 return 0;
4543 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004544 }
4545 return 1;
4546}
4547
4548sub getTypeId($)
4549{
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04004550 if($_[0] and my $Info = $LibInfo{$Version}{"info"}{$_[0]})
4551 {
4552 if($Info=~/type[ ]*:[ ]*@(\d+) /) {
4553 return $1;
4554 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004555 }
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04004556 return "";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004557}
4558
4559sub setTypeMemb($$)
4560{
4561 my ($TypeId, $TypeAttr) = @_;
4562 my $TypeType = $TypeAttr->{"Type"};
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04004563 my ($Pos, $UnnamedPos) = (0, 0);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004564 if($TypeType eq "Enum")
4565 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04004566 my $TypeMembInfoId = getTreeAttr_Csts($TypeId);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004567 while($TypeMembInfoId)
4568 {
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04004569 $TypeAttr->{"Memb"}{$Pos}{"value"} = getEnumMembVal($TypeMembInfoId);
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04004570 my $MembName = getTreeStr(getTreeAttr_Purp($TypeMembInfoId));
4571 $TypeAttr->{"Memb"}{$Pos}{"name"} = $MembName;
4572 $EnumMembName_Id{$Version}{getTreeAttr_Valu($TypeMembInfoId)} = ($TypeAttr->{"NameSpace"})?$TypeAttr->{"NameSpace"}."::".$MembName:$MembName;
4573 $TypeMembInfoId = getNextElem($TypeMembInfoId);
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04004574 $Pos += 1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004575 }
4576 }
4577 elsif($TypeType=~/\A(Struct|Class|Union)\Z/)
4578 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04004579 my $TypeMembInfoId = getTreeAttr_Flds($TypeId);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004580 while($TypeMembInfoId)
4581 {
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04004582 my $IType = $LibInfo{$Version}{"info_type"}{$TypeMembInfoId};
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04004583 my $MInfo = $LibInfo{$Version}{"info"}{$TypeMembInfoId};
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04004584 if(not $IType or $IType ne "field_decl")
4585 { # search for fields, skip other stuff in the declaration
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04004586 $TypeMembInfoId = getNextElem($TypeMembInfoId);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004587 next;
4588 }
4589 my $StructMembName = getStructMembName($TypeMembInfoId);
4590 if($StructMembName=~/_vptr\./)
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04004591 { # virtual tables
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04004592 $TypeMembInfoId = getNextElem($TypeMembInfoId);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004593 next;
4594 }
4595 if(not $StructMembName)
4596 { # unnamed fields
4597 if($TypeAttr->{"Name"}!~/_type_info_pseudo/)
4598 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04004599 my $UnnamedTid = getTreeAttr_Type($TypeMembInfoId);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004600 my $UnnamedTName = getNameByInfo(getTypeDeclId($UnnamedTid));
4601 if(isAnon($UnnamedTName))
4602 { # rename unnamed fields to unnamed0, unnamed1, ...
4603 $StructMembName = "unnamed".($UnnamedPos++);
4604 }
4605 }
4606 }
4607 if(not $StructMembName)
4608 { # unnamed fields and base classes
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04004609 $TypeMembInfoId = getNextElem($TypeMembInfoId);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004610 next;
4611 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04004612 my $MembTypeId = getTreeAttr_Type($TypeMembInfoId);
4613 if(defined $MissedTypedef{$Version}{$MembTypeId})
4614 {
4615 if(my $AddedTid = $MissedTypedef{$Version}{$MembTypeId}{"Tid"}) {
4616 $MembTypeId = $AddedTid;
4617 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004618 }
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04004619 $TypeAttr->{"Memb"}{$Pos}{"type"} = $MembTypeId;
4620 $TypeAttr->{"Memb"}{$Pos}{"name"} = $StructMembName;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004621 if((my $Access = getTreeAccess($TypeMembInfoId)) ne "public")
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04004622 { # marked only protected and private, public by default
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04004623 $TypeAttr->{"Memb"}{$Pos}{"access"} = $Access;
4624 }
4625 if($MInfo=~/spec:\s*mutable /)
4626 { # mutable fields
4627 $TypeAttr->{"Memb"}{$Pos}{"mutable"} = 1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004628 }
4629 if(my $BFSize = getStructMembBitFieldSize($TypeMembInfoId)) {
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04004630 $TypeAttr->{"Memb"}{$Pos}{"bitfield"} = $BFSize;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004631 }
4632 else
4633 { # set alignment for non-bit fields
4634 # alignment for bitfields is always equal to 1 bit
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04004635 if(my $Algn = getAlgn($TypeMembInfoId)) {
4636 $TypeAttr->{"Memb"}{$Pos}{"algn"} = $Algn/$BYTE_SIZE;
4637 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004638 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04004639 $TypeMembInfoId = getNextElem($TypeMembInfoId);
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04004640 $Pos += 1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004641 }
4642 }
4643}
4644
4645sub setFuncParams($)
4646{
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04004647 my $InfoId = $_[0];
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04004648 my $ParamInfoId = getTreeAttr_Args($InfoId);
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04004649 if(getFuncType($InfoId) eq "Method")
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004650 { # check type of "this" pointer
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04004651 my $ObjectTypeId = getTreeAttr_Type($ParamInfoId);
4652 if(my $ObjectName = $TypeInfo{$Version}{$ObjectTypeId}{"Name"})
Andrey Ponomarenko85043792012-05-14 16:48:07 +04004653 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04004654 if($ObjectName=~/\bconst(| volatile)\*const\b/) {
Andrey Ponomarenko85043792012-05-14 16:48:07 +04004655 $SymbolInfo{$Version}{$InfoId}{"Const"} = 1;
4656 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04004657 if($ObjectName=~/\bvolatile\b/) {
Andrey Ponomarenko85043792012-05-14 16:48:07 +04004658 $SymbolInfo{$Version}{$InfoId}{"Volatile"} = 1;
4659 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004660 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +04004661 else
4662 { # skip
4663 return 1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004664 }
4665 $ParamInfoId = getNextElem($ParamInfoId);
4666 }
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04004667 my ($Pos, $Vtt_Pos) = (0, -1);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004668 while($ParamInfoId)
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04004669 { # formal args
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04004670 my $ParamTypeId = getTreeAttr_Type($ParamInfoId);
4671 my $ParamName = getTreeStr(getTreeAttr_Name($ParamInfoId));
4672 if(not $ParamName)
4673 { # unnamed
4674 $ParamName = "p".($Pos+1);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004675 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04004676 if(defined $MissedTypedef{$Version}{$ParamTypeId})
4677 {
4678 if(my $AddedTid = $MissedTypedef{$Version}{$ParamTypeId}{"Tid"}) {
4679 $ParamTypeId = $AddedTid;
4680 }
4681 }
4682 my $PType = $TypeInfo{$Version}{$ParamTypeId}{"Type"};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004683 if(not $PType or $PType eq "Unknown") {
4684 return 1;
4685 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04004686 my $PTName = $TypeInfo{$Version}{$ParamTypeId}{"Name"};
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04004687 if(not $PTName) {
4688 return 1;
4689 }
4690 if($PTName eq "void") {
4691 last;
4692 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004693 if($ParamName eq "__vtt_parm"
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04004694 and $TypeInfo{$Version}{$ParamTypeId}{"Name"} eq "void const**")
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004695 {
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04004696 $Vtt_Pos = $Pos;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004697 $ParamInfoId = getNextElem($ParamInfoId);
4698 next;
4699 }
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04004700 $SymbolInfo{$Version}{$InfoId}{"Param"}{$Pos}{"type"} = $ParamTypeId;
4701 $SymbolInfo{$Version}{$InfoId}{"Param"}{$Pos}{"name"} = $ParamName;
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04004702 if(my $Algn = getAlgn($ParamInfoId)) {
4703 $SymbolInfo{$Version}{$InfoId}{"Param"}{$Pos}{"algn"} = $Algn/$BYTE_SIZE;
4704 }
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04004705 if(not $SymbolInfo{$Version}{$InfoId}{"Param"}{$Pos}{"name"}) {
4706 $SymbolInfo{$Version}{$InfoId}{"Param"}{$Pos}{"name"} = "p".($Pos+1);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004707 }
4708 if($LibInfo{$Version}{"info"}{$ParamInfoId}=~/spec:\s*register /)
4709 { # foo(register type arg)
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04004710 $SymbolInfo{$Version}{$InfoId}{"Param"}{$Pos}{"reg"} = 1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004711 }
4712 $ParamInfoId = getNextElem($ParamInfoId);
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04004713 $Pos += 1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004714 }
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04004715 if(setFuncArgs($InfoId, $Vtt_Pos)) {
4716 $SymbolInfo{$Version}{$InfoId}{"Param"}{$Pos}{"type"} = -1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004717 }
4718 return 0;
4719}
4720
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04004721sub setFuncArgs($$)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004722{
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04004723 my ($InfoId, $Vtt_Pos) = @_;
4724 my $FuncTypeId = getFuncTypeId($InfoId);
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04004725 my $ParamListElemId = getTreeAttr_Prms($FuncTypeId);
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04004726 if(getFuncType($InfoId) eq "Method") {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004727 $ParamListElemId = getNextElem($ParamListElemId);
4728 }
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04004729 if(not $ParamListElemId)
4730 { # foo(...)
4731 return 1;
4732 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004733 my $HaveVoid = 0;
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04004734 my $Pos = 0;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004735 while($ParamListElemId)
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04004736 { # actual params: may differ from formal args
4737 # formal int*const
4738 # actual: int*
4739 if($Vtt_Pos!=-1 and $Pos==$Vtt_Pos)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004740 {
4741 $Vtt_Pos=-1;
4742 $ParamListElemId = getNextElem($ParamListElemId);
4743 next;
4744 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04004745 my $ParamTypeId = getTreeAttr_Valu($ParamListElemId);
4746 if($TypeInfo{$Version}{$ParamTypeId}{"Name"} eq "void")
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04004747 {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004748 $HaveVoid = 1;
4749 last;
4750 }
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04004751 elsif(not defined $SymbolInfo{$Version}{$InfoId}{"Param"}{$Pos}{"type"})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004752 {
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04004753 $SymbolInfo{$Version}{$InfoId}{"Param"}{$Pos}{"type"} = $ParamTypeId;
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04004754 if(not $SymbolInfo{$Version}{$InfoId}{"Param"}{$Pos}{"name"})
4755 { # unnamed
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04004756 $SymbolInfo{$Version}{$InfoId}{"Param"}{$Pos}{"name"} = "p".($Pos+1);
4757 }
4758 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04004759 if(my $PurpId = getTreeAttr_Purp($ParamListElemId))
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04004760 { # default arguments
4761 if(my $PurpType = $LibInfo{$Version}{"info_type"}{$PurpId}) {
4762 $SymbolInfo{$Version}{$InfoId}{"Param"}{$Pos}{"default"} = getInitVal($PurpId, $ParamTypeId);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004763 }
4764 }
4765 $ParamListElemId = getNextElem($ParamListElemId);
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04004766 $Pos += 1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004767 }
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04004768 return ($Pos>=1 and not $HaveVoid);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004769}
4770
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04004771sub getTreeAttr_Chan($)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004772{
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04004773 if($_[0] and my $Info = $LibInfo{$Version}{"info"}{$_[0]})
4774 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04004775 if($Info=~/chan[ ]*:[ ]*@(\d+) /) {
4776 return $1;
4777 }
4778 }
4779 return "";
4780}
4781
4782sub getTreeAttr_Chain($)
4783{
4784 if($_[0] and my $Info = $LibInfo{$Version}{"info"}{$_[0]})
4785 {
4786 if($Info=~/chain[ ]*:[ ]*@(\d+) /) {
4787 return $1;
4788 }
4789 }
4790 return "";
4791}
4792
4793sub getTreeAttr_Scpe($)
4794{
4795 if($_[0] and my $Info = $LibInfo{$Version}{"info"}{$_[0]})
4796 {
4797 if($Info=~/scpe[ ]*:[ ]*@(\d+) /) {
4798 return $1;
4799 }
4800 }
4801 return "";
4802}
4803
4804sub getTreeAttr_Type($)
4805{
4806 if($_[0] and my $Info = $LibInfo{$Version}{"info"}{$_[0]})
4807 {
4808 if($Info=~/type[ ]*:[ ]*@(\d+) /) {
4809 return $1;
4810 }
4811 }
4812 return "";
4813}
4814
4815sub getTreeAttr_Name($)
4816{
4817 if($_[0] and my $Info = $LibInfo{$Version}{"info"}{$_[0]})
4818 {
4819 if($Info=~/name[ ]*:[ ]*@(\d+) /) {
4820 return $1;
4821 }
4822 }
4823 return "";
4824}
4825
4826sub getTreeAttr_Mngl($)
4827{
4828 if($_[0] and my $Info = $LibInfo{$Version}{"info"}{$_[0]})
4829 {
4830 if($Info=~/mngl[ ]*:[ ]*@(\d+) /) {
4831 return $1;
4832 }
4833 }
4834 return "";
4835}
4836
4837sub getTreeAttr_Prms($)
4838{
4839 if($_[0] and my $Info = $LibInfo{$Version}{"info"}{$_[0]})
4840 {
4841 if($Info=~/prms[ ]*:[ ]*@(\d+) /) {
4842 return $1;
4843 }
4844 }
4845 return "";
4846}
4847
4848sub getTreeAttr_Fncs($)
4849{
4850 if($_[0] and my $Info = $LibInfo{$Version}{"info"}{$_[0]})
4851 {
4852 if($Info=~/fncs[ ]*:[ ]*@(\d+) /) {
4853 return $1;
4854 }
4855 }
4856 return "";
4857}
4858
4859sub getTreeAttr_Csts($)
4860{
4861 if($_[0] and my $Info = $LibInfo{$Version}{"info"}{$_[0]})
4862 {
4863 if($Info=~/csts[ ]*:[ ]*@(\d+) /) {
4864 return $1;
4865 }
4866 }
4867 return "";
4868}
4869
4870sub getTreeAttr_Purp($)
4871{
4872 if($_[0] and my $Info = $LibInfo{$Version}{"info"}{$_[0]})
4873 {
4874 if($Info=~/purp[ ]*:[ ]*@(\d+) /) {
4875 return $1;
4876 }
4877 }
4878 return "";
4879}
4880
4881sub getTreeAttr_Valu($)
4882{
4883 if($_[0] and my $Info = $LibInfo{$Version}{"info"}{$_[0]})
4884 {
4885 if($Info=~/valu[ ]*:[ ]*@(\d+) /) {
4886 return $1;
4887 }
4888 }
4889 return "";
4890}
4891
4892sub getTreeAttr_Flds($)
4893{
4894 if($_[0] and my $Info = $LibInfo{$Version}{"info"}{$_[0]})
4895 {
4896 if($Info=~/flds[ ]*:[ ]*@(\d+) /) {
4897 return $1;
4898 }
4899 }
4900 return "";
4901}
4902
4903sub getTreeAttr_Args($)
4904{
4905 if($_[0] and my $Info = $LibInfo{$Version}{"info"}{$_[0]})
4906 {
4907 if($Info=~/args[ ]*:[ ]*@(\d+) /) {
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04004908 return $1;
4909 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004910 }
4911 return "";
4912}
4913
4914sub getTreeValue($)
4915{
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04004916 if($_[0] and my $Info = $LibInfo{$Version}{"info"}{$_[0]})
4917 {
4918 if($Info=~/low[ ]*:[ ]*([^ ]+) /) {
4919 return $1;
4920 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004921 }
4922 return "";
4923}
4924
4925sub getTreeAccess($)
4926{
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04004927 if($_[0] and my $Info = $LibInfo{$Version}{"info"}{$_[0]})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004928 {
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04004929 if($Info=~/accs[ ]*:[ ]*([a-zA-Z]+) /)
4930 {
4931 my $Access = $1;
4932 if($Access eq "prot") {
4933 return "protected";
4934 }
4935 elsif($Access eq "priv") {
4936 return "private";
4937 }
4938 }
4939 elsif($Info=~/ protected /)
4940 { # support for old GCC versions
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004941 return "protected";
4942 }
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04004943 elsif($Info=~/ private /)
4944 { # support for old GCC versions
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004945 return "private";
4946 }
4947 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004948 return "public";
4949}
4950
4951sub setFuncAccess($)
4952{
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04004953 my $Access = getTreeAccess($_[0]);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004954 if($Access eq "protected") {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04004955 $SymbolInfo{$Version}{$_[0]}{"Protected"} = 1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004956 }
4957 elsif($Access eq "private") {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04004958 $SymbolInfo{$Version}{$_[0]}{"Private"} = 1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004959 }
4960}
4961
4962sub setTypeAccess($$)
4963{
4964 my ($TypeId, $TypeAttr) = @_;
4965 my $Access = getTreeAccess($TypeId);
4966 if($Access eq "protected") {
4967 $TypeAttr->{"Protected"} = 1;
4968 }
4969 elsif($Access eq "private") {
4970 $TypeAttr->{"Private"} = 1;
4971 }
4972}
4973
4974sub setFuncKind($)
4975{
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04004976 if($_[0] and my $Info = $LibInfo{$Version}{"info"}{$_[0]})
4977 {
4978 if($Info=~/pseudo tmpl/) {
4979 $SymbolInfo{$Version}{$_[0]}{"PseudoTemplate"} = 1;
4980 }
4981 elsif($Info=~/ constructor /) {
4982 $SymbolInfo{$Version}{$_[0]}{"Constructor"} = 1;
4983 }
4984 elsif($Info=~/ destructor /) {
4985 $SymbolInfo{$Version}{$_[0]}{"Destructor"} = 1;
4986 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004987 }
4988}
4989
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04004990sub getVirtSpec($)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004991{
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04004992 if($_[0] and my $Info = $LibInfo{$Version}{"info"}{$_[0]})
4993 {
4994 if($Info=~/spec[ ]*:[ ]*pure /) {
4995 return "PureVirt";
4996 }
4997 elsif($Info=~/spec[ ]*:[ ]*virt /) {
4998 return "Virt";
4999 }
5000 elsif($Info=~/ pure\s+virtual /)
5001 { # support for old GCC versions
5002 return "PureVirt";
5003 }
5004 elsif($Info=~/ virtual /)
5005 { # support for old GCC versions
5006 return "Virt";
5007 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005008 }
5009 return "";
5010}
5011
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005012sub getFuncLink($)
5013{
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04005014 if($_[0] and my $Info = $LibInfo{$Version}{"info"}{$_[0]})
5015 {
5016 if($Info=~/link[ ]*:[ ]*static /) {
5017 return "Static";
5018 }
5019 elsif($Info=~/link[ ]*:[ ]*([a-zA-Z]+) /) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005020 return $1;
5021 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005022 }
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04005023 return "";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005024}
5025
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005026sub get_IntNameSpace($$)
5027{
5028 my ($Interface, $LibVersion) = @_;
5029 return "" if(not $Interface or not $LibVersion);
5030 if(defined $Cache{"get_IntNameSpace"}{$Interface}{$LibVersion}) {
5031 return $Cache{"get_IntNameSpace"}{$Interface}{$LibVersion};
5032 }
5033 my $Signature = get_Signature($Interface, $LibVersion);
5034 if($Signature=~/\:\:/)
5035 {
5036 my $FounNameSpace = 0;
5037 foreach my $NameSpace (sort {get_depth($b)<=>get_depth($a)} keys(%{$NestedNameSpaces{$LibVersion}}))
5038 {
5039 if($Signature=~/(\A|\s+for\s+)\Q$NameSpace\E\:\:/) {
5040 return ($Cache{"get_IntNameSpace"}{$Interface}{$LibVersion} = $NameSpace);
5041 }
5042 }
5043 }
5044 else {
5045 return ($Cache{"get_IntNameSpace"}{$Interface}{$LibVersion} = "");
5046 }
5047}
5048
5049sub parse_TypeNameSpace($$)
5050{
5051 my ($TypeName, $LibVersion) = @_;
5052 return "" if(not $TypeName or not $LibVersion);
5053 if(defined $Cache{"parse_TypeNameSpace"}{$TypeName}{$LibVersion}) {
5054 return $Cache{"parse_TypeNameSpace"}{$TypeName}{$LibVersion};
5055 }
5056 if($TypeName=~/\:\:/)
5057 {
5058 my $FounNameSpace = 0;
5059 foreach my $NameSpace (sort {get_depth($b)<=>get_depth($a)} keys(%{$NestedNameSpaces{$LibVersion}}))
5060 {
5061 if($TypeName=~/\A\Q$NameSpace\E\:\:/) {
5062 return ($Cache{"parse_TypeNameSpace"}{$TypeName}{$LibVersion} = $NameSpace);
5063 }
5064 }
5065 }
5066 else {
5067 return ($Cache{"parse_TypeNameSpace"}{$TypeName}{$LibVersion} = "");
5068 }
5069}
5070
5071sub getNameSpace($)
5072{
5073 my $TypeInfoId = $_[0];
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04005074 if(my $NSInfoId = getTreeAttr_Scpe($TypeInfoId))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005075 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04005076 if(my $InfoType = $LibInfo{$Version}{"info_type"}{$NSInfoId})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005077 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04005078 if($InfoType eq "namespace_decl")
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04005079 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04005080 if($LibInfo{$Version}{"info"}{$NSInfoId}=~/name[ ]*:[ ]*@(\d+) /)
5081 {
5082 my $NameSpace = getTreeStr($1);
5083 if($NameSpace eq "::")
5084 { # global namespace
5085 return "";
5086 }
5087 if(my $BaseNameSpace = getNameSpace($NSInfoId)) {
5088 $NameSpace = $BaseNameSpace."::".$NameSpace;
5089 }
5090 $NestedNameSpaces{$Version}{$NameSpace} = 1;
5091 return $NameSpace;
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04005092 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04005093 else {
5094 return "";
5095 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005096 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04005097 elsif($InfoType eq "record_type")
5098 { # inside data type
5099 my ($Name, $NameNS) = getTrivialName(getTypeDeclId($NSInfoId), $NSInfoId);
5100 return $Name;
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04005101 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005102 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005103 }
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04005104 return "";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005105}
5106
5107sub getNameSpaceId($)
5108{
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04005109 if($_[0] and my $Info = $LibInfo{$Version}{"info"}{$_[0]})
5110 {
5111 if($Info=~/scpe[ ]*:[ ]*\@(\d+)/) {
5112 return $1;
5113 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005114 }
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04005115 return "";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005116}
5117
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005118sub getStructMembName($)
5119{
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04005120 if($_[0] and my $Info = $LibInfo{$Version}{"info"}{$_[0]})
5121 {
5122 if($Info=~/name[ ]*:[ ]*\@(\d+)/) {
5123 return getTreeStr($1);
5124 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005125 }
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04005126 return "";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005127}
5128
5129sub getEnumMembVal($)
5130{
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04005131 if($_[0] and my $Info = $LibInfo{$Version}{"info"}{$_[0]})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005132 {
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04005133 if($Info=~/valu[ ]*:[ ]*\@(\d+)/)
5134 {
5135 if(my $VInfo = $LibInfo{$Version}{"info"}{$1})
5136 {
5137 if($VInfo=~/cnst[ ]*:[ ]*\@(\d+)/)
5138 { # in newer versions of GCC the value is in the "const_decl->cnst" node
5139 return getTreeValue($1);
5140 }
5141 else
5142 { # some old versions of GCC (3.3) have the value in the "integer_cst" node
5143 return getTreeValue($1);
5144 }
5145 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005146 }
5147 }
5148 return "";
5149}
5150
5151sub getSize($)
5152{
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04005153 if($_[0] and my $Info = $LibInfo{$Version}{"info"}{$_[0]})
5154 {
5155 if($Info=~/size[ ]*:[ ]*\@(\d+)/) {
5156 return getTreeValue($1);
5157 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005158 }
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04005159 return 0;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005160}
5161
5162sub getAlgn($)
5163{
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04005164 if($_[0] and my $Info = $LibInfo{$Version}{"info"}{$_[0]})
5165 {
5166 if($Info=~/algn[ ]*:[ ]*(\d+) /) {
5167 return $1;
5168 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005169 }
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04005170 return "";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005171}
5172
5173sub getStructMembBitFieldSize($)
5174{
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04005175 if($_[0] and my $Info = $LibInfo{$Version}{"info"}{$_[0]})
5176 {
5177 if($Info=~/ bitfield /) {
5178 return getSize($_[0]);
5179 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005180 }
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04005181 return 0;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005182}
5183
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04005184sub getNextElem($)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005185{
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04005186 if(my $Chan = getTreeAttr_Chan($_[0])) {
5187 return $Chan;
5188 }
5189 elsif(my $Chain = getTreeAttr_Chain($_[0])) {
5190 return $Chain;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005191 }
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04005192 return "";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005193}
5194
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04005195sub registerHeader($$)
5196{ # input: absolute path of header, relative path or name
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005197 my ($Header, $LibVersion) = @_;
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04005198 if(not $Header) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005199 return "";
5200 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04005201 if(is_abs($Header) and not -f $Header)
5202 { # incorrect absolute path
5203 exitStatus("Access_Error", "can't access \'$Header\'");
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005204 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04005205 if(skipHeader($Header, $LibVersion))
5206 { # skip
5207 return "";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005208 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04005209 if(my $Header_Path = identifyHeader($Header, $LibVersion))
5210 {
5211 detect_header_includes($Header_Path, $LibVersion);
5212
5213 if(my $RHeader_Path = $Header_ErrorRedirect{$LibVersion}{$Header_Path})
5214 { # redirect
5215 if($Registered_Headers{$LibVersion}{$RHeader_Path}{"Identity"}
5216 or skipHeader($RHeader_Path, $LibVersion))
5217 { # skip
5218 return "";
5219 }
5220 $Header_Path = $RHeader_Path;
5221 }
5222 elsif($Header_ShouldNotBeUsed{$LibVersion}{$Header_Path})
5223 { # skip
5224 return "";
5225 }
5226
5227 if(my $HName = get_filename($Header_Path))
5228 { # register
5229 $Registered_Headers{$LibVersion}{$Header_Path}{"Identity"} = $HName;
5230 $HeaderName_Paths{$LibVersion}{$HName}{$Header_Path} = 1;
5231 }
5232
5233 if(($Header=~/\.(\w+)\Z/ and $1 ne "h")
5234 or $Header!~/\.(\w+)\Z/)
5235 { # hpp, hh
5236 setLanguage($LibVersion, "C++");
5237 }
5238
5239 if($CheckHeadersOnly
5240 and $Header=~/(\A|\/)c\+\+(\/|\Z)/)
5241 { # /usr/include/c++/4.6.1/...
5242 $STDCXX_TESTING = 1;
5243 }
5244
5245 return $Header_Path;
5246 }
5247 return "";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005248}
5249
5250sub register_directory($$$)
5251{
5252 my ($Dir, $WithDeps, $LibVersion) = @_;
5253 $Dir=~s/[\/\\]+\Z//g;
5254 return if(not $LibVersion or not $Dir or not -d $Dir);
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04005255 return if(skipHeader($Dir, $LibVersion));
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005256 $Dir = get_abs_path($Dir);
5257 my $Mode = "All";
Andrey Ponomarenko85043792012-05-14 16:48:07 +04005258 if($WithDeps)
5259 {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005260 if($RegisteredDirs{$LibVersion}{$Dir}{1}) {
5261 return;
5262 }
5263 elsif($RegisteredDirs{$LibVersion}{$Dir}{0}) {
5264 $Mode = "DepsOnly";
5265 }
5266 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +04005267 else
5268 {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005269 if($RegisteredDirs{$LibVersion}{$Dir}{1}
5270 or $RegisteredDirs{$LibVersion}{$Dir}{0}) {
5271 return;
5272 }
5273 }
5274 $Header_Dependency{$LibVersion}{$Dir} = 1;
5275 $RegisteredDirs{$LibVersion}{$Dir}{$WithDeps} = 1;
5276 if($Mode eq "DepsOnly")
5277 {
5278 foreach my $Path (cmd_find($Dir,"d","","")) {
5279 $Header_Dependency{$LibVersion}{$Path} = 1;
5280 }
5281 return;
5282 }
5283 foreach my $Path (sort {length($b)<=>length($a)} cmd_find($Dir,"f","",""))
5284 {
5285 if($WithDeps)
5286 {
5287 my $SubDir = $Path;
5288 while(($SubDir = get_dirname($SubDir)) ne $Dir)
5289 { # register all sub directories
5290 $Header_Dependency{$LibVersion}{$SubDir} = 1;
5291 }
5292 }
5293 next if(is_not_header($Path));
5294 next if(ignore_path($Path));
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04005295 next if(skipHeader($Path, $LibVersion));
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005296 # Neighbors
5297 foreach my $Part (get_path_prefixes($Path)) {
5298 $Include_Neighbors{$LibVersion}{$Part} = $Path;
5299 }
5300 }
5301 if(get_filename($Dir) eq "include")
5302 { # search for "lib/include/" directory
5303 my $LibDir = $Dir;
5304 if($LibDir=~s/([\/\\])include\Z/$1lib/g and -d $LibDir) {
5305 register_directory($LibDir, $WithDeps, $LibVersion);
5306 }
5307 }
5308}
5309
5310sub parse_redirect($$$)
5311{
5312 my ($Content, $Path, $LibVersion) = @_;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005313 my @Errors = ();
5314 while($Content=~s/#\s*error\s+([^\n]+?)\s*(\n|\Z)//) {
5315 push(@Errors, $1);
5316 }
5317 my $Redirect = "";
5318 foreach (@Errors)
5319 {
5320 s/\s{2,}/ /g;
5321 if(/(only|must\ include
5322 |update\ to\ include
5323 |replaced\ with
5324 |replaced\ by|renamed\ to
5325 |is\ in|use)\ (<[^<>]+>|[\w\-\/\\]+\.($HEADER_EXT))/ix)
5326 {
5327 $Redirect = $2;
5328 last;
5329 }
5330 elsif(/(include|use|is\ in)\ (<[^<>]+>|[\w\-\/\\]+\.($HEADER_EXT))\ instead/i)
5331 {
5332 $Redirect = $2;
5333 last;
5334 }
5335 elsif(/this\ header\ should\ not\ be\ used
5336 |programs\ should\ not\ directly\ include
5337 |you\ should\ not\ (include|be\ (including|using)\ this\ (file|header))
5338 |is\ not\ supported\ API\ for\ general\ use
5339 |do\ not\ use
5340 |should\ not\ be\ used
5341 |cannot\ be\ included\ directly/ix and not /\ from\ /i) {
5342 $Header_ShouldNotBeUsed{$LibVersion}{$Path} = 1;
5343 }
5344 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +04005345 if($Redirect)
5346 {
5347 $Redirect=~s/\A<//g;
5348 $Redirect=~s/>\Z//g;
5349 }
5350 return $Redirect;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005351}
5352
5353sub parse_includes($$)
5354{
5355 my ($Content, $Path) = @_;
5356 my %Includes = ();
5357 while($Content=~s/#([ \t]*)(include|include_next|import)([ \t]*)(<|")([^<>"]+)(>|")//)
Andrey Ponomarenko85043792012-05-14 16:48:07 +04005358 { # C/C++: include, Objective C/C++: import directive
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005359 my ($Header, $Method) = ($5, $4);
5360 $Header = path_format($Header, $OSgroup);
Andrey Ponomarenko85043792012-05-14 16:48:07 +04005361 if($Method eq "\"" or is_abs($Header))
5362 {
5363 if(-e joinPath(get_dirname($Path), $Header))
5364 { # relative path exists
5365 $Includes{$Header} = -1;
5366 }
5367 else
5368 { # include "..." that doesn't exist is equal to include <...>
5369 $Includes{$Header} = 2;
5370 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005371 }
5372 else {
5373 $Includes{$Header} = 1;
5374 }
5375 }
5376 return \%Includes;
5377}
5378
5379sub ignore_path($)
5380{
5381 my $Path = $_[0];
5382 if($Path=~/\~\Z/)
5383 {# skipping system backup files
5384 return 1;
5385 }
5386 if($Path=~/(\A|[\/\\]+)(\.(svn|git|bzr|hg)|CVS)([\/\\]+|\Z)/)
5387 {# skipping hidden .svn, .git, .bzr, .hg and CVS directories
5388 return 1;
5389 }
5390 return 0;
5391}
5392
5393sub sort_by_word($$)
5394{
5395 my ($ArrRef, $W) = @_;
5396 return if(length($W)<2);
5397 @{$ArrRef} = sort {get_filename($b)=~/\Q$W\E/i<=>get_filename($a)=~/\Q$W\E/i} @{$ArrRef};
5398}
5399
5400sub natural_sorting($$)
5401{
5402 my ($H1, $H2) = @_;
5403 $H1=~s/\.[a-z]+\Z//ig;
5404 $H2=~s/\.[a-z]+\Z//ig;
5405 my ($HDir1, $Hname1) = separate_path($H1);
5406 my ($HDir2, $Hname2) = separate_path($H2);
5407 my $Dirname1 = get_filename($HDir1);
5408 my $Dirname2 = get_filename($HDir2);
5409 if($H1 eq $H2) {
5410 return 0;
5411 }
5412 elsif($H1=~/\A\Q$H2\E/) {
5413 return 1;
5414 }
5415 elsif($H2=~/\A\Q$H1\E/) {
5416 return -1;
5417 }
5418 elsif($HDir1=~/\Q$Hname1\E/i
5419 and $HDir2!~/\Q$Hname2\E/i)
5420 {# include/glib-2.0/glib.h
5421 return -1;
5422 }
5423 elsif($HDir2=~/\Q$Hname2\E/i
5424 and $HDir1!~/\Q$Hname1\E/i)
5425 {# include/glib-2.0/glib.h
5426 return 1;
5427 }
5428 elsif($Hname1=~/\Q$Dirname1\E/i
5429 and $Hname2!~/\Q$Dirname2\E/i)
5430 {# include/hildon-thumbnail/hildon-thumbnail-factory.h
5431 return -1;
5432 }
5433 elsif($Hname2=~/\Q$Dirname2\E/i
5434 and $Hname1!~/\Q$Dirname1\E/i)
5435 {# include/hildon-thumbnail/hildon-thumbnail-factory.h
5436 return 1;
5437 }
5438 elsif($Hname1=~/(config|lib)/i
5439 and $Hname2!~/(config|lib)/i)
5440 {# include/alsa/asoundlib.h
5441 return -1;
5442 }
5443 elsif($Hname2=~/(config|lib)/i
5444 and $Hname1!~/(config|lib)/i)
5445 {# include/alsa/asoundlib.h
5446 return 1;
5447 }
5448 elsif(checkRelevance($H1)
5449 and not checkRelevance($H2))
5450 {# libebook/e-book.h
5451 return -1;
5452 }
5453 elsif(checkRelevance($H2)
5454 and not checkRelevance($H1))
5455 {# libebook/e-book.h
5456 return 1;
5457 }
5458 else {
5459 return (lc($H1) cmp lc($H2));
5460 }
5461}
5462
5463sub searchForHeaders($)
5464{
5465 my $LibVersion = $_[0];
5466 # gcc standard include paths
5467 find_gcc_cxx_headers($LibVersion);
5468 # processing header paths
5469 foreach my $Path (keys(%{$Descriptor{$LibVersion}{"IncludePaths"}}),
5470 keys(%{$Descriptor{$LibVersion}{"AddIncludePaths"}}))
5471 {
5472 my $IPath = $Path;
5473 if(not -e $Path) {
5474 exitStatus("Access_Error", "can't access \'$Path\'");
5475 }
5476 elsif(-f $Path) {
5477 exitStatus("Access_Error", "\'$Path\' - not a directory");
5478 }
5479 elsif(-d $Path)
5480 {
5481 $Path = get_abs_path($Path);
5482 register_directory($Path, 0, $LibVersion);
5483 if($Descriptor{$LibVersion}{"AddIncludePaths"}{$IPath}) {
5484 $Add_Include_Paths{$LibVersion}{$Path} = 1;
5485 }
5486 else {
5487 $Include_Paths{$LibVersion}{$Path} = 1;
5488 }
5489 }
5490 }
5491 if(keys(%{$Include_Paths{$LibVersion}})) {
5492 $INC_PATH_AUTODETECT{$LibVersion} = 0;
5493 }
5494 # registering directories
5495 foreach my $Path (split(/\s*\n\s*/, $Descriptor{$LibVersion}{"Headers"}))
5496 {
5497 next if(not -e $Path);
5498 $Path = get_abs_path($Path);
5499 $Path = path_format($Path, $OSgroup);
5500 if(-d $Path) {
5501 register_directory($Path, 1, $LibVersion);
5502 }
5503 elsif(-f $Path)
5504 {
5505 my $Dir = get_dirname($Path);
5506 if(not $SystemPaths{"include"}{$Dir}
5507 and not $LocalIncludes{$Dir})
5508 {
5509 register_directory($Dir, 1, $LibVersion);
5510 if(my $OutDir = get_dirname($Dir))
5511 { # registering the outer directory
5512 if(not $SystemPaths{"include"}{$OutDir}
5513 and not $LocalIncludes{$OutDir}) {
5514 register_directory($OutDir, 0, $LibVersion);
5515 }
5516 }
5517 }
5518 }
5519 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +04005520
5521 # clean memory
5522 %RegisteredDirs = ();
5523
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005524 # registering headers
5525 my $Position = 0;
5526 foreach my $Dest (split(/\s*\n\s*/, $Descriptor{$LibVersion}{"Headers"}))
5527 {
5528 if(is_abs($Dest) and not -e $Dest) {
5529 exitStatus("Access_Error", "can't access \'$Dest\'");
5530 }
5531 $Dest = path_format($Dest, $OSgroup);
5532 if(is_header($Dest, 1, $LibVersion))
5533 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04005534 if(my $HPath = registerHeader($Dest, $LibVersion)) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005535 $Registered_Headers{$LibVersion}{$HPath}{"Pos"} = $Position++;
5536 }
5537 }
5538 elsif(-d $Dest)
5539 {
5540 my @Registered = ();
5541 foreach my $Path (cmd_find($Dest,"f","",""))
5542 {
5543 next if(ignore_path($Path));
5544 next if(not is_header($Path, 0, $LibVersion));
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04005545 if(my $HPath = registerHeader($Path, $LibVersion)) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005546 push(@Registered, $HPath);
5547 }
5548 }
5549 @Registered = sort {natural_sorting($a, $b)} @Registered;
5550 sort_by_word(\@Registered, $TargetLibraryShortName);
5551 foreach my $Path (@Registered) {
5552 $Registered_Headers{$LibVersion}{$Path}{"Pos"} = $Position++;
5553 }
5554 }
5555 else {
5556 exitStatus("Access_Error", "can't identify \'$Dest\' as a header file");
5557 }
5558 }
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04005559 if(my $HList = $Descriptor{$LibVersion}{"IncludePreamble"})
5560 { # preparing preamble headers
5561 my $PPos=0;
5562 foreach my $Header (split(/\s*\n\s*/, $HList))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005563 {
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04005564 if(is_abs($Header) and not -f $Header) {
5565 exitStatus("Access_Error", "can't access file \'$Header\'");
5566 }
5567 $Header = path_format($Header, $OSgroup);
5568 if(my $Header_Path = is_header($Header, 1, $LibVersion))
5569 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04005570 next if(skipHeader($Header_Path, $LibVersion));
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04005571 $Include_Preamble{$LibVersion}{$Header_Path}{"Position"} = $PPos++;
5572 }
5573 else {
5574 exitStatus("Access_Error", "can't identify \'$Header\' as a header file");
5575 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005576 }
5577 }
5578 foreach my $Header_Name (keys(%{$HeaderName_Paths{$LibVersion}}))
5579 { # set relative paths (for duplicates)
5580 if(keys(%{$HeaderName_Paths{$LibVersion}{$Header_Name}})>=2)
5581 { # search for duplicates
5582 my $FirstPath = (keys(%{$HeaderName_Paths{$LibVersion}{$Header_Name}}))[0];
5583 my $Prefix = get_dirname($FirstPath);
5584 while($Prefix=~/\A(.+)[\/\\]+[^\/\\]+\Z/)
5585 { # detect a shortest distinguishing prefix
5586 my $NewPrefix = $1;
5587 my %Identity = ();
5588 foreach my $Path (keys(%{$HeaderName_Paths{$LibVersion}{$Header_Name}}))
5589 {
5590 if($Path=~/\A\Q$Prefix\E[\/\\]+(.*)\Z/) {
5591 $Identity{$Path} = $1;
5592 }
5593 }
5594 if(keys(%Identity)==keys(%{$HeaderName_Paths{$LibVersion}{$Header_Name}}))
5595 { # all names are differend with current prefix
5596 foreach my $Path (keys(%{$HeaderName_Paths{$LibVersion}{$Header_Name}})) {
5597 $Registered_Headers{$LibVersion}{$Path}{"Identity"} = $Identity{$Path};
5598 }
5599 last;
5600 }
5601 $Prefix = $NewPrefix; # increase prefix
5602 }
5603 }
5604 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +04005605
5606 # clean memory
5607 %HeaderName_Paths = ();
5608
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005609 foreach my $HeaderName (keys(%{$Include_Order{$LibVersion}}))
5610 { # ordering headers according to descriptor
5611 my $PairName=$Include_Order{$LibVersion}{$HeaderName};
5612 my ($Pos, $PairPos) = (-1, -1);
5613 my ($Path, $PairPath) = ();
5614 my @Paths = keys(%{$Registered_Headers{$LibVersion}});
5615 @Paths = sort {int($Registered_Headers{$LibVersion}{$a}{"Pos"})<=>int($Registered_Headers{$LibVersion}{$b}{"Pos"})} @Paths;
5616 foreach my $Header_Path (@Paths)
5617 {
5618 if(get_filename($Header_Path) eq $PairName)
5619 {
5620 $PairPos = $Registered_Headers{$LibVersion}{$Header_Path}{"Pos"};
5621 $PairPath = $Header_Path;
5622 }
5623 if(get_filename($Header_Path) eq $HeaderName)
5624 {
5625 $Pos = $Registered_Headers{$LibVersion}{$Header_Path}{"Pos"};
5626 $Path = $Header_Path;
5627 }
5628 }
5629 if($PairPos!=-1 and $Pos!=-1
5630 and int($PairPos)<int($Pos))
5631 {
5632 my %Tmp = %{$Registered_Headers{$LibVersion}{$Path}};
5633 %{$Registered_Headers{$LibVersion}{$Path}} = %{$Registered_Headers{$LibVersion}{$PairPath}};
5634 %{$Registered_Headers{$LibVersion}{$PairPath}} = %Tmp;
5635 }
5636 }
5637 if(not keys(%{$Registered_Headers{$LibVersion}})) {
5638 exitStatus("Error", "header files are not found in the ".$Descriptor{$LibVersion}{"Version"});
5639 }
5640}
5641
5642sub detect_real_includes($$)
5643{
5644 my ($AbsPath, $LibVersion) = @_;
5645 return () if(not $LibVersion or not $AbsPath or not -e $AbsPath);
5646 if($Cache{"detect_real_includes"}{$LibVersion}{$AbsPath}
5647 or keys(%{$RecursiveIncludes{$LibVersion}{$AbsPath}})) {
5648 return keys(%{$RecursiveIncludes{$LibVersion}{$AbsPath}});
5649 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +04005650 $Cache{"detect_real_includes"}{$LibVersion}{$AbsPath}=1;
5651
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005652 my $Path = callPreprocessor($AbsPath, "", $LibVersion);
5653 return () if(not $Path);
5654 open(PREPROC, $Path);
5655 while(<PREPROC>)
5656 {
5657 if(/#\s+\d+\s+"([^"]+)"[\s\d]*\n/)
5658 {
5659 my $Include = path_format($1, $OSgroup);
5660 if($Include=~/\<(built\-in|internal|command(\-|\s)line)\>|\A\./) {
5661 next;
5662 }
5663 if($Include eq $AbsPath) {
5664 next;
5665 }
5666 $RecursiveIncludes{$LibVersion}{$AbsPath}{$Include} = 1;
5667 }
5668 }
5669 close(PREPROC);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005670 return keys(%{$RecursiveIncludes{$LibVersion}{$AbsPath}});
5671}
5672
5673sub detect_header_includes($$)
5674{
5675 my ($Path, $LibVersion) = @_;
Andrey Ponomarenko85043792012-05-14 16:48:07 +04005676 return if(not $LibVersion or not $Path);
5677 if(defined $Cache{"detect_header_includes"}{$LibVersion}{$Path}) {
5678 return;
5679 }
5680 $Cache{"detect_header_includes"}{$LibVersion}{$Path}=1;
5681
5682 if(not -e $Path) {
5683 return;
5684 }
5685
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005686 my $Content = readFile($Path);
Andrey Ponomarenko85043792012-05-14 16:48:07 +04005687 if(my $Redirect = parse_redirect($Content, $Path, $LibVersion))
5688 { # detect error directive in headers
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04005689 if(my $RedirectPath = identifyHeader($Redirect, $LibVersion))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005690 {
5691 if($RedirectPath=~/\/usr\/include\// and $Path!~/\/usr\/include\//) {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04005692 $RedirectPath = identifyHeader(get_filename($Redirect), $LibVersion);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005693 }
5694 if($RedirectPath ne $Path) {
5695 $Header_ErrorRedirect{$LibVersion}{$Path} = $RedirectPath;
5696 }
5697 }
5698 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +04005699 if(my $Inc = parse_includes($Content, $Path))
5700 {
5701 foreach my $Include (keys(%{$Inc}))
5702 { # detect includes
Andrey Ponomarenko85043792012-05-14 16:48:07 +04005703 $Header_Includes{$LibVersion}{$Path}{$Include} = $Inc->{$Include};
5704 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005705 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005706}
5707
5708sub simplify_path($)
5709{
5710 my $Path = $_[0];
5711 while($Path=~s&([\/\\])[^\/\\]+[\/\\]\.\.[\/\\]&$1&){};
5712 return $Path;
5713}
5714
5715sub fromLibc($)
5716{ # GLIBC header
5717 my $Path = $_[0];
5718 my ($Dir, $Name) = separate_path($Path);
5719 if(get_filename($Dir)=~/\A(include|libc)\Z/ and $GlibcHeader{$Name})
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04005720 { # /usr/include/{stdio, ...}.h
5721 # epoc32/include/libc/{stdio, ...}.h
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005722 return 1;
5723 }
5724 if(isLibcDir($Dir)) {
5725 return 1;
5726 }
5727 return 0;
5728}
5729
5730sub isLibcDir($)
5731{ # GLIBC directory
5732 my $Dir = $_[0];
5733 my ($OutDir, $Name) = separate_path($Dir);
5734 if(get_filename($OutDir)=~/\A(include|libc)\Z/
5735 and ($Name=~/\Aasm(|-.+)\Z/ or $GlibcDir{$Name}))
5736 { # /usr/include/{sys,bits,asm,asm-*}/*.h
5737 return 1;
5738 }
5739 return 0;
5740}
5741
5742sub detect_recursive_includes($$)
5743{
5744 my ($AbsPath, $LibVersion) = @_;
5745 return () if(not $AbsPath);
5746 if(isCyclical(\@RecurInclude, $AbsPath)) {
5747 return keys(%{$RecursiveIncludes{$LibVersion}{$AbsPath}});
5748 }
5749 my ($AbsDir, $Name) = separate_path($AbsPath);
5750 if(isLibcDir($AbsDir))
5751 { # GLIBC internals
5752 return ();
5753 }
5754 if(keys(%{$RecursiveIncludes{$LibVersion}{$AbsPath}})) {
5755 return keys(%{$RecursiveIncludes{$LibVersion}{$AbsPath}});
5756 }
5757 return () if($OSgroup ne "windows" and $Name=~/windows|win32|win64/i);
5758 return () if($MAIN_CPP_DIR and $AbsPath=~/\A\Q$MAIN_CPP_DIR\E/ and not $STDCXX_TESTING);
5759 push(@RecurInclude, $AbsPath);
5760 if($DefaultGccPaths{$AbsDir}
5761 or fromLibc($AbsPath))
5762 { # check "real" (non-"model") include paths
5763 my @Paths = detect_real_includes($AbsPath, $LibVersion);
5764 pop(@RecurInclude);
5765 return @Paths;
5766 }
5767 if(not keys(%{$Header_Includes{$LibVersion}{$AbsPath}})) {
5768 detect_header_includes($AbsPath, $LibVersion);
5769 }
5770 foreach my $Include (keys(%{$Header_Includes{$LibVersion}{$AbsPath}}))
5771 {
Andrey Ponomarenko85043792012-05-14 16:48:07 +04005772 my $IncType = $Header_Includes{$LibVersion}{$AbsPath}{$Include};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005773 my $HPath = "";
Andrey Ponomarenko85043792012-05-14 16:48:07 +04005774 if($IncType<0)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005775 { # for #include "..."
5776 my $Candidate = joinPath($AbsDir, $Include);
5777 if(-f $Candidate) {
5778 $HPath = simplify_path($Candidate);
5779 }
5780 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +04005781 elsif($IncType>0
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04005782 and $Include=~/[\/\\]/) # and not find_in_defaults($Include)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005783 { # search for the nearest header
5784 # QtCore/qabstractanimation.h includes <QtCore/qobject.h>
5785 my $Candidate = joinPath(get_dirname($AbsDir), $Include);
5786 if(-f $Candidate) {
5787 $HPath = $Candidate;
5788 }
5789 }
5790 if(not $HPath) {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04005791 $HPath = identifyHeader($Include, $LibVersion);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005792 }
5793 next if(not $HPath);
5794 if($HPath eq $AbsPath) {
5795 next;
5796 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +04005797 $RecursiveIncludes{$LibVersion}{$AbsPath}{$HPath} = $IncType;
5798 if($IncType>0)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005799 { # only include <...>, skip include "..." prefixes
5800 $Header_Include_Prefix{$LibVersion}{$AbsPath}{$HPath}{get_dirname($Include)} = 1;
5801 }
5802 foreach my $IncPath (detect_recursive_includes($HPath, $LibVersion))
5803 {
5804 if($IncPath eq $AbsPath) {
5805 next;
5806 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +04005807 my $RIncType = $RecursiveIncludes{$LibVersion}{$HPath}{$IncPath};
5808 if($RIncType==-1)
5809 { # include "..."
5810 $RIncType = $IncType;
5811 }
5812 elsif($RIncType==2)
5813 {
5814 if($IncType!=-1) {
5815 $RIncType = $IncType;
5816 }
5817 }
5818 $RecursiveIncludes{$LibVersion}{$AbsPath}{$IncPath} = $RIncType;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005819 foreach my $Prefix (keys(%{$Header_Include_Prefix{$LibVersion}{$HPath}{$IncPath}})) {
5820 $Header_Include_Prefix{$LibVersion}{$AbsPath}{$IncPath}{$Prefix} = 1;
5821 }
5822 }
5823 foreach my $Dep (keys(%{$Header_Include_Prefix{$LibVersion}{$AbsPath}}))
5824 {
5825 if($GlibcHeader{get_filename($Dep)} and keys(%{$Header_Include_Prefix{$LibVersion}{$AbsPath}{$Dep}})>=2
5826 and defined $Header_Include_Prefix{$LibVersion}{$AbsPath}{$Dep}{""})
5827 { # distinguish math.h from glibc and math.h from the tested library
5828 delete($Header_Include_Prefix{$LibVersion}{$AbsPath}{$Dep}{""});
5829 last;
5830 }
5831 }
5832 }
5833 pop(@RecurInclude);
5834 return keys(%{$RecursiveIncludes{$LibVersion}{$AbsPath}});
5835}
5836
5837sub find_in_framework($$$)
5838{
5839 my ($Header, $Framework, $LibVersion) = @_;
5840 return "" if(not $Header or not $Framework or not $LibVersion);
5841 if(defined $Cache{"find_in_framework"}{$LibVersion}{$Framework}{$Header}) {
5842 return $Cache{"find_in_framework"}{$LibVersion}{$Framework}{$Header};
5843 }
5844 foreach my $Dependency (sort {get_depth($a)<=>get_depth($b)} keys(%{$Header_Dependency{$LibVersion}}))
5845 {
5846 if(get_filename($Dependency) eq $Framework
5847 and -f get_dirname($Dependency)."/".$Header) {
5848 return ($Cache{"find_in_framework"}{$LibVersion}{$Framework}{$Header} = get_dirname($Dependency));
5849 }
5850 }
5851 return ($Cache{"find_in_framework"}{$LibVersion}{$Framework}{$Header} = "");
5852}
5853
5854sub find_in_defaults($)
5855{
5856 my $Header = $_[0];
5857 return "" if(not $Header);
5858 if(defined $Cache{"find_in_defaults"}{$Header}) {
5859 return $Cache{"find_in_defaults"}{$Header};
5860 }
5861 foreach my $Dir (sort {get_depth($a)<=>get_depth($b)}
5862 (keys(%DefaultIncPaths), keys(%DefaultGccPaths), keys(%DefaultCppPaths), keys(%UserIncPath)))
5863 {
5864 next if(not $Dir);
5865 if(-f $Dir."/".$Header) {
5866 return ($Cache{"find_in_defaults"}{$Header}=$Dir);
5867 }
5868 }
5869 return ($Cache{"find_in_defaults"}{$Header}="");
5870}
5871
5872sub cmp_paths($$)
5873{
5874 my ($Path1, $Path2) = @_;
5875 my @Parts1 = split(/[\/\\]/, $Path1);
5876 my @Parts2 = split(/[\/\\]/, $Path2);
5877 foreach my $Num (0 .. $#Parts1)
5878 {
5879 my $Part1 = $Parts1[$Num];
5880 my $Part2 = $Parts2[$Num];
5881 if($GlibcDir{$Part1}
5882 and not $GlibcDir{$Part2}) {
5883 return 1;
5884 }
5885 elsif($GlibcDir{$Part2}
5886 and not $GlibcDir{$Part1}) {
5887 return -1;
5888 }
5889 elsif($Part1=~/glib/
5890 and $Part2!~/glib/) {
5891 return 1;
5892 }
5893 elsif($Part1!~/glib/
5894 and $Part2=~/glib/) {
5895 return -1;
5896 }
5897 elsif(my $CmpRes = ($Part1 cmp $Part2)) {
5898 return $CmpRes;
5899 }
5900 }
5901 return 0;
5902}
5903
5904sub checkRelevance($)
5905{
5906 my ($Path) = @_;
5907 return 0 if(not $Path);
5908 if($SystemRoot) {
5909 $Path=~s/\A\Q$SystemRoot\E//g;
5910 }
5911 my ($Dir, $Name) = separate_path($Path);
5912 $Name=~s/\.\w+\Z//g;# remove extension (.h)
5913 my @Tokens = split(/[_\d\W]+/, $Name);
5914 foreach (@Tokens)
5915 {
5916 next if(not $_);
5917 if($Dir=~/(\A|lib|[_\d\W])\Q$_\E([_\d\W]|lib|\Z)/i
5918 or length($_)>=4 and $Dir=~/\Q$_\E/i)
5919 { # include/gupnp-1.0/libgupnp/gupnp-context.h
5920 # include/evolution-data-server-1.4/libebook/e-book.h
5921 return 1;
5922 }
5923 }
5924 return 0;
5925}
5926
5927sub checkFamily(@)
5928{
5929 my @Paths = @_;
5930 return 1 if($#Paths<=0);
5931 my %Prefix = ();
5932 foreach my $Path (@Paths)
5933 {
5934 if($SystemRoot) {
5935 $Path = cut_path_prefix($Path, $SystemRoot);
5936 }
5937 if(my $Dir = get_dirname($Path))
5938 {
5939 $Dir=~s/(\/[^\/]+?)[\d\.\-\_]+\Z/$1/g; # remove version suffix
5940 $Prefix{$Dir} += 1;
5941 $Prefix{get_dirname($Dir)} += 1;
5942 }
5943 }
5944 foreach (sort keys(%Prefix))
5945 {
5946 if(get_depth($_)>=3
5947 and $Prefix{$_}==$#Paths+1) {
5948 return 1;
5949 }
5950 }
5951 return 0;
5952}
5953
5954sub isAcceptable($$$)
5955{
5956 my ($Header, $Candidate, $LibVersion) = @_;
5957 my $HName = get_filename($Header);
5958 if(get_dirname($Header))
5959 { # with prefix
5960 return 1;
5961 }
5962 if($HName=~/config|setup/i and $Candidate=~/[\/\\]lib\d*[\/\\]/)
5963 { # allow to search for glibconfig.h in /usr/lib/glib-2.0/include/
5964 return 1;
5965 }
5966 if(checkRelevance($Candidate))
5967 { # allow to search for atk.h in /usr/include/atk-1.0/atk/
5968 return 1;
5969 }
5970 if(checkFamily(getSystemHeaders($HName, $LibVersion)))
5971 { # /usr/include/qt4/QtNetwork/qsslconfiguration.h
5972 # /usr/include/qt4/Qt/qsslconfiguration.h
5973 return 1;
5974 }
5975 if($OStarget eq "symbian")
5976 {
5977 if($Candidate=~/[\/\\]stdapis[\/\\]/) {
5978 return 1;
5979 }
5980 }
5981 return 0;
5982}
5983
5984sub isRelevant($$$)
5985{ # disallow to search for "abstract" headers in too deep directories
5986 my ($Header, $Candidate, $LibVersion) = @_;
5987 my $HName = get_filename($Header);
5988 if($OStarget eq "symbian")
5989 {
5990 if($Candidate=~/[\/\\](tools|stlportv5)[\/\\]/) {
5991 return 0;
5992 }
5993 }
5994 if($OStarget ne "bsd") {
5995 if($Candidate=~/[\/\\]include[\/\\]bsd[\/\\]/)
5996 { # openssh: skip /usr/lib/bcc/include/bsd/signal.h
5997 return 0;
5998 }
5999 }
6000 if(not get_dirname($Header)
6001 and $Candidate=~/[\/\\]wx[\/\\]/)
6002 { # do NOT search in system /wx/ directory
6003 # for headers without a prefix: sstream.h
6004 return 0;
6005 }
6006 if($Candidate=~/c\+\+[\/\\]\d+/ and $MAIN_CPP_DIR
6007 and $Candidate!~/\A\Q$MAIN_CPP_DIR\E/)
6008 { # skip ../c++/3.3.3/ if using ../c++/4.5/
6009 return 0;
6010 }
6011 if($Candidate=~/[\/\\]asm-/
6012 and (my $Arch = getArch($LibVersion)) ne "unknown")
6013 { # arch-specific header files
6014 if($Candidate!~/[\/\\]asm-\Q$Arch\E/)
6015 {# skip ../asm-arm/ if using x86 architecture
6016 return 0;
6017 }
6018 }
6019 my @Candidates = getSystemHeaders($HName, $LibVersion);
6020 if($#Candidates==1)
6021 { # unique header
6022 return 1;
6023 }
6024 my @SCandidates = getSystemHeaders($Header, $LibVersion);
6025 if($#SCandidates==1)
6026 { # unique name
6027 return 1;
6028 }
6029 my $SystemDepth = $SystemRoot?get_depth($SystemRoot):0;
6030 if(get_depth($Candidate)-$SystemDepth>=5)
6031 { # abstract headers in too deep directories
6032 # sstream.h or typeinfo.h in /usr/include/wx-2.9/wx/
6033 if(not isAcceptable($Header, $Candidate, $LibVersion)) {
6034 return 0;
6035 }
6036 }
6037 if($Header eq "parser.h"
6038 and $Candidate!~/\/libxml2\//)
6039 { # select parser.h from xml2 library
6040 return 0;
6041 }
6042 if(not get_dirname($Header)
6043 and keys(%{$SystemHeaders{$HName}})>=3)
6044 { # many headers with the same name
6045 # like thread.h included without a prefix
6046 if(not checkFamily(@Candidates)) {
6047 return 0;
6048 }
6049 }
6050 return 1;
6051}
6052
6053sub selectSystemHeader($$)
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04006054{ # cache function
6055 if(defined $Cache{"selectSystemHeader"}{$_[1]}{$_[0]}) {
6056 return $Cache{"selectSystemHeader"}{$_[1]}{$_[0]};
6057 }
6058 return ($Cache{"selectSystemHeader"}{$_[1]}{$_[0]} = selectSystemHeader_I(@_));
6059}
6060
6061sub selectSystemHeader_I($$)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006062{
6063 my ($Header, $LibVersion) = @_;
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04006064 if(-f $Header) {
6065 return $Header;
6066 }
6067 if(is_abs($Header) and not -f $Header)
6068 { # incorrect absolute path
6069 return "";
6070 }
6071 if($Header=~/\A(atomic|config|configure|build|conf|setup)\.h\Z/i)
6072 { # too abstract configuration headers
6073 return "";
6074 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006075 if($OSgroup ne "windows")
6076 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04006077 if(get_filename($Header)=~/windows|win32|win64|\A(dos|process|winsock|config-win)\.h\Z/i)
6078 { # windows headers
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006079 return "";
6080 }
6081 elsif($Header=~/\A(mem)\.h\Z/)
6082 { # pngconf.h include mem.h for __MSDOS__
6083 return "";
6084 }
6085 }
6086 if($OSgroup ne "solaris")
6087 {
6088 if($Header=~/\A(thread)\.h\Z/)
6089 { # thread.h in Solaris
6090 return "";
6091 }
6092 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04006093
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006094 foreach my $Path (keys(%{$SystemPaths{"include"}}))
6095 { # search in default paths
6096 if(-f $Path."/".$Header) {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04006097 return joinPath($Path,$Header);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006098 }
6099 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04006100 if(not keys(%SystemHeaders))
6101 { # register all headers in system include dirs
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006102 detectSystemHeaders();
6103 }
6104 foreach my $Candidate (sort {get_depth($a)<=>get_depth($b)}
6105 sort {cmp_paths($b, $a)} getSystemHeaders($Header, $LibVersion))
6106 {
6107 if(isRelevant($Header, $Candidate, $LibVersion)) {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04006108 return $Candidate;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006109 }
6110 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04006111 # error
6112 return "";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006113}
6114
6115sub getSystemHeaders($$)
6116{
6117 my ($Header, $LibVersion) = @_;
6118 my @Candidates = ();
6119 foreach my $Candidate (sort keys(%{$SystemHeaders{$Header}}))
6120 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04006121 if(skipHeader($Candidate, $LibVersion)) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006122 next;
6123 }
6124 push(@Candidates, $Candidate);
6125 }
6126 return @Candidates;
6127}
6128
6129sub cut_path_prefix($$)
6130{
6131 my ($Path, $Prefix) = @_;
6132 return $Path if(not $Prefix);
6133 $Prefix=~s/[\/\\]+\Z//;
6134 $Path=~s/\A\Q$Prefix\E([\/\\]+|\Z)//;
6135 return $Path;
6136}
6137
6138sub is_default_include_dir($)
6139{
6140 my $Dir = $_[0];
6141 $Dir=~s/[\/\\]+\Z//;
6142 return ($DefaultGccPaths{$Dir} or $DefaultCppPaths{$Dir} or $DefaultIncPaths{$Dir});
6143}
6144
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04006145sub identifyHeader($$)
6146{ # cache function
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006147 my ($Header, $LibVersion) = @_;
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04006148 if(not $Header) {
6149 return "";
6150 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006151 $Header=~s/\A(\.\.[\\\/])+//g;
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04006152 if(defined $Cache{"identifyHeader"}{$LibVersion}{$Header}) {
6153 return $Cache{"identifyHeader"}{$LibVersion}{$Header};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006154 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04006155 return ($Cache{"identifyHeader"}{$LibVersion}{$Header} = identifyHeader_I($Header, $LibVersion));
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006156}
6157
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04006158sub identifyHeader_I($$)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006159{ # search for header by absolute path, relative path or name
6160 my ($Header, $LibVersion) = @_;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006161 if(-f $Header)
6162 { # it's relative or absolute path
6163 return get_abs_path($Header);
6164 }
6165 elsif($GlibcHeader{$Header} and not $GLIBC_TESTING
6166 and my $HeaderDir = find_in_defaults($Header))
6167 { # search for libc headers in the /usr/include
6168 # for non-libc target library before searching
6169 # in the library paths
6170 return joinPath($HeaderDir,$Header);
6171 }
6172 elsif(my $Path = $Include_Neighbors{$LibVersion}{$Header})
6173 { # search in the target library paths
6174 return $Path;
6175 }
6176 elsif($DefaultGccHeader{$Header})
6177 { # search in the internal GCC include paths
6178 return $DefaultGccHeader{$Header};
6179 }
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04006180 elsif(my $DefaultDir = find_in_defaults($Header))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006181 { # search in the default GCC include paths
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04006182 return joinPath($DefaultDir,$Header);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006183 }
6184 elsif($DefaultCppHeader{$Header})
6185 { # search in the default G++ include paths
6186 return $DefaultCppHeader{$Header};
6187 }
6188 elsif(my $AnyPath = selectSystemHeader($Header, $LibVersion))
6189 { # search everywhere in the system
6190 return $AnyPath;
6191 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04006192 elsif($OSgroup eq "macos")
6193 { # search in frameworks: "OpenGL/gl.h" is "OpenGL.framework/Headers/gl.h"
6194 if(my $Dir = get_dirname($Header))
6195 {
6196 my $RelPath = "Headers\/".get_filename($Header);
6197 if(my $HeaderDir = find_in_framework($RelPath, $Dir.".framework", $LibVersion)) {
6198 return joinPath($HeaderDir, $RelPath);
6199 }
6200 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006201 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04006202 # cannot find anything
6203 return "";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006204}
6205
6206sub getLocation($)
6207{
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04006208 if($_[0] and my $Info = $LibInfo{$Version}{"info"}{$_[0]})
6209 {
6210 if($Info=~/srcp[ ]*:[ ]*([\w\-\<\>\.\+\/\\]+):(\d+) /) {
6211 return ($1, $2);
6212 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006213 }
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04006214 return ();
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006215}
6216
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006217sub getNameByInfo($)
6218{
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04006219 if($_[0] and my $Info = $LibInfo{$Version}{"info"}{$_[0]})
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04006220 {
6221 if($Info=~/name[ ]*:[ ]*@(\d+) /)
6222 {
6223 if(my $NInfo = $LibInfo{$Version}{"info"}{$1})
6224 {
6225 if($NInfo=~/strg[ ]*:[ ]*(.*?)[ ]+lngt/)
6226 { # short unsigned int (may include spaces)
6227 return $1;
6228 }
6229 }
6230 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006231 }
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04006232 return "";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006233}
6234
6235sub getTreeStr($)
6236{
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04006237 if($_[0] and my $Info = $LibInfo{$Version}{"info"}{$_[0]})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006238 {
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04006239 if($Info=~/strg[ ]*:[ ]*([^ ]*)/)
6240 {
6241 my $Str = $1;
6242 if($C99Mode{$Version}
6243 and $Str=~/\Ac99_(.+)\Z/) {
6244 if($CppKeywords_A{$1}) {
6245 $Str=$1;
6246 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006247 }
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04006248 return $Str;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006249 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006250 }
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04006251 return "";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006252}
6253
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006254sub getFuncShortName($)
6255{
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04006256 if(my $Info = $LibInfo{$Version}{"info"}{$_[0]})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006257 {
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04006258 if($Info=~/ operator /)
6259 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04006260 if($Info=~/ conversion /)
6261 {
6262 if(my $Rid = $SymbolInfo{$Version}{$_[0]}{"Return"})
6263 {
6264 if(my $RName = $TypeInfo{$Version}{$Rid}{"Name"}) {
6265 return "operator ".$RName;
6266 }
6267 }
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04006268 }
6269 else
6270 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04006271 if($Info=~/ operator[ ]+([a-zA-Z]+) /)
6272 {
6273 if(my $Ind = $Operator_Indication{$1}) {
6274 return "operator".$Ind;
6275 }
6276 elsif(not $UnknownOperator{$1})
6277 {
6278 printMsg("WARNING", "unknown operator $1");
6279 $UnknownOperator{$1} = 1;
6280 }
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04006281 }
6282 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006283 }
6284 else
6285 {
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04006286 if($Info=~/name[ ]*:[ ]*@(\d+) /) {
6287 return getTreeStr($1);
6288 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006289 }
6290 }
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04006291 return "";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006292}
6293
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006294sub getFuncReturn($)
6295{
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04006296 if($_[0] and my $Info = $LibInfo{$Version}{"info"}{$_[0]})
6297 {
6298 if($Info=~/type[ ]*:[ ]*@(\d+) /)
6299 {
6300 if($LibInfo{$Version}{"info"}{$1}=~/retn[ ]*:[ ]*@(\d+) /) {
6301 return $1;
6302 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006303 }
6304 }
6305 return "";
6306}
6307
6308sub getFuncOrig($)
6309{
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04006310 if($_[0] and my $Info = $LibInfo{$Version}{"info"}{$_[0]})
6311 {
6312 if($Info=~/orig[ ]*:[ ]*@(\d+) /) {
6313 return $1;
6314 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006315 }
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04006316 return $_[0];
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006317}
6318
6319sub unmangleSymbol($)
6320{
6321 my $Symbol = $_[0];
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04006322 if(my @Unmngl = unmangleArray($Symbol)) {
6323 return $Unmngl[0];
6324 }
6325 return "";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006326}
6327
6328sub unmangleArray(@)
6329{
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04006330 if($_[0]=~/\A\?/)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006331 { # MSVC mangling
6332 my $UndNameCmd = get_CmdPath("undname");
6333 if(not $UndNameCmd) {
6334 exitStatus("Not_Found", "can't find \"undname\"");
6335 }
6336 writeFile("$TMP_DIR/unmangle", join("\n", @_));
6337 return split(/\n/, `$UndNameCmd 0x8386 $TMP_DIR/unmangle`);
6338 }
6339 else
6340 { # GCC mangling
6341 my $CppFiltCmd = get_CmdPath("c++filt");
6342 if(not $CppFiltCmd) {
6343 exitStatus("Not_Found", "can't find c++filt in PATH");
6344 }
6345 my $Info = `$CppFiltCmd -h 2>&1`;
6346 if($Info=~/\@<file>/)
6347 {# new version of c++filt can take a file
6348 my $NoStrip = "";
6349 if($OSgroup eq "macos"
6350 or $OSgroup eq "windows") {
6351 $NoStrip = "-n";
6352 }
6353 writeFile("$TMP_DIR/unmangle", join("\n", @_));
6354 return split(/\n/, `$CppFiltCmd $NoStrip \@\"$TMP_DIR/unmangle\"`);
6355 }
6356 else
6357 { # old-style unmangling
6358 if($#_>$MAX_COMMAND_LINE_ARGUMENTS) {
6359 my @Half = splice(@_, 0, ($#_+1)/2);
6360 return (unmangleArray(@Half), unmangleArray(@_))
6361 }
6362 else
6363 {
6364 my $NoStrip = "";
6365 if($OSgroup eq "macos"
6366 or $OSgroup eq "windows") {
6367 $NoStrip = "-n";
6368 }
6369 my $Strings = join(" ", @_);
6370 return split(/\n/, `$CppFiltCmd $NoStrip $Strings`);
6371 }
6372 }
6373 }
6374}
6375
6376sub get_SignatureNoInfo($$)
6377{
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04006378 my ($Symbol, $LibVersion) = @_;
6379 if($Cache{"get_SignatureNoInfo"}{$LibVersion}{$Symbol}) {
6380 return $Cache{"get_SignatureNoInfo"}{$LibVersion}{$Symbol};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006381 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04006382 my ($MnglName, $VersionSpec, $SymbolVersion) = separate_symbol($Symbol);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006383 my $Signature = $tr_name{$MnglName}?$tr_name{$MnglName}:$MnglName;
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04006384 if($Symbol=~/\A(_Z|\?)/)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006385 { # C++
6386 $Signature=~s/\Qstd::basic_string<char, std::char_traits<char>, std::allocator<char> >\E/std::string/g;
6387 $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;
6388 }
6389 if(not $CheckObjectsOnly or $OSgroup=~/linux|bsd|beos/)
6390 { # ELF format marks data as OBJECT
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04006391 if($GlobalDataObject{$LibVersion}{$Symbol}) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006392 $Signature .= " [data]";
6393 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04006394 elsif($Symbol!~/\A(_Z|\?)/) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006395 $Signature .= " (...)";
6396 }
6397 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04006398 if(my $ChargeLevel = get_ChargeLevel($Symbol, $LibVersion))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006399 {
Andrey Ponomarenko16934472012-03-29 15:37:04 +04006400 my $ShortName = substr($Signature, 0, find_center($Signature, "("));
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006401 $Signature=~s/\A\Q$ShortName\E/$ShortName $ChargeLevel/g;
6402 }
6403 if($SymbolVersion) {
6404 $Signature .= $VersionSpec.$SymbolVersion;
6405 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04006406 return ($Cache{"get_SignatureNoInfo"}{$LibVersion}{$Symbol} = $Signature);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006407}
6408
6409sub get_ChargeLevel($$)
6410{
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04006411 my ($Symbol, $LibVersion) = @_;
6412 return "" if($Symbol!~/\A(_Z|\?)/);
6413 if(defined $CompleteSignature{$LibVersion}{$Symbol}
6414 and $CompleteSignature{$LibVersion}{$Symbol}{"Header"})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006415 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04006416 if($CompleteSignature{$LibVersion}{$Symbol}{"Constructor"})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006417 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04006418 if($Symbol=~/C1E/) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006419 return "[in-charge]";
6420 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04006421 elsif($Symbol=~/C2E/) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006422 return "[not-in-charge]";
6423 }
6424 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04006425 elsif($CompleteSignature{$LibVersion}{$Symbol}{"Destructor"})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006426 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04006427 if($Symbol=~/D1E/) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006428 return "[in-charge]";
6429 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04006430 elsif($Symbol=~/D2E/) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006431 return "[not-in-charge]";
6432 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04006433 elsif($Symbol=~/D0E/) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006434 return "[in-charge-deleting]";
6435 }
6436 }
6437 }
6438 else
6439 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04006440 if($Symbol=~/C1E/) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006441 return "[in-charge]";
6442 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04006443 elsif($Symbol=~/C2E/) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006444 return "[not-in-charge]";
6445 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04006446 elsif($Symbol=~/D1E/) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006447 return "[in-charge]";
6448 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04006449 elsif($Symbol=~/D2E/) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006450 return "[not-in-charge]";
6451 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04006452 elsif($Symbol=~/D0E/) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006453 return "[in-charge-deleting]";
6454 }
6455 }
6456 return "";
6457}
6458
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04006459sub get_Signature_M($$)
6460{
6461 my ($Symbol, $LibVersion) = @_;
6462 my $Signature_M = $tr_name{$Symbol};
6463 if(my $RTid = $CompleteSignature{$LibVersion}{$Symbol}{"Return"})
6464 { # add return type name
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04006465 $Signature_M = $TypeInfo{$LibVersion}{$RTid}{"Name"}." ".$Signature_M;
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04006466 }
6467 return $Signature_M;
6468}
6469
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006470sub get_Signature($$)
6471{
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04006472 my ($Symbol, $LibVersion) = @_;
6473 if($Cache{"get_Signature"}{$LibVersion}{$Symbol}) {
6474 return $Cache{"get_Signature"}{$LibVersion}{$Symbol};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006475 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04006476 my ($MnglName, $VersionSpec, $SymbolVersion) = separate_symbol($Symbol);
6477 if(isPrivateData($MnglName) or not $CompleteSignature{$LibVersion}{$Symbol}{"Header"})
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04006478 { # non-public global data
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04006479 return get_SignatureNoInfo($Symbol, $LibVersion);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006480 }
6481 my ($Func_Signature, @Param_Types_FromUnmangledName) = ();
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04006482 my $ShortName = $CompleteSignature{$LibVersion}{$Symbol}{"ShortName"};
6483 if($Symbol=~/\A(_Z|\?)/)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006484 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04006485 if(my $ClassId = $CompleteSignature{$LibVersion}{$Symbol}{"Class"}) {
6486 $Func_Signature = $TypeInfo{$LibVersion}{$ClassId}{"Name"}."::".(($CompleteSignature{$LibVersion}{$Symbol}{"Destructor"})?"~":"").$ShortName;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006487 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04006488 elsif(my $NameSpace = $CompleteSignature{$LibVersion}{$Symbol}{"NameSpace"}) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006489 $Func_Signature = $NameSpace."::".$ShortName;
6490 }
6491 else {
6492 $Func_Signature = $ShortName;
6493 }
6494 @Param_Types_FromUnmangledName = get_s_params($tr_name{$MnglName}, 0);
6495 }
6496 else {
6497 $Func_Signature = $MnglName;
6498 }
6499 my @ParamArray = ();
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04006500 foreach my $Pos (sort {int($a) <=> int($b)} keys(%{$CompleteSignature{$LibVersion}{$Symbol}{"Param"}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006501 {
6502 next if($Pos eq "");
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04006503 my $ParamTypeId = $CompleteSignature{$LibVersion}{$Symbol}{"Param"}{$Pos}{"type"};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006504 next if(not $ParamTypeId);
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04006505 my $ParamTypeName = $TypeInfo{$LibVersion}{$ParamTypeId}{"Name"};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006506 if(not $ParamTypeName) {
6507 $ParamTypeName = $Param_Types_FromUnmangledName[$Pos];
6508 }
6509 foreach my $Typedef (keys(%ChangedTypedef))
6510 {
6511 my $Base = $Typedef_BaseName{$LibVersion}{$Typedef};
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04006512 $ParamTypeName=~s/\b\Q$Typedef\E\b/$Base/g;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006513 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04006514 if(my $ParamName = $CompleteSignature{$LibVersion}{$Symbol}{"Param"}{$Pos}{"name"}) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006515 push(@ParamArray, create_member_decl($ParamTypeName, $ParamName));
6516 }
6517 else {
6518 push(@ParamArray, $ParamTypeName);
6519 }
6520 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04006521 if($CompleteSignature{$LibVersion}{$Symbol}{"Data"}
6522 or $GlobalDataObject{$LibVersion}{$Symbol}) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006523 $Func_Signature .= " [data]";
6524 }
6525 else
6526 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04006527 if(my $ChargeLevel = get_ChargeLevel($Symbol, $LibVersion))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006528 { # add [in-charge]
6529 $Func_Signature .= " ".$ChargeLevel;
6530 }
6531 $Func_Signature .= " (".join(", ", @ParamArray).")";
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04006532 if($CompleteSignature{$LibVersion}{$Symbol}{"Const"}
6533 or $Symbol=~/\A_ZN(V|)K/) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006534 $Func_Signature .= " const";
6535 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04006536 if($CompleteSignature{$LibVersion}{$Symbol}{"Volatile"}
6537 or $Symbol=~/\A_ZN(K|)V/) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006538 $Func_Signature .= " volatile";
6539 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04006540 if($CompleteSignature{$LibVersion}{$Symbol}{"Static"}
6541 and $Symbol=~/\A(_Z|\?)/)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006542 {# for static methods
6543 $Func_Signature .= " [static]";
6544 }
6545 }
6546 if(defined $ShowRetVal
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04006547 and my $ReturnTId = $CompleteSignature{$LibVersion}{$Symbol}{"Return"}) {
6548 $Func_Signature .= ":".$TypeInfo{$LibVersion}{$ReturnTId}{"Name"};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006549 }
6550 if($SymbolVersion) {
6551 $Func_Signature .= $VersionSpec.$SymbolVersion;
6552 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04006553 return ($Cache{"get_Signature"}{$LibVersion}{$Symbol} = $Func_Signature);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006554}
6555
6556sub create_member_decl($$)
6557{
6558 my ($TName, $Member) = @_;
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04006559 if($TName=~/\([\*]+\)/)
6560 {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006561 $TName=~s/\(([\*]+)\)/\($1$Member\)/;
6562 return $TName;
6563 }
6564 else
6565 {
6566 my @ArraySizes = ();
6567 while($TName=~s/(\[[^\[\]]*\])\Z//) {
6568 push(@ArraySizes, $1);
6569 }
6570 return $TName." ".$Member.join("", @ArraySizes);
6571 }
6572}
6573
6574sub getFuncType($)
6575{
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04006576 if($_[0] and my $Info = $LibInfo{$Version}{"info"}{$_[0]})
6577 {
6578 if($Info=~/type[ ]*:[ ]*@(\d+) /)
6579 {
6580 if(my $Type = $LibInfo{$Version}{"info_type"}{$1})
6581 {
6582 if($Type eq "method_type") {
6583 return "Method";
6584 }
6585 elsif($Type eq "function_type") {
6586 return "Function";
6587 }
6588 else {
6589 return "Other";
6590 }
6591 }
6592 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006593 }
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04006594 return ""
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006595}
6596
6597sub getFuncTypeId($)
6598{
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04006599 if($_[0] and my $Info = $LibInfo{$Version}{"info"}{$_[0]})
6600 {
6601 if($Info=~/type[ ]*:[ ]*@(\d+)( |\Z)/) {
6602 return $1;
6603 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006604 }
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04006605 return 0;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006606}
6607
6608sub isNotAnon($) {
6609 return (not isAnon($_[0]));
6610}
6611
6612sub isAnon($)
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04006613{ # "._N" or "$_N" in older GCC versions
6614 return ($_[0] and $_[0]=~/(\.|\$)\_\d+|anon\-/);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006615}
6616
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006617sub formatName($)
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04006618{ # type name correction
6619 if(defined $Cache{"formatName"}{$_[0]}) {
6620 return $Cache{"formatName"}{$_[0]};
6621 }
6622
6623 $_ = $_[0];
6624
6625 s/\A[ ]+|[ ]+\Z//g;
6626 s/[ ]{2,}/ /g;
6627 s/[ ]*(\W)[ ]*/$1/g;
6628
6629 s/\bvolatile const\b/const volatile/g;
6630
6631 s/\b(long long|short|long) unsigned\b/unsigned $1/g;
6632 s/\b(short|long) int\b/$1/g;
6633
6634 s/([\)\]])(const|volatile)\b/$1 $2/g;
6635
6636 while(s/>>/> >/g) {};
6637
6638 s/\b(operator[ ]*)> >/$1>>/;
6639
6640 return ($Cache{"formatName"}{$_[0]}=$_);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006641}
6642
6643sub get_HeaderDeps($$)
6644{
6645 my ($AbsPath, $LibVersion) = @_;
6646 return () if(not $AbsPath or not $LibVersion);
6647 if(defined $Cache{"get_HeaderDeps"}{$LibVersion}{$AbsPath}) {
6648 return @{$Cache{"get_HeaderDeps"}{$LibVersion}{$AbsPath}};
6649 }
6650 my %IncDir = ();
6651 detect_recursive_includes($AbsPath, $LibVersion);
6652 foreach my $HeaderPath (keys(%{$RecursiveIncludes{$LibVersion}{$AbsPath}}))
6653 {
6654 next if(not $HeaderPath);
6655 next if($MAIN_CPP_DIR and $HeaderPath=~/\A\Q$MAIN_CPP_DIR\E([\/\\]|\Z)/);
6656 my $Dir = get_dirname($HeaderPath);
6657 foreach my $Prefix (keys(%{$Header_Include_Prefix{$LibVersion}{$AbsPath}{$HeaderPath}}))
6658 {
6659 my $Dep = $Dir;
6660 if($Prefix)
6661 {
6662 if($OSgroup eq "windows")
6663 { # case insensitive seach on windows
6664 if(not $Dep=~s/[\/\\]+\Q$Prefix\E\Z//ig) {
6665 next;
6666 }
6667 }
6668 elsif($OSgroup eq "macos")
6669 { # seach in frameworks
6670 if(not $Dep=~s/[\/\\]+\Q$Prefix\E\Z//g)
6671 {
6672 if($HeaderPath=~/(.+\.framework)\/Headers\/([^\/]+)/)
6673 {# frameworks
6674 my ($HFramework, $HName) = ($1, $2);
6675 $Dep = $HFramework;
6676 }
6677 else
6678 {# mismatch
6679 next;
6680 }
6681 }
6682 }
6683 elsif(not $Dep=~s/[\/\\]+\Q$Prefix\E\Z//g)
6684 { # Linux, FreeBSD
6685 next;
6686 }
6687 }
6688 if(not $Dep)
6689 { # nothing to include
6690 next;
6691 }
6692 if(is_default_include_dir($Dep))
6693 { # included by the compiler
6694 next;
6695 }
6696 if(get_depth($Dep)==1)
6697 { # too short
6698 next;
6699 }
6700 if(isLibcDir($Dep))
6701 { # do NOT include /usr/include/{sys,bits}
6702 next;
6703 }
6704 $IncDir{$Dep}=1;
6705 }
6706 }
6707 $Cache{"get_HeaderDeps"}{$LibVersion}{$AbsPath} = sortIncPaths([keys(%IncDir)], $LibVersion);
6708 return @{$Cache{"get_HeaderDeps"}{$LibVersion}{$AbsPath}};
6709}
6710
6711sub sortIncPaths($$)
6712{
6713 my ($ArrRef, $LibVersion) = @_;
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04006714 if(not $ArrRef or $#{$ArrRef}<0) {
6715 return $ArrRef;
6716 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006717 @{$ArrRef} = sort {$b cmp $a} @{$ArrRef};
6718 @{$ArrRef} = sort {get_depth($a)<=>get_depth($b)} @{$ArrRef};
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04006719 @{$ArrRef} = sort {sortDeps($b, $a, $LibVersion)} @{$ArrRef};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006720 return $ArrRef;
6721}
6722
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04006723sub sortDeps($$$)
6724{
6725 if($Header_Dependency{$_[2]}{$_[0]}
6726 and not $Header_Dependency{$_[2]}{$_[1]}) {
6727 return 1;
6728 }
6729 elsif(not $Header_Dependency{$_[2]}{$_[0]}
6730 and $Header_Dependency{$_[2]}{$_[1]}) {
6731 return -1;
6732 }
6733 return 0;
6734}
6735
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006736sub joinPath($$) {
6737 return join($SLASH, @_);
6738}
6739
6740sub get_namespace_additions($)
6741{
6742 my $NameSpaces = $_[0];
6743 my ($Additions, $AddNameSpaceId) = ("", 1);
6744 foreach my $NS (sort {$a=~/_/ <=> $b=~/_/} sort {lc($a) cmp lc($b)} keys(%{$NameSpaces}))
6745 {
6746 next if($SkipNameSpaces{$Version}{$NS});
6747 next if(not $NS or $NameSpaces->{$NS}==-1);
6748 next if($NS=~/(\A|::)iterator(::|\Z)/i);
6749 next if($NS=~/\A__/i);
6750 next if(($NS=~/\Astd::/ or $NS=~/\A(std|tr1|rel_ops|fcntl)\Z/) and not $STDCXX_TESTING);
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04006751 $NestedNameSpaces{$Version}{$NS} = 1; # for future use in reports
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006752 my ($TypeDecl_Prefix, $TypeDecl_Suffix) = ();
6753 my @NS_Parts = split(/::/, $NS);
6754 next if($#NS_Parts==-1);
6755 next if($NS_Parts[0]=~/\A(random|or)\Z/);
6756 foreach my $NS_Part (@NS_Parts)
6757 {
6758 $TypeDecl_Prefix .= "namespace $NS_Part\{";
6759 $TypeDecl_Suffix .= "}";
6760 }
6761 my $TypeDecl = $TypeDecl_Prefix."typedef int tmp_add_type_$AddNameSpaceId;".$TypeDecl_Suffix;
6762 my $FuncDecl = "$NS\:\:tmp_add_type_$AddNameSpaceId tmp_add_func_$AddNameSpaceId(){return 0;};";
6763 $Additions.=" $TypeDecl\n $FuncDecl\n";
6764 $AddNameSpaceId+=1;
6765 }
6766 return $Additions;
6767}
6768
6769sub path_format($$)
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04006770{ # forward slash to pass into MinGW GCC
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006771 my ($Path, $Fmt) = @_;
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04006772 if($Fmt eq "windows")
6773 {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006774 $Path=~s/\//\\/g;
6775 $Path=lc($Path);
6776 }
6777 else {
6778 $Path=~s/\\/\//g;
6779 }
6780 return $Path;
6781}
6782
6783sub inc_opt($$)
6784{
6785 my ($Path, $Style) = @_;
6786 if($Style eq "GCC")
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04006787 { # GCC options
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006788 if($OSgroup eq "windows")
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04006789 { # to MinGW GCC
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006790 return "-I\"".path_format($Path, "unix")."\"";
6791 }
6792 elsif($OSgroup eq "macos"
6793 and $Path=~/\.framework\Z/)
6794 {# to Apple's GCC
6795 return "-F".esc(get_dirname($Path));
6796 }
6797 else {
6798 return "-I".esc($Path);
6799 }
6800 }
6801 elsif($Style eq "CL") {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04006802 return "/I \"".$Path."\"";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006803 }
6804 return "";
6805}
6806
6807sub platformSpecs($)
6808{
6809 my $LibVersion = $_[0];
6810 my $Arch = getArch($LibVersion);
6811 if($OStarget eq "symbian")
6812 { # options for GCCE compiler
6813 my %Symbian_Opts = map {$_=>1} (
6814 "-D__GCCE__",
6815 "-DUNICODE",
6816 "-fexceptions",
6817 "-D__SYMBIAN32__",
6818 "-D__MARM_INTERWORK__",
6819 "-D_UNICODE",
6820 "-D__S60_50__",
6821 "-D__S60_3X__",
6822 "-D__SERIES60_3X__",
6823 "-D__EPOC32__",
6824 "-D__MARM__",
6825 "-D__EABI__",
6826 "-D__MARM_ARMV5__",
6827 "-D__SUPPORT_CPP_EXCEPTIONS__",
6828 "-march=armv5t",
6829 "-mapcs",
6830 "-mthumb-interwork",
6831 "-DEKA2",
6832 "-DSYMBIAN_ENABLE_SPLIT_HEADERS"
6833 );
6834 return join(" ", keys(%Symbian_Opts));
6835 }
6836 elsif($OSgroup eq "windows"
6837 and get_dumpmachine($GCC_PATH)=~/mingw/i)
6838 { # add options to MinGW compiler
6839 # to simulate the MSVC compiler
6840 my %MinGW_Opts = map {$_=>1} (
6841 "-D_WIN32",
6842 "-D_STDCALL_SUPPORTED",
6843 "-D__int64=\"long long\"",
6844 "-D__int32=int",
6845 "-D__int16=short",
6846 "-D__int8=char",
6847 "-D__possibly_notnullterminated=\" \"",
6848 "-D__nullterminated=\" \"",
6849 "-D__nullnullterminated=\" \"",
6850 "-D__w64=\" \"",
6851 "-D__ptr32=\" \"",
6852 "-D__ptr64=\" \"",
6853 "-D__forceinline=inline",
6854 "-D__inline=inline",
6855 "-D__uuidof(x)=IID()",
6856 "-D__try=",
6857 "-D__except(x)=",
6858 "-D__declspec(x)=__attribute__((x))",
6859 "-D__pragma(x)=",
6860 "-D_inline=inline",
6861 "-D__forceinline=__inline",
6862 "-D__stdcall=__attribute__((__stdcall__))",
6863 "-D__cdecl=__attribute__((__cdecl__))",
6864 "-D__fastcall=__attribute__((__fastcall__))",
6865 "-D__thiscall=__attribute__((__thiscall__))",
6866 "-D_stdcall=__attribute__((__stdcall__))",
6867 "-D_cdecl=__attribute__((__cdecl__))",
6868 "-D_fastcall=__attribute__((__fastcall__))",
6869 "-D_thiscall=__attribute__((__thiscall__))",
6870 "-DSHSTDAPI_(x)=x",
6871 "-D_MSC_EXTENSIONS",
6872 "-DSECURITY_WIN32",
6873 "-D_MSC_VER=1500",
6874 "-D_USE_DECLSPECS_FOR_SAL",
6875 "-D__noop=\" \"",
6876 "-DDECLSPEC_DEPRECATED=\" \"",
6877 "-D__builtin_alignof(x)=__alignof__(x)",
6878 "-DSORTPP_PASS");
6879 if($Arch eq "x86") {
6880 $MinGW_Opts{"-D_M_IX86=300"}=1;
6881 }
6882 elsif($Arch eq "x86_64") {
6883 $MinGW_Opts{"-D_M_AMD64=300"}=1;
6884 }
6885 elsif($Arch eq "ia64") {
6886 $MinGW_Opts{"-D_M_IA64=300"}=1;
6887 }
6888 return join(" ", keys(%MinGW_Opts));
6889 }
6890 return "";
6891}
6892
6893my %C_Structure = map {$_=>1} (
6894# FIXME: Can't separate union and struct data types before dumping,
6895# so it sometimes cause compilation errors for unknown reason
6896# when trying to declare TYPE* tmp_add_class_N
6897# This is a list of such structures + list of other C structures
6898 "sigval",
6899 "sigevent",
6900 "sigaction",
6901 "sigvec",
6902 "sigstack",
6903 "timeval",
6904 "timezone",
6905 "rusage",
6906 "rlimit",
6907 "wait",
6908 "flock",
6909 "stat",
6910 "_stat",
6911 "stat32",
6912 "_stat32",
6913 "stat64",
6914 "_stat64",
6915 "_stati64",
6916 "if_nameindex",
6917 "usb_device",
6918 "sigaltstack",
6919 "sysinfo",
6920 "timeLocale",
6921 "tcp_debug",
6922 "rpc_createerr",
6923# Other C structures appearing in every dump
6924 "timespec",
6925 "random_data",
6926 "drand48_data",
6927 "_IO_marker",
6928 "_IO_FILE",
6929 "lconv",
6930 "sched_param",
6931 "tm",
6932 "itimerspec",
6933 "_pthread_cleanup_buffer",
6934 "fd_set",
6935 "siginfo"
6936);
6937
6938sub getCompileCmd($$$)
6939{
6940 my ($Path, $Opt, $Inc) = @_;
6941 my $GccCall = $GCC_PATH;
6942 if($Opt) {
6943 $GccCall .= " ".$Opt;
6944 }
6945 $GccCall .= " -x ";
6946 if($OSgroup eq "macos") {
6947 $GccCall .= "objective-";
6948 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04006949 if(check_gcc($GCC_PATH, "4"))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006950 { # compile as "C++" header
6951 # to obtain complete dump using GCC 4.0
6952 $GccCall .= "c++-header";
6953 }
6954 else
6955 { # compile as "C++" source
6956 # GCC 3.3 cannot compile headers
6957 $GccCall .= "c++";
6958 }
6959 if(my $Opts = platformSpecs($Version))
6960 {# platform-specific options
6961 $GccCall .= " ".$Opts;
6962 }
6963 # allow extra qualifications
6964 # and other nonconformant code
6965 $GccCall .= " -fpermissive -w";
6966 if($NoStdInc)
6967 {
6968 $GccCall .= " -nostdinc";
6969 $GccCall .= " -nostdinc++";
6970 }
6971 if($CompilerOptions{$Version})
6972 { # user-defined options
6973 $GccCall .= " ".$CompilerOptions{$Version};
6974 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04006975 $GccCall .= " \"".$Path."\"";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006976 if($Inc)
6977 { # include paths
6978 $GccCall .= " ".$Inc;
6979 }
6980 return $GccCall;
6981}
6982
6983sub getDump()
6984{
6985 if(not $GCC_PATH) {
6986 exitStatus("Error", "internal error - GCC path is not set");
6987 }
6988 my %HeaderElems = (
6989 # Types
6990 "stdio.h" => ["FILE", "va_list"],
Andrey Ponomarenko85043792012-05-14 16:48:07 +04006991 "stddef.h" => ["NULL", "ptrdiff_t"],
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006992 "stdint.h" => ["uint32_t", "int32_t", "uint64_t"],
6993 "time.h" => ["time_t"],
6994 "sys/types.h" => ["ssize_t", "u_int32_t", "u_short", "u_char",
6995 "u_int", "off_t", "u_quad_t", "u_long", "size_t", "mode_t"],
6996 "unistd.h" => ["gid_t", "uid_t"],
6997 "stdbool.h" => ["_Bool"],
6998 "rpc/xdr.h" => ["bool_t"],
6999 "in_systm.h" => ["n_long", "n_short"],
7000 # Fields
Andrey Ponomarenkobede8372012-03-29 17:43:21 +04007001 "arpa/inet.h" => ["fw_src", "ip_src"],
7002 # Functions
7003 "stdlib.h" => ["free", "malloc"],
Andrey Ponomarenko85043792012-05-14 16:48:07 +04007004 "string.h" => ["memmove", "strcmp"]
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007005 );
7006 my %AutoPreamble = ();
Andrey Ponomarenko85043792012-05-14 16:48:07 +04007007 foreach (keys(%HeaderElems))
7008 {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007009 foreach my $Elem (@{$HeaderElems{$_}}) {
7010 $AutoPreamble{$Elem}=$_;
7011 }
7012 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04007013 my $TmpHeaderPath = $TMP_DIR."/dump".$Version.".h";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007014 my $MHeaderPath = $TmpHeaderPath;
Andrey Ponomarenko85043792012-05-14 16:48:07 +04007015 open(TMP_HEADER, ">", $TmpHeaderPath) || die ("can't open file \'$TmpHeaderPath\': $!\n");
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007016 if(my $AddDefines = $Descriptor{$Version}{"Defines"})
7017 {
7018 $AddDefines=~s/\n\s+/\n /g;
Andrey Ponomarenko85043792012-05-14 16:48:07 +04007019 print TMP_HEADER "\n // add defines\n ".$AddDefines."\n";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007020 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +04007021 print TMP_HEADER "\n // add includes\n";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007022 my @PreambleHeaders = keys(%{$Include_Preamble{$Version}});
7023 @PreambleHeaders = sort {int($Include_Preamble{$Version}{$a}{"Position"})<=>int($Include_Preamble{$Version}{$b}{"Position"})} @PreambleHeaders;
7024 foreach my $Header_Path (@PreambleHeaders) {
Andrey Ponomarenko85043792012-05-14 16:48:07 +04007025 print TMP_HEADER " #include \"".path_format($Header_Path, "unix")."\"\n";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007026 }
7027 my @Headers = keys(%{$Registered_Headers{$Version}});
7028 @Headers = sort {int($Registered_Headers{$Version}{$a}{"Pos"})<=>int($Registered_Headers{$Version}{$b}{"Pos"})} @Headers;
7029 foreach my $Header_Path (@Headers)
7030 {
7031 next if($Include_Preamble{$Version}{$Header_Path});
Andrey Ponomarenko85043792012-05-14 16:48:07 +04007032 print TMP_HEADER " #include \"".path_format($Header_Path, "unix")."\"\n";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007033 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +04007034 close(TMP_HEADER);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007035 my $IncludeString = getIncString(getIncPaths(@PreambleHeaders, @Headers), "GCC");
7036 if($Debug)
7037 { # debug mode
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04007038 writeFile($DEBUG_PATH{$Version}."/headers/direct-includes.txt", Dumper($Header_Includes{$Version}));
7039 writeFile($DEBUG_PATH{$Version}."/headers/recursive-includes.txt", Dumper($RecursiveIncludes{$Version}));
7040 writeFile($DEBUG_PATH{$Version}."/headers/include-paths.txt", Dumper($Cache{"get_HeaderDeps"}{$Version}));
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04007041 writeFile($DEBUG_PATH{$Version}."/headers/default-paths.txt", Dumper(\%DefaultIncPaths));
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007042 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +04007043
7044 # Target headers
7045 addTargetHeaders($Version);
7046
7047 # clean memory
7048 %RecursiveIncludes = ();
7049 %Header_Include_Prefix = ();
7050 %Header_Includes = ();
7051
7052 # clean cache
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04007053 delete($Cache{"identifyHeader"});
Andrey Ponomarenko85043792012-05-14 16:48:07 +04007054 delete($Cache{"detect_header_includes"});
7055 delete($Cache{"selectSystemHeader"});
7056
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007057 # preprocessing stage
7058 checkPreprocessedUnit(callPreprocessor($TmpHeaderPath, $IncludeString, $Version));
Andrey Ponomarenko85043792012-05-14 16:48:07 +04007059
7060 # clean memory
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04007061 delete($Include_Neighbors{$Version});
Andrey Ponomarenko85043792012-05-14 16:48:07 +04007062
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007063 my $MContent = "";
7064 my $PreprocessCmd = getCompileCmd($TmpHeaderPath, "-E", $IncludeString);
7065 if($OStarget eq "windows"
7066 and get_dumpmachine($GCC_PATH)=~/mingw/i
7067 and $MinGWMode{$Version}!=-1)
7068 { # modify headers to compile by MinGW
7069 if(not $MContent)
7070 { # preprocessing
7071 $MContent = `$PreprocessCmd 2>$TMP_DIR/null`;
7072 }
7073 if($MContent=~s/__asm\s*(\{[^{}]*?\}|[^{};]*)//g)
7074 { # __asm { ... }
7075 $MinGWMode{$Version}=1;
7076 }
7077 if($MContent=~s/\s+(\/ \/.*?)\n/\n/g)
7078 { # comments after preprocessing
7079 $MinGWMode{$Version}=1;
7080 }
7081 if($MContent=~s/(\W)(0x[a-f]+|\d+)(i|ui)(8|16|32|64)(\W)/$1$2$5/g)
7082 { # 0xffui8
7083 $MinGWMode{$Version}=1;
7084 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +04007085 if($MinGWMode{$Version})
7086 {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007087 printMsg("INFO", "Using MinGW compatibility mode");
Andrey Ponomarenkob8d203d2012-05-25 18:11:07 +04007088 $MHeaderPath = $TMP_DIR."/dump$Version.i";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007089 }
7090 }
7091 if(($COMMON_LANGUAGE{$Version} eq "C" or $CheckHeadersOnly)
7092 and $C99Mode{$Version}!=-1 and not $Cpp2003)
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04007093 { # rename C++ keywords in C code
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007094 if(not $MContent)
7095 { # preprocessing
7096 $MContent = `$PreprocessCmd 2>$TMP_DIR/null`;
7097 }
7098 my $RegExp_C = join("|", keys(%CppKeywords_C));
7099 my $RegExp_F = join("|", keys(%CppKeywords_F));
7100 my $RegExp_O = join("|", keys(%CppKeywords_O));
7101 while($MContent=~s/(\A|\n[^\#\/\n][^\n]*?|\n)(\*\s*|\s+|\@|\,|\()($RegExp_C|$RegExp_F)(\s*(\,|\)|\;|\-\>|\.|\:\s*\d))/$1$2c99_$3$4/g)
7102 { # MATCH:
7103 # int foo(int new, int class, int (*new)(int));
7104 # unsigned private: 8;
7105 # DO NOT MATCH:
7106 # #pragma GCC visibility push(default)
7107 $C99Mode{$Version} = 1;
7108 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04007109 if($MContent=~s/([^\w\s]|\w\s+)(?<!operator )(delete)(\s*\()/$1c99_$2$3/g)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007110 { # MATCH:
7111 # int delete(...);
7112 # int explicit(...);
7113 # DO NOT MATCH:
7114 # void operator delete(...)
7115 $C99Mode{$Version} = 1;
7116 }
7117 if($MContent=~s/(\s+)($RegExp_O)(\s*(\;|\:))/$1c99_$2$3/g)
7118 { # MATCH:
7119 # int bool;
7120 # DO NOT MATCH:
7121 # bool X;
7122 # return *this;
7123 # throw;
7124 $C99Mode{$Version} = 1;
7125 }
7126 if($MContent=~s/(\s+)(operator)(\s*(\(\s*\)\s*[^\(\s]|\(\s*[^\)\s]))/$1c99_$2$3/g)
7127 { # MATCH:
7128 # int operator(...);
7129 # DO NOT MATCH:
7130 # int operator()(...);
7131 $C99Mode{$Version} = 1;
7132 }
7133 if($MContent=~s/([^\w\(\,\s]\s*|\s+)(operator)(\s*(\,\s*[^\(\s]|\)))/$1c99_$2$3/g)
7134 { # MATCH:
7135 # int foo(int operator);
7136 # int foo(int operator, int other);
7137 # DO NOT MATCH:
7138 # int operator,(...);
7139 $C99Mode{$Version} = 1;
7140 }
7141 if($MContent=~s/(\*\s*|\w\s+)(bool)(\s*(\,|\)))/$1c99_$2$3/g)
7142 { # MATCH:
7143 # int foo(gboolean *bool);
7144 # DO NOT MATCH:
7145 # void setTabEnabled(int index, bool);
7146 $C99Mode{$Version} = 1;
7147 }
7148 if($MContent=~s/(\w)([^\w\(\,\s]\s*|\s+)(this)(\s*(\,|\)))/$1$2c99_$3$4/g)
7149 { # MATCH:
7150 # int foo(int* this);
7151 # int bar(int this);
7152 # DO NOT MATCH:
7153 # baz(X, this);
7154 $C99Mode{$Version} = 1;
7155 }
7156 if($C99Mode{$Version}==1)
7157 { # try to change C++ "keyword" to "c99_keyword"
7158 printMsg("INFO", "Using C99 compatibility mode");
Andrey Ponomarenkob8d203d2012-05-25 18:11:07 +04007159 $MHeaderPath = $TMP_DIR."/dump$Version.i";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007160 }
7161 }
7162 if($C99Mode{$Version}==1
7163 or $MinGWMode{$Version}==1)
7164 { # compile the corrected preprocessor output
7165 writeFile($MHeaderPath, $MContent);
7166 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +04007167
7168 # clean memory
7169 undef $MContent;
7170
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007171 if($COMMON_LANGUAGE{$Version} eq "C++")
7172 { # add classes and namespaces to the dump
7173 my $CHdump = "-fdump-class-hierarchy -c";
7174 if($C99Mode{$Version}==1
7175 or $MinGWMode{$Version}==1) {
7176 $CHdump .= " -fpreprocessed";
7177 }
7178 my $ClassHierarchyCmd = getCompileCmd($MHeaderPath, $CHdump, $IncludeString);
7179 chdir($TMP_DIR);
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04007180 system($ClassHierarchyCmd." >null 2>&1");
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007181 chdir($ORIG_DIR);
7182 if(my $ClassDump = (cmd_find($TMP_DIR,"f","*.class",1))[0])
7183 {
7184 my %AddClasses = ();
7185 my $Content = readFile($ClassDump);
7186 foreach my $ClassInfo (split(/\n\n/, $Content))
7187 {
7188 if($ClassInfo=~/\AClass\s+(.+)\s*/i)
7189 {
7190 my $CName = $1;
7191 next if($CName=~/\A(__|_objc_|_opaque_)/);
7192 $TUnit_NameSpaces{$Version}{$CName} = -1;
7193 if($CName=~/\A[\w:]+\Z/)
7194 { # classes
7195 $AddClasses{$CName} = 1;
7196 }
7197 if($CName=~/(\w[\w:]*)::/)
7198 { # namespaces
7199 my $NS = $1;
7200 if(not defined $TUnit_NameSpaces{$Version}{$NS}) {
7201 $TUnit_NameSpaces{$Version}{$NS} = 1;
7202 }
7203 }
7204 }
7205 elsif($ClassInfo=~/\AVtable\s+for\s+(.+)\n((.|\n)+)\Z/i)
7206 { # read v-tables (advanced approach)
7207 my ($CName, $VTable) = ($1, $2);
7208 $ClassVTable_Content{$Version}{$CName} = $VTable;
7209 }
7210 }
7211 if($Debug)
7212 { # debug mode
7213 mkpath($DEBUG_PATH{$Version});
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04007214 copy($ClassDump, $DEBUG_PATH{$Version}."/class-hierarchy-dump.txt");
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007215 }
7216 unlink($ClassDump);
7217 if(my $NS_Add = get_namespace_additions($TUnit_NameSpaces{$Version}))
7218 { # GCC on all supported platforms does not include namespaces to the dump by default
7219 appendFile($MHeaderPath, "\n // add namespaces\n".$NS_Add);
7220 }
7221 # some GCC versions don't include class methods to the TU dump by default
7222 my ($AddClass, $ClassNum) = ("", 0);
7223 foreach my $CName (sort keys(%AddClasses))
7224 {
7225 next if($C_Structure{$CName});
7226 next if(not $STDCXX_TESTING and $CName=~/\Astd::/);
7227 next if(($CName=~tr![:]!!)>2);
7228 next if($SkipTypes{$Version}{$CName});
7229 if($CName=~/\A(.+)::[^:]+\Z/
7230 and $AddClasses{$1}) {
7231 next;
7232 }
7233 $AddClass .= " $CName* tmp_add_class_".($ClassNum++).";\n";
7234 }
7235 appendFile($MHeaderPath, "\n // add classes\n".$AddClass);
7236 }
7237 }
7238 writeLog($Version, "Temporary header file \'$TmpHeaderPath\' with the following content will be compiled to create GCC translation unit dump:\n".readFile($TmpHeaderPath)."\n");
7239 # create TU dump
7240 my $TUdump = "-fdump-translation-unit -fkeep-inline-functions -c";
7241 if($C99Mode{$Version}==1
7242 or $MinGWMode{$Version}==1) {
7243 $TUdump .= " -fpreprocessed";
7244 }
7245 my $SyntaxTreeCmd = getCompileCmd($MHeaderPath, $TUdump, $IncludeString);
7246 writeLog($Version, "The GCC parameters:\n $SyntaxTreeCmd\n\n");
7247 chdir($TMP_DIR);
7248 system($SyntaxTreeCmd." >$TMP_DIR/tu_errors 2>&1");
7249 if($?)
7250 { # failed to compile, but the TU dump still can be created
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04007251 my $Errors = readFile($TMP_DIR."/tu_errors");
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007252 if($Errors=~/c99_/)
7253 { # disable c99 mode
7254 $C99Mode{$Version}=-1;
7255 printMsg("INFO", "Disabling C99 compatibility mode");
7256 resetLogging($Version);
7257 $TMP_DIR = tempdir(CLEANUP=>1);
7258 return getDump();
7259 }
7260 elsif($AutoPreambleMode{$Version}!=-1
7261 and my $TErrors = $Errors)
7262 {
7263 my %Types = ();
7264 while($TErrors=~s/error\:\s*(field\s*|)\W+(.+?)\W+//)
7265 { # error: 'FILE' has not been declared
7266 $Types{$2}=1;
7267 }
7268 my %AddHeaders = ();
7269 foreach my $Type (keys(%Types))
7270 {
7271 if(my $Header = $AutoPreamble{$Type}) {
7272 $AddHeaders{path_format($Header, $OSgroup)}=$Type;
7273 }
7274 }
7275 if(my @Headers = sort {$b cmp $a} keys(%AddHeaders))
7276 { # sys/types.h should be the first
7277 foreach my $Num (0 .. $#Headers)
7278 {
7279 my $Name = $Headers[$Num];
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04007280 if(my $Path = identifyHeader($Name, $Version))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007281 { # add automatic preamble headers
7282 if(defined $Include_Preamble{$Version}{$Path})
7283 { # already added
7284 next;
7285 }
7286 $Include_Preamble{$Version}{$Path}{"Position"} = keys(%{$Include_Preamble{$Version}});
7287 my $Type = $AddHeaders{$Name};
7288 printMsg("INFO", "Add \'$Name\' preamble header for \'$Type\'");
7289 }
7290 }
7291 $AutoPreambleMode{$Version}=-1;
7292 resetLogging($Version);
7293 $TMP_DIR = tempdir(CLEANUP=>1);
7294 return getDump();
7295 }
7296 }
7297 elsif($MinGWMode{$Version}!=-1)
7298 {
7299 $MinGWMode{$Version}=-1;
7300 resetLogging($Version);
7301 $TMP_DIR = tempdir(CLEANUP=>1);
7302 return getDump();
7303 }
7304 # FIXME: handle other errors and try to recompile
7305 writeLog($Version, $Errors);
7306 printMsg("ERROR", "some errors occurred when compiling headers");
7307 printErrorLog($Version);
7308 $COMPILE_ERRORS = $ERROR_CODE{"Compile_Error"};
7309 writeLog($Version, "\n");# new line
7310 }
7311 chdir($ORIG_DIR);
7312 unlink($TmpHeaderPath, $MHeaderPath);
7313 return (cmd_find($TMP_DIR,"f","*.tu",1))[0];
7314}
7315
7316sub cmd_file($)
7317{
7318 my $Path = $_[0];
7319 return "" if(not $Path or not -e $Path);
7320 if(my $CmdPath = get_CmdPath("file")) {
7321 return `$CmdPath -b \"$Path\"`;
7322 }
7323 return "";
7324}
7325
7326sub getIncString($$)
7327{
7328 my ($ArrRef, $Style) = @_;
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04007329 return "" if(not $ArrRef or $#{$ArrRef}<0);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007330 my $String = "";
7331 foreach (@{$ArrRef}) {
7332 $String .= " ".inc_opt($_, $Style);
7333 }
7334 return $String;
7335}
7336
7337sub getIncPaths(@)
7338{
7339 my @HeaderPaths = @_;
7340 my @IncPaths = ();
7341 if($INC_PATH_AUTODETECT{$Version})
7342 { # auto-detecting dependencies
7343 my %Includes = ();
7344 foreach my $HPath (@HeaderPaths)
7345 {
7346 foreach my $Dir (get_HeaderDeps($HPath, $Version))
7347 {
7348 if($Skip_Include_Paths{$Version}{$Dir}) {
7349 next;
7350 }
7351 $Includes{$Dir}=1;
7352 }
7353 }
7354 foreach my $Dir (keys(%{$Add_Include_Paths{$Version}}))
7355 { # added by user
7356 next if($Includes{$Dir});
7357 push(@IncPaths, $Dir);
7358 }
7359 foreach my $Dir (@{sortIncPaths([keys(%Includes)], $Version)}) {
7360 push(@IncPaths, $Dir);
7361 }
7362 }
7363 else
7364 { # user-defined paths
7365 foreach my $Dir (sort {get_depth($a)<=>get_depth($b)}
7366 sort {$b cmp $a} keys(%{$Include_Paths{$Version}})) {
7367 push(@IncPaths, $Dir);
7368 }
7369 }
7370 return \@IncPaths;
7371}
7372
7373sub callPreprocessor($$$)
7374{
7375 my ($Path, $Inc, $LibVersion) = @_;
7376 return "" if(not $Path or not -f $Path);
7377 my $IncludeString=$Inc;
7378 if(not $Inc) {
7379 $IncludeString = getIncString(getIncPaths($Path), "GCC");
7380 }
7381 my $Cmd = getCompileCmd($Path, "-dD -E", $IncludeString);
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04007382 my $Out = $TMP_DIR."/preprocessed";
7383 system($Cmd." >$Out 2>$TMP_DIR/null");
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04007384 return $Out;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007385}
7386
7387sub cmd_find($$$$)
7388{ # native "find" is much faster than File::Find (~6x)
7389 # also the File::Find doesn't support --maxdepth N option
7390 # so using the cross-platform wrapper for the native one
7391 my ($Path, $Type, $Name, $MaxDepth) = @_;
7392 return () if(not $Path or not -e $Path);
7393 if($OSgroup eq "windows")
7394 {
7395 my $DirCmd = get_CmdPath("dir");
7396 if(not $DirCmd) {
7397 exitStatus("Not_Found", "can't find \"dir\" command");
7398 }
7399 $Path=~s/[\\]+\Z//;
7400 $Path = get_abs_path($Path);
7401 $Path = path_format($Path, $OSgroup);
7402 my $Cmd = $DirCmd." \"$Path\" /B /O";
7403 if($MaxDepth!=1) {
7404 $Cmd .= " /S";
7405 }
7406 if($Type eq "d") {
7407 $Cmd .= " /AD";
7408 }
7409 my @Files = ();
7410 if($Name)
7411 { # FIXME: how to search file names in MS shell?
7412 $Name=~s/\*/.*/g if($Name!~/\]/);
7413 foreach my $File (split(/\n/, `$Cmd`))
7414 {
7415 if($File=~/$Name\Z/i) {
7416 push(@Files, $File);
7417 }
7418 }
7419 }
7420 else {
7421 @Files = split(/\n/, `$Cmd 2>$TMP_DIR/null`);
7422 }
7423 my @AbsPaths = ();
7424 foreach my $File (@Files)
7425 {
7426 if(not is_abs($File)) {
7427 $File = joinPath($Path, $File);
7428 }
7429 if($Type eq "f" and not -f $File)
7430 { # skip dirs
7431 next;
7432 }
7433 push(@AbsPaths, path_format($File, $OSgroup));
7434 }
7435 if($Type eq "d") {
7436 push(@AbsPaths, $Path);
7437 }
7438 return @AbsPaths;
7439 }
7440 else
7441 {
7442 my $FindCmd = get_CmdPath("find");
7443 if(not $FindCmd) {
7444 exitStatus("Not_Found", "can't find a \"find\" command");
7445 }
7446 $Path = get_abs_path($Path);
7447 if(-d $Path and -l $Path
7448 and $Path!~/\/\Z/)
7449 { # for directories that are symlinks
7450 $Path.="/";
7451 }
7452 my $Cmd = $FindCmd." \"$Path\"";
7453 if($MaxDepth) {
7454 $Cmd .= " -maxdepth $MaxDepth";
7455 }
7456 if($Type) {
7457 $Cmd .= " -type $Type";
7458 }
7459 if($Name)
7460 { # file name
7461 if($Name=~/\]/) {
7462 $Cmd .= " -regex \"$Name\"";
7463 }
7464 else {
7465 $Cmd .= " -name \"$Name\"";
7466 }
7467 }
7468 return split(/\n/, `$Cmd 2>$TMP_DIR/null`);
7469 }
7470}
7471
7472sub unpackDump($)
7473{
7474 my $Path = $_[0];
7475 return "" if(not $Path or not -e $Path);
7476 $Path = get_abs_path($Path);
7477 $Path = path_format($Path, $OSgroup);
7478 my ($Dir, $FileName) = separate_path($Path);
7479 my $UnpackDir = $TMP_DIR."/unpack";
7480 rmtree($UnpackDir);
7481 mkpath($UnpackDir);
7482 if($FileName=~s/\Q.zip\E\Z//g)
7483 { # *.zip
7484 my $UnzipCmd = get_CmdPath("unzip");
7485 if(not $UnzipCmd) {
7486 exitStatus("Not_Found", "can't find \"unzip\" command");
7487 }
7488 chdir($UnpackDir);
7489 system("$UnzipCmd \"$Path\" >$UnpackDir/contents.txt");
7490 if($?) {
7491 exitStatus("Error", "can't extract \'$Path\'");
7492 }
7493 chdir($ORIG_DIR);
7494 my @Contents = ();
7495 foreach (split("\n", readFile("$UnpackDir/contents.txt")))
7496 {
7497 if(/inflating:\s*([^\s]+)/) {
7498 push(@Contents, $1);
7499 }
7500 }
7501 if(not @Contents) {
7502 exitStatus("Error", "can't extract \'$Path\'");
7503 }
7504 return joinPath($UnpackDir, $Contents[0]);
7505 }
7506 elsif($FileName=~s/\Q.tar.gz\E\Z//g)
7507 { # *.tar.gz
7508 if($OSgroup eq "windows")
7509 { # -xvzf option is not implemented in tar.exe (2003)
7510 # use "gzip.exe -k -d -f" + "tar.exe -xvf" instead
7511 my $TarCmd = get_CmdPath("tar");
7512 if(not $TarCmd) {
7513 exitStatus("Not_Found", "can't find \"tar\" command");
7514 }
7515 my $GzipCmd = get_CmdPath("gzip");
7516 if(not $GzipCmd) {
7517 exitStatus("Not_Found", "can't find \"gzip\" command");
7518 }
7519 chdir($UnpackDir);
7520 system("$GzipCmd -k -d -f \"$Path\"");# keep input files (-k)
7521 if($?) {
7522 exitStatus("Error", "can't extract \'$Path\'");
7523 }
7524 system("$TarCmd -xvf \"$Dir\\$FileName.tar\" >$UnpackDir/contents.txt");
7525 if($?) {
7526 exitStatus("Error", "can't extract \'$Path\'");
7527 }
7528 chdir($ORIG_DIR);
7529 unlink($Dir."/".$FileName.".tar");
7530 my @Contents = split("\n", readFile("$UnpackDir/contents.txt"));
7531 if(not @Contents) {
7532 exitStatus("Error", "can't extract \'$Path\'");
7533 }
7534 return joinPath($UnpackDir, $Contents[0]);
7535 }
7536 else
7537 { # Unix
7538 my $TarCmd = get_CmdPath("tar");
7539 if(not $TarCmd) {
7540 exitStatus("Not_Found", "can't find \"tar\" command");
7541 }
7542 chdir($UnpackDir);
7543 system("$TarCmd -xvzf \"$Path\" >$UnpackDir/contents.txt");
7544 if($?) {
7545 exitStatus("Error", "can't extract \'$Path\'");
7546 }
7547 chdir($ORIG_DIR);
7548 # The content file name may be different
7549 # from the package file name
7550 my @Contents = split("\n", readFile("$UnpackDir/contents.txt"));
7551 if(not @Contents) {
7552 exitStatus("Error", "can't extract \'$Path\'");
7553 }
7554 return joinPath($UnpackDir, $Contents[0]);
7555 }
7556 }
7557}
7558
7559sub createArchive($$)
7560{
7561 my ($Path, $To) = @_;
7562 if(not $Path or not -e $Path
7563 or not -d $To) {
7564 return "";
7565 }
7566 my ($From, $Name) = separate_path($Path);
7567 if($OSgroup eq "windows")
7568 { # *.zip
7569 my $ZipCmd = get_CmdPath("zip");
7570 if(not $ZipCmd) {
7571 exitStatus("Not_Found", "can't find \"zip\"");
7572 }
7573 my $Pkg = $To."/".$Name.".zip";
7574 unlink($Pkg);
7575 chdir($To);
7576 system("$ZipCmd -j \"$Name.zip\" \"$Path\" >$TMP_DIR/null");
7577 if($?)
7578 { # cannot allocate memory (or other problems with "zip")
7579 unlink($Path);
7580 exitStatus("Error", "can't pack the ABI dump: ".$!);
7581 }
7582 chdir($ORIG_DIR);
7583 unlink($Path);
7584 return $Pkg;
7585 }
7586 else
7587 { # *.tar.gz
7588 my $TarCmd = get_CmdPath("tar");
7589 if(not $TarCmd) {
7590 exitStatus("Not_Found", "can't find \"tar\"");
7591 }
7592 my $GzipCmd = get_CmdPath("gzip");
7593 if(not $GzipCmd) {
7594 exitStatus("Not_Found", "can't find \"gzip\"");
7595 }
7596 my $Pkg = abs_path($To)."/".$Name.".tar.gz";
7597 unlink($Pkg);
7598 chdir($From);
7599 system($TarCmd, "-czf", $Pkg, $Name);
7600 if($?)
7601 { # cannot allocate memory (or other problems with "tar")
7602 unlink($Path);
7603 exitStatus("Error", "can't pack the ABI dump: ".$!);
7604 }
7605 chdir($ORIG_DIR);
7606 unlink($Path);
7607 return $To."/".$Name.".tar.gz";
7608 }
7609}
7610
7611sub is_header_file($)
7612{
7613 if($_[0]=~/\.($HEADER_EXT)\Z/i) {
7614 return $_[0];
7615 }
7616 return 0;
7617}
7618
7619sub is_not_header($)
7620{
7621 if($_[0]=~/\.\w+\Z/
7622 and $_[0]!~/\.($HEADER_EXT)\Z/i) {
7623 return 1;
7624 }
7625 return 0;
7626}
7627
7628sub is_header($$$)
7629{
7630 my ($Header, $UserDefined, $LibVersion) = @_;
7631 return 0 if(-d $Header);
7632 if(-f $Header) {
7633 $Header = get_abs_path($Header);
7634 }
7635 else
7636 {
7637 if(is_abs($Header))
7638 { # incorrect absolute path
7639 return 0;
7640 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04007641 if(my $HPath = identifyHeader($Header, $LibVersion)) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007642 $Header = $HPath;
7643 }
7644 else
7645 { # can't find header
7646 return 0;
7647 }
7648 }
7649 if($Header=~/\.\w+\Z/)
7650 { # have an extension
7651 return is_header_file($Header);
7652 }
7653 else
7654 {
7655 if($UserDefined==2)
7656 { # specified on the command line
7657 if(cmd_file($Header)!~/HTML|XML/i) {
7658 return $Header;
7659 }
7660 }
7661 elsif($UserDefined)
7662 { # specified in the XML-descriptor
7663 # header file without an extension
7664 return $Header;
7665 }
7666 else
7667 {
Andrey Ponomarenko85043792012-05-14 16:48:07 +04007668 if($Header=~/\/include\//
7669 or cmd_file($Header)=~/C[\+]*\s+program/i)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007670 { # !~/HTML|XML|shared|dynamic/i
7671 return $Header;
7672 }
7673 }
7674 }
7675 return 0;
7676}
7677
Andrey Ponomarenko16934472012-03-29 15:37:04 +04007678sub addTargetHeaders($)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007679{
7680 my $LibVersion = $_[0];
7681 foreach my $RegHeader (keys(%{$Registered_Headers{$LibVersion}}))
7682 {
7683 my $RegDir = get_dirname($RegHeader);
7684 $TargetHeaders{$LibVersion}{get_filename($RegHeader)}=1;
7685 foreach my $RecInc (keys(%{$RecursiveIncludes{$LibVersion}{$RegHeader}}))
7686 {
7687 my $Dir = get_dirname($RecInc);
Andrey Ponomarenko85043792012-05-14 16:48:07 +04007688 if($Dir=~/\A\Q$RegDir\E([\/\\]|\Z)/
7689 or $RecursiveIncludes{$LibVersion}{$RegHeader}{$RecInc}!=1)
7690 { # in the same directory or included by #include "..."
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007691 $TargetHeaders{$LibVersion}{get_filename($RecInc)}=1;
7692 }
7693 }
7694 }
7695}
7696
7697sub readHeaders($)
7698{
7699 $Version = $_[0];
7700 printMsg("INFO", "checking header(s) ".$Descriptor{$Version}{"Version"}." ...");
7701 my $DumpPath = getDump();
7702 if(not $DumpPath) {
7703 exitStatus("Cannot_Compile", "can't compile header(s)");
7704 }
7705 if($Debug)
7706 { # debug mode
7707 mkpath($DEBUG_PATH{$Version});
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04007708 copy($DumpPath, $DEBUG_PATH{$Version}."/translation-unit-dump.txt");
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007709 }
7710 getInfo($DumpPath);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007711}
7712
7713sub prepareTypes($)
7714{
7715 my $LibVersion = $_[0];
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04007716 if(not checkDump($LibVersion, "2.0"))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007717 { # support for old ABI dumps
7718 # type names have been corrected in ACC 1.22 (dump 2.0 format)
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04007719 foreach my $TypeId (keys(%{$TypeInfo{$LibVersion}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007720 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04007721 my $TName = $TypeInfo{$LibVersion}{$TypeId}{"Name"};
7722 if($TName=~/\A(\w+)::(\w+)/) {
7723 my ($P1, $P2) = ($1, $2);
7724 if($P1 eq $P2) {
7725 $TName=~s/\A$P1:\:$P1(\W)/$P1$1/;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007726 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04007727 else {
7728 $TName=~s/\A(\w+:\:)$P2:\:$P2(\W)/$1$P2$2/;
7729 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007730 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04007731 $TypeInfo{$LibVersion}{$TypeId}{"Name"} = $TName;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007732 }
7733 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04007734 if(not checkDump($LibVersion, "2.5"))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007735 { # support for old ABI dumps
7736 # V < 2.5: array size == "number of elements"
7737 # V >= 2.5: array size in bytes
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04007738 foreach my $TypeId (sort {int($a)<=>int($b)} keys(%{$TypeInfo{$LibVersion}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007739 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04007740 my %Type = get_PureType($TypeId, $LibVersion);
7741 if($Type{"Type"} eq "Array")
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007742 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04007743 if($Type{"Size"})
7744 { # array[N]
7745 my %Base = get_OneStep_BaseType($Type{"Tid"}, $LibVersion);
7746 $TypeInfo{$LibVersion}{$TypeId}{"Size"} = $Type{"Size"}*$Base{"Size"};
7747 }
7748 else
7749 { # array[] is a pointer
7750 $TypeInfo{$LibVersion}{$TypeId}{"Size"} = $WORD_SIZE{$LibVersion};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007751 }
7752 }
7753 }
7754 }
7755 my $V2 = ($LibVersion==1)?2:1;
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04007756 if(not checkDump($LibVersion, "2.7"))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007757 { # support for old ABI dumps
7758 # size of "method ptr" corrected in 2.7
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04007759 foreach my $TypeId (sort {int($a)<=>int($b)} keys(%{$TypeInfo{$LibVersion}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007760 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04007761 my %PureType = get_PureType($TypeId, $LibVersion);
7762 if($PureType{"Type"} eq "MethodPtr")
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007763 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04007764 my %Type = get_Type($TypeId, $LibVersion);
7765 my $TypeId_2 = getTypeIdByName($PureType{"Name"}, $V2);
7766 my %Type2 = get_Type($TypeId_2, $V2);
7767 if($Type{"Size"} ne $Type2{"Size"}) {
7768 $TypeInfo{$LibVersion}{$TypeId}{"Size"} = $Type2{"Size"};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007769 }
7770 }
7771 }
7772 }
7773}
7774
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04007775sub prepareSymbols($)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007776{
7777 my $LibVersion = $_[0];
Andrey Ponomarenko16934472012-03-29 15:37:04 +04007778
7779 if(not keys(%{$SymbolInfo{$LibVersion}}))
7780 { # check if input is valid
7781 if(not $ExtendedCheck and not $CheckObjectsOnly)
7782 {
7783 if($CheckHeadersOnly) {
7784 exitStatus("Empty_Set", "the set of public symbols is empty (".$Descriptor{$LibVersion}{"Version"}.")");
7785 }
7786 else {
7787 exitStatus("Empty_Intersection", "the sets of public symbols in headers and libraries have empty intersection (".$Descriptor{$LibVersion}{"Version"}.")");
7788 }
7789 }
7790 }
7791
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007792 my $Remangle = 0;
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04007793 if(not checkDump(1, "2.10")
7794 or not checkDump(2, "2.10"))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007795 { # different formats
7796 $Remangle = 1;
7797 }
7798 if($CheckHeadersOnly)
7799 { # different languages
7800 if($UserLang)
7801 { # --lang=LANG for both versions
7802 if(($UsedDump{1}{"V"} and $UserLang ne $UsedDump{1}{"L"})
7803 or ($UsedDump{2}{"V"} and $UserLang ne $UsedDump{2}{"L"}))
7804 {
7805 if($UserLang eq "C++")
7806 { # remangle symbols
7807 $Remangle = 1;
7808 }
7809 elsif($UserLang eq "C")
7810 { # remove mangling
7811 $Remangle = -1;
7812 }
7813 }
7814 }
7815 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04007816
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04007817 foreach my $InfoId (sort {int($b)<=>int($a)} keys(%{$SymbolInfo{$LibVersion}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007818 { # reverse order: D0, D1, D2, D0 (artificial, GCC < 4.5), C1, C2
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04007819 if(not checkDump($LibVersion, "2.13"))
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04007820 { # support for old ABI dumps
7821 if(defined $SymbolInfo{$LibVersion}{$InfoId}{"Param"})
7822 {
7823 foreach my $P (keys(%{$SymbolInfo{$LibVersion}{$InfoId}{"Param"}}))
7824 {
7825 my $TypeId = $SymbolInfo{$LibVersion}{$InfoId}{"Param"}{$P}{"type"};
7826 my $DVal = $SymbolInfo{$LibVersion}{$InfoId}{"Param"}{$P}{"default"};
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04007827 my $TName = $TypeInfo{$LibVersion}{$TypeId}{"Name"};
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04007828 if(defined $DVal and $DVal ne "")
7829 {
7830 if($TName eq "char") {
7831 $SymbolInfo{$LibVersion}{$InfoId}{"Param"}{$P}{"default"} = chr($DVal);
7832 }
7833 elsif($TName eq "bool") {
7834 $SymbolInfo{$LibVersion}{$InfoId}{"Param"}{$P}{"default"} = $DVal?"true":"false";
7835 }
7836 }
7837 }
7838 }
7839 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04007840 if($SymbolInfo{$LibVersion}{$InfoId}{"Destructor"})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007841 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04007842 if(defined $SymbolInfo{$LibVersion}{$InfoId}{"Param"}
7843 and keys(%{$SymbolInfo{$LibVersion}{$InfoId}{"Param"}})
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04007844 and $SymbolInfo{$LibVersion}{$InfoId}{"Param"}{0}{"name"})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007845 { # support for old GCC < 4.5: skip artificial ~dtor(int __in_chrg)
7846 # + support for old ABI dumps
7847 next;
7848 }
7849 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04007850 my $MnglName = $SymbolInfo{$LibVersion}{$InfoId}{"MnglName"};
Andrey Ponomarenko85043792012-05-14 16:48:07 +04007851 my $ShortName = $SymbolInfo{$LibVersion}{$InfoId}{"ShortName"};
Andrey Ponomarenko16934472012-03-29 15:37:04 +04007852 my $ClassID = $SymbolInfo{$LibVersion}{$InfoId}{"Class"};
Andrey Ponomarenko85043792012-05-14 16:48:07 +04007853 my $Return = $SymbolInfo{$LibVersion}{$InfoId}{"Return"};
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04007854
7855 if(not $MnglName)
7856 { # ABI dumps have no mangled names for C-functions
Andrey Ponomarenko85043792012-05-14 16:48:07 +04007857 $MnglName = $ShortName;
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04007858 $SymbolInfo{$LibVersion}{$InfoId}{"MnglName"} = $MnglName;
7859 }
7860
Andrey Ponomarenko16934472012-03-29 15:37:04 +04007861 my $SRemangle = 0;
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04007862 if(not checkDump(1, "2.12")
7863 or not checkDump(2, "2.12"))
Andrey Ponomarenko16934472012-03-29 15:37:04 +04007864 { # support for old ABI dumps
Andrey Ponomarenko85043792012-05-14 16:48:07 +04007865 if($ShortName eq "operator>>")
7866 {
7867 if(not $SymbolInfo{$LibVersion}{$InfoId}{"Class"})
7868 { # corrected mangling of operator>>
7869 $SRemangle = 1;
7870 }
Andrey Ponomarenko16934472012-03-29 15:37:04 +04007871 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +04007872 if($SymbolInfo{$LibVersion}{$InfoId}{"Data"})
7873 {
7874 if(not $SymbolInfo{$LibVersion}{$InfoId}{"Class"}
7875 and isConstType($Return, $LibVersion) and $MnglName!~/L\d+$ShortName/)
7876 { # corrected mangling of const global data
7877 # some global data is not mangled in the TU dump: qt_sine_table (Qt 4.8)
7878 # and incorrectly mangled by old ACC versions
7879 $SRemangle = 1;
7880 }
Andrey Ponomarenko16934472012-03-29 15:37:04 +04007881 }
7882 }
7883 if($Remangle==1 or $SRemangle==1)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007884 { # support for old ABI dumps: some symbols are not mangled in old dumps
7885 # mangle both sets of symbols (old and new)
7886 # NOTE: remangling all symbols by the same mangler
7887 if($MnglName=~/\A_ZN(V|)K/)
7888 { # mangling may be incorrect on old ABI dumps
7889 # because of absent "Const" attribute
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04007890 $SymbolInfo{$LibVersion}{$InfoId}{"Const"} = 1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007891 }
7892 if($MnglName=~/\A_ZN(K|)V/)
7893 { # mangling may be incorrect on old ABI dumps
7894 # because of absent "Volatile" attribute
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04007895 $SymbolInfo{$LibVersion}{$InfoId}{"Volatile"} = 1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007896 }
Andrey Ponomarenko16934472012-03-29 15:37:04 +04007897 if(($ClassID and $MnglName!~/\A(_Z|\?)/)
7898 or (not $ClassID and $CheckHeadersOnly)
7899 or (not $ClassID and not link_symbol($MnglName, $LibVersion, "-Deps")))
7900 { # support for old ABI dumps, GCC >= 4.0
7901 # remangling all manually mangled symbols
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04007902 if($MnglName = mangle_symbol($InfoId, $LibVersion, "GCC"))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007903 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04007904 $SymbolInfo{$LibVersion}{$InfoId}{"MnglName"} = $MnglName;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007905 $MangledNames{$LibVersion}{$MnglName} = 1;
7906 }
7907 }
7908 }
7909 elsif($Remangle==-1)
7910 { # remove mangling
7911 $MnglName = "";
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04007912 $SymbolInfo{$LibVersion}{$InfoId}{"MnglName"} = "";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007913 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007914 if(not $MnglName) {
7915 next;
7916 }
7917 if(not $CompleteSignature{$LibVersion}{$MnglName}{"MnglName"})
7918 { # NOTE: global data may enter here twice
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04007919 %{$CompleteSignature{$LibVersion}{$MnglName}} = %{$SymbolInfo{$LibVersion}{$InfoId}};
7920
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007921 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04007922 if(not checkDump($LibVersion, "2.6"))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007923 { # support for old dumps
7924 # add "Volatile" attribute
7925 if($MnglName=~/_Z(K|)V/) {
7926 $CompleteSignature{$LibVersion}{$MnglName}{"Volatile"}=1;
7927 }
7928 }
7929 # symbol and its symlink have same signatures
7930 if($SymVer{$LibVersion}{$MnglName}) {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04007931 %{$CompleteSignature{$LibVersion}{$SymVer{$LibVersion}{$MnglName}}} = %{$SymbolInfo{$LibVersion}{$InfoId}};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007932 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +04007933
7934 # clean memory
Andrey Ponomarenko16934472012-03-29 15:37:04 +04007935 delete($SymbolInfo{$LibVersion}{$InfoId});
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007936 }
7937 if($COMMON_LANGUAGE{$LibVersion} eq "C++" or $OSgroup eq "windows") {
7938 translateSymbols(keys(%{$CompleteSignature{$LibVersion}}), $LibVersion);
7939 }
7940 if($ExtendedCheck)
7941 { # --ext option
7942 addExtension($LibVersion);
7943 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +04007944
7945 # clean memory
7946 delete($SymbolInfo{$LibVersion});
7947
7948 foreach my $Symbol (keys(%{$CompleteSignature{$LibVersion}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007949 { # detect allocable classes with public exported constructors
7950 # or classes with auto-generated or inline-only constructors
Andrey Ponomarenko85043792012-05-14 16:48:07 +04007951 if(my $ClassId = $CompleteSignature{$LibVersion}{$Symbol}{"Class"})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007952 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04007953 my $ClassName = $TypeInfo{$LibVersion}{$ClassId}{"Name"};
Andrey Ponomarenko85043792012-05-14 16:48:07 +04007954 if($CompleteSignature{$LibVersion}{$Symbol}{"Constructor"}
7955 and not $CompleteSignature{$LibVersion}{$Symbol}{"InLine"})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007956 { # Class() { ... } will not be exported
Andrey Ponomarenko85043792012-05-14 16:48:07 +04007957 if(not $CompleteSignature{$LibVersion}{$Symbol}{"Private"})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007958 {
Andrey Ponomarenko85043792012-05-14 16:48:07 +04007959 if($CheckHeadersOnly or link_symbol($Symbol, $LibVersion, "-Deps")) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007960 $AllocableClass{$LibVersion}{$ClassName} = 1;
7961 }
7962 }
7963 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +04007964 if(not $CompleteSignature{$LibVersion}{$Symbol}{"Private"})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007965 { # all imported class methods
Andrey Ponomarenko85043792012-05-14 16:48:07 +04007966 if(symbolFilter($Symbol, $LibVersion, "Affected", "Binary"))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007967 {
Andrey Ponomarenko85043792012-05-14 16:48:07 +04007968 if($CheckHeadersOnly)
7969 {
7970 if(not $CompleteSignature{$LibVersion}{$Symbol}{"InLine"}
7971 or $CompleteSignature{$LibVersion}{$Symbol}{"Virt"})
7972 { # all symbols except non-virtual inline
7973 $ClassMethods{"Binary"}{$LibVersion}{$ClassName}{$Symbol} = 1;
7974 }
7975 }
7976 else {
7977 $ClassMethods{"Binary"}{$LibVersion}{$ClassName}{$Symbol} = 1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007978 }
7979 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04007980 if(symbolFilter($Symbol, $LibVersion, "Affected", "Source")) {
Andrey Ponomarenko85043792012-05-14 16:48:07 +04007981 $ClassMethods{"Source"}{$LibVersion}{$ClassName}{$Symbol} = 1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007982 }
7983 }
Andrey Ponomarenko16934472012-03-29 15:37:04 +04007984 $ClassNames{$LibVersion}{$ClassName} = 1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007985 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +04007986 if(my $RetId = $CompleteSignature{$LibVersion}{$Symbol}{"Return"})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007987 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04007988 my %Base = get_BaseType($RetId, $LibVersion);
Andrey Ponomarenko85043792012-05-14 16:48:07 +04007989 if(defined $Base{"Type"}
7990 and $Base{"Type"}=~/Struct|Class/)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007991 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04007992 my $Name = $TypeInfo{$LibVersion}{$Base{"Tid"}}{"Name"};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007993 if($Name=~/<([^<>\s]+)>/)
7994 {
7995 if(my $Tid = getTypeIdByName($1, $LibVersion)) {
7996 $ReturnedClass{$LibVersion}{$Tid} = 1;
7997 }
7998 }
7999 else {
8000 $ReturnedClass{$LibVersion}{$Base{"Tid"}} = 1;
8001 }
8002 }
8003 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +04008004 foreach my $Num (keys(%{$CompleteSignature{$LibVersion}{$Symbol}{"Param"}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008005 {
Andrey Ponomarenko85043792012-05-14 16:48:07 +04008006 my $PId = $CompleteSignature{$LibVersion}{$Symbol}{"Param"}{$Num}{"type"};
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04008007 if(get_PLevel($PId, $LibVersion)>=1)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008008 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04008009 if(my %Base = get_BaseType($PId, $LibVersion))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008010 {
Andrey Ponomarenko16934472012-03-29 15:37:04 +04008011 if($Base{"Type"}=~/Struct|Class/)
8012 {
Andrey Ponomarenko85043792012-05-14 16:48:07 +04008013 $ParamClass{$LibVersion}{$Base{"Tid"}}{$Symbol} = 1;
Andrey Ponomarenko16934472012-03-29 15:37:04 +04008014 foreach my $SubId (get_sub_classes($Base{"Tid"}, $LibVersion, 1))
8015 { # mark all derived classes
Andrey Ponomarenko85043792012-05-14 16:48:07 +04008016 $ParamClass{$LibVersion}{$SubId}{$Symbol} = 1;
Andrey Ponomarenko16934472012-03-29 15:37:04 +04008017 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008018 }
8019 }
8020 }
8021 }
8022 }
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04008023 foreach my $MnglName (keys(%VTableClass))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008024 { # reconstruct header name for v-tables
8025 if($MnglName=~/\A_ZTV/)
8026 {
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04008027 if(my $ClassName = $VTableClass{$MnglName})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008028 {
8029 if(my $ClassId = $TName_Tid{$LibVersion}{$ClassName}) {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04008030 $CompleteSignature{$LibVersion}{$MnglName}{"Header"} = $TypeInfo{$LibVersion}{$ClassId}{"Header"};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008031 }
8032 }
8033 }
8034 }
Andrey Ponomarenko16934472012-03-29 15:37:04 +04008035
8036 # types
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04008037 foreach my $TypeId (keys(%{$TypeInfo{$LibVersion}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008038 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04008039 if(my $TName = $TypeInfo{$LibVersion}{$TypeId}{"Name"})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008040 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04008041 if(defined $TypeInfo{$LibVersion}{$TypeId}{"VTable"}) {
8042 $ClassNames{$LibVersion}{$TName} = 1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008043 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04008044 if(defined $TypeInfo{$LibVersion}{$TypeId}{"Base"})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008045 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04008046 $ClassNames{$LibVersion}{$TName} = 1;
8047 foreach my $Bid (keys(%{$TypeInfo{$LibVersion}{$TypeId}{"Base"}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008048 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04008049 if(my $BName = $TypeInfo{$LibVersion}{$Bid}{"Name"}) {
8050 $ClassNames{$LibVersion}{$BName} = 1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008051 }
8052 }
8053 }
8054 }
8055 }
8056}
8057
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04008058sub register_TypeUsage($$)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008059{
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04008060 my ($TypeId, $LibVersion) = @_;
8061 if(not $TypeId) {
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04008062 return 0;
8063 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04008064 if($UsedType{$LibVersion}{$TypeId})
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04008065 { # already registered
8066 return 1;
8067 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04008068 my %TInfo = get_Type($TypeId, $LibVersion);
Andrey Ponomarenko85043792012-05-14 16:48:07 +04008069 if($TInfo{"Type"})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008070 {
Andrey Ponomarenko85043792012-05-14 16:48:07 +04008071 if($TInfo{"Type"}=~/\A(Struct|Union|Class|FuncPtr|MethodPtr|FieldPtr|Enum)\Z/)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008072 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04008073 $UsedType{$LibVersion}{$TypeId} = 1;
Andrey Ponomarenko85043792012-05-14 16:48:07 +04008074 if($TInfo{"Type"}=~/\A(Struct|Class)\Z/)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008075 {
Andrey Ponomarenko85043792012-05-14 16:48:07 +04008076 foreach my $BaseId (keys(%{$TInfo{"Base"}}))
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04008077 { # register base classes
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04008078 register_TypeUsage($BaseId, $LibVersion);
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04008079 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +04008080 foreach my $TPos (keys(%{$TInfo{"TParam"}}))
8081 {
8082 my $TPName = $TInfo{"TParam"}{$TPos}{"name"};
8083 if(my $TTid = $TName_Tid{$LibVersion}{$TPName}) {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04008084 register_TypeUsage($TTid, $LibVersion);
Andrey Ponomarenko85043792012-05-14 16:48:07 +04008085 }
8086 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008087 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +04008088 foreach my $Memb_Pos (keys(%{$TInfo{"Memb"}}))
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04008089 {
Andrey Ponomarenko85043792012-05-14 16:48:07 +04008090 if(my $MTid = $TInfo{"Memb"}{$Memb_Pos}{"type"}) {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04008091 register_TypeUsage($MTid, $LibVersion);
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04008092 }
8093 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +04008094 if($TInfo{"Type"} eq "FuncPtr"
8095 or $TInfo{"Type"} eq "MethodPtr")
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04008096 {
Andrey Ponomarenko85043792012-05-14 16:48:07 +04008097 if(my $RTid = $TInfo{"Return"}) {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04008098 register_TypeUsage($RTid, $LibVersion);
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04008099 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +04008100 foreach my $Memb_Pos (keys(%{$TInfo{"Param"}}))
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04008101 {
Andrey Ponomarenko85043792012-05-14 16:48:07 +04008102 if(my $MTid = $TInfo{"Param"}{$Memb_Pos}{"type"}) {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04008103 register_TypeUsage($MTid, $LibVersion);
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04008104 }
8105 }
8106 }
8107 return 1;
8108 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +04008109 elsif($TInfo{"Type"}=~/\A(Const|ConstVolatile|Volatile|Pointer|Ref|Restrict|Array|Typedef)\Z/)
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04008110 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04008111 $UsedType{$LibVersion}{$TypeId} = 1;
8112 register_TypeUsage($TInfo{"BaseType"}{"Tid"}, $LibVersion);
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04008113 return 1;
8114 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04008115 elsif($TInfo{"Type"} eq "Intrinsic")
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04008116 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04008117 $UsedType{$LibVersion}{$TypeId} = 1;
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04008118 return 1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008119 }
8120 }
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04008121 return 0;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008122}
8123
Andrey Ponomarenko85043792012-05-14 16:48:07 +04008124sub selectSymbol($$$$)
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04008125{
Andrey Ponomarenko85043792012-05-14 16:48:07 +04008126 my ($Symbol, $SInfo, $Level, $LibVersion) = @_;
8127
8128 if(not $STDCXX_TESTING and $Symbol=~/\A(_ZS|_ZNS|_ZNKS)/)
8129 { # stdc++ interfaces
8130 return 0;
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04008131 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +04008132
8133 my $Target = 0;
8134 if(my $Header = $SInfo->{"Header"}) {
8135 $Target = (is_target_header($Header, 1) or is_target_header($Header, 2));
8136 }
8137 if($CheckHeadersOnly)
8138 {
8139 if($Target)
8140 {
8141 if($Level eq "Dump")
8142 { # dumped
8143 if($BinaryOnly)
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04008144 {
Andrey Ponomarenko85043792012-05-14 16:48:07 +04008145 if(not $SInfo->{"InLine"} or $SInfo->{"Data"}) {
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04008146 return 1;
8147 }
8148 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +04008149 else {
8150 return 1;
8151 }
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04008152 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +04008153 elsif($Level eq "Source")
8154 { # checked
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04008155 return 1;
8156 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +04008157 elsif($Level eq "Binary")
8158 { # checked
8159 if(not $SInfo->{"InLine"} or $SInfo->{"Data"}
8160 or $SInfo->{"Virt"} or $SInfo->{"PureVirt"}) {
8161 return 1;
8162 }
8163 }
8164 }
8165 }
8166 else
8167 { # library is available
8168 if(link_symbol($Symbol, $LibVersion, "-Deps"))
8169 { # exported symbols
8170 return 1;
8171 }
8172 if($Level eq "Dump")
8173 { # dumped
8174 if(not $BinaryOnly)
8175 { # SrcBin
8176 if($Target) {
8177 return 1;
8178 }
8179 }
8180 if($SInfo->{"Data"})
8181 {
8182 if($Target) {
8183 return 1;
8184 }
8185 }
8186 }
8187 elsif($Level eq "Source")
8188 { # checked
8189 if($Target) {
8190 return 1;
8191 }
8192 }
8193 elsif($Level eq "Binary")
8194 { # checked
8195 if($SInfo->{"PureVirt"} or $SInfo->{"Data"})
8196 {
8197 if($Target) {
8198 return 1;
8199 }
8200 }
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04008201 }
8202 }
8203 return 0;
8204}
8205
Andrey Ponomarenko85043792012-05-14 16:48:07 +04008206sub cleanDump($)
8207{ # clean data
Andrey Ponomarenko16934472012-03-29 15:37:04 +04008208 my $LibVersion = $_[0];
8209 foreach my $InfoId (keys(%{$SymbolInfo{$LibVersion}}))
8210 {
8211 my $MnglName = $SymbolInfo{$LibVersion}{$InfoId}{"MnglName"};
8212 if(not $MnglName) {
8213 delete($SymbolInfo{$LibVersion}{$InfoId});
8214 next;
8215 }
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04008216 my $ShortName = $SymbolInfo{$LibVersion}{$InfoId}{"ShortName"};
Andrey Ponomarenko85043792012-05-14 16:48:07 +04008217 if(not $ShortName) {
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04008218 delete($SymbolInfo{$LibVersion}{$InfoId});
8219 next;
Andrey Ponomarenko16934472012-03-29 15:37:04 +04008220 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +04008221 if($MnglName eq $ShortName)
8222 { # remove duplicate data
8223 delete($SymbolInfo{$LibVersion}{$InfoId}{"MnglName"});
Andrey Ponomarenko16934472012-03-29 15:37:04 +04008224 }
8225 if(not keys(%{$SymbolInfo{$LibVersion}{$InfoId}{"Param"}})) {
8226 delete($SymbolInfo{$LibVersion}{$InfoId}{"Param"});
8227 }
8228 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04008229 foreach my $Tid (keys(%{$TypeInfo{$LibVersion}}))
Andrey Ponomarenko85043792012-05-14 16:48:07 +04008230 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04008231 foreach my $Attr ("Header", "Line", "Size", "NameSpace")
Andrey Ponomarenko16934472012-03-29 15:37:04 +04008232 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04008233 if(not $TypeInfo{$LibVersion}{$Tid}{$Attr}) {
8234 delete($TypeInfo{$LibVersion}{$Tid}{$Attr});
8235 }
8236 }
8237 }
8238}
8239
8240sub selectType($$)
8241{
8242 my ($Tid, $LibVersion) = @_;
8243 if(my $THeader = $TypeInfo{$LibVersion}{$Tid}{"Header"})
8244 {
8245 if(not isBuiltIn($THeader))
8246 {
8247 if($TypeInfo{$LibVersion}{$Tid}{"Type"}=~/Class|Struct|Union|Enum|Typedef/)
Andrey Ponomarenko16934472012-03-29 15:37:04 +04008248 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04008249 if(not isAnon($TypeInfo{$LibVersion}{$Tid}{"Name"}))
8250 {
8251 if(is_target_header($THeader, $LibVersion))
8252 { # from target headers
8253 if(not selfTypedef($Tid, $LibVersion)) {
8254 return 1;
8255 }
8256 }
Andrey Ponomarenko16934472012-03-29 15:37:04 +04008257 }
8258 }
8259 }
8260 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04008261 return 0;
Andrey Ponomarenko16934472012-03-29 15:37:04 +04008262}
8263
Andrey Ponomarenko85043792012-05-14 16:48:07 +04008264sub removeUnused($$)
8265{ # remove unused data types from the ABI dump
8266 my ($LibVersion, $Kind) = @_;
8267 foreach my $InfoId (keys(%{$SymbolInfo{$LibVersion}}))
8268 {
8269 my %FuncInfo = %{$SymbolInfo{$LibVersion}{$InfoId}};
8270 if(my $RTid = $FuncInfo{"Return"}) {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04008271 register_TypeUsage($RTid, $LibVersion);
Andrey Ponomarenko85043792012-05-14 16:48:07 +04008272 }
8273 if(my $FCid = $FuncInfo{"Class"})
8274 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04008275 register_TypeUsage($FCid, $LibVersion);
8276 if(my $ThisId = getTypeIdByName($TypeInfo{$LibVersion}{$FCid}{"Name"}."*const", $LibVersion))
Andrey Ponomarenko85043792012-05-14 16:48:07 +04008277 { # register "this" pointer
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04008278 $UsedType{$LibVersion}{$ThisId} = 1;
8279 if(my %ThisType = get_Type($ThisId, $LibVersion)) {
8280 register_TypeUsage($ThisType{"BaseType"}{"Tid"}, $LibVersion);
Andrey Ponomarenko85043792012-05-14 16:48:07 +04008281 }
8282 }
8283 }
8284 foreach my $PPos (keys(%{$FuncInfo{"Param"}}))
8285 {
8286 if(my $PTid = $FuncInfo{"Param"}{$PPos}{"type"}) {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04008287 register_TypeUsage($PTid, $LibVersion);
Andrey Ponomarenko85043792012-05-14 16:48:07 +04008288 }
8289 }
8290 foreach my $TPos (keys(%{$FuncInfo{"TParam"}}))
8291 {
8292 my $TPName = $FuncInfo{"TParam"}{$TPos}{"name"};
8293 if(my $TTid = $TName_Tid{$LibVersion}{$TPName}) {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04008294 register_TypeUsage($TTid, $LibVersion);
Andrey Ponomarenko85043792012-05-14 16:48:07 +04008295 }
8296 }
8297 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04008298 foreach my $Tid (keys(%{$TypeInfo{$LibVersion}}))
8299 {
8300 if($UsedType{$LibVersion}{$Tid})
8301 { # All & Derived
8302 next;
8303 }
8304
8305 if($Kind eq "Derived")
Andrey Ponomarenko85043792012-05-14 16:48:07 +04008306 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04008307 if(selectType($Tid, $LibVersion)) {
8308 register_TypeUsage($Tid, $LibVersion);
Andrey Ponomarenko85043792012-05-14 16:48:07 +04008309 }
8310 }
8311 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04008312 foreach my $Tid (keys(%{$TypeInfo{$LibVersion}}))
8313 { # remove unused types
8314 if($UsedType{$LibVersion}{$Tid})
8315 { # All & Derived
8316 next;
8317 }
8318 # remove type
8319 delete($TypeInfo{$LibVersion}{$Tid});
8320 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +04008321
8322 # clean memory
8323 %UsedType = ();
8324}
8325
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04008326sub selfTypedef($$)
Andrey Ponomarenko85043792012-05-14 16:48:07 +04008327{
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04008328 my ($TypeId, $LibVersion) = @_;
8329 my %Type = get_Type($TypeId, $LibVersion);
Andrey Ponomarenko85043792012-05-14 16:48:07 +04008330 if($Type{"Type"} eq "Typedef")
8331 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04008332 my %Base = get_OneStep_BaseType($TypeId, $LibVersion);
Andrey Ponomarenko85043792012-05-14 16:48:07 +04008333 if($Base{"Type"}=~/Class|Struct/)
8334 {
8335 if($Type{"Name"} eq $Base{"Name"}) {
8336 return 1;
8337 }
8338 elsif($Type{"Name"}=~/::(\w+)\Z/)
8339 {
8340 if($Type{"Name"} eq $Base{"Name"}."::".$1)
8341 { # QPointer<QWidget>::QPointer
8342 return 1;
8343 }
8344 }
8345 }
8346 }
8347 return 0;
8348}
8349
Andrey Ponomarenko16934472012-03-29 15:37:04 +04008350sub addExtension($)
8351{
8352 my $LibVersion = $_[0];
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04008353 foreach my $Tid (keys(%{$TypeInfo{$LibVersion}}))
Andrey Ponomarenko16934472012-03-29 15:37:04 +04008354 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04008355 if(selectType($Tid, $LibVersion))
Andrey Ponomarenko16934472012-03-29 15:37:04 +04008356 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04008357 my $Symbol = "external_func_".$TypeInfo{$LibVersion}{$Tid}{"Name"};
8358
8359 %{$CompleteSignature{$LibVersion}{$Symbol}} = (
8360 "Header" => "extended.h",
8361 "ShortName" => $Symbol,
8362 "MnglName" => $Symbol,
8363 "Param" => { 0 => { "type"=>$Tid, "name"=>"p1" } }
8364 );
8365
8366 $ExtendedSymbols{$Symbol}=1;
8367 $CheckedSymbols{"Binary"}{$Symbol}=1;
8368 $CheckedSymbols{"Source"}{$Symbol}=1;
Andrey Ponomarenko16934472012-03-29 15:37:04 +04008369 }
8370 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04008371 $ExtendedSymbols{"external_func_0"}=1;
8372 $CheckedSymbols{"Binary"}{"external_func_0"}=1;
8373 $CheckedSymbols{"Source"}{"external_func_0"}=1;
Andrey Ponomarenko16934472012-03-29 15:37:04 +04008374}
8375
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008376sub findMethod($$$)
8377{
8378 my ($VirtFunc, $ClassId, $LibVersion) = @_;
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04008379 foreach my $BaseClass_Id (keys(%{$TypeInfo{$LibVersion}{$ClassId}{"Base"}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008380 {
8381 if(my $VirtMethodInClass = findMethod_Class($VirtFunc, $BaseClass_Id, $LibVersion)) {
8382 return $VirtMethodInClass;
8383 }
8384 elsif(my $VirtMethodInBaseClasses = findMethod($VirtFunc, $BaseClass_Id, $LibVersion)) {
8385 return $VirtMethodInBaseClasses;
8386 }
8387 }
8388 return "";
8389}
8390
8391sub findMethod_Class($$$)
8392{
8393 my ($VirtFunc, $ClassId, $LibVersion) = @_;
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04008394 my $ClassName = $TypeInfo{$LibVersion}{$ClassId}{"Name"};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008395 return "" if(not defined $VirtualTable{$LibVersion}{$ClassName});
8396 my $TargetSuffix = get_symbol_suffix($VirtFunc, 1);
8397 my $TargetShortName = $CompleteSignature{$LibVersion}{$VirtFunc}{"ShortName"};
8398 foreach my $Candidate (keys(%{$VirtualTable{$LibVersion}{$ClassName}}))
8399 { # search for interface with the same parameters suffix (overridden)
8400 if($TargetSuffix eq get_symbol_suffix($Candidate, 1))
8401 {
8402 if($CompleteSignature{$LibVersion}{$VirtFunc}{"Destructor"}) {
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04008403 if($CompleteSignature{$LibVersion}{$Candidate}{"Destructor"})
8404 {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008405 if(($VirtFunc=~/D0E/ and $Candidate=~/D0E/)
8406 or ($VirtFunc=~/D1E/ and $Candidate=~/D1E/)
8407 or ($VirtFunc=~/D2E/ and $Candidate=~/D2E/)) {
8408 return $Candidate;
8409 }
8410 }
8411 }
8412 else {
8413 if($TargetShortName eq $CompleteSignature{$LibVersion}{$Candidate}{"ShortName"}) {
8414 return $Candidate;
8415 }
8416 }
8417 }
8418 }
8419 return "";
8420}
8421
Andrey Ponomarenko16934472012-03-29 15:37:04 +04008422sub registerVTable($)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008423{
Andrey Ponomarenko16934472012-03-29 15:37:04 +04008424 my $LibVersion = $_[0];
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04008425 foreach my $Symbol (keys(%{$CompleteSignature{$LibVersion}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008426 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04008427 if($CompleteSignature{$LibVersion}{$Symbol}{"Virt"}
8428 or $CompleteSignature{$LibVersion}{$Symbol}{"PureVirt"})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008429 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04008430 my $ClassName = $TypeInfo{$LibVersion}{$CompleteSignature{$LibVersion}{$Symbol}{"Class"}}{"Name"};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008431 next if(not $STDCXX_TESTING and $ClassName=~/\A(std::|__cxxabi)/);
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04008432 if($CompleteSignature{$LibVersion}{$Symbol}{"Destructor"}
8433 and $Symbol=~/D2E/)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008434 { # pure virtual D2-destructors are marked as "virt" in the dump
8435 # virtual D2-destructors are NOT marked as "virt" in the dump
8436 # both destructors are not presented in the v-table
8437 next;
8438 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04008439 my ($MnglName, $VersionSpec, $SymbolVersion) = separate_symbol($Symbol);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008440 $VirtualTable{$LibVersion}{$ClassName}{$MnglName} = 1;
8441 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008442 }
8443}
8444
8445sub registerOverriding($)
8446{
8447 my $LibVersion = $_[0];
8448 my @Classes = keys(%{$VirtualTable{$LibVersion}});
Andrey Ponomarenko85043792012-05-14 16:48:07 +04008449 @Classes = sort {int($TName_Tid{$LibVersion}{$a})<=>int($TName_Tid{$LibVersion}{$b})} @Classes;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008450 foreach my $ClassName (@Classes)
8451 {
8452 foreach my $VirtFunc (keys(%{$VirtualTable{$LibVersion}{$ClassName}}))
8453 {
Andrey Ponomarenko16934472012-03-29 15:37:04 +04008454 if($CompleteSignature{$LibVersion}{$VirtFunc}{"PureVirt"})
8455 { # pure virtuals
8456 next;
8457 }
8458 my $ClassId = $TName_Tid{$LibVersion}{$ClassName};
8459 if(my $Overridden = findMethod($VirtFunc, $ClassId, $LibVersion))
Andrey Ponomarenko85043792012-05-14 16:48:07 +04008460 {
8461 if($CompleteSignature{$LibVersion}{$Overridden}{"Virt"}
8462 or $CompleteSignature{$LibVersion}{$Overridden}{"PureVirt"})
8463 { # both overridden virtual methods
8464 # and implemented pure virtual methods
8465 $CompleteSignature{$LibVersion}{$VirtFunc}{"Override"} = $Overridden;
8466 $OverriddenMethods{$LibVersion}{$Overridden}{$VirtFunc} = 1;
8467 delete($VirtualTable{$LibVersion}{$ClassName}{$VirtFunc}); # remove from v-table model
8468 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008469 }
8470 }
8471 if(not keys(%{$VirtualTable{$LibVersion}{$ClassName}})) {
8472 delete($VirtualTable{$LibVersion}{$ClassName});
8473 }
8474 }
8475}
8476
8477sub setVirtFuncPositions($)
8478{
8479 my $LibVersion = $_[0];
8480 foreach my $ClassName (keys(%{$VirtualTable{$LibVersion}}))
8481 {
8482 my ($Num, $RelPos, $AbsNum) = (1, 0, 1);
8483 foreach my $VirtFunc (sort {int($CompleteSignature{$LibVersion}{$a}{"Line"}) <=> int($CompleteSignature{$LibVersion}{$b}{"Line"})}
8484 sort keys(%{$VirtualTable{$LibVersion}{$ClassName}}))
8485 {
Andrey Ponomarenko16934472012-03-29 15:37:04 +04008486 $VirtualTable{$LibVersion}{$ClassName}{$VirtFunc}=$Num++;
8487
8488 # set relative positions
8489 if(defined $VirtualTable{1}{$ClassName} and defined $VirtualTable{1}{$ClassName}{$VirtFunc}
8490 and defined $VirtualTable{2}{$ClassName} and defined $VirtualTable{2}{$ClassName}{$VirtFunc})
8491 { # relative position excluding added and removed virtual functions
8492 if(not $CompleteSignature{1}{$VirtFunc}{"Override"}
8493 and not $CompleteSignature{2}{$VirtFunc}{"Override"}) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008494 $CompleteSignature{$LibVersion}{$VirtFunc}{"RelPos"} = $RelPos++;
8495 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008496 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008497 }
8498 }
Andrey Ponomarenko16934472012-03-29 15:37:04 +04008499 foreach my $ClassName (keys(%{$ClassNames{$LibVersion}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008500 {
8501 my $AbsNum = 1;
Andrey Ponomarenko16934472012-03-29 15:37:04 +04008502 foreach my $VirtFunc (getVTable_Model($TName_Tid{$LibVersion}{$ClassName}, $LibVersion)) {
8503 $VirtualTable_Model{$LibVersion}{$ClassName}{$VirtFunc}=$AbsNum++;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008504 }
8505 }
8506}
8507
8508sub get_sub_classes($$$)
8509{
8510 my ($ClassId, $LibVersion, $Recursive) = @_;
8511 return () if(not defined $Class_SubClasses{$LibVersion}{$ClassId});
8512 my @Subs = ();
8513 foreach my $SubId (keys(%{$Class_SubClasses{$LibVersion}{$ClassId}}))
8514 {
Andrey Ponomarenko16934472012-03-29 15:37:04 +04008515 if($Recursive)
8516 {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008517 foreach my $SubSubId (get_sub_classes($SubId, $LibVersion, $Recursive)) {
8518 push(@Subs, $SubSubId);
8519 }
8520 }
8521 push(@Subs, $SubId);
8522 }
8523 return @Subs;
8524}
8525
8526sub get_base_classes($$$)
8527{
8528 my ($ClassId, $LibVersion, $Recursive) = @_;
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04008529 my %ClassType = get_Type($ClassId, $LibVersion);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008530 return () if(not defined $ClassType{"Base"});
8531 my @Bases = ();
8532 foreach my $BaseId (sort {int($ClassType{"Base"}{$a}{"pos"})<=>int($ClassType{"Base"}{$b}{"pos"})}
8533 keys(%{$ClassType{"Base"}}))
8534 {
Andrey Ponomarenko16934472012-03-29 15:37:04 +04008535 if($Recursive)
8536 {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008537 foreach my $SubBaseId (get_base_classes($BaseId, $LibVersion, $Recursive)) {
8538 push(@Bases, $SubBaseId);
8539 }
8540 }
8541 push(@Bases, $BaseId);
8542 }
8543 return @Bases;
8544}
8545
Andrey Ponomarenko16934472012-03-29 15:37:04 +04008546sub getVTable_Model($$)
8547{ # return an ordered list of v-table elements
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008548 my ($ClassId, $LibVersion) = @_;
8549 my @Bases = get_base_classes($ClassId, $LibVersion, 1);
8550 my @Elements = ();
8551 foreach my $BaseId (@Bases, $ClassId)
8552 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04008553 if(my $BName = $TypeInfo{$LibVersion}{$BaseId}{"Name"})
Andrey Ponomarenko85043792012-05-14 16:48:07 +04008554 {
8555 if(defined $VirtualTable{$LibVersion}{$BName})
8556 {
8557 my @VFunctions = keys(%{$VirtualTable{$LibVersion}{$BName}});
8558 @VFunctions = sort {int($CompleteSignature{$LibVersion}{$a}{"Line"}) <=> int($CompleteSignature{$LibVersion}{$b}{"Line"})} @VFunctions;
8559 foreach my $VFunc (@VFunctions) {
8560 push(@Elements, $VFunc);
8561 }
8562 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008563 }
8564 }
8565 return @Elements;
8566}
8567
8568sub getVShift($$)
8569{
8570 my ($ClassId, $LibVersion) = @_;
8571 my @Bases = get_base_classes($ClassId, $LibVersion, 1);
8572 my $VShift = 0;
8573 foreach my $BaseId (@Bases)
8574 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04008575 if(my $BName = $TypeInfo{$LibVersion}{$BaseId}{"Name"})
Andrey Ponomarenko85043792012-05-14 16:48:07 +04008576 {
8577 if(defined $VirtualTable{$LibVersion}{$BName}) {
8578 $VShift+=keys(%{$VirtualTable{$LibVersion}{$BName}});
8579 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008580 }
8581 }
8582 return $VShift;
8583}
8584
8585sub getShift($$)
8586{
8587 my ($ClassId, $LibVersion) = @_;
8588 my @Bases = get_base_classes($ClassId, $LibVersion, 0);
8589 my $Shift = 0;
8590 foreach my $BaseId (@Bases)
8591 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04008592 if(my $Size = $TypeInfo{$LibVersion}{$BaseId}{"Size"})
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04008593 {
8594 if($Size!=1)
8595 { # not empty base class
8596 $Shift+=$Size;
8597 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008598 }
8599 }
8600 return $Shift;
8601}
8602
Andrey Ponomarenko16934472012-03-29 15:37:04 +04008603sub getVTable_Size($$)
8604{ # number of v-table elements
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008605 my ($ClassName, $LibVersion) = @_;
Andrey Ponomarenko16934472012-03-29 15:37:04 +04008606 my $Size = 0;
8607 # three approaches
8608 if(not $Size)
8609 { # real size
8610 if(my %VTable = getVTable_Real($ClassName, $LibVersion)) {
8611 $Size = keys(%VTable);
8612 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008613 }
Andrey Ponomarenko16934472012-03-29 15:37:04 +04008614 if(not $Size)
8615 { # shared library symbol size
8616 if($Size = getSymbolSize($ClassVTable{$ClassName}, $LibVersion)) {
8617 $Size /= $WORD_SIZE{$LibVersion};
8618 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008619 }
Andrey Ponomarenko16934472012-03-29 15:37:04 +04008620 if(not $Size)
8621 { # model size
8622 if(defined $VirtualTable_Model{$LibVersion}{$ClassName}) {
8623 $Size = keys(%{$VirtualTable_Model{$LibVersion}{$ClassName}}) + 2;
8624 }
8625 }
8626 return $Size;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008627}
8628
8629sub isCopyingClass($$)
8630{
8631 my ($TypeId, $LibVersion) = @_;
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04008632 return $TypeInfo{$LibVersion}{$TypeId}{"Copied"};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008633}
8634
8635sub isLeafClass($$)
8636{
8637 my ($ClassId, $LibVersion) = @_;
8638 return (not keys(%{$Class_SubClasses{$LibVersion}{$ClassId}}));
8639}
8640
8641sub havePubFields($)
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04008642{ # check structured type for public fields
8643 return isAccessible($_[0], {}, 0, -1);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008644}
8645
8646sub isAccessible($$$$)
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04008647{ # check interval in structured type for public fields
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008648 my ($TypePtr, $Skip, $Start, $End) = @_;
8649 return 0 if(not $TypePtr);
8650 if($End==-1) {
8651 $End = keys(%{$TypePtr->{"Memb"}})-1;
8652 }
8653 foreach my $MemPos (keys(%{$TypePtr->{"Memb"}}))
8654 {
8655 if($Skip and $Skip->{$MemPos})
8656 { # skip removed/added fields
8657 next;
8658 }
8659 if(int($MemPos)>=$Start and int($MemPos)<=$End)
8660 {
8661 if(isPublic($TypePtr, $MemPos)) {
8662 return ($MemPos+1);
8663 }
8664 }
8665 }
8666 return 0;
8667}
8668
8669sub getAlignment($$$)
8670{
8671 my ($Pos, $TypePtr, $LibVersion) = @_;
8672 my $Tid = $TypePtr->{"Memb"}{$Pos}{"type"};
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04008673 my %Type = get_PureType($Tid, $LibVersion);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008674 my $TSize = $Type{"Size"}*$BYTE_SIZE;
8675 my $MSize = $Type{"Size"}*$BYTE_SIZE;
8676 if(my $BSize = $TypePtr->{"Memb"}{$Pos}{"bitfield"})
8677 { # bitfields
8678 ($TSize, $MSize) = ($WORD_SIZE{$LibVersion}*$BYTE_SIZE, $BSize);
8679 }
8680 elsif($Type{"Type"} eq "Array")
8681 { # in the context of function parameter
8682 # it's passed through the pointer
8683 }
8684 # alignment
8685 my $Alignment = $WORD_SIZE{$LibVersion}*$BYTE_SIZE; # default
8686 if(my $Computed = $TypePtr->{"Memb"}{$Pos}{"algn"})
8687 { # computed by GCC
8688 $Alignment = $Computed*$BYTE_SIZE;
8689 }
8690 elsif($TypePtr->{"Memb"}{$Pos}{"bitfield"})
8691 { # bitfields are 1 bit aligned
8692 $Alignment = 1;
8693 }
8694 elsif($TSize and $TSize<$WORD_SIZE{$LibVersion}*$BYTE_SIZE)
8695 { # model
8696 $Alignment = $TSize;
8697 }
8698 return ($Alignment, $MSize);
8699}
8700
8701sub getOffset($$$)
8702{ # offset of the field including padding
8703 my ($FieldPos, $TypePtr, $LibVersion) = @_;
8704 my $Offset = 0;
8705 foreach my $Pos (0 .. keys(%{$TypePtr->{"Memb"}})-1)
8706 {
8707 my ($Alignment, $MSize) = getAlignment($Pos, $TypePtr, $LibVersion);
8708 # padding
8709 my $Padding = 0;
8710 if($Offset % $Alignment!=0)
8711 { # not aligned, add padding
8712 $Padding = $Alignment - $Offset % $Alignment;
8713 }
8714 $Offset += $Padding;
8715 if($Pos==$FieldPos)
8716 { # after the padding
8717 # before the field
8718 return $Offset;
8719 }
8720 $Offset += $MSize;
8721 }
8722 return $FieldPos;# if something is going wrong
8723}
8724
8725sub isMemPadded($$$$$)
8726{ # check if the target field can be added/removed/changed
8727 # without shifting other fields because of padding bits
8728 my ($FieldPos, $Size, $TypePtr, $Skip, $LibVersion) = @_;
8729 return 0 if($FieldPos==0);
8730 if(defined $TypePtr->{"Memb"}{""})
8731 {
8732 delete($TypePtr->{"Memb"}{""});
8733 if($Debug) {
8734 printMsg("WARNING", "internal error detected");
8735 }
8736 }
8737 my $Offset = 0;
8738 my (%Alignment, %MSize) = ();
8739 my $MaxAlgn = 0;
8740 my $End = keys(%{$TypePtr->{"Memb"}})-1;
8741 my $NextField = $FieldPos+1;
8742 foreach my $Pos (0 .. $End)
8743 {
8744 if($Skip and $Skip->{$Pos})
8745 { # skip removed/added fields
8746 if($Pos > $FieldPos)
8747 { # after the target
8748 $NextField += 1;
8749 next;
8750 }
8751 }
8752 ($Alignment{$Pos}, $MSize{$Pos}) = getAlignment($Pos, $TypePtr, $LibVersion);
8753 if($Alignment{$Pos}>$MaxAlgn) {
8754 $MaxAlgn = $Alignment{$Pos};
8755 }
8756 if($Pos==$FieldPos)
8757 {
8758 if($Size==-1)
8759 { # added/removed fields
8760 if($Pos!=$End)
8761 { # skip target field and see
8762 # if enough padding will be
8763 # created on the next step
8764 # to include this field
8765 next;
8766 }
8767 }
8768 }
8769 # padding
8770 my $Padding = 0;
8771 if($Offset % $Alignment{$Pos}!=0)
8772 { # not aligned, add padding
8773 $Padding = $Alignment{$Pos} - $Offset % $Alignment{$Pos};
8774 }
8775 if($Pos==$NextField)
8776 { # try to place target field in the padding
8777 if($Size==-1)
8778 { # added/removed fields
8779 my $TPadding = 0;
8780 if($Offset % $Alignment{$FieldPos}!=0)
8781 {# padding of the target field
8782 $TPadding = $Alignment{$FieldPos} - $Offset % $Alignment{$FieldPos};
8783 }
8784 if($TPadding+$MSize{$FieldPos}<=$Padding)
8785 { # enough padding to place target field
8786 return 1;
8787 }
8788 else {
8789 return 0;
8790 }
8791 }
8792 else
8793 { # changed fields
8794 my $Delta = $Size-$MSize{$FieldPos};
8795 if($Delta>=0)
8796 { # increased
8797 if($Size-$MSize{$FieldPos}<=$Padding)
8798 { # enough padding to change target field
8799 return 1;
8800 }
8801 else {
8802 return 0;
8803 }
8804 }
8805 else
8806 { # decreased
8807 $Delta = abs($Delta);
8808 if($Delta+$Padding>=$MSize{$Pos})
8809 { # try to place the next field
8810 if(($Offset-$Delta) % $Alignment{$Pos} != 0)
8811 { # padding of the next field in new place
8812 my $NPadding = $Alignment{$Pos} - ($Offset-$Delta) % $Alignment{$Pos};
8813 if($NPadding+$MSize{$Pos}<=$Delta+$Padding)
8814 { # enough delta+padding to store next field
8815 return 0;
8816 }
8817 }
8818 else
8819 {
8820 return 0;
8821 }
8822 }
8823 return 1;
8824 }
8825 }
8826 }
8827 elsif($Pos==$End)
8828 { # target field is the last field
8829 if($Size==-1)
8830 { # added/removed fields
8831 if($Offset % $MaxAlgn!=0)
8832 { # tail padding
8833 my $TailPadding = $MaxAlgn - $Offset % $MaxAlgn;
8834 if($Padding+$MSize{$Pos}<=$TailPadding)
8835 { # enough tail padding to place the last field
8836 return 1;
8837 }
8838 }
8839 return 0;
8840 }
8841 else
8842 { # changed fields
8843 # scenario #1
8844 my $Offset1 = $Offset+$Padding+$MSize{$Pos};
8845 if($Offset1 % $MaxAlgn != 0)
8846 { # tail padding
8847 $Offset1 += $MaxAlgn - $Offset1 % $MaxAlgn;
8848 }
8849 # scenario #2
8850 my $Offset2 = $Offset+$Padding+$Size;
8851 if($Offset2 % $MaxAlgn != 0)
8852 { # tail padding
8853 $Offset2 += $MaxAlgn - $Offset2 % $MaxAlgn;
8854 }
8855 if($Offset1!=$Offset2)
8856 { # different sizes of structure
8857 return 0;
8858 }
8859 return 1;
8860 }
8861 }
8862 $Offset += $Padding+$MSize{$Pos};
8863 }
8864 return 0;
8865}
8866
8867sub isReserved($)
8868{ # reserved fields == private
8869 my $MName = $_[0];
8870 if($MName=~/reserved|padding|f_spare/i) {
8871 return 1;
8872 }
8873 if($MName=~/\A[_]*(spare|pad|unused)[_]*\Z/i) {
8874 return 1;
8875 }
8876 if($MName=~/(pad\d+)/i) {
8877 return 1;
8878 }
8879 return 0;
8880}
8881
8882sub isPublic($$)
8883{
8884 my ($TypePtr, $FieldPos) = @_;
8885 return 0 if(not $TypePtr);
8886 return 0 if(not defined $TypePtr->{"Memb"}{$FieldPos});
8887 return 0 if(not defined $TypePtr->{"Memb"}{$FieldPos}{"name"});
8888 if(not $TypePtr->{"Memb"}{$FieldPos}{"access"})
8889 { # by name in C language
8890 # FIXME: add other methods to detect private members
8891 my $MName = $TypePtr->{"Memb"}{$FieldPos}{"name"};
8892 if($MName=~/priv|abidata|parent_object/i)
8893 { # C-styled private data
8894 return 0;
8895 }
8896 if(lc($MName) eq "abi")
8897 { # ABI information/reserved field
8898 return 0;
8899 }
8900 if(isReserved($MName))
8901 { # reserved fields
8902 return 0;
8903 }
8904 return 1;
8905 }
8906 elsif($TypePtr->{"Memb"}{$FieldPos}{"access"} ne "private")
8907 { # by access in C++ language
8908 return 1;
8909 }
8910 return 0;
8911}
8912
Andrey Ponomarenko16934472012-03-29 15:37:04 +04008913sub getVTable_Real($$)
8914{
8915 my ($ClassName, $LibVersion) = @_;
8916 if(my $ClassId = $TName_Tid{$LibVersion}{$ClassName})
8917 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04008918 my %Type = get_Type($ClassId, $LibVersion);
Andrey Ponomarenko16934472012-03-29 15:37:04 +04008919 if(defined $Type{"VTable"}) {
8920 return %{$Type{"VTable"}};
8921 }
8922 }
8923 return ();
8924}
8925
8926sub cmpVTables($)
8927{
8928 my $ClassName = $_[0];
8929 my $Res = cmpVTables_Real($ClassName, 1);
8930 if($Res==-1) {
8931 $Res = cmpVTables_Model($ClassName);
8932 }
8933 return $Res;
8934}
8935
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008936sub cmpVTables_Model($)
8937{
8938 my $ClassName = $_[0];
Andrey Ponomarenko16934472012-03-29 15:37:04 +04008939 foreach my $Symbol (keys(%{$VirtualTable_Model{1}{$ClassName}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008940 {
Andrey Ponomarenko16934472012-03-29 15:37:04 +04008941 if(not defined $VirtualTable_Model{2}{$ClassName}{$Symbol}) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008942 return 1;
8943 }
8944 }
8945 return 0;
8946}
8947
Andrey Ponomarenko16934472012-03-29 15:37:04 +04008948sub cmpVTables_Real($$)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008949{
8950 my ($ClassName, $Strong) = @_;
Andrey Ponomarenko16934472012-03-29 15:37:04 +04008951 if(defined $Cache{"cmpVTables_Real"}{$Strong}{$ClassName}) {
8952 return $Cache{"cmpVTables_Real"}{$Strong}{$ClassName};
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04008953 }
Andrey Ponomarenko16934472012-03-29 15:37:04 +04008954 my %VTable_Old = getVTable_Real($ClassName, 1);
8955 my %VTable_New = getVTable_Real($ClassName, 2);
8956 if(not %VTable_Old or not %VTable_New)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008957 { # old ABI dumps
Andrey Ponomarenko16934472012-03-29 15:37:04 +04008958 return ($Cache{"cmpVTables_Real"}{$Strong}{$ClassName} = -1);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008959 }
Andrey Ponomarenko16934472012-03-29 15:37:04 +04008960 my %Indexes = map {$_=>1} (keys(%VTable_Old), keys(%VTable_New));
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008961 foreach my $Offset (sort {int($a)<=>int($b)} keys(%Indexes))
8962 {
Andrey Ponomarenko16934472012-03-29 15:37:04 +04008963 if(not defined $VTable_Old{$Offset})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008964 { # v-table v.1 < v-table v.2
Andrey Ponomarenko16934472012-03-29 15:37:04 +04008965 return ($Cache{"cmpVTables_Real"}{$Strong}{$ClassName} = $Strong);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008966 }
Andrey Ponomarenko16934472012-03-29 15:37:04 +04008967 my $Entry1 = $VTable_Old{$Offset};
8968 if(not defined $VTable_New{$Offset})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008969 { # v-table v.1 > v-table v.2
Andrey Ponomarenko16934472012-03-29 15:37:04 +04008970 return ($Cache{"cmpVTables_Real"}{$Strong}{$ClassName} = ($Strong or $Entry1!~/__cxa_pure_virtual/));
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008971 }
Andrey Ponomarenko16934472012-03-29 15:37:04 +04008972 my $Entry2 = $VTable_New{$Offset};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008973 $Entry1 = simpleVEntry($Entry1);
8974 $Entry2 = simpleVEntry($Entry2);
8975 if($Entry1 ne $Entry2)
8976 { # register as changed
8977 if($Entry1=~/::([^:]+)\Z/)
8978 {
8979 my $M1 = $1;
8980 if($Entry2=~/::([^:]+)\Z/)
8981 {
8982 my $M2 = $1;
8983 if($M1 eq $M2)
8984 { # overridden
8985 next;
8986 }
8987 }
8988 }
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04008989 if(differentDumps("G"))
8990 {
8991 if($Entry1=~/\A\-(0x|\d+)/ and $Entry2=~/\A\-(0x|\d+)/)
8992 {
8993 # GCC 4.6.1: -0x00000000000000010
8994 # GCC 4.7.0: -16
8995 next;
8996 }
8997 }
Andrey Ponomarenko16934472012-03-29 15:37:04 +04008998 return ($Cache{"cmpVTables_Real"}{$Strong}{$ClassName} = 1);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008999 }
9000 }
Andrey Ponomarenko16934472012-03-29 15:37:04 +04009001 return ($Cache{"cmpVTables_Real"}{$Strong}{$ClassName} = 0);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009002}
9003
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04009004sub mergeVTables($)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009005{ # merging v-tables without diagnostics
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04009006 my $Level = $_[0];
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009007 foreach my $ClassName (keys(%{$VirtualTable{1}}))
9008 {
Andrey Ponomarenko16934472012-03-29 15:37:04 +04009009 if($VTableChanged_M{$ClassName})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009010 { # already registered
9011 next;
9012 }
Andrey Ponomarenko16934472012-03-29 15:37:04 +04009013 if(cmpVTables_Real($ClassName, 0)==1)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009014 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04009015 my @Affected = (keys(%{$ClassMethods{$Level}{1}{$ClassName}}));
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009016 foreach my $Symbol (@Affected)
9017 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04009018 %{$CompatProblems{$Level}{$Symbol}{"Virtual_Table_Changed_Unknown"}{$ClassName}}=(
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009019 "Type_Name"=>$ClassName,
9020 "Type_Type"=>"Class",
9021 "Target"=>$ClassName);
9022 }
9023 }
9024 }
9025}
9026
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04009027sub mergeBases($)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009028{
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04009029 my $Level = $_[0];
Andrey Ponomarenko16934472012-03-29 15:37:04 +04009030 foreach my $ClassName (keys(%{$ClassNames{1}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009031 { # detect added and removed virtual functions
Andrey Ponomarenko16934472012-03-29 15:37:04 +04009032 my $ClassId = $TName_Tid{1}{$ClassName};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009033 next if(not $ClassId);
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04009034 if(defined $VirtualTable{2}{$ClassName})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009035 {
Andrey Ponomarenko16934472012-03-29 15:37:04 +04009036 foreach my $Symbol (keys(%{$VirtualTable{2}{$ClassName}}))
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04009037 {
Andrey Ponomarenko16934472012-03-29 15:37:04 +04009038 if($TName_Tid{1}{$ClassName}
9039 and not defined $VirtualTable{1}{$ClassName}{$Symbol})
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04009040 { # added to v-table
Andrey Ponomarenko16934472012-03-29 15:37:04 +04009041 if(defined $CompleteSignature{1}{$Symbol}
9042 and $CompleteSignature{1}{$Symbol}{"Virt"})
9043 { # override some method in v.1
9044 next;
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04009045 }
Andrey Ponomarenko16934472012-03-29 15:37:04 +04009046 $AddedInt_Virt{$Level}{$ClassName}{$Symbol} = 1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009047 }
9048 }
9049 }
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04009050 if(defined $VirtualTable{1}{$ClassName})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009051 {
Andrey Ponomarenko16934472012-03-29 15:37:04 +04009052 foreach my $Symbol (keys(%{$VirtualTable{1}{$ClassName}}))
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04009053 {
Andrey Ponomarenko16934472012-03-29 15:37:04 +04009054 if($TName_Tid{2}{$ClassName}
9055 and not defined $VirtualTable{2}{$ClassName}{$Symbol})
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04009056 { # removed from v-table
Andrey Ponomarenko16934472012-03-29 15:37:04 +04009057 if(defined $CompleteSignature{2}{$Symbol}
9058 and $CompleteSignature{2}{$Symbol}{"Virt"})
9059 { # override some method in v.2
9060 next;
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04009061 }
Andrey Ponomarenko16934472012-03-29 15:37:04 +04009062 $RemovedInt_Virt{$Level}{$ClassName}{$Symbol} = 1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009063 }
9064 }
9065 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04009066 if($Level eq "Binary")
9067 { # Binary-level
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04009068 my %Class_Type = get_Type($ClassId, 1);
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04009069 foreach my $AddedVFunc (keys(%{$AddedInt_Virt{$Level}{$ClassName}}))
9070 { # check replacements, including pure virtual methods
9071 my $AddedPos = $VirtualTable{2}{$ClassName}{$AddedVFunc};
9072 foreach my $RemovedVFunc (keys(%{$RemovedInt_Virt{$Level}{$ClassName}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009073 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04009074 my $RemovedPos = $VirtualTable{1}{$ClassName}{$RemovedVFunc};
9075 if($AddedPos==$RemovedPos)
9076 {
9077 $VirtualReplacement{$AddedVFunc} = $RemovedVFunc;
9078 $VirtualReplacement{$RemovedVFunc} = $AddedVFunc;
9079 last; # other methods will be reported as "added" or "removed"
9080 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009081 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04009082 if(my $RemovedVFunc = $VirtualReplacement{$AddedVFunc})
9083 {
9084 if(lc($AddedVFunc) eq lc($RemovedVFunc))
9085 { # skip: DomUi => DomUI parameter (Qt 4.2.3 to 4.3.0)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009086 next;
9087 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04009088 my $ProblemType = "Virtual_Replacement";
9089 my @Affected = ($RemovedVFunc);
9090 if($CompleteSignature{1}{$RemovedVFunc}{"PureVirt"})
9091 { # pure methods
9092 if(not isUsedClass($ClassId, 1, $Level))
9093 { # not a parameter of some exported method
9094 next;
9095 }
9096 $ProblemType = "Pure_Virtual_Replacement";
9097 @Affected = (keys(%{$ClassMethods{$Level}{1}{$ClassName}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009098 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04009099 foreach my $AffectedInt (@Affected)
9100 {
9101 if($CompleteSignature{1}{$AffectedInt}{"PureVirt"})
9102 { # affected exported methods only
9103 next;
9104 }
9105 %{$CompatProblems{$Level}{$AffectedInt}{$ProblemType}{$tr_name{$AddedVFunc}}}=(
9106 "Type_Name"=>$Class_Type{"Name"},
9107 "Type_Type"=>"Class",
9108 "Target"=>get_Signature($AddedVFunc, 2),
9109 "Old_Value"=>get_Signature($RemovedVFunc, 1));
9110 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009111 }
9112 }
9113 }
9114 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04009115 if(not checkDump(1, "2.0")
9116 or not checkDump(2, "2.0"))
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04009117 { # support for old ABI dumps
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009118 # "Base" attribute introduced in ACC 1.22 (dump 2.0 format)
9119 return;
9120 }
Andrey Ponomarenko16934472012-03-29 15:37:04 +04009121 foreach my $ClassName (sort keys(%{$ClassNames{1}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009122 {
Andrey Ponomarenko16934472012-03-29 15:37:04 +04009123 my $ClassId_Old = $TName_Tid{1}{$ClassName};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009124 next if(not $ClassId_Old);
9125 if(not isCreatable($ClassId_Old, 1))
9126 { # skip classes without public constructors (including auto-generated)
9127 # example: class has only a private exported or private inline constructor
9128 next;
9129 }
9130 if($ClassName=~/>/)
9131 { # skip affected template instances
9132 next;
9133 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04009134 my %Class_Old = get_Type($ClassId_Old, 1);
Andrey Ponomarenko16934472012-03-29 15:37:04 +04009135 my $ClassId_New = $TName_Tid{2}{$ClassName};
Andrey Ponomarenko85043792012-05-14 16:48:07 +04009136 if(not $ClassId_New) {
9137 next;
9138 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04009139 my %Class_New = get_Type($ClassId_New, 2);
Andrey Ponomarenko85043792012-05-14 16:48:07 +04009140 if($Class_New{"Type"}!~/Class|Struct/)
9141 { # became typedef
9142 if($Level eq "Binary") {
9143 next;
9144 }
9145 if($Level eq "Source")
9146 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04009147 %Class_New = get_PureType($ClassId_New, 2);
Andrey Ponomarenko85043792012-05-14 16:48:07 +04009148 if($Class_New{"Type"}!~/Class|Struct/) {
9149 next;
9150 }
9151 $ClassId_New = $Class_New{"Tid"};
9152 }
9153 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009154 my @Bases_Old = sort {$Class_Old{"Base"}{$a}{"pos"}<=>$Class_Old{"Base"}{$b}{"pos"}} keys(%{$Class_Old{"Base"}});
9155 my @Bases_New = sort {$Class_New{"Base"}{$a}{"pos"}<=>$Class_New{"Base"}{$b}{"pos"}} keys(%{$Class_New{"Base"}});
9156 my ($BNum1, $BNum2) = (1, 1);
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04009157 my %BasePos_Old = map {$TypeInfo{1}{$_}{"Name"} => $BNum1++} @Bases_Old;
9158 my %BasePos_New = map {$TypeInfo{2}{$_}{"Name"} => $BNum2++} @Bases_New;
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04009159 my %ShortBase_Old = map {get_ShortType($_, 1) => 1} @Bases_Old;
9160 my %ShortBase_New = map {get_ShortType($_, 2) => 1} @Bases_New;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009161 my $Shift_Old = getShift($ClassId_Old, 1);
9162 my $Shift_New = getShift($ClassId_New, 2);
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04009163 my %BaseId_New = map {$TypeInfo{2}{$_}{"Name"} => $_} @Bases_New;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009164 my ($Added, $Removed) = (0, 0);
9165 my @StableBases_Old = ();
9166 foreach my $BaseId (@Bases_Old)
9167 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04009168 my $BaseName = $TypeInfo{1}{$BaseId}{"Name"};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009169 if($BasePos_New{$BaseName}) {
9170 push(@StableBases_Old, $BaseId);
9171 }
9172 elsif(not $ShortBase_New{$BaseName}
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04009173 and not $ShortBase_New{get_ShortType($BaseId, 1)})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009174 { # removed base
9175 # excluding namespace::SomeClass to SomeClass renaming
9176 my $ProblemKind = "Removed_Base_Class";
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04009177 if($Level eq "Binary")
9178 { # Binary-level
9179 if($Shift_Old ne $Shift_New)
9180 { # affected fields
9181 if(havePubFields(\%Class_Old)) {
9182 $ProblemKind .= "_And_Shift";
9183 }
9184 elsif($Class_Old{"Size"} ne $Class_New{"Size"}) {
9185 $ProblemKind .= "_And_Size";
9186 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009187 }
Andrey Ponomarenko16934472012-03-29 15:37:04 +04009188 if(keys(%{$VirtualTable_Model{1}{$BaseName}})
9189 and cmpVTables($ClassName)==1)
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04009190 { # affected v-table
9191 $ProblemKind .= "_And_VTable";
Andrey Ponomarenko16934472012-03-29 15:37:04 +04009192 $VTableChanged_M{$ClassName}=1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009193 }
9194 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04009195 my @Affected = keys(%{$ClassMethods{$Level}{1}{$ClassName}});
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009196 foreach my $SubId (get_sub_classes($ClassId_Old, 1, 1))
9197 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04009198 my $SubName = $TypeInfo{1}{$SubId}{"Name"};
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04009199 push(@Affected, keys(%{$ClassMethods{$Level}{1}{$SubName}}));
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009200 if($ProblemKind=~/VTable/) {
Andrey Ponomarenko16934472012-03-29 15:37:04 +04009201 $VTableChanged_M{$SubName}=1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009202 }
9203 }
9204 foreach my $Interface (@Affected)
9205 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04009206 %{$CompatProblems{$Level}{$Interface}{$ProblemKind}{"this"}}=(
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009207 "Type_Name"=>$ClassName,
9208 "Type_Type"=>"Class",
9209 "Target"=>$BaseName,
9210 "Old_Size"=>$Class_Old{"Size"}*$BYTE_SIZE,
9211 "New_Size"=>$Class_New{"Size"}*$BYTE_SIZE,
9212 "Shift"=>abs($Shift_New-$Shift_Old) );
9213 }
9214 $Removed+=1;
9215 }
9216 }
9217 my @StableBases_New = ();
9218 foreach my $BaseId (@Bases_New)
9219 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04009220 my $BaseName = $TypeInfo{2}{$BaseId}{"Name"};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009221 if($BasePos_Old{$BaseName}) {
9222 push(@StableBases_New, $BaseId);
9223 }
9224 elsif(not $ShortBase_Old{$BaseName}
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04009225 and not $ShortBase_Old{get_ShortType($BaseId, 2)})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009226 { # added base
9227 # excluding namespace::SomeClass to SomeClass renaming
9228 my $ProblemKind = "Added_Base_Class";
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04009229 if($Level eq "Binary")
9230 { # Binary-level
9231 if($Shift_Old ne $Shift_New)
9232 { # affected fields
9233 if(havePubFields(\%Class_Old)) {
9234 $ProblemKind .= "_And_Shift";
9235 }
9236 elsif($Class_Old{"Size"} ne $Class_New{"Size"}) {
9237 $ProblemKind .= "_And_Size";
9238 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009239 }
Andrey Ponomarenko16934472012-03-29 15:37:04 +04009240 if(keys(%{$VirtualTable_Model{2}{$BaseName}})
9241 and cmpVTables($ClassName)==1)
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04009242 { # affected v-table
9243 $ProblemKind .= "_And_VTable";
Andrey Ponomarenko16934472012-03-29 15:37:04 +04009244 $VTableChanged_M{$ClassName}=1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009245 }
9246 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04009247 my @Affected = keys(%{$ClassMethods{$Level}{1}{$ClassName}});
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009248 foreach my $SubId (get_sub_classes($ClassId_Old, 1, 1))
9249 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04009250 my $SubName = $TypeInfo{1}{$SubId}{"Name"};
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04009251 push(@Affected, keys(%{$ClassMethods{$Level}{1}{$SubName}}));
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009252 if($ProblemKind=~/VTable/) {
Andrey Ponomarenko16934472012-03-29 15:37:04 +04009253 $VTableChanged_M{$SubName}=1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009254 }
9255 }
9256 foreach my $Interface (@Affected)
9257 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04009258 %{$CompatProblems{$Level}{$Interface}{$ProblemKind}{"this"}}=(
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009259 "Type_Name"=>$ClassName,
9260 "Type_Type"=>"Class",
9261 "Target"=>$BaseName,
9262 "Old_Size"=>$Class_Old{"Size"}*$BYTE_SIZE,
9263 "New_Size"=>$Class_New{"Size"}*$BYTE_SIZE,
9264 "Shift"=>abs($Shift_New-$Shift_Old) );
9265 }
9266 $Added+=1;
9267 }
9268 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04009269 if($Level eq "Binary")
9270 { # Binary-level
9271 ($BNum1, $BNum2) = (1, 1);
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04009272 my %BaseRelPos_Old = map {$TypeInfo{1}{$_}{"Name"} => $BNum1++} @StableBases_Old;
9273 my %BaseRelPos_New = map {$TypeInfo{2}{$_}{"Name"} => $BNum2++} @StableBases_New;
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04009274 foreach my $BaseId (@Bases_Old)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009275 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04009276 my $BaseName = $TypeInfo{1}{$BaseId}{"Name"};
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04009277 if(my $NewPos = $BaseRelPos_New{$BaseName})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009278 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04009279 my $BaseNewId = $BaseId_New{$BaseName};
9280 my $OldPos = $BaseRelPos_Old{$BaseName};
9281 if($NewPos!=$OldPos)
9282 { # changed position of the base class
9283 foreach my $Interface (keys(%{$ClassMethods{$Level}{1}{$ClassName}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009284 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04009285 %{$CompatProblems{$Level}{$Interface}{"Base_Class_Position"}{"this"}}=(
9286 "Type_Name"=>$ClassName,
9287 "Type_Type"=>"Class",
9288 "Target"=>$BaseName,
9289 "Old_Value"=>$OldPos-1,
9290 "New_Value"=>$NewPos-1 );
9291 }
9292 }
9293 if($Class_Old{"Base"}{$BaseId}{"virtual"}
9294 and not $Class_New{"Base"}{$BaseNewId}{"virtual"})
9295 { # became non-virtual base
9296 foreach my $Interface (keys(%{$ClassMethods{$Level}{1}{$ClassName}}))
9297 {
9298 %{$CompatProblems{$Level}{$Interface}{"Base_Class_Became_Non_Virtually_Inherited"}{"this->".$BaseName}}=(
9299 "Type_Name"=>$ClassName,
9300 "Type_Type"=>"Class",
9301 "Target"=>$BaseName );
9302 }
9303 }
9304 elsif(not $Class_Old{"Base"}{$BaseId}{"virtual"}
9305 and $Class_New{"Base"}{$BaseNewId}{"virtual"})
9306 { # became virtual base
9307 foreach my $Interface (keys(%{$ClassMethods{$Level}{1}{$ClassName}}))
9308 {
9309 %{$CompatProblems{$Level}{$Interface}{"Base_Class_Became_Virtually_Inherited"}{"this->".$BaseName}}=(
9310 "Type_Name"=>$ClassName,
9311 "Type_Type"=>"Class",
9312 "Target"=>$BaseName );
9313 }
9314 }
9315 }
9316 }
9317 # detect size changes in base classes
9318 if($Shift_Old!=$Shift_New)
9319 { # size of allocable class
9320 foreach my $BaseId (@StableBases_Old)
9321 { # search for changed base
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04009322 my %BaseType = get_Type($BaseId, 1);
9323 my $Size_Old = $TypeInfo{1}{$BaseId}{"Size"};
9324 my $Size_New = $TypeInfo{2}{$BaseId_New{$BaseType{"Name"}}}{"Size"};
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04009325 if($Size_Old ne $Size_New
9326 and $Size_Old and $Size_New)
9327 {
9328 my $ProblemType = "";
9329 if(isCopyingClass($BaseId, 1)) {
9330 $ProblemType = "Size_Of_Copying_Class";
9331 }
9332 elsif($AllocableClass{1}{$BaseType{"Name"}})
9333 {
9334 if($Size_New>$Size_Old)
9335 { # increased size
9336 $ProblemType = "Size_Of_Allocable_Class_Increased";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009337 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04009338 else
9339 { # decreased size
9340 $ProblemType = "Size_Of_Allocable_Class_Decreased";
9341 if(not havePubFields(\%Class_Old))
9342 { # affected class has no public members
9343 next;
9344 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009345 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04009346 }
9347 next if(not $ProblemType);
9348 foreach my $Interface (keys(%{$ClassMethods{$Level}{1}{$ClassName}}))
9349 { # base class size changes affecting current class
9350 %{$CompatProblems{$Level}{$Interface}{$ProblemType}{"this->".$BaseType{"Name"}}}=(
9351 "Type_Name"=>$BaseType{"Name"},
9352 "Type_Type"=>"Class",
9353 "Target"=>$BaseType{"Name"},
9354 "Old_Size"=>$Size_Old*$BYTE_SIZE,
9355 "New_Size"=>$Size_New*$BYTE_SIZE );
9356 }
9357 }
9358 }
9359 }
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04009360 if(defined $VirtualTable{1}{$ClassName}
Andrey Ponomarenko16934472012-03-29 15:37:04 +04009361 and cmpVTables_Real($ClassName, 1)==1
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04009362 and my @VFunctions = keys(%{$VirtualTable{1}{$ClassName}}))
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04009363 { # compare virtual tables size in base classes
9364 my $VShift_Old = getVShift($ClassId_Old, 1);
9365 my $VShift_New = getVShift($ClassId_New, 2);
9366 if($VShift_Old ne $VShift_New)
9367 { # changes in the base class or changes in the list of base classes
9368 my @AllBases_Old = get_base_classes($ClassId_Old, 1, 1);
9369 my @AllBases_New = get_base_classes($ClassId_New, 2, 1);
9370 ($BNum1, $BNum2) = (1, 1);
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04009371 my %StableBase = map {$TypeInfo{2}{$_}{"Name"} => $_} @AllBases_New;
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04009372 foreach my $BaseId (@AllBases_Old)
9373 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04009374 my %BaseType = get_Type($BaseId, 1);
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04009375 if(not $StableBase{$BaseType{"Name"}})
9376 { # lost base
9377 next;
9378 }
Andrey Ponomarenko16934472012-03-29 15:37:04 +04009379 my $VSize_Old = getVTable_Size($BaseType{"Name"}, 1);
9380 my $VSize_New = getVTable_Size($BaseType{"Name"}, 2);
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04009381 if($VSize_Old!=$VSize_New)
9382 {
Andrey Ponomarenko85043792012-05-14 16:48:07 +04009383 foreach my $Symbol (@VFunctions)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009384 {
Andrey Ponomarenko85043792012-05-14 16:48:07 +04009385 if(not defined $VirtualTable{2}{$ClassName}{$Symbol})
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04009386 { # Removed_Virtual_Method, will be registered in mergeVirtualTables()
9387 next;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009388 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +04009389 if($VirtualTable_Model{2}{$ClassName}{$Symbol}-$VirtualTable_Model{1}{$ClassName}{$Symbol}==0)
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04009390 { # skip interfaces that have not changed the absolute virtual position
9391 next;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009392 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +04009393 if(not symbolFilter($Symbol, 1, "Affected", $Level)) {
9394 next;
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04009395 }
Andrey Ponomarenko16934472012-03-29 15:37:04 +04009396 $VTableChanged_M{$BaseType{"Name"}} = 1;
9397 $VTableChanged_M{$ClassName} = 1;
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04009398 foreach my $VirtFunc (keys(%{$AddedInt_Virt{$Level}{$BaseType{"Name"}}}))
9399 { # the reason of the layout change: added virtual functions
9400 next if($VirtualReplacement{$VirtFunc});
9401 my $ProblemType = "Added_Virtual_Method";
9402 if($CompleteSignature{2}{$VirtFunc}{"PureVirt"}) {
9403 $ProblemType = "Added_Pure_Virtual_Method";
9404 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +04009405 %{$CompatProblems{$Level}{$Symbol}{$ProblemType}{get_Signature($VirtFunc, 2)}}=(
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04009406 "Type_Name"=>$BaseType{"Name"},
9407 "Type_Type"=>"Class",
9408 "Target"=>get_Signature($VirtFunc, 2) );
9409 }
9410 foreach my $VirtFunc (keys(%{$RemovedInt_Virt{$Level}{$BaseType{"Name"}}}))
9411 { # the reason of the layout change: removed virtual functions
9412 next if($VirtualReplacement{$VirtFunc});
9413 my $ProblemType = "Removed_Virtual_Method";
9414 if($CompleteSignature{1}{$VirtFunc}{"PureVirt"}) {
9415 $ProblemType = "Removed_Pure_Virtual_Method";
9416 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +04009417 %{$CompatProblems{$Level}{$Symbol}{$ProblemType}{get_Signature($VirtFunc, 1)}}=(
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04009418 "Type_Name"=>$BaseType{"Name"},
9419 "Type_Type"=>"Class",
9420 "Target"=>get_Signature($VirtFunc, 1) );
9421 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009422 }
9423 }
9424 }
9425 }
9426 }
9427 }
9428 }
9429}
9430
9431sub isCreatable($$)
9432{
9433 my ($ClassId, $LibVersion) = @_;
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04009434 if($AllocableClass{$LibVersion}{$TypeInfo{$LibVersion}{$ClassId}{"Name"}}
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009435 or isCopyingClass($ClassId, $LibVersion)) {
9436 return 1;
9437 }
9438 if(keys(%{$Class_SubClasses{$LibVersion}{$ClassId}}))
9439 { # Fix for incomplete data: if this class has
9440 # a base class then it should also has a constructor
9441 return 1;
9442 }
9443 if($ReturnedClass{$LibVersion}{$ClassId})
9444 { # returned by some method of this class
9445 # or any other class
9446 return 1;
9447 }
9448 return 0;
9449}
9450
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04009451sub isUsedClass($$$)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009452{
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04009453 my ($ClassId, $LibVersion, $Level) = @_;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009454 if(keys(%{$ParamClass{$LibVersion}{$ClassId}}))
9455 { # parameter of some exported method
9456 return 1;
9457 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04009458 my $CName = $TypeInfo{$LibVersion}{$ClassId}{"Name"};
9459 if(keys(%{$ClassMethods{$Level}{$LibVersion}{$CName}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009460 { # method from target class
9461 return 1;
9462 }
9463 return 0;
9464}
9465
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04009466sub mergeVirtualTables($$)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009467{ # check for changes in the virtual table
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04009468 my ($Interface, $Level) = @_;
Andrey Ponomarenko16934472012-03-29 15:37:04 +04009469 # affected methods:
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009470 # - virtual
9471 # - pure-virtual
9472 # - non-virtual
9473 if($CompleteSignature{1}{$Interface}{"Data"})
9474 { # global data is not affected
9475 return;
9476 }
9477 my $Class_Id = $CompleteSignature{1}{$Interface}{"Class"};
Andrey Ponomarenko16934472012-03-29 15:37:04 +04009478 if(not $Class_Id) {
9479 return;
9480 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04009481 my $CName = $TypeInfo{1}{$Class_Id}{"Name"};
Andrey Ponomarenko16934472012-03-29 15:37:04 +04009482 if(cmpVTables_Real($CName, 1)==0)
9483 { # no changes
9484 return;
9485 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04009486 $CheckedTypes{$Level}{$CName} = 1;
9487 if($Level eq "Binary")
9488 { # Binary-level
9489 if($CompleteSignature{1}{$Interface}{"PureVirt"}
9490 and not isUsedClass($Class_Id, 1, $Level))
9491 { # pure virtuals should not be affected
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04009492 # if there are no exported methods using this class
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04009493 return;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009494 }
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04009495 }
9496 foreach my $Func (keys(%{$VirtualTable{1}{$CName}}))
9497 {
9498 if(defined $VirtualTable{2}{$CName}{$Func}
9499 and defined $CompleteSignature{2}{$Func})
9500 {
9501 if(not $CompleteSignature{1}{$Func}{"PureVirt"}
9502 and $CompleteSignature{2}{$Func}{"PureVirt"})
9503 { # became pure virtual
9504 %{$CompatProblems{$Level}{$Interface}{"Virtual_Method_Became_Pure"}{$tr_name{$Func}}}=(
9505 "Type_Name"=>$CName,
9506 "Type_Type"=>"Class",
9507 "Target"=>get_Signature_M($Func, 1) );
9508 $VTableChanged_M{$CName} = 1;
9509 }
9510 elsif($CompleteSignature{1}{$Func}{"PureVirt"}
9511 and not $CompleteSignature{2}{$Func}{"PureVirt"})
9512 { # became non-pure virtual
9513 %{$CompatProblems{$Level}{$Interface}{"Virtual_Method_Became_Non_Pure"}{$tr_name{$Func}}}=(
9514 "Type_Name"=>$CName,
9515 "Type_Type"=>"Class",
9516 "Target"=>get_Signature_M($Func, 1) );
9517 $VTableChanged_M{$CName} = 1;
9518 }
9519 }
9520 }
9521 if($Level eq "Binary")
9522 { # Binary-level
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04009523 # check virtual table structure
9524 foreach my $AddedVFunc (keys(%{$AddedInt_Virt{$Level}{$CName}}))
9525 {
9526 next if($Interface eq $AddedVFunc);
9527 next if($VirtualReplacement{$AddedVFunc});
9528 my $VPos_Added = $VirtualTable{2}{$CName}{$AddedVFunc};
9529 if($CompleteSignature{2}{$AddedVFunc}{"PureVirt"})
9530 { # pure virtual methods affect all others (virtual and non-virtual)
9531 %{$CompatProblems{$Level}{$Interface}{"Added_Pure_Virtual_Method"}{$tr_name{$AddedVFunc}}}=(
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009532 "Type_Name"=>$CName,
9533 "Type_Type"=>"Class",
9534 "Target"=>get_Signature($AddedVFunc, 2) );
Andrey Ponomarenko16934472012-03-29 15:37:04 +04009535 $VTableChanged_M{$CName} = 1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009536 }
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04009537 elsif(not defined $VirtualTable{1}{$CName}
9538 or $VPos_Added>keys(%{$VirtualTable{1}{$CName}}))
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04009539 { # added virtual function at the end of v-table
Andrey Ponomarenko16934472012-03-29 15:37:04 +04009540 if(not keys(%{$VirtualTable_Model{1}{$CName}}))
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04009541 { # became polymorphous class, added v-table pointer
9542 %{$CompatProblems{$Level}{$Interface}{"Added_First_Virtual_Method"}{$tr_name{$AddedVFunc}}}=(
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009543 "Type_Name"=>$CName,
9544 "Type_Type"=>"Class",
9545 "Target"=>get_Signature($AddedVFunc, 2) );
Andrey Ponomarenko16934472012-03-29 15:37:04 +04009546 $VTableChanged_M{$CName} = 1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009547 }
9548 else
9549 {
Andrey Ponomarenko16934472012-03-29 15:37:04 +04009550 my $VSize_Old = getVTable_Size($CName, 1);
9551 my $VSize_New = getVTable_Size($CName, 2);
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04009552 next if($VSize_Old==$VSize_New);# exception: register as removed and added virtual method
9553 if(isCopyingClass($Class_Id, 1))
9554 { # class has no constructors and v-table will be copied by applications, this may affect all methods
9555 my $ProblemType = "Added_Virtual_Method";
9556 if(isLeafClass($Class_Id, 1)) {
9557 $ProblemType = "Added_Virtual_Method_At_End_Of_Leaf_Copying_Class";
9558 }
9559 %{$CompatProblems{$Level}{$Interface}{$ProblemType}{$tr_name{$AddedVFunc}}}=(
9560 "Type_Name"=>$CName,
9561 "Type_Type"=>"Class",
9562 "Target"=>get_Signature($AddedVFunc, 2) );
Andrey Ponomarenko16934472012-03-29 15:37:04 +04009563 $VTableChanged_M{$CName} = 1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009564 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04009565 else
9566 {
9567 my $ProblemType = "Added_Virtual_Method";
9568 if(isLeafClass($Class_Id, 1)) {
9569 $ProblemType = "Added_Virtual_Method_At_End_Of_Leaf_Allocable_Class";
9570 }
9571 %{$CompatProblems{$Level}{$Interface}{$ProblemType}{$tr_name{$AddedVFunc}}}=(
9572 "Type_Name"=>$CName,
9573 "Type_Type"=>"Class",
9574 "Target"=>get_Signature($AddedVFunc, 2) );
Andrey Ponomarenko16934472012-03-29 15:37:04 +04009575 $VTableChanged_M{$CName} = 1;
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04009576 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009577 }
9578 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04009579 elsif($CompleteSignature{1}{$Interface}{"Virt"}
9580 or $CompleteSignature{1}{$Interface}{"PureVirt"})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009581 {
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04009582 if(defined $VirtualTable{1}{$CName}
9583 and defined $VirtualTable{2}{$CName})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009584 {
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04009585 my $VPos_Old = $VirtualTable{1}{$CName}{$Interface};
9586 my $VPos_New = $VirtualTable{2}{$CName}{$Interface};
9587 if($VPos_Added<=$VPos_Old and $VPos_Old!=$VPos_New)
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04009588 {
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04009589 my @Affected = ($Interface, keys(%{$OverriddenMethods{1}{$Interface}}));
9590 foreach my $ASymbol (@Affected)
9591 {
Andrey Ponomarenko85043792012-05-14 16:48:07 +04009592 if(not $CompleteSignature{1}{$ASymbol}{"PureVirt"})
9593 {
9594 if(symbolFilter($ASymbol, 1, "Affected", $Level)) {
9595 next;
9596 }
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04009597 }
9598 $CheckedSymbols{$Level}{$ASymbol} = 1;
9599 %{$CompatProblems{$Level}{$ASymbol}{"Added_Virtual_Method"}{$tr_name{$AddedVFunc}}}=(
9600 "Type_Name"=>$CName,
9601 "Type_Type"=>"Class",
9602 "Target"=>get_Signature($AddedVFunc, 2) );
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04009603 $VTableChanged_M{$TypeInfo{1}{$CompleteSignature{1}{$ASymbol}{"Class"}}{"Name"}} = 1;
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04009604 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009605 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009606 }
9607 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04009608 else {
9609 # safe
9610 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009611 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04009612 foreach my $RemovedVFunc (keys(%{$RemovedInt_Virt{$Level}{$CName}}))
9613 {
9614 next if($VirtualReplacement{$RemovedVFunc});
9615 if($RemovedVFunc eq $Interface
9616 and $CompleteSignature{1}{$RemovedVFunc}{"PureVirt"})
9617 { # This case is for removed virtual methods
9618 # implemented in both versions of a library
9619 next;
9620 }
Andrey Ponomarenko16934472012-03-29 15:37:04 +04009621 if(not keys(%{$VirtualTable_Model{2}{$CName}}))
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04009622 { # became non-polymorphous class, removed v-table pointer
9623 %{$CompatProblems{$Level}{$Interface}{"Removed_Last_Virtual_Method"}{$tr_name{$RemovedVFunc}}}=(
9624 "Type_Name"=>$CName,
9625 "Type_Type"=>"Class",
9626 "Target"=>get_Signature($RemovedVFunc, 1) );
Andrey Ponomarenko16934472012-03-29 15:37:04 +04009627 $VTableChanged_M{$CName} = 1;
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04009628 }
9629 elsif($CompleteSignature{1}{$Interface}{"Virt"}
9630 or $CompleteSignature{1}{$Interface}{"PureVirt"})
9631 {
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04009632 if(defined $VirtualTable{1}{$CName} and defined $VirtualTable{2}{$CName})
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04009633 {
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04009634 if(not defined $VirtualTable{1}{$CName}{$Interface}) {
9635 next;
9636 }
9637 my $VPos_New = -1;
9638 if(defined $VirtualTable{2}{$CName}{$Interface})
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04009639 {
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04009640 $VPos_New = $VirtualTable{2}{$CName}{$Interface};
9641 }
9642 else
9643 {
9644 if($Interface ne $RemovedVFunc) {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04009645 next;
9646 }
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04009647 }
9648 my $VPos_Removed = $VirtualTable{1}{$CName}{$RemovedVFunc};
9649 my $VPos_Old = $VirtualTable{1}{$CName}{$Interface};
9650 if($VPos_Removed<=$VPos_Old and $VPos_Old!=$VPos_New)
9651 {
9652 my @Affected = ($Interface, keys(%{$OverriddenMethods{1}{$Interface}}));
9653 foreach my $ASymbol (@Affected)
9654 {
Andrey Ponomarenko85043792012-05-14 16:48:07 +04009655 if(not $CompleteSignature{1}{$ASymbol}{"PureVirt"})
9656 {
9657 if(symbolFilter($ASymbol, 1, "Affected", $Level)) {
9658 next;
9659 }
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04009660 }
9661 my $ProblemType = "Removed_Virtual_Method";
9662 if($CompleteSignature{1}{$RemovedVFunc}{"PureVirt"}) {
9663 $ProblemType = "Removed_Pure_Virtual_Method";
9664 }
9665 $CheckedSymbols{$Level}{$ASymbol} = 1;
9666 %{$CompatProblems{$Level}{$ASymbol}{$ProblemType}{$tr_name{$RemovedVFunc}}}=(
9667 "Type_Name"=>$CName,
9668 "Type_Type"=>"Class",
9669 "Target"=>get_Signature($RemovedVFunc, 1) );
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04009670 $VTableChanged_M{$TypeInfo{1}{$CompleteSignature{1}{$ASymbol}{"Class"}}{"Name"}} = 1;
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04009671 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04009672 }
9673 }
9674 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009675 }
9676 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04009677 else
9678 { # Source-level
9679 foreach my $AddedVFunc (keys(%{$AddedInt_Virt{$Level}{$CName}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009680 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04009681 next if($Interface eq $AddedVFunc);
9682 if($CompleteSignature{2}{$AddedVFunc}{"PureVirt"})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009683 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04009684 %{$CompatProblems{$Level}{$Interface}{"Added_Pure_Virtual_Method"}{$tr_name{$AddedVFunc}}}=(
9685 "Type_Name"=>$CName,
9686 "Type_Type"=>"Class",
9687 "Target"=>get_Signature($AddedVFunc, 2) );
9688 }
9689 }
9690 foreach my $RemovedVFunc (keys(%{$RemovedInt_Virt{$Level}{$CName}}))
9691 {
9692 if($CompleteSignature{1}{$RemovedVFunc}{"PureVirt"})
9693 {
9694 %{$CompatProblems{$Level}{$Interface}{"Removed_Pure_Virtual_Method"}{$tr_name{$RemovedVFunc}}}=(
9695 "Type_Name"=>$CName,
9696 "Type_Type"=>"Class",
9697 "Target"=>get_Signature($RemovedVFunc, 1) );
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009698 }
9699 }
9700 }
9701}
9702
9703sub find_MemberPair_Pos_byName($$)
9704{
9705 my ($Member_Name, $Pair_Type) = @_;
9706 $Member_Name=~s/\A[_]+|[_]+\Z//g;
9707 foreach my $MemberPair_Pos (sort {int($a)<=>int($b)} keys(%{$Pair_Type->{"Memb"}}))
9708 {
9709 if(defined $Pair_Type->{"Memb"}{$MemberPair_Pos})
9710 {
9711 my $Name = $Pair_Type->{"Memb"}{$MemberPair_Pos}{"name"};
9712 $Name=~s/\A[_]+|[_]+\Z//g;
9713 if($Name eq $Member_Name) {
9714 return $MemberPair_Pos;
9715 }
9716 }
9717 }
9718 return "lost";
9719}
9720
9721sub find_MemberPair_Pos_byVal($$)
9722{
9723 my ($Member_Value, $Pair_Type) = @_;
9724 foreach my $MemberPair_Pos (sort {int($a)<=>int($b)} keys(%{$Pair_Type->{"Memb"}}))
9725 {
9726 if(defined $Pair_Type->{"Memb"}{$MemberPair_Pos}
9727 and $Pair_Type->{"Memb"}{$MemberPair_Pos}{"value"} eq $Member_Value) {
9728 return $MemberPair_Pos;
9729 }
9730 }
9731 return "lost";
9732}
9733
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04009734my %Severity_Val=(
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009735 "High"=>3,
9736 "Medium"=>2,
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04009737 "Low"=>1,
9738 "Safe"=>-1
9739);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009740
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04009741sub maxSeverity($$)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009742{
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04009743 my ($S1, $S2) = @_;
9744 if(cmpSeverities($S1, $S2)) {
9745 return $S1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009746 }
9747 else {
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04009748 return $S2;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009749 }
9750}
9751
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04009752sub cmpSeverities($$)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009753{
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04009754 my ($S1, $S2) = @_;
9755 if(not $S1) {
9756 return 0;
9757 }
9758 elsif(not $S2) {
9759 return 1;
9760 }
9761 return ($Severity_Val{$S1}>$Severity_Val{$S2});
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009762}
9763
9764sub getProblemSeverity($$)
9765{
9766 my ($Level, $Kind) = @_;
9767 return $CompatRules{$Level}{$Kind}{"Severity"};
9768}
9769
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04009770sub isRecurType($$)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009771{
9772 foreach (@RecurTypes)
9773 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04009774 if( $_->{"T1"} eq $_[0]
9775 and $_->{"T2"} eq $_[1] )
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009776 {
9777 return 1;
9778 }
9779 }
9780 return 0;
9781}
9782
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04009783sub pushType($$)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009784{
9785 my %TypeIDs=(
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04009786 "T1" => $_[0], #Tid1
9787 "T2" => $_[1] #Tid2
Andrey Ponomarenko16934472012-03-29 15:37:04 +04009788 );
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009789 push(@RecurTypes, \%TypeIDs);
9790}
9791
9792sub isRenamed($$$$$)
9793{
9794 my ($MemPos, $Type1, $LVersion1, $Type2, $LVersion2) = @_;
9795 my $Member_Name = $Type1->{"Memb"}{$MemPos}{"name"};
9796 my $MemberType_Id = $Type1->{"Memb"}{$MemPos}{"type"};
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04009797 my %MemberType_Pure = get_PureType($MemberType_Id, $LVersion1);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009798 if(not defined $Type2->{"Memb"}{$MemPos}) {
9799 return "";
9800 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04009801 my $PairType_Id = $Type2->{"Memb"}{$MemPos}{"type"};
9802 my %PairType_Pure = get_PureType($PairType_Id, $LVersion2);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009803
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04009804 my $Pair_Name = $Type2->{"Memb"}{$MemPos}{"name"};
9805 my $MemberPair_Pos_Rev = ($Member_Name eq $Pair_Name)?$MemPos:find_MemberPair_Pos_byName($Pair_Name, $Type1);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009806 if($MemberPair_Pos_Rev eq "lost")
9807 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04009808 if($MemberType_Pure{"Name"} eq $PairType_Pure{"Name"})
9809 { # base type match
9810 return $Pair_Name;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009811 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04009812 if($TypeInfo{$LVersion1}{$MemberType_Id}{"Name"} eq $TypeInfo{$LVersion2}{$PairType_Id}{"Name"})
9813 { # exact type match
9814 return $Pair_Name;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009815 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04009816 if($MemberType_Pure{"Size"} eq $PairType_Pure{"Size"})
9817 { # size match
9818 return $Pair_Name;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009819 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04009820 if(isReserved($Pair_Name))
9821 { # reserved fields
9822 return $Pair_Name;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009823 }
9824 }
9825 return "";
9826}
9827
9828sub isLastElem($$)
9829{
9830 my ($Pos, $TypeRef) = @_;
9831 my $Name = $TypeRef->{"Memb"}{$Pos}{"name"};
9832 if($Name=~/last|count|max|total/i)
9833 { # GST_LEVEL_COUNT, GST_RTSP_ELAST
9834 return 1;
9835 }
9836 elsif($Name=~/END|NLIMITS\Z/)
9837 { # __RLIMIT_NLIMITS
9838 return 1;
9839 }
9840 elsif($Name=~/\AN[A-Z](.+)[a-z]+s\Z/
9841 and $Pos+1==keys(%{$TypeRef->{"Memb"}}))
9842 { # NImageFormats, NColorRoles
9843 return 1;
9844 }
9845 return 0;
9846}
9847
9848sub nonComparable($$)
9849{
9850 my ($T1, $T2) = @_;
9851 if($T1->{"Name"} ne $T2->{"Name"}
9852 and not isAnon($T1->{"Name"})
9853 and not isAnon($T2->{"Name"}))
9854 { # different names
9855 if($T1->{"Type"} ne "Pointer"
9856 or $T2->{"Type"} ne "Pointer")
9857 { # compare base types
9858 return 1;
9859 }
9860 if($T1->{"Name"}!~/\Avoid\s*\*/
9861 and $T2->{"Name"}=~/\Avoid\s*\*/)
9862 {
9863 return 1;
9864 }
9865 }
9866 elsif($T1->{"Type"} ne $T2->{"Type"})
9867 { # different types
9868 if($T1->{"Type"} eq "Class"
9869 and $T2->{"Type"} eq "Struct")
9870 { # "class" to "struct"
9871 return 0;
9872 }
9873 elsif($T2->{"Type"} eq "Class"
9874 and $T1->{"Type"} eq "Struct")
9875 { # "struct" to "class"
9876 return 0;
9877 }
9878 else
9879 { # "class" to "enum"
9880 # "union" to "class"
9881 # ...
9882 return 1;
9883 }
9884 }
9885 return 0;
9886}
9887
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04009888sub mergeTypes($$$)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009889{
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04009890 my ($Type1_Id, $Type2_Id, $Level) = @_;
9891 return () if(not $Type1_Id or not $Type2_Id);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009892 my (%Sub_SubProblems, %SubProblems) = ();
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04009893 if($Cache{"mergeTypes"}{$Level}{$Type1_Id}{$Type2_Id})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009894 { # already merged
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04009895 return %{$Cache{"mergeTypes"}{$Level}{$Type1_Id}{$Type2_Id}};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009896 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04009897 my %Type1 = get_Type($Type1_Id, 1);
9898 my %Type2 = get_Type($Type2_Id, 2);
Andrey Ponomarenko16934472012-03-29 15:37:04 +04009899 if(not $Type1{"Name"} or not $Type2{"Name"}) {
9900 return ();
9901 }
9902 $CheckedTypes{$Level}{$Type1{"Name"}}=1;
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04009903 my %Type1_Pure = get_PureType($Type1_Id, 1);
9904 my %Type2_Pure = get_PureType($Type2_Id, 2);
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04009905 $CheckedTypes{$Level}{$Type1_Pure{"Name"}}=1;
Andrey Ponomarenko85043792012-05-14 16:48:07 +04009906 if(not $Type1_Pure{"Size"} or not $Type2_Pure{"Size"})
9907 { # including a case when "class Class { ... };" changed to "class Class;"
9908 return ();
9909 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04009910 if(isRecurType($Type1_Pure{"Tid"}, $Type2_Pure{"Tid"}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009911 { # skip recursive declarations
9912 return ();
9913 }
9914 return () if(not $Type1_Pure{"Name"} or not $Type2_Pure{"Name"});
9915 return () if($SkipTypes{1}{$Type1_Pure{"Name"}});
9916 return () if($SkipTypes{1}{$Type1{"Name"}});
9917
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04009918 my %Typedef_1 = goToFirst($Type1{"Tid"}, 1, "Typedef");
9919 my %Typedef_2 = goToFirst($Type2{"Tid"}, 2, "Typedef");
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04009920 if(not $UseOldDumps and %Typedef_1 and %Typedef_2
9921 and $Typedef_1{"Type"} eq "Typedef" and $Typedef_2{"Type"} eq "Typedef"
9922 and $Typedef_1{"Name"} eq $Typedef_2{"Name"})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009923 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04009924 my %Base_1 = get_OneStep_BaseType($Typedef_1{"Tid"}, 1);
9925 my %Base_2 = get_OneStep_BaseType($Typedef_2{"Tid"}, 2);
Andrey Ponomarenko85043792012-05-14 16:48:07 +04009926 if($Base_1{"Name"} ne $Base_2{"Name"})
9927 {
9928 if(differentDumps("G")
9929 or differentDumps("V"))
9930 { # different GCC versions or different dumps
9931 $Base_1{"Name"} = uncover_typedefs($Base_1{"Name"}, 1);
9932 $Base_2{"Name"} = uncover_typedefs($Base_2{"Name"}, 2);
9933 # std::__va_list and __va_list
9934 $Base_1{"Name"}=~s/\A(\w+::)+//;
9935 $Base_2{"Name"}=~s/\A(\w+::)+//;
9936 $Base_1{"Name"} = formatName($Base_1{"Name"});
9937 $Base_2{"Name"} = formatName($Base_2{"Name"});
9938 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009939 }
9940 if($Base_1{"Name"}!~/anon\-/ and $Base_2{"Name"}!~/anon\-/
9941 and $Base_1{"Name"} ne $Base_2{"Name"})
9942 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04009943 if($Level eq "Binary"
9944 and $Type1{"Size"} ne $Type2{"Size"})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009945 {
9946 %{$SubProblems{"DataType_Size"}{$Typedef_1{"Name"}}}=(
9947 "Target"=>$Typedef_1{"Name"},
9948 "Type_Name"=>$Typedef_1{"Name"},
9949 "Type_Type"=>"Typedef",
9950 "Old_Size"=>$Type1{"Size"}*$BYTE_SIZE,
9951 "New_Size"=>$Type2{"Size"}*$BYTE_SIZE );
9952 }
9953 %{$SubProblems{"Typedef_BaseType"}{$Typedef_1{"Name"}}}=(
9954 "Target"=>$Typedef_1{"Name"},
9955 "Type_Name"=>$Typedef_1{"Name"},
9956 "Type_Type"=>"Typedef",
9957 "Old_Value"=>$Base_1{"Name"},
9958 "New_Value"=>$Base_2{"Name"} );
9959 }
9960 }
9961 if(nonComparable(\%Type1_Pure, \%Type2_Pure))
9962 { # different types (reported in detectTypeChange(...))
9963 if($Type1_Pure{"Name"} eq $Type2_Pure{"Name"}
9964 and $Type1_Pure{"Type"} ne $Type2_Pure{"Type"}
9965 and $Type1_Pure{"Type"}!~/Intrinsic|Pointer|Ref|Typedef/)
9966 { # different type of the type
9967 %{$SubProblems{"DataType_Type"}{$Type1_Pure{"Name"}}}=(
9968 "Target"=>$Type1_Pure{"Name"},
9969 "Type_Name"=>$Type1_Pure{"Name"},
9970 "Type_Type"=>$Type1_Pure{"Type"},
9971 "Old_Value"=>lc($Type1_Pure{"Type"}),
9972 "New_Value"=>lc($Type2_Pure{"Type"}) );
9973 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04009974 %{$Cache{"mergeTypes"}{$Level}{$Type1_Id}{$Type2_Id}} = %SubProblems;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009975 return %SubProblems;
9976 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04009977 pushType($Type1_Pure{"Tid"}, $Type2_Pure{"Tid"});
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009978 if(($Type1_Pure{"Name"} eq $Type2_Pure{"Name"}
9979 or (isAnon($Type1_Pure{"Name"}) and isAnon($Type2_Pure{"Name"})))
9980 and $Type1_Pure{"Type"}=~/\A(Struct|Class|Union)\Z/)
9981 { # checking size
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04009982 if($Level eq "Binary"
9983 and $Type1_Pure{"Size"} ne $Type2_Pure{"Size"})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009984 {
9985 my $ProblemKind = "DataType_Size";
9986 if($Type1_Pure{"Type"} eq "Class"
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04009987 and keys(%{$ClassMethods{$Level}{1}{$Type1_Pure{"Name"}}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009988 {
9989 if(isCopyingClass($Type1_Pure{"Tid"}, 1)) {
9990 $ProblemKind = "Size_Of_Copying_Class";
9991 }
9992 elsif($AllocableClass{1}{$Type1_Pure{"Name"}})
9993 {
9994 if(int($Type2_Pure{"Size"})>int($Type1_Pure{"Size"})) {
9995 $ProblemKind = "Size_Of_Allocable_Class_Increased";
9996 }
9997 else {
9998 # descreased size of allocable class
9999 # it has no special effects
10000 }
10001 }
10002 }
10003 %{$SubProblems{$ProblemKind}{$Type1_Pure{"Name"}}}=(
10004 "Target"=>$Type1_Pure{"Name"},
10005 "Type_Name"=>$Type1_Pure{"Name"},
10006 "Type_Type"=>$Type1_Pure{"Type"},
10007 "Old_Size"=>$Type1_Pure{"Size"}*$BYTE_SIZE,
10008 "New_Size"=>$Type2_Pure{"Size"}*$BYTE_SIZE,
10009 "InitialType_Type"=>$Type1_Pure{"Type"} );
10010 }
10011 }
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040010012 if(defined $Type1_Pure{"BaseType"} and $Type1_Pure{"BaseType"}{"Tid"}
10013 and defined $Type2_Pure{"BaseType"} and $Type2_Pure{"BaseType"}{"Tid"})
10014 { # checking base types
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040010015 %Sub_SubProblems = mergeTypes($Type1_Pure{"BaseType"}{"Tid"}, $Type2_Pure{"BaseType"}{"Tid"}, $Level);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010016 foreach my $Sub_SubProblemType (keys(%Sub_SubProblems))
10017 {
10018 foreach my $Sub_SubLocation (keys(%{$Sub_SubProblems{$Sub_SubProblemType}}))
10019 {
10020 foreach my $Attr (keys(%{$Sub_SubProblems{$Sub_SubProblemType}{$Sub_SubLocation}})) {
10021 $SubProblems{$Sub_SubProblemType}{$Sub_SubLocation}{$Attr} = $Sub_SubProblems{$Sub_SubProblemType}{$Sub_SubLocation}{$Attr};
10022 }
10023 $SubProblems{$Sub_SubProblemType}{$Sub_SubLocation}{"InitialType_Type"} = $Type1_Pure{"Type"};
10024 }
10025 }
10026 }
10027 my (%AddedField, %RemovedField, %RenamedField, %RenamedField_Rev, %RelatedField, %RelatedField_Rev) = ();
10028 my %NameToPosA = map {$Type1_Pure{"Memb"}{$_}{"name"}=>$_} keys(%{$Type1_Pure{"Memb"}});
10029 my %NameToPosB = map {$Type2_Pure{"Memb"}{$_}{"name"}=>$_} keys(%{$Type2_Pure{"Memb"}});
10030 foreach my $Member_Pos (sort {int($a) <=> int($b)} keys(%{$Type1_Pure{"Memb"}}))
10031 { # detect removed and renamed fields
10032 my $Member_Name = $Type1_Pure{"Memb"}{$Member_Pos}{"name"};
10033 next if(not $Member_Name);
10034 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);
10035 if($MemberPair_Pos eq "lost")
10036 {
10037 if($Type2_Pure{"Type"}=~/\A(Struct|Class|Union)\Z/)
10038 {
10039 if(isUnnamed($Member_Name))
10040 { # support for old-version dumps
10041 # unnamed fields have been introduced in the ACC 1.23 (dump 2.1 format)
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040010042 if(not checkDump(2, "2.1")) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010043 next;
10044 }
10045 }
10046 if(my $RenamedTo = isRenamed($Member_Pos, \%Type1_Pure, 1, \%Type2_Pure, 2))
10047 { # renamed
10048 $RenamedField{$Member_Pos}=$RenamedTo;
10049 $RenamedField_Rev{$NameToPosB{$RenamedTo}}=$Member_Name;
10050 }
10051 else
10052 { # removed
10053 $RemovedField{$Member_Pos}=1;
10054 }
10055 }
10056 elsif($Type1_Pure{"Type"} eq "Enum")
10057 {
10058 my $Member_Value1 = $Type1_Pure{"Memb"}{$Member_Pos}{"value"};
10059 next if($Member_Value1 eq "");
10060 $MemberPair_Pos = find_MemberPair_Pos_byVal($Member_Value1, \%Type2_Pure);
10061 if($MemberPair_Pos ne "lost")
10062 { # renamed
10063 my $RenamedTo = $Type2_Pure{"Memb"}{$MemberPair_Pos}{"name"};
10064 my $MemberPair_Pos_Rev = find_MemberPair_Pos_byName($RenamedTo, \%Type1_Pure);
10065 if($MemberPair_Pos_Rev eq "lost")
10066 {
10067 $RenamedField{$Member_Pos}=$RenamedTo;
10068 $RenamedField_Rev{$NameToPosB{$RenamedTo}}=$Member_Name;
10069 }
10070 else {
10071 $RemovedField{$Member_Pos}=1;
10072 }
10073 }
10074 else
10075 { # removed
10076 $RemovedField{$Member_Pos}=1;
10077 }
10078 }
10079 }
10080 else
10081 { # related
10082 $RelatedField{$Member_Pos} = $MemberPair_Pos;
10083 $RelatedField_Rev{$MemberPair_Pos} = $Member_Pos;
10084 }
10085 }
10086 foreach my $Member_Pos (sort {int($a) <=> int($b)} keys(%{$Type2_Pure{"Memb"}}))
10087 { # detect added fields
10088 my $Member_Name = $Type2_Pure{"Memb"}{$Member_Pos}{"name"};
10089 next if(not $Member_Name);
10090 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);
10091 if($MemberPair_Pos eq "lost")
10092 {
10093 if(isUnnamed($Member_Name))
10094 { # support for old-version dumps
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040010095 # unnamed fields have been introduced in the ACC 1.23 (dump 2.1 format)
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040010096 if(not checkDump(1, "2.1")) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010097 next;
10098 }
10099 }
10100 if($Type2_Pure{"Type"}=~/\A(Struct|Class|Union|Enum)\Z/)
10101 {
10102 if(not $RenamedField_Rev{$Member_Pos})
10103 { # added
10104 $AddedField{$Member_Pos}=1;
10105 }
10106 }
10107 }
10108 }
10109 if($Type2_Pure{"Type"}=~/\A(Struct|Class)\Z/)
10110 { # detect moved fields
10111 my (%RelPos, %RelPosName, %AbsPos) = ();
10112 my $Pos = 0;
10113 foreach my $Member_Pos (sort {int($a) <=> int($b)} keys(%{$Type1_Pure{"Memb"}}))
10114 { # relative positions in 1st version
10115 my $Member_Name = $Type1_Pure{"Memb"}{$Member_Pos}{"name"};
10116 next if(not $Member_Name);
10117 if(not $RemovedField{$Member_Pos})
10118 { # old type without removed fields
10119 $RelPos{1}{$Member_Name}=$Pos;
10120 $RelPosName{1}{$Pos} = $Member_Name;
10121 $AbsPos{1}{$Pos++} = $Member_Pos;
10122 }
10123 }
10124 $Pos = 0;
10125 foreach my $Member_Pos (sort {int($a) <=> int($b)} keys(%{$Type2_Pure{"Memb"}}))
10126 { # relative positions in 2nd version
10127 my $Member_Name = $Type2_Pure{"Memb"}{$Member_Pos}{"name"};
10128 next if(not $Member_Name);
10129 if(not $AddedField{$Member_Pos})
10130 { # new type without added fields
10131 $RelPos{2}{$Member_Name}=$Pos;
10132 $RelPosName{2}{$Pos} = $Member_Name;
10133 $AbsPos{2}{$Pos++} = $Member_Pos;
10134 }
10135 }
10136 foreach my $Member_Name (keys(%{$RelPos{1}}))
10137 {
10138 my $RPos1 = $RelPos{1}{$Member_Name};
10139 my $AbsPos1 = $NameToPosA{$Member_Name};
10140 my $Member_Name2 = $Member_Name;
10141 if(my $RenamedTo = $RenamedField{$AbsPos1})
10142 { # renamed
10143 $Member_Name2 = $RenamedTo;
10144 }
10145 my $RPos2 = $RelPos{2}{$Member_Name2};
10146 if($RPos2 ne "" and $RPos1 ne $RPos2)
10147 { # different relative positions
10148 my $AbsPos2 = $NameToPosB{$Member_Name2};
10149 if($AbsPos1 ne $AbsPos2)
10150 { # different absolute positions
10151 my $ProblemType = "Moved_Field";
10152 if(not isPublic(\%Type1_Pure, $AbsPos1))
10153 { # may change layout and size of type
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040010154 if($Level eq "Source") {
10155 next;
10156 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010157 $ProblemType = "Moved_Private_Field";
10158 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040010159 if($Level eq "Binary"
10160 and $Type1_Pure{"Size"} ne $Type2_Pure{"Size"})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010161 { # affected size
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040010162 my $MemSize1 = $TypeInfo{1}{$Type1_Pure{"Memb"}{$AbsPos1}{"type"}}{"Size"};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010163 my $MovedAbsPos = $AbsPos{1}{$RPos2};
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040010164 my $MemSize2 = $TypeInfo{1}{$Type1_Pure{"Memb"}{$MovedAbsPos}{"type"}}{"Size"};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010165 if($MemSize1 ne $MemSize2) {
10166 $ProblemType .= "_And_Size";
10167 }
10168 }
10169 if($ProblemType eq "Moved_Private_Field") {
10170 next;
10171 }
10172 %{$SubProblems{$ProblemType}{$Member_Name}}=(
10173 "Target"=>$Member_Name,
10174 "Type_Name"=>$Type1_Pure{"Name"},
10175 "Type_Type"=>$Type1_Pure{"Type"},
10176 "Old_Value"=>$RPos1,
10177 "New_Value"=>$RPos2 );
10178 }
10179 }
10180 }
10181 }
10182 foreach my $Member_Pos (sort {int($a) <=> int($b)} keys(%{$Type1_Pure{"Memb"}}))
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040010183 { # check older fields, public and private
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010184 my $Member_Name = $Type1_Pure{"Memb"}{$Member_Pos}{"name"};
10185 next if(not $Member_Name);
10186 if(my $RenamedTo = $RenamedField{$Member_Pos})
10187 { # renamed
10188 if($Type2_Pure{"Type"}=~/\A(Struct|Class|Union)\Z/)
10189 {
10190 if(isPublic(\%Type1_Pure, $Member_Pos))
10191 {
10192 %{$SubProblems{"Renamed_Field"}{$Member_Name}}=(
10193 "Target"=>$Member_Name,
10194 "Type_Name"=>$Type1_Pure{"Name"},
10195 "Type_Type"=>$Type1_Pure{"Type"},
10196 "Old_Value"=>$Member_Name,
10197 "New_Value"=>$RenamedTo );
10198 }
10199 }
10200 elsif($Type1_Pure{"Type"} eq "Enum")
10201 {
10202 %{$SubProblems{"Enum_Member_Name"}{$Type1_Pure{"Memb"}{$Member_Pos}{"value"}}}=(
10203 "Target"=>$Type1_Pure{"Memb"}{$Member_Pos}{"value"},
10204 "Type_Name"=>$Type1_Pure{"Name"},
10205 "Type_Type"=>$Type1_Pure{"Type"},
10206 "Old_Value"=>$Member_Name,
10207 "New_Value"=>$RenamedTo );
10208 }
10209 }
10210 elsif($RemovedField{$Member_Pos})
10211 { # removed
10212 if($Type2_Pure{"Type"}=~/\A(Struct|Class)\Z/)
10213 {
10214 my $ProblemType = "Removed_Field";
10215 if(not isPublic(\%Type1_Pure, $Member_Pos)
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040010216 or isUnnamed($Member_Name))
10217 {
10218 if($Level eq "Source") {
10219 next;
10220 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010221 $ProblemType = "Removed_Private_Field";
10222 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040010223 if($Level eq "Binary"
10224 and not isMemPadded($Member_Pos, -1, \%Type1_Pure, \%RemovedField, 1))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010225 {
10226 if(my $MNum = isAccessible(\%Type1_Pure, \%RemovedField, $Member_Pos+1, -1))
10227 { # affected fields
10228 if(getOffset($MNum-1, \%Type1_Pure, 1)!=getOffset($RelatedField{$MNum-1}, \%Type2_Pure, 2))
10229 { # changed offset
10230 $ProblemType .= "_And_Layout";
10231 }
10232 }
10233 if($Type1_Pure{"Size"} ne $Type2_Pure{"Size"})
10234 { # affected size
10235 $ProblemType .= "_And_Size";
10236 }
10237 }
10238 if($ProblemType eq "Removed_Private_Field") {
10239 next;
10240 }
10241 %{$SubProblems{$ProblemType}{$Member_Name}}=(
10242 "Target"=>$Member_Name,
10243 "Type_Name"=>$Type1_Pure{"Name"},
10244 "Type_Type"=>$Type1_Pure{"Type"} );
10245 }
10246 elsif($Type2_Pure{"Type"} eq "Union")
10247 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040010248 if($Level eq "Binary"
10249 and $Type1_Pure{"Size"} ne $Type2_Pure{"Size"})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010250 {
10251 %{$SubProblems{"Removed_Union_Field_And_Size"}{$Member_Name}}=(
10252 "Target"=>$Member_Name,
10253 "Type_Name"=>$Type1_Pure{"Name"},
10254 "Type_Type"=>$Type1_Pure{"Type"} );
10255 }
10256 else
10257 {
10258 %{$SubProblems{"Removed_Union_Field"}{$Member_Name}}=(
10259 "Target"=>$Member_Name,
10260 "Type_Name"=>$Type1_Pure{"Name"},
10261 "Type_Type"=>$Type1_Pure{"Type"} );
10262 }
10263 }
10264 elsif($Type1_Pure{"Type"} eq "Enum")
10265 {
10266 %{$SubProblems{"Enum_Member_Removed"}{$Member_Name}}=(
10267 "Target"=>$Member_Name,
10268 "Type_Name"=>$Type1_Pure{"Name"},
10269 "Type_Type"=>$Type1_Pure{"Type"},
10270 "Old_Value"=>$Member_Name );
10271 }
10272 }
10273 else
10274 { # changed
10275 my $MemberPair_Pos = $RelatedField{$Member_Pos};
10276 if($Type1_Pure{"Type"} eq "Enum")
10277 {
10278 my $Member_Value1 = $Type1_Pure{"Memb"}{$Member_Pos}{"value"};
10279 next if($Member_Value1 eq "");
10280 my $Member_Value2 = $Type2_Pure{"Memb"}{$MemberPair_Pos}{"value"};
10281 next if($Member_Value2 eq "");
10282 if($Member_Value1 ne $Member_Value2)
10283 {
10284 my $ProblemType = "Enum_Member_Value";
10285 if(isLastElem($Member_Pos, \%Type1_Pure)) {
10286 $ProblemType = "Enum_Last_Member_Value";
10287 }
10288 %{$SubProblems{$ProblemType}{$Member_Name}}=(
10289 "Target"=>$Member_Name,
10290 "Type_Name"=>$Type1_Pure{"Name"},
10291 "Type_Type"=>$Type1_Pure{"Type"},
10292 "Old_Value"=>$Member_Value1,
10293 "New_Value"=>$Member_Value2 );
10294 }
10295 }
10296 elsif($Type2_Pure{"Type"}=~/\A(Struct|Class|Union)\Z/)
10297 {
10298 my $MemberType1_Id = $Type1_Pure{"Memb"}{$Member_Pos}{"type"};
10299 my $MemberType2_Id = $Type2_Pure{"Memb"}{$MemberPair_Pos}{"type"};
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040010300 my $SizeV1 = $TypeInfo{1}{$MemberType1_Id}{"Size"}*$BYTE_SIZE;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010301 if(my $BSize1 = $Type1_Pure{"Memb"}{$Member_Pos}{"bitfield"}) {
10302 $SizeV1 = $BSize1;
10303 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040010304 my $SizeV2 = $TypeInfo{2}{$MemberType2_Id}{"Size"}*$BYTE_SIZE;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010305 if(my $BSize2 = $Type2_Pure{"Memb"}{$MemberPair_Pos}{"bitfield"}) {
10306 $SizeV2 = $BSize2;
10307 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040010308 my $MemberType1_Name = $TypeInfo{1}{$MemberType1_Id}{"Name"};
10309 my $MemberType2_Name = $TypeInfo{2}{$MemberType2_Id}{"Name"};
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040010310 if($Level eq "Binary"
10311 and $SizeV1 ne $SizeV2)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010312 {
10313 if($MemberType1_Name eq $MemberType2_Name or (isAnon($MemberType1_Name) and isAnon($MemberType2_Name))
10314 or ($Type1_Pure{"Memb"}{$Member_Pos}{"bitfield"} and $Type2_Pure{"Memb"}{$MemberPair_Pos}{"bitfield"}))
10315 { # field size change (including anon-structures and unions)
10316 # - same types
10317 # - unnamed types
10318 # - bitfields
10319 my $ProblemType = "Field_Size";
10320 if(not isPublic(\%Type1_Pure, $Member_Pos)
10321 or isUnnamed($Member_Name))
10322 { # should not be accessed by applications, goes to "Low Severity"
10323 # example: "abidata" members in GStreamer types
10324 $ProblemType = "Private_".$ProblemType;
10325 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040010326 if(not isMemPadded($Member_Pos, $TypeInfo{2}{$MemberType2_Id}{"Size"}*$BYTE_SIZE, \%Type1_Pure, \%RemovedField, 1))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010327 { # check an effect
10328 if(my $MNum = isAccessible(\%Type1_Pure, \%RemovedField, $Member_Pos+1, -1))
10329 { # public fields after the current
10330 if(getOffset($MNum-1, \%Type1_Pure, 1)!=getOffset($RelatedField{$MNum-1}, \%Type2_Pure, 2))
10331 { # changed offset
10332 $ProblemType .= "_And_Layout";
10333 }
10334 }
10335 if($Type1_Pure{"Size"} ne $Type2_Pure{"Size"}) {
10336 $ProblemType .= "_And_Type_Size";
10337 }
10338 }
10339 if($ProblemType eq "Private_Field_Size")
10340 { # private field size with no effect
10341 $ProblemType = "";
10342 }
10343 if($ProblemType)
10344 { # register a problem
10345 %{$SubProblems{$ProblemType}{$Member_Name}}=(
10346 "Target"=>$Member_Name,
10347 "Type_Name"=>$Type1_Pure{"Name"},
10348 "Type_Type"=>$Type1_Pure{"Type"},
10349 "Old_Size"=>$SizeV1,
10350 "New_Size"=>$SizeV2);
10351 }
10352 }
10353 }
10354 if($Type1_Pure{"Memb"}{$Member_Pos}{"bitfield"}
10355 or $Type2_Pure{"Memb"}{$MemberPair_Pos}{"bitfield"})
10356 { # do NOT check bitfield type changes
10357 next;
10358 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040010359 if(checkDump(1, "2.13") and checkDump(2, "2.13"))
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040010360 {
10361 if(not $Type1_Pure{"Memb"}{$Member_Pos}{"mutable"}
10362 and $Type2_Pure{"Memb"}{$MemberPair_Pos}{"mutable"})
10363 {
10364 %{$SubProblems{"Field_Became_Mutable"}{$Member_Name}}=(
10365 "Target"=>$Member_Name,
10366 "Type_Name"=>$Type1_Pure{"Name"},
10367 "Type_Type"=>$Type1_Pure{"Type"});
10368 }
10369 elsif($Type1_Pure{"Memb"}{$Member_Pos}{"mutable"}
10370 and not $Type2_Pure{"Memb"}{$MemberPair_Pos}{"mutable"})
10371 {
10372 %{$SubProblems{"Field_Became_NonMutable"}{$Member_Name}}=(
10373 "Target"=>$Member_Name,
10374 "Type_Name"=>$Type1_Pure{"Name"},
10375 "Type_Type"=>$Type1_Pure{"Type"});
10376 }
10377 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040010378 %Sub_SubProblems = detectTypeChange($MemberType1_Id, $MemberType2_Id, "Field", $Level);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010379 foreach my $ProblemType (keys(%Sub_SubProblems))
10380 {
10381 my $Old_Value = $Sub_SubProblems{$ProblemType}{"Old_Value"};
10382 my $New_Value = $Sub_SubProblems{$ProblemType}{"New_Value"};
10383 if($ProblemType eq "Field_Type"
10384 or $ProblemType eq "Field_Type_And_Size")
10385 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040010386 if(checkDump(1, "2.6") and checkDump(2, "2.6"))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010387 {
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040010388 if(my $RA = addedQual($Old_Value, $New_Value, "volatile"))
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040010389 {
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040010390 %{$Sub_SubProblems{"Field_Became_Volatile"}} = %{$Sub_SubProblems{$ProblemType}};
10391 if($Level eq "Source"
10392 and cmpBTypes($Old_Value, $New_Value, 1, 2)) {
10393 delete($Sub_SubProblems{$ProblemType});
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040010394 }
10395 }
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040010396 elsif(my $RR = removedQual($Old_Value, $New_Value, "volatile"))
10397 {
10398 %{$Sub_SubProblems{"Field_Became_NonVolatile"}} = %{$Sub_SubProblems{$ProblemType}};
10399 if($Level eq "Source"
10400 and cmpBTypes($Old_Value, $New_Value, 1, 2)) {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040010401 delete($Sub_SubProblems{$ProblemType});
10402 }
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040010403 }
10404 }
10405 if(my $RA = addedQual($Old_Value, $New_Value, "const"))
10406 {
10407 if($RA==2) {
10408 %{$Sub_SubProblems{"Field_Added_Const"}} = %{$Sub_SubProblems{$ProblemType}};
10409 }
10410 else {
10411 %{$Sub_SubProblems{"Field_Became_Const"}} = %{$Sub_SubProblems{$ProblemType}};
10412 }
10413 if($Level eq "Source"
10414 and cmpBTypes($Old_Value, $New_Value, 1, 2)) {
10415 delete($Sub_SubProblems{$ProblemType});
10416 }
10417 }
10418 elsif(my $RR = removedQual($Old_Value, $New_Value, "const"))
10419 {
10420 if($RR==2) {
10421 %{$Sub_SubProblems{"Field_Removed_Const"}} = %{$Sub_SubProblems{$ProblemType}};
10422 }
10423 else {
10424 %{$Sub_SubProblems{"Field_Became_NonConst"}} = %{$Sub_SubProblems{$ProblemType}};
10425 }
10426 if($Level eq "Source"
10427 and cmpBTypes($Old_Value, $New_Value, 1, 2)) {
10428 delete($Sub_SubProblems{$ProblemType});
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010429 }
10430 }
10431 }
10432 }
10433 foreach my $ProblemType (keys(%Sub_SubProblems))
10434 {
10435 my $ProblemType_Init = $ProblemType;
10436 if($ProblemType eq "Field_Type_And_Size")
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040010437 { # Binary
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010438 if(not isPublic(\%Type1_Pure, $Member_Pos)
10439 or isUnnamed($Member_Name)) {
10440 $ProblemType = "Private_".$ProblemType;
10441 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040010442 if(not isMemPadded($Member_Pos, $TypeInfo{2}{$MemberType2_Id}{"Size"}*$BYTE_SIZE, \%Type1_Pure, \%RemovedField, 1))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010443 { # check an effect
10444 if(my $MNum = isAccessible(\%Type1_Pure, \%RemovedField, $Member_Pos+1, -1))
10445 { # public fields after the current
10446 if(getOffset($MNum-1, \%Type1_Pure, 1)!=getOffset($RelatedField{$MNum-1}, \%Type2_Pure, 2))
10447 { # changed offset
10448 $ProblemType .= "_And_Layout";
10449 }
10450 }
10451 if($Type1_Pure{"Size"} ne $Type2_Pure{"Size"}) {
10452 $ProblemType .= "_And_Type_Size";
10453 }
10454 }
10455 }
10456 else
10457 {
10458 if(not isPublic(\%Type1_Pure, $Member_Pos)
10459 or isUnnamed($Member_Name)) {
10460 next;
10461 }
10462 }
10463 if($ProblemType eq "Private_Field_Type_And_Size")
10464 { # private field change with no effect
10465 next;
10466 }
10467 %{$SubProblems{$ProblemType}{$Member_Name}}=(
10468 "Target"=>$Member_Name,
10469 "Type_Name"=>$Type1_Pure{"Name"},
10470 "Type_Type"=>$Type1_Pure{"Type"} );
10471 foreach my $Attr (keys(%{$Sub_SubProblems{$ProblemType_Init}}))
10472 { # other properties
10473 $SubProblems{$ProblemType}{$Member_Name}{$Attr} = $Sub_SubProblems{$ProblemType_Init}{$Attr};
10474 }
10475 }
10476 if(not isPublic(\%Type1_Pure, $Member_Pos))
10477 { # do NOT check internal type changes
10478 next;
10479 }
10480 if($MemberType1_Id and $MemberType2_Id)
10481 {# checking member type changes (replace)
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040010482 %Sub_SubProblems = mergeTypes($MemberType1_Id, $MemberType2_Id, $Level);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010483 foreach my $Sub_SubProblemType (keys(%Sub_SubProblems))
10484 {
10485 foreach my $Sub_SubLocation (keys(%{$Sub_SubProblems{$Sub_SubProblemType}}))
10486 {
10487 my $NewLocation = ($Sub_SubLocation)?$Member_Name."->".$Sub_SubLocation:$Member_Name;
10488 $SubProblems{$Sub_SubProblemType}{$NewLocation}{"IsInTypeInternals"}=1;
10489 foreach my $Attr (keys(%{$Sub_SubProblems{$Sub_SubProblemType}{$Sub_SubLocation}})) {
10490 $SubProblems{$Sub_SubProblemType}{$NewLocation}{$Attr} = $Sub_SubProblems{$Sub_SubProblemType}{$Sub_SubLocation}{$Attr};
10491 }
10492 if($Sub_SubLocation!~/\-\>/) {
10493 $SubProblems{$Sub_SubProblemType}{$NewLocation}{"Start_Type_Name"} = $MemberType1_Name;
10494 }
10495 }
10496 }
10497 }
10498 }
10499 }
10500 }
10501 foreach my $Member_Pos (sort {int($a) <=> int($b)} keys(%{$Type2_Pure{"Memb"}}))
10502 { # checking added members, public and private
10503 my $Member_Name = $Type2_Pure{"Memb"}{$Member_Pos}{"name"};
10504 next if(not $Member_Name);
10505 if($AddedField{$Member_Pos})
10506 { # added
10507 if($Type2_Pure{"Type"}=~/\A(Struct|Class)\Z/)
10508 {
10509 my $ProblemType = "Added_Field";
10510 if(not isPublic(\%Type2_Pure, $Member_Pos)
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040010511 or isUnnamed($Member_Name))
10512 {
10513 if($Level eq "Source") {
10514 next;
10515 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010516 $ProblemType = "Added_Private_Field";
10517 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040010518 if($Level eq "Binary"
10519 and not isMemPadded($Member_Pos, -1, \%Type2_Pure, \%AddedField, 2))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010520 {
10521 if(my $MNum = isAccessible(\%Type2_Pure, \%AddedField, $Member_Pos, -1))
10522 { # public fields after the current
10523 if(getOffset($MNum-1, \%Type2_Pure, 2)!=getOffset($RelatedField_Rev{$MNum-1}, \%Type1_Pure, 1))
10524 { # changed offset
10525 $ProblemType .= "_And_Layout";
10526 }
10527 }
10528 if($Type1_Pure{"Size"} ne $Type2_Pure{"Size"}) {
10529 $ProblemType .= "_And_Size";
10530 }
10531 }
10532 if($ProblemType eq "Added_Private_Field")
10533 { # skip added private fields
10534 next;
10535 }
10536 %{$SubProblems{$ProblemType}{$Member_Name}}=(
10537 "Target"=>$Member_Name,
10538 "Type_Name"=>$Type1_Pure{"Name"},
10539 "Type_Type"=>$Type1_Pure{"Type"} );
10540 }
10541 elsif($Type2_Pure{"Type"} eq "Union")
10542 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040010543 if($Level eq "Binary"
10544 and $Type1_Pure{"Size"} ne $Type2_Pure{"Size"})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010545 {
10546 %{$SubProblems{"Added_Union_Field_And_Size"}{$Member_Name}}=(
10547 "Target"=>$Member_Name,
10548 "Type_Name"=>$Type1_Pure{"Name"},
10549 "Type_Type"=>$Type1_Pure{"Type"} );
10550 }
10551 else
10552 {
10553 %{$SubProblems{"Added_Union_Field"}{$Member_Name}}=(
10554 "Target"=>$Member_Name,
10555 "Type_Name"=>$Type1_Pure{"Name"},
10556 "Type_Type"=>$Type1_Pure{"Type"} );
10557 }
10558 }
10559 elsif($Type2_Pure{"Type"} eq "Enum")
10560 {
10561 my $Member_Value = $Type2_Pure{"Memb"}{$Member_Pos}{"value"};
10562 next if($Member_Value eq "");
10563 %{$SubProblems{"Added_Enum_Member"}{$Member_Name}}=(
10564 "Target"=>$Member_Name,
10565 "Type_Name"=>$Type2_Pure{"Name"},
10566 "Type_Type"=>$Type2_Pure{"Type"},
10567 "New_Value"=>$Member_Value );
10568 }
10569 }
10570 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040010571 %{$Cache{"mergeTypes"}{$Level}{$Type1_Id}{$Type2_Id}} = %SubProblems;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010572 pop(@RecurTypes);
10573 return %SubProblems;
10574}
10575
10576sub isUnnamed($) {
10577 return $_[0]=~/\Aunnamed\d+\Z/;
10578}
10579
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040010580sub get_ShortType($$)
10581{
10582 my ($TypeId, $LibVersion) = @_;
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040010583 my $TypeName = $TypeInfo{$LibVersion}{$TypeId}{"Name"};
10584 if(my $NameSpace = $TypeInfo{$LibVersion}{$TypeId}{"NameSpace"}) {
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040010585 $TypeName=~s/\A$NameSpace\:\://g;
10586 }
10587 return $TypeName;
10588}
10589
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040010590sub goToFirst($$$)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010591{
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040010592 my ($TypeId, $LibVersion, $Type_Type) = @_;
Andrey Ponomarenko16934472012-03-29 15:37:04 +040010593 return () if(not $TypeId);
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040010594 if(defined $Cache{"goToFirst"}{$TypeId}{$LibVersion}{$Type_Type}) {
10595 return %{$Cache{"goToFirst"}{$TypeId}{$LibVersion}{$Type_Type}};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010596 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040010597 return () if(not $TypeInfo{$LibVersion}{$TypeId});
10598 my %Type = %{$TypeInfo{$LibVersion}{$TypeId}};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010599 return () if(not $Type{"Type"});
10600 if($Type{"Type"} ne $Type_Type)
10601 {
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040010602 return () if(not defined $Type{"BaseType"});
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040010603 return () if(not $Type{"BaseType"}{"Tid"});
10604 %Type = goToFirst($Type{"BaseType"}{"Tid"}, $LibVersion, $Type_Type);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010605 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040010606 $Cache{"goToFirst"}{$TypeId}{$LibVersion}{$Type_Type} = \%Type;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010607 return %Type;
10608}
10609
10610my %TypeSpecAttributes = (
10611 "Const" => 1,
10612 "Volatile" => 1,
10613 "ConstVolatile" => 1,
10614 "Restrict" => 1,
10615 "Typedef" => 1
10616);
10617
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040010618sub get_PureType($$)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010619{
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040010620 my ($TypeId, $LibVersion) = @_;
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040010621 return () if(not $TypeId);
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040010622 if(defined $Cache{"get_PureType"}{$TypeId}{$LibVersion}) {
10623 return %{$Cache{"get_PureType"}{$TypeId}{$LibVersion}};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010624 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040010625 return () if(not $TypeInfo{$LibVersion}{$TypeId});
10626 my %Type = %{$TypeInfo{$LibVersion}{$TypeId}};
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040010627 return %Type if(not defined $Type{"BaseType"});
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040010628 return %Type if(not $Type{"BaseType"}{"Tid"});
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010629 if($TypeSpecAttributes{$Type{"Type"}}) {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040010630 %Type = get_PureType($Type{"BaseType"}{"Tid"}, $LibVersion);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010631 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040010632 $Cache{"get_PureType"}{$TypeId}{$LibVersion} = \%Type;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010633 return %Type;
10634}
10635
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040010636sub get_PLevel($$)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010637{
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040010638 my ($TypeId, $LibVersion) = @_;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010639 return 0 if(not $TypeId);
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040010640 if(defined $Cache{"get_PLevel"}{$TypeId}{$LibVersion}) {
10641 return $Cache{"get_PLevel"}{$TypeId}{$LibVersion};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010642 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040010643 return 0 if(not $TypeInfo{$LibVersion}{$TypeId});
10644 my %Type = %{$TypeInfo{$LibVersion}{$TypeId}};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010645 return 1 if($Type{"Type"}=~/FuncPtr|MethodPtr|FieldPtr/);
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040010646 return 0 if(not defined $Type{"BaseType"});
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040010647 return 0 if(not $Type{"BaseType"}{"Tid"});
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010648 my $PointerLevel = 0;
10649 if($Type{"Type"} =~/Pointer|Ref|FuncPtr|MethodPtr|FieldPtr/) {
10650 $PointerLevel += 1;
10651 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040010652 $PointerLevel += get_PLevel($Type{"BaseType"}{"Tid"}, $LibVersion);
10653 $Cache{"get_PLevel"}{$TypeId}{$LibVersion} = $PointerLevel;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010654 return $PointerLevel;
10655}
10656
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040010657sub get_BaseType($$)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010658{
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040010659 my ($TypeId, $LibVersion) = @_;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010660 return () if(not $TypeId);
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040010661 if(defined $Cache{"get_BaseType"}{$TypeId}{$LibVersion}) {
10662 return %{$Cache{"get_BaseType"}{$TypeId}{$LibVersion}};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010663 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040010664 return () if(not $TypeInfo{$LibVersion}{$TypeId});
10665 my %Type = %{$TypeInfo{$LibVersion}{$TypeId}};
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040010666 return %Type if(not defined $Type{"BaseType"});
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040010667 return %Type if(not $Type{"BaseType"}{"Tid"});
10668 %Type = get_BaseType($Type{"BaseType"}{"Tid"}, $LibVersion);
10669 $Cache{"get_BaseType"}{$TypeId}{$LibVersion} = \%Type;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010670 return %Type;
10671}
10672
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040010673sub get_BaseTypeQual($$)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010674{
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040010675 my ($TypeId, $LibVersion) = @_;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010676 return "" if(not $TypeId);
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040010677 return "" if(not $TypeInfo{$LibVersion}{$TypeId});
10678 my %Type = %{$TypeInfo{$LibVersion}{$TypeId}};
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040010679 return "" if(not defined $Type{"BaseType"});
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040010680 return "" if(not $Type{"BaseType"}{"Tid"});
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010681 my $Qual = "";
10682 if($Type{"Type"} eq "Pointer") {
10683 $Qual .= "*";
10684 }
10685 elsif($Type{"Type"} eq "Ref") {
10686 $Qual .= "&";
10687 }
10688 elsif($Type{"Type"} eq "ConstVolatile") {
10689 $Qual .= "const volatile";
10690 }
10691 elsif($Type{"Type"} eq "Const"
10692 or $Type{"Type"} eq "Volatile"
10693 or $Type{"Type"} eq "Restrict") {
10694 $Qual .= lc($Type{"Type"});
10695 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040010696 my $BQual = get_BaseTypeQual($Type{"BaseType"}{"Tid"}, $LibVersion);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010697 return $BQual.$Qual;
10698}
10699
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040010700sub get_OneStep_BaseType($$)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010701{
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040010702 my ($TypeId, $LibVersion) = @_;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010703 return () if(not $TypeId);
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040010704 return () if(not $TypeInfo{$LibVersion}{$TypeId});
10705 my %Type = %{$TypeInfo{$LibVersion}{$TypeId}};
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040010706 return %Type if(not defined $Type{"BaseType"});
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040010707 return %Type if(not $Type{"BaseType"}{"Tid"});
10708 return get_Type($Type{"BaseType"}{"Tid"}, $LibVersion);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010709}
10710
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040010711sub get_Type($$)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010712{
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040010713 my ($TypeId, $LibVersion) = @_;
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040010714 return () if(not $TypeId);
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040010715 return () if(not $TypeInfo{$LibVersion}{$TypeId});
10716 return %{$TypeInfo{$LibVersion}{$TypeId}};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010717}
10718
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +040010719sub isPrivateData($)
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040010720{ # non-public global data
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010721 my $Symbol = $_[0];
10722 return ($Symbol=~/\A(_ZGV|_ZTI|_ZTS|_ZTT|_ZTV|_ZTC|_ZThn|_ZTv0_n)/);
10723}
10724
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040010725sub isTemplateInstance($$)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010726{
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040010727 my ($Symbol, $LibVersion) = @_;
10728 if($CheckObjectsOnly)
10729 {
10730 if($Symbol!~/\A(_Z|\?)/) {
10731 return 0;
10732 }
10733 if(my $Signature = $tr_name{$Symbol})
10734 {
10735 if(index($Signature,">")==-1) {
10736 return 0;
10737 }
10738 if(my $ShortName = substr($Signature, 0, find_center($Signature, "(")))
10739 {
10740 if($ShortName=~/<.+>/) {
10741 return 1;
10742 }
10743 }
10744 }
10745 }
10746 else
10747 {
10748 if(my $ClassId = $CompleteSignature{$LibVersion}{$Symbol}{"Class"})
10749 {
10750 if(my $ClassName = $TypeInfo{$LibVersion}{$ClassId}{"Name"})
10751 {
10752 if(index($ClassName,"<")!=-1) {
10753 return 1;
10754 }
10755 }
10756 }
10757 if(my $ShortName = $CompleteSignature{$LibVersion}{$Symbol}{"ShortName"})
10758 {
10759 if($ShortName=~/<.+>/) {
10760 return 1;
10761 }
10762 }
10763 }
10764 return 0;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010765}
10766
10767sub isTemplateSpec($$)
10768{
10769 my ($Symbol, $LibVersion) = @_;
10770 if(my $ClassId = $CompleteSignature{$LibVersion}{$Symbol}{"Class"})
10771 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040010772 if($TypeInfo{$LibVersion}{$ClassId}{"Spec"})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010773 { # class specialization
10774 return 1;
10775 }
10776 elsif($CompleteSignature{$LibVersion}{$Symbol}{"Spec"})
10777 { # method specialization
10778 return 1;
10779 }
10780 }
10781 return 0;
10782}
10783
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040010784sub symbolFilter($$$$)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010785{ # some special cases when the symbol cannot be imported
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040010786 my ($Symbol, $LibVersion, $Type, $Level) = @_;
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +040010787 if(isPrivateData($Symbol))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010788 { # non-public global data
10789 return 0;
10790 }
10791 if($CheckObjectsOnly) {
10792 return 0 if($Symbol=~/\A(_init|_fini)\Z/);
10793 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040010794 if($CheckHeadersOnly and not checkDump($LibVersion, "2.7"))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010795 { # support for old ABI dumps in --headers-only mode
10796 foreach my $Pos (keys(%{$CompleteSignature{$LibVersion}{$Symbol}{"Param"}}))
10797 {
10798 if(my $Pid = $CompleteSignature{$LibVersion}{$Symbol}{"Param"}{$Pos}{"type"})
10799 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040010800 my $PType = $TypeInfo{$LibVersion}{$Pid}{"Type"};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010801 if(not $PType or $PType eq "Unknown") {
10802 return 0;
10803 }
10804 }
10805 }
10806 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +040010807 if($Type=~/Affected/)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010808 {
10809 my $ClassId = $CompleteSignature{$LibVersion}{$Symbol}{"Class"};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010810 if($SkipSymbols{$LibVersion}{$Symbol})
10811 { # user defined symbols to ignore
10812 return 0;
10813 }
10814 my $NameSpace = $CompleteSignature{$LibVersion}{$Symbol}{"NameSpace"};
10815 if(not $NameSpace and $ClassId)
10816 { # class methods have no "NameSpace" attribute
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040010817 $NameSpace = $TypeInfo{$LibVersion}{$ClassId}{"NameSpace"};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010818 }
10819 if($NameSpace)
10820 { # user defined namespaces to ignore
10821 if($SkipNameSpaces{$LibVersion}{$NameSpace}) {
10822 return 0;
10823 }
10824 foreach my $NS (keys(%{$SkipNameSpaces{$LibVersion}}))
10825 { # nested namespaces
10826 if($NameSpace=~/\A\Q$NS\E(\:\:|\Z)/) {
10827 return 0;
10828 }
10829 }
10830 }
10831 if(my $Header = $CompleteSignature{$LibVersion}{$Symbol}{"Header"})
10832 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040010833 if(my $Skip = skipHeader($Header, $LibVersion))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010834 { # --skip-headers or <skip_headers> (not <skip_including>)
10835 if($Skip==1) {
10836 return 0;
10837 }
10838 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010839 }
10840 if($SymbolsListPath and not $SymbolsList{$Symbol})
10841 { # user defined symbols
10842 return 0;
10843 }
10844 if($AppPath and not $SymbolsList_App{$Symbol})
10845 { # user defined symbols (in application)
10846 return 0;
10847 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +040010848 if(not selectSymbol($Symbol, $CompleteSignature{$LibVersion}{$Symbol}, $Level, $LibVersion))
10849 { # non-target symbols
10850 return 0;
10851 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040010852 if($Level eq "Binary")
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010853 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040010854 if($CheckObjectsOnly)
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040010855 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040010856 if(isTemplateInstance($Symbol, $LibVersion)) {
10857 return 0;
10858 }
10859 }
10860 else
10861 {
10862 if($CompleteSignature{$LibVersion}{$Symbol}{"InLine"}
10863 or (isTemplateInstance($Symbol, $LibVersion) and not isTemplateSpec($Symbol, $LibVersion)))
10864 {
10865 if($ClassId and $CompleteSignature{$LibVersion}{$Symbol}{"Virt"})
10866 { # inline virtual methods
10867 if($Type=~/InlineVirt/) {
10868 return 1;
10869 }
10870 my $Allocable = (not isCopyingClass($ClassId, $LibVersion));
10871 if(not $Allocable)
10872 { # check bases
10873 foreach my $DCId (get_sub_classes($ClassId, $LibVersion, 1))
10874 {
10875 if(not isCopyingClass($DCId, $LibVersion))
10876 { # exists a derived class without default c-tor
10877 $Allocable=1;
10878 last;
10879 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040010880 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010881 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040010882 if(not $Allocable) {
10883 return 0;
10884 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010885 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040010886 else
10887 { # inline non-virtual methods
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040010888 return 0;
10889 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010890 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010891 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010892 }
10893 }
10894 return 1;
10895}
10896
10897sub mergeImpl()
10898{
10899 my $DiffCmd = get_CmdPath("diff");
10900 if(not $DiffCmd) {
10901 exitStatus("Not_Found", "can't find \"diff\"");
10902 }
10903 foreach my $Interface (sort keys(%{$Symbol_Library{1}}))
10904 { # implementation changes
10905 next if($CompleteSignature{1}{$Interface}{"Private"});
10906 next if(not $CompleteSignature{1}{$Interface}{"Header"} and not $CheckObjectsOnly);
10907 next if(not $Symbol_Library{2}{$Interface} and not $Symbol_Library{2}{$SymVer{2}{$Interface}});
Andrey Ponomarenko85043792012-05-14 16:48:07 +040010908 if(not symbolFilter($Interface, 1, "Affected", "Binary")) {
10909 next;
10910 }
Andrey Ponomarenko16934472012-03-29 15:37:04 +040010911 my $Impl1 = canonifyImpl($Interface_Impl{1}{$Interface});
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010912 next if(not $Impl1);
Andrey Ponomarenko16934472012-03-29 15:37:04 +040010913 my $Impl2 = canonifyImpl($Interface_Impl{2}{$Interface});
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010914 next if(not $Impl2);
10915 if($Impl1 ne $Impl2)
10916 {
10917 writeFile("$TMP_DIR/impl1", $Impl1);
10918 writeFile("$TMP_DIR/impl2", $Impl2);
10919 my $Diff = `$DiffCmd -rNau $TMP_DIR/impl1 $TMP_DIR/impl2`;
10920 $Diff=~s/(---|\+\+\+).+\n//g;
10921 $Diff=~s/[ ]{3,}/ /g;
10922 $Diff=~s/\n\@\@/\n \n\@\@/g;
10923 unlink("$TMP_DIR/impl1", "$TMP_DIR/impl2");
10924 %{$ImplProblems{$Interface}}=(
10925 "Diff" => get_CodeView($Diff) );
10926 }
10927 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +040010928
10929 # clean memory
10930 %Interface_Impl = ();
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010931}
10932
Andrey Ponomarenko16934472012-03-29 15:37:04 +040010933sub canonifyImpl($)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010934{
10935 my $FuncBody= $_[0];
10936 return "" if(not $FuncBody);
10937 $FuncBody=~s/0x[a-f\d]+/0x?/g;# addr
10938 $FuncBody=~s/((\A|\n)[a-z]+[\t ]+)[a-f\d]+([^x]|\Z)/$1?$3/g;# call, jump
10939 $FuncBody=~s/# [a-f\d]+ /# ? /g;# call, jump
10940 $FuncBody=~s/%([a-z]+[a-f\d]*)/\%reg/g;# registers
10941 while($FuncBody=~s/\nnop[ \t]*(\n|\Z)/$1/g){};# empty op
10942 $FuncBody=~s/<.+?\.cpp.+?>/<name.cpp>/g;
10943 $FuncBody=~s/(\A|\n)[a-f\d]+ </$1? </g;# 5e74 <_ZN...
10944 $FuncBody=~s/\.L\d+/.L/g;
10945 $FuncBody=~s/#(-?)\d+/#$1?/g;# r3, [r3, #120]
10946 $FuncBody=~s/[\n]{2,}/\n/g;
10947 return $FuncBody;
10948}
10949
10950sub get_CodeView($)
10951{
10952 my $Code = $_[0];
10953 my $View = "";
10954 foreach my $Line (split(/\n/, $Code))
10955 {
10956 if($Line=~s/\A(\+|-)/$1 /g)
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040010957 { # bold line
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010958 $View .= "<tr><td><b>".htmlSpecChars($Line)."</b></td></tr>\n";
10959 }
10960 else {
10961 $View .= "<tr><td>".htmlSpecChars($Line)."</td></tr>\n";
10962 }
10963 }
10964 return "<table class='code_view'>$View</table>\n";
10965}
10966
10967sub getImplementations($$)
10968{
10969 my ($LibVersion, $Path) = @_;
10970 return if(not $LibVersion or not -e $Path);
10971 if($OSgroup eq "macos")
10972 {
10973 my $OtoolCmd = get_CmdPath("otool");
10974 if(not $OtoolCmd) {
10975 exitStatus("Not_Found", "can't find \"otool\"");
10976 }
10977 my $CurInterface = "";
10978 foreach my $Line (split(/\n/, `$OtoolCmd -tv $Path 2>$TMP_DIR/null`))
10979 {
10980 if($Line=~/\A\s*_(\w+)\s*:/i) {
10981 $CurInterface = $1;
10982 }
10983 elsif($Line=~/\A\s*[\da-z]+\s+(.+?)\Z/i) {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040010984 $Interface_Impl{$LibVersion}{$CurInterface} .= $1."\n";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010985 }
10986 }
10987 }
10988 else
10989 {
10990 my $ObjdumpCmd = get_CmdPath("objdump");
10991 if(not $ObjdumpCmd) {
10992 exitStatus("Not_Found", "can't find \"objdump\"");
10993 }
10994 my $CurInterface = "";
10995 foreach my $Line (split(/\n/, `$ObjdumpCmd -d $Path 2>$TMP_DIR/null`))
10996 {
10997 if($Line=~/\A[\da-z]+\s+<(\w+)>/i) {
10998 $CurInterface = $1;
10999 }
11000 else
11001 { # x86: 51fa:(\t)89 e5 (\t)mov %esp,%ebp
11002 # arm: 5020:(\t)e24cb004(\t)sub(\t)fp, ip, #4(\t); 0x4
11003 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 +040011004 $Interface_Impl{$LibVersion}{$CurInterface} .= $2."\n";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011005 }
11006 }
11007 }
11008 }
11009}
11010
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011011sub detectAdded($)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011012{
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011013 my $Level = $_[0];
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011014 foreach my $Symbol (keys(%{$Symbol_Library{2}}))
11015 {
11016 if(link_symbol($Symbol, 1, "+Deps"))
11017 { # linker can find a new symbol
11018 # in the old-version library
11019 # So, it's not a new symbol
11020 next;
11021 }
11022 if(my $VSym = $SymVer{2}{$Symbol}
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040011023 and index($Symbol,"\@")==-1) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011024 next;
11025 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011026 $AddedInt{$Level}{$Symbol} = 1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011027 }
11028}
11029
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011030sub detectRemoved($)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011031{
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011032 my $Level = $_[0];
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011033 foreach my $Symbol (keys(%{$Symbol_Library{1}}))
11034 {
11035 if($CheckObjectsOnly) {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011036 $CheckedSymbols{"Binary"}{$Symbol} = 1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011037 }
11038 if(link_symbol($Symbol, 2, "+Deps"))
11039 { # linker can find an old symbol
11040 # in the new-version library
11041 next;
11042 }
11043 if(my $VSym = $SymVer{1}{$Symbol}
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040011044 and index($Symbol,"\@")==-1) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011045 next;
11046 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011047 $RemovedInt{$Level}{$Symbol} = 1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011048 }
11049}
11050
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011051sub mergeLibs($)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011052{
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011053 my $Level = $_[0];
11054 foreach my $Symbol (sort keys(%{$AddedInt{$Level}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011055 { # checking added symbols
11056 next if($CompleteSignature{2}{$Symbol}{"Private"});
11057 next if(not $CompleteSignature{2}{$Symbol}{"Header"} and not $CheckObjectsOnly);
Andrey Ponomarenko85043792012-05-14 16:48:07 +040011058 next if(not symbolFilter($Symbol, 2, "Affected", $Level));
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011059 %{$CompatProblems{$Level}{$Symbol}{"Added_Symbol"}{""}}=();
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011060 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011061 foreach my $Symbol (sort keys(%{$RemovedInt{$Level}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011062 { # checking removed symbols
11063 next if($CompleteSignature{1}{$Symbol}{"Private"});
11064 next if(not $CompleteSignature{1}{$Symbol}{"Header"} and not $CheckObjectsOnly);
11065 if($Symbol=~/\A_ZTV/)
11066 { # skip v-tables for templates, that should not be imported by applications
11067 next if($tr_name{$Symbol}=~/</);
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040011068 if(my $CName = $VTableClass{$Symbol})
11069 {
11070 if(not keys(%{$ClassMethods{$Level}{1}{$CName}}))
11071 { # vtables for "private" classes
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040011072 # use case: vtable for QDragManager (Qt 4.5.3 to 4.6.0) became HIDDEN symbol
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040011073 next;
11074 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011075 }
11076 }
11077 else {
Andrey Ponomarenko85043792012-05-14 16:48:07 +040011078 next if(not symbolFilter($Symbol, 1, "Affected", $Level));
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011079 }
11080 if($CompleteSignature{1}{$Symbol}{"PureVirt"})
11081 { # symbols for pure virtual methods cannot be called by clients
11082 next;
11083 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011084 %{$CompatProblems{$Level}{$Symbol}{"Removed_Symbol"}{""}}=();
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011085 }
11086}
11087
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040011088sub checkDump($$)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011089{
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040011090 my ($LibVersion, $V) = @_;
11091 if(defined $Cache{"checkDump"}{$LibVersion}{$V}) {
11092 return $Cache{"checkDump"}{$LibVersion}{$V};
11093 }
11094 return ($Cache{"checkDump"}{$LibVersion}{$V} = (not $UsedDump{$LibVersion}{"V"} or cmpVersions($UsedDump{$LibVersion}{"V"}, $V)>=0));
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011095}
11096
11097sub detectAdded_H($)
11098{
11099 my $Level = $_[0];
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011100 foreach my $Symbol (sort keys(%{$CompleteSignature{2}}))
11101 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011102 if($Level eq "Source")
11103 { # remove symbol version
11104 my ($SN, $SS, $SV) = separate_symbol($Symbol);
11105 $Symbol=$SN;
Andrey Ponomarenkob8d203d2012-05-25 18:11:07 +040011106
11107 if($CompleteSignature{2}{$Symbol}{"Artificial"})
11108 { # skip artificial constructors
11109 next;
11110 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011111 }
Andrey Ponomarenko16934472012-03-29 15:37:04 +040011112 if(not $CompleteSignature{2}{$Symbol}{"Header"}
11113 or not $CompleteSignature{2}{$Symbol}{"MnglName"}) {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011114 next;
11115 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040011116 if($ExtendedSymbols{$Symbol}) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011117 next;
11118 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011119 if(not defined $CompleteSignature{1}{$Symbol}
11120 or not $CompleteSignature{1}{$Symbol}{"MnglName"})
11121 {
Andrey Ponomarenko16934472012-03-29 15:37:04 +040011122 if($UsedDump{2}{"SrcBin"})
11123 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040011124 if($UsedDump{1}{"BinOnly"} or not checkDump(1, "2.11"))
Andrey Ponomarenko16934472012-03-29 15:37:04 +040011125 { # support for old and different (!) ABI dumps
11126 if(not $CompleteSignature{2}{$Symbol}{"Virt"}
11127 and not $CompleteSignature{2}{$Symbol}{"PureVirt"})
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011128 {
Andrey Ponomarenko16934472012-03-29 15:37:04 +040011129 if($CheckHeadersOnly)
Andrey Ponomarenko85043792012-05-14 16:48:07 +040011130 {
11131 if(my $Lang = $CompleteSignature{2}{$Symbol}{"Lang"})
11132 {
11133 if($Lang eq "C")
11134 { # support for old ABI dumps: missed extern "C" functions
11135 next;
11136 }
11137 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011138 }
Andrey Ponomarenko16934472012-03-29 15:37:04 +040011139 else
11140 {
11141 if(not link_symbol($Symbol, 2, "-Deps"))
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040011142 { # skip added inline symbols and const global data
Andrey Ponomarenko16934472012-03-29 15:37:04 +040011143 next;
11144 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011145 }
11146 }
11147 }
11148 }
11149 $AddedInt{$Level}{$Symbol} = 1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011150 }
11151 }
11152}
11153
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011154sub detectRemoved_H($)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011155{
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011156 my $Level = $_[0];
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011157 foreach my $Symbol (sort keys(%{$CompleteSignature{1}}))
11158 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011159 if($Level eq "Source")
11160 { # remove symbol version
11161 my ($SN, $SS, $SV) = separate_symbol($Symbol);
11162 $Symbol=$SN;
11163 }
Andrey Ponomarenko16934472012-03-29 15:37:04 +040011164 if(not $CompleteSignature{1}{$Symbol}{"Header"}
11165 or not $CompleteSignature{1}{$Symbol}{"MnglName"}) {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011166 next;
11167 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040011168 if($ExtendedSymbols{$Symbol}) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011169 next;
11170 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011171 if(not defined $CompleteSignature{2}{$Symbol}
11172 or not $CompleteSignature{2}{$Symbol}{"MnglName"})
Andrey Ponomarenko85043792012-05-14 16:48:07 +040011173 {
Andrey Ponomarenko16934472012-03-29 15:37:04 +040011174 if($UsedDump{1}{"SrcBin"})
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011175 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040011176 if($UsedDump{2}{"BinOnly"} or not checkDump(2, "2.11"))
Andrey Ponomarenko85043792012-05-14 16:48:07 +040011177 { # support for old and different (!) ABI dumps
Andrey Ponomarenko16934472012-03-29 15:37:04 +040011178 if(not $CompleteSignature{1}{$Symbol}{"Virt"}
11179 and not $CompleteSignature{1}{$Symbol}{"PureVirt"})
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011180 {
Andrey Ponomarenko16934472012-03-29 15:37:04 +040011181 if($CheckHeadersOnly)
11182 { # skip all removed symbols
Andrey Ponomarenko85043792012-05-14 16:48:07 +040011183 if(my $Lang = $CompleteSignature{1}{$Symbol}{"Lang"})
11184 {
11185 if($Lang eq "C")
11186 { # support for old ABI dumps: missed extern "C" functions
11187 next;
11188 }
11189 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011190 }
Andrey Ponomarenko16934472012-03-29 15:37:04 +040011191 else
11192 {
11193 if(not link_symbol($Symbol, 1, "-Deps"))
11194 { # skip removed inline symbols
11195 next;
11196 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011197 }
11198 }
11199 }
11200 }
Andrey Ponomarenkob8d203d2012-05-25 18:11:07 +040011201 if(not checkDump(1, "2.15"))
11202 {
11203 if($Symbol=~/_IT_E\Z/)
11204 { # _ZN28QExplicitlySharedDataPointerI22QSslCertificatePrivateEC1IT_EERKS_IT_E
11205 next;
11206 }
11207 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011208 $RemovedInt{$Level}{$Symbol} = 1;
11209 if($Level eq "Source")
11210 { # search for a source-compatible equivalent
11211 setAlternative($Symbol, $Level);
11212 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011213 }
11214 }
11215}
11216
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011217sub mergeHeaders($)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011218{
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011219 my $Level = $_[0];
11220 foreach my $Symbol (sort keys(%{$AddedInt{$Level}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011221 { # checking added symbols
11222 next if($CompleteSignature{2}{$Symbol}{"PureVirt"});
Andrey Ponomarenko85043792012-05-14 16:48:07 +040011223 if($Level eq "Binary")
11224 {
11225 if($CompleteSignature{2}{$Symbol}{"InLine"})
11226 {
11227 if(not $CompleteSignature{2}{$Symbol}{"Virt"})
11228 { # skip inline non-virtual functions
11229 next;
11230 }
11231 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011232 }
11233 else
11234 { # Source
11235 if($SourceAlternative_B{$Symbol}) {
11236 next;
11237 }
11238 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011239 next if($CompleteSignature{2}{$Symbol}{"Private"});
Andrey Ponomarenko85043792012-05-14 16:48:07 +040011240 next if(not symbolFilter($Symbol, 2, "Affected", $Level));
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011241 %{$CompatProblems{$Level}{$Symbol}{"Added_Symbol"}{""}}=();
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011242 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011243 foreach my $Symbol (sort keys(%{$RemovedInt{$Level}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011244 { # checking removed symbols
11245 next if($CompleteSignature{1}{$Symbol}{"PureVirt"});
Andrey Ponomarenko85043792012-05-14 16:48:07 +040011246 if($Level eq "Binary")
11247 {
11248 if($CompleteSignature{1}{$Symbol}{"InLine"})
11249 {
11250 if(not $CompleteSignature{1}{$Symbol}{"Virt"})
11251 { # skip inline non-virtual functions
11252 next;
11253 }
11254 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011255 }
11256 else
11257 { # Source
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040011258 if(my $Alt = $SourceAlternative{$Symbol})
11259 {
11260 if(defined $CompleteSignature{1}{$Alt}
11261 and $CompleteSignature{1}{$Symbol}{"Const"})
11262 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040011263 my $Cid = $CompleteSignature{1}{$Symbol}{"Class"};
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040011264 %{$CompatProblems{$Level}{$Symbol}{"Removed_Const_Overload"}{$tr_name{$Symbol}}}=(
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040011265 "Type_Name"=>$TypeInfo{1}{$Cid}{"Name"},
Andrey Ponomarenko85043792012-05-14 16:48:07 +040011266 "Type_Type"=>"Class",
11267 "Target"=>get_Signature($Alt, 1) );
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040011268 }
11269 else
11270 { # do NOT show removed symbol
11271 next;
11272 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011273 }
11274 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011275 next if($CompleteSignature{1}{$Symbol}{"Private"});
Andrey Ponomarenko85043792012-05-14 16:48:07 +040011276 next if(not symbolFilter($Symbol, 1, "Affected", $Level));
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011277 %{$CompatProblems{$Level}{$Symbol}{"Removed_Symbol"}{""}}=();
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011278 }
11279}
11280
11281sub addParamNames($)
11282{
11283 my $LibraryVersion = $_[0];
11284 return if(not keys(%AddIntParams));
11285 my $SecondVersion = $LibraryVersion==1?2:1;
11286 foreach my $Interface (sort keys(%{$CompleteSignature{$LibraryVersion}}))
11287 {
11288 next if(not keys(%{$AddIntParams{$Interface}}));
11289 foreach my $ParamPos (sort {int($a)<=>int($b)} keys(%{$CompleteSignature{$LibraryVersion}{$Interface}{"Param"}}))
Andrey Ponomarenko85043792012-05-14 16:48:07 +040011290 { # add absent parameter names
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011291 my $ParamName = $CompleteSignature{$LibraryVersion}{$Interface}{"Param"}{$ParamPos}{"name"};
11292 if($ParamName=~/\Ap\d+\Z/ and my $NewParamName = $AddIntParams{$Interface}{$ParamPos})
Andrey Ponomarenko85043792012-05-14 16:48:07 +040011293 { # names from the external file
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011294 if(defined $CompleteSignature{$SecondVersion}{$Interface}
11295 and defined $CompleteSignature{$SecondVersion}{$Interface}{"Param"}{$ParamPos})
11296 {
11297 if($CompleteSignature{$SecondVersion}{$Interface}{"Param"}{$ParamPos}{"name"}=~/\Ap\d+\Z/) {
11298 $CompleteSignature{$LibraryVersion}{$Interface}{"Param"}{$ParamPos}{"name"} = $NewParamName;
11299 }
11300 }
11301 else {
11302 $CompleteSignature{$LibraryVersion}{$Interface}{"Param"}{$ParamPos}{"name"} = $NewParamName;
11303 }
11304 }
11305 }
11306 }
11307}
11308
11309sub detectChangedTypedefs()
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +040011310{ # detect changed typedefs to show
11311 # correct function signatures
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011312 foreach my $Typedef (keys(%{$Typedef_BaseName{1}}))
11313 {
11314 next if(not $Typedef);
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +040011315 my $BName1 = $Typedef_BaseName{1}{$Typedef};
11316 if(not $BName1 or isAnon($BName1)) {
11317 next;
11318 }
11319 my $BName2 = $Typedef_BaseName{2}{$Typedef};
11320 if(not $BName2 or isAnon($BName2)) {
11321 next;
11322 }
11323 if($BName1 ne $BName2) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011324 $ChangedTypedef{$Typedef} = 1;
11325 }
11326 }
11327}
11328
11329sub get_symbol_suffix($$)
11330{
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011331 my ($Symbol, $Full) = @_;
11332 my ($SN, $SO, $SV) = separate_symbol($Symbol);
11333 $Symbol=$SN;# remove version
11334 my $Signature = $tr_name{$Symbol};
Andrey Ponomarenko16934472012-03-29 15:37:04 +040011335 my $Suffix = substr($Signature, find_center($Signature, "("));
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011336 if(not $Full) {
11337 $Suffix=~s/(\))\s*(const volatile|volatile const|const|volatile)\Z/$1/g;
11338 }
11339 return $Suffix;
11340}
11341
11342sub get_symbol_prefix($$)
11343{
11344 my ($Symbol, $LibVersion) = @_;
11345 my $ShortName = $CompleteSignature{$LibVersion}{$Symbol}{"ShortName"};
11346 if(my $ClassId = $CompleteSignature{$LibVersion}{$Symbol}{"Class"})
11347 { # methods
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040011348 $ShortName = $TypeInfo{$LibVersion}{$ClassId}{"Name"}."::".$ShortName;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011349 }
11350 return $ShortName;
11351}
11352
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011353sub setAlternative($)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011354{
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011355 my $Symbol = $_[0];
11356 my $PSymbol = $Symbol;
11357 if(not defined $CompleteSignature{2}{$PSymbol}
11358 or (not $CompleteSignature{2}{$PSymbol}{"MnglName"}
11359 and not $CompleteSignature{2}{$PSymbol}{"ShortName"}))
11360 { # search for a pair
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040011361 if(my $ShortName = $CompleteSignature{1}{$PSymbol}{"ShortName"})
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011362 {
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040011363 if($CompleteSignature{1}{$PSymbol}{"Data"})
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011364 {
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040011365 if($PSymbol=~s/L(\d+$ShortName(E)\Z)/$1/
11366 or $PSymbol=~s/(\d+$ShortName(E)\Z)/L$1/)
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011367 {
11368 if(defined $CompleteSignature{2}{$PSymbol}
11369 and $CompleteSignature{2}{$PSymbol}{"MnglName"})
11370 {
11371 $SourceAlternative{$Symbol} = $PSymbol;
11372 $SourceAlternative_B{$PSymbol} = $Symbol;
11373 if(not defined $CompleteSignature{1}{$PSymbol}
11374 or not $CompleteSignature{1}{$PSymbol}{"MnglName"}) {
11375 $SourceReplacement{$Symbol} = $PSymbol;
11376 }
11377 }
11378 }
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040011379 }
11380 else
11381 {
11382 foreach my $Sp ("KV", "VK", "K", "V")
11383 {
11384 if($PSymbol=~s/\A_ZN$Sp/_ZN/
11385 or $PSymbol=~s/\A_ZN/_ZN$Sp/)
11386 {
11387 if(defined $CompleteSignature{2}{$PSymbol}
11388 and $CompleteSignature{2}{$PSymbol}{"MnglName"})
11389 {
11390 $SourceAlternative{$Symbol} = $PSymbol;
11391 $SourceAlternative_B{$PSymbol} = $Symbol;
11392 if(not defined $CompleteSignature{1}{$PSymbol}
11393 or not $CompleteSignature{1}{$PSymbol}{"MnglName"}) {
11394 $SourceReplacement{$Symbol} = $PSymbol;
11395 }
11396 }
11397 }
11398 $PSymbol = $Symbol;
11399 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011400 }
11401 }
11402 }
11403 return "";
11404}
11405
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040011406sub getSymKind($$)
11407{
11408 my ($Symbol, $LibVersion) = @_;
11409 if($CompleteSignature{$LibVersion}{$Symbol}{"Data"})
11410 {
11411 return "Global_Data";
11412 }
11413 elsif($CompleteSignature{$LibVersion}{$Symbol}{"Class"})
11414 {
11415 return "Method";
11416 }
11417 return "Function";
11418}
11419
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011420sub mergeSignatures($)
11421{
11422 my $Level = $_[0];
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011423 my %SubProblems = ();
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011424
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011425 mergeBases($Level);
11426
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011427 my %AddedOverloads = ();
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011428 foreach my $Symbol (sort keys(%{$AddedInt{$Level}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011429 { # check all added exported symbols
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011430 if(not $CompleteSignature{2}{$Symbol}{"Header"}) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011431 next;
11432 }
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040011433 if(defined $CompleteSignature{1}{$Symbol}
11434 and $CompleteSignature{1}{$Symbol}{"Header"})
11435 { # double-check added symbol
11436 next;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011437 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +040011438 if(not symbolFilter($Symbol, 2, "Affected", $Level)) {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011439 next;
11440 }
11441 if($Symbol=~/\A(_Z|\?)/)
11442 { # C++
11443 $AddedOverloads{get_symbol_prefix($Symbol, 2)}{get_symbol_suffix($Symbol, 1)} = $Symbol;
11444 }
11445 if(my $OverriddenMethod = $CompleteSignature{2}{$Symbol}{"Override"})
11446 { # register virtual overridings
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040011447 my $Cid = $CompleteSignature{2}{$Symbol}{"Class"};
11448 my $AffectedClass_Name = $TypeInfo{2}{$Cid}{"Name"};
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040011449 if(defined $CompleteSignature{1}{$OverriddenMethod} and $CompleteSignature{1}{$OverriddenMethod}{"Virt"}
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011450 and not $CompleteSignature{1}{$OverriddenMethod}{"Private"})
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040011451 {
11452 if($TName_Tid{1}{$AffectedClass_Name})
11453 { # class should exist in previous version
11454 if(not isCopyingClass($TName_Tid{1}{$AffectedClass_Name}, 1))
11455 { # old v-table is NOT copied by old applications
11456 %{$CompatProblems{$Level}{$OverriddenMethod}{"Overridden_Virtual_Method"}{$tr_name{$Symbol}}}=(
11457 "Type_Name"=>$AffectedClass_Name,
11458 "Type_Type"=>"Class",
11459 "Target"=>get_Signature($Symbol, 2),
11460 "Old_Value"=>get_Signature($OverriddenMethod, 2),
11461 "New_Value"=>get_Signature($Symbol, 2) );
11462 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011463 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011464 }
11465 }
11466 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011467 foreach my $Symbol (sort keys(%{$RemovedInt{$Level}}))
11468 { # check all removed exported symbols
11469 if(not $CompleteSignature{1}{$Symbol}{"Header"}) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011470 next;
11471 }
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040011472 if(defined $CompleteSignature{2}{$Symbol}
11473 and $CompleteSignature{2}{$Symbol}{"Header"})
11474 { # double-check removed symbol
11475 next;
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011476 }
11477 if($CompleteSignature{1}{$Symbol}{"Private"})
11478 { # skip private methods
11479 next;
11480 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +040011481 if(not symbolFilter($Symbol, 1, "Affected", $Level)) {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011482 next;
11483 }
11484 $CheckedSymbols{$Level}{$Symbol} = 1;
11485 if(my $OverriddenMethod = $CompleteSignature{1}{$Symbol}{"Override"})
11486 { # register virtual overridings
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040011487 my $Cid = $CompleteSignature{1}{$Symbol}{"Class"};
11488 my $AffectedClass_Name = $TypeInfo{1}{$Cid}{"Name"};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011489 if(defined $CompleteSignature{2}{$OverriddenMethod}
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040011490 and $CompleteSignature{2}{$OverriddenMethod}{"Virt"})
11491 {
11492 if($TName_Tid{2}{$AffectedClass_Name})
11493 { # class should exist in newer version
11494 if(not isCopyingClass($CompleteSignature{1}{$Symbol}{"Class"}, 1))
11495 { # old v-table is NOT copied by old applications
11496 %{$CompatProblems{$Level}{$Symbol}{"Overridden_Virtual_Method_B"}{$tr_name{$OverriddenMethod}}}=(
11497 "Type_Name"=>$AffectedClass_Name,
11498 "Type_Type"=>"Class",
11499 "Target"=>get_Signature($OverriddenMethod, 1),
11500 "Old_Value"=>get_Signature($Symbol, 1),
11501 "New_Value"=>get_Signature($OverriddenMethod, 1) );
11502 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011503 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011504 }
11505 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011506 if($Level eq "Binary"
11507 and $OSgroup eq "windows")
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011508 { # register the reason of symbol name change
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040011509 if(my $NewSym = $mangled_name{2}{$tr_name{$Symbol}})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011510 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040011511 if($AddedInt{$Level}{$NewSym})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011512 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040011513 if($CompleteSignature{1}{$Symbol}{"Static"} ne $CompleteSignature{2}{$NewSym}{"Static"})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011514 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040011515 if($CompleteSignature{2}{$NewSym}{"Static"})
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011516 {
11517 %{$CompatProblems{$Level}{$Symbol}{"Symbol_Became_Static"}{$tr_name{$Symbol}}}=(
11518 "Target"=>$tr_name{$Symbol},
11519 "Old_Value"=>$Symbol,
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040011520 "New_Value"=>$NewSym );
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011521 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011522 else
11523 {
11524 %{$CompatProblems{$Level}{$Symbol}{"Symbol_Became_NonStatic"}{$tr_name{$Symbol}}}=(
11525 "Target"=>$tr_name{$Symbol},
11526 "Old_Value"=>$Symbol,
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040011527 "New_Value"=>$NewSym );
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011528 }
11529 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040011530 if($CompleteSignature{1}{$Symbol}{"Virt"} ne $CompleteSignature{2}{$NewSym}{"Virt"})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011531 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040011532 if($CompleteSignature{2}{$NewSym}{"Virt"})
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011533 {
11534 %{$CompatProblems{$Level}{$Symbol}{"Symbol_Became_Virtual"}{$tr_name{$Symbol}}}=(
11535 "Target"=>$tr_name{$Symbol},
11536 "Old_Value"=>$Symbol,
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040011537 "New_Value"=>$NewSym );
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011538 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011539 else
11540 {
11541 %{$CompatProblems{$Level}{$Symbol}{"Symbol_Became_NonVirtual"}{$tr_name{$Symbol}}}=(
11542 "Target"=>$tr_name{$Symbol},
11543 "Old_Value"=>$Symbol,
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040011544 "New_Value"=>$NewSym );
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011545 }
11546 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040011547 my $RTId1 = $CompleteSignature{1}{$Symbol}{"Return"};
11548 my $RTId2 = $CompleteSignature{2}{$NewSym}{"Return"};
11549 my $RTName1 = $TypeInfo{1}{$RTId1}{"Name"};
11550 my $RTName2 = $TypeInfo{2}{$RTId2}{"Name"};
11551 if($RTName1 ne $RTName2)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011552 {
11553 my $ProblemType = "Symbol_Changed_Return";
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011554 if($CompleteSignature{1}{$Symbol}{"Data"}) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011555 $ProblemType = "Global_Data_Symbol_Changed_Type";
11556 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011557 %{$CompatProblems{$Level}{$Symbol}{$ProblemType}{$tr_name{$Symbol}}}=(
11558 "Target"=>$tr_name{$Symbol},
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040011559 "Old_Type"=>$RTName1,
11560 "New_Type"=>$RTName2,
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011561 "Old_Value"=>$Symbol,
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040011562 "New_Value"=>$NewSym );
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011563 }
11564 }
11565 }
11566 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011567 if($Symbol=~/\A(_Z|\?)/)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011568 { # C++
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011569 my $Prefix = get_symbol_prefix($Symbol, 1);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011570 if(my @Overloads = sort keys(%{$AddedOverloads{$Prefix}})
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011571 and not $AddedOverloads{$Prefix}{get_symbol_suffix($Symbol, 1)})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011572 { # changed signature: params, "const"-qualifier
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040011573 my $NewSym = $AddedOverloads{$Prefix}{$Overloads[0]};
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011574 if($CompleteSignature{1}{$Symbol}{"Constructor"})
11575 {
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +040011576 if($Symbol=~/(C1E|C2E)/)
11577 {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011578 my $CtorType = $1;
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040011579 $NewSym=~s/(C1E|C2E)/$CtorType/g;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011580 }
11581 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011582 elsif($CompleteSignature{1}{$Symbol}{"Destructor"})
11583 {
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +040011584 if($Symbol=~/(D0E|D1E|D2E)/)
11585 {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011586 my $DtorType = $1;
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040011587 $NewSym=~s/(D0E|D1E|D2E)/$DtorType/g;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011588 }
11589 }
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040011590 my $NS1 = $CompleteSignature{1}{$Symbol}{"NameSpace"};
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040011591 my $NS2 = $CompleteSignature{2}{$NewSym}{"NameSpace"};
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040011592 if((not $NS1 and not $NS2) or ($NS1 and $NS2 and $NS1 eq $NS2))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011593 { # from the same class and namespace
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011594 if($CompleteSignature{1}{$Symbol}{"Const"}
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040011595 and not $CompleteSignature{2}{$NewSym}{"Const"})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011596 { # "const" to non-"const"
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040011597 %{$CompatProblems{$Level}{$Symbol}{"Method_Became_NonConst"}{$tr_name{$Symbol}}}=(
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040011598 "Type_Name"=>$TypeInfo{1}{$CompleteSignature{1}{$Symbol}{"Class"}}{"Name"},
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011599 "Target"=>$tr_name{$Symbol},
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040011600 "New_Signature"=>get_Signature($NewSym, 2),
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011601 "Old_Value"=>$Symbol,
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040011602 "New_Value"=>$NewSym );
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011603 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011604 elsif(not $CompleteSignature{1}{$Symbol}{"Const"}
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040011605 and $CompleteSignature{2}{$NewSym}{"Const"})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011606 { # non-"const" to "const"
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040011607 %{$CompatProblems{$Level}{$Symbol}{"Method_Became_Const"}{$tr_name{$Symbol}}}=(
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011608 "Target"=>$tr_name{$Symbol},
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040011609 "New_Signature"=>get_Signature($NewSym, 2),
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011610 "Old_Value"=>$Symbol,
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040011611 "New_Value"=>$NewSym );
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011612 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011613 if($CompleteSignature{1}{$Symbol}{"Volatile"}
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040011614 and not $CompleteSignature{2}{$NewSym}{"Volatile"})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011615 { # "volatile" to non-"volatile"
11616
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040011617 %{$CompatProblems{$Level}{$Symbol}{"Method_Became_NonVolatile"}{$tr_name{$Symbol}}}=(
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011618 "Target"=>$tr_name{$Symbol},
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040011619 "New_Signature"=>get_Signature($NewSym, 2),
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011620 "Old_Value"=>$Symbol,
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040011621 "New_Value"=>$NewSym );
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011622 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011623 elsif(not $CompleteSignature{1}{$Symbol}{"Volatile"}
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040011624 and $CompleteSignature{2}{$NewSym}{"Volatile"})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011625 { # non-"volatile" to "volatile"
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040011626 %{$CompatProblems{$Level}{$Symbol}{"Method_Became_Volatile"}{$tr_name{$Symbol}}}=(
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011627 "Target"=>$tr_name{$Symbol},
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040011628 "New_Signature"=>get_Signature($NewSym, 2),
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011629 "Old_Value"=>$Symbol,
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040011630 "New_Value"=>$NewSym );
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011631 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040011632 if(get_symbol_suffix($Symbol, 0) ne get_symbol_suffix($NewSym, 0))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011633 { # params list
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011634 %{$CompatProblems{$Level}{$Symbol}{"Symbol_Changed_Parameters"}{$tr_name{$Symbol}}}=(
11635 "Target"=>$tr_name{$Symbol},
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040011636 "New_Signature"=>get_Signature($NewSym, 2),
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011637 "Old_Value"=>$Symbol,
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040011638 "New_Value"=>$NewSym );
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011639 }
11640 }
11641 }
11642 }
11643 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011644 foreach my $Symbol (sort keys(%{$CompleteSignature{1}}))
11645 { # checking symbols
11646 my ($SN, $SS, $SV) = separate_symbol($Symbol);
11647 if($Level eq "Source")
11648 { # remove symbol version
11649 $Symbol=$SN;
11650 }
11651 else
11652 { # Binary
11653 if(not $SV)
11654 { # symbol without version
11655 if(my $VSym = $SymVer{1}{$Symbol})
11656 { # the symbol is linked with versioned symbol
11657 if($CompleteSignature{2}{$VSym}{"MnglName"})
11658 { # show report for symbol@ver only
11659 next;
11660 }
11661 elsif(not link_symbol($VSym, 2, "-Deps"))
11662 { # changed version: sym@v1 to sym@v2
11663 # do NOT show report for symbol
11664 next;
11665 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011666 }
11667 }
11668 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011669 my $PSymbol = $Symbol;
11670 if($Level eq "Source"
11671 and my $S = $SourceReplacement{$Symbol})
11672 { # take a source-compatible replacement function
11673 $PSymbol = $S;
11674 }
11675 if($CompleteSignature{1}{$Symbol}{"Private"})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011676 { # private symbols
11677 next;
11678 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011679 if(not defined $CompleteSignature{1}{$Symbol}
11680 or not defined $CompleteSignature{2}{$PSymbol})
11681 { # no info
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011682 next;
11683 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011684 if(not $CompleteSignature{1}{$Symbol}{"MnglName"}
11685 or not $CompleteSignature{2}{$PSymbol}{"MnglName"})
11686 { # no mangled name
11687 next;
11688 }
11689 if(not $CompleteSignature{1}{$Symbol}{"Header"}
11690 or not $CompleteSignature{2}{$PSymbol}{"Header"})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011691 { # without a header
11692 next;
11693 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040011694 if(checkDump(1, "2.13") and checkDump(2, "2.13"))
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040011695 {
11696 if($CompleteSignature{1}{$Symbol}{"Data"}
11697 and $CompleteSignature{2}{$PSymbol}{"Data"})
11698 {
11699 my $Value1 = $CompleteSignature{1}{$Symbol}{"Value"};
11700 my $Value2 = $CompleteSignature{2}{$PSymbol}{"Value"};
11701 if(defined $Value1)
11702 {
11703 $Value1 = showVal($Value1, $CompleteSignature{1}{$Symbol}{"Return"}, 1);
11704 if(defined $Value2)
11705 {
11706 $Value2 = showVal($Value2, $CompleteSignature{2}{$PSymbol}{"Return"}, 2);
11707 if($Value1 ne $Value2)
11708 {
11709 %{$CompatProblems{$Level}{$Symbol}{"Global_Data_Value_Changed"}{""}}=(
11710 "Old_Value"=>$Value1,
11711 "New_Value"=>$Value2,
11712 "Target"=>get_Signature($Symbol, 1) );
11713 }
11714 }
11715 }
11716 }
11717 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +040011718
11719 if(not $CompleteSignature{1}{$Symbol}{"PureVirt"}
11720 and $CompleteSignature{2}{$PSymbol}{"PureVirt"})
11721 { # became pure
11722 next;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011723 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +040011724 if($CompleteSignature{1}{$Symbol}{"PureVirt"}
11725 and not $CompleteSignature{2}{$PSymbol}{"PureVirt"})
11726 { # became non-pure
11727 next;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011728 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +040011729
11730 if(not symbolFilter($Symbol, 1, "Affected + InlineVirt", $Level))
11731 { # exported, target, inline virtual and pure virtual
11732 next;
11733 }
11734 if(not symbolFilter($PSymbol, 2, "Affected + InlineVirt", $Level))
11735 { # exported, target, inline virtual and pure virtual
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011736 next;
11737 }
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040011738
11739 if($CompleteSignature{2}{$PSymbol}{"Private"})
11740 {
11741 %{$CompatProblems{$Level}{$Symbol}{getSymKind($Symbol, 1)."_Became_Private"}{""}}=(
11742 "Target"=>get_Signature_M($PSymbol, 2) );
11743 }
11744 elsif(not $CompleteSignature{1}{$Symbol}{"Protected"}
11745 and $CompleteSignature{2}{$PSymbol}{"Protected"})
11746 {
11747 %{$CompatProblems{$Level}{$Symbol}{getSymKind($Symbol, 1)."_Became_Protected"}{""}}=(
11748 "Target"=>get_Signature_M($PSymbol, 2) );
11749 }
11750 elsif($CompleteSignature{1}{$Symbol}{"Protected"}
11751 and not $CompleteSignature{2}{$PSymbol}{"Protected"})
11752 {
11753 %{$CompatProblems{$Level}{$Symbol}{getSymKind($Symbol, 1)."_Became_Public"}{""}}=(
11754 "Target"=>get_Signature_M($PSymbol, 2) );
11755 }
11756
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011757 # checking virtual table
Andrey Ponomarenko16934472012-03-29 15:37:04 +040011758 mergeVirtualTables($Symbol, $Level);
11759
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011760 if($COMPILE_ERRORS)
11761 { # if some errors occurred at the compiling stage
11762 # then some false positives can be skipped here
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011763 if(not $CompleteSignature{1}{$Symbol}{"Data"} and $CompleteSignature{2}{$PSymbol}{"Data"}
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040011764 and not $GlobalDataObject{2}{$Symbol})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011765 { # missed information about parameters in newer version
11766 next;
11767 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040011768 if($CompleteSignature{1}{$Symbol}{"Data"} and not $GlobalDataObject{1}{$Symbol}
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011769 and not $CompleteSignature{2}{$PSymbol}{"Data"})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011770 {# missed information about parameters in older version
11771 next;
11772 }
11773 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011774 my ($MnglName, $VersionSpec, $SymbolVersion) = separate_symbol($Symbol);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011775 # checking attributes
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011776 if($CompleteSignature{2}{$PSymbol}{"Static"}
11777 and not $CompleteSignature{1}{$Symbol}{"Static"} and $Symbol=~/\A(_Z|\?)/) {
11778 %{$CompatProblems{$Level}{$Symbol}{"Method_Became_Static"}{""}}=(
11779 "Target"=>get_Signature($Symbol, 1)
11780 );
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011781 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011782 elsif(not $CompleteSignature{2}{$PSymbol}{"Static"}
11783 and $CompleteSignature{1}{$Symbol}{"Static"} and $Symbol=~/\A(_Z|\?)/) {
11784 %{$CompatProblems{$Level}{$Symbol}{"Method_Became_NonStatic"}{""}}=(
11785 "Target"=>get_Signature($Symbol, 1)
11786 );
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011787 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011788 if(($CompleteSignature{1}{$Symbol}{"Virt"} and $CompleteSignature{2}{$PSymbol}{"Virt"})
11789 or ($CompleteSignature{1}{$Symbol}{"PureVirt"} and $CompleteSignature{2}{$PSymbol}{"PureVirt"}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011790 { # relative position of virtual and pure virtual methods
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011791 if($Level eq "Binary")
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011792 {
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040011793 if(defined $CompleteSignature{1}{$Symbol}{"RelPos"} and defined $CompleteSignature{2}{$PSymbol}{"RelPos"}
11794 and $CompleteSignature{1}{$Symbol}{"RelPos"}!=$CompleteSignature{2}{$PSymbol}{"RelPos"})
11795 { # top-level virtual methods only
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011796 my $Class_Id = $CompleteSignature{1}{$Symbol}{"Class"};
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040011797 my $Class_Name = $TypeInfo{1}{$Class_Id}{"Name"};
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040011798 if(defined $VirtualTable{1}{$Class_Name} and defined $VirtualTable{2}{$Class_Name}
11799 and $VirtualTable{1}{$Class_Name}{$Symbol}!=$VirtualTable{2}{$Class_Name}{$Symbol})
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011800 { # check the absolute position of virtual method (including added and removed methods)
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040011801 my %Class_Type = get_Type($Class_Id, 1);
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011802 my $ProblemType = "Virtual_Method_Position";
11803 if($CompleteSignature{1}{$Symbol}{"PureVirt"}) {
11804 $ProblemType = "Pure_Virtual_Method_Position";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011805 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011806 if(isUsedClass($Class_Id, 1, $Level))
11807 {
11808 my @Affected = ($Symbol, keys(%{$OverriddenMethods{1}{$Symbol}}));
11809 foreach my $AffectedInterface (@Affected)
11810 {
11811 %{$CompatProblems{$Level}{$AffectedInterface}{$ProblemType}{$tr_name{$MnglName}}}=(
11812 "Type_Name"=>$Class_Type{"Name"},
11813 "Type_Type"=>"Class",
11814 "Old_Value"=>$CompleteSignature{1}{$Symbol}{"RelPos"},
11815 "New_Value"=>$CompleteSignature{2}{$PSymbol}{"RelPos"},
11816 "Target"=>get_Signature($Symbol, 1) );
11817 }
Andrey Ponomarenko16934472012-03-29 15:37:04 +040011818 $VTableChanged_M{$Class_Type{"Name"}} = 1;
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011819 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011820 }
11821 }
11822 }
11823 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011824 if($CompleteSignature{1}{$Symbol}{"PureVirt"}
11825 or $CompleteSignature{2}{$PSymbol}{"PureVirt"})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011826 { # do NOT check type changes in pure virtuals
11827 next;
11828 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011829 $CheckedSymbols{$Level}{$Symbol}=1;
11830 if($Symbol=~/\A(_Z|\?)/
11831 or keys(%{$CompleteSignature{1}{$Symbol}{"Param"}})==keys(%{$CompleteSignature{2}{$PSymbol}{"Param"}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011832 { # C/C++: changes in parameters
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011833 foreach my $ParamPos (sort {int($a) <=> int($b)} keys(%{$CompleteSignature{1}{$Symbol}{"Param"}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011834 { # checking parameters
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011835 mergeParameters($Symbol, $PSymbol, $ParamPos, $ParamPos, $Level);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011836 }
11837 }
11838 else
11839 { # C: added/removed parameters
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011840 foreach my $ParamPos (sort {int($a) <=> int($b)} keys(%{$CompleteSignature{2}{$PSymbol}{"Param"}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011841 { # checking added parameters
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040011842 my $PType2_Id = $CompleteSignature{2}{$PSymbol}{"Param"}{$ParamPos}{"type"};
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040011843 my $PType2_Name = $TypeInfo{2}{$PType2_Id}{"Name"};
11844 last if($PType2_Name eq "...");
11845 my $PName = $CompleteSignature{2}{$PSymbol}{"Param"}{$ParamPos}{"name"};
11846 my $PName_Old = (defined $CompleteSignature{1}{$Symbol}{"Param"}{$ParamPos})?$CompleteSignature{1}{$Symbol}{"Param"}{$ParamPos}{"name"}:"";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011847 my $ParamPos_Prev = "-1";
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040011848 if($PName=~/\Ap\d+\Z/i)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011849 { # added unnamed parameter ( pN )
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040011850 my @Positions1 = find_ParamPair_Pos_byTypeAndPos($PType2_Name, $ParamPos, "backward", $Symbol, 1);
11851 my @Positions2 = find_ParamPair_Pos_byTypeAndPos($PType2_Name, $ParamPos, "backward", $Symbol, 2);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011852 if($#Positions1==-1 or $#Positions2>$#Positions1) {
11853 $ParamPos_Prev = "lost";
11854 }
11855 }
11856 else {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040011857 $ParamPos_Prev = find_ParamPair_Pos_byName($PName, $Symbol, 1);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011858 }
11859 if($ParamPos_Prev eq "lost")
11860 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011861 if($ParamPos>keys(%{$CompleteSignature{1}{$Symbol}{"Param"}})-1)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011862 {
11863 my $ProblemType = "Added_Parameter";
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040011864 if($PName=~/\Ap\d+\Z/) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011865 $ProblemType = "Added_Unnamed_Parameter";
11866 }
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040011867 %{$CompatProblems{$Level}{$Symbol}{$ProblemType}{showPos($ParamPos)." Parameter"}}=(
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040011868 "Target"=>$PName,
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011869 "Param_Pos"=>$ParamPos,
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040011870 "Param_Type"=>$PType2_Name,
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011871 "New_Signature"=>get_Signature($Symbol, 2) );
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011872 }
11873 else
11874 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040011875 my %ParamType_Pure = get_PureType($PType2_Id, 2);
11876 my $PairType_Id = $CompleteSignature{1}{$Symbol}{"Param"}{$ParamPos}{"type"};
11877 my %PairType_Pure = get_PureType($PairType_Id, 1);
11878 if(($ParamType_Pure{"Name"} eq $PairType_Pure{"Name"} or $PType2_Name eq $TypeInfo{1}{$PairType_Id}{"Name"})
11879 and find_ParamPair_Pos_byName($PName_Old, $Symbol, 2) eq "lost")
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011880 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040011881 if($PName_Old!~/\Ap\d+\Z/ and $PName!~/\Ap\d+\Z/)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011882 {
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040011883 %{$CompatProblems{$Level}{$Symbol}{"Renamed_Parameter"}{showPos($ParamPos)." Parameter"}}=(
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040011884 "Target"=>$PName_Old,
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011885 "Param_Pos"=>$ParamPos,
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040011886 "Param_Type"=>$PType2_Name,
11887 "Old_Value"=>$PName_Old,
11888 "New_Value"=>$PName,
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011889 "New_Signature"=>get_Signature($Symbol, 2) );
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011890 }
11891 }
11892 else
11893 {
11894 my $ProblemType = "Added_Middle_Parameter";
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040011895 if($PName=~/\Ap\d+\Z/) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011896 $ProblemType = "Added_Middle_Unnamed_Parameter";
11897 }
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040011898 %{$CompatProblems{$Level}{$Symbol}{$ProblemType}{showPos($ParamPos)." Parameter"}}=(
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040011899 "Target"=>$PName,
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011900 "Param_Pos"=>$ParamPos,
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040011901 "Param_Type"=>$PType2_Name,
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011902 "New_Signature"=>get_Signature($Symbol, 2) );
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011903 }
11904 }
11905 }
11906 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011907 foreach my $ParamPos (sort {int($a) <=> int($b)} keys(%{$CompleteSignature{1}{$Symbol}{"Param"}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011908 { # check relevant parameters
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040011909 my $PType1_Id = $CompleteSignature{1}{$Symbol}{"Param"}{$ParamPos}{"type"};
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011910 my $ParamName1 = $CompleteSignature{1}{$Symbol}{"Param"}{$ParamPos}{"name"};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011911 # FIXME: find relevant parameter by name
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011912 if(defined $CompleteSignature{2}{$PSymbol}{"Param"}{$ParamPos})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011913 {
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040011914 my $PType2_Id = $CompleteSignature{2}{$PSymbol}{"Param"}{$ParamPos}{"type"};
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011915 my $ParamName2 = $CompleteSignature{2}{$PSymbol}{"Param"}{$ParamPos}{"name"};
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040011916 if($TypeInfo{1}{$PType1_Id}{"Name"} eq $TypeInfo{2}{$PType2_Id}{"Name"}
11917 or ($ParamName1!~/\Ap\d+\Z/i and $ParamName1 eq $ParamName2)) {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011918 mergeParameters($Symbol, $PSymbol, $ParamPos, $ParamPos, $Level);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011919 }
11920 }
11921 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011922 foreach my $ParamPos (sort {int($a) <=> int($b)} keys(%{$CompleteSignature{1}{$Symbol}{"Param"}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011923 { # checking removed parameters
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040011924 my $PType1_Id = $CompleteSignature{1}{$Symbol}{"Param"}{$ParamPos}{"type"};
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040011925 my $PType1_Name = $TypeInfo{1}{$PType1_Id}{"Name"};
11926 last if($PType1_Name eq "...");
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011927 my $Parameter_Name = $CompleteSignature{1}{$Symbol}{"Param"}{$ParamPos}{"name"};
11928 my $Parameter_NewName = (defined $CompleteSignature{2}{$PSymbol}{"Param"}{$ParamPos})?$CompleteSignature{2}{$PSymbol}{"Param"}{$ParamPos}{"name"}:"";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011929 my $ParamPos_New = "-1";
11930 if($Parameter_Name=~/\Ap\d+\Z/i)
11931 { # removed unnamed parameter ( pN )
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040011932 my @Positions1 = find_ParamPair_Pos_byTypeAndPos($PType1_Name, $ParamPos, "forward", $Symbol, 1);
11933 my @Positions2 = find_ParamPair_Pos_byTypeAndPos($PType1_Name, $ParamPos, "forward", $Symbol, 2);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011934 if($#Positions2==-1 or $#Positions2<$#Positions1) {
11935 $ParamPos_New = "lost";
11936 }
11937 }
11938 else {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011939 $ParamPos_New = find_ParamPair_Pos_byName($Parameter_Name, $Symbol, 2);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011940 }
11941 if($ParamPos_New eq "lost")
11942 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011943 if($ParamPos>keys(%{$CompleteSignature{2}{$PSymbol}{"Param"}})-1)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011944 {
11945 my $ProblemType = "Removed_Parameter";
11946 if($Parameter_Name=~/\Ap\d+\Z/) {
11947 $ProblemType = "Removed_Unnamed_Parameter";
11948 }
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040011949 %{$CompatProblems{$Level}{$Symbol}{$ProblemType}{showPos($ParamPos)." Parameter"}}=(
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011950 "Target"=>$Parameter_Name,
11951 "Param_Pos"=>$ParamPos,
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040011952 "Param_Type"=>$PType1_Name,
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011953 "New_Signature"=>get_Signature($Symbol, 2) );
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011954 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011955 elsif($ParamPos<keys(%{$CompleteSignature{1}{$Symbol}{"Param"}})-1)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011956 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040011957 my %ParamType_Pure = get_PureType($PType1_Id, 1);
11958 my $PairType_Id = $CompleteSignature{2}{$PSymbol}{"Param"}{$ParamPos}{"type"};
11959 my %PairType_Pure = get_PureType($PairType_Id, 2);
11960 if(($ParamType_Pure{"Name"} eq $PairType_Pure{"Name"} or $PType1_Name eq $TypeInfo{2}{$PairType_Id}{"Name"})
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011961 and find_ParamPair_Pos_byName($Parameter_NewName, $Symbol, 1) eq "lost")
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011962 {
11963 if($Parameter_NewName!~/\Ap\d+\Z/ and $Parameter_Name!~/\Ap\d+\Z/)
11964 {
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040011965 %{$CompatProblems{$Level}{$Symbol}{"Renamed_Parameter"}{showPos($ParamPos)." Parameter"}}=(
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011966 "Target"=>$Parameter_Name,
11967 "Param_Pos"=>$ParamPos,
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040011968 "Param_Type"=>$PType1_Name,
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011969 "Old_Value"=>$Parameter_Name,
11970 "New_Value"=>$Parameter_NewName,
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011971 "New_Signature"=>get_Signature($Symbol, 2) );
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011972 }
11973 }
11974 else
11975 {
11976 my $ProblemType = "Removed_Middle_Parameter";
11977 if($Parameter_Name=~/\Ap\d+\Z/) {
11978 $ProblemType = "Removed_Middle_Unnamed_Parameter";
11979 }
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040011980 %{$CompatProblems{$Level}{$Symbol}{$ProblemType}{showPos($ParamPos)." Parameter"}}=(
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011981 "Target"=>$Parameter_Name,
11982 "Param_Pos"=>$ParamPos,
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040011983 "Param_Type"=>$PType1_Name,
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011984 "New_Signature"=>get_Signature($Symbol, 2) );
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011985 }
11986 }
11987 }
11988 }
11989 }
11990 # checking return type
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011991 my $ReturnType1_Id = $CompleteSignature{1}{$Symbol}{"Return"};
11992 my $ReturnType2_Id = $CompleteSignature{2}{$PSymbol}{"Return"};
11993 %SubProblems = detectTypeChange($ReturnType1_Id, $ReturnType2_Id, "Return", $Level);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011994 foreach my $SubProblemType (keys(%SubProblems))
11995 {
11996 my $New_Value = $SubProblems{$SubProblemType}{"New_Value"};
11997 my $Old_Value = $SubProblems{$SubProblemType}{"Old_Value"};
11998 my $NewProblemType = $SubProblemType;
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011999 if($Level eq "Binary" and $SubProblemType eq "Return_Type_Became_Void"
12000 and keys(%{$CompleteSignature{1}{$Symbol}{"Param"}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012001 { # parameters stack has been affected
12002 $NewProblemType = "Return_Type_Became_Void_And_Stack_Layout";
12003 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012004 elsif($Level eq "Binary"
12005 and $SubProblemType eq "Return_Type_From_Void")
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012006 { # parameters stack has been affected
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012007 if(keys(%{$CompleteSignature{1}{$Symbol}{"Param"}})) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012008 $NewProblemType = "Return_Type_From_Void_And_Stack_Layout";
12009 }
12010 else
12011 { # safe
12012 delete($SubProblems{$SubProblemType});
12013 next;
12014 }
12015 }
12016 elsif($SubProblemType eq "Return_Type_And_Size"
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012017 and $CompleteSignature{1}{$Symbol}{"Data"}) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012018 $NewProblemType = "Global_Data_Type_And_Size";
12019 }
12020 elsif($SubProblemType eq "Return_Type")
12021 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012022 if($CompleteSignature{1}{$Symbol}{"Data"})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012023 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012024 if(removedQual($Old_Value, $New_Value, "const"))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012025 { # const -> non-const global data
12026 $NewProblemType = "Global_Data_Became_Non_Const";
12027 }
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040012028 elsif(addedQual($Old_Value, $New_Value, "const"))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012029 { # non-const -> const global data
12030 $NewProblemType = "Global_Data_Became_Const";
12031 }
12032 else {
12033 $NewProblemType = "Global_Data_Type";
12034 }
12035 }
12036 else
12037 {
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040012038 if(addedQual($Old_Value, $New_Value, "const")) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012039 $NewProblemType = "Return_Type_Became_Const";
12040 }
12041 }
12042 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012043 elsif($SubProblemType eq "Return_Type_Format")
12044 {
12045 if($CompleteSignature{1}{$Symbol}{"Data"}) {
12046 $NewProblemType = "Global_Data_Type_Format";
12047 }
12048 }
12049 @{$CompatProblems{$Level}{$Symbol}{$NewProblemType}{"retval"}}{keys(%{$SubProblems{$SubProblemType}})} = values %{$SubProblems{$SubProblemType}};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012050 }
12051 if($ReturnType1_Id and $ReturnType2_Id)
12052 {
12053 @RecurTypes = ();
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040012054 %SubProblems = mergeTypes($ReturnType1_Id, $ReturnType2_Id, $Level);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012055 foreach my $SubProblemType (keys(%SubProblems))
12056 { # add "Global_Data_Size" problem
12057 my $New_Value = $SubProblems{$SubProblemType}{"New_Value"};
12058 my $Old_Value = $SubProblems{$SubProblemType}{"Old_Value"};
12059 if($SubProblemType eq "DataType_Size"
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012060 and $CompleteSignature{1}{$Symbol}{"Data"}
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040012061 and get_PLevel($ReturnType1_Id, 1)==0)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012062 { # add a new problem
12063 %{$SubProblems{"Global_Data_Size"}} = %{$SubProblems{$SubProblemType}};
12064 }
12065 }
12066 foreach my $SubProblemType (keys(%SubProblems))
12067 {
12068 foreach my $SubLocation (keys(%{$SubProblems{$SubProblemType}}))
12069 {
12070 my $NewLocation = ($SubLocation)?"retval->".$SubLocation:"retval";
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012071 %{$CompatProblems{$Level}{$Symbol}{$SubProblemType}{$NewLocation}}=(
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040012072 "Return_Type_Name"=>$TypeInfo{1}{$ReturnType1_Id}{"Name"} );
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012073 @{$CompatProblems{$Level}{$Symbol}{$SubProblemType}{$NewLocation}}{keys(%{$SubProblems{$SubProblemType}{$SubLocation}})} = values %{$SubProblems{$SubProblemType}{$SubLocation}};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012074 if($SubLocation!~/\-\>/) {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040012075 $CompatProblems{$Level}{$Symbol}{$SubProblemType}{$NewLocation}{"Start_Type_Name"} = $TypeInfo{1}{$ReturnType1_Id}{"Name"};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012076 }
12077 }
12078 }
12079 }
12080
12081 # checking object type
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040012082 my $ObjTId1 = $CompleteSignature{1}{$Symbol}{"Class"};
12083 my $ObjTId2 = $CompleteSignature{2}{$PSymbol}{"Class"};
12084 if($ObjTId1 and $ObjTId2
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012085 and not $CompleteSignature{1}{$Symbol}{"Static"})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012086 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040012087 my $ThisPtr1_Id = getTypeIdByName($TypeInfo{1}{$ObjTId1}{"Name"}."*const", 1);
12088 my $ThisPtr2_Id = getTypeIdByName($TypeInfo{2}{$ObjTId2}{"Name"}."*const", 2);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012089 if($ThisPtr1_Id and $ThisPtr2_Id)
12090 {
12091 @RecurTypes = ();
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040012092 %SubProblems = mergeTypes($ThisPtr1_Id, $ThisPtr2_Id, $Level);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012093 foreach my $SubProblemType (keys(%SubProblems))
12094 {
12095 foreach my $SubLocation (keys(%{$SubProblems{$SubProblemType}}))
12096 {
12097 my $NewLocation = ($SubLocation)?"this->".$SubLocation:"this";
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012098 %{$CompatProblems{$Level}{$Symbol}{$SubProblemType}{$NewLocation}}=(
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040012099 "Object_Type_Name"=>$TypeInfo{1}{$ObjTId1}{"Name"} );
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012100 @{$CompatProblems{$Level}{$Symbol}{$SubProblemType}{$NewLocation}}{keys(%{$SubProblems{$SubProblemType}{$SubLocation}})} = values %{$SubProblems{$SubProblemType}{$SubLocation}};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012101 if($SubLocation!~/\-\>/) {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040012102 $CompatProblems{$Level}{$Symbol}{$SubProblemType}{$NewLocation}{"Start_Type_Name"} = $TypeInfo{1}{$ObjTId1}{"Name"};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012103 }
12104 }
12105 }
12106 }
12107 }
12108 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012109 if($Level eq "Binary") {
12110 mergeVTables($Level);
12111 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +040012112 foreach my $Symbol (keys(%{$CompatProblems{$Level}})) {
12113 $CheckedSymbols{$Level}{$Symbol} = 1;
12114 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012115}
12116
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040012117sub rmQuals($$)
12118{
12119 my ($Value, $Qual) = @_;
12120 if(not $Qual) {
12121 return $Value;
12122 }
12123 if($Qual eq "all")
12124 { # all quals
12125 $Qual = "const|volatile|restrict";
12126 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040012127 while($Value=~s/\b$Qual\b//) {
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040012128 $Value = formatName($Value);
12129 }
12130 return $Value;
12131}
12132
12133sub cmpBTypes($$$$)
12134{
12135 my ($T1, $T2, $V1, $V2) = @_;
12136 $T1 = uncover_typedefs($T1, $V1);
12137 $T2 = uncover_typedefs($T2, $V2);
12138 return (rmQuals($T1, "all") eq rmQuals($T2, "all"));
12139}
12140
12141sub addedQual($$$)
12142{
12143 my ($Old_Value, $New_Value, $Qual) = @_;
Andrey Ponomarenko85043792012-05-14 16:48:07 +040012144 return removedQual_($New_Value, $Old_Value, 2, 1, $Qual);
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040012145}
12146
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012147sub removedQual($$$)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012148{
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012149 my ($Old_Value, $New_Value, $Qual) = @_;
Andrey Ponomarenko85043792012-05-14 16:48:07 +040012150 return removedQual_($Old_Value, $New_Value, 1, 2, $Qual);
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040012151}
12152
12153sub removedQual_($$$$$)
12154{
12155 my ($Old_Value, $New_Value, $V1, $V2, $Qual) = @_;
12156 $Old_Value = uncover_typedefs($Old_Value, $V1);
12157 $New_Value = uncover_typedefs($New_Value, $V2);
12158 if($Old_Value eq $New_Value)
12159 { # equal types
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012160 return 0;
12161 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040012162 if($Old_Value!~/\b$Qual\b/)
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040012163 { # without a qual
12164 return 0;
12165 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040012166 elsif($New_Value!~/\b$Qual\b/)
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040012167 { # became non-qual
12168 return 1;
12169 }
12170 else
12171 {
12172 my @BQ1 = getQualModel($Old_Value, $Qual);
12173 my @BQ2 = getQualModel($New_Value, $Qual);
12174 foreach (0 .. $#BQ1)
12175 { # removed qual
12176 if($BQ1[$_]==1
12177 and $BQ2[$_]!=1)
12178 {
12179 return 2;
12180 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012181 }
12182 }
12183 return 0;
12184}
12185
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040012186sub getQualModel($$)
12187{
12188 my ($Value, $Qual) = @_;
12189 if(not $Qual) {
12190 return $Value;
12191 }
12192
12193 # cleaning
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040012194 while($Value=~/(\w+)/ and $1 ne $Qual) {
12195 $Value=~s/\b$1\b//g;
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040012196 }
12197 $Value=~s/[^\*\&\w]+//g;
12198
12199 # modeling
12200 # int*const*const == 011
12201 # int**const == 001
12202 my @Model = ();
12203 my @Elems = split(/[\*\&]/, $Value);
12204 if(not @Elems) {
12205 return (0);
12206 }
12207 foreach (@Elems)
12208 {
12209 if($_ eq $Qual) {
12210 push(@Model, 1);
12211 }
12212 else {
12213 push(@Model, 0);
12214 }
12215 }
12216
12217 return @Model;
12218}
12219
12220sub showVal($$$)
12221{
12222 my ($Value, $TypeId, $LibVersion) = @_;
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040012223 my %PureType = get_PureType($TypeId, $LibVersion);
12224 if($PureType{"Name"}=~/\A(char(| const)\*|std::string(|&))\Z/)
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040012225 { # strings
12226 return "\"$Value\"";
12227 }
12228 elsif($PureType{"Name"}=~/\Achar(| const)\Z/)
12229 { # characters
12230 return "\'$Value\'";
12231 }
12232 return $Value;
12233}
12234
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012235sub mergeParameters($$$$$)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012236{
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012237 my ($Symbol, $PSymbol, $ParamPos1, $ParamPos2, $Level) = @_;
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040012238 if(not $Symbol) {
12239 return;
12240 }
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040012241 my $PType1_Id = $CompleteSignature{1}{$Symbol}{"Param"}{$ParamPos1}{"type"};
12242 my $PName1 = $CompleteSignature{1}{$Symbol}{"Param"}{$ParamPos1}{"name"};
12243 my $PType2_Id = $CompleteSignature{2}{$PSymbol}{"Param"}{$ParamPos2}{"type"};
12244 my $PName2 = $CompleteSignature{2}{$PSymbol}{"Param"}{$ParamPos2}{"name"};
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040012245 if(not $PType1_Id
12246 or not $PType2_Id) {
12247 return;
12248 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040012249 my %Type1 = get_Type($PType1_Id, 1);
12250 my %Type2 = get_Type($PType2_Id, 2);
12251 my %BaseType1 = get_BaseType($PType1_Id, 1);
12252 my %BaseType2 = get_BaseType($PType2_Id, 2);
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040012253 my $Parameter_Location = ($PName1)?$PName1:showPos($ParamPos1)." Parameter";
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012254 if($Level eq "Binary")
12255 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040012256 if(checkDump(1, "2.6.1") and checkDump(2, "2.6.1"))
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012257 { # "reg" attribute added in ACC 1.95.1 (dump 2.6.1 format)
12258 if($CompleteSignature{1}{$Symbol}{"Param"}{$ParamPos1}{"reg"}
12259 and not $CompleteSignature{2}{$PSymbol}{"Param"}{$ParamPos2}{"reg"})
12260 {
12261 %{$CompatProblems{$Level}{$Symbol}{"Parameter_Became_Non_Register"}{$Parameter_Location}}=(
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040012262 "Target"=>$PName1,
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012263 "Param_Pos"=>$ParamPos1 );
12264 }
12265 elsif(not $CompleteSignature{1}{$Symbol}{"Param"}{$ParamPos1}{"reg"}
12266 and $CompleteSignature{2}{$PSymbol}{"Param"}{$ParamPos2}{"reg"})
12267 {
12268 %{$CompatProblems{$Level}{$Symbol}{"Parameter_Became_Register"}{$Parameter_Location}}=(
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040012269 "Target"=>$PName1,
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012270 "Param_Pos"=>$ParamPos1 );
12271 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012272 }
12273 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040012274 if(checkDump(1, "2.0") and checkDump(2, "2.0"))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012275 { # "default" attribute added in ACC 1.22 (dump 2.0 format)
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040012276 my $Value_Old = $CompleteSignature{1}{$Symbol}{"Param"}{$ParamPos1}{"default"};
12277 my $Value_New = $CompleteSignature{2}{$PSymbol}{"Param"}{$ParamPos2}{"default"};
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040012278 if(not checkDump(1, "2.13")
12279 and checkDump(2, "2.13"))
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040012280 { # support for old ABI dumps
12281 if(defined $Value_Old and defined $Value_New)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012282 {
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040012283 if($Type1{"Name"} eq "bool"
12284 and $Value_Old eq "false" and $Value_New eq "0")
12285 { # int class::method ( bool p = 0 );
12286 # old ABI dumps: "false"
12287 # new ABI dumps: "0"
12288 $Value_Old = "0";
12289 }
12290 }
12291 }
12292 if(defined $Value_Old)
12293 {
12294 $Value_Old = showVal($Value_Old, $PType1_Id, 1);
12295 if(defined $Value_New)
12296 {
12297 $Value_New = showVal($Value_New, $PType2_Id, 2);
12298 if($Value_Old ne $Value_New)
12299 { # FIXME: how to distinguish "0" and 0 (NULL)
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012300 %{$CompatProblems{$Level}{$Symbol}{"Parameter_Default_Value_Changed"}{$Parameter_Location}}=(
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040012301 "Target"=>$PName1,
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012302 "Param_Pos"=>$ParamPos1,
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040012303 "Old_Value"=>$Value_Old,
12304 "New_Value"=>$Value_New );
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012305 }
12306 }
12307 else
12308 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012309 %{$CompatProblems{$Level}{$Symbol}{"Parameter_Default_Value_Removed"}{$Parameter_Location}}=(
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040012310 "Target"=>$PName1,
12311 "Param_Pos"=>$ParamPos1,
12312 "Old_Value"=>$Value_Old );
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012313 }
12314 }
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040012315 elsif(defined $Value_New)
12316 {
12317 $Value_New = showVal($Value_New, $PType2_Id, 2);
12318 %{$CompatProblems{$Level}{$Symbol}{"Parameter_Default_Value_Added"}{$Parameter_Location}}=(
12319 "Target"=>$PName1,
12320 "Param_Pos"=>$ParamPos1,
12321 "New_Value"=>$Value_New );
12322 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012323 }
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040012324 if($PName1 and $PName2 and $PName1 ne $PName2
12325 and $PType1_Id!=-1 and $PType2_Id!=-1
12326 and $PName1!~/\Ap\d+\Z/ and $PName2!~/\Ap\d+\Z/)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012327 { # except unnamed "..." value list (Id=-1)
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040012328 %{$CompatProblems{$Level}{$Symbol}{"Renamed_Parameter"}{showPos($ParamPos1)." Parameter"}}=(
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040012329 "Target"=>$PName1,
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012330 "Param_Pos"=>$ParamPos1,
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040012331 "Param_Type"=>$TypeInfo{1}{$PType1_Id}{"Name"},
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040012332 "Old_Value"=>$PName1,
12333 "New_Value"=>$PName2,
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012334 "New_Signature"=>get_Signature($Symbol, 2) );
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012335 }
12336 # checking type change (replace)
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040012337 my %SubProblems = detectTypeChange($PType1_Id, $PType2_Id, "Parameter", $Level);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012338 foreach my $SubProblemType (keys(%SubProblems))
12339 { # add new problems, remove false alarms
12340 my $New_Value = $SubProblems{$SubProblemType}{"New_Value"};
12341 my $Old_Value = $SubProblems{$SubProblemType}{"Old_Value"};
12342 if($SubProblemType eq "Parameter_Type")
12343 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040012344 if(checkDump(1, "2.6") and checkDump(2, "2.6"))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012345 {
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040012346 if(my $RA = addedQual($Old_Value, $New_Value, "restrict"))
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012347 {
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040012348 %{$SubProblems{"Parameter_Became_Restrict"}} = %{$SubProblems{$SubProblemType}};
12349 if($Level eq "Source"
12350 and cmpBTypes($Old_Value, $New_Value, 1, 2)) {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012351 delete($SubProblems{$SubProblemType});
12352 }
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040012353 }
12354 elsif(my $RR = removedQual($Old_Value, $New_Value, "restrict"))
12355 {
12356 %{$SubProblems{"Parameter_Became_NonRestrict"}} = %{$SubProblems{$SubProblemType}};
12357 if($Level eq "Source"
12358 and cmpBTypes($Old_Value, $New_Value, 1, 2)) {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012359 delete($SubProblems{$SubProblemType});
12360 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012361 }
12362 }
12363 if($Type2{"Type"} eq "Const" and $BaseType2{"Name"} eq $Type1{"Name"}
12364 and $Type1{"Type"}=~/Intrinsic|Class|Struct|Union|Enum/)
12365 { # int to "int const"
12366 delete($SubProblems{$SubProblemType});
12367 }
12368 if($Type1{"Type"} eq "Const" and $BaseType1{"Name"} eq $Type2{"Name"}
12369 and $Type2{"Type"}=~/Intrinsic|Class|Struct|Union|Enum/)
12370 { # "int const" to int
12371 delete($SubProblems{$SubProblemType});
12372 }
12373 }
12374 }
12375 foreach my $SubProblemType (keys(%SubProblems))
12376 { # modify/register problems
12377 my $New_Value = $SubProblems{$SubProblemType}{"New_Value"};
12378 my $Old_Value = $SubProblems{$SubProblemType}{"Old_Value"};
12379 my $NewProblemType = $SubProblemType;
12380 if($Old_Value eq "..." and $New_Value ne "...")
12381 { # change from "..." to "int"
12382 if($ParamPos1==0)
12383 { # ISO C requires a named argument before "..."
12384 next;
12385 }
12386 $NewProblemType = "Parameter_Became_NonVaList";
12387 }
12388 elsif($New_Value eq "..." and $Old_Value ne "...")
12389 { # change from "int" to "..."
12390 if($ParamPos2==0)
12391 { # ISO C requires a named argument before "..."
12392 next;
12393 }
12394 $NewProblemType = "Parameter_Became_VaList";
12395 }
12396 elsif($SubProblemType eq "Parameter_Type"
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012397 and removedQual($Old_Value, $New_Value, "const"))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012398 { # parameter: "const" to non-"const"
12399 $NewProblemType = "Parameter_Became_Non_Const";
12400 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012401 elsif($Level eq "Binary" and ($SubProblemType eq "Parameter_Type_And_Size"
12402 or $SubProblemType eq "Parameter_Type"))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012403 {
12404 my ($Arch1, $Arch2) = (getArch(1), getArch(2));
12405 if($Arch1 eq "unknown" or $Arch2 eq "unknown")
12406 { # if one of the architectures is unknown
12407 # then set other arhitecture to unknown too
12408 ($Arch1, $Arch2) = ("unknown", "unknown");
12409 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012410 my ($Method1, $Passed1, $SizeOnStack1, $RegName1) = callingConvention($Symbol, $ParamPos1, 1, $Arch1);
12411 my ($Method2, $Passed2, $SizeOnStack2, $RegName2) = callingConvention($Symbol, $ParamPos2, 2, $Arch2);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012412 if($Method1 eq $Method2)
12413 {
12414 if($Method1 eq "stack" and $SizeOnStack1 ne $SizeOnStack2) {
12415 $NewProblemType = "Parameter_Type_And_Stack";
12416 }
12417 elsif($Method1 eq "register" and $RegName1 ne $RegName2) {
12418 $NewProblemType = "Parameter_Type_And_Register";
12419 }
12420 }
12421 else
12422 {
12423 if($Method1 eq "stack") {
12424 $NewProblemType = "Parameter_Type_And_Pass_Through_Register";
12425 }
12426 elsif($Method1 eq "register") {
12427 $NewProblemType = "Parameter_Type_And_Pass_Through_Stack";
12428 }
12429 }
12430 $SubProblems{$SubProblemType}{"Old_Reg"} = $RegName1;
12431 $SubProblems{$SubProblemType}{"New_Reg"} = $RegName2;
12432 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012433 %{$CompatProblems{$Level}{$Symbol}{$NewProblemType}{$Parameter_Location}}=(
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040012434 "Target"=>$PName1,
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012435 "Param_Pos"=>$ParamPos1,
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012436 "New_Signature"=>get_Signature($Symbol, 2) );
12437 @{$CompatProblems{$Level}{$Symbol}{$NewProblemType}{$Parameter_Location}}{keys(%{$SubProblems{$SubProblemType}})} = values %{$SubProblems{$SubProblemType}};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012438 }
12439 @RecurTypes = ();
12440 # checking type definition changes
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040012441 my %SubProblems_Merge = mergeTypes($PType1_Id, $PType2_Id, $Level);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012442 foreach my $SubProblemType (keys(%SubProblems_Merge))
12443 {
12444 foreach my $SubLocation (keys(%{$SubProblems_Merge{$SubProblemType}}))
12445 {
12446 my $NewProblemType = $SubProblemType;
12447 if($SubProblemType eq "DataType_Size")
12448 {
12449 my $InitialType_Type = $SubProblems_Merge{$SubProblemType}{$SubLocation}{"InitialType_Type"};
12450 if($InitialType_Type!~/\A(Pointer|Ref)\Z/ and $SubLocation!~/\-\>/)
12451 { # stack has been affected
12452 $NewProblemType = "DataType_Size_And_Stack";
12453 }
12454 }
12455 my $NewLocation = ($SubLocation)?$Parameter_Location."->".$SubLocation:$Parameter_Location;
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012456 %{$CompatProblems{$Level}{$Symbol}{$NewProblemType}{$NewLocation}}=(
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040012457 "Param_Type"=>$TypeInfo{1}{$PType1_Id}{"Name"},
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012458 "Param_Pos"=>$ParamPos1,
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040012459 "Param_Name"=>$PName1 );
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012460 @{$CompatProblems{$Level}{$Symbol}{$NewProblemType}{$NewLocation}}{keys(%{$SubProblems_Merge{$SubProblemType}{$SubLocation}})} = values %{$SubProblems_Merge{$SubProblemType}{$SubLocation}};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012461 if($SubLocation!~/\-\>/) {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040012462 $CompatProblems{$Level}{$Symbol}{$NewProblemType}{$NewLocation}{"Start_Type_Name"} = $TypeInfo{1}{$PType1_Id}{"Name"};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012463 }
12464 }
12465 }
12466}
12467
12468sub callingConvention($$$$)
12469{ # calling conventions for different compilers and operating systems
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012470 my ($Symbol, $ParamPos, $LibVersion, $Arch) = @_;
12471 my $ParamTypeId = $CompleteSignature{$LibVersion}{$Symbol}{"Param"}{$ParamPos}{"type"};
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040012472 my %Type = get_PureType($ParamTypeId, $LibVersion);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012473 my ($Method, $Alignment, $Passed, $Register) = ("", 0, "", "");
12474 if($OSgroup=~/\A(linux|macos|freebsd)\Z/)
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012475 { # GCC
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012476 if($Arch eq "x86")
12477 { # System V ABI Intel386 ("Function Calling Sequence")
12478 # The stack is word aligned. Although the architecture does not require any
12479 # alignment of the stack, software convention and the operating system
12480 # requires that the stack be aligned on a word boundary.
12481
12482 # Argument words are pushed onto the stack in reverse order (that is, the
12483 # rightmost argument in C call syntax has the highest address), preserving the
12484 # stack’s word alignment. All incoming arguments appear on the stack, residing
12485 # in the stack frame of the caller.
12486
12487 # An argument’s size is increased, if necessary, to make it a multiple of words.
12488 # This may require tail padding, depending on the size of the argument.
12489
12490 # Other areas depend on the compiler and the code being compiled. The stan-
12491 # dard calling sequence does not define a maximum stack frame size, nor does
12492 # it restrict how a language system uses the ‘‘unspecified’’ area of the stan-
12493 # dard stack frame.
12494 ($Method, $Alignment) = ("stack", 4);
12495 }
12496 elsif($Arch eq "x86_64")
12497 { # System V AMD64 ABI ("Function Calling Sequence")
12498 ($Method, $Alignment) = ("stack", 8);# eightbyte aligned
12499 }
12500 elsif($Arch eq "arm")
12501 { # Procedure Call Standard for the ARM Architecture
12502 # The stack must be double-word aligned
12503 ($Method, $Alignment) = ("stack", 8);# double-word
12504 }
12505 }
12506 elsif($OSgroup eq "windows")
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012507 { # MS C++ Compiler
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012508 if($Arch eq "x86")
12509 {
12510 if($ParamPos==0) {
12511 ($Method, $Register, $Passed) = ("register", "ecx", "value");
12512 }
12513 elsif($ParamPos==1) {
12514 ($Method, $Register, $Passed) = ("register", "edx", "value");
12515 }
12516 else {
12517 ($Method, $Alignment) = ("stack", 4);
12518 }
12519 }
12520 elsif($Arch eq "x86_64")
12521 {
12522 if($ParamPos<=3)
12523 {
12524 if($Type{"Name"}=~/\A(float|double|long double)\Z/) {
12525 ($Method, $Passed) = ("xmm".$ParamPos, "value");
12526 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040012527 elsif(isScalar($Type{"Name"})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012528 or $Type{"Type"}=~/\A(Struct|Union|Enum|Array)\Z/
12529 or $Type{"Name"}=~/\A(__m64|__m128)\Z/)
12530 {
12531 if($ParamPos==0) {
12532 ($Method, $Register, $Passed) = ("register", "rcx", "value");
12533 }
12534 elsif($ParamPos==1) {
12535 ($Method, $Register, $Passed) = ("register", "rdx", "value");
12536 }
12537 elsif($ParamPos==2) {
12538 ($Method, $Register, $Passed) = ("register", "r8", "value");
12539 }
12540 elsif($ParamPos==3) {
12541 ($Method, $Register, $Passed) = ("register", "r9", "value");
12542 }
12543 if($Type{"Size"}>64
12544 or $Type{"Type"} eq "Array") {
12545 $Passed = "pointer";
12546 }
12547 }
12548 }
12549 else {
12550 ($Method, $Alignment) = ("stack", 8);# word alignment
12551 }
12552 }
12553 }
12554 if($Method eq "register") {
12555 return ("register", $Passed, "", $Register);
12556 }
12557 else
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012558 { # on the stack
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012559 if(not $Alignment)
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012560 { # default convention
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012561 $Alignment = $WORD_SIZE{$LibVersion};
12562 }
12563 if(not $Passed)
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012564 { # default convention
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012565 $Passed = "value";
12566 }
12567 my $SizeOnStack = $Type{"Size"};
12568 # FIXME: improve stack alignment
12569 if($SizeOnStack!=$Alignment) {
12570 $SizeOnStack = int(($Type{"Size"}+$Alignment)/$Alignment)*$Alignment;
12571 }
12572 return ("stack", $Passed, $SizeOnStack, "");
12573 }
12574}
12575
12576sub find_ParamPair_Pos_byName($$$)
12577{
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012578 my ($Name, $Symbol, $LibVersion) = @_;
12579 foreach my $ParamPos (sort {int($a)<=>int($b)} keys(%{$CompleteSignature{$LibVersion}{$Symbol}{"Param"}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012580 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012581 next if(not defined $CompleteSignature{$LibVersion}{$Symbol}{"Param"}{$ParamPos});
12582 if($CompleteSignature{$LibVersion}{$Symbol}{"Param"}{$ParamPos}{"name"} eq $Name)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012583 {
12584 return $ParamPos;
12585 }
12586 }
12587 return "lost";
12588}
12589
12590sub find_ParamPair_Pos_byTypeAndPos($$$$$)
12591{
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012592 my ($TypeName, $MediumPos, $Order, $Symbol, $LibVersion) = @_;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012593 my @Positions = ();
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012594 foreach my $ParamPos (sort {int($a)<=>int($b)} keys(%{$CompleteSignature{$LibVersion}{$Symbol}{"Param"}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012595 {
12596 next if($Order eq "backward" and $ParamPos>$MediumPos);
12597 next if($Order eq "forward" and $ParamPos<$MediumPos);
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012598 next if(not defined $CompleteSignature{$LibVersion}{$Symbol}{"Param"}{$ParamPos});
12599 my $PTypeId = $CompleteSignature{$LibVersion}{$Symbol}{"Param"}{$ParamPos}{"type"};
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040012600 if($TypeInfo{$LibVersion}{$PTypeId}{"Name"} eq $TypeName) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012601 push(@Positions, $ParamPos);
12602 }
12603 }
12604 return @Positions;
12605}
12606
12607sub getTypeIdByName($$)
12608{
12609 my ($TypeName, $Version) = @_;
12610 return $TName_Tid{$Version}{formatName($TypeName)};
12611}
12612
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012613sub checkFormatChange($$$)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012614{
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012615 my ($Type1_Id, $Type2_Id, $Level) = @_;
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040012616 my %Type1_Pure = get_PureType($Type1_Id, 1);
12617 my %Type2_Pure = get_PureType($Type2_Id, 2);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012618 if($Type1_Pure{"Name"} eq $Type2_Pure{"Name"})
12619 { # equal types
12620 return 0;
12621 }
12622 if($Type1_Pure{"Name"}=~/\*/
12623 or $Type2_Pure{"Name"}=~/\*/)
12624 { # compared in detectTypeChange()
12625 return 0;
12626 }
12627 my %FloatType = map {$_=>1} (
12628 "float",
12629 "double",
12630 "long double"
12631 );
12632 if($Type1_Pure{"Type"} ne $Type2_Pure{"Type"})
12633 { # different types
12634 if($Type1_Pure{"Type"} eq "Intrinsic"
12635 and $Type2_Pure{"Type"} eq "Enum")
12636 { # "int" to "enum"
12637 return 0;
12638 }
12639 elsif($Type2_Pure{"Type"} eq "Intrinsic"
12640 and $Type1_Pure{"Type"} eq "Enum")
12641 { # "enum" to "int"
12642 return 0;
12643 }
12644 else
12645 { # "union" to "struct"
12646 # ...
12647 return 1;
12648 }
12649 }
12650 else
12651 {
12652 if($Type1_Pure{"Type"} eq "Intrinsic")
12653 {
12654 if($FloatType{$Type1_Pure{"Name"}}
12655 or $FloatType{$Type2_Pure{"Name"}})
12656 { # "float" to "double"
12657 # "float" to "int"
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012658 if($Level eq "Source")
12659 { # Safe
12660 return 0;
12661 }
12662 else {
12663 return 1;
12664 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012665 }
12666 }
12667 elsif($Type1_Pure{"Type"}=~/Class|Struct|Union|Enum/)
12668 {
12669 my @Membs1 = keys(%{$Type1_Pure{"Memb"}});
12670 my @Membs2 = keys(%{$Type2_Pure{"Memb"}});
12671 if($#Membs1!=$#Membs2)
12672 { # different number of elements
12673 return 1;
12674 }
12675 if($Type1_Pure{"Type"} eq "Enum")
12676 {
12677 foreach my $Pos (@Membs1)
12678 { # compare elements by name and value
12679 if($Type1_Pure{"Memb"}{$Pos}{"name"} ne $Type2_Pure{"Memb"}{$Pos}{"name"}
12680 or $Type1_Pure{"Memb"}{$Pos}{"value"} ne $Type2_Pure{"Memb"}{$Pos}{"value"})
12681 { # different names
12682 return 1;
12683 }
12684 }
12685 }
12686 else
12687 {
12688 foreach my $Pos (@Membs1)
12689 { # compare elements by type name
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040012690 my $MT1 = $TypeInfo{1}{$Type1_Pure{"Memb"}{$Pos}{"type"}}{"Name"};
12691 my $MT2 = $TypeInfo{2}{$Type2_Pure{"Memb"}{$Pos}{"type"}}{"Name"};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012692 if($MT1 ne $MT2)
12693 { # different types
12694 return 1;
12695 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012696 if($Level eq "Source")
12697 {
12698 if($Type1_Pure{"Memb"}{$Pos}{"name"} ne $Type2_Pure{"Memb"}{$Pos}{"name"})
12699 { # different names
12700 return 1;
12701 }
12702 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012703 }
12704 }
12705 }
12706 }
12707 return 0;
12708}
12709
12710sub isScalar($) {
12711 return ($_[0]=~/\A(unsigned |)(short|int|long|long long)\Z/);
12712}
12713
12714sub isFloat($) {
12715 return ($_[0]=~/\A(float|double|long double)\Z/);
12716}
12717
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012718sub detectTypeChange($$$$)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012719{
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012720 my ($Type1_Id, $Type2_Id, $Prefix, $Level) = @_;
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040012721 if(not $Type1_Id or not $Type2_Id) {
12722 return ();
12723 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012724 my %LocalProblems = ();
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040012725 my %Type1 = get_Type($Type1_Id, 1);
12726 my %Type2 = get_Type($Type2_Id, 2);
12727 my %Type1_Pure = get_PureType($Type1_Id, 1);
12728 my %Type2_Pure = get_PureType($Type2_Id, 2);
12729 my %Type1_Base = ($Type1_Pure{"Type"} eq "Array")?get_OneStep_BaseType($Type1_Pure{"Tid"}, 1):get_BaseType($Type1_Id, 1);
12730 my %Type2_Base = ($Type2_Pure{"Type"} eq "Array")?get_OneStep_BaseType($Type2_Pure{"Tid"}, 2):get_BaseType($Type2_Id, 2);
12731 my $Type1_PLevel = get_PLevel($Type1_Id, 1);
12732 my $Type2_PLevel = get_PLevel($Type2_Id, 2);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012733 return () if(not $Type1{"Name"} or not $Type2{"Name"});
12734 return () if(not $Type1_Base{"Name"} or not $Type2_Base{"Name"});
12735 return () if($Type1_PLevel eq "" or $Type2_PLevel eq "");
12736 if($Type1_Base{"Name"} ne $Type2_Base{"Name"}
12737 and ($Type1{"Name"} eq $Type2{"Name"} or ($Type1_PLevel>=1 and $Type1_PLevel==$Type2_PLevel
12738 and $Type1_Base{"Name"} ne "void" and $Type2_Base{"Name"} ne "void")))
12739 { # base type change
12740 if($Type1{"Type"} eq "Typedef" and $Type2{"Type"} eq "Typedef"
12741 and $Type1{"Name"} eq $Type2{"Name"})
12742 { # will be reported in mergeTypes() as typedef problem
12743 return ();
12744 }
12745 if($Type1_Base{"Name"}!~/anon\-/ and $Type2_Base{"Name"}!~/anon\-/)
12746 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012747 if($Level eq "Binary"
12748 and $Type1_Base{"Size"} ne $Type2_Base{"Size"}
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012749 and $Type1_Base{"Size"} and $Type2_Base{"Size"})
12750 {
12751 %{$LocalProblems{$Prefix."_BaseType_And_Size"}}=(
12752 "Old_Value"=>$Type1_Base{"Name"},
12753 "New_Value"=>$Type2_Base{"Name"},
12754 "Old_Size"=>$Type1_Base{"Size"}*$BYTE_SIZE,
12755 "New_Size"=>$Type2_Base{"Size"}*$BYTE_SIZE,
12756 "InitialType_Type"=>$Type1_Pure{"Type"});
12757 }
12758 else
12759 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012760 if(checkFormatChange($Type1_Base{"Tid"}, $Type2_Base{"Tid"}, $Level))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012761 { # format change
12762 %{$LocalProblems{$Prefix."_BaseType_Format"}}=(
12763 "Old_Value"=>$Type1_Base{"Name"},
12764 "New_Value"=>$Type2_Base{"Name"},
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012765 "InitialType_Type"=>$Type1_Pure{"Type"});
12766 }
12767 elsif(tNameLock($Type1_Base{"Tid"}, $Type2_Base{"Tid"}))
12768 {
12769 %{$LocalProblems{$Prefix."_BaseType"}}=(
12770 "Old_Value"=>$Type1_Base{"Name"},
12771 "New_Value"=>$Type2_Base{"Name"},
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012772 "InitialType_Type"=>$Type1_Pure{"Type"});
12773 }
12774 }
12775 }
12776 }
12777 elsif($Type1{"Name"} ne $Type2{"Name"})
12778 { # type change
12779 if($Type1{"Name"}!~/anon\-/ and $Type2{"Name"}!~/anon\-/)
12780 {
12781 if($Prefix eq "Return" and $Type1{"Name"} eq "void"
12782 and $Type2_Pure{"Type"}=~/Intrinsic|Enum/) {
12783 # safe change
12784 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012785 elsif($Level eq "Binary"
12786 and $Prefix eq "Return"
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012787 and $Type1_Pure{"Name"} eq "void")
12788 {
12789 %{$LocalProblems{"Return_Type_From_Void"}}=(
12790 "New_Value"=>$Type2{"Name"},
12791 "New_Size"=>$Type2{"Size"}*$BYTE_SIZE,
12792 "InitialType_Type"=>$Type1_Pure{"Type"});
12793 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012794 elsif($Level eq "Binary"
12795 and $Prefix eq "Return" and $Type1_Pure{"Type"}=~/Intrinsic|Enum/
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012796 and $Type2_Pure{"Type"}=~/Struct|Class|Union/)
12797 { # returns into hidden first parameter instead of a register
12798
12799 # System V ABI Intel386 ("Function Calling Sequence")
12800 # A function that returns an integral or pointer value places its result in register %eax.
12801
12802 # A floating-point return value appears on the top of the Intel387 register stack. The
12803 # caller then must remove the value from the Intel387 stack, even if it doesn’t use the
12804 # value.
12805
12806 # If a function returns a structure or union, then the caller provides space for the
12807 # return value and places its address on the stack as argument word zero. In effect,
12808 # this address becomes a ‘‘hidden’’ first argument.
12809
12810 %{$LocalProblems{"Return_Type_From_Register_To_Stack"}}=(
12811 "Old_Value"=>$Type1{"Name"},
12812 "New_Value"=>$Type2{"Name"},
12813 "Old_Size"=>$Type1{"Size"}*$BYTE_SIZE,
12814 "New_Size"=>$Type2{"Size"}*$BYTE_SIZE,
12815 "InitialType_Type"=>$Type1_Pure{"Type"});
12816 }
12817 elsif($Prefix eq "Return"
12818 and $Type2_Pure{"Name"} eq "void")
12819 {
12820 %{$LocalProblems{"Return_Type_Became_Void"}}=(
12821 "Old_Value"=>$Type1{"Name"},
12822 "Old_Size"=>$Type1{"Size"}*$BYTE_SIZE,
12823 "InitialType_Type"=>$Type1_Pure{"Type"});
12824 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012825 elsif($Level eq "Binary" and $Prefix eq "Return"
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012826 and ((isScalar($Type1_Pure{"Name"}) and isFloat($Type2_Pure{"Name"}))
12827 or (isScalar($Type2_Pure{"Name"}) and isFloat($Type1_Pure{"Name"}))))
12828 { # The scalar and floating-point values are passed in different registers
12829 %{$LocalProblems{"Return_Type_And_Register"}}=(
12830 "Old_Value"=>$Type1{"Name"},
12831 "New_Value"=>$Type2{"Name"},
12832 "Old_Size"=>$Type1{"Size"}*$BYTE_SIZE,
12833 "New_Size"=>$Type2{"Size"}*$BYTE_SIZE,
12834 "InitialType_Type"=>$Type1_Pure{"Type"});
12835 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012836 elsif($Level eq "Binary"
12837 and $Prefix eq "Return" and $Type2_Pure{"Type"}=~/Intrinsic|Enum/
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012838 and $Type1_Pure{"Type"}=~/Struct|Class|Union/)
12839 { # returns in a register instead of a hidden first parameter
12840 %{$LocalProblems{"Return_Type_From_Stack_To_Register"}}=(
12841 "Old_Value"=>$Type1{"Name"},
12842 "New_Value"=>$Type2{"Name"},
12843 "Old_Size"=>$Type1{"Size"}*$BYTE_SIZE,
12844 "New_Size"=>$Type2{"Size"}*$BYTE_SIZE,
12845 "InitialType_Type"=>$Type1_Pure{"Type"});
12846 }
12847 else
12848 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012849 if($Level eq "Binary"
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040012850 and $Type1{"Size"} and $Type2{"Size"}
12851 and $Type1{"Size"} ne $Type2{"Size"})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012852 {
12853 %{$LocalProblems{$Prefix."_Type_And_Size"}}=(
12854 "Old_Value"=>$Type1{"Name"},
12855 "New_Value"=>$Type2{"Name"},
12856 "Old_Size"=>$Type1{"Size"}*$BYTE_SIZE,
12857 "New_Size"=>$Type2{"Size"}*$BYTE_SIZE,
12858 "InitialType_Type"=>$Type1_Pure{"Type"});
12859 }
12860 else
12861 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012862 if(checkFormatChange($Type1_Id, $Type2_Id, $Level))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012863 { # format change
12864 %{$LocalProblems{$Prefix."_Type_Format"}}=(
12865 "Old_Value"=>$Type1{"Name"},
12866 "New_Value"=>$Type2{"Name"},
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012867 "InitialType_Type"=>$Type1_Pure{"Type"});
12868 }
12869 elsif(tNameLock($Type1_Id, $Type2_Id))
12870 { # FIXME: correct this condition
12871 %{$LocalProblems{$Prefix."_Type"}}=(
12872 "Old_Value"=>$Type1{"Name"},
12873 "New_Value"=>$Type2{"Name"},
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012874 "InitialType_Type"=>$Type1_Pure{"Type"});
12875 }
12876 }
12877 }
12878 }
12879 }
12880 if($Type1_PLevel!=$Type2_PLevel)
12881 {
12882 if($Type1{"Name"} ne "void" and $Type1{"Name"} ne "..."
12883 and $Type2{"Name"} ne "void" and $Type2{"Name"} ne "...")
12884 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012885 if($Level eq "Source")
12886 {
12887 %{$LocalProblems{$Prefix."_PointerLevel"}}=(
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012888 "Old_Value"=>$Type1_PLevel,
12889 "New_Value"=>$Type2_PLevel);
12890 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012891 else
12892 {
12893 if($Type2_PLevel>$Type1_PLevel) {
12894 %{$LocalProblems{$Prefix."_PointerLevel_Increased"}}=(
12895 "Old_Value"=>$Type1_PLevel,
12896 "New_Value"=>$Type2_PLevel);
12897 }
12898 else {
12899 %{$LocalProblems{$Prefix."_PointerLevel_Decreased"}}=(
12900 "Old_Value"=>$Type1_PLevel,
12901 "New_Value"=>$Type2_PLevel);
12902 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012903 }
12904 }
12905 }
12906 if($Type1_Pure{"Type"} eq "Array")
12907 { # base_type[N] -> base_type[N]
12908 # base_type: older_structure -> typedef to newer_structure
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012909 my %SubProblems = detectTypeChange($Type1_Base{"Tid"}, $Type2_Base{"Tid"}, $Prefix, $Level);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012910 foreach my $SubProblemType (keys(%SubProblems))
12911 {
12912 $SubProblemType=~s/_Type/_BaseType/g;
12913 next if(defined $LocalProblems{$SubProblemType});
12914 foreach my $Attr (keys(%{$SubProblems{$SubProblemType}})) {
12915 $LocalProblems{$SubProblemType}{$Attr} = $SubProblems{$SubProblemType}{$Attr};
12916 }
12917 }
12918 }
12919 return %LocalProblems;
12920}
12921
12922sub tNameLock($$)
12923{
12924 my ($Tid1, $Tid2) = @_;
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040012925 my $Changed = 0;
12926 if(differentDumps("G"))
12927 { # different GCC versions
12928 $Changed = 1;
12929 }
12930 elsif(differentDumps("V"))
12931 { # different versions of ABI dumps
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040012932 if(not checkDump(1, "2.13")
12933 or not checkDump(2, "2.13"))
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040012934 { # latest names update
12935 # 2.6: added restrict qualifier
12936 # 2.13: added missed typedefs to qualified types
12937 $Changed = 1;
12938 }
12939 }
12940 if($Changed)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012941 { # different formats
12942 if($UseOldDumps)
12943 { # old dumps
12944 return 0;
12945 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040012946 my $TN1 = $TypeInfo{1}{$Tid1}{"Name"};
12947 my $TN2 = $TypeInfo{2}{$Tid2}{"Name"};
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040012948
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040012949 my $TT1 = $TypeInfo{1}{$Tid1}{"Type"};
12950 my $TT2 = $TypeInfo{2}{$Tid2}{"Type"};
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040012951
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040012952 my %Base1 = get_Type($Tid1, 1);
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040012953 while(defined $Base1{"Type"} and $Base1{"Type"} eq "Typedef") {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040012954 %Base1 = get_OneStep_BaseType($Base1{"Tid"}, 1);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012955 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040012956 my %Base2 = get_Type($Tid2, 2);
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040012957 while(defined $Base2{"Type"} and $Base2{"Type"} eq "Typedef") {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040012958 %Base2 = get_OneStep_BaseType($Base2{"Tid"}, 2);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012959 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +040012960 my $BName1 = uncover_typedefs($Base1{"Name"}, 1);
12961 my $BName2 = uncover_typedefs($Base2{"Name"}, 2);
12962 if($BName1 eq $BName2)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012963 { # equal base types
12964 return 0;
12965 }
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040012966
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040012967 if(not checkDump(1, "2.13")
12968 or not checkDump(2, "2.13"))
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040012969 { # broken array names in ABI dumps < 2.13
12970 if($TT1 eq "Array"
12971 and $TT2 eq "Array")
12972 {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012973 return 0;
12974 }
12975 }
12976
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040012977 if(not checkDump(1, "2.6")
12978 or not checkDump(2, "2.6"))
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040012979 { # added restrict attribute in 2.6
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040012980 if($TN1!~/\brestrict\b/
12981 and $TN2=~/\brestrict\b/)
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040012982 {
12983 return 0;
12984 }
12985 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012986 }
12987 return 1;
12988}
12989
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012990sub differentDumps($)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012991{
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012992 my $Check = $_[0];
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +040012993 if(defined $Cache{"differentDumps"}{$Check}) {
12994 return $Cache{"differentDumps"}{$Check};
12995 }
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040012996 if($UsedDump{1}{"V"} and $UsedDump{2}{"V"})
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012997 {
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040012998 if($Check eq "G")
12999 {
13000 if(getGccVersion(1) ne getGccVersion(2))
13001 { # different GCC versions
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +040013002 return ($Cache{"differentDumps"}{$Check}=1);
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040013003 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040013004 }
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040013005 if($Check eq "V")
13006 {
13007 if(cmpVersions(formatVersion($UsedDump{1}{"V"}, 2),
13008 formatVersion($UsedDump{2}{"V"}, 2))!=0)
13009 { # different dump versions (skip micro version)
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +040013010 return ($Cache{"differentDumps"}{$Check}=1);
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040013011 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040013012 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013013 }
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +040013014 return ($Cache{"differentDumps"}{$Check}=0);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013015}
13016
13017sub formatVersion($$)
13018{ # cut off version digits
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040013019 my ($V, $Digits) = @_;
13020 my @Elems = split(/\./, $V);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013021 return join(".", splice(@Elems, 0, $Digits));
13022}
13023
13024sub htmlSpecChars($)
13025{
13026 my $Str = $_[0];
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040013027 if($Str eq "") {
13028 return "";
13029 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013030 $Str=~s/\&([^#]|\Z)/&amp;$1/g;
13031 $Str=~s/</&lt;/g;
13032 $Str=~s/\-\>/&#45;&gt;/g; # &minus;
13033 $Str=~s/>/&gt;/g;
13034 $Str=~s/([^ ])( )([^ ])/$1\@ALONE_SP\@$3/g;
13035 $Str=~s/ /&#160;/g; # &nbsp;
13036 $Str=~s/\@ALONE_SP\@/ /g;
13037 $Str=~s/\n/<br\/>/g;
13038 $Str=~s/\"/&quot;/g;
13039 $Str=~s/\'/&#39;/g;
13040 return $Str;
13041}
13042
13043sub black_name($)
13044{
13045 my $Name = $_[0];
13046 return "<span class='iname_b'>".highLight_Signature($Name)."</span>";
13047}
13048
13049sub highLight_Signature($)
13050{
13051 my $Signature = $_[0];
13052 return highLight_Signature_PPos_Italic($Signature, "", 0, 0, 0);
13053}
13054
13055sub highLight_Signature_Italic_Color($)
13056{
13057 my $Signature = $_[0];
13058 return highLight_Signature_PPos_Italic($Signature, "", 1, 1, 1);
13059}
13060
13061sub separate_symbol($)
13062{
13063 my $Symbol = $_[0];
13064 my ($Name, $Spec, $Ver) = ($Symbol, "", "");
13065 if($Symbol=~/\A([^\@\$\?]+)([\@\$]+)([^\@\$]+)\Z/) {
13066 ($Name, $Spec, $Ver) = ($1, $2, $3);
13067 }
13068 return ($Name, $Spec, $Ver);
13069}
13070
13071sub cut_f_attrs($)
13072{
13073 if($_[0]=~s/(\))((| (const volatile|const|volatile))(| \[static\]))\Z/$1/) {
13074 return $2;
13075 }
13076 return "";
13077}
13078
13079sub highLight_Signature_PPos_Italic($$$$$)
13080{
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040013081 my ($FullSignature, $Param_Pos, $ItalicParams, $ColorParams, $ShowReturn) = @_;
13082 $Param_Pos = "" if(not defined $Param_Pos);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013083 if($CheckObjectsOnly) {
13084 $ItalicParams=$ColorParams=0;
13085 }
13086 my ($Signature, $VersionSpec, $SymbolVersion) = separate_symbol($FullSignature);
13087 my $Return = "";
13088 if($ShowRetVal and $Signature=~s/([^:]):([^:].+?)\Z/$1/g) {
13089 $Return = $2;
13090 }
Andrey Ponomarenko16934472012-03-29 15:37:04 +040013091 my $SCenter = find_center($Signature, "(");
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013092 if(not $SCenter)
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040013093 { # global data
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013094 $Signature = htmlSpecChars($Signature);
13095 $Signature=~s!(\[data\])!<span style='color:Black;font-weight:normal;'>$1</span>!g;
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040013096 $Signature .= (($SymbolVersion)?"<span class='sym_ver'>&#160;$VersionSpec&#160;$SymbolVersion</span>":"");
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013097 if($Return and $ShowReturn) {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040013098 $Signature .= "<span class='sym_p nowrap'> &#160;<b>:</b>&#160;&#160;".htmlSpecChars($Return)."</span>";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013099 }
13100 return $Signature;
13101 }
13102 my ($Begin, $End) = (substr($Signature, 0, $SCenter), "");
13103 $Begin.=" " if($Begin!~/ \Z/);
13104 $End = cut_f_attrs($Signature);
13105 my @Parts = ();
13106 my @SParts = get_s_params($Signature, 1);
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040013107 foreach my $Pos (0 .. $#SParts)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013108 {
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040013109 my $Part = $SParts[$Pos];
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013110 $Part=~s/\A\s+|\s+\Z//g;
13111 my ($Part_Styled, $ParamName) = (htmlSpecChars($Part), "");
13112 if($Part=~/\([\*]+(\w+)\)/i) {
13113 $ParamName = $1;#func-ptr
13114 }
13115 elsif($Part=~/(\w+)[\,\)]*\Z/i) {
13116 $ParamName = $1;
13117 }
13118 if(not $ParamName) {
13119 push(@Parts, $Part_Styled);
13120 next;
13121 }
13122 if($ItalicParams and not $TName_Tid{1}{$Part}
13123 and not $TName_Tid{2}{$Part})
13124 {
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040013125 my $Style = "param";
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040013126 if($Param_Pos ne ""
13127 and $Pos==$Param_Pos) {
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040013128 $Style = "focus_p";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013129 }
13130 elsif($ColorParams) {
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040013131 $Style = "color_p";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013132 }
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040013133 $Part_Styled =~ s!(\W)$ParamName([\,\)]|\Z)!$1<span class=\'$Style\'>$ParamName</span>$2!ig;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013134 }
13135 $Part_Styled=~s/,(\w)/, $1/g;
13136 push(@Parts, $Part_Styled);
13137 }
13138 if(@Parts)
13139 {
13140 foreach my $Num (0 .. $#Parts)
13141 {
13142 if($Num==$#Parts)
13143 { # add ")" to the last parameter
13144 $Parts[$Num] = "<span class='nowrap'>".$Parts[$Num]." )</span>";
13145 }
13146 elsif(length($Parts[$Num])<=45) {
13147 $Parts[$Num] = "<span class='nowrap'>".$Parts[$Num]."</span>";
13148 }
13149 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040013150 $Signature = htmlSpecChars($Begin)."<span class='sym_p'>(&#160;".join(" ", @Parts)."</span>".$End;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013151 }
13152 else {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040013153 $Signature = htmlSpecChars($Begin)."<span class='sym_p'>(&#160;)</span>".$End;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013154 }
13155 if($Return and $ShowReturn) {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040013156 $Signature .= "<span class='sym_p nowrap'> &#160;<b>:</b>&#160;&#160;".htmlSpecChars($Return)."</span>";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013157 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040013158 $Signature=~s!\[\]![&#160;]!g;
13159 $Signature=~s!operator=!operator&#160;=!g;
13160 $Signature=~s!(\[in-charge\]|\[not-in-charge\]|\[in-charge-deleting\]|\[static\])!<span class='sym_kind'>$1</span>!g;
13161 return $Signature.(($SymbolVersion)?"<span class='sym_ver'>&#160;$VersionSpec&#160;$SymbolVersion</span>":"");
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013162}
13163
13164sub get_s_params($$)
13165{
13166 my ($Signature, $Comma) = @_;
13167 my @Parts = ();
Andrey Ponomarenko16934472012-03-29 15:37:04 +040013168 my $ShortName = substr($Signature, 0, find_center($Signature, "("));
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013169 $Signature=~s/\A\Q$ShortName\E\(//g;
13170 cut_f_attrs($Signature);
13171 $Signature=~s/\)\Z//;
13172 return separate_params($Signature, $Comma);
13173}
13174
13175sub separate_params($$)
13176{
13177 my ($Params, $Comma) = @_;
13178 my @Parts = ();
Andrey Ponomarenko16934472012-03-29 15:37:04 +040013179 my %B = ( "("=>0, "<"=>0, ")"=>0, ">"=>0 );
13180 my $Part = 0;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013181 foreach my $Pos (0 .. length($Params) - 1)
13182 {
Andrey Ponomarenko16934472012-03-29 15:37:04 +040013183 my $S = substr($Params, $Pos, 1);
13184 if(defined $B{$S}) {
13185 $B{$S}+=1;
13186 }
13187 if($S eq "," and
13188 $B{"("}==$B{")"} and $B{"<"}==$B{">"})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013189 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040013190 if($Comma)
13191 { # include comma
Andrey Ponomarenko16934472012-03-29 15:37:04 +040013192 $Parts[$Part] .= $S;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013193 }
Andrey Ponomarenko16934472012-03-29 15:37:04 +040013194 $Part += 1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013195 }
13196 else {
Andrey Ponomarenko16934472012-03-29 15:37:04 +040013197 $Parts[$Part] .= $S;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013198 }
13199 }
13200 return @Parts;
13201}
13202
Andrey Ponomarenko16934472012-03-29 15:37:04 +040013203sub find_center($$)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013204{
13205 my ($Sign, $Target) = @_;
Andrey Ponomarenko16934472012-03-29 15:37:04 +040013206 my %B = ( "("=>0, "<"=>0, ")"=>0, ">"=>0 );
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013207 my $Center = 0;
Andrey Ponomarenko16934472012-03-29 15:37:04 +040013208 if($Sign=~s/(operator([^\w\s\(\)]+|\(\)))//g)
13209 { # operators
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013210 $Center+=length($1);
13211 }
13212 foreach my $Pos (0 .. length($Sign)-1)
13213 {
13214 my $S = substr($Sign, $Pos, 1);
13215 if($S eq $Target)
13216 {
13217 if($B{"("}==$B{")"}
13218 and $B{"<"}==$B{">"}) {
13219 return $Center;
13220 }
13221 }
13222 if(defined $B{$S}) {
13223 $B{$S}+=1;
13224 }
13225 $Center+=1;
13226 }
13227 return 0;
13228}
13229
13230sub appendFile($$)
13231{
13232 my ($Path, $Content) = @_;
13233 return if(not $Path);
13234 if(my $Dir = get_dirname($Path)) {
13235 mkpath($Dir);
13236 }
Andrey Ponomarenko16934472012-03-29 15:37:04 +040013237 open(FILE, ">>", $Path) || die ("can't open file \'$Path\': $!\n");
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013238 print FILE $Content;
13239 close(FILE);
13240}
13241
13242sub writeFile($$)
13243{
13244 my ($Path, $Content) = @_;
13245 return if(not $Path);
13246 if(my $Dir = get_dirname($Path)) {
13247 mkpath($Dir);
13248 }
Andrey Ponomarenko16934472012-03-29 15:37:04 +040013249 open(FILE, ">", $Path) || die ("can't open file \'$Path\': $!\n");
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013250 print FILE $Content;
13251 close(FILE);
13252}
13253
13254sub readFile($)
13255{
13256 my $Path = $_[0];
13257 return "" if(not $Path or not -f $Path);
Andrey Ponomarenko16934472012-03-29 15:37:04 +040013258 open(FILE, $Path);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013259 local $/ = undef;
13260 my $Content = <FILE>;
13261 close(FILE);
Andrey Ponomarenko85043792012-05-14 16:48:07 +040013262 if($Path!~/\.(tu|class|abi)\Z/) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013263 $Content=~s/\r/\n/g;
13264 }
13265 return $Content;
13266}
13267
13268sub get_filename($)
13269{ # much faster than basename() from File::Basename module
Andrey Ponomarenko85043792012-05-14 16:48:07 +040013270 if(defined $Cache{"get_filename"}{$_[0]}) {
13271 return $Cache{"get_filename"}{$_[0]};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013272 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +040013273 if($_[0] and $_[0]=~/([^\/\\]+)[\/\\]*\Z/) {
13274 return ($Cache{"get_filename"}{$_[0]}=$1);
13275 }
13276 return ($Cache{"get_filename"}{$_[0]}="");
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013277}
13278
13279sub get_dirname($)
13280{ # much faster than dirname() from File::Basename module
Andrey Ponomarenko85043792012-05-14 16:48:07 +040013281 if(defined $Cache{"get_dirname"}{$_[0]}) {
13282 return $Cache{"get_dirname"}{$_[0]};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013283 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +040013284 if($_[0] and $_[0]=~/\A(.*?)[\/\\]+[^\/\\]*[\/\\]*\Z/) {
13285 return ($Cache{"get_dirname"}{$_[0]}=$1);
13286 }
13287 return ($Cache{"get_dirname"}{$_[0]}="");
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013288}
13289
13290sub separate_path($) {
13291 return (get_dirname($_[0]), get_filename($_[0]));
13292}
13293
13294sub esc($)
13295{
13296 my $Str = $_[0];
13297 $Str=~s/([()\[\]{}$ &'"`;,<>\+])/\\$1/g;
13298 return $Str;
13299}
13300
13301sub readLineNum($$)
13302{
13303 my ($Path, $Num) = @_;
13304 return "" if(not $Path or not -f $Path);
Andrey Ponomarenko16934472012-03-29 15:37:04 +040013305 open(FILE, $Path);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013306 foreach (1 ... $Num) {
13307 <FILE>;
13308 }
13309 my $Line = <FILE>;
13310 close(FILE);
13311 return $Line;
13312}
13313
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040013314sub readAttributes($$)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013315{
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040013316 my ($Path, $Num) = @_;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013317 return () if(not $Path or not -f $Path);
13318 my %Attributes = ();
Andrey Ponomarenko85043792012-05-14 16:48:07 +040013319 if(readLineNum($Path, $Num)=~/<!--\s+(.+)\s+-->/)
13320 {
13321 foreach my $AttrVal (split(/;/, $1))
13322 {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013323 if($AttrVal=~/(.+):(.+)/)
13324 {
13325 my ($Name, $Value) = ($1, $2);
13326 $Attributes{$Name} = $Value;
13327 }
13328 }
13329 }
13330 return \%Attributes;
13331}
13332
13333sub is_abs($) {
13334 return ($_[0]=~/\A(\/|\w+:[\/\\])/);
13335}
13336
13337sub get_abs_path($)
13338{ # abs_path() should NOT be called for absolute inputs
13339 # because it can change them
13340 my $Path = $_[0];
13341 if(not is_abs($Path)) {
13342 $Path = abs_path($Path);
13343 }
13344 return $Path;
13345}
13346
13347sub get_OSgroup()
13348{
13349 $_ = $Config{"osname"};
13350 if(/macos|darwin|rhapsody/i) {
13351 return "macos";
13352 }
13353 elsif(/freebsd|openbsd|netbsd/i) {
13354 return "bsd";
13355 }
13356 elsif(/haiku|beos/i) {
13357 return "beos";
13358 }
13359 elsif(/symbian|epoc/i) {
13360 return "symbian";
13361 }
13362 elsif(/win/i) {
13363 return "windows";
13364 }
13365 else {
13366 return $_;
13367 }
13368}
13369
13370sub getGccVersion($)
13371{
13372 my $LibVersion = $_[0];
13373 if($GCC_VERSION{$LibVersion})
13374 { # dump version
13375 return $GCC_VERSION{$LibVersion};
13376 }
13377 elsif($UsedDump{$LibVersion}{"V"})
13378 { # old-version dumps
13379 return "unknown";
13380 }
13381 my $GccVersion = get_dumpversion($GCC_PATH); # host version
13382 if(not $GccVersion) {
13383 return "unknown";
13384 }
13385 return $GccVersion;
13386}
13387
13388sub showArch($)
13389{
13390 my $Arch = $_[0];
13391 if($Arch eq "arm"
13392 or $Arch eq "mips") {
13393 return uc($Arch);
13394 }
13395 return $Arch;
13396}
13397
13398sub getArch($)
13399{
13400 my $LibVersion = $_[0];
13401 if($CPU_ARCH{$LibVersion})
13402 { # dump version
13403 return $CPU_ARCH{$LibVersion};
13404 }
13405 elsif($UsedDump{$LibVersion}{"V"})
13406 { # old-version dumps
13407 return "unknown";
13408 }
13409 if(defined $Cache{"getArch"}{$LibVersion}) {
13410 return $Cache{"getArch"}{$LibVersion};
13411 }
13412 my $Arch = get_dumpmachine($GCC_PATH); # host version
13413 if(not $Arch) {
13414 return "unknown";
13415 }
13416 if($Arch=~/\A([\w]{3,})(-|\Z)/) {
13417 $Arch = $1;
13418 }
13419 $Arch = "x86" if($Arch=~/\Ai[3-7]86\Z/);
13420 if($OSgroup eq "windows") {
13421 $Arch = "x86" if($Arch=~/win32|mingw32/i);
13422 $Arch = "x86_64" if($Arch=~/win64|mingw64/i);
13423 }
13424 $Cache{"getArch"}{$LibVersion} = $Arch;
13425 return $Arch;
13426}
13427
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040013428sub get_Report_Header($)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013429{
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040013430 my $Level = $_[0];
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013431 my $ArchInfo = " on <span style='color:Blue;'>".showArch(getArch(1))."</span>";
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040013432 if(getArch(1) ne getArch(2)
13433 or getArch(1) eq "unknown"
13434 or $Level eq "Source")
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013435 { # don't show architecture in the header
13436 $ArchInfo="";
13437 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040013438 my $Report_Header = "<h1><span class='nowrap'>";
13439 if($Level eq "Source") {
13440 $Report_Header .= "Source compatibility";
13441 }
13442 elsif($Level eq "Binary") {
13443 $Report_Header .= "Binary compatibility";
13444 }
13445 else {
13446 $Report_Header .= "API compatibility";
13447 }
13448 $Report_Header .= " report for the <span style='color:Blue;'>$TargetLibraryFName</span> $TargetComponent</span>";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013449 $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>";
13450 if($AppPath) {
13451 $Report_Header .= " <span class='nowrap'>&#160;(relating to the portability of application <span style='color:Blue;'>".get_filename($AppPath)."</span>)</span>";
13452 }
13453 $Report_Header .= "</h1>\n";
13454 return $Report_Header;
13455}
13456
13457sub get_SourceInfo()
13458{
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040013459 my ($CheckedHeaders, $CheckedLibs) = ("", "");
13460 if(not $CheckObjectsOnly)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013461 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040013462 $CheckedHeaders = "<a name='Headers'></a><h2>Header Files (".keys(%{$Registered_Headers{1}}).")</h2><hr/>\n";
13463 $CheckedHeaders .= "<div class='h_list'>\n";
13464 foreach my $Header_Path (sort {lc($Registered_Headers{1}{$a}{"Identity"}) cmp lc($Registered_Headers{1}{$b}{"Identity"})} keys(%{$Registered_Headers{1}}))
13465 {
13466 my $Identity = $Registered_Headers{1}{$Header_Path}{"Identity"};
13467 my $Header_Name = get_filename($Identity);
13468 my $Dest_Comment = ($Identity=~/[\/\\]/)?" ($Identity)":"";
13469 $CheckedHeaders .= $Header_Name.$Dest_Comment."<br/>\n";
13470 }
13471 $CheckedHeaders .= "</div>\n";
13472 $CheckedHeaders .= "<br/>$TOP_REF<br/>\n";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013473 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040013474 if(not $CheckHeadersOnly)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013475 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040013476 $CheckedLibs = "<a name='Libs'></a><h2>".ucfirst($SLIB_TYPE)." Libraries (".keys(%{$Library_Symbol{1}}).")</h2><hr/>\n";
13477 $CheckedLibs .= "<div class='lib_list'>\n";
13478 foreach my $Library (sort {lc($a) cmp lc($b)} keys(%{$Library_Symbol{1}}))
13479 {
13480 $Library.=" (.$LIB_EXT)" if($Library!~/\.\w+\Z/);
13481 $CheckedLibs .= $Library."<br/>\n";
13482 }
13483 $CheckedLibs .= "</div>\n";
13484 $CheckedLibs .= "<br/>$TOP_REF<br/>\n";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013485 }
13486 return $CheckedHeaders.$CheckedLibs;
13487}
13488
13489sub get_TypeProblems_Count($$$)
13490{
13491 my ($TypeChanges, $TargetPriority, $Level) = @_;
13492 my $Type_Problems_Count = 0;
13493 foreach my $Type_Name (sort keys(%{$TypeChanges}))
13494 {
13495 my %Kinds_Target = ();
13496 foreach my $Kind (keys(%{$TypeChanges->{$Type_Name}}))
13497 {
13498 foreach my $Location (keys(%{$TypeChanges->{$Type_Name}{$Kind}}))
13499 {
13500 my $Target = $TypeChanges->{$Type_Name}{$Kind}{$Location}{"Target"};
13501 my $Priority = getProblemSeverity($Level, $Kind);
13502 next if($Priority ne $TargetPriority);
13503 if($Kinds_Target{$Kind}{$Target}) {
13504 next;
13505 }
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040013506 if(cmpSeverities($Type_MaxSeverity{$Level}{$Type_Name}{$Kind}{$Target}, $Priority))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013507 { # select a problem with the highest priority
13508 next;
13509 }
13510 $Kinds_Target{$Kind}{$Target} = 1;
13511 $Type_Problems_Count += 1;
13512 }
13513 }
13514 }
13515 return $Type_Problems_Count;
13516}
13517
13518sub get_Summary($)
13519{
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040013520 my $Level = $_[0];
13521 my ($Added, $Removed, $I_Problems_High, $I_Problems_Medium, $I_Problems_Low, $T_Problems_High,
13522 $C_Problems_Low, $T_Problems_Medium, $T_Problems_Low, $I_Other, $T_Other) = (0,0,0,0,0,0,0,0,0,0,0);
13523 %{$RESULT{$Level}} = (
13524 "Problems"=>0,
13525 "Warnings"=>0,
13526 "Affected"=>0 );
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013527 # check rules
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040013528 foreach my $Interface (sort keys(%{$CompatProblems{$Level}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013529 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040013530 foreach my $Kind (keys(%{$CompatProblems{$Level}{$Interface}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013531 {
13532 if(not defined $CompatRules{$Level}{$Kind})
13533 { # unknown rule
13534 if(not $UnknownRules{$Level}{$Kind})
13535 { # only one warning
13536 printMsg("WARNING", "unknown rule \"$Kind\" (\"$Level\")");
13537 $UnknownRules{$Level}{$Kind}=1;
13538 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040013539 delete($CompatProblems{$Level}{$Interface}{$Kind});
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013540 }
13541 }
13542 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040013543 foreach my $Interface (sort keys(%{$CompatProblems{$Level}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013544 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040013545 foreach my $Kind (sort keys(%{$CompatProblems{$Level}{$Interface}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013546 {
13547 if($CompatRules{$Level}{$Kind}{"Kind"} eq "Symbols")
13548 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040013549 foreach my $Location (sort keys(%{$CompatProblems{$Level}{$Interface}{$Kind}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013550 {
13551 my $Priority = getProblemSeverity($Level, $Kind);
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040013552 if($Kind eq "Added_Symbol") {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013553 $Added += 1;
13554 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040013555 elsif($Kind eq "Removed_Symbol")
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013556 {
13557 $Removed += 1;
13558 $TotalAffected{$Level}{$Interface} = $Priority;
13559 }
13560 else
13561 {
13562 if($Priority eq "Safe") {
13563 $I_Other += 1;
13564 }
13565 elsif($Priority eq "High") {
13566 $I_Problems_High += 1;
13567 }
13568 elsif($Priority eq "Medium") {
13569 $I_Problems_Medium += 1;
13570 }
13571 elsif($Priority eq "Low") {
13572 $I_Problems_Low += 1;
13573 }
13574 if(($Priority ne "Low" or $StrictCompat)
13575 and $Priority ne "Safe") {
13576 $TotalAffected{$Level}{$Interface} = $Priority;
13577 }
13578 }
13579 }
13580 }
13581 }
13582 }
13583 my %TypeChanges = ();
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040013584 foreach my $Interface (sort keys(%{$CompatProblems{$Level}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013585 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040013586 foreach my $Kind (keys(%{$CompatProblems{$Level}{$Interface}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013587 {
13588 if($CompatRules{$Level}{$Kind}{"Kind"} eq "Types")
13589 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040013590 foreach my $Location (sort {cmp_locations($b, $a)} sort keys(%{$CompatProblems{$Level}{$Interface}{$Kind}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013591 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040013592 my $Type_Name = $CompatProblems{$Level}{$Interface}{$Kind}{$Location}{"Type_Name"};
13593 my $Target = $CompatProblems{$Level}{$Interface}{$Kind}{$Location}{"Target"};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013594 my $Priority = getProblemSeverity($Level, $Kind);
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040013595 if(cmpSeverities($Type_MaxSeverity{$Level}{$Type_Name}{$Kind}{$Target}, $Priority))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013596 { # select a problem with the highest priority
13597 next;
13598 }
13599 if(($Priority ne "Low" or $StrictCompat)
13600 and $Priority ne "Safe") {
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040013601 $TotalAffected{$Level}{$Interface} = maxSeverity($TotalAffected{$Level}{$Interface}, $Priority);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013602 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040013603 %{$TypeChanges{$Type_Name}{$Kind}{$Location}} = %{$CompatProblems{$Level}{$Interface}{$Kind}{$Location}};
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040013604 $Type_MaxSeverity{$Level}{$Type_Name}{$Kind}{$Target} = maxSeverity($Type_MaxSeverity{$Level}{$Type_Name}{$Kind}{$Target}, $Priority);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013605 }
13606 }
13607 }
13608 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040013609
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013610 $T_Problems_High = get_TypeProblems_Count(\%TypeChanges, "High", $Level);
13611 $T_Problems_Medium = get_TypeProblems_Count(\%TypeChanges, "Medium", $Level);
13612 $T_Problems_Low = get_TypeProblems_Count(\%TypeChanges, "Low", $Level);
13613 $T_Other = get_TypeProblems_Count(\%TypeChanges, "Safe", $Level);
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040013614
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013615 if($CheckObjectsOnly)
13616 { # only removed exported symbols
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040013617 $RESULT{$Level}{"Affected"} = $Removed*100/keys(%{$Symbol_Library{1}});
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013618 }
13619 else
13620 { # changed and removed public symbols
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040013621 my $SCount = keys(%{$CheckedSymbols{$Level}});
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013622 if($ExtendedCheck)
13623 { # don't count external_func_0 for constants
13624 $SCount-=1;
13625 }
13626 if($SCount)
13627 {
13628 my %Weight = (
13629 "High" => 100,
13630 "Medium" => 50,
13631 "Low" => 25
13632 );
13633 foreach (keys(%{$TotalAffected{$Level}})) {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040013634 $RESULT{$Level}{"Affected"}+=$Weight{$TotalAffected{$Level}{$_}};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013635 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040013636 $RESULT{$Level}{"Affected"} = $RESULT{$Level}{"Affected"}/$SCount;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013637 }
13638 else {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040013639 $RESULT{$Level}{"Affected"} = 0;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013640 }
13641 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040013642 $RESULT{$Level}{"Affected"} = show_number($RESULT{$Level}{"Affected"});
13643 if($RESULT{$Level}{"Affected"}>=100) {
13644 $RESULT{$Level}{"Affected"} = 100;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013645 }
13646
Andrey Ponomarenko85043792012-05-14 16:48:07 +040013647 $RESULT{$Level}{"Problems"} += $Removed;
13648 $RESULT{$Level}{"Problems"} += $T_Problems_High + $I_Problems_High;
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040013649 $RESULT{$Level}{"Problems"} += $T_Problems_Medium + $I_Problems_Medium;
Andrey Ponomarenko85043792012-05-14 16:48:07 +040013650 if($StrictCompat) {
13651 $RESULT{$Level}{"Problems"} += $T_Problems_Low + $I_Problems_Low;
13652 }
13653 else {
13654 $RESULT{$Level}{"Warnings"} += $T_Problems_Low + $I_Problems_Low;
13655 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013656
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040013657 if($C_Problems_Low = keys(%{$ProblemsWithConstants{$Level}}))
13658 {
Andrey Ponomarenko85043792012-05-14 16:48:07 +040013659 if(defined $CompatRules{$Level}{"Changed_Constant"})
13660 {
13661 if($StrictCompat) {
13662 $RESULT{$Level}{"Problems"} += $C_Problems_Low;
13663 }
13664 else {
13665 $RESULT{$Level}{"Warnings"} += $C_Problems_Low;
13666 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040013667 }
13668 else
13669 {
13670 printMsg("WARNING", "unknown rule \"Changed_Constant\" (\"$Level\")");
13671 $C_Problems_Low = 0;
13672 }
13673 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +040013674 if($CheckImpl and $Level eq "Binary")
13675 {
13676 if($StrictCompat) {
13677 $RESULT{$Level}{"Problems"} += keys(%ImplProblems);
13678 }
13679 else {
13680 $RESULT{$Level}{"Warnings"} += keys(%ImplProblems);
13681 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040013682 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +040013683 if($RESULT{$Level}{"Problems"}
13684 and $RESULT{$Level}{"Affected"}) {
13685 $RESULT{$Level}{"Verdict"} = "incompatible";
13686 }
13687 else {
13688 $RESULT{$Level}{"Verdict"} = "compatible";
13689 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040013690
13691 my $TotalTypes = keys(%{$CheckedTypes{$Level}});
13692 if(not $TotalTypes)
13693 { # list all the types
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013694 $TotalTypes = keys(%{$TName_Tid{1}});
13695 }
13696
13697 my ($Arch1, $Arch2) = (getArch(1), getArch(2));
13698 my ($GccV1, $GccV2) = (getGccVersion(1), getGccVersion(2));
13699
13700 my ($TestInfo, $TestResults, $Problem_Summary) = ();
13701
13702 if($ReportFormat eq "xml")
13703 { # XML
13704 # test info
13705 $TestInfo .= " <library>$TargetLibraryName</library>\n";
13706 $TestInfo .= " <version1>\n";
13707 $TestInfo .= " <number>".$Descriptor{1}{"Version"}."</number>\n";
13708 $TestInfo .= " <architecture>$Arch1</architecture>\n";
13709 $TestInfo .= " <gcc>$GccV1</gcc>\n";
13710 $TestInfo .= " </version1>\n";
13711
13712 $TestInfo .= " <version2>\n";
13713 $TestInfo .= " <number>".$Descriptor{2}{"Version"}."</number>\n";
13714 $TestInfo .= " <architecture>$Arch2</architecture>\n";
13715 $TestInfo .= " <gcc>$GccV2</gcc>\n";
13716 $TestInfo .= " </version2>\n";
13717 $TestInfo = "<test_info>\n".$TestInfo."</test_info>\n\n";
13718
13719 # test results
13720 $TestResults .= " <headers>\n";
13721 foreach my $Name (sort {lc($Registered_Headers{1}{$a}{"Identity"}) cmp lc($Registered_Headers{1}{$b}{"Identity"})} keys(%{$Registered_Headers{1}}))
13722 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040013723 my $Identity = $Registered_Headers{1}{$Name}{"Identity"};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013724 my $Comment = ($Identity=~/[\/\\]/)?" ($Identity)":"";
13725 $TestResults .= " <name>".get_filename($Name).$Comment."</name>\n";
13726 }
13727 $TestResults .= " </headers>\n";
13728
13729 $TestResults .= " <libs>\n";
13730 foreach my $Library (sort {lc($a) cmp lc($b)} keys(%{$Library_Symbol{1}}))
13731 {
13732 $Library.=" (.$LIB_EXT)" if($Library!~/\.\w+\Z/);
13733 $TestResults .= " <name>$Library</name>\n";
13734 }
13735 $TestResults .= " </libs>\n";
13736
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040013737 $TestResults .= " <symbols>".(keys(%{$CheckedSymbols{$Level}}) - keys(%ExtendedSymbols))."</symbols>\n";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013738 $TestResults .= " <types>".$TotalTypes."</types>\n";
13739
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040013740 $TestResults .= " <verdict>".$RESULT{$Level}{"Verdict"}."</verdict>\n";
13741 $TestResults .= " <affected>".$RESULT{$Level}{"Affected"}."</affected>\n";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013742 $TestResults = "<test_results>\n".$TestResults."</test_results>\n\n";
13743
13744 # problem summary
13745 $Problem_Summary .= " <added_symbols>".$Added."</added_symbols>\n";
13746 $Problem_Summary .= " <removed_symbols>".$Removed."</removed_symbols>\n";
13747
13748 $Problem_Summary .= " <problems_with_types>\n";
13749 $Problem_Summary .= " <high>$T_Problems_High</high>\n";
13750 $Problem_Summary .= " <medium>$T_Problems_Medium</medium>\n";
13751 $Problem_Summary .= " <low>$T_Problems_Low</low>\n";
13752 $Problem_Summary .= " <safe>$T_Other</safe>\n";
13753 $Problem_Summary .= " </problems_with_types>\n";
13754
13755 $Problem_Summary .= " <problems_with_symbols>\n";
13756 $Problem_Summary .= " <high>$I_Problems_High</high>\n";
13757 $Problem_Summary .= " <medium>$I_Problems_Medium</medium>\n";
13758 $Problem_Summary .= " <low>$I_Problems_Low</low>\n";
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040013759 $Problem_Summary .= " <safe>$I_Other</safe>\n";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013760 $Problem_Summary .= " </problems_with_symbols>\n";
13761
13762 $Problem_Summary .= " <problems_with_constants>\n";
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040013763 $Problem_Summary .= " <low>$C_Problems_Low</low>\n";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013764 $Problem_Summary .= " </problems_with_constants>\n";
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040013765 if($CheckImpl and $Level eq "Binary")
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013766 {
13767 $Problem_Summary .= " <impl>\n";
13768 $Problem_Summary .= " <low>".keys(%ImplProblems)."</low>\n";
13769 $Problem_Summary .= " </impl>\n";
13770 }
13771 $Problem_Summary = "<problem_summary>\n".$Problem_Summary."</problem_summary>\n\n";
13772
13773 return ($TestInfo.$TestResults.$Problem_Summary, "");
13774 }
13775 else
13776 { # HTML
13777 # test info
13778 $TestInfo = "<h2>Test Info</h2><hr/>\n";
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040013779 $TestInfo .= "<table class='summary'>\n";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013780 $TestInfo .= "<tr><th>".ucfirst($TargetComponent)." Name</th><td>$TargetLibraryFName</td></tr>\n";
13781
13782 my (@VInf1, @VInf2, $AddTestInfo) = ();
13783 if($Arch1 ne "unknown"
13784 and $Arch2 ne "unknown")
13785 { # CPU arch
13786 if($Arch1 eq $Arch2)
13787 { # go to the separate section
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040013788 $AddTestInfo .= "<tr><th>CPU Type</th><td>".showArch($Arch1)."</td></tr>\n";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013789 }
13790 else
13791 { # go to the version number
13792 push(@VInf1, showArch($Arch1));
13793 push(@VInf2, showArch($Arch2));
13794 }
13795 }
13796 if($GccV1 ne "unknown"
13797 and $GccV2 ne "unknown"
13798 and $OStarget ne "windows")
13799 { # GCC version
13800 if($GccV1 eq $GccV2)
13801 { # go to the separate section
13802 $AddTestInfo .= "<tr><th>GCC Version</th><td>$GccV1</td></tr>\n";
13803 }
13804 else
13805 { # go to the version number
13806 push(@VInf1, "gcc ".$GccV1);
13807 push(@VInf2, "gcc ".$GccV2);
13808 }
13809 }
13810 # show long version names with GCC version and CPU architecture name (if different)
13811 $TestInfo .= "<tr><th>Version #1</th><td>".$Descriptor{1}{"Version"}.(@VInf1?" (".join(", ", reverse(@VInf1)).")":"")."</td></tr>\n";
13812 $TestInfo .= "<tr><th>Version #2</th><td>".$Descriptor{2}{"Version"}.(@VInf2?" (".join(", ", reverse(@VInf2)).")":"")."</td></tr>\n";
13813 $TestInfo .= $AddTestInfo;
13814 #if($COMMON_LANGUAGE{1}) {
13815 # $TestInfo .= "<tr><th>Language</th><td>".$COMMON_LANGUAGE{1}."</td></tr>\n";
13816 #}
13817 if($ExtendedCheck) {
13818 $TestInfo .= "<tr><th>Mode</th><td>Extended</td></tr>\n";
13819 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040013820 if($JoinReport)
13821 {
13822 if($Level eq "Binary") {
Andrey Ponomarenko16934472012-03-29 15:37:04 +040013823 $TestInfo .= "<tr><th>Subject</th><td width='150px'>Binary Compatibility</td></tr>\n"; # Run-time
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040013824 }
13825 if($Level eq "Source") {
Andrey Ponomarenko16934472012-03-29 15:37:04 +040013826 $TestInfo .= "<tr><th>Subject</th><td width='150px'>Source Compatibility</td></tr>\n"; # Build-time
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040013827 }
13828 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013829 $TestInfo .= "</table>\n";
13830
13831 # test results
13832 $TestResults = "<h2>Test Results</h2><hr/>\n";
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040013833 $TestResults .= "<table class='summary'>";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013834
13835 my $Headers_Link = "0";
13836 $Headers_Link = "<a href='#Headers' style='color:Blue;'>".keys(%{$Registered_Headers{1}})."</a>" if(keys(%{$Registered_Headers{1}})>0);
13837 $TestResults .= "<tr><th>Total Header Files</th><td>".($CheckObjectsOnly?"0&#160;(not&#160;analyzed)":$Headers_Link)."</td></tr>\n";
13838
13839 if(not $ExtendedCheck)
13840 {
13841 my $Libs_Link = "0";
13842 $Libs_Link = "<a href='#Libs' style='color:Blue;'>".keys(%{$Library_Symbol{1}})."</a>" if(keys(%{$Library_Symbol{1}})>0);
13843 $TestResults .= "<tr><th>Total ".ucfirst($SLIB_TYPE)." Libraries</th><td>".($CheckHeadersOnly?"0&#160;(not&#160;analyzed)":$Libs_Link)."</td></tr>\n";
13844 }
13845
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040013846 $TestResults .= "<tr><th>Total Symbols / Types</th><td>".(keys(%{$CheckedSymbols{$Level}}) - keys(%ExtendedSymbols))." / ".$TotalTypes."</td></tr>\n";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013847
Andrey Ponomarenko85043792012-05-14 16:48:07 +040013848 my $META_DATA = "verdict:".$RESULT{$Level}{"Verdict"}.";";
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040013849 if($JoinReport) {
13850 $META_DATA = "kind:".lc($Level).";".$META_DATA;
13851 }
Andrey Ponomarenko16934472012-03-29 15:37:04 +040013852 $TestResults .= "<tr><th>Verdict</th>";
Andrey Ponomarenko85043792012-05-14 16:48:07 +040013853 if($RESULT{$Level}{"Verdict"} eq "incompatible") {
Andrey Ponomarenko16934472012-03-29 15:37:04 +040013854 $TestResults .= "<td><span style='color:Red;'><b>Incompatible<br/>(".$RESULT{$Level}{"Affected"}."%)</b></span></td>";
13855 }
13856 else {
13857 $TestResults .= "<td><span style='color:Green;'><b>Compatible</b></span></td>";
13858 }
13859 $TestResults .= "</tr>\n";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013860 $TestResults .= "</table>\n";
13861
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040013862 $META_DATA .= "affected:".$RESULT{$Level}{"Affected"}.";";# in percents
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013863 # problem summary
13864 $Problem_Summary = "<h2>Problem Summary</h2><hr/>\n";
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040013865 $Problem_Summary .= "<table class='summary'>";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013866 $Problem_Summary .= "<tr><th></th><th style='text-align:center;'>Severity</th><th style='text-align:center;'>Count</th></tr>";
13867
13868 my $Added_Link = "0";
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040013869 if($Added>0)
13870 {
13871 if($JoinReport) {
13872 $Added_Link = "<a href='#".$Level."_Added' style='color:Blue;'>$Added</a>";
13873 }
13874 else {
13875 $Added_Link = "<a href='#Added' style='color:Blue;'>$Added</a>";
13876 }
13877 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013878 $META_DATA .= "added:$Added;";
Andrey Ponomarenko16934472012-03-29 15:37:04 +040013879 $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 +040013880
13881 my $Removed_Link = "0";
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040013882 if($Removed>0)
13883 {
13884 if($JoinReport) {
13885 $Removed_Link = "<a href='#".$Level."_Removed' style='color:Blue;'>$Removed</a>"
13886 }
13887 else {
13888 $Removed_Link = "<a href='#Removed' style='color:Blue;'>$Removed</a>"
13889 }
13890 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013891 $META_DATA .= "removed:$Removed;";
Andrey Ponomarenko16934472012-03-29 15:37:04 +040013892 $Problem_Summary .= "<tr><th>Removed Symbols</th>";
13893 $Problem_Summary .= "<td>High</td><td".getStyle("I", "R", $Removed).">$Removed_Link</td></tr>\n";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013894
13895 my $TH_Link = "0";
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040013896 $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 +040013897 $TH_Link = "n/a" if($CheckObjectsOnly);
13898 $META_DATA .= "type_problems_high:$T_Problems_High;";
Andrey Ponomarenko16934472012-03-29 15:37:04 +040013899 $Problem_Summary .= "<tr><th rowspan='3'>Problems with<br/>Data Types</th>";
13900 $Problem_Summary .= "<td>High</td><td".getStyle("T", "H", $T_Problems_High).">$TH_Link</td></tr>\n";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013901
13902 my $TM_Link = "0";
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040013903 $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 +040013904 $TM_Link = "n/a" if($CheckObjectsOnly);
13905 $META_DATA .= "type_problems_medium:$T_Problems_Medium;";
Andrey Ponomarenko16934472012-03-29 15:37:04 +040013906 $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 +040013907
13908 my $TL_Link = "0";
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040013909 $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 +040013910 $TL_Link = "n/a" if($CheckObjectsOnly);
13911 $META_DATA .= "type_problems_low:$T_Problems_Low;";
Andrey Ponomarenko16934472012-03-29 15:37:04 +040013912 $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 +040013913
13914 my $IH_Link = "0";
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040013915 $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 +040013916 $IH_Link = "n/a" if($CheckObjectsOnly);
13917 $META_DATA .= "interface_problems_high:$I_Problems_High;";
Andrey Ponomarenko16934472012-03-29 15:37:04 +040013918 $Problem_Summary .= "<tr><th rowspan='3'>Problems with<br/>Symbols</th>";
13919 $Problem_Summary .= "<td>High</td><td".getStyle("I", "H", $I_Problems_High).">$IH_Link</td></tr>\n";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013920
13921 my $IM_Link = "0";
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040013922 $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 +040013923 $IM_Link = "n/a" if($CheckObjectsOnly);
13924 $META_DATA .= "interface_problems_medium:$I_Problems_Medium;";
Andrey Ponomarenko16934472012-03-29 15:37:04 +040013925 $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 +040013926
13927 my $IL_Link = "0";
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040013928 $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 +040013929 $IL_Link = "n/a" if($CheckObjectsOnly);
13930 $META_DATA .= "interface_problems_low:$I_Problems_Low;";
Andrey Ponomarenko16934472012-03-29 15:37:04 +040013931 $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 +040013932
13933 my $ChangedConstants_Link = "0";
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040013934 if(keys(%{$CheckedSymbols{$Level}}) and $C_Problems_Low)
13935 {
13936 if($JoinReport) {
13937 $ChangedConstants_Link = "<a href='#".$Level."_Changed_Constants' style='color:Blue;'>$C_Problems_Low</a>";
13938 }
13939 else {
13940 $ChangedConstants_Link = "<a href='#Changed_Constants' style='color:Blue;'>$C_Problems_Low</a>";
13941 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013942 }
13943 $ChangedConstants_Link = "n/a" if($CheckObjectsOnly);
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040013944 $META_DATA .= "changed_constants:$C_Problems_Low;";
Andrey Ponomarenko16934472012-03-29 15:37:04 +040013945 $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 +040013946
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040013947 if($CheckImpl and $Level eq "Binary")
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013948 {
13949 my $ChangedImpl_Link = "0";
13950 $ChangedImpl_Link = "<a href='#Changed_Implementation' style='color:Blue;'>".keys(%ImplProblems)."</a>" if(keys(%ImplProblems)>0);
13951 $ChangedImpl_Link = "n/a" if($CheckHeadersOnly);
13952 $META_DATA .= "changed_implementation:".keys(%ImplProblems).";";
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040013953 $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 +040013954 }
13955 # Safe Changes
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040013956 if($T_Other and not $CheckObjectsOnly)
13957 {
13958 my $TS_Link = "<a href='#".get_Anchor("Type", $Level, "Safe")."' style='color:Blue;'>$T_Other</a>";
Andrey Ponomarenko16934472012-03-29 15:37:04 +040013959 $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 +040013960 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040013961
13962 if($I_Other and not $CheckObjectsOnly)
13963 {
13964 my $IS_Link = "<a href='#".get_Anchor("Symbol", $Level, "Safe")."' style='color:Blue;'>$I_Other</a>";
Andrey Ponomarenko16934472012-03-29 15:37:04 +040013965 $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 +040013966 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013967
13968 $META_DATA .= "tool_version:$TOOL_VERSION";
13969 $Problem_Summary .= "</table>\n";
Andrey Ponomarenko16934472012-03-29 15:37:04 +040013970 # $TestInfo = getLegend().$TestInfo;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013971 return ($TestInfo.$TestResults.$Problem_Summary, $META_DATA);
13972 }
13973}
13974
Andrey Ponomarenko16934472012-03-29 15:37:04 +040013975sub getStyle($$$)
13976{
13977 my ($Subj, $Act, $Num) = @_;
13978 my %Style = (
13979 "A"=>"new",
13980 "R"=>"failed",
13981 "S"=>"passed",
13982 "L"=>"warning",
13983 "M"=>"failed",
13984 "H"=>"failed"
13985 );
13986 if($Num>0) {
13987 return " class='".$Style{$Act}."'";
13988 }
13989 return "";
13990}
13991
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013992sub show_number($)
13993{
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040013994 if($_[0])
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013995 {
Andrey Ponomarenko16934472012-03-29 15:37:04 +040013996 my $Num = cut_off_number($_[0], 2, 0);
13997 if($Num eq "0")
13998 {
13999 foreach my $P (3 .. 7)
14000 {
14001 $Num = cut_off_number($_[0], $P, 1);
14002 if($Num ne "0") {
14003 last;
14004 }
14005 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014006 }
14007 if($Num eq "0") {
14008 $Num = $_[0];
14009 }
14010 return $Num;
14011 }
14012 return $_[0];
14013}
14014
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014015sub cut_off_number($$$)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014016{
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014017 my ($num, $digs_to_cut, $z) = @_;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014018 if($num!~/\./)
14019 {
14020 $num .= ".";
14021 foreach (1 .. $digs_to_cut-1) {
14022 $num .= "0";
14023 }
14024 }
14025 elsif($num=~/\.(.+)\Z/ and length($1)<$digs_to_cut-1)
14026 {
14027 foreach (1 .. $digs_to_cut - 1 - length($1)) {
14028 $num .= "0";
14029 }
14030 }
14031 elsif($num=~/\d+\.(\d){$digs_to_cut,}/) {
14032 $num=sprintf("%.".($digs_to_cut-1)."f", $num);
14033 }
14034 $num=~s/\.[0]+\Z//g;
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014035 if($z) {
14036 $num=~s/(\.[1-9]+)[0]+\Z/$1/g;
14037 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014038 return $num;
14039}
14040
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014041sub get_Report_ChangedConstants($)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014042{
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014043 my $Level = $_[0];
Andrey Ponomarenko16934472012-03-29 15:37:04 +040014044 my $CHANGED_CONSTANTS = "";
14045 my %ReportMap = ();
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014046 foreach my $Constant (keys(%{$ProblemsWithConstants{$Level}})) {
Andrey Ponomarenko16934472012-03-29 15:37:04 +040014047 $ReportMap{$Constants{1}{$Constant}{"Header"}}{$Constant} = 1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014048 }
14049 my $Kind = "Changed_Constant";
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014050 if(not defined $CompatRules{$Level}{$Kind}) {
14051 return "";
14052 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014053 if($ReportFormat eq "xml")
14054 { # XML
Andrey Ponomarenko16934472012-03-29 15:37:04 +040014055 foreach my $HeaderName (sort {lc($a) cmp lc($b)} keys(%ReportMap))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014056 {
14057 $CHANGED_CONSTANTS .= " <header name=\"$HeaderName\">\n";
Andrey Ponomarenko16934472012-03-29 15:37:04 +040014058 foreach my $Constant (sort {lc($a) cmp lc($b)} keys(%{$ReportMap{$HeaderName}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014059 {
14060 $CHANGED_CONSTANTS .= " <constant name=\"$Constant\">\n";
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014061 my $Change = $CompatRules{$Level}{$Kind}{"Change"};
14062 my $Effect = $CompatRules{$Level}{$Kind}{"Effect"};
14063 my $Overcome = $CompatRules{$Level}{$Kind}{"Overcome"};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014064 $CHANGED_CONSTANTS .= " <problem id=\"$Kind\">\n";
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014065 $CHANGED_CONSTANTS .= " <change".getXmlParams($Change, $ProblemsWithConstants{$Level}{$Constant}).">$Change</change>\n";
14066 $CHANGED_CONSTANTS .= " <effect".getXmlParams($Effect, $ProblemsWithConstants{$Level}{$Constant}).">$Effect</effect>\n";
14067 $CHANGED_CONSTANTS .= " <overcome".getXmlParams($Overcome, $ProblemsWithConstants{$Level}{$Constant}).">$Overcome</overcome>\n";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014068 $CHANGED_CONSTANTS .= " </problem>\n";
14069 $CHANGED_CONSTANTS .= " </constant>\n";
14070 }
14071 $CHANGED_CONSTANTS .= " </header>\n";
14072 }
14073 $CHANGED_CONSTANTS = "<problems_with_constants severity=\"Low\">\n".$CHANGED_CONSTANTS."</problems_with_constants>\n\n";
14074 }
14075 else
14076 { # HTML
14077 my $Number = 0;
Andrey Ponomarenko16934472012-03-29 15:37:04 +040014078 foreach my $HeaderName (sort {lc($a) cmp lc($b)} keys(%ReportMap))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014079 {
14080 $CHANGED_CONSTANTS .= "<span class='h_name'>$HeaderName</span><br/>\n";
Andrey Ponomarenko16934472012-03-29 15:37:04 +040014081 foreach my $Name (sort {lc($a) cmp lc($b)} keys(%{$ReportMap{$HeaderName}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014082 {
14083 $Number += 1;
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014084 my $Change = applyMacroses($Level, $Kind, $CompatRules{$Level}{$Kind}{"Change"}, $ProblemsWithConstants{$Level}{$Name});
14085 my $Effect = $CompatRules{$Level}{$Kind}{"Effect"};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014086 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 +040014087 $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 +040014088 $Report = $ContentSpanStart."<span class='extendable'>[+]</span> ".$Name.$ContentSpanEnd."<br/>\n".$Report;
14089 $CHANGED_CONSTANTS .= insertIDs($Report);
14090 }
14091 $CHANGED_CONSTANTS .= "<br/>\n";
14092 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014093 if($CHANGED_CONSTANTS)
14094 {
14095 my $Anchor = "<a name='Changed_Constants'></a>";
14096 if($JoinReport) {
14097 $Anchor = "<a name='".$Level."_Changed_Constants'></a>";
14098 }
14099 $CHANGED_CONSTANTS = $Anchor."<h2>Problems with Constants ($Number)</h2><hr/>\n".$CHANGED_CONSTANTS.$TOP_REF."<br/>\n";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014100 }
14101 }
14102 return $CHANGED_CONSTANTS;
14103}
14104
14105sub get_Report_Impl()
14106{
Andrey Ponomarenko16934472012-03-29 15:37:04 +040014107 my $CHANGED_IMPLEMENTATION = "";
14108 my %ReportMap = ();
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014109 foreach my $Interface (sort keys(%ImplProblems))
14110 {
14111 my $HeaderName = $CompleteSignature{1}{$Interface}{"Header"};
14112 my $DyLib = $Symbol_Library{1}{$Interface};
Andrey Ponomarenko16934472012-03-29 15:37:04 +040014113 $ReportMap{$HeaderName}{$DyLib}{$Interface} = 1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014114 }
14115 my $Changed_Number = 0;
Andrey Ponomarenko16934472012-03-29 15:37:04 +040014116 foreach my $HeaderName (sort {lc($a) cmp lc($b)} keys(%ReportMap))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014117 {
Andrey Ponomarenko16934472012-03-29 15:37:04 +040014118 foreach my $DyLib (sort {lc($a) cmp lc($b)} keys(%{$ReportMap{$HeaderName}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014119 {
14120 my $FDyLib=$DyLib.($DyLib!~/\.\w+\Z/?" (.$LIB_EXT)":"");
14121 if($HeaderName) {
14122 $CHANGED_IMPLEMENTATION .= "<span class='h_name'>$HeaderName</span>, <span class='lib_name'>$FDyLib</span><br/>\n";
14123 }
14124 else {
14125 $CHANGED_IMPLEMENTATION .= "<span class='lib_name'>$DyLib</span><br/>\n";
14126 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014127 my %NameSpaceSymbols = ();
Andrey Ponomarenko16934472012-03-29 15:37:04 +040014128 foreach my $Interface (keys(%{$ReportMap{$HeaderName}{$DyLib}})) {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014129 $NameSpaceSymbols{get_IntNameSpace($Interface, 2)}{$Interface} = 1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014130 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014131 foreach my $NameSpace (sort keys(%NameSpaceSymbols))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014132 {
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040014133 $CHANGED_IMPLEMENTATION .= ($NameSpace)?"<span class='ns_title'>namespace</span> <span class='ns'>$NameSpace</span><br/>\n":"";
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014134 my @SortedInterfaces = sort {lc(get_Signature($a, 1)) cmp lc(get_Signature($b, 1))} keys(%{$NameSpaceSymbols{$NameSpace}});
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014135 foreach my $Interface (@SortedInterfaces)
14136 {
14137 $Changed_Number += 1;
14138 my $Signature = get_Signature($Interface, 1);
14139 if($NameSpace) {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040014140 $Signature=~s/\b\Q$NameSpace\E::\b//g;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014141 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014142 $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 +040014143 }
14144 }
14145 $CHANGED_IMPLEMENTATION .= "<br/>\n";
14146 }
14147 }
14148 if($CHANGED_IMPLEMENTATION) {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014149 $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 +040014150 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +040014151
14152 # clean memory
14153 %ImplProblems = ();
14154
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014155 return $CHANGED_IMPLEMENTATION;
14156}
14157
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014158sub getTitle($$$)
14159{
14160 my ($Header, $Library, $NameSpace) = @_;
14161 my $Title = "";
14162 if($Library and $Library!~/\.\w+\Z/) {
14163 $Library .= " (.$LIB_EXT)";
14164 }
14165 if($Header and $Library)
14166 {
14167 $Title .= "<span class='h_name'>$Header</span>";
14168 $Title .= ", <span class='lib_name'>$Library</span><br/>\n";
14169 }
14170 elsif($Library) {
14171 $Title .= "<span class='lib_name'>$Library</span><br/>\n";
14172 }
14173 elsif($Header) {
14174 $Title .= "<span class='h_name'>$Header</span><br/>\n";
14175 }
14176 if($NameSpace) {
14177 $Title .= "<span class='ns_title'>namespace</span> <span class='ns'>$NameSpace</span><br/>\n";
14178 }
14179 return $Title;
14180}
14181
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014182sub get_Report_Added($)
14183{
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014184 my $Level = $_[0];
Andrey Ponomarenko16934472012-03-29 15:37:04 +040014185 my $ADDED_INTERFACES = "";
14186 my %ReportMap = ();
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014187 foreach my $Interface (sort keys(%{$CompatProblems{$Level}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014188 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014189 foreach my $Kind (sort keys(%{$CompatProblems{$Level}{$Interface}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014190 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014191 if($Kind eq "Added_Symbol")
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014192 {
14193 my $HeaderName = $CompleteSignature{2}{$Interface}{"Header"};
14194 my $DyLib = $Symbol_Library{2}{$Interface};
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014195 if($Level eq "Source" and $ReportFormat eq "html")
14196 { # do not show library name in HTML report
14197 $DyLib = "";
14198 }
14199 $ReportMap{$HeaderName}{$DyLib}{$Interface} = 1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014200 }
14201 }
14202 }
14203 if($ReportFormat eq "xml")
14204 { # XML
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014205 foreach my $HeaderName (sort {lc($a) cmp lc($b)} keys(%ReportMap))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014206 {
14207 $ADDED_INTERFACES .= " <header name=\"$HeaderName\">\n";
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014208 foreach my $DyLib (sort {lc($a) cmp lc($b)} keys(%{$ReportMap{$HeaderName}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014209 {
14210 $ADDED_INTERFACES .= " <library name=\"$DyLib\">\n";
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014211 foreach my $Interface (keys(%{$ReportMap{$HeaderName}{$DyLib}})) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014212 $ADDED_INTERFACES .= " <name>$Interface</name>\n";
14213 }
14214 $ADDED_INTERFACES .= " </library>\n";
14215 }
14216 $ADDED_INTERFACES .= " </header>\n";
14217 }
14218 $ADDED_INTERFACES = "<added_symbols>\n".$ADDED_INTERFACES."</added_symbols>\n\n";
14219 }
14220 else
14221 { # HTML
14222 my $Added_Number = 0;
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014223 foreach my $HeaderName (sort {lc($a) cmp lc($b)} keys(%ReportMap))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014224 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014225 foreach my $DyLib (sort {lc($a) cmp lc($b)} keys(%{$ReportMap{$HeaderName}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014226 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014227 my %NameSpaceSymbols = ();
14228 foreach my $Interface (keys(%{$ReportMap{$HeaderName}{$DyLib}})) {
14229 $NameSpaceSymbols{get_IntNameSpace($Interface, 2)}{$Interface} = 1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014230 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014231 foreach my $NameSpace (sort keys(%NameSpaceSymbols))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014232 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014233 $ADDED_INTERFACES .= getTitle($HeaderName, $DyLib, $NameSpace);
14234 my @SortedInterfaces = sort {lc(get_Signature($a, 2)) cmp lc(get_Signature($b, 2))} keys(%{$NameSpaceSymbols{$NameSpace}});
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014235 foreach my $Interface (@SortedInterfaces)
14236 {
14237 $Added_Number += 1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014238 my $Signature = get_Signature($Interface, 2);
14239 if($NameSpace) {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040014240 $Signature=~s/\b\Q$NameSpace\E::\b//g;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014241 }
14242 if($Interface=~/\A(_Z|\?)/) {
14243 if($Signature) {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014244 $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 +040014245 }
14246 else {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014247 $ADDED_INTERFACES .= "<span class=\"iname\">".$Interface."</span><br/>\n";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014248 }
14249 }
14250 else {
14251 if($Signature) {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014252 $ADDED_INTERFACES .= "<span class=\"iname\">".highLight_Signature_Italic_Color($Signature)."</span><br/>\n";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014253 }
14254 else {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014255 $ADDED_INTERFACES .= "<span class=\"iname\">".$Interface."</span><br/>\n";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014256 }
14257 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014258 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014259 $ADDED_INTERFACES .= "<br/>\n";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014260 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014261 }
14262 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014263 if($ADDED_INTERFACES)
14264 {
14265 my $Anchor = "<a name='Added'></a>";
14266 if($JoinReport) {
14267 $Anchor = "<a name='".$Level."_Added'></a>";
14268 }
14269 $ADDED_INTERFACES = $Anchor."<h2>Added Symbols ($Added_Number)</h2><hr/>\n".$ADDED_INTERFACES.$TOP_REF."<br/>\n";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014270 }
14271 }
14272 return $ADDED_INTERFACES;
14273}
14274
14275sub get_Report_Removed($)
14276{
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014277 my $Level = $_[0];
Andrey Ponomarenko16934472012-03-29 15:37:04 +040014278 my $REMOVED_INTERFACES = "";
14279 my %ReportMap = ();
Andrey Ponomarenko85043792012-05-14 16:48:07 +040014280 foreach my $Symbol (sort keys(%{$CompatProblems{$Level}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014281 {
Andrey Ponomarenko85043792012-05-14 16:48:07 +040014282 foreach my $Kind (sort keys(%{$CompatProblems{$Level}{$Symbol}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014283 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014284 if($Kind eq "Removed_Symbol")
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014285 {
Andrey Ponomarenko85043792012-05-14 16:48:07 +040014286 my $HeaderName = $CompleteSignature{1}{$Symbol}{"Header"};
14287 my $DyLib = $Symbol_Library{1}{$Symbol};
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014288 if($Level eq "Source" and $ReportFormat eq "html")
14289 { # do not show library name in HTML report
14290 $DyLib = "";
14291 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +040014292 $ReportMap{$HeaderName}{$DyLib}{$Symbol} = 1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014293 }
14294 }
14295 }
14296 if($ReportFormat eq "xml")
14297 { # XML
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014298 foreach my $HeaderName (sort {lc($a) cmp lc($b)} keys(%ReportMap))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014299 {
14300 $REMOVED_INTERFACES .= " <header name=\"$HeaderName\">\n";
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014301 foreach my $DyLib (sort {lc($a) cmp lc($b)} keys(%{$ReportMap{$HeaderName}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014302 {
14303 $REMOVED_INTERFACES .= " <library name=\"$DyLib\">\n";
Andrey Ponomarenko85043792012-05-14 16:48:07 +040014304 foreach my $Symbol (keys(%{$ReportMap{$HeaderName}{$DyLib}})) {
14305 $REMOVED_INTERFACES .= " <name>$Symbol</name>\n";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014306 }
14307 $REMOVED_INTERFACES .= " </library>\n";
14308 }
14309 $REMOVED_INTERFACES .= " </header>\n";
14310 }
14311 $REMOVED_INTERFACES = "<removed_symbols>\n".$REMOVED_INTERFACES."</removed_symbols>\n\n";
14312 }
14313 else
14314 { # HTML
14315 my $Removed_Number = 0;
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014316 foreach my $HeaderName (sort {lc($a) cmp lc($b)} keys(%ReportMap))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014317 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014318 foreach my $DyLib (sort {lc($a) cmp lc($b)} keys(%{$ReportMap{$HeaderName}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014319 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014320 my %NameSpaceSymbols = ();
14321 foreach my $Interface (keys(%{$ReportMap{$HeaderName}{$DyLib}})) {
14322 $NameSpaceSymbols{get_IntNameSpace($Interface, 1)}{$Interface} = 1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014323 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014324 foreach my $NameSpace (sort keys(%NameSpaceSymbols))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014325 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014326 $REMOVED_INTERFACES .= getTitle($HeaderName, $DyLib, $NameSpace);
14327 my @SortedInterfaces = sort {lc(get_Signature($a, 1)) cmp lc(get_Signature($b, 1))} keys(%{$NameSpaceSymbols{$NameSpace}});
Andrey Ponomarenko85043792012-05-14 16:48:07 +040014328 foreach my $Symbol (@SortedInterfaces)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014329 {
14330 $Removed_Number += 1;
14331 my $SubReport = "";
Andrey Ponomarenko85043792012-05-14 16:48:07 +040014332 my $Signature = get_Signature($Symbol, 1);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014333 if($NameSpace) {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040014334 $Signature=~s/\b\Q$NameSpace\E::\b//g;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014335 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +040014336 if($Symbol=~/\A(_Z|\?)/)
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014337 {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014338 if($Signature) {
Andrey Ponomarenko85043792012-05-14 16:48:07 +040014339 $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 +040014340 }
14341 else {
Andrey Ponomarenko85043792012-05-14 16:48:07 +040014342 $REMOVED_INTERFACES .= "<span class=\"iname\">".$Symbol."</span><br/>\n";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014343 }
14344 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014345 else
14346 {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014347 if($Signature) {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014348 $REMOVED_INTERFACES .= "<span class=\"iname\">".highLight_Signature_Italic_Color($Signature)."</span><br/>\n";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014349 }
14350 else {
Andrey Ponomarenko85043792012-05-14 16:48:07 +040014351 $REMOVED_INTERFACES .= "<span class=\"iname\">".$Symbol."</span><br/>\n";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014352 }
14353 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014354 }
14355 }
14356 $REMOVED_INTERFACES .= "<br/>\n";
14357 }
14358 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014359 if($REMOVED_INTERFACES)
14360 {
14361 my $Anchor = "<a name='Removed'></a><a name='Withdrawn'></a>";
14362 if($JoinReport) {
14363 $Anchor = "<a name='".$Level."_Removed'></a><a name='".$Level."_Withdrawn'></a>";
14364 }
14365 $REMOVED_INTERFACES = $Anchor."<h2>Removed Symbols ($Removed_Number)</h2><hr/>\n".$REMOVED_INTERFACES.$TOP_REF."<br/>\n";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014366 }
14367 }
14368 return $REMOVED_INTERFACES;
14369}
14370
14371sub getXmlParams($$)
14372{
14373 my ($Content, $Problem) = @_;
14374 return "" if(not $Content or not $Problem);
14375 my %XMLparams = ();
14376 foreach my $Attr (sort {$b cmp $a} keys(%{$Problem}))
14377 {
14378 my $Macro = "\@".lc($Attr);
14379 if($Content=~/\Q$Macro\E/) {
14380 $XMLparams{lc($Attr)} = $Problem->{$Attr};
14381 }
14382 }
14383 my @PString = ();
14384 foreach my $P (sort {$b cmp $a} keys(%XMLparams)) {
14385 push(@PString, $P."=\"".htmlSpecChars($XMLparams{$P})."\"");
14386 }
14387 if(@PString) {
14388 return " ".join(" ", @PString);
14389 }
14390 else {
14391 return "";
14392 }
14393}
14394
14395sub addMarkup($)
14396{
14397 my $Content = $_[0];
14398 # auto-markup
14399 $Content=~s/\n[ ]*//; # spaces
14400 $Content=~s!(\@\w+\s*\(\@\w+\))!<nowrap>$1</nowrap>!g; # @old_type (@old_size)
14401 $Content=~s!(... \(\w+\))!<nowrap><b>$1</b></nowrap>!g; # ... (va_list)
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040014402 $Content=~s!<nowrap>(.+?)</nowrap>!<span class='nowrap'>$1</span>!g;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014403 $Content=~s!([2-9]\))!<br/>$1!g; # 1), 2), ...
14404 if($Content=~/\ANOTE:/)
14405 { # notes
14406 $Content=~s!(NOTE):!<b>$1</b>:!g;
14407 }
14408 else {
14409 $Content=~s!(NOTE):!<br/><b>$1</b>:!g;
14410 }
14411 $Content=~s! (out)-! <b>$1</b>-!g; # out-parameters
14412 my @Keywords = (
14413 "void",
14414 "const",
14415 "static",
14416 "restrict",
14417 "volatile",
14418 "register",
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040014419 "virtual"
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014420 );
14421 my $MKeys = join("|", @Keywords);
14422 foreach (@Keywords) {
14423 $MKeys .= "|non-".$_;
14424 }
14425 $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 +040014426
14427 # Markdown
14428 $Content=~s!\*\*([\w\-]+)\*\*!<b>$1</b>!ig;
14429 $Content=~s!\*([\w\-]+)\*!<i>$1</i>!ig;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014430 return $Content;
14431}
14432
14433sub applyMacroses($$$$)
14434{
14435 my ($Level, $Kind, $Content, $Problem) = @_;
14436 return "" if(not $Content or not $Problem);
14437 $Problem->{"Word_Size"} = $WORD_SIZE{2};
14438 $Content = addMarkup($Content);
14439 # macros
14440 foreach my $Attr (sort {$b cmp $a} keys(%{$Problem}))
14441 {
14442 my $Macro = "\@".lc($Attr);
14443 my $Value = $Problem->{$Attr};
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040014444 if(not defined $Value
14445 or $Value eq "") {
14446 next;
14447 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014448 if($Value=~/\s\(/)
14449 { # functions
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014450 $Value=~s/\s*\[[\w\-]+\]//g; # remove quals
14451 $Value=~s/\s\w+(\)|,)/$1/g; # remove parameter names
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014452 $Value = black_name($Value);
14453 }
14454 elsif($Value=~/\s/) {
14455 $Value = "<span class='value'>".htmlSpecChars($Value)."</span>";
14456 }
14457 elsif($Value=~/\A\d+\Z/
14458 and ($Attr eq "Old_Size" or $Attr eq "New_Size"))
14459 { # bits to bytes
14460 if($Value % $BYTE_SIZE)
14461 { # bits
14462 if($Value==1) {
14463 $Value = "<b>".$Value."</b> bit";
14464 }
14465 else {
14466 $Value = "<b>".$Value."</b> bits";
14467 }
14468 }
14469 else
14470 { # bytes
14471 $Value /= $BYTE_SIZE;
14472 if($Value==1) {
14473 $Value = "<b>".$Value."</b> byte";
14474 }
14475 else {
14476 $Value = "<b>".$Value."</b> bytes";
14477 }
14478 }
14479 }
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040014480 else
14481 {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014482 $Value = "<b>".htmlSpecChars($Value)."</b>";
14483 }
14484 $Content=~s/\Q$Macro\E/$Value/g;
14485 }
14486
14487 if($Content=~/(\A|[^\@\w])\@\w/)
14488 {
14489 if(not $IncompleteRules{$Level}{$Kind})
14490 { # only one warning
14491 printMsg("WARNING", "incomplete rule \"$Kind\" (\"$Level\")");
14492 $IncompleteRules{$Level}{$Kind} = 1;
14493 }
14494 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014495 return $Content;
14496}
14497
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040014498sub get_Report_SymbolProblems($$)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014499{
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014500 my ($TargetSeverity, $Level) = @_;
Andrey Ponomarenko16934472012-03-29 15:37:04 +040014501 my $INTERFACE_PROBLEMS = "";
14502 my (%ReportMap, %SymbolChanges) = ();
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014503 foreach my $Symbol (sort keys(%{$CompatProblems{$Level}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014504 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014505 my ($SN, $SS, $SV) = separate_symbol($Symbol);
14506 if($SV and defined $CompatProblems{$Level}{$SN}) {
14507 next;
14508 }
14509 foreach my $Kind (sort keys(%{$CompatProblems{$Level}{$Symbol}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014510 {
14511 if($CompatRules{$Level}{$Kind}{"Kind"} eq "Symbols"
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014512 and $Kind ne "Added_Symbol" and $Kind ne "Removed_Symbol")
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014513 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014514 my $HeaderName = $CompleteSignature{1}{$Symbol}{"Header"};
14515 my $DyLib = $Symbol_Library{1}{$Symbol};
14516 if(not $DyLib and my $VSym = $SymVer{1}{$Symbol})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014517 { # Symbol with Version
14518 $DyLib = $Symbol_Library{1}{$VSym};
14519 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040014520 if(not $DyLib)
14521 { # const global data
14522 $DyLib = "";
14523 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014524 if($Level eq "Source" and $ReportFormat eq "html")
14525 { # do not show library name in HTML report
14526 $DyLib = "";
14527 }
14528 %{$SymbolChanges{$Symbol}{$Kind}} = %{$CompatProblems{$Level}{$Symbol}{$Kind}};
14529 foreach my $Location (sort keys(%{$SymbolChanges{$Symbol}{$Kind}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014530 {
14531 my $Priority = getProblemSeverity($Level, $Kind);
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014532 if($Priority ne $TargetSeverity) {
14533 delete($SymbolChanges{$Symbol}{$Kind}{$Location});
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014534 }
14535 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014536 if(not keys(%{$SymbolChanges{$Symbol}{$Kind}}))
14537 {
14538 delete($SymbolChanges{$Symbol}{$Kind});
14539 next;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014540 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014541 $ReportMap{$HeaderName}{$DyLib}{$Symbol} = 1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014542 }
14543 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014544 if(not keys(%{$SymbolChanges{$Symbol}})) {
14545 delete($SymbolChanges{$Symbol});
14546 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014547 }
14548 if($ReportFormat eq "xml")
14549 { # XML
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014550 foreach my $HeaderName (sort {lc($a) cmp lc($b)} keys(%ReportMap))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014551 {
14552 $INTERFACE_PROBLEMS .= " <header name=\"$HeaderName\">\n";
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014553 foreach my $DyLib (sort {lc($a) cmp lc($b)} keys(%{$ReportMap{$HeaderName}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014554 {
14555 $INTERFACE_PROBLEMS .= " <library name=\"$DyLib\">\n";
14556 foreach my $Symbol (sort {lc($tr_name{$a}) cmp lc($tr_name{$b})} keys(%SymbolChanges))
14557 {
14558 $INTERFACE_PROBLEMS .= " <symbol name=\"$Symbol\">\n";
14559 foreach my $Kind (keys(%{$SymbolChanges{$Symbol}}))
14560 {
14561 foreach my $Location (sort keys(%{$SymbolChanges{$Symbol}{$Kind}}))
14562 {
14563 my %Problem = %{$SymbolChanges{$Symbol}{$Kind}{$Location}};
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040014564 $Problem{"Param_Pos"} = showPos($Problem{"Param_Pos"});
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014565 $INTERFACE_PROBLEMS .= " <problem id=\"$Kind\">\n";
14566 my $Change = $CompatRules{$Level}{$Kind}{"Change"};
14567 $INTERFACE_PROBLEMS .= " <change".getXmlParams($Change, \%Problem).">$Change</change>\n";
14568 my $Effect = $CompatRules{$Level}{$Kind}{"Effect"};
14569 $INTERFACE_PROBLEMS .= " <effect".getXmlParams($Effect, \%Problem).">$Effect</effect>\n";
14570 my $Overcome = $CompatRules{$Level}{$Kind}{"Overcome"};
14571 $INTERFACE_PROBLEMS .= " <overcome".getXmlParams($Overcome, \%Problem).">$Overcome</overcome>\n";
14572 $INTERFACE_PROBLEMS .= " </problem>\n";
14573 }
14574 }
14575 $INTERFACE_PROBLEMS .= " </symbol>\n";
14576 }
14577 $INTERFACE_PROBLEMS .= " </library>\n";
14578 }
14579 $INTERFACE_PROBLEMS .= " </header>\n";
14580 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014581 $INTERFACE_PROBLEMS = "<problems_with_symbols severity=\"$TargetSeverity\">\n".$INTERFACE_PROBLEMS."</problems_with_symbols>\n\n";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014582 }
14583 else
14584 { # HTML
14585 my $ProblemsNum = 0;
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014586 foreach my $HeaderName (sort {lc($a) cmp lc($b)} keys(%ReportMap))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014587 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014588 foreach my $DyLib (sort {lc($a) cmp lc($b)} keys(%{$ReportMap{$HeaderName}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014589 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014590 my (%NameSpaceSymbols, %NewSignature) = ();
14591 foreach my $Symbol (keys(%{$ReportMap{$HeaderName}{$DyLib}})) {
14592 $NameSpaceSymbols{get_IntNameSpace($Symbol, 1)}{$Symbol} = 1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014593 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014594 foreach my $NameSpace (sort keys(%NameSpaceSymbols))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014595 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014596 $INTERFACE_PROBLEMS .= getTitle($HeaderName, $DyLib, $NameSpace);
14597 my @SortedInterfaces = sort {lc($tr_name{$a}) cmp lc($tr_name{$b})} keys(%{$NameSpaceSymbols{$NameSpace}});
14598 foreach my $Symbol (@SortedInterfaces)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014599 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014600 my $Signature = get_Signature($Symbol, 1);
14601 my $SYMBOL_REPORT = "";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014602 my $ProblemNum = 1;
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014603 foreach my $Kind (keys(%{$SymbolChanges{$Symbol}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014604 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014605 foreach my $Location (sort keys(%{$SymbolChanges{$Symbol}{$Kind}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014606 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014607 my %Problem = %{$SymbolChanges{$Symbol}{$Kind}{$Location}};
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040014608 $Problem{"Param_Pos"} = showPos($Problem{"Param_Pos"});
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014609 if($Problem{"New_Signature"}) {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014610 $NewSignature{$Symbol} = $Problem{"New_Signature"};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014611 }
14612 if(my $Change = applyMacroses($Level, $Kind, $CompatRules{$Level}{$Kind}{"Change"}, \%Problem))
14613 {
14614 my $Effect = applyMacroses($Level, $Kind, $CompatRules{$Level}{$Kind}{"Effect"}, \%Problem);
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014615 $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 +040014616 $ProblemNum += 1;
14617 $ProblemsNum += 1;
14618 }
14619 }
14620 }
14621 $ProblemNum -= 1;
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014622 if($SYMBOL_REPORT)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014623 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014624 $INTERFACE_PROBLEMS .= $ContentSpanStart."<span class='extendable'>[+]</span> ";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014625 if($Signature) {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014626 $INTERFACE_PROBLEMS .= highLight_Signature_Italic_Color($Signature);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014627 }
14628 else {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014629 $INTERFACE_PROBLEMS .= $Symbol;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014630 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014631 $INTERFACE_PROBLEMS .= " ($ProblemNum)".$ContentSpanEnd."<br/>\n";
14632 $INTERFACE_PROBLEMS .= $ContentDivStart."\n";
14633 if($NewSignature{$Symbol})
14634 { # argument list changed to
14635 $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 +040014636 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014637 if($Symbol=~/\A(_Z|\?)/) {
14638 $INTERFACE_PROBLEMS .= "<span class='mangled'>&#160;&#160;&#160;&#160;[symbol: <b>$Symbol</b>]</span><br/>\n";
14639 }
14640 $INTERFACE_PROBLEMS .= "<table class='ptable'><tr><th width='2%'></th><th width='47%'>Change</th><th>Effect</th></tr>$SYMBOL_REPORT</table><br/>\n";
14641 $INTERFACE_PROBLEMS .= $ContentDivEnd;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014642 if($NameSpace) {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040014643 $INTERFACE_PROBLEMS=~s/\b\Q$NameSpace\E::\b//g;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014644 }
14645 }
14646 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014647 $INTERFACE_PROBLEMS .= "<br/>";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014648 }
14649 }
14650 }
14651 if($INTERFACE_PROBLEMS)
14652 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014653 $INTERFACE_PROBLEMS = insertIDs($INTERFACE_PROBLEMS);
14654 my $Title = "Problems with Symbols, $TargetSeverity Severity";
14655 if($TargetSeverity eq "Safe")
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014656 { # Safe Changes
14657 $Title = "Other Changes in Symbols";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014658 }
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040014659 $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 +040014660 }
14661 }
14662 return $INTERFACE_PROBLEMS;
14663}
14664
14665sub get_Report_TypeProblems($$)
14666{
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014667 my ($TargetSeverity, $Level) = @_;
Andrey Ponomarenko16934472012-03-29 15:37:04 +040014668 my $TYPE_PROBLEMS = "";
14669 my (%ReportMap, %TypeChanges, %TypeType) = ();
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014670 foreach my $Interface (sort keys(%{$CompatProblems{$Level}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014671 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014672 foreach my $Kind (keys(%{$CompatProblems{$Level}{$Interface}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014673 {
14674 if($CompatRules{$Level}{$Kind}{"Kind"} eq "Types")
14675 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014676 foreach my $Location (sort {cmp_locations($b, $a)} sort keys(%{$CompatProblems{$Level}{$Interface}{$Kind}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014677 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014678 my $TypeName = $CompatProblems{$Level}{$Interface}{$Kind}{$Location}{"Type_Name"};
14679 my $TypeType = $CompatProblems{$Level}{$Interface}{$Kind}{$Location}{"Type_Type"};
14680 my $Target = $CompatProblems{$Level}{$Interface}{$Kind}{$Location}{"Target"};
14681 $CompatProblems{$Level}{$Interface}{$Kind}{$Location}{"Type_Type"} = lc($TypeType);
14682 my $Severity = getProblemSeverity($Level, $Kind);
14683 if($Severity eq "Safe"
14684 and $TargetSeverity ne "Safe") {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014685 next;
14686 }
14687 if(not $TypeType{$TypeName}
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014688 or $TypeType{$TypeName} eq "struct")
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014689 { # register type of the type, select "class" if type has "class"- and "struct"-type changes
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014690 $TypeType{$TypeName} = $CompatProblems{$Level}{$Interface}{$Kind}{$Location}{"Type_Type"};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014691 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014692
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040014693 if(cmpSeverities($Type_MaxSeverity{$Level}{$TypeName}{$Kind}{$Target}, $Severity))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014694 { # select a problem with the highest priority
14695 next;
14696 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014697 %{$TypeChanges{$TypeName}{$Kind}{$Location}} = %{$CompatProblems{$Level}{$Interface}{$Kind}{$Location}};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014698 }
14699 }
14700 }
14701 }
14702 my %Kinds_Locations = ();
14703 foreach my $TypeName (keys(%TypeChanges))
14704 {
14705 my %Kinds_Target = ();
14706 foreach my $Kind (sort keys(%{$TypeChanges{$TypeName}}))
14707 {
14708 foreach my $Location (sort {cmp_locations($b, $a)} sort keys(%{$TypeChanges{$TypeName}{$Kind}}))
14709 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014710 my $Severity = getProblemSeverity($Level, $Kind);
14711 if($Severity ne $TargetSeverity)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014712 { # other priority
14713 delete($TypeChanges{$TypeName}{$Kind}{$Location});
14714 next;
14715 }
14716 $Kinds_Locations{$TypeName}{$Kind}{$Location} = 1;
14717 my $Target = $TypeChanges{$TypeName}{$Kind}{$Location}{"Target"};
14718 if($Kinds_Target{$Kind}{$Target})
14719 { # duplicate target
14720 delete($TypeChanges{$TypeName}{$Kind}{$Location});
14721 next;
14722 }
14723 $Kinds_Target{$Kind}{$Target} = 1;
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040014724 my $HeaderName = $TypeInfo{1}{$TName_Tid{1}{$TypeName}}{"Header"};
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014725 $ReportMap{$HeaderName}{$TypeName} = 1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014726 }
14727 if(not keys(%{$TypeChanges{$TypeName}{$Kind}})) {
14728 delete($TypeChanges{$TypeName}{$Kind});
14729 }
14730 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014731 if(not keys(%{$TypeChanges{$TypeName}})) {
14732 delete($TypeChanges{$TypeName});
14733 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014734 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +040014735 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 +040014736 if($ReportFormat eq "xml")
14737 { # XML
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014738 foreach my $HeaderName (sort {lc($a) cmp lc($b)} keys(%ReportMap))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014739 {
14740 $TYPE_PROBLEMS .= " <header name=\"$HeaderName\">\n";
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014741 foreach my $TypeName (keys(%{$ReportMap{$HeaderName}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014742 {
14743 $TYPE_PROBLEMS .= " <type name=\"".htmlSpecChars($TypeName)."\">\n";
14744 foreach my $Kind (sort {$b=~/Size/ <=> $a=~/Size/} sort keys(%{$TypeChanges{$TypeName}}))
14745 {
14746 foreach my $Location (sort {cmp_locations($b, $a)} sort keys(%{$TypeChanges{$TypeName}{$Kind}}))
14747 {
14748 my %Problem = %{$TypeChanges{$TypeName}{$Kind}{$Location}};
14749 $TYPE_PROBLEMS .= " <problem id=\"$Kind\">\n";
14750 my $Change = $CompatRules{$Level}{$Kind}{"Change"};
14751 $TYPE_PROBLEMS .= " <change".getXmlParams($Change, \%Problem).">$Change</change>\n";
14752 my $Effect = $CompatRules{$Level}{$Kind}{"Effect"};
14753 $TYPE_PROBLEMS .= " <effect".getXmlParams($Effect, \%Problem).">$Effect</effect>\n";
14754 my $Overcome = $CompatRules{$Level}{$Kind}{"Overcome"};
14755 $TYPE_PROBLEMS .= " <overcome".getXmlParams($Overcome, \%Problem).">$Overcome</overcome>\n";
14756 $TYPE_PROBLEMS .= " </problem>\n";
14757 }
14758 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +040014759 $TYPE_PROBLEMS .= getAffectedSymbols($Level, $TypeName, $Kinds_Locations{$TypeName}, \@Symbols);
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014760 if($Level eq "Binary" and grep {$_=~/Virtual|Base_Class/} keys(%{$Kinds_Locations{$TypeName}})) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014761 $TYPE_PROBLEMS .= showVTables($TypeName);
14762 }
14763 $TYPE_PROBLEMS .= " </type>\n";
14764 }
14765 $TYPE_PROBLEMS .= " </header>\n";
14766 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014767 $TYPE_PROBLEMS = "<problems_with_types severity=\"$TargetSeverity\">\n".$TYPE_PROBLEMS."</problems_with_types>\n\n";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014768 }
14769 else
14770 { # HTML
14771 my $ProblemsNum = 0;
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014772 foreach my $HeaderName (sort {lc($a) cmp lc($b)} keys(%ReportMap))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014773 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014774 my (%NameSpace_Type) = ();
14775 foreach my $TypeName (keys(%{$ReportMap{$HeaderName}})) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014776 $NameSpace_Type{parse_TypeNameSpace($TypeName, 1)}{$TypeName} = 1;
14777 }
14778 foreach my $NameSpace (sort keys(%NameSpace_Type))
14779 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014780 $TYPE_PROBLEMS .= getTitle($HeaderName, "", $NameSpace);
14781 my @SortedTypes = sort {$TypeType{$a}." ".lc($a) cmp $TypeType{$b}." ".lc($b)} keys(%{$NameSpace_Type{$NameSpace}});
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014782 foreach my $TypeName (@SortedTypes)
14783 {
14784 my $ProblemNum = 1;
14785 my $TYPE_REPORT = "";
14786 foreach my $Kind (sort {$b=~/Size/ <=> $a=~/Size/} sort keys(%{$TypeChanges{$TypeName}}))
14787 {
14788 foreach my $Location (sort {cmp_locations($b, $a)} sort keys(%{$TypeChanges{$TypeName}{$Kind}}))
14789 {
14790 my %Problem = %{$TypeChanges{$TypeName}{$Kind}{$Location}};
14791 if(my $Change = applyMacroses($Level, $Kind, $CompatRules{$Level}{$Kind}{"Change"}, \%Problem))
14792 {
14793 my $Effect = applyMacroses($Level, $Kind, $CompatRules{$Level}{$Kind}{"Effect"}, \%Problem);
14794 $TYPE_REPORT .= "<tr><th>$ProblemNum</th><td align='left' valign='top'>".$Change."</td><td align='left' valign='top'>$Effect</td></tr>\n";
14795 $ProblemNum += 1;
14796 $ProblemsNum += 1;
14797 }
14798 }
14799 }
14800 $ProblemNum -= 1;
14801 if($TYPE_REPORT)
14802 {
Andrey Ponomarenko85043792012-05-14 16:48:07 +040014803 my $Affected = getAffectedSymbols($Level, $TypeName, $Kinds_Locations{$TypeName}, \@Symbols);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014804 my $ShowVTables = "";
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014805 if($Level eq "Binary" and grep {$_=~/Virtual|Base_Class/} keys(%{$Kinds_Locations{$TypeName}})) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014806 $ShowVTables = showVTables($TypeName);
14807 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014808 $TYPE_PROBLEMS .= $ContentSpanStart."<span class='extendable'>[+]</span> <span class='ttype'>".$TypeType{$TypeName}."</span> ".htmlSpecChars($TypeName)." ($ProblemNum)".$ContentSpanEnd;
14809 $TYPE_PROBLEMS .= "<br/>\n".$ContentDivStart."<table class='ptable'><tr>\n";
14810 $TYPE_PROBLEMS .= "<th width='2%'></th><th width='47%'>Change</th>\n";
14811 $TYPE_PROBLEMS .= "<th>Effect</th></tr>".$TYPE_REPORT."</table>\n";
14812 $TYPE_PROBLEMS .= $ShowVTables.$Affected."<br/><br/>".$ContentDivEnd."\n";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014813 if($NameSpace) {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040014814 $TYPE_PROBLEMS=~s/\b\Q$NameSpace\E::(\w|\~)/$1/g;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014815 }
14816 }
14817 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014818 $TYPE_PROBLEMS .= "<br/>";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014819 }
14820 }
14821 if($TYPE_PROBLEMS)
14822 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014823 $TYPE_PROBLEMS = insertIDs($TYPE_PROBLEMS);
14824 my $Title = "Problems with Data Types, $TargetSeverity Severity";
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014825 if($TargetSeverity eq "Safe")
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014826 { # Safe Changes
14827 $Title = "Other Changes in Data Types";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014828 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014829 $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 +040014830 }
14831 }
14832 return $TYPE_PROBLEMS;
14833}
14834
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014835sub get_Anchor($$$)
14836{
14837 my ($Kind, $Level, $Severity) = @_;
14838 if($JoinReport)
14839 {
14840 if($Severity eq "Safe") {
14841 return "Other_".$Level."_Changes_In_".$Kind."s";
14842 }
14843 else {
14844 return $Kind."_".$Level."_Problems_".$Severity;
14845 }
14846 }
14847 else
14848 {
14849 if($Severity eq "Safe") {
14850 return "Other_Changes_In_".$Kind."s";
14851 }
14852 else {
14853 return $Kind."_Problems_".$Severity;
14854 }
14855 }
14856}
14857
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014858sub showVTables($)
14859{
14860 my $TypeName = $_[0];
14861 my $TypeId1 = $TName_Tid{1}{$TypeName};
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040014862 my %Type1 = get_Type($TypeId1, 1);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014863 if(defined $Type1{"VTable"}
14864 and keys(%{$Type1{"VTable"}}))
14865 {
14866 my $TypeId2 = $TName_Tid{2}{$TypeName};
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040014867 my %Type2 = get_Type($TypeId2, 2);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014868 if(defined $Type2{"VTable"}
14869 and keys(%{$Type2{"VTable"}}))
14870 {
14871 my %Indexes = map {$_=>1} (keys(%{$Type1{"VTable"}}), keys(%{$Type2{"VTable"}}));
14872 my %Entries = ();
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014873 foreach my $Index (sort {int($a)<=>int($b)} (keys(%Indexes)))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014874 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014875 $Entries{$Index}{"E1"} = simpleVEntry($Type1{"VTable"}{$Index});
14876 $Entries{$Index}{"E2"} = simpleVEntry($Type2{"VTable"}{$Index});
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014877 }
14878 my $VTABLES = "";
14879 if($ReportFormat eq "xml")
14880 { # XML
14881 $VTABLES .= " <vtable>\n";
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014882 foreach my $Index (sort {int($a)<=>int($b)} (keys(%Entries)))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014883 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014884 $VTABLES .= " <entry offset=\"".$Index."\">\n";
14885 $VTABLES .= " <old>".htmlSpecChars($Entries{$Index}{"E1"})."</old>\n";
14886 $VTABLES .= " <new>".htmlSpecChars($Entries{$Index}{"E2"})."</new>\n";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014887 $VTABLES .= " </entry>\n";
14888 }
14889 $VTABLES .= " </vtable>\n\n";
14890 }
14891 else
14892 { # HTML
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014893 $VTABLES .= "<table class='vtable'>";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014894 $VTABLES .= "<tr><th width='2%'>Offset</th>";
14895 $VTABLES .= "<th width='45%'>Virtual Table (Old) - ".(keys(%{$Type1{"VTable"}}))." entries</th>";
14896 $VTABLES .= "<th>Virtual Table (New) - ".(keys(%{$Type2{"VTable"}}))." entries</th></tr>";
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014897 foreach my $Index (sort {int($a)<=>int($b)} (keys(%Entries)))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014898 {
14899 my ($Color1, $Color2) = ("", "");
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014900 if($Entries{$Index}{"E1"} ne $Entries{$Index}{"E2"})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014901 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014902 if($Entries{$Index}{"E1"})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014903 {
Andrey Ponomarenko16934472012-03-29 15:37:04 +040014904 $Color1 = " class='failed'";
14905 $Color2 = " class='failed'";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014906 }
14907 else {
Andrey Ponomarenko16934472012-03-29 15:37:04 +040014908 $Color2 = " class='warning'";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014909 }
14910 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014911 $VTABLES .= "<tr><th>".$Index."</th>\n";
14912 $VTABLES .= "<td$Color1>".htmlSpecChars($Entries{$Index}{"E1"})."</td>\n";
14913 $VTABLES .= "<td$Color2>".htmlSpecChars($Entries{$Index}{"E2"})."</td></tr>\n";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014914 }
14915 $VTABLES .= "</table><br/>\n";
14916 $VTABLES = $ContentDivStart.$VTABLES.$ContentDivEnd;
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014917 $VTABLES = $ContentSpanStart_Info."[+] show v-table (old and new)".$ContentSpanEnd."<br/>\n".$VTABLES;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014918 }
14919 return $VTABLES;
14920 }
14921 }
14922 return "";
14923}
14924
14925sub simpleVEntry($)
14926{
14927 my $VEntry = $_[0];
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040014928 if(not defined $VEntry
14929 or $VEntry eq "") {
14930 return "";
14931 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014932 $VEntry=~s/\A(.+)::(_ZThn.+)\Z/$2/; # thunks
14933 $VEntry=~s/_ZTI\w+/typeinfo/g; # typeinfo
14934 if($VEntry=~/\A_ZThn.+\Z/) {
14935 $VEntry = "non-virtual thunk";
14936 }
14937 $VEntry=~s/\A\(int \(\*\)\(...\)\)([^\(\d])/$1/i;
14938 # support for old GCC versions
14939 $VEntry=~s/\A0u\Z/(int (*)(...))0/;
14940 $VEntry=~s/\A4294967268u\Z/(int (*)(...))-0x000000004/;
14941 $VEntry=~s/\A&_Z\Z/& _Z/;
14942 # templates
14943 if($VEntry=~s/ \[with (\w+) = (.+?)(, [^=]+ = .+|])\Z//g)
14944 { # std::basic_streambuf<_CharT, _Traits>::imbue [with _CharT = char, _Traits = std::char_traits<char>]
14945 # become std::basic_streambuf<char, ...>::imbue
14946 my ($Pname, $Pval) = ($1, $2);
14947 if($Pname eq "_CharT" and $VEntry=~/\Astd::/)
14948 { # stdc++ typedefs
14949 $VEntry=~s/<$Pname(, [^<>]+|)>/<$Pval>/g;
14950 # FIXME: simplify names using stdcxx typedefs (StdCxxTypedef)
14951 # The typedef info should be added to ABI dumps
14952 }
14953 else
14954 {
14955 $VEntry=~s/<$Pname>/<$Pval>/g;
14956 $VEntry=~s/<$Pname, [^<>]+>/<$Pval, ...>/g;
14957 }
14958 }
14959 $VEntry=~s/([^:]+)::\~([^:]+)\Z/~$1/; # destructors
14960 return $VEntry;
14961}
14962
Andrey Ponomarenko85043792012-05-14 16:48:07 +040014963sub getAffectedSymbols($$$$)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014964{
Andrey Ponomarenko85043792012-05-14 16:48:07 +040014965 my ($Level, $Target_TypeName, $Kinds_Locations, $Syms) = @_;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014966 my $LIMIT = 1000;
Andrey Ponomarenko85043792012-05-14 16:48:07 +040014967 if($#{$Syms}>=10000)
14968 { # reduce size of the report
14969 $LIMIT = 10;
14970 }
14971 my %SProblems = ();
14972 foreach my $Symbol (@{$Syms})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014973 {
Andrey Ponomarenko85043792012-05-14 16:48:07 +040014974 if(keys(%SProblems)>$LIMIT) {
14975 last;
14976 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014977 if(($Symbol=~/C2E|D2E|D0E/))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014978 { # duplicated problems for C2 constructors, D2 and D0 destructors
14979 next;
14980 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014981 my ($SN, $SS, $SV) = separate_symbol($Symbol);
14982 if($Level eq "Source")
14983 { # remove symbol version
14984 $Symbol=$SN;
14985 }
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040014986 my ($MinPath_Length, $ProblemLocation_Last) = (-1, "");
14987 my $Severity_Max = 0;
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014988 my $Signature = get_Signature($Symbol, 1);
14989 foreach my $Kind (keys(%{$CompatProblems{$Level}{$Symbol}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014990 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014991 foreach my $Location (keys(%{$CompatProblems{$Level}{$Symbol}{$Kind}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014992 {
14993 if(not defined $Kinds_Locations->{$Kind}
14994 or not $Kinds_Locations->{$Kind}{$Location}) {
14995 next;
14996 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014997 if($SV and defined $CompatProblems{$Level}{$SN}
14998 and defined $CompatProblems{$Level}{$SN}{$Kind}{$Location})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014999 { # duplicated problems for versioned symbols
15000 next;
15001 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015002 my $Type_Name = $CompatProblems{$Level}{$Symbol}{$Kind}{$Location}{"Type_Name"};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015003 next if($Type_Name ne $Target_TypeName);
15004
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015005 my $Position = $CompatProblems{$Level}{$Symbol}{$Kind}{$Location}{"Param_Pos"};
15006 my $Param_Name = $CompatProblems{$Level}{$Symbol}{$Kind}{$Location}{"Param_Name"};
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040015007 my $Severity = getProblemSeverity($Level, $Kind);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015008 my $Path_Length = 0;
15009 my $ProblemLocation = $Location;
15010 if($Type_Name) {
15011 $ProblemLocation=~s/->\Q$Type_Name\E\Z//g;
15012 }
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040015013 while($ProblemLocation=~/\-\>/g) {
15014 $Path_Length += 1;
15015 }
15016 if($MinPath_Length==-1 or ($Path_Length<=$MinPath_Length and $Severity_Val{$Severity}>$Severity_Max)
15017 or (cmp_locations($ProblemLocation, $ProblemLocation_Last) and $Severity_Val{$Severity}==$Severity_Max))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015018 {
15019 $MinPath_Length = $Path_Length;
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040015020 $Severity_Max = $Severity_Val{$Severity};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015021 $ProblemLocation_Last = $ProblemLocation;
Andrey Ponomarenko85043792012-05-14 16:48:07 +040015022 %{$SProblems{$Symbol}} = (
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040015023 "Descr"=>getAffectDescription($Level, $Symbol, $Kind, $Location),
15024 "Severity_Max"=>$Severity_Max,
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015025 "Signature"=>$Signature,
15026 "Position"=>$Position,
15027 "Param_Name"=>$Param_Name,
15028 "Location"=>$Location
15029 );
15030 }
15031 }
15032 }
15033 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +040015034 my @Symbols = keys(%SProblems);
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015035 @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 +040015036 @Symbols = sort {$SProblems{$b}{"Severity_Max"}<=>$SProblems{$a}{"Severity_Max"}} @Symbols;
15037 if($#Symbols+1>$LIMIT)
15038 { # remove last element
15039 pop(@Symbols);
15040 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015041 my $Affected = "";
15042 if($ReportFormat eq "xml")
15043 { # XML
15044 $Affected .= " <affected>\n";
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015045 foreach my $Symbol (@Symbols)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015046 {
Andrey Ponomarenko85043792012-05-14 16:48:07 +040015047 my $Param_Name = $SProblems{$Symbol}{"Param_Name"};
15048 my $Description = $SProblems{$Symbol}{"Descr"};
15049 my $Location = $SProblems{$Symbol}{"Location"};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015050 my $Target = "";
15051 if($Param_Name) {
15052 $Target = " affected=\"param\" param_name=\"$Param_Name\"";
15053 }
15054 elsif($Location=~/\Aretval(\-|\Z)/i) {
15055 $Target = " affected=\"retval\"";
15056 }
15057 elsif($Location=~/\Athis(\-|\Z)/i) {
15058 $Target = " affected=\"this\"";
15059 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015060 $Affected .= " <symbol$Target name=\"$Symbol\">\n";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015061 $Affected .= " <comment>".htmlSpecChars($Description)."</comment>\n";
15062 $Affected .= " </symbol>\n";
15063 }
15064 $Affected .= " </affected>\n";
15065 }
15066 else
15067 { # HTML
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015068 foreach my $Symbol (@Symbols)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015069 {
Andrey Ponomarenko85043792012-05-14 16:48:07 +040015070 my $Description = $SProblems{$Symbol}{"Descr"};
15071 my $Signature = $SProblems{$Symbol}{"Signature"};
15072 my $Pos = $SProblems{$Symbol}{"Position"};
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040015073 $Affected .= "<span class='iname_b'>".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 +040015074 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +040015075 if(keys(%SProblems)>$LIMIT) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015076 $Affected .= "and others ...<br/>";
15077 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +040015078 $Affected = "<div class='affected'>".$Affected."</div>";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015079 if($Affected)
15080 {
15081 $Affected = $ContentDivStart.$Affected.$ContentDivEnd;
Andrey Ponomarenko85043792012-05-14 16:48:07 +040015082 $Affected = $ContentSpanStart_Affected."[+] affected symbols (".(keys(%SProblems)>$LIMIT?">".$LIMIT:keys(%SProblems)).")".$ContentSpanEnd.$Affected;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015083 }
15084 }
15085 return $Affected;
15086}
15087
15088sub cmp_locations($$)
15089{
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040015090 my ($L1, $L2) = @_;
15091 if($L2=~/\b(retval|this)\b/
15092 and $L1!~/\b(retval|this)\b/ and $L1!~/\-\>/) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015093 return 1;
15094 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040015095 if($L2=~/\b(retval|this)\b/ and $L2=~/\-\>/
15096 and $L1!~/\b(retval|this)\b/ and $L1=~/\-\>/) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015097 return 1;
15098 }
15099 return 0;
15100}
15101
15102sub getAffectDescription($$$$)
15103{
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015104 my ($Level, $Symbol, $Kind, $Location) = @_;
15105 my %Problem = %{$CompatProblems{$Level}{$Symbol}{$Kind}{$Location}};
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040015106 my $PPos = showPos($Problem{"Param_Pos"});
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015107 my @Sentence = ();
15108 $Location=~s/\A(.*)\-\>.+?\Z/$1/;
15109 if($Kind eq "Overridden_Virtual_Method"
15110 or $Kind eq "Overridden_Virtual_Method_B") {
15111 push(@Sentence, "The method '".$Problem{"New_Value"}."' will be called instead of this method.");
15112 }
15113 elsif($CompatRules{$Level}{$Kind}{"Kind"} eq "Types")
15114 {
15115 if($Location eq "this" or $Kind=~/(\A|_)Virtual(_|\Z)/)
15116 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015117 my $METHOD_TYPE = $CompleteSignature{1}{$Symbol}{"Constructor"}?"constructor":"method";
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040015118 my $ClassName = $TypeInfo{1}{$CompleteSignature{1}{$Symbol}{"Class"}}{"Name"};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015119 if($ClassName eq $Problem{"Type_Name"}) {
15120 push(@Sentence, "This $METHOD_TYPE is from \'".$Problem{"Type_Name"}."\' class.");
15121 }
15122 else {
15123 push(@Sentence, "This $METHOD_TYPE is from derived class \'".$ClassName."\'.");
15124 }
15125 }
15126 else
15127 {
15128 if($Location=~/retval/)
15129 { # return value
15130 if($Location=~/\-\>/) {
15131 push(@Sentence, "Field \'".$Location."\' in return value");
15132 }
15133 else {
15134 push(@Sentence, "Return value");
15135 }
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040015136 if(my $Init = $Problem{"InitialType_Type"})
15137 {
15138 if($Init eq "Pointer") {
15139 push(@Sentence, "(pointer)");
15140 }
15141 elsif($Init eq "Ref") {
15142 push(@Sentence, "(reference)");
15143 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015144 }
15145 }
15146 elsif($Location=~/this/)
15147 { # "this" pointer
15148 if($Location=~/\-\>/) {
15149 push(@Sentence, "Field \'".$Location."\' in the object of this method");
15150 }
15151 else {
15152 push(@Sentence, "\'this\' pointer");
15153 }
15154 }
15155 else
15156 { # parameters
15157 if($Location=~/\-\>/) {
15158 push(@Sentence, "Field \'".$Location."\' in $PPos parameter");
15159 }
15160 else {
15161 push(@Sentence, "$PPos parameter");
15162 }
15163 if($Problem{"Param_Name"}) {
15164 push(@Sentence, "\'".$Problem{"Param_Name"}."\'");
15165 }
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040015166 if(my $Init = $Problem{"InitialType_Type"})
15167 {
15168 if($Init eq "Pointer") {
15169 push(@Sentence, "(pointer)");
15170 }
15171 elsif($Init eq "Ref") {
15172 push(@Sentence, "(reference)");
15173 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015174 }
15175 }
15176 if($Location eq "this") {
15177 push(@Sentence, "has base type \'".$Problem{"Type_Name"}."\'.");
15178 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040015179 elsif(defined $Problem{"Start_Type_Name"}
15180 and $Problem{"Start_Type_Name"} eq $Problem{"Type_Name"}) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015181 push(@Sentence, "has type \'".$Problem{"Type_Name"}."\'.");
15182 }
15183 else {
15184 push(@Sentence, "has base type \'".$Problem{"Type_Name"}."\'.");
15185 }
15186 }
15187 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040015188 if($ExtendedSymbols{$Symbol}) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015189 push(@Sentence, " This is a symbol from an artificial external library that may use the \'$TargetLibraryName\' library and change its ABI after recompiling.");
15190 }
15191 return join(" ", @Sentence);
15192}
15193
15194sub get_XmlSign($$)
15195{
15196 my ($Symbol, $LibVersion) = @_;
15197 my $Info = $CompleteSignature{$LibVersion}{$Symbol};
15198 my $Report = "";
15199 foreach my $Pos (sort {int($a)<=>int($b)} keys(%{$Info->{"Param"}}))
15200 {
15201 my $Name = $Info->{"Param"}{$Pos}{"name"};
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040015202 my $Type = $Info->{"Param"}{$Pos}{"type"};
15203 my $TypeName = $TypeInfo{$LibVersion}{$Type}{"Name"};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015204 foreach my $Typedef (keys(%ChangedTypedef))
15205 {
15206 my $Base = $Typedef_BaseName{$LibVersion}{$Typedef};
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040015207 $TypeName=~s/\b\Q$Typedef\E\b/$Base/g;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015208 }
15209 $Report .= " <param pos=\"$Pos\">\n";
15210 $Report .= " <name>".$Name."</name>\n";
15211 $Report .= " <type>".htmlSpecChars($TypeName)."</type>\n";
15212 $Report .= " </param>\n";
15213 }
15214 if(my $Return = $Info->{"Return"})
15215 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040015216 my $RTName = $TypeInfo{$LibVersion}{$Return}{"Name"};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015217 $Report .= " <retval>\n";
15218 $Report .= " <type>".htmlSpecChars($RTName)."</type>\n";
15219 $Report .= " </retval>\n";
15220 }
15221 return $Report;
15222}
15223
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015224sub get_Report_SymbolsInfo($)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015225{
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015226 my $Level = $_[0];
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015227 my $Report = "<symbols_info>\n";
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015228 foreach my $Symbol (sort keys(%{$CompatProblems{$Level}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015229 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015230 my ($SN, $SS, $SV) = separate_symbol($Symbol);
15231 if($SV and defined $CompatProblems{$Level}{$SN}) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015232 next;
15233 }
15234 $Report .= " <symbol name=\"$Symbol\">\n";
15235 my ($S1, $P1, $S2, $P2) = ();
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015236 if(not $AddedInt{$Level}{$Symbol})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015237 {
15238 if(defined $CompleteSignature{1}{$Symbol}
15239 and defined $CompleteSignature{1}{$Symbol}{"Header"})
15240 {
15241 $P1 = get_XmlSign($Symbol, 1);
15242 $S1 = get_Signature($Symbol, 1);
15243 }
15244 elsif($Symbol=~/\A(_Z|\?)/) {
15245 $S1 = $tr_name{$Symbol};
15246 }
15247 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015248 if(not $RemovedInt{$Level}{$Symbol})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015249 {
15250 if(defined $CompleteSignature{2}{$Symbol}
15251 and defined $CompleteSignature{2}{$Symbol}{"Header"})
15252 {
15253 $P2 = get_XmlSign($Symbol, 2);
15254 $S2 = get_Signature($Symbol, 2);
15255 }
15256 elsif($Symbol=~/\A(_Z|\?)/) {
15257 $S2 = $tr_name{$Symbol};
15258 }
15259 }
15260 if($S1)
15261 {
15262 $Report .= " <old signature=\"".htmlSpecChars($S1)."\">\n";
15263 $Report .= $P1;
15264 $Report .= " </old>\n";
15265 }
15266 if($S2 and $S2 ne $S1)
15267 {
15268 $Report .= " <new signature=\"".htmlSpecChars($S2)."\">\n";
15269 $Report .= $P2;
15270 $Report .= " </new>\n";
15271 }
15272 $Report .= " </symbol>\n";
15273 }
15274 $Report .= "</symbols_info>\n";
15275 return $Report;
15276}
15277
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015278sub writeReport($$)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015279{
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015280 my ($Level, $Report) = @_;
15281 if($ReportFormat eq "xml") {
15282 $Report = "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n".$Report;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015283 }
15284 if($StdOut)
15285 { # --stdout option
15286 print STDOUT $Report;
15287 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015288 else
15289 {
15290 my $RPath = getReportPath($Level);
Andrey Ponomarenko85043792012-05-14 16:48:07 +040015291 mkpath(get_dirname($RPath));
15292
15293 open(REPORT, ">", $RPath) || die ("can't open file \'$RPath\': $!\n");
15294 print REPORT $Report;
15295 close(REPORT);
15296
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040015297 if($Browse or $OpenReport)
15298 { # open in browser
15299 openReport($RPath);
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015300 if($JoinReport or $DoubleReport)
15301 {
15302 if($Level eq "Binary")
15303 { # wait to open a browser
15304 sleep(1);
15305 }
15306 }
15307 }
15308 }
15309}
15310
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040015311sub openReport($)
15312{
15313 my $Path = $_[0];
15314 my $Cmd = "";
15315 if($Browse)
15316 { # user-defined browser
15317 $Cmd = $Browse." \"".$Path."\"";
15318 }
15319 if(not $Cmd)
15320 { # default browser
15321 if($OSgroup eq "macos") {
15322 system("open \"".$Path."\"");
15323 }
15324 elsif($OSgroup eq "windows") {
15325 system("start \"".$Path."\"");
15326 }
15327 else
15328 { # linux, freebsd, solaris
15329 my @Browsers = (
15330 "x-www-browser",
15331 "sensible-browser",
15332 "firefox",
15333 "opera",
15334 "xdg-open",
15335 "lynx",
15336 "links"
15337 );
15338 foreach my $Br (@Browsers)
15339 {
15340 if($Br = get_CmdPath($Br))
15341 {
15342 $Cmd = $Br." \"".$Path."\"";
15343 last;
15344 }
15345 }
15346 }
15347 }
15348 if($Cmd)
15349 {
15350 if($Debug) {
15351 printMsg("INFO", "running $Cmd");
15352 }
15353 if($Cmd!~/lynx|links/) {
15354 $Cmd .= " >/dev/null 2>&1 &";
15355 }
15356 system($Cmd);
15357 }
15358 else {
15359 printMsg("ERROR", "cannot open report in browser");
15360 }
15361}
15362
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015363sub getReport($)
15364{
15365 my $Level = $_[0];
15366 if($ReportFormat eq "xml")
15367 { # XML
15368
15369 if($Level eq "Join")
15370 {
15371 my $Report = "<reports>\n";
15372 $Report .= getReport("Binary");
15373 $Report .= getReport("Source");
15374 $Report .= "</reports>\n";
15375 return $Report;
15376 }
15377 else
15378 {
15379 my $Report = "<report kind=\"".lc($Level)."\" version=\"$XML_REPORT_VERSION\">\n\n";
15380 my ($Summary, $MetaData) = get_Summary($Level);
15381 $Report .= $Summary."\n";
15382 $Report .= get_Report_Added($Level).get_Report_Removed($Level);
15383 $Report .= get_Report_Problems("High", $Level).get_Report_Problems("Medium", $Level).get_Report_Problems("Low", $Level).get_Report_Problems("Safe", $Level);
15384 $Report .= get_Report_SymbolsInfo($Level);
15385 $Report .= "</report>\n";
15386 return $Report;
15387 }
15388 }
15389 else
15390 { # HTML
15391 my $CssStyles = readModule("Styles", "Report.css");
15392 my $JScripts = readModule("Scripts", "Sections.js");
15393 if($Level eq "Join")
15394 {
15395 $CssStyles .= "\n".readModule("Styles", "Tabs.css");
15396 $JScripts .= "\n".readModule("Scripts", "Tabs.js");
Andrey Ponomarenkob8d203d2012-05-25 18:11:07 +040015397 my $Title = $TargetLibraryFName.": ".$Descriptor{1}{"Version"}." to ".$Descriptor{2}{"Version"}." compatibility report";
15398 my $Keywords = $TargetLibraryFName.", compatibility, API, report";
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015399 my $Description = "Compatibility report for the $TargetLibraryFName $TargetComponent between ".$Descriptor{1}{"Version"}." and ".$Descriptor{2}{"Version"}." versions";
15400 my ($BSummary, $BMetaData) = get_Summary("Binary");
15401 my ($SSummary, $SMetaData) = get_Summary("Source");
15402 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>";
15403 $Report .= get_Report_Header("Join")."
15404 <br/><div class='tabset'>
Andrey Ponomarenko16934472012-03-29 15:37:04 +040015405 <a id='BinaryID' href='#BinaryTab' class='tab active'>Binary<br/>Compatibility</a>
15406 <a id='SourceID' href='#SourceTab' style='margin-left:3px' class='tab disabled'>Source<br/>Compatibility</a>
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015407 </div>";
15408 $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>";
15409 $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>";
15410 $Report .= getReportFooter($TargetLibraryFName);
15411 $Report .= "\n<div style='height:999px;'></div>\n</body></html>";
15412 return $Report;
15413 }
15414 else
15415 {
15416 my ($Summary, $MetaData) = get_Summary($Level);
Andrey Ponomarenkob8d203d2012-05-25 18:11:07 +040015417 my $Title = $TargetLibraryFName.": ".$Descriptor{1}{"Version"}." to ".$Descriptor{2}{"Version"}." ".lc($Level)." compatibility report";
15418 my $Keywords = $TargetLibraryFName.", ".lc($Level)." compatibility, API, report";
15419 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 +040015420 if($Level eq "Binary")
15421 {
15422 if(getArch(1) eq getArch(2)
15423 and getArch(1) ne "unknown") {
15424 $Description .= " on ".showArch(getArch(1));
15425 }
15426 }
15427 my $Report = "<!-\- $MetaData -\->\n".composeHTML_Head($Title, $Keywords, $Description, $CssStyles, $JScripts)."\n<body>\n<div><a name='Top'></a>\n";
15428 $Report .= get_Report_Header($Level)."\n".$Summary."\n";
15429 $Report .= get_Report_Added($Level).get_Report_Removed($Level);
15430 $Report .= get_Report_Problems("High", $Level).get_Report_Problems("Medium", $Level).get_Report_Problems("Low", $Level).get_Report_Problems("Safe", $Level);
15431 $Report .= get_SourceInfo();
15432 $Report .= "</div>\n<br/><br/><br/><hr/>\n";
15433 $Report .= getReportFooter($TargetLibraryFName);
15434 $Report .= "\n<div style='height:999px;'></div>\n</body></html>";
15435 return $Report;
15436 }
15437 }
15438}
15439
Andrey Ponomarenko16934472012-03-29 15:37:04 +040015440sub getLegend()
15441{
15442 return "<br/>
15443<table class='summary'>
15444<tr>
15445 <td class='new'>added</td>
15446 <td class='passed'>compatible</td>
15447</tr>
15448<tr>
15449 <td class='warning'>warning</td>
15450 <td class='failed'>incompatible</td>
15451</tr></table>\n";
15452}
15453
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015454sub createReport()
15455{
15456 if($JoinReport)
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040015457 { # --stdout
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015458 writeReport("Join", getReport("Join"));
15459 }
15460 elsif($DoubleReport)
15461 { # default
15462 writeReport("Binary", getReport("Binary"));
15463 writeReport("Source", getReport("Source"));
15464 }
15465 elsif($BinaryOnly)
15466 { # --binary
15467 writeReport("Binary", getReport("Binary"));
15468 }
15469 elsif($SourceOnly)
15470 { # --source
15471 writeReport("Source", getReport("Source"));
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015472 }
15473}
15474
15475sub getReportFooter($)
15476{
15477 my $LibName = $_[0];
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015478 my $FooterStyle = (not $JoinReport)?"width:99%":"width:97%;padding-top:3px";
15479 my $Footer = "<div style='$FooterStyle;font-size:11px;' align='right'><i>Generated on ".(localtime time); # report date
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015480 $Footer .= " for <span style='font-weight:bold'>$LibName</span>"; # tested library/system name
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015481 $Footer .= " by <a href='".$HomePage{"Wiki"}."'>ABI Compliance Checker</a>"; # tool name
15482 my $ToolSummary = "<br/>A tool for checking backward compatibility of a C/C++ library API&#160;&#160;";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015483 $Footer .= " $TOOL_VERSION &#160;$ToolSummary</i></div>"; # tool version
15484 return $Footer;
15485}
15486
15487sub get_Report_Problems($$)
15488{
15489 my ($Priority, $Level) = @_;
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040015490 my $Report = get_Report_TypeProblems($Priority, $Level);
Andrey Ponomarenko16934472012-03-29 15:37:04 +040015491 if(my $SProblems = get_Report_SymbolProblems($Priority, $Level)) {
15492 $Report .= $SProblems;
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040015493 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015494 if($Priority eq "Low")
15495 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015496 $Report .= get_Report_ChangedConstants($Level);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015497 if($ReportFormat eq "html") {
15498 if($CheckImpl and $Level eq "Binary") {
15499 $Report .= get_Report_Impl();
15500 }
15501 }
15502 }
15503 if($ReportFormat eq "html")
15504 {
15505 if($Report)
15506 { # add anchor
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015507 if($JoinReport)
15508 {
15509 if($Priority eq "Safe") {
15510 $Report = "<a name=\'Other_".$Level."_Changes\'></a>".$Report;
15511 }
15512 else {
15513 $Report = "<a name=\'".$Priority."_Risk_".$Level."_Problems\'></a>".$Report;
15514 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015515 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015516 else
15517 {
15518 if($Priority eq "Safe") {
15519 $Report = "<a name=\'Other_Changes\'></a>".$Report;
15520 }
15521 else {
15522 $Report = "<a name=\'".$Priority."_Risk_Problems\'></a>".$Report;
15523 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015524 }
15525 }
15526 }
15527 return $Report;
15528}
15529
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015530sub composeHTML_Head($$$$$)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015531{
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015532 my ($Title, $Keywords, $Description, $Styles, $Scripts) = @_;
15533 return "<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.0 Transitional//EN\" \"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd\">
15534 <html xmlns=\"http://www.w3.org/1999/xhtml\" xml:lang=\"en\" lang=\"en\">
15535 <head>
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015536 <meta http-equiv=\"Content-Type\" content=\"text/html; charset=utf-8\" />
15537 <meta name=\"keywords\" content=\"$Keywords\" />
15538 <meta name=\"description\" content=\"$Description\" />
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015539 <title>
15540 $Title
15541 </title>
15542 <style type=\"text/css\">
15543 $Styles
15544 </style>
15545 <script type=\"text/javascript\" language=\"JavaScript\">
15546 <!--
15547 $Scripts
15548 -->
15549 </script>
15550 </head>";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015551}
15552
15553sub insertIDs($)
15554{
15555 my $Text = $_[0];
15556 while($Text=~/CONTENT_ID/)
15557 {
15558 if(int($Content_Counter)%2) {
15559 $ContentID -= 1;
15560 }
15561 $Text=~s/CONTENT_ID/c_$ContentID/;
15562 $ContentID += 1;
15563 $Content_Counter += 1;
15564 }
15565 return $Text;
15566}
15567
15568sub checkPreprocessedUnit($)
15569{
15570 my $Path = $_[0];
15571 my $CurHeader = "";
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015572 open(PREPROC, $Path) || die ("can't open file \'$Path\': $!\n");
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015573 while(<PREPROC>)
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015574 { # detecting public and private constants
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015575 next if(not /\A#/);
15576 chomp($_);
15577 if(/#[ \t]+\d+[ \t]+\"(.+)\"/) {
15578 $CurHeader=path_format($1, $OSgroup);
15579 }
15580 if(not $Include_Neighbors{$Version}{get_filename($CurHeader)}
15581 and not $Registered_Headers{$Version}{$CurHeader})
15582 { # not a target
15583 next;
15584 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +040015585 my $HName = get_filename($CurHeader);
15586 if(not is_target_header($HName, 1)
15587 and not is_target_header($HName, 2))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015588 { # user-defined header
15589 next;
15590 }
15591 if(/\#[ \t]*define[ \t]+([_A-Z0-9]+)[ \t]+(.+)[ \t]*\Z/)
15592 {
15593 my ($Name, $Value) = ($1, $2);
15594 if(not $Constants{$Version}{$Name}{"Access"})
15595 {
15596 $Constants{$Version}{$Name}{"Access"} = "public";
15597 $Constants{$Version}{$Name}{"Value"} = $Value;
15598 $Constants{$Version}{$Name}{"Header"} = get_filename($CurHeader);
15599 }
15600 }
15601 elsif(/\#[ \t]*undef[ \t]+([_A-Z]+)[ \t]*/) {
15602 $Constants{$Version}{$1}{"Access"} = "private";
15603 }
15604 }
15605 close(PREPROC);
15606 foreach my $Constant (keys(%{$Constants{$Version}}))
15607 {
15608 if($Constants{$Version}{$Constant}{"Access"} eq "private" or $Constant=~/_h\Z/i
15609 or isBuiltIn($Constants{$Version}{$Constant}{"Header"}))
15610 { # skip private constants
15611 delete($Constants{$Version}{$Constant});
15612 }
15613 else {
15614 delete($Constants{$Version}{$Constant}{"Access"});
15615 }
15616 }
15617}
15618
Andrey Ponomarenko16934472012-03-29 15:37:04 +040015619sub uncoverConstant($$)
15620{
15621 my ($LibVersion, $Constant) = @_;
15622 return "" if(not $LibVersion or not $Constant);
15623 return $Constant if(isCyclical(\@RecurConstant, $Constant));
15624 if(defined $Cache{"uncoverConstant"}{$LibVersion}{$Constant}) {
15625 return $Cache{"uncoverConstant"}{$LibVersion}{$Constant};
15626 }
15627 my $Value = $Constants{$LibVersion}{$Constant}{"Value"};
15628 if(defined $Value)
15629 {
15630 if($Value=~/\A[A-Z0-9_]+\Z/ and $Value=~/[A-Z]/)
15631 {
15632 push(@RecurConstant, $Constant);
15633 my $Uncovered = uncoverConstant($LibVersion, $Value);
15634 if($Uncovered ne "") {
15635 $Value = $Uncovered;
15636 }
15637 pop(@RecurConstant);
15638 }
15639 # FIXME: uncover $Value using all the enum constants
15640 # USECASE: change of define NC_LONG from NC_INT (enum value) to NC_INT (define)
15641 return ($Cache{"uncoverConstant"}{$LibVersion}{$Constant} = $Value);
15642 }
15643 return ($Cache{"uncoverConstant"}{$LibVersion}{$Constant} = "");
15644}
15645
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015646my %IgnoreConstant=(
15647 "VERSION"=>1,
15648 "VERSIONCODE"=>1,
15649 "VERNUM"=>1,
15650 "VERS_INFO"=>1,
15651 "PATCHLEVEL"=>1,
15652 "INSTALLPREFIX"=>1,
15653 "VBUILD"=>1,
15654 "VPATCH"=>1,
15655 "VMINOR"=>1,
15656 "BUILD_STRING"=>1,
15657 "BUILD_TIME"=>1,
15658 "PACKAGE_STRING"=>1,
15659 "PRODUCTION"=>1,
15660 "CONFIGURE_COMMAND"=>1,
15661 "INSTALLDIR"=>1,
15662 "BINDIR"=>1,
15663 "CONFIG_FILE_PATH"=>1,
15664 "DATADIR"=>1,
15665 "EXTENSION_DIR"=>1,
15666 "INCLUDE_PATH"=>1,
15667 "LIBDIR"=>1,
15668 "LOCALSTATEDIR"=>1,
15669 "SBINDIR"=>1,
15670 "SYSCONFDIR"=>1,
15671 "RELEASE"=>1,
15672 "SOURCE_ID"=>1,
15673 "SUBMINOR"=>1,
15674 "MINOR"=>1,
15675 "MINNOR"=>1,
15676 "MINORVERSION"=>1,
15677 "MAJOR"=>1,
15678 "MAJORVERSION"=>1,
15679 "MICRO"=>1,
15680 "MICROVERSION"=>1,
15681 "BINARY_AGE"=>1,
15682 "INTERFACE_AGE"=>1,
15683 "CORE_ABI"=>1,
15684 "PATCH"=>1,
15685 "COPYRIGHT"=>1,
15686 "TIMESTAMP"=>1,
15687 "REVISION"=>1,
15688 "PACKAGE_TAG"=>1,
15689 "PACKAGEDATE"=>1,
15690 "NUMVERSION"=>1
15691);
15692
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015693sub mergeConstants($)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015694{
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015695 my $Level = $_[0];
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015696 foreach my $Constant (keys(%{$Constants{1}}))
15697 {
15698 if($SkipConstants{1}{$Constant})
15699 { # skipped by the user
15700 next;
15701 }
Andrey Ponomarenko16934472012-03-29 15:37:04 +040015702 if(not defined $Constants{2}{$Constant}{"Value"}
15703 or $Constants{2}{$Constant}{"Value"} eq "")
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015704 { # empty value
15705 next;
15706 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +040015707 my $Header = $Constants{1}{$Constant}{"Header"};
15708 if(not is_target_header($Header, 1)
15709 and not is_target_header($Header, 2))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015710 { # user-defined header
15711 next;
15712 }
15713 my ($Old_Value, $New_Value, $Old_Value_Pure, $New_Value_Pure);
Andrey Ponomarenko16934472012-03-29 15:37:04 +040015714 $Old_Value = $Old_Value_Pure = uncoverConstant(1, $Constant);
15715 $New_Value = $New_Value_Pure = uncoverConstant(2, $Constant);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015716 $Old_Value_Pure=~s/(\W)\s+/$1/g;
15717 $Old_Value_Pure=~s/\s+(\W)/$1/g;
15718 $New_Value_Pure=~s/(\W)\s+/$1/g;
15719 $New_Value_Pure=~s/\s+(\W)/$1/g;
15720 next if($New_Value_Pure eq "" or $Old_Value_Pure eq "");
15721 if($New_Value_Pure ne $Old_Value_Pure)
15722 { # different values
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015723 if($Level eq "Binary")
15724 {
15725 if(grep {$Constant=~/(\A|_)$_(_|\Z)/} keys(%IgnoreConstant))
15726 { # ignore library version
15727 next;
15728 }
15729 if($Constant=~/(\A|_)(lib|open|)$TargetLibraryShortName(_|)(VERSION|VER|DATE|API|PREFIX)(_|\Z)/i)
15730 { # ignore library version
15731 next;
15732 }
15733 if($Old_Value=~/\A('|"|)[\/\\]\w+([\/\\]|:|('|"|)\Z)/ or $Old_Value=~/[\/\\]\w+[\/\\]\w+/)
15734 { # ignoring path defines:
Andrey Ponomarenko85043792012-05-14 16:48:07 +040015735 # /lib64:/usr/lib64:/lib:/usr/lib:/usr/X11R6/lib/Xaw3d ...
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015736 next;
15737 }
15738 if($Old_Value=~/\A\(*[a-z_]+(\s+|\|)/i)
15739 { # ignore source defines:
Andrey Ponomarenko85043792012-05-14 16:48:07 +040015740 # static int gcry_pth_init ( void) { return ...
15741 # (RE_BACKSLASH_ESCAPE_IN_LISTS | RE...
15742 next;
15743 }
15744 if($Old_Value=~/\(/i and $Old_Value!~/[\"\']/i)
15745 { # ignore source defines:
15746 # foo(p)
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015747 next;
15748 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015749 }
15750 if(convert_integer($Old_Value) eq convert_integer($New_Value))
15751 { # 0x0001 and 0x1, 0x1 and 1 equal constants
15752 next;
15753 }
15754 if($Old_Value eq "0" and $New_Value eq "NULL")
15755 { # 0 => NULL
15756 next;
15757 }
15758 if($Old_Value eq "NULL" and $New_Value eq "0")
15759 { # NULL => 0
15760 next;
15761 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015762 %{$ProblemsWithConstants{$Level}{$Constant}} = (
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015763 "Target"=>$Constant,
15764 "Old_Value"=>$Old_Value,
15765 "New_Value"=>$New_Value );
15766 }
15767 }
15768}
15769
15770sub convert_integer($)
15771{
15772 my $Value = $_[0];
15773 if($Value=~/\A0x[a-f0-9]+\Z/)
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015774 { # hexadecimal
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015775 return hex($Value);
15776 }
15777 elsif($Value=~/\A0[0-7]+\Z/)
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015778 { # octal
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015779 return oct($Value);
15780 }
15781 elsif($Value=~/\A0b[0-1]+\Z/)
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015782 { # binary
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015783 return oct($Value);
15784 }
15785 else {
15786 return $Value;
15787 }
15788}
15789
Andrey Ponomarenko16934472012-03-29 15:37:04 +040015790sub readSymbols($)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015791{
15792 my $LibVersion = $_[0];
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040015793 my @LibPaths = getSOPaths($LibVersion);
Andrey Ponomarenko16934472012-03-29 15:37:04 +040015794 if($#LibPaths==-1 and not $CheckHeadersOnly)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015795 {
15796 if($LibVersion==1)
15797 {
15798 printMsg("WARNING", "checking headers only");
15799 $CheckHeadersOnly = 1;
15800 }
15801 else {
15802 exitStatus("Error", "$SLIB_TYPE libraries are not found in ".$Descriptor{$LibVersion}{"Version"});
15803 }
15804 }
Andrey Ponomarenko16934472012-03-29 15:37:04 +040015805 my %GroupNames = map {parse_libname(get_filename($_), "name+ext", $OStarget)=>1} @LibPaths;
15806 foreach my $LibPath (sort {length($a)<=>length($b)} @LibPaths) {
15807 readSymbols_Lib($LibVersion, $LibPath, 0, \%GroupNames, "+Weak");
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015808 }
Andrey Ponomarenko16934472012-03-29 15:37:04 +040015809 if(not $CheckHeadersOnly)
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040015810 {
Andrey Ponomarenko16934472012-03-29 15:37:04 +040015811 if($#LibPaths!=-1)
15812 {
15813 if(not keys(%{$Symbol_Library{$LibVersion}}))
15814 {
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040015815 printMsg("WARNING", "the set of public symbols in library(ies) is empty ($LibVersion)");
Andrey Ponomarenko16934472012-03-29 15:37:04 +040015816 printMsg("WARNING", "checking headers only");
15817 $CheckHeadersOnly = 1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015818 }
15819 }
15820 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +040015821
15822 # clean memory
15823 %SystemObjects = ();
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015824}
15825
Andrey Ponomarenko16934472012-03-29 15:37:04 +040015826sub getSymbolSize($$)
15827{ # size from the shared library
15828 my ($Symbol, $LibVersion) = @_;
15829 return 0 if(not $Symbol);
15830 if(defined $Symbol_Library{$LibVersion}{$Symbol}
15831 and my $LibName = $Symbol_Library{$LibVersion}{$Symbol})
15832 {
15833 if(defined $Library_Symbol{$LibVersion}{$LibName}{$Symbol}
15834 and my $Size = $Library_Symbol{$LibVersion}{$LibName}{$Symbol})
15835 {
15836 if($Size<0) {
15837 return -$Size;
15838 }
15839 }
15840 }
15841 return 0;
15842}
15843
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015844sub canonifyName($)
15845{ # make TIFFStreamOpen(char const*, std::basic_ostream<char, std::char_traits<char> >*)
15846 # to be TIFFStreamOpen(char const*, std::basic_ostream<char>*)
15847 my $Name = $_[0];
15848 my $Rem = "std::(allocator|less|char_traits|regex_traits)";
Andrey Ponomarenko85043792012-05-14 16:48:07 +040015849 while($Name=~/([^<>,]+),\s*$Rem<([^<>,]+)>\s*/ and $1 eq $3)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015850 {
Andrey Ponomarenko85043792012-05-14 16:48:07 +040015851 my $P = $1;
15852 $Name=~s/\Q$P\E,\s*$Rem<\Q$P\E>\s*/$P/g;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015853 }
15854 return $Name;
15855}
15856
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040015857sub translateSymbols(@)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015858{
15859 my $LibVersion = pop(@_);
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040015860 my (@MnglNames1, @MnglNames2, @UnmangledNames) = ();
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015861 foreach my $Interface (sort @_)
15862 {
15863 if($Interface=~/\A_Z/)
15864 {
15865 next if($tr_name{$Interface});
15866 $Interface=~s/[\@\$]+(.*)\Z//;
15867 push(@MnglNames1, $Interface);
15868 }
15869 elsif($Interface=~/\A\?/) {
15870 push(@MnglNames2, $Interface);
15871 }
15872 else
15873 { # not mangled
15874 $tr_name{$Interface} = $Interface;
15875 $mangled_name_gcc{$Interface} = $Interface;
15876 $mangled_name{$LibVersion}{$Interface} = $Interface;
15877 }
15878 }
15879 if($#MnglNames1 > -1)
15880 { # GCC names
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040015881 @UnmangledNames = reverse(unmangleArray(@MnglNames1));
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015882 foreach my $MnglName (@MnglNames1)
15883 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040015884 if(my $Unmangled = pop(@UnmangledNames))
15885 {
15886 $tr_name{$MnglName} = formatName(canonifyName($Unmangled));
15887 if(not $mangled_name_gcc{$tr_name{$MnglName}}) {
15888 $mangled_name_gcc{$tr_name{$MnglName}} = $MnglName;
15889 }
15890 if($MnglName=~/\A_ZTV/
15891 and $tr_name{$MnglName}=~/vtable for (.+)/)
15892 { # bind class name and v-table symbol
15893 my $ClassName = $1;
15894 $ClassVTable{$ClassName} = $MnglName;
15895 $VTableClass{$MnglName} = $ClassName;
15896 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015897 }
15898 }
15899 }
15900 if($#MnglNames2 > -1)
15901 { # MSVC names
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040015902 @UnmangledNames = reverse(unmangleArray(@MnglNames2));
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015903 foreach my $MnglName (@MnglNames2)
15904 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040015905 if(my $Unmangled = pop(@UnmangledNames))
15906 {
15907 $tr_name{$MnglName} = formatName($Unmangled);
15908 $mangled_name{$LibVersion}{$tr_name{$MnglName}} = $MnglName;
15909 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015910 }
15911 }
15912 return \%tr_name;
15913}
15914
15915sub link_symbol($$$)
15916{
15917 my ($Symbol, $RunWith, $Deps) = @_;
15918 if(link_symbol_internal($Symbol, $RunWith, \%Symbol_Library)) {
15919 return 1;
15920 }
15921 if($Deps eq "+Deps")
15922 { # check the dependencies
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040015923 if(link_symbol_internal($Symbol, $RunWith, \%DepSymbol_Library)) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015924 return 1;
15925 }
15926 }
15927 return 0;
15928}
15929
15930sub link_symbol_internal($$$)
15931{
15932 my ($Symbol, $RunWith, $Where) = @_;
15933 return 0 if(not $Where or not $Symbol);
15934 if($Where->{$RunWith}{$Symbol})
15935 { # the exact match by symbol name
15936 return 1;
15937 }
15938 if(my $VSym = $SymVer{$RunWith}{$Symbol})
15939 { # indirect symbol version, i.e.
15940 # foo_old and its symlink foo@v (or foo@@v)
15941 # foo_old may be in .symtab table
15942 if($Where->{$RunWith}{$VSym}) {
15943 return 1;
15944 }
15945 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015946 my ($Sym, $Spec, $Ver) = separate_symbol($Symbol);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015947 if($Sym and $Ver)
15948 { # search for the symbol with the same version
15949 # or without version
15950 if($Where->{$RunWith}{$Sym})
15951 { # old: foo@v|foo@@v
15952 # new: foo
15953 return 1;
15954 }
15955 if($Where->{$RunWith}{$Sym."\@".$Ver})
15956 { # old: foo|foo@@v
15957 # new: foo@v
15958 return 1;
15959 }
15960 if($Where->{$RunWith}{$Sym."\@\@".$Ver})
15961 { # old: foo|foo@v
15962 # new: foo@@v
15963 return 1;
15964 }
15965 }
15966 return 0;
15967}
15968
Andrey Ponomarenko16934472012-03-29 15:37:04 +040015969sub readSymbols_App($)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015970{
15971 my $Path = $_[0];
15972 return () if(not $Path or not -f $Path);
15973 my @Imported = ();
15974 if($OSgroup eq "macos")
15975 {
15976 my $OtoolCmd = get_CmdPath("otool");
15977 if(not $OtoolCmd) {
15978 exitStatus("Not_Found", "can't find \"otool\"");
15979 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015980 open(APP, "$OtoolCmd -IV \"".$Path."\" 2>$TMP_DIR/null |");
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015981 while(<APP>) {
15982 if(/[^_]+\s+_?([\w\$]+)\s*\Z/) {
15983 push(@Imported, $1);
15984 }
15985 }
15986 close(APP);
15987 }
15988 elsif($OSgroup eq "windows")
15989 {
15990 my $DumpBinCmd = get_CmdPath("dumpbin");
15991 if(not $DumpBinCmd) {
15992 exitStatus("Not_Found", "can't find \"dumpbin.exe\"");
15993 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015994 open(APP, "$DumpBinCmd /IMPORTS \"".$Path."\" 2>$TMP_DIR/null |");
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015995 while(<APP>) {
15996 if(/\s*\w+\s+\w+\s+\w+\s+([\w\?\@]+)\s*/) {
15997 push(@Imported, $1);
15998 }
15999 }
16000 close(APP);
16001 }
16002 else
16003 {
16004 my $ReadelfCmd = get_CmdPath("readelf");
16005 if(not $ReadelfCmd) {
16006 exitStatus("Not_Found", "can't find \"readelf\"");
16007 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040016008 open(APP, "$ReadelfCmd -WhlSsdA \"".$Path."\" 2>$TMP_DIR/null |");
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040016009 my $symtab=0; # indicates that we are processing 'symtab' section of 'readelf' output
16010 while(<APP>)
16011 {
16012 if( /'.dynsym'/ ) {
16013 $symtab=0;
16014 }
16015 elsif($symtab == 1) {
16016 # do nothing with symtab (but there are some plans for the future)
16017 next;
16018 }
16019 elsif( /'.symtab'/ ) {
16020 $symtab=1;
16021 }
16022 elsif(my ($fullname, $idx, $Ndx, $type, $size, $bind) = readline_ELF($_))
16023 {
16024 if( $Ndx eq "UND" ) {
16025 #only imported symbols
16026 push(@Imported, $fullname);
16027 }
16028 }
16029 }
16030 close(APP);
16031 }
16032 return @Imported;
16033}
16034
16035sub readline_ELF($)
16036{
16037 if($_[0]=~/\s*\d+:\s+(\w*)\s+(\w+)\s+(\w+)\s+(\w+)\s+(\w+)\s+(\w+)\s([^\s]+)/)
16038 { # the line of 'readelf' output corresponding to the interface
16039 # symbian-style: _ZN12CCTTokenType4NewLE4TUid3RFs@@ctfinder{000a0000}[102020e5].dll
16040 my ($value, $size, $type, $bind,
16041 $vis, $Ndx, $fullname)=($1, $2, $3, $4, $5, $6, $7);
16042 if($bind!~/\A(WEAK|GLOBAL)\Z/) {
16043 return ();
16044 }
16045 if($type!~/\A(FUNC|IFUNC|OBJECT|COMMON)\Z/) {
16046 return ();
16047 }
16048 if($vis!~/\A(DEFAULT|PROTECTED)\Z/) {
16049 return ();
16050 }
16051 if($Ndx eq "ABS" and $value!~/\D|1|2|3|4|5|6|7|8|9/) {
16052 return ();
16053 }
16054 if($OStarget eq "symbian")
16055 {
16056 if($fullname=~/_\._\.absent_export_\d+/)
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040016057 { # "_._.absent_export_111"@@libstdcpp{00010001}[10282872].dll
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040016058 return ();
16059 }
16060 my @Elems = separate_symbol($fullname);
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040016061 $fullname = $Elems[0]; # remove internal version, {00020001}[10011235].dll
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040016062 }
16063 return ($fullname, $value, $Ndx, $type, $size, $bind);
16064 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040016065 return ();
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040016066}
16067
Andrey Ponomarenko16934472012-03-29 15:37:04 +040016068sub read_symlink($)
16069{
16070 my $Path = $_[0];
16071 return "" if(not $Path);
16072 return "" if(not -f $Path and not -l $Path);
16073 if(defined $Cache{"read_symlink"}{$Path}) {
16074 return $Cache{"read_symlink"}{$Path};
16075 }
16076 if(my $Res = readlink($Path)) {
16077 return ($Cache{"read_symlink"}{$Path} = $Res);
16078 }
16079 elsif(my $ReadlinkCmd = get_CmdPath("readlink")) {
16080 return ($Cache{"read_symlink"}{$Path} = `$ReadlinkCmd -n $Path`);
16081 }
16082 elsif(my $FileCmd = get_CmdPath("file"))
16083 {
16084 my $Info = `$FileCmd $Path`;
16085 if($Info=~/symbolic\s+link\s+to\s+['`"]*([\w\d\.\-\/\\]+)['`"]*/i) {
16086 return ($Cache{"read_symlink"}{$Path} = $1);
16087 }
16088 }
16089 return ($Cache{"read_symlink"}{$Path} = "");
16090}
16091
16092sub resolve_symlink($)
16093{
16094 my $Path = $_[0];
16095 return "" if(not $Path);
16096 return "" if(not -f $Path and not -l $Path);
16097 if(defined $Cache{"resolve_symlink"}{$Path}) {
16098 return $Cache{"resolve_symlink"}{$Path};
16099 }
16100 return $Path if(isCyclical(\@RecurSymlink, $Path));
16101 push(@RecurSymlink, $Path);
16102 if(-l $Path and my $Redirect=read_symlink($Path))
16103 {
16104 if(is_abs($Redirect))
16105 { # absolute path
16106 if($SystemRoot and $SystemRoot ne "/"
16107 and $Path=~/\A\Q$SystemRoot\E\//
16108 and (-f $SystemRoot.$Redirect or -l $SystemRoot.$Redirect))
16109 { # symbolic links from the sysroot
16110 # should be corrected to point to
16111 # the files inside sysroot
16112 $Redirect = $SystemRoot.$Redirect;
16113 }
16114 my $Res = resolve_symlink($Redirect);
16115 pop(@RecurSymlink);
16116 return ($Cache{"resolve_symlink"}{$Path} = $Res);
16117 }
16118 elsif($Redirect=~/\.\.[\/\\]/)
16119 { # relative path
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040016120 $Redirect = joinPath(get_dirname($Path), $Redirect);
Andrey Ponomarenko16934472012-03-29 15:37:04 +040016121 while($Redirect=~s&(/|\\)[^\/\\]+(\/|\\)\.\.(\/|\\)&$1&){};
16122 my $Res = resolve_symlink($Redirect);
16123 pop(@RecurSymlink);
16124 return ($Cache{"resolve_symlink"}{$Path} = $Res);
16125 }
16126 elsif(-f get_dirname($Path)."/".$Redirect)
16127 { # file name in the same directory
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040016128 my $Res = resolve_symlink(joinPath(get_dirname($Path), $Redirect));
Andrey Ponomarenko16934472012-03-29 15:37:04 +040016129 pop(@RecurSymlink);
16130 return ($Cache{"resolve_symlink"}{$Path} = $Res);
16131 }
16132 else
16133 { # broken link
16134 pop(@RecurSymlink);
16135 return ($Cache{"resolve_symlink"}{$Path} = "");
16136 }
16137 }
16138 pop(@RecurSymlink);
16139 return ($Cache{"resolve_symlink"}{$Path} = $Path);
16140}
16141
16142sub find_lib_path($$)
16143{
16144 my ($LibVersion, $DyLib) = @_;
16145 return "" if(not $DyLib or not $LibVersion);
16146 return $DyLib if(is_abs($DyLib));
16147 if(defined $Cache{"find_lib_path"}{$LibVersion}{$DyLib}) {
16148 return $Cache{"find_lib_path"}{$LibVersion}{$DyLib};
16149 }
16150 if(my @Paths = sort keys(%{$InputObject_Paths{$LibVersion}{$DyLib}})) {
16151 return ($Cache{"find_lib_path"}{$LibVersion}{$DyLib} = $Paths[0]);
16152 }
16153 elsif(my $DefaultPath = $DyLib_DefaultPath{$DyLib}) {
16154 return ($Cache{"find_lib_path"}{$LibVersion}{$DyLib} = $DefaultPath);
16155 }
16156 else
16157 {
16158 foreach my $Dir (sort keys(%DefaultLibPaths), sort keys(%{$SystemPaths{"lib"}}))
16159 { # search in default linker paths and then in all system paths
16160 if(-f $Dir."/".$DyLib) {
16161 return ($Cache{"find_lib_path"}{$LibVersion}{$DyLib} = joinPath($Dir,$DyLib));
16162 }
16163 }
16164 detectSystemObjects() if(not keys(%SystemObjects));
16165 if(my @AllObjects = keys(%{$SystemObjects{$DyLib}})) {
16166 return ($Cache{"find_lib_path"}{$LibVersion}{$DyLib} = $AllObjects[0]);
16167 }
16168 my $ShortName = parse_libname($DyLib, "name+ext", $OStarget);
16169 if($ShortName ne $DyLib
16170 and my $Path = find_lib_path($ShortName))
16171 { # FIXME: check this case
16172 return ($Cache{"find_lib_path"}{$LibVersion}{$DyLib} = $Path);
16173 }
16174 return ($Cache{"find_lib_path"}{$LibVersion}{$DyLib} = "");
16175 }
16176}
16177
16178sub readSymbols_Lib($$$$$)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040016179{
16180 my ($LibVersion, $Lib_Path, $IsNeededLib, $GroupNames, $Weak) = @_;
16181 return if(not $Lib_Path or not -f $Lib_Path);
16182 my ($Lib_Dir, $Lib_Name) = separate_path(resolve_symlink($Lib_Path));
16183 return if($CheckedDyLib{$LibVersion}{$Lib_Name} and $IsNeededLib);
16184 return if(isCyclical(\@RecurLib, $Lib_Name) or $#RecurLib>=1);
16185 $CheckedDyLib{$LibVersion}{$Lib_Name} = 1;
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040016186 my $Lib_SName = parse_libname($Lib_Name, "name+ext", $OStarget);
16187
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040016188 if($CheckImpl and not $IsNeededLib) {
16189 getImplementations($LibVersion, $Lib_Path);
16190 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040016191
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040016192 push(@RecurLib, $Lib_Name);
16193 my (%Value_Interface, %Interface_Value, %NeededLib) = ();
16194 if(not $IsNeededLib)
16195 { # libstdc++ and libc are always used by other libs
16196 # if you test one of these libs then you not need
16197 # to find them in the system for reusing
16198 if(parse_libname($Lib_Name, "short", $OStarget) eq "libstdc++")
16199 { # libstdc++.so.6
16200 $STDCXX_TESTING = 1;
16201 }
16202 if(parse_libname($Lib_Name, "short", $OStarget) eq "libc")
16203 { # libc-2.11.3.so
16204 $GLIBC_TESTING = 1;
16205 }
16206 }
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040016207 my $DebugPath = "";
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040016208 if($Debug)
16209 { # debug mode
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040016210 $DebugPath = $DEBUG_PATH{$LibVersion}."/libs/".get_filename($Lib_Path).".txt";
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040016211 mkpath(get_dirname($DebugPath));
16212 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040016213 if($OStarget eq "macos")
16214 { # Mac OS X: *.dylib, *.a
16215 my $OtoolCmd = get_CmdPath("otool");
16216 if(not $OtoolCmd) {
16217 exitStatus("Not_Found", "can't find \"otool\"");
16218 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040016219 $OtoolCmd .= " -TV \"".$Lib_Path."\" 2>$TMP_DIR/null";
16220 if($Debug)
16221 { # debug mode
Andrey Ponomarenko16934472012-03-29 15:37:04 +040016222 # write to file
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040016223 system($OtoolCmd." >".$DebugPath);
Andrey Ponomarenko16934472012-03-29 15:37:04 +040016224 open(LIB, $DebugPath);
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040016225 }
Andrey Ponomarenko16934472012-03-29 15:37:04 +040016226 else
16227 { # write to pipe
16228 open(LIB, $OtoolCmd." |");
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040016229 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040016230 while(<LIB>)
16231 {
16232 if(/[^_]+\s+_([\w\$]+)\s*\Z/)
16233 {
16234 my $realname = $1;
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040016235 if($IsNeededLib)
16236 {
16237 if(not $GroupNames->{$Lib_SName})
16238 {
16239 $DepSymbol_Library{$LibVersion}{$realname} = $Lib_Name;
16240 $DepLibrary_Symbol{$LibVersion}{$Lib_Name}{$realname} = 1;
16241 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040016242 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040016243 else
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040016244 {
16245 $Symbol_Library{$LibVersion}{$realname} = $Lib_Name;
16246 $Library_Symbol{$LibVersion}{$Lib_Name}{$realname} = 1;
16247 if($COMMON_LANGUAGE{$LibVersion} ne "C++"
16248 and $realname=~/\A(_Z|\?)/) {
16249 setLanguage($LibVersion, "C++");
16250 }
16251 if($CheckObjectsOnly
16252 and $LibVersion==1) {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040016253 $CheckedSymbols{"Binary"}{$realname} = 1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040016254 }
16255 }
16256 }
16257 }
16258 close(LIB);
16259 if($LIB_TYPE eq "dynamic")
16260 { # dependencies
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040016261 open(LIB, "$OtoolCmd -L \"".$Lib_Path."\" 2>$TMP_DIR/null |");
16262 while(<LIB>)
16263 {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040016264 if(/\s*([\/\\].+\.$LIB_EXT)\s*/
16265 and $1 ne $Lib_Path) {
16266 $NeededLib{$1} = 1;
16267 }
16268 }
16269 close(LIB);
16270 }
16271 }
16272 elsif($OStarget eq "windows")
16273 { # Windows *.dll, *.lib
16274 my $DumpBinCmd = get_CmdPath("dumpbin");
16275 if(not $DumpBinCmd) {
16276 exitStatus("Not_Found", "can't find \"dumpbin\"");
16277 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040016278 $DumpBinCmd .= " /EXPORTS \"".$Lib_Path."\" 2>$TMP_DIR/null";
16279 if($Debug)
16280 { # debug mode
Andrey Ponomarenko16934472012-03-29 15:37:04 +040016281 # write to file
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040016282 system($DumpBinCmd." >".$DebugPath);
Andrey Ponomarenko16934472012-03-29 15:37:04 +040016283 open(LIB, $DebugPath);
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040016284 }
Andrey Ponomarenko16934472012-03-29 15:37:04 +040016285 else
16286 { # write to pipe
16287 open(LIB, $DumpBinCmd." |");
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040016288 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040016289 while(<LIB>)
16290 { # 1197 4AC 0000A620 SetThreadStackGuarantee
16291 # 1198 4AD SetThreadToken (forwarded to ...)
16292 # 3368 _o2i_ECPublicKey
16293 if(/\A\s*\d+\s+[a-f\d]+\s+[a-f\d]+\s+([\w\?\@]+)\s*\Z/i
16294 or /\A\s*\d+\s+[a-f\d]+\s+([\w\?\@]+)\s*\(\s*forwarded\s+/
16295 or /\A\s*\d+\s+_([\w\?\@]+)\s*\Z/)
16296 { # dynamic, static and forwarded symbols
16297 my $realname = $1;
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040016298 if($IsNeededLib)
16299 {
16300 if(not $GroupNames->{$Lib_SName})
16301 {
16302 $DepSymbol_Library{$LibVersion}{$realname} = $Lib_Name;
16303 $DepLibrary_Symbol{$LibVersion}{$Lib_Name}{$realname} = 1;
16304 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040016305 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040016306 else
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040016307 {
16308 $Symbol_Library{$LibVersion}{$realname} = $Lib_Name;
16309 $Library_Symbol{$LibVersion}{$Lib_Name}{$realname} = 1;
16310 if($COMMON_LANGUAGE{$LibVersion} ne "C++"
16311 and $realname=~/\A(_Z|\?)/) {
16312 setLanguage($LibVersion, "C++");
16313 }
16314 if($CheckObjectsOnly
16315 and $LibVersion==1) {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040016316 $CheckedSymbols{"Binary"}{$realname} = 1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040016317 }
16318 }
16319 }
16320 }
16321 close(LIB);
16322 if($LIB_TYPE eq "dynamic")
16323 { # dependencies
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040016324 open(LIB, "$DumpBinCmd /DEPENDENTS \"".$Lib_Path."\" 2>$TMP_DIR/null |");
16325 while(<LIB>)
16326 {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040016327 if(/\s*([^\s]+?\.$LIB_EXT)\s*/i
16328 and $1 ne $Lib_Path) {
16329 $NeededLib{path_format($1, $OSgroup)} = 1;
16330 }
16331 }
16332 close(LIB);
16333 }
16334 }
16335 else
16336 { # Unix; *.so, *.a
16337 # Symbian: *.dso, *.lib
16338 my $ReadelfCmd = get_CmdPath("readelf");
16339 if(not $ReadelfCmd) {
16340 exitStatus("Not_Found", "can't find \"readelf\"");
16341 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040016342 $ReadelfCmd .= " -WhlSsdA \"".$Lib_Path."\" 2>$TMP_DIR/null";
16343 if($Debug)
16344 { # debug mode
Andrey Ponomarenko16934472012-03-29 15:37:04 +040016345 # write to file
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040016346 system($ReadelfCmd." >".$DebugPath);
Andrey Ponomarenko16934472012-03-29 15:37:04 +040016347 open(LIB, $DebugPath);
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040016348 }
Andrey Ponomarenko16934472012-03-29 15:37:04 +040016349 else
16350 { # write to pipe
16351 open(LIB, $ReadelfCmd." |");
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040016352 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040016353 my $symtab=0; # indicates that we are processing 'symtab' section of 'readelf' output
16354 while(<LIB>)
16355 {
16356 if($LIB_TYPE eq "dynamic")
16357 { # dynamic library specifics
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040016358 if($symtab==1)
16359 {
16360 if(/'\.dynsym'/)
16361 { # dynamic table
16362 $symtab=0;
16363 next;
16364 }
16365 else
16366 { # do nothing with symtab
16367 next;
16368 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040016369 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040016370 elsif(/'\.symtab'/)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040016371 { # symbol table
16372 $symtab=1;
16373 next;
16374 }
16375 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040016376 if(my ($fullname, $idx, $Ndx, $type, $size, $bind) = readline_ELF($_))
16377 { # read ELF entry
16378 if( $Ndx eq "UND" )
16379 { # ignore interfaces that are imported from somewhere else
16380 next;
16381 }
16382 if($bind eq "WEAK"
16383 and $Weak eq "-Weak")
16384 { # skip WEAK symbols
16385 next;
16386 }
16387 my ($realname, $version_spec, $version) = separate_symbol($fullname);
16388 if($type eq "OBJECT")
16389 { # global data
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040016390 $GlobalDataObject{$LibVersion}{$fullname} = 1;
16391 $GlobalDataObject{$LibVersion}{$realname} = 1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040016392 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040016393 if($IsNeededLib)
16394 {
16395 if(not $GroupNames->{$Lib_SName})
16396 {
16397 $DepSymbol_Library{$LibVersion}{$fullname} = $Lib_Name;
16398 $DepLibrary_Symbol{$LibVersion}{$Lib_Name}{$fullname} = ($type eq "OBJECT")?-$size:1;
16399 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040016400 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040016401 else
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040016402 {
16403 $Symbol_Library{$LibVersion}{$fullname} = $Lib_Name;
16404 $Library_Symbol{$LibVersion}{$Lib_Name}{$fullname} = ($type eq "OBJECT")?-$size:1;
16405 if($LIB_EXT eq "so")
16406 { # value
16407 $Interface_Value{$LibVersion}{$fullname} = $idx;
16408 $Value_Interface{$LibVersion}{$idx}{$fullname} = 1;
16409 }
16410 if($COMMON_LANGUAGE{$LibVersion} ne "C++"
16411 and $realname=~/\A(_Z|\?)/) {
16412 setLanguage($LibVersion, "C++");
16413 }
16414 if($CheckObjectsOnly
16415 and $LibVersion==1) {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040016416 $CheckedSymbols{"Binary"}{$fullname} = 1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040016417 }
16418 }
16419 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040016420 elsif($LIB_TYPE eq "dynamic")
16421 { # dynamic library specifics
16422 if(/NEEDED.+\[([^\[\]]+)\]/)
16423 { # dependencies:
16424 # 0x00000001 (NEEDED) Shared library: [libc.so.6]
16425 $NeededLib{$1} = 1;
16426 }
16427 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040016428 }
16429 close(LIB);
16430 }
16431 if(not $IsNeededLib and $LIB_EXT eq "so")
16432 { # get symbol versions
16433 foreach my $Symbol (keys(%{$Symbol_Library{$LibVersion}}))
16434 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040016435 next if(index($Symbol,"\@")==-1);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040016436 my $Interface_SymName = "";
16437 foreach my $Symbol_SameValue (keys(%{$Value_Interface{$LibVersion}{$Interface_Value{$LibVersion}{$Symbol}}}))
16438 {
16439 if($Symbol_SameValue ne $Symbol
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040016440 and index($Symbol_SameValue,"\@")==-1)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040016441 {
16442 $SymVer{$LibVersion}{$Symbol_SameValue} = $Symbol;
16443 $Interface_SymName = $Symbol_SameValue;
16444 last;
16445 }
16446 }
16447 if(not $Interface_SymName)
16448 {
16449 if($Symbol=~/\A([^\@\$\?]*)[\@\$]+([^\@\$]*)\Z/
16450 and not $SymVer{$LibVersion}{$1}) {
16451 $SymVer{$LibVersion}{$1} = $Symbol;
16452 }
16453 }
16454 }
16455 }
16456 foreach my $DyLib (sort keys(%NeededLib))
16457 {
16458 my $DepPath = find_lib_path($LibVersion, $DyLib);
16459 if($DepPath and -f $DepPath) {
Andrey Ponomarenko16934472012-03-29 15:37:04 +040016460 readSymbols_Lib($LibVersion, $DepPath, 1, $GroupNames, "+Weak");
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040016461 }
16462 }
16463 pop(@RecurLib);
16464 return $Library_Symbol{$LibVersion};
16465}
16466
16467sub get_path_prefixes($)
16468{
16469 my $Path = $_[0];
16470 my ($Dir, $Name) = separate_path($Path);
16471 my %Prefixes = ();
16472 foreach my $Prefix (reverse(split(/[\/\\]+/, $Dir)))
16473 {
16474 $Prefixes{$Name} = 1;
16475 $Name = joinPath($Prefix, $Name);
16476 last if(keys(%Prefixes)>5 or $Prefix eq "include");
16477 }
16478 return keys(%Prefixes);
16479}
16480
16481sub detectSystemHeaders()
16482{
16483 my @SysHeaders = ();
16484 foreach my $DevelPath (keys(%{$SystemPaths{"include"}}))
16485 {
16486 next if(not -d $DevelPath);
16487 # search for all header files in the /usr/include
16488 # with or without extension (ncurses.h, QtCore, ...)
16489 @SysHeaders = (@SysHeaders, cmd_find($DevelPath,"f","",""));
16490 foreach my $Link (cmd_find($DevelPath,"l","",""))
16491 { # add symbolic links
16492 if(-f $Link) {
16493 push(@SysHeaders, $Link);
16494 }
16495 }
16496 }
16497 foreach my $DevelPath (keys(%{$SystemPaths{"lib"}}))
16498 {
16499 next if(not -d $DevelPath);
16500 # search for config headers in the /usr/lib
16501 @SysHeaders = (@SysHeaders, cmd_find($DevelPath,"f","*.h",""));
16502 foreach my $Dir (cmd_find($DevelPath,"d","include",""))
16503 { # search for all include directories
16504 # this is for headers that are installed to /usr/lib
16505 # Example: Qt4 headers in Mandriva (/usr/lib/qt4/include/)
16506 if($Dir=~/\/(gcc|jvm|syslinux|kdb)\//) {
16507 next;
16508 }
16509 @SysHeaders = (@SysHeaders, cmd_find($Dir,"f","",""));
16510 }
16511 }
16512 foreach my $Path (@SysHeaders)
16513 {
16514 foreach my $Part (get_path_prefixes($Path)) {
16515 $SystemHeaders{$Part}{$Path}=1;
16516 }
16517 }
16518}
16519
16520sub detectSystemObjects()
16521{
16522 foreach my $DevelPath (keys(%{$SystemPaths{"lib"}}))
16523 {
16524 next if(not -d $DevelPath);
16525 foreach my $Path (find_libs($DevelPath,"",""))
16526 { # search for shared libraries in the /usr/lib (including symbolic links)
16527 $SystemObjects{parse_libname(get_filename($Path), "name+ext", $OStarget)}{$Path}=1;
16528 }
16529 }
16530}
16531
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040016532sub getSOPaths($)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040016533{
16534 my $LibVersion = $_[0];
16535 my @SoPaths = ();
16536 foreach my $Dest (split(/\s*\n\s*/, $Descriptor{$LibVersion}{"Libs"}))
16537 {
16538 if(not -e $Dest) {
16539 exitStatus("Access_Error", "can't access \'$Dest\'");
16540 }
16541 my @SoPaths_Dest = getSOPaths_Dest($Dest, $LibVersion);
16542 foreach (@SoPaths_Dest) {
16543 push(@SoPaths, $_);
16544 }
16545 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040016546 return sort @SoPaths;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040016547}
16548
16549sub skip_lib($$)
16550{
16551 my ($Path, $LibVersion) = @_;
16552 return 1 if(not $Path or not $LibVersion);
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040016553 my $Name = get_filename($Path);
16554 if($SkipLibs{$LibVersion}{"Name"}{$Name}) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040016555 return 1;
16556 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040016557 my $ShortName = parse_libname($Name, "name+ext", $OStarget);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040016558 if($SkipLibs{$LibVersion}{"Name"}{$ShortName}) {
16559 return 1;
16560 }
16561 foreach my $Dir (keys(%{$SkipLibs{$LibVersion}{"Path"}}))
16562 {
16563 if($Path=~/\Q$Dir\E([\/\\]|\Z)/) {
16564 return 1;
16565 }
16566 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040016567 foreach my $P (keys(%{$SkipLibs{$LibVersion}{"Pattern"}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040016568 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040016569 if($Name=~/$P/) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040016570 return 1;
16571 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040016572 if($P=~/[\/\\]/ and $Path=~/$P/) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040016573 return 1;
16574 }
16575 }
16576 return 0;
16577}
16578
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040016579sub skipHeader($$)
16580{
16581 my ($Path, $LibVersion) = @_;
16582 return 1 if(not $Path or not $LibVersion);
16583 if(not keys(%{$SkipHeaders{$LibVersion}})) {
16584 return 0;
16585 }
16586 if(defined $Cache{"skipHeader"}{$Path}) {
16587 return $Cache{"skipHeader"}{$Path};
16588 }
16589 return ($Cache{"skipHeader"}{$Path} = skipHeader_I(@_));
16590}
16591
16592sub skipHeader_I($$)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040016593{ # returns:
16594 # 1 - if header should NOT be included and checked
16595 # 2 - if header should NOT be included, but should be checked
16596 my ($Path, $LibVersion) = @_;
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040016597 my $Name = get_filename($Path);
16598 if(my $Kind = $SkipHeaders{$LibVersion}{"Name"}{$Name}) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040016599 return $Kind;
16600 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040016601 foreach my $D (keys(%{$SkipHeaders{$LibVersion}{"Path"}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040016602 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040016603 if($Path=~/\Q$D\E([\/\\]|\Z)/) {
16604 return $SkipHeaders{$LibVersion}{"Path"}{$D};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040016605 }
16606 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040016607 foreach my $P (keys(%{$SkipHeaders{$LibVersion}{"Pattern"}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040016608 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040016609 if(my $Kind = $SkipHeaders{$LibVersion}{"Pattern"}{$P})
16610 {
16611 if($Name=~/$P/) {
16612 return $Kind;
16613 }
16614 if($P=~/[\/\\]/ and $Path=~/$P/) {
16615 return $Kind;
16616 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040016617 }
16618 }
16619 return 0;
16620}
16621
16622sub register_objects($$)
16623{
16624 my ($Dir, $LibVersion) = @_;
16625 if($SystemPaths{"lib"}{$Dir})
16626 { # system directory
16627 return;
16628 }
16629 if($RegisteredObjDirs{$LibVersion}{$Dir})
16630 { # already registered
16631 return;
16632 }
16633 foreach my $Path (find_libs($Dir,"",1))
16634 {
16635 next if(ignore_path($Path));
16636 next if(skip_lib($Path, $LibVersion));
16637 $InputObject_Paths{$LibVersion}{get_filename($Path)}{$Path} = 1;
16638 }
16639 $RegisteredObjDirs{$LibVersion}{$Dir} = 1;
16640}
16641
16642sub getSOPaths_Dest($$)
16643{
16644 my ($Dest, $LibVersion) = @_;
16645 if(skip_lib($Dest, $LibVersion)) {
16646 return ();
16647 }
16648 if(-f $Dest)
16649 {
16650 if(not parse_libname($Dest, "name", $OStarget)) {
16651 exitStatus("Error", "incorrect format of library (should be *.$LIB_EXT): \'$Dest\'");
16652 }
16653 $InputObject_Paths{$LibVersion}{get_filename($Dest)}{$Dest} = 1;
16654 register_objects(get_dirname($Dest), $LibVersion);
16655 return ($Dest);
16656 }
16657 elsif(-d $Dest)
16658 {
16659 $Dest=~s/[\/\\]+\Z//g;
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040016660 my %Libs = ();
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040016661 if($SystemPaths{"lib"}{$Dest})
16662 { # you have specified /usr/lib as the search directory (<libs>) in the XML descriptor
16663 # and the real name of the library by -l option (bz2, stdc++, Xaw, ...)
16664 foreach my $Path (cmd_find($Dest,"","*".esc($TargetLibraryName)."*\.$LIB_EXT*",2))
16665 { # all files and symlinks that match the name of a library
16666 if(get_filename($Path)=~/\A(|lib)\Q$TargetLibraryName\E[\d\-]*\.$LIB_EXT[\d\.]*\Z/i)
16667 {
16668 $InputObject_Paths{$LibVersion}{get_filename($Path)}{$Path} = 1;
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040016669 $Libs{resolve_symlink($Path)}=1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040016670 }
16671 }
16672 }
16673 else
16674 { # search for all files and symlinks
16675 foreach my $Path (find_libs($Dest,"",""))
16676 {
16677 next if(ignore_path($Path));
16678 next if(skip_lib($Path, $LibVersion));
16679 $InputObject_Paths{$LibVersion}{get_filename($Path)}{$Path} = 1;
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040016680 $Libs{resolve_symlink($Path)}=1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040016681 }
16682 if($OSgroup eq "macos")
16683 { # shared libraries on MacOS X may have no extension
16684 foreach my $Path (cmd_find($Dest,"f","",""))
16685 {
16686 next if(ignore_path($Path));
16687 next if(skip_lib($Path, $LibVersion));
16688 if(get_filename($Path)!~/\./
Andrey Ponomarenko85043792012-05-14 16:48:07 +040016689 and cmd_file($Path)=~/(shared|dynamic)\s+library/i)
16690 {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040016691 $InputObject_Paths{$LibVersion}{get_filename($Path)}{$Path} = 1;
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040016692 $Libs{resolve_symlink($Path)}=1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040016693 }
16694 }
16695 }
16696 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040016697 return keys(%Libs);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040016698 }
16699 else {
16700 return ();
16701 }
16702}
16703
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040016704sub isCyclical($$)
16705{
16706 my ($Stack, $Value) = @_;
16707 return (grep {$_ eq $Value} @{$Stack});
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040016708}
16709
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040016710sub generateTemplate()
16711{
16712 writeFile("VERSION.xml", $DescriptorTemplate."\n");
16713 printMsg("INFO", "XML-descriptor template ./VERSION.xml has been generated");
16714}
16715
16716sub detectWordSize()
16717{
16718 return "" if(not $GCC_PATH);
16719 if($Cache{"detectWordSize"}) {
16720 return $Cache{"detectWordSize"};
16721 }
16722 writeFile("$TMP_DIR/empty.h", "");
16723 my $Defines = `$GCC_PATH -E -dD $TMP_DIR/empty.h`;
16724 unlink("$TMP_DIR/empty.h");
16725 my $WSize = 0;
16726 if($Defines=~/ __SIZEOF_POINTER__\s+(\d+)/)
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040016727 { # GCC 4
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040016728 $WSize = $1;
16729 }
16730 elsif($Defines=~/ __PTRDIFF_TYPE__\s+(\w+)/)
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040016731 { # GCC 3
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040016732 my $PTRDIFF = $1;
16733 if($PTRDIFF=~/long/) {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040016734 $WSize = "8";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040016735 }
16736 else {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040016737 $WSize = "4";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040016738 }
16739 }
16740 if(not int($WSize)) {
16741 exitStatus("Error", "can't check WORD size");
16742 }
16743 return ($Cache{"detectWordSize"} = $WSize);
16744}
16745
16746sub majorVersion($)
16747{
16748 my $V = $_[0];
16749 return 0 if(not $V);
16750 my @VParts = split(/\./, $V);
16751 return $VParts[0];
16752}
16753
16754sub cmpVersions($$)
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040016755{ # compare two versions in dotted-numeric format
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040016756 my ($V1, $V2) = @_;
16757 return 0 if($V1 eq $V2);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040016758 my @V1Parts = split(/\./, $V1);
16759 my @V2Parts = split(/\./, $V2);
16760 for (my $i = 0; $i <= $#V1Parts && $i <= $#V2Parts; $i++) {
16761 return -1 if(int($V1Parts[$i]) < int($V2Parts[$i]));
16762 return 1 if(int($V1Parts[$i]) > int($V2Parts[$i]));
16763 }
16764 return -1 if($#V1Parts < $#V2Parts);
16765 return 1 if($#V1Parts > $#V2Parts);
16766 return 0;
16767}
16768
16769sub read_ABI_Dump($$)
16770{
16771 my ($LibVersion, $Path) = @_;
16772 return if(not $LibVersion or not -e $Path);
16773 my $FilePath = "";
16774 if($Path=~/\.abi\Z/)
16775 { # input *.abi
16776 $FilePath = $Path;
16777 }
16778 else
16779 { # input *.abi.tar.gz
16780 $FilePath = unpackDump($Path);
16781 }
16782 if($FilePath!~/\.abi\Z/) {
16783 exitStatus("Invalid_Dump", "specified ABI dump \'$Path\' is not valid, try to recreate it");
16784 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +040016785
16786 open(DUMP, $FilePath);
16787 local $/ = undef;
16788 my $Content = <DUMP>;
16789 close(DUMP);
16790
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040016791 if($Path!~/\.abi\Z/)
16792 { # remove temp file
16793 unlink($FilePath);
16794 }
16795 if($Content!~/};\s*\Z/) {
16796 exitStatus("Invalid_Dump", "specified ABI dump \'$Path\' is not valid, try to recreate it");
16797 }
16798 my $LibraryABI = eval($Content);
16799 if(not $LibraryABI) {
16800 exitStatus("Error", "internal error - eval() procedure seem to not working correctly, try to remove 'use strict' and try again");
16801 }
16802 # new dumps (>=1.22) have a personal versioning
16803 my $DumpVersion = $LibraryABI->{"ABI_DUMP_VERSION"};
16804 my $ToolVersion = $LibraryABI->{"ABI_COMPLIANCE_CHECKER_VERSION"};
16805 if(not $DumpVersion)
16806 { # old dumps (<=1.21.6) have been marked by the tool version
16807 $DumpVersion = $ToolVersion;
16808 }
16809 $UsedDump{$LibVersion}{"V"} = $DumpVersion;
16810 if(majorVersion($DumpVersion) ne majorVersion($ABI_DUMP_VERSION))
16811 { # should be compatible with dumps of the same major version
16812 if(cmpVersions($DumpVersion, $ABI_DUMP_VERSION)>0)
16813 { # Don't know how to parse future dump formats
16814 exitStatus("Dump_Version", "incompatible version $DumpVersion of specified ABI dump (newer than $ABI_DUMP_VERSION)");
16815 }
16816 elsif(cmpVersions($DumpVersion, $TOOL_VERSION)>0 and not $LibraryABI->{"ABI_DUMP_VERSION"})
16817 { # Don't know how to parse future dump formats
16818 exitStatus("Dump_Version", "incompatible version $DumpVersion of specified ABI dump (newer than $TOOL_VERSION)");
16819 }
16820 if($UseOldDumps)
16821 {
16822 if(cmpVersions($DumpVersion, $OLDEST_SUPPORTED_VERSION)<0) {
16823 exitStatus("Dump_Version", "incompatible version $DumpVersion of specified ABI dump (older than $OLDEST_SUPPORTED_VERSION)");
16824 }
16825 }
16826 else
16827 {
16828 my $Msg = "incompatible version $DumpVersion of specified ABI dump (allowed only ".majorVersion($ABI_DUMP_VERSION).".0<=V<=$ABI_DUMP_VERSION)";
16829 if(cmpVersions($DumpVersion, $OLDEST_SUPPORTED_VERSION)>=0) {
16830 $Msg .= "\nUse -old-dumps option to use old-version dumps ($OLDEST_SUPPORTED_VERSION<=V<".majorVersion($ABI_DUMP_VERSION).".0)";
16831 }
16832 exitStatus("Dump_Version", $Msg);
16833 }
16834 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040016835 if($LibraryABI->{"SrcBin"})
16836 { # default
16837 $UsedDump{$LibVersion}{"SrcBin"} = 1;
16838 }
16839 elsif($LibraryABI->{"BinOnly"})
16840 { # ABI dump created with --binary option
16841 $UsedDump{$LibVersion}{"BinOnly"} = 1;
16842 }
Andrey Ponomarenko16934472012-03-29 15:37:04 +040016843 if(defined $LibraryABI->{"Mode"}
16844 and $LibraryABI->{"Mode"} eq "Extended")
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040016845 { # --ext option
16846 $ExtendedCheck = 1;
16847 }
16848 if(my $Lang = $LibraryABI->{"Language"})
16849 {
16850 $UsedDump{$LibVersion}{"L"} = $Lang;
16851 setLanguage($LibVersion, $Lang);
16852 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040016853 if(checkDump($LibVersion, "2.15")) {
16854 $TypeInfo{$LibVersion} = $LibraryABI->{"TypeInfo"};
16855 }
16856 else
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040016857 { # support for old ABI dumps
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040016858 my $TInfo = $LibraryABI->{"TypeInfo"};
16859 if(not $TInfo)
16860 { # support for older ABI dumps
16861 $TInfo = $LibraryABI->{"TypeDescr"};
16862 }
16863 my %Tid_TDid = ();
16864 foreach my $TDid (keys(%{$TInfo}))
16865 {
16866 foreach my $Tid (keys(%{$TInfo->{$TDid}}))
16867 {
16868 $MAX_ID = $Tid if($Tid>$MAX_ID);
16869 $MAX_ID = $TDid if($TDid and $TDid>$MAX_ID);
16870 $Tid_TDid{$Tid}{$TDid}=1;
16871 }
16872 }
16873 my %NewID = ();
16874 foreach my $Tid (keys(%Tid_TDid))
16875 {
16876 my @TDids = keys(%{$Tid_TDid{$Tid}});
16877 if($#TDids>=1)
16878 {
16879 foreach my $TDid (@TDids)
16880 {
16881 if($TDid) {
16882 %{$TypeInfo{$LibVersion}{$Tid}} = %{$TInfo->{$TDid}{$Tid}};
16883 }
16884 else
16885 {
16886 if(my $ID = ++$MAX_ID)
16887 {
16888 $NewID{$TDid}{$Tid} = $ID;
16889 %{$TypeInfo{$LibVersion}{$ID}} = %{$TInfo->{$TDid}{$Tid}};
16890 $TypeInfo{$LibVersion}{$ID}{"Tid"} = $ID;
16891 }
16892 }
16893 }
16894 }
16895 else
16896 {
16897 my $TDid = $TDids[0];
16898 %{$TypeInfo{$LibVersion}{$Tid}} = %{$TInfo->{$TDid}{$Tid}};
16899 }
16900 }
16901 foreach my $Tid (keys(%{$TypeInfo{$LibVersion}}))
16902 {
16903 my %Info = %{$TypeInfo{$LibVersion}{$Tid}};
16904 if(defined $Info{"BaseType"})
16905 {
16906 my $Bid = $Info{"BaseType"}{"Tid"};
16907 my $BDid = $Info{"BaseType"}{"TDid"};
16908 $BDid="" if(not defined $BDid);
16909 if(defined $NewID{$BDid} and my $ID = $NewID{$BDid}{$Bid}) {
16910 $TypeInfo{$LibVersion}{$Tid}{"BaseType"}{"Tid"} = $ID;
16911 }
16912 delete($TypeInfo{$LibVersion}{$Tid}{"BaseType"}{"TDid"});
16913 }
16914 delete($TypeInfo{$LibVersion}{$Tid}{"TDid"});
16915 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040016916 }
16917 read_Machine_DumpInfo($LibraryABI, $LibVersion);
16918 $SymbolInfo{$LibVersion} = $LibraryABI->{"SymbolInfo"};
16919 if(not $SymbolInfo{$LibVersion})
16920 { # support for old dumps
16921 $SymbolInfo{$LibVersion} = $LibraryABI->{"FuncDescr"};
16922 }
16923 if(not keys(%{$SymbolInfo{$LibVersion}}))
16924 { # validation of old-version dumps
16925 if(not $ExtendedCheck) {
16926 exitStatus("Invalid_Dump", "the input dump d$LibVersion is invalid");
16927 }
16928 }
16929 $Library_Symbol{$LibVersion} = $LibraryABI->{"Symbols"};
16930 if(not $Library_Symbol{$LibVersion})
16931 { # support for old dumps
16932 $Library_Symbol{$LibVersion} = $LibraryABI->{"Interfaces"};
16933 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040016934 if(checkDump($LibVersion, "2.15")) {
16935 $DepLibrary_Symbol{$LibVersion} = $LibraryABI->{"DepSymbols"};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040016936 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040016937 else
16938 { # support for old ABI dumps
16939 my $DepSymbols = $LibraryABI->{"DepSymbols"};
16940 if(not $DepSymbols) {
16941 $DepSymbols = $LibraryABI->{"DepInterfaces"};
16942 }
16943 if(not $DepSymbols)
16944 { # Cannot reconstruct DepSymbols. This may result in false
16945 # positives if the old dump is for library 2. Not a problem if
16946 # old dumps are only from old libraries.
16947 $DepSymbols = {};
16948 }
16949 foreach my $Symbol (keys(%{$DepSymbols})) {
16950 $DepSymbol_Library{$LibVersion}{$Symbol} = 1;
16951 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040016952 }
16953 $SymVer{$LibVersion} = $LibraryABI->{"SymbolVersion"};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040016954 $Descriptor{$LibVersion}{"Version"} = $LibraryABI->{"LibraryVersion"};
16955 $SkipTypes{$LibVersion} = $LibraryABI->{"SkipTypes"};
16956 if(not $SkipTypes{$LibVersion})
16957 { # support for old dumps
16958 $SkipTypes{$LibVersion} = $LibraryABI->{"OpaqueTypes"};
16959 }
16960 $SkipSymbols{$LibVersion} = $LibraryABI->{"SkipSymbols"};
16961 if(not $SkipSymbols{$LibVersion})
16962 { # support for old dumps
16963 $SkipSymbols{$LibVersion} = $LibraryABI->{"SkipInterfaces"};
16964 }
16965 if(not $SkipSymbols{$LibVersion})
16966 { # support for old dumps
16967 $SkipSymbols{$LibVersion} = $LibraryABI->{"InternalInterfaces"};
16968 }
16969 $SkipNameSpaces{$LibVersion} = $LibraryABI->{"SkipNameSpaces"};
16970 $TargetHeaders{$LibVersion} = $LibraryABI->{"TargetHeaders"};
16971 foreach my $Path (keys(%{$LibraryABI->{"SkipHeaders"}}))
16972 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040016973 $SkipHeadersList{$LibVersion}{$Path} = $LibraryABI->{"SkipHeaders"}{$Path};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040016974 my ($CPath, $Type) = classifyPath($Path);
16975 $SkipHeaders{$LibVersion}{$Type}{$CPath} = $LibraryABI->{"SkipHeaders"}{$Path};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040016976 }
16977 read_Headers_DumpInfo($LibraryABI, $LibVersion);
16978 read_Libs_DumpInfo($LibraryABI, $LibVersion);
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040016979 if(not checkDump($LibVersion, "2.10.1"))
Andrey Ponomarenko85043792012-05-14 16:48:07 +040016980 { # support for old ABI dumps: added target headers
16981 foreach (keys(%{$Registered_Headers{$LibVersion}})) {
16982 $TargetHeaders{$LibVersion}{get_filename($_)}=1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040016983 }
16984 }
16985 $Constants{$LibVersion} = $LibraryABI->{"Constants"};
16986 $NestedNameSpaces{$LibVersion} = $LibraryABI->{"NameSpaces"};
16987 if(not $NestedNameSpaces{$LibVersion})
16988 { # support for old dumps
16989 # Cannot reconstruct NameSpaces. This may affect design
16990 # of the compatibility report.
16991 $NestedNameSpaces{$LibVersion} = {};
16992 }
16993 # target system type
16994 # needed to adopt HTML report
16995 if(not $DumpSystem)
16996 { # to use in createSymbolsList(...)
16997 $OStarget = $LibraryABI->{"Target"};
16998 }
16999 # recreate environment
17000 foreach my $Lib_Name (keys(%{$Library_Symbol{$LibVersion}}))
17001 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040017002 foreach my $Symbol (keys(%{$Library_Symbol{$LibVersion}{$Lib_Name}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017003 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040017004 $Symbol_Library{$LibVersion}{$Symbol} = $Lib_Name;
17005 if($Library_Symbol{$LibVersion}{$Lib_Name}{$Symbol}<=-1)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017006 { # data marked as -size in the dump
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040017007 $GlobalDataObject{$LibVersion}{$Symbol}=1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017008 }
17009 if($COMMON_LANGUAGE{$LibVersion} ne "C++"
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040017010 and $Symbol=~/\A(_Z|\?)/) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017011 setLanguage($LibVersion, "C++");
17012 }
17013 }
17014 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040017015 foreach my $Lib_Name (keys(%{$DepLibrary_Symbol{$LibVersion}}))
17016 {
17017 foreach my $Symbol (keys(%{$DepLibrary_Symbol{$LibVersion}{$Lib_Name}})) {
17018 $DepSymbol_Library{$LibVersion}{$Symbol} = $Lib_Name;
17019 }
17020 }
17021
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017022 my @VFunc = ();
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040017023 foreach my $InfoId (keys(%{$SymbolInfo{$LibVersion}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017024 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040017025 my $MnglName = $SymbolInfo{$LibVersion}{$InfoId}{"MnglName"};
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040017026 if($MnglName)
17027 {
17028 if(not $Symbol_Library{$LibVersion}{$MnglName}
17029 and not $DepSymbol_Library{$LibVersion}{$MnglName}) {
17030 push(@VFunc, $MnglName);
17031 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017032 }
17033 }
17034 translateSymbols(@VFunc, $LibVersion);
17035 translateSymbols(keys(%{$Symbol_Library{$LibVersion}}), $LibVersion);
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040017036 translateSymbols(keys(%{$DepSymbol_Library{$LibVersion}}), $LibVersion);
17037
17038 foreach my $TypeId (sort {int($a)<=>int($b)} keys(%{$TypeInfo{$LibVersion}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017039 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040017040 if(defined $TypeInfo{$LibVersion}{$TypeId}{"BaseClass"})
17041 { # support for old ABI dumps < 2.0 (ACC 1.22)
17042 foreach my $BId (keys(%{$TypeInfo{$LibVersion}{$TypeId}{"BaseClass"}}))
17043 {
17044 if(my $Access = $TypeInfo{$LibVersion}{$TypeId}{"BaseClass"}{$BId})
17045 {
17046 if($Access ne "public") {
17047 $TypeInfo{$LibVersion}{$TypeId}{"Base"}{$BId}{"access"} = $Access;
17048 }
17049 }
17050 $TypeInfo{$LibVersion}{$TypeId}{"Base"}{$BId} = {};
17051 }
17052 delete($TypeInfo{$LibVersion}{$TypeId}{"BaseClass"});
17053 }
17054 my %TInfo = %{$TypeInfo{$LibVersion}{$TypeId}};
17055 if(defined $TInfo{"Base"})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017056 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040017057 foreach (keys(%{$TInfo{"Base"}})) {
17058 $Class_SubClasses{$LibVersion}{$_}{$TypeId}=1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017059 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040017060 }
17061 if($TInfo{"Type"} eq "Typedef" and defined $TInfo{"BaseType"})
17062 {
17063 if(my $BTid = $TInfo{"BaseType"}{"Tid"})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017064 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040017065 my $BName = $TypeInfo{$LibVersion}{$BTid}{"Name"};
17066 if(not $BName)
17067 { # broken type
17068 next;
17069 }
17070 if($TInfo{"Name"} eq $BName)
17071 { # typedef to "class Class"
17072 # should not be registered in TName_Tid
17073 next;
17074 }
17075 if(not $Typedef_BaseName{$LibVersion}{$TInfo{"Name"}}) {
17076 $Typedef_BaseName{$LibVersion}{$TInfo{"Name"}} = $BName;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017077 }
17078 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040017079 }
17080 if(not $TName_Tid{$LibVersion}{$TInfo{"Name"}})
17081 { # classes: class (id1), typedef (artificial, id2 > id1)
17082 $TName_Tid{$LibVersion}{$TInfo{"Name"}} = $TypeId;
17083 }
17084 }
17085
17086 if(not checkDump($LibVersion, "2.15"))
17087 { # support for old ABI dumps
17088 my %Dups = ();
17089 foreach my $InfoId (keys(%{$SymbolInfo{$LibVersion}}))
17090 {
17091 if(my $ClassId = $SymbolInfo{$LibVersion}{$InfoId}{"Class"})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017092 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040017093 if(not defined $TypeInfo{$LibVersion}{$ClassId})
17094 { # remove template decls
17095 delete($SymbolInfo{$LibVersion}{$InfoId});
17096 next;
Andrey Ponomarenko16934472012-03-29 15:37:04 +040017097 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017098 }
Andrey Ponomarenkob8d203d2012-05-25 18:11:07 +040017099 my $MName = $SymbolInfo{$LibVersion}{$InfoId}{"MnglName"};
17100 if(not $MName and $SymbolInfo{$LibVersion}{$InfoId}{"Class"})
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040017101 { # templates
17102 delete($SymbolInfo{$LibVersion}{$InfoId});
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017103 }
17104 }
17105 }
17106
17107 $Descriptor{$LibVersion}{"Dump"} = 1;
17108}
17109
17110sub read_Machine_DumpInfo($$)
17111{
17112 my ($LibraryABI, $LibVersion) = @_;
17113 if($LibraryABI->{"Arch"}) {
17114 $CPU_ARCH{$LibVersion} = $LibraryABI->{"Arch"};
17115 }
17116 if($LibraryABI->{"WordSize"}) {
17117 $WORD_SIZE{$LibVersion} = $LibraryABI->{"WordSize"};
17118 }
17119 else
17120 { # support for old dumps
17121 $WORD_SIZE{$LibVersion} = $LibraryABI->{"SizeOfPointer"};
17122 }
17123 if(not $WORD_SIZE{$LibVersion})
17124 { # support for old dumps (<1.23)
17125 if(my $Tid = getTypeIdByName("char*", $LibVersion))
17126 { # size of char*
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040017127 $WORD_SIZE{$LibVersion} = $TypeInfo{$LibVersion}{$Tid}{"Size"};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017128 }
17129 else
17130 {
17131 my $PSize = 0;
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040017132 foreach my $Tid (keys(%{$TypeInfo{$LibVersion}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017133 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040017134 if($TypeInfo{$LibVersion}{$Tid}{"Type"} eq "Pointer")
17135 { # any "pointer"-type
17136 $PSize = $TypeInfo{$LibVersion}{$Tid}{"Size"};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017137 last;
17138 }
17139 }
17140 if($PSize)
17141 { # a pointer type size
17142 $WORD_SIZE{$LibVersion} = $PSize;
17143 }
17144 else {
17145 printMsg("WARNING", "cannot identify a WORD size in the ABI dump (too old format)");
17146 }
17147 }
17148 }
17149 if($LibraryABI->{"GccVersion"}) {
17150 $GCC_VERSION{$LibVersion} = $LibraryABI->{"GccVersion"};
17151 }
17152}
17153
17154sub read_Libs_DumpInfo($$)
17155{
17156 my ($LibraryABI, $LibVersion) = @_;
17157 if(keys(%{$Library_Symbol{$LibVersion}})
17158 and not $DumpAPI) {
17159 $Descriptor{$LibVersion}{"Libs"} = "OK";
17160 }
17161}
17162
17163sub read_Headers_DumpInfo($$)
17164{
17165 my ($LibraryABI, $LibVersion) = @_;
17166 if(keys(%{$LibraryABI->{"Headers"}})
17167 and not $DumpAPI) {
17168 $Descriptor{$LibVersion}{"Headers"} = "OK";
17169 }
17170 foreach my $Identity (keys(%{$LibraryABI->{"Headers"}}))
17171 { # headers info is stored in the old dumps in the different way
17172 if($UseOldDumps
17173 and my $Name = $LibraryABI->{"Headers"}{$Identity}{"Name"})
17174 { # support for old dumps: headers info corrected in 1.22
17175 $Identity = $Name;
17176 }
17177 $Registered_Headers{$LibVersion}{$Identity}{"Identity"} = $Identity;
17178 }
17179}
17180
17181sub find_libs($$$)
17182{
17183 my ($Path, $Type, $MaxDepth) = @_;
17184 # FIXME: correct the search pattern
17185 return cmd_find($Path, $Type, ".*\\.$LIB_EXT\[0-9.]*", $MaxDepth);
17186}
17187
17188sub createDescriptor($$)
17189{
17190 my ($LibVersion, $Path) = @_;
17191 if(not $LibVersion or not $Path
17192 or not -e $Path) {
17193 return "";
17194 }
17195 if(-d $Path)
17196 { # directory with headers files and shared objects
17197 return "
17198 <version>
17199 ".$TargetVersion{$LibVersion}."
17200 </version>
17201
17202 <headers>
17203 $Path
17204 </headers>
17205
17206 <libs>
17207 $Path
17208 </libs>";
17209 }
17210 else
17211 { # files
17212 if($Path=~/\.xml\Z/i)
17213 { # standard XML-descriptor
17214 return readFile($Path);
17215 }
17216 elsif(is_header($Path, 2, $LibVersion))
17217 { # header file
17218 return "
17219 <version>
17220 ".$TargetVersion{$LibVersion}."
17221 </version>
17222
17223 <headers>
17224 $Path
17225 </headers>
17226
17227 <libs>
17228 none
17229 </libs>";
17230 }
17231 elsif(parse_libname($Path, "name", $OStarget))
17232 { # shared object
17233 return "
17234 <version>
17235 ".$TargetVersion{$LibVersion}."
17236 </version>
17237
17238 <headers>
17239 none
17240 </headers>
17241
17242 <libs>
17243 $Path
17244 </libs>";
17245 }
17246 else
17247 { # standard XML-descriptor
17248 return readFile($Path);
17249 }
17250 }
17251}
17252
17253sub detect_lib_default_paths()
17254{
17255 my %LPaths = ();
17256 if($OSgroup eq "bsd")
17257 {
17258 if(my $LdConfig = get_CmdPath("ldconfig")) {
17259 foreach my $Line (split(/\n/, `$LdConfig -r 2>$TMP_DIR/null`)) {
17260 if($Line=~/\A[ \t]*\d+:\-l(.+) \=\> (.+)\Z/) {
17261 $LPaths{"lib".$1} = $2;
17262 }
17263 }
17264 }
17265 else {
17266 printMsg("WARNING", "can't find ldconfig");
17267 }
17268 }
17269 else
17270 {
17271 if(my $LdConfig = get_CmdPath("ldconfig"))
17272 {
17273 if($SystemRoot and $OSgroup eq "linux")
17274 { # use host (x86) ldconfig with the target (arm) ld.so.conf
17275 if(-e $SystemRoot."/etc/ld.so.conf") {
17276 $LdConfig .= " -f ".$SystemRoot."/etc/ld.so.conf";
17277 }
17278 }
17279 foreach my $Line (split(/\n/, `$LdConfig -p 2>$TMP_DIR/null`)) {
17280 if($Line=~/\A[ \t]*([^ \t]+) .* \=\> (.+)\Z/)
17281 {
17282 my ($Name, $Path) = ($1, $2);
17283 $Path=~s/[\/]{2,}/\//;
17284 $LPaths{$Name} = $Path;
17285 }
17286 }
17287 }
17288 elsif($OSgroup=~/linux/i) {
17289 printMsg("WARNING", "can't find ldconfig");
17290 }
17291 }
17292 return \%LPaths;
17293}
17294
17295sub detect_bin_default_paths()
17296{
17297 my $EnvPaths = $ENV{"PATH"};
17298 if($OSgroup eq "beos") {
17299 $EnvPaths.=":".$ENV{"BETOOLS"};
17300 }
17301 my $Sep = ($OSgroup eq "windows")?";":":|;";
17302 foreach my $Path (sort {length($a)<=>length($b)} split(/$Sep/, $EnvPaths))
17303 {
17304 $Path = path_format($Path, $OSgroup);
17305 $Path=~s/[\/\\]+\Z//g;
17306 next if(not $Path);
17307 if($SystemRoot
17308 and $Path=~/\A\Q$SystemRoot\E\//)
17309 { # do NOT use binaries from target system
17310 next;
17311 }
17312 $DefaultBinPaths{$Path} = 1;
17313 }
17314}
17315
17316sub detect_inc_default_paths()
17317{
17318 return () if(not $GCC_PATH);
17319 my %DPaths = ("Cpp"=>{},"Gcc"=>{},"Inc"=>{});
17320 writeFile("$TMP_DIR/empty.h", "");
17321 foreach my $Line (split(/\n/, `$GCC_PATH -v -x c++ -E "$TMP_DIR/empty.h" 2>&1`))
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040017322 { # detecting GCC default include paths
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017323 if($Line=~/\A[ \t]*((\/|\w+:\\).+)[ \t]*\Z/)
17324 {
17325 my $Path = simplify_path($1);
17326 $Path=~s/[\/\\]+\Z//g;
17327 $Path = path_format($Path, $OSgroup);
17328 if($Path=~/c\+\+|\/g\+\+\//)
17329 {
17330 $DPaths{"Cpp"}{$Path}=1;
17331 if(not defined $MAIN_CPP_DIR
17332 or get_depth($MAIN_CPP_DIR)>get_depth($Path)) {
17333 $MAIN_CPP_DIR = $Path;
17334 }
17335 }
17336 elsif($Path=~/gcc/) {
17337 $DPaths{"Gcc"}{$Path}=1;
17338 }
17339 else
17340 {
17341 next if($Path=~/local[\/\\]+include/);
17342 if($SystemRoot
17343 and $Path!~/\A\Q$SystemRoot\E(\/|\Z)/)
17344 { # The GCC include path for user headers is not a part of the system root
17345 # The reason: you are not specified the --cross-gcc option or selected a wrong compiler
17346 # or it is the internal cross-GCC path like arm-linux-gnueabi/include
17347 next;
17348 }
17349 $DPaths{"Inc"}{$Path}=1;
17350 }
17351 }
17352 }
17353 unlink("$TMP_DIR/empty.h");
17354 return %DPaths;
17355}
17356
17357sub detect_default_paths($)
17358{
17359 my ($HSearch, $LSearch, $BSearch, $GSearch) = (1, 1, 1, 1);
17360 my $Search = $_[0];
17361 if($Search!~/inc/) {
17362 $HSearch = 0;
17363 }
17364 if($Search!~/lib/) {
17365 $LSearch = 0;
17366 }
17367 if($Search!~/bin/) {
17368 $BSearch = 0;
17369 }
17370 if($Search!~/gcc/) {
17371 $GSearch = 0;
17372 }
17373 if(keys(%{$SystemPaths{"include"}}))
17374 { # <search_headers> section of the XML descriptor
17375 # do NOT search for systems headers
17376 $HSearch = 0;
17377 }
17378 if(keys(%{$SystemPaths{"lib"}}))
17379 { # <search_headers> section of the XML descriptor
17380 # do NOT search for systems headers
17381 $LSearch = 0;
17382 }
17383 foreach my $Type (keys(%{$OS_AddPath{$OSgroup}}))
17384 { # additional search paths
17385 next if($Type eq "include" and not $HSearch);
17386 next if($Type eq "lib" and not $LSearch);
17387 next if($Type eq "bin" and not $BSearch);
17388 foreach my $Path (keys(%{$OS_AddPath{$OSgroup}{$Type}}))
17389 {
17390 next if(not -d $Path);
17391 $SystemPaths{$Type}{$Path} = $OS_AddPath{$OSgroup}{$Type}{$Path};
17392 }
17393 }
17394 if($OSgroup ne "windows")
17395 { # unix-like
17396 foreach my $Type ("include", "lib", "bin")
17397 { # automatic detection of system "devel" directories
17398 next if($Type eq "include" and not $HSearch);
17399 next if($Type eq "lib" and not $LSearch);
17400 next if($Type eq "bin" and not $BSearch);
17401 my ($UsrDir, $RootDir) = ("/usr", "/");
17402 if($SystemRoot and $Type ne "bin")
17403 { # 1. search for target headers and libraries
17404 # 2. use host commands: ldconfig, readelf, etc.
17405 ($UsrDir, $RootDir) = ("$SystemRoot/usr", $SystemRoot);
17406 }
17407 foreach my $Path (cmd_find($RootDir,"d","*$Type*",1)) {
17408 $SystemPaths{$Type}{$Path} = 1;
17409 }
17410 if(-d $RootDir."/".$Type)
17411 { # if "/lib" is symbolic link
17412 if($RootDir eq "/") {
17413 $SystemPaths{$Type}{"/".$Type} = 1;
17414 }
17415 else {
17416 $SystemPaths{$Type}{$RootDir."/".$Type} = 1;
17417 }
17418 }
17419 if(-d $UsrDir) {
17420 foreach my $Path (cmd_find($UsrDir,"d","*$Type*",1)) {
17421 $SystemPaths{$Type}{$Path} = 1;
17422 }
17423 if(-d $UsrDir."/".$Type)
17424 { # if "/usr/lib" is symbolic link
17425 $SystemPaths{$Type}{$UsrDir."/".$Type} = 1;
17426 }
17427 }
17428 }
17429 }
17430 if($BSearch)
17431 {
17432 detect_bin_default_paths();
17433 foreach my $Path (keys(%DefaultBinPaths)) {
17434 $SystemPaths{"bin"}{$Path} = $DefaultBinPaths{$Path};
17435 }
17436 }
17437 # check environment variables
17438 if($OSgroup eq "beos")
17439 {
17440 foreach (keys(%{$SystemPaths{"bin"}}))
17441 {
17442 if($_ eq ".") {
17443 next;
17444 }
17445 foreach my $Path (cmd_find($_, "d", "bin", ""))
17446 { # search for /boot/develop/abi/x86/gcc4/tools/gcc-4.4.4-haiku-101111/bin/
17447 $SystemPaths{"bin"}{$Path} = 1;
17448 }
17449 }
17450 if($HSearch)
17451 {
17452 foreach my $Path (split(/:|;/, $ENV{"BEINCLUDES"}))
17453 {
17454 if(is_abs($Path)) {
17455 $DefaultIncPaths{$Path} = 1;
17456 }
17457 }
17458 }
17459 if($LSearch)
17460 {
17461 foreach my $Path (split(/:|;/, $ENV{"BELIBRARIES"}), split(/:|;/, $ENV{"LIBRARY_PATH"}))
17462 {
17463 if(is_abs($Path)) {
17464 $DefaultLibPaths{$Path} = 1;
17465 }
17466 }
17467 }
17468 }
17469 if($LSearch)
17470 { # using linker to get system paths
17471 if(my $LPaths = detect_lib_default_paths())
17472 { # unix-like
17473 foreach my $Name (keys(%{$LPaths}))
17474 {
17475 if($SystemRoot
17476 and $LPaths->{$Name}!~/\A\Q$SystemRoot\E\//)
17477 { # wrong ldconfig configuration
17478 # check your <sysroot>/etc/ld.so.conf
17479 next;
17480 }
17481 $DyLib_DefaultPath{$Name} = $LPaths->{$Name};
17482 $DefaultLibPaths{get_dirname($LPaths->{$Name})} = 1;
17483 }
17484 }
17485 foreach my $Path (keys(%DefaultLibPaths)) {
17486 $SystemPaths{"lib"}{$Path} = $DefaultLibPaths{$Path};
17487 }
17488 }
17489 if($BSearch)
17490 {
17491 if($CrossGcc)
17492 { # --cross-gcc=arm-linux-gcc
17493 if(-e $CrossGcc)
17494 { # absolute or relative path
17495 $GCC_PATH = get_abs_path($CrossGcc);
17496 }
17497 elsif($CrossGcc!~/\// and get_CmdPath($CrossGcc))
17498 { # command name
17499 $GCC_PATH = $CrossGcc;
17500 }
17501 else {
17502 exitStatus("Access_Error", "can't access \'$CrossGcc\'");
17503 }
17504 if($GCC_PATH=~/\s/) {
17505 $GCC_PATH = "\"".$GCC_PATH."\"";
17506 }
17507 }
17508 }
17509 if($GSearch)
17510 { # GCC path and default include dirs
17511 if(not $CrossGcc) {
17512 $GCC_PATH = get_CmdPath("gcc");
17513 }
17514 if(not $GCC_PATH) {
17515 exitStatus("Not_Found", "can't find GCC>=3.0 in PATH");
17516 }
17517 if(not $CheckObjectsOnly_Opt)
17518 {
17519 if(my $GCC_Ver = get_dumpversion($GCC_PATH))
17520 {
17521 my $GccTarget = get_dumpmachine($GCC_PATH);
17522 printMsg("INFO", "Using GCC $GCC_Ver ($GccTarget)");
17523 if($GccTarget=~/symbian/)
17524 {
17525 $OStarget = "symbian";
17526 $LIB_EXT = $OS_LibExt{$LIB_TYPE}{$OStarget};
17527 }
17528 }
17529 else {
17530 exitStatus("Error", "something is going wrong with the GCC compiler");
17531 }
17532 }
17533 if(not $NoStdInc)
17534 { # do NOT search in GCC standard paths
17535 my %DPaths = detect_inc_default_paths();
17536 %DefaultCppPaths = %{$DPaths{"Cpp"}};
17537 %DefaultGccPaths = %{$DPaths{"Gcc"}};
17538 %DefaultIncPaths = %{$DPaths{"Inc"}};
17539 foreach my $Path (keys(%DefaultIncPaths)) {
17540 $SystemPaths{"include"}{$Path} = $DefaultIncPaths{$Path};
17541 }
17542 }
17543 }
17544 if($HSearch)
17545 { # user include paths
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040017546 my $IncPath = "/usr/include";
17547 if($SystemRoot) {
17548 $IncPath = $SystemRoot.$IncPath;
17549 }
17550 if(-d $IncPath) {
17551 $UserIncPath{$IncPath}=1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017552 }
17553 }
17554}
17555
17556sub getLIB_EXT($)
17557{
17558 my $Target = $_[0];
17559 if(my $Ext = $OS_LibExt{$LIB_TYPE}{$Target}) {
17560 return $Ext;
17561 }
17562 return $OS_LibExt{$LIB_TYPE}{"default"};
17563}
17564
17565sub getAR_EXT($)
17566{
17567 my $Target = $_[0];
17568 if(my $Ext = $OS_Archive{$Target}) {
17569 return $Ext;
17570 }
17571 return $OS_Archive{"default"};
17572}
17573
17574sub get_dumpversion($)
17575{
17576 my $Cmd = $_[0];
17577 return "" if(not $Cmd);
17578 if($Cache{"get_dumpversion"}{$Cmd}) {
17579 return $Cache{"get_dumpversion"}{$Cmd};
17580 }
17581 my $V = `$Cmd -dumpversion 2>$TMP_DIR/null`;
17582 chomp($V);
17583 return ($Cache{"get_dumpversion"}{$Cmd} = $V);
17584}
17585
17586sub get_dumpmachine($)
17587{
17588 my $Cmd = $_[0];
17589 return "" if(not $Cmd);
17590 if($Cache{"get_dumpmachine"}{$Cmd}) {
17591 return $Cache{"get_dumpmachine"}{$Cmd};
17592 }
17593 my $Machine = `$Cmd -dumpmachine 2>$TMP_DIR/null`;
17594 chomp($Machine);
17595 return ($Cache{"get_dumpmachine"}{$Cmd} = $Machine);
17596}
17597
17598sub check_command($)
17599{
17600 my $Cmd = $_[0];
17601 return "" if(not $Cmd);
17602 my @Options = (
17603 "--version",
17604 "-help"
17605 );
17606 foreach my $Opt (@Options)
17607 {
17608 my $Info = `$Cmd $Opt 2>$TMP_DIR/null`;
17609 if($Info) {
17610 return 1;
17611 }
17612 }
17613 return 0;
17614}
17615
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040017616sub check_gcc($$)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017617{
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040017618 my ($Cmd, $ReqVer) = @_;
17619 return 0 if(not $Cmd or not $ReqVer);
17620 if(defined $Cache{"check_gcc"}{$Cmd}{$ReqVer}) {
17621 return $Cache{"check_gcc"}{$Cmd}{$ReqVer};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017622 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040017623 if(my $GccVer = get_dumpversion($Cmd))
17624 {
17625 $GccVer=~s/(-|_)[a-z_]+.*\Z//; # remove suffix (like "-haiku-100818")
17626 if(cmpVersions($GccVer, $ReqVer)>=0) {
17627 return ($Cache{"check_gcc"}{$Cmd}{$ReqVer} = $Cmd);
17628 }
17629 }
17630 return ($Cache{"check_gcc"}{$Cmd}{$ReqVer} = "");
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017631}
17632
17633sub get_depth($)
17634{
17635 if(defined $Cache{"get_depth"}{$_[0]}) {
17636 return $Cache{"get_depth"}{$_[0]}
17637 }
17638 return ($Cache{"get_depth"}{$_[0]} = ($_[0]=~tr![\/\\]|\:\:!!));
17639}
17640
17641sub find_gcc_cxx_headers($)
17642{
17643 my $LibVersion = $_[0];
17644 return if($Cache{"find_gcc_cxx_headers"});# this function should be called once
17645 # detecting system header paths
17646 foreach my $Path (sort {get_depth($b) <=> get_depth($a)} keys(%DefaultGccPaths))
17647 {
17648 foreach my $HeaderPath (sort {get_depth($a) <=> get_depth($b)} cmd_find($Path,"f","",""))
17649 {
17650 my $FileName = get_filename($HeaderPath);
17651 next if($DefaultGccHeader{$FileName});
17652 $DefaultGccHeader{$FileName} = $HeaderPath;
17653 }
17654 }
17655 if($COMMON_LANGUAGE{$LibVersion} eq "C++" and not $STDCXX_TESTING)
17656 {
17657 foreach my $CppDir (sort {get_depth($b)<=>get_depth($a)} keys(%DefaultCppPaths))
17658 {
17659 my @AllCppHeaders = cmd_find($CppDir,"f","","");
17660 foreach my $Path (sort {get_depth($a)<=>get_depth($b)} @AllCppHeaders)
17661 {
17662 my $FileName = get_filename($Path);
17663 next if($DefaultCppHeader{$FileName});
17664 $DefaultCppHeader{$FileName} = $Path;
17665 }
17666 }
17667 }
17668 $Cache{"find_gcc_cxx_headers"} = 1;
17669}
17670
17671sub parse_libname($$$)
17672{
17673 my ($Name, $Type, $Target) = @_;
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040017674 if(not $Name) {
17675 return "";
17676 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017677 if($Target eq "symbian") {
17678 return parse_libname_symbian($Name, $Type);
17679 }
17680 elsif($Target eq "windows") {
17681 return parse_libname_windows($Name, $Type);
17682 }
17683 my $Ext = getLIB_EXT($Target);
17684 if($Name=~/((((lib|).+?)([\-\_][\d\-\.\_]+|))\.$Ext)(\.(.+)|)\Z/)
17685 { # libSDL-1.2.so.0.7.1
17686 # libwbxml2.so.0.0.18
17687 if($Type eq "name")
17688 { # libSDL-1.2
17689 # libwbxml2
17690 return $2;
17691 }
17692 elsif($Type eq "name+ext")
17693 { # libSDL-1.2.so
17694 # libwbxml2.so
17695 return $1;
17696 }
17697 elsif($Type eq "version")
17698 {
17699 if($7 ne "")
17700 { # 0.7.1
17701 return $7;
17702 }
17703 else
17704 { # libc-2.5.so (=>2.5 version)
17705 my $MV = $5;
17706 $MV=~s/\A[\-\_]+//g;
17707 return $MV;
17708 }
17709 }
17710 elsif($Type eq "short")
17711 { # libSDL
17712 # libwbxml2
17713 return $3;
17714 }
17715 elsif($Type eq "shortest")
17716 { # SDL
17717 # wbxml
17718 return shortest_name($3);
17719 }
17720 }
17721 return "";# error
17722}
17723
17724sub parse_libname_symbian($$)
17725{
17726 my ($Name, $Type) = @_;
17727 my $Ext = getLIB_EXT("symbian");
17728 if($Name=~/(((.+?)(\{.+\}|))\.$Ext)\Z/)
17729 { # libpthread{00010001}.dso
17730 if($Type eq "name")
17731 { # libpthread{00010001}
17732 return $2;
17733 }
17734 elsif($Type eq "name+ext")
17735 { # libpthread{00010001}.dso
17736 return $1;
17737 }
17738 elsif($Type eq "version")
17739 { # 00010001
17740 my $V = $4;
17741 $V=~s/\{(.+)\}/$1/;
17742 return $V;
17743 }
17744 elsif($Type eq "short")
17745 { # libpthread
17746 return $3;
17747 }
17748 elsif($Type eq "shortest")
17749 { # pthread
17750 return shortest_name($3);
17751 }
17752 }
17753 return "";# error
17754}
17755
17756sub parse_libname_windows($$)
17757{
17758 my ($Name, $Type) = @_;
17759 my $Ext = getLIB_EXT("windows");
17760 if($Name=~/((.+?)\.$Ext)\Z/)
17761 { # netapi32.dll
17762 if($Type eq "name")
17763 { # netapi32
17764 return $2;
17765 }
17766 elsif($Type eq "name+ext")
17767 { # netapi32.dll
17768 return $1;
17769 }
17770 elsif($Type eq "version")
17771 { # DLL version embedded
17772 # at binary-level
17773 return "";
17774 }
17775 elsif($Type eq "short")
17776 { # netapi32
17777 return $2;
17778 }
17779 elsif($Type eq "shortest")
17780 { # netapi
17781 return shortest_name($2);
17782 }
17783 }
17784 return "";# error
17785}
17786
17787sub shortest_name($)
17788{
17789 my $Name = $_[0];
17790 # remove prefix
17791 $Name=~s/\A(lib|open)//;
17792 # remove suffix
17793 $Name=~s/[\W\d_]+\Z//i;
17794 $Name=~s/([a-z]{2,})(lib)\Z/$1/i;
17795 return $Name;
17796}
17797
17798sub getPrefix($)
17799{
17800 my $Str = $_[0];
17801 if($Str=~/\A(Get|get|Set|set)([A-Z]|_)/)
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040017802 { # GetError
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017803 return "";
17804 }
17805 if($Str=~/\A([_]*[A-Z][a-z]{1,5})[A-Z]/)
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040017806 { # XmuValidArea: Xmu
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017807 return $1;
17808 }
17809 elsif($Str=~/\A([_]*[a-z]+)[A-Z]/)
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040017810 { # snfReadFont: snf
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017811 return $1;
17812 }
17813 elsif($Str=~/\A([_]*[A-Z]{2,})[A-Z][a-z]+([A-Z][a-z]+|\Z)/)
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040017814 { # XRRTimes: XRR
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017815 return $1;
17816 }
17817 elsif($Str=~/\A([_]*[a-z0-9]{2,}_)[a-z]+/i)
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040017818 { # alarm_event_add: alarm_
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017819 return $1;
17820 }
17821 elsif($Str=~/\A(([a-z])\2{1,})/i)
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040017822 { # ffopen
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017823 return $1;
17824 }
17825 else {
17826 return "";
17827 }
17828}
17829
17830sub problem_title($)
17831{
17832 if($_[0]==1) {
17833 return "1 problem";
17834 }
17835 else {
17836 return $_[0]." problems";
17837 }
17838}
17839
17840sub warning_title($)
17841{
17842 if($_[0]==1) {
17843 return "1 warning";
17844 }
17845 else {
17846 return $_[0]." warnings";
17847 }
17848}
17849
17850sub createSymbolsList($$$$$)
17851{
17852 my ($DPath, $SaveTo, $LName, $LVersion, $ArchName) = @_;
17853 read_ABI_Dump(1, $DPath);
17854 if(not $CheckObjectsOnly) {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040017855 prepareSymbols(1);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017856 }
17857 my %SymbolHeaderLib = ();
17858 my $Total = 0;
17859 # Get List
17860 foreach my $Symbol (sort keys(%{$CompleteSignature{1}}))
17861 {
17862 if(not link_symbol($Symbol, 1, "-Deps"))
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040017863 { # skip src only and all external functions
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017864 next;
17865 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040017866 if(not symbolFilter($Symbol, 1, "Public", "Binary"))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017867 { # skip other symbols
17868 next;
17869 }
17870 my $HeaderName = $CompleteSignature{1}{$Symbol}{"Header"};
17871 if(not $HeaderName)
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040017872 { # skip src only and all external functions
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017873 next;
17874 }
17875 my $DyLib = $Symbol_Library{1}{$Symbol};
17876 if(not $DyLib)
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040017877 { # skip src only and all external functions
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017878 next;
17879 }
17880 $SymbolHeaderLib{$HeaderName}{$DyLib}{$Symbol} = 1;
17881 $Total+=1;
17882 }
17883 # Draw List
17884 my $SYMBOLS_LIST = "<h1>Public symbols in <span style='color:Blue;'>$LName</span> (<span style='color:Red;'>$LVersion</span>)";
17885 $SYMBOLS_LIST .= " on <span style='color:Blue;'>".showArch($ArchName)."</span><br/>Total: $Total</h1><br/>";
17886 foreach my $HeaderName (sort {lc($a) cmp lc($b)} keys(%SymbolHeaderLib))
17887 {
17888 foreach my $DyLib (sort {lc($a) cmp lc($b)} keys(%{$SymbolHeaderLib{$HeaderName}}))
17889 {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017890 my %NS_Symbol = ();
17891 foreach my $Symbol (keys(%{$SymbolHeaderLib{$HeaderName}{$DyLib}})) {
17892 $NS_Symbol{get_IntNameSpace($Symbol, 1)}{$Symbol} = 1;
17893 }
17894 foreach my $NameSpace (sort keys(%NS_Symbol))
17895 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040017896 $SYMBOLS_LIST .= getTitle($HeaderName, $DyLib, $NameSpace);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017897 my @SortedInterfaces = sort {lc(get_Signature($a, 1)) cmp lc(get_Signature($b, 1))} keys(%{$NS_Symbol{$NameSpace}});
17898 foreach my $Symbol (@SortedInterfaces)
17899 {
17900 my $SubReport = "";
17901 my $Signature = get_Signature($Symbol, 1);
17902 if($NameSpace) {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040017903 $Signature=~s/\b\Q$NameSpace\E::\b//g;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017904 }
17905 if($Symbol=~/\A(_Z|\?)/)
17906 {
17907 if($Signature) {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040017908 $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 Ponomarenkoab282102012-03-11 11:57:02 +040017909 }# report_added
17910 else {
17911 $SubReport = "<span class='iname'>".$Symbol."</span><br/>\n";
17912 }
17913 }
17914 else
17915 {
17916 if($Signature) {
17917 $SubReport = "<span class='iname'>".highLight_Signature_Italic_Color($Signature)."</span><br/>\n";
17918 }
17919 else {
17920 $SubReport = "<span class='iname'>".$Symbol."</span><br/>\n";
17921 }
17922 }
17923 $SYMBOLS_LIST .= $SubReport;
17924 }
17925 }
17926 $SYMBOLS_LIST .= "<br/>\n";
17927 }
17928 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040017929 # clear info
17930 (%TypeInfo, %SymbolInfo, %Library_Symbol, %DepSymbol_Library,
17931 %DepLibrary_Symbol, %SymVer, %SkipTypes, %SkipSymbols,
17932 %NestedNameSpaces, %ClassMethods, %AllocableClass, %ClassNames,
17933 %CompleteSignature, %SkipNameSpaces, %Symbol_Library, %Library_Symbol) = ();
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017934 ($Content_Counter, $ContentID) = (0, 0);
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040017935 # print report
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040017936 my $CssStyles = readModule("Styles", "SymbolsList.css");
17937 my $JScripts = readModule("Scripts", "Sections.js");
17938 $SYMBOLS_LIST = "<a name='Top'></a>".$SYMBOLS_LIST.$TOP_REF."<br/>\n";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017939 my $Title = "$LName: public symbols";
17940 my $Keywords = "$LName, API, symbols";
17941 my $Description = "List of symbols in $LName ($LVersion) on ".showArch($ArchName);
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040017942 $SYMBOLS_LIST = composeHTML_Head($Title, $Keywords, $Description, $CssStyles, $JScripts)."
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017943 <body><div>\n$SYMBOLS_LIST</div>
17944 <br/><br/><hr/>\n".getReportFooter($LName)."
17945 <div style='height:999px;'></div></body></html>";
17946 writeFile($SaveTo, $SYMBOLS_LIST);
17947}
17948
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040017949sub readModule($$)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017950{
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040017951 my ($Module, $Name) = @_;
17952 my $Path = $MODULES_DIR."/Internals/$Module/".$Name;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017953 if(not -f $Path) {
17954 exitStatus("Module_Error", "can't access \'$Path\'");
17955 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040017956 return readFile($Path);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017957}
17958
17959sub is_target_lib($)
17960{
17961 my $LName = $_[0];
17962 if($TargetLibraryName
17963 and $LName!~/\Q$TargetLibraryName\E/) {
17964 return 0;
17965 }
17966 if(keys(%TargetLibs)
17967 and not $TargetLibs{$LName}
17968 and not $TargetLibs{parse_libname($LName, "name+ext", $OStarget)}) {
17969 return 0;
17970 }
17971 return 1;
17972}
17973
Andrey Ponomarenko85043792012-05-14 16:48:07 +040017974sub is_target_header($$)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017975{ # --header, --headers-list
Andrey Ponomarenko85043792012-05-14 16:48:07 +040017976 my ($H, $V) = @_;
17977 if(keys(%{$TargetHeaders{$V}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017978 {
Andrey Ponomarenko85043792012-05-14 16:48:07 +040017979 if($TargetHeaders{$V}{$H}) {
17980 return 1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017981 }
17982 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +040017983 return 0;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017984}
17985
17986sub checkVersionNum($$)
17987{
17988 my ($LibVersion, $Path) = @_;
17989 if(my $VerNum = $TargetVersion{$LibVersion}) {
17990 return $VerNum;
17991 }
17992 my $UsedAltDescr = 0;
17993 foreach my $Part (split(/\s*,\s*/, $Path))
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040017994 { # try to get version string from file path
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017995 next if($Part=~/\.xml\Z/i);
17996 next if(isDump($Part));
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040017997 my $VerNum = "";
17998 if(parse_libname($Part, "name", $OStarget))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017999 {
18000 $UsedAltDescr = 1;
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040018001 $VerNum = parse_libname($Part, "version", $OStarget);
18002 if(not $VerNum) {
18003 $VerNum = readStringVersion($Part);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040018004 }
18005 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040018006 elsif(is_header($Part, 2, $LibVersion) or -d $Part)
18007 {
18008 $UsedAltDescr = 1;
18009 $VerNum = readStringVersion($Part);
18010 }
18011 if($VerNum ne "")
18012 {
18013 $TargetVersion{$LibVersion} = $VerNum;
18014 if($DumpAPI) {
18015 printMsg("WARNING", "setting version number to $VerNum (use -vnum <num> option to change it)");
18016 }
18017 else {
18018 printMsg("WARNING", "setting ".($LibVersion==1?"1st":"2nd")." version number to \"$VerNum\" (use -v$LibVersion <num> option to change it)");
18019 }
18020 return $TargetVersion{$LibVersion};
18021 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040018022 }
18023 if($UsedAltDescr)
18024 {
18025 if($DumpAPI) {
18026 exitStatus("Error", "version number is not set (use -vnum <num> option)");
18027 }
18028 else {
18029 exitStatus("Error", ($LibVersion==1?"1st":"2nd")." version number is not set (use -v$LibVersion <num> option)");
18030 }
18031 }
18032}
18033
18034sub readStringVersion($)
18035{
18036 my $Str = $_[0];
18037 return "" if(not $Str);
18038 $Str=~s/\Q$TargetLibraryName\E//g;
18039 if($Str=~/(\/|\\|\w|\A)[\-\_]*(\d+[\d\.\-]+\d+|\d+)/)
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040018040 { # .../libssh-0.4.0/...
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040018041 return $2;
18042 }
18043 elsif(my $V = parse_libname($Str, "version", $OStarget)) {
18044 return $V;
18045 }
18046 return "";
18047}
18048
18049sub readLibs($)
18050{
18051 my $LibVersion = $_[0];
18052 if($OStarget eq "windows")
18053 { # dumpbin.exe will crash
18054 # without VS Environment
18055 check_win32_env();
18056 }
Andrey Ponomarenko16934472012-03-29 15:37:04 +040018057 readSymbols($LibVersion);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040018058 translateSymbols(keys(%{$Symbol_Library{$LibVersion}}), $LibVersion);
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040018059 translateSymbols(keys(%{$DepSymbol_Library{$LibVersion}}), $LibVersion);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040018060}
18061
18062sub dump_sorting($)
18063{
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +040018064 my $Hash = $_[0];
18065 return [] if(not $Hash);
18066 my @Keys = keys(%{$Hash});
18067 return [] if($#Keys<0);
18068 if($Keys[0]=~/\A\d+\Z/)
18069 { # numbers
18070 return [sort {int($a)<=>int($b)} @Keys];
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040018071 }
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +040018072 else
18073 { # strings
18074 return [sort {$a cmp $b} @Keys];
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040018075 }
18076}
18077
18078sub printMsg($$)
18079{
18080 my ($Type, $Msg) = @_;
18081 if($Type!~/\AINFO/) {
18082 $Msg = $Type.": ".$Msg;
18083 }
18084 if($Type!~/_C\Z/) {
18085 $Msg .= "\n";
18086 }
18087 if($Quiet)
18088 { # --quiet option
18089 appendFile($COMMON_LOG_PATH, $Msg);
18090 }
18091 else
18092 {
18093 if($Type eq "ERROR") {
18094 print STDERR $Msg;
18095 }
18096 else {
18097 print $Msg;
18098 }
18099 }
18100}
18101
18102sub exitStatus($$)
18103{
18104 my ($Code, $Msg) = @_;
18105 printMsg("ERROR", $Msg);
18106 exit($ERROR_CODE{$Code});
18107}
18108
18109sub exitReport()
18110{ # the tool has run without any errors
18111 printReport();
18112 if($COMPILE_ERRORS)
18113 { # errors in headers may add false positives/negatives
18114 exit($ERROR_CODE{"Compile_Error"});
18115 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040018116 if($BinaryOnly and $RESULT{"Binary"}{"Problems"})
18117 { # --binary
18118 exit($ERROR_CODE{"Incompatible"});
18119 }
18120 elsif($SourceOnly and $RESULT{"Source"}{"Problems"})
18121 { # --source
18122 exit($ERROR_CODE{"Incompatible"});
18123 }
18124 elsif($RESULT{"Source"}{"Problems"}
18125 or $RESULT{"Binary"}{"Problems"})
18126 { # default
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040018127 exit($ERROR_CODE{"Incompatible"});
18128 }
18129 else {
18130 exit($ERROR_CODE{"Compatible"});
18131 }
18132}
18133
18134sub readRules($)
18135{
18136 my $Kind = $_[0];
18137 if(not -f $RULES_PATH{$Kind}) {
18138 exitStatus("Module_Error", "can't access \'".$RULES_PATH{$Kind}."\'");
18139 }
18140 my $Content = readFile($RULES_PATH{$Kind});
18141 while(my $Rule = parseTag(\$Content, "rule"))
18142 {
18143 my $RId = parseTag(\$Rule, "id");
18144 my @Properties = ("Severity", "Change", "Effect", "Overcome", "Kind");
18145 foreach my $Prop (@Properties) {
18146 if(my $Value = parseTag(\$Rule, lc($Prop)))
18147 {
18148 $Value=~s/\n[ ]*//;
18149 $CompatRules{$Kind}{$RId}{$Prop} = $Value;
18150 }
18151 }
18152 if($CompatRules{$Kind}{$RId}{"Kind"}=~/\A(Symbols|Parameters)\Z/) {
18153 $CompatRules{$Kind}{$RId}{"Kind"} = "Symbols";
18154 }
18155 else {
18156 $CompatRules{$Kind}{$RId}{"Kind"} = "Types";
18157 }
18158 }
18159}
18160
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040018161sub getReportPath($)
18162{
18163 my $Level = $_[0];
18164 my $Dir = "compat_reports/$TargetLibraryName/".$Descriptor{1}{"Version"}."_to_".$Descriptor{2}{"Version"};
18165 if($Level eq "Binary")
18166 {
18167 if($BinaryReportPath)
18168 { # --bin-report-path
18169 return $BinaryReportPath;
18170 }
18171 elsif($OutputReportPath)
18172 { # --report-path
18173 return $OutputReportPath;
18174 }
18175 else
18176 { # default
18177 return $Dir."/abi_compat_report.$ReportFormat";
18178 }
18179 }
18180 elsif($Level eq "Source")
18181 {
18182 if($SourceReportPath)
18183 { # --src-report-path
18184 return $SourceReportPath;
18185 }
18186 elsif($OutputReportPath)
18187 { # --report-path
18188 return $OutputReportPath;
18189 }
18190 else
18191 { # default
18192 return $Dir."/src_compat_report.$ReportFormat";
18193 }
18194 }
18195 else
18196 {
18197 if($OutputReportPath)
18198 { # --report-path
18199 return $OutputReportPath;
18200 }
18201 else
18202 { # default
18203 return $Dir."/compat_report.$ReportFormat";
18204 }
18205 }
18206}
18207
18208sub printStatMsg($)
18209{
18210 my $Level = $_[0];
18211 printMsg("INFO", "total \"$Level\" compatibility problems: ".$RESULT{$Level}{"Problems"}.", warnings: ".$RESULT{$Level}{"Warnings"});
18212}
18213
18214sub listAffected($)
18215{
18216 my $Level = $_[0];
18217 my $List = "";
18218 foreach (keys(%{$TotalAffected{$Level}}))
18219 {
18220 if($StrictCompat and $TotalAffected{$Level}{$_} eq "Low")
18221 { # skip "Low"-severity problems
18222 next;
18223 }
18224 $List .= "$_\n";
18225 }
18226 my $Dir = get_dirname(getReportPath($Level));
18227 if($Level eq "Binary") {
18228 writeFile($Dir."/abi_affected.txt", $List);
18229 }
18230 elsif($Level eq "Source") {
18231 writeFile($Dir."/src_affected.txt", $List);
18232 }
18233}
18234
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040018235sub printReport()
18236{
18237 printMsg("INFO", "creating compatibility report ...");
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040018238 createReport();
18239 if($JoinReport or $DoubleReport)
18240 {
18241 if($RESULT{"Binary"}{"Problems"}
18242 or $RESULT{"Source"}{"Problems"}) {
18243 printMsg("INFO", "result: INCOMPATIBLE (Binary: ".$RESULT{"Binary"}{"Affected"}."\%, Source: ".$RESULT{"Source"}{"Affected"}."\%)");
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040018244 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040018245 else {
18246 printMsg("INFO", "result: COMPATIBLE");
18247 }
18248 printStatMsg("Binary");
18249 printStatMsg("Source");
18250 if($ListAffected)
18251 { # --list-affected
18252 listAffected("Binary");
18253 listAffected("Source");
18254 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040018255 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040018256 elsif($BinaryOnly)
18257 {
18258 if($RESULT{"Binary"}{"Problems"}) {
18259 printMsg("INFO", "result: INCOMPATIBLE (".$RESULT{"Binary"}{"Affected"}."\%)");
18260 }
18261 else {
18262 printMsg("INFO", "result: COMPATIBLE");
18263 }
18264 printStatMsg("Binary");
18265 if($ListAffected)
18266 { # --list-affected
18267 listAffected("Binary");
18268 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040018269 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040018270 elsif($SourceOnly)
18271 {
18272 if($RESULT{"Source"}{"Problems"}) {
18273 printMsg("INFO", "result: INCOMPATIBLE (".$RESULT{"Source"}{"Affected"}."\%)");
18274 }
18275 else {
18276 printMsg("INFO", "result: COMPATIBLE");
18277 }
18278 printStatMsg("Source");
18279 if($ListAffected)
18280 { # --list-affected
18281 listAffected("Source");
18282 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040018283 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040018284 if($StdOut)
18285 {
18286 if($JoinReport or not $DoubleReport)
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040018287 { # --binary or --source
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040018288 printMsg("INFO", "compatibility report has been generated to stdout");
18289 }
18290 else
18291 { # default
18292 printMsg("INFO", "compatibility reports have been generated to stdout");
18293 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040018294 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040018295 else
18296 {
18297 if($JoinReport)
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040018298 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040018299 printMsg("INFO", "see detailed report:\n ".getReportPath("Join"));
18300 }
18301 elsif($DoubleReport)
18302 { # default
18303 printMsg("INFO", "see detailed reports:\n ".getReportPath("Binary")."\n ".getReportPath("Source"));
18304 }
18305 elsif($BinaryOnly)
18306 { # --binary
18307 printMsg("INFO", "see detailed report:\n ".getReportPath("Binary"));
18308 }
18309 elsif($SourceOnly)
18310 { # --source
18311 printMsg("INFO", "see detailed report:\n ".getReportPath("Source"));
18312 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040018313 }
18314}
18315
18316sub check_win32_env()
18317{
18318 if(not $ENV{"DevEnvDir"}
18319 or not $ENV{"LIB"}) {
18320 exitStatus("Error", "can't start without VS environment (vsvars32.bat)");
18321 }
18322}
18323
18324sub create_ABI_Dump()
18325{
18326 if(not -e $DumpAPI) {
18327 exitStatus("Access_Error", "can't access \'$DumpAPI\'");
18328 }
18329 # check the archive utilities
18330 if($OSgroup eq "windows")
18331 { # using zip
18332 my $ZipCmd = get_CmdPath("zip");
18333 if(not $ZipCmd) {
18334 exitStatus("Not_Found", "can't find \"zip\"");
18335 }
18336 }
18337 else
18338 { # using tar and gzip
18339 my $TarCmd = get_CmdPath("tar");
18340 if(not $TarCmd) {
18341 exitStatus("Not_Found", "can't find \"tar\"");
18342 }
18343 my $GzipCmd = get_CmdPath("gzip");
18344 if(not $GzipCmd) {
18345 exitStatus("Not_Found", "can't find \"gzip\"");
18346 }
18347 }
18348 my @DParts = split(/\s*,\s*/, $DumpAPI);
18349 foreach my $Part (@DParts)
18350 {
18351 if(not -e $Part) {
18352 exitStatus("Access_Error", "can't access \'$Part\'");
18353 }
18354 }
18355 checkVersionNum(1, $DumpAPI);
18356 foreach my $Part (@DParts)
18357 {
18358 if(isDump($Part)) {
18359 read_ABI_Dump(1, $Part);
18360 }
18361 else {
18362 readDescriptor(1, createDescriptor(1, $Part));
18363 }
18364 }
18365 initLogging(1);
18366 detect_default_paths("inc|lib|bin|gcc"); # complete analysis
18367 if(not $CheckHeadersOnly) {
18368 readLibs(1);
18369 }
18370 if($CheckHeadersOnly) {
18371 setLanguage(1, "C++");
18372 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +040018373 if(not $CheckObjectsOnly) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040018374 searchForHeaders(1);
18375 }
18376 $WORD_SIZE{1} = detectWordSize();
18377 if($Descriptor{1}{"Headers"}
18378 and not $Descriptor{1}{"Dump"}) {
18379 readHeaders(1);
18380 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +040018381 cleanDump(1);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040018382 if(not keys(%{$SymbolInfo{1}}))
18383 { # check if created dump is valid
18384 if(not $ExtendedCheck and not $CheckObjectsOnly)
18385 {
18386 if($CheckHeadersOnly) {
18387 exitStatus("Empty_Set", "the set of public symbols is empty");
18388 }
18389 else {
18390 exitStatus("Empty_Intersection", "the sets of public symbols in headers and libraries have empty intersection");
18391 }
18392 }
18393 }
18394 my %HeadersInfo = ();
18395 foreach my $HPath (keys(%{$Registered_Headers{1}}))
18396 { # headers info stored without paths in the dump
18397 $HeadersInfo{$Registered_Headers{1}{$HPath}{"Identity"}} = $Registered_Headers{1}{$HPath}{"Pos"};
18398 }
18399 printMsg("INFO", "creating library ABI dump ...");
18400 my %LibraryABI = (
18401 "TypeInfo" => $TypeInfo{1},
18402 "SymbolInfo" => $SymbolInfo{1},
18403 "Symbols" => $Library_Symbol{1},
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040018404 "DepSymbols" => $DepLibrary_Symbol{1},
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040018405 "SymbolVersion" => $SymVer{1},
18406 "LibraryVersion" => $Descriptor{1}{"Version"},
18407 "LibraryName" => $TargetLibraryName,
18408 "Language" => $COMMON_LANGUAGE{1},
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040018409 "SkipTypes" => $SkipTypes{1},
18410 "SkipSymbols" => $SkipSymbols{1},
18411 "SkipNameSpaces" => $SkipNameSpaces{1},
18412 "SkipHeaders" => $SkipHeadersList{1},
18413 "TargetHeaders" => $TargetHeaders{1},
18414 "Headers" => \%HeadersInfo,
18415 "Constants" => $Constants{1},
18416 "NameSpaces" => $NestedNameSpaces{1},
18417 "Target" => $OStarget,
18418 "Arch" => getArch(1),
18419 "WordSize" => $WORD_SIZE{1},
18420 "GccVersion" => get_dumpversion($GCC_PATH),
18421 "ABI_DUMP_VERSION" => $ABI_DUMP_VERSION,
18422 "ABI_COMPLIANCE_CHECKER_VERSION" => $TOOL_VERSION
18423 );
18424 if($ExtendedCheck)
18425 { # --ext option
18426 $LibraryABI{"Mode"} = "Extended";
18427 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040018428 if($BinaryOnly)
18429 { # --binary
18430 $LibraryABI{"BinOnly"} = 1;
18431 }
18432 else
18433 { # default
18434 $LibraryABI{"SrcBin"} = 1;
18435 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +040018436
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040018437 if($StdOut)
18438 { # --stdout option
18439 print STDOUT Dumper(\%LibraryABI);
18440 printMsg("INFO", "ABI dump has been generated to stdout");
18441 return;
18442 }
18443 else
18444 { # write to gzipped file
18445 my $DumpPath = "abi_dumps/$TargetLibraryName/".$TargetLibraryName."_".$Descriptor{1}{"Version"}.".abi.".$AR_EXT;
18446 if($OutputDumpPath)
18447 { # user defined path
18448 $DumpPath = $OutputDumpPath;
18449 }
18450 if(not $DumpPath=~s/\Q.$AR_EXT\E\Z//g) {
18451 exitStatus("Error", "the dump path (-dump-path option) should be the path to a *.$AR_EXT file");
18452 }
18453 my ($DDir, $DName) = separate_path($DumpPath);
18454 my $DPath = $TMP_DIR."/".$DName;
18455 mkpath($DDir);
Andrey Ponomarenko85043792012-05-14 16:48:07 +040018456
18457 open(DUMP, ">", $DPath) || die ("can't open file \'$DPath\': $!\n");
18458 print DUMP Dumper(\%LibraryABI);
18459 close(DUMP);
18460
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040018461 if(not -s $DPath) {
18462 exitStatus("Error", "can't create ABI dump because something is going wrong with the Data::Dumper module");
18463 }
18464 my $Pkg = createArchive($DPath, $DDir);
18465 printMsg("INFO", "library ABI has been dumped to:\n $Pkg");
18466 printMsg("INFO", "you can transfer this dump everywhere and use instead of the ".$Descriptor{1}{"Version"}." version descriptor");
18467 }
18468}
18469
18470sub quickEmptyReports()
18471{ # Quick "empty" reports
18472 # 4 times faster than merging equal dumps
18473 # NOTE: the dump contains the "LibraryVersion" attribute
18474 # if you change the version, then your dump will be different
18475 # OVERCOME: use -v1 and v2 options for comparing dumps
18476 # and don't change version in the XML descriptor (and dumps)
18477 # OVERCOME 2: separate meta info from the dumps in ACC 2.0
18478 if(-s $Descriptor{1}{"Path"} == -s $Descriptor{2}{"Path"})
18479 {
18480 my $FilePath1 = unpackDump($Descriptor{1}{"Path"});
18481 my $FilePath2 = unpackDump($Descriptor{2}{"Path"});
18482 if($FilePath1 and $FilePath2)
18483 {
Andrey Ponomarenko85043792012-05-14 16:48:07 +040018484 local $/ = undef;
18485
18486 open(DUMP1, $FilePath1);
18487 my $Content1 = <DUMP1>;
18488 close(DUMP1);
18489
18490 open(DUMP2, $FilePath2);
18491 my $Content2 = <DUMP2>;
18492 close(DUMP2);
18493
18494 if($Content1 eq $Content2)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040018495 {
Andrey Ponomarenko85043792012-05-14 16:48:07 +040018496 # clean memory
18497 undef $Content2;
18498
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040018499 # read a number of headers, libs, symbols and types
Andrey Ponomarenko85043792012-05-14 16:48:07 +040018500 my $ABIdump = eval($Content1);
18501
18502 # clean memory
18503 undef $Content1;
18504
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040018505 if(not $ABIdump) {
18506 exitStatus("Error", "internal error");
18507 }
18508 if(not $ABIdump->{"TypeInfo"})
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040018509 { # support for old dumps
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040018510 $ABIdump->{"TypeInfo"} = $ABIdump->{"TypeDescr"};
18511 }
18512 if(not $ABIdump->{"SymbolInfo"})
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040018513 { # support for old dumps
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040018514 $ABIdump->{"SymbolInfo"} = $ABIdump->{"FuncDescr"};
18515 }
18516 read_Headers_DumpInfo($ABIdump, 1);
18517 read_Libs_DumpInfo($ABIdump, 1);
18518 read_Machine_DumpInfo($ABIdump, 1);
18519 read_Machine_DumpInfo($ABIdump, 2);
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040018520
18521 %{$CheckedTypes{"Binary"}} = %{$ABIdump->{"TypeInfo"}};
18522 %{$CheckedTypes{"Source"}} = %{$ABIdump->{"TypeInfo"}};
18523
18524 %{$CheckedSymbols{"Binary"}} = %{$ABIdump->{"SymbolInfo"}};
18525 %{$CheckedSymbols{"Source"}} = %{$ABIdump->{"SymbolInfo"}};
18526
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040018527 $Descriptor{1}{"Version"} = $TargetVersion{1}?$TargetVersion{1}:$ABIdump->{"LibraryVersion"};
18528 $Descriptor{2}{"Version"} = $TargetVersion{2}?$TargetVersion{2}:$ABIdump->{"LibraryVersion"};
18529 exitReport();
18530 }
18531 }
18532 }
18533}
18534
18535sub initLogging($)
18536{
18537 my $LibVersion = $_[0];
18538 # create log directory
18539 my ($LOG_DIR, $LOG_FILE) = ("logs/$TargetLibraryName/".$Descriptor{$LibVersion}{"Version"}, "log.txt");
18540 if($OutputLogPath{$LibVersion})
18541 { # user-defined by -log-path option
18542 ($LOG_DIR, $LOG_FILE) = separate_path($OutputLogPath{$LibVersion});
18543 }
18544 if($LogMode ne "n") {
18545 mkpath($LOG_DIR);
18546 }
18547 $LOG_PATH{$LibVersion} = get_abs_path($LOG_DIR)."/".$LOG_FILE;
18548 resetLogging($LibVersion);
18549 if($Debug)
18550 { # debug directory
18551 $DEBUG_PATH{$LibVersion} = "debug/$TargetLibraryName/".$Descriptor{$LibVersion}{"Version"};
18552 rmtree($DEBUG_PATH{$LibVersion});
18553 }
18554}
18555
18556sub writeLog($$)
18557{
18558 my ($LibVersion, $Msg) = @_;
18559 if($LogMode ne "n") {
18560 appendFile($LOG_PATH{$LibVersion}, $Msg);
18561 }
18562}
18563
18564sub resetLogging($)
18565{
18566 my $LibVersion = $_[0];
18567 if($LogMode!~/a|n/)
18568 { # remove old log
18569 unlink($LOG_PATH{$LibVersion});
18570 }
18571}
18572
18573sub printErrorLog($)
18574{
18575 my $LibVersion = $_[0];
18576 if($LogMode ne "n") {
18577 printMsg("ERROR", "see log for details:\n ".$LOG_PATH{$LibVersion}."\n");
18578 }
18579}
18580
18581sub isDump($)
18582{
18583 if(get_filename($_[0])=~/\A(.+)\.abi(\Q.tar.gz\E|\Q.zip\E|)\Z/)
18584 { # returns a name of package
18585 return $1;
18586 }
18587 return 0;
18588}
18589
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040018590sub compareInit()
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040018591{
18592 # read input XML descriptors or ABI dumps
18593 if(not $Descriptor{1}{"Path"}) {
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040018594 exitStatus("Error", "-old option is not specified");
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040018595 }
18596 my @DParts1 = split(/\s*,\s*/, $Descriptor{1}{"Path"});
18597 foreach my $Part (@DParts1)
18598 {
18599 if(not -e $Part) {
18600 exitStatus("Access_Error", "can't access \'$Part\'");
18601 }
18602 }
18603 if(not $Descriptor{2}{"Path"}) {
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040018604 exitStatus("Error", "-new option is not specified");
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040018605 }
18606 my @DParts2 = split(/\s*,\s*/, $Descriptor{2}{"Path"});
18607 foreach my $Part (@DParts2)
18608 {
18609 if(not -e $Part) {
18610 exitStatus("Access_Error", "can't access \'$Part\'");
18611 }
18612 }
18613 detect_default_paths("bin"); # to extract dumps
18614 if($#DParts1==0 and $#DParts2==0
18615 and isDump($Descriptor{1}{"Path"})
18616 and isDump($Descriptor{2}{"Path"}))
18617 { # optimization: equal ABI dumps
18618 quickEmptyReports();
18619 }
18620 checkVersionNum(1, $Descriptor{1}{"Path"});
18621 checkVersionNum(2, $Descriptor{2}{"Path"});
18622 printMsg("INFO", "preparation, please wait ...");
18623 foreach my $Part (@DParts1)
18624 {
18625 if(isDump($Part)) {
18626 read_ABI_Dump(1, $Part);
18627 }
18628 else {
18629 readDescriptor(1, createDescriptor(1, $Part));
18630 }
18631 }
18632 foreach my $Part (@DParts2)
18633 {
18634 if(isDump($Part)) {
18635 read_ABI_Dump(2, $Part);
18636 }
18637 else {
18638 readDescriptor(2, createDescriptor(2, $Part));
18639 }
18640 }
18641 initLogging(1);
18642 initLogging(2);
18643 # check consistency
18644 if(not $Descriptor{1}{"Headers"}
18645 and not $Descriptor{1}{"Libs"}) {
18646 exitStatus("Error", "descriptor d1 does not contain both header files and libraries info");
18647 }
18648 if(not $Descriptor{2}{"Headers"}
18649 and not $Descriptor{2}{"Libs"}) {
18650 exitStatus("Error", "descriptor d2 does not contain both header files and libraries info");
18651 }
18652 if($Descriptor{1}{"Headers"} and not $Descriptor{1}{"Libs"}
18653 and not $Descriptor{2}{"Headers"} and $Descriptor{2}{"Libs"}) {
18654 exitStatus("Error", "can't compare headers with $SLIB_TYPE libraries");
18655 }
18656 elsif(not $Descriptor{1}{"Headers"} and $Descriptor{1}{"Libs"}
18657 and $Descriptor{2}{"Headers"} and not $Descriptor{2}{"Libs"}) {
18658 exitStatus("Error", "can't compare $SLIB_TYPE libraries with headers");
18659 }
18660 if(not $Descriptor{1}{"Headers"}) {
18661 if($CheckHeadersOnly_Opt) {
18662 exitStatus("Error", "can't find header files info in descriptor d1");
18663 }
18664 }
18665 if(not $Descriptor{2}{"Headers"}) {
18666 if($CheckHeadersOnly_Opt) {
18667 exitStatus("Error", "can't find header files info in descriptor d2");
18668 }
18669 }
18670 if(not $Descriptor{1}{"Headers"}
18671 or not $Descriptor{2}{"Headers"}) {
18672 if(not $CheckObjectsOnly_Opt) {
18673 printMsg("WARNING", "comparing $SLIB_TYPE libraries only");
18674 $CheckObjectsOnly = 1;
18675 }
18676 }
18677 if(not $Descriptor{1}{"Libs"}) {
18678 if($CheckObjectsOnly_Opt) {
18679 exitStatus("Error", "can't find $SLIB_TYPE libraries info in descriptor d1");
18680 }
18681 }
18682 if(not $Descriptor{2}{"Libs"}) {
18683 if($CheckObjectsOnly_Opt) {
18684 exitStatus("Error", "can't find $SLIB_TYPE libraries info in descriptor d2");
18685 }
18686 }
18687 if(not $Descriptor{1}{"Libs"}
18688 or not $Descriptor{2}{"Libs"})
18689 { # comparing standalone header files
18690 # comparing ABI dumps created with --headers-only
18691 if(not $CheckHeadersOnly_Opt)
18692 {
18693 printMsg("WARNING", "checking headers only");
18694 $CheckHeadersOnly = 1;
18695 }
18696 }
18697 if($UseDumps)
18698 { # --use-dumps
18699 # parallel processing
18700 my $pid = fork();
18701 if($pid)
18702 { # dump on two CPU cores
18703 my @PARAMS = ("-dump", $Descriptor{1}{"Path"}, "-l", $TargetLibraryName);
18704 if($RelativeDirectory{1}) {
18705 @PARAMS = (@PARAMS, "-relpath", $RelativeDirectory{1});
18706 }
18707 if($OutputLogPath{1}) {
18708 @PARAMS = (@PARAMS, "-log-path", $OutputLogPath{1});
18709 }
18710 if($CrossGcc) {
18711 @PARAMS = (@PARAMS, "-cross-gcc", $CrossGcc);
18712 }
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040018713 if($Quiet)
18714 {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040018715 @PARAMS = (@PARAMS, "-quiet");
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040018716 @PARAMS = (@PARAMS, "-logging-mode", "a");
18717 }
18718 elsif($LogMode and $LogMode ne "w")
18719 { # "w" is default
18720 @PARAMS = (@PARAMS, "-logging-mode", $LogMode);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040018721 }
18722 if($ExtendedCheck) {
18723 @PARAMS = (@PARAMS, "-extended");
18724 }
18725 if($UserLang) {
18726 @PARAMS = (@PARAMS, "-lang", $UserLang);
18727 }
18728 if($TargetVersion{1}) {
18729 @PARAMS = (@PARAMS, "-vnum", $TargetVersion{1});
18730 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +040018731 if($BinaryOnly) {
18732 @PARAMS = (@PARAMS, "-binary");
18733 }
18734 if($SourceOnly) {
18735 @PARAMS = (@PARAMS, "-source");
18736 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040018737 if($SortDump) {
18738 @PARAMS = (@PARAMS, "-sort");
18739 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +040018740 if($Debug)
18741 {
18742 @PARAMS = (@PARAMS, "-debug");
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040018743 printMsg("INFO", "running perl $0 @PARAMS");
Andrey Ponomarenko85043792012-05-14 16:48:07 +040018744 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040018745 system("perl", $0, @PARAMS);
18746 if($?) {
18747 exit(1);
18748 }
18749 }
18750 else
18751 { # child
18752 my @PARAMS = ("-dump", $Descriptor{2}{"Path"}, "-l", $TargetLibraryName);
18753 if($RelativeDirectory{2}) {
18754 @PARAMS = (@PARAMS, "-relpath", $RelativeDirectory{2});
18755 }
18756 if($OutputLogPath{2}) {
18757 @PARAMS = (@PARAMS, "-log-path", $OutputLogPath{2});
18758 }
18759 if($CrossGcc) {
18760 @PARAMS = (@PARAMS, "-cross-gcc", $CrossGcc);
18761 }
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040018762 if($Quiet)
18763 {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040018764 @PARAMS = (@PARAMS, "-quiet");
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040018765 @PARAMS = (@PARAMS, "-logging-mode", "a");
18766 }
18767 elsif($LogMode and $LogMode ne "w")
18768 { # "w" is default
18769 @PARAMS = (@PARAMS, "-logging-mode", $LogMode);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040018770 }
18771 if($ExtendedCheck) {
18772 @PARAMS = (@PARAMS, "-extended");
18773 }
18774 if($UserLang) {
18775 @PARAMS = (@PARAMS, "-lang", $UserLang);
18776 }
18777 if($TargetVersion{2}) {
18778 @PARAMS = (@PARAMS, "-vnum", $TargetVersion{2});
18779 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +040018780 if($BinaryOnly) {
18781 @PARAMS = (@PARAMS, "-binary");
18782 }
18783 if($SourceOnly) {
18784 @PARAMS = (@PARAMS, "-source");
18785 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040018786 if($SortDump) {
18787 @PARAMS = (@PARAMS, "-sort");
18788 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +040018789 if($Debug)
18790 {
18791 @PARAMS = (@PARAMS, "-debug");
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040018792 printMsg("INFO", "running perl $0 @PARAMS");
Andrey Ponomarenko85043792012-05-14 16:48:07 +040018793 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040018794 system("perl", $0, @PARAMS);
18795 if($?) {
18796 exit(1);
18797 }
18798 else {
18799 exit(0);
18800 }
18801 }
18802 waitpid($pid, 0);
18803 my @CMP_PARAMS = ("-l", $TargetLibraryName);
18804 @CMP_PARAMS = (@CMP_PARAMS, "-d1", "abi_dumps/$TargetLibraryName/".$TargetLibraryName."_".$Descriptor{1}{"Version"}.".abi.$AR_EXT");
18805 @CMP_PARAMS = (@CMP_PARAMS, "-d2", "abi_dumps/$TargetLibraryName/".$TargetLibraryName."_".$Descriptor{2}{"Version"}.".abi.$AR_EXT");
18806 if($TargetLibraryFName ne $TargetLibraryName) {
18807 @CMP_PARAMS = (@CMP_PARAMS, "-l-full", $TargetLibraryFName);
18808 }
18809 if($ShowRetVal) {
18810 @CMP_PARAMS = (@CMP_PARAMS, "-show-retval");
18811 }
18812 if($CrossGcc) {
18813 @CMP_PARAMS = (@CMP_PARAMS, "-cross-gcc", $CrossGcc);
18814 }
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040018815 if($Quiet)
18816 {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040018817 @CMP_PARAMS = (@CMP_PARAMS, "-quiet");
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040018818 @CMP_PARAMS = (@CMP_PARAMS, "-logging-mode", "a");
18819 }
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040018820 elsif($LogMode and $LogMode ne "w")
18821 { # "w" is default
18822 @CMP_PARAMS = (@CMP_PARAMS, "-logging-mode", $LogMode);
18823 }
18824 if($ReportFormat and $ReportFormat ne "html")
18825 { # HTML is default format
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040018826 @CMP_PARAMS = (@CMP_PARAMS, "-report-format", $ReportFormat);
18827 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040018828 if($OutputReportPath) {
18829 @CMP_PARAMS = (@CMP_PARAMS, "-report-path", $OutputReportPath);
18830 }
18831 if($BinaryReportPath) {
18832 @CMP_PARAMS = (@CMP_PARAMS, "-bin-report-path", $BinaryReportPath);
18833 }
18834 if($SourceReportPath) {
18835 @CMP_PARAMS = (@CMP_PARAMS, "-src-report-path", $SourceReportPath);
18836 }
18837 if($LoggingPath) {
18838 @CMP_PARAMS = (@CMP_PARAMS, "-log-path", $LoggingPath);
18839 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +040018840 if($Browse) {
18841 @CMP_PARAMS = (@CMP_PARAMS, "-browse", $Browse);
18842 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040018843 if($OpenReport) {
18844 @CMP_PARAMS = (@CMP_PARAMS, "-open");
18845 }
18846 if($Debug)
18847 {
18848 @CMP_PARAMS = (@CMP_PARAMS, "-debug");
18849 printMsg("INFO", "running perl $0 @CMP_PARAMS");
Andrey Ponomarenko85043792012-05-14 16:48:07 +040018850 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040018851 system("perl", $0, @CMP_PARAMS);
18852 exit($?>>8);
18853 }
18854 if(not $Descriptor{1}{"Dump"}
18855 or not $Descriptor{2}{"Dump"})
18856 { # need GCC toolchain to analyze
18857 # header files and libraries
18858 detect_default_paths("inc|lib|gcc");
18859 }
18860 if(not $Descriptor{1}{"Dump"})
18861 {
18862 if(not $CheckHeadersOnly) {
18863 readLibs(1);
18864 }
18865 if($CheckHeadersOnly) {
18866 setLanguage(1, "C++");
18867 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +040018868 if(not $CheckObjectsOnly) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040018869 searchForHeaders(1);
18870 }
18871 $WORD_SIZE{1} = detectWordSize();
18872 }
18873 if(not $Descriptor{2}{"Dump"})
18874 {
18875 if(not $CheckHeadersOnly) {
18876 readLibs(2);
18877 }
18878 if($CheckHeadersOnly) {
18879 setLanguage(2, "C++");
18880 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +040018881 if(not $CheckObjectsOnly) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040018882 searchForHeaders(2);
18883 }
18884 $WORD_SIZE{2} = detectWordSize();
18885 }
18886 if($WORD_SIZE{1} ne $WORD_SIZE{2})
18887 { # support for old ABI dumps
18888 # try to synch different WORD sizes
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040018889 if(not checkDump(1, "2.1"))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040018890 {
18891 $WORD_SIZE{1} = $WORD_SIZE{2};
18892 printMsg("WARNING", "set WORD size to ".$WORD_SIZE{2}." bytes");
18893 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040018894 elsif(not checkDump(2, "2.1"))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040018895 {
18896 $WORD_SIZE{2} = $WORD_SIZE{1};
18897 printMsg("WARNING", "set WORD size to ".$WORD_SIZE{1}." bytes");
18898 }
18899 }
18900 elsif(not $WORD_SIZE{1}
18901 and not $WORD_SIZE{2})
18902 { # support for old ABI dumps
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040018903 $WORD_SIZE{1} = "4";
18904 $WORD_SIZE{2} = "4";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040018905 }
18906 if($Descriptor{1}{"Dump"})
18907 { # support for old ABI dumps
18908 prepareTypes(1);
18909 }
18910 if($Descriptor{2}{"Dump"})
18911 { # support for old ABI dumps
18912 prepareTypes(2);
18913 }
18914 if($AppPath and not keys(%{$Symbol_Library{1}})) {
18915 printMsg("WARNING", "the application ".get_filename($AppPath)." has no symbols imported from the $SLIB_TYPE libraries");
18916 }
18917 # started to process input data
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040018918 if(not $CheckObjectsOnly)
18919 {
18920 if($Descriptor{1}{"Headers"}
18921 and not $Descriptor{1}{"Dump"}) {
18922 readHeaders(1);
18923 }
18924 if($Descriptor{2}{"Headers"}
18925 and not $Descriptor{2}{"Dump"}) {
18926 readHeaders(2);
18927 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040018928 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +040018929
18930 # clean memory
18931 %SystemHeaders = ();
18932 %mangled_name_gcc = ();
18933
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040018934 prepareSymbols(1);
18935 prepareSymbols(2);
Andrey Ponomarenko16934472012-03-29 15:37:04 +040018936
Andrey Ponomarenko85043792012-05-14 16:48:07 +040018937 # clean memory
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040018938 %SymbolInfo = ();
Andrey Ponomarenko16934472012-03-29 15:37:04 +040018939
18940 # Virtual Tables
18941 registerVTable(1);
18942 registerVTable(2);
18943
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040018944 if(not checkDump(1, "1.22")
18945 and checkDump(2, "1.22"))
Andrey Ponomarenko16934472012-03-29 15:37:04 +040018946 { # support for old ABI dumps
18947 foreach my $ClassName (keys(%{$VirtualTable{2}}))
18948 {
18949 if($ClassName=~/</)
18950 { # templates
18951 if(not defined $VirtualTable{1}{$ClassName})
18952 { # synchronize
18953 delete($VirtualTable{2}{$ClassName});
18954 }
18955 }
18956 }
18957 }
18958
18959 registerOverriding(1);
18960 registerOverriding(2);
18961
18962 setVirtFuncPositions(1);
18963 setVirtFuncPositions(2);
18964
18965 # Other
18966 addParamNames(1);
18967 addParamNames(2);
18968
18969 detectChangedTypedefs();
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040018970}
18971
18972sub compareAPIs($)
18973{
18974 my $Level = $_[0];
18975 readRules($Level);
18976 if($Level eq "Binary") {
18977 printMsg("INFO", "comparing ABIs ...");
18978 }
18979 else {
18980 printMsg("INFO", "comparing APIs ...");
18981 }
18982 if($CheckHeadersOnly
18983 or $Level eq "Source")
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040018984 { # added/removed in headers
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040018985 detectAdded_H($Level);
18986 detectRemoved_H($Level);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040018987 }
18988 else
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040018989 { # added/removed in libs
18990 detectAdded($Level);
18991 detectRemoved($Level);
18992 }
18993 if(not $CheckObjectsOnly)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040018994 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040018995 mergeSignatures($Level);
18996 if(keys(%{$CheckedSymbols{$Level}})) {
18997 mergeConstants($Level);
18998 }
18999 }
19000 if($CheckHeadersOnly
19001 or $Level eq "Source")
19002 { # added/removed in headers
19003 mergeHeaders($Level);
19004 }
19005 else
19006 { # added/removed in libs
19007 mergeLibs($Level);
19008 if($CheckImpl
19009 and $Level eq "Binary") {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040019010 mergeImpl();
19011 }
19012 }
19013}
19014
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040019015sub writeOpts()
19016{
19017 my %Opts = (
19018 "OStarget"=>$OStarget,
19019 "Debug"=>$Debug,
19020 "Quiet"=>$Quiet,
19021 "LogMode"=>$LogMode,
19022 "CheckHeadersOnly"=>$CheckHeadersOnly,
19023
19024 "SystemRoot"=>$SystemRoot,
19025 "MODULES_DIR"=>$MODULES_DIR,
19026 "GCC_PATH"=>$GCC_PATH,
19027 "TargetSysInfo"=>$TargetSysInfo,
19028 "CrossPrefix"=>$CrossPrefix,
19029 "TargetLibraryName"=>$TargetLibraryName,
19030 "CrossGcc"=>$CrossGcc,
19031 "UseStaticLibs"=>$UseStaticLibs,
19032 "NoStdInc"=>$NoStdInc
19033 );
19034 return \%Opts;
19035}
19036
19037sub get_CoreError($)
19038{
19039 my %CODE_ERROR = reverse(%ERROR_CODE);
19040 return $CODE_ERROR{$_[0]};
19041}
19042
19043sub scenario()
19044{
19045 if($StdOut)
19046 { # enable quiet mode
19047 $Quiet = 1;
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040019048 $JoinReport = 1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040019049 }
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040019050 if(not $LogMode)
19051 { # default
19052 $LogMode = "w";
19053 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040019054 if($UserLang)
19055 { # --lang=C++
19056 $UserLang = uc($UserLang);
19057 $COMMON_LANGUAGE{1}=$UserLang;
19058 $COMMON_LANGUAGE{2}=$UserLang;
19059 }
19060 if($LoggingPath)
19061 {
19062 $OutputLogPath{1} = $LoggingPath;
19063 $OutputLogPath{2} = $LoggingPath;
19064 if($Quiet) {
19065 $COMMON_LOG_PATH = $LoggingPath;
19066 }
19067 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040019068 if($BinaryOnly and $SourceOnly)
19069 { # both --binary and --source
19070 # is the default mode
19071 $DoubleReport = 1;
19072 $JoinReport = 0;
19073 $BinaryOnly = 0;
19074 $SourceOnly = 0;
19075 if($OutputReportPath)
19076 { # --report-path
19077 $DoubleReport = 0;
19078 $JoinReport = 1;
19079 }
19080 }
19081 elsif($BinaryOnly or $SourceOnly)
19082 { # --binary or --source
19083 $DoubleReport = 0;
19084 $JoinReport = 0;
19085 }
19086 if($UseXML)
19087 { # --xml option
19088 $ReportFormat = "xml";
19089 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040019090 if($ReportFormat)
19091 { # validate
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040019092 $ReportFormat = lc($ReportFormat);
19093 if($ReportFormat!~/\A(xml|html|htm)\Z/) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040019094 exitStatus("Error", "unknown format \'$ReportFormat\'");
19095 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040019096 if($ReportFormat eq "htm")
19097 { # HTM == HTML
19098 $ReportFormat = "html";
19099 }
19100 elsif($ReportFormat eq "xml")
19101 { # --report-format=XML equal to --xml
19102 $UseXML = 1;
19103 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040019104 }
19105 else
19106 { # default: HTML
19107 $ReportFormat = "html";
19108 }
19109 if($Quiet and $LogMode!~/a|n/)
19110 { # --quiet log
19111 if(-f $COMMON_LOG_PATH) {
19112 unlink($COMMON_LOG_PATH);
19113 }
19114 }
19115 if($TestTool and $UseDumps)
19116 { # --test && --use-dumps == --test-dump
19117 $TestDump = 1;
19118 }
19119 if($Help) {
19120 HELP_MESSAGE();
19121 exit(0);
19122 }
19123 if($InfoMsg) {
19124 INFO_MESSAGE();
19125 exit(0);
19126 }
19127 if($ShowVersion) {
19128 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.");
19129 exit(0);
19130 }
19131 if($DumpVersion) {
19132 printMsg("INFO", $TOOL_VERSION);
19133 exit(0);
19134 }
19135 if($ExtendedCheck) {
19136 $CheckHeadersOnly = 1;
19137 }
19138 if($SystemRoot_Opt)
19139 { # user defined root
19140 if(not -e $SystemRoot_Opt) {
19141 exitStatus("Access_Error", "can't access \'$SystemRoot\'");
19142 }
19143 $SystemRoot = $SystemRoot_Opt;
19144 $SystemRoot=~s/[\/]+\Z//g;
19145 if($SystemRoot) {
19146 $SystemRoot = get_abs_path($SystemRoot);
19147 }
19148 }
19149 $Data::Dumper::Sortkeys = 1;
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +040019150
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040019151 if($SortDump)
19152 {
19153 $Data::Dumper::Useperl = 1;
19154 $Data::Dumper::Sortkeys = \&dump_sorting;
19155 }
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +040019156
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040019157 if($TargetLibsPath)
19158 {
19159 if(not -f $TargetLibsPath) {
19160 exitStatus("Access_Error", "can't access file \'$TargetLibsPath\'");
19161 }
19162 foreach my $Lib (split(/\s*\n\s*/, readFile($TargetLibsPath))) {
19163 $TargetLibs{$Lib} = 1;
19164 }
19165 }
19166 if($TargetHeadersPath)
19167 { # --headers-list
19168 if(not -f $TargetHeadersPath) {
19169 exitStatus("Access_Error", "can't access file \'$TargetHeadersPath\'");
19170 }
19171 foreach my $Header (split(/\s*\n\s*/, readFile($TargetHeadersPath)))
19172 {
19173 $TargetHeaders{1}{$Header} = 1;
19174 $TargetHeaders{2}{$Header} = 1;
19175 }
19176 }
19177 if($TargetHeader)
19178 { # --header
19179 $TargetHeaders{1}{$TargetHeader} = 1;
19180 $TargetHeaders{2}{$TargetHeader} = 1;
19181 }
19182 if($TestTool
19183 or $TestDump)
19184 { # --test, --test-dump
19185 detect_default_paths("bin|gcc"); # to compile libs
19186 loadModule("RegTests");
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040019187 testTool($TestDump, $Debug, $Quiet, $ExtendedCheck, $LogMode,
19188 $ReportFormat, $LIB_EXT, $GCC_PATH, $Browse, $OpenReport, $SortDump);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040019189 exit(0);
19190 }
19191 if($DumpSystem)
19192 { # --dump-system
19193 loadModule("SysCheck");
19194 if($DumpSystem=~/\.xml\Z/)
19195 { # system XML descriptor
19196 if(not -f $DumpSystem) {
19197 exitStatus("Access_Error", "can't access file \'$DumpSystem\'");
19198 }
19199 my $Ret = readSystemDescriptor(readFile($DumpSystem));
19200 foreach (@{$Ret->{"Tools"}}) {
19201 $SystemPaths{"bin"}{$_} = 1;
19202 $TargetTools{$_}=1;
19203 }
19204 if($Ret->{"CrossPrefix"}) {
19205 $CrossPrefix = $Ret->{"CrossPrefix"};
19206 }
19207 }
19208 elsif($SystemRoot_Opt)
19209 { # -sysroot "/" option
19210 # default target: /usr/lib, /usr/include
19211 # search libs: /usr/lib and /lib
19212 if(not -e $SystemRoot."/usr/lib") {
19213 exitStatus("Access_Error", "can't access '".$SystemRoot."/usr/lib'");
19214 }
19215 if(not -e $SystemRoot."/lib") {
19216 exitStatus("Access_Error", "can't access '".$SystemRoot."/lib'");
19217 }
19218 if(not -e $SystemRoot."/usr/include") {
19219 exitStatus("Access_Error", "can't access '".$SystemRoot."/usr/include'");
19220 }
19221 readSystemDescriptor("
19222 <name>
19223 $DumpSystem
19224 </name>
19225 <headers>
19226 $SystemRoot/usr/include
19227 </headers>
19228 <libs>
19229 $SystemRoot/usr/lib
19230 </libs>
19231 <search_libs>
19232 $SystemRoot/lib
19233 </search_libs>");
19234 }
19235 else {
19236 exitStatus("Error", "-sysroot <dirpath> option should be specified, usually it's \"/\"");
19237 }
19238 detect_default_paths("bin|gcc"); # to check symbols
19239 if($OStarget eq "windows")
19240 { # to run dumpbin.exe
19241 # and undname.exe
19242 check_win32_env();
19243 }
19244 dumpSystem(writeOpts());
19245 exit(0);
19246 }
19247 if($CmpSystems)
19248 { # --cmp-systems
19249 detect_default_paths("bin"); # to extract dumps
19250 loadModule("SysCheck");
19251 cmpSystems($Descriptor{1}{"Path"}, $Descriptor{2}{"Path"}, writeOpts());
19252 exit(0);
19253 }
19254 if($GenerateTemplate) {
19255 generateTemplate();
19256 exit(0);
19257 }
19258 if(not $TargetLibraryName) {
19259 exitStatus("Error", "library name is not selected (option -l <name>)");
19260 }
19261 else
19262 { # validate library name
19263 if($TargetLibraryName=~/[\*\/\\]/) {
19264 exitStatus("Error", "\"\\\", \"\/\" and \"*\" symbols are not allowed in the library name");
19265 }
19266 }
19267 if(not $TargetLibraryFName) {
19268 $TargetLibraryFName = $TargetLibraryName;
19269 }
19270 if($CheckHeadersOnly_Opt and $CheckObjectsOnly_Opt) {
19271 exitStatus("Error", "you can't specify both -headers-only and -objects-only options at the same time");
19272 }
19273 if($SymbolsListPath)
19274 {
19275 if(not -f $SymbolsListPath) {
19276 exitStatus("Access_Error", "can't access file \'$SymbolsListPath\'");
19277 }
19278 foreach my $Interface (split(/\s*\n\s*/, readFile($SymbolsListPath))) {
19279 $SymbolsList{$Interface} = 1;
19280 }
19281 }
19282 if($SkipHeadersPath)
19283 {
19284 if(not -f $SkipHeadersPath) {
19285 exitStatus("Access_Error", "can't access file \'$SkipHeadersPath\'");
19286 }
19287 foreach my $Path (split(/\s*\n\s*/, readFile($SkipHeadersPath)))
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040019288 { # register for both versions
19289 $SkipHeadersList{1}{$Path} = 1;
19290 $SkipHeadersList{2}{$Path} = 1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040019291 my ($CPath, $Type) = classifyPath($Path);
19292 $SkipHeaders{1}{$Type}{$CPath} = 1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040019293 $SkipHeaders{2}{$Type}{$CPath} = 1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040019294 }
19295 }
19296 if($ParamNamesPath)
19297 {
19298 if(not -f $ParamNamesPath) {
19299 exitStatus("Access_Error", "can't access file \'$ParamNamesPath\'");
19300 }
19301 foreach my $Line (split(/\n/, readFile($ParamNamesPath)))
19302 {
19303 if($Line=~s/\A(\w+)\;//)
19304 {
19305 my $Interface = $1;
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040019306 if($Line=~/;(\d+);/)
19307 {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040019308 while($Line=~s/(\d+);(\w+)//) {
19309 $AddIntParams{$Interface}{$1}=$2;
19310 }
19311 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040019312 else
19313 {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040019314 my $Num = 0;
19315 foreach my $Name (split(/;/, $Line)) {
19316 $AddIntParams{$Interface}{$Num++}=$Name;
19317 }
19318 }
19319 }
19320 }
19321 }
19322 if($AppPath)
19323 {
19324 if(not -f $AppPath) {
19325 exitStatus("Access_Error", "can't access file \'$AppPath\'");
19326 }
Andrey Ponomarenko16934472012-03-29 15:37:04 +040019327 foreach my $Interface (readSymbols_App($AppPath)) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040019328 $SymbolsList_App{$Interface} = 1;
19329 }
19330 }
19331 if($DumpAPI)
19332 { # --dump-abi
19333 # make an API dump
19334 create_ABI_Dump();
19335 exit($COMPILE_ERRORS);
19336 }
19337 # default: compare APIs
19338 # -d1 <path>
19339 # -d2 <path>
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040019340 compareInit();
19341 if($JoinReport or $DoubleReport)
19342 {
19343 compareAPIs("Binary");
19344 compareAPIs("Source");
19345 }
19346 elsif($BinaryOnly) {
19347 compareAPIs("Binary");
19348 }
19349 elsif($SourceOnly) {
19350 compareAPIs("Source");
19351 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040019352 exitReport();
19353}
19354
19355scenario();