blob: ec636dbbdda9091f9580273f75fd00bf765f088f [file] [log] [blame]
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04001#!/usr/bin/perl
2###########################################################################
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04003# ABI Compliance Checker (ACC) 1.97.6
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04004# A tool for checking backward compatibility of a C/C++ library API
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005#
Andrey Ponomarenko85043792012-05-14 16:48:07 +04006# Copyright (C) 2009-2010 The Linux Foundation
7# Copyright (C) 2009-2011 Institute for System Programming, RAS
8# Copyright (C) 2011-2012 Nokia Corporation and/or its subsidiary(-ies)
9# Copyright (C) 2011-2012 ROSA Laboratory
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010#
11# Written by Andrey Ponomarenko
12#
13# PLATFORMS
14# =========
15# Linux, FreeBSD, Mac OS X, Haiku, MS Windows, Symbian
16#
17# REQUIREMENTS
18# ============
19# Linux
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +040020# - G++ (3.0-4.7, recommended 4.5 or newer)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040021# - GNU Binutils (readelf, c++filt, objdump)
Andrey Ponomarenko85043792012-05-14 16:48:07 +040022# - Perl 5 (5.8 or newer)
Andrey 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 Ponomarenko62ddcfa2012-05-23 13:13:15 +040058my $TOOL_VERSION = "1.97.6";
59my $ABI_DUMP_VERSION = "2.15";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040060my $OLDEST_SUPPORTED_VERSION = "1.18";
61my $XML_REPORT_VERSION = "1.0";
62my $OSgroup = get_OSgroup();
63my $ORIG_DIR = cwd();
64my $TMP_DIR = tempdir(CLEANUP=>1);
65
66# Internal modules
67my $MODULES_DIR = get_Modules();
68push(@INC, get_dirname($MODULES_DIR));
69# Rules DB
70my %RULES_PATH = (
71 "Binary" => $MODULES_DIR."/RulesBin.xml",
72 "Source" => $MODULES_DIR."/RulesSrc.xml");
73
74my ($Help, $ShowVersion, %Descriptor, $TargetLibraryName, $GenerateTemplate,
75$TestTool, $DumpAPI, $SymbolsListPath, $CheckHeadersOnly_Opt, $UseDumps,
76$CheckObjectsOnly_Opt, $AppPath, $StrictCompat, $DumpVersion, $ParamNamesPath,
77%RelativeDirectory, $TargetLibraryFName, $TestDump, $CheckImpl, $LoggingPath,
78%TargetVersion, $InfoMsg, $UseOldDumps, %UsedDump, $CrossGcc, %OutputLogPath,
79$OutputReportPath, $OutputDumpPath, $ShowRetVal, $SystemRoot_Opt, $DumpSystem,
80$CmpSystems, $TargetLibsPath, $Debug, $CrossPrefix, $UseStaticLibs, $NoStdInc,
81$TargetComponent_Opt, $TargetSysInfo, $TargetHeader, $ExtendedCheck, $Quiet,
82$SkipHeadersPath, $Cpp2003, $LogMode, $StdOut, $ListAffected, $ReportFormat,
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040083$UserLang, $TargetHeadersPath, $BinaryOnly, $SourceOnly, $BinaryReportPath,
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040084$SourceReportPath, $UseXML, $Browse, $OpenReport, $SortDump);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040085
86my $CmdName = get_filename($0);
87my %OS_LibExt = (
88 "dynamic" => {
89 "default"=>"so",
90 "macos"=>"dylib",
91 "windows"=>"dll",
92 "symbian"=>"dso"
93 },
94 "static" => {
95 "default"=>"a",
96 "windows"=>"lib",
97 "symbian"=>"lib"
98 }
99);
100
101my %OS_Archive = (
102 "windows"=>"zip",
103 "default"=>"tar.gz"
104);
105
106my %ERROR_CODE = (
107 # Compatible verdict
108 "Compatible"=>0,
109 "Success"=>0,
110 # Incompatible verdict
111 "Incompatible"=>1,
112 # Undifferentiated error code
113 "Error"=>2,
114 # System command is not found
115 "Not_Found"=>3,
116 # Cannot access input files
117 "Access_Error"=>4,
118 # Cannot compile header files
119 "Cannot_Compile"=>5,
120 # Header compiled with errors
121 "Compile_Error"=>6,
122 # Invalid input ABI dump
123 "Invalid_Dump"=>7,
124 # Incompatible version of ABI dump
125 "Dump_Version"=>8,
126 # Cannot find a module
127 "Module_Error"=>9,
128 # Empty intersection between
129 # headers and shared objects
130 "Empty_Intersection"=>10,
131 # Empty set of symbols in headers
132 "Empty_Set"=>11
133);
134
135my %HomePage = (
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +0400136 "Wiki"=>"http://ispras.linuxbase.org/index.php/ABI_compliance_checker",
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +0400137 "Dev1"=>"https://github.com/lvc/abi-compliance-checker",
138 "Dev2"=>"http://forge.ispras.ru/projects/abi-compliance-checker"
Andrey Ponomarenkoab282102012-03-11 11:57:02 +0400139);
140
141my $ShortUsage = "ABI Compliance Checker (ACC) $TOOL_VERSION
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +0400142A tool for checking backward compatibility of a C/C++ library API
Andrey Ponomarenkoab282102012-03-11 11:57:02 +0400143Copyright (C) 2012 ROSA Laboratory
144License: GNU LGPL or GNU GPL
145
146Usage: $CmdName [options]
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +0400147Example: $CmdName -lib NAME -old OLD.xml -new NEW.xml
Andrey Ponomarenkoab282102012-03-11 11:57:02 +0400148
149OLD.xml and NEW.xml are XML-descriptors:
150
151 <version>
152 1.0
153 </version>
154
155 <headers>
156 /path/to/headers/
157 </headers>
158
159 <libs>
160 /path/to/libraries/
161 </libs>
162
163More info: $CmdName --help\n";
164
165if($#ARGV==-1) {
166 printMsg("INFO", $ShortUsage);
167 exit(0);
168}
169
170foreach (2 .. $#ARGV)
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +0400171{ # correct comma separated options
Andrey Ponomarenkoab282102012-03-11 11:57:02 +0400172 if($ARGV[$_-1] eq ",") {
173 $ARGV[$_-2].=",".$ARGV[$_];
174 splice(@ARGV, $_-1, 2);
175 }
176 elsif($ARGV[$_-1]=~/,\Z/) {
177 $ARGV[$_-1].=$ARGV[$_];
178 splice(@ARGV, $_, 1);
179 }
180 elsif($ARGV[$_]=~/\A,/
181 and $ARGV[$_] ne ",") {
182 $ARGV[$_-1].=$ARGV[$_];
183 splice(@ARGV, $_, 1);
184 }
185}
186
187GetOptions("h|help!" => \$Help,
188 "i|info!" => \$InfoMsg,
189 "v|version!" => \$ShowVersion,
190 "dumpversion!" => \$DumpVersion,
191# general options
192 "l|lib|library=s" => \$TargetLibraryName,
193 "d1|old|o=s" => \$Descriptor{1}{"Path"},
194 "d2|new|n=s" => \$Descriptor{2}{"Path"},
195 "dump|dump-abi|dump_abi=s" => \$DumpAPI,
196 "old-dumps!" => \$UseOldDumps,
197# extra options
198 "d|descriptor-template!" => \$GenerateTemplate,
199 "app|application=s" => \$AppPath,
200 "static-libs!" => \$UseStaticLibs,
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +0400201 "cross-gcc|gcc-path=s" => \$CrossGcc,
202 "cross-prefix|gcc-prefix=s" => \$CrossPrefix,
Andrey Ponomarenkoab282102012-03-11 11:57:02 +0400203 "sysroot=s" => \$SystemRoot_Opt,
204 "v1|version1|vnum=s" => \$TargetVersion{1},
205 "v2|version2=s" => \$TargetVersion{2},
206 "s|strict!" => \$StrictCompat,
207 "symbols-list=s" => \$SymbolsListPath,
208 "skip-headers=s" => \$SkipHeadersPath,
209 "headers-only|headers_only!" => \$CheckHeadersOnly_Opt,
210 "objects-only!" => \$CheckObjectsOnly_Opt,
211 "check-impl|check-implementation!" => \$CheckImpl,
212 "show-retval!" => \$ShowRetVal,
213 "use-dumps!" => \$UseDumps,
214 "nostdinc!" => \$NoStdInc,
215 "dump-system=s" => \$DumpSystem,
216 "sysinfo=s" => \$TargetSysInfo,
217 "cmp-systems!" => \$CmpSystems,
218 "libs-list=s" => \$TargetLibsPath,
219 "headers-list=s" => \$TargetHeadersPath,
220 "header=s" => \$TargetHeader,
221 "ext|extended!" => \$ExtendedCheck,
222 "q|quiet!" => \$Quiet,
223 "stdout!" => \$StdOut,
224 "report-format=s" => \$ReportFormat,
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +0400225 "xml!" => \$UseXML,
Andrey Ponomarenkoab282102012-03-11 11:57:02 +0400226 "lang=s" => \$UserLang,
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +0400227 "binary|bin|abi!" => \$BinaryOnly,
228 "source|src|api!" => \$SourceOnly,
Andrey Ponomarenkoab282102012-03-11 11:57:02 +0400229# other options
230 "test!" => \$TestTool,
231 "test-dump!" => \$TestDump,
232 "debug!" => \$Debug,
233 "cpp-compatible!" => \$Cpp2003,
234 "p|params=s" => \$ParamNamesPath,
235 "relpath1|relpath=s" => \$RelativeDirectory{1},
236 "relpath2=s" => \$RelativeDirectory{2},
237 "dump-path=s" => \$OutputDumpPath,
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +0400238 "sort!" => \$SortDump,
Andrey Ponomarenkoab282102012-03-11 11:57:02 +0400239 "report-path=s" => \$OutputReportPath,
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +0400240 "bin-report-path=s" => \$BinaryReportPath,
241 "src-report-path=s" => \$SourceReportPath,
Andrey Ponomarenkoab282102012-03-11 11:57:02 +0400242 "log-path=s" => \$LoggingPath,
243 "log1-path=s" => \$OutputLogPath{1},
244 "log2-path=s" => \$OutputLogPath{2},
245 "logging-mode=s" => \$LogMode,
246 "list-affected!" => \$ListAffected,
247 "l-full|lib-full=s" => \$TargetLibraryFName,
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +0400248 "component=s" => \$TargetComponent_Opt,
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +0400249 "b|browse=s" => \$Browse,
250 "open!" => \$OpenReport
Andrey Ponomarenkoab282102012-03-11 11:57:02 +0400251) or ERR_MESSAGE();
252
253sub ERR_MESSAGE()
254{
255 printMsg("INFO", "\n".$ShortUsage);
256 exit($ERROR_CODE{"Error"});
257}
258
259my $LIB_TYPE = $UseStaticLibs?"static":"dynamic";
260my $SLIB_TYPE = $LIB_TYPE;
261if($OSgroup!~/macos|windows/ and $SLIB_TYPE eq "dynamic")
262{ # show as "shared" library
263 $SLIB_TYPE = "shared";
264}
265my $LIB_EXT = getLIB_EXT($OSgroup);
266my $AR_EXT = getAR_EXT($OSgroup);
267my $BYTE_SIZE = 8;
268my $COMMON_LOG_PATH = "logs/run.log";
269
270my $HelpMessage="
271NAME:
272 ABI Compliance Checker ($CmdName)
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +0400273 Check backward compatibility of a C/C++ library API
Andrey Ponomarenkoab282102012-03-11 11:57:02 +0400274
275DESCRIPTION:
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +0400276 ABI Compliance Checker (ACC) is a tool for checking backward binary and
277 source-level compatibility of a $SLIB_TYPE C/C++ library. The tool checks
278 header files and $SLIB_TYPE libraries (*.$LIB_EXT) of old and new versions and
279 analyzes changes in API and ABI (ABI=API+compiler ABI) that may break binary
280 and/or source-level compatibility: changes in calling stack, v-table changes,
281 removed symbols, renamed fields, etc. Binary incompatibility may result in
282 crashing or incorrect behavior of applications built with an old version of
283 a library if they run on a new one. Source incompatibility may result in
284 recompilation errors with a new library version.
Andrey Ponomarenkoab282102012-03-11 11:57:02 +0400285
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +0400286 The tool is intended for developers of software libraries and maintainers
287 of operating systems who are interested in ensuring backward compatibility,
288 i.e. allow old applications to run or to be recompiled with newer library
289 versions.
290
291 Also the tool can be used by ISVs for checking applications portability to
292 new library versions. Found issues can be taken into account when adapting
293 the application to a new library version.
Andrey Ponomarenkoab282102012-03-11 11:57:02 +0400294
295 This tool is free software: you can redistribute it and/or modify it
296 under the terms of the GNU LGPL or GNU GPL.
297
298USAGE:
299 $CmdName [options]
300
301EXAMPLE:
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +0400302 $CmdName -lib NAME -old OLD.xml -new NEW.xml
Andrey Ponomarenkoab282102012-03-11 11:57:02 +0400303
304 OLD.xml and NEW.xml are XML-descriptors:
305
306 <version>
307 1.0
308 </version>
309
310 <headers>
311 /path1/to/header(s)/
312 /path2/to/header(s)/
313 ...
314 </headers>
315
316 <libs>
317 /path1/to/library(ies)/
318 /path2/to/library(ies)/
319 ...
320 </libs>
321
322INFORMATION OPTIONS:
323 -h|-help
324 Print this help.
325
326 -i|-info
327 Print complete info.
328
329 -v|-version
330 Print version information.
331
332 -dumpversion
333 Print the tool version ($TOOL_VERSION) and don't do anything else.
334
335GENERAL OPTIONS:
336 -l|-lib|-library <name>
337 Library name (without version).
338 It affects only on the path and the title of the report.
339
340 -d1|-old|-o <path>
341 Descriptor of 1st (old) library version.
342 It may be one of the following:
343
344 1. XML-descriptor (VERSION.xml file):
345
346 <version>
347 1.0
348 </version>
349
350 <headers>
351 /path1/to/header(s)/
352 /path2/to/header(s)/
353 ...
354 </headers>
355
356 <libs>
357 /path1/to/library(ies)/
358 /path2/to/library(ies)/
359 ...
360 </libs>
361
362 ... (XML-descriptor template
363 can be generated by -d option)
364
365 2. ABI dump generated by -dump option
366 3. Directory with headers and/or $SLIB_TYPE libraries
367 4. Single header file
368 5. Single $SLIB_TYPE library
369 6. Comma separated list of headers and/or libraries
370
371 If you are using an 2-6 descriptor types then you should
372 specify version numbers with -v1 <num> and -v2 <num> options too.
373
374 For more information, please see:
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +0400375 http://ispras.linuxbase.org/index.php/Library_Descriptor
Andrey Ponomarenkoab282102012-03-11 11:57:02 +0400376
377 -d2|-new|-n <path>
378 Descriptor of 2nd (new) library version.
379
380 -dump|-dump-abi <descriptor path(s)>
381 Dump library ABI to gzipped TXT format file. You can transfer it
382 anywhere and pass instead of the descriptor. Also it can be used
383 for debugging the tool. Compatible dump versions: ".majorVersion($ABI_DUMP_VERSION).".0<=V<=$ABI_DUMP_VERSION
384
385 -old-dumps
386 Enable support for old-version ABI dumps ($OLDEST_SUPPORTED_VERSION<=V<".majorVersion($ABI_DUMP_VERSION).".0).\n";
387
388sub HELP_MESSAGE() {
389 printMsg("INFO", $HelpMessage."
390MORE INFO:
391 $CmdName --info\n");
392}
393
394sub INFO_MESSAGE()
395{
396 printMsg("INFO", "$HelpMessage
397EXTRA OPTIONS:
398 -d|-descriptor-template
399 Create XML-descriptor template ./VERSION.xml
400
401 -app|-application <path>
402 This option allows to specify the application that should be checked
403 for portability to the new library version.
404
405 -static-libs
406 Check static libraries instead of the shared ones. The <libs> section
407 of the XML-descriptor should point to static libraries location.
408
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +0400409 -cross-gcc|-gcc-path <path>
Andrey Ponomarenkoab282102012-03-11 11:57:02 +0400410 Path to the cross GCC compiler to use instead of the usual (host) GCC.
411
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +0400412 -cross-prefix|-gcc-prefix <prefix>
Andrey Ponomarenkoab282102012-03-11 11:57:02 +0400413 GCC toolchain prefix.
414
415 -sysroot <dirpath>
416 Specify the alternative root directory. The tool will search for include
417 paths in the <dirpath>/usr/include and <dirpath>/usr/lib directories.
418
419 -v1|-version1 <num>
420 Specify 1st library version outside the descriptor. This option is needed
421 if you have prefered an alternative descriptor type (see -d1 option).
422
423 In general case you should specify it in the XML-descriptor:
424 <version>
425 VERSION
426 </version>
427
428 -v2|-version2 <num>
429 Specify 2nd library version outside the descriptor.
430
431 -s|-strict
432 Treat all compatibility warnings as problems. Add a number of \"Low\"
433 severity problems to the return value of the tool.
434
435 -headers-only
436 Check header files without $SLIB_TYPE libraries. It is easy to run, but may
437 provide a low quality compatibility report with false positives and
438 without detecting of added/removed symbols.
439
440 Alternatively you can write \"none\" word to the <libs> section
441 in the XML-descriptor:
442 <libs>
443 none
444 </libs>
445
446 -objects-only
447 Check $SLIB_TYPE libraries without header files. It is easy to run, but may
448 provide a low quality compatibility report with false positives and
449 without analysis of changes in parameters and data types.
450
451 Alternatively you can write \"none\" word to the <headers> section
452 in the XML-descriptor:
453 <headers>
454 none
455 </headers>
456
457 -check-impl|-check-implementation
458 Compare canonified disassembled binary code of $SLIB_TYPE libraries to
459 detect changes in the implementation. Add \'Problems with Implementation\'
460 section to the report.
461
462 -show-retval
463 Show the symbol's return type in the report.
464
465 -symbols-list <path>
466 This option allows to specify a file with a list of symbols (mangled
467 names in C++) that should be checked, other symbols will not be checked.
468
469 -skip-headers <path>
470 The file with the list of header files, that should not be checked.
471
472 -use-dumps
473 Make dumps for two versions of a library and compare dumps. This should
474 increase the performance of the tool and decrease the system memory usage.
475
476 -nostdinc
477 Do not search the GCC standard system directories for header files.
478
479 -dump-system <name> -sysroot <dirpath>
480 Find all the shared libraries and header files in <dirpath> directory,
481 create XML descriptors and make ABI dumps for each library. The result
482 set of ABI dumps can be compared (--cmp-systems) with the other one
483 created for other version of operating system in order to check them for
484 compatibility. Do not forget to specify -cross-gcc option if your target
485 system requires some specific version of GCC compiler (different from
486 the host GCC). The system ABI dump will be generated to:
487 sys_dumps/<name>/<arch>
488
489 -dump-system <descriptor.xml>
490 The same as the previous option but takes an XML descriptor of the target
491 system as input, where you should describe it:
492
493 /* Primary sections */
494
495 <name>
496 /* Name of the system */
497 </name>
498
499 <headers>
500 /* The list of paths to header files and/or
501 directories with header files, one per line */
502 </headers>
503
504 <libs>
505 /* The list of paths to shared libraries and/or
506 directories with shared libraries, one per line */
507 </libs>
508
509 /* Optional sections */
510
511 <search_headers>
512 /* List of directories to be searched
513 for header files to automatically
514 generate include paths, one per line */
515 </search_headers>
516
517 <search_libs>
518 /* List of directories to be searched
519 for shared libraries to resolve
520 dependencies, one per line */
521 </search_libs>
522
523 <tools>
524 /* List of directories with tools used
525 for analysis (GCC toolchain), one per line */
526 </tools>
527
528 <cross_prefix>
529 /* GCC toolchain prefix.
530 Examples:
531 arm-linux-gnueabi
532 arm-none-symbianelf */
533 </cross_prefix>
534
535 <gcc_options>
536 /* Additional GCC options, one per line */
537 </gcc_options>
538
539 -sysinfo <dir>
540 This option may be used with -dump-system to dump ABI of operating
541 systems and configure the dumping process.
542 Default:
543 modules/Targets/{unix, symbian, windows}
544
545 -cmp-systems -d1 sys_dumps/<name1>/<arch> -d2 sys_dumps/<name2>/<arch>
546 Compare two system ABI dumps. Create compatibility reports for each
547 library and the common HTML report including the summary of test
548 results for all checked libraries. Report will be generated to:
549 sys_compat_reports/<name1>_to_<name2>/<arch>
550
551 -libs-list <path>
552 The file with a list of libraries, that should be dumped by
553 the -dump-system option or should be checked by the -cmp-systems option.
554
555 -header <name>
556 Check/Dump ABI of this header only.
557
558 -headers-list <path>
559 The file with a list of headers, that should be checked/dumped.
560
561 -ext|-extended
562 If your library A is supposed to be used by other library B and you
563 want to control the ABI of B, then you should enable this option. The
564 tool will check for changes in all data types, even if they are not
565 used by any function in the library A. Such data types are not part
566 of the A library ABI, but may be a part of the ABI of the B library.
567
568 The short scheme is:
569 app C (broken) -> lib B (broken ABI) -> lib A (stable ABI)
570
571 -q|-quiet
572 Print all messages to the file instead of stdout and stderr.
573 Default path (can be changed by -log-path option):
574 $COMMON_LOG_PATH
575
576 -stdout
577 Print analysis results (compatibility reports and ABI dumps) to stdout
578 instead of creating a file. This would allow piping data to other programs.
579
580 -report-format <fmt>
581 Change format of compatibility report.
582 Formats:
583 htm - HTML format (default)
584 xml - XML format
585
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +0400586 -xml
587 Alias for: --report-format=xml
588
Andrey Ponomarenkoab282102012-03-11 11:57:02 +0400589 -lang <lang>
590 Set library language (C or C++). You can use this option if the tool
591 cannot auto-detect a language. This option may be useful for checking
592 C-library headers (--lang=C) in --headers-only or --extended modes.
593
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +0400594 -binary|-bin|-abi
595 Show \"Binary\" compatibility problems only.
596 Generate report to:
597 compat_reports/<library name>/<v1>_to_<v2>/abi_compat_report.html
598
599 -source|-src|-api
600 Show \"Source\" compatibility problems only.
601 Generate report to:
602 compat_reports/<library name>/<v1>_to_<v2>/src_compat_report.html
603
Andrey Ponomarenkoab282102012-03-11 11:57:02 +0400604OTHER OPTIONS:
605 -test
606 Run internal tests. Create two binary incompatible versions of a sample
607 library and run the tool to check them for compatibility. This option
608 allows to check if the tool works correctly in the current environment.
609
610 -test-dump
611 Test ability to create, read and compare ABI dumps.
612
613 -debug
614 Debugging mode. Print debug info on the screen. Save intermediate
615 analysis stages in the debug directory:
616 debug/<library>/<version>/
617
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +0400618 Also consider using --dump option for debugging the tool.
619
Andrey Ponomarenkoab282102012-03-11 11:57:02 +0400620 -cpp-compatible
621 If your header file is written in C language and can be compiled by
622 the C++ compiler (i.e. doesn't contain C++-keywords and other bad
623 things), then you can tell ACC about this and speedup the analysis.
624
625 -p|-params <path>
626 Path to file with the function parameter names. It can be used
627 for improving report view if the library header files have no
628 parameter names. File format:
629
630 func1;param1;param2;param3 ...
631 func2;param1;param2;param3 ...
632 ...
633
634 -relpath <path>
635 Replace {RELPATH} macros to <path> in the XML-descriptor used
636 for dumping the library ABI (see -dump option).
637
638 -relpath1 <path>
639 Replace {RELPATH} macros to <path> in the 1st XML-descriptor (-d1).
640
641 -relpath2 <path>
642 Replace {RELPATH} macros to <path> in the 2nd XML-descriptor (-d2).
643
644 -dump-path <path>
645 Specify a file path (*.abi.$AR_EXT) where to generate an ABI dump.
646 Default:
647 abi_dumps/<library>/<library>_<version>.abi.$AR_EXT
648
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +0400649 -sort
650 Enable sorting of data in ABI dumps.
651
Andrey Ponomarenkoab282102012-03-11 11:57:02 +0400652 -report-path <path>
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +0400653 Path to compatibility report.
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +0400654 Default:
655 compat_reports/<library name>/<v1>_to_<v2>/compat_report.html
656
657 -bin-report-path <path>
658 Path to \"Binary\" compatibility report.
Andrey Ponomarenkoab282102012-03-11 11:57:02 +0400659 Default:
660 compat_reports/<library name>/<v1>_to_<v2>/abi_compat_report.html
661
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +0400662 -src-report-path <path>
663 Path to \"Source\" compatibility report.
664 Default:
665 compat_reports/<library name>/<v1>_to_<v2>/src_compat_report.html
666
Andrey Ponomarenkoab282102012-03-11 11:57:02 +0400667 -log-path <path>
668 Log path for all messages.
669 Default:
670 logs/<library>/<version>/log.txt
671
672 -log1-path <path>
673 Log path for 1st version of a library.
674 Default:
675 logs/<library name>/<v1>/log.txt
676
677 -log2-path <path>
678 Log path for 2nd version of a library.
679 Default:
680 logs/<library name>/<v2>/log.txt
681
682 -logging-mode <mode>
683 Change logging mode.
684 Modes:
685 w - overwrite old logs (default)
686 a - append old logs
687 n - do not write any logs
688
689 -list-affected
690 Generate file with the list of incompatible
691 symbols beside the HTML compatibility report.
692 Use 'c++filt \@file' command from GNU binutils
693 to unmangle C++ symbols in the generated file.
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +0400694 Default names:
Andrey Ponomarenkoab282102012-03-11 11:57:02 +0400695 abi_affected.txt
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +0400696 src_affected.txt
Andrey Ponomarenkoab282102012-03-11 11:57:02 +0400697
698 -component <name>
699 The component name in the title and summary of the HTML report.
700 Default:
701 library
702
703 -l-full|-lib-full <name>
704 Change library name in the report title to <name>. By default
705 will be displayed a name specified by -l option.
706
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +0400707 -b|-browse <program>
708 Open report(s) in the browser (firefox, opera, etc.).
709
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +0400710 -open
711 Open report(s) in the default browser.
712
Andrey Ponomarenkoab282102012-03-11 11:57:02 +0400713REPORT:
714 Compatibility report will be generated to:
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +0400715 compat_reports/<library name>/<v1>_to_<v2>/compat_report.html
Andrey Ponomarenkoab282102012-03-11 11:57:02 +0400716
717 Log will be generated to:
718 logs/<library name>/<v1>/log.txt
719 logs/<library name>/<v2>/log.txt
720
721EXIT CODES:
722 0 - Compatible. The tool has run without any errors.
723 non-zero - Incompatible or the tool has run with errors.
724
725REPORT BUGS TO:
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +0400726 Andrey Ponomarenko <aponomarenko\@rosalab.ru>
Andrey Ponomarenkoab282102012-03-11 11:57:02 +0400727
728MORE INFORMATION:
729 ".$HomePage{"Wiki"}."
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +0400730 ".$HomePage{"Dev1"}."\n");
Andrey Ponomarenkoab282102012-03-11 11:57:02 +0400731}
732
733my $DescriptorTemplate = "
734<?xml version=\"1.0\" encoding=\"utf-8\"?>
735<descriptor>
736
737/* Primary sections */
738
739<version>
740 /* Version of the library */
741</version>
742
743<headers>
744 /* The list of paths to header files and/or
745 directories with header files, one per line */
746</headers>
747
748<libs>
749 /* The list of paths to shared libraries (*.$LIB_EXT) and/or
750 directories with shared libraries, one per line */
751</libs>
752
753/* Optional sections */
754
755<include_paths>
756 /* The list of include paths that will be provided
757 to GCC to compile library headers, one per line.
758 NOTE: If you define this section then the tool
759 will not automatically generate include paths */
760</include_paths>
761
762<add_include_paths>
763 /* The list of include paths that will be added
764 to the automatically generated include paths, one per line */
765</add_include_paths>
766
767<skip_include_paths>
768 /* The list of include paths that will be removed from the
769 list of automatically generated include paths, one per line */
770</skip_include_paths>
771
772<gcc_options>
773 /* Additional GCC options, one per line */
774</gcc_options>
775
776<include_preamble>
777 /* The list of header files that will be
778 included before other headers, one per line.
779 Examples:
780 1) tree.h for libxml2
781 2) ft2build.h for freetype2 */
782</include_preamble>
783
784<defines>
785 /* The list of defines that will be added at the
786 headers compiling stage, one per line:
787 #define A B
788 #define C D */
789</defines>
790
791<skip_types>
792 /* The list of data types, that
793 should not be checked, one per line */
794</skip_types>
795
796<skip_symbols>
797 /* The list of functions (mangled/symbol names in C++),
798 that should not be checked, one per line */
799</skip_symbols>
800
801<skip_namespaces>
802 /* The list of C++ namespaces, that
803 should not be checked, one per line */
804</skip_namespaces>
805
806<skip_constants>
807 /* The list of constants that should
808 not be checked, one name per line */
809</skip_constants>
810
811<skip_headers>
812 /* The list of header files and/or directories
813 with header files that should not be checked, one per line */
814</skip_headers>
815
816<skip_libs>
817 /* The list of shared libraries and/or directories
818 with shared libraries that should not be checked, one per line */
819</skip_libs>
820
821<skip_including>
822 /* The list of header files, that cannot be included
823 directly (or non-self compiled ones), one per line */
824</skip_including>
825
826<search_headers>
827 /* List of directories to be searched
828 for header files to automatically
829 generate include paths, one per line. */
830</search_headers>
831
832<search_libs>
833 /* List of directories to be searched
834 for shared librariess to resolve
835 dependencies, one per line */
836</search_libs>
837
838<tools>
839 /* List of directories with tools used
840 for analysis (GCC toolchain), one per line */
841</tools>
842
843<cross_prefix>
844 /* GCC toolchain prefix.
845 Examples:
846 arm-linux-gnueabi
847 arm-none-symbianelf */
848</cross_prefix>
849
850</descriptor>";
851
852my %Operator_Indication = (
853 "not" => "~",
854 "assign" => "=",
855 "andassign" => "&=",
856 "orassign" => "|=",
857 "xorassign" => "^=",
858 "or" => "|",
859 "xor" => "^",
860 "addr" => "&",
861 "and" => "&",
862 "lnot" => "!",
863 "eq" => "==",
864 "ne" => "!=",
865 "lt" => "<",
866 "lshift" => "<<",
867 "lshiftassign" => "<<=",
868 "rshiftassign" => ">>=",
869 "call" => "()",
870 "mod" => "%",
871 "modassign" => "%=",
872 "subs" => "[]",
873 "land" => "&&",
874 "lor" => "||",
875 "rshift" => ">>",
876 "ref" => "->",
877 "le" => "<=",
878 "deref" => "*",
879 "mult" => "*",
880 "preinc" => "++",
881 "delete" => " delete",
882 "vecnew" => " new[]",
883 "vecdelete" => " delete[]",
884 "predec" => "--",
885 "postinc" => "++",
886 "postdec" => "--",
887 "plusassign" => "+=",
888 "plus" => "+",
889 "minus" => "-",
890 "minusassign" => "-=",
891 "gt" => ">",
892 "ge" => ">=",
893 "new" => " new",
894 "multassign" => "*=",
895 "divassign" => "/=",
896 "div" => "/",
897 "neg" => "-",
898 "pos" => "+",
899 "memref" => "->*",
900 "compound" => "," );
901
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +0400902my %UnknownOperator;
903
904my %NodeType= (
905 "array_type" => "Array",
906 "binfo" => "Other",
907 "boolean_type" => "Intrinsic",
908 "complex_type" => "Intrinsic",
909 "const_decl" => "Other",
910 "enumeral_type" => "Enum",
911 "field_decl" => "Other",
912 "function_decl" => "Other",
913 "function_type" => "FunctionType",
914 "identifier_node" => "Other",
915 "integer_cst" => "Other",
916 "integer_type" => "Intrinsic",
917 "method_type" => "MethodType",
918 "namespace_decl" => "Other",
919 "parm_decl" => "Other",
920 "pointer_type" => "Pointer",
921 "real_cst" => "Other",
922 "real_type" => "Intrinsic",
923 "record_type" => "Struct",
924 "reference_type" => "Ref",
925 "string_cst" => "Other",
926 "template_decl" => "Other",
927 "template_type_parm" => "Other",
928 "tree_list" => "Other",
929 "tree_vec" => "Other",
930 "type_decl" => "Other",
931 "union_type" => "Union",
932 "var_decl" => "Other",
933 "void_type" => "Intrinsic",
934 # "nop_expr" => "Other",
935 # "addr_expr" => "Other",
936 "offset_type" => "Other" );
937
Andrey Ponomarenkoab282102012-03-11 11:57:02 +0400938my %CppKeywords_C = map {$_=>1} (
939 # C++ 2003 keywords
940 "public",
941 "protected",
942 "private",
943 "default",
944 "template",
945 "new",
946 #"asm",
947 "dynamic_cast",
948 "auto",
949 "try",
950 "namespace",
951 "typename",
952 "using",
953 "reinterpret_cast",
954 "friend",
955 "class",
956 "virtual",
957 "const_cast",
958 "mutable",
959 "static_cast",
960 "export",
961 # C++0x keywords
962 "noexcept",
963 "nullptr",
964 "constexpr",
965 "static_assert",
966 "explicit",
967 # cannot be used as a macro name
968 # as it is an operator in C++
969 "and",
970 #"and_eq",
971 "not",
972 #"not_eq",
973 "or"
974 #"or_eq",
975 #"bitand",
976 #"bitor",
977 #"xor",
978 #"xor_eq",
979 #"compl"
980);
981
982my %CppKeywords_F = map {$_=>1} (
983 "delete",
984 "catch",
985 "alignof",
986 "thread_local",
987 "decltype",
988 "typeid"
989);
990
991my %CppKeywords_O = map {$_=>1} (
992 "bool",
993 "register",
994 "inline",
995 "operator"
996);
997
998my %CppKeywords_A = map {$_=>1} (
999 "this",
1000 "throw"
1001);
1002
1003foreach (keys(%CppKeywords_C),
1004keys(%CppKeywords_F),
1005keys(%CppKeywords_O)) {
1006 $CppKeywords_A{$_}=1;
1007}
1008
1009# Header file extensions as described by gcc
1010my $HEADER_EXT = "h|hh|hp|hxx|hpp|h\\+\\+";
1011
1012my %IntrinsicMangling = (
1013 "void" => "v",
1014 "bool" => "b",
1015 "wchar_t" => "w",
1016 "char" => "c",
1017 "signed char" => "a",
1018 "unsigned char" => "h",
1019 "short" => "s",
1020 "unsigned short" => "t",
1021 "int" => "i",
1022 "unsigned int" => "j",
1023 "long" => "l",
1024 "unsigned long" => "m",
1025 "long long" => "x",
1026 "__int64" => "x",
1027 "unsigned long long" => "y",
1028 "__int128" => "n",
1029 "unsigned __int128" => "o",
1030 "float" => "f",
1031 "double" => "d",
1032 "long double" => "e",
1033 "__float80" => "e",
1034 "__float128" => "g",
1035 "..." => "z"
1036);
1037
1038my %StdcxxMangling = (
1039 "3std"=>"St",
1040 "3std9allocator"=>"Sa",
1041 "3std12basic_string"=>"Sb",
1042 "3std12basic_stringIcE"=>"Ss",
1043 "3std13basic_istreamIcE"=>"Si",
1044 "3std13basic_ostreamIcE"=>"So",
1045 "3std14basic_iostreamIcE"=>"Sd"
1046);
1047
1048my %ConstantSuffix = (
1049 "unsigned int"=>"u",
1050 "long"=>"l",
1051 "unsigned long"=>"ul",
1052 "long long"=>"ll",
1053 "unsigned long long"=>"ull"
1054);
1055
1056my %ConstantSuffixR =
1057reverse(%ConstantSuffix);
1058
1059my %OperatorMangling = (
1060 "~" => "co",
1061 "=" => "aS",
1062 "|" => "or",
1063 "^" => "eo",
1064 "&" => "an",#ad (addr)
1065 "==" => "eq",
1066 "!" => "nt",
1067 "!=" => "ne",
1068 "<" => "lt",
1069 "<=" => "le",
1070 "<<" => "ls",
1071 "<<=" => "lS",
1072 ">" => "gt",
1073 ">=" => "ge",
1074 ">>" => "rs",
1075 ">>=" => "rS",
1076 "()" => "cl",
1077 "%" => "rm",
1078 "[]" => "ix",
1079 "&&" => "aa",
1080 "||" => "oo",
1081 "*" => "ml",#de (deref)
1082 "++" => "pp",#
1083 "--" => "mm",#
1084 "new" => "nw",
1085 "delete" => "dl",
1086 "new[]" => "na",
1087 "delete[]" => "da",
1088 "+=" => "pL",
1089 "+" => "pl",#ps (pos)
1090 "-" => "mi",#ng (neg)
1091 "-=" => "mI",
1092 "*=" => "mL",
1093 "/=" => "dV",
1094 "&=" => "aN",
1095 "|=" => "oR",
1096 "%=" => "rM",
1097 "^=" => "eO",
1098 "/" => "dv",
1099 "->*" => "pm",
1100 "->" => "pt",#rf (ref)
1101 "," => "cm",
1102 "?" => "qu",
1103 "." => "dt",
1104 "sizeof"=> "sz"#st
1105);
1106
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04001107my %Intrinsic_Keywords = map {$_=>1} (
1108 "true",
1109 "false",
1110 "_Bool",
1111 "_Complex",
1112 "const",
1113 "int",
1114 "long",
1115 "void",
1116 "short",
1117 "float",
1118 "volatile",
1119 "restrict",
1120 "unsigned",
1121 "signed",
1122 "char",
1123 "double",
1124 "class",
1125 "struct",
1126 "union",
1127 "enum"
1128);
1129
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04001130my %GlibcHeader = map {$_=>1} (
1131 "aliases.h",
1132 "argp.h",
1133 "argz.h",
1134 "assert.h",
1135 "cpio.h",
1136 "ctype.h",
1137 "dirent.h",
1138 "envz.h",
1139 "errno.h",
1140 "error.h",
1141 "execinfo.h",
1142 "fcntl.h",
1143 "fstab.h",
1144 "ftw.h",
1145 "glob.h",
1146 "grp.h",
1147 "iconv.h",
1148 "ifaddrs.h",
1149 "inttypes.h",
1150 "langinfo.h",
1151 "limits.h",
1152 "link.h",
1153 "locale.h",
1154 "malloc.h",
1155 "math.h",
1156 "mntent.h",
1157 "monetary.h",
1158 "nl_types.h",
1159 "obstack.h",
1160 "printf.h",
1161 "pwd.h",
1162 "regex.h",
1163 "sched.h",
1164 "search.h",
1165 "setjmp.h",
1166 "shadow.h",
1167 "signal.h",
1168 "spawn.h",
1169 "stdarg.h",
1170 "stdint.h",
1171 "stdio.h",
1172 "stdlib.h",
1173 "string.h",
1174 "tar.h",
1175 "termios.h",
1176 "time.h",
1177 "ulimit.h",
1178 "unistd.h",
1179 "utime.h",
1180 "wchar.h",
1181 "wctype.h",
1182 "wordexp.h" );
1183
1184my %GlibcDir = map {$_=>1} (
1185 "arpa",
1186 "bits",
1187 "gnu",
1188 "netinet",
1189 "net",
1190 "nfs",
1191 "rpc",
1192 "sys",
1193 "linux" );
1194
1195my %LocalIncludes = map {$_=>1} (
1196 "/usr/local/include",
1197 "/usr/local" );
1198
1199my %OS_AddPath=(
1200# These paths are needed if the tool cannot detect them automatically
1201 "macos"=>{
1202 "include"=>{
1203 "/Library"=>1,
1204 "/Developer/usr/include"=>1
1205 },
1206 "lib"=>{
1207 "/Library"=>1,
1208 "/Developer/usr/lib"=>1
1209 },
1210 "bin"=>{
1211 "/Developer/usr/bin"=>1
1212 }
1213 },
1214 "beos"=>{
1215 # Haiku has GCC 2.95.3 by default
1216 # try to find GCC>=3.0 in /boot/develop/abi
1217 "include"=>{
1218 "/boot/common"=>1,
1219 "/boot/develop"=>1},
1220 "lib"=>{
1221 "/boot/common/lib"=>1,
1222 "/boot/system/lib"=>1,
1223 "/boot/apps"=>1},
1224 "bin"=>{
1225 "/boot/common/bin"=>1,
1226 "/boot/system/bin"=>1,
1227 "/boot/develop/abi"=>1
1228 }
1229}
1230);
1231
1232my %Slash_Type=(
1233 "default"=>"/",
1234 "windows"=>"\\"
1235);
1236
1237my $SLASH = $Slash_Type{$OSgroup}?$Slash_Type{$OSgroup}:$Slash_Type{"default"};
1238
1239# Global Variables
1240my %COMMON_LANGUAGE=(
1241 1 => "C",
1242 2 => "C" );
1243
1244my $MAX_COMMAND_LINE_ARGUMENTS = 4096;
1245my (%WORD_SIZE, %CPU_ARCH, %GCC_VERSION);
1246
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04001247my $STDCXX_TESTING = 0;
1248my $GLIBC_TESTING = 0;
1249
1250my $CheckHeadersOnly = $CheckHeadersOnly_Opt;
1251my $CheckObjectsOnly = $CheckObjectsOnly_Opt;
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04001252my $TargetComponent;
1253
1254# Set Target Component Name
1255if($TargetComponent_Opt) {
1256 $TargetComponent = lc($TargetComponent_Opt);
1257}
1258else
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04001259{ # default: library
1260 # other components: header, system, ...
1261 $TargetComponent = "library";
1262}
1263
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04001264my $TOP_REF = "<a style='font-size:11px;' href='#Top'>to the top</a>";
1265
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04001266my $SystemRoot;
1267
1268my $MAIN_CPP_DIR;
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04001269my %RESULT;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04001270my %LOG_PATH;
1271my %DEBUG_PATH;
1272my %Cache;
1273my %LibInfo;
1274my $COMPILE_ERRORS = 0;
1275my %CompilerOptions;
1276my %CheckedDyLib;
1277my $TargetLibraryShortName = parse_libname($TargetLibraryName, "shortest", $OSgroup);
1278
1279# Constants (#defines)
1280my %Constants;
1281my %SkipConstants;
1282
1283# Types
1284my %TypeInfo;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04001285my %TemplateInstance;
Andrey Ponomarenko85043792012-05-14 16:48:07 +04001286my %TemplateDecl;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04001287my %SkipTypes = (
1288 "1"=>{},
1289 "2"=>{} );
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04001290my %CheckedTypes;
1291my %TName_Tid;
1292my %EnumMembName_Id;
1293my %NestedNameSpaces = (
1294 "1"=>{},
1295 "2"=>{} );
1296my %UsedType;
1297my %VirtualTable;
Andrey Ponomarenko16934472012-03-29 15:37:04 +04001298my %VirtualTable_Model;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04001299my %ClassVTable;
1300my %ClassVTable_Content;
1301my %VTableClass;
1302my %AllocableClass;
1303my %ClassMethods;
Andrey Ponomarenko16934472012-03-29 15:37:04 +04001304my %ClassNames;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04001305my %Class_SubClasses;
1306my %OverriddenMethods;
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04001307my $MAX_ID = 0;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04001308
1309# Typedefs
1310my %Typedef_BaseName;
1311my %Typedef_Tr;
1312my %Typedef_Eq;
1313my %StdCxxTypedef;
1314my %MissedTypedef;
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04001315my %MissedBase;
1316my %MissedBase_R;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04001317
1318# Symbols
1319my %SymbolInfo;
1320my %tr_name;
1321my %mangled_name_gcc;
1322my %mangled_name;
1323my %SkipSymbols = (
1324 "1"=>{},
1325 "2"=>{} );
1326my %SkipNameSpaces = (
1327 "1"=>{},
1328 "2"=>{} );
1329my %SymbolsList;
1330my %SymbolsList_App;
1331my %CheckedSymbols;
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04001332my %Symbol_Library = (
1333 "1"=>{},
1334 "2"=>{} );
1335my %Library_Symbol = (
1336 "1"=>{},
1337 "2"=>{} );
1338my %DepSymbol_Library = (
1339 "1"=>{},
1340 "2"=>{} );
1341my %DepLibrary_Symbol = (
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04001342 "1"=>{},
1343 "2"=>{} );
1344my %MangledNames;
1345my %AddIntParams;
1346my %Interface_Impl;
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04001347my %GlobalDataObject;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04001348
1349# Headers
1350my %Include_Preamble;
1351my %Registered_Headers;
1352my %HeaderName_Paths;
1353my %Header_Dependency;
1354my %Include_Neighbors;
1355my %Include_Paths;
1356my %INC_PATH_AUTODETECT = (
1357 "1"=>1,
1358 "2"=>1 );
1359my %Add_Include_Paths;
1360my %Skip_Include_Paths;
1361my %RegisteredDirs;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04001362my %Header_ErrorRedirect;
1363my %Header_Includes;
1364my %Header_ShouldNotBeUsed;
1365my %RecursiveIncludes;
1366my %Header_Include_Prefix;
1367my %SkipHeaders;
1368my %SkipHeadersList=(
1369 "1"=>{},
1370 "2"=>{} );
1371my %SkipLibs;
1372my %Include_Order;
1373my %TUnit_NameSpaces;
1374
1375my %C99Mode = (
1376 "1"=>0,
1377 "2"=>0 );
1378my %AutoPreambleMode = (
1379 "1"=>0,
1380 "2"=>0 );
1381my %MinGWMode = (
1382 "1"=>0,
1383 "2"=>0 );
1384
1385# Shared Objects
1386my %DyLib_DefaultPath;
1387my %InputObject_Paths;
1388my %RegisteredObjDirs;
1389
1390# System Objects
1391my %SystemObjects;
1392my %DefaultLibPaths;
1393
1394# System Headers
1395my %SystemHeaders;
1396my %DefaultCppPaths;
1397my %DefaultGccPaths;
1398my %DefaultIncPaths;
1399my %DefaultCppHeader;
1400my %DefaultGccHeader;
1401my %UserIncPath;
1402
1403# Merging
1404my %CompleteSignature;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04001405my $Version;
1406my %AddedInt;
1407my %RemovedInt;
1408my %AddedInt_Virt;
1409my %RemovedInt_Virt;
1410my %VirtualReplacement;
1411my %ChangedTypedef;
1412my %CompatRules;
1413my %IncompleteRules;
1414my %UnknownRules;
Andrey Ponomarenko16934472012-03-29 15:37:04 +04001415my %VTableChanged_M;
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04001416my %ExtendedSymbols;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04001417my %ReturnedClass;
1418my %ParamClass;
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04001419my %SourceAlternative;
1420my %SourceAlternative_B;
1421my %SourceReplacement;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04001422
1423# OS Compliance
1424my %TargetLibs;
1425my %TargetHeaders;
1426
1427# OS Specifics
1428my $OStarget = $OSgroup;
1429my %TargetTools;
1430
1431# Compliance Report
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04001432my %Type_MaxSeverity;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04001433
1434# Recursion locks
1435my @RecurLib;
1436my @RecurSymlink;
1437my @RecurTypes;
1438my @RecurInclude;
1439my @RecurConstant;
1440
1441# System
1442my %SystemPaths;
1443my %DefaultBinPaths;
1444my $GCC_PATH;
1445
1446# Symbols versioning
1447my %SymVer = (
1448 "1"=>{},
1449 "2"=>{} );
1450
1451# Problem descriptions
1452my %CompatProblems;
1453my %ProblemsWithConstants;
1454my %ImplProblems;
1455my %TotalAffected;
1456
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04001457# Reports
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04001458my $ContentID = 1;
1459my $ContentSpanStart = "<span class=\"section\" onclick=\"javascript:showContent(this, 'CONTENT_ID')\">\n";
1460my $ContentSpanStart_Affected = "<span class=\"section_affected\" onclick=\"javascript:showContent(this, 'CONTENT_ID')\">\n";
1461my $ContentSpanStart_Info = "<span class=\"section_info\" onclick=\"javascript:showContent(this, 'CONTENT_ID')\">\n";
1462my $ContentSpanEnd = "</span>\n";
1463my $ContentDivStart = "<div id=\"CONTENT_ID\" style=\"display:none;\">\n";
1464my $ContentDivEnd = "</div>\n";
1465my $Content_Counter = 0;
1466
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04001467# Modes
1468my $JoinReport = 1;
1469my $DoubleReport = 0;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04001470
1471sub get_Modules()
1472{
1473 my $TOOL_DIR = get_dirname($0);
1474 if(not $TOOL_DIR)
1475 { # patch for MS Windows
1476 $TOOL_DIR = ".";
1477 }
1478 my @SEARCH_DIRS = (
1479 # tool's directory
1480 abs_path($TOOL_DIR),
1481 # relative path to modules
1482 abs_path($TOOL_DIR)."/../share/abi-compliance-checker",
1483 # system directory
1484 "ACC_MODULES_INSTALL_PATH"
1485 );
1486 foreach my $DIR (@SEARCH_DIRS)
1487 {
1488 if(not is_abs($DIR))
1489 { # relative path
1490 $DIR = abs_path($TOOL_DIR)."/".$DIR;
1491 }
1492 if(-d $DIR."/modules") {
1493 return $DIR."/modules";
1494 }
1495 }
1496 exitStatus("Module_Error", "can't find modules");
1497}
1498
1499sub loadModule($)
1500{
1501 my $Name = $_[0];
1502 my $Path = $MODULES_DIR."/Internals/$Name.pm";
1503 if(not -f $Path) {
1504 exitStatus("Module_Error", "can't access \'$Path\'");
1505 }
1506 require $Path;
1507}
1508
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04001509sub showPos($)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04001510{
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04001511 my $Number = $_[0];
1512 if(not $Number) {
1513 $Number = 1;
1514 }
1515 else {
1516 $Number = int($Number)+1;
1517 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04001518 if($Number>3) {
1519 return $Number."th";
1520 }
1521 elsif($Number==1) {
1522 return "1st";
1523 }
1524 elsif($Number==2) {
1525 return "2nd";
1526 }
1527 elsif($Number==3) {
1528 return "3rd";
1529 }
1530 else {
1531 return $Number;
1532 }
1533}
1534
1535sub search_Tools($)
1536{
1537 my $Name = $_[0];
1538 return "" if(not $Name);
1539 if(my @Paths = keys(%TargetTools))
1540 {
1541 foreach my $Path (@Paths)
1542 {
1543 if(-f joinPath($Path, $Name)) {
1544 return joinPath($Path, $Name);
1545 }
1546 if($CrossPrefix)
1547 { # user-defined prefix (arm-none-symbianelf, ...)
1548 my $Candidate = joinPath($Path, $CrossPrefix."-".$Name);
1549 if(-f $Candidate) {
1550 return $Candidate;
1551 }
1552 }
1553 }
1554 }
1555 else {
1556 return "";
1557 }
1558}
1559
1560sub synch_Cmd($)
1561{
1562 my $Name = $_[0];
1563 if(not $GCC_PATH)
1564 { # GCC was not found yet
1565 return "";
1566 }
1567 my $Candidate = $GCC_PATH;
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04001568 if($Candidate=~s/\bgcc(|\.\w+)\Z/$Name$1/) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04001569 return $Candidate;
1570 }
1571 return "";
1572}
1573
1574sub get_CmdPath($)
1575{
1576 my $Name = $_[0];
1577 return "" if(not $Name);
1578 if(defined $Cache{"get_CmdPath"}{$Name}) {
1579 return $Cache{"get_CmdPath"}{$Name};
1580 }
1581 my %BinUtils = map {$_=>1} (
1582 "c++filt",
1583 "objdump",
1584 "readelf"
1585 );
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04001586 if($BinUtils{$Name} and $GCC_PATH)
1587 {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04001588 if(my $Dir = get_dirname($GCC_PATH)) {
1589 $TargetTools{$Dir}=1;
1590 }
1591 }
1592 my $Path = search_Tools($Name);
1593 if(not $Path and $OSgroup eq "windows") {
1594 $Path = search_Tools($Name.".exe");
1595 }
1596 if(not $Path and $BinUtils{$Name})
1597 {
1598 if($CrossPrefix)
1599 { # user-defined prefix
1600 $Path = search_Cmd($CrossPrefix."-".$Name);
1601 }
1602 }
1603 if(not $Path and $BinUtils{$Name})
1604 {
1605 if(my $Candidate = synch_Cmd($Name))
1606 { # synch with GCC
1607 if($Candidate=~/[\/\\]/)
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04001608 { # command path
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04001609 if(-f $Candidate) {
1610 $Path = $Candidate;
1611 }
1612 }
1613 elsif($Candidate = search_Cmd($Candidate))
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04001614 { # command name
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04001615 $Path = $Candidate;
1616 }
1617 }
1618 }
1619 if(not $Path) {
1620 $Path = search_Cmd($Name);
1621 }
1622 if(not $Path and $OSgroup eq "windows")
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04001623 { # search for *.exe file
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04001624 $Path=search_Cmd($Name.".exe");
1625 }
1626 if($Path=~/\s/) {
1627 $Path = "\"".$Path."\"";
1628 }
1629 return ($Cache{"get_CmdPath"}{$Name}=$Path);
1630}
1631
1632sub search_Cmd($)
1633{
1634 my $Name = $_[0];
1635 return "" if(not $Name);
1636 if(defined $Cache{"search_Cmd"}{$Name}) {
1637 return $Cache{"search_Cmd"}{$Name};
1638 }
1639 if(my $DefaultPath = get_CmdPath_Default($Name)) {
1640 return ($Cache{"search_Cmd"}{$Name} = $DefaultPath);
1641 }
1642 foreach my $Path (sort {length($a)<=>length($b)} keys(%{$SystemPaths{"bin"}}))
1643 {
1644 my $CmdPath = joinPath($Path,$Name);
1645 if(-f $CmdPath)
1646 {
1647 if($Name=~/gcc/) {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04001648 next if(not check_gcc($CmdPath, "3"));
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04001649 }
1650 return ($Cache{"search_Cmd"}{$Name} = $CmdPath);
1651 }
1652 }
1653 return ($Cache{"search_Cmd"}{$Name} = "");
1654}
1655
1656sub get_CmdPath_Default($)
1657{ # search in PATH
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04001658 return "" if(not $_[0]);
1659 if(defined $Cache{"get_CmdPath_Default"}{$_[0]}) {
1660 return $Cache{"get_CmdPath_Default"}{$_[0]};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04001661 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04001662 return ($Cache{"get_CmdPath_Default"}{$_[0]} = get_CmdPath_Default_I($_[0]));
1663}
1664
1665sub get_CmdPath_Default_I($)
1666{ # search in PATH
1667 my $Name = $_[0];
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04001668 if($Name=~/find/)
1669 { # special case: search for "find" utility
1670 if(`find . -maxdepth 0 2>$TMP_DIR/null`) {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04001671 return "find";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04001672 }
1673 }
1674 elsif($Name=~/gcc/) {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04001675 return check_gcc($Name, "3");
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04001676 }
1677 if(check_command($Name)) {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04001678 return $Name;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04001679 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04001680 if($OSgroup eq "windows")
1681 {
1682 if(`$Name /? 2>$TMP_DIR/null`) {
1683 return $Name;
1684 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04001685 }
1686 if($Name!~/which/)
1687 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04001688 if(my $WhichCmd = get_CmdPath("which"))
1689 {
1690 if(`$WhichCmd $Name 2>$TMP_DIR/null`) {
1691 return $Name;
1692 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04001693 }
1694 }
1695 foreach my $Path (sort {length($a)<=>length($b)} keys(%DefaultBinPaths))
1696 {
1697 if(-f $Path."/".$Name) {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04001698 return joinPath($Path,$Name);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04001699 }
1700 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04001701 return "";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04001702}
1703
1704sub clean_path($)
1705{
1706 my $Path = $_[0];
1707 $Path=~s/[\/\\]+\Z//g;
1708 return $Path;
1709}
1710
1711sub classifyPath($)
1712{
1713 my $Path = $_[0];
1714 if($Path=~/[\*\[]/)
1715 { # wildcard
1716 $Path=~s/\*/.*/g;
1717 $Path=~s/\\/\\\\/g;
1718 return ($Path, "Pattern");
1719 }
1720 elsif($Path=~/[\/\\]/)
1721 { # directory or relative path
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04001722 $Path=~s/[\/\\]+\Z//g;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04001723 return (path_format($Path, $OSgroup), "Path");
1724 }
1725 else {
1726 return ($Path, "Name");
1727 }
1728}
1729
1730sub readDescriptor($$)
1731{
1732 my ($LibVersion, $Content) = @_;
1733 return if(not $LibVersion);
1734 my $DName = $DumpAPI?"descriptor":"descriptor \"d$LibVersion\"";
1735 if(not $Content) {
1736 exitStatus("Error", "$DName is empty");
1737 }
1738 if($Content!~/\</) {
1739 exitStatus("Error", "$DName is not a descriptor (see -d1 option)");
1740 }
1741 $Content=~s/\/\*(.|\n)+?\*\///g;
1742 $Content=~s/<\!--(.|\n)+?-->//g;
1743 $Descriptor{$LibVersion}{"Version"} = parseTag(\$Content, "version");
1744 if($TargetVersion{$LibVersion}) {
1745 $Descriptor{$LibVersion}{"Version"} = $TargetVersion{$LibVersion};
1746 }
1747 if(not $Descriptor{$LibVersion}{"Version"}) {
1748 exitStatus("Error", "version in the $DName is not specified (<version> section)");
1749 }
1750 if($Content=~/{RELPATH}/)
1751 {
1752 if(my $RelDir = $RelativeDirectory{$LibVersion}) {
1753 $Content =~ s/{RELPATH}/$RelDir/g;
1754 }
1755 else
1756 {
1757 my $NeedRelpath = $DumpAPI?"-relpath":"-relpath$LibVersion";
1758 exitStatus("Error", "you have not specified $NeedRelpath option, but the $DName contains {RELPATH} macro");
1759 }
1760 }
1761
1762 if(not $CheckObjectsOnly_Opt)
1763 {
1764 my $DHeaders = parseTag(\$Content, "headers");
1765 if(not $DHeaders) {
1766 exitStatus("Error", "header files in the $DName are not specified (<headers> section)");
1767 }
1768 elsif(lc($DHeaders) ne "none")
1769 { # append the descriptor headers list
1770 if($Descriptor{$LibVersion}{"Headers"})
1771 { # multiple descriptors
1772 $Descriptor{$LibVersion}{"Headers"} .= "\n".$DHeaders;
1773 }
1774 else {
1775 $Descriptor{$LibVersion}{"Headers"} = $DHeaders;
1776 }
1777 foreach my $Path (split(/\s*\n\s*/, $DHeaders))
1778 {
1779 if(not -e $Path) {
1780 exitStatus("Access_Error", "can't access \'$Path\'");
1781 }
1782 }
1783 }
1784 }
1785 if(not $CheckHeadersOnly_Opt)
1786 {
1787 my $DObjects = parseTag(\$Content, "libs");
1788 if(not $DObjects) {
1789 exitStatus("Error", "$SLIB_TYPE libraries in the $DName are not specified (<libs> section)");
1790 }
1791 elsif(lc($DObjects) ne "none")
1792 { # append the descriptor libraries list
1793 if($Descriptor{$LibVersion}{"Libs"})
1794 { # multiple descriptors
1795 $Descriptor{$LibVersion}{"Libs"} .= "\n".$DObjects;
1796 }
1797 else {
1798 $Descriptor{$LibVersion}{"Libs"} .= $DObjects;
1799 }
1800 foreach my $Path (split(/\s*\n\s*/, $DObjects))
1801 {
1802 if(not -e $Path) {
1803 exitStatus("Access_Error", "can't access \'$Path\'");
1804 }
1805 }
1806 }
1807 }
1808 foreach my $Path (split(/\s*\n\s*/, parseTag(\$Content, "search_headers")))
1809 {
1810 $Path = clean_path($Path);
1811 if(not -d $Path) {
1812 exitStatus("Access_Error", "can't access directory \'$Path\'");
1813 }
1814 $Path = path_format($Path, $OSgroup);
1815 $SystemPaths{"include"}{$Path}=1;
1816 }
1817 foreach my $Path (split(/\s*\n\s*/, parseTag(\$Content, "search_libs")))
1818 {
1819 $Path = clean_path($Path);
1820 if(not -d $Path) {
1821 exitStatus("Access_Error", "can't access directory \'$Path\'");
1822 }
1823 $Path = path_format($Path, $OSgroup);
1824 $SystemPaths{"lib"}{$Path}=1;
1825 }
1826 foreach my $Path (split(/\s*\n\s*/, parseTag(\$Content, "tools")))
1827 {
1828 $Path=clean_path($Path);
1829 if(not -d $Path) {
1830 exitStatus("Access_Error", "can't access directory \'$Path\'");
1831 }
1832 $Path = path_format($Path, $OSgroup);
1833 $SystemPaths{"bin"}{$Path}=1;
1834 $TargetTools{$Path}=1;
1835 }
1836 if(my $Prefix = parseTag(\$Content, "cross_prefix")) {
1837 $CrossPrefix = $Prefix;
1838 }
1839 foreach my $Path (split(/\s*\n\s*/, parseTag(\$Content, "include_paths")))
1840 {
1841 $Path=clean_path($Path);
1842 if(not -d $Path) {
1843 exitStatus("Access_Error", "can't access directory \'$Path\'");
1844 }
1845 $Path = path_format($Path, $OSgroup);
1846 $Descriptor{$LibVersion}{"IncludePaths"}{$Path} = 1;
1847 }
1848 foreach my $Path (split(/\s*\n\s*/, parseTag(\$Content, "add_include_paths")))
1849 {
1850 $Path=clean_path($Path);
1851 if(not -d $Path) {
1852 exitStatus("Access_Error", "can't access directory \'$Path\'");
1853 }
1854 $Path = path_format($Path, $OSgroup);
1855 $Descriptor{$LibVersion}{"AddIncludePaths"}{$Path} = 1;
1856 }
1857 foreach my $Path (split(/\s*\n\s*/, parseTag(\$Content, "skip_include_paths")))
1858 {
1859 # skip some auto-generated include paths
1860 $Skip_Include_Paths{$LibVersion}{path_format($Path)}=1;
1861 }
1862 foreach my $Path (split(/\s*\n\s*/, parseTag(\$Content, "skip_including")))
1863 {
1864 # skip direct including of some headers
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04001865 $SkipHeadersList{$LibVersion}{$Path} = 2;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04001866 my ($CPath, $Type) = classifyPath($Path);
1867 $SkipHeaders{$LibVersion}{$Type}{$CPath} = 2;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04001868 }
1869 $Descriptor{$LibVersion}{"GccOptions"} = parseTag(\$Content, "gcc_options");
1870 foreach my $Option (split(/\s*\n\s*/, $Descriptor{$LibVersion}{"GccOptions"})) {
1871 $CompilerOptions{$LibVersion} .= " ".$Option;
1872 }
1873 $Descriptor{$LibVersion}{"SkipHeaders"} = parseTag(\$Content, "skip_headers");
1874 foreach my $Path (split(/\s*\n\s*/, $Descriptor{$LibVersion}{"SkipHeaders"}))
1875 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04001876 $SkipHeadersList{$LibVersion}{$Path} = 1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04001877 my ($CPath, $Type) = classifyPath($Path);
1878 $SkipHeaders{$LibVersion}{$Type}{$CPath} = 1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04001879 }
1880 $Descriptor{$LibVersion}{"SkipLibs"} = parseTag(\$Content, "skip_libs");
1881 foreach my $Path (split(/\s*\n\s*/, $Descriptor{$LibVersion}{"SkipLibs"}))
1882 {
1883 my ($CPath, $Type) = classifyPath($Path);
1884 $SkipLibs{$LibVersion}{$Type}{$CPath} = 1;
1885 }
1886 if(my $DDefines = parseTag(\$Content, "defines"))
1887 {
1888 if($Descriptor{$LibVersion}{"Defines"})
1889 { # multiple descriptors
1890 $Descriptor{$LibVersion}{"Defines"} .= "\n".$DDefines;
1891 }
1892 else {
1893 $Descriptor{$LibVersion}{"Defines"} = $DDefines;
1894 }
1895 }
1896 foreach my $Order (split(/\s*\n\s*/, parseTag(\$Content, "include_order")))
1897 {
1898 if($Order=~/\A(.+):(.+)\Z/) {
1899 $Include_Order{$LibVersion}{$1} = $2;
1900 }
1901 }
1902 foreach my $Type_Name (split(/\s*\n\s*/, parseTag(\$Content, "opaque_types")),
1903 split(/\s*\n\s*/, parseTag(\$Content, "skip_types")))
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04001904 { # opaque_types renamed to skip_types (1.23.4)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04001905 $SkipTypes{$LibVersion}{$Type_Name} = 1;
1906 }
1907 foreach my $Symbol (split(/\s*\n\s*/, parseTag(\$Content, "skip_interfaces")),
1908 split(/\s*\n\s*/, parseTag(\$Content, "skip_symbols")))
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04001909 { # skip_interfaces renamed to skip_symbols (1.22.1)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04001910 $SkipSymbols{$LibVersion}{$Symbol} = 1;
1911 }
1912 foreach my $NameSpace (split(/\s*\n\s*/, parseTag(\$Content, "skip_namespaces"))) {
1913 $SkipNameSpaces{$LibVersion}{$NameSpace} = 1;
1914 }
1915 foreach my $Constant (split(/\s*\n\s*/, parseTag(\$Content, "skip_constants"))) {
1916 $SkipConstants{$LibVersion}{$Constant} = 1;
1917 }
1918 if(my $DIncPreamble = parseTag(\$Content, "include_preamble"))
1919 {
1920 if($Descriptor{$LibVersion}{"IncludePreamble"})
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04001921 { # multiple descriptors
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04001922 $Descriptor{$LibVersion}{"IncludePreamble"} .= "\n".$DIncPreamble;
1923 }
1924 else {
1925 $Descriptor{$LibVersion}{"IncludePreamble"} = $DIncPreamble;
1926 }
1927 }
1928}
1929
1930sub parseTag($$)
1931{
1932 my ($CodeRef, $Tag) = @_;
1933 return "" if(not $CodeRef or not ${$CodeRef} or not $Tag);
1934 if(${$CodeRef}=~s/\<\Q$Tag\E\>((.|\n)+?)\<\/\Q$Tag\E\>//)
1935 {
1936 my $Content = $1;
1937 $Content=~s/(\A\s+|\s+\Z)//g;
1938 return $Content;
1939 }
1940 else {
1941 return "";
1942 }
1943}
1944
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04001945sub getInfo($)
1946{
Andrey Ponomarenko85043792012-05-14 16:48:07 +04001947 my $DumpPath = $_[0];
1948 return if(not $DumpPath or not -f $DumpPath);
1949
1950 readTUDump($DumpPath);
1951
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04001952 # processing info
1953 setTemplateParams_All();
1954 getTypeInfo_All();
1955 simplifyNames();
1956 getSymbolInfo_All();
1957 getVarInfo_All();
1958
Andrey Ponomarenko85043792012-05-14 16:48:07 +04001959 # clean memory
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04001960 %LibInfo = ();
1961 %TemplateInstance = ();
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04001962 %MangledNames = ();
Andrey Ponomarenko85043792012-05-14 16:48:07 +04001963 %TemplateDecl = ();
1964 %StdCxxTypedef = ();
1965 %MissedTypedef = ();
1966 %Typedef_Tr = ();
1967 %Typedef_Eq = ();
1968
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04001969 # clean cache
1970 delete($Cache{"getTypeAttr"});
1971 delete($Cache{"getTypeDeclId"});
1972
1973 # remove unused types
1974 if($BinaryOnly and not $ExtendedCheck)
1975 { # --binary
1976 removeUnused($Version, "All");
1977 }
1978 else {
1979 removeUnused($Version, "Derived");
1980 }
1981
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04001982 if($Debug) {
1983 # debugMangling($Version);
1984 }
1985}
1986
Andrey Ponomarenko85043792012-05-14 16:48:07 +04001987sub readTUDump($)
1988{
1989 my $DumpPath = $_[0];
1990
1991 open(TU_DUMP, $DumpPath);
1992 local $/ = undef;
1993 my $Content = <TU_DUMP>;
1994 close(TU_DUMP);
1995
1996 unlink($DumpPath);
1997
1998 $Content=~s/\n[ ]+/ /g;
1999 my @Lines = split("\n", $Content);
2000
2001 # clean memory
2002 undef $Content;
2003
2004 $MAX_ID = $#Lines+1;
2005
2006 foreach (0 .. $#Lines)
2007 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04002008 if($Lines[$_]=~/\A\@(\d+)[ ]+([a-z_]+)[ ]+(.+)\Z/i)
Andrey Ponomarenko85043792012-05-14 16:48:07 +04002009 { # get a number and attributes of a node
2010 next if(not $NodeType{$2});
2011 $LibInfo{$Version}{"info_type"}{$1}=$2;
2012 $LibInfo{$Version}{"info"}{$1}=$3;
2013 }
2014
2015 # clean memory
2016 delete($Lines[$_]);
2017 }
2018
2019 # clean memory
2020 undef @Lines;
2021}
2022
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002023sub simplifyNames()
2024{
2025 foreach my $Base (keys(%{$Typedef_Tr{$Version}}))
2026 {
2027 my @Translations = keys(%{$Typedef_Tr{$Version}{$Base}});
2028 if($#Translations==0 and length($Translations[0])<=length($Base)) {
2029 $Typedef_Eq{$Version}{$Base} = $Translations[0];
2030 }
2031 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04002032 foreach my $Tid (keys(%{$TypeInfo{$Version}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002033 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04002034 my $TypeName = $TypeInfo{$Version}{$Tid}{"Name"};
2035 if(not $TypeName) {
2036 next;
2037 }
2038 next if(index($TypeName,"<")==-1);# template instances only
2039 if($TypeName=~/>(::\w+)+\Z/)
2040 { # skip unused types
2041 next;
2042 };
2043 foreach my $Base (sort {length($b)<=>length($a)}
2044 sort {$b cmp $a} keys(%{$Typedef_Eq{$Version}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002045 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04002046 next if(not $Base);
2047 next if(index($TypeName,$Base)==-1);
2048 next if(length($TypeName) - length($Base) <= 3);
2049 my $Typedef = $Typedef_Eq{$Version}{$Base};
2050 $TypeName=~s/(\<|\,)\Q$Base\E(\W|\Z)/$1$Typedef$2/g;
2051 $TypeName=~s/(\<|\,)\Q$Base\E(\w|\Z)/$1$Typedef $2/g;
2052 if(defined $TypeInfo{$Version}{$Tid}{"TParam"})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002053 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04002054 foreach my $TPos (keys(%{$TypeInfo{$Version}{$Tid}{"TParam"}}))
Andrey Ponomarenko85043792012-05-14 16:48:07 +04002055 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04002056 my $TPName = $TypeInfo{$Version}{$Tid}{"TParam"}{$TPos}{"name"};
2057 $TPName=~s/\A\Q$Base\E(\W|\Z)/$Typedef$1/g;
2058 $TypeInfo{$Version}{$Tid}{"TParam"}{$TPos}{"name"} = formatName($TPName);
Andrey Ponomarenko85043792012-05-14 16:48:07 +04002059 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002060 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002061 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04002062 $TypeName = formatName($TypeName);
2063 $TypeInfo{$Version}{$Tid}{"Name"} = $TypeName;
2064 $TName_Tid{$Version}{$TypeName} = $Tid;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002065 }
2066}
2067
2068sub setTemplateParams_All()
2069{
2070 foreach (keys(%{$LibInfo{$Version}{"info"}}))
2071 {
2072 if($LibInfo{$Version}{"info_type"}{$_} eq "template_decl") {
2073 setTemplateParams($_);
2074 }
2075 }
2076}
2077
2078sub setTemplateParams($)
2079{
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04002080 if(my $Info = $LibInfo{$Version}{"info"}{$_[0]})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002081 {
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04002082 if($Info=~/(inst|spcs)[ ]*:[ ]*@(\d+) /)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002083 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04002084 my $TmplInst_Id = $2;
2085 setTemplateInstParams($TmplInst_Id);
2086 while($TmplInst_Id = getNextElem($TmplInst_Id)) {
2087 setTemplateInstParams($TmplInst_Id);
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04002088 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002089 }
2090 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04002091 if(my $TypeId = getTreeAttr_Type($_[0]))
Andrey Ponomarenko85043792012-05-14 16:48:07 +04002092 {
2093 if(my $IType = $LibInfo{$Version}{"info_type"}{$TypeId})
2094 {
2095 if($IType eq "record_type") {
2096 $TemplateDecl{$Version}{$TypeId}=1;
2097 }
2098 }
2099 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002100}
2101
2102sub setTemplateInstParams($)
2103{
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04002104 if(my $Info = $LibInfo{$Version}{"info"}{$_[0]})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002105 {
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04002106 my ($Params_InfoId, $ElemId) = ();
2107 if($Info=~/purp[ ]*:[ ]*@(\d+) /) {
2108 $Params_InfoId = $1;
2109 }
2110 if($Info=~/valu[ ]*:[ ]*@(\d+) /) {
2111 $ElemId = $1;
2112 }
2113 if($Params_InfoId and $ElemId)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002114 {
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04002115 my $Params_Info = $LibInfo{$Version}{"info"}{$Params_InfoId};
2116 while($Params_Info=~s/ (\d+)[ ]*:[ ]*\@(\d+) / /)
2117 {
2118 my ($PPos, $PTypeId) = ($1, $2);
2119 if(my $PType = $LibInfo{$Version}{"info_type"}{$PTypeId})
2120 {
Andrey Ponomarenko85043792012-05-14 16:48:07 +04002121 if($PType eq "template_type_parm")
2122 {
2123 $TemplateDecl{$Version}{$ElemId}=1;
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04002124 return;
2125 }
2126 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +04002127 if($LibInfo{$Version}{"info_type"}{$ElemId} eq "function_decl")
2128 { # functions
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04002129 $TemplateInstance{$Version}{"Func"}{$ElemId}{$PPos} = $PTypeId;
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04002130 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +04002131 else
2132 { # types
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04002133 $TemplateInstance{$Version}{"Type"}{$ElemId}{$PPos} = $PTypeId;
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04002134 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002135 }
2136 }
2137 }
2138}
2139
2140sub getTypeDeclId($)
2141{
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04002142 if($_[0])
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04002143 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04002144 if(defined $Cache{"getTypeDeclId"}{$Version}{$_[0]}) {
2145 return $Cache{"getTypeDeclId"}{$Version}{$_[0]};
2146 }
2147 if(my $Info = $LibInfo{$Version}{"info"}{$_[0]})
2148 {
2149 if($Info=~/name[ ]*:[ ]*@(\d+)/) {
2150 return ($Cache{"getTypeDeclId"}{$Version}{$_[0]} = $1);
2151 }
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04002152 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002153 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04002154 return ($Cache{"getTypeDeclId"}{$Version}{$_[0]} = 0);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002155}
2156
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002157sub getTypeInfo_All()
2158{
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04002159 if(not check_gcc($GCC_PATH, "4.5"))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002160 { # support for GCC < 4.5
2161 # missed typedefs: QStyle::State is typedef to QFlags<QStyle::StateFlag>
2162 # but QStyleOption.state is of type QFlags<QStyle::StateFlag> in the TU dump
2163 # FIXME: check GCC versions
2164 addMissedTypes_Pre();
2165 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04002166
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002167 foreach (sort {int($a)<=>int($b)} keys(%{$LibInfo{$Version}{"info"}}))
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04002168 { # forward order only
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002169 my $IType = $LibInfo{$Version}{"info_type"}{$_};
2170 if($IType=~/_type\Z/ and $IType ne "function_type"
2171 and $IType ne "method_type") {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04002172 getTypeInfo("$_");
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002173 }
2174 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04002175
2176 # add "..." type
2177 $TypeInfo{$Version}{-1} = {
2178 "Name" => "...",
2179 "Type" => "Intrinsic",
2180 "Tid" => -1
2181 };
2182 $TName_Tid{$Version}{"..."} = -1;
2183
2184 if(not check_gcc($GCC_PATH, "4.5"))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002185 { # support for GCC < 4.5
2186 addMissedTypes_Post();
2187 }
2188}
2189
2190sub addMissedTypes_Pre()
2191{
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04002192 my %MissedTypes = ();
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002193 foreach my $MissedTDid (sort {int($a)<=>int($b)} keys(%{$LibInfo{$Version}{"info"}}))
2194 { # detecting missed typedefs
2195 if($LibInfo{$Version}{"info_type"}{$MissedTDid} eq "type_decl")
2196 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04002197 my $TypeId = getTreeAttr_Type($MissedTDid);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002198 next if(not $TypeId);
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04002199 my $TypeType = getTypeType($TypeId);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002200 if($TypeType eq "Unknown")
2201 { # template_type_parm
2202 next;
2203 }
2204 my $TypeDeclId = getTypeDeclId($TypeId);
2205 next if($TypeDeclId eq $MissedTDid);#or not $TypeDeclId
2206 my $TypedefName = getNameByInfo($MissedTDid);
2207 next if(not $TypedefName);
2208 next if($TypedefName eq "__float80");
2209 next if(isAnon($TypedefName));
2210 if(not $TypeDeclId
2211 or getNameByInfo($TypeDeclId) ne $TypedefName) {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04002212 $MissedTypes{$Version}{$TypeId}{$MissedTDid} = 1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002213 }
2214 }
2215 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04002216 foreach my $Tid (keys(%{$MissedTypes{$Version}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002217 { # add missed typedefs
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04002218 my @Missed = keys(%{$MissedTypes{$Version}{$Tid}});
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002219 if(not @Missed or $#Missed>=1) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002220 next;
2221 }
2222 my $MissedTDid = $Missed[0];
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002223 my ($TypedefName, $TypedefNS) = getTrivialName($MissedTDid, $Tid);
2224 my %MissedInfo = ( # typedef info
2225 "Name" => $TypedefName,
2226 "NameSpace" => $TypedefNS,
2227 "BaseType" => {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002228 "Tid" => $Tid
2229 },
2230 "Type" => "Typedef",
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04002231 "Tid" => ++$MAX_ID );
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002232 my ($H, $L) = getLocation($MissedTDid);
2233 $MissedInfo{"Header"} = $H;
2234 $MissedInfo{"Line"} = $L;
2235 # $MissedInfo{"Size"} = getSize($Tid)/$BYTE_SIZE;
2236 my $MName = $MissedInfo{"Name"};
2237 next if(not $MName);
2238 if($MName=~/\*|\&|\s/)
2239 { # other types
2240 next;
2241 }
2242 if($MName=~/>(::\w+)+\Z/)
2243 { # QFlags<Qt::DropAction>::enum_type
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002244 next;
2245 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04002246 if(getTypeType($Tid)=~/\A(Intrinsic|Union|Struct|Enum|Class)\Z/)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002247 { # double-check for the name of typedef
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04002248 my ($TName, $TNS) = getTrivialName(getTypeDeclId($Tid), $Tid); # base type info
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002249 next if(not $TName);
2250 if(length($MName)>=length($TName))
2251 { # too long typedef
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002252 next;
2253 }
2254 if($TName=~/\A\Q$MName\E</) {
2255 next;
2256 }
2257 if($MName=~/\A\Q$TName\E/)
2258 { # QDateTimeEdit::Section and QDateTimeEdit::Sections::enum_type
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002259 next;
2260 }
2261 if(get_depth($MName)==0 and get_depth($TName)!=0)
2262 { # std::_Vector_base and std::vector::_Base
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002263 next;
2264 }
2265 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04002266 %{$TypeInfo{$Version}{$MissedInfo{"Tid"}}} = %MissedInfo;
2267 $TName_Tid{$Version}{$TypedefName} = $MissedInfo{"Tid"};
2268 delete($TypeInfo{$Version}{$Tid});
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002269 # register typedef
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002270 $MissedTypedef{$Version}{$Tid}{"Tid"} = $MissedInfo{"Tid"};
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04002271 $MissedTypedef{$Version}{$Tid}{"TDid"} = $MissedTDid;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002272 }
2273}
2274
2275sub addMissedTypes_Post()
2276{
2277 foreach my $BaseId (keys(%{$MissedTypedef{$Version}}))
2278 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04002279 if(my $Tid = $MissedTypedef{$Version}{$BaseId}{"Tid"})
2280 {
2281 $TypeInfo{$Version}{$Tid}{"Size"} = $TypeInfo{$Version}{$BaseId}{"Size"};
2282 if(my $TName = $TypeInfo{$Version}{$Tid}{"Name"}) {
2283 $Typedef_BaseName{$Version}{$TName} = $TypeInfo{$Version}{$BaseId}{"Name"};
2284 }
2285 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002286 }
2287}
2288
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04002289sub getTypeInfo($)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002290{
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04002291 my $Tid = $_[0];
2292 %{$TypeInfo{$Version}{$Tid}} = getTypeAttr($Tid);
2293 my $TName = $TypeInfo{$Version}{$Tid}{"Name"};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002294 if(not $TName) {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04002295 delete($TypeInfo{$Version}{$Tid});
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002296 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002297}
2298
2299sub getArraySize($$)
2300{
2301 my ($TypeId, $BaseName) = @_;
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04002302 if(my $Size = getSize($TypeId))
2303 {
2304 my $Elems = $Size/$BYTE_SIZE;
2305 while($BaseName=~s/\s*\[(\d+)\]//) {
2306 $Elems/=$1;
2307 }
2308 if(my $BasicId = $TName_Tid{$Version}{$BaseName})
2309 {
2310 if(my $BasicSize = $TypeInfo{$Version}{$BasicId}{"Size"}) {
2311 $Elems/=$BasicSize;
2312 }
2313 }
2314 return $Elems;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002315 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04002316 return 0;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002317}
2318
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04002319sub getTParams($$)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002320{
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04002321 my ($TypeId, $Kind) = @_;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002322 my @TmplParams = ();
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04002323 my @Positions = sort {int($a)<=>int($b)} keys(%{$TemplateInstance{$Version}{$Kind}{$TypeId}});
2324 foreach my $Pos (@Positions)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002325 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04002326 my $Param_TypeId = $TemplateInstance{$Version}{$Kind}{$TypeId}{$Pos};
2327 my $NodeType = $LibInfo{$Version}{"info_type"}{$Param_TypeId};
2328 if(not $NodeType)
2329 { # typename_type
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002330 return ();
2331 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04002332 if($NodeType eq "tree_vec")
2333 {
2334 if($Pos!=$#Positions)
2335 { # select last vector of parameters ( ns<P1>::type<P2> )
2336 next;
2337 }
2338 }
2339 my @Params = get_TemplateParam($Pos, $Param_TypeId);
2340 foreach my $P (@Params)
2341 {
2342 if($P eq "") {
2343 return ();
2344 }
2345 elsif($P ne "\@skip\@") {
2346 @TmplParams = (@TmplParams, $P);
2347 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002348 }
2349 }
2350 return @TmplParams;
2351}
2352
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04002353sub getTypeAttr($)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002354{
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04002355 my $TypeId = $_[0];
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04002356 my %TypeAttr = ();
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04002357 if(defined $TypeInfo{$Version}{$TypeId}
2358 and $TypeInfo{$Version}{$TypeId}{"Name"})
2359 { # already created
2360 return %{$TypeInfo{$Version}{$TypeId}};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002361 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04002362 elsif($Cache{"getTypeAttr"}{$Version}{$TypeId})
2363 { # incomplete type
2364 return ();
2365 }
2366 $Cache{"getTypeAttr"}{$Version}{$TypeId} = 1;
2367
2368 my $TypeDeclId = getTypeDeclId($TypeId);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002369 $TypeAttr{"Tid"} = $TypeId;
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04002370
2371 if(not $MissedBase{$Version}{$TypeId} and isTypedef($TypeId))
2372 {
2373 if(my $Info = $LibInfo{$Version}{"info"}{$TypeId})
2374 {
2375 if($Info=~/qual[ ]*:/)
2376 {
2377 if(my $NID = ++$MAX_ID)
2378 {
2379 $MissedBase{$Version}{$TypeId}="$NID";
2380 $MissedBase_R{$Version}{$NID}=$TypeId;
2381 $LibInfo{$Version}{"info"}{$NID} = $LibInfo{$Version}{"info"}{$TypeId};
2382 $LibInfo{$Version}{"info_type"}{$NID} = $LibInfo{$Version}{"info_type"}{$TypeId};
2383 }
2384 }
2385 }
2386 $TypeAttr{"Type"} = "Typedef";
2387 }
2388 else {
2389 $TypeAttr{"Type"} = getTypeType($TypeId);
2390 }
2391
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002392 if($TypeAttr{"Type"} eq "Unknown") {
2393 return ();
2394 }
2395 elsif($TypeAttr{"Type"}=~/(Func|Method|Field)Ptr/)
2396 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04002397 %TypeAttr = getMemPtrAttr(pointTo($TypeId), $TypeId, $TypeAttr{"Type"});
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04002398 if(my $TName = $TypeAttr{"Name"})
2399 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04002400 %{$TypeInfo{$Version}{$TypeId}} = %TypeAttr;
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04002401 $TName_Tid{$Version}{$TName} = $TypeId;
2402 return %TypeAttr;
2403 }
2404 else {
2405 return ();
2406 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002407 }
2408 elsif($TypeAttr{"Type"} eq "Array")
2409 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04002410 my ($BTid, $BTSpec) = selectBaseType($TypeId);
2411 if(not $BTid) {
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04002412 return ();
2413 }
2414 $TypeAttr{"BaseType"}{"Tid"} = $BTid;
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04002415 if(my %BTAttr = getTypeAttr($BTid))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002416 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04002417 if(not $BTAttr{"Name"}) {
2418 return ();
2419 }
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04002420 if(my $NElems = getArraySize($TypeId, $BTAttr{"Name"}))
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04002421 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04002422 if(my $Size = getSize($TypeId)) {
2423 $TypeAttr{"Size"} = $Size/$BYTE_SIZE;
2424 }
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04002425 if($BTAttr{"Name"}=~/\A([^\[\]]+)(\[(\d+|)\].*)\Z/) {
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04002426 $TypeAttr{"Name"} = $1."[$NElems]".$2;
2427 }
2428 else {
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04002429 $TypeAttr{"Name"} = $BTAttr{"Name"}."[$NElems]";
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04002430 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002431 }
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04002432 else
2433 {
2434 $TypeAttr{"Size"} = $WORD_SIZE{$Version}; # pointer
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04002435 if($BTAttr{"Name"}=~/\A([^\[\]]+)(\[(\d+|)\].*)\Z/) {
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04002436 $TypeAttr{"Name"} = $1."[]".$2;
2437 }
2438 else {
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04002439 $TypeAttr{"Name"} = $BTAttr{"Name"}."[]";
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04002440 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002441 }
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04002442 $TypeAttr{"Name"} = formatName($TypeAttr{"Name"});
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04002443 if($BTAttr{"Header"}) {
2444 $TypeAttr{"Header"} = $BTAttr{"Header"};
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04002445 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04002446 %{$TypeInfo{$Version}{$TypeId}} = %TypeAttr;
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04002447 $TName_Tid{$Version}{$TypeAttr{"Name"}} = $TypeId;
2448 return %TypeAttr;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002449 }
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04002450 return ();
2451 }
2452 elsif($TypeAttr{"Type"}=~/\A(Intrinsic|Union|Struct|Enum|Class)\Z/)
2453 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04002454 %TypeAttr = getTrivialTypeAttr($TypeId);
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04002455 if($TypeAttr{"Name"})
2456 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04002457 %{$TypeInfo{$Version}{$TypeId}} = %TypeAttr;
2458 if($TypeAttr{"Name"} ne "int" or getTypeDeclId($TypeAttr{"Tid"}))
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04002459 { # NOTE: register only one int: with built-in decl
2460 if(not $TName_Tid{$Version}{$TypeAttr{"Name"}}) {
2461 $TName_Tid{$Version}{$TypeAttr{"Name"}} = $TypeId;
2462 }
2463 }
2464 return %TypeAttr;
2465 }
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04002466 else {
2467 return ();
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002468 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002469 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002470 else
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04002471 { # derived types
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04002472 my ($BTid, $BTSpec) = selectBaseType($TypeId);
2473 if(not $BTid) {
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04002474 return ();
2475 }
2476 $TypeAttr{"BaseType"}{"Tid"} = $BTid;
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04002477 if(defined $MissedTypedef{$Version}{$BTid})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002478 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04002479 if(my $MissedTDid = $MissedTypedef{$Version}{$BTid}{"TDid"})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002480 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04002481 if($MissedTDid ne $TypeDeclId) {
2482 $TypeAttr{"BaseType"}{"Tid"} = $MissedTypedef{$Version}{$BTid}{"Tid"};
2483 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002484 }
2485 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04002486 my %BTAttr = getTypeAttr($TypeAttr{"BaseType"}{"Tid"});
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04002487 if(not $BTAttr{"Name"})
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04002488 { # templates
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002489 return ();
2490 }
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04002491 if($BTAttr{"Type"} eq "Typedef")
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002492 { # relinking typedefs
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04002493 my %BaseBase = get_Type($BTAttr{"BaseType"}{"Tid"}, $Version);
2494 if($BTAttr{"Name"} eq $BaseBase{"Name"}) {
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04002495 $TypeAttr{"BaseType"}{"Tid"} = $BaseBase{"Tid"};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002496 }
2497 }
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04002498 if($BTSpec)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002499 {
2500 if($TypeAttr{"Type"} eq "Pointer"
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04002501 and $BTAttr{"Name"}=~/\([\*]+\)/)
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04002502 {
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04002503 $TypeAttr{"Name"} = $BTAttr{"Name"};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002504 $TypeAttr{"Name"}=~s/\(([*]+)\)/($1*)/g;
2505 }
2506 else {
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04002507 $TypeAttr{"Name"} = $BTAttr{"Name"}." ".$BTSpec;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002508 }
2509 }
2510 else {
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04002511 $TypeAttr{"Name"} = $BTAttr{"Name"};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002512 }
2513 if($TypeAttr{"Type"} eq "Typedef")
2514 {
2515 $TypeAttr{"Name"} = getNameByInfo($TypeDeclId);
Andrey Ponomarenko85043792012-05-14 16:48:07 +04002516 if(isAnon($TypeAttr{"Name"}))
2517 { # anon typedef to anon type: ._N
2518 return ();
2519 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002520 if(my $NS = getNameSpace($TypeDeclId))
2521 {
2522 my $TypeName = $TypeAttr{"Name"};
2523 if($NS=~/\A(struct |union |class |)((.+)::|)\Q$TypeName\E\Z/)
2524 { # "some_type" is the typedef to "struct some_type" in C++
2525 if($3) {
2526 $TypeAttr{"Name"} = $3."::".$TypeName;
2527 }
2528 }
2529 else
2530 {
2531 $TypeAttr{"NameSpace"} = $NS;
2532 $TypeAttr{"Name"} = $TypeAttr{"NameSpace"}."::".$TypeAttr{"Name"};
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04002533
2534 if($TypeAttr{"NameSpace"}=~/\Astd(::|\Z)/
2535 and $TypeAttr{"Name"}!~/>(::\w+)+\Z/)
2536 {
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04002537 if($BTAttr{"NameSpace"}
2538 and $BTAttr{"NameSpace"}=~/\Astd(::|\Z)/ and $BTAttr{"Name"}=~/</)
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04002539 { # types like "std::fpos<__mbstate_t>" are
2540 # not covered by typedefs in the TU dump
2541 # so trying to add such typedefs manually
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04002542 $StdCxxTypedef{$Version}{$BTAttr{"Name"}}{$TypeAttr{"Name"}} = 1;
2543 if(length($TypeAttr{"Name"})<=length($BTAttr{"Name"}))
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04002544 {
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04002545 if(($BTAttr{"Name"}!~/\A(std|boost)::/ or $TypeAttr{"Name"}!~/\A[a-z]+\Z/))
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04002546 { # skip "other" in "std" and "type" in "boost"
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04002547 $Typedef_Eq{$Version}{$BTAttr{"Name"}} = $TypeAttr{"Name"};
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04002548 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002549 }
2550 }
2551 }
2552 }
2553 }
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04002554 if($TypeAttr{"Name"} ne $BTAttr{"Name"}
2555 and $TypeAttr{"Name"}!~/>(::\w+)+\Z/ and $BTAttr{"Name"}!~/>(::\w+)+\Z/)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002556 {
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04002557 if(not defined $Typedef_BaseName{$Version}{$TypeAttr{"Name"}})
2558 { # typedef int*const TYPEDEF; // first
2559 # int foo(TYPEDEF p); // const is optimized out
2560 $Typedef_BaseName{$Version}{$TypeAttr{"Name"}} = $BTAttr{"Name"};
2561 if($BTAttr{"Name"}=~/</)
2562 {
2563 if(($BTAttr{"Name"}!~/\A(std|boost)::/ or $TypeAttr{"Name"}!~/\A[a-z]+\Z/)) {
2564 $Typedef_Tr{$Version}{$BTAttr{"Name"}}{$TypeAttr{"Name"}} = 1;
2565 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002566 }
2567 }
2568 }
2569 ($TypeAttr{"Header"}, $TypeAttr{"Line"}) = getLocation($TypeDeclId);
2570 }
2571 if(not $TypeAttr{"Size"})
2572 {
2573 if($TypeAttr{"Type"} eq "Pointer") {
2574 $TypeAttr{"Size"} = $WORD_SIZE{$Version};
2575 }
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04002576 elsif($BTAttr{"Size"}) {
2577 $TypeAttr{"Size"} = $BTAttr{"Size"};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002578 }
2579 }
2580 $TypeAttr{"Name"} = formatName($TypeAttr{"Name"});
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04002581 if(not $TypeAttr{"Header"} and $BTAttr{"Header"}) {
2582 $TypeAttr{"Header"} = $BTAttr{"Header"};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002583 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04002584 %{$TypeInfo{$Version}{$TypeId}} = %TypeAttr;
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04002585 if($TypeAttr{"Name"} ne $BTAttr{"Name"})
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04002586 { # typedef to "class Class"
2587 # should not be registered in TName_Tid
2588 if(not $TName_Tid{$Version}{$TypeAttr{"Name"}}) {
2589 $TName_Tid{$Version}{$TypeAttr{"Name"}} = $TypeId;
2590 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002591 }
2592 return %TypeAttr;
2593 }
2594}
2595
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04002596sub getTreeVec($)
2597{
2598 my %Vector = ();
2599 if($_[0] and my $Info = $LibInfo{$Version}{"info"}{$_[0]})
2600 {
2601 while($Info=~s/ (\d+)[ ]*:[ ]*\@(\d+) / /)
2602 { # string length is N-1 because of the null terminator
2603 $Vector{$1} = $2;
2604 }
2605 }
2606 return \%Vector;
2607}
2608
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002609sub get_TemplateParam($$)
2610{
2611 my ($Pos, $Type_Id) = @_;
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04002612 return () if(not $Type_Id);
2613 my $NodeType = $LibInfo{$Version}{"info_type"}{$Type_Id};
2614 return () if(not $NodeType);
2615 if($NodeType eq "integer_cst")
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002616 { # int (1), unsigned (2u), char ('c' as 99), ...
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04002617 my $CstTid = getTreeAttr_Type($Type_Id);
2618 my %CstType = getTypeAttr($CstTid);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002619 my $Num = getNodeIntCst($Type_Id);
2620 if(my $CstSuffix = $ConstantSuffix{$CstType{"Name"}}) {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04002621 return ($Num.$CstSuffix);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002622 }
2623 else {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04002624 return ("(".$CstType{"Name"}.")".$Num);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002625 }
2626 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04002627 elsif($NodeType eq "string_cst") {
2628 return (getNodeStrCst($Type_Id));
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002629 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04002630 elsif($NodeType eq "tree_vec")
2631 {
2632 my $Vector = getTreeVec($Type_Id);
2633 my @Params = ();
2634 foreach my $P1 (sort {int($a)<=>int($b)} keys(%{$Vector}))
2635 {
2636 foreach my $P2 (get_TemplateParam($Pos, $Vector->{$P1})) {
2637 push(@Params, $P2);
2638 }
2639 }
2640 return @Params;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002641 }
2642 else
2643 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04002644 my %ParamAttr = getTypeAttr($Type_Id);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002645 if(not $ParamAttr{"Name"}) {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04002646 return ();
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002647 }
2648 my $PName = $ParamAttr{"Name"};
2649 if($ParamAttr{"Name"}=~/\>/) {
2650 if(my $Cover = cover_stdcxx_typedef($ParamAttr{"Name"})) {
2651 $PName = $Cover;
2652 }
2653 }
2654 if($Pos>=1 and
2655 $PName=~/\Astd::(allocator|less|((char|regex)_traits)|((i|o)streambuf_iterator))\</)
2656 { # template<typename _Tp, typename _Alloc = std::allocator<_Tp> >
2657 # template<typename _Key, typename _Compare = std::less<_Key>
2658 # template<typename _CharT, typename _Traits = std::char_traits<_CharT> >
2659 # template<typename _Ch_type, typename _Rx_traits = regex_traits<_Ch_type> >
2660 # template<typename _CharT, typename _InIter = istreambuf_iterator<_CharT> >
2661 # template<typename _CharT, typename _OutIter = ostreambuf_iterator<_CharT> >
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04002662 return ("\@skip\@");
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002663 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04002664 return ($PName);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002665 }
2666}
2667
2668sub cover_stdcxx_typedef($)
2669{
2670 my $TypeName = $_[0];
2671 if(my @Covers = sort {length($a)<=>length($b)}
2672 sort keys(%{$StdCxxTypedef{$Version}{$TypeName}}))
2673 { # take the shortest typedef
2674 # FIXME: there may be more than
2675 # one typedefs to the same type
2676 return $Covers[0];
2677 }
2678 my $TypeName_Covered = $TypeName;
2679 while($TypeName=~s/(>)[ ]*(const|volatile|restrict| |\*|\&)\Z/$1/g){};
2680 if(my @Covers = sort {length($a)<=>length($b)} sort keys(%{$StdCxxTypedef{$Version}{$TypeName}}))
2681 {
2682 my $Cover = $Covers[0];
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04002683 $TypeName_Covered=~s/\b\Q$TypeName\E(\W|\Z)/$Cover$1/g;
2684 $TypeName_Covered=~s/\b\Q$TypeName\E(\w|\Z)/$Cover $1/g;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002685 }
2686 return formatName($TypeName_Covered);
2687}
2688
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002689sub getNodeIntCst($)
2690{
2691 my $CstId = $_[0];
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04002692 my $CstTypeId = getTreeAttr_Type($CstId);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002693 if($EnumMembName_Id{$Version}{$CstId}) {
2694 return $EnumMembName_Id{$Version}{$CstId};
2695 }
2696 elsif((my $Value = getTreeValue($CstId)) ne "")
2697 {
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04002698 if($Value eq "0")
2699 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04002700 if($LibInfo{$Version}{"info_type"}{$CstTypeId} eq "boolean_type") {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002701 return "false";
2702 }
2703 else {
2704 return "0";
2705 }
2706 }
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04002707 elsif($Value eq "1")
2708 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04002709 if($LibInfo{$Version}{"info_type"}{$CstTypeId} eq "boolean_type") {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002710 return "true";
2711 }
2712 else {
2713 return "1";
2714 }
2715 }
2716 else {
2717 return $Value;
2718 }
2719 }
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04002720 return "";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002721}
2722
2723sub getNodeStrCst($)
2724{
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04002725 if($_[0] and my $Info = $LibInfo{$Version}{"info"}{$_[0]})
2726 {
2727 if($Info=~/strg[ ]*: (.+) lngt:[ ]*(\d+)/)
2728 { # string length is N-1 because of the null terminator
2729 return substr($1, 0, $2-1);
2730 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002731 }
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04002732 return "";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002733}
2734
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04002735sub getMemPtrAttr($$$)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002736{ # function, method and field pointers
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04002737 my ($PtrId, $TypeId, $Type) = @_;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002738 my $MemInfo = $LibInfo{$Version}{"info"}{$PtrId};
2739 if($Type eq "FieldPtr") {
2740 $MemInfo = $LibInfo{$Version}{"info"}{$TypeId};
2741 }
2742 my $MemInfo_Type = $LibInfo{$Version}{"info_type"}{$PtrId};
2743 my $MemPtrName = "";
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04002744 my %TypeAttr = ("Size"=>$WORD_SIZE{$Version}, "Type"=>$Type, "Tid"=>$TypeId);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002745 if($Type eq "MethodPtr")
2746 { # size of "method pointer" may be greater than WORD size
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04002747 if(my $Size = getSize($TypeId)) {
2748 $TypeAttr{"Size"} = $Size/$BYTE_SIZE;
2749 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002750 }
2751 # Return
2752 if($Type eq "FieldPtr")
2753 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04002754 my %ReturnAttr = getTypeAttr($PtrId);
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04002755 if($ReturnAttr{"Name"}) {
2756 $MemPtrName .= $ReturnAttr{"Name"};
2757 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002758 $TypeAttr{"Return"} = $PtrId;
2759 }
2760 else
2761 {
2762 if($MemInfo=~/retn[ ]*:[ ]*\@(\d+) /)
2763 {
2764 my $ReturnTypeId = $1;
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04002765 my %ReturnAttr = getTypeAttr($ReturnTypeId);
2766 if(not $ReturnAttr{"Name"})
2767 { # templates
2768 return ();
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04002769 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04002770 $MemPtrName .= $ReturnAttr{"Name"};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002771 $TypeAttr{"Return"} = $ReturnTypeId;
2772 }
2773 }
2774 # Class
2775 if($MemInfo=~/(clas|cls)[ ]*:[ ]*@(\d+) /)
2776 {
2777 $TypeAttr{"Class"} = $2;
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04002778 my %Class = getTypeAttr($TypeAttr{"Class"});
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002779 if($Class{"Name"}) {
2780 $MemPtrName .= " (".$Class{"Name"}."\:\:*)";
2781 }
2782 else {
2783 $MemPtrName .= " (*)";
2784 }
2785 }
2786 else {
2787 $MemPtrName .= " (*)";
2788 }
2789 # Parameters
2790 if($Type eq "FuncPtr"
2791 or $Type eq "MethodPtr")
2792 {
2793 my @ParamTypeName = ();
2794 if($MemInfo=~/prms[ ]*:[ ]*@(\d+) /)
2795 {
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04002796 my $PTypeInfoId = $1;
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04002797 my $Pos = 0;
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04002798 while($PTypeInfoId)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002799 {
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04002800 my $PTypeInfo = $LibInfo{$Version}{"info"}{$PTypeInfoId};
2801 if($PTypeInfo=~/valu[ ]*:[ ]*@(\d+) /)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002802 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04002803 my $PTypeId = $1;
2804 my %ParamAttr = getTypeAttr($PTypeId);
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04002805 if(not $ParamAttr{"Name"})
2806 { # templates (template_type_parm), etc.
2807 return ();
2808 }
2809 if($ParamAttr{"Name"} eq "void") {
2810 last;
2811 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04002812 if($Pos!=0 or $Type ne "MethodPtr")
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04002813 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04002814 $TypeAttr{"Param"}{$Pos}{"type"} = $PTypeId;
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04002815 push(@ParamTypeName, $ParamAttr{"Name"});
2816 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04002817 if($PTypeInfoId = getNextElem($PTypeInfoId)) {
2818 $Pos+=1;
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04002819 }
2820 else {
2821 last;
2822 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002823 }
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04002824 else {
2825 last;
2826 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002827 }
2828 }
2829 $MemPtrName .= " (".join(", ", @ParamTypeName).")";
2830 }
2831 $TypeAttr{"Name"} = formatName($MemPtrName);
2832 return %TypeAttr;
2833}
2834
2835sub getTreeTypeName($)
2836{
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04002837 my $TypeId = $_[0];
2838 if(my $Info = $LibInfo{$Version}{"info"}{$TypeId})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002839 {
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04002840 if($LibInfo{$Version}{"info_type"}{$_[0]} eq "integer_type")
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002841 {
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04002842 if(my $Name = getNameByInfo($TypeId))
2843 { # bit_size_type
2844 return $Name;
2845 }
2846 elsif($Info=~/unsigned/) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002847 return "unsigned int";
2848 }
2849 else {
2850 return "int";
2851 }
2852 }
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04002853 elsif($Info=~/name[ ]*:[ ]*@(\d+) /)
2854 {
2855 return getNameByInfo($1);
2856 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002857 }
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04002858 return "";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002859}
2860
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04002861sub isFuncPtr($)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002862{
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04002863 my $Ptd = pointTo($_[0]);
2864 return 0 if(not $Ptd);
2865 if(my $Info = $LibInfo{$Version}{"info"}{$_[0]})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002866 {
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04002867 if($Info=~/unql[ ]*:/ and $Info!~/qual[ ]*:/) {
2868 return 0;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002869 }
2870 }
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04002871 if(my $InfoT1 = $LibInfo{$Version}{"info_type"}{$_[0]}
2872 and my $InfoT2 = $LibInfo{$Version}{"info_type"}{$Ptd})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002873 {
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04002874 if($InfoT1 eq "pointer_type"
2875 and $InfoT2 eq "function_type") {
2876 return 1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002877 }
2878 }
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04002879 return 0;
2880}
2881
2882sub isMethodPtr($)
2883{
2884 my $Ptd = pointTo($_[0]);
2885 return 0 if(not $Ptd);
2886 if(my $Info = $LibInfo{$Version}{"info"}{$_[0]})
2887 {
2888 if($LibInfo{$Version}{"info_type"}{$_[0]} eq "record_type"
2889 and $LibInfo{$Version}{"info_type"}{$Ptd} eq "method_type"
2890 and $Info=~/ ptrmem /) {
2891 return 1;
2892 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002893 }
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04002894 return 0;
2895}
2896
2897sub isFieldPtr($)
2898{
2899 if($_[0] and my $Info = $LibInfo{$Version}{"info"}{$_[0]})
2900 {
2901 if($LibInfo{$Version}{"info_type"}{$_[0]} eq "offset_type"
2902 and $Info=~/ ptrmem /) {
2903 return 1;
2904 }
2905 }
2906 return 0;
2907}
2908
2909sub pointTo($)
2910{
2911 if($_[0] and my $Info = $LibInfo{$Version}{"info"}{$_[0]})
2912 {
2913 if($Info=~/ptd[ ]*:[ ]*@(\d+)/) {
2914 return $1;
2915 }
2916 }
2917 return "";
2918}
2919
2920sub getTypeTypeByTypeId($)
2921{
2922 my $TypeId = $_[0];
2923 if(my $TType = $LibInfo{$Version}{"info_type"}{$TypeId})
2924 {
2925 my $NType = $NodeType{$TType};
2926 if($NType eq "Intrinsic") {
2927 return $NType;
2928 }
2929 elsif(isFuncPtr($TypeId)) {
2930 return "FuncPtr";
2931 }
2932 elsif(isMethodPtr($TypeId)) {
2933 return "MethodPtr";
2934 }
2935 elsif(isFieldPtr($TypeId)) {
2936 return "FieldPtr";
2937 }
2938 elsif($NType ne "Other") {
2939 return $NType;
2940 }
2941 }
2942 return "Unknown";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002943}
2944
2945sub getQual($)
2946{
2947 my $TypeId = $_[0];
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002948 my %UnQual = (
2949 "r"=>"restrict",
2950 "v"=>"volatile",
2951 "c"=>"const",
2952 "cv"=>"const volatile"
2953 );
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04002954 if(my $Info = $LibInfo{$Version}{"info"}{$TypeId})
2955 {
2956 my ($Qual, $To) = ();
2957 if($Info=~/qual[ ]*:[ ]*(r|c|v|cv) /) {
2958 $Qual = $UnQual{$1};
2959 }
2960 if($Info=~/unql[ ]*:[ ]*\@(\d+)/) {
2961 $To = $1;
2962 }
2963 if($Qual and $To) {
2964 return ($Qual, $To);
2965 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002966 }
2967 return ();
2968}
2969
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04002970sub getQualType($)
2971{
2972 if($_[0] eq "const volatile") {
2973 return "ConstVolatile";
2974 }
2975 return ucfirst($_[0]);
2976}
2977
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04002978sub getTypeType($)
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04002979{
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04002980 my $TypeId = $_[0];
2981 my $TypeDeclId = getTypeDeclId($TypeId);
2982 if(defined $MissedTypedef{$Version}{$TypeId})
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04002983 { # support for old GCC versions
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04002984 if($MissedTypedef{$Version}{$TypeId}{"TDid"} eq $TypeDeclId) {
2985 return "Typedef";
2986 }
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04002987 }
2988 my $Info = $LibInfo{$Version}{"info"}{$TypeId};
2989 my ($Qual, $To) = getQual($TypeId);
2990 if(($Qual or $To) and $Info=~/name[ ]*:[ ]*\@(\d+) /
2991 and (getTypeId($1) ne $TypeId))
2992 { # qualified types (special)
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04002993 return getQualType($Qual);
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04002994 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04002995 elsif(not $MissedBase_R{$Version}{$TypeId}
2996 and isTypedef($TypeId)) {
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04002997 return "Typedef";
2998 }
2999 elsif($Qual)
3000 { # qualified types
3001 return getQualType($Qual);
3002 }
3003 my $TypeType = getTypeTypeByTypeId($TypeId);
3004 if($TypeType eq "Struct")
3005 {
3006 if($TypeDeclId
3007 and $LibInfo{$Version}{"info_type"}{$TypeDeclId} eq "template_decl") {
3008 return "Template";
3009 }
3010 }
3011 return $TypeType;
3012}
3013
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04003014sub isTypedef($)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003015{
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04003016 if($_[0] and my $Info = $LibInfo{$Version}{"info"}{$_[0]})
3017 {
3018 my $TDid = getTypeDeclId($_[0]);
3019 if(getNameByInfo($TDid)
3020 and $Info=~/unql[ ]*:[ ]*\@(\d+) /
3021 and getTypeId($TDid) eq $_[0]) {
3022 return $1;
3023 }
3024 }
3025 return 0;
3026}
3027
3028sub selectBaseType($)
3029{
3030 my $TypeId = $_[0];
3031 if(defined $MissedTypedef{$Version}{$TypeId})
3032 { # add missed typedefs
3033 if($MissedTypedef{$Version}{$TypeId}{"TDid"} eq getTypeDeclId($TypeId)) {
3034 return ($TypeId, "");
3035 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003036 }
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04003037 my $Info = $LibInfo{$Version}{"info"}{$TypeId};
3038 my $InfoType = $LibInfo{$Version}{"info_type"}{$TypeId};
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04003039
3040 my $MB_R = $MissedBase_R{$Version}{$TypeId};
3041 my $MB = $MissedBase{$Version}{$TypeId};
3042
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04003043 my ($Qual, $To) = getQual($TypeId);
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04003044 if(($Qual or $To) and $Info=~/name[ ]*:[ ]*\@(\d+) /
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04003045 and (getTypeId($1) ne $TypeId)
3046 and (not $MB_R or getTypeId($1) ne $MB_R))
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04003047 { # qualified types (special)
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04003048 return (getTypeId($1), $Qual);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003049 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04003050 elsif($MB)
3051 { # add base
3052 return ($MB, "");
3053 }
3054 elsif(not $MB_R and my $Bid = isTypedef($TypeId))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003055 { # typedefs
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04003056 return ($Bid, "");
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003057 }
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04003058 elsif($Qual or $To)
3059 { # qualified types
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04003060 return ($To, $Qual);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003061 }
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04003062 elsif($InfoType eq "reference_type")
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003063 {
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04003064 if($Info=~/refd[ ]*:[ ]*@(\d+) /) {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04003065 return ($1, "&");
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003066 }
3067 else {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04003068 return (0, "");
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003069 }
3070 }
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04003071 elsif($InfoType eq "array_type")
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003072 {
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04003073 if($Info=~/elts[ ]*:[ ]*@(\d+) /) {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04003074 return ($1, "");
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003075 }
3076 else {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04003077 return (0, "");
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003078 }
3079 }
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04003080 elsif($InfoType eq "pointer_type")
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003081 {
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04003082 if($Info=~/ptd[ ]*:[ ]*@(\d+) /) {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04003083 return ($1, "*");
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003084 }
3085 else {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04003086 return (0, "");
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003087 }
3088 }
3089 else {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04003090 return (0, "");
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003091 }
3092}
3093
3094sub getSymbolInfo_All()
3095{
3096 foreach (sort {int($b)<=>int($a)} keys(%{$LibInfo{$Version}{"info"}}))
3097 { # reverse order
3098 if($LibInfo{$Version}{"info_type"}{$_} eq "function_decl") {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04003099 getSymbolInfo($_);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003100 }
3101 }
3102}
3103
3104sub getVarInfo_All()
3105{
3106 foreach (sort {int($b)<=>int($a)} keys(%{$LibInfo{$Version}{"info"}}))
3107 { # reverse order
3108 if($LibInfo{$Version}{"info_type"}{$_} eq "var_decl") {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04003109 getVarInfo($_);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003110 }
3111 }
3112}
3113
3114sub isBuiltIn($) {
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04003115 return ($_[0] and $_[0]=~/\<built\-in\>|\<internal\>|\A\./);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003116}
3117
3118sub getVarInfo($)
3119{
3120 my $InfoId = $_[0];
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04003121 if(my $NSid = getNameSpaceId($InfoId))
3122 {
3123 my $NSInfoType = $LibInfo{$Version}{"info_type"}{$NSid};
3124 if($NSInfoType and $NSInfoType eq "function_decl") {
3125 return;
3126 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003127 }
3128 ($SymbolInfo{$Version}{$InfoId}{"Header"}, $SymbolInfo{$Version}{$InfoId}{"Line"}) = getLocation($InfoId);
3129 if(not $SymbolInfo{$Version}{$InfoId}{"Header"}
3130 or isBuiltIn($SymbolInfo{$Version}{$InfoId}{"Header"})) {
3131 delete($SymbolInfo{$Version}{$InfoId});
3132 return;
3133 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04003134 my $ShortName = getTreeStr(getTreeAttr_Name($InfoId));
Andrey Ponomarenko85043792012-05-14 16:48:07 +04003135 if(not $ShortName) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003136 delete($SymbolInfo{$Version}{$InfoId});
3137 return;
3138 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +04003139 if($ShortName=~/\Atmp_add_class_\d+\Z/) {
3140 delete($SymbolInfo{$Version}{$InfoId});
3141 return;
3142 }
3143 $SymbolInfo{$Version}{$InfoId}{"ShortName"} = $ShortName;
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04003144 $SymbolInfo{$Version}{$InfoId}{"MnglName"} = getTreeStr(getTreeAttr_Mngl($InfoId));
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003145 if($SymbolInfo{$Version}{$InfoId}{"MnglName"}
3146 and $SymbolInfo{$Version}{$InfoId}{"MnglName"}!~/\A_Z/)
3147 { # validate mangled name
3148 delete($SymbolInfo{$Version}{$InfoId});
3149 return;
3150 }
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04003151 if(not $SymbolInfo{$Version}{$InfoId}{"MnglName"}
Andrey Ponomarenko85043792012-05-14 16:48:07 +04003152 and $ShortName=~/\A_Z/)
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04003153 { # _ZTS, etc.
Andrey Ponomarenko85043792012-05-14 16:48:07 +04003154 $SymbolInfo{$Version}{$InfoId}{"MnglName"} = $ShortName;
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04003155 }
3156 if(isPrivateData($SymbolInfo{$Version}{$InfoId}{"MnglName"}))
3157 { # non-public global data
3158 delete($SymbolInfo{$Version}{$InfoId});
3159 return;
3160 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003161 $SymbolInfo{$Version}{$InfoId}{"Data"} = 1;
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04003162 if(my $Rid = getTypeId($InfoId))
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04003163 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04003164 if(not $TypeInfo{$Version}{$Rid}{"Name"})
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04003165 { # typename_type
3166 delete($SymbolInfo{$Version}{$InfoId});
3167 return;
3168 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04003169 $SymbolInfo{$Version}{$InfoId}{"Return"} = $Rid;
3170 my $Val = getDataVal($InfoId, $Rid);
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04003171 if(defined $Val) {
3172 $SymbolInfo{$Version}{$InfoId}{"Value"} = $Val;
3173 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003174 }
3175 set_Class_And_Namespace($InfoId);
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04003176 if(my $ClassId = $SymbolInfo{$Version}{$InfoId}{"Class"})
3177 {
3178 if(not $TypeInfo{$Version}{$ClassId}{"Name"})
3179 { # templates
3180 delete($SymbolInfo{$Version}{$InfoId});
3181 return;
3182 }
3183 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003184 if($LibInfo{$Version}{"info"}{$InfoId}=~/ lang:[ ]*C /i) {
3185 $SymbolInfo{$Version}{$InfoId}{"Lang"} = "C";
3186 }
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04003187 if($UserLang and $UserLang eq "C")
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003188 { # --lang=C option
Andrey Ponomarenko85043792012-05-14 16:48:07 +04003189 $SymbolInfo{$Version}{$InfoId}{"MnglName"} = $ShortName;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003190 }
3191 if($COMMON_LANGUAGE{$Version} eq "C++")
3192 {
3193 if(not $SymbolInfo{$Version}{$InfoId}{"MnglName"})
3194 { # for some symbols (_ZTI) the short name is the mangled name
3195 if($ShortName=~/\A_Z/) {
3196 $SymbolInfo{$Version}{$InfoId}{"MnglName"} = $ShortName;
3197 }
3198 }
3199 if(not $SymbolInfo{$Version}{$InfoId}{"MnglName"})
3200 { # try to mangle symbol (link with libraries)
3201 $SymbolInfo{$Version}{$InfoId}{"MnglName"} = linkSymbol($InfoId);
3202 }
3203 if($OStarget eq "windows")
3204 {
3205 if(my $Mangled = $mangled_name{$Version}{modelUnmangled($InfoId, "MSVC")})
3206 { # link MS C++ symbols from library with GCC symbols from headers
3207 $SymbolInfo{$Version}{$InfoId}{"MnglName"} = $Mangled;
3208 }
3209 }
3210 }
3211 if(not $SymbolInfo{$Version}{$InfoId}{"MnglName"}) {
3212 $SymbolInfo{$Version}{$InfoId}{"MnglName"} = $ShortName;
3213 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04003214 if(not $CheckHeadersOnly
3215 and not link_symbol($SymbolInfo{$Version}{$InfoId}{"MnglName"}, $Version, "-Deps"))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003216 {
Andrey Ponomarenko85043792012-05-14 16:48:07 +04003217 if(link_symbol($ShortName, $Version, "-Deps"))
3218 {
3219 if(not $SymbolInfo{$Version}{$InfoId}{"Class"}
3220 and isConstType($SymbolInfo{$Version}{$InfoId}{"Return"}, $Version)
3221 and $SymbolInfo{$Version}{$InfoId}{"MnglName"}=~/L\d+$ShortName/)
3222 { # "const" global data is mangled as _ZL... in the TU dump
3223 # but not mangled when compiling a C shared library
3224 $SymbolInfo{$Version}{$InfoId}{"MnglName"} = $ShortName;
3225 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003226 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003227 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +04003228 if(my $Symbol = $SymbolInfo{$Version}{$InfoId}{"MnglName"})
3229 {
3230 if(not selectSymbol($Symbol, $SymbolInfo{$Version}{$InfoId}, "Dump", $Version))
3231 { # non-target symbols
3232 delete($SymbolInfo{$Version}{$InfoId});
3233 return;
3234 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003235 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04003236 if(my $Rid = $SymbolInfo{$Version}{$InfoId}{"Return"})
3237 {
3238 if(defined $MissedTypedef{$Version}{$Rid})
3239 {
3240 if(my $AddedTid = $MissedTypedef{$Version}{$Rid}{"Tid"}) {
3241 $SymbolInfo{$Version}{$InfoId}{"Return"} = $AddedTid;
3242 }
3243 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003244 }
3245 setFuncAccess($InfoId);
3246 if($SymbolInfo{$Version}{$InfoId}{"MnglName"}=~/\A_ZTV/) {
3247 delete($SymbolInfo{$Version}{$InfoId}{"Return"});
3248 }
3249 if($ShortName=~/\A(_Z|\?)/) {
3250 delete($SymbolInfo{$Version}{$InfoId}{"ShortName"});
3251 }
3252}
3253
Andrey Ponomarenko85043792012-05-14 16:48:07 +04003254sub isConstType($$)
3255{
3256 my ($TypeId, $LibVersion) = @_;
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04003257 my %Base = get_Type($TypeId, $LibVersion);
Andrey Ponomarenko85043792012-05-14 16:48:07 +04003258 while(defined $Base{"Type"} and $Base{"Type"} eq "Typedef") {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04003259 %Base = get_OneStep_BaseType($Base{"Tid"}, $LibVersion);
Andrey Ponomarenko85043792012-05-14 16:48:07 +04003260 }
3261 return ($Base{"Type"} eq "Const");
3262}
3263
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003264sub getTrivialName($$)
3265{
3266 my ($TypeInfoId, $TypeId) = @_;
3267 my %TypeAttr = ();
3268 $TypeAttr{"Name"} = getNameByInfo($TypeInfoId);
3269 if(not $TypeAttr{"Name"}) {
3270 $TypeAttr{"Name"} = getTreeTypeName($TypeId);
3271 }
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04003272 ($TypeAttr{"Header"}, $TypeAttr{"Line"}) = getLocation($TypeInfoId);
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04003273 $TypeAttr{"Type"} = getTypeType($TypeId);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003274 $TypeAttr{"Name"}=~s/<(.+)\Z//g; # GCC 3.4.4 add template params to the name
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04003275 if(isAnon($TypeAttr{"Name"}))
3276 {
3277 my $NameSpaceId = $TypeId;
3278 while(my $NSId = getNameSpaceId(getTypeDeclId($NameSpaceId)))
3279 { # searching for a first not anon scope
3280 if($NSId eq $NameSpaceId) {
3281 last;
3282 }
3283 else
3284 {
3285 $TypeAttr{"NameSpace"} = getNameSpace(getTypeDeclId($TypeId));
3286 if(not $TypeAttr{"NameSpace"}
3287 or isNotAnon($TypeAttr{"NameSpace"})) {
3288 last;
3289 }
3290 }
3291 $NameSpaceId=$NSId;
3292 }
3293 }
3294 else
3295 {
3296 if(my $NameSpaceId = getNameSpaceId($TypeInfoId))
3297 {
3298 if($NameSpaceId ne $TypeId) {
3299 $TypeAttr{"NameSpace"} = getNameSpace($TypeInfoId);
3300 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003301 }
3302 }
3303 if($TypeAttr{"NameSpace"} and isNotAnon($TypeAttr{"Name"})) {
3304 $TypeAttr{"Name"} = $TypeAttr{"NameSpace"}."::".$TypeAttr{"Name"};
3305 }
3306 $TypeAttr{"Name"} = formatName($TypeAttr{"Name"});
3307 if(isAnon($TypeAttr{"Name"}))
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04003308 { # anon-struct-header.h-line
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04003309 $TypeAttr{"Name"} = "anon-".lc($TypeAttr{"Type"})."-";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003310 $TypeAttr{"Name"} .= $TypeAttr{"Header"}."-".$TypeAttr{"Line"};
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04003311 if($TypeAttr{"NameSpace"}) {
3312 $TypeAttr{"Name"} = $TypeAttr{"NameSpace"}."::".$TypeAttr{"Name"};
3313 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003314 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04003315 if(defined $TemplateInstance{$Version}{"Type"}{$TypeId})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003316 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04003317 my @TParams = getTParams($TypeId, "Type");
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003318 if(not @TParams)
3319 { # template declarations with abstract params
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003320 return ("", "");
3321 }
3322 $TypeAttr{"Name"} = formatName($TypeAttr{"Name"}."< ".join(", ", @TParams)." >");
3323 }
3324 return ($TypeAttr{"Name"}, $TypeAttr{"NameSpace"});
3325}
3326
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04003327sub getTrivialTypeAttr($)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003328{
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04003329 my $TypeId = $_[0];
3330 my $TypeInfoId = getTypeDeclId($_[0]);
Andrey Ponomarenko85043792012-05-14 16:48:07 +04003331
3332 if($TemplateDecl{$Version}{$TypeId})
3333 { # template_decl
3334 return ();
3335 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04003336 if(my $ScopeId = getTreeAttr_Scpe($TypeInfoId))
3337 {
3338 if($TemplateDecl{$Version}{$ScopeId})
3339 { # template_decl
3340 return ();
3341 }
3342 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +04003343
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003344 my %TypeAttr = ();
3345 if(getTypeTypeByTypeId($TypeId)!~/\A(Intrinsic|Union|Struct|Enum|Class)\Z/) {
3346 return ();
3347 }
3348 setTypeAccess($TypeId, \%TypeAttr);
3349 ($TypeAttr{"Header"}, $TypeAttr{"Line"}) = getLocation($TypeInfoId);
3350 if(isBuiltIn($TypeAttr{"Header"}))
3351 {
3352 delete($TypeAttr{"Header"});
3353 delete($TypeAttr{"Line"});
3354 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04003355 $TypeAttr{"Type"} = getTypeType($TypeId);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003356 ($TypeAttr{"Name"}, $TypeAttr{"NameSpace"}) = getTrivialName($TypeInfoId, $TypeId);
3357 if(not $TypeAttr{"Name"}) {
3358 return ();
3359 }
3360 if(not $TypeAttr{"NameSpace"}) {
3361 delete($TypeAttr{"NameSpace"});
3362 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04003363 if(defined $TemplateInstance{$Version}{"Type"}{$TypeId})
Andrey Ponomarenko16934472012-03-29 15:37:04 +04003364 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04003365 if(my @TParams = getTParams($TypeId, "Type"))
Andrey Ponomarenko16934472012-03-29 15:37:04 +04003366 {
3367 foreach my $Pos (0 .. $#TParams) {
3368 $TypeAttr{"TParam"}{$Pos}{"name"}=$TParams[$Pos];
3369 }
3370 }
3371 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003372 if(my $Size = getSize($TypeId)) {
3373 $TypeAttr{"Size"} = $Size/$BYTE_SIZE;
3374 }
3375 if($TypeAttr{"Type"} eq "Struct"
3376 and detect_lang($TypeId))
3377 {
3378 $TypeAttr{"Type"} = "Class";
Andrey Ponomarenko85043792012-05-14 16:48:07 +04003379 $TypeAttr{"Copied"} = 1; # default, will be changed in getSymbolInfo()
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003380 }
3381 if($TypeAttr{"Type"} eq "Struct"
Andrey Ponomarenko85043792012-05-14 16:48:07 +04003382 or $TypeAttr{"Type"} eq "Class")
3383 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04003384 my $Skip = setBaseClasses($TypeId, \%TypeAttr);
Andrey Ponomarenko85043792012-05-14 16:48:07 +04003385 if($Skip) {
3386 return ();
3387 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003388 }
3389 setSpec($TypeId, \%TypeAttr);
3390 setTypeMemb($TypeId, \%TypeAttr);
3391 $TypeAttr{"Tid"} = $TypeId;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003392 if(my $VTable = $ClassVTable_Content{$Version}{$TypeAttr{"Name"}})
3393 {
3394 my @Entries = split(/\n/, $VTable);
3395 foreach (1 .. $#Entries)
3396 {
3397 my $Entry = $Entries[$_];
3398 if($Entry=~/\A(\d+)\s+(.+)\Z/) {
3399 $TypeAttr{"VTable"}{$1} = $2;
3400 }
3401 }
3402 }
3403 return %TypeAttr;
3404}
3405
3406sub detect_lang($)
3407{
3408 my $TypeId = $_[0];
3409 my $Info = $LibInfo{$Version}{"info"}{$TypeId};
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04003410 if(check_gcc($GCC_PATH, "4"))
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04003411 { # GCC 4 fncs-node points to only non-artificial methods
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003412 return ($Info=~/(fncs)[ ]*:[ ]*@(\d+) /);
3413 }
3414 else
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04003415 { # GCC 3
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04003416 my $Fncs = getTreeAttr_Fncs($TypeId);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003417 while($Fncs)
3418 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04003419 if($LibInfo{$Version}{"info"}{$Fncs}!~/artificial/) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003420 return 1;
3421 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04003422 $Fncs = getTreeAttr_Chan($Fncs);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003423 }
3424 }
3425 return 0;
3426}
3427
3428sub setSpec($$)
3429{
3430 my ($TypeId, $TypeAttr) = @_;
3431 my $Info = $LibInfo{$Version}{"info"}{$TypeId};
3432 if($Info=~/\s+spec\s+/) {
3433 $TypeAttr->{"Spec"} = 1;
3434 }
3435}
3436
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04003437sub setBaseClasses($$)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003438{
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04003439 my ($TypeId, $TypeAttr) = @_;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003440 my $Info = $LibInfo{$Version}{"info"}{$TypeId};
3441 if($Info=~/binf[ ]*:[ ]*@(\d+) /)
3442 {
3443 $Info = $LibInfo{$Version}{"info"}{$1};
3444 my $Pos = 0;
3445 while($Info=~s/(pub|public|prot|protected|priv|private|)[ ]+binf[ ]*:[ ]*@(\d+) //)
3446 {
3447 my ($Access, $BInfoId) = ($1, $2);
3448 my $ClassId = getBinfClassId($BInfoId);
Andrey Ponomarenko85043792012-05-14 16:48:07 +04003449 my $CType = $LibInfo{$Version}{"info_type"}{$ClassId};
3450 if(not $CType or $CType eq "template_type_parm"
3451 or $CType eq "typename_type")
3452 { # skip
3453 return 1;
3454 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003455 my $BaseInfo = $LibInfo{$Version}{"info"}{$BInfoId};
3456 if($Access=~/prot/)
3457 {
3458 $TypeAttr->{"Base"}{$ClassId}{"access"} = "protected";
3459 }
3460 elsif($Access=~/priv/)
3461 {
3462 $TypeAttr->{"Base"}{$ClassId}{"access"} = "private";
3463 }
3464 $TypeAttr->{"Base"}{$ClassId}{"pos"} = $Pos++;
3465 if($BaseInfo=~/virt/)
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04003466 { # virtual base
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003467 $TypeAttr->{"Base"}{$ClassId}{"virtual"} = 1;
3468 }
3469 $Class_SubClasses{$Version}{$ClassId}{$TypeId}=1;
3470 }
3471 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +04003472 return 0;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003473}
3474
3475sub getBinfClassId($)
3476{
3477 my $Info = $LibInfo{$Version}{"info"}{$_[0]};
3478 $Info=~/type[ ]*:[ ]*@(\d+) /;
3479 return $1;
3480}
3481
3482sub unmangledFormat($$)
3483{
3484 my ($Name, $LibVersion) = @_;
3485 $Name = uncover_typedefs($Name, $LibVersion);
3486 while($Name=~s/([^\w>*])(const|volatile)(,|>|\Z)/$1$3/g){};
3487 $Name=~s/\(\w+\)(\d)/$1/;
3488 return $Name;
3489}
3490
3491sub modelUnmangled($$)
3492{
3493 my ($InfoId, $Compiler) = @_;
3494 if($Cache{"modelUnmangled"}{$Version}{$Compiler}{$InfoId}) {
3495 return $Cache{"modelUnmangled"}{$Version}{$Compiler}{$InfoId};
3496 }
3497 my $PureSignature = $SymbolInfo{$Version}{$InfoId}{"ShortName"};
3498 if($SymbolInfo{$Version}{$InfoId}{"Destructor"}) {
3499 $PureSignature = "~".$PureSignature;
3500 }
3501 if(not $SymbolInfo{$Version}{$InfoId}{"Data"})
3502 {
3503 my (@Params, @ParamTypes) = ();
3504 if(defined $SymbolInfo{$Version}{$InfoId}{"Param"}
3505 and not $SymbolInfo{$Version}{$InfoId}{"Destructor"}) {
3506 @Params = keys(%{$SymbolInfo{$Version}{$InfoId}{"Param"}});
3507 }
3508 foreach my $ParamPos (sort {int($a) <=> int($b)} @Params)
3509 { # checking parameters
3510 my $PId = $SymbolInfo{$Version}{$InfoId}{"Param"}{$ParamPos}{"type"};
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04003511 my %PType = get_PureType($PId, $Version);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003512 my $PTName = unmangledFormat($PType{"Name"}, $Version);
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04003513 $PTName=~s/\b(restrict|register)\b//g;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003514 if($Compiler eq "MSVC") {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04003515 $PTName=~s/\blong long\b/__int64/;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003516 }
3517 @ParamTypes = (@ParamTypes, $PTName);
3518 }
3519 if(@ParamTypes) {
3520 $PureSignature .= "(".join(", ", @ParamTypes).")";
3521 }
3522 else
3523 {
3524 if($Compiler eq "MSVC")
3525 {
3526 $PureSignature .= "(void)";
3527 }
3528 else
3529 { # GCC
3530 $PureSignature .= "()";
3531 }
3532 }
3533 $PureSignature = delete_keywords($PureSignature);
3534 }
3535 if(my $ClassId = $SymbolInfo{$Version}{$InfoId}{"Class"})
3536 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04003537 my $ClassName = unmangledFormat($TypeInfo{$Version}{$ClassId}{"Name"}, $Version);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003538 $PureSignature = $ClassName."::".$PureSignature;
3539 }
3540 elsif(my $NS = $SymbolInfo{$Version}{$InfoId}{"NameSpace"}) {
3541 $PureSignature = $NS."::".$PureSignature;
3542 }
3543 if($SymbolInfo{$Version}{$InfoId}{"Const"}) {
3544 $PureSignature .= " const";
3545 }
3546 if($SymbolInfo{$Version}{$InfoId}{"Volatile"}) {
3547 $PureSignature .= " volatile";
3548 }
3549 my $ShowReturn = 0;
3550 if($Compiler eq "MSVC"
3551 and $SymbolInfo{$Version}{$InfoId}{"Data"})
3552 {
3553 $ShowReturn=1;
3554 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04003555 elsif(defined $TemplateInstance{$Version}{"Func"}{$InfoId}
3556 and keys(%{$TemplateInstance{$Version}{"Func"}{$InfoId}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003557 {
3558 $ShowReturn=1;
3559 }
3560 if($ShowReturn)
3561 { # mangled names for template function specializations include return value
3562 if(my $ReturnId = $SymbolInfo{$Version}{$InfoId}{"Return"})
3563 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04003564 my %RType = get_PureType($ReturnId, $Version);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003565 my $ReturnName = unmangledFormat($RType{"Name"}, $Version);
3566 $PureSignature = $ReturnName." ".$PureSignature;
3567 }
3568 }
3569 return ($Cache{"modelUnmangled"}{$Version}{$Compiler}{$InfoId} = formatName($PureSignature));
3570}
3571
3572sub mangle_symbol($$$)
3573{ # mangling for simple methods
3574 # see gcc-4.6.0/gcc/cp/mangle.c
3575 my ($InfoId, $LibVersion, $Compiler) = @_;
3576 if($Cache{"mangle_symbol"}{$LibVersion}{$InfoId}{$Compiler}) {
3577 return $Cache{"mangle_symbol"}{$LibVersion}{$InfoId}{$Compiler};
3578 }
3579 my $Mangled = "";
3580 if($Compiler eq "GCC") {
Andrey Ponomarenko16934472012-03-29 15:37:04 +04003581 $Mangled = mangle_symbol_GCC($InfoId, $LibVersion);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003582 }
3583 elsif($Compiler eq "MSVC") {
Andrey Ponomarenko16934472012-03-29 15:37:04 +04003584 $Mangled = mangle_symbol_MSVC($InfoId, $LibVersion);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003585 }
3586 return ($Cache{"mangle_symbol"}{$LibVersion}{$InfoId}{$Compiler} = $Mangled);
3587}
3588
Andrey Ponomarenko16934472012-03-29 15:37:04 +04003589sub mangle_symbol_MSVC($$)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003590{
3591 my ($InfoId, $LibVersion) = @_;
3592 return "";
3593}
3594
Andrey Ponomarenko16934472012-03-29 15:37:04 +04003595sub mangle_symbol_GCC($$)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003596{ # see gcc-4.6.0/gcc/cp/mangle.c
3597 my ($InfoId, $LibVersion) = @_;
3598 my ($Mangled, $ClassId, $NameSpace) = ("_Z", 0, "");
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04003599 my $Return = $SymbolInfo{$LibVersion}{$InfoId}{"Return"};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003600 my %Repl = ();# SN_ replacements
3601 if($ClassId = $SymbolInfo{$LibVersion}{$InfoId}{"Class"})
3602 {
3603 my $MangledClass = mangle_param($ClassId, $LibVersion, \%Repl);
3604 if($MangledClass!~/\AN/) {
3605 $MangledClass = "N".$MangledClass;
3606 }
3607 else {
3608 $MangledClass=~s/E\Z//;
3609 }
3610 if($SymbolInfo{$LibVersion}{$InfoId}{"Volatile"}) {
3611 $MangledClass=~s/\AN/NV/;
3612 }
3613 if($SymbolInfo{$LibVersion}{$InfoId}{"Const"}) {
3614 $MangledClass=~s/\AN/NK/;
3615 }
3616 $Mangled .= $MangledClass;
3617 }
3618 elsif($NameSpace = $SymbolInfo{$LibVersion}{$InfoId}{"NameSpace"})
3619 { # mangled by name due to the absence of structured info
3620 my $MangledNS = mangle_ns($NameSpace, $LibVersion, \%Repl);
3621 if($MangledNS!~/\AN/) {
3622 $MangledNS = "N".$MangledNS;
3623 }
3624 else {
3625 $MangledNS=~s/E\Z//;
3626 }
3627 $Mangled .= $MangledNS;
3628 }
3629 my ($ShortName, $TmplParams) = template_base($SymbolInfo{$LibVersion}{$InfoId}{"ShortName"});
Andrey Ponomarenko16934472012-03-29 15:37:04 +04003630 my @TParams = ();
3631 if($Version)
3632 { # parsing mode
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04003633 @TParams = getTParams($InfoId, "Func");
Andrey Ponomarenko16934472012-03-29 15:37:04 +04003634 }
3635 elsif($TmplParams)
3636 { # remangling mode
3637 # support for old ABI dumps
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003638 @TParams = separate_params($TmplParams, 0);
3639 }
3640 if($SymbolInfo{$LibVersion}{$InfoId}{"Constructor"}) {
3641 $Mangled .= "C1";
3642 }
3643 elsif($SymbolInfo{$LibVersion}{$InfoId}{"Destructor"}) {
3644 $Mangled .= "D0";
3645 }
3646 elsif($ShortName)
3647 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04003648 if($SymbolInfo{$LibVersion}{$InfoId}{"Data"})
3649 {
Andrey Ponomarenko16934472012-03-29 15:37:04 +04003650 if(not $SymbolInfo{$LibVersion}{$InfoId}{"Class"}
Andrey Ponomarenko85043792012-05-14 16:48:07 +04003651 and isConstType($Return, $LibVersion))
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04003652 { # "const" global data is mangled as _ZL...
3653 $Mangled .= "L";
3654 }
3655 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003656 if($ShortName=~/\Aoperator(\W.*)\Z/)
3657 {
3658 my $Op = $1;
3659 $Op=~s/\A[ ]+//g;
3660 if(my $OpMngl = $OperatorMangling{$Op}) {
3661 $Mangled .= $OpMngl;
3662 }
3663 else { # conversion operator
3664 $Mangled .= "cv".mangle_param(getTypeIdByName($Op, $LibVersion), $LibVersion, \%Repl);
3665 }
3666 }
3667 else {
3668 $Mangled .= length($ShortName).$ShortName;
3669 }
3670 if(@TParams)
3671 { # templates
3672 $Mangled .= "I";
3673 foreach my $TParam (@TParams) {
3674 $Mangled .= mangle_template_param($TParam, $LibVersion, \%Repl);
3675 }
3676 $Mangled .= "E";
3677 }
3678 if(not $ClassId and @TParams) {
3679 add_substitution($ShortName, \%Repl, 0);
3680 }
3681 }
3682 if($ClassId or $NameSpace) {
3683 $Mangled .= "E";
3684 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +04003685 if(@TParams)
3686 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04003687 if($Return) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003688 $Mangled .= mangle_param($Return, $LibVersion, \%Repl);
3689 }
3690 }
3691 if(not $SymbolInfo{$LibVersion}{$InfoId}{"Data"})
3692 {
3693 my @Params = ();
3694 if(defined $SymbolInfo{$LibVersion}{$InfoId}{"Param"}
3695 and not $SymbolInfo{$LibVersion}{$InfoId}{"Destructor"}) {
3696 @Params = keys(%{$SymbolInfo{$LibVersion}{$InfoId}{"Param"}});
3697 }
3698 foreach my $ParamPos (sort {int($a) <=> int($b)} @Params)
3699 { # checking parameters
3700 my $ParamType_Id = $SymbolInfo{$LibVersion}{$InfoId}{"Param"}{$ParamPos}{"type"};
3701 $Mangled .= mangle_param($ParamType_Id, $LibVersion, \%Repl);
3702 }
3703 if(not @Params) {
3704 $Mangled .= "v";
3705 }
3706 }
3707 $Mangled = correct_incharge($InfoId, $LibVersion, $Mangled);
3708 $Mangled = write_stdcxx_substitution($Mangled);
3709 if($Mangled eq "_Z") {
3710 return "";
3711 }
3712 return $Mangled;
3713}
3714
3715sub correct_incharge($$$)
3716{
3717 my ($InfoId, $LibVersion, $Mangled) = @_;
3718 if($SymbolInfo{$LibVersion}{$InfoId}{"Constructor"})
3719 {
3720 if($MangledNames{$LibVersion}{$Mangled}) {
3721 $Mangled=~s/C1E/C2E/;
3722 }
3723 }
3724 elsif($SymbolInfo{$LibVersion}{$InfoId}{"Destructor"})
3725 {
3726 if($MangledNames{$LibVersion}{$Mangled}) {
3727 $Mangled=~s/D0E/D1E/;
3728 }
3729 if($MangledNames{$LibVersion}{$Mangled}) {
3730 $Mangled=~s/D1E/D2E/;
3731 }
3732 }
3733 return $Mangled;
3734}
3735
3736sub template_base($)
3737{ # NOTE: std::_Vector_base<mysqlpp::mysql_type_info>::_Vector_impl
Andrey Ponomarenko16934472012-03-29 15:37:04 +04003738 # NOTE: operators: >>, <<
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003739 my $Name = $_[0];
Andrey Ponomarenko16934472012-03-29 15:37:04 +04003740 if($Name!~/>\Z/ or $Name!~/</) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003741 return $Name;
3742 }
3743 my $TParams = $Name;
Andrey Ponomarenko16934472012-03-29 15:37:04 +04003744 while(my $CPos = find_center($TParams, "<"))
3745 { # search for the last <T>
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003746 $TParams = substr($TParams, $CPos);
3747 }
Andrey Ponomarenko16934472012-03-29 15:37:04 +04003748 if($TParams=~s/\A<(.+)>\Z/$1/) {
3749 $Name=~s/<\Q$TParams\E>\Z//;
3750 }
3751 else
3752 { # error
3753 $TParams = "";
3754 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003755 return ($Name, $TParams);
3756}
3757
3758sub get_sub_ns($)
3759{
3760 my $Name = $_[0];
3761 my @NS = ();
Andrey Ponomarenko16934472012-03-29 15:37:04 +04003762 while(my $CPos = find_center($Name, ":"))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003763 {
3764 push(@NS, substr($Name, 0, $CPos));
3765 $Name = substr($Name, $CPos);
3766 $Name=~s/\A:://;
3767 }
3768 return (join("::", @NS), $Name);
3769}
3770
3771sub mangle_ns($$$)
3772{
3773 my ($Name, $LibVersion, $Repl) = @_;
3774 if(my $Tid = $TName_Tid{$LibVersion}{$Name})
3775 {
3776 my $Mangled = mangle_param($Tid, $LibVersion, $Repl);
3777 $Mangled=~s/\AN(.+)E\Z/$1/;
3778 return $Mangled;
3779
3780 }
3781 else
3782 {
3783 my ($MangledNS, $SubNS) = ("", "");
3784 ($SubNS, $Name) = get_sub_ns($Name);
3785 if($SubNS) {
3786 $MangledNS .= mangle_ns($SubNS, $LibVersion, $Repl);
3787 }
3788 $MangledNS .= length($Name).$Name;
3789 add_substitution($MangledNS, $Repl, 0);
3790 return $MangledNS;
3791 }
3792}
3793
3794sub mangle_param($$$)
3795{
3796 my ($PTid, $LibVersion, $Repl) = @_;
3797 my ($MPrefix, $Mangled) = ("", "");
3798 my %ReplCopy = %{$Repl};
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04003799 my %BaseType = get_BaseType($PTid, $LibVersion);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003800 my $BaseType_Name = $BaseType{"Name"};
3801 if(not $BaseType_Name) {
3802 return "";
3803 }
3804 my ($ShortName, $TmplParams) = template_base($BaseType_Name);
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04003805 my $Suffix = get_BaseTypeQual($PTid, $LibVersion);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003806 while($Suffix=~s/\s*(const|volatile|restrict)\Z//g){};
3807 while($Suffix=~/(&|\*|const)\Z/)
3808 {
3809 if($Suffix=~s/[ ]*&\Z//) {
3810 $MPrefix .= "R";
3811 }
3812 if($Suffix=~s/[ ]*\*\Z//) {
3813 $MPrefix .= "P";
3814 }
3815 if($Suffix=~s/[ ]*const\Z//)
3816 {
3817 if($MPrefix=~/R|P/
3818 or $Suffix=~/&|\*/) {
3819 $MPrefix .= "K";
3820 }
3821 }
3822 if($Suffix=~s/[ ]*volatile\Z//) {
3823 $MPrefix .= "V";
3824 }
3825 #if($Suffix=~s/[ ]*restrict\Z//) {
3826 #$MPrefix .= "r";
3827 #}
3828 }
3829 if(my $Token = $IntrinsicMangling{$BaseType_Name}) {
3830 $Mangled .= $Token;
3831 }
3832 elsif($BaseType{"Type"}=~/(Class|Struct|Union|Enum)/)
3833 {
Andrey Ponomarenko16934472012-03-29 15:37:04 +04003834 my @TParams = ();
3835 if($Version)
3836 { # parsing mode
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04003837 @TParams = getTParams($BaseType{"Tid"}, "Type");
Andrey Ponomarenko16934472012-03-29 15:37:04 +04003838 }
3839 elsif($TmplParams)
3840 { # remangling mode
3841 # support for old ABI dumps
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003842 @TParams = separate_params($TmplParams, 0);
3843 }
3844 my $MangledNS = "";
3845 my ($SubNS, $SName) = get_sub_ns($ShortName);
3846 if($SubNS) {
3847 $MangledNS .= mangle_ns($SubNS, $LibVersion, $Repl);
3848 }
3849 $MangledNS .= length($SName).$SName;
3850 if(@TParams) {
3851 add_substitution($MangledNS, $Repl, 0);
3852 }
3853 $Mangled .= "N".$MangledNS;
3854 if(@TParams)
3855 { # templates
3856 $Mangled .= "I";
3857 foreach my $TParam (@TParams) {
3858 $Mangled .= mangle_template_param($TParam, $LibVersion, $Repl);
3859 }
3860 $Mangled .= "E";
3861 }
3862 $Mangled .= "E";
3863 }
3864 elsif($BaseType{"Type"}=~/(FuncPtr|MethodPtr)/)
3865 {
3866 if($BaseType{"Type"} eq "MethodPtr") {
3867 $Mangled .= "M".mangle_param($BaseType{"Class"}, $LibVersion, $Repl)."F";
3868 }
3869 else {
3870 $Mangled .= "PF";
3871 }
3872 $Mangled .= mangle_param($BaseType{"Return"}, $LibVersion, $Repl);
3873 my @Params = keys(%{$BaseType{"Param"}});
3874 foreach my $Num (sort {int($a)<=>int($b)} @Params) {
3875 $Mangled .= mangle_param($BaseType{"Param"}{$Num}{"type"}, $LibVersion, $Repl);
3876 }
3877 if(not @Params) {
3878 $Mangled .= "v";
3879 }
3880 $Mangled .= "E";
3881 }
3882 elsif($BaseType{"Type"} eq "FieldPtr")
3883 {
3884 $Mangled .= "M".mangle_param($BaseType{"Class"}, $LibVersion, $Repl);
3885 $Mangled .= mangle_param($BaseType{"Return"}, $LibVersion, $Repl);
3886 }
3887 $Mangled = $MPrefix.$Mangled;# add prefix (RPK)
3888 if(my $Optimized = write_substitution($Mangled, \%ReplCopy))
3889 {
3890 if($Mangled eq $Optimized)
3891 {
3892 if($ShortName!~/::/)
3893 { # remove "N ... E"
3894 if($MPrefix) {
3895 $Mangled=~s/\A($MPrefix)N(.+)E\Z/$1$2/g;
3896 }
3897 else {
3898 $Mangled=~s/\AN(.+)E\Z/$1/g;
3899 }
3900 }
3901 }
3902 else {
3903 $Mangled = $Optimized;
3904 }
3905 }
3906 add_substitution($Mangled, $Repl, 1);
3907 return $Mangled;
3908}
3909
3910sub mangle_template_param($$$)
3911{ # types + literals
3912 my ($TParam, $LibVersion, $Repl) = @_;
3913 if(my $TPTid = $TName_Tid{$LibVersion}{$TParam}) {
3914 return mangle_param($TPTid, $LibVersion, $Repl);
3915 }
3916 elsif($TParam=~/\A(\d+)(\w+)\Z/)
3917 { # class_name<1u>::method(...)
3918 return "L".$IntrinsicMangling{$ConstantSuffixR{$2}}.$1."E";
3919 }
3920 elsif($TParam=~/\A\(([\w ]+)\)(\d+)\Z/)
3921 { # class_name<(signed char)1>::method(...)
3922 return "L".$IntrinsicMangling{$1}.$2."E";
3923 }
3924 elsif($TParam eq "true")
3925 { # class_name<true>::method(...)
3926 return "Lb1E";
3927 }
3928 elsif($TParam eq "false")
3929 { # class_name<true>::method(...)
3930 return "Lb0E";
3931 }
3932 else { # internal error
3933 return length($TParam).$TParam;
3934 }
3935}
3936
3937sub add_substitution($$$)
3938{
3939 my ($Value, $Repl, $Rec) = @_;
3940 if($Rec)
3941 { # subtypes
3942 my @Subs = ($Value);
3943 while($Value=~s/\A(R|P|K)//) {
3944 push(@Subs, $Value);
3945 }
3946 foreach (reverse(@Subs)) {
3947 add_substitution($_, $Repl, 0);
3948 }
3949 return;
3950 }
3951 return if($Value=~/\AS(\d*)_\Z/);
3952 $Value=~s/\AN(.+)E\Z/$1/g;
3953 return if(defined $Repl->{$Value});
3954 return if(length($Value)<=1);
3955 return if($StdcxxMangling{$Value});
3956 # check for duplicates
3957 my $Base = $Value;
3958 foreach my $Type (sort {$Repl->{$a}<=>$Repl->{$b}} sort keys(%{$Repl}))
3959 {
3960 my $Num = $Repl->{$Type};
3961 my $Replace = macro_mangle($Num);
3962 $Base=~s/\Q$Replace\E/$Type/;
3963 }
3964 if(my $OldNum = $Repl->{$Base})
3965 {
3966 $Repl->{$Value} = $OldNum;
3967 return;
3968 }
3969 my @Repls = sort {$b<=>$a} values(%{$Repl});
3970 if(@Repls) {
3971 $Repl->{$Value} = $Repls[0]+1;
3972 }
3973 else {
3974 $Repl->{$Value} = -1;
3975 }
3976 # register duplicates
3977 # upward
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04003978 $Base = $Value;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003979 foreach my $Type (sort {$Repl->{$a}<=>$Repl->{$b}} sort keys(%{$Repl}))
3980 {
3981 next if($Base eq $Type);
3982 my $Num = $Repl->{$Type};
3983 my $Replace = macro_mangle($Num);
3984 $Base=~s/\Q$Type\E/$Replace/;
3985 $Repl->{$Base} = $Repl->{$Value};
3986 }
3987}
3988
3989sub macro_mangle($)
3990{
3991 my $Num = $_[0];
3992 if($Num==-1) {
3993 return "S_";
3994 }
3995 else
3996 {
3997 my $Code = "";
3998 if($Num<10)
3999 { # S0_, S1_, S2_, ...
4000 $Code = $Num;
4001 }
4002 elsif($Num>=10 and $Num<=35)
4003 { # SA_, SB_, SC_, ...
4004 $Code = chr(55+$Num);
4005 }
4006 else
4007 { # S10_, S11_, S12_
4008 $Code = $Num-26; # 26 is length of english alphabet
4009 }
4010 return "S".$Code."_";
4011 }
4012}
4013
4014sub write_stdcxx_substitution($)
4015{
4016 my $Mangled = $_[0];
4017 if($StdcxxMangling{$Mangled}) {
4018 return $StdcxxMangling{$Mangled};
4019 }
4020 else
4021 {
4022 my @Repls = keys(%StdcxxMangling);
4023 @Repls = sort {length($b)<=>length($a)} sort {$b cmp $a} @Repls;
4024 foreach my $MangledType (@Repls)
4025 {
4026 my $Replace = $StdcxxMangling{$MangledType};
4027 #if($Mangled!~/$Replace/) {
4028 $Mangled=~s/N\Q$MangledType\EE/$Replace/g;
4029 $Mangled=~s/\Q$MangledType\E/$Replace/g;
4030 #}
4031 }
4032 }
4033 return $Mangled;
4034}
4035
4036sub write_substitution($$)
4037{
4038 my ($Mangled, $Repl) = @_;
4039 if(defined $Repl->{$Mangled}
4040 and my $MnglNum = $Repl->{$Mangled}) {
4041 $Mangled = macro_mangle($MnglNum);
4042 }
4043 else
4044 {
4045 my @Repls = keys(%{$Repl});
4046 #@Repls = sort {$Repl->{$a}<=>$Repl->{$b}} @Repls;
4047 # FIXME: how to apply replacements? by num or by pos
4048 @Repls = sort {length($b)<=>length($a)} sort {$b cmp $a} @Repls;
4049 foreach my $MangledType (@Repls)
4050 {
4051 my $Replace = macro_mangle($Repl->{$MangledType});
4052 if($Mangled!~/$Replace/) {
4053 $Mangled=~s/N\Q$MangledType\EE/$Replace/g;
4054 $Mangled=~s/\Q$MangledType\E/$Replace/g;
4055 }
4056 }
4057 }
4058 return $Mangled;
4059}
4060
4061sub delete_keywords($)
4062{
4063 my $TypeName = $_[0];
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04004064 $TypeName=~s/\b(enum|struct|union|class) //g;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004065 return $TypeName;
4066}
4067
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004068sub uncover_typedefs($$)
4069{
4070 my ($TypeName, $LibVersion) = @_;
4071 return "" if(not $TypeName);
4072 if(defined $Cache{"uncover_typedefs"}{$LibVersion}{$TypeName}) {
4073 return $Cache{"uncover_typedefs"}{$LibVersion}{$TypeName};
4074 }
4075 my ($TypeName_New, $TypeName_Pre) = (formatName($TypeName), "");
4076 while($TypeName_New ne $TypeName_Pre)
4077 {
4078 $TypeName_Pre = $TypeName_New;
4079 my $TypeName_Copy = $TypeName_New;
4080 my %Words = ();
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04004081 while($TypeName_Copy=~s/\b([a-z_]([\w:]*\w|))\b//io)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004082 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04004083 if(not $Intrinsic_Keywords{$1}) {
4084 $Words{$1} = 1;
4085 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004086 }
4087 foreach my $Word (keys(%Words))
4088 {
4089 my $BaseType_Name = $Typedef_BaseName{$LibVersion}{$Word};
4090 next if(not $BaseType_Name);
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04004091 next if($TypeName_New=~/\b(struct|union|enum)\s\Q$Word\E\b/);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004092 if($BaseType_Name=~/\([\*]+\)/)
4093 { # FuncPtr
4094 if($TypeName_New=~/\Q$Word\E(.*)\Z/)
4095 {
4096 my $Type_Suffix = $1;
4097 $TypeName_New = $BaseType_Name;
4098 if($TypeName_New=~s/\(([\*]+)\)/($1 $Type_Suffix)/) {
4099 $TypeName_New = formatName($TypeName_New);
4100 }
4101 }
4102 }
4103 else
4104 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04004105 if($TypeName_New=~s/\b\Q$Word\E\b/$BaseType_Name/g) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004106 $TypeName_New = formatName($TypeName_New);
4107 }
4108 }
4109 }
4110 }
4111 return ($Cache{"uncover_typedefs"}{$LibVersion}{$TypeName} = $TypeName_New);
4112}
4113
4114sub isInternal($)
4115{
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04004116 if($_[0] and my $Info = $LibInfo{$Version}{"info"}{$_[0]})
4117 {
4118 if($Info=~/mngl[ ]*:[ ]*@(\d+) /)
4119 {
4120 if($LibInfo{$Version}{"info"}{$1}=~/\*[ ]*INTERNAL[ ]*\*/)
4121 { # _ZN7mysqlpp8DateTimeC1ERKS0_ *INTERNAL*
4122 return 1;
4123 }
4124 }
4125 }
4126 return 0;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004127}
4128
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04004129sub getDataVal($$)
4130{
4131 my ($InfoId, $TypeId) = @_;
4132 if(my $Info = $LibInfo{$Version}{"info"}{$InfoId})
4133 {
4134 if($Info=~/init[ ]*:[ ]*@(\d+) /)
4135 {
4136 if(defined $LibInfo{$Version}{"info_type"}{$1}
4137 and $LibInfo{$Version}{"info_type"}{$1} eq "nop_expr")
4138 { # char const* data = "str"
4139 # NOTE: disabled
4140 if(my $NopExpr = $LibInfo{$Version}{"info"}{$1})
4141 {
4142 if($NopExpr=~/op 0[ ]*:[ ]*@(\d+) /)
4143 {
4144 if(defined $LibInfo{$Version}{"info_type"}{$1}
4145 and $LibInfo{$Version}{"info_type"}{$1} eq "addr_expr")
4146 {
4147 if(my $AddrExpr = $LibInfo{$Version}{"info"}{$1})
4148 {
4149 if($AddrExpr=~/op 0[ ]*:[ ]*@(\d+) /)
4150 {
4151 return getInitVal($1, $TypeId);
4152 }
4153 }
4154 }
4155 }
4156 }
4157 }
4158 else {
4159 return getInitVal($1, $TypeId);
4160 }
4161 }
4162 }
4163 return undef;
4164}
4165
4166sub getInitVal($$)
4167{
4168 my ($InfoId, $TypeId) = @_;
4169 if(my $Info = $LibInfo{$Version}{"info"}{$InfoId})
4170 {
4171 if(my $InfoType = $LibInfo{$Version}{"info_type"}{$InfoId})
4172 {
4173 if($InfoType eq "integer_cst")
4174 {
4175 my $Val = getNodeIntCst($InfoId);
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04004176 if($TypeId and $TypeInfo{$Version}{$TypeId}{"Name"}=~/\Achar(| const)\Z/)
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04004177 { # characters
4178 $Val = chr($Val);
4179 }
4180 return $Val;
4181 }
4182 elsif($InfoType eq "string_cst") {
4183 return getNodeStrCst($InfoId);
4184 }
4185 }
4186 }
4187 return undef;
4188}
4189
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004190sub set_Class_And_Namespace($)
4191{
4192 my $InfoId = $_[0];
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04004193 if(my $Info = $LibInfo{$Version}{"info"}{$InfoId})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004194 {
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04004195 if($Info=~/scpe[ ]*:[ ]*@(\d+) /)
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04004196 {
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04004197 my $NSInfoId = $1;
4198 if(my $InfoType = $LibInfo{$Version}{"info_type"}{$NSInfoId})
4199 {
4200 if($InfoType eq "namespace_decl") {
4201 $SymbolInfo{$Version}{$InfoId}{"NameSpace"} = getNameSpace($InfoId);
4202 }
4203 elsif($InfoType eq "record_type") {
4204 $SymbolInfo{$Version}{$InfoId}{"Class"} = $NSInfoId;
4205 }
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04004206 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004207 }
4208 }
4209 if($SymbolInfo{$Version}{$InfoId}{"Class"}
4210 or $SymbolInfo{$Version}{$InfoId}{"NameSpace"})
4211 { # identify language
4212 setLanguage($Version, "C++");
4213 }
4214}
4215
4216sub debugType($$)
4217{
4218 my ($Tid, $LibVersion) = @_;
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04004219 my %Type = get_Type($Tid, $LibVersion);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004220 printMsg("INFO", Dumper(\%Type));
4221}
4222
4223sub debugMangling($)
4224{
4225 my $LibVersion = $_[0];
4226 my %Mangled = ();
4227 foreach my $InfoId (keys(%{$SymbolInfo{$LibVersion}}))
4228 {
4229 if(my $Mngl = $SymbolInfo{$LibVersion}{$InfoId}{"MnglName"})
4230 {
4231 if($Mngl=~/\A(_Z|\?)/) {
4232 $Mangled{$Mngl}=$InfoId;
4233 }
4234 }
4235 }
4236 translateSymbols(keys(%Mangled), $LibVersion);
4237 foreach my $Mngl (keys(%Mangled))
4238 {
Andrey Ponomarenko85043792012-05-14 16:48:07 +04004239 my $U1 = modelUnmangled($Mangled{$Mngl}, "GCC");
4240 my $U2 = $tr_name{$Mngl};
4241 if($U1 ne $U2) {
4242 printMsg("INFO", "INCORRECT MANGLING:\n $Mngl\n $U1\n $U2\n");
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004243 }
4244 }
4245}
4246
4247sub linkSymbol($)
4248{ # link symbols from shared libraries
4249 # with the symbols from header files
4250 my $InfoId = $_[0];
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04004251 if(my $Lang = $SymbolInfo{$Version}{$InfoId}{"Lang"})
4252 {
4253 if($Lang eq "C")
4254 { # extern "C"
4255 return $SymbolInfo{$Version}{$InfoId}{"ShortName"};
4256 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004257 }
4258 # try to mangle symbol
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04004259 if((not check_gcc($GCC_PATH, "4") and $SymbolInfo{$Version}{$InfoId}{"Class"})
4260 or (check_gcc($GCC_PATH, "4") and not $SymbolInfo{$Version}{$InfoId}{"Class"}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004261 { # 1. GCC 3.x doesn't mangle class methods names in the TU dump (only functions and global data)
4262 # 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 +04004263 if(not $CheckHeadersOnly)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004264 {
4265 if(my $Mangled = $mangled_name_gcc{modelUnmangled($InfoId, "GCC")}) {
4266 return correct_incharge($InfoId, $Version, $Mangled);
4267 }
4268 }
Andrey Ponomarenko16934472012-03-29 15:37:04 +04004269 if($CheckHeadersOnly
4270 or not $BinaryOnly)
4271 { # 1. --headers-only mode
4272 # 2. not mangled src-only symbols
4273 if(my $Mangled = mangle_symbol($InfoId, $Version, "GCC")) {
4274 return $Mangled;
4275 }
4276 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004277 }
4278 return "";
4279}
4280
4281sub setLanguage($$)
4282{
4283 my ($LibVersion, $Lang) = @_;
4284 if(not $UserLang) {
4285 $COMMON_LANGUAGE{$LibVersion} = $Lang;
4286 }
4287}
4288
4289sub getSymbolInfo($)
4290{
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04004291 my $InfoId = $_[0];
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04004292 if(isInternal($InfoId)) {
4293 return;
4294 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04004295 ($SymbolInfo{$Version}{$InfoId}{"Header"}, $SymbolInfo{$Version}{$InfoId}{"Line"}) = getLocation($InfoId);
4296 if(not $SymbolInfo{$Version}{$InfoId}{"Header"}
4297 or isBuiltIn($SymbolInfo{$Version}{$InfoId}{"Header"})) {
4298 delete($SymbolInfo{$Version}{$InfoId});
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004299 return;
4300 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04004301 setFuncAccess($InfoId);
4302 setFuncKind($InfoId);
4303 if($SymbolInfo{$Version}{$InfoId}{"PseudoTemplate"}) {
4304 delete($SymbolInfo{$Version}{$InfoId});
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004305 return;
4306 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04004307 $SymbolInfo{$Version}{$InfoId}{"Type"} = getFuncType($InfoId);
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04004308 if($SymbolInfo{$Version}{$InfoId}{"Return"} = getFuncReturn($InfoId))
4309 {
4310 if(not $TypeInfo{$Version}{$SymbolInfo{$Version}{$InfoId}{"Return"}}{"Name"})
4311 { # templates
4312 delete($SymbolInfo{$Version}{$InfoId});
4313 return;
4314 }
4315 }
4316 if(my $Rid = $SymbolInfo{$Version}{$InfoId}{"Return"})
4317 {
4318 if(defined $MissedTypedef{$Version}{$Rid})
4319 {
4320 if(my $AddedTid = $MissedTypedef{$Version}{$Rid}{"Tid"}) {
4321 $SymbolInfo{$Version}{$InfoId}{"Return"} = $AddedTid;
4322 }
4323 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004324 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04004325 if(not $SymbolInfo{$Version}{$InfoId}{"Return"}) {
4326 delete($SymbolInfo{$Version}{$InfoId}{"Return"});
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004327 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04004328 $SymbolInfo{$Version}{$InfoId}{"ShortName"} = getFuncShortName(getFuncOrig($InfoId));
4329 if($SymbolInfo{$Version}{$InfoId}{"ShortName"}=~/\._/) {
4330 delete($SymbolInfo{$Version}{$InfoId});
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004331 return;
4332 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04004333 if(defined $TemplateInstance{$Version}{"Func"}{$InfoId})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004334 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04004335 my @TParams = getTParams($InfoId, "Func");
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004336 if(not @TParams) {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04004337 delete($SymbolInfo{$Version}{$InfoId});
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004338 return;
4339 }
Andrey Ponomarenko16934472012-03-29 15:37:04 +04004340 foreach my $Pos (0 .. $#TParams) {
4341 $SymbolInfo{$Version}{$InfoId}{"TParam"}{$Pos}{"name"}=$TParams[$Pos];
4342 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004343 my $PrmsInLine = join(", ", @TParams);
Andrey Ponomarenko16934472012-03-29 15:37:04 +04004344 if($SymbolInfo{$Version}{$InfoId}{"ShortName"}=~/\Aoperator\W+\Z/)
4345 { # operator<< <T>, operator>> <T>
4346 $SymbolInfo{$Version}{$InfoId}{"ShortName"} .= " ";
4347 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04004348 $SymbolInfo{$Version}{$InfoId}{"ShortName"} .= "<".$PrmsInLine.">";
4349 $SymbolInfo{$Version}{$InfoId}{"ShortName"} = formatName($SymbolInfo{$Version}{$InfoId}{"ShortName"});
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004350 }
4351 else
4352 { # support for GCC 3.4
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04004353 $SymbolInfo{$Version}{$InfoId}{"ShortName"}=~s/<.+>\Z//;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004354 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04004355 $SymbolInfo{$Version}{$InfoId}{"MnglName"} = getTreeStr(getTreeAttr_Mngl($InfoId));
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04004356 # NOTE: mangling of some symbols may change depending on GCC version
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04004357 # GCC 4.6: _ZN28QExplicitlySharedDataPointerI11QPixmapDataEC2IT_EERKS_IT_E
4358 # GCC 4.7: _ZN28QExplicitlySharedDataPointerI11QPixmapDataEC2ERKS1_
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04004359
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04004360 if($SymbolInfo{$Version}{$InfoId}{"MnglName"}
4361 and $SymbolInfo{$Version}{$InfoId}{"MnglName"}!~/\A_Z/)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004362 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04004363 delete($SymbolInfo{$Version}{$InfoId});
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004364 return;
4365 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04004366 if(not $SymbolInfo{$Version}{$InfoId}{"Destructor"})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004367 { # destructors have an empty parameter list
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04004368 my $Skip = setFuncParams($InfoId);
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04004369 if($Skip) {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04004370 delete($SymbolInfo{$Version}{$InfoId});
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004371 return;
4372 }
4373 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04004374 set_Class_And_Namespace($InfoId);
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04004375 if(my $ClassId = $SymbolInfo{$Version}{$InfoId}{"Class"})
4376 {
4377 if(not $TypeInfo{$Version}{$ClassId}{"Name"})
4378 { # templates
4379 delete($SymbolInfo{$Version}{$InfoId});
4380 return;
4381 }
4382 }
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04004383 if(not $CheckHeadersOnly)
4384 {
4385 if($SymbolInfo{$Version}{$InfoId}{"Type"} eq "Function"
4386 and not $SymbolInfo{$Version}{$InfoId}{"Class"}
4387 and link_symbol($SymbolInfo{$Version}{$InfoId}{"ShortName"}, $Version, "-Deps"))
4388 { # functions (C++): not mangled in library, but are mangled in TU dump
4389 if(not $SymbolInfo{$Version}{$InfoId}{"MnglName"}
4390 or not link_symbol($SymbolInfo{$Version}{$InfoId}{"MnglName"}, $Version, "-Deps")) {
4391 $SymbolInfo{$Version}{$InfoId}{"MnglName"} = $SymbolInfo{$Version}{$InfoId}{"ShortName"};
4392 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004393 }
4394 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04004395 if($LibInfo{$Version}{"info"}{$InfoId}=~/ lang:[ ]*C /i) {
4396 $SymbolInfo{$Version}{$InfoId}{"Lang"} = "C";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004397 }
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04004398 if($UserLang and $UserLang eq "C")
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004399 { # --lang=C option
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04004400 $SymbolInfo{$Version}{$InfoId}{"MnglName"} = $SymbolInfo{$Version}{$InfoId}{"ShortName"};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004401 }
4402 if($COMMON_LANGUAGE{$Version} eq "C++")
4403 { # correct mangled & short names
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04004404 # C++ or --headers-only mode
4405 if($SymbolInfo{$Version}{$InfoId}{"ShortName"}=~/\A__(comp|base|deleting)_(c|d)tor\Z/)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004406 { # support for old GCC versions: reconstruct real names for constructors and destructors
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04004407 $SymbolInfo{$Version}{$InfoId}{"ShortName"} = getNameByInfo(getTypeDeclId($SymbolInfo{$Version}{$InfoId}{"Class"}));
4408 $SymbolInfo{$Version}{$InfoId}{"ShortName"}=~s/<.+>\Z//;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004409 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04004410 if(not $SymbolInfo{$Version}{$InfoId}{"MnglName"})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004411 { # try to mangle symbol (link with libraries)
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04004412 if(my $Mangled = linkSymbol($InfoId)) {
4413 $SymbolInfo{$Version}{$InfoId}{"MnglName"} = $Mangled;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004414 }
4415 }
4416 if($OStarget eq "windows")
4417 { # link MS C++ symbols from library with GCC symbols from headers
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04004418 if(my $Mangled1 = $mangled_name{$Version}{modelUnmangled($InfoId, "MSVC")})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004419 { # exported symbols
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04004420 $SymbolInfo{$Version}{$InfoId}{"MnglName"} = $Mangled1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004421 }
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04004422 elsif(my $Mangled2 = mangle_symbol($InfoId, $Version, "MSVC"))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004423 { # pure virtual symbols
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04004424 $SymbolInfo{$Version}{$InfoId}{"MnglName"} = $Mangled2;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004425 }
4426 }
4427 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04004428 if(not $SymbolInfo{$Version}{$InfoId}{"MnglName"})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004429 { # can't detect symbol name
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04004430 delete($SymbolInfo{$Version}{$InfoId});
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004431 return;
4432 }
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04004433 if(not $SymbolInfo{$Version}{$InfoId}{"Constructor"}
4434 and my $Spec = getVirtSpec(getFuncOrig($InfoId)))
4435 { # identify virtual and pure virtual functions
4436 # NOTE: constructors cannot be virtual
4437 # NOTE: in GCC 4.7 D1 destructors have no virtual spec
4438 # in the TU dump, so taking it from the original symbol
4439 if(not ($SymbolInfo{$Version}{$InfoId}{"Destructor"}
4440 and $SymbolInfo{$Version}{$InfoId}{"MnglName"}=~/D2E/))
4441 { # NOTE: D2 destructors are not present in a v-table
4442 $SymbolInfo{$Version}{$InfoId}{$Spec} = 1;
4443 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004444 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04004445 if(isInline($InfoId)) {
4446 $SymbolInfo{$Version}{$InfoId}{"InLine"} = 1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004447 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04004448 if($SymbolInfo{$Version}{$InfoId}{"Constructor"}
4449 and my $ClassId = $SymbolInfo{$Version}{$InfoId}{"Class"})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004450 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04004451 if(not $SymbolInfo{$Version}{$InfoId}{"InLine"}
4452 and $LibInfo{$Version}{"info"}{$InfoId}!~/ artificial /i)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004453 { # inline or auto-generated constructor
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04004454 delete($TypeInfo{$Version}{$ClassId}{"Copied"});
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004455 }
4456 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +04004457 if(my $Symbol = $SymbolInfo{$Version}{$InfoId}{"MnglName"})
4458 {
4459 if(not $SymbolInfo{$Version}{$InfoId}{"Virt"}
4460 and not $SymbolInfo{$Version}{$InfoId}{"PureVirt"})
4461 {
4462 if(not selectSymbol($Symbol, $SymbolInfo{$Version}{$InfoId}, "Dump", $Version))
4463 { # non-target symbols
4464 delete($SymbolInfo{$Version}{$InfoId});
4465 return;
4466 }
4467 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004468 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04004469 if($SymbolInfo{$Version}{$InfoId}{"Type"} eq "Method"
4470 or $SymbolInfo{$Version}{$InfoId}{"Constructor"}
4471 or $SymbolInfo{$Version}{$InfoId}{"Destructor"}
4472 or $SymbolInfo{$Version}{$InfoId}{"Class"})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004473 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04004474 if($SymbolInfo{$Version}{$InfoId}{"MnglName"}!~/\A(_Z|\?)/) {
4475 delete($SymbolInfo{$Version}{$InfoId});
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004476 return;
4477 }
4478 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04004479 if($SymbolInfo{$Version}{$InfoId}{"MnglName"})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004480 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04004481 if($MangledNames{$Version}{$SymbolInfo{$Version}{$InfoId}{"MnglName"}})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004482 { # one instance for one mangled name only
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04004483 delete($SymbolInfo{$Version}{$InfoId});
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004484 return;
4485 }
4486 else {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04004487 $MangledNames{$Version}{$SymbolInfo{$Version}{$InfoId}{"MnglName"}} = 1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004488 }
4489 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04004490 if($SymbolInfo{$Version}{$InfoId}{"Constructor"}
4491 or $SymbolInfo{$Version}{$InfoId}{"Destructor"}) {
4492 delete($SymbolInfo{$Version}{$InfoId}{"Return"});
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004493 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04004494 if($SymbolInfo{$Version}{$InfoId}{"MnglName"}=~/\A(_Z|\?)/
4495 and $SymbolInfo{$Version}{$InfoId}{"Class"})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004496 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04004497 if($SymbolInfo{$Version}{$InfoId}{"Type"} eq "Function")
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004498 { # static methods
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04004499 $SymbolInfo{$Version}{$InfoId}{"Static"} = 1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004500 }
4501 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04004502 if(getFuncLink($InfoId) eq "Static") {
4503 $SymbolInfo{$Version}{$InfoId}{"Static"} = 1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004504 }
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04004505 if($SymbolInfo{$Version}{$InfoId}{"MnglName"}=~/\A(_Z|\?)/)
4506 {
4507 if(my $Unmangled = $tr_name{$SymbolInfo{$Version}{$InfoId}{"MnglName"}})
4508 {
4509 if($Unmangled=~/\.\_\d/) {
4510 delete($SymbolInfo{$Version}{$InfoId});
4511 return;
4512 }
4513 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004514 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04004515 delete($SymbolInfo{$Version}{$InfoId}{"Type"});
4516 if($SymbolInfo{$Version}{$InfoId}{"MnglName"}=~/\A_ZN(V|)K/) {
4517 $SymbolInfo{$Version}{$InfoId}{"Const"} = 1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004518 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04004519 if($SymbolInfo{$Version}{$InfoId}{"MnglName"}=~/\A_ZN(K|)V/) {
4520 $SymbolInfo{$Version}{$InfoId}{"Volatile"} = 1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004521 }
4522}
4523
4524sub isInline($)
4525{ # "body: undefined" in the tree
4526 # -fkeep-inline-functions GCC option should be specified
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04004527 if($_[0] and my $Info = $LibInfo{$Version}{"info"}{$_[0]})
4528 {
4529 if($Info=~/ undefined /i) {
4530 return 0;
4531 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004532 }
4533 return 1;
4534}
4535
4536sub getTypeId($)
4537{
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04004538 if($_[0] and my $Info = $LibInfo{$Version}{"info"}{$_[0]})
4539 {
4540 if($Info=~/type[ ]*:[ ]*@(\d+) /) {
4541 return $1;
4542 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004543 }
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04004544 return "";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004545}
4546
4547sub setTypeMemb($$)
4548{
4549 my ($TypeId, $TypeAttr) = @_;
4550 my $TypeType = $TypeAttr->{"Type"};
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04004551 my ($Pos, $UnnamedPos) = (0, 0);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004552 if($TypeType eq "Enum")
4553 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04004554 my $TypeMembInfoId = getTreeAttr_Csts($TypeId);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004555 while($TypeMembInfoId)
4556 {
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04004557 $TypeAttr->{"Memb"}{$Pos}{"value"} = getEnumMembVal($TypeMembInfoId);
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04004558 my $MembName = getTreeStr(getTreeAttr_Purp($TypeMembInfoId));
4559 $TypeAttr->{"Memb"}{$Pos}{"name"} = $MembName;
4560 $EnumMembName_Id{$Version}{getTreeAttr_Valu($TypeMembInfoId)} = ($TypeAttr->{"NameSpace"})?$TypeAttr->{"NameSpace"}."::".$MembName:$MembName;
4561 $TypeMembInfoId = getNextElem($TypeMembInfoId);
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04004562 $Pos += 1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004563 }
4564 }
4565 elsif($TypeType=~/\A(Struct|Class|Union)\Z/)
4566 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04004567 my $TypeMembInfoId = getTreeAttr_Flds($TypeId);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004568 while($TypeMembInfoId)
4569 {
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04004570 my $IType = $LibInfo{$Version}{"info_type"}{$TypeMembInfoId};
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04004571 my $MInfo = $LibInfo{$Version}{"info"}{$TypeMembInfoId};
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04004572 if(not $IType or $IType ne "field_decl")
4573 { # search for fields, skip other stuff in the declaration
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04004574 $TypeMembInfoId = getNextElem($TypeMembInfoId);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004575 next;
4576 }
4577 my $StructMembName = getStructMembName($TypeMembInfoId);
4578 if($StructMembName=~/_vptr\./)
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04004579 { # virtual tables
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04004580 $TypeMembInfoId = getNextElem($TypeMembInfoId);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004581 next;
4582 }
4583 if(not $StructMembName)
4584 { # unnamed fields
4585 if($TypeAttr->{"Name"}!~/_type_info_pseudo/)
4586 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04004587 my $UnnamedTid = getTreeAttr_Type($TypeMembInfoId);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004588 my $UnnamedTName = getNameByInfo(getTypeDeclId($UnnamedTid));
4589 if(isAnon($UnnamedTName))
4590 { # rename unnamed fields to unnamed0, unnamed1, ...
4591 $StructMembName = "unnamed".($UnnamedPos++);
4592 }
4593 }
4594 }
4595 if(not $StructMembName)
4596 { # unnamed fields and base classes
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04004597 $TypeMembInfoId = getNextElem($TypeMembInfoId);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004598 next;
4599 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04004600 my $MembTypeId = getTreeAttr_Type($TypeMembInfoId);
4601 if(defined $MissedTypedef{$Version}{$MembTypeId})
4602 {
4603 if(my $AddedTid = $MissedTypedef{$Version}{$MembTypeId}{"Tid"}) {
4604 $MembTypeId = $AddedTid;
4605 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004606 }
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04004607 $TypeAttr->{"Memb"}{$Pos}{"type"} = $MembTypeId;
4608 $TypeAttr->{"Memb"}{$Pos}{"name"} = $StructMembName;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004609 if((my $Access = getTreeAccess($TypeMembInfoId)) ne "public")
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04004610 { # marked only protected and private, public by default
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04004611 $TypeAttr->{"Memb"}{$Pos}{"access"} = $Access;
4612 }
4613 if($MInfo=~/spec:\s*mutable /)
4614 { # mutable fields
4615 $TypeAttr->{"Memb"}{$Pos}{"mutable"} = 1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004616 }
4617 if(my $BFSize = getStructMembBitFieldSize($TypeMembInfoId)) {
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04004618 $TypeAttr->{"Memb"}{$Pos}{"bitfield"} = $BFSize;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004619 }
4620 else
4621 { # set alignment for non-bit fields
4622 # alignment for bitfields is always equal to 1 bit
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04004623 if(my $Algn = getAlgn($TypeMembInfoId)) {
4624 $TypeAttr->{"Memb"}{$Pos}{"algn"} = $Algn/$BYTE_SIZE;
4625 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004626 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04004627 $TypeMembInfoId = getNextElem($TypeMembInfoId);
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04004628 $Pos += 1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004629 }
4630 }
4631}
4632
4633sub setFuncParams($)
4634{
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04004635 my $InfoId = $_[0];
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04004636 my $ParamInfoId = getTreeAttr_Args($InfoId);
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04004637 if(getFuncType($InfoId) eq "Method")
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004638 { # check type of "this" pointer
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04004639 my $ObjectTypeId = getTreeAttr_Type($ParamInfoId);
4640 if(my $ObjectName = $TypeInfo{$Version}{$ObjectTypeId}{"Name"})
Andrey Ponomarenko85043792012-05-14 16:48:07 +04004641 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04004642 if($ObjectName=~/\bconst(| volatile)\*const\b/) {
Andrey Ponomarenko85043792012-05-14 16:48:07 +04004643 $SymbolInfo{$Version}{$InfoId}{"Const"} = 1;
4644 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04004645 if($ObjectName=~/\bvolatile\b/) {
Andrey Ponomarenko85043792012-05-14 16:48:07 +04004646 $SymbolInfo{$Version}{$InfoId}{"Volatile"} = 1;
4647 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004648 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +04004649 else
4650 { # skip
4651 return 1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004652 }
4653 $ParamInfoId = getNextElem($ParamInfoId);
4654 }
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04004655 my ($Pos, $Vtt_Pos) = (0, -1);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004656 while($ParamInfoId)
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04004657 { # formal args
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04004658 my $ParamTypeId = getTreeAttr_Type($ParamInfoId);
4659 my $ParamName = getTreeStr(getTreeAttr_Name($ParamInfoId));
4660 if(not $ParamName)
4661 { # unnamed
4662 $ParamName = "p".($Pos+1);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004663 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04004664 if(defined $MissedTypedef{$Version}{$ParamTypeId})
4665 {
4666 if(my $AddedTid = $MissedTypedef{$Version}{$ParamTypeId}{"Tid"}) {
4667 $ParamTypeId = $AddedTid;
4668 }
4669 }
4670 my $PType = $TypeInfo{$Version}{$ParamTypeId}{"Type"};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004671 if(not $PType or $PType eq "Unknown") {
4672 return 1;
4673 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04004674 my $PTName = $TypeInfo{$Version}{$ParamTypeId}{"Name"};
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04004675 if(not $PTName) {
4676 return 1;
4677 }
4678 if($PTName eq "void") {
4679 last;
4680 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004681 if($ParamName eq "__vtt_parm"
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04004682 and $TypeInfo{$Version}{$ParamTypeId}{"Name"} eq "void const**")
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004683 {
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04004684 $Vtt_Pos = $Pos;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004685 $ParamInfoId = getNextElem($ParamInfoId);
4686 next;
4687 }
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04004688 $SymbolInfo{$Version}{$InfoId}{"Param"}{$Pos}{"type"} = $ParamTypeId;
4689 $SymbolInfo{$Version}{$InfoId}{"Param"}{$Pos}{"name"} = $ParamName;
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04004690 if(my $Algn = getAlgn($ParamInfoId)) {
4691 $SymbolInfo{$Version}{$InfoId}{"Param"}{$Pos}{"algn"} = $Algn/$BYTE_SIZE;
4692 }
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04004693 if(not $SymbolInfo{$Version}{$InfoId}{"Param"}{$Pos}{"name"}) {
4694 $SymbolInfo{$Version}{$InfoId}{"Param"}{$Pos}{"name"} = "p".($Pos+1);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004695 }
4696 if($LibInfo{$Version}{"info"}{$ParamInfoId}=~/spec:\s*register /)
4697 { # foo(register type arg)
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04004698 $SymbolInfo{$Version}{$InfoId}{"Param"}{$Pos}{"reg"} = 1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004699 }
4700 $ParamInfoId = getNextElem($ParamInfoId);
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04004701 $Pos += 1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004702 }
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04004703 if(setFuncArgs($InfoId, $Vtt_Pos)) {
4704 $SymbolInfo{$Version}{$InfoId}{"Param"}{$Pos}{"type"} = -1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004705 }
4706 return 0;
4707}
4708
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04004709sub setFuncArgs($$)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004710{
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04004711 my ($InfoId, $Vtt_Pos) = @_;
4712 my $FuncTypeId = getFuncTypeId($InfoId);
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04004713 my $ParamListElemId = getTreeAttr_Prms($FuncTypeId);
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04004714 if(getFuncType($InfoId) eq "Method") {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004715 $ParamListElemId = getNextElem($ParamListElemId);
4716 }
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04004717 if(not $ParamListElemId)
4718 { # foo(...)
4719 return 1;
4720 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004721 my $HaveVoid = 0;
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04004722 my $Pos = 0;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004723 while($ParamListElemId)
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04004724 { # actual params: may differ from formal args
4725 # formal int*const
4726 # actual: int*
4727 if($Vtt_Pos!=-1 and $Pos==$Vtt_Pos)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004728 {
4729 $Vtt_Pos=-1;
4730 $ParamListElemId = getNextElem($ParamListElemId);
4731 next;
4732 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04004733 my $ParamTypeId = getTreeAttr_Valu($ParamListElemId);
4734 if($TypeInfo{$Version}{$ParamTypeId}{"Name"} eq "void")
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04004735 {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004736 $HaveVoid = 1;
4737 last;
4738 }
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04004739 elsif(not defined $SymbolInfo{$Version}{$InfoId}{"Param"}{$Pos}{"type"})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004740 {
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04004741 $SymbolInfo{$Version}{$InfoId}{"Param"}{$Pos}{"type"} = $ParamTypeId;
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04004742 if(not $SymbolInfo{$Version}{$InfoId}{"Param"}{$Pos}{"name"})
4743 { # unnamed
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04004744 $SymbolInfo{$Version}{$InfoId}{"Param"}{$Pos}{"name"} = "p".($Pos+1);
4745 }
4746 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04004747 if(my $PurpId = getTreeAttr_Purp($ParamListElemId))
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04004748 { # default arguments
4749 if(my $PurpType = $LibInfo{$Version}{"info_type"}{$PurpId}) {
4750 $SymbolInfo{$Version}{$InfoId}{"Param"}{$Pos}{"default"} = getInitVal($PurpId, $ParamTypeId);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004751 }
4752 }
4753 $ParamListElemId = getNextElem($ParamListElemId);
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04004754 $Pos += 1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004755 }
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04004756 return ($Pos>=1 and not $HaveVoid);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004757}
4758
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04004759sub getTreeAttr_Chan($)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004760{
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04004761 if($_[0] and my $Info = $LibInfo{$Version}{"info"}{$_[0]})
4762 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04004763 if($Info=~/chan[ ]*:[ ]*@(\d+) /) {
4764 return $1;
4765 }
4766 }
4767 return "";
4768}
4769
4770sub getTreeAttr_Chain($)
4771{
4772 if($_[0] and my $Info = $LibInfo{$Version}{"info"}{$_[0]})
4773 {
4774 if($Info=~/chain[ ]*:[ ]*@(\d+) /) {
4775 return $1;
4776 }
4777 }
4778 return "";
4779}
4780
4781sub getTreeAttr_Scpe($)
4782{
4783 if($_[0] and my $Info = $LibInfo{$Version}{"info"}{$_[0]})
4784 {
4785 if($Info=~/scpe[ ]*:[ ]*@(\d+) /) {
4786 return $1;
4787 }
4788 }
4789 return "";
4790}
4791
4792sub getTreeAttr_Type($)
4793{
4794 if($_[0] and my $Info = $LibInfo{$Version}{"info"}{$_[0]})
4795 {
4796 if($Info=~/type[ ]*:[ ]*@(\d+) /) {
4797 return $1;
4798 }
4799 }
4800 return "";
4801}
4802
4803sub getTreeAttr_Name($)
4804{
4805 if($_[0] and my $Info = $LibInfo{$Version}{"info"}{$_[0]})
4806 {
4807 if($Info=~/name[ ]*:[ ]*@(\d+) /) {
4808 return $1;
4809 }
4810 }
4811 return "";
4812}
4813
4814sub getTreeAttr_Mngl($)
4815{
4816 if($_[0] and my $Info = $LibInfo{$Version}{"info"}{$_[0]})
4817 {
4818 if($Info=~/mngl[ ]*:[ ]*@(\d+) /) {
4819 return $1;
4820 }
4821 }
4822 return "";
4823}
4824
4825sub getTreeAttr_Prms($)
4826{
4827 if($_[0] and my $Info = $LibInfo{$Version}{"info"}{$_[0]})
4828 {
4829 if($Info=~/prms[ ]*:[ ]*@(\d+) /) {
4830 return $1;
4831 }
4832 }
4833 return "";
4834}
4835
4836sub getTreeAttr_Fncs($)
4837{
4838 if($_[0] and my $Info = $LibInfo{$Version}{"info"}{$_[0]})
4839 {
4840 if($Info=~/fncs[ ]*:[ ]*@(\d+) /) {
4841 return $1;
4842 }
4843 }
4844 return "";
4845}
4846
4847sub getTreeAttr_Csts($)
4848{
4849 if($_[0] and my $Info = $LibInfo{$Version}{"info"}{$_[0]})
4850 {
4851 if($Info=~/csts[ ]*:[ ]*@(\d+) /) {
4852 return $1;
4853 }
4854 }
4855 return "";
4856}
4857
4858sub getTreeAttr_Purp($)
4859{
4860 if($_[0] and my $Info = $LibInfo{$Version}{"info"}{$_[0]})
4861 {
4862 if($Info=~/purp[ ]*:[ ]*@(\d+) /) {
4863 return $1;
4864 }
4865 }
4866 return "";
4867}
4868
4869sub getTreeAttr_Valu($)
4870{
4871 if($_[0] and my $Info = $LibInfo{$Version}{"info"}{$_[0]})
4872 {
4873 if($Info=~/valu[ ]*:[ ]*@(\d+) /) {
4874 return $1;
4875 }
4876 }
4877 return "";
4878}
4879
4880sub getTreeAttr_Flds($)
4881{
4882 if($_[0] and my $Info = $LibInfo{$Version}{"info"}{$_[0]})
4883 {
4884 if($Info=~/flds[ ]*:[ ]*@(\d+) /) {
4885 return $1;
4886 }
4887 }
4888 return "";
4889}
4890
4891sub getTreeAttr_Args($)
4892{
4893 if($_[0] and my $Info = $LibInfo{$Version}{"info"}{$_[0]})
4894 {
4895 if($Info=~/args[ ]*:[ ]*@(\d+) /) {
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04004896 return $1;
4897 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004898 }
4899 return "";
4900}
4901
4902sub getTreeValue($)
4903{
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04004904 if($_[0] and my $Info = $LibInfo{$Version}{"info"}{$_[0]})
4905 {
4906 if($Info=~/low[ ]*:[ ]*([^ ]+) /) {
4907 return $1;
4908 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004909 }
4910 return "";
4911}
4912
4913sub getTreeAccess($)
4914{
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04004915 if($_[0] and my $Info = $LibInfo{$Version}{"info"}{$_[0]})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004916 {
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04004917 if($Info=~/accs[ ]*:[ ]*([a-zA-Z]+) /)
4918 {
4919 my $Access = $1;
4920 if($Access eq "prot") {
4921 return "protected";
4922 }
4923 elsif($Access eq "priv") {
4924 return "private";
4925 }
4926 }
4927 elsif($Info=~/ protected /)
4928 { # support for old GCC versions
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004929 return "protected";
4930 }
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04004931 elsif($Info=~/ private /)
4932 { # support for old GCC versions
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004933 return "private";
4934 }
4935 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004936 return "public";
4937}
4938
4939sub setFuncAccess($)
4940{
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04004941 my $Access = getTreeAccess($_[0]);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004942 if($Access eq "protected") {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04004943 $SymbolInfo{$Version}{$_[0]}{"Protected"} = 1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004944 }
4945 elsif($Access eq "private") {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04004946 $SymbolInfo{$Version}{$_[0]}{"Private"} = 1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004947 }
4948}
4949
4950sub setTypeAccess($$)
4951{
4952 my ($TypeId, $TypeAttr) = @_;
4953 my $Access = getTreeAccess($TypeId);
4954 if($Access eq "protected") {
4955 $TypeAttr->{"Protected"} = 1;
4956 }
4957 elsif($Access eq "private") {
4958 $TypeAttr->{"Private"} = 1;
4959 }
4960}
4961
4962sub setFuncKind($)
4963{
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04004964 if($_[0] and my $Info = $LibInfo{$Version}{"info"}{$_[0]})
4965 {
4966 if($Info=~/pseudo tmpl/) {
4967 $SymbolInfo{$Version}{$_[0]}{"PseudoTemplate"} = 1;
4968 }
4969 elsif($Info=~/ constructor /) {
4970 $SymbolInfo{$Version}{$_[0]}{"Constructor"} = 1;
4971 }
4972 elsif($Info=~/ destructor /) {
4973 $SymbolInfo{$Version}{$_[0]}{"Destructor"} = 1;
4974 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004975 }
4976}
4977
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04004978sub getVirtSpec($)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004979{
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04004980 if($_[0] and my $Info = $LibInfo{$Version}{"info"}{$_[0]})
4981 {
4982 if($Info=~/spec[ ]*:[ ]*pure /) {
4983 return "PureVirt";
4984 }
4985 elsif($Info=~/spec[ ]*:[ ]*virt /) {
4986 return "Virt";
4987 }
4988 elsif($Info=~/ pure\s+virtual /)
4989 { # support for old GCC versions
4990 return "PureVirt";
4991 }
4992 elsif($Info=~/ virtual /)
4993 { # support for old GCC versions
4994 return "Virt";
4995 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004996 }
4997 return "";
4998}
4999
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005000sub getFuncLink($)
5001{
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04005002 if($_[0] and my $Info = $LibInfo{$Version}{"info"}{$_[0]})
5003 {
5004 if($Info=~/link[ ]*:[ ]*static /) {
5005 return "Static";
5006 }
5007 elsif($Info=~/link[ ]*:[ ]*([a-zA-Z]+) /) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005008 return $1;
5009 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005010 }
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04005011 return "";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005012}
5013
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005014sub get_IntNameSpace($$)
5015{
5016 my ($Interface, $LibVersion) = @_;
5017 return "" if(not $Interface or not $LibVersion);
5018 if(defined $Cache{"get_IntNameSpace"}{$Interface}{$LibVersion}) {
5019 return $Cache{"get_IntNameSpace"}{$Interface}{$LibVersion};
5020 }
5021 my $Signature = get_Signature($Interface, $LibVersion);
5022 if($Signature=~/\:\:/)
5023 {
5024 my $FounNameSpace = 0;
5025 foreach my $NameSpace (sort {get_depth($b)<=>get_depth($a)} keys(%{$NestedNameSpaces{$LibVersion}}))
5026 {
5027 if($Signature=~/(\A|\s+for\s+)\Q$NameSpace\E\:\:/) {
5028 return ($Cache{"get_IntNameSpace"}{$Interface}{$LibVersion} = $NameSpace);
5029 }
5030 }
5031 }
5032 else {
5033 return ($Cache{"get_IntNameSpace"}{$Interface}{$LibVersion} = "");
5034 }
5035}
5036
5037sub parse_TypeNameSpace($$)
5038{
5039 my ($TypeName, $LibVersion) = @_;
5040 return "" if(not $TypeName or not $LibVersion);
5041 if(defined $Cache{"parse_TypeNameSpace"}{$TypeName}{$LibVersion}) {
5042 return $Cache{"parse_TypeNameSpace"}{$TypeName}{$LibVersion};
5043 }
5044 if($TypeName=~/\:\:/)
5045 {
5046 my $FounNameSpace = 0;
5047 foreach my $NameSpace (sort {get_depth($b)<=>get_depth($a)} keys(%{$NestedNameSpaces{$LibVersion}}))
5048 {
5049 if($TypeName=~/\A\Q$NameSpace\E\:\:/) {
5050 return ($Cache{"parse_TypeNameSpace"}{$TypeName}{$LibVersion} = $NameSpace);
5051 }
5052 }
5053 }
5054 else {
5055 return ($Cache{"parse_TypeNameSpace"}{$TypeName}{$LibVersion} = "");
5056 }
5057}
5058
5059sub getNameSpace($)
5060{
5061 my $TypeInfoId = $_[0];
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04005062 if(my $NSInfoId = getTreeAttr_Scpe($TypeInfoId))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005063 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04005064 if(my $InfoType = $LibInfo{$Version}{"info_type"}{$NSInfoId})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005065 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04005066 if($InfoType eq "namespace_decl")
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04005067 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04005068 if($LibInfo{$Version}{"info"}{$NSInfoId}=~/name[ ]*:[ ]*@(\d+) /)
5069 {
5070 my $NameSpace = getTreeStr($1);
5071 if($NameSpace eq "::")
5072 { # global namespace
5073 return "";
5074 }
5075 if(my $BaseNameSpace = getNameSpace($NSInfoId)) {
5076 $NameSpace = $BaseNameSpace."::".$NameSpace;
5077 }
5078 $NestedNameSpaces{$Version}{$NameSpace} = 1;
5079 return $NameSpace;
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04005080 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04005081 else {
5082 return "";
5083 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005084 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04005085 elsif($InfoType eq "record_type")
5086 { # inside data type
5087 my ($Name, $NameNS) = getTrivialName(getTypeDeclId($NSInfoId), $NSInfoId);
5088 return $Name;
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04005089 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005090 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005091 }
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04005092 return "";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005093}
5094
5095sub getNameSpaceId($)
5096{
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04005097 if($_[0] and my $Info = $LibInfo{$Version}{"info"}{$_[0]})
5098 {
5099 if($Info=~/scpe[ ]*:[ ]*\@(\d+)/) {
5100 return $1;
5101 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005102 }
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04005103 return "";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005104}
5105
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005106sub getStructMembName($)
5107{
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04005108 if($_[0] and my $Info = $LibInfo{$Version}{"info"}{$_[0]})
5109 {
5110 if($Info=~/name[ ]*:[ ]*\@(\d+)/) {
5111 return getTreeStr($1);
5112 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005113 }
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04005114 return "";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005115}
5116
5117sub getEnumMembVal($)
5118{
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04005119 if($_[0] and my $Info = $LibInfo{$Version}{"info"}{$_[0]})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005120 {
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04005121 if($Info=~/valu[ ]*:[ ]*\@(\d+)/)
5122 {
5123 if(my $VInfo = $LibInfo{$Version}{"info"}{$1})
5124 {
5125 if($VInfo=~/cnst[ ]*:[ ]*\@(\d+)/)
5126 { # in newer versions of GCC the value is in the "const_decl->cnst" node
5127 return getTreeValue($1);
5128 }
5129 else
5130 { # some old versions of GCC (3.3) have the value in the "integer_cst" node
5131 return getTreeValue($1);
5132 }
5133 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005134 }
5135 }
5136 return "";
5137}
5138
5139sub getSize($)
5140{
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04005141 if($_[0] and my $Info = $LibInfo{$Version}{"info"}{$_[0]})
5142 {
5143 if($Info=~/size[ ]*:[ ]*\@(\d+)/) {
5144 return getTreeValue($1);
5145 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005146 }
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04005147 return 0;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005148}
5149
5150sub getAlgn($)
5151{
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04005152 if($_[0] and my $Info = $LibInfo{$Version}{"info"}{$_[0]})
5153 {
5154 if($Info=~/algn[ ]*:[ ]*(\d+) /) {
5155 return $1;
5156 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005157 }
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04005158 return "";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005159}
5160
5161sub getStructMembBitFieldSize($)
5162{
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04005163 if($_[0] and my $Info = $LibInfo{$Version}{"info"}{$_[0]})
5164 {
5165 if($Info=~/ bitfield /) {
5166 return getSize($_[0]);
5167 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005168 }
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04005169 return 0;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005170}
5171
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04005172sub getNextElem($)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005173{
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04005174 if(my $Chan = getTreeAttr_Chan($_[0])) {
5175 return $Chan;
5176 }
5177 elsif(my $Chain = getTreeAttr_Chain($_[0])) {
5178 return $Chain;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005179 }
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04005180 return "";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005181}
5182
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04005183sub registerHeader($$)
5184{ # input: absolute path of header, relative path or name
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005185 my ($Header, $LibVersion) = @_;
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04005186 if(not $Header) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005187 return "";
5188 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04005189 if(is_abs($Header) and not -f $Header)
5190 { # incorrect absolute path
5191 exitStatus("Access_Error", "can't access \'$Header\'");
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005192 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04005193 if(skipHeader($Header, $LibVersion))
5194 { # skip
5195 return "";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005196 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04005197 if(my $Header_Path = identifyHeader($Header, $LibVersion))
5198 {
5199 detect_header_includes($Header_Path, $LibVersion);
5200
5201 if(my $RHeader_Path = $Header_ErrorRedirect{$LibVersion}{$Header_Path})
5202 { # redirect
5203 if($Registered_Headers{$LibVersion}{$RHeader_Path}{"Identity"}
5204 or skipHeader($RHeader_Path, $LibVersion))
5205 { # skip
5206 return "";
5207 }
5208 $Header_Path = $RHeader_Path;
5209 }
5210 elsif($Header_ShouldNotBeUsed{$LibVersion}{$Header_Path})
5211 { # skip
5212 return "";
5213 }
5214
5215 if(my $HName = get_filename($Header_Path))
5216 { # register
5217 $Registered_Headers{$LibVersion}{$Header_Path}{"Identity"} = $HName;
5218 $HeaderName_Paths{$LibVersion}{$HName}{$Header_Path} = 1;
5219 }
5220
5221 if(($Header=~/\.(\w+)\Z/ and $1 ne "h")
5222 or $Header!~/\.(\w+)\Z/)
5223 { # hpp, hh
5224 setLanguage($LibVersion, "C++");
5225 }
5226
5227 if($CheckHeadersOnly
5228 and $Header=~/(\A|\/)c\+\+(\/|\Z)/)
5229 { # /usr/include/c++/4.6.1/...
5230 $STDCXX_TESTING = 1;
5231 }
5232
5233 return $Header_Path;
5234 }
5235 return "";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005236}
5237
5238sub register_directory($$$)
5239{
5240 my ($Dir, $WithDeps, $LibVersion) = @_;
5241 $Dir=~s/[\/\\]+\Z//g;
5242 return if(not $LibVersion or not $Dir or not -d $Dir);
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04005243 return if(skipHeader($Dir, $LibVersion));
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005244 $Dir = get_abs_path($Dir);
5245 my $Mode = "All";
Andrey Ponomarenko85043792012-05-14 16:48:07 +04005246 if($WithDeps)
5247 {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005248 if($RegisteredDirs{$LibVersion}{$Dir}{1}) {
5249 return;
5250 }
5251 elsif($RegisteredDirs{$LibVersion}{$Dir}{0}) {
5252 $Mode = "DepsOnly";
5253 }
5254 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +04005255 else
5256 {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005257 if($RegisteredDirs{$LibVersion}{$Dir}{1}
5258 or $RegisteredDirs{$LibVersion}{$Dir}{0}) {
5259 return;
5260 }
5261 }
5262 $Header_Dependency{$LibVersion}{$Dir} = 1;
5263 $RegisteredDirs{$LibVersion}{$Dir}{$WithDeps} = 1;
5264 if($Mode eq "DepsOnly")
5265 {
5266 foreach my $Path (cmd_find($Dir,"d","","")) {
5267 $Header_Dependency{$LibVersion}{$Path} = 1;
5268 }
5269 return;
5270 }
5271 foreach my $Path (sort {length($b)<=>length($a)} cmd_find($Dir,"f","",""))
5272 {
5273 if($WithDeps)
5274 {
5275 my $SubDir = $Path;
5276 while(($SubDir = get_dirname($SubDir)) ne $Dir)
5277 { # register all sub directories
5278 $Header_Dependency{$LibVersion}{$SubDir} = 1;
5279 }
5280 }
5281 next if(is_not_header($Path));
5282 next if(ignore_path($Path));
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04005283 next if(skipHeader($Path, $LibVersion));
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005284 # Neighbors
5285 foreach my $Part (get_path_prefixes($Path)) {
5286 $Include_Neighbors{$LibVersion}{$Part} = $Path;
5287 }
5288 }
5289 if(get_filename($Dir) eq "include")
5290 { # search for "lib/include/" directory
5291 my $LibDir = $Dir;
5292 if($LibDir=~s/([\/\\])include\Z/$1lib/g and -d $LibDir) {
5293 register_directory($LibDir, $WithDeps, $LibVersion);
5294 }
5295 }
5296}
5297
5298sub parse_redirect($$$)
5299{
5300 my ($Content, $Path, $LibVersion) = @_;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005301 my @Errors = ();
5302 while($Content=~s/#\s*error\s+([^\n]+?)\s*(\n|\Z)//) {
5303 push(@Errors, $1);
5304 }
5305 my $Redirect = "";
5306 foreach (@Errors)
5307 {
5308 s/\s{2,}/ /g;
5309 if(/(only|must\ include
5310 |update\ to\ include
5311 |replaced\ with
5312 |replaced\ by|renamed\ to
5313 |is\ in|use)\ (<[^<>]+>|[\w\-\/\\]+\.($HEADER_EXT))/ix)
5314 {
5315 $Redirect = $2;
5316 last;
5317 }
5318 elsif(/(include|use|is\ in)\ (<[^<>]+>|[\w\-\/\\]+\.($HEADER_EXT))\ instead/i)
5319 {
5320 $Redirect = $2;
5321 last;
5322 }
5323 elsif(/this\ header\ should\ not\ be\ used
5324 |programs\ should\ not\ directly\ include
5325 |you\ should\ not\ (include|be\ (including|using)\ this\ (file|header))
5326 |is\ not\ supported\ API\ for\ general\ use
5327 |do\ not\ use
5328 |should\ not\ be\ used
5329 |cannot\ be\ included\ directly/ix and not /\ from\ /i) {
5330 $Header_ShouldNotBeUsed{$LibVersion}{$Path} = 1;
5331 }
5332 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +04005333 if($Redirect)
5334 {
5335 $Redirect=~s/\A<//g;
5336 $Redirect=~s/>\Z//g;
5337 }
5338 return $Redirect;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005339}
5340
5341sub parse_includes($$)
5342{
5343 my ($Content, $Path) = @_;
5344 my %Includes = ();
5345 while($Content=~s/#([ \t]*)(include|include_next|import)([ \t]*)(<|")([^<>"]+)(>|")//)
Andrey Ponomarenko85043792012-05-14 16:48:07 +04005346 { # C/C++: include, Objective C/C++: import directive
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005347 my ($Header, $Method) = ($5, $4);
5348 $Header = path_format($Header, $OSgroup);
Andrey Ponomarenko85043792012-05-14 16:48:07 +04005349 if($Method eq "\"" or is_abs($Header))
5350 {
5351 if(-e joinPath(get_dirname($Path), $Header))
5352 { # relative path exists
5353 $Includes{$Header} = -1;
5354 }
5355 else
5356 { # include "..." that doesn't exist is equal to include <...>
5357 $Includes{$Header} = 2;
5358 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005359 }
5360 else {
5361 $Includes{$Header} = 1;
5362 }
5363 }
5364 return \%Includes;
5365}
5366
5367sub ignore_path($)
5368{
5369 my $Path = $_[0];
5370 if($Path=~/\~\Z/)
5371 {# skipping system backup files
5372 return 1;
5373 }
5374 if($Path=~/(\A|[\/\\]+)(\.(svn|git|bzr|hg)|CVS)([\/\\]+|\Z)/)
5375 {# skipping hidden .svn, .git, .bzr, .hg and CVS directories
5376 return 1;
5377 }
5378 return 0;
5379}
5380
5381sub sort_by_word($$)
5382{
5383 my ($ArrRef, $W) = @_;
5384 return if(length($W)<2);
5385 @{$ArrRef} = sort {get_filename($b)=~/\Q$W\E/i<=>get_filename($a)=~/\Q$W\E/i} @{$ArrRef};
5386}
5387
5388sub natural_sorting($$)
5389{
5390 my ($H1, $H2) = @_;
5391 $H1=~s/\.[a-z]+\Z//ig;
5392 $H2=~s/\.[a-z]+\Z//ig;
5393 my ($HDir1, $Hname1) = separate_path($H1);
5394 my ($HDir2, $Hname2) = separate_path($H2);
5395 my $Dirname1 = get_filename($HDir1);
5396 my $Dirname2 = get_filename($HDir2);
5397 if($H1 eq $H2) {
5398 return 0;
5399 }
5400 elsif($H1=~/\A\Q$H2\E/) {
5401 return 1;
5402 }
5403 elsif($H2=~/\A\Q$H1\E/) {
5404 return -1;
5405 }
5406 elsif($HDir1=~/\Q$Hname1\E/i
5407 and $HDir2!~/\Q$Hname2\E/i)
5408 {# include/glib-2.0/glib.h
5409 return -1;
5410 }
5411 elsif($HDir2=~/\Q$Hname2\E/i
5412 and $HDir1!~/\Q$Hname1\E/i)
5413 {# include/glib-2.0/glib.h
5414 return 1;
5415 }
5416 elsif($Hname1=~/\Q$Dirname1\E/i
5417 and $Hname2!~/\Q$Dirname2\E/i)
5418 {# include/hildon-thumbnail/hildon-thumbnail-factory.h
5419 return -1;
5420 }
5421 elsif($Hname2=~/\Q$Dirname2\E/i
5422 and $Hname1!~/\Q$Dirname1\E/i)
5423 {# include/hildon-thumbnail/hildon-thumbnail-factory.h
5424 return 1;
5425 }
5426 elsif($Hname1=~/(config|lib)/i
5427 and $Hname2!~/(config|lib)/i)
5428 {# include/alsa/asoundlib.h
5429 return -1;
5430 }
5431 elsif($Hname2=~/(config|lib)/i
5432 and $Hname1!~/(config|lib)/i)
5433 {# include/alsa/asoundlib.h
5434 return 1;
5435 }
5436 elsif(checkRelevance($H1)
5437 and not checkRelevance($H2))
5438 {# libebook/e-book.h
5439 return -1;
5440 }
5441 elsif(checkRelevance($H2)
5442 and not checkRelevance($H1))
5443 {# libebook/e-book.h
5444 return 1;
5445 }
5446 else {
5447 return (lc($H1) cmp lc($H2));
5448 }
5449}
5450
5451sub searchForHeaders($)
5452{
5453 my $LibVersion = $_[0];
5454 # gcc standard include paths
5455 find_gcc_cxx_headers($LibVersion);
5456 # processing header paths
5457 foreach my $Path (keys(%{$Descriptor{$LibVersion}{"IncludePaths"}}),
5458 keys(%{$Descriptor{$LibVersion}{"AddIncludePaths"}}))
5459 {
5460 my $IPath = $Path;
5461 if(not -e $Path) {
5462 exitStatus("Access_Error", "can't access \'$Path\'");
5463 }
5464 elsif(-f $Path) {
5465 exitStatus("Access_Error", "\'$Path\' - not a directory");
5466 }
5467 elsif(-d $Path)
5468 {
5469 $Path = get_abs_path($Path);
5470 register_directory($Path, 0, $LibVersion);
5471 if($Descriptor{$LibVersion}{"AddIncludePaths"}{$IPath}) {
5472 $Add_Include_Paths{$LibVersion}{$Path} = 1;
5473 }
5474 else {
5475 $Include_Paths{$LibVersion}{$Path} = 1;
5476 }
5477 }
5478 }
5479 if(keys(%{$Include_Paths{$LibVersion}})) {
5480 $INC_PATH_AUTODETECT{$LibVersion} = 0;
5481 }
5482 # registering directories
5483 foreach my $Path (split(/\s*\n\s*/, $Descriptor{$LibVersion}{"Headers"}))
5484 {
5485 next if(not -e $Path);
5486 $Path = get_abs_path($Path);
5487 $Path = path_format($Path, $OSgroup);
5488 if(-d $Path) {
5489 register_directory($Path, 1, $LibVersion);
5490 }
5491 elsif(-f $Path)
5492 {
5493 my $Dir = get_dirname($Path);
5494 if(not $SystemPaths{"include"}{$Dir}
5495 and not $LocalIncludes{$Dir})
5496 {
5497 register_directory($Dir, 1, $LibVersion);
5498 if(my $OutDir = get_dirname($Dir))
5499 { # registering the outer directory
5500 if(not $SystemPaths{"include"}{$OutDir}
5501 and not $LocalIncludes{$OutDir}) {
5502 register_directory($OutDir, 0, $LibVersion);
5503 }
5504 }
5505 }
5506 }
5507 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +04005508
5509 # clean memory
5510 %RegisteredDirs = ();
5511
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005512 # registering headers
5513 my $Position = 0;
5514 foreach my $Dest (split(/\s*\n\s*/, $Descriptor{$LibVersion}{"Headers"}))
5515 {
5516 if(is_abs($Dest) and not -e $Dest) {
5517 exitStatus("Access_Error", "can't access \'$Dest\'");
5518 }
5519 $Dest = path_format($Dest, $OSgroup);
5520 if(is_header($Dest, 1, $LibVersion))
5521 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04005522 if(my $HPath = registerHeader($Dest, $LibVersion)) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005523 $Registered_Headers{$LibVersion}{$HPath}{"Pos"} = $Position++;
5524 }
5525 }
5526 elsif(-d $Dest)
5527 {
5528 my @Registered = ();
5529 foreach my $Path (cmd_find($Dest,"f","",""))
5530 {
5531 next if(ignore_path($Path));
5532 next if(not is_header($Path, 0, $LibVersion));
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04005533 if(my $HPath = registerHeader($Path, $LibVersion)) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005534 push(@Registered, $HPath);
5535 }
5536 }
5537 @Registered = sort {natural_sorting($a, $b)} @Registered;
5538 sort_by_word(\@Registered, $TargetLibraryShortName);
5539 foreach my $Path (@Registered) {
5540 $Registered_Headers{$LibVersion}{$Path}{"Pos"} = $Position++;
5541 }
5542 }
5543 else {
5544 exitStatus("Access_Error", "can't identify \'$Dest\' as a header file");
5545 }
5546 }
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04005547 if(my $HList = $Descriptor{$LibVersion}{"IncludePreamble"})
5548 { # preparing preamble headers
5549 my $PPos=0;
5550 foreach my $Header (split(/\s*\n\s*/, $HList))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005551 {
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04005552 if(is_abs($Header) and not -f $Header) {
5553 exitStatus("Access_Error", "can't access file \'$Header\'");
5554 }
5555 $Header = path_format($Header, $OSgroup);
5556 if(my $Header_Path = is_header($Header, 1, $LibVersion))
5557 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04005558 next if(skipHeader($Header_Path, $LibVersion));
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04005559 $Include_Preamble{$LibVersion}{$Header_Path}{"Position"} = $PPos++;
5560 }
5561 else {
5562 exitStatus("Access_Error", "can't identify \'$Header\' as a header file");
5563 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005564 }
5565 }
5566 foreach my $Header_Name (keys(%{$HeaderName_Paths{$LibVersion}}))
5567 { # set relative paths (for duplicates)
5568 if(keys(%{$HeaderName_Paths{$LibVersion}{$Header_Name}})>=2)
5569 { # search for duplicates
5570 my $FirstPath = (keys(%{$HeaderName_Paths{$LibVersion}{$Header_Name}}))[0];
5571 my $Prefix = get_dirname($FirstPath);
5572 while($Prefix=~/\A(.+)[\/\\]+[^\/\\]+\Z/)
5573 { # detect a shortest distinguishing prefix
5574 my $NewPrefix = $1;
5575 my %Identity = ();
5576 foreach my $Path (keys(%{$HeaderName_Paths{$LibVersion}{$Header_Name}}))
5577 {
5578 if($Path=~/\A\Q$Prefix\E[\/\\]+(.*)\Z/) {
5579 $Identity{$Path} = $1;
5580 }
5581 }
5582 if(keys(%Identity)==keys(%{$HeaderName_Paths{$LibVersion}{$Header_Name}}))
5583 { # all names are differend with current prefix
5584 foreach my $Path (keys(%{$HeaderName_Paths{$LibVersion}{$Header_Name}})) {
5585 $Registered_Headers{$LibVersion}{$Path}{"Identity"} = $Identity{$Path};
5586 }
5587 last;
5588 }
5589 $Prefix = $NewPrefix; # increase prefix
5590 }
5591 }
5592 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +04005593
5594 # clean memory
5595 %HeaderName_Paths = ();
5596
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005597 foreach my $HeaderName (keys(%{$Include_Order{$LibVersion}}))
5598 { # ordering headers according to descriptor
5599 my $PairName=$Include_Order{$LibVersion}{$HeaderName};
5600 my ($Pos, $PairPos) = (-1, -1);
5601 my ($Path, $PairPath) = ();
5602 my @Paths = keys(%{$Registered_Headers{$LibVersion}});
5603 @Paths = sort {int($Registered_Headers{$LibVersion}{$a}{"Pos"})<=>int($Registered_Headers{$LibVersion}{$b}{"Pos"})} @Paths;
5604 foreach my $Header_Path (@Paths)
5605 {
5606 if(get_filename($Header_Path) eq $PairName)
5607 {
5608 $PairPos = $Registered_Headers{$LibVersion}{$Header_Path}{"Pos"};
5609 $PairPath = $Header_Path;
5610 }
5611 if(get_filename($Header_Path) eq $HeaderName)
5612 {
5613 $Pos = $Registered_Headers{$LibVersion}{$Header_Path}{"Pos"};
5614 $Path = $Header_Path;
5615 }
5616 }
5617 if($PairPos!=-1 and $Pos!=-1
5618 and int($PairPos)<int($Pos))
5619 {
5620 my %Tmp = %{$Registered_Headers{$LibVersion}{$Path}};
5621 %{$Registered_Headers{$LibVersion}{$Path}} = %{$Registered_Headers{$LibVersion}{$PairPath}};
5622 %{$Registered_Headers{$LibVersion}{$PairPath}} = %Tmp;
5623 }
5624 }
5625 if(not keys(%{$Registered_Headers{$LibVersion}})) {
5626 exitStatus("Error", "header files are not found in the ".$Descriptor{$LibVersion}{"Version"});
5627 }
5628}
5629
5630sub detect_real_includes($$)
5631{
5632 my ($AbsPath, $LibVersion) = @_;
5633 return () if(not $LibVersion or not $AbsPath or not -e $AbsPath);
5634 if($Cache{"detect_real_includes"}{$LibVersion}{$AbsPath}
5635 or keys(%{$RecursiveIncludes{$LibVersion}{$AbsPath}})) {
5636 return keys(%{$RecursiveIncludes{$LibVersion}{$AbsPath}});
5637 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +04005638 $Cache{"detect_real_includes"}{$LibVersion}{$AbsPath}=1;
5639
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005640 my $Path = callPreprocessor($AbsPath, "", $LibVersion);
5641 return () if(not $Path);
5642 open(PREPROC, $Path);
5643 while(<PREPROC>)
5644 {
5645 if(/#\s+\d+\s+"([^"]+)"[\s\d]*\n/)
5646 {
5647 my $Include = path_format($1, $OSgroup);
5648 if($Include=~/\<(built\-in|internal|command(\-|\s)line)\>|\A\./) {
5649 next;
5650 }
5651 if($Include eq $AbsPath) {
5652 next;
5653 }
5654 $RecursiveIncludes{$LibVersion}{$AbsPath}{$Include} = 1;
5655 }
5656 }
5657 close(PREPROC);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005658 return keys(%{$RecursiveIncludes{$LibVersion}{$AbsPath}});
5659}
5660
5661sub detect_header_includes($$)
5662{
5663 my ($Path, $LibVersion) = @_;
Andrey Ponomarenko85043792012-05-14 16:48:07 +04005664 return if(not $LibVersion or not $Path);
5665 if(defined $Cache{"detect_header_includes"}{$LibVersion}{$Path}) {
5666 return;
5667 }
5668 $Cache{"detect_header_includes"}{$LibVersion}{$Path}=1;
5669
5670 if(not -e $Path) {
5671 return;
5672 }
5673
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005674 my $Content = readFile($Path);
Andrey Ponomarenko85043792012-05-14 16:48:07 +04005675 if(my $Redirect = parse_redirect($Content, $Path, $LibVersion))
5676 { # detect error directive in headers
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04005677 if(my $RedirectPath = identifyHeader($Redirect, $LibVersion))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005678 {
5679 if($RedirectPath=~/\/usr\/include\// and $Path!~/\/usr\/include\//) {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04005680 $RedirectPath = identifyHeader(get_filename($Redirect), $LibVersion);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005681 }
5682 if($RedirectPath ne $Path) {
5683 $Header_ErrorRedirect{$LibVersion}{$Path} = $RedirectPath;
5684 }
5685 }
5686 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +04005687 if(my $Inc = parse_includes($Content, $Path))
5688 {
5689 foreach my $Include (keys(%{$Inc}))
5690 { # detect includes
Andrey Ponomarenko85043792012-05-14 16:48:07 +04005691 $Header_Includes{$LibVersion}{$Path}{$Include} = $Inc->{$Include};
5692 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005693 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005694}
5695
5696sub simplify_path($)
5697{
5698 my $Path = $_[0];
5699 while($Path=~s&([\/\\])[^\/\\]+[\/\\]\.\.[\/\\]&$1&){};
5700 return $Path;
5701}
5702
5703sub fromLibc($)
5704{ # GLIBC header
5705 my $Path = $_[0];
5706 my ($Dir, $Name) = separate_path($Path);
5707 if(get_filename($Dir)=~/\A(include|libc)\Z/ and $GlibcHeader{$Name})
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04005708 { # /usr/include/{stdio, ...}.h
5709 # epoc32/include/libc/{stdio, ...}.h
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005710 return 1;
5711 }
5712 if(isLibcDir($Dir)) {
5713 return 1;
5714 }
5715 return 0;
5716}
5717
5718sub isLibcDir($)
5719{ # GLIBC directory
5720 my $Dir = $_[0];
5721 my ($OutDir, $Name) = separate_path($Dir);
5722 if(get_filename($OutDir)=~/\A(include|libc)\Z/
5723 and ($Name=~/\Aasm(|-.+)\Z/ or $GlibcDir{$Name}))
5724 { # /usr/include/{sys,bits,asm,asm-*}/*.h
5725 return 1;
5726 }
5727 return 0;
5728}
5729
5730sub detect_recursive_includes($$)
5731{
5732 my ($AbsPath, $LibVersion) = @_;
5733 return () if(not $AbsPath);
5734 if(isCyclical(\@RecurInclude, $AbsPath)) {
5735 return keys(%{$RecursiveIncludes{$LibVersion}{$AbsPath}});
5736 }
5737 my ($AbsDir, $Name) = separate_path($AbsPath);
5738 if(isLibcDir($AbsDir))
5739 { # GLIBC internals
5740 return ();
5741 }
5742 if(keys(%{$RecursiveIncludes{$LibVersion}{$AbsPath}})) {
5743 return keys(%{$RecursiveIncludes{$LibVersion}{$AbsPath}});
5744 }
5745 return () if($OSgroup ne "windows" and $Name=~/windows|win32|win64/i);
5746 return () if($MAIN_CPP_DIR and $AbsPath=~/\A\Q$MAIN_CPP_DIR\E/ and not $STDCXX_TESTING);
5747 push(@RecurInclude, $AbsPath);
5748 if($DefaultGccPaths{$AbsDir}
5749 or fromLibc($AbsPath))
5750 { # check "real" (non-"model") include paths
5751 my @Paths = detect_real_includes($AbsPath, $LibVersion);
5752 pop(@RecurInclude);
5753 return @Paths;
5754 }
5755 if(not keys(%{$Header_Includes{$LibVersion}{$AbsPath}})) {
5756 detect_header_includes($AbsPath, $LibVersion);
5757 }
5758 foreach my $Include (keys(%{$Header_Includes{$LibVersion}{$AbsPath}}))
5759 {
Andrey Ponomarenko85043792012-05-14 16:48:07 +04005760 my $IncType = $Header_Includes{$LibVersion}{$AbsPath}{$Include};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005761 my $HPath = "";
Andrey Ponomarenko85043792012-05-14 16:48:07 +04005762 if($IncType<0)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005763 { # for #include "..."
5764 my $Candidate = joinPath($AbsDir, $Include);
5765 if(-f $Candidate) {
5766 $HPath = simplify_path($Candidate);
5767 }
5768 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +04005769 elsif($IncType>0
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04005770 and $Include=~/[\/\\]/) # and not find_in_defaults($Include)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005771 { # search for the nearest header
5772 # QtCore/qabstractanimation.h includes <QtCore/qobject.h>
5773 my $Candidate = joinPath(get_dirname($AbsDir), $Include);
5774 if(-f $Candidate) {
5775 $HPath = $Candidate;
5776 }
5777 }
5778 if(not $HPath) {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04005779 $HPath = identifyHeader($Include, $LibVersion);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005780 }
5781 next if(not $HPath);
5782 if($HPath eq $AbsPath) {
5783 next;
5784 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +04005785 $RecursiveIncludes{$LibVersion}{$AbsPath}{$HPath} = $IncType;
5786 if($IncType>0)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005787 { # only include <...>, skip include "..." prefixes
5788 $Header_Include_Prefix{$LibVersion}{$AbsPath}{$HPath}{get_dirname($Include)} = 1;
5789 }
5790 foreach my $IncPath (detect_recursive_includes($HPath, $LibVersion))
5791 {
5792 if($IncPath eq $AbsPath) {
5793 next;
5794 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +04005795 my $RIncType = $RecursiveIncludes{$LibVersion}{$HPath}{$IncPath};
5796 if($RIncType==-1)
5797 { # include "..."
5798 $RIncType = $IncType;
5799 }
5800 elsif($RIncType==2)
5801 {
5802 if($IncType!=-1) {
5803 $RIncType = $IncType;
5804 }
5805 }
5806 $RecursiveIncludes{$LibVersion}{$AbsPath}{$IncPath} = $RIncType;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005807 foreach my $Prefix (keys(%{$Header_Include_Prefix{$LibVersion}{$HPath}{$IncPath}})) {
5808 $Header_Include_Prefix{$LibVersion}{$AbsPath}{$IncPath}{$Prefix} = 1;
5809 }
5810 }
5811 foreach my $Dep (keys(%{$Header_Include_Prefix{$LibVersion}{$AbsPath}}))
5812 {
5813 if($GlibcHeader{get_filename($Dep)} and keys(%{$Header_Include_Prefix{$LibVersion}{$AbsPath}{$Dep}})>=2
5814 and defined $Header_Include_Prefix{$LibVersion}{$AbsPath}{$Dep}{""})
5815 { # distinguish math.h from glibc and math.h from the tested library
5816 delete($Header_Include_Prefix{$LibVersion}{$AbsPath}{$Dep}{""});
5817 last;
5818 }
5819 }
5820 }
5821 pop(@RecurInclude);
5822 return keys(%{$RecursiveIncludes{$LibVersion}{$AbsPath}});
5823}
5824
5825sub find_in_framework($$$)
5826{
5827 my ($Header, $Framework, $LibVersion) = @_;
5828 return "" if(not $Header or not $Framework or not $LibVersion);
5829 if(defined $Cache{"find_in_framework"}{$LibVersion}{$Framework}{$Header}) {
5830 return $Cache{"find_in_framework"}{$LibVersion}{$Framework}{$Header};
5831 }
5832 foreach my $Dependency (sort {get_depth($a)<=>get_depth($b)} keys(%{$Header_Dependency{$LibVersion}}))
5833 {
5834 if(get_filename($Dependency) eq $Framework
5835 and -f get_dirname($Dependency)."/".$Header) {
5836 return ($Cache{"find_in_framework"}{$LibVersion}{$Framework}{$Header} = get_dirname($Dependency));
5837 }
5838 }
5839 return ($Cache{"find_in_framework"}{$LibVersion}{$Framework}{$Header} = "");
5840}
5841
5842sub find_in_defaults($)
5843{
5844 my $Header = $_[0];
5845 return "" if(not $Header);
5846 if(defined $Cache{"find_in_defaults"}{$Header}) {
5847 return $Cache{"find_in_defaults"}{$Header};
5848 }
5849 foreach my $Dir (sort {get_depth($a)<=>get_depth($b)}
5850 (keys(%DefaultIncPaths), keys(%DefaultGccPaths), keys(%DefaultCppPaths), keys(%UserIncPath)))
5851 {
5852 next if(not $Dir);
5853 if(-f $Dir."/".$Header) {
5854 return ($Cache{"find_in_defaults"}{$Header}=$Dir);
5855 }
5856 }
5857 return ($Cache{"find_in_defaults"}{$Header}="");
5858}
5859
5860sub cmp_paths($$)
5861{
5862 my ($Path1, $Path2) = @_;
5863 my @Parts1 = split(/[\/\\]/, $Path1);
5864 my @Parts2 = split(/[\/\\]/, $Path2);
5865 foreach my $Num (0 .. $#Parts1)
5866 {
5867 my $Part1 = $Parts1[$Num];
5868 my $Part2 = $Parts2[$Num];
5869 if($GlibcDir{$Part1}
5870 and not $GlibcDir{$Part2}) {
5871 return 1;
5872 }
5873 elsif($GlibcDir{$Part2}
5874 and not $GlibcDir{$Part1}) {
5875 return -1;
5876 }
5877 elsif($Part1=~/glib/
5878 and $Part2!~/glib/) {
5879 return 1;
5880 }
5881 elsif($Part1!~/glib/
5882 and $Part2=~/glib/) {
5883 return -1;
5884 }
5885 elsif(my $CmpRes = ($Part1 cmp $Part2)) {
5886 return $CmpRes;
5887 }
5888 }
5889 return 0;
5890}
5891
5892sub checkRelevance($)
5893{
5894 my ($Path) = @_;
5895 return 0 if(not $Path);
5896 if($SystemRoot) {
5897 $Path=~s/\A\Q$SystemRoot\E//g;
5898 }
5899 my ($Dir, $Name) = separate_path($Path);
5900 $Name=~s/\.\w+\Z//g;# remove extension (.h)
5901 my @Tokens = split(/[_\d\W]+/, $Name);
5902 foreach (@Tokens)
5903 {
5904 next if(not $_);
5905 if($Dir=~/(\A|lib|[_\d\W])\Q$_\E([_\d\W]|lib|\Z)/i
5906 or length($_)>=4 and $Dir=~/\Q$_\E/i)
5907 { # include/gupnp-1.0/libgupnp/gupnp-context.h
5908 # include/evolution-data-server-1.4/libebook/e-book.h
5909 return 1;
5910 }
5911 }
5912 return 0;
5913}
5914
5915sub checkFamily(@)
5916{
5917 my @Paths = @_;
5918 return 1 if($#Paths<=0);
5919 my %Prefix = ();
5920 foreach my $Path (@Paths)
5921 {
5922 if($SystemRoot) {
5923 $Path = cut_path_prefix($Path, $SystemRoot);
5924 }
5925 if(my $Dir = get_dirname($Path))
5926 {
5927 $Dir=~s/(\/[^\/]+?)[\d\.\-\_]+\Z/$1/g; # remove version suffix
5928 $Prefix{$Dir} += 1;
5929 $Prefix{get_dirname($Dir)} += 1;
5930 }
5931 }
5932 foreach (sort keys(%Prefix))
5933 {
5934 if(get_depth($_)>=3
5935 and $Prefix{$_}==$#Paths+1) {
5936 return 1;
5937 }
5938 }
5939 return 0;
5940}
5941
5942sub isAcceptable($$$)
5943{
5944 my ($Header, $Candidate, $LibVersion) = @_;
5945 my $HName = get_filename($Header);
5946 if(get_dirname($Header))
5947 { # with prefix
5948 return 1;
5949 }
5950 if($HName=~/config|setup/i and $Candidate=~/[\/\\]lib\d*[\/\\]/)
5951 { # allow to search for glibconfig.h in /usr/lib/glib-2.0/include/
5952 return 1;
5953 }
5954 if(checkRelevance($Candidate))
5955 { # allow to search for atk.h in /usr/include/atk-1.0/atk/
5956 return 1;
5957 }
5958 if(checkFamily(getSystemHeaders($HName, $LibVersion)))
5959 { # /usr/include/qt4/QtNetwork/qsslconfiguration.h
5960 # /usr/include/qt4/Qt/qsslconfiguration.h
5961 return 1;
5962 }
5963 if($OStarget eq "symbian")
5964 {
5965 if($Candidate=~/[\/\\]stdapis[\/\\]/) {
5966 return 1;
5967 }
5968 }
5969 return 0;
5970}
5971
5972sub isRelevant($$$)
5973{ # disallow to search for "abstract" headers in too deep directories
5974 my ($Header, $Candidate, $LibVersion) = @_;
5975 my $HName = get_filename($Header);
5976 if($OStarget eq "symbian")
5977 {
5978 if($Candidate=~/[\/\\](tools|stlportv5)[\/\\]/) {
5979 return 0;
5980 }
5981 }
5982 if($OStarget ne "bsd") {
5983 if($Candidate=~/[\/\\]include[\/\\]bsd[\/\\]/)
5984 { # openssh: skip /usr/lib/bcc/include/bsd/signal.h
5985 return 0;
5986 }
5987 }
5988 if(not get_dirname($Header)
5989 and $Candidate=~/[\/\\]wx[\/\\]/)
5990 { # do NOT search in system /wx/ directory
5991 # for headers without a prefix: sstream.h
5992 return 0;
5993 }
5994 if($Candidate=~/c\+\+[\/\\]\d+/ and $MAIN_CPP_DIR
5995 and $Candidate!~/\A\Q$MAIN_CPP_DIR\E/)
5996 { # skip ../c++/3.3.3/ if using ../c++/4.5/
5997 return 0;
5998 }
5999 if($Candidate=~/[\/\\]asm-/
6000 and (my $Arch = getArch($LibVersion)) ne "unknown")
6001 { # arch-specific header files
6002 if($Candidate!~/[\/\\]asm-\Q$Arch\E/)
6003 {# skip ../asm-arm/ if using x86 architecture
6004 return 0;
6005 }
6006 }
6007 my @Candidates = getSystemHeaders($HName, $LibVersion);
6008 if($#Candidates==1)
6009 { # unique header
6010 return 1;
6011 }
6012 my @SCandidates = getSystemHeaders($Header, $LibVersion);
6013 if($#SCandidates==1)
6014 { # unique name
6015 return 1;
6016 }
6017 my $SystemDepth = $SystemRoot?get_depth($SystemRoot):0;
6018 if(get_depth($Candidate)-$SystemDepth>=5)
6019 { # abstract headers in too deep directories
6020 # sstream.h or typeinfo.h in /usr/include/wx-2.9/wx/
6021 if(not isAcceptable($Header, $Candidate, $LibVersion)) {
6022 return 0;
6023 }
6024 }
6025 if($Header eq "parser.h"
6026 and $Candidate!~/\/libxml2\//)
6027 { # select parser.h from xml2 library
6028 return 0;
6029 }
6030 if(not get_dirname($Header)
6031 and keys(%{$SystemHeaders{$HName}})>=3)
6032 { # many headers with the same name
6033 # like thread.h included without a prefix
6034 if(not checkFamily(@Candidates)) {
6035 return 0;
6036 }
6037 }
6038 return 1;
6039}
6040
6041sub selectSystemHeader($$)
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04006042{ # cache function
6043 if(defined $Cache{"selectSystemHeader"}{$_[1]}{$_[0]}) {
6044 return $Cache{"selectSystemHeader"}{$_[1]}{$_[0]};
6045 }
6046 return ($Cache{"selectSystemHeader"}{$_[1]}{$_[0]} = selectSystemHeader_I(@_));
6047}
6048
6049sub selectSystemHeader_I($$)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006050{
6051 my ($Header, $LibVersion) = @_;
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04006052 if(-f $Header) {
6053 return $Header;
6054 }
6055 if(is_abs($Header) and not -f $Header)
6056 { # incorrect absolute path
6057 return "";
6058 }
6059 if($Header=~/\A(atomic|config|configure|build|conf|setup)\.h\Z/i)
6060 { # too abstract configuration headers
6061 return "";
6062 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006063 if($OSgroup ne "windows")
6064 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04006065 if(get_filename($Header)=~/windows|win32|win64|\A(dos|process|winsock|config-win)\.h\Z/i)
6066 { # windows headers
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006067 return "";
6068 }
6069 elsif($Header=~/\A(mem)\.h\Z/)
6070 { # pngconf.h include mem.h for __MSDOS__
6071 return "";
6072 }
6073 }
6074 if($OSgroup ne "solaris")
6075 {
6076 if($Header=~/\A(thread)\.h\Z/)
6077 { # thread.h in Solaris
6078 return "";
6079 }
6080 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04006081
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006082 foreach my $Path (keys(%{$SystemPaths{"include"}}))
6083 { # search in default paths
6084 if(-f $Path."/".$Header) {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04006085 return joinPath($Path,$Header);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006086 }
6087 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04006088 if(not keys(%SystemHeaders))
6089 { # register all headers in system include dirs
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006090 detectSystemHeaders();
6091 }
6092 foreach my $Candidate (sort {get_depth($a)<=>get_depth($b)}
6093 sort {cmp_paths($b, $a)} getSystemHeaders($Header, $LibVersion))
6094 {
6095 if(isRelevant($Header, $Candidate, $LibVersion)) {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04006096 return $Candidate;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006097 }
6098 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04006099 # error
6100 return "";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006101}
6102
6103sub getSystemHeaders($$)
6104{
6105 my ($Header, $LibVersion) = @_;
6106 my @Candidates = ();
6107 foreach my $Candidate (sort keys(%{$SystemHeaders{$Header}}))
6108 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04006109 if(skipHeader($Candidate, $LibVersion)) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006110 next;
6111 }
6112 push(@Candidates, $Candidate);
6113 }
6114 return @Candidates;
6115}
6116
6117sub cut_path_prefix($$)
6118{
6119 my ($Path, $Prefix) = @_;
6120 return $Path if(not $Prefix);
6121 $Prefix=~s/[\/\\]+\Z//;
6122 $Path=~s/\A\Q$Prefix\E([\/\\]+|\Z)//;
6123 return $Path;
6124}
6125
6126sub is_default_include_dir($)
6127{
6128 my $Dir = $_[0];
6129 $Dir=~s/[\/\\]+\Z//;
6130 return ($DefaultGccPaths{$Dir} or $DefaultCppPaths{$Dir} or $DefaultIncPaths{$Dir});
6131}
6132
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04006133sub identifyHeader($$)
6134{ # cache function
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006135 my ($Header, $LibVersion) = @_;
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04006136 if(not $Header) {
6137 return "";
6138 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006139 $Header=~s/\A(\.\.[\\\/])+//g;
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04006140 if(defined $Cache{"identifyHeader"}{$LibVersion}{$Header}) {
6141 return $Cache{"identifyHeader"}{$LibVersion}{$Header};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006142 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04006143 return ($Cache{"identifyHeader"}{$LibVersion}{$Header} = identifyHeader_I($Header, $LibVersion));
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006144}
6145
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04006146sub identifyHeader_I($$)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006147{ # search for header by absolute path, relative path or name
6148 my ($Header, $LibVersion) = @_;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006149 if(-f $Header)
6150 { # it's relative or absolute path
6151 return get_abs_path($Header);
6152 }
6153 elsif($GlibcHeader{$Header} and not $GLIBC_TESTING
6154 and my $HeaderDir = find_in_defaults($Header))
6155 { # search for libc headers in the /usr/include
6156 # for non-libc target library before searching
6157 # in the library paths
6158 return joinPath($HeaderDir,$Header);
6159 }
6160 elsif(my $Path = $Include_Neighbors{$LibVersion}{$Header})
6161 { # search in the target library paths
6162 return $Path;
6163 }
6164 elsif($DefaultGccHeader{$Header})
6165 { # search in the internal GCC include paths
6166 return $DefaultGccHeader{$Header};
6167 }
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04006168 elsif(my $DefaultDir = find_in_defaults($Header))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006169 { # search in the default GCC include paths
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04006170 return joinPath($DefaultDir,$Header);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006171 }
6172 elsif($DefaultCppHeader{$Header})
6173 { # search in the default G++ include paths
6174 return $DefaultCppHeader{$Header};
6175 }
6176 elsif(my $AnyPath = selectSystemHeader($Header, $LibVersion))
6177 { # search everywhere in the system
6178 return $AnyPath;
6179 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04006180 elsif($OSgroup eq "macos")
6181 { # search in frameworks: "OpenGL/gl.h" is "OpenGL.framework/Headers/gl.h"
6182 if(my $Dir = get_dirname($Header))
6183 {
6184 my $RelPath = "Headers\/".get_filename($Header);
6185 if(my $HeaderDir = find_in_framework($RelPath, $Dir.".framework", $LibVersion)) {
6186 return joinPath($HeaderDir, $RelPath);
6187 }
6188 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006189 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04006190 # cannot find anything
6191 return "";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006192}
6193
6194sub getLocation($)
6195{
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04006196 if($_[0] and my $Info = $LibInfo{$Version}{"info"}{$_[0]})
6197 {
6198 if($Info=~/srcp[ ]*:[ ]*([\w\-\<\>\.\+\/\\]+):(\d+) /) {
6199 return ($1, $2);
6200 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006201 }
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04006202 return ();
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006203}
6204
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006205sub getNameByInfo($)
6206{
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04006207 if($_[0] and my $Info = $LibInfo{$Version}{"info"}{$_[0]})
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04006208 {
6209 if($Info=~/name[ ]*:[ ]*@(\d+) /)
6210 {
6211 if(my $NInfo = $LibInfo{$Version}{"info"}{$1})
6212 {
6213 if($NInfo=~/strg[ ]*:[ ]*(.*?)[ ]+lngt/)
6214 { # short unsigned int (may include spaces)
6215 return $1;
6216 }
6217 }
6218 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006219 }
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04006220 return "";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006221}
6222
6223sub getTreeStr($)
6224{
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04006225 if($_[0] and my $Info = $LibInfo{$Version}{"info"}{$_[0]})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006226 {
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04006227 if($Info=~/strg[ ]*:[ ]*([^ ]*)/)
6228 {
6229 my $Str = $1;
6230 if($C99Mode{$Version}
6231 and $Str=~/\Ac99_(.+)\Z/) {
6232 if($CppKeywords_A{$1}) {
6233 $Str=$1;
6234 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006235 }
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04006236 return $Str;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006237 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006238 }
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04006239 return "";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006240}
6241
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006242sub getFuncShortName($)
6243{
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04006244 if(my $Info = $LibInfo{$Version}{"info"}{$_[0]})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006245 {
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04006246 if($Info=~/ operator /)
6247 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04006248 if($Info=~/ conversion /)
6249 {
6250 if(my $Rid = $SymbolInfo{$Version}{$_[0]}{"Return"})
6251 {
6252 if(my $RName = $TypeInfo{$Version}{$Rid}{"Name"}) {
6253 return "operator ".$RName;
6254 }
6255 }
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04006256 }
6257 else
6258 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04006259 if($Info=~/ operator[ ]+([a-zA-Z]+) /)
6260 {
6261 if(my $Ind = $Operator_Indication{$1}) {
6262 return "operator".$Ind;
6263 }
6264 elsif(not $UnknownOperator{$1})
6265 {
6266 printMsg("WARNING", "unknown operator $1");
6267 $UnknownOperator{$1} = 1;
6268 }
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04006269 }
6270 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006271 }
6272 else
6273 {
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04006274 if($Info=~/name[ ]*:[ ]*@(\d+) /) {
6275 return getTreeStr($1);
6276 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006277 }
6278 }
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04006279 return "";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006280}
6281
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006282sub getFuncReturn($)
6283{
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04006284 if($_[0] and my $Info = $LibInfo{$Version}{"info"}{$_[0]})
6285 {
6286 if($Info=~/type[ ]*:[ ]*@(\d+) /)
6287 {
6288 if($LibInfo{$Version}{"info"}{$1}=~/retn[ ]*:[ ]*@(\d+) /) {
6289 return $1;
6290 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006291 }
6292 }
6293 return "";
6294}
6295
6296sub getFuncOrig($)
6297{
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04006298 if($_[0] and my $Info = $LibInfo{$Version}{"info"}{$_[0]})
6299 {
6300 if($Info=~/orig[ ]*:[ ]*@(\d+) /) {
6301 return $1;
6302 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006303 }
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04006304 return $_[0];
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006305}
6306
6307sub unmangleSymbol($)
6308{
6309 my $Symbol = $_[0];
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04006310 if(my @Unmngl = unmangleArray($Symbol)) {
6311 return $Unmngl[0];
6312 }
6313 return "";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006314}
6315
6316sub unmangleArray(@)
6317{
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04006318 if($_[0]=~/\A\?/)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006319 { # MSVC mangling
6320 my $UndNameCmd = get_CmdPath("undname");
6321 if(not $UndNameCmd) {
6322 exitStatus("Not_Found", "can't find \"undname\"");
6323 }
6324 writeFile("$TMP_DIR/unmangle", join("\n", @_));
6325 return split(/\n/, `$UndNameCmd 0x8386 $TMP_DIR/unmangle`);
6326 }
6327 else
6328 { # GCC mangling
6329 my $CppFiltCmd = get_CmdPath("c++filt");
6330 if(not $CppFiltCmd) {
6331 exitStatus("Not_Found", "can't find c++filt in PATH");
6332 }
6333 my $Info = `$CppFiltCmd -h 2>&1`;
6334 if($Info=~/\@<file>/)
6335 {# new version of c++filt can take a file
6336 my $NoStrip = "";
6337 if($OSgroup eq "macos"
6338 or $OSgroup eq "windows") {
6339 $NoStrip = "-n";
6340 }
6341 writeFile("$TMP_DIR/unmangle", join("\n", @_));
6342 return split(/\n/, `$CppFiltCmd $NoStrip \@\"$TMP_DIR/unmangle\"`);
6343 }
6344 else
6345 { # old-style unmangling
6346 if($#_>$MAX_COMMAND_LINE_ARGUMENTS) {
6347 my @Half = splice(@_, 0, ($#_+1)/2);
6348 return (unmangleArray(@Half), unmangleArray(@_))
6349 }
6350 else
6351 {
6352 my $NoStrip = "";
6353 if($OSgroup eq "macos"
6354 or $OSgroup eq "windows") {
6355 $NoStrip = "-n";
6356 }
6357 my $Strings = join(" ", @_);
6358 return split(/\n/, `$CppFiltCmd $NoStrip $Strings`);
6359 }
6360 }
6361 }
6362}
6363
6364sub get_SignatureNoInfo($$)
6365{
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04006366 my ($Symbol, $LibVersion) = @_;
6367 if($Cache{"get_SignatureNoInfo"}{$LibVersion}{$Symbol}) {
6368 return $Cache{"get_SignatureNoInfo"}{$LibVersion}{$Symbol};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006369 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04006370 my ($MnglName, $VersionSpec, $SymbolVersion) = separate_symbol($Symbol);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006371 my $Signature = $tr_name{$MnglName}?$tr_name{$MnglName}:$MnglName;
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04006372 if($Symbol=~/\A(_Z|\?)/)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006373 { # C++
6374 $Signature=~s/\Qstd::basic_string<char, std::char_traits<char>, std::allocator<char> >\E/std::string/g;
6375 $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;
6376 }
6377 if(not $CheckObjectsOnly or $OSgroup=~/linux|bsd|beos/)
6378 { # ELF format marks data as OBJECT
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04006379 if($GlobalDataObject{$LibVersion}{$Symbol}) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006380 $Signature .= " [data]";
6381 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04006382 elsif($Symbol!~/\A(_Z|\?)/) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006383 $Signature .= " (...)";
6384 }
6385 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04006386 if(my $ChargeLevel = get_ChargeLevel($Symbol, $LibVersion))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006387 {
Andrey Ponomarenko16934472012-03-29 15:37:04 +04006388 my $ShortName = substr($Signature, 0, find_center($Signature, "("));
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006389 $Signature=~s/\A\Q$ShortName\E/$ShortName $ChargeLevel/g;
6390 }
6391 if($SymbolVersion) {
6392 $Signature .= $VersionSpec.$SymbolVersion;
6393 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04006394 return ($Cache{"get_SignatureNoInfo"}{$LibVersion}{$Symbol} = $Signature);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006395}
6396
6397sub get_ChargeLevel($$)
6398{
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04006399 my ($Symbol, $LibVersion) = @_;
6400 return "" if($Symbol!~/\A(_Z|\?)/);
6401 if(defined $CompleteSignature{$LibVersion}{$Symbol}
6402 and $CompleteSignature{$LibVersion}{$Symbol}{"Header"})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006403 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04006404 if($CompleteSignature{$LibVersion}{$Symbol}{"Constructor"})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006405 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04006406 if($Symbol=~/C1E/) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006407 return "[in-charge]";
6408 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04006409 elsif($Symbol=~/C2E/) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006410 return "[not-in-charge]";
6411 }
6412 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04006413 elsif($CompleteSignature{$LibVersion}{$Symbol}{"Destructor"})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006414 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04006415 if($Symbol=~/D1E/) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006416 return "[in-charge]";
6417 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04006418 elsif($Symbol=~/D2E/) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006419 return "[not-in-charge]";
6420 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04006421 elsif($Symbol=~/D0E/) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006422 return "[in-charge-deleting]";
6423 }
6424 }
6425 }
6426 else
6427 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04006428 if($Symbol=~/C1E/) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006429 return "[in-charge]";
6430 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04006431 elsif($Symbol=~/C2E/) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006432 return "[not-in-charge]";
6433 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04006434 elsif($Symbol=~/D1E/) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006435 return "[in-charge]";
6436 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04006437 elsif($Symbol=~/D2E/) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006438 return "[not-in-charge]";
6439 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04006440 elsif($Symbol=~/D0E/) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006441 return "[in-charge-deleting]";
6442 }
6443 }
6444 return "";
6445}
6446
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04006447sub get_Signature_M($$)
6448{
6449 my ($Symbol, $LibVersion) = @_;
6450 my $Signature_M = $tr_name{$Symbol};
6451 if(my $RTid = $CompleteSignature{$LibVersion}{$Symbol}{"Return"})
6452 { # add return type name
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04006453 $Signature_M = $TypeInfo{$LibVersion}{$RTid}{"Name"}." ".$Signature_M;
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04006454 }
6455 return $Signature_M;
6456}
6457
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006458sub get_Signature($$)
6459{
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04006460 my ($Symbol, $LibVersion) = @_;
6461 if($Cache{"get_Signature"}{$LibVersion}{$Symbol}) {
6462 return $Cache{"get_Signature"}{$LibVersion}{$Symbol};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006463 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04006464 my ($MnglName, $VersionSpec, $SymbolVersion) = separate_symbol($Symbol);
6465 if(isPrivateData($MnglName) or not $CompleteSignature{$LibVersion}{$Symbol}{"Header"})
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04006466 { # non-public global data
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04006467 return get_SignatureNoInfo($Symbol, $LibVersion);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006468 }
6469 my ($Func_Signature, @Param_Types_FromUnmangledName) = ();
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04006470 my $ShortName = $CompleteSignature{$LibVersion}{$Symbol}{"ShortName"};
6471 if($Symbol=~/\A(_Z|\?)/)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006472 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04006473 if(my $ClassId = $CompleteSignature{$LibVersion}{$Symbol}{"Class"}) {
6474 $Func_Signature = $TypeInfo{$LibVersion}{$ClassId}{"Name"}."::".(($CompleteSignature{$LibVersion}{$Symbol}{"Destructor"})?"~":"").$ShortName;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006475 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04006476 elsif(my $NameSpace = $CompleteSignature{$LibVersion}{$Symbol}{"NameSpace"}) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006477 $Func_Signature = $NameSpace."::".$ShortName;
6478 }
6479 else {
6480 $Func_Signature = $ShortName;
6481 }
6482 @Param_Types_FromUnmangledName = get_s_params($tr_name{$MnglName}, 0);
6483 }
6484 else {
6485 $Func_Signature = $MnglName;
6486 }
6487 my @ParamArray = ();
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04006488 foreach my $Pos (sort {int($a) <=> int($b)} keys(%{$CompleteSignature{$LibVersion}{$Symbol}{"Param"}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006489 {
6490 next if($Pos eq "");
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04006491 my $ParamTypeId = $CompleteSignature{$LibVersion}{$Symbol}{"Param"}{$Pos}{"type"};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006492 next if(not $ParamTypeId);
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04006493 my $ParamTypeName = $TypeInfo{$LibVersion}{$ParamTypeId}{"Name"};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006494 if(not $ParamTypeName) {
6495 $ParamTypeName = $Param_Types_FromUnmangledName[$Pos];
6496 }
6497 foreach my $Typedef (keys(%ChangedTypedef))
6498 {
6499 my $Base = $Typedef_BaseName{$LibVersion}{$Typedef};
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04006500 $ParamTypeName=~s/\b\Q$Typedef\E\b/$Base/g;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006501 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04006502 if(my $ParamName = $CompleteSignature{$LibVersion}{$Symbol}{"Param"}{$Pos}{"name"}) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006503 push(@ParamArray, create_member_decl($ParamTypeName, $ParamName));
6504 }
6505 else {
6506 push(@ParamArray, $ParamTypeName);
6507 }
6508 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04006509 if($CompleteSignature{$LibVersion}{$Symbol}{"Data"}
6510 or $GlobalDataObject{$LibVersion}{$Symbol}) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006511 $Func_Signature .= " [data]";
6512 }
6513 else
6514 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04006515 if(my $ChargeLevel = get_ChargeLevel($Symbol, $LibVersion))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006516 { # add [in-charge]
6517 $Func_Signature .= " ".$ChargeLevel;
6518 }
6519 $Func_Signature .= " (".join(", ", @ParamArray).")";
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04006520 if($CompleteSignature{$LibVersion}{$Symbol}{"Const"}
6521 or $Symbol=~/\A_ZN(V|)K/) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006522 $Func_Signature .= " const";
6523 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04006524 if($CompleteSignature{$LibVersion}{$Symbol}{"Volatile"}
6525 or $Symbol=~/\A_ZN(K|)V/) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006526 $Func_Signature .= " volatile";
6527 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04006528 if($CompleteSignature{$LibVersion}{$Symbol}{"Static"}
6529 and $Symbol=~/\A(_Z|\?)/)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006530 {# for static methods
6531 $Func_Signature .= " [static]";
6532 }
6533 }
6534 if(defined $ShowRetVal
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04006535 and my $ReturnTId = $CompleteSignature{$LibVersion}{$Symbol}{"Return"}) {
6536 $Func_Signature .= ":".$TypeInfo{$LibVersion}{$ReturnTId}{"Name"};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006537 }
6538 if($SymbolVersion) {
6539 $Func_Signature .= $VersionSpec.$SymbolVersion;
6540 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04006541 return ($Cache{"get_Signature"}{$LibVersion}{$Symbol} = $Func_Signature);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006542}
6543
6544sub create_member_decl($$)
6545{
6546 my ($TName, $Member) = @_;
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04006547 if($TName=~/\([\*]+\)/)
6548 {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006549 $TName=~s/\(([\*]+)\)/\($1$Member\)/;
6550 return $TName;
6551 }
6552 else
6553 {
6554 my @ArraySizes = ();
6555 while($TName=~s/(\[[^\[\]]*\])\Z//) {
6556 push(@ArraySizes, $1);
6557 }
6558 return $TName." ".$Member.join("", @ArraySizes);
6559 }
6560}
6561
6562sub getFuncType($)
6563{
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04006564 if($_[0] and my $Info = $LibInfo{$Version}{"info"}{$_[0]})
6565 {
6566 if($Info=~/type[ ]*:[ ]*@(\d+) /)
6567 {
6568 if(my $Type = $LibInfo{$Version}{"info_type"}{$1})
6569 {
6570 if($Type eq "method_type") {
6571 return "Method";
6572 }
6573 elsif($Type eq "function_type") {
6574 return "Function";
6575 }
6576 else {
6577 return "Other";
6578 }
6579 }
6580 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006581 }
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04006582 return ""
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006583}
6584
6585sub getFuncTypeId($)
6586{
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04006587 if($_[0] and my $Info = $LibInfo{$Version}{"info"}{$_[0]})
6588 {
6589 if($Info=~/type[ ]*:[ ]*@(\d+)( |\Z)/) {
6590 return $1;
6591 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006592 }
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04006593 return 0;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006594}
6595
6596sub isNotAnon($) {
6597 return (not isAnon($_[0]));
6598}
6599
6600sub isAnon($)
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04006601{ # "._N" or "$_N" in older GCC versions
6602 return ($_[0] and $_[0]=~/(\.|\$)\_\d+|anon\-/);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006603}
6604
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006605sub formatName($)
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04006606{ # type name correction
6607 if(defined $Cache{"formatName"}{$_[0]}) {
6608 return $Cache{"formatName"}{$_[0]};
6609 }
6610
6611 $_ = $_[0];
6612
6613 s/\A[ ]+|[ ]+\Z//g;
6614 s/[ ]{2,}/ /g;
6615 s/[ ]*(\W)[ ]*/$1/g;
6616
6617 s/\bvolatile const\b/const volatile/g;
6618
6619 s/\b(long long|short|long) unsigned\b/unsigned $1/g;
6620 s/\b(short|long) int\b/$1/g;
6621
6622 s/([\)\]])(const|volatile)\b/$1 $2/g;
6623
6624 while(s/>>/> >/g) {};
6625
6626 s/\b(operator[ ]*)> >/$1>>/;
6627
6628 return ($Cache{"formatName"}{$_[0]}=$_);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006629}
6630
6631sub get_HeaderDeps($$)
6632{
6633 my ($AbsPath, $LibVersion) = @_;
6634 return () if(not $AbsPath or not $LibVersion);
6635 if(defined $Cache{"get_HeaderDeps"}{$LibVersion}{$AbsPath}) {
6636 return @{$Cache{"get_HeaderDeps"}{$LibVersion}{$AbsPath}};
6637 }
6638 my %IncDir = ();
6639 detect_recursive_includes($AbsPath, $LibVersion);
6640 foreach my $HeaderPath (keys(%{$RecursiveIncludes{$LibVersion}{$AbsPath}}))
6641 {
6642 next if(not $HeaderPath);
6643 next if($MAIN_CPP_DIR and $HeaderPath=~/\A\Q$MAIN_CPP_DIR\E([\/\\]|\Z)/);
6644 my $Dir = get_dirname($HeaderPath);
6645 foreach my $Prefix (keys(%{$Header_Include_Prefix{$LibVersion}{$AbsPath}{$HeaderPath}}))
6646 {
6647 my $Dep = $Dir;
6648 if($Prefix)
6649 {
6650 if($OSgroup eq "windows")
6651 { # case insensitive seach on windows
6652 if(not $Dep=~s/[\/\\]+\Q$Prefix\E\Z//ig) {
6653 next;
6654 }
6655 }
6656 elsif($OSgroup eq "macos")
6657 { # seach in frameworks
6658 if(not $Dep=~s/[\/\\]+\Q$Prefix\E\Z//g)
6659 {
6660 if($HeaderPath=~/(.+\.framework)\/Headers\/([^\/]+)/)
6661 {# frameworks
6662 my ($HFramework, $HName) = ($1, $2);
6663 $Dep = $HFramework;
6664 }
6665 else
6666 {# mismatch
6667 next;
6668 }
6669 }
6670 }
6671 elsif(not $Dep=~s/[\/\\]+\Q$Prefix\E\Z//g)
6672 { # Linux, FreeBSD
6673 next;
6674 }
6675 }
6676 if(not $Dep)
6677 { # nothing to include
6678 next;
6679 }
6680 if(is_default_include_dir($Dep))
6681 { # included by the compiler
6682 next;
6683 }
6684 if(get_depth($Dep)==1)
6685 { # too short
6686 next;
6687 }
6688 if(isLibcDir($Dep))
6689 { # do NOT include /usr/include/{sys,bits}
6690 next;
6691 }
6692 $IncDir{$Dep}=1;
6693 }
6694 }
6695 $Cache{"get_HeaderDeps"}{$LibVersion}{$AbsPath} = sortIncPaths([keys(%IncDir)], $LibVersion);
6696 return @{$Cache{"get_HeaderDeps"}{$LibVersion}{$AbsPath}};
6697}
6698
6699sub sortIncPaths($$)
6700{
6701 my ($ArrRef, $LibVersion) = @_;
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04006702 if(not $ArrRef or $#{$ArrRef}<0) {
6703 return $ArrRef;
6704 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006705 @{$ArrRef} = sort {$b cmp $a} @{$ArrRef};
6706 @{$ArrRef} = sort {get_depth($a)<=>get_depth($b)} @{$ArrRef};
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04006707 @{$ArrRef} = sort {sortDeps($b, $a, $LibVersion)} @{$ArrRef};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006708 return $ArrRef;
6709}
6710
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04006711sub sortDeps($$$)
6712{
6713 if($Header_Dependency{$_[2]}{$_[0]}
6714 and not $Header_Dependency{$_[2]}{$_[1]}) {
6715 return 1;
6716 }
6717 elsif(not $Header_Dependency{$_[2]}{$_[0]}
6718 and $Header_Dependency{$_[2]}{$_[1]}) {
6719 return -1;
6720 }
6721 return 0;
6722}
6723
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006724sub joinPath($$) {
6725 return join($SLASH, @_);
6726}
6727
6728sub get_namespace_additions($)
6729{
6730 my $NameSpaces = $_[0];
6731 my ($Additions, $AddNameSpaceId) = ("", 1);
6732 foreach my $NS (sort {$a=~/_/ <=> $b=~/_/} sort {lc($a) cmp lc($b)} keys(%{$NameSpaces}))
6733 {
6734 next if($SkipNameSpaces{$Version}{$NS});
6735 next if(not $NS or $NameSpaces->{$NS}==-1);
6736 next if($NS=~/(\A|::)iterator(::|\Z)/i);
6737 next if($NS=~/\A__/i);
6738 next if(($NS=~/\Astd::/ or $NS=~/\A(std|tr1|rel_ops|fcntl)\Z/) and not $STDCXX_TESTING);
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04006739 $NestedNameSpaces{$Version}{$NS} = 1; # for future use in reports
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006740 my ($TypeDecl_Prefix, $TypeDecl_Suffix) = ();
6741 my @NS_Parts = split(/::/, $NS);
6742 next if($#NS_Parts==-1);
6743 next if($NS_Parts[0]=~/\A(random|or)\Z/);
6744 foreach my $NS_Part (@NS_Parts)
6745 {
6746 $TypeDecl_Prefix .= "namespace $NS_Part\{";
6747 $TypeDecl_Suffix .= "}";
6748 }
6749 my $TypeDecl = $TypeDecl_Prefix."typedef int tmp_add_type_$AddNameSpaceId;".$TypeDecl_Suffix;
6750 my $FuncDecl = "$NS\:\:tmp_add_type_$AddNameSpaceId tmp_add_func_$AddNameSpaceId(){return 0;};";
6751 $Additions.=" $TypeDecl\n $FuncDecl\n";
6752 $AddNameSpaceId+=1;
6753 }
6754 return $Additions;
6755}
6756
6757sub path_format($$)
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04006758{ # forward slash to pass into MinGW GCC
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006759 my ($Path, $Fmt) = @_;
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04006760 if($Fmt eq "windows")
6761 {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006762 $Path=~s/\//\\/g;
6763 $Path=lc($Path);
6764 }
6765 else {
6766 $Path=~s/\\/\//g;
6767 }
6768 return $Path;
6769}
6770
6771sub inc_opt($$)
6772{
6773 my ($Path, $Style) = @_;
6774 if($Style eq "GCC")
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04006775 { # GCC options
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006776 if($OSgroup eq "windows")
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04006777 { # to MinGW GCC
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006778 return "-I\"".path_format($Path, "unix")."\"";
6779 }
6780 elsif($OSgroup eq "macos"
6781 and $Path=~/\.framework\Z/)
6782 {# to Apple's GCC
6783 return "-F".esc(get_dirname($Path));
6784 }
6785 else {
6786 return "-I".esc($Path);
6787 }
6788 }
6789 elsif($Style eq "CL") {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04006790 return "/I \"".$Path."\"";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006791 }
6792 return "";
6793}
6794
6795sub platformSpecs($)
6796{
6797 my $LibVersion = $_[0];
6798 my $Arch = getArch($LibVersion);
6799 if($OStarget eq "symbian")
6800 { # options for GCCE compiler
6801 my %Symbian_Opts = map {$_=>1} (
6802 "-D__GCCE__",
6803 "-DUNICODE",
6804 "-fexceptions",
6805 "-D__SYMBIAN32__",
6806 "-D__MARM_INTERWORK__",
6807 "-D_UNICODE",
6808 "-D__S60_50__",
6809 "-D__S60_3X__",
6810 "-D__SERIES60_3X__",
6811 "-D__EPOC32__",
6812 "-D__MARM__",
6813 "-D__EABI__",
6814 "-D__MARM_ARMV5__",
6815 "-D__SUPPORT_CPP_EXCEPTIONS__",
6816 "-march=armv5t",
6817 "-mapcs",
6818 "-mthumb-interwork",
6819 "-DEKA2",
6820 "-DSYMBIAN_ENABLE_SPLIT_HEADERS"
6821 );
6822 return join(" ", keys(%Symbian_Opts));
6823 }
6824 elsif($OSgroup eq "windows"
6825 and get_dumpmachine($GCC_PATH)=~/mingw/i)
6826 { # add options to MinGW compiler
6827 # to simulate the MSVC compiler
6828 my %MinGW_Opts = map {$_=>1} (
6829 "-D_WIN32",
6830 "-D_STDCALL_SUPPORTED",
6831 "-D__int64=\"long long\"",
6832 "-D__int32=int",
6833 "-D__int16=short",
6834 "-D__int8=char",
6835 "-D__possibly_notnullterminated=\" \"",
6836 "-D__nullterminated=\" \"",
6837 "-D__nullnullterminated=\" \"",
6838 "-D__w64=\" \"",
6839 "-D__ptr32=\" \"",
6840 "-D__ptr64=\" \"",
6841 "-D__forceinline=inline",
6842 "-D__inline=inline",
6843 "-D__uuidof(x)=IID()",
6844 "-D__try=",
6845 "-D__except(x)=",
6846 "-D__declspec(x)=__attribute__((x))",
6847 "-D__pragma(x)=",
6848 "-D_inline=inline",
6849 "-D__forceinline=__inline",
6850 "-D__stdcall=__attribute__((__stdcall__))",
6851 "-D__cdecl=__attribute__((__cdecl__))",
6852 "-D__fastcall=__attribute__((__fastcall__))",
6853 "-D__thiscall=__attribute__((__thiscall__))",
6854 "-D_stdcall=__attribute__((__stdcall__))",
6855 "-D_cdecl=__attribute__((__cdecl__))",
6856 "-D_fastcall=__attribute__((__fastcall__))",
6857 "-D_thiscall=__attribute__((__thiscall__))",
6858 "-DSHSTDAPI_(x)=x",
6859 "-D_MSC_EXTENSIONS",
6860 "-DSECURITY_WIN32",
6861 "-D_MSC_VER=1500",
6862 "-D_USE_DECLSPECS_FOR_SAL",
6863 "-D__noop=\" \"",
6864 "-DDECLSPEC_DEPRECATED=\" \"",
6865 "-D__builtin_alignof(x)=__alignof__(x)",
6866 "-DSORTPP_PASS");
6867 if($Arch eq "x86") {
6868 $MinGW_Opts{"-D_M_IX86=300"}=1;
6869 }
6870 elsif($Arch eq "x86_64") {
6871 $MinGW_Opts{"-D_M_AMD64=300"}=1;
6872 }
6873 elsif($Arch eq "ia64") {
6874 $MinGW_Opts{"-D_M_IA64=300"}=1;
6875 }
6876 return join(" ", keys(%MinGW_Opts));
6877 }
6878 return "";
6879}
6880
6881my %C_Structure = map {$_=>1} (
6882# FIXME: Can't separate union and struct data types before dumping,
6883# so it sometimes cause compilation errors for unknown reason
6884# when trying to declare TYPE* tmp_add_class_N
6885# This is a list of such structures + list of other C structures
6886 "sigval",
6887 "sigevent",
6888 "sigaction",
6889 "sigvec",
6890 "sigstack",
6891 "timeval",
6892 "timezone",
6893 "rusage",
6894 "rlimit",
6895 "wait",
6896 "flock",
6897 "stat",
6898 "_stat",
6899 "stat32",
6900 "_stat32",
6901 "stat64",
6902 "_stat64",
6903 "_stati64",
6904 "if_nameindex",
6905 "usb_device",
6906 "sigaltstack",
6907 "sysinfo",
6908 "timeLocale",
6909 "tcp_debug",
6910 "rpc_createerr",
6911# Other C structures appearing in every dump
6912 "timespec",
6913 "random_data",
6914 "drand48_data",
6915 "_IO_marker",
6916 "_IO_FILE",
6917 "lconv",
6918 "sched_param",
6919 "tm",
6920 "itimerspec",
6921 "_pthread_cleanup_buffer",
6922 "fd_set",
6923 "siginfo"
6924);
6925
6926sub getCompileCmd($$$)
6927{
6928 my ($Path, $Opt, $Inc) = @_;
6929 my $GccCall = $GCC_PATH;
6930 if($Opt) {
6931 $GccCall .= " ".$Opt;
6932 }
6933 $GccCall .= " -x ";
6934 if($OSgroup eq "macos") {
6935 $GccCall .= "objective-";
6936 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04006937 if(check_gcc($GCC_PATH, "4"))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006938 { # compile as "C++" header
6939 # to obtain complete dump using GCC 4.0
6940 $GccCall .= "c++-header";
6941 }
6942 else
6943 { # compile as "C++" source
6944 # GCC 3.3 cannot compile headers
6945 $GccCall .= "c++";
6946 }
6947 if(my $Opts = platformSpecs($Version))
6948 {# platform-specific options
6949 $GccCall .= " ".$Opts;
6950 }
6951 # allow extra qualifications
6952 # and other nonconformant code
6953 $GccCall .= " -fpermissive -w";
6954 if($NoStdInc)
6955 {
6956 $GccCall .= " -nostdinc";
6957 $GccCall .= " -nostdinc++";
6958 }
6959 if($CompilerOptions{$Version})
6960 { # user-defined options
6961 $GccCall .= " ".$CompilerOptions{$Version};
6962 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04006963 $GccCall .= " \"".$Path."\"";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006964 if($Inc)
6965 { # include paths
6966 $GccCall .= " ".$Inc;
6967 }
6968 return $GccCall;
6969}
6970
6971sub getDump()
6972{
6973 if(not $GCC_PATH) {
6974 exitStatus("Error", "internal error - GCC path is not set");
6975 }
6976 my %HeaderElems = (
6977 # Types
6978 "stdio.h" => ["FILE", "va_list"],
Andrey Ponomarenko85043792012-05-14 16:48:07 +04006979 "stddef.h" => ["NULL", "ptrdiff_t"],
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006980 "stdint.h" => ["uint32_t", "int32_t", "uint64_t"],
6981 "time.h" => ["time_t"],
6982 "sys/types.h" => ["ssize_t", "u_int32_t", "u_short", "u_char",
6983 "u_int", "off_t", "u_quad_t", "u_long", "size_t", "mode_t"],
6984 "unistd.h" => ["gid_t", "uid_t"],
6985 "stdbool.h" => ["_Bool"],
6986 "rpc/xdr.h" => ["bool_t"],
6987 "in_systm.h" => ["n_long", "n_short"],
6988 # Fields
Andrey Ponomarenkobede8372012-03-29 17:43:21 +04006989 "arpa/inet.h" => ["fw_src", "ip_src"],
6990 # Functions
6991 "stdlib.h" => ["free", "malloc"],
Andrey Ponomarenko85043792012-05-14 16:48:07 +04006992 "string.h" => ["memmove", "strcmp"]
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006993 );
6994 my %AutoPreamble = ();
Andrey Ponomarenko85043792012-05-14 16:48:07 +04006995 foreach (keys(%HeaderElems))
6996 {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006997 foreach my $Elem (@{$HeaderElems{$_}}) {
6998 $AutoPreamble{$Elem}=$_;
6999 }
7000 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04007001 my $TmpHeaderPath = $TMP_DIR."/dump".$Version.".h";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007002 my $MHeaderPath = $TmpHeaderPath;
Andrey Ponomarenko85043792012-05-14 16:48:07 +04007003 open(TMP_HEADER, ">", $TmpHeaderPath) || die ("can't open file \'$TmpHeaderPath\': $!\n");
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007004 if(my $AddDefines = $Descriptor{$Version}{"Defines"})
7005 {
7006 $AddDefines=~s/\n\s+/\n /g;
Andrey Ponomarenko85043792012-05-14 16:48:07 +04007007 print TMP_HEADER "\n // add defines\n ".$AddDefines."\n";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007008 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +04007009 print TMP_HEADER "\n // add includes\n";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007010 my @PreambleHeaders = keys(%{$Include_Preamble{$Version}});
7011 @PreambleHeaders = sort {int($Include_Preamble{$Version}{$a}{"Position"})<=>int($Include_Preamble{$Version}{$b}{"Position"})} @PreambleHeaders;
7012 foreach my $Header_Path (@PreambleHeaders) {
Andrey Ponomarenko85043792012-05-14 16:48:07 +04007013 print TMP_HEADER " #include \"".path_format($Header_Path, "unix")."\"\n";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007014 }
7015 my @Headers = keys(%{$Registered_Headers{$Version}});
7016 @Headers = sort {int($Registered_Headers{$Version}{$a}{"Pos"})<=>int($Registered_Headers{$Version}{$b}{"Pos"})} @Headers;
7017 foreach my $Header_Path (@Headers)
7018 {
7019 next if($Include_Preamble{$Version}{$Header_Path});
Andrey Ponomarenko85043792012-05-14 16:48:07 +04007020 print TMP_HEADER " #include \"".path_format($Header_Path, "unix")."\"\n";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007021 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +04007022 close(TMP_HEADER);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007023 my $IncludeString = getIncString(getIncPaths(@PreambleHeaders, @Headers), "GCC");
7024 if($Debug)
7025 { # debug mode
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04007026 writeFile($DEBUG_PATH{$Version}."/headers/direct-includes.txt", Dumper($Header_Includes{$Version}));
7027 writeFile($DEBUG_PATH{$Version}."/headers/recursive-includes.txt", Dumper($RecursiveIncludes{$Version}));
7028 writeFile($DEBUG_PATH{$Version}."/headers/include-paths.txt", Dumper($Cache{"get_HeaderDeps"}{$Version}));
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04007029 writeFile($DEBUG_PATH{$Version}."/headers/default-paths.txt", Dumper(\%DefaultIncPaths));
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007030 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +04007031
7032 # Target headers
7033 addTargetHeaders($Version);
7034
7035 # clean memory
7036 %RecursiveIncludes = ();
7037 %Header_Include_Prefix = ();
7038 %Header_Includes = ();
7039
7040 # clean cache
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04007041 delete($Cache{"identifyHeader"});
Andrey Ponomarenko85043792012-05-14 16:48:07 +04007042 delete($Cache{"detect_header_includes"});
7043 delete($Cache{"selectSystemHeader"});
7044
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007045 # preprocessing stage
7046 checkPreprocessedUnit(callPreprocessor($TmpHeaderPath, $IncludeString, $Version));
Andrey Ponomarenko85043792012-05-14 16:48:07 +04007047
7048 # clean memory
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04007049 delete($Include_Neighbors{$Version});
Andrey Ponomarenko85043792012-05-14 16:48:07 +04007050
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007051 my $MContent = "";
7052 my $PreprocessCmd = getCompileCmd($TmpHeaderPath, "-E", $IncludeString);
7053 if($OStarget eq "windows"
7054 and get_dumpmachine($GCC_PATH)=~/mingw/i
7055 and $MinGWMode{$Version}!=-1)
7056 { # modify headers to compile by MinGW
7057 if(not $MContent)
7058 { # preprocessing
7059 $MContent = `$PreprocessCmd 2>$TMP_DIR/null`;
7060 }
7061 if($MContent=~s/__asm\s*(\{[^{}]*?\}|[^{};]*)//g)
7062 { # __asm { ... }
7063 $MinGWMode{$Version}=1;
7064 }
7065 if($MContent=~s/\s+(\/ \/.*?)\n/\n/g)
7066 { # comments after preprocessing
7067 $MinGWMode{$Version}=1;
7068 }
7069 if($MContent=~s/(\W)(0x[a-f]+|\d+)(i|ui)(8|16|32|64)(\W)/$1$2$5/g)
7070 { # 0xffui8
7071 $MinGWMode{$Version}=1;
7072 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +04007073 if($MinGWMode{$Version})
7074 {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007075 printMsg("INFO", "Using MinGW compatibility mode");
7076 $MHeaderPath = "$TMP_DIR/dump$Version.i";
7077 }
7078 }
7079 if(($COMMON_LANGUAGE{$Version} eq "C" or $CheckHeadersOnly)
7080 and $C99Mode{$Version}!=-1 and not $Cpp2003)
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04007081 { # rename C++ keywords in C code
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007082 if(not $MContent)
7083 { # preprocessing
7084 $MContent = `$PreprocessCmd 2>$TMP_DIR/null`;
7085 }
7086 my $RegExp_C = join("|", keys(%CppKeywords_C));
7087 my $RegExp_F = join("|", keys(%CppKeywords_F));
7088 my $RegExp_O = join("|", keys(%CppKeywords_O));
7089 while($MContent=~s/(\A|\n[^\#\/\n][^\n]*?|\n)(\*\s*|\s+|\@|\,|\()($RegExp_C|$RegExp_F)(\s*(\,|\)|\;|\-\>|\.|\:\s*\d))/$1$2c99_$3$4/g)
7090 { # MATCH:
7091 # int foo(int new, int class, int (*new)(int));
7092 # unsigned private: 8;
7093 # DO NOT MATCH:
7094 # #pragma GCC visibility push(default)
7095 $C99Mode{$Version} = 1;
7096 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04007097 if($MContent=~s/([^\w\s]|\w\s+)(?<!operator )(delete)(\s*\()/$1c99_$2$3/g)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007098 { # MATCH:
7099 # int delete(...);
7100 # int explicit(...);
7101 # DO NOT MATCH:
7102 # void operator delete(...)
7103 $C99Mode{$Version} = 1;
7104 }
7105 if($MContent=~s/(\s+)($RegExp_O)(\s*(\;|\:))/$1c99_$2$3/g)
7106 { # MATCH:
7107 # int bool;
7108 # DO NOT MATCH:
7109 # bool X;
7110 # return *this;
7111 # throw;
7112 $C99Mode{$Version} = 1;
7113 }
7114 if($MContent=~s/(\s+)(operator)(\s*(\(\s*\)\s*[^\(\s]|\(\s*[^\)\s]))/$1c99_$2$3/g)
7115 { # MATCH:
7116 # int operator(...);
7117 # DO NOT MATCH:
7118 # int operator()(...);
7119 $C99Mode{$Version} = 1;
7120 }
7121 if($MContent=~s/([^\w\(\,\s]\s*|\s+)(operator)(\s*(\,\s*[^\(\s]|\)))/$1c99_$2$3/g)
7122 { # MATCH:
7123 # int foo(int operator);
7124 # int foo(int operator, int other);
7125 # DO NOT MATCH:
7126 # int operator,(...);
7127 $C99Mode{$Version} = 1;
7128 }
7129 if($MContent=~s/(\*\s*|\w\s+)(bool)(\s*(\,|\)))/$1c99_$2$3/g)
7130 { # MATCH:
7131 # int foo(gboolean *bool);
7132 # DO NOT MATCH:
7133 # void setTabEnabled(int index, bool);
7134 $C99Mode{$Version} = 1;
7135 }
7136 if($MContent=~s/(\w)([^\w\(\,\s]\s*|\s+)(this)(\s*(\,|\)))/$1$2c99_$3$4/g)
7137 { # MATCH:
7138 # int foo(int* this);
7139 # int bar(int this);
7140 # DO NOT MATCH:
7141 # baz(X, this);
7142 $C99Mode{$Version} = 1;
7143 }
7144 if($C99Mode{$Version}==1)
7145 { # try to change C++ "keyword" to "c99_keyword"
7146 printMsg("INFO", "Using C99 compatibility mode");
7147 $MHeaderPath = "$TMP_DIR/dump$Version.i";
7148 }
7149 }
7150 if($C99Mode{$Version}==1
7151 or $MinGWMode{$Version}==1)
7152 { # compile the corrected preprocessor output
7153 writeFile($MHeaderPath, $MContent);
7154 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +04007155
7156 # clean memory
7157 undef $MContent;
7158
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007159 if($COMMON_LANGUAGE{$Version} eq "C++")
7160 { # add classes and namespaces to the dump
7161 my $CHdump = "-fdump-class-hierarchy -c";
7162 if($C99Mode{$Version}==1
7163 or $MinGWMode{$Version}==1) {
7164 $CHdump .= " -fpreprocessed";
7165 }
7166 my $ClassHierarchyCmd = getCompileCmd($MHeaderPath, $CHdump, $IncludeString);
7167 chdir($TMP_DIR);
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04007168 system($ClassHierarchyCmd." >null 2>&1");
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007169 chdir($ORIG_DIR);
7170 if(my $ClassDump = (cmd_find($TMP_DIR,"f","*.class",1))[0])
7171 {
7172 my %AddClasses = ();
7173 my $Content = readFile($ClassDump);
7174 foreach my $ClassInfo (split(/\n\n/, $Content))
7175 {
7176 if($ClassInfo=~/\AClass\s+(.+)\s*/i)
7177 {
7178 my $CName = $1;
7179 next if($CName=~/\A(__|_objc_|_opaque_)/);
7180 $TUnit_NameSpaces{$Version}{$CName} = -1;
7181 if($CName=~/\A[\w:]+\Z/)
7182 { # classes
7183 $AddClasses{$CName} = 1;
7184 }
7185 if($CName=~/(\w[\w:]*)::/)
7186 { # namespaces
7187 my $NS = $1;
7188 if(not defined $TUnit_NameSpaces{$Version}{$NS}) {
7189 $TUnit_NameSpaces{$Version}{$NS} = 1;
7190 }
7191 }
7192 }
7193 elsif($ClassInfo=~/\AVtable\s+for\s+(.+)\n((.|\n)+)\Z/i)
7194 { # read v-tables (advanced approach)
7195 my ($CName, $VTable) = ($1, $2);
7196 $ClassVTable_Content{$Version}{$CName} = $VTable;
7197 }
7198 }
7199 if($Debug)
7200 { # debug mode
7201 mkpath($DEBUG_PATH{$Version});
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04007202 copy($ClassDump, $DEBUG_PATH{$Version}."/class-hierarchy-dump.txt");
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007203 }
7204 unlink($ClassDump);
7205 if(my $NS_Add = get_namespace_additions($TUnit_NameSpaces{$Version}))
7206 { # GCC on all supported platforms does not include namespaces to the dump by default
7207 appendFile($MHeaderPath, "\n // add namespaces\n".$NS_Add);
7208 }
7209 # some GCC versions don't include class methods to the TU dump by default
7210 my ($AddClass, $ClassNum) = ("", 0);
7211 foreach my $CName (sort keys(%AddClasses))
7212 {
7213 next if($C_Structure{$CName});
7214 next if(not $STDCXX_TESTING and $CName=~/\Astd::/);
7215 next if(($CName=~tr![:]!!)>2);
7216 next if($SkipTypes{$Version}{$CName});
7217 if($CName=~/\A(.+)::[^:]+\Z/
7218 and $AddClasses{$1}) {
7219 next;
7220 }
7221 $AddClass .= " $CName* tmp_add_class_".($ClassNum++).";\n";
7222 }
7223 appendFile($MHeaderPath, "\n // add classes\n".$AddClass);
7224 }
7225 }
7226 writeLog($Version, "Temporary header file \'$TmpHeaderPath\' with the following content will be compiled to create GCC translation unit dump:\n".readFile($TmpHeaderPath)."\n");
7227 # create TU dump
7228 my $TUdump = "-fdump-translation-unit -fkeep-inline-functions -c";
7229 if($C99Mode{$Version}==1
7230 or $MinGWMode{$Version}==1) {
7231 $TUdump .= " -fpreprocessed";
7232 }
7233 my $SyntaxTreeCmd = getCompileCmd($MHeaderPath, $TUdump, $IncludeString);
7234 writeLog($Version, "The GCC parameters:\n $SyntaxTreeCmd\n\n");
7235 chdir($TMP_DIR);
7236 system($SyntaxTreeCmd." >$TMP_DIR/tu_errors 2>&1");
7237 if($?)
7238 { # failed to compile, but the TU dump still can be created
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04007239 my $Errors = readFile($TMP_DIR."/tu_errors");
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007240 if($Errors=~/c99_/)
7241 { # disable c99 mode
7242 $C99Mode{$Version}=-1;
7243 printMsg("INFO", "Disabling C99 compatibility mode");
7244 resetLogging($Version);
7245 $TMP_DIR = tempdir(CLEANUP=>1);
7246 return getDump();
7247 }
7248 elsif($AutoPreambleMode{$Version}!=-1
7249 and my $TErrors = $Errors)
7250 {
7251 my %Types = ();
7252 while($TErrors=~s/error\:\s*(field\s*|)\W+(.+?)\W+//)
7253 { # error: 'FILE' has not been declared
7254 $Types{$2}=1;
7255 }
7256 my %AddHeaders = ();
7257 foreach my $Type (keys(%Types))
7258 {
7259 if(my $Header = $AutoPreamble{$Type}) {
7260 $AddHeaders{path_format($Header, $OSgroup)}=$Type;
7261 }
7262 }
7263 if(my @Headers = sort {$b cmp $a} keys(%AddHeaders))
7264 { # sys/types.h should be the first
7265 foreach my $Num (0 .. $#Headers)
7266 {
7267 my $Name = $Headers[$Num];
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04007268 if(my $Path = identifyHeader($Name, $Version))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007269 { # add automatic preamble headers
7270 if(defined $Include_Preamble{$Version}{$Path})
7271 { # already added
7272 next;
7273 }
7274 $Include_Preamble{$Version}{$Path}{"Position"} = keys(%{$Include_Preamble{$Version}});
7275 my $Type = $AddHeaders{$Name};
7276 printMsg("INFO", "Add \'$Name\' preamble header for \'$Type\'");
7277 }
7278 }
7279 $AutoPreambleMode{$Version}=-1;
7280 resetLogging($Version);
7281 $TMP_DIR = tempdir(CLEANUP=>1);
7282 return getDump();
7283 }
7284 }
7285 elsif($MinGWMode{$Version}!=-1)
7286 {
7287 $MinGWMode{$Version}=-1;
7288 resetLogging($Version);
7289 $TMP_DIR = tempdir(CLEANUP=>1);
7290 return getDump();
7291 }
7292 # FIXME: handle other errors and try to recompile
7293 writeLog($Version, $Errors);
7294 printMsg("ERROR", "some errors occurred when compiling headers");
7295 printErrorLog($Version);
7296 $COMPILE_ERRORS = $ERROR_CODE{"Compile_Error"};
7297 writeLog($Version, "\n");# new line
7298 }
7299 chdir($ORIG_DIR);
7300 unlink($TmpHeaderPath, $MHeaderPath);
7301 return (cmd_find($TMP_DIR,"f","*.tu",1))[0];
7302}
7303
7304sub cmd_file($)
7305{
7306 my $Path = $_[0];
7307 return "" if(not $Path or not -e $Path);
7308 if(my $CmdPath = get_CmdPath("file")) {
7309 return `$CmdPath -b \"$Path\"`;
7310 }
7311 return "";
7312}
7313
7314sub getIncString($$)
7315{
7316 my ($ArrRef, $Style) = @_;
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04007317 return "" if(not $ArrRef or $#{$ArrRef}<0);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007318 my $String = "";
7319 foreach (@{$ArrRef}) {
7320 $String .= " ".inc_opt($_, $Style);
7321 }
7322 return $String;
7323}
7324
7325sub getIncPaths(@)
7326{
7327 my @HeaderPaths = @_;
7328 my @IncPaths = ();
7329 if($INC_PATH_AUTODETECT{$Version})
7330 { # auto-detecting dependencies
7331 my %Includes = ();
7332 foreach my $HPath (@HeaderPaths)
7333 {
7334 foreach my $Dir (get_HeaderDeps($HPath, $Version))
7335 {
7336 if($Skip_Include_Paths{$Version}{$Dir}) {
7337 next;
7338 }
7339 $Includes{$Dir}=1;
7340 }
7341 }
7342 foreach my $Dir (keys(%{$Add_Include_Paths{$Version}}))
7343 { # added by user
7344 next if($Includes{$Dir});
7345 push(@IncPaths, $Dir);
7346 }
7347 foreach my $Dir (@{sortIncPaths([keys(%Includes)], $Version)}) {
7348 push(@IncPaths, $Dir);
7349 }
7350 }
7351 else
7352 { # user-defined paths
7353 foreach my $Dir (sort {get_depth($a)<=>get_depth($b)}
7354 sort {$b cmp $a} keys(%{$Include_Paths{$Version}})) {
7355 push(@IncPaths, $Dir);
7356 }
7357 }
7358 return \@IncPaths;
7359}
7360
7361sub callPreprocessor($$$)
7362{
7363 my ($Path, $Inc, $LibVersion) = @_;
7364 return "" if(not $Path or not -f $Path);
7365 my $IncludeString=$Inc;
7366 if(not $Inc) {
7367 $IncludeString = getIncString(getIncPaths($Path), "GCC");
7368 }
7369 my $Cmd = getCompileCmd($Path, "-dD -E", $IncludeString);
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04007370 my $Out = $TMP_DIR."/preprocessed";
7371 system($Cmd." >$Out 2>$TMP_DIR/null");
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04007372 return $Out;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007373}
7374
7375sub cmd_find($$$$)
7376{ # native "find" is much faster than File::Find (~6x)
7377 # also the File::Find doesn't support --maxdepth N option
7378 # so using the cross-platform wrapper for the native one
7379 my ($Path, $Type, $Name, $MaxDepth) = @_;
7380 return () if(not $Path or not -e $Path);
7381 if($OSgroup eq "windows")
7382 {
7383 my $DirCmd = get_CmdPath("dir");
7384 if(not $DirCmd) {
7385 exitStatus("Not_Found", "can't find \"dir\" command");
7386 }
7387 $Path=~s/[\\]+\Z//;
7388 $Path = get_abs_path($Path);
7389 $Path = path_format($Path, $OSgroup);
7390 my $Cmd = $DirCmd." \"$Path\" /B /O";
7391 if($MaxDepth!=1) {
7392 $Cmd .= " /S";
7393 }
7394 if($Type eq "d") {
7395 $Cmd .= " /AD";
7396 }
7397 my @Files = ();
7398 if($Name)
7399 { # FIXME: how to search file names in MS shell?
7400 $Name=~s/\*/.*/g if($Name!~/\]/);
7401 foreach my $File (split(/\n/, `$Cmd`))
7402 {
7403 if($File=~/$Name\Z/i) {
7404 push(@Files, $File);
7405 }
7406 }
7407 }
7408 else {
7409 @Files = split(/\n/, `$Cmd 2>$TMP_DIR/null`);
7410 }
7411 my @AbsPaths = ();
7412 foreach my $File (@Files)
7413 {
7414 if(not is_abs($File)) {
7415 $File = joinPath($Path, $File);
7416 }
7417 if($Type eq "f" and not -f $File)
7418 { # skip dirs
7419 next;
7420 }
7421 push(@AbsPaths, path_format($File, $OSgroup));
7422 }
7423 if($Type eq "d") {
7424 push(@AbsPaths, $Path);
7425 }
7426 return @AbsPaths;
7427 }
7428 else
7429 {
7430 my $FindCmd = get_CmdPath("find");
7431 if(not $FindCmd) {
7432 exitStatus("Not_Found", "can't find a \"find\" command");
7433 }
7434 $Path = get_abs_path($Path);
7435 if(-d $Path and -l $Path
7436 and $Path!~/\/\Z/)
7437 { # for directories that are symlinks
7438 $Path.="/";
7439 }
7440 my $Cmd = $FindCmd." \"$Path\"";
7441 if($MaxDepth) {
7442 $Cmd .= " -maxdepth $MaxDepth";
7443 }
7444 if($Type) {
7445 $Cmd .= " -type $Type";
7446 }
7447 if($Name)
7448 { # file name
7449 if($Name=~/\]/) {
7450 $Cmd .= " -regex \"$Name\"";
7451 }
7452 else {
7453 $Cmd .= " -name \"$Name\"";
7454 }
7455 }
7456 return split(/\n/, `$Cmd 2>$TMP_DIR/null`);
7457 }
7458}
7459
7460sub unpackDump($)
7461{
7462 my $Path = $_[0];
7463 return "" if(not $Path or not -e $Path);
7464 $Path = get_abs_path($Path);
7465 $Path = path_format($Path, $OSgroup);
7466 my ($Dir, $FileName) = separate_path($Path);
7467 my $UnpackDir = $TMP_DIR."/unpack";
7468 rmtree($UnpackDir);
7469 mkpath($UnpackDir);
7470 if($FileName=~s/\Q.zip\E\Z//g)
7471 { # *.zip
7472 my $UnzipCmd = get_CmdPath("unzip");
7473 if(not $UnzipCmd) {
7474 exitStatus("Not_Found", "can't find \"unzip\" command");
7475 }
7476 chdir($UnpackDir);
7477 system("$UnzipCmd \"$Path\" >$UnpackDir/contents.txt");
7478 if($?) {
7479 exitStatus("Error", "can't extract \'$Path\'");
7480 }
7481 chdir($ORIG_DIR);
7482 my @Contents = ();
7483 foreach (split("\n", readFile("$UnpackDir/contents.txt")))
7484 {
7485 if(/inflating:\s*([^\s]+)/) {
7486 push(@Contents, $1);
7487 }
7488 }
7489 if(not @Contents) {
7490 exitStatus("Error", "can't extract \'$Path\'");
7491 }
7492 return joinPath($UnpackDir, $Contents[0]);
7493 }
7494 elsif($FileName=~s/\Q.tar.gz\E\Z//g)
7495 { # *.tar.gz
7496 if($OSgroup eq "windows")
7497 { # -xvzf option is not implemented in tar.exe (2003)
7498 # use "gzip.exe -k -d -f" + "tar.exe -xvf" instead
7499 my $TarCmd = get_CmdPath("tar");
7500 if(not $TarCmd) {
7501 exitStatus("Not_Found", "can't find \"tar\" command");
7502 }
7503 my $GzipCmd = get_CmdPath("gzip");
7504 if(not $GzipCmd) {
7505 exitStatus("Not_Found", "can't find \"gzip\" command");
7506 }
7507 chdir($UnpackDir);
7508 system("$GzipCmd -k -d -f \"$Path\"");# keep input files (-k)
7509 if($?) {
7510 exitStatus("Error", "can't extract \'$Path\'");
7511 }
7512 system("$TarCmd -xvf \"$Dir\\$FileName.tar\" >$UnpackDir/contents.txt");
7513 if($?) {
7514 exitStatus("Error", "can't extract \'$Path\'");
7515 }
7516 chdir($ORIG_DIR);
7517 unlink($Dir."/".$FileName.".tar");
7518 my @Contents = split("\n", readFile("$UnpackDir/contents.txt"));
7519 if(not @Contents) {
7520 exitStatus("Error", "can't extract \'$Path\'");
7521 }
7522 return joinPath($UnpackDir, $Contents[0]);
7523 }
7524 else
7525 { # Unix
7526 my $TarCmd = get_CmdPath("tar");
7527 if(not $TarCmd) {
7528 exitStatus("Not_Found", "can't find \"tar\" command");
7529 }
7530 chdir($UnpackDir);
7531 system("$TarCmd -xvzf \"$Path\" >$UnpackDir/contents.txt");
7532 if($?) {
7533 exitStatus("Error", "can't extract \'$Path\'");
7534 }
7535 chdir($ORIG_DIR);
7536 # The content file name may be different
7537 # from the package file name
7538 my @Contents = split("\n", readFile("$UnpackDir/contents.txt"));
7539 if(not @Contents) {
7540 exitStatus("Error", "can't extract \'$Path\'");
7541 }
7542 return joinPath($UnpackDir, $Contents[0]);
7543 }
7544 }
7545}
7546
7547sub createArchive($$)
7548{
7549 my ($Path, $To) = @_;
7550 if(not $Path or not -e $Path
7551 or not -d $To) {
7552 return "";
7553 }
7554 my ($From, $Name) = separate_path($Path);
7555 if($OSgroup eq "windows")
7556 { # *.zip
7557 my $ZipCmd = get_CmdPath("zip");
7558 if(not $ZipCmd) {
7559 exitStatus("Not_Found", "can't find \"zip\"");
7560 }
7561 my $Pkg = $To."/".$Name.".zip";
7562 unlink($Pkg);
7563 chdir($To);
7564 system("$ZipCmd -j \"$Name.zip\" \"$Path\" >$TMP_DIR/null");
7565 if($?)
7566 { # cannot allocate memory (or other problems with "zip")
7567 unlink($Path);
7568 exitStatus("Error", "can't pack the ABI dump: ".$!);
7569 }
7570 chdir($ORIG_DIR);
7571 unlink($Path);
7572 return $Pkg;
7573 }
7574 else
7575 { # *.tar.gz
7576 my $TarCmd = get_CmdPath("tar");
7577 if(not $TarCmd) {
7578 exitStatus("Not_Found", "can't find \"tar\"");
7579 }
7580 my $GzipCmd = get_CmdPath("gzip");
7581 if(not $GzipCmd) {
7582 exitStatus("Not_Found", "can't find \"gzip\"");
7583 }
7584 my $Pkg = abs_path($To)."/".$Name.".tar.gz";
7585 unlink($Pkg);
7586 chdir($From);
7587 system($TarCmd, "-czf", $Pkg, $Name);
7588 if($?)
7589 { # cannot allocate memory (or other problems with "tar")
7590 unlink($Path);
7591 exitStatus("Error", "can't pack the ABI dump: ".$!);
7592 }
7593 chdir($ORIG_DIR);
7594 unlink($Path);
7595 return $To."/".$Name.".tar.gz";
7596 }
7597}
7598
7599sub is_header_file($)
7600{
7601 if($_[0]=~/\.($HEADER_EXT)\Z/i) {
7602 return $_[0];
7603 }
7604 return 0;
7605}
7606
7607sub is_not_header($)
7608{
7609 if($_[0]=~/\.\w+\Z/
7610 and $_[0]!~/\.($HEADER_EXT)\Z/i) {
7611 return 1;
7612 }
7613 return 0;
7614}
7615
7616sub is_header($$$)
7617{
7618 my ($Header, $UserDefined, $LibVersion) = @_;
7619 return 0 if(-d $Header);
7620 if(-f $Header) {
7621 $Header = get_abs_path($Header);
7622 }
7623 else
7624 {
7625 if(is_abs($Header))
7626 { # incorrect absolute path
7627 return 0;
7628 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04007629 if(my $HPath = identifyHeader($Header, $LibVersion)) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007630 $Header = $HPath;
7631 }
7632 else
7633 { # can't find header
7634 return 0;
7635 }
7636 }
7637 if($Header=~/\.\w+\Z/)
7638 { # have an extension
7639 return is_header_file($Header);
7640 }
7641 else
7642 {
7643 if($UserDefined==2)
7644 { # specified on the command line
7645 if(cmd_file($Header)!~/HTML|XML/i) {
7646 return $Header;
7647 }
7648 }
7649 elsif($UserDefined)
7650 { # specified in the XML-descriptor
7651 # header file without an extension
7652 return $Header;
7653 }
7654 else
7655 {
Andrey Ponomarenko85043792012-05-14 16:48:07 +04007656 if($Header=~/\/include\//
7657 or cmd_file($Header)=~/C[\+]*\s+program/i)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007658 { # !~/HTML|XML|shared|dynamic/i
7659 return $Header;
7660 }
7661 }
7662 }
7663 return 0;
7664}
7665
Andrey Ponomarenko16934472012-03-29 15:37:04 +04007666sub addTargetHeaders($)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007667{
7668 my $LibVersion = $_[0];
7669 foreach my $RegHeader (keys(%{$Registered_Headers{$LibVersion}}))
7670 {
7671 my $RegDir = get_dirname($RegHeader);
7672 $TargetHeaders{$LibVersion}{get_filename($RegHeader)}=1;
7673 foreach my $RecInc (keys(%{$RecursiveIncludes{$LibVersion}{$RegHeader}}))
7674 {
7675 my $Dir = get_dirname($RecInc);
Andrey Ponomarenko85043792012-05-14 16:48:07 +04007676 if($Dir=~/\A\Q$RegDir\E([\/\\]|\Z)/
7677 or $RecursiveIncludes{$LibVersion}{$RegHeader}{$RecInc}!=1)
7678 { # in the same directory or included by #include "..."
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007679 $TargetHeaders{$LibVersion}{get_filename($RecInc)}=1;
7680 }
7681 }
7682 }
7683}
7684
7685sub readHeaders($)
7686{
7687 $Version = $_[0];
7688 printMsg("INFO", "checking header(s) ".$Descriptor{$Version}{"Version"}." ...");
7689 my $DumpPath = getDump();
7690 if(not $DumpPath) {
7691 exitStatus("Cannot_Compile", "can't compile header(s)");
7692 }
7693 if($Debug)
7694 { # debug mode
7695 mkpath($DEBUG_PATH{$Version});
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04007696 copy($DumpPath, $DEBUG_PATH{$Version}."/translation-unit-dump.txt");
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007697 }
7698 getInfo($DumpPath);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007699}
7700
7701sub prepareTypes($)
7702{
7703 my $LibVersion = $_[0];
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04007704 if(not checkDump($LibVersion, "2.0"))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007705 { # support for old ABI dumps
7706 # type names have been corrected in ACC 1.22 (dump 2.0 format)
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04007707 foreach my $TypeId (keys(%{$TypeInfo{$LibVersion}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007708 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04007709 my $TName = $TypeInfo{$LibVersion}{$TypeId}{"Name"};
7710 if($TName=~/\A(\w+)::(\w+)/) {
7711 my ($P1, $P2) = ($1, $2);
7712 if($P1 eq $P2) {
7713 $TName=~s/\A$P1:\:$P1(\W)/$P1$1/;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007714 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04007715 else {
7716 $TName=~s/\A(\w+:\:)$P2:\:$P2(\W)/$1$P2$2/;
7717 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007718 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04007719 $TypeInfo{$LibVersion}{$TypeId}{"Name"} = $TName;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007720 }
7721 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04007722 if(not checkDump($LibVersion, "2.5"))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007723 { # support for old ABI dumps
7724 # V < 2.5: array size == "number of elements"
7725 # V >= 2.5: array size in bytes
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04007726 foreach my $TypeId (sort {int($a)<=>int($b)} keys(%{$TypeInfo{$LibVersion}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007727 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04007728 my %Type = get_PureType($TypeId, $LibVersion);
7729 if($Type{"Type"} eq "Array")
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007730 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04007731 if($Type{"Size"})
7732 { # array[N]
7733 my %Base = get_OneStep_BaseType($Type{"Tid"}, $LibVersion);
7734 $TypeInfo{$LibVersion}{$TypeId}{"Size"} = $Type{"Size"}*$Base{"Size"};
7735 }
7736 else
7737 { # array[] is a pointer
7738 $TypeInfo{$LibVersion}{$TypeId}{"Size"} = $WORD_SIZE{$LibVersion};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007739 }
7740 }
7741 }
7742 }
7743 my $V2 = ($LibVersion==1)?2:1;
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04007744 if(not checkDump($LibVersion, "2.7"))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007745 { # support for old ABI dumps
7746 # size of "method ptr" corrected in 2.7
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04007747 foreach my $TypeId (sort {int($a)<=>int($b)} keys(%{$TypeInfo{$LibVersion}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007748 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04007749 my %PureType = get_PureType($TypeId, $LibVersion);
7750 if($PureType{"Type"} eq "MethodPtr")
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007751 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04007752 my %Type = get_Type($TypeId, $LibVersion);
7753 my $TypeId_2 = getTypeIdByName($PureType{"Name"}, $V2);
7754 my %Type2 = get_Type($TypeId_2, $V2);
7755 if($Type{"Size"} ne $Type2{"Size"}) {
7756 $TypeInfo{$LibVersion}{$TypeId}{"Size"} = $Type2{"Size"};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007757 }
7758 }
7759 }
7760 }
7761}
7762
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04007763sub prepareSymbols($)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007764{
7765 my $LibVersion = $_[0];
Andrey Ponomarenko16934472012-03-29 15:37:04 +04007766
7767 if(not keys(%{$SymbolInfo{$LibVersion}}))
7768 { # check if input is valid
7769 if(not $ExtendedCheck and not $CheckObjectsOnly)
7770 {
7771 if($CheckHeadersOnly) {
7772 exitStatus("Empty_Set", "the set of public symbols is empty (".$Descriptor{$LibVersion}{"Version"}.")");
7773 }
7774 else {
7775 exitStatus("Empty_Intersection", "the sets of public symbols in headers and libraries have empty intersection (".$Descriptor{$LibVersion}{"Version"}.")");
7776 }
7777 }
7778 }
7779
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007780 my $Remangle = 0;
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04007781 if(not checkDump(1, "2.10")
7782 or not checkDump(2, "2.10"))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007783 { # different formats
7784 $Remangle = 1;
7785 }
7786 if($CheckHeadersOnly)
7787 { # different languages
7788 if($UserLang)
7789 { # --lang=LANG for both versions
7790 if(($UsedDump{1}{"V"} and $UserLang ne $UsedDump{1}{"L"})
7791 or ($UsedDump{2}{"V"} and $UserLang ne $UsedDump{2}{"L"}))
7792 {
7793 if($UserLang eq "C++")
7794 { # remangle symbols
7795 $Remangle = 1;
7796 }
7797 elsif($UserLang eq "C")
7798 { # remove mangling
7799 $Remangle = -1;
7800 }
7801 }
7802 }
7803 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04007804
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04007805 foreach my $InfoId (sort {int($b)<=>int($a)} keys(%{$SymbolInfo{$LibVersion}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007806 { # reverse order: D0, D1, D2, D0 (artificial, GCC < 4.5), C1, C2
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04007807 if(not checkDump($LibVersion, "2.13"))
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04007808 { # support for old ABI dumps
7809 if(defined $SymbolInfo{$LibVersion}{$InfoId}{"Param"})
7810 {
7811 foreach my $P (keys(%{$SymbolInfo{$LibVersion}{$InfoId}{"Param"}}))
7812 {
7813 my $TypeId = $SymbolInfo{$LibVersion}{$InfoId}{"Param"}{$P}{"type"};
7814 my $DVal = $SymbolInfo{$LibVersion}{$InfoId}{"Param"}{$P}{"default"};
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04007815 my $TName = $TypeInfo{$LibVersion}{$TypeId}{"Name"};
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04007816 if(defined $DVal and $DVal ne "")
7817 {
7818 if($TName eq "char") {
7819 $SymbolInfo{$LibVersion}{$InfoId}{"Param"}{$P}{"default"} = chr($DVal);
7820 }
7821 elsif($TName eq "bool") {
7822 $SymbolInfo{$LibVersion}{$InfoId}{"Param"}{$P}{"default"} = $DVal?"true":"false";
7823 }
7824 }
7825 }
7826 }
7827 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04007828 if($SymbolInfo{$LibVersion}{$InfoId}{"Destructor"})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007829 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04007830 if(defined $SymbolInfo{$LibVersion}{$InfoId}{"Param"}
7831 and keys(%{$SymbolInfo{$LibVersion}{$InfoId}{"Param"}})
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04007832 and $SymbolInfo{$LibVersion}{$InfoId}{"Param"}{0}{"name"})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007833 { # support for old GCC < 4.5: skip artificial ~dtor(int __in_chrg)
7834 # + support for old ABI dumps
7835 next;
7836 }
7837 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04007838 my $MnglName = $SymbolInfo{$LibVersion}{$InfoId}{"MnglName"};
Andrey Ponomarenko85043792012-05-14 16:48:07 +04007839 my $ShortName = $SymbolInfo{$LibVersion}{$InfoId}{"ShortName"};
Andrey Ponomarenko16934472012-03-29 15:37:04 +04007840 my $ClassID = $SymbolInfo{$LibVersion}{$InfoId}{"Class"};
Andrey Ponomarenko85043792012-05-14 16:48:07 +04007841 my $Return = $SymbolInfo{$LibVersion}{$InfoId}{"Return"};
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04007842
7843 if(not $MnglName)
7844 { # ABI dumps have no mangled names for C-functions
Andrey Ponomarenko85043792012-05-14 16:48:07 +04007845 $MnglName = $ShortName;
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04007846 $SymbolInfo{$LibVersion}{$InfoId}{"MnglName"} = $MnglName;
7847 }
7848
Andrey Ponomarenko16934472012-03-29 15:37:04 +04007849 my $SRemangle = 0;
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04007850 if(not checkDump(1, "2.12")
7851 or not checkDump(2, "2.12"))
Andrey Ponomarenko16934472012-03-29 15:37:04 +04007852 { # support for old ABI dumps
Andrey Ponomarenko85043792012-05-14 16:48:07 +04007853 if($ShortName eq "operator>>")
7854 {
7855 if(not $SymbolInfo{$LibVersion}{$InfoId}{"Class"})
7856 { # corrected mangling of operator>>
7857 $SRemangle = 1;
7858 }
Andrey Ponomarenko16934472012-03-29 15:37:04 +04007859 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +04007860 if($SymbolInfo{$LibVersion}{$InfoId}{"Data"})
7861 {
7862 if(not $SymbolInfo{$LibVersion}{$InfoId}{"Class"}
7863 and isConstType($Return, $LibVersion) and $MnglName!~/L\d+$ShortName/)
7864 { # corrected mangling of const global data
7865 # some global data is not mangled in the TU dump: qt_sine_table (Qt 4.8)
7866 # and incorrectly mangled by old ACC versions
7867 $SRemangle = 1;
7868 }
Andrey Ponomarenko16934472012-03-29 15:37:04 +04007869 }
7870 }
7871 if($Remangle==1 or $SRemangle==1)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007872 { # support for old ABI dumps: some symbols are not mangled in old dumps
7873 # mangle both sets of symbols (old and new)
7874 # NOTE: remangling all symbols by the same mangler
7875 if($MnglName=~/\A_ZN(V|)K/)
7876 { # mangling may be incorrect on old ABI dumps
7877 # because of absent "Const" attribute
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04007878 $SymbolInfo{$LibVersion}{$InfoId}{"Const"} = 1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007879 }
7880 if($MnglName=~/\A_ZN(K|)V/)
7881 { # mangling may be incorrect on old ABI dumps
7882 # because of absent "Volatile" attribute
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04007883 $SymbolInfo{$LibVersion}{$InfoId}{"Volatile"} = 1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007884 }
Andrey Ponomarenko16934472012-03-29 15:37:04 +04007885 if(($ClassID and $MnglName!~/\A(_Z|\?)/)
7886 or (not $ClassID and $CheckHeadersOnly)
7887 or (not $ClassID and not link_symbol($MnglName, $LibVersion, "-Deps")))
7888 { # support for old ABI dumps, GCC >= 4.0
7889 # remangling all manually mangled symbols
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04007890 if($MnglName = mangle_symbol($InfoId, $LibVersion, "GCC"))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007891 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04007892 $SymbolInfo{$LibVersion}{$InfoId}{"MnglName"} = $MnglName;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007893 $MangledNames{$LibVersion}{$MnglName} = 1;
7894 }
7895 }
7896 }
7897 elsif($Remangle==-1)
7898 { # remove mangling
7899 $MnglName = "";
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04007900 $SymbolInfo{$LibVersion}{$InfoId}{"MnglName"} = "";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007901 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007902 if(not $MnglName) {
7903 next;
7904 }
7905 if(not $CompleteSignature{$LibVersion}{$MnglName}{"MnglName"})
7906 { # NOTE: global data may enter here twice
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04007907 %{$CompleteSignature{$LibVersion}{$MnglName}} = %{$SymbolInfo{$LibVersion}{$InfoId}};
7908
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007909 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04007910 if(not checkDump($LibVersion, "2.6"))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007911 { # support for old dumps
7912 # add "Volatile" attribute
7913 if($MnglName=~/_Z(K|)V/) {
7914 $CompleteSignature{$LibVersion}{$MnglName}{"Volatile"}=1;
7915 }
7916 }
7917 # symbol and its symlink have same signatures
7918 if($SymVer{$LibVersion}{$MnglName}) {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04007919 %{$CompleteSignature{$LibVersion}{$SymVer{$LibVersion}{$MnglName}}} = %{$SymbolInfo{$LibVersion}{$InfoId}};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007920 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +04007921
7922 # clean memory
Andrey Ponomarenko16934472012-03-29 15:37:04 +04007923 delete($SymbolInfo{$LibVersion}{$InfoId});
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007924 }
7925 if($COMMON_LANGUAGE{$LibVersion} eq "C++" or $OSgroup eq "windows") {
7926 translateSymbols(keys(%{$CompleteSignature{$LibVersion}}), $LibVersion);
7927 }
7928 if($ExtendedCheck)
7929 { # --ext option
7930 addExtension($LibVersion);
7931 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +04007932
7933 # clean memory
7934 delete($SymbolInfo{$LibVersion});
7935
7936 foreach my $Symbol (keys(%{$CompleteSignature{$LibVersion}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007937 { # detect allocable classes with public exported constructors
7938 # or classes with auto-generated or inline-only constructors
Andrey Ponomarenko85043792012-05-14 16:48:07 +04007939 if(my $ClassId = $CompleteSignature{$LibVersion}{$Symbol}{"Class"})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007940 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04007941 my $ClassName = $TypeInfo{$LibVersion}{$ClassId}{"Name"};
Andrey Ponomarenko85043792012-05-14 16:48:07 +04007942 if($CompleteSignature{$LibVersion}{$Symbol}{"Constructor"}
7943 and not $CompleteSignature{$LibVersion}{$Symbol}{"InLine"})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007944 { # Class() { ... } will not be exported
Andrey Ponomarenko85043792012-05-14 16:48:07 +04007945 if(not $CompleteSignature{$LibVersion}{$Symbol}{"Private"})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007946 {
Andrey Ponomarenko85043792012-05-14 16:48:07 +04007947 if($CheckHeadersOnly or link_symbol($Symbol, $LibVersion, "-Deps")) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007948 $AllocableClass{$LibVersion}{$ClassName} = 1;
7949 }
7950 }
7951 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +04007952 if(not $CompleteSignature{$LibVersion}{$Symbol}{"Private"})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007953 { # all imported class methods
Andrey Ponomarenko85043792012-05-14 16:48:07 +04007954 if(symbolFilter($Symbol, $LibVersion, "Affected", "Binary"))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007955 {
Andrey Ponomarenko85043792012-05-14 16:48:07 +04007956 if($CheckHeadersOnly)
7957 {
7958 if(not $CompleteSignature{$LibVersion}{$Symbol}{"InLine"}
7959 or $CompleteSignature{$LibVersion}{$Symbol}{"Virt"})
7960 { # all symbols except non-virtual inline
7961 $ClassMethods{"Binary"}{$LibVersion}{$ClassName}{$Symbol} = 1;
7962 }
7963 }
7964 else {
7965 $ClassMethods{"Binary"}{$LibVersion}{$ClassName}{$Symbol} = 1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007966 }
7967 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04007968 if(symbolFilter($Symbol, $LibVersion, "Affected", "Source")) {
Andrey Ponomarenko85043792012-05-14 16:48:07 +04007969 $ClassMethods{"Source"}{$LibVersion}{$ClassName}{$Symbol} = 1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007970 }
7971 }
Andrey Ponomarenko16934472012-03-29 15:37:04 +04007972 $ClassNames{$LibVersion}{$ClassName} = 1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007973 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +04007974 if(my $RetId = $CompleteSignature{$LibVersion}{$Symbol}{"Return"})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007975 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04007976 my %Base = get_BaseType($RetId, $LibVersion);
Andrey Ponomarenko85043792012-05-14 16:48:07 +04007977 if(defined $Base{"Type"}
7978 and $Base{"Type"}=~/Struct|Class/)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007979 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04007980 my $Name = $TypeInfo{$LibVersion}{$Base{"Tid"}}{"Name"};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007981 if($Name=~/<([^<>\s]+)>/)
7982 {
7983 if(my $Tid = getTypeIdByName($1, $LibVersion)) {
7984 $ReturnedClass{$LibVersion}{$Tid} = 1;
7985 }
7986 }
7987 else {
7988 $ReturnedClass{$LibVersion}{$Base{"Tid"}} = 1;
7989 }
7990 }
7991 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +04007992 foreach my $Num (keys(%{$CompleteSignature{$LibVersion}{$Symbol}{"Param"}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007993 {
Andrey Ponomarenko85043792012-05-14 16:48:07 +04007994 my $PId = $CompleteSignature{$LibVersion}{$Symbol}{"Param"}{$Num}{"type"};
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04007995 if(get_PLevel($PId, $LibVersion)>=1)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007996 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04007997 if(my %Base = get_BaseType($PId, $LibVersion))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007998 {
Andrey Ponomarenko16934472012-03-29 15:37:04 +04007999 if($Base{"Type"}=~/Struct|Class/)
8000 {
Andrey Ponomarenko85043792012-05-14 16:48:07 +04008001 $ParamClass{$LibVersion}{$Base{"Tid"}}{$Symbol} = 1;
Andrey Ponomarenko16934472012-03-29 15:37:04 +04008002 foreach my $SubId (get_sub_classes($Base{"Tid"}, $LibVersion, 1))
8003 { # mark all derived classes
Andrey Ponomarenko85043792012-05-14 16:48:07 +04008004 $ParamClass{$LibVersion}{$SubId}{$Symbol} = 1;
Andrey Ponomarenko16934472012-03-29 15:37:04 +04008005 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008006 }
8007 }
8008 }
8009 }
8010 }
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04008011 foreach my $MnglName (keys(%VTableClass))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008012 { # reconstruct header name for v-tables
8013 if($MnglName=~/\A_ZTV/)
8014 {
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04008015 if(my $ClassName = $VTableClass{$MnglName})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008016 {
8017 if(my $ClassId = $TName_Tid{$LibVersion}{$ClassName}) {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04008018 $CompleteSignature{$LibVersion}{$MnglName}{"Header"} = $TypeInfo{$LibVersion}{$ClassId}{"Header"};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008019 }
8020 }
8021 }
8022 }
Andrey Ponomarenko16934472012-03-29 15:37:04 +04008023
8024 # types
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04008025 foreach my $TypeId (keys(%{$TypeInfo{$LibVersion}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008026 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04008027 if(my $TName = $TypeInfo{$LibVersion}{$TypeId}{"Name"})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008028 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04008029 if(defined $TypeInfo{$LibVersion}{$TypeId}{"VTable"}) {
8030 $ClassNames{$LibVersion}{$TName} = 1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008031 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04008032 if(defined $TypeInfo{$LibVersion}{$TypeId}{"Base"})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008033 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04008034 $ClassNames{$LibVersion}{$TName} = 1;
8035 foreach my $Bid (keys(%{$TypeInfo{$LibVersion}{$TypeId}{"Base"}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008036 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04008037 if(my $BName = $TypeInfo{$LibVersion}{$Bid}{"Name"}) {
8038 $ClassNames{$LibVersion}{$BName} = 1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008039 }
8040 }
8041 }
8042 }
8043 }
8044}
8045
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04008046sub register_TypeUsage($$)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008047{
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04008048 my ($TypeId, $LibVersion) = @_;
8049 if(not $TypeId) {
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04008050 return 0;
8051 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04008052 if($UsedType{$LibVersion}{$TypeId})
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04008053 { # already registered
8054 return 1;
8055 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04008056 my %TInfo = get_Type($TypeId, $LibVersion);
Andrey Ponomarenko85043792012-05-14 16:48:07 +04008057 if($TInfo{"Type"})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008058 {
Andrey Ponomarenko85043792012-05-14 16:48:07 +04008059 if($TInfo{"Type"}=~/\A(Struct|Union|Class|FuncPtr|MethodPtr|FieldPtr|Enum)\Z/)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008060 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04008061 $UsedType{$LibVersion}{$TypeId} = 1;
Andrey Ponomarenko85043792012-05-14 16:48:07 +04008062 if($TInfo{"Type"}=~/\A(Struct|Class)\Z/)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008063 {
Andrey Ponomarenko85043792012-05-14 16:48:07 +04008064 foreach my $BaseId (keys(%{$TInfo{"Base"}}))
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04008065 { # register base classes
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04008066 register_TypeUsage($BaseId, $LibVersion);
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04008067 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +04008068 foreach my $TPos (keys(%{$TInfo{"TParam"}}))
8069 {
8070 my $TPName = $TInfo{"TParam"}{$TPos}{"name"};
8071 if(my $TTid = $TName_Tid{$LibVersion}{$TPName}) {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04008072 register_TypeUsage($TTid, $LibVersion);
Andrey Ponomarenko85043792012-05-14 16:48:07 +04008073 }
8074 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008075 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +04008076 foreach my $Memb_Pos (keys(%{$TInfo{"Memb"}}))
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04008077 {
Andrey Ponomarenko85043792012-05-14 16:48:07 +04008078 if(my $MTid = $TInfo{"Memb"}{$Memb_Pos}{"type"}) {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04008079 register_TypeUsage($MTid, $LibVersion);
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04008080 }
8081 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +04008082 if($TInfo{"Type"} eq "FuncPtr"
8083 or $TInfo{"Type"} eq "MethodPtr")
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04008084 {
Andrey Ponomarenko85043792012-05-14 16:48:07 +04008085 if(my $RTid = $TInfo{"Return"}) {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04008086 register_TypeUsage($RTid, $LibVersion);
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04008087 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +04008088 foreach my $Memb_Pos (keys(%{$TInfo{"Param"}}))
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04008089 {
Andrey Ponomarenko85043792012-05-14 16:48:07 +04008090 if(my $MTid = $TInfo{"Param"}{$Memb_Pos}{"type"}) {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04008091 register_TypeUsage($MTid, $LibVersion);
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04008092 }
8093 }
8094 }
8095 return 1;
8096 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +04008097 elsif($TInfo{"Type"}=~/\A(Const|ConstVolatile|Volatile|Pointer|Ref|Restrict|Array|Typedef)\Z/)
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04008098 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04008099 $UsedType{$LibVersion}{$TypeId} = 1;
8100 register_TypeUsage($TInfo{"BaseType"}{"Tid"}, $LibVersion);
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04008101 return 1;
8102 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04008103 elsif($TInfo{"Type"} eq "Intrinsic")
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04008104 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04008105 $UsedType{$LibVersion}{$TypeId} = 1;
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04008106 return 1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008107 }
8108 }
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04008109 return 0;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008110}
8111
Andrey Ponomarenko85043792012-05-14 16:48:07 +04008112sub selectSymbol($$$$)
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04008113{
Andrey Ponomarenko85043792012-05-14 16:48:07 +04008114 my ($Symbol, $SInfo, $Level, $LibVersion) = @_;
8115
8116 if(not $STDCXX_TESTING and $Symbol=~/\A(_ZS|_ZNS|_ZNKS)/)
8117 { # stdc++ interfaces
8118 return 0;
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04008119 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +04008120
8121 my $Target = 0;
8122 if(my $Header = $SInfo->{"Header"}) {
8123 $Target = (is_target_header($Header, 1) or is_target_header($Header, 2));
8124 }
8125 if($CheckHeadersOnly)
8126 {
8127 if($Target)
8128 {
8129 if($Level eq "Dump")
8130 { # dumped
8131 if($BinaryOnly)
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04008132 {
Andrey Ponomarenko85043792012-05-14 16:48:07 +04008133 if(not $SInfo->{"InLine"} or $SInfo->{"Data"}) {
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04008134 return 1;
8135 }
8136 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +04008137 else {
8138 return 1;
8139 }
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04008140 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +04008141 elsif($Level eq "Source")
8142 { # checked
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04008143 return 1;
8144 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +04008145 elsif($Level eq "Binary")
8146 { # checked
8147 if(not $SInfo->{"InLine"} or $SInfo->{"Data"}
8148 or $SInfo->{"Virt"} or $SInfo->{"PureVirt"}) {
8149 return 1;
8150 }
8151 }
8152 }
8153 }
8154 else
8155 { # library is available
8156 if(link_symbol($Symbol, $LibVersion, "-Deps"))
8157 { # exported symbols
8158 return 1;
8159 }
8160 if($Level eq "Dump")
8161 { # dumped
8162 if(not $BinaryOnly)
8163 { # SrcBin
8164 if($Target) {
8165 return 1;
8166 }
8167 }
8168 if($SInfo->{"Data"})
8169 {
8170 if($Target) {
8171 return 1;
8172 }
8173 }
8174 }
8175 elsif($Level eq "Source")
8176 { # checked
8177 if($Target) {
8178 return 1;
8179 }
8180 }
8181 elsif($Level eq "Binary")
8182 { # checked
8183 if($SInfo->{"PureVirt"} or $SInfo->{"Data"})
8184 {
8185 if($Target) {
8186 return 1;
8187 }
8188 }
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04008189 }
8190 }
8191 return 0;
8192}
8193
Andrey Ponomarenko85043792012-05-14 16:48:07 +04008194sub cleanDump($)
8195{ # clean data
Andrey Ponomarenko16934472012-03-29 15:37:04 +04008196 my $LibVersion = $_[0];
8197 foreach my $InfoId (keys(%{$SymbolInfo{$LibVersion}}))
8198 {
8199 my $MnglName = $SymbolInfo{$LibVersion}{$InfoId}{"MnglName"};
8200 if(not $MnglName) {
8201 delete($SymbolInfo{$LibVersion}{$InfoId});
8202 next;
8203 }
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04008204 my $ShortName = $SymbolInfo{$LibVersion}{$InfoId}{"ShortName"};
Andrey Ponomarenko85043792012-05-14 16:48:07 +04008205 if(not $ShortName) {
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04008206 delete($SymbolInfo{$LibVersion}{$InfoId});
8207 next;
Andrey Ponomarenko16934472012-03-29 15:37:04 +04008208 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +04008209 if($MnglName eq $ShortName)
8210 { # remove duplicate data
8211 delete($SymbolInfo{$LibVersion}{$InfoId}{"MnglName"});
Andrey Ponomarenko16934472012-03-29 15:37:04 +04008212 }
8213 if(not keys(%{$SymbolInfo{$LibVersion}{$InfoId}{"Param"}})) {
8214 delete($SymbolInfo{$LibVersion}{$InfoId}{"Param"});
8215 }
8216 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04008217 foreach my $Tid (keys(%{$TypeInfo{$LibVersion}}))
Andrey Ponomarenko85043792012-05-14 16:48:07 +04008218 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04008219 foreach my $Attr ("Header", "Line", "Size", "NameSpace")
Andrey Ponomarenko16934472012-03-29 15:37:04 +04008220 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04008221 if(not $TypeInfo{$LibVersion}{$Tid}{$Attr}) {
8222 delete($TypeInfo{$LibVersion}{$Tid}{$Attr});
8223 }
8224 }
8225 }
8226}
8227
8228sub selectType($$)
8229{
8230 my ($Tid, $LibVersion) = @_;
8231 if(my $THeader = $TypeInfo{$LibVersion}{$Tid}{"Header"})
8232 {
8233 if(not isBuiltIn($THeader))
8234 {
8235 if($TypeInfo{$LibVersion}{$Tid}{"Type"}=~/Class|Struct|Union|Enum|Typedef/)
Andrey Ponomarenko16934472012-03-29 15:37:04 +04008236 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04008237 if(not isAnon($TypeInfo{$LibVersion}{$Tid}{"Name"}))
8238 {
8239 if(is_target_header($THeader, $LibVersion))
8240 { # from target headers
8241 if(not selfTypedef($Tid, $LibVersion)) {
8242 return 1;
8243 }
8244 }
Andrey Ponomarenko16934472012-03-29 15:37:04 +04008245 }
8246 }
8247 }
8248 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04008249 return 0;
Andrey Ponomarenko16934472012-03-29 15:37:04 +04008250}
8251
Andrey Ponomarenko85043792012-05-14 16:48:07 +04008252sub removeUnused($$)
8253{ # remove unused data types from the ABI dump
8254 my ($LibVersion, $Kind) = @_;
8255 foreach my $InfoId (keys(%{$SymbolInfo{$LibVersion}}))
8256 {
8257 my %FuncInfo = %{$SymbolInfo{$LibVersion}{$InfoId}};
8258 if(my $RTid = $FuncInfo{"Return"}) {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04008259 register_TypeUsage($RTid, $LibVersion);
Andrey Ponomarenko85043792012-05-14 16:48:07 +04008260 }
8261 if(my $FCid = $FuncInfo{"Class"})
8262 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04008263 register_TypeUsage($FCid, $LibVersion);
8264 if(my $ThisId = getTypeIdByName($TypeInfo{$LibVersion}{$FCid}{"Name"}."*const", $LibVersion))
Andrey Ponomarenko85043792012-05-14 16:48:07 +04008265 { # register "this" pointer
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04008266 $UsedType{$LibVersion}{$ThisId} = 1;
8267 if(my %ThisType = get_Type($ThisId, $LibVersion)) {
8268 register_TypeUsage($ThisType{"BaseType"}{"Tid"}, $LibVersion);
Andrey Ponomarenko85043792012-05-14 16:48:07 +04008269 }
8270 }
8271 }
8272 foreach my $PPos (keys(%{$FuncInfo{"Param"}}))
8273 {
8274 if(my $PTid = $FuncInfo{"Param"}{$PPos}{"type"}) {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04008275 register_TypeUsage($PTid, $LibVersion);
Andrey Ponomarenko85043792012-05-14 16:48:07 +04008276 }
8277 }
8278 foreach my $TPos (keys(%{$FuncInfo{"TParam"}}))
8279 {
8280 my $TPName = $FuncInfo{"TParam"}{$TPos}{"name"};
8281 if(my $TTid = $TName_Tid{$LibVersion}{$TPName}) {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04008282 register_TypeUsage($TTid, $LibVersion);
Andrey Ponomarenko85043792012-05-14 16:48:07 +04008283 }
8284 }
8285 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04008286 foreach my $Tid (keys(%{$TypeInfo{$LibVersion}}))
8287 {
8288 if($UsedType{$LibVersion}{$Tid})
8289 { # All & Derived
8290 next;
8291 }
8292
8293 if($Kind eq "Derived")
Andrey Ponomarenko85043792012-05-14 16:48:07 +04008294 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04008295 if(selectType($Tid, $LibVersion)) {
8296 register_TypeUsage($Tid, $LibVersion);
Andrey Ponomarenko85043792012-05-14 16:48:07 +04008297 }
8298 }
8299 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04008300 foreach my $Tid (keys(%{$TypeInfo{$LibVersion}}))
8301 { # remove unused types
8302 if($UsedType{$LibVersion}{$Tid})
8303 { # All & Derived
8304 next;
8305 }
8306 # remove type
8307 delete($TypeInfo{$LibVersion}{$Tid});
8308 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +04008309
8310 # clean memory
8311 %UsedType = ();
8312}
8313
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04008314sub selfTypedef($$)
Andrey Ponomarenko85043792012-05-14 16:48:07 +04008315{
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04008316 my ($TypeId, $LibVersion) = @_;
8317 my %Type = get_Type($TypeId, $LibVersion);
Andrey Ponomarenko85043792012-05-14 16:48:07 +04008318 if($Type{"Type"} eq "Typedef")
8319 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04008320 my %Base = get_OneStep_BaseType($TypeId, $LibVersion);
Andrey Ponomarenko85043792012-05-14 16:48:07 +04008321 if($Base{"Type"}=~/Class|Struct/)
8322 {
8323 if($Type{"Name"} eq $Base{"Name"}) {
8324 return 1;
8325 }
8326 elsif($Type{"Name"}=~/::(\w+)\Z/)
8327 {
8328 if($Type{"Name"} eq $Base{"Name"}."::".$1)
8329 { # QPointer<QWidget>::QPointer
8330 return 1;
8331 }
8332 }
8333 }
8334 }
8335 return 0;
8336}
8337
Andrey Ponomarenko16934472012-03-29 15:37:04 +04008338sub addExtension($)
8339{
8340 my $LibVersion = $_[0];
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04008341 foreach my $Tid (keys(%{$TypeInfo{$LibVersion}}))
Andrey Ponomarenko16934472012-03-29 15:37:04 +04008342 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04008343 if(selectType($Tid, $LibVersion))
Andrey Ponomarenko16934472012-03-29 15:37:04 +04008344 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04008345 my $Symbol = "external_func_".$TypeInfo{$LibVersion}{$Tid}{"Name"};
8346
8347 %{$CompleteSignature{$LibVersion}{$Symbol}} = (
8348 "Header" => "extended.h",
8349 "ShortName" => $Symbol,
8350 "MnglName" => $Symbol,
8351 "Param" => { 0 => { "type"=>$Tid, "name"=>"p1" } }
8352 );
8353
8354 $ExtendedSymbols{$Symbol}=1;
8355 $CheckedSymbols{"Binary"}{$Symbol}=1;
8356 $CheckedSymbols{"Source"}{$Symbol}=1;
Andrey Ponomarenko16934472012-03-29 15:37:04 +04008357 }
8358 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04008359 $ExtendedSymbols{"external_func_0"}=1;
8360 $CheckedSymbols{"Binary"}{"external_func_0"}=1;
8361 $CheckedSymbols{"Source"}{"external_func_0"}=1;
Andrey Ponomarenko16934472012-03-29 15:37:04 +04008362}
8363
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008364sub findMethod($$$)
8365{
8366 my ($VirtFunc, $ClassId, $LibVersion) = @_;
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04008367 foreach my $BaseClass_Id (keys(%{$TypeInfo{$LibVersion}{$ClassId}{"Base"}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008368 {
8369 if(my $VirtMethodInClass = findMethod_Class($VirtFunc, $BaseClass_Id, $LibVersion)) {
8370 return $VirtMethodInClass;
8371 }
8372 elsif(my $VirtMethodInBaseClasses = findMethod($VirtFunc, $BaseClass_Id, $LibVersion)) {
8373 return $VirtMethodInBaseClasses;
8374 }
8375 }
8376 return "";
8377}
8378
8379sub findMethod_Class($$$)
8380{
8381 my ($VirtFunc, $ClassId, $LibVersion) = @_;
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04008382 my $ClassName = $TypeInfo{$LibVersion}{$ClassId}{"Name"};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008383 return "" if(not defined $VirtualTable{$LibVersion}{$ClassName});
8384 my $TargetSuffix = get_symbol_suffix($VirtFunc, 1);
8385 my $TargetShortName = $CompleteSignature{$LibVersion}{$VirtFunc}{"ShortName"};
8386 foreach my $Candidate (keys(%{$VirtualTable{$LibVersion}{$ClassName}}))
8387 { # search for interface with the same parameters suffix (overridden)
8388 if($TargetSuffix eq get_symbol_suffix($Candidate, 1))
8389 {
8390 if($CompleteSignature{$LibVersion}{$VirtFunc}{"Destructor"}) {
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04008391 if($CompleteSignature{$LibVersion}{$Candidate}{"Destructor"})
8392 {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008393 if(($VirtFunc=~/D0E/ and $Candidate=~/D0E/)
8394 or ($VirtFunc=~/D1E/ and $Candidate=~/D1E/)
8395 or ($VirtFunc=~/D2E/ and $Candidate=~/D2E/)) {
8396 return $Candidate;
8397 }
8398 }
8399 }
8400 else {
8401 if($TargetShortName eq $CompleteSignature{$LibVersion}{$Candidate}{"ShortName"}) {
8402 return $Candidate;
8403 }
8404 }
8405 }
8406 }
8407 return "";
8408}
8409
Andrey Ponomarenko16934472012-03-29 15:37:04 +04008410sub registerVTable($)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008411{
Andrey Ponomarenko16934472012-03-29 15:37:04 +04008412 my $LibVersion = $_[0];
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04008413 foreach my $Symbol (keys(%{$CompleteSignature{$LibVersion}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008414 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04008415 if($CompleteSignature{$LibVersion}{$Symbol}{"Virt"}
8416 or $CompleteSignature{$LibVersion}{$Symbol}{"PureVirt"})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008417 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04008418 my $ClassName = $TypeInfo{$LibVersion}{$CompleteSignature{$LibVersion}{$Symbol}{"Class"}}{"Name"};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008419 next if(not $STDCXX_TESTING and $ClassName=~/\A(std::|__cxxabi)/);
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04008420 if($CompleteSignature{$LibVersion}{$Symbol}{"Destructor"}
8421 and $Symbol=~/D2E/)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008422 { # pure virtual D2-destructors are marked as "virt" in the dump
8423 # virtual D2-destructors are NOT marked as "virt" in the dump
8424 # both destructors are not presented in the v-table
8425 next;
8426 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04008427 my ($MnglName, $VersionSpec, $SymbolVersion) = separate_symbol($Symbol);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008428 $VirtualTable{$LibVersion}{$ClassName}{$MnglName} = 1;
8429 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008430 }
8431}
8432
8433sub registerOverriding($)
8434{
8435 my $LibVersion = $_[0];
8436 my @Classes = keys(%{$VirtualTable{$LibVersion}});
Andrey Ponomarenko85043792012-05-14 16:48:07 +04008437 @Classes = sort {int($TName_Tid{$LibVersion}{$a})<=>int($TName_Tid{$LibVersion}{$b})} @Classes;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008438 foreach my $ClassName (@Classes)
8439 {
8440 foreach my $VirtFunc (keys(%{$VirtualTable{$LibVersion}{$ClassName}}))
8441 {
Andrey Ponomarenko16934472012-03-29 15:37:04 +04008442 if($CompleteSignature{$LibVersion}{$VirtFunc}{"PureVirt"})
8443 { # pure virtuals
8444 next;
8445 }
8446 my $ClassId = $TName_Tid{$LibVersion}{$ClassName};
8447 if(my $Overridden = findMethod($VirtFunc, $ClassId, $LibVersion))
Andrey Ponomarenko85043792012-05-14 16:48:07 +04008448 {
8449 if($CompleteSignature{$LibVersion}{$Overridden}{"Virt"}
8450 or $CompleteSignature{$LibVersion}{$Overridden}{"PureVirt"})
8451 { # both overridden virtual methods
8452 # and implemented pure virtual methods
8453 $CompleteSignature{$LibVersion}{$VirtFunc}{"Override"} = $Overridden;
8454 $OverriddenMethods{$LibVersion}{$Overridden}{$VirtFunc} = 1;
8455 delete($VirtualTable{$LibVersion}{$ClassName}{$VirtFunc}); # remove from v-table model
8456 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008457 }
8458 }
8459 if(not keys(%{$VirtualTable{$LibVersion}{$ClassName}})) {
8460 delete($VirtualTable{$LibVersion}{$ClassName});
8461 }
8462 }
8463}
8464
8465sub setVirtFuncPositions($)
8466{
8467 my $LibVersion = $_[0];
8468 foreach my $ClassName (keys(%{$VirtualTable{$LibVersion}}))
8469 {
8470 my ($Num, $RelPos, $AbsNum) = (1, 0, 1);
8471 foreach my $VirtFunc (sort {int($CompleteSignature{$LibVersion}{$a}{"Line"}) <=> int($CompleteSignature{$LibVersion}{$b}{"Line"})}
8472 sort keys(%{$VirtualTable{$LibVersion}{$ClassName}}))
8473 {
Andrey Ponomarenko16934472012-03-29 15:37:04 +04008474 $VirtualTable{$LibVersion}{$ClassName}{$VirtFunc}=$Num++;
8475
8476 # set relative positions
8477 if(defined $VirtualTable{1}{$ClassName} and defined $VirtualTable{1}{$ClassName}{$VirtFunc}
8478 and defined $VirtualTable{2}{$ClassName} and defined $VirtualTable{2}{$ClassName}{$VirtFunc})
8479 { # relative position excluding added and removed virtual functions
8480 if(not $CompleteSignature{1}{$VirtFunc}{"Override"}
8481 and not $CompleteSignature{2}{$VirtFunc}{"Override"}) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008482 $CompleteSignature{$LibVersion}{$VirtFunc}{"RelPos"} = $RelPos++;
8483 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008484 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008485 }
8486 }
Andrey Ponomarenko16934472012-03-29 15:37:04 +04008487 foreach my $ClassName (keys(%{$ClassNames{$LibVersion}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008488 {
8489 my $AbsNum = 1;
Andrey Ponomarenko16934472012-03-29 15:37:04 +04008490 foreach my $VirtFunc (getVTable_Model($TName_Tid{$LibVersion}{$ClassName}, $LibVersion)) {
8491 $VirtualTable_Model{$LibVersion}{$ClassName}{$VirtFunc}=$AbsNum++;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008492 }
8493 }
8494}
8495
8496sub get_sub_classes($$$)
8497{
8498 my ($ClassId, $LibVersion, $Recursive) = @_;
8499 return () if(not defined $Class_SubClasses{$LibVersion}{$ClassId});
8500 my @Subs = ();
8501 foreach my $SubId (keys(%{$Class_SubClasses{$LibVersion}{$ClassId}}))
8502 {
Andrey Ponomarenko16934472012-03-29 15:37:04 +04008503 if($Recursive)
8504 {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008505 foreach my $SubSubId (get_sub_classes($SubId, $LibVersion, $Recursive)) {
8506 push(@Subs, $SubSubId);
8507 }
8508 }
8509 push(@Subs, $SubId);
8510 }
8511 return @Subs;
8512}
8513
8514sub get_base_classes($$$)
8515{
8516 my ($ClassId, $LibVersion, $Recursive) = @_;
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04008517 my %ClassType = get_Type($ClassId, $LibVersion);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008518 return () if(not defined $ClassType{"Base"});
8519 my @Bases = ();
8520 foreach my $BaseId (sort {int($ClassType{"Base"}{$a}{"pos"})<=>int($ClassType{"Base"}{$b}{"pos"})}
8521 keys(%{$ClassType{"Base"}}))
8522 {
Andrey Ponomarenko16934472012-03-29 15:37:04 +04008523 if($Recursive)
8524 {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008525 foreach my $SubBaseId (get_base_classes($BaseId, $LibVersion, $Recursive)) {
8526 push(@Bases, $SubBaseId);
8527 }
8528 }
8529 push(@Bases, $BaseId);
8530 }
8531 return @Bases;
8532}
8533
Andrey Ponomarenko16934472012-03-29 15:37:04 +04008534sub getVTable_Model($$)
8535{ # return an ordered list of v-table elements
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008536 my ($ClassId, $LibVersion) = @_;
8537 my @Bases = get_base_classes($ClassId, $LibVersion, 1);
8538 my @Elements = ();
8539 foreach my $BaseId (@Bases, $ClassId)
8540 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04008541 if(my $BName = $TypeInfo{$LibVersion}{$BaseId}{"Name"})
Andrey Ponomarenko85043792012-05-14 16:48:07 +04008542 {
8543 if(defined $VirtualTable{$LibVersion}{$BName})
8544 {
8545 my @VFunctions = keys(%{$VirtualTable{$LibVersion}{$BName}});
8546 @VFunctions = sort {int($CompleteSignature{$LibVersion}{$a}{"Line"}) <=> int($CompleteSignature{$LibVersion}{$b}{"Line"})} @VFunctions;
8547 foreach my $VFunc (@VFunctions) {
8548 push(@Elements, $VFunc);
8549 }
8550 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008551 }
8552 }
8553 return @Elements;
8554}
8555
8556sub getVShift($$)
8557{
8558 my ($ClassId, $LibVersion) = @_;
8559 my @Bases = get_base_classes($ClassId, $LibVersion, 1);
8560 my $VShift = 0;
8561 foreach my $BaseId (@Bases)
8562 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04008563 if(my $BName = $TypeInfo{$LibVersion}{$BaseId}{"Name"})
Andrey Ponomarenko85043792012-05-14 16:48:07 +04008564 {
8565 if(defined $VirtualTable{$LibVersion}{$BName}) {
8566 $VShift+=keys(%{$VirtualTable{$LibVersion}{$BName}});
8567 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008568 }
8569 }
8570 return $VShift;
8571}
8572
8573sub getShift($$)
8574{
8575 my ($ClassId, $LibVersion) = @_;
8576 my @Bases = get_base_classes($ClassId, $LibVersion, 0);
8577 my $Shift = 0;
8578 foreach my $BaseId (@Bases)
8579 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04008580 if(my $Size = $TypeInfo{$LibVersion}{$BaseId}{"Size"})
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04008581 {
8582 if($Size!=1)
8583 { # not empty base class
8584 $Shift+=$Size;
8585 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008586 }
8587 }
8588 return $Shift;
8589}
8590
Andrey Ponomarenko16934472012-03-29 15:37:04 +04008591sub getVTable_Size($$)
8592{ # number of v-table elements
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008593 my ($ClassName, $LibVersion) = @_;
Andrey Ponomarenko16934472012-03-29 15:37:04 +04008594 my $Size = 0;
8595 # three approaches
8596 if(not $Size)
8597 { # real size
8598 if(my %VTable = getVTable_Real($ClassName, $LibVersion)) {
8599 $Size = keys(%VTable);
8600 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008601 }
Andrey Ponomarenko16934472012-03-29 15:37:04 +04008602 if(not $Size)
8603 { # shared library symbol size
8604 if($Size = getSymbolSize($ClassVTable{$ClassName}, $LibVersion)) {
8605 $Size /= $WORD_SIZE{$LibVersion};
8606 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008607 }
Andrey Ponomarenko16934472012-03-29 15:37:04 +04008608 if(not $Size)
8609 { # model size
8610 if(defined $VirtualTable_Model{$LibVersion}{$ClassName}) {
8611 $Size = keys(%{$VirtualTable_Model{$LibVersion}{$ClassName}}) + 2;
8612 }
8613 }
8614 return $Size;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008615}
8616
8617sub isCopyingClass($$)
8618{
8619 my ($TypeId, $LibVersion) = @_;
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04008620 return $TypeInfo{$LibVersion}{$TypeId}{"Copied"};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008621}
8622
8623sub isLeafClass($$)
8624{
8625 my ($ClassId, $LibVersion) = @_;
8626 return (not keys(%{$Class_SubClasses{$LibVersion}{$ClassId}}));
8627}
8628
8629sub havePubFields($)
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04008630{ # check structured type for public fields
8631 return isAccessible($_[0], {}, 0, -1);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008632}
8633
8634sub isAccessible($$$$)
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04008635{ # check interval in structured type for public fields
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008636 my ($TypePtr, $Skip, $Start, $End) = @_;
8637 return 0 if(not $TypePtr);
8638 if($End==-1) {
8639 $End = keys(%{$TypePtr->{"Memb"}})-1;
8640 }
8641 foreach my $MemPos (keys(%{$TypePtr->{"Memb"}}))
8642 {
8643 if($Skip and $Skip->{$MemPos})
8644 { # skip removed/added fields
8645 next;
8646 }
8647 if(int($MemPos)>=$Start and int($MemPos)<=$End)
8648 {
8649 if(isPublic($TypePtr, $MemPos)) {
8650 return ($MemPos+1);
8651 }
8652 }
8653 }
8654 return 0;
8655}
8656
8657sub getAlignment($$$)
8658{
8659 my ($Pos, $TypePtr, $LibVersion) = @_;
8660 my $Tid = $TypePtr->{"Memb"}{$Pos}{"type"};
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04008661 my %Type = get_PureType($Tid, $LibVersion);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008662 my $TSize = $Type{"Size"}*$BYTE_SIZE;
8663 my $MSize = $Type{"Size"}*$BYTE_SIZE;
8664 if(my $BSize = $TypePtr->{"Memb"}{$Pos}{"bitfield"})
8665 { # bitfields
8666 ($TSize, $MSize) = ($WORD_SIZE{$LibVersion}*$BYTE_SIZE, $BSize);
8667 }
8668 elsif($Type{"Type"} eq "Array")
8669 { # in the context of function parameter
8670 # it's passed through the pointer
8671 }
8672 # alignment
8673 my $Alignment = $WORD_SIZE{$LibVersion}*$BYTE_SIZE; # default
8674 if(my $Computed = $TypePtr->{"Memb"}{$Pos}{"algn"})
8675 { # computed by GCC
8676 $Alignment = $Computed*$BYTE_SIZE;
8677 }
8678 elsif($TypePtr->{"Memb"}{$Pos}{"bitfield"})
8679 { # bitfields are 1 bit aligned
8680 $Alignment = 1;
8681 }
8682 elsif($TSize and $TSize<$WORD_SIZE{$LibVersion}*$BYTE_SIZE)
8683 { # model
8684 $Alignment = $TSize;
8685 }
8686 return ($Alignment, $MSize);
8687}
8688
8689sub getOffset($$$)
8690{ # offset of the field including padding
8691 my ($FieldPos, $TypePtr, $LibVersion) = @_;
8692 my $Offset = 0;
8693 foreach my $Pos (0 .. keys(%{$TypePtr->{"Memb"}})-1)
8694 {
8695 my ($Alignment, $MSize) = getAlignment($Pos, $TypePtr, $LibVersion);
8696 # padding
8697 my $Padding = 0;
8698 if($Offset % $Alignment!=0)
8699 { # not aligned, add padding
8700 $Padding = $Alignment - $Offset % $Alignment;
8701 }
8702 $Offset += $Padding;
8703 if($Pos==$FieldPos)
8704 { # after the padding
8705 # before the field
8706 return $Offset;
8707 }
8708 $Offset += $MSize;
8709 }
8710 return $FieldPos;# if something is going wrong
8711}
8712
8713sub isMemPadded($$$$$)
8714{ # check if the target field can be added/removed/changed
8715 # without shifting other fields because of padding bits
8716 my ($FieldPos, $Size, $TypePtr, $Skip, $LibVersion) = @_;
8717 return 0 if($FieldPos==0);
8718 if(defined $TypePtr->{"Memb"}{""})
8719 {
8720 delete($TypePtr->{"Memb"}{""});
8721 if($Debug) {
8722 printMsg("WARNING", "internal error detected");
8723 }
8724 }
8725 my $Offset = 0;
8726 my (%Alignment, %MSize) = ();
8727 my $MaxAlgn = 0;
8728 my $End = keys(%{$TypePtr->{"Memb"}})-1;
8729 my $NextField = $FieldPos+1;
8730 foreach my $Pos (0 .. $End)
8731 {
8732 if($Skip and $Skip->{$Pos})
8733 { # skip removed/added fields
8734 if($Pos > $FieldPos)
8735 { # after the target
8736 $NextField += 1;
8737 next;
8738 }
8739 }
8740 ($Alignment{$Pos}, $MSize{$Pos}) = getAlignment($Pos, $TypePtr, $LibVersion);
8741 if($Alignment{$Pos}>$MaxAlgn) {
8742 $MaxAlgn = $Alignment{$Pos};
8743 }
8744 if($Pos==$FieldPos)
8745 {
8746 if($Size==-1)
8747 { # added/removed fields
8748 if($Pos!=$End)
8749 { # skip target field and see
8750 # if enough padding will be
8751 # created on the next step
8752 # to include this field
8753 next;
8754 }
8755 }
8756 }
8757 # padding
8758 my $Padding = 0;
8759 if($Offset % $Alignment{$Pos}!=0)
8760 { # not aligned, add padding
8761 $Padding = $Alignment{$Pos} - $Offset % $Alignment{$Pos};
8762 }
8763 if($Pos==$NextField)
8764 { # try to place target field in the padding
8765 if($Size==-1)
8766 { # added/removed fields
8767 my $TPadding = 0;
8768 if($Offset % $Alignment{$FieldPos}!=0)
8769 {# padding of the target field
8770 $TPadding = $Alignment{$FieldPos} - $Offset % $Alignment{$FieldPos};
8771 }
8772 if($TPadding+$MSize{$FieldPos}<=$Padding)
8773 { # enough padding to place target field
8774 return 1;
8775 }
8776 else {
8777 return 0;
8778 }
8779 }
8780 else
8781 { # changed fields
8782 my $Delta = $Size-$MSize{$FieldPos};
8783 if($Delta>=0)
8784 { # increased
8785 if($Size-$MSize{$FieldPos}<=$Padding)
8786 { # enough padding to change target field
8787 return 1;
8788 }
8789 else {
8790 return 0;
8791 }
8792 }
8793 else
8794 { # decreased
8795 $Delta = abs($Delta);
8796 if($Delta+$Padding>=$MSize{$Pos})
8797 { # try to place the next field
8798 if(($Offset-$Delta) % $Alignment{$Pos} != 0)
8799 { # padding of the next field in new place
8800 my $NPadding = $Alignment{$Pos} - ($Offset-$Delta) % $Alignment{$Pos};
8801 if($NPadding+$MSize{$Pos}<=$Delta+$Padding)
8802 { # enough delta+padding to store next field
8803 return 0;
8804 }
8805 }
8806 else
8807 {
8808 return 0;
8809 }
8810 }
8811 return 1;
8812 }
8813 }
8814 }
8815 elsif($Pos==$End)
8816 { # target field is the last field
8817 if($Size==-1)
8818 { # added/removed fields
8819 if($Offset % $MaxAlgn!=0)
8820 { # tail padding
8821 my $TailPadding = $MaxAlgn - $Offset % $MaxAlgn;
8822 if($Padding+$MSize{$Pos}<=$TailPadding)
8823 { # enough tail padding to place the last field
8824 return 1;
8825 }
8826 }
8827 return 0;
8828 }
8829 else
8830 { # changed fields
8831 # scenario #1
8832 my $Offset1 = $Offset+$Padding+$MSize{$Pos};
8833 if($Offset1 % $MaxAlgn != 0)
8834 { # tail padding
8835 $Offset1 += $MaxAlgn - $Offset1 % $MaxAlgn;
8836 }
8837 # scenario #2
8838 my $Offset2 = $Offset+$Padding+$Size;
8839 if($Offset2 % $MaxAlgn != 0)
8840 { # tail padding
8841 $Offset2 += $MaxAlgn - $Offset2 % $MaxAlgn;
8842 }
8843 if($Offset1!=$Offset2)
8844 { # different sizes of structure
8845 return 0;
8846 }
8847 return 1;
8848 }
8849 }
8850 $Offset += $Padding+$MSize{$Pos};
8851 }
8852 return 0;
8853}
8854
8855sub isReserved($)
8856{ # reserved fields == private
8857 my $MName = $_[0];
8858 if($MName=~/reserved|padding|f_spare/i) {
8859 return 1;
8860 }
8861 if($MName=~/\A[_]*(spare|pad|unused)[_]*\Z/i) {
8862 return 1;
8863 }
8864 if($MName=~/(pad\d+)/i) {
8865 return 1;
8866 }
8867 return 0;
8868}
8869
8870sub isPublic($$)
8871{
8872 my ($TypePtr, $FieldPos) = @_;
8873 return 0 if(not $TypePtr);
8874 return 0 if(not defined $TypePtr->{"Memb"}{$FieldPos});
8875 return 0 if(not defined $TypePtr->{"Memb"}{$FieldPos}{"name"});
8876 if(not $TypePtr->{"Memb"}{$FieldPos}{"access"})
8877 { # by name in C language
8878 # FIXME: add other methods to detect private members
8879 my $MName = $TypePtr->{"Memb"}{$FieldPos}{"name"};
8880 if($MName=~/priv|abidata|parent_object/i)
8881 { # C-styled private data
8882 return 0;
8883 }
8884 if(lc($MName) eq "abi")
8885 { # ABI information/reserved field
8886 return 0;
8887 }
8888 if(isReserved($MName))
8889 { # reserved fields
8890 return 0;
8891 }
8892 return 1;
8893 }
8894 elsif($TypePtr->{"Memb"}{$FieldPos}{"access"} ne "private")
8895 { # by access in C++ language
8896 return 1;
8897 }
8898 return 0;
8899}
8900
Andrey Ponomarenko16934472012-03-29 15:37:04 +04008901sub getVTable_Real($$)
8902{
8903 my ($ClassName, $LibVersion) = @_;
8904 if(my $ClassId = $TName_Tid{$LibVersion}{$ClassName})
8905 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04008906 my %Type = get_Type($ClassId, $LibVersion);
Andrey Ponomarenko16934472012-03-29 15:37:04 +04008907 if(defined $Type{"VTable"}) {
8908 return %{$Type{"VTable"}};
8909 }
8910 }
8911 return ();
8912}
8913
8914sub cmpVTables($)
8915{
8916 my $ClassName = $_[0];
8917 my $Res = cmpVTables_Real($ClassName, 1);
8918 if($Res==-1) {
8919 $Res = cmpVTables_Model($ClassName);
8920 }
8921 return $Res;
8922}
8923
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008924sub cmpVTables_Model($)
8925{
8926 my $ClassName = $_[0];
Andrey Ponomarenko16934472012-03-29 15:37:04 +04008927 foreach my $Symbol (keys(%{$VirtualTable_Model{1}{$ClassName}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008928 {
Andrey Ponomarenko16934472012-03-29 15:37:04 +04008929 if(not defined $VirtualTable_Model{2}{$ClassName}{$Symbol}) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008930 return 1;
8931 }
8932 }
8933 return 0;
8934}
8935
Andrey Ponomarenko16934472012-03-29 15:37:04 +04008936sub cmpVTables_Real($$)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008937{
8938 my ($ClassName, $Strong) = @_;
Andrey Ponomarenko16934472012-03-29 15:37:04 +04008939 if(defined $Cache{"cmpVTables_Real"}{$Strong}{$ClassName}) {
8940 return $Cache{"cmpVTables_Real"}{$Strong}{$ClassName};
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04008941 }
Andrey Ponomarenko16934472012-03-29 15:37:04 +04008942 my %VTable_Old = getVTable_Real($ClassName, 1);
8943 my %VTable_New = getVTable_Real($ClassName, 2);
8944 if(not %VTable_Old or not %VTable_New)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008945 { # old ABI dumps
Andrey Ponomarenko16934472012-03-29 15:37:04 +04008946 return ($Cache{"cmpVTables_Real"}{$Strong}{$ClassName} = -1);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008947 }
Andrey Ponomarenko16934472012-03-29 15:37:04 +04008948 my %Indexes = map {$_=>1} (keys(%VTable_Old), keys(%VTable_New));
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008949 foreach my $Offset (sort {int($a)<=>int($b)} keys(%Indexes))
8950 {
Andrey Ponomarenko16934472012-03-29 15:37:04 +04008951 if(not defined $VTable_Old{$Offset})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008952 { # v-table v.1 < v-table v.2
Andrey Ponomarenko16934472012-03-29 15:37:04 +04008953 return ($Cache{"cmpVTables_Real"}{$Strong}{$ClassName} = $Strong);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008954 }
Andrey Ponomarenko16934472012-03-29 15:37:04 +04008955 my $Entry1 = $VTable_Old{$Offset};
8956 if(not defined $VTable_New{$Offset})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008957 { # v-table v.1 > v-table v.2
Andrey Ponomarenko16934472012-03-29 15:37:04 +04008958 return ($Cache{"cmpVTables_Real"}{$Strong}{$ClassName} = ($Strong or $Entry1!~/__cxa_pure_virtual/));
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008959 }
Andrey Ponomarenko16934472012-03-29 15:37:04 +04008960 my $Entry2 = $VTable_New{$Offset};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008961 $Entry1 = simpleVEntry($Entry1);
8962 $Entry2 = simpleVEntry($Entry2);
8963 if($Entry1 ne $Entry2)
8964 { # register as changed
8965 if($Entry1=~/::([^:]+)\Z/)
8966 {
8967 my $M1 = $1;
8968 if($Entry2=~/::([^:]+)\Z/)
8969 {
8970 my $M2 = $1;
8971 if($M1 eq $M2)
8972 { # overridden
8973 next;
8974 }
8975 }
8976 }
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04008977 if(differentDumps("G"))
8978 {
8979 if($Entry1=~/\A\-(0x|\d+)/ and $Entry2=~/\A\-(0x|\d+)/)
8980 {
8981 # GCC 4.6.1: -0x00000000000000010
8982 # GCC 4.7.0: -16
8983 next;
8984 }
8985 }
Andrey Ponomarenko16934472012-03-29 15:37:04 +04008986 return ($Cache{"cmpVTables_Real"}{$Strong}{$ClassName} = 1);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008987 }
8988 }
Andrey Ponomarenko16934472012-03-29 15:37:04 +04008989 return ($Cache{"cmpVTables_Real"}{$Strong}{$ClassName} = 0);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008990}
8991
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04008992sub mergeVTables($)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008993{ # merging v-tables without diagnostics
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04008994 my $Level = $_[0];
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008995 foreach my $ClassName (keys(%{$VirtualTable{1}}))
8996 {
Andrey Ponomarenko16934472012-03-29 15:37:04 +04008997 if($VTableChanged_M{$ClassName})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008998 { # already registered
8999 next;
9000 }
Andrey Ponomarenko16934472012-03-29 15:37:04 +04009001 if(cmpVTables_Real($ClassName, 0)==1)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009002 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04009003 my @Affected = (keys(%{$ClassMethods{$Level}{1}{$ClassName}}));
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009004 foreach my $Symbol (@Affected)
9005 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04009006 %{$CompatProblems{$Level}{$Symbol}{"Virtual_Table_Changed_Unknown"}{$ClassName}}=(
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009007 "Type_Name"=>$ClassName,
9008 "Type_Type"=>"Class",
9009 "Target"=>$ClassName);
9010 }
9011 }
9012 }
9013}
9014
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04009015sub mergeBases($)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009016{
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04009017 my $Level = $_[0];
Andrey Ponomarenko16934472012-03-29 15:37:04 +04009018 foreach my $ClassName (keys(%{$ClassNames{1}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009019 { # detect added and removed virtual functions
Andrey Ponomarenko16934472012-03-29 15:37:04 +04009020 my $ClassId = $TName_Tid{1}{$ClassName};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009021 next if(not $ClassId);
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04009022 if(defined $VirtualTable{2}{$ClassName})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009023 {
Andrey Ponomarenko16934472012-03-29 15:37:04 +04009024 foreach my $Symbol (keys(%{$VirtualTable{2}{$ClassName}}))
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04009025 {
Andrey Ponomarenko16934472012-03-29 15:37:04 +04009026 if($TName_Tid{1}{$ClassName}
9027 and not defined $VirtualTable{1}{$ClassName}{$Symbol})
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04009028 { # added to v-table
Andrey Ponomarenko16934472012-03-29 15:37:04 +04009029 if(defined $CompleteSignature{1}{$Symbol}
9030 and $CompleteSignature{1}{$Symbol}{"Virt"})
9031 { # override some method in v.1
9032 next;
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04009033 }
Andrey Ponomarenko16934472012-03-29 15:37:04 +04009034 $AddedInt_Virt{$Level}{$ClassName}{$Symbol} = 1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009035 }
9036 }
9037 }
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04009038 if(defined $VirtualTable{1}{$ClassName})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009039 {
Andrey Ponomarenko16934472012-03-29 15:37:04 +04009040 foreach my $Symbol (keys(%{$VirtualTable{1}{$ClassName}}))
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04009041 {
Andrey Ponomarenko16934472012-03-29 15:37:04 +04009042 if($TName_Tid{2}{$ClassName}
9043 and not defined $VirtualTable{2}{$ClassName}{$Symbol})
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04009044 { # removed from v-table
Andrey Ponomarenko16934472012-03-29 15:37:04 +04009045 if(defined $CompleteSignature{2}{$Symbol}
9046 and $CompleteSignature{2}{$Symbol}{"Virt"})
9047 { # override some method in v.2
9048 next;
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04009049 }
Andrey Ponomarenko16934472012-03-29 15:37:04 +04009050 $RemovedInt_Virt{$Level}{$ClassName}{$Symbol} = 1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009051 }
9052 }
9053 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04009054 if($Level eq "Binary")
9055 { # Binary-level
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04009056 my %Class_Type = get_Type($ClassId, 1);
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04009057 foreach my $AddedVFunc (keys(%{$AddedInt_Virt{$Level}{$ClassName}}))
9058 { # check replacements, including pure virtual methods
9059 my $AddedPos = $VirtualTable{2}{$ClassName}{$AddedVFunc};
9060 foreach my $RemovedVFunc (keys(%{$RemovedInt_Virt{$Level}{$ClassName}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009061 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04009062 my $RemovedPos = $VirtualTable{1}{$ClassName}{$RemovedVFunc};
9063 if($AddedPos==$RemovedPos)
9064 {
9065 $VirtualReplacement{$AddedVFunc} = $RemovedVFunc;
9066 $VirtualReplacement{$RemovedVFunc} = $AddedVFunc;
9067 last; # other methods will be reported as "added" or "removed"
9068 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009069 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04009070 if(my $RemovedVFunc = $VirtualReplacement{$AddedVFunc})
9071 {
9072 if(lc($AddedVFunc) eq lc($RemovedVFunc))
9073 { # skip: DomUi => DomUI parameter (Qt 4.2.3 to 4.3.0)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009074 next;
9075 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04009076 my $ProblemType = "Virtual_Replacement";
9077 my @Affected = ($RemovedVFunc);
9078 if($CompleteSignature{1}{$RemovedVFunc}{"PureVirt"})
9079 { # pure methods
9080 if(not isUsedClass($ClassId, 1, $Level))
9081 { # not a parameter of some exported method
9082 next;
9083 }
9084 $ProblemType = "Pure_Virtual_Replacement";
9085 @Affected = (keys(%{$ClassMethods{$Level}{1}{$ClassName}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009086 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04009087 foreach my $AffectedInt (@Affected)
9088 {
9089 if($CompleteSignature{1}{$AffectedInt}{"PureVirt"})
9090 { # affected exported methods only
9091 next;
9092 }
9093 %{$CompatProblems{$Level}{$AffectedInt}{$ProblemType}{$tr_name{$AddedVFunc}}}=(
9094 "Type_Name"=>$Class_Type{"Name"},
9095 "Type_Type"=>"Class",
9096 "Target"=>get_Signature($AddedVFunc, 2),
9097 "Old_Value"=>get_Signature($RemovedVFunc, 1));
9098 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009099 }
9100 }
9101 }
9102 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04009103 if(not checkDump(1, "2.0")
9104 or not checkDump(2, "2.0"))
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04009105 { # support for old ABI dumps
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009106 # "Base" attribute introduced in ACC 1.22 (dump 2.0 format)
9107 return;
9108 }
Andrey Ponomarenko16934472012-03-29 15:37:04 +04009109 foreach my $ClassName (sort keys(%{$ClassNames{1}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009110 {
Andrey Ponomarenko16934472012-03-29 15:37:04 +04009111 my $ClassId_Old = $TName_Tid{1}{$ClassName};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009112 next if(not $ClassId_Old);
9113 if(not isCreatable($ClassId_Old, 1))
9114 { # skip classes without public constructors (including auto-generated)
9115 # example: class has only a private exported or private inline constructor
9116 next;
9117 }
9118 if($ClassName=~/>/)
9119 { # skip affected template instances
9120 next;
9121 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04009122 my %Class_Old = get_Type($ClassId_Old, 1);
Andrey Ponomarenko16934472012-03-29 15:37:04 +04009123 my $ClassId_New = $TName_Tid{2}{$ClassName};
Andrey Ponomarenko85043792012-05-14 16:48:07 +04009124 if(not $ClassId_New) {
9125 next;
9126 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04009127 my %Class_New = get_Type($ClassId_New, 2);
Andrey Ponomarenko85043792012-05-14 16:48:07 +04009128 if($Class_New{"Type"}!~/Class|Struct/)
9129 { # became typedef
9130 if($Level eq "Binary") {
9131 next;
9132 }
9133 if($Level eq "Source")
9134 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04009135 %Class_New = get_PureType($ClassId_New, 2);
Andrey Ponomarenko85043792012-05-14 16:48:07 +04009136 if($Class_New{"Type"}!~/Class|Struct/) {
9137 next;
9138 }
9139 $ClassId_New = $Class_New{"Tid"};
9140 }
9141 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009142 my @Bases_Old = sort {$Class_Old{"Base"}{$a}{"pos"}<=>$Class_Old{"Base"}{$b}{"pos"}} keys(%{$Class_Old{"Base"}});
9143 my @Bases_New = sort {$Class_New{"Base"}{$a}{"pos"}<=>$Class_New{"Base"}{$b}{"pos"}} keys(%{$Class_New{"Base"}});
9144 my ($BNum1, $BNum2) = (1, 1);
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04009145 my %BasePos_Old = map {$TypeInfo{1}{$_}{"Name"} => $BNum1++} @Bases_Old;
9146 my %BasePos_New = map {$TypeInfo{2}{$_}{"Name"} => $BNum2++} @Bases_New;
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04009147 my %ShortBase_Old = map {get_ShortType($_, 1) => 1} @Bases_Old;
9148 my %ShortBase_New = map {get_ShortType($_, 2) => 1} @Bases_New;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009149 my $Shift_Old = getShift($ClassId_Old, 1);
9150 my $Shift_New = getShift($ClassId_New, 2);
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04009151 my %BaseId_New = map {$TypeInfo{2}{$_}{"Name"} => $_} @Bases_New;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009152 my ($Added, $Removed) = (0, 0);
9153 my @StableBases_Old = ();
9154 foreach my $BaseId (@Bases_Old)
9155 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04009156 my $BaseName = $TypeInfo{1}{$BaseId}{"Name"};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009157 if($BasePos_New{$BaseName}) {
9158 push(@StableBases_Old, $BaseId);
9159 }
9160 elsif(not $ShortBase_New{$BaseName}
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04009161 and not $ShortBase_New{get_ShortType($BaseId, 1)})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009162 { # removed base
9163 # excluding namespace::SomeClass to SomeClass renaming
9164 my $ProblemKind = "Removed_Base_Class";
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04009165 if($Level eq "Binary")
9166 { # Binary-level
9167 if($Shift_Old ne $Shift_New)
9168 { # affected fields
9169 if(havePubFields(\%Class_Old)) {
9170 $ProblemKind .= "_And_Shift";
9171 }
9172 elsif($Class_Old{"Size"} ne $Class_New{"Size"}) {
9173 $ProblemKind .= "_And_Size";
9174 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009175 }
Andrey Ponomarenko16934472012-03-29 15:37:04 +04009176 if(keys(%{$VirtualTable_Model{1}{$BaseName}})
9177 and cmpVTables($ClassName)==1)
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04009178 { # affected v-table
9179 $ProblemKind .= "_And_VTable";
Andrey Ponomarenko16934472012-03-29 15:37:04 +04009180 $VTableChanged_M{$ClassName}=1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009181 }
9182 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04009183 my @Affected = keys(%{$ClassMethods{$Level}{1}{$ClassName}});
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009184 foreach my $SubId (get_sub_classes($ClassId_Old, 1, 1))
9185 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04009186 my $SubName = $TypeInfo{1}{$SubId}{"Name"};
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04009187 push(@Affected, keys(%{$ClassMethods{$Level}{1}{$SubName}}));
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009188 if($ProblemKind=~/VTable/) {
Andrey Ponomarenko16934472012-03-29 15:37:04 +04009189 $VTableChanged_M{$SubName}=1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009190 }
9191 }
9192 foreach my $Interface (@Affected)
9193 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04009194 %{$CompatProblems{$Level}{$Interface}{$ProblemKind}{"this"}}=(
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009195 "Type_Name"=>$ClassName,
9196 "Type_Type"=>"Class",
9197 "Target"=>$BaseName,
9198 "Old_Size"=>$Class_Old{"Size"}*$BYTE_SIZE,
9199 "New_Size"=>$Class_New{"Size"}*$BYTE_SIZE,
9200 "Shift"=>abs($Shift_New-$Shift_Old) );
9201 }
9202 $Removed+=1;
9203 }
9204 }
9205 my @StableBases_New = ();
9206 foreach my $BaseId (@Bases_New)
9207 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04009208 my $BaseName = $TypeInfo{2}{$BaseId}{"Name"};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009209 if($BasePos_Old{$BaseName}) {
9210 push(@StableBases_New, $BaseId);
9211 }
9212 elsif(not $ShortBase_Old{$BaseName}
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04009213 and not $ShortBase_Old{get_ShortType($BaseId, 2)})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009214 { # added base
9215 # excluding namespace::SomeClass to SomeClass renaming
9216 my $ProblemKind = "Added_Base_Class";
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04009217 if($Level eq "Binary")
9218 { # Binary-level
9219 if($Shift_Old ne $Shift_New)
9220 { # affected fields
9221 if(havePubFields(\%Class_Old)) {
9222 $ProblemKind .= "_And_Shift";
9223 }
9224 elsif($Class_Old{"Size"} ne $Class_New{"Size"}) {
9225 $ProblemKind .= "_And_Size";
9226 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009227 }
Andrey Ponomarenko16934472012-03-29 15:37:04 +04009228 if(keys(%{$VirtualTable_Model{2}{$BaseName}})
9229 and cmpVTables($ClassName)==1)
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04009230 { # affected v-table
9231 $ProblemKind .= "_And_VTable";
Andrey Ponomarenko16934472012-03-29 15:37:04 +04009232 $VTableChanged_M{$ClassName}=1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009233 }
9234 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04009235 my @Affected = keys(%{$ClassMethods{$Level}{1}{$ClassName}});
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009236 foreach my $SubId (get_sub_classes($ClassId_Old, 1, 1))
9237 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04009238 my $SubName = $TypeInfo{1}{$SubId}{"Name"};
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04009239 push(@Affected, keys(%{$ClassMethods{$Level}{1}{$SubName}}));
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009240 if($ProblemKind=~/VTable/) {
Andrey Ponomarenko16934472012-03-29 15:37:04 +04009241 $VTableChanged_M{$SubName}=1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009242 }
9243 }
9244 foreach my $Interface (@Affected)
9245 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04009246 %{$CompatProblems{$Level}{$Interface}{$ProblemKind}{"this"}}=(
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009247 "Type_Name"=>$ClassName,
9248 "Type_Type"=>"Class",
9249 "Target"=>$BaseName,
9250 "Old_Size"=>$Class_Old{"Size"}*$BYTE_SIZE,
9251 "New_Size"=>$Class_New{"Size"}*$BYTE_SIZE,
9252 "Shift"=>abs($Shift_New-$Shift_Old) );
9253 }
9254 $Added+=1;
9255 }
9256 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04009257 if($Level eq "Binary")
9258 { # Binary-level
9259 ($BNum1, $BNum2) = (1, 1);
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04009260 my %BaseRelPos_Old = map {$TypeInfo{1}{$_}{"Name"} => $BNum1++} @StableBases_Old;
9261 my %BaseRelPos_New = map {$TypeInfo{2}{$_}{"Name"} => $BNum2++} @StableBases_New;
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04009262 foreach my $BaseId (@Bases_Old)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009263 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04009264 my $BaseName = $TypeInfo{1}{$BaseId}{"Name"};
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04009265 if(my $NewPos = $BaseRelPos_New{$BaseName})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009266 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04009267 my $BaseNewId = $BaseId_New{$BaseName};
9268 my $OldPos = $BaseRelPos_Old{$BaseName};
9269 if($NewPos!=$OldPos)
9270 { # changed position of the base class
9271 foreach my $Interface (keys(%{$ClassMethods{$Level}{1}{$ClassName}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009272 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04009273 %{$CompatProblems{$Level}{$Interface}{"Base_Class_Position"}{"this"}}=(
9274 "Type_Name"=>$ClassName,
9275 "Type_Type"=>"Class",
9276 "Target"=>$BaseName,
9277 "Old_Value"=>$OldPos-1,
9278 "New_Value"=>$NewPos-1 );
9279 }
9280 }
9281 if($Class_Old{"Base"}{$BaseId}{"virtual"}
9282 and not $Class_New{"Base"}{$BaseNewId}{"virtual"})
9283 { # became non-virtual base
9284 foreach my $Interface (keys(%{$ClassMethods{$Level}{1}{$ClassName}}))
9285 {
9286 %{$CompatProblems{$Level}{$Interface}{"Base_Class_Became_Non_Virtually_Inherited"}{"this->".$BaseName}}=(
9287 "Type_Name"=>$ClassName,
9288 "Type_Type"=>"Class",
9289 "Target"=>$BaseName );
9290 }
9291 }
9292 elsif(not $Class_Old{"Base"}{$BaseId}{"virtual"}
9293 and $Class_New{"Base"}{$BaseNewId}{"virtual"})
9294 { # became virtual base
9295 foreach my $Interface (keys(%{$ClassMethods{$Level}{1}{$ClassName}}))
9296 {
9297 %{$CompatProblems{$Level}{$Interface}{"Base_Class_Became_Virtually_Inherited"}{"this->".$BaseName}}=(
9298 "Type_Name"=>$ClassName,
9299 "Type_Type"=>"Class",
9300 "Target"=>$BaseName );
9301 }
9302 }
9303 }
9304 }
9305 # detect size changes in base classes
9306 if($Shift_Old!=$Shift_New)
9307 { # size of allocable class
9308 foreach my $BaseId (@StableBases_Old)
9309 { # search for changed base
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04009310 my %BaseType = get_Type($BaseId, 1);
9311 my $Size_Old = $TypeInfo{1}{$BaseId}{"Size"};
9312 my $Size_New = $TypeInfo{2}{$BaseId_New{$BaseType{"Name"}}}{"Size"};
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04009313 if($Size_Old ne $Size_New
9314 and $Size_Old and $Size_New)
9315 {
9316 my $ProblemType = "";
9317 if(isCopyingClass($BaseId, 1)) {
9318 $ProblemType = "Size_Of_Copying_Class";
9319 }
9320 elsif($AllocableClass{1}{$BaseType{"Name"}})
9321 {
9322 if($Size_New>$Size_Old)
9323 { # increased size
9324 $ProblemType = "Size_Of_Allocable_Class_Increased";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009325 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04009326 else
9327 { # decreased size
9328 $ProblemType = "Size_Of_Allocable_Class_Decreased";
9329 if(not havePubFields(\%Class_Old))
9330 { # affected class has no public members
9331 next;
9332 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009333 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04009334 }
9335 next if(not $ProblemType);
9336 foreach my $Interface (keys(%{$ClassMethods{$Level}{1}{$ClassName}}))
9337 { # base class size changes affecting current class
9338 %{$CompatProblems{$Level}{$Interface}{$ProblemType}{"this->".$BaseType{"Name"}}}=(
9339 "Type_Name"=>$BaseType{"Name"},
9340 "Type_Type"=>"Class",
9341 "Target"=>$BaseType{"Name"},
9342 "Old_Size"=>$Size_Old*$BYTE_SIZE,
9343 "New_Size"=>$Size_New*$BYTE_SIZE );
9344 }
9345 }
9346 }
9347 }
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04009348 if(defined $VirtualTable{1}{$ClassName}
Andrey Ponomarenko16934472012-03-29 15:37:04 +04009349 and cmpVTables_Real($ClassName, 1)==1
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04009350 and my @VFunctions = keys(%{$VirtualTable{1}{$ClassName}}))
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04009351 { # compare virtual tables size in base classes
9352 my $VShift_Old = getVShift($ClassId_Old, 1);
9353 my $VShift_New = getVShift($ClassId_New, 2);
9354 if($VShift_Old ne $VShift_New)
9355 { # changes in the base class or changes in the list of base classes
9356 my @AllBases_Old = get_base_classes($ClassId_Old, 1, 1);
9357 my @AllBases_New = get_base_classes($ClassId_New, 2, 1);
9358 ($BNum1, $BNum2) = (1, 1);
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04009359 my %StableBase = map {$TypeInfo{2}{$_}{"Name"} => $_} @AllBases_New;
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04009360 foreach my $BaseId (@AllBases_Old)
9361 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04009362 my %BaseType = get_Type($BaseId, 1);
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04009363 if(not $StableBase{$BaseType{"Name"}})
9364 { # lost base
9365 next;
9366 }
Andrey Ponomarenko16934472012-03-29 15:37:04 +04009367 my $VSize_Old = getVTable_Size($BaseType{"Name"}, 1);
9368 my $VSize_New = getVTable_Size($BaseType{"Name"}, 2);
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04009369 if($VSize_Old!=$VSize_New)
9370 {
Andrey Ponomarenko85043792012-05-14 16:48:07 +04009371 foreach my $Symbol (@VFunctions)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009372 {
Andrey Ponomarenko85043792012-05-14 16:48:07 +04009373 if(not defined $VirtualTable{2}{$ClassName}{$Symbol})
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04009374 { # Removed_Virtual_Method, will be registered in mergeVirtualTables()
9375 next;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009376 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +04009377 if($VirtualTable_Model{2}{$ClassName}{$Symbol}-$VirtualTable_Model{1}{$ClassName}{$Symbol}==0)
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04009378 { # skip interfaces that have not changed the absolute virtual position
9379 next;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009380 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +04009381 if(not symbolFilter($Symbol, 1, "Affected", $Level)) {
9382 next;
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04009383 }
Andrey Ponomarenko16934472012-03-29 15:37:04 +04009384 $VTableChanged_M{$BaseType{"Name"}} = 1;
9385 $VTableChanged_M{$ClassName} = 1;
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04009386 foreach my $VirtFunc (keys(%{$AddedInt_Virt{$Level}{$BaseType{"Name"}}}))
9387 { # the reason of the layout change: added virtual functions
9388 next if($VirtualReplacement{$VirtFunc});
9389 my $ProblemType = "Added_Virtual_Method";
9390 if($CompleteSignature{2}{$VirtFunc}{"PureVirt"}) {
9391 $ProblemType = "Added_Pure_Virtual_Method";
9392 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +04009393 %{$CompatProblems{$Level}{$Symbol}{$ProblemType}{get_Signature($VirtFunc, 2)}}=(
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04009394 "Type_Name"=>$BaseType{"Name"},
9395 "Type_Type"=>"Class",
9396 "Target"=>get_Signature($VirtFunc, 2) );
9397 }
9398 foreach my $VirtFunc (keys(%{$RemovedInt_Virt{$Level}{$BaseType{"Name"}}}))
9399 { # the reason of the layout change: removed virtual functions
9400 next if($VirtualReplacement{$VirtFunc});
9401 my $ProblemType = "Removed_Virtual_Method";
9402 if($CompleteSignature{1}{$VirtFunc}{"PureVirt"}) {
9403 $ProblemType = "Removed_Pure_Virtual_Method";
9404 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +04009405 %{$CompatProblems{$Level}{$Symbol}{$ProblemType}{get_Signature($VirtFunc, 1)}}=(
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04009406 "Type_Name"=>$BaseType{"Name"},
9407 "Type_Type"=>"Class",
9408 "Target"=>get_Signature($VirtFunc, 1) );
9409 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009410 }
9411 }
9412 }
9413 }
9414 }
9415 }
9416 }
9417}
9418
9419sub isCreatable($$)
9420{
9421 my ($ClassId, $LibVersion) = @_;
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04009422 if($AllocableClass{$LibVersion}{$TypeInfo{$LibVersion}{$ClassId}{"Name"}}
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009423 or isCopyingClass($ClassId, $LibVersion)) {
9424 return 1;
9425 }
9426 if(keys(%{$Class_SubClasses{$LibVersion}{$ClassId}}))
9427 { # Fix for incomplete data: if this class has
9428 # a base class then it should also has a constructor
9429 return 1;
9430 }
9431 if($ReturnedClass{$LibVersion}{$ClassId})
9432 { # returned by some method of this class
9433 # or any other class
9434 return 1;
9435 }
9436 return 0;
9437}
9438
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04009439sub isUsedClass($$$)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009440{
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04009441 my ($ClassId, $LibVersion, $Level) = @_;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009442 if(keys(%{$ParamClass{$LibVersion}{$ClassId}}))
9443 { # parameter of some exported method
9444 return 1;
9445 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04009446 my $CName = $TypeInfo{$LibVersion}{$ClassId}{"Name"};
9447 if(keys(%{$ClassMethods{$Level}{$LibVersion}{$CName}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009448 { # method from target class
9449 return 1;
9450 }
9451 return 0;
9452}
9453
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04009454sub mergeVirtualTables($$)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009455{ # check for changes in the virtual table
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04009456 my ($Interface, $Level) = @_;
Andrey Ponomarenko16934472012-03-29 15:37:04 +04009457 # affected methods:
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009458 # - virtual
9459 # - pure-virtual
9460 # - non-virtual
9461 if($CompleteSignature{1}{$Interface}{"Data"})
9462 { # global data is not affected
9463 return;
9464 }
9465 my $Class_Id = $CompleteSignature{1}{$Interface}{"Class"};
Andrey Ponomarenko16934472012-03-29 15:37:04 +04009466 if(not $Class_Id) {
9467 return;
9468 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04009469 my $CName = $TypeInfo{1}{$Class_Id}{"Name"};
Andrey Ponomarenko16934472012-03-29 15:37:04 +04009470 if(cmpVTables_Real($CName, 1)==0)
9471 { # no changes
9472 return;
9473 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04009474 $CheckedTypes{$Level}{$CName} = 1;
9475 if($Level eq "Binary")
9476 { # Binary-level
9477 if($CompleteSignature{1}{$Interface}{"PureVirt"}
9478 and not isUsedClass($Class_Id, 1, $Level))
9479 { # pure virtuals should not be affected
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04009480 # if there are no exported methods using this class
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04009481 return;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009482 }
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04009483 }
9484 foreach my $Func (keys(%{$VirtualTable{1}{$CName}}))
9485 {
9486 if(defined $VirtualTable{2}{$CName}{$Func}
9487 and defined $CompleteSignature{2}{$Func})
9488 {
9489 if(not $CompleteSignature{1}{$Func}{"PureVirt"}
9490 and $CompleteSignature{2}{$Func}{"PureVirt"})
9491 { # became pure virtual
9492 %{$CompatProblems{$Level}{$Interface}{"Virtual_Method_Became_Pure"}{$tr_name{$Func}}}=(
9493 "Type_Name"=>$CName,
9494 "Type_Type"=>"Class",
9495 "Target"=>get_Signature_M($Func, 1) );
9496 $VTableChanged_M{$CName} = 1;
9497 }
9498 elsif($CompleteSignature{1}{$Func}{"PureVirt"}
9499 and not $CompleteSignature{2}{$Func}{"PureVirt"})
9500 { # became non-pure virtual
9501 %{$CompatProblems{$Level}{$Interface}{"Virtual_Method_Became_Non_Pure"}{$tr_name{$Func}}}=(
9502 "Type_Name"=>$CName,
9503 "Type_Type"=>"Class",
9504 "Target"=>get_Signature_M($Func, 1) );
9505 $VTableChanged_M{$CName} = 1;
9506 }
9507 }
9508 }
9509 if($Level eq "Binary")
9510 { # Binary-level
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04009511 # check virtual table structure
9512 foreach my $AddedVFunc (keys(%{$AddedInt_Virt{$Level}{$CName}}))
9513 {
9514 next if($Interface eq $AddedVFunc);
9515 next if($VirtualReplacement{$AddedVFunc});
9516 my $VPos_Added = $VirtualTable{2}{$CName}{$AddedVFunc};
9517 if($CompleteSignature{2}{$AddedVFunc}{"PureVirt"})
9518 { # pure virtual methods affect all others (virtual and non-virtual)
9519 %{$CompatProblems{$Level}{$Interface}{"Added_Pure_Virtual_Method"}{$tr_name{$AddedVFunc}}}=(
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009520 "Type_Name"=>$CName,
9521 "Type_Type"=>"Class",
9522 "Target"=>get_Signature($AddedVFunc, 2) );
Andrey Ponomarenko16934472012-03-29 15:37:04 +04009523 $VTableChanged_M{$CName} = 1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009524 }
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04009525 elsif(not defined $VirtualTable{1}{$CName}
9526 or $VPos_Added>keys(%{$VirtualTable{1}{$CName}}))
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04009527 { # added virtual function at the end of v-table
Andrey Ponomarenko16934472012-03-29 15:37:04 +04009528 if(not keys(%{$VirtualTable_Model{1}{$CName}}))
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04009529 { # became polymorphous class, added v-table pointer
9530 %{$CompatProblems{$Level}{$Interface}{"Added_First_Virtual_Method"}{$tr_name{$AddedVFunc}}}=(
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009531 "Type_Name"=>$CName,
9532 "Type_Type"=>"Class",
9533 "Target"=>get_Signature($AddedVFunc, 2) );
Andrey Ponomarenko16934472012-03-29 15:37:04 +04009534 $VTableChanged_M{$CName} = 1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009535 }
9536 else
9537 {
Andrey Ponomarenko16934472012-03-29 15:37:04 +04009538 my $VSize_Old = getVTable_Size($CName, 1);
9539 my $VSize_New = getVTable_Size($CName, 2);
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04009540 next if($VSize_Old==$VSize_New);# exception: register as removed and added virtual method
9541 if(isCopyingClass($Class_Id, 1))
9542 { # class has no constructors and v-table will be copied by applications, this may affect all methods
9543 my $ProblemType = "Added_Virtual_Method";
9544 if(isLeafClass($Class_Id, 1)) {
9545 $ProblemType = "Added_Virtual_Method_At_End_Of_Leaf_Copying_Class";
9546 }
9547 %{$CompatProblems{$Level}{$Interface}{$ProblemType}{$tr_name{$AddedVFunc}}}=(
9548 "Type_Name"=>$CName,
9549 "Type_Type"=>"Class",
9550 "Target"=>get_Signature($AddedVFunc, 2) );
Andrey Ponomarenko16934472012-03-29 15:37:04 +04009551 $VTableChanged_M{$CName} = 1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009552 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04009553 else
9554 {
9555 my $ProblemType = "Added_Virtual_Method";
9556 if(isLeafClass($Class_Id, 1)) {
9557 $ProblemType = "Added_Virtual_Method_At_End_Of_Leaf_Allocable_Class";
9558 }
9559 %{$CompatProblems{$Level}{$Interface}{$ProblemType}{$tr_name{$AddedVFunc}}}=(
9560 "Type_Name"=>$CName,
9561 "Type_Type"=>"Class",
9562 "Target"=>get_Signature($AddedVFunc, 2) );
Andrey Ponomarenko16934472012-03-29 15:37:04 +04009563 $VTableChanged_M{$CName} = 1;
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04009564 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009565 }
9566 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04009567 elsif($CompleteSignature{1}{$Interface}{"Virt"}
9568 or $CompleteSignature{1}{$Interface}{"PureVirt"})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009569 {
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04009570 if(defined $VirtualTable{1}{$CName}
9571 and defined $VirtualTable{2}{$CName})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009572 {
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04009573 my $VPos_Old = $VirtualTable{1}{$CName}{$Interface};
9574 my $VPos_New = $VirtualTable{2}{$CName}{$Interface};
9575 if($VPos_Added<=$VPos_Old and $VPos_Old!=$VPos_New)
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04009576 {
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04009577 my @Affected = ($Interface, keys(%{$OverriddenMethods{1}{$Interface}}));
9578 foreach my $ASymbol (@Affected)
9579 {
Andrey Ponomarenko85043792012-05-14 16:48:07 +04009580 if(not $CompleteSignature{1}{$ASymbol}{"PureVirt"})
9581 {
9582 if(symbolFilter($ASymbol, 1, "Affected", $Level)) {
9583 next;
9584 }
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04009585 }
9586 $CheckedSymbols{$Level}{$ASymbol} = 1;
9587 %{$CompatProblems{$Level}{$ASymbol}{"Added_Virtual_Method"}{$tr_name{$AddedVFunc}}}=(
9588 "Type_Name"=>$CName,
9589 "Type_Type"=>"Class",
9590 "Target"=>get_Signature($AddedVFunc, 2) );
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04009591 $VTableChanged_M{$TypeInfo{1}{$CompleteSignature{1}{$ASymbol}{"Class"}}{"Name"}} = 1;
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04009592 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009593 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009594 }
9595 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04009596 else {
9597 # safe
9598 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009599 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04009600 foreach my $RemovedVFunc (keys(%{$RemovedInt_Virt{$Level}{$CName}}))
9601 {
9602 next if($VirtualReplacement{$RemovedVFunc});
9603 if($RemovedVFunc eq $Interface
9604 and $CompleteSignature{1}{$RemovedVFunc}{"PureVirt"})
9605 { # This case is for removed virtual methods
9606 # implemented in both versions of a library
9607 next;
9608 }
Andrey Ponomarenko16934472012-03-29 15:37:04 +04009609 if(not keys(%{$VirtualTable_Model{2}{$CName}}))
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04009610 { # became non-polymorphous class, removed v-table pointer
9611 %{$CompatProblems{$Level}{$Interface}{"Removed_Last_Virtual_Method"}{$tr_name{$RemovedVFunc}}}=(
9612 "Type_Name"=>$CName,
9613 "Type_Type"=>"Class",
9614 "Target"=>get_Signature($RemovedVFunc, 1) );
Andrey Ponomarenko16934472012-03-29 15:37:04 +04009615 $VTableChanged_M{$CName} = 1;
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04009616 }
9617 elsif($CompleteSignature{1}{$Interface}{"Virt"}
9618 or $CompleteSignature{1}{$Interface}{"PureVirt"})
9619 {
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04009620 if(defined $VirtualTable{1}{$CName} and defined $VirtualTable{2}{$CName})
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04009621 {
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04009622 if(not defined $VirtualTable{1}{$CName}{$Interface}) {
9623 next;
9624 }
9625 my $VPos_New = -1;
9626 if(defined $VirtualTable{2}{$CName}{$Interface})
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04009627 {
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04009628 $VPos_New = $VirtualTable{2}{$CName}{$Interface};
9629 }
9630 else
9631 {
9632 if($Interface ne $RemovedVFunc) {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04009633 next;
9634 }
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04009635 }
9636 my $VPos_Removed = $VirtualTable{1}{$CName}{$RemovedVFunc};
9637 my $VPos_Old = $VirtualTable{1}{$CName}{$Interface};
9638 if($VPos_Removed<=$VPos_Old and $VPos_Old!=$VPos_New)
9639 {
9640 my @Affected = ($Interface, keys(%{$OverriddenMethods{1}{$Interface}}));
9641 foreach my $ASymbol (@Affected)
9642 {
Andrey Ponomarenko85043792012-05-14 16:48:07 +04009643 if(not $CompleteSignature{1}{$ASymbol}{"PureVirt"})
9644 {
9645 if(symbolFilter($ASymbol, 1, "Affected", $Level)) {
9646 next;
9647 }
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04009648 }
9649 my $ProblemType = "Removed_Virtual_Method";
9650 if($CompleteSignature{1}{$RemovedVFunc}{"PureVirt"}) {
9651 $ProblemType = "Removed_Pure_Virtual_Method";
9652 }
9653 $CheckedSymbols{$Level}{$ASymbol} = 1;
9654 %{$CompatProblems{$Level}{$ASymbol}{$ProblemType}{$tr_name{$RemovedVFunc}}}=(
9655 "Type_Name"=>$CName,
9656 "Type_Type"=>"Class",
9657 "Target"=>get_Signature($RemovedVFunc, 1) );
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04009658 $VTableChanged_M{$TypeInfo{1}{$CompleteSignature{1}{$ASymbol}{"Class"}}{"Name"}} = 1;
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04009659 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04009660 }
9661 }
9662 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009663 }
9664 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04009665 else
9666 { # Source-level
9667 foreach my $AddedVFunc (keys(%{$AddedInt_Virt{$Level}{$CName}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009668 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04009669 next if($Interface eq $AddedVFunc);
9670 if($CompleteSignature{2}{$AddedVFunc}{"PureVirt"})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009671 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04009672 %{$CompatProblems{$Level}{$Interface}{"Added_Pure_Virtual_Method"}{$tr_name{$AddedVFunc}}}=(
9673 "Type_Name"=>$CName,
9674 "Type_Type"=>"Class",
9675 "Target"=>get_Signature($AddedVFunc, 2) );
9676 }
9677 }
9678 foreach my $RemovedVFunc (keys(%{$RemovedInt_Virt{$Level}{$CName}}))
9679 {
9680 if($CompleteSignature{1}{$RemovedVFunc}{"PureVirt"})
9681 {
9682 %{$CompatProblems{$Level}{$Interface}{"Removed_Pure_Virtual_Method"}{$tr_name{$RemovedVFunc}}}=(
9683 "Type_Name"=>$CName,
9684 "Type_Type"=>"Class",
9685 "Target"=>get_Signature($RemovedVFunc, 1) );
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009686 }
9687 }
9688 }
9689}
9690
9691sub find_MemberPair_Pos_byName($$)
9692{
9693 my ($Member_Name, $Pair_Type) = @_;
9694 $Member_Name=~s/\A[_]+|[_]+\Z//g;
9695 foreach my $MemberPair_Pos (sort {int($a)<=>int($b)} keys(%{$Pair_Type->{"Memb"}}))
9696 {
9697 if(defined $Pair_Type->{"Memb"}{$MemberPair_Pos})
9698 {
9699 my $Name = $Pair_Type->{"Memb"}{$MemberPair_Pos}{"name"};
9700 $Name=~s/\A[_]+|[_]+\Z//g;
9701 if($Name eq $Member_Name) {
9702 return $MemberPair_Pos;
9703 }
9704 }
9705 }
9706 return "lost";
9707}
9708
9709sub find_MemberPair_Pos_byVal($$)
9710{
9711 my ($Member_Value, $Pair_Type) = @_;
9712 foreach my $MemberPair_Pos (sort {int($a)<=>int($b)} keys(%{$Pair_Type->{"Memb"}}))
9713 {
9714 if(defined $Pair_Type->{"Memb"}{$MemberPair_Pos}
9715 and $Pair_Type->{"Memb"}{$MemberPair_Pos}{"value"} eq $Member_Value) {
9716 return $MemberPair_Pos;
9717 }
9718 }
9719 return "lost";
9720}
9721
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04009722my %Severity_Val=(
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009723 "High"=>3,
9724 "Medium"=>2,
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04009725 "Low"=>1,
9726 "Safe"=>-1
9727);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009728
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04009729sub maxSeverity($$)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009730{
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04009731 my ($S1, $S2) = @_;
9732 if(cmpSeverities($S1, $S2)) {
9733 return $S1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009734 }
9735 else {
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04009736 return $S2;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009737 }
9738}
9739
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04009740sub cmpSeverities($$)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009741{
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04009742 my ($S1, $S2) = @_;
9743 if(not $S1) {
9744 return 0;
9745 }
9746 elsif(not $S2) {
9747 return 1;
9748 }
9749 return ($Severity_Val{$S1}>$Severity_Val{$S2});
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009750}
9751
9752sub getProblemSeverity($$)
9753{
9754 my ($Level, $Kind) = @_;
9755 return $CompatRules{$Level}{$Kind}{"Severity"};
9756}
9757
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04009758sub isRecurType($$)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009759{
9760 foreach (@RecurTypes)
9761 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04009762 if( $_->{"T1"} eq $_[0]
9763 and $_->{"T2"} eq $_[1] )
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009764 {
9765 return 1;
9766 }
9767 }
9768 return 0;
9769}
9770
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04009771sub pushType($$)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009772{
9773 my %TypeIDs=(
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04009774 "T1" => $_[0], #Tid1
9775 "T2" => $_[1] #Tid2
Andrey Ponomarenko16934472012-03-29 15:37:04 +04009776 );
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009777 push(@RecurTypes, \%TypeIDs);
9778}
9779
9780sub isRenamed($$$$$)
9781{
9782 my ($MemPos, $Type1, $LVersion1, $Type2, $LVersion2) = @_;
9783 my $Member_Name = $Type1->{"Memb"}{$MemPos}{"name"};
9784 my $MemberType_Id = $Type1->{"Memb"}{$MemPos}{"type"};
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04009785 my %MemberType_Pure = get_PureType($MemberType_Id, $LVersion1);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009786 if(not defined $Type2->{"Memb"}{$MemPos}) {
9787 return "";
9788 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04009789 my $PairType_Id = $Type2->{"Memb"}{$MemPos}{"type"};
9790 my %PairType_Pure = get_PureType($PairType_Id, $LVersion2);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009791
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04009792 my $Pair_Name = $Type2->{"Memb"}{$MemPos}{"name"};
9793 my $MemberPair_Pos_Rev = ($Member_Name eq $Pair_Name)?$MemPos:find_MemberPair_Pos_byName($Pair_Name, $Type1);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009794 if($MemberPair_Pos_Rev eq "lost")
9795 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04009796 if($MemberType_Pure{"Name"} eq $PairType_Pure{"Name"})
9797 { # base type match
9798 return $Pair_Name;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009799 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04009800 if($TypeInfo{$LVersion1}{$MemberType_Id}{"Name"} eq $TypeInfo{$LVersion2}{$PairType_Id}{"Name"})
9801 { # exact type match
9802 return $Pair_Name;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009803 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04009804 if($MemberType_Pure{"Size"} eq $PairType_Pure{"Size"})
9805 { # size match
9806 return $Pair_Name;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009807 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04009808 if(isReserved($Pair_Name))
9809 { # reserved fields
9810 return $Pair_Name;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009811 }
9812 }
9813 return "";
9814}
9815
9816sub isLastElem($$)
9817{
9818 my ($Pos, $TypeRef) = @_;
9819 my $Name = $TypeRef->{"Memb"}{$Pos}{"name"};
9820 if($Name=~/last|count|max|total/i)
9821 { # GST_LEVEL_COUNT, GST_RTSP_ELAST
9822 return 1;
9823 }
9824 elsif($Name=~/END|NLIMITS\Z/)
9825 { # __RLIMIT_NLIMITS
9826 return 1;
9827 }
9828 elsif($Name=~/\AN[A-Z](.+)[a-z]+s\Z/
9829 and $Pos+1==keys(%{$TypeRef->{"Memb"}}))
9830 { # NImageFormats, NColorRoles
9831 return 1;
9832 }
9833 return 0;
9834}
9835
9836sub nonComparable($$)
9837{
9838 my ($T1, $T2) = @_;
9839 if($T1->{"Name"} ne $T2->{"Name"}
9840 and not isAnon($T1->{"Name"})
9841 and not isAnon($T2->{"Name"}))
9842 { # different names
9843 if($T1->{"Type"} ne "Pointer"
9844 or $T2->{"Type"} ne "Pointer")
9845 { # compare base types
9846 return 1;
9847 }
9848 if($T1->{"Name"}!~/\Avoid\s*\*/
9849 and $T2->{"Name"}=~/\Avoid\s*\*/)
9850 {
9851 return 1;
9852 }
9853 }
9854 elsif($T1->{"Type"} ne $T2->{"Type"})
9855 { # different types
9856 if($T1->{"Type"} eq "Class"
9857 and $T2->{"Type"} eq "Struct")
9858 { # "class" to "struct"
9859 return 0;
9860 }
9861 elsif($T2->{"Type"} eq "Class"
9862 and $T1->{"Type"} eq "Struct")
9863 { # "struct" to "class"
9864 return 0;
9865 }
9866 else
9867 { # "class" to "enum"
9868 # "union" to "class"
9869 # ...
9870 return 1;
9871 }
9872 }
9873 return 0;
9874}
9875
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04009876sub mergeTypes($$$)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009877{
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04009878 my ($Type1_Id, $Type2_Id, $Level) = @_;
9879 return () if(not $Type1_Id or not $Type2_Id);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009880 my (%Sub_SubProblems, %SubProblems) = ();
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04009881 if($Cache{"mergeTypes"}{$Level}{$Type1_Id}{$Type2_Id})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009882 { # already merged
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04009883 return %{$Cache{"mergeTypes"}{$Level}{$Type1_Id}{$Type2_Id}};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009884 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04009885 my %Type1 = get_Type($Type1_Id, 1);
9886 my %Type2 = get_Type($Type2_Id, 2);
Andrey Ponomarenko16934472012-03-29 15:37:04 +04009887 if(not $Type1{"Name"} or not $Type2{"Name"}) {
9888 return ();
9889 }
9890 $CheckedTypes{$Level}{$Type1{"Name"}}=1;
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04009891 my %Type1_Pure = get_PureType($Type1_Id, 1);
9892 my %Type2_Pure = get_PureType($Type2_Id, 2);
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04009893 $CheckedTypes{$Level}{$Type1_Pure{"Name"}}=1;
Andrey Ponomarenko85043792012-05-14 16:48:07 +04009894 if(not $Type1_Pure{"Size"} or not $Type2_Pure{"Size"})
9895 { # including a case when "class Class { ... };" changed to "class Class;"
9896 return ();
9897 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04009898 if(isRecurType($Type1_Pure{"Tid"}, $Type2_Pure{"Tid"}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009899 { # skip recursive declarations
9900 return ();
9901 }
9902 return () if(not $Type1_Pure{"Name"} or not $Type2_Pure{"Name"});
9903 return () if($SkipTypes{1}{$Type1_Pure{"Name"}});
9904 return () if($SkipTypes{1}{$Type1{"Name"}});
9905
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04009906 my %Typedef_1 = goToFirst($Type1{"Tid"}, 1, "Typedef");
9907 my %Typedef_2 = goToFirst($Type2{"Tid"}, 2, "Typedef");
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04009908 if(not $UseOldDumps and %Typedef_1 and %Typedef_2
9909 and $Typedef_1{"Type"} eq "Typedef" and $Typedef_2{"Type"} eq "Typedef"
9910 and $Typedef_1{"Name"} eq $Typedef_2{"Name"})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009911 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04009912 my %Base_1 = get_OneStep_BaseType($Typedef_1{"Tid"}, 1);
9913 my %Base_2 = get_OneStep_BaseType($Typedef_2{"Tid"}, 2);
Andrey Ponomarenko85043792012-05-14 16:48:07 +04009914 if($Base_1{"Name"} ne $Base_2{"Name"})
9915 {
9916 if(differentDumps("G")
9917 or differentDumps("V"))
9918 { # different GCC versions or different dumps
9919 $Base_1{"Name"} = uncover_typedefs($Base_1{"Name"}, 1);
9920 $Base_2{"Name"} = uncover_typedefs($Base_2{"Name"}, 2);
9921 # std::__va_list and __va_list
9922 $Base_1{"Name"}=~s/\A(\w+::)+//;
9923 $Base_2{"Name"}=~s/\A(\w+::)+//;
9924 $Base_1{"Name"} = formatName($Base_1{"Name"});
9925 $Base_2{"Name"} = formatName($Base_2{"Name"});
9926 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009927 }
9928 if($Base_1{"Name"}!~/anon\-/ and $Base_2{"Name"}!~/anon\-/
9929 and $Base_1{"Name"} ne $Base_2{"Name"})
9930 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04009931 if($Level eq "Binary"
9932 and $Type1{"Size"} ne $Type2{"Size"})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009933 {
9934 %{$SubProblems{"DataType_Size"}{$Typedef_1{"Name"}}}=(
9935 "Target"=>$Typedef_1{"Name"},
9936 "Type_Name"=>$Typedef_1{"Name"},
9937 "Type_Type"=>"Typedef",
9938 "Old_Size"=>$Type1{"Size"}*$BYTE_SIZE,
9939 "New_Size"=>$Type2{"Size"}*$BYTE_SIZE );
9940 }
9941 %{$SubProblems{"Typedef_BaseType"}{$Typedef_1{"Name"}}}=(
9942 "Target"=>$Typedef_1{"Name"},
9943 "Type_Name"=>$Typedef_1{"Name"},
9944 "Type_Type"=>"Typedef",
9945 "Old_Value"=>$Base_1{"Name"},
9946 "New_Value"=>$Base_2{"Name"} );
9947 }
9948 }
9949 if(nonComparable(\%Type1_Pure, \%Type2_Pure))
9950 { # different types (reported in detectTypeChange(...))
9951 if($Type1_Pure{"Name"} eq $Type2_Pure{"Name"}
9952 and $Type1_Pure{"Type"} ne $Type2_Pure{"Type"}
9953 and $Type1_Pure{"Type"}!~/Intrinsic|Pointer|Ref|Typedef/)
9954 { # different type of the type
9955 %{$SubProblems{"DataType_Type"}{$Type1_Pure{"Name"}}}=(
9956 "Target"=>$Type1_Pure{"Name"},
9957 "Type_Name"=>$Type1_Pure{"Name"},
9958 "Type_Type"=>$Type1_Pure{"Type"},
9959 "Old_Value"=>lc($Type1_Pure{"Type"}),
9960 "New_Value"=>lc($Type2_Pure{"Type"}) );
9961 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04009962 %{$Cache{"mergeTypes"}{$Level}{$Type1_Id}{$Type2_Id}} = %SubProblems;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009963 return %SubProblems;
9964 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04009965 pushType($Type1_Pure{"Tid"}, $Type2_Pure{"Tid"});
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009966 if(($Type1_Pure{"Name"} eq $Type2_Pure{"Name"}
9967 or (isAnon($Type1_Pure{"Name"}) and isAnon($Type2_Pure{"Name"})))
9968 and $Type1_Pure{"Type"}=~/\A(Struct|Class|Union)\Z/)
9969 { # checking size
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04009970 if($Level eq "Binary"
9971 and $Type1_Pure{"Size"} ne $Type2_Pure{"Size"})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009972 {
9973 my $ProblemKind = "DataType_Size";
9974 if($Type1_Pure{"Type"} eq "Class"
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04009975 and keys(%{$ClassMethods{$Level}{1}{$Type1_Pure{"Name"}}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009976 {
9977 if(isCopyingClass($Type1_Pure{"Tid"}, 1)) {
9978 $ProblemKind = "Size_Of_Copying_Class";
9979 }
9980 elsif($AllocableClass{1}{$Type1_Pure{"Name"}})
9981 {
9982 if(int($Type2_Pure{"Size"})>int($Type1_Pure{"Size"})) {
9983 $ProblemKind = "Size_Of_Allocable_Class_Increased";
9984 }
9985 else {
9986 # descreased size of allocable class
9987 # it has no special effects
9988 }
9989 }
9990 }
9991 %{$SubProblems{$ProblemKind}{$Type1_Pure{"Name"}}}=(
9992 "Target"=>$Type1_Pure{"Name"},
9993 "Type_Name"=>$Type1_Pure{"Name"},
9994 "Type_Type"=>$Type1_Pure{"Type"},
9995 "Old_Size"=>$Type1_Pure{"Size"}*$BYTE_SIZE,
9996 "New_Size"=>$Type2_Pure{"Size"}*$BYTE_SIZE,
9997 "InitialType_Type"=>$Type1_Pure{"Type"} );
9998 }
9999 }
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040010000 if(defined $Type1_Pure{"BaseType"} and $Type1_Pure{"BaseType"}{"Tid"}
10001 and defined $Type2_Pure{"BaseType"} and $Type2_Pure{"BaseType"}{"Tid"})
10002 { # checking base types
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040010003 %Sub_SubProblems = mergeTypes($Type1_Pure{"BaseType"}{"Tid"}, $Type2_Pure{"BaseType"}{"Tid"}, $Level);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010004 foreach my $Sub_SubProblemType (keys(%Sub_SubProblems))
10005 {
10006 foreach my $Sub_SubLocation (keys(%{$Sub_SubProblems{$Sub_SubProblemType}}))
10007 {
10008 foreach my $Attr (keys(%{$Sub_SubProblems{$Sub_SubProblemType}{$Sub_SubLocation}})) {
10009 $SubProblems{$Sub_SubProblemType}{$Sub_SubLocation}{$Attr} = $Sub_SubProblems{$Sub_SubProblemType}{$Sub_SubLocation}{$Attr};
10010 }
10011 $SubProblems{$Sub_SubProblemType}{$Sub_SubLocation}{"InitialType_Type"} = $Type1_Pure{"Type"};
10012 }
10013 }
10014 }
10015 my (%AddedField, %RemovedField, %RenamedField, %RenamedField_Rev, %RelatedField, %RelatedField_Rev) = ();
10016 my %NameToPosA = map {$Type1_Pure{"Memb"}{$_}{"name"}=>$_} keys(%{$Type1_Pure{"Memb"}});
10017 my %NameToPosB = map {$Type2_Pure{"Memb"}{$_}{"name"}=>$_} keys(%{$Type2_Pure{"Memb"}});
10018 foreach my $Member_Pos (sort {int($a) <=> int($b)} keys(%{$Type1_Pure{"Memb"}}))
10019 { # detect removed and renamed fields
10020 my $Member_Name = $Type1_Pure{"Memb"}{$Member_Pos}{"name"};
10021 next if(not $Member_Name);
10022 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);
10023 if($MemberPair_Pos eq "lost")
10024 {
10025 if($Type2_Pure{"Type"}=~/\A(Struct|Class|Union)\Z/)
10026 {
10027 if(isUnnamed($Member_Name))
10028 { # support for old-version dumps
10029 # unnamed fields have been introduced in the ACC 1.23 (dump 2.1 format)
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040010030 if(not checkDump(2, "2.1")) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010031 next;
10032 }
10033 }
10034 if(my $RenamedTo = isRenamed($Member_Pos, \%Type1_Pure, 1, \%Type2_Pure, 2))
10035 { # renamed
10036 $RenamedField{$Member_Pos}=$RenamedTo;
10037 $RenamedField_Rev{$NameToPosB{$RenamedTo}}=$Member_Name;
10038 }
10039 else
10040 { # removed
10041 $RemovedField{$Member_Pos}=1;
10042 }
10043 }
10044 elsif($Type1_Pure{"Type"} eq "Enum")
10045 {
10046 my $Member_Value1 = $Type1_Pure{"Memb"}{$Member_Pos}{"value"};
10047 next if($Member_Value1 eq "");
10048 $MemberPair_Pos = find_MemberPair_Pos_byVal($Member_Value1, \%Type2_Pure);
10049 if($MemberPair_Pos ne "lost")
10050 { # renamed
10051 my $RenamedTo = $Type2_Pure{"Memb"}{$MemberPair_Pos}{"name"};
10052 my $MemberPair_Pos_Rev = find_MemberPair_Pos_byName($RenamedTo, \%Type1_Pure);
10053 if($MemberPair_Pos_Rev eq "lost")
10054 {
10055 $RenamedField{$Member_Pos}=$RenamedTo;
10056 $RenamedField_Rev{$NameToPosB{$RenamedTo}}=$Member_Name;
10057 }
10058 else {
10059 $RemovedField{$Member_Pos}=1;
10060 }
10061 }
10062 else
10063 { # removed
10064 $RemovedField{$Member_Pos}=1;
10065 }
10066 }
10067 }
10068 else
10069 { # related
10070 $RelatedField{$Member_Pos} = $MemberPair_Pos;
10071 $RelatedField_Rev{$MemberPair_Pos} = $Member_Pos;
10072 }
10073 }
10074 foreach my $Member_Pos (sort {int($a) <=> int($b)} keys(%{$Type2_Pure{"Memb"}}))
10075 { # detect added fields
10076 my $Member_Name = $Type2_Pure{"Memb"}{$Member_Pos}{"name"};
10077 next if(not $Member_Name);
10078 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);
10079 if($MemberPair_Pos eq "lost")
10080 {
10081 if(isUnnamed($Member_Name))
10082 { # support for old-version dumps
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040010083 # unnamed fields have been introduced in the ACC 1.23 (dump 2.1 format)
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040010084 if(not checkDump(1, "2.1")) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010085 next;
10086 }
10087 }
10088 if($Type2_Pure{"Type"}=~/\A(Struct|Class|Union|Enum)\Z/)
10089 {
10090 if(not $RenamedField_Rev{$Member_Pos})
10091 { # added
10092 $AddedField{$Member_Pos}=1;
10093 }
10094 }
10095 }
10096 }
10097 if($Type2_Pure{"Type"}=~/\A(Struct|Class)\Z/)
10098 { # detect moved fields
10099 my (%RelPos, %RelPosName, %AbsPos) = ();
10100 my $Pos = 0;
10101 foreach my $Member_Pos (sort {int($a) <=> int($b)} keys(%{$Type1_Pure{"Memb"}}))
10102 { # relative positions in 1st version
10103 my $Member_Name = $Type1_Pure{"Memb"}{$Member_Pos}{"name"};
10104 next if(not $Member_Name);
10105 if(not $RemovedField{$Member_Pos})
10106 { # old type without removed fields
10107 $RelPos{1}{$Member_Name}=$Pos;
10108 $RelPosName{1}{$Pos} = $Member_Name;
10109 $AbsPos{1}{$Pos++} = $Member_Pos;
10110 }
10111 }
10112 $Pos = 0;
10113 foreach my $Member_Pos (sort {int($a) <=> int($b)} keys(%{$Type2_Pure{"Memb"}}))
10114 { # relative positions in 2nd version
10115 my $Member_Name = $Type2_Pure{"Memb"}{$Member_Pos}{"name"};
10116 next if(not $Member_Name);
10117 if(not $AddedField{$Member_Pos})
10118 { # new type without added fields
10119 $RelPos{2}{$Member_Name}=$Pos;
10120 $RelPosName{2}{$Pos} = $Member_Name;
10121 $AbsPos{2}{$Pos++} = $Member_Pos;
10122 }
10123 }
10124 foreach my $Member_Name (keys(%{$RelPos{1}}))
10125 {
10126 my $RPos1 = $RelPos{1}{$Member_Name};
10127 my $AbsPos1 = $NameToPosA{$Member_Name};
10128 my $Member_Name2 = $Member_Name;
10129 if(my $RenamedTo = $RenamedField{$AbsPos1})
10130 { # renamed
10131 $Member_Name2 = $RenamedTo;
10132 }
10133 my $RPos2 = $RelPos{2}{$Member_Name2};
10134 if($RPos2 ne "" and $RPos1 ne $RPos2)
10135 { # different relative positions
10136 my $AbsPos2 = $NameToPosB{$Member_Name2};
10137 if($AbsPos1 ne $AbsPos2)
10138 { # different absolute positions
10139 my $ProblemType = "Moved_Field";
10140 if(not isPublic(\%Type1_Pure, $AbsPos1))
10141 { # may change layout and size of type
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040010142 if($Level eq "Source") {
10143 next;
10144 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010145 $ProblemType = "Moved_Private_Field";
10146 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040010147 if($Level eq "Binary"
10148 and $Type1_Pure{"Size"} ne $Type2_Pure{"Size"})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010149 { # affected size
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040010150 my $MemSize1 = $TypeInfo{1}{$Type1_Pure{"Memb"}{$AbsPos1}{"type"}}{"Size"};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010151 my $MovedAbsPos = $AbsPos{1}{$RPos2};
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040010152 my $MemSize2 = $TypeInfo{1}{$Type1_Pure{"Memb"}{$MovedAbsPos}{"type"}}{"Size"};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010153 if($MemSize1 ne $MemSize2) {
10154 $ProblemType .= "_And_Size";
10155 }
10156 }
10157 if($ProblemType eq "Moved_Private_Field") {
10158 next;
10159 }
10160 %{$SubProblems{$ProblemType}{$Member_Name}}=(
10161 "Target"=>$Member_Name,
10162 "Type_Name"=>$Type1_Pure{"Name"},
10163 "Type_Type"=>$Type1_Pure{"Type"},
10164 "Old_Value"=>$RPos1,
10165 "New_Value"=>$RPos2 );
10166 }
10167 }
10168 }
10169 }
10170 foreach my $Member_Pos (sort {int($a) <=> int($b)} keys(%{$Type1_Pure{"Memb"}}))
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040010171 { # check older fields, public and private
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010172 my $Member_Name = $Type1_Pure{"Memb"}{$Member_Pos}{"name"};
10173 next if(not $Member_Name);
10174 if(my $RenamedTo = $RenamedField{$Member_Pos})
10175 { # renamed
10176 if($Type2_Pure{"Type"}=~/\A(Struct|Class|Union)\Z/)
10177 {
10178 if(isPublic(\%Type1_Pure, $Member_Pos))
10179 {
10180 %{$SubProblems{"Renamed_Field"}{$Member_Name}}=(
10181 "Target"=>$Member_Name,
10182 "Type_Name"=>$Type1_Pure{"Name"},
10183 "Type_Type"=>$Type1_Pure{"Type"},
10184 "Old_Value"=>$Member_Name,
10185 "New_Value"=>$RenamedTo );
10186 }
10187 }
10188 elsif($Type1_Pure{"Type"} eq "Enum")
10189 {
10190 %{$SubProblems{"Enum_Member_Name"}{$Type1_Pure{"Memb"}{$Member_Pos}{"value"}}}=(
10191 "Target"=>$Type1_Pure{"Memb"}{$Member_Pos}{"value"},
10192 "Type_Name"=>$Type1_Pure{"Name"},
10193 "Type_Type"=>$Type1_Pure{"Type"},
10194 "Old_Value"=>$Member_Name,
10195 "New_Value"=>$RenamedTo );
10196 }
10197 }
10198 elsif($RemovedField{$Member_Pos})
10199 { # removed
10200 if($Type2_Pure{"Type"}=~/\A(Struct|Class)\Z/)
10201 {
10202 my $ProblemType = "Removed_Field";
10203 if(not isPublic(\%Type1_Pure, $Member_Pos)
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040010204 or isUnnamed($Member_Name))
10205 {
10206 if($Level eq "Source") {
10207 next;
10208 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010209 $ProblemType = "Removed_Private_Field";
10210 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040010211 if($Level eq "Binary"
10212 and not isMemPadded($Member_Pos, -1, \%Type1_Pure, \%RemovedField, 1))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010213 {
10214 if(my $MNum = isAccessible(\%Type1_Pure, \%RemovedField, $Member_Pos+1, -1))
10215 { # affected fields
10216 if(getOffset($MNum-1, \%Type1_Pure, 1)!=getOffset($RelatedField{$MNum-1}, \%Type2_Pure, 2))
10217 { # changed offset
10218 $ProblemType .= "_And_Layout";
10219 }
10220 }
10221 if($Type1_Pure{"Size"} ne $Type2_Pure{"Size"})
10222 { # affected size
10223 $ProblemType .= "_And_Size";
10224 }
10225 }
10226 if($ProblemType eq "Removed_Private_Field") {
10227 next;
10228 }
10229 %{$SubProblems{$ProblemType}{$Member_Name}}=(
10230 "Target"=>$Member_Name,
10231 "Type_Name"=>$Type1_Pure{"Name"},
10232 "Type_Type"=>$Type1_Pure{"Type"} );
10233 }
10234 elsif($Type2_Pure{"Type"} eq "Union")
10235 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040010236 if($Level eq "Binary"
10237 and $Type1_Pure{"Size"} ne $Type2_Pure{"Size"})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010238 {
10239 %{$SubProblems{"Removed_Union_Field_And_Size"}{$Member_Name}}=(
10240 "Target"=>$Member_Name,
10241 "Type_Name"=>$Type1_Pure{"Name"},
10242 "Type_Type"=>$Type1_Pure{"Type"} );
10243 }
10244 else
10245 {
10246 %{$SubProblems{"Removed_Union_Field"}{$Member_Name}}=(
10247 "Target"=>$Member_Name,
10248 "Type_Name"=>$Type1_Pure{"Name"},
10249 "Type_Type"=>$Type1_Pure{"Type"} );
10250 }
10251 }
10252 elsif($Type1_Pure{"Type"} eq "Enum")
10253 {
10254 %{$SubProblems{"Enum_Member_Removed"}{$Member_Name}}=(
10255 "Target"=>$Member_Name,
10256 "Type_Name"=>$Type1_Pure{"Name"},
10257 "Type_Type"=>$Type1_Pure{"Type"},
10258 "Old_Value"=>$Member_Name );
10259 }
10260 }
10261 else
10262 { # changed
10263 my $MemberPair_Pos = $RelatedField{$Member_Pos};
10264 if($Type1_Pure{"Type"} eq "Enum")
10265 {
10266 my $Member_Value1 = $Type1_Pure{"Memb"}{$Member_Pos}{"value"};
10267 next if($Member_Value1 eq "");
10268 my $Member_Value2 = $Type2_Pure{"Memb"}{$MemberPair_Pos}{"value"};
10269 next if($Member_Value2 eq "");
10270 if($Member_Value1 ne $Member_Value2)
10271 {
10272 my $ProblemType = "Enum_Member_Value";
10273 if(isLastElem($Member_Pos, \%Type1_Pure)) {
10274 $ProblemType = "Enum_Last_Member_Value";
10275 }
10276 %{$SubProblems{$ProblemType}{$Member_Name}}=(
10277 "Target"=>$Member_Name,
10278 "Type_Name"=>$Type1_Pure{"Name"},
10279 "Type_Type"=>$Type1_Pure{"Type"},
10280 "Old_Value"=>$Member_Value1,
10281 "New_Value"=>$Member_Value2 );
10282 }
10283 }
10284 elsif($Type2_Pure{"Type"}=~/\A(Struct|Class|Union)\Z/)
10285 {
10286 my $MemberType1_Id = $Type1_Pure{"Memb"}{$Member_Pos}{"type"};
10287 my $MemberType2_Id = $Type2_Pure{"Memb"}{$MemberPair_Pos}{"type"};
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040010288 my $SizeV1 = $TypeInfo{1}{$MemberType1_Id}{"Size"}*$BYTE_SIZE;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010289 if(my $BSize1 = $Type1_Pure{"Memb"}{$Member_Pos}{"bitfield"}) {
10290 $SizeV1 = $BSize1;
10291 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040010292 my $SizeV2 = $TypeInfo{2}{$MemberType2_Id}{"Size"}*$BYTE_SIZE;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010293 if(my $BSize2 = $Type2_Pure{"Memb"}{$MemberPair_Pos}{"bitfield"}) {
10294 $SizeV2 = $BSize2;
10295 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040010296 my $MemberType1_Name = $TypeInfo{1}{$MemberType1_Id}{"Name"};
10297 my $MemberType2_Name = $TypeInfo{2}{$MemberType2_Id}{"Name"};
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040010298 if($Level eq "Binary"
10299 and $SizeV1 ne $SizeV2)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010300 {
10301 if($MemberType1_Name eq $MemberType2_Name or (isAnon($MemberType1_Name) and isAnon($MemberType2_Name))
10302 or ($Type1_Pure{"Memb"}{$Member_Pos}{"bitfield"} and $Type2_Pure{"Memb"}{$MemberPair_Pos}{"bitfield"}))
10303 { # field size change (including anon-structures and unions)
10304 # - same types
10305 # - unnamed types
10306 # - bitfields
10307 my $ProblemType = "Field_Size";
10308 if(not isPublic(\%Type1_Pure, $Member_Pos)
10309 or isUnnamed($Member_Name))
10310 { # should not be accessed by applications, goes to "Low Severity"
10311 # example: "abidata" members in GStreamer types
10312 $ProblemType = "Private_".$ProblemType;
10313 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040010314 if(not isMemPadded($Member_Pos, $TypeInfo{2}{$MemberType2_Id}{"Size"}*$BYTE_SIZE, \%Type1_Pure, \%RemovedField, 1))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010315 { # check an effect
10316 if(my $MNum = isAccessible(\%Type1_Pure, \%RemovedField, $Member_Pos+1, -1))
10317 { # public fields after the current
10318 if(getOffset($MNum-1, \%Type1_Pure, 1)!=getOffset($RelatedField{$MNum-1}, \%Type2_Pure, 2))
10319 { # changed offset
10320 $ProblemType .= "_And_Layout";
10321 }
10322 }
10323 if($Type1_Pure{"Size"} ne $Type2_Pure{"Size"}) {
10324 $ProblemType .= "_And_Type_Size";
10325 }
10326 }
10327 if($ProblemType eq "Private_Field_Size")
10328 { # private field size with no effect
10329 $ProblemType = "";
10330 }
10331 if($ProblemType)
10332 { # register a problem
10333 %{$SubProblems{$ProblemType}{$Member_Name}}=(
10334 "Target"=>$Member_Name,
10335 "Type_Name"=>$Type1_Pure{"Name"},
10336 "Type_Type"=>$Type1_Pure{"Type"},
10337 "Old_Size"=>$SizeV1,
10338 "New_Size"=>$SizeV2);
10339 }
10340 }
10341 }
10342 if($Type1_Pure{"Memb"}{$Member_Pos}{"bitfield"}
10343 or $Type2_Pure{"Memb"}{$MemberPair_Pos}{"bitfield"})
10344 { # do NOT check bitfield type changes
10345 next;
10346 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040010347 if(checkDump(1, "2.13") and checkDump(2, "2.13"))
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040010348 {
10349 if(not $Type1_Pure{"Memb"}{$Member_Pos}{"mutable"}
10350 and $Type2_Pure{"Memb"}{$MemberPair_Pos}{"mutable"})
10351 {
10352 %{$SubProblems{"Field_Became_Mutable"}{$Member_Name}}=(
10353 "Target"=>$Member_Name,
10354 "Type_Name"=>$Type1_Pure{"Name"},
10355 "Type_Type"=>$Type1_Pure{"Type"});
10356 }
10357 elsif($Type1_Pure{"Memb"}{$Member_Pos}{"mutable"}
10358 and not $Type2_Pure{"Memb"}{$MemberPair_Pos}{"mutable"})
10359 {
10360 %{$SubProblems{"Field_Became_NonMutable"}{$Member_Name}}=(
10361 "Target"=>$Member_Name,
10362 "Type_Name"=>$Type1_Pure{"Name"},
10363 "Type_Type"=>$Type1_Pure{"Type"});
10364 }
10365 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040010366 %Sub_SubProblems = detectTypeChange($MemberType1_Id, $MemberType2_Id, "Field", $Level);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010367 foreach my $ProblemType (keys(%Sub_SubProblems))
10368 {
10369 my $Old_Value = $Sub_SubProblems{$ProblemType}{"Old_Value"};
10370 my $New_Value = $Sub_SubProblems{$ProblemType}{"New_Value"};
10371 if($ProblemType eq "Field_Type"
10372 or $ProblemType eq "Field_Type_And_Size")
10373 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040010374 if(checkDump(1, "2.6") and checkDump(2, "2.6"))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010375 {
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040010376 if(my $RA = addedQual($Old_Value, $New_Value, "volatile"))
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040010377 {
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040010378 %{$Sub_SubProblems{"Field_Became_Volatile"}} = %{$Sub_SubProblems{$ProblemType}};
10379 if($Level eq "Source"
10380 and cmpBTypes($Old_Value, $New_Value, 1, 2)) {
10381 delete($Sub_SubProblems{$ProblemType});
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040010382 }
10383 }
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040010384 elsif(my $RR = removedQual($Old_Value, $New_Value, "volatile"))
10385 {
10386 %{$Sub_SubProblems{"Field_Became_NonVolatile"}} = %{$Sub_SubProblems{$ProblemType}};
10387 if($Level eq "Source"
10388 and cmpBTypes($Old_Value, $New_Value, 1, 2)) {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040010389 delete($Sub_SubProblems{$ProblemType});
10390 }
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040010391 }
10392 }
10393 if(my $RA = addedQual($Old_Value, $New_Value, "const"))
10394 {
10395 if($RA==2) {
10396 %{$Sub_SubProblems{"Field_Added_Const"}} = %{$Sub_SubProblems{$ProblemType}};
10397 }
10398 else {
10399 %{$Sub_SubProblems{"Field_Became_Const"}} = %{$Sub_SubProblems{$ProblemType}};
10400 }
10401 if($Level eq "Source"
10402 and cmpBTypes($Old_Value, $New_Value, 1, 2)) {
10403 delete($Sub_SubProblems{$ProblemType});
10404 }
10405 }
10406 elsif(my $RR = removedQual($Old_Value, $New_Value, "const"))
10407 {
10408 if($RR==2) {
10409 %{$Sub_SubProblems{"Field_Removed_Const"}} = %{$Sub_SubProblems{$ProblemType}};
10410 }
10411 else {
10412 %{$Sub_SubProblems{"Field_Became_NonConst"}} = %{$Sub_SubProblems{$ProblemType}};
10413 }
10414 if($Level eq "Source"
10415 and cmpBTypes($Old_Value, $New_Value, 1, 2)) {
10416 delete($Sub_SubProblems{$ProblemType});
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010417 }
10418 }
10419 }
10420 }
10421 foreach my $ProblemType (keys(%Sub_SubProblems))
10422 {
10423 my $ProblemType_Init = $ProblemType;
10424 if($ProblemType eq "Field_Type_And_Size")
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040010425 { # Binary
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010426 if(not isPublic(\%Type1_Pure, $Member_Pos)
10427 or isUnnamed($Member_Name)) {
10428 $ProblemType = "Private_".$ProblemType;
10429 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040010430 if(not isMemPadded($Member_Pos, $TypeInfo{2}{$MemberType2_Id}{"Size"}*$BYTE_SIZE, \%Type1_Pure, \%RemovedField, 1))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010431 { # check an effect
10432 if(my $MNum = isAccessible(\%Type1_Pure, \%RemovedField, $Member_Pos+1, -1))
10433 { # public fields after the current
10434 if(getOffset($MNum-1, \%Type1_Pure, 1)!=getOffset($RelatedField{$MNum-1}, \%Type2_Pure, 2))
10435 { # changed offset
10436 $ProblemType .= "_And_Layout";
10437 }
10438 }
10439 if($Type1_Pure{"Size"} ne $Type2_Pure{"Size"}) {
10440 $ProblemType .= "_And_Type_Size";
10441 }
10442 }
10443 }
10444 else
10445 {
10446 if(not isPublic(\%Type1_Pure, $Member_Pos)
10447 or isUnnamed($Member_Name)) {
10448 next;
10449 }
10450 }
10451 if($ProblemType eq "Private_Field_Type_And_Size")
10452 { # private field change with no effect
10453 next;
10454 }
10455 %{$SubProblems{$ProblemType}{$Member_Name}}=(
10456 "Target"=>$Member_Name,
10457 "Type_Name"=>$Type1_Pure{"Name"},
10458 "Type_Type"=>$Type1_Pure{"Type"} );
10459 foreach my $Attr (keys(%{$Sub_SubProblems{$ProblemType_Init}}))
10460 { # other properties
10461 $SubProblems{$ProblemType}{$Member_Name}{$Attr} = $Sub_SubProblems{$ProblemType_Init}{$Attr};
10462 }
10463 }
10464 if(not isPublic(\%Type1_Pure, $Member_Pos))
10465 { # do NOT check internal type changes
10466 next;
10467 }
10468 if($MemberType1_Id and $MemberType2_Id)
10469 {# checking member type changes (replace)
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040010470 %Sub_SubProblems = mergeTypes($MemberType1_Id, $MemberType2_Id, $Level);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010471 foreach my $Sub_SubProblemType (keys(%Sub_SubProblems))
10472 {
10473 foreach my $Sub_SubLocation (keys(%{$Sub_SubProblems{$Sub_SubProblemType}}))
10474 {
10475 my $NewLocation = ($Sub_SubLocation)?$Member_Name."->".$Sub_SubLocation:$Member_Name;
10476 $SubProblems{$Sub_SubProblemType}{$NewLocation}{"IsInTypeInternals"}=1;
10477 foreach my $Attr (keys(%{$Sub_SubProblems{$Sub_SubProblemType}{$Sub_SubLocation}})) {
10478 $SubProblems{$Sub_SubProblemType}{$NewLocation}{$Attr} = $Sub_SubProblems{$Sub_SubProblemType}{$Sub_SubLocation}{$Attr};
10479 }
10480 if($Sub_SubLocation!~/\-\>/) {
10481 $SubProblems{$Sub_SubProblemType}{$NewLocation}{"Start_Type_Name"} = $MemberType1_Name;
10482 }
10483 }
10484 }
10485 }
10486 }
10487 }
10488 }
10489 foreach my $Member_Pos (sort {int($a) <=> int($b)} keys(%{$Type2_Pure{"Memb"}}))
10490 { # checking added members, public and private
10491 my $Member_Name = $Type2_Pure{"Memb"}{$Member_Pos}{"name"};
10492 next if(not $Member_Name);
10493 if($AddedField{$Member_Pos})
10494 { # added
10495 if($Type2_Pure{"Type"}=~/\A(Struct|Class)\Z/)
10496 {
10497 my $ProblemType = "Added_Field";
10498 if(not isPublic(\%Type2_Pure, $Member_Pos)
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040010499 or isUnnamed($Member_Name))
10500 {
10501 if($Level eq "Source") {
10502 next;
10503 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010504 $ProblemType = "Added_Private_Field";
10505 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040010506 if($Level eq "Binary"
10507 and not isMemPadded($Member_Pos, -1, \%Type2_Pure, \%AddedField, 2))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010508 {
10509 if(my $MNum = isAccessible(\%Type2_Pure, \%AddedField, $Member_Pos, -1))
10510 { # public fields after the current
10511 if(getOffset($MNum-1, \%Type2_Pure, 2)!=getOffset($RelatedField_Rev{$MNum-1}, \%Type1_Pure, 1))
10512 { # changed offset
10513 $ProblemType .= "_And_Layout";
10514 }
10515 }
10516 if($Type1_Pure{"Size"} ne $Type2_Pure{"Size"}) {
10517 $ProblemType .= "_And_Size";
10518 }
10519 }
10520 if($ProblemType eq "Added_Private_Field")
10521 { # skip added private fields
10522 next;
10523 }
10524 %{$SubProblems{$ProblemType}{$Member_Name}}=(
10525 "Target"=>$Member_Name,
10526 "Type_Name"=>$Type1_Pure{"Name"},
10527 "Type_Type"=>$Type1_Pure{"Type"} );
10528 }
10529 elsif($Type2_Pure{"Type"} eq "Union")
10530 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040010531 if($Level eq "Binary"
10532 and $Type1_Pure{"Size"} ne $Type2_Pure{"Size"})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010533 {
10534 %{$SubProblems{"Added_Union_Field_And_Size"}{$Member_Name}}=(
10535 "Target"=>$Member_Name,
10536 "Type_Name"=>$Type1_Pure{"Name"},
10537 "Type_Type"=>$Type1_Pure{"Type"} );
10538 }
10539 else
10540 {
10541 %{$SubProblems{"Added_Union_Field"}{$Member_Name}}=(
10542 "Target"=>$Member_Name,
10543 "Type_Name"=>$Type1_Pure{"Name"},
10544 "Type_Type"=>$Type1_Pure{"Type"} );
10545 }
10546 }
10547 elsif($Type2_Pure{"Type"} eq "Enum")
10548 {
10549 my $Member_Value = $Type2_Pure{"Memb"}{$Member_Pos}{"value"};
10550 next if($Member_Value eq "");
10551 %{$SubProblems{"Added_Enum_Member"}{$Member_Name}}=(
10552 "Target"=>$Member_Name,
10553 "Type_Name"=>$Type2_Pure{"Name"},
10554 "Type_Type"=>$Type2_Pure{"Type"},
10555 "New_Value"=>$Member_Value );
10556 }
10557 }
10558 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040010559 %{$Cache{"mergeTypes"}{$Level}{$Type1_Id}{$Type2_Id}} = %SubProblems;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010560 pop(@RecurTypes);
10561 return %SubProblems;
10562}
10563
10564sub isUnnamed($) {
10565 return $_[0]=~/\Aunnamed\d+\Z/;
10566}
10567
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040010568sub get_ShortType($$)
10569{
10570 my ($TypeId, $LibVersion) = @_;
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040010571 my $TypeName = $TypeInfo{$LibVersion}{$TypeId}{"Name"};
10572 if(my $NameSpace = $TypeInfo{$LibVersion}{$TypeId}{"NameSpace"}) {
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040010573 $TypeName=~s/\A$NameSpace\:\://g;
10574 }
10575 return $TypeName;
10576}
10577
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040010578sub goToFirst($$$)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010579{
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040010580 my ($TypeId, $LibVersion, $Type_Type) = @_;
Andrey Ponomarenko16934472012-03-29 15:37:04 +040010581 return () if(not $TypeId);
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040010582 if(defined $Cache{"goToFirst"}{$TypeId}{$LibVersion}{$Type_Type}) {
10583 return %{$Cache{"goToFirst"}{$TypeId}{$LibVersion}{$Type_Type}};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010584 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040010585 return () if(not $TypeInfo{$LibVersion}{$TypeId});
10586 my %Type = %{$TypeInfo{$LibVersion}{$TypeId}};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010587 return () if(not $Type{"Type"});
10588 if($Type{"Type"} ne $Type_Type)
10589 {
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040010590 return () if(not defined $Type{"BaseType"});
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040010591 return () if(not $Type{"BaseType"}{"Tid"});
10592 %Type = goToFirst($Type{"BaseType"}{"Tid"}, $LibVersion, $Type_Type);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010593 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040010594 $Cache{"goToFirst"}{$TypeId}{$LibVersion}{$Type_Type} = \%Type;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010595 return %Type;
10596}
10597
10598my %TypeSpecAttributes = (
10599 "Const" => 1,
10600 "Volatile" => 1,
10601 "ConstVolatile" => 1,
10602 "Restrict" => 1,
10603 "Typedef" => 1
10604);
10605
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040010606sub get_PureType($$)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010607{
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040010608 my ($TypeId, $LibVersion) = @_;
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040010609 return () if(not $TypeId);
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040010610 if(defined $Cache{"get_PureType"}{$TypeId}{$LibVersion}) {
10611 return %{$Cache{"get_PureType"}{$TypeId}{$LibVersion}};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010612 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040010613 return () if(not $TypeInfo{$LibVersion}{$TypeId});
10614 my %Type = %{$TypeInfo{$LibVersion}{$TypeId}};
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040010615 return %Type if(not defined $Type{"BaseType"});
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040010616 return %Type if(not $Type{"BaseType"}{"Tid"});
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010617 if($TypeSpecAttributes{$Type{"Type"}}) {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040010618 %Type = get_PureType($Type{"BaseType"}{"Tid"}, $LibVersion);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010619 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040010620 $Cache{"get_PureType"}{$TypeId}{$LibVersion} = \%Type;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010621 return %Type;
10622}
10623
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040010624sub get_PLevel($$)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010625{
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040010626 my ($TypeId, $LibVersion) = @_;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010627 return 0 if(not $TypeId);
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040010628 if(defined $Cache{"get_PLevel"}{$TypeId}{$LibVersion}) {
10629 return $Cache{"get_PLevel"}{$TypeId}{$LibVersion};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010630 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040010631 return 0 if(not $TypeInfo{$LibVersion}{$TypeId});
10632 my %Type = %{$TypeInfo{$LibVersion}{$TypeId}};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010633 return 1 if($Type{"Type"}=~/FuncPtr|MethodPtr|FieldPtr/);
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040010634 return 0 if(not defined $Type{"BaseType"});
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040010635 return 0 if(not $Type{"BaseType"}{"Tid"});
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010636 my $PointerLevel = 0;
10637 if($Type{"Type"} =~/Pointer|Ref|FuncPtr|MethodPtr|FieldPtr/) {
10638 $PointerLevel += 1;
10639 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040010640 $PointerLevel += get_PLevel($Type{"BaseType"}{"Tid"}, $LibVersion);
10641 $Cache{"get_PLevel"}{$TypeId}{$LibVersion} = $PointerLevel;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010642 return $PointerLevel;
10643}
10644
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040010645sub get_BaseType($$)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010646{
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040010647 my ($TypeId, $LibVersion) = @_;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010648 return () if(not $TypeId);
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040010649 if(defined $Cache{"get_BaseType"}{$TypeId}{$LibVersion}) {
10650 return %{$Cache{"get_BaseType"}{$TypeId}{$LibVersion}};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010651 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040010652 return () if(not $TypeInfo{$LibVersion}{$TypeId});
10653 my %Type = %{$TypeInfo{$LibVersion}{$TypeId}};
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040010654 return %Type if(not defined $Type{"BaseType"});
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040010655 return %Type if(not $Type{"BaseType"}{"Tid"});
10656 %Type = get_BaseType($Type{"BaseType"}{"Tid"}, $LibVersion);
10657 $Cache{"get_BaseType"}{$TypeId}{$LibVersion} = \%Type;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010658 return %Type;
10659}
10660
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040010661sub get_BaseTypeQual($$)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010662{
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040010663 my ($TypeId, $LibVersion) = @_;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010664 return "" if(not $TypeId);
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040010665 return "" if(not $TypeInfo{$LibVersion}{$TypeId});
10666 my %Type = %{$TypeInfo{$LibVersion}{$TypeId}};
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040010667 return "" if(not defined $Type{"BaseType"});
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040010668 return "" if(not $Type{"BaseType"}{"Tid"});
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010669 my $Qual = "";
10670 if($Type{"Type"} eq "Pointer") {
10671 $Qual .= "*";
10672 }
10673 elsif($Type{"Type"} eq "Ref") {
10674 $Qual .= "&";
10675 }
10676 elsif($Type{"Type"} eq "ConstVolatile") {
10677 $Qual .= "const volatile";
10678 }
10679 elsif($Type{"Type"} eq "Const"
10680 or $Type{"Type"} eq "Volatile"
10681 or $Type{"Type"} eq "Restrict") {
10682 $Qual .= lc($Type{"Type"});
10683 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040010684 my $BQual = get_BaseTypeQual($Type{"BaseType"}{"Tid"}, $LibVersion);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010685 return $BQual.$Qual;
10686}
10687
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040010688sub get_OneStep_BaseType($$)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010689{
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040010690 my ($TypeId, $LibVersion) = @_;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010691 return () if(not $TypeId);
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040010692 return () if(not $TypeInfo{$LibVersion}{$TypeId});
10693 my %Type = %{$TypeInfo{$LibVersion}{$TypeId}};
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040010694 return %Type if(not defined $Type{"BaseType"});
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040010695 return %Type if(not $Type{"BaseType"}{"Tid"});
10696 return get_Type($Type{"BaseType"}{"Tid"}, $LibVersion);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010697}
10698
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040010699sub get_Type($$)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010700{
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040010701 my ($TypeId, $LibVersion) = @_;
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040010702 return () if(not $TypeId);
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040010703 return () if(not $TypeInfo{$LibVersion}{$TypeId});
10704 return %{$TypeInfo{$LibVersion}{$TypeId}};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010705}
10706
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +040010707sub isPrivateData($)
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040010708{ # non-public global data
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010709 my $Symbol = $_[0];
10710 return ($Symbol=~/\A(_ZGV|_ZTI|_ZTS|_ZTT|_ZTV|_ZTC|_ZThn|_ZTv0_n)/);
10711}
10712
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040010713sub isTemplateInstance($$)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010714{
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040010715 my ($Symbol, $LibVersion) = @_;
10716 if($CheckObjectsOnly)
10717 {
10718 if($Symbol!~/\A(_Z|\?)/) {
10719 return 0;
10720 }
10721 if(my $Signature = $tr_name{$Symbol})
10722 {
10723 if(index($Signature,">")==-1) {
10724 return 0;
10725 }
10726 if(my $ShortName = substr($Signature, 0, find_center($Signature, "(")))
10727 {
10728 if($ShortName=~/<.+>/) {
10729 return 1;
10730 }
10731 }
10732 }
10733 }
10734 else
10735 {
10736 if(my $ClassId = $CompleteSignature{$LibVersion}{$Symbol}{"Class"})
10737 {
10738 if(my $ClassName = $TypeInfo{$LibVersion}{$ClassId}{"Name"})
10739 {
10740 if(index($ClassName,"<")!=-1) {
10741 return 1;
10742 }
10743 }
10744 }
10745 if(my $ShortName = $CompleteSignature{$LibVersion}{$Symbol}{"ShortName"})
10746 {
10747 if($ShortName=~/<.+>/) {
10748 return 1;
10749 }
10750 }
10751 }
10752 return 0;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010753}
10754
10755sub isTemplateSpec($$)
10756{
10757 my ($Symbol, $LibVersion) = @_;
10758 if(my $ClassId = $CompleteSignature{$LibVersion}{$Symbol}{"Class"})
10759 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040010760 if($TypeInfo{$LibVersion}{$ClassId}{"Spec"})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010761 { # class specialization
10762 return 1;
10763 }
10764 elsif($CompleteSignature{$LibVersion}{$Symbol}{"Spec"})
10765 { # method specialization
10766 return 1;
10767 }
10768 }
10769 return 0;
10770}
10771
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040010772sub symbolFilter($$$$)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010773{ # some special cases when the symbol cannot be imported
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040010774 my ($Symbol, $LibVersion, $Type, $Level) = @_;
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +040010775 if(isPrivateData($Symbol))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010776 { # non-public global data
10777 return 0;
10778 }
10779 if($CheckObjectsOnly) {
10780 return 0 if($Symbol=~/\A(_init|_fini)\Z/);
10781 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040010782 if($CheckHeadersOnly and not checkDump($LibVersion, "2.7"))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010783 { # support for old ABI dumps in --headers-only mode
10784 foreach my $Pos (keys(%{$CompleteSignature{$LibVersion}{$Symbol}{"Param"}}))
10785 {
10786 if(my $Pid = $CompleteSignature{$LibVersion}{$Symbol}{"Param"}{$Pos}{"type"})
10787 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040010788 my $PType = $TypeInfo{$LibVersion}{$Pid}{"Type"};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010789 if(not $PType or $PType eq "Unknown") {
10790 return 0;
10791 }
10792 }
10793 }
10794 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +040010795 if($Type=~/Affected/)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010796 {
10797 my $ClassId = $CompleteSignature{$LibVersion}{$Symbol}{"Class"};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010798 if($SkipSymbols{$LibVersion}{$Symbol})
10799 { # user defined symbols to ignore
10800 return 0;
10801 }
10802 my $NameSpace = $CompleteSignature{$LibVersion}{$Symbol}{"NameSpace"};
10803 if(not $NameSpace and $ClassId)
10804 { # class methods have no "NameSpace" attribute
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040010805 $NameSpace = $TypeInfo{$LibVersion}{$ClassId}{"NameSpace"};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010806 }
10807 if($NameSpace)
10808 { # user defined namespaces to ignore
10809 if($SkipNameSpaces{$LibVersion}{$NameSpace}) {
10810 return 0;
10811 }
10812 foreach my $NS (keys(%{$SkipNameSpaces{$LibVersion}}))
10813 { # nested namespaces
10814 if($NameSpace=~/\A\Q$NS\E(\:\:|\Z)/) {
10815 return 0;
10816 }
10817 }
10818 }
10819 if(my $Header = $CompleteSignature{$LibVersion}{$Symbol}{"Header"})
10820 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040010821 if(my $Skip = skipHeader($Header, $LibVersion))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010822 { # --skip-headers or <skip_headers> (not <skip_including>)
10823 if($Skip==1) {
10824 return 0;
10825 }
10826 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010827 }
10828 if($SymbolsListPath and not $SymbolsList{$Symbol})
10829 { # user defined symbols
10830 return 0;
10831 }
10832 if($AppPath and not $SymbolsList_App{$Symbol})
10833 { # user defined symbols (in application)
10834 return 0;
10835 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +040010836 if(not selectSymbol($Symbol, $CompleteSignature{$LibVersion}{$Symbol}, $Level, $LibVersion))
10837 { # non-target symbols
10838 return 0;
10839 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040010840 if($Level eq "Binary")
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010841 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040010842 if($CheckObjectsOnly)
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040010843 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040010844 if(isTemplateInstance($Symbol, $LibVersion)) {
10845 return 0;
10846 }
10847 }
10848 else
10849 {
10850 if($CompleteSignature{$LibVersion}{$Symbol}{"InLine"}
10851 or (isTemplateInstance($Symbol, $LibVersion) and not isTemplateSpec($Symbol, $LibVersion)))
10852 {
10853 if($ClassId and $CompleteSignature{$LibVersion}{$Symbol}{"Virt"})
10854 { # inline virtual methods
10855 if($Type=~/InlineVirt/) {
10856 return 1;
10857 }
10858 my $Allocable = (not isCopyingClass($ClassId, $LibVersion));
10859 if(not $Allocable)
10860 { # check bases
10861 foreach my $DCId (get_sub_classes($ClassId, $LibVersion, 1))
10862 {
10863 if(not isCopyingClass($DCId, $LibVersion))
10864 { # exists a derived class without default c-tor
10865 $Allocable=1;
10866 last;
10867 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040010868 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010869 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040010870 if(not $Allocable) {
10871 return 0;
10872 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010873 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040010874 else
10875 { # inline non-virtual methods
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040010876 return 0;
10877 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010878 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010879 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010880 }
10881 }
10882 return 1;
10883}
10884
10885sub mergeImpl()
10886{
10887 my $DiffCmd = get_CmdPath("diff");
10888 if(not $DiffCmd) {
10889 exitStatus("Not_Found", "can't find \"diff\"");
10890 }
10891 foreach my $Interface (sort keys(%{$Symbol_Library{1}}))
10892 { # implementation changes
10893 next if($CompleteSignature{1}{$Interface}{"Private"});
10894 next if(not $CompleteSignature{1}{$Interface}{"Header"} and not $CheckObjectsOnly);
10895 next if(not $Symbol_Library{2}{$Interface} and not $Symbol_Library{2}{$SymVer{2}{$Interface}});
Andrey Ponomarenko85043792012-05-14 16:48:07 +040010896 if(not symbolFilter($Interface, 1, "Affected", "Binary")) {
10897 next;
10898 }
Andrey Ponomarenko16934472012-03-29 15:37:04 +040010899 my $Impl1 = canonifyImpl($Interface_Impl{1}{$Interface});
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010900 next if(not $Impl1);
Andrey Ponomarenko16934472012-03-29 15:37:04 +040010901 my $Impl2 = canonifyImpl($Interface_Impl{2}{$Interface});
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010902 next if(not $Impl2);
10903 if($Impl1 ne $Impl2)
10904 {
10905 writeFile("$TMP_DIR/impl1", $Impl1);
10906 writeFile("$TMP_DIR/impl2", $Impl2);
10907 my $Diff = `$DiffCmd -rNau $TMP_DIR/impl1 $TMP_DIR/impl2`;
10908 $Diff=~s/(---|\+\+\+).+\n//g;
10909 $Diff=~s/[ ]{3,}/ /g;
10910 $Diff=~s/\n\@\@/\n \n\@\@/g;
10911 unlink("$TMP_DIR/impl1", "$TMP_DIR/impl2");
10912 %{$ImplProblems{$Interface}}=(
10913 "Diff" => get_CodeView($Diff) );
10914 }
10915 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +040010916
10917 # clean memory
10918 %Interface_Impl = ();
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010919}
10920
Andrey Ponomarenko16934472012-03-29 15:37:04 +040010921sub canonifyImpl($)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010922{
10923 my $FuncBody= $_[0];
10924 return "" if(not $FuncBody);
10925 $FuncBody=~s/0x[a-f\d]+/0x?/g;# addr
10926 $FuncBody=~s/((\A|\n)[a-z]+[\t ]+)[a-f\d]+([^x]|\Z)/$1?$3/g;# call, jump
10927 $FuncBody=~s/# [a-f\d]+ /# ? /g;# call, jump
10928 $FuncBody=~s/%([a-z]+[a-f\d]*)/\%reg/g;# registers
10929 while($FuncBody=~s/\nnop[ \t]*(\n|\Z)/$1/g){};# empty op
10930 $FuncBody=~s/<.+?\.cpp.+?>/<name.cpp>/g;
10931 $FuncBody=~s/(\A|\n)[a-f\d]+ </$1? </g;# 5e74 <_ZN...
10932 $FuncBody=~s/\.L\d+/.L/g;
10933 $FuncBody=~s/#(-?)\d+/#$1?/g;# r3, [r3, #120]
10934 $FuncBody=~s/[\n]{2,}/\n/g;
10935 return $FuncBody;
10936}
10937
10938sub get_CodeView($)
10939{
10940 my $Code = $_[0];
10941 my $View = "";
10942 foreach my $Line (split(/\n/, $Code))
10943 {
10944 if($Line=~s/\A(\+|-)/$1 /g)
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040010945 { # bold line
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010946 $View .= "<tr><td><b>".htmlSpecChars($Line)."</b></td></tr>\n";
10947 }
10948 else {
10949 $View .= "<tr><td>".htmlSpecChars($Line)."</td></tr>\n";
10950 }
10951 }
10952 return "<table class='code_view'>$View</table>\n";
10953}
10954
10955sub getImplementations($$)
10956{
10957 my ($LibVersion, $Path) = @_;
10958 return if(not $LibVersion or not -e $Path);
10959 if($OSgroup eq "macos")
10960 {
10961 my $OtoolCmd = get_CmdPath("otool");
10962 if(not $OtoolCmd) {
10963 exitStatus("Not_Found", "can't find \"otool\"");
10964 }
10965 my $CurInterface = "";
10966 foreach my $Line (split(/\n/, `$OtoolCmd -tv $Path 2>$TMP_DIR/null`))
10967 {
10968 if($Line=~/\A\s*_(\w+)\s*:/i) {
10969 $CurInterface = $1;
10970 }
10971 elsif($Line=~/\A\s*[\da-z]+\s+(.+?)\Z/i) {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040010972 $Interface_Impl{$LibVersion}{$CurInterface} .= $1."\n";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010973 }
10974 }
10975 }
10976 else
10977 {
10978 my $ObjdumpCmd = get_CmdPath("objdump");
10979 if(not $ObjdumpCmd) {
10980 exitStatus("Not_Found", "can't find \"objdump\"");
10981 }
10982 my $CurInterface = "";
10983 foreach my $Line (split(/\n/, `$ObjdumpCmd -d $Path 2>$TMP_DIR/null`))
10984 {
10985 if($Line=~/\A[\da-z]+\s+<(\w+)>/i) {
10986 $CurInterface = $1;
10987 }
10988 else
10989 { # x86: 51fa:(\t)89 e5 (\t)mov %esp,%ebp
10990 # arm: 5020:(\t)e24cb004(\t)sub(\t)fp, ip, #4(\t); 0x4
10991 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 +040010992 $Interface_Impl{$LibVersion}{$CurInterface} .= $2."\n";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010993 }
10994 }
10995 }
10996 }
10997}
10998
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040010999sub detectAdded($)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011000{
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011001 my $Level = $_[0];
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011002 foreach my $Symbol (keys(%{$Symbol_Library{2}}))
11003 {
11004 if(link_symbol($Symbol, 1, "+Deps"))
11005 { # linker can find a new symbol
11006 # in the old-version library
11007 # So, it's not a new symbol
11008 next;
11009 }
11010 if(my $VSym = $SymVer{2}{$Symbol}
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040011011 and index($Symbol,"\@")==-1) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011012 next;
11013 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011014 $AddedInt{$Level}{$Symbol} = 1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011015 }
11016}
11017
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011018sub detectRemoved($)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011019{
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011020 my $Level = $_[0];
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011021 foreach my $Symbol (keys(%{$Symbol_Library{1}}))
11022 {
11023 if($CheckObjectsOnly) {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011024 $CheckedSymbols{"Binary"}{$Symbol} = 1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011025 }
11026 if(link_symbol($Symbol, 2, "+Deps"))
11027 { # linker can find an old symbol
11028 # in the new-version library
11029 next;
11030 }
11031 if(my $VSym = $SymVer{1}{$Symbol}
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040011032 and index($Symbol,"\@")==-1) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011033 next;
11034 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011035 $RemovedInt{$Level}{$Symbol} = 1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011036 }
11037}
11038
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011039sub mergeLibs($)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011040{
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011041 my $Level = $_[0];
11042 foreach my $Symbol (sort keys(%{$AddedInt{$Level}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011043 { # checking added symbols
11044 next if($CompleteSignature{2}{$Symbol}{"Private"});
11045 next if(not $CompleteSignature{2}{$Symbol}{"Header"} and not $CheckObjectsOnly);
Andrey Ponomarenko85043792012-05-14 16:48:07 +040011046 next if(not symbolFilter($Symbol, 2, "Affected", $Level));
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011047 %{$CompatProblems{$Level}{$Symbol}{"Added_Symbol"}{""}}=();
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011048 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011049 foreach my $Symbol (sort keys(%{$RemovedInt{$Level}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011050 { # checking removed symbols
11051 next if($CompleteSignature{1}{$Symbol}{"Private"});
11052 next if(not $CompleteSignature{1}{$Symbol}{"Header"} and not $CheckObjectsOnly);
11053 if($Symbol=~/\A_ZTV/)
11054 { # skip v-tables for templates, that should not be imported by applications
11055 next if($tr_name{$Symbol}=~/</);
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040011056 if(my $CName = $VTableClass{$Symbol})
11057 {
11058 if(not keys(%{$ClassMethods{$Level}{1}{$CName}}))
11059 { # vtables for "private" classes
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040011060 # use case: vtable for QDragManager (Qt 4.5.3 to 4.6.0) became HIDDEN symbol
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040011061 next;
11062 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011063 }
11064 }
11065 else {
Andrey Ponomarenko85043792012-05-14 16:48:07 +040011066 next if(not symbolFilter($Symbol, 1, "Affected", $Level));
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011067 }
11068 if($CompleteSignature{1}{$Symbol}{"PureVirt"})
11069 { # symbols for pure virtual methods cannot be called by clients
11070 next;
11071 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011072 %{$CompatProblems{$Level}{$Symbol}{"Removed_Symbol"}{""}}=();
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011073 }
11074}
11075
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040011076sub checkDump($$)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011077{
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040011078 my ($LibVersion, $V) = @_;
11079 if(defined $Cache{"checkDump"}{$LibVersion}{$V}) {
11080 return $Cache{"checkDump"}{$LibVersion}{$V};
11081 }
11082 return ($Cache{"checkDump"}{$LibVersion}{$V} = (not $UsedDump{$LibVersion}{"V"} or cmpVersions($UsedDump{$LibVersion}{"V"}, $V)>=0));
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011083}
11084
11085sub detectAdded_H($)
11086{
11087 my $Level = $_[0];
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011088 foreach my $Symbol (sort keys(%{$CompleteSignature{2}}))
11089 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011090 if($Level eq "Source")
11091 { # remove symbol version
11092 my ($SN, $SS, $SV) = separate_symbol($Symbol);
11093 $Symbol=$SN;
11094 }
Andrey Ponomarenko16934472012-03-29 15:37:04 +040011095 if(not $CompleteSignature{2}{$Symbol}{"Header"}
11096 or not $CompleteSignature{2}{$Symbol}{"MnglName"}) {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011097 next;
11098 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040011099 if($ExtendedSymbols{$Symbol}) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011100 next;
11101 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011102 if(not defined $CompleteSignature{1}{$Symbol}
11103 or not $CompleteSignature{1}{$Symbol}{"MnglName"})
11104 {
Andrey Ponomarenko16934472012-03-29 15:37:04 +040011105 if($UsedDump{2}{"SrcBin"})
11106 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040011107 if($UsedDump{1}{"BinOnly"} or not checkDump(1, "2.11"))
Andrey Ponomarenko16934472012-03-29 15:37:04 +040011108 { # support for old and different (!) ABI dumps
11109 if(not $CompleteSignature{2}{$Symbol}{"Virt"}
11110 and not $CompleteSignature{2}{$Symbol}{"PureVirt"})
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011111 {
Andrey Ponomarenko16934472012-03-29 15:37:04 +040011112 if($CheckHeadersOnly)
Andrey Ponomarenko85043792012-05-14 16:48:07 +040011113 {
11114 if(my $Lang = $CompleteSignature{2}{$Symbol}{"Lang"})
11115 {
11116 if($Lang eq "C")
11117 { # support for old ABI dumps: missed extern "C" functions
11118 next;
11119 }
11120 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011121 }
Andrey Ponomarenko16934472012-03-29 15:37:04 +040011122 else
11123 {
11124 if(not link_symbol($Symbol, 2, "-Deps"))
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040011125 { # skip added inline symbols and const global data
Andrey Ponomarenko16934472012-03-29 15:37:04 +040011126 next;
11127 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011128 }
11129 }
11130 }
11131 }
11132 $AddedInt{$Level}{$Symbol} = 1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011133 }
11134 }
11135}
11136
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011137sub detectRemoved_H($)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011138{
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011139 my $Level = $_[0];
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011140 foreach my $Symbol (sort keys(%{$CompleteSignature{1}}))
11141 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011142 if($Level eq "Source")
11143 { # remove symbol version
11144 my ($SN, $SS, $SV) = separate_symbol($Symbol);
11145 $Symbol=$SN;
11146 }
Andrey Ponomarenko16934472012-03-29 15:37:04 +040011147 if(not $CompleteSignature{1}{$Symbol}{"Header"}
11148 or not $CompleteSignature{1}{$Symbol}{"MnglName"}) {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011149 next;
11150 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040011151 if($ExtendedSymbols{$Symbol}) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011152 next;
11153 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011154 if(not defined $CompleteSignature{2}{$Symbol}
11155 or not $CompleteSignature{2}{$Symbol}{"MnglName"})
Andrey Ponomarenko85043792012-05-14 16:48:07 +040011156 {
Andrey Ponomarenko16934472012-03-29 15:37:04 +040011157 if($UsedDump{1}{"SrcBin"})
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011158 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040011159 if($UsedDump{2}{"BinOnly"} or not checkDump(2, "2.11"))
Andrey Ponomarenko85043792012-05-14 16:48:07 +040011160 { # support for old and different (!) ABI dumps
Andrey Ponomarenko16934472012-03-29 15:37:04 +040011161 if(not $CompleteSignature{1}{$Symbol}{"Virt"}
11162 and not $CompleteSignature{1}{$Symbol}{"PureVirt"})
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011163 {
Andrey Ponomarenko16934472012-03-29 15:37:04 +040011164 if($CheckHeadersOnly)
11165 { # skip all removed symbols
Andrey Ponomarenko85043792012-05-14 16:48:07 +040011166 if(my $Lang = $CompleteSignature{1}{$Symbol}{"Lang"})
11167 {
11168 if($Lang eq "C")
11169 { # support for old ABI dumps: missed extern "C" functions
11170 next;
11171 }
11172 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011173 }
Andrey Ponomarenko16934472012-03-29 15:37:04 +040011174 else
11175 {
11176 if(not link_symbol($Symbol, 1, "-Deps"))
11177 { # skip removed inline symbols
11178 next;
11179 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011180 }
11181 }
11182 }
11183 }
11184 $RemovedInt{$Level}{$Symbol} = 1;
11185 if($Level eq "Source")
11186 { # search for a source-compatible equivalent
11187 setAlternative($Symbol, $Level);
11188 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011189 }
11190 }
11191}
11192
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011193sub mergeHeaders($)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011194{
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011195 my $Level = $_[0];
11196 foreach my $Symbol (sort keys(%{$AddedInt{$Level}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011197 { # checking added symbols
11198 next if($CompleteSignature{2}{$Symbol}{"PureVirt"});
Andrey Ponomarenko85043792012-05-14 16:48:07 +040011199 if($Level eq "Binary")
11200 {
11201 if($CompleteSignature{2}{$Symbol}{"InLine"})
11202 {
11203 if(not $CompleteSignature{2}{$Symbol}{"Virt"})
11204 { # skip inline non-virtual functions
11205 next;
11206 }
11207 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011208 }
11209 else
11210 { # Source
11211 if($SourceAlternative_B{$Symbol}) {
11212 next;
11213 }
11214 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011215 next if($CompleteSignature{2}{$Symbol}{"Private"});
Andrey Ponomarenko85043792012-05-14 16:48:07 +040011216 next if(not symbolFilter($Symbol, 2, "Affected", $Level));
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011217 %{$CompatProblems{$Level}{$Symbol}{"Added_Symbol"}{""}}=();
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011218 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011219 foreach my $Symbol (sort keys(%{$RemovedInt{$Level}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011220 { # checking removed symbols
11221 next if($CompleteSignature{1}{$Symbol}{"PureVirt"});
Andrey Ponomarenko85043792012-05-14 16:48:07 +040011222 if($Level eq "Binary")
11223 {
11224 if($CompleteSignature{1}{$Symbol}{"InLine"})
11225 {
11226 if(not $CompleteSignature{1}{$Symbol}{"Virt"})
11227 { # skip inline non-virtual functions
11228 next;
11229 }
11230 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011231 }
11232 else
11233 { # Source
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040011234 if(my $Alt = $SourceAlternative{$Symbol})
11235 {
11236 if(defined $CompleteSignature{1}{$Alt}
11237 and $CompleteSignature{1}{$Symbol}{"Const"})
11238 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040011239 my $Cid = $CompleteSignature{1}{$Symbol}{"Class"};
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040011240 %{$CompatProblems{$Level}{$Symbol}{"Removed_Const_Overload"}{$tr_name{$Symbol}}}=(
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040011241 "Type_Name"=>$TypeInfo{1}{$Cid}{"Name"},
Andrey Ponomarenko85043792012-05-14 16:48:07 +040011242 "Type_Type"=>"Class",
11243 "Target"=>get_Signature($Alt, 1) );
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040011244 }
11245 else
11246 { # do NOT show removed symbol
11247 next;
11248 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011249 }
11250 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011251 next if($CompleteSignature{1}{$Symbol}{"Private"});
Andrey Ponomarenko85043792012-05-14 16:48:07 +040011252 next if(not symbolFilter($Symbol, 1, "Affected", $Level));
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011253 %{$CompatProblems{$Level}{$Symbol}{"Removed_Symbol"}{""}}=();
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011254 }
11255}
11256
11257sub addParamNames($)
11258{
11259 my $LibraryVersion = $_[0];
11260 return if(not keys(%AddIntParams));
11261 my $SecondVersion = $LibraryVersion==1?2:1;
11262 foreach my $Interface (sort keys(%{$CompleteSignature{$LibraryVersion}}))
11263 {
11264 next if(not keys(%{$AddIntParams{$Interface}}));
11265 foreach my $ParamPos (sort {int($a)<=>int($b)} keys(%{$CompleteSignature{$LibraryVersion}{$Interface}{"Param"}}))
Andrey Ponomarenko85043792012-05-14 16:48:07 +040011266 { # add absent parameter names
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011267 my $ParamName = $CompleteSignature{$LibraryVersion}{$Interface}{"Param"}{$ParamPos}{"name"};
11268 if($ParamName=~/\Ap\d+\Z/ and my $NewParamName = $AddIntParams{$Interface}{$ParamPos})
Andrey Ponomarenko85043792012-05-14 16:48:07 +040011269 { # names from the external file
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011270 if(defined $CompleteSignature{$SecondVersion}{$Interface}
11271 and defined $CompleteSignature{$SecondVersion}{$Interface}{"Param"}{$ParamPos})
11272 {
11273 if($CompleteSignature{$SecondVersion}{$Interface}{"Param"}{$ParamPos}{"name"}=~/\Ap\d+\Z/) {
11274 $CompleteSignature{$LibraryVersion}{$Interface}{"Param"}{$ParamPos}{"name"} = $NewParamName;
11275 }
11276 }
11277 else {
11278 $CompleteSignature{$LibraryVersion}{$Interface}{"Param"}{$ParamPos}{"name"} = $NewParamName;
11279 }
11280 }
11281 }
11282 }
11283}
11284
11285sub detectChangedTypedefs()
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +040011286{ # detect changed typedefs to show
11287 # correct function signatures
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011288 foreach my $Typedef (keys(%{$Typedef_BaseName{1}}))
11289 {
11290 next if(not $Typedef);
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +040011291 my $BName1 = $Typedef_BaseName{1}{$Typedef};
11292 if(not $BName1 or isAnon($BName1)) {
11293 next;
11294 }
11295 my $BName2 = $Typedef_BaseName{2}{$Typedef};
11296 if(not $BName2 or isAnon($BName2)) {
11297 next;
11298 }
11299 if($BName1 ne $BName2) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011300 $ChangedTypedef{$Typedef} = 1;
11301 }
11302 }
11303}
11304
11305sub get_symbol_suffix($$)
11306{
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011307 my ($Symbol, $Full) = @_;
11308 my ($SN, $SO, $SV) = separate_symbol($Symbol);
11309 $Symbol=$SN;# remove version
11310 my $Signature = $tr_name{$Symbol};
Andrey Ponomarenko16934472012-03-29 15:37:04 +040011311 my $Suffix = substr($Signature, find_center($Signature, "("));
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011312 if(not $Full) {
11313 $Suffix=~s/(\))\s*(const volatile|volatile const|const|volatile)\Z/$1/g;
11314 }
11315 return $Suffix;
11316}
11317
11318sub get_symbol_prefix($$)
11319{
11320 my ($Symbol, $LibVersion) = @_;
11321 my $ShortName = $CompleteSignature{$LibVersion}{$Symbol}{"ShortName"};
11322 if(my $ClassId = $CompleteSignature{$LibVersion}{$Symbol}{"Class"})
11323 { # methods
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040011324 $ShortName = $TypeInfo{$LibVersion}{$ClassId}{"Name"}."::".$ShortName;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011325 }
11326 return $ShortName;
11327}
11328
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011329sub setAlternative($)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011330{
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011331 my $Symbol = $_[0];
11332 my $PSymbol = $Symbol;
11333 if(not defined $CompleteSignature{2}{$PSymbol}
11334 or (not $CompleteSignature{2}{$PSymbol}{"MnglName"}
11335 and not $CompleteSignature{2}{$PSymbol}{"ShortName"}))
11336 { # search for a pair
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040011337 if(my $ShortName = $CompleteSignature{1}{$PSymbol}{"ShortName"})
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011338 {
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040011339 if($CompleteSignature{1}{$PSymbol}{"Data"})
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011340 {
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040011341 if($PSymbol=~s/L(\d+$ShortName(E)\Z)/$1/
11342 or $PSymbol=~s/(\d+$ShortName(E)\Z)/L$1/)
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011343 {
11344 if(defined $CompleteSignature{2}{$PSymbol}
11345 and $CompleteSignature{2}{$PSymbol}{"MnglName"})
11346 {
11347 $SourceAlternative{$Symbol} = $PSymbol;
11348 $SourceAlternative_B{$PSymbol} = $Symbol;
11349 if(not defined $CompleteSignature{1}{$PSymbol}
11350 or not $CompleteSignature{1}{$PSymbol}{"MnglName"}) {
11351 $SourceReplacement{$Symbol} = $PSymbol;
11352 }
11353 }
11354 }
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040011355 }
11356 else
11357 {
11358 foreach my $Sp ("KV", "VK", "K", "V")
11359 {
11360 if($PSymbol=~s/\A_ZN$Sp/_ZN/
11361 or $PSymbol=~s/\A_ZN/_ZN$Sp/)
11362 {
11363 if(defined $CompleteSignature{2}{$PSymbol}
11364 and $CompleteSignature{2}{$PSymbol}{"MnglName"})
11365 {
11366 $SourceAlternative{$Symbol} = $PSymbol;
11367 $SourceAlternative_B{$PSymbol} = $Symbol;
11368 if(not defined $CompleteSignature{1}{$PSymbol}
11369 or not $CompleteSignature{1}{$PSymbol}{"MnglName"}) {
11370 $SourceReplacement{$Symbol} = $PSymbol;
11371 }
11372 }
11373 }
11374 $PSymbol = $Symbol;
11375 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011376 }
11377 }
11378 }
11379 return "";
11380}
11381
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040011382sub getSymKind($$)
11383{
11384 my ($Symbol, $LibVersion) = @_;
11385 if($CompleteSignature{$LibVersion}{$Symbol}{"Data"})
11386 {
11387 return "Global_Data";
11388 }
11389 elsif($CompleteSignature{$LibVersion}{$Symbol}{"Class"})
11390 {
11391 return "Method";
11392 }
11393 return "Function";
11394}
11395
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011396sub mergeSignatures($)
11397{
11398 my $Level = $_[0];
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011399 my %SubProblems = ();
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011400
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011401 mergeBases($Level);
11402
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011403 my %AddedOverloads = ();
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011404 foreach my $Symbol (sort keys(%{$AddedInt{$Level}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011405 { # check all added exported symbols
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011406 if(not $CompleteSignature{2}{$Symbol}{"Header"}) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011407 next;
11408 }
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040011409 if(defined $CompleteSignature{1}{$Symbol}
11410 and $CompleteSignature{1}{$Symbol}{"Header"})
11411 { # double-check added symbol
11412 next;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011413 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +040011414 if(not symbolFilter($Symbol, 2, "Affected", $Level)) {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011415 next;
11416 }
11417 if($Symbol=~/\A(_Z|\?)/)
11418 { # C++
11419 $AddedOverloads{get_symbol_prefix($Symbol, 2)}{get_symbol_suffix($Symbol, 1)} = $Symbol;
11420 }
11421 if(my $OverriddenMethod = $CompleteSignature{2}{$Symbol}{"Override"})
11422 { # register virtual overridings
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040011423 my $Cid = $CompleteSignature{2}{$Symbol}{"Class"};
11424 my $AffectedClass_Name = $TypeInfo{2}{$Cid}{"Name"};
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040011425 if(defined $CompleteSignature{1}{$OverriddenMethod} and $CompleteSignature{1}{$OverriddenMethod}{"Virt"}
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011426 and not $CompleteSignature{1}{$OverriddenMethod}{"Private"})
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040011427 {
11428 if($TName_Tid{1}{$AffectedClass_Name})
11429 { # class should exist in previous version
11430 if(not isCopyingClass($TName_Tid{1}{$AffectedClass_Name}, 1))
11431 { # old v-table is NOT copied by old applications
11432 %{$CompatProblems{$Level}{$OverriddenMethod}{"Overridden_Virtual_Method"}{$tr_name{$Symbol}}}=(
11433 "Type_Name"=>$AffectedClass_Name,
11434 "Type_Type"=>"Class",
11435 "Target"=>get_Signature($Symbol, 2),
11436 "Old_Value"=>get_Signature($OverriddenMethod, 2),
11437 "New_Value"=>get_Signature($Symbol, 2) );
11438 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011439 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011440 }
11441 }
11442 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011443 foreach my $Symbol (sort keys(%{$RemovedInt{$Level}}))
11444 { # check all removed exported symbols
11445 if(not $CompleteSignature{1}{$Symbol}{"Header"}) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011446 next;
11447 }
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040011448 if(defined $CompleteSignature{2}{$Symbol}
11449 and $CompleteSignature{2}{$Symbol}{"Header"})
11450 { # double-check removed symbol
11451 next;
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011452 }
11453 if($CompleteSignature{1}{$Symbol}{"Private"})
11454 { # skip private methods
11455 next;
11456 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +040011457 if(not symbolFilter($Symbol, 1, "Affected", $Level)) {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011458 next;
11459 }
11460 $CheckedSymbols{$Level}{$Symbol} = 1;
11461 if(my $OverriddenMethod = $CompleteSignature{1}{$Symbol}{"Override"})
11462 { # register virtual overridings
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040011463 my $Cid = $CompleteSignature{1}{$Symbol}{"Class"};
11464 my $AffectedClass_Name = $TypeInfo{1}{$Cid}{"Name"};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011465 if(defined $CompleteSignature{2}{$OverriddenMethod}
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040011466 and $CompleteSignature{2}{$OverriddenMethod}{"Virt"})
11467 {
11468 if($TName_Tid{2}{$AffectedClass_Name})
11469 { # class should exist in newer version
11470 if(not isCopyingClass($CompleteSignature{1}{$Symbol}{"Class"}, 1))
11471 { # old v-table is NOT copied by old applications
11472 %{$CompatProblems{$Level}{$Symbol}{"Overridden_Virtual_Method_B"}{$tr_name{$OverriddenMethod}}}=(
11473 "Type_Name"=>$AffectedClass_Name,
11474 "Type_Type"=>"Class",
11475 "Target"=>get_Signature($OverriddenMethod, 1),
11476 "Old_Value"=>get_Signature($Symbol, 1),
11477 "New_Value"=>get_Signature($OverriddenMethod, 1) );
11478 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011479 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011480 }
11481 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011482 if($Level eq "Binary"
11483 and $OSgroup eq "windows")
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011484 { # register the reason of symbol name change
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040011485 if(my $NewSym = $mangled_name{2}{$tr_name{$Symbol}})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011486 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040011487 if($AddedInt{$Level}{$NewSym})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011488 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040011489 if($CompleteSignature{1}{$Symbol}{"Static"} ne $CompleteSignature{2}{$NewSym}{"Static"})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011490 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040011491 if($CompleteSignature{2}{$NewSym}{"Static"})
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011492 {
11493 %{$CompatProblems{$Level}{$Symbol}{"Symbol_Became_Static"}{$tr_name{$Symbol}}}=(
11494 "Target"=>$tr_name{$Symbol},
11495 "Old_Value"=>$Symbol,
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040011496 "New_Value"=>$NewSym );
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011497 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011498 else
11499 {
11500 %{$CompatProblems{$Level}{$Symbol}{"Symbol_Became_NonStatic"}{$tr_name{$Symbol}}}=(
11501 "Target"=>$tr_name{$Symbol},
11502 "Old_Value"=>$Symbol,
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040011503 "New_Value"=>$NewSym );
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011504 }
11505 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040011506 if($CompleteSignature{1}{$Symbol}{"Virt"} ne $CompleteSignature{2}{$NewSym}{"Virt"})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011507 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040011508 if($CompleteSignature{2}{$NewSym}{"Virt"})
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011509 {
11510 %{$CompatProblems{$Level}{$Symbol}{"Symbol_Became_Virtual"}{$tr_name{$Symbol}}}=(
11511 "Target"=>$tr_name{$Symbol},
11512 "Old_Value"=>$Symbol,
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040011513 "New_Value"=>$NewSym );
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011514 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011515 else
11516 {
11517 %{$CompatProblems{$Level}{$Symbol}{"Symbol_Became_NonVirtual"}{$tr_name{$Symbol}}}=(
11518 "Target"=>$tr_name{$Symbol},
11519 "Old_Value"=>$Symbol,
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040011520 "New_Value"=>$NewSym );
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011521 }
11522 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040011523 my $RTId1 = $CompleteSignature{1}{$Symbol}{"Return"};
11524 my $RTId2 = $CompleteSignature{2}{$NewSym}{"Return"};
11525 my $RTName1 = $TypeInfo{1}{$RTId1}{"Name"};
11526 my $RTName2 = $TypeInfo{2}{$RTId2}{"Name"};
11527 if($RTName1 ne $RTName2)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011528 {
11529 my $ProblemType = "Symbol_Changed_Return";
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011530 if($CompleteSignature{1}{$Symbol}{"Data"}) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011531 $ProblemType = "Global_Data_Symbol_Changed_Type";
11532 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011533 %{$CompatProblems{$Level}{$Symbol}{$ProblemType}{$tr_name{$Symbol}}}=(
11534 "Target"=>$tr_name{$Symbol},
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040011535 "Old_Type"=>$RTName1,
11536 "New_Type"=>$RTName2,
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011537 "Old_Value"=>$Symbol,
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040011538 "New_Value"=>$NewSym );
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011539 }
11540 }
11541 }
11542 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011543 if($Symbol=~/\A(_Z|\?)/)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011544 { # C++
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011545 my $Prefix = get_symbol_prefix($Symbol, 1);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011546 if(my @Overloads = sort keys(%{$AddedOverloads{$Prefix}})
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011547 and not $AddedOverloads{$Prefix}{get_symbol_suffix($Symbol, 1)})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011548 { # changed signature: params, "const"-qualifier
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040011549 my $NewSym = $AddedOverloads{$Prefix}{$Overloads[0]};
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011550 if($CompleteSignature{1}{$Symbol}{"Constructor"})
11551 {
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +040011552 if($Symbol=~/(C1E|C2E)/)
11553 {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011554 my $CtorType = $1;
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040011555 $NewSym=~s/(C1E|C2E)/$CtorType/g;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011556 }
11557 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011558 elsif($CompleteSignature{1}{$Symbol}{"Destructor"})
11559 {
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +040011560 if($Symbol=~/(D0E|D1E|D2E)/)
11561 {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011562 my $DtorType = $1;
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040011563 $NewSym=~s/(D0E|D1E|D2E)/$DtorType/g;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011564 }
11565 }
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040011566 my $NS1 = $CompleteSignature{1}{$Symbol}{"NameSpace"};
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040011567 my $NS2 = $CompleteSignature{2}{$NewSym}{"NameSpace"};
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040011568 if((not $NS1 and not $NS2) or ($NS1 and $NS2 and $NS1 eq $NS2))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011569 { # from the same class and namespace
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011570 if($CompleteSignature{1}{$Symbol}{"Const"}
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040011571 and not $CompleteSignature{2}{$NewSym}{"Const"})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011572 { # "const" to non-"const"
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040011573 %{$CompatProblems{$Level}{$Symbol}{"Method_Became_NonConst"}{$tr_name{$Symbol}}}=(
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040011574 "Type_Name"=>$TypeInfo{1}{$CompleteSignature{1}{$Symbol}{"Class"}}{"Name"},
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011575 "Target"=>$tr_name{$Symbol},
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040011576 "New_Signature"=>get_Signature($NewSym, 2),
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011577 "Old_Value"=>$Symbol,
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040011578 "New_Value"=>$NewSym );
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011579 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011580 elsif(not $CompleteSignature{1}{$Symbol}{"Const"}
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040011581 and $CompleteSignature{2}{$NewSym}{"Const"})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011582 { # non-"const" to "const"
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040011583 %{$CompatProblems{$Level}{$Symbol}{"Method_Became_Const"}{$tr_name{$Symbol}}}=(
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011584 "Target"=>$tr_name{$Symbol},
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040011585 "New_Signature"=>get_Signature($NewSym, 2),
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011586 "Old_Value"=>$Symbol,
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040011587 "New_Value"=>$NewSym );
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011588 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011589 if($CompleteSignature{1}{$Symbol}{"Volatile"}
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040011590 and not $CompleteSignature{2}{$NewSym}{"Volatile"})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011591 { # "volatile" to non-"volatile"
11592
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040011593 %{$CompatProblems{$Level}{$Symbol}{"Method_Became_NonVolatile"}{$tr_name{$Symbol}}}=(
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011594 "Target"=>$tr_name{$Symbol},
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040011595 "New_Signature"=>get_Signature($NewSym, 2),
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011596 "Old_Value"=>$Symbol,
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040011597 "New_Value"=>$NewSym );
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011598 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011599 elsif(not $CompleteSignature{1}{$Symbol}{"Volatile"}
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040011600 and $CompleteSignature{2}{$NewSym}{"Volatile"})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011601 { # non-"volatile" to "volatile"
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040011602 %{$CompatProblems{$Level}{$Symbol}{"Method_Became_Volatile"}{$tr_name{$Symbol}}}=(
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011603 "Target"=>$tr_name{$Symbol},
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040011604 "New_Signature"=>get_Signature($NewSym, 2),
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011605 "Old_Value"=>$Symbol,
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040011606 "New_Value"=>$NewSym );
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011607 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040011608 if(get_symbol_suffix($Symbol, 0) ne get_symbol_suffix($NewSym, 0))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011609 { # params list
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011610 %{$CompatProblems{$Level}{$Symbol}{"Symbol_Changed_Parameters"}{$tr_name{$Symbol}}}=(
11611 "Target"=>$tr_name{$Symbol},
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040011612 "New_Signature"=>get_Signature($NewSym, 2),
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011613 "Old_Value"=>$Symbol,
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040011614 "New_Value"=>$NewSym );
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011615 }
11616 }
11617 }
11618 }
11619 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011620 foreach my $Symbol (sort keys(%{$CompleteSignature{1}}))
11621 { # checking symbols
11622 my ($SN, $SS, $SV) = separate_symbol($Symbol);
11623 if($Level eq "Source")
11624 { # remove symbol version
11625 $Symbol=$SN;
11626 }
11627 else
11628 { # Binary
11629 if(not $SV)
11630 { # symbol without version
11631 if(my $VSym = $SymVer{1}{$Symbol})
11632 { # the symbol is linked with versioned symbol
11633 if($CompleteSignature{2}{$VSym}{"MnglName"})
11634 { # show report for symbol@ver only
11635 next;
11636 }
11637 elsif(not link_symbol($VSym, 2, "-Deps"))
11638 { # changed version: sym@v1 to sym@v2
11639 # do NOT show report for symbol
11640 next;
11641 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011642 }
11643 }
11644 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011645 my $PSymbol = $Symbol;
11646 if($Level eq "Source"
11647 and my $S = $SourceReplacement{$Symbol})
11648 { # take a source-compatible replacement function
11649 $PSymbol = $S;
11650 }
11651 if($CompleteSignature{1}{$Symbol}{"Private"})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011652 { # private symbols
11653 next;
11654 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011655 if(not defined $CompleteSignature{1}{$Symbol}
11656 or not defined $CompleteSignature{2}{$PSymbol})
11657 { # no info
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011658 next;
11659 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011660 if(not $CompleteSignature{1}{$Symbol}{"MnglName"}
11661 or not $CompleteSignature{2}{$PSymbol}{"MnglName"})
11662 { # no mangled name
11663 next;
11664 }
11665 if(not $CompleteSignature{1}{$Symbol}{"Header"}
11666 or not $CompleteSignature{2}{$PSymbol}{"Header"})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011667 { # without a header
11668 next;
11669 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040011670 if(checkDump(1, "2.13") and checkDump(2, "2.13"))
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040011671 {
11672 if($CompleteSignature{1}{$Symbol}{"Data"}
11673 and $CompleteSignature{2}{$PSymbol}{"Data"})
11674 {
11675 my $Value1 = $CompleteSignature{1}{$Symbol}{"Value"};
11676 my $Value2 = $CompleteSignature{2}{$PSymbol}{"Value"};
11677 if(defined $Value1)
11678 {
11679 $Value1 = showVal($Value1, $CompleteSignature{1}{$Symbol}{"Return"}, 1);
11680 if(defined $Value2)
11681 {
11682 $Value2 = showVal($Value2, $CompleteSignature{2}{$PSymbol}{"Return"}, 2);
11683 if($Value1 ne $Value2)
11684 {
11685 %{$CompatProblems{$Level}{$Symbol}{"Global_Data_Value_Changed"}{""}}=(
11686 "Old_Value"=>$Value1,
11687 "New_Value"=>$Value2,
11688 "Target"=>get_Signature($Symbol, 1) );
11689 }
11690 }
11691 }
11692 }
11693 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +040011694
11695 if(not $CompleteSignature{1}{$Symbol}{"PureVirt"}
11696 and $CompleteSignature{2}{$PSymbol}{"PureVirt"})
11697 { # became pure
11698 next;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011699 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +040011700 if($CompleteSignature{1}{$Symbol}{"PureVirt"}
11701 and not $CompleteSignature{2}{$PSymbol}{"PureVirt"})
11702 { # became non-pure
11703 next;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011704 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +040011705
11706 if(not symbolFilter($Symbol, 1, "Affected + InlineVirt", $Level))
11707 { # exported, target, inline virtual and pure virtual
11708 next;
11709 }
11710 if(not symbolFilter($PSymbol, 2, "Affected + InlineVirt", $Level))
11711 { # exported, target, inline virtual and pure virtual
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011712 next;
11713 }
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040011714
11715 if($CompleteSignature{2}{$PSymbol}{"Private"})
11716 {
11717 %{$CompatProblems{$Level}{$Symbol}{getSymKind($Symbol, 1)."_Became_Private"}{""}}=(
11718 "Target"=>get_Signature_M($PSymbol, 2) );
11719 }
11720 elsif(not $CompleteSignature{1}{$Symbol}{"Protected"}
11721 and $CompleteSignature{2}{$PSymbol}{"Protected"})
11722 {
11723 %{$CompatProblems{$Level}{$Symbol}{getSymKind($Symbol, 1)."_Became_Protected"}{""}}=(
11724 "Target"=>get_Signature_M($PSymbol, 2) );
11725 }
11726 elsif($CompleteSignature{1}{$Symbol}{"Protected"}
11727 and not $CompleteSignature{2}{$PSymbol}{"Protected"})
11728 {
11729 %{$CompatProblems{$Level}{$Symbol}{getSymKind($Symbol, 1)."_Became_Public"}{""}}=(
11730 "Target"=>get_Signature_M($PSymbol, 2) );
11731 }
11732
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011733 # checking virtual table
Andrey Ponomarenko16934472012-03-29 15:37:04 +040011734 mergeVirtualTables($Symbol, $Level);
11735
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011736 if($COMPILE_ERRORS)
11737 { # if some errors occurred at the compiling stage
11738 # then some false positives can be skipped here
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011739 if(not $CompleteSignature{1}{$Symbol}{"Data"} and $CompleteSignature{2}{$PSymbol}{"Data"}
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040011740 and not $GlobalDataObject{2}{$Symbol})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011741 { # missed information about parameters in newer version
11742 next;
11743 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040011744 if($CompleteSignature{1}{$Symbol}{"Data"} and not $GlobalDataObject{1}{$Symbol}
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011745 and not $CompleteSignature{2}{$PSymbol}{"Data"})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011746 {# missed information about parameters in older version
11747 next;
11748 }
11749 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011750 my ($MnglName, $VersionSpec, $SymbolVersion) = separate_symbol($Symbol);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011751 # checking attributes
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011752 if($CompleteSignature{2}{$PSymbol}{"Static"}
11753 and not $CompleteSignature{1}{$Symbol}{"Static"} and $Symbol=~/\A(_Z|\?)/) {
11754 %{$CompatProblems{$Level}{$Symbol}{"Method_Became_Static"}{""}}=(
11755 "Target"=>get_Signature($Symbol, 1)
11756 );
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011757 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011758 elsif(not $CompleteSignature{2}{$PSymbol}{"Static"}
11759 and $CompleteSignature{1}{$Symbol}{"Static"} and $Symbol=~/\A(_Z|\?)/) {
11760 %{$CompatProblems{$Level}{$Symbol}{"Method_Became_NonStatic"}{""}}=(
11761 "Target"=>get_Signature($Symbol, 1)
11762 );
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011763 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011764 if(($CompleteSignature{1}{$Symbol}{"Virt"} and $CompleteSignature{2}{$PSymbol}{"Virt"})
11765 or ($CompleteSignature{1}{$Symbol}{"PureVirt"} and $CompleteSignature{2}{$PSymbol}{"PureVirt"}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011766 { # relative position of virtual and pure virtual methods
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011767 if($Level eq "Binary")
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011768 {
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040011769 if(defined $CompleteSignature{1}{$Symbol}{"RelPos"} and defined $CompleteSignature{2}{$PSymbol}{"RelPos"}
11770 and $CompleteSignature{1}{$Symbol}{"RelPos"}!=$CompleteSignature{2}{$PSymbol}{"RelPos"})
11771 { # top-level virtual methods only
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011772 my $Class_Id = $CompleteSignature{1}{$Symbol}{"Class"};
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040011773 my $Class_Name = $TypeInfo{1}{$Class_Id}{"Name"};
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040011774 if(defined $VirtualTable{1}{$Class_Name} and defined $VirtualTable{2}{$Class_Name}
11775 and $VirtualTable{1}{$Class_Name}{$Symbol}!=$VirtualTable{2}{$Class_Name}{$Symbol})
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011776 { # check the absolute position of virtual method (including added and removed methods)
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040011777 my %Class_Type = get_Type($Class_Id, 1);
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011778 my $ProblemType = "Virtual_Method_Position";
11779 if($CompleteSignature{1}{$Symbol}{"PureVirt"}) {
11780 $ProblemType = "Pure_Virtual_Method_Position";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011781 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011782 if(isUsedClass($Class_Id, 1, $Level))
11783 {
11784 my @Affected = ($Symbol, keys(%{$OverriddenMethods{1}{$Symbol}}));
11785 foreach my $AffectedInterface (@Affected)
11786 {
11787 %{$CompatProblems{$Level}{$AffectedInterface}{$ProblemType}{$tr_name{$MnglName}}}=(
11788 "Type_Name"=>$Class_Type{"Name"},
11789 "Type_Type"=>"Class",
11790 "Old_Value"=>$CompleteSignature{1}{$Symbol}{"RelPos"},
11791 "New_Value"=>$CompleteSignature{2}{$PSymbol}{"RelPos"},
11792 "Target"=>get_Signature($Symbol, 1) );
11793 }
Andrey Ponomarenko16934472012-03-29 15:37:04 +040011794 $VTableChanged_M{$Class_Type{"Name"}} = 1;
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011795 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011796 }
11797 }
11798 }
11799 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011800 if($CompleteSignature{1}{$Symbol}{"PureVirt"}
11801 or $CompleteSignature{2}{$PSymbol}{"PureVirt"})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011802 { # do NOT check type changes in pure virtuals
11803 next;
11804 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011805 $CheckedSymbols{$Level}{$Symbol}=1;
11806 if($Symbol=~/\A(_Z|\?)/
11807 or keys(%{$CompleteSignature{1}{$Symbol}{"Param"}})==keys(%{$CompleteSignature{2}{$PSymbol}{"Param"}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011808 { # C/C++: changes in parameters
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011809 foreach my $ParamPos (sort {int($a) <=> int($b)} keys(%{$CompleteSignature{1}{$Symbol}{"Param"}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011810 { # checking parameters
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011811 mergeParameters($Symbol, $PSymbol, $ParamPos, $ParamPos, $Level);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011812 }
11813 }
11814 else
11815 { # C: added/removed parameters
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011816 foreach my $ParamPos (sort {int($a) <=> int($b)} keys(%{$CompleteSignature{2}{$PSymbol}{"Param"}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011817 { # checking added parameters
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040011818 my $PType2_Id = $CompleteSignature{2}{$PSymbol}{"Param"}{$ParamPos}{"type"};
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040011819 my $PType2_Name = $TypeInfo{2}{$PType2_Id}{"Name"};
11820 last if($PType2_Name eq "...");
11821 my $PName = $CompleteSignature{2}{$PSymbol}{"Param"}{$ParamPos}{"name"};
11822 my $PName_Old = (defined $CompleteSignature{1}{$Symbol}{"Param"}{$ParamPos})?$CompleteSignature{1}{$Symbol}{"Param"}{$ParamPos}{"name"}:"";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011823 my $ParamPos_Prev = "-1";
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040011824 if($PName=~/\Ap\d+\Z/i)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011825 { # added unnamed parameter ( pN )
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040011826 my @Positions1 = find_ParamPair_Pos_byTypeAndPos($PType2_Name, $ParamPos, "backward", $Symbol, 1);
11827 my @Positions2 = find_ParamPair_Pos_byTypeAndPos($PType2_Name, $ParamPos, "backward", $Symbol, 2);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011828 if($#Positions1==-1 or $#Positions2>$#Positions1) {
11829 $ParamPos_Prev = "lost";
11830 }
11831 }
11832 else {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040011833 $ParamPos_Prev = find_ParamPair_Pos_byName($PName, $Symbol, 1);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011834 }
11835 if($ParamPos_Prev eq "lost")
11836 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011837 if($ParamPos>keys(%{$CompleteSignature{1}{$Symbol}{"Param"}})-1)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011838 {
11839 my $ProblemType = "Added_Parameter";
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040011840 if($PName=~/\Ap\d+\Z/) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011841 $ProblemType = "Added_Unnamed_Parameter";
11842 }
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040011843 %{$CompatProblems{$Level}{$Symbol}{$ProblemType}{showPos($ParamPos)." Parameter"}}=(
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040011844 "Target"=>$PName,
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011845 "Param_Pos"=>$ParamPos,
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040011846 "Param_Type"=>$PType2_Name,
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011847 "New_Signature"=>get_Signature($Symbol, 2) );
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011848 }
11849 else
11850 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040011851 my %ParamType_Pure = get_PureType($PType2_Id, 2);
11852 my $PairType_Id = $CompleteSignature{1}{$Symbol}{"Param"}{$ParamPos}{"type"};
11853 my %PairType_Pure = get_PureType($PairType_Id, 1);
11854 if(($ParamType_Pure{"Name"} eq $PairType_Pure{"Name"} or $PType2_Name eq $TypeInfo{1}{$PairType_Id}{"Name"})
11855 and find_ParamPair_Pos_byName($PName_Old, $Symbol, 2) eq "lost")
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011856 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040011857 if($PName_Old!~/\Ap\d+\Z/ and $PName!~/\Ap\d+\Z/)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011858 {
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040011859 %{$CompatProblems{$Level}{$Symbol}{"Renamed_Parameter"}{showPos($ParamPos)." Parameter"}}=(
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040011860 "Target"=>$PName_Old,
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011861 "Param_Pos"=>$ParamPos,
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040011862 "Param_Type"=>$PType2_Name,
11863 "Old_Value"=>$PName_Old,
11864 "New_Value"=>$PName,
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011865 "New_Signature"=>get_Signature($Symbol, 2) );
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011866 }
11867 }
11868 else
11869 {
11870 my $ProblemType = "Added_Middle_Parameter";
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040011871 if($PName=~/\Ap\d+\Z/) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011872 $ProblemType = "Added_Middle_Unnamed_Parameter";
11873 }
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040011874 %{$CompatProblems{$Level}{$Symbol}{$ProblemType}{showPos($ParamPos)." Parameter"}}=(
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040011875 "Target"=>$PName,
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011876 "Param_Pos"=>$ParamPos,
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040011877 "Param_Type"=>$PType2_Name,
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011878 "New_Signature"=>get_Signature($Symbol, 2) );
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011879 }
11880 }
11881 }
11882 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011883 foreach my $ParamPos (sort {int($a) <=> int($b)} keys(%{$CompleteSignature{1}{$Symbol}{"Param"}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011884 { # check relevant parameters
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040011885 my $PType1_Id = $CompleteSignature{1}{$Symbol}{"Param"}{$ParamPos}{"type"};
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011886 my $ParamName1 = $CompleteSignature{1}{$Symbol}{"Param"}{$ParamPos}{"name"};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011887 # FIXME: find relevant parameter by name
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011888 if(defined $CompleteSignature{2}{$PSymbol}{"Param"}{$ParamPos})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011889 {
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040011890 my $PType2_Id = $CompleteSignature{2}{$PSymbol}{"Param"}{$ParamPos}{"type"};
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011891 my $ParamName2 = $CompleteSignature{2}{$PSymbol}{"Param"}{$ParamPos}{"name"};
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040011892 if($TypeInfo{1}{$PType1_Id}{"Name"} eq $TypeInfo{2}{$PType2_Id}{"Name"}
11893 or ($ParamName1!~/\Ap\d+\Z/i and $ParamName1 eq $ParamName2)) {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011894 mergeParameters($Symbol, $PSymbol, $ParamPos, $ParamPos, $Level);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011895 }
11896 }
11897 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011898 foreach my $ParamPos (sort {int($a) <=> int($b)} keys(%{$CompleteSignature{1}{$Symbol}{"Param"}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011899 { # checking removed parameters
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040011900 my $PType1_Id = $CompleteSignature{1}{$Symbol}{"Param"}{$ParamPos}{"type"};
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040011901 my $PType1_Name = $TypeInfo{1}{$PType1_Id}{"Name"};
11902 last if($PType1_Name eq "...");
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011903 my $Parameter_Name = $CompleteSignature{1}{$Symbol}{"Param"}{$ParamPos}{"name"};
11904 my $Parameter_NewName = (defined $CompleteSignature{2}{$PSymbol}{"Param"}{$ParamPos})?$CompleteSignature{2}{$PSymbol}{"Param"}{$ParamPos}{"name"}:"";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011905 my $ParamPos_New = "-1";
11906 if($Parameter_Name=~/\Ap\d+\Z/i)
11907 { # removed unnamed parameter ( pN )
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040011908 my @Positions1 = find_ParamPair_Pos_byTypeAndPos($PType1_Name, $ParamPos, "forward", $Symbol, 1);
11909 my @Positions2 = find_ParamPair_Pos_byTypeAndPos($PType1_Name, $ParamPos, "forward", $Symbol, 2);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011910 if($#Positions2==-1 or $#Positions2<$#Positions1) {
11911 $ParamPos_New = "lost";
11912 }
11913 }
11914 else {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011915 $ParamPos_New = find_ParamPair_Pos_byName($Parameter_Name, $Symbol, 2);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011916 }
11917 if($ParamPos_New eq "lost")
11918 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011919 if($ParamPos>keys(%{$CompleteSignature{2}{$PSymbol}{"Param"}})-1)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011920 {
11921 my $ProblemType = "Removed_Parameter";
11922 if($Parameter_Name=~/\Ap\d+\Z/) {
11923 $ProblemType = "Removed_Unnamed_Parameter";
11924 }
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040011925 %{$CompatProblems{$Level}{$Symbol}{$ProblemType}{showPos($ParamPos)." Parameter"}}=(
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011926 "Target"=>$Parameter_Name,
11927 "Param_Pos"=>$ParamPos,
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040011928 "Param_Type"=>$PType1_Name,
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011929 "New_Signature"=>get_Signature($Symbol, 2) );
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011930 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011931 elsif($ParamPos<keys(%{$CompleteSignature{1}{$Symbol}{"Param"}})-1)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011932 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040011933 my %ParamType_Pure = get_PureType($PType1_Id, 1);
11934 my $PairType_Id = $CompleteSignature{2}{$PSymbol}{"Param"}{$ParamPos}{"type"};
11935 my %PairType_Pure = get_PureType($PairType_Id, 2);
11936 if(($ParamType_Pure{"Name"} eq $PairType_Pure{"Name"} or $PType1_Name eq $TypeInfo{2}{$PairType_Id}{"Name"})
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011937 and find_ParamPair_Pos_byName($Parameter_NewName, $Symbol, 1) eq "lost")
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011938 {
11939 if($Parameter_NewName!~/\Ap\d+\Z/ and $Parameter_Name!~/\Ap\d+\Z/)
11940 {
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040011941 %{$CompatProblems{$Level}{$Symbol}{"Renamed_Parameter"}{showPos($ParamPos)." Parameter"}}=(
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011942 "Target"=>$Parameter_Name,
11943 "Param_Pos"=>$ParamPos,
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040011944 "Param_Type"=>$PType1_Name,
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011945 "Old_Value"=>$Parameter_Name,
11946 "New_Value"=>$Parameter_NewName,
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011947 "New_Signature"=>get_Signature($Symbol, 2) );
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011948 }
11949 }
11950 else
11951 {
11952 my $ProblemType = "Removed_Middle_Parameter";
11953 if($Parameter_Name=~/\Ap\d+\Z/) {
11954 $ProblemType = "Removed_Middle_Unnamed_Parameter";
11955 }
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040011956 %{$CompatProblems{$Level}{$Symbol}{$ProblemType}{showPos($ParamPos)." Parameter"}}=(
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011957 "Target"=>$Parameter_Name,
11958 "Param_Pos"=>$ParamPos,
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040011959 "Param_Type"=>$PType1_Name,
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011960 "New_Signature"=>get_Signature($Symbol, 2) );
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011961 }
11962 }
11963 }
11964 }
11965 }
11966 # checking return type
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011967 my $ReturnType1_Id = $CompleteSignature{1}{$Symbol}{"Return"};
11968 my $ReturnType2_Id = $CompleteSignature{2}{$PSymbol}{"Return"};
11969 %SubProblems = detectTypeChange($ReturnType1_Id, $ReturnType2_Id, "Return", $Level);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011970 foreach my $SubProblemType (keys(%SubProblems))
11971 {
11972 my $New_Value = $SubProblems{$SubProblemType}{"New_Value"};
11973 my $Old_Value = $SubProblems{$SubProblemType}{"Old_Value"};
11974 my $NewProblemType = $SubProblemType;
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011975 if($Level eq "Binary" and $SubProblemType eq "Return_Type_Became_Void"
11976 and keys(%{$CompleteSignature{1}{$Symbol}{"Param"}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011977 { # parameters stack has been affected
11978 $NewProblemType = "Return_Type_Became_Void_And_Stack_Layout";
11979 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011980 elsif($Level eq "Binary"
11981 and $SubProblemType eq "Return_Type_From_Void")
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011982 { # parameters stack has been affected
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011983 if(keys(%{$CompleteSignature{1}{$Symbol}{"Param"}})) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011984 $NewProblemType = "Return_Type_From_Void_And_Stack_Layout";
11985 }
11986 else
11987 { # safe
11988 delete($SubProblems{$SubProblemType});
11989 next;
11990 }
11991 }
11992 elsif($SubProblemType eq "Return_Type_And_Size"
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011993 and $CompleteSignature{1}{$Symbol}{"Data"}) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011994 $NewProblemType = "Global_Data_Type_And_Size";
11995 }
11996 elsif($SubProblemType eq "Return_Type")
11997 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011998 if($CompleteSignature{1}{$Symbol}{"Data"})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011999 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012000 if(removedQual($Old_Value, $New_Value, "const"))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012001 { # const -> non-const global data
12002 $NewProblemType = "Global_Data_Became_Non_Const";
12003 }
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040012004 elsif(addedQual($Old_Value, $New_Value, "const"))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012005 { # non-const -> const global data
12006 $NewProblemType = "Global_Data_Became_Const";
12007 }
12008 else {
12009 $NewProblemType = "Global_Data_Type";
12010 }
12011 }
12012 else
12013 {
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040012014 if(addedQual($Old_Value, $New_Value, "const")) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012015 $NewProblemType = "Return_Type_Became_Const";
12016 }
12017 }
12018 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012019 elsif($SubProblemType eq "Return_Type_Format")
12020 {
12021 if($CompleteSignature{1}{$Symbol}{"Data"}) {
12022 $NewProblemType = "Global_Data_Type_Format";
12023 }
12024 }
12025 @{$CompatProblems{$Level}{$Symbol}{$NewProblemType}{"retval"}}{keys(%{$SubProblems{$SubProblemType}})} = values %{$SubProblems{$SubProblemType}};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012026 }
12027 if($ReturnType1_Id and $ReturnType2_Id)
12028 {
12029 @RecurTypes = ();
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040012030 %SubProblems = mergeTypes($ReturnType1_Id, $ReturnType2_Id, $Level);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012031 foreach my $SubProblemType (keys(%SubProblems))
12032 { # add "Global_Data_Size" problem
12033 my $New_Value = $SubProblems{$SubProblemType}{"New_Value"};
12034 my $Old_Value = $SubProblems{$SubProblemType}{"Old_Value"};
12035 if($SubProblemType eq "DataType_Size"
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012036 and $CompleteSignature{1}{$Symbol}{"Data"}
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040012037 and get_PLevel($ReturnType1_Id, 1)==0)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012038 { # add a new problem
12039 %{$SubProblems{"Global_Data_Size"}} = %{$SubProblems{$SubProblemType}};
12040 }
12041 }
12042 foreach my $SubProblemType (keys(%SubProblems))
12043 {
12044 foreach my $SubLocation (keys(%{$SubProblems{$SubProblemType}}))
12045 {
12046 my $NewLocation = ($SubLocation)?"retval->".$SubLocation:"retval";
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012047 %{$CompatProblems{$Level}{$Symbol}{$SubProblemType}{$NewLocation}}=(
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040012048 "Return_Type_Name"=>$TypeInfo{1}{$ReturnType1_Id}{"Name"} );
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012049 @{$CompatProblems{$Level}{$Symbol}{$SubProblemType}{$NewLocation}}{keys(%{$SubProblems{$SubProblemType}{$SubLocation}})} = values %{$SubProblems{$SubProblemType}{$SubLocation}};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012050 if($SubLocation!~/\-\>/) {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040012051 $CompatProblems{$Level}{$Symbol}{$SubProblemType}{$NewLocation}{"Start_Type_Name"} = $TypeInfo{1}{$ReturnType1_Id}{"Name"};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012052 }
12053 }
12054 }
12055 }
12056
12057 # checking object type
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040012058 my $ObjTId1 = $CompleteSignature{1}{$Symbol}{"Class"};
12059 my $ObjTId2 = $CompleteSignature{2}{$PSymbol}{"Class"};
12060 if($ObjTId1 and $ObjTId2
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012061 and not $CompleteSignature{1}{$Symbol}{"Static"})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012062 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040012063 my $ThisPtr1_Id = getTypeIdByName($TypeInfo{1}{$ObjTId1}{"Name"}."*const", 1);
12064 my $ThisPtr2_Id = getTypeIdByName($TypeInfo{2}{$ObjTId2}{"Name"}."*const", 2);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012065 if($ThisPtr1_Id and $ThisPtr2_Id)
12066 {
12067 @RecurTypes = ();
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040012068 %SubProblems = mergeTypes($ThisPtr1_Id, $ThisPtr2_Id, $Level);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012069 foreach my $SubProblemType (keys(%SubProblems))
12070 {
12071 foreach my $SubLocation (keys(%{$SubProblems{$SubProblemType}}))
12072 {
12073 my $NewLocation = ($SubLocation)?"this->".$SubLocation:"this";
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012074 %{$CompatProblems{$Level}{$Symbol}{$SubProblemType}{$NewLocation}}=(
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040012075 "Object_Type_Name"=>$TypeInfo{1}{$ObjTId1}{"Name"} );
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012076 @{$CompatProblems{$Level}{$Symbol}{$SubProblemType}{$NewLocation}}{keys(%{$SubProblems{$SubProblemType}{$SubLocation}})} = values %{$SubProblems{$SubProblemType}{$SubLocation}};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012077 if($SubLocation!~/\-\>/) {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040012078 $CompatProblems{$Level}{$Symbol}{$SubProblemType}{$NewLocation}{"Start_Type_Name"} = $TypeInfo{1}{$ObjTId1}{"Name"};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012079 }
12080 }
12081 }
12082 }
12083 }
12084 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012085 if($Level eq "Binary") {
12086 mergeVTables($Level);
12087 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +040012088 foreach my $Symbol (keys(%{$CompatProblems{$Level}})) {
12089 $CheckedSymbols{$Level}{$Symbol} = 1;
12090 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012091}
12092
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040012093sub rmQuals($$)
12094{
12095 my ($Value, $Qual) = @_;
12096 if(not $Qual) {
12097 return $Value;
12098 }
12099 if($Qual eq "all")
12100 { # all quals
12101 $Qual = "const|volatile|restrict";
12102 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040012103 while($Value=~s/\b$Qual\b//) {
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040012104 $Value = formatName($Value);
12105 }
12106 return $Value;
12107}
12108
12109sub cmpBTypes($$$$)
12110{
12111 my ($T1, $T2, $V1, $V2) = @_;
12112 $T1 = uncover_typedefs($T1, $V1);
12113 $T2 = uncover_typedefs($T2, $V2);
12114 return (rmQuals($T1, "all") eq rmQuals($T2, "all"));
12115}
12116
12117sub addedQual($$$)
12118{
12119 my ($Old_Value, $New_Value, $Qual) = @_;
Andrey Ponomarenko85043792012-05-14 16:48:07 +040012120 return removedQual_($New_Value, $Old_Value, 2, 1, $Qual);
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040012121}
12122
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012123sub removedQual($$$)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012124{
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012125 my ($Old_Value, $New_Value, $Qual) = @_;
Andrey Ponomarenko85043792012-05-14 16:48:07 +040012126 return removedQual_($Old_Value, $New_Value, 1, 2, $Qual);
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040012127}
12128
12129sub removedQual_($$$$$)
12130{
12131 my ($Old_Value, $New_Value, $V1, $V2, $Qual) = @_;
12132 $Old_Value = uncover_typedefs($Old_Value, $V1);
12133 $New_Value = uncover_typedefs($New_Value, $V2);
12134 if($Old_Value eq $New_Value)
12135 { # equal types
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012136 return 0;
12137 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040012138 if($Old_Value!~/\b$Qual\b/)
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040012139 { # without a qual
12140 return 0;
12141 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040012142 elsif($New_Value!~/\b$Qual\b/)
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040012143 { # became non-qual
12144 return 1;
12145 }
12146 else
12147 {
12148 my @BQ1 = getQualModel($Old_Value, $Qual);
12149 my @BQ2 = getQualModel($New_Value, $Qual);
12150 foreach (0 .. $#BQ1)
12151 { # removed qual
12152 if($BQ1[$_]==1
12153 and $BQ2[$_]!=1)
12154 {
12155 return 2;
12156 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012157 }
12158 }
12159 return 0;
12160}
12161
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040012162sub getQualModel($$)
12163{
12164 my ($Value, $Qual) = @_;
12165 if(not $Qual) {
12166 return $Value;
12167 }
12168
12169 # cleaning
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040012170 while($Value=~/(\w+)/ and $1 ne $Qual) {
12171 $Value=~s/\b$1\b//g;
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040012172 }
12173 $Value=~s/[^\*\&\w]+//g;
12174
12175 # modeling
12176 # int*const*const == 011
12177 # int**const == 001
12178 my @Model = ();
12179 my @Elems = split(/[\*\&]/, $Value);
12180 if(not @Elems) {
12181 return (0);
12182 }
12183 foreach (@Elems)
12184 {
12185 if($_ eq $Qual) {
12186 push(@Model, 1);
12187 }
12188 else {
12189 push(@Model, 0);
12190 }
12191 }
12192
12193 return @Model;
12194}
12195
12196sub showVal($$$)
12197{
12198 my ($Value, $TypeId, $LibVersion) = @_;
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040012199 my %PureType = get_PureType($TypeId, $LibVersion);
12200 if($PureType{"Name"}=~/\A(char(| const)\*|std::string(|&))\Z/)
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040012201 { # strings
12202 return "\"$Value\"";
12203 }
12204 elsif($PureType{"Name"}=~/\Achar(| const)\Z/)
12205 { # characters
12206 return "\'$Value\'";
12207 }
12208 return $Value;
12209}
12210
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012211sub mergeParameters($$$$$)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012212{
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012213 my ($Symbol, $PSymbol, $ParamPos1, $ParamPos2, $Level) = @_;
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040012214 if(not $Symbol) {
12215 return;
12216 }
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040012217 my $PType1_Id = $CompleteSignature{1}{$Symbol}{"Param"}{$ParamPos1}{"type"};
12218 my $PName1 = $CompleteSignature{1}{$Symbol}{"Param"}{$ParamPos1}{"name"};
12219 my $PType2_Id = $CompleteSignature{2}{$PSymbol}{"Param"}{$ParamPos2}{"type"};
12220 my $PName2 = $CompleteSignature{2}{$PSymbol}{"Param"}{$ParamPos2}{"name"};
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040012221 if(not $PType1_Id
12222 or not $PType2_Id) {
12223 return;
12224 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040012225 my %Type1 = get_Type($PType1_Id, 1);
12226 my %Type2 = get_Type($PType2_Id, 2);
12227 my %BaseType1 = get_BaseType($PType1_Id, 1);
12228 my %BaseType2 = get_BaseType($PType2_Id, 2);
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040012229 my $Parameter_Location = ($PName1)?$PName1:showPos($ParamPos1)." Parameter";
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012230 if($Level eq "Binary")
12231 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040012232 if(checkDump(1, "2.6.1") and checkDump(2, "2.6.1"))
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012233 { # "reg" attribute added in ACC 1.95.1 (dump 2.6.1 format)
12234 if($CompleteSignature{1}{$Symbol}{"Param"}{$ParamPos1}{"reg"}
12235 and not $CompleteSignature{2}{$PSymbol}{"Param"}{$ParamPos2}{"reg"})
12236 {
12237 %{$CompatProblems{$Level}{$Symbol}{"Parameter_Became_Non_Register"}{$Parameter_Location}}=(
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040012238 "Target"=>$PName1,
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012239 "Param_Pos"=>$ParamPos1 );
12240 }
12241 elsif(not $CompleteSignature{1}{$Symbol}{"Param"}{$ParamPos1}{"reg"}
12242 and $CompleteSignature{2}{$PSymbol}{"Param"}{$ParamPos2}{"reg"})
12243 {
12244 %{$CompatProblems{$Level}{$Symbol}{"Parameter_Became_Register"}{$Parameter_Location}}=(
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040012245 "Target"=>$PName1,
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012246 "Param_Pos"=>$ParamPos1 );
12247 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012248 }
12249 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040012250 if(checkDump(1, "2.0") and checkDump(2, "2.0"))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012251 { # "default" attribute added in ACC 1.22 (dump 2.0 format)
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040012252 my $Value_Old = $CompleteSignature{1}{$Symbol}{"Param"}{$ParamPos1}{"default"};
12253 my $Value_New = $CompleteSignature{2}{$PSymbol}{"Param"}{$ParamPos2}{"default"};
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040012254 if(not checkDump(1, "2.13")
12255 and checkDump(2, "2.13"))
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040012256 { # support for old ABI dumps
12257 if(defined $Value_Old and defined $Value_New)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012258 {
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040012259 if($Type1{"Name"} eq "bool"
12260 and $Value_Old eq "false" and $Value_New eq "0")
12261 { # int class::method ( bool p = 0 );
12262 # old ABI dumps: "false"
12263 # new ABI dumps: "0"
12264 $Value_Old = "0";
12265 }
12266 }
12267 }
12268 if(defined $Value_Old)
12269 {
12270 $Value_Old = showVal($Value_Old, $PType1_Id, 1);
12271 if(defined $Value_New)
12272 {
12273 $Value_New = showVal($Value_New, $PType2_Id, 2);
12274 if($Value_Old ne $Value_New)
12275 { # FIXME: how to distinguish "0" and 0 (NULL)
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012276 %{$CompatProblems{$Level}{$Symbol}{"Parameter_Default_Value_Changed"}{$Parameter_Location}}=(
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040012277 "Target"=>$PName1,
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012278 "Param_Pos"=>$ParamPos1,
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040012279 "Old_Value"=>$Value_Old,
12280 "New_Value"=>$Value_New );
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012281 }
12282 }
12283 else
12284 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012285 %{$CompatProblems{$Level}{$Symbol}{"Parameter_Default_Value_Removed"}{$Parameter_Location}}=(
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040012286 "Target"=>$PName1,
12287 "Param_Pos"=>$ParamPos1,
12288 "Old_Value"=>$Value_Old );
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012289 }
12290 }
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040012291 elsif(defined $Value_New)
12292 {
12293 $Value_New = showVal($Value_New, $PType2_Id, 2);
12294 %{$CompatProblems{$Level}{$Symbol}{"Parameter_Default_Value_Added"}{$Parameter_Location}}=(
12295 "Target"=>$PName1,
12296 "Param_Pos"=>$ParamPos1,
12297 "New_Value"=>$Value_New );
12298 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012299 }
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040012300 if($PName1 and $PName2 and $PName1 ne $PName2
12301 and $PType1_Id!=-1 and $PType2_Id!=-1
12302 and $PName1!~/\Ap\d+\Z/ and $PName2!~/\Ap\d+\Z/)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012303 { # except unnamed "..." value list (Id=-1)
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040012304 %{$CompatProblems{$Level}{$Symbol}{"Renamed_Parameter"}{showPos($ParamPos1)." Parameter"}}=(
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040012305 "Target"=>$PName1,
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012306 "Param_Pos"=>$ParamPos1,
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040012307 "Param_Type"=>$TypeInfo{1}{$PType1_Id}{"Name"},
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040012308 "Old_Value"=>$PName1,
12309 "New_Value"=>$PName2,
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012310 "New_Signature"=>get_Signature($Symbol, 2) );
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012311 }
12312 # checking type change (replace)
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040012313 my %SubProblems = detectTypeChange($PType1_Id, $PType2_Id, "Parameter", $Level);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012314 foreach my $SubProblemType (keys(%SubProblems))
12315 { # add new problems, remove false alarms
12316 my $New_Value = $SubProblems{$SubProblemType}{"New_Value"};
12317 my $Old_Value = $SubProblems{$SubProblemType}{"Old_Value"};
12318 if($SubProblemType eq "Parameter_Type")
12319 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040012320 if(checkDump(1, "2.6") and checkDump(2, "2.6"))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012321 {
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040012322 if(my $RA = addedQual($Old_Value, $New_Value, "restrict"))
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012323 {
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040012324 %{$SubProblems{"Parameter_Became_Restrict"}} = %{$SubProblems{$SubProblemType}};
12325 if($Level eq "Source"
12326 and cmpBTypes($Old_Value, $New_Value, 1, 2)) {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012327 delete($SubProblems{$SubProblemType});
12328 }
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040012329 }
12330 elsif(my $RR = removedQual($Old_Value, $New_Value, "restrict"))
12331 {
12332 %{$SubProblems{"Parameter_Became_NonRestrict"}} = %{$SubProblems{$SubProblemType}};
12333 if($Level eq "Source"
12334 and cmpBTypes($Old_Value, $New_Value, 1, 2)) {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012335 delete($SubProblems{$SubProblemType});
12336 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012337 }
12338 }
12339 if($Type2{"Type"} eq "Const" and $BaseType2{"Name"} eq $Type1{"Name"}
12340 and $Type1{"Type"}=~/Intrinsic|Class|Struct|Union|Enum/)
12341 { # int to "int const"
12342 delete($SubProblems{$SubProblemType});
12343 }
12344 if($Type1{"Type"} eq "Const" and $BaseType1{"Name"} eq $Type2{"Name"}
12345 and $Type2{"Type"}=~/Intrinsic|Class|Struct|Union|Enum/)
12346 { # "int const" to int
12347 delete($SubProblems{$SubProblemType});
12348 }
12349 }
12350 }
12351 foreach my $SubProblemType (keys(%SubProblems))
12352 { # modify/register problems
12353 my $New_Value = $SubProblems{$SubProblemType}{"New_Value"};
12354 my $Old_Value = $SubProblems{$SubProblemType}{"Old_Value"};
12355 my $NewProblemType = $SubProblemType;
12356 if($Old_Value eq "..." and $New_Value ne "...")
12357 { # change from "..." to "int"
12358 if($ParamPos1==0)
12359 { # ISO C requires a named argument before "..."
12360 next;
12361 }
12362 $NewProblemType = "Parameter_Became_NonVaList";
12363 }
12364 elsif($New_Value eq "..." and $Old_Value ne "...")
12365 { # change from "int" to "..."
12366 if($ParamPos2==0)
12367 { # ISO C requires a named argument before "..."
12368 next;
12369 }
12370 $NewProblemType = "Parameter_Became_VaList";
12371 }
12372 elsif($SubProblemType eq "Parameter_Type"
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012373 and removedQual($Old_Value, $New_Value, "const"))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012374 { # parameter: "const" to non-"const"
12375 $NewProblemType = "Parameter_Became_Non_Const";
12376 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012377 elsif($Level eq "Binary" and ($SubProblemType eq "Parameter_Type_And_Size"
12378 or $SubProblemType eq "Parameter_Type"))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012379 {
12380 my ($Arch1, $Arch2) = (getArch(1), getArch(2));
12381 if($Arch1 eq "unknown" or $Arch2 eq "unknown")
12382 { # if one of the architectures is unknown
12383 # then set other arhitecture to unknown too
12384 ($Arch1, $Arch2) = ("unknown", "unknown");
12385 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012386 my ($Method1, $Passed1, $SizeOnStack1, $RegName1) = callingConvention($Symbol, $ParamPos1, 1, $Arch1);
12387 my ($Method2, $Passed2, $SizeOnStack2, $RegName2) = callingConvention($Symbol, $ParamPos2, 2, $Arch2);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012388 if($Method1 eq $Method2)
12389 {
12390 if($Method1 eq "stack" and $SizeOnStack1 ne $SizeOnStack2) {
12391 $NewProblemType = "Parameter_Type_And_Stack";
12392 }
12393 elsif($Method1 eq "register" and $RegName1 ne $RegName2) {
12394 $NewProblemType = "Parameter_Type_And_Register";
12395 }
12396 }
12397 else
12398 {
12399 if($Method1 eq "stack") {
12400 $NewProblemType = "Parameter_Type_And_Pass_Through_Register";
12401 }
12402 elsif($Method1 eq "register") {
12403 $NewProblemType = "Parameter_Type_And_Pass_Through_Stack";
12404 }
12405 }
12406 $SubProblems{$SubProblemType}{"Old_Reg"} = $RegName1;
12407 $SubProblems{$SubProblemType}{"New_Reg"} = $RegName2;
12408 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012409 %{$CompatProblems{$Level}{$Symbol}{$NewProblemType}{$Parameter_Location}}=(
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040012410 "Target"=>$PName1,
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012411 "Param_Pos"=>$ParamPos1,
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012412 "New_Signature"=>get_Signature($Symbol, 2) );
12413 @{$CompatProblems{$Level}{$Symbol}{$NewProblemType}{$Parameter_Location}}{keys(%{$SubProblems{$SubProblemType}})} = values %{$SubProblems{$SubProblemType}};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012414 }
12415 @RecurTypes = ();
12416 # checking type definition changes
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040012417 my %SubProblems_Merge = mergeTypes($PType1_Id, $PType2_Id, $Level);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012418 foreach my $SubProblemType (keys(%SubProblems_Merge))
12419 {
12420 foreach my $SubLocation (keys(%{$SubProblems_Merge{$SubProblemType}}))
12421 {
12422 my $NewProblemType = $SubProblemType;
12423 if($SubProblemType eq "DataType_Size")
12424 {
12425 my $InitialType_Type = $SubProblems_Merge{$SubProblemType}{$SubLocation}{"InitialType_Type"};
12426 if($InitialType_Type!~/\A(Pointer|Ref)\Z/ and $SubLocation!~/\-\>/)
12427 { # stack has been affected
12428 $NewProblemType = "DataType_Size_And_Stack";
12429 }
12430 }
12431 my $NewLocation = ($SubLocation)?$Parameter_Location."->".$SubLocation:$Parameter_Location;
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012432 %{$CompatProblems{$Level}{$Symbol}{$NewProblemType}{$NewLocation}}=(
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040012433 "Param_Type"=>$TypeInfo{1}{$PType1_Id}{"Name"},
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012434 "Param_Pos"=>$ParamPos1,
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040012435 "Param_Name"=>$PName1 );
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012436 @{$CompatProblems{$Level}{$Symbol}{$NewProblemType}{$NewLocation}}{keys(%{$SubProblems_Merge{$SubProblemType}{$SubLocation}})} = values %{$SubProblems_Merge{$SubProblemType}{$SubLocation}};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012437 if($SubLocation!~/\-\>/) {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040012438 $CompatProblems{$Level}{$Symbol}{$NewProblemType}{$NewLocation}{"Start_Type_Name"} = $TypeInfo{1}{$PType1_Id}{"Name"};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012439 }
12440 }
12441 }
12442}
12443
12444sub callingConvention($$$$)
12445{ # calling conventions for different compilers and operating systems
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012446 my ($Symbol, $ParamPos, $LibVersion, $Arch) = @_;
12447 my $ParamTypeId = $CompleteSignature{$LibVersion}{$Symbol}{"Param"}{$ParamPos}{"type"};
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040012448 my %Type = get_PureType($ParamTypeId, $LibVersion);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012449 my ($Method, $Alignment, $Passed, $Register) = ("", 0, "", "");
12450 if($OSgroup=~/\A(linux|macos|freebsd)\Z/)
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012451 { # GCC
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012452 if($Arch eq "x86")
12453 { # System V ABI Intel386 ("Function Calling Sequence")
12454 # The stack is word aligned. Although the architecture does not require any
12455 # alignment of the stack, software convention and the operating system
12456 # requires that the stack be aligned on a word boundary.
12457
12458 # Argument words are pushed onto the stack in reverse order (that is, the
12459 # rightmost argument in C call syntax has the highest address), preserving the
12460 # stack’s word alignment. All incoming arguments appear on the stack, residing
12461 # in the stack frame of the caller.
12462
12463 # An argument’s size is increased, if necessary, to make it a multiple of words.
12464 # This may require tail padding, depending on the size of the argument.
12465
12466 # Other areas depend on the compiler and the code being compiled. The stan-
12467 # dard calling sequence does not define a maximum stack frame size, nor does
12468 # it restrict how a language system uses the ‘‘unspecified’’ area of the stan-
12469 # dard stack frame.
12470 ($Method, $Alignment) = ("stack", 4);
12471 }
12472 elsif($Arch eq "x86_64")
12473 { # System V AMD64 ABI ("Function Calling Sequence")
12474 ($Method, $Alignment) = ("stack", 8);# eightbyte aligned
12475 }
12476 elsif($Arch eq "arm")
12477 { # Procedure Call Standard for the ARM Architecture
12478 # The stack must be double-word aligned
12479 ($Method, $Alignment) = ("stack", 8);# double-word
12480 }
12481 }
12482 elsif($OSgroup eq "windows")
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012483 { # MS C++ Compiler
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012484 if($Arch eq "x86")
12485 {
12486 if($ParamPos==0) {
12487 ($Method, $Register, $Passed) = ("register", "ecx", "value");
12488 }
12489 elsif($ParamPos==1) {
12490 ($Method, $Register, $Passed) = ("register", "edx", "value");
12491 }
12492 else {
12493 ($Method, $Alignment) = ("stack", 4);
12494 }
12495 }
12496 elsif($Arch eq "x86_64")
12497 {
12498 if($ParamPos<=3)
12499 {
12500 if($Type{"Name"}=~/\A(float|double|long double)\Z/) {
12501 ($Method, $Passed) = ("xmm".$ParamPos, "value");
12502 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040012503 elsif(isScalar($Type{"Name"})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012504 or $Type{"Type"}=~/\A(Struct|Union|Enum|Array)\Z/
12505 or $Type{"Name"}=~/\A(__m64|__m128)\Z/)
12506 {
12507 if($ParamPos==0) {
12508 ($Method, $Register, $Passed) = ("register", "rcx", "value");
12509 }
12510 elsif($ParamPos==1) {
12511 ($Method, $Register, $Passed) = ("register", "rdx", "value");
12512 }
12513 elsif($ParamPos==2) {
12514 ($Method, $Register, $Passed) = ("register", "r8", "value");
12515 }
12516 elsif($ParamPos==3) {
12517 ($Method, $Register, $Passed) = ("register", "r9", "value");
12518 }
12519 if($Type{"Size"}>64
12520 or $Type{"Type"} eq "Array") {
12521 $Passed = "pointer";
12522 }
12523 }
12524 }
12525 else {
12526 ($Method, $Alignment) = ("stack", 8);# word alignment
12527 }
12528 }
12529 }
12530 if($Method eq "register") {
12531 return ("register", $Passed, "", $Register);
12532 }
12533 else
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012534 { # on the stack
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012535 if(not $Alignment)
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012536 { # default convention
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012537 $Alignment = $WORD_SIZE{$LibVersion};
12538 }
12539 if(not $Passed)
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012540 { # default convention
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012541 $Passed = "value";
12542 }
12543 my $SizeOnStack = $Type{"Size"};
12544 # FIXME: improve stack alignment
12545 if($SizeOnStack!=$Alignment) {
12546 $SizeOnStack = int(($Type{"Size"}+$Alignment)/$Alignment)*$Alignment;
12547 }
12548 return ("stack", $Passed, $SizeOnStack, "");
12549 }
12550}
12551
12552sub find_ParamPair_Pos_byName($$$)
12553{
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012554 my ($Name, $Symbol, $LibVersion) = @_;
12555 foreach my $ParamPos (sort {int($a)<=>int($b)} keys(%{$CompleteSignature{$LibVersion}{$Symbol}{"Param"}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012556 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012557 next if(not defined $CompleteSignature{$LibVersion}{$Symbol}{"Param"}{$ParamPos});
12558 if($CompleteSignature{$LibVersion}{$Symbol}{"Param"}{$ParamPos}{"name"} eq $Name)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012559 {
12560 return $ParamPos;
12561 }
12562 }
12563 return "lost";
12564}
12565
12566sub find_ParamPair_Pos_byTypeAndPos($$$$$)
12567{
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012568 my ($TypeName, $MediumPos, $Order, $Symbol, $LibVersion) = @_;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012569 my @Positions = ();
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012570 foreach my $ParamPos (sort {int($a)<=>int($b)} keys(%{$CompleteSignature{$LibVersion}{$Symbol}{"Param"}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012571 {
12572 next if($Order eq "backward" and $ParamPos>$MediumPos);
12573 next if($Order eq "forward" and $ParamPos<$MediumPos);
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012574 next if(not defined $CompleteSignature{$LibVersion}{$Symbol}{"Param"}{$ParamPos});
12575 my $PTypeId = $CompleteSignature{$LibVersion}{$Symbol}{"Param"}{$ParamPos}{"type"};
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040012576 if($TypeInfo{$LibVersion}{$PTypeId}{"Name"} eq $TypeName) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012577 push(@Positions, $ParamPos);
12578 }
12579 }
12580 return @Positions;
12581}
12582
12583sub getTypeIdByName($$)
12584{
12585 my ($TypeName, $Version) = @_;
12586 return $TName_Tid{$Version}{formatName($TypeName)};
12587}
12588
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012589sub checkFormatChange($$$)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012590{
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012591 my ($Type1_Id, $Type2_Id, $Level) = @_;
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040012592 my %Type1_Pure = get_PureType($Type1_Id, 1);
12593 my %Type2_Pure = get_PureType($Type2_Id, 2);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012594 if($Type1_Pure{"Name"} eq $Type2_Pure{"Name"})
12595 { # equal types
12596 return 0;
12597 }
12598 if($Type1_Pure{"Name"}=~/\*/
12599 or $Type2_Pure{"Name"}=~/\*/)
12600 { # compared in detectTypeChange()
12601 return 0;
12602 }
12603 my %FloatType = map {$_=>1} (
12604 "float",
12605 "double",
12606 "long double"
12607 );
12608 if($Type1_Pure{"Type"} ne $Type2_Pure{"Type"})
12609 { # different types
12610 if($Type1_Pure{"Type"} eq "Intrinsic"
12611 and $Type2_Pure{"Type"} eq "Enum")
12612 { # "int" to "enum"
12613 return 0;
12614 }
12615 elsif($Type2_Pure{"Type"} eq "Intrinsic"
12616 and $Type1_Pure{"Type"} eq "Enum")
12617 { # "enum" to "int"
12618 return 0;
12619 }
12620 else
12621 { # "union" to "struct"
12622 # ...
12623 return 1;
12624 }
12625 }
12626 else
12627 {
12628 if($Type1_Pure{"Type"} eq "Intrinsic")
12629 {
12630 if($FloatType{$Type1_Pure{"Name"}}
12631 or $FloatType{$Type2_Pure{"Name"}})
12632 { # "float" to "double"
12633 # "float" to "int"
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012634 if($Level eq "Source")
12635 { # Safe
12636 return 0;
12637 }
12638 else {
12639 return 1;
12640 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012641 }
12642 }
12643 elsif($Type1_Pure{"Type"}=~/Class|Struct|Union|Enum/)
12644 {
12645 my @Membs1 = keys(%{$Type1_Pure{"Memb"}});
12646 my @Membs2 = keys(%{$Type2_Pure{"Memb"}});
12647 if($#Membs1!=$#Membs2)
12648 { # different number of elements
12649 return 1;
12650 }
12651 if($Type1_Pure{"Type"} eq "Enum")
12652 {
12653 foreach my $Pos (@Membs1)
12654 { # compare elements by name and value
12655 if($Type1_Pure{"Memb"}{$Pos}{"name"} ne $Type2_Pure{"Memb"}{$Pos}{"name"}
12656 or $Type1_Pure{"Memb"}{$Pos}{"value"} ne $Type2_Pure{"Memb"}{$Pos}{"value"})
12657 { # different names
12658 return 1;
12659 }
12660 }
12661 }
12662 else
12663 {
12664 foreach my $Pos (@Membs1)
12665 { # compare elements by type name
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040012666 my $MT1 = $TypeInfo{1}{$Type1_Pure{"Memb"}{$Pos}{"type"}}{"Name"};
12667 my $MT2 = $TypeInfo{2}{$Type2_Pure{"Memb"}{$Pos}{"type"}}{"Name"};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012668 if($MT1 ne $MT2)
12669 { # different types
12670 return 1;
12671 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012672 if($Level eq "Source")
12673 {
12674 if($Type1_Pure{"Memb"}{$Pos}{"name"} ne $Type2_Pure{"Memb"}{$Pos}{"name"})
12675 { # different names
12676 return 1;
12677 }
12678 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012679 }
12680 }
12681 }
12682 }
12683 return 0;
12684}
12685
12686sub isScalar($) {
12687 return ($_[0]=~/\A(unsigned |)(short|int|long|long long)\Z/);
12688}
12689
12690sub isFloat($) {
12691 return ($_[0]=~/\A(float|double|long double)\Z/);
12692}
12693
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012694sub detectTypeChange($$$$)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012695{
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012696 my ($Type1_Id, $Type2_Id, $Prefix, $Level) = @_;
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040012697 if(not $Type1_Id or not $Type2_Id) {
12698 return ();
12699 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012700 my %LocalProblems = ();
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040012701 my %Type1 = get_Type($Type1_Id, 1);
12702 my %Type2 = get_Type($Type2_Id, 2);
12703 my %Type1_Pure = get_PureType($Type1_Id, 1);
12704 my %Type2_Pure = get_PureType($Type2_Id, 2);
12705 my %Type1_Base = ($Type1_Pure{"Type"} eq "Array")?get_OneStep_BaseType($Type1_Pure{"Tid"}, 1):get_BaseType($Type1_Id, 1);
12706 my %Type2_Base = ($Type2_Pure{"Type"} eq "Array")?get_OneStep_BaseType($Type2_Pure{"Tid"}, 2):get_BaseType($Type2_Id, 2);
12707 my $Type1_PLevel = get_PLevel($Type1_Id, 1);
12708 my $Type2_PLevel = get_PLevel($Type2_Id, 2);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012709 return () if(not $Type1{"Name"} or not $Type2{"Name"});
12710 return () if(not $Type1_Base{"Name"} or not $Type2_Base{"Name"});
12711 return () if($Type1_PLevel eq "" or $Type2_PLevel eq "");
12712 if($Type1_Base{"Name"} ne $Type2_Base{"Name"}
12713 and ($Type1{"Name"} eq $Type2{"Name"} or ($Type1_PLevel>=1 and $Type1_PLevel==$Type2_PLevel
12714 and $Type1_Base{"Name"} ne "void" and $Type2_Base{"Name"} ne "void")))
12715 { # base type change
12716 if($Type1{"Type"} eq "Typedef" and $Type2{"Type"} eq "Typedef"
12717 and $Type1{"Name"} eq $Type2{"Name"})
12718 { # will be reported in mergeTypes() as typedef problem
12719 return ();
12720 }
12721 if($Type1_Base{"Name"}!~/anon\-/ and $Type2_Base{"Name"}!~/anon\-/)
12722 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012723 if($Level eq "Binary"
12724 and $Type1_Base{"Size"} ne $Type2_Base{"Size"}
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012725 and $Type1_Base{"Size"} and $Type2_Base{"Size"})
12726 {
12727 %{$LocalProblems{$Prefix."_BaseType_And_Size"}}=(
12728 "Old_Value"=>$Type1_Base{"Name"},
12729 "New_Value"=>$Type2_Base{"Name"},
12730 "Old_Size"=>$Type1_Base{"Size"}*$BYTE_SIZE,
12731 "New_Size"=>$Type2_Base{"Size"}*$BYTE_SIZE,
12732 "InitialType_Type"=>$Type1_Pure{"Type"});
12733 }
12734 else
12735 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012736 if(checkFormatChange($Type1_Base{"Tid"}, $Type2_Base{"Tid"}, $Level))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012737 { # format change
12738 %{$LocalProblems{$Prefix."_BaseType_Format"}}=(
12739 "Old_Value"=>$Type1_Base{"Name"},
12740 "New_Value"=>$Type2_Base{"Name"},
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012741 "InitialType_Type"=>$Type1_Pure{"Type"});
12742 }
12743 elsif(tNameLock($Type1_Base{"Tid"}, $Type2_Base{"Tid"}))
12744 {
12745 %{$LocalProblems{$Prefix."_BaseType"}}=(
12746 "Old_Value"=>$Type1_Base{"Name"},
12747 "New_Value"=>$Type2_Base{"Name"},
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012748 "InitialType_Type"=>$Type1_Pure{"Type"});
12749 }
12750 }
12751 }
12752 }
12753 elsif($Type1{"Name"} ne $Type2{"Name"})
12754 { # type change
12755 if($Type1{"Name"}!~/anon\-/ and $Type2{"Name"}!~/anon\-/)
12756 {
12757 if($Prefix eq "Return" and $Type1{"Name"} eq "void"
12758 and $Type2_Pure{"Type"}=~/Intrinsic|Enum/) {
12759 # safe change
12760 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012761 elsif($Level eq "Binary"
12762 and $Prefix eq "Return"
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012763 and $Type1_Pure{"Name"} eq "void")
12764 {
12765 %{$LocalProblems{"Return_Type_From_Void"}}=(
12766 "New_Value"=>$Type2{"Name"},
12767 "New_Size"=>$Type2{"Size"}*$BYTE_SIZE,
12768 "InitialType_Type"=>$Type1_Pure{"Type"});
12769 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012770 elsif($Level eq "Binary"
12771 and $Prefix eq "Return" and $Type1_Pure{"Type"}=~/Intrinsic|Enum/
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012772 and $Type2_Pure{"Type"}=~/Struct|Class|Union/)
12773 { # returns into hidden first parameter instead of a register
12774
12775 # System V ABI Intel386 ("Function Calling Sequence")
12776 # A function that returns an integral or pointer value places its result in register %eax.
12777
12778 # A floating-point return value appears on the top of the Intel387 register stack. The
12779 # caller then must remove the value from the Intel387 stack, even if it doesn’t use the
12780 # value.
12781
12782 # If a function returns a structure or union, then the caller provides space for the
12783 # return value and places its address on the stack as argument word zero. In effect,
12784 # this address becomes a ‘‘hidden’’ first argument.
12785
12786 %{$LocalProblems{"Return_Type_From_Register_To_Stack"}}=(
12787 "Old_Value"=>$Type1{"Name"},
12788 "New_Value"=>$Type2{"Name"},
12789 "Old_Size"=>$Type1{"Size"}*$BYTE_SIZE,
12790 "New_Size"=>$Type2{"Size"}*$BYTE_SIZE,
12791 "InitialType_Type"=>$Type1_Pure{"Type"});
12792 }
12793 elsif($Prefix eq "Return"
12794 and $Type2_Pure{"Name"} eq "void")
12795 {
12796 %{$LocalProblems{"Return_Type_Became_Void"}}=(
12797 "Old_Value"=>$Type1{"Name"},
12798 "Old_Size"=>$Type1{"Size"}*$BYTE_SIZE,
12799 "InitialType_Type"=>$Type1_Pure{"Type"});
12800 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012801 elsif($Level eq "Binary" and $Prefix eq "Return"
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012802 and ((isScalar($Type1_Pure{"Name"}) and isFloat($Type2_Pure{"Name"}))
12803 or (isScalar($Type2_Pure{"Name"}) and isFloat($Type1_Pure{"Name"}))))
12804 { # The scalar and floating-point values are passed in different registers
12805 %{$LocalProblems{"Return_Type_And_Register"}}=(
12806 "Old_Value"=>$Type1{"Name"},
12807 "New_Value"=>$Type2{"Name"},
12808 "Old_Size"=>$Type1{"Size"}*$BYTE_SIZE,
12809 "New_Size"=>$Type2{"Size"}*$BYTE_SIZE,
12810 "InitialType_Type"=>$Type1_Pure{"Type"});
12811 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012812 elsif($Level eq "Binary"
12813 and $Prefix eq "Return" and $Type2_Pure{"Type"}=~/Intrinsic|Enum/
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012814 and $Type1_Pure{"Type"}=~/Struct|Class|Union/)
12815 { # returns in a register instead of a hidden first parameter
12816 %{$LocalProblems{"Return_Type_From_Stack_To_Register"}}=(
12817 "Old_Value"=>$Type1{"Name"},
12818 "New_Value"=>$Type2{"Name"},
12819 "Old_Size"=>$Type1{"Size"}*$BYTE_SIZE,
12820 "New_Size"=>$Type2{"Size"}*$BYTE_SIZE,
12821 "InitialType_Type"=>$Type1_Pure{"Type"});
12822 }
12823 else
12824 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012825 if($Level eq "Binary"
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040012826 and $Type1{"Size"} and $Type2{"Size"}
12827 and $Type1{"Size"} ne $Type2{"Size"})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012828 {
12829 %{$LocalProblems{$Prefix."_Type_And_Size"}}=(
12830 "Old_Value"=>$Type1{"Name"},
12831 "New_Value"=>$Type2{"Name"},
12832 "Old_Size"=>$Type1{"Size"}*$BYTE_SIZE,
12833 "New_Size"=>$Type2{"Size"}*$BYTE_SIZE,
12834 "InitialType_Type"=>$Type1_Pure{"Type"});
12835 }
12836 else
12837 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012838 if(checkFormatChange($Type1_Id, $Type2_Id, $Level))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012839 { # format change
12840 %{$LocalProblems{$Prefix."_Type_Format"}}=(
12841 "Old_Value"=>$Type1{"Name"},
12842 "New_Value"=>$Type2{"Name"},
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012843 "InitialType_Type"=>$Type1_Pure{"Type"});
12844 }
12845 elsif(tNameLock($Type1_Id, $Type2_Id))
12846 { # FIXME: correct this condition
12847 %{$LocalProblems{$Prefix."_Type"}}=(
12848 "Old_Value"=>$Type1{"Name"},
12849 "New_Value"=>$Type2{"Name"},
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012850 "InitialType_Type"=>$Type1_Pure{"Type"});
12851 }
12852 }
12853 }
12854 }
12855 }
12856 if($Type1_PLevel!=$Type2_PLevel)
12857 {
12858 if($Type1{"Name"} ne "void" and $Type1{"Name"} ne "..."
12859 and $Type2{"Name"} ne "void" and $Type2{"Name"} ne "...")
12860 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012861 if($Level eq "Source")
12862 {
12863 %{$LocalProblems{$Prefix."_PointerLevel"}}=(
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012864 "Old_Value"=>$Type1_PLevel,
12865 "New_Value"=>$Type2_PLevel);
12866 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012867 else
12868 {
12869 if($Type2_PLevel>$Type1_PLevel) {
12870 %{$LocalProblems{$Prefix."_PointerLevel_Increased"}}=(
12871 "Old_Value"=>$Type1_PLevel,
12872 "New_Value"=>$Type2_PLevel);
12873 }
12874 else {
12875 %{$LocalProblems{$Prefix."_PointerLevel_Decreased"}}=(
12876 "Old_Value"=>$Type1_PLevel,
12877 "New_Value"=>$Type2_PLevel);
12878 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012879 }
12880 }
12881 }
12882 if($Type1_Pure{"Type"} eq "Array")
12883 { # base_type[N] -> base_type[N]
12884 # base_type: older_structure -> typedef to newer_structure
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012885 my %SubProblems = detectTypeChange($Type1_Base{"Tid"}, $Type2_Base{"Tid"}, $Prefix, $Level);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012886 foreach my $SubProblemType (keys(%SubProblems))
12887 {
12888 $SubProblemType=~s/_Type/_BaseType/g;
12889 next if(defined $LocalProblems{$SubProblemType});
12890 foreach my $Attr (keys(%{$SubProblems{$SubProblemType}})) {
12891 $LocalProblems{$SubProblemType}{$Attr} = $SubProblems{$SubProblemType}{$Attr};
12892 }
12893 }
12894 }
12895 return %LocalProblems;
12896}
12897
12898sub tNameLock($$)
12899{
12900 my ($Tid1, $Tid2) = @_;
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040012901 my $Changed = 0;
12902 if(differentDumps("G"))
12903 { # different GCC versions
12904 $Changed = 1;
12905 }
12906 elsif(differentDumps("V"))
12907 { # different versions of ABI dumps
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040012908 if(not checkDump(1, "2.13")
12909 or not checkDump(2, "2.13"))
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040012910 { # latest names update
12911 # 2.6: added restrict qualifier
12912 # 2.13: added missed typedefs to qualified types
12913 $Changed = 1;
12914 }
12915 }
12916 if($Changed)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012917 { # different formats
12918 if($UseOldDumps)
12919 { # old dumps
12920 return 0;
12921 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040012922 my $TN1 = $TypeInfo{1}{$Tid1}{"Name"};
12923 my $TN2 = $TypeInfo{2}{$Tid2}{"Name"};
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040012924
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040012925 my $TT1 = $TypeInfo{1}{$Tid1}{"Type"};
12926 my $TT2 = $TypeInfo{2}{$Tid2}{"Type"};
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040012927
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040012928 my %Base1 = get_Type($Tid1, 1);
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040012929 while(defined $Base1{"Type"} and $Base1{"Type"} eq "Typedef") {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040012930 %Base1 = get_OneStep_BaseType($Base1{"Tid"}, 1);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012931 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040012932 my %Base2 = get_Type($Tid2, 2);
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040012933 while(defined $Base2{"Type"} and $Base2{"Type"} eq "Typedef") {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040012934 %Base2 = get_OneStep_BaseType($Base2{"Tid"}, 2);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012935 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +040012936 my $BName1 = uncover_typedefs($Base1{"Name"}, 1);
12937 my $BName2 = uncover_typedefs($Base2{"Name"}, 2);
12938 if($BName1 eq $BName2)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012939 { # equal base types
12940 return 0;
12941 }
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040012942
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040012943 if(not checkDump(1, "2.13")
12944 or not checkDump(2, "2.13"))
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040012945 { # broken array names in ABI dumps < 2.13
12946 if($TT1 eq "Array"
12947 and $TT2 eq "Array")
12948 {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012949 return 0;
12950 }
12951 }
12952
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040012953 if(not checkDump(1, "2.6")
12954 or not checkDump(2, "2.6"))
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040012955 { # added restrict attribute in 2.6
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040012956 if($TN1!~/\brestrict\b/
12957 and $TN2=~/\brestrict\b/)
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040012958 {
12959 return 0;
12960 }
12961 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012962 }
12963 return 1;
12964}
12965
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012966sub differentDumps($)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012967{
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012968 my $Check = $_[0];
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +040012969 if(defined $Cache{"differentDumps"}{$Check}) {
12970 return $Cache{"differentDumps"}{$Check};
12971 }
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040012972 if($UsedDump{1}{"V"} and $UsedDump{2}{"V"})
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012973 {
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040012974 if($Check eq "G")
12975 {
12976 if(getGccVersion(1) ne getGccVersion(2))
12977 { # different GCC versions
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +040012978 return ($Cache{"differentDumps"}{$Check}=1);
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040012979 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012980 }
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040012981 if($Check eq "V")
12982 {
12983 if(cmpVersions(formatVersion($UsedDump{1}{"V"}, 2),
12984 formatVersion($UsedDump{2}{"V"}, 2))!=0)
12985 { # different dump versions (skip micro version)
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +040012986 return ($Cache{"differentDumps"}{$Check}=1);
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040012987 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012988 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012989 }
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +040012990 return ($Cache{"differentDumps"}{$Check}=0);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012991}
12992
12993sub formatVersion($$)
12994{ # cut off version digits
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040012995 my ($V, $Digits) = @_;
12996 my @Elems = split(/\./, $V);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012997 return join(".", splice(@Elems, 0, $Digits));
12998}
12999
13000sub htmlSpecChars($)
13001{
13002 my $Str = $_[0];
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040013003 if($Str eq "") {
13004 return "";
13005 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013006 $Str=~s/\&([^#]|\Z)/&amp;$1/g;
13007 $Str=~s/</&lt;/g;
13008 $Str=~s/\-\>/&#45;&gt;/g; # &minus;
13009 $Str=~s/>/&gt;/g;
13010 $Str=~s/([^ ])( )([^ ])/$1\@ALONE_SP\@$3/g;
13011 $Str=~s/ /&#160;/g; # &nbsp;
13012 $Str=~s/\@ALONE_SP\@/ /g;
13013 $Str=~s/\n/<br\/>/g;
13014 $Str=~s/\"/&quot;/g;
13015 $Str=~s/\'/&#39;/g;
13016 return $Str;
13017}
13018
13019sub black_name($)
13020{
13021 my $Name = $_[0];
13022 return "<span class='iname_b'>".highLight_Signature($Name)."</span>";
13023}
13024
13025sub highLight_Signature($)
13026{
13027 my $Signature = $_[0];
13028 return highLight_Signature_PPos_Italic($Signature, "", 0, 0, 0);
13029}
13030
13031sub highLight_Signature_Italic_Color($)
13032{
13033 my $Signature = $_[0];
13034 return highLight_Signature_PPos_Italic($Signature, "", 1, 1, 1);
13035}
13036
13037sub separate_symbol($)
13038{
13039 my $Symbol = $_[0];
13040 my ($Name, $Spec, $Ver) = ($Symbol, "", "");
13041 if($Symbol=~/\A([^\@\$\?]+)([\@\$]+)([^\@\$]+)\Z/) {
13042 ($Name, $Spec, $Ver) = ($1, $2, $3);
13043 }
13044 return ($Name, $Spec, $Ver);
13045}
13046
13047sub cut_f_attrs($)
13048{
13049 if($_[0]=~s/(\))((| (const volatile|const|volatile))(| \[static\]))\Z/$1/) {
13050 return $2;
13051 }
13052 return "";
13053}
13054
13055sub highLight_Signature_PPos_Italic($$$$$)
13056{
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040013057 my ($FullSignature, $Param_Pos, $ItalicParams, $ColorParams, $ShowReturn) = @_;
13058 $Param_Pos = "" if(not defined $Param_Pos);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013059 if($CheckObjectsOnly) {
13060 $ItalicParams=$ColorParams=0;
13061 }
13062 my ($Signature, $VersionSpec, $SymbolVersion) = separate_symbol($FullSignature);
13063 my $Return = "";
13064 if($ShowRetVal and $Signature=~s/([^:]):([^:].+?)\Z/$1/g) {
13065 $Return = $2;
13066 }
Andrey Ponomarenko16934472012-03-29 15:37:04 +040013067 my $SCenter = find_center($Signature, "(");
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013068 if(not $SCenter)
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040013069 { # global data
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013070 $Signature = htmlSpecChars($Signature);
13071 $Signature=~s!(\[data\])!<span style='color:Black;font-weight:normal;'>$1</span>!g;
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040013072 $Signature .= (($SymbolVersion)?"<span class='sym_ver'>&#160;$VersionSpec&#160;$SymbolVersion</span>":"");
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013073 if($Return and $ShowReturn) {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040013074 $Signature .= "<span class='sym_p nowrap'> &#160;<b>:</b>&#160;&#160;".htmlSpecChars($Return)."</span>";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013075 }
13076 return $Signature;
13077 }
13078 my ($Begin, $End) = (substr($Signature, 0, $SCenter), "");
13079 $Begin.=" " if($Begin!~/ \Z/);
13080 $End = cut_f_attrs($Signature);
13081 my @Parts = ();
13082 my @SParts = get_s_params($Signature, 1);
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040013083 foreach my $Pos (0 .. $#SParts)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013084 {
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040013085 my $Part = $SParts[$Pos];
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013086 $Part=~s/\A\s+|\s+\Z//g;
13087 my ($Part_Styled, $ParamName) = (htmlSpecChars($Part), "");
13088 if($Part=~/\([\*]+(\w+)\)/i) {
13089 $ParamName = $1;#func-ptr
13090 }
13091 elsif($Part=~/(\w+)[\,\)]*\Z/i) {
13092 $ParamName = $1;
13093 }
13094 if(not $ParamName) {
13095 push(@Parts, $Part_Styled);
13096 next;
13097 }
13098 if($ItalicParams and not $TName_Tid{1}{$Part}
13099 and not $TName_Tid{2}{$Part})
13100 {
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040013101 my $Style = "param";
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040013102 if($Param_Pos ne ""
13103 and $Pos==$Param_Pos) {
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040013104 $Style = "focus_p";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013105 }
13106 elsif($ColorParams) {
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040013107 $Style = "color_p";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013108 }
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040013109 $Part_Styled =~ s!(\W)$ParamName([\,\)]|\Z)!$1<span class=\'$Style\'>$ParamName</span>$2!ig;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013110 }
13111 $Part_Styled=~s/,(\w)/, $1/g;
13112 push(@Parts, $Part_Styled);
13113 }
13114 if(@Parts)
13115 {
13116 foreach my $Num (0 .. $#Parts)
13117 {
13118 if($Num==$#Parts)
13119 { # add ")" to the last parameter
13120 $Parts[$Num] = "<span class='nowrap'>".$Parts[$Num]." )</span>";
13121 }
13122 elsif(length($Parts[$Num])<=45) {
13123 $Parts[$Num] = "<span class='nowrap'>".$Parts[$Num]."</span>";
13124 }
13125 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040013126 $Signature = htmlSpecChars($Begin)."<span class='sym_p'>(&#160;".join(" ", @Parts)."</span>".$End;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013127 }
13128 else {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040013129 $Signature = htmlSpecChars($Begin)."<span class='sym_p'>(&#160;)</span>".$End;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013130 }
13131 if($Return and $ShowReturn) {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040013132 $Signature .= "<span class='sym_p nowrap'> &#160;<b>:</b>&#160;&#160;".htmlSpecChars($Return)."</span>";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013133 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040013134 $Signature=~s!\[\]![&#160;]!g;
13135 $Signature=~s!operator=!operator&#160;=!g;
13136 $Signature=~s!(\[in-charge\]|\[not-in-charge\]|\[in-charge-deleting\]|\[static\])!<span class='sym_kind'>$1</span>!g;
13137 return $Signature.(($SymbolVersion)?"<span class='sym_ver'>&#160;$VersionSpec&#160;$SymbolVersion</span>":"");
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013138}
13139
13140sub get_s_params($$)
13141{
13142 my ($Signature, $Comma) = @_;
13143 my @Parts = ();
Andrey Ponomarenko16934472012-03-29 15:37:04 +040013144 my $ShortName = substr($Signature, 0, find_center($Signature, "("));
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013145 $Signature=~s/\A\Q$ShortName\E\(//g;
13146 cut_f_attrs($Signature);
13147 $Signature=~s/\)\Z//;
13148 return separate_params($Signature, $Comma);
13149}
13150
13151sub separate_params($$)
13152{
13153 my ($Params, $Comma) = @_;
13154 my @Parts = ();
Andrey Ponomarenko16934472012-03-29 15:37:04 +040013155 my %B = ( "("=>0, "<"=>0, ")"=>0, ">"=>0 );
13156 my $Part = 0;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013157 foreach my $Pos (0 .. length($Params) - 1)
13158 {
Andrey Ponomarenko16934472012-03-29 15:37:04 +040013159 my $S = substr($Params, $Pos, 1);
13160 if(defined $B{$S}) {
13161 $B{$S}+=1;
13162 }
13163 if($S eq "," and
13164 $B{"("}==$B{")"} and $B{"<"}==$B{">"})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013165 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040013166 if($Comma)
13167 { # include comma
Andrey Ponomarenko16934472012-03-29 15:37:04 +040013168 $Parts[$Part] .= $S;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013169 }
Andrey Ponomarenko16934472012-03-29 15:37:04 +040013170 $Part += 1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013171 }
13172 else {
Andrey Ponomarenko16934472012-03-29 15:37:04 +040013173 $Parts[$Part] .= $S;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013174 }
13175 }
13176 return @Parts;
13177}
13178
Andrey Ponomarenko16934472012-03-29 15:37:04 +040013179sub find_center($$)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013180{
13181 my ($Sign, $Target) = @_;
Andrey Ponomarenko16934472012-03-29 15:37:04 +040013182 my %B = ( "("=>0, "<"=>0, ")"=>0, ">"=>0 );
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013183 my $Center = 0;
Andrey Ponomarenko16934472012-03-29 15:37:04 +040013184 if($Sign=~s/(operator([^\w\s\(\)]+|\(\)))//g)
13185 { # operators
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013186 $Center+=length($1);
13187 }
13188 foreach my $Pos (0 .. length($Sign)-1)
13189 {
13190 my $S = substr($Sign, $Pos, 1);
13191 if($S eq $Target)
13192 {
13193 if($B{"("}==$B{")"}
13194 and $B{"<"}==$B{">"}) {
13195 return $Center;
13196 }
13197 }
13198 if(defined $B{$S}) {
13199 $B{$S}+=1;
13200 }
13201 $Center+=1;
13202 }
13203 return 0;
13204}
13205
13206sub appendFile($$)
13207{
13208 my ($Path, $Content) = @_;
13209 return if(not $Path);
13210 if(my $Dir = get_dirname($Path)) {
13211 mkpath($Dir);
13212 }
Andrey Ponomarenko16934472012-03-29 15:37:04 +040013213 open(FILE, ">>", $Path) || die ("can't open file \'$Path\': $!\n");
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013214 print FILE $Content;
13215 close(FILE);
13216}
13217
13218sub writeFile($$)
13219{
13220 my ($Path, $Content) = @_;
13221 return if(not $Path);
13222 if(my $Dir = get_dirname($Path)) {
13223 mkpath($Dir);
13224 }
Andrey Ponomarenko16934472012-03-29 15:37:04 +040013225 open(FILE, ">", $Path) || die ("can't open file \'$Path\': $!\n");
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013226 print FILE $Content;
13227 close(FILE);
13228}
13229
13230sub readFile($)
13231{
13232 my $Path = $_[0];
13233 return "" if(not $Path or not -f $Path);
Andrey Ponomarenko16934472012-03-29 15:37:04 +040013234 open(FILE, $Path);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013235 local $/ = undef;
13236 my $Content = <FILE>;
13237 close(FILE);
Andrey Ponomarenko85043792012-05-14 16:48:07 +040013238 if($Path!~/\.(tu|class|abi)\Z/) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013239 $Content=~s/\r/\n/g;
13240 }
13241 return $Content;
13242}
13243
13244sub get_filename($)
13245{ # much faster than basename() from File::Basename module
Andrey Ponomarenko85043792012-05-14 16:48:07 +040013246 if(defined $Cache{"get_filename"}{$_[0]}) {
13247 return $Cache{"get_filename"}{$_[0]};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013248 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +040013249 if($_[0] and $_[0]=~/([^\/\\]+)[\/\\]*\Z/) {
13250 return ($Cache{"get_filename"}{$_[0]}=$1);
13251 }
13252 return ($Cache{"get_filename"}{$_[0]}="");
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013253}
13254
13255sub get_dirname($)
13256{ # much faster than dirname() from File::Basename module
Andrey Ponomarenko85043792012-05-14 16:48:07 +040013257 if(defined $Cache{"get_dirname"}{$_[0]}) {
13258 return $Cache{"get_dirname"}{$_[0]};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013259 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +040013260 if($_[0] and $_[0]=~/\A(.*?)[\/\\]+[^\/\\]*[\/\\]*\Z/) {
13261 return ($Cache{"get_dirname"}{$_[0]}=$1);
13262 }
13263 return ($Cache{"get_dirname"}{$_[0]}="");
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013264}
13265
13266sub separate_path($) {
13267 return (get_dirname($_[0]), get_filename($_[0]));
13268}
13269
13270sub esc($)
13271{
13272 my $Str = $_[0];
13273 $Str=~s/([()\[\]{}$ &'"`;,<>\+])/\\$1/g;
13274 return $Str;
13275}
13276
13277sub readLineNum($$)
13278{
13279 my ($Path, $Num) = @_;
13280 return "" if(not $Path or not -f $Path);
Andrey Ponomarenko16934472012-03-29 15:37:04 +040013281 open(FILE, $Path);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013282 foreach (1 ... $Num) {
13283 <FILE>;
13284 }
13285 my $Line = <FILE>;
13286 close(FILE);
13287 return $Line;
13288}
13289
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040013290sub readAttributes($$)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013291{
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040013292 my ($Path, $Num) = @_;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013293 return () if(not $Path or not -f $Path);
13294 my %Attributes = ();
Andrey Ponomarenko85043792012-05-14 16:48:07 +040013295 if(readLineNum($Path, $Num)=~/<!--\s+(.+)\s+-->/)
13296 {
13297 foreach my $AttrVal (split(/;/, $1))
13298 {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013299 if($AttrVal=~/(.+):(.+)/)
13300 {
13301 my ($Name, $Value) = ($1, $2);
13302 $Attributes{$Name} = $Value;
13303 }
13304 }
13305 }
13306 return \%Attributes;
13307}
13308
13309sub is_abs($) {
13310 return ($_[0]=~/\A(\/|\w+:[\/\\])/);
13311}
13312
13313sub get_abs_path($)
13314{ # abs_path() should NOT be called for absolute inputs
13315 # because it can change them
13316 my $Path = $_[0];
13317 if(not is_abs($Path)) {
13318 $Path = abs_path($Path);
13319 }
13320 return $Path;
13321}
13322
13323sub get_OSgroup()
13324{
13325 $_ = $Config{"osname"};
13326 if(/macos|darwin|rhapsody/i) {
13327 return "macos";
13328 }
13329 elsif(/freebsd|openbsd|netbsd/i) {
13330 return "bsd";
13331 }
13332 elsif(/haiku|beos/i) {
13333 return "beos";
13334 }
13335 elsif(/symbian|epoc/i) {
13336 return "symbian";
13337 }
13338 elsif(/win/i) {
13339 return "windows";
13340 }
13341 else {
13342 return $_;
13343 }
13344}
13345
13346sub getGccVersion($)
13347{
13348 my $LibVersion = $_[0];
13349 if($GCC_VERSION{$LibVersion})
13350 { # dump version
13351 return $GCC_VERSION{$LibVersion};
13352 }
13353 elsif($UsedDump{$LibVersion}{"V"})
13354 { # old-version dumps
13355 return "unknown";
13356 }
13357 my $GccVersion = get_dumpversion($GCC_PATH); # host version
13358 if(not $GccVersion) {
13359 return "unknown";
13360 }
13361 return $GccVersion;
13362}
13363
13364sub showArch($)
13365{
13366 my $Arch = $_[0];
13367 if($Arch eq "arm"
13368 or $Arch eq "mips") {
13369 return uc($Arch);
13370 }
13371 return $Arch;
13372}
13373
13374sub getArch($)
13375{
13376 my $LibVersion = $_[0];
13377 if($CPU_ARCH{$LibVersion})
13378 { # dump version
13379 return $CPU_ARCH{$LibVersion};
13380 }
13381 elsif($UsedDump{$LibVersion}{"V"})
13382 { # old-version dumps
13383 return "unknown";
13384 }
13385 if(defined $Cache{"getArch"}{$LibVersion}) {
13386 return $Cache{"getArch"}{$LibVersion};
13387 }
13388 my $Arch = get_dumpmachine($GCC_PATH); # host version
13389 if(not $Arch) {
13390 return "unknown";
13391 }
13392 if($Arch=~/\A([\w]{3,})(-|\Z)/) {
13393 $Arch = $1;
13394 }
13395 $Arch = "x86" if($Arch=~/\Ai[3-7]86\Z/);
13396 if($OSgroup eq "windows") {
13397 $Arch = "x86" if($Arch=~/win32|mingw32/i);
13398 $Arch = "x86_64" if($Arch=~/win64|mingw64/i);
13399 }
13400 $Cache{"getArch"}{$LibVersion} = $Arch;
13401 return $Arch;
13402}
13403
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040013404sub get_Report_Header($)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013405{
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040013406 my $Level = $_[0];
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013407 my $ArchInfo = " on <span style='color:Blue;'>".showArch(getArch(1))."</span>";
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040013408 if(getArch(1) ne getArch(2)
13409 or getArch(1) eq "unknown"
13410 or $Level eq "Source")
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013411 { # don't show architecture in the header
13412 $ArchInfo="";
13413 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040013414 my $Report_Header = "<h1><span class='nowrap'>";
13415 if($Level eq "Source") {
13416 $Report_Header .= "Source compatibility";
13417 }
13418 elsif($Level eq "Binary") {
13419 $Report_Header .= "Binary compatibility";
13420 }
13421 else {
13422 $Report_Header .= "API compatibility";
13423 }
13424 $Report_Header .= " report for the <span style='color:Blue;'>$TargetLibraryFName</span> $TargetComponent</span>";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013425 $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>";
13426 if($AppPath) {
13427 $Report_Header .= " <span class='nowrap'>&#160;(relating to the portability of application <span style='color:Blue;'>".get_filename($AppPath)."</span>)</span>";
13428 }
13429 $Report_Header .= "</h1>\n";
13430 return $Report_Header;
13431}
13432
13433sub get_SourceInfo()
13434{
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040013435 my ($CheckedHeaders, $CheckedLibs) = ("", "");
13436 if(not $CheckObjectsOnly)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013437 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040013438 $CheckedHeaders = "<a name='Headers'></a><h2>Header Files (".keys(%{$Registered_Headers{1}}).")</h2><hr/>\n";
13439 $CheckedHeaders .= "<div class='h_list'>\n";
13440 foreach my $Header_Path (sort {lc($Registered_Headers{1}{$a}{"Identity"}) cmp lc($Registered_Headers{1}{$b}{"Identity"})} keys(%{$Registered_Headers{1}}))
13441 {
13442 my $Identity = $Registered_Headers{1}{$Header_Path}{"Identity"};
13443 my $Header_Name = get_filename($Identity);
13444 my $Dest_Comment = ($Identity=~/[\/\\]/)?" ($Identity)":"";
13445 $CheckedHeaders .= $Header_Name.$Dest_Comment."<br/>\n";
13446 }
13447 $CheckedHeaders .= "</div>\n";
13448 $CheckedHeaders .= "<br/>$TOP_REF<br/>\n";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013449 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040013450 if(not $CheckHeadersOnly)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013451 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040013452 $CheckedLibs = "<a name='Libs'></a><h2>".ucfirst($SLIB_TYPE)." Libraries (".keys(%{$Library_Symbol{1}}).")</h2><hr/>\n";
13453 $CheckedLibs .= "<div class='lib_list'>\n";
13454 foreach my $Library (sort {lc($a) cmp lc($b)} keys(%{$Library_Symbol{1}}))
13455 {
13456 $Library.=" (.$LIB_EXT)" if($Library!~/\.\w+\Z/);
13457 $CheckedLibs .= $Library."<br/>\n";
13458 }
13459 $CheckedLibs .= "</div>\n";
13460 $CheckedLibs .= "<br/>$TOP_REF<br/>\n";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013461 }
13462 return $CheckedHeaders.$CheckedLibs;
13463}
13464
13465sub get_TypeProblems_Count($$$)
13466{
13467 my ($TypeChanges, $TargetPriority, $Level) = @_;
13468 my $Type_Problems_Count = 0;
13469 foreach my $Type_Name (sort keys(%{$TypeChanges}))
13470 {
13471 my %Kinds_Target = ();
13472 foreach my $Kind (keys(%{$TypeChanges->{$Type_Name}}))
13473 {
13474 foreach my $Location (keys(%{$TypeChanges->{$Type_Name}{$Kind}}))
13475 {
13476 my $Target = $TypeChanges->{$Type_Name}{$Kind}{$Location}{"Target"};
13477 my $Priority = getProblemSeverity($Level, $Kind);
13478 next if($Priority ne $TargetPriority);
13479 if($Kinds_Target{$Kind}{$Target}) {
13480 next;
13481 }
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040013482 if(cmpSeverities($Type_MaxSeverity{$Level}{$Type_Name}{$Kind}{$Target}, $Priority))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013483 { # select a problem with the highest priority
13484 next;
13485 }
13486 $Kinds_Target{$Kind}{$Target} = 1;
13487 $Type_Problems_Count += 1;
13488 }
13489 }
13490 }
13491 return $Type_Problems_Count;
13492}
13493
13494sub get_Summary($)
13495{
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040013496 my $Level = $_[0];
13497 my ($Added, $Removed, $I_Problems_High, $I_Problems_Medium, $I_Problems_Low, $T_Problems_High,
13498 $C_Problems_Low, $T_Problems_Medium, $T_Problems_Low, $I_Other, $T_Other) = (0,0,0,0,0,0,0,0,0,0,0);
13499 %{$RESULT{$Level}} = (
13500 "Problems"=>0,
13501 "Warnings"=>0,
13502 "Affected"=>0 );
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013503 # check rules
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040013504 foreach my $Interface (sort keys(%{$CompatProblems{$Level}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013505 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040013506 foreach my $Kind (keys(%{$CompatProblems{$Level}{$Interface}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013507 {
13508 if(not defined $CompatRules{$Level}{$Kind})
13509 { # unknown rule
13510 if(not $UnknownRules{$Level}{$Kind})
13511 { # only one warning
13512 printMsg("WARNING", "unknown rule \"$Kind\" (\"$Level\")");
13513 $UnknownRules{$Level}{$Kind}=1;
13514 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040013515 delete($CompatProblems{$Level}{$Interface}{$Kind});
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013516 }
13517 }
13518 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040013519 foreach my $Interface (sort keys(%{$CompatProblems{$Level}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013520 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040013521 foreach my $Kind (sort keys(%{$CompatProblems{$Level}{$Interface}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013522 {
13523 if($CompatRules{$Level}{$Kind}{"Kind"} eq "Symbols")
13524 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040013525 foreach my $Location (sort keys(%{$CompatProblems{$Level}{$Interface}{$Kind}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013526 {
13527 my $Priority = getProblemSeverity($Level, $Kind);
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040013528 if($Kind eq "Added_Symbol") {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013529 $Added += 1;
13530 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040013531 elsif($Kind eq "Removed_Symbol")
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013532 {
13533 $Removed += 1;
13534 $TotalAffected{$Level}{$Interface} = $Priority;
13535 }
13536 else
13537 {
13538 if($Priority eq "Safe") {
13539 $I_Other += 1;
13540 }
13541 elsif($Priority eq "High") {
13542 $I_Problems_High += 1;
13543 }
13544 elsif($Priority eq "Medium") {
13545 $I_Problems_Medium += 1;
13546 }
13547 elsif($Priority eq "Low") {
13548 $I_Problems_Low += 1;
13549 }
13550 if(($Priority ne "Low" or $StrictCompat)
13551 and $Priority ne "Safe") {
13552 $TotalAffected{$Level}{$Interface} = $Priority;
13553 }
13554 }
13555 }
13556 }
13557 }
13558 }
13559 my %TypeChanges = ();
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040013560 foreach my $Interface (sort keys(%{$CompatProblems{$Level}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013561 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040013562 foreach my $Kind (keys(%{$CompatProblems{$Level}{$Interface}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013563 {
13564 if($CompatRules{$Level}{$Kind}{"Kind"} eq "Types")
13565 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040013566 foreach my $Location (sort {cmp_locations($b, $a)} sort keys(%{$CompatProblems{$Level}{$Interface}{$Kind}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013567 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040013568 my $Type_Name = $CompatProblems{$Level}{$Interface}{$Kind}{$Location}{"Type_Name"};
13569 my $Target = $CompatProblems{$Level}{$Interface}{$Kind}{$Location}{"Target"};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013570 my $Priority = getProblemSeverity($Level, $Kind);
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040013571 if(cmpSeverities($Type_MaxSeverity{$Level}{$Type_Name}{$Kind}{$Target}, $Priority))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013572 { # select a problem with the highest priority
13573 next;
13574 }
13575 if(($Priority ne "Low" or $StrictCompat)
13576 and $Priority ne "Safe") {
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040013577 $TotalAffected{$Level}{$Interface} = maxSeverity($TotalAffected{$Level}{$Interface}, $Priority);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013578 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040013579 %{$TypeChanges{$Type_Name}{$Kind}{$Location}} = %{$CompatProblems{$Level}{$Interface}{$Kind}{$Location}};
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040013580 $Type_MaxSeverity{$Level}{$Type_Name}{$Kind}{$Target} = maxSeverity($Type_MaxSeverity{$Level}{$Type_Name}{$Kind}{$Target}, $Priority);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013581 }
13582 }
13583 }
13584 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040013585
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013586 $T_Problems_High = get_TypeProblems_Count(\%TypeChanges, "High", $Level);
13587 $T_Problems_Medium = get_TypeProblems_Count(\%TypeChanges, "Medium", $Level);
13588 $T_Problems_Low = get_TypeProblems_Count(\%TypeChanges, "Low", $Level);
13589 $T_Other = get_TypeProblems_Count(\%TypeChanges, "Safe", $Level);
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040013590
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013591 if($CheckObjectsOnly)
13592 { # only removed exported symbols
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040013593 $RESULT{$Level}{"Affected"} = $Removed*100/keys(%{$Symbol_Library{1}});
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013594 }
13595 else
13596 { # changed and removed public symbols
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040013597 my $SCount = keys(%{$CheckedSymbols{$Level}});
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013598 if($ExtendedCheck)
13599 { # don't count external_func_0 for constants
13600 $SCount-=1;
13601 }
13602 if($SCount)
13603 {
13604 my %Weight = (
13605 "High" => 100,
13606 "Medium" => 50,
13607 "Low" => 25
13608 );
13609 foreach (keys(%{$TotalAffected{$Level}})) {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040013610 $RESULT{$Level}{"Affected"}+=$Weight{$TotalAffected{$Level}{$_}};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013611 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040013612 $RESULT{$Level}{"Affected"} = $RESULT{$Level}{"Affected"}/$SCount;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013613 }
13614 else {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040013615 $RESULT{$Level}{"Affected"} = 0;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013616 }
13617 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040013618 $RESULT{$Level}{"Affected"} = show_number($RESULT{$Level}{"Affected"});
13619 if($RESULT{$Level}{"Affected"}>=100) {
13620 $RESULT{$Level}{"Affected"} = 100;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013621 }
13622
Andrey Ponomarenko85043792012-05-14 16:48:07 +040013623 $RESULT{$Level}{"Problems"} += $Removed;
13624 $RESULT{$Level}{"Problems"} += $T_Problems_High + $I_Problems_High;
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040013625 $RESULT{$Level}{"Problems"} += $T_Problems_Medium + $I_Problems_Medium;
Andrey Ponomarenko85043792012-05-14 16:48:07 +040013626 if($StrictCompat) {
13627 $RESULT{$Level}{"Problems"} += $T_Problems_Low + $I_Problems_Low;
13628 }
13629 else {
13630 $RESULT{$Level}{"Warnings"} += $T_Problems_Low + $I_Problems_Low;
13631 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013632
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040013633 if($C_Problems_Low = keys(%{$ProblemsWithConstants{$Level}}))
13634 {
Andrey Ponomarenko85043792012-05-14 16:48:07 +040013635 if(defined $CompatRules{$Level}{"Changed_Constant"})
13636 {
13637 if($StrictCompat) {
13638 $RESULT{$Level}{"Problems"} += $C_Problems_Low;
13639 }
13640 else {
13641 $RESULT{$Level}{"Warnings"} += $C_Problems_Low;
13642 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040013643 }
13644 else
13645 {
13646 printMsg("WARNING", "unknown rule \"Changed_Constant\" (\"$Level\")");
13647 $C_Problems_Low = 0;
13648 }
13649 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +040013650 if($CheckImpl and $Level eq "Binary")
13651 {
13652 if($StrictCompat) {
13653 $RESULT{$Level}{"Problems"} += keys(%ImplProblems);
13654 }
13655 else {
13656 $RESULT{$Level}{"Warnings"} += keys(%ImplProblems);
13657 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040013658 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +040013659 if($RESULT{$Level}{"Problems"}
13660 and $RESULT{$Level}{"Affected"}) {
13661 $RESULT{$Level}{"Verdict"} = "incompatible";
13662 }
13663 else {
13664 $RESULT{$Level}{"Verdict"} = "compatible";
13665 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040013666
13667 my $TotalTypes = keys(%{$CheckedTypes{$Level}});
13668 if(not $TotalTypes)
13669 { # list all the types
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013670 $TotalTypes = keys(%{$TName_Tid{1}});
13671 }
13672
13673 my ($Arch1, $Arch2) = (getArch(1), getArch(2));
13674 my ($GccV1, $GccV2) = (getGccVersion(1), getGccVersion(2));
13675
13676 my ($TestInfo, $TestResults, $Problem_Summary) = ();
13677
13678 if($ReportFormat eq "xml")
13679 { # XML
13680 # test info
13681 $TestInfo .= " <library>$TargetLibraryName</library>\n";
13682 $TestInfo .= " <version1>\n";
13683 $TestInfo .= " <number>".$Descriptor{1}{"Version"}."</number>\n";
13684 $TestInfo .= " <architecture>$Arch1</architecture>\n";
13685 $TestInfo .= " <gcc>$GccV1</gcc>\n";
13686 $TestInfo .= " </version1>\n";
13687
13688 $TestInfo .= " <version2>\n";
13689 $TestInfo .= " <number>".$Descriptor{2}{"Version"}."</number>\n";
13690 $TestInfo .= " <architecture>$Arch2</architecture>\n";
13691 $TestInfo .= " <gcc>$GccV2</gcc>\n";
13692 $TestInfo .= " </version2>\n";
13693 $TestInfo = "<test_info>\n".$TestInfo."</test_info>\n\n";
13694
13695 # test results
13696 $TestResults .= " <headers>\n";
13697 foreach my $Name (sort {lc($Registered_Headers{1}{$a}{"Identity"}) cmp lc($Registered_Headers{1}{$b}{"Identity"})} keys(%{$Registered_Headers{1}}))
13698 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040013699 my $Identity = $Registered_Headers{1}{$Name}{"Identity"};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013700 my $Comment = ($Identity=~/[\/\\]/)?" ($Identity)":"";
13701 $TestResults .= " <name>".get_filename($Name).$Comment."</name>\n";
13702 }
13703 $TestResults .= " </headers>\n";
13704
13705 $TestResults .= " <libs>\n";
13706 foreach my $Library (sort {lc($a) cmp lc($b)} keys(%{$Library_Symbol{1}}))
13707 {
13708 $Library.=" (.$LIB_EXT)" if($Library!~/\.\w+\Z/);
13709 $TestResults .= " <name>$Library</name>\n";
13710 }
13711 $TestResults .= " </libs>\n";
13712
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040013713 $TestResults .= " <symbols>".(keys(%{$CheckedSymbols{$Level}}) - keys(%ExtendedSymbols))."</symbols>\n";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013714 $TestResults .= " <types>".$TotalTypes."</types>\n";
13715
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040013716 $TestResults .= " <verdict>".$RESULT{$Level}{"Verdict"}."</verdict>\n";
13717 $TestResults .= " <affected>".$RESULT{$Level}{"Affected"}."</affected>\n";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013718 $TestResults = "<test_results>\n".$TestResults."</test_results>\n\n";
13719
13720 # problem summary
13721 $Problem_Summary .= " <added_symbols>".$Added."</added_symbols>\n";
13722 $Problem_Summary .= " <removed_symbols>".$Removed."</removed_symbols>\n";
13723
13724 $Problem_Summary .= " <problems_with_types>\n";
13725 $Problem_Summary .= " <high>$T_Problems_High</high>\n";
13726 $Problem_Summary .= " <medium>$T_Problems_Medium</medium>\n";
13727 $Problem_Summary .= " <low>$T_Problems_Low</low>\n";
13728 $Problem_Summary .= " <safe>$T_Other</safe>\n";
13729 $Problem_Summary .= " </problems_with_types>\n";
13730
13731 $Problem_Summary .= " <problems_with_symbols>\n";
13732 $Problem_Summary .= " <high>$I_Problems_High</high>\n";
13733 $Problem_Summary .= " <medium>$I_Problems_Medium</medium>\n";
13734 $Problem_Summary .= " <low>$I_Problems_Low</low>\n";
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040013735 $Problem_Summary .= " <safe>$I_Other</safe>\n";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013736 $Problem_Summary .= " </problems_with_symbols>\n";
13737
13738 $Problem_Summary .= " <problems_with_constants>\n";
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040013739 $Problem_Summary .= " <low>$C_Problems_Low</low>\n";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013740 $Problem_Summary .= " </problems_with_constants>\n";
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040013741 if($CheckImpl and $Level eq "Binary")
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013742 {
13743 $Problem_Summary .= " <impl>\n";
13744 $Problem_Summary .= " <low>".keys(%ImplProblems)."</low>\n";
13745 $Problem_Summary .= " </impl>\n";
13746 }
13747 $Problem_Summary = "<problem_summary>\n".$Problem_Summary."</problem_summary>\n\n";
13748
13749 return ($TestInfo.$TestResults.$Problem_Summary, "");
13750 }
13751 else
13752 { # HTML
13753 # test info
13754 $TestInfo = "<h2>Test Info</h2><hr/>\n";
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040013755 $TestInfo .= "<table class='summary'>\n";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013756 $TestInfo .= "<tr><th>".ucfirst($TargetComponent)." Name</th><td>$TargetLibraryFName</td></tr>\n";
13757
13758 my (@VInf1, @VInf2, $AddTestInfo) = ();
13759 if($Arch1 ne "unknown"
13760 and $Arch2 ne "unknown")
13761 { # CPU arch
13762 if($Arch1 eq $Arch2)
13763 { # go to the separate section
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040013764 $AddTestInfo .= "<tr><th>CPU Type</th><td>".showArch($Arch1)."</td></tr>\n";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013765 }
13766 else
13767 { # go to the version number
13768 push(@VInf1, showArch($Arch1));
13769 push(@VInf2, showArch($Arch2));
13770 }
13771 }
13772 if($GccV1 ne "unknown"
13773 and $GccV2 ne "unknown"
13774 and $OStarget ne "windows")
13775 { # GCC version
13776 if($GccV1 eq $GccV2)
13777 { # go to the separate section
13778 $AddTestInfo .= "<tr><th>GCC Version</th><td>$GccV1</td></tr>\n";
13779 }
13780 else
13781 { # go to the version number
13782 push(@VInf1, "gcc ".$GccV1);
13783 push(@VInf2, "gcc ".$GccV2);
13784 }
13785 }
13786 # show long version names with GCC version and CPU architecture name (if different)
13787 $TestInfo .= "<tr><th>Version #1</th><td>".$Descriptor{1}{"Version"}.(@VInf1?" (".join(", ", reverse(@VInf1)).")":"")."</td></tr>\n";
13788 $TestInfo .= "<tr><th>Version #2</th><td>".$Descriptor{2}{"Version"}.(@VInf2?" (".join(", ", reverse(@VInf2)).")":"")."</td></tr>\n";
13789 $TestInfo .= $AddTestInfo;
13790 #if($COMMON_LANGUAGE{1}) {
13791 # $TestInfo .= "<tr><th>Language</th><td>".$COMMON_LANGUAGE{1}."</td></tr>\n";
13792 #}
13793 if($ExtendedCheck) {
13794 $TestInfo .= "<tr><th>Mode</th><td>Extended</td></tr>\n";
13795 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040013796 if($JoinReport)
13797 {
13798 if($Level eq "Binary") {
Andrey Ponomarenko16934472012-03-29 15:37:04 +040013799 $TestInfo .= "<tr><th>Subject</th><td width='150px'>Binary Compatibility</td></tr>\n"; # Run-time
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040013800 }
13801 if($Level eq "Source") {
Andrey Ponomarenko16934472012-03-29 15:37:04 +040013802 $TestInfo .= "<tr><th>Subject</th><td width='150px'>Source Compatibility</td></tr>\n"; # Build-time
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040013803 }
13804 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013805 $TestInfo .= "</table>\n";
13806
13807 # test results
13808 $TestResults = "<h2>Test Results</h2><hr/>\n";
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040013809 $TestResults .= "<table class='summary'>";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013810
13811 my $Headers_Link = "0";
13812 $Headers_Link = "<a href='#Headers' style='color:Blue;'>".keys(%{$Registered_Headers{1}})."</a>" if(keys(%{$Registered_Headers{1}})>0);
13813 $TestResults .= "<tr><th>Total Header Files</th><td>".($CheckObjectsOnly?"0&#160;(not&#160;analyzed)":$Headers_Link)."</td></tr>\n";
13814
13815 if(not $ExtendedCheck)
13816 {
13817 my $Libs_Link = "0";
13818 $Libs_Link = "<a href='#Libs' style='color:Blue;'>".keys(%{$Library_Symbol{1}})."</a>" if(keys(%{$Library_Symbol{1}})>0);
13819 $TestResults .= "<tr><th>Total ".ucfirst($SLIB_TYPE)." Libraries</th><td>".($CheckHeadersOnly?"0&#160;(not&#160;analyzed)":$Libs_Link)."</td></tr>\n";
13820 }
13821
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040013822 $TestResults .= "<tr><th>Total Symbols / Types</th><td>".(keys(%{$CheckedSymbols{$Level}}) - keys(%ExtendedSymbols))." / ".$TotalTypes."</td></tr>\n";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013823
Andrey Ponomarenko85043792012-05-14 16:48:07 +040013824 my $META_DATA = "verdict:".$RESULT{$Level}{"Verdict"}.";";
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040013825 if($JoinReport) {
13826 $META_DATA = "kind:".lc($Level).";".$META_DATA;
13827 }
Andrey Ponomarenko16934472012-03-29 15:37:04 +040013828 $TestResults .= "<tr><th>Verdict</th>";
Andrey Ponomarenko85043792012-05-14 16:48:07 +040013829 if($RESULT{$Level}{"Verdict"} eq "incompatible") {
Andrey Ponomarenko16934472012-03-29 15:37:04 +040013830 $TestResults .= "<td><span style='color:Red;'><b>Incompatible<br/>(".$RESULT{$Level}{"Affected"}."%)</b></span></td>";
13831 }
13832 else {
13833 $TestResults .= "<td><span style='color:Green;'><b>Compatible</b></span></td>";
13834 }
13835 $TestResults .= "</tr>\n";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013836 $TestResults .= "</table>\n";
13837
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040013838 $META_DATA .= "affected:".$RESULT{$Level}{"Affected"}.";";# in percents
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013839 # problem summary
13840 $Problem_Summary = "<h2>Problem Summary</h2><hr/>\n";
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040013841 $Problem_Summary .= "<table class='summary'>";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013842 $Problem_Summary .= "<tr><th></th><th style='text-align:center;'>Severity</th><th style='text-align:center;'>Count</th></tr>";
13843
13844 my $Added_Link = "0";
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040013845 if($Added>0)
13846 {
13847 if($JoinReport) {
13848 $Added_Link = "<a href='#".$Level."_Added' style='color:Blue;'>$Added</a>";
13849 }
13850 else {
13851 $Added_Link = "<a href='#Added' style='color:Blue;'>$Added</a>";
13852 }
13853 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013854 $META_DATA .= "added:$Added;";
Andrey Ponomarenko16934472012-03-29 15:37:04 +040013855 $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 +040013856
13857 my $Removed_Link = "0";
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040013858 if($Removed>0)
13859 {
13860 if($JoinReport) {
13861 $Removed_Link = "<a href='#".$Level."_Removed' style='color:Blue;'>$Removed</a>"
13862 }
13863 else {
13864 $Removed_Link = "<a href='#Removed' style='color:Blue;'>$Removed</a>"
13865 }
13866 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013867 $META_DATA .= "removed:$Removed;";
Andrey Ponomarenko16934472012-03-29 15:37:04 +040013868 $Problem_Summary .= "<tr><th>Removed Symbols</th>";
13869 $Problem_Summary .= "<td>High</td><td".getStyle("I", "R", $Removed).">$Removed_Link</td></tr>\n";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013870
13871 my $TH_Link = "0";
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040013872 $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 +040013873 $TH_Link = "n/a" if($CheckObjectsOnly);
13874 $META_DATA .= "type_problems_high:$T_Problems_High;";
Andrey Ponomarenko16934472012-03-29 15:37:04 +040013875 $Problem_Summary .= "<tr><th rowspan='3'>Problems with<br/>Data Types</th>";
13876 $Problem_Summary .= "<td>High</td><td".getStyle("T", "H", $T_Problems_High).">$TH_Link</td></tr>\n";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013877
13878 my $TM_Link = "0";
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040013879 $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 +040013880 $TM_Link = "n/a" if($CheckObjectsOnly);
13881 $META_DATA .= "type_problems_medium:$T_Problems_Medium;";
Andrey Ponomarenko16934472012-03-29 15:37:04 +040013882 $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 +040013883
13884 my $TL_Link = "0";
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040013885 $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 +040013886 $TL_Link = "n/a" if($CheckObjectsOnly);
13887 $META_DATA .= "type_problems_low:$T_Problems_Low;";
Andrey Ponomarenko16934472012-03-29 15:37:04 +040013888 $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 +040013889
13890 my $IH_Link = "0";
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040013891 $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 +040013892 $IH_Link = "n/a" if($CheckObjectsOnly);
13893 $META_DATA .= "interface_problems_high:$I_Problems_High;";
Andrey Ponomarenko16934472012-03-29 15:37:04 +040013894 $Problem_Summary .= "<tr><th rowspan='3'>Problems with<br/>Symbols</th>";
13895 $Problem_Summary .= "<td>High</td><td".getStyle("I", "H", $I_Problems_High).">$IH_Link</td></tr>\n";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013896
13897 my $IM_Link = "0";
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040013898 $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 +040013899 $IM_Link = "n/a" if($CheckObjectsOnly);
13900 $META_DATA .= "interface_problems_medium:$I_Problems_Medium;";
Andrey Ponomarenko16934472012-03-29 15:37:04 +040013901 $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 +040013902
13903 my $IL_Link = "0";
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040013904 $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 +040013905 $IL_Link = "n/a" if($CheckObjectsOnly);
13906 $META_DATA .= "interface_problems_low:$I_Problems_Low;";
Andrey Ponomarenko16934472012-03-29 15:37:04 +040013907 $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 +040013908
13909 my $ChangedConstants_Link = "0";
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040013910 if(keys(%{$CheckedSymbols{$Level}}) and $C_Problems_Low)
13911 {
13912 if($JoinReport) {
13913 $ChangedConstants_Link = "<a href='#".$Level."_Changed_Constants' style='color:Blue;'>$C_Problems_Low</a>";
13914 }
13915 else {
13916 $ChangedConstants_Link = "<a href='#Changed_Constants' style='color:Blue;'>$C_Problems_Low</a>";
13917 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013918 }
13919 $ChangedConstants_Link = "n/a" if($CheckObjectsOnly);
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040013920 $META_DATA .= "changed_constants:$C_Problems_Low;";
Andrey Ponomarenko16934472012-03-29 15:37:04 +040013921 $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 +040013922
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040013923 if($CheckImpl and $Level eq "Binary")
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013924 {
13925 my $ChangedImpl_Link = "0";
13926 $ChangedImpl_Link = "<a href='#Changed_Implementation' style='color:Blue;'>".keys(%ImplProblems)."</a>" if(keys(%ImplProblems)>0);
13927 $ChangedImpl_Link = "n/a" if($CheckHeadersOnly);
13928 $META_DATA .= "changed_implementation:".keys(%ImplProblems).";";
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040013929 $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 +040013930 }
13931 # Safe Changes
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040013932 if($T_Other and not $CheckObjectsOnly)
13933 {
13934 my $TS_Link = "<a href='#".get_Anchor("Type", $Level, "Safe")."' style='color:Blue;'>$T_Other</a>";
Andrey Ponomarenko16934472012-03-29 15:37:04 +040013935 $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 +040013936 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040013937
13938 if($I_Other and not $CheckObjectsOnly)
13939 {
13940 my $IS_Link = "<a href='#".get_Anchor("Symbol", $Level, "Safe")."' style='color:Blue;'>$I_Other</a>";
Andrey Ponomarenko16934472012-03-29 15:37:04 +040013941 $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 +040013942 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013943
13944 $META_DATA .= "tool_version:$TOOL_VERSION";
13945 $Problem_Summary .= "</table>\n";
Andrey Ponomarenko16934472012-03-29 15:37:04 +040013946 # $TestInfo = getLegend().$TestInfo;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013947 return ($TestInfo.$TestResults.$Problem_Summary, $META_DATA);
13948 }
13949}
13950
Andrey Ponomarenko16934472012-03-29 15:37:04 +040013951sub getStyle($$$)
13952{
13953 my ($Subj, $Act, $Num) = @_;
13954 my %Style = (
13955 "A"=>"new",
13956 "R"=>"failed",
13957 "S"=>"passed",
13958 "L"=>"warning",
13959 "M"=>"failed",
13960 "H"=>"failed"
13961 );
13962 if($Num>0) {
13963 return " class='".$Style{$Act}."'";
13964 }
13965 return "";
13966}
13967
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013968sub show_number($)
13969{
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040013970 if($_[0])
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013971 {
Andrey Ponomarenko16934472012-03-29 15:37:04 +040013972 my $Num = cut_off_number($_[0], 2, 0);
13973 if($Num eq "0")
13974 {
13975 foreach my $P (3 .. 7)
13976 {
13977 $Num = cut_off_number($_[0], $P, 1);
13978 if($Num ne "0") {
13979 last;
13980 }
13981 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013982 }
13983 if($Num eq "0") {
13984 $Num = $_[0];
13985 }
13986 return $Num;
13987 }
13988 return $_[0];
13989}
13990
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040013991sub cut_off_number($$$)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013992{
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040013993 my ($num, $digs_to_cut, $z) = @_;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013994 if($num!~/\./)
13995 {
13996 $num .= ".";
13997 foreach (1 .. $digs_to_cut-1) {
13998 $num .= "0";
13999 }
14000 }
14001 elsif($num=~/\.(.+)\Z/ and length($1)<$digs_to_cut-1)
14002 {
14003 foreach (1 .. $digs_to_cut - 1 - length($1)) {
14004 $num .= "0";
14005 }
14006 }
14007 elsif($num=~/\d+\.(\d){$digs_to_cut,}/) {
14008 $num=sprintf("%.".($digs_to_cut-1)."f", $num);
14009 }
14010 $num=~s/\.[0]+\Z//g;
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014011 if($z) {
14012 $num=~s/(\.[1-9]+)[0]+\Z/$1/g;
14013 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014014 return $num;
14015}
14016
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014017sub get_Report_ChangedConstants($)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014018{
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014019 my $Level = $_[0];
Andrey Ponomarenko16934472012-03-29 15:37:04 +040014020 my $CHANGED_CONSTANTS = "";
14021 my %ReportMap = ();
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014022 foreach my $Constant (keys(%{$ProblemsWithConstants{$Level}})) {
Andrey Ponomarenko16934472012-03-29 15:37:04 +040014023 $ReportMap{$Constants{1}{$Constant}{"Header"}}{$Constant} = 1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014024 }
14025 my $Kind = "Changed_Constant";
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014026 if(not defined $CompatRules{$Level}{$Kind}) {
14027 return "";
14028 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014029 if($ReportFormat eq "xml")
14030 { # XML
Andrey Ponomarenko16934472012-03-29 15:37:04 +040014031 foreach my $HeaderName (sort {lc($a) cmp lc($b)} keys(%ReportMap))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014032 {
14033 $CHANGED_CONSTANTS .= " <header name=\"$HeaderName\">\n";
Andrey Ponomarenko16934472012-03-29 15:37:04 +040014034 foreach my $Constant (sort {lc($a) cmp lc($b)} keys(%{$ReportMap{$HeaderName}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014035 {
14036 $CHANGED_CONSTANTS .= " <constant name=\"$Constant\">\n";
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014037 my $Change = $CompatRules{$Level}{$Kind}{"Change"};
14038 my $Effect = $CompatRules{$Level}{$Kind}{"Effect"};
14039 my $Overcome = $CompatRules{$Level}{$Kind}{"Overcome"};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014040 $CHANGED_CONSTANTS .= " <problem id=\"$Kind\">\n";
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014041 $CHANGED_CONSTANTS .= " <change".getXmlParams($Change, $ProblemsWithConstants{$Level}{$Constant}).">$Change</change>\n";
14042 $CHANGED_CONSTANTS .= " <effect".getXmlParams($Effect, $ProblemsWithConstants{$Level}{$Constant}).">$Effect</effect>\n";
14043 $CHANGED_CONSTANTS .= " <overcome".getXmlParams($Overcome, $ProblemsWithConstants{$Level}{$Constant}).">$Overcome</overcome>\n";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014044 $CHANGED_CONSTANTS .= " </problem>\n";
14045 $CHANGED_CONSTANTS .= " </constant>\n";
14046 }
14047 $CHANGED_CONSTANTS .= " </header>\n";
14048 }
14049 $CHANGED_CONSTANTS = "<problems_with_constants severity=\"Low\">\n".$CHANGED_CONSTANTS."</problems_with_constants>\n\n";
14050 }
14051 else
14052 { # HTML
14053 my $Number = 0;
Andrey Ponomarenko16934472012-03-29 15:37:04 +040014054 foreach my $HeaderName (sort {lc($a) cmp lc($b)} keys(%ReportMap))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014055 {
14056 $CHANGED_CONSTANTS .= "<span class='h_name'>$HeaderName</span><br/>\n";
Andrey Ponomarenko16934472012-03-29 15:37:04 +040014057 foreach my $Name (sort {lc($a) cmp lc($b)} keys(%{$ReportMap{$HeaderName}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014058 {
14059 $Number += 1;
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014060 my $Change = applyMacroses($Level, $Kind, $CompatRules{$Level}{$Kind}{"Change"}, $ProblemsWithConstants{$Level}{$Name});
14061 my $Effect = $CompatRules{$Level}{$Kind}{"Effect"};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014062 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 +040014063 $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 +040014064 $Report = $ContentSpanStart."<span class='extendable'>[+]</span> ".$Name.$ContentSpanEnd."<br/>\n".$Report;
14065 $CHANGED_CONSTANTS .= insertIDs($Report);
14066 }
14067 $CHANGED_CONSTANTS .= "<br/>\n";
14068 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014069 if($CHANGED_CONSTANTS)
14070 {
14071 my $Anchor = "<a name='Changed_Constants'></a>";
14072 if($JoinReport) {
14073 $Anchor = "<a name='".$Level."_Changed_Constants'></a>";
14074 }
14075 $CHANGED_CONSTANTS = $Anchor."<h2>Problems with Constants ($Number)</h2><hr/>\n".$CHANGED_CONSTANTS.$TOP_REF."<br/>\n";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014076 }
14077 }
14078 return $CHANGED_CONSTANTS;
14079}
14080
14081sub get_Report_Impl()
14082{
Andrey Ponomarenko16934472012-03-29 15:37:04 +040014083 my $CHANGED_IMPLEMENTATION = "";
14084 my %ReportMap = ();
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014085 foreach my $Interface (sort keys(%ImplProblems))
14086 {
14087 my $HeaderName = $CompleteSignature{1}{$Interface}{"Header"};
14088 my $DyLib = $Symbol_Library{1}{$Interface};
Andrey Ponomarenko16934472012-03-29 15:37:04 +040014089 $ReportMap{$HeaderName}{$DyLib}{$Interface} = 1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014090 }
14091 my $Changed_Number = 0;
Andrey Ponomarenko16934472012-03-29 15:37:04 +040014092 foreach my $HeaderName (sort {lc($a) cmp lc($b)} keys(%ReportMap))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014093 {
Andrey Ponomarenko16934472012-03-29 15:37:04 +040014094 foreach my $DyLib (sort {lc($a) cmp lc($b)} keys(%{$ReportMap{$HeaderName}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014095 {
14096 my $FDyLib=$DyLib.($DyLib!~/\.\w+\Z/?" (.$LIB_EXT)":"");
14097 if($HeaderName) {
14098 $CHANGED_IMPLEMENTATION .= "<span class='h_name'>$HeaderName</span>, <span class='lib_name'>$FDyLib</span><br/>\n";
14099 }
14100 else {
14101 $CHANGED_IMPLEMENTATION .= "<span class='lib_name'>$DyLib</span><br/>\n";
14102 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014103 my %NameSpaceSymbols = ();
Andrey Ponomarenko16934472012-03-29 15:37:04 +040014104 foreach my $Interface (keys(%{$ReportMap{$HeaderName}{$DyLib}})) {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014105 $NameSpaceSymbols{get_IntNameSpace($Interface, 2)}{$Interface} = 1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014106 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014107 foreach my $NameSpace (sort keys(%NameSpaceSymbols))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014108 {
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040014109 $CHANGED_IMPLEMENTATION .= ($NameSpace)?"<span class='ns_title'>namespace</span> <span class='ns'>$NameSpace</span><br/>\n":"";
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014110 my @SortedInterfaces = sort {lc(get_Signature($a, 1)) cmp lc(get_Signature($b, 1))} keys(%{$NameSpaceSymbols{$NameSpace}});
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014111 foreach my $Interface (@SortedInterfaces)
14112 {
14113 $Changed_Number += 1;
14114 my $Signature = get_Signature($Interface, 1);
14115 if($NameSpace) {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040014116 $Signature=~s/\b\Q$NameSpace\E::\b//g;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014117 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014118 $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 +040014119 }
14120 }
14121 $CHANGED_IMPLEMENTATION .= "<br/>\n";
14122 }
14123 }
14124 if($CHANGED_IMPLEMENTATION) {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014125 $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 +040014126 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +040014127
14128 # clean memory
14129 %ImplProblems = ();
14130
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014131 return $CHANGED_IMPLEMENTATION;
14132}
14133
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014134sub getTitle($$$)
14135{
14136 my ($Header, $Library, $NameSpace) = @_;
14137 my $Title = "";
14138 if($Library and $Library!~/\.\w+\Z/) {
14139 $Library .= " (.$LIB_EXT)";
14140 }
14141 if($Header and $Library)
14142 {
14143 $Title .= "<span class='h_name'>$Header</span>";
14144 $Title .= ", <span class='lib_name'>$Library</span><br/>\n";
14145 }
14146 elsif($Library) {
14147 $Title .= "<span class='lib_name'>$Library</span><br/>\n";
14148 }
14149 elsif($Header) {
14150 $Title .= "<span class='h_name'>$Header</span><br/>\n";
14151 }
14152 if($NameSpace) {
14153 $Title .= "<span class='ns_title'>namespace</span> <span class='ns'>$NameSpace</span><br/>\n";
14154 }
14155 return $Title;
14156}
14157
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014158sub get_Report_Added($)
14159{
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014160 my $Level = $_[0];
Andrey Ponomarenko16934472012-03-29 15:37:04 +040014161 my $ADDED_INTERFACES = "";
14162 my %ReportMap = ();
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014163 foreach my $Interface (sort keys(%{$CompatProblems{$Level}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014164 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014165 foreach my $Kind (sort keys(%{$CompatProblems{$Level}{$Interface}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014166 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014167 if($Kind eq "Added_Symbol")
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014168 {
14169 my $HeaderName = $CompleteSignature{2}{$Interface}{"Header"};
14170 my $DyLib = $Symbol_Library{2}{$Interface};
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014171 if($Level eq "Source" and $ReportFormat eq "html")
14172 { # do not show library name in HTML report
14173 $DyLib = "";
14174 }
14175 $ReportMap{$HeaderName}{$DyLib}{$Interface} = 1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014176 }
14177 }
14178 }
14179 if($ReportFormat eq "xml")
14180 { # XML
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014181 foreach my $HeaderName (sort {lc($a) cmp lc($b)} keys(%ReportMap))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014182 {
14183 $ADDED_INTERFACES .= " <header name=\"$HeaderName\">\n";
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014184 foreach my $DyLib (sort {lc($a) cmp lc($b)} keys(%{$ReportMap{$HeaderName}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014185 {
14186 $ADDED_INTERFACES .= " <library name=\"$DyLib\">\n";
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014187 foreach my $Interface (keys(%{$ReportMap{$HeaderName}{$DyLib}})) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014188 $ADDED_INTERFACES .= " <name>$Interface</name>\n";
14189 }
14190 $ADDED_INTERFACES .= " </library>\n";
14191 }
14192 $ADDED_INTERFACES .= " </header>\n";
14193 }
14194 $ADDED_INTERFACES = "<added_symbols>\n".$ADDED_INTERFACES."</added_symbols>\n\n";
14195 }
14196 else
14197 { # HTML
14198 my $Added_Number = 0;
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014199 foreach my $HeaderName (sort {lc($a) cmp lc($b)} keys(%ReportMap))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014200 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014201 foreach my $DyLib (sort {lc($a) cmp lc($b)} keys(%{$ReportMap{$HeaderName}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014202 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014203 my %NameSpaceSymbols = ();
14204 foreach my $Interface (keys(%{$ReportMap{$HeaderName}{$DyLib}})) {
14205 $NameSpaceSymbols{get_IntNameSpace($Interface, 2)}{$Interface} = 1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014206 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014207 foreach my $NameSpace (sort keys(%NameSpaceSymbols))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014208 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014209 $ADDED_INTERFACES .= getTitle($HeaderName, $DyLib, $NameSpace);
14210 my @SortedInterfaces = sort {lc(get_Signature($a, 2)) cmp lc(get_Signature($b, 2))} keys(%{$NameSpaceSymbols{$NameSpace}});
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014211 foreach my $Interface (@SortedInterfaces)
14212 {
14213 $Added_Number += 1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014214 my $Signature = get_Signature($Interface, 2);
14215 if($NameSpace) {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040014216 $Signature=~s/\b\Q$NameSpace\E::\b//g;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014217 }
14218 if($Interface=~/\A(_Z|\?)/) {
14219 if($Signature) {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014220 $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 +040014221 }
14222 else {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014223 $ADDED_INTERFACES .= "<span class=\"iname\">".$Interface."</span><br/>\n";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014224 }
14225 }
14226 else {
14227 if($Signature) {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014228 $ADDED_INTERFACES .= "<span class=\"iname\">".highLight_Signature_Italic_Color($Signature)."</span><br/>\n";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014229 }
14230 else {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014231 $ADDED_INTERFACES .= "<span class=\"iname\">".$Interface."</span><br/>\n";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014232 }
14233 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014234 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014235 $ADDED_INTERFACES .= "<br/>\n";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014236 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014237 }
14238 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014239 if($ADDED_INTERFACES)
14240 {
14241 my $Anchor = "<a name='Added'></a>";
14242 if($JoinReport) {
14243 $Anchor = "<a name='".$Level."_Added'></a>";
14244 }
14245 $ADDED_INTERFACES = $Anchor."<h2>Added Symbols ($Added_Number)</h2><hr/>\n".$ADDED_INTERFACES.$TOP_REF."<br/>\n";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014246 }
14247 }
14248 return $ADDED_INTERFACES;
14249}
14250
14251sub get_Report_Removed($)
14252{
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014253 my $Level = $_[0];
Andrey Ponomarenko16934472012-03-29 15:37:04 +040014254 my $REMOVED_INTERFACES = "";
14255 my %ReportMap = ();
Andrey Ponomarenko85043792012-05-14 16:48:07 +040014256 foreach my $Symbol (sort keys(%{$CompatProblems{$Level}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014257 {
Andrey Ponomarenko85043792012-05-14 16:48:07 +040014258 foreach my $Kind (sort keys(%{$CompatProblems{$Level}{$Symbol}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014259 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014260 if($Kind eq "Removed_Symbol")
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014261 {
Andrey Ponomarenko85043792012-05-14 16:48:07 +040014262 my $HeaderName = $CompleteSignature{1}{$Symbol}{"Header"};
14263 my $DyLib = $Symbol_Library{1}{$Symbol};
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014264 if($Level eq "Source" and $ReportFormat eq "html")
14265 { # do not show library name in HTML report
14266 $DyLib = "";
14267 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +040014268 $ReportMap{$HeaderName}{$DyLib}{$Symbol} = 1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014269 }
14270 }
14271 }
14272 if($ReportFormat eq "xml")
14273 { # XML
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014274 foreach my $HeaderName (sort {lc($a) cmp lc($b)} keys(%ReportMap))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014275 {
14276 $REMOVED_INTERFACES .= " <header name=\"$HeaderName\">\n";
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014277 foreach my $DyLib (sort {lc($a) cmp lc($b)} keys(%{$ReportMap{$HeaderName}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014278 {
14279 $REMOVED_INTERFACES .= " <library name=\"$DyLib\">\n";
Andrey Ponomarenko85043792012-05-14 16:48:07 +040014280 foreach my $Symbol (keys(%{$ReportMap{$HeaderName}{$DyLib}})) {
14281 $REMOVED_INTERFACES .= " <name>$Symbol</name>\n";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014282 }
14283 $REMOVED_INTERFACES .= " </library>\n";
14284 }
14285 $REMOVED_INTERFACES .= " </header>\n";
14286 }
14287 $REMOVED_INTERFACES = "<removed_symbols>\n".$REMOVED_INTERFACES."</removed_symbols>\n\n";
14288 }
14289 else
14290 { # HTML
14291 my $Removed_Number = 0;
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014292 foreach my $HeaderName (sort {lc($a) cmp lc($b)} keys(%ReportMap))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014293 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014294 foreach my $DyLib (sort {lc($a) cmp lc($b)} keys(%{$ReportMap{$HeaderName}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014295 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014296 my %NameSpaceSymbols = ();
14297 foreach my $Interface (keys(%{$ReportMap{$HeaderName}{$DyLib}})) {
14298 $NameSpaceSymbols{get_IntNameSpace($Interface, 1)}{$Interface} = 1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014299 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014300 foreach my $NameSpace (sort keys(%NameSpaceSymbols))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014301 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014302 $REMOVED_INTERFACES .= getTitle($HeaderName, $DyLib, $NameSpace);
14303 my @SortedInterfaces = sort {lc(get_Signature($a, 1)) cmp lc(get_Signature($b, 1))} keys(%{$NameSpaceSymbols{$NameSpace}});
Andrey Ponomarenko85043792012-05-14 16:48:07 +040014304 foreach my $Symbol (@SortedInterfaces)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014305 {
14306 $Removed_Number += 1;
14307 my $SubReport = "";
Andrey Ponomarenko85043792012-05-14 16:48:07 +040014308 my $Signature = get_Signature($Symbol, 1);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014309 if($NameSpace) {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040014310 $Signature=~s/\b\Q$NameSpace\E::\b//g;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014311 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +040014312 if($Symbol=~/\A(_Z|\?)/)
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014313 {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014314 if($Signature) {
Andrey Ponomarenko85043792012-05-14 16:48:07 +040014315 $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 +040014316 }
14317 else {
Andrey Ponomarenko85043792012-05-14 16:48:07 +040014318 $REMOVED_INTERFACES .= "<span class=\"iname\">".$Symbol."</span><br/>\n";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014319 }
14320 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014321 else
14322 {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014323 if($Signature) {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014324 $REMOVED_INTERFACES .= "<span class=\"iname\">".highLight_Signature_Italic_Color($Signature)."</span><br/>\n";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014325 }
14326 else {
Andrey Ponomarenko85043792012-05-14 16:48:07 +040014327 $REMOVED_INTERFACES .= "<span class=\"iname\">".$Symbol."</span><br/>\n";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014328 }
14329 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014330 }
14331 }
14332 $REMOVED_INTERFACES .= "<br/>\n";
14333 }
14334 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014335 if($REMOVED_INTERFACES)
14336 {
14337 my $Anchor = "<a name='Removed'></a><a name='Withdrawn'></a>";
14338 if($JoinReport) {
14339 $Anchor = "<a name='".$Level."_Removed'></a><a name='".$Level."_Withdrawn'></a>";
14340 }
14341 $REMOVED_INTERFACES = $Anchor."<h2>Removed Symbols ($Removed_Number)</h2><hr/>\n".$REMOVED_INTERFACES.$TOP_REF."<br/>\n";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014342 }
14343 }
14344 return $REMOVED_INTERFACES;
14345}
14346
14347sub getXmlParams($$)
14348{
14349 my ($Content, $Problem) = @_;
14350 return "" if(not $Content or not $Problem);
14351 my %XMLparams = ();
14352 foreach my $Attr (sort {$b cmp $a} keys(%{$Problem}))
14353 {
14354 my $Macro = "\@".lc($Attr);
14355 if($Content=~/\Q$Macro\E/) {
14356 $XMLparams{lc($Attr)} = $Problem->{$Attr};
14357 }
14358 }
14359 my @PString = ();
14360 foreach my $P (sort {$b cmp $a} keys(%XMLparams)) {
14361 push(@PString, $P."=\"".htmlSpecChars($XMLparams{$P})."\"");
14362 }
14363 if(@PString) {
14364 return " ".join(" ", @PString);
14365 }
14366 else {
14367 return "";
14368 }
14369}
14370
14371sub addMarkup($)
14372{
14373 my $Content = $_[0];
14374 # auto-markup
14375 $Content=~s/\n[ ]*//; # spaces
14376 $Content=~s!(\@\w+\s*\(\@\w+\))!<nowrap>$1</nowrap>!g; # @old_type (@old_size)
14377 $Content=~s!(... \(\w+\))!<nowrap><b>$1</b></nowrap>!g; # ... (va_list)
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040014378 $Content=~s!<nowrap>(.+?)</nowrap>!<span class='nowrap'>$1</span>!g;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014379 $Content=~s!([2-9]\))!<br/>$1!g; # 1), 2), ...
14380 if($Content=~/\ANOTE:/)
14381 { # notes
14382 $Content=~s!(NOTE):!<b>$1</b>:!g;
14383 }
14384 else {
14385 $Content=~s!(NOTE):!<br/><b>$1</b>:!g;
14386 }
14387 $Content=~s! (out)-! <b>$1</b>-!g; # out-parameters
14388 my @Keywords = (
14389 "void",
14390 "const",
14391 "static",
14392 "restrict",
14393 "volatile",
14394 "register",
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040014395 "virtual"
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014396 );
14397 my $MKeys = join("|", @Keywords);
14398 foreach (@Keywords) {
14399 $MKeys .= "|non-".$_;
14400 }
14401 $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 +040014402
14403 # Markdown
14404 $Content=~s!\*\*([\w\-]+)\*\*!<b>$1</b>!ig;
14405 $Content=~s!\*([\w\-]+)\*!<i>$1</i>!ig;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014406 return $Content;
14407}
14408
14409sub applyMacroses($$$$)
14410{
14411 my ($Level, $Kind, $Content, $Problem) = @_;
14412 return "" if(not $Content or not $Problem);
14413 $Problem->{"Word_Size"} = $WORD_SIZE{2};
14414 $Content = addMarkup($Content);
14415 # macros
14416 foreach my $Attr (sort {$b cmp $a} keys(%{$Problem}))
14417 {
14418 my $Macro = "\@".lc($Attr);
14419 my $Value = $Problem->{$Attr};
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040014420 if(not defined $Value
14421 or $Value eq "") {
14422 next;
14423 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014424 if($Value=~/\s\(/)
14425 { # functions
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014426 $Value=~s/\s*\[[\w\-]+\]//g; # remove quals
14427 $Value=~s/\s\w+(\)|,)/$1/g; # remove parameter names
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014428 $Value = black_name($Value);
14429 }
14430 elsif($Value=~/\s/) {
14431 $Value = "<span class='value'>".htmlSpecChars($Value)."</span>";
14432 }
14433 elsif($Value=~/\A\d+\Z/
14434 and ($Attr eq "Old_Size" or $Attr eq "New_Size"))
14435 { # bits to bytes
14436 if($Value % $BYTE_SIZE)
14437 { # bits
14438 if($Value==1) {
14439 $Value = "<b>".$Value."</b> bit";
14440 }
14441 else {
14442 $Value = "<b>".$Value."</b> bits";
14443 }
14444 }
14445 else
14446 { # bytes
14447 $Value /= $BYTE_SIZE;
14448 if($Value==1) {
14449 $Value = "<b>".$Value."</b> byte";
14450 }
14451 else {
14452 $Value = "<b>".$Value."</b> bytes";
14453 }
14454 }
14455 }
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040014456 else
14457 {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014458 $Value = "<b>".htmlSpecChars($Value)."</b>";
14459 }
14460 $Content=~s/\Q$Macro\E/$Value/g;
14461 }
14462
14463 if($Content=~/(\A|[^\@\w])\@\w/)
14464 {
14465 if(not $IncompleteRules{$Level}{$Kind})
14466 { # only one warning
14467 printMsg("WARNING", "incomplete rule \"$Kind\" (\"$Level\")");
14468 $IncompleteRules{$Level}{$Kind} = 1;
14469 }
14470 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014471 return $Content;
14472}
14473
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040014474sub get_Report_SymbolProblems($$)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014475{
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014476 my ($TargetSeverity, $Level) = @_;
Andrey Ponomarenko16934472012-03-29 15:37:04 +040014477 my $INTERFACE_PROBLEMS = "";
14478 my (%ReportMap, %SymbolChanges) = ();
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014479 foreach my $Symbol (sort keys(%{$CompatProblems{$Level}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014480 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014481 my ($SN, $SS, $SV) = separate_symbol($Symbol);
14482 if($SV and defined $CompatProblems{$Level}{$SN}) {
14483 next;
14484 }
14485 foreach my $Kind (sort keys(%{$CompatProblems{$Level}{$Symbol}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014486 {
14487 if($CompatRules{$Level}{$Kind}{"Kind"} eq "Symbols"
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014488 and $Kind ne "Added_Symbol" and $Kind ne "Removed_Symbol")
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014489 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014490 my $HeaderName = $CompleteSignature{1}{$Symbol}{"Header"};
14491 my $DyLib = $Symbol_Library{1}{$Symbol};
14492 if(not $DyLib and my $VSym = $SymVer{1}{$Symbol})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014493 { # Symbol with Version
14494 $DyLib = $Symbol_Library{1}{$VSym};
14495 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040014496 if(not $DyLib)
14497 { # const global data
14498 $DyLib = "";
14499 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014500 if($Level eq "Source" and $ReportFormat eq "html")
14501 { # do not show library name in HTML report
14502 $DyLib = "";
14503 }
14504 %{$SymbolChanges{$Symbol}{$Kind}} = %{$CompatProblems{$Level}{$Symbol}{$Kind}};
14505 foreach my $Location (sort keys(%{$SymbolChanges{$Symbol}{$Kind}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014506 {
14507 my $Priority = getProblemSeverity($Level, $Kind);
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014508 if($Priority ne $TargetSeverity) {
14509 delete($SymbolChanges{$Symbol}{$Kind}{$Location});
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014510 }
14511 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014512 if(not keys(%{$SymbolChanges{$Symbol}{$Kind}}))
14513 {
14514 delete($SymbolChanges{$Symbol}{$Kind});
14515 next;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014516 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014517 $ReportMap{$HeaderName}{$DyLib}{$Symbol} = 1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014518 }
14519 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014520 if(not keys(%{$SymbolChanges{$Symbol}})) {
14521 delete($SymbolChanges{$Symbol});
14522 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014523 }
14524 if($ReportFormat eq "xml")
14525 { # XML
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014526 foreach my $HeaderName (sort {lc($a) cmp lc($b)} keys(%ReportMap))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014527 {
14528 $INTERFACE_PROBLEMS .= " <header name=\"$HeaderName\">\n";
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014529 foreach my $DyLib (sort {lc($a) cmp lc($b)} keys(%{$ReportMap{$HeaderName}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014530 {
14531 $INTERFACE_PROBLEMS .= " <library name=\"$DyLib\">\n";
14532 foreach my $Symbol (sort {lc($tr_name{$a}) cmp lc($tr_name{$b})} keys(%SymbolChanges))
14533 {
14534 $INTERFACE_PROBLEMS .= " <symbol name=\"$Symbol\">\n";
14535 foreach my $Kind (keys(%{$SymbolChanges{$Symbol}}))
14536 {
14537 foreach my $Location (sort keys(%{$SymbolChanges{$Symbol}{$Kind}}))
14538 {
14539 my %Problem = %{$SymbolChanges{$Symbol}{$Kind}{$Location}};
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040014540 $Problem{"Param_Pos"} = showPos($Problem{"Param_Pos"});
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014541 $INTERFACE_PROBLEMS .= " <problem id=\"$Kind\">\n";
14542 my $Change = $CompatRules{$Level}{$Kind}{"Change"};
14543 $INTERFACE_PROBLEMS .= " <change".getXmlParams($Change, \%Problem).">$Change</change>\n";
14544 my $Effect = $CompatRules{$Level}{$Kind}{"Effect"};
14545 $INTERFACE_PROBLEMS .= " <effect".getXmlParams($Effect, \%Problem).">$Effect</effect>\n";
14546 my $Overcome = $CompatRules{$Level}{$Kind}{"Overcome"};
14547 $INTERFACE_PROBLEMS .= " <overcome".getXmlParams($Overcome, \%Problem).">$Overcome</overcome>\n";
14548 $INTERFACE_PROBLEMS .= " </problem>\n";
14549 }
14550 }
14551 $INTERFACE_PROBLEMS .= " </symbol>\n";
14552 }
14553 $INTERFACE_PROBLEMS .= " </library>\n";
14554 }
14555 $INTERFACE_PROBLEMS .= " </header>\n";
14556 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014557 $INTERFACE_PROBLEMS = "<problems_with_symbols severity=\"$TargetSeverity\">\n".$INTERFACE_PROBLEMS."</problems_with_symbols>\n\n";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014558 }
14559 else
14560 { # HTML
14561 my $ProblemsNum = 0;
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014562 foreach my $HeaderName (sort {lc($a) cmp lc($b)} keys(%ReportMap))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014563 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014564 foreach my $DyLib (sort {lc($a) cmp lc($b)} keys(%{$ReportMap{$HeaderName}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014565 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014566 my (%NameSpaceSymbols, %NewSignature) = ();
14567 foreach my $Symbol (keys(%{$ReportMap{$HeaderName}{$DyLib}})) {
14568 $NameSpaceSymbols{get_IntNameSpace($Symbol, 1)}{$Symbol} = 1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014569 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014570 foreach my $NameSpace (sort keys(%NameSpaceSymbols))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014571 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014572 $INTERFACE_PROBLEMS .= getTitle($HeaderName, $DyLib, $NameSpace);
14573 my @SortedInterfaces = sort {lc($tr_name{$a}) cmp lc($tr_name{$b})} keys(%{$NameSpaceSymbols{$NameSpace}});
14574 foreach my $Symbol (@SortedInterfaces)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014575 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014576 my $Signature = get_Signature($Symbol, 1);
14577 my $SYMBOL_REPORT = "";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014578 my $ProblemNum = 1;
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014579 foreach my $Kind (keys(%{$SymbolChanges{$Symbol}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014580 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014581 foreach my $Location (sort keys(%{$SymbolChanges{$Symbol}{$Kind}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014582 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014583 my %Problem = %{$SymbolChanges{$Symbol}{$Kind}{$Location}};
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040014584 $Problem{"Param_Pos"} = showPos($Problem{"Param_Pos"});
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014585 if($Problem{"New_Signature"}) {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014586 $NewSignature{$Symbol} = $Problem{"New_Signature"};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014587 }
14588 if(my $Change = applyMacroses($Level, $Kind, $CompatRules{$Level}{$Kind}{"Change"}, \%Problem))
14589 {
14590 my $Effect = applyMacroses($Level, $Kind, $CompatRules{$Level}{$Kind}{"Effect"}, \%Problem);
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014591 $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 +040014592 $ProblemNum += 1;
14593 $ProblemsNum += 1;
14594 }
14595 }
14596 }
14597 $ProblemNum -= 1;
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014598 if($SYMBOL_REPORT)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014599 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014600 $INTERFACE_PROBLEMS .= $ContentSpanStart."<span class='extendable'>[+]</span> ";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014601 if($Signature) {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014602 $INTERFACE_PROBLEMS .= highLight_Signature_Italic_Color($Signature);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014603 }
14604 else {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014605 $INTERFACE_PROBLEMS .= $Symbol;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014606 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014607 $INTERFACE_PROBLEMS .= " ($ProblemNum)".$ContentSpanEnd."<br/>\n";
14608 $INTERFACE_PROBLEMS .= $ContentDivStart."\n";
14609 if($NewSignature{$Symbol})
14610 { # argument list changed to
14611 $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 +040014612 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014613 if($Symbol=~/\A(_Z|\?)/) {
14614 $INTERFACE_PROBLEMS .= "<span class='mangled'>&#160;&#160;&#160;&#160;[symbol: <b>$Symbol</b>]</span><br/>\n";
14615 }
14616 $INTERFACE_PROBLEMS .= "<table class='ptable'><tr><th width='2%'></th><th width='47%'>Change</th><th>Effect</th></tr>$SYMBOL_REPORT</table><br/>\n";
14617 $INTERFACE_PROBLEMS .= $ContentDivEnd;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014618 if($NameSpace) {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040014619 $INTERFACE_PROBLEMS=~s/\b\Q$NameSpace\E::\b//g;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014620 }
14621 }
14622 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014623 $INTERFACE_PROBLEMS .= "<br/>";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014624 }
14625 }
14626 }
14627 if($INTERFACE_PROBLEMS)
14628 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014629 $INTERFACE_PROBLEMS = insertIDs($INTERFACE_PROBLEMS);
14630 my $Title = "Problems with Symbols, $TargetSeverity Severity";
14631 if($TargetSeverity eq "Safe")
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014632 { # Safe Changes
14633 $Title = "Other Changes in Symbols";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014634 }
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040014635 $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 +040014636 }
14637 }
14638 return $INTERFACE_PROBLEMS;
14639}
14640
14641sub get_Report_TypeProblems($$)
14642{
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014643 my ($TargetSeverity, $Level) = @_;
Andrey Ponomarenko16934472012-03-29 15:37:04 +040014644 my $TYPE_PROBLEMS = "";
14645 my (%ReportMap, %TypeChanges, %TypeType) = ();
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014646 foreach my $Interface (sort keys(%{$CompatProblems{$Level}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014647 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014648 foreach my $Kind (keys(%{$CompatProblems{$Level}{$Interface}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014649 {
14650 if($CompatRules{$Level}{$Kind}{"Kind"} eq "Types")
14651 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014652 foreach my $Location (sort {cmp_locations($b, $a)} sort keys(%{$CompatProblems{$Level}{$Interface}{$Kind}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014653 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014654 my $TypeName = $CompatProblems{$Level}{$Interface}{$Kind}{$Location}{"Type_Name"};
14655 my $TypeType = $CompatProblems{$Level}{$Interface}{$Kind}{$Location}{"Type_Type"};
14656 my $Target = $CompatProblems{$Level}{$Interface}{$Kind}{$Location}{"Target"};
14657 $CompatProblems{$Level}{$Interface}{$Kind}{$Location}{"Type_Type"} = lc($TypeType);
14658 my $Severity = getProblemSeverity($Level, $Kind);
14659 if($Severity eq "Safe"
14660 and $TargetSeverity ne "Safe") {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014661 next;
14662 }
14663 if(not $TypeType{$TypeName}
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014664 or $TypeType{$TypeName} eq "struct")
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014665 { # register type of the type, select "class" if type has "class"- and "struct"-type changes
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014666 $TypeType{$TypeName} = $CompatProblems{$Level}{$Interface}{$Kind}{$Location}{"Type_Type"};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014667 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014668
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040014669 if(cmpSeverities($Type_MaxSeverity{$Level}{$TypeName}{$Kind}{$Target}, $Severity))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014670 { # select a problem with the highest priority
14671 next;
14672 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014673 %{$TypeChanges{$TypeName}{$Kind}{$Location}} = %{$CompatProblems{$Level}{$Interface}{$Kind}{$Location}};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014674 }
14675 }
14676 }
14677 }
14678 my %Kinds_Locations = ();
14679 foreach my $TypeName (keys(%TypeChanges))
14680 {
14681 my %Kinds_Target = ();
14682 foreach my $Kind (sort keys(%{$TypeChanges{$TypeName}}))
14683 {
14684 foreach my $Location (sort {cmp_locations($b, $a)} sort keys(%{$TypeChanges{$TypeName}{$Kind}}))
14685 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014686 my $Severity = getProblemSeverity($Level, $Kind);
14687 if($Severity ne $TargetSeverity)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014688 { # other priority
14689 delete($TypeChanges{$TypeName}{$Kind}{$Location});
14690 next;
14691 }
14692 $Kinds_Locations{$TypeName}{$Kind}{$Location} = 1;
14693 my $Target = $TypeChanges{$TypeName}{$Kind}{$Location}{"Target"};
14694 if($Kinds_Target{$Kind}{$Target})
14695 { # duplicate target
14696 delete($TypeChanges{$TypeName}{$Kind}{$Location});
14697 next;
14698 }
14699 $Kinds_Target{$Kind}{$Target} = 1;
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040014700 my $HeaderName = $TypeInfo{1}{$TName_Tid{1}{$TypeName}}{"Header"};
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014701 $ReportMap{$HeaderName}{$TypeName} = 1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014702 }
14703 if(not keys(%{$TypeChanges{$TypeName}{$Kind}})) {
14704 delete($TypeChanges{$TypeName}{$Kind});
14705 }
14706 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014707 if(not keys(%{$TypeChanges{$TypeName}})) {
14708 delete($TypeChanges{$TypeName});
14709 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014710 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +040014711 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 +040014712 if($ReportFormat eq "xml")
14713 { # XML
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014714 foreach my $HeaderName (sort {lc($a) cmp lc($b)} keys(%ReportMap))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014715 {
14716 $TYPE_PROBLEMS .= " <header name=\"$HeaderName\">\n";
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014717 foreach my $TypeName (keys(%{$ReportMap{$HeaderName}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014718 {
14719 $TYPE_PROBLEMS .= " <type name=\"".htmlSpecChars($TypeName)."\">\n";
14720 foreach my $Kind (sort {$b=~/Size/ <=> $a=~/Size/} sort keys(%{$TypeChanges{$TypeName}}))
14721 {
14722 foreach my $Location (sort {cmp_locations($b, $a)} sort keys(%{$TypeChanges{$TypeName}{$Kind}}))
14723 {
14724 my %Problem = %{$TypeChanges{$TypeName}{$Kind}{$Location}};
14725 $TYPE_PROBLEMS .= " <problem id=\"$Kind\">\n";
14726 my $Change = $CompatRules{$Level}{$Kind}{"Change"};
14727 $TYPE_PROBLEMS .= " <change".getXmlParams($Change, \%Problem).">$Change</change>\n";
14728 my $Effect = $CompatRules{$Level}{$Kind}{"Effect"};
14729 $TYPE_PROBLEMS .= " <effect".getXmlParams($Effect, \%Problem).">$Effect</effect>\n";
14730 my $Overcome = $CompatRules{$Level}{$Kind}{"Overcome"};
14731 $TYPE_PROBLEMS .= " <overcome".getXmlParams($Overcome, \%Problem).">$Overcome</overcome>\n";
14732 $TYPE_PROBLEMS .= " </problem>\n";
14733 }
14734 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +040014735 $TYPE_PROBLEMS .= getAffectedSymbols($Level, $TypeName, $Kinds_Locations{$TypeName}, \@Symbols);
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014736 if($Level eq "Binary" and grep {$_=~/Virtual|Base_Class/} keys(%{$Kinds_Locations{$TypeName}})) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014737 $TYPE_PROBLEMS .= showVTables($TypeName);
14738 }
14739 $TYPE_PROBLEMS .= " </type>\n";
14740 }
14741 $TYPE_PROBLEMS .= " </header>\n";
14742 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014743 $TYPE_PROBLEMS = "<problems_with_types severity=\"$TargetSeverity\">\n".$TYPE_PROBLEMS."</problems_with_types>\n\n";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014744 }
14745 else
14746 { # HTML
14747 my $ProblemsNum = 0;
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014748 foreach my $HeaderName (sort {lc($a) cmp lc($b)} keys(%ReportMap))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014749 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014750 my (%NameSpace_Type) = ();
14751 foreach my $TypeName (keys(%{$ReportMap{$HeaderName}})) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014752 $NameSpace_Type{parse_TypeNameSpace($TypeName, 1)}{$TypeName} = 1;
14753 }
14754 foreach my $NameSpace (sort keys(%NameSpace_Type))
14755 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014756 $TYPE_PROBLEMS .= getTitle($HeaderName, "", $NameSpace);
14757 my @SortedTypes = sort {$TypeType{$a}." ".lc($a) cmp $TypeType{$b}." ".lc($b)} keys(%{$NameSpace_Type{$NameSpace}});
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014758 foreach my $TypeName (@SortedTypes)
14759 {
14760 my $ProblemNum = 1;
14761 my $TYPE_REPORT = "";
14762 foreach my $Kind (sort {$b=~/Size/ <=> $a=~/Size/} sort keys(%{$TypeChanges{$TypeName}}))
14763 {
14764 foreach my $Location (sort {cmp_locations($b, $a)} sort keys(%{$TypeChanges{$TypeName}{$Kind}}))
14765 {
14766 my %Problem = %{$TypeChanges{$TypeName}{$Kind}{$Location}};
14767 if(my $Change = applyMacroses($Level, $Kind, $CompatRules{$Level}{$Kind}{"Change"}, \%Problem))
14768 {
14769 my $Effect = applyMacroses($Level, $Kind, $CompatRules{$Level}{$Kind}{"Effect"}, \%Problem);
14770 $TYPE_REPORT .= "<tr><th>$ProblemNum</th><td align='left' valign='top'>".$Change."</td><td align='left' valign='top'>$Effect</td></tr>\n";
14771 $ProblemNum += 1;
14772 $ProblemsNum += 1;
14773 }
14774 }
14775 }
14776 $ProblemNum -= 1;
14777 if($TYPE_REPORT)
14778 {
Andrey Ponomarenko85043792012-05-14 16:48:07 +040014779 my $Affected = getAffectedSymbols($Level, $TypeName, $Kinds_Locations{$TypeName}, \@Symbols);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014780 my $ShowVTables = "";
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014781 if($Level eq "Binary" and grep {$_=~/Virtual|Base_Class/} keys(%{$Kinds_Locations{$TypeName}})) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014782 $ShowVTables = showVTables($TypeName);
14783 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014784 $TYPE_PROBLEMS .= $ContentSpanStart."<span class='extendable'>[+]</span> <span class='ttype'>".$TypeType{$TypeName}."</span> ".htmlSpecChars($TypeName)." ($ProblemNum)".$ContentSpanEnd;
14785 $TYPE_PROBLEMS .= "<br/>\n".$ContentDivStart."<table class='ptable'><tr>\n";
14786 $TYPE_PROBLEMS .= "<th width='2%'></th><th width='47%'>Change</th>\n";
14787 $TYPE_PROBLEMS .= "<th>Effect</th></tr>".$TYPE_REPORT."</table>\n";
14788 $TYPE_PROBLEMS .= $ShowVTables.$Affected."<br/><br/>".$ContentDivEnd."\n";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014789 if($NameSpace) {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040014790 $TYPE_PROBLEMS=~s/\b\Q$NameSpace\E::(\w|\~)/$1/g;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014791 }
14792 }
14793 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014794 $TYPE_PROBLEMS .= "<br/>";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014795 }
14796 }
14797 if($TYPE_PROBLEMS)
14798 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014799 $TYPE_PROBLEMS = insertIDs($TYPE_PROBLEMS);
14800 my $Title = "Problems with Data Types, $TargetSeverity Severity";
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014801 if($TargetSeverity eq "Safe")
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014802 { # Safe Changes
14803 $Title = "Other Changes in Data Types";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014804 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014805 $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 +040014806 }
14807 }
14808 return $TYPE_PROBLEMS;
14809}
14810
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014811sub get_Anchor($$$)
14812{
14813 my ($Kind, $Level, $Severity) = @_;
14814 if($JoinReport)
14815 {
14816 if($Severity eq "Safe") {
14817 return "Other_".$Level."_Changes_In_".$Kind."s";
14818 }
14819 else {
14820 return $Kind."_".$Level."_Problems_".$Severity;
14821 }
14822 }
14823 else
14824 {
14825 if($Severity eq "Safe") {
14826 return "Other_Changes_In_".$Kind."s";
14827 }
14828 else {
14829 return $Kind."_Problems_".$Severity;
14830 }
14831 }
14832}
14833
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014834sub showVTables($)
14835{
14836 my $TypeName = $_[0];
14837 my $TypeId1 = $TName_Tid{1}{$TypeName};
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040014838 my %Type1 = get_Type($TypeId1, 1);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014839 if(defined $Type1{"VTable"}
14840 and keys(%{$Type1{"VTable"}}))
14841 {
14842 my $TypeId2 = $TName_Tid{2}{$TypeName};
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040014843 my %Type2 = get_Type($TypeId2, 2);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014844 if(defined $Type2{"VTable"}
14845 and keys(%{$Type2{"VTable"}}))
14846 {
14847 my %Indexes = map {$_=>1} (keys(%{$Type1{"VTable"}}), keys(%{$Type2{"VTable"}}));
14848 my %Entries = ();
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014849 foreach my $Index (sort {int($a)<=>int($b)} (keys(%Indexes)))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014850 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014851 $Entries{$Index}{"E1"} = simpleVEntry($Type1{"VTable"}{$Index});
14852 $Entries{$Index}{"E2"} = simpleVEntry($Type2{"VTable"}{$Index});
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014853 }
14854 my $VTABLES = "";
14855 if($ReportFormat eq "xml")
14856 { # XML
14857 $VTABLES .= " <vtable>\n";
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014858 foreach my $Index (sort {int($a)<=>int($b)} (keys(%Entries)))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014859 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014860 $VTABLES .= " <entry offset=\"".$Index."\">\n";
14861 $VTABLES .= " <old>".htmlSpecChars($Entries{$Index}{"E1"})."</old>\n";
14862 $VTABLES .= " <new>".htmlSpecChars($Entries{$Index}{"E2"})."</new>\n";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014863 $VTABLES .= " </entry>\n";
14864 }
14865 $VTABLES .= " </vtable>\n\n";
14866 }
14867 else
14868 { # HTML
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014869 $VTABLES .= "<table class='vtable'>";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014870 $VTABLES .= "<tr><th width='2%'>Offset</th>";
14871 $VTABLES .= "<th width='45%'>Virtual Table (Old) - ".(keys(%{$Type1{"VTable"}}))." entries</th>";
14872 $VTABLES .= "<th>Virtual Table (New) - ".(keys(%{$Type2{"VTable"}}))." entries</th></tr>";
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014873 foreach my $Index (sort {int($a)<=>int($b)} (keys(%Entries)))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014874 {
14875 my ($Color1, $Color2) = ("", "");
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014876 if($Entries{$Index}{"E1"} ne $Entries{$Index}{"E2"})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014877 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014878 if($Entries{$Index}{"E1"})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014879 {
Andrey Ponomarenko16934472012-03-29 15:37:04 +040014880 $Color1 = " class='failed'";
14881 $Color2 = " class='failed'";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014882 }
14883 else {
Andrey Ponomarenko16934472012-03-29 15:37:04 +040014884 $Color2 = " class='warning'";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014885 }
14886 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014887 $VTABLES .= "<tr><th>".$Index."</th>\n";
14888 $VTABLES .= "<td$Color1>".htmlSpecChars($Entries{$Index}{"E1"})."</td>\n";
14889 $VTABLES .= "<td$Color2>".htmlSpecChars($Entries{$Index}{"E2"})."</td></tr>\n";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014890 }
14891 $VTABLES .= "</table><br/>\n";
14892 $VTABLES = $ContentDivStart.$VTABLES.$ContentDivEnd;
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014893 $VTABLES = $ContentSpanStart_Info."[+] show v-table (old and new)".$ContentSpanEnd."<br/>\n".$VTABLES;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014894 }
14895 return $VTABLES;
14896 }
14897 }
14898 return "";
14899}
14900
14901sub simpleVEntry($)
14902{
14903 my $VEntry = $_[0];
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040014904 if(not defined $VEntry
14905 or $VEntry eq "") {
14906 return "";
14907 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014908 $VEntry=~s/\A(.+)::(_ZThn.+)\Z/$2/; # thunks
14909 $VEntry=~s/_ZTI\w+/typeinfo/g; # typeinfo
14910 if($VEntry=~/\A_ZThn.+\Z/) {
14911 $VEntry = "non-virtual thunk";
14912 }
14913 $VEntry=~s/\A\(int \(\*\)\(...\)\)([^\(\d])/$1/i;
14914 # support for old GCC versions
14915 $VEntry=~s/\A0u\Z/(int (*)(...))0/;
14916 $VEntry=~s/\A4294967268u\Z/(int (*)(...))-0x000000004/;
14917 $VEntry=~s/\A&_Z\Z/& _Z/;
14918 # templates
14919 if($VEntry=~s/ \[with (\w+) = (.+?)(, [^=]+ = .+|])\Z//g)
14920 { # std::basic_streambuf<_CharT, _Traits>::imbue [with _CharT = char, _Traits = std::char_traits<char>]
14921 # become std::basic_streambuf<char, ...>::imbue
14922 my ($Pname, $Pval) = ($1, $2);
14923 if($Pname eq "_CharT" and $VEntry=~/\Astd::/)
14924 { # stdc++ typedefs
14925 $VEntry=~s/<$Pname(, [^<>]+|)>/<$Pval>/g;
14926 # FIXME: simplify names using stdcxx typedefs (StdCxxTypedef)
14927 # The typedef info should be added to ABI dumps
14928 }
14929 else
14930 {
14931 $VEntry=~s/<$Pname>/<$Pval>/g;
14932 $VEntry=~s/<$Pname, [^<>]+>/<$Pval, ...>/g;
14933 }
14934 }
14935 $VEntry=~s/([^:]+)::\~([^:]+)\Z/~$1/; # destructors
14936 return $VEntry;
14937}
14938
Andrey Ponomarenko85043792012-05-14 16:48:07 +040014939sub getAffectedSymbols($$$$)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014940{
Andrey Ponomarenko85043792012-05-14 16:48:07 +040014941 my ($Level, $Target_TypeName, $Kinds_Locations, $Syms) = @_;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014942 my $LIMIT = 1000;
Andrey Ponomarenko85043792012-05-14 16:48:07 +040014943 if($#{$Syms}>=10000)
14944 { # reduce size of the report
14945 $LIMIT = 10;
14946 }
14947 my %SProblems = ();
14948 foreach my $Symbol (@{$Syms})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014949 {
Andrey Ponomarenko85043792012-05-14 16:48:07 +040014950 if(keys(%SProblems)>$LIMIT) {
14951 last;
14952 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014953 if(($Symbol=~/C2E|D2E|D0E/))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014954 { # duplicated problems for C2 constructors, D2 and D0 destructors
14955 next;
14956 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014957 my ($SN, $SS, $SV) = separate_symbol($Symbol);
14958 if($Level eq "Source")
14959 { # remove symbol version
14960 $Symbol=$SN;
14961 }
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040014962 my ($MinPath_Length, $ProblemLocation_Last) = (-1, "");
14963 my $Severity_Max = 0;
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014964 my $Signature = get_Signature($Symbol, 1);
14965 foreach my $Kind (keys(%{$CompatProblems{$Level}{$Symbol}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014966 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014967 foreach my $Location (keys(%{$CompatProblems{$Level}{$Symbol}{$Kind}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014968 {
14969 if(not defined $Kinds_Locations->{$Kind}
14970 or not $Kinds_Locations->{$Kind}{$Location}) {
14971 next;
14972 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014973 if($SV and defined $CompatProblems{$Level}{$SN}
14974 and defined $CompatProblems{$Level}{$SN}{$Kind}{$Location})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014975 { # duplicated problems for versioned symbols
14976 next;
14977 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014978 my $Type_Name = $CompatProblems{$Level}{$Symbol}{$Kind}{$Location}{"Type_Name"};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014979 next if($Type_Name ne $Target_TypeName);
14980
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014981 my $Position = $CompatProblems{$Level}{$Symbol}{$Kind}{$Location}{"Param_Pos"};
14982 my $Param_Name = $CompatProblems{$Level}{$Symbol}{$Kind}{$Location}{"Param_Name"};
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040014983 my $Severity = getProblemSeverity($Level, $Kind);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014984 my $Path_Length = 0;
14985 my $ProblemLocation = $Location;
14986 if($Type_Name) {
14987 $ProblemLocation=~s/->\Q$Type_Name\E\Z//g;
14988 }
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040014989 while($ProblemLocation=~/\-\>/g) {
14990 $Path_Length += 1;
14991 }
14992 if($MinPath_Length==-1 or ($Path_Length<=$MinPath_Length and $Severity_Val{$Severity}>$Severity_Max)
14993 or (cmp_locations($ProblemLocation, $ProblemLocation_Last) and $Severity_Val{$Severity}==$Severity_Max))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014994 {
14995 $MinPath_Length = $Path_Length;
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040014996 $Severity_Max = $Severity_Val{$Severity};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014997 $ProblemLocation_Last = $ProblemLocation;
Andrey Ponomarenko85043792012-05-14 16:48:07 +040014998 %{$SProblems{$Symbol}} = (
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040014999 "Descr"=>getAffectDescription($Level, $Symbol, $Kind, $Location),
15000 "Severity_Max"=>$Severity_Max,
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015001 "Signature"=>$Signature,
15002 "Position"=>$Position,
15003 "Param_Name"=>$Param_Name,
15004 "Location"=>$Location
15005 );
15006 }
15007 }
15008 }
15009 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +040015010 my @Symbols = keys(%SProblems);
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015011 @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 +040015012 @Symbols = sort {$SProblems{$b}{"Severity_Max"}<=>$SProblems{$a}{"Severity_Max"}} @Symbols;
15013 if($#Symbols+1>$LIMIT)
15014 { # remove last element
15015 pop(@Symbols);
15016 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015017 my $Affected = "";
15018 if($ReportFormat eq "xml")
15019 { # XML
15020 $Affected .= " <affected>\n";
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015021 foreach my $Symbol (@Symbols)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015022 {
Andrey Ponomarenko85043792012-05-14 16:48:07 +040015023 my $Param_Name = $SProblems{$Symbol}{"Param_Name"};
15024 my $Description = $SProblems{$Symbol}{"Descr"};
15025 my $Location = $SProblems{$Symbol}{"Location"};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015026 my $Target = "";
15027 if($Param_Name) {
15028 $Target = " affected=\"param\" param_name=\"$Param_Name\"";
15029 }
15030 elsif($Location=~/\Aretval(\-|\Z)/i) {
15031 $Target = " affected=\"retval\"";
15032 }
15033 elsif($Location=~/\Athis(\-|\Z)/i) {
15034 $Target = " affected=\"this\"";
15035 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015036 $Affected .= " <symbol$Target name=\"$Symbol\">\n";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015037 $Affected .= " <comment>".htmlSpecChars($Description)."</comment>\n";
15038 $Affected .= " </symbol>\n";
15039 }
15040 $Affected .= " </affected>\n";
15041 }
15042 else
15043 { # HTML
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015044 foreach my $Symbol (@Symbols)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015045 {
Andrey Ponomarenko85043792012-05-14 16:48:07 +040015046 my $Description = $SProblems{$Symbol}{"Descr"};
15047 my $Signature = $SProblems{$Symbol}{"Signature"};
15048 my $Pos = $SProblems{$Symbol}{"Position"};
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040015049 $Affected .= "<span class='iname_b'>".highLight_Signature_PPos_Italic($Signature, $Pos, 1, 0, 0)."</span><br/><div class='affect'>".htmlSpecChars($Description)."</div>\n";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015050 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +040015051 if(keys(%SProblems)>$LIMIT) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015052 $Affected .= "and others ...<br/>";
15053 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +040015054 $Affected = "<div class='affected'>".$Affected."</div>";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015055 if($Affected)
15056 {
15057 $Affected = $ContentDivStart.$Affected.$ContentDivEnd;
Andrey Ponomarenko85043792012-05-14 16:48:07 +040015058 $Affected = $ContentSpanStart_Affected."[+] affected symbols (".(keys(%SProblems)>$LIMIT?">".$LIMIT:keys(%SProblems)).")".$ContentSpanEnd.$Affected;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015059 }
15060 }
15061 return $Affected;
15062}
15063
15064sub cmp_locations($$)
15065{
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040015066 my ($L1, $L2) = @_;
15067 if($L2=~/\b(retval|this)\b/
15068 and $L1!~/\b(retval|this)\b/ and $L1!~/\-\>/) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015069 return 1;
15070 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040015071 if($L2=~/\b(retval|this)\b/ and $L2=~/\-\>/
15072 and $L1!~/\b(retval|this)\b/ and $L1=~/\-\>/) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015073 return 1;
15074 }
15075 return 0;
15076}
15077
15078sub getAffectDescription($$$$)
15079{
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015080 my ($Level, $Symbol, $Kind, $Location) = @_;
15081 my %Problem = %{$CompatProblems{$Level}{$Symbol}{$Kind}{$Location}};
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040015082 my $PPos = showPos($Problem{"Param_Pos"});
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015083 my @Sentence = ();
15084 $Location=~s/\A(.*)\-\>.+?\Z/$1/;
15085 if($Kind eq "Overridden_Virtual_Method"
15086 or $Kind eq "Overridden_Virtual_Method_B") {
15087 push(@Sentence, "The method '".$Problem{"New_Value"}."' will be called instead of this method.");
15088 }
15089 elsif($CompatRules{$Level}{$Kind}{"Kind"} eq "Types")
15090 {
15091 if($Location eq "this" or $Kind=~/(\A|_)Virtual(_|\Z)/)
15092 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015093 my $METHOD_TYPE = $CompleteSignature{1}{$Symbol}{"Constructor"}?"constructor":"method";
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040015094 my $ClassName = $TypeInfo{1}{$CompleteSignature{1}{$Symbol}{"Class"}}{"Name"};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015095 if($ClassName eq $Problem{"Type_Name"}) {
15096 push(@Sentence, "This $METHOD_TYPE is from \'".$Problem{"Type_Name"}."\' class.");
15097 }
15098 else {
15099 push(@Sentence, "This $METHOD_TYPE is from derived class \'".$ClassName."\'.");
15100 }
15101 }
15102 else
15103 {
15104 if($Location=~/retval/)
15105 { # return value
15106 if($Location=~/\-\>/) {
15107 push(@Sentence, "Field \'".$Location."\' in return value");
15108 }
15109 else {
15110 push(@Sentence, "Return value");
15111 }
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040015112 if(my $Init = $Problem{"InitialType_Type"})
15113 {
15114 if($Init eq "Pointer") {
15115 push(@Sentence, "(pointer)");
15116 }
15117 elsif($Init eq "Ref") {
15118 push(@Sentence, "(reference)");
15119 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015120 }
15121 }
15122 elsif($Location=~/this/)
15123 { # "this" pointer
15124 if($Location=~/\-\>/) {
15125 push(@Sentence, "Field \'".$Location."\' in the object of this method");
15126 }
15127 else {
15128 push(@Sentence, "\'this\' pointer");
15129 }
15130 }
15131 else
15132 { # parameters
15133 if($Location=~/\-\>/) {
15134 push(@Sentence, "Field \'".$Location."\' in $PPos parameter");
15135 }
15136 else {
15137 push(@Sentence, "$PPos parameter");
15138 }
15139 if($Problem{"Param_Name"}) {
15140 push(@Sentence, "\'".$Problem{"Param_Name"}."\'");
15141 }
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040015142 if(my $Init = $Problem{"InitialType_Type"})
15143 {
15144 if($Init eq "Pointer") {
15145 push(@Sentence, "(pointer)");
15146 }
15147 elsif($Init eq "Ref") {
15148 push(@Sentence, "(reference)");
15149 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015150 }
15151 }
15152 if($Location eq "this") {
15153 push(@Sentence, "has base type \'".$Problem{"Type_Name"}."\'.");
15154 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040015155 elsif(defined $Problem{"Start_Type_Name"}
15156 and $Problem{"Start_Type_Name"} eq $Problem{"Type_Name"}) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015157 push(@Sentence, "has type \'".$Problem{"Type_Name"}."\'.");
15158 }
15159 else {
15160 push(@Sentence, "has base type \'".$Problem{"Type_Name"}."\'.");
15161 }
15162 }
15163 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040015164 if($ExtendedSymbols{$Symbol}) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015165 push(@Sentence, " This is a symbol from an artificial external library that may use the \'$TargetLibraryName\' library and change its ABI after recompiling.");
15166 }
15167 return join(" ", @Sentence);
15168}
15169
15170sub get_XmlSign($$)
15171{
15172 my ($Symbol, $LibVersion) = @_;
15173 my $Info = $CompleteSignature{$LibVersion}{$Symbol};
15174 my $Report = "";
15175 foreach my $Pos (sort {int($a)<=>int($b)} keys(%{$Info->{"Param"}}))
15176 {
15177 my $Name = $Info->{"Param"}{$Pos}{"name"};
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040015178 my $Type = $Info->{"Param"}{$Pos}{"type"};
15179 my $TypeName = $TypeInfo{$LibVersion}{$Type}{"Name"};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015180 foreach my $Typedef (keys(%ChangedTypedef))
15181 {
15182 my $Base = $Typedef_BaseName{$LibVersion}{$Typedef};
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040015183 $TypeName=~s/\b\Q$Typedef\E\b/$Base/g;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015184 }
15185 $Report .= " <param pos=\"$Pos\">\n";
15186 $Report .= " <name>".$Name."</name>\n";
15187 $Report .= " <type>".htmlSpecChars($TypeName)."</type>\n";
15188 $Report .= " </param>\n";
15189 }
15190 if(my $Return = $Info->{"Return"})
15191 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040015192 my $RTName = $TypeInfo{$LibVersion}{$Return}{"Name"};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015193 $Report .= " <retval>\n";
15194 $Report .= " <type>".htmlSpecChars($RTName)."</type>\n";
15195 $Report .= " </retval>\n";
15196 }
15197 return $Report;
15198}
15199
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015200sub get_Report_SymbolsInfo($)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015201{
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015202 my $Level = $_[0];
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015203 my $Report = "<symbols_info>\n";
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015204 foreach my $Symbol (sort keys(%{$CompatProblems{$Level}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015205 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015206 my ($SN, $SS, $SV) = separate_symbol($Symbol);
15207 if($SV and defined $CompatProblems{$Level}{$SN}) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015208 next;
15209 }
15210 $Report .= " <symbol name=\"$Symbol\">\n";
15211 my ($S1, $P1, $S2, $P2) = ();
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015212 if(not $AddedInt{$Level}{$Symbol})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015213 {
15214 if(defined $CompleteSignature{1}{$Symbol}
15215 and defined $CompleteSignature{1}{$Symbol}{"Header"})
15216 {
15217 $P1 = get_XmlSign($Symbol, 1);
15218 $S1 = get_Signature($Symbol, 1);
15219 }
15220 elsif($Symbol=~/\A(_Z|\?)/) {
15221 $S1 = $tr_name{$Symbol};
15222 }
15223 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015224 if(not $RemovedInt{$Level}{$Symbol})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015225 {
15226 if(defined $CompleteSignature{2}{$Symbol}
15227 and defined $CompleteSignature{2}{$Symbol}{"Header"})
15228 {
15229 $P2 = get_XmlSign($Symbol, 2);
15230 $S2 = get_Signature($Symbol, 2);
15231 }
15232 elsif($Symbol=~/\A(_Z|\?)/) {
15233 $S2 = $tr_name{$Symbol};
15234 }
15235 }
15236 if($S1)
15237 {
15238 $Report .= " <old signature=\"".htmlSpecChars($S1)."\">\n";
15239 $Report .= $P1;
15240 $Report .= " </old>\n";
15241 }
15242 if($S2 and $S2 ne $S1)
15243 {
15244 $Report .= " <new signature=\"".htmlSpecChars($S2)."\">\n";
15245 $Report .= $P2;
15246 $Report .= " </new>\n";
15247 }
15248 $Report .= " </symbol>\n";
15249 }
15250 $Report .= "</symbols_info>\n";
15251 return $Report;
15252}
15253
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015254sub writeReport($$)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015255{
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015256 my ($Level, $Report) = @_;
15257 if($ReportFormat eq "xml") {
15258 $Report = "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n".$Report;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015259 }
15260 if($StdOut)
15261 { # --stdout option
15262 print STDOUT $Report;
15263 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015264 else
15265 {
15266 my $RPath = getReportPath($Level);
Andrey Ponomarenko85043792012-05-14 16:48:07 +040015267 mkpath(get_dirname($RPath));
15268
15269 open(REPORT, ">", $RPath) || die ("can't open file \'$RPath\': $!\n");
15270 print REPORT $Report;
15271 close(REPORT);
15272
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040015273 if($Browse or $OpenReport)
15274 { # open in browser
15275 openReport($RPath);
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015276 if($JoinReport or $DoubleReport)
15277 {
15278 if($Level eq "Binary")
15279 { # wait to open a browser
15280 sleep(1);
15281 }
15282 }
15283 }
15284 }
15285}
15286
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040015287sub openReport($)
15288{
15289 my $Path = $_[0];
15290 my $Cmd = "";
15291 if($Browse)
15292 { # user-defined browser
15293 $Cmd = $Browse." \"".$Path."\"";
15294 }
15295 if(not $Cmd)
15296 { # default browser
15297 if($OSgroup eq "macos") {
15298 system("open \"".$Path."\"");
15299 }
15300 elsif($OSgroup eq "windows") {
15301 system("start \"".$Path."\"");
15302 }
15303 else
15304 { # linux, freebsd, solaris
15305 my @Browsers = (
15306 "x-www-browser",
15307 "sensible-browser",
15308 "firefox",
15309 "opera",
15310 "xdg-open",
15311 "lynx",
15312 "links"
15313 );
15314 foreach my $Br (@Browsers)
15315 {
15316 if($Br = get_CmdPath($Br))
15317 {
15318 $Cmd = $Br." \"".$Path."\"";
15319 last;
15320 }
15321 }
15322 }
15323 }
15324 if($Cmd)
15325 {
15326 if($Debug) {
15327 printMsg("INFO", "running $Cmd");
15328 }
15329 if($Cmd!~/lynx|links/) {
15330 $Cmd .= " >/dev/null 2>&1 &";
15331 }
15332 system($Cmd);
15333 }
15334 else {
15335 printMsg("ERROR", "cannot open report in browser");
15336 }
15337}
15338
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015339sub getReport($)
15340{
15341 my $Level = $_[0];
15342 if($ReportFormat eq "xml")
15343 { # XML
15344
15345 if($Level eq "Join")
15346 {
15347 my $Report = "<reports>\n";
15348 $Report .= getReport("Binary");
15349 $Report .= getReport("Source");
15350 $Report .= "</reports>\n";
15351 return $Report;
15352 }
15353 else
15354 {
15355 my $Report = "<report kind=\"".lc($Level)."\" version=\"$XML_REPORT_VERSION\">\n\n";
15356 my ($Summary, $MetaData) = get_Summary($Level);
15357 $Report .= $Summary."\n";
15358 $Report .= get_Report_Added($Level).get_Report_Removed($Level);
15359 $Report .= get_Report_Problems("High", $Level).get_Report_Problems("Medium", $Level).get_Report_Problems("Low", $Level).get_Report_Problems("Safe", $Level);
15360 $Report .= get_Report_SymbolsInfo($Level);
15361 $Report .= "</report>\n";
15362 return $Report;
15363 }
15364 }
15365 else
15366 { # HTML
15367 my $CssStyles = readModule("Styles", "Report.css");
15368 my $JScripts = readModule("Scripts", "Sections.js");
15369 if($Level eq "Join")
15370 {
15371 $CssStyles .= "\n".readModule("Styles", "Tabs.css");
15372 $JScripts .= "\n".readModule("Scripts", "Tabs.js");
15373 my $Title = "$TargetLibraryFName: ".$Descriptor{1}{"Version"}." to ".$Descriptor{2}{"Version"}." compatibility report";
15374 my $Keywords = "$TargetLibraryFName, compatibility, API, report";
15375 my $Description = "Compatibility report for the $TargetLibraryFName $TargetComponent between ".$Descriptor{1}{"Version"}." and ".$Descriptor{2}{"Version"}." versions";
15376 my ($BSummary, $BMetaData) = get_Summary("Binary");
15377 my ($SSummary, $SMetaData) = get_Summary("Source");
15378 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>";
15379 $Report .= get_Report_Header("Join")."
15380 <br/><div class='tabset'>
Andrey Ponomarenko16934472012-03-29 15:37:04 +040015381 <a id='BinaryID' href='#BinaryTab' class='tab active'>Binary<br/>Compatibility</a>
15382 <a id='SourceID' href='#SourceTab' style='margin-left:3px' class='tab disabled'>Source<br/>Compatibility</a>
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015383 </div>";
15384 $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>";
15385 $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>";
15386 $Report .= getReportFooter($TargetLibraryFName);
15387 $Report .= "\n<div style='height:999px;'></div>\n</body></html>";
15388 return $Report;
15389 }
15390 else
15391 {
15392 my ($Summary, $MetaData) = get_Summary($Level);
15393 my $Title = "$TargetLibraryFName: ".$Descriptor{1}{"Version"}." to ".$Descriptor{2}{"Version"}." ".lc($Level)." compatibility report";
15394 my $Keywords = "$TargetLibraryFName, ".lc($Level)." compatibility, API, report";
15395 my $Description = "$Level compatibility report for the $TargetLibraryFName $TargetComponent between ".$Descriptor{1}{"Version"}." and ".$Descriptor{2}{"Version"}." versions";
15396 if($Level eq "Binary")
15397 {
15398 if(getArch(1) eq getArch(2)
15399 and getArch(1) ne "unknown") {
15400 $Description .= " on ".showArch(getArch(1));
15401 }
15402 }
15403 my $Report = "<!-\- $MetaData -\->\n".composeHTML_Head($Title, $Keywords, $Description, $CssStyles, $JScripts)."\n<body>\n<div><a name='Top'></a>\n";
15404 $Report .= get_Report_Header($Level)."\n".$Summary."\n";
15405 $Report .= get_Report_Added($Level).get_Report_Removed($Level);
15406 $Report .= get_Report_Problems("High", $Level).get_Report_Problems("Medium", $Level).get_Report_Problems("Low", $Level).get_Report_Problems("Safe", $Level);
15407 $Report .= get_SourceInfo();
15408 $Report .= "</div>\n<br/><br/><br/><hr/>\n";
15409 $Report .= getReportFooter($TargetLibraryFName);
15410 $Report .= "\n<div style='height:999px;'></div>\n</body></html>";
15411 return $Report;
15412 }
15413 }
15414}
15415
Andrey Ponomarenko16934472012-03-29 15:37:04 +040015416sub getLegend()
15417{
15418 return "<br/>
15419<table class='summary'>
15420<tr>
15421 <td class='new'>added</td>
15422 <td class='passed'>compatible</td>
15423</tr>
15424<tr>
15425 <td class='warning'>warning</td>
15426 <td class='failed'>incompatible</td>
15427</tr></table>\n";
15428}
15429
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015430sub createReport()
15431{
15432 if($JoinReport)
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040015433 { # --stdout
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015434 writeReport("Join", getReport("Join"));
15435 }
15436 elsif($DoubleReport)
15437 { # default
15438 writeReport("Binary", getReport("Binary"));
15439 writeReport("Source", getReport("Source"));
15440 }
15441 elsif($BinaryOnly)
15442 { # --binary
15443 writeReport("Binary", getReport("Binary"));
15444 }
15445 elsif($SourceOnly)
15446 { # --source
15447 writeReport("Source", getReport("Source"));
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015448 }
15449}
15450
15451sub getReportFooter($)
15452{
15453 my $LibName = $_[0];
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015454 my $FooterStyle = (not $JoinReport)?"width:99%":"width:97%;padding-top:3px";
15455 my $Footer = "<div style='$FooterStyle;font-size:11px;' align='right'><i>Generated on ".(localtime time); # report date
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015456 $Footer .= " for <span style='font-weight:bold'>$LibName</span>"; # tested library/system name
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015457 $Footer .= " by <a href='".$HomePage{"Wiki"}."'>ABI Compliance Checker</a>"; # tool name
15458 my $ToolSummary = "<br/>A tool for checking backward compatibility of a C/C++ library API&#160;&#160;";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015459 $Footer .= " $TOOL_VERSION &#160;$ToolSummary</i></div>"; # tool version
15460 return $Footer;
15461}
15462
15463sub get_Report_Problems($$)
15464{
15465 my ($Priority, $Level) = @_;
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040015466 my $Report = get_Report_TypeProblems($Priority, $Level);
Andrey Ponomarenko16934472012-03-29 15:37:04 +040015467 if(my $SProblems = get_Report_SymbolProblems($Priority, $Level)) {
15468 $Report .= $SProblems;
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040015469 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015470 if($Priority eq "Low")
15471 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015472 $Report .= get_Report_ChangedConstants($Level);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015473 if($ReportFormat eq "html") {
15474 if($CheckImpl and $Level eq "Binary") {
15475 $Report .= get_Report_Impl();
15476 }
15477 }
15478 }
15479 if($ReportFormat eq "html")
15480 {
15481 if($Report)
15482 { # add anchor
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015483 if($JoinReport)
15484 {
15485 if($Priority eq "Safe") {
15486 $Report = "<a name=\'Other_".$Level."_Changes\'></a>".$Report;
15487 }
15488 else {
15489 $Report = "<a name=\'".$Priority."_Risk_".$Level."_Problems\'></a>".$Report;
15490 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015491 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015492 else
15493 {
15494 if($Priority eq "Safe") {
15495 $Report = "<a name=\'Other_Changes\'></a>".$Report;
15496 }
15497 else {
15498 $Report = "<a name=\'".$Priority."_Risk_Problems\'></a>".$Report;
15499 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015500 }
15501 }
15502 }
15503 return $Report;
15504}
15505
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015506sub composeHTML_Head($$$$$)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015507{
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015508 my ($Title, $Keywords, $Description, $Styles, $Scripts) = @_;
15509 return "<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.0 Transitional//EN\" \"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd\">
15510 <html xmlns=\"http://www.w3.org/1999/xhtml\" xml:lang=\"en\" lang=\"en\">
15511 <head>
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015512 <meta http-equiv=\"Content-Type\" content=\"text/html; charset=utf-8\" />
15513 <meta name=\"keywords\" content=\"$Keywords\" />
15514 <meta name=\"description\" content=\"$Description\" />
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015515 <title>
15516 $Title
15517 </title>
15518 <style type=\"text/css\">
15519 $Styles
15520 </style>
15521 <script type=\"text/javascript\" language=\"JavaScript\">
15522 <!--
15523 $Scripts
15524 -->
15525 </script>
15526 </head>";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015527}
15528
15529sub insertIDs($)
15530{
15531 my $Text = $_[0];
15532 while($Text=~/CONTENT_ID/)
15533 {
15534 if(int($Content_Counter)%2) {
15535 $ContentID -= 1;
15536 }
15537 $Text=~s/CONTENT_ID/c_$ContentID/;
15538 $ContentID += 1;
15539 $Content_Counter += 1;
15540 }
15541 return $Text;
15542}
15543
15544sub checkPreprocessedUnit($)
15545{
15546 my $Path = $_[0];
15547 my $CurHeader = "";
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015548 open(PREPROC, $Path) || die ("can't open file \'$Path\': $!\n");
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015549 while(<PREPROC>)
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015550 { # detecting public and private constants
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015551 next if(not /\A#/);
15552 chomp($_);
15553 if(/#[ \t]+\d+[ \t]+\"(.+)\"/) {
15554 $CurHeader=path_format($1, $OSgroup);
15555 }
15556 if(not $Include_Neighbors{$Version}{get_filename($CurHeader)}
15557 and not $Registered_Headers{$Version}{$CurHeader})
15558 { # not a target
15559 next;
15560 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +040015561 my $HName = get_filename($CurHeader);
15562 if(not is_target_header($HName, 1)
15563 and not is_target_header($HName, 2))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015564 { # user-defined header
15565 next;
15566 }
15567 if(/\#[ \t]*define[ \t]+([_A-Z0-9]+)[ \t]+(.+)[ \t]*\Z/)
15568 {
15569 my ($Name, $Value) = ($1, $2);
15570 if(not $Constants{$Version}{$Name}{"Access"})
15571 {
15572 $Constants{$Version}{$Name}{"Access"} = "public";
15573 $Constants{$Version}{$Name}{"Value"} = $Value;
15574 $Constants{$Version}{$Name}{"Header"} = get_filename($CurHeader);
15575 }
15576 }
15577 elsif(/\#[ \t]*undef[ \t]+([_A-Z]+)[ \t]*/) {
15578 $Constants{$Version}{$1}{"Access"} = "private";
15579 }
15580 }
15581 close(PREPROC);
15582 foreach my $Constant (keys(%{$Constants{$Version}}))
15583 {
15584 if($Constants{$Version}{$Constant}{"Access"} eq "private" or $Constant=~/_h\Z/i
15585 or isBuiltIn($Constants{$Version}{$Constant}{"Header"}))
15586 { # skip private constants
15587 delete($Constants{$Version}{$Constant});
15588 }
15589 else {
15590 delete($Constants{$Version}{$Constant}{"Access"});
15591 }
15592 }
15593}
15594
Andrey Ponomarenko16934472012-03-29 15:37:04 +040015595sub uncoverConstant($$)
15596{
15597 my ($LibVersion, $Constant) = @_;
15598 return "" if(not $LibVersion or not $Constant);
15599 return $Constant if(isCyclical(\@RecurConstant, $Constant));
15600 if(defined $Cache{"uncoverConstant"}{$LibVersion}{$Constant}) {
15601 return $Cache{"uncoverConstant"}{$LibVersion}{$Constant};
15602 }
15603 my $Value = $Constants{$LibVersion}{$Constant}{"Value"};
15604 if(defined $Value)
15605 {
15606 if($Value=~/\A[A-Z0-9_]+\Z/ and $Value=~/[A-Z]/)
15607 {
15608 push(@RecurConstant, $Constant);
15609 my $Uncovered = uncoverConstant($LibVersion, $Value);
15610 if($Uncovered ne "") {
15611 $Value = $Uncovered;
15612 }
15613 pop(@RecurConstant);
15614 }
15615 # FIXME: uncover $Value using all the enum constants
15616 # USECASE: change of define NC_LONG from NC_INT (enum value) to NC_INT (define)
15617 return ($Cache{"uncoverConstant"}{$LibVersion}{$Constant} = $Value);
15618 }
15619 return ($Cache{"uncoverConstant"}{$LibVersion}{$Constant} = "");
15620}
15621
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015622my %IgnoreConstant=(
15623 "VERSION"=>1,
15624 "VERSIONCODE"=>1,
15625 "VERNUM"=>1,
15626 "VERS_INFO"=>1,
15627 "PATCHLEVEL"=>1,
15628 "INSTALLPREFIX"=>1,
15629 "VBUILD"=>1,
15630 "VPATCH"=>1,
15631 "VMINOR"=>1,
15632 "BUILD_STRING"=>1,
15633 "BUILD_TIME"=>1,
15634 "PACKAGE_STRING"=>1,
15635 "PRODUCTION"=>1,
15636 "CONFIGURE_COMMAND"=>1,
15637 "INSTALLDIR"=>1,
15638 "BINDIR"=>1,
15639 "CONFIG_FILE_PATH"=>1,
15640 "DATADIR"=>1,
15641 "EXTENSION_DIR"=>1,
15642 "INCLUDE_PATH"=>1,
15643 "LIBDIR"=>1,
15644 "LOCALSTATEDIR"=>1,
15645 "SBINDIR"=>1,
15646 "SYSCONFDIR"=>1,
15647 "RELEASE"=>1,
15648 "SOURCE_ID"=>1,
15649 "SUBMINOR"=>1,
15650 "MINOR"=>1,
15651 "MINNOR"=>1,
15652 "MINORVERSION"=>1,
15653 "MAJOR"=>1,
15654 "MAJORVERSION"=>1,
15655 "MICRO"=>1,
15656 "MICROVERSION"=>1,
15657 "BINARY_AGE"=>1,
15658 "INTERFACE_AGE"=>1,
15659 "CORE_ABI"=>1,
15660 "PATCH"=>1,
15661 "COPYRIGHT"=>1,
15662 "TIMESTAMP"=>1,
15663 "REVISION"=>1,
15664 "PACKAGE_TAG"=>1,
15665 "PACKAGEDATE"=>1,
15666 "NUMVERSION"=>1
15667);
15668
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015669sub mergeConstants($)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015670{
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015671 my $Level = $_[0];
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015672 foreach my $Constant (keys(%{$Constants{1}}))
15673 {
15674 if($SkipConstants{1}{$Constant})
15675 { # skipped by the user
15676 next;
15677 }
Andrey Ponomarenko16934472012-03-29 15:37:04 +040015678 if(not defined $Constants{2}{$Constant}{"Value"}
15679 or $Constants{2}{$Constant}{"Value"} eq "")
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015680 { # empty value
15681 next;
15682 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +040015683 my $Header = $Constants{1}{$Constant}{"Header"};
15684 if(not is_target_header($Header, 1)
15685 and not is_target_header($Header, 2))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015686 { # user-defined header
15687 next;
15688 }
15689 my ($Old_Value, $New_Value, $Old_Value_Pure, $New_Value_Pure);
Andrey Ponomarenko16934472012-03-29 15:37:04 +040015690 $Old_Value = $Old_Value_Pure = uncoverConstant(1, $Constant);
15691 $New_Value = $New_Value_Pure = uncoverConstant(2, $Constant);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015692 $Old_Value_Pure=~s/(\W)\s+/$1/g;
15693 $Old_Value_Pure=~s/\s+(\W)/$1/g;
15694 $New_Value_Pure=~s/(\W)\s+/$1/g;
15695 $New_Value_Pure=~s/\s+(\W)/$1/g;
15696 next if($New_Value_Pure eq "" or $Old_Value_Pure eq "");
15697 if($New_Value_Pure ne $Old_Value_Pure)
15698 { # different values
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015699 if($Level eq "Binary")
15700 {
15701 if(grep {$Constant=~/(\A|_)$_(_|\Z)/} keys(%IgnoreConstant))
15702 { # ignore library version
15703 next;
15704 }
15705 if($Constant=~/(\A|_)(lib|open|)$TargetLibraryShortName(_|)(VERSION|VER|DATE|API|PREFIX)(_|\Z)/i)
15706 { # ignore library version
15707 next;
15708 }
15709 if($Old_Value=~/\A('|"|)[\/\\]\w+([\/\\]|:|('|"|)\Z)/ or $Old_Value=~/[\/\\]\w+[\/\\]\w+/)
15710 { # ignoring path defines:
Andrey Ponomarenko85043792012-05-14 16:48:07 +040015711 # /lib64:/usr/lib64:/lib:/usr/lib:/usr/X11R6/lib/Xaw3d ...
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015712 next;
15713 }
15714 if($Old_Value=~/\A\(*[a-z_]+(\s+|\|)/i)
15715 { # ignore source defines:
Andrey Ponomarenko85043792012-05-14 16:48:07 +040015716 # static int gcry_pth_init ( void) { return ...
15717 # (RE_BACKSLASH_ESCAPE_IN_LISTS | RE...
15718 next;
15719 }
15720 if($Old_Value=~/\(/i and $Old_Value!~/[\"\']/i)
15721 { # ignore source defines:
15722 # foo(p)
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015723 next;
15724 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015725 }
15726 if(convert_integer($Old_Value) eq convert_integer($New_Value))
15727 { # 0x0001 and 0x1, 0x1 and 1 equal constants
15728 next;
15729 }
15730 if($Old_Value eq "0" and $New_Value eq "NULL")
15731 { # 0 => NULL
15732 next;
15733 }
15734 if($Old_Value eq "NULL" and $New_Value eq "0")
15735 { # NULL => 0
15736 next;
15737 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015738 %{$ProblemsWithConstants{$Level}{$Constant}} = (
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015739 "Target"=>$Constant,
15740 "Old_Value"=>$Old_Value,
15741 "New_Value"=>$New_Value );
15742 }
15743 }
15744}
15745
15746sub convert_integer($)
15747{
15748 my $Value = $_[0];
15749 if($Value=~/\A0x[a-f0-9]+\Z/)
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015750 { # hexadecimal
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015751 return hex($Value);
15752 }
15753 elsif($Value=~/\A0[0-7]+\Z/)
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015754 { # octal
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015755 return oct($Value);
15756 }
15757 elsif($Value=~/\A0b[0-1]+\Z/)
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015758 { # binary
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015759 return oct($Value);
15760 }
15761 else {
15762 return $Value;
15763 }
15764}
15765
Andrey Ponomarenko16934472012-03-29 15:37:04 +040015766sub readSymbols($)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015767{
15768 my $LibVersion = $_[0];
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040015769 my @LibPaths = getSOPaths($LibVersion);
Andrey Ponomarenko16934472012-03-29 15:37:04 +040015770 if($#LibPaths==-1 and not $CheckHeadersOnly)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015771 {
15772 if($LibVersion==1)
15773 {
15774 printMsg("WARNING", "checking headers only");
15775 $CheckHeadersOnly = 1;
15776 }
15777 else {
15778 exitStatus("Error", "$SLIB_TYPE libraries are not found in ".$Descriptor{$LibVersion}{"Version"});
15779 }
15780 }
Andrey Ponomarenko16934472012-03-29 15:37:04 +040015781 my %GroupNames = map {parse_libname(get_filename($_), "name+ext", $OStarget)=>1} @LibPaths;
15782 foreach my $LibPath (sort {length($a)<=>length($b)} @LibPaths) {
15783 readSymbols_Lib($LibVersion, $LibPath, 0, \%GroupNames, "+Weak");
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015784 }
Andrey Ponomarenko16934472012-03-29 15:37:04 +040015785 if(not $CheckHeadersOnly)
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040015786 {
Andrey Ponomarenko16934472012-03-29 15:37:04 +040015787 if($#LibPaths!=-1)
15788 {
15789 if(not keys(%{$Symbol_Library{$LibVersion}}))
15790 {
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040015791 printMsg("WARNING", "the set of public symbols in library(ies) is empty ($LibVersion)");
Andrey Ponomarenko16934472012-03-29 15:37:04 +040015792 printMsg("WARNING", "checking headers only");
15793 $CheckHeadersOnly = 1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015794 }
15795 }
15796 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +040015797
15798 # clean memory
15799 %SystemObjects = ();
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015800}
15801
Andrey Ponomarenko16934472012-03-29 15:37:04 +040015802sub getSymbolSize($$)
15803{ # size from the shared library
15804 my ($Symbol, $LibVersion) = @_;
15805 return 0 if(not $Symbol);
15806 if(defined $Symbol_Library{$LibVersion}{$Symbol}
15807 and my $LibName = $Symbol_Library{$LibVersion}{$Symbol})
15808 {
15809 if(defined $Library_Symbol{$LibVersion}{$LibName}{$Symbol}
15810 and my $Size = $Library_Symbol{$LibVersion}{$LibName}{$Symbol})
15811 {
15812 if($Size<0) {
15813 return -$Size;
15814 }
15815 }
15816 }
15817 return 0;
15818}
15819
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015820sub canonifyName($)
15821{ # make TIFFStreamOpen(char const*, std::basic_ostream<char, std::char_traits<char> >*)
15822 # to be TIFFStreamOpen(char const*, std::basic_ostream<char>*)
15823 my $Name = $_[0];
15824 my $Rem = "std::(allocator|less|char_traits|regex_traits)";
Andrey Ponomarenko85043792012-05-14 16:48:07 +040015825 while($Name=~/([^<>,]+),\s*$Rem<([^<>,]+)>\s*/ and $1 eq $3)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015826 {
Andrey Ponomarenko85043792012-05-14 16:48:07 +040015827 my $P = $1;
15828 $Name=~s/\Q$P\E,\s*$Rem<\Q$P\E>\s*/$P/g;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015829 }
15830 return $Name;
15831}
15832
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040015833sub translateSymbols(@)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015834{
15835 my $LibVersion = pop(@_);
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040015836 my (@MnglNames1, @MnglNames2, @UnmangledNames) = ();
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015837 foreach my $Interface (sort @_)
15838 {
15839 if($Interface=~/\A_Z/)
15840 {
15841 next if($tr_name{$Interface});
15842 $Interface=~s/[\@\$]+(.*)\Z//;
15843 push(@MnglNames1, $Interface);
15844 }
15845 elsif($Interface=~/\A\?/) {
15846 push(@MnglNames2, $Interface);
15847 }
15848 else
15849 { # not mangled
15850 $tr_name{$Interface} = $Interface;
15851 $mangled_name_gcc{$Interface} = $Interface;
15852 $mangled_name{$LibVersion}{$Interface} = $Interface;
15853 }
15854 }
15855 if($#MnglNames1 > -1)
15856 { # GCC names
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040015857 @UnmangledNames = reverse(unmangleArray(@MnglNames1));
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015858 foreach my $MnglName (@MnglNames1)
15859 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040015860 if(my $Unmangled = pop(@UnmangledNames))
15861 {
15862 $tr_name{$MnglName} = formatName(canonifyName($Unmangled));
15863 if(not $mangled_name_gcc{$tr_name{$MnglName}}) {
15864 $mangled_name_gcc{$tr_name{$MnglName}} = $MnglName;
15865 }
15866 if($MnglName=~/\A_ZTV/
15867 and $tr_name{$MnglName}=~/vtable for (.+)/)
15868 { # bind class name and v-table symbol
15869 my $ClassName = $1;
15870 $ClassVTable{$ClassName} = $MnglName;
15871 $VTableClass{$MnglName} = $ClassName;
15872 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015873 }
15874 }
15875 }
15876 if($#MnglNames2 > -1)
15877 { # MSVC names
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040015878 @UnmangledNames = reverse(unmangleArray(@MnglNames2));
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015879 foreach my $MnglName (@MnglNames2)
15880 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040015881 if(my $Unmangled = pop(@UnmangledNames))
15882 {
15883 $tr_name{$MnglName} = formatName($Unmangled);
15884 $mangled_name{$LibVersion}{$tr_name{$MnglName}} = $MnglName;
15885 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015886 }
15887 }
15888 return \%tr_name;
15889}
15890
15891sub link_symbol($$$)
15892{
15893 my ($Symbol, $RunWith, $Deps) = @_;
15894 if(link_symbol_internal($Symbol, $RunWith, \%Symbol_Library)) {
15895 return 1;
15896 }
15897 if($Deps eq "+Deps")
15898 { # check the dependencies
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040015899 if(link_symbol_internal($Symbol, $RunWith, \%DepSymbol_Library)) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015900 return 1;
15901 }
15902 }
15903 return 0;
15904}
15905
15906sub link_symbol_internal($$$)
15907{
15908 my ($Symbol, $RunWith, $Where) = @_;
15909 return 0 if(not $Where or not $Symbol);
15910 if($Where->{$RunWith}{$Symbol})
15911 { # the exact match by symbol name
15912 return 1;
15913 }
15914 if(my $VSym = $SymVer{$RunWith}{$Symbol})
15915 { # indirect symbol version, i.e.
15916 # foo_old and its symlink foo@v (or foo@@v)
15917 # foo_old may be in .symtab table
15918 if($Where->{$RunWith}{$VSym}) {
15919 return 1;
15920 }
15921 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015922 my ($Sym, $Spec, $Ver) = separate_symbol($Symbol);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015923 if($Sym and $Ver)
15924 { # search for the symbol with the same version
15925 # or without version
15926 if($Where->{$RunWith}{$Sym})
15927 { # old: foo@v|foo@@v
15928 # new: foo
15929 return 1;
15930 }
15931 if($Where->{$RunWith}{$Sym."\@".$Ver})
15932 { # old: foo|foo@@v
15933 # new: foo@v
15934 return 1;
15935 }
15936 if($Where->{$RunWith}{$Sym."\@\@".$Ver})
15937 { # old: foo|foo@v
15938 # new: foo@@v
15939 return 1;
15940 }
15941 }
15942 return 0;
15943}
15944
Andrey Ponomarenko16934472012-03-29 15:37:04 +040015945sub readSymbols_App($)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015946{
15947 my $Path = $_[0];
15948 return () if(not $Path or not -f $Path);
15949 my @Imported = ();
15950 if($OSgroup eq "macos")
15951 {
15952 my $OtoolCmd = get_CmdPath("otool");
15953 if(not $OtoolCmd) {
15954 exitStatus("Not_Found", "can't find \"otool\"");
15955 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015956 open(APP, "$OtoolCmd -IV \"".$Path."\" 2>$TMP_DIR/null |");
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015957 while(<APP>) {
15958 if(/[^_]+\s+_?([\w\$]+)\s*\Z/) {
15959 push(@Imported, $1);
15960 }
15961 }
15962 close(APP);
15963 }
15964 elsif($OSgroup eq "windows")
15965 {
15966 my $DumpBinCmd = get_CmdPath("dumpbin");
15967 if(not $DumpBinCmd) {
15968 exitStatus("Not_Found", "can't find \"dumpbin.exe\"");
15969 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015970 open(APP, "$DumpBinCmd /IMPORTS \"".$Path."\" 2>$TMP_DIR/null |");
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015971 while(<APP>) {
15972 if(/\s*\w+\s+\w+\s+\w+\s+([\w\?\@]+)\s*/) {
15973 push(@Imported, $1);
15974 }
15975 }
15976 close(APP);
15977 }
15978 else
15979 {
15980 my $ReadelfCmd = get_CmdPath("readelf");
15981 if(not $ReadelfCmd) {
15982 exitStatus("Not_Found", "can't find \"readelf\"");
15983 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015984 open(APP, "$ReadelfCmd -WhlSsdA \"".$Path."\" 2>$TMP_DIR/null |");
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015985 my $symtab=0; # indicates that we are processing 'symtab' section of 'readelf' output
15986 while(<APP>)
15987 {
15988 if( /'.dynsym'/ ) {
15989 $symtab=0;
15990 }
15991 elsif($symtab == 1) {
15992 # do nothing with symtab (but there are some plans for the future)
15993 next;
15994 }
15995 elsif( /'.symtab'/ ) {
15996 $symtab=1;
15997 }
15998 elsif(my ($fullname, $idx, $Ndx, $type, $size, $bind) = readline_ELF($_))
15999 {
16000 if( $Ndx eq "UND" ) {
16001 #only imported symbols
16002 push(@Imported, $fullname);
16003 }
16004 }
16005 }
16006 close(APP);
16007 }
16008 return @Imported;
16009}
16010
16011sub readline_ELF($)
16012{
16013 if($_[0]=~/\s*\d+:\s+(\w*)\s+(\w+)\s+(\w+)\s+(\w+)\s+(\w+)\s+(\w+)\s([^\s]+)/)
16014 { # the line of 'readelf' output corresponding to the interface
16015 # symbian-style: _ZN12CCTTokenType4NewLE4TUid3RFs@@ctfinder{000a0000}[102020e5].dll
16016 my ($value, $size, $type, $bind,
16017 $vis, $Ndx, $fullname)=($1, $2, $3, $4, $5, $6, $7);
16018 if($bind!~/\A(WEAK|GLOBAL)\Z/) {
16019 return ();
16020 }
16021 if($type!~/\A(FUNC|IFUNC|OBJECT|COMMON)\Z/) {
16022 return ();
16023 }
16024 if($vis!~/\A(DEFAULT|PROTECTED)\Z/) {
16025 return ();
16026 }
16027 if($Ndx eq "ABS" and $value!~/\D|1|2|3|4|5|6|7|8|9/) {
16028 return ();
16029 }
16030 if($OStarget eq "symbian")
16031 {
16032 if($fullname=~/_\._\.absent_export_\d+/)
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040016033 { # "_._.absent_export_111"@@libstdcpp{00010001}[10282872].dll
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040016034 return ();
16035 }
16036 my @Elems = separate_symbol($fullname);
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040016037 $fullname = $Elems[0]; # remove internal version, {00020001}[10011235].dll
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040016038 }
16039 return ($fullname, $value, $Ndx, $type, $size, $bind);
16040 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040016041 return ();
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040016042}
16043
Andrey Ponomarenko16934472012-03-29 15:37:04 +040016044sub read_symlink($)
16045{
16046 my $Path = $_[0];
16047 return "" if(not $Path);
16048 return "" if(not -f $Path and not -l $Path);
16049 if(defined $Cache{"read_symlink"}{$Path}) {
16050 return $Cache{"read_symlink"}{$Path};
16051 }
16052 if(my $Res = readlink($Path)) {
16053 return ($Cache{"read_symlink"}{$Path} = $Res);
16054 }
16055 elsif(my $ReadlinkCmd = get_CmdPath("readlink")) {
16056 return ($Cache{"read_symlink"}{$Path} = `$ReadlinkCmd -n $Path`);
16057 }
16058 elsif(my $FileCmd = get_CmdPath("file"))
16059 {
16060 my $Info = `$FileCmd $Path`;
16061 if($Info=~/symbolic\s+link\s+to\s+['`"]*([\w\d\.\-\/\\]+)['`"]*/i) {
16062 return ($Cache{"read_symlink"}{$Path} = $1);
16063 }
16064 }
16065 return ($Cache{"read_symlink"}{$Path} = "");
16066}
16067
16068sub resolve_symlink($)
16069{
16070 my $Path = $_[0];
16071 return "" if(not $Path);
16072 return "" if(not -f $Path and not -l $Path);
16073 if(defined $Cache{"resolve_symlink"}{$Path}) {
16074 return $Cache{"resolve_symlink"}{$Path};
16075 }
16076 return $Path if(isCyclical(\@RecurSymlink, $Path));
16077 push(@RecurSymlink, $Path);
16078 if(-l $Path and my $Redirect=read_symlink($Path))
16079 {
16080 if(is_abs($Redirect))
16081 { # absolute path
16082 if($SystemRoot and $SystemRoot ne "/"
16083 and $Path=~/\A\Q$SystemRoot\E\//
16084 and (-f $SystemRoot.$Redirect or -l $SystemRoot.$Redirect))
16085 { # symbolic links from the sysroot
16086 # should be corrected to point to
16087 # the files inside sysroot
16088 $Redirect = $SystemRoot.$Redirect;
16089 }
16090 my $Res = resolve_symlink($Redirect);
16091 pop(@RecurSymlink);
16092 return ($Cache{"resolve_symlink"}{$Path} = $Res);
16093 }
16094 elsif($Redirect=~/\.\.[\/\\]/)
16095 { # relative path
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040016096 $Redirect = joinPath(get_dirname($Path), $Redirect);
Andrey Ponomarenko16934472012-03-29 15:37:04 +040016097 while($Redirect=~s&(/|\\)[^\/\\]+(\/|\\)\.\.(\/|\\)&$1&){};
16098 my $Res = resolve_symlink($Redirect);
16099 pop(@RecurSymlink);
16100 return ($Cache{"resolve_symlink"}{$Path} = $Res);
16101 }
16102 elsif(-f get_dirname($Path)."/".$Redirect)
16103 { # file name in the same directory
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040016104 my $Res = resolve_symlink(joinPath(get_dirname($Path), $Redirect));
Andrey Ponomarenko16934472012-03-29 15:37:04 +040016105 pop(@RecurSymlink);
16106 return ($Cache{"resolve_symlink"}{$Path} = $Res);
16107 }
16108 else
16109 { # broken link
16110 pop(@RecurSymlink);
16111 return ($Cache{"resolve_symlink"}{$Path} = "");
16112 }
16113 }
16114 pop(@RecurSymlink);
16115 return ($Cache{"resolve_symlink"}{$Path} = $Path);
16116}
16117
16118sub find_lib_path($$)
16119{
16120 my ($LibVersion, $DyLib) = @_;
16121 return "" if(not $DyLib or not $LibVersion);
16122 return $DyLib if(is_abs($DyLib));
16123 if(defined $Cache{"find_lib_path"}{$LibVersion}{$DyLib}) {
16124 return $Cache{"find_lib_path"}{$LibVersion}{$DyLib};
16125 }
16126 if(my @Paths = sort keys(%{$InputObject_Paths{$LibVersion}{$DyLib}})) {
16127 return ($Cache{"find_lib_path"}{$LibVersion}{$DyLib} = $Paths[0]);
16128 }
16129 elsif(my $DefaultPath = $DyLib_DefaultPath{$DyLib}) {
16130 return ($Cache{"find_lib_path"}{$LibVersion}{$DyLib} = $DefaultPath);
16131 }
16132 else
16133 {
16134 foreach my $Dir (sort keys(%DefaultLibPaths), sort keys(%{$SystemPaths{"lib"}}))
16135 { # search in default linker paths and then in all system paths
16136 if(-f $Dir."/".$DyLib) {
16137 return ($Cache{"find_lib_path"}{$LibVersion}{$DyLib} = joinPath($Dir,$DyLib));
16138 }
16139 }
16140 detectSystemObjects() if(not keys(%SystemObjects));
16141 if(my @AllObjects = keys(%{$SystemObjects{$DyLib}})) {
16142 return ($Cache{"find_lib_path"}{$LibVersion}{$DyLib} = $AllObjects[0]);
16143 }
16144 my $ShortName = parse_libname($DyLib, "name+ext", $OStarget);
16145 if($ShortName ne $DyLib
16146 and my $Path = find_lib_path($ShortName))
16147 { # FIXME: check this case
16148 return ($Cache{"find_lib_path"}{$LibVersion}{$DyLib} = $Path);
16149 }
16150 return ($Cache{"find_lib_path"}{$LibVersion}{$DyLib} = "");
16151 }
16152}
16153
16154sub readSymbols_Lib($$$$$)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040016155{
16156 my ($LibVersion, $Lib_Path, $IsNeededLib, $GroupNames, $Weak) = @_;
16157 return if(not $Lib_Path or not -f $Lib_Path);
16158 my ($Lib_Dir, $Lib_Name) = separate_path(resolve_symlink($Lib_Path));
16159 return if($CheckedDyLib{$LibVersion}{$Lib_Name} and $IsNeededLib);
16160 return if(isCyclical(\@RecurLib, $Lib_Name) or $#RecurLib>=1);
16161 $CheckedDyLib{$LibVersion}{$Lib_Name} = 1;
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040016162 my $Lib_SName = parse_libname($Lib_Name, "name+ext", $OStarget);
16163
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040016164 if($CheckImpl and not $IsNeededLib) {
16165 getImplementations($LibVersion, $Lib_Path);
16166 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040016167
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040016168 push(@RecurLib, $Lib_Name);
16169 my (%Value_Interface, %Interface_Value, %NeededLib) = ();
16170 if(not $IsNeededLib)
16171 { # libstdc++ and libc are always used by other libs
16172 # if you test one of these libs then you not need
16173 # to find them in the system for reusing
16174 if(parse_libname($Lib_Name, "short", $OStarget) eq "libstdc++")
16175 { # libstdc++.so.6
16176 $STDCXX_TESTING = 1;
16177 }
16178 if(parse_libname($Lib_Name, "short", $OStarget) eq "libc")
16179 { # libc-2.11.3.so
16180 $GLIBC_TESTING = 1;
16181 }
16182 }
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040016183 my $DebugPath = "";
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040016184 if($Debug)
16185 { # debug mode
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040016186 $DebugPath = $DEBUG_PATH{$LibVersion}."/libs/".get_filename($Lib_Path).".txt";
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040016187 mkpath(get_dirname($DebugPath));
16188 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040016189 if($OStarget eq "macos")
16190 { # Mac OS X: *.dylib, *.a
16191 my $OtoolCmd = get_CmdPath("otool");
16192 if(not $OtoolCmd) {
16193 exitStatus("Not_Found", "can't find \"otool\"");
16194 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040016195 $OtoolCmd .= " -TV \"".$Lib_Path."\" 2>$TMP_DIR/null";
16196 if($Debug)
16197 { # debug mode
Andrey Ponomarenko16934472012-03-29 15:37:04 +040016198 # write to file
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040016199 system($OtoolCmd." >".$DebugPath);
Andrey Ponomarenko16934472012-03-29 15:37:04 +040016200 open(LIB, $DebugPath);
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040016201 }
Andrey Ponomarenko16934472012-03-29 15:37:04 +040016202 else
16203 { # write to pipe
16204 open(LIB, $OtoolCmd." |");
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040016205 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040016206 while(<LIB>)
16207 {
16208 if(/[^_]+\s+_([\w\$]+)\s*\Z/)
16209 {
16210 my $realname = $1;
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040016211 if($IsNeededLib)
16212 {
16213 if(not $GroupNames->{$Lib_SName})
16214 {
16215 $DepSymbol_Library{$LibVersion}{$realname} = $Lib_Name;
16216 $DepLibrary_Symbol{$LibVersion}{$Lib_Name}{$realname} = 1;
16217 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040016218 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040016219 else
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040016220 {
16221 $Symbol_Library{$LibVersion}{$realname} = $Lib_Name;
16222 $Library_Symbol{$LibVersion}{$Lib_Name}{$realname} = 1;
16223 if($COMMON_LANGUAGE{$LibVersion} ne "C++"
16224 and $realname=~/\A(_Z|\?)/) {
16225 setLanguage($LibVersion, "C++");
16226 }
16227 if($CheckObjectsOnly
16228 and $LibVersion==1) {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040016229 $CheckedSymbols{"Binary"}{$realname} = 1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040016230 }
16231 }
16232 }
16233 }
16234 close(LIB);
16235 if($LIB_TYPE eq "dynamic")
16236 { # dependencies
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040016237 open(LIB, "$OtoolCmd -L \"".$Lib_Path."\" 2>$TMP_DIR/null |");
16238 while(<LIB>)
16239 {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040016240 if(/\s*([\/\\].+\.$LIB_EXT)\s*/
16241 and $1 ne $Lib_Path) {
16242 $NeededLib{$1} = 1;
16243 }
16244 }
16245 close(LIB);
16246 }
16247 }
16248 elsif($OStarget eq "windows")
16249 { # Windows *.dll, *.lib
16250 my $DumpBinCmd = get_CmdPath("dumpbin");
16251 if(not $DumpBinCmd) {
16252 exitStatus("Not_Found", "can't find \"dumpbin\"");
16253 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040016254 $DumpBinCmd .= " /EXPORTS \"".$Lib_Path."\" 2>$TMP_DIR/null";
16255 if($Debug)
16256 { # debug mode
Andrey Ponomarenko16934472012-03-29 15:37:04 +040016257 # write to file
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040016258 system($DumpBinCmd." >".$DebugPath);
Andrey Ponomarenko16934472012-03-29 15:37:04 +040016259 open(LIB, $DebugPath);
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040016260 }
Andrey Ponomarenko16934472012-03-29 15:37:04 +040016261 else
16262 { # write to pipe
16263 open(LIB, $DumpBinCmd." |");
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040016264 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040016265 while(<LIB>)
16266 { # 1197 4AC 0000A620 SetThreadStackGuarantee
16267 # 1198 4AD SetThreadToken (forwarded to ...)
16268 # 3368 _o2i_ECPublicKey
16269 if(/\A\s*\d+\s+[a-f\d]+\s+[a-f\d]+\s+([\w\?\@]+)\s*\Z/i
16270 or /\A\s*\d+\s+[a-f\d]+\s+([\w\?\@]+)\s*\(\s*forwarded\s+/
16271 or /\A\s*\d+\s+_([\w\?\@]+)\s*\Z/)
16272 { # dynamic, static and forwarded symbols
16273 my $realname = $1;
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040016274 if($IsNeededLib)
16275 {
16276 if(not $GroupNames->{$Lib_SName})
16277 {
16278 $DepSymbol_Library{$LibVersion}{$realname} = $Lib_Name;
16279 $DepLibrary_Symbol{$LibVersion}{$Lib_Name}{$realname} = 1;
16280 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040016281 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040016282 else
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040016283 {
16284 $Symbol_Library{$LibVersion}{$realname} = $Lib_Name;
16285 $Library_Symbol{$LibVersion}{$Lib_Name}{$realname} = 1;
16286 if($COMMON_LANGUAGE{$LibVersion} ne "C++"
16287 and $realname=~/\A(_Z|\?)/) {
16288 setLanguage($LibVersion, "C++");
16289 }
16290 if($CheckObjectsOnly
16291 and $LibVersion==1) {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040016292 $CheckedSymbols{"Binary"}{$realname} = 1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040016293 }
16294 }
16295 }
16296 }
16297 close(LIB);
16298 if($LIB_TYPE eq "dynamic")
16299 { # dependencies
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040016300 open(LIB, "$DumpBinCmd /DEPENDENTS \"".$Lib_Path."\" 2>$TMP_DIR/null |");
16301 while(<LIB>)
16302 {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040016303 if(/\s*([^\s]+?\.$LIB_EXT)\s*/i
16304 and $1 ne $Lib_Path) {
16305 $NeededLib{path_format($1, $OSgroup)} = 1;
16306 }
16307 }
16308 close(LIB);
16309 }
16310 }
16311 else
16312 { # Unix; *.so, *.a
16313 # Symbian: *.dso, *.lib
16314 my $ReadelfCmd = get_CmdPath("readelf");
16315 if(not $ReadelfCmd) {
16316 exitStatus("Not_Found", "can't find \"readelf\"");
16317 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040016318 $ReadelfCmd .= " -WhlSsdA \"".$Lib_Path."\" 2>$TMP_DIR/null";
16319 if($Debug)
16320 { # debug mode
Andrey Ponomarenko16934472012-03-29 15:37:04 +040016321 # write to file
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040016322 system($ReadelfCmd." >".$DebugPath);
Andrey Ponomarenko16934472012-03-29 15:37:04 +040016323 open(LIB, $DebugPath);
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040016324 }
Andrey Ponomarenko16934472012-03-29 15:37:04 +040016325 else
16326 { # write to pipe
16327 open(LIB, $ReadelfCmd." |");
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040016328 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040016329 my $symtab=0; # indicates that we are processing 'symtab' section of 'readelf' output
16330 while(<LIB>)
16331 {
16332 if($LIB_TYPE eq "dynamic")
16333 { # dynamic library specifics
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040016334 if($symtab==1)
16335 {
16336 if(/'\.dynsym'/)
16337 { # dynamic table
16338 $symtab=0;
16339 next;
16340 }
16341 else
16342 { # do nothing with symtab
16343 next;
16344 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040016345 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040016346 elsif(/'\.symtab'/)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040016347 { # symbol table
16348 $symtab=1;
16349 next;
16350 }
16351 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040016352 if(my ($fullname, $idx, $Ndx, $type, $size, $bind) = readline_ELF($_))
16353 { # read ELF entry
16354 if( $Ndx eq "UND" )
16355 { # ignore interfaces that are imported from somewhere else
16356 next;
16357 }
16358 if($bind eq "WEAK"
16359 and $Weak eq "-Weak")
16360 { # skip WEAK symbols
16361 next;
16362 }
16363 my ($realname, $version_spec, $version) = separate_symbol($fullname);
16364 if($type eq "OBJECT")
16365 { # global data
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040016366 $GlobalDataObject{$LibVersion}{$fullname} = 1;
16367 $GlobalDataObject{$LibVersion}{$realname} = 1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040016368 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040016369 if($IsNeededLib)
16370 {
16371 if(not $GroupNames->{$Lib_SName})
16372 {
16373 $DepSymbol_Library{$LibVersion}{$fullname} = $Lib_Name;
16374 $DepLibrary_Symbol{$LibVersion}{$Lib_Name}{$fullname} = ($type eq "OBJECT")?-$size:1;
16375 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040016376 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040016377 else
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040016378 {
16379 $Symbol_Library{$LibVersion}{$fullname} = $Lib_Name;
16380 $Library_Symbol{$LibVersion}{$Lib_Name}{$fullname} = ($type eq "OBJECT")?-$size:1;
16381 if($LIB_EXT eq "so")
16382 { # value
16383 $Interface_Value{$LibVersion}{$fullname} = $idx;
16384 $Value_Interface{$LibVersion}{$idx}{$fullname} = 1;
16385 }
16386 if($COMMON_LANGUAGE{$LibVersion} ne "C++"
16387 and $realname=~/\A(_Z|\?)/) {
16388 setLanguage($LibVersion, "C++");
16389 }
16390 if($CheckObjectsOnly
16391 and $LibVersion==1) {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040016392 $CheckedSymbols{"Binary"}{$fullname} = 1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040016393 }
16394 }
16395 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040016396 elsif($LIB_TYPE eq "dynamic")
16397 { # dynamic library specifics
16398 if(/NEEDED.+\[([^\[\]]+)\]/)
16399 { # dependencies:
16400 # 0x00000001 (NEEDED) Shared library: [libc.so.6]
16401 $NeededLib{$1} = 1;
16402 }
16403 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040016404 }
16405 close(LIB);
16406 }
16407 if(not $IsNeededLib and $LIB_EXT eq "so")
16408 { # get symbol versions
16409 foreach my $Symbol (keys(%{$Symbol_Library{$LibVersion}}))
16410 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040016411 next if(index($Symbol,"\@")==-1);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040016412 my $Interface_SymName = "";
16413 foreach my $Symbol_SameValue (keys(%{$Value_Interface{$LibVersion}{$Interface_Value{$LibVersion}{$Symbol}}}))
16414 {
16415 if($Symbol_SameValue ne $Symbol
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040016416 and index($Symbol_SameValue,"\@")==-1)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040016417 {
16418 $SymVer{$LibVersion}{$Symbol_SameValue} = $Symbol;
16419 $Interface_SymName = $Symbol_SameValue;
16420 last;
16421 }
16422 }
16423 if(not $Interface_SymName)
16424 {
16425 if($Symbol=~/\A([^\@\$\?]*)[\@\$]+([^\@\$]*)\Z/
16426 and not $SymVer{$LibVersion}{$1}) {
16427 $SymVer{$LibVersion}{$1} = $Symbol;
16428 }
16429 }
16430 }
16431 }
16432 foreach my $DyLib (sort keys(%NeededLib))
16433 {
16434 my $DepPath = find_lib_path($LibVersion, $DyLib);
16435 if($DepPath and -f $DepPath) {
Andrey Ponomarenko16934472012-03-29 15:37:04 +040016436 readSymbols_Lib($LibVersion, $DepPath, 1, $GroupNames, "+Weak");
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040016437 }
16438 }
16439 pop(@RecurLib);
16440 return $Library_Symbol{$LibVersion};
16441}
16442
16443sub get_path_prefixes($)
16444{
16445 my $Path = $_[0];
16446 my ($Dir, $Name) = separate_path($Path);
16447 my %Prefixes = ();
16448 foreach my $Prefix (reverse(split(/[\/\\]+/, $Dir)))
16449 {
16450 $Prefixes{$Name} = 1;
16451 $Name = joinPath($Prefix, $Name);
16452 last if(keys(%Prefixes)>5 or $Prefix eq "include");
16453 }
16454 return keys(%Prefixes);
16455}
16456
16457sub detectSystemHeaders()
16458{
16459 my @SysHeaders = ();
16460 foreach my $DevelPath (keys(%{$SystemPaths{"include"}}))
16461 {
16462 next if(not -d $DevelPath);
16463 # search for all header files in the /usr/include
16464 # with or without extension (ncurses.h, QtCore, ...)
16465 @SysHeaders = (@SysHeaders, cmd_find($DevelPath,"f","",""));
16466 foreach my $Link (cmd_find($DevelPath,"l","",""))
16467 { # add symbolic links
16468 if(-f $Link) {
16469 push(@SysHeaders, $Link);
16470 }
16471 }
16472 }
16473 foreach my $DevelPath (keys(%{$SystemPaths{"lib"}}))
16474 {
16475 next if(not -d $DevelPath);
16476 # search for config headers in the /usr/lib
16477 @SysHeaders = (@SysHeaders, cmd_find($DevelPath,"f","*.h",""));
16478 foreach my $Dir (cmd_find($DevelPath,"d","include",""))
16479 { # search for all include directories
16480 # this is for headers that are installed to /usr/lib
16481 # Example: Qt4 headers in Mandriva (/usr/lib/qt4/include/)
16482 if($Dir=~/\/(gcc|jvm|syslinux|kdb)\//) {
16483 next;
16484 }
16485 @SysHeaders = (@SysHeaders, cmd_find($Dir,"f","",""));
16486 }
16487 }
16488 foreach my $Path (@SysHeaders)
16489 {
16490 foreach my $Part (get_path_prefixes($Path)) {
16491 $SystemHeaders{$Part}{$Path}=1;
16492 }
16493 }
16494}
16495
16496sub detectSystemObjects()
16497{
16498 foreach my $DevelPath (keys(%{$SystemPaths{"lib"}}))
16499 {
16500 next if(not -d $DevelPath);
16501 foreach my $Path (find_libs($DevelPath,"",""))
16502 { # search for shared libraries in the /usr/lib (including symbolic links)
16503 $SystemObjects{parse_libname(get_filename($Path), "name+ext", $OStarget)}{$Path}=1;
16504 }
16505 }
16506}
16507
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040016508sub getSOPaths($)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040016509{
16510 my $LibVersion = $_[0];
16511 my @SoPaths = ();
16512 foreach my $Dest (split(/\s*\n\s*/, $Descriptor{$LibVersion}{"Libs"}))
16513 {
16514 if(not -e $Dest) {
16515 exitStatus("Access_Error", "can't access \'$Dest\'");
16516 }
16517 my @SoPaths_Dest = getSOPaths_Dest($Dest, $LibVersion);
16518 foreach (@SoPaths_Dest) {
16519 push(@SoPaths, $_);
16520 }
16521 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040016522 return sort @SoPaths;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040016523}
16524
16525sub skip_lib($$)
16526{
16527 my ($Path, $LibVersion) = @_;
16528 return 1 if(not $Path or not $LibVersion);
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040016529 my $Name = get_filename($Path);
16530 if($SkipLibs{$LibVersion}{"Name"}{$Name}) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040016531 return 1;
16532 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040016533 my $ShortName = parse_libname($Name, "name+ext", $OStarget);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040016534 if($SkipLibs{$LibVersion}{"Name"}{$ShortName}) {
16535 return 1;
16536 }
16537 foreach my $Dir (keys(%{$SkipLibs{$LibVersion}{"Path"}}))
16538 {
16539 if($Path=~/\Q$Dir\E([\/\\]|\Z)/) {
16540 return 1;
16541 }
16542 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040016543 foreach my $P (keys(%{$SkipLibs{$LibVersion}{"Pattern"}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040016544 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040016545 if($Name=~/$P/) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040016546 return 1;
16547 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040016548 if($P=~/[\/\\]/ and $Path=~/$P/) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040016549 return 1;
16550 }
16551 }
16552 return 0;
16553}
16554
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040016555sub skipHeader($$)
16556{
16557 my ($Path, $LibVersion) = @_;
16558 return 1 if(not $Path or not $LibVersion);
16559 if(not keys(%{$SkipHeaders{$LibVersion}})) {
16560 return 0;
16561 }
16562 if(defined $Cache{"skipHeader"}{$Path}) {
16563 return $Cache{"skipHeader"}{$Path};
16564 }
16565 return ($Cache{"skipHeader"}{$Path} = skipHeader_I(@_));
16566}
16567
16568sub skipHeader_I($$)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040016569{ # returns:
16570 # 1 - if header should NOT be included and checked
16571 # 2 - if header should NOT be included, but should be checked
16572 my ($Path, $LibVersion) = @_;
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040016573 my $Name = get_filename($Path);
16574 if(my $Kind = $SkipHeaders{$LibVersion}{"Name"}{$Name}) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040016575 return $Kind;
16576 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040016577 foreach my $D (keys(%{$SkipHeaders{$LibVersion}{"Path"}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040016578 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040016579 if($Path=~/\Q$D\E([\/\\]|\Z)/) {
16580 return $SkipHeaders{$LibVersion}{"Path"}{$D};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040016581 }
16582 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040016583 foreach my $P (keys(%{$SkipHeaders{$LibVersion}{"Pattern"}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040016584 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040016585 if(my $Kind = $SkipHeaders{$LibVersion}{"Pattern"}{$P})
16586 {
16587 if($Name=~/$P/) {
16588 return $Kind;
16589 }
16590 if($P=~/[\/\\]/ and $Path=~/$P/) {
16591 return $Kind;
16592 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040016593 }
16594 }
16595 return 0;
16596}
16597
16598sub register_objects($$)
16599{
16600 my ($Dir, $LibVersion) = @_;
16601 if($SystemPaths{"lib"}{$Dir})
16602 { # system directory
16603 return;
16604 }
16605 if($RegisteredObjDirs{$LibVersion}{$Dir})
16606 { # already registered
16607 return;
16608 }
16609 foreach my $Path (find_libs($Dir,"",1))
16610 {
16611 next if(ignore_path($Path));
16612 next if(skip_lib($Path, $LibVersion));
16613 $InputObject_Paths{$LibVersion}{get_filename($Path)}{$Path} = 1;
16614 }
16615 $RegisteredObjDirs{$LibVersion}{$Dir} = 1;
16616}
16617
16618sub getSOPaths_Dest($$)
16619{
16620 my ($Dest, $LibVersion) = @_;
16621 if(skip_lib($Dest, $LibVersion)) {
16622 return ();
16623 }
16624 if(-f $Dest)
16625 {
16626 if(not parse_libname($Dest, "name", $OStarget)) {
16627 exitStatus("Error", "incorrect format of library (should be *.$LIB_EXT): \'$Dest\'");
16628 }
16629 $InputObject_Paths{$LibVersion}{get_filename($Dest)}{$Dest} = 1;
16630 register_objects(get_dirname($Dest), $LibVersion);
16631 return ($Dest);
16632 }
16633 elsif(-d $Dest)
16634 {
16635 $Dest=~s/[\/\\]+\Z//g;
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040016636 my %Libs = ();
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040016637 if($SystemPaths{"lib"}{$Dest})
16638 { # you have specified /usr/lib as the search directory (<libs>) in the XML descriptor
16639 # and the real name of the library by -l option (bz2, stdc++, Xaw, ...)
16640 foreach my $Path (cmd_find($Dest,"","*".esc($TargetLibraryName)."*\.$LIB_EXT*",2))
16641 { # all files and symlinks that match the name of a library
16642 if(get_filename($Path)=~/\A(|lib)\Q$TargetLibraryName\E[\d\-]*\.$LIB_EXT[\d\.]*\Z/i)
16643 {
16644 $InputObject_Paths{$LibVersion}{get_filename($Path)}{$Path} = 1;
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040016645 $Libs{resolve_symlink($Path)}=1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040016646 }
16647 }
16648 }
16649 else
16650 { # search for all files and symlinks
16651 foreach my $Path (find_libs($Dest,"",""))
16652 {
16653 next if(ignore_path($Path));
16654 next if(skip_lib($Path, $LibVersion));
16655 $InputObject_Paths{$LibVersion}{get_filename($Path)}{$Path} = 1;
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040016656 $Libs{resolve_symlink($Path)}=1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040016657 }
16658 if($OSgroup eq "macos")
16659 { # shared libraries on MacOS X may have no extension
16660 foreach my $Path (cmd_find($Dest,"f","",""))
16661 {
16662 next if(ignore_path($Path));
16663 next if(skip_lib($Path, $LibVersion));
16664 if(get_filename($Path)!~/\./
Andrey Ponomarenko85043792012-05-14 16:48:07 +040016665 and cmd_file($Path)=~/(shared|dynamic)\s+library/i)
16666 {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040016667 $InputObject_Paths{$LibVersion}{get_filename($Path)}{$Path} = 1;
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040016668 $Libs{resolve_symlink($Path)}=1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040016669 }
16670 }
16671 }
16672 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040016673 return keys(%Libs);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040016674 }
16675 else {
16676 return ();
16677 }
16678}
16679
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040016680sub isCyclical($$)
16681{
16682 my ($Stack, $Value) = @_;
16683 return (grep {$_ eq $Value} @{$Stack});
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040016684}
16685
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040016686sub generateTemplate()
16687{
16688 writeFile("VERSION.xml", $DescriptorTemplate."\n");
16689 printMsg("INFO", "XML-descriptor template ./VERSION.xml has been generated");
16690}
16691
16692sub detectWordSize()
16693{
16694 return "" if(not $GCC_PATH);
16695 if($Cache{"detectWordSize"}) {
16696 return $Cache{"detectWordSize"};
16697 }
16698 writeFile("$TMP_DIR/empty.h", "");
16699 my $Defines = `$GCC_PATH -E -dD $TMP_DIR/empty.h`;
16700 unlink("$TMP_DIR/empty.h");
16701 my $WSize = 0;
16702 if($Defines=~/ __SIZEOF_POINTER__\s+(\d+)/)
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040016703 { # GCC 4
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040016704 $WSize = $1;
16705 }
16706 elsif($Defines=~/ __PTRDIFF_TYPE__\s+(\w+)/)
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040016707 { # GCC 3
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040016708 my $PTRDIFF = $1;
16709 if($PTRDIFF=~/long/) {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040016710 $WSize = "8";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040016711 }
16712 else {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040016713 $WSize = "4";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040016714 }
16715 }
16716 if(not int($WSize)) {
16717 exitStatus("Error", "can't check WORD size");
16718 }
16719 return ($Cache{"detectWordSize"} = $WSize);
16720}
16721
16722sub majorVersion($)
16723{
16724 my $V = $_[0];
16725 return 0 if(not $V);
16726 my @VParts = split(/\./, $V);
16727 return $VParts[0];
16728}
16729
16730sub cmpVersions($$)
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040016731{ # compare two versions in dotted-numeric format
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040016732 my ($V1, $V2) = @_;
16733 return 0 if($V1 eq $V2);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040016734 my @V1Parts = split(/\./, $V1);
16735 my @V2Parts = split(/\./, $V2);
16736 for (my $i = 0; $i <= $#V1Parts && $i <= $#V2Parts; $i++) {
16737 return -1 if(int($V1Parts[$i]) < int($V2Parts[$i]));
16738 return 1 if(int($V1Parts[$i]) > int($V2Parts[$i]));
16739 }
16740 return -1 if($#V1Parts < $#V2Parts);
16741 return 1 if($#V1Parts > $#V2Parts);
16742 return 0;
16743}
16744
16745sub read_ABI_Dump($$)
16746{
16747 my ($LibVersion, $Path) = @_;
16748 return if(not $LibVersion or not -e $Path);
16749 my $FilePath = "";
16750 if($Path=~/\.abi\Z/)
16751 { # input *.abi
16752 $FilePath = $Path;
16753 }
16754 else
16755 { # input *.abi.tar.gz
16756 $FilePath = unpackDump($Path);
16757 }
16758 if($FilePath!~/\.abi\Z/) {
16759 exitStatus("Invalid_Dump", "specified ABI dump \'$Path\' is not valid, try to recreate it");
16760 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +040016761
16762 open(DUMP, $FilePath);
16763 local $/ = undef;
16764 my $Content = <DUMP>;
16765 close(DUMP);
16766
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040016767 if($Path!~/\.abi\Z/)
16768 { # remove temp file
16769 unlink($FilePath);
16770 }
16771 if($Content!~/};\s*\Z/) {
16772 exitStatus("Invalid_Dump", "specified ABI dump \'$Path\' is not valid, try to recreate it");
16773 }
16774 my $LibraryABI = eval($Content);
16775 if(not $LibraryABI) {
16776 exitStatus("Error", "internal error - eval() procedure seem to not working correctly, try to remove 'use strict' and try again");
16777 }
16778 # new dumps (>=1.22) have a personal versioning
16779 my $DumpVersion = $LibraryABI->{"ABI_DUMP_VERSION"};
16780 my $ToolVersion = $LibraryABI->{"ABI_COMPLIANCE_CHECKER_VERSION"};
16781 if(not $DumpVersion)
16782 { # old dumps (<=1.21.6) have been marked by the tool version
16783 $DumpVersion = $ToolVersion;
16784 }
16785 $UsedDump{$LibVersion}{"V"} = $DumpVersion;
16786 if(majorVersion($DumpVersion) ne majorVersion($ABI_DUMP_VERSION))
16787 { # should be compatible with dumps of the same major version
16788 if(cmpVersions($DumpVersion, $ABI_DUMP_VERSION)>0)
16789 { # Don't know how to parse future dump formats
16790 exitStatus("Dump_Version", "incompatible version $DumpVersion of specified ABI dump (newer than $ABI_DUMP_VERSION)");
16791 }
16792 elsif(cmpVersions($DumpVersion, $TOOL_VERSION)>0 and not $LibraryABI->{"ABI_DUMP_VERSION"})
16793 { # Don't know how to parse future dump formats
16794 exitStatus("Dump_Version", "incompatible version $DumpVersion of specified ABI dump (newer than $TOOL_VERSION)");
16795 }
16796 if($UseOldDumps)
16797 {
16798 if(cmpVersions($DumpVersion, $OLDEST_SUPPORTED_VERSION)<0) {
16799 exitStatus("Dump_Version", "incompatible version $DumpVersion of specified ABI dump (older than $OLDEST_SUPPORTED_VERSION)");
16800 }
16801 }
16802 else
16803 {
16804 my $Msg = "incompatible version $DumpVersion of specified ABI dump (allowed only ".majorVersion($ABI_DUMP_VERSION).".0<=V<=$ABI_DUMP_VERSION)";
16805 if(cmpVersions($DumpVersion, $OLDEST_SUPPORTED_VERSION)>=0) {
16806 $Msg .= "\nUse -old-dumps option to use old-version dumps ($OLDEST_SUPPORTED_VERSION<=V<".majorVersion($ABI_DUMP_VERSION).".0)";
16807 }
16808 exitStatus("Dump_Version", $Msg);
16809 }
16810 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040016811 if($LibraryABI->{"SrcBin"})
16812 { # default
16813 $UsedDump{$LibVersion}{"SrcBin"} = 1;
16814 }
16815 elsif($LibraryABI->{"BinOnly"})
16816 { # ABI dump created with --binary option
16817 $UsedDump{$LibVersion}{"BinOnly"} = 1;
16818 }
Andrey Ponomarenko16934472012-03-29 15:37:04 +040016819 if(defined $LibraryABI->{"Mode"}
16820 and $LibraryABI->{"Mode"} eq "Extended")
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040016821 { # --ext option
16822 $ExtendedCheck = 1;
16823 }
16824 if(my $Lang = $LibraryABI->{"Language"})
16825 {
16826 $UsedDump{$LibVersion}{"L"} = $Lang;
16827 setLanguage($LibVersion, $Lang);
16828 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040016829 if(checkDump($LibVersion, "2.15")) {
16830 $TypeInfo{$LibVersion} = $LibraryABI->{"TypeInfo"};
16831 }
16832 else
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040016833 { # support for old ABI dumps
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040016834 my $TInfo = $LibraryABI->{"TypeInfo"};
16835 if(not $TInfo)
16836 { # support for older ABI dumps
16837 $TInfo = $LibraryABI->{"TypeDescr"};
16838 }
16839 my %Tid_TDid = ();
16840 foreach my $TDid (keys(%{$TInfo}))
16841 {
16842 foreach my $Tid (keys(%{$TInfo->{$TDid}}))
16843 {
16844 $MAX_ID = $Tid if($Tid>$MAX_ID);
16845 $MAX_ID = $TDid if($TDid and $TDid>$MAX_ID);
16846 $Tid_TDid{$Tid}{$TDid}=1;
16847 }
16848 }
16849 my %NewID = ();
16850 foreach my $Tid (keys(%Tid_TDid))
16851 {
16852 my @TDids = keys(%{$Tid_TDid{$Tid}});
16853 if($#TDids>=1)
16854 {
16855 foreach my $TDid (@TDids)
16856 {
16857 if($TDid) {
16858 %{$TypeInfo{$LibVersion}{$Tid}} = %{$TInfo->{$TDid}{$Tid}};
16859 }
16860 else
16861 {
16862 if(my $ID = ++$MAX_ID)
16863 {
16864 $NewID{$TDid}{$Tid} = $ID;
16865 %{$TypeInfo{$LibVersion}{$ID}} = %{$TInfo->{$TDid}{$Tid}};
16866 $TypeInfo{$LibVersion}{$ID}{"Tid"} = $ID;
16867 }
16868 }
16869 }
16870 }
16871 else
16872 {
16873 my $TDid = $TDids[0];
16874 %{$TypeInfo{$LibVersion}{$Tid}} = %{$TInfo->{$TDid}{$Tid}};
16875 }
16876 }
16877 foreach my $Tid (keys(%{$TypeInfo{$LibVersion}}))
16878 {
16879 my %Info = %{$TypeInfo{$LibVersion}{$Tid}};
16880 if(defined $Info{"BaseType"})
16881 {
16882 my $Bid = $Info{"BaseType"}{"Tid"};
16883 my $BDid = $Info{"BaseType"}{"TDid"};
16884 $BDid="" if(not defined $BDid);
16885 if(defined $NewID{$BDid} and my $ID = $NewID{$BDid}{$Bid}) {
16886 $TypeInfo{$LibVersion}{$Tid}{"BaseType"}{"Tid"} = $ID;
16887 }
16888 delete($TypeInfo{$LibVersion}{$Tid}{"BaseType"}{"TDid"});
16889 }
16890 delete($TypeInfo{$LibVersion}{$Tid}{"TDid"});
16891 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040016892 }
16893 read_Machine_DumpInfo($LibraryABI, $LibVersion);
16894 $SymbolInfo{$LibVersion} = $LibraryABI->{"SymbolInfo"};
16895 if(not $SymbolInfo{$LibVersion})
16896 { # support for old dumps
16897 $SymbolInfo{$LibVersion} = $LibraryABI->{"FuncDescr"};
16898 }
16899 if(not keys(%{$SymbolInfo{$LibVersion}}))
16900 { # validation of old-version dumps
16901 if(not $ExtendedCheck) {
16902 exitStatus("Invalid_Dump", "the input dump d$LibVersion is invalid");
16903 }
16904 }
16905 $Library_Symbol{$LibVersion} = $LibraryABI->{"Symbols"};
16906 if(not $Library_Symbol{$LibVersion})
16907 { # support for old dumps
16908 $Library_Symbol{$LibVersion} = $LibraryABI->{"Interfaces"};
16909 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040016910 if(checkDump($LibVersion, "2.15")) {
16911 $DepLibrary_Symbol{$LibVersion} = $LibraryABI->{"DepSymbols"};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040016912 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040016913 else
16914 { # support for old ABI dumps
16915 my $DepSymbols = $LibraryABI->{"DepSymbols"};
16916 if(not $DepSymbols) {
16917 $DepSymbols = $LibraryABI->{"DepInterfaces"};
16918 }
16919 if(not $DepSymbols)
16920 { # Cannot reconstruct DepSymbols. This may result in false
16921 # positives if the old dump is for library 2. Not a problem if
16922 # old dumps are only from old libraries.
16923 $DepSymbols = {};
16924 }
16925 foreach my $Symbol (keys(%{$DepSymbols})) {
16926 $DepSymbol_Library{$LibVersion}{$Symbol} = 1;
16927 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040016928 }
16929 $SymVer{$LibVersion} = $LibraryABI->{"SymbolVersion"};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040016930 $Descriptor{$LibVersion}{"Version"} = $LibraryABI->{"LibraryVersion"};
16931 $SkipTypes{$LibVersion} = $LibraryABI->{"SkipTypes"};
16932 if(not $SkipTypes{$LibVersion})
16933 { # support for old dumps
16934 $SkipTypes{$LibVersion} = $LibraryABI->{"OpaqueTypes"};
16935 }
16936 $SkipSymbols{$LibVersion} = $LibraryABI->{"SkipSymbols"};
16937 if(not $SkipSymbols{$LibVersion})
16938 { # support for old dumps
16939 $SkipSymbols{$LibVersion} = $LibraryABI->{"SkipInterfaces"};
16940 }
16941 if(not $SkipSymbols{$LibVersion})
16942 { # support for old dumps
16943 $SkipSymbols{$LibVersion} = $LibraryABI->{"InternalInterfaces"};
16944 }
16945 $SkipNameSpaces{$LibVersion} = $LibraryABI->{"SkipNameSpaces"};
16946 $TargetHeaders{$LibVersion} = $LibraryABI->{"TargetHeaders"};
16947 foreach my $Path (keys(%{$LibraryABI->{"SkipHeaders"}}))
16948 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040016949 $SkipHeadersList{$LibVersion}{$Path} = $LibraryABI->{"SkipHeaders"}{$Path};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040016950 my ($CPath, $Type) = classifyPath($Path);
16951 $SkipHeaders{$LibVersion}{$Type}{$CPath} = $LibraryABI->{"SkipHeaders"}{$Path};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040016952 }
16953 read_Headers_DumpInfo($LibraryABI, $LibVersion);
16954 read_Libs_DumpInfo($LibraryABI, $LibVersion);
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040016955 if(not checkDump($LibVersion, "2.10.1"))
Andrey Ponomarenko85043792012-05-14 16:48:07 +040016956 { # support for old ABI dumps: added target headers
16957 foreach (keys(%{$Registered_Headers{$LibVersion}})) {
16958 $TargetHeaders{$LibVersion}{get_filename($_)}=1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040016959 }
16960 }
16961 $Constants{$LibVersion} = $LibraryABI->{"Constants"};
16962 $NestedNameSpaces{$LibVersion} = $LibraryABI->{"NameSpaces"};
16963 if(not $NestedNameSpaces{$LibVersion})
16964 { # support for old dumps
16965 # Cannot reconstruct NameSpaces. This may affect design
16966 # of the compatibility report.
16967 $NestedNameSpaces{$LibVersion} = {};
16968 }
16969 # target system type
16970 # needed to adopt HTML report
16971 if(not $DumpSystem)
16972 { # to use in createSymbolsList(...)
16973 $OStarget = $LibraryABI->{"Target"};
16974 }
16975 # recreate environment
16976 foreach my $Lib_Name (keys(%{$Library_Symbol{$LibVersion}}))
16977 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040016978 foreach my $Symbol (keys(%{$Library_Symbol{$LibVersion}{$Lib_Name}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040016979 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040016980 $Symbol_Library{$LibVersion}{$Symbol} = $Lib_Name;
16981 if($Library_Symbol{$LibVersion}{$Lib_Name}{$Symbol}<=-1)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040016982 { # data marked as -size in the dump
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040016983 $GlobalDataObject{$LibVersion}{$Symbol}=1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040016984 }
16985 if($COMMON_LANGUAGE{$LibVersion} ne "C++"
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040016986 and $Symbol=~/\A(_Z|\?)/) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040016987 setLanguage($LibVersion, "C++");
16988 }
16989 }
16990 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040016991 foreach my $Lib_Name (keys(%{$DepLibrary_Symbol{$LibVersion}}))
16992 {
16993 foreach my $Symbol (keys(%{$DepLibrary_Symbol{$LibVersion}{$Lib_Name}})) {
16994 $DepSymbol_Library{$LibVersion}{$Symbol} = $Lib_Name;
16995 }
16996 }
16997
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040016998 my @VFunc = ();
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040016999 foreach my $InfoId (keys(%{$SymbolInfo{$LibVersion}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017000 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040017001 my $MnglName = $SymbolInfo{$LibVersion}{$InfoId}{"MnglName"};
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040017002 if($MnglName)
17003 {
17004 if(not $Symbol_Library{$LibVersion}{$MnglName}
17005 and not $DepSymbol_Library{$LibVersion}{$MnglName}) {
17006 push(@VFunc, $MnglName);
17007 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017008 }
17009 }
17010 translateSymbols(@VFunc, $LibVersion);
17011 translateSymbols(keys(%{$Symbol_Library{$LibVersion}}), $LibVersion);
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040017012 translateSymbols(keys(%{$DepSymbol_Library{$LibVersion}}), $LibVersion);
17013
17014 foreach my $TypeId (sort {int($a)<=>int($b)} keys(%{$TypeInfo{$LibVersion}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017015 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040017016 if(defined $TypeInfo{$LibVersion}{$TypeId}{"BaseClass"})
17017 { # support for old ABI dumps < 2.0 (ACC 1.22)
17018 foreach my $BId (keys(%{$TypeInfo{$LibVersion}{$TypeId}{"BaseClass"}}))
17019 {
17020 if(my $Access = $TypeInfo{$LibVersion}{$TypeId}{"BaseClass"}{$BId})
17021 {
17022 if($Access ne "public") {
17023 $TypeInfo{$LibVersion}{$TypeId}{"Base"}{$BId}{"access"} = $Access;
17024 }
17025 }
17026 $TypeInfo{$LibVersion}{$TypeId}{"Base"}{$BId} = {};
17027 }
17028 delete($TypeInfo{$LibVersion}{$TypeId}{"BaseClass"});
17029 }
17030 my %TInfo = %{$TypeInfo{$LibVersion}{$TypeId}};
17031 if(defined $TInfo{"Base"})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017032 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040017033 foreach (keys(%{$TInfo{"Base"}})) {
17034 $Class_SubClasses{$LibVersion}{$_}{$TypeId}=1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017035 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040017036 }
17037 if($TInfo{"Type"} eq "Typedef" and defined $TInfo{"BaseType"})
17038 {
17039 if(my $BTid = $TInfo{"BaseType"}{"Tid"})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017040 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040017041 my $BName = $TypeInfo{$LibVersion}{$BTid}{"Name"};
17042 if(not $BName)
17043 { # broken type
17044 next;
17045 }
17046 if($TInfo{"Name"} eq $BName)
17047 { # typedef to "class Class"
17048 # should not be registered in TName_Tid
17049 next;
17050 }
17051 if(not $Typedef_BaseName{$LibVersion}{$TInfo{"Name"}}) {
17052 $Typedef_BaseName{$LibVersion}{$TInfo{"Name"}} = $BName;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017053 }
17054 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040017055 }
17056 if(not $TName_Tid{$LibVersion}{$TInfo{"Name"}})
17057 { # classes: class (id1), typedef (artificial, id2 > id1)
17058 $TName_Tid{$LibVersion}{$TInfo{"Name"}} = $TypeId;
17059 }
17060 }
17061
17062 if(not checkDump($LibVersion, "2.15"))
17063 { # support for old ABI dumps
17064 my %Dups = ();
17065 foreach my $InfoId (keys(%{$SymbolInfo{$LibVersion}}))
17066 {
17067 if(my $ClassId = $SymbolInfo{$LibVersion}{$InfoId}{"Class"})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017068 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040017069 if(not defined $TypeInfo{$LibVersion}{$ClassId})
17070 { # remove template decls
17071 delete($SymbolInfo{$LibVersion}{$InfoId});
17072 next;
Andrey Ponomarenko16934472012-03-29 15:37:04 +040017073 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017074 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040017075 if(my $MName = $SymbolInfo{$LibVersion}{$InfoId}{"MnglName"})
17076 {
17077 if($MName=~/_IT_E\Z/)
17078 { # _ZN28QExplicitlySharedDataPointerI22QSslCertificatePrivateEC1IT_EERKS_IT_E
17079 delete($SymbolInfo{$LibVersion}{$InfoId});
17080 }
17081 }
17082 elsif($SymbolInfo{$LibVersion}{$InfoId}{"Class"})
17083 { # templates
17084 delete($SymbolInfo{$LibVersion}{$InfoId});
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017085 }
17086 }
17087 }
17088
17089 $Descriptor{$LibVersion}{"Dump"} = 1;
17090}
17091
17092sub read_Machine_DumpInfo($$)
17093{
17094 my ($LibraryABI, $LibVersion) = @_;
17095 if($LibraryABI->{"Arch"}) {
17096 $CPU_ARCH{$LibVersion} = $LibraryABI->{"Arch"};
17097 }
17098 if($LibraryABI->{"WordSize"}) {
17099 $WORD_SIZE{$LibVersion} = $LibraryABI->{"WordSize"};
17100 }
17101 else
17102 { # support for old dumps
17103 $WORD_SIZE{$LibVersion} = $LibraryABI->{"SizeOfPointer"};
17104 }
17105 if(not $WORD_SIZE{$LibVersion})
17106 { # support for old dumps (<1.23)
17107 if(my $Tid = getTypeIdByName("char*", $LibVersion))
17108 { # size of char*
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040017109 $WORD_SIZE{$LibVersion} = $TypeInfo{$LibVersion}{$Tid}{"Size"};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017110 }
17111 else
17112 {
17113 my $PSize = 0;
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040017114 foreach my $Tid (keys(%{$TypeInfo{$LibVersion}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017115 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040017116 if($TypeInfo{$LibVersion}{$Tid}{"Type"} eq "Pointer")
17117 { # any "pointer"-type
17118 $PSize = $TypeInfo{$LibVersion}{$Tid}{"Size"};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017119 last;
17120 }
17121 }
17122 if($PSize)
17123 { # a pointer type size
17124 $WORD_SIZE{$LibVersion} = $PSize;
17125 }
17126 else {
17127 printMsg("WARNING", "cannot identify a WORD size in the ABI dump (too old format)");
17128 }
17129 }
17130 }
17131 if($LibraryABI->{"GccVersion"}) {
17132 $GCC_VERSION{$LibVersion} = $LibraryABI->{"GccVersion"};
17133 }
17134}
17135
17136sub read_Libs_DumpInfo($$)
17137{
17138 my ($LibraryABI, $LibVersion) = @_;
17139 if(keys(%{$Library_Symbol{$LibVersion}})
17140 and not $DumpAPI) {
17141 $Descriptor{$LibVersion}{"Libs"} = "OK";
17142 }
17143}
17144
17145sub read_Headers_DumpInfo($$)
17146{
17147 my ($LibraryABI, $LibVersion) = @_;
17148 if(keys(%{$LibraryABI->{"Headers"}})
17149 and not $DumpAPI) {
17150 $Descriptor{$LibVersion}{"Headers"} = "OK";
17151 }
17152 foreach my $Identity (keys(%{$LibraryABI->{"Headers"}}))
17153 { # headers info is stored in the old dumps in the different way
17154 if($UseOldDumps
17155 and my $Name = $LibraryABI->{"Headers"}{$Identity}{"Name"})
17156 { # support for old dumps: headers info corrected in 1.22
17157 $Identity = $Name;
17158 }
17159 $Registered_Headers{$LibVersion}{$Identity}{"Identity"} = $Identity;
17160 }
17161}
17162
17163sub find_libs($$$)
17164{
17165 my ($Path, $Type, $MaxDepth) = @_;
17166 # FIXME: correct the search pattern
17167 return cmd_find($Path, $Type, ".*\\.$LIB_EXT\[0-9.]*", $MaxDepth);
17168}
17169
17170sub createDescriptor($$)
17171{
17172 my ($LibVersion, $Path) = @_;
17173 if(not $LibVersion or not $Path
17174 or not -e $Path) {
17175 return "";
17176 }
17177 if(-d $Path)
17178 { # directory with headers files and shared objects
17179 return "
17180 <version>
17181 ".$TargetVersion{$LibVersion}."
17182 </version>
17183
17184 <headers>
17185 $Path
17186 </headers>
17187
17188 <libs>
17189 $Path
17190 </libs>";
17191 }
17192 else
17193 { # files
17194 if($Path=~/\.xml\Z/i)
17195 { # standard XML-descriptor
17196 return readFile($Path);
17197 }
17198 elsif(is_header($Path, 2, $LibVersion))
17199 { # header file
17200 return "
17201 <version>
17202 ".$TargetVersion{$LibVersion}."
17203 </version>
17204
17205 <headers>
17206 $Path
17207 </headers>
17208
17209 <libs>
17210 none
17211 </libs>";
17212 }
17213 elsif(parse_libname($Path, "name", $OStarget))
17214 { # shared object
17215 return "
17216 <version>
17217 ".$TargetVersion{$LibVersion}."
17218 </version>
17219
17220 <headers>
17221 none
17222 </headers>
17223
17224 <libs>
17225 $Path
17226 </libs>";
17227 }
17228 else
17229 { # standard XML-descriptor
17230 return readFile($Path);
17231 }
17232 }
17233}
17234
17235sub detect_lib_default_paths()
17236{
17237 my %LPaths = ();
17238 if($OSgroup eq "bsd")
17239 {
17240 if(my $LdConfig = get_CmdPath("ldconfig")) {
17241 foreach my $Line (split(/\n/, `$LdConfig -r 2>$TMP_DIR/null`)) {
17242 if($Line=~/\A[ \t]*\d+:\-l(.+) \=\> (.+)\Z/) {
17243 $LPaths{"lib".$1} = $2;
17244 }
17245 }
17246 }
17247 else {
17248 printMsg("WARNING", "can't find ldconfig");
17249 }
17250 }
17251 else
17252 {
17253 if(my $LdConfig = get_CmdPath("ldconfig"))
17254 {
17255 if($SystemRoot and $OSgroup eq "linux")
17256 { # use host (x86) ldconfig with the target (arm) ld.so.conf
17257 if(-e $SystemRoot."/etc/ld.so.conf") {
17258 $LdConfig .= " -f ".$SystemRoot."/etc/ld.so.conf";
17259 }
17260 }
17261 foreach my $Line (split(/\n/, `$LdConfig -p 2>$TMP_DIR/null`)) {
17262 if($Line=~/\A[ \t]*([^ \t]+) .* \=\> (.+)\Z/)
17263 {
17264 my ($Name, $Path) = ($1, $2);
17265 $Path=~s/[\/]{2,}/\//;
17266 $LPaths{$Name} = $Path;
17267 }
17268 }
17269 }
17270 elsif($OSgroup=~/linux/i) {
17271 printMsg("WARNING", "can't find ldconfig");
17272 }
17273 }
17274 return \%LPaths;
17275}
17276
17277sub detect_bin_default_paths()
17278{
17279 my $EnvPaths = $ENV{"PATH"};
17280 if($OSgroup eq "beos") {
17281 $EnvPaths.=":".$ENV{"BETOOLS"};
17282 }
17283 my $Sep = ($OSgroup eq "windows")?";":":|;";
17284 foreach my $Path (sort {length($a)<=>length($b)} split(/$Sep/, $EnvPaths))
17285 {
17286 $Path = path_format($Path, $OSgroup);
17287 $Path=~s/[\/\\]+\Z//g;
17288 next if(not $Path);
17289 if($SystemRoot
17290 and $Path=~/\A\Q$SystemRoot\E\//)
17291 { # do NOT use binaries from target system
17292 next;
17293 }
17294 $DefaultBinPaths{$Path} = 1;
17295 }
17296}
17297
17298sub detect_inc_default_paths()
17299{
17300 return () if(not $GCC_PATH);
17301 my %DPaths = ("Cpp"=>{},"Gcc"=>{},"Inc"=>{});
17302 writeFile("$TMP_DIR/empty.h", "");
17303 foreach my $Line (split(/\n/, `$GCC_PATH -v -x c++ -E "$TMP_DIR/empty.h" 2>&1`))
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040017304 { # detecting GCC default include paths
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017305 if($Line=~/\A[ \t]*((\/|\w+:\\).+)[ \t]*\Z/)
17306 {
17307 my $Path = simplify_path($1);
17308 $Path=~s/[\/\\]+\Z//g;
17309 $Path = path_format($Path, $OSgroup);
17310 if($Path=~/c\+\+|\/g\+\+\//)
17311 {
17312 $DPaths{"Cpp"}{$Path}=1;
17313 if(not defined $MAIN_CPP_DIR
17314 or get_depth($MAIN_CPP_DIR)>get_depth($Path)) {
17315 $MAIN_CPP_DIR = $Path;
17316 }
17317 }
17318 elsif($Path=~/gcc/) {
17319 $DPaths{"Gcc"}{$Path}=1;
17320 }
17321 else
17322 {
17323 next if($Path=~/local[\/\\]+include/);
17324 if($SystemRoot
17325 and $Path!~/\A\Q$SystemRoot\E(\/|\Z)/)
17326 { # The GCC include path for user headers is not a part of the system root
17327 # The reason: you are not specified the --cross-gcc option or selected a wrong compiler
17328 # or it is the internal cross-GCC path like arm-linux-gnueabi/include
17329 next;
17330 }
17331 $DPaths{"Inc"}{$Path}=1;
17332 }
17333 }
17334 }
17335 unlink("$TMP_DIR/empty.h");
17336 return %DPaths;
17337}
17338
17339sub detect_default_paths($)
17340{
17341 my ($HSearch, $LSearch, $BSearch, $GSearch) = (1, 1, 1, 1);
17342 my $Search = $_[0];
17343 if($Search!~/inc/) {
17344 $HSearch = 0;
17345 }
17346 if($Search!~/lib/) {
17347 $LSearch = 0;
17348 }
17349 if($Search!~/bin/) {
17350 $BSearch = 0;
17351 }
17352 if($Search!~/gcc/) {
17353 $GSearch = 0;
17354 }
17355 if(keys(%{$SystemPaths{"include"}}))
17356 { # <search_headers> section of the XML descriptor
17357 # do NOT search for systems headers
17358 $HSearch = 0;
17359 }
17360 if(keys(%{$SystemPaths{"lib"}}))
17361 { # <search_headers> section of the XML descriptor
17362 # do NOT search for systems headers
17363 $LSearch = 0;
17364 }
17365 foreach my $Type (keys(%{$OS_AddPath{$OSgroup}}))
17366 { # additional search paths
17367 next if($Type eq "include" and not $HSearch);
17368 next if($Type eq "lib" and not $LSearch);
17369 next if($Type eq "bin" and not $BSearch);
17370 foreach my $Path (keys(%{$OS_AddPath{$OSgroup}{$Type}}))
17371 {
17372 next if(not -d $Path);
17373 $SystemPaths{$Type}{$Path} = $OS_AddPath{$OSgroup}{$Type}{$Path};
17374 }
17375 }
17376 if($OSgroup ne "windows")
17377 { # unix-like
17378 foreach my $Type ("include", "lib", "bin")
17379 { # automatic detection of system "devel" directories
17380 next if($Type eq "include" and not $HSearch);
17381 next if($Type eq "lib" and not $LSearch);
17382 next if($Type eq "bin" and not $BSearch);
17383 my ($UsrDir, $RootDir) = ("/usr", "/");
17384 if($SystemRoot and $Type ne "bin")
17385 { # 1. search for target headers and libraries
17386 # 2. use host commands: ldconfig, readelf, etc.
17387 ($UsrDir, $RootDir) = ("$SystemRoot/usr", $SystemRoot);
17388 }
17389 foreach my $Path (cmd_find($RootDir,"d","*$Type*",1)) {
17390 $SystemPaths{$Type}{$Path} = 1;
17391 }
17392 if(-d $RootDir."/".$Type)
17393 { # if "/lib" is symbolic link
17394 if($RootDir eq "/") {
17395 $SystemPaths{$Type}{"/".$Type} = 1;
17396 }
17397 else {
17398 $SystemPaths{$Type}{$RootDir."/".$Type} = 1;
17399 }
17400 }
17401 if(-d $UsrDir) {
17402 foreach my $Path (cmd_find($UsrDir,"d","*$Type*",1)) {
17403 $SystemPaths{$Type}{$Path} = 1;
17404 }
17405 if(-d $UsrDir."/".$Type)
17406 { # if "/usr/lib" is symbolic link
17407 $SystemPaths{$Type}{$UsrDir."/".$Type} = 1;
17408 }
17409 }
17410 }
17411 }
17412 if($BSearch)
17413 {
17414 detect_bin_default_paths();
17415 foreach my $Path (keys(%DefaultBinPaths)) {
17416 $SystemPaths{"bin"}{$Path} = $DefaultBinPaths{$Path};
17417 }
17418 }
17419 # check environment variables
17420 if($OSgroup eq "beos")
17421 {
17422 foreach (keys(%{$SystemPaths{"bin"}}))
17423 {
17424 if($_ eq ".") {
17425 next;
17426 }
17427 foreach my $Path (cmd_find($_, "d", "bin", ""))
17428 { # search for /boot/develop/abi/x86/gcc4/tools/gcc-4.4.4-haiku-101111/bin/
17429 $SystemPaths{"bin"}{$Path} = 1;
17430 }
17431 }
17432 if($HSearch)
17433 {
17434 foreach my $Path (split(/:|;/, $ENV{"BEINCLUDES"}))
17435 {
17436 if(is_abs($Path)) {
17437 $DefaultIncPaths{$Path} = 1;
17438 }
17439 }
17440 }
17441 if($LSearch)
17442 {
17443 foreach my $Path (split(/:|;/, $ENV{"BELIBRARIES"}), split(/:|;/, $ENV{"LIBRARY_PATH"}))
17444 {
17445 if(is_abs($Path)) {
17446 $DefaultLibPaths{$Path} = 1;
17447 }
17448 }
17449 }
17450 }
17451 if($LSearch)
17452 { # using linker to get system paths
17453 if(my $LPaths = detect_lib_default_paths())
17454 { # unix-like
17455 foreach my $Name (keys(%{$LPaths}))
17456 {
17457 if($SystemRoot
17458 and $LPaths->{$Name}!~/\A\Q$SystemRoot\E\//)
17459 { # wrong ldconfig configuration
17460 # check your <sysroot>/etc/ld.so.conf
17461 next;
17462 }
17463 $DyLib_DefaultPath{$Name} = $LPaths->{$Name};
17464 $DefaultLibPaths{get_dirname($LPaths->{$Name})} = 1;
17465 }
17466 }
17467 foreach my $Path (keys(%DefaultLibPaths)) {
17468 $SystemPaths{"lib"}{$Path} = $DefaultLibPaths{$Path};
17469 }
17470 }
17471 if($BSearch)
17472 {
17473 if($CrossGcc)
17474 { # --cross-gcc=arm-linux-gcc
17475 if(-e $CrossGcc)
17476 { # absolute or relative path
17477 $GCC_PATH = get_abs_path($CrossGcc);
17478 }
17479 elsif($CrossGcc!~/\// and get_CmdPath($CrossGcc))
17480 { # command name
17481 $GCC_PATH = $CrossGcc;
17482 }
17483 else {
17484 exitStatus("Access_Error", "can't access \'$CrossGcc\'");
17485 }
17486 if($GCC_PATH=~/\s/) {
17487 $GCC_PATH = "\"".$GCC_PATH."\"";
17488 }
17489 }
17490 }
17491 if($GSearch)
17492 { # GCC path and default include dirs
17493 if(not $CrossGcc) {
17494 $GCC_PATH = get_CmdPath("gcc");
17495 }
17496 if(not $GCC_PATH) {
17497 exitStatus("Not_Found", "can't find GCC>=3.0 in PATH");
17498 }
17499 if(not $CheckObjectsOnly_Opt)
17500 {
17501 if(my $GCC_Ver = get_dumpversion($GCC_PATH))
17502 {
17503 my $GccTarget = get_dumpmachine($GCC_PATH);
17504 printMsg("INFO", "Using GCC $GCC_Ver ($GccTarget)");
17505 if($GccTarget=~/symbian/)
17506 {
17507 $OStarget = "symbian";
17508 $LIB_EXT = $OS_LibExt{$LIB_TYPE}{$OStarget};
17509 }
17510 }
17511 else {
17512 exitStatus("Error", "something is going wrong with the GCC compiler");
17513 }
17514 }
17515 if(not $NoStdInc)
17516 { # do NOT search in GCC standard paths
17517 my %DPaths = detect_inc_default_paths();
17518 %DefaultCppPaths = %{$DPaths{"Cpp"}};
17519 %DefaultGccPaths = %{$DPaths{"Gcc"}};
17520 %DefaultIncPaths = %{$DPaths{"Inc"}};
17521 foreach my $Path (keys(%DefaultIncPaths)) {
17522 $SystemPaths{"include"}{$Path} = $DefaultIncPaths{$Path};
17523 }
17524 }
17525 }
17526 if($HSearch)
17527 { # user include paths
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040017528 my $IncPath = "/usr/include";
17529 if($SystemRoot) {
17530 $IncPath = $SystemRoot.$IncPath;
17531 }
17532 if(-d $IncPath) {
17533 $UserIncPath{$IncPath}=1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017534 }
17535 }
17536}
17537
17538sub getLIB_EXT($)
17539{
17540 my $Target = $_[0];
17541 if(my $Ext = $OS_LibExt{$LIB_TYPE}{$Target}) {
17542 return $Ext;
17543 }
17544 return $OS_LibExt{$LIB_TYPE}{"default"};
17545}
17546
17547sub getAR_EXT($)
17548{
17549 my $Target = $_[0];
17550 if(my $Ext = $OS_Archive{$Target}) {
17551 return $Ext;
17552 }
17553 return $OS_Archive{"default"};
17554}
17555
17556sub get_dumpversion($)
17557{
17558 my $Cmd = $_[0];
17559 return "" if(not $Cmd);
17560 if($Cache{"get_dumpversion"}{$Cmd}) {
17561 return $Cache{"get_dumpversion"}{$Cmd};
17562 }
17563 my $V = `$Cmd -dumpversion 2>$TMP_DIR/null`;
17564 chomp($V);
17565 return ($Cache{"get_dumpversion"}{$Cmd} = $V);
17566}
17567
17568sub get_dumpmachine($)
17569{
17570 my $Cmd = $_[0];
17571 return "" if(not $Cmd);
17572 if($Cache{"get_dumpmachine"}{$Cmd}) {
17573 return $Cache{"get_dumpmachine"}{$Cmd};
17574 }
17575 my $Machine = `$Cmd -dumpmachine 2>$TMP_DIR/null`;
17576 chomp($Machine);
17577 return ($Cache{"get_dumpmachine"}{$Cmd} = $Machine);
17578}
17579
17580sub check_command($)
17581{
17582 my $Cmd = $_[0];
17583 return "" if(not $Cmd);
17584 my @Options = (
17585 "--version",
17586 "-help"
17587 );
17588 foreach my $Opt (@Options)
17589 {
17590 my $Info = `$Cmd $Opt 2>$TMP_DIR/null`;
17591 if($Info) {
17592 return 1;
17593 }
17594 }
17595 return 0;
17596}
17597
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040017598sub check_gcc($$)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017599{
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040017600 my ($Cmd, $ReqVer) = @_;
17601 return 0 if(not $Cmd or not $ReqVer);
17602 if(defined $Cache{"check_gcc"}{$Cmd}{$ReqVer}) {
17603 return $Cache{"check_gcc"}{$Cmd}{$ReqVer};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017604 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040017605 if(my $GccVer = get_dumpversion($Cmd))
17606 {
17607 $GccVer=~s/(-|_)[a-z_]+.*\Z//; # remove suffix (like "-haiku-100818")
17608 if(cmpVersions($GccVer, $ReqVer)>=0) {
17609 return ($Cache{"check_gcc"}{$Cmd}{$ReqVer} = $Cmd);
17610 }
17611 }
17612 return ($Cache{"check_gcc"}{$Cmd}{$ReqVer} = "");
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017613}
17614
17615sub get_depth($)
17616{
17617 if(defined $Cache{"get_depth"}{$_[0]}) {
17618 return $Cache{"get_depth"}{$_[0]}
17619 }
17620 return ($Cache{"get_depth"}{$_[0]} = ($_[0]=~tr![\/\\]|\:\:!!));
17621}
17622
17623sub find_gcc_cxx_headers($)
17624{
17625 my $LibVersion = $_[0];
17626 return if($Cache{"find_gcc_cxx_headers"});# this function should be called once
17627 # detecting system header paths
17628 foreach my $Path (sort {get_depth($b) <=> get_depth($a)} keys(%DefaultGccPaths))
17629 {
17630 foreach my $HeaderPath (sort {get_depth($a) <=> get_depth($b)} cmd_find($Path,"f","",""))
17631 {
17632 my $FileName = get_filename($HeaderPath);
17633 next if($DefaultGccHeader{$FileName});
17634 $DefaultGccHeader{$FileName} = $HeaderPath;
17635 }
17636 }
17637 if($COMMON_LANGUAGE{$LibVersion} eq "C++" and not $STDCXX_TESTING)
17638 {
17639 foreach my $CppDir (sort {get_depth($b)<=>get_depth($a)} keys(%DefaultCppPaths))
17640 {
17641 my @AllCppHeaders = cmd_find($CppDir,"f","","");
17642 foreach my $Path (sort {get_depth($a)<=>get_depth($b)} @AllCppHeaders)
17643 {
17644 my $FileName = get_filename($Path);
17645 next if($DefaultCppHeader{$FileName});
17646 $DefaultCppHeader{$FileName} = $Path;
17647 }
17648 }
17649 }
17650 $Cache{"find_gcc_cxx_headers"} = 1;
17651}
17652
17653sub parse_libname($$$)
17654{
17655 my ($Name, $Type, $Target) = @_;
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040017656 if(not $Name) {
17657 return "";
17658 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017659 if($Target eq "symbian") {
17660 return parse_libname_symbian($Name, $Type);
17661 }
17662 elsif($Target eq "windows") {
17663 return parse_libname_windows($Name, $Type);
17664 }
17665 my $Ext = getLIB_EXT($Target);
17666 if($Name=~/((((lib|).+?)([\-\_][\d\-\.\_]+|))\.$Ext)(\.(.+)|)\Z/)
17667 { # libSDL-1.2.so.0.7.1
17668 # libwbxml2.so.0.0.18
17669 if($Type eq "name")
17670 { # libSDL-1.2
17671 # libwbxml2
17672 return $2;
17673 }
17674 elsif($Type eq "name+ext")
17675 { # libSDL-1.2.so
17676 # libwbxml2.so
17677 return $1;
17678 }
17679 elsif($Type eq "version")
17680 {
17681 if($7 ne "")
17682 { # 0.7.1
17683 return $7;
17684 }
17685 else
17686 { # libc-2.5.so (=>2.5 version)
17687 my $MV = $5;
17688 $MV=~s/\A[\-\_]+//g;
17689 return $MV;
17690 }
17691 }
17692 elsif($Type eq "short")
17693 { # libSDL
17694 # libwbxml2
17695 return $3;
17696 }
17697 elsif($Type eq "shortest")
17698 { # SDL
17699 # wbxml
17700 return shortest_name($3);
17701 }
17702 }
17703 return "";# error
17704}
17705
17706sub parse_libname_symbian($$)
17707{
17708 my ($Name, $Type) = @_;
17709 my $Ext = getLIB_EXT("symbian");
17710 if($Name=~/(((.+?)(\{.+\}|))\.$Ext)\Z/)
17711 { # libpthread{00010001}.dso
17712 if($Type eq "name")
17713 { # libpthread{00010001}
17714 return $2;
17715 }
17716 elsif($Type eq "name+ext")
17717 { # libpthread{00010001}.dso
17718 return $1;
17719 }
17720 elsif($Type eq "version")
17721 { # 00010001
17722 my $V = $4;
17723 $V=~s/\{(.+)\}/$1/;
17724 return $V;
17725 }
17726 elsif($Type eq "short")
17727 { # libpthread
17728 return $3;
17729 }
17730 elsif($Type eq "shortest")
17731 { # pthread
17732 return shortest_name($3);
17733 }
17734 }
17735 return "";# error
17736}
17737
17738sub parse_libname_windows($$)
17739{
17740 my ($Name, $Type) = @_;
17741 my $Ext = getLIB_EXT("windows");
17742 if($Name=~/((.+?)\.$Ext)\Z/)
17743 { # netapi32.dll
17744 if($Type eq "name")
17745 { # netapi32
17746 return $2;
17747 }
17748 elsif($Type eq "name+ext")
17749 { # netapi32.dll
17750 return $1;
17751 }
17752 elsif($Type eq "version")
17753 { # DLL version embedded
17754 # at binary-level
17755 return "";
17756 }
17757 elsif($Type eq "short")
17758 { # netapi32
17759 return $2;
17760 }
17761 elsif($Type eq "shortest")
17762 { # netapi
17763 return shortest_name($2);
17764 }
17765 }
17766 return "";# error
17767}
17768
17769sub shortest_name($)
17770{
17771 my $Name = $_[0];
17772 # remove prefix
17773 $Name=~s/\A(lib|open)//;
17774 # remove suffix
17775 $Name=~s/[\W\d_]+\Z//i;
17776 $Name=~s/([a-z]{2,})(lib)\Z/$1/i;
17777 return $Name;
17778}
17779
17780sub getPrefix($)
17781{
17782 my $Str = $_[0];
17783 if($Str=~/\A(Get|get|Set|set)([A-Z]|_)/)
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040017784 { # GetError
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017785 return "";
17786 }
17787 if($Str=~/\A([_]*[A-Z][a-z]{1,5})[A-Z]/)
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040017788 { # XmuValidArea: Xmu
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017789 return $1;
17790 }
17791 elsif($Str=~/\A([_]*[a-z]+)[A-Z]/)
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040017792 { # snfReadFont: snf
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017793 return $1;
17794 }
17795 elsif($Str=~/\A([_]*[A-Z]{2,})[A-Z][a-z]+([A-Z][a-z]+|\Z)/)
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040017796 { # XRRTimes: XRR
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017797 return $1;
17798 }
17799 elsif($Str=~/\A([_]*[a-z0-9]{2,}_)[a-z]+/i)
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040017800 { # alarm_event_add: alarm_
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017801 return $1;
17802 }
17803 elsif($Str=~/\A(([a-z])\2{1,})/i)
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040017804 { # ffopen
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017805 return $1;
17806 }
17807 else {
17808 return "";
17809 }
17810}
17811
17812sub problem_title($)
17813{
17814 if($_[0]==1) {
17815 return "1 problem";
17816 }
17817 else {
17818 return $_[0]." problems";
17819 }
17820}
17821
17822sub warning_title($)
17823{
17824 if($_[0]==1) {
17825 return "1 warning";
17826 }
17827 else {
17828 return $_[0]." warnings";
17829 }
17830}
17831
17832sub createSymbolsList($$$$$)
17833{
17834 my ($DPath, $SaveTo, $LName, $LVersion, $ArchName) = @_;
17835 read_ABI_Dump(1, $DPath);
17836 if(not $CheckObjectsOnly) {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040017837 prepareSymbols(1);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017838 }
17839 my %SymbolHeaderLib = ();
17840 my $Total = 0;
17841 # Get List
17842 foreach my $Symbol (sort keys(%{$CompleteSignature{1}}))
17843 {
17844 if(not link_symbol($Symbol, 1, "-Deps"))
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040017845 { # skip src only and all external functions
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017846 next;
17847 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040017848 if(not symbolFilter($Symbol, 1, "Public", "Binary"))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017849 { # skip other symbols
17850 next;
17851 }
17852 my $HeaderName = $CompleteSignature{1}{$Symbol}{"Header"};
17853 if(not $HeaderName)
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040017854 { # skip src only and all external functions
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017855 next;
17856 }
17857 my $DyLib = $Symbol_Library{1}{$Symbol};
17858 if(not $DyLib)
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040017859 { # skip src only and all external functions
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017860 next;
17861 }
17862 $SymbolHeaderLib{$HeaderName}{$DyLib}{$Symbol} = 1;
17863 $Total+=1;
17864 }
17865 # Draw List
17866 my $SYMBOLS_LIST = "<h1>Public symbols in <span style='color:Blue;'>$LName</span> (<span style='color:Red;'>$LVersion</span>)";
17867 $SYMBOLS_LIST .= " on <span style='color:Blue;'>".showArch($ArchName)."</span><br/>Total: $Total</h1><br/>";
17868 foreach my $HeaderName (sort {lc($a) cmp lc($b)} keys(%SymbolHeaderLib))
17869 {
17870 foreach my $DyLib (sort {lc($a) cmp lc($b)} keys(%{$SymbolHeaderLib{$HeaderName}}))
17871 {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017872 my %NS_Symbol = ();
17873 foreach my $Symbol (keys(%{$SymbolHeaderLib{$HeaderName}{$DyLib}})) {
17874 $NS_Symbol{get_IntNameSpace($Symbol, 1)}{$Symbol} = 1;
17875 }
17876 foreach my $NameSpace (sort keys(%NS_Symbol))
17877 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040017878 $SYMBOLS_LIST .= getTitle($HeaderName, $DyLib, $NameSpace);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017879 my @SortedInterfaces = sort {lc(get_Signature($a, 1)) cmp lc(get_Signature($b, 1))} keys(%{$NS_Symbol{$NameSpace}});
17880 foreach my $Symbol (@SortedInterfaces)
17881 {
17882 my $SubReport = "";
17883 my $Signature = get_Signature($Symbol, 1);
17884 if($NameSpace) {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040017885 $Signature=~s/\b\Q$NameSpace\E::\b//g;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017886 }
17887 if($Symbol=~/\A(_Z|\?)/)
17888 {
17889 if($Signature) {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040017890 $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 +040017891 }# report_added
17892 else {
17893 $SubReport = "<span class='iname'>".$Symbol."</span><br/>\n";
17894 }
17895 }
17896 else
17897 {
17898 if($Signature) {
17899 $SubReport = "<span class='iname'>".highLight_Signature_Italic_Color($Signature)."</span><br/>\n";
17900 }
17901 else {
17902 $SubReport = "<span class='iname'>".$Symbol."</span><br/>\n";
17903 }
17904 }
17905 $SYMBOLS_LIST .= $SubReport;
17906 }
17907 }
17908 $SYMBOLS_LIST .= "<br/>\n";
17909 }
17910 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040017911 # clear info
17912 (%TypeInfo, %SymbolInfo, %Library_Symbol, %DepSymbol_Library,
17913 %DepLibrary_Symbol, %SymVer, %SkipTypes, %SkipSymbols,
17914 %NestedNameSpaces, %ClassMethods, %AllocableClass, %ClassNames,
17915 %CompleteSignature, %SkipNameSpaces, %Symbol_Library, %Library_Symbol) = ();
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017916 ($Content_Counter, $ContentID) = (0, 0);
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040017917 # print report
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040017918 my $CssStyles = readModule("Styles", "SymbolsList.css");
17919 my $JScripts = readModule("Scripts", "Sections.js");
17920 $SYMBOLS_LIST = "<a name='Top'></a>".$SYMBOLS_LIST.$TOP_REF."<br/>\n";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017921 my $Title = "$LName: public symbols";
17922 my $Keywords = "$LName, API, symbols";
17923 my $Description = "List of symbols in $LName ($LVersion) on ".showArch($ArchName);
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040017924 $SYMBOLS_LIST = composeHTML_Head($Title, $Keywords, $Description, $CssStyles, $JScripts)."
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017925 <body><div>\n$SYMBOLS_LIST</div>
17926 <br/><br/><hr/>\n".getReportFooter($LName)."
17927 <div style='height:999px;'></div></body></html>";
17928 writeFile($SaveTo, $SYMBOLS_LIST);
17929}
17930
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040017931sub readModule($$)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017932{
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040017933 my ($Module, $Name) = @_;
17934 my $Path = $MODULES_DIR."/Internals/$Module/".$Name;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017935 if(not -f $Path) {
17936 exitStatus("Module_Error", "can't access \'$Path\'");
17937 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040017938 return readFile($Path);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017939}
17940
17941sub is_target_lib($)
17942{
17943 my $LName = $_[0];
17944 if($TargetLibraryName
17945 and $LName!~/\Q$TargetLibraryName\E/) {
17946 return 0;
17947 }
17948 if(keys(%TargetLibs)
17949 and not $TargetLibs{$LName}
17950 and not $TargetLibs{parse_libname($LName, "name+ext", $OStarget)}) {
17951 return 0;
17952 }
17953 return 1;
17954}
17955
Andrey Ponomarenko85043792012-05-14 16:48:07 +040017956sub is_target_header($$)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017957{ # --header, --headers-list
Andrey Ponomarenko85043792012-05-14 16:48:07 +040017958 my ($H, $V) = @_;
17959 if(keys(%{$TargetHeaders{$V}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017960 {
Andrey Ponomarenko85043792012-05-14 16:48:07 +040017961 if($TargetHeaders{$V}{$H}) {
17962 return 1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017963 }
17964 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +040017965 return 0;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017966}
17967
17968sub checkVersionNum($$)
17969{
17970 my ($LibVersion, $Path) = @_;
17971 if(my $VerNum = $TargetVersion{$LibVersion}) {
17972 return $VerNum;
17973 }
17974 my $UsedAltDescr = 0;
17975 foreach my $Part (split(/\s*,\s*/, $Path))
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040017976 { # try to get version string from file path
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017977 next if($Part=~/\.xml\Z/i);
17978 next if(isDump($Part));
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040017979 my $VerNum = "";
17980 if(parse_libname($Part, "name", $OStarget))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017981 {
17982 $UsedAltDescr = 1;
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040017983 $VerNum = parse_libname($Part, "version", $OStarget);
17984 if(not $VerNum) {
17985 $VerNum = readStringVersion($Part);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017986 }
17987 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040017988 elsif(is_header($Part, 2, $LibVersion) or -d $Part)
17989 {
17990 $UsedAltDescr = 1;
17991 $VerNum = readStringVersion($Part);
17992 }
17993 if($VerNum ne "")
17994 {
17995 $TargetVersion{$LibVersion} = $VerNum;
17996 if($DumpAPI) {
17997 printMsg("WARNING", "setting version number to $VerNum (use -vnum <num> option to change it)");
17998 }
17999 else {
18000 printMsg("WARNING", "setting ".($LibVersion==1?"1st":"2nd")." version number to \"$VerNum\" (use -v$LibVersion <num> option to change it)");
18001 }
18002 return $TargetVersion{$LibVersion};
18003 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040018004 }
18005 if($UsedAltDescr)
18006 {
18007 if($DumpAPI) {
18008 exitStatus("Error", "version number is not set (use -vnum <num> option)");
18009 }
18010 else {
18011 exitStatus("Error", ($LibVersion==1?"1st":"2nd")." version number is not set (use -v$LibVersion <num> option)");
18012 }
18013 }
18014}
18015
18016sub readStringVersion($)
18017{
18018 my $Str = $_[0];
18019 return "" if(not $Str);
18020 $Str=~s/\Q$TargetLibraryName\E//g;
18021 if($Str=~/(\/|\\|\w|\A)[\-\_]*(\d+[\d\.\-]+\d+|\d+)/)
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040018022 { # .../libssh-0.4.0/...
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040018023 return $2;
18024 }
18025 elsif(my $V = parse_libname($Str, "version", $OStarget)) {
18026 return $V;
18027 }
18028 return "";
18029}
18030
18031sub readLibs($)
18032{
18033 my $LibVersion = $_[0];
18034 if($OStarget eq "windows")
18035 { # dumpbin.exe will crash
18036 # without VS Environment
18037 check_win32_env();
18038 }
Andrey Ponomarenko16934472012-03-29 15:37:04 +040018039 readSymbols($LibVersion);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040018040 translateSymbols(keys(%{$Symbol_Library{$LibVersion}}), $LibVersion);
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040018041 translateSymbols(keys(%{$DepSymbol_Library{$LibVersion}}), $LibVersion);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040018042}
18043
18044sub dump_sorting($)
18045{
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +040018046 my $Hash = $_[0];
18047 return [] if(not $Hash);
18048 my @Keys = keys(%{$Hash});
18049 return [] if($#Keys<0);
18050 if($Keys[0]=~/\A\d+\Z/)
18051 { # numbers
18052 return [sort {int($a)<=>int($b)} @Keys];
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040018053 }
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +040018054 else
18055 { # strings
18056 return [sort {$a cmp $b} @Keys];
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040018057 }
18058}
18059
18060sub printMsg($$)
18061{
18062 my ($Type, $Msg) = @_;
18063 if($Type!~/\AINFO/) {
18064 $Msg = $Type.": ".$Msg;
18065 }
18066 if($Type!~/_C\Z/) {
18067 $Msg .= "\n";
18068 }
18069 if($Quiet)
18070 { # --quiet option
18071 appendFile($COMMON_LOG_PATH, $Msg);
18072 }
18073 else
18074 {
18075 if($Type eq "ERROR") {
18076 print STDERR $Msg;
18077 }
18078 else {
18079 print $Msg;
18080 }
18081 }
18082}
18083
18084sub exitStatus($$)
18085{
18086 my ($Code, $Msg) = @_;
18087 printMsg("ERROR", $Msg);
18088 exit($ERROR_CODE{$Code});
18089}
18090
18091sub exitReport()
18092{ # the tool has run without any errors
18093 printReport();
18094 if($COMPILE_ERRORS)
18095 { # errors in headers may add false positives/negatives
18096 exit($ERROR_CODE{"Compile_Error"});
18097 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040018098 if($BinaryOnly and $RESULT{"Binary"}{"Problems"})
18099 { # --binary
18100 exit($ERROR_CODE{"Incompatible"});
18101 }
18102 elsif($SourceOnly and $RESULT{"Source"}{"Problems"})
18103 { # --source
18104 exit($ERROR_CODE{"Incompatible"});
18105 }
18106 elsif($RESULT{"Source"}{"Problems"}
18107 or $RESULT{"Binary"}{"Problems"})
18108 { # default
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040018109 exit($ERROR_CODE{"Incompatible"});
18110 }
18111 else {
18112 exit($ERROR_CODE{"Compatible"});
18113 }
18114}
18115
18116sub readRules($)
18117{
18118 my $Kind = $_[0];
18119 if(not -f $RULES_PATH{$Kind}) {
18120 exitStatus("Module_Error", "can't access \'".$RULES_PATH{$Kind}."\'");
18121 }
18122 my $Content = readFile($RULES_PATH{$Kind});
18123 while(my $Rule = parseTag(\$Content, "rule"))
18124 {
18125 my $RId = parseTag(\$Rule, "id");
18126 my @Properties = ("Severity", "Change", "Effect", "Overcome", "Kind");
18127 foreach my $Prop (@Properties) {
18128 if(my $Value = parseTag(\$Rule, lc($Prop)))
18129 {
18130 $Value=~s/\n[ ]*//;
18131 $CompatRules{$Kind}{$RId}{$Prop} = $Value;
18132 }
18133 }
18134 if($CompatRules{$Kind}{$RId}{"Kind"}=~/\A(Symbols|Parameters)\Z/) {
18135 $CompatRules{$Kind}{$RId}{"Kind"} = "Symbols";
18136 }
18137 else {
18138 $CompatRules{$Kind}{$RId}{"Kind"} = "Types";
18139 }
18140 }
18141}
18142
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040018143sub getReportPath($)
18144{
18145 my $Level = $_[0];
18146 my $Dir = "compat_reports/$TargetLibraryName/".$Descriptor{1}{"Version"}."_to_".$Descriptor{2}{"Version"};
18147 if($Level eq "Binary")
18148 {
18149 if($BinaryReportPath)
18150 { # --bin-report-path
18151 return $BinaryReportPath;
18152 }
18153 elsif($OutputReportPath)
18154 { # --report-path
18155 return $OutputReportPath;
18156 }
18157 else
18158 { # default
18159 return $Dir."/abi_compat_report.$ReportFormat";
18160 }
18161 }
18162 elsif($Level eq "Source")
18163 {
18164 if($SourceReportPath)
18165 { # --src-report-path
18166 return $SourceReportPath;
18167 }
18168 elsif($OutputReportPath)
18169 { # --report-path
18170 return $OutputReportPath;
18171 }
18172 else
18173 { # default
18174 return $Dir."/src_compat_report.$ReportFormat";
18175 }
18176 }
18177 else
18178 {
18179 if($OutputReportPath)
18180 { # --report-path
18181 return $OutputReportPath;
18182 }
18183 else
18184 { # default
18185 return $Dir."/compat_report.$ReportFormat";
18186 }
18187 }
18188}
18189
18190sub printStatMsg($)
18191{
18192 my $Level = $_[0];
18193 printMsg("INFO", "total \"$Level\" compatibility problems: ".$RESULT{$Level}{"Problems"}.", warnings: ".$RESULT{$Level}{"Warnings"});
18194}
18195
18196sub listAffected($)
18197{
18198 my $Level = $_[0];
18199 my $List = "";
18200 foreach (keys(%{$TotalAffected{$Level}}))
18201 {
18202 if($StrictCompat and $TotalAffected{$Level}{$_} eq "Low")
18203 { # skip "Low"-severity problems
18204 next;
18205 }
18206 $List .= "$_\n";
18207 }
18208 my $Dir = get_dirname(getReportPath($Level));
18209 if($Level eq "Binary") {
18210 writeFile($Dir."/abi_affected.txt", $List);
18211 }
18212 elsif($Level eq "Source") {
18213 writeFile($Dir."/src_affected.txt", $List);
18214 }
18215}
18216
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040018217sub printReport()
18218{
18219 printMsg("INFO", "creating compatibility report ...");
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040018220 createReport();
18221 if($JoinReport or $DoubleReport)
18222 {
18223 if($RESULT{"Binary"}{"Problems"}
18224 or $RESULT{"Source"}{"Problems"}) {
18225 printMsg("INFO", "result: INCOMPATIBLE (Binary: ".$RESULT{"Binary"}{"Affected"}."\%, Source: ".$RESULT{"Source"}{"Affected"}."\%)");
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040018226 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040018227 else {
18228 printMsg("INFO", "result: COMPATIBLE");
18229 }
18230 printStatMsg("Binary");
18231 printStatMsg("Source");
18232 if($ListAffected)
18233 { # --list-affected
18234 listAffected("Binary");
18235 listAffected("Source");
18236 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040018237 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040018238 elsif($BinaryOnly)
18239 {
18240 if($RESULT{"Binary"}{"Problems"}) {
18241 printMsg("INFO", "result: INCOMPATIBLE (".$RESULT{"Binary"}{"Affected"}."\%)");
18242 }
18243 else {
18244 printMsg("INFO", "result: COMPATIBLE");
18245 }
18246 printStatMsg("Binary");
18247 if($ListAffected)
18248 { # --list-affected
18249 listAffected("Binary");
18250 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040018251 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040018252 elsif($SourceOnly)
18253 {
18254 if($RESULT{"Source"}{"Problems"}) {
18255 printMsg("INFO", "result: INCOMPATIBLE (".$RESULT{"Source"}{"Affected"}."\%)");
18256 }
18257 else {
18258 printMsg("INFO", "result: COMPATIBLE");
18259 }
18260 printStatMsg("Source");
18261 if($ListAffected)
18262 { # --list-affected
18263 listAffected("Source");
18264 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040018265 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040018266 if($StdOut)
18267 {
18268 if($JoinReport or not $DoubleReport)
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040018269 { # --binary or --source
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040018270 printMsg("INFO", "compatibility report has been generated to stdout");
18271 }
18272 else
18273 { # default
18274 printMsg("INFO", "compatibility reports have been generated to stdout");
18275 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040018276 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040018277 else
18278 {
18279 if($JoinReport)
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040018280 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040018281 printMsg("INFO", "see detailed report:\n ".getReportPath("Join"));
18282 }
18283 elsif($DoubleReport)
18284 { # default
18285 printMsg("INFO", "see detailed reports:\n ".getReportPath("Binary")."\n ".getReportPath("Source"));
18286 }
18287 elsif($BinaryOnly)
18288 { # --binary
18289 printMsg("INFO", "see detailed report:\n ".getReportPath("Binary"));
18290 }
18291 elsif($SourceOnly)
18292 { # --source
18293 printMsg("INFO", "see detailed report:\n ".getReportPath("Source"));
18294 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040018295 }
18296}
18297
18298sub check_win32_env()
18299{
18300 if(not $ENV{"DevEnvDir"}
18301 or not $ENV{"LIB"}) {
18302 exitStatus("Error", "can't start without VS environment (vsvars32.bat)");
18303 }
18304}
18305
18306sub create_ABI_Dump()
18307{
18308 if(not -e $DumpAPI) {
18309 exitStatus("Access_Error", "can't access \'$DumpAPI\'");
18310 }
18311 # check the archive utilities
18312 if($OSgroup eq "windows")
18313 { # using zip
18314 my $ZipCmd = get_CmdPath("zip");
18315 if(not $ZipCmd) {
18316 exitStatus("Not_Found", "can't find \"zip\"");
18317 }
18318 }
18319 else
18320 { # using tar and gzip
18321 my $TarCmd = get_CmdPath("tar");
18322 if(not $TarCmd) {
18323 exitStatus("Not_Found", "can't find \"tar\"");
18324 }
18325 my $GzipCmd = get_CmdPath("gzip");
18326 if(not $GzipCmd) {
18327 exitStatus("Not_Found", "can't find \"gzip\"");
18328 }
18329 }
18330 my @DParts = split(/\s*,\s*/, $DumpAPI);
18331 foreach my $Part (@DParts)
18332 {
18333 if(not -e $Part) {
18334 exitStatus("Access_Error", "can't access \'$Part\'");
18335 }
18336 }
18337 checkVersionNum(1, $DumpAPI);
18338 foreach my $Part (@DParts)
18339 {
18340 if(isDump($Part)) {
18341 read_ABI_Dump(1, $Part);
18342 }
18343 else {
18344 readDescriptor(1, createDescriptor(1, $Part));
18345 }
18346 }
18347 initLogging(1);
18348 detect_default_paths("inc|lib|bin|gcc"); # complete analysis
18349 if(not $CheckHeadersOnly) {
18350 readLibs(1);
18351 }
18352 if($CheckHeadersOnly) {
18353 setLanguage(1, "C++");
18354 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +040018355 if(not $CheckObjectsOnly) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040018356 searchForHeaders(1);
18357 }
18358 $WORD_SIZE{1} = detectWordSize();
18359 if($Descriptor{1}{"Headers"}
18360 and not $Descriptor{1}{"Dump"}) {
18361 readHeaders(1);
18362 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +040018363 cleanDump(1);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040018364 if(not keys(%{$SymbolInfo{1}}))
18365 { # check if created dump is valid
18366 if(not $ExtendedCheck and not $CheckObjectsOnly)
18367 {
18368 if($CheckHeadersOnly) {
18369 exitStatus("Empty_Set", "the set of public symbols is empty");
18370 }
18371 else {
18372 exitStatus("Empty_Intersection", "the sets of public symbols in headers and libraries have empty intersection");
18373 }
18374 }
18375 }
18376 my %HeadersInfo = ();
18377 foreach my $HPath (keys(%{$Registered_Headers{1}}))
18378 { # headers info stored without paths in the dump
18379 $HeadersInfo{$Registered_Headers{1}{$HPath}{"Identity"}} = $Registered_Headers{1}{$HPath}{"Pos"};
18380 }
18381 printMsg("INFO", "creating library ABI dump ...");
18382 my %LibraryABI = (
18383 "TypeInfo" => $TypeInfo{1},
18384 "SymbolInfo" => $SymbolInfo{1},
18385 "Symbols" => $Library_Symbol{1},
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040018386 "DepSymbols" => $DepLibrary_Symbol{1},
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040018387 "SymbolVersion" => $SymVer{1},
18388 "LibraryVersion" => $Descriptor{1}{"Version"},
18389 "LibraryName" => $TargetLibraryName,
18390 "Language" => $COMMON_LANGUAGE{1},
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040018391 "SkipTypes" => $SkipTypes{1},
18392 "SkipSymbols" => $SkipSymbols{1},
18393 "SkipNameSpaces" => $SkipNameSpaces{1},
18394 "SkipHeaders" => $SkipHeadersList{1},
18395 "TargetHeaders" => $TargetHeaders{1},
18396 "Headers" => \%HeadersInfo,
18397 "Constants" => $Constants{1},
18398 "NameSpaces" => $NestedNameSpaces{1},
18399 "Target" => $OStarget,
18400 "Arch" => getArch(1),
18401 "WordSize" => $WORD_SIZE{1},
18402 "GccVersion" => get_dumpversion($GCC_PATH),
18403 "ABI_DUMP_VERSION" => $ABI_DUMP_VERSION,
18404 "ABI_COMPLIANCE_CHECKER_VERSION" => $TOOL_VERSION
18405 );
18406 if($ExtendedCheck)
18407 { # --ext option
18408 $LibraryABI{"Mode"} = "Extended";
18409 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040018410 if($BinaryOnly)
18411 { # --binary
18412 $LibraryABI{"BinOnly"} = 1;
18413 }
18414 else
18415 { # default
18416 $LibraryABI{"SrcBin"} = 1;
18417 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +040018418
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040018419 if($StdOut)
18420 { # --stdout option
18421 print STDOUT Dumper(\%LibraryABI);
18422 printMsg("INFO", "ABI dump has been generated to stdout");
18423 return;
18424 }
18425 else
18426 { # write to gzipped file
18427 my $DumpPath = "abi_dumps/$TargetLibraryName/".$TargetLibraryName."_".$Descriptor{1}{"Version"}.".abi.".$AR_EXT;
18428 if($OutputDumpPath)
18429 { # user defined path
18430 $DumpPath = $OutputDumpPath;
18431 }
18432 if(not $DumpPath=~s/\Q.$AR_EXT\E\Z//g) {
18433 exitStatus("Error", "the dump path (-dump-path option) should be the path to a *.$AR_EXT file");
18434 }
18435 my ($DDir, $DName) = separate_path($DumpPath);
18436 my $DPath = $TMP_DIR."/".$DName;
18437 mkpath($DDir);
Andrey Ponomarenko85043792012-05-14 16:48:07 +040018438
18439 open(DUMP, ">", $DPath) || die ("can't open file \'$DPath\': $!\n");
18440 print DUMP Dumper(\%LibraryABI);
18441 close(DUMP);
18442
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040018443 if(not -s $DPath) {
18444 exitStatus("Error", "can't create ABI dump because something is going wrong with the Data::Dumper module");
18445 }
18446 my $Pkg = createArchive($DPath, $DDir);
18447 printMsg("INFO", "library ABI has been dumped to:\n $Pkg");
18448 printMsg("INFO", "you can transfer this dump everywhere and use instead of the ".$Descriptor{1}{"Version"}." version descriptor");
18449 }
18450}
18451
18452sub quickEmptyReports()
18453{ # Quick "empty" reports
18454 # 4 times faster than merging equal dumps
18455 # NOTE: the dump contains the "LibraryVersion" attribute
18456 # if you change the version, then your dump will be different
18457 # OVERCOME: use -v1 and v2 options for comparing dumps
18458 # and don't change version in the XML descriptor (and dumps)
18459 # OVERCOME 2: separate meta info from the dumps in ACC 2.0
18460 if(-s $Descriptor{1}{"Path"} == -s $Descriptor{2}{"Path"})
18461 {
18462 my $FilePath1 = unpackDump($Descriptor{1}{"Path"});
18463 my $FilePath2 = unpackDump($Descriptor{2}{"Path"});
18464 if($FilePath1 and $FilePath2)
18465 {
Andrey Ponomarenko85043792012-05-14 16:48:07 +040018466 local $/ = undef;
18467
18468 open(DUMP1, $FilePath1);
18469 my $Content1 = <DUMP1>;
18470 close(DUMP1);
18471
18472 open(DUMP2, $FilePath2);
18473 my $Content2 = <DUMP2>;
18474 close(DUMP2);
18475
18476 if($Content1 eq $Content2)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040018477 {
Andrey Ponomarenko85043792012-05-14 16:48:07 +040018478 # clean memory
18479 undef $Content2;
18480
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040018481 # read a number of headers, libs, symbols and types
Andrey Ponomarenko85043792012-05-14 16:48:07 +040018482 my $ABIdump = eval($Content1);
18483
18484 # clean memory
18485 undef $Content1;
18486
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040018487 if(not $ABIdump) {
18488 exitStatus("Error", "internal error");
18489 }
18490 if(not $ABIdump->{"TypeInfo"})
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040018491 { # support for old dumps
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040018492 $ABIdump->{"TypeInfo"} = $ABIdump->{"TypeDescr"};
18493 }
18494 if(not $ABIdump->{"SymbolInfo"})
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040018495 { # support for old dumps
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040018496 $ABIdump->{"SymbolInfo"} = $ABIdump->{"FuncDescr"};
18497 }
18498 read_Headers_DumpInfo($ABIdump, 1);
18499 read_Libs_DumpInfo($ABIdump, 1);
18500 read_Machine_DumpInfo($ABIdump, 1);
18501 read_Machine_DumpInfo($ABIdump, 2);
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040018502
18503 %{$CheckedTypes{"Binary"}} = %{$ABIdump->{"TypeInfo"}};
18504 %{$CheckedTypes{"Source"}} = %{$ABIdump->{"TypeInfo"}};
18505
18506 %{$CheckedSymbols{"Binary"}} = %{$ABIdump->{"SymbolInfo"}};
18507 %{$CheckedSymbols{"Source"}} = %{$ABIdump->{"SymbolInfo"}};
18508
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040018509 $Descriptor{1}{"Version"} = $TargetVersion{1}?$TargetVersion{1}:$ABIdump->{"LibraryVersion"};
18510 $Descriptor{2}{"Version"} = $TargetVersion{2}?$TargetVersion{2}:$ABIdump->{"LibraryVersion"};
18511 exitReport();
18512 }
18513 }
18514 }
18515}
18516
18517sub initLogging($)
18518{
18519 my $LibVersion = $_[0];
18520 # create log directory
18521 my ($LOG_DIR, $LOG_FILE) = ("logs/$TargetLibraryName/".$Descriptor{$LibVersion}{"Version"}, "log.txt");
18522 if($OutputLogPath{$LibVersion})
18523 { # user-defined by -log-path option
18524 ($LOG_DIR, $LOG_FILE) = separate_path($OutputLogPath{$LibVersion});
18525 }
18526 if($LogMode ne "n") {
18527 mkpath($LOG_DIR);
18528 }
18529 $LOG_PATH{$LibVersion} = get_abs_path($LOG_DIR)."/".$LOG_FILE;
18530 resetLogging($LibVersion);
18531 if($Debug)
18532 { # debug directory
18533 $DEBUG_PATH{$LibVersion} = "debug/$TargetLibraryName/".$Descriptor{$LibVersion}{"Version"};
18534 rmtree($DEBUG_PATH{$LibVersion});
18535 }
18536}
18537
18538sub writeLog($$)
18539{
18540 my ($LibVersion, $Msg) = @_;
18541 if($LogMode ne "n") {
18542 appendFile($LOG_PATH{$LibVersion}, $Msg);
18543 }
18544}
18545
18546sub resetLogging($)
18547{
18548 my $LibVersion = $_[0];
18549 if($LogMode!~/a|n/)
18550 { # remove old log
18551 unlink($LOG_PATH{$LibVersion});
18552 }
18553}
18554
18555sub printErrorLog($)
18556{
18557 my $LibVersion = $_[0];
18558 if($LogMode ne "n") {
18559 printMsg("ERROR", "see log for details:\n ".$LOG_PATH{$LibVersion}."\n");
18560 }
18561}
18562
18563sub isDump($)
18564{
18565 if(get_filename($_[0])=~/\A(.+)\.abi(\Q.tar.gz\E|\Q.zip\E|)\Z/)
18566 { # returns a name of package
18567 return $1;
18568 }
18569 return 0;
18570}
18571
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040018572sub compareInit()
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040018573{
18574 # read input XML descriptors or ABI dumps
18575 if(not $Descriptor{1}{"Path"}) {
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040018576 exitStatus("Error", "-old option is not specified");
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040018577 }
18578 my @DParts1 = split(/\s*,\s*/, $Descriptor{1}{"Path"});
18579 foreach my $Part (@DParts1)
18580 {
18581 if(not -e $Part) {
18582 exitStatus("Access_Error", "can't access \'$Part\'");
18583 }
18584 }
18585 if(not $Descriptor{2}{"Path"}) {
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040018586 exitStatus("Error", "-new option is not specified");
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040018587 }
18588 my @DParts2 = split(/\s*,\s*/, $Descriptor{2}{"Path"});
18589 foreach my $Part (@DParts2)
18590 {
18591 if(not -e $Part) {
18592 exitStatus("Access_Error", "can't access \'$Part\'");
18593 }
18594 }
18595 detect_default_paths("bin"); # to extract dumps
18596 if($#DParts1==0 and $#DParts2==0
18597 and isDump($Descriptor{1}{"Path"})
18598 and isDump($Descriptor{2}{"Path"}))
18599 { # optimization: equal ABI dumps
18600 quickEmptyReports();
18601 }
18602 checkVersionNum(1, $Descriptor{1}{"Path"});
18603 checkVersionNum(2, $Descriptor{2}{"Path"});
18604 printMsg("INFO", "preparation, please wait ...");
18605 foreach my $Part (@DParts1)
18606 {
18607 if(isDump($Part)) {
18608 read_ABI_Dump(1, $Part);
18609 }
18610 else {
18611 readDescriptor(1, createDescriptor(1, $Part));
18612 }
18613 }
18614 foreach my $Part (@DParts2)
18615 {
18616 if(isDump($Part)) {
18617 read_ABI_Dump(2, $Part);
18618 }
18619 else {
18620 readDescriptor(2, createDescriptor(2, $Part));
18621 }
18622 }
18623 initLogging(1);
18624 initLogging(2);
18625 # check consistency
18626 if(not $Descriptor{1}{"Headers"}
18627 and not $Descriptor{1}{"Libs"}) {
18628 exitStatus("Error", "descriptor d1 does not contain both header files and libraries info");
18629 }
18630 if(not $Descriptor{2}{"Headers"}
18631 and not $Descriptor{2}{"Libs"}) {
18632 exitStatus("Error", "descriptor d2 does not contain both header files and libraries info");
18633 }
18634 if($Descriptor{1}{"Headers"} and not $Descriptor{1}{"Libs"}
18635 and not $Descriptor{2}{"Headers"} and $Descriptor{2}{"Libs"}) {
18636 exitStatus("Error", "can't compare headers with $SLIB_TYPE libraries");
18637 }
18638 elsif(not $Descriptor{1}{"Headers"} and $Descriptor{1}{"Libs"}
18639 and $Descriptor{2}{"Headers"} and not $Descriptor{2}{"Libs"}) {
18640 exitStatus("Error", "can't compare $SLIB_TYPE libraries with headers");
18641 }
18642 if(not $Descriptor{1}{"Headers"}) {
18643 if($CheckHeadersOnly_Opt) {
18644 exitStatus("Error", "can't find header files info in descriptor d1");
18645 }
18646 }
18647 if(not $Descriptor{2}{"Headers"}) {
18648 if($CheckHeadersOnly_Opt) {
18649 exitStatus("Error", "can't find header files info in descriptor d2");
18650 }
18651 }
18652 if(not $Descriptor{1}{"Headers"}
18653 or not $Descriptor{2}{"Headers"}) {
18654 if(not $CheckObjectsOnly_Opt) {
18655 printMsg("WARNING", "comparing $SLIB_TYPE libraries only");
18656 $CheckObjectsOnly = 1;
18657 }
18658 }
18659 if(not $Descriptor{1}{"Libs"}) {
18660 if($CheckObjectsOnly_Opt) {
18661 exitStatus("Error", "can't find $SLIB_TYPE libraries info in descriptor d1");
18662 }
18663 }
18664 if(not $Descriptor{2}{"Libs"}) {
18665 if($CheckObjectsOnly_Opt) {
18666 exitStatus("Error", "can't find $SLIB_TYPE libraries info in descriptor d2");
18667 }
18668 }
18669 if(not $Descriptor{1}{"Libs"}
18670 or not $Descriptor{2}{"Libs"})
18671 { # comparing standalone header files
18672 # comparing ABI dumps created with --headers-only
18673 if(not $CheckHeadersOnly_Opt)
18674 {
18675 printMsg("WARNING", "checking headers only");
18676 $CheckHeadersOnly = 1;
18677 }
18678 }
18679 if($UseDumps)
18680 { # --use-dumps
18681 # parallel processing
18682 my $pid = fork();
18683 if($pid)
18684 { # dump on two CPU cores
18685 my @PARAMS = ("-dump", $Descriptor{1}{"Path"}, "-l", $TargetLibraryName);
18686 if($RelativeDirectory{1}) {
18687 @PARAMS = (@PARAMS, "-relpath", $RelativeDirectory{1});
18688 }
18689 if($OutputLogPath{1}) {
18690 @PARAMS = (@PARAMS, "-log-path", $OutputLogPath{1});
18691 }
18692 if($CrossGcc) {
18693 @PARAMS = (@PARAMS, "-cross-gcc", $CrossGcc);
18694 }
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040018695 if($Quiet)
18696 {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040018697 @PARAMS = (@PARAMS, "-quiet");
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040018698 @PARAMS = (@PARAMS, "-logging-mode", "a");
18699 }
18700 elsif($LogMode and $LogMode ne "w")
18701 { # "w" is default
18702 @PARAMS = (@PARAMS, "-logging-mode", $LogMode);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040018703 }
18704 if($ExtendedCheck) {
18705 @PARAMS = (@PARAMS, "-extended");
18706 }
18707 if($UserLang) {
18708 @PARAMS = (@PARAMS, "-lang", $UserLang);
18709 }
18710 if($TargetVersion{1}) {
18711 @PARAMS = (@PARAMS, "-vnum", $TargetVersion{1});
18712 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +040018713 if($BinaryOnly) {
18714 @PARAMS = (@PARAMS, "-binary");
18715 }
18716 if($SourceOnly) {
18717 @PARAMS = (@PARAMS, "-source");
18718 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040018719 if($SortDump) {
18720 @PARAMS = (@PARAMS, "-sort");
18721 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +040018722 if($Debug)
18723 {
18724 @PARAMS = (@PARAMS, "-debug");
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040018725 printMsg("INFO", "running perl $0 @PARAMS");
Andrey Ponomarenko85043792012-05-14 16:48:07 +040018726 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040018727 system("perl", $0, @PARAMS);
18728 if($?) {
18729 exit(1);
18730 }
18731 }
18732 else
18733 { # child
18734 my @PARAMS = ("-dump", $Descriptor{2}{"Path"}, "-l", $TargetLibraryName);
18735 if($RelativeDirectory{2}) {
18736 @PARAMS = (@PARAMS, "-relpath", $RelativeDirectory{2});
18737 }
18738 if($OutputLogPath{2}) {
18739 @PARAMS = (@PARAMS, "-log-path", $OutputLogPath{2});
18740 }
18741 if($CrossGcc) {
18742 @PARAMS = (@PARAMS, "-cross-gcc", $CrossGcc);
18743 }
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040018744 if($Quiet)
18745 {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040018746 @PARAMS = (@PARAMS, "-quiet");
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040018747 @PARAMS = (@PARAMS, "-logging-mode", "a");
18748 }
18749 elsif($LogMode and $LogMode ne "w")
18750 { # "w" is default
18751 @PARAMS = (@PARAMS, "-logging-mode", $LogMode);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040018752 }
18753 if($ExtendedCheck) {
18754 @PARAMS = (@PARAMS, "-extended");
18755 }
18756 if($UserLang) {
18757 @PARAMS = (@PARAMS, "-lang", $UserLang);
18758 }
18759 if($TargetVersion{2}) {
18760 @PARAMS = (@PARAMS, "-vnum", $TargetVersion{2});
18761 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +040018762 if($BinaryOnly) {
18763 @PARAMS = (@PARAMS, "-binary");
18764 }
18765 if($SourceOnly) {
18766 @PARAMS = (@PARAMS, "-source");
18767 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040018768 if($SortDump) {
18769 @PARAMS = (@PARAMS, "-sort");
18770 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +040018771 if($Debug)
18772 {
18773 @PARAMS = (@PARAMS, "-debug");
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040018774 printMsg("INFO", "running perl $0 @PARAMS");
Andrey Ponomarenko85043792012-05-14 16:48:07 +040018775 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040018776 system("perl", $0, @PARAMS);
18777 if($?) {
18778 exit(1);
18779 }
18780 else {
18781 exit(0);
18782 }
18783 }
18784 waitpid($pid, 0);
18785 my @CMP_PARAMS = ("-l", $TargetLibraryName);
18786 @CMP_PARAMS = (@CMP_PARAMS, "-d1", "abi_dumps/$TargetLibraryName/".$TargetLibraryName."_".$Descriptor{1}{"Version"}.".abi.$AR_EXT");
18787 @CMP_PARAMS = (@CMP_PARAMS, "-d2", "abi_dumps/$TargetLibraryName/".$TargetLibraryName."_".$Descriptor{2}{"Version"}.".abi.$AR_EXT");
18788 if($TargetLibraryFName ne $TargetLibraryName) {
18789 @CMP_PARAMS = (@CMP_PARAMS, "-l-full", $TargetLibraryFName);
18790 }
18791 if($ShowRetVal) {
18792 @CMP_PARAMS = (@CMP_PARAMS, "-show-retval");
18793 }
18794 if($CrossGcc) {
18795 @CMP_PARAMS = (@CMP_PARAMS, "-cross-gcc", $CrossGcc);
18796 }
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040018797 if($Quiet)
18798 {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040018799 @CMP_PARAMS = (@CMP_PARAMS, "-quiet");
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040018800 @CMP_PARAMS = (@CMP_PARAMS, "-logging-mode", "a");
18801 }
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040018802 elsif($LogMode and $LogMode ne "w")
18803 { # "w" is default
18804 @CMP_PARAMS = (@CMP_PARAMS, "-logging-mode", $LogMode);
18805 }
18806 if($ReportFormat and $ReportFormat ne "html")
18807 { # HTML is default format
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040018808 @CMP_PARAMS = (@CMP_PARAMS, "-report-format", $ReportFormat);
18809 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040018810 if($OutputReportPath) {
18811 @CMP_PARAMS = (@CMP_PARAMS, "-report-path", $OutputReportPath);
18812 }
18813 if($BinaryReportPath) {
18814 @CMP_PARAMS = (@CMP_PARAMS, "-bin-report-path", $BinaryReportPath);
18815 }
18816 if($SourceReportPath) {
18817 @CMP_PARAMS = (@CMP_PARAMS, "-src-report-path", $SourceReportPath);
18818 }
18819 if($LoggingPath) {
18820 @CMP_PARAMS = (@CMP_PARAMS, "-log-path", $LoggingPath);
18821 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +040018822 if($Browse) {
18823 @CMP_PARAMS = (@CMP_PARAMS, "-browse", $Browse);
18824 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040018825 if($OpenReport) {
18826 @CMP_PARAMS = (@CMP_PARAMS, "-open");
18827 }
18828 if($Debug)
18829 {
18830 @CMP_PARAMS = (@CMP_PARAMS, "-debug");
18831 printMsg("INFO", "running perl $0 @CMP_PARAMS");
Andrey Ponomarenko85043792012-05-14 16:48:07 +040018832 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040018833 system("perl", $0, @CMP_PARAMS);
18834 exit($?>>8);
18835 }
18836 if(not $Descriptor{1}{"Dump"}
18837 or not $Descriptor{2}{"Dump"})
18838 { # need GCC toolchain to analyze
18839 # header files and libraries
18840 detect_default_paths("inc|lib|gcc");
18841 }
18842 if(not $Descriptor{1}{"Dump"})
18843 {
18844 if(not $CheckHeadersOnly) {
18845 readLibs(1);
18846 }
18847 if($CheckHeadersOnly) {
18848 setLanguage(1, "C++");
18849 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +040018850 if(not $CheckObjectsOnly) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040018851 searchForHeaders(1);
18852 }
18853 $WORD_SIZE{1} = detectWordSize();
18854 }
18855 if(not $Descriptor{2}{"Dump"})
18856 {
18857 if(not $CheckHeadersOnly) {
18858 readLibs(2);
18859 }
18860 if($CheckHeadersOnly) {
18861 setLanguage(2, "C++");
18862 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +040018863 if(not $CheckObjectsOnly) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040018864 searchForHeaders(2);
18865 }
18866 $WORD_SIZE{2} = detectWordSize();
18867 }
18868 if($WORD_SIZE{1} ne $WORD_SIZE{2})
18869 { # support for old ABI dumps
18870 # try to synch different WORD sizes
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040018871 if(not checkDump(1, "2.1"))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040018872 {
18873 $WORD_SIZE{1} = $WORD_SIZE{2};
18874 printMsg("WARNING", "set WORD size to ".$WORD_SIZE{2}." bytes");
18875 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040018876 elsif(not checkDump(2, "2.1"))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040018877 {
18878 $WORD_SIZE{2} = $WORD_SIZE{1};
18879 printMsg("WARNING", "set WORD size to ".$WORD_SIZE{1}." bytes");
18880 }
18881 }
18882 elsif(not $WORD_SIZE{1}
18883 and not $WORD_SIZE{2})
18884 { # support for old ABI dumps
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040018885 $WORD_SIZE{1} = "4";
18886 $WORD_SIZE{2} = "4";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040018887 }
18888 if($Descriptor{1}{"Dump"})
18889 { # support for old ABI dumps
18890 prepareTypes(1);
18891 }
18892 if($Descriptor{2}{"Dump"})
18893 { # support for old ABI dumps
18894 prepareTypes(2);
18895 }
18896 if($AppPath and not keys(%{$Symbol_Library{1}})) {
18897 printMsg("WARNING", "the application ".get_filename($AppPath)." has no symbols imported from the $SLIB_TYPE libraries");
18898 }
18899 # started to process input data
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040018900 if(not $CheckObjectsOnly)
18901 {
18902 if($Descriptor{1}{"Headers"}
18903 and not $Descriptor{1}{"Dump"}) {
18904 readHeaders(1);
18905 }
18906 if($Descriptor{2}{"Headers"}
18907 and not $Descriptor{2}{"Dump"}) {
18908 readHeaders(2);
18909 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040018910 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +040018911
18912 # clean memory
18913 %SystemHeaders = ();
18914 %mangled_name_gcc = ();
18915
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040018916 prepareSymbols(1);
18917 prepareSymbols(2);
Andrey Ponomarenko16934472012-03-29 15:37:04 +040018918
Andrey Ponomarenko85043792012-05-14 16:48:07 +040018919 # clean memory
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040018920 %SymbolInfo = ();
Andrey Ponomarenko16934472012-03-29 15:37:04 +040018921
18922 # Virtual Tables
18923 registerVTable(1);
18924 registerVTable(2);
18925
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040018926 if(not checkDump(1, "1.22")
18927 and checkDump(2, "1.22"))
Andrey Ponomarenko16934472012-03-29 15:37:04 +040018928 { # support for old ABI dumps
18929 foreach my $ClassName (keys(%{$VirtualTable{2}}))
18930 {
18931 if($ClassName=~/</)
18932 { # templates
18933 if(not defined $VirtualTable{1}{$ClassName})
18934 { # synchronize
18935 delete($VirtualTable{2}{$ClassName});
18936 }
18937 }
18938 }
18939 }
18940
18941 registerOverriding(1);
18942 registerOverriding(2);
18943
18944 setVirtFuncPositions(1);
18945 setVirtFuncPositions(2);
18946
18947 # Other
18948 addParamNames(1);
18949 addParamNames(2);
18950
18951 detectChangedTypedefs();
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040018952}
18953
18954sub compareAPIs($)
18955{
18956 my $Level = $_[0];
18957 readRules($Level);
18958 if($Level eq "Binary") {
18959 printMsg("INFO", "comparing ABIs ...");
18960 }
18961 else {
18962 printMsg("INFO", "comparing APIs ...");
18963 }
18964 if($CheckHeadersOnly
18965 or $Level eq "Source")
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040018966 { # added/removed in headers
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040018967 detectAdded_H($Level);
18968 detectRemoved_H($Level);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040018969 }
18970 else
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040018971 { # added/removed in libs
18972 detectAdded($Level);
18973 detectRemoved($Level);
18974 }
18975 if(not $CheckObjectsOnly)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040018976 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040018977 mergeSignatures($Level);
18978 if(keys(%{$CheckedSymbols{$Level}})) {
18979 mergeConstants($Level);
18980 }
18981 }
18982 if($CheckHeadersOnly
18983 or $Level eq "Source")
18984 { # added/removed in headers
18985 mergeHeaders($Level);
18986 }
18987 else
18988 { # added/removed in libs
18989 mergeLibs($Level);
18990 if($CheckImpl
18991 and $Level eq "Binary") {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040018992 mergeImpl();
18993 }
18994 }
18995}
18996
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040018997sub writeOpts()
18998{
18999 my %Opts = (
19000 "OStarget"=>$OStarget,
19001 "Debug"=>$Debug,
19002 "Quiet"=>$Quiet,
19003 "LogMode"=>$LogMode,
19004 "CheckHeadersOnly"=>$CheckHeadersOnly,
19005
19006 "SystemRoot"=>$SystemRoot,
19007 "MODULES_DIR"=>$MODULES_DIR,
19008 "GCC_PATH"=>$GCC_PATH,
19009 "TargetSysInfo"=>$TargetSysInfo,
19010 "CrossPrefix"=>$CrossPrefix,
19011 "TargetLibraryName"=>$TargetLibraryName,
19012 "CrossGcc"=>$CrossGcc,
19013 "UseStaticLibs"=>$UseStaticLibs,
19014 "NoStdInc"=>$NoStdInc
19015 );
19016 return \%Opts;
19017}
19018
19019sub get_CoreError($)
19020{
19021 my %CODE_ERROR = reverse(%ERROR_CODE);
19022 return $CODE_ERROR{$_[0]};
19023}
19024
19025sub scenario()
19026{
19027 if($StdOut)
19028 { # enable quiet mode
19029 $Quiet = 1;
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040019030 $JoinReport = 1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040019031 }
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040019032 if(not $LogMode)
19033 { # default
19034 $LogMode = "w";
19035 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040019036 if($UserLang)
19037 { # --lang=C++
19038 $UserLang = uc($UserLang);
19039 $COMMON_LANGUAGE{1}=$UserLang;
19040 $COMMON_LANGUAGE{2}=$UserLang;
19041 }
19042 if($LoggingPath)
19043 {
19044 $OutputLogPath{1} = $LoggingPath;
19045 $OutputLogPath{2} = $LoggingPath;
19046 if($Quiet) {
19047 $COMMON_LOG_PATH = $LoggingPath;
19048 }
19049 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040019050 if($BinaryOnly and $SourceOnly)
19051 { # both --binary and --source
19052 # is the default mode
19053 $DoubleReport = 1;
19054 $JoinReport = 0;
19055 $BinaryOnly = 0;
19056 $SourceOnly = 0;
19057 if($OutputReportPath)
19058 { # --report-path
19059 $DoubleReport = 0;
19060 $JoinReport = 1;
19061 }
19062 }
19063 elsif($BinaryOnly or $SourceOnly)
19064 { # --binary or --source
19065 $DoubleReport = 0;
19066 $JoinReport = 0;
19067 }
19068 if($UseXML)
19069 { # --xml option
19070 $ReportFormat = "xml";
19071 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040019072 if($ReportFormat)
19073 { # validate
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040019074 $ReportFormat = lc($ReportFormat);
19075 if($ReportFormat!~/\A(xml|html|htm)\Z/) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040019076 exitStatus("Error", "unknown format \'$ReportFormat\'");
19077 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040019078 if($ReportFormat eq "htm")
19079 { # HTM == HTML
19080 $ReportFormat = "html";
19081 }
19082 elsif($ReportFormat eq "xml")
19083 { # --report-format=XML equal to --xml
19084 $UseXML = 1;
19085 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040019086 }
19087 else
19088 { # default: HTML
19089 $ReportFormat = "html";
19090 }
19091 if($Quiet and $LogMode!~/a|n/)
19092 { # --quiet log
19093 if(-f $COMMON_LOG_PATH) {
19094 unlink($COMMON_LOG_PATH);
19095 }
19096 }
19097 if($TestTool and $UseDumps)
19098 { # --test && --use-dumps == --test-dump
19099 $TestDump = 1;
19100 }
19101 if($Help) {
19102 HELP_MESSAGE();
19103 exit(0);
19104 }
19105 if($InfoMsg) {
19106 INFO_MESSAGE();
19107 exit(0);
19108 }
19109 if($ShowVersion) {
19110 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.");
19111 exit(0);
19112 }
19113 if($DumpVersion) {
19114 printMsg("INFO", $TOOL_VERSION);
19115 exit(0);
19116 }
19117 if($ExtendedCheck) {
19118 $CheckHeadersOnly = 1;
19119 }
19120 if($SystemRoot_Opt)
19121 { # user defined root
19122 if(not -e $SystemRoot_Opt) {
19123 exitStatus("Access_Error", "can't access \'$SystemRoot\'");
19124 }
19125 $SystemRoot = $SystemRoot_Opt;
19126 $SystemRoot=~s/[\/]+\Z//g;
19127 if($SystemRoot) {
19128 $SystemRoot = get_abs_path($SystemRoot);
19129 }
19130 }
19131 $Data::Dumper::Sortkeys = 1;
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +040019132
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040019133 if($SortDump)
19134 {
19135 $Data::Dumper::Useperl = 1;
19136 $Data::Dumper::Sortkeys = \&dump_sorting;
19137 }
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +040019138
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040019139 if($TargetLibsPath)
19140 {
19141 if(not -f $TargetLibsPath) {
19142 exitStatus("Access_Error", "can't access file \'$TargetLibsPath\'");
19143 }
19144 foreach my $Lib (split(/\s*\n\s*/, readFile($TargetLibsPath))) {
19145 $TargetLibs{$Lib} = 1;
19146 }
19147 }
19148 if($TargetHeadersPath)
19149 { # --headers-list
19150 if(not -f $TargetHeadersPath) {
19151 exitStatus("Access_Error", "can't access file \'$TargetHeadersPath\'");
19152 }
19153 foreach my $Header (split(/\s*\n\s*/, readFile($TargetHeadersPath)))
19154 {
19155 $TargetHeaders{1}{$Header} = 1;
19156 $TargetHeaders{2}{$Header} = 1;
19157 }
19158 }
19159 if($TargetHeader)
19160 { # --header
19161 $TargetHeaders{1}{$TargetHeader} = 1;
19162 $TargetHeaders{2}{$TargetHeader} = 1;
19163 }
19164 if($TestTool
19165 or $TestDump)
19166 { # --test, --test-dump
19167 detect_default_paths("bin|gcc"); # to compile libs
19168 loadModule("RegTests");
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040019169 testTool($TestDump, $Debug, $Quiet, $ExtendedCheck, $LogMode,
19170 $ReportFormat, $LIB_EXT, $GCC_PATH, $Browse, $OpenReport, $SortDump);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040019171 exit(0);
19172 }
19173 if($DumpSystem)
19174 { # --dump-system
19175 loadModule("SysCheck");
19176 if($DumpSystem=~/\.xml\Z/)
19177 { # system XML descriptor
19178 if(not -f $DumpSystem) {
19179 exitStatus("Access_Error", "can't access file \'$DumpSystem\'");
19180 }
19181 my $Ret = readSystemDescriptor(readFile($DumpSystem));
19182 foreach (@{$Ret->{"Tools"}}) {
19183 $SystemPaths{"bin"}{$_} = 1;
19184 $TargetTools{$_}=1;
19185 }
19186 if($Ret->{"CrossPrefix"}) {
19187 $CrossPrefix = $Ret->{"CrossPrefix"};
19188 }
19189 }
19190 elsif($SystemRoot_Opt)
19191 { # -sysroot "/" option
19192 # default target: /usr/lib, /usr/include
19193 # search libs: /usr/lib and /lib
19194 if(not -e $SystemRoot."/usr/lib") {
19195 exitStatus("Access_Error", "can't access '".$SystemRoot."/usr/lib'");
19196 }
19197 if(not -e $SystemRoot."/lib") {
19198 exitStatus("Access_Error", "can't access '".$SystemRoot."/lib'");
19199 }
19200 if(not -e $SystemRoot."/usr/include") {
19201 exitStatus("Access_Error", "can't access '".$SystemRoot."/usr/include'");
19202 }
19203 readSystemDescriptor("
19204 <name>
19205 $DumpSystem
19206 </name>
19207 <headers>
19208 $SystemRoot/usr/include
19209 </headers>
19210 <libs>
19211 $SystemRoot/usr/lib
19212 </libs>
19213 <search_libs>
19214 $SystemRoot/lib
19215 </search_libs>");
19216 }
19217 else {
19218 exitStatus("Error", "-sysroot <dirpath> option should be specified, usually it's \"/\"");
19219 }
19220 detect_default_paths("bin|gcc"); # to check symbols
19221 if($OStarget eq "windows")
19222 { # to run dumpbin.exe
19223 # and undname.exe
19224 check_win32_env();
19225 }
19226 dumpSystem(writeOpts());
19227 exit(0);
19228 }
19229 if($CmpSystems)
19230 { # --cmp-systems
19231 detect_default_paths("bin"); # to extract dumps
19232 loadModule("SysCheck");
19233 cmpSystems($Descriptor{1}{"Path"}, $Descriptor{2}{"Path"}, writeOpts());
19234 exit(0);
19235 }
19236 if($GenerateTemplate) {
19237 generateTemplate();
19238 exit(0);
19239 }
19240 if(not $TargetLibraryName) {
19241 exitStatus("Error", "library name is not selected (option -l <name>)");
19242 }
19243 else
19244 { # validate library name
19245 if($TargetLibraryName=~/[\*\/\\]/) {
19246 exitStatus("Error", "\"\\\", \"\/\" and \"*\" symbols are not allowed in the library name");
19247 }
19248 }
19249 if(not $TargetLibraryFName) {
19250 $TargetLibraryFName = $TargetLibraryName;
19251 }
19252 if($CheckHeadersOnly_Opt and $CheckObjectsOnly_Opt) {
19253 exitStatus("Error", "you can't specify both -headers-only and -objects-only options at the same time");
19254 }
19255 if($SymbolsListPath)
19256 {
19257 if(not -f $SymbolsListPath) {
19258 exitStatus("Access_Error", "can't access file \'$SymbolsListPath\'");
19259 }
19260 foreach my $Interface (split(/\s*\n\s*/, readFile($SymbolsListPath))) {
19261 $SymbolsList{$Interface} = 1;
19262 }
19263 }
19264 if($SkipHeadersPath)
19265 {
19266 if(not -f $SkipHeadersPath) {
19267 exitStatus("Access_Error", "can't access file \'$SkipHeadersPath\'");
19268 }
19269 foreach my $Path (split(/\s*\n\s*/, readFile($SkipHeadersPath)))
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040019270 { # register for both versions
19271 $SkipHeadersList{1}{$Path} = 1;
19272 $SkipHeadersList{2}{$Path} = 1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040019273 my ($CPath, $Type) = classifyPath($Path);
19274 $SkipHeaders{1}{$Type}{$CPath} = 1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040019275 $SkipHeaders{2}{$Type}{$CPath} = 1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040019276 }
19277 }
19278 if($ParamNamesPath)
19279 {
19280 if(not -f $ParamNamesPath) {
19281 exitStatus("Access_Error", "can't access file \'$ParamNamesPath\'");
19282 }
19283 foreach my $Line (split(/\n/, readFile($ParamNamesPath)))
19284 {
19285 if($Line=~s/\A(\w+)\;//)
19286 {
19287 my $Interface = $1;
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040019288 if($Line=~/;(\d+);/)
19289 {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040019290 while($Line=~s/(\d+);(\w+)//) {
19291 $AddIntParams{$Interface}{$1}=$2;
19292 }
19293 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040019294 else
19295 {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040019296 my $Num = 0;
19297 foreach my $Name (split(/;/, $Line)) {
19298 $AddIntParams{$Interface}{$Num++}=$Name;
19299 }
19300 }
19301 }
19302 }
19303 }
19304 if($AppPath)
19305 {
19306 if(not -f $AppPath) {
19307 exitStatus("Access_Error", "can't access file \'$AppPath\'");
19308 }
Andrey Ponomarenko16934472012-03-29 15:37:04 +040019309 foreach my $Interface (readSymbols_App($AppPath)) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040019310 $SymbolsList_App{$Interface} = 1;
19311 }
19312 }
19313 if($DumpAPI)
19314 { # --dump-abi
19315 # make an API dump
19316 create_ABI_Dump();
19317 exit($COMPILE_ERRORS);
19318 }
19319 # default: compare APIs
19320 # -d1 <path>
19321 # -d2 <path>
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040019322 compareInit();
19323 if($JoinReport or $DoubleReport)
19324 {
19325 compareAPIs("Binary");
19326 compareAPIs("Source");
19327 }
19328 elsif($BinaryOnly) {
19329 compareAPIs("Binary");
19330 }
19331 elsif($SourceOnly) {
19332 compareAPIs("Source");
19333 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040019334 exitReport();
19335}
19336
19337scenario();