blob: 4452781dfb6bc57bfeba67431f655d81cddf7926 [file] [log] [blame]
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04001#!/usr/bin/perl
2###########################################################################
Andrey Ponomarenkoa01311b2012-06-08 17:20:02 +04003# ABI Compliance Checker (ACC) 1.97.8
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 Ponomarenkoa01311b2012-06-08 17:20:02 +040058my $TOOL_VERSION = "1.97.8";
Andrey Ponomarenkob8d203d2012-05-25 18:11:07 +040059my $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
Andrey Ponomarenkoa01311b2012-06-08 17:20:02 +0400791<add_namespaces>
792 /* The list of namespaces that should be added to the alanysis
793 if the tool cannot find them automatically, one per line */
794</add_namespaces>
795
Andrey Ponomarenkoab282102012-03-11 11:57:02 +0400796<skip_types>
797 /* The list of data types, that
798 should not be checked, one per line */
799</skip_types>
800
801<skip_symbols>
802 /* The list of functions (mangled/symbol names in C++),
803 that should not be checked, one per line */
804</skip_symbols>
805
806<skip_namespaces>
807 /* The list of C++ namespaces, that
808 should not be checked, one per line */
809</skip_namespaces>
810
811<skip_constants>
812 /* The list of constants that should
813 not be checked, one name per line */
814</skip_constants>
815
816<skip_headers>
817 /* The list of header files and/or directories
818 with header files that should not be checked, one per line */
819</skip_headers>
820
821<skip_libs>
822 /* The list of shared libraries and/or directories
823 with shared libraries that should not be checked, one per line */
824</skip_libs>
825
826<skip_including>
827 /* The list of header files, that cannot be included
828 directly (or non-self compiled ones), one per line */
829</skip_including>
830
831<search_headers>
832 /* List of directories to be searched
833 for header files to automatically
834 generate include paths, one per line. */
835</search_headers>
836
837<search_libs>
838 /* List of directories to be searched
839 for shared librariess to resolve
840 dependencies, one per line */
841</search_libs>
842
843<tools>
844 /* List of directories with tools used
845 for analysis (GCC toolchain), one per line */
846</tools>
847
848<cross_prefix>
849 /* GCC toolchain prefix.
850 Examples:
851 arm-linux-gnueabi
852 arm-none-symbianelf */
853</cross_prefix>
854
855</descriptor>";
856
857my %Operator_Indication = (
858 "not" => "~",
859 "assign" => "=",
860 "andassign" => "&=",
861 "orassign" => "|=",
862 "xorassign" => "^=",
863 "or" => "|",
864 "xor" => "^",
865 "addr" => "&",
866 "and" => "&",
867 "lnot" => "!",
868 "eq" => "==",
869 "ne" => "!=",
870 "lt" => "<",
871 "lshift" => "<<",
872 "lshiftassign" => "<<=",
873 "rshiftassign" => ">>=",
874 "call" => "()",
875 "mod" => "%",
876 "modassign" => "%=",
877 "subs" => "[]",
878 "land" => "&&",
879 "lor" => "||",
880 "rshift" => ">>",
881 "ref" => "->",
882 "le" => "<=",
883 "deref" => "*",
884 "mult" => "*",
885 "preinc" => "++",
886 "delete" => " delete",
887 "vecnew" => " new[]",
888 "vecdelete" => " delete[]",
889 "predec" => "--",
890 "postinc" => "++",
891 "postdec" => "--",
892 "plusassign" => "+=",
893 "plus" => "+",
894 "minus" => "-",
895 "minusassign" => "-=",
896 "gt" => ">",
897 "ge" => ">=",
898 "new" => " new",
899 "multassign" => "*=",
900 "divassign" => "/=",
901 "div" => "/",
902 "neg" => "-",
903 "pos" => "+",
904 "memref" => "->*",
905 "compound" => "," );
906
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +0400907my %UnknownOperator;
908
909my %NodeType= (
910 "array_type" => "Array",
911 "binfo" => "Other",
912 "boolean_type" => "Intrinsic",
913 "complex_type" => "Intrinsic",
914 "const_decl" => "Other",
915 "enumeral_type" => "Enum",
916 "field_decl" => "Other",
917 "function_decl" => "Other",
918 "function_type" => "FunctionType",
919 "identifier_node" => "Other",
920 "integer_cst" => "Other",
921 "integer_type" => "Intrinsic",
922 "method_type" => "MethodType",
923 "namespace_decl" => "Other",
924 "parm_decl" => "Other",
925 "pointer_type" => "Pointer",
926 "real_cst" => "Other",
927 "real_type" => "Intrinsic",
928 "record_type" => "Struct",
929 "reference_type" => "Ref",
930 "string_cst" => "Other",
931 "template_decl" => "Other",
932 "template_type_parm" => "Other",
933 "tree_list" => "Other",
934 "tree_vec" => "Other",
935 "type_decl" => "Other",
936 "union_type" => "Union",
937 "var_decl" => "Other",
938 "void_type" => "Intrinsic",
939 # "nop_expr" => "Other",
940 # "addr_expr" => "Other",
941 "offset_type" => "Other" );
942
Andrey Ponomarenkoab282102012-03-11 11:57:02 +0400943my %CppKeywords_C = map {$_=>1} (
944 # C++ 2003 keywords
945 "public",
946 "protected",
947 "private",
948 "default",
949 "template",
950 "new",
951 #"asm",
952 "dynamic_cast",
953 "auto",
954 "try",
955 "namespace",
956 "typename",
957 "using",
958 "reinterpret_cast",
959 "friend",
960 "class",
961 "virtual",
962 "const_cast",
963 "mutable",
964 "static_cast",
965 "export",
966 # C++0x keywords
967 "noexcept",
968 "nullptr",
969 "constexpr",
970 "static_assert",
971 "explicit",
972 # cannot be used as a macro name
973 # as it is an operator in C++
974 "and",
975 #"and_eq",
976 "not",
977 #"not_eq",
978 "or"
979 #"or_eq",
980 #"bitand",
981 #"bitor",
982 #"xor",
983 #"xor_eq",
984 #"compl"
985);
986
987my %CppKeywords_F = map {$_=>1} (
988 "delete",
989 "catch",
990 "alignof",
991 "thread_local",
992 "decltype",
993 "typeid"
994);
995
996my %CppKeywords_O = map {$_=>1} (
997 "bool",
998 "register",
999 "inline",
1000 "operator"
1001);
1002
1003my %CppKeywords_A = map {$_=>1} (
1004 "this",
1005 "throw"
1006);
1007
1008foreach (keys(%CppKeywords_C),
1009keys(%CppKeywords_F),
1010keys(%CppKeywords_O)) {
1011 $CppKeywords_A{$_}=1;
1012}
1013
1014# Header file extensions as described by gcc
1015my $HEADER_EXT = "h|hh|hp|hxx|hpp|h\\+\\+";
1016
1017my %IntrinsicMangling = (
1018 "void" => "v",
1019 "bool" => "b",
1020 "wchar_t" => "w",
1021 "char" => "c",
1022 "signed char" => "a",
1023 "unsigned char" => "h",
1024 "short" => "s",
1025 "unsigned short" => "t",
1026 "int" => "i",
1027 "unsigned int" => "j",
1028 "long" => "l",
1029 "unsigned long" => "m",
1030 "long long" => "x",
1031 "__int64" => "x",
1032 "unsigned long long" => "y",
1033 "__int128" => "n",
1034 "unsigned __int128" => "o",
1035 "float" => "f",
1036 "double" => "d",
1037 "long double" => "e",
1038 "__float80" => "e",
1039 "__float128" => "g",
1040 "..." => "z"
1041);
1042
1043my %StdcxxMangling = (
1044 "3std"=>"St",
1045 "3std9allocator"=>"Sa",
1046 "3std12basic_string"=>"Sb",
1047 "3std12basic_stringIcE"=>"Ss",
1048 "3std13basic_istreamIcE"=>"Si",
1049 "3std13basic_ostreamIcE"=>"So",
1050 "3std14basic_iostreamIcE"=>"Sd"
1051);
1052
1053my %ConstantSuffix = (
1054 "unsigned int"=>"u",
1055 "long"=>"l",
1056 "unsigned long"=>"ul",
1057 "long long"=>"ll",
1058 "unsigned long long"=>"ull"
1059);
1060
1061my %ConstantSuffixR =
1062reverse(%ConstantSuffix);
1063
1064my %OperatorMangling = (
1065 "~" => "co",
1066 "=" => "aS",
1067 "|" => "or",
1068 "^" => "eo",
1069 "&" => "an",#ad (addr)
1070 "==" => "eq",
1071 "!" => "nt",
1072 "!=" => "ne",
1073 "<" => "lt",
1074 "<=" => "le",
1075 "<<" => "ls",
1076 "<<=" => "lS",
1077 ">" => "gt",
1078 ">=" => "ge",
1079 ">>" => "rs",
1080 ">>=" => "rS",
1081 "()" => "cl",
1082 "%" => "rm",
1083 "[]" => "ix",
1084 "&&" => "aa",
1085 "||" => "oo",
1086 "*" => "ml",#de (deref)
1087 "++" => "pp",#
1088 "--" => "mm",#
1089 "new" => "nw",
1090 "delete" => "dl",
1091 "new[]" => "na",
1092 "delete[]" => "da",
1093 "+=" => "pL",
1094 "+" => "pl",#ps (pos)
1095 "-" => "mi",#ng (neg)
1096 "-=" => "mI",
1097 "*=" => "mL",
1098 "/=" => "dV",
1099 "&=" => "aN",
1100 "|=" => "oR",
1101 "%=" => "rM",
1102 "^=" => "eO",
1103 "/" => "dv",
1104 "->*" => "pm",
1105 "->" => "pt",#rf (ref)
1106 "," => "cm",
1107 "?" => "qu",
1108 "." => "dt",
1109 "sizeof"=> "sz"#st
1110);
1111
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04001112my %Intrinsic_Keywords = map {$_=>1} (
1113 "true",
1114 "false",
1115 "_Bool",
1116 "_Complex",
1117 "const",
1118 "int",
1119 "long",
1120 "void",
1121 "short",
1122 "float",
1123 "volatile",
1124 "restrict",
1125 "unsigned",
1126 "signed",
1127 "char",
1128 "double",
1129 "class",
1130 "struct",
1131 "union",
1132 "enum"
1133);
1134
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04001135my %GlibcHeader = map {$_=>1} (
1136 "aliases.h",
1137 "argp.h",
1138 "argz.h",
1139 "assert.h",
1140 "cpio.h",
1141 "ctype.h",
1142 "dirent.h",
1143 "envz.h",
1144 "errno.h",
1145 "error.h",
1146 "execinfo.h",
1147 "fcntl.h",
1148 "fstab.h",
1149 "ftw.h",
1150 "glob.h",
1151 "grp.h",
1152 "iconv.h",
1153 "ifaddrs.h",
1154 "inttypes.h",
1155 "langinfo.h",
1156 "limits.h",
1157 "link.h",
1158 "locale.h",
1159 "malloc.h",
1160 "math.h",
1161 "mntent.h",
1162 "monetary.h",
1163 "nl_types.h",
1164 "obstack.h",
1165 "printf.h",
1166 "pwd.h",
1167 "regex.h",
1168 "sched.h",
1169 "search.h",
1170 "setjmp.h",
1171 "shadow.h",
1172 "signal.h",
1173 "spawn.h",
1174 "stdarg.h",
1175 "stdint.h",
1176 "stdio.h",
1177 "stdlib.h",
1178 "string.h",
1179 "tar.h",
1180 "termios.h",
1181 "time.h",
1182 "ulimit.h",
1183 "unistd.h",
1184 "utime.h",
1185 "wchar.h",
1186 "wctype.h",
1187 "wordexp.h" );
1188
1189my %GlibcDir = map {$_=>1} (
1190 "arpa",
1191 "bits",
1192 "gnu",
1193 "netinet",
1194 "net",
1195 "nfs",
1196 "rpc",
1197 "sys",
1198 "linux" );
1199
1200my %LocalIncludes = map {$_=>1} (
1201 "/usr/local/include",
1202 "/usr/local" );
1203
1204my %OS_AddPath=(
1205# These paths are needed if the tool cannot detect them automatically
1206 "macos"=>{
1207 "include"=>{
1208 "/Library"=>1,
1209 "/Developer/usr/include"=>1
1210 },
1211 "lib"=>{
1212 "/Library"=>1,
1213 "/Developer/usr/lib"=>1
1214 },
1215 "bin"=>{
1216 "/Developer/usr/bin"=>1
1217 }
1218 },
1219 "beos"=>{
1220 # Haiku has GCC 2.95.3 by default
1221 # try to find GCC>=3.0 in /boot/develop/abi
1222 "include"=>{
1223 "/boot/common"=>1,
1224 "/boot/develop"=>1},
1225 "lib"=>{
1226 "/boot/common/lib"=>1,
1227 "/boot/system/lib"=>1,
1228 "/boot/apps"=>1},
1229 "bin"=>{
1230 "/boot/common/bin"=>1,
1231 "/boot/system/bin"=>1,
1232 "/boot/develop/abi"=>1
1233 }
1234}
1235);
1236
1237my %Slash_Type=(
1238 "default"=>"/",
1239 "windows"=>"\\"
1240);
1241
1242my $SLASH = $Slash_Type{$OSgroup}?$Slash_Type{$OSgroup}:$Slash_Type{"default"};
1243
1244# Global Variables
1245my %COMMON_LANGUAGE=(
1246 1 => "C",
1247 2 => "C" );
1248
1249my $MAX_COMMAND_LINE_ARGUMENTS = 4096;
1250my (%WORD_SIZE, %CPU_ARCH, %GCC_VERSION);
1251
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04001252my $STDCXX_TESTING = 0;
1253my $GLIBC_TESTING = 0;
1254
1255my $CheckHeadersOnly = $CheckHeadersOnly_Opt;
1256my $CheckObjectsOnly = $CheckObjectsOnly_Opt;
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04001257my $TargetComponent;
1258
1259# Set Target Component Name
1260if($TargetComponent_Opt) {
1261 $TargetComponent = lc($TargetComponent_Opt);
1262}
1263else
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04001264{ # default: library
1265 # other components: header, system, ...
1266 $TargetComponent = "library";
1267}
1268
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04001269my $TOP_REF = "<a style='font-size:11px;' href='#Top'>to the top</a>";
1270
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04001271my $SystemRoot;
1272
1273my $MAIN_CPP_DIR;
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04001274my %RESULT;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04001275my %LOG_PATH;
1276my %DEBUG_PATH;
1277my %Cache;
1278my %LibInfo;
1279my $COMPILE_ERRORS = 0;
1280my %CompilerOptions;
1281my %CheckedDyLib;
1282my $TargetLibraryShortName = parse_libname($TargetLibraryName, "shortest", $OSgroup);
1283
1284# Constants (#defines)
1285my %Constants;
1286my %SkipConstants;
1287
1288# Types
1289my %TypeInfo;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04001290my %TemplateInstance;
Andrey Ponomarenko85043792012-05-14 16:48:07 +04001291my %TemplateDecl;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04001292my %SkipTypes = (
1293 "1"=>{},
1294 "2"=>{} );
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04001295my %CheckedTypes;
1296my %TName_Tid;
1297my %EnumMembName_Id;
1298my %NestedNameSpaces = (
1299 "1"=>{},
1300 "2"=>{} );
1301my %UsedType;
1302my %VirtualTable;
Andrey Ponomarenko16934472012-03-29 15:37:04 +04001303my %VirtualTable_Model;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04001304my %ClassVTable;
1305my %ClassVTable_Content;
1306my %VTableClass;
1307my %AllocableClass;
1308my %ClassMethods;
Andrey Ponomarenko16934472012-03-29 15:37:04 +04001309my %ClassNames;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04001310my %Class_SubClasses;
1311my %OverriddenMethods;
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04001312my $MAX_ID = 0;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04001313
1314# Typedefs
1315my %Typedef_BaseName;
1316my %Typedef_Tr;
1317my %Typedef_Eq;
1318my %StdCxxTypedef;
1319my %MissedTypedef;
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04001320my %MissedBase;
1321my %MissedBase_R;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04001322
1323# Symbols
1324my %SymbolInfo;
1325my %tr_name;
1326my %mangled_name_gcc;
1327my %mangled_name;
1328my %SkipSymbols = (
1329 "1"=>{},
1330 "2"=>{} );
1331my %SkipNameSpaces = (
1332 "1"=>{},
1333 "2"=>{} );
Andrey Ponomarenkoa01311b2012-06-08 17:20:02 +04001334my %AddNameSpaces = (
1335 "1"=>{},
1336 "2"=>{} );
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04001337my %SymbolsList;
1338my %SymbolsList_App;
1339my %CheckedSymbols;
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04001340my %Symbol_Library = (
1341 "1"=>{},
1342 "2"=>{} );
1343my %Library_Symbol = (
1344 "1"=>{},
1345 "2"=>{} );
1346my %DepSymbol_Library = (
1347 "1"=>{},
1348 "2"=>{} );
1349my %DepLibrary_Symbol = (
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04001350 "1"=>{},
1351 "2"=>{} );
1352my %MangledNames;
1353my %AddIntParams;
1354my %Interface_Impl;
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04001355my %GlobalDataObject;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04001356
1357# Headers
1358my %Include_Preamble;
1359my %Registered_Headers;
1360my %HeaderName_Paths;
1361my %Header_Dependency;
1362my %Include_Neighbors;
1363my %Include_Paths;
1364my %INC_PATH_AUTODETECT = (
1365 "1"=>1,
1366 "2"=>1 );
1367my %Add_Include_Paths;
1368my %Skip_Include_Paths;
1369my %RegisteredDirs;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04001370my %Header_ErrorRedirect;
1371my %Header_Includes;
1372my %Header_ShouldNotBeUsed;
1373my %RecursiveIncludes;
1374my %Header_Include_Prefix;
1375my %SkipHeaders;
1376my %SkipHeadersList=(
1377 "1"=>{},
1378 "2"=>{} );
1379my %SkipLibs;
1380my %Include_Order;
1381my %TUnit_NameSpaces;
1382
1383my %C99Mode = (
1384 "1"=>0,
1385 "2"=>0 );
1386my %AutoPreambleMode = (
1387 "1"=>0,
1388 "2"=>0 );
1389my %MinGWMode = (
1390 "1"=>0,
1391 "2"=>0 );
1392
1393# Shared Objects
1394my %DyLib_DefaultPath;
1395my %InputObject_Paths;
1396my %RegisteredObjDirs;
1397
1398# System Objects
1399my %SystemObjects;
1400my %DefaultLibPaths;
1401
1402# System Headers
1403my %SystemHeaders;
1404my %DefaultCppPaths;
1405my %DefaultGccPaths;
1406my %DefaultIncPaths;
1407my %DefaultCppHeader;
1408my %DefaultGccHeader;
1409my %UserIncPath;
1410
1411# Merging
1412my %CompleteSignature;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04001413my $Version;
1414my %AddedInt;
1415my %RemovedInt;
1416my %AddedInt_Virt;
1417my %RemovedInt_Virt;
1418my %VirtualReplacement;
1419my %ChangedTypedef;
1420my %CompatRules;
1421my %IncompleteRules;
1422my %UnknownRules;
Andrey Ponomarenko16934472012-03-29 15:37:04 +04001423my %VTableChanged_M;
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04001424my %ExtendedSymbols;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04001425my %ReturnedClass;
1426my %ParamClass;
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04001427my %SourceAlternative;
1428my %SourceAlternative_B;
1429my %SourceReplacement;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04001430
1431# OS Compliance
1432my %TargetLibs;
1433my %TargetHeaders;
1434
1435# OS Specifics
1436my $OStarget = $OSgroup;
1437my %TargetTools;
1438
1439# Compliance Report
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04001440my %Type_MaxSeverity;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04001441
1442# Recursion locks
1443my @RecurLib;
1444my @RecurSymlink;
1445my @RecurTypes;
1446my @RecurInclude;
1447my @RecurConstant;
1448
1449# System
1450my %SystemPaths;
1451my %DefaultBinPaths;
1452my $GCC_PATH;
1453
1454# Symbols versioning
1455my %SymVer = (
1456 "1"=>{},
1457 "2"=>{} );
1458
1459# Problem descriptions
1460my %CompatProblems;
1461my %ProblemsWithConstants;
1462my %ImplProblems;
1463my %TotalAffected;
1464
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04001465# Reports
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04001466my $ContentID = 1;
1467my $ContentSpanStart = "<span class=\"section\" onclick=\"javascript:showContent(this, 'CONTENT_ID')\">\n";
1468my $ContentSpanStart_Affected = "<span class=\"section_affected\" onclick=\"javascript:showContent(this, 'CONTENT_ID')\">\n";
1469my $ContentSpanStart_Info = "<span class=\"section_info\" onclick=\"javascript:showContent(this, 'CONTENT_ID')\">\n";
1470my $ContentSpanEnd = "</span>\n";
1471my $ContentDivStart = "<div id=\"CONTENT_ID\" style=\"display:none;\">\n";
1472my $ContentDivEnd = "</div>\n";
1473my $Content_Counter = 0;
1474
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04001475# Modes
1476my $JoinReport = 1;
1477my $DoubleReport = 0;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04001478
1479sub get_Modules()
1480{
1481 my $TOOL_DIR = get_dirname($0);
1482 if(not $TOOL_DIR)
1483 { # patch for MS Windows
1484 $TOOL_DIR = ".";
1485 }
1486 my @SEARCH_DIRS = (
1487 # tool's directory
1488 abs_path($TOOL_DIR),
1489 # relative path to modules
1490 abs_path($TOOL_DIR)."/../share/abi-compliance-checker",
1491 # system directory
1492 "ACC_MODULES_INSTALL_PATH"
1493 );
1494 foreach my $DIR (@SEARCH_DIRS)
1495 {
1496 if(not is_abs($DIR))
1497 { # relative path
1498 $DIR = abs_path($TOOL_DIR)."/".$DIR;
1499 }
1500 if(-d $DIR."/modules") {
1501 return $DIR."/modules";
1502 }
1503 }
1504 exitStatus("Module_Error", "can't find modules");
1505}
1506
1507sub loadModule($)
1508{
1509 my $Name = $_[0];
1510 my $Path = $MODULES_DIR."/Internals/$Name.pm";
1511 if(not -f $Path) {
1512 exitStatus("Module_Error", "can't access \'$Path\'");
1513 }
1514 require $Path;
1515}
1516
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04001517sub showPos($)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04001518{
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04001519 my $Number = $_[0];
1520 if(not $Number) {
1521 $Number = 1;
1522 }
1523 else {
1524 $Number = int($Number)+1;
1525 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04001526 if($Number>3) {
1527 return $Number."th";
1528 }
1529 elsif($Number==1) {
1530 return "1st";
1531 }
1532 elsif($Number==2) {
1533 return "2nd";
1534 }
1535 elsif($Number==3) {
1536 return "3rd";
1537 }
1538 else {
1539 return $Number;
1540 }
1541}
1542
1543sub search_Tools($)
1544{
1545 my $Name = $_[0];
1546 return "" if(not $Name);
1547 if(my @Paths = keys(%TargetTools))
1548 {
1549 foreach my $Path (@Paths)
1550 {
1551 if(-f joinPath($Path, $Name)) {
1552 return joinPath($Path, $Name);
1553 }
1554 if($CrossPrefix)
1555 { # user-defined prefix (arm-none-symbianelf, ...)
1556 my $Candidate = joinPath($Path, $CrossPrefix."-".$Name);
1557 if(-f $Candidate) {
1558 return $Candidate;
1559 }
1560 }
1561 }
1562 }
1563 else {
1564 return "";
1565 }
1566}
1567
1568sub synch_Cmd($)
1569{
1570 my $Name = $_[0];
1571 if(not $GCC_PATH)
1572 { # GCC was not found yet
1573 return "";
1574 }
1575 my $Candidate = $GCC_PATH;
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04001576 if($Candidate=~s/\bgcc(|\.\w+)\Z/$Name$1/) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04001577 return $Candidate;
1578 }
1579 return "";
1580}
1581
1582sub get_CmdPath($)
1583{
1584 my $Name = $_[0];
1585 return "" if(not $Name);
1586 if(defined $Cache{"get_CmdPath"}{$Name}) {
1587 return $Cache{"get_CmdPath"}{$Name};
1588 }
1589 my %BinUtils = map {$_=>1} (
1590 "c++filt",
1591 "objdump",
1592 "readelf"
1593 );
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04001594 if($BinUtils{$Name} and $GCC_PATH)
1595 {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04001596 if(my $Dir = get_dirname($GCC_PATH)) {
1597 $TargetTools{$Dir}=1;
1598 }
1599 }
1600 my $Path = search_Tools($Name);
1601 if(not $Path and $OSgroup eq "windows") {
1602 $Path = search_Tools($Name.".exe");
1603 }
1604 if(not $Path and $BinUtils{$Name})
1605 {
1606 if($CrossPrefix)
1607 { # user-defined prefix
1608 $Path = search_Cmd($CrossPrefix."-".$Name);
1609 }
1610 }
1611 if(not $Path and $BinUtils{$Name})
1612 {
1613 if(my $Candidate = synch_Cmd($Name))
1614 { # synch with GCC
1615 if($Candidate=~/[\/\\]/)
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04001616 { # command path
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04001617 if(-f $Candidate) {
1618 $Path = $Candidate;
1619 }
1620 }
1621 elsif($Candidate = search_Cmd($Candidate))
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04001622 { # command name
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04001623 $Path = $Candidate;
1624 }
1625 }
1626 }
1627 if(not $Path) {
1628 $Path = search_Cmd($Name);
1629 }
1630 if(not $Path and $OSgroup eq "windows")
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04001631 { # search for *.exe file
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04001632 $Path=search_Cmd($Name.".exe");
1633 }
1634 if($Path=~/\s/) {
1635 $Path = "\"".$Path."\"";
1636 }
1637 return ($Cache{"get_CmdPath"}{$Name}=$Path);
1638}
1639
1640sub search_Cmd($)
1641{
1642 my $Name = $_[0];
1643 return "" if(not $Name);
1644 if(defined $Cache{"search_Cmd"}{$Name}) {
1645 return $Cache{"search_Cmd"}{$Name};
1646 }
1647 if(my $DefaultPath = get_CmdPath_Default($Name)) {
1648 return ($Cache{"search_Cmd"}{$Name} = $DefaultPath);
1649 }
1650 foreach my $Path (sort {length($a)<=>length($b)} keys(%{$SystemPaths{"bin"}}))
1651 {
1652 my $CmdPath = joinPath($Path,$Name);
1653 if(-f $CmdPath)
1654 {
1655 if($Name=~/gcc/) {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04001656 next if(not check_gcc($CmdPath, "3"));
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04001657 }
1658 return ($Cache{"search_Cmd"}{$Name} = $CmdPath);
1659 }
1660 }
1661 return ($Cache{"search_Cmd"}{$Name} = "");
1662}
1663
1664sub get_CmdPath_Default($)
1665{ # search in PATH
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04001666 return "" if(not $_[0]);
1667 if(defined $Cache{"get_CmdPath_Default"}{$_[0]}) {
1668 return $Cache{"get_CmdPath_Default"}{$_[0]};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04001669 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04001670 return ($Cache{"get_CmdPath_Default"}{$_[0]} = get_CmdPath_Default_I($_[0]));
1671}
1672
1673sub get_CmdPath_Default_I($)
1674{ # search in PATH
1675 my $Name = $_[0];
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04001676 if($Name=~/find/)
1677 { # special case: search for "find" utility
Andrey Ponomarenkoa01311b2012-06-08 17:20:02 +04001678 if(`find \"$TMP_DIR\" -maxdepth 0 2>\"$TMP_DIR/null\"`) {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04001679 return "find";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04001680 }
1681 }
1682 elsif($Name=~/gcc/) {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04001683 return check_gcc($Name, "3");
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04001684 }
1685 if(check_command($Name)) {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04001686 return $Name;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04001687 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04001688 if($OSgroup eq "windows")
1689 {
Andrey Ponomarenkoa01311b2012-06-08 17:20:02 +04001690 if(`$Name /? 2>\"$TMP_DIR/null\"`) {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04001691 return $Name;
1692 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04001693 }
1694 if($Name!~/which/)
1695 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04001696 if(my $WhichCmd = get_CmdPath("which"))
1697 {
Andrey Ponomarenkoa01311b2012-06-08 17:20:02 +04001698 if(`$WhichCmd $Name 2>\"$TMP_DIR/null\"`) {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04001699 return $Name;
1700 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04001701 }
1702 }
1703 foreach my $Path (sort {length($a)<=>length($b)} keys(%DefaultBinPaths))
1704 {
1705 if(-f $Path."/".$Name) {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04001706 return joinPath($Path,$Name);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04001707 }
1708 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04001709 return "";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04001710}
1711
1712sub clean_path($)
1713{
1714 my $Path = $_[0];
1715 $Path=~s/[\/\\]+\Z//g;
1716 return $Path;
1717}
1718
1719sub classifyPath($)
1720{
1721 my $Path = $_[0];
1722 if($Path=~/[\*\[]/)
1723 { # wildcard
1724 $Path=~s/\*/.*/g;
1725 $Path=~s/\\/\\\\/g;
1726 return ($Path, "Pattern");
1727 }
1728 elsif($Path=~/[\/\\]/)
1729 { # directory or relative path
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04001730 $Path=~s/[\/\\]+\Z//g;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04001731 return (path_format($Path, $OSgroup), "Path");
1732 }
1733 else {
1734 return ($Path, "Name");
1735 }
1736}
1737
1738sub readDescriptor($$)
1739{
1740 my ($LibVersion, $Content) = @_;
1741 return if(not $LibVersion);
1742 my $DName = $DumpAPI?"descriptor":"descriptor \"d$LibVersion\"";
1743 if(not $Content) {
1744 exitStatus("Error", "$DName is empty");
1745 }
1746 if($Content!~/\</) {
1747 exitStatus("Error", "$DName is not a descriptor (see -d1 option)");
1748 }
1749 $Content=~s/\/\*(.|\n)+?\*\///g;
1750 $Content=~s/<\!--(.|\n)+?-->//g;
1751 $Descriptor{$LibVersion}{"Version"} = parseTag(\$Content, "version");
1752 if($TargetVersion{$LibVersion}) {
1753 $Descriptor{$LibVersion}{"Version"} = $TargetVersion{$LibVersion};
1754 }
1755 if(not $Descriptor{$LibVersion}{"Version"}) {
1756 exitStatus("Error", "version in the $DName is not specified (<version> section)");
1757 }
1758 if($Content=~/{RELPATH}/)
1759 {
1760 if(my $RelDir = $RelativeDirectory{$LibVersion}) {
1761 $Content =~ s/{RELPATH}/$RelDir/g;
1762 }
1763 else
1764 {
1765 my $NeedRelpath = $DumpAPI?"-relpath":"-relpath$LibVersion";
1766 exitStatus("Error", "you have not specified $NeedRelpath option, but the $DName contains {RELPATH} macro");
1767 }
1768 }
1769
1770 if(not $CheckObjectsOnly_Opt)
1771 {
1772 my $DHeaders = parseTag(\$Content, "headers");
1773 if(not $DHeaders) {
1774 exitStatus("Error", "header files in the $DName are not specified (<headers> section)");
1775 }
1776 elsif(lc($DHeaders) ne "none")
1777 { # append the descriptor headers list
1778 if($Descriptor{$LibVersion}{"Headers"})
1779 { # multiple descriptors
1780 $Descriptor{$LibVersion}{"Headers"} .= "\n".$DHeaders;
1781 }
1782 else {
1783 $Descriptor{$LibVersion}{"Headers"} = $DHeaders;
1784 }
1785 foreach my $Path (split(/\s*\n\s*/, $DHeaders))
1786 {
1787 if(not -e $Path) {
1788 exitStatus("Access_Error", "can't access \'$Path\'");
1789 }
1790 }
1791 }
1792 }
1793 if(not $CheckHeadersOnly_Opt)
1794 {
1795 my $DObjects = parseTag(\$Content, "libs");
1796 if(not $DObjects) {
1797 exitStatus("Error", "$SLIB_TYPE libraries in the $DName are not specified (<libs> section)");
1798 }
1799 elsif(lc($DObjects) ne "none")
1800 { # append the descriptor libraries list
1801 if($Descriptor{$LibVersion}{"Libs"})
1802 { # multiple descriptors
1803 $Descriptor{$LibVersion}{"Libs"} .= "\n".$DObjects;
1804 }
1805 else {
1806 $Descriptor{$LibVersion}{"Libs"} .= $DObjects;
1807 }
1808 foreach my $Path (split(/\s*\n\s*/, $DObjects))
1809 {
1810 if(not -e $Path) {
1811 exitStatus("Access_Error", "can't access \'$Path\'");
1812 }
1813 }
1814 }
1815 }
1816 foreach my $Path (split(/\s*\n\s*/, parseTag(\$Content, "search_headers")))
1817 {
1818 $Path = clean_path($Path);
1819 if(not -d $Path) {
1820 exitStatus("Access_Error", "can't access directory \'$Path\'");
1821 }
1822 $Path = path_format($Path, $OSgroup);
1823 $SystemPaths{"include"}{$Path}=1;
1824 }
1825 foreach my $Path (split(/\s*\n\s*/, parseTag(\$Content, "search_libs")))
1826 {
1827 $Path = clean_path($Path);
1828 if(not -d $Path) {
1829 exitStatus("Access_Error", "can't access directory \'$Path\'");
1830 }
1831 $Path = path_format($Path, $OSgroup);
1832 $SystemPaths{"lib"}{$Path}=1;
1833 }
1834 foreach my $Path (split(/\s*\n\s*/, parseTag(\$Content, "tools")))
1835 {
1836 $Path=clean_path($Path);
1837 if(not -d $Path) {
1838 exitStatus("Access_Error", "can't access directory \'$Path\'");
1839 }
1840 $Path = path_format($Path, $OSgroup);
1841 $SystemPaths{"bin"}{$Path}=1;
1842 $TargetTools{$Path}=1;
1843 }
1844 if(my $Prefix = parseTag(\$Content, "cross_prefix")) {
1845 $CrossPrefix = $Prefix;
1846 }
1847 foreach my $Path (split(/\s*\n\s*/, parseTag(\$Content, "include_paths")))
1848 {
1849 $Path=clean_path($Path);
1850 if(not -d $Path) {
1851 exitStatus("Access_Error", "can't access directory \'$Path\'");
1852 }
1853 $Path = path_format($Path, $OSgroup);
1854 $Descriptor{$LibVersion}{"IncludePaths"}{$Path} = 1;
1855 }
1856 foreach my $Path (split(/\s*\n\s*/, parseTag(\$Content, "add_include_paths")))
1857 {
1858 $Path=clean_path($Path);
1859 if(not -d $Path) {
1860 exitStatus("Access_Error", "can't access directory \'$Path\'");
1861 }
1862 $Path = path_format($Path, $OSgroup);
1863 $Descriptor{$LibVersion}{"AddIncludePaths"}{$Path} = 1;
1864 }
1865 foreach my $Path (split(/\s*\n\s*/, parseTag(\$Content, "skip_include_paths")))
1866 {
1867 # skip some auto-generated include paths
1868 $Skip_Include_Paths{$LibVersion}{path_format($Path)}=1;
1869 }
1870 foreach my $Path (split(/\s*\n\s*/, parseTag(\$Content, "skip_including")))
1871 {
1872 # skip direct including of some headers
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04001873 $SkipHeadersList{$LibVersion}{$Path} = 2;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04001874 my ($CPath, $Type) = classifyPath($Path);
1875 $SkipHeaders{$LibVersion}{$Type}{$CPath} = 2;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04001876 }
1877 $Descriptor{$LibVersion}{"GccOptions"} = parseTag(\$Content, "gcc_options");
1878 foreach my $Option (split(/\s*\n\s*/, $Descriptor{$LibVersion}{"GccOptions"})) {
1879 $CompilerOptions{$LibVersion} .= " ".$Option;
1880 }
1881 $Descriptor{$LibVersion}{"SkipHeaders"} = parseTag(\$Content, "skip_headers");
1882 foreach my $Path (split(/\s*\n\s*/, $Descriptor{$LibVersion}{"SkipHeaders"}))
1883 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04001884 $SkipHeadersList{$LibVersion}{$Path} = 1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04001885 my ($CPath, $Type) = classifyPath($Path);
1886 $SkipHeaders{$LibVersion}{$Type}{$CPath} = 1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04001887 }
1888 $Descriptor{$LibVersion}{"SkipLibs"} = parseTag(\$Content, "skip_libs");
1889 foreach my $Path (split(/\s*\n\s*/, $Descriptor{$LibVersion}{"SkipLibs"}))
1890 {
1891 my ($CPath, $Type) = classifyPath($Path);
1892 $SkipLibs{$LibVersion}{$Type}{$CPath} = 1;
1893 }
1894 if(my $DDefines = parseTag(\$Content, "defines"))
1895 {
1896 if($Descriptor{$LibVersion}{"Defines"})
1897 { # multiple descriptors
1898 $Descriptor{$LibVersion}{"Defines"} .= "\n".$DDefines;
1899 }
1900 else {
1901 $Descriptor{$LibVersion}{"Defines"} = $DDefines;
1902 }
1903 }
1904 foreach my $Order (split(/\s*\n\s*/, parseTag(\$Content, "include_order")))
1905 {
1906 if($Order=~/\A(.+):(.+)\Z/) {
1907 $Include_Order{$LibVersion}{$1} = $2;
1908 }
1909 }
1910 foreach my $Type_Name (split(/\s*\n\s*/, parseTag(\$Content, "opaque_types")),
1911 split(/\s*\n\s*/, parseTag(\$Content, "skip_types")))
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04001912 { # opaque_types renamed to skip_types (1.23.4)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04001913 $SkipTypes{$LibVersion}{$Type_Name} = 1;
1914 }
1915 foreach my $Symbol (split(/\s*\n\s*/, parseTag(\$Content, "skip_interfaces")),
1916 split(/\s*\n\s*/, parseTag(\$Content, "skip_symbols")))
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04001917 { # skip_interfaces renamed to skip_symbols (1.22.1)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04001918 $SkipSymbols{$LibVersion}{$Symbol} = 1;
1919 }
1920 foreach my $NameSpace (split(/\s*\n\s*/, parseTag(\$Content, "skip_namespaces"))) {
1921 $SkipNameSpaces{$LibVersion}{$NameSpace} = 1;
1922 }
Andrey Ponomarenkoa01311b2012-06-08 17:20:02 +04001923 foreach my $NameSpace (split(/\s*\n\s*/, parseTag(\$Content, "add_namespaces"))) {
1924 $AddNameSpaces{$LibVersion}{$NameSpace} = 1;
1925 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04001926 foreach my $Constant (split(/\s*\n\s*/, parseTag(\$Content, "skip_constants"))) {
1927 $SkipConstants{$LibVersion}{$Constant} = 1;
1928 }
1929 if(my $DIncPreamble = parseTag(\$Content, "include_preamble"))
1930 {
1931 if($Descriptor{$LibVersion}{"IncludePreamble"})
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04001932 { # multiple descriptors
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04001933 $Descriptor{$LibVersion}{"IncludePreamble"} .= "\n".$DIncPreamble;
1934 }
1935 else {
1936 $Descriptor{$LibVersion}{"IncludePreamble"} = $DIncPreamble;
1937 }
1938 }
1939}
1940
1941sub parseTag($$)
1942{
1943 my ($CodeRef, $Tag) = @_;
1944 return "" if(not $CodeRef or not ${$CodeRef} or not $Tag);
1945 if(${$CodeRef}=~s/\<\Q$Tag\E\>((.|\n)+?)\<\/\Q$Tag\E\>//)
1946 {
1947 my $Content = $1;
1948 $Content=~s/(\A\s+|\s+\Z)//g;
1949 return $Content;
1950 }
1951 else {
1952 return "";
1953 }
1954}
1955
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04001956sub getInfo($)
1957{
Andrey Ponomarenko85043792012-05-14 16:48:07 +04001958 my $DumpPath = $_[0];
1959 return if(not $DumpPath or not -f $DumpPath);
1960
1961 readTUDump($DumpPath);
1962
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04001963 # processing info
1964 setTemplateParams_All();
1965 getTypeInfo_All();
1966 simplifyNames();
1967 getSymbolInfo_All();
1968 getVarInfo_All();
1969
Andrey Ponomarenko85043792012-05-14 16:48:07 +04001970 # clean memory
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04001971 %LibInfo = ();
1972 %TemplateInstance = ();
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04001973 %MangledNames = ();
Andrey Ponomarenko85043792012-05-14 16:48:07 +04001974 %TemplateDecl = ();
1975 %StdCxxTypedef = ();
1976 %MissedTypedef = ();
1977 %Typedef_Tr = ();
1978 %Typedef_Eq = ();
1979
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04001980 # clean cache
1981 delete($Cache{"getTypeAttr"});
1982 delete($Cache{"getTypeDeclId"});
1983
1984 # remove unused types
1985 if($BinaryOnly and not $ExtendedCheck)
1986 { # --binary
1987 removeUnused($Version, "All");
1988 }
1989 else {
1990 removeUnused($Version, "Derived");
1991 }
1992
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04001993 if($Debug) {
1994 # debugMangling($Version);
1995 }
1996}
1997
Andrey Ponomarenko85043792012-05-14 16:48:07 +04001998sub readTUDump($)
1999{
2000 my $DumpPath = $_[0];
2001
2002 open(TU_DUMP, $DumpPath);
2003 local $/ = undef;
2004 my $Content = <TU_DUMP>;
2005 close(TU_DUMP);
2006
2007 unlink($DumpPath);
2008
2009 $Content=~s/\n[ ]+/ /g;
2010 my @Lines = split("\n", $Content);
2011
2012 # clean memory
2013 undef $Content;
2014
2015 $MAX_ID = $#Lines+1;
2016
2017 foreach (0 .. $#Lines)
2018 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04002019 if($Lines[$_]=~/\A\@(\d+)[ ]+([a-z_]+)[ ]+(.+)\Z/i)
Andrey Ponomarenko85043792012-05-14 16:48:07 +04002020 { # get a number and attributes of a node
2021 next if(not $NodeType{$2});
2022 $LibInfo{$Version}{"info_type"}{$1}=$2;
2023 $LibInfo{$Version}{"info"}{$1}=$3;
2024 }
2025
2026 # clean memory
2027 delete($Lines[$_]);
2028 }
2029
2030 # clean memory
2031 undef @Lines;
2032}
2033
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002034sub simplifyNames()
2035{
2036 foreach my $Base (keys(%{$Typedef_Tr{$Version}}))
2037 {
2038 my @Translations = keys(%{$Typedef_Tr{$Version}{$Base}});
2039 if($#Translations==0 and length($Translations[0])<=length($Base)) {
2040 $Typedef_Eq{$Version}{$Base} = $Translations[0];
2041 }
2042 }
Andrey Ponomarenkob8d203d2012-05-25 18:11:07 +04002043 foreach my $TypeId (keys(%{$TypeInfo{$Version}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002044 {
Andrey Ponomarenkob8d203d2012-05-25 18:11:07 +04002045 my $TypeName = $TypeInfo{$Version}{$TypeId}{"Name"};
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04002046 if(not $TypeName) {
2047 next;
2048 }
2049 next if(index($TypeName,"<")==-1);# template instances only
2050 if($TypeName=~/>(::\w+)+\Z/)
2051 { # skip unused types
2052 next;
2053 };
2054 foreach my $Base (sort {length($b)<=>length($a)}
2055 sort {$b cmp $a} keys(%{$Typedef_Eq{$Version}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002056 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04002057 next if(not $Base);
2058 next if(index($TypeName,$Base)==-1);
2059 next if(length($TypeName) - length($Base) <= 3);
2060 my $Typedef = $Typedef_Eq{$Version}{$Base};
2061 $TypeName=~s/(\<|\,)\Q$Base\E(\W|\Z)/$1$Typedef$2/g;
2062 $TypeName=~s/(\<|\,)\Q$Base\E(\w|\Z)/$1$Typedef $2/g;
Andrey Ponomarenkob8d203d2012-05-25 18:11:07 +04002063 if(defined $TypeInfo{$Version}{$TypeId}{"TParam"})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002064 {
Andrey Ponomarenkob8d203d2012-05-25 18:11:07 +04002065 foreach my $TPos (keys(%{$TypeInfo{$Version}{$TypeId}{"TParam"}}))
Andrey Ponomarenko85043792012-05-14 16:48:07 +04002066 {
Andrey Ponomarenkob8d203d2012-05-25 18:11:07 +04002067 my $TPName = $TypeInfo{$Version}{$TypeId}{"TParam"}{$TPos}{"name"};
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04002068 $TPName=~s/\A\Q$Base\E(\W|\Z)/$Typedef$1/g;
Andrey Ponomarenkob8d203d2012-05-25 18:11:07 +04002069 $TypeInfo{$Version}{$TypeId}{"TParam"}{$TPos}{"name"} = formatName($TPName);
Andrey Ponomarenko85043792012-05-14 16:48:07 +04002070 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002071 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002072 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04002073 $TypeName = formatName($TypeName);
Andrey Ponomarenkob8d203d2012-05-25 18:11:07 +04002074 $TypeInfo{$Version}{$TypeId}{"Name"} = $TypeName;
2075 $TName_Tid{$Version}{$TypeName} = $TypeId;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002076 }
2077}
2078
2079sub setTemplateParams_All()
2080{
2081 foreach (keys(%{$LibInfo{$Version}{"info"}}))
2082 {
2083 if($LibInfo{$Version}{"info_type"}{$_} eq "template_decl") {
2084 setTemplateParams($_);
2085 }
2086 }
2087}
2088
2089sub setTemplateParams($)
2090{
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04002091 if(my $Info = $LibInfo{$Version}{"info"}{$_[0]})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002092 {
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04002093 if($Info=~/(inst|spcs)[ ]*:[ ]*@(\d+) /)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002094 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04002095 my $TmplInst_Id = $2;
2096 setTemplateInstParams($TmplInst_Id);
2097 while($TmplInst_Id = getNextElem($TmplInst_Id)) {
2098 setTemplateInstParams($TmplInst_Id);
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04002099 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002100 }
2101 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04002102 if(my $TypeId = getTreeAttr_Type($_[0]))
Andrey Ponomarenko85043792012-05-14 16:48:07 +04002103 {
2104 if(my $IType = $LibInfo{$Version}{"info_type"}{$TypeId})
2105 {
2106 if($IType eq "record_type") {
2107 $TemplateDecl{$Version}{$TypeId}=1;
2108 }
2109 }
2110 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002111}
2112
2113sub setTemplateInstParams($)
2114{
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04002115 if(my $Info = $LibInfo{$Version}{"info"}{$_[0]})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002116 {
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04002117 my ($Params_InfoId, $ElemId) = ();
2118 if($Info=~/purp[ ]*:[ ]*@(\d+) /) {
2119 $Params_InfoId = $1;
2120 }
2121 if($Info=~/valu[ ]*:[ ]*@(\d+) /) {
2122 $ElemId = $1;
2123 }
2124 if($Params_InfoId and $ElemId)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002125 {
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04002126 my $Params_Info = $LibInfo{$Version}{"info"}{$Params_InfoId};
2127 while($Params_Info=~s/ (\d+)[ ]*:[ ]*\@(\d+) / /)
2128 {
2129 my ($PPos, $PTypeId) = ($1, $2);
2130 if(my $PType = $LibInfo{$Version}{"info_type"}{$PTypeId})
2131 {
Andrey Ponomarenko85043792012-05-14 16:48:07 +04002132 if($PType eq "template_type_parm")
2133 {
2134 $TemplateDecl{$Version}{$ElemId}=1;
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04002135 return;
2136 }
2137 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +04002138 if($LibInfo{$Version}{"info_type"}{$ElemId} eq "function_decl")
2139 { # functions
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04002140 $TemplateInstance{$Version}{"Func"}{$ElemId}{$PPos} = $PTypeId;
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04002141 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +04002142 else
2143 { # types
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04002144 $TemplateInstance{$Version}{"Type"}{$ElemId}{$PPos} = $PTypeId;
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04002145 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002146 }
2147 }
2148 }
2149}
2150
2151sub getTypeDeclId($)
2152{
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04002153 if($_[0])
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04002154 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04002155 if(defined $Cache{"getTypeDeclId"}{$Version}{$_[0]}) {
2156 return $Cache{"getTypeDeclId"}{$Version}{$_[0]};
2157 }
2158 if(my $Info = $LibInfo{$Version}{"info"}{$_[0]})
2159 {
2160 if($Info=~/name[ ]*:[ ]*@(\d+)/) {
2161 return ($Cache{"getTypeDeclId"}{$Version}{$_[0]} = $1);
2162 }
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04002163 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002164 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04002165 return ($Cache{"getTypeDeclId"}{$Version}{$_[0]} = 0);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002166}
2167
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002168sub getTypeInfo_All()
2169{
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04002170 if(not check_gcc($GCC_PATH, "4.5"))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002171 { # support for GCC < 4.5
2172 # missed typedefs: QStyle::State is typedef to QFlags<QStyle::StateFlag>
2173 # but QStyleOption.state is of type QFlags<QStyle::StateFlag> in the TU dump
2174 # FIXME: check GCC versions
2175 addMissedTypes_Pre();
2176 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04002177
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002178 foreach (sort {int($a)<=>int($b)} keys(%{$LibInfo{$Version}{"info"}}))
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04002179 { # forward order only
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002180 my $IType = $LibInfo{$Version}{"info_type"}{$_};
2181 if($IType=~/_type\Z/ and $IType ne "function_type"
2182 and $IType ne "method_type") {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04002183 getTypeInfo("$_");
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002184 }
2185 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04002186
2187 # add "..." type
2188 $TypeInfo{$Version}{-1} = {
2189 "Name" => "...",
2190 "Type" => "Intrinsic",
2191 "Tid" => -1
2192 };
2193 $TName_Tid{$Version}{"..."} = -1;
2194
2195 if(not check_gcc($GCC_PATH, "4.5"))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002196 { # support for GCC < 4.5
2197 addMissedTypes_Post();
2198 }
2199}
2200
2201sub addMissedTypes_Pre()
2202{
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04002203 my %MissedTypes = ();
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002204 foreach my $MissedTDid (sort {int($a)<=>int($b)} keys(%{$LibInfo{$Version}{"info"}}))
2205 { # detecting missed typedefs
2206 if($LibInfo{$Version}{"info_type"}{$MissedTDid} eq "type_decl")
2207 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04002208 my $TypeId = getTreeAttr_Type($MissedTDid);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002209 next if(not $TypeId);
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04002210 my $TypeType = getTypeType($TypeId);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002211 if($TypeType eq "Unknown")
2212 { # template_type_parm
2213 next;
2214 }
2215 my $TypeDeclId = getTypeDeclId($TypeId);
2216 next if($TypeDeclId eq $MissedTDid);#or not $TypeDeclId
2217 my $TypedefName = getNameByInfo($MissedTDid);
2218 next if(not $TypedefName);
2219 next if($TypedefName eq "__float80");
2220 next if(isAnon($TypedefName));
2221 if(not $TypeDeclId
2222 or getNameByInfo($TypeDeclId) ne $TypedefName) {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04002223 $MissedTypes{$Version}{$TypeId}{$MissedTDid} = 1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002224 }
2225 }
2226 }
Andrey Ponomarenkob8d203d2012-05-25 18:11:07 +04002227 my %AddTypes = ();
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04002228 foreach my $Tid (keys(%{$MissedTypes{$Version}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002229 { # add missed typedefs
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04002230 my @Missed = keys(%{$MissedTypes{$Version}{$Tid}});
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002231 if(not @Missed or $#Missed>=1) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002232 next;
2233 }
2234 my $MissedTDid = $Missed[0];
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002235 my ($TypedefName, $TypedefNS) = getTrivialName($MissedTDid, $Tid);
Andrey Ponomarenkob8d203d2012-05-25 18:11:07 +04002236 if(not $TypedefName) {
2237 next;
2238 }
2239 $MAX_ID++;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002240 my %MissedInfo = ( # typedef info
2241 "Name" => $TypedefName,
2242 "NameSpace" => $TypedefNS,
2243 "BaseType" => {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002244 "Tid" => $Tid
2245 },
2246 "Type" => "Typedef",
Andrey Ponomarenkob8d203d2012-05-25 18:11:07 +04002247 "Tid" => "$MAX_ID" );
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002248 my ($H, $L) = getLocation($MissedTDid);
2249 $MissedInfo{"Header"} = $H;
2250 $MissedInfo{"Line"} = $L;
Andrey Ponomarenkob8d203d2012-05-25 18:11:07 +04002251 if($TypedefName=~/\*|\&|\s/)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002252 { # other types
2253 next;
2254 }
Andrey Ponomarenkob8d203d2012-05-25 18:11:07 +04002255 if($TypedefName=~/>(::\w+)+\Z/)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002256 { # QFlags<Qt::DropAction>::enum_type
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002257 next;
2258 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04002259 if(getTypeType($Tid)=~/\A(Intrinsic|Union|Struct|Enum|Class)\Z/)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002260 { # double-check for the name of typedef
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04002261 my ($TName, $TNS) = getTrivialName(getTypeDeclId($Tid), $Tid); # base type info
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002262 next if(not $TName);
Andrey Ponomarenkob8d203d2012-05-25 18:11:07 +04002263 if(length($TypedefName)>=length($TName))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002264 { # too long typedef
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002265 next;
2266 }
Andrey Ponomarenkob8d203d2012-05-25 18:11:07 +04002267 if($TName=~/\A\Q$TypedefName\E</) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002268 next;
2269 }
Andrey Ponomarenkob8d203d2012-05-25 18:11:07 +04002270 if($TypedefName=~/\A\Q$TName\E/)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002271 { # QDateTimeEdit::Section and QDateTimeEdit::Sections::enum_type
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002272 next;
2273 }
Andrey Ponomarenkob8d203d2012-05-25 18:11:07 +04002274 if(get_depth($TypedefName)==0 and get_depth($TName)!=0)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002275 { # std::_Vector_base and std::vector::_Base
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002276 next;
2277 }
2278 }
Andrey Ponomarenkob8d203d2012-05-25 18:11:07 +04002279
2280 $AddTypes{$MissedInfo{"Tid"}} = \%MissedInfo;
2281
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002282 # register typedef
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002283 $MissedTypedef{$Version}{$Tid}{"Tid"} = $MissedInfo{"Tid"};
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04002284 $MissedTypedef{$Version}{$Tid}{"TDid"} = $MissedTDid;
Andrey Ponomarenkob8d203d2012-05-25 18:11:07 +04002285 $TName_Tid{$Version}{$TypedefName} = $MissedInfo{"Tid"};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002286 }
Andrey Ponomarenkob8d203d2012-05-25 18:11:07 +04002287
2288 # add missed & remove other
2289 $TypeInfo{$Version} = \%AddTypes;
2290 delete($Cache{"getTypeAttr"}{$Version});
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002291}
2292
2293sub addMissedTypes_Post()
2294{
2295 foreach my $BaseId (keys(%{$MissedTypedef{$Version}}))
2296 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04002297 if(my $Tid = $MissedTypedef{$Version}{$BaseId}{"Tid"})
2298 {
2299 $TypeInfo{$Version}{$Tid}{"Size"} = $TypeInfo{$Version}{$BaseId}{"Size"};
2300 if(my $TName = $TypeInfo{$Version}{$Tid}{"Name"}) {
2301 $Typedef_BaseName{$Version}{$TName} = $TypeInfo{$Version}{$BaseId}{"Name"};
2302 }
2303 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002304 }
2305}
2306
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04002307sub getTypeInfo($)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002308{
Andrey Ponomarenkob8d203d2012-05-25 18:11:07 +04002309 my $TypeId = $_[0];
2310 %{$TypeInfo{$Version}{$TypeId}} = getTypeAttr($TypeId);
2311 my $TName = $TypeInfo{$Version}{$TypeId}{"Name"};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002312 if(not $TName) {
Andrey Ponomarenkob8d203d2012-05-25 18:11:07 +04002313 delete($TypeInfo{$Version}{$TypeId});
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002314 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002315}
2316
2317sub getArraySize($$)
2318{
2319 my ($TypeId, $BaseName) = @_;
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04002320 if(my $Size = getSize($TypeId))
2321 {
2322 my $Elems = $Size/$BYTE_SIZE;
2323 while($BaseName=~s/\s*\[(\d+)\]//) {
2324 $Elems/=$1;
2325 }
2326 if(my $BasicId = $TName_Tid{$Version}{$BaseName})
2327 {
2328 if(my $BasicSize = $TypeInfo{$Version}{$BasicId}{"Size"}) {
2329 $Elems/=$BasicSize;
2330 }
2331 }
2332 return $Elems;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002333 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04002334 return 0;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002335}
2336
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04002337sub getTParams($$)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002338{
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04002339 my ($TypeId, $Kind) = @_;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002340 my @TmplParams = ();
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04002341 my @Positions = sort {int($a)<=>int($b)} keys(%{$TemplateInstance{$Version}{$Kind}{$TypeId}});
2342 foreach my $Pos (@Positions)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002343 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04002344 my $Param_TypeId = $TemplateInstance{$Version}{$Kind}{$TypeId}{$Pos};
2345 my $NodeType = $LibInfo{$Version}{"info_type"}{$Param_TypeId};
2346 if(not $NodeType)
2347 { # typename_type
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002348 return ();
2349 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04002350 if($NodeType eq "tree_vec")
2351 {
2352 if($Pos!=$#Positions)
2353 { # select last vector of parameters ( ns<P1>::type<P2> )
2354 next;
2355 }
2356 }
2357 my @Params = get_TemplateParam($Pos, $Param_TypeId);
2358 foreach my $P (@Params)
2359 {
2360 if($P eq "") {
2361 return ();
2362 }
2363 elsif($P ne "\@skip\@") {
2364 @TmplParams = (@TmplParams, $P);
2365 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002366 }
2367 }
2368 return @TmplParams;
2369}
2370
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04002371sub getTypeAttr($)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002372{
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04002373 my $TypeId = $_[0];
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04002374 my %TypeAttr = ();
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04002375 if(defined $TypeInfo{$Version}{$TypeId}
2376 and $TypeInfo{$Version}{$TypeId}{"Name"})
2377 { # already created
2378 return %{$TypeInfo{$Version}{$TypeId}};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002379 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04002380 elsif($Cache{"getTypeAttr"}{$Version}{$TypeId})
2381 { # incomplete type
2382 return ();
2383 }
2384 $Cache{"getTypeAttr"}{$Version}{$TypeId} = 1;
2385
2386 my $TypeDeclId = getTypeDeclId($TypeId);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002387 $TypeAttr{"Tid"} = $TypeId;
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04002388
2389 if(not $MissedBase{$Version}{$TypeId} and isTypedef($TypeId))
2390 {
2391 if(my $Info = $LibInfo{$Version}{"info"}{$TypeId})
2392 {
2393 if($Info=~/qual[ ]*:/)
2394 {
2395 if(my $NID = ++$MAX_ID)
2396 {
2397 $MissedBase{$Version}{$TypeId}="$NID";
2398 $MissedBase_R{$Version}{$NID}=$TypeId;
2399 $LibInfo{$Version}{"info"}{$NID} = $LibInfo{$Version}{"info"}{$TypeId};
2400 $LibInfo{$Version}{"info_type"}{$NID} = $LibInfo{$Version}{"info_type"}{$TypeId};
2401 }
2402 }
2403 }
2404 $TypeAttr{"Type"} = "Typedef";
2405 }
2406 else {
2407 $TypeAttr{"Type"} = getTypeType($TypeId);
2408 }
2409
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002410 if($TypeAttr{"Type"} eq "Unknown") {
2411 return ();
2412 }
2413 elsif($TypeAttr{"Type"}=~/(Func|Method|Field)Ptr/)
2414 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04002415 %TypeAttr = getMemPtrAttr(pointTo($TypeId), $TypeId, $TypeAttr{"Type"});
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04002416 if(my $TName = $TypeAttr{"Name"})
2417 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04002418 %{$TypeInfo{$Version}{$TypeId}} = %TypeAttr;
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04002419 $TName_Tid{$Version}{$TName} = $TypeId;
2420 return %TypeAttr;
2421 }
2422 else {
2423 return ();
2424 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002425 }
2426 elsif($TypeAttr{"Type"} eq "Array")
2427 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04002428 my ($BTid, $BTSpec) = selectBaseType($TypeId);
2429 if(not $BTid) {
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04002430 return ();
2431 }
2432 $TypeAttr{"BaseType"}{"Tid"} = $BTid;
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04002433 if(my %BTAttr = getTypeAttr($BTid))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002434 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04002435 if(not $BTAttr{"Name"}) {
2436 return ();
2437 }
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04002438 if(my $NElems = getArraySize($TypeId, $BTAttr{"Name"}))
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04002439 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04002440 if(my $Size = getSize($TypeId)) {
2441 $TypeAttr{"Size"} = $Size/$BYTE_SIZE;
2442 }
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04002443 if($BTAttr{"Name"}=~/\A([^\[\]]+)(\[(\d+|)\].*)\Z/) {
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04002444 $TypeAttr{"Name"} = $1."[$NElems]".$2;
2445 }
2446 else {
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04002447 $TypeAttr{"Name"} = $BTAttr{"Name"}."[$NElems]";
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04002448 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002449 }
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04002450 else
2451 {
2452 $TypeAttr{"Size"} = $WORD_SIZE{$Version}; # pointer
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04002453 if($BTAttr{"Name"}=~/\A([^\[\]]+)(\[(\d+|)\].*)\Z/) {
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04002454 $TypeAttr{"Name"} = $1."[]".$2;
2455 }
2456 else {
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04002457 $TypeAttr{"Name"} = $BTAttr{"Name"}."[]";
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04002458 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002459 }
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04002460 $TypeAttr{"Name"} = formatName($TypeAttr{"Name"});
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04002461 if($BTAttr{"Header"}) {
2462 $TypeAttr{"Header"} = $BTAttr{"Header"};
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04002463 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04002464 %{$TypeInfo{$Version}{$TypeId}} = %TypeAttr;
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04002465 $TName_Tid{$Version}{$TypeAttr{"Name"}} = $TypeId;
2466 return %TypeAttr;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002467 }
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04002468 return ();
2469 }
2470 elsif($TypeAttr{"Type"}=~/\A(Intrinsic|Union|Struct|Enum|Class)\Z/)
2471 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04002472 %TypeAttr = getTrivialTypeAttr($TypeId);
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04002473 if($TypeAttr{"Name"})
2474 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04002475 %{$TypeInfo{$Version}{$TypeId}} = %TypeAttr;
2476 if($TypeAttr{"Name"} ne "int" or getTypeDeclId($TypeAttr{"Tid"}))
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04002477 { # NOTE: register only one int: with built-in decl
2478 if(not $TName_Tid{$Version}{$TypeAttr{"Name"}}) {
2479 $TName_Tid{$Version}{$TypeAttr{"Name"}} = $TypeId;
2480 }
2481 }
2482 return %TypeAttr;
2483 }
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04002484 else {
2485 return ();
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002486 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002487 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002488 else
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04002489 { # derived types
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04002490 my ($BTid, $BTSpec) = selectBaseType($TypeId);
2491 if(not $BTid) {
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04002492 return ();
2493 }
2494 $TypeAttr{"BaseType"}{"Tid"} = $BTid;
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04002495 if(defined $MissedTypedef{$Version}{$BTid})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002496 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04002497 if(my $MissedTDid = $MissedTypedef{$Version}{$BTid}{"TDid"})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002498 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04002499 if($MissedTDid ne $TypeDeclId) {
2500 $TypeAttr{"BaseType"}{"Tid"} = $MissedTypedef{$Version}{$BTid}{"Tid"};
2501 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002502 }
2503 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04002504 my %BTAttr = getTypeAttr($TypeAttr{"BaseType"}{"Tid"});
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04002505 if(not $BTAttr{"Name"})
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04002506 { # templates
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002507 return ();
2508 }
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04002509 if($BTAttr{"Type"} eq "Typedef")
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002510 { # relinking typedefs
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04002511 my %BaseBase = get_Type($BTAttr{"BaseType"}{"Tid"}, $Version);
2512 if($BTAttr{"Name"} eq $BaseBase{"Name"}) {
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04002513 $TypeAttr{"BaseType"}{"Tid"} = $BaseBase{"Tid"};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002514 }
2515 }
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04002516 if($BTSpec)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002517 {
2518 if($TypeAttr{"Type"} eq "Pointer"
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04002519 and $BTAttr{"Name"}=~/\([\*]+\)/)
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04002520 {
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04002521 $TypeAttr{"Name"} = $BTAttr{"Name"};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002522 $TypeAttr{"Name"}=~s/\(([*]+)\)/($1*)/g;
2523 }
2524 else {
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04002525 $TypeAttr{"Name"} = $BTAttr{"Name"}." ".$BTSpec;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002526 }
2527 }
2528 else {
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04002529 $TypeAttr{"Name"} = $BTAttr{"Name"};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002530 }
2531 if($TypeAttr{"Type"} eq "Typedef")
2532 {
2533 $TypeAttr{"Name"} = getNameByInfo($TypeDeclId);
Andrey Ponomarenko85043792012-05-14 16:48:07 +04002534 if(isAnon($TypeAttr{"Name"}))
2535 { # anon typedef to anon type: ._N
2536 return ();
2537 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002538 if(my $NS = getNameSpace($TypeDeclId))
2539 {
2540 my $TypeName = $TypeAttr{"Name"};
2541 if($NS=~/\A(struct |union |class |)((.+)::|)\Q$TypeName\E\Z/)
2542 { # "some_type" is the typedef to "struct some_type" in C++
2543 if($3) {
2544 $TypeAttr{"Name"} = $3."::".$TypeName;
2545 }
2546 }
2547 else
2548 {
2549 $TypeAttr{"NameSpace"} = $NS;
2550 $TypeAttr{"Name"} = $TypeAttr{"NameSpace"}."::".$TypeAttr{"Name"};
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04002551
2552 if($TypeAttr{"NameSpace"}=~/\Astd(::|\Z)/
2553 and $TypeAttr{"Name"}!~/>(::\w+)+\Z/)
2554 {
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04002555 if($BTAttr{"NameSpace"}
2556 and $BTAttr{"NameSpace"}=~/\Astd(::|\Z)/ and $BTAttr{"Name"}=~/</)
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04002557 { # types like "std::fpos<__mbstate_t>" are
2558 # not covered by typedefs in the TU dump
2559 # so trying to add such typedefs manually
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04002560 $StdCxxTypedef{$Version}{$BTAttr{"Name"}}{$TypeAttr{"Name"}} = 1;
2561 if(length($TypeAttr{"Name"})<=length($BTAttr{"Name"}))
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04002562 {
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04002563 if(($BTAttr{"Name"}!~/\A(std|boost)::/ or $TypeAttr{"Name"}!~/\A[a-z]+\Z/))
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04002564 { # skip "other" in "std" and "type" in "boost"
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04002565 $Typedef_Eq{$Version}{$BTAttr{"Name"}} = $TypeAttr{"Name"};
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04002566 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002567 }
2568 }
2569 }
2570 }
2571 }
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04002572 if($TypeAttr{"Name"} ne $BTAttr{"Name"}
2573 and $TypeAttr{"Name"}!~/>(::\w+)+\Z/ and $BTAttr{"Name"}!~/>(::\w+)+\Z/)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002574 {
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04002575 if(not defined $Typedef_BaseName{$Version}{$TypeAttr{"Name"}})
2576 { # typedef int*const TYPEDEF; // first
2577 # int foo(TYPEDEF p); // const is optimized out
2578 $Typedef_BaseName{$Version}{$TypeAttr{"Name"}} = $BTAttr{"Name"};
2579 if($BTAttr{"Name"}=~/</)
2580 {
2581 if(($BTAttr{"Name"}!~/\A(std|boost)::/ or $TypeAttr{"Name"}!~/\A[a-z]+\Z/)) {
2582 $Typedef_Tr{$Version}{$BTAttr{"Name"}}{$TypeAttr{"Name"}} = 1;
2583 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002584 }
2585 }
2586 }
2587 ($TypeAttr{"Header"}, $TypeAttr{"Line"}) = getLocation($TypeDeclId);
2588 }
2589 if(not $TypeAttr{"Size"})
2590 {
2591 if($TypeAttr{"Type"} eq "Pointer") {
2592 $TypeAttr{"Size"} = $WORD_SIZE{$Version};
2593 }
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04002594 elsif($BTAttr{"Size"}) {
2595 $TypeAttr{"Size"} = $BTAttr{"Size"};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002596 }
2597 }
2598 $TypeAttr{"Name"} = formatName($TypeAttr{"Name"});
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04002599 if(not $TypeAttr{"Header"} and $BTAttr{"Header"}) {
2600 $TypeAttr{"Header"} = $BTAttr{"Header"};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002601 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04002602 %{$TypeInfo{$Version}{$TypeId}} = %TypeAttr;
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04002603 if($TypeAttr{"Name"} ne $BTAttr{"Name"})
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04002604 { # typedef to "class Class"
2605 # should not be registered in TName_Tid
2606 if(not $TName_Tid{$Version}{$TypeAttr{"Name"}}) {
2607 $TName_Tid{$Version}{$TypeAttr{"Name"}} = $TypeId;
2608 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002609 }
2610 return %TypeAttr;
2611 }
2612}
2613
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04002614sub getTreeVec($)
2615{
2616 my %Vector = ();
2617 if($_[0] and my $Info = $LibInfo{$Version}{"info"}{$_[0]})
2618 {
2619 while($Info=~s/ (\d+)[ ]*:[ ]*\@(\d+) / /)
2620 { # string length is N-1 because of the null terminator
2621 $Vector{$1} = $2;
2622 }
2623 }
2624 return \%Vector;
2625}
2626
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002627sub get_TemplateParam($$)
2628{
2629 my ($Pos, $Type_Id) = @_;
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04002630 return () if(not $Type_Id);
2631 my $NodeType = $LibInfo{$Version}{"info_type"}{$Type_Id};
2632 return () if(not $NodeType);
2633 if($NodeType eq "integer_cst")
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002634 { # int (1), unsigned (2u), char ('c' as 99), ...
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04002635 my $CstTid = getTreeAttr_Type($Type_Id);
Andrey Ponomarenkob8d203d2012-05-25 18:11:07 +04002636 my %CstType = getTypeAttr($CstTid); # without recursion
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002637 my $Num = getNodeIntCst($Type_Id);
2638 if(my $CstSuffix = $ConstantSuffix{$CstType{"Name"}}) {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04002639 return ($Num.$CstSuffix);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002640 }
2641 else {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04002642 return ("(".$CstType{"Name"}.")".$Num);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002643 }
2644 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04002645 elsif($NodeType eq "string_cst") {
2646 return (getNodeStrCst($Type_Id));
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002647 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04002648 elsif($NodeType eq "tree_vec")
2649 {
2650 my $Vector = getTreeVec($Type_Id);
2651 my @Params = ();
2652 foreach my $P1 (sort {int($a)<=>int($b)} keys(%{$Vector}))
2653 {
2654 foreach my $P2 (get_TemplateParam($Pos, $Vector->{$P1})) {
2655 push(@Params, $P2);
2656 }
2657 }
2658 return @Params;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002659 }
2660 else
2661 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04002662 my %ParamAttr = getTypeAttr($Type_Id);
Andrey Ponomarenkob8d203d2012-05-25 18:11:07 +04002663 my $PName = $ParamAttr{"Name"};
2664 if(not $PName) {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04002665 return ();
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002666 }
Andrey Ponomarenkob8d203d2012-05-25 18:11:07 +04002667 if($PName=~/\>/)
2668 {
2669 if(my $Cover = cover_stdcxx_typedef($PName)) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002670 $PName = $Cover;
2671 }
2672 }
2673 if($Pos>=1 and
2674 $PName=~/\Astd::(allocator|less|((char|regex)_traits)|((i|o)streambuf_iterator))\</)
2675 { # template<typename _Tp, typename _Alloc = std::allocator<_Tp> >
2676 # template<typename _Key, typename _Compare = std::less<_Key>
2677 # template<typename _CharT, typename _Traits = std::char_traits<_CharT> >
2678 # template<typename _Ch_type, typename _Rx_traits = regex_traits<_Ch_type> >
2679 # template<typename _CharT, typename _InIter = istreambuf_iterator<_CharT> >
2680 # template<typename _CharT, typename _OutIter = ostreambuf_iterator<_CharT> >
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04002681 return ("\@skip\@");
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002682 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04002683 return ($PName);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002684 }
2685}
2686
2687sub cover_stdcxx_typedef($)
2688{
2689 my $TypeName = $_[0];
2690 if(my @Covers = sort {length($a)<=>length($b)}
2691 sort keys(%{$StdCxxTypedef{$Version}{$TypeName}}))
2692 { # take the shortest typedef
2693 # FIXME: there may be more than
2694 # one typedefs to the same type
2695 return $Covers[0];
2696 }
2697 my $TypeName_Covered = $TypeName;
2698 while($TypeName=~s/(>)[ ]*(const|volatile|restrict| |\*|\&)\Z/$1/g){};
2699 if(my @Covers = sort {length($a)<=>length($b)} sort keys(%{$StdCxxTypedef{$Version}{$TypeName}}))
2700 {
2701 my $Cover = $Covers[0];
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04002702 $TypeName_Covered=~s/\b\Q$TypeName\E(\W|\Z)/$Cover$1/g;
2703 $TypeName_Covered=~s/\b\Q$TypeName\E(\w|\Z)/$Cover $1/g;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002704 }
2705 return formatName($TypeName_Covered);
2706}
2707
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002708sub getNodeIntCst($)
2709{
2710 my $CstId = $_[0];
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04002711 my $CstTypeId = getTreeAttr_Type($CstId);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002712 if($EnumMembName_Id{$Version}{$CstId}) {
2713 return $EnumMembName_Id{$Version}{$CstId};
2714 }
2715 elsif((my $Value = getTreeValue($CstId)) ne "")
2716 {
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04002717 if($Value eq "0")
2718 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04002719 if($LibInfo{$Version}{"info_type"}{$CstTypeId} eq "boolean_type") {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002720 return "false";
2721 }
2722 else {
2723 return "0";
2724 }
2725 }
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04002726 elsif($Value eq "1")
2727 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04002728 if($LibInfo{$Version}{"info_type"}{$CstTypeId} eq "boolean_type") {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002729 return "true";
2730 }
2731 else {
2732 return "1";
2733 }
2734 }
2735 else {
2736 return $Value;
2737 }
2738 }
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04002739 return "";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002740}
2741
2742sub getNodeStrCst($)
2743{
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04002744 if($_[0] and my $Info = $LibInfo{$Version}{"info"}{$_[0]})
2745 {
2746 if($Info=~/strg[ ]*: (.+) lngt:[ ]*(\d+)/)
2747 { # string length is N-1 because of the null terminator
2748 return substr($1, 0, $2-1);
2749 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002750 }
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04002751 return "";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002752}
2753
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04002754sub getMemPtrAttr($$$)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002755{ # function, method and field pointers
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04002756 my ($PtrId, $TypeId, $Type) = @_;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002757 my $MemInfo = $LibInfo{$Version}{"info"}{$PtrId};
2758 if($Type eq "FieldPtr") {
2759 $MemInfo = $LibInfo{$Version}{"info"}{$TypeId};
2760 }
2761 my $MemInfo_Type = $LibInfo{$Version}{"info_type"}{$PtrId};
2762 my $MemPtrName = "";
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04002763 my %TypeAttr = ("Size"=>$WORD_SIZE{$Version}, "Type"=>$Type, "Tid"=>$TypeId);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002764 if($Type eq "MethodPtr")
2765 { # size of "method pointer" may be greater than WORD size
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04002766 if(my $Size = getSize($TypeId)) {
2767 $TypeAttr{"Size"} = $Size/$BYTE_SIZE;
2768 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002769 }
2770 # Return
2771 if($Type eq "FieldPtr")
2772 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04002773 my %ReturnAttr = getTypeAttr($PtrId);
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04002774 if($ReturnAttr{"Name"}) {
2775 $MemPtrName .= $ReturnAttr{"Name"};
2776 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002777 $TypeAttr{"Return"} = $PtrId;
2778 }
2779 else
2780 {
2781 if($MemInfo=~/retn[ ]*:[ ]*\@(\d+) /)
2782 {
2783 my $ReturnTypeId = $1;
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04002784 my %ReturnAttr = getTypeAttr($ReturnTypeId);
2785 if(not $ReturnAttr{"Name"})
2786 { # templates
2787 return ();
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04002788 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04002789 $MemPtrName .= $ReturnAttr{"Name"};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002790 $TypeAttr{"Return"} = $ReturnTypeId;
2791 }
2792 }
2793 # Class
2794 if($MemInfo=~/(clas|cls)[ ]*:[ ]*@(\d+) /)
2795 {
2796 $TypeAttr{"Class"} = $2;
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04002797 my %Class = getTypeAttr($TypeAttr{"Class"});
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002798 if($Class{"Name"}) {
2799 $MemPtrName .= " (".$Class{"Name"}."\:\:*)";
2800 }
2801 else {
2802 $MemPtrName .= " (*)";
2803 }
2804 }
2805 else {
2806 $MemPtrName .= " (*)";
2807 }
2808 # Parameters
2809 if($Type eq "FuncPtr"
2810 or $Type eq "MethodPtr")
2811 {
2812 my @ParamTypeName = ();
2813 if($MemInfo=~/prms[ ]*:[ ]*@(\d+) /)
2814 {
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04002815 my $PTypeInfoId = $1;
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04002816 my $Pos = 0;
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04002817 while($PTypeInfoId)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002818 {
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04002819 my $PTypeInfo = $LibInfo{$Version}{"info"}{$PTypeInfoId};
2820 if($PTypeInfo=~/valu[ ]*:[ ]*@(\d+) /)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002821 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04002822 my $PTypeId = $1;
2823 my %ParamAttr = getTypeAttr($PTypeId);
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04002824 if(not $ParamAttr{"Name"})
2825 { # templates (template_type_parm), etc.
2826 return ();
2827 }
2828 if($ParamAttr{"Name"} eq "void") {
2829 last;
2830 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04002831 if($Pos!=0 or $Type ne "MethodPtr")
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04002832 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04002833 $TypeAttr{"Param"}{$Pos}{"type"} = $PTypeId;
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04002834 push(@ParamTypeName, $ParamAttr{"Name"});
2835 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04002836 if($PTypeInfoId = getNextElem($PTypeInfoId)) {
2837 $Pos+=1;
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04002838 }
2839 else {
2840 last;
2841 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002842 }
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04002843 else {
2844 last;
2845 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002846 }
2847 }
2848 $MemPtrName .= " (".join(", ", @ParamTypeName).")";
2849 }
2850 $TypeAttr{"Name"} = formatName($MemPtrName);
2851 return %TypeAttr;
2852}
2853
2854sub getTreeTypeName($)
2855{
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04002856 my $TypeId = $_[0];
2857 if(my $Info = $LibInfo{$Version}{"info"}{$TypeId})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002858 {
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04002859 if($LibInfo{$Version}{"info_type"}{$_[0]} eq "integer_type")
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002860 {
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04002861 if(my $Name = getNameByInfo($TypeId))
2862 { # bit_size_type
2863 return $Name;
2864 }
2865 elsif($Info=~/unsigned/) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002866 return "unsigned int";
2867 }
2868 else {
2869 return "int";
2870 }
2871 }
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04002872 elsif($Info=~/name[ ]*:[ ]*@(\d+) /)
2873 {
2874 return getNameByInfo($1);
2875 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002876 }
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04002877 return "";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002878}
2879
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04002880sub isFuncPtr($)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002881{
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04002882 my $Ptd = pointTo($_[0]);
2883 return 0 if(not $Ptd);
2884 if(my $Info = $LibInfo{$Version}{"info"}{$_[0]})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002885 {
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04002886 if($Info=~/unql[ ]*:/ and $Info!~/qual[ ]*:/) {
2887 return 0;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002888 }
2889 }
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04002890 if(my $InfoT1 = $LibInfo{$Version}{"info_type"}{$_[0]}
2891 and my $InfoT2 = $LibInfo{$Version}{"info_type"}{$Ptd})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002892 {
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04002893 if($InfoT1 eq "pointer_type"
2894 and $InfoT2 eq "function_type") {
2895 return 1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002896 }
2897 }
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04002898 return 0;
2899}
2900
2901sub isMethodPtr($)
2902{
2903 my $Ptd = pointTo($_[0]);
2904 return 0 if(not $Ptd);
2905 if(my $Info = $LibInfo{$Version}{"info"}{$_[0]})
2906 {
2907 if($LibInfo{$Version}{"info_type"}{$_[0]} eq "record_type"
2908 and $LibInfo{$Version}{"info_type"}{$Ptd} eq "method_type"
2909 and $Info=~/ ptrmem /) {
2910 return 1;
2911 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002912 }
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04002913 return 0;
2914}
2915
2916sub isFieldPtr($)
2917{
2918 if($_[0] and my $Info = $LibInfo{$Version}{"info"}{$_[0]})
2919 {
2920 if($LibInfo{$Version}{"info_type"}{$_[0]} eq "offset_type"
2921 and $Info=~/ ptrmem /) {
2922 return 1;
2923 }
2924 }
2925 return 0;
2926}
2927
2928sub pointTo($)
2929{
2930 if($_[0] and my $Info = $LibInfo{$Version}{"info"}{$_[0]})
2931 {
2932 if($Info=~/ptd[ ]*:[ ]*@(\d+)/) {
2933 return $1;
2934 }
2935 }
2936 return "";
2937}
2938
2939sub getTypeTypeByTypeId($)
2940{
2941 my $TypeId = $_[0];
2942 if(my $TType = $LibInfo{$Version}{"info_type"}{$TypeId})
2943 {
2944 my $NType = $NodeType{$TType};
2945 if($NType eq "Intrinsic") {
2946 return $NType;
2947 }
2948 elsif(isFuncPtr($TypeId)) {
2949 return "FuncPtr";
2950 }
2951 elsif(isMethodPtr($TypeId)) {
2952 return "MethodPtr";
2953 }
2954 elsif(isFieldPtr($TypeId)) {
2955 return "FieldPtr";
2956 }
2957 elsif($NType ne "Other") {
2958 return $NType;
2959 }
2960 }
2961 return "Unknown";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002962}
2963
2964sub getQual($)
2965{
2966 my $TypeId = $_[0];
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002967 my %UnQual = (
2968 "r"=>"restrict",
2969 "v"=>"volatile",
2970 "c"=>"const",
2971 "cv"=>"const volatile"
2972 );
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04002973 if(my $Info = $LibInfo{$Version}{"info"}{$TypeId})
2974 {
2975 my ($Qual, $To) = ();
2976 if($Info=~/qual[ ]*:[ ]*(r|c|v|cv) /) {
2977 $Qual = $UnQual{$1};
2978 }
2979 if($Info=~/unql[ ]*:[ ]*\@(\d+)/) {
2980 $To = $1;
2981 }
2982 if($Qual and $To) {
2983 return ($Qual, $To);
2984 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002985 }
2986 return ();
2987}
2988
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04002989sub getQualType($)
2990{
2991 if($_[0] eq "const volatile") {
2992 return "ConstVolatile";
2993 }
2994 return ucfirst($_[0]);
2995}
2996
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04002997sub getTypeType($)
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04002998{
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04002999 my $TypeId = $_[0];
3000 my $TypeDeclId = getTypeDeclId($TypeId);
3001 if(defined $MissedTypedef{$Version}{$TypeId})
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04003002 { # support for old GCC versions
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04003003 if($MissedTypedef{$Version}{$TypeId}{"TDid"} eq $TypeDeclId) {
3004 return "Typedef";
3005 }
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04003006 }
3007 my $Info = $LibInfo{$Version}{"info"}{$TypeId};
3008 my ($Qual, $To) = getQual($TypeId);
3009 if(($Qual or $To) and $Info=~/name[ ]*:[ ]*\@(\d+) /
3010 and (getTypeId($1) ne $TypeId))
3011 { # qualified types (special)
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04003012 return getQualType($Qual);
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04003013 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04003014 elsif(not $MissedBase_R{$Version}{$TypeId}
3015 and isTypedef($TypeId)) {
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04003016 return "Typedef";
3017 }
3018 elsif($Qual)
3019 { # qualified types
3020 return getQualType($Qual);
3021 }
3022 my $TypeType = getTypeTypeByTypeId($TypeId);
3023 if($TypeType eq "Struct")
3024 {
3025 if($TypeDeclId
3026 and $LibInfo{$Version}{"info_type"}{$TypeDeclId} eq "template_decl") {
3027 return "Template";
3028 }
3029 }
3030 return $TypeType;
3031}
3032
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04003033sub isTypedef($)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003034{
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04003035 if($_[0] and my $Info = $LibInfo{$Version}{"info"}{$_[0]})
3036 {
3037 my $TDid = getTypeDeclId($_[0]);
3038 if(getNameByInfo($TDid)
3039 and $Info=~/unql[ ]*:[ ]*\@(\d+) /
3040 and getTypeId($TDid) eq $_[0]) {
3041 return $1;
3042 }
3043 }
3044 return 0;
3045}
3046
3047sub selectBaseType($)
3048{
3049 my $TypeId = $_[0];
3050 if(defined $MissedTypedef{$Version}{$TypeId})
3051 { # add missed typedefs
3052 if($MissedTypedef{$Version}{$TypeId}{"TDid"} eq getTypeDeclId($TypeId)) {
3053 return ($TypeId, "");
3054 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003055 }
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04003056 my $Info = $LibInfo{$Version}{"info"}{$TypeId};
3057 my $InfoType = $LibInfo{$Version}{"info_type"}{$TypeId};
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04003058
3059 my $MB_R = $MissedBase_R{$Version}{$TypeId};
3060 my $MB = $MissedBase{$Version}{$TypeId};
3061
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04003062 my ($Qual, $To) = getQual($TypeId);
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04003063 if(($Qual or $To) and $Info=~/name[ ]*:[ ]*\@(\d+) /
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04003064 and (getTypeId($1) ne $TypeId)
3065 and (not $MB_R or getTypeId($1) ne $MB_R))
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04003066 { # qualified types (special)
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04003067 return (getTypeId($1), $Qual);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003068 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04003069 elsif($MB)
3070 { # add base
3071 return ($MB, "");
3072 }
3073 elsif(not $MB_R and my $Bid = isTypedef($TypeId))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003074 { # typedefs
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04003075 return ($Bid, "");
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003076 }
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04003077 elsif($Qual or $To)
3078 { # qualified types
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04003079 return ($To, $Qual);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003080 }
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04003081 elsif($InfoType eq "reference_type")
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003082 {
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04003083 if($Info=~/refd[ ]*:[ ]*@(\d+) /) {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04003084 return ($1, "&");
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003085 }
3086 else {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04003087 return (0, "");
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003088 }
3089 }
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04003090 elsif($InfoType eq "array_type")
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003091 {
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04003092 if($Info=~/elts[ ]*:[ ]*@(\d+) /) {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04003093 return ($1, "");
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003094 }
3095 else {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04003096 return (0, "");
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003097 }
3098 }
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04003099 elsif($InfoType eq "pointer_type")
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003100 {
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04003101 if($Info=~/ptd[ ]*:[ ]*@(\d+) /) {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04003102 return ($1, "*");
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003103 }
3104 else {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04003105 return (0, "");
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003106 }
3107 }
3108 else {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04003109 return (0, "");
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003110 }
3111}
3112
3113sub getSymbolInfo_All()
3114{
3115 foreach (sort {int($b)<=>int($a)} keys(%{$LibInfo{$Version}{"info"}}))
3116 { # reverse order
3117 if($LibInfo{$Version}{"info_type"}{$_} eq "function_decl") {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04003118 getSymbolInfo($_);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003119 }
3120 }
3121}
3122
3123sub getVarInfo_All()
3124{
3125 foreach (sort {int($b)<=>int($a)} keys(%{$LibInfo{$Version}{"info"}}))
3126 { # reverse order
3127 if($LibInfo{$Version}{"info_type"}{$_} eq "var_decl") {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04003128 getVarInfo($_);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003129 }
3130 }
3131}
3132
3133sub isBuiltIn($) {
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04003134 return ($_[0] and $_[0]=~/\<built\-in\>|\<internal\>|\A\./);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003135}
3136
3137sub getVarInfo($)
3138{
3139 my $InfoId = $_[0];
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04003140 if(my $NSid = getNameSpaceId($InfoId))
3141 {
3142 my $NSInfoType = $LibInfo{$Version}{"info_type"}{$NSid};
3143 if($NSInfoType and $NSInfoType eq "function_decl") {
3144 return;
3145 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003146 }
3147 ($SymbolInfo{$Version}{$InfoId}{"Header"}, $SymbolInfo{$Version}{$InfoId}{"Line"}) = getLocation($InfoId);
3148 if(not $SymbolInfo{$Version}{$InfoId}{"Header"}
3149 or isBuiltIn($SymbolInfo{$Version}{$InfoId}{"Header"})) {
3150 delete($SymbolInfo{$Version}{$InfoId});
3151 return;
3152 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04003153 my $ShortName = getTreeStr(getTreeAttr_Name($InfoId));
Andrey Ponomarenko85043792012-05-14 16:48:07 +04003154 if(not $ShortName) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003155 delete($SymbolInfo{$Version}{$InfoId});
3156 return;
3157 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +04003158 if($ShortName=~/\Atmp_add_class_\d+\Z/) {
3159 delete($SymbolInfo{$Version}{$InfoId});
3160 return;
3161 }
3162 $SymbolInfo{$Version}{$InfoId}{"ShortName"} = $ShortName;
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04003163 $SymbolInfo{$Version}{$InfoId}{"MnglName"} = getTreeStr(getTreeAttr_Mngl($InfoId));
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003164 if($SymbolInfo{$Version}{$InfoId}{"MnglName"}
3165 and $SymbolInfo{$Version}{$InfoId}{"MnglName"}!~/\A_Z/)
3166 { # validate mangled name
3167 delete($SymbolInfo{$Version}{$InfoId});
3168 return;
3169 }
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04003170 if(not $SymbolInfo{$Version}{$InfoId}{"MnglName"}
Andrey Ponomarenko85043792012-05-14 16:48:07 +04003171 and $ShortName=~/\A_Z/)
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04003172 { # _ZTS, etc.
Andrey Ponomarenko85043792012-05-14 16:48:07 +04003173 $SymbolInfo{$Version}{$InfoId}{"MnglName"} = $ShortName;
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04003174 }
3175 if(isPrivateData($SymbolInfo{$Version}{$InfoId}{"MnglName"}))
3176 { # non-public global data
3177 delete($SymbolInfo{$Version}{$InfoId});
3178 return;
3179 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003180 $SymbolInfo{$Version}{$InfoId}{"Data"} = 1;
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04003181 if(my $Rid = getTypeId($InfoId))
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04003182 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04003183 if(not $TypeInfo{$Version}{$Rid}{"Name"})
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04003184 { # typename_type
3185 delete($SymbolInfo{$Version}{$InfoId});
3186 return;
3187 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04003188 $SymbolInfo{$Version}{$InfoId}{"Return"} = $Rid;
3189 my $Val = getDataVal($InfoId, $Rid);
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04003190 if(defined $Val) {
3191 $SymbolInfo{$Version}{$InfoId}{"Value"} = $Val;
3192 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003193 }
3194 set_Class_And_Namespace($InfoId);
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04003195 if(my $ClassId = $SymbolInfo{$Version}{$InfoId}{"Class"})
3196 {
3197 if(not $TypeInfo{$Version}{$ClassId}{"Name"})
3198 { # templates
3199 delete($SymbolInfo{$Version}{$InfoId});
3200 return;
3201 }
3202 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003203 if($LibInfo{$Version}{"info"}{$InfoId}=~/ lang:[ ]*C /i) {
3204 $SymbolInfo{$Version}{$InfoId}{"Lang"} = "C";
3205 }
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04003206 if($UserLang and $UserLang eq "C")
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003207 { # --lang=C option
Andrey Ponomarenko85043792012-05-14 16:48:07 +04003208 $SymbolInfo{$Version}{$InfoId}{"MnglName"} = $ShortName;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003209 }
3210 if($COMMON_LANGUAGE{$Version} eq "C++")
3211 {
3212 if(not $SymbolInfo{$Version}{$InfoId}{"MnglName"})
3213 { # for some symbols (_ZTI) the short name is the mangled name
3214 if($ShortName=~/\A_Z/) {
3215 $SymbolInfo{$Version}{$InfoId}{"MnglName"} = $ShortName;
3216 }
3217 }
3218 if(not $SymbolInfo{$Version}{$InfoId}{"MnglName"})
3219 { # try to mangle symbol (link with libraries)
3220 $SymbolInfo{$Version}{$InfoId}{"MnglName"} = linkSymbol($InfoId);
3221 }
3222 if($OStarget eq "windows")
3223 {
3224 if(my $Mangled = $mangled_name{$Version}{modelUnmangled($InfoId, "MSVC")})
3225 { # link MS C++ symbols from library with GCC symbols from headers
3226 $SymbolInfo{$Version}{$InfoId}{"MnglName"} = $Mangled;
3227 }
3228 }
3229 }
3230 if(not $SymbolInfo{$Version}{$InfoId}{"MnglName"}) {
3231 $SymbolInfo{$Version}{$InfoId}{"MnglName"} = $ShortName;
3232 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04003233 if(not $CheckHeadersOnly
3234 and not link_symbol($SymbolInfo{$Version}{$InfoId}{"MnglName"}, $Version, "-Deps"))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003235 {
Andrey Ponomarenko85043792012-05-14 16:48:07 +04003236 if(link_symbol($ShortName, $Version, "-Deps"))
3237 {
3238 if(not $SymbolInfo{$Version}{$InfoId}{"Class"}
3239 and isConstType($SymbolInfo{$Version}{$InfoId}{"Return"}, $Version)
3240 and $SymbolInfo{$Version}{$InfoId}{"MnglName"}=~/L\d+$ShortName/)
3241 { # "const" global data is mangled as _ZL... in the TU dump
3242 # but not mangled when compiling a C shared library
3243 $SymbolInfo{$Version}{$InfoId}{"MnglName"} = $ShortName;
3244 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003245 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003246 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +04003247 if(my $Symbol = $SymbolInfo{$Version}{$InfoId}{"MnglName"})
3248 {
3249 if(not selectSymbol($Symbol, $SymbolInfo{$Version}{$InfoId}, "Dump", $Version))
3250 { # non-target symbols
3251 delete($SymbolInfo{$Version}{$InfoId});
3252 return;
3253 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003254 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04003255 if(my $Rid = $SymbolInfo{$Version}{$InfoId}{"Return"})
3256 {
3257 if(defined $MissedTypedef{$Version}{$Rid})
3258 {
3259 if(my $AddedTid = $MissedTypedef{$Version}{$Rid}{"Tid"}) {
3260 $SymbolInfo{$Version}{$InfoId}{"Return"} = $AddedTid;
3261 }
3262 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003263 }
3264 setFuncAccess($InfoId);
3265 if($SymbolInfo{$Version}{$InfoId}{"MnglName"}=~/\A_ZTV/) {
3266 delete($SymbolInfo{$Version}{$InfoId}{"Return"});
3267 }
3268 if($ShortName=~/\A(_Z|\?)/) {
3269 delete($SymbolInfo{$Version}{$InfoId}{"ShortName"});
3270 }
3271}
3272
Andrey Ponomarenko85043792012-05-14 16:48:07 +04003273sub isConstType($$)
3274{
3275 my ($TypeId, $LibVersion) = @_;
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04003276 my %Base = get_Type($TypeId, $LibVersion);
Andrey Ponomarenko85043792012-05-14 16:48:07 +04003277 while(defined $Base{"Type"} and $Base{"Type"} eq "Typedef") {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04003278 %Base = get_OneStep_BaseType($Base{"Tid"}, $LibVersion);
Andrey Ponomarenko85043792012-05-14 16:48:07 +04003279 }
3280 return ($Base{"Type"} eq "Const");
3281}
3282
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003283sub getTrivialName($$)
3284{
3285 my ($TypeInfoId, $TypeId) = @_;
3286 my %TypeAttr = ();
3287 $TypeAttr{"Name"} = getNameByInfo($TypeInfoId);
3288 if(not $TypeAttr{"Name"}) {
3289 $TypeAttr{"Name"} = getTreeTypeName($TypeId);
3290 }
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04003291 ($TypeAttr{"Header"}, $TypeAttr{"Line"}) = getLocation($TypeInfoId);
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04003292 $TypeAttr{"Type"} = getTypeType($TypeId);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003293 $TypeAttr{"Name"}=~s/<(.+)\Z//g; # GCC 3.4.4 add template params to the name
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04003294 if(isAnon($TypeAttr{"Name"}))
3295 {
3296 my $NameSpaceId = $TypeId;
3297 while(my $NSId = getNameSpaceId(getTypeDeclId($NameSpaceId)))
3298 { # searching for a first not anon scope
3299 if($NSId eq $NameSpaceId) {
3300 last;
3301 }
3302 else
3303 {
3304 $TypeAttr{"NameSpace"} = getNameSpace(getTypeDeclId($TypeId));
3305 if(not $TypeAttr{"NameSpace"}
3306 or isNotAnon($TypeAttr{"NameSpace"})) {
3307 last;
3308 }
3309 }
3310 $NameSpaceId=$NSId;
3311 }
3312 }
3313 else
3314 {
3315 if(my $NameSpaceId = getNameSpaceId($TypeInfoId))
3316 {
3317 if($NameSpaceId ne $TypeId) {
3318 $TypeAttr{"NameSpace"} = getNameSpace($TypeInfoId);
3319 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003320 }
3321 }
3322 if($TypeAttr{"NameSpace"} and isNotAnon($TypeAttr{"Name"})) {
3323 $TypeAttr{"Name"} = $TypeAttr{"NameSpace"}."::".$TypeAttr{"Name"};
3324 }
3325 $TypeAttr{"Name"} = formatName($TypeAttr{"Name"});
3326 if(isAnon($TypeAttr{"Name"}))
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04003327 { # anon-struct-header.h-line
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04003328 $TypeAttr{"Name"} = "anon-".lc($TypeAttr{"Type"})."-";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003329 $TypeAttr{"Name"} .= $TypeAttr{"Header"}."-".$TypeAttr{"Line"};
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04003330 if($TypeAttr{"NameSpace"}) {
3331 $TypeAttr{"Name"} = $TypeAttr{"NameSpace"}."::".$TypeAttr{"Name"};
3332 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003333 }
Andrey Ponomarenkob8d203d2012-05-25 18:11:07 +04003334 if(defined $TemplateInstance{$Version}{"Type"}{$TypeId}
3335 and getTypeDeclId($TypeId) eq $TypeInfoId)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003336 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04003337 my @TParams = getTParams($TypeId, "Type");
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003338 if(not @TParams)
3339 { # template declarations with abstract params
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003340 return ("", "");
3341 }
3342 $TypeAttr{"Name"} = formatName($TypeAttr{"Name"}."< ".join(", ", @TParams)." >");
3343 }
3344 return ($TypeAttr{"Name"}, $TypeAttr{"NameSpace"});
3345}
3346
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04003347sub getTrivialTypeAttr($)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003348{
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04003349 my $TypeId = $_[0];
3350 my $TypeInfoId = getTypeDeclId($_[0]);
Andrey Ponomarenko85043792012-05-14 16:48:07 +04003351
3352 if($TemplateDecl{$Version}{$TypeId})
3353 { # template_decl
3354 return ();
3355 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04003356 if(my $ScopeId = getTreeAttr_Scpe($TypeInfoId))
3357 {
3358 if($TemplateDecl{$Version}{$ScopeId})
3359 { # template_decl
3360 return ();
3361 }
3362 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +04003363
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003364 my %TypeAttr = ();
3365 if(getTypeTypeByTypeId($TypeId)!~/\A(Intrinsic|Union|Struct|Enum|Class)\Z/) {
3366 return ();
3367 }
3368 setTypeAccess($TypeId, \%TypeAttr);
3369 ($TypeAttr{"Header"}, $TypeAttr{"Line"}) = getLocation($TypeInfoId);
3370 if(isBuiltIn($TypeAttr{"Header"}))
3371 {
3372 delete($TypeAttr{"Header"});
3373 delete($TypeAttr{"Line"});
3374 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04003375 $TypeAttr{"Type"} = getTypeType($TypeId);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003376 ($TypeAttr{"Name"}, $TypeAttr{"NameSpace"}) = getTrivialName($TypeInfoId, $TypeId);
3377 if(not $TypeAttr{"Name"}) {
3378 return ();
3379 }
3380 if(not $TypeAttr{"NameSpace"}) {
3381 delete($TypeAttr{"NameSpace"});
3382 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04003383 if(defined $TemplateInstance{$Version}{"Type"}{$TypeId})
Andrey Ponomarenko16934472012-03-29 15:37:04 +04003384 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04003385 if(my @TParams = getTParams($TypeId, "Type"))
Andrey Ponomarenko16934472012-03-29 15:37:04 +04003386 {
3387 foreach my $Pos (0 .. $#TParams) {
3388 $TypeAttr{"TParam"}{$Pos}{"name"}=$TParams[$Pos];
3389 }
3390 }
3391 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003392 if(my $Size = getSize($TypeId)) {
3393 $TypeAttr{"Size"} = $Size/$BYTE_SIZE;
3394 }
3395 if($TypeAttr{"Type"} eq "Struct"
3396 and detect_lang($TypeId))
3397 {
3398 $TypeAttr{"Type"} = "Class";
Andrey Ponomarenko85043792012-05-14 16:48:07 +04003399 $TypeAttr{"Copied"} = 1; # default, will be changed in getSymbolInfo()
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003400 }
3401 if($TypeAttr{"Type"} eq "Struct"
Andrey Ponomarenko85043792012-05-14 16:48:07 +04003402 or $TypeAttr{"Type"} eq "Class")
3403 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04003404 my $Skip = setBaseClasses($TypeId, \%TypeAttr);
Andrey Ponomarenko85043792012-05-14 16:48:07 +04003405 if($Skip) {
3406 return ();
3407 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003408 }
3409 setSpec($TypeId, \%TypeAttr);
3410 setTypeMemb($TypeId, \%TypeAttr);
3411 $TypeAttr{"Tid"} = $TypeId;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003412 if(my $VTable = $ClassVTable_Content{$Version}{$TypeAttr{"Name"}})
3413 {
3414 my @Entries = split(/\n/, $VTable);
3415 foreach (1 .. $#Entries)
3416 {
3417 my $Entry = $Entries[$_];
3418 if($Entry=~/\A(\d+)\s+(.+)\Z/) {
3419 $TypeAttr{"VTable"}{$1} = $2;
3420 }
3421 }
3422 }
3423 return %TypeAttr;
3424}
3425
3426sub detect_lang($)
3427{
3428 my $TypeId = $_[0];
3429 my $Info = $LibInfo{$Version}{"info"}{$TypeId};
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04003430 if(check_gcc($GCC_PATH, "4"))
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04003431 { # GCC 4 fncs-node points to only non-artificial methods
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003432 return ($Info=~/(fncs)[ ]*:[ ]*@(\d+) /);
3433 }
3434 else
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04003435 { # GCC 3
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04003436 my $Fncs = getTreeAttr_Fncs($TypeId);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003437 while($Fncs)
3438 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04003439 if($LibInfo{$Version}{"info"}{$Fncs}!~/artificial/) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003440 return 1;
3441 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04003442 $Fncs = getTreeAttr_Chan($Fncs);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003443 }
3444 }
3445 return 0;
3446}
3447
3448sub setSpec($$)
3449{
3450 my ($TypeId, $TypeAttr) = @_;
3451 my $Info = $LibInfo{$Version}{"info"}{$TypeId};
3452 if($Info=~/\s+spec\s+/) {
3453 $TypeAttr->{"Spec"} = 1;
3454 }
3455}
3456
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04003457sub setBaseClasses($$)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003458{
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04003459 my ($TypeId, $TypeAttr) = @_;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003460 my $Info = $LibInfo{$Version}{"info"}{$TypeId};
3461 if($Info=~/binf[ ]*:[ ]*@(\d+) /)
3462 {
3463 $Info = $LibInfo{$Version}{"info"}{$1};
3464 my $Pos = 0;
3465 while($Info=~s/(pub|public|prot|protected|priv|private|)[ ]+binf[ ]*:[ ]*@(\d+) //)
3466 {
3467 my ($Access, $BInfoId) = ($1, $2);
3468 my $ClassId = getBinfClassId($BInfoId);
Andrey Ponomarenko85043792012-05-14 16:48:07 +04003469 my $CType = $LibInfo{$Version}{"info_type"}{$ClassId};
3470 if(not $CType or $CType eq "template_type_parm"
3471 or $CType eq "typename_type")
3472 { # skip
3473 return 1;
3474 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003475 my $BaseInfo = $LibInfo{$Version}{"info"}{$BInfoId};
3476 if($Access=~/prot/)
3477 {
3478 $TypeAttr->{"Base"}{$ClassId}{"access"} = "protected";
3479 }
3480 elsif($Access=~/priv/)
3481 {
3482 $TypeAttr->{"Base"}{$ClassId}{"access"} = "private";
3483 }
3484 $TypeAttr->{"Base"}{$ClassId}{"pos"} = $Pos++;
3485 if($BaseInfo=~/virt/)
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04003486 { # virtual base
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003487 $TypeAttr->{"Base"}{$ClassId}{"virtual"} = 1;
3488 }
3489 $Class_SubClasses{$Version}{$ClassId}{$TypeId}=1;
3490 }
3491 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +04003492 return 0;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003493}
3494
3495sub getBinfClassId($)
3496{
3497 my $Info = $LibInfo{$Version}{"info"}{$_[0]};
3498 $Info=~/type[ ]*:[ ]*@(\d+) /;
3499 return $1;
3500}
3501
3502sub unmangledFormat($$)
3503{
3504 my ($Name, $LibVersion) = @_;
3505 $Name = uncover_typedefs($Name, $LibVersion);
3506 while($Name=~s/([^\w>*])(const|volatile)(,|>|\Z)/$1$3/g){};
3507 $Name=~s/\(\w+\)(\d)/$1/;
3508 return $Name;
3509}
3510
3511sub modelUnmangled($$)
3512{
3513 my ($InfoId, $Compiler) = @_;
3514 if($Cache{"modelUnmangled"}{$Version}{$Compiler}{$InfoId}) {
3515 return $Cache{"modelUnmangled"}{$Version}{$Compiler}{$InfoId};
3516 }
3517 my $PureSignature = $SymbolInfo{$Version}{$InfoId}{"ShortName"};
3518 if($SymbolInfo{$Version}{$InfoId}{"Destructor"}) {
3519 $PureSignature = "~".$PureSignature;
3520 }
3521 if(not $SymbolInfo{$Version}{$InfoId}{"Data"})
3522 {
3523 my (@Params, @ParamTypes) = ();
3524 if(defined $SymbolInfo{$Version}{$InfoId}{"Param"}
3525 and not $SymbolInfo{$Version}{$InfoId}{"Destructor"}) {
3526 @Params = keys(%{$SymbolInfo{$Version}{$InfoId}{"Param"}});
3527 }
3528 foreach my $ParamPos (sort {int($a) <=> int($b)} @Params)
3529 { # checking parameters
3530 my $PId = $SymbolInfo{$Version}{$InfoId}{"Param"}{$ParamPos}{"type"};
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04003531 my %PType = get_PureType($PId, $Version);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003532 my $PTName = unmangledFormat($PType{"Name"}, $Version);
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04003533 $PTName=~s/\b(restrict|register)\b//g;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003534 if($Compiler eq "MSVC") {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04003535 $PTName=~s/\blong long\b/__int64/;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003536 }
3537 @ParamTypes = (@ParamTypes, $PTName);
3538 }
3539 if(@ParamTypes) {
3540 $PureSignature .= "(".join(", ", @ParamTypes).")";
3541 }
3542 else
3543 {
3544 if($Compiler eq "MSVC")
3545 {
3546 $PureSignature .= "(void)";
3547 }
3548 else
3549 { # GCC
3550 $PureSignature .= "()";
3551 }
3552 }
3553 $PureSignature = delete_keywords($PureSignature);
3554 }
3555 if(my $ClassId = $SymbolInfo{$Version}{$InfoId}{"Class"})
3556 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04003557 my $ClassName = unmangledFormat($TypeInfo{$Version}{$ClassId}{"Name"}, $Version);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003558 $PureSignature = $ClassName."::".$PureSignature;
3559 }
3560 elsif(my $NS = $SymbolInfo{$Version}{$InfoId}{"NameSpace"}) {
3561 $PureSignature = $NS."::".$PureSignature;
3562 }
3563 if($SymbolInfo{$Version}{$InfoId}{"Const"}) {
3564 $PureSignature .= " const";
3565 }
3566 if($SymbolInfo{$Version}{$InfoId}{"Volatile"}) {
3567 $PureSignature .= " volatile";
3568 }
3569 my $ShowReturn = 0;
3570 if($Compiler eq "MSVC"
3571 and $SymbolInfo{$Version}{$InfoId}{"Data"})
3572 {
3573 $ShowReturn=1;
3574 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04003575 elsif(defined $TemplateInstance{$Version}{"Func"}{$InfoId}
3576 and keys(%{$TemplateInstance{$Version}{"Func"}{$InfoId}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003577 {
3578 $ShowReturn=1;
3579 }
3580 if($ShowReturn)
3581 { # mangled names for template function specializations include return value
3582 if(my $ReturnId = $SymbolInfo{$Version}{$InfoId}{"Return"})
3583 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04003584 my %RType = get_PureType($ReturnId, $Version);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003585 my $ReturnName = unmangledFormat($RType{"Name"}, $Version);
3586 $PureSignature = $ReturnName." ".$PureSignature;
3587 }
3588 }
3589 return ($Cache{"modelUnmangled"}{$Version}{$Compiler}{$InfoId} = formatName($PureSignature));
3590}
3591
3592sub mangle_symbol($$$)
3593{ # mangling for simple methods
3594 # see gcc-4.6.0/gcc/cp/mangle.c
3595 my ($InfoId, $LibVersion, $Compiler) = @_;
3596 if($Cache{"mangle_symbol"}{$LibVersion}{$InfoId}{$Compiler}) {
3597 return $Cache{"mangle_symbol"}{$LibVersion}{$InfoId}{$Compiler};
3598 }
3599 my $Mangled = "";
3600 if($Compiler eq "GCC") {
Andrey Ponomarenko16934472012-03-29 15:37:04 +04003601 $Mangled = mangle_symbol_GCC($InfoId, $LibVersion);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003602 }
3603 elsif($Compiler eq "MSVC") {
Andrey Ponomarenko16934472012-03-29 15:37:04 +04003604 $Mangled = mangle_symbol_MSVC($InfoId, $LibVersion);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003605 }
3606 return ($Cache{"mangle_symbol"}{$LibVersion}{$InfoId}{$Compiler} = $Mangled);
3607}
3608
Andrey Ponomarenko16934472012-03-29 15:37:04 +04003609sub mangle_symbol_MSVC($$)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003610{
3611 my ($InfoId, $LibVersion) = @_;
3612 return "";
3613}
3614
Andrey Ponomarenko16934472012-03-29 15:37:04 +04003615sub mangle_symbol_GCC($$)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003616{ # see gcc-4.6.0/gcc/cp/mangle.c
3617 my ($InfoId, $LibVersion) = @_;
3618 my ($Mangled, $ClassId, $NameSpace) = ("_Z", 0, "");
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04003619 my $Return = $SymbolInfo{$LibVersion}{$InfoId}{"Return"};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003620 my %Repl = ();# SN_ replacements
3621 if($ClassId = $SymbolInfo{$LibVersion}{$InfoId}{"Class"})
3622 {
3623 my $MangledClass = mangle_param($ClassId, $LibVersion, \%Repl);
3624 if($MangledClass!~/\AN/) {
3625 $MangledClass = "N".$MangledClass;
3626 }
3627 else {
3628 $MangledClass=~s/E\Z//;
3629 }
3630 if($SymbolInfo{$LibVersion}{$InfoId}{"Volatile"}) {
3631 $MangledClass=~s/\AN/NV/;
3632 }
3633 if($SymbolInfo{$LibVersion}{$InfoId}{"Const"}) {
3634 $MangledClass=~s/\AN/NK/;
3635 }
3636 $Mangled .= $MangledClass;
3637 }
3638 elsif($NameSpace = $SymbolInfo{$LibVersion}{$InfoId}{"NameSpace"})
3639 { # mangled by name due to the absence of structured info
3640 my $MangledNS = mangle_ns($NameSpace, $LibVersion, \%Repl);
3641 if($MangledNS!~/\AN/) {
3642 $MangledNS = "N".$MangledNS;
3643 }
3644 else {
3645 $MangledNS=~s/E\Z//;
3646 }
3647 $Mangled .= $MangledNS;
3648 }
3649 my ($ShortName, $TmplParams) = template_base($SymbolInfo{$LibVersion}{$InfoId}{"ShortName"});
Andrey Ponomarenko16934472012-03-29 15:37:04 +04003650 my @TParams = ();
3651 if($Version)
3652 { # parsing mode
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04003653 @TParams = getTParams($InfoId, "Func");
Andrey Ponomarenko16934472012-03-29 15:37:04 +04003654 }
3655 elsif($TmplParams)
3656 { # remangling mode
3657 # support for old ABI dumps
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003658 @TParams = separate_params($TmplParams, 0);
3659 }
3660 if($SymbolInfo{$LibVersion}{$InfoId}{"Constructor"}) {
3661 $Mangled .= "C1";
3662 }
3663 elsif($SymbolInfo{$LibVersion}{$InfoId}{"Destructor"}) {
3664 $Mangled .= "D0";
3665 }
3666 elsif($ShortName)
3667 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04003668 if($SymbolInfo{$LibVersion}{$InfoId}{"Data"})
3669 {
Andrey Ponomarenko16934472012-03-29 15:37:04 +04003670 if(not $SymbolInfo{$LibVersion}{$InfoId}{"Class"}
Andrey Ponomarenko85043792012-05-14 16:48:07 +04003671 and isConstType($Return, $LibVersion))
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04003672 { # "const" global data is mangled as _ZL...
3673 $Mangled .= "L";
3674 }
3675 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003676 if($ShortName=~/\Aoperator(\W.*)\Z/)
3677 {
3678 my $Op = $1;
3679 $Op=~s/\A[ ]+//g;
3680 if(my $OpMngl = $OperatorMangling{$Op}) {
3681 $Mangled .= $OpMngl;
3682 }
3683 else { # conversion operator
3684 $Mangled .= "cv".mangle_param(getTypeIdByName($Op, $LibVersion), $LibVersion, \%Repl);
3685 }
3686 }
3687 else {
3688 $Mangled .= length($ShortName).$ShortName;
3689 }
3690 if(@TParams)
3691 { # templates
3692 $Mangled .= "I";
3693 foreach my $TParam (@TParams) {
3694 $Mangled .= mangle_template_param($TParam, $LibVersion, \%Repl);
3695 }
3696 $Mangled .= "E";
3697 }
3698 if(not $ClassId and @TParams) {
3699 add_substitution($ShortName, \%Repl, 0);
3700 }
3701 }
3702 if($ClassId or $NameSpace) {
3703 $Mangled .= "E";
3704 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +04003705 if(@TParams)
3706 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04003707 if($Return) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003708 $Mangled .= mangle_param($Return, $LibVersion, \%Repl);
3709 }
3710 }
3711 if(not $SymbolInfo{$LibVersion}{$InfoId}{"Data"})
3712 {
3713 my @Params = ();
3714 if(defined $SymbolInfo{$LibVersion}{$InfoId}{"Param"}
3715 and not $SymbolInfo{$LibVersion}{$InfoId}{"Destructor"}) {
3716 @Params = keys(%{$SymbolInfo{$LibVersion}{$InfoId}{"Param"}});
3717 }
3718 foreach my $ParamPos (sort {int($a) <=> int($b)} @Params)
3719 { # checking parameters
3720 my $ParamType_Id = $SymbolInfo{$LibVersion}{$InfoId}{"Param"}{$ParamPos}{"type"};
3721 $Mangled .= mangle_param($ParamType_Id, $LibVersion, \%Repl);
3722 }
3723 if(not @Params) {
3724 $Mangled .= "v";
3725 }
3726 }
3727 $Mangled = correct_incharge($InfoId, $LibVersion, $Mangled);
3728 $Mangled = write_stdcxx_substitution($Mangled);
3729 if($Mangled eq "_Z") {
3730 return "";
3731 }
3732 return $Mangled;
3733}
3734
3735sub correct_incharge($$$)
3736{
3737 my ($InfoId, $LibVersion, $Mangled) = @_;
3738 if($SymbolInfo{$LibVersion}{$InfoId}{"Constructor"})
3739 {
3740 if($MangledNames{$LibVersion}{$Mangled}) {
3741 $Mangled=~s/C1E/C2E/;
3742 }
3743 }
3744 elsif($SymbolInfo{$LibVersion}{$InfoId}{"Destructor"})
3745 {
3746 if($MangledNames{$LibVersion}{$Mangled}) {
3747 $Mangled=~s/D0E/D1E/;
3748 }
3749 if($MangledNames{$LibVersion}{$Mangled}) {
3750 $Mangled=~s/D1E/D2E/;
3751 }
3752 }
3753 return $Mangled;
3754}
3755
3756sub template_base($)
3757{ # NOTE: std::_Vector_base<mysqlpp::mysql_type_info>::_Vector_impl
Andrey Ponomarenko16934472012-03-29 15:37:04 +04003758 # NOTE: operators: >>, <<
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003759 my $Name = $_[0];
Andrey Ponomarenko16934472012-03-29 15:37:04 +04003760 if($Name!~/>\Z/ or $Name!~/</) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003761 return $Name;
3762 }
3763 my $TParams = $Name;
Andrey Ponomarenko16934472012-03-29 15:37:04 +04003764 while(my $CPos = find_center($TParams, "<"))
3765 { # search for the last <T>
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003766 $TParams = substr($TParams, $CPos);
3767 }
Andrey Ponomarenko16934472012-03-29 15:37:04 +04003768 if($TParams=~s/\A<(.+)>\Z/$1/) {
3769 $Name=~s/<\Q$TParams\E>\Z//;
3770 }
3771 else
3772 { # error
3773 $TParams = "";
3774 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003775 return ($Name, $TParams);
3776}
3777
3778sub get_sub_ns($)
3779{
3780 my $Name = $_[0];
3781 my @NS = ();
Andrey Ponomarenko16934472012-03-29 15:37:04 +04003782 while(my $CPos = find_center($Name, ":"))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003783 {
3784 push(@NS, substr($Name, 0, $CPos));
3785 $Name = substr($Name, $CPos);
3786 $Name=~s/\A:://;
3787 }
3788 return (join("::", @NS), $Name);
3789}
3790
3791sub mangle_ns($$$)
3792{
3793 my ($Name, $LibVersion, $Repl) = @_;
3794 if(my $Tid = $TName_Tid{$LibVersion}{$Name})
3795 {
3796 my $Mangled = mangle_param($Tid, $LibVersion, $Repl);
3797 $Mangled=~s/\AN(.+)E\Z/$1/;
3798 return $Mangled;
3799
3800 }
3801 else
3802 {
3803 my ($MangledNS, $SubNS) = ("", "");
3804 ($SubNS, $Name) = get_sub_ns($Name);
3805 if($SubNS) {
3806 $MangledNS .= mangle_ns($SubNS, $LibVersion, $Repl);
3807 }
3808 $MangledNS .= length($Name).$Name;
3809 add_substitution($MangledNS, $Repl, 0);
3810 return $MangledNS;
3811 }
3812}
3813
3814sub mangle_param($$$)
3815{
3816 my ($PTid, $LibVersion, $Repl) = @_;
3817 my ($MPrefix, $Mangled) = ("", "");
3818 my %ReplCopy = %{$Repl};
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04003819 my %BaseType = get_BaseType($PTid, $LibVersion);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003820 my $BaseType_Name = $BaseType{"Name"};
3821 if(not $BaseType_Name) {
3822 return "";
3823 }
3824 my ($ShortName, $TmplParams) = template_base($BaseType_Name);
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04003825 my $Suffix = get_BaseTypeQual($PTid, $LibVersion);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003826 while($Suffix=~s/\s*(const|volatile|restrict)\Z//g){};
3827 while($Suffix=~/(&|\*|const)\Z/)
3828 {
3829 if($Suffix=~s/[ ]*&\Z//) {
3830 $MPrefix .= "R";
3831 }
3832 if($Suffix=~s/[ ]*\*\Z//) {
3833 $MPrefix .= "P";
3834 }
3835 if($Suffix=~s/[ ]*const\Z//)
3836 {
3837 if($MPrefix=~/R|P/
3838 or $Suffix=~/&|\*/) {
3839 $MPrefix .= "K";
3840 }
3841 }
3842 if($Suffix=~s/[ ]*volatile\Z//) {
3843 $MPrefix .= "V";
3844 }
3845 #if($Suffix=~s/[ ]*restrict\Z//) {
3846 #$MPrefix .= "r";
3847 #}
3848 }
3849 if(my $Token = $IntrinsicMangling{$BaseType_Name}) {
3850 $Mangled .= $Token;
3851 }
3852 elsif($BaseType{"Type"}=~/(Class|Struct|Union|Enum)/)
3853 {
Andrey Ponomarenko16934472012-03-29 15:37:04 +04003854 my @TParams = ();
3855 if($Version)
3856 { # parsing mode
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04003857 @TParams = getTParams($BaseType{"Tid"}, "Type");
Andrey Ponomarenko16934472012-03-29 15:37:04 +04003858 }
3859 elsif($TmplParams)
3860 { # remangling mode
3861 # support for old ABI dumps
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003862 @TParams = separate_params($TmplParams, 0);
3863 }
3864 my $MangledNS = "";
3865 my ($SubNS, $SName) = get_sub_ns($ShortName);
3866 if($SubNS) {
3867 $MangledNS .= mangle_ns($SubNS, $LibVersion, $Repl);
3868 }
3869 $MangledNS .= length($SName).$SName;
3870 if(@TParams) {
3871 add_substitution($MangledNS, $Repl, 0);
3872 }
3873 $Mangled .= "N".$MangledNS;
3874 if(@TParams)
3875 { # templates
3876 $Mangled .= "I";
3877 foreach my $TParam (@TParams) {
3878 $Mangled .= mangle_template_param($TParam, $LibVersion, $Repl);
3879 }
3880 $Mangled .= "E";
3881 }
3882 $Mangled .= "E";
3883 }
3884 elsif($BaseType{"Type"}=~/(FuncPtr|MethodPtr)/)
3885 {
3886 if($BaseType{"Type"} eq "MethodPtr") {
3887 $Mangled .= "M".mangle_param($BaseType{"Class"}, $LibVersion, $Repl)."F";
3888 }
3889 else {
3890 $Mangled .= "PF";
3891 }
3892 $Mangled .= mangle_param($BaseType{"Return"}, $LibVersion, $Repl);
3893 my @Params = keys(%{$BaseType{"Param"}});
3894 foreach my $Num (sort {int($a)<=>int($b)} @Params) {
3895 $Mangled .= mangle_param($BaseType{"Param"}{$Num}{"type"}, $LibVersion, $Repl);
3896 }
3897 if(not @Params) {
3898 $Mangled .= "v";
3899 }
3900 $Mangled .= "E";
3901 }
3902 elsif($BaseType{"Type"} eq "FieldPtr")
3903 {
3904 $Mangled .= "M".mangle_param($BaseType{"Class"}, $LibVersion, $Repl);
3905 $Mangled .= mangle_param($BaseType{"Return"}, $LibVersion, $Repl);
3906 }
3907 $Mangled = $MPrefix.$Mangled;# add prefix (RPK)
3908 if(my $Optimized = write_substitution($Mangled, \%ReplCopy))
3909 {
3910 if($Mangled eq $Optimized)
3911 {
3912 if($ShortName!~/::/)
3913 { # remove "N ... E"
3914 if($MPrefix) {
3915 $Mangled=~s/\A($MPrefix)N(.+)E\Z/$1$2/g;
3916 }
3917 else {
3918 $Mangled=~s/\AN(.+)E\Z/$1/g;
3919 }
3920 }
3921 }
3922 else {
3923 $Mangled = $Optimized;
3924 }
3925 }
3926 add_substitution($Mangled, $Repl, 1);
3927 return $Mangled;
3928}
3929
3930sub mangle_template_param($$$)
3931{ # types + literals
3932 my ($TParam, $LibVersion, $Repl) = @_;
3933 if(my $TPTid = $TName_Tid{$LibVersion}{$TParam}) {
3934 return mangle_param($TPTid, $LibVersion, $Repl);
3935 }
3936 elsif($TParam=~/\A(\d+)(\w+)\Z/)
3937 { # class_name<1u>::method(...)
3938 return "L".$IntrinsicMangling{$ConstantSuffixR{$2}}.$1."E";
3939 }
3940 elsif($TParam=~/\A\(([\w ]+)\)(\d+)\Z/)
3941 { # class_name<(signed char)1>::method(...)
3942 return "L".$IntrinsicMangling{$1}.$2."E";
3943 }
3944 elsif($TParam eq "true")
3945 { # class_name<true>::method(...)
3946 return "Lb1E";
3947 }
3948 elsif($TParam eq "false")
3949 { # class_name<true>::method(...)
3950 return "Lb0E";
3951 }
3952 else { # internal error
3953 return length($TParam).$TParam;
3954 }
3955}
3956
3957sub add_substitution($$$)
3958{
3959 my ($Value, $Repl, $Rec) = @_;
3960 if($Rec)
3961 { # subtypes
3962 my @Subs = ($Value);
3963 while($Value=~s/\A(R|P|K)//) {
3964 push(@Subs, $Value);
3965 }
3966 foreach (reverse(@Subs)) {
3967 add_substitution($_, $Repl, 0);
3968 }
3969 return;
3970 }
3971 return if($Value=~/\AS(\d*)_\Z/);
3972 $Value=~s/\AN(.+)E\Z/$1/g;
3973 return if(defined $Repl->{$Value});
3974 return if(length($Value)<=1);
3975 return if($StdcxxMangling{$Value});
3976 # check for duplicates
3977 my $Base = $Value;
3978 foreach my $Type (sort {$Repl->{$a}<=>$Repl->{$b}} sort keys(%{$Repl}))
3979 {
3980 my $Num = $Repl->{$Type};
3981 my $Replace = macro_mangle($Num);
3982 $Base=~s/\Q$Replace\E/$Type/;
3983 }
3984 if(my $OldNum = $Repl->{$Base})
3985 {
3986 $Repl->{$Value} = $OldNum;
3987 return;
3988 }
3989 my @Repls = sort {$b<=>$a} values(%{$Repl});
3990 if(@Repls) {
3991 $Repl->{$Value} = $Repls[0]+1;
3992 }
3993 else {
3994 $Repl->{$Value} = -1;
3995 }
3996 # register duplicates
3997 # upward
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04003998 $Base = $Value;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003999 foreach my $Type (sort {$Repl->{$a}<=>$Repl->{$b}} sort keys(%{$Repl}))
4000 {
4001 next if($Base eq $Type);
4002 my $Num = $Repl->{$Type};
4003 my $Replace = macro_mangle($Num);
4004 $Base=~s/\Q$Type\E/$Replace/;
4005 $Repl->{$Base} = $Repl->{$Value};
4006 }
4007}
4008
4009sub macro_mangle($)
4010{
4011 my $Num = $_[0];
4012 if($Num==-1) {
4013 return "S_";
4014 }
4015 else
4016 {
4017 my $Code = "";
4018 if($Num<10)
4019 { # S0_, S1_, S2_, ...
4020 $Code = $Num;
4021 }
4022 elsif($Num>=10 and $Num<=35)
4023 { # SA_, SB_, SC_, ...
4024 $Code = chr(55+$Num);
4025 }
4026 else
4027 { # S10_, S11_, S12_
4028 $Code = $Num-26; # 26 is length of english alphabet
4029 }
4030 return "S".$Code."_";
4031 }
4032}
4033
4034sub write_stdcxx_substitution($)
4035{
4036 my $Mangled = $_[0];
4037 if($StdcxxMangling{$Mangled}) {
4038 return $StdcxxMangling{$Mangled};
4039 }
4040 else
4041 {
4042 my @Repls = keys(%StdcxxMangling);
4043 @Repls = sort {length($b)<=>length($a)} sort {$b cmp $a} @Repls;
4044 foreach my $MangledType (@Repls)
4045 {
4046 my $Replace = $StdcxxMangling{$MangledType};
4047 #if($Mangled!~/$Replace/) {
4048 $Mangled=~s/N\Q$MangledType\EE/$Replace/g;
4049 $Mangled=~s/\Q$MangledType\E/$Replace/g;
4050 #}
4051 }
4052 }
4053 return $Mangled;
4054}
4055
4056sub write_substitution($$)
4057{
4058 my ($Mangled, $Repl) = @_;
4059 if(defined $Repl->{$Mangled}
4060 and my $MnglNum = $Repl->{$Mangled}) {
4061 $Mangled = macro_mangle($MnglNum);
4062 }
4063 else
4064 {
4065 my @Repls = keys(%{$Repl});
4066 #@Repls = sort {$Repl->{$a}<=>$Repl->{$b}} @Repls;
4067 # FIXME: how to apply replacements? by num or by pos
4068 @Repls = sort {length($b)<=>length($a)} sort {$b cmp $a} @Repls;
4069 foreach my $MangledType (@Repls)
4070 {
4071 my $Replace = macro_mangle($Repl->{$MangledType});
4072 if($Mangled!~/$Replace/) {
4073 $Mangled=~s/N\Q$MangledType\EE/$Replace/g;
4074 $Mangled=~s/\Q$MangledType\E/$Replace/g;
4075 }
4076 }
4077 }
4078 return $Mangled;
4079}
4080
4081sub delete_keywords($)
4082{
4083 my $TypeName = $_[0];
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04004084 $TypeName=~s/\b(enum|struct|union|class) //g;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004085 return $TypeName;
4086}
4087
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004088sub uncover_typedefs($$)
4089{
4090 my ($TypeName, $LibVersion) = @_;
4091 return "" if(not $TypeName);
4092 if(defined $Cache{"uncover_typedefs"}{$LibVersion}{$TypeName}) {
4093 return $Cache{"uncover_typedefs"}{$LibVersion}{$TypeName};
4094 }
4095 my ($TypeName_New, $TypeName_Pre) = (formatName($TypeName), "");
4096 while($TypeName_New ne $TypeName_Pre)
4097 {
4098 $TypeName_Pre = $TypeName_New;
4099 my $TypeName_Copy = $TypeName_New;
4100 my %Words = ();
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04004101 while($TypeName_Copy=~s/\b([a-z_]([\w:]*\w|))\b//io)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004102 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04004103 if(not $Intrinsic_Keywords{$1}) {
4104 $Words{$1} = 1;
4105 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004106 }
4107 foreach my $Word (keys(%Words))
4108 {
4109 my $BaseType_Name = $Typedef_BaseName{$LibVersion}{$Word};
4110 next if(not $BaseType_Name);
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04004111 next if($TypeName_New=~/\b(struct|union|enum)\s\Q$Word\E\b/);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004112 if($BaseType_Name=~/\([\*]+\)/)
4113 { # FuncPtr
4114 if($TypeName_New=~/\Q$Word\E(.*)\Z/)
4115 {
4116 my $Type_Suffix = $1;
4117 $TypeName_New = $BaseType_Name;
4118 if($TypeName_New=~s/\(([\*]+)\)/($1 $Type_Suffix)/) {
4119 $TypeName_New = formatName($TypeName_New);
4120 }
4121 }
4122 }
4123 else
4124 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04004125 if($TypeName_New=~s/\b\Q$Word\E\b/$BaseType_Name/g) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004126 $TypeName_New = formatName($TypeName_New);
4127 }
4128 }
4129 }
4130 }
4131 return ($Cache{"uncover_typedefs"}{$LibVersion}{$TypeName} = $TypeName_New);
4132}
4133
4134sub isInternal($)
4135{
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04004136 if($_[0] and my $Info = $LibInfo{$Version}{"info"}{$_[0]})
4137 {
4138 if($Info=~/mngl[ ]*:[ ]*@(\d+) /)
4139 {
4140 if($LibInfo{$Version}{"info"}{$1}=~/\*[ ]*INTERNAL[ ]*\*/)
4141 { # _ZN7mysqlpp8DateTimeC1ERKS0_ *INTERNAL*
4142 return 1;
4143 }
4144 }
4145 }
4146 return 0;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004147}
4148
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04004149sub getDataVal($$)
4150{
4151 my ($InfoId, $TypeId) = @_;
4152 if(my $Info = $LibInfo{$Version}{"info"}{$InfoId})
4153 {
4154 if($Info=~/init[ ]*:[ ]*@(\d+) /)
4155 {
4156 if(defined $LibInfo{$Version}{"info_type"}{$1}
4157 and $LibInfo{$Version}{"info_type"}{$1} eq "nop_expr")
4158 { # char const* data = "str"
4159 # NOTE: disabled
4160 if(my $NopExpr = $LibInfo{$Version}{"info"}{$1})
4161 {
4162 if($NopExpr=~/op 0[ ]*:[ ]*@(\d+) /)
4163 {
4164 if(defined $LibInfo{$Version}{"info_type"}{$1}
4165 and $LibInfo{$Version}{"info_type"}{$1} eq "addr_expr")
4166 {
4167 if(my $AddrExpr = $LibInfo{$Version}{"info"}{$1})
4168 {
4169 if($AddrExpr=~/op 0[ ]*:[ ]*@(\d+) /)
4170 {
4171 return getInitVal($1, $TypeId);
4172 }
4173 }
4174 }
4175 }
4176 }
4177 }
4178 else {
4179 return getInitVal($1, $TypeId);
4180 }
4181 }
4182 }
4183 return undef;
4184}
4185
4186sub getInitVal($$)
4187{
4188 my ($InfoId, $TypeId) = @_;
4189 if(my $Info = $LibInfo{$Version}{"info"}{$InfoId})
4190 {
4191 if(my $InfoType = $LibInfo{$Version}{"info_type"}{$InfoId})
4192 {
4193 if($InfoType eq "integer_cst")
4194 {
4195 my $Val = getNodeIntCst($InfoId);
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04004196 if($TypeId and $TypeInfo{$Version}{$TypeId}{"Name"}=~/\Achar(| const)\Z/)
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04004197 { # characters
4198 $Val = chr($Val);
4199 }
4200 return $Val;
4201 }
4202 elsif($InfoType eq "string_cst") {
4203 return getNodeStrCst($InfoId);
4204 }
4205 }
4206 }
4207 return undef;
4208}
4209
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004210sub set_Class_And_Namespace($)
4211{
4212 my $InfoId = $_[0];
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04004213 if(my $Info = $LibInfo{$Version}{"info"}{$InfoId})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004214 {
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04004215 if($Info=~/scpe[ ]*:[ ]*@(\d+) /)
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04004216 {
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04004217 my $NSInfoId = $1;
4218 if(my $InfoType = $LibInfo{$Version}{"info_type"}{$NSInfoId})
4219 {
4220 if($InfoType eq "namespace_decl") {
4221 $SymbolInfo{$Version}{$InfoId}{"NameSpace"} = getNameSpace($InfoId);
4222 }
4223 elsif($InfoType eq "record_type") {
4224 $SymbolInfo{$Version}{$InfoId}{"Class"} = $NSInfoId;
4225 }
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04004226 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004227 }
4228 }
4229 if($SymbolInfo{$Version}{$InfoId}{"Class"}
4230 or $SymbolInfo{$Version}{$InfoId}{"NameSpace"})
4231 { # identify language
4232 setLanguage($Version, "C++");
4233 }
4234}
4235
4236sub debugType($$)
4237{
4238 my ($Tid, $LibVersion) = @_;
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04004239 my %Type = get_Type($Tid, $LibVersion);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004240 printMsg("INFO", Dumper(\%Type));
4241}
4242
4243sub debugMangling($)
4244{
4245 my $LibVersion = $_[0];
4246 my %Mangled = ();
4247 foreach my $InfoId (keys(%{$SymbolInfo{$LibVersion}}))
4248 {
4249 if(my $Mngl = $SymbolInfo{$LibVersion}{$InfoId}{"MnglName"})
4250 {
4251 if($Mngl=~/\A(_Z|\?)/) {
4252 $Mangled{$Mngl}=$InfoId;
4253 }
4254 }
4255 }
4256 translateSymbols(keys(%Mangled), $LibVersion);
4257 foreach my $Mngl (keys(%Mangled))
4258 {
Andrey Ponomarenko85043792012-05-14 16:48:07 +04004259 my $U1 = modelUnmangled($Mangled{$Mngl}, "GCC");
4260 my $U2 = $tr_name{$Mngl};
4261 if($U1 ne $U2) {
4262 printMsg("INFO", "INCORRECT MANGLING:\n $Mngl\n $U1\n $U2\n");
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004263 }
4264 }
4265}
4266
4267sub linkSymbol($)
4268{ # link symbols from shared libraries
4269 # with the symbols from header files
4270 my $InfoId = $_[0];
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04004271 if(my $Lang = $SymbolInfo{$Version}{$InfoId}{"Lang"})
4272 {
4273 if($Lang eq "C")
4274 { # extern "C"
4275 return $SymbolInfo{$Version}{$InfoId}{"ShortName"};
4276 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004277 }
4278 # try to mangle symbol
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04004279 if((not check_gcc($GCC_PATH, "4") and $SymbolInfo{$Version}{$InfoId}{"Class"})
4280 or (check_gcc($GCC_PATH, "4") and not $SymbolInfo{$Version}{$InfoId}{"Class"}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004281 { # 1. GCC 3.x doesn't mangle class methods names in the TU dump (only functions and global data)
4282 # 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 +04004283 if(not $CheckHeadersOnly)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004284 {
4285 if(my $Mangled = $mangled_name_gcc{modelUnmangled($InfoId, "GCC")}) {
4286 return correct_incharge($InfoId, $Version, $Mangled);
4287 }
4288 }
Andrey Ponomarenko16934472012-03-29 15:37:04 +04004289 if($CheckHeadersOnly
4290 or not $BinaryOnly)
4291 { # 1. --headers-only mode
4292 # 2. not mangled src-only symbols
4293 if(my $Mangled = mangle_symbol($InfoId, $Version, "GCC")) {
4294 return $Mangled;
4295 }
4296 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004297 }
4298 return "";
4299}
4300
4301sub setLanguage($$)
4302{
4303 my ($LibVersion, $Lang) = @_;
4304 if(not $UserLang) {
4305 $COMMON_LANGUAGE{$LibVersion} = $Lang;
4306 }
4307}
4308
4309sub getSymbolInfo($)
4310{
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04004311 my $InfoId = $_[0];
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04004312 if(isInternal($InfoId)) {
4313 return;
4314 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04004315 ($SymbolInfo{$Version}{$InfoId}{"Header"}, $SymbolInfo{$Version}{$InfoId}{"Line"}) = getLocation($InfoId);
4316 if(not $SymbolInfo{$Version}{$InfoId}{"Header"}
Andrey Ponomarenkoa01311b2012-06-08 17:20:02 +04004317 or isBuiltIn($SymbolInfo{$Version}{$InfoId}{"Header"}))
4318 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04004319 delete($SymbolInfo{$Version}{$InfoId});
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004320 return;
4321 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04004322 setFuncAccess($InfoId);
4323 setFuncKind($InfoId);
Andrey Ponomarenkoa01311b2012-06-08 17:20:02 +04004324 if($SymbolInfo{$Version}{$InfoId}{"PseudoTemplate"})
4325 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04004326 delete($SymbolInfo{$Version}{$InfoId});
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004327 return;
4328 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04004329 $SymbolInfo{$Version}{$InfoId}{"Type"} = getFuncType($InfoId);
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04004330 if($SymbolInfo{$Version}{$InfoId}{"Return"} = getFuncReturn($InfoId))
4331 {
4332 if(not $TypeInfo{$Version}{$SymbolInfo{$Version}{$InfoId}{"Return"}}{"Name"})
4333 { # templates
4334 delete($SymbolInfo{$Version}{$InfoId});
4335 return;
4336 }
4337 }
4338 if(my $Rid = $SymbolInfo{$Version}{$InfoId}{"Return"})
4339 {
4340 if(defined $MissedTypedef{$Version}{$Rid})
4341 {
4342 if(my $AddedTid = $MissedTypedef{$Version}{$Rid}{"Tid"}) {
4343 $SymbolInfo{$Version}{$InfoId}{"Return"} = $AddedTid;
4344 }
4345 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004346 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04004347 if(not $SymbolInfo{$Version}{$InfoId}{"Return"}) {
4348 delete($SymbolInfo{$Version}{$InfoId}{"Return"});
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004349 }
Andrey Ponomarenkoa01311b2012-06-08 17:20:02 +04004350 my $Orig = getFuncOrig($InfoId);
4351 $SymbolInfo{$Version}{$InfoId}{"ShortName"} = getFuncShortName($Orig);
4352 if($SymbolInfo{$Version}{$InfoId}{"ShortName"}=~/\._/)
4353 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04004354 delete($SymbolInfo{$Version}{$InfoId});
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004355 return;
4356 }
Andrey Ponomarenkoa01311b2012-06-08 17:20:02 +04004357
4358 if(defined $TemplateInstance{$Version}{"Func"}{$Orig})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004359 {
Andrey Ponomarenkoa01311b2012-06-08 17:20:02 +04004360 my @TParams = getTParams($Orig, "Func");
4361 if(not @TParams)
4362 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04004363 delete($SymbolInfo{$Version}{$InfoId});
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004364 return;
4365 }
Andrey Ponomarenko16934472012-03-29 15:37:04 +04004366 foreach my $Pos (0 .. $#TParams) {
4367 $SymbolInfo{$Version}{$InfoId}{"TParam"}{$Pos}{"name"}=$TParams[$Pos];
4368 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004369 my $PrmsInLine = join(", ", @TParams);
Andrey Ponomarenko16934472012-03-29 15:37:04 +04004370 if($SymbolInfo{$Version}{$InfoId}{"ShortName"}=~/\Aoperator\W+\Z/)
4371 { # operator<< <T>, operator>> <T>
4372 $SymbolInfo{$Version}{$InfoId}{"ShortName"} .= " ";
4373 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04004374 $SymbolInfo{$Version}{$InfoId}{"ShortName"} .= "<".$PrmsInLine.">";
4375 $SymbolInfo{$Version}{$InfoId}{"ShortName"} = formatName($SymbolInfo{$Version}{$InfoId}{"ShortName"});
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004376 }
4377 else
4378 { # support for GCC 3.4
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04004379 $SymbolInfo{$Version}{$InfoId}{"ShortName"}=~s/<.+>\Z//;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004380 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04004381 $SymbolInfo{$Version}{$InfoId}{"MnglName"} = getTreeStr(getTreeAttr_Mngl($InfoId));
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04004382 # NOTE: mangling of some symbols may change depending on GCC version
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04004383 # GCC 4.6: _ZN28QExplicitlySharedDataPointerI11QPixmapDataEC2IT_EERKS_IT_E
4384 # GCC 4.7: _ZN28QExplicitlySharedDataPointerI11QPixmapDataEC2ERKS1_
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04004385
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04004386 if($SymbolInfo{$Version}{$InfoId}{"MnglName"}
4387 and $SymbolInfo{$Version}{$InfoId}{"MnglName"}!~/\A_Z/)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004388 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04004389 delete($SymbolInfo{$Version}{$InfoId});
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004390 return;
4391 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04004392 if(not $SymbolInfo{$Version}{$InfoId}{"Destructor"})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004393 { # destructors have an empty parameter list
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04004394 my $Skip = setFuncParams($InfoId);
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04004395 if($Skip) {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04004396 delete($SymbolInfo{$Version}{$InfoId});
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004397 return;
4398 }
4399 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04004400 set_Class_And_Namespace($InfoId);
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04004401 if(my $ClassId = $SymbolInfo{$Version}{$InfoId}{"Class"})
4402 {
4403 if(not $TypeInfo{$Version}{$ClassId}{"Name"})
4404 { # templates
4405 delete($SymbolInfo{$Version}{$InfoId});
4406 return;
4407 }
4408 }
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04004409 if(not $CheckHeadersOnly)
4410 {
4411 if($SymbolInfo{$Version}{$InfoId}{"Type"} eq "Function"
4412 and not $SymbolInfo{$Version}{$InfoId}{"Class"}
4413 and link_symbol($SymbolInfo{$Version}{$InfoId}{"ShortName"}, $Version, "-Deps"))
4414 { # functions (C++): not mangled in library, but are mangled in TU dump
4415 if(not $SymbolInfo{$Version}{$InfoId}{"MnglName"}
4416 or not link_symbol($SymbolInfo{$Version}{$InfoId}{"MnglName"}, $Version, "-Deps")) {
4417 $SymbolInfo{$Version}{$InfoId}{"MnglName"} = $SymbolInfo{$Version}{$InfoId}{"ShortName"};
4418 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004419 }
4420 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04004421 if($LibInfo{$Version}{"info"}{$InfoId}=~/ lang:[ ]*C /i) {
4422 $SymbolInfo{$Version}{$InfoId}{"Lang"} = "C";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004423 }
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04004424 if($UserLang and $UserLang eq "C")
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004425 { # --lang=C option
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04004426 $SymbolInfo{$Version}{$InfoId}{"MnglName"} = $SymbolInfo{$Version}{$InfoId}{"ShortName"};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004427 }
4428 if($COMMON_LANGUAGE{$Version} eq "C++")
4429 { # correct mangled & short names
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04004430 # C++ or --headers-only mode
4431 if($SymbolInfo{$Version}{$InfoId}{"ShortName"}=~/\A__(comp|base|deleting)_(c|d)tor\Z/)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004432 { # support for old GCC versions: reconstruct real names for constructors and destructors
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04004433 $SymbolInfo{$Version}{$InfoId}{"ShortName"} = getNameByInfo(getTypeDeclId($SymbolInfo{$Version}{$InfoId}{"Class"}));
4434 $SymbolInfo{$Version}{$InfoId}{"ShortName"}=~s/<.+>\Z//;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004435 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04004436 if(not $SymbolInfo{$Version}{$InfoId}{"MnglName"})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004437 { # try to mangle symbol (link with libraries)
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04004438 if(my $Mangled = linkSymbol($InfoId)) {
4439 $SymbolInfo{$Version}{$InfoId}{"MnglName"} = $Mangled;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004440 }
4441 }
4442 if($OStarget eq "windows")
4443 { # link MS C++ symbols from library with GCC symbols from headers
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04004444 if(my $Mangled1 = $mangled_name{$Version}{modelUnmangled($InfoId, "MSVC")})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004445 { # exported symbols
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04004446 $SymbolInfo{$Version}{$InfoId}{"MnglName"} = $Mangled1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004447 }
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04004448 elsif(my $Mangled2 = mangle_symbol($InfoId, $Version, "MSVC"))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004449 { # pure virtual symbols
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04004450 $SymbolInfo{$Version}{$InfoId}{"MnglName"} = $Mangled2;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004451 }
4452 }
4453 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04004454 if(not $SymbolInfo{$Version}{$InfoId}{"MnglName"})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004455 { # can't detect symbol name
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04004456 delete($SymbolInfo{$Version}{$InfoId});
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004457 return;
4458 }
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04004459 if(not $SymbolInfo{$Version}{$InfoId}{"Constructor"}
Andrey Ponomarenkoa01311b2012-06-08 17:20:02 +04004460 and my $Spec = getVirtSpec($Orig))
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04004461 { # identify virtual and pure virtual functions
4462 # NOTE: constructors cannot be virtual
4463 # NOTE: in GCC 4.7 D1 destructors have no virtual spec
4464 # in the TU dump, so taking it from the original symbol
4465 if(not ($SymbolInfo{$Version}{$InfoId}{"Destructor"}
4466 and $SymbolInfo{$Version}{$InfoId}{"MnglName"}=~/D2E/))
4467 { # NOTE: D2 destructors are not present in a v-table
4468 $SymbolInfo{$Version}{$InfoId}{$Spec} = 1;
4469 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004470 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04004471 if(isInline($InfoId)) {
4472 $SymbolInfo{$Version}{$InfoId}{"InLine"} = 1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004473 }
Andrey Ponomarenkob8d203d2012-05-25 18:11:07 +04004474 if($LibInfo{$Version}{"info"}{$InfoId}=~/ artificial /i) {
4475 $SymbolInfo{$Version}{$InfoId}{"Artificial"} = 1;
4476 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04004477 if($SymbolInfo{$Version}{$InfoId}{"Constructor"}
4478 and my $ClassId = $SymbolInfo{$Version}{$InfoId}{"Class"})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004479 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04004480 if(not $SymbolInfo{$Version}{$InfoId}{"InLine"}
Andrey Ponomarenkob8d203d2012-05-25 18:11:07 +04004481 and not $SymbolInfo{$Version}{$InfoId}{"Artificial"})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004482 { # inline or auto-generated constructor
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04004483 delete($TypeInfo{$Version}{$ClassId}{"Copied"});
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004484 }
4485 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +04004486 if(my $Symbol = $SymbolInfo{$Version}{$InfoId}{"MnglName"})
4487 {
4488 if(not $SymbolInfo{$Version}{$InfoId}{"Virt"}
4489 and not $SymbolInfo{$Version}{$InfoId}{"PureVirt"})
4490 {
4491 if(not selectSymbol($Symbol, $SymbolInfo{$Version}{$InfoId}, "Dump", $Version))
4492 { # non-target symbols
4493 delete($SymbolInfo{$Version}{$InfoId});
4494 return;
4495 }
4496 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004497 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04004498 if($SymbolInfo{$Version}{$InfoId}{"Type"} eq "Method"
4499 or $SymbolInfo{$Version}{$InfoId}{"Constructor"}
4500 or $SymbolInfo{$Version}{$InfoId}{"Destructor"}
4501 or $SymbolInfo{$Version}{$InfoId}{"Class"})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004502 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04004503 if($SymbolInfo{$Version}{$InfoId}{"MnglName"}!~/\A(_Z|\?)/) {
4504 delete($SymbolInfo{$Version}{$InfoId});
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004505 return;
4506 }
4507 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04004508 if($SymbolInfo{$Version}{$InfoId}{"MnglName"})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004509 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04004510 if($MangledNames{$Version}{$SymbolInfo{$Version}{$InfoId}{"MnglName"}})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004511 { # one instance for one mangled name only
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04004512 delete($SymbolInfo{$Version}{$InfoId});
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004513 return;
4514 }
4515 else {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04004516 $MangledNames{$Version}{$SymbolInfo{$Version}{$InfoId}{"MnglName"}} = 1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004517 }
4518 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04004519 if($SymbolInfo{$Version}{$InfoId}{"Constructor"}
4520 or $SymbolInfo{$Version}{$InfoId}{"Destructor"}) {
4521 delete($SymbolInfo{$Version}{$InfoId}{"Return"});
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004522 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04004523 if($SymbolInfo{$Version}{$InfoId}{"MnglName"}=~/\A(_Z|\?)/
4524 and $SymbolInfo{$Version}{$InfoId}{"Class"})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004525 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04004526 if($SymbolInfo{$Version}{$InfoId}{"Type"} eq "Function")
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004527 { # static methods
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04004528 $SymbolInfo{$Version}{$InfoId}{"Static"} = 1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004529 }
4530 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04004531 if(getFuncLink($InfoId) eq "Static") {
4532 $SymbolInfo{$Version}{$InfoId}{"Static"} = 1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004533 }
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04004534 if($SymbolInfo{$Version}{$InfoId}{"MnglName"}=~/\A(_Z|\?)/)
4535 {
4536 if(my $Unmangled = $tr_name{$SymbolInfo{$Version}{$InfoId}{"MnglName"}})
4537 {
4538 if($Unmangled=~/\.\_\d/) {
4539 delete($SymbolInfo{$Version}{$InfoId});
4540 return;
4541 }
4542 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004543 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04004544 delete($SymbolInfo{$Version}{$InfoId}{"Type"});
4545 if($SymbolInfo{$Version}{$InfoId}{"MnglName"}=~/\A_ZN(V|)K/) {
4546 $SymbolInfo{$Version}{$InfoId}{"Const"} = 1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004547 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04004548 if($SymbolInfo{$Version}{$InfoId}{"MnglName"}=~/\A_ZN(K|)V/) {
4549 $SymbolInfo{$Version}{$InfoId}{"Volatile"} = 1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004550 }
4551}
4552
4553sub isInline($)
4554{ # "body: undefined" in the tree
4555 # -fkeep-inline-functions GCC option should be specified
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04004556 if($_[0] and my $Info = $LibInfo{$Version}{"info"}{$_[0]})
4557 {
4558 if($Info=~/ undefined /i) {
4559 return 0;
4560 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004561 }
4562 return 1;
4563}
4564
4565sub getTypeId($)
4566{
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04004567 if($_[0] and my $Info = $LibInfo{$Version}{"info"}{$_[0]})
4568 {
4569 if($Info=~/type[ ]*:[ ]*@(\d+) /) {
4570 return $1;
4571 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004572 }
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04004573 return "";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004574}
4575
4576sub setTypeMemb($$)
4577{
4578 my ($TypeId, $TypeAttr) = @_;
4579 my $TypeType = $TypeAttr->{"Type"};
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04004580 my ($Pos, $UnnamedPos) = (0, 0);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004581 if($TypeType eq "Enum")
4582 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04004583 my $TypeMembInfoId = getTreeAttr_Csts($TypeId);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004584 while($TypeMembInfoId)
4585 {
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04004586 $TypeAttr->{"Memb"}{$Pos}{"value"} = getEnumMembVal($TypeMembInfoId);
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04004587 my $MembName = getTreeStr(getTreeAttr_Purp($TypeMembInfoId));
4588 $TypeAttr->{"Memb"}{$Pos}{"name"} = $MembName;
4589 $EnumMembName_Id{$Version}{getTreeAttr_Valu($TypeMembInfoId)} = ($TypeAttr->{"NameSpace"})?$TypeAttr->{"NameSpace"}."::".$MembName:$MembName;
4590 $TypeMembInfoId = getNextElem($TypeMembInfoId);
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04004591 $Pos += 1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004592 }
4593 }
4594 elsif($TypeType=~/\A(Struct|Class|Union)\Z/)
4595 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04004596 my $TypeMembInfoId = getTreeAttr_Flds($TypeId);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004597 while($TypeMembInfoId)
4598 {
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04004599 my $IType = $LibInfo{$Version}{"info_type"}{$TypeMembInfoId};
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04004600 my $MInfo = $LibInfo{$Version}{"info"}{$TypeMembInfoId};
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04004601 if(not $IType or $IType ne "field_decl")
4602 { # search for fields, skip other stuff in the declaration
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04004603 $TypeMembInfoId = getNextElem($TypeMembInfoId);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004604 next;
4605 }
4606 my $StructMembName = getStructMembName($TypeMembInfoId);
4607 if($StructMembName=~/_vptr\./)
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04004608 { # virtual tables
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04004609 $TypeMembInfoId = getNextElem($TypeMembInfoId);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004610 next;
4611 }
4612 if(not $StructMembName)
4613 { # unnamed fields
4614 if($TypeAttr->{"Name"}!~/_type_info_pseudo/)
4615 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04004616 my $UnnamedTid = getTreeAttr_Type($TypeMembInfoId);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004617 my $UnnamedTName = getNameByInfo(getTypeDeclId($UnnamedTid));
4618 if(isAnon($UnnamedTName))
4619 { # rename unnamed fields to unnamed0, unnamed1, ...
4620 $StructMembName = "unnamed".($UnnamedPos++);
4621 }
4622 }
4623 }
4624 if(not $StructMembName)
4625 { # unnamed fields and base classes
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04004626 $TypeMembInfoId = getNextElem($TypeMembInfoId);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004627 next;
4628 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04004629 my $MembTypeId = getTreeAttr_Type($TypeMembInfoId);
4630 if(defined $MissedTypedef{$Version}{$MembTypeId})
4631 {
4632 if(my $AddedTid = $MissedTypedef{$Version}{$MembTypeId}{"Tid"}) {
4633 $MembTypeId = $AddedTid;
4634 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004635 }
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04004636 $TypeAttr->{"Memb"}{$Pos}{"type"} = $MembTypeId;
4637 $TypeAttr->{"Memb"}{$Pos}{"name"} = $StructMembName;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004638 if((my $Access = getTreeAccess($TypeMembInfoId)) ne "public")
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04004639 { # marked only protected and private, public by default
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04004640 $TypeAttr->{"Memb"}{$Pos}{"access"} = $Access;
4641 }
4642 if($MInfo=~/spec:\s*mutable /)
4643 { # mutable fields
4644 $TypeAttr->{"Memb"}{$Pos}{"mutable"} = 1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004645 }
4646 if(my $BFSize = getStructMembBitFieldSize($TypeMembInfoId)) {
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04004647 $TypeAttr->{"Memb"}{$Pos}{"bitfield"} = $BFSize;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004648 }
4649 else
4650 { # set alignment for non-bit fields
4651 # alignment for bitfields is always equal to 1 bit
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04004652 if(my $Algn = getAlgn($TypeMembInfoId)) {
4653 $TypeAttr->{"Memb"}{$Pos}{"algn"} = $Algn/$BYTE_SIZE;
4654 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004655 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04004656 $TypeMembInfoId = getNextElem($TypeMembInfoId);
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04004657 $Pos += 1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004658 }
4659 }
4660}
4661
4662sub setFuncParams($)
4663{
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04004664 my $InfoId = $_[0];
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04004665 my $ParamInfoId = getTreeAttr_Args($InfoId);
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04004666 if(getFuncType($InfoId) eq "Method")
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004667 { # check type of "this" pointer
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04004668 my $ObjectTypeId = getTreeAttr_Type($ParamInfoId);
4669 if(my $ObjectName = $TypeInfo{$Version}{$ObjectTypeId}{"Name"})
Andrey Ponomarenko85043792012-05-14 16:48:07 +04004670 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04004671 if($ObjectName=~/\bconst(| volatile)\*const\b/) {
Andrey Ponomarenko85043792012-05-14 16:48:07 +04004672 $SymbolInfo{$Version}{$InfoId}{"Const"} = 1;
4673 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04004674 if($ObjectName=~/\bvolatile\b/) {
Andrey Ponomarenko85043792012-05-14 16:48:07 +04004675 $SymbolInfo{$Version}{$InfoId}{"Volatile"} = 1;
4676 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004677 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +04004678 else
4679 { # skip
4680 return 1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004681 }
4682 $ParamInfoId = getNextElem($ParamInfoId);
4683 }
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04004684 my ($Pos, $Vtt_Pos) = (0, -1);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004685 while($ParamInfoId)
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04004686 { # formal args
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04004687 my $ParamTypeId = getTreeAttr_Type($ParamInfoId);
4688 my $ParamName = getTreeStr(getTreeAttr_Name($ParamInfoId));
4689 if(not $ParamName)
4690 { # unnamed
4691 $ParamName = "p".($Pos+1);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004692 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04004693 if(defined $MissedTypedef{$Version}{$ParamTypeId})
4694 {
4695 if(my $AddedTid = $MissedTypedef{$Version}{$ParamTypeId}{"Tid"}) {
4696 $ParamTypeId = $AddedTid;
4697 }
4698 }
4699 my $PType = $TypeInfo{$Version}{$ParamTypeId}{"Type"};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004700 if(not $PType or $PType eq "Unknown") {
4701 return 1;
4702 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04004703 my $PTName = $TypeInfo{$Version}{$ParamTypeId}{"Name"};
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04004704 if(not $PTName) {
4705 return 1;
4706 }
4707 if($PTName eq "void") {
4708 last;
4709 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004710 if($ParamName eq "__vtt_parm"
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04004711 and $TypeInfo{$Version}{$ParamTypeId}{"Name"} eq "void const**")
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004712 {
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04004713 $Vtt_Pos = $Pos;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004714 $ParamInfoId = getNextElem($ParamInfoId);
4715 next;
4716 }
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04004717 $SymbolInfo{$Version}{$InfoId}{"Param"}{$Pos}{"type"} = $ParamTypeId;
4718 $SymbolInfo{$Version}{$InfoId}{"Param"}{$Pos}{"name"} = $ParamName;
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04004719 if(my $Algn = getAlgn($ParamInfoId)) {
4720 $SymbolInfo{$Version}{$InfoId}{"Param"}{$Pos}{"algn"} = $Algn/$BYTE_SIZE;
4721 }
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04004722 if(not $SymbolInfo{$Version}{$InfoId}{"Param"}{$Pos}{"name"}) {
4723 $SymbolInfo{$Version}{$InfoId}{"Param"}{$Pos}{"name"} = "p".($Pos+1);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004724 }
4725 if($LibInfo{$Version}{"info"}{$ParamInfoId}=~/spec:\s*register /)
4726 { # foo(register type arg)
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04004727 $SymbolInfo{$Version}{$InfoId}{"Param"}{$Pos}{"reg"} = 1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004728 }
4729 $ParamInfoId = getNextElem($ParamInfoId);
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04004730 $Pos += 1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004731 }
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04004732 if(setFuncArgs($InfoId, $Vtt_Pos)) {
4733 $SymbolInfo{$Version}{$InfoId}{"Param"}{$Pos}{"type"} = -1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004734 }
4735 return 0;
4736}
4737
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04004738sub setFuncArgs($$)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004739{
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04004740 my ($InfoId, $Vtt_Pos) = @_;
4741 my $FuncTypeId = getFuncTypeId($InfoId);
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04004742 my $ParamListElemId = getTreeAttr_Prms($FuncTypeId);
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04004743 if(getFuncType($InfoId) eq "Method") {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004744 $ParamListElemId = getNextElem($ParamListElemId);
4745 }
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04004746 if(not $ParamListElemId)
4747 { # foo(...)
4748 return 1;
4749 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004750 my $HaveVoid = 0;
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04004751 my $Pos = 0;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004752 while($ParamListElemId)
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04004753 { # actual params: may differ from formal args
4754 # formal int*const
4755 # actual: int*
4756 if($Vtt_Pos!=-1 and $Pos==$Vtt_Pos)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004757 {
4758 $Vtt_Pos=-1;
4759 $ParamListElemId = getNextElem($ParamListElemId);
4760 next;
4761 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04004762 my $ParamTypeId = getTreeAttr_Valu($ParamListElemId);
4763 if($TypeInfo{$Version}{$ParamTypeId}{"Name"} eq "void")
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04004764 {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004765 $HaveVoid = 1;
4766 last;
4767 }
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04004768 elsif(not defined $SymbolInfo{$Version}{$InfoId}{"Param"}{$Pos}{"type"})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004769 {
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04004770 $SymbolInfo{$Version}{$InfoId}{"Param"}{$Pos}{"type"} = $ParamTypeId;
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04004771 if(not $SymbolInfo{$Version}{$InfoId}{"Param"}{$Pos}{"name"})
4772 { # unnamed
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04004773 $SymbolInfo{$Version}{$InfoId}{"Param"}{$Pos}{"name"} = "p".($Pos+1);
4774 }
4775 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04004776 if(my $PurpId = getTreeAttr_Purp($ParamListElemId))
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04004777 { # default arguments
4778 if(my $PurpType = $LibInfo{$Version}{"info_type"}{$PurpId}) {
4779 $SymbolInfo{$Version}{$InfoId}{"Param"}{$Pos}{"default"} = getInitVal($PurpId, $ParamTypeId);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004780 }
4781 }
4782 $ParamListElemId = getNextElem($ParamListElemId);
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04004783 $Pos += 1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004784 }
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04004785 return ($Pos>=1 and not $HaveVoid);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004786}
4787
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04004788sub getTreeAttr_Chan($)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004789{
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04004790 if($_[0] and my $Info = $LibInfo{$Version}{"info"}{$_[0]})
4791 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04004792 if($Info=~/chan[ ]*:[ ]*@(\d+) /) {
4793 return $1;
4794 }
4795 }
4796 return "";
4797}
4798
4799sub getTreeAttr_Chain($)
4800{
4801 if($_[0] and my $Info = $LibInfo{$Version}{"info"}{$_[0]})
4802 {
4803 if($Info=~/chain[ ]*:[ ]*@(\d+) /) {
4804 return $1;
4805 }
4806 }
4807 return "";
4808}
4809
4810sub getTreeAttr_Scpe($)
4811{
4812 if($_[0] and my $Info = $LibInfo{$Version}{"info"}{$_[0]})
4813 {
4814 if($Info=~/scpe[ ]*:[ ]*@(\d+) /) {
4815 return $1;
4816 }
4817 }
4818 return "";
4819}
4820
4821sub getTreeAttr_Type($)
4822{
4823 if($_[0] and my $Info = $LibInfo{$Version}{"info"}{$_[0]})
4824 {
4825 if($Info=~/type[ ]*:[ ]*@(\d+) /) {
4826 return $1;
4827 }
4828 }
4829 return "";
4830}
4831
4832sub getTreeAttr_Name($)
4833{
4834 if($_[0] and my $Info = $LibInfo{$Version}{"info"}{$_[0]})
4835 {
4836 if($Info=~/name[ ]*:[ ]*@(\d+) /) {
4837 return $1;
4838 }
4839 }
4840 return "";
4841}
4842
4843sub getTreeAttr_Mngl($)
4844{
4845 if($_[0] and my $Info = $LibInfo{$Version}{"info"}{$_[0]})
4846 {
4847 if($Info=~/mngl[ ]*:[ ]*@(\d+) /) {
4848 return $1;
4849 }
4850 }
4851 return "";
4852}
4853
4854sub getTreeAttr_Prms($)
4855{
4856 if($_[0] and my $Info = $LibInfo{$Version}{"info"}{$_[0]})
4857 {
4858 if($Info=~/prms[ ]*:[ ]*@(\d+) /) {
4859 return $1;
4860 }
4861 }
4862 return "";
4863}
4864
4865sub getTreeAttr_Fncs($)
4866{
4867 if($_[0] and my $Info = $LibInfo{$Version}{"info"}{$_[0]})
4868 {
4869 if($Info=~/fncs[ ]*:[ ]*@(\d+) /) {
4870 return $1;
4871 }
4872 }
4873 return "";
4874}
4875
4876sub getTreeAttr_Csts($)
4877{
4878 if($_[0] and my $Info = $LibInfo{$Version}{"info"}{$_[0]})
4879 {
4880 if($Info=~/csts[ ]*:[ ]*@(\d+) /) {
4881 return $1;
4882 }
4883 }
4884 return "";
4885}
4886
4887sub getTreeAttr_Purp($)
4888{
4889 if($_[0] and my $Info = $LibInfo{$Version}{"info"}{$_[0]})
4890 {
4891 if($Info=~/purp[ ]*:[ ]*@(\d+) /) {
4892 return $1;
4893 }
4894 }
4895 return "";
4896}
4897
4898sub getTreeAttr_Valu($)
4899{
4900 if($_[0] and my $Info = $LibInfo{$Version}{"info"}{$_[0]})
4901 {
4902 if($Info=~/valu[ ]*:[ ]*@(\d+) /) {
4903 return $1;
4904 }
4905 }
4906 return "";
4907}
4908
4909sub getTreeAttr_Flds($)
4910{
4911 if($_[0] and my $Info = $LibInfo{$Version}{"info"}{$_[0]})
4912 {
4913 if($Info=~/flds[ ]*:[ ]*@(\d+) /) {
4914 return $1;
4915 }
4916 }
4917 return "";
4918}
4919
4920sub getTreeAttr_Args($)
4921{
4922 if($_[0] and my $Info = $LibInfo{$Version}{"info"}{$_[0]})
4923 {
4924 if($Info=~/args[ ]*:[ ]*@(\d+) /) {
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04004925 return $1;
4926 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004927 }
4928 return "";
4929}
4930
4931sub getTreeValue($)
4932{
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04004933 if($_[0] and my $Info = $LibInfo{$Version}{"info"}{$_[0]})
4934 {
4935 if($Info=~/low[ ]*:[ ]*([^ ]+) /) {
4936 return $1;
4937 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004938 }
4939 return "";
4940}
4941
4942sub getTreeAccess($)
4943{
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04004944 if($_[0] and my $Info = $LibInfo{$Version}{"info"}{$_[0]})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004945 {
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04004946 if($Info=~/accs[ ]*:[ ]*([a-zA-Z]+) /)
4947 {
4948 my $Access = $1;
4949 if($Access eq "prot") {
4950 return "protected";
4951 }
4952 elsif($Access eq "priv") {
4953 return "private";
4954 }
4955 }
4956 elsif($Info=~/ protected /)
4957 { # support for old GCC versions
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004958 return "protected";
4959 }
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04004960 elsif($Info=~/ private /)
4961 { # support for old GCC versions
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004962 return "private";
4963 }
4964 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004965 return "public";
4966}
4967
4968sub setFuncAccess($)
4969{
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04004970 my $Access = getTreeAccess($_[0]);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004971 if($Access eq "protected") {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04004972 $SymbolInfo{$Version}{$_[0]}{"Protected"} = 1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004973 }
4974 elsif($Access eq "private") {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04004975 $SymbolInfo{$Version}{$_[0]}{"Private"} = 1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004976 }
4977}
4978
4979sub setTypeAccess($$)
4980{
4981 my ($TypeId, $TypeAttr) = @_;
4982 my $Access = getTreeAccess($TypeId);
4983 if($Access eq "protected") {
4984 $TypeAttr->{"Protected"} = 1;
4985 }
4986 elsif($Access eq "private") {
4987 $TypeAttr->{"Private"} = 1;
4988 }
4989}
4990
4991sub setFuncKind($)
4992{
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04004993 if($_[0] and my $Info = $LibInfo{$Version}{"info"}{$_[0]})
4994 {
4995 if($Info=~/pseudo tmpl/) {
4996 $SymbolInfo{$Version}{$_[0]}{"PseudoTemplate"} = 1;
4997 }
4998 elsif($Info=~/ constructor /) {
4999 $SymbolInfo{$Version}{$_[0]}{"Constructor"} = 1;
5000 }
5001 elsif($Info=~/ destructor /) {
5002 $SymbolInfo{$Version}{$_[0]}{"Destructor"} = 1;
5003 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005004 }
5005}
5006
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04005007sub getVirtSpec($)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005008{
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04005009 if($_[0] and my $Info = $LibInfo{$Version}{"info"}{$_[0]})
5010 {
5011 if($Info=~/spec[ ]*:[ ]*pure /) {
5012 return "PureVirt";
5013 }
5014 elsif($Info=~/spec[ ]*:[ ]*virt /) {
5015 return "Virt";
5016 }
5017 elsif($Info=~/ pure\s+virtual /)
5018 { # support for old GCC versions
5019 return "PureVirt";
5020 }
5021 elsif($Info=~/ virtual /)
5022 { # support for old GCC versions
5023 return "Virt";
5024 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005025 }
5026 return "";
5027}
5028
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005029sub getFuncLink($)
5030{
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04005031 if($_[0] and my $Info = $LibInfo{$Version}{"info"}{$_[0]})
5032 {
5033 if($Info=~/link[ ]*:[ ]*static /) {
5034 return "Static";
5035 }
5036 elsif($Info=~/link[ ]*:[ ]*([a-zA-Z]+) /) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005037 return $1;
5038 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005039 }
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04005040 return "";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005041}
5042
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005043sub get_IntNameSpace($$)
5044{
5045 my ($Interface, $LibVersion) = @_;
5046 return "" if(not $Interface or not $LibVersion);
5047 if(defined $Cache{"get_IntNameSpace"}{$Interface}{$LibVersion}) {
5048 return $Cache{"get_IntNameSpace"}{$Interface}{$LibVersion};
5049 }
5050 my $Signature = get_Signature($Interface, $LibVersion);
5051 if($Signature=~/\:\:/)
5052 {
5053 my $FounNameSpace = 0;
5054 foreach my $NameSpace (sort {get_depth($b)<=>get_depth($a)} keys(%{$NestedNameSpaces{$LibVersion}}))
5055 {
5056 if($Signature=~/(\A|\s+for\s+)\Q$NameSpace\E\:\:/) {
5057 return ($Cache{"get_IntNameSpace"}{$Interface}{$LibVersion} = $NameSpace);
5058 }
5059 }
5060 }
5061 else {
5062 return ($Cache{"get_IntNameSpace"}{$Interface}{$LibVersion} = "");
5063 }
5064}
5065
5066sub parse_TypeNameSpace($$)
5067{
5068 my ($TypeName, $LibVersion) = @_;
5069 return "" if(not $TypeName or not $LibVersion);
5070 if(defined $Cache{"parse_TypeNameSpace"}{$TypeName}{$LibVersion}) {
5071 return $Cache{"parse_TypeNameSpace"}{$TypeName}{$LibVersion};
5072 }
5073 if($TypeName=~/\:\:/)
5074 {
5075 my $FounNameSpace = 0;
5076 foreach my $NameSpace (sort {get_depth($b)<=>get_depth($a)} keys(%{$NestedNameSpaces{$LibVersion}}))
5077 {
5078 if($TypeName=~/\A\Q$NameSpace\E\:\:/) {
5079 return ($Cache{"parse_TypeNameSpace"}{$TypeName}{$LibVersion} = $NameSpace);
5080 }
5081 }
5082 }
5083 else {
5084 return ($Cache{"parse_TypeNameSpace"}{$TypeName}{$LibVersion} = "");
5085 }
5086}
5087
5088sub getNameSpace($)
5089{
5090 my $TypeInfoId = $_[0];
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04005091 if(my $NSInfoId = getTreeAttr_Scpe($TypeInfoId))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005092 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04005093 if(my $InfoType = $LibInfo{$Version}{"info_type"}{$NSInfoId})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005094 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04005095 if($InfoType eq "namespace_decl")
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04005096 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04005097 if($LibInfo{$Version}{"info"}{$NSInfoId}=~/name[ ]*:[ ]*@(\d+) /)
5098 {
5099 my $NameSpace = getTreeStr($1);
5100 if($NameSpace eq "::")
5101 { # global namespace
5102 return "";
5103 }
5104 if(my $BaseNameSpace = getNameSpace($NSInfoId)) {
5105 $NameSpace = $BaseNameSpace."::".$NameSpace;
5106 }
5107 $NestedNameSpaces{$Version}{$NameSpace} = 1;
5108 return $NameSpace;
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04005109 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04005110 else {
5111 return "";
5112 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005113 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04005114 elsif($InfoType eq "record_type")
5115 { # inside data type
5116 my ($Name, $NameNS) = getTrivialName(getTypeDeclId($NSInfoId), $NSInfoId);
5117 return $Name;
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04005118 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005119 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005120 }
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04005121 return "";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005122}
5123
5124sub getNameSpaceId($)
5125{
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04005126 if($_[0] and my $Info = $LibInfo{$Version}{"info"}{$_[0]})
5127 {
5128 if($Info=~/scpe[ ]*:[ ]*\@(\d+)/) {
5129 return $1;
5130 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005131 }
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04005132 return "";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005133}
5134
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005135sub getStructMembName($)
5136{
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04005137 if($_[0] and my $Info = $LibInfo{$Version}{"info"}{$_[0]})
5138 {
5139 if($Info=~/name[ ]*:[ ]*\@(\d+)/) {
5140 return getTreeStr($1);
5141 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005142 }
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04005143 return "";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005144}
5145
5146sub getEnumMembVal($)
5147{
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04005148 if($_[0] and my $Info = $LibInfo{$Version}{"info"}{$_[0]})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005149 {
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04005150 if($Info=~/valu[ ]*:[ ]*\@(\d+)/)
5151 {
5152 if(my $VInfo = $LibInfo{$Version}{"info"}{$1})
5153 {
5154 if($VInfo=~/cnst[ ]*:[ ]*\@(\d+)/)
5155 { # in newer versions of GCC the value is in the "const_decl->cnst" node
5156 return getTreeValue($1);
5157 }
5158 else
5159 { # some old versions of GCC (3.3) have the value in the "integer_cst" node
5160 return getTreeValue($1);
5161 }
5162 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005163 }
5164 }
5165 return "";
5166}
5167
5168sub getSize($)
5169{
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04005170 if($_[0] and my $Info = $LibInfo{$Version}{"info"}{$_[0]})
5171 {
5172 if($Info=~/size[ ]*:[ ]*\@(\d+)/) {
5173 return getTreeValue($1);
5174 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005175 }
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04005176 return 0;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005177}
5178
5179sub getAlgn($)
5180{
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04005181 if($_[0] and my $Info = $LibInfo{$Version}{"info"}{$_[0]})
5182 {
5183 if($Info=~/algn[ ]*:[ ]*(\d+) /) {
5184 return $1;
5185 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005186 }
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04005187 return "";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005188}
5189
5190sub getStructMembBitFieldSize($)
5191{
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04005192 if($_[0] and my $Info = $LibInfo{$Version}{"info"}{$_[0]})
5193 {
5194 if($Info=~/ bitfield /) {
5195 return getSize($_[0]);
5196 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005197 }
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04005198 return 0;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005199}
5200
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04005201sub getNextElem($)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005202{
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04005203 if(my $Chan = getTreeAttr_Chan($_[0])) {
5204 return $Chan;
5205 }
5206 elsif(my $Chain = getTreeAttr_Chain($_[0])) {
5207 return $Chain;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005208 }
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04005209 return "";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005210}
5211
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04005212sub registerHeader($$)
5213{ # input: absolute path of header, relative path or name
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005214 my ($Header, $LibVersion) = @_;
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04005215 if(not $Header) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005216 return "";
5217 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04005218 if(is_abs($Header) and not -f $Header)
5219 { # incorrect absolute path
5220 exitStatus("Access_Error", "can't access \'$Header\'");
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005221 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04005222 if(skipHeader($Header, $LibVersion))
5223 { # skip
5224 return "";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005225 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04005226 if(my $Header_Path = identifyHeader($Header, $LibVersion))
5227 {
5228 detect_header_includes($Header_Path, $LibVersion);
5229
5230 if(my $RHeader_Path = $Header_ErrorRedirect{$LibVersion}{$Header_Path})
5231 { # redirect
5232 if($Registered_Headers{$LibVersion}{$RHeader_Path}{"Identity"}
5233 or skipHeader($RHeader_Path, $LibVersion))
5234 { # skip
5235 return "";
5236 }
5237 $Header_Path = $RHeader_Path;
5238 }
5239 elsif($Header_ShouldNotBeUsed{$LibVersion}{$Header_Path})
5240 { # skip
5241 return "";
5242 }
5243
5244 if(my $HName = get_filename($Header_Path))
5245 { # register
5246 $Registered_Headers{$LibVersion}{$Header_Path}{"Identity"} = $HName;
5247 $HeaderName_Paths{$LibVersion}{$HName}{$Header_Path} = 1;
5248 }
5249
5250 if(($Header=~/\.(\w+)\Z/ and $1 ne "h")
5251 or $Header!~/\.(\w+)\Z/)
5252 { # hpp, hh
5253 setLanguage($LibVersion, "C++");
5254 }
5255
5256 if($CheckHeadersOnly
5257 and $Header=~/(\A|\/)c\+\+(\/|\Z)/)
5258 { # /usr/include/c++/4.6.1/...
5259 $STDCXX_TESTING = 1;
5260 }
5261
5262 return $Header_Path;
5263 }
5264 return "";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005265}
5266
5267sub register_directory($$$)
5268{
5269 my ($Dir, $WithDeps, $LibVersion) = @_;
5270 $Dir=~s/[\/\\]+\Z//g;
5271 return if(not $LibVersion or not $Dir or not -d $Dir);
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04005272 return if(skipHeader($Dir, $LibVersion));
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005273 $Dir = get_abs_path($Dir);
5274 my $Mode = "All";
Andrey Ponomarenko85043792012-05-14 16:48:07 +04005275 if($WithDeps)
5276 {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005277 if($RegisteredDirs{$LibVersion}{$Dir}{1}) {
5278 return;
5279 }
5280 elsif($RegisteredDirs{$LibVersion}{$Dir}{0}) {
5281 $Mode = "DepsOnly";
5282 }
5283 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +04005284 else
5285 {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005286 if($RegisteredDirs{$LibVersion}{$Dir}{1}
5287 or $RegisteredDirs{$LibVersion}{$Dir}{0}) {
5288 return;
5289 }
5290 }
5291 $Header_Dependency{$LibVersion}{$Dir} = 1;
5292 $RegisteredDirs{$LibVersion}{$Dir}{$WithDeps} = 1;
5293 if($Mode eq "DepsOnly")
5294 {
5295 foreach my $Path (cmd_find($Dir,"d","","")) {
5296 $Header_Dependency{$LibVersion}{$Path} = 1;
5297 }
5298 return;
5299 }
5300 foreach my $Path (sort {length($b)<=>length($a)} cmd_find($Dir,"f","",""))
5301 {
5302 if($WithDeps)
5303 {
5304 my $SubDir = $Path;
5305 while(($SubDir = get_dirname($SubDir)) ne $Dir)
5306 { # register all sub directories
5307 $Header_Dependency{$LibVersion}{$SubDir} = 1;
5308 }
5309 }
5310 next if(is_not_header($Path));
5311 next if(ignore_path($Path));
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04005312 next if(skipHeader($Path, $LibVersion));
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005313 # Neighbors
5314 foreach my $Part (get_path_prefixes($Path)) {
5315 $Include_Neighbors{$LibVersion}{$Part} = $Path;
5316 }
5317 }
5318 if(get_filename($Dir) eq "include")
5319 { # search for "lib/include/" directory
5320 my $LibDir = $Dir;
5321 if($LibDir=~s/([\/\\])include\Z/$1lib/g and -d $LibDir) {
5322 register_directory($LibDir, $WithDeps, $LibVersion);
5323 }
5324 }
5325}
5326
5327sub parse_redirect($$$)
5328{
5329 my ($Content, $Path, $LibVersion) = @_;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005330 my @Errors = ();
5331 while($Content=~s/#\s*error\s+([^\n]+?)\s*(\n|\Z)//) {
5332 push(@Errors, $1);
5333 }
5334 my $Redirect = "";
5335 foreach (@Errors)
5336 {
5337 s/\s{2,}/ /g;
5338 if(/(only|must\ include
5339 |update\ to\ include
5340 |replaced\ with
5341 |replaced\ by|renamed\ to
5342 |is\ in|use)\ (<[^<>]+>|[\w\-\/\\]+\.($HEADER_EXT))/ix)
5343 {
5344 $Redirect = $2;
5345 last;
5346 }
5347 elsif(/(include|use|is\ in)\ (<[^<>]+>|[\w\-\/\\]+\.($HEADER_EXT))\ instead/i)
5348 {
5349 $Redirect = $2;
5350 last;
5351 }
5352 elsif(/this\ header\ should\ not\ be\ used
5353 |programs\ should\ not\ directly\ include
5354 |you\ should\ not\ (include|be\ (including|using)\ this\ (file|header))
5355 |is\ not\ supported\ API\ for\ general\ use
5356 |do\ not\ use
5357 |should\ not\ be\ used
5358 |cannot\ be\ included\ directly/ix and not /\ from\ /i) {
5359 $Header_ShouldNotBeUsed{$LibVersion}{$Path} = 1;
5360 }
5361 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +04005362 if($Redirect)
5363 {
5364 $Redirect=~s/\A<//g;
5365 $Redirect=~s/>\Z//g;
5366 }
5367 return $Redirect;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005368}
5369
5370sub parse_includes($$)
5371{
5372 my ($Content, $Path) = @_;
5373 my %Includes = ();
5374 while($Content=~s/#([ \t]*)(include|include_next|import)([ \t]*)(<|")([^<>"]+)(>|")//)
Andrey Ponomarenko85043792012-05-14 16:48:07 +04005375 { # C/C++: include, Objective C/C++: import directive
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005376 my ($Header, $Method) = ($5, $4);
5377 $Header = path_format($Header, $OSgroup);
Andrey Ponomarenko85043792012-05-14 16:48:07 +04005378 if($Method eq "\"" or is_abs($Header))
5379 {
5380 if(-e joinPath(get_dirname($Path), $Header))
5381 { # relative path exists
5382 $Includes{$Header} = -1;
5383 }
5384 else
5385 { # include "..." that doesn't exist is equal to include <...>
5386 $Includes{$Header} = 2;
5387 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005388 }
5389 else {
5390 $Includes{$Header} = 1;
5391 }
5392 }
5393 return \%Includes;
5394}
5395
5396sub ignore_path($)
5397{
5398 my $Path = $_[0];
5399 if($Path=~/\~\Z/)
5400 {# skipping system backup files
5401 return 1;
5402 }
5403 if($Path=~/(\A|[\/\\]+)(\.(svn|git|bzr|hg)|CVS)([\/\\]+|\Z)/)
5404 {# skipping hidden .svn, .git, .bzr, .hg and CVS directories
5405 return 1;
5406 }
5407 return 0;
5408}
5409
5410sub sort_by_word($$)
5411{
5412 my ($ArrRef, $W) = @_;
5413 return if(length($W)<2);
5414 @{$ArrRef} = sort {get_filename($b)=~/\Q$W\E/i<=>get_filename($a)=~/\Q$W\E/i} @{$ArrRef};
5415}
5416
5417sub natural_sorting($$)
5418{
5419 my ($H1, $H2) = @_;
5420 $H1=~s/\.[a-z]+\Z//ig;
5421 $H2=~s/\.[a-z]+\Z//ig;
5422 my ($HDir1, $Hname1) = separate_path($H1);
5423 my ($HDir2, $Hname2) = separate_path($H2);
5424 my $Dirname1 = get_filename($HDir1);
5425 my $Dirname2 = get_filename($HDir2);
5426 if($H1 eq $H2) {
5427 return 0;
5428 }
5429 elsif($H1=~/\A\Q$H2\E/) {
5430 return 1;
5431 }
5432 elsif($H2=~/\A\Q$H1\E/) {
5433 return -1;
5434 }
5435 elsif($HDir1=~/\Q$Hname1\E/i
5436 and $HDir2!~/\Q$Hname2\E/i)
5437 {# include/glib-2.0/glib.h
5438 return -1;
5439 }
5440 elsif($HDir2=~/\Q$Hname2\E/i
5441 and $HDir1!~/\Q$Hname1\E/i)
5442 {# include/glib-2.0/glib.h
5443 return 1;
5444 }
5445 elsif($Hname1=~/\Q$Dirname1\E/i
5446 and $Hname2!~/\Q$Dirname2\E/i)
5447 {# include/hildon-thumbnail/hildon-thumbnail-factory.h
5448 return -1;
5449 }
5450 elsif($Hname2=~/\Q$Dirname2\E/i
5451 and $Hname1!~/\Q$Dirname1\E/i)
5452 {# include/hildon-thumbnail/hildon-thumbnail-factory.h
5453 return 1;
5454 }
5455 elsif($Hname1=~/(config|lib)/i
5456 and $Hname2!~/(config|lib)/i)
5457 {# include/alsa/asoundlib.h
5458 return -1;
5459 }
5460 elsif($Hname2=~/(config|lib)/i
5461 and $Hname1!~/(config|lib)/i)
5462 {# include/alsa/asoundlib.h
5463 return 1;
5464 }
5465 elsif(checkRelevance($H1)
5466 and not checkRelevance($H2))
5467 {# libebook/e-book.h
5468 return -1;
5469 }
5470 elsif(checkRelevance($H2)
5471 and not checkRelevance($H1))
5472 {# libebook/e-book.h
5473 return 1;
5474 }
5475 else {
5476 return (lc($H1) cmp lc($H2));
5477 }
5478}
5479
5480sub searchForHeaders($)
5481{
5482 my $LibVersion = $_[0];
5483 # gcc standard include paths
5484 find_gcc_cxx_headers($LibVersion);
5485 # processing header paths
5486 foreach my $Path (keys(%{$Descriptor{$LibVersion}{"IncludePaths"}}),
5487 keys(%{$Descriptor{$LibVersion}{"AddIncludePaths"}}))
5488 {
5489 my $IPath = $Path;
Andrey Ponomarenkoa01311b2012-06-08 17:20:02 +04005490 if($SystemRoot)
5491 {
5492 if(is_abs($Path)) {
5493 $Path = $SystemRoot.$Path;
5494 }
5495 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005496 if(not -e $Path) {
5497 exitStatus("Access_Error", "can't access \'$Path\'");
5498 }
5499 elsif(-f $Path) {
5500 exitStatus("Access_Error", "\'$Path\' - not a directory");
5501 }
5502 elsif(-d $Path)
5503 {
5504 $Path = get_abs_path($Path);
5505 register_directory($Path, 0, $LibVersion);
5506 if($Descriptor{$LibVersion}{"AddIncludePaths"}{$IPath}) {
5507 $Add_Include_Paths{$LibVersion}{$Path} = 1;
5508 }
5509 else {
5510 $Include_Paths{$LibVersion}{$Path} = 1;
5511 }
5512 }
5513 }
5514 if(keys(%{$Include_Paths{$LibVersion}})) {
5515 $INC_PATH_AUTODETECT{$LibVersion} = 0;
5516 }
5517 # registering directories
5518 foreach my $Path (split(/\s*\n\s*/, $Descriptor{$LibVersion}{"Headers"}))
5519 {
5520 next if(not -e $Path);
5521 $Path = get_abs_path($Path);
5522 $Path = path_format($Path, $OSgroup);
5523 if(-d $Path) {
5524 register_directory($Path, 1, $LibVersion);
5525 }
5526 elsif(-f $Path)
5527 {
5528 my $Dir = get_dirname($Path);
5529 if(not $SystemPaths{"include"}{$Dir}
5530 and not $LocalIncludes{$Dir})
5531 {
5532 register_directory($Dir, 1, $LibVersion);
5533 if(my $OutDir = get_dirname($Dir))
5534 { # registering the outer directory
5535 if(not $SystemPaths{"include"}{$OutDir}
5536 and not $LocalIncludes{$OutDir}) {
5537 register_directory($OutDir, 0, $LibVersion);
5538 }
5539 }
5540 }
5541 }
5542 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +04005543
5544 # clean memory
5545 %RegisteredDirs = ();
5546
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005547 # registering headers
5548 my $Position = 0;
5549 foreach my $Dest (split(/\s*\n\s*/, $Descriptor{$LibVersion}{"Headers"}))
5550 {
5551 if(is_abs($Dest) and not -e $Dest) {
5552 exitStatus("Access_Error", "can't access \'$Dest\'");
5553 }
5554 $Dest = path_format($Dest, $OSgroup);
5555 if(is_header($Dest, 1, $LibVersion))
5556 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04005557 if(my $HPath = registerHeader($Dest, $LibVersion)) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005558 $Registered_Headers{$LibVersion}{$HPath}{"Pos"} = $Position++;
5559 }
5560 }
5561 elsif(-d $Dest)
5562 {
5563 my @Registered = ();
5564 foreach my $Path (cmd_find($Dest,"f","",""))
5565 {
5566 next if(ignore_path($Path));
5567 next if(not is_header($Path, 0, $LibVersion));
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04005568 if(my $HPath = registerHeader($Path, $LibVersion)) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005569 push(@Registered, $HPath);
5570 }
5571 }
5572 @Registered = sort {natural_sorting($a, $b)} @Registered;
5573 sort_by_word(\@Registered, $TargetLibraryShortName);
5574 foreach my $Path (@Registered) {
5575 $Registered_Headers{$LibVersion}{$Path}{"Pos"} = $Position++;
5576 }
5577 }
5578 else {
5579 exitStatus("Access_Error", "can't identify \'$Dest\' as a header file");
5580 }
5581 }
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04005582 if(my $HList = $Descriptor{$LibVersion}{"IncludePreamble"})
5583 { # preparing preamble headers
5584 my $PPos=0;
5585 foreach my $Header (split(/\s*\n\s*/, $HList))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005586 {
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04005587 if(is_abs($Header) and not -f $Header) {
5588 exitStatus("Access_Error", "can't access file \'$Header\'");
5589 }
5590 $Header = path_format($Header, $OSgroup);
5591 if(my $Header_Path = is_header($Header, 1, $LibVersion))
5592 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04005593 next if(skipHeader($Header_Path, $LibVersion));
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04005594 $Include_Preamble{$LibVersion}{$Header_Path}{"Position"} = $PPos++;
5595 }
5596 else {
5597 exitStatus("Access_Error", "can't identify \'$Header\' as a header file");
5598 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005599 }
5600 }
5601 foreach my $Header_Name (keys(%{$HeaderName_Paths{$LibVersion}}))
5602 { # set relative paths (for duplicates)
5603 if(keys(%{$HeaderName_Paths{$LibVersion}{$Header_Name}})>=2)
5604 { # search for duplicates
5605 my $FirstPath = (keys(%{$HeaderName_Paths{$LibVersion}{$Header_Name}}))[0];
5606 my $Prefix = get_dirname($FirstPath);
5607 while($Prefix=~/\A(.+)[\/\\]+[^\/\\]+\Z/)
5608 { # detect a shortest distinguishing prefix
5609 my $NewPrefix = $1;
5610 my %Identity = ();
5611 foreach my $Path (keys(%{$HeaderName_Paths{$LibVersion}{$Header_Name}}))
5612 {
5613 if($Path=~/\A\Q$Prefix\E[\/\\]+(.*)\Z/) {
5614 $Identity{$Path} = $1;
5615 }
5616 }
5617 if(keys(%Identity)==keys(%{$HeaderName_Paths{$LibVersion}{$Header_Name}}))
5618 { # all names are differend with current prefix
5619 foreach my $Path (keys(%{$HeaderName_Paths{$LibVersion}{$Header_Name}})) {
5620 $Registered_Headers{$LibVersion}{$Path}{"Identity"} = $Identity{$Path};
5621 }
5622 last;
5623 }
5624 $Prefix = $NewPrefix; # increase prefix
5625 }
5626 }
5627 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +04005628
5629 # clean memory
5630 %HeaderName_Paths = ();
5631
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005632 foreach my $HeaderName (keys(%{$Include_Order{$LibVersion}}))
5633 { # ordering headers according to descriptor
5634 my $PairName=$Include_Order{$LibVersion}{$HeaderName};
5635 my ($Pos, $PairPos) = (-1, -1);
5636 my ($Path, $PairPath) = ();
5637 my @Paths = keys(%{$Registered_Headers{$LibVersion}});
5638 @Paths = sort {int($Registered_Headers{$LibVersion}{$a}{"Pos"})<=>int($Registered_Headers{$LibVersion}{$b}{"Pos"})} @Paths;
5639 foreach my $Header_Path (@Paths)
5640 {
5641 if(get_filename($Header_Path) eq $PairName)
5642 {
5643 $PairPos = $Registered_Headers{$LibVersion}{$Header_Path}{"Pos"};
5644 $PairPath = $Header_Path;
5645 }
5646 if(get_filename($Header_Path) eq $HeaderName)
5647 {
5648 $Pos = $Registered_Headers{$LibVersion}{$Header_Path}{"Pos"};
5649 $Path = $Header_Path;
5650 }
5651 }
5652 if($PairPos!=-1 and $Pos!=-1
5653 and int($PairPos)<int($Pos))
5654 {
5655 my %Tmp = %{$Registered_Headers{$LibVersion}{$Path}};
5656 %{$Registered_Headers{$LibVersion}{$Path}} = %{$Registered_Headers{$LibVersion}{$PairPath}};
5657 %{$Registered_Headers{$LibVersion}{$PairPath}} = %Tmp;
5658 }
5659 }
5660 if(not keys(%{$Registered_Headers{$LibVersion}})) {
5661 exitStatus("Error", "header files are not found in the ".$Descriptor{$LibVersion}{"Version"});
5662 }
5663}
5664
5665sub detect_real_includes($$)
5666{
5667 my ($AbsPath, $LibVersion) = @_;
5668 return () if(not $LibVersion or not $AbsPath or not -e $AbsPath);
5669 if($Cache{"detect_real_includes"}{$LibVersion}{$AbsPath}
5670 or keys(%{$RecursiveIncludes{$LibVersion}{$AbsPath}})) {
5671 return keys(%{$RecursiveIncludes{$LibVersion}{$AbsPath}});
5672 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +04005673 $Cache{"detect_real_includes"}{$LibVersion}{$AbsPath}=1;
5674
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005675 my $Path = callPreprocessor($AbsPath, "", $LibVersion);
5676 return () if(not $Path);
5677 open(PREPROC, $Path);
5678 while(<PREPROC>)
5679 {
5680 if(/#\s+\d+\s+"([^"]+)"[\s\d]*\n/)
5681 {
5682 my $Include = path_format($1, $OSgroup);
5683 if($Include=~/\<(built\-in|internal|command(\-|\s)line)\>|\A\./) {
5684 next;
5685 }
5686 if($Include eq $AbsPath) {
5687 next;
5688 }
5689 $RecursiveIncludes{$LibVersion}{$AbsPath}{$Include} = 1;
5690 }
5691 }
5692 close(PREPROC);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005693 return keys(%{$RecursiveIncludes{$LibVersion}{$AbsPath}});
5694}
5695
5696sub detect_header_includes($$)
5697{
5698 my ($Path, $LibVersion) = @_;
Andrey Ponomarenko85043792012-05-14 16:48:07 +04005699 return if(not $LibVersion or not $Path);
5700 if(defined $Cache{"detect_header_includes"}{$LibVersion}{$Path}) {
5701 return;
5702 }
5703 $Cache{"detect_header_includes"}{$LibVersion}{$Path}=1;
5704
5705 if(not -e $Path) {
5706 return;
5707 }
5708
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005709 my $Content = readFile($Path);
Andrey Ponomarenko85043792012-05-14 16:48:07 +04005710 if(my $Redirect = parse_redirect($Content, $Path, $LibVersion))
5711 { # detect error directive in headers
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04005712 if(my $RedirectPath = identifyHeader($Redirect, $LibVersion))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005713 {
5714 if($RedirectPath=~/\/usr\/include\// and $Path!~/\/usr\/include\//) {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04005715 $RedirectPath = identifyHeader(get_filename($Redirect), $LibVersion);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005716 }
5717 if($RedirectPath ne $Path) {
5718 $Header_ErrorRedirect{$LibVersion}{$Path} = $RedirectPath;
5719 }
5720 }
5721 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +04005722 if(my $Inc = parse_includes($Content, $Path))
5723 {
5724 foreach my $Include (keys(%{$Inc}))
5725 { # detect includes
Andrey Ponomarenko85043792012-05-14 16:48:07 +04005726 $Header_Includes{$LibVersion}{$Path}{$Include} = $Inc->{$Include};
5727 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005728 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005729}
5730
5731sub simplify_path($)
5732{
5733 my $Path = $_[0];
5734 while($Path=~s&([\/\\])[^\/\\]+[\/\\]\.\.[\/\\]&$1&){};
5735 return $Path;
5736}
5737
5738sub fromLibc($)
5739{ # GLIBC header
5740 my $Path = $_[0];
5741 my ($Dir, $Name) = separate_path($Path);
5742 if(get_filename($Dir)=~/\A(include|libc)\Z/ and $GlibcHeader{$Name})
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04005743 { # /usr/include/{stdio, ...}.h
5744 # epoc32/include/libc/{stdio, ...}.h
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005745 return 1;
5746 }
5747 if(isLibcDir($Dir)) {
5748 return 1;
5749 }
5750 return 0;
5751}
5752
5753sub isLibcDir($)
5754{ # GLIBC directory
5755 my $Dir = $_[0];
5756 my ($OutDir, $Name) = separate_path($Dir);
5757 if(get_filename($OutDir)=~/\A(include|libc)\Z/
5758 and ($Name=~/\Aasm(|-.+)\Z/ or $GlibcDir{$Name}))
5759 { # /usr/include/{sys,bits,asm,asm-*}/*.h
5760 return 1;
5761 }
5762 return 0;
5763}
5764
5765sub detect_recursive_includes($$)
5766{
5767 my ($AbsPath, $LibVersion) = @_;
5768 return () if(not $AbsPath);
5769 if(isCyclical(\@RecurInclude, $AbsPath)) {
5770 return keys(%{$RecursiveIncludes{$LibVersion}{$AbsPath}});
5771 }
5772 my ($AbsDir, $Name) = separate_path($AbsPath);
5773 if(isLibcDir($AbsDir))
5774 { # GLIBC internals
5775 return ();
5776 }
5777 if(keys(%{$RecursiveIncludes{$LibVersion}{$AbsPath}})) {
5778 return keys(%{$RecursiveIncludes{$LibVersion}{$AbsPath}});
5779 }
5780 return () if($OSgroup ne "windows" and $Name=~/windows|win32|win64/i);
5781 return () if($MAIN_CPP_DIR and $AbsPath=~/\A\Q$MAIN_CPP_DIR\E/ and not $STDCXX_TESTING);
5782 push(@RecurInclude, $AbsPath);
5783 if($DefaultGccPaths{$AbsDir}
5784 or fromLibc($AbsPath))
5785 { # check "real" (non-"model") include paths
5786 my @Paths = detect_real_includes($AbsPath, $LibVersion);
5787 pop(@RecurInclude);
5788 return @Paths;
5789 }
5790 if(not keys(%{$Header_Includes{$LibVersion}{$AbsPath}})) {
5791 detect_header_includes($AbsPath, $LibVersion);
5792 }
5793 foreach my $Include (keys(%{$Header_Includes{$LibVersion}{$AbsPath}}))
5794 {
Andrey Ponomarenko85043792012-05-14 16:48:07 +04005795 my $IncType = $Header_Includes{$LibVersion}{$AbsPath}{$Include};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005796 my $HPath = "";
Andrey Ponomarenko85043792012-05-14 16:48:07 +04005797 if($IncType<0)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005798 { # for #include "..."
5799 my $Candidate = joinPath($AbsDir, $Include);
5800 if(-f $Candidate) {
5801 $HPath = simplify_path($Candidate);
5802 }
5803 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +04005804 elsif($IncType>0
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04005805 and $Include=~/[\/\\]/) # and not find_in_defaults($Include)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005806 { # search for the nearest header
5807 # QtCore/qabstractanimation.h includes <QtCore/qobject.h>
5808 my $Candidate = joinPath(get_dirname($AbsDir), $Include);
5809 if(-f $Candidate) {
5810 $HPath = $Candidate;
5811 }
5812 }
5813 if(not $HPath) {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04005814 $HPath = identifyHeader($Include, $LibVersion);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005815 }
5816 next if(not $HPath);
5817 if($HPath eq $AbsPath) {
5818 next;
5819 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +04005820 $RecursiveIncludes{$LibVersion}{$AbsPath}{$HPath} = $IncType;
5821 if($IncType>0)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005822 { # only include <...>, skip include "..." prefixes
5823 $Header_Include_Prefix{$LibVersion}{$AbsPath}{$HPath}{get_dirname($Include)} = 1;
5824 }
5825 foreach my $IncPath (detect_recursive_includes($HPath, $LibVersion))
5826 {
5827 if($IncPath eq $AbsPath) {
5828 next;
5829 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +04005830 my $RIncType = $RecursiveIncludes{$LibVersion}{$HPath}{$IncPath};
5831 if($RIncType==-1)
5832 { # include "..."
5833 $RIncType = $IncType;
5834 }
5835 elsif($RIncType==2)
5836 {
5837 if($IncType!=-1) {
5838 $RIncType = $IncType;
5839 }
5840 }
5841 $RecursiveIncludes{$LibVersion}{$AbsPath}{$IncPath} = $RIncType;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005842 foreach my $Prefix (keys(%{$Header_Include_Prefix{$LibVersion}{$HPath}{$IncPath}})) {
5843 $Header_Include_Prefix{$LibVersion}{$AbsPath}{$IncPath}{$Prefix} = 1;
5844 }
5845 }
5846 foreach my $Dep (keys(%{$Header_Include_Prefix{$LibVersion}{$AbsPath}}))
5847 {
5848 if($GlibcHeader{get_filename($Dep)} and keys(%{$Header_Include_Prefix{$LibVersion}{$AbsPath}{$Dep}})>=2
5849 and defined $Header_Include_Prefix{$LibVersion}{$AbsPath}{$Dep}{""})
5850 { # distinguish math.h from glibc and math.h from the tested library
5851 delete($Header_Include_Prefix{$LibVersion}{$AbsPath}{$Dep}{""});
5852 last;
5853 }
5854 }
5855 }
5856 pop(@RecurInclude);
5857 return keys(%{$RecursiveIncludes{$LibVersion}{$AbsPath}});
5858}
5859
5860sub find_in_framework($$$)
5861{
5862 my ($Header, $Framework, $LibVersion) = @_;
5863 return "" if(not $Header or not $Framework or not $LibVersion);
5864 if(defined $Cache{"find_in_framework"}{$LibVersion}{$Framework}{$Header}) {
5865 return $Cache{"find_in_framework"}{$LibVersion}{$Framework}{$Header};
5866 }
5867 foreach my $Dependency (sort {get_depth($a)<=>get_depth($b)} keys(%{$Header_Dependency{$LibVersion}}))
5868 {
5869 if(get_filename($Dependency) eq $Framework
5870 and -f get_dirname($Dependency)."/".$Header) {
5871 return ($Cache{"find_in_framework"}{$LibVersion}{$Framework}{$Header} = get_dirname($Dependency));
5872 }
5873 }
5874 return ($Cache{"find_in_framework"}{$LibVersion}{$Framework}{$Header} = "");
5875}
5876
5877sub find_in_defaults($)
5878{
5879 my $Header = $_[0];
5880 return "" if(not $Header);
5881 if(defined $Cache{"find_in_defaults"}{$Header}) {
5882 return $Cache{"find_in_defaults"}{$Header};
5883 }
5884 foreach my $Dir (sort {get_depth($a)<=>get_depth($b)}
5885 (keys(%DefaultIncPaths), keys(%DefaultGccPaths), keys(%DefaultCppPaths), keys(%UserIncPath)))
5886 {
5887 next if(not $Dir);
5888 if(-f $Dir."/".$Header) {
5889 return ($Cache{"find_in_defaults"}{$Header}=$Dir);
5890 }
5891 }
5892 return ($Cache{"find_in_defaults"}{$Header}="");
5893}
5894
5895sub cmp_paths($$)
5896{
5897 my ($Path1, $Path2) = @_;
5898 my @Parts1 = split(/[\/\\]/, $Path1);
5899 my @Parts2 = split(/[\/\\]/, $Path2);
5900 foreach my $Num (0 .. $#Parts1)
5901 {
5902 my $Part1 = $Parts1[$Num];
5903 my $Part2 = $Parts2[$Num];
5904 if($GlibcDir{$Part1}
5905 and not $GlibcDir{$Part2}) {
5906 return 1;
5907 }
5908 elsif($GlibcDir{$Part2}
5909 and not $GlibcDir{$Part1}) {
5910 return -1;
5911 }
5912 elsif($Part1=~/glib/
5913 and $Part2!~/glib/) {
5914 return 1;
5915 }
5916 elsif($Part1!~/glib/
5917 and $Part2=~/glib/) {
5918 return -1;
5919 }
5920 elsif(my $CmpRes = ($Part1 cmp $Part2)) {
5921 return $CmpRes;
5922 }
5923 }
5924 return 0;
5925}
5926
5927sub checkRelevance($)
5928{
5929 my ($Path) = @_;
5930 return 0 if(not $Path);
5931 if($SystemRoot) {
Andrey Ponomarenkoa01311b2012-06-08 17:20:02 +04005932 $Path = cut_path_prefix($Path, $SystemRoot);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005933 }
5934 my ($Dir, $Name) = separate_path($Path);
Andrey Ponomarenkoa01311b2012-06-08 17:20:02 +04005935 $Name=~s/\.\w+\Z//g; # remove extension (.h)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005936 my @Tokens = split(/[_\d\W]+/, $Name);
5937 foreach (@Tokens)
5938 {
5939 next if(not $_);
5940 if($Dir=~/(\A|lib|[_\d\W])\Q$_\E([_\d\W]|lib|\Z)/i
5941 or length($_)>=4 and $Dir=~/\Q$_\E/i)
5942 { # include/gupnp-1.0/libgupnp/gupnp-context.h
5943 # include/evolution-data-server-1.4/libebook/e-book.h
5944 return 1;
5945 }
5946 }
5947 return 0;
5948}
5949
5950sub checkFamily(@)
5951{
5952 my @Paths = @_;
5953 return 1 if($#Paths<=0);
5954 my %Prefix = ();
5955 foreach my $Path (@Paths)
5956 {
5957 if($SystemRoot) {
5958 $Path = cut_path_prefix($Path, $SystemRoot);
5959 }
5960 if(my $Dir = get_dirname($Path))
5961 {
5962 $Dir=~s/(\/[^\/]+?)[\d\.\-\_]+\Z/$1/g; # remove version suffix
5963 $Prefix{$Dir} += 1;
5964 $Prefix{get_dirname($Dir)} += 1;
5965 }
5966 }
5967 foreach (sort keys(%Prefix))
5968 {
5969 if(get_depth($_)>=3
5970 and $Prefix{$_}==$#Paths+1) {
5971 return 1;
5972 }
5973 }
5974 return 0;
5975}
5976
5977sub isAcceptable($$$)
5978{
5979 my ($Header, $Candidate, $LibVersion) = @_;
5980 my $HName = get_filename($Header);
5981 if(get_dirname($Header))
5982 { # with prefix
5983 return 1;
5984 }
5985 if($HName=~/config|setup/i and $Candidate=~/[\/\\]lib\d*[\/\\]/)
5986 { # allow to search for glibconfig.h in /usr/lib/glib-2.0/include/
5987 return 1;
5988 }
5989 if(checkRelevance($Candidate))
5990 { # allow to search for atk.h in /usr/include/atk-1.0/atk/
5991 return 1;
5992 }
5993 if(checkFamily(getSystemHeaders($HName, $LibVersion)))
5994 { # /usr/include/qt4/QtNetwork/qsslconfiguration.h
5995 # /usr/include/qt4/Qt/qsslconfiguration.h
5996 return 1;
5997 }
5998 if($OStarget eq "symbian")
5999 {
6000 if($Candidate=~/[\/\\]stdapis[\/\\]/) {
6001 return 1;
6002 }
6003 }
6004 return 0;
6005}
6006
6007sub isRelevant($$$)
6008{ # disallow to search for "abstract" headers in too deep directories
6009 my ($Header, $Candidate, $LibVersion) = @_;
6010 my $HName = get_filename($Header);
6011 if($OStarget eq "symbian")
6012 {
6013 if($Candidate=~/[\/\\](tools|stlportv5)[\/\\]/) {
6014 return 0;
6015 }
6016 }
6017 if($OStarget ne "bsd") {
6018 if($Candidate=~/[\/\\]include[\/\\]bsd[\/\\]/)
6019 { # openssh: skip /usr/lib/bcc/include/bsd/signal.h
6020 return 0;
6021 }
6022 }
6023 if(not get_dirname($Header)
6024 and $Candidate=~/[\/\\]wx[\/\\]/)
6025 { # do NOT search in system /wx/ directory
6026 # for headers without a prefix: sstream.h
6027 return 0;
6028 }
6029 if($Candidate=~/c\+\+[\/\\]\d+/ and $MAIN_CPP_DIR
6030 and $Candidate!~/\A\Q$MAIN_CPP_DIR\E/)
6031 { # skip ../c++/3.3.3/ if using ../c++/4.5/
6032 return 0;
6033 }
6034 if($Candidate=~/[\/\\]asm-/
6035 and (my $Arch = getArch($LibVersion)) ne "unknown")
6036 { # arch-specific header files
6037 if($Candidate!~/[\/\\]asm-\Q$Arch\E/)
6038 {# skip ../asm-arm/ if using x86 architecture
6039 return 0;
6040 }
6041 }
6042 my @Candidates = getSystemHeaders($HName, $LibVersion);
6043 if($#Candidates==1)
6044 { # unique header
6045 return 1;
6046 }
6047 my @SCandidates = getSystemHeaders($Header, $LibVersion);
6048 if($#SCandidates==1)
6049 { # unique name
6050 return 1;
6051 }
6052 my $SystemDepth = $SystemRoot?get_depth($SystemRoot):0;
6053 if(get_depth($Candidate)-$SystemDepth>=5)
6054 { # abstract headers in too deep directories
6055 # sstream.h or typeinfo.h in /usr/include/wx-2.9/wx/
6056 if(not isAcceptable($Header, $Candidate, $LibVersion)) {
6057 return 0;
6058 }
6059 }
6060 if($Header eq "parser.h"
6061 and $Candidate!~/\/libxml2\//)
6062 { # select parser.h from xml2 library
6063 return 0;
6064 }
6065 if(not get_dirname($Header)
6066 and keys(%{$SystemHeaders{$HName}})>=3)
6067 { # many headers with the same name
6068 # like thread.h included without a prefix
6069 if(not checkFamily(@Candidates)) {
6070 return 0;
6071 }
6072 }
6073 return 1;
6074}
6075
6076sub selectSystemHeader($$)
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04006077{ # cache function
6078 if(defined $Cache{"selectSystemHeader"}{$_[1]}{$_[0]}) {
6079 return $Cache{"selectSystemHeader"}{$_[1]}{$_[0]};
6080 }
6081 return ($Cache{"selectSystemHeader"}{$_[1]}{$_[0]} = selectSystemHeader_I(@_));
6082}
6083
6084sub selectSystemHeader_I($$)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006085{
6086 my ($Header, $LibVersion) = @_;
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04006087 if(-f $Header) {
6088 return $Header;
6089 }
6090 if(is_abs($Header) and not -f $Header)
6091 { # incorrect absolute path
6092 return "";
6093 }
6094 if($Header=~/\A(atomic|config|configure|build|conf|setup)\.h\Z/i)
6095 { # too abstract configuration headers
6096 return "";
6097 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006098 if($OSgroup ne "windows")
6099 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04006100 if(get_filename($Header)=~/windows|win32|win64|\A(dos|process|winsock|config-win)\.h\Z/i)
6101 { # windows headers
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006102 return "";
6103 }
6104 elsif($Header=~/\A(mem)\.h\Z/)
6105 { # pngconf.h include mem.h for __MSDOS__
6106 return "";
6107 }
6108 }
6109 if($OSgroup ne "solaris")
6110 {
6111 if($Header=~/\A(thread)\.h\Z/)
6112 { # thread.h in Solaris
6113 return "";
6114 }
6115 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04006116
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006117 foreach my $Path (keys(%{$SystemPaths{"include"}}))
6118 { # search in default paths
6119 if(-f $Path."/".$Header) {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04006120 return joinPath($Path,$Header);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006121 }
6122 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04006123 if(not keys(%SystemHeaders))
6124 { # register all headers in system include dirs
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006125 detectSystemHeaders();
6126 }
6127 foreach my $Candidate (sort {get_depth($a)<=>get_depth($b)}
6128 sort {cmp_paths($b, $a)} getSystemHeaders($Header, $LibVersion))
6129 {
6130 if(isRelevant($Header, $Candidate, $LibVersion)) {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04006131 return $Candidate;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006132 }
6133 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04006134 # error
6135 return "";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006136}
6137
6138sub getSystemHeaders($$)
6139{
6140 my ($Header, $LibVersion) = @_;
6141 my @Candidates = ();
6142 foreach my $Candidate (sort keys(%{$SystemHeaders{$Header}}))
6143 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04006144 if(skipHeader($Candidate, $LibVersion)) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006145 next;
6146 }
6147 push(@Candidates, $Candidate);
6148 }
6149 return @Candidates;
6150}
6151
6152sub cut_path_prefix($$)
6153{
6154 my ($Path, $Prefix) = @_;
6155 return $Path if(not $Prefix);
6156 $Prefix=~s/[\/\\]+\Z//;
6157 $Path=~s/\A\Q$Prefix\E([\/\\]+|\Z)//;
6158 return $Path;
6159}
6160
6161sub is_default_include_dir($)
6162{
6163 my $Dir = $_[0];
6164 $Dir=~s/[\/\\]+\Z//;
6165 return ($DefaultGccPaths{$Dir} or $DefaultCppPaths{$Dir} or $DefaultIncPaths{$Dir});
6166}
6167
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04006168sub identifyHeader($$)
6169{ # cache function
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006170 my ($Header, $LibVersion) = @_;
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04006171 if(not $Header) {
6172 return "";
6173 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006174 $Header=~s/\A(\.\.[\\\/])+//g;
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04006175 if(defined $Cache{"identifyHeader"}{$LibVersion}{$Header}) {
6176 return $Cache{"identifyHeader"}{$LibVersion}{$Header};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006177 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04006178 return ($Cache{"identifyHeader"}{$LibVersion}{$Header} = identifyHeader_I($Header, $LibVersion));
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006179}
6180
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04006181sub identifyHeader_I($$)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006182{ # search for header by absolute path, relative path or name
6183 my ($Header, $LibVersion) = @_;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006184 if(-f $Header)
6185 { # it's relative or absolute path
6186 return get_abs_path($Header);
6187 }
6188 elsif($GlibcHeader{$Header} and not $GLIBC_TESTING
6189 and my $HeaderDir = find_in_defaults($Header))
6190 { # search for libc headers in the /usr/include
6191 # for non-libc target library before searching
6192 # in the library paths
6193 return joinPath($HeaderDir,$Header);
6194 }
6195 elsif(my $Path = $Include_Neighbors{$LibVersion}{$Header})
6196 { # search in the target library paths
6197 return $Path;
6198 }
6199 elsif($DefaultGccHeader{$Header})
6200 { # search in the internal GCC include paths
6201 return $DefaultGccHeader{$Header};
6202 }
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04006203 elsif(my $DefaultDir = find_in_defaults($Header))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006204 { # search in the default GCC include paths
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04006205 return joinPath($DefaultDir,$Header);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006206 }
6207 elsif($DefaultCppHeader{$Header})
6208 { # search in the default G++ include paths
6209 return $DefaultCppHeader{$Header};
6210 }
6211 elsif(my $AnyPath = selectSystemHeader($Header, $LibVersion))
6212 { # search everywhere in the system
6213 return $AnyPath;
6214 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04006215 elsif($OSgroup eq "macos")
6216 { # search in frameworks: "OpenGL/gl.h" is "OpenGL.framework/Headers/gl.h"
6217 if(my $Dir = get_dirname($Header))
6218 {
6219 my $RelPath = "Headers\/".get_filename($Header);
6220 if(my $HeaderDir = find_in_framework($RelPath, $Dir.".framework", $LibVersion)) {
6221 return joinPath($HeaderDir, $RelPath);
6222 }
6223 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006224 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04006225 # cannot find anything
6226 return "";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006227}
6228
6229sub getLocation($)
6230{
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04006231 if($_[0] and my $Info = $LibInfo{$Version}{"info"}{$_[0]})
6232 {
6233 if($Info=~/srcp[ ]*:[ ]*([\w\-\<\>\.\+\/\\]+):(\d+) /) {
6234 return ($1, $2);
6235 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006236 }
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04006237 return ();
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006238}
6239
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006240sub getNameByInfo($)
6241{
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04006242 if($_[0] and my $Info = $LibInfo{$Version}{"info"}{$_[0]})
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04006243 {
6244 if($Info=~/name[ ]*:[ ]*@(\d+) /)
6245 {
6246 if(my $NInfo = $LibInfo{$Version}{"info"}{$1})
6247 {
6248 if($NInfo=~/strg[ ]*:[ ]*(.*?)[ ]+lngt/)
6249 { # short unsigned int (may include spaces)
6250 return $1;
6251 }
6252 }
6253 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006254 }
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04006255 return "";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006256}
6257
6258sub getTreeStr($)
6259{
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04006260 if($_[0] and my $Info = $LibInfo{$Version}{"info"}{$_[0]})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006261 {
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04006262 if($Info=~/strg[ ]*:[ ]*([^ ]*)/)
6263 {
6264 my $Str = $1;
6265 if($C99Mode{$Version}
6266 and $Str=~/\Ac99_(.+)\Z/) {
6267 if($CppKeywords_A{$1}) {
6268 $Str=$1;
6269 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006270 }
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04006271 return $Str;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006272 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006273 }
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04006274 return "";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006275}
6276
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006277sub getFuncShortName($)
6278{
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04006279 if(my $Info = $LibInfo{$Version}{"info"}{$_[0]})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006280 {
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04006281 if($Info=~/ operator /)
6282 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04006283 if($Info=~/ conversion /)
6284 {
6285 if(my $Rid = $SymbolInfo{$Version}{$_[0]}{"Return"})
6286 {
6287 if(my $RName = $TypeInfo{$Version}{$Rid}{"Name"}) {
6288 return "operator ".$RName;
6289 }
6290 }
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04006291 }
6292 else
6293 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04006294 if($Info=~/ operator[ ]+([a-zA-Z]+) /)
6295 {
6296 if(my $Ind = $Operator_Indication{$1}) {
6297 return "operator".$Ind;
6298 }
6299 elsif(not $UnknownOperator{$1})
6300 {
6301 printMsg("WARNING", "unknown operator $1");
6302 $UnknownOperator{$1} = 1;
6303 }
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04006304 }
6305 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006306 }
6307 else
6308 {
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04006309 if($Info=~/name[ ]*:[ ]*@(\d+) /) {
6310 return getTreeStr($1);
6311 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006312 }
6313 }
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04006314 return "";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006315}
6316
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006317sub getFuncReturn($)
6318{
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04006319 if($_[0] and my $Info = $LibInfo{$Version}{"info"}{$_[0]})
6320 {
6321 if($Info=~/type[ ]*:[ ]*@(\d+) /)
6322 {
6323 if($LibInfo{$Version}{"info"}{$1}=~/retn[ ]*:[ ]*@(\d+) /) {
6324 return $1;
6325 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006326 }
6327 }
6328 return "";
6329}
6330
6331sub getFuncOrig($)
6332{
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04006333 if($_[0] and my $Info = $LibInfo{$Version}{"info"}{$_[0]})
6334 {
6335 if($Info=~/orig[ ]*:[ ]*@(\d+) /) {
6336 return $1;
6337 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006338 }
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04006339 return $_[0];
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006340}
6341
6342sub unmangleSymbol($)
6343{
6344 my $Symbol = $_[0];
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04006345 if(my @Unmngl = unmangleArray($Symbol)) {
6346 return $Unmngl[0];
6347 }
6348 return "";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006349}
6350
6351sub unmangleArray(@)
6352{
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04006353 if($_[0]=~/\A\?/)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006354 { # MSVC mangling
6355 my $UndNameCmd = get_CmdPath("undname");
6356 if(not $UndNameCmd) {
6357 exitStatus("Not_Found", "can't find \"undname\"");
6358 }
6359 writeFile("$TMP_DIR/unmangle", join("\n", @_));
Andrey Ponomarenkoa01311b2012-06-08 17:20:02 +04006360 return split(/\n/, `$UndNameCmd 0x8386 \"$TMP_DIR/unmangle\"`);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006361 }
6362 else
6363 { # GCC mangling
6364 my $CppFiltCmd = get_CmdPath("c++filt");
6365 if(not $CppFiltCmd) {
6366 exitStatus("Not_Found", "can't find c++filt in PATH");
6367 }
6368 my $Info = `$CppFiltCmd -h 2>&1`;
6369 if($Info=~/\@<file>/)
6370 {# new version of c++filt can take a file
6371 my $NoStrip = "";
6372 if($OSgroup eq "macos"
6373 or $OSgroup eq "windows") {
6374 $NoStrip = "-n";
6375 }
6376 writeFile("$TMP_DIR/unmangle", join("\n", @_));
6377 return split(/\n/, `$CppFiltCmd $NoStrip \@\"$TMP_DIR/unmangle\"`);
6378 }
6379 else
6380 { # old-style unmangling
6381 if($#_>$MAX_COMMAND_LINE_ARGUMENTS) {
6382 my @Half = splice(@_, 0, ($#_+1)/2);
6383 return (unmangleArray(@Half), unmangleArray(@_))
6384 }
6385 else
6386 {
6387 my $NoStrip = "";
6388 if($OSgroup eq "macos"
6389 or $OSgroup eq "windows") {
6390 $NoStrip = "-n";
6391 }
6392 my $Strings = join(" ", @_);
6393 return split(/\n/, `$CppFiltCmd $NoStrip $Strings`);
6394 }
6395 }
6396 }
6397}
6398
6399sub get_SignatureNoInfo($$)
6400{
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04006401 my ($Symbol, $LibVersion) = @_;
6402 if($Cache{"get_SignatureNoInfo"}{$LibVersion}{$Symbol}) {
6403 return $Cache{"get_SignatureNoInfo"}{$LibVersion}{$Symbol};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006404 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04006405 my ($MnglName, $VersionSpec, $SymbolVersion) = separate_symbol($Symbol);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006406 my $Signature = $tr_name{$MnglName}?$tr_name{$MnglName}:$MnglName;
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04006407 if($Symbol=~/\A(_Z|\?)/)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006408 { # C++
6409 $Signature=~s/\Qstd::basic_string<char, std::char_traits<char>, std::allocator<char> >\E/std::string/g;
6410 $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;
6411 }
6412 if(not $CheckObjectsOnly or $OSgroup=~/linux|bsd|beos/)
6413 { # ELF format marks data as OBJECT
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04006414 if($GlobalDataObject{$LibVersion}{$Symbol}) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006415 $Signature .= " [data]";
6416 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04006417 elsif($Symbol!~/\A(_Z|\?)/) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006418 $Signature .= " (...)";
6419 }
6420 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04006421 if(my $ChargeLevel = get_ChargeLevel($Symbol, $LibVersion))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006422 {
Andrey Ponomarenko16934472012-03-29 15:37:04 +04006423 my $ShortName = substr($Signature, 0, find_center($Signature, "("));
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006424 $Signature=~s/\A\Q$ShortName\E/$ShortName $ChargeLevel/g;
6425 }
6426 if($SymbolVersion) {
6427 $Signature .= $VersionSpec.$SymbolVersion;
6428 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04006429 return ($Cache{"get_SignatureNoInfo"}{$LibVersion}{$Symbol} = $Signature);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006430}
6431
6432sub get_ChargeLevel($$)
6433{
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04006434 my ($Symbol, $LibVersion) = @_;
6435 return "" if($Symbol!~/\A(_Z|\?)/);
6436 if(defined $CompleteSignature{$LibVersion}{$Symbol}
6437 and $CompleteSignature{$LibVersion}{$Symbol}{"Header"})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006438 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04006439 if($CompleteSignature{$LibVersion}{$Symbol}{"Constructor"})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006440 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04006441 if($Symbol=~/C1E/) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006442 return "[in-charge]";
6443 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04006444 elsif($Symbol=~/C2E/) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006445 return "[not-in-charge]";
6446 }
6447 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04006448 elsif($CompleteSignature{$LibVersion}{$Symbol}{"Destructor"})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006449 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04006450 if($Symbol=~/D1E/) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006451 return "[in-charge]";
6452 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04006453 elsif($Symbol=~/D2E/) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006454 return "[not-in-charge]";
6455 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04006456 elsif($Symbol=~/D0E/) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006457 return "[in-charge-deleting]";
6458 }
6459 }
6460 }
6461 else
6462 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04006463 if($Symbol=~/C1E/) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006464 return "[in-charge]";
6465 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04006466 elsif($Symbol=~/C2E/) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006467 return "[not-in-charge]";
6468 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04006469 elsif($Symbol=~/D1E/) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006470 return "[in-charge]";
6471 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04006472 elsif($Symbol=~/D2E/) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006473 return "[not-in-charge]";
6474 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04006475 elsif($Symbol=~/D0E/) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006476 return "[in-charge-deleting]";
6477 }
6478 }
6479 return "";
6480}
6481
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04006482sub get_Signature_M($$)
6483{
6484 my ($Symbol, $LibVersion) = @_;
6485 my $Signature_M = $tr_name{$Symbol};
6486 if(my $RTid = $CompleteSignature{$LibVersion}{$Symbol}{"Return"})
6487 { # add return type name
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04006488 $Signature_M = $TypeInfo{$LibVersion}{$RTid}{"Name"}." ".$Signature_M;
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04006489 }
6490 return $Signature_M;
6491}
6492
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006493sub get_Signature($$)
6494{
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04006495 my ($Symbol, $LibVersion) = @_;
6496 if($Cache{"get_Signature"}{$LibVersion}{$Symbol}) {
6497 return $Cache{"get_Signature"}{$LibVersion}{$Symbol};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006498 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04006499 my ($MnglName, $VersionSpec, $SymbolVersion) = separate_symbol($Symbol);
6500 if(isPrivateData($MnglName) or not $CompleteSignature{$LibVersion}{$Symbol}{"Header"})
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04006501 { # non-public global data
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04006502 return get_SignatureNoInfo($Symbol, $LibVersion);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006503 }
6504 my ($Func_Signature, @Param_Types_FromUnmangledName) = ();
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04006505 my $ShortName = $CompleteSignature{$LibVersion}{$Symbol}{"ShortName"};
6506 if($Symbol=~/\A(_Z|\?)/)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006507 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04006508 if(my $ClassId = $CompleteSignature{$LibVersion}{$Symbol}{"Class"}) {
6509 $Func_Signature = $TypeInfo{$LibVersion}{$ClassId}{"Name"}."::".(($CompleteSignature{$LibVersion}{$Symbol}{"Destructor"})?"~":"").$ShortName;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006510 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04006511 elsif(my $NameSpace = $CompleteSignature{$LibVersion}{$Symbol}{"NameSpace"}) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006512 $Func_Signature = $NameSpace."::".$ShortName;
6513 }
6514 else {
6515 $Func_Signature = $ShortName;
6516 }
6517 @Param_Types_FromUnmangledName = get_s_params($tr_name{$MnglName}, 0);
6518 }
6519 else {
6520 $Func_Signature = $MnglName;
6521 }
6522 my @ParamArray = ();
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04006523 foreach my $Pos (sort {int($a) <=> int($b)} keys(%{$CompleteSignature{$LibVersion}{$Symbol}{"Param"}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006524 {
6525 next if($Pos eq "");
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04006526 my $ParamTypeId = $CompleteSignature{$LibVersion}{$Symbol}{"Param"}{$Pos}{"type"};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006527 next if(not $ParamTypeId);
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04006528 my $ParamTypeName = $TypeInfo{$LibVersion}{$ParamTypeId}{"Name"};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006529 if(not $ParamTypeName) {
6530 $ParamTypeName = $Param_Types_FromUnmangledName[$Pos];
6531 }
6532 foreach my $Typedef (keys(%ChangedTypedef))
6533 {
6534 my $Base = $Typedef_BaseName{$LibVersion}{$Typedef};
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04006535 $ParamTypeName=~s/\b\Q$Typedef\E\b/$Base/g;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006536 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04006537 if(my $ParamName = $CompleteSignature{$LibVersion}{$Symbol}{"Param"}{$Pos}{"name"}) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006538 push(@ParamArray, create_member_decl($ParamTypeName, $ParamName));
6539 }
6540 else {
6541 push(@ParamArray, $ParamTypeName);
6542 }
6543 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04006544 if($CompleteSignature{$LibVersion}{$Symbol}{"Data"}
6545 or $GlobalDataObject{$LibVersion}{$Symbol}) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006546 $Func_Signature .= " [data]";
6547 }
6548 else
6549 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04006550 if(my $ChargeLevel = get_ChargeLevel($Symbol, $LibVersion))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006551 { # add [in-charge]
6552 $Func_Signature .= " ".$ChargeLevel;
6553 }
6554 $Func_Signature .= " (".join(", ", @ParamArray).")";
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04006555 if($CompleteSignature{$LibVersion}{$Symbol}{"Const"}
6556 or $Symbol=~/\A_ZN(V|)K/) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006557 $Func_Signature .= " const";
6558 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04006559 if($CompleteSignature{$LibVersion}{$Symbol}{"Volatile"}
6560 or $Symbol=~/\A_ZN(K|)V/) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006561 $Func_Signature .= " volatile";
6562 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04006563 if($CompleteSignature{$LibVersion}{$Symbol}{"Static"}
6564 and $Symbol=~/\A(_Z|\?)/)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006565 {# for static methods
6566 $Func_Signature .= " [static]";
6567 }
6568 }
6569 if(defined $ShowRetVal
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04006570 and my $ReturnTId = $CompleteSignature{$LibVersion}{$Symbol}{"Return"}) {
6571 $Func_Signature .= ":".$TypeInfo{$LibVersion}{$ReturnTId}{"Name"};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006572 }
6573 if($SymbolVersion) {
6574 $Func_Signature .= $VersionSpec.$SymbolVersion;
6575 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04006576 return ($Cache{"get_Signature"}{$LibVersion}{$Symbol} = $Func_Signature);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006577}
6578
6579sub create_member_decl($$)
6580{
6581 my ($TName, $Member) = @_;
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04006582 if($TName=~/\([\*]+\)/)
6583 {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006584 $TName=~s/\(([\*]+)\)/\($1$Member\)/;
6585 return $TName;
6586 }
6587 else
6588 {
6589 my @ArraySizes = ();
6590 while($TName=~s/(\[[^\[\]]*\])\Z//) {
6591 push(@ArraySizes, $1);
6592 }
6593 return $TName." ".$Member.join("", @ArraySizes);
6594 }
6595}
6596
6597sub getFuncType($)
6598{
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04006599 if($_[0] and my $Info = $LibInfo{$Version}{"info"}{$_[0]})
6600 {
6601 if($Info=~/type[ ]*:[ ]*@(\d+) /)
6602 {
6603 if(my $Type = $LibInfo{$Version}{"info_type"}{$1})
6604 {
6605 if($Type eq "method_type") {
6606 return "Method";
6607 }
6608 elsif($Type eq "function_type") {
6609 return "Function";
6610 }
6611 else {
6612 return "Other";
6613 }
6614 }
6615 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006616 }
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04006617 return ""
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006618}
6619
6620sub getFuncTypeId($)
6621{
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04006622 if($_[0] and my $Info = $LibInfo{$Version}{"info"}{$_[0]})
6623 {
6624 if($Info=~/type[ ]*:[ ]*@(\d+)( |\Z)/) {
6625 return $1;
6626 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006627 }
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04006628 return 0;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006629}
6630
6631sub isNotAnon($) {
6632 return (not isAnon($_[0]));
6633}
6634
6635sub isAnon($)
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04006636{ # "._N" or "$_N" in older GCC versions
6637 return ($_[0] and $_[0]=~/(\.|\$)\_\d+|anon\-/);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006638}
6639
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006640sub formatName($)
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04006641{ # type name correction
6642 if(defined $Cache{"formatName"}{$_[0]}) {
6643 return $Cache{"formatName"}{$_[0]};
6644 }
6645
6646 $_ = $_[0];
6647
6648 s/\A[ ]+|[ ]+\Z//g;
6649 s/[ ]{2,}/ /g;
6650 s/[ ]*(\W)[ ]*/$1/g;
6651
6652 s/\bvolatile const\b/const volatile/g;
6653
6654 s/\b(long long|short|long) unsigned\b/unsigned $1/g;
6655 s/\b(short|long) int\b/$1/g;
6656
6657 s/([\)\]])(const|volatile)\b/$1 $2/g;
6658
6659 while(s/>>/> >/g) {};
6660
6661 s/\b(operator[ ]*)> >/$1>>/;
6662
6663 return ($Cache{"formatName"}{$_[0]}=$_);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006664}
6665
6666sub get_HeaderDeps($$)
6667{
6668 my ($AbsPath, $LibVersion) = @_;
6669 return () if(not $AbsPath or not $LibVersion);
6670 if(defined $Cache{"get_HeaderDeps"}{$LibVersion}{$AbsPath}) {
6671 return @{$Cache{"get_HeaderDeps"}{$LibVersion}{$AbsPath}};
6672 }
6673 my %IncDir = ();
6674 detect_recursive_includes($AbsPath, $LibVersion);
6675 foreach my $HeaderPath (keys(%{$RecursiveIncludes{$LibVersion}{$AbsPath}}))
6676 {
6677 next if(not $HeaderPath);
6678 next if($MAIN_CPP_DIR and $HeaderPath=~/\A\Q$MAIN_CPP_DIR\E([\/\\]|\Z)/);
6679 my $Dir = get_dirname($HeaderPath);
6680 foreach my $Prefix (keys(%{$Header_Include_Prefix{$LibVersion}{$AbsPath}{$HeaderPath}}))
6681 {
6682 my $Dep = $Dir;
6683 if($Prefix)
6684 {
6685 if($OSgroup eq "windows")
6686 { # case insensitive seach on windows
6687 if(not $Dep=~s/[\/\\]+\Q$Prefix\E\Z//ig) {
6688 next;
6689 }
6690 }
6691 elsif($OSgroup eq "macos")
6692 { # seach in frameworks
6693 if(not $Dep=~s/[\/\\]+\Q$Prefix\E\Z//g)
6694 {
6695 if($HeaderPath=~/(.+\.framework)\/Headers\/([^\/]+)/)
6696 {# frameworks
6697 my ($HFramework, $HName) = ($1, $2);
6698 $Dep = $HFramework;
6699 }
6700 else
6701 {# mismatch
6702 next;
6703 }
6704 }
6705 }
6706 elsif(not $Dep=~s/[\/\\]+\Q$Prefix\E\Z//g)
6707 { # Linux, FreeBSD
6708 next;
6709 }
6710 }
6711 if(not $Dep)
6712 { # nothing to include
6713 next;
6714 }
6715 if(is_default_include_dir($Dep))
6716 { # included by the compiler
6717 next;
6718 }
6719 if(get_depth($Dep)==1)
6720 { # too short
6721 next;
6722 }
6723 if(isLibcDir($Dep))
6724 { # do NOT include /usr/include/{sys,bits}
6725 next;
6726 }
6727 $IncDir{$Dep}=1;
6728 }
6729 }
6730 $Cache{"get_HeaderDeps"}{$LibVersion}{$AbsPath} = sortIncPaths([keys(%IncDir)], $LibVersion);
6731 return @{$Cache{"get_HeaderDeps"}{$LibVersion}{$AbsPath}};
6732}
6733
6734sub sortIncPaths($$)
6735{
6736 my ($ArrRef, $LibVersion) = @_;
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04006737 if(not $ArrRef or $#{$ArrRef}<0) {
6738 return $ArrRef;
6739 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006740 @{$ArrRef} = sort {$b cmp $a} @{$ArrRef};
6741 @{$ArrRef} = sort {get_depth($a)<=>get_depth($b)} @{$ArrRef};
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04006742 @{$ArrRef} = sort {sortDeps($b, $a, $LibVersion)} @{$ArrRef};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006743 return $ArrRef;
6744}
6745
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04006746sub sortDeps($$$)
6747{
6748 if($Header_Dependency{$_[2]}{$_[0]}
6749 and not $Header_Dependency{$_[2]}{$_[1]}) {
6750 return 1;
6751 }
6752 elsif(not $Header_Dependency{$_[2]}{$_[0]}
6753 and $Header_Dependency{$_[2]}{$_[1]}) {
6754 return -1;
6755 }
6756 return 0;
6757}
6758
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006759sub joinPath($$) {
6760 return join($SLASH, @_);
6761}
6762
6763sub get_namespace_additions($)
6764{
6765 my $NameSpaces = $_[0];
6766 my ($Additions, $AddNameSpaceId) = ("", 1);
6767 foreach my $NS (sort {$a=~/_/ <=> $b=~/_/} sort {lc($a) cmp lc($b)} keys(%{$NameSpaces}))
6768 {
6769 next if($SkipNameSpaces{$Version}{$NS});
6770 next if(not $NS or $NameSpaces->{$NS}==-1);
6771 next if($NS=~/(\A|::)iterator(::|\Z)/i);
6772 next if($NS=~/\A__/i);
6773 next if(($NS=~/\Astd::/ or $NS=~/\A(std|tr1|rel_ops|fcntl)\Z/) and not $STDCXX_TESTING);
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04006774 $NestedNameSpaces{$Version}{$NS} = 1; # for future use in reports
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006775 my ($TypeDecl_Prefix, $TypeDecl_Suffix) = ();
6776 my @NS_Parts = split(/::/, $NS);
6777 next if($#NS_Parts==-1);
6778 next if($NS_Parts[0]=~/\A(random|or)\Z/);
6779 foreach my $NS_Part (@NS_Parts)
6780 {
6781 $TypeDecl_Prefix .= "namespace $NS_Part\{";
6782 $TypeDecl_Suffix .= "}";
6783 }
6784 my $TypeDecl = $TypeDecl_Prefix."typedef int tmp_add_type_$AddNameSpaceId;".$TypeDecl_Suffix;
6785 my $FuncDecl = "$NS\:\:tmp_add_type_$AddNameSpaceId tmp_add_func_$AddNameSpaceId(){return 0;};";
6786 $Additions.=" $TypeDecl\n $FuncDecl\n";
6787 $AddNameSpaceId+=1;
6788 }
6789 return $Additions;
6790}
6791
6792sub path_format($$)
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04006793{ # forward slash to pass into MinGW GCC
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006794 my ($Path, $Fmt) = @_;
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04006795 if($Fmt eq "windows")
6796 {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006797 $Path=~s/\//\\/g;
6798 $Path=lc($Path);
6799 }
6800 else {
6801 $Path=~s/\\/\//g;
6802 }
6803 return $Path;
6804}
6805
6806sub inc_opt($$)
6807{
6808 my ($Path, $Style) = @_;
6809 if($Style eq "GCC")
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04006810 { # GCC options
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006811 if($OSgroup eq "windows")
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04006812 { # to MinGW GCC
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006813 return "-I\"".path_format($Path, "unix")."\"";
6814 }
6815 elsif($OSgroup eq "macos"
6816 and $Path=~/\.framework\Z/)
6817 {# to Apple's GCC
6818 return "-F".esc(get_dirname($Path));
6819 }
6820 else {
6821 return "-I".esc($Path);
6822 }
6823 }
6824 elsif($Style eq "CL") {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04006825 return "/I \"".$Path."\"";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006826 }
6827 return "";
6828}
6829
6830sub platformSpecs($)
6831{
6832 my $LibVersion = $_[0];
6833 my $Arch = getArch($LibVersion);
6834 if($OStarget eq "symbian")
6835 { # options for GCCE compiler
6836 my %Symbian_Opts = map {$_=>1} (
6837 "-D__GCCE__",
6838 "-DUNICODE",
6839 "-fexceptions",
6840 "-D__SYMBIAN32__",
6841 "-D__MARM_INTERWORK__",
6842 "-D_UNICODE",
6843 "-D__S60_50__",
6844 "-D__S60_3X__",
6845 "-D__SERIES60_3X__",
6846 "-D__EPOC32__",
6847 "-D__MARM__",
6848 "-D__EABI__",
6849 "-D__MARM_ARMV5__",
6850 "-D__SUPPORT_CPP_EXCEPTIONS__",
6851 "-march=armv5t",
6852 "-mapcs",
6853 "-mthumb-interwork",
6854 "-DEKA2",
6855 "-DSYMBIAN_ENABLE_SPLIT_HEADERS"
6856 );
6857 return join(" ", keys(%Symbian_Opts));
6858 }
6859 elsif($OSgroup eq "windows"
6860 and get_dumpmachine($GCC_PATH)=~/mingw/i)
6861 { # add options to MinGW compiler
6862 # to simulate the MSVC compiler
6863 my %MinGW_Opts = map {$_=>1} (
6864 "-D_WIN32",
6865 "-D_STDCALL_SUPPORTED",
6866 "-D__int64=\"long long\"",
6867 "-D__int32=int",
6868 "-D__int16=short",
6869 "-D__int8=char",
6870 "-D__possibly_notnullterminated=\" \"",
6871 "-D__nullterminated=\" \"",
6872 "-D__nullnullterminated=\" \"",
6873 "-D__w64=\" \"",
6874 "-D__ptr32=\" \"",
6875 "-D__ptr64=\" \"",
6876 "-D__forceinline=inline",
6877 "-D__inline=inline",
6878 "-D__uuidof(x)=IID()",
6879 "-D__try=",
6880 "-D__except(x)=",
6881 "-D__declspec(x)=__attribute__((x))",
6882 "-D__pragma(x)=",
6883 "-D_inline=inline",
6884 "-D__forceinline=__inline",
6885 "-D__stdcall=__attribute__((__stdcall__))",
6886 "-D__cdecl=__attribute__((__cdecl__))",
6887 "-D__fastcall=__attribute__((__fastcall__))",
6888 "-D__thiscall=__attribute__((__thiscall__))",
6889 "-D_stdcall=__attribute__((__stdcall__))",
6890 "-D_cdecl=__attribute__((__cdecl__))",
6891 "-D_fastcall=__attribute__((__fastcall__))",
6892 "-D_thiscall=__attribute__((__thiscall__))",
6893 "-DSHSTDAPI_(x)=x",
6894 "-D_MSC_EXTENSIONS",
6895 "-DSECURITY_WIN32",
6896 "-D_MSC_VER=1500",
6897 "-D_USE_DECLSPECS_FOR_SAL",
6898 "-D__noop=\" \"",
6899 "-DDECLSPEC_DEPRECATED=\" \"",
6900 "-D__builtin_alignof(x)=__alignof__(x)",
6901 "-DSORTPP_PASS");
6902 if($Arch eq "x86") {
6903 $MinGW_Opts{"-D_M_IX86=300"}=1;
6904 }
6905 elsif($Arch eq "x86_64") {
6906 $MinGW_Opts{"-D_M_AMD64=300"}=1;
6907 }
6908 elsif($Arch eq "ia64") {
6909 $MinGW_Opts{"-D_M_IA64=300"}=1;
6910 }
6911 return join(" ", keys(%MinGW_Opts));
6912 }
6913 return "";
6914}
6915
6916my %C_Structure = map {$_=>1} (
6917# FIXME: Can't separate union and struct data types before dumping,
6918# so it sometimes cause compilation errors for unknown reason
6919# when trying to declare TYPE* tmp_add_class_N
6920# This is a list of such structures + list of other C structures
6921 "sigval",
6922 "sigevent",
6923 "sigaction",
6924 "sigvec",
6925 "sigstack",
6926 "timeval",
6927 "timezone",
6928 "rusage",
6929 "rlimit",
6930 "wait",
6931 "flock",
6932 "stat",
6933 "_stat",
6934 "stat32",
6935 "_stat32",
6936 "stat64",
6937 "_stat64",
6938 "_stati64",
6939 "if_nameindex",
6940 "usb_device",
6941 "sigaltstack",
6942 "sysinfo",
6943 "timeLocale",
6944 "tcp_debug",
6945 "rpc_createerr",
6946# Other C structures appearing in every dump
6947 "timespec",
6948 "random_data",
6949 "drand48_data",
6950 "_IO_marker",
6951 "_IO_FILE",
6952 "lconv",
6953 "sched_param",
6954 "tm",
6955 "itimerspec",
6956 "_pthread_cleanup_buffer",
6957 "fd_set",
6958 "siginfo"
6959);
6960
6961sub getCompileCmd($$$)
6962{
6963 my ($Path, $Opt, $Inc) = @_;
6964 my $GccCall = $GCC_PATH;
6965 if($Opt) {
6966 $GccCall .= " ".$Opt;
6967 }
6968 $GccCall .= " -x ";
6969 if($OSgroup eq "macos") {
6970 $GccCall .= "objective-";
6971 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04006972 if(check_gcc($GCC_PATH, "4"))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006973 { # compile as "C++" header
6974 # to obtain complete dump using GCC 4.0
6975 $GccCall .= "c++-header";
6976 }
6977 else
6978 { # compile as "C++" source
6979 # GCC 3.3 cannot compile headers
6980 $GccCall .= "c++";
6981 }
6982 if(my $Opts = platformSpecs($Version))
6983 {# platform-specific options
6984 $GccCall .= " ".$Opts;
6985 }
6986 # allow extra qualifications
6987 # and other nonconformant code
6988 $GccCall .= " -fpermissive -w";
6989 if($NoStdInc)
6990 {
6991 $GccCall .= " -nostdinc";
6992 $GccCall .= " -nostdinc++";
6993 }
6994 if($CompilerOptions{$Version})
6995 { # user-defined options
6996 $GccCall .= " ".$CompilerOptions{$Version};
6997 }
Andrey Ponomarenkoa01311b2012-06-08 17:20:02 +04006998 $GccCall .= " \"$Path\"";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006999 if($Inc)
7000 { # include paths
7001 $GccCall .= " ".$Inc;
7002 }
7003 return $GccCall;
7004}
7005
7006sub getDump()
7007{
7008 if(not $GCC_PATH) {
7009 exitStatus("Error", "internal error - GCC path is not set");
7010 }
7011 my %HeaderElems = (
7012 # Types
7013 "stdio.h" => ["FILE", "va_list"],
Andrey Ponomarenko85043792012-05-14 16:48:07 +04007014 "stddef.h" => ["NULL", "ptrdiff_t"],
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007015 "stdint.h" => ["uint32_t", "int32_t", "uint64_t"],
7016 "time.h" => ["time_t"],
7017 "sys/types.h" => ["ssize_t", "u_int32_t", "u_short", "u_char",
7018 "u_int", "off_t", "u_quad_t", "u_long", "size_t", "mode_t"],
7019 "unistd.h" => ["gid_t", "uid_t"],
7020 "stdbool.h" => ["_Bool"],
7021 "rpc/xdr.h" => ["bool_t"],
7022 "in_systm.h" => ["n_long", "n_short"],
7023 # Fields
Andrey Ponomarenkobede8372012-03-29 17:43:21 +04007024 "arpa/inet.h" => ["fw_src", "ip_src"],
7025 # Functions
7026 "stdlib.h" => ["free", "malloc"],
Andrey Ponomarenko85043792012-05-14 16:48:07 +04007027 "string.h" => ["memmove", "strcmp"]
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007028 );
7029 my %AutoPreamble = ();
Andrey Ponomarenko85043792012-05-14 16:48:07 +04007030 foreach (keys(%HeaderElems))
7031 {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007032 foreach my $Elem (@{$HeaderElems{$_}}) {
7033 $AutoPreamble{$Elem}=$_;
7034 }
7035 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04007036 my $TmpHeaderPath = $TMP_DIR."/dump".$Version.".h";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007037 my $MHeaderPath = $TmpHeaderPath;
Andrey Ponomarenko85043792012-05-14 16:48:07 +04007038 open(TMP_HEADER, ">", $TmpHeaderPath) || die ("can't open file \'$TmpHeaderPath\': $!\n");
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007039 if(my $AddDefines = $Descriptor{$Version}{"Defines"})
7040 {
7041 $AddDefines=~s/\n\s+/\n /g;
Andrey Ponomarenko85043792012-05-14 16:48:07 +04007042 print TMP_HEADER "\n // add defines\n ".$AddDefines."\n";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007043 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +04007044 print TMP_HEADER "\n // add includes\n";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007045 my @PreambleHeaders = keys(%{$Include_Preamble{$Version}});
7046 @PreambleHeaders = sort {int($Include_Preamble{$Version}{$a}{"Position"})<=>int($Include_Preamble{$Version}{$b}{"Position"})} @PreambleHeaders;
7047 foreach my $Header_Path (@PreambleHeaders) {
Andrey Ponomarenko85043792012-05-14 16:48:07 +04007048 print TMP_HEADER " #include \"".path_format($Header_Path, "unix")."\"\n";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007049 }
7050 my @Headers = keys(%{$Registered_Headers{$Version}});
7051 @Headers = sort {int($Registered_Headers{$Version}{$a}{"Pos"})<=>int($Registered_Headers{$Version}{$b}{"Pos"})} @Headers;
7052 foreach my $Header_Path (@Headers)
7053 {
7054 next if($Include_Preamble{$Version}{$Header_Path});
Andrey Ponomarenko85043792012-05-14 16:48:07 +04007055 print TMP_HEADER " #include \"".path_format($Header_Path, "unix")."\"\n";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007056 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +04007057 close(TMP_HEADER);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007058 my $IncludeString = getIncString(getIncPaths(@PreambleHeaders, @Headers), "GCC");
7059 if($Debug)
7060 { # debug mode
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04007061 writeFile($DEBUG_PATH{$Version}."/headers/direct-includes.txt", Dumper($Header_Includes{$Version}));
7062 writeFile($DEBUG_PATH{$Version}."/headers/recursive-includes.txt", Dumper($RecursiveIncludes{$Version}));
7063 writeFile($DEBUG_PATH{$Version}."/headers/include-paths.txt", Dumper($Cache{"get_HeaderDeps"}{$Version}));
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04007064 writeFile($DEBUG_PATH{$Version}."/headers/default-paths.txt", Dumper(\%DefaultIncPaths));
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007065 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +04007066
7067 # Target headers
7068 addTargetHeaders($Version);
7069
7070 # clean memory
7071 %RecursiveIncludes = ();
7072 %Header_Include_Prefix = ();
7073 %Header_Includes = ();
7074
7075 # clean cache
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04007076 delete($Cache{"identifyHeader"});
Andrey Ponomarenko85043792012-05-14 16:48:07 +04007077 delete($Cache{"detect_header_includes"});
7078 delete($Cache{"selectSystemHeader"});
7079
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007080 # preprocessing stage
7081 checkPreprocessedUnit(callPreprocessor($TmpHeaderPath, $IncludeString, $Version));
Andrey Ponomarenko85043792012-05-14 16:48:07 +04007082
7083 # clean memory
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04007084 delete($Include_Neighbors{$Version});
Andrey Ponomarenko85043792012-05-14 16:48:07 +04007085
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007086 my $MContent = "";
7087 my $PreprocessCmd = getCompileCmd($TmpHeaderPath, "-E", $IncludeString);
7088 if($OStarget eq "windows"
7089 and get_dumpmachine($GCC_PATH)=~/mingw/i
7090 and $MinGWMode{$Version}!=-1)
7091 { # modify headers to compile by MinGW
7092 if(not $MContent)
7093 { # preprocessing
Andrey Ponomarenkoa01311b2012-06-08 17:20:02 +04007094 $MContent = `$PreprocessCmd 2>\"$TMP_DIR/null\"`;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007095 }
7096 if($MContent=~s/__asm\s*(\{[^{}]*?\}|[^{};]*)//g)
7097 { # __asm { ... }
7098 $MinGWMode{$Version}=1;
7099 }
7100 if($MContent=~s/\s+(\/ \/.*?)\n/\n/g)
7101 { # comments after preprocessing
7102 $MinGWMode{$Version}=1;
7103 }
7104 if($MContent=~s/(\W)(0x[a-f]+|\d+)(i|ui)(8|16|32|64)(\W)/$1$2$5/g)
7105 { # 0xffui8
7106 $MinGWMode{$Version}=1;
7107 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +04007108 if($MinGWMode{$Version})
7109 {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007110 printMsg("INFO", "Using MinGW compatibility mode");
Andrey Ponomarenkob8d203d2012-05-25 18:11:07 +04007111 $MHeaderPath = $TMP_DIR."/dump$Version.i";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007112 }
7113 }
7114 if(($COMMON_LANGUAGE{$Version} eq "C" or $CheckHeadersOnly)
7115 and $C99Mode{$Version}!=-1 and not $Cpp2003)
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04007116 { # rename C++ keywords in C code
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007117 if(not $MContent)
7118 { # preprocessing
Andrey Ponomarenkoa01311b2012-06-08 17:20:02 +04007119 $MContent = `$PreprocessCmd 2>\"$TMP_DIR/null\"`;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007120 }
7121 my $RegExp_C = join("|", keys(%CppKeywords_C));
7122 my $RegExp_F = join("|", keys(%CppKeywords_F));
7123 my $RegExp_O = join("|", keys(%CppKeywords_O));
7124 while($MContent=~s/(\A|\n[^\#\/\n][^\n]*?|\n)(\*\s*|\s+|\@|\,|\()($RegExp_C|$RegExp_F)(\s*(\,|\)|\;|\-\>|\.|\:\s*\d))/$1$2c99_$3$4/g)
7125 { # MATCH:
7126 # int foo(int new, int class, int (*new)(int));
7127 # unsigned private: 8;
7128 # DO NOT MATCH:
7129 # #pragma GCC visibility push(default)
7130 $C99Mode{$Version} = 1;
7131 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04007132 if($MContent=~s/([^\w\s]|\w\s+)(?<!operator )(delete)(\s*\()/$1c99_$2$3/g)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007133 { # MATCH:
7134 # int delete(...);
7135 # int explicit(...);
7136 # DO NOT MATCH:
7137 # void operator delete(...)
7138 $C99Mode{$Version} = 1;
7139 }
7140 if($MContent=~s/(\s+)($RegExp_O)(\s*(\;|\:))/$1c99_$2$3/g)
7141 { # MATCH:
7142 # int bool;
7143 # DO NOT MATCH:
7144 # bool X;
7145 # return *this;
7146 # throw;
7147 $C99Mode{$Version} = 1;
7148 }
7149 if($MContent=~s/(\s+)(operator)(\s*(\(\s*\)\s*[^\(\s]|\(\s*[^\)\s]))/$1c99_$2$3/g)
7150 { # MATCH:
7151 # int operator(...);
7152 # DO NOT MATCH:
7153 # int operator()(...);
7154 $C99Mode{$Version} = 1;
7155 }
7156 if($MContent=~s/([^\w\(\,\s]\s*|\s+)(operator)(\s*(\,\s*[^\(\s]|\)))/$1c99_$2$3/g)
7157 { # MATCH:
7158 # int foo(int operator);
7159 # int foo(int operator, int other);
7160 # DO NOT MATCH:
7161 # int operator,(...);
7162 $C99Mode{$Version} = 1;
7163 }
7164 if($MContent=~s/(\*\s*|\w\s+)(bool)(\s*(\,|\)))/$1c99_$2$3/g)
7165 { # MATCH:
7166 # int foo(gboolean *bool);
7167 # DO NOT MATCH:
7168 # void setTabEnabled(int index, bool);
7169 $C99Mode{$Version} = 1;
7170 }
7171 if($MContent=~s/(\w)([^\w\(\,\s]\s*|\s+)(this)(\s*(\,|\)))/$1$2c99_$3$4/g)
7172 { # MATCH:
7173 # int foo(int* this);
7174 # int bar(int this);
7175 # DO NOT MATCH:
7176 # baz(X, this);
7177 $C99Mode{$Version} = 1;
7178 }
7179 if($C99Mode{$Version}==1)
7180 { # try to change C++ "keyword" to "c99_keyword"
7181 printMsg("INFO", "Using C99 compatibility mode");
Andrey Ponomarenkob8d203d2012-05-25 18:11:07 +04007182 $MHeaderPath = $TMP_DIR."/dump$Version.i";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007183 }
7184 }
7185 if($C99Mode{$Version}==1
7186 or $MinGWMode{$Version}==1)
7187 { # compile the corrected preprocessor output
7188 writeFile($MHeaderPath, $MContent);
7189 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +04007190
7191 # clean memory
7192 undef $MContent;
7193
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007194 if($COMMON_LANGUAGE{$Version} eq "C++")
7195 { # add classes and namespaces to the dump
7196 my $CHdump = "-fdump-class-hierarchy -c";
7197 if($C99Mode{$Version}==1
7198 or $MinGWMode{$Version}==1) {
7199 $CHdump .= " -fpreprocessed";
7200 }
7201 my $ClassHierarchyCmd = getCompileCmd($MHeaderPath, $CHdump, $IncludeString);
7202 chdir($TMP_DIR);
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04007203 system($ClassHierarchyCmd." >null 2>&1");
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007204 chdir($ORIG_DIR);
7205 if(my $ClassDump = (cmd_find($TMP_DIR,"f","*.class",1))[0])
7206 {
7207 my %AddClasses = ();
7208 my $Content = readFile($ClassDump);
7209 foreach my $ClassInfo (split(/\n\n/, $Content))
7210 {
7211 if($ClassInfo=~/\AClass\s+(.+)\s*/i)
7212 {
7213 my $CName = $1;
7214 next if($CName=~/\A(__|_objc_|_opaque_)/);
7215 $TUnit_NameSpaces{$Version}{$CName} = -1;
7216 if($CName=~/\A[\w:]+\Z/)
7217 { # classes
7218 $AddClasses{$CName} = 1;
7219 }
7220 if($CName=~/(\w[\w:]*)::/)
7221 { # namespaces
7222 my $NS = $1;
7223 if(not defined $TUnit_NameSpaces{$Version}{$NS}) {
7224 $TUnit_NameSpaces{$Version}{$NS} = 1;
7225 }
7226 }
7227 }
7228 elsif($ClassInfo=~/\AVtable\s+for\s+(.+)\n((.|\n)+)\Z/i)
7229 { # read v-tables (advanced approach)
7230 my ($CName, $VTable) = ($1, $2);
7231 $ClassVTable_Content{$Version}{$CName} = $VTable;
7232 }
7233 }
Andrey Ponomarenkoa01311b2012-06-08 17:20:02 +04007234 foreach my $NS (keys(%{$AddNameSpaces{$Version}}))
7235 { # add user-defined namespaces
7236 $TUnit_NameSpaces{$Version}{$NS} = 1;
7237 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007238 if($Debug)
7239 { # debug mode
7240 mkpath($DEBUG_PATH{$Version});
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04007241 copy($ClassDump, $DEBUG_PATH{$Version}."/class-hierarchy-dump.txt");
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007242 }
7243 unlink($ClassDump);
7244 if(my $NS_Add = get_namespace_additions($TUnit_NameSpaces{$Version}))
7245 { # GCC on all supported platforms does not include namespaces to the dump by default
7246 appendFile($MHeaderPath, "\n // add namespaces\n".$NS_Add);
7247 }
7248 # some GCC versions don't include class methods to the TU dump by default
7249 my ($AddClass, $ClassNum) = ("", 0);
7250 foreach my $CName (sort keys(%AddClasses))
7251 {
7252 next if($C_Structure{$CName});
7253 next if(not $STDCXX_TESTING and $CName=~/\Astd::/);
7254 next if(($CName=~tr![:]!!)>2);
7255 next if($SkipTypes{$Version}{$CName});
7256 if($CName=~/\A(.+)::[^:]+\Z/
7257 and $AddClasses{$1}) {
7258 next;
7259 }
7260 $AddClass .= " $CName* tmp_add_class_".($ClassNum++).";\n";
7261 }
7262 appendFile($MHeaderPath, "\n // add classes\n".$AddClass);
7263 }
7264 }
7265 writeLog($Version, "Temporary header file \'$TmpHeaderPath\' with the following content will be compiled to create GCC translation unit dump:\n".readFile($TmpHeaderPath)."\n");
7266 # create TU dump
7267 my $TUdump = "-fdump-translation-unit -fkeep-inline-functions -c";
7268 if($C99Mode{$Version}==1
7269 or $MinGWMode{$Version}==1) {
7270 $TUdump .= " -fpreprocessed";
7271 }
7272 my $SyntaxTreeCmd = getCompileCmd($MHeaderPath, $TUdump, $IncludeString);
7273 writeLog($Version, "The GCC parameters:\n $SyntaxTreeCmd\n\n");
7274 chdir($TMP_DIR);
Andrey Ponomarenkoa01311b2012-06-08 17:20:02 +04007275 system($SyntaxTreeCmd." >\"$TMP_DIR/tu_errors\" 2>&1");
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007276 if($?)
7277 { # failed to compile, but the TU dump still can be created
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04007278 my $Errors = readFile($TMP_DIR."/tu_errors");
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007279 if($Errors=~/c99_/)
7280 { # disable c99 mode
7281 $C99Mode{$Version}=-1;
7282 printMsg("INFO", "Disabling C99 compatibility mode");
7283 resetLogging($Version);
7284 $TMP_DIR = tempdir(CLEANUP=>1);
7285 return getDump();
7286 }
7287 elsif($AutoPreambleMode{$Version}!=-1
7288 and my $TErrors = $Errors)
7289 {
7290 my %Types = ();
7291 while($TErrors=~s/error\:\s*(field\s*|)\W+(.+?)\W+//)
7292 { # error: 'FILE' has not been declared
7293 $Types{$2}=1;
7294 }
7295 my %AddHeaders = ();
7296 foreach my $Type (keys(%Types))
7297 {
7298 if(my $Header = $AutoPreamble{$Type}) {
7299 $AddHeaders{path_format($Header, $OSgroup)}=$Type;
7300 }
7301 }
7302 if(my @Headers = sort {$b cmp $a} keys(%AddHeaders))
7303 { # sys/types.h should be the first
7304 foreach my $Num (0 .. $#Headers)
7305 {
7306 my $Name = $Headers[$Num];
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04007307 if(my $Path = identifyHeader($Name, $Version))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007308 { # add automatic preamble headers
7309 if(defined $Include_Preamble{$Version}{$Path})
7310 { # already added
7311 next;
7312 }
7313 $Include_Preamble{$Version}{$Path}{"Position"} = keys(%{$Include_Preamble{$Version}});
7314 my $Type = $AddHeaders{$Name};
7315 printMsg("INFO", "Add \'$Name\' preamble header for \'$Type\'");
7316 }
7317 }
7318 $AutoPreambleMode{$Version}=-1;
7319 resetLogging($Version);
7320 $TMP_DIR = tempdir(CLEANUP=>1);
7321 return getDump();
7322 }
7323 }
7324 elsif($MinGWMode{$Version}!=-1)
7325 {
7326 $MinGWMode{$Version}=-1;
7327 resetLogging($Version);
7328 $TMP_DIR = tempdir(CLEANUP=>1);
7329 return getDump();
7330 }
7331 # FIXME: handle other errors and try to recompile
7332 writeLog($Version, $Errors);
7333 printMsg("ERROR", "some errors occurred when compiling headers");
7334 printErrorLog($Version);
7335 $COMPILE_ERRORS = $ERROR_CODE{"Compile_Error"};
7336 writeLog($Version, "\n");# new line
7337 }
7338 chdir($ORIG_DIR);
7339 unlink($TmpHeaderPath, $MHeaderPath);
7340 return (cmd_find($TMP_DIR,"f","*.tu",1))[0];
7341}
7342
7343sub cmd_file($)
7344{
7345 my $Path = $_[0];
7346 return "" if(not $Path or not -e $Path);
7347 if(my $CmdPath = get_CmdPath("file")) {
7348 return `$CmdPath -b \"$Path\"`;
7349 }
7350 return "";
7351}
7352
7353sub getIncString($$)
7354{
7355 my ($ArrRef, $Style) = @_;
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04007356 return "" if(not $ArrRef or $#{$ArrRef}<0);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007357 my $String = "";
7358 foreach (@{$ArrRef}) {
7359 $String .= " ".inc_opt($_, $Style);
7360 }
7361 return $String;
7362}
7363
7364sub getIncPaths(@)
7365{
7366 my @HeaderPaths = @_;
7367 my @IncPaths = ();
7368 if($INC_PATH_AUTODETECT{$Version})
7369 { # auto-detecting dependencies
7370 my %Includes = ();
7371 foreach my $HPath (@HeaderPaths)
7372 {
7373 foreach my $Dir (get_HeaderDeps($HPath, $Version))
7374 {
7375 if($Skip_Include_Paths{$Version}{$Dir}) {
7376 next;
7377 }
Andrey Ponomarenkoa01311b2012-06-08 17:20:02 +04007378 if($SystemRoot)
7379 {
7380 if($Skip_Include_Paths{$Version}{$SystemRoot.$Dir}) {
7381 next;
7382 }
7383 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007384 $Includes{$Dir}=1;
7385 }
7386 }
7387 foreach my $Dir (keys(%{$Add_Include_Paths{$Version}}))
7388 { # added by user
7389 next if($Includes{$Dir});
7390 push(@IncPaths, $Dir);
7391 }
7392 foreach my $Dir (@{sortIncPaths([keys(%Includes)], $Version)}) {
7393 push(@IncPaths, $Dir);
7394 }
7395 }
7396 else
7397 { # user-defined paths
7398 foreach my $Dir (sort {get_depth($a)<=>get_depth($b)}
7399 sort {$b cmp $a} keys(%{$Include_Paths{$Version}})) {
7400 push(@IncPaths, $Dir);
7401 }
7402 }
7403 return \@IncPaths;
7404}
7405
7406sub callPreprocessor($$$)
7407{
7408 my ($Path, $Inc, $LibVersion) = @_;
7409 return "" if(not $Path or not -f $Path);
7410 my $IncludeString=$Inc;
7411 if(not $Inc) {
7412 $IncludeString = getIncString(getIncPaths($Path), "GCC");
7413 }
7414 my $Cmd = getCompileCmd($Path, "-dD -E", $IncludeString);
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04007415 my $Out = $TMP_DIR."/preprocessed";
Andrey Ponomarenkoa01311b2012-06-08 17:20:02 +04007416 system($Cmd." >\"$Out\" 2>\"$TMP_DIR/null\"");
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04007417 return $Out;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007418}
7419
7420sub cmd_find($$$$)
7421{ # native "find" is much faster than File::Find (~6x)
7422 # also the File::Find doesn't support --maxdepth N option
7423 # so using the cross-platform wrapper for the native one
7424 my ($Path, $Type, $Name, $MaxDepth) = @_;
7425 return () if(not $Path or not -e $Path);
7426 if($OSgroup eq "windows")
7427 {
7428 my $DirCmd = get_CmdPath("dir");
7429 if(not $DirCmd) {
7430 exitStatus("Not_Found", "can't find \"dir\" command");
7431 }
7432 $Path=~s/[\\]+\Z//;
7433 $Path = get_abs_path($Path);
7434 $Path = path_format($Path, $OSgroup);
7435 my $Cmd = $DirCmd." \"$Path\" /B /O";
7436 if($MaxDepth!=1) {
7437 $Cmd .= " /S";
7438 }
7439 if($Type eq "d") {
7440 $Cmd .= " /AD";
7441 }
7442 my @Files = ();
7443 if($Name)
7444 { # FIXME: how to search file names in MS shell?
7445 $Name=~s/\*/.*/g if($Name!~/\]/);
7446 foreach my $File (split(/\n/, `$Cmd`))
7447 {
7448 if($File=~/$Name\Z/i) {
7449 push(@Files, $File);
7450 }
7451 }
7452 }
7453 else {
Andrey Ponomarenkoa01311b2012-06-08 17:20:02 +04007454 @Files = split(/\n/, `$Cmd 2>\"$TMP_DIR/null\"`);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007455 }
7456 my @AbsPaths = ();
7457 foreach my $File (@Files)
7458 {
7459 if(not is_abs($File)) {
7460 $File = joinPath($Path, $File);
7461 }
7462 if($Type eq "f" and not -f $File)
7463 { # skip dirs
7464 next;
7465 }
7466 push(@AbsPaths, path_format($File, $OSgroup));
7467 }
7468 if($Type eq "d") {
7469 push(@AbsPaths, $Path);
7470 }
7471 return @AbsPaths;
7472 }
7473 else
7474 {
7475 my $FindCmd = get_CmdPath("find");
7476 if(not $FindCmd) {
7477 exitStatus("Not_Found", "can't find a \"find\" command");
7478 }
7479 $Path = get_abs_path($Path);
7480 if(-d $Path and -l $Path
7481 and $Path!~/\/\Z/)
7482 { # for directories that are symlinks
7483 $Path.="/";
7484 }
7485 my $Cmd = $FindCmd." \"$Path\"";
7486 if($MaxDepth) {
7487 $Cmd .= " -maxdepth $MaxDepth";
7488 }
7489 if($Type) {
7490 $Cmd .= " -type $Type";
7491 }
7492 if($Name)
7493 { # file name
7494 if($Name=~/\]/) {
7495 $Cmd .= " -regex \"$Name\"";
7496 }
7497 else {
7498 $Cmd .= " -name \"$Name\"";
7499 }
7500 }
Andrey Ponomarenkoa01311b2012-06-08 17:20:02 +04007501 return split(/\n/, `$Cmd 2>\"$TMP_DIR/null\"`);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007502 }
7503}
7504
7505sub unpackDump($)
7506{
7507 my $Path = $_[0];
7508 return "" if(not $Path or not -e $Path);
7509 $Path = get_abs_path($Path);
7510 $Path = path_format($Path, $OSgroup);
7511 my ($Dir, $FileName) = separate_path($Path);
7512 my $UnpackDir = $TMP_DIR."/unpack";
7513 rmtree($UnpackDir);
7514 mkpath($UnpackDir);
7515 if($FileName=~s/\Q.zip\E\Z//g)
7516 { # *.zip
7517 my $UnzipCmd = get_CmdPath("unzip");
7518 if(not $UnzipCmd) {
7519 exitStatus("Not_Found", "can't find \"unzip\" command");
7520 }
7521 chdir($UnpackDir);
Andrey Ponomarenkoa01311b2012-06-08 17:20:02 +04007522 system("$UnzipCmd \"$Path\" >contents.txt");
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007523 if($?) {
7524 exitStatus("Error", "can't extract \'$Path\'");
7525 }
7526 chdir($ORIG_DIR);
7527 my @Contents = ();
7528 foreach (split("\n", readFile("$UnpackDir/contents.txt")))
7529 {
7530 if(/inflating:\s*([^\s]+)/) {
7531 push(@Contents, $1);
7532 }
7533 }
7534 if(not @Contents) {
7535 exitStatus("Error", "can't extract \'$Path\'");
7536 }
7537 return joinPath($UnpackDir, $Contents[0]);
7538 }
7539 elsif($FileName=~s/\Q.tar.gz\E\Z//g)
7540 { # *.tar.gz
7541 if($OSgroup eq "windows")
7542 { # -xvzf option is not implemented in tar.exe (2003)
7543 # use "gzip.exe -k -d -f" + "tar.exe -xvf" instead
7544 my $TarCmd = get_CmdPath("tar");
7545 if(not $TarCmd) {
7546 exitStatus("Not_Found", "can't find \"tar\" command");
7547 }
7548 my $GzipCmd = get_CmdPath("gzip");
7549 if(not $GzipCmd) {
7550 exitStatus("Not_Found", "can't find \"gzip\" command");
7551 }
7552 chdir($UnpackDir);
Andrey Ponomarenkoa01311b2012-06-08 17:20:02 +04007553 system("$GzipCmd -k -d -f \"$Path\""); # keep input files (-k)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007554 if($?) {
7555 exitStatus("Error", "can't extract \'$Path\'");
7556 }
Andrey Ponomarenkoa01311b2012-06-08 17:20:02 +04007557 system("$TarCmd -xvf \"$Dir\\$FileName.tar\" >contents.txt");
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007558 if($?) {
7559 exitStatus("Error", "can't extract \'$Path\'");
7560 }
7561 chdir($ORIG_DIR);
7562 unlink($Dir."/".$FileName.".tar");
7563 my @Contents = split("\n", readFile("$UnpackDir/contents.txt"));
7564 if(not @Contents) {
7565 exitStatus("Error", "can't extract \'$Path\'");
7566 }
7567 return joinPath($UnpackDir, $Contents[0]);
7568 }
7569 else
7570 { # Unix
7571 my $TarCmd = get_CmdPath("tar");
7572 if(not $TarCmd) {
7573 exitStatus("Not_Found", "can't find \"tar\" command");
7574 }
7575 chdir($UnpackDir);
Andrey Ponomarenkoa01311b2012-06-08 17:20:02 +04007576 system("$TarCmd -xvzf \"$Path\" >contents.txt");
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007577 if($?) {
7578 exitStatus("Error", "can't extract \'$Path\'");
7579 }
7580 chdir($ORIG_DIR);
7581 # The content file name may be different
7582 # from the package file name
7583 my @Contents = split("\n", readFile("$UnpackDir/contents.txt"));
7584 if(not @Contents) {
7585 exitStatus("Error", "can't extract \'$Path\'");
7586 }
7587 return joinPath($UnpackDir, $Contents[0]);
7588 }
7589 }
7590}
7591
7592sub createArchive($$)
7593{
7594 my ($Path, $To) = @_;
7595 if(not $Path or not -e $Path
7596 or not -d $To) {
7597 return "";
7598 }
7599 my ($From, $Name) = separate_path($Path);
7600 if($OSgroup eq "windows")
7601 { # *.zip
7602 my $ZipCmd = get_CmdPath("zip");
7603 if(not $ZipCmd) {
7604 exitStatus("Not_Found", "can't find \"zip\"");
7605 }
7606 my $Pkg = $To."/".$Name.".zip";
7607 unlink($Pkg);
7608 chdir($To);
Andrey Ponomarenkoa01311b2012-06-08 17:20:02 +04007609 system("$ZipCmd -j \"$Name.zip\" \"$Path\" >\"$TMP_DIR/null\"");
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007610 if($?)
7611 { # cannot allocate memory (or other problems with "zip")
7612 unlink($Path);
7613 exitStatus("Error", "can't pack the ABI dump: ".$!);
7614 }
7615 chdir($ORIG_DIR);
7616 unlink($Path);
7617 return $Pkg;
7618 }
7619 else
7620 { # *.tar.gz
7621 my $TarCmd = get_CmdPath("tar");
7622 if(not $TarCmd) {
7623 exitStatus("Not_Found", "can't find \"tar\"");
7624 }
7625 my $GzipCmd = get_CmdPath("gzip");
7626 if(not $GzipCmd) {
7627 exitStatus("Not_Found", "can't find \"gzip\"");
7628 }
7629 my $Pkg = abs_path($To)."/".$Name.".tar.gz";
7630 unlink($Pkg);
7631 chdir($From);
7632 system($TarCmd, "-czf", $Pkg, $Name);
7633 if($?)
7634 { # cannot allocate memory (or other problems with "tar")
7635 unlink($Path);
7636 exitStatus("Error", "can't pack the ABI dump: ".$!);
7637 }
7638 chdir($ORIG_DIR);
7639 unlink($Path);
7640 return $To."/".$Name.".tar.gz";
7641 }
7642}
7643
7644sub is_header_file($)
7645{
7646 if($_[0]=~/\.($HEADER_EXT)\Z/i) {
7647 return $_[0];
7648 }
7649 return 0;
7650}
7651
7652sub is_not_header($)
7653{
7654 if($_[0]=~/\.\w+\Z/
7655 and $_[0]!~/\.($HEADER_EXT)\Z/i) {
7656 return 1;
7657 }
7658 return 0;
7659}
7660
7661sub is_header($$$)
7662{
7663 my ($Header, $UserDefined, $LibVersion) = @_;
7664 return 0 if(-d $Header);
7665 if(-f $Header) {
7666 $Header = get_abs_path($Header);
7667 }
7668 else
7669 {
7670 if(is_abs($Header))
7671 { # incorrect absolute path
7672 return 0;
7673 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04007674 if(my $HPath = identifyHeader($Header, $LibVersion)) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007675 $Header = $HPath;
7676 }
7677 else
7678 { # can't find header
7679 return 0;
7680 }
7681 }
7682 if($Header=~/\.\w+\Z/)
7683 { # have an extension
7684 return is_header_file($Header);
7685 }
7686 else
7687 {
7688 if($UserDefined==2)
7689 { # specified on the command line
7690 if(cmd_file($Header)!~/HTML|XML/i) {
7691 return $Header;
7692 }
7693 }
7694 elsif($UserDefined)
7695 { # specified in the XML-descriptor
7696 # header file without an extension
7697 return $Header;
7698 }
7699 else
7700 {
Andrey Ponomarenko85043792012-05-14 16:48:07 +04007701 if($Header=~/\/include\//
7702 or cmd_file($Header)=~/C[\+]*\s+program/i)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007703 { # !~/HTML|XML|shared|dynamic/i
7704 return $Header;
7705 }
7706 }
7707 }
7708 return 0;
7709}
7710
Andrey Ponomarenko16934472012-03-29 15:37:04 +04007711sub addTargetHeaders($)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007712{
7713 my $LibVersion = $_[0];
7714 foreach my $RegHeader (keys(%{$Registered_Headers{$LibVersion}}))
7715 {
7716 my $RegDir = get_dirname($RegHeader);
7717 $TargetHeaders{$LibVersion}{get_filename($RegHeader)}=1;
7718 foreach my $RecInc (keys(%{$RecursiveIncludes{$LibVersion}{$RegHeader}}))
7719 {
7720 my $Dir = get_dirname($RecInc);
Andrey Ponomarenko85043792012-05-14 16:48:07 +04007721 if($Dir=~/\A\Q$RegDir\E([\/\\]|\Z)/
7722 or $RecursiveIncludes{$LibVersion}{$RegHeader}{$RecInc}!=1)
7723 { # in the same directory or included by #include "..."
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007724 $TargetHeaders{$LibVersion}{get_filename($RecInc)}=1;
7725 }
7726 }
7727 }
7728}
7729
7730sub readHeaders($)
7731{
7732 $Version = $_[0];
7733 printMsg("INFO", "checking header(s) ".$Descriptor{$Version}{"Version"}." ...");
7734 my $DumpPath = getDump();
7735 if(not $DumpPath) {
7736 exitStatus("Cannot_Compile", "can't compile header(s)");
7737 }
7738 if($Debug)
7739 { # debug mode
7740 mkpath($DEBUG_PATH{$Version});
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04007741 copy($DumpPath, $DEBUG_PATH{$Version}."/translation-unit-dump.txt");
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007742 }
7743 getInfo($DumpPath);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007744}
7745
7746sub prepareTypes($)
7747{
7748 my $LibVersion = $_[0];
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04007749 if(not checkDump($LibVersion, "2.0"))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007750 { # support for old ABI dumps
7751 # type names have been corrected in ACC 1.22 (dump 2.0 format)
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04007752 foreach my $TypeId (keys(%{$TypeInfo{$LibVersion}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007753 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04007754 my $TName = $TypeInfo{$LibVersion}{$TypeId}{"Name"};
7755 if($TName=~/\A(\w+)::(\w+)/) {
7756 my ($P1, $P2) = ($1, $2);
7757 if($P1 eq $P2) {
7758 $TName=~s/\A$P1:\:$P1(\W)/$P1$1/;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007759 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04007760 else {
7761 $TName=~s/\A(\w+:\:)$P2:\:$P2(\W)/$1$P2$2/;
7762 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007763 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04007764 $TypeInfo{$LibVersion}{$TypeId}{"Name"} = $TName;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007765 }
7766 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04007767 if(not checkDump($LibVersion, "2.5"))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007768 { # support for old ABI dumps
7769 # V < 2.5: array size == "number of elements"
7770 # V >= 2.5: array size in bytes
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04007771 foreach my $TypeId (sort {int($a)<=>int($b)} keys(%{$TypeInfo{$LibVersion}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007772 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04007773 my %Type = get_PureType($TypeId, $LibVersion);
7774 if($Type{"Type"} eq "Array")
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007775 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04007776 if($Type{"Size"})
7777 { # array[N]
7778 my %Base = get_OneStep_BaseType($Type{"Tid"}, $LibVersion);
7779 $TypeInfo{$LibVersion}{$TypeId}{"Size"} = $Type{"Size"}*$Base{"Size"};
7780 }
7781 else
7782 { # array[] is a pointer
7783 $TypeInfo{$LibVersion}{$TypeId}{"Size"} = $WORD_SIZE{$LibVersion};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007784 }
7785 }
7786 }
7787 }
7788 my $V2 = ($LibVersion==1)?2:1;
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04007789 if(not checkDump($LibVersion, "2.7"))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007790 { # support for old ABI dumps
7791 # size of "method ptr" corrected in 2.7
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04007792 foreach my $TypeId (sort {int($a)<=>int($b)} keys(%{$TypeInfo{$LibVersion}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007793 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04007794 my %PureType = get_PureType($TypeId, $LibVersion);
7795 if($PureType{"Type"} eq "MethodPtr")
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007796 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04007797 my %Type = get_Type($TypeId, $LibVersion);
7798 my $TypeId_2 = getTypeIdByName($PureType{"Name"}, $V2);
7799 my %Type2 = get_Type($TypeId_2, $V2);
7800 if($Type{"Size"} ne $Type2{"Size"}) {
7801 $TypeInfo{$LibVersion}{$TypeId}{"Size"} = $Type2{"Size"};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007802 }
7803 }
7804 }
7805 }
7806}
7807
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04007808sub prepareSymbols($)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007809{
7810 my $LibVersion = $_[0];
Andrey Ponomarenko16934472012-03-29 15:37:04 +04007811
7812 if(not keys(%{$SymbolInfo{$LibVersion}}))
7813 { # check if input is valid
7814 if(not $ExtendedCheck and not $CheckObjectsOnly)
7815 {
7816 if($CheckHeadersOnly) {
7817 exitStatus("Empty_Set", "the set of public symbols is empty (".$Descriptor{$LibVersion}{"Version"}.")");
7818 }
7819 else {
7820 exitStatus("Empty_Intersection", "the sets of public symbols in headers and libraries have empty intersection (".$Descriptor{$LibVersion}{"Version"}.")");
7821 }
7822 }
7823 }
7824
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007825 my $Remangle = 0;
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04007826 if(not checkDump(1, "2.10")
7827 or not checkDump(2, "2.10"))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007828 { # different formats
7829 $Remangle = 1;
7830 }
7831 if($CheckHeadersOnly)
7832 { # different languages
7833 if($UserLang)
7834 { # --lang=LANG for both versions
7835 if(($UsedDump{1}{"V"} and $UserLang ne $UsedDump{1}{"L"})
7836 or ($UsedDump{2}{"V"} and $UserLang ne $UsedDump{2}{"L"}))
7837 {
7838 if($UserLang eq "C++")
7839 { # remangle symbols
7840 $Remangle = 1;
7841 }
7842 elsif($UserLang eq "C")
7843 { # remove mangling
7844 $Remangle = -1;
7845 }
7846 }
7847 }
7848 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04007849
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04007850 foreach my $InfoId (sort {int($b)<=>int($a)} keys(%{$SymbolInfo{$LibVersion}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007851 { # reverse order: D0, D1, D2, D0 (artificial, GCC < 4.5), C1, C2
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04007852 if(not checkDump($LibVersion, "2.13"))
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04007853 { # support for old ABI dumps
7854 if(defined $SymbolInfo{$LibVersion}{$InfoId}{"Param"})
7855 {
7856 foreach my $P (keys(%{$SymbolInfo{$LibVersion}{$InfoId}{"Param"}}))
7857 {
7858 my $TypeId = $SymbolInfo{$LibVersion}{$InfoId}{"Param"}{$P}{"type"};
7859 my $DVal = $SymbolInfo{$LibVersion}{$InfoId}{"Param"}{$P}{"default"};
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04007860 my $TName = $TypeInfo{$LibVersion}{$TypeId}{"Name"};
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04007861 if(defined $DVal and $DVal ne "")
7862 {
7863 if($TName eq "char") {
7864 $SymbolInfo{$LibVersion}{$InfoId}{"Param"}{$P}{"default"} = chr($DVal);
7865 }
7866 elsif($TName eq "bool") {
7867 $SymbolInfo{$LibVersion}{$InfoId}{"Param"}{$P}{"default"} = $DVal?"true":"false";
7868 }
7869 }
7870 }
7871 }
7872 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04007873 if($SymbolInfo{$LibVersion}{$InfoId}{"Destructor"})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007874 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04007875 if(defined $SymbolInfo{$LibVersion}{$InfoId}{"Param"}
7876 and keys(%{$SymbolInfo{$LibVersion}{$InfoId}{"Param"}})
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04007877 and $SymbolInfo{$LibVersion}{$InfoId}{"Param"}{0}{"name"})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007878 { # support for old GCC < 4.5: skip artificial ~dtor(int __in_chrg)
7879 # + support for old ABI dumps
7880 next;
7881 }
7882 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04007883 my $MnglName = $SymbolInfo{$LibVersion}{$InfoId}{"MnglName"};
Andrey Ponomarenko85043792012-05-14 16:48:07 +04007884 my $ShortName = $SymbolInfo{$LibVersion}{$InfoId}{"ShortName"};
Andrey Ponomarenko16934472012-03-29 15:37:04 +04007885 my $ClassID = $SymbolInfo{$LibVersion}{$InfoId}{"Class"};
Andrey Ponomarenko85043792012-05-14 16:48:07 +04007886 my $Return = $SymbolInfo{$LibVersion}{$InfoId}{"Return"};
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04007887
7888 if(not $MnglName)
7889 { # ABI dumps have no mangled names for C-functions
Andrey Ponomarenko85043792012-05-14 16:48:07 +04007890 $MnglName = $ShortName;
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04007891 $SymbolInfo{$LibVersion}{$InfoId}{"MnglName"} = $MnglName;
7892 }
7893
Andrey Ponomarenko16934472012-03-29 15:37:04 +04007894 my $SRemangle = 0;
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04007895 if(not checkDump(1, "2.12")
7896 or not checkDump(2, "2.12"))
Andrey Ponomarenko16934472012-03-29 15:37:04 +04007897 { # support for old ABI dumps
Andrey Ponomarenko85043792012-05-14 16:48:07 +04007898 if($ShortName eq "operator>>")
7899 {
7900 if(not $SymbolInfo{$LibVersion}{$InfoId}{"Class"})
7901 { # corrected mangling of operator>>
7902 $SRemangle = 1;
7903 }
Andrey Ponomarenko16934472012-03-29 15:37:04 +04007904 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +04007905 if($SymbolInfo{$LibVersion}{$InfoId}{"Data"})
7906 {
7907 if(not $SymbolInfo{$LibVersion}{$InfoId}{"Class"}
7908 and isConstType($Return, $LibVersion) and $MnglName!~/L\d+$ShortName/)
7909 { # corrected mangling of const global data
7910 # some global data is not mangled in the TU dump: qt_sine_table (Qt 4.8)
7911 # and incorrectly mangled by old ACC versions
7912 $SRemangle = 1;
7913 }
Andrey Ponomarenko16934472012-03-29 15:37:04 +04007914 }
7915 }
7916 if($Remangle==1 or $SRemangle==1)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007917 { # support for old ABI dumps: some symbols are not mangled in old dumps
7918 # mangle both sets of symbols (old and new)
7919 # NOTE: remangling all symbols by the same mangler
7920 if($MnglName=~/\A_ZN(V|)K/)
7921 { # mangling may be incorrect on old ABI dumps
7922 # because of absent "Const" attribute
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04007923 $SymbolInfo{$LibVersion}{$InfoId}{"Const"} = 1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007924 }
7925 if($MnglName=~/\A_ZN(K|)V/)
7926 { # mangling may be incorrect on old ABI dumps
7927 # because of absent "Volatile" attribute
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04007928 $SymbolInfo{$LibVersion}{$InfoId}{"Volatile"} = 1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007929 }
Andrey Ponomarenko16934472012-03-29 15:37:04 +04007930 if(($ClassID and $MnglName!~/\A(_Z|\?)/)
7931 or (not $ClassID and $CheckHeadersOnly)
7932 or (not $ClassID and not link_symbol($MnglName, $LibVersion, "-Deps")))
7933 { # support for old ABI dumps, GCC >= 4.0
7934 # remangling all manually mangled symbols
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04007935 if($MnglName = mangle_symbol($InfoId, $LibVersion, "GCC"))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007936 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04007937 $SymbolInfo{$LibVersion}{$InfoId}{"MnglName"} = $MnglName;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007938 $MangledNames{$LibVersion}{$MnglName} = 1;
7939 }
7940 }
7941 }
7942 elsif($Remangle==-1)
7943 { # remove mangling
7944 $MnglName = "";
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04007945 $SymbolInfo{$LibVersion}{$InfoId}{"MnglName"} = "";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007946 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007947 if(not $MnglName) {
7948 next;
7949 }
7950 if(not $CompleteSignature{$LibVersion}{$MnglName}{"MnglName"})
7951 { # NOTE: global data may enter here twice
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04007952 %{$CompleteSignature{$LibVersion}{$MnglName}} = %{$SymbolInfo{$LibVersion}{$InfoId}};
7953
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007954 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04007955 if(not checkDump($LibVersion, "2.6"))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007956 { # support for old dumps
7957 # add "Volatile" attribute
7958 if($MnglName=~/_Z(K|)V/) {
7959 $CompleteSignature{$LibVersion}{$MnglName}{"Volatile"}=1;
7960 }
7961 }
7962 # symbol and its symlink have same signatures
7963 if($SymVer{$LibVersion}{$MnglName}) {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04007964 %{$CompleteSignature{$LibVersion}{$SymVer{$LibVersion}{$MnglName}}} = %{$SymbolInfo{$LibVersion}{$InfoId}};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007965 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +04007966
7967 # clean memory
Andrey Ponomarenko16934472012-03-29 15:37:04 +04007968 delete($SymbolInfo{$LibVersion}{$InfoId});
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007969 }
7970 if($COMMON_LANGUAGE{$LibVersion} eq "C++" or $OSgroup eq "windows") {
7971 translateSymbols(keys(%{$CompleteSignature{$LibVersion}}), $LibVersion);
7972 }
7973 if($ExtendedCheck)
7974 { # --ext option
7975 addExtension($LibVersion);
7976 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +04007977
7978 # clean memory
7979 delete($SymbolInfo{$LibVersion});
7980
7981 foreach my $Symbol (keys(%{$CompleteSignature{$LibVersion}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007982 { # detect allocable classes with public exported constructors
7983 # or classes with auto-generated or inline-only constructors
Andrey Ponomarenko85043792012-05-14 16:48:07 +04007984 if(my $ClassId = $CompleteSignature{$LibVersion}{$Symbol}{"Class"})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007985 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04007986 my $ClassName = $TypeInfo{$LibVersion}{$ClassId}{"Name"};
Andrey Ponomarenko85043792012-05-14 16:48:07 +04007987 if($CompleteSignature{$LibVersion}{$Symbol}{"Constructor"}
7988 and not $CompleteSignature{$LibVersion}{$Symbol}{"InLine"})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007989 { # Class() { ... } will not be exported
Andrey Ponomarenko85043792012-05-14 16:48:07 +04007990 if(not $CompleteSignature{$LibVersion}{$Symbol}{"Private"})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007991 {
Andrey Ponomarenko85043792012-05-14 16:48:07 +04007992 if($CheckHeadersOnly or link_symbol($Symbol, $LibVersion, "-Deps")) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007993 $AllocableClass{$LibVersion}{$ClassName} = 1;
7994 }
7995 }
7996 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +04007997 if(not $CompleteSignature{$LibVersion}{$Symbol}{"Private"})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007998 { # all imported class methods
Andrey Ponomarenko85043792012-05-14 16:48:07 +04007999 if(symbolFilter($Symbol, $LibVersion, "Affected", "Binary"))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008000 {
Andrey Ponomarenko85043792012-05-14 16:48:07 +04008001 if($CheckHeadersOnly)
8002 {
8003 if(not $CompleteSignature{$LibVersion}{$Symbol}{"InLine"}
8004 or $CompleteSignature{$LibVersion}{$Symbol}{"Virt"})
8005 { # all symbols except non-virtual inline
8006 $ClassMethods{"Binary"}{$LibVersion}{$ClassName}{$Symbol} = 1;
8007 }
8008 }
8009 else {
8010 $ClassMethods{"Binary"}{$LibVersion}{$ClassName}{$Symbol} = 1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008011 }
8012 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04008013 if(symbolFilter($Symbol, $LibVersion, "Affected", "Source")) {
Andrey Ponomarenko85043792012-05-14 16:48:07 +04008014 $ClassMethods{"Source"}{$LibVersion}{$ClassName}{$Symbol} = 1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008015 }
8016 }
Andrey Ponomarenko16934472012-03-29 15:37:04 +04008017 $ClassNames{$LibVersion}{$ClassName} = 1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008018 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +04008019 if(my $RetId = $CompleteSignature{$LibVersion}{$Symbol}{"Return"})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008020 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04008021 my %Base = get_BaseType($RetId, $LibVersion);
Andrey Ponomarenko85043792012-05-14 16:48:07 +04008022 if(defined $Base{"Type"}
8023 and $Base{"Type"}=~/Struct|Class/)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008024 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04008025 my $Name = $TypeInfo{$LibVersion}{$Base{"Tid"}}{"Name"};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008026 if($Name=~/<([^<>\s]+)>/)
8027 {
8028 if(my $Tid = getTypeIdByName($1, $LibVersion)) {
8029 $ReturnedClass{$LibVersion}{$Tid} = 1;
8030 }
8031 }
8032 else {
8033 $ReturnedClass{$LibVersion}{$Base{"Tid"}} = 1;
8034 }
8035 }
8036 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +04008037 foreach my $Num (keys(%{$CompleteSignature{$LibVersion}{$Symbol}{"Param"}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008038 {
Andrey Ponomarenko85043792012-05-14 16:48:07 +04008039 my $PId = $CompleteSignature{$LibVersion}{$Symbol}{"Param"}{$Num}{"type"};
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04008040 if(get_PLevel($PId, $LibVersion)>=1)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008041 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04008042 if(my %Base = get_BaseType($PId, $LibVersion))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008043 {
Andrey Ponomarenko16934472012-03-29 15:37:04 +04008044 if($Base{"Type"}=~/Struct|Class/)
8045 {
Andrey Ponomarenko85043792012-05-14 16:48:07 +04008046 $ParamClass{$LibVersion}{$Base{"Tid"}}{$Symbol} = 1;
Andrey Ponomarenko16934472012-03-29 15:37:04 +04008047 foreach my $SubId (get_sub_classes($Base{"Tid"}, $LibVersion, 1))
8048 { # mark all derived classes
Andrey Ponomarenko85043792012-05-14 16:48:07 +04008049 $ParamClass{$LibVersion}{$SubId}{$Symbol} = 1;
Andrey Ponomarenko16934472012-03-29 15:37:04 +04008050 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008051 }
8052 }
8053 }
8054 }
8055 }
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04008056 foreach my $MnglName (keys(%VTableClass))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008057 { # reconstruct header name for v-tables
8058 if($MnglName=~/\A_ZTV/)
8059 {
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04008060 if(my $ClassName = $VTableClass{$MnglName})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008061 {
8062 if(my $ClassId = $TName_Tid{$LibVersion}{$ClassName}) {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04008063 $CompleteSignature{$LibVersion}{$MnglName}{"Header"} = $TypeInfo{$LibVersion}{$ClassId}{"Header"};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008064 }
8065 }
8066 }
8067 }
Andrey Ponomarenko16934472012-03-29 15:37:04 +04008068
8069 # types
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04008070 foreach my $TypeId (keys(%{$TypeInfo{$LibVersion}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008071 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04008072 if(my $TName = $TypeInfo{$LibVersion}{$TypeId}{"Name"})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008073 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04008074 if(defined $TypeInfo{$LibVersion}{$TypeId}{"VTable"}) {
8075 $ClassNames{$LibVersion}{$TName} = 1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008076 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04008077 if(defined $TypeInfo{$LibVersion}{$TypeId}{"Base"})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008078 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04008079 $ClassNames{$LibVersion}{$TName} = 1;
8080 foreach my $Bid (keys(%{$TypeInfo{$LibVersion}{$TypeId}{"Base"}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008081 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04008082 if(my $BName = $TypeInfo{$LibVersion}{$Bid}{"Name"}) {
8083 $ClassNames{$LibVersion}{$BName} = 1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008084 }
8085 }
8086 }
8087 }
8088 }
8089}
8090
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04008091sub register_TypeUsage($$)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008092{
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04008093 my ($TypeId, $LibVersion) = @_;
8094 if(not $TypeId) {
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04008095 return 0;
8096 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04008097 if($UsedType{$LibVersion}{$TypeId})
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04008098 { # already registered
8099 return 1;
8100 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04008101 my %TInfo = get_Type($TypeId, $LibVersion);
Andrey Ponomarenko85043792012-05-14 16:48:07 +04008102 if($TInfo{"Type"})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008103 {
Andrey Ponomarenko85043792012-05-14 16:48:07 +04008104 if($TInfo{"Type"}=~/\A(Struct|Union|Class|FuncPtr|MethodPtr|FieldPtr|Enum)\Z/)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008105 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04008106 $UsedType{$LibVersion}{$TypeId} = 1;
Andrey Ponomarenko85043792012-05-14 16:48:07 +04008107 if($TInfo{"Type"}=~/\A(Struct|Class)\Z/)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008108 {
Andrey Ponomarenko85043792012-05-14 16:48:07 +04008109 foreach my $BaseId (keys(%{$TInfo{"Base"}}))
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04008110 { # register base classes
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04008111 register_TypeUsage($BaseId, $LibVersion);
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04008112 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +04008113 foreach my $TPos (keys(%{$TInfo{"TParam"}}))
8114 {
8115 my $TPName = $TInfo{"TParam"}{$TPos}{"name"};
8116 if(my $TTid = $TName_Tid{$LibVersion}{$TPName}) {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04008117 register_TypeUsage($TTid, $LibVersion);
Andrey Ponomarenko85043792012-05-14 16:48:07 +04008118 }
8119 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008120 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +04008121 foreach my $Memb_Pos (keys(%{$TInfo{"Memb"}}))
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04008122 {
Andrey Ponomarenko85043792012-05-14 16:48:07 +04008123 if(my $MTid = $TInfo{"Memb"}{$Memb_Pos}{"type"}) {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04008124 register_TypeUsage($MTid, $LibVersion);
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04008125 }
8126 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +04008127 if($TInfo{"Type"} eq "FuncPtr"
8128 or $TInfo{"Type"} eq "MethodPtr")
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04008129 {
Andrey Ponomarenko85043792012-05-14 16:48:07 +04008130 if(my $RTid = $TInfo{"Return"}) {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04008131 register_TypeUsage($RTid, $LibVersion);
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04008132 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +04008133 foreach my $Memb_Pos (keys(%{$TInfo{"Param"}}))
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04008134 {
Andrey Ponomarenko85043792012-05-14 16:48:07 +04008135 if(my $MTid = $TInfo{"Param"}{$Memb_Pos}{"type"}) {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04008136 register_TypeUsage($MTid, $LibVersion);
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04008137 }
8138 }
8139 }
8140 return 1;
8141 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +04008142 elsif($TInfo{"Type"}=~/\A(Const|ConstVolatile|Volatile|Pointer|Ref|Restrict|Array|Typedef)\Z/)
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04008143 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04008144 $UsedType{$LibVersion}{$TypeId} = 1;
8145 register_TypeUsage($TInfo{"BaseType"}{"Tid"}, $LibVersion);
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04008146 return 1;
8147 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04008148 elsif($TInfo{"Type"} eq "Intrinsic")
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04008149 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04008150 $UsedType{$LibVersion}{$TypeId} = 1;
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04008151 return 1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008152 }
8153 }
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04008154 return 0;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008155}
8156
Andrey Ponomarenko85043792012-05-14 16:48:07 +04008157sub selectSymbol($$$$)
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04008158{
Andrey Ponomarenko85043792012-05-14 16:48:07 +04008159 my ($Symbol, $SInfo, $Level, $LibVersion) = @_;
8160
8161 if(not $STDCXX_TESTING and $Symbol=~/\A(_ZS|_ZNS|_ZNKS)/)
8162 { # stdc++ interfaces
8163 return 0;
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04008164 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +04008165
8166 my $Target = 0;
8167 if(my $Header = $SInfo->{"Header"}) {
8168 $Target = (is_target_header($Header, 1) or is_target_header($Header, 2));
8169 }
8170 if($CheckHeadersOnly)
8171 {
8172 if($Target)
8173 {
8174 if($Level eq "Dump")
8175 { # dumped
8176 if($BinaryOnly)
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04008177 {
Andrey Ponomarenko85043792012-05-14 16:48:07 +04008178 if(not $SInfo->{"InLine"} or $SInfo->{"Data"}) {
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04008179 return 1;
8180 }
8181 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +04008182 else {
8183 return 1;
8184 }
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04008185 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +04008186 elsif($Level eq "Source")
8187 { # checked
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04008188 return 1;
8189 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +04008190 elsif($Level eq "Binary")
8191 { # checked
8192 if(not $SInfo->{"InLine"} or $SInfo->{"Data"}
8193 or $SInfo->{"Virt"} or $SInfo->{"PureVirt"}) {
8194 return 1;
8195 }
8196 }
8197 }
8198 }
8199 else
8200 { # library is available
8201 if(link_symbol($Symbol, $LibVersion, "-Deps"))
8202 { # exported symbols
8203 return 1;
8204 }
8205 if($Level eq "Dump")
8206 { # dumped
8207 if(not $BinaryOnly)
8208 { # SrcBin
8209 if($Target) {
8210 return 1;
8211 }
8212 }
8213 if($SInfo->{"Data"})
8214 {
8215 if($Target) {
8216 return 1;
8217 }
8218 }
8219 }
8220 elsif($Level eq "Source")
8221 { # checked
8222 if($Target) {
8223 return 1;
8224 }
8225 }
8226 elsif($Level eq "Binary")
8227 { # checked
8228 if($SInfo->{"PureVirt"} or $SInfo->{"Data"})
8229 {
8230 if($Target) {
8231 return 1;
8232 }
8233 }
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04008234 }
8235 }
8236 return 0;
8237}
8238
Andrey Ponomarenko85043792012-05-14 16:48:07 +04008239sub cleanDump($)
8240{ # clean data
Andrey Ponomarenko16934472012-03-29 15:37:04 +04008241 my $LibVersion = $_[0];
8242 foreach my $InfoId (keys(%{$SymbolInfo{$LibVersion}}))
8243 {
8244 my $MnglName = $SymbolInfo{$LibVersion}{$InfoId}{"MnglName"};
8245 if(not $MnglName) {
8246 delete($SymbolInfo{$LibVersion}{$InfoId});
8247 next;
8248 }
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04008249 my $ShortName = $SymbolInfo{$LibVersion}{$InfoId}{"ShortName"};
Andrey Ponomarenko85043792012-05-14 16:48:07 +04008250 if(not $ShortName) {
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04008251 delete($SymbolInfo{$LibVersion}{$InfoId});
8252 next;
Andrey Ponomarenko16934472012-03-29 15:37:04 +04008253 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +04008254 if($MnglName eq $ShortName)
8255 { # remove duplicate data
8256 delete($SymbolInfo{$LibVersion}{$InfoId}{"MnglName"});
Andrey Ponomarenko16934472012-03-29 15:37:04 +04008257 }
8258 if(not keys(%{$SymbolInfo{$LibVersion}{$InfoId}{"Param"}})) {
8259 delete($SymbolInfo{$LibVersion}{$InfoId}{"Param"});
8260 }
8261 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04008262 foreach my $Tid (keys(%{$TypeInfo{$LibVersion}}))
Andrey Ponomarenko85043792012-05-14 16:48:07 +04008263 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04008264 foreach my $Attr ("Header", "Line", "Size", "NameSpace")
Andrey Ponomarenko16934472012-03-29 15:37:04 +04008265 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04008266 if(not $TypeInfo{$LibVersion}{$Tid}{$Attr}) {
8267 delete($TypeInfo{$LibVersion}{$Tid}{$Attr});
8268 }
8269 }
8270 }
8271}
8272
8273sub selectType($$)
8274{
8275 my ($Tid, $LibVersion) = @_;
8276 if(my $THeader = $TypeInfo{$LibVersion}{$Tid}{"Header"})
8277 {
8278 if(not isBuiltIn($THeader))
8279 {
8280 if($TypeInfo{$LibVersion}{$Tid}{"Type"}=~/Class|Struct|Union|Enum|Typedef/)
Andrey Ponomarenko16934472012-03-29 15:37:04 +04008281 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04008282 if(not isAnon($TypeInfo{$LibVersion}{$Tid}{"Name"}))
8283 {
8284 if(is_target_header($THeader, $LibVersion))
8285 { # from target headers
8286 if(not selfTypedef($Tid, $LibVersion)) {
8287 return 1;
8288 }
8289 }
Andrey Ponomarenko16934472012-03-29 15:37:04 +04008290 }
8291 }
8292 }
8293 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04008294 return 0;
Andrey Ponomarenko16934472012-03-29 15:37:04 +04008295}
8296
Andrey Ponomarenko85043792012-05-14 16:48:07 +04008297sub removeUnused($$)
8298{ # remove unused data types from the ABI dump
8299 my ($LibVersion, $Kind) = @_;
8300 foreach my $InfoId (keys(%{$SymbolInfo{$LibVersion}}))
8301 {
8302 my %FuncInfo = %{$SymbolInfo{$LibVersion}{$InfoId}};
8303 if(my $RTid = $FuncInfo{"Return"}) {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04008304 register_TypeUsage($RTid, $LibVersion);
Andrey Ponomarenko85043792012-05-14 16:48:07 +04008305 }
8306 if(my $FCid = $FuncInfo{"Class"})
8307 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04008308 register_TypeUsage($FCid, $LibVersion);
8309 if(my $ThisId = getTypeIdByName($TypeInfo{$LibVersion}{$FCid}{"Name"}."*const", $LibVersion))
Andrey Ponomarenko85043792012-05-14 16:48:07 +04008310 { # register "this" pointer
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04008311 $UsedType{$LibVersion}{$ThisId} = 1;
8312 if(my %ThisType = get_Type($ThisId, $LibVersion)) {
8313 register_TypeUsage($ThisType{"BaseType"}{"Tid"}, $LibVersion);
Andrey Ponomarenko85043792012-05-14 16:48:07 +04008314 }
8315 }
8316 }
8317 foreach my $PPos (keys(%{$FuncInfo{"Param"}}))
8318 {
8319 if(my $PTid = $FuncInfo{"Param"}{$PPos}{"type"}) {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04008320 register_TypeUsage($PTid, $LibVersion);
Andrey Ponomarenko85043792012-05-14 16:48:07 +04008321 }
8322 }
8323 foreach my $TPos (keys(%{$FuncInfo{"TParam"}}))
8324 {
8325 my $TPName = $FuncInfo{"TParam"}{$TPos}{"name"};
8326 if(my $TTid = $TName_Tid{$LibVersion}{$TPName}) {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04008327 register_TypeUsage($TTid, $LibVersion);
Andrey Ponomarenko85043792012-05-14 16:48:07 +04008328 }
8329 }
8330 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04008331 foreach my $Tid (keys(%{$TypeInfo{$LibVersion}}))
8332 {
8333 if($UsedType{$LibVersion}{$Tid})
8334 { # All & Derived
8335 next;
8336 }
8337
8338 if($Kind eq "Derived")
Andrey Ponomarenko85043792012-05-14 16:48:07 +04008339 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04008340 if(selectType($Tid, $LibVersion)) {
8341 register_TypeUsage($Tid, $LibVersion);
Andrey Ponomarenko85043792012-05-14 16:48:07 +04008342 }
8343 }
8344 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04008345 foreach my $Tid (keys(%{$TypeInfo{$LibVersion}}))
8346 { # remove unused types
8347 if($UsedType{$LibVersion}{$Tid})
8348 { # All & Derived
8349 next;
8350 }
8351 # remove type
8352 delete($TypeInfo{$LibVersion}{$Tid});
8353 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +04008354
8355 # clean memory
8356 %UsedType = ();
8357}
8358
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04008359sub selfTypedef($$)
Andrey Ponomarenko85043792012-05-14 16:48:07 +04008360{
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04008361 my ($TypeId, $LibVersion) = @_;
8362 my %Type = get_Type($TypeId, $LibVersion);
Andrey Ponomarenko85043792012-05-14 16:48:07 +04008363 if($Type{"Type"} eq "Typedef")
8364 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04008365 my %Base = get_OneStep_BaseType($TypeId, $LibVersion);
Andrey Ponomarenko85043792012-05-14 16:48:07 +04008366 if($Base{"Type"}=~/Class|Struct/)
8367 {
8368 if($Type{"Name"} eq $Base{"Name"}) {
8369 return 1;
8370 }
8371 elsif($Type{"Name"}=~/::(\w+)\Z/)
8372 {
8373 if($Type{"Name"} eq $Base{"Name"}."::".$1)
8374 { # QPointer<QWidget>::QPointer
8375 return 1;
8376 }
8377 }
8378 }
8379 }
8380 return 0;
8381}
8382
Andrey Ponomarenko16934472012-03-29 15:37:04 +04008383sub addExtension($)
8384{
8385 my $LibVersion = $_[0];
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04008386 foreach my $Tid (keys(%{$TypeInfo{$LibVersion}}))
Andrey Ponomarenko16934472012-03-29 15:37:04 +04008387 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04008388 if(selectType($Tid, $LibVersion))
Andrey Ponomarenko16934472012-03-29 15:37:04 +04008389 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04008390 my $Symbol = "external_func_".$TypeInfo{$LibVersion}{$Tid}{"Name"};
8391
8392 %{$CompleteSignature{$LibVersion}{$Symbol}} = (
8393 "Header" => "extended.h",
8394 "ShortName" => $Symbol,
8395 "MnglName" => $Symbol,
8396 "Param" => { 0 => { "type"=>$Tid, "name"=>"p1" } }
8397 );
8398
8399 $ExtendedSymbols{$Symbol}=1;
8400 $CheckedSymbols{"Binary"}{$Symbol}=1;
8401 $CheckedSymbols{"Source"}{$Symbol}=1;
Andrey Ponomarenko16934472012-03-29 15:37:04 +04008402 }
8403 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04008404 $ExtendedSymbols{"external_func_0"}=1;
8405 $CheckedSymbols{"Binary"}{"external_func_0"}=1;
8406 $CheckedSymbols{"Source"}{"external_func_0"}=1;
Andrey Ponomarenko16934472012-03-29 15:37:04 +04008407}
8408
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008409sub findMethod($$$)
8410{
8411 my ($VirtFunc, $ClassId, $LibVersion) = @_;
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04008412 foreach my $BaseClass_Id (keys(%{$TypeInfo{$LibVersion}{$ClassId}{"Base"}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008413 {
8414 if(my $VirtMethodInClass = findMethod_Class($VirtFunc, $BaseClass_Id, $LibVersion)) {
8415 return $VirtMethodInClass;
8416 }
8417 elsif(my $VirtMethodInBaseClasses = findMethod($VirtFunc, $BaseClass_Id, $LibVersion)) {
8418 return $VirtMethodInBaseClasses;
8419 }
8420 }
8421 return "";
8422}
8423
8424sub findMethod_Class($$$)
8425{
8426 my ($VirtFunc, $ClassId, $LibVersion) = @_;
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04008427 my $ClassName = $TypeInfo{$LibVersion}{$ClassId}{"Name"};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008428 return "" if(not defined $VirtualTable{$LibVersion}{$ClassName});
8429 my $TargetSuffix = get_symbol_suffix($VirtFunc, 1);
8430 my $TargetShortName = $CompleteSignature{$LibVersion}{$VirtFunc}{"ShortName"};
8431 foreach my $Candidate (keys(%{$VirtualTable{$LibVersion}{$ClassName}}))
8432 { # search for interface with the same parameters suffix (overridden)
8433 if($TargetSuffix eq get_symbol_suffix($Candidate, 1))
8434 {
8435 if($CompleteSignature{$LibVersion}{$VirtFunc}{"Destructor"}) {
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04008436 if($CompleteSignature{$LibVersion}{$Candidate}{"Destructor"})
8437 {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008438 if(($VirtFunc=~/D0E/ and $Candidate=~/D0E/)
8439 or ($VirtFunc=~/D1E/ and $Candidate=~/D1E/)
8440 or ($VirtFunc=~/D2E/ and $Candidate=~/D2E/)) {
8441 return $Candidate;
8442 }
8443 }
8444 }
8445 else {
8446 if($TargetShortName eq $CompleteSignature{$LibVersion}{$Candidate}{"ShortName"}) {
8447 return $Candidate;
8448 }
8449 }
8450 }
8451 }
8452 return "";
8453}
8454
Andrey Ponomarenko16934472012-03-29 15:37:04 +04008455sub registerVTable($)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008456{
Andrey Ponomarenko16934472012-03-29 15:37:04 +04008457 my $LibVersion = $_[0];
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04008458 foreach my $Symbol (keys(%{$CompleteSignature{$LibVersion}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008459 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04008460 if($CompleteSignature{$LibVersion}{$Symbol}{"Virt"}
8461 or $CompleteSignature{$LibVersion}{$Symbol}{"PureVirt"})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008462 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04008463 my $ClassName = $TypeInfo{$LibVersion}{$CompleteSignature{$LibVersion}{$Symbol}{"Class"}}{"Name"};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008464 next if(not $STDCXX_TESTING and $ClassName=~/\A(std::|__cxxabi)/);
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04008465 if($CompleteSignature{$LibVersion}{$Symbol}{"Destructor"}
8466 and $Symbol=~/D2E/)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008467 { # pure virtual D2-destructors are marked as "virt" in the dump
8468 # virtual D2-destructors are NOT marked as "virt" in the dump
8469 # both destructors are not presented in the v-table
8470 next;
8471 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04008472 my ($MnglName, $VersionSpec, $SymbolVersion) = separate_symbol($Symbol);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008473 $VirtualTable{$LibVersion}{$ClassName}{$MnglName} = 1;
8474 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008475 }
8476}
8477
8478sub registerOverriding($)
8479{
8480 my $LibVersion = $_[0];
8481 my @Classes = keys(%{$VirtualTable{$LibVersion}});
Andrey Ponomarenko85043792012-05-14 16:48:07 +04008482 @Classes = sort {int($TName_Tid{$LibVersion}{$a})<=>int($TName_Tid{$LibVersion}{$b})} @Classes;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008483 foreach my $ClassName (@Classes)
8484 {
8485 foreach my $VirtFunc (keys(%{$VirtualTable{$LibVersion}{$ClassName}}))
8486 {
Andrey Ponomarenko16934472012-03-29 15:37:04 +04008487 if($CompleteSignature{$LibVersion}{$VirtFunc}{"PureVirt"})
8488 { # pure virtuals
8489 next;
8490 }
8491 my $ClassId = $TName_Tid{$LibVersion}{$ClassName};
8492 if(my $Overridden = findMethod($VirtFunc, $ClassId, $LibVersion))
Andrey Ponomarenko85043792012-05-14 16:48:07 +04008493 {
8494 if($CompleteSignature{$LibVersion}{$Overridden}{"Virt"}
8495 or $CompleteSignature{$LibVersion}{$Overridden}{"PureVirt"})
8496 { # both overridden virtual methods
8497 # and implemented pure virtual methods
8498 $CompleteSignature{$LibVersion}{$VirtFunc}{"Override"} = $Overridden;
8499 $OverriddenMethods{$LibVersion}{$Overridden}{$VirtFunc} = 1;
8500 delete($VirtualTable{$LibVersion}{$ClassName}{$VirtFunc}); # remove from v-table model
8501 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008502 }
8503 }
8504 if(not keys(%{$VirtualTable{$LibVersion}{$ClassName}})) {
8505 delete($VirtualTable{$LibVersion}{$ClassName});
8506 }
8507 }
8508}
8509
8510sub setVirtFuncPositions($)
8511{
8512 my $LibVersion = $_[0];
8513 foreach my $ClassName (keys(%{$VirtualTable{$LibVersion}}))
8514 {
8515 my ($Num, $RelPos, $AbsNum) = (1, 0, 1);
8516 foreach my $VirtFunc (sort {int($CompleteSignature{$LibVersion}{$a}{"Line"}) <=> int($CompleteSignature{$LibVersion}{$b}{"Line"})}
8517 sort keys(%{$VirtualTable{$LibVersion}{$ClassName}}))
8518 {
Andrey Ponomarenko16934472012-03-29 15:37:04 +04008519 $VirtualTable{$LibVersion}{$ClassName}{$VirtFunc}=$Num++;
8520
8521 # set relative positions
8522 if(defined $VirtualTable{1}{$ClassName} and defined $VirtualTable{1}{$ClassName}{$VirtFunc}
8523 and defined $VirtualTable{2}{$ClassName} and defined $VirtualTable{2}{$ClassName}{$VirtFunc})
8524 { # relative position excluding added and removed virtual functions
8525 if(not $CompleteSignature{1}{$VirtFunc}{"Override"}
8526 and not $CompleteSignature{2}{$VirtFunc}{"Override"}) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008527 $CompleteSignature{$LibVersion}{$VirtFunc}{"RelPos"} = $RelPos++;
8528 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008529 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008530 }
8531 }
Andrey Ponomarenko16934472012-03-29 15:37:04 +04008532 foreach my $ClassName (keys(%{$ClassNames{$LibVersion}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008533 {
8534 my $AbsNum = 1;
Andrey Ponomarenko16934472012-03-29 15:37:04 +04008535 foreach my $VirtFunc (getVTable_Model($TName_Tid{$LibVersion}{$ClassName}, $LibVersion)) {
8536 $VirtualTable_Model{$LibVersion}{$ClassName}{$VirtFunc}=$AbsNum++;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008537 }
8538 }
8539}
8540
8541sub get_sub_classes($$$)
8542{
8543 my ($ClassId, $LibVersion, $Recursive) = @_;
8544 return () if(not defined $Class_SubClasses{$LibVersion}{$ClassId});
8545 my @Subs = ();
8546 foreach my $SubId (keys(%{$Class_SubClasses{$LibVersion}{$ClassId}}))
8547 {
Andrey Ponomarenko16934472012-03-29 15:37:04 +04008548 if($Recursive)
8549 {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008550 foreach my $SubSubId (get_sub_classes($SubId, $LibVersion, $Recursive)) {
8551 push(@Subs, $SubSubId);
8552 }
8553 }
8554 push(@Subs, $SubId);
8555 }
8556 return @Subs;
8557}
8558
8559sub get_base_classes($$$)
8560{
8561 my ($ClassId, $LibVersion, $Recursive) = @_;
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04008562 my %ClassType = get_Type($ClassId, $LibVersion);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008563 return () if(not defined $ClassType{"Base"});
8564 my @Bases = ();
8565 foreach my $BaseId (sort {int($ClassType{"Base"}{$a}{"pos"})<=>int($ClassType{"Base"}{$b}{"pos"})}
8566 keys(%{$ClassType{"Base"}}))
8567 {
Andrey Ponomarenko16934472012-03-29 15:37:04 +04008568 if($Recursive)
8569 {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008570 foreach my $SubBaseId (get_base_classes($BaseId, $LibVersion, $Recursive)) {
8571 push(@Bases, $SubBaseId);
8572 }
8573 }
8574 push(@Bases, $BaseId);
8575 }
8576 return @Bases;
8577}
8578
Andrey Ponomarenko16934472012-03-29 15:37:04 +04008579sub getVTable_Model($$)
8580{ # return an ordered list of v-table elements
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008581 my ($ClassId, $LibVersion) = @_;
8582 my @Bases = get_base_classes($ClassId, $LibVersion, 1);
8583 my @Elements = ();
8584 foreach my $BaseId (@Bases, $ClassId)
8585 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04008586 if(my $BName = $TypeInfo{$LibVersion}{$BaseId}{"Name"})
Andrey Ponomarenko85043792012-05-14 16:48:07 +04008587 {
8588 if(defined $VirtualTable{$LibVersion}{$BName})
8589 {
8590 my @VFunctions = keys(%{$VirtualTable{$LibVersion}{$BName}});
8591 @VFunctions = sort {int($CompleteSignature{$LibVersion}{$a}{"Line"}) <=> int($CompleteSignature{$LibVersion}{$b}{"Line"})} @VFunctions;
8592 foreach my $VFunc (@VFunctions) {
8593 push(@Elements, $VFunc);
8594 }
8595 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008596 }
8597 }
8598 return @Elements;
8599}
8600
8601sub getVShift($$)
8602{
8603 my ($ClassId, $LibVersion) = @_;
8604 my @Bases = get_base_classes($ClassId, $LibVersion, 1);
8605 my $VShift = 0;
8606 foreach my $BaseId (@Bases)
8607 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04008608 if(my $BName = $TypeInfo{$LibVersion}{$BaseId}{"Name"})
Andrey Ponomarenko85043792012-05-14 16:48:07 +04008609 {
8610 if(defined $VirtualTable{$LibVersion}{$BName}) {
8611 $VShift+=keys(%{$VirtualTable{$LibVersion}{$BName}});
8612 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008613 }
8614 }
8615 return $VShift;
8616}
8617
8618sub getShift($$)
8619{
8620 my ($ClassId, $LibVersion) = @_;
8621 my @Bases = get_base_classes($ClassId, $LibVersion, 0);
8622 my $Shift = 0;
8623 foreach my $BaseId (@Bases)
8624 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04008625 if(my $Size = $TypeInfo{$LibVersion}{$BaseId}{"Size"})
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04008626 {
8627 if($Size!=1)
8628 { # not empty base class
8629 $Shift+=$Size;
8630 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008631 }
8632 }
8633 return $Shift;
8634}
8635
Andrey Ponomarenko16934472012-03-29 15:37:04 +04008636sub getVTable_Size($$)
8637{ # number of v-table elements
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008638 my ($ClassName, $LibVersion) = @_;
Andrey Ponomarenko16934472012-03-29 15:37:04 +04008639 my $Size = 0;
8640 # three approaches
8641 if(not $Size)
8642 { # real size
8643 if(my %VTable = getVTable_Real($ClassName, $LibVersion)) {
8644 $Size = keys(%VTable);
8645 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008646 }
Andrey Ponomarenko16934472012-03-29 15:37:04 +04008647 if(not $Size)
8648 { # shared library symbol size
8649 if($Size = getSymbolSize($ClassVTable{$ClassName}, $LibVersion)) {
8650 $Size /= $WORD_SIZE{$LibVersion};
8651 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008652 }
Andrey Ponomarenko16934472012-03-29 15:37:04 +04008653 if(not $Size)
8654 { # model size
8655 if(defined $VirtualTable_Model{$LibVersion}{$ClassName}) {
8656 $Size = keys(%{$VirtualTable_Model{$LibVersion}{$ClassName}}) + 2;
8657 }
8658 }
8659 return $Size;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008660}
8661
8662sub isCopyingClass($$)
8663{
8664 my ($TypeId, $LibVersion) = @_;
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04008665 return $TypeInfo{$LibVersion}{$TypeId}{"Copied"};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008666}
8667
8668sub isLeafClass($$)
8669{
8670 my ($ClassId, $LibVersion) = @_;
8671 return (not keys(%{$Class_SubClasses{$LibVersion}{$ClassId}}));
8672}
8673
8674sub havePubFields($)
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04008675{ # check structured type for public fields
8676 return isAccessible($_[0], {}, 0, -1);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008677}
8678
8679sub isAccessible($$$$)
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04008680{ # check interval in structured type for public fields
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008681 my ($TypePtr, $Skip, $Start, $End) = @_;
8682 return 0 if(not $TypePtr);
8683 if($End==-1) {
8684 $End = keys(%{$TypePtr->{"Memb"}})-1;
8685 }
8686 foreach my $MemPos (keys(%{$TypePtr->{"Memb"}}))
8687 {
8688 if($Skip and $Skip->{$MemPos})
8689 { # skip removed/added fields
8690 next;
8691 }
8692 if(int($MemPos)>=$Start and int($MemPos)<=$End)
8693 {
8694 if(isPublic($TypePtr, $MemPos)) {
8695 return ($MemPos+1);
8696 }
8697 }
8698 }
8699 return 0;
8700}
8701
8702sub getAlignment($$$)
8703{
8704 my ($Pos, $TypePtr, $LibVersion) = @_;
8705 my $Tid = $TypePtr->{"Memb"}{$Pos}{"type"};
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04008706 my %Type = get_PureType($Tid, $LibVersion);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008707 my $TSize = $Type{"Size"}*$BYTE_SIZE;
8708 my $MSize = $Type{"Size"}*$BYTE_SIZE;
8709 if(my $BSize = $TypePtr->{"Memb"}{$Pos}{"bitfield"})
8710 { # bitfields
8711 ($TSize, $MSize) = ($WORD_SIZE{$LibVersion}*$BYTE_SIZE, $BSize);
8712 }
8713 elsif($Type{"Type"} eq "Array")
8714 { # in the context of function parameter
8715 # it's passed through the pointer
8716 }
8717 # alignment
8718 my $Alignment = $WORD_SIZE{$LibVersion}*$BYTE_SIZE; # default
8719 if(my $Computed = $TypePtr->{"Memb"}{$Pos}{"algn"})
8720 { # computed by GCC
8721 $Alignment = $Computed*$BYTE_SIZE;
8722 }
8723 elsif($TypePtr->{"Memb"}{$Pos}{"bitfield"})
8724 { # bitfields are 1 bit aligned
8725 $Alignment = 1;
8726 }
8727 elsif($TSize and $TSize<$WORD_SIZE{$LibVersion}*$BYTE_SIZE)
8728 { # model
8729 $Alignment = $TSize;
8730 }
8731 return ($Alignment, $MSize);
8732}
8733
8734sub getOffset($$$)
8735{ # offset of the field including padding
8736 my ($FieldPos, $TypePtr, $LibVersion) = @_;
8737 my $Offset = 0;
8738 foreach my $Pos (0 .. keys(%{$TypePtr->{"Memb"}})-1)
8739 {
8740 my ($Alignment, $MSize) = getAlignment($Pos, $TypePtr, $LibVersion);
8741 # padding
8742 my $Padding = 0;
8743 if($Offset % $Alignment!=0)
8744 { # not aligned, add padding
8745 $Padding = $Alignment - $Offset % $Alignment;
8746 }
8747 $Offset += $Padding;
8748 if($Pos==$FieldPos)
8749 { # after the padding
8750 # before the field
8751 return $Offset;
8752 }
8753 $Offset += $MSize;
8754 }
8755 return $FieldPos;# if something is going wrong
8756}
8757
8758sub isMemPadded($$$$$)
8759{ # check if the target field can be added/removed/changed
8760 # without shifting other fields because of padding bits
8761 my ($FieldPos, $Size, $TypePtr, $Skip, $LibVersion) = @_;
8762 return 0 if($FieldPos==0);
8763 if(defined $TypePtr->{"Memb"}{""})
8764 {
8765 delete($TypePtr->{"Memb"}{""});
8766 if($Debug) {
8767 printMsg("WARNING", "internal error detected");
8768 }
8769 }
8770 my $Offset = 0;
8771 my (%Alignment, %MSize) = ();
8772 my $MaxAlgn = 0;
8773 my $End = keys(%{$TypePtr->{"Memb"}})-1;
8774 my $NextField = $FieldPos+1;
8775 foreach my $Pos (0 .. $End)
8776 {
8777 if($Skip and $Skip->{$Pos})
8778 { # skip removed/added fields
8779 if($Pos > $FieldPos)
8780 { # after the target
8781 $NextField += 1;
8782 next;
8783 }
8784 }
8785 ($Alignment{$Pos}, $MSize{$Pos}) = getAlignment($Pos, $TypePtr, $LibVersion);
8786 if($Alignment{$Pos}>$MaxAlgn) {
8787 $MaxAlgn = $Alignment{$Pos};
8788 }
8789 if($Pos==$FieldPos)
8790 {
8791 if($Size==-1)
8792 { # added/removed fields
8793 if($Pos!=$End)
8794 { # skip target field and see
8795 # if enough padding will be
8796 # created on the next step
8797 # to include this field
8798 next;
8799 }
8800 }
8801 }
8802 # padding
8803 my $Padding = 0;
8804 if($Offset % $Alignment{$Pos}!=0)
8805 { # not aligned, add padding
8806 $Padding = $Alignment{$Pos} - $Offset % $Alignment{$Pos};
8807 }
8808 if($Pos==$NextField)
8809 { # try to place target field in the padding
8810 if($Size==-1)
8811 { # added/removed fields
8812 my $TPadding = 0;
8813 if($Offset % $Alignment{$FieldPos}!=0)
8814 {# padding of the target field
8815 $TPadding = $Alignment{$FieldPos} - $Offset % $Alignment{$FieldPos};
8816 }
8817 if($TPadding+$MSize{$FieldPos}<=$Padding)
8818 { # enough padding to place target field
8819 return 1;
8820 }
8821 else {
8822 return 0;
8823 }
8824 }
8825 else
8826 { # changed fields
8827 my $Delta = $Size-$MSize{$FieldPos};
8828 if($Delta>=0)
8829 { # increased
8830 if($Size-$MSize{$FieldPos}<=$Padding)
8831 { # enough padding to change target field
8832 return 1;
8833 }
8834 else {
8835 return 0;
8836 }
8837 }
8838 else
8839 { # decreased
8840 $Delta = abs($Delta);
8841 if($Delta+$Padding>=$MSize{$Pos})
8842 { # try to place the next field
8843 if(($Offset-$Delta) % $Alignment{$Pos} != 0)
8844 { # padding of the next field in new place
8845 my $NPadding = $Alignment{$Pos} - ($Offset-$Delta) % $Alignment{$Pos};
8846 if($NPadding+$MSize{$Pos}<=$Delta+$Padding)
8847 { # enough delta+padding to store next field
8848 return 0;
8849 }
8850 }
8851 else
8852 {
8853 return 0;
8854 }
8855 }
8856 return 1;
8857 }
8858 }
8859 }
8860 elsif($Pos==$End)
8861 { # target field is the last field
8862 if($Size==-1)
8863 { # added/removed fields
8864 if($Offset % $MaxAlgn!=0)
8865 { # tail padding
8866 my $TailPadding = $MaxAlgn - $Offset % $MaxAlgn;
8867 if($Padding+$MSize{$Pos}<=$TailPadding)
8868 { # enough tail padding to place the last field
8869 return 1;
8870 }
8871 }
8872 return 0;
8873 }
8874 else
8875 { # changed fields
8876 # scenario #1
8877 my $Offset1 = $Offset+$Padding+$MSize{$Pos};
8878 if($Offset1 % $MaxAlgn != 0)
8879 { # tail padding
8880 $Offset1 += $MaxAlgn - $Offset1 % $MaxAlgn;
8881 }
8882 # scenario #2
8883 my $Offset2 = $Offset+$Padding+$Size;
8884 if($Offset2 % $MaxAlgn != 0)
8885 { # tail padding
8886 $Offset2 += $MaxAlgn - $Offset2 % $MaxAlgn;
8887 }
8888 if($Offset1!=$Offset2)
8889 { # different sizes of structure
8890 return 0;
8891 }
8892 return 1;
8893 }
8894 }
8895 $Offset += $Padding+$MSize{$Pos};
8896 }
8897 return 0;
8898}
8899
8900sub isReserved($)
8901{ # reserved fields == private
8902 my $MName = $_[0];
8903 if($MName=~/reserved|padding|f_spare/i) {
8904 return 1;
8905 }
8906 if($MName=~/\A[_]*(spare|pad|unused)[_]*\Z/i) {
8907 return 1;
8908 }
8909 if($MName=~/(pad\d+)/i) {
8910 return 1;
8911 }
8912 return 0;
8913}
8914
8915sub isPublic($$)
8916{
8917 my ($TypePtr, $FieldPos) = @_;
8918 return 0 if(not $TypePtr);
8919 return 0 if(not defined $TypePtr->{"Memb"}{$FieldPos});
8920 return 0 if(not defined $TypePtr->{"Memb"}{$FieldPos}{"name"});
8921 if(not $TypePtr->{"Memb"}{$FieldPos}{"access"})
8922 { # by name in C language
8923 # FIXME: add other methods to detect private members
8924 my $MName = $TypePtr->{"Memb"}{$FieldPos}{"name"};
8925 if($MName=~/priv|abidata|parent_object/i)
8926 { # C-styled private data
8927 return 0;
8928 }
8929 if(lc($MName) eq "abi")
8930 { # ABI information/reserved field
8931 return 0;
8932 }
8933 if(isReserved($MName))
8934 { # reserved fields
8935 return 0;
8936 }
8937 return 1;
8938 }
8939 elsif($TypePtr->{"Memb"}{$FieldPos}{"access"} ne "private")
8940 { # by access in C++ language
8941 return 1;
8942 }
8943 return 0;
8944}
8945
Andrey Ponomarenko16934472012-03-29 15:37:04 +04008946sub getVTable_Real($$)
8947{
8948 my ($ClassName, $LibVersion) = @_;
8949 if(my $ClassId = $TName_Tid{$LibVersion}{$ClassName})
8950 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04008951 my %Type = get_Type($ClassId, $LibVersion);
Andrey Ponomarenko16934472012-03-29 15:37:04 +04008952 if(defined $Type{"VTable"}) {
8953 return %{$Type{"VTable"}};
8954 }
8955 }
8956 return ();
8957}
8958
8959sub cmpVTables($)
8960{
8961 my $ClassName = $_[0];
8962 my $Res = cmpVTables_Real($ClassName, 1);
8963 if($Res==-1) {
8964 $Res = cmpVTables_Model($ClassName);
8965 }
8966 return $Res;
8967}
8968
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008969sub cmpVTables_Model($)
8970{
8971 my $ClassName = $_[0];
Andrey Ponomarenko16934472012-03-29 15:37:04 +04008972 foreach my $Symbol (keys(%{$VirtualTable_Model{1}{$ClassName}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008973 {
Andrey Ponomarenko16934472012-03-29 15:37:04 +04008974 if(not defined $VirtualTable_Model{2}{$ClassName}{$Symbol}) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008975 return 1;
8976 }
8977 }
8978 return 0;
8979}
8980
Andrey Ponomarenko16934472012-03-29 15:37:04 +04008981sub cmpVTables_Real($$)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008982{
8983 my ($ClassName, $Strong) = @_;
Andrey Ponomarenko16934472012-03-29 15:37:04 +04008984 if(defined $Cache{"cmpVTables_Real"}{$Strong}{$ClassName}) {
8985 return $Cache{"cmpVTables_Real"}{$Strong}{$ClassName};
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04008986 }
Andrey Ponomarenko16934472012-03-29 15:37:04 +04008987 my %VTable_Old = getVTable_Real($ClassName, 1);
8988 my %VTable_New = getVTable_Real($ClassName, 2);
8989 if(not %VTable_Old or not %VTable_New)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008990 { # old ABI dumps
Andrey Ponomarenko16934472012-03-29 15:37:04 +04008991 return ($Cache{"cmpVTables_Real"}{$Strong}{$ClassName} = -1);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008992 }
Andrey Ponomarenko16934472012-03-29 15:37:04 +04008993 my %Indexes = map {$_=>1} (keys(%VTable_Old), keys(%VTable_New));
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008994 foreach my $Offset (sort {int($a)<=>int($b)} keys(%Indexes))
8995 {
Andrey Ponomarenko16934472012-03-29 15:37:04 +04008996 if(not defined $VTable_Old{$Offset})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008997 { # v-table v.1 < v-table v.2
Andrey Ponomarenko16934472012-03-29 15:37:04 +04008998 return ($Cache{"cmpVTables_Real"}{$Strong}{$ClassName} = $Strong);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008999 }
Andrey Ponomarenko16934472012-03-29 15:37:04 +04009000 my $Entry1 = $VTable_Old{$Offset};
9001 if(not defined $VTable_New{$Offset})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009002 { # v-table v.1 > v-table v.2
Andrey Ponomarenko16934472012-03-29 15:37:04 +04009003 return ($Cache{"cmpVTables_Real"}{$Strong}{$ClassName} = ($Strong or $Entry1!~/__cxa_pure_virtual/));
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009004 }
Andrey Ponomarenko16934472012-03-29 15:37:04 +04009005 my $Entry2 = $VTable_New{$Offset};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009006 $Entry1 = simpleVEntry($Entry1);
9007 $Entry2 = simpleVEntry($Entry2);
9008 if($Entry1 ne $Entry2)
9009 { # register as changed
9010 if($Entry1=~/::([^:]+)\Z/)
9011 {
9012 my $M1 = $1;
9013 if($Entry2=~/::([^:]+)\Z/)
9014 {
9015 my $M2 = $1;
9016 if($M1 eq $M2)
9017 { # overridden
9018 next;
9019 }
9020 }
9021 }
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04009022 if(differentDumps("G"))
9023 {
9024 if($Entry1=~/\A\-(0x|\d+)/ and $Entry2=~/\A\-(0x|\d+)/)
9025 {
9026 # GCC 4.6.1: -0x00000000000000010
9027 # GCC 4.7.0: -16
9028 next;
9029 }
9030 }
Andrey Ponomarenko16934472012-03-29 15:37:04 +04009031 return ($Cache{"cmpVTables_Real"}{$Strong}{$ClassName} = 1);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009032 }
9033 }
Andrey Ponomarenko16934472012-03-29 15:37:04 +04009034 return ($Cache{"cmpVTables_Real"}{$Strong}{$ClassName} = 0);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009035}
9036
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04009037sub mergeVTables($)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009038{ # merging v-tables without diagnostics
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04009039 my $Level = $_[0];
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009040 foreach my $ClassName (keys(%{$VirtualTable{1}}))
9041 {
Andrey Ponomarenko16934472012-03-29 15:37:04 +04009042 if($VTableChanged_M{$ClassName})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009043 { # already registered
9044 next;
9045 }
Andrey Ponomarenko16934472012-03-29 15:37:04 +04009046 if(cmpVTables_Real($ClassName, 0)==1)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009047 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04009048 my @Affected = (keys(%{$ClassMethods{$Level}{1}{$ClassName}}));
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009049 foreach my $Symbol (@Affected)
9050 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04009051 %{$CompatProblems{$Level}{$Symbol}{"Virtual_Table_Changed_Unknown"}{$ClassName}}=(
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009052 "Type_Name"=>$ClassName,
9053 "Type_Type"=>"Class",
9054 "Target"=>$ClassName);
9055 }
9056 }
9057 }
9058}
9059
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04009060sub mergeBases($)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009061{
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04009062 my $Level = $_[0];
Andrey Ponomarenko16934472012-03-29 15:37:04 +04009063 foreach my $ClassName (keys(%{$ClassNames{1}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009064 { # detect added and removed virtual functions
Andrey Ponomarenko16934472012-03-29 15:37:04 +04009065 my $ClassId = $TName_Tid{1}{$ClassName};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009066 next if(not $ClassId);
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04009067 if(defined $VirtualTable{2}{$ClassName})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009068 {
Andrey Ponomarenko16934472012-03-29 15:37:04 +04009069 foreach my $Symbol (keys(%{$VirtualTable{2}{$ClassName}}))
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04009070 {
Andrey Ponomarenko16934472012-03-29 15:37:04 +04009071 if($TName_Tid{1}{$ClassName}
9072 and not defined $VirtualTable{1}{$ClassName}{$Symbol})
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04009073 { # added to v-table
Andrey Ponomarenko16934472012-03-29 15:37:04 +04009074 if(defined $CompleteSignature{1}{$Symbol}
9075 and $CompleteSignature{1}{$Symbol}{"Virt"})
9076 { # override some method in v.1
9077 next;
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04009078 }
Andrey Ponomarenko16934472012-03-29 15:37:04 +04009079 $AddedInt_Virt{$Level}{$ClassName}{$Symbol} = 1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009080 }
9081 }
9082 }
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04009083 if(defined $VirtualTable{1}{$ClassName})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009084 {
Andrey Ponomarenko16934472012-03-29 15:37:04 +04009085 foreach my $Symbol (keys(%{$VirtualTable{1}{$ClassName}}))
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04009086 {
Andrey Ponomarenko16934472012-03-29 15:37:04 +04009087 if($TName_Tid{2}{$ClassName}
9088 and not defined $VirtualTable{2}{$ClassName}{$Symbol})
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04009089 { # removed from v-table
Andrey Ponomarenko16934472012-03-29 15:37:04 +04009090 if(defined $CompleteSignature{2}{$Symbol}
9091 and $CompleteSignature{2}{$Symbol}{"Virt"})
9092 { # override some method in v.2
9093 next;
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04009094 }
Andrey Ponomarenko16934472012-03-29 15:37:04 +04009095 $RemovedInt_Virt{$Level}{$ClassName}{$Symbol} = 1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009096 }
9097 }
9098 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04009099 if($Level eq "Binary")
9100 { # Binary-level
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04009101 my %Class_Type = get_Type($ClassId, 1);
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04009102 foreach my $AddedVFunc (keys(%{$AddedInt_Virt{$Level}{$ClassName}}))
9103 { # check replacements, including pure virtual methods
9104 my $AddedPos = $VirtualTable{2}{$ClassName}{$AddedVFunc};
9105 foreach my $RemovedVFunc (keys(%{$RemovedInt_Virt{$Level}{$ClassName}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009106 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04009107 my $RemovedPos = $VirtualTable{1}{$ClassName}{$RemovedVFunc};
9108 if($AddedPos==$RemovedPos)
9109 {
9110 $VirtualReplacement{$AddedVFunc} = $RemovedVFunc;
9111 $VirtualReplacement{$RemovedVFunc} = $AddedVFunc;
9112 last; # other methods will be reported as "added" or "removed"
9113 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009114 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04009115 if(my $RemovedVFunc = $VirtualReplacement{$AddedVFunc})
9116 {
9117 if(lc($AddedVFunc) eq lc($RemovedVFunc))
9118 { # skip: DomUi => DomUI parameter (Qt 4.2.3 to 4.3.0)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009119 next;
9120 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04009121 my $ProblemType = "Virtual_Replacement";
9122 my @Affected = ($RemovedVFunc);
9123 if($CompleteSignature{1}{$RemovedVFunc}{"PureVirt"})
9124 { # pure methods
9125 if(not isUsedClass($ClassId, 1, $Level))
9126 { # not a parameter of some exported method
9127 next;
9128 }
9129 $ProblemType = "Pure_Virtual_Replacement";
9130 @Affected = (keys(%{$ClassMethods{$Level}{1}{$ClassName}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009131 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04009132 foreach my $AffectedInt (@Affected)
9133 {
9134 if($CompleteSignature{1}{$AffectedInt}{"PureVirt"})
9135 { # affected exported methods only
9136 next;
9137 }
9138 %{$CompatProblems{$Level}{$AffectedInt}{$ProblemType}{$tr_name{$AddedVFunc}}}=(
9139 "Type_Name"=>$Class_Type{"Name"},
9140 "Type_Type"=>"Class",
9141 "Target"=>get_Signature($AddedVFunc, 2),
9142 "Old_Value"=>get_Signature($RemovedVFunc, 1));
9143 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009144 }
9145 }
9146 }
9147 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04009148 if(not checkDump(1, "2.0")
9149 or not checkDump(2, "2.0"))
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04009150 { # support for old ABI dumps
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009151 # "Base" attribute introduced in ACC 1.22 (dump 2.0 format)
9152 return;
9153 }
Andrey Ponomarenko16934472012-03-29 15:37:04 +04009154 foreach my $ClassName (sort keys(%{$ClassNames{1}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009155 {
Andrey Ponomarenko16934472012-03-29 15:37:04 +04009156 my $ClassId_Old = $TName_Tid{1}{$ClassName};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009157 next if(not $ClassId_Old);
9158 if(not isCreatable($ClassId_Old, 1))
9159 { # skip classes without public constructors (including auto-generated)
9160 # example: class has only a private exported or private inline constructor
9161 next;
9162 }
9163 if($ClassName=~/>/)
9164 { # skip affected template instances
9165 next;
9166 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04009167 my %Class_Old = get_Type($ClassId_Old, 1);
Andrey Ponomarenko16934472012-03-29 15:37:04 +04009168 my $ClassId_New = $TName_Tid{2}{$ClassName};
Andrey Ponomarenko85043792012-05-14 16:48:07 +04009169 if(not $ClassId_New) {
9170 next;
9171 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04009172 my %Class_New = get_Type($ClassId_New, 2);
Andrey Ponomarenko85043792012-05-14 16:48:07 +04009173 if($Class_New{"Type"}!~/Class|Struct/)
9174 { # became typedef
9175 if($Level eq "Binary") {
9176 next;
9177 }
9178 if($Level eq "Source")
9179 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04009180 %Class_New = get_PureType($ClassId_New, 2);
Andrey Ponomarenko85043792012-05-14 16:48:07 +04009181 if($Class_New{"Type"}!~/Class|Struct/) {
9182 next;
9183 }
9184 $ClassId_New = $Class_New{"Tid"};
9185 }
9186 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009187 my @Bases_Old = sort {$Class_Old{"Base"}{$a}{"pos"}<=>$Class_Old{"Base"}{$b}{"pos"}} keys(%{$Class_Old{"Base"}});
9188 my @Bases_New = sort {$Class_New{"Base"}{$a}{"pos"}<=>$Class_New{"Base"}{$b}{"pos"}} keys(%{$Class_New{"Base"}});
9189 my ($BNum1, $BNum2) = (1, 1);
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04009190 my %BasePos_Old = map {$TypeInfo{1}{$_}{"Name"} => $BNum1++} @Bases_Old;
9191 my %BasePos_New = map {$TypeInfo{2}{$_}{"Name"} => $BNum2++} @Bases_New;
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04009192 my %ShortBase_Old = map {get_ShortType($_, 1) => 1} @Bases_Old;
9193 my %ShortBase_New = map {get_ShortType($_, 2) => 1} @Bases_New;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009194 my $Shift_Old = getShift($ClassId_Old, 1);
9195 my $Shift_New = getShift($ClassId_New, 2);
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04009196 my %BaseId_New = map {$TypeInfo{2}{$_}{"Name"} => $_} @Bases_New;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009197 my ($Added, $Removed) = (0, 0);
9198 my @StableBases_Old = ();
9199 foreach my $BaseId (@Bases_Old)
9200 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04009201 my $BaseName = $TypeInfo{1}{$BaseId}{"Name"};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009202 if($BasePos_New{$BaseName}) {
9203 push(@StableBases_Old, $BaseId);
9204 }
9205 elsif(not $ShortBase_New{$BaseName}
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04009206 and not $ShortBase_New{get_ShortType($BaseId, 1)})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009207 { # removed base
9208 # excluding namespace::SomeClass to SomeClass renaming
9209 my $ProblemKind = "Removed_Base_Class";
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04009210 if($Level eq "Binary")
9211 { # Binary-level
9212 if($Shift_Old ne $Shift_New)
9213 { # affected fields
9214 if(havePubFields(\%Class_Old)) {
9215 $ProblemKind .= "_And_Shift";
9216 }
9217 elsif($Class_Old{"Size"} ne $Class_New{"Size"}) {
9218 $ProblemKind .= "_And_Size";
9219 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009220 }
Andrey Ponomarenko16934472012-03-29 15:37:04 +04009221 if(keys(%{$VirtualTable_Model{1}{$BaseName}})
9222 and cmpVTables($ClassName)==1)
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04009223 { # affected v-table
9224 $ProblemKind .= "_And_VTable";
Andrey Ponomarenko16934472012-03-29 15:37:04 +04009225 $VTableChanged_M{$ClassName}=1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009226 }
9227 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04009228 my @Affected = keys(%{$ClassMethods{$Level}{1}{$ClassName}});
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009229 foreach my $SubId (get_sub_classes($ClassId_Old, 1, 1))
9230 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04009231 my $SubName = $TypeInfo{1}{$SubId}{"Name"};
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04009232 push(@Affected, keys(%{$ClassMethods{$Level}{1}{$SubName}}));
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009233 if($ProblemKind=~/VTable/) {
Andrey Ponomarenko16934472012-03-29 15:37:04 +04009234 $VTableChanged_M{$SubName}=1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009235 }
9236 }
9237 foreach my $Interface (@Affected)
9238 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04009239 %{$CompatProblems{$Level}{$Interface}{$ProblemKind}{"this"}}=(
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009240 "Type_Name"=>$ClassName,
9241 "Type_Type"=>"Class",
9242 "Target"=>$BaseName,
9243 "Old_Size"=>$Class_Old{"Size"}*$BYTE_SIZE,
9244 "New_Size"=>$Class_New{"Size"}*$BYTE_SIZE,
9245 "Shift"=>abs($Shift_New-$Shift_Old) );
9246 }
9247 $Removed+=1;
9248 }
9249 }
9250 my @StableBases_New = ();
9251 foreach my $BaseId (@Bases_New)
9252 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04009253 my $BaseName = $TypeInfo{2}{$BaseId}{"Name"};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009254 if($BasePos_Old{$BaseName}) {
9255 push(@StableBases_New, $BaseId);
9256 }
9257 elsif(not $ShortBase_Old{$BaseName}
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04009258 and not $ShortBase_Old{get_ShortType($BaseId, 2)})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009259 { # added base
9260 # excluding namespace::SomeClass to SomeClass renaming
9261 my $ProblemKind = "Added_Base_Class";
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04009262 if($Level eq "Binary")
9263 { # Binary-level
9264 if($Shift_Old ne $Shift_New)
9265 { # affected fields
9266 if(havePubFields(\%Class_Old)) {
9267 $ProblemKind .= "_And_Shift";
9268 }
9269 elsif($Class_Old{"Size"} ne $Class_New{"Size"}) {
9270 $ProblemKind .= "_And_Size";
9271 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009272 }
Andrey Ponomarenko16934472012-03-29 15:37:04 +04009273 if(keys(%{$VirtualTable_Model{2}{$BaseName}})
9274 and cmpVTables($ClassName)==1)
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04009275 { # affected v-table
9276 $ProblemKind .= "_And_VTable";
Andrey Ponomarenko16934472012-03-29 15:37:04 +04009277 $VTableChanged_M{$ClassName}=1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009278 }
9279 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04009280 my @Affected = keys(%{$ClassMethods{$Level}{1}{$ClassName}});
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009281 foreach my $SubId (get_sub_classes($ClassId_Old, 1, 1))
9282 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04009283 my $SubName = $TypeInfo{1}{$SubId}{"Name"};
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04009284 push(@Affected, keys(%{$ClassMethods{$Level}{1}{$SubName}}));
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009285 if($ProblemKind=~/VTable/) {
Andrey Ponomarenko16934472012-03-29 15:37:04 +04009286 $VTableChanged_M{$SubName}=1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009287 }
9288 }
9289 foreach my $Interface (@Affected)
9290 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04009291 %{$CompatProblems{$Level}{$Interface}{$ProblemKind}{"this"}}=(
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009292 "Type_Name"=>$ClassName,
9293 "Type_Type"=>"Class",
9294 "Target"=>$BaseName,
9295 "Old_Size"=>$Class_Old{"Size"}*$BYTE_SIZE,
9296 "New_Size"=>$Class_New{"Size"}*$BYTE_SIZE,
9297 "Shift"=>abs($Shift_New-$Shift_Old) );
9298 }
9299 $Added+=1;
9300 }
9301 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04009302 if($Level eq "Binary")
9303 { # Binary-level
9304 ($BNum1, $BNum2) = (1, 1);
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04009305 my %BaseRelPos_Old = map {$TypeInfo{1}{$_}{"Name"} => $BNum1++} @StableBases_Old;
9306 my %BaseRelPos_New = map {$TypeInfo{2}{$_}{"Name"} => $BNum2++} @StableBases_New;
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04009307 foreach my $BaseId (@Bases_Old)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009308 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04009309 my $BaseName = $TypeInfo{1}{$BaseId}{"Name"};
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04009310 if(my $NewPos = $BaseRelPos_New{$BaseName})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009311 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04009312 my $BaseNewId = $BaseId_New{$BaseName};
9313 my $OldPos = $BaseRelPos_Old{$BaseName};
9314 if($NewPos!=$OldPos)
9315 { # changed position of the base class
9316 foreach my $Interface (keys(%{$ClassMethods{$Level}{1}{$ClassName}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009317 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04009318 %{$CompatProblems{$Level}{$Interface}{"Base_Class_Position"}{"this"}}=(
9319 "Type_Name"=>$ClassName,
9320 "Type_Type"=>"Class",
9321 "Target"=>$BaseName,
9322 "Old_Value"=>$OldPos-1,
9323 "New_Value"=>$NewPos-1 );
9324 }
9325 }
9326 if($Class_Old{"Base"}{$BaseId}{"virtual"}
9327 and not $Class_New{"Base"}{$BaseNewId}{"virtual"})
9328 { # became non-virtual base
9329 foreach my $Interface (keys(%{$ClassMethods{$Level}{1}{$ClassName}}))
9330 {
9331 %{$CompatProblems{$Level}{$Interface}{"Base_Class_Became_Non_Virtually_Inherited"}{"this->".$BaseName}}=(
9332 "Type_Name"=>$ClassName,
9333 "Type_Type"=>"Class",
9334 "Target"=>$BaseName );
9335 }
9336 }
9337 elsif(not $Class_Old{"Base"}{$BaseId}{"virtual"}
9338 and $Class_New{"Base"}{$BaseNewId}{"virtual"})
9339 { # became virtual base
9340 foreach my $Interface (keys(%{$ClassMethods{$Level}{1}{$ClassName}}))
9341 {
9342 %{$CompatProblems{$Level}{$Interface}{"Base_Class_Became_Virtually_Inherited"}{"this->".$BaseName}}=(
9343 "Type_Name"=>$ClassName,
9344 "Type_Type"=>"Class",
9345 "Target"=>$BaseName );
9346 }
9347 }
9348 }
9349 }
9350 # detect size changes in base classes
9351 if($Shift_Old!=$Shift_New)
9352 { # size of allocable class
9353 foreach my $BaseId (@StableBases_Old)
9354 { # search for changed base
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04009355 my %BaseType = get_Type($BaseId, 1);
9356 my $Size_Old = $TypeInfo{1}{$BaseId}{"Size"};
9357 my $Size_New = $TypeInfo{2}{$BaseId_New{$BaseType{"Name"}}}{"Size"};
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04009358 if($Size_Old ne $Size_New
9359 and $Size_Old and $Size_New)
9360 {
9361 my $ProblemType = "";
9362 if(isCopyingClass($BaseId, 1)) {
9363 $ProblemType = "Size_Of_Copying_Class";
9364 }
9365 elsif($AllocableClass{1}{$BaseType{"Name"}})
9366 {
9367 if($Size_New>$Size_Old)
9368 { # increased size
9369 $ProblemType = "Size_Of_Allocable_Class_Increased";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009370 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04009371 else
9372 { # decreased size
9373 $ProblemType = "Size_Of_Allocable_Class_Decreased";
9374 if(not havePubFields(\%Class_Old))
9375 { # affected class has no public members
9376 next;
9377 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009378 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04009379 }
9380 next if(not $ProblemType);
9381 foreach my $Interface (keys(%{$ClassMethods{$Level}{1}{$ClassName}}))
9382 { # base class size changes affecting current class
9383 %{$CompatProblems{$Level}{$Interface}{$ProblemType}{"this->".$BaseType{"Name"}}}=(
9384 "Type_Name"=>$BaseType{"Name"},
9385 "Type_Type"=>"Class",
9386 "Target"=>$BaseType{"Name"},
9387 "Old_Size"=>$Size_Old*$BYTE_SIZE,
9388 "New_Size"=>$Size_New*$BYTE_SIZE );
9389 }
9390 }
9391 }
9392 }
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04009393 if(defined $VirtualTable{1}{$ClassName}
Andrey Ponomarenko16934472012-03-29 15:37:04 +04009394 and cmpVTables_Real($ClassName, 1)==1
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04009395 and my @VFunctions = keys(%{$VirtualTable{1}{$ClassName}}))
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04009396 { # compare virtual tables size in base classes
9397 my $VShift_Old = getVShift($ClassId_Old, 1);
9398 my $VShift_New = getVShift($ClassId_New, 2);
9399 if($VShift_Old ne $VShift_New)
9400 { # changes in the base class or changes in the list of base classes
9401 my @AllBases_Old = get_base_classes($ClassId_Old, 1, 1);
9402 my @AllBases_New = get_base_classes($ClassId_New, 2, 1);
9403 ($BNum1, $BNum2) = (1, 1);
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04009404 my %StableBase = map {$TypeInfo{2}{$_}{"Name"} => $_} @AllBases_New;
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04009405 foreach my $BaseId (@AllBases_Old)
9406 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04009407 my %BaseType = get_Type($BaseId, 1);
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04009408 if(not $StableBase{$BaseType{"Name"}})
9409 { # lost base
9410 next;
9411 }
Andrey Ponomarenko16934472012-03-29 15:37:04 +04009412 my $VSize_Old = getVTable_Size($BaseType{"Name"}, 1);
9413 my $VSize_New = getVTable_Size($BaseType{"Name"}, 2);
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04009414 if($VSize_Old!=$VSize_New)
9415 {
Andrey Ponomarenko85043792012-05-14 16:48:07 +04009416 foreach my $Symbol (@VFunctions)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009417 {
Andrey Ponomarenko85043792012-05-14 16:48:07 +04009418 if(not defined $VirtualTable{2}{$ClassName}{$Symbol})
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04009419 { # Removed_Virtual_Method, will be registered in mergeVirtualTables()
9420 next;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009421 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +04009422 if($VirtualTable_Model{2}{$ClassName}{$Symbol}-$VirtualTable_Model{1}{$ClassName}{$Symbol}==0)
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04009423 { # skip interfaces that have not changed the absolute virtual position
9424 next;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009425 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +04009426 if(not symbolFilter($Symbol, 1, "Affected", $Level)) {
9427 next;
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04009428 }
Andrey Ponomarenko16934472012-03-29 15:37:04 +04009429 $VTableChanged_M{$BaseType{"Name"}} = 1;
9430 $VTableChanged_M{$ClassName} = 1;
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04009431 foreach my $VirtFunc (keys(%{$AddedInt_Virt{$Level}{$BaseType{"Name"}}}))
9432 { # the reason of the layout change: added virtual functions
9433 next if($VirtualReplacement{$VirtFunc});
9434 my $ProblemType = "Added_Virtual_Method";
9435 if($CompleteSignature{2}{$VirtFunc}{"PureVirt"}) {
9436 $ProblemType = "Added_Pure_Virtual_Method";
9437 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +04009438 %{$CompatProblems{$Level}{$Symbol}{$ProblemType}{get_Signature($VirtFunc, 2)}}=(
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04009439 "Type_Name"=>$BaseType{"Name"},
9440 "Type_Type"=>"Class",
9441 "Target"=>get_Signature($VirtFunc, 2) );
9442 }
9443 foreach my $VirtFunc (keys(%{$RemovedInt_Virt{$Level}{$BaseType{"Name"}}}))
9444 { # the reason of the layout change: removed virtual functions
9445 next if($VirtualReplacement{$VirtFunc});
9446 my $ProblemType = "Removed_Virtual_Method";
9447 if($CompleteSignature{1}{$VirtFunc}{"PureVirt"}) {
9448 $ProblemType = "Removed_Pure_Virtual_Method";
9449 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +04009450 %{$CompatProblems{$Level}{$Symbol}{$ProblemType}{get_Signature($VirtFunc, 1)}}=(
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04009451 "Type_Name"=>$BaseType{"Name"},
9452 "Type_Type"=>"Class",
9453 "Target"=>get_Signature($VirtFunc, 1) );
9454 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009455 }
9456 }
9457 }
9458 }
9459 }
9460 }
9461 }
9462}
9463
9464sub isCreatable($$)
9465{
9466 my ($ClassId, $LibVersion) = @_;
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04009467 if($AllocableClass{$LibVersion}{$TypeInfo{$LibVersion}{$ClassId}{"Name"}}
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009468 or isCopyingClass($ClassId, $LibVersion)) {
9469 return 1;
9470 }
9471 if(keys(%{$Class_SubClasses{$LibVersion}{$ClassId}}))
9472 { # Fix for incomplete data: if this class has
9473 # a base class then it should also has a constructor
9474 return 1;
9475 }
9476 if($ReturnedClass{$LibVersion}{$ClassId})
9477 { # returned by some method of this class
9478 # or any other class
9479 return 1;
9480 }
9481 return 0;
9482}
9483
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04009484sub isUsedClass($$$)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009485{
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04009486 my ($ClassId, $LibVersion, $Level) = @_;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009487 if(keys(%{$ParamClass{$LibVersion}{$ClassId}}))
9488 { # parameter of some exported method
9489 return 1;
9490 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04009491 my $CName = $TypeInfo{$LibVersion}{$ClassId}{"Name"};
9492 if(keys(%{$ClassMethods{$Level}{$LibVersion}{$CName}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009493 { # method from target class
9494 return 1;
9495 }
9496 return 0;
9497}
9498
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04009499sub mergeVirtualTables($$)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009500{ # check for changes in the virtual table
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04009501 my ($Interface, $Level) = @_;
Andrey Ponomarenko16934472012-03-29 15:37:04 +04009502 # affected methods:
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009503 # - virtual
9504 # - pure-virtual
9505 # - non-virtual
9506 if($CompleteSignature{1}{$Interface}{"Data"})
9507 { # global data is not affected
9508 return;
9509 }
9510 my $Class_Id = $CompleteSignature{1}{$Interface}{"Class"};
Andrey Ponomarenko16934472012-03-29 15:37:04 +04009511 if(not $Class_Id) {
9512 return;
9513 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04009514 my $CName = $TypeInfo{1}{$Class_Id}{"Name"};
Andrey Ponomarenko16934472012-03-29 15:37:04 +04009515 if(cmpVTables_Real($CName, 1)==0)
9516 { # no changes
9517 return;
9518 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04009519 $CheckedTypes{$Level}{$CName} = 1;
9520 if($Level eq "Binary")
9521 { # Binary-level
9522 if($CompleteSignature{1}{$Interface}{"PureVirt"}
9523 and not isUsedClass($Class_Id, 1, $Level))
9524 { # pure virtuals should not be affected
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04009525 # if there are no exported methods using this class
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04009526 return;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009527 }
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04009528 }
9529 foreach my $Func (keys(%{$VirtualTable{1}{$CName}}))
9530 {
9531 if(defined $VirtualTable{2}{$CName}{$Func}
9532 and defined $CompleteSignature{2}{$Func})
9533 {
9534 if(not $CompleteSignature{1}{$Func}{"PureVirt"}
9535 and $CompleteSignature{2}{$Func}{"PureVirt"})
9536 { # became pure virtual
9537 %{$CompatProblems{$Level}{$Interface}{"Virtual_Method_Became_Pure"}{$tr_name{$Func}}}=(
9538 "Type_Name"=>$CName,
9539 "Type_Type"=>"Class",
9540 "Target"=>get_Signature_M($Func, 1) );
9541 $VTableChanged_M{$CName} = 1;
9542 }
9543 elsif($CompleteSignature{1}{$Func}{"PureVirt"}
9544 and not $CompleteSignature{2}{$Func}{"PureVirt"})
9545 { # became non-pure virtual
9546 %{$CompatProblems{$Level}{$Interface}{"Virtual_Method_Became_Non_Pure"}{$tr_name{$Func}}}=(
9547 "Type_Name"=>$CName,
9548 "Type_Type"=>"Class",
9549 "Target"=>get_Signature_M($Func, 1) );
9550 $VTableChanged_M{$CName} = 1;
9551 }
9552 }
9553 }
9554 if($Level eq "Binary")
9555 { # Binary-level
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04009556 # check virtual table structure
9557 foreach my $AddedVFunc (keys(%{$AddedInt_Virt{$Level}{$CName}}))
9558 {
9559 next if($Interface eq $AddedVFunc);
9560 next if($VirtualReplacement{$AddedVFunc});
9561 my $VPos_Added = $VirtualTable{2}{$CName}{$AddedVFunc};
9562 if($CompleteSignature{2}{$AddedVFunc}{"PureVirt"})
9563 { # pure virtual methods affect all others (virtual and non-virtual)
9564 %{$CompatProblems{$Level}{$Interface}{"Added_Pure_Virtual_Method"}{$tr_name{$AddedVFunc}}}=(
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009565 "Type_Name"=>$CName,
9566 "Type_Type"=>"Class",
9567 "Target"=>get_Signature($AddedVFunc, 2) );
Andrey Ponomarenko16934472012-03-29 15:37:04 +04009568 $VTableChanged_M{$CName} = 1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009569 }
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04009570 elsif(not defined $VirtualTable{1}{$CName}
9571 or $VPos_Added>keys(%{$VirtualTable{1}{$CName}}))
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04009572 { # added virtual function at the end of v-table
Andrey Ponomarenko16934472012-03-29 15:37:04 +04009573 if(not keys(%{$VirtualTable_Model{1}{$CName}}))
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04009574 { # became polymorphous class, added v-table pointer
9575 %{$CompatProblems{$Level}{$Interface}{"Added_First_Virtual_Method"}{$tr_name{$AddedVFunc}}}=(
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009576 "Type_Name"=>$CName,
9577 "Type_Type"=>"Class",
9578 "Target"=>get_Signature($AddedVFunc, 2) );
Andrey Ponomarenko16934472012-03-29 15:37:04 +04009579 $VTableChanged_M{$CName} = 1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009580 }
9581 else
9582 {
Andrey Ponomarenko16934472012-03-29 15:37:04 +04009583 my $VSize_Old = getVTable_Size($CName, 1);
9584 my $VSize_New = getVTable_Size($CName, 2);
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04009585 next if($VSize_Old==$VSize_New);# exception: register as removed and added virtual method
9586 if(isCopyingClass($Class_Id, 1))
9587 { # class has no constructors and v-table will be copied by applications, this may affect all methods
9588 my $ProblemType = "Added_Virtual_Method";
9589 if(isLeafClass($Class_Id, 1)) {
9590 $ProblemType = "Added_Virtual_Method_At_End_Of_Leaf_Copying_Class";
9591 }
9592 %{$CompatProblems{$Level}{$Interface}{$ProblemType}{$tr_name{$AddedVFunc}}}=(
9593 "Type_Name"=>$CName,
9594 "Type_Type"=>"Class",
9595 "Target"=>get_Signature($AddedVFunc, 2) );
Andrey Ponomarenko16934472012-03-29 15:37:04 +04009596 $VTableChanged_M{$CName} = 1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009597 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04009598 else
9599 {
9600 my $ProblemType = "Added_Virtual_Method";
9601 if(isLeafClass($Class_Id, 1)) {
9602 $ProblemType = "Added_Virtual_Method_At_End_Of_Leaf_Allocable_Class";
9603 }
9604 %{$CompatProblems{$Level}{$Interface}{$ProblemType}{$tr_name{$AddedVFunc}}}=(
9605 "Type_Name"=>$CName,
9606 "Type_Type"=>"Class",
9607 "Target"=>get_Signature($AddedVFunc, 2) );
Andrey Ponomarenko16934472012-03-29 15:37:04 +04009608 $VTableChanged_M{$CName} = 1;
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04009609 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009610 }
9611 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04009612 elsif($CompleteSignature{1}{$Interface}{"Virt"}
9613 or $CompleteSignature{1}{$Interface}{"PureVirt"})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009614 {
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04009615 if(defined $VirtualTable{1}{$CName}
9616 and defined $VirtualTable{2}{$CName})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009617 {
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04009618 my $VPos_Old = $VirtualTable{1}{$CName}{$Interface};
9619 my $VPos_New = $VirtualTable{2}{$CName}{$Interface};
9620 if($VPos_Added<=$VPos_Old and $VPos_Old!=$VPos_New)
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04009621 {
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04009622 my @Affected = ($Interface, keys(%{$OverriddenMethods{1}{$Interface}}));
9623 foreach my $ASymbol (@Affected)
9624 {
Andrey Ponomarenko85043792012-05-14 16:48:07 +04009625 if(not $CompleteSignature{1}{$ASymbol}{"PureVirt"})
9626 {
9627 if(symbolFilter($ASymbol, 1, "Affected", $Level)) {
9628 next;
9629 }
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04009630 }
9631 $CheckedSymbols{$Level}{$ASymbol} = 1;
9632 %{$CompatProblems{$Level}{$ASymbol}{"Added_Virtual_Method"}{$tr_name{$AddedVFunc}}}=(
9633 "Type_Name"=>$CName,
9634 "Type_Type"=>"Class",
9635 "Target"=>get_Signature($AddedVFunc, 2) );
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04009636 $VTableChanged_M{$TypeInfo{1}{$CompleteSignature{1}{$ASymbol}{"Class"}}{"Name"}} = 1;
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04009637 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009638 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009639 }
9640 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04009641 else {
9642 # safe
9643 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009644 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04009645 foreach my $RemovedVFunc (keys(%{$RemovedInt_Virt{$Level}{$CName}}))
9646 {
9647 next if($VirtualReplacement{$RemovedVFunc});
9648 if($RemovedVFunc eq $Interface
9649 and $CompleteSignature{1}{$RemovedVFunc}{"PureVirt"})
9650 { # This case is for removed virtual methods
9651 # implemented in both versions of a library
9652 next;
9653 }
Andrey Ponomarenko16934472012-03-29 15:37:04 +04009654 if(not keys(%{$VirtualTable_Model{2}{$CName}}))
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04009655 { # became non-polymorphous class, removed v-table pointer
9656 %{$CompatProblems{$Level}{$Interface}{"Removed_Last_Virtual_Method"}{$tr_name{$RemovedVFunc}}}=(
9657 "Type_Name"=>$CName,
9658 "Type_Type"=>"Class",
9659 "Target"=>get_Signature($RemovedVFunc, 1) );
Andrey Ponomarenko16934472012-03-29 15:37:04 +04009660 $VTableChanged_M{$CName} = 1;
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04009661 }
9662 elsif($CompleteSignature{1}{$Interface}{"Virt"}
9663 or $CompleteSignature{1}{$Interface}{"PureVirt"})
9664 {
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04009665 if(defined $VirtualTable{1}{$CName} and defined $VirtualTable{2}{$CName})
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04009666 {
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04009667 if(not defined $VirtualTable{1}{$CName}{$Interface}) {
9668 next;
9669 }
9670 my $VPos_New = -1;
9671 if(defined $VirtualTable{2}{$CName}{$Interface})
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04009672 {
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04009673 $VPos_New = $VirtualTable{2}{$CName}{$Interface};
9674 }
9675 else
9676 {
9677 if($Interface ne $RemovedVFunc) {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04009678 next;
9679 }
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04009680 }
9681 my $VPos_Removed = $VirtualTable{1}{$CName}{$RemovedVFunc};
9682 my $VPos_Old = $VirtualTable{1}{$CName}{$Interface};
9683 if($VPos_Removed<=$VPos_Old and $VPos_Old!=$VPos_New)
9684 {
9685 my @Affected = ($Interface, keys(%{$OverriddenMethods{1}{$Interface}}));
9686 foreach my $ASymbol (@Affected)
9687 {
Andrey Ponomarenko85043792012-05-14 16:48:07 +04009688 if(not $CompleteSignature{1}{$ASymbol}{"PureVirt"})
9689 {
9690 if(symbolFilter($ASymbol, 1, "Affected", $Level)) {
9691 next;
9692 }
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04009693 }
9694 my $ProblemType = "Removed_Virtual_Method";
9695 if($CompleteSignature{1}{$RemovedVFunc}{"PureVirt"}) {
9696 $ProblemType = "Removed_Pure_Virtual_Method";
9697 }
9698 $CheckedSymbols{$Level}{$ASymbol} = 1;
9699 %{$CompatProblems{$Level}{$ASymbol}{$ProblemType}{$tr_name{$RemovedVFunc}}}=(
9700 "Type_Name"=>$CName,
9701 "Type_Type"=>"Class",
9702 "Target"=>get_Signature($RemovedVFunc, 1) );
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04009703 $VTableChanged_M{$TypeInfo{1}{$CompleteSignature{1}{$ASymbol}{"Class"}}{"Name"}} = 1;
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04009704 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04009705 }
9706 }
9707 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009708 }
9709 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04009710 else
9711 { # Source-level
9712 foreach my $AddedVFunc (keys(%{$AddedInt_Virt{$Level}{$CName}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009713 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04009714 next if($Interface eq $AddedVFunc);
9715 if($CompleteSignature{2}{$AddedVFunc}{"PureVirt"})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009716 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04009717 %{$CompatProblems{$Level}{$Interface}{"Added_Pure_Virtual_Method"}{$tr_name{$AddedVFunc}}}=(
9718 "Type_Name"=>$CName,
9719 "Type_Type"=>"Class",
9720 "Target"=>get_Signature($AddedVFunc, 2) );
9721 }
9722 }
9723 foreach my $RemovedVFunc (keys(%{$RemovedInt_Virt{$Level}{$CName}}))
9724 {
9725 if($CompleteSignature{1}{$RemovedVFunc}{"PureVirt"})
9726 {
9727 %{$CompatProblems{$Level}{$Interface}{"Removed_Pure_Virtual_Method"}{$tr_name{$RemovedVFunc}}}=(
9728 "Type_Name"=>$CName,
9729 "Type_Type"=>"Class",
9730 "Target"=>get_Signature($RemovedVFunc, 1) );
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009731 }
9732 }
9733 }
9734}
9735
9736sub find_MemberPair_Pos_byName($$)
9737{
9738 my ($Member_Name, $Pair_Type) = @_;
9739 $Member_Name=~s/\A[_]+|[_]+\Z//g;
9740 foreach my $MemberPair_Pos (sort {int($a)<=>int($b)} keys(%{$Pair_Type->{"Memb"}}))
9741 {
9742 if(defined $Pair_Type->{"Memb"}{$MemberPair_Pos})
9743 {
9744 my $Name = $Pair_Type->{"Memb"}{$MemberPair_Pos}{"name"};
9745 $Name=~s/\A[_]+|[_]+\Z//g;
9746 if($Name eq $Member_Name) {
9747 return $MemberPair_Pos;
9748 }
9749 }
9750 }
9751 return "lost";
9752}
9753
9754sub find_MemberPair_Pos_byVal($$)
9755{
9756 my ($Member_Value, $Pair_Type) = @_;
9757 foreach my $MemberPair_Pos (sort {int($a)<=>int($b)} keys(%{$Pair_Type->{"Memb"}}))
9758 {
9759 if(defined $Pair_Type->{"Memb"}{$MemberPair_Pos}
9760 and $Pair_Type->{"Memb"}{$MemberPair_Pos}{"value"} eq $Member_Value) {
9761 return $MemberPair_Pos;
9762 }
9763 }
9764 return "lost";
9765}
9766
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04009767my %Severity_Val=(
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009768 "High"=>3,
9769 "Medium"=>2,
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04009770 "Low"=>1,
9771 "Safe"=>-1
9772);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009773
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04009774sub maxSeverity($$)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009775{
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04009776 my ($S1, $S2) = @_;
9777 if(cmpSeverities($S1, $S2)) {
9778 return $S1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009779 }
9780 else {
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04009781 return $S2;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009782 }
9783}
9784
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04009785sub cmpSeverities($$)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009786{
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04009787 my ($S1, $S2) = @_;
9788 if(not $S1) {
9789 return 0;
9790 }
9791 elsif(not $S2) {
9792 return 1;
9793 }
9794 return ($Severity_Val{$S1}>$Severity_Val{$S2});
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009795}
9796
9797sub getProblemSeverity($$)
9798{
9799 my ($Level, $Kind) = @_;
9800 return $CompatRules{$Level}{$Kind}{"Severity"};
9801}
9802
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04009803sub isRecurType($$)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009804{
9805 foreach (@RecurTypes)
9806 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04009807 if( $_->{"T1"} eq $_[0]
9808 and $_->{"T2"} eq $_[1] )
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009809 {
9810 return 1;
9811 }
9812 }
9813 return 0;
9814}
9815
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04009816sub pushType($$)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009817{
9818 my %TypeIDs=(
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04009819 "T1" => $_[0], #Tid1
9820 "T2" => $_[1] #Tid2
Andrey Ponomarenko16934472012-03-29 15:37:04 +04009821 );
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009822 push(@RecurTypes, \%TypeIDs);
9823}
9824
9825sub isRenamed($$$$$)
9826{
9827 my ($MemPos, $Type1, $LVersion1, $Type2, $LVersion2) = @_;
9828 my $Member_Name = $Type1->{"Memb"}{$MemPos}{"name"};
9829 my $MemberType_Id = $Type1->{"Memb"}{$MemPos}{"type"};
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04009830 my %MemberType_Pure = get_PureType($MemberType_Id, $LVersion1);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009831 if(not defined $Type2->{"Memb"}{$MemPos}) {
9832 return "";
9833 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04009834 my $PairType_Id = $Type2->{"Memb"}{$MemPos}{"type"};
9835 my %PairType_Pure = get_PureType($PairType_Id, $LVersion2);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009836
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04009837 my $Pair_Name = $Type2->{"Memb"}{$MemPos}{"name"};
9838 my $MemberPair_Pos_Rev = ($Member_Name eq $Pair_Name)?$MemPos:find_MemberPair_Pos_byName($Pair_Name, $Type1);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009839 if($MemberPair_Pos_Rev eq "lost")
9840 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04009841 if($MemberType_Pure{"Name"} eq $PairType_Pure{"Name"})
9842 { # base type match
9843 return $Pair_Name;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009844 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04009845 if($TypeInfo{$LVersion1}{$MemberType_Id}{"Name"} eq $TypeInfo{$LVersion2}{$PairType_Id}{"Name"})
9846 { # exact type match
9847 return $Pair_Name;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009848 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04009849 if($MemberType_Pure{"Size"} eq $PairType_Pure{"Size"})
9850 { # size match
9851 return $Pair_Name;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009852 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04009853 if(isReserved($Pair_Name))
9854 { # reserved fields
9855 return $Pair_Name;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009856 }
9857 }
9858 return "";
9859}
9860
9861sub isLastElem($$)
9862{
9863 my ($Pos, $TypeRef) = @_;
9864 my $Name = $TypeRef->{"Memb"}{$Pos}{"name"};
9865 if($Name=~/last|count|max|total/i)
9866 { # GST_LEVEL_COUNT, GST_RTSP_ELAST
9867 return 1;
9868 }
9869 elsif($Name=~/END|NLIMITS\Z/)
9870 { # __RLIMIT_NLIMITS
9871 return 1;
9872 }
9873 elsif($Name=~/\AN[A-Z](.+)[a-z]+s\Z/
9874 and $Pos+1==keys(%{$TypeRef->{"Memb"}}))
9875 { # NImageFormats, NColorRoles
9876 return 1;
9877 }
9878 return 0;
9879}
9880
9881sub nonComparable($$)
9882{
9883 my ($T1, $T2) = @_;
9884 if($T1->{"Name"} ne $T2->{"Name"}
9885 and not isAnon($T1->{"Name"})
9886 and not isAnon($T2->{"Name"}))
9887 { # different names
9888 if($T1->{"Type"} ne "Pointer"
9889 or $T2->{"Type"} ne "Pointer")
9890 { # compare base types
9891 return 1;
9892 }
9893 if($T1->{"Name"}!~/\Avoid\s*\*/
9894 and $T2->{"Name"}=~/\Avoid\s*\*/)
9895 {
9896 return 1;
9897 }
9898 }
9899 elsif($T1->{"Type"} ne $T2->{"Type"})
9900 { # different types
9901 if($T1->{"Type"} eq "Class"
9902 and $T2->{"Type"} eq "Struct")
9903 { # "class" to "struct"
9904 return 0;
9905 }
9906 elsif($T2->{"Type"} eq "Class"
9907 and $T1->{"Type"} eq "Struct")
9908 { # "struct" to "class"
9909 return 0;
9910 }
9911 else
9912 { # "class" to "enum"
9913 # "union" to "class"
9914 # ...
9915 return 1;
9916 }
9917 }
9918 return 0;
9919}
9920
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04009921sub mergeTypes($$$)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009922{
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04009923 my ($Type1_Id, $Type2_Id, $Level) = @_;
9924 return () if(not $Type1_Id or not $Type2_Id);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009925 my (%Sub_SubProblems, %SubProblems) = ();
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04009926 if($Cache{"mergeTypes"}{$Level}{$Type1_Id}{$Type2_Id})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009927 { # already merged
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04009928 return %{$Cache{"mergeTypes"}{$Level}{$Type1_Id}{$Type2_Id}};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009929 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04009930 my %Type1 = get_Type($Type1_Id, 1);
9931 my %Type2 = get_Type($Type2_Id, 2);
Andrey Ponomarenko16934472012-03-29 15:37:04 +04009932 if(not $Type1{"Name"} or not $Type2{"Name"}) {
9933 return ();
9934 }
9935 $CheckedTypes{$Level}{$Type1{"Name"}}=1;
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04009936 my %Type1_Pure = get_PureType($Type1_Id, 1);
9937 my %Type2_Pure = get_PureType($Type2_Id, 2);
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04009938 $CheckedTypes{$Level}{$Type1_Pure{"Name"}}=1;
Andrey Ponomarenko85043792012-05-14 16:48:07 +04009939 if(not $Type1_Pure{"Size"} or not $Type2_Pure{"Size"})
9940 { # including a case when "class Class { ... };" changed to "class Class;"
9941 return ();
9942 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04009943 if(isRecurType($Type1_Pure{"Tid"}, $Type2_Pure{"Tid"}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009944 { # skip recursive declarations
9945 return ();
9946 }
9947 return () if(not $Type1_Pure{"Name"} or not $Type2_Pure{"Name"});
9948 return () if($SkipTypes{1}{$Type1_Pure{"Name"}});
9949 return () if($SkipTypes{1}{$Type1{"Name"}});
9950
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04009951 my %Typedef_1 = goToFirst($Type1{"Tid"}, 1, "Typedef");
9952 my %Typedef_2 = goToFirst($Type2{"Tid"}, 2, "Typedef");
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04009953 if(not $UseOldDumps and %Typedef_1 and %Typedef_2
9954 and $Typedef_1{"Type"} eq "Typedef" and $Typedef_2{"Type"} eq "Typedef"
9955 and $Typedef_1{"Name"} eq $Typedef_2{"Name"})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009956 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04009957 my %Base_1 = get_OneStep_BaseType($Typedef_1{"Tid"}, 1);
9958 my %Base_2 = get_OneStep_BaseType($Typedef_2{"Tid"}, 2);
Andrey Ponomarenko85043792012-05-14 16:48:07 +04009959 if($Base_1{"Name"} ne $Base_2{"Name"})
9960 {
9961 if(differentDumps("G")
9962 or differentDumps("V"))
9963 { # different GCC versions or different dumps
9964 $Base_1{"Name"} = uncover_typedefs($Base_1{"Name"}, 1);
9965 $Base_2{"Name"} = uncover_typedefs($Base_2{"Name"}, 2);
9966 # std::__va_list and __va_list
9967 $Base_1{"Name"}=~s/\A(\w+::)+//;
9968 $Base_2{"Name"}=~s/\A(\w+::)+//;
9969 $Base_1{"Name"} = formatName($Base_1{"Name"});
9970 $Base_2{"Name"} = formatName($Base_2{"Name"});
9971 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009972 }
9973 if($Base_1{"Name"}!~/anon\-/ and $Base_2{"Name"}!~/anon\-/
9974 and $Base_1{"Name"} ne $Base_2{"Name"})
9975 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04009976 if($Level eq "Binary"
9977 and $Type1{"Size"} ne $Type2{"Size"})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009978 {
9979 %{$SubProblems{"DataType_Size"}{$Typedef_1{"Name"}}}=(
9980 "Target"=>$Typedef_1{"Name"},
9981 "Type_Name"=>$Typedef_1{"Name"},
9982 "Type_Type"=>"Typedef",
9983 "Old_Size"=>$Type1{"Size"}*$BYTE_SIZE,
9984 "New_Size"=>$Type2{"Size"}*$BYTE_SIZE );
9985 }
9986 %{$SubProblems{"Typedef_BaseType"}{$Typedef_1{"Name"}}}=(
9987 "Target"=>$Typedef_1{"Name"},
9988 "Type_Name"=>$Typedef_1{"Name"},
9989 "Type_Type"=>"Typedef",
9990 "Old_Value"=>$Base_1{"Name"},
9991 "New_Value"=>$Base_2{"Name"} );
9992 }
9993 }
9994 if(nonComparable(\%Type1_Pure, \%Type2_Pure))
9995 { # different types (reported in detectTypeChange(...))
9996 if($Type1_Pure{"Name"} eq $Type2_Pure{"Name"}
9997 and $Type1_Pure{"Type"} ne $Type2_Pure{"Type"}
9998 and $Type1_Pure{"Type"}!~/Intrinsic|Pointer|Ref|Typedef/)
9999 { # different type of the type
10000 %{$SubProblems{"DataType_Type"}{$Type1_Pure{"Name"}}}=(
10001 "Target"=>$Type1_Pure{"Name"},
10002 "Type_Name"=>$Type1_Pure{"Name"},
10003 "Type_Type"=>$Type1_Pure{"Type"},
10004 "Old_Value"=>lc($Type1_Pure{"Type"}),
10005 "New_Value"=>lc($Type2_Pure{"Type"}) );
10006 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040010007 %{$Cache{"mergeTypes"}{$Level}{$Type1_Id}{$Type2_Id}} = %SubProblems;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010008 return %SubProblems;
10009 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040010010 pushType($Type1_Pure{"Tid"}, $Type2_Pure{"Tid"});
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010011 if(($Type1_Pure{"Name"} eq $Type2_Pure{"Name"}
10012 or (isAnon($Type1_Pure{"Name"}) and isAnon($Type2_Pure{"Name"})))
10013 and $Type1_Pure{"Type"}=~/\A(Struct|Class|Union)\Z/)
10014 { # checking size
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040010015 if($Level eq "Binary"
10016 and $Type1_Pure{"Size"} ne $Type2_Pure{"Size"})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010017 {
10018 my $ProblemKind = "DataType_Size";
10019 if($Type1_Pure{"Type"} eq "Class"
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040010020 and keys(%{$ClassMethods{$Level}{1}{$Type1_Pure{"Name"}}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010021 {
10022 if(isCopyingClass($Type1_Pure{"Tid"}, 1)) {
10023 $ProblemKind = "Size_Of_Copying_Class";
10024 }
10025 elsif($AllocableClass{1}{$Type1_Pure{"Name"}})
10026 {
10027 if(int($Type2_Pure{"Size"})>int($Type1_Pure{"Size"})) {
10028 $ProblemKind = "Size_Of_Allocable_Class_Increased";
10029 }
10030 else {
10031 # descreased size of allocable class
10032 # it has no special effects
10033 }
10034 }
10035 }
10036 %{$SubProblems{$ProblemKind}{$Type1_Pure{"Name"}}}=(
10037 "Target"=>$Type1_Pure{"Name"},
10038 "Type_Name"=>$Type1_Pure{"Name"},
10039 "Type_Type"=>$Type1_Pure{"Type"},
10040 "Old_Size"=>$Type1_Pure{"Size"}*$BYTE_SIZE,
10041 "New_Size"=>$Type2_Pure{"Size"}*$BYTE_SIZE,
10042 "InitialType_Type"=>$Type1_Pure{"Type"} );
10043 }
10044 }
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040010045 if(defined $Type1_Pure{"BaseType"} and $Type1_Pure{"BaseType"}{"Tid"}
10046 and defined $Type2_Pure{"BaseType"} and $Type2_Pure{"BaseType"}{"Tid"})
10047 { # checking base types
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040010048 %Sub_SubProblems = mergeTypes($Type1_Pure{"BaseType"}{"Tid"}, $Type2_Pure{"BaseType"}{"Tid"}, $Level);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010049 foreach my $Sub_SubProblemType (keys(%Sub_SubProblems))
10050 {
10051 foreach my $Sub_SubLocation (keys(%{$Sub_SubProblems{$Sub_SubProblemType}}))
10052 {
10053 foreach my $Attr (keys(%{$Sub_SubProblems{$Sub_SubProblemType}{$Sub_SubLocation}})) {
10054 $SubProblems{$Sub_SubProblemType}{$Sub_SubLocation}{$Attr} = $Sub_SubProblems{$Sub_SubProblemType}{$Sub_SubLocation}{$Attr};
10055 }
10056 $SubProblems{$Sub_SubProblemType}{$Sub_SubLocation}{"InitialType_Type"} = $Type1_Pure{"Type"};
10057 }
10058 }
10059 }
10060 my (%AddedField, %RemovedField, %RenamedField, %RenamedField_Rev, %RelatedField, %RelatedField_Rev) = ();
10061 my %NameToPosA = map {$Type1_Pure{"Memb"}{$_}{"name"}=>$_} keys(%{$Type1_Pure{"Memb"}});
10062 my %NameToPosB = map {$Type2_Pure{"Memb"}{$_}{"name"}=>$_} keys(%{$Type2_Pure{"Memb"}});
10063 foreach my $Member_Pos (sort {int($a) <=> int($b)} keys(%{$Type1_Pure{"Memb"}}))
10064 { # detect removed and renamed fields
10065 my $Member_Name = $Type1_Pure{"Memb"}{$Member_Pos}{"name"};
10066 next if(not $Member_Name);
10067 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);
10068 if($MemberPair_Pos eq "lost")
10069 {
10070 if($Type2_Pure{"Type"}=~/\A(Struct|Class|Union)\Z/)
10071 {
10072 if(isUnnamed($Member_Name))
10073 { # support for old-version dumps
10074 # unnamed fields have been introduced in the ACC 1.23 (dump 2.1 format)
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040010075 if(not checkDump(2, "2.1")) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010076 next;
10077 }
10078 }
10079 if(my $RenamedTo = isRenamed($Member_Pos, \%Type1_Pure, 1, \%Type2_Pure, 2))
10080 { # renamed
10081 $RenamedField{$Member_Pos}=$RenamedTo;
10082 $RenamedField_Rev{$NameToPosB{$RenamedTo}}=$Member_Name;
10083 }
10084 else
10085 { # removed
10086 $RemovedField{$Member_Pos}=1;
10087 }
10088 }
10089 elsif($Type1_Pure{"Type"} eq "Enum")
10090 {
10091 my $Member_Value1 = $Type1_Pure{"Memb"}{$Member_Pos}{"value"};
10092 next if($Member_Value1 eq "");
10093 $MemberPair_Pos = find_MemberPair_Pos_byVal($Member_Value1, \%Type2_Pure);
10094 if($MemberPair_Pos ne "lost")
10095 { # renamed
10096 my $RenamedTo = $Type2_Pure{"Memb"}{$MemberPair_Pos}{"name"};
10097 my $MemberPair_Pos_Rev = find_MemberPair_Pos_byName($RenamedTo, \%Type1_Pure);
10098 if($MemberPair_Pos_Rev eq "lost")
10099 {
10100 $RenamedField{$Member_Pos}=$RenamedTo;
10101 $RenamedField_Rev{$NameToPosB{$RenamedTo}}=$Member_Name;
10102 }
10103 else {
10104 $RemovedField{$Member_Pos}=1;
10105 }
10106 }
10107 else
10108 { # removed
10109 $RemovedField{$Member_Pos}=1;
10110 }
10111 }
10112 }
10113 else
10114 { # related
10115 $RelatedField{$Member_Pos} = $MemberPair_Pos;
10116 $RelatedField_Rev{$MemberPair_Pos} = $Member_Pos;
10117 }
10118 }
10119 foreach my $Member_Pos (sort {int($a) <=> int($b)} keys(%{$Type2_Pure{"Memb"}}))
10120 { # detect added fields
10121 my $Member_Name = $Type2_Pure{"Memb"}{$Member_Pos}{"name"};
10122 next if(not $Member_Name);
10123 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);
10124 if($MemberPair_Pos eq "lost")
10125 {
10126 if(isUnnamed($Member_Name))
10127 { # support for old-version dumps
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040010128 # unnamed fields have been introduced in the ACC 1.23 (dump 2.1 format)
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040010129 if(not checkDump(1, "2.1")) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010130 next;
10131 }
10132 }
10133 if($Type2_Pure{"Type"}=~/\A(Struct|Class|Union|Enum)\Z/)
10134 {
10135 if(not $RenamedField_Rev{$Member_Pos})
10136 { # added
10137 $AddedField{$Member_Pos}=1;
10138 }
10139 }
10140 }
10141 }
10142 if($Type2_Pure{"Type"}=~/\A(Struct|Class)\Z/)
10143 { # detect moved fields
10144 my (%RelPos, %RelPosName, %AbsPos) = ();
10145 my $Pos = 0;
10146 foreach my $Member_Pos (sort {int($a) <=> int($b)} keys(%{$Type1_Pure{"Memb"}}))
10147 { # relative positions in 1st version
10148 my $Member_Name = $Type1_Pure{"Memb"}{$Member_Pos}{"name"};
10149 next if(not $Member_Name);
10150 if(not $RemovedField{$Member_Pos})
10151 { # old type without removed fields
10152 $RelPos{1}{$Member_Name}=$Pos;
10153 $RelPosName{1}{$Pos} = $Member_Name;
10154 $AbsPos{1}{$Pos++} = $Member_Pos;
10155 }
10156 }
10157 $Pos = 0;
10158 foreach my $Member_Pos (sort {int($a) <=> int($b)} keys(%{$Type2_Pure{"Memb"}}))
10159 { # relative positions in 2nd version
10160 my $Member_Name = $Type2_Pure{"Memb"}{$Member_Pos}{"name"};
10161 next if(not $Member_Name);
10162 if(not $AddedField{$Member_Pos})
10163 { # new type without added fields
10164 $RelPos{2}{$Member_Name}=$Pos;
10165 $RelPosName{2}{$Pos} = $Member_Name;
10166 $AbsPos{2}{$Pos++} = $Member_Pos;
10167 }
10168 }
10169 foreach my $Member_Name (keys(%{$RelPos{1}}))
10170 {
10171 my $RPos1 = $RelPos{1}{$Member_Name};
10172 my $AbsPos1 = $NameToPosA{$Member_Name};
10173 my $Member_Name2 = $Member_Name;
10174 if(my $RenamedTo = $RenamedField{$AbsPos1})
10175 { # renamed
10176 $Member_Name2 = $RenamedTo;
10177 }
10178 my $RPos2 = $RelPos{2}{$Member_Name2};
10179 if($RPos2 ne "" and $RPos1 ne $RPos2)
10180 { # different relative positions
10181 my $AbsPos2 = $NameToPosB{$Member_Name2};
10182 if($AbsPos1 ne $AbsPos2)
10183 { # different absolute positions
10184 my $ProblemType = "Moved_Field";
10185 if(not isPublic(\%Type1_Pure, $AbsPos1))
10186 { # may change layout and size of type
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040010187 if($Level eq "Source") {
10188 next;
10189 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010190 $ProblemType = "Moved_Private_Field";
10191 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040010192 if($Level eq "Binary"
10193 and $Type1_Pure{"Size"} ne $Type2_Pure{"Size"})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010194 { # affected size
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040010195 my $MemSize1 = $TypeInfo{1}{$Type1_Pure{"Memb"}{$AbsPos1}{"type"}}{"Size"};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010196 my $MovedAbsPos = $AbsPos{1}{$RPos2};
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040010197 my $MemSize2 = $TypeInfo{1}{$Type1_Pure{"Memb"}{$MovedAbsPos}{"type"}}{"Size"};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010198 if($MemSize1 ne $MemSize2) {
10199 $ProblemType .= "_And_Size";
10200 }
10201 }
10202 if($ProblemType eq "Moved_Private_Field") {
10203 next;
10204 }
10205 %{$SubProblems{$ProblemType}{$Member_Name}}=(
10206 "Target"=>$Member_Name,
10207 "Type_Name"=>$Type1_Pure{"Name"},
10208 "Type_Type"=>$Type1_Pure{"Type"},
10209 "Old_Value"=>$RPos1,
10210 "New_Value"=>$RPos2 );
10211 }
10212 }
10213 }
10214 }
10215 foreach my $Member_Pos (sort {int($a) <=> int($b)} keys(%{$Type1_Pure{"Memb"}}))
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040010216 { # check older fields, public and private
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010217 my $Member_Name = $Type1_Pure{"Memb"}{$Member_Pos}{"name"};
10218 next if(not $Member_Name);
10219 if(my $RenamedTo = $RenamedField{$Member_Pos})
10220 { # renamed
10221 if($Type2_Pure{"Type"}=~/\A(Struct|Class|Union)\Z/)
10222 {
10223 if(isPublic(\%Type1_Pure, $Member_Pos))
10224 {
10225 %{$SubProblems{"Renamed_Field"}{$Member_Name}}=(
10226 "Target"=>$Member_Name,
10227 "Type_Name"=>$Type1_Pure{"Name"},
10228 "Type_Type"=>$Type1_Pure{"Type"},
10229 "Old_Value"=>$Member_Name,
10230 "New_Value"=>$RenamedTo );
10231 }
10232 }
10233 elsif($Type1_Pure{"Type"} eq "Enum")
10234 {
10235 %{$SubProblems{"Enum_Member_Name"}{$Type1_Pure{"Memb"}{$Member_Pos}{"value"}}}=(
10236 "Target"=>$Type1_Pure{"Memb"}{$Member_Pos}{"value"},
10237 "Type_Name"=>$Type1_Pure{"Name"},
10238 "Type_Type"=>$Type1_Pure{"Type"},
10239 "Old_Value"=>$Member_Name,
10240 "New_Value"=>$RenamedTo );
10241 }
10242 }
10243 elsif($RemovedField{$Member_Pos})
10244 { # removed
10245 if($Type2_Pure{"Type"}=~/\A(Struct|Class)\Z/)
10246 {
10247 my $ProblemType = "Removed_Field";
10248 if(not isPublic(\%Type1_Pure, $Member_Pos)
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040010249 or isUnnamed($Member_Name))
10250 {
10251 if($Level eq "Source") {
10252 next;
10253 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010254 $ProblemType = "Removed_Private_Field";
10255 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040010256 if($Level eq "Binary"
10257 and not isMemPadded($Member_Pos, -1, \%Type1_Pure, \%RemovedField, 1))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010258 {
10259 if(my $MNum = isAccessible(\%Type1_Pure, \%RemovedField, $Member_Pos+1, -1))
10260 { # affected fields
10261 if(getOffset($MNum-1, \%Type1_Pure, 1)!=getOffset($RelatedField{$MNum-1}, \%Type2_Pure, 2))
10262 { # changed offset
10263 $ProblemType .= "_And_Layout";
10264 }
10265 }
10266 if($Type1_Pure{"Size"} ne $Type2_Pure{"Size"})
10267 { # affected size
10268 $ProblemType .= "_And_Size";
10269 }
10270 }
10271 if($ProblemType eq "Removed_Private_Field") {
10272 next;
10273 }
10274 %{$SubProblems{$ProblemType}{$Member_Name}}=(
10275 "Target"=>$Member_Name,
10276 "Type_Name"=>$Type1_Pure{"Name"},
10277 "Type_Type"=>$Type1_Pure{"Type"} );
10278 }
10279 elsif($Type2_Pure{"Type"} eq "Union")
10280 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040010281 if($Level eq "Binary"
10282 and $Type1_Pure{"Size"} ne $Type2_Pure{"Size"})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010283 {
10284 %{$SubProblems{"Removed_Union_Field_And_Size"}{$Member_Name}}=(
10285 "Target"=>$Member_Name,
10286 "Type_Name"=>$Type1_Pure{"Name"},
10287 "Type_Type"=>$Type1_Pure{"Type"} );
10288 }
10289 else
10290 {
10291 %{$SubProblems{"Removed_Union_Field"}{$Member_Name}}=(
10292 "Target"=>$Member_Name,
10293 "Type_Name"=>$Type1_Pure{"Name"},
10294 "Type_Type"=>$Type1_Pure{"Type"} );
10295 }
10296 }
10297 elsif($Type1_Pure{"Type"} eq "Enum")
10298 {
10299 %{$SubProblems{"Enum_Member_Removed"}{$Member_Name}}=(
10300 "Target"=>$Member_Name,
10301 "Type_Name"=>$Type1_Pure{"Name"},
10302 "Type_Type"=>$Type1_Pure{"Type"},
10303 "Old_Value"=>$Member_Name );
10304 }
10305 }
10306 else
10307 { # changed
10308 my $MemberPair_Pos = $RelatedField{$Member_Pos};
10309 if($Type1_Pure{"Type"} eq "Enum")
10310 {
10311 my $Member_Value1 = $Type1_Pure{"Memb"}{$Member_Pos}{"value"};
10312 next if($Member_Value1 eq "");
10313 my $Member_Value2 = $Type2_Pure{"Memb"}{$MemberPair_Pos}{"value"};
10314 next if($Member_Value2 eq "");
10315 if($Member_Value1 ne $Member_Value2)
10316 {
10317 my $ProblemType = "Enum_Member_Value";
10318 if(isLastElem($Member_Pos, \%Type1_Pure)) {
10319 $ProblemType = "Enum_Last_Member_Value";
10320 }
10321 %{$SubProblems{$ProblemType}{$Member_Name}}=(
10322 "Target"=>$Member_Name,
10323 "Type_Name"=>$Type1_Pure{"Name"},
10324 "Type_Type"=>$Type1_Pure{"Type"},
10325 "Old_Value"=>$Member_Value1,
10326 "New_Value"=>$Member_Value2 );
10327 }
10328 }
10329 elsif($Type2_Pure{"Type"}=~/\A(Struct|Class|Union)\Z/)
10330 {
10331 my $MemberType1_Id = $Type1_Pure{"Memb"}{$Member_Pos}{"type"};
10332 my $MemberType2_Id = $Type2_Pure{"Memb"}{$MemberPair_Pos}{"type"};
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040010333 my $SizeV1 = $TypeInfo{1}{$MemberType1_Id}{"Size"}*$BYTE_SIZE;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010334 if(my $BSize1 = $Type1_Pure{"Memb"}{$Member_Pos}{"bitfield"}) {
10335 $SizeV1 = $BSize1;
10336 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040010337 my $SizeV2 = $TypeInfo{2}{$MemberType2_Id}{"Size"}*$BYTE_SIZE;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010338 if(my $BSize2 = $Type2_Pure{"Memb"}{$MemberPair_Pos}{"bitfield"}) {
10339 $SizeV2 = $BSize2;
10340 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040010341 my $MemberType1_Name = $TypeInfo{1}{$MemberType1_Id}{"Name"};
10342 my $MemberType2_Name = $TypeInfo{2}{$MemberType2_Id}{"Name"};
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040010343 if($Level eq "Binary"
10344 and $SizeV1 ne $SizeV2)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010345 {
10346 if($MemberType1_Name eq $MemberType2_Name or (isAnon($MemberType1_Name) and isAnon($MemberType2_Name))
10347 or ($Type1_Pure{"Memb"}{$Member_Pos}{"bitfield"} and $Type2_Pure{"Memb"}{$MemberPair_Pos}{"bitfield"}))
10348 { # field size change (including anon-structures and unions)
10349 # - same types
10350 # - unnamed types
10351 # - bitfields
10352 my $ProblemType = "Field_Size";
10353 if(not isPublic(\%Type1_Pure, $Member_Pos)
10354 or isUnnamed($Member_Name))
10355 { # should not be accessed by applications, goes to "Low Severity"
10356 # example: "abidata" members in GStreamer types
10357 $ProblemType = "Private_".$ProblemType;
10358 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040010359 if(not isMemPadded($Member_Pos, $TypeInfo{2}{$MemberType2_Id}{"Size"}*$BYTE_SIZE, \%Type1_Pure, \%RemovedField, 1))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010360 { # check an effect
10361 if(my $MNum = isAccessible(\%Type1_Pure, \%RemovedField, $Member_Pos+1, -1))
10362 { # public fields after the current
10363 if(getOffset($MNum-1, \%Type1_Pure, 1)!=getOffset($RelatedField{$MNum-1}, \%Type2_Pure, 2))
10364 { # changed offset
10365 $ProblemType .= "_And_Layout";
10366 }
10367 }
10368 if($Type1_Pure{"Size"} ne $Type2_Pure{"Size"}) {
10369 $ProblemType .= "_And_Type_Size";
10370 }
10371 }
10372 if($ProblemType eq "Private_Field_Size")
10373 { # private field size with no effect
10374 $ProblemType = "";
10375 }
10376 if($ProblemType)
10377 { # register a problem
10378 %{$SubProblems{$ProblemType}{$Member_Name}}=(
10379 "Target"=>$Member_Name,
10380 "Type_Name"=>$Type1_Pure{"Name"},
10381 "Type_Type"=>$Type1_Pure{"Type"},
10382 "Old_Size"=>$SizeV1,
10383 "New_Size"=>$SizeV2);
10384 }
10385 }
10386 }
10387 if($Type1_Pure{"Memb"}{$Member_Pos}{"bitfield"}
10388 or $Type2_Pure{"Memb"}{$MemberPair_Pos}{"bitfield"})
10389 { # do NOT check bitfield type changes
10390 next;
10391 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040010392 if(checkDump(1, "2.13") and checkDump(2, "2.13"))
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040010393 {
10394 if(not $Type1_Pure{"Memb"}{$Member_Pos}{"mutable"}
10395 and $Type2_Pure{"Memb"}{$MemberPair_Pos}{"mutable"})
10396 {
10397 %{$SubProblems{"Field_Became_Mutable"}{$Member_Name}}=(
10398 "Target"=>$Member_Name,
10399 "Type_Name"=>$Type1_Pure{"Name"},
10400 "Type_Type"=>$Type1_Pure{"Type"});
10401 }
10402 elsif($Type1_Pure{"Memb"}{$Member_Pos}{"mutable"}
10403 and not $Type2_Pure{"Memb"}{$MemberPair_Pos}{"mutable"})
10404 {
10405 %{$SubProblems{"Field_Became_NonMutable"}{$Member_Name}}=(
10406 "Target"=>$Member_Name,
10407 "Type_Name"=>$Type1_Pure{"Name"},
10408 "Type_Type"=>$Type1_Pure{"Type"});
10409 }
10410 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040010411 %Sub_SubProblems = detectTypeChange($MemberType1_Id, $MemberType2_Id, "Field", $Level);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010412 foreach my $ProblemType (keys(%Sub_SubProblems))
10413 {
10414 my $Old_Value = $Sub_SubProblems{$ProblemType}{"Old_Value"};
10415 my $New_Value = $Sub_SubProblems{$ProblemType}{"New_Value"};
10416 if($ProblemType eq "Field_Type"
10417 or $ProblemType eq "Field_Type_And_Size")
10418 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040010419 if(checkDump(1, "2.6") and checkDump(2, "2.6"))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010420 {
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040010421 if(my $RA = addedQual($Old_Value, $New_Value, "volatile"))
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040010422 {
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040010423 %{$Sub_SubProblems{"Field_Became_Volatile"}} = %{$Sub_SubProblems{$ProblemType}};
10424 if($Level eq "Source"
10425 and cmpBTypes($Old_Value, $New_Value, 1, 2)) {
10426 delete($Sub_SubProblems{$ProblemType});
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040010427 }
10428 }
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040010429 elsif(my $RR = removedQual($Old_Value, $New_Value, "volatile"))
10430 {
10431 %{$Sub_SubProblems{"Field_Became_NonVolatile"}} = %{$Sub_SubProblems{$ProblemType}};
10432 if($Level eq "Source"
10433 and cmpBTypes($Old_Value, $New_Value, 1, 2)) {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040010434 delete($Sub_SubProblems{$ProblemType});
10435 }
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040010436 }
10437 }
10438 if(my $RA = addedQual($Old_Value, $New_Value, "const"))
10439 {
10440 if($RA==2) {
10441 %{$Sub_SubProblems{"Field_Added_Const"}} = %{$Sub_SubProblems{$ProblemType}};
10442 }
10443 else {
10444 %{$Sub_SubProblems{"Field_Became_Const"}} = %{$Sub_SubProblems{$ProblemType}};
10445 }
10446 if($Level eq "Source"
10447 and cmpBTypes($Old_Value, $New_Value, 1, 2)) {
10448 delete($Sub_SubProblems{$ProblemType});
10449 }
10450 }
10451 elsif(my $RR = removedQual($Old_Value, $New_Value, "const"))
10452 {
10453 if($RR==2) {
10454 %{$Sub_SubProblems{"Field_Removed_Const"}} = %{$Sub_SubProblems{$ProblemType}};
10455 }
10456 else {
10457 %{$Sub_SubProblems{"Field_Became_NonConst"}} = %{$Sub_SubProblems{$ProblemType}};
10458 }
10459 if($Level eq "Source"
10460 and cmpBTypes($Old_Value, $New_Value, 1, 2)) {
10461 delete($Sub_SubProblems{$ProblemType});
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010462 }
10463 }
10464 }
10465 }
10466 foreach my $ProblemType (keys(%Sub_SubProblems))
10467 {
10468 my $ProblemType_Init = $ProblemType;
10469 if($ProblemType eq "Field_Type_And_Size")
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040010470 { # Binary
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010471 if(not isPublic(\%Type1_Pure, $Member_Pos)
10472 or isUnnamed($Member_Name)) {
10473 $ProblemType = "Private_".$ProblemType;
10474 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040010475 if(not isMemPadded($Member_Pos, $TypeInfo{2}{$MemberType2_Id}{"Size"}*$BYTE_SIZE, \%Type1_Pure, \%RemovedField, 1))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010476 { # check an effect
10477 if(my $MNum = isAccessible(\%Type1_Pure, \%RemovedField, $Member_Pos+1, -1))
10478 { # public fields after the current
10479 if(getOffset($MNum-1, \%Type1_Pure, 1)!=getOffset($RelatedField{$MNum-1}, \%Type2_Pure, 2))
10480 { # changed offset
10481 $ProblemType .= "_And_Layout";
10482 }
10483 }
10484 if($Type1_Pure{"Size"} ne $Type2_Pure{"Size"}) {
10485 $ProblemType .= "_And_Type_Size";
10486 }
10487 }
10488 }
10489 else
10490 {
10491 if(not isPublic(\%Type1_Pure, $Member_Pos)
10492 or isUnnamed($Member_Name)) {
10493 next;
10494 }
10495 }
10496 if($ProblemType eq "Private_Field_Type_And_Size")
10497 { # private field change with no effect
10498 next;
10499 }
10500 %{$SubProblems{$ProblemType}{$Member_Name}}=(
10501 "Target"=>$Member_Name,
10502 "Type_Name"=>$Type1_Pure{"Name"},
10503 "Type_Type"=>$Type1_Pure{"Type"} );
10504 foreach my $Attr (keys(%{$Sub_SubProblems{$ProblemType_Init}}))
10505 { # other properties
10506 $SubProblems{$ProblemType}{$Member_Name}{$Attr} = $Sub_SubProblems{$ProblemType_Init}{$Attr};
10507 }
10508 }
10509 if(not isPublic(\%Type1_Pure, $Member_Pos))
10510 { # do NOT check internal type changes
10511 next;
10512 }
10513 if($MemberType1_Id and $MemberType2_Id)
10514 {# checking member type changes (replace)
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040010515 %Sub_SubProblems = mergeTypes($MemberType1_Id, $MemberType2_Id, $Level);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010516 foreach my $Sub_SubProblemType (keys(%Sub_SubProblems))
10517 {
10518 foreach my $Sub_SubLocation (keys(%{$Sub_SubProblems{$Sub_SubProblemType}}))
10519 {
10520 my $NewLocation = ($Sub_SubLocation)?$Member_Name."->".$Sub_SubLocation:$Member_Name;
10521 $SubProblems{$Sub_SubProblemType}{$NewLocation}{"IsInTypeInternals"}=1;
10522 foreach my $Attr (keys(%{$Sub_SubProblems{$Sub_SubProblemType}{$Sub_SubLocation}})) {
10523 $SubProblems{$Sub_SubProblemType}{$NewLocation}{$Attr} = $Sub_SubProblems{$Sub_SubProblemType}{$Sub_SubLocation}{$Attr};
10524 }
10525 if($Sub_SubLocation!~/\-\>/) {
10526 $SubProblems{$Sub_SubProblemType}{$NewLocation}{"Start_Type_Name"} = $MemberType1_Name;
10527 }
10528 }
10529 }
10530 }
10531 }
10532 }
10533 }
10534 foreach my $Member_Pos (sort {int($a) <=> int($b)} keys(%{$Type2_Pure{"Memb"}}))
10535 { # checking added members, public and private
10536 my $Member_Name = $Type2_Pure{"Memb"}{$Member_Pos}{"name"};
10537 next if(not $Member_Name);
10538 if($AddedField{$Member_Pos})
10539 { # added
10540 if($Type2_Pure{"Type"}=~/\A(Struct|Class)\Z/)
10541 {
10542 my $ProblemType = "Added_Field";
10543 if(not isPublic(\%Type2_Pure, $Member_Pos)
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040010544 or isUnnamed($Member_Name))
10545 {
10546 if($Level eq "Source") {
10547 next;
10548 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010549 $ProblemType = "Added_Private_Field";
10550 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040010551 if($Level eq "Binary"
10552 and not isMemPadded($Member_Pos, -1, \%Type2_Pure, \%AddedField, 2))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010553 {
10554 if(my $MNum = isAccessible(\%Type2_Pure, \%AddedField, $Member_Pos, -1))
10555 { # public fields after the current
10556 if(getOffset($MNum-1, \%Type2_Pure, 2)!=getOffset($RelatedField_Rev{$MNum-1}, \%Type1_Pure, 1))
10557 { # changed offset
10558 $ProblemType .= "_And_Layout";
10559 }
10560 }
10561 if($Type1_Pure{"Size"} ne $Type2_Pure{"Size"}) {
10562 $ProblemType .= "_And_Size";
10563 }
10564 }
10565 if($ProblemType eq "Added_Private_Field")
10566 { # skip added private fields
10567 next;
10568 }
10569 %{$SubProblems{$ProblemType}{$Member_Name}}=(
10570 "Target"=>$Member_Name,
10571 "Type_Name"=>$Type1_Pure{"Name"},
10572 "Type_Type"=>$Type1_Pure{"Type"} );
10573 }
10574 elsif($Type2_Pure{"Type"} eq "Union")
10575 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040010576 if($Level eq "Binary"
10577 and $Type1_Pure{"Size"} ne $Type2_Pure{"Size"})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010578 {
10579 %{$SubProblems{"Added_Union_Field_And_Size"}{$Member_Name}}=(
10580 "Target"=>$Member_Name,
10581 "Type_Name"=>$Type1_Pure{"Name"},
10582 "Type_Type"=>$Type1_Pure{"Type"} );
10583 }
10584 else
10585 {
10586 %{$SubProblems{"Added_Union_Field"}{$Member_Name}}=(
10587 "Target"=>$Member_Name,
10588 "Type_Name"=>$Type1_Pure{"Name"},
10589 "Type_Type"=>$Type1_Pure{"Type"} );
10590 }
10591 }
10592 elsif($Type2_Pure{"Type"} eq "Enum")
10593 {
10594 my $Member_Value = $Type2_Pure{"Memb"}{$Member_Pos}{"value"};
10595 next if($Member_Value eq "");
10596 %{$SubProblems{"Added_Enum_Member"}{$Member_Name}}=(
10597 "Target"=>$Member_Name,
10598 "Type_Name"=>$Type2_Pure{"Name"},
10599 "Type_Type"=>$Type2_Pure{"Type"},
10600 "New_Value"=>$Member_Value );
10601 }
10602 }
10603 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040010604 %{$Cache{"mergeTypes"}{$Level}{$Type1_Id}{$Type2_Id}} = %SubProblems;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010605 pop(@RecurTypes);
10606 return %SubProblems;
10607}
10608
10609sub isUnnamed($) {
10610 return $_[0]=~/\Aunnamed\d+\Z/;
10611}
10612
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040010613sub get_ShortType($$)
10614{
10615 my ($TypeId, $LibVersion) = @_;
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040010616 my $TypeName = $TypeInfo{$LibVersion}{$TypeId}{"Name"};
10617 if(my $NameSpace = $TypeInfo{$LibVersion}{$TypeId}{"NameSpace"}) {
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040010618 $TypeName=~s/\A$NameSpace\:\://g;
10619 }
10620 return $TypeName;
10621}
10622
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040010623sub goToFirst($$$)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010624{
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040010625 my ($TypeId, $LibVersion, $Type_Type) = @_;
Andrey Ponomarenko16934472012-03-29 15:37:04 +040010626 return () if(not $TypeId);
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040010627 if(defined $Cache{"goToFirst"}{$TypeId}{$LibVersion}{$Type_Type}) {
10628 return %{$Cache{"goToFirst"}{$TypeId}{$LibVersion}{$Type_Type}};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010629 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040010630 return () if(not $TypeInfo{$LibVersion}{$TypeId});
10631 my %Type = %{$TypeInfo{$LibVersion}{$TypeId}};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010632 return () if(not $Type{"Type"});
10633 if($Type{"Type"} ne $Type_Type)
10634 {
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040010635 return () if(not defined $Type{"BaseType"});
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040010636 return () if(not $Type{"BaseType"}{"Tid"});
10637 %Type = goToFirst($Type{"BaseType"}{"Tid"}, $LibVersion, $Type_Type);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010638 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040010639 $Cache{"goToFirst"}{$TypeId}{$LibVersion}{$Type_Type} = \%Type;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010640 return %Type;
10641}
10642
10643my %TypeSpecAttributes = (
10644 "Const" => 1,
10645 "Volatile" => 1,
10646 "ConstVolatile" => 1,
10647 "Restrict" => 1,
10648 "Typedef" => 1
10649);
10650
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040010651sub get_PureType($$)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010652{
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040010653 my ($TypeId, $LibVersion) = @_;
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040010654 return () if(not $TypeId);
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040010655 if(defined $Cache{"get_PureType"}{$TypeId}{$LibVersion}) {
10656 return %{$Cache{"get_PureType"}{$TypeId}{$LibVersion}};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010657 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040010658 return () if(not $TypeInfo{$LibVersion}{$TypeId});
10659 my %Type = %{$TypeInfo{$LibVersion}{$TypeId}};
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040010660 return %Type if(not defined $Type{"BaseType"});
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040010661 return %Type if(not $Type{"BaseType"}{"Tid"});
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010662 if($TypeSpecAttributes{$Type{"Type"}}) {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040010663 %Type = get_PureType($Type{"BaseType"}{"Tid"}, $LibVersion);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010664 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040010665 $Cache{"get_PureType"}{$TypeId}{$LibVersion} = \%Type;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010666 return %Type;
10667}
10668
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040010669sub get_PLevel($$)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010670{
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040010671 my ($TypeId, $LibVersion) = @_;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010672 return 0 if(not $TypeId);
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040010673 if(defined $Cache{"get_PLevel"}{$TypeId}{$LibVersion}) {
10674 return $Cache{"get_PLevel"}{$TypeId}{$LibVersion};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010675 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040010676 return 0 if(not $TypeInfo{$LibVersion}{$TypeId});
10677 my %Type = %{$TypeInfo{$LibVersion}{$TypeId}};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010678 return 1 if($Type{"Type"}=~/FuncPtr|MethodPtr|FieldPtr/);
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040010679 return 0 if(not defined $Type{"BaseType"});
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040010680 return 0 if(not $Type{"BaseType"}{"Tid"});
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010681 my $PointerLevel = 0;
10682 if($Type{"Type"} =~/Pointer|Ref|FuncPtr|MethodPtr|FieldPtr/) {
10683 $PointerLevel += 1;
10684 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040010685 $PointerLevel += get_PLevel($Type{"BaseType"}{"Tid"}, $LibVersion);
10686 $Cache{"get_PLevel"}{$TypeId}{$LibVersion} = $PointerLevel;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010687 return $PointerLevel;
10688}
10689
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040010690sub get_BaseType($$)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010691{
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040010692 my ($TypeId, $LibVersion) = @_;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010693 return () if(not $TypeId);
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040010694 if(defined $Cache{"get_BaseType"}{$TypeId}{$LibVersion}) {
10695 return %{$Cache{"get_BaseType"}{$TypeId}{$LibVersion}};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010696 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040010697 return () if(not $TypeInfo{$LibVersion}{$TypeId});
10698 my %Type = %{$TypeInfo{$LibVersion}{$TypeId}};
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040010699 return %Type if(not defined $Type{"BaseType"});
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040010700 return %Type if(not $Type{"BaseType"}{"Tid"});
10701 %Type = get_BaseType($Type{"BaseType"}{"Tid"}, $LibVersion);
10702 $Cache{"get_BaseType"}{$TypeId}{$LibVersion} = \%Type;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010703 return %Type;
10704}
10705
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040010706sub get_BaseTypeQual($$)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010707{
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040010708 my ($TypeId, $LibVersion) = @_;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010709 return "" if(not $TypeId);
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040010710 return "" if(not $TypeInfo{$LibVersion}{$TypeId});
10711 my %Type = %{$TypeInfo{$LibVersion}{$TypeId}};
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040010712 return "" if(not defined $Type{"BaseType"});
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040010713 return "" if(not $Type{"BaseType"}{"Tid"});
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010714 my $Qual = "";
10715 if($Type{"Type"} eq "Pointer") {
10716 $Qual .= "*";
10717 }
10718 elsif($Type{"Type"} eq "Ref") {
10719 $Qual .= "&";
10720 }
10721 elsif($Type{"Type"} eq "ConstVolatile") {
10722 $Qual .= "const volatile";
10723 }
10724 elsif($Type{"Type"} eq "Const"
10725 or $Type{"Type"} eq "Volatile"
10726 or $Type{"Type"} eq "Restrict") {
10727 $Qual .= lc($Type{"Type"});
10728 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040010729 my $BQual = get_BaseTypeQual($Type{"BaseType"}{"Tid"}, $LibVersion);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010730 return $BQual.$Qual;
10731}
10732
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040010733sub get_OneStep_BaseType($$)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010734{
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040010735 my ($TypeId, $LibVersion) = @_;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010736 return () if(not $TypeId);
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040010737 return () if(not $TypeInfo{$LibVersion}{$TypeId});
10738 my %Type = %{$TypeInfo{$LibVersion}{$TypeId}};
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040010739 return %Type if(not defined $Type{"BaseType"});
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040010740 return %Type if(not $Type{"BaseType"}{"Tid"});
10741 return get_Type($Type{"BaseType"}{"Tid"}, $LibVersion);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010742}
10743
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040010744sub get_Type($$)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010745{
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040010746 my ($TypeId, $LibVersion) = @_;
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040010747 return () if(not $TypeId);
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040010748 return () if(not $TypeInfo{$LibVersion}{$TypeId});
10749 return %{$TypeInfo{$LibVersion}{$TypeId}};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010750}
10751
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +040010752sub isPrivateData($)
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040010753{ # non-public global data
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010754 my $Symbol = $_[0];
10755 return ($Symbol=~/\A(_ZGV|_ZTI|_ZTS|_ZTT|_ZTV|_ZTC|_ZThn|_ZTv0_n)/);
10756}
10757
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040010758sub isTemplateInstance($$)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010759{
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040010760 my ($Symbol, $LibVersion) = @_;
10761 if($CheckObjectsOnly)
10762 {
10763 if($Symbol!~/\A(_Z|\?)/) {
10764 return 0;
10765 }
10766 if(my $Signature = $tr_name{$Symbol})
10767 {
10768 if(index($Signature,">")==-1) {
10769 return 0;
10770 }
10771 if(my $ShortName = substr($Signature, 0, find_center($Signature, "(")))
10772 {
10773 if($ShortName=~/<.+>/) {
10774 return 1;
10775 }
10776 }
10777 }
10778 }
10779 else
10780 {
10781 if(my $ClassId = $CompleteSignature{$LibVersion}{$Symbol}{"Class"})
10782 {
10783 if(my $ClassName = $TypeInfo{$LibVersion}{$ClassId}{"Name"})
10784 {
10785 if(index($ClassName,"<")!=-1) {
10786 return 1;
10787 }
10788 }
10789 }
10790 if(my $ShortName = $CompleteSignature{$LibVersion}{$Symbol}{"ShortName"})
10791 {
10792 if($ShortName=~/<.+>/) {
10793 return 1;
10794 }
10795 }
10796 }
10797 return 0;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010798}
10799
10800sub isTemplateSpec($$)
10801{
10802 my ($Symbol, $LibVersion) = @_;
10803 if(my $ClassId = $CompleteSignature{$LibVersion}{$Symbol}{"Class"})
10804 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040010805 if($TypeInfo{$LibVersion}{$ClassId}{"Spec"})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010806 { # class specialization
10807 return 1;
10808 }
10809 elsif($CompleteSignature{$LibVersion}{$Symbol}{"Spec"})
10810 { # method specialization
10811 return 1;
10812 }
10813 }
10814 return 0;
10815}
10816
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040010817sub symbolFilter($$$$)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010818{ # some special cases when the symbol cannot be imported
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040010819 my ($Symbol, $LibVersion, $Type, $Level) = @_;
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +040010820 if(isPrivateData($Symbol))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010821 { # non-public global data
10822 return 0;
10823 }
10824 if($CheckObjectsOnly) {
10825 return 0 if($Symbol=~/\A(_init|_fini)\Z/);
10826 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040010827 if($CheckHeadersOnly and not checkDump($LibVersion, "2.7"))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010828 { # support for old ABI dumps in --headers-only mode
10829 foreach my $Pos (keys(%{$CompleteSignature{$LibVersion}{$Symbol}{"Param"}}))
10830 {
10831 if(my $Pid = $CompleteSignature{$LibVersion}{$Symbol}{"Param"}{$Pos}{"type"})
10832 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040010833 my $PType = $TypeInfo{$LibVersion}{$Pid}{"Type"};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010834 if(not $PType or $PType eq "Unknown") {
10835 return 0;
10836 }
10837 }
10838 }
10839 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +040010840 if($Type=~/Affected/)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010841 {
10842 my $ClassId = $CompleteSignature{$LibVersion}{$Symbol}{"Class"};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010843 if($SkipSymbols{$LibVersion}{$Symbol})
10844 { # user defined symbols to ignore
10845 return 0;
10846 }
10847 my $NameSpace = $CompleteSignature{$LibVersion}{$Symbol}{"NameSpace"};
10848 if(not $NameSpace and $ClassId)
10849 { # class methods have no "NameSpace" attribute
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040010850 $NameSpace = $TypeInfo{$LibVersion}{$ClassId}{"NameSpace"};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010851 }
10852 if($NameSpace)
10853 { # user defined namespaces to ignore
10854 if($SkipNameSpaces{$LibVersion}{$NameSpace}) {
10855 return 0;
10856 }
10857 foreach my $NS (keys(%{$SkipNameSpaces{$LibVersion}}))
10858 { # nested namespaces
10859 if($NameSpace=~/\A\Q$NS\E(\:\:|\Z)/) {
10860 return 0;
10861 }
10862 }
10863 }
10864 if(my $Header = $CompleteSignature{$LibVersion}{$Symbol}{"Header"})
10865 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040010866 if(my $Skip = skipHeader($Header, $LibVersion))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010867 { # --skip-headers or <skip_headers> (not <skip_including>)
10868 if($Skip==1) {
10869 return 0;
10870 }
10871 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010872 }
10873 if($SymbolsListPath and not $SymbolsList{$Symbol})
10874 { # user defined symbols
10875 return 0;
10876 }
10877 if($AppPath and not $SymbolsList_App{$Symbol})
10878 { # user defined symbols (in application)
10879 return 0;
10880 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +040010881 if(not selectSymbol($Symbol, $CompleteSignature{$LibVersion}{$Symbol}, $Level, $LibVersion))
10882 { # non-target symbols
10883 return 0;
10884 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040010885 if($Level eq "Binary")
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010886 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040010887 if($CheckObjectsOnly)
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040010888 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040010889 if(isTemplateInstance($Symbol, $LibVersion)) {
10890 return 0;
10891 }
10892 }
10893 else
10894 {
10895 if($CompleteSignature{$LibVersion}{$Symbol}{"InLine"}
10896 or (isTemplateInstance($Symbol, $LibVersion) and not isTemplateSpec($Symbol, $LibVersion)))
10897 {
10898 if($ClassId and $CompleteSignature{$LibVersion}{$Symbol}{"Virt"})
10899 { # inline virtual methods
10900 if($Type=~/InlineVirt/) {
10901 return 1;
10902 }
10903 my $Allocable = (not isCopyingClass($ClassId, $LibVersion));
10904 if(not $Allocable)
10905 { # check bases
10906 foreach my $DCId (get_sub_classes($ClassId, $LibVersion, 1))
10907 {
10908 if(not isCopyingClass($DCId, $LibVersion))
10909 { # exists a derived class without default c-tor
10910 $Allocable=1;
10911 last;
10912 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040010913 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010914 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040010915 if(not $Allocable) {
10916 return 0;
10917 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010918 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040010919 else
10920 { # inline non-virtual methods
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040010921 return 0;
10922 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010923 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010924 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010925 }
10926 }
10927 return 1;
10928}
10929
10930sub mergeImpl()
10931{
10932 my $DiffCmd = get_CmdPath("diff");
10933 if(not $DiffCmd) {
10934 exitStatus("Not_Found", "can't find \"diff\"");
10935 }
10936 foreach my $Interface (sort keys(%{$Symbol_Library{1}}))
10937 { # implementation changes
10938 next if($CompleteSignature{1}{$Interface}{"Private"});
10939 next if(not $CompleteSignature{1}{$Interface}{"Header"} and not $CheckObjectsOnly);
10940 next if(not $Symbol_Library{2}{$Interface} and not $Symbol_Library{2}{$SymVer{2}{$Interface}});
Andrey Ponomarenko85043792012-05-14 16:48:07 +040010941 if(not symbolFilter($Interface, 1, "Affected", "Binary")) {
10942 next;
10943 }
Andrey Ponomarenko16934472012-03-29 15:37:04 +040010944 my $Impl1 = canonifyImpl($Interface_Impl{1}{$Interface});
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010945 next if(not $Impl1);
Andrey Ponomarenko16934472012-03-29 15:37:04 +040010946 my $Impl2 = canonifyImpl($Interface_Impl{2}{$Interface});
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010947 next if(not $Impl2);
10948 if($Impl1 ne $Impl2)
10949 {
10950 writeFile("$TMP_DIR/impl1", $Impl1);
10951 writeFile("$TMP_DIR/impl2", $Impl2);
Andrey Ponomarenkoa01311b2012-06-08 17:20:02 +040010952 my $Diff = `$DiffCmd -rNau \"$TMP_DIR/impl1\" \"$TMP_DIR/impl2\"`;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010953 $Diff=~s/(---|\+\+\+).+\n//g;
10954 $Diff=~s/[ ]{3,}/ /g;
10955 $Diff=~s/\n\@\@/\n \n\@\@/g;
Andrey Ponomarenkoa01311b2012-06-08 17:20:02 +040010956 unlink("$TMP_DIR/impl1");
10957 unlink("$TMP_DIR/impl2");
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010958 %{$ImplProblems{$Interface}}=(
10959 "Diff" => get_CodeView($Diff) );
10960 }
10961 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +040010962
10963 # clean memory
10964 %Interface_Impl = ();
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010965}
10966
Andrey Ponomarenko16934472012-03-29 15:37:04 +040010967sub canonifyImpl($)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010968{
10969 my $FuncBody= $_[0];
10970 return "" if(not $FuncBody);
10971 $FuncBody=~s/0x[a-f\d]+/0x?/g;# addr
10972 $FuncBody=~s/((\A|\n)[a-z]+[\t ]+)[a-f\d]+([^x]|\Z)/$1?$3/g;# call, jump
10973 $FuncBody=~s/# [a-f\d]+ /# ? /g;# call, jump
10974 $FuncBody=~s/%([a-z]+[a-f\d]*)/\%reg/g;# registers
10975 while($FuncBody=~s/\nnop[ \t]*(\n|\Z)/$1/g){};# empty op
10976 $FuncBody=~s/<.+?\.cpp.+?>/<name.cpp>/g;
10977 $FuncBody=~s/(\A|\n)[a-f\d]+ </$1? </g;# 5e74 <_ZN...
10978 $FuncBody=~s/\.L\d+/.L/g;
10979 $FuncBody=~s/#(-?)\d+/#$1?/g;# r3, [r3, #120]
10980 $FuncBody=~s/[\n]{2,}/\n/g;
10981 return $FuncBody;
10982}
10983
10984sub get_CodeView($)
10985{
10986 my $Code = $_[0];
10987 my $View = "";
10988 foreach my $Line (split(/\n/, $Code))
10989 {
10990 if($Line=~s/\A(\+|-)/$1 /g)
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040010991 { # bold line
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010992 $View .= "<tr><td><b>".htmlSpecChars($Line)."</b></td></tr>\n";
10993 }
10994 else {
10995 $View .= "<tr><td>".htmlSpecChars($Line)."</td></tr>\n";
10996 }
10997 }
10998 return "<table class='code_view'>$View</table>\n";
10999}
11000
11001sub getImplementations($$)
11002{
11003 my ($LibVersion, $Path) = @_;
11004 return if(not $LibVersion or not -e $Path);
11005 if($OSgroup eq "macos")
11006 {
11007 my $OtoolCmd = get_CmdPath("otool");
11008 if(not $OtoolCmd) {
11009 exitStatus("Not_Found", "can't find \"otool\"");
11010 }
11011 my $CurInterface = "";
Andrey Ponomarenkoa01311b2012-06-08 17:20:02 +040011012 foreach my $Line (split(/\n/, `$OtoolCmd -tv \"$Path\" 2>\"$TMP_DIR/null\"`))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011013 {
11014 if($Line=~/\A\s*_(\w+)\s*:/i) {
11015 $CurInterface = $1;
11016 }
11017 elsif($Line=~/\A\s*[\da-z]+\s+(.+?)\Z/i) {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040011018 $Interface_Impl{$LibVersion}{$CurInterface} .= $1."\n";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011019 }
11020 }
11021 }
11022 else
11023 {
11024 my $ObjdumpCmd = get_CmdPath("objdump");
11025 if(not $ObjdumpCmd) {
11026 exitStatus("Not_Found", "can't find \"objdump\"");
11027 }
11028 my $CurInterface = "";
Andrey Ponomarenkoa01311b2012-06-08 17:20:02 +040011029 foreach my $Line (split(/\n/, `$ObjdumpCmd -d \"$Path\" 2>\"$TMP_DIR/null\"`))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011030 {
11031 if($Line=~/\A[\da-z]+\s+<(\w+)>/i) {
11032 $CurInterface = $1;
11033 }
11034 else
11035 { # x86: 51fa:(\t)89 e5 (\t)mov %esp,%ebp
11036 # arm: 5020:(\t)e24cb004(\t)sub(\t)fp, ip, #4(\t); 0x4
11037 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 +040011038 $Interface_Impl{$LibVersion}{$CurInterface} .= $2."\n";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011039 }
11040 }
11041 }
11042 }
11043}
11044
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011045sub detectAdded($)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011046{
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011047 my $Level = $_[0];
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011048 foreach my $Symbol (keys(%{$Symbol_Library{2}}))
11049 {
11050 if(link_symbol($Symbol, 1, "+Deps"))
11051 { # linker can find a new symbol
11052 # in the old-version library
11053 # So, it's not a new symbol
11054 next;
11055 }
11056 if(my $VSym = $SymVer{2}{$Symbol}
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040011057 and index($Symbol,"\@")==-1) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011058 next;
11059 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011060 $AddedInt{$Level}{$Symbol} = 1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011061 }
11062}
11063
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011064sub detectRemoved($)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011065{
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011066 my $Level = $_[0];
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011067 foreach my $Symbol (keys(%{$Symbol_Library{1}}))
11068 {
11069 if($CheckObjectsOnly) {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011070 $CheckedSymbols{"Binary"}{$Symbol} = 1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011071 }
11072 if(link_symbol($Symbol, 2, "+Deps"))
11073 { # linker can find an old symbol
11074 # in the new-version library
11075 next;
11076 }
11077 if(my $VSym = $SymVer{1}{$Symbol}
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040011078 and index($Symbol,"\@")==-1) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011079 next;
11080 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011081 $RemovedInt{$Level}{$Symbol} = 1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011082 }
11083}
11084
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011085sub mergeLibs($)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011086{
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011087 my $Level = $_[0];
11088 foreach my $Symbol (sort keys(%{$AddedInt{$Level}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011089 { # checking added symbols
11090 next if($CompleteSignature{2}{$Symbol}{"Private"});
11091 next if(not $CompleteSignature{2}{$Symbol}{"Header"} and not $CheckObjectsOnly);
Andrey Ponomarenko85043792012-05-14 16:48:07 +040011092 next if(not symbolFilter($Symbol, 2, "Affected", $Level));
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011093 %{$CompatProblems{$Level}{$Symbol}{"Added_Symbol"}{""}}=();
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011094 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011095 foreach my $Symbol (sort keys(%{$RemovedInt{$Level}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011096 { # checking removed symbols
11097 next if($CompleteSignature{1}{$Symbol}{"Private"});
11098 next if(not $CompleteSignature{1}{$Symbol}{"Header"} and not $CheckObjectsOnly);
11099 if($Symbol=~/\A_ZTV/)
11100 { # skip v-tables for templates, that should not be imported by applications
11101 next if($tr_name{$Symbol}=~/</);
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040011102 if(my $CName = $VTableClass{$Symbol})
11103 {
11104 if(not keys(%{$ClassMethods{$Level}{1}{$CName}}))
11105 { # vtables for "private" classes
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040011106 # use case: vtable for QDragManager (Qt 4.5.3 to 4.6.0) became HIDDEN symbol
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040011107 next;
11108 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011109 }
11110 }
11111 else {
Andrey Ponomarenko85043792012-05-14 16:48:07 +040011112 next if(not symbolFilter($Symbol, 1, "Affected", $Level));
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011113 }
11114 if($CompleteSignature{1}{$Symbol}{"PureVirt"})
11115 { # symbols for pure virtual methods cannot be called by clients
11116 next;
11117 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011118 %{$CompatProblems{$Level}{$Symbol}{"Removed_Symbol"}{""}}=();
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011119 }
11120}
11121
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040011122sub checkDump($$)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011123{
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040011124 my ($LibVersion, $V) = @_;
11125 if(defined $Cache{"checkDump"}{$LibVersion}{$V}) {
11126 return $Cache{"checkDump"}{$LibVersion}{$V};
11127 }
11128 return ($Cache{"checkDump"}{$LibVersion}{$V} = (not $UsedDump{$LibVersion}{"V"} or cmpVersions($UsedDump{$LibVersion}{"V"}, $V)>=0));
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011129}
11130
11131sub detectAdded_H($)
11132{
11133 my $Level = $_[0];
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011134 foreach my $Symbol (sort keys(%{$CompleteSignature{2}}))
11135 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011136 if($Level eq "Source")
11137 { # remove symbol version
11138 my ($SN, $SS, $SV) = separate_symbol($Symbol);
11139 $Symbol=$SN;
Andrey Ponomarenkob8d203d2012-05-25 18:11:07 +040011140
11141 if($CompleteSignature{2}{$Symbol}{"Artificial"})
11142 { # skip artificial constructors
11143 next;
11144 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011145 }
Andrey Ponomarenko16934472012-03-29 15:37:04 +040011146 if(not $CompleteSignature{2}{$Symbol}{"Header"}
11147 or not $CompleteSignature{2}{$Symbol}{"MnglName"}) {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011148 next;
11149 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040011150 if($ExtendedSymbols{$Symbol}) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011151 next;
11152 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011153 if(not defined $CompleteSignature{1}{$Symbol}
11154 or not $CompleteSignature{1}{$Symbol}{"MnglName"})
11155 {
Andrey Ponomarenko16934472012-03-29 15:37:04 +040011156 if($UsedDump{2}{"SrcBin"})
11157 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040011158 if($UsedDump{1}{"BinOnly"} or not checkDump(1, "2.11"))
Andrey Ponomarenko16934472012-03-29 15:37:04 +040011159 { # support for old and different (!) ABI dumps
11160 if(not $CompleteSignature{2}{$Symbol}{"Virt"}
11161 and not $CompleteSignature{2}{$Symbol}{"PureVirt"})
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011162 {
Andrey Ponomarenko16934472012-03-29 15:37:04 +040011163 if($CheckHeadersOnly)
Andrey Ponomarenko85043792012-05-14 16:48:07 +040011164 {
11165 if(my $Lang = $CompleteSignature{2}{$Symbol}{"Lang"})
11166 {
11167 if($Lang eq "C")
11168 { # support for old ABI dumps: missed extern "C" functions
11169 next;
11170 }
11171 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011172 }
Andrey Ponomarenko16934472012-03-29 15:37:04 +040011173 else
11174 {
11175 if(not link_symbol($Symbol, 2, "-Deps"))
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040011176 { # skip added inline symbols and const global data
Andrey Ponomarenko16934472012-03-29 15:37:04 +040011177 next;
11178 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011179 }
11180 }
11181 }
11182 }
11183 $AddedInt{$Level}{$Symbol} = 1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011184 }
11185 }
11186}
11187
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011188sub detectRemoved_H($)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011189{
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011190 my $Level = $_[0];
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011191 foreach my $Symbol (sort keys(%{$CompleteSignature{1}}))
11192 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011193 if($Level eq "Source")
11194 { # remove symbol version
11195 my ($SN, $SS, $SV) = separate_symbol($Symbol);
11196 $Symbol=$SN;
11197 }
Andrey Ponomarenko16934472012-03-29 15:37:04 +040011198 if(not $CompleteSignature{1}{$Symbol}{"Header"}
11199 or not $CompleteSignature{1}{$Symbol}{"MnglName"}) {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011200 next;
11201 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040011202 if($ExtendedSymbols{$Symbol}) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011203 next;
11204 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011205 if(not defined $CompleteSignature{2}{$Symbol}
11206 or not $CompleteSignature{2}{$Symbol}{"MnglName"})
Andrey Ponomarenko85043792012-05-14 16:48:07 +040011207 {
Andrey Ponomarenko16934472012-03-29 15:37:04 +040011208 if($UsedDump{1}{"SrcBin"})
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011209 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040011210 if($UsedDump{2}{"BinOnly"} or not checkDump(2, "2.11"))
Andrey Ponomarenko85043792012-05-14 16:48:07 +040011211 { # support for old and different (!) ABI dumps
Andrey Ponomarenko16934472012-03-29 15:37:04 +040011212 if(not $CompleteSignature{1}{$Symbol}{"Virt"}
11213 and not $CompleteSignature{1}{$Symbol}{"PureVirt"})
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011214 {
Andrey Ponomarenko16934472012-03-29 15:37:04 +040011215 if($CheckHeadersOnly)
11216 { # skip all removed symbols
Andrey Ponomarenko85043792012-05-14 16:48:07 +040011217 if(my $Lang = $CompleteSignature{1}{$Symbol}{"Lang"})
11218 {
11219 if($Lang eq "C")
11220 { # support for old ABI dumps: missed extern "C" functions
11221 next;
11222 }
11223 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011224 }
Andrey Ponomarenko16934472012-03-29 15:37:04 +040011225 else
11226 {
11227 if(not link_symbol($Symbol, 1, "-Deps"))
11228 { # skip removed inline symbols
11229 next;
11230 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011231 }
11232 }
11233 }
11234 }
Andrey Ponomarenkob8d203d2012-05-25 18:11:07 +040011235 if(not checkDump(1, "2.15"))
11236 {
11237 if($Symbol=~/_IT_E\Z/)
11238 { # _ZN28QExplicitlySharedDataPointerI22QSslCertificatePrivateEC1IT_EERKS_IT_E
11239 next;
11240 }
11241 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011242 $RemovedInt{$Level}{$Symbol} = 1;
11243 if($Level eq "Source")
11244 { # search for a source-compatible equivalent
11245 setAlternative($Symbol, $Level);
11246 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011247 }
11248 }
11249}
11250
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011251sub mergeHeaders($)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011252{
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011253 my $Level = $_[0];
11254 foreach my $Symbol (sort keys(%{$AddedInt{$Level}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011255 { # checking added symbols
11256 next if($CompleteSignature{2}{$Symbol}{"PureVirt"});
Andrey Ponomarenko85043792012-05-14 16:48:07 +040011257 if($Level eq "Binary")
11258 {
11259 if($CompleteSignature{2}{$Symbol}{"InLine"})
11260 {
11261 if(not $CompleteSignature{2}{$Symbol}{"Virt"})
11262 { # skip inline non-virtual functions
11263 next;
11264 }
11265 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011266 }
11267 else
11268 { # Source
11269 if($SourceAlternative_B{$Symbol}) {
11270 next;
11271 }
11272 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011273 next if($CompleteSignature{2}{$Symbol}{"Private"});
Andrey Ponomarenko85043792012-05-14 16:48:07 +040011274 next if(not symbolFilter($Symbol, 2, "Affected", $Level));
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011275 %{$CompatProblems{$Level}{$Symbol}{"Added_Symbol"}{""}}=();
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011276 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011277 foreach my $Symbol (sort keys(%{$RemovedInt{$Level}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011278 { # checking removed symbols
11279 next if($CompleteSignature{1}{$Symbol}{"PureVirt"});
Andrey Ponomarenko85043792012-05-14 16:48:07 +040011280 if($Level eq "Binary")
11281 {
11282 if($CompleteSignature{1}{$Symbol}{"InLine"})
11283 {
11284 if(not $CompleteSignature{1}{$Symbol}{"Virt"})
11285 { # skip inline non-virtual functions
11286 next;
11287 }
11288 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011289 }
11290 else
11291 { # Source
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040011292 if(my $Alt = $SourceAlternative{$Symbol})
11293 {
11294 if(defined $CompleteSignature{1}{$Alt}
11295 and $CompleteSignature{1}{$Symbol}{"Const"})
11296 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040011297 my $Cid = $CompleteSignature{1}{$Symbol}{"Class"};
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040011298 %{$CompatProblems{$Level}{$Symbol}{"Removed_Const_Overload"}{$tr_name{$Symbol}}}=(
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040011299 "Type_Name"=>$TypeInfo{1}{$Cid}{"Name"},
Andrey Ponomarenko85043792012-05-14 16:48:07 +040011300 "Type_Type"=>"Class",
11301 "Target"=>get_Signature($Alt, 1) );
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040011302 }
11303 else
11304 { # do NOT show removed symbol
11305 next;
11306 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011307 }
11308 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011309 next if($CompleteSignature{1}{$Symbol}{"Private"});
Andrey Ponomarenko85043792012-05-14 16:48:07 +040011310 next if(not symbolFilter($Symbol, 1, "Affected", $Level));
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011311 %{$CompatProblems{$Level}{$Symbol}{"Removed_Symbol"}{""}}=();
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011312 }
11313}
11314
11315sub addParamNames($)
11316{
11317 my $LibraryVersion = $_[0];
11318 return if(not keys(%AddIntParams));
11319 my $SecondVersion = $LibraryVersion==1?2:1;
11320 foreach my $Interface (sort keys(%{$CompleteSignature{$LibraryVersion}}))
11321 {
11322 next if(not keys(%{$AddIntParams{$Interface}}));
11323 foreach my $ParamPos (sort {int($a)<=>int($b)} keys(%{$CompleteSignature{$LibraryVersion}{$Interface}{"Param"}}))
Andrey Ponomarenko85043792012-05-14 16:48:07 +040011324 { # add absent parameter names
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011325 my $ParamName = $CompleteSignature{$LibraryVersion}{$Interface}{"Param"}{$ParamPos}{"name"};
11326 if($ParamName=~/\Ap\d+\Z/ and my $NewParamName = $AddIntParams{$Interface}{$ParamPos})
Andrey Ponomarenko85043792012-05-14 16:48:07 +040011327 { # names from the external file
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011328 if(defined $CompleteSignature{$SecondVersion}{$Interface}
11329 and defined $CompleteSignature{$SecondVersion}{$Interface}{"Param"}{$ParamPos})
11330 {
11331 if($CompleteSignature{$SecondVersion}{$Interface}{"Param"}{$ParamPos}{"name"}=~/\Ap\d+\Z/) {
11332 $CompleteSignature{$LibraryVersion}{$Interface}{"Param"}{$ParamPos}{"name"} = $NewParamName;
11333 }
11334 }
11335 else {
11336 $CompleteSignature{$LibraryVersion}{$Interface}{"Param"}{$ParamPos}{"name"} = $NewParamName;
11337 }
11338 }
11339 }
11340 }
11341}
11342
11343sub detectChangedTypedefs()
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +040011344{ # detect changed typedefs to show
11345 # correct function signatures
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011346 foreach my $Typedef (keys(%{$Typedef_BaseName{1}}))
11347 {
11348 next if(not $Typedef);
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +040011349 my $BName1 = $Typedef_BaseName{1}{$Typedef};
11350 if(not $BName1 or isAnon($BName1)) {
11351 next;
11352 }
11353 my $BName2 = $Typedef_BaseName{2}{$Typedef};
11354 if(not $BName2 or isAnon($BName2)) {
11355 next;
11356 }
11357 if($BName1 ne $BName2) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011358 $ChangedTypedef{$Typedef} = 1;
11359 }
11360 }
11361}
11362
11363sub get_symbol_suffix($$)
11364{
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011365 my ($Symbol, $Full) = @_;
11366 my ($SN, $SO, $SV) = separate_symbol($Symbol);
11367 $Symbol=$SN;# remove version
11368 my $Signature = $tr_name{$Symbol};
Andrey Ponomarenko16934472012-03-29 15:37:04 +040011369 my $Suffix = substr($Signature, find_center($Signature, "("));
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011370 if(not $Full) {
11371 $Suffix=~s/(\))\s*(const volatile|volatile const|const|volatile)\Z/$1/g;
11372 }
11373 return $Suffix;
11374}
11375
11376sub get_symbol_prefix($$)
11377{
11378 my ($Symbol, $LibVersion) = @_;
11379 my $ShortName = $CompleteSignature{$LibVersion}{$Symbol}{"ShortName"};
11380 if(my $ClassId = $CompleteSignature{$LibVersion}{$Symbol}{"Class"})
11381 { # methods
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040011382 $ShortName = $TypeInfo{$LibVersion}{$ClassId}{"Name"}."::".$ShortName;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011383 }
11384 return $ShortName;
11385}
11386
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011387sub setAlternative($)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011388{
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011389 my $Symbol = $_[0];
11390 my $PSymbol = $Symbol;
11391 if(not defined $CompleteSignature{2}{$PSymbol}
11392 or (not $CompleteSignature{2}{$PSymbol}{"MnglName"}
11393 and not $CompleteSignature{2}{$PSymbol}{"ShortName"}))
11394 { # search for a pair
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040011395 if(my $ShortName = $CompleteSignature{1}{$PSymbol}{"ShortName"})
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011396 {
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040011397 if($CompleteSignature{1}{$PSymbol}{"Data"})
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011398 {
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040011399 if($PSymbol=~s/L(\d+$ShortName(E)\Z)/$1/
11400 or $PSymbol=~s/(\d+$ShortName(E)\Z)/L$1/)
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011401 {
11402 if(defined $CompleteSignature{2}{$PSymbol}
11403 and $CompleteSignature{2}{$PSymbol}{"MnglName"})
11404 {
11405 $SourceAlternative{$Symbol} = $PSymbol;
11406 $SourceAlternative_B{$PSymbol} = $Symbol;
11407 if(not defined $CompleteSignature{1}{$PSymbol}
11408 or not $CompleteSignature{1}{$PSymbol}{"MnglName"}) {
11409 $SourceReplacement{$Symbol} = $PSymbol;
11410 }
11411 }
11412 }
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040011413 }
11414 else
11415 {
11416 foreach my $Sp ("KV", "VK", "K", "V")
11417 {
11418 if($PSymbol=~s/\A_ZN$Sp/_ZN/
11419 or $PSymbol=~s/\A_ZN/_ZN$Sp/)
11420 {
11421 if(defined $CompleteSignature{2}{$PSymbol}
11422 and $CompleteSignature{2}{$PSymbol}{"MnglName"})
11423 {
11424 $SourceAlternative{$Symbol} = $PSymbol;
11425 $SourceAlternative_B{$PSymbol} = $Symbol;
11426 if(not defined $CompleteSignature{1}{$PSymbol}
11427 or not $CompleteSignature{1}{$PSymbol}{"MnglName"}) {
11428 $SourceReplacement{$Symbol} = $PSymbol;
11429 }
11430 }
11431 }
11432 $PSymbol = $Symbol;
11433 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011434 }
11435 }
11436 }
11437 return "";
11438}
11439
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040011440sub getSymKind($$)
11441{
11442 my ($Symbol, $LibVersion) = @_;
11443 if($CompleteSignature{$LibVersion}{$Symbol}{"Data"})
11444 {
11445 return "Global_Data";
11446 }
11447 elsif($CompleteSignature{$LibVersion}{$Symbol}{"Class"})
11448 {
11449 return "Method";
11450 }
11451 return "Function";
11452}
11453
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011454sub mergeSignatures($)
11455{
11456 my $Level = $_[0];
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011457 my %SubProblems = ();
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011458
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011459 mergeBases($Level);
11460
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011461 my %AddedOverloads = ();
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011462 foreach my $Symbol (sort keys(%{$AddedInt{$Level}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011463 { # check all added exported symbols
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011464 if(not $CompleteSignature{2}{$Symbol}{"Header"}) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011465 next;
11466 }
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040011467 if(defined $CompleteSignature{1}{$Symbol}
11468 and $CompleteSignature{1}{$Symbol}{"Header"})
11469 { # double-check added symbol
11470 next;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011471 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +040011472 if(not symbolFilter($Symbol, 2, "Affected", $Level)) {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011473 next;
11474 }
11475 if($Symbol=~/\A(_Z|\?)/)
11476 { # C++
11477 $AddedOverloads{get_symbol_prefix($Symbol, 2)}{get_symbol_suffix($Symbol, 1)} = $Symbol;
11478 }
11479 if(my $OverriddenMethod = $CompleteSignature{2}{$Symbol}{"Override"})
11480 { # register virtual overridings
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040011481 my $Cid = $CompleteSignature{2}{$Symbol}{"Class"};
11482 my $AffectedClass_Name = $TypeInfo{2}{$Cid}{"Name"};
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040011483 if(defined $CompleteSignature{1}{$OverriddenMethod} and $CompleteSignature{1}{$OverriddenMethod}{"Virt"}
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011484 and not $CompleteSignature{1}{$OverriddenMethod}{"Private"})
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040011485 {
11486 if($TName_Tid{1}{$AffectedClass_Name})
11487 { # class should exist in previous version
11488 if(not isCopyingClass($TName_Tid{1}{$AffectedClass_Name}, 1))
11489 { # old v-table is NOT copied by old applications
11490 %{$CompatProblems{$Level}{$OverriddenMethod}{"Overridden_Virtual_Method"}{$tr_name{$Symbol}}}=(
11491 "Type_Name"=>$AffectedClass_Name,
11492 "Type_Type"=>"Class",
11493 "Target"=>get_Signature($Symbol, 2),
11494 "Old_Value"=>get_Signature($OverriddenMethod, 2),
11495 "New_Value"=>get_Signature($Symbol, 2) );
11496 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011497 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011498 }
11499 }
11500 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011501 foreach my $Symbol (sort keys(%{$RemovedInt{$Level}}))
11502 { # check all removed exported symbols
11503 if(not $CompleteSignature{1}{$Symbol}{"Header"}) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011504 next;
11505 }
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040011506 if(defined $CompleteSignature{2}{$Symbol}
11507 and $CompleteSignature{2}{$Symbol}{"Header"})
11508 { # double-check removed symbol
11509 next;
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011510 }
11511 if($CompleteSignature{1}{$Symbol}{"Private"})
11512 { # skip private methods
11513 next;
11514 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +040011515 if(not symbolFilter($Symbol, 1, "Affected", $Level)) {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011516 next;
11517 }
11518 $CheckedSymbols{$Level}{$Symbol} = 1;
11519 if(my $OverriddenMethod = $CompleteSignature{1}{$Symbol}{"Override"})
11520 { # register virtual overridings
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040011521 my $Cid = $CompleteSignature{1}{$Symbol}{"Class"};
11522 my $AffectedClass_Name = $TypeInfo{1}{$Cid}{"Name"};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011523 if(defined $CompleteSignature{2}{$OverriddenMethod}
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040011524 and $CompleteSignature{2}{$OverriddenMethod}{"Virt"})
11525 {
11526 if($TName_Tid{2}{$AffectedClass_Name})
11527 { # class should exist in newer version
11528 if(not isCopyingClass($CompleteSignature{1}{$Symbol}{"Class"}, 1))
11529 { # old v-table is NOT copied by old applications
11530 %{$CompatProblems{$Level}{$Symbol}{"Overridden_Virtual_Method_B"}{$tr_name{$OverriddenMethod}}}=(
11531 "Type_Name"=>$AffectedClass_Name,
11532 "Type_Type"=>"Class",
11533 "Target"=>get_Signature($OverriddenMethod, 1),
11534 "Old_Value"=>get_Signature($Symbol, 1),
11535 "New_Value"=>get_Signature($OverriddenMethod, 1) );
11536 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011537 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011538 }
11539 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011540 if($Level eq "Binary"
11541 and $OSgroup eq "windows")
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011542 { # register the reason of symbol name change
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040011543 if(my $NewSym = $mangled_name{2}{$tr_name{$Symbol}})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011544 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040011545 if($AddedInt{$Level}{$NewSym})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011546 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040011547 if($CompleteSignature{1}{$Symbol}{"Static"} ne $CompleteSignature{2}{$NewSym}{"Static"})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011548 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040011549 if($CompleteSignature{2}{$NewSym}{"Static"})
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011550 {
11551 %{$CompatProblems{$Level}{$Symbol}{"Symbol_Became_Static"}{$tr_name{$Symbol}}}=(
11552 "Target"=>$tr_name{$Symbol},
11553 "Old_Value"=>$Symbol,
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040011554 "New_Value"=>$NewSym );
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011555 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011556 else
11557 {
11558 %{$CompatProblems{$Level}{$Symbol}{"Symbol_Became_NonStatic"}{$tr_name{$Symbol}}}=(
11559 "Target"=>$tr_name{$Symbol},
11560 "Old_Value"=>$Symbol,
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040011561 "New_Value"=>$NewSym );
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011562 }
11563 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040011564 if($CompleteSignature{1}{$Symbol}{"Virt"} ne $CompleteSignature{2}{$NewSym}{"Virt"})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011565 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040011566 if($CompleteSignature{2}{$NewSym}{"Virt"})
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011567 {
11568 %{$CompatProblems{$Level}{$Symbol}{"Symbol_Became_Virtual"}{$tr_name{$Symbol}}}=(
11569 "Target"=>$tr_name{$Symbol},
11570 "Old_Value"=>$Symbol,
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040011571 "New_Value"=>$NewSym );
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011572 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011573 else
11574 {
11575 %{$CompatProblems{$Level}{$Symbol}{"Symbol_Became_NonVirtual"}{$tr_name{$Symbol}}}=(
11576 "Target"=>$tr_name{$Symbol},
11577 "Old_Value"=>$Symbol,
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040011578 "New_Value"=>$NewSym );
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011579 }
11580 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040011581 my $RTId1 = $CompleteSignature{1}{$Symbol}{"Return"};
11582 my $RTId2 = $CompleteSignature{2}{$NewSym}{"Return"};
11583 my $RTName1 = $TypeInfo{1}{$RTId1}{"Name"};
11584 my $RTName2 = $TypeInfo{2}{$RTId2}{"Name"};
11585 if($RTName1 ne $RTName2)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011586 {
11587 my $ProblemType = "Symbol_Changed_Return";
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011588 if($CompleteSignature{1}{$Symbol}{"Data"}) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011589 $ProblemType = "Global_Data_Symbol_Changed_Type";
11590 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011591 %{$CompatProblems{$Level}{$Symbol}{$ProblemType}{$tr_name{$Symbol}}}=(
11592 "Target"=>$tr_name{$Symbol},
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040011593 "Old_Type"=>$RTName1,
11594 "New_Type"=>$RTName2,
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011595 "Old_Value"=>$Symbol,
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040011596 "New_Value"=>$NewSym );
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011597 }
11598 }
11599 }
11600 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011601 if($Symbol=~/\A(_Z|\?)/)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011602 { # C++
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011603 my $Prefix = get_symbol_prefix($Symbol, 1);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011604 if(my @Overloads = sort keys(%{$AddedOverloads{$Prefix}})
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011605 and not $AddedOverloads{$Prefix}{get_symbol_suffix($Symbol, 1)})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011606 { # changed signature: params, "const"-qualifier
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040011607 my $NewSym = $AddedOverloads{$Prefix}{$Overloads[0]};
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011608 if($CompleteSignature{1}{$Symbol}{"Constructor"})
11609 {
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +040011610 if($Symbol=~/(C1E|C2E)/)
11611 {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011612 my $CtorType = $1;
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040011613 $NewSym=~s/(C1E|C2E)/$CtorType/g;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011614 }
11615 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011616 elsif($CompleteSignature{1}{$Symbol}{"Destructor"})
11617 {
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +040011618 if($Symbol=~/(D0E|D1E|D2E)/)
11619 {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011620 my $DtorType = $1;
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040011621 $NewSym=~s/(D0E|D1E|D2E)/$DtorType/g;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011622 }
11623 }
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040011624 my $NS1 = $CompleteSignature{1}{$Symbol}{"NameSpace"};
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040011625 my $NS2 = $CompleteSignature{2}{$NewSym}{"NameSpace"};
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040011626 if((not $NS1 and not $NS2) or ($NS1 and $NS2 and $NS1 eq $NS2))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011627 { # from the same class and namespace
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011628 if($CompleteSignature{1}{$Symbol}{"Const"}
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040011629 and not $CompleteSignature{2}{$NewSym}{"Const"})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011630 { # "const" to non-"const"
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040011631 %{$CompatProblems{$Level}{$Symbol}{"Method_Became_NonConst"}{$tr_name{$Symbol}}}=(
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040011632 "Type_Name"=>$TypeInfo{1}{$CompleteSignature{1}{$Symbol}{"Class"}}{"Name"},
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011633 "Target"=>$tr_name{$Symbol},
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040011634 "New_Signature"=>get_Signature($NewSym, 2),
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011635 "Old_Value"=>$Symbol,
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040011636 "New_Value"=>$NewSym );
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011637 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011638 elsif(not $CompleteSignature{1}{$Symbol}{"Const"}
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040011639 and $CompleteSignature{2}{$NewSym}{"Const"})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011640 { # non-"const" to "const"
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040011641 %{$CompatProblems{$Level}{$Symbol}{"Method_Became_Const"}{$tr_name{$Symbol}}}=(
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011642 "Target"=>$tr_name{$Symbol},
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040011643 "New_Signature"=>get_Signature($NewSym, 2),
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011644 "Old_Value"=>$Symbol,
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040011645 "New_Value"=>$NewSym );
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011646 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011647 if($CompleteSignature{1}{$Symbol}{"Volatile"}
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040011648 and not $CompleteSignature{2}{$NewSym}{"Volatile"})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011649 { # "volatile" to non-"volatile"
11650
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040011651 %{$CompatProblems{$Level}{$Symbol}{"Method_Became_NonVolatile"}{$tr_name{$Symbol}}}=(
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011652 "Target"=>$tr_name{$Symbol},
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040011653 "New_Signature"=>get_Signature($NewSym, 2),
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011654 "Old_Value"=>$Symbol,
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040011655 "New_Value"=>$NewSym );
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011656 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011657 elsif(not $CompleteSignature{1}{$Symbol}{"Volatile"}
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040011658 and $CompleteSignature{2}{$NewSym}{"Volatile"})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011659 { # non-"volatile" to "volatile"
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040011660 %{$CompatProblems{$Level}{$Symbol}{"Method_Became_Volatile"}{$tr_name{$Symbol}}}=(
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011661 "Target"=>$tr_name{$Symbol},
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040011662 "New_Signature"=>get_Signature($NewSym, 2),
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011663 "Old_Value"=>$Symbol,
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040011664 "New_Value"=>$NewSym );
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011665 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040011666 if(get_symbol_suffix($Symbol, 0) ne get_symbol_suffix($NewSym, 0))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011667 { # params list
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011668 %{$CompatProblems{$Level}{$Symbol}{"Symbol_Changed_Parameters"}{$tr_name{$Symbol}}}=(
11669 "Target"=>$tr_name{$Symbol},
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040011670 "New_Signature"=>get_Signature($NewSym, 2),
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011671 "Old_Value"=>$Symbol,
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040011672 "New_Value"=>$NewSym );
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011673 }
11674 }
11675 }
11676 }
11677 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011678 foreach my $Symbol (sort keys(%{$CompleteSignature{1}}))
11679 { # checking symbols
11680 my ($SN, $SS, $SV) = separate_symbol($Symbol);
11681 if($Level eq "Source")
11682 { # remove symbol version
11683 $Symbol=$SN;
11684 }
11685 else
11686 { # Binary
11687 if(not $SV)
11688 { # symbol without version
11689 if(my $VSym = $SymVer{1}{$Symbol})
11690 { # the symbol is linked with versioned symbol
11691 if($CompleteSignature{2}{$VSym}{"MnglName"})
11692 { # show report for symbol@ver only
11693 next;
11694 }
11695 elsif(not link_symbol($VSym, 2, "-Deps"))
11696 { # changed version: sym@v1 to sym@v2
11697 # do NOT show report for symbol
11698 next;
11699 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011700 }
11701 }
11702 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011703 my $PSymbol = $Symbol;
11704 if($Level eq "Source"
11705 and my $S = $SourceReplacement{$Symbol})
11706 { # take a source-compatible replacement function
11707 $PSymbol = $S;
11708 }
11709 if($CompleteSignature{1}{$Symbol}{"Private"})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011710 { # private symbols
11711 next;
11712 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011713 if(not defined $CompleteSignature{1}{$Symbol}
11714 or not defined $CompleteSignature{2}{$PSymbol})
11715 { # no info
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011716 next;
11717 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011718 if(not $CompleteSignature{1}{$Symbol}{"MnglName"}
11719 or not $CompleteSignature{2}{$PSymbol}{"MnglName"})
11720 { # no mangled name
11721 next;
11722 }
11723 if(not $CompleteSignature{1}{$Symbol}{"Header"}
11724 or not $CompleteSignature{2}{$PSymbol}{"Header"})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011725 { # without a header
11726 next;
11727 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040011728 if(checkDump(1, "2.13") and checkDump(2, "2.13"))
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040011729 {
11730 if($CompleteSignature{1}{$Symbol}{"Data"}
11731 and $CompleteSignature{2}{$PSymbol}{"Data"})
11732 {
11733 my $Value1 = $CompleteSignature{1}{$Symbol}{"Value"};
11734 my $Value2 = $CompleteSignature{2}{$PSymbol}{"Value"};
11735 if(defined $Value1)
11736 {
11737 $Value1 = showVal($Value1, $CompleteSignature{1}{$Symbol}{"Return"}, 1);
11738 if(defined $Value2)
11739 {
11740 $Value2 = showVal($Value2, $CompleteSignature{2}{$PSymbol}{"Return"}, 2);
11741 if($Value1 ne $Value2)
11742 {
11743 %{$CompatProblems{$Level}{$Symbol}{"Global_Data_Value_Changed"}{""}}=(
11744 "Old_Value"=>$Value1,
11745 "New_Value"=>$Value2,
11746 "Target"=>get_Signature($Symbol, 1) );
11747 }
11748 }
11749 }
11750 }
11751 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +040011752
11753 if(not $CompleteSignature{1}{$Symbol}{"PureVirt"}
11754 and $CompleteSignature{2}{$PSymbol}{"PureVirt"})
11755 { # became pure
11756 next;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011757 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +040011758 if($CompleteSignature{1}{$Symbol}{"PureVirt"}
11759 and not $CompleteSignature{2}{$PSymbol}{"PureVirt"})
11760 { # became non-pure
11761 next;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011762 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +040011763
11764 if(not symbolFilter($Symbol, 1, "Affected + InlineVirt", $Level))
11765 { # exported, target, inline virtual and pure virtual
11766 next;
11767 }
11768 if(not symbolFilter($PSymbol, 2, "Affected + InlineVirt", $Level))
11769 { # exported, target, inline virtual and pure virtual
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011770 next;
11771 }
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040011772
11773 if($CompleteSignature{2}{$PSymbol}{"Private"})
11774 {
11775 %{$CompatProblems{$Level}{$Symbol}{getSymKind($Symbol, 1)."_Became_Private"}{""}}=(
11776 "Target"=>get_Signature_M($PSymbol, 2) );
11777 }
11778 elsif(not $CompleteSignature{1}{$Symbol}{"Protected"}
11779 and $CompleteSignature{2}{$PSymbol}{"Protected"})
11780 {
11781 %{$CompatProblems{$Level}{$Symbol}{getSymKind($Symbol, 1)."_Became_Protected"}{""}}=(
11782 "Target"=>get_Signature_M($PSymbol, 2) );
11783 }
11784 elsif($CompleteSignature{1}{$Symbol}{"Protected"}
11785 and not $CompleteSignature{2}{$PSymbol}{"Protected"})
11786 {
11787 %{$CompatProblems{$Level}{$Symbol}{getSymKind($Symbol, 1)."_Became_Public"}{""}}=(
11788 "Target"=>get_Signature_M($PSymbol, 2) );
11789 }
11790
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011791 # checking virtual table
Andrey Ponomarenko16934472012-03-29 15:37:04 +040011792 mergeVirtualTables($Symbol, $Level);
11793
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011794 if($COMPILE_ERRORS)
11795 { # if some errors occurred at the compiling stage
11796 # then some false positives can be skipped here
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011797 if(not $CompleteSignature{1}{$Symbol}{"Data"} and $CompleteSignature{2}{$PSymbol}{"Data"}
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040011798 and not $GlobalDataObject{2}{$Symbol})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011799 { # missed information about parameters in newer version
11800 next;
11801 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040011802 if($CompleteSignature{1}{$Symbol}{"Data"} and not $GlobalDataObject{1}{$Symbol}
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011803 and not $CompleteSignature{2}{$PSymbol}{"Data"})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011804 {# missed information about parameters in older version
11805 next;
11806 }
11807 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011808 my ($MnglName, $VersionSpec, $SymbolVersion) = separate_symbol($Symbol);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011809 # checking attributes
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011810 if($CompleteSignature{2}{$PSymbol}{"Static"}
11811 and not $CompleteSignature{1}{$Symbol}{"Static"} and $Symbol=~/\A(_Z|\?)/) {
11812 %{$CompatProblems{$Level}{$Symbol}{"Method_Became_Static"}{""}}=(
11813 "Target"=>get_Signature($Symbol, 1)
11814 );
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011815 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011816 elsif(not $CompleteSignature{2}{$PSymbol}{"Static"}
11817 and $CompleteSignature{1}{$Symbol}{"Static"} and $Symbol=~/\A(_Z|\?)/) {
11818 %{$CompatProblems{$Level}{$Symbol}{"Method_Became_NonStatic"}{""}}=(
11819 "Target"=>get_Signature($Symbol, 1)
11820 );
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011821 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011822 if(($CompleteSignature{1}{$Symbol}{"Virt"} and $CompleteSignature{2}{$PSymbol}{"Virt"})
11823 or ($CompleteSignature{1}{$Symbol}{"PureVirt"} and $CompleteSignature{2}{$PSymbol}{"PureVirt"}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011824 { # relative position of virtual and pure virtual methods
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011825 if($Level eq "Binary")
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011826 {
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040011827 if(defined $CompleteSignature{1}{$Symbol}{"RelPos"} and defined $CompleteSignature{2}{$PSymbol}{"RelPos"}
11828 and $CompleteSignature{1}{$Symbol}{"RelPos"}!=$CompleteSignature{2}{$PSymbol}{"RelPos"})
11829 { # top-level virtual methods only
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011830 my $Class_Id = $CompleteSignature{1}{$Symbol}{"Class"};
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040011831 my $Class_Name = $TypeInfo{1}{$Class_Id}{"Name"};
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040011832 if(defined $VirtualTable{1}{$Class_Name} and defined $VirtualTable{2}{$Class_Name}
11833 and $VirtualTable{1}{$Class_Name}{$Symbol}!=$VirtualTable{2}{$Class_Name}{$Symbol})
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011834 { # check the absolute position of virtual method (including added and removed methods)
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040011835 my %Class_Type = get_Type($Class_Id, 1);
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011836 my $ProblemType = "Virtual_Method_Position";
11837 if($CompleteSignature{1}{$Symbol}{"PureVirt"}) {
11838 $ProblemType = "Pure_Virtual_Method_Position";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011839 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011840 if(isUsedClass($Class_Id, 1, $Level))
11841 {
11842 my @Affected = ($Symbol, keys(%{$OverriddenMethods{1}{$Symbol}}));
11843 foreach my $AffectedInterface (@Affected)
11844 {
11845 %{$CompatProblems{$Level}{$AffectedInterface}{$ProblemType}{$tr_name{$MnglName}}}=(
11846 "Type_Name"=>$Class_Type{"Name"},
11847 "Type_Type"=>"Class",
11848 "Old_Value"=>$CompleteSignature{1}{$Symbol}{"RelPos"},
11849 "New_Value"=>$CompleteSignature{2}{$PSymbol}{"RelPos"},
11850 "Target"=>get_Signature($Symbol, 1) );
11851 }
Andrey Ponomarenko16934472012-03-29 15:37:04 +040011852 $VTableChanged_M{$Class_Type{"Name"}} = 1;
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011853 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011854 }
11855 }
11856 }
11857 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011858 if($CompleteSignature{1}{$Symbol}{"PureVirt"}
11859 or $CompleteSignature{2}{$PSymbol}{"PureVirt"})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011860 { # do NOT check type changes in pure virtuals
11861 next;
11862 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011863 $CheckedSymbols{$Level}{$Symbol}=1;
11864 if($Symbol=~/\A(_Z|\?)/
11865 or keys(%{$CompleteSignature{1}{$Symbol}{"Param"}})==keys(%{$CompleteSignature{2}{$PSymbol}{"Param"}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011866 { # C/C++: changes in parameters
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011867 foreach my $ParamPos (sort {int($a) <=> int($b)} keys(%{$CompleteSignature{1}{$Symbol}{"Param"}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011868 { # checking parameters
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011869 mergeParameters($Symbol, $PSymbol, $ParamPos, $ParamPos, $Level);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011870 }
11871 }
11872 else
11873 { # C: added/removed parameters
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011874 foreach my $ParamPos (sort {int($a) <=> int($b)} keys(%{$CompleteSignature{2}{$PSymbol}{"Param"}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011875 { # checking added parameters
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040011876 my $PType2_Id = $CompleteSignature{2}{$PSymbol}{"Param"}{$ParamPos}{"type"};
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040011877 my $PType2_Name = $TypeInfo{2}{$PType2_Id}{"Name"};
11878 last if($PType2_Name eq "...");
11879 my $PName = $CompleteSignature{2}{$PSymbol}{"Param"}{$ParamPos}{"name"};
11880 my $PName_Old = (defined $CompleteSignature{1}{$Symbol}{"Param"}{$ParamPos})?$CompleteSignature{1}{$Symbol}{"Param"}{$ParamPos}{"name"}:"";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011881 my $ParamPos_Prev = "-1";
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040011882 if($PName=~/\Ap\d+\Z/i)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011883 { # added unnamed parameter ( pN )
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040011884 my @Positions1 = find_ParamPair_Pos_byTypeAndPos($PType2_Name, $ParamPos, "backward", $Symbol, 1);
11885 my @Positions2 = find_ParamPair_Pos_byTypeAndPos($PType2_Name, $ParamPos, "backward", $Symbol, 2);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011886 if($#Positions1==-1 or $#Positions2>$#Positions1) {
11887 $ParamPos_Prev = "lost";
11888 }
11889 }
11890 else {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040011891 $ParamPos_Prev = find_ParamPair_Pos_byName($PName, $Symbol, 1);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011892 }
11893 if($ParamPos_Prev eq "lost")
11894 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011895 if($ParamPos>keys(%{$CompleteSignature{1}{$Symbol}{"Param"}})-1)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011896 {
11897 my $ProblemType = "Added_Parameter";
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040011898 if($PName=~/\Ap\d+\Z/) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011899 $ProblemType = "Added_Unnamed_Parameter";
11900 }
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040011901 %{$CompatProblems{$Level}{$Symbol}{$ProblemType}{showPos($ParamPos)." Parameter"}}=(
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040011902 "Target"=>$PName,
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011903 "Param_Pos"=>$ParamPos,
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040011904 "Param_Type"=>$PType2_Name,
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011905 "New_Signature"=>get_Signature($Symbol, 2) );
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011906 }
11907 else
11908 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040011909 my %ParamType_Pure = get_PureType($PType2_Id, 2);
11910 my $PairType_Id = $CompleteSignature{1}{$Symbol}{"Param"}{$ParamPos}{"type"};
11911 my %PairType_Pure = get_PureType($PairType_Id, 1);
11912 if(($ParamType_Pure{"Name"} eq $PairType_Pure{"Name"} or $PType2_Name eq $TypeInfo{1}{$PairType_Id}{"Name"})
11913 and find_ParamPair_Pos_byName($PName_Old, $Symbol, 2) eq "lost")
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011914 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040011915 if($PName_Old!~/\Ap\d+\Z/ and $PName!~/\Ap\d+\Z/)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011916 {
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040011917 %{$CompatProblems{$Level}{$Symbol}{"Renamed_Parameter"}{showPos($ParamPos)." Parameter"}}=(
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040011918 "Target"=>$PName_Old,
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011919 "Param_Pos"=>$ParamPos,
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040011920 "Param_Type"=>$PType2_Name,
11921 "Old_Value"=>$PName_Old,
11922 "New_Value"=>$PName,
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011923 "New_Signature"=>get_Signature($Symbol, 2) );
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011924 }
11925 }
11926 else
11927 {
11928 my $ProblemType = "Added_Middle_Parameter";
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040011929 if($PName=~/\Ap\d+\Z/) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011930 $ProblemType = "Added_Middle_Unnamed_Parameter";
11931 }
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040011932 %{$CompatProblems{$Level}{$Symbol}{$ProblemType}{showPos($ParamPos)." Parameter"}}=(
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040011933 "Target"=>$PName,
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011934 "Param_Pos"=>$ParamPos,
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040011935 "Param_Type"=>$PType2_Name,
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011936 "New_Signature"=>get_Signature($Symbol, 2) );
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011937 }
11938 }
11939 }
11940 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011941 foreach my $ParamPos (sort {int($a) <=> int($b)} keys(%{$CompleteSignature{1}{$Symbol}{"Param"}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011942 { # check relevant parameters
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040011943 my $PType1_Id = $CompleteSignature{1}{$Symbol}{"Param"}{$ParamPos}{"type"};
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011944 my $ParamName1 = $CompleteSignature{1}{$Symbol}{"Param"}{$ParamPos}{"name"};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011945 # FIXME: find relevant parameter by name
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011946 if(defined $CompleteSignature{2}{$PSymbol}{"Param"}{$ParamPos})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011947 {
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040011948 my $PType2_Id = $CompleteSignature{2}{$PSymbol}{"Param"}{$ParamPos}{"type"};
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011949 my $ParamName2 = $CompleteSignature{2}{$PSymbol}{"Param"}{$ParamPos}{"name"};
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040011950 if($TypeInfo{1}{$PType1_Id}{"Name"} eq $TypeInfo{2}{$PType2_Id}{"Name"}
11951 or ($ParamName1!~/\Ap\d+\Z/i and $ParamName1 eq $ParamName2)) {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011952 mergeParameters($Symbol, $PSymbol, $ParamPos, $ParamPos, $Level);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011953 }
11954 }
11955 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011956 foreach my $ParamPos (sort {int($a) <=> int($b)} keys(%{$CompleteSignature{1}{$Symbol}{"Param"}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011957 { # checking removed parameters
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040011958 my $PType1_Id = $CompleteSignature{1}{$Symbol}{"Param"}{$ParamPos}{"type"};
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040011959 my $PType1_Name = $TypeInfo{1}{$PType1_Id}{"Name"};
11960 last if($PType1_Name eq "...");
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011961 my $Parameter_Name = $CompleteSignature{1}{$Symbol}{"Param"}{$ParamPos}{"name"};
11962 my $Parameter_NewName = (defined $CompleteSignature{2}{$PSymbol}{"Param"}{$ParamPos})?$CompleteSignature{2}{$PSymbol}{"Param"}{$ParamPos}{"name"}:"";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011963 my $ParamPos_New = "-1";
11964 if($Parameter_Name=~/\Ap\d+\Z/i)
11965 { # removed unnamed parameter ( pN )
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040011966 my @Positions1 = find_ParamPair_Pos_byTypeAndPos($PType1_Name, $ParamPos, "forward", $Symbol, 1);
11967 my @Positions2 = find_ParamPair_Pos_byTypeAndPos($PType1_Name, $ParamPos, "forward", $Symbol, 2);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011968 if($#Positions2==-1 or $#Positions2<$#Positions1) {
11969 $ParamPos_New = "lost";
11970 }
11971 }
11972 else {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011973 $ParamPos_New = find_ParamPair_Pos_byName($Parameter_Name, $Symbol, 2);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011974 }
11975 if($ParamPos_New eq "lost")
11976 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011977 if($ParamPos>keys(%{$CompleteSignature{2}{$PSymbol}{"Param"}})-1)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011978 {
11979 my $ProblemType = "Removed_Parameter";
11980 if($Parameter_Name=~/\Ap\d+\Z/) {
11981 $ProblemType = "Removed_Unnamed_Parameter";
11982 }
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040011983 %{$CompatProblems{$Level}{$Symbol}{$ProblemType}{showPos($ParamPos)." Parameter"}}=(
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011984 "Target"=>$Parameter_Name,
11985 "Param_Pos"=>$ParamPos,
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040011986 "Param_Type"=>$PType1_Name,
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011987 "New_Signature"=>get_Signature($Symbol, 2) );
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011988 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011989 elsif($ParamPos<keys(%{$CompleteSignature{1}{$Symbol}{"Param"}})-1)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011990 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040011991 my %ParamType_Pure = get_PureType($PType1_Id, 1);
11992 my $PairType_Id = $CompleteSignature{2}{$PSymbol}{"Param"}{$ParamPos}{"type"};
11993 my %PairType_Pure = get_PureType($PairType_Id, 2);
11994 if(($ParamType_Pure{"Name"} eq $PairType_Pure{"Name"} or $PType1_Name eq $TypeInfo{2}{$PairType_Id}{"Name"})
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011995 and find_ParamPair_Pos_byName($Parameter_NewName, $Symbol, 1) eq "lost")
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011996 {
11997 if($Parameter_NewName!~/\Ap\d+\Z/ and $Parameter_Name!~/\Ap\d+\Z/)
11998 {
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040011999 %{$CompatProblems{$Level}{$Symbol}{"Renamed_Parameter"}{showPos($ParamPos)." Parameter"}}=(
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012000 "Target"=>$Parameter_Name,
12001 "Param_Pos"=>$ParamPos,
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040012002 "Param_Type"=>$PType1_Name,
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012003 "Old_Value"=>$Parameter_Name,
12004 "New_Value"=>$Parameter_NewName,
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012005 "New_Signature"=>get_Signature($Symbol, 2) );
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012006 }
12007 }
12008 else
12009 {
12010 my $ProblemType = "Removed_Middle_Parameter";
12011 if($Parameter_Name=~/\Ap\d+\Z/) {
12012 $ProblemType = "Removed_Middle_Unnamed_Parameter";
12013 }
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040012014 %{$CompatProblems{$Level}{$Symbol}{$ProblemType}{showPos($ParamPos)." Parameter"}}=(
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012015 "Target"=>$Parameter_Name,
12016 "Param_Pos"=>$ParamPos,
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040012017 "Param_Type"=>$PType1_Name,
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012018 "New_Signature"=>get_Signature($Symbol, 2) );
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012019 }
12020 }
12021 }
12022 }
12023 }
12024 # checking return type
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012025 my $ReturnType1_Id = $CompleteSignature{1}{$Symbol}{"Return"};
12026 my $ReturnType2_Id = $CompleteSignature{2}{$PSymbol}{"Return"};
12027 %SubProblems = detectTypeChange($ReturnType1_Id, $ReturnType2_Id, "Return", $Level);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012028 foreach my $SubProblemType (keys(%SubProblems))
12029 {
12030 my $New_Value = $SubProblems{$SubProblemType}{"New_Value"};
12031 my $Old_Value = $SubProblems{$SubProblemType}{"Old_Value"};
12032 my $NewProblemType = $SubProblemType;
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012033 if($Level eq "Binary" and $SubProblemType eq "Return_Type_Became_Void"
12034 and keys(%{$CompleteSignature{1}{$Symbol}{"Param"}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012035 { # parameters stack has been affected
12036 $NewProblemType = "Return_Type_Became_Void_And_Stack_Layout";
12037 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012038 elsif($Level eq "Binary"
12039 and $SubProblemType eq "Return_Type_From_Void")
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012040 { # parameters stack has been affected
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012041 if(keys(%{$CompleteSignature{1}{$Symbol}{"Param"}})) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012042 $NewProblemType = "Return_Type_From_Void_And_Stack_Layout";
12043 }
12044 else
12045 { # safe
12046 delete($SubProblems{$SubProblemType});
12047 next;
12048 }
12049 }
12050 elsif($SubProblemType eq "Return_Type_And_Size"
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012051 and $CompleteSignature{1}{$Symbol}{"Data"}) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012052 $NewProblemType = "Global_Data_Type_And_Size";
12053 }
12054 elsif($SubProblemType eq "Return_Type")
12055 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012056 if($CompleteSignature{1}{$Symbol}{"Data"})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012057 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012058 if(removedQual($Old_Value, $New_Value, "const"))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012059 { # const -> non-const global data
12060 $NewProblemType = "Global_Data_Became_Non_Const";
12061 }
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040012062 elsif(addedQual($Old_Value, $New_Value, "const"))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012063 { # non-const -> const global data
12064 $NewProblemType = "Global_Data_Became_Const";
12065 }
12066 else {
12067 $NewProblemType = "Global_Data_Type";
12068 }
12069 }
12070 else
12071 {
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040012072 if(addedQual($Old_Value, $New_Value, "const")) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012073 $NewProblemType = "Return_Type_Became_Const";
12074 }
12075 }
12076 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012077 elsif($SubProblemType eq "Return_Type_Format")
12078 {
12079 if($CompleteSignature{1}{$Symbol}{"Data"}) {
12080 $NewProblemType = "Global_Data_Type_Format";
12081 }
12082 }
12083 @{$CompatProblems{$Level}{$Symbol}{$NewProblemType}{"retval"}}{keys(%{$SubProblems{$SubProblemType}})} = values %{$SubProblems{$SubProblemType}};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012084 }
12085 if($ReturnType1_Id and $ReturnType2_Id)
12086 {
12087 @RecurTypes = ();
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040012088 %SubProblems = mergeTypes($ReturnType1_Id, $ReturnType2_Id, $Level);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012089 foreach my $SubProblemType (keys(%SubProblems))
12090 { # add "Global_Data_Size" problem
12091 my $New_Value = $SubProblems{$SubProblemType}{"New_Value"};
12092 my $Old_Value = $SubProblems{$SubProblemType}{"Old_Value"};
12093 if($SubProblemType eq "DataType_Size"
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012094 and $CompleteSignature{1}{$Symbol}{"Data"}
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040012095 and get_PLevel($ReturnType1_Id, 1)==0)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012096 { # add a new problem
12097 %{$SubProblems{"Global_Data_Size"}} = %{$SubProblems{$SubProblemType}};
12098 }
12099 }
12100 foreach my $SubProblemType (keys(%SubProblems))
12101 {
12102 foreach my $SubLocation (keys(%{$SubProblems{$SubProblemType}}))
12103 {
12104 my $NewLocation = ($SubLocation)?"retval->".$SubLocation:"retval";
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012105 %{$CompatProblems{$Level}{$Symbol}{$SubProblemType}{$NewLocation}}=(
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040012106 "Return_Type_Name"=>$TypeInfo{1}{$ReturnType1_Id}{"Name"} );
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012107 @{$CompatProblems{$Level}{$Symbol}{$SubProblemType}{$NewLocation}}{keys(%{$SubProblems{$SubProblemType}{$SubLocation}})} = values %{$SubProblems{$SubProblemType}{$SubLocation}};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012108 if($SubLocation!~/\-\>/) {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040012109 $CompatProblems{$Level}{$Symbol}{$SubProblemType}{$NewLocation}{"Start_Type_Name"} = $TypeInfo{1}{$ReturnType1_Id}{"Name"};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012110 }
12111 }
12112 }
12113 }
12114
12115 # checking object type
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040012116 my $ObjTId1 = $CompleteSignature{1}{$Symbol}{"Class"};
12117 my $ObjTId2 = $CompleteSignature{2}{$PSymbol}{"Class"};
12118 if($ObjTId1 and $ObjTId2
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012119 and not $CompleteSignature{1}{$Symbol}{"Static"})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012120 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040012121 my $ThisPtr1_Id = getTypeIdByName($TypeInfo{1}{$ObjTId1}{"Name"}."*const", 1);
12122 my $ThisPtr2_Id = getTypeIdByName($TypeInfo{2}{$ObjTId2}{"Name"}."*const", 2);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012123 if($ThisPtr1_Id and $ThisPtr2_Id)
12124 {
12125 @RecurTypes = ();
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040012126 %SubProblems = mergeTypes($ThisPtr1_Id, $ThisPtr2_Id, $Level);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012127 foreach my $SubProblemType (keys(%SubProblems))
12128 {
12129 foreach my $SubLocation (keys(%{$SubProblems{$SubProblemType}}))
12130 {
12131 my $NewLocation = ($SubLocation)?"this->".$SubLocation:"this";
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012132 %{$CompatProblems{$Level}{$Symbol}{$SubProblemType}{$NewLocation}}=(
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040012133 "Object_Type_Name"=>$TypeInfo{1}{$ObjTId1}{"Name"} );
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012134 @{$CompatProblems{$Level}{$Symbol}{$SubProblemType}{$NewLocation}}{keys(%{$SubProblems{$SubProblemType}{$SubLocation}})} = values %{$SubProblems{$SubProblemType}{$SubLocation}};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012135 if($SubLocation!~/\-\>/) {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040012136 $CompatProblems{$Level}{$Symbol}{$SubProblemType}{$NewLocation}{"Start_Type_Name"} = $TypeInfo{1}{$ObjTId1}{"Name"};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012137 }
12138 }
12139 }
12140 }
12141 }
12142 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012143 if($Level eq "Binary") {
12144 mergeVTables($Level);
12145 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +040012146 foreach my $Symbol (keys(%{$CompatProblems{$Level}})) {
12147 $CheckedSymbols{$Level}{$Symbol} = 1;
12148 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012149}
12150
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040012151sub rmQuals($$)
12152{
12153 my ($Value, $Qual) = @_;
12154 if(not $Qual) {
12155 return $Value;
12156 }
12157 if($Qual eq "all")
12158 { # all quals
12159 $Qual = "const|volatile|restrict";
12160 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040012161 while($Value=~s/\b$Qual\b//) {
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040012162 $Value = formatName($Value);
12163 }
12164 return $Value;
12165}
12166
12167sub cmpBTypes($$$$)
12168{
12169 my ($T1, $T2, $V1, $V2) = @_;
12170 $T1 = uncover_typedefs($T1, $V1);
12171 $T2 = uncover_typedefs($T2, $V2);
12172 return (rmQuals($T1, "all") eq rmQuals($T2, "all"));
12173}
12174
12175sub addedQual($$$)
12176{
12177 my ($Old_Value, $New_Value, $Qual) = @_;
Andrey Ponomarenko85043792012-05-14 16:48:07 +040012178 return removedQual_($New_Value, $Old_Value, 2, 1, $Qual);
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040012179}
12180
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012181sub removedQual($$$)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012182{
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012183 my ($Old_Value, $New_Value, $Qual) = @_;
Andrey Ponomarenko85043792012-05-14 16:48:07 +040012184 return removedQual_($Old_Value, $New_Value, 1, 2, $Qual);
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040012185}
12186
12187sub removedQual_($$$$$)
12188{
12189 my ($Old_Value, $New_Value, $V1, $V2, $Qual) = @_;
12190 $Old_Value = uncover_typedefs($Old_Value, $V1);
12191 $New_Value = uncover_typedefs($New_Value, $V2);
12192 if($Old_Value eq $New_Value)
12193 { # equal types
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012194 return 0;
12195 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040012196 if($Old_Value!~/\b$Qual\b/)
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040012197 { # without a qual
12198 return 0;
12199 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040012200 elsif($New_Value!~/\b$Qual\b/)
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040012201 { # became non-qual
12202 return 1;
12203 }
12204 else
12205 {
12206 my @BQ1 = getQualModel($Old_Value, $Qual);
12207 my @BQ2 = getQualModel($New_Value, $Qual);
12208 foreach (0 .. $#BQ1)
12209 { # removed qual
12210 if($BQ1[$_]==1
12211 and $BQ2[$_]!=1)
12212 {
12213 return 2;
12214 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012215 }
12216 }
12217 return 0;
12218}
12219
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040012220sub getQualModel($$)
12221{
12222 my ($Value, $Qual) = @_;
12223 if(not $Qual) {
12224 return $Value;
12225 }
12226
12227 # cleaning
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040012228 while($Value=~/(\w+)/ and $1 ne $Qual) {
12229 $Value=~s/\b$1\b//g;
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040012230 }
12231 $Value=~s/[^\*\&\w]+//g;
12232
12233 # modeling
12234 # int*const*const == 011
12235 # int**const == 001
12236 my @Model = ();
12237 my @Elems = split(/[\*\&]/, $Value);
12238 if(not @Elems) {
12239 return (0);
12240 }
12241 foreach (@Elems)
12242 {
12243 if($_ eq $Qual) {
12244 push(@Model, 1);
12245 }
12246 else {
12247 push(@Model, 0);
12248 }
12249 }
12250
12251 return @Model;
12252}
12253
12254sub showVal($$$)
12255{
12256 my ($Value, $TypeId, $LibVersion) = @_;
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040012257 my %PureType = get_PureType($TypeId, $LibVersion);
Andrey Ponomarenkoa01311b2012-06-08 17:20:02 +040012258 my $TName = uncover_typedefs($PureType{"Name"}, $LibVersion);
12259 if($TName=~/\A(char(| const)\*|std::(string|basic_string<char>)(|&))\Z/)
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040012260 { # strings
12261 return "\"$Value\"";
12262 }
Andrey Ponomarenkoa01311b2012-06-08 17:20:02 +040012263 elsif($TName=~/\Achar(| const)\Z/)
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040012264 { # characters
12265 return "\'$Value\'";
12266 }
12267 return $Value;
12268}
12269
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012270sub mergeParameters($$$$$)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012271{
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012272 my ($Symbol, $PSymbol, $ParamPos1, $ParamPos2, $Level) = @_;
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040012273 if(not $Symbol) {
12274 return;
12275 }
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040012276 my $PType1_Id = $CompleteSignature{1}{$Symbol}{"Param"}{$ParamPos1}{"type"};
12277 my $PName1 = $CompleteSignature{1}{$Symbol}{"Param"}{$ParamPos1}{"name"};
12278 my $PType2_Id = $CompleteSignature{2}{$PSymbol}{"Param"}{$ParamPos2}{"type"};
12279 my $PName2 = $CompleteSignature{2}{$PSymbol}{"Param"}{$ParamPos2}{"name"};
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040012280 if(not $PType1_Id
12281 or not $PType2_Id) {
12282 return;
12283 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040012284 my %Type1 = get_Type($PType1_Id, 1);
12285 my %Type2 = get_Type($PType2_Id, 2);
12286 my %BaseType1 = get_BaseType($PType1_Id, 1);
12287 my %BaseType2 = get_BaseType($PType2_Id, 2);
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040012288 my $Parameter_Location = ($PName1)?$PName1:showPos($ParamPos1)." Parameter";
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012289 if($Level eq "Binary")
12290 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040012291 if(checkDump(1, "2.6.1") and checkDump(2, "2.6.1"))
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012292 { # "reg" attribute added in ACC 1.95.1 (dump 2.6.1 format)
12293 if($CompleteSignature{1}{$Symbol}{"Param"}{$ParamPos1}{"reg"}
12294 and not $CompleteSignature{2}{$PSymbol}{"Param"}{$ParamPos2}{"reg"})
12295 {
12296 %{$CompatProblems{$Level}{$Symbol}{"Parameter_Became_Non_Register"}{$Parameter_Location}}=(
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040012297 "Target"=>$PName1,
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012298 "Param_Pos"=>$ParamPos1 );
12299 }
12300 elsif(not $CompleteSignature{1}{$Symbol}{"Param"}{$ParamPos1}{"reg"}
12301 and $CompleteSignature{2}{$PSymbol}{"Param"}{$ParamPos2}{"reg"})
12302 {
12303 %{$CompatProblems{$Level}{$Symbol}{"Parameter_Became_Register"}{$Parameter_Location}}=(
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040012304 "Target"=>$PName1,
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012305 "Param_Pos"=>$ParamPos1 );
12306 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012307 }
12308 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040012309 if(checkDump(1, "2.0") and checkDump(2, "2.0"))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012310 { # "default" attribute added in ACC 1.22 (dump 2.0 format)
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040012311 my $Value_Old = $CompleteSignature{1}{$Symbol}{"Param"}{$ParamPos1}{"default"};
12312 my $Value_New = $CompleteSignature{2}{$PSymbol}{"Param"}{$ParamPos2}{"default"};
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040012313 if(not checkDump(1, "2.13")
12314 and checkDump(2, "2.13"))
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040012315 { # support for old ABI dumps
12316 if(defined $Value_Old and defined $Value_New)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012317 {
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040012318 if($Type1{"Name"} eq "bool"
12319 and $Value_Old eq "false" and $Value_New eq "0")
12320 { # int class::method ( bool p = 0 );
12321 # old ABI dumps: "false"
12322 # new ABI dumps: "0"
12323 $Value_Old = "0";
12324 }
12325 }
12326 }
12327 if(defined $Value_Old)
12328 {
12329 $Value_Old = showVal($Value_Old, $PType1_Id, 1);
12330 if(defined $Value_New)
12331 {
12332 $Value_New = showVal($Value_New, $PType2_Id, 2);
12333 if($Value_Old ne $Value_New)
12334 { # FIXME: how to distinguish "0" and 0 (NULL)
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012335 %{$CompatProblems{$Level}{$Symbol}{"Parameter_Default_Value_Changed"}{$Parameter_Location}}=(
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040012336 "Target"=>$PName1,
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012337 "Param_Pos"=>$ParamPos1,
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040012338 "Old_Value"=>$Value_Old,
12339 "New_Value"=>$Value_New );
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012340 }
12341 }
12342 else
12343 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012344 %{$CompatProblems{$Level}{$Symbol}{"Parameter_Default_Value_Removed"}{$Parameter_Location}}=(
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040012345 "Target"=>$PName1,
12346 "Param_Pos"=>$ParamPos1,
12347 "Old_Value"=>$Value_Old );
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012348 }
12349 }
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040012350 elsif(defined $Value_New)
12351 {
12352 $Value_New = showVal($Value_New, $PType2_Id, 2);
12353 %{$CompatProblems{$Level}{$Symbol}{"Parameter_Default_Value_Added"}{$Parameter_Location}}=(
12354 "Target"=>$PName1,
12355 "Param_Pos"=>$ParamPos1,
12356 "New_Value"=>$Value_New );
12357 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012358 }
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040012359 if($PName1 and $PName2 and $PName1 ne $PName2
12360 and $PType1_Id!=-1 and $PType2_Id!=-1
12361 and $PName1!~/\Ap\d+\Z/ and $PName2!~/\Ap\d+\Z/)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012362 { # except unnamed "..." value list (Id=-1)
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040012363 %{$CompatProblems{$Level}{$Symbol}{"Renamed_Parameter"}{showPos($ParamPos1)." Parameter"}}=(
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040012364 "Target"=>$PName1,
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012365 "Param_Pos"=>$ParamPos1,
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040012366 "Param_Type"=>$TypeInfo{1}{$PType1_Id}{"Name"},
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040012367 "Old_Value"=>$PName1,
12368 "New_Value"=>$PName2,
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012369 "New_Signature"=>get_Signature($Symbol, 2) );
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012370 }
12371 # checking type change (replace)
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040012372 my %SubProblems = detectTypeChange($PType1_Id, $PType2_Id, "Parameter", $Level);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012373 foreach my $SubProblemType (keys(%SubProblems))
12374 { # add new problems, remove false alarms
12375 my $New_Value = $SubProblems{$SubProblemType}{"New_Value"};
12376 my $Old_Value = $SubProblems{$SubProblemType}{"Old_Value"};
12377 if($SubProblemType eq "Parameter_Type")
12378 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040012379 if(checkDump(1, "2.6") and checkDump(2, "2.6"))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012380 {
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040012381 if(my $RA = addedQual($Old_Value, $New_Value, "restrict"))
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012382 {
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040012383 %{$SubProblems{"Parameter_Became_Restrict"}} = %{$SubProblems{$SubProblemType}};
12384 if($Level eq "Source"
12385 and cmpBTypes($Old_Value, $New_Value, 1, 2)) {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012386 delete($SubProblems{$SubProblemType});
12387 }
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040012388 }
12389 elsif(my $RR = removedQual($Old_Value, $New_Value, "restrict"))
12390 {
12391 %{$SubProblems{"Parameter_Became_NonRestrict"}} = %{$SubProblems{$SubProblemType}};
12392 if($Level eq "Source"
12393 and cmpBTypes($Old_Value, $New_Value, 1, 2)) {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012394 delete($SubProblems{$SubProblemType});
12395 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012396 }
12397 }
12398 if($Type2{"Type"} eq "Const" and $BaseType2{"Name"} eq $Type1{"Name"}
12399 and $Type1{"Type"}=~/Intrinsic|Class|Struct|Union|Enum/)
12400 { # int to "int const"
12401 delete($SubProblems{$SubProblemType});
12402 }
12403 if($Type1{"Type"} eq "Const" and $BaseType1{"Name"} eq $Type2{"Name"}
12404 and $Type2{"Type"}=~/Intrinsic|Class|Struct|Union|Enum/)
12405 { # "int const" to int
12406 delete($SubProblems{$SubProblemType});
12407 }
12408 }
12409 }
12410 foreach my $SubProblemType (keys(%SubProblems))
12411 { # modify/register problems
12412 my $New_Value = $SubProblems{$SubProblemType}{"New_Value"};
12413 my $Old_Value = $SubProblems{$SubProblemType}{"Old_Value"};
12414 my $NewProblemType = $SubProblemType;
12415 if($Old_Value eq "..." and $New_Value ne "...")
12416 { # change from "..." to "int"
12417 if($ParamPos1==0)
12418 { # ISO C requires a named argument before "..."
12419 next;
12420 }
12421 $NewProblemType = "Parameter_Became_NonVaList";
12422 }
12423 elsif($New_Value eq "..." and $Old_Value ne "...")
12424 { # change from "int" to "..."
12425 if($ParamPos2==0)
12426 { # ISO C requires a named argument before "..."
12427 next;
12428 }
12429 $NewProblemType = "Parameter_Became_VaList";
12430 }
12431 elsif($SubProblemType eq "Parameter_Type"
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012432 and removedQual($Old_Value, $New_Value, "const"))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012433 { # parameter: "const" to non-"const"
12434 $NewProblemType = "Parameter_Became_Non_Const";
12435 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012436 elsif($Level eq "Binary" and ($SubProblemType eq "Parameter_Type_And_Size"
12437 or $SubProblemType eq "Parameter_Type"))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012438 {
12439 my ($Arch1, $Arch2) = (getArch(1), getArch(2));
12440 if($Arch1 eq "unknown" or $Arch2 eq "unknown")
12441 { # if one of the architectures is unknown
12442 # then set other arhitecture to unknown too
12443 ($Arch1, $Arch2) = ("unknown", "unknown");
12444 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012445 my ($Method1, $Passed1, $SizeOnStack1, $RegName1) = callingConvention($Symbol, $ParamPos1, 1, $Arch1);
12446 my ($Method2, $Passed2, $SizeOnStack2, $RegName2) = callingConvention($Symbol, $ParamPos2, 2, $Arch2);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012447 if($Method1 eq $Method2)
12448 {
12449 if($Method1 eq "stack" and $SizeOnStack1 ne $SizeOnStack2) {
12450 $NewProblemType = "Parameter_Type_And_Stack";
12451 }
12452 elsif($Method1 eq "register" and $RegName1 ne $RegName2) {
12453 $NewProblemType = "Parameter_Type_And_Register";
12454 }
12455 }
12456 else
12457 {
12458 if($Method1 eq "stack") {
12459 $NewProblemType = "Parameter_Type_And_Pass_Through_Register";
12460 }
12461 elsif($Method1 eq "register") {
12462 $NewProblemType = "Parameter_Type_And_Pass_Through_Stack";
12463 }
12464 }
12465 $SubProblems{$SubProblemType}{"Old_Reg"} = $RegName1;
12466 $SubProblems{$SubProblemType}{"New_Reg"} = $RegName2;
12467 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012468 %{$CompatProblems{$Level}{$Symbol}{$NewProblemType}{$Parameter_Location}}=(
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040012469 "Target"=>$PName1,
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012470 "Param_Pos"=>$ParamPos1,
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012471 "New_Signature"=>get_Signature($Symbol, 2) );
12472 @{$CompatProblems{$Level}{$Symbol}{$NewProblemType}{$Parameter_Location}}{keys(%{$SubProblems{$SubProblemType}})} = values %{$SubProblems{$SubProblemType}};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012473 }
12474 @RecurTypes = ();
12475 # checking type definition changes
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040012476 my %SubProblems_Merge = mergeTypes($PType1_Id, $PType2_Id, $Level);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012477 foreach my $SubProblemType (keys(%SubProblems_Merge))
12478 {
12479 foreach my $SubLocation (keys(%{$SubProblems_Merge{$SubProblemType}}))
12480 {
12481 my $NewProblemType = $SubProblemType;
12482 if($SubProblemType eq "DataType_Size")
12483 {
12484 my $InitialType_Type = $SubProblems_Merge{$SubProblemType}{$SubLocation}{"InitialType_Type"};
12485 if($InitialType_Type!~/\A(Pointer|Ref)\Z/ and $SubLocation!~/\-\>/)
12486 { # stack has been affected
12487 $NewProblemType = "DataType_Size_And_Stack";
12488 }
12489 }
12490 my $NewLocation = ($SubLocation)?$Parameter_Location."->".$SubLocation:$Parameter_Location;
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012491 %{$CompatProblems{$Level}{$Symbol}{$NewProblemType}{$NewLocation}}=(
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040012492 "Param_Type"=>$TypeInfo{1}{$PType1_Id}{"Name"},
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012493 "Param_Pos"=>$ParamPos1,
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040012494 "Param_Name"=>$PName1 );
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012495 @{$CompatProblems{$Level}{$Symbol}{$NewProblemType}{$NewLocation}}{keys(%{$SubProblems_Merge{$SubProblemType}{$SubLocation}})} = values %{$SubProblems_Merge{$SubProblemType}{$SubLocation}};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012496 if($SubLocation!~/\-\>/) {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040012497 $CompatProblems{$Level}{$Symbol}{$NewProblemType}{$NewLocation}{"Start_Type_Name"} = $TypeInfo{1}{$PType1_Id}{"Name"};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012498 }
12499 }
12500 }
12501}
12502
12503sub callingConvention($$$$)
12504{ # calling conventions for different compilers and operating systems
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012505 my ($Symbol, $ParamPos, $LibVersion, $Arch) = @_;
12506 my $ParamTypeId = $CompleteSignature{$LibVersion}{$Symbol}{"Param"}{$ParamPos}{"type"};
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040012507 my %Type = get_PureType($ParamTypeId, $LibVersion);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012508 my ($Method, $Alignment, $Passed, $Register) = ("", 0, "", "");
12509 if($OSgroup=~/\A(linux|macos|freebsd)\Z/)
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012510 { # GCC
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012511 if($Arch eq "x86")
12512 { # System V ABI Intel386 ("Function Calling Sequence")
12513 # The stack is word aligned. Although the architecture does not require any
12514 # alignment of the stack, software convention and the operating system
12515 # requires that the stack be aligned on a word boundary.
12516
12517 # Argument words are pushed onto the stack in reverse order (that is, the
12518 # rightmost argument in C call syntax has the highest address), preserving the
12519 # stack’s word alignment. All incoming arguments appear on the stack, residing
12520 # in the stack frame of the caller.
12521
12522 # An argument’s size is increased, if necessary, to make it a multiple of words.
12523 # This may require tail padding, depending on the size of the argument.
12524
12525 # Other areas depend on the compiler and the code being compiled. The stan-
12526 # dard calling sequence does not define a maximum stack frame size, nor does
12527 # it restrict how a language system uses the ‘‘unspecified’’ area of the stan-
12528 # dard stack frame.
12529 ($Method, $Alignment) = ("stack", 4);
12530 }
12531 elsif($Arch eq "x86_64")
12532 { # System V AMD64 ABI ("Function Calling Sequence")
12533 ($Method, $Alignment) = ("stack", 8);# eightbyte aligned
12534 }
12535 elsif($Arch eq "arm")
12536 { # Procedure Call Standard for the ARM Architecture
12537 # The stack must be double-word aligned
12538 ($Method, $Alignment) = ("stack", 8);# double-word
12539 }
12540 }
12541 elsif($OSgroup eq "windows")
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012542 { # MS C++ Compiler
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012543 if($Arch eq "x86")
12544 {
12545 if($ParamPos==0) {
12546 ($Method, $Register, $Passed) = ("register", "ecx", "value");
12547 }
12548 elsif($ParamPos==1) {
12549 ($Method, $Register, $Passed) = ("register", "edx", "value");
12550 }
12551 else {
12552 ($Method, $Alignment) = ("stack", 4);
12553 }
12554 }
12555 elsif($Arch eq "x86_64")
12556 {
12557 if($ParamPos<=3)
12558 {
12559 if($Type{"Name"}=~/\A(float|double|long double)\Z/) {
12560 ($Method, $Passed) = ("xmm".$ParamPos, "value");
12561 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040012562 elsif(isScalar($Type{"Name"})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012563 or $Type{"Type"}=~/\A(Struct|Union|Enum|Array)\Z/
12564 or $Type{"Name"}=~/\A(__m64|__m128)\Z/)
12565 {
12566 if($ParamPos==0) {
12567 ($Method, $Register, $Passed) = ("register", "rcx", "value");
12568 }
12569 elsif($ParamPos==1) {
12570 ($Method, $Register, $Passed) = ("register", "rdx", "value");
12571 }
12572 elsif($ParamPos==2) {
12573 ($Method, $Register, $Passed) = ("register", "r8", "value");
12574 }
12575 elsif($ParamPos==3) {
12576 ($Method, $Register, $Passed) = ("register", "r9", "value");
12577 }
12578 if($Type{"Size"}>64
12579 or $Type{"Type"} eq "Array") {
12580 $Passed = "pointer";
12581 }
12582 }
12583 }
12584 else {
12585 ($Method, $Alignment) = ("stack", 8);# word alignment
12586 }
12587 }
12588 }
12589 if($Method eq "register") {
12590 return ("register", $Passed, "", $Register);
12591 }
12592 else
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012593 { # on the stack
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012594 if(not $Alignment)
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012595 { # default convention
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012596 $Alignment = $WORD_SIZE{$LibVersion};
12597 }
12598 if(not $Passed)
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012599 { # default convention
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012600 $Passed = "value";
12601 }
12602 my $SizeOnStack = $Type{"Size"};
12603 # FIXME: improve stack alignment
12604 if($SizeOnStack!=$Alignment) {
12605 $SizeOnStack = int(($Type{"Size"}+$Alignment)/$Alignment)*$Alignment;
12606 }
12607 return ("stack", $Passed, $SizeOnStack, "");
12608 }
12609}
12610
12611sub find_ParamPair_Pos_byName($$$)
12612{
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012613 my ($Name, $Symbol, $LibVersion) = @_;
12614 foreach my $ParamPos (sort {int($a)<=>int($b)} keys(%{$CompleteSignature{$LibVersion}{$Symbol}{"Param"}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012615 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012616 next if(not defined $CompleteSignature{$LibVersion}{$Symbol}{"Param"}{$ParamPos});
12617 if($CompleteSignature{$LibVersion}{$Symbol}{"Param"}{$ParamPos}{"name"} eq $Name)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012618 {
12619 return $ParamPos;
12620 }
12621 }
12622 return "lost";
12623}
12624
12625sub find_ParamPair_Pos_byTypeAndPos($$$$$)
12626{
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012627 my ($TypeName, $MediumPos, $Order, $Symbol, $LibVersion) = @_;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012628 my @Positions = ();
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012629 foreach my $ParamPos (sort {int($a)<=>int($b)} keys(%{$CompleteSignature{$LibVersion}{$Symbol}{"Param"}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012630 {
12631 next if($Order eq "backward" and $ParamPos>$MediumPos);
12632 next if($Order eq "forward" and $ParamPos<$MediumPos);
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012633 next if(not defined $CompleteSignature{$LibVersion}{$Symbol}{"Param"}{$ParamPos});
12634 my $PTypeId = $CompleteSignature{$LibVersion}{$Symbol}{"Param"}{$ParamPos}{"type"};
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040012635 if($TypeInfo{$LibVersion}{$PTypeId}{"Name"} eq $TypeName) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012636 push(@Positions, $ParamPos);
12637 }
12638 }
12639 return @Positions;
12640}
12641
12642sub getTypeIdByName($$)
12643{
12644 my ($TypeName, $Version) = @_;
12645 return $TName_Tid{$Version}{formatName($TypeName)};
12646}
12647
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012648sub checkFormatChange($$$)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012649{
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012650 my ($Type1_Id, $Type2_Id, $Level) = @_;
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040012651 my %Type1_Pure = get_PureType($Type1_Id, 1);
12652 my %Type2_Pure = get_PureType($Type2_Id, 2);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012653 if($Type1_Pure{"Name"} eq $Type2_Pure{"Name"})
12654 { # equal types
12655 return 0;
12656 }
12657 if($Type1_Pure{"Name"}=~/\*/
12658 or $Type2_Pure{"Name"}=~/\*/)
12659 { # compared in detectTypeChange()
12660 return 0;
12661 }
12662 my %FloatType = map {$_=>1} (
12663 "float",
12664 "double",
12665 "long double"
12666 );
12667 if($Type1_Pure{"Type"} ne $Type2_Pure{"Type"})
12668 { # different types
12669 if($Type1_Pure{"Type"} eq "Intrinsic"
12670 and $Type2_Pure{"Type"} eq "Enum")
12671 { # "int" to "enum"
12672 return 0;
12673 }
12674 elsif($Type2_Pure{"Type"} eq "Intrinsic"
12675 and $Type1_Pure{"Type"} eq "Enum")
12676 { # "enum" to "int"
12677 return 0;
12678 }
12679 else
12680 { # "union" to "struct"
12681 # ...
12682 return 1;
12683 }
12684 }
12685 else
12686 {
12687 if($Type1_Pure{"Type"} eq "Intrinsic")
12688 {
12689 if($FloatType{$Type1_Pure{"Name"}}
12690 or $FloatType{$Type2_Pure{"Name"}})
12691 { # "float" to "double"
12692 # "float" to "int"
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012693 if($Level eq "Source")
12694 { # Safe
12695 return 0;
12696 }
12697 else {
12698 return 1;
12699 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012700 }
12701 }
12702 elsif($Type1_Pure{"Type"}=~/Class|Struct|Union|Enum/)
12703 {
12704 my @Membs1 = keys(%{$Type1_Pure{"Memb"}});
12705 my @Membs2 = keys(%{$Type2_Pure{"Memb"}});
12706 if($#Membs1!=$#Membs2)
12707 { # different number of elements
12708 return 1;
12709 }
12710 if($Type1_Pure{"Type"} eq "Enum")
12711 {
12712 foreach my $Pos (@Membs1)
12713 { # compare elements by name and value
12714 if($Type1_Pure{"Memb"}{$Pos}{"name"} ne $Type2_Pure{"Memb"}{$Pos}{"name"}
12715 or $Type1_Pure{"Memb"}{$Pos}{"value"} ne $Type2_Pure{"Memb"}{$Pos}{"value"})
12716 { # different names
12717 return 1;
12718 }
12719 }
12720 }
12721 else
12722 {
12723 foreach my $Pos (@Membs1)
12724 { # compare elements by type name
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040012725 my $MT1 = $TypeInfo{1}{$Type1_Pure{"Memb"}{$Pos}{"type"}}{"Name"};
12726 my $MT2 = $TypeInfo{2}{$Type2_Pure{"Memb"}{$Pos}{"type"}}{"Name"};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012727 if($MT1 ne $MT2)
12728 { # different types
12729 return 1;
12730 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012731 if($Level eq "Source")
12732 {
12733 if($Type1_Pure{"Memb"}{$Pos}{"name"} ne $Type2_Pure{"Memb"}{$Pos}{"name"})
12734 { # different names
12735 return 1;
12736 }
12737 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012738 }
12739 }
12740 }
12741 }
12742 return 0;
12743}
12744
12745sub isScalar($) {
12746 return ($_[0]=~/\A(unsigned |)(short|int|long|long long)\Z/);
12747}
12748
12749sub isFloat($) {
12750 return ($_[0]=~/\A(float|double|long double)\Z/);
12751}
12752
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012753sub detectTypeChange($$$$)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012754{
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012755 my ($Type1_Id, $Type2_Id, $Prefix, $Level) = @_;
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040012756 if(not $Type1_Id or not $Type2_Id) {
12757 return ();
12758 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012759 my %LocalProblems = ();
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040012760 my %Type1 = get_Type($Type1_Id, 1);
12761 my %Type2 = get_Type($Type2_Id, 2);
12762 my %Type1_Pure = get_PureType($Type1_Id, 1);
12763 my %Type2_Pure = get_PureType($Type2_Id, 2);
12764 my %Type1_Base = ($Type1_Pure{"Type"} eq "Array")?get_OneStep_BaseType($Type1_Pure{"Tid"}, 1):get_BaseType($Type1_Id, 1);
12765 my %Type2_Base = ($Type2_Pure{"Type"} eq "Array")?get_OneStep_BaseType($Type2_Pure{"Tid"}, 2):get_BaseType($Type2_Id, 2);
12766 my $Type1_PLevel = get_PLevel($Type1_Id, 1);
12767 my $Type2_PLevel = get_PLevel($Type2_Id, 2);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012768 return () if(not $Type1{"Name"} or not $Type2{"Name"});
12769 return () if(not $Type1_Base{"Name"} or not $Type2_Base{"Name"});
12770 return () if($Type1_PLevel eq "" or $Type2_PLevel eq "");
12771 if($Type1_Base{"Name"} ne $Type2_Base{"Name"}
12772 and ($Type1{"Name"} eq $Type2{"Name"} or ($Type1_PLevel>=1 and $Type1_PLevel==$Type2_PLevel
12773 and $Type1_Base{"Name"} ne "void" and $Type2_Base{"Name"} ne "void")))
12774 { # base type change
12775 if($Type1{"Type"} eq "Typedef" and $Type2{"Type"} eq "Typedef"
12776 and $Type1{"Name"} eq $Type2{"Name"})
12777 { # will be reported in mergeTypes() as typedef problem
12778 return ();
12779 }
12780 if($Type1_Base{"Name"}!~/anon\-/ and $Type2_Base{"Name"}!~/anon\-/)
12781 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012782 if($Level eq "Binary"
12783 and $Type1_Base{"Size"} ne $Type2_Base{"Size"}
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012784 and $Type1_Base{"Size"} and $Type2_Base{"Size"})
12785 {
12786 %{$LocalProblems{$Prefix."_BaseType_And_Size"}}=(
12787 "Old_Value"=>$Type1_Base{"Name"},
12788 "New_Value"=>$Type2_Base{"Name"},
12789 "Old_Size"=>$Type1_Base{"Size"}*$BYTE_SIZE,
12790 "New_Size"=>$Type2_Base{"Size"}*$BYTE_SIZE,
12791 "InitialType_Type"=>$Type1_Pure{"Type"});
12792 }
12793 else
12794 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012795 if(checkFormatChange($Type1_Base{"Tid"}, $Type2_Base{"Tid"}, $Level))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012796 { # format change
12797 %{$LocalProblems{$Prefix."_BaseType_Format"}}=(
12798 "Old_Value"=>$Type1_Base{"Name"},
12799 "New_Value"=>$Type2_Base{"Name"},
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012800 "InitialType_Type"=>$Type1_Pure{"Type"});
12801 }
12802 elsif(tNameLock($Type1_Base{"Tid"}, $Type2_Base{"Tid"}))
12803 {
12804 %{$LocalProblems{$Prefix."_BaseType"}}=(
12805 "Old_Value"=>$Type1_Base{"Name"},
12806 "New_Value"=>$Type2_Base{"Name"},
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012807 "InitialType_Type"=>$Type1_Pure{"Type"});
12808 }
12809 }
12810 }
12811 }
12812 elsif($Type1{"Name"} ne $Type2{"Name"})
12813 { # type change
12814 if($Type1{"Name"}!~/anon\-/ and $Type2{"Name"}!~/anon\-/)
12815 {
12816 if($Prefix eq "Return" and $Type1{"Name"} eq "void"
12817 and $Type2_Pure{"Type"}=~/Intrinsic|Enum/) {
12818 # safe change
12819 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012820 elsif($Level eq "Binary"
12821 and $Prefix eq "Return"
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012822 and $Type1_Pure{"Name"} eq "void")
12823 {
12824 %{$LocalProblems{"Return_Type_From_Void"}}=(
12825 "New_Value"=>$Type2{"Name"},
12826 "New_Size"=>$Type2{"Size"}*$BYTE_SIZE,
12827 "InitialType_Type"=>$Type1_Pure{"Type"});
12828 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012829 elsif($Level eq "Binary"
12830 and $Prefix eq "Return" and $Type1_Pure{"Type"}=~/Intrinsic|Enum/
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012831 and $Type2_Pure{"Type"}=~/Struct|Class|Union/)
12832 { # returns into hidden first parameter instead of a register
12833
12834 # System V ABI Intel386 ("Function Calling Sequence")
12835 # A function that returns an integral or pointer value places its result in register %eax.
12836
12837 # A floating-point return value appears on the top of the Intel387 register stack. The
12838 # caller then must remove the value from the Intel387 stack, even if it doesn’t use the
12839 # value.
12840
12841 # If a function returns a structure or union, then the caller provides space for the
12842 # return value and places its address on the stack as argument word zero. In effect,
12843 # this address becomes a ‘‘hidden’’ first argument.
12844
12845 %{$LocalProblems{"Return_Type_From_Register_To_Stack"}}=(
12846 "Old_Value"=>$Type1{"Name"},
12847 "New_Value"=>$Type2{"Name"},
12848 "Old_Size"=>$Type1{"Size"}*$BYTE_SIZE,
12849 "New_Size"=>$Type2{"Size"}*$BYTE_SIZE,
12850 "InitialType_Type"=>$Type1_Pure{"Type"});
12851 }
12852 elsif($Prefix eq "Return"
12853 and $Type2_Pure{"Name"} eq "void")
12854 {
12855 %{$LocalProblems{"Return_Type_Became_Void"}}=(
12856 "Old_Value"=>$Type1{"Name"},
12857 "Old_Size"=>$Type1{"Size"}*$BYTE_SIZE,
12858 "InitialType_Type"=>$Type1_Pure{"Type"});
12859 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012860 elsif($Level eq "Binary" and $Prefix eq "Return"
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012861 and ((isScalar($Type1_Pure{"Name"}) and isFloat($Type2_Pure{"Name"}))
12862 or (isScalar($Type2_Pure{"Name"}) and isFloat($Type1_Pure{"Name"}))))
12863 { # The scalar and floating-point values are passed in different registers
12864 %{$LocalProblems{"Return_Type_And_Register"}}=(
12865 "Old_Value"=>$Type1{"Name"},
12866 "New_Value"=>$Type2{"Name"},
12867 "Old_Size"=>$Type1{"Size"}*$BYTE_SIZE,
12868 "New_Size"=>$Type2{"Size"}*$BYTE_SIZE,
12869 "InitialType_Type"=>$Type1_Pure{"Type"});
12870 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012871 elsif($Level eq "Binary"
12872 and $Prefix eq "Return" and $Type2_Pure{"Type"}=~/Intrinsic|Enum/
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012873 and $Type1_Pure{"Type"}=~/Struct|Class|Union/)
12874 { # returns in a register instead of a hidden first parameter
12875 %{$LocalProblems{"Return_Type_From_Stack_To_Register"}}=(
12876 "Old_Value"=>$Type1{"Name"},
12877 "New_Value"=>$Type2{"Name"},
12878 "Old_Size"=>$Type1{"Size"}*$BYTE_SIZE,
12879 "New_Size"=>$Type2{"Size"}*$BYTE_SIZE,
12880 "InitialType_Type"=>$Type1_Pure{"Type"});
12881 }
12882 else
12883 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012884 if($Level eq "Binary"
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040012885 and $Type1{"Size"} and $Type2{"Size"}
12886 and $Type1{"Size"} ne $Type2{"Size"})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012887 {
12888 %{$LocalProblems{$Prefix."_Type_And_Size"}}=(
12889 "Old_Value"=>$Type1{"Name"},
12890 "New_Value"=>$Type2{"Name"},
12891 "Old_Size"=>$Type1{"Size"}*$BYTE_SIZE,
12892 "New_Size"=>$Type2{"Size"}*$BYTE_SIZE,
12893 "InitialType_Type"=>$Type1_Pure{"Type"});
12894 }
12895 else
12896 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012897 if(checkFormatChange($Type1_Id, $Type2_Id, $Level))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012898 { # format change
12899 %{$LocalProblems{$Prefix."_Type_Format"}}=(
12900 "Old_Value"=>$Type1{"Name"},
12901 "New_Value"=>$Type2{"Name"},
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012902 "InitialType_Type"=>$Type1_Pure{"Type"});
12903 }
12904 elsif(tNameLock($Type1_Id, $Type2_Id))
12905 { # FIXME: correct this condition
12906 %{$LocalProblems{$Prefix."_Type"}}=(
12907 "Old_Value"=>$Type1{"Name"},
12908 "New_Value"=>$Type2{"Name"},
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012909 "InitialType_Type"=>$Type1_Pure{"Type"});
12910 }
12911 }
12912 }
12913 }
12914 }
12915 if($Type1_PLevel!=$Type2_PLevel)
12916 {
12917 if($Type1{"Name"} ne "void" and $Type1{"Name"} ne "..."
12918 and $Type2{"Name"} ne "void" and $Type2{"Name"} ne "...")
12919 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012920 if($Level eq "Source")
12921 {
12922 %{$LocalProblems{$Prefix."_PointerLevel"}}=(
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012923 "Old_Value"=>$Type1_PLevel,
12924 "New_Value"=>$Type2_PLevel);
12925 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012926 else
12927 {
12928 if($Type2_PLevel>$Type1_PLevel) {
12929 %{$LocalProblems{$Prefix."_PointerLevel_Increased"}}=(
12930 "Old_Value"=>$Type1_PLevel,
12931 "New_Value"=>$Type2_PLevel);
12932 }
12933 else {
12934 %{$LocalProblems{$Prefix."_PointerLevel_Decreased"}}=(
12935 "Old_Value"=>$Type1_PLevel,
12936 "New_Value"=>$Type2_PLevel);
12937 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012938 }
12939 }
12940 }
12941 if($Type1_Pure{"Type"} eq "Array")
12942 { # base_type[N] -> base_type[N]
12943 # base_type: older_structure -> typedef to newer_structure
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012944 my %SubProblems = detectTypeChange($Type1_Base{"Tid"}, $Type2_Base{"Tid"}, $Prefix, $Level);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012945 foreach my $SubProblemType (keys(%SubProblems))
12946 {
12947 $SubProblemType=~s/_Type/_BaseType/g;
12948 next if(defined $LocalProblems{$SubProblemType});
12949 foreach my $Attr (keys(%{$SubProblems{$SubProblemType}})) {
12950 $LocalProblems{$SubProblemType}{$Attr} = $SubProblems{$SubProblemType}{$Attr};
12951 }
12952 }
12953 }
12954 return %LocalProblems;
12955}
12956
12957sub tNameLock($$)
12958{
12959 my ($Tid1, $Tid2) = @_;
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040012960 my $Changed = 0;
12961 if(differentDumps("G"))
12962 { # different GCC versions
12963 $Changed = 1;
12964 }
12965 elsif(differentDumps("V"))
12966 { # different versions of ABI dumps
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 { # latest names update
12970 # 2.6: added restrict qualifier
12971 # 2.13: added missed typedefs to qualified types
12972 $Changed = 1;
12973 }
12974 }
12975 if($Changed)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012976 { # different formats
12977 if($UseOldDumps)
12978 { # old dumps
12979 return 0;
12980 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040012981 my $TN1 = $TypeInfo{1}{$Tid1}{"Name"};
12982 my $TN2 = $TypeInfo{2}{$Tid2}{"Name"};
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040012983
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040012984 my $TT1 = $TypeInfo{1}{$Tid1}{"Type"};
12985 my $TT2 = $TypeInfo{2}{$Tid2}{"Type"};
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040012986
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040012987 my %Base1 = get_Type($Tid1, 1);
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040012988 while(defined $Base1{"Type"} and $Base1{"Type"} eq "Typedef") {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040012989 %Base1 = get_OneStep_BaseType($Base1{"Tid"}, 1);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012990 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040012991 my %Base2 = get_Type($Tid2, 2);
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040012992 while(defined $Base2{"Type"} and $Base2{"Type"} eq "Typedef") {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040012993 %Base2 = get_OneStep_BaseType($Base2{"Tid"}, 2);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012994 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +040012995 my $BName1 = uncover_typedefs($Base1{"Name"}, 1);
12996 my $BName2 = uncover_typedefs($Base2{"Name"}, 2);
12997 if($BName1 eq $BName2)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012998 { # equal base types
12999 return 0;
13000 }
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040013001
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040013002 if(not checkDump(1, "2.13")
13003 or not checkDump(2, "2.13"))
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040013004 { # broken array names in ABI dumps < 2.13
13005 if($TT1 eq "Array"
13006 and $TT2 eq "Array")
13007 {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013008 return 0;
13009 }
13010 }
13011
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040013012 if(not checkDump(1, "2.6")
13013 or not checkDump(2, "2.6"))
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040013014 { # added restrict attribute in 2.6
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040013015 if($TN1!~/\brestrict\b/
13016 and $TN2=~/\brestrict\b/)
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040013017 {
13018 return 0;
13019 }
13020 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013021 }
13022 return 1;
13023}
13024
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040013025sub differentDumps($)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013026{
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040013027 my $Check = $_[0];
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +040013028 if(defined $Cache{"differentDumps"}{$Check}) {
13029 return $Cache{"differentDumps"}{$Check};
13030 }
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040013031 if($UsedDump{1}{"V"} and $UsedDump{2}{"V"})
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040013032 {
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040013033 if($Check eq "G")
13034 {
13035 if(getGccVersion(1) ne getGccVersion(2))
13036 { # different GCC versions
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +040013037 return ($Cache{"differentDumps"}{$Check}=1);
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040013038 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040013039 }
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040013040 if($Check eq "V")
13041 {
13042 if(cmpVersions(formatVersion($UsedDump{1}{"V"}, 2),
13043 formatVersion($UsedDump{2}{"V"}, 2))!=0)
13044 { # different dump versions (skip micro version)
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +040013045 return ($Cache{"differentDumps"}{$Check}=1);
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040013046 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040013047 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013048 }
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +040013049 return ($Cache{"differentDumps"}{$Check}=0);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013050}
13051
13052sub formatVersion($$)
13053{ # cut off version digits
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040013054 my ($V, $Digits) = @_;
13055 my @Elems = split(/\./, $V);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013056 return join(".", splice(@Elems, 0, $Digits));
13057}
13058
13059sub htmlSpecChars($)
13060{
13061 my $Str = $_[0];
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040013062 if($Str eq "") {
13063 return "";
13064 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013065 $Str=~s/\&([^#]|\Z)/&amp;$1/g;
13066 $Str=~s/</&lt;/g;
13067 $Str=~s/\-\>/&#45;&gt;/g; # &minus;
13068 $Str=~s/>/&gt;/g;
13069 $Str=~s/([^ ])( )([^ ])/$1\@ALONE_SP\@$3/g;
13070 $Str=~s/ /&#160;/g; # &nbsp;
13071 $Str=~s/\@ALONE_SP\@/ /g;
13072 $Str=~s/\n/<br\/>/g;
13073 $Str=~s/\"/&quot;/g;
13074 $Str=~s/\'/&#39;/g;
13075 return $Str;
13076}
13077
13078sub black_name($)
13079{
13080 my $Name = $_[0];
13081 return "<span class='iname_b'>".highLight_Signature($Name)."</span>";
13082}
13083
13084sub highLight_Signature($)
13085{
13086 my $Signature = $_[0];
13087 return highLight_Signature_PPos_Italic($Signature, "", 0, 0, 0);
13088}
13089
13090sub highLight_Signature_Italic_Color($)
13091{
13092 my $Signature = $_[0];
13093 return highLight_Signature_PPos_Italic($Signature, "", 1, 1, 1);
13094}
13095
13096sub separate_symbol($)
13097{
13098 my $Symbol = $_[0];
13099 my ($Name, $Spec, $Ver) = ($Symbol, "", "");
13100 if($Symbol=~/\A([^\@\$\?]+)([\@\$]+)([^\@\$]+)\Z/) {
13101 ($Name, $Spec, $Ver) = ($1, $2, $3);
13102 }
13103 return ($Name, $Spec, $Ver);
13104}
13105
13106sub cut_f_attrs($)
13107{
13108 if($_[0]=~s/(\))((| (const volatile|const|volatile))(| \[static\]))\Z/$1/) {
13109 return $2;
13110 }
13111 return "";
13112}
13113
13114sub highLight_Signature_PPos_Italic($$$$$)
13115{
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040013116 my ($FullSignature, $Param_Pos, $ItalicParams, $ColorParams, $ShowReturn) = @_;
13117 $Param_Pos = "" if(not defined $Param_Pos);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013118 if($CheckObjectsOnly) {
13119 $ItalicParams=$ColorParams=0;
13120 }
13121 my ($Signature, $VersionSpec, $SymbolVersion) = separate_symbol($FullSignature);
13122 my $Return = "";
13123 if($ShowRetVal and $Signature=~s/([^:]):([^:].+?)\Z/$1/g) {
13124 $Return = $2;
13125 }
Andrey Ponomarenko16934472012-03-29 15:37:04 +040013126 my $SCenter = find_center($Signature, "(");
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013127 if(not $SCenter)
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040013128 { # global data
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013129 $Signature = htmlSpecChars($Signature);
13130 $Signature=~s!(\[data\])!<span style='color:Black;font-weight:normal;'>$1</span>!g;
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040013131 $Signature .= (($SymbolVersion)?"<span class='sym_ver'>&#160;$VersionSpec&#160;$SymbolVersion</span>":"");
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013132 if($Return and $ShowReturn) {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040013133 $Signature .= "<span class='sym_p nowrap'> &#160;<b>:</b>&#160;&#160;".htmlSpecChars($Return)."</span>";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013134 }
13135 return $Signature;
13136 }
13137 my ($Begin, $End) = (substr($Signature, 0, $SCenter), "");
13138 $Begin.=" " if($Begin!~/ \Z/);
13139 $End = cut_f_attrs($Signature);
13140 my @Parts = ();
13141 my @SParts = get_s_params($Signature, 1);
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040013142 foreach my $Pos (0 .. $#SParts)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013143 {
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040013144 my $Part = $SParts[$Pos];
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013145 $Part=~s/\A\s+|\s+\Z//g;
13146 my ($Part_Styled, $ParamName) = (htmlSpecChars($Part), "");
13147 if($Part=~/\([\*]+(\w+)\)/i) {
13148 $ParamName = $1;#func-ptr
13149 }
13150 elsif($Part=~/(\w+)[\,\)]*\Z/i) {
13151 $ParamName = $1;
13152 }
13153 if(not $ParamName) {
13154 push(@Parts, $Part_Styled);
13155 next;
13156 }
13157 if($ItalicParams and not $TName_Tid{1}{$Part}
13158 and not $TName_Tid{2}{$Part})
13159 {
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040013160 my $Style = "param";
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040013161 if($Param_Pos ne ""
13162 and $Pos==$Param_Pos) {
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040013163 $Style = "focus_p";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013164 }
13165 elsif($ColorParams) {
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040013166 $Style = "color_p";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013167 }
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040013168 $Part_Styled =~ s!(\W)$ParamName([\,\)]|\Z)!$1<span class=\'$Style\'>$ParamName</span>$2!ig;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013169 }
13170 $Part_Styled=~s/,(\w)/, $1/g;
13171 push(@Parts, $Part_Styled);
13172 }
13173 if(@Parts)
13174 {
13175 foreach my $Num (0 .. $#Parts)
13176 {
13177 if($Num==$#Parts)
13178 { # add ")" to the last parameter
13179 $Parts[$Num] = "<span class='nowrap'>".$Parts[$Num]." )</span>";
13180 }
13181 elsif(length($Parts[$Num])<=45) {
13182 $Parts[$Num] = "<span class='nowrap'>".$Parts[$Num]."</span>";
13183 }
13184 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040013185 $Signature = htmlSpecChars($Begin)."<span class='sym_p'>(&#160;".join(" ", @Parts)."</span>".$End;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013186 }
13187 else {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040013188 $Signature = htmlSpecChars($Begin)."<span class='sym_p'>(&#160;)</span>".$End;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013189 }
13190 if($Return and $ShowReturn) {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040013191 $Signature .= "<span class='sym_p nowrap'> &#160;<b>:</b>&#160;&#160;".htmlSpecChars($Return)."</span>";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013192 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040013193 $Signature=~s!\[\]![&#160;]!g;
13194 $Signature=~s!operator=!operator&#160;=!g;
13195 $Signature=~s!(\[in-charge\]|\[not-in-charge\]|\[in-charge-deleting\]|\[static\])!<span class='sym_kind'>$1</span>!g;
13196 return $Signature.(($SymbolVersion)?"<span class='sym_ver'>&#160;$VersionSpec&#160;$SymbolVersion</span>":"");
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013197}
13198
13199sub get_s_params($$)
13200{
13201 my ($Signature, $Comma) = @_;
13202 my @Parts = ();
Andrey Ponomarenko16934472012-03-29 15:37:04 +040013203 my $ShortName = substr($Signature, 0, find_center($Signature, "("));
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013204 $Signature=~s/\A\Q$ShortName\E\(//g;
13205 cut_f_attrs($Signature);
13206 $Signature=~s/\)\Z//;
13207 return separate_params($Signature, $Comma);
13208}
13209
13210sub separate_params($$)
13211{
13212 my ($Params, $Comma) = @_;
13213 my @Parts = ();
Andrey Ponomarenko16934472012-03-29 15:37:04 +040013214 my %B = ( "("=>0, "<"=>0, ")"=>0, ">"=>0 );
13215 my $Part = 0;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013216 foreach my $Pos (0 .. length($Params) - 1)
13217 {
Andrey Ponomarenko16934472012-03-29 15:37:04 +040013218 my $S = substr($Params, $Pos, 1);
13219 if(defined $B{$S}) {
13220 $B{$S}+=1;
13221 }
13222 if($S eq "," and
13223 $B{"("}==$B{")"} and $B{"<"}==$B{">"})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013224 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040013225 if($Comma)
13226 { # include comma
Andrey Ponomarenko16934472012-03-29 15:37:04 +040013227 $Parts[$Part] .= $S;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013228 }
Andrey Ponomarenko16934472012-03-29 15:37:04 +040013229 $Part += 1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013230 }
13231 else {
Andrey Ponomarenko16934472012-03-29 15:37:04 +040013232 $Parts[$Part] .= $S;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013233 }
13234 }
13235 return @Parts;
13236}
13237
Andrey Ponomarenko16934472012-03-29 15:37:04 +040013238sub find_center($$)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013239{
13240 my ($Sign, $Target) = @_;
Andrey Ponomarenko16934472012-03-29 15:37:04 +040013241 my %B = ( "("=>0, "<"=>0, ")"=>0, ">"=>0 );
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013242 my $Center = 0;
Andrey Ponomarenko16934472012-03-29 15:37:04 +040013243 if($Sign=~s/(operator([^\w\s\(\)]+|\(\)))//g)
13244 { # operators
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013245 $Center+=length($1);
13246 }
13247 foreach my $Pos (0 .. length($Sign)-1)
13248 {
13249 my $S = substr($Sign, $Pos, 1);
13250 if($S eq $Target)
13251 {
13252 if($B{"("}==$B{")"}
13253 and $B{"<"}==$B{">"}) {
13254 return $Center;
13255 }
13256 }
13257 if(defined $B{$S}) {
13258 $B{$S}+=1;
13259 }
13260 $Center+=1;
13261 }
13262 return 0;
13263}
13264
13265sub appendFile($$)
13266{
13267 my ($Path, $Content) = @_;
13268 return if(not $Path);
13269 if(my $Dir = get_dirname($Path)) {
13270 mkpath($Dir);
13271 }
Andrey Ponomarenko16934472012-03-29 15:37:04 +040013272 open(FILE, ">>", $Path) || die ("can't open file \'$Path\': $!\n");
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013273 print FILE $Content;
13274 close(FILE);
13275}
13276
13277sub writeFile($$)
13278{
13279 my ($Path, $Content) = @_;
13280 return if(not $Path);
13281 if(my $Dir = get_dirname($Path)) {
13282 mkpath($Dir);
13283 }
Andrey Ponomarenko16934472012-03-29 15:37:04 +040013284 open(FILE, ">", $Path) || die ("can't open file \'$Path\': $!\n");
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013285 print FILE $Content;
13286 close(FILE);
13287}
13288
13289sub readFile($)
13290{
13291 my $Path = $_[0];
13292 return "" if(not $Path or not -f $Path);
Andrey Ponomarenko16934472012-03-29 15:37:04 +040013293 open(FILE, $Path);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013294 local $/ = undef;
13295 my $Content = <FILE>;
13296 close(FILE);
Andrey Ponomarenko85043792012-05-14 16:48:07 +040013297 if($Path!~/\.(tu|class|abi)\Z/) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013298 $Content=~s/\r/\n/g;
13299 }
13300 return $Content;
13301}
13302
13303sub get_filename($)
13304{ # much faster than basename() from File::Basename module
Andrey Ponomarenko85043792012-05-14 16:48:07 +040013305 if(defined $Cache{"get_filename"}{$_[0]}) {
13306 return $Cache{"get_filename"}{$_[0]};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013307 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +040013308 if($_[0] and $_[0]=~/([^\/\\]+)[\/\\]*\Z/) {
13309 return ($Cache{"get_filename"}{$_[0]}=$1);
13310 }
13311 return ($Cache{"get_filename"}{$_[0]}="");
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013312}
13313
13314sub get_dirname($)
13315{ # much faster than dirname() from File::Basename module
Andrey Ponomarenko85043792012-05-14 16:48:07 +040013316 if(defined $Cache{"get_dirname"}{$_[0]}) {
13317 return $Cache{"get_dirname"}{$_[0]};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013318 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +040013319 if($_[0] and $_[0]=~/\A(.*?)[\/\\]+[^\/\\]*[\/\\]*\Z/) {
13320 return ($Cache{"get_dirname"}{$_[0]}=$1);
13321 }
13322 return ($Cache{"get_dirname"}{$_[0]}="");
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013323}
13324
13325sub separate_path($) {
13326 return (get_dirname($_[0]), get_filename($_[0]));
13327}
13328
13329sub esc($)
13330{
13331 my $Str = $_[0];
13332 $Str=~s/([()\[\]{}$ &'"`;,<>\+])/\\$1/g;
13333 return $Str;
13334}
13335
13336sub readLineNum($$)
13337{
13338 my ($Path, $Num) = @_;
13339 return "" if(not $Path or not -f $Path);
Andrey Ponomarenko16934472012-03-29 15:37:04 +040013340 open(FILE, $Path);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013341 foreach (1 ... $Num) {
13342 <FILE>;
13343 }
13344 my $Line = <FILE>;
13345 close(FILE);
13346 return $Line;
13347}
13348
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040013349sub readAttributes($$)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013350{
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040013351 my ($Path, $Num) = @_;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013352 return () if(not $Path or not -f $Path);
13353 my %Attributes = ();
Andrey Ponomarenko85043792012-05-14 16:48:07 +040013354 if(readLineNum($Path, $Num)=~/<!--\s+(.+)\s+-->/)
13355 {
13356 foreach my $AttrVal (split(/;/, $1))
13357 {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013358 if($AttrVal=~/(.+):(.+)/)
13359 {
13360 my ($Name, $Value) = ($1, $2);
13361 $Attributes{$Name} = $Value;
13362 }
13363 }
13364 }
13365 return \%Attributes;
13366}
13367
13368sub is_abs($) {
13369 return ($_[0]=~/\A(\/|\w+:[\/\\])/);
13370}
13371
13372sub get_abs_path($)
13373{ # abs_path() should NOT be called for absolute inputs
13374 # because it can change them
13375 my $Path = $_[0];
13376 if(not is_abs($Path)) {
13377 $Path = abs_path($Path);
13378 }
13379 return $Path;
13380}
13381
13382sub get_OSgroup()
13383{
13384 $_ = $Config{"osname"};
13385 if(/macos|darwin|rhapsody/i) {
13386 return "macos";
13387 }
13388 elsif(/freebsd|openbsd|netbsd/i) {
13389 return "bsd";
13390 }
13391 elsif(/haiku|beos/i) {
13392 return "beos";
13393 }
13394 elsif(/symbian|epoc/i) {
13395 return "symbian";
13396 }
13397 elsif(/win/i) {
13398 return "windows";
13399 }
13400 else {
13401 return $_;
13402 }
13403}
13404
13405sub getGccVersion($)
13406{
13407 my $LibVersion = $_[0];
13408 if($GCC_VERSION{$LibVersion})
13409 { # dump version
13410 return $GCC_VERSION{$LibVersion};
13411 }
13412 elsif($UsedDump{$LibVersion}{"V"})
13413 { # old-version dumps
13414 return "unknown";
13415 }
13416 my $GccVersion = get_dumpversion($GCC_PATH); # host version
13417 if(not $GccVersion) {
13418 return "unknown";
13419 }
13420 return $GccVersion;
13421}
13422
13423sub showArch($)
13424{
13425 my $Arch = $_[0];
13426 if($Arch eq "arm"
13427 or $Arch eq "mips") {
13428 return uc($Arch);
13429 }
13430 return $Arch;
13431}
13432
13433sub getArch($)
13434{
13435 my $LibVersion = $_[0];
13436 if($CPU_ARCH{$LibVersion})
13437 { # dump version
13438 return $CPU_ARCH{$LibVersion};
13439 }
13440 elsif($UsedDump{$LibVersion}{"V"})
13441 { # old-version dumps
13442 return "unknown";
13443 }
13444 if(defined $Cache{"getArch"}{$LibVersion}) {
13445 return $Cache{"getArch"}{$LibVersion};
13446 }
13447 my $Arch = get_dumpmachine($GCC_PATH); # host version
13448 if(not $Arch) {
13449 return "unknown";
13450 }
13451 if($Arch=~/\A([\w]{3,})(-|\Z)/) {
13452 $Arch = $1;
13453 }
13454 $Arch = "x86" if($Arch=~/\Ai[3-7]86\Z/);
13455 if($OSgroup eq "windows") {
13456 $Arch = "x86" if($Arch=~/win32|mingw32/i);
13457 $Arch = "x86_64" if($Arch=~/win64|mingw64/i);
13458 }
13459 $Cache{"getArch"}{$LibVersion} = $Arch;
13460 return $Arch;
13461}
13462
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040013463sub get_Report_Header($)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013464{
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040013465 my $Level = $_[0];
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013466 my $ArchInfo = " on <span style='color:Blue;'>".showArch(getArch(1))."</span>";
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040013467 if(getArch(1) ne getArch(2)
13468 or getArch(1) eq "unknown"
13469 or $Level eq "Source")
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013470 { # don't show architecture in the header
13471 $ArchInfo="";
13472 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040013473 my $Report_Header = "<h1><span class='nowrap'>";
13474 if($Level eq "Source") {
13475 $Report_Header .= "Source compatibility";
13476 }
13477 elsif($Level eq "Binary") {
13478 $Report_Header .= "Binary compatibility";
13479 }
13480 else {
13481 $Report_Header .= "API compatibility";
13482 }
13483 $Report_Header .= " report for the <span style='color:Blue;'>$TargetLibraryFName</span> $TargetComponent</span>";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013484 $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>";
13485 if($AppPath) {
13486 $Report_Header .= " <span class='nowrap'>&#160;(relating to the portability of application <span style='color:Blue;'>".get_filename($AppPath)."</span>)</span>";
13487 }
13488 $Report_Header .= "</h1>\n";
13489 return $Report_Header;
13490}
13491
13492sub get_SourceInfo()
13493{
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040013494 my ($CheckedHeaders, $CheckedLibs) = ("", "");
13495 if(not $CheckObjectsOnly)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013496 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040013497 $CheckedHeaders = "<a name='Headers'></a><h2>Header Files (".keys(%{$Registered_Headers{1}}).")</h2><hr/>\n";
13498 $CheckedHeaders .= "<div class='h_list'>\n";
13499 foreach my $Header_Path (sort {lc($Registered_Headers{1}{$a}{"Identity"}) cmp lc($Registered_Headers{1}{$b}{"Identity"})} keys(%{$Registered_Headers{1}}))
13500 {
13501 my $Identity = $Registered_Headers{1}{$Header_Path}{"Identity"};
13502 my $Header_Name = get_filename($Identity);
13503 my $Dest_Comment = ($Identity=~/[\/\\]/)?" ($Identity)":"";
13504 $CheckedHeaders .= $Header_Name.$Dest_Comment."<br/>\n";
13505 }
13506 $CheckedHeaders .= "</div>\n";
13507 $CheckedHeaders .= "<br/>$TOP_REF<br/>\n";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013508 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040013509 if(not $CheckHeadersOnly)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013510 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040013511 $CheckedLibs = "<a name='Libs'></a><h2>".ucfirst($SLIB_TYPE)." Libraries (".keys(%{$Library_Symbol{1}}).")</h2><hr/>\n";
13512 $CheckedLibs .= "<div class='lib_list'>\n";
13513 foreach my $Library (sort {lc($a) cmp lc($b)} keys(%{$Library_Symbol{1}}))
13514 {
13515 $Library.=" (.$LIB_EXT)" if($Library!~/\.\w+\Z/);
13516 $CheckedLibs .= $Library."<br/>\n";
13517 }
13518 $CheckedLibs .= "</div>\n";
13519 $CheckedLibs .= "<br/>$TOP_REF<br/>\n";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013520 }
13521 return $CheckedHeaders.$CheckedLibs;
13522}
13523
13524sub get_TypeProblems_Count($$$)
13525{
13526 my ($TypeChanges, $TargetPriority, $Level) = @_;
13527 my $Type_Problems_Count = 0;
13528 foreach my $Type_Name (sort keys(%{$TypeChanges}))
13529 {
13530 my %Kinds_Target = ();
13531 foreach my $Kind (keys(%{$TypeChanges->{$Type_Name}}))
13532 {
13533 foreach my $Location (keys(%{$TypeChanges->{$Type_Name}{$Kind}}))
13534 {
13535 my $Target = $TypeChanges->{$Type_Name}{$Kind}{$Location}{"Target"};
13536 my $Priority = getProblemSeverity($Level, $Kind);
13537 next if($Priority ne $TargetPriority);
13538 if($Kinds_Target{$Kind}{$Target}) {
13539 next;
13540 }
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040013541 if(cmpSeverities($Type_MaxSeverity{$Level}{$Type_Name}{$Kind}{$Target}, $Priority))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013542 { # select a problem with the highest priority
13543 next;
13544 }
13545 $Kinds_Target{$Kind}{$Target} = 1;
13546 $Type_Problems_Count += 1;
13547 }
13548 }
13549 }
13550 return $Type_Problems_Count;
13551}
13552
13553sub get_Summary($)
13554{
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040013555 my $Level = $_[0];
13556 my ($Added, $Removed, $I_Problems_High, $I_Problems_Medium, $I_Problems_Low, $T_Problems_High,
13557 $C_Problems_Low, $T_Problems_Medium, $T_Problems_Low, $I_Other, $T_Other) = (0,0,0,0,0,0,0,0,0,0,0);
13558 %{$RESULT{$Level}} = (
13559 "Problems"=>0,
13560 "Warnings"=>0,
13561 "Affected"=>0 );
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013562 # check rules
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040013563 foreach my $Interface (sort keys(%{$CompatProblems{$Level}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013564 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040013565 foreach my $Kind (keys(%{$CompatProblems{$Level}{$Interface}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013566 {
13567 if(not defined $CompatRules{$Level}{$Kind})
13568 { # unknown rule
13569 if(not $UnknownRules{$Level}{$Kind})
13570 { # only one warning
13571 printMsg("WARNING", "unknown rule \"$Kind\" (\"$Level\")");
13572 $UnknownRules{$Level}{$Kind}=1;
13573 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040013574 delete($CompatProblems{$Level}{$Interface}{$Kind});
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013575 }
13576 }
13577 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040013578 foreach my $Interface (sort keys(%{$CompatProblems{$Level}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013579 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040013580 foreach my $Kind (sort keys(%{$CompatProblems{$Level}{$Interface}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013581 {
13582 if($CompatRules{$Level}{$Kind}{"Kind"} eq "Symbols")
13583 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040013584 foreach my $Location (sort keys(%{$CompatProblems{$Level}{$Interface}{$Kind}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013585 {
13586 my $Priority = getProblemSeverity($Level, $Kind);
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040013587 if($Kind eq "Added_Symbol") {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013588 $Added += 1;
13589 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040013590 elsif($Kind eq "Removed_Symbol")
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013591 {
13592 $Removed += 1;
13593 $TotalAffected{$Level}{$Interface} = $Priority;
13594 }
13595 else
13596 {
13597 if($Priority eq "Safe") {
13598 $I_Other += 1;
13599 }
13600 elsif($Priority eq "High") {
13601 $I_Problems_High += 1;
13602 }
13603 elsif($Priority eq "Medium") {
13604 $I_Problems_Medium += 1;
13605 }
13606 elsif($Priority eq "Low") {
13607 $I_Problems_Low += 1;
13608 }
13609 if(($Priority ne "Low" or $StrictCompat)
13610 and $Priority ne "Safe") {
13611 $TotalAffected{$Level}{$Interface} = $Priority;
13612 }
13613 }
13614 }
13615 }
13616 }
13617 }
13618 my %TypeChanges = ();
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040013619 foreach my $Interface (sort keys(%{$CompatProblems{$Level}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013620 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040013621 foreach my $Kind (keys(%{$CompatProblems{$Level}{$Interface}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013622 {
13623 if($CompatRules{$Level}{$Kind}{"Kind"} eq "Types")
13624 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040013625 foreach my $Location (sort {cmp_locations($b, $a)} sort keys(%{$CompatProblems{$Level}{$Interface}{$Kind}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013626 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040013627 my $Type_Name = $CompatProblems{$Level}{$Interface}{$Kind}{$Location}{"Type_Name"};
13628 my $Target = $CompatProblems{$Level}{$Interface}{$Kind}{$Location}{"Target"};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013629 my $Priority = getProblemSeverity($Level, $Kind);
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040013630 if(cmpSeverities($Type_MaxSeverity{$Level}{$Type_Name}{$Kind}{$Target}, $Priority))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013631 { # select a problem with the highest priority
13632 next;
13633 }
13634 if(($Priority ne "Low" or $StrictCompat)
13635 and $Priority ne "Safe") {
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040013636 $TotalAffected{$Level}{$Interface} = maxSeverity($TotalAffected{$Level}{$Interface}, $Priority);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013637 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040013638 %{$TypeChanges{$Type_Name}{$Kind}{$Location}} = %{$CompatProblems{$Level}{$Interface}{$Kind}{$Location}};
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040013639 $Type_MaxSeverity{$Level}{$Type_Name}{$Kind}{$Target} = maxSeverity($Type_MaxSeverity{$Level}{$Type_Name}{$Kind}{$Target}, $Priority);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013640 }
13641 }
13642 }
13643 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040013644
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013645 $T_Problems_High = get_TypeProblems_Count(\%TypeChanges, "High", $Level);
13646 $T_Problems_Medium = get_TypeProblems_Count(\%TypeChanges, "Medium", $Level);
13647 $T_Problems_Low = get_TypeProblems_Count(\%TypeChanges, "Low", $Level);
13648 $T_Other = get_TypeProblems_Count(\%TypeChanges, "Safe", $Level);
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040013649
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013650 if($CheckObjectsOnly)
13651 { # only removed exported symbols
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040013652 $RESULT{$Level}{"Affected"} = $Removed*100/keys(%{$Symbol_Library{1}});
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013653 }
13654 else
13655 { # changed and removed public symbols
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040013656 my $SCount = keys(%{$CheckedSymbols{$Level}});
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013657 if($ExtendedCheck)
13658 { # don't count external_func_0 for constants
13659 $SCount-=1;
13660 }
13661 if($SCount)
13662 {
13663 my %Weight = (
13664 "High" => 100,
13665 "Medium" => 50,
13666 "Low" => 25
13667 );
13668 foreach (keys(%{$TotalAffected{$Level}})) {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040013669 $RESULT{$Level}{"Affected"}+=$Weight{$TotalAffected{$Level}{$_}};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013670 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040013671 $RESULT{$Level}{"Affected"} = $RESULT{$Level}{"Affected"}/$SCount;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013672 }
13673 else {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040013674 $RESULT{$Level}{"Affected"} = 0;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013675 }
13676 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040013677 $RESULT{$Level}{"Affected"} = show_number($RESULT{$Level}{"Affected"});
13678 if($RESULT{$Level}{"Affected"}>=100) {
13679 $RESULT{$Level}{"Affected"} = 100;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013680 }
13681
Andrey Ponomarenko85043792012-05-14 16:48:07 +040013682 $RESULT{$Level}{"Problems"} += $Removed;
13683 $RESULT{$Level}{"Problems"} += $T_Problems_High + $I_Problems_High;
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040013684 $RESULT{$Level}{"Problems"} += $T_Problems_Medium + $I_Problems_Medium;
Andrey Ponomarenko85043792012-05-14 16:48:07 +040013685 if($StrictCompat) {
13686 $RESULT{$Level}{"Problems"} += $T_Problems_Low + $I_Problems_Low;
13687 }
13688 else {
13689 $RESULT{$Level}{"Warnings"} += $T_Problems_Low + $I_Problems_Low;
13690 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013691
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040013692 if($C_Problems_Low = keys(%{$ProblemsWithConstants{$Level}}))
13693 {
Andrey Ponomarenko85043792012-05-14 16:48:07 +040013694 if(defined $CompatRules{$Level}{"Changed_Constant"})
13695 {
13696 if($StrictCompat) {
13697 $RESULT{$Level}{"Problems"} += $C_Problems_Low;
13698 }
13699 else {
13700 $RESULT{$Level}{"Warnings"} += $C_Problems_Low;
13701 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040013702 }
13703 else
13704 {
13705 printMsg("WARNING", "unknown rule \"Changed_Constant\" (\"$Level\")");
13706 $C_Problems_Low = 0;
13707 }
13708 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +040013709 if($CheckImpl and $Level eq "Binary")
13710 {
13711 if($StrictCompat) {
13712 $RESULT{$Level}{"Problems"} += keys(%ImplProblems);
13713 }
13714 else {
13715 $RESULT{$Level}{"Warnings"} += keys(%ImplProblems);
13716 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040013717 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +040013718 if($RESULT{$Level}{"Problems"}
13719 and $RESULT{$Level}{"Affected"}) {
13720 $RESULT{$Level}{"Verdict"} = "incompatible";
13721 }
13722 else {
13723 $RESULT{$Level}{"Verdict"} = "compatible";
13724 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040013725
13726 my $TotalTypes = keys(%{$CheckedTypes{$Level}});
13727 if(not $TotalTypes)
13728 { # list all the types
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013729 $TotalTypes = keys(%{$TName_Tid{1}});
13730 }
13731
13732 my ($Arch1, $Arch2) = (getArch(1), getArch(2));
13733 my ($GccV1, $GccV2) = (getGccVersion(1), getGccVersion(2));
13734
13735 my ($TestInfo, $TestResults, $Problem_Summary) = ();
13736
13737 if($ReportFormat eq "xml")
13738 { # XML
13739 # test info
13740 $TestInfo .= " <library>$TargetLibraryName</library>\n";
13741 $TestInfo .= " <version1>\n";
13742 $TestInfo .= " <number>".$Descriptor{1}{"Version"}."</number>\n";
13743 $TestInfo .= " <architecture>$Arch1</architecture>\n";
13744 $TestInfo .= " <gcc>$GccV1</gcc>\n";
13745 $TestInfo .= " </version1>\n";
13746
13747 $TestInfo .= " <version2>\n";
13748 $TestInfo .= " <number>".$Descriptor{2}{"Version"}."</number>\n";
13749 $TestInfo .= " <architecture>$Arch2</architecture>\n";
13750 $TestInfo .= " <gcc>$GccV2</gcc>\n";
13751 $TestInfo .= " </version2>\n";
13752 $TestInfo = "<test_info>\n".$TestInfo."</test_info>\n\n";
13753
13754 # test results
13755 $TestResults .= " <headers>\n";
13756 foreach my $Name (sort {lc($Registered_Headers{1}{$a}{"Identity"}) cmp lc($Registered_Headers{1}{$b}{"Identity"})} keys(%{$Registered_Headers{1}}))
13757 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040013758 my $Identity = $Registered_Headers{1}{$Name}{"Identity"};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013759 my $Comment = ($Identity=~/[\/\\]/)?" ($Identity)":"";
13760 $TestResults .= " <name>".get_filename($Name).$Comment."</name>\n";
13761 }
13762 $TestResults .= " </headers>\n";
13763
13764 $TestResults .= " <libs>\n";
13765 foreach my $Library (sort {lc($a) cmp lc($b)} keys(%{$Library_Symbol{1}}))
13766 {
13767 $Library.=" (.$LIB_EXT)" if($Library!~/\.\w+\Z/);
13768 $TestResults .= " <name>$Library</name>\n";
13769 }
13770 $TestResults .= " </libs>\n";
13771
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040013772 $TestResults .= " <symbols>".(keys(%{$CheckedSymbols{$Level}}) - keys(%ExtendedSymbols))."</symbols>\n";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013773 $TestResults .= " <types>".$TotalTypes."</types>\n";
13774
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040013775 $TestResults .= " <verdict>".$RESULT{$Level}{"Verdict"}."</verdict>\n";
13776 $TestResults .= " <affected>".$RESULT{$Level}{"Affected"}."</affected>\n";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013777 $TestResults = "<test_results>\n".$TestResults."</test_results>\n\n";
13778
13779 # problem summary
13780 $Problem_Summary .= " <added_symbols>".$Added."</added_symbols>\n";
13781 $Problem_Summary .= " <removed_symbols>".$Removed."</removed_symbols>\n";
13782
13783 $Problem_Summary .= " <problems_with_types>\n";
13784 $Problem_Summary .= " <high>$T_Problems_High</high>\n";
13785 $Problem_Summary .= " <medium>$T_Problems_Medium</medium>\n";
13786 $Problem_Summary .= " <low>$T_Problems_Low</low>\n";
13787 $Problem_Summary .= " <safe>$T_Other</safe>\n";
13788 $Problem_Summary .= " </problems_with_types>\n";
13789
13790 $Problem_Summary .= " <problems_with_symbols>\n";
13791 $Problem_Summary .= " <high>$I_Problems_High</high>\n";
13792 $Problem_Summary .= " <medium>$I_Problems_Medium</medium>\n";
13793 $Problem_Summary .= " <low>$I_Problems_Low</low>\n";
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040013794 $Problem_Summary .= " <safe>$I_Other</safe>\n";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013795 $Problem_Summary .= " </problems_with_symbols>\n";
13796
13797 $Problem_Summary .= " <problems_with_constants>\n";
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040013798 $Problem_Summary .= " <low>$C_Problems_Low</low>\n";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013799 $Problem_Summary .= " </problems_with_constants>\n";
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040013800 if($CheckImpl and $Level eq "Binary")
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013801 {
13802 $Problem_Summary .= " <impl>\n";
13803 $Problem_Summary .= " <low>".keys(%ImplProblems)."</low>\n";
13804 $Problem_Summary .= " </impl>\n";
13805 }
13806 $Problem_Summary = "<problem_summary>\n".$Problem_Summary."</problem_summary>\n\n";
13807
13808 return ($TestInfo.$TestResults.$Problem_Summary, "");
13809 }
13810 else
13811 { # HTML
13812 # test info
13813 $TestInfo = "<h2>Test Info</h2><hr/>\n";
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040013814 $TestInfo .= "<table class='summary'>\n";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013815 $TestInfo .= "<tr><th>".ucfirst($TargetComponent)." Name</th><td>$TargetLibraryFName</td></tr>\n";
13816
13817 my (@VInf1, @VInf2, $AddTestInfo) = ();
13818 if($Arch1 ne "unknown"
13819 and $Arch2 ne "unknown")
13820 { # CPU arch
13821 if($Arch1 eq $Arch2)
13822 { # go to the separate section
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040013823 $AddTestInfo .= "<tr><th>CPU Type</th><td>".showArch($Arch1)."</td></tr>\n";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013824 }
13825 else
13826 { # go to the version number
13827 push(@VInf1, showArch($Arch1));
13828 push(@VInf2, showArch($Arch2));
13829 }
13830 }
13831 if($GccV1 ne "unknown"
13832 and $GccV2 ne "unknown"
13833 and $OStarget ne "windows")
13834 { # GCC version
13835 if($GccV1 eq $GccV2)
13836 { # go to the separate section
13837 $AddTestInfo .= "<tr><th>GCC Version</th><td>$GccV1</td></tr>\n";
13838 }
13839 else
13840 { # go to the version number
13841 push(@VInf1, "gcc ".$GccV1);
13842 push(@VInf2, "gcc ".$GccV2);
13843 }
13844 }
13845 # show long version names with GCC version and CPU architecture name (if different)
13846 $TestInfo .= "<tr><th>Version #1</th><td>".$Descriptor{1}{"Version"}.(@VInf1?" (".join(", ", reverse(@VInf1)).")":"")."</td></tr>\n";
13847 $TestInfo .= "<tr><th>Version #2</th><td>".$Descriptor{2}{"Version"}.(@VInf2?" (".join(", ", reverse(@VInf2)).")":"")."</td></tr>\n";
13848 $TestInfo .= $AddTestInfo;
13849 #if($COMMON_LANGUAGE{1}) {
13850 # $TestInfo .= "<tr><th>Language</th><td>".$COMMON_LANGUAGE{1}."</td></tr>\n";
13851 #}
13852 if($ExtendedCheck) {
13853 $TestInfo .= "<tr><th>Mode</th><td>Extended</td></tr>\n";
13854 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040013855 if($JoinReport)
13856 {
13857 if($Level eq "Binary") {
Andrey Ponomarenko16934472012-03-29 15:37:04 +040013858 $TestInfo .= "<tr><th>Subject</th><td width='150px'>Binary Compatibility</td></tr>\n"; # Run-time
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040013859 }
13860 if($Level eq "Source") {
Andrey Ponomarenko16934472012-03-29 15:37:04 +040013861 $TestInfo .= "<tr><th>Subject</th><td width='150px'>Source Compatibility</td></tr>\n"; # Build-time
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040013862 }
13863 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013864 $TestInfo .= "</table>\n";
13865
13866 # test results
13867 $TestResults = "<h2>Test Results</h2><hr/>\n";
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040013868 $TestResults .= "<table class='summary'>";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013869
13870 my $Headers_Link = "0";
13871 $Headers_Link = "<a href='#Headers' style='color:Blue;'>".keys(%{$Registered_Headers{1}})."</a>" if(keys(%{$Registered_Headers{1}})>0);
13872 $TestResults .= "<tr><th>Total Header Files</th><td>".($CheckObjectsOnly?"0&#160;(not&#160;analyzed)":$Headers_Link)."</td></tr>\n";
13873
13874 if(not $ExtendedCheck)
13875 {
13876 my $Libs_Link = "0";
13877 $Libs_Link = "<a href='#Libs' style='color:Blue;'>".keys(%{$Library_Symbol{1}})."</a>" if(keys(%{$Library_Symbol{1}})>0);
13878 $TestResults .= "<tr><th>Total ".ucfirst($SLIB_TYPE)." Libraries</th><td>".($CheckHeadersOnly?"0&#160;(not&#160;analyzed)":$Libs_Link)."</td></tr>\n";
13879 }
13880
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040013881 $TestResults .= "<tr><th>Total Symbols / Types</th><td>".(keys(%{$CheckedSymbols{$Level}}) - keys(%ExtendedSymbols))." / ".$TotalTypes."</td></tr>\n";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013882
Andrey Ponomarenko85043792012-05-14 16:48:07 +040013883 my $META_DATA = "verdict:".$RESULT{$Level}{"Verdict"}.";";
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040013884 if($JoinReport) {
13885 $META_DATA = "kind:".lc($Level).";".$META_DATA;
13886 }
Andrey Ponomarenko16934472012-03-29 15:37:04 +040013887 $TestResults .= "<tr><th>Verdict</th>";
Andrey Ponomarenko85043792012-05-14 16:48:07 +040013888 if($RESULT{$Level}{"Verdict"} eq "incompatible") {
Andrey Ponomarenko16934472012-03-29 15:37:04 +040013889 $TestResults .= "<td><span style='color:Red;'><b>Incompatible<br/>(".$RESULT{$Level}{"Affected"}."%)</b></span></td>";
13890 }
13891 else {
13892 $TestResults .= "<td><span style='color:Green;'><b>Compatible</b></span></td>";
13893 }
13894 $TestResults .= "</tr>\n";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013895 $TestResults .= "</table>\n";
13896
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040013897 $META_DATA .= "affected:".$RESULT{$Level}{"Affected"}.";";# in percents
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013898 # problem summary
13899 $Problem_Summary = "<h2>Problem Summary</h2><hr/>\n";
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040013900 $Problem_Summary .= "<table class='summary'>";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013901 $Problem_Summary .= "<tr><th></th><th style='text-align:center;'>Severity</th><th style='text-align:center;'>Count</th></tr>";
13902
13903 my $Added_Link = "0";
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040013904 if($Added>0)
13905 {
13906 if($JoinReport) {
13907 $Added_Link = "<a href='#".$Level."_Added' style='color:Blue;'>$Added</a>";
13908 }
13909 else {
13910 $Added_Link = "<a href='#Added' style='color:Blue;'>$Added</a>";
13911 }
13912 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013913 $META_DATA .= "added:$Added;";
Andrey Ponomarenko16934472012-03-29 15:37:04 +040013914 $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 +040013915
13916 my $Removed_Link = "0";
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040013917 if($Removed>0)
13918 {
13919 if($JoinReport) {
13920 $Removed_Link = "<a href='#".$Level."_Removed' style='color:Blue;'>$Removed</a>"
13921 }
13922 else {
13923 $Removed_Link = "<a href='#Removed' style='color:Blue;'>$Removed</a>"
13924 }
13925 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013926 $META_DATA .= "removed:$Removed;";
Andrey Ponomarenko16934472012-03-29 15:37:04 +040013927 $Problem_Summary .= "<tr><th>Removed Symbols</th>";
13928 $Problem_Summary .= "<td>High</td><td".getStyle("I", "R", $Removed).">$Removed_Link</td></tr>\n";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013929
13930 my $TH_Link = "0";
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040013931 $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 +040013932 $TH_Link = "n/a" if($CheckObjectsOnly);
13933 $META_DATA .= "type_problems_high:$T_Problems_High;";
Andrey Ponomarenko16934472012-03-29 15:37:04 +040013934 $Problem_Summary .= "<tr><th rowspan='3'>Problems with<br/>Data Types</th>";
13935 $Problem_Summary .= "<td>High</td><td".getStyle("T", "H", $T_Problems_High).">$TH_Link</td></tr>\n";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013936
13937 my $TM_Link = "0";
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040013938 $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 +040013939 $TM_Link = "n/a" if($CheckObjectsOnly);
13940 $META_DATA .= "type_problems_medium:$T_Problems_Medium;";
Andrey Ponomarenko16934472012-03-29 15:37:04 +040013941 $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 +040013942
13943 my $TL_Link = "0";
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040013944 $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 +040013945 $TL_Link = "n/a" if($CheckObjectsOnly);
13946 $META_DATA .= "type_problems_low:$T_Problems_Low;";
Andrey Ponomarenko16934472012-03-29 15:37:04 +040013947 $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 +040013948
13949 my $IH_Link = "0";
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040013950 $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 +040013951 $IH_Link = "n/a" if($CheckObjectsOnly);
13952 $META_DATA .= "interface_problems_high:$I_Problems_High;";
Andrey Ponomarenko16934472012-03-29 15:37:04 +040013953 $Problem_Summary .= "<tr><th rowspan='3'>Problems with<br/>Symbols</th>";
13954 $Problem_Summary .= "<td>High</td><td".getStyle("I", "H", $I_Problems_High).">$IH_Link</td></tr>\n";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013955
13956 my $IM_Link = "0";
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040013957 $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 +040013958 $IM_Link = "n/a" if($CheckObjectsOnly);
13959 $META_DATA .= "interface_problems_medium:$I_Problems_Medium;";
Andrey Ponomarenko16934472012-03-29 15:37:04 +040013960 $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 +040013961
13962 my $IL_Link = "0";
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040013963 $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 +040013964 $IL_Link = "n/a" if($CheckObjectsOnly);
13965 $META_DATA .= "interface_problems_low:$I_Problems_Low;";
Andrey Ponomarenko16934472012-03-29 15:37:04 +040013966 $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 +040013967
13968 my $ChangedConstants_Link = "0";
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040013969 if(keys(%{$CheckedSymbols{$Level}}) and $C_Problems_Low)
13970 {
13971 if($JoinReport) {
13972 $ChangedConstants_Link = "<a href='#".$Level."_Changed_Constants' style='color:Blue;'>$C_Problems_Low</a>";
13973 }
13974 else {
13975 $ChangedConstants_Link = "<a href='#Changed_Constants' style='color:Blue;'>$C_Problems_Low</a>";
13976 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013977 }
13978 $ChangedConstants_Link = "n/a" if($CheckObjectsOnly);
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040013979 $META_DATA .= "changed_constants:$C_Problems_Low;";
Andrey Ponomarenko16934472012-03-29 15:37:04 +040013980 $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 +040013981
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040013982 if($CheckImpl and $Level eq "Binary")
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013983 {
13984 my $ChangedImpl_Link = "0";
13985 $ChangedImpl_Link = "<a href='#Changed_Implementation' style='color:Blue;'>".keys(%ImplProblems)."</a>" if(keys(%ImplProblems)>0);
13986 $ChangedImpl_Link = "n/a" if($CheckHeadersOnly);
13987 $META_DATA .= "changed_implementation:".keys(%ImplProblems).";";
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040013988 $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 +040013989 }
13990 # Safe Changes
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040013991 if($T_Other and not $CheckObjectsOnly)
13992 {
13993 my $TS_Link = "<a href='#".get_Anchor("Type", $Level, "Safe")."' style='color:Blue;'>$T_Other</a>";
Andrey Ponomarenko16934472012-03-29 15:37:04 +040013994 $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 +040013995 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040013996
13997 if($I_Other and not $CheckObjectsOnly)
13998 {
13999 my $IS_Link = "<a href='#".get_Anchor("Symbol", $Level, "Safe")."' style='color:Blue;'>$I_Other</a>";
Andrey Ponomarenko16934472012-03-29 15:37:04 +040014000 $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 +040014001 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014002
14003 $META_DATA .= "tool_version:$TOOL_VERSION";
14004 $Problem_Summary .= "</table>\n";
Andrey Ponomarenko16934472012-03-29 15:37:04 +040014005 # $TestInfo = getLegend().$TestInfo;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014006 return ($TestInfo.$TestResults.$Problem_Summary, $META_DATA);
14007 }
14008}
14009
Andrey Ponomarenko16934472012-03-29 15:37:04 +040014010sub getStyle($$$)
14011{
14012 my ($Subj, $Act, $Num) = @_;
14013 my %Style = (
14014 "A"=>"new",
14015 "R"=>"failed",
14016 "S"=>"passed",
14017 "L"=>"warning",
14018 "M"=>"failed",
14019 "H"=>"failed"
14020 );
14021 if($Num>0) {
14022 return " class='".$Style{$Act}."'";
14023 }
14024 return "";
14025}
14026
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014027sub show_number($)
14028{
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014029 if($_[0])
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014030 {
Andrey Ponomarenko16934472012-03-29 15:37:04 +040014031 my $Num = cut_off_number($_[0], 2, 0);
14032 if($Num eq "0")
14033 {
14034 foreach my $P (3 .. 7)
14035 {
14036 $Num = cut_off_number($_[0], $P, 1);
14037 if($Num ne "0") {
14038 last;
14039 }
14040 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014041 }
14042 if($Num eq "0") {
14043 $Num = $_[0];
14044 }
14045 return $Num;
14046 }
14047 return $_[0];
14048}
14049
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014050sub cut_off_number($$$)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014051{
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014052 my ($num, $digs_to_cut, $z) = @_;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014053 if($num!~/\./)
14054 {
14055 $num .= ".";
14056 foreach (1 .. $digs_to_cut-1) {
14057 $num .= "0";
14058 }
14059 }
14060 elsif($num=~/\.(.+)\Z/ and length($1)<$digs_to_cut-1)
14061 {
14062 foreach (1 .. $digs_to_cut - 1 - length($1)) {
14063 $num .= "0";
14064 }
14065 }
14066 elsif($num=~/\d+\.(\d){$digs_to_cut,}/) {
14067 $num=sprintf("%.".($digs_to_cut-1)."f", $num);
14068 }
14069 $num=~s/\.[0]+\Z//g;
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014070 if($z) {
14071 $num=~s/(\.[1-9]+)[0]+\Z/$1/g;
14072 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014073 return $num;
14074}
14075
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014076sub get_Report_ChangedConstants($)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014077{
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014078 my $Level = $_[0];
Andrey Ponomarenko16934472012-03-29 15:37:04 +040014079 my $CHANGED_CONSTANTS = "";
14080 my %ReportMap = ();
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014081 foreach my $Constant (keys(%{$ProblemsWithConstants{$Level}})) {
Andrey Ponomarenko16934472012-03-29 15:37:04 +040014082 $ReportMap{$Constants{1}{$Constant}{"Header"}}{$Constant} = 1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014083 }
14084 my $Kind = "Changed_Constant";
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014085 if(not defined $CompatRules{$Level}{$Kind}) {
14086 return "";
14087 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014088 if($ReportFormat eq "xml")
14089 { # XML
Andrey Ponomarenko16934472012-03-29 15:37:04 +040014090 foreach my $HeaderName (sort {lc($a) cmp lc($b)} keys(%ReportMap))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014091 {
14092 $CHANGED_CONSTANTS .= " <header name=\"$HeaderName\">\n";
Andrey Ponomarenko16934472012-03-29 15:37:04 +040014093 foreach my $Constant (sort {lc($a) cmp lc($b)} keys(%{$ReportMap{$HeaderName}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014094 {
14095 $CHANGED_CONSTANTS .= " <constant name=\"$Constant\">\n";
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014096 my $Change = $CompatRules{$Level}{$Kind}{"Change"};
14097 my $Effect = $CompatRules{$Level}{$Kind}{"Effect"};
14098 my $Overcome = $CompatRules{$Level}{$Kind}{"Overcome"};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014099 $CHANGED_CONSTANTS .= " <problem id=\"$Kind\">\n";
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014100 $CHANGED_CONSTANTS .= " <change".getXmlParams($Change, $ProblemsWithConstants{$Level}{$Constant}).">$Change</change>\n";
14101 $CHANGED_CONSTANTS .= " <effect".getXmlParams($Effect, $ProblemsWithConstants{$Level}{$Constant}).">$Effect</effect>\n";
14102 $CHANGED_CONSTANTS .= " <overcome".getXmlParams($Overcome, $ProblemsWithConstants{$Level}{$Constant}).">$Overcome</overcome>\n";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014103 $CHANGED_CONSTANTS .= " </problem>\n";
14104 $CHANGED_CONSTANTS .= " </constant>\n";
14105 }
14106 $CHANGED_CONSTANTS .= " </header>\n";
14107 }
14108 $CHANGED_CONSTANTS = "<problems_with_constants severity=\"Low\">\n".$CHANGED_CONSTANTS."</problems_with_constants>\n\n";
14109 }
14110 else
14111 { # HTML
14112 my $Number = 0;
Andrey Ponomarenko16934472012-03-29 15:37:04 +040014113 foreach my $HeaderName (sort {lc($a) cmp lc($b)} keys(%ReportMap))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014114 {
14115 $CHANGED_CONSTANTS .= "<span class='h_name'>$HeaderName</span><br/>\n";
Andrey Ponomarenko16934472012-03-29 15:37:04 +040014116 foreach my $Name (sort {lc($a) cmp lc($b)} keys(%{$ReportMap{$HeaderName}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014117 {
14118 $Number += 1;
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014119 my $Change = applyMacroses($Level, $Kind, $CompatRules{$Level}{$Kind}{"Change"}, $ProblemsWithConstants{$Level}{$Name});
14120 my $Effect = $CompatRules{$Level}{$Kind}{"Effect"};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014121 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 +040014122 $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 +040014123 $Report = $ContentSpanStart."<span class='extendable'>[+]</span> ".$Name.$ContentSpanEnd."<br/>\n".$Report;
14124 $CHANGED_CONSTANTS .= insertIDs($Report);
14125 }
14126 $CHANGED_CONSTANTS .= "<br/>\n";
14127 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014128 if($CHANGED_CONSTANTS)
14129 {
14130 my $Anchor = "<a name='Changed_Constants'></a>";
14131 if($JoinReport) {
14132 $Anchor = "<a name='".$Level."_Changed_Constants'></a>";
14133 }
14134 $CHANGED_CONSTANTS = $Anchor."<h2>Problems with Constants ($Number)</h2><hr/>\n".$CHANGED_CONSTANTS.$TOP_REF."<br/>\n";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014135 }
14136 }
14137 return $CHANGED_CONSTANTS;
14138}
14139
14140sub get_Report_Impl()
14141{
Andrey Ponomarenko16934472012-03-29 15:37:04 +040014142 my $CHANGED_IMPLEMENTATION = "";
14143 my %ReportMap = ();
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014144 foreach my $Interface (sort keys(%ImplProblems))
14145 {
14146 my $HeaderName = $CompleteSignature{1}{$Interface}{"Header"};
14147 my $DyLib = $Symbol_Library{1}{$Interface};
Andrey Ponomarenko16934472012-03-29 15:37:04 +040014148 $ReportMap{$HeaderName}{$DyLib}{$Interface} = 1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014149 }
14150 my $Changed_Number = 0;
Andrey Ponomarenko16934472012-03-29 15:37:04 +040014151 foreach my $HeaderName (sort {lc($a) cmp lc($b)} keys(%ReportMap))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014152 {
Andrey Ponomarenko16934472012-03-29 15:37:04 +040014153 foreach my $DyLib (sort {lc($a) cmp lc($b)} keys(%{$ReportMap{$HeaderName}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014154 {
14155 my $FDyLib=$DyLib.($DyLib!~/\.\w+\Z/?" (.$LIB_EXT)":"");
14156 if($HeaderName) {
14157 $CHANGED_IMPLEMENTATION .= "<span class='h_name'>$HeaderName</span>, <span class='lib_name'>$FDyLib</span><br/>\n";
14158 }
14159 else {
14160 $CHANGED_IMPLEMENTATION .= "<span class='lib_name'>$DyLib</span><br/>\n";
14161 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014162 my %NameSpaceSymbols = ();
Andrey Ponomarenko16934472012-03-29 15:37:04 +040014163 foreach my $Interface (keys(%{$ReportMap{$HeaderName}{$DyLib}})) {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014164 $NameSpaceSymbols{get_IntNameSpace($Interface, 2)}{$Interface} = 1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014165 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014166 foreach my $NameSpace (sort keys(%NameSpaceSymbols))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014167 {
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040014168 $CHANGED_IMPLEMENTATION .= ($NameSpace)?"<span class='ns_title'>namespace</span> <span class='ns'>$NameSpace</span><br/>\n":"";
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014169 my @SortedInterfaces = sort {lc(get_Signature($a, 1)) cmp lc(get_Signature($b, 1))} keys(%{$NameSpaceSymbols{$NameSpace}});
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014170 foreach my $Interface (@SortedInterfaces)
14171 {
14172 $Changed_Number += 1;
14173 my $Signature = get_Signature($Interface, 1);
14174 if($NameSpace) {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040014175 $Signature=~s/\b\Q$NameSpace\E::\b//g;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014176 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014177 $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 +040014178 }
14179 }
14180 $CHANGED_IMPLEMENTATION .= "<br/>\n";
14181 }
14182 }
14183 if($CHANGED_IMPLEMENTATION) {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014184 $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 +040014185 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +040014186
14187 # clean memory
14188 %ImplProblems = ();
14189
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014190 return $CHANGED_IMPLEMENTATION;
14191}
14192
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014193sub getTitle($$$)
14194{
14195 my ($Header, $Library, $NameSpace) = @_;
14196 my $Title = "";
14197 if($Library and $Library!~/\.\w+\Z/) {
14198 $Library .= " (.$LIB_EXT)";
14199 }
14200 if($Header and $Library)
14201 {
14202 $Title .= "<span class='h_name'>$Header</span>";
14203 $Title .= ", <span class='lib_name'>$Library</span><br/>\n";
14204 }
14205 elsif($Library) {
14206 $Title .= "<span class='lib_name'>$Library</span><br/>\n";
14207 }
14208 elsif($Header) {
14209 $Title .= "<span class='h_name'>$Header</span><br/>\n";
14210 }
14211 if($NameSpace) {
14212 $Title .= "<span class='ns_title'>namespace</span> <span class='ns'>$NameSpace</span><br/>\n";
14213 }
14214 return $Title;
14215}
14216
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014217sub get_Report_Added($)
14218{
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014219 my $Level = $_[0];
Andrey Ponomarenko16934472012-03-29 15:37:04 +040014220 my $ADDED_INTERFACES = "";
14221 my %ReportMap = ();
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014222 foreach my $Interface (sort keys(%{$CompatProblems{$Level}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014223 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014224 foreach my $Kind (sort keys(%{$CompatProblems{$Level}{$Interface}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014225 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014226 if($Kind eq "Added_Symbol")
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014227 {
14228 my $HeaderName = $CompleteSignature{2}{$Interface}{"Header"};
14229 my $DyLib = $Symbol_Library{2}{$Interface};
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014230 if($Level eq "Source" and $ReportFormat eq "html")
14231 { # do not show library name in HTML report
14232 $DyLib = "";
14233 }
14234 $ReportMap{$HeaderName}{$DyLib}{$Interface} = 1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014235 }
14236 }
14237 }
14238 if($ReportFormat eq "xml")
14239 { # XML
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014240 foreach my $HeaderName (sort {lc($a) cmp lc($b)} keys(%ReportMap))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014241 {
14242 $ADDED_INTERFACES .= " <header name=\"$HeaderName\">\n";
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014243 foreach my $DyLib (sort {lc($a) cmp lc($b)} keys(%{$ReportMap{$HeaderName}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014244 {
14245 $ADDED_INTERFACES .= " <library name=\"$DyLib\">\n";
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014246 foreach my $Interface (keys(%{$ReportMap{$HeaderName}{$DyLib}})) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014247 $ADDED_INTERFACES .= " <name>$Interface</name>\n";
14248 }
14249 $ADDED_INTERFACES .= " </library>\n";
14250 }
14251 $ADDED_INTERFACES .= " </header>\n";
14252 }
14253 $ADDED_INTERFACES = "<added_symbols>\n".$ADDED_INTERFACES."</added_symbols>\n\n";
14254 }
14255 else
14256 { # HTML
14257 my $Added_Number = 0;
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014258 foreach my $HeaderName (sort {lc($a) cmp lc($b)} keys(%ReportMap))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014259 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014260 foreach my $DyLib (sort {lc($a) cmp lc($b)} keys(%{$ReportMap{$HeaderName}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014261 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014262 my %NameSpaceSymbols = ();
14263 foreach my $Interface (keys(%{$ReportMap{$HeaderName}{$DyLib}})) {
14264 $NameSpaceSymbols{get_IntNameSpace($Interface, 2)}{$Interface} = 1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014265 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014266 foreach my $NameSpace (sort keys(%NameSpaceSymbols))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014267 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014268 $ADDED_INTERFACES .= getTitle($HeaderName, $DyLib, $NameSpace);
14269 my @SortedInterfaces = sort {lc(get_Signature($a, 2)) cmp lc(get_Signature($b, 2))} keys(%{$NameSpaceSymbols{$NameSpace}});
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014270 foreach my $Interface (@SortedInterfaces)
14271 {
14272 $Added_Number += 1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014273 my $Signature = get_Signature($Interface, 2);
14274 if($NameSpace) {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040014275 $Signature=~s/\b\Q$NameSpace\E::\b//g;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014276 }
14277 if($Interface=~/\A(_Z|\?)/) {
14278 if($Signature) {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014279 $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 +040014280 }
14281 else {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014282 $ADDED_INTERFACES .= "<span class=\"iname\">".$Interface."</span><br/>\n";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014283 }
14284 }
14285 else {
14286 if($Signature) {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014287 $ADDED_INTERFACES .= "<span class=\"iname\">".highLight_Signature_Italic_Color($Signature)."</span><br/>\n";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014288 }
14289 else {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014290 $ADDED_INTERFACES .= "<span class=\"iname\">".$Interface."</span><br/>\n";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014291 }
14292 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014293 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014294 $ADDED_INTERFACES .= "<br/>\n";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014295 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014296 }
14297 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014298 if($ADDED_INTERFACES)
14299 {
14300 my $Anchor = "<a name='Added'></a>";
14301 if($JoinReport) {
14302 $Anchor = "<a name='".$Level."_Added'></a>";
14303 }
14304 $ADDED_INTERFACES = $Anchor."<h2>Added Symbols ($Added_Number)</h2><hr/>\n".$ADDED_INTERFACES.$TOP_REF."<br/>\n";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014305 }
14306 }
14307 return $ADDED_INTERFACES;
14308}
14309
14310sub get_Report_Removed($)
14311{
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014312 my $Level = $_[0];
Andrey Ponomarenko16934472012-03-29 15:37:04 +040014313 my $REMOVED_INTERFACES = "";
14314 my %ReportMap = ();
Andrey Ponomarenko85043792012-05-14 16:48:07 +040014315 foreach my $Symbol (sort keys(%{$CompatProblems{$Level}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014316 {
Andrey Ponomarenko85043792012-05-14 16:48:07 +040014317 foreach my $Kind (sort keys(%{$CompatProblems{$Level}{$Symbol}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014318 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014319 if($Kind eq "Removed_Symbol")
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014320 {
Andrey Ponomarenko85043792012-05-14 16:48:07 +040014321 my $HeaderName = $CompleteSignature{1}{$Symbol}{"Header"};
14322 my $DyLib = $Symbol_Library{1}{$Symbol};
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014323 if($Level eq "Source" and $ReportFormat eq "html")
14324 { # do not show library name in HTML report
14325 $DyLib = "";
14326 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +040014327 $ReportMap{$HeaderName}{$DyLib}{$Symbol} = 1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014328 }
14329 }
14330 }
14331 if($ReportFormat eq "xml")
14332 { # XML
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014333 foreach my $HeaderName (sort {lc($a) cmp lc($b)} keys(%ReportMap))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014334 {
14335 $REMOVED_INTERFACES .= " <header name=\"$HeaderName\">\n";
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014336 foreach my $DyLib (sort {lc($a) cmp lc($b)} keys(%{$ReportMap{$HeaderName}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014337 {
14338 $REMOVED_INTERFACES .= " <library name=\"$DyLib\">\n";
Andrey Ponomarenko85043792012-05-14 16:48:07 +040014339 foreach my $Symbol (keys(%{$ReportMap{$HeaderName}{$DyLib}})) {
14340 $REMOVED_INTERFACES .= " <name>$Symbol</name>\n";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014341 }
14342 $REMOVED_INTERFACES .= " </library>\n";
14343 }
14344 $REMOVED_INTERFACES .= " </header>\n";
14345 }
14346 $REMOVED_INTERFACES = "<removed_symbols>\n".$REMOVED_INTERFACES."</removed_symbols>\n\n";
14347 }
14348 else
14349 { # HTML
14350 my $Removed_Number = 0;
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014351 foreach my $HeaderName (sort {lc($a) cmp lc($b)} keys(%ReportMap))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014352 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014353 foreach my $DyLib (sort {lc($a) cmp lc($b)} keys(%{$ReportMap{$HeaderName}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014354 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014355 my %NameSpaceSymbols = ();
14356 foreach my $Interface (keys(%{$ReportMap{$HeaderName}{$DyLib}})) {
14357 $NameSpaceSymbols{get_IntNameSpace($Interface, 1)}{$Interface} = 1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014358 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014359 foreach my $NameSpace (sort keys(%NameSpaceSymbols))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014360 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014361 $REMOVED_INTERFACES .= getTitle($HeaderName, $DyLib, $NameSpace);
14362 my @SortedInterfaces = sort {lc(get_Signature($a, 1)) cmp lc(get_Signature($b, 1))} keys(%{$NameSpaceSymbols{$NameSpace}});
Andrey Ponomarenko85043792012-05-14 16:48:07 +040014363 foreach my $Symbol (@SortedInterfaces)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014364 {
14365 $Removed_Number += 1;
14366 my $SubReport = "";
Andrey Ponomarenko85043792012-05-14 16:48:07 +040014367 my $Signature = get_Signature($Symbol, 1);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014368 if($NameSpace) {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040014369 $Signature=~s/\b\Q$NameSpace\E::\b//g;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014370 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +040014371 if($Symbol=~/\A(_Z|\?)/)
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014372 {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014373 if($Signature) {
Andrey Ponomarenko85043792012-05-14 16:48:07 +040014374 $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 +040014375 }
14376 else {
Andrey Ponomarenko85043792012-05-14 16:48:07 +040014377 $REMOVED_INTERFACES .= "<span class=\"iname\">".$Symbol."</span><br/>\n";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014378 }
14379 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014380 else
14381 {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014382 if($Signature) {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014383 $REMOVED_INTERFACES .= "<span class=\"iname\">".highLight_Signature_Italic_Color($Signature)."</span><br/>\n";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014384 }
14385 else {
Andrey Ponomarenko85043792012-05-14 16:48:07 +040014386 $REMOVED_INTERFACES .= "<span class=\"iname\">".$Symbol."</span><br/>\n";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014387 }
14388 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014389 }
14390 }
14391 $REMOVED_INTERFACES .= "<br/>\n";
14392 }
14393 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014394 if($REMOVED_INTERFACES)
14395 {
14396 my $Anchor = "<a name='Removed'></a><a name='Withdrawn'></a>";
14397 if($JoinReport) {
14398 $Anchor = "<a name='".$Level."_Removed'></a><a name='".$Level."_Withdrawn'></a>";
14399 }
14400 $REMOVED_INTERFACES = $Anchor."<h2>Removed Symbols ($Removed_Number)</h2><hr/>\n".$REMOVED_INTERFACES.$TOP_REF."<br/>\n";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014401 }
14402 }
14403 return $REMOVED_INTERFACES;
14404}
14405
14406sub getXmlParams($$)
14407{
14408 my ($Content, $Problem) = @_;
14409 return "" if(not $Content or not $Problem);
14410 my %XMLparams = ();
14411 foreach my $Attr (sort {$b cmp $a} keys(%{$Problem}))
14412 {
14413 my $Macro = "\@".lc($Attr);
14414 if($Content=~/\Q$Macro\E/) {
14415 $XMLparams{lc($Attr)} = $Problem->{$Attr};
14416 }
14417 }
14418 my @PString = ();
14419 foreach my $P (sort {$b cmp $a} keys(%XMLparams)) {
14420 push(@PString, $P."=\"".htmlSpecChars($XMLparams{$P})."\"");
14421 }
14422 if(@PString) {
14423 return " ".join(" ", @PString);
14424 }
14425 else {
14426 return "";
14427 }
14428}
14429
14430sub addMarkup($)
14431{
14432 my $Content = $_[0];
14433 # auto-markup
14434 $Content=~s/\n[ ]*//; # spaces
14435 $Content=~s!(\@\w+\s*\(\@\w+\))!<nowrap>$1</nowrap>!g; # @old_type (@old_size)
14436 $Content=~s!(... \(\w+\))!<nowrap><b>$1</b></nowrap>!g; # ... (va_list)
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040014437 $Content=~s!<nowrap>(.+?)</nowrap>!<span class='nowrap'>$1</span>!g;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014438 $Content=~s!([2-9]\))!<br/>$1!g; # 1), 2), ...
14439 if($Content=~/\ANOTE:/)
14440 { # notes
14441 $Content=~s!(NOTE):!<b>$1</b>:!g;
14442 }
14443 else {
14444 $Content=~s!(NOTE):!<br/><b>$1</b>:!g;
14445 }
14446 $Content=~s! (out)-! <b>$1</b>-!g; # out-parameters
14447 my @Keywords = (
14448 "void",
14449 "const",
14450 "static",
14451 "restrict",
14452 "volatile",
14453 "register",
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040014454 "virtual"
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014455 );
14456 my $MKeys = join("|", @Keywords);
14457 foreach (@Keywords) {
14458 $MKeys .= "|non-".$_;
14459 }
14460 $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 +040014461
14462 # Markdown
14463 $Content=~s!\*\*([\w\-]+)\*\*!<b>$1</b>!ig;
14464 $Content=~s!\*([\w\-]+)\*!<i>$1</i>!ig;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014465 return $Content;
14466}
14467
14468sub applyMacroses($$$$)
14469{
14470 my ($Level, $Kind, $Content, $Problem) = @_;
14471 return "" if(not $Content or not $Problem);
14472 $Problem->{"Word_Size"} = $WORD_SIZE{2};
14473 $Content = addMarkup($Content);
14474 # macros
14475 foreach my $Attr (sort {$b cmp $a} keys(%{$Problem}))
14476 {
14477 my $Macro = "\@".lc($Attr);
14478 my $Value = $Problem->{$Attr};
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040014479 if(not defined $Value
14480 or $Value eq "") {
14481 next;
14482 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014483 if($Value=~/\s\(/)
14484 { # functions
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014485 $Value=~s/\s*\[[\w\-]+\]//g; # remove quals
14486 $Value=~s/\s\w+(\)|,)/$1/g; # remove parameter names
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014487 $Value = black_name($Value);
14488 }
14489 elsif($Value=~/\s/) {
14490 $Value = "<span class='value'>".htmlSpecChars($Value)."</span>";
14491 }
14492 elsif($Value=~/\A\d+\Z/
14493 and ($Attr eq "Old_Size" or $Attr eq "New_Size"))
14494 { # bits to bytes
14495 if($Value % $BYTE_SIZE)
14496 { # bits
14497 if($Value==1) {
14498 $Value = "<b>".$Value."</b> bit";
14499 }
14500 else {
14501 $Value = "<b>".$Value."</b> bits";
14502 }
14503 }
14504 else
14505 { # bytes
14506 $Value /= $BYTE_SIZE;
14507 if($Value==1) {
14508 $Value = "<b>".$Value."</b> byte";
14509 }
14510 else {
14511 $Value = "<b>".$Value."</b> bytes";
14512 }
14513 }
14514 }
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040014515 else
14516 {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014517 $Value = "<b>".htmlSpecChars($Value)."</b>";
14518 }
14519 $Content=~s/\Q$Macro\E/$Value/g;
14520 }
14521
14522 if($Content=~/(\A|[^\@\w])\@\w/)
14523 {
14524 if(not $IncompleteRules{$Level}{$Kind})
14525 { # only one warning
14526 printMsg("WARNING", "incomplete rule \"$Kind\" (\"$Level\")");
14527 $IncompleteRules{$Level}{$Kind} = 1;
14528 }
14529 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014530 return $Content;
14531}
14532
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040014533sub get_Report_SymbolProblems($$)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014534{
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014535 my ($TargetSeverity, $Level) = @_;
Andrey Ponomarenko16934472012-03-29 15:37:04 +040014536 my $INTERFACE_PROBLEMS = "";
14537 my (%ReportMap, %SymbolChanges) = ();
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014538 foreach my $Symbol (sort keys(%{$CompatProblems{$Level}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014539 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014540 my ($SN, $SS, $SV) = separate_symbol($Symbol);
14541 if($SV and defined $CompatProblems{$Level}{$SN}) {
14542 next;
14543 }
14544 foreach my $Kind (sort keys(%{$CompatProblems{$Level}{$Symbol}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014545 {
14546 if($CompatRules{$Level}{$Kind}{"Kind"} eq "Symbols"
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014547 and $Kind ne "Added_Symbol" and $Kind ne "Removed_Symbol")
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014548 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014549 my $HeaderName = $CompleteSignature{1}{$Symbol}{"Header"};
14550 my $DyLib = $Symbol_Library{1}{$Symbol};
14551 if(not $DyLib and my $VSym = $SymVer{1}{$Symbol})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014552 { # Symbol with Version
14553 $DyLib = $Symbol_Library{1}{$VSym};
14554 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040014555 if(not $DyLib)
14556 { # const global data
14557 $DyLib = "";
14558 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014559 if($Level eq "Source" and $ReportFormat eq "html")
14560 { # do not show library name in HTML report
14561 $DyLib = "";
14562 }
14563 %{$SymbolChanges{$Symbol}{$Kind}} = %{$CompatProblems{$Level}{$Symbol}{$Kind}};
14564 foreach my $Location (sort keys(%{$SymbolChanges{$Symbol}{$Kind}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014565 {
14566 my $Priority = getProblemSeverity($Level, $Kind);
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014567 if($Priority ne $TargetSeverity) {
14568 delete($SymbolChanges{$Symbol}{$Kind}{$Location});
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014569 }
14570 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014571 if(not keys(%{$SymbolChanges{$Symbol}{$Kind}}))
14572 {
14573 delete($SymbolChanges{$Symbol}{$Kind});
14574 next;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014575 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014576 $ReportMap{$HeaderName}{$DyLib}{$Symbol} = 1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014577 }
14578 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014579 if(not keys(%{$SymbolChanges{$Symbol}})) {
14580 delete($SymbolChanges{$Symbol});
14581 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014582 }
14583 if($ReportFormat eq "xml")
14584 { # XML
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014585 foreach my $HeaderName (sort {lc($a) cmp lc($b)} keys(%ReportMap))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014586 {
14587 $INTERFACE_PROBLEMS .= " <header name=\"$HeaderName\">\n";
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 {
14590 $INTERFACE_PROBLEMS .= " <library name=\"$DyLib\">\n";
14591 foreach my $Symbol (sort {lc($tr_name{$a}) cmp lc($tr_name{$b})} keys(%SymbolChanges))
14592 {
14593 $INTERFACE_PROBLEMS .= " <symbol name=\"$Symbol\">\n";
14594 foreach my $Kind (keys(%{$SymbolChanges{$Symbol}}))
14595 {
14596 foreach my $Location (sort keys(%{$SymbolChanges{$Symbol}{$Kind}}))
14597 {
14598 my %Problem = %{$SymbolChanges{$Symbol}{$Kind}{$Location}};
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040014599 $Problem{"Param_Pos"} = showPos($Problem{"Param_Pos"});
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014600 $INTERFACE_PROBLEMS .= " <problem id=\"$Kind\">\n";
14601 my $Change = $CompatRules{$Level}{$Kind}{"Change"};
14602 $INTERFACE_PROBLEMS .= " <change".getXmlParams($Change, \%Problem).">$Change</change>\n";
14603 my $Effect = $CompatRules{$Level}{$Kind}{"Effect"};
14604 $INTERFACE_PROBLEMS .= " <effect".getXmlParams($Effect, \%Problem).">$Effect</effect>\n";
14605 my $Overcome = $CompatRules{$Level}{$Kind}{"Overcome"};
14606 $INTERFACE_PROBLEMS .= " <overcome".getXmlParams($Overcome, \%Problem).">$Overcome</overcome>\n";
14607 $INTERFACE_PROBLEMS .= " </problem>\n";
14608 }
14609 }
14610 $INTERFACE_PROBLEMS .= " </symbol>\n";
14611 }
14612 $INTERFACE_PROBLEMS .= " </library>\n";
14613 }
14614 $INTERFACE_PROBLEMS .= " </header>\n";
14615 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014616 $INTERFACE_PROBLEMS = "<problems_with_symbols severity=\"$TargetSeverity\">\n".$INTERFACE_PROBLEMS."</problems_with_symbols>\n\n";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014617 }
14618 else
14619 { # HTML
14620 my $ProblemsNum = 0;
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014621 foreach my $HeaderName (sort {lc($a) cmp lc($b)} keys(%ReportMap))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014622 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014623 foreach my $DyLib (sort {lc($a) cmp lc($b)} keys(%{$ReportMap{$HeaderName}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014624 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014625 my (%NameSpaceSymbols, %NewSignature) = ();
14626 foreach my $Symbol (keys(%{$ReportMap{$HeaderName}{$DyLib}})) {
14627 $NameSpaceSymbols{get_IntNameSpace($Symbol, 1)}{$Symbol} = 1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014628 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014629 foreach my $NameSpace (sort keys(%NameSpaceSymbols))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014630 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014631 $INTERFACE_PROBLEMS .= getTitle($HeaderName, $DyLib, $NameSpace);
14632 my @SortedInterfaces = sort {lc($tr_name{$a}) cmp lc($tr_name{$b})} keys(%{$NameSpaceSymbols{$NameSpace}});
14633 foreach my $Symbol (@SortedInterfaces)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014634 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014635 my $Signature = get_Signature($Symbol, 1);
14636 my $SYMBOL_REPORT = "";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014637 my $ProblemNum = 1;
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014638 foreach my $Kind (keys(%{$SymbolChanges{$Symbol}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014639 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014640 foreach my $Location (sort keys(%{$SymbolChanges{$Symbol}{$Kind}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014641 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014642 my %Problem = %{$SymbolChanges{$Symbol}{$Kind}{$Location}};
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040014643 $Problem{"Param_Pos"} = showPos($Problem{"Param_Pos"});
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014644 if($Problem{"New_Signature"}) {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014645 $NewSignature{$Symbol} = $Problem{"New_Signature"};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014646 }
14647 if(my $Change = applyMacroses($Level, $Kind, $CompatRules{$Level}{$Kind}{"Change"}, \%Problem))
14648 {
14649 my $Effect = applyMacroses($Level, $Kind, $CompatRules{$Level}{$Kind}{"Effect"}, \%Problem);
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014650 $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 +040014651 $ProblemNum += 1;
14652 $ProblemsNum += 1;
14653 }
14654 }
14655 }
14656 $ProblemNum -= 1;
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014657 if($SYMBOL_REPORT)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014658 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014659 $INTERFACE_PROBLEMS .= $ContentSpanStart."<span class='extendable'>[+]</span> ";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014660 if($Signature) {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014661 $INTERFACE_PROBLEMS .= highLight_Signature_Italic_Color($Signature);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014662 }
14663 else {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014664 $INTERFACE_PROBLEMS .= $Symbol;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014665 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014666 $INTERFACE_PROBLEMS .= " ($ProblemNum)".$ContentSpanEnd."<br/>\n";
14667 $INTERFACE_PROBLEMS .= $ContentDivStart."\n";
14668 if($NewSignature{$Symbol})
14669 { # argument list changed to
14670 $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 +040014671 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014672 if($Symbol=~/\A(_Z|\?)/) {
14673 $INTERFACE_PROBLEMS .= "<span class='mangled'>&#160;&#160;&#160;&#160;[symbol: <b>$Symbol</b>]</span><br/>\n";
14674 }
14675 $INTERFACE_PROBLEMS .= "<table class='ptable'><tr><th width='2%'></th><th width='47%'>Change</th><th>Effect</th></tr>$SYMBOL_REPORT</table><br/>\n";
14676 $INTERFACE_PROBLEMS .= $ContentDivEnd;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014677 if($NameSpace) {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040014678 $INTERFACE_PROBLEMS=~s/\b\Q$NameSpace\E::\b//g;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014679 }
14680 }
14681 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014682 $INTERFACE_PROBLEMS .= "<br/>";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014683 }
14684 }
14685 }
14686 if($INTERFACE_PROBLEMS)
14687 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014688 $INTERFACE_PROBLEMS = insertIDs($INTERFACE_PROBLEMS);
14689 my $Title = "Problems with Symbols, $TargetSeverity Severity";
14690 if($TargetSeverity eq "Safe")
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014691 { # Safe Changes
14692 $Title = "Other Changes in Symbols";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014693 }
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040014694 $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 +040014695 }
14696 }
14697 return $INTERFACE_PROBLEMS;
14698}
14699
14700sub get_Report_TypeProblems($$)
14701{
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014702 my ($TargetSeverity, $Level) = @_;
Andrey Ponomarenko16934472012-03-29 15:37:04 +040014703 my $TYPE_PROBLEMS = "";
14704 my (%ReportMap, %TypeChanges, %TypeType) = ();
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014705 foreach my $Interface (sort keys(%{$CompatProblems{$Level}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014706 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014707 foreach my $Kind (keys(%{$CompatProblems{$Level}{$Interface}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014708 {
14709 if($CompatRules{$Level}{$Kind}{"Kind"} eq "Types")
14710 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014711 foreach my $Location (sort {cmp_locations($b, $a)} sort keys(%{$CompatProblems{$Level}{$Interface}{$Kind}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014712 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014713 my $TypeName = $CompatProblems{$Level}{$Interface}{$Kind}{$Location}{"Type_Name"};
14714 my $TypeType = $CompatProblems{$Level}{$Interface}{$Kind}{$Location}{"Type_Type"};
14715 my $Target = $CompatProblems{$Level}{$Interface}{$Kind}{$Location}{"Target"};
14716 $CompatProblems{$Level}{$Interface}{$Kind}{$Location}{"Type_Type"} = lc($TypeType);
14717 my $Severity = getProblemSeverity($Level, $Kind);
14718 if($Severity eq "Safe"
14719 and $TargetSeverity ne "Safe") {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014720 next;
14721 }
14722 if(not $TypeType{$TypeName}
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014723 or $TypeType{$TypeName} eq "struct")
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014724 { # register type of the type, select "class" if type has "class"- and "struct"-type changes
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014725 $TypeType{$TypeName} = $CompatProblems{$Level}{$Interface}{$Kind}{$Location}{"Type_Type"};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014726 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014727
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040014728 if(cmpSeverities($Type_MaxSeverity{$Level}{$TypeName}{$Kind}{$Target}, $Severity))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014729 { # select a problem with the highest priority
14730 next;
14731 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014732 %{$TypeChanges{$TypeName}{$Kind}{$Location}} = %{$CompatProblems{$Level}{$Interface}{$Kind}{$Location}};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014733 }
14734 }
14735 }
14736 }
14737 my %Kinds_Locations = ();
14738 foreach my $TypeName (keys(%TypeChanges))
14739 {
14740 my %Kinds_Target = ();
14741 foreach my $Kind (sort keys(%{$TypeChanges{$TypeName}}))
14742 {
14743 foreach my $Location (sort {cmp_locations($b, $a)} sort keys(%{$TypeChanges{$TypeName}{$Kind}}))
14744 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014745 my $Severity = getProblemSeverity($Level, $Kind);
14746 if($Severity ne $TargetSeverity)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014747 { # other priority
14748 delete($TypeChanges{$TypeName}{$Kind}{$Location});
14749 next;
14750 }
14751 $Kinds_Locations{$TypeName}{$Kind}{$Location} = 1;
14752 my $Target = $TypeChanges{$TypeName}{$Kind}{$Location}{"Target"};
14753 if($Kinds_Target{$Kind}{$Target})
14754 { # duplicate target
14755 delete($TypeChanges{$TypeName}{$Kind}{$Location});
14756 next;
14757 }
14758 $Kinds_Target{$Kind}{$Target} = 1;
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040014759 my $HeaderName = $TypeInfo{1}{$TName_Tid{1}{$TypeName}}{"Header"};
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014760 $ReportMap{$HeaderName}{$TypeName} = 1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014761 }
14762 if(not keys(%{$TypeChanges{$TypeName}{$Kind}})) {
14763 delete($TypeChanges{$TypeName}{$Kind});
14764 }
14765 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014766 if(not keys(%{$TypeChanges{$TypeName}})) {
14767 delete($TypeChanges{$TypeName});
14768 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014769 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +040014770 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 +040014771 if($ReportFormat eq "xml")
14772 { # XML
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014773 foreach my $HeaderName (sort {lc($a) cmp lc($b)} keys(%ReportMap))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014774 {
14775 $TYPE_PROBLEMS .= " <header name=\"$HeaderName\">\n";
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014776 foreach my $TypeName (keys(%{$ReportMap{$HeaderName}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014777 {
14778 $TYPE_PROBLEMS .= " <type name=\"".htmlSpecChars($TypeName)."\">\n";
14779 foreach my $Kind (sort {$b=~/Size/ <=> $a=~/Size/} sort keys(%{$TypeChanges{$TypeName}}))
14780 {
14781 foreach my $Location (sort {cmp_locations($b, $a)} sort keys(%{$TypeChanges{$TypeName}{$Kind}}))
14782 {
14783 my %Problem = %{$TypeChanges{$TypeName}{$Kind}{$Location}};
14784 $TYPE_PROBLEMS .= " <problem id=\"$Kind\">\n";
14785 my $Change = $CompatRules{$Level}{$Kind}{"Change"};
14786 $TYPE_PROBLEMS .= " <change".getXmlParams($Change, \%Problem).">$Change</change>\n";
14787 my $Effect = $CompatRules{$Level}{$Kind}{"Effect"};
14788 $TYPE_PROBLEMS .= " <effect".getXmlParams($Effect, \%Problem).">$Effect</effect>\n";
14789 my $Overcome = $CompatRules{$Level}{$Kind}{"Overcome"};
14790 $TYPE_PROBLEMS .= " <overcome".getXmlParams($Overcome, \%Problem).">$Overcome</overcome>\n";
14791 $TYPE_PROBLEMS .= " </problem>\n";
14792 }
14793 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +040014794 $TYPE_PROBLEMS .= getAffectedSymbols($Level, $TypeName, $Kinds_Locations{$TypeName}, \@Symbols);
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014795 if($Level eq "Binary" and grep {$_=~/Virtual|Base_Class/} keys(%{$Kinds_Locations{$TypeName}})) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014796 $TYPE_PROBLEMS .= showVTables($TypeName);
14797 }
14798 $TYPE_PROBLEMS .= " </type>\n";
14799 }
14800 $TYPE_PROBLEMS .= " </header>\n";
14801 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014802 $TYPE_PROBLEMS = "<problems_with_types severity=\"$TargetSeverity\">\n".$TYPE_PROBLEMS."</problems_with_types>\n\n";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014803 }
14804 else
14805 { # HTML
14806 my $ProblemsNum = 0;
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014807 foreach my $HeaderName (sort {lc($a) cmp lc($b)} keys(%ReportMap))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014808 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014809 my (%NameSpace_Type) = ();
14810 foreach my $TypeName (keys(%{$ReportMap{$HeaderName}})) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014811 $NameSpace_Type{parse_TypeNameSpace($TypeName, 1)}{$TypeName} = 1;
14812 }
14813 foreach my $NameSpace (sort keys(%NameSpace_Type))
14814 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014815 $TYPE_PROBLEMS .= getTitle($HeaderName, "", $NameSpace);
14816 my @SortedTypes = sort {$TypeType{$a}." ".lc($a) cmp $TypeType{$b}." ".lc($b)} keys(%{$NameSpace_Type{$NameSpace}});
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014817 foreach my $TypeName (@SortedTypes)
14818 {
14819 my $ProblemNum = 1;
14820 my $TYPE_REPORT = "";
14821 foreach my $Kind (sort {$b=~/Size/ <=> $a=~/Size/} sort keys(%{$TypeChanges{$TypeName}}))
14822 {
14823 foreach my $Location (sort {cmp_locations($b, $a)} sort keys(%{$TypeChanges{$TypeName}{$Kind}}))
14824 {
14825 my %Problem = %{$TypeChanges{$TypeName}{$Kind}{$Location}};
14826 if(my $Change = applyMacroses($Level, $Kind, $CompatRules{$Level}{$Kind}{"Change"}, \%Problem))
14827 {
14828 my $Effect = applyMacroses($Level, $Kind, $CompatRules{$Level}{$Kind}{"Effect"}, \%Problem);
14829 $TYPE_REPORT .= "<tr><th>$ProblemNum</th><td align='left' valign='top'>".$Change."</td><td align='left' valign='top'>$Effect</td></tr>\n";
14830 $ProblemNum += 1;
14831 $ProblemsNum += 1;
14832 }
14833 }
14834 }
14835 $ProblemNum -= 1;
14836 if($TYPE_REPORT)
14837 {
Andrey Ponomarenko85043792012-05-14 16:48:07 +040014838 my $Affected = getAffectedSymbols($Level, $TypeName, $Kinds_Locations{$TypeName}, \@Symbols);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014839 my $ShowVTables = "";
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014840 if($Level eq "Binary" and grep {$_=~/Virtual|Base_Class/} keys(%{$Kinds_Locations{$TypeName}})) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014841 $ShowVTables = showVTables($TypeName);
14842 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014843 $TYPE_PROBLEMS .= $ContentSpanStart."<span class='extendable'>[+]</span> <span class='ttype'>".$TypeType{$TypeName}."</span> ".htmlSpecChars($TypeName)." ($ProblemNum)".$ContentSpanEnd;
14844 $TYPE_PROBLEMS .= "<br/>\n".$ContentDivStart."<table class='ptable'><tr>\n";
14845 $TYPE_PROBLEMS .= "<th width='2%'></th><th width='47%'>Change</th>\n";
14846 $TYPE_PROBLEMS .= "<th>Effect</th></tr>".$TYPE_REPORT."</table>\n";
14847 $TYPE_PROBLEMS .= $ShowVTables.$Affected."<br/><br/>".$ContentDivEnd."\n";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014848 if($NameSpace) {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040014849 $TYPE_PROBLEMS=~s/\b\Q$NameSpace\E::(\w|\~)/$1/g;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014850 }
14851 }
14852 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014853 $TYPE_PROBLEMS .= "<br/>";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014854 }
14855 }
14856 if($TYPE_PROBLEMS)
14857 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014858 $TYPE_PROBLEMS = insertIDs($TYPE_PROBLEMS);
14859 my $Title = "Problems with Data Types, $TargetSeverity Severity";
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014860 if($TargetSeverity eq "Safe")
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014861 { # Safe Changes
14862 $Title = "Other Changes in Data Types";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014863 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014864 $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 +040014865 }
14866 }
14867 return $TYPE_PROBLEMS;
14868}
14869
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014870sub get_Anchor($$$)
14871{
14872 my ($Kind, $Level, $Severity) = @_;
14873 if($JoinReport)
14874 {
14875 if($Severity eq "Safe") {
14876 return "Other_".$Level."_Changes_In_".$Kind."s";
14877 }
14878 else {
14879 return $Kind."_".$Level."_Problems_".$Severity;
14880 }
14881 }
14882 else
14883 {
14884 if($Severity eq "Safe") {
14885 return "Other_Changes_In_".$Kind."s";
14886 }
14887 else {
14888 return $Kind."_Problems_".$Severity;
14889 }
14890 }
14891}
14892
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014893sub showVTables($)
14894{
14895 my $TypeName = $_[0];
14896 my $TypeId1 = $TName_Tid{1}{$TypeName};
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040014897 my %Type1 = get_Type($TypeId1, 1);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014898 if(defined $Type1{"VTable"}
14899 and keys(%{$Type1{"VTable"}}))
14900 {
14901 my $TypeId2 = $TName_Tid{2}{$TypeName};
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040014902 my %Type2 = get_Type($TypeId2, 2);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014903 if(defined $Type2{"VTable"}
14904 and keys(%{$Type2{"VTable"}}))
14905 {
14906 my %Indexes = map {$_=>1} (keys(%{$Type1{"VTable"}}), keys(%{$Type2{"VTable"}}));
14907 my %Entries = ();
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014908 foreach my $Index (sort {int($a)<=>int($b)} (keys(%Indexes)))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014909 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014910 $Entries{$Index}{"E1"} = simpleVEntry($Type1{"VTable"}{$Index});
14911 $Entries{$Index}{"E2"} = simpleVEntry($Type2{"VTable"}{$Index});
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014912 }
14913 my $VTABLES = "";
14914 if($ReportFormat eq "xml")
14915 { # XML
14916 $VTABLES .= " <vtable>\n";
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014917 foreach my $Index (sort {int($a)<=>int($b)} (keys(%Entries)))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014918 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014919 $VTABLES .= " <entry offset=\"".$Index."\">\n";
14920 $VTABLES .= " <old>".htmlSpecChars($Entries{$Index}{"E1"})."</old>\n";
14921 $VTABLES .= " <new>".htmlSpecChars($Entries{$Index}{"E2"})."</new>\n";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014922 $VTABLES .= " </entry>\n";
14923 }
14924 $VTABLES .= " </vtable>\n\n";
14925 }
14926 else
14927 { # HTML
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014928 $VTABLES .= "<table class='vtable'>";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014929 $VTABLES .= "<tr><th width='2%'>Offset</th>";
14930 $VTABLES .= "<th width='45%'>Virtual Table (Old) - ".(keys(%{$Type1{"VTable"}}))." entries</th>";
14931 $VTABLES .= "<th>Virtual Table (New) - ".(keys(%{$Type2{"VTable"}}))." entries</th></tr>";
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014932 foreach my $Index (sort {int($a)<=>int($b)} (keys(%Entries)))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014933 {
14934 my ($Color1, $Color2) = ("", "");
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014935 if($Entries{$Index}{"E1"} ne $Entries{$Index}{"E2"})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014936 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014937 if($Entries{$Index}{"E1"})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014938 {
Andrey Ponomarenko16934472012-03-29 15:37:04 +040014939 $Color1 = " class='failed'";
14940 $Color2 = " class='failed'";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014941 }
14942 else {
Andrey Ponomarenko16934472012-03-29 15:37:04 +040014943 $Color2 = " class='warning'";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014944 }
14945 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014946 $VTABLES .= "<tr><th>".$Index."</th>\n";
14947 $VTABLES .= "<td$Color1>".htmlSpecChars($Entries{$Index}{"E1"})."</td>\n";
14948 $VTABLES .= "<td$Color2>".htmlSpecChars($Entries{$Index}{"E2"})."</td></tr>\n";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014949 }
14950 $VTABLES .= "</table><br/>\n";
14951 $VTABLES = $ContentDivStart.$VTABLES.$ContentDivEnd;
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014952 $VTABLES = $ContentSpanStart_Info."[+] show v-table (old and new)".$ContentSpanEnd."<br/>\n".$VTABLES;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014953 }
14954 return $VTABLES;
14955 }
14956 }
14957 return "";
14958}
14959
14960sub simpleVEntry($)
14961{
14962 my $VEntry = $_[0];
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040014963 if(not defined $VEntry
14964 or $VEntry eq "") {
14965 return "";
14966 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014967 $VEntry=~s/\A(.+)::(_ZThn.+)\Z/$2/; # thunks
14968 $VEntry=~s/_ZTI\w+/typeinfo/g; # typeinfo
14969 if($VEntry=~/\A_ZThn.+\Z/) {
14970 $VEntry = "non-virtual thunk";
14971 }
14972 $VEntry=~s/\A\(int \(\*\)\(...\)\)([^\(\d])/$1/i;
14973 # support for old GCC versions
14974 $VEntry=~s/\A0u\Z/(int (*)(...))0/;
14975 $VEntry=~s/\A4294967268u\Z/(int (*)(...))-0x000000004/;
14976 $VEntry=~s/\A&_Z\Z/& _Z/;
14977 # templates
14978 if($VEntry=~s/ \[with (\w+) = (.+?)(, [^=]+ = .+|])\Z//g)
14979 { # std::basic_streambuf<_CharT, _Traits>::imbue [with _CharT = char, _Traits = std::char_traits<char>]
14980 # become std::basic_streambuf<char, ...>::imbue
14981 my ($Pname, $Pval) = ($1, $2);
14982 if($Pname eq "_CharT" and $VEntry=~/\Astd::/)
14983 { # stdc++ typedefs
14984 $VEntry=~s/<$Pname(, [^<>]+|)>/<$Pval>/g;
14985 # FIXME: simplify names using stdcxx typedefs (StdCxxTypedef)
14986 # The typedef info should be added to ABI dumps
14987 }
14988 else
14989 {
14990 $VEntry=~s/<$Pname>/<$Pval>/g;
14991 $VEntry=~s/<$Pname, [^<>]+>/<$Pval, ...>/g;
14992 }
14993 }
14994 $VEntry=~s/([^:]+)::\~([^:]+)\Z/~$1/; # destructors
14995 return $VEntry;
14996}
14997
Andrey Ponomarenko85043792012-05-14 16:48:07 +040014998sub getAffectedSymbols($$$$)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014999{
Andrey Ponomarenko85043792012-05-14 16:48:07 +040015000 my ($Level, $Target_TypeName, $Kinds_Locations, $Syms) = @_;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015001 my $LIMIT = 1000;
Andrey Ponomarenko85043792012-05-14 16:48:07 +040015002 if($#{$Syms}>=10000)
15003 { # reduce size of the report
15004 $LIMIT = 10;
15005 }
15006 my %SProblems = ();
15007 foreach my $Symbol (@{$Syms})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015008 {
Andrey Ponomarenko85043792012-05-14 16:48:07 +040015009 if(keys(%SProblems)>$LIMIT) {
15010 last;
15011 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015012 if(($Symbol=~/C2E|D2E|D0E/))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015013 { # duplicated problems for C2 constructors, D2 and D0 destructors
15014 next;
15015 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015016 my ($SN, $SS, $SV) = separate_symbol($Symbol);
15017 if($Level eq "Source")
15018 { # remove symbol version
15019 $Symbol=$SN;
15020 }
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040015021 my ($MinPath_Length, $ProblemLocation_Last) = (-1, "");
15022 my $Severity_Max = 0;
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015023 my $Signature = get_Signature($Symbol, 1);
15024 foreach my $Kind (keys(%{$CompatProblems{$Level}{$Symbol}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015025 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015026 foreach my $Location (keys(%{$CompatProblems{$Level}{$Symbol}{$Kind}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015027 {
15028 if(not defined $Kinds_Locations->{$Kind}
15029 or not $Kinds_Locations->{$Kind}{$Location}) {
15030 next;
15031 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015032 if($SV and defined $CompatProblems{$Level}{$SN}
15033 and defined $CompatProblems{$Level}{$SN}{$Kind}{$Location})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015034 { # duplicated problems for versioned symbols
15035 next;
15036 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015037 my $Type_Name = $CompatProblems{$Level}{$Symbol}{$Kind}{$Location}{"Type_Name"};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015038 next if($Type_Name ne $Target_TypeName);
15039
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015040 my $Position = $CompatProblems{$Level}{$Symbol}{$Kind}{$Location}{"Param_Pos"};
15041 my $Param_Name = $CompatProblems{$Level}{$Symbol}{$Kind}{$Location}{"Param_Name"};
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040015042 my $Severity = getProblemSeverity($Level, $Kind);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015043 my $Path_Length = 0;
15044 my $ProblemLocation = $Location;
15045 if($Type_Name) {
15046 $ProblemLocation=~s/->\Q$Type_Name\E\Z//g;
15047 }
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040015048 while($ProblemLocation=~/\-\>/g) {
15049 $Path_Length += 1;
15050 }
15051 if($MinPath_Length==-1 or ($Path_Length<=$MinPath_Length and $Severity_Val{$Severity}>$Severity_Max)
15052 or (cmp_locations($ProblemLocation, $ProblemLocation_Last) and $Severity_Val{$Severity}==$Severity_Max))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015053 {
15054 $MinPath_Length = $Path_Length;
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040015055 $Severity_Max = $Severity_Val{$Severity};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015056 $ProblemLocation_Last = $ProblemLocation;
Andrey Ponomarenko85043792012-05-14 16:48:07 +040015057 %{$SProblems{$Symbol}} = (
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040015058 "Descr"=>getAffectDescription($Level, $Symbol, $Kind, $Location),
15059 "Severity_Max"=>$Severity_Max,
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015060 "Signature"=>$Signature,
15061 "Position"=>$Position,
15062 "Param_Name"=>$Param_Name,
15063 "Location"=>$Location
15064 );
15065 }
15066 }
15067 }
15068 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +040015069 my @Symbols = keys(%SProblems);
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015070 @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 +040015071 @Symbols = sort {$SProblems{$b}{"Severity_Max"}<=>$SProblems{$a}{"Severity_Max"}} @Symbols;
15072 if($#Symbols+1>$LIMIT)
15073 { # remove last element
15074 pop(@Symbols);
15075 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015076 my $Affected = "";
15077 if($ReportFormat eq "xml")
15078 { # XML
15079 $Affected .= " <affected>\n";
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015080 foreach my $Symbol (@Symbols)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015081 {
Andrey Ponomarenko85043792012-05-14 16:48:07 +040015082 my $Param_Name = $SProblems{$Symbol}{"Param_Name"};
15083 my $Description = $SProblems{$Symbol}{"Descr"};
15084 my $Location = $SProblems{$Symbol}{"Location"};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015085 my $Target = "";
15086 if($Param_Name) {
15087 $Target = " affected=\"param\" param_name=\"$Param_Name\"";
15088 }
15089 elsif($Location=~/\Aretval(\-|\Z)/i) {
15090 $Target = " affected=\"retval\"";
15091 }
15092 elsif($Location=~/\Athis(\-|\Z)/i) {
15093 $Target = " affected=\"this\"";
15094 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015095 $Affected .= " <symbol$Target name=\"$Symbol\">\n";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015096 $Affected .= " <comment>".htmlSpecChars($Description)."</comment>\n";
15097 $Affected .= " </symbol>\n";
15098 }
15099 $Affected .= " </affected>\n";
15100 }
15101 else
15102 { # HTML
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015103 foreach my $Symbol (@Symbols)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015104 {
Andrey Ponomarenko85043792012-05-14 16:48:07 +040015105 my $Description = $SProblems{$Symbol}{"Descr"};
15106 my $Signature = $SProblems{$Symbol}{"Signature"};
15107 my $Pos = $SProblems{$Symbol}{"Position"};
Andrey Ponomarenkoa01311b2012-06-08 17:20:02 +040015108 $Affected .= "<span class='iname_a'>".highLight_Signature_PPos_Italic($Signature, $Pos, 1, 0, 0)."</span><br/><div class='affect'>".htmlSpecChars($Description)."</div>\n";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015109 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +040015110 if(keys(%SProblems)>$LIMIT) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015111 $Affected .= "and others ...<br/>";
15112 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +040015113 $Affected = "<div class='affected'>".$Affected."</div>";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015114 if($Affected)
15115 {
15116 $Affected = $ContentDivStart.$Affected.$ContentDivEnd;
Andrey Ponomarenko85043792012-05-14 16:48:07 +040015117 $Affected = $ContentSpanStart_Affected."[+] affected symbols (".(keys(%SProblems)>$LIMIT?">".$LIMIT:keys(%SProblems)).")".$ContentSpanEnd.$Affected;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015118 }
15119 }
15120 return $Affected;
15121}
15122
15123sub cmp_locations($$)
15124{
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040015125 my ($L1, $L2) = @_;
15126 if($L2=~/\b(retval|this)\b/
15127 and $L1!~/\b(retval|this)\b/ and $L1!~/\-\>/) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015128 return 1;
15129 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040015130 if($L2=~/\b(retval|this)\b/ and $L2=~/\-\>/
15131 and $L1!~/\b(retval|this)\b/ and $L1=~/\-\>/) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015132 return 1;
15133 }
15134 return 0;
15135}
15136
15137sub getAffectDescription($$$$)
15138{
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015139 my ($Level, $Symbol, $Kind, $Location) = @_;
15140 my %Problem = %{$CompatProblems{$Level}{$Symbol}{$Kind}{$Location}};
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040015141 my $PPos = showPos($Problem{"Param_Pos"});
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015142 my @Sentence = ();
15143 $Location=~s/\A(.*)\-\>.+?\Z/$1/;
15144 if($Kind eq "Overridden_Virtual_Method"
15145 or $Kind eq "Overridden_Virtual_Method_B") {
15146 push(@Sentence, "The method '".$Problem{"New_Value"}."' will be called instead of this method.");
15147 }
15148 elsif($CompatRules{$Level}{$Kind}{"Kind"} eq "Types")
15149 {
15150 if($Location eq "this" or $Kind=~/(\A|_)Virtual(_|\Z)/)
15151 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015152 my $METHOD_TYPE = $CompleteSignature{1}{$Symbol}{"Constructor"}?"constructor":"method";
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040015153 my $ClassName = $TypeInfo{1}{$CompleteSignature{1}{$Symbol}{"Class"}}{"Name"};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015154 if($ClassName eq $Problem{"Type_Name"}) {
15155 push(@Sentence, "This $METHOD_TYPE is from \'".$Problem{"Type_Name"}."\' class.");
15156 }
15157 else {
15158 push(@Sentence, "This $METHOD_TYPE is from derived class \'".$ClassName."\'.");
15159 }
15160 }
15161 else
15162 {
15163 if($Location=~/retval/)
15164 { # return value
15165 if($Location=~/\-\>/) {
15166 push(@Sentence, "Field \'".$Location."\' in return value");
15167 }
15168 else {
15169 push(@Sentence, "Return value");
15170 }
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040015171 if(my $Init = $Problem{"InitialType_Type"})
15172 {
15173 if($Init eq "Pointer") {
15174 push(@Sentence, "(pointer)");
15175 }
15176 elsif($Init eq "Ref") {
15177 push(@Sentence, "(reference)");
15178 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015179 }
15180 }
15181 elsif($Location=~/this/)
15182 { # "this" pointer
15183 if($Location=~/\-\>/) {
15184 push(@Sentence, "Field \'".$Location."\' in the object of this method");
15185 }
15186 else {
15187 push(@Sentence, "\'this\' pointer");
15188 }
15189 }
15190 else
15191 { # parameters
15192 if($Location=~/\-\>/) {
15193 push(@Sentence, "Field \'".$Location."\' in $PPos parameter");
15194 }
15195 else {
15196 push(@Sentence, "$PPos parameter");
15197 }
15198 if($Problem{"Param_Name"}) {
15199 push(@Sentence, "\'".$Problem{"Param_Name"}."\'");
15200 }
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040015201 if(my $Init = $Problem{"InitialType_Type"})
15202 {
15203 if($Init eq "Pointer") {
15204 push(@Sentence, "(pointer)");
15205 }
15206 elsif($Init eq "Ref") {
15207 push(@Sentence, "(reference)");
15208 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015209 }
15210 }
15211 if($Location eq "this") {
15212 push(@Sentence, "has base type \'".$Problem{"Type_Name"}."\'.");
15213 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040015214 elsif(defined $Problem{"Start_Type_Name"}
15215 and $Problem{"Start_Type_Name"} eq $Problem{"Type_Name"}) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015216 push(@Sentence, "has type \'".$Problem{"Type_Name"}."\'.");
15217 }
15218 else {
15219 push(@Sentence, "has base type \'".$Problem{"Type_Name"}."\'.");
15220 }
15221 }
15222 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040015223 if($ExtendedSymbols{$Symbol}) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015224 push(@Sentence, " This is a symbol from an artificial external library that may use the \'$TargetLibraryName\' library and change its ABI after recompiling.");
15225 }
15226 return join(" ", @Sentence);
15227}
15228
15229sub get_XmlSign($$)
15230{
15231 my ($Symbol, $LibVersion) = @_;
15232 my $Info = $CompleteSignature{$LibVersion}{$Symbol};
15233 my $Report = "";
15234 foreach my $Pos (sort {int($a)<=>int($b)} keys(%{$Info->{"Param"}}))
15235 {
15236 my $Name = $Info->{"Param"}{$Pos}{"name"};
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040015237 my $Type = $Info->{"Param"}{$Pos}{"type"};
15238 my $TypeName = $TypeInfo{$LibVersion}{$Type}{"Name"};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015239 foreach my $Typedef (keys(%ChangedTypedef))
15240 {
15241 my $Base = $Typedef_BaseName{$LibVersion}{$Typedef};
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040015242 $TypeName=~s/\b\Q$Typedef\E\b/$Base/g;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015243 }
15244 $Report .= " <param pos=\"$Pos\">\n";
15245 $Report .= " <name>".$Name."</name>\n";
15246 $Report .= " <type>".htmlSpecChars($TypeName)."</type>\n";
15247 $Report .= " </param>\n";
15248 }
15249 if(my $Return = $Info->{"Return"})
15250 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040015251 my $RTName = $TypeInfo{$LibVersion}{$Return}{"Name"};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015252 $Report .= " <retval>\n";
15253 $Report .= " <type>".htmlSpecChars($RTName)."</type>\n";
15254 $Report .= " </retval>\n";
15255 }
15256 return $Report;
15257}
15258
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015259sub get_Report_SymbolsInfo($)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015260{
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015261 my $Level = $_[0];
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015262 my $Report = "<symbols_info>\n";
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015263 foreach my $Symbol (sort keys(%{$CompatProblems{$Level}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015264 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015265 my ($SN, $SS, $SV) = separate_symbol($Symbol);
15266 if($SV and defined $CompatProblems{$Level}{$SN}) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015267 next;
15268 }
15269 $Report .= " <symbol name=\"$Symbol\">\n";
15270 my ($S1, $P1, $S2, $P2) = ();
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015271 if(not $AddedInt{$Level}{$Symbol})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015272 {
15273 if(defined $CompleteSignature{1}{$Symbol}
15274 and defined $CompleteSignature{1}{$Symbol}{"Header"})
15275 {
15276 $P1 = get_XmlSign($Symbol, 1);
15277 $S1 = get_Signature($Symbol, 1);
15278 }
15279 elsif($Symbol=~/\A(_Z|\?)/) {
15280 $S1 = $tr_name{$Symbol};
15281 }
15282 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015283 if(not $RemovedInt{$Level}{$Symbol})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015284 {
15285 if(defined $CompleteSignature{2}{$Symbol}
15286 and defined $CompleteSignature{2}{$Symbol}{"Header"})
15287 {
15288 $P2 = get_XmlSign($Symbol, 2);
15289 $S2 = get_Signature($Symbol, 2);
15290 }
15291 elsif($Symbol=~/\A(_Z|\?)/) {
15292 $S2 = $tr_name{$Symbol};
15293 }
15294 }
15295 if($S1)
15296 {
15297 $Report .= " <old signature=\"".htmlSpecChars($S1)."\">\n";
15298 $Report .= $P1;
15299 $Report .= " </old>\n";
15300 }
15301 if($S2 and $S2 ne $S1)
15302 {
15303 $Report .= " <new signature=\"".htmlSpecChars($S2)."\">\n";
15304 $Report .= $P2;
15305 $Report .= " </new>\n";
15306 }
15307 $Report .= " </symbol>\n";
15308 }
15309 $Report .= "</symbols_info>\n";
15310 return $Report;
15311}
15312
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015313sub writeReport($$)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015314{
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015315 my ($Level, $Report) = @_;
15316 if($ReportFormat eq "xml") {
15317 $Report = "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n".$Report;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015318 }
15319 if($StdOut)
15320 { # --stdout option
15321 print STDOUT $Report;
15322 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015323 else
15324 {
15325 my $RPath = getReportPath($Level);
Andrey Ponomarenko85043792012-05-14 16:48:07 +040015326 mkpath(get_dirname($RPath));
15327
15328 open(REPORT, ">", $RPath) || die ("can't open file \'$RPath\': $!\n");
15329 print REPORT $Report;
15330 close(REPORT);
15331
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040015332 if($Browse or $OpenReport)
15333 { # open in browser
15334 openReport($RPath);
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015335 if($JoinReport or $DoubleReport)
15336 {
15337 if($Level eq "Binary")
15338 { # wait to open a browser
15339 sleep(1);
15340 }
15341 }
15342 }
15343 }
15344}
15345
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040015346sub openReport($)
15347{
15348 my $Path = $_[0];
15349 my $Cmd = "";
15350 if($Browse)
15351 { # user-defined browser
Andrey Ponomarenkoa01311b2012-06-08 17:20:02 +040015352 $Cmd = $Browse." \"$Path\"";
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040015353 }
15354 if(not $Cmd)
15355 { # default browser
15356 if($OSgroup eq "macos") {
Andrey Ponomarenkoa01311b2012-06-08 17:20:02 +040015357 system("open \"$Path\"");
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040015358 }
15359 elsif($OSgroup eq "windows") {
Andrey Ponomarenkoa01311b2012-06-08 17:20:02 +040015360 system("start \"$Path\"");
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040015361 }
15362 else
15363 { # linux, freebsd, solaris
15364 my @Browsers = (
15365 "x-www-browser",
15366 "sensible-browser",
15367 "firefox",
15368 "opera",
15369 "xdg-open",
15370 "lynx",
15371 "links"
15372 );
15373 foreach my $Br (@Browsers)
15374 {
15375 if($Br = get_CmdPath($Br))
15376 {
Andrey Ponomarenkoa01311b2012-06-08 17:20:02 +040015377 $Cmd = $Br." \"$Path\"";
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040015378 last;
15379 }
15380 }
15381 }
15382 }
15383 if($Cmd)
15384 {
15385 if($Debug) {
15386 printMsg("INFO", "running $Cmd");
15387 }
15388 if($Cmd!~/lynx|links/) {
Andrey Ponomarenkoa01311b2012-06-08 17:20:02 +040015389 $Cmd .= " >\"$TMP_DIR/null\" 2>&1 &";
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040015390 }
15391 system($Cmd);
15392 }
15393 else {
15394 printMsg("ERROR", "cannot open report in browser");
15395 }
15396}
15397
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015398sub getReport($)
15399{
15400 my $Level = $_[0];
15401 if($ReportFormat eq "xml")
15402 { # XML
15403
15404 if($Level eq "Join")
15405 {
15406 my $Report = "<reports>\n";
15407 $Report .= getReport("Binary");
15408 $Report .= getReport("Source");
15409 $Report .= "</reports>\n";
15410 return $Report;
15411 }
15412 else
15413 {
15414 my $Report = "<report kind=\"".lc($Level)."\" version=\"$XML_REPORT_VERSION\">\n\n";
15415 my ($Summary, $MetaData) = get_Summary($Level);
15416 $Report .= $Summary."\n";
15417 $Report .= get_Report_Added($Level).get_Report_Removed($Level);
15418 $Report .= get_Report_Problems("High", $Level).get_Report_Problems("Medium", $Level).get_Report_Problems("Low", $Level).get_Report_Problems("Safe", $Level);
15419 $Report .= get_Report_SymbolsInfo($Level);
15420 $Report .= "</report>\n";
15421 return $Report;
15422 }
15423 }
15424 else
15425 { # HTML
15426 my $CssStyles = readModule("Styles", "Report.css");
15427 my $JScripts = readModule("Scripts", "Sections.js");
15428 if($Level eq "Join")
15429 {
15430 $CssStyles .= "\n".readModule("Styles", "Tabs.css");
15431 $JScripts .= "\n".readModule("Scripts", "Tabs.js");
Andrey Ponomarenkob8d203d2012-05-25 18:11:07 +040015432 my $Title = $TargetLibraryFName.": ".$Descriptor{1}{"Version"}." to ".$Descriptor{2}{"Version"}." compatibility report";
15433 my $Keywords = $TargetLibraryFName.", compatibility, API, report";
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015434 my $Description = "Compatibility report for the $TargetLibraryFName $TargetComponent between ".$Descriptor{1}{"Version"}." and ".$Descriptor{2}{"Version"}." versions";
15435 my ($BSummary, $BMetaData) = get_Summary("Binary");
15436 my ($SSummary, $SMetaData) = get_Summary("Source");
15437 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>";
15438 $Report .= get_Report_Header("Join")."
15439 <br/><div class='tabset'>
Andrey Ponomarenko16934472012-03-29 15:37:04 +040015440 <a id='BinaryID' href='#BinaryTab' class='tab active'>Binary<br/>Compatibility</a>
15441 <a id='SourceID' href='#SourceTab' style='margin-left:3px' class='tab disabled'>Source<br/>Compatibility</a>
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015442 </div>";
15443 $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>";
15444 $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>";
15445 $Report .= getReportFooter($TargetLibraryFName);
15446 $Report .= "\n<div style='height:999px;'></div>\n</body></html>";
15447 return $Report;
15448 }
15449 else
15450 {
15451 my ($Summary, $MetaData) = get_Summary($Level);
Andrey Ponomarenkob8d203d2012-05-25 18:11:07 +040015452 my $Title = $TargetLibraryFName.": ".$Descriptor{1}{"Version"}." to ".$Descriptor{2}{"Version"}." ".lc($Level)." compatibility report";
15453 my $Keywords = $TargetLibraryFName.", ".lc($Level)." compatibility, API, report";
15454 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 +040015455 if($Level eq "Binary")
15456 {
15457 if(getArch(1) eq getArch(2)
15458 and getArch(1) ne "unknown") {
15459 $Description .= " on ".showArch(getArch(1));
15460 }
15461 }
15462 my $Report = "<!-\- $MetaData -\->\n".composeHTML_Head($Title, $Keywords, $Description, $CssStyles, $JScripts)."\n<body>\n<div><a name='Top'></a>\n";
15463 $Report .= get_Report_Header($Level)."\n".$Summary."\n";
15464 $Report .= get_Report_Added($Level).get_Report_Removed($Level);
15465 $Report .= get_Report_Problems("High", $Level).get_Report_Problems("Medium", $Level).get_Report_Problems("Low", $Level).get_Report_Problems("Safe", $Level);
15466 $Report .= get_SourceInfo();
15467 $Report .= "</div>\n<br/><br/><br/><hr/>\n";
15468 $Report .= getReportFooter($TargetLibraryFName);
15469 $Report .= "\n<div style='height:999px;'></div>\n</body></html>";
15470 return $Report;
15471 }
15472 }
15473}
15474
Andrey Ponomarenko16934472012-03-29 15:37:04 +040015475sub getLegend()
15476{
15477 return "<br/>
15478<table class='summary'>
15479<tr>
15480 <td class='new'>added</td>
15481 <td class='passed'>compatible</td>
15482</tr>
15483<tr>
15484 <td class='warning'>warning</td>
15485 <td class='failed'>incompatible</td>
15486</tr></table>\n";
15487}
15488
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015489sub createReport()
15490{
15491 if($JoinReport)
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040015492 { # --stdout
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015493 writeReport("Join", getReport("Join"));
15494 }
15495 elsif($DoubleReport)
15496 { # default
15497 writeReport("Binary", getReport("Binary"));
15498 writeReport("Source", getReport("Source"));
15499 }
15500 elsif($BinaryOnly)
15501 { # --binary
15502 writeReport("Binary", getReport("Binary"));
15503 }
15504 elsif($SourceOnly)
15505 { # --source
15506 writeReport("Source", getReport("Source"));
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015507 }
15508}
15509
15510sub getReportFooter($)
15511{
15512 my $LibName = $_[0];
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015513 my $FooterStyle = (not $JoinReport)?"width:99%":"width:97%;padding-top:3px";
15514 my $Footer = "<div style='$FooterStyle;font-size:11px;' align='right'><i>Generated on ".(localtime time); # report date
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015515 $Footer .= " for <span style='font-weight:bold'>$LibName</span>"; # tested library/system name
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015516 $Footer .= " by <a href='".$HomePage{"Wiki"}."'>ABI Compliance Checker</a>"; # tool name
15517 my $ToolSummary = "<br/>A tool for checking backward compatibility of a C/C++ library API&#160;&#160;";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015518 $Footer .= " $TOOL_VERSION &#160;$ToolSummary</i></div>"; # tool version
15519 return $Footer;
15520}
15521
15522sub get_Report_Problems($$)
15523{
15524 my ($Priority, $Level) = @_;
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040015525 my $Report = get_Report_TypeProblems($Priority, $Level);
Andrey Ponomarenko16934472012-03-29 15:37:04 +040015526 if(my $SProblems = get_Report_SymbolProblems($Priority, $Level)) {
15527 $Report .= $SProblems;
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040015528 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015529 if($Priority eq "Low")
15530 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015531 $Report .= get_Report_ChangedConstants($Level);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015532 if($ReportFormat eq "html") {
15533 if($CheckImpl and $Level eq "Binary") {
15534 $Report .= get_Report_Impl();
15535 }
15536 }
15537 }
15538 if($ReportFormat eq "html")
15539 {
15540 if($Report)
15541 { # add anchor
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015542 if($JoinReport)
15543 {
15544 if($Priority eq "Safe") {
15545 $Report = "<a name=\'Other_".$Level."_Changes\'></a>".$Report;
15546 }
15547 else {
15548 $Report = "<a name=\'".$Priority."_Risk_".$Level."_Problems\'></a>".$Report;
15549 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015550 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015551 else
15552 {
15553 if($Priority eq "Safe") {
15554 $Report = "<a name=\'Other_Changes\'></a>".$Report;
15555 }
15556 else {
15557 $Report = "<a name=\'".$Priority."_Risk_Problems\'></a>".$Report;
15558 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015559 }
15560 }
15561 }
15562 return $Report;
15563}
15564
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015565sub composeHTML_Head($$$$$)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015566{
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015567 my ($Title, $Keywords, $Description, $Styles, $Scripts) = @_;
15568 return "<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.0 Transitional//EN\" \"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd\">
15569 <html xmlns=\"http://www.w3.org/1999/xhtml\" xml:lang=\"en\" lang=\"en\">
15570 <head>
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015571 <meta http-equiv=\"Content-Type\" content=\"text/html; charset=utf-8\" />
15572 <meta name=\"keywords\" content=\"$Keywords\" />
15573 <meta name=\"description\" content=\"$Description\" />
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015574 <title>
15575 $Title
15576 </title>
15577 <style type=\"text/css\">
15578 $Styles
15579 </style>
15580 <script type=\"text/javascript\" language=\"JavaScript\">
15581 <!--
15582 $Scripts
15583 -->
15584 </script>
15585 </head>";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015586}
15587
15588sub insertIDs($)
15589{
15590 my $Text = $_[0];
15591 while($Text=~/CONTENT_ID/)
15592 {
15593 if(int($Content_Counter)%2) {
15594 $ContentID -= 1;
15595 }
15596 $Text=~s/CONTENT_ID/c_$ContentID/;
15597 $ContentID += 1;
15598 $Content_Counter += 1;
15599 }
15600 return $Text;
15601}
15602
15603sub checkPreprocessedUnit($)
15604{
15605 my $Path = $_[0];
Andrey Ponomarenkoa01311b2012-06-08 17:20:02 +040015606 my ($CurHeader, $CurHeaderName) = ("", "");
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015607 open(PREPROC, $Path) || die ("can't open file \'$Path\': $!\n");
Andrey Ponomarenkoa01311b2012-06-08 17:20:02 +040015608 while(my $Line = <PREPROC>)
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015609 { # detecting public and private constants
Andrey Ponomarenkoa01311b2012-06-08 17:20:02 +040015610
15611 if(substr($Line, 0, 1) eq "#")
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015612 {
Andrey Ponomarenkoa01311b2012-06-08 17:20:02 +040015613 chomp($Line);
15614 if($Line=~/\A\#\s+\d+\s+\"(.+)\"/)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015615 {
Andrey Ponomarenkoa01311b2012-06-08 17:20:02 +040015616 $CurHeader = path_format($1, $OSgroup);
15617 $CurHeaderName = get_filename($CurHeader);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015618 }
Andrey Ponomarenkoa01311b2012-06-08 17:20:02 +040015619 if(not $Include_Neighbors{$Version}{$CurHeaderName}
15620 and not $Registered_Headers{$Version}{$CurHeader})
15621 { # not a target
15622 next;
15623 }
15624 if(not is_target_header($CurHeaderName, 1)
15625 and not is_target_header($CurHeaderName, 2))
15626 { # user-defined header
15627 next;
15628 }
15629 if($Line=~/\A\#\s*define\s+([_A-Z0-9]+)\s+(.+)\s*\Z/)
15630 {
15631 my ($Name, $Value) = ($1, $2);
15632 if(not $Constants{$Version}{$Name}{"Access"})
15633 {
15634 $Constants{$Version}{$Name}{"Access"} = "public";
15635 $Constants{$Version}{$Name}{"Value"} = $Value;
15636 $Constants{$Version}{$Name}{"Header"} = $CurHeaderName;
15637 }
15638 }
15639 elsif($Line=~/\A\#[ \t]*undef[ \t]+([_A-Z]+)[ \t]*/) {
15640 $Constants{$Version}{$1}{"Access"} = "private";
15641 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015642 }
15643 }
15644 close(PREPROC);
15645 foreach my $Constant (keys(%{$Constants{$Version}}))
15646 {
Andrey Ponomarenkoa01311b2012-06-08 17:20:02 +040015647 if($Constants{$Version}{$Constant}{"Access"} eq "private"
15648 or $Constant=~/_h\Z/i
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015649 or isBuiltIn($Constants{$Version}{$Constant}{"Header"}))
15650 { # skip private constants
15651 delete($Constants{$Version}{$Constant});
15652 }
15653 else {
15654 delete($Constants{$Version}{$Constant}{"Access"});
15655 }
15656 }
Andrey Ponomarenkoa01311b2012-06-08 17:20:02 +040015657 if($Debug)
15658 {
15659 mkpath($DEBUG_PATH{$Version});
15660 copy($Path, $DEBUG_PATH{$Version}."/preprocessor.txt");
15661 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015662}
15663
Andrey Ponomarenko16934472012-03-29 15:37:04 +040015664sub uncoverConstant($$)
15665{
15666 my ($LibVersion, $Constant) = @_;
15667 return "" if(not $LibVersion or not $Constant);
15668 return $Constant if(isCyclical(\@RecurConstant, $Constant));
15669 if(defined $Cache{"uncoverConstant"}{$LibVersion}{$Constant}) {
15670 return $Cache{"uncoverConstant"}{$LibVersion}{$Constant};
15671 }
15672 my $Value = $Constants{$LibVersion}{$Constant}{"Value"};
15673 if(defined $Value)
15674 {
15675 if($Value=~/\A[A-Z0-9_]+\Z/ and $Value=~/[A-Z]/)
15676 {
15677 push(@RecurConstant, $Constant);
15678 my $Uncovered = uncoverConstant($LibVersion, $Value);
15679 if($Uncovered ne "") {
15680 $Value = $Uncovered;
15681 }
15682 pop(@RecurConstant);
15683 }
15684 # FIXME: uncover $Value using all the enum constants
15685 # USECASE: change of define NC_LONG from NC_INT (enum value) to NC_INT (define)
15686 return ($Cache{"uncoverConstant"}{$LibVersion}{$Constant} = $Value);
15687 }
15688 return ($Cache{"uncoverConstant"}{$LibVersion}{$Constant} = "");
15689}
15690
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015691my %IgnoreConstant=(
15692 "VERSION"=>1,
15693 "VERSIONCODE"=>1,
15694 "VERNUM"=>1,
15695 "VERS_INFO"=>1,
15696 "PATCHLEVEL"=>1,
15697 "INSTALLPREFIX"=>1,
15698 "VBUILD"=>1,
15699 "VPATCH"=>1,
15700 "VMINOR"=>1,
15701 "BUILD_STRING"=>1,
15702 "BUILD_TIME"=>1,
15703 "PACKAGE_STRING"=>1,
15704 "PRODUCTION"=>1,
15705 "CONFIGURE_COMMAND"=>1,
15706 "INSTALLDIR"=>1,
15707 "BINDIR"=>1,
15708 "CONFIG_FILE_PATH"=>1,
15709 "DATADIR"=>1,
15710 "EXTENSION_DIR"=>1,
15711 "INCLUDE_PATH"=>1,
15712 "LIBDIR"=>1,
15713 "LOCALSTATEDIR"=>1,
15714 "SBINDIR"=>1,
15715 "SYSCONFDIR"=>1,
15716 "RELEASE"=>1,
15717 "SOURCE_ID"=>1,
15718 "SUBMINOR"=>1,
15719 "MINOR"=>1,
15720 "MINNOR"=>1,
15721 "MINORVERSION"=>1,
15722 "MAJOR"=>1,
15723 "MAJORVERSION"=>1,
15724 "MICRO"=>1,
15725 "MICROVERSION"=>1,
15726 "BINARY_AGE"=>1,
15727 "INTERFACE_AGE"=>1,
15728 "CORE_ABI"=>1,
15729 "PATCH"=>1,
15730 "COPYRIGHT"=>1,
15731 "TIMESTAMP"=>1,
15732 "REVISION"=>1,
15733 "PACKAGE_TAG"=>1,
15734 "PACKAGEDATE"=>1,
15735 "NUMVERSION"=>1
15736);
15737
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015738sub mergeConstants($)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015739{
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015740 my $Level = $_[0];
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015741 foreach my $Constant (keys(%{$Constants{1}}))
15742 {
15743 if($SkipConstants{1}{$Constant})
15744 { # skipped by the user
15745 next;
15746 }
Andrey Ponomarenko16934472012-03-29 15:37:04 +040015747 if(not defined $Constants{2}{$Constant}{"Value"}
15748 or $Constants{2}{$Constant}{"Value"} eq "")
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015749 { # empty value
15750 next;
15751 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +040015752 my $Header = $Constants{1}{$Constant}{"Header"};
15753 if(not is_target_header($Header, 1)
15754 and not is_target_header($Header, 2))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015755 { # user-defined header
15756 next;
15757 }
15758 my ($Old_Value, $New_Value, $Old_Value_Pure, $New_Value_Pure);
Andrey Ponomarenko16934472012-03-29 15:37:04 +040015759 $Old_Value = $Old_Value_Pure = uncoverConstant(1, $Constant);
15760 $New_Value = $New_Value_Pure = uncoverConstant(2, $Constant);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015761 $Old_Value_Pure=~s/(\W)\s+/$1/g;
15762 $Old_Value_Pure=~s/\s+(\W)/$1/g;
15763 $New_Value_Pure=~s/(\W)\s+/$1/g;
15764 $New_Value_Pure=~s/\s+(\W)/$1/g;
15765 next if($New_Value_Pure eq "" or $Old_Value_Pure eq "");
15766 if($New_Value_Pure ne $Old_Value_Pure)
15767 { # different values
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015768 if($Level eq "Binary")
15769 {
15770 if(grep {$Constant=~/(\A|_)$_(_|\Z)/} keys(%IgnoreConstant))
15771 { # ignore library version
15772 next;
15773 }
15774 if($Constant=~/(\A|_)(lib|open|)$TargetLibraryShortName(_|)(VERSION|VER|DATE|API|PREFIX)(_|\Z)/i)
15775 { # ignore library version
15776 next;
15777 }
15778 if($Old_Value=~/\A('|"|)[\/\\]\w+([\/\\]|:|('|"|)\Z)/ or $Old_Value=~/[\/\\]\w+[\/\\]\w+/)
15779 { # ignoring path defines:
Andrey Ponomarenko85043792012-05-14 16:48:07 +040015780 # /lib64:/usr/lib64:/lib:/usr/lib:/usr/X11R6/lib/Xaw3d ...
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015781 next;
15782 }
15783 if($Old_Value=~/\A\(*[a-z_]+(\s+|\|)/i)
15784 { # ignore source defines:
Andrey Ponomarenko85043792012-05-14 16:48:07 +040015785 # static int gcry_pth_init ( void) { return ...
15786 # (RE_BACKSLASH_ESCAPE_IN_LISTS | RE...
15787 next;
15788 }
15789 if($Old_Value=~/\(/i and $Old_Value!~/[\"\']/i)
15790 { # ignore source defines:
15791 # foo(p)
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015792 next;
15793 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015794 }
15795 if(convert_integer($Old_Value) eq convert_integer($New_Value))
15796 { # 0x0001 and 0x1, 0x1 and 1 equal constants
15797 next;
15798 }
15799 if($Old_Value eq "0" and $New_Value eq "NULL")
15800 { # 0 => NULL
15801 next;
15802 }
15803 if($Old_Value eq "NULL" and $New_Value eq "0")
15804 { # NULL => 0
15805 next;
15806 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015807 %{$ProblemsWithConstants{$Level}{$Constant}} = (
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015808 "Target"=>$Constant,
15809 "Old_Value"=>$Old_Value,
15810 "New_Value"=>$New_Value );
15811 }
15812 }
15813}
15814
15815sub convert_integer($)
15816{
15817 my $Value = $_[0];
15818 if($Value=~/\A0x[a-f0-9]+\Z/)
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015819 { # hexadecimal
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015820 return hex($Value);
15821 }
15822 elsif($Value=~/\A0[0-7]+\Z/)
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015823 { # octal
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015824 return oct($Value);
15825 }
15826 elsif($Value=~/\A0b[0-1]+\Z/)
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015827 { # binary
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015828 return oct($Value);
15829 }
15830 else {
15831 return $Value;
15832 }
15833}
15834
Andrey Ponomarenko16934472012-03-29 15:37:04 +040015835sub readSymbols($)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015836{
15837 my $LibVersion = $_[0];
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040015838 my @LibPaths = getSOPaths($LibVersion);
Andrey Ponomarenko16934472012-03-29 15:37:04 +040015839 if($#LibPaths==-1 and not $CheckHeadersOnly)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015840 {
15841 if($LibVersion==1)
15842 {
15843 printMsg("WARNING", "checking headers only");
15844 $CheckHeadersOnly = 1;
15845 }
15846 else {
15847 exitStatus("Error", "$SLIB_TYPE libraries are not found in ".$Descriptor{$LibVersion}{"Version"});
15848 }
15849 }
Andrey Ponomarenko16934472012-03-29 15:37:04 +040015850 my %GroupNames = map {parse_libname(get_filename($_), "name+ext", $OStarget)=>1} @LibPaths;
15851 foreach my $LibPath (sort {length($a)<=>length($b)} @LibPaths) {
15852 readSymbols_Lib($LibVersion, $LibPath, 0, \%GroupNames, "+Weak");
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015853 }
Andrey Ponomarenko16934472012-03-29 15:37:04 +040015854 if(not $CheckHeadersOnly)
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040015855 {
Andrey Ponomarenko16934472012-03-29 15:37:04 +040015856 if($#LibPaths!=-1)
15857 {
15858 if(not keys(%{$Symbol_Library{$LibVersion}}))
15859 {
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040015860 printMsg("WARNING", "the set of public symbols in library(ies) is empty ($LibVersion)");
Andrey Ponomarenko16934472012-03-29 15:37:04 +040015861 printMsg("WARNING", "checking headers only");
15862 $CheckHeadersOnly = 1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015863 }
15864 }
15865 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +040015866
15867 # clean memory
15868 %SystemObjects = ();
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015869}
15870
Andrey Ponomarenko16934472012-03-29 15:37:04 +040015871sub getSymbolSize($$)
15872{ # size from the shared library
15873 my ($Symbol, $LibVersion) = @_;
15874 return 0 if(not $Symbol);
15875 if(defined $Symbol_Library{$LibVersion}{$Symbol}
15876 and my $LibName = $Symbol_Library{$LibVersion}{$Symbol})
15877 {
15878 if(defined $Library_Symbol{$LibVersion}{$LibName}{$Symbol}
15879 and my $Size = $Library_Symbol{$LibVersion}{$LibName}{$Symbol})
15880 {
15881 if($Size<0) {
15882 return -$Size;
15883 }
15884 }
15885 }
15886 return 0;
15887}
15888
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015889sub canonifyName($)
15890{ # make TIFFStreamOpen(char const*, std::basic_ostream<char, std::char_traits<char> >*)
15891 # to be TIFFStreamOpen(char const*, std::basic_ostream<char>*)
15892 my $Name = $_[0];
15893 my $Rem = "std::(allocator|less|char_traits|regex_traits)";
Andrey Ponomarenko85043792012-05-14 16:48:07 +040015894 while($Name=~/([^<>,]+),\s*$Rem<([^<>,]+)>\s*/ and $1 eq $3)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015895 {
Andrey Ponomarenko85043792012-05-14 16:48:07 +040015896 my $P = $1;
15897 $Name=~s/\Q$P\E,\s*$Rem<\Q$P\E>\s*/$P/g;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015898 }
15899 return $Name;
15900}
15901
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040015902sub translateSymbols(@)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015903{
15904 my $LibVersion = pop(@_);
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040015905 my (@MnglNames1, @MnglNames2, @UnmangledNames) = ();
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015906 foreach my $Interface (sort @_)
15907 {
15908 if($Interface=~/\A_Z/)
15909 {
15910 next if($tr_name{$Interface});
15911 $Interface=~s/[\@\$]+(.*)\Z//;
15912 push(@MnglNames1, $Interface);
15913 }
15914 elsif($Interface=~/\A\?/) {
15915 push(@MnglNames2, $Interface);
15916 }
15917 else
15918 { # not mangled
15919 $tr_name{$Interface} = $Interface;
15920 $mangled_name_gcc{$Interface} = $Interface;
15921 $mangled_name{$LibVersion}{$Interface} = $Interface;
15922 }
15923 }
15924 if($#MnglNames1 > -1)
15925 { # GCC names
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040015926 @UnmangledNames = reverse(unmangleArray(@MnglNames1));
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015927 foreach my $MnglName (@MnglNames1)
15928 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040015929 if(my $Unmangled = pop(@UnmangledNames))
15930 {
15931 $tr_name{$MnglName} = formatName(canonifyName($Unmangled));
15932 if(not $mangled_name_gcc{$tr_name{$MnglName}}) {
15933 $mangled_name_gcc{$tr_name{$MnglName}} = $MnglName;
15934 }
15935 if($MnglName=~/\A_ZTV/
15936 and $tr_name{$MnglName}=~/vtable for (.+)/)
15937 { # bind class name and v-table symbol
15938 my $ClassName = $1;
15939 $ClassVTable{$ClassName} = $MnglName;
15940 $VTableClass{$MnglName} = $ClassName;
15941 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015942 }
15943 }
15944 }
15945 if($#MnglNames2 > -1)
15946 { # MSVC names
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040015947 @UnmangledNames = reverse(unmangleArray(@MnglNames2));
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015948 foreach my $MnglName (@MnglNames2)
15949 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040015950 if(my $Unmangled = pop(@UnmangledNames))
15951 {
15952 $tr_name{$MnglName} = formatName($Unmangled);
15953 $mangled_name{$LibVersion}{$tr_name{$MnglName}} = $MnglName;
15954 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015955 }
15956 }
15957 return \%tr_name;
15958}
15959
15960sub link_symbol($$$)
15961{
15962 my ($Symbol, $RunWith, $Deps) = @_;
15963 if(link_symbol_internal($Symbol, $RunWith, \%Symbol_Library)) {
15964 return 1;
15965 }
15966 if($Deps eq "+Deps")
15967 { # check the dependencies
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040015968 if(link_symbol_internal($Symbol, $RunWith, \%DepSymbol_Library)) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015969 return 1;
15970 }
15971 }
15972 return 0;
15973}
15974
15975sub link_symbol_internal($$$)
15976{
15977 my ($Symbol, $RunWith, $Where) = @_;
15978 return 0 if(not $Where or not $Symbol);
15979 if($Where->{$RunWith}{$Symbol})
15980 { # the exact match by symbol name
15981 return 1;
15982 }
15983 if(my $VSym = $SymVer{$RunWith}{$Symbol})
15984 { # indirect symbol version, i.e.
15985 # foo_old and its symlink foo@v (or foo@@v)
15986 # foo_old may be in .symtab table
15987 if($Where->{$RunWith}{$VSym}) {
15988 return 1;
15989 }
15990 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015991 my ($Sym, $Spec, $Ver) = separate_symbol($Symbol);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015992 if($Sym and $Ver)
15993 { # search for the symbol with the same version
15994 # or without version
15995 if($Where->{$RunWith}{$Sym})
15996 { # old: foo@v|foo@@v
15997 # new: foo
15998 return 1;
15999 }
16000 if($Where->{$RunWith}{$Sym."\@".$Ver})
16001 { # old: foo|foo@@v
16002 # new: foo@v
16003 return 1;
16004 }
16005 if($Where->{$RunWith}{$Sym."\@\@".$Ver})
16006 { # old: foo|foo@v
16007 # new: foo@@v
16008 return 1;
16009 }
16010 }
16011 return 0;
16012}
16013
Andrey Ponomarenko16934472012-03-29 15:37:04 +040016014sub readSymbols_App($)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040016015{
16016 my $Path = $_[0];
16017 return () if(not $Path or not -f $Path);
16018 my @Imported = ();
16019 if($OSgroup eq "macos")
16020 {
16021 my $OtoolCmd = get_CmdPath("otool");
16022 if(not $OtoolCmd) {
16023 exitStatus("Not_Found", "can't find \"otool\"");
16024 }
Andrey Ponomarenkoa01311b2012-06-08 17:20:02 +040016025 open(APP, "$OtoolCmd -IV \"$Path\" 2>\"$TMP_DIR/null\" |");
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040016026 while(<APP>) {
16027 if(/[^_]+\s+_?([\w\$]+)\s*\Z/) {
16028 push(@Imported, $1);
16029 }
16030 }
16031 close(APP);
16032 }
16033 elsif($OSgroup eq "windows")
16034 {
16035 my $DumpBinCmd = get_CmdPath("dumpbin");
16036 if(not $DumpBinCmd) {
16037 exitStatus("Not_Found", "can't find \"dumpbin.exe\"");
16038 }
Andrey Ponomarenkoa01311b2012-06-08 17:20:02 +040016039 open(APP, "$DumpBinCmd /IMPORTS \"$Path\" 2>\"$TMP_DIR/null\" |");
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040016040 while(<APP>) {
16041 if(/\s*\w+\s+\w+\s+\w+\s+([\w\?\@]+)\s*/) {
16042 push(@Imported, $1);
16043 }
16044 }
16045 close(APP);
16046 }
16047 else
16048 {
16049 my $ReadelfCmd = get_CmdPath("readelf");
16050 if(not $ReadelfCmd) {
16051 exitStatus("Not_Found", "can't find \"readelf\"");
16052 }
Andrey Ponomarenkoa01311b2012-06-08 17:20:02 +040016053 open(APP, "$ReadelfCmd -WhlSsdA \"$Path\" 2>\"$TMP_DIR/null\" |");
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040016054 my $symtab=0; # indicates that we are processing 'symtab' section of 'readelf' output
16055 while(<APP>)
16056 {
16057 if( /'.dynsym'/ ) {
16058 $symtab=0;
16059 }
16060 elsif($symtab == 1) {
16061 # do nothing with symtab (but there are some plans for the future)
16062 next;
16063 }
16064 elsif( /'.symtab'/ ) {
16065 $symtab=1;
16066 }
16067 elsif(my ($fullname, $idx, $Ndx, $type, $size, $bind) = readline_ELF($_))
16068 {
16069 if( $Ndx eq "UND" ) {
16070 #only imported symbols
16071 push(@Imported, $fullname);
16072 }
16073 }
16074 }
16075 close(APP);
16076 }
16077 return @Imported;
16078}
16079
16080sub readline_ELF($)
16081{
16082 if($_[0]=~/\s*\d+:\s+(\w*)\s+(\w+)\s+(\w+)\s+(\w+)\s+(\w+)\s+(\w+)\s([^\s]+)/)
16083 { # the line of 'readelf' output corresponding to the interface
16084 # symbian-style: _ZN12CCTTokenType4NewLE4TUid3RFs@@ctfinder{000a0000}[102020e5].dll
16085 my ($value, $size, $type, $bind,
16086 $vis, $Ndx, $fullname)=($1, $2, $3, $4, $5, $6, $7);
16087 if($bind!~/\A(WEAK|GLOBAL)\Z/) {
16088 return ();
16089 }
16090 if($type!~/\A(FUNC|IFUNC|OBJECT|COMMON)\Z/) {
16091 return ();
16092 }
16093 if($vis!~/\A(DEFAULT|PROTECTED)\Z/) {
16094 return ();
16095 }
16096 if($Ndx eq "ABS" and $value!~/\D|1|2|3|4|5|6|7|8|9/) {
16097 return ();
16098 }
16099 if($OStarget eq "symbian")
16100 {
16101 if($fullname=~/_\._\.absent_export_\d+/)
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040016102 { # "_._.absent_export_111"@@libstdcpp{00010001}[10282872].dll
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040016103 return ();
16104 }
16105 my @Elems = separate_symbol($fullname);
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040016106 $fullname = $Elems[0]; # remove internal version, {00020001}[10011235].dll
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040016107 }
Andrey Ponomarenkoa01311b2012-06-08 17:20:02 +040016108 if(index($size, "0x")!=-1)
16109 { # 0x3d158
16110 $size = hex($size);
16111 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040016112 return ($fullname, $value, $Ndx, $type, $size, $bind);
16113 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040016114 return ();
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040016115}
16116
Andrey Ponomarenko16934472012-03-29 15:37:04 +040016117sub read_symlink($)
16118{
16119 my $Path = $_[0];
16120 return "" if(not $Path);
16121 return "" if(not -f $Path and not -l $Path);
16122 if(defined $Cache{"read_symlink"}{$Path}) {
16123 return $Cache{"read_symlink"}{$Path};
16124 }
16125 if(my $Res = readlink($Path)) {
16126 return ($Cache{"read_symlink"}{$Path} = $Res);
16127 }
16128 elsif(my $ReadlinkCmd = get_CmdPath("readlink")) {
Andrey Ponomarenkoa01311b2012-06-08 17:20:02 +040016129 return ($Cache{"read_symlink"}{$Path} = `$ReadlinkCmd -n \"$Path\"`);
Andrey Ponomarenko16934472012-03-29 15:37:04 +040016130 }
16131 elsif(my $FileCmd = get_CmdPath("file"))
16132 {
Andrey Ponomarenkoa01311b2012-06-08 17:20:02 +040016133 my $Info = `$FileCmd \"$Path\"`;
Andrey Ponomarenko16934472012-03-29 15:37:04 +040016134 if($Info=~/symbolic\s+link\s+to\s+['`"]*([\w\d\.\-\/\\]+)['`"]*/i) {
16135 return ($Cache{"read_symlink"}{$Path} = $1);
16136 }
16137 }
16138 return ($Cache{"read_symlink"}{$Path} = "");
16139}
16140
16141sub resolve_symlink($)
16142{
16143 my $Path = $_[0];
16144 return "" if(not $Path);
16145 return "" if(not -f $Path and not -l $Path);
16146 if(defined $Cache{"resolve_symlink"}{$Path}) {
16147 return $Cache{"resolve_symlink"}{$Path};
16148 }
16149 return $Path if(isCyclical(\@RecurSymlink, $Path));
16150 push(@RecurSymlink, $Path);
16151 if(-l $Path and my $Redirect=read_symlink($Path))
16152 {
16153 if(is_abs($Redirect))
16154 { # absolute path
16155 if($SystemRoot and $SystemRoot ne "/"
16156 and $Path=~/\A\Q$SystemRoot\E\//
16157 and (-f $SystemRoot.$Redirect or -l $SystemRoot.$Redirect))
16158 { # symbolic links from the sysroot
16159 # should be corrected to point to
16160 # the files inside sysroot
16161 $Redirect = $SystemRoot.$Redirect;
16162 }
16163 my $Res = resolve_symlink($Redirect);
16164 pop(@RecurSymlink);
16165 return ($Cache{"resolve_symlink"}{$Path} = $Res);
16166 }
16167 elsif($Redirect=~/\.\.[\/\\]/)
16168 { # relative path
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040016169 $Redirect = joinPath(get_dirname($Path), $Redirect);
Andrey Ponomarenko16934472012-03-29 15:37:04 +040016170 while($Redirect=~s&(/|\\)[^\/\\]+(\/|\\)\.\.(\/|\\)&$1&){};
16171 my $Res = resolve_symlink($Redirect);
16172 pop(@RecurSymlink);
16173 return ($Cache{"resolve_symlink"}{$Path} = $Res);
16174 }
16175 elsif(-f get_dirname($Path)."/".$Redirect)
16176 { # file name in the same directory
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040016177 my $Res = resolve_symlink(joinPath(get_dirname($Path), $Redirect));
Andrey Ponomarenko16934472012-03-29 15:37:04 +040016178 pop(@RecurSymlink);
16179 return ($Cache{"resolve_symlink"}{$Path} = $Res);
16180 }
16181 else
16182 { # broken link
16183 pop(@RecurSymlink);
16184 return ($Cache{"resolve_symlink"}{$Path} = "");
16185 }
16186 }
16187 pop(@RecurSymlink);
16188 return ($Cache{"resolve_symlink"}{$Path} = $Path);
16189}
16190
16191sub find_lib_path($$)
16192{
16193 my ($LibVersion, $DyLib) = @_;
16194 return "" if(not $DyLib or not $LibVersion);
16195 return $DyLib if(is_abs($DyLib));
16196 if(defined $Cache{"find_lib_path"}{$LibVersion}{$DyLib}) {
16197 return $Cache{"find_lib_path"}{$LibVersion}{$DyLib};
16198 }
16199 if(my @Paths = sort keys(%{$InputObject_Paths{$LibVersion}{$DyLib}})) {
16200 return ($Cache{"find_lib_path"}{$LibVersion}{$DyLib} = $Paths[0]);
16201 }
16202 elsif(my $DefaultPath = $DyLib_DefaultPath{$DyLib}) {
16203 return ($Cache{"find_lib_path"}{$LibVersion}{$DyLib} = $DefaultPath);
16204 }
16205 else
16206 {
16207 foreach my $Dir (sort keys(%DefaultLibPaths), sort keys(%{$SystemPaths{"lib"}}))
16208 { # search in default linker paths and then in all system paths
16209 if(-f $Dir."/".$DyLib) {
16210 return ($Cache{"find_lib_path"}{$LibVersion}{$DyLib} = joinPath($Dir,$DyLib));
16211 }
16212 }
16213 detectSystemObjects() if(not keys(%SystemObjects));
16214 if(my @AllObjects = keys(%{$SystemObjects{$DyLib}})) {
16215 return ($Cache{"find_lib_path"}{$LibVersion}{$DyLib} = $AllObjects[0]);
16216 }
16217 my $ShortName = parse_libname($DyLib, "name+ext", $OStarget);
16218 if($ShortName ne $DyLib
16219 and my $Path = find_lib_path($ShortName))
16220 { # FIXME: check this case
16221 return ($Cache{"find_lib_path"}{$LibVersion}{$DyLib} = $Path);
16222 }
16223 return ($Cache{"find_lib_path"}{$LibVersion}{$DyLib} = "");
16224 }
16225}
16226
16227sub readSymbols_Lib($$$$$)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040016228{
16229 my ($LibVersion, $Lib_Path, $IsNeededLib, $GroupNames, $Weak) = @_;
16230 return if(not $Lib_Path or not -f $Lib_Path);
16231 my ($Lib_Dir, $Lib_Name) = separate_path(resolve_symlink($Lib_Path));
16232 return if($CheckedDyLib{$LibVersion}{$Lib_Name} and $IsNeededLib);
16233 return if(isCyclical(\@RecurLib, $Lib_Name) or $#RecurLib>=1);
16234 $CheckedDyLib{$LibVersion}{$Lib_Name} = 1;
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040016235 my $Lib_SName = parse_libname($Lib_Name, "name+ext", $OStarget);
16236
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040016237 if($CheckImpl and not $IsNeededLib) {
16238 getImplementations($LibVersion, $Lib_Path);
16239 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040016240
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040016241 push(@RecurLib, $Lib_Name);
16242 my (%Value_Interface, %Interface_Value, %NeededLib) = ();
16243 if(not $IsNeededLib)
16244 { # libstdc++ and libc are always used by other libs
16245 # if you test one of these libs then you not need
16246 # to find them in the system for reusing
16247 if(parse_libname($Lib_Name, "short", $OStarget) eq "libstdc++")
16248 { # libstdc++.so.6
16249 $STDCXX_TESTING = 1;
16250 }
16251 if(parse_libname($Lib_Name, "short", $OStarget) eq "libc")
16252 { # libc-2.11.3.so
16253 $GLIBC_TESTING = 1;
16254 }
16255 }
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040016256 my $DebugPath = "";
Andrey Ponomarenkoa01311b2012-06-08 17:20:02 +040016257 if($Debug and not $DumpSystem)
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040016258 { # debug mode
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040016259 $DebugPath = $DEBUG_PATH{$LibVersion}."/libs/".get_filename($Lib_Path).".txt";
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040016260 mkpath(get_dirname($DebugPath));
16261 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040016262 if($OStarget eq "macos")
16263 { # Mac OS X: *.dylib, *.a
16264 my $OtoolCmd = get_CmdPath("otool");
16265 if(not $OtoolCmd) {
16266 exitStatus("Not_Found", "can't find \"otool\"");
16267 }
Andrey Ponomarenkoa01311b2012-06-08 17:20:02 +040016268 $OtoolCmd .= " -TV \"$Lib_Path\" 2>\"$TMP_DIR/null\"";
16269 if($DebugPath)
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040016270 { # debug mode
Andrey Ponomarenko16934472012-03-29 15:37:04 +040016271 # write to file
Andrey Ponomarenkoa01311b2012-06-08 17:20:02 +040016272 system($OtoolCmd." >\"$DebugPath\"");
Andrey Ponomarenko16934472012-03-29 15:37:04 +040016273 open(LIB, $DebugPath);
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040016274 }
Andrey Ponomarenko16934472012-03-29 15:37:04 +040016275 else
16276 { # write to pipe
16277 open(LIB, $OtoolCmd." |");
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040016278 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040016279 while(<LIB>)
16280 {
16281 if(/[^_]+\s+_([\w\$]+)\s*\Z/)
16282 {
16283 my $realname = $1;
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040016284 if($IsNeededLib)
16285 {
16286 if(not $GroupNames->{$Lib_SName})
16287 {
16288 $DepSymbol_Library{$LibVersion}{$realname} = $Lib_Name;
16289 $DepLibrary_Symbol{$LibVersion}{$Lib_Name}{$realname} = 1;
16290 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040016291 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040016292 else
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040016293 {
16294 $Symbol_Library{$LibVersion}{$realname} = $Lib_Name;
16295 $Library_Symbol{$LibVersion}{$Lib_Name}{$realname} = 1;
16296 if($COMMON_LANGUAGE{$LibVersion} ne "C++"
16297 and $realname=~/\A(_Z|\?)/) {
16298 setLanguage($LibVersion, "C++");
16299 }
16300 if($CheckObjectsOnly
16301 and $LibVersion==1) {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040016302 $CheckedSymbols{"Binary"}{$realname} = 1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040016303 }
16304 }
16305 }
16306 }
16307 close(LIB);
16308 if($LIB_TYPE eq "dynamic")
16309 { # dependencies
Andrey Ponomarenkoa01311b2012-06-08 17:20:02 +040016310 open(LIB, "$OtoolCmd -L \"$Lib_Path\" 2>\"$TMP_DIR/null\" |");
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040016311 while(<LIB>)
16312 {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040016313 if(/\s*([\/\\].+\.$LIB_EXT)\s*/
16314 and $1 ne $Lib_Path) {
16315 $NeededLib{$1} = 1;
16316 }
16317 }
16318 close(LIB);
16319 }
16320 }
16321 elsif($OStarget eq "windows")
16322 { # Windows *.dll, *.lib
16323 my $DumpBinCmd = get_CmdPath("dumpbin");
16324 if(not $DumpBinCmd) {
16325 exitStatus("Not_Found", "can't find \"dumpbin\"");
16326 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040016327 $DumpBinCmd .= " /EXPORTS \"".$Lib_Path."\" 2>$TMP_DIR/null";
Andrey Ponomarenkoa01311b2012-06-08 17:20:02 +040016328 if($DebugPath)
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040016329 { # debug mode
Andrey Ponomarenko16934472012-03-29 15:37:04 +040016330 # write to file
Andrey Ponomarenkoa01311b2012-06-08 17:20:02 +040016331 system($DumpBinCmd." >\"$DebugPath\"");
Andrey Ponomarenko16934472012-03-29 15:37:04 +040016332 open(LIB, $DebugPath);
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040016333 }
Andrey Ponomarenko16934472012-03-29 15:37:04 +040016334 else
16335 { # write to pipe
16336 open(LIB, $DumpBinCmd." |");
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040016337 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040016338 while(<LIB>)
16339 { # 1197 4AC 0000A620 SetThreadStackGuarantee
16340 # 1198 4AD SetThreadToken (forwarded to ...)
16341 # 3368 _o2i_ECPublicKey
16342 if(/\A\s*\d+\s+[a-f\d]+\s+[a-f\d]+\s+([\w\?\@]+)\s*\Z/i
16343 or /\A\s*\d+\s+[a-f\d]+\s+([\w\?\@]+)\s*\(\s*forwarded\s+/
16344 or /\A\s*\d+\s+_([\w\?\@]+)\s*\Z/)
16345 { # dynamic, static and forwarded symbols
16346 my $realname = $1;
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040016347 if($IsNeededLib)
16348 {
16349 if(not $GroupNames->{$Lib_SName})
16350 {
16351 $DepSymbol_Library{$LibVersion}{$realname} = $Lib_Name;
16352 $DepLibrary_Symbol{$LibVersion}{$Lib_Name}{$realname} = 1;
16353 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040016354 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040016355 else
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040016356 {
16357 $Symbol_Library{$LibVersion}{$realname} = $Lib_Name;
16358 $Library_Symbol{$LibVersion}{$Lib_Name}{$realname} = 1;
16359 if($COMMON_LANGUAGE{$LibVersion} ne "C++"
16360 and $realname=~/\A(_Z|\?)/) {
16361 setLanguage($LibVersion, "C++");
16362 }
16363 if($CheckObjectsOnly
16364 and $LibVersion==1) {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040016365 $CheckedSymbols{"Binary"}{$realname} = 1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040016366 }
16367 }
16368 }
16369 }
16370 close(LIB);
16371 if($LIB_TYPE eq "dynamic")
16372 { # dependencies
Andrey Ponomarenkoa01311b2012-06-08 17:20:02 +040016373 open(LIB, "$DumpBinCmd /DEPENDENTS \"$Lib_Path\" 2>\"$TMP_DIR/null\" |");
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040016374 while(<LIB>)
16375 {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040016376 if(/\s*([^\s]+?\.$LIB_EXT)\s*/i
16377 and $1 ne $Lib_Path) {
16378 $NeededLib{path_format($1, $OSgroup)} = 1;
16379 }
16380 }
16381 close(LIB);
16382 }
16383 }
16384 else
16385 { # Unix; *.so, *.a
16386 # Symbian: *.dso, *.lib
16387 my $ReadelfCmd = get_CmdPath("readelf");
16388 if(not $ReadelfCmd) {
16389 exitStatus("Not_Found", "can't find \"readelf\"");
16390 }
Andrey Ponomarenkoa01311b2012-06-08 17:20:02 +040016391 $ReadelfCmd .= " -WhlSsdA \"$Lib_Path\" 2>\"$TMP_DIR/null\"";
16392 if($DebugPath)
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040016393 { # debug mode
Andrey Ponomarenko16934472012-03-29 15:37:04 +040016394 # write to file
Andrey Ponomarenkoa01311b2012-06-08 17:20:02 +040016395 system($ReadelfCmd." >\"$DebugPath\"");
Andrey Ponomarenko16934472012-03-29 15:37:04 +040016396 open(LIB, $DebugPath);
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040016397 }
Andrey Ponomarenko16934472012-03-29 15:37:04 +040016398 else
16399 { # write to pipe
16400 open(LIB, $ReadelfCmd." |");
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040016401 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040016402 my $symtab=0; # indicates that we are processing 'symtab' section of 'readelf' output
16403 while(<LIB>)
16404 {
16405 if($LIB_TYPE eq "dynamic")
16406 { # dynamic library specifics
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040016407 if($symtab==1)
16408 {
16409 if(/'\.dynsym'/)
16410 { # dynamic table
16411 $symtab=0;
16412 next;
16413 }
16414 else
16415 { # do nothing with symtab
16416 next;
16417 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040016418 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040016419 elsif(/'\.symtab'/)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040016420 { # symbol table
16421 $symtab=1;
16422 next;
16423 }
16424 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040016425 if(my ($fullname, $idx, $Ndx, $type, $size, $bind) = readline_ELF($_))
16426 { # read ELF entry
16427 if( $Ndx eq "UND" )
16428 { # ignore interfaces that are imported from somewhere else
16429 next;
16430 }
16431 if($bind eq "WEAK"
16432 and $Weak eq "-Weak")
16433 { # skip WEAK symbols
16434 next;
16435 }
16436 my ($realname, $version_spec, $version) = separate_symbol($fullname);
16437 if($type eq "OBJECT")
16438 { # global data
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040016439 $GlobalDataObject{$LibVersion}{$fullname} = 1;
16440 $GlobalDataObject{$LibVersion}{$realname} = 1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040016441 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040016442 if($IsNeededLib)
16443 {
16444 if(not $GroupNames->{$Lib_SName})
16445 {
16446 $DepSymbol_Library{$LibVersion}{$fullname} = $Lib_Name;
16447 $DepLibrary_Symbol{$LibVersion}{$Lib_Name}{$fullname} = ($type eq "OBJECT")?-$size:1;
16448 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040016449 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040016450 else
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040016451 {
16452 $Symbol_Library{$LibVersion}{$fullname} = $Lib_Name;
16453 $Library_Symbol{$LibVersion}{$Lib_Name}{$fullname} = ($type eq "OBJECT")?-$size:1;
16454 if($LIB_EXT eq "so")
16455 { # value
16456 $Interface_Value{$LibVersion}{$fullname} = $idx;
16457 $Value_Interface{$LibVersion}{$idx}{$fullname} = 1;
16458 }
16459 if($COMMON_LANGUAGE{$LibVersion} ne "C++"
16460 and $realname=~/\A(_Z|\?)/) {
16461 setLanguage($LibVersion, "C++");
16462 }
16463 if($CheckObjectsOnly
16464 and $LibVersion==1) {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040016465 $CheckedSymbols{"Binary"}{$fullname} = 1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040016466 }
16467 }
16468 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040016469 elsif($LIB_TYPE eq "dynamic")
16470 { # dynamic library specifics
16471 if(/NEEDED.+\[([^\[\]]+)\]/)
16472 { # dependencies:
16473 # 0x00000001 (NEEDED) Shared library: [libc.so.6]
16474 $NeededLib{$1} = 1;
16475 }
16476 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040016477 }
16478 close(LIB);
16479 }
16480 if(not $IsNeededLib and $LIB_EXT eq "so")
16481 { # get symbol versions
16482 foreach my $Symbol (keys(%{$Symbol_Library{$LibVersion}}))
16483 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040016484 next if(index($Symbol,"\@")==-1);
Andrey Ponomarenkoa01311b2012-06-08 17:20:02 +040016485 if(my $Value = $Interface_Value{$LibVersion}{$Symbol})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040016486 {
Andrey Ponomarenkoa01311b2012-06-08 17:20:02 +040016487 my $Interface_SymName = "";
16488 foreach my $Symbol_SameValue (keys(%{$Value_Interface{$LibVersion}{$Value}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040016489 {
Andrey Ponomarenkoa01311b2012-06-08 17:20:02 +040016490 if($Symbol_SameValue ne $Symbol
16491 and index($Symbol_SameValue,"\@")==-1)
16492 {
16493 $SymVer{$LibVersion}{$Symbol_SameValue} = $Symbol;
16494 $Interface_SymName = $Symbol_SameValue;
16495 last;
16496 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040016497 }
Andrey Ponomarenkoa01311b2012-06-08 17:20:02 +040016498 if(not $Interface_SymName)
16499 {
16500 if($Symbol=~/\A([^\@\$\?]*)[\@\$]+([^\@\$]*)\Z/
16501 and not $SymVer{$LibVersion}{$1}) {
16502 $SymVer{$LibVersion}{$1} = $Symbol;
16503 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040016504 }
16505 }
16506 }
16507 }
16508 foreach my $DyLib (sort keys(%NeededLib))
16509 {
16510 my $DepPath = find_lib_path($LibVersion, $DyLib);
16511 if($DepPath and -f $DepPath) {
Andrey Ponomarenko16934472012-03-29 15:37:04 +040016512 readSymbols_Lib($LibVersion, $DepPath, 1, $GroupNames, "+Weak");
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040016513 }
16514 }
16515 pop(@RecurLib);
16516 return $Library_Symbol{$LibVersion};
16517}
16518
16519sub get_path_prefixes($)
16520{
16521 my $Path = $_[0];
16522 my ($Dir, $Name) = separate_path($Path);
16523 my %Prefixes = ();
16524 foreach my $Prefix (reverse(split(/[\/\\]+/, $Dir)))
16525 {
16526 $Prefixes{$Name} = 1;
16527 $Name = joinPath($Prefix, $Name);
16528 last if(keys(%Prefixes)>5 or $Prefix eq "include");
16529 }
16530 return keys(%Prefixes);
16531}
16532
16533sub detectSystemHeaders()
16534{
16535 my @SysHeaders = ();
16536 foreach my $DevelPath (keys(%{$SystemPaths{"include"}}))
16537 {
16538 next if(not -d $DevelPath);
16539 # search for all header files in the /usr/include
16540 # with or without extension (ncurses.h, QtCore, ...)
16541 @SysHeaders = (@SysHeaders, cmd_find($DevelPath,"f","",""));
16542 foreach my $Link (cmd_find($DevelPath,"l","",""))
16543 { # add symbolic links
16544 if(-f $Link) {
16545 push(@SysHeaders, $Link);
16546 }
16547 }
16548 }
16549 foreach my $DevelPath (keys(%{$SystemPaths{"lib"}}))
16550 {
16551 next if(not -d $DevelPath);
16552 # search for config headers in the /usr/lib
16553 @SysHeaders = (@SysHeaders, cmd_find($DevelPath,"f","*.h",""));
16554 foreach my $Dir (cmd_find($DevelPath,"d","include",""))
16555 { # search for all include directories
16556 # this is for headers that are installed to /usr/lib
16557 # Example: Qt4 headers in Mandriva (/usr/lib/qt4/include/)
16558 if($Dir=~/\/(gcc|jvm|syslinux|kdb)\//) {
16559 next;
16560 }
16561 @SysHeaders = (@SysHeaders, cmd_find($Dir,"f","",""));
16562 }
16563 }
16564 foreach my $Path (@SysHeaders)
16565 {
16566 foreach my $Part (get_path_prefixes($Path)) {
16567 $SystemHeaders{$Part}{$Path}=1;
16568 }
16569 }
16570}
16571
16572sub detectSystemObjects()
16573{
16574 foreach my $DevelPath (keys(%{$SystemPaths{"lib"}}))
16575 {
16576 next if(not -d $DevelPath);
16577 foreach my $Path (find_libs($DevelPath,"",""))
16578 { # search for shared libraries in the /usr/lib (including symbolic links)
16579 $SystemObjects{parse_libname(get_filename($Path), "name+ext", $OStarget)}{$Path}=1;
16580 }
16581 }
16582}
16583
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040016584sub getSOPaths($)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040016585{
16586 my $LibVersion = $_[0];
16587 my @SoPaths = ();
16588 foreach my $Dest (split(/\s*\n\s*/, $Descriptor{$LibVersion}{"Libs"}))
16589 {
16590 if(not -e $Dest) {
16591 exitStatus("Access_Error", "can't access \'$Dest\'");
16592 }
16593 my @SoPaths_Dest = getSOPaths_Dest($Dest, $LibVersion);
16594 foreach (@SoPaths_Dest) {
16595 push(@SoPaths, $_);
16596 }
16597 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040016598 return sort @SoPaths;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040016599}
16600
16601sub skip_lib($$)
16602{
16603 my ($Path, $LibVersion) = @_;
16604 return 1 if(not $Path or not $LibVersion);
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040016605 my $Name = get_filename($Path);
16606 if($SkipLibs{$LibVersion}{"Name"}{$Name}) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040016607 return 1;
16608 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040016609 my $ShortName = parse_libname($Name, "name+ext", $OStarget);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040016610 if($SkipLibs{$LibVersion}{"Name"}{$ShortName}) {
16611 return 1;
16612 }
16613 foreach my $Dir (keys(%{$SkipLibs{$LibVersion}{"Path"}}))
16614 {
16615 if($Path=~/\Q$Dir\E([\/\\]|\Z)/) {
16616 return 1;
16617 }
16618 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040016619 foreach my $P (keys(%{$SkipLibs{$LibVersion}{"Pattern"}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040016620 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040016621 if($Name=~/$P/) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040016622 return 1;
16623 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040016624 if($P=~/[\/\\]/ and $Path=~/$P/) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040016625 return 1;
16626 }
16627 }
16628 return 0;
16629}
16630
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040016631sub skipHeader($$)
16632{
16633 my ($Path, $LibVersion) = @_;
16634 return 1 if(not $Path or not $LibVersion);
16635 if(not keys(%{$SkipHeaders{$LibVersion}})) {
16636 return 0;
16637 }
16638 if(defined $Cache{"skipHeader"}{$Path}) {
16639 return $Cache{"skipHeader"}{$Path};
16640 }
16641 return ($Cache{"skipHeader"}{$Path} = skipHeader_I(@_));
16642}
16643
16644sub skipHeader_I($$)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040016645{ # returns:
16646 # 1 - if header should NOT be included and checked
16647 # 2 - if header should NOT be included, but should be checked
16648 my ($Path, $LibVersion) = @_;
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040016649 my $Name = get_filename($Path);
16650 if(my $Kind = $SkipHeaders{$LibVersion}{"Name"}{$Name}) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040016651 return $Kind;
16652 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040016653 foreach my $D (keys(%{$SkipHeaders{$LibVersion}{"Path"}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040016654 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040016655 if($Path=~/\Q$D\E([\/\\]|\Z)/) {
16656 return $SkipHeaders{$LibVersion}{"Path"}{$D};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040016657 }
16658 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040016659 foreach my $P (keys(%{$SkipHeaders{$LibVersion}{"Pattern"}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040016660 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040016661 if(my $Kind = $SkipHeaders{$LibVersion}{"Pattern"}{$P})
16662 {
16663 if($Name=~/$P/) {
16664 return $Kind;
16665 }
16666 if($P=~/[\/\\]/ and $Path=~/$P/) {
16667 return $Kind;
16668 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040016669 }
16670 }
16671 return 0;
16672}
16673
16674sub register_objects($$)
16675{
16676 my ($Dir, $LibVersion) = @_;
16677 if($SystemPaths{"lib"}{$Dir})
16678 { # system directory
16679 return;
16680 }
16681 if($RegisteredObjDirs{$LibVersion}{$Dir})
16682 { # already registered
16683 return;
16684 }
16685 foreach my $Path (find_libs($Dir,"",1))
16686 {
16687 next if(ignore_path($Path));
16688 next if(skip_lib($Path, $LibVersion));
16689 $InputObject_Paths{$LibVersion}{get_filename($Path)}{$Path} = 1;
16690 }
16691 $RegisteredObjDirs{$LibVersion}{$Dir} = 1;
16692}
16693
16694sub getSOPaths_Dest($$)
16695{
16696 my ($Dest, $LibVersion) = @_;
16697 if(skip_lib($Dest, $LibVersion)) {
16698 return ();
16699 }
16700 if(-f $Dest)
16701 {
16702 if(not parse_libname($Dest, "name", $OStarget)) {
16703 exitStatus("Error", "incorrect format of library (should be *.$LIB_EXT): \'$Dest\'");
16704 }
16705 $InputObject_Paths{$LibVersion}{get_filename($Dest)}{$Dest} = 1;
16706 register_objects(get_dirname($Dest), $LibVersion);
16707 return ($Dest);
16708 }
16709 elsif(-d $Dest)
16710 {
16711 $Dest=~s/[\/\\]+\Z//g;
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040016712 my %Libs = ();
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040016713 if($SystemPaths{"lib"}{$Dest})
16714 { # you have specified /usr/lib as the search directory (<libs>) in the XML descriptor
16715 # and the real name of the library by -l option (bz2, stdc++, Xaw, ...)
16716 foreach my $Path (cmd_find($Dest,"","*".esc($TargetLibraryName)."*\.$LIB_EXT*",2))
16717 { # all files and symlinks that match the name of a library
16718 if(get_filename($Path)=~/\A(|lib)\Q$TargetLibraryName\E[\d\-]*\.$LIB_EXT[\d\.]*\Z/i)
16719 {
16720 $InputObject_Paths{$LibVersion}{get_filename($Path)}{$Path} = 1;
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040016721 $Libs{resolve_symlink($Path)}=1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040016722 }
16723 }
16724 }
16725 else
16726 { # search for all files and symlinks
16727 foreach my $Path (find_libs($Dest,"",""))
16728 {
16729 next if(ignore_path($Path));
16730 next if(skip_lib($Path, $LibVersion));
16731 $InputObject_Paths{$LibVersion}{get_filename($Path)}{$Path} = 1;
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040016732 $Libs{resolve_symlink($Path)}=1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040016733 }
16734 if($OSgroup eq "macos")
16735 { # shared libraries on MacOS X may have no extension
16736 foreach my $Path (cmd_find($Dest,"f","",""))
16737 {
16738 next if(ignore_path($Path));
16739 next if(skip_lib($Path, $LibVersion));
16740 if(get_filename($Path)!~/\./
Andrey Ponomarenko85043792012-05-14 16:48:07 +040016741 and cmd_file($Path)=~/(shared|dynamic)\s+library/i)
16742 {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040016743 $InputObject_Paths{$LibVersion}{get_filename($Path)}{$Path} = 1;
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040016744 $Libs{resolve_symlink($Path)}=1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040016745 }
16746 }
16747 }
16748 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040016749 return keys(%Libs);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040016750 }
16751 else {
16752 return ();
16753 }
16754}
16755
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040016756sub isCyclical($$)
16757{
16758 my ($Stack, $Value) = @_;
16759 return (grep {$_ eq $Value} @{$Stack});
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040016760}
16761
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040016762sub generateTemplate()
16763{
16764 writeFile("VERSION.xml", $DescriptorTemplate."\n");
16765 printMsg("INFO", "XML-descriptor template ./VERSION.xml has been generated");
16766}
16767
16768sub detectWordSize()
16769{
16770 return "" if(not $GCC_PATH);
16771 if($Cache{"detectWordSize"}) {
16772 return $Cache{"detectWordSize"};
16773 }
16774 writeFile("$TMP_DIR/empty.h", "");
Andrey Ponomarenkoa01311b2012-06-08 17:20:02 +040016775 my $Defines = `$GCC_PATH -E -dD \"$TMP_DIR/empty.h\"`;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040016776 unlink("$TMP_DIR/empty.h");
16777 my $WSize = 0;
16778 if($Defines=~/ __SIZEOF_POINTER__\s+(\d+)/)
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040016779 { # GCC 4
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040016780 $WSize = $1;
16781 }
16782 elsif($Defines=~/ __PTRDIFF_TYPE__\s+(\w+)/)
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040016783 { # GCC 3
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040016784 my $PTRDIFF = $1;
16785 if($PTRDIFF=~/long/) {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040016786 $WSize = "8";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040016787 }
16788 else {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040016789 $WSize = "4";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040016790 }
16791 }
16792 if(not int($WSize)) {
16793 exitStatus("Error", "can't check WORD size");
16794 }
16795 return ($Cache{"detectWordSize"} = $WSize);
16796}
16797
16798sub majorVersion($)
16799{
16800 my $V = $_[0];
16801 return 0 if(not $V);
16802 my @VParts = split(/\./, $V);
16803 return $VParts[0];
16804}
16805
16806sub cmpVersions($$)
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040016807{ # compare two versions in dotted-numeric format
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040016808 my ($V1, $V2) = @_;
16809 return 0 if($V1 eq $V2);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040016810 my @V1Parts = split(/\./, $V1);
16811 my @V2Parts = split(/\./, $V2);
16812 for (my $i = 0; $i <= $#V1Parts && $i <= $#V2Parts; $i++) {
16813 return -1 if(int($V1Parts[$i]) < int($V2Parts[$i]));
16814 return 1 if(int($V1Parts[$i]) > int($V2Parts[$i]));
16815 }
16816 return -1 if($#V1Parts < $#V2Parts);
16817 return 1 if($#V1Parts > $#V2Parts);
16818 return 0;
16819}
16820
16821sub read_ABI_Dump($$)
16822{
16823 my ($LibVersion, $Path) = @_;
16824 return if(not $LibVersion or not -e $Path);
16825 my $FilePath = "";
16826 if($Path=~/\.abi\Z/)
16827 { # input *.abi
16828 $FilePath = $Path;
16829 }
16830 else
16831 { # input *.abi.tar.gz
16832 $FilePath = unpackDump($Path);
16833 }
16834 if($FilePath!~/\.abi\Z/) {
16835 exitStatus("Invalid_Dump", "specified ABI dump \'$Path\' is not valid, try to recreate it");
16836 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +040016837
16838 open(DUMP, $FilePath);
16839 local $/ = undef;
16840 my $Content = <DUMP>;
16841 close(DUMP);
16842
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040016843 if($Path!~/\.abi\Z/)
16844 { # remove temp file
16845 unlink($FilePath);
16846 }
16847 if($Content!~/};\s*\Z/) {
16848 exitStatus("Invalid_Dump", "specified ABI dump \'$Path\' is not valid, try to recreate it");
16849 }
16850 my $LibraryABI = eval($Content);
16851 if(not $LibraryABI) {
16852 exitStatus("Error", "internal error - eval() procedure seem to not working correctly, try to remove 'use strict' and try again");
16853 }
16854 # new dumps (>=1.22) have a personal versioning
16855 my $DumpVersion = $LibraryABI->{"ABI_DUMP_VERSION"};
16856 my $ToolVersion = $LibraryABI->{"ABI_COMPLIANCE_CHECKER_VERSION"};
16857 if(not $DumpVersion)
16858 { # old dumps (<=1.21.6) have been marked by the tool version
16859 $DumpVersion = $ToolVersion;
16860 }
16861 $UsedDump{$LibVersion}{"V"} = $DumpVersion;
16862 if(majorVersion($DumpVersion) ne majorVersion($ABI_DUMP_VERSION))
16863 { # should be compatible with dumps of the same major version
16864 if(cmpVersions($DumpVersion, $ABI_DUMP_VERSION)>0)
16865 { # Don't know how to parse future dump formats
16866 exitStatus("Dump_Version", "incompatible version $DumpVersion of specified ABI dump (newer than $ABI_DUMP_VERSION)");
16867 }
16868 elsif(cmpVersions($DumpVersion, $TOOL_VERSION)>0 and not $LibraryABI->{"ABI_DUMP_VERSION"})
16869 { # Don't know how to parse future dump formats
16870 exitStatus("Dump_Version", "incompatible version $DumpVersion of specified ABI dump (newer than $TOOL_VERSION)");
16871 }
16872 if($UseOldDumps)
16873 {
16874 if(cmpVersions($DumpVersion, $OLDEST_SUPPORTED_VERSION)<0) {
16875 exitStatus("Dump_Version", "incompatible version $DumpVersion of specified ABI dump (older than $OLDEST_SUPPORTED_VERSION)");
16876 }
16877 }
16878 else
16879 {
16880 my $Msg = "incompatible version $DumpVersion of specified ABI dump (allowed only ".majorVersion($ABI_DUMP_VERSION).".0<=V<=$ABI_DUMP_VERSION)";
16881 if(cmpVersions($DumpVersion, $OLDEST_SUPPORTED_VERSION)>=0) {
16882 $Msg .= "\nUse -old-dumps option to use old-version dumps ($OLDEST_SUPPORTED_VERSION<=V<".majorVersion($ABI_DUMP_VERSION).".0)";
16883 }
16884 exitStatus("Dump_Version", $Msg);
16885 }
16886 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040016887 if($LibraryABI->{"SrcBin"})
16888 { # default
16889 $UsedDump{$LibVersion}{"SrcBin"} = 1;
16890 }
16891 elsif($LibraryABI->{"BinOnly"})
16892 { # ABI dump created with --binary option
16893 $UsedDump{$LibVersion}{"BinOnly"} = 1;
16894 }
Andrey Ponomarenko16934472012-03-29 15:37:04 +040016895 if(defined $LibraryABI->{"Mode"}
16896 and $LibraryABI->{"Mode"} eq "Extended")
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040016897 { # --ext option
16898 $ExtendedCheck = 1;
16899 }
16900 if(my $Lang = $LibraryABI->{"Language"})
16901 {
16902 $UsedDump{$LibVersion}{"L"} = $Lang;
16903 setLanguage($LibVersion, $Lang);
16904 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040016905 if(checkDump($LibVersion, "2.15")) {
16906 $TypeInfo{$LibVersion} = $LibraryABI->{"TypeInfo"};
16907 }
16908 else
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040016909 { # support for old ABI dumps
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040016910 my $TInfo = $LibraryABI->{"TypeInfo"};
16911 if(not $TInfo)
16912 { # support for older ABI dumps
16913 $TInfo = $LibraryABI->{"TypeDescr"};
16914 }
16915 my %Tid_TDid = ();
16916 foreach my $TDid (keys(%{$TInfo}))
16917 {
16918 foreach my $Tid (keys(%{$TInfo->{$TDid}}))
16919 {
16920 $MAX_ID = $Tid if($Tid>$MAX_ID);
16921 $MAX_ID = $TDid if($TDid and $TDid>$MAX_ID);
16922 $Tid_TDid{$Tid}{$TDid}=1;
16923 }
16924 }
16925 my %NewID = ();
16926 foreach my $Tid (keys(%Tid_TDid))
16927 {
16928 my @TDids = keys(%{$Tid_TDid{$Tid}});
16929 if($#TDids>=1)
16930 {
16931 foreach my $TDid (@TDids)
16932 {
16933 if($TDid) {
16934 %{$TypeInfo{$LibVersion}{$Tid}} = %{$TInfo->{$TDid}{$Tid}};
16935 }
16936 else
16937 {
16938 if(my $ID = ++$MAX_ID)
16939 {
16940 $NewID{$TDid}{$Tid} = $ID;
16941 %{$TypeInfo{$LibVersion}{$ID}} = %{$TInfo->{$TDid}{$Tid}};
16942 $TypeInfo{$LibVersion}{$ID}{"Tid"} = $ID;
16943 }
16944 }
16945 }
16946 }
16947 else
16948 {
16949 my $TDid = $TDids[0];
16950 %{$TypeInfo{$LibVersion}{$Tid}} = %{$TInfo->{$TDid}{$Tid}};
16951 }
16952 }
16953 foreach my $Tid (keys(%{$TypeInfo{$LibVersion}}))
16954 {
16955 my %Info = %{$TypeInfo{$LibVersion}{$Tid}};
16956 if(defined $Info{"BaseType"})
16957 {
16958 my $Bid = $Info{"BaseType"}{"Tid"};
16959 my $BDid = $Info{"BaseType"}{"TDid"};
16960 $BDid="" if(not defined $BDid);
16961 if(defined $NewID{$BDid} and my $ID = $NewID{$BDid}{$Bid}) {
16962 $TypeInfo{$LibVersion}{$Tid}{"BaseType"}{"Tid"} = $ID;
16963 }
16964 delete($TypeInfo{$LibVersion}{$Tid}{"BaseType"}{"TDid"});
16965 }
16966 delete($TypeInfo{$LibVersion}{$Tid}{"TDid"});
16967 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040016968 }
16969 read_Machine_DumpInfo($LibraryABI, $LibVersion);
16970 $SymbolInfo{$LibVersion} = $LibraryABI->{"SymbolInfo"};
16971 if(not $SymbolInfo{$LibVersion})
16972 { # support for old dumps
16973 $SymbolInfo{$LibVersion} = $LibraryABI->{"FuncDescr"};
16974 }
16975 if(not keys(%{$SymbolInfo{$LibVersion}}))
16976 { # validation of old-version dumps
16977 if(not $ExtendedCheck) {
16978 exitStatus("Invalid_Dump", "the input dump d$LibVersion is invalid");
16979 }
16980 }
16981 $Library_Symbol{$LibVersion} = $LibraryABI->{"Symbols"};
16982 if(not $Library_Symbol{$LibVersion})
16983 { # support for old dumps
16984 $Library_Symbol{$LibVersion} = $LibraryABI->{"Interfaces"};
16985 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040016986 if(checkDump($LibVersion, "2.15")) {
16987 $DepLibrary_Symbol{$LibVersion} = $LibraryABI->{"DepSymbols"};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040016988 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040016989 else
16990 { # support for old ABI dumps
16991 my $DepSymbols = $LibraryABI->{"DepSymbols"};
16992 if(not $DepSymbols) {
16993 $DepSymbols = $LibraryABI->{"DepInterfaces"};
16994 }
16995 if(not $DepSymbols)
16996 { # Cannot reconstruct DepSymbols. This may result in false
16997 # positives if the old dump is for library 2. Not a problem if
16998 # old dumps are only from old libraries.
16999 $DepSymbols = {};
17000 }
17001 foreach my $Symbol (keys(%{$DepSymbols})) {
17002 $DepSymbol_Library{$LibVersion}{$Symbol} = 1;
17003 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017004 }
17005 $SymVer{$LibVersion} = $LibraryABI->{"SymbolVersion"};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017006 $Descriptor{$LibVersion}{"Version"} = $LibraryABI->{"LibraryVersion"};
17007 $SkipTypes{$LibVersion} = $LibraryABI->{"SkipTypes"};
17008 if(not $SkipTypes{$LibVersion})
17009 { # support for old dumps
17010 $SkipTypes{$LibVersion} = $LibraryABI->{"OpaqueTypes"};
17011 }
17012 $SkipSymbols{$LibVersion} = $LibraryABI->{"SkipSymbols"};
17013 if(not $SkipSymbols{$LibVersion})
17014 { # support for old dumps
17015 $SkipSymbols{$LibVersion} = $LibraryABI->{"SkipInterfaces"};
17016 }
17017 if(not $SkipSymbols{$LibVersion})
17018 { # support for old dumps
17019 $SkipSymbols{$LibVersion} = $LibraryABI->{"InternalInterfaces"};
17020 }
17021 $SkipNameSpaces{$LibVersion} = $LibraryABI->{"SkipNameSpaces"};
17022 $TargetHeaders{$LibVersion} = $LibraryABI->{"TargetHeaders"};
17023 foreach my $Path (keys(%{$LibraryABI->{"SkipHeaders"}}))
17024 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040017025 $SkipHeadersList{$LibVersion}{$Path} = $LibraryABI->{"SkipHeaders"}{$Path};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017026 my ($CPath, $Type) = classifyPath($Path);
17027 $SkipHeaders{$LibVersion}{$Type}{$CPath} = $LibraryABI->{"SkipHeaders"}{$Path};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017028 }
17029 read_Headers_DumpInfo($LibraryABI, $LibVersion);
17030 read_Libs_DumpInfo($LibraryABI, $LibVersion);
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040017031 if(not checkDump($LibVersion, "2.10.1"))
Andrey Ponomarenko85043792012-05-14 16:48:07 +040017032 { # support for old ABI dumps: added target headers
17033 foreach (keys(%{$Registered_Headers{$LibVersion}})) {
17034 $TargetHeaders{$LibVersion}{get_filename($_)}=1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017035 }
17036 }
17037 $Constants{$LibVersion} = $LibraryABI->{"Constants"};
17038 $NestedNameSpaces{$LibVersion} = $LibraryABI->{"NameSpaces"};
17039 if(not $NestedNameSpaces{$LibVersion})
17040 { # support for old dumps
17041 # Cannot reconstruct NameSpaces. This may affect design
17042 # of the compatibility report.
17043 $NestedNameSpaces{$LibVersion} = {};
17044 }
17045 # target system type
17046 # needed to adopt HTML report
17047 if(not $DumpSystem)
17048 { # to use in createSymbolsList(...)
17049 $OStarget = $LibraryABI->{"Target"};
17050 }
17051 # recreate environment
17052 foreach my $Lib_Name (keys(%{$Library_Symbol{$LibVersion}}))
17053 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040017054 foreach my $Symbol (keys(%{$Library_Symbol{$LibVersion}{$Lib_Name}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017055 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040017056 $Symbol_Library{$LibVersion}{$Symbol} = $Lib_Name;
17057 if($Library_Symbol{$LibVersion}{$Lib_Name}{$Symbol}<=-1)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017058 { # data marked as -size in the dump
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040017059 $GlobalDataObject{$LibVersion}{$Symbol}=1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017060 }
17061 if($COMMON_LANGUAGE{$LibVersion} ne "C++"
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040017062 and $Symbol=~/\A(_Z|\?)/) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017063 setLanguage($LibVersion, "C++");
17064 }
17065 }
17066 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040017067 foreach my $Lib_Name (keys(%{$DepLibrary_Symbol{$LibVersion}}))
17068 {
17069 foreach my $Symbol (keys(%{$DepLibrary_Symbol{$LibVersion}{$Lib_Name}})) {
17070 $DepSymbol_Library{$LibVersion}{$Symbol} = $Lib_Name;
17071 }
17072 }
17073
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017074 my @VFunc = ();
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040017075 foreach my $InfoId (keys(%{$SymbolInfo{$LibVersion}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017076 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040017077 my $MnglName = $SymbolInfo{$LibVersion}{$InfoId}{"MnglName"};
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040017078 if($MnglName)
17079 {
17080 if(not $Symbol_Library{$LibVersion}{$MnglName}
17081 and not $DepSymbol_Library{$LibVersion}{$MnglName}) {
17082 push(@VFunc, $MnglName);
17083 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017084 }
17085 }
17086 translateSymbols(@VFunc, $LibVersion);
17087 translateSymbols(keys(%{$Symbol_Library{$LibVersion}}), $LibVersion);
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040017088 translateSymbols(keys(%{$DepSymbol_Library{$LibVersion}}), $LibVersion);
17089
17090 foreach my $TypeId (sort {int($a)<=>int($b)} keys(%{$TypeInfo{$LibVersion}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017091 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040017092 if(defined $TypeInfo{$LibVersion}{$TypeId}{"BaseClass"})
17093 { # support for old ABI dumps < 2.0 (ACC 1.22)
17094 foreach my $BId (keys(%{$TypeInfo{$LibVersion}{$TypeId}{"BaseClass"}}))
17095 {
17096 if(my $Access = $TypeInfo{$LibVersion}{$TypeId}{"BaseClass"}{$BId})
17097 {
17098 if($Access ne "public") {
17099 $TypeInfo{$LibVersion}{$TypeId}{"Base"}{$BId}{"access"} = $Access;
17100 }
17101 }
17102 $TypeInfo{$LibVersion}{$TypeId}{"Base"}{$BId} = {};
17103 }
17104 delete($TypeInfo{$LibVersion}{$TypeId}{"BaseClass"});
17105 }
17106 my %TInfo = %{$TypeInfo{$LibVersion}{$TypeId}};
17107 if(defined $TInfo{"Base"})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017108 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040017109 foreach (keys(%{$TInfo{"Base"}})) {
17110 $Class_SubClasses{$LibVersion}{$_}{$TypeId}=1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017111 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040017112 }
17113 if($TInfo{"Type"} eq "Typedef" and defined $TInfo{"BaseType"})
17114 {
17115 if(my $BTid = $TInfo{"BaseType"}{"Tid"})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017116 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040017117 my $BName = $TypeInfo{$LibVersion}{$BTid}{"Name"};
17118 if(not $BName)
17119 { # broken type
17120 next;
17121 }
17122 if($TInfo{"Name"} eq $BName)
17123 { # typedef to "class Class"
17124 # should not be registered in TName_Tid
17125 next;
17126 }
17127 if(not $Typedef_BaseName{$LibVersion}{$TInfo{"Name"}}) {
17128 $Typedef_BaseName{$LibVersion}{$TInfo{"Name"}} = $BName;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017129 }
17130 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040017131 }
17132 if(not $TName_Tid{$LibVersion}{$TInfo{"Name"}})
17133 { # classes: class (id1), typedef (artificial, id2 > id1)
17134 $TName_Tid{$LibVersion}{$TInfo{"Name"}} = $TypeId;
17135 }
17136 }
17137
17138 if(not checkDump($LibVersion, "2.15"))
17139 { # support for old ABI dumps
17140 my %Dups = ();
17141 foreach my $InfoId (keys(%{$SymbolInfo{$LibVersion}}))
17142 {
17143 if(my $ClassId = $SymbolInfo{$LibVersion}{$InfoId}{"Class"})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017144 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040017145 if(not defined $TypeInfo{$LibVersion}{$ClassId})
17146 { # remove template decls
17147 delete($SymbolInfo{$LibVersion}{$InfoId});
17148 next;
Andrey Ponomarenko16934472012-03-29 15:37:04 +040017149 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017150 }
Andrey Ponomarenkob8d203d2012-05-25 18:11:07 +040017151 my $MName = $SymbolInfo{$LibVersion}{$InfoId}{"MnglName"};
17152 if(not $MName and $SymbolInfo{$LibVersion}{$InfoId}{"Class"})
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040017153 { # templates
17154 delete($SymbolInfo{$LibVersion}{$InfoId});
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017155 }
17156 }
17157 }
17158
17159 $Descriptor{$LibVersion}{"Dump"} = 1;
17160}
17161
17162sub read_Machine_DumpInfo($$)
17163{
17164 my ($LibraryABI, $LibVersion) = @_;
17165 if($LibraryABI->{"Arch"}) {
17166 $CPU_ARCH{$LibVersion} = $LibraryABI->{"Arch"};
17167 }
17168 if($LibraryABI->{"WordSize"}) {
17169 $WORD_SIZE{$LibVersion} = $LibraryABI->{"WordSize"};
17170 }
17171 else
17172 { # support for old dumps
17173 $WORD_SIZE{$LibVersion} = $LibraryABI->{"SizeOfPointer"};
17174 }
17175 if(not $WORD_SIZE{$LibVersion})
17176 { # support for old dumps (<1.23)
17177 if(my $Tid = getTypeIdByName("char*", $LibVersion))
17178 { # size of char*
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040017179 $WORD_SIZE{$LibVersion} = $TypeInfo{$LibVersion}{$Tid}{"Size"};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017180 }
17181 else
17182 {
17183 my $PSize = 0;
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040017184 foreach my $Tid (keys(%{$TypeInfo{$LibVersion}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017185 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040017186 if($TypeInfo{$LibVersion}{$Tid}{"Type"} eq "Pointer")
17187 { # any "pointer"-type
17188 $PSize = $TypeInfo{$LibVersion}{$Tid}{"Size"};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017189 last;
17190 }
17191 }
17192 if($PSize)
17193 { # a pointer type size
17194 $WORD_SIZE{$LibVersion} = $PSize;
17195 }
17196 else {
17197 printMsg("WARNING", "cannot identify a WORD size in the ABI dump (too old format)");
17198 }
17199 }
17200 }
17201 if($LibraryABI->{"GccVersion"}) {
17202 $GCC_VERSION{$LibVersion} = $LibraryABI->{"GccVersion"};
17203 }
17204}
17205
17206sub read_Libs_DumpInfo($$)
17207{
17208 my ($LibraryABI, $LibVersion) = @_;
17209 if(keys(%{$Library_Symbol{$LibVersion}})
17210 and not $DumpAPI) {
17211 $Descriptor{$LibVersion}{"Libs"} = "OK";
17212 }
17213}
17214
17215sub read_Headers_DumpInfo($$)
17216{
17217 my ($LibraryABI, $LibVersion) = @_;
17218 if(keys(%{$LibraryABI->{"Headers"}})
17219 and not $DumpAPI) {
17220 $Descriptor{$LibVersion}{"Headers"} = "OK";
17221 }
17222 foreach my $Identity (keys(%{$LibraryABI->{"Headers"}}))
17223 { # headers info is stored in the old dumps in the different way
17224 if($UseOldDumps
17225 and my $Name = $LibraryABI->{"Headers"}{$Identity}{"Name"})
17226 { # support for old dumps: headers info corrected in 1.22
17227 $Identity = $Name;
17228 }
17229 $Registered_Headers{$LibVersion}{$Identity}{"Identity"} = $Identity;
17230 }
17231}
17232
17233sub find_libs($$$)
17234{
17235 my ($Path, $Type, $MaxDepth) = @_;
17236 # FIXME: correct the search pattern
17237 return cmd_find($Path, $Type, ".*\\.$LIB_EXT\[0-9.]*", $MaxDepth);
17238}
17239
17240sub createDescriptor($$)
17241{
17242 my ($LibVersion, $Path) = @_;
17243 if(not $LibVersion or not $Path
17244 or not -e $Path) {
17245 return "";
17246 }
17247 if(-d $Path)
17248 { # directory with headers files and shared objects
17249 return "
17250 <version>
17251 ".$TargetVersion{$LibVersion}."
17252 </version>
17253
17254 <headers>
17255 $Path
17256 </headers>
17257
17258 <libs>
17259 $Path
17260 </libs>";
17261 }
17262 else
17263 { # files
17264 if($Path=~/\.xml\Z/i)
17265 { # standard XML-descriptor
17266 return readFile($Path);
17267 }
17268 elsif(is_header($Path, 2, $LibVersion))
17269 { # header file
17270 return "
17271 <version>
17272 ".$TargetVersion{$LibVersion}."
17273 </version>
17274
17275 <headers>
17276 $Path
17277 </headers>
17278
17279 <libs>
17280 none
17281 </libs>";
17282 }
17283 elsif(parse_libname($Path, "name", $OStarget))
17284 { # shared object
17285 return "
17286 <version>
17287 ".$TargetVersion{$LibVersion}."
17288 </version>
17289
17290 <headers>
17291 none
17292 </headers>
17293
17294 <libs>
17295 $Path
17296 </libs>";
17297 }
17298 else
17299 { # standard XML-descriptor
17300 return readFile($Path);
17301 }
17302 }
17303}
17304
17305sub detect_lib_default_paths()
17306{
17307 my %LPaths = ();
17308 if($OSgroup eq "bsd")
17309 {
Andrey Ponomarenkoa01311b2012-06-08 17:20:02 +040017310 if(my $LdConfig = get_CmdPath("ldconfig"))
17311 {
17312 foreach my $Line (split(/\n/, `$LdConfig -r 2>\"$TMP_DIR/null\"`))
17313 {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017314 if($Line=~/\A[ \t]*\d+:\-l(.+) \=\> (.+)\Z/) {
17315 $LPaths{"lib".$1} = $2;
17316 }
17317 }
17318 }
17319 else {
17320 printMsg("WARNING", "can't find ldconfig");
17321 }
17322 }
17323 else
17324 {
17325 if(my $LdConfig = get_CmdPath("ldconfig"))
17326 {
17327 if($SystemRoot and $OSgroup eq "linux")
17328 { # use host (x86) ldconfig with the target (arm) ld.so.conf
17329 if(-e $SystemRoot."/etc/ld.so.conf") {
17330 $LdConfig .= " -f ".$SystemRoot."/etc/ld.so.conf";
17331 }
17332 }
Andrey Ponomarenkoa01311b2012-06-08 17:20:02 +040017333 foreach my $Line (split(/\n/, `$LdConfig -p 2>\"$TMP_DIR/null\"`))
17334 {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017335 if($Line=~/\A[ \t]*([^ \t]+) .* \=\> (.+)\Z/)
17336 {
17337 my ($Name, $Path) = ($1, $2);
17338 $Path=~s/[\/]{2,}/\//;
17339 $LPaths{$Name} = $Path;
17340 }
17341 }
17342 }
17343 elsif($OSgroup=~/linux/i) {
17344 printMsg("WARNING", "can't find ldconfig");
17345 }
17346 }
17347 return \%LPaths;
17348}
17349
17350sub detect_bin_default_paths()
17351{
17352 my $EnvPaths = $ENV{"PATH"};
17353 if($OSgroup eq "beos") {
17354 $EnvPaths.=":".$ENV{"BETOOLS"};
17355 }
17356 my $Sep = ($OSgroup eq "windows")?";":":|;";
17357 foreach my $Path (sort {length($a)<=>length($b)} split(/$Sep/, $EnvPaths))
17358 {
17359 $Path = path_format($Path, $OSgroup);
17360 $Path=~s/[\/\\]+\Z//g;
17361 next if(not $Path);
17362 if($SystemRoot
17363 and $Path=~/\A\Q$SystemRoot\E\//)
17364 { # do NOT use binaries from target system
17365 next;
17366 }
17367 $DefaultBinPaths{$Path} = 1;
17368 }
17369}
17370
17371sub detect_inc_default_paths()
17372{
17373 return () if(not $GCC_PATH);
17374 my %DPaths = ("Cpp"=>{},"Gcc"=>{},"Inc"=>{});
17375 writeFile("$TMP_DIR/empty.h", "");
Andrey Ponomarenkoa01311b2012-06-08 17:20:02 +040017376 foreach my $Line (split(/\n/, `$GCC_PATH -v -x c++ -E \"$TMP_DIR/empty.h\" 2>&1`))
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040017377 { # detecting GCC default include paths
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017378 if($Line=~/\A[ \t]*((\/|\w+:\\).+)[ \t]*\Z/)
17379 {
17380 my $Path = simplify_path($1);
17381 $Path=~s/[\/\\]+\Z//g;
17382 $Path = path_format($Path, $OSgroup);
17383 if($Path=~/c\+\+|\/g\+\+\//)
17384 {
17385 $DPaths{"Cpp"}{$Path}=1;
17386 if(not defined $MAIN_CPP_DIR
17387 or get_depth($MAIN_CPP_DIR)>get_depth($Path)) {
17388 $MAIN_CPP_DIR = $Path;
17389 }
17390 }
17391 elsif($Path=~/gcc/) {
17392 $DPaths{"Gcc"}{$Path}=1;
17393 }
17394 else
17395 {
17396 next if($Path=~/local[\/\\]+include/);
17397 if($SystemRoot
17398 and $Path!~/\A\Q$SystemRoot\E(\/|\Z)/)
17399 { # The GCC include path for user headers is not a part of the system root
17400 # The reason: you are not specified the --cross-gcc option or selected a wrong compiler
17401 # or it is the internal cross-GCC path like arm-linux-gnueabi/include
17402 next;
17403 }
17404 $DPaths{"Inc"}{$Path}=1;
17405 }
17406 }
17407 }
17408 unlink("$TMP_DIR/empty.h");
17409 return %DPaths;
17410}
17411
17412sub detect_default_paths($)
17413{
17414 my ($HSearch, $LSearch, $BSearch, $GSearch) = (1, 1, 1, 1);
17415 my $Search = $_[0];
17416 if($Search!~/inc/) {
17417 $HSearch = 0;
17418 }
17419 if($Search!~/lib/) {
17420 $LSearch = 0;
17421 }
17422 if($Search!~/bin/) {
17423 $BSearch = 0;
17424 }
17425 if($Search!~/gcc/) {
17426 $GSearch = 0;
17427 }
17428 if(keys(%{$SystemPaths{"include"}}))
17429 { # <search_headers> section of the XML descriptor
17430 # do NOT search for systems headers
17431 $HSearch = 0;
17432 }
17433 if(keys(%{$SystemPaths{"lib"}}))
17434 { # <search_headers> section of the XML descriptor
17435 # do NOT search for systems headers
17436 $LSearch = 0;
17437 }
17438 foreach my $Type (keys(%{$OS_AddPath{$OSgroup}}))
17439 { # additional search paths
17440 next if($Type eq "include" and not $HSearch);
17441 next if($Type eq "lib" and not $LSearch);
17442 next if($Type eq "bin" and not $BSearch);
17443 foreach my $Path (keys(%{$OS_AddPath{$OSgroup}{$Type}}))
17444 {
17445 next if(not -d $Path);
17446 $SystemPaths{$Type}{$Path} = $OS_AddPath{$OSgroup}{$Type}{$Path};
17447 }
17448 }
17449 if($OSgroup ne "windows")
17450 { # unix-like
17451 foreach my $Type ("include", "lib", "bin")
17452 { # automatic detection of system "devel" directories
17453 next if($Type eq "include" and not $HSearch);
17454 next if($Type eq "lib" and not $LSearch);
17455 next if($Type eq "bin" and not $BSearch);
17456 my ($UsrDir, $RootDir) = ("/usr", "/");
17457 if($SystemRoot and $Type ne "bin")
17458 { # 1. search for target headers and libraries
17459 # 2. use host commands: ldconfig, readelf, etc.
17460 ($UsrDir, $RootDir) = ("$SystemRoot/usr", $SystemRoot);
17461 }
17462 foreach my $Path (cmd_find($RootDir,"d","*$Type*",1)) {
17463 $SystemPaths{$Type}{$Path} = 1;
17464 }
17465 if(-d $RootDir."/".$Type)
17466 { # if "/lib" is symbolic link
17467 if($RootDir eq "/") {
17468 $SystemPaths{$Type}{"/".$Type} = 1;
17469 }
17470 else {
17471 $SystemPaths{$Type}{$RootDir."/".$Type} = 1;
17472 }
17473 }
17474 if(-d $UsrDir) {
17475 foreach my $Path (cmd_find($UsrDir,"d","*$Type*",1)) {
17476 $SystemPaths{$Type}{$Path} = 1;
17477 }
17478 if(-d $UsrDir."/".$Type)
17479 { # if "/usr/lib" is symbolic link
17480 $SystemPaths{$Type}{$UsrDir."/".$Type} = 1;
17481 }
17482 }
17483 }
17484 }
17485 if($BSearch)
17486 {
17487 detect_bin_default_paths();
17488 foreach my $Path (keys(%DefaultBinPaths)) {
17489 $SystemPaths{"bin"}{$Path} = $DefaultBinPaths{$Path};
17490 }
17491 }
17492 # check environment variables
17493 if($OSgroup eq "beos")
17494 {
17495 foreach (keys(%{$SystemPaths{"bin"}}))
17496 {
17497 if($_ eq ".") {
17498 next;
17499 }
17500 foreach my $Path (cmd_find($_, "d", "bin", ""))
17501 { # search for /boot/develop/abi/x86/gcc4/tools/gcc-4.4.4-haiku-101111/bin/
17502 $SystemPaths{"bin"}{$Path} = 1;
17503 }
17504 }
17505 if($HSearch)
17506 {
17507 foreach my $Path (split(/:|;/, $ENV{"BEINCLUDES"}))
17508 {
17509 if(is_abs($Path)) {
17510 $DefaultIncPaths{$Path} = 1;
17511 }
17512 }
17513 }
17514 if($LSearch)
17515 {
17516 foreach my $Path (split(/:|;/, $ENV{"BELIBRARIES"}), split(/:|;/, $ENV{"LIBRARY_PATH"}))
17517 {
17518 if(is_abs($Path)) {
17519 $DefaultLibPaths{$Path} = 1;
17520 }
17521 }
17522 }
17523 }
17524 if($LSearch)
17525 { # using linker to get system paths
17526 if(my $LPaths = detect_lib_default_paths())
17527 { # unix-like
17528 foreach my $Name (keys(%{$LPaths}))
17529 {
17530 if($SystemRoot
17531 and $LPaths->{$Name}!~/\A\Q$SystemRoot\E\//)
17532 { # wrong ldconfig configuration
17533 # check your <sysroot>/etc/ld.so.conf
17534 next;
17535 }
17536 $DyLib_DefaultPath{$Name} = $LPaths->{$Name};
17537 $DefaultLibPaths{get_dirname($LPaths->{$Name})} = 1;
17538 }
17539 }
17540 foreach my $Path (keys(%DefaultLibPaths)) {
17541 $SystemPaths{"lib"}{$Path} = $DefaultLibPaths{$Path};
17542 }
17543 }
17544 if($BSearch)
17545 {
17546 if($CrossGcc)
17547 { # --cross-gcc=arm-linux-gcc
17548 if(-e $CrossGcc)
17549 { # absolute or relative path
17550 $GCC_PATH = get_abs_path($CrossGcc);
17551 }
17552 elsif($CrossGcc!~/\// and get_CmdPath($CrossGcc))
17553 { # command name
17554 $GCC_PATH = $CrossGcc;
17555 }
17556 else {
17557 exitStatus("Access_Error", "can't access \'$CrossGcc\'");
17558 }
17559 if($GCC_PATH=~/\s/) {
17560 $GCC_PATH = "\"".$GCC_PATH."\"";
17561 }
17562 }
17563 }
17564 if($GSearch)
17565 { # GCC path and default include dirs
17566 if(not $CrossGcc) {
17567 $GCC_PATH = get_CmdPath("gcc");
17568 }
17569 if(not $GCC_PATH) {
17570 exitStatus("Not_Found", "can't find GCC>=3.0 in PATH");
17571 }
17572 if(not $CheckObjectsOnly_Opt)
17573 {
17574 if(my $GCC_Ver = get_dumpversion($GCC_PATH))
17575 {
17576 my $GccTarget = get_dumpmachine($GCC_PATH);
17577 printMsg("INFO", "Using GCC $GCC_Ver ($GccTarget)");
17578 if($GccTarget=~/symbian/)
17579 {
17580 $OStarget = "symbian";
17581 $LIB_EXT = $OS_LibExt{$LIB_TYPE}{$OStarget};
17582 }
17583 }
17584 else {
17585 exitStatus("Error", "something is going wrong with the GCC compiler");
17586 }
17587 }
17588 if(not $NoStdInc)
17589 { # do NOT search in GCC standard paths
17590 my %DPaths = detect_inc_default_paths();
17591 %DefaultCppPaths = %{$DPaths{"Cpp"}};
17592 %DefaultGccPaths = %{$DPaths{"Gcc"}};
17593 %DefaultIncPaths = %{$DPaths{"Inc"}};
17594 foreach my $Path (keys(%DefaultIncPaths)) {
17595 $SystemPaths{"include"}{$Path} = $DefaultIncPaths{$Path};
17596 }
17597 }
17598 }
17599 if($HSearch)
17600 { # user include paths
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040017601 my $IncPath = "/usr/include";
17602 if($SystemRoot) {
17603 $IncPath = $SystemRoot.$IncPath;
17604 }
17605 if(-d $IncPath) {
17606 $UserIncPath{$IncPath}=1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017607 }
17608 }
17609}
17610
17611sub getLIB_EXT($)
17612{
17613 my $Target = $_[0];
17614 if(my $Ext = $OS_LibExt{$LIB_TYPE}{$Target}) {
17615 return $Ext;
17616 }
17617 return $OS_LibExt{$LIB_TYPE}{"default"};
17618}
17619
17620sub getAR_EXT($)
17621{
17622 my $Target = $_[0];
17623 if(my $Ext = $OS_Archive{$Target}) {
17624 return $Ext;
17625 }
17626 return $OS_Archive{"default"};
17627}
17628
17629sub get_dumpversion($)
17630{
17631 my $Cmd = $_[0];
17632 return "" if(not $Cmd);
17633 if($Cache{"get_dumpversion"}{$Cmd}) {
17634 return $Cache{"get_dumpversion"}{$Cmd};
17635 }
Andrey Ponomarenkoa01311b2012-06-08 17:20:02 +040017636 my $V = `$Cmd -dumpversion 2>\"$TMP_DIR/null\"`;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017637 chomp($V);
17638 return ($Cache{"get_dumpversion"}{$Cmd} = $V);
17639}
17640
17641sub get_dumpmachine($)
17642{
17643 my $Cmd = $_[0];
17644 return "" if(not $Cmd);
17645 if($Cache{"get_dumpmachine"}{$Cmd}) {
17646 return $Cache{"get_dumpmachine"}{$Cmd};
17647 }
Andrey Ponomarenkoa01311b2012-06-08 17:20:02 +040017648 my $Machine = `$Cmd -dumpmachine 2>\"$TMP_DIR/null\"`;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017649 chomp($Machine);
17650 return ($Cache{"get_dumpmachine"}{$Cmd} = $Machine);
17651}
17652
17653sub check_command($)
17654{
17655 my $Cmd = $_[0];
17656 return "" if(not $Cmd);
17657 my @Options = (
17658 "--version",
17659 "-help"
17660 );
17661 foreach my $Opt (@Options)
17662 {
Andrey Ponomarenkoa01311b2012-06-08 17:20:02 +040017663 my $Info = `$Cmd $Opt 2>\"$TMP_DIR/null\"`;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017664 if($Info) {
17665 return 1;
17666 }
17667 }
17668 return 0;
17669}
17670
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040017671sub check_gcc($$)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017672{
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040017673 my ($Cmd, $ReqVer) = @_;
17674 return 0 if(not $Cmd or not $ReqVer);
17675 if(defined $Cache{"check_gcc"}{$Cmd}{$ReqVer}) {
17676 return $Cache{"check_gcc"}{$Cmd}{$ReqVer};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017677 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040017678 if(my $GccVer = get_dumpversion($Cmd))
17679 {
17680 $GccVer=~s/(-|_)[a-z_]+.*\Z//; # remove suffix (like "-haiku-100818")
17681 if(cmpVersions($GccVer, $ReqVer)>=0) {
17682 return ($Cache{"check_gcc"}{$Cmd}{$ReqVer} = $Cmd);
17683 }
17684 }
17685 return ($Cache{"check_gcc"}{$Cmd}{$ReqVer} = "");
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017686}
17687
17688sub get_depth($)
17689{
17690 if(defined $Cache{"get_depth"}{$_[0]}) {
17691 return $Cache{"get_depth"}{$_[0]}
17692 }
17693 return ($Cache{"get_depth"}{$_[0]} = ($_[0]=~tr![\/\\]|\:\:!!));
17694}
17695
17696sub find_gcc_cxx_headers($)
17697{
17698 my $LibVersion = $_[0];
17699 return if($Cache{"find_gcc_cxx_headers"});# this function should be called once
17700 # detecting system header paths
17701 foreach my $Path (sort {get_depth($b) <=> get_depth($a)} keys(%DefaultGccPaths))
17702 {
17703 foreach my $HeaderPath (sort {get_depth($a) <=> get_depth($b)} cmd_find($Path,"f","",""))
17704 {
17705 my $FileName = get_filename($HeaderPath);
17706 next if($DefaultGccHeader{$FileName});
17707 $DefaultGccHeader{$FileName} = $HeaderPath;
17708 }
17709 }
17710 if($COMMON_LANGUAGE{$LibVersion} eq "C++" and not $STDCXX_TESTING)
17711 {
17712 foreach my $CppDir (sort {get_depth($b)<=>get_depth($a)} keys(%DefaultCppPaths))
17713 {
17714 my @AllCppHeaders = cmd_find($CppDir,"f","","");
17715 foreach my $Path (sort {get_depth($a)<=>get_depth($b)} @AllCppHeaders)
17716 {
17717 my $FileName = get_filename($Path);
17718 next if($DefaultCppHeader{$FileName});
17719 $DefaultCppHeader{$FileName} = $Path;
17720 }
17721 }
17722 }
17723 $Cache{"find_gcc_cxx_headers"} = 1;
17724}
17725
17726sub parse_libname($$$)
17727{
17728 my ($Name, $Type, $Target) = @_;
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040017729 if(not $Name) {
17730 return "";
17731 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017732 if($Target eq "symbian") {
17733 return parse_libname_symbian($Name, $Type);
17734 }
17735 elsif($Target eq "windows") {
17736 return parse_libname_windows($Name, $Type);
17737 }
17738 my $Ext = getLIB_EXT($Target);
Andrey Ponomarenkoa01311b2012-06-08 17:20:02 +040017739 if($Name=~/((((lib|).+?)([\-\_][\d\-\.\_]+.*?|))\.$Ext)(\.(.+)|)\Z/)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017740 { # libSDL-1.2.so.0.7.1
17741 # libwbxml2.so.0.0.18
Andrey Ponomarenkoa01311b2012-06-08 17:20:02 +040017742 # libopcodes-2.21.53-system.20110810.so
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017743 if($Type eq "name")
17744 { # libSDL-1.2
17745 # libwbxml2
17746 return $2;
17747 }
17748 elsif($Type eq "name+ext")
17749 { # libSDL-1.2.so
17750 # libwbxml2.so
17751 return $1;
17752 }
17753 elsif($Type eq "version")
17754 {
Andrey Ponomarenkoa01311b2012-06-08 17:20:02 +040017755 if(defined $7
17756 and $7 ne "")
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017757 { # 0.7.1
17758 return $7;
17759 }
17760 else
17761 { # libc-2.5.so (=>2.5 version)
17762 my $MV = $5;
17763 $MV=~s/\A[\-\_]+//g;
17764 return $MV;
17765 }
17766 }
17767 elsif($Type eq "short")
17768 { # libSDL
17769 # libwbxml2
17770 return $3;
17771 }
17772 elsif($Type eq "shortest")
17773 { # SDL
17774 # wbxml
17775 return shortest_name($3);
17776 }
17777 }
17778 return "";# error
17779}
17780
17781sub parse_libname_symbian($$)
17782{
17783 my ($Name, $Type) = @_;
17784 my $Ext = getLIB_EXT("symbian");
17785 if($Name=~/(((.+?)(\{.+\}|))\.$Ext)\Z/)
17786 { # libpthread{00010001}.dso
17787 if($Type eq "name")
17788 { # libpthread{00010001}
17789 return $2;
17790 }
17791 elsif($Type eq "name+ext")
17792 { # libpthread{00010001}.dso
17793 return $1;
17794 }
17795 elsif($Type eq "version")
17796 { # 00010001
17797 my $V = $4;
17798 $V=~s/\{(.+)\}/$1/;
17799 return $V;
17800 }
17801 elsif($Type eq "short")
17802 { # libpthread
17803 return $3;
17804 }
17805 elsif($Type eq "shortest")
17806 { # pthread
17807 return shortest_name($3);
17808 }
17809 }
17810 return "";# error
17811}
17812
17813sub parse_libname_windows($$)
17814{
17815 my ($Name, $Type) = @_;
17816 my $Ext = getLIB_EXT("windows");
17817 if($Name=~/((.+?)\.$Ext)\Z/)
17818 { # netapi32.dll
17819 if($Type eq "name")
17820 { # netapi32
17821 return $2;
17822 }
17823 elsif($Type eq "name+ext")
17824 { # netapi32.dll
17825 return $1;
17826 }
17827 elsif($Type eq "version")
17828 { # DLL version embedded
17829 # at binary-level
17830 return "";
17831 }
17832 elsif($Type eq "short")
17833 { # netapi32
17834 return $2;
17835 }
17836 elsif($Type eq "shortest")
17837 { # netapi
17838 return shortest_name($2);
17839 }
17840 }
17841 return "";# error
17842}
17843
17844sub shortest_name($)
17845{
17846 my $Name = $_[0];
17847 # remove prefix
17848 $Name=~s/\A(lib|open)//;
17849 # remove suffix
17850 $Name=~s/[\W\d_]+\Z//i;
17851 $Name=~s/([a-z]{2,})(lib)\Z/$1/i;
17852 return $Name;
17853}
17854
17855sub getPrefix($)
17856{
17857 my $Str = $_[0];
17858 if($Str=~/\A(Get|get|Set|set)([A-Z]|_)/)
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040017859 { # GetError
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017860 return "";
17861 }
17862 if($Str=~/\A([_]*[A-Z][a-z]{1,5})[A-Z]/)
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040017863 { # XmuValidArea: Xmu
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017864 return $1;
17865 }
17866 elsif($Str=~/\A([_]*[a-z]+)[A-Z]/)
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040017867 { # snfReadFont: snf
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017868 return $1;
17869 }
17870 elsif($Str=~/\A([_]*[A-Z]{2,})[A-Z][a-z]+([A-Z][a-z]+|\Z)/)
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040017871 { # XRRTimes: XRR
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017872 return $1;
17873 }
17874 elsif($Str=~/\A([_]*[a-z0-9]{2,}_)[a-z]+/i)
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040017875 { # alarm_event_add: alarm_
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017876 return $1;
17877 }
17878 elsif($Str=~/\A(([a-z])\2{1,})/i)
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040017879 { # ffopen
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017880 return $1;
17881 }
17882 else {
17883 return "";
17884 }
17885}
17886
17887sub problem_title($)
17888{
17889 if($_[0]==1) {
17890 return "1 problem";
17891 }
17892 else {
17893 return $_[0]." problems";
17894 }
17895}
17896
17897sub warning_title($)
17898{
17899 if($_[0]==1) {
17900 return "1 warning";
17901 }
17902 else {
17903 return $_[0]." warnings";
17904 }
17905}
17906
17907sub createSymbolsList($$$$$)
17908{
17909 my ($DPath, $SaveTo, $LName, $LVersion, $ArchName) = @_;
17910 read_ABI_Dump(1, $DPath);
17911 if(not $CheckObjectsOnly) {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040017912 prepareSymbols(1);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017913 }
17914 my %SymbolHeaderLib = ();
17915 my $Total = 0;
17916 # Get List
17917 foreach my $Symbol (sort keys(%{$CompleteSignature{1}}))
17918 {
17919 if(not link_symbol($Symbol, 1, "-Deps"))
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040017920 { # skip src only and all external functions
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017921 next;
17922 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040017923 if(not symbolFilter($Symbol, 1, "Public", "Binary"))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017924 { # skip other symbols
17925 next;
17926 }
17927 my $HeaderName = $CompleteSignature{1}{$Symbol}{"Header"};
17928 if(not $HeaderName)
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040017929 { # skip src only and all external functions
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017930 next;
17931 }
17932 my $DyLib = $Symbol_Library{1}{$Symbol};
17933 if(not $DyLib)
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040017934 { # skip src only and all external functions
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017935 next;
17936 }
17937 $SymbolHeaderLib{$HeaderName}{$DyLib}{$Symbol} = 1;
17938 $Total+=1;
17939 }
17940 # Draw List
17941 my $SYMBOLS_LIST = "<h1>Public symbols in <span style='color:Blue;'>$LName</span> (<span style='color:Red;'>$LVersion</span>)";
17942 $SYMBOLS_LIST .= " on <span style='color:Blue;'>".showArch($ArchName)."</span><br/>Total: $Total</h1><br/>";
17943 foreach my $HeaderName (sort {lc($a) cmp lc($b)} keys(%SymbolHeaderLib))
17944 {
17945 foreach my $DyLib (sort {lc($a) cmp lc($b)} keys(%{$SymbolHeaderLib{$HeaderName}}))
17946 {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017947 my %NS_Symbol = ();
17948 foreach my $Symbol (keys(%{$SymbolHeaderLib{$HeaderName}{$DyLib}})) {
17949 $NS_Symbol{get_IntNameSpace($Symbol, 1)}{$Symbol} = 1;
17950 }
17951 foreach my $NameSpace (sort keys(%NS_Symbol))
17952 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040017953 $SYMBOLS_LIST .= getTitle($HeaderName, $DyLib, $NameSpace);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017954 my @SortedInterfaces = sort {lc(get_Signature($a, 1)) cmp lc(get_Signature($b, 1))} keys(%{$NS_Symbol{$NameSpace}});
17955 foreach my $Symbol (@SortedInterfaces)
17956 {
17957 my $SubReport = "";
17958 my $Signature = get_Signature($Symbol, 1);
17959 if($NameSpace) {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040017960 $Signature=~s/\b\Q$NameSpace\E::\b//g;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017961 }
17962 if($Symbol=~/\A(_Z|\?)/)
17963 {
17964 if($Signature) {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040017965 $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 +040017966 }# report_added
17967 else {
17968 $SubReport = "<span class='iname'>".$Symbol."</span><br/>\n";
17969 }
17970 }
17971 else
17972 {
17973 if($Signature) {
17974 $SubReport = "<span class='iname'>".highLight_Signature_Italic_Color($Signature)."</span><br/>\n";
17975 }
17976 else {
17977 $SubReport = "<span class='iname'>".$Symbol."</span><br/>\n";
17978 }
17979 }
17980 $SYMBOLS_LIST .= $SubReport;
17981 }
17982 }
17983 $SYMBOLS_LIST .= "<br/>\n";
17984 }
17985 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040017986 # clear info
17987 (%TypeInfo, %SymbolInfo, %Library_Symbol, %DepSymbol_Library,
17988 %DepLibrary_Symbol, %SymVer, %SkipTypes, %SkipSymbols,
17989 %NestedNameSpaces, %ClassMethods, %AllocableClass, %ClassNames,
17990 %CompleteSignature, %SkipNameSpaces, %Symbol_Library, %Library_Symbol) = ();
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017991 ($Content_Counter, $ContentID) = (0, 0);
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040017992 # print report
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040017993 my $CssStyles = readModule("Styles", "SymbolsList.css");
17994 my $JScripts = readModule("Scripts", "Sections.js");
17995 $SYMBOLS_LIST = "<a name='Top'></a>".$SYMBOLS_LIST.$TOP_REF."<br/>\n";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017996 my $Title = "$LName: public symbols";
17997 my $Keywords = "$LName, API, symbols";
17998 my $Description = "List of symbols in $LName ($LVersion) on ".showArch($ArchName);
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040017999 $SYMBOLS_LIST = composeHTML_Head($Title, $Keywords, $Description, $CssStyles, $JScripts)."
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040018000 <body><div>\n$SYMBOLS_LIST</div>
18001 <br/><br/><hr/>\n".getReportFooter($LName)."
18002 <div style='height:999px;'></div></body></html>";
18003 writeFile($SaveTo, $SYMBOLS_LIST);
18004}
18005
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040018006sub readModule($$)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040018007{
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040018008 my ($Module, $Name) = @_;
18009 my $Path = $MODULES_DIR."/Internals/$Module/".$Name;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040018010 if(not -f $Path) {
18011 exitStatus("Module_Error", "can't access \'$Path\'");
18012 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040018013 return readFile($Path);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040018014}
18015
18016sub is_target_lib($)
18017{
18018 my $LName = $_[0];
Andrey Ponomarenkoa01311b2012-06-08 17:20:02 +040018019 if(not $LName) {
18020 return 0;
18021 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040018022 if($TargetLibraryName
18023 and $LName!~/\Q$TargetLibraryName\E/) {
18024 return 0;
18025 }
18026 if(keys(%TargetLibs)
18027 and not $TargetLibs{$LName}
18028 and not $TargetLibs{parse_libname($LName, "name+ext", $OStarget)}) {
18029 return 0;
18030 }
18031 return 1;
18032}
18033
Andrey Ponomarenko85043792012-05-14 16:48:07 +040018034sub is_target_header($$)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040018035{ # --header, --headers-list
Andrey Ponomarenko85043792012-05-14 16:48:07 +040018036 my ($H, $V) = @_;
18037 if(keys(%{$TargetHeaders{$V}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040018038 {
Andrey Ponomarenko85043792012-05-14 16:48:07 +040018039 if($TargetHeaders{$V}{$H}) {
18040 return 1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040018041 }
18042 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +040018043 return 0;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040018044}
18045
18046sub checkVersionNum($$)
18047{
18048 my ($LibVersion, $Path) = @_;
18049 if(my $VerNum = $TargetVersion{$LibVersion}) {
18050 return $VerNum;
18051 }
18052 my $UsedAltDescr = 0;
18053 foreach my $Part (split(/\s*,\s*/, $Path))
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040018054 { # try to get version string from file path
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040018055 next if($Part=~/\.xml\Z/i);
18056 next if(isDump($Part));
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040018057 my $VerNum = "";
18058 if(parse_libname($Part, "name", $OStarget))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040018059 {
18060 $UsedAltDescr = 1;
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040018061 $VerNum = parse_libname($Part, "version", $OStarget);
18062 if(not $VerNum) {
18063 $VerNum = readStringVersion($Part);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040018064 }
18065 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040018066 elsif(is_header($Part, 2, $LibVersion) or -d $Part)
18067 {
18068 $UsedAltDescr = 1;
18069 $VerNum = readStringVersion($Part);
18070 }
18071 if($VerNum ne "")
18072 {
18073 $TargetVersion{$LibVersion} = $VerNum;
18074 if($DumpAPI) {
18075 printMsg("WARNING", "setting version number to $VerNum (use -vnum <num> option to change it)");
18076 }
18077 else {
18078 printMsg("WARNING", "setting ".($LibVersion==1?"1st":"2nd")." version number to \"$VerNum\" (use -v$LibVersion <num> option to change it)");
18079 }
18080 return $TargetVersion{$LibVersion};
18081 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040018082 }
18083 if($UsedAltDescr)
18084 {
18085 if($DumpAPI) {
18086 exitStatus("Error", "version number is not set (use -vnum <num> option)");
18087 }
18088 else {
18089 exitStatus("Error", ($LibVersion==1?"1st":"2nd")." version number is not set (use -v$LibVersion <num> option)");
18090 }
18091 }
18092}
18093
18094sub readStringVersion($)
18095{
18096 my $Str = $_[0];
18097 return "" if(not $Str);
18098 $Str=~s/\Q$TargetLibraryName\E//g;
18099 if($Str=~/(\/|\\|\w|\A)[\-\_]*(\d+[\d\.\-]+\d+|\d+)/)
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040018100 { # .../libssh-0.4.0/...
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040018101 return $2;
18102 }
18103 elsif(my $V = parse_libname($Str, "version", $OStarget)) {
18104 return $V;
18105 }
18106 return "";
18107}
18108
18109sub readLibs($)
18110{
18111 my $LibVersion = $_[0];
18112 if($OStarget eq "windows")
18113 { # dumpbin.exe will crash
18114 # without VS Environment
18115 check_win32_env();
18116 }
Andrey Ponomarenko16934472012-03-29 15:37:04 +040018117 readSymbols($LibVersion);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040018118 translateSymbols(keys(%{$Symbol_Library{$LibVersion}}), $LibVersion);
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040018119 translateSymbols(keys(%{$DepSymbol_Library{$LibVersion}}), $LibVersion);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040018120}
18121
18122sub dump_sorting($)
18123{
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +040018124 my $Hash = $_[0];
18125 return [] if(not $Hash);
18126 my @Keys = keys(%{$Hash});
18127 return [] if($#Keys<0);
18128 if($Keys[0]=~/\A\d+\Z/)
18129 { # numbers
18130 return [sort {int($a)<=>int($b)} @Keys];
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040018131 }
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +040018132 else
18133 { # strings
18134 return [sort {$a cmp $b} @Keys];
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040018135 }
18136}
18137
18138sub printMsg($$)
18139{
18140 my ($Type, $Msg) = @_;
18141 if($Type!~/\AINFO/) {
18142 $Msg = $Type.": ".$Msg;
18143 }
18144 if($Type!~/_C\Z/) {
18145 $Msg .= "\n";
18146 }
18147 if($Quiet)
18148 { # --quiet option
18149 appendFile($COMMON_LOG_PATH, $Msg);
18150 }
18151 else
18152 {
18153 if($Type eq "ERROR") {
18154 print STDERR $Msg;
18155 }
18156 else {
18157 print $Msg;
18158 }
18159 }
18160}
18161
18162sub exitStatus($$)
18163{
18164 my ($Code, $Msg) = @_;
18165 printMsg("ERROR", $Msg);
18166 exit($ERROR_CODE{$Code});
18167}
18168
18169sub exitReport()
18170{ # the tool has run without any errors
18171 printReport();
18172 if($COMPILE_ERRORS)
18173 { # errors in headers may add false positives/negatives
18174 exit($ERROR_CODE{"Compile_Error"});
18175 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040018176 if($BinaryOnly and $RESULT{"Binary"}{"Problems"})
18177 { # --binary
18178 exit($ERROR_CODE{"Incompatible"});
18179 }
18180 elsif($SourceOnly and $RESULT{"Source"}{"Problems"})
18181 { # --source
18182 exit($ERROR_CODE{"Incompatible"});
18183 }
18184 elsif($RESULT{"Source"}{"Problems"}
18185 or $RESULT{"Binary"}{"Problems"})
18186 { # default
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040018187 exit($ERROR_CODE{"Incompatible"});
18188 }
18189 else {
18190 exit($ERROR_CODE{"Compatible"});
18191 }
18192}
18193
18194sub readRules($)
18195{
18196 my $Kind = $_[0];
18197 if(not -f $RULES_PATH{$Kind}) {
18198 exitStatus("Module_Error", "can't access \'".$RULES_PATH{$Kind}."\'");
18199 }
18200 my $Content = readFile($RULES_PATH{$Kind});
18201 while(my $Rule = parseTag(\$Content, "rule"))
18202 {
18203 my $RId = parseTag(\$Rule, "id");
18204 my @Properties = ("Severity", "Change", "Effect", "Overcome", "Kind");
18205 foreach my $Prop (@Properties) {
18206 if(my $Value = parseTag(\$Rule, lc($Prop)))
18207 {
18208 $Value=~s/\n[ ]*//;
18209 $CompatRules{$Kind}{$RId}{$Prop} = $Value;
18210 }
18211 }
18212 if($CompatRules{$Kind}{$RId}{"Kind"}=~/\A(Symbols|Parameters)\Z/) {
18213 $CompatRules{$Kind}{$RId}{"Kind"} = "Symbols";
18214 }
18215 else {
18216 $CompatRules{$Kind}{$RId}{"Kind"} = "Types";
18217 }
18218 }
18219}
18220
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040018221sub getReportPath($)
18222{
18223 my $Level = $_[0];
18224 my $Dir = "compat_reports/$TargetLibraryName/".$Descriptor{1}{"Version"}."_to_".$Descriptor{2}{"Version"};
18225 if($Level eq "Binary")
18226 {
18227 if($BinaryReportPath)
18228 { # --bin-report-path
18229 return $BinaryReportPath;
18230 }
18231 elsif($OutputReportPath)
18232 { # --report-path
18233 return $OutputReportPath;
18234 }
18235 else
18236 { # default
18237 return $Dir."/abi_compat_report.$ReportFormat";
18238 }
18239 }
18240 elsif($Level eq "Source")
18241 {
18242 if($SourceReportPath)
18243 { # --src-report-path
18244 return $SourceReportPath;
18245 }
18246 elsif($OutputReportPath)
18247 { # --report-path
18248 return $OutputReportPath;
18249 }
18250 else
18251 { # default
18252 return $Dir."/src_compat_report.$ReportFormat";
18253 }
18254 }
18255 else
18256 {
18257 if($OutputReportPath)
18258 { # --report-path
18259 return $OutputReportPath;
18260 }
18261 else
18262 { # default
18263 return $Dir."/compat_report.$ReportFormat";
18264 }
18265 }
18266}
18267
18268sub printStatMsg($)
18269{
18270 my $Level = $_[0];
18271 printMsg("INFO", "total \"$Level\" compatibility problems: ".$RESULT{$Level}{"Problems"}.", warnings: ".$RESULT{$Level}{"Warnings"});
18272}
18273
18274sub listAffected($)
18275{
18276 my $Level = $_[0];
18277 my $List = "";
18278 foreach (keys(%{$TotalAffected{$Level}}))
18279 {
18280 if($StrictCompat and $TotalAffected{$Level}{$_} eq "Low")
18281 { # skip "Low"-severity problems
18282 next;
18283 }
18284 $List .= "$_\n";
18285 }
18286 my $Dir = get_dirname(getReportPath($Level));
18287 if($Level eq "Binary") {
18288 writeFile($Dir."/abi_affected.txt", $List);
18289 }
18290 elsif($Level eq "Source") {
18291 writeFile($Dir."/src_affected.txt", $List);
18292 }
18293}
18294
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040018295sub printReport()
18296{
18297 printMsg("INFO", "creating compatibility report ...");
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040018298 createReport();
18299 if($JoinReport or $DoubleReport)
18300 {
18301 if($RESULT{"Binary"}{"Problems"}
18302 or $RESULT{"Source"}{"Problems"}) {
18303 printMsg("INFO", "result: INCOMPATIBLE (Binary: ".$RESULT{"Binary"}{"Affected"}."\%, Source: ".$RESULT{"Source"}{"Affected"}."\%)");
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040018304 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040018305 else {
18306 printMsg("INFO", "result: COMPATIBLE");
18307 }
18308 printStatMsg("Binary");
18309 printStatMsg("Source");
18310 if($ListAffected)
18311 { # --list-affected
18312 listAffected("Binary");
18313 listAffected("Source");
18314 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040018315 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040018316 elsif($BinaryOnly)
18317 {
18318 if($RESULT{"Binary"}{"Problems"}) {
18319 printMsg("INFO", "result: INCOMPATIBLE (".$RESULT{"Binary"}{"Affected"}."\%)");
18320 }
18321 else {
18322 printMsg("INFO", "result: COMPATIBLE");
18323 }
18324 printStatMsg("Binary");
18325 if($ListAffected)
18326 { # --list-affected
18327 listAffected("Binary");
18328 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040018329 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040018330 elsif($SourceOnly)
18331 {
18332 if($RESULT{"Source"}{"Problems"}) {
18333 printMsg("INFO", "result: INCOMPATIBLE (".$RESULT{"Source"}{"Affected"}."\%)");
18334 }
18335 else {
18336 printMsg("INFO", "result: COMPATIBLE");
18337 }
18338 printStatMsg("Source");
18339 if($ListAffected)
18340 { # --list-affected
18341 listAffected("Source");
18342 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040018343 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040018344 if($StdOut)
18345 {
18346 if($JoinReport or not $DoubleReport)
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040018347 { # --binary or --source
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040018348 printMsg("INFO", "compatibility report has been generated to stdout");
18349 }
18350 else
18351 { # default
18352 printMsg("INFO", "compatibility reports have been generated to stdout");
18353 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040018354 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040018355 else
18356 {
18357 if($JoinReport)
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040018358 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040018359 printMsg("INFO", "see detailed report:\n ".getReportPath("Join"));
18360 }
18361 elsif($DoubleReport)
18362 { # default
18363 printMsg("INFO", "see detailed reports:\n ".getReportPath("Binary")."\n ".getReportPath("Source"));
18364 }
18365 elsif($BinaryOnly)
18366 { # --binary
18367 printMsg("INFO", "see detailed report:\n ".getReportPath("Binary"));
18368 }
18369 elsif($SourceOnly)
18370 { # --source
18371 printMsg("INFO", "see detailed report:\n ".getReportPath("Source"));
18372 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040018373 }
18374}
18375
18376sub check_win32_env()
18377{
18378 if(not $ENV{"DevEnvDir"}
18379 or not $ENV{"LIB"}) {
18380 exitStatus("Error", "can't start without VS environment (vsvars32.bat)");
18381 }
18382}
18383
18384sub create_ABI_Dump()
18385{
18386 if(not -e $DumpAPI) {
18387 exitStatus("Access_Error", "can't access \'$DumpAPI\'");
18388 }
18389 # check the archive utilities
18390 if($OSgroup eq "windows")
18391 { # using zip
18392 my $ZipCmd = get_CmdPath("zip");
18393 if(not $ZipCmd) {
18394 exitStatus("Not_Found", "can't find \"zip\"");
18395 }
18396 }
18397 else
18398 { # using tar and gzip
18399 my $TarCmd = get_CmdPath("tar");
18400 if(not $TarCmd) {
18401 exitStatus("Not_Found", "can't find \"tar\"");
18402 }
18403 my $GzipCmd = get_CmdPath("gzip");
18404 if(not $GzipCmd) {
18405 exitStatus("Not_Found", "can't find \"gzip\"");
18406 }
18407 }
18408 my @DParts = split(/\s*,\s*/, $DumpAPI);
18409 foreach my $Part (@DParts)
18410 {
18411 if(not -e $Part) {
18412 exitStatus("Access_Error", "can't access \'$Part\'");
18413 }
18414 }
18415 checkVersionNum(1, $DumpAPI);
18416 foreach my $Part (@DParts)
18417 {
18418 if(isDump($Part)) {
18419 read_ABI_Dump(1, $Part);
18420 }
18421 else {
18422 readDescriptor(1, createDescriptor(1, $Part));
18423 }
18424 }
18425 initLogging(1);
18426 detect_default_paths("inc|lib|bin|gcc"); # complete analysis
18427 if(not $CheckHeadersOnly) {
18428 readLibs(1);
18429 }
18430 if($CheckHeadersOnly) {
18431 setLanguage(1, "C++");
18432 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +040018433 if(not $CheckObjectsOnly) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040018434 searchForHeaders(1);
18435 }
18436 $WORD_SIZE{1} = detectWordSize();
18437 if($Descriptor{1}{"Headers"}
18438 and not $Descriptor{1}{"Dump"}) {
18439 readHeaders(1);
18440 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +040018441 cleanDump(1);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040018442 if(not keys(%{$SymbolInfo{1}}))
18443 { # check if created dump is valid
18444 if(not $ExtendedCheck and not $CheckObjectsOnly)
18445 {
18446 if($CheckHeadersOnly) {
18447 exitStatus("Empty_Set", "the set of public symbols is empty");
18448 }
18449 else {
18450 exitStatus("Empty_Intersection", "the sets of public symbols in headers and libraries have empty intersection");
18451 }
18452 }
18453 }
18454 my %HeadersInfo = ();
18455 foreach my $HPath (keys(%{$Registered_Headers{1}}))
18456 { # headers info stored without paths in the dump
18457 $HeadersInfo{$Registered_Headers{1}{$HPath}{"Identity"}} = $Registered_Headers{1}{$HPath}{"Pos"};
18458 }
18459 printMsg("INFO", "creating library ABI dump ...");
18460 my %LibraryABI = (
18461 "TypeInfo" => $TypeInfo{1},
18462 "SymbolInfo" => $SymbolInfo{1},
18463 "Symbols" => $Library_Symbol{1},
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040018464 "DepSymbols" => $DepLibrary_Symbol{1},
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040018465 "SymbolVersion" => $SymVer{1},
18466 "LibraryVersion" => $Descriptor{1}{"Version"},
18467 "LibraryName" => $TargetLibraryName,
18468 "Language" => $COMMON_LANGUAGE{1},
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040018469 "SkipTypes" => $SkipTypes{1},
18470 "SkipSymbols" => $SkipSymbols{1},
18471 "SkipNameSpaces" => $SkipNameSpaces{1},
18472 "SkipHeaders" => $SkipHeadersList{1},
18473 "TargetHeaders" => $TargetHeaders{1},
18474 "Headers" => \%HeadersInfo,
18475 "Constants" => $Constants{1},
18476 "NameSpaces" => $NestedNameSpaces{1},
18477 "Target" => $OStarget,
18478 "Arch" => getArch(1),
18479 "WordSize" => $WORD_SIZE{1},
18480 "GccVersion" => get_dumpversion($GCC_PATH),
18481 "ABI_DUMP_VERSION" => $ABI_DUMP_VERSION,
18482 "ABI_COMPLIANCE_CHECKER_VERSION" => $TOOL_VERSION
18483 );
18484 if($ExtendedCheck)
18485 { # --ext option
18486 $LibraryABI{"Mode"} = "Extended";
18487 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040018488 if($BinaryOnly)
18489 { # --binary
18490 $LibraryABI{"BinOnly"} = 1;
18491 }
18492 else
18493 { # default
18494 $LibraryABI{"SrcBin"} = 1;
18495 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +040018496
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040018497 if($StdOut)
18498 { # --stdout option
18499 print STDOUT Dumper(\%LibraryABI);
18500 printMsg("INFO", "ABI dump has been generated to stdout");
18501 return;
18502 }
18503 else
18504 { # write to gzipped file
18505 my $DumpPath = "abi_dumps/$TargetLibraryName/".$TargetLibraryName."_".$Descriptor{1}{"Version"}.".abi.".$AR_EXT;
18506 if($OutputDumpPath)
18507 { # user defined path
18508 $DumpPath = $OutputDumpPath;
18509 }
18510 if(not $DumpPath=~s/\Q.$AR_EXT\E\Z//g) {
18511 exitStatus("Error", "the dump path (-dump-path option) should be the path to a *.$AR_EXT file");
18512 }
18513 my ($DDir, $DName) = separate_path($DumpPath);
18514 my $DPath = $TMP_DIR."/".$DName;
18515 mkpath($DDir);
Andrey Ponomarenko85043792012-05-14 16:48:07 +040018516
18517 open(DUMP, ">", $DPath) || die ("can't open file \'$DPath\': $!\n");
18518 print DUMP Dumper(\%LibraryABI);
18519 close(DUMP);
18520
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040018521 if(not -s $DPath) {
18522 exitStatus("Error", "can't create ABI dump because something is going wrong with the Data::Dumper module");
18523 }
18524 my $Pkg = createArchive($DPath, $DDir);
18525 printMsg("INFO", "library ABI has been dumped to:\n $Pkg");
18526 printMsg("INFO", "you can transfer this dump everywhere and use instead of the ".$Descriptor{1}{"Version"}." version descriptor");
18527 }
18528}
18529
18530sub quickEmptyReports()
18531{ # Quick "empty" reports
18532 # 4 times faster than merging equal dumps
18533 # NOTE: the dump contains the "LibraryVersion" attribute
18534 # if you change the version, then your dump will be different
18535 # OVERCOME: use -v1 and v2 options for comparing dumps
18536 # and don't change version in the XML descriptor (and dumps)
18537 # OVERCOME 2: separate meta info from the dumps in ACC 2.0
18538 if(-s $Descriptor{1}{"Path"} == -s $Descriptor{2}{"Path"})
18539 {
18540 my $FilePath1 = unpackDump($Descriptor{1}{"Path"});
18541 my $FilePath2 = unpackDump($Descriptor{2}{"Path"});
18542 if($FilePath1 and $FilePath2)
18543 {
Andrey Ponomarenko85043792012-05-14 16:48:07 +040018544 local $/ = undef;
18545
18546 open(DUMP1, $FilePath1);
18547 my $Content1 = <DUMP1>;
18548 close(DUMP1);
18549
18550 open(DUMP2, $FilePath2);
18551 my $Content2 = <DUMP2>;
18552 close(DUMP2);
18553
18554 if($Content1 eq $Content2)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040018555 {
Andrey Ponomarenko85043792012-05-14 16:48:07 +040018556 # clean memory
18557 undef $Content2;
18558
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040018559 # read a number of headers, libs, symbols and types
Andrey Ponomarenko85043792012-05-14 16:48:07 +040018560 my $ABIdump = eval($Content1);
18561
18562 # clean memory
18563 undef $Content1;
18564
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040018565 if(not $ABIdump) {
18566 exitStatus("Error", "internal error");
18567 }
18568 if(not $ABIdump->{"TypeInfo"})
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040018569 { # support for old dumps
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040018570 $ABIdump->{"TypeInfo"} = $ABIdump->{"TypeDescr"};
18571 }
18572 if(not $ABIdump->{"SymbolInfo"})
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040018573 { # support for old dumps
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040018574 $ABIdump->{"SymbolInfo"} = $ABIdump->{"FuncDescr"};
18575 }
18576 read_Headers_DumpInfo($ABIdump, 1);
18577 read_Libs_DumpInfo($ABIdump, 1);
18578 read_Machine_DumpInfo($ABIdump, 1);
18579 read_Machine_DumpInfo($ABIdump, 2);
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040018580
18581 %{$CheckedTypes{"Binary"}} = %{$ABIdump->{"TypeInfo"}};
18582 %{$CheckedTypes{"Source"}} = %{$ABIdump->{"TypeInfo"}};
18583
18584 %{$CheckedSymbols{"Binary"}} = %{$ABIdump->{"SymbolInfo"}};
18585 %{$CheckedSymbols{"Source"}} = %{$ABIdump->{"SymbolInfo"}};
18586
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040018587 $Descriptor{1}{"Version"} = $TargetVersion{1}?$TargetVersion{1}:$ABIdump->{"LibraryVersion"};
18588 $Descriptor{2}{"Version"} = $TargetVersion{2}?$TargetVersion{2}:$ABIdump->{"LibraryVersion"};
18589 exitReport();
18590 }
18591 }
18592 }
18593}
18594
18595sub initLogging($)
18596{
18597 my $LibVersion = $_[0];
18598 # create log directory
18599 my ($LOG_DIR, $LOG_FILE) = ("logs/$TargetLibraryName/".$Descriptor{$LibVersion}{"Version"}, "log.txt");
18600 if($OutputLogPath{$LibVersion})
18601 { # user-defined by -log-path option
18602 ($LOG_DIR, $LOG_FILE) = separate_path($OutputLogPath{$LibVersion});
18603 }
18604 if($LogMode ne "n") {
18605 mkpath($LOG_DIR);
18606 }
18607 $LOG_PATH{$LibVersion} = get_abs_path($LOG_DIR)."/".$LOG_FILE;
18608 resetLogging($LibVersion);
18609 if($Debug)
18610 { # debug directory
18611 $DEBUG_PATH{$LibVersion} = "debug/$TargetLibraryName/".$Descriptor{$LibVersion}{"Version"};
18612 rmtree($DEBUG_PATH{$LibVersion});
18613 }
18614}
18615
18616sub writeLog($$)
18617{
18618 my ($LibVersion, $Msg) = @_;
18619 if($LogMode ne "n") {
18620 appendFile($LOG_PATH{$LibVersion}, $Msg);
18621 }
18622}
18623
18624sub resetLogging($)
18625{
18626 my $LibVersion = $_[0];
18627 if($LogMode!~/a|n/)
18628 { # remove old log
18629 unlink($LOG_PATH{$LibVersion});
18630 }
18631}
18632
18633sub printErrorLog($)
18634{
18635 my $LibVersion = $_[0];
18636 if($LogMode ne "n") {
18637 printMsg("ERROR", "see log for details:\n ".$LOG_PATH{$LibVersion}."\n");
18638 }
18639}
18640
18641sub isDump($)
18642{
18643 if(get_filename($_[0])=~/\A(.+)\.abi(\Q.tar.gz\E|\Q.zip\E|)\Z/)
18644 { # returns a name of package
18645 return $1;
18646 }
18647 return 0;
18648}
18649
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040018650sub compareInit()
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040018651{
18652 # read input XML descriptors or ABI dumps
18653 if(not $Descriptor{1}{"Path"}) {
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040018654 exitStatus("Error", "-old option is not specified");
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040018655 }
18656 my @DParts1 = split(/\s*,\s*/, $Descriptor{1}{"Path"});
18657 foreach my $Part (@DParts1)
18658 {
18659 if(not -e $Part) {
18660 exitStatus("Access_Error", "can't access \'$Part\'");
18661 }
18662 }
18663 if(not $Descriptor{2}{"Path"}) {
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040018664 exitStatus("Error", "-new option is not specified");
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040018665 }
18666 my @DParts2 = split(/\s*,\s*/, $Descriptor{2}{"Path"});
18667 foreach my $Part (@DParts2)
18668 {
18669 if(not -e $Part) {
18670 exitStatus("Access_Error", "can't access \'$Part\'");
18671 }
18672 }
18673 detect_default_paths("bin"); # to extract dumps
18674 if($#DParts1==0 and $#DParts2==0
18675 and isDump($Descriptor{1}{"Path"})
18676 and isDump($Descriptor{2}{"Path"}))
18677 { # optimization: equal ABI dumps
18678 quickEmptyReports();
18679 }
18680 checkVersionNum(1, $Descriptor{1}{"Path"});
18681 checkVersionNum(2, $Descriptor{2}{"Path"});
18682 printMsg("INFO", "preparation, please wait ...");
18683 foreach my $Part (@DParts1)
18684 {
18685 if(isDump($Part)) {
18686 read_ABI_Dump(1, $Part);
18687 }
18688 else {
18689 readDescriptor(1, createDescriptor(1, $Part));
18690 }
18691 }
18692 foreach my $Part (@DParts2)
18693 {
18694 if(isDump($Part)) {
18695 read_ABI_Dump(2, $Part);
18696 }
18697 else {
18698 readDescriptor(2, createDescriptor(2, $Part));
18699 }
18700 }
18701 initLogging(1);
18702 initLogging(2);
18703 # check consistency
18704 if(not $Descriptor{1}{"Headers"}
18705 and not $Descriptor{1}{"Libs"}) {
18706 exitStatus("Error", "descriptor d1 does not contain both header files and libraries info");
18707 }
18708 if(not $Descriptor{2}{"Headers"}
18709 and not $Descriptor{2}{"Libs"}) {
18710 exitStatus("Error", "descriptor d2 does not contain both header files and libraries info");
18711 }
18712 if($Descriptor{1}{"Headers"} and not $Descriptor{1}{"Libs"}
18713 and not $Descriptor{2}{"Headers"} and $Descriptor{2}{"Libs"}) {
18714 exitStatus("Error", "can't compare headers with $SLIB_TYPE libraries");
18715 }
18716 elsif(not $Descriptor{1}{"Headers"} and $Descriptor{1}{"Libs"}
18717 and $Descriptor{2}{"Headers"} and not $Descriptor{2}{"Libs"}) {
18718 exitStatus("Error", "can't compare $SLIB_TYPE libraries with headers");
18719 }
18720 if(not $Descriptor{1}{"Headers"}) {
18721 if($CheckHeadersOnly_Opt) {
18722 exitStatus("Error", "can't find header files info in descriptor d1");
18723 }
18724 }
18725 if(not $Descriptor{2}{"Headers"}) {
18726 if($CheckHeadersOnly_Opt) {
18727 exitStatus("Error", "can't find header files info in descriptor d2");
18728 }
18729 }
18730 if(not $Descriptor{1}{"Headers"}
18731 or not $Descriptor{2}{"Headers"}) {
18732 if(not $CheckObjectsOnly_Opt) {
18733 printMsg("WARNING", "comparing $SLIB_TYPE libraries only");
18734 $CheckObjectsOnly = 1;
18735 }
18736 }
18737 if(not $Descriptor{1}{"Libs"}) {
18738 if($CheckObjectsOnly_Opt) {
18739 exitStatus("Error", "can't find $SLIB_TYPE libraries info in descriptor d1");
18740 }
18741 }
18742 if(not $Descriptor{2}{"Libs"}) {
18743 if($CheckObjectsOnly_Opt) {
18744 exitStatus("Error", "can't find $SLIB_TYPE libraries info in descriptor d2");
18745 }
18746 }
18747 if(not $Descriptor{1}{"Libs"}
18748 or not $Descriptor{2}{"Libs"})
18749 { # comparing standalone header files
18750 # comparing ABI dumps created with --headers-only
18751 if(not $CheckHeadersOnly_Opt)
18752 {
18753 printMsg("WARNING", "checking headers only");
18754 $CheckHeadersOnly = 1;
18755 }
18756 }
18757 if($UseDumps)
18758 { # --use-dumps
18759 # parallel processing
18760 my $pid = fork();
18761 if($pid)
18762 { # dump on two CPU cores
18763 my @PARAMS = ("-dump", $Descriptor{1}{"Path"}, "-l", $TargetLibraryName);
18764 if($RelativeDirectory{1}) {
18765 @PARAMS = (@PARAMS, "-relpath", $RelativeDirectory{1});
18766 }
18767 if($OutputLogPath{1}) {
18768 @PARAMS = (@PARAMS, "-log-path", $OutputLogPath{1});
18769 }
18770 if($CrossGcc) {
18771 @PARAMS = (@PARAMS, "-cross-gcc", $CrossGcc);
18772 }
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040018773 if($Quiet)
18774 {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040018775 @PARAMS = (@PARAMS, "-quiet");
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040018776 @PARAMS = (@PARAMS, "-logging-mode", "a");
18777 }
18778 elsif($LogMode and $LogMode ne "w")
18779 { # "w" is default
18780 @PARAMS = (@PARAMS, "-logging-mode", $LogMode);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040018781 }
18782 if($ExtendedCheck) {
18783 @PARAMS = (@PARAMS, "-extended");
18784 }
18785 if($UserLang) {
18786 @PARAMS = (@PARAMS, "-lang", $UserLang);
18787 }
18788 if($TargetVersion{1}) {
18789 @PARAMS = (@PARAMS, "-vnum", $TargetVersion{1});
18790 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +040018791 if($BinaryOnly) {
18792 @PARAMS = (@PARAMS, "-binary");
18793 }
18794 if($SourceOnly) {
18795 @PARAMS = (@PARAMS, "-source");
18796 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040018797 if($SortDump) {
18798 @PARAMS = (@PARAMS, "-sort");
18799 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +040018800 if($Debug)
18801 {
18802 @PARAMS = (@PARAMS, "-debug");
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040018803 printMsg("INFO", "running perl $0 @PARAMS");
Andrey Ponomarenko85043792012-05-14 16:48:07 +040018804 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040018805 system("perl", $0, @PARAMS);
18806 if($?) {
18807 exit(1);
18808 }
18809 }
18810 else
18811 { # child
18812 my @PARAMS = ("-dump", $Descriptor{2}{"Path"}, "-l", $TargetLibraryName);
18813 if($RelativeDirectory{2}) {
18814 @PARAMS = (@PARAMS, "-relpath", $RelativeDirectory{2});
18815 }
18816 if($OutputLogPath{2}) {
18817 @PARAMS = (@PARAMS, "-log-path", $OutputLogPath{2});
18818 }
18819 if($CrossGcc) {
18820 @PARAMS = (@PARAMS, "-cross-gcc", $CrossGcc);
18821 }
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040018822 if($Quiet)
18823 {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040018824 @PARAMS = (@PARAMS, "-quiet");
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040018825 @PARAMS = (@PARAMS, "-logging-mode", "a");
18826 }
18827 elsif($LogMode and $LogMode ne "w")
18828 { # "w" is default
18829 @PARAMS = (@PARAMS, "-logging-mode", $LogMode);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040018830 }
18831 if($ExtendedCheck) {
18832 @PARAMS = (@PARAMS, "-extended");
18833 }
18834 if($UserLang) {
18835 @PARAMS = (@PARAMS, "-lang", $UserLang);
18836 }
18837 if($TargetVersion{2}) {
18838 @PARAMS = (@PARAMS, "-vnum", $TargetVersion{2});
18839 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +040018840 if($BinaryOnly) {
18841 @PARAMS = (@PARAMS, "-binary");
18842 }
18843 if($SourceOnly) {
18844 @PARAMS = (@PARAMS, "-source");
18845 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040018846 if($SortDump) {
18847 @PARAMS = (@PARAMS, "-sort");
18848 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +040018849 if($Debug)
18850 {
18851 @PARAMS = (@PARAMS, "-debug");
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040018852 printMsg("INFO", "running perl $0 @PARAMS");
Andrey Ponomarenko85043792012-05-14 16:48:07 +040018853 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040018854 system("perl", $0, @PARAMS);
18855 if($?) {
18856 exit(1);
18857 }
18858 else {
18859 exit(0);
18860 }
18861 }
18862 waitpid($pid, 0);
18863 my @CMP_PARAMS = ("-l", $TargetLibraryName);
18864 @CMP_PARAMS = (@CMP_PARAMS, "-d1", "abi_dumps/$TargetLibraryName/".$TargetLibraryName."_".$Descriptor{1}{"Version"}.".abi.$AR_EXT");
18865 @CMP_PARAMS = (@CMP_PARAMS, "-d2", "abi_dumps/$TargetLibraryName/".$TargetLibraryName."_".$Descriptor{2}{"Version"}.".abi.$AR_EXT");
18866 if($TargetLibraryFName ne $TargetLibraryName) {
18867 @CMP_PARAMS = (@CMP_PARAMS, "-l-full", $TargetLibraryFName);
18868 }
18869 if($ShowRetVal) {
18870 @CMP_PARAMS = (@CMP_PARAMS, "-show-retval");
18871 }
18872 if($CrossGcc) {
18873 @CMP_PARAMS = (@CMP_PARAMS, "-cross-gcc", $CrossGcc);
18874 }
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040018875 if($Quiet)
18876 {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040018877 @CMP_PARAMS = (@CMP_PARAMS, "-quiet");
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040018878 @CMP_PARAMS = (@CMP_PARAMS, "-logging-mode", "a");
18879 }
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040018880 elsif($LogMode and $LogMode ne "w")
18881 { # "w" is default
18882 @CMP_PARAMS = (@CMP_PARAMS, "-logging-mode", $LogMode);
18883 }
18884 if($ReportFormat and $ReportFormat ne "html")
18885 { # HTML is default format
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040018886 @CMP_PARAMS = (@CMP_PARAMS, "-report-format", $ReportFormat);
18887 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040018888 if($OutputReportPath) {
18889 @CMP_PARAMS = (@CMP_PARAMS, "-report-path", $OutputReportPath);
18890 }
18891 if($BinaryReportPath) {
18892 @CMP_PARAMS = (@CMP_PARAMS, "-bin-report-path", $BinaryReportPath);
18893 }
18894 if($SourceReportPath) {
18895 @CMP_PARAMS = (@CMP_PARAMS, "-src-report-path", $SourceReportPath);
18896 }
18897 if($LoggingPath) {
18898 @CMP_PARAMS = (@CMP_PARAMS, "-log-path", $LoggingPath);
18899 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +040018900 if($Browse) {
18901 @CMP_PARAMS = (@CMP_PARAMS, "-browse", $Browse);
18902 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040018903 if($OpenReport) {
18904 @CMP_PARAMS = (@CMP_PARAMS, "-open");
18905 }
18906 if($Debug)
18907 {
18908 @CMP_PARAMS = (@CMP_PARAMS, "-debug");
18909 printMsg("INFO", "running perl $0 @CMP_PARAMS");
Andrey Ponomarenko85043792012-05-14 16:48:07 +040018910 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040018911 system("perl", $0, @CMP_PARAMS);
18912 exit($?>>8);
18913 }
18914 if(not $Descriptor{1}{"Dump"}
18915 or not $Descriptor{2}{"Dump"})
18916 { # need GCC toolchain to analyze
18917 # header files and libraries
18918 detect_default_paths("inc|lib|gcc");
18919 }
18920 if(not $Descriptor{1}{"Dump"})
18921 {
18922 if(not $CheckHeadersOnly) {
18923 readLibs(1);
18924 }
18925 if($CheckHeadersOnly) {
18926 setLanguage(1, "C++");
18927 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +040018928 if(not $CheckObjectsOnly) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040018929 searchForHeaders(1);
18930 }
18931 $WORD_SIZE{1} = detectWordSize();
18932 }
18933 if(not $Descriptor{2}{"Dump"})
18934 {
18935 if(not $CheckHeadersOnly) {
18936 readLibs(2);
18937 }
18938 if($CheckHeadersOnly) {
18939 setLanguage(2, "C++");
18940 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +040018941 if(not $CheckObjectsOnly) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040018942 searchForHeaders(2);
18943 }
18944 $WORD_SIZE{2} = detectWordSize();
18945 }
18946 if($WORD_SIZE{1} ne $WORD_SIZE{2})
18947 { # support for old ABI dumps
18948 # try to synch different WORD sizes
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040018949 if(not checkDump(1, "2.1"))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040018950 {
18951 $WORD_SIZE{1} = $WORD_SIZE{2};
18952 printMsg("WARNING", "set WORD size to ".$WORD_SIZE{2}." bytes");
18953 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040018954 elsif(not checkDump(2, "2.1"))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040018955 {
18956 $WORD_SIZE{2} = $WORD_SIZE{1};
18957 printMsg("WARNING", "set WORD size to ".$WORD_SIZE{1}." bytes");
18958 }
18959 }
18960 elsif(not $WORD_SIZE{1}
18961 and not $WORD_SIZE{2})
18962 { # support for old ABI dumps
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040018963 $WORD_SIZE{1} = "4";
18964 $WORD_SIZE{2} = "4";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040018965 }
18966 if($Descriptor{1}{"Dump"})
18967 { # support for old ABI dumps
18968 prepareTypes(1);
18969 }
18970 if($Descriptor{2}{"Dump"})
18971 { # support for old ABI dumps
18972 prepareTypes(2);
18973 }
18974 if($AppPath and not keys(%{$Symbol_Library{1}})) {
18975 printMsg("WARNING", "the application ".get_filename($AppPath)." has no symbols imported from the $SLIB_TYPE libraries");
18976 }
18977 # started to process input data
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040018978 if(not $CheckObjectsOnly)
18979 {
18980 if($Descriptor{1}{"Headers"}
18981 and not $Descriptor{1}{"Dump"}) {
18982 readHeaders(1);
18983 }
18984 if($Descriptor{2}{"Headers"}
18985 and not $Descriptor{2}{"Dump"}) {
18986 readHeaders(2);
18987 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040018988 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +040018989
18990 # clean memory
18991 %SystemHeaders = ();
18992 %mangled_name_gcc = ();
18993
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040018994 prepareSymbols(1);
18995 prepareSymbols(2);
Andrey Ponomarenko16934472012-03-29 15:37:04 +040018996
Andrey Ponomarenko85043792012-05-14 16:48:07 +040018997 # clean memory
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040018998 %SymbolInfo = ();
Andrey Ponomarenko16934472012-03-29 15:37:04 +040018999
19000 # Virtual Tables
19001 registerVTable(1);
19002 registerVTable(2);
19003
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040019004 if(not checkDump(1, "1.22")
19005 and checkDump(2, "1.22"))
Andrey Ponomarenko16934472012-03-29 15:37:04 +040019006 { # support for old ABI dumps
19007 foreach my $ClassName (keys(%{$VirtualTable{2}}))
19008 {
19009 if($ClassName=~/</)
19010 { # templates
19011 if(not defined $VirtualTable{1}{$ClassName})
19012 { # synchronize
19013 delete($VirtualTable{2}{$ClassName});
19014 }
19015 }
19016 }
19017 }
19018
19019 registerOverriding(1);
19020 registerOverriding(2);
19021
19022 setVirtFuncPositions(1);
19023 setVirtFuncPositions(2);
19024
19025 # Other
19026 addParamNames(1);
19027 addParamNames(2);
19028
19029 detectChangedTypedefs();
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040019030}
19031
19032sub compareAPIs($)
19033{
19034 my $Level = $_[0];
19035 readRules($Level);
19036 if($Level eq "Binary") {
19037 printMsg("INFO", "comparing ABIs ...");
19038 }
19039 else {
19040 printMsg("INFO", "comparing APIs ...");
19041 }
19042 if($CheckHeadersOnly
19043 or $Level eq "Source")
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040019044 { # added/removed in headers
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040019045 detectAdded_H($Level);
19046 detectRemoved_H($Level);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040019047 }
19048 else
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040019049 { # added/removed in libs
19050 detectAdded($Level);
19051 detectRemoved($Level);
19052 }
19053 if(not $CheckObjectsOnly)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040019054 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040019055 mergeSignatures($Level);
19056 if(keys(%{$CheckedSymbols{$Level}})) {
19057 mergeConstants($Level);
19058 }
19059 }
19060 if($CheckHeadersOnly
19061 or $Level eq "Source")
19062 { # added/removed in headers
19063 mergeHeaders($Level);
19064 }
19065 else
19066 { # added/removed in libs
19067 mergeLibs($Level);
19068 if($CheckImpl
19069 and $Level eq "Binary") {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040019070 mergeImpl();
19071 }
19072 }
19073}
19074
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040019075sub writeOpts()
19076{
19077 my %Opts = (
19078 "OStarget"=>$OStarget,
19079 "Debug"=>$Debug,
19080 "Quiet"=>$Quiet,
19081 "LogMode"=>$LogMode,
19082 "CheckHeadersOnly"=>$CheckHeadersOnly,
19083
19084 "SystemRoot"=>$SystemRoot,
19085 "MODULES_DIR"=>$MODULES_DIR,
19086 "GCC_PATH"=>$GCC_PATH,
19087 "TargetSysInfo"=>$TargetSysInfo,
19088 "CrossPrefix"=>$CrossPrefix,
19089 "TargetLibraryName"=>$TargetLibraryName,
19090 "CrossGcc"=>$CrossGcc,
19091 "UseStaticLibs"=>$UseStaticLibs,
19092 "NoStdInc"=>$NoStdInc
19093 );
19094 return \%Opts;
19095}
19096
19097sub get_CoreError($)
19098{
19099 my %CODE_ERROR = reverse(%ERROR_CODE);
19100 return $CODE_ERROR{$_[0]};
19101}
19102
19103sub scenario()
19104{
19105 if($StdOut)
19106 { # enable quiet mode
19107 $Quiet = 1;
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040019108 $JoinReport = 1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040019109 }
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040019110 if(not $LogMode)
19111 { # default
19112 $LogMode = "w";
19113 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040019114 if($UserLang)
19115 { # --lang=C++
19116 $UserLang = uc($UserLang);
19117 $COMMON_LANGUAGE{1}=$UserLang;
19118 $COMMON_LANGUAGE{2}=$UserLang;
19119 }
19120 if($LoggingPath)
19121 {
19122 $OutputLogPath{1} = $LoggingPath;
19123 $OutputLogPath{2} = $LoggingPath;
19124 if($Quiet) {
19125 $COMMON_LOG_PATH = $LoggingPath;
19126 }
19127 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040019128 if($BinaryOnly and $SourceOnly)
19129 { # both --binary and --source
19130 # is the default mode
19131 $DoubleReport = 1;
19132 $JoinReport = 0;
19133 $BinaryOnly = 0;
19134 $SourceOnly = 0;
19135 if($OutputReportPath)
19136 { # --report-path
19137 $DoubleReport = 0;
19138 $JoinReport = 1;
19139 }
19140 }
19141 elsif($BinaryOnly or $SourceOnly)
19142 { # --binary or --source
19143 $DoubleReport = 0;
19144 $JoinReport = 0;
19145 }
19146 if($UseXML)
19147 { # --xml option
19148 $ReportFormat = "xml";
19149 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040019150 if($ReportFormat)
19151 { # validate
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040019152 $ReportFormat = lc($ReportFormat);
19153 if($ReportFormat!~/\A(xml|html|htm)\Z/) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040019154 exitStatus("Error", "unknown format \'$ReportFormat\'");
19155 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040019156 if($ReportFormat eq "htm")
19157 { # HTM == HTML
19158 $ReportFormat = "html";
19159 }
19160 elsif($ReportFormat eq "xml")
19161 { # --report-format=XML equal to --xml
19162 $UseXML = 1;
19163 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040019164 }
19165 else
19166 { # default: HTML
19167 $ReportFormat = "html";
19168 }
19169 if($Quiet and $LogMode!~/a|n/)
19170 { # --quiet log
19171 if(-f $COMMON_LOG_PATH) {
19172 unlink($COMMON_LOG_PATH);
19173 }
19174 }
19175 if($TestTool and $UseDumps)
19176 { # --test && --use-dumps == --test-dump
19177 $TestDump = 1;
19178 }
19179 if($Help) {
19180 HELP_MESSAGE();
19181 exit(0);
19182 }
19183 if($InfoMsg) {
19184 INFO_MESSAGE();
19185 exit(0);
19186 }
19187 if($ShowVersion) {
19188 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.");
19189 exit(0);
19190 }
19191 if($DumpVersion) {
19192 printMsg("INFO", $TOOL_VERSION);
19193 exit(0);
19194 }
19195 if($ExtendedCheck) {
19196 $CheckHeadersOnly = 1;
19197 }
19198 if($SystemRoot_Opt)
19199 { # user defined root
19200 if(not -e $SystemRoot_Opt) {
19201 exitStatus("Access_Error", "can't access \'$SystemRoot\'");
19202 }
19203 $SystemRoot = $SystemRoot_Opt;
19204 $SystemRoot=~s/[\/]+\Z//g;
19205 if($SystemRoot) {
19206 $SystemRoot = get_abs_path($SystemRoot);
19207 }
19208 }
19209 $Data::Dumper::Sortkeys = 1;
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +040019210
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040019211 if($SortDump)
19212 {
19213 $Data::Dumper::Useperl = 1;
19214 $Data::Dumper::Sortkeys = \&dump_sorting;
19215 }
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +040019216
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040019217 if($TargetLibsPath)
19218 {
19219 if(not -f $TargetLibsPath) {
19220 exitStatus("Access_Error", "can't access file \'$TargetLibsPath\'");
19221 }
19222 foreach my $Lib (split(/\s*\n\s*/, readFile($TargetLibsPath))) {
19223 $TargetLibs{$Lib} = 1;
19224 }
19225 }
19226 if($TargetHeadersPath)
19227 { # --headers-list
19228 if(not -f $TargetHeadersPath) {
19229 exitStatus("Access_Error", "can't access file \'$TargetHeadersPath\'");
19230 }
19231 foreach my $Header (split(/\s*\n\s*/, readFile($TargetHeadersPath)))
19232 {
19233 $TargetHeaders{1}{$Header} = 1;
19234 $TargetHeaders{2}{$Header} = 1;
19235 }
19236 }
19237 if($TargetHeader)
19238 { # --header
19239 $TargetHeaders{1}{$TargetHeader} = 1;
19240 $TargetHeaders{2}{$TargetHeader} = 1;
19241 }
19242 if($TestTool
19243 or $TestDump)
19244 { # --test, --test-dump
19245 detect_default_paths("bin|gcc"); # to compile libs
19246 loadModule("RegTests");
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040019247 testTool($TestDump, $Debug, $Quiet, $ExtendedCheck, $LogMode,
19248 $ReportFormat, $LIB_EXT, $GCC_PATH, $Browse, $OpenReport, $SortDump);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040019249 exit(0);
19250 }
19251 if($DumpSystem)
19252 { # --dump-system
19253 loadModule("SysCheck");
19254 if($DumpSystem=~/\.xml\Z/)
19255 { # system XML descriptor
19256 if(not -f $DumpSystem) {
19257 exitStatus("Access_Error", "can't access file \'$DumpSystem\'");
19258 }
19259 my $Ret = readSystemDescriptor(readFile($DumpSystem));
19260 foreach (@{$Ret->{"Tools"}}) {
19261 $SystemPaths{"bin"}{$_} = 1;
19262 $TargetTools{$_}=1;
19263 }
19264 if($Ret->{"CrossPrefix"}) {
19265 $CrossPrefix = $Ret->{"CrossPrefix"};
19266 }
19267 }
19268 elsif($SystemRoot_Opt)
19269 { # -sysroot "/" option
19270 # default target: /usr/lib, /usr/include
19271 # search libs: /usr/lib and /lib
19272 if(not -e $SystemRoot."/usr/lib") {
19273 exitStatus("Access_Error", "can't access '".$SystemRoot."/usr/lib'");
19274 }
19275 if(not -e $SystemRoot."/lib") {
19276 exitStatus("Access_Error", "can't access '".$SystemRoot."/lib'");
19277 }
19278 if(not -e $SystemRoot."/usr/include") {
19279 exitStatus("Access_Error", "can't access '".$SystemRoot."/usr/include'");
19280 }
19281 readSystemDescriptor("
19282 <name>
19283 $DumpSystem
19284 </name>
19285 <headers>
19286 $SystemRoot/usr/include
19287 </headers>
19288 <libs>
19289 $SystemRoot/usr/lib
19290 </libs>
19291 <search_libs>
19292 $SystemRoot/lib
19293 </search_libs>");
19294 }
19295 else {
19296 exitStatus("Error", "-sysroot <dirpath> option should be specified, usually it's \"/\"");
19297 }
19298 detect_default_paths("bin|gcc"); # to check symbols
19299 if($OStarget eq "windows")
19300 { # to run dumpbin.exe
19301 # and undname.exe
19302 check_win32_env();
19303 }
19304 dumpSystem(writeOpts());
19305 exit(0);
19306 }
19307 if($CmpSystems)
19308 { # --cmp-systems
19309 detect_default_paths("bin"); # to extract dumps
19310 loadModule("SysCheck");
19311 cmpSystems($Descriptor{1}{"Path"}, $Descriptor{2}{"Path"}, writeOpts());
19312 exit(0);
19313 }
19314 if($GenerateTemplate) {
19315 generateTemplate();
19316 exit(0);
19317 }
19318 if(not $TargetLibraryName) {
19319 exitStatus("Error", "library name is not selected (option -l <name>)");
19320 }
19321 else
19322 { # validate library name
19323 if($TargetLibraryName=~/[\*\/\\]/) {
19324 exitStatus("Error", "\"\\\", \"\/\" and \"*\" symbols are not allowed in the library name");
19325 }
19326 }
19327 if(not $TargetLibraryFName) {
19328 $TargetLibraryFName = $TargetLibraryName;
19329 }
19330 if($CheckHeadersOnly_Opt and $CheckObjectsOnly_Opt) {
19331 exitStatus("Error", "you can't specify both -headers-only and -objects-only options at the same time");
19332 }
19333 if($SymbolsListPath)
19334 {
19335 if(not -f $SymbolsListPath) {
19336 exitStatus("Access_Error", "can't access file \'$SymbolsListPath\'");
19337 }
19338 foreach my $Interface (split(/\s*\n\s*/, readFile($SymbolsListPath))) {
19339 $SymbolsList{$Interface} = 1;
19340 }
19341 }
19342 if($SkipHeadersPath)
19343 {
19344 if(not -f $SkipHeadersPath) {
19345 exitStatus("Access_Error", "can't access file \'$SkipHeadersPath\'");
19346 }
19347 foreach my $Path (split(/\s*\n\s*/, readFile($SkipHeadersPath)))
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040019348 { # register for both versions
19349 $SkipHeadersList{1}{$Path} = 1;
19350 $SkipHeadersList{2}{$Path} = 1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040019351 my ($CPath, $Type) = classifyPath($Path);
19352 $SkipHeaders{1}{$Type}{$CPath} = 1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040019353 $SkipHeaders{2}{$Type}{$CPath} = 1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040019354 }
19355 }
19356 if($ParamNamesPath)
19357 {
19358 if(not -f $ParamNamesPath) {
19359 exitStatus("Access_Error", "can't access file \'$ParamNamesPath\'");
19360 }
19361 foreach my $Line (split(/\n/, readFile($ParamNamesPath)))
19362 {
19363 if($Line=~s/\A(\w+)\;//)
19364 {
19365 my $Interface = $1;
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040019366 if($Line=~/;(\d+);/)
19367 {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040019368 while($Line=~s/(\d+);(\w+)//) {
19369 $AddIntParams{$Interface}{$1}=$2;
19370 }
19371 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040019372 else
19373 {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040019374 my $Num = 0;
19375 foreach my $Name (split(/;/, $Line)) {
19376 $AddIntParams{$Interface}{$Num++}=$Name;
19377 }
19378 }
19379 }
19380 }
19381 }
19382 if($AppPath)
19383 {
19384 if(not -f $AppPath) {
19385 exitStatus("Access_Error", "can't access file \'$AppPath\'");
19386 }
Andrey Ponomarenko16934472012-03-29 15:37:04 +040019387 foreach my $Interface (readSymbols_App($AppPath)) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040019388 $SymbolsList_App{$Interface} = 1;
19389 }
19390 }
19391 if($DumpAPI)
19392 { # --dump-abi
19393 # make an API dump
19394 create_ABI_Dump();
19395 exit($COMPILE_ERRORS);
19396 }
19397 # default: compare APIs
19398 # -d1 <path>
19399 # -d2 <path>
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040019400 compareInit();
19401 if($JoinReport or $DoubleReport)
19402 {
19403 compareAPIs("Binary");
19404 compareAPIs("Source");
19405 }
19406 elsif($BinaryOnly) {
19407 compareAPIs("Binary");
19408 }
19409 elsif($SourceOnly) {
19410 compareAPIs("Source");
19411 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040019412 exitReport();
19413}
19414
19415scenario();