blob: f61894fe7b20669953facd4274eaa2c72d251803 [file] [log] [blame]
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04001#!/usr/bin/perl
2###########################################################################
Andrey Ponomarenko85043792012-05-14 16:48:07 +04003# ABI Compliance Checker (ACC) 1.97.5
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 Ponomarenko85043792012-05-14 16:48:07 +040058my $TOOL_VERSION = "1.97.5";
59my $ABI_DUMP_VERSION = "2.14";
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,
84$SourceReportPath, $UseXML, $Browse);
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,
238 "report-path=s" => \$OutputReportPath,
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +0400239 "bin-report-path=s" => \$BinaryReportPath,
240 "src-report-path=s" => \$SourceReportPath,
Andrey Ponomarenkoab282102012-03-11 11:57:02 +0400241 "log-path=s" => \$LoggingPath,
242 "log1-path=s" => \$OutputLogPath{1},
243 "log2-path=s" => \$OutputLogPath{2},
244 "logging-mode=s" => \$LogMode,
245 "list-affected!" => \$ListAffected,
246 "l-full|lib-full=s" => \$TargetLibraryFName,
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +0400247 "component=s" => \$TargetComponent_Opt,
248 "b|browse=s" => \$Browse
Andrey Ponomarenkoab282102012-03-11 11:57:02 +0400249) or ERR_MESSAGE();
250
251sub ERR_MESSAGE()
252{
253 printMsg("INFO", "\n".$ShortUsage);
254 exit($ERROR_CODE{"Error"});
255}
256
257my $LIB_TYPE = $UseStaticLibs?"static":"dynamic";
258my $SLIB_TYPE = $LIB_TYPE;
259if($OSgroup!~/macos|windows/ and $SLIB_TYPE eq "dynamic")
260{ # show as "shared" library
261 $SLIB_TYPE = "shared";
262}
263my $LIB_EXT = getLIB_EXT($OSgroup);
264my $AR_EXT = getAR_EXT($OSgroup);
265my $BYTE_SIZE = 8;
266my $COMMON_LOG_PATH = "logs/run.log";
267
268my $HelpMessage="
269NAME:
270 ABI Compliance Checker ($CmdName)
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +0400271 Check backward compatibility of a C/C++ library API
Andrey Ponomarenkoab282102012-03-11 11:57:02 +0400272
273DESCRIPTION:
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +0400274 ABI Compliance Checker (ACC) is a tool for checking backward binary and
275 source-level compatibility of a $SLIB_TYPE C/C++ library. The tool checks
276 header files and $SLIB_TYPE libraries (*.$LIB_EXT) of old and new versions and
277 analyzes changes in API and ABI (ABI=API+compiler ABI) that may break binary
278 and/or source-level compatibility: changes in calling stack, v-table changes,
279 removed symbols, renamed fields, etc. Binary incompatibility may result in
280 crashing or incorrect behavior of applications built with an old version of
281 a library if they run on a new one. Source incompatibility may result in
282 recompilation errors with a new library version.
Andrey Ponomarenkoab282102012-03-11 11:57:02 +0400283
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +0400284 The tool is intended for developers of software libraries and maintainers
285 of operating systems who are interested in ensuring backward compatibility,
286 i.e. allow old applications to run or to be recompiled with newer library
287 versions.
288
289 Also the tool can be used by ISVs for checking applications portability to
290 new library versions. Found issues can be taken into account when adapting
291 the application to a new library version.
Andrey Ponomarenkoab282102012-03-11 11:57:02 +0400292
293 This tool is free software: you can redistribute it and/or modify it
294 under the terms of the GNU LGPL or GNU GPL.
295
296USAGE:
297 $CmdName [options]
298
299EXAMPLE:
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +0400300 $CmdName -lib NAME -old OLD.xml -new NEW.xml
Andrey Ponomarenkoab282102012-03-11 11:57:02 +0400301
302 OLD.xml and NEW.xml are XML-descriptors:
303
304 <version>
305 1.0
306 </version>
307
308 <headers>
309 /path1/to/header(s)/
310 /path2/to/header(s)/
311 ...
312 </headers>
313
314 <libs>
315 /path1/to/library(ies)/
316 /path2/to/library(ies)/
317 ...
318 </libs>
319
320INFORMATION OPTIONS:
321 -h|-help
322 Print this help.
323
324 -i|-info
325 Print complete info.
326
327 -v|-version
328 Print version information.
329
330 -dumpversion
331 Print the tool version ($TOOL_VERSION) and don't do anything else.
332
333GENERAL OPTIONS:
334 -l|-lib|-library <name>
335 Library name (without version).
336 It affects only on the path and the title of the report.
337
338 -d1|-old|-o <path>
339 Descriptor of 1st (old) library version.
340 It may be one of the following:
341
342 1. XML-descriptor (VERSION.xml file):
343
344 <version>
345 1.0
346 </version>
347
348 <headers>
349 /path1/to/header(s)/
350 /path2/to/header(s)/
351 ...
352 </headers>
353
354 <libs>
355 /path1/to/library(ies)/
356 /path2/to/library(ies)/
357 ...
358 </libs>
359
360 ... (XML-descriptor template
361 can be generated by -d option)
362
363 2. ABI dump generated by -dump option
364 3. Directory with headers and/or $SLIB_TYPE libraries
365 4. Single header file
366 5. Single $SLIB_TYPE library
367 6. Comma separated list of headers and/or libraries
368
369 If you are using an 2-6 descriptor types then you should
370 specify version numbers with -v1 <num> and -v2 <num> options too.
371
372 For more information, please see:
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +0400373 http://ispras.linuxbase.org/index.php/Library_Descriptor
Andrey Ponomarenkoab282102012-03-11 11:57:02 +0400374
375 -d2|-new|-n <path>
376 Descriptor of 2nd (new) library version.
377
378 -dump|-dump-abi <descriptor path(s)>
379 Dump library ABI to gzipped TXT format file. You can transfer it
380 anywhere and pass instead of the descriptor. Also it can be used
381 for debugging the tool. Compatible dump versions: ".majorVersion($ABI_DUMP_VERSION).".0<=V<=$ABI_DUMP_VERSION
382
383 -old-dumps
384 Enable support for old-version ABI dumps ($OLDEST_SUPPORTED_VERSION<=V<".majorVersion($ABI_DUMP_VERSION).".0).\n";
385
386sub HELP_MESSAGE() {
387 printMsg("INFO", $HelpMessage."
388MORE INFO:
389 $CmdName --info\n");
390}
391
392sub INFO_MESSAGE()
393{
394 printMsg("INFO", "$HelpMessage
395EXTRA OPTIONS:
396 -d|-descriptor-template
397 Create XML-descriptor template ./VERSION.xml
398
399 -app|-application <path>
400 This option allows to specify the application that should be checked
401 for portability to the new library version.
402
403 -static-libs
404 Check static libraries instead of the shared ones. The <libs> section
405 of the XML-descriptor should point to static libraries location.
406
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +0400407 -cross-gcc|-gcc-path <path>
Andrey Ponomarenkoab282102012-03-11 11:57:02 +0400408 Path to the cross GCC compiler to use instead of the usual (host) GCC.
409
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +0400410 -cross-prefix|-gcc-prefix <prefix>
Andrey Ponomarenkoab282102012-03-11 11:57:02 +0400411 GCC toolchain prefix.
412
413 -sysroot <dirpath>
414 Specify the alternative root directory. The tool will search for include
415 paths in the <dirpath>/usr/include and <dirpath>/usr/lib directories.
416
417 -v1|-version1 <num>
418 Specify 1st library version outside the descriptor. This option is needed
419 if you have prefered an alternative descriptor type (see -d1 option).
420
421 In general case you should specify it in the XML-descriptor:
422 <version>
423 VERSION
424 </version>
425
426 -v2|-version2 <num>
427 Specify 2nd library version outside the descriptor.
428
429 -s|-strict
430 Treat all compatibility warnings as problems. Add a number of \"Low\"
431 severity problems to the return value of the tool.
432
433 -headers-only
434 Check header files without $SLIB_TYPE libraries. It is easy to run, but may
435 provide a low quality compatibility report with false positives and
436 without detecting of added/removed symbols.
437
438 Alternatively you can write \"none\" word to the <libs> section
439 in the XML-descriptor:
440 <libs>
441 none
442 </libs>
443
444 -objects-only
445 Check $SLIB_TYPE libraries without header files. It is easy to run, but may
446 provide a low quality compatibility report with false positives and
447 without analysis of changes in parameters and data types.
448
449 Alternatively you can write \"none\" word to the <headers> section
450 in the XML-descriptor:
451 <headers>
452 none
453 </headers>
454
455 -check-impl|-check-implementation
456 Compare canonified disassembled binary code of $SLIB_TYPE libraries to
457 detect changes in the implementation. Add \'Problems with Implementation\'
458 section to the report.
459
460 -show-retval
461 Show the symbol's return type in the report.
462
463 -symbols-list <path>
464 This option allows to specify a file with a list of symbols (mangled
465 names in C++) that should be checked, other symbols will not be checked.
466
467 -skip-headers <path>
468 The file with the list of header files, that should not be checked.
469
470 -use-dumps
471 Make dumps for two versions of a library and compare dumps. This should
472 increase the performance of the tool and decrease the system memory usage.
473
474 -nostdinc
475 Do not search the GCC standard system directories for header files.
476
477 -dump-system <name> -sysroot <dirpath>
478 Find all the shared libraries and header files in <dirpath> directory,
479 create XML descriptors and make ABI dumps for each library. The result
480 set of ABI dumps can be compared (--cmp-systems) with the other one
481 created for other version of operating system in order to check them for
482 compatibility. Do not forget to specify -cross-gcc option if your target
483 system requires some specific version of GCC compiler (different from
484 the host GCC). The system ABI dump will be generated to:
485 sys_dumps/<name>/<arch>
486
487 -dump-system <descriptor.xml>
488 The same as the previous option but takes an XML descriptor of the target
489 system as input, where you should describe it:
490
491 /* Primary sections */
492
493 <name>
494 /* Name of the system */
495 </name>
496
497 <headers>
498 /* The list of paths to header files and/or
499 directories with header files, one per line */
500 </headers>
501
502 <libs>
503 /* The list of paths to shared libraries and/or
504 directories with shared libraries, one per line */
505 </libs>
506
507 /* Optional sections */
508
509 <search_headers>
510 /* List of directories to be searched
511 for header files to automatically
512 generate include paths, one per line */
513 </search_headers>
514
515 <search_libs>
516 /* List of directories to be searched
517 for shared libraries to resolve
518 dependencies, one per line */
519 </search_libs>
520
521 <tools>
522 /* List of directories with tools used
523 for analysis (GCC toolchain), one per line */
524 </tools>
525
526 <cross_prefix>
527 /* GCC toolchain prefix.
528 Examples:
529 arm-linux-gnueabi
530 arm-none-symbianelf */
531 </cross_prefix>
532
533 <gcc_options>
534 /* Additional GCC options, one per line */
535 </gcc_options>
536
537 -sysinfo <dir>
538 This option may be used with -dump-system to dump ABI of operating
539 systems and configure the dumping process.
540 Default:
541 modules/Targets/{unix, symbian, windows}
542
543 -cmp-systems -d1 sys_dumps/<name1>/<arch> -d2 sys_dumps/<name2>/<arch>
544 Compare two system ABI dumps. Create compatibility reports for each
545 library and the common HTML report including the summary of test
546 results for all checked libraries. Report will be generated to:
547 sys_compat_reports/<name1>_to_<name2>/<arch>
548
549 -libs-list <path>
550 The file with a list of libraries, that should be dumped by
551 the -dump-system option or should be checked by the -cmp-systems option.
552
553 -header <name>
554 Check/Dump ABI of this header only.
555
556 -headers-list <path>
557 The file with a list of headers, that should be checked/dumped.
558
559 -ext|-extended
560 If your library A is supposed to be used by other library B and you
561 want to control the ABI of B, then you should enable this option. The
562 tool will check for changes in all data types, even if they are not
563 used by any function in the library A. Such data types are not part
564 of the A library ABI, but may be a part of the ABI of the B library.
565
566 The short scheme is:
567 app C (broken) -> lib B (broken ABI) -> lib A (stable ABI)
568
569 -q|-quiet
570 Print all messages to the file instead of stdout and stderr.
571 Default path (can be changed by -log-path option):
572 $COMMON_LOG_PATH
573
574 -stdout
575 Print analysis results (compatibility reports and ABI dumps) to stdout
576 instead of creating a file. This would allow piping data to other programs.
577
578 -report-format <fmt>
579 Change format of compatibility report.
580 Formats:
581 htm - HTML format (default)
582 xml - XML format
583
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +0400584 -xml
585 Alias for: --report-format=xml
586
Andrey Ponomarenkoab282102012-03-11 11:57:02 +0400587 -lang <lang>
588 Set library language (C or C++). You can use this option if the tool
589 cannot auto-detect a language. This option may be useful for checking
590 C-library headers (--lang=C) in --headers-only or --extended modes.
591
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +0400592 -binary|-bin|-abi
593 Show \"Binary\" compatibility problems only.
594 Generate report to:
595 compat_reports/<library name>/<v1>_to_<v2>/abi_compat_report.html
596
597 -source|-src|-api
598 Show \"Source\" compatibility problems only.
599 Generate report to:
600 compat_reports/<library name>/<v1>_to_<v2>/src_compat_report.html
601
Andrey Ponomarenkoab282102012-03-11 11:57:02 +0400602OTHER OPTIONS:
603 -test
604 Run internal tests. Create two binary incompatible versions of a sample
605 library and run the tool to check them for compatibility. This option
606 allows to check if the tool works correctly in the current environment.
607
608 -test-dump
609 Test ability to create, read and compare ABI dumps.
610
611 -debug
612 Debugging mode. Print debug info on the screen. Save intermediate
613 analysis stages in the debug directory:
614 debug/<library>/<version>/
615
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +0400616 Also consider using --dump option for debugging the tool.
617
Andrey Ponomarenkoab282102012-03-11 11:57:02 +0400618 -cpp-compatible
619 If your header file is written in C language and can be compiled by
620 the C++ compiler (i.e. doesn't contain C++-keywords and other bad
621 things), then you can tell ACC about this and speedup the analysis.
622
623 -p|-params <path>
624 Path to file with the function parameter names. It can be used
625 for improving report view if the library header files have no
626 parameter names. File format:
627
628 func1;param1;param2;param3 ...
629 func2;param1;param2;param3 ...
630 ...
631
632 -relpath <path>
633 Replace {RELPATH} macros to <path> in the XML-descriptor used
634 for dumping the library ABI (see -dump option).
635
636 -relpath1 <path>
637 Replace {RELPATH} macros to <path> in the 1st XML-descriptor (-d1).
638
639 -relpath2 <path>
640 Replace {RELPATH} macros to <path> in the 2nd XML-descriptor (-d2).
641
642 -dump-path <path>
643 Specify a file path (*.abi.$AR_EXT) where to generate an ABI dump.
644 Default:
645 abi_dumps/<library>/<library>_<version>.abi.$AR_EXT
646
647 -report-path <path>
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +0400648 Path to compatibility report.
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +0400649 Default:
650 compat_reports/<library name>/<v1>_to_<v2>/compat_report.html
651
652 -bin-report-path <path>
653 Path to \"Binary\" compatibility report.
Andrey Ponomarenkoab282102012-03-11 11:57:02 +0400654 Default:
655 compat_reports/<library name>/<v1>_to_<v2>/abi_compat_report.html
656
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +0400657 -src-report-path <path>
658 Path to \"Source\" compatibility report.
659 Default:
660 compat_reports/<library name>/<v1>_to_<v2>/src_compat_report.html
661
Andrey Ponomarenkoab282102012-03-11 11:57:02 +0400662 -log-path <path>
663 Log path for all messages.
664 Default:
665 logs/<library>/<version>/log.txt
666
667 -log1-path <path>
668 Log path for 1st version of a library.
669 Default:
670 logs/<library name>/<v1>/log.txt
671
672 -log2-path <path>
673 Log path for 2nd version of a library.
674 Default:
675 logs/<library name>/<v2>/log.txt
676
677 -logging-mode <mode>
678 Change logging mode.
679 Modes:
680 w - overwrite old logs (default)
681 a - append old logs
682 n - do not write any logs
683
684 -list-affected
685 Generate file with the list of incompatible
686 symbols beside the HTML compatibility report.
687 Use 'c++filt \@file' command from GNU binutils
688 to unmangle C++ symbols in the generated file.
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +0400689 Default names:
Andrey Ponomarenkoab282102012-03-11 11:57:02 +0400690 abi_affected.txt
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +0400691 src_affected.txt
Andrey Ponomarenkoab282102012-03-11 11:57:02 +0400692
693 -component <name>
694 The component name in the title and summary of the HTML report.
695 Default:
696 library
697
698 -l-full|-lib-full <name>
699 Change library name in the report title to <name>. By default
700 will be displayed a name specified by -l option.
701
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +0400702 -b|-browse <program>
703 Open report(s) in the browser (firefox, opera, etc.).
704
Andrey Ponomarenkoab282102012-03-11 11:57:02 +0400705REPORT:
706 Compatibility report will be generated to:
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +0400707 compat_reports/<library name>/<v1>_to_<v2>/compat_report.html
Andrey Ponomarenkoab282102012-03-11 11:57:02 +0400708
709 Log will be generated to:
710 logs/<library name>/<v1>/log.txt
711 logs/<library name>/<v2>/log.txt
712
713EXIT CODES:
714 0 - Compatible. The tool has run without any errors.
715 non-zero - Incompatible or the tool has run with errors.
716
717REPORT BUGS TO:
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +0400718 Andrey Ponomarenko <aponomarenko\@rosalab.ru>
Andrey Ponomarenkoab282102012-03-11 11:57:02 +0400719
720MORE INFORMATION:
721 ".$HomePage{"Wiki"}."
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +0400722 ".$HomePage{"Dev1"}."\n");
Andrey Ponomarenkoab282102012-03-11 11:57:02 +0400723}
724
725my $DescriptorTemplate = "
726<?xml version=\"1.0\" encoding=\"utf-8\"?>
727<descriptor>
728
729/* Primary sections */
730
731<version>
732 /* Version of the library */
733</version>
734
735<headers>
736 /* The list of paths to header files and/or
737 directories with header files, one per line */
738</headers>
739
740<libs>
741 /* The list of paths to shared libraries (*.$LIB_EXT) and/or
742 directories with shared libraries, one per line */
743</libs>
744
745/* Optional sections */
746
747<include_paths>
748 /* The list of include paths that will be provided
749 to GCC to compile library headers, one per line.
750 NOTE: If you define this section then the tool
751 will not automatically generate include paths */
752</include_paths>
753
754<add_include_paths>
755 /* The list of include paths that will be added
756 to the automatically generated include paths, one per line */
757</add_include_paths>
758
759<skip_include_paths>
760 /* The list of include paths that will be removed from the
761 list of automatically generated include paths, one per line */
762</skip_include_paths>
763
764<gcc_options>
765 /* Additional GCC options, one per line */
766</gcc_options>
767
768<include_preamble>
769 /* The list of header files that will be
770 included before other headers, one per line.
771 Examples:
772 1) tree.h for libxml2
773 2) ft2build.h for freetype2 */
774</include_preamble>
775
776<defines>
777 /* The list of defines that will be added at the
778 headers compiling stage, one per line:
779 #define A B
780 #define C D */
781</defines>
782
783<skip_types>
784 /* The list of data types, that
785 should not be checked, one per line */
786</skip_types>
787
788<skip_symbols>
789 /* The list of functions (mangled/symbol names in C++),
790 that should not be checked, one per line */
791</skip_symbols>
792
793<skip_namespaces>
794 /* The list of C++ namespaces, that
795 should not be checked, one per line */
796</skip_namespaces>
797
798<skip_constants>
799 /* The list of constants that should
800 not be checked, one name per line */
801</skip_constants>
802
803<skip_headers>
804 /* The list of header files and/or directories
805 with header files that should not be checked, one per line */
806</skip_headers>
807
808<skip_libs>
809 /* The list of shared libraries and/or directories
810 with shared libraries that should not be checked, one per line */
811</skip_libs>
812
813<skip_including>
814 /* The list of header files, that cannot be included
815 directly (or non-self compiled ones), one per line */
816</skip_including>
817
818<search_headers>
819 /* List of directories to be searched
820 for header files to automatically
821 generate include paths, one per line. */
822</search_headers>
823
824<search_libs>
825 /* List of directories to be searched
826 for shared librariess to resolve
827 dependencies, one per line */
828</search_libs>
829
830<tools>
831 /* List of directories with tools used
832 for analysis (GCC toolchain), one per line */
833</tools>
834
835<cross_prefix>
836 /* GCC toolchain prefix.
837 Examples:
838 arm-linux-gnueabi
839 arm-none-symbianelf */
840</cross_prefix>
841
842</descriptor>";
843
844my %Operator_Indication = (
845 "not" => "~",
846 "assign" => "=",
847 "andassign" => "&=",
848 "orassign" => "|=",
849 "xorassign" => "^=",
850 "or" => "|",
851 "xor" => "^",
852 "addr" => "&",
853 "and" => "&",
854 "lnot" => "!",
855 "eq" => "==",
856 "ne" => "!=",
857 "lt" => "<",
858 "lshift" => "<<",
859 "lshiftassign" => "<<=",
860 "rshiftassign" => ">>=",
861 "call" => "()",
862 "mod" => "%",
863 "modassign" => "%=",
864 "subs" => "[]",
865 "land" => "&&",
866 "lor" => "||",
867 "rshift" => ">>",
868 "ref" => "->",
869 "le" => "<=",
870 "deref" => "*",
871 "mult" => "*",
872 "preinc" => "++",
873 "delete" => " delete",
874 "vecnew" => " new[]",
875 "vecdelete" => " delete[]",
876 "predec" => "--",
877 "postinc" => "++",
878 "postdec" => "--",
879 "plusassign" => "+=",
880 "plus" => "+",
881 "minus" => "-",
882 "minusassign" => "-=",
883 "gt" => ">",
884 "ge" => ">=",
885 "new" => " new",
886 "multassign" => "*=",
887 "divassign" => "/=",
888 "div" => "/",
889 "neg" => "-",
890 "pos" => "+",
891 "memref" => "->*",
892 "compound" => "," );
893
894my %CppKeywords_C = map {$_=>1} (
895 # C++ 2003 keywords
896 "public",
897 "protected",
898 "private",
899 "default",
900 "template",
901 "new",
902 #"asm",
903 "dynamic_cast",
904 "auto",
905 "try",
906 "namespace",
907 "typename",
908 "using",
909 "reinterpret_cast",
910 "friend",
911 "class",
912 "virtual",
913 "const_cast",
914 "mutable",
915 "static_cast",
916 "export",
917 # C++0x keywords
918 "noexcept",
919 "nullptr",
920 "constexpr",
921 "static_assert",
922 "explicit",
923 # cannot be used as a macro name
924 # as it is an operator in C++
925 "and",
926 #"and_eq",
927 "not",
928 #"not_eq",
929 "or"
930 #"or_eq",
931 #"bitand",
932 #"bitor",
933 #"xor",
934 #"xor_eq",
935 #"compl"
936);
937
938my %CppKeywords_F = map {$_=>1} (
939 "delete",
940 "catch",
941 "alignof",
942 "thread_local",
943 "decltype",
944 "typeid"
945);
946
947my %CppKeywords_O = map {$_=>1} (
948 "bool",
949 "register",
950 "inline",
951 "operator"
952);
953
954my %CppKeywords_A = map {$_=>1} (
955 "this",
956 "throw"
957);
958
959foreach (keys(%CppKeywords_C),
960keys(%CppKeywords_F),
961keys(%CppKeywords_O)) {
962 $CppKeywords_A{$_}=1;
963}
964
965# Header file extensions as described by gcc
966my $HEADER_EXT = "h|hh|hp|hxx|hpp|h\\+\\+";
967
968my %IntrinsicMangling = (
969 "void" => "v",
970 "bool" => "b",
971 "wchar_t" => "w",
972 "char" => "c",
973 "signed char" => "a",
974 "unsigned char" => "h",
975 "short" => "s",
976 "unsigned short" => "t",
977 "int" => "i",
978 "unsigned int" => "j",
979 "long" => "l",
980 "unsigned long" => "m",
981 "long long" => "x",
982 "__int64" => "x",
983 "unsigned long long" => "y",
984 "__int128" => "n",
985 "unsigned __int128" => "o",
986 "float" => "f",
987 "double" => "d",
988 "long double" => "e",
989 "__float80" => "e",
990 "__float128" => "g",
991 "..." => "z"
992);
993
994my %StdcxxMangling = (
995 "3std"=>"St",
996 "3std9allocator"=>"Sa",
997 "3std12basic_string"=>"Sb",
998 "3std12basic_stringIcE"=>"Ss",
999 "3std13basic_istreamIcE"=>"Si",
1000 "3std13basic_ostreamIcE"=>"So",
1001 "3std14basic_iostreamIcE"=>"Sd"
1002);
1003
1004my %ConstantSuffix = (
1005 "unsigned int"=>"u",
1006 "long"=>"l",
1007 "unsigned long"=>"ul",
1008 "long long"=>"ll",
1009 "unsigned long long"=>"ull"
1010);
1011
1012my %ConstantSuffixR =
1013reverse(%ConstantSuffix);
1014
1015my %OperatorMangling = (
1016 "~" => "co",
1017 "=" => "aS",
1018 "|" => "or",
1019 "^" => "eo",
1020 "&" => "an",#ad (addr)
1021 "==" => "eq",
1022 "!" => "nt",
1023 "!=" => "ne",
1024 "<" => "lt",
1025 "<=" => "le",
1026 "<<" => "ls",
1027 "<<=" => "lS",
1028 ">" => "gt",
1029 ">=" => "ge",
1030 ">>" => "rs",
1031 ">>=" => "rS",
1032 "()" => "cl",
1033 "%" => "rm",
1034 "[]" => "ix",
1035 "&&" => "aa",
1036 "||" => "oo",
1037 "*" => "ml",#de (deref)
1038 "++" => "pp",#
1039 "--" => "mm",#
1040 "new" => "nw",
1041 "delete" => "dl",
1042 "new[]" => "na",
1043 "delete[]" => "da",
1044 "+=" => "pL",
1045 "+" => "pl",#ps (pos)
1046 "-" => "mi",#ng (neg)
1047 "-=" => "mI",
1048 "*=" => "mL",
1049 "/=" => "dV",
1050 "&=" => "aN",
1051 "|=" => "oR",
1052 "%=" => "rM",
1053 "^=" => "eO",
1054 "/" => "dv",
1055 "->*" => "pm",
1056 "->" => "pt",#rf (ref)
1057 "," => "cm",
1058 "?" => "qu",
1059 "." => "dt",
1060 "sizeof"=> "sz"#st
1061);
1062
1063my %GlibcHeader = map {$_=>1} (
1064 "aliases.h",
1065 "argp.h",
1066 "argz.h",
1067 "assert.h",
1068 "cpio.h",
1069 "ctype.h",
1070 "dirent.h",
1071 "envz.h",
1072 "errno.h",
1073 "error.h",
1074 "execinfo.h",
1075 "fcntl.h",
1076 "fstab.h",
1077 "ftw.h",
1078 "glob.h",
1079 "grp.h",
1080 "iconv.h",
1081 "ifaddrs.h",
1082 "inttypes.h",
1083 "langinfo.h",
1084 "limits.h",
1085 "link.h",
1086 "locale.h",
1087 "malloc.h",
1088 "math.h",
1089 "mntent.h",
1090 "monetary.h",
1091 "nl_types.h",
1092 "obstack.h",
1093 "printf.h",
1094 "pwd.h",
1095 "regex.h",
1096 "sched.h",
1097 "search.h",
1098 "setjmp.h",
1099 "shadow.h",
1100 "signal.h",
1101 "spawn.h",
1102 "stdarg.h",
1103 "stdint.h",
1104 "stdio.h",
1105 "stdlib.h",
1106 "string.h",
1107 "tar.h",
1108 "termios.h",
1109 "time.h",
1110 "ulimit.h",
1111 "unistd.h",
1112 "utime.h",
1113 "wchar.h",
1114 "wctype.h",
1115 "wordexp.h" );
1116
1117my %GlibcDir = map {$_=>1} (
1118 "arpa",
1119 "bits",
1120 "gnu",
1121 "netinet",
1122 "net",
1123 "nfs",
1124 "rpc",
1125 "sys",
1126 "linux" );
1127
1128my %LocalIncludes = map {$_=>1} (
1129 "/usr/local/include",
1130 "/usr/local" );
1131
1132my %OS_AddPath=(
1133# These paths are needed if the tool cannot detect them automatically
1134 "macos"=>{
1135 "include"=>{
1136 "/Library"=>1,
1137 "/Developer/usr/include"=>1
1138 },
1139 "lib"=>{
1140 "/Library"=>1,
1141 "/Developer/usr/lib"=>1
1142 },
1143 "bin"=>{
1144 "/Developer/usr/bin"=>1
1145 }
1146 },
1147 "beos"=>{
1148 # Haiku has GCC 2.95.3 by default
1149 # try to find GCC>=3.0 in /boot/develop/abi
1150 "include"=>{
1151 "/boot/common"=>1,
1152 "/boot/develop"=>1},
1153 "lib"=>{
1154 "/boot/common/lib"=>1,
1155 "/boot/system/lib"=>1,
1156 "/boot/apps"=>1},
1157 "bin"=>{
1158 "/boot/common/bin"=>1,
1159 "/boot/system/bin"=>1,
1160 "/boot/develop/abi"=>1
1161 }
1162}
1163);
1164
1165my %Slash_Type=(
1166 "default"=>"/",
1167 "windows"=>"\\"
1168);
1169
1170my $SLASH = $Slash_Type{$OSgroup}?$Slash_Type{$OSgroup}:$Slash_Type{"default"};
1171
1172# Global Variables
1173my %COMMON_LANGUAGE=(
1174 1 => "C",
1175 2 => "C" );
1176
1177my $MAX_COMMAND_LINE_ARGUMENTS = 4096;
1178my (%WORD_SIZE, %CPU_ARCH, %GCC_VERSION);
1179
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04001180my $STDCXX_TESTING = 0;
1181my $GLIBC_TESTING = 0;
1182
1183my $CheckHeadersOnly = $CheckHeadersOnly_Opt;
1184my $CheckObjectsOnly = $CheckObjectsOnly_Opt;
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04001185my $TargetComponent;
1186
1187# Set Target Component Name
1188if($TargetComponent_Opt) {
1189 $TargetComponent = lc($TargetComponent_Opt);
1190}
1191else
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04001192{ # default: library
1193 # other components: header, system, ...
1194 $TargetComponent = "library";
1195}
1196
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04001197my $TOP_REF = "<a style='font-size:11px;' href='#Top'>to the top</a>";
1198
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04001199my $SystemRoot;
1200
1201my $MAIN_CPP_DIR;
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04001202my %RESULT;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04001203my %LOG_PATH;
1204my %DEBUG_PATH;
1205my %Cache;
1206my %LibInfo;
1207my $COMPILE_ERRORS = 0;
1208my %CompilerOptions;
1209my %CheckedDyLib;
1210my $TargetLibraryShortName = parse_libname($TargetLibraryName, "shortest", $OSgroup);
1211
1212# Constants (#defines)
1213my %Constants;
1214my %SkipConstants;
1215
1216# Types
1217my %TypeInfo;
1218my %TemplateInstance_Func;
1219my %TemplateInstance;
Andrey Ponomarenko85043792012-05-14 16:48:07 +04001220my %TemplateDecl;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04001221my %SkipTypes = (
1222 "1"=>{},
1223 "2"=>{} );
1224my %Tid_TDid = (
1225 "1"=>{},
1226 "2"=>{} );
1227my %CheckedTypes;
1228my %TName_Tid;
1229my %EnumMembName_Id;
1230my %NestedNameSpaces = (
1231 "1"=>{},
1232 "2"=>{} );
1233my %UsedType;
1234my %VirtualTable;
Andrey Ponomarenko16934472012-03-29 15:37:04 +04001235my %VirtualTable_Model;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04001236my %ClassVTable;
1237my %ClassVTable_Content;
1238my %VTableClass;
1239my %AllocableClass;
1240my %ClassMethods;
Andrey Ponomarenko16934472012-03-29 15:37:04 +04001241my %ClassNames;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04001242my %Class_SubClasses;
1243my %OverriddenMethods;
Andrey Ponomarenko16934472012-03-29 15:37:04 +04001244my $MAX_ID;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04001245
1246# Typedefs
1247my %Typedef_BaseName;
1248my %Typedef_Tr;
1249my %Typedef_Eq;
1250my %StdCxxTypedef;
1251my %MissedTypedef;
1252
1253# Symbols
1254my %SymbolInfo;
1255my %tr_name;
1256my %mangled_name_gcc;
1257my %mangled_name;
1258my %SkipSymbols = (
1259 "1"=>{},
1260 "2"=>{} );
1261my %SkipNameSpaces = (
1262 "1"=>{},
1263 "2"=>{} );
1264my %SymbolsList;
1265my %SymbolsList_App;
1266my %CheckedSymbols;
1267my %GeneratedSymbols;
1268my %DepSymbols = (
1269 "1"=>{},
1270 "2"=>{} );
1271my %MangledNames;
1272my %AddIntParams;
1273my %Interface_Impl;
1274
1275# Headers
1276my %Include_Preamble;
1277my %Registered_Headers;
1278my %HeaderName_Paths;
1279my %Header_Dependency;
1280my %Include_Neighbors;
1281my %Include_Paths;
1282my %INC_PATH_AUTODETECT = (
1283 "1"=>1,
1284 "2"=>1 );
1285my %Add_Include_Paths;
1286my %Skip_Include_Paths;
1287my %RegisteredDirs;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04001288my %Header_ErrorRedirect;
1289my %Header_Includes;
1290my %Header_ShouldNotBeUsed;
1291my %RecursiveIncludes;
1292my %Header_Include_Prefix;
1293my %SkipHeaders;
1294my %SkipHeadersList=(
1295 "1"=>{},
1296 "2"=>{} );
1297my %SkipLibs;
1298my %Include_Order;
1299my %TUnit_NameSpaces;
1300
1301my %C99Mode = (
1302 "1"=>0,
1303 "2"=>0 );
1304my %AutoPreambleMode = (
1305 "1"=>0,
1306 "2"=>0 );
1307my %MinGWMode = (
1308 "1"=>0,
1309 "2"=>0 );
1310
1311# Shared Objects
1312my %DyLib_DefaultPath;
1313my %InputObject_Paths;
1314my %RegisteredObjDirs;
1315
1316# System Objects
1317my %SystemObjects;
1318my %DefaultLibPaths;
1319
1320# System Headers
1321my %SystemHeaders;
1322my %DefaultCppPaths;
1323my %DefaultGccPaths;
1324my %DefaultIncPaths;
1325my %DefaultCppHeader;
1326my %DefaultGccHeader;
1327my %UserIncPath;
1328
1329# Merging
1330my %CompleteSignature;
1331my %Symbol_Library;
1332my %Library_Symbol = (
1333 "1"=>{},
1334 "2"=>{} );
1335my $Version;
1336my %AddedInt;
1337my %RemovedInt;
1338my %AddedInt_Virt;
1339my %RemovedInt_Virt;
1340my %VirtualReplacement;
1341my %ChangedTypedef;
1342my %CompatRules;
1343my %IncompleteRules;
1344my %UnknownRules;
Andrey Ponomarenko16934472012-03-29 15:37:04 +04001345my %VTableChanged_M;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04001346my %ExtendedFuncs;
1347my %ReturnedClass;
1348my %ParamClass;
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04001349my %SourceAlternative;
1350my %SourceAlternative_B;
1351my %SourceReplacement;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04001352
1353# OS Compliance
1354my %TargetLibs;
1355my %TargetHeaders;
1356
1357# OS Specifics
1358my $OStarget = $OSgroup;
1359my %TargetTools;
1360
1361# Compliance Report
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04001362my %Type_MaxSeverity;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04001363
1364# Recursion locks
1365my @RecurLib;
1366my @RecurSymlink;
1367my @RecurTypes;
1368my @RecurInclude;
1369my @RecurConstant;
1370
1371# System
1372my %SystemPaths;
1373my %DefaultBinPaths;
1374my $GCC_PATH;
1375
1376# Symbols versioning
1377my %SymVer = (
1378 "1"=>{},
1379 "2"=>{} );
1380
1381# Problem descriptions
1382my %CompatProblems;
1383my %ProblemsWithConstants;
1384my %ImplProblems;
1385my %TotalAffected;
1386
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04001387# Reports
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04001388my $ContentID = 1;
1389my $ContentSpanStart = "<span class=\"section\" onclick=\"javascript:showContent(this, 'CONTENT_ID')\">\n";
1390my $ContentSpanStart_Affected = "<span class=\"section_affected\" onclick=\"javascript:showContent(this, 'CONTENT_ID')\">\n";
1391my $ContentSpanStart_Info = "<span class=\"section_info\" onclick=\"javascript:showContent(this, 'CONTENT_ID')\">\n";
1392my $ContentSpanEnd = "</span>\n";
1393my $ContentDivStart = "<div id=\"CONTENT_ID\" style=\"display:none;\">\n";
1394my $ContentDivEnd = "</div>\n";
1395my $Content_Counter = 0;
1396
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04001397# Modes
1398my $JoinReport = 1;
1399my $DoubleReport = 0;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04001400
1401sub get_Modules()
1402{
1403 my $TOOL_DIR = get_dirname($0);
1404 if(not $TOOL_DIR)
1405 { # patch for MS Windows
1406 $TOOL_DIR = ".";
1407 }
1408 my @SEARCH_DIRS = (
1409 # tool's directory
1410 abs_path($TOOL_DIR),
1411 # relative path to modules
1412 abs_path($TOOL_DIR)."/../share/abi-compliance-checker",
1413 # system directory
1414 "ACC_MODULES_INSTALL_PATH"
1415 );
1416 foreach my $DIR (@SEARCH_DIRS)
1417 {
1418 if(not is_abs($DIR))
1419 { # relative path
1420 $DIR = abs_path($TOOL_DIR)."/".$DIR;
1421 }
1422 if(-d $DIR."/modules") {
1423 return $DIR."/modules";
1424 }
1425 }
1426 exitStatus("Module_Error", "can't find modules");
1427}
1428
1429sub loadModule($)
1430{
1431 my $Name = $_[0];
1432 my $Path = $MODULES_DIR."/Internals/$Name.pm";
1433 if(not -f $Path) {
1434 exitStatus("Module_Error", "can't access \'$Path\'");
1435 }
1436 require $Path;
1437}
1438
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04001439sub showPos($)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04001440{
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04001441 my $Number = $_[0];
1442 if(not $Number) {
1443 $Number = 1;
1444 }
1445 else {
1446 $Number = int($Number)+1;
1447 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04001448 if($Number>3) {
1449 return $Number."th";
1450 }
1451 elsif($Number==1) {
1452 return "1st";
1453 }
1454 elsif($Number==2) {
1455 return "2nd";
1456 }
1457 elsif($Number==3) {
1458 return "3rd";
1459 }
1460 else {
1461 return $Number;
1462 }
1463}
1464
1465sub search_Tools($)
1466{
1467 my $Name = $_[0];
1468 return "" if(not $Name);
1469 if(my @Paths = keys(%TargetTools))
1470 {
1471 foreach my $Path (@Paths)
1472 {
1473 if(-f joinPath($Path, $Name)) {
1474 return joinPath($Path, $Name);
1475 }
1476 if($CrossPrefix)
1477 { # user-defined prefix (arm-none-symbianelf, ...)
1478 my $Candidate = joinPath($Path, $CrossPrefix."-".$Name);
1479 if(-f $Candidate) {
1480 return $Candidate;
1481 }
1482 }
1483 }
1484 }
1485 else {
1486 return "";
1487 }
1488}
1489
1490sub synch_Cmd($)
1491{
1492 my $Name = $_[0];
1493 if(not $GCC_PATH)
1494 { # GCC was not found yet
1495 return "";
1496 }
1497 my $Candidate = $GCC_PATH;
1498 if($Candidate=~s/(\W|\A)gcc(|\.\w+)\Z/$1$Name$2/) {
1499 return $Candidate;
1500 }
1501 return "";
1502}
1503
1504sub get_CmdPath($)
1505{
1506 my $Name = $_[0];
1507 return "" if(not $Name);
1508 if(defined $Cache{"get_CmdPath"}{$Name}) {
1509 return $Cache{"get_CmdPath"}{$Name};
1510 }
1511 my %BinUtils = map {$_=>1} (
1512 "c++filt",
1513 "objdump",
1514 "readelf"
1515 );
1516 if($BinUtils{$Name}) {
1517 if(my $Dir = get_dirname($GCC_PATH)) {
1518 $TargetTools{$Dir}=1;
1519 }
1520 }
1521 my $Path = search_Tools($Name);
1522 if(not $Path and $OSgroup eq "windows") {
1523 $Path = search_Tools($Name.".exe");
1524 }
1525 if(not $Path and $BinUtils{$Name})
1526 {
1527 if($CrossPrefix)
1528 { # user-defined prefix
1529 $Path = search_Cmd($CrossPrefix."-".$Name);
1530 }
1531 }
1532 if(not $Path and $BinUtils{$Name})
1533 {
1534 if(my $Candidate = synch_Cmd($Name))
1535 { # synch with GCC
1536 if($Candidate=~/[\/\\]/)
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04001537 { # command path
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04001538 if(-f $Candidate) {
1539 $Path = $Candidate;
1540 }
1541 }
1542 elsif($Candidate = search_Cmd($Candidate))
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04001543 { # command name
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04001544 $Path = $Candidate;
1545 }
1546 }
1547 }
1548 if(not $Path) {
1549 $Path = search_Cmd($Name);
1550 }
1551 if(not $Path and $OSgroup eq "windows")
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04001552 { # search for *.exe file
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04001553 $Path=search_Cmd($Name.".exe");
1554 }
1555 if($Path=~/\s/) {
1556 $Path = "\"".$Path."\"";
1557 }
1558 return ($Cache{"get_CmdPath"}{$Name}=$Path);
1559}
1560
1561sub search_Cmd($)
1562{
1563 my $Name = $_[0];
1564 return "" if(not $Name);
1565 if(defined $Cache{"search_Cmd"}{$Name}) {
1566 return $Cache{"search_Cmd"}{$Name};
1567 }
1568 if(my $DefaultPath = get_CmdPath_Default($Name)) {
1569 return ($Cache{"search_Cmd"}{$Name} = $DefaultPath);
1570 }
1571 foreach my $Path (sort {length($a)<=>length($b)} keys(%{$SystemPaths{"bin"}}))
1572 {
1573 my $CmdPath = joinPath($Path,$Name);
1574 if(-f $CmdPath)
1575 {
1576 if($Name=~/gcc/) {
1577 next if(not check_gcc_version($CmdPath, "3"));
1578 }
1579 return ($Cache{"search_Cmd"}{$Name} = $CmdPath);
1580 }
1581 }
1582 return ($Cache{"search_Cmd"}{$Name} = "");
1583}
1584
1585sub get_CmdPath_Default($)
1586{ # search in PATH
1587 my $Name = $_[0];
1588 return "" if(not $Name);
1589 if(defined $Cache{"get_CmdPath_Default"}{$Name}) {
1590 return $Cache{"get_CmdPath_Default"}{$Name};
1591 }
1592 if($Name=~/find/)
1593 { # special case: search for "find" utility
1594 if(`find . -maxdepth 0 2>$TMP_DIR/null`) {
1595 return ($Cache{"get_CmdPath_Default"}{$Name} = "find");
1596 }
1597 }
1598 elsif($Name=~/gcc/) {
1599 return check_gcc_version($Name, "3");
1600 }
1601 if(check_command($Name)) {
1602 return ($Cache{"get_CmdPath_Default"}{$Name} = $Name);
1603 }
1604 if($OSgroup eq "windows"
1605 and `$Name /? 2>$TMP_DIR/null`) {
1606 return ($Cache{"get_CmdPath_Default"}{$Name} = $Name);
1607 }
1608 if($Name!~/which/)
1609 {
1610 my $WhichCmd = get_CmdPath("which");
1611 if($WhichCmd and `$WhichCmd $Name 2>$TMP_DIR/null`) {
1612 return ($Cache{"get_CmdPath_Default"}{$Name} = $Name);
1613 }
1614 }
1615 foreach my $Path (sort {length($a)<=>length($b)} keys(%DefaultBinPaths))
1616 {
1617 if(-f $Path."/".$Name) {
1618 return ($Cache{"get_CmdPath_Default"}{$Name} = joinPath($Path,$Name));
1619 }
1620 }
1621 return ($Cache{"get_CmdPath_Default"}{$Name} = "");
1622}
1623
1624sub clean_path($)
1625{
1626 my $Path = $_[0];
1627 $Path=~s/[\/\\]+\Z//g;
1628 return $Path;
1629}
1630
1631sub classifyPath($)
1632{
1633 my $Path = $_[0];
1634 if($Path=~/[\*\[]/)
1635 { # wildcard
1636 $Path=~s/\*/.*/g;
1637 $Path=~s/\\/\\\\/g;
1638 return ($Path, "Pattern");
1639 }
1640 elsif($Path=~/[\/\\]/)
1641 { # directory or relative path
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04001642 $Path=~s/[\/\\]+\Z//g;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04001643 return (path_format($Path, $OSgroup), "Path");
1644 }
1645 else {
1646 return ($Path, "Name");
1647 }
1648}
1649
1650sub readDescriptor($$)
1651{
1652 my ($LibVersion, $Content) = @_;
1653 return if(not $LibVersion);
1654 my $DName = $DumpAPI?"descriptor":"descriptor \"d$LibVersion\"";
1655 if(not $Content) {
1656 exitStatus("Error", "$DName is empty");
1657 }
1658 if($Content!~/\</) {
1659 exitStatus("Error", "$DName is not a descriptor (see -d1 option)");
1660 }
1661 $Content=~s/\/\*(.|\n)+?\*\///g;
1662 $Content=~s/<\!--(.|\n)+?-->//g;
1663 $Descriptor{$LibVersion}{"Version"} = parseTag(\$Content, "version");
1664 if($TargetVersion{$LibVersion}) {
1665 $Descriptor{$LibVersion}{"Version"} = $TargetVersion{$LibVersion};
1666 }
1667 if(not $Descriptor{$LibVersion}{"Version"}) {
1668 exitStatus("Error", "version in the $DName is not specified (<version> section)");
1669 }
1670 if($Content=~/{RELPATH}/)
1671 {
1672 if(my $RelDir = $RelativeDirectory{$LibVersion}) {
1673 $Content =~ s/{RELPATH}/$RelDir/g;
1674 }
1675 else
1676 {
1677 my $NeedRelpath = $DumpAPI?"-relpath":"-relpath$LibVersion";
1678 exitStatus("Error", "you have not specified $NeedRelpath option, but the $DName contains {RELPATH} macro");
1679 }
1680 }
1681
1682 if(not $CheckObjectsOnly_Opt)
1683 {
1684 my $DHeaders = parseTag(\$Content, "headers");
1685 if(not $DHeaders) {
1686 exitStatus("Error", "header files in the $DName are not specified (<headers> section)");
1687 }
1688 elsif(lc($DHeaders) ne "none")
1689 { # append the descriptor headers list
1690 if($Descriptor{$LibVersion}{"Headers"})
1691 { # multiple descriptors
1692 $Descriptor{$LibVersion}{"Headers"} .= "\n".$DHeaders;
1693 }
1694 else {
1695 $Descriptor{$LibVersion}{"Headers"} = $DHeaders;
1696 }
1697 foreach my $Path (split(/\s*\n\s*/, $DHeaders))
1698 {
1699 if(not -e $Path) {
1700 exitStatus("Access_Error", "can't access \'$Path\'");
1701 }
1702 }
1703 }
1704 }
1705 if(not $CheckHeadersOnly_Opt)
1706 {
1707 my $DObjects = parseTag(\$Content, "libs");
1708 if(not $DObjects) {
1709 exitStatus("Error", "$SLIB_TYPE libraries in the $DName are not specified (<libs> section)");
1710 }
1711 elsif(lc($DObjects) ne "none")
1712 { # append the descriptor libraries list
1713 if($Descriptor{$LibVersion}{"Libs"})
1714 { # multiple descriptors
1715 $Descriptor{$LibVersion}{"Libs"} .= "\n".$DObjects;
1716 }
1717 else {
1718 $Descriptor{$LibVersion}{"Libs"} .= $DObjects;
1719 }
1720 foreach my $Path (split(/\s*\n\s*/, $DObjects))
1721 {
1722 if(not -e $Path) {
1723 exitStatus("Access_Error", "can't access \'$Path\'");
1724 }
1725 }
1726 }
1727 }
1728 foreach my $Path (split(/\s*\n\s*/, parseTag(\$Content, "search_headers")))
1729 {
1730 $Path = clean_path($Path);
1731 if(not -d $Path) {
1732 exitStatus("Access_Error", "can't access directory \'$Path\'");
1733 }
1734 $Path = path_format($Path, $OSgroup);
1735 $SystemPaths{"include"}{$Path}=1;
1736 }
1737 foreach my $Path (split(/\s*\n\s*/, parseTag(\$Content, "search_libs")))
1738 {
1739 $Path = clean_path($Path);
1740 if(not -d $Path) {
1741 exitStatus("Access_Error", "can't access directory \'$Path\'");
1742 }
1743 $Path = path_format($Path, $OSgroup);
1744 $SystemPaths{"lib"}{$Path}=1;
1745 }
1746 foreach my $Path (split(/\s*\n\s*/, parseTag(\$Content, "tools")))
1747 {
1748 $Path=clean_path($Path);
1749 if(not -d $Path) {
1750 exitStatus("Access_Error", "can't access directory \'$Path\'");
1751 }
1752 $Path = path_format($Path, $OSgroup);
1753 $SystemPaths{"bin"}{$Path}=1;
1754 $TargetTools{$Path}=1;
1755 }
1756 if(my $Prefix = parseTag(\$Content, "cross_prefix")) {
1757 $CrossPrefix = $Prefix;
1758 }
1759 foreach my $Path (split(/\s*\n\s*/, parseTag(\$Content, "include_paths")))
1760 {
1761 $Path=clean_path($Path);
1762 if(not -d $Path) {
1763 exitStatus("Access_Error", "can't access directory \'$Path\'");
1764 }
1765 $Path = path_format($Path, $OSgroup);
1766 $Descriptor{$LibVersion}{"IncludePaths"}{$Path} = 1;
1767 }
1768 foreach my $Path (split(/\s*\n\s*/, parseTag(\$Content, "add_include_paths")))
1769 {
1770 $Path=clean_path($Path);
1771 if(not -d $Path) {
1772 exitStatus("Access_Error", "can't access directory \'$Path\'");
1773 }
1774 $Path = path_format($Path, $OSgroup);
1775 $Descriptor{$LibVersion}{"AddIncludePaths"}{$Path} = 1;
1776 }
1777 foreach my $Path (split(/\s*\n\s*/, parseTag(\$Content, "skip_include_paths")))
1778 {
1779 # skip some auto-generated include paths
1780 $Skip_Include_Paths{$LibVersion}{path_format($Path)}=1;
1781 }
1782 foreach my $Path (split(/\s*\n\s*/, parseTag(\$Content, "skip_including")))
1783 {
1784 # skip direct including of some headers
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04001785 $SkipHeadersList{$LibVersion}{$Path} = 2;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04001786 my ($CPath, $Type) = classifyPath($Path);
1787 $SkipHeaders{$LibVersion}{$Type}{$CPath} = 2;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04001788 }
1789 $Descriptor{$LibVersion}{"GccOptions"} = parseTag(\$Content, "gcc_options");
1790 foreach my $Option (split(/\s*\n\s*/, $Descriptor{$LibVersion}{"GccOptions"})) {
1791 $CompilerOptions{$LibVersion} .= " ".$Option;
1792 }
1793 $Descriptor{$LibVersion}{"SkipHeaders"} = parseTag(\$Content, "skip_headers");
1794 foreach my $Path (split(/\s*\n\s*/, $Descriptor{$LibVersion}{"SkipHeaders"}))
1795 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04001796 $SkipHeadersList{$LibVersion}{$Path} = 1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04001797 my ($CPath, $Type) = classifyPath($Path);
1798 $SkipHeaders{$LibVersion}{$Type}{$CPath} = 1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04001799 }
1800 $Descriptor{$LibVersion}{"SkipLibs"} = parseTag(\$Content, "skip_libs");
1801 foreach my $Path (split(/\s*\n\s*/, $Descriptor{$LibVersion}{"SkipLibs"}))
1802 {
1803 my ($CPath, $Type) = classifyPath($Path);
1804 $SkipLibs{$LibVersion}{$Type}{$CPath} = 1;
1805 }
1806 if(my $DDefines = parseTag(\$Content, "defines"))
1807 {
1808 if($Descriptor{$LibVersion}{"Defines"})
1809 { # multiple descriptors
1810 $Descriptor{$LibVersion}{"Defines"} .= "\n".$DDefines;
1811 }
1812 else {
1813 $Descriptor{$LibVersion}{"Defines"} = $DDefines;
1814 }
1815 }
1816 foreach my $Order (split(/\s*\n\s*/, parseTag(\$Content, "include_order")))
1817 {
1818 if($Order=~/\A(.+):(.+)\Z/) {
1819 $Include_Order{$LibVersion}{$1} = $2;
1820 }
1821 }
1822 foreach my $Type_Name (split(/\s*\n\s*/, parseTag(\$Content, "opaque_types")),
1823 split(/\s*\n\s*/, parseTag(\$Content, "skip_types")))
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04001824 { # opaque_types renamed to skip_types (1.23.4)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04001825 $SkipTypes{$LibVersion}{$Type_Name} = 1;
1826 }
1827 foreach my $Symbol (split(/\s*\n\s*/, parseTag(\$Content, "skip_interfaces")),
1828 split(/\s*\n\s*/, parseTag(\$Content, "skip_symbols")))
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04001829 { # skip_interfaces renamed to skip_symbols (1.22.1)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04001830 $SkipSymbols{$LibVersion}{$Symbol} = 1;
1831 }
1832 foreach my $NameSpace (split(/\s*\n\s*/, parseTag(\$Content, "skip_namespaces"))) {
1833 $SkipNameSpaces{$LibVersion}{$NameSpace} = 1;
1834 }
1835 foreach my $Constant (split(/\s*\n\s*/, parseTag(\$Content, "skip_constants"))) {
1836 $SkipConstants{$LibVersion}{$Constant} = 1;
1837 }
1838 if(my $DIncPreamble = parseTag(\$Content, "include_preamble"))
1839 {
1840 if($Descriptor{$LibVersion}{"IncludePreamble"})
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04001841 { # multiple descriptors
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04001842 $Descriptor{$LibVersion}{"IncludePreamble"} .= "\n".$DIncPreamble;
1843 }
1844 else {
1845 $Descriptor{$LibVersion}{"IncludePreamble"} = $DIncPreamble;
1846 }
1847 }
1848}
1849
1850sub parseTag($$)
1851{
1852 my ($CodeRef, $Tag) = @_;
1853 return "" if(not $CodeRef or not ${$CodeRef} or not $Tag);
1854 if(${$CodeRef}=~s/\<\Q$Tag\E\>((.|\n)+?)\<\/\Q$Tag\E\>//)
1855 {
1856 my $Content = $1;
1857 $Content=~s/(\A\s+|\s+\Z)//g;
1858 return $Content;
1859 }
1860 else {
1861 return "";
1862 }
1863}
1864
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04001865my %NodeType= (
1866 "array_type" => "Array",
1867 "binfo" => "Other",
1868 "boolean_type" => "Intrinsic",
1869 "complex_type" => "Intrinsic",
1870 "const_decl" => "Other",
1871 "enumeral_type" => "Enum",
1872 "field_decl" => "Other",
1873 "function_decl" => "Other",
1874 "function_type" => "FunctionType",
1875 "identifier_node" => "Other",
1876 "integer_cst" => "Other",
1877 "integer_type" => "Intrinsic",
1878 "method_type" => "MethodType",
1879 "namespace_decl" => "Other",
1880 "parm_decl" => "Other",
1881 "pointer_type" => "Pointer",
1882 "real_cst" => "Other",
1883 "real_type" => "Intrinsic",
1884 "record_type" => "Struct",
1885 "reference_type" => "Ref",
1886 "string_cst" => "Other",
1887 "template_decl" => "Other",
1888 "template_type_parm" => "Other",
1889 "tree_list" => "Other",
1890 "tree_vec" => "Other",
1891 "type_decl" => "Other",
1892 "union_type" => "Union",
1893 "var_decl" => "Other",
1894 "void_type" => "Intrinsic",
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04001895 # "nop_expr" => "Other",
1896 # "addr_expr" => "Other",
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04001897 "offset_type" => "Other" );
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04001898
1899sub getInfo($)
1900{
Andrey Ponomarenko85043792012-05-14 16:48:07 +04001901 my $DumpPath = $_[0];
1902 return if(not $DumpPath or not -f $DumpPath);
1903
1904 readTUDump($DumpPath);
1905
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04001906 # processing info
1907 setTemplateParams_All();
1908 getTypeInfo_All();
1909 simplifyNames();
1910 getSymbolInfo_All();
1911 getVarInfo_All();
1912
Andrey Ponomarenko85043792012-05-14 16:48:07 +04001913 # clean memory
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04001914 %LibInfo = ();
1915 %TemplateInstance = ();
1916 %TemplateInstance_Func = ();
1917 %MangledNames = ();
Andrey Ponomarenko85043792012-05-14 16:48:07 +04001918 %TemplateDecl = ();
1919 %StdCxxTypedef = ();
1920 %MissedTypedef = ();
1921 %Typedef_Tr = ();
1922 %Typedef_Eq = ();
1923
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04001924 if($Debug) {
1925 # debugMangling($Version);
1926 }
1927}
1928
Andrey Ponomarenko85043792012-05-14 16:48:07 +04001929sub readTUDump($)
1930{
1931 my $DumpPath = $_[0];
1932
1933 open(TU_DUMP, $DumpPath);
1934 local $/ = undef;
1935 my $Content = <TU_DUMP>;
1936 close(TU_DUMP);
1937
1938 unlink($DumpPath);
1939
1940 $Content=~s/\n[ ]+/ /g;
1941 my @Lines = split("\n", $Content);
1942
1943 # clean memory
1944 undef $Content;
1945
1946 $MAX_ID = $#Lines+1;
1947
1948 foreach (0 .. $#Lines)
1949 {
1950 if($Lines[$_]=~/\A\@(\d+)\s+([a-z_]+)\s+(.+)\Z/oi)
1951 { # get a number and attributes of a node
1952 next if(not $NodeType{$2});
1953 $LibInfo{$Version}{"info_type"}{$1}=$2;
1954 $LibInfo{$Version}{"info"}{$1}=$3;
1955 }
1956
1957 # clean memory
1958 delete($Lines[$_]);
1959 }
1960
1961 # clean memory
1962 undef @Lines;
1963}
1964
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04001965sub simplifyNames()
1966{
1967 foreach my $Base (keys(%{$Typedef_Tr{$Version}}))
1968 {
1969 my @Translations = keys(%{$Typedef_Tr{$Version}{$Base}});
1970 if($#Translations==0 and length($Translations[0])<=length($Base)) {
1971 $Typedef_Eq{$Version}{$Base} = $Translations[0];
1972 }
1973 }
1974 foreach my $TDid (keys(%{$TypeInfo{$Version}}))
1975 {
1976 foreach my $Tid (keys(%{$TypeInfo{$Version}{$TDid}}))
1977 {
1978 my $TypeName = $TypeInfo{$Version}{$TDid}{$Tid}{"Name"};
1979 if(not $TypeName) {
1980 next;
1981 }
1982 next if(index($TypeName,"<")==-1);# template instances only
1983 if($TypeName=~/>(::\w+)+\Z/)
1984 { # skip unused types
1985 next;
1986 };
1987 foreach my $Base (sort {length($b)<=>length($a)}
1988 sort {$b cmp $a} keys(%{$Typedef_Eq{$Version}}))
1989 {
1990 next if(not $Base);
1991 next if(index($TypeName,$Base)==-1);
1992 next if(length($TypeName) - length($Base) <= 3);
1993 my $Typedef = $Typedef_Eq{$Version}{$Base};
1994 $TypeName=~s/(\<|\,)\Q$Base\E(\W|\Z)/$1$Typedef$2/g;
1995 $TypeName=~s/(\<|\,)\Q$Base\E(\w|\Z)/$1$Typedef $2/g;
Andrey Ponomarenko85043792012-05-14 16:48:07 +04001996 if(defined $TypeInfo{$Version}{$TDid}{$Tid}{"TParam"})
1997 {
1998 foreach my $TPos (keys(%{$TypeInfo{$Version}{$TDid}{$Tid}{"TParam"}}))
1999 {
2000 my $TPName = $TypeInfo{$Version}{$TDid}{$Tid}{"TParam"}{$TPos}{"name"};
2001 $TPName=~s/\A\Q$Base\E(\W|\Z)/$1$Typedef$2/g;
2002 $TypeInfo{$Version}{$TDid}{$Tid}{"TParam"}{$TPos}{"name"} = formatName($TPName);
2003 }
2004 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002005 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +04002006 $TypeName = formatName($TypeName);
2007 $TypeInfo{$Version}{$TDid}{$Tid}{"Name"} = $TypeName;
2008 $TName_Tid{$Version}{$TypeName} = $Tid;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002009 }
2010 }
2011}
2012
2013sub setTemplateParams_All()
2014{
2015 foreach (keys(%{$LibInfo{$Version}{"info"}}))
2016 {
2017 if($LibInfo{$Version}{"info_type"}{$_} eq "template_decl") {
2018 setTemplateParams($_);
2019 }
2020 }
2021}
2022
2023sub setTemplateParams($)
2024{
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04002025 if(my $Info = $LibInfo{$Version}{"info"}{$_[0]})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002026 {
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04002027 if($Info=~/(inst|spcs)[ ]*:[ ]*@(\d+) /)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002028 {
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04002029 my $TmplInst_InfoId = $2;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002030 setTemplateInstParams($TmplInst_InfoId);
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04002031 my $TmplInst_Info = $LibInfo{$Version}{"info"}{$TmplInst_InfoId};
2032 while($TmplInst_Info=~/(chan|chain)[ ]*:[ ]*@(\d+) /)
2033 {
2034 $TmplInst_InfoId = $2;
2035 $TmplInst_Info = $LibInfo{$Version}{"info"}{$TmplInst_InfoId};
2036 setTemplateInstParams($TmplInst_InfoId);
2037 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002038 }
2039 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +04002040 if(my $TypeId = getTreeAttr($_[0], "type"))
2041 {
2042 if(my $IType = $LibInfo{$Version}{"info_type"}{$TypeId})
2043 {
2044 if($IType eq "record_type") {
2045 $TemplateDecl{$Version}{$TypeId}=1;
2046 }
2047 }
2048 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002049}
2050
2051sub setTemplateInstParams($)
2052{
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04002053 if(my $Info = $LibInfo{$Version}{"info"}{$_[0]})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002054 {
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04002055 my ($Params_InfoId, $ElemId) = ();
2056 if($Info=~/purp[ ]*:[ ]*@(\d+) /) {
2057 $Params_InfoId = $1;
2058 }
2059 if($Info=~/valu[ ]*:[ ]*@(\d+) /) {
2060 $ElemId = $1;
2061 }
2062 if($Params_InfoId and $ElemId)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002063 {
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04002064 my $Params_Info = $LibInfo{$Version}{"info"}{$Params_InfoId};
2065 while($Params_Info=~s/ (\d+)[ ]*:[ ]*\@(\d+) / /)
2066 {
2067 my ($PPos, $PTypeId) = ($1, $2);
2068 if(my $PType = $LibInfo{$Version}{"info_type"}{$PTypeId})
2069 {
Andrey Ponomarenko85043792012-05-14 16:48:07 +04002070 if($PType eq "template_type_parm")
2071 {
2072 $TemplateDecl{$Version}{$ElemId}=1;
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04002073 return;
2074 }
2075 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +04002076 if($LibInfo{$Version}{"info_type"}{$ElemId} eq "function_decl")
2077 { # functions
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04002078 $TemplateInstance_Func{$Version}{$ElemId}{$PPos} = $PTypeId;
2079 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +04002080 else
2081 { # types
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04002082 $TemplateInstance{$Version}{getTypeDeclId($ElemId)}{$ElemId}{$PPos} = $PTypeId;
2083 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002084 }
2085 }
2086 }
2087}
2088
2089sub getTypeDeclId($)
2090{
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04002091 if($_[0] and my $Info = $LibInfo{$Version}{"info"}{$_[0]})
2092 {
2093 if($Info=~/name[ ]*:[ ]*@(\d+)/) {
2094 return $1;
2095 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002096 }
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04002097 return "";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002098}
2099
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002100sub getTypeInfo_All()
2101{
2102 if(not check_gcc_version($GCC_PATH, "4.5"))
2103 { # support for GCC < 4.5
2104 # missed typedefs: QStyle::State is typedef to QFlags<QStyle::StateFlag>
2105 # but QStyleOption.state is of type QFlags<QStyle::StateFlag> in the TU dump
2106 # FIXME: check GCC versions
2107 addMissedTypes_Pre();
2108 }
2109 foreach (sort {int($a)<=>int($b)} keys(%{$LibInfo{$Version}{"info"}}))
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04002110 { # forward order only
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002111 my $IType = $LibInfo{$Version}{"info_type"}{$_};
2112 if($IType=~/_type\Z/ and $IType ne "function_type"
2113 and $IType ne "method_type") {
2114 getTypeInfo(getTypeDeclId("$_"), "$_");
2115 }
2116 }
2117 $TypeInfo{$Version}{""}{-1}{"Name"} = "...";
2118 $TypeInfo{$Version}{""}{-1}{"Type"} = "Intrinsic";
2119 $TypeInfo{$Version}{""}{-1}{"Tid"} = -1;
2120 if(not check_gcc_version($GCC_PATH, "4.5"))
2121 { # support for GCC < 4.5
2122 addMissedTypes_Post();
2123 }
2124}
2125
2126sub addMissedTypes_Pre()
2127{
2128 foreach my $MissedTDid (sort {int($a)<=>int($b)} keys(%{$LibInfo{$Version}{"info"}}))
2129 { # detecting missed typedefs
2130 if($LibInfo{$Version}{"info_type"}{$MissedTDid} eq "type_decl")
2131 {
2132 my $TypeId = getTreeAttr($MissedTDid, "type");
2133 next if(not $TypeId);
2134 my $TypeType = getTypeType($MissedTDid, $TypeId);
2135 if($TypeType eq "Unknown")
2136 { # template_type_parm
2137 next;
2138 }
2139 my $TypeDeclId = getTypeDeclId($TypeId);
2140 next if($TypeDeclId eq $MissedTDid);#or not $TypeDeclId
2141 my $TypedefName = getNameByInfo($MissedTDid);
2142 next if(not $TypedefName);
2143 next if($TypedefName eq "__float80");
2144 next if(isAnon($TypedefName));
2145 if(not $TypeDeclId
2146 or getNameByInfo($TypeDeclId) ne $TypedefName) {
2147 $MissedTypedef{$Version}{$TypeId}{"$MissedTDid"} = 1;
2148 }
2149 }
2150 }
2151 foreach my $Tid (keys(%{$MissedTypedef{$Version}}))
2152 { # add missed typedefs
2153 my @Missed = keys(%{$MissedTypedef{$Version}{$Tid}});
2154 if(not @Missed or $#Missed>=1) {
2155 delete($MissedTypedef{$Version}{$Tid});
2156 next;
2157 }
2158 my $MissedTDid = $Missed[0];
2159 my $TDid = getTypeDeclId($Tid);
2160 my ($TypedefName, $TypedefNS) = getTrivialName($MissedTDid, $Tid);
2161 my %MissedInfo = ( # typedef info
2162 "Name" => $TypedefName,
2163 "NameSpace" => $TypedefNS,
2164 "BaseType" => {
2165 "TDid" => $TDid,
2166 "Tid" => $Tid
2167 },
2168 "Type" => "Typedef",
Andrey Ponomarenko16934472012-03-29 15:37:04 +04002169 "Tid" => ++$MAX_ID,
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002170 "TDid" => $MissedTDid );
2171 my ($H, $L) = getLocation($MissedTDid);
2172 $MissedInfo{"Header"} = $H;
2173 $MissedInfo{"Line"} = $L;
2174 # $MissedInfo{"Size"} = getSize($Tid)/$BYTE_SIZE;
2175 my $MName = $MissedInfo{"Name"};
2176 next if(not $MName);
2177 if($MName=~/\*|\&|\s/)
2178 { # other types
2179 next;
2180 }
2181 if($MName=~/>(::\w+)+\Z/)
2182 { # QFlags<Qt::DropAction>::enum_type
2183 delete($MissedTypedef{$Version}{$Tid});
2184 next;
2185 }
2186 if(getTypeType($TDid, $Tid)=~/\A(Intrinsic|Union|Struct|Enum|Class)\Z/)
2187 { # double-check for the name of typedef
2188 my ($TName, $TNS) = getTrivialName($TDid, $Tid); # base type info
2189 next if(not $TName);
2190 if(length($MName)>=length($TName))
2191 { # too long typedef
2192 delete($MissedTypedef{$Version}{$Tid});
2193 next;
2194 }
2195 if($TName=~/\A\Q$MName\E</) {
2196 next;
2197 }
2198 if($MName=~/\A\Q$TName\E/)
2199 { # QDateTimeEdit::Section and QDateTimeEdit::Sections::enum_type
2200 delete($MissedTypedef{$Version}{$Tid});
2201 next;
2202 }
2203 if(get_depth($MName)==0 and get_depth($TName)!=0)
2204 { # std::_Vector_base and std::vector::_Base
2205 delete($MissedTypedef{$Version}{$Tid});
2206 next;
2207 }
2208 }
2209 %{$TypeInfo{$Version}{$MissedTDid}{$MissedInfo{"Tid"}}} = %MissedInfo;
2210 $Tid_TDid{$Version}{$MissedInfo{"Tid"}} = $MissedTDid;
2211 delete($TypeInfo{$Version}{$MissedTDid}{$Tid});
2212 # register typedef
2213 $MissedTypedef{$Version}{$Tid}{"TDid"} = $MissedTDid;
2214 $MissedTypedef{$Version}{$Tid}{"Tid"} = $MissedInfo{"Tid"};
2215 }
2216}
2217
2218sub addMissedTypes_Post()
2219{
2220 foreach my $BaseId (keys(%{$MissedTypedef{$Version}}))
2221 {
2222 my $Tid = $MissedTypedef{$Version}{$BaseId}{"Tid"};
2223 my $TDid = $MissedTypedef{$Version}{$BaseId}{"TDid"};
2224 $TypeInfo{$Version}{$TDid}{$Tid}{"Size"} = get_TypeAttr($BaseId, $Version, "Size");
2225 }
2226}
2227
2228sub getTypeInfo($$)
2229{
2230 my ($TDId, $TId) = @_;
2231 %{$TypeInfo{$Version}{$TDId}{$TId}} = getTypeAttr($TDId, $TId);
2232 my $TName = $TypeInfo{$Version}{$TDId}{$TId}{"Name"};
2233 if(not $TName) {
2234 delete($TypeInfo{$Version}{$TDId}{$TId});
2235 return;
2236 }
2237 if($TDId) {
2238 $Tid_TDid{$Version}{$TId} = $TDId;
2239 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002240}
2241
2242sub getArraySize($$)
2243{
2244 my ($TypeId, $BaseName) = @_;
2245 my $SizeBytes = getSize($TypeId)/$BYTE_SIZE;
2246 while($BaseName=~s/\s*\[(\d+)\]//) {
2247 $SizeBytes/=$1;
2248 }
2249 my $BasicId = $TName_Tid{$Version}{$BaseName};
2250 if(my $BasicSize = $TypeInfo{$Version}{getTypeDeclId($BasicId)}{$BasicId}{"Size"}) {
2251 $SizeBytes/=$BasicSize;
2252 }
2253 return $SizeBytes;
2254}
2255
2256sub getTParams_Func($)
2257{
Andrey Ponomarenko16934472012-03-29 15:37:04 +04002258 my $InfoId = $_[0];
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002259 my @TmplParams = ();
Andrey Ponomarenko16934472012-03-29 15:37:04 +04002260 foreach my $Pos (sort {int($a) <=> int($b)} keys(%{$TemplateInstance_Func{$Version}{$InfoId}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002261 {
Andrey Ponomarenko16934472012-03-29 15:37:04 +04002262 my $Param = get_TemplateParam($Pos, $TemplateInstance_Func{$Version}{$InfoId}{$Pos});
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002263 if($Param eq "") {
2264 return ();
2265 }
2266 elsif($Param ne "\@skip\@") {
2267 push(@TmplParams, $Param);
2268 }
2269 }
2270 return @TmplParams;
2271}
2272
2273sub getTParams($$)
2274{
2275 my ($TypeDeclId, $TypeId) = @_;
2276 my @Template_Params = ();
2277 foreach my $Pos (sort {int($a)<=>int($b)} keys(%{$TemplateInstance{$Version}{$TypeDeclId}{$TypeId}}))
2278 {
2279 my $Param_TypeId = $TemplateInstance{$Version}{$TypeDeclId}{$TypeId}{$Pos};
2280 my $Param = get_TemplateParam($Pos, $Param_TypeId);
2281 if($Param eq "") {
2282 return ();
2283 }
2284 elsif($Param ne "\@skip\@") {
2285 @Template_Params = (@Template_Params, $Param);
2286 }
2287 }
2288 return @Template_Params;
2289}
2290
2291sub getTypeAttr($$)
2292{
2293 my ($TypeDeclId, $TypeId) = @_;
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04002294 my %TypeAttr = ();
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002295 if(defined $TypeInfo{$Version}{$TypeDeclId}{$TypeId}
2296 and $TypeInfo{$Version}{$TypeDeclId}{$TypeId}{"Name"}) {
2297 return %{$TypeInfo{$Version}{$TypeDeclId}{$TypeId}};
2298 }
2299 $TypeAttr{"Tid"} = $TypeId;
2300 $TypeAttr{"TDid"} = $TypeDeclId;
2301 $TypeAttr{"Type"} = getTypeType($TypeDeclId, $TypeId);
2302 if($TypeAttr{"Type"} eq "Unknown") {
2303 return ();
2304 }
2305 elsif($TypeAttr{"Type"}=~/(Func|Method|Field)Ptr/)
2306 {
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04002307 %TypeAttr = getMemPtrAttr(pointTo($TypeId), $TypeDeclId, $TypeId, $TypeAttr{"Type"});
2308 if(my $TName = $TypeAttr{"Name"})
2309 {
2310 %{$TypeInfo{$Version}{$TypeDeclId}{$TypeId}} = %TypeAttr;
2311 $TName_Tid{$Version}{$TName} = $TypeId;
2312 return %TypeAttr;
2313 }
2314 else {
2315 return ();
2316 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002317 }
2318 elsif($TypeAttr{"Type"} eq "Array")
2319 {
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04002320 my ($BTid, $BTDid, $BTSpec) = selectBaseType($TypeDeclId, $TypeId);
2321 if(not $BTid and not $BTDid) {
2322 return ();
2323 }
2324 $TypeAttr{"BaseType"}{"Tid"} = $BTid;
2325 $TypeAttr{"BaseType"}{"TDid"} = $BTDid;
2326 if(my %BTAttr = getTypeAttr($BTDid, $BTid))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002327 {
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04002328 if(my $NElems = getArraySize($TypeId, $BTAttr{"Name"}))
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04002329 {
2330 $TypeAttr{"Size"} = getSize($TypeId)/$BYTE_SIZE;
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04002331 if($BTAttr{"Name"}=~/\A([^\[\]]+)(\[(\d+|)\].*)\Z/) {
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04002332 $TypeAttr{"Name"} = $1."[$NElems]".$2;
2333 }
2334 else {
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04002335 $TypeAttr{"Name"} = $BTAttr{"Name"}."[$NElems]";
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04002336 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002337 }
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04002338 else
2339 {
2340 $TypeAttr{"Size"} = $WORD_SIZE{$Version}; # pointer
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04002341 if($BTAttr{"Name"}=~/\A([^\[\]]+)(\[(\d+|)\].*)\Z/) {
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04002342 $TypeAttr{"Name"} = $1."[]".$2;
2343 }
2344 else {
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04002345 $TypeAttr{"Name"} = $BTAttr{"Name"}."[]";
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04002346 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002347 }
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04002348 $TypeAttr{"Name"} = formatName($TypeAttr{"Name"});
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04002349 if($BTAttr{"Header"}) {
2350 $TypeAttr{"Header"} = $BTAttr{"Header"};
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04002351 }
2352 %{$TypeInfo{$Version}{$TypeDeclId}{$TypeId}} = %TypeAttr;
2353 $TName_Tid{$Version}{$TypeAttr{"Name"}} = $TypeId;
2354 return %TypeAttr;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002355 }
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04002356 return ();
2357 }
2358 elsif($TypeAttr{"Type"}=~/\A(Intrinsic|Union|Struct|Enum|Class)\Z/)
2359 {
2360 %TypeAttr = getTrivialTypeAttr($TypeDeclId, $TypeId);
2361 if($TypeAttr{"Name"})
2362 {
2363 %{$TypeInfo{$Version}{$TypeDeclId}{$TypeId}} = %TypeAttr;
2364 if($TypeAttr{"Name"} ne "int" or $TypeAttr{"TDid"})
2365 { # NOTE: register only one int: with built-in decl
2366 if(not $TName_Tid{$Version}{$TypeAttr{"Name"}}) {
2367 $TName_Tid{$Version}{$TypeAttr{"Name"}} = $TypeId;
2368 }
2369 }
2370 return %TypeAttr;
2371 }
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04002372 else {
2373 return ();
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002374 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002375 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002376 else
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04002377 { # derived types
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04002378 my ($BTid, $BTDid, $BTSpec) = selectBaseType($TypeDeclId, $TypeId);
2379 if(not $BTid and not $BTDid) {
2380 return ();
2381 }
2382 $TypeAttr{"BaseType"}{"Tid"} = $BTid;
2383 $TypeAttr{"BaseType"}{"TDid"} = $BTDid;
2384 if(my $MissedTDid = $MissedTypedef{$Version}{$BTid}{"TDid"})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002385 {
2386 if($MissedTDid ne $TypeDeclId)
2387 {
2388 $TypeAttr{"BaseType"}{"TDid"} = $MissedTDid;
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04002389 $TypeAttr{"BaseType"}{"Tid"} = $MissedTypedef{$Version}{$BTid}{"Tid"};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002390 }
2391 }
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04002392 my %BTAttr = getTypeAttr($TypeAttr{"BaseType"}{"TDid"}, $TypeAttr{"BaseType"}{"Tid"});
2393 if(not $BTAttr{"Name"})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002394 { # const "template_type_parm"
2395 return ();
2396 }
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04002397 if($BTAttr{"Type"} eq "Typedef")
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002398 { # relinking typedefs
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04002399 my %BaseBase = get_Type($BTAttr{"BaseType"}{"TDid"}, $BTAttr{"BaseType"}{"Tid"}, $Version);
2400 if($BTAttr{"Name"} eq $BaseBase{"Name"})
2401 {
2402 $TypeAttr{"BaseType"}{"Tid"} = $BaseBase{"Tid"};
2403 $TypeAttr{"BaseType"}{"TDid"} = $BaseBase{"TDid"};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002404 }
2405 }
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04002406 if($BTSpec)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002407 {
2408 if($TypeAttr{"Type"} eq "Pointer"
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04002409 and $BTAttr{"Name"}=~/\([\*]+\)/)
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04002410 {
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04002411 $TypeAttr{"Name"} = $BTAttr{"Name"};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002412 $TypeAttr{"Name"}=~s/\(([*]+)\)/($1*)/g;
2413 }
2414 else {
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04002415 $TypeAttr{"Name"} = $BTAttr{"Name"}." ".$BTSpec;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002416 }
2417 }
2418 else {
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04002419 $TypeAttr{"Name"} = $BTAttr{"Name"};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002420 }
2421 if($TypeAttr{"Type"} eq "Typedef")
2422 {
2423 $TypeAttr{"Name"} = getNameByInfo($TypeDeclId);
Andrey Ponomarenko85043792012-05-14 16:48:07 +04002424 if(isAnon($TypeAttr{"Name"}))
2425 { # anon typedef to anon type: ._N
2426 return ();
2427 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002428 if(my $NS = getNameSpace($TypeDeclId))
2429 {
2430 my $TypeName = $TypeAttr{"Name"};
2431 if($NS=~/\A(struct |union |class |)((.+)::|)\Q$TypeName\E\Z/)
2432 { # "some_type" is the typedef to "struct some_type" in C++
2433 if($3) {
2434 $TypeAttr{"Name"} = $3."::".$TypeName;
2435 }
2436 }
2437 else
2438 {
2439 $TypeAttr{"NameSpace"} = $NS;
2440 $TypeAttr{"Name"} = $TypeAttr{"NameSpace"}."::".$TypeAttr{"Name"};
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04002441
2442 if($TypeAttr{"NameSpace"}=~/\Astd(::|\Z)/
2443 and $TypeAttr{"Name"}!~/>(::\w+)+\Z/)
2444 {
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04002445 if($BTAttr{"NameSpace"}
2446 and $BTAttr{"NameSpace"}=~/\Astd(::|\Z)/ and $BTAttr{"Name"}=~/</)
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04002447 { # types like "std::fpos<__mbstate_t>" are
2448 # not covered by typedefs in the TU dump
2449 # so trying to add such typedefs manually
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04002450 $StdCxxTypedef{$Version}{$BTAttr{"Name"}}{$TypeAttr{"Name"}} = 1;
2451 if(length($TypeAttr{"Name"})<=length($BTAttr{"Name"}))
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04002452 {
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04002453 if(($BTAttr{"Name"}!~/\A(std|boost)::/ or $TypeAttr{"Name"}!~/\A[a-z]+\Z/))
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04002454 { # skip "other" in "std" and "type" in "boost"
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04002455 $Typedef_Eq{$Version}{$BTAttr{"Name"}} = $TypeAttr{"Name"};
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04002456 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002457 }
2458 }
2459 }
2460 }
2461 }
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04002462 if($TypeAttr{"Name"} ne $BTAttr{"Name"}
2463 and $TypeAttr{"Name"}!~/>(::\w+)+\Z/ and $BTAttr{"Name"}!~/>(::\w+)+\Z/)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002464 {
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04002465 if(not defined $Typedef_BaseName{$Version}{$TypeAttr{"Name"}})
2466 { # typedef int*const TYPEDEF; // first
2467 # int foo(TYPEDEF p); // const is optimized out
2468 $Typedef_BaseName{$Version}{$TypeAttr{"Name"}} = $BTAttr{"Name"};
2469 if($BTAttr{"Name"}=~/</)
2470 {
2471 if(($BTAttr{"Name"}!~/\A(std|boost)::/ or $TypeAttr{"Name"}!~/\A[a-z]+\Z/)) {
2472 $Typedef_Tr{$Version}{$BTAttr{"Name"}}{$TypeAttr{"Name"}} = 1;
2473 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002474 }
2475 }
2476 }
2477 ($TypeAttr{"Header"}, $TypeAttr{"Line"}) = getLocation($TypeDeclId);
2478 }
2479 if(not $TypeAttr{"Size"})
2480 {
2481 if($TypeAttr{"Type"} eq "Pointer") {
2482 $TypeAttr{"Size"} = $WORD_SIZE{$Version};
2483 }
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04002484 elsif($BTAttr{"Size"}) {
2485 $TypeAttr{"Size"} = $BTAttr{"Size"};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002486 }
2487 }
2488 $TypeAttr{"Name"} = formatName($TypeAttr{"Name"});
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04002489 if(not $TypeAttr{"Header"} and $BTAttr{"Header"}) {
2490 $TypeAttr{"Header"} = $BTAttr{"Header"};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002491 }
2492 %{$TypeInfo{$Version}{$TypeDeclId}{$TypeId}} = %TypeAttr;
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04002493 if($TypeAttr{"Name"} ne $BTAttr{"Name"})
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04002494 { # typedef to "class Class"
2495 # should not be registered in TName_Tid
2496 if(not $TName_Tid{$Version}{$TypeAttr{"Name"}}) {
2497 $TName_Tid{$Version}{$TypeAttr{"Name"}} = $TypeId;
2498 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002499 }
2500 return %TypeAttr;
2501 }
2502}
2503
2504sub get_TemplateParam($$)
2505{
2506 my ($Pos, $Type_Id) = @_;
2507 return "" if(not $Type_Id);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002508 if(getNodeType($Type_Id) eq "integer_cst")
2509 { # int (1), unsigned (2u), char ('c' as 99), ...
2510 my $CstTid = getTreeAttr($Type_Id, "type");
2511 my %CstType = getTypeAttr(getTypeDeclId($CstTid), $CstTid);
2512 my $Num = getNodeIntCst($Type_Id);
2513 if(my $CstSuffix = $ConstantSuffix{$CstType{"Name"}}) {
2514 return $Num.$CstSuffix;
2515 }
2516 else {
2517 return "(".$CstType{"Name"}.")".$Num;
2518 }
2519 }
2520 elsif(getNodeType($Type_Id) eq "string_cst") {
2521 return getNodeStrCst($Type_Id);
2522 }
2523 elsif(getNodeType($Type_Id) eq "tree_vec") {
2524 return "\@skip\@";
2525 }
2526 else
2527 {
2528 my $Type_DId = getTypeDeclId($Type_Id);
2529 my %ParamAttr = getTypeAttr($Type_DId, $Type_Id);
2530 if(not $ParamAttr{"Name"}) {
2531 return "";
2532 }
2533 my $PName = $ParamAttr{"Name"};
2534 if($ParamAttr{"Name"}=~/\>/) {
2535 if(my $Cover = cover_stdcxx_typedef($ParamAttr{"Name"})) {
2536 $PName = $Cover;
2537 }
2538 }
2539 if($Pos>=1 and
2540 $PName=~/\Astd::(allocator|less|((char|regex)_traits)|((i|o)streambuf_iterator))\</)
2541 { # template<typename _Tp, typename _Alloc = std::allocator<_Tp> >
2542 # template<typename _Key, typename _Compare = std::less<_Key>
2543 # template<typename _CharT, typename _Traits = std::char_traits<_CharT> >
2544 # template<typename _Ch_type, typename _Rx_traits = regex_traits<_Ch_type> >
2545 # template<typename _CharT, typename _InIter = istreambuf_iterator<_CharT> >
2546 # template<typename _CharT, typename _OutIter = ostreambuf_iterator<_CharT> >
2547 return "\@skip\@";
2548 }
2549 return $PName;
2550 }
2551}
2552
2553sub cover_stdcxx_typedef($)
2554{
2555 my $TypeName = $_[0];
2556 if(my @Covers = sort {length($a)<=>length($b)}
2557 sort keys(%{$StdCxxTypedef{$Version}{$TypeName}}))
2558 { # take the shortest typedef
2559 # FIXME: there may be more than
2560 # one typedefs to the same type
2561 return $Covers[0];
2562 }
2563 my $TypeName_Covered = $TypeName;
2564 while($TypeName=~s/(>)[ ]*(const|volatile|restrict| |\*|\&)\Z/$1/g){};
2565 if(my @Covers = sort {length($a)<=>length($b)} sort keys(%{$StdCxxTypedef{$Version}{$TypeName}}))
2566 {
2567 my $Cover = $Covers[0];
2568 $TypeName_Covered=~s/(\W|\A)\Q$TypeName\E(\W|\Z)/$1$Cover$2/g;
2569 $TypeName_Covered=~s/(\W|\A)\Q$TypeName\E(\w|\Z)/$1$Cover $2/g;
2570 }
2571 return formatName($TypeName_Covered);
2572}
2573
2574sub getNodeType($)
2575{
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04002576 if(my $NType = $LibInfo{$Version}{"info_type"}{$_[0]}) {
2577 return $NType;
2578 }
2579 return "";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002580}
2581
2582sub getNodeIntCst($)
2583{
2584 my $CstId = $_[0];
2585 my $CstTypeId = getTreeAttr($CstId, "type");
2586 if($EnumMembName_Id{$Version}{$CstId}) {
2587 return $EnumMembName_Id{$Version}{$CstId};
2588 }
2589 elsif((my $Value = getTreeValue($CstId)) ne "")
2590 {
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04002591 if($Value eq "0")
2592 {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002593 if(getNodeType($CstTypeId) eq "boolean_type") {
2594 return "false";
2595 }
2596 else {
2597 return "0";
2598 }
2599 }
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04002600 elsif($Value eq "1")
2601 {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002602 if(getNodeType($CstTypeId) eq "boolean_type") {
2603 return "true";
2604 }
2605 else {
2606 return "1";
2607 }
2608 }
2609 else {
2610 return $Value;
2611 }
2612 }
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04002613 return "";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002614}
2615
2616sub getNodeStrCst($)
2617{
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04002618 if($_[0] and my $Info = $LibInfo{$Version}{"info"}{$_[0]})
2619 {
2620 if($Info=~/strg[ ]*: (.+) lngt:[ ]*(\d+)/)
2621 { # string length is N-1 because of the null terminator
2622 return substr($1, 0, $2-1);
2623 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002624 }
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04002625 return "";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002626}
2627
2628sub getMemPtrAttr($$$$)
2629{ # function, method and field pointers
2630 my ($PtrId, $TypeDeclId, $TypeId, $Type) = @_;
2631 my $MemInfo = $LibInfo{$Version}{"info"}{$PtrId};
2632 if($Type eq "FieldPtr") {
2633 $MemInfo = $LibInfo{$Version}{"info"}{$TypeId};
2634 }
2635 my $MemInfo_Type = $LibInfo{$Version}{"info_type"}{$PtrId};
2636 my $MemPtrName = "";
2637 my %TypeAttr = ("Size"=>$WORD_SIZE{$Version}, "Type"=>$Type, "TDid"=>$TypeDeclId, "Tid"=>$TypeId);
2638 if($Type eq "MethodPtr")
2639 { # size of "method pointer" may be greater than WORD size
2640 $TypeAttr{"Size"} = getSize($TypeId)/$BYTE_SIZE;
2641 }
2642 # Return
2643 if($Type eq "FieldPtr")
2644 {
2645 my %ReturnAttr = getTypeAttr(getTypeDeclId($PtrId), $PtrId);
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04002646 if($ReturnAttr{"Name"}) {
2647 $MemPtrName .= $ReturnAttr{"Name"};
2648 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002649 $TypeAttr{"Return"} = $PtrId;
2650 }
2651 else
2652 {
2653 if($MemInfo=~/retn[ ]*:[ ]*\@(\d+) /)
2654 {
2655 my $ReturnTypeId = $1;
2656 my %ReturnAttr = getTypeAttr(getTypeDeclId($ReturnTypeId), $ReturnTypeId);
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04002657 if($ReturnAttr{"Name"}) {
2658 $MemPtrName .= $ReturnAttr{"Name"};
2659 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002660 $TypeAttr{"Return"} = $ReturnTypeId;
2661 }
2662 }
2663 # Class
2664 if($MemInfo=~/(clas|cls)[ ]*:[ ]*@(\d+) /)
2665 {
2666 $TypeAttr{"Class"} = $2;
2667 my %Class = getTypeAttr(getTypeDeclId($TypeAttr{"Class"}), $TypeAttr{"Class"});
2668 if($Class{"Name"}) {
2669 $MemPtrName .= " (".$Class{"Name"}."\:\:*)";
2670 }
2671 else {
2672 $MemPtrName .= " (*)";
2673 }
2674 }
2675 else {
2676 $MemPtrName .= " (*)";
2677 }
2678 # Parameters
2679 if($Type eq "FuncPtr"
2680 or $Type eq "MethodPtr")
2681 {
2682 my @ParamTypeName = ();
2683 if($MemInfo=~/prms[ ]*:[ ]*@(\d+) /)
2684 {
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04002685 my $PTypeInfoId = $1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002686 my $Position = 0;
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04002687 while($PTypeInfoId)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002688 {
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04002689 my $PTypeInfo = $LibInfo{$Version}{"info"}{$PTypeInfoId};
2690 if($PTypeInfo=~/valu[ ]*:[ ]*@(\d+) /)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002691 {
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04002692 my $ParamTypeId = $1;
2693 my %ParamAttr = getTypeAttr(getTypeDeclId($ParamTypeId), $ParamTypeId);
2694 if(not $ParamAttr{"Name"})
2695 { # templates (template_type_parm), etc.
2696 return ();
2697 }
2698 if($ParamAttr{"Name"} eq "void") {
2699 last;
2700 }
2701 if($Position!=0 or $Type ne "MethodPtr")
2702 {
2703 $TypeAttr{"Param"}{$Position}{"type"} = $ParamTypeId;
2704 push(@ParamTypeName, $ParamAttr{"Name"});
2705 }
2706 if($PTypeInfo=~/(chan|chain)[ ]*:[ ]*@(\d+) /)
2707 {
2708 $PTypeInfoId = $2;
2709 $Position+=1;
2710 }
2711 else {
2712 last;
2713 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002714 }
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04002715 else {
2716 last;
2717 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002718 }
2719 }
2720 $MemPtrName .= " (".join(", ", @ParamTypeName).")";
2721 }
2722 $TypeAttr{"Name"} = formatName($MemPtrName);
2723 return %TypeAttr;
2724}
2725
2726sub getTreeTypeName($)
2727{
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04002728 my $TypeId = $_[0];
2729 if(my $Info = $LibInfo{$Version}{"info"}{$TypeId})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002730 {
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04002731 if($LibInfo{$Version}{"info_type"}{$_[0]} eq "integer_type")
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002732 {
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04002733 if(my $Name = getNameByInfo($TypeId))
2734 { # bit_size_type
2735 return $Name;
2736 }
2737 elsif($Info=~/unsigned/) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002738 return "unsigned int";
2739 }
2740 else {
2741 return "int";
2742 }
2743 }
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04002744 elsif($Info=~/name[ ]*:[ ]*@(\d+) /)
2745 {
2746 return getNameByInfo($1);
2747 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002748 }
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04002749 return "";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002750}
2751
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04002752sub isFuncPtr($)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002753{
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04002754 my $Ptd = pointTo($_[0]);
2755 return 0 if(not $Ptd);
2756 if(my $Info = $LibInfo{$Version}{"info"}{$_[0]})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002757 {
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04002758 if($Info=~/unql[ ]*:/ and $Info!~/qual[ ]*:/) {
2759 return 0;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002760 }
2761 }
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04002762 if(my $InfoT1 = $LibInfo{$Version}{"info_type"}{$_[0]}
2763 and my $InfoT2 = $LibInfo{$Version}{"info_type"}{$Ptd})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002764 {
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04002765 if($InfoT1 eq "pointer_type"
2766 and $InfoT2 eq "function_type") {
2767 return 1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002768 }
2769 }
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04002770 return 0;
2771}
2772
2773sub isMethodPtr($)
2774{
2775 my $Ptd = pointTo($_[0]);
2776 return 0 if(not $Ptd);
2777 if(my $Info = $LibInfo{$Version}{"info"}{$_[0]})
2778 {
2779 if($LibInfo{$Version}{"info_type"}{$_[0]} eq "record_type"
2780 and $LibInfo{$Version}{"info_type"}{$Ptd} eq "method_type"
2781 and $Info=~/ ptrmem /) {
2782 return 1;
2783 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002784 }
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04002785 return 0;
2786}
2787
2788sub isFieldPtr($)
2789{
2790 if($_[0] and my $Info = $LibInfo{$Version}{"info"}{$_[0]})
2791 {
2792 if($LibInfo{$Version}{"info_type"}{$_[0]} eq "offset_type"
2793 and $Info=~/ ptrmem /) {
2794 return 1;
2795 }
2796 }
2797 return 0;
2798}
2799
2800sub pointTo($)
2801{
2802 if($_[0] and my $Info = $LibInfo{$Version}{"info"}{$_[0]})
2803 {
2804 if($Info=~/ptd[ ]*:[ ]*@(\d+)/) {
2805 return $1;
2806 }
2807 }
2808 return "";
2809}
2810
2811sub getTypeTypeByTypeId($)
2812{
2813 my $TypeId = $_[0];
2814 if(my $TType = $LibInfo{$Version}{"info_type"}{$TypeId})
2815 {
2816 my $NType = $NodeType{$TType};
2817 if($NType eq "Intrinsic") {
2818 return $NType;
2819 }
2820 elsif(isFuncPtr($TypeId)) {
2821 return "FuncPtr";
2822 }
2823 elsif(isMethodPtr($TypeId)) {
2824 return "MethodPtr";
2825 }
2826 elsif(isFieldPtr($TypeId)) {
2827 return "FieldPtr";
2828 }
2829 elsif($NType ne "Other") {
2830 return $NType;
2831 }
2832 }
2833 return "Unknown";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002834}
2835
2836sub getQual($)
2837{
2838 my $TypeId = $_[0];
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002839 my %UnQual = (
2840 "r"=>"restrict",
2841 "v"=>"volatile",
2842 "c"=>"const",
2843 "cv"=>"const volatile"
2844 );
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04002845 if(my $Info = $LibInfo{$Version}{"info"}{$TypeId})
2846 {
2847 my ($Qual, $To) = ();
2848 if($Info=~/qual[ ]*:[ ]*(r|c|v|cv) /) {
2849 $Qual = $UnQual{$1};
2850 }
2851 if($Info=~/unql[ ]*:[ ]*\@(\d+)/) {
2852 $To = $1;
2853 }
2854 if($Qual and $To) {
2855 return ($Qual, $To);
2856 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002857 }
2858 return ();
2859}
2860
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04002861sub getQualType($)
2862{
2863 if($_[0] eq "const volatile") {
2864 return "ConstVolatile";
2865 }
2866 return ucfirst($_[0]);
2867}
2868
2869sub getTypeType($$)
2870{
2871 my ($TypeDeclId, $TypeId) = @_;
2872 if(defined $MissedTypedef{$Version}{$TypeId}{"TDid"}
2873 and $MissedTypedef{$Version}{$TypeId}{"TDid"} eq $TypeDeclId)
2874 { # support for old GCC versions
2875 return "Typedef";
2876 }
2877 my $Info = $LibInfo{$Version}{"info"}{$TypeId};
2878 my ($Qual, $To) = getQual($TypeId);
2879 if(($Qual or $To) and $Info=~/name[ ]*:[ ]*\@(\d+) /
2880 and (getTypeId($1) ne $TypeId))
2881 { # qualified types (special)
2882 return (getTypeId($1), $1, getQualType($Qual));
2883 }
2884 if($Info and $Info=~/unql[ ]*:/
2885 and $TypeDeclId and getNameByInfo($TypeDeclId)) {
2886 return "Typedef";
2887 }
2888 elsif($Qual)
2889 { # qualified types
2890 return getQualType($Qual);
2891 }
2892 my $TypeType = getTypeTypeByTypeId($TypeId);
2893 if($TypeType eq "Struct")
2894 {
2895 if($TypeDeclId
2896 and $LibInfo{$Version}{"info_type"}{$TypeDeclId} eq "template_decl") {
2897 return "Template";
2898 }
2899 }
2900 return $TypeType;
2901}
2902
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002903sub selectBaseType($$)
2904{
2905 my ($TypeDeclId, $TypeId) = @_;
2906 if($MissedTypedef{$Version}{$TypeId}{"TDid"}
2907 and $MissedTypedef{$Version}{$TypeId}{"TDid"} eq $TypeDeclId) {
2908 return ($TypeId, getTypeDeclId($TypeId), "");
2909 }
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04002910 my $Info = $LibInfo{$Version}{"info"}{$TypeId};
2911 my $InfoType = $LibInfo{$Version}{"info_type"}{$TypeId};
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04002912 my ($Qual, $To) = getQual($TypeId);
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04002913 if(($Qual or $To) and $Info=~/name[ ]*:[ ]*\@(\d+) /
2914 and (getTypeId($1) ne $TypeId))
2915 { # qualified types (special)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002916 return (getTypeId($1), $1, $Qual);
2917 }
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04002918 elsif($Info=~/unql[ ]*:[ ]*\@(\d+) /
2919 and $TypeDeclId and getNameByInfo($TypeDeclId))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002920 { # typedefs
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04002921 my $ID = $1;
2922 if($Info=~/qual[ ]*:/) {
2923 return ($TypeId, "", "");
2924 }
2925 else {
2926 return ($ID, getTypeDeclId($ID), "");
2927 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002928 }
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04002929 elsif($Qual or $To)
2930 { # qualified types
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002931 return ($To, getTypeDeclId($To), $Qual);
2932 }
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04002933 elsif($InfoType eq "reference_type")
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002934 {
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04002935 if($Info=~/refd[ ]*:[ ]*@(\d+) /) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002936 return ($1, getTypeDeclId($1), "&");
2937 }
2938 else {
2939 return (0, 0, "");
2940 }
2941 }
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04002942 elsif($InfoType eq "array_type")
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002943 {
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04002944 if($Info=~/elts[ ]*:[ ]*@(\d+) /) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002945 return ($1, getTypeDeclId($1), "");
2946 }
2947 else {
2948 return (0, 0, "");
2949 }
2950 }
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04002951 elsif($InfoType eq "pointer_type")
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002952 {
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04002953 if($Info=~/ptd[ ]*:[ ]*@(\d+) /) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002954 return ($1, getTypeDeclId($1), "*");
2955 }
2956 else {
2957 return (0, 0, "");
2958 }
2959 }
2960 else {
2961 return (0, 0, "");
2962 }
2963}
2964
2965sub getSymbolInfo_All()
2966{
2967 foreach (sort {int($b)<=>int($a)} keys(%{$LibInfo{$Version}{"info"}}))
2968 { # reverse order
2969 if($LibInfo{$Version}{"info_type"}{$_} eq "function_decl") {
2970 getSymbolInfo("$_");
2971 }
2972 }
2973}
2974
2975sub getVarInfo_All()
2976{
2977 foreach (sort {int($b)<=>int($a)} keys(%{$LibInfo{$Version}{"info"}}))
2978 { # reverse order
2979 if($LibInfo{$Version}{"info_type"}{$_} eq "var_decl") {
2980 getVarInfo("$_");
2981 }
2982 }
2983}
2984
2985sub isBuiltIn($) {
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04002986 return ($_[0] and $_[0]=~/\<built\-in\>|\<internal\>|\A\./);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002987}
2988
2989sub getVarInfo($)
2990{
2991 my $InfoId = $_[0];
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04002992 if(my $NSid = getNameSpaceId($InfoId))
2993 {
2994 my $NSInfoType = $LibInfo{$Version}{"info_type"}{$NSid};
2995 if($NSInfoType and $NSInfoType eq "function_decl") {
2996 return;
2997 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002998 }
2999 ($SymbolInfo{$Version}{$InfoId}{"Header"}, $SymbolInfo{$Version}{$InfoId}{"Line"}) = getLocation($InfoId);
3000 if(not $SymbolInfo{$Version}{$InfoId}{"Header"}
3001 or isBuiltIn($SymbolInfo{$Version}{$InfoId}{"Header"})) {
3002 delete($SymbolInfo{$Version}{$InfoId});
3003 return;
3004 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +04003005 my $ShortName = getVarShortName($InfoId);
3006 if(not $ShortName) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003007 delete($SymbolInfo{$Version}{$InfoId});
3008 return;
3009 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +04003010 if($ShortName=~/\Atmp_add_class_\d+\Z/) {
3011 delete($SymbolInfo{$Version}{$InfoId});
3012 return;
3013 }
3014 $SymbolInfo{$Version}{$InfoId}{"ShortName"} = $ShortName;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003015 $SymbolInfo{$Version}{$InfoId}{"MnglName"} = getFuncMnglName($InfoId);
3016 if($SymbolInfo{$Version}{$InfoId}{"MnglName"}
3017 and $SymbolInfo{$Version}{$InfoId}{"MnglName"}!~/\A_Z/)
3018 { # validate mangled name
3019 delete($SymbolInfo{$Version}{$InfoId});
3020 return;
3021 }
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04003022 if(not $SymbolInfo{$Version}{$InfoId}{"MnglName"}
Andrey Ponomarenko85043792012-05-14 16:48:07 +04003023 and $ShortName=~/\A_Z/)
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04003024 { # _ZTS, etc.
Andrey Ponomarenko85043792012-05-14 16:48:07 +04003025 $SymbolInfo{$Version}{$InfoId}{"MnglName"} = $ShortName;
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04003026 }
3027 if(isPrivateData($SymbolInfo{$Version}{$InfoId}{"MnglName"}))
3028 { # non-public global data
3029 delete($SymbolInfo{$Version}{$InfoId});
3030 return;
3031 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003032 $SymbolInfo{$Version}{$InfoId}{"Data"} = 1;
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04003033 if(my $Ret = getTypeId($InfoId))
3034 {
3035 if(not get_TypeName($Ret, $Version))
3036 { # typename_type
3037 delete($SymbolInfo{$Version}{$InfoId});
3038 return;
3039 }
3040 $SymbolInfo{$Version}{$InfoId}{"Return"} = $Ret;
3041 my $Val = getDataVal($InfoId, $Ret);
3042 if(defined $Val) {
3043 $SymbolInfo{$Version}{$InfoId}{"Value"} = $Val;
3044 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003045 }
3046 set_Class_And_Namespace($InfoId);
3047 if($LibInfo{$Version}{"info"}{$InfoId}=~/ lang:[ ]*C /i) {
3048 $SymbolInfo{$Version}{$InfoId}{"Lang"} = "C";
3049 }
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04003050 if($UserLang and $UserLang eq "C")
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003051 { # --lang=C option
Andrey Ponomarenko85043792012-05-14 16:48:07 +04003052 $SymbolInfo{$Version}{$InfoId}{"MnglName"} = $ShortName;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003053 }
3054 if($COMMON_LANGUAGE{$Version} eq "C++")
3055 {
3056 if(not $SymbolInfo{$Version}{$InfoId}{"MnglName"})
3057 { # for some symbols (_ZTI) the short name is the mangled name
3058 if($ShortName=~/\A_Z/) {
3059 $SymbolInfo{$Version}{$InfoId}{"MnglName"} = $ShortName;
3060 }
3061 }
3062 if(not $SymbolInfo{$Version}{$InfoId}{"MnglName"})
3063 { # try to mangle symbol (link with libraries)
3064 $SymbolInfo{$Version}{$InfoId}{"MnglName"} = linkSymbol($InfoId);
3065 }
3066 if($OStarget eq "windows")
3067 {
3068 if(my $Mangled = $mangled_name{$Version}{modelUnmangled($InfoId, "MSVC")})
3069 { # link MS C++ symbols from library with GCC symbols from headers
3070 $SymbolInfo{$Version}{$InfoId}{"MnglName"} = $Mangled;
3071 }
3072 }
3073 }
3074 if(not $SymbolInfo{$Version}{$InfoId}{"MnglName"}) {
3075 $SymbolInfo{$Version}{$InfoId}{"MnglName"} = $ShortName;
3076 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04003077 if(not $CheckHeadersOnly
3078 and not link_symbol($SymbolInfo{$Version}{$InfoId}{"MnglName"}, $Version, "-Deps"))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003079 {
Andrey Ponomarenko85043792012-05-14 16:48:07 +04003080 if(link_symbol($ShortName, $Version, "-Deps"))
3081 {
3082 if(not $SymbolInfo{$Version}{$InfoId}{"Class"}
3083 and isConstType($SymbolInfo{$Version}{$InfoId}{"Return"}, $Version)
3084 and $SymbolInfo{$Version}{$InfoId}{"MnglName"}=~/L\d+$ShortName/)
3085 { # "const" global data is mangled as _ZL... in the TU dump
3086 # but not mangled when compiling a C shared library
3087 $SymbolInfo{$Version}{$InfoId}{"MnglName"} = $ShortName;
3088 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003089 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003090 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +04003091 if(my $Symbol = $SymbolInfo{$Version}{$InfoId}{"MnglName"})
3092 {
3093 if(not selectSymbol($Symbol, $SymbolInfo{$Version}{$InfoId}, "Dump", $Version))
3094 { # non-target symbols
3095 delete($SymbolInfo{$Version}{$InfoId});
3096 return;
3097 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003098 }
3099 if(my $AddedTid = $MissedTypedef{$Version}{$SymbolInfo{$Version}{$InfoId}{"Return"}}{"Tid"}) {
3100 $SymbolInfo{$Version}{$InfoId}{"Return"} = $AddedTid;
3101 }
3102 setFuncAccess($InfoId);
3103 if($SymbolInfo{$Version}{$InfoId}{"MnglName"}=~/\A_ZTV/) {
3104 delete($SymbolInfo{$Version}{$InfoId}{"Return"});
3105 }
3106 if($ShortName=~/\A(_Z|\?)/) {
3107 delete($SymbolInfo{$Version}{$InfoId}{"ShortName"});
3108 }
3109}
3110
Andrey Ponomarenko85043792012-05-14 16:48:07 +04003111sub isConstType($$)
3112{
3113 my ($TypeId, $LibVersion) = @_;
3114 my %Base = get_Type($Tid_TDid{$LibVersion}{$TypeId}, $TypeId, $LibVersion);
3115 while(defined $Base{"Type"} and $Base{"Type"} eq "Typedef") {
3116 %Base = get_OneStep_BaseType($Base{"TDid"}, $Base{"Tid"}, $LibVersion);
3117 }
3118 return ($Base{"Type"} eq "Const");
3119}
3120
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003121sub getTrivialName($$)
3122{
3123 my ($TypeInfoId, $TypeId) = @_;
3124 my %TypeAttr = ();
3125 $TypeAttr{"Name"} = getNameByInfo($TypeInfoId);
3126 if(not $TypeAttr{"Name"}) {
3127 $TypeAttr{"Name"} = getTreeTypeName($TypeId);
3128 }
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04003129 ($TypeAttr{"Header"}, $TypeAttr{"Line"}) = getLocation($TypeInfoId);
3130 $TypeAttr{"Type"} = getTypeType($TypeInfoId, $TypeId);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003131 $TypeAttr{"Name"}=~s/<(.+)\Z//g; # GCC 3.4.4 add template params to the name
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04003132 if(isAnon($TypeAttr{"Name"}))
3133 {
3134 my $NameSpaceId = $TypeId;
3135 while(my $NSId = getNameSpaceId(getTypeDeclId($NameSpaceId)))
3136 { # searching for a first not anon scope
3137 if($NSId eq $NameSpaceId) {
3138 last;
3139 }
3140 else
3141 {
3142 $TypeAttr{"NameSpace"} = getNameSpace(getTypeDeclId($TypeId));
3143 if(not $TypeAttr{"NameSpace"}
3144 or isNotAnon($TypeAttr{"NameSpace"})) {
3145 last;
3146 }
3147 }
3148 $NameSpaceId=$NSId;
3149 }
3150 }
3151 else
3152 {
3153 if(my $NameSpaceId = getNameSpaceId($TypeInfoId))
3154 {
3155 if($NameSpaceId ne $TypeId) {
3156 $TypeAttr{"NameSpace"} = getNameSpace($TypeInfoId);
3157 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003158 }
3159 }
3160 if($TypeAttr{"NameSpace"} and isNotAnon($TypeAttr{"Name"})) {
3161 $TypeAttr{"Name"} = $TypeAttr{"NameSpace"}."::".$TypeAttr{"Name"};
3162 }
3163 $TypeAttr{"Name"} = formatName($TypeAttr{"Name"});
3164 if(isAnon($TypeAttr{"Name"}))
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04003165 { # anon-struct-header.h-line
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04003166 $TypeAttr{"Name"} = "anon-".lc($TypeAttr{"Type"})."-";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003167 $TypeAttr{"Name"} .= $TypeAttr{"Header"}."-".$TypeAttr{"Line"};
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04003168 if($TypeAttr{"NameSpace"}) {
3169 $TypeAttr{"Name"} = $TypeAttr{"NameSpace"}."::".$TypeAttr{"Name"};
3170 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003171 }
3172 if(defined $TemplateInstance{$Version}{$TypeInfoId}{$TypeId})
3173 {
3174 my @TParams = getTParams($TypeInfoId, $TypeId);
3175 if(not @TParams)
3176 { # template declarations with abstract params
3177 # vector (tree_vec) of template_type_parm nodes in the TU dump
3178 return ("", "");
3179 }
3180 $TypeAttr{"Name"} = formatName($TypeAttr{"Name"}."< ".join(", ", @TParams)." >");
3181 }
3182 return ($TypeAttr{"Name"}, $TypeAttr{"NameSpace"});
3183}
3184
3185sub getTrivialTypeAttr($$)
3186{
3187 my ($TypeInfoId, $TypeId) = @_;
Andrey Ponomarenko85043792012-05-14 16:48:07 +04003188
3189 if($TemplateDecl{$Version}{$TypeId})
3190 { # template_decl
3191 return ();
3192 }
3193
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003194 my %TypeAttr = ();
3195 if(getTypeTypeByTypeId($TypeId)!~/\A(Intrinsic|Union|Struct|Enum|Class)\Z/) {
3196 return ();
3197 }
3198 setTypeAccess($TypeId, \%TypeAttr);
3199 ($TypeAttr{"Header"}, $TypeAttr{"Line"}) = getLocation($TypeInfoId);
3200 if(isBuiltIn($TypeAttr{"Header"}))
3201 {
3202 delete($TypeAttr{"Header"});
3203 delete($TypeAttr{"Line"});
3204 }
3205 $TypeAttr{"Type"} = getTypeType($TypeInfoId, $TypeId);
3206 ($TypeAttr{"Name"}, $TypeAttr{"NameSpace"}) = getTrivialName($TypeInfoId, $TypeId);
3207 if(not $TypeAttr{"Name"}) {
3208 return ();
3209 }
3210 if(not $TypeAttr{"NameSpace"}) {
3211 delete($TypeAttr{"NameSpace"});
3212 }
Andrey Ponomarenko16934472012-03-29 15:37:04 +04003213 if(defined $TemplateInstance{$Version}{$TypeInfoId}{$TypeId})
3214 {
3215 if(my @TParams = getTParams($TypeInfoId, $TypeId))
3216 {
3217 foreach my $Pos (0 .. $#TParams) {
3218 $TypeAttr{"TParam"}{$Pos}{"name"}=$TParams[$Pos];
3219 }
3220 }
3221 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003222 if(my $Size = getSize($TypeId)) {
3223 $TypeAttr{"Size"} = $Size/$BYTE_SIZE;
3224 }
3225 if($TypeAttr{"Type"} eq "Struct"
3226 and detect_lang($TypeId))
3227 {
3228 $TypeAttr{"Type"} = "Class";
Andrey Ponomarenko85043792012-05-14 16:48:07 +04003229 $TypeAttr{"Copied"} = 1; # default, will be changed in getSymbolInfo()
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003230 }
3231 if($TypeAttr{"Type"} eq "Struct"
Andrey Ponomarenko85043792012-05-14 16:48:07 +04003232 or $TypeAttr{"Type"} eq "Class")
3233 {
3234 my $Skip = setBaseClasses($TypeInfoId, $TypeId, \%TypeAttr);
3235 if($Skip) {
3236 return ();
3237 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003238 }
3239 setSpec($TypeId, \%TypeAttr);
3240 setTypeMemb($TypeId, \%TypeAttr);
3241 $TypeAttr{"Tid"} = $TypeId;
3242 $TypeAttr{"TDid"} = $TypeInfoId;
3243 if($TypeInfoId) {
3244 $Tid_TDid{$Version}{$TypeId} = $TypeInfoId;
3245 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003246 if(my $VTable = $ClassVTable_Content{$Version}{$TypeAttr{"Name"}})
3247 {
3248 my @Entries = split(/\n/, $VTable);
3249 foreach (1 .. $#Entries)
3250 {
3251 my $Entry = $Entries[$_];
3252 if($Entry=~/\A(\d+)\s+(.+)\Z/) {
3253 $TypeAttr{"VTable"}{$1} = $2;
3254 }
3255 }
3256 }
3257 return %TypeAttr;
3258}
3259
3260sub detect_lang($)
3261{
3262 my $TypeId = $_[0];
3263 my $Info = $LibInfo{$Version}{"info"}{$TypeId};
3264 if(check_gcc_version($GCC_PATH, "4"))
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04003265 { # GCC 4 fncs-node points to only non-artificial methods
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003266 return ($Info=~/(fncs)[ ]*:[ ]*@(\d+) /);
3267 }
3268 else
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04003269 { # GCC 3
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003270 my $Fncs = getTreeAttr($TypeId, "fncs");
3271 while($Fncs)
3272 {
3273 my $Info = $LibInfo{$Version}{"info"}{$Fncs};
3274 if($Info!~/artificial/) {
3275 return 1;
3276 }
3277 $Fncs = getTreeAttr($Fncs, "chan");
3278 }
3279 }
3280 return 0;
3281}
3282
3283sub setSpec($$)
3284{
3285 my ($TypeId, $TypeAttr) = @_;
3286 my $Info = $LibInfo{$Version}{"info"}{$TypeId};
3287 if($Info=~/\s+spec\s+/) {
3288 $TypeAttr->{"Spec"} = 1;
3289 }
3290}
3291
3292sub setBaseClasses($$$)
3293{
3294 my ($TypeInfoId, $TypeId, $TypeAttr) = @_;
3295 my $Info = $LibInfo{$Version}{"info"}{$TypeId};
3296 if($Info=~/binf[ ]*:[ ]*@(\d+) /)
3297 {
3298 $Info = $LibInfo{$Version}{"info"}{$1};
3299 my $Pos = 0;
3300 while($Info=~s/(pub|public|prot|protected|priv|private|)[ ]+binf[ ]*:[ ]*@(\d+) //)
3301 {
3302 my ($Access, $BInfoId) = ($1, $2);
3303 my $ClassId = getBinfClassId($BInfoId);
Andrey Ponomarenko85043792012-05-14 16:48:07 +04003304 my $CType = $LibInfo{$Version}{"info_type"}{$ClassId};
3305 if(not $CType or $CType eq "template_type_parm"
3306 or $CType eq "typename_type")
3307 { # skip
3308 return 1;
3309 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003310 my $BaseInfo = $LibInfo{$Version}{"info"}{$BInfoId};
3311 if($Access=~/prot/)
3312 {
3313 $TypeAttr->{"Base"}{$ClassId}{"access"} = "protected";
3314 }
3315 elsif($Access=~/priv/)
3316 {
3317 $TypeAttr->{"Base"}{$ClassId}{"access"} = "private";
3318 }
3319 $TypeAttr->{"Base"}{$ClassId}{"pos"} = $Pos++;
3320 if($BaseInfo=~/virt/)
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04003321 { # virtual base
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003322 $TypeAttr->{"Base"}{$ClassId}{"virtual"} = 1;
3323 }
3324 $Class_SubClasses{$Version}{$ClassId}{$TypeId}=1;
3325 }
3326 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +04003327 return 0;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003328}
3329
3330sub getBinfClassId($)
3331{
3332 my $Info = $LibInfo{$Version}{"info"}{$_[0]};
3333 $Info=~/type[ ]*:[ ]*@(\d+) /;
3334 return $1;
3335}
3336
3337sub unmangledFormat($$)
3338{
3339 my ($Name, $LibVersion) = @_;
3340 $Name = uncover_typedefs($Name, $LibVersion);
3341 while($Name=~s/([^\w>*])(const|volatile)(,|>|\Z)/$1$3/g){};
3342 $Name=~s/\(\w+\)(\d)/$1/;
3343 return $Name;
3344}
3345
3346sub modelUnmangled($$)
3347{
3348 my ($InfoId, $Compiler) = @_;
3349 if($Cache{"modelUnmangled"}{$Version}{$Compiler}{$InfoId}) {
3350 return $Cache{"modelUnmangled"}{$Version}{$Compiler}{$InfoId};
3351 }
3352 my $PureSignature = $SymbolInfo{$Version}{$InfoId}{"ShortName"};
3353 if($SymbolInfo{$Version}{$InfoId}{"Destructor"}) {
3354 $PureSignature = "~".$PureSignature;
3355 }
3356 if(not $SymbolInfo{$Version}{$InfoId}{"Data"})
3357 {
3358 my (@Params, @ParamTypes) = ();
3359 if(defined $SymbolInfo{$Version}{$InfoId}{"Param"}
3360 and not $SymbolInfo{$Version}{$InfoId}{"Destructor"}) {
3361 @Params = keys(%{$SymbolInfo{$Version}{$InfoId}{"Param"}});
3362 }
3363 foreach my $ParamPos (sort {int($a) <=> int($b)} @Params)
3364 { # checking parameters
3365 my $PId = $SymbolInfo{$Version}{$InfoId}{"Param"}{$ParamPos}{"type"};
3366 my %PType = get_PureType($Tid_TDid{$Version}{$PId}, $PId, $Version);
3367 my $PTName = unmangledFormat($PType{"Name"}, $Version);
3368 $PTName=~s/(\A|\W)(restrict|register)(\W|\Z)/$1$3/g;
3369 if($Compiler eq "MSVC") {
3370 $PTName=~s/(\W|\A)long long(\W|\Z)/$1__int64$2/;
3371 }
3372 @ParamTypes = (@ParamTypes, $PTName);
3373 }
3374 if(@ParamTypes) {
3375 $PureSignature .= "(".join(", ", @ParamTypes).")";
3376 }
3377 else
3378 {
3379 if($Compiler eq "MSVC")
3380 {
3381 $PureSignature .= "(void)";
3382 }
3383 else
3384 { # GCC
3385 $PureSignature .= "()";
3386 }
3387 }
3388 $PureSignature = delete_keywords($PureSignature);
3389 }
3390 if(my $ClassId = $SymbolInfo{$Version}{$InfoId}{"Class"})
3391 {
3392 my $ClassName = unmangledFormat(get_TypeName($ClassId, $Version), $Version);
3393 $PureSignature = $ClassName."::".$PureSignature;
3394 }
3395 elsif(my $NS = $SymbolInfo{$Version}{$InfoId}{"NameSpace"}) {
3396 $PureSignature = $NS."::".$PureSignature;
3397 }
3398 if($SymbolInfo{$Version}{$InfoId}{"Const"}) {
3399 $PureSignature .= " const";
3400 }
3401 if($SymbolInfo{$Version}{$InfoId}{"Volatile"}) {
3402 $PureSignature .= " volatile";
3403 }
3404 my $ShowReturn = 0;
3405 if($Compiler eq "MSVC"
3406 and $SymbolInfo{$Version}{$InfoId}{"Data"})
3407 {
3408 $ShowReturn=1;
3409 }
3410 elsif(defined $TemplateInstance_Func{$Version}{$InfoId}
3411 and keys(%{$TemplateInstance_Func{$Version}{$InfoId}}))
3412 {
3413 $ShowReturn=1;
3414 }
3415 if($ShowReturn)
3416 { # mangled names for template function specializations include return value
3417 if(my $ReturnId = $SymbolInfo{$Version}{$InfoId}{"Return"})
3418 {
3419 my %RType = get_PureType($Tid_TDid{$Version}{$ReturnId}, $ReturnId, $Version);
3420 my $ReturnName = unmangledFormat($RType{"Name"}, $Version);
3421 $PureSignature = $ReturnName." ".$PureSignature;
3422 }
3423 }
3424 return ($Cache{"modelUnmangled"}{$Version}{$Compiler}{$InfoId} = formatName($PureSignature));
3425}
3426
3427sub mangle_symbol($$$)
3428{ # mangling for simple methods
3429 # see gcc-4.6.0/gcc/cp/mangle.c
3430 my ($InfoId, $LibVersion, $Compiler) = @_;
3431 if($Cache{"mangle_symbol"}{$LibVersion}{$InfoId}{$Compiler}) {
3432 return $Cache{"mangle_symbol"}{$LibVersion}{$InfoId}{$Compiler};
3433 }
3434 my $Mangled = "";
3435 if($Compiler eq "GCC") {
Andrey Ponomarenko16934472012-03-29 15:37:04 +04003436 $Mangled = mangle_symbol_GCC($InfoId, $LibVersion);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003437 }
3438 elsif($Compiler eq "MSVC") {
Andrey Ponomarenko16934472012-03-29 15:37:04 +04003439 $Mangled = mangle_symbol_MSVC($InfoId, $LibVersion);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003440 }
3441 return ($Cache{"mangle_symbol"}{$LibVersion}{$InfoId}{$Compiler} = $Mangled);
3442}
3443
Andrey Ponomarenko16934472012-03-29 15:37:04 +04003444sub mangle_symbol_MSVC($$)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003445{
3446 my ($InfoId, $LibVersion) = @_;
3447 return "";
3448}
3449
Andrey Ponomarenko16934472012-03-29 15:37:04 +04003450sub mangle_symbol_GCC($$)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003451{ # see gcc-4.6.0/gcc/cp/mangle.c
3452 my ($InfoId, $LibVersion) = @_;
3453 my ($Mangled, $ClassId, $NameSpace) = ("_Z", 0, "");
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04003454 my $Return = $SymbolInfo{$LibVersion}{$InfoId}{"Return"};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003455 my %Repl = ();# SN_ replacements
3456 if($ClassId = $SymbolInfo{$LibVersion}{$InfoId}{"Class"})
3457 {
3458 my $MangledClass = mangle_param($ClassId, $LibVersion, \%Repl);
3459 if($MangledClass!~/\AN/) {
3460 $MangledClass = "N".$MangledClass;
3461 }
3462 else {
3463 $MangledClass=~s/E\Z//;
3464 }
3465 if($SymbolInfo{$LibVersion}{$InfoId}{"Volatile"}) {
3466 $MangledClass=~s/\AN/NV/;
3467 }
3468 if($SymbolInfo{$LibVersion}{$InfoId}{"Const"}) {
3469 $MangledClass=~s/\AN/NK/;
3470 }
3471 $Mangled .= $MangledClass;
3472 }
3473 elsif($NameSpace = $SymbolInfo{$LibVersion}{$InfoId}{"NameSpace"})
3474 { # mangled by name due to the absence of structured info
3475 my $MangledNS = mangle_ns($NameSpace, $LibVersion, \%Repl);
3476 if($MangledNS!~/\AN/) {
3477 $MangledNS = "N".$MangledNS;
3478 }
3479 else {
3480 $MangledNS=~s/E\Z//;
3481 }
3482 $Mangled .= $MangledNS;
3483 }
3484 my ($ShortName, $TmplParams) = template_base($SymbolInfo{$LibVersion}{$InfoId}{"ShortName"});
Andrey Ponomarenko16934472012-03-29 15:37:04 +04003485 my @TParams = ();
3486 if($Version)
3487 { # parsing mode
3488 @TParams = getTParams_Func($InfoId);
3489 }
3490 elsif($TmplParams)
3491 { # remangling mode
3492 # support for old ABI dumps
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003493 @TParams = separate_params($TmplParams, 0);
3494 }
3495 if($SymbolInfo{$LibVersion}{$InfoId}{"Constructor"}) {
3496 $Mangled .= "C1";
3497 }
3498 elsif($SymbolInfo{$LibVersion}{$InfoId}{"Destructor"}) {
3499 $Mangled .= "D0";
3500 }
3501 elsif($ShortName)
3502 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04003503 if($SymbolInfo{$LibVersion}{$InfoId}{"Data"})
3504 {
Andrey Ponomarenko16934472012-03-29 15:37:04 +04003505 if(not $SymbolInfo{$LibVersion}{$InfoId}{"Class"}
Andrey Ponomarenko85043792012-05-14 16:48:07 +04003506 and isConstType($Return, $LibVersion))
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04003507 { # "const" global data is mangled as _ZL...
3508 $Mangled .= "L";
3509 }
3510 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003511 if($ShortName=~/\Aoperator(\W.*)\Z/)
3512 {
3513 my $Op = $1;
3514 $Op=~s/\A[ ]+//g;
3515 if(my $OpMngl = $OperatorMangling{$Op}) {
3516 $Mangled .= $OpMngl;
3517 }
3518 else { # conversion operator
3519 $Mangled .= "cv".mangle_param(getTypeIdByName($Op, $LibVersion), $LibVersion, \%Repl);
3520 }
3521 }
3522 else {
3523 $Mangled .= length($ShortName).$ShortName;
3524 }
3525 if(@TParams)
3526 { # templates
3527 $Mangled .= "I";
3528 foreach my $TParam (@TParams) {
3529 $Mangled .= mangle_template_param($TParam, $LibVersion, \%Repl);
3530 }
3531 $Mangled .= "E";
3532 }
3533 if(not $ClassId and @TParams) {
3534 add_substitution($ShortName, \%Repl, 0);
3535 }
3536 }
3537 if($ClassId or $NameSpace) {
3538 $Mangled .= "E";
3539 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +04003540 if(@TParams)
3541 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04003542 if($Return) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003543 $Mangled .= mangle_param($Return, $LibVersion, \%Repl);
3544 }
3545 }
3546 if(not $SymbolInfo{$LibVersion}{$InfoId}{"Data"})
3547 {
3548 my @Params = ();
3549 if(defined $SymbolInfo{$LibVersion}{$InfoId}{"Param"}
3550 and not $SymbolInfo{$LibVersion}{$InfoId}{"Destructor"}) {
3551 @Params = keys(%{$SymbolInfo{$LibVersion}{$InfoId}{"Param"}});
3552 }
3553 foreach my $ParamPos (sort {int($a) <=> int($b)} @Params)
3554 { # checking parameters
3555 my $ParamType_Id = $SymbolInfo{$LibVersion}{$InfoId}{"Param"}{$ParamPos}{"type"};
3556 $Mangled .= mangle_param($ParamType_Id, $LibVersion, \%Repl);
3557 }
3558 if(not @Params) {
3559 $Mangled .= "v";
3560 }
3561 }
3562 $Mangled = correct_incharge($InfoId, $LibVersion, $Mangled);
3563 $Mangled = write_stdcxx_substitution($Mangled);
3564 if($Mangled eq "_Z") {
3565 return "";
3566 }
3567 return $Mangled;
3568}
3569
3570sub correct_incharge($$$)
3571{
3572 my ($InfoId, $LibVersion, $Mangled) = @_;
3573 if($SymbolInfo{$LibVersion}{$InfoId}{"Constructor"})
3574 {
3575 if($MangledNames{$LibVersion}{$Mangled}) {
3576 $Mangled=~s/C1E/C2E/;
3577 }
3578 }
3579 elsif($SymbolInfo{$LibVersion}{$InfoId}{"Destructor"})
3580 {
3581 if($MangledNames{$LibVersion}{$Mangled}) {
3582 $Mangled=~s/D0E/D1E/;
3583 }
3584 if($MangledNames{$LibVersion}{$Mangled}) {
3585 $Mangled=~s/D1E/D2E/;
3586 }
3587 }
3588 return $Mangled;
3589}
3590
3591sub template_base($)
3592{ # NOTE: std::_Vector_base<mysqlpp::mysql_type_info>::_Vector_impl
Andrey Ponomarenko16934472012-03-29 15:37:04 +04003593 # NOTE: operators: >>, <<
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003594 my $Name = $_[0];
Andrey Ponomarenko16934472012-03-29 15:37:04 +04003595 if($Name!~/>\Z/ or $Name!~/</) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003596 return $Name;
3597 }
3598 my $TParams = $Name;
Andrey Ponomarenko16934472012-03-29 15:37:04 +04003599 while(my $CPos = find_center($TParams, "<"))
3600 { # search for the last <T>
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003601 $TParams = substr($TParams, $CPos);
3602 }
Andrey Ponomarenko16934472012-03-29 15:37:04 +04003603 if($TParams=~s/\A<(.+)>\Z/$1/) {
3604 $Name=~s/<\Q$TParams\E>\Z//;
3605 }
3606 else
3607 { # error
3608 $TParams = "";
3609 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003610 return ($Name, $TParams);
3611}
3612
3613sub get_sub_ns($)
3614{
3615 my $Name = $_[0];
3616 my @NS = ();
Andrey Ponomarenko16934472012-03-29 15:37:04 +04003617 while(my $CPos = find_center($Name, ":"))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003618 {
3619 push(@NS, substr($Name, 0, $CPos));
3620 $Name = substr($Name, $CPos);
3621 $Name=~s/\A:://;
3622 }
3623 return (join("::", @NS), $Name);
3624}
3625
3626sub mangle_ns($$$)
3627{
3628 my ($Name, $LibVersion, $Repl) = @_;
3629 if(my $Tid = $TName_Tid{$LibVersion}{$Name})
3630 {
3631 my $Mangled = mangle_param($Tid, $LibVersion, $Repl);
3632 $Mangled=~s/\AN(.+)E\Z/$1/;
3633 return $Mangled;
3634
3635 }
3636 else
3637 {
3638 my ($MangledNS, $SubNS) = ("", "");
3639 ($SubNS, $Name) = get_sub_ns($Name);
3640 if($SubNS) {
3641 $MangledNS .= mangle_ns($SubNS, $LibVersion, $Repl);
3642 }
3643 $MangledNS .= length($Name).$Name;
3644 add_substitution($MangledNS, $Repl, 0);
3645 return $MangledNS;
3646 }
3647}
3648
3649sub mangle_param($$$)
3650{
3651 my ($PTid, $LibVersion, $Repl) = @_;
3652 my ($MPrefix, $Mangled) = ("", "");
3653 my %ReplCopy = %{$Repl};
3654 my %BaseType = get_BaseType($Tid_TDid{$LibVersion}{$PTid}, $PTid, $LibVersion);
3655 my $BaseType_Name = $BaseType{"Name"};
3656 if(not $BaseType_Name) {
3657 return "";
3658 }
3659 my ($ShortName, $TmplParams) = template_base($BaseType_Name);
3660 my $Suffix = get_BaseTypeQual($Tid_TDid{$LibVersion}{$PTid}, $PTid, $LibVersion);
3661 while($Suffix=~s/\s*(const|volatile|restrict)\Z//g){};
3662 while($Suffix=~/(&|\*|const)\Z/)
3663 {
3664 if($Suffix=~s/[ ]*&\Z//) {
3665 $MPrefix .= "R";
3666 }
3667 if($Suffix=~s/[ ]*\*\Z//) {
3668 $MPrefix .= "P";
3669 }
3670 if($Suffix=~s/[ ]*const\Z//)
3671 {
3672 if($MPrefix=~/R|P/
3673 or $Suffix=~/&|\*/) {
3674 $MPrefix .= "K";
3675 }
3676 }
3677 if($Suffix=~s/[ ]*volatile\Z//) {
3678 $MPrefix .= "V";
3679 }
3680 #if($Suffix=~s/[ ]*restrict\Z//) {
3681 #$MPrefix .= "r";
3682 #}
3683 }
3684 if(my $Token = $IntrinsicMangling{$BaseType_Name}) {
3685 $Mangled .= $Token;
3686 }
3687 elsif($BaseType{"Type"}=~/(Class|Struct|Union|Enum)/)
3688 {
Andrey Ponomarenko16934472012-03-29 15:37:04 +04003689 my @TParams = ();
3690 if($Version)
3691 { # parsing mode
3692 @TParams = getTParams($BaseType{"TDid"}, $BaseType{"Tid"});
3693 }
3694 elsif($TmplParams)
3695 { # remangling mode
3696 # support for old ABI dumps
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003697 @TParams = separate_params($TmplParams, 0);
3698 }
3699 my $MangledNS = "";
3700 my ($SubNS, $SName) = get_sub_ns($ShortName);
3701 if($SubNS) {
3702 $MangledNS .= mangle_ns($SubNS, $LibVersion, $Repl);
3703 }
3704 $MangledNS .= length($SName).$SName;
3705 if(@TParams) {
3706 add_substitution($MangledNS, $Repl, 0);
3707 }
3708 $Mangled .= "N".$MangledNS;
3709 if(@TParams)
3710 { # templates
3711 $Mangled .= "I";
3712 foreach my $TParam (@TParams) {
3713 $Mangled .= mangle_template_param($TParam, $LibVersion, $Repl);
3714 }
3715 $Mangled .= "E";
3716 }
3717 $Mangled .= "E";
3718 }
3719 elsif($BaseType{"Type"}=~/(FuncPtr|MethodPtr)/)
3720 {
3721 if($BaseType{"Type"} eq "MethodPtr") {
3722 $Mangled .= "M".mangle_param($BaseType{"Class"}, $LibVersion, $Repl)."F";
3723 }
3724 else {
3725 $Mangled .= "PF";
3726 }
3727 $Mangled .= mangle_param($BaseType{"Return"}, $LibVersion, $Repl);
3728 my @Params = keys(%{$BaseType{"Param"}});
3729 foreach my $Num (sort {int($a)<=>int($b)} @Params) {
3730 $Mangled .= mangle_param($BaseType{"Param"}{$Num}{"type"}, $LibVersion, $Repl);
3731 }
3732 if(not @Params) {
3733 $Mangled .= "v";
3734 }
3735 $Mangled .= "E";
3736 }
3737 elsif($BaseType{"Type"} eq "FieldPtr")
3738 {
3739 $Mangled .= "M".mangle_param($BaseType{"Class"}, $LibVersion, $Repl);
3740 $Mangled .= mangle_param($BaseType{"Return"}, $LibVersion, $Repl);
3741 }
3742 $Mangled = $MPrefix.$Mangled;# add prefix (RPK)
3743 if(my $Optimized = write_substitution($Mangled, \%ReplCopy))
3744 {
3745 if($Mangled eq $Optimized)
3746 {
3747 if($ShortName!~/::/)
3748 { # remove "N ... E"
3749 if($MPrefix) {
3750 $Mangled=~s/\A($MPrefix)N(.+)E\Z/$1$2/g;
3751 }
3752 else {
3753 $Mangled=~s/\AN(.+)E\Z/$1/g;
3754 }
3755 }
3756 }
3757 else {
3758 $Mangled = $Optimized;
3759 }
3760 }
3761 add_substitution($Mangled, $Repl, 1);
3762 return $Mangled;
3763}
3764
3765sub mangle_template_param($$$)
3766{ # types + literals
3767 my ($TParam, $LibVersion, $Repl) = @_;
3768 if(my $TPTid = $TName_Tid{$LibVersion}{$TParam}) {
3769 return mangle_param($TPTid, $LibVersion, $Repl);
3770 }
3771 elsif($TParam=~/\A(\d+)(\w+)\Z/)
3772 { # class_name<1u>::method(...)
3773 return "L".$IntrinsicMangling{$ConstantSuffixR{$2}}.$1."E";
3774 }
3775 elsif($TParam=~/\A\(([\w ]+)\)(\d+)\Z/)
3776 { # class_name<(signed char)1>::method(...)
3777 return "L".$IntrinsicMangling{$1}.$2."E";
3778 }
3779 elsif($TParam eq "true")
3780 { # class_name<true>::method(...)
3781 return "Lb1E";
3782 }
3783 elsif($TParam eq "false")
3784 { # class_name<true>::method(...)
3785 return "Lb0E";
3786 }
3787 else { # internal error
3788 return length($TParam).$TParam;
3789 }
3790}
3791
3792sub add_substitution($$$)
3793{
3794 my ($Value, $Repl, $Rec) = @_;
3795 if($Rec)
3796 { # subtypes
3797 my @Subs = ($Value);
3798 while($Value=~s/\A(R|P|K)//) {
3799 push(@Subs, $Value);
3800 }
3801 foreach (reverse(@Subs)) {
3802 add_substitution($_, $Repl, 0);
3803 }
3804 return;
3805 }
3806 return if($Value=~/\AS(\d*)_\Z/);
3807 $Value=~s/\AN(.+)E\Z/$1/g;
3808 return if(defined $Repl->{$Value});
3809 return if(length($Value)<=1);
3810 return if($StdcxxMangling{$Value});
3811 # check for duplicates
3812 my $Base = $Value;
3813 foreach my $Type (sort {$Repl->{$a}<=>$Repl->{$b}} sort keys(%{$Repl}))
3814 {
3815 my $Num = $Repl->{$Type};
3816 my $Replace = macro_mangle($Num);
3817 $Base=~s/\Q$Replace\E/$Type/;
3818 }
3819 if(my $OldNum = $Repl->{$Base})
3820 {
3821 $Repl->{$Value} = $OldNum;
3822 return;
3823 }
3824 my @Repls = sort {$b<=>$a} values(%{$Repl});
3825 if(@Repls) {
3826 $Repl->{$Value} = $Repls[0]+1;
3827 }
3828 else {
3829 $Repl->{$Value} = -1;
3830 }
3831 # register duplicates
3832 # upward
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04003833 $Base = $Value;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003834 foreach my $Type (sort {$Repl->{$a}<=>$Repl->{$b}} sort keys(%{$Repl}))
3835 {
3836 next if($Base eq $Type);
3837 my $Num = $Repl->{$Type};
3838 my $Replace = macro_mangle($Num);
3839 $Base=~s/\Q$Type\E/$Replace/;
3840 $Repl->{$Base} = $Repl->{$Value};
3841 }
3842}
3843
3844sub macro_mangle($)
3845{
3846 my $Num = $_[0];
3847 if($Num==-1) {
3848 return "S_";
3849 }
3850 else
3851 {
3852 my $Code = "";
3853 if($Num<10)
3854 { # S0_, S1_, S2_, ...
3855 $Code = $Num;
3856 }
3857 elsif($Num>=10 and $Num<=35)
3858 { # SA_, SB_, SC_, ...
3859 $Code = chr(55+$Num);
3860 }
3861 else
3862 { # S10_, S11_, S12_
3863 $Code = $Num-26; # 26 is length of english alphabet
3864 }
3865 return "S".$Code."_";
3866 }
3867}
3868
3869sub write_stdcxx_substitution($)
3870{
3871 my $Mangled = $_[0];
3872 if($StdcxxMangling{$Mangled}) {
3873 return $StdcxxMangling{$Mangled};
3874 }
3875 else
3876 {
3877 my @Repls = keys(%StdcxxMangling);
3878 @Repls = sort {length($b)<=>length($a)} sort {$b cmp $a} @Repls;
3879 foreach my $MangledType (@Repls)
3880 {
3881 my $Replace = $StdcxxMangling{$MangledType};
3882 #if($Mangled!~/$Replace/) {
3883 $Mangled=~s/N\Q$MangledType\EE/$Replace/g;
3884 $Mangled=~s/\Q$MangledType\E/$Replace/g;
3885 #}
3886 }
3887 }
3888 return $Mangled;
3889}
3890
3891sub write_substitution($$)
3892{
3893 my ($Mangled, $Repl) = @_;
3894 if(defined $Repl->{$Mangled}
3895 and my $MnglNum = $Repl->{$Mangled}) {
3896 $Mangled = macro_mangle($MnglNum);
3897 }
3898 else
3899 {
3900 my @Repls = keys(%{$Repl});
3901 #@Repls = sort {$Repl->{$a}<=>$Repl->{$b}} @Repls;
3902 # FIXME: how to apply replacements? by num or by pos
3903 @Repls = sort {length($b)<=>length($a)} sort {$b cmp $a} @Repls;
3904 foreach my $MangledType (@Repls)
3905 {
3906 my $Replace = macro_mangle($Repl->{$MangledType});
3907 if($Mangled!~/$Replace/) {
3908 $Mangled=~s/N\Q$MangledType\EE/$Replace/g;
3909 $Mangled=~s/\Q$MangledType\E/$Replace/g;
3910 }
3911 }
3912 }
3913 return $Mangled;
3914}
3915
3916sub delete_keywords($)
3917{
3918 my $TypeName = $_[0];
3919 $TypeName=~s/(\W|\A)(enum |struct |union |class )/$1/g;
3920 return $TypeName;
3921}
3922
3923my %Intrinsic_Keywords = map {$_=>1} (
3924 "true",
3925 "false",
3926 "_Bool",
3927 "_Complex",
3928 "const",
3929 "int",
3930 "long",
3931 "void",
3932 "short",
3933 "float",
3934 "volatile",
3935 "restrict",
3936 "unsigned",
3937 "signed",
3938 "char",
3939 "double",
3940 "class",
3941 "struct",
3942 "union",
3943 "enum"
3944);
3945
3946sub uncover_typedefs($$)
3947{
3948 my ($TypeName, $LibVersion) = @_;
3949 return "" if(not $TypeName);
3950 if(defined $Cache{"uncover_typedefs"}{$LibVersion}{$TypeName}) {
3951 return $Cache{"uncover_typedefs"}{$LibVersion}{$TypeName};
3952 }
3953 my ($TypeName_New, $TypeName_Pre) = (formatName($TypeName), "");
3954 while($TypeName_New ne $TypeName_Pre)
3955 {
3956 $TypeName_Pre = $TypeName_New;
3957 my $TypeName_Copy = $TypeName_New;
3958 my %Words = ();
3959 while($TypeName_Copy=~s/(\W|\A)([a-z_][\w:]*)(\W|\Z)//io)
3960 {
3961 my $Word = $2;
3962 next if(not $Word or $Intrinsic_Keywords{$Word});
3963 $Words{$Word} = 1;
3964 }
3965 foreach my $Word (keys(%Words))
3966 {
3967 my $BaseType_Name = $Typedef_BaseName{$LibVersion}{$Word};
3968 next if(not $BaseType_Name);
3969 next if($TypeName_New=~/(\A|\W)(struct|union|enum)\s\Q$Word\E(\W|\Z)/);
3970 if($BaseType_Name=~/\([\*]+\)/)
3971 { # FuncPtr
3972 if($TypeName_New=~/\Q$Word\E(.*)\Z/)
3973 {
3974 my $Type_Suffix = $1;
3975 $TypeName_New = $BaseType_Name;
3976 if($TypeName_New=~s/\(([\*]+)\)/($1 $Type_Suffix)/) {
3977 $TypeName_New = formatName($TypeName_New);
3978 }
3979 }
3980 }
3981 else
3982 {
3983 if($TypeName_New=~s/(\W|\A)\Q$Word\E(\W|\Z)/$1$BaseType_Name$2/g) {
3984 $TypeName_New = formatName($TypeName_New);
3985 }
3986 }
3987 }
3988 }
3989 return ($Cache{"uncover_typedefs"}{$LibVersion}{$TypeName} = $TypeName_New);
3990}
3991
3992sub isInternal($)
3993{
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04003994 if($_[0] and my $Info = $LibInfo{$Version}{"info"}{$_[0]})
3995 {
3996 if($Info=~/mngl[ ]*:[ ]*@(\d+) /)
3997 {
3998 if($LibInfo{$Version}{"info"}{$1}=~/\*[ ]*INTERNAL[ ]*\*/)
3999 { # _ZN7mysqlpp8DateTimeC1ERKS0_ *INTERNAL*
4000 return 1;
4001 }
4002 }
4003 }
4004 return 0;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004005}
4006
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04004007sub getDataVal($$)
4008{
4009 my ($InfoId, $TypeId) = @_;
4010 if(my $Info = $LibInfo{$Version}{"info"}{$InfoId})
4011 {
4012 if($Info=~/init[ ]*:[ ]*@(\d+) /)
4013 {
4014 if(defined $LibInfo{$Version}{"info_type"}{$1}
4015 and $LibInfo{$Version}{"info_type"}{$1} eq "nop_expr")
4016 { # char const* data = "str"
4017 # NOTE: disabled
4018 if(my $NopExpr = $LibInfo{$Version}{"info"}{$1})
4019 {
4020 if($NopExpr=~/op 0[ ]*:[ ]*@(\d+) /)
4021 {
4022 if(defined $LibInfo{$Version}{"info_type"}{$1}
4023 and $LibInfo{$Version}{"info_type"}{$1} eq "addr_expr")
4024 {
4025 if(my $AddrExpr = $LibInfo{$Version}{"info"}{$1})
4026 {
4027 if($AddrExpr=~/op 0[ ]*:[ ]*@(\d+) /)
4028 {
4029 return getInitVal($1, $TypeId);
4030 }
4031 }
4032 }
4033 }
4034 }
4035 }
4036 else {
4037 return getInitVal($1, $TypeId);
4038 }
4039 }
4040 }
4041 return undef;
4042}
4043
4044sub getInitVal($$)
4045{
4046 my ($InfoId, $TypeId) = @_;
4047 if(my $Info = $LibInfo{$Version}{"info"}{$InfoId})
4048 {
4049 if(my $InfoType = $LibInfo{$Version}{"info_type"}{$InfoId})
4050 {
4051 if($InfoType eq "integer_cst")
4052 {
4053 my $Val = getNodeIntCst($InfoId);
4054 if($TypeId and get_TypeName($TypeId, $Version)=~/\Achar(| const)\Z/)
4055 { # characters
4056 $Val = chr($Val);
4057 }
4058 return $Val;
4059 }
4060 elsif($InfoType eq "string_cst") {
4061 return getNodeStrCst($InfoId);
4062 }
4063 }
4064 }
4065 return undef;
4066}
4067
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004068sub set_Class_And_Namespace($)
4069{
4070 my $InfoId = $_[0];
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04004071 if(my $Info = $LibInfo{$Version}{"info"}{$InfoId})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004072 {
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04004073 if($Info=~/scpe[ ]*:[ ]*@(\d+) /)
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04004074 {
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04004075 my $NSInfoId = $1;
4076 if(my $InfoType = $LibInfo{$Version}{"info_type"}{$NSInfoId})
4077 {
4078 if($InfoType eq "namespace_decl") {
4079 $SymbolInfo{$Version}{$InfoId}{"NameSpace"} = getNameSpace($InfoId);
4080 }
4081 elsif($InfoType eq "record_type") {
4082 $SymbolInfo{$Version}{$InfoId}{"Class"} = $NSInfoId;
4083 }
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04004084 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004085 }
4086 }
4087 if($SymbolInfo{$Version}{$InfoId}{"Class"}
4088 or $SymbolInfo{$Version}{$InfoId}{"NameSpace"})
4089 { # identify language
4090 setLanguage($Version, "C++");
4091 }
4092}
4093
4094sub debugType($$)
4095{
4096 my ($Tid, $LibVersion) = @_;
4097 my %Type = get_Type($Tid_TDid{$LibVersion}{$Tid}, $Tid, $LibVersion);
4098 printMsg("INFO", Dumper(\%Type));
4099}
4100
4101sub debugMangling($)
4102{
4103 my $LibVersion = $_[0];
4104 my %Mangled = ();
4105 foreach my $InfoId (keys(%{$SymbolInfo{$LibVersion}}))
4106 {
4107 if(my $Mngl = $SymbolInfo{$LibVersion}{$InfoId}{"MnglName"})
4108 {
4109 if($Mngl=~/\A(_Z|\?)/) {
4110 $Mangled{$Mngl}=$InfoId;
4111 }
4112 }
4113 }
4114 translateSymbols(keys(%Mangled), $LibVersion);
4115 foreach my $Mngl (keys(%Mangled))
4116 {
Andrey Ponomarenko85043792012-05-14 16:48:07 +04004117 my $U1 = modelUnmangled($Mangled{$Mngl}, "GCC");
4118 my $U2 = $tr_name{$Mngl};
4119 if($U1 ne $U2) {
4120 printMsg("INFO", "INCORRECT MANGLING:\n $Mngl\n $U1\n $U2\n");
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004121 }
4122 }
4123}
4124
4125sub linkSymbol($)
4126{ # link symbols from shared libraries
4127 # with the symbols from header files
4128 my $InfoId = $_[0];
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04004129 if(my $Lang = $SymbolInfo{$Version}{$InfoId}{"Lang"})
4130 {
4131 if($Lang eq "C")
4132 { # extern "C"
4133 return $SymbolInfo{$Version}{$InfoId}{"ShortName"};
4134 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004135 }
4136 # try to mangle symbol
4137 if((not check_gcc_version($GCC_PATH, "4") and $SymbolInfo{$Version}{$InfoId}{"Class"})
4138 or (check_gcc_version($GCC_PATH, "4") and not $SymbolInfo{$Version}{$InfoId}{"Class"}))
4139 { # 1. GCC 3.x doesn't mangle class methods names in the TU dump (only functions and global data)
4140 # 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 +04004141 if(not $CheckHeadersOnly)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004142 {
4143 if(my $Mangled = $mangled_name_gcc{modelUnmangled($InfoId, "GCC")}) {
4144 return correct_incharge($InfoId, $Version, $Mangled);
4145 }
4146 }
Andrey Ponomarenko16934472012-03-29 15:37:04 +04004147 if($CheckHeadersOnly
4148 or not $BinaryOnly)
4149 { # 1. --headers-only mode
4150 # 2. not mangled src-only symbols
4151 if(my $Mangled = mangle_symbol($InfoId, $Version, "GCC")) {
4152 return $Mangled;
4153 }
4154 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004155 }
4156 return "";
4157}
4158
4159sub setLanguage($$)
4160{
4161 my ($LibVersion, $Lang) = @_;
4162 if(not $UserLang) {
4163 $COMMON_LANGUAGE{$LibVersion} = $Lang;
4164 }
4165}
4166
4167sub getSymbolInfo($)
4168{
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04004169 my $InfoId = $_[0];
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04004170 if(isInternal($InfoId)) {
4171 return;
4172 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04004173 ($SymbolInfo{$Version}{$InfoId}{"Header"}, $SymbolInfo{$Version}{$InfoId}{"Line"}) = getLocation($InfoId);
4174 if(not $SymbolInfo{$Version}{$InfoId}{"Header"}
4175 or isBuiltIn($SymbolInfo{$Version}{$InfoId}{"Header"})) {
4176 delete($SymbolInfo{$Version}{$InfoId});
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004177 return;
4178 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04004179 setFuncAccess($InfoId);
4180 setFuncKind($InfoId);
4181 if($SymbolInfo{$Version}{$InfoId}{"PseudoTemplate"}) {
4182 delete($SymbolInfo{$Version}{$InfoId});
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004183 return;
4184 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04004185 $SymbolInfo{$Version}{$InfoId}{"Type"} = getFuncType($InfoId);
4186 $SymbolInfo{$Version}{$InfoId}{"Return"} = getFuncReturn($InfoId);
4187 if(my $AddedTid = $MissedTypedef{$Version}{$SymbolInfo{$Version}{$InfoId}{"Return"}}{"Tid"}) {
4188 $SymbolInfo{$Version}{$InfoId}{"Return"} = $AddedTid;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004189 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04004190 if(not $SymbolInfo{$Version}{$InfoId}{"Return"}) {
4191 delete($SymbolInfo{$Version}{$InfoId}{"Return"});
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004192 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04004193 $SymbolInfo{$Version}{$InfoId}{"ShortName"} = getFuncShortName(getFuncOrig($InfoId));
4194 if($SymbolInfo{$Version}{$InfoId}{"ShortName"}=~/\._/) {
4195 delete($SymbolInfo{$Version}{$InfoId});
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004196 return;
4197 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04004198 if(defined $TemplateInstance_Func{$Version}{$InfoId})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004199 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04004200 my @TParams = getTParams_Func($InfoId);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004201 if(not @TParams) {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04004202 delete($SymbolInfo{$Version}{$InfoId});
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004203 return;
4204 }
Andrey Ponomarenko16934472012-03-29 15:37:04 +04004205 foreach my $Pos (0 .. $#TParams) {
4206 $SymbolInfo{$Version}{$InfoId}{"TParam"}{$Pos}{"name"}=$TParams[$Pos];
4207 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004208 my $PrmsInLine = join(", ", @TParams);
Andrey Ponomarenko16934472012-03-29 15:37:04 +04004209 if($SymbolInfo{$Version}{$InfoId}{"ShortName"}=~/\Aoperator\W+\Z/)
4210 { # operator<< <T>, operator>> <T>
4211 $SymbolInfo{$Version}{$InfoId}{"ShortName"} .= " ";
4212 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04004213 $SymbolInfo{$Version}{$InfoId}{"ShortName"} .= "<".$PrmsInLine.">";
4214 $SymbolInfo{$Version}{$InfoId}{"ShortName"} = formatName($SymbolInfo{$Version}{$InfoId}{"ShortName"});
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004215 }
4216 else
4217 { # support for GCC 3.4
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04004218 $SymbolInfo{$Version}{$InfoId}{"ShortName"}=~s/<.+>\Z//;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004219 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04004220 $SymbolInfo{$Version}{$InfoId}{"MnglName"} = getFuncMnglName($InfoId);
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04004221 # NOTE: mangling of some symbols may change depending on GCC version
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04004222 # GCC 4.6: _ZN28QExplicitlySharedDataPointerI11QPixmapDataEC2IT_EERKS_IT_E
4223 # GCC 4.7: _ZN28QExplicitlySharedDataPointerI11QPixmapDataEC2ERKS1_
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04004224
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04004225 if($SymbolInfo{$Version}{$InfoId}{"MnglName"}
4226 and $SymbolInfo{$Version}{$InfoId}{"MnglName"}!~/\A_Z/)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004227 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04004228 delete($SymbolInfo{$Version}{$InfoId});
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004229 return;
4230 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04004231 if(not $SymbolInfo{$Version}{$InfoId}{"Destructor"})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004232 { # destructors have an empty parameter list
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04004233 my $Skip = setFuncParams($InfoId);
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04004234 if($Skip) {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04004235 delete($SymbolInfo{$Version}{$InfoId});
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004236 return;
4237 }
4238 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04004239 set_Class_And_Namespace($InfoId);
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04004240 if(not $CheckHeadersOnly)
4241 {
4242 if($SymbolInfo{$Version}{$InfoId}{"Type"} eq "Function"
4243 and not $SymbolInfo{$Version}{$InfoId}{"Class"}
4244 and link_symbol($SymbolInfo{$Version}{$InfoId}{"ShortName"}, $Version, "-Deps"))
4245 { # functions (C++): not mangled in library, but are mangled in TU dump
4246 if(not $SymbolInfo{$Version}{$InfoId}{"MnglName"}
4247 or not link_symbol($SymbolInfo{$Version}{$InfoId}{"MnglName"}, $Version, "-Deps")) {
4248 $SymbolInfo{$Version}{$InfoId}{"MnglName"} = $SymbolInfo{$Version}{$InfoId}{"ShortName"};
4249 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004250 }
4251 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04004252 if($LibInfo{$Version}{"info"}{$InfoId}=~/ lang:[ ]*C /i) {
4253 $SymbolInfo{$Version}{$InfoId}{"Lang"} = "C";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004254 }
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04004255 if($UserLang and $UserLang eq "C")
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004256 { # --lang=C option
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04004257 $SymbolInfo{$Version}{$InfoId}{"MnglName"} = $SymbolInfo{$Version}{$InfoId}{"ShortName"};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004258 }
4259 if($COMMON_LANGUAGE{$Version} eq "C++")
4260 { # correct mangled & short names
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04004261 # C++ or --headers-only mode
4262 if($SymbolInfo{$Version}{$InfoId}{"ShortName"}=~/\A__(comp|base|deleting)_(c|d)tor\Z/)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004263 { # support for old GCC versions: reconstruct real names for constructors and destructors
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04004264 $SymbolInfo{$Version}{$InfoId}{"ShortName"} = getNameByInfo(getTypeDeclId($SymbolInfo{$Version}{$InfoId}{"Class"}));
4265 $SymbolInfo{$Version}{$InfoId}{"ShortName"}=~s/<.+>\Z//;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004266 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04004267 if(not $SymbolInfo{$Version}{$InfoId}{"MnglName"})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004268 { # try to mangle symbol (link with libraries)
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04004269 if(my $Mangled = linkSymbol($InfoId)) {
4270 $SymbolInfo{$Version}{$InfoId}{"MnglName"} = $Mangled;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004271 }
4272 }
4273 if($OStarget eq "windows")
4274 { # link MS C++ symbols from library with GCC symbols from headers
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04004275 if(my $Mangled1 = $mangled_name{$Version}{modelUnmangled($InfoId, "MSVC")})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004276 { # exported symbols
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04004277 $SymbolInfo{$Version}{$InfoId}{"MnglName"} = $Mangled1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004278 }
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04004279 elsif(my $Mangled2 = mangle_symbol($InfoId, $Version, "MSVC"))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004280 { # pure virtual symbols
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04004281 $SymbolInfo{$Version}{$InfoId}{"MnglName"} = $Mangled2;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004282 }
4283 }
4284 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04004285 if(not $SymbolInfo{$Version}{$InfoId}{"MnglName"})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004286 { # can't detect symbol name
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04004287 delete($SymbolInfo{$Version}{$InfoId});
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004288 return;
4289 }
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04004290 if(not $SymbolInfo{$Version}{$InfoId}{"Constructor"}
4291 and my $Spec = getVirtSpec(getFuncOrig($InfoId)))
4292 { # identify virtual and pure virtual functions
4293 # NOTE: constructors cannot be virtual
4294 # NOTE: in GCC 4.7 D1 destructors have no virtual spec
4295 # in the TU dump, so taking it from the original symbol
4296 if(not ($SymbolInfo{$Version}{$InfoId}{"Destructor"}
4297 and $SymbolInfo{$Version}{$InfoId}{"MnglName"}=~/D2E/))
4298 { # NOTE: D2 destructors are not present in a v-table
4299 $SymbolInfo{$Version}{$InfoId}{$Spec} = 1;
4300 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004301 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04004302 if(isInline($InfoId)) {
4303 $SymbolInfo{$Version}{$InfoId}{"InLine"} = 1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004304 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04004305 if($SymbolInfo{$Version}{$InfoId}{"Constructor"}
4306 and my $ClassId = $SymbolInfo{$Version}{$InfoId}{"Class"})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004307 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04004308 if(not $SymbolInfo{$Version}{$InfoId}{"InLine"}
4309 and $LibInfo{$Version}{"info"}{$InfoId}!~/ artificial /i)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004310 { # inline or auto-generated constructor
4311 delete($TypeInfo{$Version}{$Tid_TDid{$Version}{$ClassId}}{$ClassId}{"Copied"});
4312 }
4313 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +04004314 if(my $Symbol = $SymbolInfo{$Version}{$InfoId}{"MnglName"})
4315 {
4316 if(not $SymbolInfo{$Version}{$InfoId}{"Virt"}
4317 and not $SymbolInfo{$Version}{$InfoId}{"PureVirt"})
4318 {
4319 if(not selectSymbol($Symbol, $SymbolInfo{$Version}{$InfoId}, "Dump", $Version))
4320 { # non-target symbols
4321 delete($SymbolInfo{$Version}{$InfoId});
4322 return;
4323 }
4324 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004325 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04004326 if($SymbolInfo{$Version}{$InfoId}{"Type"} eq "Method"
4327 or $SymbolInfo{$Version}{$InfoId}{"Constructor"}
4328 or $SymbolInfo{$Version}{$InfoId}{"Destructor"}
4329 or $SymbolInfo{$Version}{$InfoId}{"Class"})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004330 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04004331 if($SymbolInfo{$Version}{$InfoId}{"MnglName"}!~/\A(_Z|\?)/) {
4332 delete($SymbolInfo{$Version}{$InfoId});
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004333 return;
4334 }
4335 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04004336 if($SymbolInfo{$Version}{$InfoId}{"MnglName"})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004337 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04004338 if($MangledNames{$Version}{$SymbolInfo{$Version}{$InfoId}{"MnglName"}})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004339 { # one instance for one mangled name only
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04004340 delete($SymbolInfo{$Version}{$InfoId});
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004341 return;
4342 }
4343 else {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04004344 $MangledNames{$Version}{$SymbolInfo{$Version}{$InfoId}{"MnglName"}} = 1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004345 }
4346 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04004347 if($SymbolInfo{$Version}{$InfoId}{"Constructor"}
4348 or $SymbolInfo{$Version}{$InfoId}{"Destructor"}) {
4349 delete($SymbolInfo{$Version}{$InfoId}{"Return"});
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004350 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04004351 if($SymbolInfo{$Version}{$InfoId}{"MnglName"}=~/\A(_Z|\?)/
4352 and $SymbolInfo{$Version}{$InfoId}{"Class"})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004353 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04004354 if($SymbolInfo{$Version}{$InfoId}{"Type"} eq "Function")
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004355 { # static methods
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04004356 $SymbolInfo{$Version}{$InfoId}{"Static"} = 1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004357 }
4358 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04004359 if(getFuncLink($InfoId) eq "Static") {
4360 $SymbolInfo{$Version}{$InfoId}{"Static"} = 1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004361 }
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04004362 if($SymbolInfo{$Version}{$InfoId}{"MnglName"}=~/\A(_Z|\?)/)
4363 {
4364 if(my $Unmangled = $tr_name{$SymbolInfo{$Version}{$InfoId}{"MnglName"}})
4365 {
4366 if($Unmangled=~/\.\_\d/) {
4367 delete($SymbolInfo{$Version}{$InfoId});
4368 return;
4369 }
4370 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004371 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04004372 delete($SymbolInfo{$Version}{$InfoId}{"Type"});
4373 if($SymbolInfo{$Version}{$InfoId}{"MnglName"}=~/\A_ZN(V|)K/) {
4374 $SymbolInfo{$Version}{$InfoId}{"Const"} = 1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004375 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04004376 if($SymbolInfo{$Version}{$InfoId}{"MnglName"}=~/\A_ZN(K|)V/) {
4377 $SymbolInfo{$Version}{$InfoId}{"Volatile"} = 1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004378 }
4379}
4380
4381sub isInline($)
4382{ # "body: undefined" in the tree
4383 # -fkeep-inline-functions GCC option should be specified
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04004384 if($_[0] and my $Info = $LibInfo{$Version}{"info"}{$_[0]})
4385 {
4386 if($Info=~/ undefined /i) {
4387 return 0;
4388 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004389 }
4390 return 1;
4391}
4392
4393sub getTypeId($)
4394{
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04004395 if($_[0] and my $Info = $LibInfo{$Version}{"info"}{$_[0]})
4396 {
4397 if($Info=~/type[ ]*:[ ]*@(\d+) /) {
4398 return $1;
4399 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004400 }
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04004401 return "";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004402}
4403
4404sub setTypeMemb($$)
4405{
4406 my ($TypeId, $TypeAttr) = @_;
4407 my $TypeType = $TypeAttr->{"Type"};
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04004408 my ($Pos, $UnnamedPos) = (0, 0);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004409 if($TypeType eq "Enum")
4410 {
4411 my $TypeMembInfoId = getEnumMembInfoId($TypeId);
4412 while($TypeMembInfoId)
4413 {
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04004414 $TypeAttr->{"Memb"}{$Pos}{"value"} = getEnumMembVal($TypeMembInfoId);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004415 my $MembName = getEnumMembName($TypeMembInfoId);
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04004416 $TypeAttr->{"Memb"}{$Pos}{"name"} = getEnumMembName($TypeMembInfoId);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004417 $EnumMembName_Id{$Version}{getTreeAttr($TypeMembInfoId, "valu")} = ($TypeAttr->{"NameSpace"})?$TypeAttr->{"NameSpace"}."::".$MembName:$MembName;
4418 $TypeMembInfoId = getNextMembInfoId($TypeMembInfoId);
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04004419 $Pos += 1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004420 }
4421 }
4422 elsif($TypeType=~/\A(Struct|Class|Union)\Z/)
4423 {
4424 my $TypeMembInfoId = getStructMembInfoId($TypeId);
4425 while($TypeMembInfoId)
4426 {
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04004427 my $IType = $LibInfo{$Version}{"info_type"}{$TypeMembInfoId};
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04004428 my $MInfo = $LibInfo{$Version}{"info"}{$TypeMembInfoId};
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04004429 if(not $IType or $IType ne "field_decl")
4430 { # search for fields, skip other stuff in the declaration
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004431 $TypeMembInfoId = getNextStructMembInfoId($TypeMembInfoId);
4432 next;
4433 }
4434 my $StructMembName = getStructMembName($TypeMembInfoId);
4435 if($StructMembName=~/_vptr\./)
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04004436 { # virtual tables
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004437 $TypeMembInfoId = getNextStructMembInfoId($TypeMembInfoId);
4438 next;
4439 }
4440 if(not $StructMembName)
4441 { # unnamed fields
4442 if($TypeAttr->{"Name"}!~/_type_info_pseudo/)
4443 {
4444 my $UnnamedTid = getTreeAttr($TypeMembInfoId, "type");
4445 my $UnnamedTName = getNameByInfo(getTypeDeclId($UnnamedTid));
4446 if(isAnon($UnnamedTName))
4447 { # rename unnamed fields to unnamed0, unnamed1, ...
4448 $StructMembName = "unnamed".($UnnamedPos++);
4449 }
4450 }
4451 }
4452 if(not $StructMembName)
4453 { # unnamed fields and base classes
4454 $TypeMembInfoId = getNextStructMembInfoId($TypeMembInfoId);
4455 next;
4456 }
4457 my $MembTypeId = getTreeAttr($TypeMembInfoId, "type");
4458 if(my $AddedTid = $MissedTypedef{$Version}{$MembTypeId}{"Tid"}) {
4459 $MembTypeId = $AddedTid;
4460 }
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04004461 $TypeAttr->{"Memb"}{$Pos}{"type"} = $MembTypeId;
4462 $TypeAttr->{"Memb"}{$Pos}{"name"} = $StructMembName;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004463 if((my $Access = getTreeAccess($TypeMembInfoId)) ne "public")
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04004464 { # marked only protected and private, public by default
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04004465 $TypeAttr->{"Memb"}{$Pos}{"access"} = $Access;
4466 }
4467 if($MInfo=~/spec:\s*mutable /)
4468 { # mutable fields
4469 $TypeAttr->{"Memb"}{$Pos}{"mutable"} = 1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004470 }
4471 if(my $BFSize = getStructMembBitFieldSize($TypeMembInfoId)) {
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04004472 $TypeAttr->{"Memb"}{$Pos}{"bitfield"} = $BFSize;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004473 }
4474 else
4475 { # set alignment for non-bit fields
4476 # alignment for bitfields is always equal to 1 bit
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04004477 $TypeAttr->{"Memb"}{$Pos}{"algn"} = getAlgn($TypeMembInfoId)/$BYTE_SIZE;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004478 }
4479 $TypeMembInfoId = getNextStructMembInfoId($TypeMembInfoId);
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04004480 $Pos += 1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004481 }
4482 }
4483}
4484
4485sub setFuncParams($)
4486{
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04004487 my $InfoId = $_[0];
4488 my $ParamInfoId = getFuncParamInfoId($InfoId);
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04004489 if(getFuncType($InfoId) eq "Method")
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004490 { # check type of "this" pointer
4491 my $ObjectTypeId = getFuncParamType($ParamInfoId);
Andrey Ponomarenko85043792012-05-14 16:48:07 +04004492 if(my $ObjectName = get_TypeName($ObjectTypeId, $Version))
4493 {
4494 if($ObjectName=~/(\A|\W)const(| volatile)\*const(\W|\Z)/) {
4495 $SymbolInfo{$Version}{$InfoId}{"Const"} = 1;
4496 }
4497 if($ObjectName=~/(\A|\W)volatile(\W|\Z)/) {
4498 $SymbolInfo{$Version}{$InfoId}{"Volatile"} = 1;
4499 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004500 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +04004501 else
4502 { # skip
4503 return 1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004504 }
4505 $ParamInfoId = getNextElem($ParamInfoId);
4506 }
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04004507 my ($Pos, $Vtt_Pos) = (0, -1);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004508 while($ParamInfoId)
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04004509 { # formal args
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004510 my $ParamTypeId = getFuncParamType($ParamInfoId);
4511 my $ParamName = getFuncParamName($ParamInfoId);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004512 if(my $AddedTid = $MissedTypedef{$Version}{$ParamTypeId}{"Tid"}) {
4513 $ParamTypeId = $AddedTid;
4514 }
4515 my $PType = get_TypeAttr($ParamTypeId, $Version, "Type");
4516 if(not $PType or $PType eq "Unknown") {
4517 return 1;
4518 }
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04004519 my $PTName = get_TypeAttr($ParamTypeId, $Version, "Name");
4520 if(not $PTName) {
4521 return 1;
4522 }
4523 if($PTName eq "void") {
4524 last;
4525 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004526 if($ParamName eq "__vtt_parm"
4527 and get_TypeName($ParamTypeId, $Version) eq "void const**")
4528 {
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04004529 $Vtt_Pos = $Pos;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004530 $ParamInfoId = getNextElem($ParamInfoId);
4531 next;
4532 }
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04004533 $SymbolInfo{$Version}{$InfoId}{"Param"}{$Pos}{"type"} = $ParamTypeId;
4534 $SymbolInfo{$Version}{$InfoId}{"Param"}{$Pos}{"name"} = $ParamName;
4535 $SymbolInfo{$Version}{$InfoId}{"Param"}{$Pos}{"algn"} = getAlgn($ParamInfoId)/$BYTE_SIZE;
4536 if(not $SymbolInfo{$Version}{$InfoId}{"Param"}{$Pos}{"name"}) {
4537 $SymbolInfo{$Version}{$InfoId}{"Param"}{$Pos}{"name"} = "p".($Pos+1);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004538 }
4539 if($LibInfo{$Version}{"info"}{$ParamInfoId}=~/spec:\s*register /)
4540 { # foo(register type arg)
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04004541 $SymbolInfo{$Version}{$InfoId}{"Param"}{$Pos}{"reg"} = 1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004542 }
4543 $ParamInfoId = getNextElem($ParamInfoId);
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04004544 $Pos += 1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004545 }
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04004546 if(setFuncArgs($InfoId, $Vtt_Pos)) {
4547 $SymbolInfo{$Version}{$InfoId}{"Param"}{$Pos}{"type"} = -1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004548 }
4549 return 0;
4550}
4551
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04004552sub setFuncArgs($$)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004553{
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04004554 my ($InfoId, $Vtt_Pos) = @_;
4555 my $FuncTypeId = getFuncTypeId($InfoId);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004556 my $ParamListElemId = getTreeAttr($FuncTypeId, "prms");
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04004557 if(getFuncType($InfoId) eq "Method") {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004558 $ParamListElemId = getNextElem($ParamListElemId);
4559 }
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04004560 if(not $ParamListElemId)
4561 { # foo(...)
4562 return 1;
4563 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004564 my $HaveVoid = 0;
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04004565 my $Pos = 0;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004566 while($ParamListElemId)
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04004567 { # actual params: may differ from formal args
4568 # formal int*const
4569 # actual: int*
4570 if($Vtt_Pos!=-1 and $Pos==$Vtt_Pos)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004571 {
4572 $Vtt_Pos=-1;
4573 $ParamListElemId = getNextElem($ParamListElemId);
4574 next;
4575 }
4576 my $ParamTypeId = getTreeAttr($ParamListElemId, "valu");
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04004577 if(get_TypeName($ParamTypeId, $Version) eq "void")
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04004578 {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004579 $HaveVoid = 1;
4580 last;
4581 }
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04004582 elsif(not defined $SymbolInfo{$Version}{$InfoId}{"Param"}{$Pos}{"type"})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004583 {
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04004584 $SymbolInfo{$Version}{$InfoId}{"Param"}{$Pos}{"type"} = $ParamTypeId;
4585 if(not $SymbolInfo{$Version}{$InfoId}{"Param"}{$Pos}{"name"}) {
4586 $SymbolInfo{$Version}{$InfoId}{"Param"}{$Pos}{"name"} = "p".($Pos+1);
4587 }
4588 }
4589 if(my $PurpId = getTreeAttr($ParamListElemId, "purp"))
4590 { # default arguments
4591 if(my $PurpType = $LibInfo{$Version}{"info_type"}{$PurpId}) {
4592 $SymbolInfo{$Version}{$InfoId}{"Param"}{$Pos}{"default"} = getInitVal($PurpId, $ParamTypeId);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004593 }
4594 }
4595 $ParamListElemId = getNextElem($ParamListElemId);
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04004596 $Pos += 1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004597 }
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04004598 return ($Pos>=1 and not $HaveVoid);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004599}
4600
4601sub getTreeAttr($$)
4602{
4603 my $Attr = $_[1];
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04004604 if($_[0] and my $Info = $LibInfo{$Version}{"info"}{$_[0]})
4605 {
4606 if($Info=~/\Q$Attr\E\s*:\s*\@(\d+) /) {
4607 return $1;
4608 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004609 }
4610 return "";
4611}
4612
4613sub getTreeValue($)
4614{
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04004615 if($_[0] and my $Info = $LibInfo{$Version}{"info"}{$_[0]})
4616 {
4617 if($Info=~/low[ ]*:[ ]*([^ ]+) /) {
4618 return $1;
4619 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004620 }
4621 return "";
4622}
4623
4624sub getTreeAccess($)
4625{
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04004626 if($_[0] and my $Info = $LibInfo{$Version}{"info"}{$_[0]})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004627 {
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04004628 if($Info=~/accs[ ]*:[ ]*([a-zA-Z]+) /)
4629 {
4630 my $Access = $1;
4631 if($Access eq "prot") {
4632 return "protected";
4633 }
4634 elsif($Access eq "priv") {
4635 return "private";
4636 }
4637 }
4638 elsif($Info=~/ protected /)
4639 { # support for old GCC versions
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004640 return "protected";
4641 }
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04004642 elsif($Info=~/ private /)
4643 { # support for old GCC versions
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004644 return "private";
4645 }
4646 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004647 return "public";
4648}
4649
4650sub setFuncAccess($)
4651{
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04004652 my $Access = getTreeAccess($_[0]);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004653 if($Access eq "protected") {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04004654 $SymbolInfo{$Version}{$_[0]}{"Protected"} = 1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004655 }
4656 elsif($Access eq "private") {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04004657 $SymbolInfo{$Version}{$_[0]}{"Private"} = 1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004658 }
4659}
4660
4661sub setTypeAccess($$)
4662{
4663 my ($TypeId, $TypeAttr) = @_;
4664 my $Access = getTreeAccess($TypeId);
4665 if($Access eq "protected") {
4666 $TypeAttr->{"Protected"} = 1;
4667 }
4668 elsif($Access eq "private") {
4669 $TypeAttr->{"Private"} = 1;
4670 }
4671}
4672
4673sub setFuncKind($)
4674{
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04004675 if($_[0] and my $Info = $LibInfo{$Version}{"info"}{$_[0]})
4676 {
4677 if($Info=~/pseudo tmpl/) {
4678 $SymbolInfo{$Version}{$_[0]}{"PseudoTemplate"} = 1;
4679 }
4680 elsif($Info=~/ constructor /) {
4681 $SymbolInfo{$Version}{$_[0]}{"Constructor"} = 1;
4682 }
4683 elsif($Info=~/ destructor /) {
4684 $SymbolInfo{$Version}{$_[0]}{"Destructor"} = 1;
4685 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004686 }
4687}
4688
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04004689sub getVirtSpec($)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004690{
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04004691 if($_[0] and my $Info = $LibInfo{$Version}{"info"}{$_[0]})
4692 {
4693 if($Info=~/spec[ ]*:[ ]*pure /) {
4694 return "PureVirt";
4695 }
4696 elsif($Info=~/spec[ ]*:[ ]*virt /) {
4697 return "Virt";
4698 }
4699 elsif($Info=~/ pure\s+virtual /)
4700 { # support for old GCC versions
4701 return "PureVirt";
4702 }
4703 elsif($Info=~/ virtual /)
4704 { # support for old GCC versions
4705 return "Virt";
4706 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004707 }
4708 return "";
4709}
4710
4711sub getFuncClass($)
4712{
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04004713 if($_[0] and my $Info = $LibInfo{$Version}{"info"}{$_[0]})
4714 {
4715 if($Info=~/scpe[ ]*:[ ]*@(\d+) /) {
4716 return $1;
4717 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004718 }
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04004719 return "";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004720}
4721
4722sub getFuncLink($)
4723{
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04004724 if($_[0] and my $Info = $LibInfo{$Version}{"info"}{$_[0]})
4725 {
4726 if($Info=~/link[ ]*:[ ]*static /) {
4727 return "Static";
4728 }
4729 elsif($Info=~/link[ ]*:[ ]*([a-zA-Z]+) /) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004730 return $1;
4731 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004732 }
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04004733 return "";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004734}
4735
4736sub getNextElem($)
4737{
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04004738 if($_[0] and my $Info = $LibInfo{$Version}{"info"}{$_[0]})
4739 {
4740 if($Info=~/(chan|chain)[ ]*:[ ]*@(\d+) /) {
4741 return $2;
4742 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004743 }
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04004744 return "";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004745}
4746
4747sub getFuncParamInfoId($)
4748{
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04004749 if($_[0] and my $Info = $LibInfo{$Version}{"info"}{$_[0]})
4750 {
4751 if($Info=~/args[ ]*:[ ]*@(\d+) /) {
4752 return $1;
4753 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004754 }
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04004755 return "";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004756}
4757
4758sub getFuncParamType($)
4759{
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04004760 if($_[0] and my $Info = $LibInfo{$Version}{"info"}{$_[0]})
4761 {
4762 if($Info=~/type[ ]*:[ ]*@(\d+) /) {
4763 return $1;
4764 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004765 }
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04004766 return "";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004767}
4768
4769sub getFuncParamName($)
4770{
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04004771 if($_[0] and my $Info = $LibInfo{$Version}{"info"}{$_[0]})
4772 {
4773 if($Info=~/name[ ]*:[ ]*@(\d+) /) {
4774 return getTreeStr($1);
4775 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004776 }
4777 return "";
4778}
4779
4780sub getEnumMembInfoId($)
4781{
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04004782 if($_[0] and my $Info = $LibInfo{$Version}{"info"}{$_[0]})
4783 {
4784 if($Info=~/csts[ ]*:[ ]*@(\d+) /) {
4785 return $1;
4786 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004787 }
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04004788 return "";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004789}
4790
4791sub getStructMembInfoId($)
4792{
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04004793 if($_[0] and my $Info = $LibInfo{$Version}{"info"}{$_[0]})
4794 {
4795 if($Info=~/flds[ ]*:[ ]*@(\d+) /) {
4796 return $1;
4797 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004798 }
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04004799 return "";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004800}
4801
4802sub get_IntNameSpace($$)
4803{
4804 my ($Interface, $LibVersion) = @_;
4805 return "" if(not $Interface or not $LibVersion);
4806 if(defined $Cache{"get_IntNameSpace"}{$Interface}{$LibVersion}) {
4807 return $Cache{"get_IntNameSpace"}{$Interface}{$LibVersion};
4808 }
4809 my $Signature = get_Signature($Interface, $LibVersion);
4810 if($Signature=~/\:\:/)
4811 {
4812 my $FounNameSpace = 0;
4813 foreach my $NameSpace (sort {get_depth($b)<=>get_depth($a)} keys(%{$NestedNameSpaces{$LibVersion}}))
4814 {
4815 if($Signature=~/(\A|\s+for\s+)\Q$NameSpace\E\:\:/) {
4816 return ($Cache{"get_IntNameSpace"}{$Interface}{$LibVersion} = $NameSpace);
4817 }
4818 }
4819 }
4820 else {
4821 return ($Cache{"get_IntNameSpace"}{$Interface}{$LibVersion} = "");
4822 }
4823}
4824
4825sub parse_TypeNameSpace($$)
4826{
4827 my ($TypeName, $LibVersion) = @_;
4828 return "" if(not $TypeName or not $LibVersion);
4829 if(defined $Cache{"parse_TypeNameSpace"}{$TypeName}{$LibVersion}) {
4830 return $Cache{"parse_TypeNameSpace"}{$TypeName}{$LibVersion};
4831 }
4832 if($TypeName=~/\:\:/)
4833 {
4834 my $FounNameSpace = 0;
4835 foreach my $NameSpace (sort {get_depth($b)<=>get_depth($a)} keys(%{$NestedNameSpaces{$LibVersion}}))
4836 {
4837 if($TypeName=~/\A\Q$NameSpace\E\:\:/) {
4838 return ($Cache{"parse_TypeNameSpace"}{$TypeName}{$LibVersion} = $NameSpace);
4839 }
4840 }
4841 }
4842 else {
4843 return ($Cache{"parse_TypeNameSpace"}{$TypeName}{$LibVersion} = "");
4844 }
4845}
4846
4847sub getNameSpace($)
4848{
4849 my $TypeInfoId = $_[0];
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04004850 my $NSInfoId = getTreeAttr($TypeInfoId, "scpe");
4851 return "" if(not $NSInfoId);
4852 if(my $InfoType = $LibInfo{$Version}{"info_type"}{$NSInfoId})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004853 {
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04004854 if($InfoType eq "namespace_decl")
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004855 {
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04004856 if($LibInfo{$Version}{"info"}{$NSInfoId}=~/name[ ]*:[ ]*@(\d+) /)
4857 {
4858 my $NameSpace = getTreeStr($1);
4859 return "" if($NameSpace eq "::");
4860 if(my $BaseNameSpace = getNameSpace($NSInfoId)) {
4861 $NameSpace = $BaseNameSpace."::".$NameSpace;
4862 }
4863 $NestedNameSpaces{$Version}{$NameSpace} = 1;
4864 return $NameSpace;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004865 }
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04004866 else {
4867 return "";
4868 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004869 }
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04004870 elsif($InfoType eq "record_type")
4871 { # inside data type
4872 my ($Name, $NameNS) = getTrivialName(getTypeDeclId($NSInfoId), $NSInfoId);
4873 return $Name;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004874 }
4875 }
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04004876 return "";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004877}
4878
4879sub getNameSpaceId($)
4880{
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04004881 if($_[0] and my $Info = $LibInfo{$Version}{"info"}{$_[0]})
4882 {
4883 if($Info=~/scpe[ ]*:[ ]*\@(\d+)/) {
4884 return $1;
4885 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004886 }
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04004887 return "";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004888}
4889
4890sub getEnumMembName($)
4891{
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04004892 if($_[0] and my $Info = $LibInfo{$Version}{"info"}{$_[0]})
4893 {
4894 if($Info=~/purp[ ]*:[ ]*\@(\d+)/) {
4895 return getTreeStr($1);
4896 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004897 }
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04004898 return "";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004899}
4900
4901sub getStructMembName($)
4902{
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04004903 if($_[0] and my $Info = $LibInfo{$Version}{"info"}{$_[0]})
4904 {
4905 if($Info=~/name[ ]*:[ ]*\@(\d+)/) {
4906 return getTreeStr($1);
4907 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004908 }
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04004909 return "";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004910}
4911
4912sub getEnumMembVal($)
4913{
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04004914 if($_[0] and my $Info = $LibInfo{$Version}{"info"}{$_[0]})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004915 {
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04004916 if($Info=~/valu[ ]*:[ ]*\@(\d+)/)
4917 {
4918 if(my $VInfo = $LibInfo{$Version}{"info"}{$1})
4919 {
4920 if($VInfo=~/cnst[ ]*:[ ]*\@(\d+)/)
4921 { # in newer versions of GCC the value is in the "const_decl->cnst" node
4922 return getTreeValue($1);
4923 }
4924 else
4925 { # some old versions of GCC (3.3) have the value in the "integer_cst" node
4926 return getTreeValue($1);
4927 }
4928 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004929 }
4930 }
4931 return "";
4932}
4933
4934sub getSize($)
4935{
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04004936 if($_[0] and my $Info = $LibInfo{$Version}{"info"}{$_[0]})
4937 {
4938 if($Info=~/size[ ]*:[ ]*\@(\d+)/) {
4939 return getTreeValue($1);
4940 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004941 }
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04004942 return 0;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004943}
4944
4945sub getAlgn($)
4946{
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04004947 if($_[0] and my $Info = $LibInfo{$Version}{"info"}{$_[0]})
4948 {
4949 if($Info=~/algn[ ]*:[ ]*(\d+) /) {
4950 return $1;
4951 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004952 }
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04004953 return "";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004954}
4955
4956sub getStructMembBitFieldSize($)
4957{
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04004958 if($_[0] and my $Info = $LibInfo{$Version}{"info"}{$_[0]})
4959 {
4960 if($Info=~/ bitfield /) {
4961 return getSize($_[0]);
4962 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004963 }
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04004964 return 0;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004965}
4966
4967sub getNextMembInfoId($)
4968{
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04004969 if($_[0] and my $Info = $LibInfo{$Version}{"info"}{$_[0]})
4970 {
4971 if($Info=~/(chan|chain)[ ]*:[ ]*@(\d+) /) {
4972 return $2;
4973 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004974 }
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04004975 return "";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004976}
4977
4978sub getNextStructMembInfoId($)
4979{
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04004980 if($_[0] and my $Info = $LibInfo{$Version}{"info"}{$_[0]})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004981 {
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04004982 if($Info=~/(chan|chain)[ ]*:[ ]*@(\d+) /) {
4983 return $2;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004984 }
4985 }
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04004986 return "";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004987}
4988
4989sub register_header($$)
4990{ # input: header absolute path, relative path or name
4991 my ($Header, $LibVersion) = @_;
4992 return "" if(not $Header);
4993 if(is_abs($Header) and not -f $Header) {
4994 exitStatus("Access_Error", "can't access \'$Header\'");
4995 }
4996 return "" if(skip_header($Header, $LibVersion));
4997 my $Header_Path = identify_header($Header, $LibVersion);
4998 return "" if(not $Header_Path);
4999 detect_header_includes($Header_Path, $LibVersion);
5000 if(my $RHeader_Path = $Header_ErrorRedirect{$LibVersion}{$Header_Path})
5001 {
5002 return "" if(skip_header($RHeader_Path, $LibVersion));
5003 $Header_Path = $RHeader_Path;
5004 return "" if($Registered_Headers{$LibVersion}{$Header_Path}{"Identity"});
5005 }
5006 elsif($Header_ShouldNotBeUsed{$LibVersion}{$Header_Path}) {
5007 return "";
5008 }
5009 $Registered_Headers{$LibVersion}{$Header_Path}{"Identity"} = get_filename($Header_Path);
5010 $HeaderName_Paths{$LibVersion}{get_filename($Header_Path)}{$Header_Path} = 1;
5011 if(($Header=~/\.(\w+)\Z/ and $1 ne "h")
5012 or $Header!~/\.(\w+)\Z/)
5013 { # hpp, hh
5014 setLanguage($LibVersion, "C++");
5015 }
5016 if($CheckHeadersOnly
5017 and $Header=~/(\A|\/)c\+\+(\/|\Z)/)
5018 { # /usr/include/c++/4.6.1/...
5019 $STDCXX_TESTING = 1;
5020 }
5021 return $Header_Path;
5022}
5023
5024sub register_directory($$$)
5025{
5026 my ($Dir, $WithDeps, $LibVersion) = @_;
5027 $Dir=~s/[\/\\]+\Z//g;
5028 return if(not $LibVersion or not $Dir or not -d $Dir);
5029 return if(skip_header($Dir, $LibVersion));
5030 $Dir = get_abs_path($Dir);
5031 my $Mode = "All";
Andrey Ponomarenko85043792012-05-14 16:48:07 +04005032 if($WithDeps)
5033 {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005034 if($RegisteredDirs{$LibVersion}{$Dir}{1}) {
5035 return;
5036 }
5037 elsif($RegisteredDirs{$LibVersion}{$Dir}{0}) {
5038 $Mode = "DepsOnly";
5039 }
5040 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +04005041 else
5042 {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005043 if($RegisteredDirs{$LibVersion}{$Dir}{1}
5044 or $RegisteredDirs{$LibVersion}{$Dir}{0}) {
5045 return;
5046 }
5047 }
5048 $Header_Dependency{$LibVersion}{$Dir} = 1;
5049 $RegisteredDirs{$LibVersion}{$Dir}{$WithDeps} = 1;
5050 if($Mode eq "DepsOnly")
5051 {
5052 foreach my $Path (cmd_find($Dir,"d","","")) {
5053 $Header_Dependency{$LibVersion}{$Path} = 1;
5054 }
5055 return;
5056 }
5057 foreach my $Path (sort {length($b)<=>length($a)} cmd_find($Dir,"f","",""))
5058 {
5059 if($WithDeps)
5060 {
5061 my $SubDir = $Path;
5062 while(($SubDir = get_dirname($SubDir)) ne $Dir)
5063 { # register all sub directories
5064 $Header_Dependency{$LibVersion}{$SubDir} = 1;
5065 }
5066 }
5067 next if(is_not_header($Path));
5068 next if(ignore_path($Path));
5069 next if(skip_header($Path, $LibVersion));
5070 # Neighbors
5071 foreach my $Part (get_path_prefixes($Path)) {
5072 $Include_Neighbors{$LibVersion}{$Part} = $Path;
5073 }
5074 }
5075 if(get_filename($Dir) eq "include")
5076 { # search for "lib/include/" directory
5077 my $LibDir = $Dir;
5078 if($LibDir=~s/([\/\\])include\Z/$1lib/g and -d $LibDir) {
5079 register_directory($LibDir, $WithDeps, $LibVersion);
5080 }
5081 }
5082}
5083
5084sub parse_redirect($$$)
5085{
5086 my ($Content, $Path, $LibVersion) = @_;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005087 my @Errors = ();
5088 while($Content=~s/#\s*error\s+([^\n]+?)\s*(\n|\Z)//) {
5089 push(@Errors, $1);
5090 }
5091 my $Redirect = "";
5092 foreach (@Errors)
5093 {
5094 s/\s{2,}/ /g;
5095 if(/(only|must\ include
5096 |update\ to\ include
5097 |replaced\ with
5098 |replaced\ by|renamed\ to
5099 |is\ in|use)\ (<[^<>]+>|[\w\-\/\\]+\.($HEADER_EXT))/ix)
5100 {
5101 $Redirect = $2;
5102 last;
5103 }
5104 elsif(/(include|use|is\ in)\ (<[^<>]+>|[\w\-\/\\]+\.($HEADER_EXT))\ instead/i)
5105 {
5106 $Redirect = $2;
5107 last;
5108 }
5109 elsif(/this\ header\ should\ not\ be\ used
5110 |programs\ should\ not\ directly\ include
5111 |you\ should\ not\ (include|be\ (including|using)\ this\ (file|header))
5112 |is\ not\ supported\ API\ for\ general\ use
5113 |do\ not\ use
5114 |should\ not\ be\ used
5115 |cannot\ be\ included\ directly/ix and not /\ from\ /i) {
5116 $Header_ShouldNotBeUsed{$LibVersion}{$Path} = 1;
5117 }
5118 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +04005119 if($Redirect)
5120 {
5121 $Redirect=~s/\A<//g;
5122 $Redirect=~s/>\Z//g;
5123 }
5124 return $Redirect;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005125}
5126
5127sub parse_includes($$)
5128{
5129 my ($Content, $Path) = @_;
5130 my %Includes = ();
5131 while($Content=~s/#([ \t]*)(include|include_next|import)([ \t]*)(<|")([^<>"]+)(>|")//)
Andrey Ponomarenko85043792012-05-14 16:48:07 +04005132 { # C/C++: include, Objective C/C++: import directive
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005133 my ($Header, $Method) = ($5, $4);
5134 $Header = path_format($Header, $OSgroup);
Andrey Ponomarenko85043792012-05-14 16:48:07 +04005135 if($Method eq "\"" or is_abs($Header))
5136 {
5137 if(-e joinPath(get_dirname($Path), $Header))
5138 { # relative path exists
5139 $Includes{$Header} = -1;
5140 }
5141 else
5142 { # include "..." that doesn't exist is equal to include <...>
5143 $Includes{$Header} = 2;
5144 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005145 }
5146 else {
5147 $Includes{$Header} = 1;
5148 }
5149 }
5150 return \%Includes;
5151}
5152
5153sub ignore_path($)
5154{
5155 my $Path = $_[0];
5156 if($Path=~/\~\Z/)
5157 {# skipping system backup files
5158 return 1;
5159 }
5160 if($Path=~/(\A|[\/\\]+)(\.(svn|git|bzr|hg)|CVS)([\/\\]+|\Z)/)
5161 {# skipping hidden .svn, .git, .bzr, .hg and CVS directories
5162 return 1;
5163 }
5164 return 0;
5165}
5166
5167sub sort_by_word($$)
5168{
5169 my ($ArrRef, $W) = @_;
5170 return if(length($W)<2);
5171 @{$ArrRef} = sort {get_filename($b)=~/\Q$W\E/i<=>get_filename($a)=~/\Q$W\E/i} @{$ArrRef};
5172}
5173
5174sub natural_sorting($$)
5175{
5176 my ($H1, $H2) = @_;
5177 $H1=~s/\.[a-z]+\Z//ig;
5178 $H2=~s/\.[a-z]+\Z//ig;
5179 my ($HDir1, $Hname1) = separate_path($H1);
5180 my ($HDir2, $Hname2) = separate_path($H2);
5181 my $Dirname1 = get_filename($HDir1);
5182 my $Dirname2 = get_filename($HDir2);
5183 if($H1 eq $H2) {
5184 return 0;
5185 }
5186 elsif($H1=~/\A\Q$H2\E/) {
5187 return 1;
5188 }
5189 elsif($H2=~/\A\Q$H1\E/) {
5190 return -1;
5191 }
5192 elsif($HDir1=~/\Q$Hname1\E/i
5193 and $HDir2!~/\Q$Hname2\E/i)
5194 {# include/glib-2.0/glib.h
5195 return -1;
5196 }
5197 elsif($HDir2=~/\Q$Hname2\E/i
5198 and $HDir1!~/\Q$Hname1\E/i)
5199 {# include/glib-2.0/glib.h
5200 return 1;
5201 }
5202 elsif($Hname1=~/\Q$Dirname1\E/i
5203 and $Hname2!~/\Q$Dirname2\E/i)
5204 {# include/hildon-thumbnail/hildon-thumbnail-factory.h
5205 return -1;
5206 }
5207 elsif($Hname2=~/\Q$Dirname2\E/i
5208 and $Hname1!~/\Q$Dirname1\E/i)
5209 {# include/hildon-thumbnail/hildon-thumbnail-factory.h
5210 return 1;
5211 }
5212 elsif($Hname1=~/(config|lib)/i
5213 and $Hname2!~/(config|lib)/i)
5214 {# include/alsa/asoundlib.h
5215 return -1;
5216 }
5217 elsif($Hname2=~/(config|lib)/i
5218 and $Hname1!~/(config|lib)/i)
5219 {# include/alsa/asoundlib.h
5220 return 1;
5221 }
5222 elsif(checkRelevance($H1)
5223 and not checkRelevance($H2))
5224 {# libebook/e-book.h
5225 return -1;
5226 }
5227 elsif(checkRelevance($H2)
5228 and not checkRelevance($H1))
5229 {# libebook/e-book.h
5230 return 1;
5231 }
5232 else {
5233 return (lc($H1) cmp lc($H2));
5234 }
5235}
5236
5237sub searchForHeaders($)
5238{
5239 my $LibVersion = $_[0];
5240 # gcc standard include paths
5241 find_gcc_cxx_headers($LibVersion);
5242 # processing header paths
5243 foreach my $Path (keys(%{$Descriptor{$LibVersion}{"IncludePaths"}}),
5244 keys(%{$Descriptor{$LibVersion}{"AddIncludePaths"}}))
5245 {
5246 my $IPath = $Path;
5247 if(not -e $Path) {
5248 exitStatus("Access_Error", "can't access \'$Path\'");
5249 }
5250 elsif(-f $Path) {
5251 exitStatus("Access_Error", "\'$Path\' - not a directory");
5252 }
5253 elsif(-d $Path)
5254 {
5255 $Path = get_abs_path($Path);
5256 register_directory($Path, 0, $LibVersion);
5257 if($Descriptor{$LibVersion}{"AddIncludePaths"}{$IPath}) {
5258 $Add_Include_Paths{$LibVersion}{$Path} = 1;
5259 }
5260 else {
5261 $Include_Paths{$LibVersion}{$Path} = 1;
5262 }
5263 }
5264 }
5265 if(keys(%{$Include_Paths{$LibVersion}})) {
5266 $INC_PATH_AUTODETECT{$LibVersion} = 0;
5267 }
5268 # registering directories
5269 foreach my $Path (split(/\s*\n\s*/, $Descriptor{$LibVersion}{"Headers"}))
5270 {
5271 next if(not -e $Path);
5272 $Path = get_abs_path($Path);
5273 $Path = path_format($Path, $OSgroup);
5274 if(-d $Path) {
5275 register_directory($Path, 1, $LibVersion);
5276 }
5277 elsif(-f $Path)
5278 {
5279 my $Dir = get_dirname($Path);
5280 if(not $SystemPaths{"include"}{$Dir}
5281 and not $LocalIncludes{$Dir})
5282 {
5283 register_directory($Dir, 1, $LibVersion);
5284 if(my $OutDir = get_dirname($Dir))
5285 { # registering the outer directory
5286 if(not $SystemPaths{"include"}{$OutDir}
5287 and not $LocalIncludes{$OutDir}) {
5288 register_directory($OutDir, 0, $LibVersion);
5289 }
5290 }
5291 }
5292 }
5293 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +04005294
5295 # clean memory
5296 %RegisteredDirs = ();
5297
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005298 # registering headers
5299 my $Position = 0;
5300 foreach my $Dest (split(/\s*\n\s*/, $Descriptor{$LibVersion}{"Headers"}))
5301 {
5302 if(is_abs($Dest) and not -e $Dest) {
5303 exitStatus("Access_Error", "can't access \'$Dest\'");
5304 }
5305 $Dest = path_format($Dest, $OSgroup);
5306 if(is_header($Dest, 1, $LibVersion))
5307 {
5308 if(my $HPath = register_header($Dest, $LibVersion)) {
5309 $Registered_Headers{$LibVersion}{$HPath}{"Pos"} = $Position++;
5310 }
5311 }
5312 elsif(-d $Dest)
5313 {
5314 my @Registered = ();
5315 foreach my $Path (cmd_find($Dest,"f","",""))
5316 {
5317 next if(ignore_path($Path));
5318 next if(not is_header($Path, 0, $LibVersion));
5319 if(my $HPath = register_header($Path, $LibVersion)) {
5320 push(@Registered, $HPath);
5321 }
5322 }
5323 @Registered = sort {natural_sorting($a, $b)} @Registered;
5324 sort_by_word(\@Registered, $TargetLibraryShortName);
5325 foreach my $Path (@Registered) {
5326 $Registered_Headers{$LibVersion}{$Path}{"Pos"} = $Position++;
5327 }
5328 }
5329 else {
5330 exitStatus("Access_Error", "can't identify \'$Dest\' as a header file");
5331 }
5332 }
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04005333 if(my $HList = $Descriptor{$LibVersion}{"IncludePreamble"})
5334 { # preparing preamble headers
5335 my $PPos=0;
5336 foreach my $Header (split(/\s*\n\s*/, $HList))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005337 {
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04005338 if(is_abs($Header) and not -f $Header) {
5339 exitStatus("Access_Error", "can't access file \'$Header\'");
5340 }
5341 $Header = path_format($Header, $OSgroup);
5342 if(my $Header_Path = is_header($Header, 1, $LibVersion))
5343 {
5344 next if(skip_header($Header_Path, $LibVersion));
5345 $Include_Preamble{$LibVersion}{$Header_Path}{"Position"} = $PPos++;
5346 }
5347 else {
5348 exitStatus("Access_Error", "can't identify \'$Header\' as a header file");
5349 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005350 }
5351 }
5352 foreach my $Header_Name (keys(%{$HeaderName_Paths{$LibVersion}}))
5353 { # set relative paths (for duplicates)
5354 if(keys(%{$HeaderName_Paths{$LibVersion}{$Header_Name}})>=2)
5355 { # search for duplicates
5356 my $FirstPath = (keys(%{$HeaderName_Paths{$LibVersion}{$Header_Name}}))[0];
5357 my $Prefix = get_dirname($FirstPath);
5358 while($Prefix=~/\A(.+)[\/\\]+[^\/\\]+\Z/)
5359 { # detect a shortest distinguishing prefix
5360 my $NewPrefix = $1;
5361 my %Identity = ();
5362 foreach my $Path (keys(%{$HeaderName_Paths{$LibVersion}{$Header_Name}}))
5363 {
5364 if($Path=~/\A\Q$Prefix\E[\/\\]+(.*)\Z/) {
5365 $Identity{$Path} = $1;
5366 }
5367 }
5368 if(keys(%Identity)==keys(%{$HeaderName_Paths{$LibVersion}{$Header_Name}}))
5369 { # all names are differend with current prefix
5370 foreach my $Path (keys(%{$HeaderName_Paths{$LibVersion}{$Header_Name}})) {
5371 $Registered_Headers{$LibVersion}{$Path}{"Identity"} = $Identity{$Path};
5372 }
5373 last;
5374 }
5375 $Prefix = $NewPrefix; # increase prefix
5376 }
5377 }
5378 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +04005379
5380 # clean memory
5381 %HeaderName_Paths = ();
5382
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005383 foreach my $HeaderName (keys(%{$Include_Order{$LibVersion}}))
5384 { # ordering headers according to descriptor
5385 my $PairName=$Include_Order{$LibVersion}{$HeaderName};
5386 my ($Pos, $PairPos) = (-1, -1);
5387 my ($Path, $PairPath) = ();
5388 my @Paths = keys(%{$Registered_Headers{$LibVersion}});
5389 @Paths = sort {int($Registered_Headers{$LibVersion}{$a}{"Pos"})<=>int($Registered_Headers{$LibVersion}{$b}{"Pos"})} @Paths;
5390 foreach my $Header_Path (@Paths)
5391 {
5392 if(get_filename($Header_Path) eq $PairName)
5393 {
5394 $PairPos = $Registered_Headers{$LibVersion}{$Header_Path}{"Pos"};
5395 $PairPath = $Header_Path;
5396 }
5397 if(get_filename($Header_Path) eq $HeaderName)
5398 {
5399 $Pos = $Registered_Headers{$LibVersion}{$Header_Path}{"Pos"};
5400 $Path = $Header_Path;
5401 }
5402 }
5403 if($PairPos!=-1 and $Pos!=-1
5404 and int($PairPos)<int($Pos))
5405 {
5406 my %Tmp = %{$Registered_Headers{$LibVersion}{$Path}};
5407 %{$Registered_Headers{$LibVersion}{$Path}} = %{$Registered_Headers{$LibVersion}{$PairPath}};
5408 %{$Registered_Headers{$LibVersion}{$PairPath}} = %Tmp;
5409 }
5410 }
5411 if(not keys(%{$Registered_Headers{$LibVersion}})) {
5412 exitStatus("Error", "header files are not found in the ".$Descriptor{$LibVersion}{"Version"});
5413 }
5414}
5415
5416sub detect_real_includes($$)
5417{
5418 my ($AbsPath, $LibVersion) = @_;
5419 return () if(not $LibVersion or not $AbsPath or not -e $AbsPath);
5420 if($Cache{"detect_real_includes"}{$LibVersion}{$AbsPath}
5421 or keys(%{$RecursiveIncludes{$LibVersion}{$AbsPath}})) {
5422 return keys(%{$RecursiveIncludes{$LibVersion}{$AbsPath}});
5423 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +04005424 $Cache{"detect_real_includes"}{$LibVersion}{$AbsPath}=1;
5425
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005426 my $Path = callPreprocessor($AbsPath, "", $LibVersion);
5427 return () if(not $Path);
5428 open(PREPROC, $Path);
5429 while(<PREPROC>)
5430 {
5431 if(/#\s+\d+\s+"([^"]+)"[\s\d]*\n/)
5432 {
5433 my $Include = path_format($1, $OSgroup);
5434 if($Include=~/\<(built\-in|internal|command(\-|\s)line)\>|\A\./) {
5435 next;
5436 }
5437 if($Include eq $AbsPath) {
5438 next;
5439 }
5440 $RecursiveIncludes{$LibVersion}{$AbsPath}{$Include} = 1;
5441 }
5442 }
5443 close(PREPROC);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005444 return keys(%{$RecursiveIncludes{$LibVersion}{$AbsPath}});
5445}
5446
5447sub detect_header_includes($$)
5448{
5449 my ($Path, $LibVersion) = @_;
Andrey Ponomarenko85043792012-05-14 16:48:07 +04005450 return if(not $LibVersion or not $Path);
5451 if(defined $Cache{"detect_header_includes"}{$LibVersion}{$Path}) {
5452 return;
5453 }
5454 $Cache{"detect_header_includes"}{$LibVersion}{$Path}=1;
5455
5456 if(not -e $Path) {
5457 return;
5458 }
5459
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005460 my $Content = readFile($Path);
Andrey Ponomarenko85043792012-05-14 16:48:07 +04005461 if(my $Redirect = parse_redirect($Content, $Path, $LibVersion))
5462 { # detect error directive in headers
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005463 if(my $RedirectPath = identify_header($Redirect, $LibVersion))
5464 {
5465 if($RedirectPath=~/\/usr\/include\// and $Path!~/\/usr\/include\//) {
5466 $RedirectPath = identify_header(get_filename($Redirect), $LibVersion);
5467 }
5468 if($RedirectPath ne $Path) {
5469 $Header_ErrorRedirect{$LibVersion}{$Path} = $RedirectPath;
5470 }
5471 }
5472 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +04005473 if(my $Inc = parse_includes($Content, $Path))
5474 {
5475 foreach my $Include (keys(%{$Inc}))
5476 { # detect includes
5477 #if(is_not_header($Include))
5478 #{ #include<*.c> and others
5479 # next;
5480 #}
5481 $Header_Includes{$LibVersion}{$Path}{$Include} = $Inc->{$Include};
5482 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005483 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005484}
5485
5486sub simplify_path($)
5487{
5488 my $Path = $_[0];
5489 while($Path=~s&([\/\\])[^\/\\]+[\/\\]\.\.[\/\\]&$1&){};
5490 return $Path;
5491}
5492
5493sub fromLibc($)
5494{ # GLIBC header
5495 my $Path = $_[0];
5496 my ($Dir, $Name) = separate_path($Path);
5497 if(get_filename($Dir)=~/\A(include|libc)\Z/ and $GlibcHeader{$Name})
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04005498 { # /usr/include/{stdio, ...}.h
5499 # epoc32/include/libc/{stdio, ...}.h
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005500 return 1;
5501 }
5502 if(isLibcDir($Dir)) {
5503 return 1;
5504 }
5505 return 0;
5506}
5507
5508sub isLibcDir($)
5509{ # GLIBC directory
5510 my $Dir = $_[0];
5511 my ($OutDir, $Name) = separate_path($Dir);
5512 if(get_filename($OutDir)=~/\A(include|libc)\Z/
5513 and ($Name=~/\Aasm(|-.+)\Z/ or $GlibcDir{$Name}))
5514 { # /usr/include/{sys,bits,asm,asm-*}/*.h
5515 return 1;
5516 }
5517 return 0;
5518}
5519
5520sub detect_recursive_includes($$)
5521{
5522 my ($AbsPath, $LibVersion) = @_;
5523 return () if(not $AbsPath);
5524 if(isCyclical(\@RecurInclude, $AbsPath)) {
5525 return keys(%{$RecursiveIncludes{$LibVersion}{$AbsPath}});
5526 }
5527 my ($AbsDir, $Name) = separate_path($AbsPath);
5528 if(isLibcDir($AbsDir))
5529 { # GLIBC internals
5530 return ();
5531 }
5532 if(keys(%{$RecursiveIncludes{$LibVersion}{$AbsPath}})) {
5533 return keys(%{$RecursiveIncludes{$LibVersion}{$AbsPath}});
5534 }
5535 return () if($OSgroup ne "windows" and $Name=~/windows|win32|win64/i);
5536 return () if($MAIN_CPP_DIR and $AbsPath=~/\A\Q$MAIN_CPP_DIR\E/ and not $STDCXX_TESTING);
5537 push(@RecurInclude, $AbsPath);
5538 if($DefaultGccPaths{$AbsDir}
5539 or fromLibc($AbsPath))
5540 { # check "real" (non-"model") include paths
5541 my @Paths = detect_real_includes($AbsPath, $LibVersion);
5542 pop(@RecurInclude);
5543 return @Paths;
5544 }
5545 if(not keys(%{$Header_Includes{$LibVersion}{$AbsPath}})) {
5546 detect_header_includes($AbsPath, $LibVersion);
5547 }
5548 foreach my $Include (keys(%{$Header_Includes{$LibVersion}{$AbsPath}}))
5549 {
Andrey Ponomarenko85043792012-05-14 16:48:07 +04005550 my $IncType = $Header_Includes{$LibVersion}{$AbsPath}{$Include};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005551 my $HPath = "";
Andrey Ponomarenko85043792012-05-14 16:48:07 +04005552 if($IncType<0)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005553 { # for #include "..."
5554 my $Candidate = joinPath($AbsDir, $Include);
5555 if(-f $Candidate) {
5556 $HPath = simplify_path($Candidate);
5557 }
5558 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +04005559 elsif($IncType>0
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04005560 and $Include=~/[\/\\]/) # and not find_in_defaults($Include)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005561 { # search for the nearest header
5562 # QtCore/qabstractanimation.h includes <QtCore/qobject.h>
5563 my $Candidate = joinPath(get_dirname($AbsDir), $Include);
5564 if(-f $Candidate) {
5565 $HPath = $Candidate;
5566 }
5567 }
5568 if(not $HPath) {
5569 $HPath = identify_header($Include, $LibVersion);
5570 }
5571 next if(not $HPath);
5572 if($HPath eq $AbsPath) {
5573 next;
5574 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +04005575 $RecursiveIncludes{$LibVersion}{$AbsPath}{$HPath} = $IncType;
5576 if($IncType>0)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005577 { # only include <...>, skip include "..." prefixes
5578 $Header_Include_Prefix{$LibVersion}{$AbsPath}{$HPath}{get_dirname($Include)} = 1;
5579 }
5580 foreach my $IncPath (detect_recursive_includes($HPath, $LibVersion))
5581 {
5582 if($IncPath eq $AbsPath) {
5583 next;
5584 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +04005585 my $RIncType = $RecursiveIncludes{$LibVersion}{$HPath}{$IncPath};
5586 if($RIncType==-1)
5587 { # include "..."
5588 $RIncType = $IncType;
5589 }
5590 elsif($RIncType==2)
5591 {
5592 if($IncType!=-1) {
5593 $RIncType = $IncType;
5594 }
5595 }
5596 $RecursiveIncludes{$LibVersion}{$AbsPath}{$IncPath} = $RIncType;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005597 foreach my $Prefix (keys(%{$Header_Include_Prefix{$LibVersion}{$HPath}{$IncPath}})) {
5598 $Header_Include_Prefix{$LibVersion}{$AbsPath}{$IncPath}{$Prefix} = 1;
5599 }
5600 }
5601 foreach my $Dep (keys(%{$Header_Include_Prefix{$LibVersion}{$AbsPath}}))
5602 {
5603 if($GlibcHeader{get_filename($Dep)} and keys(%{$Header_Include_Prefix{$LibVersion}{$AbsPath}{$Dep}})>=2
5604 and defined $Header_Include_Prefix{$LibVersion}{$AbsPath}{$Dep}{""})
5605 { # distinguish math.h from glibc and math.h from the tested library
5606 delete($Header_Include_Prefix{$LibVersion}{$AbsPath}{$Dep}{""});
5607 last;
5608 }
5609 }
5610 }
5611 pop(@RecurInclude);
5612 return keys(%{$RecursiveIncludes{$LibVersion}{$AbsPath}});
5613}
5614
5615sub find_in_framework($$$)
5616{
5617 my ($Header, $Framework, $LibVersion) = @_;
5618 return "" if(not $Header or not $Framework or not $LibVersion);
5619 if(defined $Cache{"find_in_framework"}{$LibVersion}{$Framework}{$Header}) {
5620 return $Cache{"find_in_framework"}{$LibVersion}{$Framework}{$Header};
5621 }
5622 foreach my $Dependency (sort {get_depth($a)<=>get_depth($b)} keys(%{$Header_Dependency{$LibVersion}}))
5623 {
5624 if(get_filename($Dependency) eq $Framework
5625 and -f get_dirname($Dependency)."/".$Header) {
5626 return ($Cache{"find_in_framework"}{$LibVersion}{$Framework}{$Header} = get_dirname($Dependency));
5627 }
5628 }
5629 return ($Cache{"find_in_framework"}{$LibVersion}{$Framework}{$Header} = "");
5630}
5631
5632sub find_in_defaults($)
5633{
5634 my $Header = $_[0];
5635 return "" if(not $Header);
5636 if(defined $Cache{"find_in_defaults"}{$Header}) {
5637 return $Cache{"find_in_defaults"}{$Header};
5638 }
5639 foreach my $Dir (sort {get_depth($a)<=>get_depth($b)}
5640 (keys(%DefaultIncPaths), keys(%DefaultGccPaths), keys(%DefaultCppPaths), keys(%UserIncPath)))
5641 {
5642 next if(not $Dir);
5643 if(-f $Dir."/".$Header) {
5644 return ($Cache{"find_in_defaults"}{$Header}=$Dir);
5645 }
5646 }
5647 return ($Cache{"find_in_defaults"}{$Header}="");
5648}
5649
5650sub cmp_paths($$)
5651{
5652 my ($Path1, $Path2) = @_;
5653 my @Parts1 = split(/[\/\\]/, $Path1);
5654 my @Parts2 = split(/[\/\\]/, $Path2);
5655 foreach my $Num (0 .. $#Parts1)
5656 {
5657 my $Part1 = $Parts1[$Num];
5658 my $Part2 = $Parts2[$Num];
5659 if($GlibcDir{$Part1}
5660 and not $GlibcDir{$Part2}) {
5661 return 1;
5662 }
5663 elsif($GlibcDir{$Part2}
5664 and not $GlibcDir{$Part1}) {
5665 return -1;
5666 }
5667 elsif($Part1=~/glib/
5668 and $Part2!~/glib/) {
5669 return 1;
5670 }
5671 elsif($Part1!~/glib/
5672 and $Part2=~/glib/) {
5673 return -1;
5674 }
5675 elsif(my $CmpRes = ($Part1 cmp $Part2)) {
5676 return $CmpRes;
5677 }
5678 }
5679 return 0;
5680}
5681
5682sub checkRelevance($)
5683{
5684 my ($Path) = @_;
5685 return 0 if(not $Path);
5686 if($SystemRoot) {
5687 $Path=~s/\A\Q$SystemRoot\E//g;
5688 }
5689 my ($Dir, $Name) = separate_path($Path);
5690 $Name=~s/\.\w+\Z//g;# remove extension (.h)
5691 my @Tokens = split(/[_\d\W]+/, $Name);
5692 foreach (@Tokens)
5693 {
5694 next if(not $_);
5695 if($Dir=~/(\A|lib|[_\d\W])\Q$_\E([_\d\W]|lib|\Z)/i
5696 or length($_)>=4 and $Dir=~/\Q$_\E/i)
5697 { # include/gupnp-1.0/libgupnp/gupnp-context.h
5698 # include/evolution-data-server-1.4/libebook/e-book.h
5699 return 1;
5700 }
5701 }
5702 return 0;
5703}
5704
5705sub checkFamily(@)
5706{
5707 my @Paths = @_;
5708 return 1 if($#Paths<=0);
5709 my %Prefix = ();
5710 foreach my $Path (@Paths)
5711 {
5712 if($SystemRoot) {
5713 $Path = cut_path_prefix($Path, $SystemRoot);
5714 }
5715 if(my $Dir = get_dirname($Path))
5716 {
5717 $Dir=~s/(\/[^\/]+?)[\d\.\-\_]+\Z/$1/g; # remove version suffix
5718 $Prefix{$Dir} += 1;
5719 $Prefix{get_dirname($Dir)} += 1;
5720 }
5721 }
5722 foreach (sort keys(%Prefix))
5723 {
5724 if(get_depth($_)>=3
5725 and $Prefix{$_}==$#Paths+1) {
5726 return 1;
5727 }
5728 }
5729 return 0;
5730}
5731
5732sub isAcceptable($$$)
5733{
5734 my ($Header, $Candidate, $LibVersion) = @_;
5735 my $HName = get_filename($Header);
5736 if(get_dirname($Header))
5737 { # with prefix
5738 return 1;
5739 }
5740 if($HName=~/config|setup/i and $Candidate=~/[\/\\]lib\d*[\/\\]/)
5741 { # allow to search for glibconfig.h in /usr/lib/glib-2.0/include/
5742 return 1;
5743 }
5744 if(checkRelevance($Candidate))
5745 { # allow to search for atk.h in /usr/include/atk-1.0/atk/
5746 return 1;
5747 }
5748 if(checkFamily(getSystemHeaders($HName, $LibVersion)))
5749 { # /usr/include/qt4/QtNetwork/qsslconfiguration.h
5750 # /usr/include/qt4/Qt/qsslconfiguration.h
5751 return 1;
5752 }
5753 if($OStarget eq "symbian")
5754 {
5755 if($Candidate=~/[\/\\]stdapis[\/\\]/) {
5756 return 1;
5757 }
5758 }
5759 return 0;
5760}
5761
5762sub isRelevant($$$)
5763{ # disallow to search for "abstract" headers in too deep directories
5764 my ($Header, $Candidate, $LibVersion) = @_;
5765 my $HName = get_filename($Header);
5766 if($OStarget eq "symbian")
5767 {
5768 if($Candidate=~/[\/\\](tools|stlportv5)[\/\\]/) {
5769 return 0;
5770 }
5771 }
5772 if($OStarget ne "bsd") {
5773 if($Candidate=~/[\/\\]include[\/\\]bsd[\/\\]/)
5774 { # openssh: skip /usr/lib/bcc/include/bsd/signal.h
5775 return 0;
5776 }
5777 }
5778 if(not get_dirname($Header)
5779 and $Candidate=~/[\/\\]wx[\/\\]/)
5780 { # do NOT search in system /wx/ directory
5781 # for headers without a prefix: sstream.h
5782 return 0;
5783 }
5784 if($Candidate=~/c\+\+[\/\\]\d+/ and $MAIN_CPP_DIR
5785 and $Candidate!~/\A\Q$MAIN_CPP_DIR\E/)
5786 { # skip ../c++/3.3.3/ if using ../c++/4.5/
5787 return 0;
5788 }
5789 if($Candidate=~/[\/\\]asm-/
5790 and (my $Arch = getArch($LibVersion)) ne "unknown")
5791 { # arch-specific header files
5792 if($Candidate!~/[\/\\]asm-\Q$Arch\E/)
5793 {# skip ../asm-arm/ if using x86 architecture
5794 return 0;
5795 }
5796 }
5797 my @Candidates = getSystemHeaders($HName, $LibVersion);
5798 if($#Candidates==1)
5799 { # unique header
5800 return 1;
5801 }
5802 my @SCandidates = getSystemHeaders($Header, $LibVersion);
5803 if($#SCandidates==1)
5804 { # unique name
5805 return 1;
5806 }
5807 my $SystemDepth = $SystemRoot?get_depth($SystemRoot):0;
5808 if(get_depth($Candidate)-$SystemDepth>=5)
5809 { # abstract headers in too deep directories
5810 # sstream.h or typeinfo.h in /usr/include/wx-2.9/wx/
5811 if(not isAcceptable($Header, $Candidate, $LibVersion)) {
5812 return 0;
5813 }
5814 }
5815 if($Header eq "parser.h"
5816 and $Candidate!~/\/libxml2\//)
5817 { # select parser.h from xml2 library
5818 return 0;
5819 }
5820 if(not get_dirname($Header)
5821 and keys(%{$SystemHeaders{$HName}})>=3)
5822 { # many headers with the same name
5823 # like thread.h included without a prefix
5824 if(not checkFamily(@Candidates)) {
5825 return 0;
5826 }
5827 }
5828 return 1;
5829}
5830
5831sub selectSystemHeader($$)
5832{
5833 my ($Header, $LibVersion) = @_;
5834 return $Header if(-f $Header);
5835 return "" if(is_abs($Header) and not -f $Header);
5836 return "" if($Header=~/\A(atomic|config|configure|build|conf|setup)\.h\Z/i);
5837 if($OSgroup ne "windows")
5838 {
5839 if(get_filename($Header)=~/windows|win32|win64|\A(dos|process|winsock|config-win)\.h\Z/i) {
5840 return "";
5841 }
5842 elsif($Header=~/\A(mem)\.h\Z/)
5843 { # pngconf.h include mem.h for __MSDOS__
5844 return "";
5845 }
5846 }
5847 if($OSgroup ne "solaris")
5848 {
5849 if($Header=~/\A(thread)\.h\Z/)
5850 { # thread.h in Solaris
5851 return "";
5852 }
5853 }
5854 if(defined $Cache{"selectSystemHeader"}{$LibVersion}{$Header}) {
5855 return $Cache{"selectSystemHeader"}{$LibVersion}{$Header};
5856 }
5857 foreach my $Path (keys(%{$SystemPaths{"include"}}))
5858 { # search in default paths
5859 if(-f $Path."/".$Header) {
5860 return ($Cache{"selectSystemHeader"}{$LibVersion}{$Header} = joinPath($Path,$Header));
5861 }
5862 }
5863 if(not keys(%SystemHeaders)) {
5864 detectSystemHeaders();
5865 }
5866 foreach my $Candidate (sort {get_depth($a)<=>get_depth($b)}
5867 sort {cmp_paths($b, $a)} getSystemHeaders($Header, $LibVersion))
5868 {
5869 if(isRelevant($Header, $Candidate, $LibVersion)) {
5870 return ($Cache{"selectSystemHeader"}{$LibVersion}{$Header} = $Candidate);
5871 }
5872 }
5873 return ($Cache{"selectSystemHeader"}{$LibVersion}{$Header} = ""); # error
5874}
5875
5876sub getSystemHeaders($$)
5877{
5878 my ($Header, $LibVersion) = @_;
5879 my @Candidates = ();
5880 foreach my $Candidate (sort keys(%{$SystemHeaders{$Header}}))
5881 {
5882 if(skip_header($Candidate, $LibVersion)) {
5883 next;
5884 }
5885 push(@Candidates, $Candidate);
5886 }
5887 return @Candidates;
5888}
5889
5890sub cut_path_prefix($$)
5891{
5892 my ($Path, $Prefix) = @_;
5893 return $Path if(not $Prefix);
5894 $Prefix=~s/[\/\\]+\Z//;
5895 $Path=~s/\A\Q$Prefix\E([\/\\]+|\Z)//;
5896 return $Path;
5897}
5898
5899sub is_default_include_dir($)
5900{
5901 my $Dir = $_[0];
5902 $Dir=~s/[\/\\]+\Z//;
5903 return ($DefaultGccPaths{$Dir} or $DefaultCppPaths{$Dir} or $DefaultIncPaths{$Dir});
5904}
5905
5906sub identify_header($$)
5907{
5908 my ($Header, $LibVersion) = @_;
5909 $Header=~s/\A(\.\.[\\\/])+//g;
Andrey Ponomarenko85043792012-05-14 16:48:07 +04005910 if(defined $Cache{"identify_header"}{$LibVersion}{$Header}) {
5911 return $Cache{"identify_header"}{$LibVersion}{$Header};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005912 }
5913 my $Path = identify_header_internal($Header, $LibVersion);
5914 if(not $Path and $OSgroup eq "macos" and my $Dir = get_dirname($Header))
5915 { # search in frameworks: "OpenGL/gl.h" is "OpenGL.framework/Headers/gl.h"
5916 my $RelPath = "Headers\/".get_filename($Header);
5917 if(my $HeaderDir = find_in_framework($RelPath, $Dir.".framework", $LibVersion)) {
5918 $Path = joinPath($HeaderDir, $RelPath);
5919 }
5920 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +04005921 return ($Cache{"identify_header"}{$LibVersion}{$Header} = $Path);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005922}
5923
5924sub identify_header_internal($$)
5925{ # search for header by absolute path, relative path or name
5926 my ($Header, $LibVersion) = @_;
5927 return "" if(not $Header);
5928 if(-f $Header)
5929 { # it's relative or absolute path
5930 return get_abs_path($Header);
5931 }
5932 elsif($GlibcHeader{$Header} and not $GLIBC_TESTING
5933 and my $HeaderDir = find_in_defaults($Header))
5934 { # search for libc headers in the /usr/include
5935 # for non-libc target library before searching
5936 # in the library paths
5937 return joinPath($HeaderDir,$Header);
5938 }
5939 elsif(my $Path = $Include_Neighbors{$LibVersion}{$Header})
5940 { # search in the target library paths
5941 return $Path;
5942 }
5943 elsif($DefaultGccHeader{$Header})
5944 { # search in the internal GCC include paths
5945 return $DefaultGccHeader{$Header};
5946 }
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04005947 elsif(my $DefaultDir = find_in_defaults($Header))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005948 { # search in the default GCC include paths
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04005949 return joinPath($DefaultDir,$Header);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005950 }
5951 elsif($DefaultCppHeader{$Header})
5952 { # search in the default G++ include paths
5953 return $DefaultCppHeader{$Header};
5954 }
5955 elsif(my $AnyPath = selectSystemHeader($Header, $LibVersion))
5956 { # search everywhere in the system
5957 return $AnyPath;
5958 }
5959 else
5960 { # cannot find anything
5961 return "";
5962 }
5963}
5964
5965sub getLocation($)
5966{
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04005967 if($_[0] and my $Info = $LibInfo{$Version}{"info"}{$_[0]})
5968 {
5969 if($Info=~/srcp[ ]*:[ ]*([\w\-\<\>\.\+\/\\]+):(\d+) /) {
5970 return ($1, $2);
5971 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005972 }
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04005973 return ();
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005974}
5975
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005976sub getNameByInfo($)
5977{
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04005978 if($_[0] and my $Info = $LibInfo{$Version}{"info"}{$_[0]})
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04005979 {
5980 if($Info=~/name[ ]*:[ ]*@(\d+) /)
5981 {
5982 if(my $NInfo = $LibInfo{$Version}{"info"}{$1})
5983 {
5984 if($NInfo=~/strg[ ]*:[ ]*(.*?)[ ]+lngt/)
5985 { # short unsigned int (may include spaces)
5986 return $1;
5987 }
5988 }
5989 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005990 }
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04005991 return "";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005992}
5993
5994sub getTreeStr($)
5995{
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04005996 if($_[0] and my $Info = $LibInfo{$Version}{"info"}{$_[0]})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005997 {
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04005998 if($Info=~/strg[ ]*:[ ]*([^ ]*)/)
5999 {
6000 my $Str = $1;
6001 if($C99Mode{$Version}
6002 and $Str=~/\Ac99_(.+)\Z/) {
6003 if($CppKeywords_A{$1}) {
6004 $Str=$1;
6005 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006006 }
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04006007 return $Str;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006008 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006009 }
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04006010 return "";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006011}
6012
6013sub getVarShortName($)
6014{
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04006015 if($_[0] and my $Info = $LibInfo{$Version}{"info"}{$_[0]})
6016 {
6017 if($Info=~/name[ ]*:[ ]*@(\d+) /) {
6018 return getTreeStr($1);
6019 }
6020 }
6021 return "";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006022}
6023
6024sub getFuncShortName($)
6025{
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04006026 if(my $Info = $LibInfo{$Version}{"info"}{$_[0]})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006027 {
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04006028 if($Info=~/ operator /)
6029 {
6030 if($Info=~/ conversion /) {
6031 return "operator ".get_TypeName($SymbolInfo{$Version}{$_[0]}{"Return"}, $Version);
6032 }
6033 else
6034 {
6035 if($Info=~/ operator[ ]+([a-zA-Z]+) /) {
6036 return "operator".$Operator_Indication{$1};
6037 }
6038 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006039 }
6040 else
6041 {
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04006042 if($Info=~/name[ ]*:[ ]*@(\d+) /) {
6043 return getTreeStr($1);
6044 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006045 }
6046 }
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04006047 return "";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006048}
6049
6050sub getFuncMnglName($)
6051{
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04006052 if($_[0] and my $Info = $LibInfo{$Version}{"info"}{$_[0]})
6053 {
6054 if($Info=~/mngl[ ]*:[ ]*@(\d+) /) {
6055 return getTreeStr($1);
6056 }
6057 }
6058 return "";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006059}
6060
6061sub getFuncReturn($)
6062{
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04006063 if($_[0] and my $Info = $LibInfo{$Version}{"info"}{$_[0]})
6064 {
6065 if($Info=~/type[ ]*:[ ]*@(\d+) /)
6066 {
6067 if($LibInfo{$Version}{"info"}{$1}=~/retn[ ]*:[ ]*@(\d+) /) {
6068 return $1;
6069 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006070 }
6071 }
6072 return "";
6073}
6074
6075sub getFuncOrig($)
6076{
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04006077 if($_[0] and my $Info = $LibInfo{$Version}{"info"}{$_[0]})
6078 {
6079 if($Info=~/orig[ ]*:[ ]*@(\d+) /) {
6080 return $1;
6081 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006082 }
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04006083 return $_[0];
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006084}
6085
6086sub unmangleSymbol($)
6087{
6088 my $Symbol = $_[0];
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04006089 if(my @Unmngl = unmangleArray($Symbol)) {
6090 return $Unmngl[0];
6091 }
6092 return "";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006093}
6094
6095sub unmangleArray(@)
6096{
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04006097 if($_[0]=~/\A\?/)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006098 { # MSVC mangling
6099 my $UndNameCmd = get_CmdPath("undname");
6100 if(not $UndNameCmd) {
6101 exitStatus("Not_Found", "can't find \"undname\"");
6102 }
6103 writeFile("$TMP_DIR/unmangle", join("\n", @_));
6104 return split(/\n/, `$UndNameCmd 0x8386 $TMP_DIR/unmangle`);
6105 }
6106 else
6107 { # GCC mangling
6108 my $CppFiltCmd = get_CmdPath("c++filt");
6109 if(not $CppFiltCmd) {
6110 exitStatus("Not_Found", "can't find c++filt in PATH");
6111 }
6112 my $Info = `$CppFiltCmd -h 2>&1`;
6113 if($Info=~/\@<file>/)
6114 {# new version of c++filt can take a file
6115 my $NoStrip = "";
6116 if($OSgroup eq "macos"
6117 or $OSgroup eq "windows") {
6118 $NoStrip = "-n";
6119 }
6120 writeFile("$TMP_DIR/unmangle", join("\n", @_));
6121 return split(/\n/, `$CppFiltCmd $NoStrip \@\"$TMP_DIR/unmangle\"`);
6122 }
6123 else
6124 { # old-style unmangling
6125 if($#_>$MAX_COMMAND_LINE_ARGUMENTS) {
6126 my @Half = splice(@_, 0, ($#_+1)/2);
6127 return (unmangleArray(@Half), unmangleArray(@_))
6128 }
6129 else
6130 {
6131 my $NoStrip = "";
6132 if($OSgroup eq "macos"
6133 or $OSgroup eq "windows") {
6134 $NoStrip = "-n";
6135 }
6136 my $Strings = join(" ", @_);
6137 return split(/\n/, `$CppFiltCmd $NoStrip $Strings`);
6138 }
6139 }
6140 }
6141}
6142
6143sub get_SignatureNoInfo($$)
6144{
6145 my ($Interface, $LibVersion) = @_;
6146 if($Cache{"get_SignatureNoInfo"}{$LibVersion}{$Interface}) {
6147 return $Cache{"get_SignatureNoInfo"}{$LibVersion}{$Interface};
6148 }
6149 my ($MnglName, $VersionSpec, $SymbolVersion) = separate_symbol($Interface);
6150 my $Signature = $tr_name{$MnglName}?$tr_name{$MnglName}:$MnglName;
6151 if($Interface=~/\A(_Z|\?)/)
6152 { # C++
6153 $Signature=~s/\Qstd::basic_string<char, std::char_traits<char>, std::allocator<char> >\E/std::string/g;
6154 $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;
6155 }
6156 if(not $CheckObjectsOnly or $OSgroup=~/linux|bsd|beos/)
6157 { # ELF format marks data as OBJECT
6158 if($CompleteSignature{$LibVersion}{$Interface}{"Object"}) {
6159 $Signature .= " [data]";
6160 }
6161 elsif($Interface!~/\A(_Z|\?)/) {
6162 $Signature .= " (...)";
6163 }
6164 }
6165 if(my $ChargeLevel = get_ChargeLevel($Interface, $LibVersion))
6166 {
Andrey Ponomarenko16934472012-03-29 15:37:04 +04006167 my $ShortName = substr($Signature, 0, find_center($Signature, "("));
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006168 $Signature=~s/\A\Q$ShortName\E/$ShortName $ChargeLevel/g;
6169 }
6170 if($SymbolVersion) {
6171 $Signature .= $VersionSpec.$SymbolVersion;
6172 }
6173 return ($Cache{"get_SignatureNoInfo"}{$LibVersion}{$Interface} = $Signature);
6174}
6175
6176sub get_ChargeLevel($$)
6177{
6178 my ($Interface, $LibVersion) = @_;
6179 return "" if($Interface!~/\A(_Z|\?)/);
6180 if(defined $CompleteSignature{$LibVersion}{$Interface}
6181 and $CompleteSignature{$LibVersion}{$Interface}{"Header"})
6182 {
6183 if($CompleteSignature{$LibVersion}{$Interface}{"Constructor"})
6184 {
6185 if($Interface=~/C1E/) {
6186 return "[in-charge]";
6187 }
6188 elsif($Interface=~/C2E/) {
6189 return "[not-in-charge]";
6190 }
6191 }
6192 elsif($CompleteSignature{$LibVersion}{$Interface}{"Destructor"})
6193 {
6194 if($Interface=~/D1E/) {
6195 return "[in-charge]";
6196 }
6197 elsif($Interface=~/D2E/) {
6198 return "[not-in-charge]";
6199 }
6200 elsif($Interface=~/D0E/) {
6201 return "[in-charge-deleting]";
6202 }
6203 }
6204 }
6205 else
6206 {
6207 if($Interface=~/C1E/) {
6208 return "[in-charge]";
6209 }
6210 elsif($Interface=~/C2E/) {
6211 return "[not-in-charge]";
6212 }
6213 elsif($Interface=~/D1E/) {
6214 return "[in-charge]";
6215 }
6216 elsif($Interface=~/D2E/) {
6217 return "[not-in-charge]";
6218 }
6219 elsif($Interface=~/D0E/) {
6220 return "[in-charge-deleting]";
6221 }
6222 }
6223 return "";
6224}
6225
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04006226sub get_Signature_M($$)
6227{
6228 my ($Symbol, $LibVersion) = @_;
6229 my $Signature_M = $tr_name{$Symbol};
6230 if(my $RTid = $CompleteSignature{$LibVersion}{$Symbol}{"Return"})
6231 { # add return type name
6232 $Signature_M = get_TypeName($RTid, $LibVersion)." ".$Signature_M;
6233 }
6234 return $Signature_M;
6235}
6236
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006237sub get_Signature($$)
6238{
6239 my ($Interface, $LibVersion) = @_;
6240 if($Cache{"get_Signature"}{$LibVersion}{$Interface}) {
6241 return $Cache{"get_Signature"}{$LibVersion}{$Interface};
6242 }
6243 my ($MnglName, $VersionSpec, $SymbolVersion) = separate_symbol($Interface);
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04006244 if(isPrivateData($MnglName) or not $CompleteSignature{$LibVersion}{$Interface}{"Header"})
6245 { # non-public global data
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006246 return get_SignatureNoInfo($Interface, $LibVersion);
6247 }
6248 my ($Func_Signature, @Param_Types_FromUnmangledName) = ();
6249 my $ShortName = $CompleteSignature{$LibVersion}{$Interface}{"ShortName"};
6250 if($Interface=~/\A(_Z|\?)/)
6251 {
6252 if(my $ClassId = $CompleteSignature{$LibVersion}{$Interface}{"Class"}) {
6253 $Func_Signature = get_TypeName($ClassId, $LibVersion)."::".(($CompleteSignature{$LibVersion}{$Interface}{"Destructor"})?"~":"").$ShortName;
6254 }
6255 elsif(my $NameSpace = $CompleteSignature{$LibVersion}{$Interface}{"NameSpace"}) {
6256 $Func_Signature = $NameSpace."::".$ShortName;
6257 }
6258 else {
6259 $Func_Signature = $ShortName;
6260 }
6261 @Param_Types_FromUnmangledName = get_s_params($tr_name{$MnglName}, 0);
6262 }
6263 else {
6264 $Func_Signature = $MnglName;
6265 }
6266 my @ParamArray = ();
6267 foreach my $Pos (sort {int($a) <=> int($b)} keys(%{$CompleteSignature{$LibVersion}{$Interface}{"Param"}}))
6268 {
6269 next if($Pos eq "");
6270 my $ParamTypeId = $CompleteSignature{$LibVersion}{$Interface}{"Param"}{$Pos}{"type"};
6271 next if(not $ParamTypeId);
6272 my $ParamTypeName = get_TypeName($ParamTypeId, $LibVersion);
6273 if(not $ParamTypeName) {
6274 $ParamTypeName = $Param_Types_FromUnmangledName[$Pos];
6275 }
6276 foreach my $Typedef (keys(%ChangedTypedef))
6277 {
6278 my $Base = $Typedef_BaseName{$LibVersion}{$Typedef};
6279 $ParamTypeName=~s/(\A|\W)\Q$Typedef\E(\W|\Z)/$1$Base$2/g;
6280 }
6281 if(my $ParamName = $CompleteSignature{$LibVersion}{$Interface}{"Param"}{$Pos}{"name"}) {
6282 push(@ParamArray, create_member_decl($ParamTypeName, $ParamName));
6283 }
6284 else {
6285 push(@ParamArray, $ParamTypeName);
6286 }
6287 }
6288 if($CompleteSignature{$LibVersion}{$Interface}{"Data"}
6289 or $CompleteSignature{$LibVersion}{$Interface}{"Object"}) {
6290 $Func_Signature .= " [data]";
6291 }
6292 else
6293 {
6294 if(my $ChargeLevel = get_ChargeLevel($Interface, $LibVersion))
6295 { # add [in-charge]
6296 $Func_Signature .= " ".$ChargeLevel;
6297 }
6298 $Func_Signature .= " (".join(", ", @ParamArray).")";
6299 if($CompleteSignature{$LibVersion}{$Interface}{"Const"}
6300 or $Interface=~/\A_ZN(V|)K/) {
6301 $Func_Signature .= " const";
6302 }
6303 if($CompleteSignature{$LibVersion}{$Interface}{"Volatile"}
6304 or $Interface=~/\A_ZN(K|)V/) {
6305 $Func_Signature .= " volatile";
6306 }
6307 if($CompleteSignature{$LibVersion}{$Interface}{"Static"}
6308 and $Interface=~/\A(_Z|\?)/)
6309 {# for static methods
6310 $Func_Signature .= " [static]";
6311 }
6312 }
6313 if(defined $ShowRetVal
6314 and my $ReturnTId = $CompleteSignature{$LibVersion}{$Interface}{"Return"}) {
6315 $Func_Signature .= ":".get_TypeName($ReturnTId, $LibVersion);
6316 }
6317 if($SymbolVersion) {
6318 $Func_Signature .= $VersionSpec.$SymbolVersion;
6319 }
6320 return ($Cache{"get_Signature"}{$LibVersion}{$Interface} = $Func_Signature);
6321}
6322
6323sub create_member_decl($$)
6324{
6325 my ($TName, $Member) = @_;
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04006326 if($TName=~/\([\*]+\)/)
6327 {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006328 $TName=~s/\(([\*]+)\)/\($1$Member\)/;
6329 return $TName;
6330 }
6331 else
6332 {
6333 my @ArraySizes = ();
6334 while($TName=~s/(\[[^\[\]]*\])\Z//) {
6335 push(@ArraySizes, $1);
6336 }
6337 return $TName." ".$Member.join("", @ArraySizes);
6338 }
6339}
6340
6341sub getFuncType($)
6342{
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04006343 if($_[0] and my $Info = $LibInfo{$Version}{"info"}{$_[0]})
6344 {
6345 if($Info=~/type[ ]*:[ ]*@(\d+) /)
6346 {
6347 if(my $Type = $LibInfo{$Version}{"info_type"}{$1})
6348 {
6349 if($Type eq "method_type") {
6350 return "Method";
6351 }
6352 elsif($Type eq "function_type") {
6353 return "Function";
6354 }
6355 else {
6356 return "Other";
6357 }
6358 }
6359 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006360 }
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04006361 return ""
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006362}
6363
6364sub getFuncTypeId($)
6365{
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04006366 if($_[0] and my $Info = $LibInfo{$Version}{"info"}{$_[0]})
6367 {
6368 if($Info=~/type[ ]*:[ ]*@(\d+)( |\Z)/) {
6369 return $1;
6370 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006371 }
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04006372 return 0;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006373}
6374
6375sub isNotAnon($) {
6376 return (not isAnon($_[0]));
6377}
6378
6379sub isAnon($)
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04006380{ # "._N" or "$_N" in older GCC versions
6381 return ($_[0] and $_[0]=~/(\.|\$)\_\d+|anon\-/);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006382}
6383
6384sub unmangled_Compact($)
6385{ # Removes all non-essential (for C++ language) whitespace from a string. If
6386 # the whitespace is essential it will be replaced with exactly one ' '
6387 # character. Works correctly only for unmangled names.
6388 my $Name = $_[0];
6389 if(defined $Cache{"unmangled_Compact"}{$Name}) {
6390 return $Cache{"unmangled_Compact"}{$Name};
6391 }
6392 # First, we reduce all spaces that we can
6393 my $coms='[-()<>:*&~!|+=%@~"?.,/[^'."']";
6394 my $coms_nobr='[-()<:*&~!|+=%@~"?.,'."']";
6395 my $clos='[),;:\]]';
6396 $_ = $Name;
6397 s/^\s+//gm;
6398 s/\s+$//gm;
6399 s/((?!\n)\s)+/ /g;
6400 s/(\w+)\s+($coms+)/$1$2/gm;
6401 s/($coms+)\s+(\w+)/$1$2/gm;
6402 s/(\w)\s+($clos)/$1$2/gm;
6403 s/($coms+)\s+($coms+)/$1 $2/gm;
6404 s/($coms_nobr+)\s+($coms+)/$1$2/gm;
6405 s/($coms+)\s+($coms_nobr+)/$1$2/gm;
6406 # don't forget about >> and <:. In unmangled names global-scope modifier
6407 # is not used, so <: will always be a digraph and requires no special treatment.
6408 # We also try to remove other parts that are better to be removed here than in other places
6409 # double-cv
6410 s/\bconst\s+const\b/const/gm;
6411 s/\bvolatile\s+volatile\b/volatile/gm;
6412 s/\bconst\s+volatile\b\s+const\b/const volatile/gm;
6413 s/\bvolatile\s+const\b\s+volatile\b/const volatile/gm;
6414 # Place cv in proper order
6415 s/\bvolatile\s+const\b/const volatile/gm;
6416 return ($Cache{"unmangled_Compact"}{$Name} = $_);
6417}
6418
6419sub unmangled_PostProcess($)
6420{
6421 my $Name = $_[0];
6422 $_ = $Name;
6423 #s/\bunsigned int\b/unsigned/g;
6424 s/\bshort unsigned int\b/unsigned short/g;
6425 s/\bshort int\b/short/g;
6426 s/\blong long unsigned int\b/unsigned long long/g;
6427 s/\blong unsigned int\b/unsigned long/g;
6428 s/\blong long int\b/long long/g;
6429 s/\blong int\b/long/g;
6430 s/\)const\b/\) const/g;
6431 s/\blong long unsigned\b/unsigned long long/g;
6432 s/\blong unsigned\b/unsigned long/g;
6433 return $_;
6434}
6435
6436sub formatName($)
6437{# type name correction
6438 my $Name = $_[0];
6439 $Name=unmangled_Compact($Name);
6440 $Name=unmangled_PostProcess($Name);
6441 $Name=~s/>>/> >/g; # double templates
6442 $Name=~s/(operator\s*)> >/$1>>/;
6443 return $Name;
6444}
6445
6446sub get_HeaderDeps($$)
6447{
6448 my ($AbsPath, $LibVersion) = @_;
6449 return () if(not $AbsPath or not $LibVersion);
6450 if(defined $Cache{"get_HeaderDeps"}{$LibVersion}{$AbsPath}) {
6451 return @{$Cache{"get_HeaderDeps"}{$LibVersion}{$AbsPath}};
6452 }
6453 my %IncDir = ();
6454 detect_recursive_includes($AbsPath, $LibVersion);
6455 foreach my $HeaderPath (keys(%{$RecursiveIncludes{$LibVersion}{$AbsPath}}))
6456 {
6457 next if(not $HeaderPath);
6458 next if($MAIN_CPP_DIR and $HeaderPath=~/\A\Q$MAIN_CPP_DIR\E([\/\\]|\Z)/);
6459 my $Dir = get_dirname($HeaderPath);
6460 foreach my $Prefix (keys(%{$Header_Include_Prefix{$LibVersion}{$AbsPath}{$HeaderPath}}))
6461 {
6462 my $Dep = $Dir;
6463 if($Prefix)
6464 {
6465 if($OSgroup eq "windows")
6466 { # case insensitive seach on windows
6467 if(not $Dep=~s/[\/\\]+\Q$Prefix\E\Z//ig) {
6468 next;
6469 }
6470 }
6471 elsif($OSgroup eq "macos")
6472 { # seach in frameworks
6473 if(not $Dep=~s/[\/\\]+\Q$Prefix\E\Z//g)
6474 {
6475 if($HeaderPath=~/(.+\.framework)\/Headers\/([^\/]+)/)
6476 {# frameworks
6477 my ($HFramework, $HName) = ($1, $2);
6478 $Dep = $HFramework;
6479 }
6480 else
6481 {# mismatch
6482 next;
6483 }
6484 }
6485 }
6486 elsif(not $Dep=~s/[\/\\]+\Q$Prefix\E\Z//g)
6487 { # Linux, FreeBSD
6488 next;
6489 }
6490 }
6491 if(not $Dep)
6492 { # nothing to include
6493 next;
6494 }
6495 if(is_default_include_dir($Dep))
6496 { # included by the compiler
6497 next;
6498 }
6499 if(get_depth($Dep)==1)
6500 { # too short
6501 next;
6502 }
6503 if(isLibcDir($Dep))
6504 { # do NOT include /usr/include/{sys,bits}
6505 next;
6506 }
6507 $IncDir{$Dep}=1;
6508 }
6509 }
6510 $Cache{"get_HeaderDeps"}{$LibVersion}{$AbsPath} = sortIncPaths([keys(%IncDir)], $LibVersion);
6511 return @{$Cache{"get_HeaderDeps"}{$LibVersion}{$AbsPath}};
6512}
6513
6514sub sortIncPaths($$)
6515{
6516 my ($ArrRef, $LibVersion) = @_;
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04006517 if(not $ArrRef or $#{$ArrRef}<0) {
6518 return $ArrRef;
6519 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006520 @{$ArrRef} = sort {$b cmp $a} @{$ArrRef};
6521 @{$ArrRef} = sort {get_depth($a)<=>get_depth($b)} @{$ArrRef};
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04006522 @{$ArrRef} = sort {sortDeps($b, $a, $LibVersion)} @{$ArrRef};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006523 return $ArrRef;
6524}
6525
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04006526sub sortDeps($$$)
6527{
6528 if($Header_Dependency{$_[2]}{$_[0]}
6529 and not $Header_Dependency{$_[2]}{$_[1]}) {
6530 return 1;
6531 }
6532 elsif(not $Header_Dependency{$_[2]}{$_[0]}
6533 and $Header_Dependency{$_[2]}{$_[1]}) {
6534 return -1;
6535 }
6536 return 0;
6537}
6538
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006539sub joinPath($$) {
6540 return join($SLASH, @_);
6541}
6542
6543sub get_namespace_additions($)
6544{
6545 my $NameSpaces = $_[0];
6546 my ($Additions, $AddNameSpaceId) = ("", 1);
6547 foreach my $NS (sort {$a=~/_/ <=> $b=~/_/} sort {lc($a) cmp lc($b)} keys(%{$NameSpaces}))
6548 {
6549 next if($SkipNameSpaces{$Version}{$NS});
6550 next if(not $NS or $NameSpaces->{$NS}==-1);
6551 next if($NS=~/(\A|::)iterator(::|\Z)/i);
6552 next if($NS=~/\A__/i);
6553 next if(($NS=~/\Astd::/ or $NS=~/\A(std|tr1|rel_ops|fcntl)\Z/) and not $STDCXX_TESTING);
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04006554 $NestedNameSpaces{$Version}{$NS} = 1; # for future use in reports
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006555 my ($TypeDecl_Prefix, $TypeDecl_Suffix) = ();
6556 my @NS_Parts = split(/::/, $NS);
6557 next if($#NS_Parts==-1);
6558 next if($NS_Parts[0]=~/\A(random|or)\Z/);
6559 foreach my $NS_Part (@NS_Parts)
6560 {
6561 $TypeDecl_Prefix .= "namespace $NS_Part\{";
6562 $TypeDecl_Suffix .= "}";
6563 }
6564 my $TypeDecl = $TypeDecl_Prefix."typedef int tmp_add_type_$AddNameSpaceId;".$TypeDecl_Suffix;
6565 my $FuncDecl = "$NS\:\:tmp_add_type_$AddNameSpaceId tmp_add_func_$AddNameSpaceId(){return 0;};";
6566 $Additions.=" $TypeDecl\n $FuncDecl\n";
6567 $AddNameSpaceId+=1;
6568 }
6569 return $Additions;
6570}
6571
6572sub path_format($$)
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04006573{ # forward slash to pass into MinGW GCC
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006574 my ($Path, $Fmt) = @_;
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04006575 if($Fmt eq "windows")
6576 {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006577 $Path=~s/\//\\/g;
6578 $Path=lc($Path);
6579 }
6580 else {
6581 $Path=~s/\\/\//g;
6582 }
6583 return $Path;
6584}
6585
6586sub inc_opt($$)
6587{
6588 my ($Path, $Style) = @_;
6589 if($Style eq "GCC")
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04006590 { # GCC options
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006591 if($OSgroup eq "windows")
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04006592 { # to MinGW GCC
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006593 return "-I\"".path_format($Path, "unix")."\"";
6594 }
6595 elsif($OSgroup eq "macos"
6596 and $Path=~/\.framework\Z/)
6597 {# to Apple's GCC
6598 return "-F".esc(get_dirname($Path));
6599 }
6600 else {
6601 return "-I".esc($Path);
6602 }
6603 }
6604 elsif($Style eq "CL") {
6605 return "/I \"$Path\"";
6606 }
6607 return "";
6608}
6609
6610sub platformSpecs($)
6611{
6612 my $LibVersion = $_[0];
6613 my $Arch = getArch($LibVersion);
6614 if($OStarget eq "symbian")
6615 { # options for GCCE compiler
6616 my %Symbian_Opts = map {$_=>1} (
6617 "-D__GCCE__",
6618 "-DUNICODE",
6619 "-fexceptions",
6620 "-D__SYMBIAN32__",
6621 "-D__MARM_INTERWORK__",
6622 "-D_UNICODE",
6623 "-D__S60_50__",
6624 "-D__S60_3X__",
6625 "-D__SERIES60_3X__",
6626 "-D__EPOC32__",
6627 "-D__MARM__",
6628 "-D__EABI__",
6629 "-D__MARM_ARMV5__",
6630 "-D__SUPPORT_CPP_EXCEPTIONS__",
6631 "-march=armv5t",
6632 "-mapcs",
6633 "-mthumb-interwork",
6634 "-DEKA2",
6635 "-DSYMBIAN_ENABLE_SPLIT_HEADERS"
6636 );
6637 return join(" ", keys(%Symbian_Opts));
6638 }
6639 elsif($OSgroup eq "windows"
6640 and get_dumpmachine($GCC_PATH)=~/mingw/i)
6641 { # add options to MinGW compiler
6642 # to simulate the MSVC compiler
6643 my %MinGW_Opts = map {$_=>1} (
6644 "-D_WIN32",
6645 "-D_STDCALL_SUPPORTED",
6646 "-D__int64=\"long long\"",
6647 "-D__int32=int",
6648 "-D__int16=short",
6649 "-D__int8=char",
6650 "-D__possibly_notnullterminated=\" \"",
6651 "-D__nullterminated=\" \"",
6652 "-D__nullnullterminated=\" \"",
6653 "-D__w64=\" \"",
6654 "-D__ptr32=\" \"",
6655 "-D__ptr64=\" \"",
6656 "-D__forceinline=inline",
6657 "-D__inline=inline",
6658 "-D__uuidof(x)=IID()",
6659 "-D__try=",
6660 "-D__except(x)=",
6661 "-D__declspec(x)=__attribute__((x))",
6662 "-D__pragma(x)=",
6663 "-D_inline=inline",
6664 "-D__forceinline=__inline",
6665 "-D__stdcall=__attribute__((__stdcall__))",
6666 "-D__cdecl=__attribute__((__cdecl__))",
6667 "-D__fastcall=__attribute__((__fastcall__))",
6668 "-D__thiscall=__attribute__((__thiscall__))",
6669 "-D_stdcall=__attribute__((__stdcall__))",
6670 "-D_cdecl=__attribute__((__cdecl__))",
6671 "-D_fastcall=__attribute__((__fastcall__))",
6672 "-D_thiscall=__attribute__((__thiscall__))",
6673 "-DSHSTDAPI_(x)=x",
6674 "-D_MSC_EXTENSIONS",
6675 "-DSECURITY_WIN32",
6676 "-D_MSC_VER=1500",
6677 "-D_USE_DECLSPECS_FOR_SAL",
6678 "-D__noop=\" \"",
6679 "-DDECLSPEC_DEPRECATED=\" \"",
6680 "-D__builtin_alignof(x)=__alignof__(x)",
6681 "-DSORTPP_PASS");
6682 if($Arch eq "x86") {
6683 $MinGW_Opts{"-D_M_IX86=300"}=1;
6684 }
6685 elsif($Arch eq "x86_64") {
6686 $MinGW_Opts{"-D_M_AMD64=300"}=1;
6687 }
6688 elsif($Arch eq "ia64") {
6689 $MinGW_Opts{"-D_M_IA64=300"}=1;
6690 }
6691 return join(" ", keys(%MinGW_Opts));
6692 }
6693 return "";
6694}
6695
6696my %C_Structure = map {$_=>1} (
6697# FIXME: Can't separate union and struct data types before dumping,
6698# so it sometimes cause compilation errors for unknown reason
6699# when trying to declare TYPE* tmp_add_class_N
6700# This is a list of such structures + list of other C structures
6701 "sigval",
6702 "sigevent",
6703 "sigaction",
6704 "sigvec",
6705 "sigstack",
6706 "timeval",
6707 "timezone",
6708 "rusage",
6709 "rlimit",
6710 "wait",
6711 "flock",
6712 "stat",
6713 "_stat",
6714 "stat32",
6715 "_stat32",
6716 "stat64",
6717 "_stat64",
6718 "_stati64",
6719 "if_nameindex",
6720 "usb_device",
6721 "sigaltstack",
6722 "sysinfo",
6723 "timeLocale",
6724 "tcp_debug",
6725 "rpc_createerr",
6726# Other C structures appearing in every dump
6727 "timespec",
6728 "random_data",
6729 "drand48_data",
6730 "_IO_marker",
6731 "_IO_FILE",
6732 "lconv",
6733 "sched_param",
6734 "tm",
6735 "itimerspec",
6736 "_pthread_cleanup_buffer",
6737 "fd_set",
6738 "siginfo"
6739);
6740
6741sub getCompileCmd($$$)
6742{
6743 my ($Path, $Opt, $Inc) = @_;
6744 my $GccCall = $GCC_PATH;
6745 if($Opt) {
6746 $GccCall .= " ".$Opt;
6747 }
6748 $GccCall .= " -x ";
6749 if($OSgroup eq "macos") {
6750 $GccCall .= "objective-";
6751 }
6752 if(check_gcc_version($GCC_PATH, "4"))
6753 { # compile as "C++" header
6754 # to obtain complete dump using GCC 4.0
6755 $GccCall .= "c++-header";
6756 }
6757 else
6758 { # compile as "C++" source
6759 # GCC 3.3 cannot compile headers
6760 $GccCall .= "c++";
6761 }
6762 if(my $Opts = platformSpecs($Version))
6763 {# platform-specific options
6764 $GccCall .= " ".$Opts;
6765 }
6766 # allow extra qualifications
6767 # and other nonconformant code
6768 $GccCall .= " -fpermissive -w";
6769 if($NoStdInc)
6770 {
6771 $GccCall .= " -nostdinc";
6772 $GccCall .= " -nostdinc++";
6773 }
6774 if($CompilerOptions{$Version})
6775 { # user-defined options
6776 $GccCall .= " ".$CompilerOptions{$Version};
6777 }
6778 $GccCall .= " \"$Path\"";
6779 if($Inc)
6780 { # include paths
6781 $GccCall .= " ".$Inc;
6782 }
6783 return $GccCall;
6784}
6785
6786sub getDump()
6787{
6788 if(not $GCC_PATH) {
6789 exitStatus("Error", "internal error - GCC path is not set");
6790 }
6791 my %HeaderElems = (
6792 # Types
6793 "stdio.h" => ["FILE", "va_list"],
Andrey Ponomarenko85043792012-05-14 16:48:07 +04006794 "stddef.h" => ["NULL", "ptrdiff_t"],
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006795 "stdint.h" => ["uint32_t", "int32_t", "uint64_t"],
6796 "time.h" => ["time_t"],
6797 "sys/types.h" => ["ssize_t", "u_int32_t", "u_short", "u_char",
6798 "u_int", "off_t", "u_quad_t", "u_long", "size_t", "mode_t"],
6799 "unistd.h" => ["gid_t", "uid_t"],
6800 "stdbool.h" => ["_Bool"],
6801 "rpc/xdr.h" => ["bool_t"],
6802 "in_systm.h" => ["n_long", "n_short"],
6803 # Fields
Andrey Ponomarenkobede8372012-03-29 17:43:21 +04006804 "arpa/inet.h" => ["fw_src", "ip_src"],
6805 # Functions
6806 "stdlib.h" => ["free", "malloc"],
Andrey Ponomarenko85043792012-05-14 16:48:07 +04006807 "string.h" => ["memmove", "strcmp"]
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006808 );
6809 my %AutoPreamble = ();
Andrey Ponomarenko85043792012-05-14 16:48:07 +04006810 foreach (keys(%HeaderElems))
6811 {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006812 foreach my $Elem (@{$HeaderElems{$_}}) {
6813 $AutoPreamble{$Elem}=$_;
6814 }
6815 }
6816 my $TmpHeaderPath = "$TMP_DIR/dump$Version.h";
6817 my $MHeaderPath = $TmpHeaderPath;
Andrey Ponomarenko85043792012-05-14 16:48:07 +04006818 open(TMP_HEADER, ">", $TmpHeaderPath) || die ("can't open file \'$TmpHeaderPath\': $!\n");
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006819 if(my $AddDefines = $Descriptor{$Version}{"Defines"})
6820 {
6821 $AddDefines=~s/\n\s+/\n /g;
Andrey Ponomarenko85043792012-05-14 16:48:07 +04006822 print TMP_HEADER "\n // add defines\n ".$AddDefines."\n";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006823 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +04006824 print TMP_HEADER "\n // add includes\n";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006825 my @PreambleHeaders = keys(%{$Include_Preamble{$Version}});
6826 @PreambleHeaders = sort {int($Include_Preamble{$Version}{$a}{"Position"})<=>int($Include_Preamble{$Version}{$b}{"Position"})} @PreambleHeaders;
6827 foreach my $Header_Path (@PreambleHeaders) {
Andrey Ponomarenko85043792012-05-14 16:48:07 +04006828 print TMP_HEADER " #include \"".path_format($Header_Path, "unix")."\"\n";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006829 }
6830 my @Headers = keys(%{$Registered_Headers{$Version}});
6831 @Headers = sort {int($Registered_Headers{$Version}{$a}{"Pos"})<=>int($Registered_Headers{$Version}{$b}{"Pos"})} @Headers;
6832 foreach my $Header_Path (@Headers)
6833 {
6834 next if($Include_Preamble{$Version}{$Header_Path});
Andrey Ponomarenko85043792012-05-14 16:48:07 +04006835 print TMP_HEADER " #include \"".path_format($Header_Path, "unix")."\"\n";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006836 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +04006837 close(TMP_HEADER);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006838 my $IncludeString = getIncString(getIncPaths(@PreambleHeaders, @Headers), "GCC");
6839 if($Debug)
6840 { # debug mode
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04006841 writeFile($DEBUG_PATH{$Version}."/headers/direct-includes.txt", Dumper(\%Header_Includes));
6842 writeFile($DEBUG_PATH{$Version}."/headers/recursive-includes.txt", Dumper(\%RecursiveIncludes));
6843 writeFile($DEBUG_PATH{$Version}."/headers/include-paths.txt", Dumper($Cache{"get_HeaderDeps"}));
6844 writeFile($DEBUG_PATH{$Version}."/headers/default-paths.txt", Dumper(\%DefaultIncPaths));
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006845 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +04006846
6847 # Target headers
6848 addTargetHeaders($Version);
6849
6850 # clean memory
6851 %RecursiveIncludes = ();
6852 %Header_Include_Prefix = ();
6853 %Header_Includes = ();
6854
6855 # clean cache
6856 delete($Cache{"identify_header"});
6857 delete($Cache{"detect_header_includes"});
6858 delete($Cache{"selectSystemHeader"});
6859
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006860 # preprocessing stage
6861 checkPreprocessedUnit(callPreprocessor($TmpHeaderPath, $IncludeString, $Version));
Andrey Ponomarenko85043792012-05-14 16:48:07 +04006862
6863 # clean memory
6864 %Include_Neighbors = ();
6865
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006866 my $MContent = "";
6867 my $PreprocessCmd = getCompileCmd($TmpHeaderPath, "-E", $IncludeString);
6868 if($OStarget eq "windows"
6869 and get_dumpmachine($GCC_PATH)=~/mingw/i
6870 and $MinGWMode{$Version}!=-1)
6871 { # modify headers to compile by MinGW
6872 if(not $MContent)
6873 { # preprocessing
6874 $MContent = `$PreprocessCmd 2>$TMP_DIR/null`;
6875 }
6876 if($MContent=~s/__asm\s*(\{[^{}]*?\}|[^{};]*)//g)
6877 { # __asm { ... }
6878 $MinGWMode{$Version}=1;
6879 }
6880 if($MContent=~s/\s+(\/ \/.*?)\n/\n/g)
6881 { # comments after preprocessing
6882 $MinGWMode{$Version}=1;
6883 }
6884 if($MContent=~s/(\W)(0x[a-f]+|\d+)(i|ui)(8|16|32|64)(\W)/$1$2$5/g)
6885 { # 0xffui8
6886 $MinGWMode{$Version}=1;
6887 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +04006888 if($MinGWMode{$Version})
6889 {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006890 printMsg("INFO", "Using MinGW compatibility mode");
6891 $MHeaderPath = "$TMP_DIR/dump$Version.i";
6892 }
6893 }
6894 if(($COMMON_LANGUAGE{$Version} eq "C" or $CheckHeadersOnly)
6895 and $C99Mode{$Version}!=-1 and not $Cpp2003)
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04006896 { # rename C++ keywords in C code
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006897 if(not $MContent)
6898 { # preprocessing
6899 $MContent = `$PreprocessCmd 2>$TMP_DIR/null`;
6900 }
6901 my $RegExp_C = join("|", keys(%CppKeywords_C));
6902 my $RegExp_F = join("|", keys(%CppKeywords_F));
6903 my $RegExp_O = join("|", keys(%CppKeywords_O));
6904 while($MContent=~s/(\A|\n[^\#\/\n][^\n]*?|\n)(\*\s*|\s+|\@|\,|\()($RegExp_C|$RegExp_F)(\s*(\,|\)|\;|\-\>|\.|\:\s*\d))/$1$2c99_$3$4/g)
6905 { # MATCH:
6906 # int foo(int new, int class, int (*new)(int));
6907 # unsigned private: 8;
6908 # DO NOT MATCH:
6909 # #pragma GCC visibility push(default)
6910 $C99Mode{$Version} = 1;
6911 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04006912 if($MContent=~s/([^\w\s]|\w\s+)(?<!operator )(delete)(\s*\()/$1c99_$2$3/g)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006913 { # MATCH:
6914 # int delete(...);
6915 # int explicit(...);
6916 # DO NOT MATCH:
6917 # void operator delete(...)
6918 $C99Mode{$Version} = 1;
6919 }
6920 if($MContent=~s/(\s+)($RegExp_O)(\s*(\;|\:))/$1c99_$2$3/g)
6921 { # MATCH:
6922 # int bool;
6923 # DO NOT MATCH:
6924 # bool X;
6925 # return *this;
6926 # throw;
6927 $C99Mode{$Version} = 1;
6928 }
6929 if($MContent=~s/(\s+)(operator)(\s*(\(\s*\)\s*[^\(\s]|\(\s*[^\)\s]))/$1c99_$2$3/g)
6930 { # MATCH:
6931 # int operator(...);
6932 # DO NOT MATCH:
6933 # int operator()(...);
6934 $C99Mode{$Version} = 1;
6935 }
6936 if($MContent=~s/([^\w\(\,\s]\s*|\s+)(operator)(\s*(\,\s*[^\(\s]|\)))/$1c99_$2$3/g)
6937 { # MATCH:
6938 # int foo(int operator);
6939 # int foo(int operator, int other);
6940 # DO NOT MATCH:
6941 # int operator,(...);
6942 $C99Mode{$Version} = 1;
6943 }
6944 if($MContent=~s/(\*\s*|\w\s+)(bool)(\s*(\,|\)))/$1c99_$2$3/g)
6945 { # MATCH:
6946 # int foo(gboolean *bool);
6947 # DO NOT MATCH:
6948 # void setTabEnabled(int index, bool);
6949 $C99Mode{$Version} = 1;
6950 }
6951 if($MContent=~s/(\w)([^\w\(\,\s]\s*|\s+)(this)(\s*(\,|\)))/$1$2c99_$3$4/g)
6952 { # MATCH:
6953 # int foo(int* this);
6954 # int bar(int this);
6955 # DO NOT MATCH:
6956 # baz(X, this);
6957 $C99Mode{$Version} = 1;
6958 }
6959 if($C99Mode{$Version}==1)
6960 { # try to change C++ "keyword" to "c99_keyword"
6961 printMsg("INFO", "Using C99 compatibility mode");
6962 $MHeaderPath = "$TMP_DIR/dump$Version.i";
6963 }
6964 }
6965 if($C99Mode{$Version}==1
6966 or $MinGWMode{$Version}==1)
6967 { # compile the corrected preprocessor output
6968 writeFile($MHeaderPath, $MContent);
6969 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +04006970
6971 # clean memory
6972 undef $MContent;
6973
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006974 if($COMMON_LANGUAGE{$Version} eq "C++")
6975 { # add classes and namespaces to the dump
6976 my $CHdump = "-fdump-class-hierarchy -c";
6977 if($C99Mode{$Version}==1
6978 or $MinGWMode{$Version}==1) {
6979 $CHdump .= " -fpreprocessed";
6980 }
6981 my $ClassHierarchyCmd = getCompileCmd($MHeaderPath, $CHdump, $IncludeString);
6982 chdir($TMP_DIR);
6983 system("$ClassHierarchyCmd >null 2>&1");
6984 chdir($ORIG_DIR);
6985 if(my $ClassDump = (cmd_find($TMP_DIR,"f","*.class",1))[0])
6986 {
6987 my %AddClasses = ();
6988 my $Content = readFile($ClassDump);
6989 foreach my $ClassInfo (split(/\n\n/, $Content))
6990 {
6991 if($ClassInfo=~/\AClass\s+(.+)\s*/i)
6992 {
6993 my $CName = $1;
6994 next if($CName=~/\A(__|_objc_|_opaque_)/);
6995 $TUnit_NameSpaces{$Version}{$CName} = -1;
6996 if($CName=~/\A[\w:]+\Z/)
6997 { # classes
6998 $AddClasses{$CName} = 1;
6999 }
7000 if($CName=~/(\w[\w:]*)::/)
7001 { # namespaces
7002 my $NS = $1;
7003 if(not defined $TUnit_NameSpaces{$Version}{$NS}) {
7004 $TUnit_NameSpaces{$Version}{$NS} = 1;
7005 }
7006 }
7007 }
7008 elsif($ClassInfo=~/\AVtable\s+for\s+(.+)\n((.|\n)+)\Z/i)
7009 { # read v-tables (advanced approach)
7010 my ($CName, $VTable) = ($1, $2);
7011 $ClassVTable_Content{$Version}{$CName} = $VTable;
7012 }
7013 }
7014 if($Debug)
7015 { # debug mode
7016 mkpath($DEBUG_PATH{$Version});
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04007017 copy($ClassDump, $DEBUG_PATH{$Version}."/class-hierarchy-dump.txt");
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007018 }
7019 unlink($ClassDump);
7020 if(my $NS_Add = get_namespace_additions($TUnit_NameSpaces{$Version}))
7021 { # GCC on all supported platforms does not include namespaces to the dump by default
7022 appendFile($MHeaderPath, "\n // add namespaces\n".$NS_Add);
7023 }
7024 # some GCC versions don't include class methods to the TU dump by default
7025 my ($AddClass, $ClassNum) = ("", 0);
7026 foreach my $CName (sort keys(%AddClasses))
7027 {
7028 next if($C_Structure{$CName});
7029 next if(not $STDCXX_TESTING and $CName=~/\Astd::/);
7030 next if(($CName=~tr![:]!!)>2);
7031 next if($SkipTypes{$Version}{$CName});
7032 if($CName=~/\A(.+)::[^:]+\Z/
7033 and $AddClasses{$1}) {
7034 next;
7035 }
7036 $AddClass .= " $CName* tmp_add_class_".($ClassNum++).";\n";
7037 }
7038 appendFile($MHeaderPath, "\n // add classes\n".$AddClass);
7039 }
7040 }
7041 writeLog($Version, "Temporary header file \'$TmpHeaderPath\' with the following content will be compiled to create GCC translation unit dump:\n".readFile($TmpHeaderPath)."\n");
7042 # create TU dump
7043 my $TUdump = "-fdump-translation-unit -fkeep-inline-functions -c";
7044 if($C99Mode{$Version}==1
7045 or $MinGWMode{$Version}==1) {
7046 $TUdump .= " -fpreprocessed";
7047 }
7048 my $SyntaxTreeCmd = getCompileCmd($MHeaderPath, $TUdump, $IncludeString);
7049 writeLog($Version, "The GCC parameters:\n $SyntaxTreeCmd\n\n");
7050 chdir($TMP_DIR);
7051 system($SyntaxTreeCmd." >$TMP_DIR/tu_errors 2>&1");
7052 if($?)
7053 { # failed to compile, but the TU dump still can be created
7054 my $Errors = readFile("$TMP_DIR/tu_errors");
7055 if($Errors=~/c99_/)
7056 { # disable c99 mode
7057 $C99Mode{$Version}=-1;
7058 printMsg("INFO", "Disabling C99 compatibility mode");
7059 resetLogging($Version);
7060 $TMP_DIR = tempdir(CLEANUP=>1);
7061 return getDump();
7062 }
7063 elsif($AutoPreambleMode{$Version}!=-1
7064 and my $TErrors = $Errors)
7065 {
7066 my %Types = ();
7067 while($TErrors=~s/error\:\s*(field\s*|)\W+(.+?)\W+//)
7068 { # error: 'FILE' has not been declared
7069 $Types{$2}=1;
7070 }
7071 my %AddHeaders = ();
7072 foreach my $Type (keys(%Types))
7073 {
7074 if(my $Header = $AutoPreamble{$Type}) {
7075 $AddHeaders{path_format($Header, $OSgroup)}=$Type;
7076 }
7077 }
7078 if(my @Headers = sort {$b cmp $a} keys(%AddHeaders))
7079 { # sys/types.h should be the first
7080 foreach my $Num (0 .. $#Headers)
7081 {
7082 my $Name = $Headers[$Num];
7083 if(my $Path = identify_header($Name, $Version))
7084 { # add automatic preamble headers
7085 if(defined $Include_Preamble{$Version}{$Path})
7086 { # already added
7087 next;
7088 }
7089 $Include_Preamble{$Version}{$Path}{"Position"} = keys(%{$Include_Preamble{$Version}});
7090 my $Type = $AddHeaders{$Name};
7091 printMsg("INFO", "Add \'$Name\' preamble header for \'$Type\'");
7092 }
7093 }
7094 $AutoPreambleMode{$Version}=-1;
7095 resetLogging($Version);
7096 $TMP_DIR = tempdir(CLEANUP=>1);
7097 return getDump();
7098 }
7099 }
7100 elsif($MinGWMode{$Version}!=-1)
7101 {
7102 $MinGWMode{$Version}=-1;
7103 resetLogging($Version);
7104 $TMP_DIR = tempdir(CLEANUP=>1);
7105 return getDump();
7106 }
7107 # FIXME: handle other errors and try to recompile
7108 writeLog($Version, $Errors);
7109 printMsg("ERROR", "some errors occurred when compiling headers");
7110 printErrorLog($Version);
7111 $COMPILE_ERRORS = $ERROR_CODE{"Compile_Error"};
7112 writeLog($Version, "\n");# new line
7113 }
7114 chdir($ORIG_DIR);
7115 unlink($TmpHeaderPath, $MHeaderPath);
7116 return (cmd_find($TMP_DIR,"f","*.tu",1))[0];
7117}
7118
7119sub cmd_file($)
7120{
7121 my $Path = $_[0];
7122 return "" if(not $Path or not -e $Path);
7123 if(my $CmdPath = get_CmdPath("file")) {
7124 return `$CmdPath -b \"$Path\"`;
7125 }
7126 return "";
7127}
7128
7129sub getIncString($$)
7130{
7131 my ($ArrRef, $Style) = @_;
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04007132 return "" if(not $ArrRef or $#{$ArrRef}<0);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007133 my $String = "";
7134 foreach (@{$ArrRef}) {
7135 $String .= " ".inc_opt($_, $Style);
7136 }
7137 return $String;
7138}
7139
7140sub getIncPaths(@)
7141{
7142 my @HeaderPaths = @_;
7143 my @IncPaths = ();
7144 if($INC_PATH_AUTODETECT{$Version})
7145 { # auto-detecting dependencies
7146 my %Includes = ();
7147 foreach my $HPath (@HeaderPaths)
7148 {
7149 foreach my $Dir (get_HeaderDeps($HPath, $Version))
7150 {
7151 if($Skip_Include_Paths{$Version}{$Dir}) {
7152 next;
7153 }
7154 $Includes{$Dir}=1;
7155 }
7156 }
7157 foreach my $Dir (keys(%{$Add_Include_Paths{$Version}}))
7158 { # added by user
7159 next if($Includes{$Dir});
7160 push(@IncPaths, $Dir);
7161 }
7162 foreach my $Dir (@{sortIncPaths([keys(%Includes)], $Version)}) {
7163 push(@IncPaths, $Dir);
7164 }
7165 }
7166 else
7167 { # user-defined paths
7168 foreach my $Dir (sort {get_depth($a)<=>get_depth($b)}
7169 sort {$b cmp $a} keys(%{$Include_Paths{$Version}})) {
7170 push(@IncPaths, $Dir);
7171 }
7172 }
7173 return \@IncPaths;
7174}
7175
7176sub callPreprocessor($$$)
7177{
7178 my ($Path, $Inc, $LibVersion) = @_;
7179 return "" if(not $Path or not -f $Path);
7180 my $IncludeString=$Inc;
7181 if(not $Inc) {
7182 $IncludeString = getIncString(getIncPaths($Path), "GCC");
7183 }
7184 my $Cmd = getCompileCmd($Path, "-dD -E", $IncludeString);
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04007185 my $Out = "$TMP_DIR/preprocessed";
7186 system("$Cmd >$Out 2>$TMP_DIR/null");
7187 return $Out;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007188}
7189
7190sub cmd_find($$$$)
7191{ # native "find" is much faster than File::Find (~6x)
7192 # also the File::Find doesn't support --maxdepth N option
7193 # so using the cross-platform wrapper for the native one
7194 my ($Path, $Type, $Name, $MaxDepth) = @_;
7195 return () if(not $Path or not -e $Path);
7196 if($OSgroup eq "windows")
7197 {
7198 my $DirCmd = get_CmdPath("dir");
7199 if(not $DirCmd) {
7200 exitStatus("Not_Found", "can't find \"dir\" command");
7201 }
7202 $Path=~s/[\\]+\Z//;
7203 $Path = get_abs_path($Path);
7204 $Path = path_format($Path, $OSgroup);
7205 my $Cmd = $DirCmd." \"$Path\" /B /O";
7206 if($MaxDepth!=1) {
7207 $Cmd .= " /S";
7208 }
7209 if($Type eq "d") {
7210 $Cmd .= " /AD";
7211 }
7212 my @Files = ();
7213 if($Name)
7214 { # FIXME: how to search file names in MS shell?
7215 $Name=~s/\*/.*/g if($Name!~/\]/);
7216 foreach my $File (split(/\n/, `$Cmd`))
7217 {
7218 if($File=~/$Name\Z/i) {
7219 push(@Files, $File);
7220 }
7221 }
7222 }
7223 else {
7224 @Files = split(/\n/, `$Cmd 2>$TMP_DIR/null`);
7225 }
7226 my @AbsPaths = ();
7227 foreach my $File (@Files)
7228 {
7229 if(not is_abs($File)) {
7230 $File = joinPath($Path, $File);
7231 }
7232 if($Type eq "f" and not -f $File)
7233 { # skip dirs
7234 next;
7235 }
7236 push(@AbsPaths, path_format($File, $OSgroup));
7237 }
7238 if($Type eq "d") {
7239 push(@AbsPaths, $Path);
7240 }
7241 return @AbsPaths;
7242 }
7243 else
7244 {
7245 my $FindCmd = get_CmdPath("find");
7246 if(not $FindCmd) {
7247 exitStatus("Not_Found", "can't find a \"find\" command");
7248 }
7249 $Path = get_abs_path($Path);
7250 if(-d $Path and -l $Path
7251 and $Path!~/\/\Z/)
7252 { # for directories that are symlinks
7253 $Path.="/";
7254 }
7255 my $Cmd = $FindCmd." \"$Path\"";
7256 if($MaxDepth) {
7257 $Cmd .= " -maxdepth $MaxDepth";
7258 }
7259 if($Type) {
7260 $Cmd .= " -type $Type";
7261 }
7262 if($Name)
7263 { # file name
7264 if($Name=~/\]/) {
7265 $Cmd .= " -regex \"$Name\"";
7266 }
7267 else {
7268 $Cmd .= " -name \"$Name\"";
7269 }
7270 }
7271 return split(/\n/, `$Cmd 2>$TMP_DIR/null`);
7272 }
7273}
7274
7275sub unpackDump($)
7276{
7277 my $Path = $_[0];
7278 return "" if(not $Path or not -e $Path);
7279 $Path = get_abs_path($Path);
7280 $Path = path_format($Path, $OSgroup);
7281 my ($Dir, $FileName) = separate_path($Path);
7282 my $UnpackDir = $TMP_DIR."/unpack";
7283 rmtree($UnpackDir);
7284 mkpath($UnpackDir);
7285 if($FileName=~s/\Q.zip\E\Z//g)
7286 { # *.zip
7287 my $UnzipCmd = get_CmdPath("unzip");
7288 if(not $UnzipCmd) {
7289 exitStatus("Not_Found", "can't find \"unzip\" command");
7290 }
7291 chdir($UnpackDir);
7292 system("$UnzipCmd \"$Path\" >$UnpackDir/contents.txt");
7293 if($?) {
7294 exitStatus("Error", "can't extract \'$Path\'");
7295 }
7296 chdir($ORIG_DIR);
7297 my @Contents = ();
7298 foreach (split("\n", readFile("$UnpackDir/contents.txt")))
7299 {
7300 if(/inflating:\s*([^\s]+)/) {
7301 push(@Contents, $1);
7302 }
7303 }
7304 if(not @Contents) {
7305 exitStatus("Error", "can't extract \'$Path\'");
7306 }
7307 return joinPath($UnpackDir, $Contents[0]);
7308 }
7309 elsif($FileName=~s/\Q.tar.gz\E\Z//g)
7310 { # *.tar.gz
7311 if($OSgroup eq "windows")
7312 { # -xvzf option is not implemented in tar.exe (2003)
7313 # use "gzip.exe -k -d -f" + "tar.exe -xvf" instead
7314 my $TarCmd = get_CmdPath("tar");
7315 if(not $TarCmd) {
7316 exitStatus("Not_Found", "can't find \"tar\" command");
7317 }
7318 my $GzipCmd = get_CmdPath("gzip");
7319 if(not $GzipCmd) {
7320 exitStatus("Not_Found", "can't find \"gzip\" command");
7321 }
7322 chdir($UnpackDir);
7323 system("$GzipCmd -k -d -f \"$Path\"");# keep input files (-k)
7324 if($?) {
7325 exitStatus("Error", "can't extract \'$Path\'");
7326 }
7327 system("$TarCmd -xvf \"$Dir\\$FileName.tar\" >$UnpackDir/contents.txt");
7328 if($?) {
7329 exitStatus("Error", "can't extract \'$Path\'");
7330 }
7331 chdir($ORIG_DIR);
7332 unlink($Dir."/".$FileName.".tar");
7333 my @Contents = split("\n", readFile("$UnpackDir/contents.txt"));
7334 if(not @Contents) {
7335 exitStatus("Error", "can't extract \'$Path\'");
7336 }
7337 return joinPath($UnpackDir, $Contents[0]);
7338 }
7339 else
7340 { # Unix
7341 my $TarCmd = get_CmdPath("tar");
7342 if(not $TarCmd) {
7343 exitStatus("Not_Found", "can't find \"tar\" command");
7344 }
7345 chdir($UnpackDir);
7346 system("$TarCmd -xvzf \"$Path\" >$UnpackDir/contents.txt");
7347 if($?) {
7348 exitStatus("Error", "can't extract \'$Path\'");
7349 }
7350 chdir($ORIG_DIR);
7351 # The content file name may be different
7352 # from the package file name
7353 my @Contents = split("\n", readFile("$UnpackDir/contents.txt"));
7354 if(not @Contents) {
7355 exitStatus("Error", "can't extract \'$Path\'");
7356 }
7357 return joinPath($UnpackDir, $Contents[0]);
7358 }
7359 }
7360}
7361
7362sub createArchive($$)
7363{
7364 my ($Path, $To) = @_;
7365 if(not $Path or not -e $Path
7366 or not -d $To) {
7367 return "";
7368 }
7369 my ($From, $Name) = separate_path($Path);
7370 if($OSgroup eq "windows")
7371 { # *.zip
7372 my $ZipCmd = get_CmdPath("zip");
7373 if(not $ZipCmd) {
7374 exitStatus("Not_Found", "can't find \"zip\"");
7375 }
7376 my $Pkg = $To."/".$Name.".zip";
7377 unlink($Pkg);
7378 chdir($To);
7379 system("$ZipCmd -j \"$Name.zip\" \"$Path\" >$TMP_DIR/null");
7380 if($?)
7381 { # cannot allocate memory (or other problems with "zip")
7382 unlink($Path);
7383 exitStatus("Error", "can't pack the ABI dump: ".$!);
7384 }
7385 chdir($ORIG_DIR);
7386 unlink($Path);
7387 return $Pkg;
7388 }
7389 else
7390 { # *.tar.gz
7391 my $TarCmd = get_CmdPath("tar");
7392 if(not $TarCmd) {
7393 exitStatus("Not_Found", "can't find \"tar\"");
7394 }
7395 my $GzipCmd = get_CmdPath("gzip");
7396 if(not $GzipCmd) {
7397 exitStatus("Not_Found", "can't find \"gzip\"");
7398 }
7399 my $Pkg = abs_path($To)."/".$Name.".tar.gz";
7400 unlink($Pkg);
7401 chdir($From);
7402 system($TarCmd, "-czf", $Pkg, $Name);
7403 if($?)
7404 { # cannot allocate memory (or other problems with "tar")
7405 unlink($Path);
7406 exitStatus("Error", "can't pack the ABI dump: ".$!);
7407 }
7408 chdir($ORIG_DIR);
7409 unlink($Path);
7410 return $To."/".$Name.".tar.gz";
7411 }
7412}
7413
7414sub is_header_file($)
7415{
7416 if($_[0]=~/\.($HEADER_EXT)\Z/i) {
7417 return $_[0];
7418 }
7419 return 0;
7420}
7421
7422sub is_not_header($)
7423{
7424 if($_[0]=~/\.\w+\Z/
7425 and $_[0]!~/\.($HEADER_EXT)\Z/i) {
7426 return 1;
7427 }
7428 return 0;
7429}
7430
7431sub is_header($$$)
7432{
7433 my ($Header, $UserDefined, $LibVersion) = @_;
7434 return 0 if(-d $Header);
7435 if(-f $Header) {
7436 $Header = get_abs_path($Header);
7437 }
7438 else
7439 {
7440 if(is_abs($Header))
7441 { # incorrect absolute path
7442 return 0;
7443 }
7444 if(my $HPath = identify_header($Header, $LibVersion)) {
7445 $Header = $HPath;
7446 }
7447 else
7448 { # can't find header
7449 return 0;
7450 }
7451 }
7452 if($Header=~/\.\w+\Z/)
7453 { # have an extension
7454 return is_header_file($Header);
7455 }
7456 else
7457 {
7458 if($UserDefined==2)
7459 { # specified on the command line
7460 if(cmd_file($Header)!~/HTML|XML/i) {
7461 return $Header;
7462 }
7463 }
7464 elsif($UserDefined)
7465 { # specified in the XML-descriptor
7466 # header file without an extension
7467 return $Header;
7468 }
7469 else
7470 {
Andrey Ponomarenko85043792012-05-14 16:48:07 +04007471 if($Header=~/\/include\//
7472 or cmd_file($Header)=~/C[\+]*\s+program/i)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007473 { # !~/HTML|XML|shared|dynamic/i
7474 return $Header;
7475 }
7476 }
7477 }
7478 return 0;
7479}
7480
Andrey Ponomarenko16934472012-03-29 15:37:04 +04007481sub addTargetHeaders($)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007482{
7483 my $LibVersion = $_[0];
7484 foreach my $RegHeader (keys(%{$Registered_Headers{$LibVersion}}))
7485 {
7486 my $RegDir = get_dirname($RegHeader);
7487 $TargetHeaders{$LibVersion}{get_filename($RegHeader)}=1;
7488 foreach my $RecInc (keys(%{$RecursiveIncludes{$LibVersion}{$RegHeader}}))
7489 {
7490 my $Dir = get_dirname($RecInc);
Andrey Ponomarenko85043792012-05-14 16:48:07 +04007491 if($Dir=~/\A\Q$RegDir\E([\/\\]|\Z)/
7492 or $RecursiveIncludes{$LibVersion}{$RegHeader}{$RecInc}!=1)
7493 { # in the same directory or included by #include "..."
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007494 $TargetHeaders{$LibVersion}{get_filename($RecInc)}=1;
7495 }
7496 }
7497 }
7498}
7499
7500sub readHeaders($)
7501{
7502 $Version = $_[0];
7503 printMsg("INFO", "checking header(s) ".$Descriptor{$Version}{"Version"}." ...");
7504 my $DumpPath = getDump();
7505 if(not $DumpPath) {
7506 exitStatus("Cannot_Compile", "can't compile header(s)");
7507 }
7508 if($Debug)
7509 { # debug mode
7510 mkpath($DEBUG_PATH{$Version});
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04007511 copy($DumpPath, $DEBUG_PATH{$Version}."/translation-unit-dump.txt");
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007512 }
7513 getInfo($DumpPath);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007514}
7515
7516sub prepareTypes($)
7517{
7518 my $LibVersion = $_[0];
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04007519 if(not checkDumpVersion($LibVersion, "2.0"))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007520 { # support for old ABI dumps
7521 # type names have been corrected in ACC 1.22 (dump 2.0 format)
7522 foreach my $TypeDeclId (keys(%{$TypeInfo{$LibVersion}}))
7523 {
7524 foreach my $TypeId (keys(%{$TypeInfo{$LibVersion}{$TypeDeclId}}))
7525 {
7526 my $TName = $TypeInfo{$LibVersion}{$TypeDeclId}{$TypeId}{"Name"};
7527 if($TName=~/\A(\w+)::(\w+)/) {
7528 my ($P1, $P2) = ($1, $2);
7529 if($P1 eq $P2) {
7530 $TName=~s/\A$P1:\:$P1(\W)/$P1$1/;
7531 }
7532 else {
7533 $TName=~s/\A(\w+:\:)$P2:\:$P2(\W)/$1$P2$2/;
7534 }
7535 }
7536 $TypeInfo{$LibVersion}{$TypeDeclId}{$TypeId}{"Name"} = $TName;
7537 }
7538 }
7539 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04007540 if(not checkDumpVersion($LibVersion, "2.5"))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007541 { # support for old ABI dumps
7542 # V < 2.5: array size == "number of elements"
7543 # V >= 2.5: array size in bytes
7544 foreach my $TypeDeclId (sort {int($a)<=>int($b)} keys(%{$TypeInfo{$LibVersion}}))
7545 {
7546 foreach my $TypeId (sort {int($a)<=>int($b)} keys(%{$TypeInfo{$LibVersion}{$TypeDeclId}}))
7547 {
7548 my %Type = get_PureType($TypeDeclId, $TypeId, $LibVersion);
7549 if($Type{"Type"} eq "Array")
7550 {
7551 if($Type{"Size"})
7552 { # array[N]
7553 my %Base = get_OneStep_BaseType($Type{"TDid"}, $Type{"Tid"}, $LibVersion);
7554 $TypeInfo{$LibVersion}{$TypeDeclId}{$TypeId}{"Size"} = $Type{"Size"}*$Base{"Size"};
7555 }
7556 else
7557 { # array[] is a pointer
7558 $TypeInfo{$LibVersion}{$TypeDeclId}{$TypeId}{"Size"} = $WORD_SIZE{$LibVersion};
7559 }
7560 }
7561 }
7562 }
7563 }
7564 my $V2 = ($LibVersion==1)?2:1;
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04007565 if(not checkDumpVersion($LibVersion, "2.7"))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007566 { # support for old ABI dumps
7567 # size of "method ptr" corrected in 2.7
7568 foreach my $TypeDeclId (sort {int($a)<=>int($b)} keys(%{$TypeInfo{$LibVersion}}))
7569 {
7570 foreach my $TypeId (sort {int($a)<=>int($b)} keys(%{$TypeInfo{$LibVersion}{$TypeDeclId}}))
7571 {
7572 my %PureType = get_PureType($TypeDeclId, $TypeId, $LibVersion);
7573 if($PureType{"Type"} eq "MethodPtr")
7574 {
7575 my %Type = get_Type($TypeDeclId, $TypeId, $LibVersion);
7576 my $TypeId_2 = getTypeIdByName($PureType{"Name"}, $V2);
7577 my %Type2 = get_Type($Tid_TDid{$V2}{$TypeId_2}, $TypeId_2, $V2);
7578 if($Type{"Size"} ne $Type2{"Size"}) {
7579 $TypeInfo{$LibVersion}{$TypeDeclId}{$TypeId}{"Size"} = $Type2{"Size"};
7580 }
7581 }
7582 }
7583 }
7584 }
7585}
7586
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04007587sub prepareSymbols($)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007588{
7589 my $LibVersion = $_[0];
Andrey Ponomarenko16934472012-03-29 15:37:04 +04007590
7591 if(not keys(%{$SymbolInfo{$LibVersion}}))
7592 { # check if input is valid
7593 if(not $ExtendedCheck and not $CheckObjectsOnly)
7594 {
7595 if($CheckHeadersOnly) {
7596 exitStatus("Empty_Set", "the set of public symbols is empty (".$Descriptor{$LibVersion}{"Version"}.")");
7597 }
7598 else {
7599 exitStatus("Empty_Intersection", "the sets of public symbols in headers and libraries have empty intersection (".$Descriptor{$LibVersion}{"Version"}.")");
7600 }
7601 }
7602 }
7603
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007604 my $Remangle = 0;
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04007605 if(not checkDumpVersion(1, "2.10")
7606 or not checkDumpVersion(2, "2.10"))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007607 { # different formats
7608 $Remangle = 1;
7609 }
7610 if($CheckHeadersOnly)
7611 { # different languages
7612 if($UserLang)
7613 { # --lang=LANG for both versions
7614 if(($UsedDump{1}{"V"} and $UserLang ne $UsedDump{1}{"L"})
7615 or ($UsedDump{2}{"V"} and $UserLang ne $UsedDump{2}{"L"}))
7616 {
7617 if($UserLang eq "C++")
7618 { # remangle symbols
7619 $Remangle = 1;
7620 }
7621 elsif($UserLang eq "C")
7622 { # remove mangling
7623 $Remangle = -1;
7624 }
7625 }
7626 }
7627 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04007628 foreach my $InfoId (sort {int($b)<=>int($a)} keys(%{$SymbolInfo{$LibVersion}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007629 { # reverse order: D0, D1, D2, D0 (artificial, GCC < 4.5), C1, C2
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04007630 if(not checkDumpVersion($LibVersion, "2.13"))
7631 { # support for old ABI dumps
7632 if(defined $SymbolInfo{$LibVersion}{$InfoId}{"Param"})
7633 {
7634 foreach my $P (keys(%{$SymbolInfo{$LibVersion}{$InfoId}{"Param"}}))
7635 {
7636 my $TypeId = $SymbolInfo{$LibVersion}{$InfoId}{"Param"}{$P}{"type"};
7637 my $DVal = $SymbolInfo{$LibVersion}{$InfoId}{"Param"}{$P}{"default"};
7638 my $TName = get_TypeName($TypeId, $LibVersion);
7639 if(defined $DVal and $DVal ne "")
7640 {
7641 if($TName eq "char") {
7642 $SymbolInfo{$LibVersion}{$InfoId}{"Param"}{$P}{"default"} = chr($DVal);
7643 }
7644 elsif($TName eq "bool") {
7645 $SymbolInfo{$LibVersion}{$InfoId}{"Param"}{$P}{"default"} = $DVal?"true":"false";
7646 }
7647 }
7648 }
7649 }
7650 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04007651 if($SymbolInfo{$LibVersion}{$InfoId}{"Destructor"})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007652 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04007653 if(defined $SymbolInfo{$LibVersion}{$InfoId}{"Param"}
7654 and keys(%{$SymbolInfo{$LibVersion}{$InfoId}{"Param"}})
7655 and $SymbolInfo{$LibVersion}{$InfoId}{"Param"}{"0"}{"name"})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007656 { # support for old GCC < 4.5: skip artificial ~dtor(int __in_chrg)
7657 # + support for old ABI dumps
7658 next;
7659 }
7660 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04007661 my $MnglName = $SymbolInfo{$LibVersion}{$InfoId}{"MnglName"};
Andrey Ponomarenko85043792012-05-14 16:48:07 +04007662 my $ShortName = $SymbolInfo{$LibVersion}{$InfoId}{"ShortName"};
Andrey Ponomarenko16934472012-03-29 15:37:04 +04007663 my $ClassID = $SymbolInfo{$LibVersion}{$InfoId}{"Class"};
Andrey Ponomarenko85043792012-05-14 16:48:07 +04007664 my $Return = $SymbolInfo{$LibVersion}{$InfoId}{"Return"};
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04007665
7666 if(not $MnglName)
7667 { # ABI dumps have no mangled names for C-functions
Andrey Ponomarenko85043792012-05-14 16:48:07 +04007668 $MnglName = $ShortName;
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04007669 $SymbolInfo{$LibVersion}{$InfoId}{"MnglName"} = $MnglName;
7670 }
7671
Andrey Ponomarenko16934472012-03-29 15:37:04 +04007672 my $SRemangle = 0;
Andrey Ponomarenko85043792012-05-14 16:48:07 +04007673 if(not checkDumpVersion(1, "2.12")
7674 or not checkDumpVersion(2, "2.12"))
Andrey Ponomarenko16934472012-03-29 15:37:04 +04007675 { # support for old ABI dumps
Andrey Ponomarenko85043792012-05-14 16:48:07 +04007676 if($ShortName eq "operator>>")
7677 {
7678 if(not $SymbolInfo{$LibVersion}{$InfoId}{"Class"})
7679 { # corrected mangling of operator>>
7680 $SRemangle = 1;
7681 }
Andrey Ponomarenko16934472012-03-29 15:37:04 +04007682 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +04007683 if($SymbolInfo{$LibVersion}{$InfoId}{"Data"})
7684 {
7685 if(not $SymbolInfo{$LibVersion}{$InfoId}{"Class"}
7686 and isConstType($Return, $LibVersion) and $MnglName!~/L\d+$ShortName/)
7687 { # corrected mangling of const global data
7688 # some global data is not mangled in the TU dump: qt_sine_table (Qt 4.8)
7689 # and incorrectly mangled by old ACC versions
7690 $SRemangle = 1;
7691 }
Andrey Ponomarenko16934472012-03-29 15:37:04 +04007692 }
7693 }
7694 if($Remangle==1 or $SRemangle==1)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007695 { # support for old ABI dumps: some symbols are not mangled in old dumps
7696 # mangle both sets of symbols (old and new)
7697 # NOTE: remangling all symbols by the same mangler
7698 if($MnglName=~/\A_ZN(V|)K/)
7699 { # mangling may be incorrect on old ABI dumps
7700 # because of absent "Const" attribute
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04007701 $SymbolInfo{$LibVersion}{$InfoId}{"Const"} = 1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007702 }
7703 if($MnglName=~/\A_ZN(K|)V/)
7704 { # mangling may be incorrect on old ABI dumps
7705 # because of absent "Volatile" attribute
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04007706 $SymbolInfo{$LibVersion}{$InfoId}{"Volatile"} = 1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007707 }
Andrey Ponomarenko16934472012-03-29 15:37:04 +04007708 if(($ClassID and $MnglName!~/\A(_Z|\?)/)
7709 or (not $ClassID and $CheckHeadersOnly)
7710 or (not $ClassID and not link_symbol($MnglName, $LibVersion, "-Deps")))
7711 { # support for old ABI dumps, GCC >= 4.0
7712 # remangling all manually mangled symbols
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04007713 if($MnglName = mangle_symbol($InfoId, $LibVersion, "GCC"))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007714 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04007715 $SymbolInfo{$LibVersion}{$InfoId}{"MnglName"} = $MnglName;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007716 $MangledNames{$LibVersion}{$MnglName} = 1;
7717 }
7718 }
7719 }
7720 elsif($Remangle==-1)
7721 { # remove mangling
7722 $MnglName = "";
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04007723 $SymbolInfo{$LibVersion}{$InfoId}{"MnglName"} = "";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007724 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007725 if(not $MnglName) {
7726 next;
7727 }
7728 if(not $CompleteSignature{$LibVersion}{$MnglName}{"MnglName"})
7729 { # NOTE: global data may enter here twice
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04007730 %{$CompleteSignature{$LibVersion}{$MnglName}} = %{$SymbolInfo{$LibVersion}{$InfoId}};
7731
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007732 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04007733 if(not checkDumpVersion($LibVersion, "2.6"))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007734 { # support for old dumps
7735 # add "Volatile" attribute
7736 if($MnglName=~/_Z(K|)V/) {
7737 $CompleteSignature{$LibVersion}{$MnglName}{"Volatile"}=1;
7738 }
7739 }
7740 # symbol and its symlink have same signatures
7741 if($SymVer{$LibVersion}{$MnglName}) {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04007742 %{$CompleteSignature{$LibVersion}{$SymVer{$LibVersion}{$MnglName}}} = %{$SymbolInfo{$LibVersion}{$InfoId}};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007743 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +04007744
7745 # clean memory
Andrey Ponomarenko16934472012-03-29 15:37:04 +04007746 delete($SymbolInfo{$LibVersion}{$InfoId});
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007747 }
7748 if($COMMON_LANGUAGE{$LibVersion} eq "C++" or $OSgroup eq "windows") {
7749 translateSymbols(keys(%{$CompleteSignature{$LibVersion}}), $LibVersion);
7750 }
7751 if($ExtendedCheck)
7752 { # --ext option
7753 addExtension($LibVersion);
7754 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +04007755
7756 # clean memory
7757 delete($SymbolInfo{$LibVersion});
7758
7759 foreach my $Symbol (keys(%{$CompleteSignature{$LibVersion}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007760 { # detect allocable classes with public exported constructors
7761 # or classes with auto-generated or inline-only constructors
Andrey Ponomarenko85043792012-05-14 16:48:07 +04007762 if(my $ClassId = $CompleteSignature{$LibVersion}{$Symbol}{"Class"})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007763 {
7764 my $ClassName = get_TypeName($ClassId, $LibVersion);
Andrey Ponomarenko85043792012-05-14 16:48:07 +04007765 if($CompleteSignature{$LibVersion}{$Symbol}{"Constructor"}
7766 and not $CompleteSignature{$LibVersion}{$Symbol}{"InLine"})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007767 { # Class() { ... } will not be exported
Andrey Ponomarenko85043792012-05-14 16:48:07 +04007768 if(not $CompleteSignature{$LibVersion}{$Symbol}{"Private"})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007769 {
Andrey Ponomarenko85043792012-05-14 16:48:07 +04007770 if($CheckHeadersOnly or link_symbol($Symbol, $LibVersion, "-Deps")) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007771 $AllocableClass{$LibVersion}{$ClassName} = 1;
7772 }
7773 }
7774 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +04007775 if(not $CompleteSignature{$LibVersion}{$Symbol}{"Private"})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007776 { # all imported class methods
Andrey Ponomarenko85043792012-05-14 16:48:07 +04007777 if(symbolFilter($Symbol, $LibVersion, "Affected", "Binary"))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007778 {
Andrey Ponomarenko85043792012-05-14 16:48:07 +04007779 if($CheckHeadersOnly)
7780 {
7781 if(not $CompleteSignature{$LibVersion}{$Symbol}{"InLine"}
7782 or $CompleteSignature{$LibVersion}{$Symbol}{"Virt"})
7783 { # all symbols except non-virtual inline
7784 $ClassMethods{"Binary"}{$LibVersion}{$ClassName}{$Symbol} = 1;
7785 }
7786 }
7787 else {
7788 $ClassMethods{"Binary"}{$LibVersion}{$ClassName}{$Symbol} = 1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007789 }
7790 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +04007791 if(symbolFilter($Symbol, $LibVersion, "Affected", "Source"))
7792 {
7793 $ClassMethods{"Source"}{$LibVersion}{$ClassName}{$Symbol} = 1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007794 }
7795 }
Andrey Ponomarenko16934472012-03-29 15:37:04 +04007796 $ClassNames{$LibVersion}{$ClassName} = 1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007797 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +04007798 if(my $RetId = $CompleteSignature{$LibVersion}{$Symbol}{"Return"})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007799 {
7800 my %Base = get_BaseType($Tid_TDid{$LibVersion}{$RetId}, $RetId, $LibVersion);
Andrey Ponomarenko85043792012-05-14 16:48:07 +04007801 if(defined $Base{"Type"}
7802 and $Base{"Type"}=~/Struct|Class/)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007803 {
7804 my $Name = get_TypeName($Base{"Tid"}, $LibVersion);
7805 if($Name=~/<([^<>\s]+)>/)
7806 {
7807 if(my $Tid = getTypeIdByName($1, $LibVersion)) {
7808 $ReturnedClass{$LibVersion}{$Tid} = 1;
7809 }
7810 }
7811 else {
7812 $ReturnedClass{$LibVersion}{$Base{"Tid"}} = 1;
7813 }
7814 }
7815 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +04007816 foreach my $Num (keys(%{$CompleteSignature{$LibVersion}{$Symbol}{"Param"}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007817 {
Andrey Ponomarenko85043792012-05-14 16:48:07 +04007818 my $PId = $CompleteSignature{$LibVersion}{$Symbol}{"Param"}{$Num}{"type"};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007819 if(get_PointerLevel($Tid_TDid{1}{$PId}, $PId, $LibVersion)>=1)
7820 {
Andrey Ponomarenko16934472012-03-29 15:37:04 +04007821 if(my %Base = get_BaseType($Tid_TDid{$LibVersion}{$PId}, $PId, $LibVersion))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007822 {
Andrey Ponomarenko16934472012-03-29 15:37:04 +04007823 if($Base{"Type"}=~/Struct|Class/)
7824 {
Andrey Ponomarenko85043792012-05-14 16:48:07 +04007825 $ParamClass{$LibVersion}{$Base{"Tid"}}{$Symbol} = 1;
Andrey Ponomarenko16934472012-03-29 15:37:04 +04007826 foreach my $SubId (get_sub_classes($Base{"Tid"}, $LibVersion, 1))
7827 { # mark all derived classes
Andrey Ponomarenko85043792012-05-14 16:48:07 +04007828 $ParamClass{$LibVersion}{$SubId}{$Symbol} = 1;
Andrey Ponomarenko16934472012-03-29 15:37:04 +04007829 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007830 }
7831 }
7832 }
7833 }
7834 }
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04007835 foreach my $MnglName (keys(%VTableClass))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007836 { # reconstruct header name for v-tables
7837 if($MnglName=~/\A_ZTV/)
7838 {
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04007839 if(my $ClassName = $VTableClass{$MnglName})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007840 {
7841 if(my $ClassId = $TName_Tid{$LibVersion}{$ClassName}) {
7842 $CompleteSignature{$LibVersion}{$MnglName}{"Header"} = get_TypeAttr($ClassId, $LibVersion, "Header");
7843 }
7844 }
7845 }
7846 }
Andrey Ponomarenko16934472012-03-29 15:37:04 +04007847
7848 # types
7849 foreach my $TypeDeclId (keys(%{$TypeInfo{$LibVersion}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007850 {
Andrey Ponomarenko16934472012-03-29 15:37:04 +04007851 foreach my $TypeId (keys(%{$TypeInfo{$LibVersion}{$TypeDeclId}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007852 {
Andrey Ponomarenko16934472012-03-29 15:37:04 +04007853 if(not defined $TypeInfo{$LibVersion}{$TypeDeclId}{$TypeId}{"TDid"})
7854 { # to avoid Perl warnings about uninitialized values
7855 $TypeInfo{$LibVersion}{$TypeDeclId}{$TypeId}{"TDid"} = "";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007856 }
Andrey Ponomarenko16934472012-03-29 15:37:04 +04007857 if(my $TName = $TypeInfo{$LibVersion}{$TypeDeclId}{$TypeId}{"Name"})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007858 {
Andrey Ponomarenko16934472012-03-29 15:37:04 +04007859 if(defined $TypeInfo{$LibVersion}{$TypeDeclId}{$TypeId}{"VTable"}) {
7860 $ClassNames{$LibVersion}{$TName} = 1;
7861 }
7862 if(defined $TypeInfo{$LibVersion}{$TypeDeclId}{$TypeId}{"Base"})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007863 {
Andrey Ponomarenko16934472012-03-29 15:37:04 +04007864 $ClassNames{$LibVersion}{$TName} = 1;
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04007865 foreach my $Bid (keys(%{$TypeInfo{$LibVersion}{$TypeDeclId}{$TypeId}{"Base"}}))
7866 {
7867 if(my $BName = get_TypeName($Bid, $LibVersion)) {
7868 $ClassNames{$LibVersion}{$BName} = 1;
7869 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007870 }
7871 }
7872 }
7873 }
7874 }
7875}
7876
7877sub register_TypeUsing($$$)
7878{
7879 my ($TypeDeclId, $TypeId, $LibVersion) = @_;
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04007880 if(not $TypeDeclId and not $TypeId) {
7881 return 0;
7882 }
7883 $TypeDeclId = "" if(not defined $TypeDeclId);
7884 if($UsedType{$LibVersion}{$TypeDeclId}{$TypeId})
7885 { # already registered
7886 return 1;
7887 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +04007888 my %TInfo = get_Type($TypeDeclId, $TypeId, $LibVersion);
7889 if($TInfo{"Type"})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007890 {
Andrey Ponomarenko85043792012-05-14 16:48:07 +04007891 if($TInfo{"Type"}=~/\A(Struct|Union|Class|FuncPtr|MethodPtr|FieldPtr|Enum)\Z/)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007892 {
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04007893 $UsedType{$LibVersion}{$TypeDeclId}{$TypeId} = 1;
Andrey Ponomarenko85043792012-05-14 16:48:07 +04007894 if($TInfo{"Type"}=~/\A(Struct|Class)\Z/)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007895 {
Andrey Ponomarenko85043792012-05-14 16:48:07 +04007896 foreach my $BaseId (keys(%{$TInfo{"Base"}}))
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04007897 { # register base classes
7898 register_TypeUsing($Tid_TDid{$LibVersion}{$BaseId}, $BaseId, $LibVersion);
7899 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +04007900 foreach my $TPos (keys(%{$TInfo{"TParam"}}))
7901 {
7902 my $TPName = $TInfo{"TParam"}{$TPos}{"name"};
7903 if(my $TTid = $TName_Tid{$LibVersion}{$TPName}) {
7904 register_TypeUsing($Tid_TDid{$LibVersion}{$TTid}, $TTid, $LibVersion);
7905 }
7906 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007907 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +04007908 foreach my $Memb_Pos (keys(%{$TInfo{"Memb"}}))
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04007909 {
Andrey Ponomarenko85043792012-05-14 16:48:07 +04007910 if(my $MTid = $TInfo{"Memb"}{$Memb_Pos}{"type"}) {
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04007911 register_TypeUsing($Tid_TDid{$LibVersion}{$MTid}, $MTid, $LibVersion);
7912 }
7913 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +04007914 if($TInfo{"Type"} eq "FuncPtr"
7915 or $TInfo{"Type"} eq "MethodPtr")
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04007916 {
Andrey Ponomarenko85043792012-05-14 16:48:07 +04007917 if(my $RTid = $TInfo{"Return"}) {
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04007918 register_TypeUsing($Tid_TDid{$LibVersion}{$RTid}, $RTid, $LibVersion);
7919 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +04007920 foreach my $Memb_Pos (keys(%{$TInfo{"Param"}}))
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04007921 {
Andrey Ponomarenko85043792012-05-14 16:48:07 +04007922 if(my $MTid = $TInfo{"Param"}{$Memb_Pos}{"type"}) {
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04007923 register_TypeUsing($Tid_TDid{$LibVersion}{$MTid}, $MTid, $LibVersion);
7924 }
7925 }
7926 }
7927 return 1;
7928 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +04007929 elsif($TInfo{"Type"}=~/\A(Const|ConstVolatile|Volatile|Pointer|Ref|Restrict|Array|Typedef)\Z/)
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04007930 {
7931 $UsedType{$LibVersion}{$TypeDeclId}{$TypeId} = 1;
Andrey Ponomarenko85043792012-05-14 16:48:07 +04007932 register_TypeUsing($TInfo{"BaseType"}{"TDid"}, $TInfo{"BaseType"}{"Tid"}, $LibVersion);
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04007933 return 1;
7934 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +04007935 elsif($TInfo{"Type"}=~/\A(Intrinsic)\Z/)
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04007936 {
7937 $UsedType{$LibVersion}{$TypeDeclId}{$TypeId} = 1;
7938 return 1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007939 }
7940 }
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04007941 return 0;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007942}
7943
Andrey Ponomarenko85043792012-05-14 16:48:07 +04007944sub selectSymbol($$$$)
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04007945{
Andrey Ponomarenko85043792012-05-14 16:48:07 +04007946 my ($Symbol, $SInfo, $Level, $LibVersion) = @_;
7947
7948 if(not $STDCXX_TESTING and $Symbol=~/\A(_ZS|_ZNS|_ZNKS)/)
7949 { # stdc++ interfaces
7950 return 0;
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04007951 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +04007952
7953 my $Target = 0;
7954 if(my $Header = $SInfo->{"Header"}) {
7955 $Target = (is_target_header($Header, 1) or is_target_header($Header, 2));
7956 }
7957 if($CheckHeadersOnly)
7958 {
7959 if($Target)
7960 {
7961 if($Level eq "Dump")
7962 { # dumped
7963 if($BinaryOnly)
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04007964 {
Andrey Ponomarenko85043792012-05-14 16:48:07 +04007965 if(not $SInfo->{"InLine"} or $SInfo->{"Data"}) {
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04007966 return 1;
7967 }
7968 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +04007969 else {
7970 return 1;
7971 }
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04007972 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +04007973 elsif($Level eq "Source")
7974 { # checked
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04007975 return 1;
7976 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +04007977 elsif($Level eq "Binary")
7978 { # checked
7979 if(not $SInfo->{"InLine"} or $SInfo->{"Data"}
7980 or $SInfo->{"Virt"} or $SInfo->{"PureVirt"}) {
7981 return 1;
7982 }
7983 }
7984 }
7985 }
7986 else
7987 { # library is available
7988 if(link_symbol($Symbol, $LibVersion, "-Deps"))
7989 { # exported symbols
7990 return 1;
7991 }
7992 if($Level eq "Dump")
7993 { # dumped
7994 if(not $BinaryOnly)
7995 { # SrcBin
7996 if($Target) {
7997 return 1;
7998 }
7999 }
8000 if($SInfo->{"Data"})
8001 {
8002 if($Target) {
8003 return 1;
8004 }
8005 }
8006 }
8007 elsif($Level eq "Source")
8008 { # checked
8009 if($Target) {
8010 return 1;
8011 }
8012 }
8013 elsif($Level eq "Binary")
8014 { # checked
8015 if($SInfo->{"PureVirt"} or $SInfo->{"Data"})
8016 {
8017 if($Target) {
8018 return 1;
8019 }
8020 }
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04008021 }
8022 }
8023 return 0;
8024}
8025
Andrey Ponomarenko85043792012-05-14 16:48:07 +04008026sub cleanDump($)
8027{ # clean data
Andrey Ponomarenko16934472012-03-29 15:37:04 +04008028 my $LibVersion = $_[0];
8029 foreach my $InfoId (keys(%{$SymbolInfo{$LibVersion}}))
8030 {
8031 my $MnglName = $SymbolInfo{$LibVersion}{$InfoId}{"MnglName"};
8032 if(not $MnglName) {
8033 delete($SymbolInfo{$LibVersion}{$InfoId});
8034 next;
8035 }
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04008036 my $ShortName = $SymbolInfo{$LibVersion}{$InfoId}{"ShortName"};
Andrey Ponomarenko85043792012-05-14 16:48:07 +04008037 if(not $ShortName) {
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04008038 delete($SymbolInfo{$LibVersion}{$InfoId});
8039 next;
Andrey Ponomarenko16934472012-03-29 15:37:04 +04008040 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +04008041 if($MnglName eq $ShortName)
8042 { # remove duplicate data
8043 delete($SymbolInfo{$LibVersion}{$InfoId}{"MnglName"});
Andrey Ponomarenko16934472012-03-29 15:37:04 +04008044 }
8045 if(not keys(%{$SymbolInfo{$LibVersion}{$InfoId}{"Param"}})) {
8046 delete($SymbolInfo{$LibVersion}{$InfoId}{"Param"});
8047 }
8048 }
8049 foreach my $TDid (keys(%{$TypeInfo{$LibVersion}}))
Andrey Ponomarenko85043792012-05-14 16:48:07 +04008050 {
Andrey Ponomarenko16934472012-03-29 15:37:04 +04008051 if(not keys(%{$TypeInfo{$LibVersion}{$TDid}})) {
8052 delete($TypeInfo{$LibVersion}{$TDid});
8053 }
8054 else
8055 {
8056 foreach my $Tid (keys(%{$TypeInfo{$LibVersion}{$TDid}}))
8057 {
Andrey Ponomarenko85043792012-05-14 16:48:07 +04008058 if(not $TypeInfo{$LibVersion}{$TDid}{$Tid}{"TDid"}) {
8059 delete($TypeInfo{$LibVersion}{$TDid}{$Tid}{"TDid"});
Andrey Ponomarenko16934472012-03-29 15:37:04 +04008060 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +04008061 if(not $TypeInfo{$LibVersion}{$TDid}{$Tid}{"NameSpace"}) {
8062 delete($TypeInfo{$LibVersion}{$TDid}{$Tid}{"NameSpace"});
8063 }
8064 if(defined $TypeInfo{$LibVersion}{$TDid}{$Tid}{"BaseType"}
8065 and not $TypeInfo{$LibVersion}{$TDid}{$Tid}{"BaseType"}{"TDid"}) {
8066 delete($TypeInfo{$LibVersion}{$TDid}{$Tid}{"BaseType"}{"TDid"});
8067 }
8068 if(not $TypeInfo{$LibVersion}{$TDid}{$Tid}{"Header"}) {
8069 delete($TypeInfo{$LibVersion}{$TDid}{$Tid}{"Header"});
8070 }
8071 if(not $TypeInfo{$LibVersion}{$TDid}{$Tid}{"Line"}) {
8072 delete($TypeInfo{$LibVersion}{$TDid}{$Tid}{"Line"});
8073 }
8074 if(not $TypeInfo{$LibVersion}{$TDid}{$Tid}{"Size"}) {
8075 delete($TypeInfo{$LibVersion}{$TDid}{$Tid}{"Size"});
Andrey Ponomarenko16934472012-03-29 15:37:04 +04008076 }
8077 }
8078 }
8079 }
8080 foreach my $Tid (keys(%{$Tid_TDid{$LibVersion}}))
8081 {
8082 if(not $Tid_TDid{$LibVersion}{$Tid}) {
8083 delete($Tid_TDid{$LibVersion}{$Tid});
8084 }
8085 }
8086}
8087
Andrey Ponomarenko85043792012-05-14 16:48:07 +04008088sub removeUnused($$)
8089{ # remove unused data types from the ABI dump
8090 my ($LibVersion, $Kind) = @_;
8091 foreach my $InfoId (keys(%{$SymbolInfo{$LibVersion}}))
8092 {
8093 my %FuncInfo = %{$SymbolInfo{$LibVersion}{$InfoId}};
8094 if(my $RTid = $FuncInfo{"Return"}) {
8095 register_TypeUsing($Tid_TDid{$LibVersion}{$RTid}, $RTid, $LibVersion);
8096 }
8097 if(my $FCid = $FuncInfo{"Class"})
8098 {
8099 register_TypeUsing($Tid_TDid{$LibVersion}{$FCid}, $FCid, $LibVersion);
8100 if(my $ThisId = getTypeIdByName(get_TypeName($FCid, $LibVersion)."*const", $LibVersion))
8101 { # register "this" pointer
8102 my $ThisDId = $Tid_TDid{$LibVersion}{$ThisId};
8103 $ThisDId = "" if(not defined $ThisDId); # for derived types
8104 $UsedType{$LibVersion}{$ThisDId}{$ThisId} = 1;
8105 if(my %ThisType = get_Type($ThisDId, $ThisId, $LibVersion)) {
8106 register_TypeUsing($ThisType{"BaseType"}{"TDid"}, $ThisType{"BaseType"}{"Tid"}, $LibVersion);
8107 }
8108 }
8109 }
8110 foreach my $PPos (keys(%{$FuncInfo{"Param"}}))
8111 {
8112 if(my $PTid = $FuncInfo{"Param"}{$PPos}{"type"}) {
8113 register_TypeUsing($Tid_TDid{$LibVersion}{$PTid}, $PTid, $LibVersion);
8114 }
8115 }
8116 foreach my $TPos (keys(%{$FuncInfo{"TParam"}}))
8117 {
8118 my $TPName = $FuncInfo{"TParam"}{$TPos}{"name"};
8119 if(my $TTid = $TName_Tid{$LibVersion}{$TPName}) {
8120 register_TypeUsing($Tid_TDid{$LibVersion}{$TTid}, $TTid, $LibVersion);
8121 }
8122 }
8123 }
8124 foreach my $TDid (sort keys(%{$TypeInfo{$LibVersion}}))
8125 { # remove unused types
8126 foreach my $Tid (sort keys(%{$TypeInfo{$LibVersion}{$TDid}}))
8127 {
8128 if($UsedType{$LibVersion}{$TDid}{$Tid})
8129 { # All & Derived
8130 next;
8131 }
8132 my $TType = $TypeInfo{$LibVersion}{$TDid}{$Tid}{"Type"};
8133 my $TName = $TypeInfo{$LibVersion}{$TDid}{$Tid}{"Name"};
8134 my $THeader = $TypeInfo{$LibVersion}{$TDid}{$Tid}{"Header"};
8135 if($Kind eq "Derived")
8136 {
8137 if($TType=~/Class|Struct|Union|Enum|Typedef/)
8138 {
8139 if(not isAnon($TName))
8140 {
8141 if(is_target_header($THeader, $LibVersion))
8142 { # from target headers
8143 if(not selfTypedef($TDid, $Tid, $LibVersion)) {
8144 next;
8145 }
8146 }
8147 }
8148 }
8149 }
8150 # remove type
8151 delete($TypeInfo{$LibVersion}{$TDid}{$Tid});
8152 if(not keys(%{$TypeInfo{$LibVersion}{$TDid}})) {
8153 delete($TypeInfo{$LibVersion}{$TDid});
8154 }
8155 if(defined $Tid_TDid{$LibVersion}{$Tid}
8156 and $Tid_TDid{$LibVersion}{$Tid} eq $TDid) {
8157 delete($Tid_TDid{$LibVersion}{$Tid});
8158 }
8159 }
8160 }
8161
8162 # clean memory
8163 %UsedType = ();
8164}
8165
8166sub selfTypedef($$$)
8167{
8168 my ($TypeDeclId, $TypeId, $LibVersion) = @_;
8169 my %Type = get_Type($TypeDeclId, $TypeId, $LibVersion);
8170 if($Type{"Type"} eq "Typedef")
8171 {
8172 my %Base = get_OneStep_BaseType($TypeDeclId, $TypeId, $LibVersion);
8173 if($Base{"Type"}=~/Class|Struct/)
8174 {
8175 if($Type{"Name"} eq $Base{"Name"}) {
8176 return 1;
8177 }
8178 elsif($Type{"Name"}=~/::(\w+)\Z/)
8179 {
8180 if($Type{"Name"} eq $Base{"Name"}."::".$1)
8181 { # QPointer<QWidget>::QPointer
8182 return 1;
8183 }
8184 }
8185 }
8186 }
8187 return 0;
8188}
8189
Andrey Ponomarenko16934472012-03-29 15:37:04 +04008190sub addExtension($)
8191{
8192 my $LibVersion = $_[0];
8193 foreach my $TDid (keys(%{$TypeInfo{$LibVersion}}))
8194 {
8195 foreach my $Tid (keys(%{$TypeInfo{$LibVersion}{$TDid}}))
8196 {
8197 my $TType = $TypeInfo{$LibVersion}{$TDid}{$Tid}{"Type"};
8198 if($TType=~/Struct|Union|Enum|Class/)
8199 {
8200 my $HName = $TypeInfo{$LibVersion}{$TDid}{$Tid}{"Header"};
8201 if(not $HName or isBuiltIn($HName)) {
8202 next;
8203 }
8204 my $TName = $TypeInfo{$LibVersion}{$TDid}{$Tid}{"Name"};
8205 if(isAnon($TName))
8206 { # anon-struct-header.h-265
8207 next;
8208 }
8209 my $FuncName = "external_func_".$TName;
8210 $ExtendedFuncs{$FuncName}=1;
8211 my %Attrs = (
8212 "Header" => "extended.h",
8213 "ShortName" => $FuncName,
8214 "MnglName" => $FuncName,
8215 "Param" => { "0" => { "type"=>$Tid, "name"=>"p1" } }
8216 );
8217 %{$CompleteSignature{$LibVersion}{$FuncName}} = %Attrs;
8218 register_TypeUsing($TDid, $Tid, $LibVersion);
8219 $GeneratedSymbols{$FuncName}=1;
8220 $CheckedSymbols{"Binary"}{$FuncName}=1;
8221 $CheckedSymbols{"Source"}{$FuncName}=1;
8222 }
8223 }
8224 }
8225 my $ConstFunc = "external_func_0";
8226 $GeneratedSymbols{$ConstFunc}=1;
8227 $CheckedSymbols{"Binary"}{$ConstFunc}=1;
8228 $CheckedSymbols{"Source"}{$ConstFunc}=1;
8229}
8230
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008231sub findMethod($$$)
8232{
8233 my ($VirtFunc, $ClassId, $LibVersion) = @_;
8234 foreach my $BaseClass_Id (keys(%{$TypeInfo{$LibVersion}{$Tid_TDid{$LibVersion}{$ClassId}}{$ClassId}{"Base"}}))
8235 {
8236 if(my $VirtMethodInClass = findMethod_Class($VirtFunc, $BaseClass_Id, $LibVersion)) {
8237 return $VirtMethodInClass;
8238 }
8239 elsif(my $VirtMethodInBaseClasses = findMethod($VirtFunc, $BaseClass_Id, $LibVersion)) {
8240 return $VirtMethodInBaseClasses;
8241 }
8242 }
8243 return "";
8244}
8245
8246sub findMethod_Class($$$)
8247{
8248 my ($VirtFunc, $ClassId, $LibVersion) = @_;
8249 my $ClassName = get_TypeName($ClassId, $LibVersion);
8250 return "" if(not defined $VirtualTable{$LibVersion}{$ClassName});
8251 my $TargetSuffix = get_symbol_suffix($VirtFunc, 1);
8252 my $TargetShortName = $CompleteSignature{$LibVersion}{$VirtFunc}{"ShortName"};
8253 foreach my $Candidate (keys(%{$VirtualTable{$LibVersion}{$ClassName}}))
8254 { # search for interface with the same parameters suffix (overridden)
8255 if($TargetSuffix eq get_symbol_suffix($Candidate, 1))
8256 {
8257 if($CompleteSignature{$LibVersion}{$VirtFunc}{"Destructor"}) {
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04008258 if($CompleteSignature{$LibVersion}{$Candidate}{"Destructor"})
8259 {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008260 if(($VirtFunc=~/D0E/ and $Candidate=~/D0E/)
8261 or ($VirtFunc=~/D1E/ and $Candidate=~/D1E/)
8262 or ($VirtFunc=~/D2E/ and $Candidate=~/D2E/)) {
8263 return $Candidate;
8264 }
8265 }
8266 }
8267 else {
8268 if($TargetShortName eq $CompleteSignature{$LibVersion}{$Candidate}{"ShortName"}) {
8269 return $Candidate;
8270 }
8271 }
8272 }
8273 }
8274 return "";
8275}
8276
Andrey Ponomarenko16934472012-03-29 15:37:04 +04008277sub registerVTable($)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008278{
Andrey Ponomarenko16934472012-03-29 15:37:04 +04008279 my $LibVersion = $_[0];
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04008280 foreach my $Symbol (keys(%{$CompleteSignature{$LibVersion}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008281 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04008282 if($CompleteSignature{$LibVersion}{$Symbol}{"Virt"}
8283 or $CompleteSignature{$LibVersion}{$Symbol}{"PureVirt"})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008284 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04008285 my $ClassName = get_TypeName($CompleteSignature{$LibVersion}{$Symbol}{"Class"}, $LibVersion);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008286 next if(not $STDCXX_TESTING and $ClassName=~/\A(std::|__cxxabi)/);
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04008287 if($CompleteSignature{$LibVersion}{$Symbol}{"Destructor"}
8288 and $Symbol=~/D2E/)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008289 { # pure virtual D2-destructors are marked as "virt" in the dump
8290 # virtual D2-destructors are NOT marked as "virt" in the dump
8291 # both destructors are not presented in the v-table
8292 next;
8293 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04008294 my ($MnglName, $VersionSpec, $SymbolVersion) = separate_symbol($Symbol);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008295 $VirtualTable{$LibVersion}{$ClassName}{$MnglName} = 1;
8296 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008297 }
8298}
8299
8300sub registerOverriding($)
8301{
8302 my $LibVersion = $_[0];
8303 my @Classes = keys(%{$VirtualTable{$LibVersion}});
Andrey Ponomarenko85043792012-05-14 16:48:07 +04008304 @Classes = sort {int($TName_Tid{$LibVersion}{$a})<=>int($TName_Tid{$LibVersion}{$b})} @Classes;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008305 foreach my $ClassName (@Classes)
8306 {
8307 foreach my $VirtFunc (keys(%{$VirtualTable{$LibVersion}{$ClassName}}))
8308 {
Andrey Ponomarenko16934472012-03-29 15:37:04 +04008309 if($CompleteSignature{$LibVersion}{$VirtFunc}{"PureVirt"})
8310 { # pure virtuals
8311 next;
8312 }
8313 my $ClassId = $TName_Tid{$LibVersion}{$ClassName};
8314 if(my $Overridden = findMethod($VirtFunc, $ClassId, $LibVersion))
Andrey Ponomarenko85043792012-05-14 16:48:07 +04008315 {
8316 if($CompleteSignature{$LibVersion}{$Overridden}{"Virt"}
8317 or $CompleteSignature{$LibVersion}{$Overridden}{"PureVirt"})
8318 { # both overridden virtual methods
8319 # and implemented pure virtual methods
8320 $CompleteSignature{$LibVersion}{$VirtFunc}{"Override"} = $Overridden;
8321 $OverriddenMethods{$LibVersion}{$Overridden}{$VirtFunc} = 1;
8322 delete($VirtualTable{$LibVersion}{$ClassName}{$VirtFunc}); # remove from v-table model
8323 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008324 }
8325 }
8326 if(not keys(%{$VirtualTable{$LibVersion}{$ClassName}})) {
8327 delete($VirtualTable{$LibVersion}{$ClassName});
8328 }
8329 }
8330}
8331
8332sub setVirtFuncPositions($)
8333{
8334 my $LibVersion = $_[0];
8335 foreach my $ClassName (keys(%{$VirtualTable{$LibVersion}}))
8336 {
8337 my ($Num, $RelPos, $AbsNum) = (1, 0, 1);
8338 foreach my $VirtFunc (sort {int($CompleteSignature{$LibVersion}{$a}{"Line"}) <=> int($CompleteSignature{$LibVersion}{$b}{"Line"})}
8339 sort keys(%{$VirtualTable{$LibVersion}{$ClassName}}))
8340 {
Andrey Ponomarenko16934472012-03-29 15:37:04 +04008341 $VirtualTable{$LibVersion}{$ClassName}{$VirtFunc}=$Num++;
8342
8343 # set relative positions
8344 if(defined $VirtualTable{1}{$ClassName} and defined $VirtualTable{1}{$ClassName}{$VirtFunc}
8345 and defined $VirtualTable{2}{$ClassName} and defined $VirtualTable{2}{$ClassName}{$VirtFunc})
8346 { # relative position excluding added and removed virtual functions
8347 if(not $CompleteSignature{1}{$VirtFunc}{"Override"}
8348 and not $CompleteSignature{2}{$VirtFunc}{"Override"}) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008349 $CompleteSignature{$LibVersion}{$VirtFunc}{"RelPos"} = $RelPos++;
8350 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008351 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008352 }
8353 }
Andrey Ponomarenko16934472012-03-29 15:37:04 +04008354 foreach my $ClassName (keys(%{$ClassNames{$LibVersion}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008355 {
8356 my $AbsNum = 1;
Andrey Ponomarenko16934472012-03-29 15:37:04 +04008357 foreach my $VirtFunc (getVTable_Model($TName_Tid{$LibVersion}{$ClassName}, $LibVersion)) {
8358 $VirtualTable_Model{$LibVersion}{$ClassName}{$VirtFunc}=$AbsNum++;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008359 }
8360 }
8361}
8362
8363sub get_sub_classes($$$)
8364{
8365 my ($ClassId, $LibVersion, $Recursive) = @_;
8366 return () if(not defined $Class_SubClasses{$LibVersion}{$ClassId});
8367 my @Subs = ();
8368 foreach my $SubId (keys(%{$Class_SubClasses{$LibVersion}{$ClassId}}))
8369 {
Andrey Ponomarenko16934472012-03-29 15:37:04 +04008370 if($Recursive)
8371 {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008372 foreach my $SubSubId (get_sub_classes($SubId, $LibVersion, $Recursive)) {
8373 push(@Subs, $SubSubId);
8374 }
8375 }
8376 push(@Subs, $SubId);
8377 }
8378 return @Subs;
8379}
8380
8381sub get_base_classes($$$)
8382{
8383 my ($ClassId, $LibVersion, $Recursive) = @_;
8384 my %ClassType = get_Type($Tid_TDid{$LibVersion}{$ClassId}, $ClassId, $LibVersion);
8385 return () if(not defined $ClassType{"Base"});
8386 my @Bases = ();
8387 foreach my $BaseId (sort {int($ClassType{"Base"}{$a}{"pos"})<=>int($ClassType{"Base"}{$b}{"pos"})}
8388 keys(%{$ClassType{"Base"}}))
8389 {
Andrey Ponomarenko16934472012-03-29 15:37:04 +04008390 if($Recursive)
8391 {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008392 foreach my $SubBaseId (get_base_classes($BaseId, $LibVersion, $Recursive)) {
8393 push(@Bases, $SubBaseId);
8394 }
8395 }
8396 push(@Bases, $BaseId);
8397 }
8398 return @Bases;
8399}
8400
Andrey Ponomarenko16934472012-03-29 15:37:04 +04008401sub getVTable_Model($$)
8402{ # return an ordered list of v-table elements
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008403 my ($ClassId, $LibVersion) = @_;
8404 my @Bases = get_base_classes($ClassId, $LibVersion, 1);
8405 my @Elements = ();
8406 foreach my $BaseId (@Bases, $ClassId)
8407 {
Andrey Ponomarenko85043792012-05-14 16:48:07 +04008408 if(my $BName = get_TypeName($BaseId, $LibVersion))
8409 {
8410 if(defined $VirtualTable{$LibVersion}{$BName})
8411 {
8412 my @VFunctions = keys(%{$VirtualTable{$LibVersion}{$BName}});
8413 @VFunctions = sort {int($CompleteSignature{$LibVersion}{$a}{"Line"}) <=> int($CompleteSignature{$LibVersion}{$b}{"Line"})} @VFunctions;
8414 foreach my $VFunc (@VFunctions) {
8415 push(@Elements, $VFunc);
8416 }
8417 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008418 }
8419 }
8420 return @Elements;
8421}
8422
8423sub getVShift($$)
8424{
8425 my ($ClassId, $LibVersion) = @_;
8426 my @Bases = get_base_classes($ClassId, $LibVersion, 1);
8427 my $VShift = 0;
8428 foreach my $BaseId (@Bases)
8429 {
Andrey Ponomarenko85043792012-05-14 16:48:07 +04008430 if(my $BName = get_TypeName($BaseId, $LibVersion))
8431 {
8432 if(defined $VirtualTable{$LibVersion}{$BName}) {
8433 $VShift+=keys(%{$VirtualTable{$LibVersion}{$BName}});
8434 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008435 }
8436 }
8437 return $VShift;
8438}
8439
8440sub getShift($$)
8441{
8442 my ($ClassId, $LibVersion) = @_;
8443 my @Bases = get_base_classes($ClassId, $LibVersion, 0);
8444 my $Shift = 0;
8445 foreach my $BaseId (@Bases)
8446 {
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04008447 if(my $Size = get_TypeSize($BaseId, $LibVersion))
8448 {
8449 if($Size!=1)
8450 { # not empty base class
8451 $Shift+=$Size;
8452 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008453 }
8454 }
8455 return $Shift;
8456}
8457
Andrey Ponomarenko16934472012-03-29 15:37:04 +04008458sub getVTable_Size($$)
8459{ # number of v-table elements
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008460 my ($ClassName, $LibVersion) = @_;
Andrey Ponomarenko16934472012-03-29 15:37:04 +04008461 my $Size = 0;
8462 # three approaches
8463 if(not $Size)
8464 { # real size
8465 if(my %VTable = getVTable_Real($ClassName, $LibVersion)) {
8466 $Size = keys(%VTable);
8467 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008468 }
Andrey Ponomarenko16934472012-03-29 15:37:04 +04008469 if(not $Size)
8470 { # shared library symbol size
8471 if($Size = getSymbolSize($ClassVTable{$ClassName}, $LibVersion)) {
8472 $Size /= $WORD_SIZE{$LibVersion};
8473 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008474 }
Andrey Ponomarenko16934472012-03-29 15:37:04 +04008475 if(not $Size)
8476 { # model size
8477 if(defined $VirtualTable_Model{$LibVersion}{$ClassName}) {
8478 $Size = keys(%{$VirtualTable_Model{$LibVersion}{$ClassName}}) + 2;
8479 }
8480 }
8481 return $Size;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008482}
8483
8484sub isCopyingClass($$)
8485{
8486 my ($TypeId, $LibVersion) = @_;
8487 return $TypeInfo{$LibVersion}{$Tid_TDid{$LibVersion}{$TypeId}}{$TypeId}{"Copied"};
8488}
8489
8490sub isLeafClass($$)
8491{
8492 my ($ClassId, $LibVersion) = @_;
8493 return (not keys(%{$Class_SubClasses{$LibVersion}{$ClassId}}));
8494}
8495
8496sub havePubFields($)
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04008497{ # check structured type for public fields
8498 return isAccessible($_[0], {}, 0, -1);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008499}
8500
8501sub isAccessible($$$$)
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04008502{ # check interval in structured type for public fields
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008503 my ($TypePtr, $Skip, $Start, $End) = @_;
8504 return 0 if(not $TypePtr);
8505 if($End==-1) {
8506 $End = keys(%{$TypePtr->{"Memb"}})-1;
8507 }
8508 foreach my $MemPos (keys(%{$TypePtr->{"Memb"}}))
8509 {
8510 if($Skip and $Skip->{$MemPos})
8511 { # skip removed/added fields
8512 next;
8513 }
8514 if(int($MemPos)>=$Start and int($MemPos)<=$End)
8515 {
8516 if(isPublic($TypePtr, $MemPos)) {
8517 return ($MemPos+1);
8518 }
8519 }
8520 }
8521 return 0;
8522}
8523
8524sub getAlignment($$$)
8525{
8526 my ($Pos, $TypePtr, $LibVersion) = @_;
8527 my $Tid = $TypePtr->{"Memb"}{$Pos}{"type"};
8528 my %Type = get_PureType($Tid_TDid{$LibVersion}{$Tid}, $Tid, $LibVersion);
8529 my $TSize = $Type{"Size"}*$BYTE_SIZE;
8530 my $MSize = $Type{"Size"}*$BYTE_SIZE;
8531 if(my $BSize = $TypePtr->{"Memb"}{$Pos}{"bitfield"})
8532 { # bitfields
8533 ($TSize, $MSize) = ($WORD_SIZE{$LibVersion}*$BYTE_SIZE, $BSize);
8534 }
8535 elsif($Type{"Type"} eq "Array")
8536 { # in the context of function parameter
8537 # it's passed through the pointer
8538 }
8539 # alignment
8540 my $Alignment = $WORD_SIZE{$LibVersion}*$BYTE_SIZE; # default
8541 if(my $Computed = $TypePtr->{"Memb"}{$Pos}{"algn"})
8542 { # computed by GCC
8543 $Alignment = $Computed*$BYTE_SIZE;
8544 }
8545 elsif($TypePtr->{"Memb"}{$Pos}{"bitfield"})
8546 { # bitfields are 1 bit aligned
8547 $Alignment = 1;
8548 }
8549 elsif($TSize and $TSize<$WORD_SIZE{$LibVersion}*$BYTE_SIZE)
8550 { # model
8551 $Alignment = $TSize;
8552 }
8553 return ($Alignment, $MSize);
8554}
8555
8556sub getOffset($$$)
8557{ # offset of the field including padding
8558 my ($FieldPos, $TypePtr, $LibVersion) = @_;
8559 my $Offset = 0;
8560 foreach my $Pos (0 .. keys(%{$TypePtr->{"Memb"}})-1)
8561 {
8562 my ($Alignment, $MSize) = getAlignment($Pos, $TypePtr, $LibVersion);
8563 # padding
8564 my $Padding = 0;
8565 if($Offset % $Alignment!=0)
8566 { # not aligned, add padding
8567 $Padding = $Alignment - $Offset % $Alignment;
8568 }
8569 $Offset += $Padding;
8570 if($Pos==$FieldPos)
8571 { # after the padding
8572 # before the field
8573 return $Offset;
8574 }
8575 $Offset += $MSize;
8576 }
8577 return $FieldPos;# if something is going wrong
8578}
8579
8580sub isMemPadded($$$$$)
8581{ # check if the target field can be added/removed/changed
8582 # without shifting other fields because of padding bits
8583 my ($FieldPos, $Size, $TypePtr, $Skip, $LibVersion) = @_;
8584 return 0 if($FieldPos==0);
8585 if(defined $TypePtr->{"Memb"}{""})
8586 {
8587 delete($TypePtr->{"Memb"}{""});
8588 if($Debug) {
8589 printMsg("WARNING", "internal error detected");
8590 }
8591 }
8592 my $Offset = 0;
8593 my (%Alignment, %MSize) = ();
8594 my $MaxAlgn = 0;
8595 my $End = keys(%{$TypePtr->{"Memb"}})-1;
8596 my $NextField = $FieldPos+1;
8597 foreach my $Pos (0 .. $End)
8598 {
8599 if($Skip and $Skip->{$Pos})
8600 { # skip removed/added fields
8601 if($Pos > $FieldPos)
8602 { # after the target
8603 $NextField += 1;
8604 next;
8605 }
8606 }
8607 ($Alignment{$Pos}, $MSize{$Pos}) = getAlignment($Pos, $TypePtr, $LibVersion);
8608 if($Alignment{$Pos}>$MaxAlgn) {
8609 $MaxAlgn = $Alignment{$Pos};
8610 }
8611 if($Pos==$FieldPos)
8612 {
8613 if($Size==-1)
8614 { # added/removed fields
8615 if($Pos!=$End)
8616 { # skip target field and see
8617 # if enough padding will be
8618 # created on the next step
8619 # to include this field
8620 next;
8621 }
8622 }
8623 }
8624 # padding
8625 my $Padding = 0;
8626 if($Offset % $Alignment{$Pos}!=0)
8627 { # not aligned, add padding
8628 $Padding = $Alignment{$Pos} - $Offset % $Alignment{$Pos};
8629 }
8630 if($Pos==$NextField)
8631 { # try to place target field in the padding
8632 if($Size==-1)
8633 { # added/removed fields
8634 my $TPadding = 0;
8635 if($Offset % $Alignment{$FieldPos}!=0)
8636 {# padding of the target field
8637 $TPadding = $Alignment{$FieldPos} - $Offset % $Alignment{$FieldPos};
8638 }
8639 if($TPadding+$MSize{$FieldPos}<=$Padding)
8640 { # enough padding to place target field
8641 return 1;
8642 }
8643 else {
8644 return 0;
8645 }
8646 }
8647 else
8648 { # changed fields
8649 my $Delta = $Size-$MSize{$FieldPos};
8650 if($Delta>=0)
8651 { # increased
8652 if($Size-$MSize{$FieldPos}<=$Padding)
8653 { # enough padding to change target field
8654 return 1;
8655 }
8656 else {
8657 return 0;
8658 }
8659 }
8660 else
8661 { # decreased
8662 $Delta = abs($Delta);
8663 if($Delta+$Padding>=$MSize{$Pos})
8664 { # try to place the next field
8665 if(($Offset-$Delta) % $Alignment{$Pos} != 0)
8666 { # padding of the next field in new place
8667 my $NPadding = $Alignment{$Pos} - ($Offset-$Delta) % $Alignment{$Pos};
8668 if($NPadding+$MSize{$Pos}<=$Delta+$Padding)
8669 { # enough delta+padding to store next field
8670 return 0;
8671 }
8672 }
8673 else
8674 {
8675 return 0;
8676 }
8677 }
8678 return 1;
8679 }
8680 }
8681 }
8682 elsif($Pos==$End)
8683 { # target field is the last field
8684 if($Size==-1)
8685 { # added/removed fields
8686 if($Offset % $MaxAlgn!=0)
8687 { # tail padding
8688 my $TailPadding = $MaxAlgn - $Offset % $MaxAlgn;
8689 if($Padding+$MSize{$Pos}<=$TailPadding)
8690 { # enough tail padding to place the last field
8691 return 1;
8692 }
8693 }
8694 return 0;
8695 }
8696 else
8697 { # changed fields
8698 # scenario #1
8699 my $Offset1 = $Offset+$Padding+$MSize{$Pos};
8700 if($Offset1 % $MaxAlgn != 0)
8701 { # tail padding
8702 $Offset1 += $MaxAlgn - $Offset1 % $MaxAlgn;
8703 }
8704 # scenario #2
8705 my $Offset2 = $Offset+$Padding+$Size;
8706 if($Offset2 % $MaxAlgn != 0)
8707 { # tail padding
8708 $Offset2 += $MaxAlgn - $Offset2 % $MaxAlgn;
8709 }
8710 if($Offset1!=$Offset2)
8711 { # different sizes of structure
8712 return 0;
8713 }
8714 return 1;
8715 }
8716 }
8717 $Offset += $Padding+$MSize{$Pos};
8718 }
8719 return 0;
8720}
8721
8722sub isReserved($)
8723{ # reserved fields == private
8724 my $MName = $_[0];
8725 if($MName=~/reserved|padding|f_spare/i) {
8726 return 1;
8727 }
8728 if($MName=~/\A[_]*(spare|pad|unused)[_]*\Z/i) {
8729 return 1;
8730 }
8731 if($MName=~/(pad\d+)/i) {
8732 return 1;
8733 }
8734 return 0;
8735}
8736
8737sub isPublic($$)
8738{
8739 my ($TypePtr, $FieldPos) = @_;
8740 return 0 if(not $TypePtr);
8741 return 0 if(not defined $TypePtr->{"Memb"}{$FieldPos});
8742 return 0 if(not defined $TypePtr->{"Memb"}{$FieldPos}{"name"});
8743 if(not $TypePtr->{"Memb"}{$FieldPos}{"access"})
8744 { # by name in C language
8745 # FIXME: add other methods to detect private members
8746 my $MName = $TypePtr->{"Memb"}{$FieldPos}{"name"};
8747 if($MName=~/priv|abidata|parent_object/i)
8748 { # C-styled private data
8749 return 0;
8750 }
8751 if(lc($MName) eq "abi")
8752 { # ABI information/reserved field
8753 return 0;
8754 }
8755 if(isReserved($MName))
8756 { # reserved fields
8757 return 0;
8758 }
8759 return 1;
8760 }
8761 elsif($TypePtr->{"Memb"}{$FieldPos}{"access"} ne "private")
8762 { # by access in C++ language
8763 return 1;
8764 }
8765 return 0;
8766}
8767
Andrey Ponomarenko16934472012-03-29 15:37:04 +04008768sub getVTable_Real($$)
8769{
8770 my ($ClassName, $LibVersion) = @_;
8771 if(my $ClassId = $TName_Tid{$LibVersion}{$ClassName})
8772 {
8773 my %Type = get_Type($Tid_TDid{$LibVersion}{$ClassId}, $ClassId, $LibVersion);
8774 if(defined $Type{"VTable"}) {
8775 return %{$Type{"VTable"}};
8776 }
8777 }
8778 return ();
8779}
8780
8781sub cmpVTables($)
8782{
8783 my $ClassName = $_[0];
8784 my $Res = cmpVTables_Real($ClassName, 1);
8785 if($Res==-1) {
8786 $Res = cmpVTables_Model($ClassName);
8787 }
8788 return $Res;
8789}
8790
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008791sub cmpVTables_Model($)
8792{
8793 my $ClassName = $_[0];
Andrey Ponomarenko16934472012-03-29 15:37:04 +04008794 foreach my $Symbol (keys(%{$VirtualTable_Model{1}{$ClassName}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008795 {
Andrey Ponomarenko16934472012-03-29 15:37:04 +04008796 if(not defined $VirtualTable_Model{2}{$ClassName}{$Symbol}) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008797 return 1;
8798 }
8799 }
8800 return 0;
8801}
8802
Andrey Ponomarenko16934472012-03-29 15:37:04 +04008803sub cmpVTables_Real($$)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008804{
8805 my ($ClassName, $Strong) = @_;
Andrey Ponomarenko16934472012-03-29 15:37:04 +04008806 if(defined $Cache{"cmpVTables_Real"}{$Strong}{$ClassName}) {
8807 return $Cache{"cmpVTables_Real"}{$Strong}{$ClassName};
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04008808 }
Andrey Ponomarenko16934472012-03-29 15:37:04 +04008809 my %VTable_Old = getVTable_Real($ClassName, 1);
8810 my %VTable_New = getVTable_Real($ClassName, 2);
8811 if(not %VTable_Old or not %VTable_New)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008812 { # old ABI dumps
Andrey Ponomarenko16934472012-03-29 15:37:04 +04008813 return ($Cache{"cmpVTables_Real"}{$Strong}{$ClassName} = -1);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008814 }
Andrey Ponomarenko16934472012-03-29 15:37:04 +04008815 my %Indexes = map {$_=>1} (keys(%VTable_Old), keys(%VTable_New));
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008816 foreach my $Offset (sort {int($a)<=>int($b)} keys(%Indexes))
8817 {
Andrey Ponomarenko16934472012-03-29 15:37:04 +04008818 if(not defined $VTable_Old{$Offset})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008819 { # v-table v.1 < v-table v.2
Andrey Ponomarenko16934472012-03-29 15:37:04 +04008820 return ($Cache{"cmpVTables_Real"}{$Strong}{$ClassName} = $Strong);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008821 }
Andrey Ponomarenko16934472012-03-29 15:37:04 +04008822 my $Entry1 = $VTable_Old{$Offset};
8823 if(not defined $VTable_New{$Offset})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008824 { # v-table v.1 > v-table v.2
Andrey Ponomarenko16934472012-03-29 15:37:04 +04008825 return ($Cache{"cmpVTables_Real"}{$Strong}{$ClassName} = ($Strong or $Entry1!~/__cxa_pure_virtual/));
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008826 }
Andrey Ponomarenko16934472012-03-29 15:37:04 +04008827 my $Entry2 = $VTable_New{$Offset};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008828 $Entry1 = simpleVEntry($Entry1);
8829 $Entry2 = simpleVEntry($Entry2);
8830 if($Entry1 ne $Entry2)
8831 { # register as changed
8832 if($Entry1=~/::([^:]+)\Z/)
8833 {
8834 my $M1 = $1;
8835 if($Entry2=~/::([^:]+)\Z/)
8836 {
8837 my $M2 = $1;
8838 if($M1 eq $M2)
8839 { # overridden
8840 next;
8841 }
8842 }
8843 }
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04008844 if(differentDumps("G"))
8845 {
8846 if($Entry1=~/\A\-(0x|\d+)/ and $Entry2=~/\A\-(0x|\d+)/)
8847 {
8848 # GCC 4.6.1: -0x00000000000000010
8849 # GCC 4.7.0: -16
8850 next;
8851 }
8852 }
Andrey Ponomarenko16934472012-03-29 15:37:04 +04008853 return ($Cache{"cmpVTables_Real"}{$Strong}{$ClassName} = 1);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008854 }
8855 }
Andrey Ponomarenko16934472012-03-29 15:37:04 +04008856 return ($Cache{"cmpVTables_Real"}{$Strong}{$ClassName} = 0);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008857}
8858
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04008859sub mergeVTables($)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008860{ # merging v-tables without diagnostics
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04008861 my $Level = $_[0];
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008862 foreach my $ClassName (keys(%{$VirtualTable{1}}))
8863 {
Andrey Ponomarenko16934472012-03-29 15:37:04 +04008864 if($VTableChanged_M{$ClassName})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008865 { # already registered
8866 next;
8867 }
Andrey Ponomarenko16934472012-03-29 15:37:04 +04008868 if(cmpVTables_Real($ClassName, 0)==1)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008869 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04008870 my @Affected = (keys(%{$ClassMethods{$Level}{1}{$ClassName}}));
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008871 foreach my $Symbol (@Affected)
8872 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04008873 %{$CompatProblems{$Level}{$Symbol}{"Virtual_Table_Changed_Unknown"}{$ClassName}}=(
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008874 "Type_Name"=>$ClassName,
8875 "Type_Type"=>"Class",
8876 "Target"=>$ClassName);
8877 }
8878 }
8879 }
8880}
8881
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04008882sub mergeBases($)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008883{
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04008884 my $Level = $_[0];
Andrey Ponomarenko16934472012-03-29 15:37:04 +04008885 foreach my $ClassName (keys(%{$ClassNames{1}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008886 { # detect added and removed virtual functions
Andrey Ponomarenko16934472012-03-29 15:37:04 +04008887 my $ClassId = $TName_Tid{1}{$ClassName};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008888 next if(not $ClassId);
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04008889 if(defined $VirtualTable{2}{$ClassName})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008890 {
Andrey Ponomarenko16934472012-03-29 15:37:04 +04008891 foreach my $Symbol (keys(%{$VirtualTable{2}{$ClassName}}))
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04008892 {
Andrey Ponomarenko16934472012-03-29 15:37:04 +04008893 if($TName_Tid{1}{$ClassName}
8894 and not defined $VirtualTable{1}{$ClassName}{$Symbol})
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04008895 { # added to v-table
Andrey Ponomarenko16934472012-03-29 15:37:04 +04008896 if(defined $CompleteSignature{1}{$Symbol}
8897 and $CompleteSignature{1}{$Symbol}{"Virt"})
8898 { # override some method in v.1
8899 next;
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04008900 }
Andrey Ponomarenko16934472012-03-29 15:37:04 +04008901 $AddedInt_Virt{$Level}{$ClassName}{$Symbol} = 1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008902 }
8903 }
8904 }
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04008905 if(defined $VirtualTable{1}{$ClassName})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008906 {
Andrey Ponomarenko16934472012-03-29 15:37:04 +04008907 foreach my $Symbol (keys(%{$VirtualTable{1}{$ClassName}}))
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04008908 {
Andrey Ponomarenko16934472012-03-29 15:37:04 +04008909 if($TName_Tid{2}{$ClassName}
8910 and not defined $VirtualTable{2}{$ClassName}{$Symbol})
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04008911 { # removed from v-table
Andrey Ponomarenko16934472012-03-29 15:37:04 +04008912 if(defined $CompleteSignature{2}{$Symbol}
8913 and $CompleteSignature{2}{$Symbol}{"Virt"})
8914 { # override some method in v.2
8915 next;
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04008916 }
Andrey Ponomarenko16934472012-03-29 15:37:04 +04008917 $RemovedInt_Virt{$Level}{$ClassName}{$Symbol} = 1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008918 }
8919 }
8920 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04008921 if($Level eq "Binary")
8922 { # Binary-level
8923 my %Class_Type = get_Type($Tid_TDid{1}{$ClassId}, $ClassId, 1);
8924 foreach my $AddedVFunc (keys(%{$AddedInt_Virt{$Level}{$ClassName}}))
8925 { # check replacements, including pure virtual methods
8926 my $AddedPos = $VirtualTable{2}{$ClassName}{$AddedVFunc};
8927 foreach my $RemovedVFunc (keys(%{$RemovedInt_Virt{$Level}{$ClassName}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008928 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04008929 my $RemovedPos = $VirtualTable{1}{$ClassName}{$RemovedVFunc};
8930 if($AddedPos==$RemovedPos)
8931 {
8932 $VirtualReplacement{$AddedVFunc} = $RemovedVFunc;
8933 $VirtualReplacement{$RemovedVFunc} = $AddedVFunc;
8934 last; # other methods will be reported as "added" or "removed"
8935 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008936 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04008937 if(my $RemovedVFunc = $VirtualReplacement{$AddedVFunc})
8938 {
8939 if(lc($AddedVFunc) eq lc($RemovedVFunc))
8940 { # skip: DomUi => DomUI parameter (Qt 4.2.3 to 4.3.0)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008941 next;
8942 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04008943 my $ProblemType = "Virtual_Replacement";
8944 my @Affected = ($RemovedVFunc);
8945 if($CompleteSignature{1}{$RemovedVFunc}{"PureVirt"})
8946 { # pure methods
8947 if(not isUsedClass($ClassId, 1, $Level))
8948 { # not a parameter of some exported method
8949 next;
8950 }
8951 $ProblemType = "Pure_Virtual_Replacement";
8952 @Affected = (keys(%{$ClassMethods{$Level}{1}{$ClassName}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008953 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04008954 foreach my $AffectedInt (@Affected)
8955 {
8956 if($CompleteSignature{1}{$AffectedInt}{"PureVirt"})
8957 { # affected exported methods only
8958 next;
8959 }
8960 %{$CompatProblems{$Level}{$AffectedInt}{$ProblemType}{$tr_name{$AddedVFunc}}}=(
8961 "Type_Name"=>$Class_Type{"Name"},
8962 "Type_Type"=>"Class",
8963 "Target"=>get_Signature($AddedVFunc, 2),
8964 "Old_Value"=>get_Signature($RemovedVFunc, 1));
8965 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008966 }
8967 }
8968 }
8969 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04008970 if(not checkDumpVersion(1, "2.0")
8971 or not checkDumpVersion(2, "2.0"))
8972 { # support for old ABI dumps
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008973 # "Base" attribute introduced in ACC 1.22 (dump 2.0 format)
8974 return;
8975 }
Andrey Ponomarenko16934472012-03-29 15:37:04 +04008976 foreach my $ClassName (sort keys(%{$ClassNames{1}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008977 {
Andrey Ponomarenko16934472012-03-29 15:37:04 +04008978 my $ClassId_Old = $TName_Tid{1}{$ClassName};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008979 next if(not $ClassId_Old);
8980 if(not isCreatable($ClassId_Old, 1))
8981 { # skip classes without public constructors (including auto-generated)
8982 # example: class has only a private exported or private inline constructor
8983 next;
8984 }
8985 if($ClassName=~/>/)
8986 { # skip affected template instances
8987 next;
8988 }
8989 my %Class_Old = get_Type($Tid_TDid{1}{$ClassId_Old}, $ClassId_Old, 1);
Andrey Ponomarenko16934472012-03-29 15:37:04 +04008990 my $ClassId_New = $TName_Tid{2}{$ClassName};
Andrey Ponomarenko85043792012-05-14 16:48:07 +04008991 if(not $ClassId_New) {
8992 next;
8993 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008994 my %Class_New = get_Type($Tid_TDid{2}{$ClassId_New}, $ClassId_New, 2);
Andrey Ponomarenko85043792012-05-14 16:48:07 +04008995 if($Class_New{"Type"}!~/Class|Struct/)
8996 { # became typedef
8997 if($Level eq "Binary") {
8998 next;
8999 }
9000 if($Level eq "Source")
9001 {
9002 %Class_New = get_PureType($Tid_TDid{2}{$ClassId_New}, $ClassId_New, 2);
9003 if($Class_New{"Type"}!~/Class|Struct/) {
9004 next;
9005 }
9006 $ClassId_New = $Class_New{"Tid"};
9007 }
9008 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009009 my @Bases_Old = sort {$Class_Old{"Base"}{$a}{"pos"}<=>$Class_Old{"Base"}{$b}{"pos"}} keys(%{$Class_Old{"Base"}});
9010 my @Bases_New = sort {$Class_New{"Base"}{$a}{"pos"}<=>$Class_New{"Base"}{$b}{"pos"}} keys(%{$Class_New{"Base"}});
9011 my ($BNum1, $BNum2) = (1, 1);
9012 my %BasePos_Old = map {get_TypeName($_, 1) => $BNum1++} @Bases_Old;
9013 my %BasePos_New = map {get_TypeName($_, 2) => $BNum2++} @Bases_New;
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04009014 my %ShortBase_Old = map {get_ShortType($_, 1) => 1} @Bases_Old;
9015 my %ShortBase_New = map {get_ShortType($_, 2) => 1} @Bases_New;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009016 my $Shift_Old = getShift($ClassId_Old, 1);
9017 my $Shift_New = getShift($ClassId_New, 2);
9018 my %BaseId_New = map {get_TypeName($_, 2) => $_} @Bases_New;
9019 my ($Added, $Removed) = (0, 0);
9020 my @StableBases_Old = ();
9021 foreach my $BaseId (@Bases_Old)
9022 {
9023 my $BaseName = get_TypeName($BaseId, 1);
9024 if($BasePos_New{$BaseName}) {
9025 push(@StableBases_Old, $BaseId);
9026 }
9027 elsif(not $ShortBase_New{$BaseName}
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04009028 and not $ShortBase_New{get_ShortType($BaseId, 1)})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009029 { # removed base
9030 # excluding namespace::SomeClass to SomeClass renaming
9031 my $ProblemKind = "Removed_Base_Class";
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04009032 if($Level eq "Binary")
9033 { # Binary-level
9034 if($Shift_Old ne $Shift_New)
9035 { # affected fields
9036 if(havePubFields(\%Class_Old)) {
9037 $ProblemKind .= "_And_Shift";
9038 }
9039 elsif($Class_Old{"Size"} ne $Class_New{"Size"}) {
9040 $ProblemKind .= "_And_Size";
9041 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009042 }
Andrey Ponomarenko16934472012-03-29 15:37:04 +04009043 if(keys(%{$VirtualTable_Model{1}{$BaseName}})
9044 and cmpVTables($ClassName)==1)
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04009045 { # affected v-table
9046 $ProblemKind .= "_And_VTable";
Andrey Ponomarenko16934472012-03-29 15:37:04 +04009047 $VTableChanged_M{$ClassName}=1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009048 }
9049 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04009050 my @Affected = keys(%{$ClassMethods{$Level}{1}{$ClassName}});
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009051 foreach my $SubId (get_sub_classes($ClassId_Old, 1, 1))
9052 {
9053 my $SubName = get_TypeName($SubId, 1);
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04009054 push(@Affected, keys(%{$ClassMethods{$Level}{1}{$SubName}}));
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009055 if($ProblemKind=~/VTable/) {
Andrey Ponomarenko16934472012-03-29 15:37:04 +04009056 $VTableChanged_M{$SubName}=1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009057 }
9058 }
9059 foreach my $Interface (@Affected)
9060 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04009061 %{$CompatProblems{$Level}{$Interface}{$ProblemKind}{"this"}}=(
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009062 "Type_Name"=>$ClassName,
9063 "Type_Type"=>"Class",
9064 "Target"=>$BaseName,
9065 "Old_Size"=>$Class_Old{"Size"}*$BYTE_SIZE,
9066 "New_Size"=>$Class_New{"Size"}*$BYTE_SIZE,
9067 "Shift"=>abs($Shift_New-$Shift_Old) );
9068 }
9069 $Removed+=1;
9070 }
9071 }
9072 my @StableBases_New = ();
9073 foreach my $BaseId (@Bases_New)
9074 {
9075 my $BaseName = get_TypeName($BaseId, 2);
9076 if($BasePos_Old{$BaseName}) {
9077 push(@StableBases_New, $BaseId);
9078 }
9079 elsif(not $ShortBase_Old{$BaseName}
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04009080 and not $ShortBase_Old{get_ShortType($BaseId, 2)})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009081 { # added base
9082 # excluding namespace::SomeClass to SomeClass renaming
9083 my $ProblemKind = "Added_Base_Class";
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04009084 if($Level eq "Binary")
9085 { # Binary-level
9086 if($Shift_Old ne $Shift_New)
9087 { # affected fields
9088 if(havePubFields(\%Class_Old)) {
9089 $ProblemKind .= "_And_Shift";
9090 }
9091 elsif($Class_Old{"Size"} ne $Class_New{"Size"}) {
9092 $ProblemKind .= "_And_Size";
9093 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009094 }
Andrey Ponomarenko16934472012-03-29 15:37:04 +04009095 if(keys(%{$VirtualTable_Model{2}{$BaseName}})
9096 and cmpVTables($ClassName)==1)
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04009097 { # affected v-table
9098 $ProblemKind .= "_And_VTable";
Andrey Ponomarenko16934472012-03-29 15:37:04 +04009099 $VTableChanged_M{$ClassName}=1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009100 }
9101 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04009102 my @Affected = keys(%{$ClassMethods{$Level}{1}{$ClassName}});
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009103 foreach my $SubId (get_sub_classes($ClassId_Old, 1, 1))
9104 {
9105 my $SubName = get_TypeName($SubId, 1);
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04009106 push(@Affected, keys(%{$ClassMethods{$Level}{1}{$SubName}}));
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009107 if($ProblemKind=~/VTable/) {
Andrey Ponomarenko16934472012-03-29 15:37:04 +04009108 $VTableChanged_M{$SubName}=1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009109 }
9110 }
9111 foreach my $Interface (@Affected)
9112 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04009113 %{$CompatProblems{$Level}{$Interface}{$ProblemKind}{"this"}}=(
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009114 "Type_Name"=>$ClassName,
9115 "Type_Type"=>"Class",
9116 "Target"=>$BaseName,
9117 "Old_Size"=>$Class_Old{"Size"}*$BYTE_SIZE,
9118 "New_Size"=>$Class_New{"Size"}*$BYTE_SIZE,
9119 "Shift"=>abs($Shift_New-$Shift_Old) );
9120 }
9121 $Added+=1;
9122 }
9123 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04009124 if($Level eq "Binary")
9125 { # Binary-level
9126 ($BNum1, $BNum2) = (1, 1);
9127 my %BaseRelPos_Old = map {get_TypeName($_, 1) => $BNum1++} @StableBases_Old;
9128 my %BaseRelPos_New = map {get_TypeName($_, 2) => $BNum2++} @StableBases_New;
9129 foreach my $BaseId (@Bases_Old)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009130 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04009131 my $BaseName = get_TypeName($BaseId, 1);
9132 if(my $NewPos = $BaseRelPos_New{$BaseName})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009133 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04009134 my $BaseNewId = $BaseId_New{$BaseName};
9135 my $OldPos = $BaseRelPos_Old{$BaseName};
9136 if($NewPos!=$OldPos)
9137 { # changed position of the base class
9138 foreach my $Interface (keys(%{$ClassMethods{$Level}{1}{$ClassName}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009139 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04009140 %{$CompatProblems{$Level}{$Interface}{"Base_Class_Position"}{"this"}}=(
9141 "Type_Name"=>$ClassName,
9142 "Type_Type"=>"Class",
9143 "Target"=>$BaseName,
9144 "Old_Value"=>$OldPos-1,
9145 "New_Value"=>$NewPos-1 );
9146 }
9147 }
9148 if($Class_Old{"Base"}{$BaseId}{"virtual"}
9149 and not $Class_New{"Base"}{$BaseNewId}{"virtual"})
9150 { # became non-virtual base
9151 foreach my $Interface (keys(%{$ClassMethods{$Level}{1}{$ClassName}}))
9152 {
9153 %{$CompatProblems{$Level}{$Interface}{"Base_Class_Became_Non_Virtually_Inherited"}{"this->".$BaseName}}=(
9154 "Type_Name"=>$ClassName,
9155 "Type_Type"=>"Class",
9156 "Target"=>$BaseName );
9157 }
9158 }
9159 elsif(not $Class_Old{"Base"}{$BaseId}{"virtual"}
9160 and $Class_New{"Base"}{$BaseNewId}{"virtual"})
9161 { # became virtual base
9162 foreach my $Interface (keys(%{$ClassMethods{$Level}{1}{$ClassName}}))
9163 {
9164 %{$CompatProblems{$Level}{$Interface}{"Base_Class_Became_Virtually_Inherited"}{"this->".$BaseName}}=(
9165 "Type_Name"=>$ClassName,
9166 "Type_Type"=>"Class",
9167 "Target"=>$BaseName );
9168 }
9169 }
9170 }
9171 }
9172 # detect size changes in base classes
9173 if($Shift_Old!=$Shift_New)
9174 { # size of allocable class
9175 foreach my $BaseId (@StableBases_Old)
9176 { # search for changed base
9177 my %BaseType = get_Type($Tid_TDid{1}{$BaseId}, $BaseId, 1);
9178 my $Size_Old = get_TypeSize($BaseId, 1);
9179 my $Size_New = get_TypeSize($BaseId_New{$BaseType{"Name"}}, 2);
9180 if($Size_Old ne $Size_New
9181 and $Size_Old and $Size_New)
9182 {
9183 my $ProblemType = "";
9184 if(isCopyingClass($BaseId, 1)) {
9185 $ProblemType = "Size_Of_Copying_Class";
9186 }
9187 elsif($AllocableClass{1}{$BaseType{"Name"}})
9188 {
9189 if($Size_New>$Size_Old)
9190 { # increased size
9191 $ProblemType = "Size_Of_Allocable_Class_Increased";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009192 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04009193 else
9194 { # decreased size
9195 $ProblemType = "Size_Of_Allocable_Class_Decreased";
9196 if(not havePubFields(\%Class_Old))
9197 { # affected class has no public members
9198 next;
9199 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009200 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04009201 }
9202 next if(not $ProblemType);
9203 foreach my $Interface (keys(%{$ClassMethods{$Level}{1}{$ClassName}}))
9204 { # base class size changes affecting current class
9205 %{$CompatProblems{$Level}{$Interface}{$ProblemType}{"this->".$BaseType{"Name"}}}=(
9206 "Type_Name"=>$BaseType{"Name"},
9207 "Type_Type"=>"Class",
9208 "Target"=>$BaseType{"Name"},
9209 "Old_Size"=>$Size_Old*$BYTE_SIZE,
9210 "New_Size"=>$Size_New*$BYTE_SIZE );
9211 }
9212 }
9213 }
9214 }
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04009215 if(defined $VirtualTable{1}{$ClassName}
Andrey Ponomarenko16934472012-03-29 15:37:04 +04009216 and cmpVTables_Real($ClassName, 1)==1
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04009217 and my @VFunctions = keys(%{$VirtualTable{1}{$ClassName}}))
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04009218 { # compare virtual tables size in base classes
9219 my $VShift_Old = getVShift($ClassId_Old, 1);
9220 my $VShift_New = getVShift($ClassId_New, 2);
9221 if($VShift_Old ne $VShift_New)
9222 { # changes in the base class or changes in the list of base classes
9223 my @AllBases_Old = get_base_classes($ClassId_Old, 1, 1);
9224 my @AllBases_New = get_base_classes($ClassId_New, 2, 1);
9225 ($BNum1, $BNum2) = (1, 1);
9226 my %StableBase = map {get_TypeName($_, 2) => $_} @AllBases_New;
9227 foreach my $BaseId (@AllBases_Old)
9228 {
9229 my %BaseType = get_Type($Tid_TDid{1}{$BaseId}, $BaseId, 1);
9230 if(not $StableBase{$BaseType{"Name"}})
9231 { # lost base
9232 next;
9233 }
Andrey Ponomarenko16934472012-03-29 15:37:04 +04009234 my $VSize_Old = getVTable_Size($BaseType{"Name"}, 1);
9235 my $VSize_New = getVTable_Size($BaseType{"Name"}, 2);
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04009236 if($VSize_Old!=$VSize_New)
9237 {
Andrey Ponomarenko85043792012-05-14 16:48:07 +04009238 foreach my $Symbol (@VFunctions)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009239 {
Andrey Ponomarenko85043792012-05-14 16:48:07 +04009240 if(not defined $VirtualTable{2}{$ClassName}{$Symbol})
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04009241 { # Removed_Virtual_Method, will be registered in mergeVirtualTables()
9242 next;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009243 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +04009244 if($VirtualTable_Model{2}{$ClassName}{$Symbol}-$VirtualTable_Model{1}{$ClassName}{$Symbol}==0)
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04009245 { # skip interfaces that have not changed the absolute virtual position
9246 next;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009247 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +04009248 if(not symbolFilter($Symbol, 1, "Affected", $Level)) {
9249 next;
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04009250 }
Andrey Ponomarenko16934472012-03-29 15:37:04 +04009251 $VTableChanged_M{$BaseType{"Name"}} = 1;
9252 $VTableChanged_M{$ClassName} = 1;
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04009253 foreach my $VirtFunc (keys(%{$AddedInt_Virt{$Level}{$BaseType{"Name"}}}))
9254 { # the reason of the layout change: added virtual functions
9255 next if($VirtualReplacement{$VirtFunc});
9256 my $ProblemType = "Added_Virtual_Method";
9257 if($CompleteSignature{2}{$VirtFunc}{"PureVirt"}) {
9258 $ProblemType = "Added_Pure_Virtual_Method";
9259 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +04009260 %{$CompatProblems{$Level}{$Symbol}{$ProblemType}{get_Signature($VirtFunc, 2)}}=(
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04009261 "Type_Name"=>$BaseType{"Name"},
9262 "Type_Type"=>"Class",
9263 "Target"=>get_Signature($VirtFunc, 2) );
9264 }
9265 foreach my $VirtFunc (keys(%{$RemovedInt_Virt{$Level}{$BaseType{"Name"}}}))
9266 { # the reason of the layout change: removed virtual functions
9267 next if($VirtualReplacement{$VirtFunc});
9268 my $ProblemType = "Removed_Virtual_Method";
9269 if($CompleteSignature{1}{$VirtFunc}{"PureVirt"}) {
9270 $ProblemType = "Removed_Pure_Virtual_Method";
9271 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +04009272 %{$CompatProblems{$Level}{$Symbol}{$ProblemType}{get_Signature($VirtFunc, 1)}}=(
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04009273 "Type_Name"=>$BaseType{"Name"},
9274 "Type_Type"=>"Class",
9275 "Target"=>get_Signature($VirtFunc, 1) );
9276 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009277 }
9278 }
9279 }
9280 }
9281 }
9282 }
9283 }
9284}
9285
9286sub isCreatable($$)
9287{
9288 my ($ClassId, $LibVersion) = @_;
9289 if($AllocableClass{$LibVersion}{get_TypeName($ClassId, $LibVersion)}
9290 or isCopyingClass($ClassId, $LibVersion)) {
9291 return 1;
9292 }
9293 if(keys(%{$Class_SubClasses{$LibVersion}{$ClassId}}))
9294 { # Fix for incomplete data: if this class has
9295 # a base class then it should also has a constructor
9296 return 1;
9297 }
9298 if($ReturnedClass{$LibVersion}{$ClassId})
9299 { # returned by some method of this class
9300 # or any other class
9301 return 1;
9302 }
9303 return 0;
9304}
9305
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04009306sub isUsedClass($$$)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009307{
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04009308 my ($ClassId, $LibVersion, $Level) = @_;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009309 if(keys(%{$ParamClass{$LibVersion}{$ClassId}}))
9310 { # parameter of some exported method
9311 return 1;
9312 }
9313 my $CName = get_TypeName($ClassId, 1);
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04009314 if(keys(%{$ClassMethods{$Level}{1}{$CName}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009315 { # method from target class
9316 return 1;
9317 }
9318 return 0;
9319}
9320
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04009321sub mergeVirtualTables($$)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009322{ # check for changes in the virtual table
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04009323 my ($Interface, $Level) = @_;
Andrey Ponomarenko16934472012-03-29 15:37:04 +04009324 # affected methods:
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009325 # - virtual
9326 # - pure-virtual
9327 # - non-virtual
9328 if($CompleteSignature{1}{$Interface}{"Data"})
9329 { # global data is not affected
9330 return;
9331 }
9332 my $Class_Id = $CompleteSignature{1}{$Interface}{"Class"};
Andrey Ponomarenko16934472012-03-29 15:37:04 +04009333 if(not $Class_Id) {
9334 return;
9335 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009336 my $CName = get_TypeName($Class_Id, 1);
Andrey Ponomarenko16934472012-03-29 15:37:04 +04009337 if(cmpVTables_Real($CName, 1)==0)
9338 { # no changes
9339 return;
9340 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04009341 $CheckedTypes{$Level}{$CName} = 1;
9342 if($Level eq "Binary")
9343 { # Binary-level
9344 if($CompleteSignature{1}{$Interface}{"PureVirt"}
9345 and not isUsedClass($Class_Id, 1, $Level))
9346 { # pure virtuals should not be affected
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04009347 # if there are no exported methods using this class
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04009348 return;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009349 }
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04009350 }
9351 foreach my $Func (keys(%{$VirtualTable{1}{$CName}}))
9352 {
9353 if(defined $VirtualTable{2}{$CName}{$Func}
9354 and defined $CompleteSignature{2}{$Func})
9355 {
9356 if(not $CompleteSignature{1}{$Func}{"PureVirt"}
9357 and $CompleteSignature{2}{$Func}{"PureVirt"})
9358 { # became pure virtual
9359 %{$CompatProblems{$Level}{$Interface}{"Virtual_Method_Became_Pure"}{$tr_name{$Func}}}=(
9360 "Type_Name"=>$CName,
9361 "Type_Type"=>"Class",
9362 "Target"=>get_Signature_M($Func, 1) );
9363 $VTableChanged_M{$CName} = 1;
9364 }
9365 elsif($CompleteSignature{1}{$Func}{"PureVirt"}
9366 and not $CompleteSignature{2}{$Func}{"PureVirt"})
9367 { # became non-pure virtual
9368 %{$CompatProblems{$Level}{$Interface}{"Virtual_Method_Became_Non_Pure"}{$tr_name{$Func}}}=(
9369 "Type_Name"=>$CName,
9370 "Type_Type"=>"Class",
9371 "Target"=>get_Signature_M($Func, 1) );
9372 $VTableChanged_M{$CName} = 1;
9373 }
9374 }
9375 }
9376 if($Level eq "Binary")
9377 { # Binary-level
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04009378 # check virtual table structure
9379 foreach my $AddedVFunc (keys(%{$AddedInt_Virt{$Level}{$CName}}))
9380 {
9381 next if($Interface eq $AddedVFunc);
9382 next if($VirtualReplacement{$AddedVFunc});
9383 my $VPos_Added = $VirtualTable{2}{$CName}{$AddedVFunc};
9384 if($CompleteSignature{2}{$AddedVFunc}{"PureVirt"})
9385 { # pure virtual methods affect all others (virtual and non-virtual)
9386 %{$CompatProblems{$Level}{$Interface}{"Added_Pure_Virtual_Method"}{$tr_name{$AddedVFunc}}}=(
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009387 "Type_Name"=>$CName,
9388 "Type_Type"=>"Class",
9389 "Target"=>get_Signature($AddedVFunc, 2) );
Andrey Ponomarenko16934472012-03-29 15:37:04 +04009390 $VTableChanged_M{$CName} = 1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009391 }
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04009392 elsif(not defined $VirtualTable{1}{$CName}
9393 or $VPos_Added>keys(%{$VirtualTable{1}{$CName}}))
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04009394 { # added virtual function at the end of v-table
Andrey Ponomarenko16934472012-03-29 15:37:04 +04009395 if(not keys(%{$VirtualTable_Model{1}{$CName}}))
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04009396 { # became polymorphous class, added v-table pointer
9397 %{$CompatProblems{$Level}{$Interface}{"Added_First_Virtual_Method"}{$tr_name{$AddedVFunc}}}=(
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009398 "Type_Name"=>$CName,
9399 "Type_Type"=>"Class",
9400 "Target"=>get_Signature($AddedVFunc, 2) );
Andrey Ponomarenko16934472012-03-29 15:37:04 +04009401 $VTableChanged_M{$CName} = 1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009402 }
9403 else
9404 {
Andrey Ponomarenko16934472012-03-29 15:37:04 +04009405 my $VSize_Old = getVTable_Size($CName, 1);
9406 my $VSize_New = getVTable_Size($CName, 2);
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04009407 next if($VSize_Old==$VSize_New);# exception: register as removed and added virtual method
9408 if(isCopyingClass($Class_Id, 1))
9409 { # class has no constructors and v-table will be copied by applications, this may affect all methods
9410 my $ProblemType = "Added_Virtual_Method";
9411 if(isLeafClass($Class_Id, 1)) {
9412 $ProblemType = "Added_Virtual_Method_At_End_Of_Leaf_Copying_Class";
9413 }
9414 %{$CompatProblems{$Level}{$Interface}{$ProblemType}{$tr_name{$AddedVFunc}}}=(
9415 "Type_Name"=>$CName,
9416 "Type_Type"=>"Class",
9417 "Target"=>get_Signature($AddedVFunc, 2) );
Andrey Ponomarenko16934472012-03-29 15:37:04 +04009418 $VTableChanged_M{$CName} = 1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009419 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04009420 else
9421 {
9422 my $ProblemType = "Added_Virtual_Method";
9423 if(isLeafClass($Class_Id, 1)) {
9424 $ProblemType = "Added_Virtual_Method_At_End_Of_Leaf_Allocable_Class";
9425 }
9426 %{$CompatProblems{$Level}{$Interface}{$ProblemType}{$tr_name{$AddedVFunc}}}=(
9427 "Type_Name"=>$CName,
9428 "Type_Type"=>"Class",
9429 "Target"=>get_Signature($AddedVFunc, 2) );
Andrey Ponomarenko16934472012-03-29 15:37:04 +04009430 $VTableChanged_M{$CName} = 1;
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04009431 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009432 }
9433 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04009434 elsif($CompleteSignature{1}{$Interface}{"Virt"}
9435 or $CompleteSignature{1}{$Interface}{"PureVirt"})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009436 {
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04009437 if(defined $VirtualTable{1}{$CName}
9438 and defined $VirtualTable{2}{$CName})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009439 {
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04009440 my $VPos_Old = $VirtualTable{1}{$CName}{$Interface};
9441 my $VPos_New = $VirtualTable{2}{$CName}{$Interface};
9442 if($VPos_Added<=$VPos_Old and $VPos_Old!=$VPos_New)
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04009443 {
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04009444 my @Affected = ($Interface, keys(%{$OverriddenMethods{1}{$Interface}}));
9445 foreach my $ASymbol (@Affected)
9446 {
Andrey Ponomarenko85043792012-05-14 16:48:07 +04009447 if(not $CompleteSignature{1}{$ASymbol}{"PureVirt"})
9448 {
9449 if(symbolFilter($ASymbol, 1, "Affected", $Level)) {
9450 next;
9451 }
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04009452 }
9453 $CheckedSymbols{$Level}{$ASymbol} = 1;
9454 %{$CompatProblems{$Level}{$ASymbol}{"Added_Virtual_Method"}{$tr_name{$AddedVFunc}}}=(
9455 "Type_Name"=>$CName,
9456 "Type_Type"=>"Class",
9457 "Target"=>get_Signature($AddedVFunc, 2) );
Andrey Ponomarenko16934472012-03-29 15:37:04 +04009458 $VTableChanged_M{get_TypeName($CompleteSignature{1}{$ASymbol}{"Class"}, 1)} = 1;
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04009459 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009460 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009461 }
9462 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04009463 else {
9464 # safe
9465 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009466 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04009467 foreach my $RemovedVFunc (keys(%{$RemovedInt_Virt{$Level}{$CName}}))
9468 {
9469 next if($VirtualReplacement{$RemovedVFunc});
9470 if($RemovedVFunc eq $Interface
9471 and $CompleteSignature{1}{$RemovedVFunc}{"PureVirt"})
9472 { # This case is for removed virtual methods
9473 # implemented in both versions of a library
9474 next;
9475 }
Andrey Ponomarenko16934472012-03-29 15:37:04 +04009476 if(not keys(%{$VirtualTable_Model{2}{$CName}}))
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04009477 { # became non-polymorphous class, removed v-table pointer
9478 %{$CompatProblems{$Level}{$Interface}{"Removed_Last_Virtual_Method"}{$tr_name{$RemovedVFunc}}}=(
9479 "Type_Name"=>$CName,
9480 "Type_Type"=>"Class",
9481 "Target"=>get_Signature($RemovedVFunc, 1) );
Andrey Ponomarenko16934472012-03-29 15:37:04 +04009482 $VTableChanged_M{$CName} = 1;
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04009483 }
9484 elsif($CompleteSignature{1}{$Interface}{"Virt"}
9485 or $CompleteSignature{1}{$Interface}{"PureVirt"})
9486 {
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04009487 if(defined $VirtualTable{1}{$CName} and defined $VirtualTable{2}{$CName})
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04009488 {
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04009489 if(not defined $VirtualTable{1}{$CName}{$Interface}) {
9490 next;
9491 }
9492 my $VPos_New = -1;
9493 if(defined $VirtualTable{2}{$CName}{$Interface})
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04009494 {
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04009495 $VPos_New = $VirtualTable{2}{$CName}{$Interface};
9496 }
9497 else
9498 {
9499 if($Interface ne $RemovedVFunc) {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04009500 next;
9501 }
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04009502 }
9503 my $VPos_Removed = $VirtualTable{1}{$CName}{$RemovedVFunc};
9504 my $VPos_Old = $VirtualTable{1}{$CName}{$Interface};
9505 if($VPos_Removed<=$VPos_Old and $VPos_Old!=$VPos_New)
9506 {
9507 my @Affected = ($Interface, keys(%{$OverriddenMethods{1}{$Interface}}));
9508 foreach my $ASymbol (@Affected)
9509 {
Andrey Ponomarenko85043792012-05-14 16:48:07 +04009510 if(not $CompleteSignature{1}{$ASymbol}{"PureVirt"})
9511 {
9512 if(symbolFilter($ASymbol, 1, "Affected", $Level)) {
9513 next;
9514 }
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04009515 }
9516 my $ProblemType = "Removed_Virtual_Method";
9517 if($CompleteSignature{1}{$RemovedVFunc}{"PureVirt"}) {
9518 $ProblemType = "Removed_Pure_Virtual_Method";
9519 }
9520 $CheckedSymbols{$Level}{$ASymbol} = 1;
9521 %{$CompatProblems{$Level}{$ASymbol}{$ProblemType}{$tr_name{$RemovedVFunc}}}=(
9522 "Type_Name"=>$CName,
9523 "Type_Type"=>"Class",
9524 "Target"=>get_Signature($RemovedVFunc, 1) );
Andrey Ponomarenko16934472012-03-29 15:37:04 +04009525 $VTableChanged_M{get_TypeName($CompleteSignature{1}{$ASymbol}{"Class"}, 1)} = 1;
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04009526 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04009527 }
9528 }
9529 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009530 }
9531 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04009532 else
9533 { # Source-level
9534 foreach my $AddedVFunc (keys(%{$AddedInt_Virt{$Level}{$CName}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009535 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04009536 next if($Interface eq $AddedVFunc);
9537 if($CompleteSignature{2}{$AddedVFunc}{"PureVirt"})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009538 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04009539 %{$CompatProblems{$Level}{$Interface}{"Added_Pure_Virtual_Method"}{$tr_name{$AddedVFunc}}}=(
9540 "Type_Name"=>$CName,
9541 "Type_Type"=>"Class",
9542 "Target"=>get_Signature($AddedVFunc, 2) );
9543 }
9544 }
9545 foreach my $RemovedVFunc (keys(%{$RemovedInt_Virt{$Level}{$CName}}))
9546 {
9547 if($CompleteSignature{1}{$RemovedVFunc}{"PureVirt"})
9548 {
9549 %{$CompatProblems{$Level}{$Interface}{"Removed_Pure_Virtual_Method"}{$tr_name{$RemovedVFunc}}}=(
9550 "Type_Name"=>$CName,
9551 "Type_Type"=>"Class",
9552 "Target"=>get_Signature($RemovedVFunc, 1) );
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009553 }
9554 }
9555 }
9556}
9557
9558sub find_MemberPair_Pos_byName($$)
9559{
9560 my ($Member_Name, $Pair_Type) = @_;
9561 $Member_Name=~s/\A[_]+|[_]+\Z//g;
9562 foreach my $MemberPair_Pos (sort {int($a)<=>int($b)} keys(%{$Pair_Type->{"Memb"}}))
9563 {
9564 if(defined $Pair_Type->{"Memb"}{$MemberPair_Pos})
9565 {
9566 my $Name = $Pair_Type->{"Memb"}{$MemberPair_Pos}{"name"};
9567 $Name=~s/\A[_]+|[_]+\Z//g;
9568 if($Name eq $Member_Name) {
9569 return $MemberPair_Pos;
9570 }
9571 }
9572 }
9573 return "lost";
9574}
9575
9576sub find_MemberPair_Pos_byVal($$)
9577{
9578 my ($Member_Value, $Pair_Type) = @_;
9579 foreach my $MemberPair_Pos (sort {int($a)<=>int($b)} keys(%{$Pair_Type->{"Memb"}}))
9580 {
9581 if(defined $Pair_Type->{"Memb"}{$MemberPair_Pos}
9582 and $Pair_Type->{"Memb"}{$MemberPair_Pos}{"value"} eq $Member_Value) {
9583 return $MemberPair_Pos;
9584 }
9585 }
9586 return "lost";
9587}
9588
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04009589my %Severity_Val=(
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009590 "High"=>3,
9591 "Medium"=>2,
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04009592 "Low"=>1,
9593 "Safe"=>-1
9594);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009595
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04009596sub maxSeverity($$)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009597{
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04009598 my ($S1, $S2) = @_;
9599 if(cmpSeverities($S1, $S2)) {
9600 return $S1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009601 }
9602 else {
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04009603 return $S2;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009604 }
9605}
9606
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04009607sub cmpSeverities($$)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009608{
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04009609 my ($S1, $S2) = @_;
9610 if(not $S1) {
9611 return 0;
9612 }
9613 elsif(not $S2) {
9614 return 1;
9615 }
9616 return ($Severity_Val{$S1}>$Severity_Val{$S2});
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009617}
9618
9619sub getProblemSeverity($$)
9620{
9621 my ($Level, $Kind) = @_;
9622 return $CompatRules{$Level}{$Kind}{"Severity"};
9623}
9624
9625sub isRecurType($$$$)
9626{
9627 foreach (@RecurTypes)
9628 {
Andrey Ponomarenko16934472012-03-29 15:37:04 +04009629 if( $_->{"1"} eq $_[0]
9630 and $_->{"2"} eq $_[1]
9631 and $_->{"3"} eq $_[2]
9632 and $_->{"4"} eq $_[3] )
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009633 {
9634 return 1;
9635 }
9636 }
9637 return 0;
9638}
9639
9640sub pushType($$$$)
9641{
9642 my %TypeIDs=(
Andrey Ponomarenko16934472012-03-29 15:37:04 +04009643 "1" => $_[0], #Tid1
9644 "2" => $_[1], #TDid1
9645 "3" => $_[2], #Tid2
9646 "4" => $_[3] #TDid2
9647 );
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009648 push(@RecurTypes, \%TypeIDs);
9649}
9650
9651sub isRenamed($$$$$)
9652{
9653 my ($MemPos, $Type1, $LVersion1, $Type2, $LVersion2) = @_;
9654 my $Member_Name = $Type1->{"Memb"}{$MemPos}{"name"};
9655 my $MemberType_Id = $Type1->{"Memb"}{$MemPos}{"type"};
9656 my %MemberType_Pure = get_PureType($Tid_TDid{$LVersion1}{$MemberType_Id}, $MemberType_Id, $LVersion1);
9657 if(not defined $Type2->{"Memb"}{$MemPos}) {
9658 return "";
9659 }
9660 my $StraightPairType_Id = $Type2->{"Memb"}{$MemPos}{"type"};
9661 my %StraightPairType_Pure = get_PureType($Tid_TDid{$LVersion2}{$StraightPairType_Id}, $StraightPairType_Id, $LVersion2);
9662
9663 my $StraightPair_Name = $Type2->{"Memb"}{$MemPos}{"name"};
9664 my $MemberPair_Pos_Rev = ($Member_Name eq $StraightPair_Name)?$MemPos:find_MemberPair_Pos_byName($StraightPair_Name, $Type1);
9665 if($MemberPair_Pos_Rev eq "lost")
9666 {
9667 if($MemberType_Pure{"Name"} eq $StraightPairType_Pure{"Name"})
9668 {# base type match
9669 return $StraightPair_Name;
9670 }
9671 if(get_TypeName($MemberType_Id, $LVersion1) eq get_TypeName($StraightPairType_Id, $LVersion2))
9672 {# exact type match
9673 return $StraightPair_Name;
9674 }
9675 if($MemberType_Pure{"Size"} eq $StraightPairType_Pure{"Size"})
9676 {# size match
9677 return $StraightPair_Name;
9678 }
9679 if(isReserved($StraightPair_Name))
9680 {# reserved fields
9681 return $StraightPair_Name;
9682 }
9683 }
9684 return "";
9685}
9686
9687sub isLastElem($$)
9688{
9689 my ($Pos, $TypeRef) = @_;
9690 my $Name = $TypeRef->{"Memb"}{$Pos}{"name"};
9691 if($Name=~/last|count|max|total/i)
9692 { # GST_LEVEL_COUNT, GST_RTSP_ELAST
9693 return 1;
9694 }
9695 elsif($Name=~/END|NLIMITS\Z/)
9696 { # __RLIMIT_NLIMITS
9697 return 1;
9698 }
9699 elsif($Name=~/\AN[A-Z](.+)[a-z]+s\Z/
9700 and $Pos+1==keys(%{$TypeRef->{"Memb"}}))
9701 { # NImageFormats, NColorRoles
9702 return 1;
9703 }
9704 return 0;
9705}
9706
9707sub nonComparable($$)
9708{
9709 my ($T1, $T2) = @_;
9710 if($T1->{"Name"} ne $T2->{"Name"}
9711 and not isAnon($T1->{"Name"})
9712 and not isAnon($T2->{"Name"}))
9713 { # different names
9714 if($T1->{"Type"} ne "Pointer"
9715 or $T2->{"Type"} ne "Pointer")
9716 { # compare base types
9717 return 1;
9718 }
9719 if($T1->{"Name"}!~/\Avoid\s*\*/
9720 and $T2->{"Name"}=~/\Avoid\s*\*/)
9721 {
9722 return 1;
9723 }
9724 }
9725 elsif($T1->{"Type"} ne $T2->{"Type"})
9726 { # different types
9727 if($T1->{"Type"} eq "Class"
9728 and $T2->{"Type"} eq "Struct")
9729 { # "class" to "struct"
9730 return 0;
9731 }
9732 elsif($T2->{"Type"} eq "Class"
9733 and $T1->{"Type"} eq "Struct")
9734 { # "struct" to "class"
9735 return 0;
9736 }
9737 else
9738 { # "class" to "enum"
9739 # "union" to "class"
9740 # ...
9741 return 1;
9742 }
9743 }
9744 return 0;
9745}
9746
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04009747sub mergeTypes($$$$$)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009748{
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04009749 my ($Type1_Id, $Type1_DId, $Type2_Id, $Type2_DId, $Level) = @_;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009750 return () if((not $Type1_Id and not $Type1_DId) or (not $Type2_Id and not $Type2_DId));
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04009751 $Type1_DId = "" if(not defined $Type1_DId);
9752 $Type2_DId = "" if(not defined $Type2_DId);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009753 my (%Sub_SubProblems, %SubProblems) = ();
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04009754 if($Cache{"mergeTypes"}{$Level}{$Type1_Id}{$Type1_DId}{$Type2_Id}{$Type2_DId})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009755 { # already merged
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04009756 return %{$Cache{"mergeTypes"}{$Level}{$Type1_Id}{$Type1_DId}{$Type2_Id}{$Type2_DId}};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009757 }
9758 my %Type1 = get_Type($Type1_DId, $Type1_Id, 1);
9759 my %Type2 = get_Type($Type2_DId, $Type2_Id, 2);
Andrey Ponomarenko16934472012-03-29 15:37:04 +04009760 if(not $Type1{"Name"} or not $Type2{"Name"}) {
9761 return ();
9762 }
9763 $CheckedTypes{$Level}{$Type1{"Name"}}=1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009764 my %Type1_Pure = get_PureType($Type1_DId, $Type1_Id, 1);
9765 my %Type2_Pure = get_PureType($Type2_DId, $Type2_Id, 2);
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04009766 $CheckedTypes{$Level}{$Type1_Pure{"Name"}}=1;
Andrey Ponomarenko85043792012-05-14 16:48:07 +04009767 if(not $Type1_Pure{"Size"} or not $Type2_Pure{"Size"})
9768 { # including a case when "class Class { ... };" changed to "class Class;"
9769 return ();
9770 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009771 if(isRecurType($Type1_Pure{"Tid"}, $Type1_Pure{"TDid"}, $Type2_Pure{"Tid"}, $Type2_Pure{"TDid"}))
9772 { # skip recursive declarations
9773 return ();
9774 }
9775 return () if(not $Type1_Pure{"Name"} or not $Type2_Pure{"Name"});
9776 return () if($SkipTypes{1}{$Type1_Pure{"Name"}});
9777 return () if($SkipTypes{1}{$Type1{"Name"}});
9778
9779 my %Typedef_1 = goToFirst($Type1{"TDid"}, $Type1{"Tid"}, 1, "Typedef");
9780 my %Typedef_2 = goToFirst($Type2{"TDid"}, $Type2{"Tid"}, 2, "Typedef");
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04009781 if(not $UseOldDumps and %Typedef_1 and %Typedef_2
9782 and $Typedef_1{"Type"} eq "Typedef" and $Typedef_2{"Type"} eq "Typedef"
9783 and $Typedef_1{"Name"} eq $Typedef_2{"Name"})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009784 {
9785 my %Base_1 = get_OneStep_BaseType($Typedef_1{"TDid"}, $Typedef_1{"Tid"}, 1);
9786 my %Base_2 = get_OneStep_BaseType($Typedef_2{"TDid"}, $Typedef_2{"Tid"}, 2);
Andrey Ponomarenko85043792012-05-14 16:48:07 +04009787 if($Base_1{"Name"} ne $Base_2{"Name"})
9788 {
9789 if(differentDumps("G")
9790 or differentDumps("V"))
9791 { # different GCC versions or different dumps
9792 $Base_1{"Name"} = uncover_typedefs($Base_1{"Name"}, 1);
9793 $Base_2{"Name"} = uncover_typedefs($Base_2{"Name"}, 2);
9794 # std::__va_list and __va_list
9795 $Base_1{"Name"}=~s/\A(\w+::)+//;
9796 $Base_2{"Name"}=~s/\A(\w+::)+//;
9797 $Base_1{"Name"} = formatName($Base_1{"Name"});
9798 $Base_2{"Name"} = formatName($Base_2{"Name"});
9799 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009800 }
9801 if($Base_1{"Name"}!~/anon\-/ and $Base_2{"Name"}!~/anon\-/
9802 and $Base_1{"Name"} ne $Base_2{"Name"})
9803 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04009804 if($Level eq "Binary"
9805 and $Type1{"Size"} ne $Type2{"Size"})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009806 {
9807 %{$SubProblems{"DataType_Size"}{$Typedef_1{"Name"}}}=(
9808 "Target"=>$Typedef_1{"Name"},
9809 "Type_Name"=>$Typedef_1{"Name"},
9810 "Type_Type"=>"Typedef",
9811 "Old_Size"=>$Type1{"Size"}*$BYTE_SIZE,
9812 "New_Size"=>$Type2{"Size"}*$BYTE_SIZE );
9813 }
9814 %{$SubProblems{"Typedef_BaseType"}{$Typedef_1{"Name"}}}=(
9815 "Target"=>$Typedef_1{"Name"},
9816 "Type_Name"=>$Typedef_1{"Name"},
9817 "Type_Type"=>"Typedef",
9818 "Old_Value"=>$Base_1{"Name"},
9819 "New_Value"=>$Base_2{"Name"} );
9820 }
9821 }
9822 if(nonComparable(\%Type1_Pure, \%Type2_Pure))
9823 { # different types (reported in detectTypeChange(...))
9824 if($Type1_Pure{"Name"} eq $Type2_Pure{"Name"}
9825 and $Type1_Pure{"Type"} ne $Type2_Pure{"Type"}
9826 and $Type1_Pure{"Type"}!~/Intrinsic|Pointer|Ref|Typedef/)
9827 { # different type of the type
9828 %{$SubProblems{"DataType_Type"}{$Type1_Pure{"Name"}}}=(
9829 "Target"=>$Type1_Pure{"Name"},
9830 "Type_Name"=>$Type1_Pure{"Name"},
9831 "Type_Type"=>$Type1_Pure{"Type"},
9832 "Old_Value"=>lc($Type1_Pure{"Type"}),
9833 "New_Value"=>lc($Type2_Pure{"Type"}) );
9834 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04009835 %{$Cache{"mergeTypes"}{$Level}{$Type1_Id}{$Type1_DId}{$Type2_Id}{$Type2_DId}} = %SubProblems;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009836 return %SubProblems;
9837 }
9838 pushType($Type1_Pure{"Tid"}, $Type1_Pure{"TDid"},
9839 $Type2_Pure{"Tid"}, $Type2_Pure{"TDid"});
9840 if(($Type1_Pure{"Name"} eq $Type2_Pure{"Name"}
9841 or (isAnon($Type1_Pure{"Name"}) and isAnon($Type2_Pure{"Name"})))
9842 and $Type1_Pure{"Type"}=~/\A(Struct|Class|Union)\Z/)
9843 { # checking size
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04009844 if($Level eq "Binary"
9845 and $Type1_Pure{"Size"} ne $Type2_Pure{"Size"})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009846 {
9847 my $ProblemKind = "DataType_Size";
9848 if($Type1_Pure{"Type"} eq "Class"
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04009849 and keys(%{$ClassMethods{$Level}{1}{$Type1_Pure{"Name"}}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009850 {
9851 if(isCopyingClass($Type1_Pure{"Tid"}, 1)) {
9852 $ProblemKind = "Size_Of_Copying_Class";
9853 }
9854 elsif($AllocableClass{1}{$Type1_Pure{"Name"}})
9855 {
9856 if(int($Type2_Pure{"Size"})>int($Type1_Pure{"Size"})) {
9857 $ProblemKind = "Size_Of_Allocable_Class_Increased";
9858 }
9859 else {
9860 # descreased size of allocable class
9861 # it has no special effects
9862 }
9863 }
9864 }
9865 %{$SubProblems{$ProblemKind}{$Type1_Pure{"Name"}}}=(
9866 "Target"=>$Type1_Pure{"Name"},
9867 "Type_Name"=>$Type1_Pure{"Name"},
9868 "Type_Type"=>$Type1_Pure{"Type"},
9869 "Old_Size"=>$Type1_Pure{"Size"}*$BYTE_SIZE,
9870 "New_Size"=>$Type2_Pure{"Size"}*$BYTE_SIZE,
9871 "InitialType_Type"=>$Type1_Pure{"Type"} );
9872 }
9873 }
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04009874 if(defined $Type1_Pure{"BaseType"} and $Type1_Pure{"BaseType"}{"Tid"}
9875 and defined $Type2_Pure{"BaseType"} and $Type2_Pure{"BaseType"}{"Tid"})
9876 { # checking base types
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009877 %Sub_SubProblems = mergeTypes($Type1_Pure{"BaseType"}{"Tid"}, $Type1_Pure{"BaseType"}{"TDid"},
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04009878 $Type2_Pure{"BaseType"}{"Tid"}, $Type2_Pure{"BaseType"}{"TDid"}, $Level);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009879 foreach my $Sub_SubProblemType (keys(%Sub_SubProblems))
9880 {
9881 foreach my $Sub_SubLocation (keys(%{$Sub_SubProblems{$Sub_SubProblemType}}))
9882 {
9883 foreach my $Attr (keys(%{$Sub_SubProblems{$Sub_SubProblemType}{$Sub_SubLocation}})) {
9884 $SubProblems{$Sub_SubProblemType}{$Sub_SubLocation}{$Attr} = $Sub_SubProblems{$Sub_SubProblemType}{$Sub_SubLocation}{$Attr};
9885 }
9886 $SubProblems{$Sub_SubProblemType}{$Sub_SubLocation}{"InitialType_Type"} = $Type1_Pure{"Type"};
9887 }
9888 }
9889 }
9890 my (%AddedField, %RemovedField, %RenamedField, %RenamedField_Rev, %RelatedField, %RelatedField_Rev) = ();
9891 my %NameToPosA = map {$Type1_Pure{"Memb"}{$_}{"name"}=>$_} keys(%{$Type1_Pure{"Memb"}});
9892 my %NameToPosB = map {$Type2_Pure{"Memb"}{$_}{"name"}=>$_} keys(%{$Type2_Pure{"Memb"}});
9893 foreach my $Member_Pos (sort {int($a) <=> int($b)} keys(%{$Type1_Pure{"Memb"}}))
9894 { # detect removed and renamed fields
9895 my $Member_Name = $Type1_Pure{"Memb"}{$Member_Pos}{"name"};
9896 next if(not $Member_Name);
9897 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);
9898 if($MemberPair_Pos eq "lost")
9899 {
9900 if($Type2_Pure{"Type"}=~/\A(Struct|Class|Union)\Z/)
9901 {
9902 if(isUnnamed($Member_Name))
9903 { # support for old-version dumps
9904 # unnamed fields have been introduced in the ACC 1.23 (dump 2.1 format)
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04009905 if(not checkDumpVersion(2, "2.1")) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009906 next;
9907 }
9908 }
9909 if(my $RenamedTo = isRenamed($Member_Pos, \%Type1_Pure, 1, \%Type2_Pure, 2))
9910 { # renamed
9911 $RenamedField{$Member_Pos}=$RenamedTo;
9912 $RenamedField_Rev{$NameToPosB{$RenamedTo}}=$Member_Name;
9913 }
9914 else
9915 { # removed
9916 $RemovedField{$Member_Pos}=1;
9917 }
9918 }
9919 elsif($Type1_Pure{"Type"} eq "Enum")
9920 {
9921 my $Member_Value1 = $Type1_Pure{"Memb"}{$Member_Pos}{"value"};
9922 next if($Member_Value1 eq "");
9923 $MemberPair_Pos = find_MemberPair_Pos_byVal($Member_Value1, \%Type2_Pure);
9924 if($MemberPair_Pos ne "lost")
9925 { # renamed
9926 my $RenamedTo = $Type2_Pure{"Memb"}{$MemberPair_Pos}{"name"};
9927 my $MemberPair_Pos_Rev = find_MemberPair_Pos_byName($RenamedTo, \%Type1_Pure);
9928 if($MemberPair_Pos_Rev eq "lost")
9929 {
9930 $RenamedField{$Member_Pos}=$RenamedTo;
9931 $RenamedField_Rev{$NameToPosB{$RenamedTo}}=$Member_Name;
9932 }
9933 else {
9934 $RemovedField{$Member_Pos}=1;
9935 }
9936 }
9937 else
9938 { # removed
9939 $RemovedField{$Member_Pos}=1;
9940 }
9941 }
9942 }
9943 else
9944 { # related
9945 $RelatedField{$Member_Pos} = $MemberPair_Pos;
9946 $RelatedField_Rev{$MemberPair_Pos} = $Member_Pos;
9947 }
9948 }
9949 foreach my $Member_Pos (sort {int($a) <=> int($b)} keys(%{$Type2_Pure{"Memb"}}))
9950 { # detect added fields
9951 my $Member_Name = $Type2_Pure{"Memb"}{$Member_Pos}{"name"};
9952 next if(not $Member_Name);
9953 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);
9954 if($MemberPair_Pos eq "lost")
9955 {
9956 if(isUnnamed($Member_Name))
9957 { # support for old-version dumps
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04009958 # unnamed fields have been introduced in the ACC 1.23 (dump 2.1 format)
9959 if(not checkDumpVersion(1, "2.1")) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009960 next;
9961 }
9962 }
9963 if($Type2_Pure{"Type"}=~/\A(Struct|Class|Union|Enum)\Z/)
9964 {
9965 if(not $RenamedField_Rev{$Member_Pos})
9966 { # added
9967 $AddedField{$Member_Pos}=1;
9968 }
9969 }
9970 }
9971 }
9972 if($Type2_Pure{"Type"}=~/\A(Struct|Class)\Z/)
9973 { # detect moved fields
9974 my (%RelPos, %RelPosName, %AbsPos) = ();
9975 my $Pos = 0;
9976 foreach my $Member_Pos (sort {int($a) <=> int($b)} keys(%{$Type1_Pure{"Memb"}}))
9977 { # relative positions in 1st version
9978 my $Member_Name = $Type1_Pure{"Memb"}{$Member_Pos}{"name"};
9979 next if(not $Member_Name);
9980 if(not $RemovedField{$Member_Pos})
9981 { # old type without removed fields
9982 $RelPos{1}{$Member_Name}=$Pos;
9983 $RelPosName{1}{$Pos} = $Member_Name;
9984 $AbsPos{1}{$Pos++} = $Member_Pos;
9985 }
9986 }
9987 $Pos = 0;
9988 foreach my $Member_Pos (sort {int($a) <=> int($b)} keys(%{$Type2_Pure{"Memb"}}))
9989 { # relative positions in 2nd version
9990 my $Member_Name = $Type2_Pure{"Memb"}{$Member_Pos}{"name"};
9991 next if(not $Member_Name);
9992 if(not $AddedField{$Member_Pos})
9993 { # new type without added fields
9994 $RelPos{2}{$Member_Name}=$Pos;
9995 $RelPosName{2}{$Pos} = $Member_Name;
9996 $AbsPos{2}{$Pos++} = $Member_Pos;
9997 }
9998 }
9999 foreach my $Member_Name (keys(%{$RelPos{1}}))
10000 {
10001 my $RPos1 = $RelPos{1}{$Member_Name};
10002 my $AbsPos1 = $NameToPosA{$Member_Name};
10003 my $Member_Name2 = $Member_Name;
10004 if(my $RenamedTo = $RenamedField{$AbsPos1})
10005 { # renamed
10006 $Member_Name2 = $RenamedTo;
10007 }
10008 my $RPos2 = $RelPos{2}{$Member_Name2};
10009 if($RPos2 ne "" and $RPos1 ne $RPos2)
10010 { # different relative positions
10011 my $AbsPos2 = $NameToPosB{$Member_Name2};
10012 if($AbsPos1 ne $AbsPos2)
10013 { # different absolute positions
10014 my $ProblemType = "Moved_Field";
10015 if(not isPublic(\%Type1_Pure, $AbsPos1))
10016 { # may change layout and size of type
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040010017 if($Level eq "Source") {
10018 next;
10019 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010020 $ProblemType = "Moved_Private_Field";
10021 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040010022 if($Level eq "Binary"
10023 and $Type1_Pure{"Size"} ne $Type2_Pure{"Size"})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010024 { # affected size
10025 my $MemSize1 = get_TypeSize($Type1_Pure{"Memb"}{$AbsPos1}{"type"}, 1);
10026 my $MovedAbsPos = $AbsPos{1}{$RPos2};
10027 my $MemSize2 = get_TypeSize($Type1_Pure{"Memb"}{$MovedAbsPos}{"type"}, 1);
10028 if($MemSize1 ne $MemSize2) {
10029 $ProblemType .= "_And_Size";
10030 }
10031 }
10032 if($ProblemType eq "Moved_Private_Field") {
10033 next;
10034 }
10035 %{$SubProblems{$ProblemType}{$Member_Name}}=(
10036 "Target"=>$Member_Name,
10037 "Type_Name"=>$Type1_Pure{"Name"},
10038 "Type_Type"=>$Type1_Pure{"Type"},
10039 "Old_Value"=>$RPos1,
10040 "New_Value"=>$RPos2 );
10041 }
10042 }
10043 }
10044 }
10045 foreach my $Member_Pos (sort {int($a) <=> int($b)} keys(%{$Type1_Pure{"Memb"}}))
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040010046 { # check older fields, public and private
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010047 my $Member_Name = $Type1_Pure{"Memb"}{$Member_Pos}{"name"};
10048 next if(not $Member_Name);
10049 if(my $RenamedTo = $RenamedField{$Member_Pos})
10050 { # renamed
10051 if($Type2_Pure{"Type"}=~/\A(Struct|Class|Union)\Z/)
10052 {
10053 if(isPublic(\%Type1_Pure, $Member_Pos))
10054 {
10055 %{$SubProblems{"Renamed_Field"}{$Member_Name}}=(
10056 "Target"=>$Member_Name,
10057 "Type_Name"=>$Type1_Pure{"Name"},
10058 "Type_Type"=>$Type1_Pure{"Type"},
10059 "Old_Value"=>$Member_Name,
10060 "New_Value"=>$RenamedTo );
10061 }
10062 }
10063 elsif($Type1_Pure{"Type"} eq "Enum")
10064 {
10065 %{$SubProblems{"Enum_Member_Name"}{$Type1_Pure{"Memb"}{$Member_Pos}{"value"}}}=(
10066 "Target"=>$Type1_Pure{"Memb"}{$Member_Pos}{"value"},
10067 "Type_Name"=>$Type1_Pure{"Name"},
10068 "Type_Type"=>$Type1_Pure{"Type"},
10069 "Old_Value"=>$Member_Name,
10070 "New_Value"=>$RenamedTo );
10071 }
10072 }
10073 elsif($RemovedField{$Member_Pos})
10074 { # removed
10075 if($Type2_Pure{"Type"}=~/\A(Struct|Class)\Z/)
10076 {
10077 my $ProblemType = "Removed_Field";
10078 if(not isPublic(\%Type1_Pure, $Member_Pos)
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040010079 or isUnnamed($Member_Name))
10080 {
10081 if($Level eq "Source") {
10082 next;
10083 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010084 $ProblemType = "Removed_Private_Field";
10085 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040010086 if($Level eq "Binary"
10087 and not isMemPadded($Member_Pos, -1, \%Type1_Pure, \%RemovedField, 1))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010088 {
10089 if(my $MNum = isAccessible(\%Type1_Pure, \%RemovedField, $Member_Pos+1, -1))
10090 { # affected fields
10091 if(getOffset($MNum-1, \%Type1_Pure, 1)!=getOffset($RelatedField{$MNum-1}, \%Type2_Pure, 2))
10092 { # changed offset
10093 $ProblemType .= "_And_Layout";
10094 }
10095 }
10096 if($Type1_Pure{"Size"} ne $Type2_Pure{"Size"})
10097 { # affected size
10098 $ProblemType .= "_And_Size";
10099 }
10100 }
10101 if($ProblemType eq "Removed_Private_Field") {
10102 next;
10103 }
10104 %{$SubProblems{$ProblemType}{$Member_Name}}=(
10105 "Target"=>$Member_Name,
10106 "Type_Name"=>$Type1_Pure{"Name"},
10107 "Type_Type"=>$Type1_Pure{"Type"} );
10108 }
10109 elsif($Type2_Pure{"Type"} eq "Union")
10110 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040010111 if($Level eq "Binary"
10112 and $Type1_Pure{"Size"} ne $Type2_Pure{"Size"})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010113 {
10114 %{$SubProblems{"Removed_Union_Field_And_Size"}{$Member_Name}}=(
10115 "Target"=>$Member_Name,
10116 "Type_Name"=>$Type1_Pure{"Name"},
10117 "Type_Type"=>$Type1_Pure{"Type"} );
10118 }
10119 else
10120 {
10121 %{$SubProblems{"Removed_Union_Field"}{$Member_Name}}=(
10122 "Target"=>$Member_Name,
10123 "Type_Name"=>$Type1_Pure{"Name"},
10124 "Type_Type"=>$Type1_Pure{"Type"} );
10125 }
10126 }
10127 elsif($Type1_Pure{"Type"} eq "Enum")
10128 {
10129 %{$SubProblems{"Enum_Member_Removed"}{$Member_Name}}=(
10130 "Target"=>$Member_Name,
10131 "Type_Name"=>$Type1_Pure{"Name"},
10132 "Type_Type"=>$Type1_Pure{"Type"},
10133 "Old_Value"=>$Member_Name );
10134 }
10135 }
10136 else
10137 { # changed
10138 my $MemberPair_Pos = $RelatedField{$Member_Pos};
10139 if($Type1_Pure{"Type"} eq "Enum")
10140 {
10141 my $Member_Value1 = $Type1_Pure{"Memb"}{$Member_Pos}{"value"};
10142 next if($Member_Value1 eq "");
10143 my $Member_Value2 = $Type2_Pure{"Memb"}{$MemberPair_Pos}{"value"};
10144 next if($Member_Value2 eq "");
10145 if($Member_Value1 ne $Member_Value2)
10146 {
10147 my $ProblemType = "Enum_Member_Value";
10148 if(isLastElem($Member_Pos, \%Type1_Pure)) {
10149 $ProblemType = "Enum_Last_Member_Value";
10150 }
10151 %{$SubProblems{$ProblemType}{$Member_Name}}=(
10152 "Target"=>$Member_Name,
10153 "Type_Name"=>$Type1_Pure{"Name"},
10154 "Type_Type"=>$Type1_Pure{"Type"},
10155 "Old_Value"=>$Member_Value1,
10156 "New_Value"=>$Member_Value2 );
10157 }
10158 }
10159 elsif($Type2_Pure{"Type"}=~/\A(Struct|Class|Union)\Z/)
10160 {
10161 my $MemberType1_Id = $Type1_Pure{"Memb"}{$Member_Pos}{"type"};
10162 my $MemberType2_Id = $Type2_Pure{"Memb"}{$MemberPair_Pos}{"type"};
10163 my $SizeV1 = get_TypeSize($MemberType1_Id, 1)*$BYTE_SIZE;
10164 if(my $BSize1 = $Type1_Pure{"Memb"}{$Member_Pos}{"bitfield"}) {
10165 $SizeV1 = $BSize1;
10166 }
10167 my $SizeV2 = get_TypeSize($MemberType2_Id, 2)*$BYTE_SIZE;
10168 if(my $BSize2 = $Type2_Pure{"Memb"}{$MemberPair_Pos}{"bitfield"}) {
10169 $SizeV2 = $BSize2;
10170 }
10171 my $MemberType1_Name = get_TypeName($MemberType1_Id, 1);
10172 my $MemberType2_Name = get_TypeName($MemberType2_Id, 2);
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040010173 if($Level eq "Binary"
10174 and $SizeV1 ne $SizeV2)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010175 {
10176 if($MemberType1_Name eq $MemberType2_Name or (isAnon($MemberType1_Name) and isAnon($MemberType2_Name))
10177 or ($Type1_Pure{"Memb"}{$Member_Pos}{"bitfield"} and $Type2_Pure{"Memb"}{$MemberPair_Pos}{"bitfield"}))
10178 { # field size change (including anon-structures and unions)
10179 # - same types
10180 # - unnamed types
10181 # - bitfields
10182 my $ProblemType = "Field_Size";
10183 if(not isPublic(\%Type1_Pure, $Member_Pos)
10184 or isUnnamed($Member_Name))
10185 { # should not be accessed by applications, goes to "Low Severity"
10186 # example: "abidata" members in GStreamer types
10187 $ProblemType = "Private_".$ProblemType;
10188 }
10189 if(not isMemPadded($Member_Pos, get_TypeSize($MemberType2_Id, 2)*$BYTE_SIZE, \%Type1_Pure, \%RemovedField, 1))
10190 { # check an effect
10191 if(my $MNum = isAccessible(\%Type1_Pure, \%RemovedField, $Member_Pos+1, -1))
10192 { # public fields after the current
10193 if(getOffset($MNum-1, \%Type1_Pure, 1)!=getOffset($RelatedField{$MNum-1}, \%Type2_Pure, 2))
10194 { # changed offset
10195 $ProblemType .= "_And_Layout";
10196 }
10197 }
10198 if($Type1_Pure{"Size"} ne $Type2_Pure{"Size"}) {
10199 $ProblemType .= "_And_Type_Size";
10200 }
10201 }
10202 if($ProblemType eq "Private_Field_Size")
10203 { # private field size with no effect
10204 $ProblemType = "";
10205 }
10206 if($ProblemType)
10207 { # register a problem
10208 %{$SubProblems{$ProblemType}{$Member_Name}}=(
10209 "Target"=>$Member_Name,
10210 "Type_Name"=>$Type1_Pure{"Name"},
10211 "Type_Type"=>$Type1_Pure{"Type"},
10212 "Old_Size"=>$SizeV1,
10213 "New_Size"=>$SizeV2);
10214 }
10215 }
10216 }
10217 if($Type1_Pure{"Memb"}{$Member_Pos}{"bitfield"}
10218 or $Type2_Pure{"Memb"}{$MemberPair_Pos}{"bitfield"})
10219 { # do NOT check bitfield type changes
10220 next;
10221 }
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040010222 if(checkDumpVersion(1, "2.13") and checkDumpVersion(2, "2.13"))
10223 {
10224 if(not $Type1_Pure{"Memb"}{$Member_Pos}{"mutable"}
10225 and $Type2_Pure{"Memb"}{$MemberPair_Pos}{"mutable"})
10226 {
10227 %{$SubProblems{"Field_Became_Mutable"}{$Member_Name}}=(
10228 "Target"=>$Member_Name,
10229 "Type_Name"=>$Type1_Pure{"Name"},
10230 "Type_Type"=>$Type1_Pure{"Type"});
10231 }
10232 elsif($Type1_Pure{"Memb"}{$Member_Pos}{"mutable"}
10233 and not $Type2_Pure{"Memb"}{$MemberPair_Pos}{"mutable"})
10234 {
10235 %{$SubProblems{"Field_Became_NonMutable"}{$Member_Name}}=(
10236 "Target"=>$Member_Name,
10237 "Type_Name"=>$Type1_Pure{"Name"},
10238 "Type_Type"=>$Type1_Pure{"Type"});
10239 }
10240 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040010241 %Sub_SubProblems = detectTypeChange($MemberType1_Id, $MemberType2_Id, "Field", $Level);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010242 foreach my $ProblemType (keys(%Sub_SubProblems))
10243 {
10244 my $Old_Value = $Sub_SubProblems{$ProblemType}{"Old_Value"};
10245 my $New_Value = $Sub_SubProblems{$ProblemType}{"New_Value"};
10246 if($ProblemType eq "Field_Type"
10247 or $ProblemType eq "Field_Type_And_Size")
10248 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040010249 if(checkDumpVersion(1, "2.6") and checkDumpVersion(2, "2.6"))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010250 {
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040010251 if(my $RA = addedQual($Old_Value, $New_Value, "volatile"))
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040010252 {
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040010253 %{$Sub_SubProblems{"Field_Became_Volatile"}} = %{$Sub_SubProblems{$ProblemType}};
10254 if($Level eq "Source"
10255 and cmpBTypes($Old_Value, $New_Value, 1, 2)) {
10256 delete($Sub_SubProblems{$ProblemType});
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040010257 }
10258 }
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040010259 elsif(my $RR = removedQual($Old_Value, $New_Value, "volatile"))
10260 {
10261 %{$Sub_SubProblems{"Field_Became_NonVolatile"}} = %{$Sub_SubProblems{$ProblemType}};
10262 if($Level eq "Source"
10263 and cmpBTypes($Old_Value, $New_Value, 1, 2)) {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040010264 delete($Sub_SubProblems{$ProblemType});
10265 }
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040010266 }
10267 }
10268 if(my $RA = addedQual($Old_Value, $New_Value, "const"))
10269 {
10270 if($RA==2) {
10271 %{$Sub_SubProblems{"Field_Added_Const"}} = %{$Sub_SubProblems{$ProblemType}};
10272 }
10273 else {
10274 %{$Sub_SubProblems{"Field_Became_Const"}} = %{$Sub_SubProblems{$ProblemType}};
10275 }
10276 if($Level eq "Source"
10277 and cmpBTypes($Old_Value, $New_Value, 1, 2)) {
10278 delete($Sub_SubProblems{$ProblemType});
10279 }
10280 }
10281 elsif(my $RR = removedQual($Old_Value, $New_Value, "const"))
10282 {
10283 if($RR==2) {
10284 %{$Sub_SubProblems{"Field_Removed_Const"}} = %{$Sub_SubProblems{$ProblemType}};
10285 }
10286 else {
10287 %{$Sub_SubProblems{"Field_Became_NonConst"}} = %{$Sub_SubProblems{$ProblemType}};
10288 }
10289 if($Level eq "Source"
10290 and cmpBTypes($Old_Value, $New_Value, 1, 2)) {
10291 delete($Sub_SubProblems{$ProblemType});
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010292 }
10293 }
10294 }
10295 }
10296 foreach my $ProblemType (keys(%Sub_SubProblems))
10297 {
10298 my $ProblemType_Init = $ProblemType;
10299 if($ProblemType eq "Field_Type_And_Size")
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040010300 { # Binary
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010301 if(not isPublic(\%Type1_Pure, $Member_Pos)
10302 or isUnnamed($Member_Name)) {
10303 $ProblemType = "Private_".$ProblemType;
10304 }
10305 if(not isMemPadded($Member_Pos, get_TypeSize($MemberType2_Id, 2)*$BYTE_SIZE, \%Type1_Pure, \%RemovedField, 1))
10306 { # check an effect
10307 if(my $MNum = isAccessible(\%Type1_Pure, \%RemovedField, $Member_Pos+1, -1))
10308 { # public fields after the current
10309 if(getOffset($MNum-1, \%Type1_Pure, 1)!=getOffset($RelatedField{$MNum-1}, \%Type2_Pure, 2))
10310 { # changed offset
10311 $ProblemType .= "_And_Layout";
10312 }
10313 }
10314 if($Type1_Pure{"Size"} ne $Type2_Pure{"Size"}) {
10315 $ProblemType .= "_And_Type_Size";
10316 }
10317 }
10318 }
10319 else
10320 {
10321 if(not isPublic(\%Type1_Pure, $Member_Pos)
10322 or isUnnamed($Member_Name)) {
10323 next;
10324 }
10325 }
10326 if($ProblemType eq "Private_Field_Type_And_Size")
10327 { # private field change with no effect
10328 next;
10329 }
10330 %{$SubProblems{$ProblemType}{$Member_Name}}=(
10331 "Target"=>$Member_Name,
10332 "Type_Name"=>$Type1_Pure{"Name"},
10333 "Type_Type"=>$Type1_Pure{"Type"} );
10334 foreach my $Attr (keys(%{$Sub_SubProblems{$ProblemType_Init}}))
10335 { # other properties
10336 $SubProblems{$ProblemType}{$Member_Name}{$Attr} = $Sub_SubProblems{$ProblemType_Init}{$Attr};
10337 }
10338 }
10339 if(not isPublic(\%Type1_Pure, $Member_Pos))
10340 { # do NOT check internal type changes
10341 next;
10342 }
10343 if($MemberType1_Id and $MemberType2_Id)
10344 {# checking member type changes (replace)
10345 %Sub_SubProblems = mergeTypes($MemberType1_Id, $Tid_TDid{1}{$MemberType1_Id},
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040010346 $MemberType2_Id, $Tid_TDid{2}{$MemberType2_Id}, $Level);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010347 foreach my $Sub_SubProblemType (keys(%Sub_SubProblems))
10348 {
10349 foreach my $Sub_SubLocation (keys(%{$Sub_SubProblems{$Sub_SubProblemType}}))
10350 {
10351 my $NewLocation = ($Sub_SubLocation)?$Member_Name."->".$Sub_SubLocation:$Member_Name;
10352 $SubProblems{$Sub_SubProblemType}{$NewLocation}{"IsInTypeInternals"}=1;
10353 foreach my $Attr (keys(%{$Sub_SubProblems{$Sub_SubProblemType}{$Sub_SubLocation}})) {
10354 $SubProblems{$Sub_SubProblemType}{$NewLocation}{$Attr} = $Sub_SubProblems{$Sub_SubProblemType}{$Sub_SubLocation}{$Attr};
10355 }
10356 if($Sub_SubLocation!~/\-\>/) {
10357 $SubProblems{$Sub_SubProblemType}{$NewLocation}{"Start_Type_Name"} = $MemberType1_Name;
10358 }
10359 }
10360 }
10361 }
10362 }
10363 }
10364 }
10365 foreach my $Member_Pos (sort {int($a) <=> int($b)} keys(%{$Type2_Pure{"Memb"}}))
10366 { # checking added members, public and private
10367 my $Member_Name = $Type2_Pure{"Memb"}{$Member_Pos}{"name"};
10368 next if(not $Member_Name);
10369 if($AddedField{$Member_Pos})
10370 { # added
10371 if($Type2_Pure{"Type"}=~/\A(Struct|Class)\Z/)
10372 {
10373 my $ProblemType = "Added_Field";
10374 if(not isPublic(\%Type2_Pure, $Member_Pos)
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040010375 or isUnnamed($Member_Name))
10376 {
10377 if($Level eq "Source") {
10378 next;
10379 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010380 $ProblemType = "Added_Private_Field";
10381 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040010382 if($Level eq "Binary"
10383 and not isMemPadded($Member_Pos, -1, \%Type2_Pure, \%AddedField, 2))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010384 {
10385 if(my $MNum = isAccessible(\%Type2_Pure, \%AddedField, $Member_Pos, -1))
10386 { # public fields after the current
10387 if(getOffset($MNum-1, \%Type2_Pure, 2)!=getOffset($RelatedField_Rev{$MNum-1}, \%Type1_Pure, 1))
10388 { # changed offset
10389 $ProblemType .= "_And_Layout";
10390 }
10391 }
10392 if($Type1_Pure{"Size"} ne $Type2_Pure{"Size"}) {
10393 $ProblemType .= "_And_Size";
10394 }
10395 }
10396 if($ProblemType eq "Added_Private_Field")
10397 { # skip added private fields
10398 next;
10399 }
10400 %{$SubProblems{$ProblemType}{$Member_Name}}=(
10401 "Target"=>$Member_Name,
10402 "Type_Name"=>$Type1_Pure{"Name"},
10403 "Type_Type"=>$Type1_Pure{"Type"} );
10404 }
10405 elsif($Type2_Pure{"Type"} eq "Union")
10406 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040010407 if($Level eq "Binary"
10408 and $Type1_Pure{"Size"} ne $Type2_Pure{"Size"})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010409 {
10410 %{$SubProblems{"Added_Union_Field_And_Size"}{$Member_Name}}=(
10411 "Target"=>$Member_Name,
10412 "Type_Name"=>$Type1_Pure{"Name"},
10413 "Type_Type"=>$Type1_Pure{"Type"} );
10414 }
10415 else
10416 {
10417 %{$SubProblems{"Added_Union_Field"}{$Member_Name}}=(
10418 "Target"=>$Member_Name,
10419 "Type_Name"=>$Type1_Pure{"Name"},
10420 "Type_Type"=>$Type1_Pure{"Type"} );
10421 }
10422 }
10423 elsif($Type2_Pure{"Type"} eq "Enum")
10424 {
10425 my $Member_Value = $Type2_Pure{"Memb"}{$Member_Pos}{"value"};
10426 next if($Member_Value eq "");
10427 %{$SubProblems{"Added_Enum_Member"}{$Member_Name}}=(
10428 "Target"=>$Member_Name,
10429 "Type_Name"=>$Type2_Pure{"Name"},
10430 "Type_Type"=>$Type2_Pure{"Type"},
10431 "New_Value"=>$Member_Value );
10432 }
10433 }
10434 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040010435 %{$Cache{"mergeTypes"}{$Level}{$Type1_Id}{$Type1_DId}{$Type2_Id}{$Type2_DId}} = %SubProblems;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010436 pop(@RecurTypes);
10437 return %SubProblems;
10438}
10439
10440sub isUnnamed($) {
10441 return $_[0]=~/\Aunnamed\d+\Z/;
10442}
10443
10444sub get_TypeName($$)
10445{
10446 my ($TypeId, $LibVersion) = @_;
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040010447 return get_TypeAttr($TypeId, $LibVersion, "Name");
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010448}
10449
10450sub get_TypeSize($$)
10451{
10452 my ($TypeId, $LibVersion) = @_;
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040010453 return get_TypeAttr($TypeId, $LibVersion, "Size");
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010454}
10455
10456sub get_TypeAttr($$$)
10457{
10458 my ($TypeId, $LibVersion, $Attr) = @_;
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040010459 return "" if(not defined $TypeId);
10460 if(not defined $Tid_TDid{$LibVersion}{$TypeId})
10461 { # correcting data
10462 $Tid_TDid{$LibVersion}{$TypeId} = "";
10463 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010464 return $TypeInfo{$LibVersion}{$Tid_TDid{$LibVersion}{$TypeId}}{$TypeId}{$Attr};
10465}
10466
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040010467sub get_ShortType($$)
10468{
10469 my ($TypeId, $LibVersion) = @_;
10470 my $TypeName = get_TypeAttr($TypeId, $LibVersion, "Name");
10471 if(my $NameSpace = get_TypeAttr($TypeId, $LibVersion, "NameSpace")) {
10472 $TypeName=~s/\A$NameSpace\:\://g;
10473 }
10474 return $TypeName;
10475}
10476
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010477sub goToFirst($$$$)
10478{
10479 my ($TypeDId, $TypeId, $LibVersion, $Type_Type) = @_;
Andrey Ponomarenko16934472012-03-29 15:37:04 +040010480 return () if(not $TypeId);
10481 $TypeDId = "" if(not defined $TypeDId);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010482 if(defined $Cache{"goToFirst"}{$TypeDId}{$TypeId}{$LibVersion}{$Type_Type}) {
10483 return %{$Cache{"goToFirst"}{$TypeDId}{$TypeId}{$LibVersion}{$Type_Type}};
10484 }
10485 return () if(not $TypeInfo{$LibVersion}{$TypeDId}{$TypeId});
10486 my %Type = %{$TypeInfo{$LibVersion}{$TypeDId}{$TypeId}};
10487 return () if(not $Type{"Type"});
10488 if($Type{"Type"} ne $Type_Type)
10489 {
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040010490 return () if(not defined $Type{"BaseType"});
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010491 return () if(not $Type{"BaseType"}{"TDid"} and not $Type{"BaseType"}{"Tid"});
10492 %Type = goToFirst($Type{"BaseType"}{"TDid"}, $Type{"BaseType"}{"Tid"}, $LibVersion, $Type_Type);
10493 }
10494 $Cache{"goToFirst"}{$TypeDId}{$TypeId}{$LibVersion}{$Type_Type} = \%Type;
10495 return %Type;
10496}
10497
10498my %TypeSpecAttributes = (
10499 "Const" => 1,
10500 "Volatile" => 1,
10501 "ConstVolatile" => 1,
10502 "Restrict" => 1,
10503 "Typedef" => 1
10504);
10505
10506sub get_PureType($$$)
10507{
10508 my ($TypeDId, $TypeId, $LibVersion) = @_;
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040010509 return () if(not $TypeId);
10510 $TypeDId = "" if(not defined $TypeDId);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010511 if(defined $Cache{"get_PureType"}{$TypeDId}{$TypeId}{$LibVersion}) {
10512 return %{$Cache{"get_PureType"}{$TypeDId}{$TypeId}{$LibVersion}};
10513 }
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040010514 return () if(not $TypeInfo{$LibVersion}{$TypeDId}{$TypeId});
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010515 my %Type = %{$TypeInfo{$LibVersion}{$TypeDId}{$TypeId}};
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040010516 return %Type if(not defined $Type{"BaseType"});
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010517 return %Type if(not $Type{"BaseType"}{"TDid"} and not $Type{"BaseType"}{"Tid"});
10518 if($TypeSpecAttributes{$Type{"Type"}}) {
10519 %Type = get_PureType($Type{"BaseType"}{"TDid"}, $Type{"BaseType"}{"Tid"}, $LibVersion);
10520 }
10521 $Cache{"get_PureType"}{$TypeDId}{$TypeId}{$LibVersion} = \%Type;
10522 return %Type;
10523}
10524
10525sub get_PointerLevel($$$)
10526{
10527 my ($TypeDId, $TypeId, $LibVersion) = @_;
10528 return 0 if(not $TypeId);
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040010529 $TypeDId = "" if(not defined $TypeDId);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010530 if(defined $Cache{"get_PointerLevel"}{$TypeDId}{$TypeId}{$LibVersion}) {
10531 return $Cache{"get_PointerLevel"}{$TypeDId}{$TypeId}{$LibVersion};
10532 }
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040010533 return 0 if(not $TypeInfo{$LibVersion}{$TypeDId}{$TypeId});
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010534 my %Type = %{$TypeInfo{$LibVersion}{$TypeDId}{$TypeId}};
10535 return 1 if($Type{"Type"}=~/FuncPtr|MethodPtr|FieldPtr/);
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040010536 return 0 if(not defined $Type{"BaseType"});
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010537 return 0 if(not $Type{"BaseType"}{"TDid"} and not $Type{"BaseType"}{"Tid"});
10538 my $PointerLevel = 0;
10539 if($Type{"Type"} =~/Pointer|Ref|FuncPtr|MethodPtr|FieldPtr/) {
10540 $PointerLevel += 1;
10541 }
10542 $PointerLevel += get_PointerLevel($Type{"BaseType"}{"TDid"}, $Type{"BaseType"}{"Tid"}, $LibVersion);
10543 $Cache{"get_PointerLevel"}{$TypeDId}{$TypeId}{$LibVersion} = $PointerLevel;
10544 return $PointerLevel;
10545}
10546
10547sub get_BaseType($$$)
10548{
10549 my ($TypeDId, $TypeId, $LibVersion) = @_;
10550 return () if(not $TypeId);
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040010551 $TypeDId = "" if(not defined $TypeDId);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010552 if(defined $Cache{"get_BaseType"}{$TypeDId}{$TypeId}{$LibVersion}) {
10553 return %{$Cache{"get_BaseType"}{$TypeDId}{$TypeId}{$LibVersion}};
10554 }
10555 return () if(not $TypeInfo{$LibVersion}{$TypeDId}{$TypeId});
10556 my %Type = %{$TypeInfo{$LibVersion}{$TypeDId}{$TypeId}};
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040010557 return %Type if(not defined $Type{"BaseType"});
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010558 return %Type if(not $Type{"BaseType"}{"TDid"} and not $Type{"BaseType"}{"Tid"});
10559 %Type = get_BaseType($Type{"BaseType"}{"TDid"}, $Type{"BaseType"}{"Tid"}, $LibVersion);
10560 $Cache{"get_BaseType"}{$TypeDId}{$TypeId}{$LibVersion} = \%Type;
10561 return %Type;
10562}
10563
10564sub get_BaseTypeQual($$$)
10565{
10566 my ($TypeDId, $TypeId, $LibVersion) = @_;
10567 return "" if(not $TypeId);
Andrey Ponomarenko16934472012-03-29 15:37:04 +040010568 $TypeDId = "" if(not defined $TypeDId);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010569 return "" if(not $TypeInfo{$LibVersion}{$TypeDId}{$TypeId});
10570 my %Type = %{$TypeInfo{$LibVersion}{$TypeDId}{$TypeId}};
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040010571 return "" if(not defined $Type{"BaseType"});
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010572 return "" if(not $Type{"BaseType"}{"TDid"} and not $Type{"BaseType"}{"Tid"});
10573 my $Qual = "";
10574 if($Type{"Type"} eq "Pointer") {
10575 $Qual .= "*";
10576 }
10577 elsif($Type{"Type"} eq "Ref") {
10578 $Qual .= "&";
10579 }
10580 elsif($Type{"Type"} eq "ConstVolatile") {
10581 $Qual .= "const volatile";
10582 }
10583 elsif($Type{"Type"} eq "Const"
10584 or $Type{"Type"} eq "Volatile"
10585 or $Type{"Type"} eq "Restrict") {
10586 $Qual .= lc($Type{"Type"});
10587 }
10588 my $BQual = get_BaseTypeQual($Type{"BaseType"}{"TDid"}, $Type{"BaseType"}{"Tid"}, $LibVersion);
10589 return $BQual.$Qual;
10590}
10591
10592sub get_OneStep_BaseType($$$)
10593{
10594 my ($TypeDId, $TypeId, $LibVersion) = @_;
10595 return () if(not $TypeId);
Andrey Ponomarenko16934472012-03-29 15:37:04 +040010596 $TypeDId = "" if(not defined $TypeDId);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010597 return () if(not $TypeInfo{$LibVersion}{$TypeDId}{$TypeId});
10598 my %Type = %{$TypeInfo{$LibVersion}{$TypeDId}{$TypeId}};
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040010599 return %Type if(not defined $Type{"BaseType"});
10600 return %Type if(not $Type{"BaseType"}{"TDid"} and not $Type{"BaseType"}{"Tid"});
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010601 return get_Type($Type{"BaseType"}{"TDid"}, $Type{"BaseType"}{"Tid"}, $LibVersion);
10602}
10603
10604sub get_Type($$$)
10605{
10606 my ($TypeDId, $TypeId, $LibVersion) = @_;
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040010607 return () if(not $TypeId);
10608 $TypeDId = "" if(not defined $TypeDId);
10609 return () if(not $TypeInfo{$LibVersion}{$TypeDId}{$TypeId});
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010610 return %{$TypeInfo{$LibVersion}{$TypeDId}{$TypeId}};
10611}
10612
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +040010613sub isPrivateData($)
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040010614{ # non-public global data
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010615 my $Symbol = $_[0];
10616 return ($Symbol=~/\A(_ZGV|_ZTI|_ZTS|_ZTT|_ZTV|_ZTC|_ZThn|_ZTv0_n)/);
10617}
10618
10619sub isTemplateInstance($)
10620{
10621 my $Symbol = $_[0];
10622 return 0 if($Symbol!~/\A(_Z|\?)/);
10623 my $Signature = $tr_name{$Symbol};
10624 return 0 if($Signature!~/>/);
Andrey Ponomarenko16934472012-03-29 15:37:04 +040010625 my $ShortName = substr($Signature, 0, find_center($Signature, "("));
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010626 $ShortName=~s/::operator .*//;# class::operator template<instance>
10627 return ($ShortName=~/<.+>/);
10628}
10629
10630sub isTemplateSpec($$)
10631{
10632 my ($Symbol, $LibVersion) = @_;
10633 if(my $ClassId = $CompleteSignature{$LibVersion}{$Symbol}{"Class"})
10634 {
10635 if(get_TypeAttr($ClassId, $LibVersion, "Spec"))
10636 { # class specialization
10637 return 1;
10638 }
10639 elsif($CompleteSignature{$LibVersion}{$Symbol}{"Spec"})
10640 { # method specialization
10641 return 1;
10642 }
10643 }
10644 return 0;
10645}
10646
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040010647sub symbolFilter($$$$)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010648{ # some special cases when the symbol cannot be imported
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040010649 my ($Symbol, $LibVersion, $Type, $Level) = @_;
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +040010650 if(isPrivateData($Symbol))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010651 { # non-public global data
10652 return 0;
10653 }
10654 if($CheckObjectsOnly) {
10655 return 0 if($Symbol=~/\A(_init|_fini)\Z/);
10656 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040010657 if($CheckHeadersOnly and not checkDumpVersion($LibVersion, "2.7"))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010658 { # support for old ABI dumps in --headers-only mode
10659 foreach my $Pos (keys(%{$CompleteSignature{$LibVersion}{$Symbol}{"Param"}}))
10660 {
10661 if(my $Pid = $CompleteSignature{$LibVersion}{$Symbol}{"Param"}{$Pos}{"type"})
10662 {
10663 my $PType = get_TypeAttr($Pid, $LibVersion, "Type");
10664 if(not $PType or $PType eq "Unknown") {
10665 return 0;
10666 }
10667 }
10668 }
10669 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +040010670 if($Type=~/Affected/)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010671 {
10672 my $ClassId = $CompleteSignature{$LibVersion}{$Symbol}{"Class"};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010673 if($SkipSymbols{$LibVersion}{$Symbol})
10674 { # user defined symbols to ignore
10675 return 0;
10676 }
10677 my $NameSpace = $CompleteSignature{$LibVersion}{$Symbol}{"NameSpace"};
10678 if(not $NameSpace and $ClassId)
10679 { # class methods have no "NameSpace" attribute
10680 $NameSpace = get_TypeAttr($ClassId, $LibVersion, "NameSpace");
10681 }
10682 if($NameSpace)
10683 { # user defined namespaces to ignore
10684 if($SkipNameSpaces{$LibVersion}{$NameSpace}) {
10685 return 0;
10686 }
10687 foreach my $NS (keys(%{$SkipNameSpaces{$LibVersion}}))
10688 { # nested namespaces
10689 if($NameSpace=~/\A\Q$NS\E(\:\:|\Z)/) {
10690 return 0;
10691 }
10692 }
10693 }
10694 if(my $Header = $CompleteSignature{$LibVersion}{$Symbol}{"Header"})
10695 {
10696 if(my $Skip = skip_header($Header, $LibVersion))
10697 { # --skip-headers or <skip_headers> (not <skip_including>)
10698 if($Skip==1) {
10699 return 0;
10700 }
10701 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010702 }
10703 if($SymbolsListPath and not $SymbolsList{$Symbol})
10704 { # user defined symbols
10705 return 0;
10706 }
10707 if($AppPath and not $SymbolsList_App{$Symbol})
10708 { # user defined symbols (in application)
10709 return 0;
10710 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +040010711 if(not selectSymbol($Symbol, $CompleteSignature{$LibVersion}{$Symbol}, $Level, $LibVersion))
10712 { # non-target symbols
10713 return 0;
10714 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040010715 if($Level eq "Binary")
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010716 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040010717 if($CompleteSignature{$LibVersion}{$Symbol}{"InLine"}
10718 or (isTemplateInstance($Symbol) and not isTemplateSpec($Symbol, $LibVersion)))
10719 {
10720 if($ClassId and $CompleteSignature{$LibVersion}{$Symbol}{"Virt"})
10721 { # inline virtual methods
Andrey Ponomarenko85043792012-05-14 16:48:07 +040010722 if($Type=~/InlineVirt/) {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040010723 return 1;
10724 }
10725 my $Allocable = (not isCopyingClass($ClassId, $LibVersion));
10726 if(not $Allocable)
10727 { # check bases
10728 foreach my $DCId (get_sub_classes($ClassId, $LibVersion, 1))
10729 {
10730 if(not isCopyingClass($DCId, $LibVersion))
10731 { # exists a derived class without default c-tor
10732 $Allocable=1;
10733 last;
10734 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010735 }
10736 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040010737 if(not $Allocable) {
10738 return 0;
10739 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010740 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040010741 else
10742 { # inline non-virtual methods
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010743 return 0;
10744 }
10745 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010746 }
10747 }
10748 return 1;
10749}
10750
10751sub mergeImpl()
10752{
10753 my $DiffCmd = get_CmdPath("diff");
10754 if(not $DiffCmd) {
10755 exitStatus("Not_Found", "can't find \"diff\"");
10756 }
10757 foreach my $Interface (sort keys(%{$Symbol_Library{1}}))
10758 { # implementation changes
10759 next if($CompleteSignature{1}{$Interface}{"Private"});
10760 next if(not $CompleteSignature{1}{$Interface}{"Header"} and not $CheckObjectsOnly);
10761 next if(not $Symbol_Library{2}{$Interface} and not $Symbol_Library{2}{$SymVer{2}{$Interface}});
Andrey Ponomarenko85043792012-05-14 16:48:07 +040010762 if(not symbolFilter($Interface, 1, "Affected", "Binary")) {
10763 next;
10764 }
Andrey Ponomarenko16934472012-03-29 15:37:04 +040010765 my $Impl1 = canonifyImpl($Interface_Impl{1}{$Interface});
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010766 next if(not $Impl1);
Andrey Ponomarenko16934472012-03-29 15:37:04 +040010767 my $Impl2 = canonifyImpl($Interface_Impl{2}{$Interface});
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010768 next if(not $Impl2);
10769 if($Impl1 ne $Impl2)
10770 {
10771 writeFile("$TMP_DIR/impl1", $Impl1);
10772 writeFile("$TMP_DIR/impl2", $Impl2);
10773 my $Diff = `$DiffCmd -rNau $TMP_DIR/impl1 $TMP_DIR/impl2`;
10774 $Diff=~s/(---|\+\+\+).+\n//g;
10775 $Diff=~s/[ ]{3,}/ /g;
10776 $Diff=~s/\n\@\@/\n \n\@\@/g;
10777 unlink("$TMP_DIR/impl1", "$TMP_DIR/impl2");
10778 %{$ImplProblems{$Interface}}=(
10779 "Diff" => get_CodeView($Diff) );
10780 }
10781 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +040010782
10783 # clean memory
10784 %Interface_Impl = ();
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010785}
10786
Andrey Ponomarenko16934472012-03-29 15:37:04 +040010787sub canonifyImpl($)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010788{
10789 my $FuncBody= $_[0];
10790 return "" if(not $FuncBody);
10791 $FuncBody=~s/0x[a-f\d]+/0x?/g;# addr
10792 $FuncBody=~s/((\A|\n)[a-z]+[\t ]+)[a-f\d]+([^x]|\Z)/$1?$3/g;# call, jump
10793 $FuncBody=~s/# [a-f\d]+ /# ? /g;# call, jump
10794 $FuncBody=~s/%([a-z]+[a-f\d]*)/\%reg/g;# registers
10795 while($FuncBody=~s/\nnop[ \t]*(\n|\Z)/$1/g){};# empty op
10796 $FuncBody=~s/<.+?\.cpp.+?>/<name.cpp>/g;
10797 $FuncBody=~s/(\A|\n)[a-f\d]+ </$1? </g;# 5e74 <_ZN...
10798 $FuncBody=~s/\.L\d+/.L/g;
10799 $FuncBody=~s/#(-?)\d+/#$1?/g;# r3, [r3, #120]
10800 $FuncBody=~s/[\n]{2,}/\n/g;
10801 return $FuncBody;
10802}
10803
10804sub get_CodeView($)
10805{
10806 my $Code = $_[0];
10807 my $View = "";
10808 foreach my $Line (split(/\n/, $Code))
10809 {
10810 if($Line=~s/\A(\+|-)/$1 /g)
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040010811 { # bold line
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010812 $View .= "<tr><td><b>".htmlSpecChars($Line)."</b></td></tr>\n";
10813 }
10814 else {
10815 $View .= "<tr><td>".htmlSpecChars($Line)."</td></tr>\n";
10816 }
10817 }
10818 return "<table class='code_view'>$View</table>\n";
10819}
10820
10821sub getImplementations($$)
10822{
10823 my ($LibVersion, $Path) = @_;
10824 return if(not $LibVersion or not -e $Path);
10825 if($OSgroup eq "macos")
10826 {
10827 my $OtoolCmd = get_CmdPath("otool");
10828 if(not $OtoolCmd) {
10829 exitStatus("Not_Found", "can't find \"otool\"");
10830 }
10831 my $CurInterface = "";
10832 foreach my $Line (split(/\n/, `$OtoolCmd -tv $Path 2>$TMP_DIR/null`))
10833 {
10834 if($Line=~/\A\s*_(\w+)\s*:/i) {
10835 $CurInterface = $1;
10836 }
10837 elsif($Line=~/\A\s*[\da-z]+\s+(.+?)\Z/i) {
10838 $Interface_Impl{$LibVersion}{$CurInterface} .= "$1\n";
10839 }
10840 }
10841 }
10842 else
10843 {
10844 my $ObjdumpCmd = get_CmdPath("objdump");
10845 if(not $ObjdumpCmd) {
10846 exitStatus("Not_Found", "can't find \"objdump\"");
10847 }
10848 my $CurInterface = "";
10849 foreach my $Line (split(/\n/, `$ObjdumpCmd -d $Path 2>$TMP_DIR/null`))
10850 {
10851 if($Line=~/\A[\da-z]+\s+<(\w+)>/i) {
10852 $CurInterface = $1;
10853 }
10854 else
10855 { # x86: 51fa:(\t)89 e5 (\t)mov %esp,%ebp
10856 # arm: 5020:(\t)e24cb004(\t)sub(\t)fp, ip, #4(\t); 0x4
10857 if($Line=~/\A\s*[a-f\d]+:\s+([a-f\d]+\s+)+([a-z]+\s+.*?)\s*(;.*|)\Z/i) {
10858 $Interface_Impl{$LibVersion}{$CurInterface} .= "$2\n";
10859 }
10860 }
10861 }
10862 }
10863}
10864
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040010865sub detectAdded($)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010866{
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040010867 my $Level = $_[0];
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010868 foreach my $Symbol (keys(%{$Symbol_Library{2}}))
10869 {
10870 if(link_symbol($Symbol, 1, "+Deps"))
10871 { # linker can find a new symbol
10872 # in the old-version library
10873 # So, it's not a new symbol
10874 next;
10875 }
10876 if(my $VSym = $SymVer{2}{$Symbol}
10877 and $Symbol!~/\@/) {
10878 next;
10879 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040010880 $AddedInt{$Level}{$Symbol} = 1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010881 }
10882}
10883
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040010884sub detectRemoved($)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010885{
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040010886 my $Level = $_[0];
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010887 foreach my $Symbol (keys(%{$Symbol_Library{1}}))
10888 {
10889 if($CheckObjectsOnly) {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040010890 $CheckedSymbols{"Binary"}{$Symbol} = 1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010891 }
10892 if(link_symbol($Symbol, 2, "+Deps"))
10893 { # linker can find an old symbol
10894 # in the new-version library
10895 next;
10896 }
10897 if(my $VSym = $SymVer{1}{$Symbol}
10898 and $Symbol!~/\@/) {
10899 next;
10900 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040010901 $RemovedInt{$Level}{$Symbol} = 1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010902 }
10903}
10904
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040010905sub mergeLibs($)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010906{
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040010907 my $Level = $_[0];
10908 foreach my $Symbol (sort keys(%{$AddedInt{$Level}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010909 { # checking added symbols
10910 next if($CompleteSignature{2}{$Symbol}{"Private"});
10911 next if(not $CompleteSignature{2}{$Symbol}{"Header"} and not $CheckObjectsOnly);
Andrey Ponomarenko85043792012-05-14 16:48:07 +040010912 next if(not symbolFilter($Symbol, 2, "Affected", $Level));
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040010913 %{$CompatProblems{$Level}{$Symbol}{"Added_Symbol"}{""}}=();
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010914 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040010915 foreach my $Symbol (sort keys(%{$RemovedInt{$Level}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010916 { # checking removed symbols
10917 next if($CompleteSignature{1}{$Symbol}{"Private"});
10918 next if(not $CompleteSignature{1}{$Symbol}{"Header"} and not $CheckObjectsOnly);
10919 if($Symbol=~/\A_ZTV/)
10920 { # skip v-tables for templates, that should not be imported by applications
10921 next if($tr_name{$Symbol}=~/</);
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040010922 if(my $CName = $VTableClass{$Symbol})
10923 {
10924 if(not keys(%{$ClassMethods{$Level}{1}{$CName}}))
10925 { # vtables for "private" classes
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040010926 # use case: vtable for QDragManager (Qt 4.5.3 to 4.6.0) became HIDDEN symbol
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040010927 next;
10928 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010929 }
10930 }
10931 else {
Andrey Ponomarenko85043792012-05-14 16:48:07 +040010932 next if(not symbolFilter($Symbol, 1, "Affected", $Level));
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010933 }
10934 if($CompleteSignature{1}{$Symbol}{"PureVirt"})
10935 { # symbols for pure virtual methods cannot be called by clients
10936 next;
10937 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040010938 %{$CompatProblems{$Level}{$Symbol}{"Removed_Symbol"}{""}}=();
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010939 }
10940}
10941
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040010942sub checkDumpVersion($$)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010943{
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040010944 my ($LibVersion, $DumpVersion) = @_;
10945 return (not $UsedDump{$LibVersion}{"V"} or cmpVersions($UsedDump{$LibVersion}{"V"}, $DumpVersion)>=0);
10946}
10947
10948sub detectAdded_H($)
10949{
10950 my $Level = $_[0];
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010951 foreach my $Symbol (sort keys(%{$CompleteSignature{2}}))
10952 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040010953 if($Level eq "Source")
10954 { # remove symbol version
10955 my ($SN, $SS, $SV) = separate_symbol($Symbol);
10956 $Symbol=$SN;
10957 }
Andrey Ponomarenko16934472012-03-29 15:37:04 +040010958 if(not $CompleteSignature{2}{$Symbol}{"Header"}
10959 or not $CompleteSignature{2}{$Symbol}{"MnglName"}) {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040010960 next;
10961 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010962 if($GeneratedSymbols{$Symbol}) {
10963 next;
10964 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040010965 if(not defined $CompleteSignature{1}{$Symbol}
10966 or not $CompleteSignature{1}{$Symbol}{"MnglName"})
10967 {
Andrey Ponomarenko16934472012-03-29 15:37:04 +040010968 if($UsedDump{2}{"SrcBin"})
10969 {
10970 if($UsedDump{1}{"BinOnly"} or not checkDumpVersion(1, "2.11"))
10971 { # support for old and different (!) ABI dumps
10972 if(not $CompleteSignature{2}{$Symbol}{"Virt"}
10973 and not $CompleteSignature{2}{$Symbol}{"PureVirt"})
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040010974 {
Andrey Ponomarenko16934472012-03-29 15:37:04 +040010975 if($CheckHeadersOnly)
Andrey Ponomarenko85043792012-05-14 16:48:07 +040010976 {
10977 if(my $Lang = $CompleteSignature{2}{$Symbol}{"Lang"})
10978 {
10979 if($Lang eq "C")
10980 { # support for old ABI dumps: missed extern "C" functions
10981 next;
10982 }
10983 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040010984 }
Andrey Ponomarenko16934472012-03-29 15:37:04 +040010985 else
10986 {
10987 if(not link_symbol($Symbol, 2, "-Deps"))
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040010988 { # skip added inline symbols and const global data
Andrey Ponomarenko16934472012-03-29 15:37:04 +040010989 next;
10990 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040010991 }
10992 }
10993 }
10994 }
10995 $AddedInt{$Level}{$Symbol} = 1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010996 }
10997 }
10998}
10999
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011000sub detectRemoved_H($)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011001{
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011002 my $Level = $_[0];
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011003 foreach my $Symbol (sort keys(%{$CompleteSignature{1}}))
11004 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011005 if($Level eq "Source")
11006 { # remove symbol version
11007 my ($SN, $SS, $SV) = separate_symbol($Symbol);
11008 $Symbol=$SN;
11009 }
Andrey Ponomarenko16934472012-03-29 15:37:04 +040011010 if(not $CompleteSignature{1}{$Symbol}{"Header"}
11011 or not $CompleteSignature{1}{$Symbol}{"MnglName"}) {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011012 next;
11013 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011014 if($GeneratedSymbols{$Symbol}) {
11015 next;
11016 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011017 if(not defined $CompleteSignature{2}{$Symbol}
11018 or not $CompleteSignature{2}{$Symbol}{"MnglName"})
Andrey Ponomarenko85043792012-05-14 16:48:07 +040011019 {
Andrey Ponomarenko16934472012-03-29 15:37:04 +040011020 if($UsedDump{1}{"SrcBin"})
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011021 {
Andrey Ponomarenko16934472012-03-29 15:37:04 +040011022 if($UsedDump{2}{"BinOnly"} or not checkDumpVersion(2, "2.11"))
Andrey Ponomarenko85043792012-05-14 16:48:07 +040011023 { # support for old and different (!) ABI dumps
Andrey Ponomarenko16934472012-03-29 15:37:04 +040011024 if(not $CompleteSignature{1}{$Symbol}{"Virt"}
11025 and not $CompleteSignature{1}{$Symbol}{"PureVirt"})
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011026 {
Andrey Ponomarenko16934472012-03-29 15:37:04 +040011027 if($CheckHeadersOnly)
11028 { # skip all removed symbols
Andrey Ponomarenko85043792012-05-14 16:48:07 +040011029 if(my $Lang = $CompleteSignature{1}{$Symbol}{"Lang"})
11030 {
11031 if($Lang eq "C")
11032 { # support for old ABI dumps: missed extern "C" functions
11033 next;
11034 }
11035 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011036 }
Andrey Ponomarenko16934472012-03-29 15:37:04 +040011037 else
11038 {
11039 if(not link_symbol($Symbol, 1, "-Deps"))
11040 { # skip removed inline symbols
11041 next;
11042 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011043 }
11044 }
11045 }
11046 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +040011047 if(not checkDumpVersion(1, "2.14"))
11048 { # support for old ABI dumps
11049 if($Symbol=~/_IT_E\Z/)
11050 { # _ZN28QExplicitlySharedDataPointerI22QSslCertificatePrivateEC1IT_EERKS_IT_E
11051 next;
11052 }
11053 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011054 $RemovedInt{$Level}{$Symbol} = 1;
11055 if($Level eq "Source")
11056 { # search for a source-compatible equivalent
11057 setAlternative($Symbol, $Level);
11058 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011059 }
11060 }
11061}
11062
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011063sub mergeHeaders($)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011064{
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011065 my $Level = $_[0];
11066 foreach my $Symbol (sort keys(%{$AddedInt{$Level}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011067 { # checking added symbols
11068 next if($CompleteSignature{2}{$Symbol}{"PureVirt"});
Andrey Ponomarenko85043792012-05-14 16:48:07 +040011069 if($Level eq "Binary")
11070 {
11071 if($CompleteSignature{2}{$Symbol}{"InLine"})
11072 {
11073 if(not $CompleteSignature{2}{$Symbol}{"Virt"})
11074 { # skip inline non-virtual functions
11075 next;
11076 }
11077 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011078 }
11079 else
11080 { # Source
11081 if($SourceAlternative_B{$Symbol}) {
11082 next;
11083 }
11084 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011085 next if($CompleteSignature{2}{$Symbol}{"Private"});
Andrey Ponomarenko85043792012-05-14 16:48:07 +040011086 next if(not symbolFilter($Symbol, 2, "Affected", $Level));
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011087 %{$CompatProblems{$Level}{$Symbol}{"Added_Symbol"}{""}}=();
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011088 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011089 foreach my $Symbol (sort keys(%{$RemovedInt{$Level}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011090 { # checking removed symbols
11091 next if($CompleteSignature{1}{$Symbol}{"PureVirt"});
Andrey Ponomarenko85043792012-05-14 16:48:07 +040011092 if($Level eq "Binary")
11093 {
11094 if($CompleteSignature{1}{$Symbol}{"InLine"})
11095 {
11096 if(not $CompleteSignature{1}{$Symbol}{"Virt"})
11097 { # skip inline non-virtual functions
11098 next;
11099 }
11100 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011101 }
11102 else
11103 { # Source
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040011104 if(my $Alt = $SourceAlternative{$Symbol})
11105 {
11106 if(defined $CompleteSignature{1}{$Alt}
11107 and $CompleteSignature{1}{$Symbol}{"Const"})
11108 {
11109 %{$CompatProblems{$Level}{$Symbol}{"Removed_Const_Overload"}{$tr_name{$Symbol}}}=(
Andrey Ponomarenko85043792012-05-14 16:48:07 +040011110 "Type_Name"=>get_TypeName($CompleteSignature{1}{$Symbol}{"Class"}, 1),
11111 "Type_Type"=>"Class",
11112 "Target"=>get_Signature($Alt, 1) );
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040011113 }
11114 else
11115 { # do NOT show removed symbol
11116 next;
11117 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011118 }
11119 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011120 next if($CompleteSignature{1}{$Symbol}{"Private"});
Andrey Ponomarenko85043792012-05-14 16:48:07 +040011121 next if(not symbolFilter($Symbol, 1, "Affected", $Level));
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011122 %{$CompatProblems{$Level}{$Symbol}{"Removed_Symbol"}{""}}=();
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011123 }
11124}
11125
11126sub addParamNames($)
11127{
11128 my $LibraryVersion = $_[0];
11129 return if(not keys(%AddIntParams));
11130 my $SecondVersion = $LibraryVersion==1?2:1;
11131 foreach my $Interface (sort keys(%{$CompleteSignature{$LibraryVersion}}))
11132 {
11133 next if(not keys(%{$AddIntParams{$Interface}}));
11134 foreach my $ParamPos (sort {int($a)<=>int($b)} keys(%{$CompleteSignature{$LibraryVersion}{$Interface}{"Param"}}))
Andrey Ponomarenko85043792012-05-14 16:48:07 +040011135 { # add absent parameter names
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011136 my $ParamName = $CompleteSignature{$LibraryVersion}{$Interface}{"Param"}{$ParamPos}{"name"};
11137 if($ParamName=~/\Ap\d+\Z/ and my $NewParamName = $AddIntParams{$Interface}{$ParamPos})
Andrey Ponomarenko85043792012-05-14 16:48:07 +040011138 { # names from the external file
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011139 if(defined $CompleteSignature{$SecondVersion}{$Interface}
11140 and defined $CompleteSignature{$SecondVersion}{$Interface}{"Param"}{$ParamPos})
11141 {
11142 if($CompleteSignature{$SecondVersion}{$Interface}{"Param"}{$ParamPos}{"name"}=~/\Ap\d+\Z/) {
11143 $CompleteSignature{$LibraryVersion}{$Interface}{"Param"}{$ParamPos}{"name"} = $NewParamName;
11144 }
11145 }
11146 else {
11147 $CompleteSignature{$LibraryVersion}{$Interface}{"Param"}{$ParamPos}{"name"} = $NewParamName;
11148 }
11149 }
11150 }
11151 }
11152}
11153
11154sub detectChangedTypedefs()
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +040011155{ # detect changed typedefs to show
11156 # correct function signatures
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011157 foreach my $Typedef (keys(%{$Typedef_BaseName{1}}))
11158 {
11159 next if(not $Typedef);
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +040011160 my $BName1 = $Typedef_BaseName{1}{$Typedef};
11161 if(not $BName1 or isAnon($BName1)) {
11162 next;
11163 }
11164 my $BName2 = $Typedef_BaseName{2}{$Typedef};
11165 if(not $BName2 or isAnon($BName2)) {
11166 next;
11167 }
11168 if($BName1 ne $BName2) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011169 $ChangedTypedef{$Typedef} = 1;
11170 }
11171 }
11172}
11173
11174sub get_symbol_suffix($$)
11175{
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011176 my ($Symbol, $Full) = @_;
11177 my ($SN, $SO, $SV) = separate_symbol($Symbol);
11178 $Symbol=$SN;# remove version
11179 my $Signature = $tr_name{$Symbol};
Andrey Ponomarenko16934472012-03-29 15:37:04 +040011180 my $Suffix = substr($Signature, find_center($Signature, "("));
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011181 if(not $Full) {
11182 $Suffix=~s/(\))\s*(const volatile|volatile const|const|volatile)\Z/$1/g;
11183 }
11184 return $Suffix;
11185}
11186
11187sub get_symbol_prefix($$)
11188{
11189 my ($Symbol, $LibVersion) = @_;
11190 my $ShortName = $CompleteSignature{$LibVersion}{$Symbol}{"ShortName"};
11191 if(my $ClassId = $CompleteSignature{$LibVersion}{$Symbol}{"Class"})
11192 { # methods
11193 $ShortName = get_TypeName($ClassId, $LibVersion)."::".$ShortName;
11194 }
11195 return $ShortName;
11196}
11197
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011198sub setAlternative($)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011199{
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011200 my $Symbol = $_[0];
11201 my $PSymbol = $Symbol;
11202 if(not defined $CompleteSignature{2}{$PSymbol}
11203 or (not $CompleteSignature{2}{$PSymbol}{"MnglName"}
11204 and not $CompleteSignature{2}{$PSymbol}{"ShortName"}))
11205 { # search for a pair
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040011206 if(my $ShortName = $CompleteSignature{1}{$PSymbol}{"ShortName"})
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011207 {
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040011208 if($CompleteSignature{1}{$PSymbol}{"Data"})
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011209 {
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040011210 if($PSymbol=~s/L(\d+$ShortName(E)\Z)/$1/
11211 or $PSymbol=~s/(\d+$ShortName(E)\Z)/L$1/)
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011212 {
11213 if(defined $CompleteSignature{2}{$PSymbol}
11214 and $CompleteSignature{2}{$PSymbol}{"MnglName"})
11215 {
11216 $SourceAlternative{$Symbol} = $PSymbol;
11217 $SourceAlternative_B{$PSymbol} = $Symbol;
11218 if(not defined $CompleteSignature{1}{$PSymbol}
11219 or not $CompleteSignature{1}{$PSymbol}{"MnglName"}) {
11220 $SourceReplacement{$Symbol} = $PSymbol;
11221 }
11222 }
11223 }
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040011224 }
11225 else
11226 {
11227 foreach my $Sp ("KV", "VK", "K", "V")
11228 {
11229 if($PSymbol=~s/\A_ZN$Sp/_ZN/
11230 or $PSymbol=~s/\A_ZN/_ZN$Sp/)
11231 {
11232 if(defined $CompleteSignature{2}{$PSymbol}
11233 and $CompleteSignature{2}{$PSymbol}{"MnglName"})
11234 {
11235 $SourceAlternative{$Symbol} = $PSymbol;
11236 $SourceAlternative_B{$PSymbol} = $Symbol;
11237 if(not defined $CompleteSignature{1}{$PSymbol}
11238 or not $CompleteSignature{1}{$PSymbol}{"MnglName"}) {
11239 $SourceReplacement{$Symbol} = $PSymbol;
11240 }
11241 }
11242 }
11243 $PSymbol = $Symbol;
11244 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011245 }
11246 }
11247 }
11248 return "";
11249}
11250
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040011251sub getSymKind($$)
11252{
11253 my ($Symbol, $LibVersion) = @_;
11254 if($CompleteSignature{$LibVersion}{$Symbol}{"Data"})
11255 {
11256 return "Global_Data";
11257 }
11258 elsif($CompleteSignature{$LibVersion}{$Symbol}{"Class"})
11259 {
11260 return "Method";
11261 }
11262 return "Function";
11263}
11264
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011265sub mergeSignatures($)
11266{
11267 my $Level = $_[0];
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011268 my %SubProblems = ();
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011269
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011270 mergeBases($Level);
11271
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011272 my %AddedOverloads = ();
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011273 foreach my $Symbol (sort keys(%{$AddedInt{$Level}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011274 { # check all added exported symbols
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011275 if(not $CompleteSignature{2}{$Symbol}{"Header"}) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011276 next;
11277 }
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040011278 if(defined $CompleteSignature{1}{$Symbol}
11279 and $CompleteSignature{1}{$Symbol}{"Header"})
11280 { # double-check added symbol
11281 next;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011282 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +040011283 if(not symbolFilter($Symbol, 2, "Affected", $Level)) {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011284 next;
11285 }
11286 if($Symbol=~/\A(_Z|\?)/)
11287 { # C++
11288 $AddedOverloads{get_symbol_prefix($Symbol, 2)}{get_symbol_suffix($Symbol, 1)} = $Symbol;
11289 }
11290 if(my $OverriddenMethod = $CompleteSignature{2}{$Symbol}{"Override"})
11291 { # register virtual overridings
11292 my $AffectedClass_Name = get_TypeName($CompleteSignature{2}{$Symbol}{"Class"}, 2);
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040011293 if(defined $CompleteSignature{1}{$OverriddenMethod} and $CompleteSignature{1}{$OverriddenMethod}{"Virt"}
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011294 and not $CompleteSignature{1}{$OverriddenMethod}{"Private"})
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040011295 {
11296 if($TName_Tid{1}{$AffectedClass_Name})
11297 { # class should exist in previous version
11298 if(not isCopyingClass($TName_Tid{1}{$AffectedClass_Name}, 1))
11299 { # old v-table is NOT copied by old applications
11300 %{$CompatProblems{$Level}{$OverriddenMethod}{"Overridden_Virtual_Method"}{$tr_name{$Symbol}}}=(
11301 "Type_Name"=>$AffectedClass_Name,
11302 "Type_Type"=>"Class",
11303 "Target"=>get_Signature($Symbol, 2),
11304 "Old_Value"=>get_Signature($OverriddenMethod, 2),
11305 "New_Value"=>get_Signature($Symbol, 2) );
11306 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011307 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011308 }
11309 }
11310 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011311 foreach my $Symbol (sort keys(%{$RemovedInt{$Level}}))
11312 { # check all removed exported symbols
11313 if(not $CompleteSignature{1}{$Symbol}{"Header"}) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011314 next;
11315 }
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040011316 if(defined $CompleteSignature{2}{$Symbol}
11317 and $CompleteSignature{2}{$Symbol}{"Header"})
11318 { # double-check removed symbol
11319 next;
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011320 }
11321 if($CompleteSignature{1}{$Symbol}{"Private"})
11322 { # skip private methods
11323 next;
11324 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +040011325 if(not symbolFilter($Symbol, 1, "Affected", $Level)) {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011326 next;
11327 }
11328 $CheckedSymbols{$Level}{$Symbol} = 1;
11329 if(my $OverriddenMethod = $CompleteSignature{1}{$Symbol}{"Override"})
11330 { # register virtual overridings
11331 my $AffectedClass_Name = get_TypeName($CompleteSignature{1}{$Symbol}{"Class"}, 1);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011332 if(defined $CompleteSignature{2}{$OverriddenMethod}
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040011333 and $CompleteSignature{2}{$OverriddenMethod}{"Virt"})
11334 {
11335 if($TName_Tid{2}{$AffectedClass_Name})
11336 { # class should exist in newer version
11337 if(not isCopyingClass($CompleteSignature{1}{$Symbol}{"Class"}, 1))
11338 { # old v-table is NOT copied by old applications
11339 %{$CompatProblems{$Level}{$Symbol}{"Overridden_Virtual_Method_B"}{$tr_name{$OverriddenMethod}}}=(
11340 "Type_Name"=>$AffectedClass_Name,
11341 "Type_Type"=>"Class",
11342 "Target"=>get_Signature($OverriddenMethod, 1),
11343 "Old_Value"=>get_Signature($Symbol, 1),
11344 "New_Value"=>get_Signature($OverriddenMethod, 1) );
11345 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011346 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011347 }
11348 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011349 if($Level eq "Binary"
11350 and $OSgroup eq "windows")
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011351 { # register the reason of symbol name change
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011352 if(my $NewSymbol = $mangled_name{2}{$tr_name{$Symbol}})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011353 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011354 if($AddedInt{$Level}{$NewSymbol})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011355 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011356 if($CompleteSignature{1}{$Symbol}{"Static"} ne $CompleteSignature{2}{$NewSymbol}{"Static"})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011357 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011358 if($CompleteSignature{2}{$NewSymbol}{"Static"})
11359 {
11360 %{$CompatProblems{$Level}{$Symbol}{"Symbol_Became_Static"}{$tr_name{$Symbol}}}=(
11361 "Target"=>$tr_name{$Symbol},
11362 "Old_Value"=>$Symbol,
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011363 "New_Value"=>$NewSymbol );
11364 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011365 else
11366 {
11367 %{$CompatProblems{$Level}{$Symbol}{"Symbol_Became_NonStatic"}{$tr_name{$Symbol}}}=(
11368 "Target"=>$tr_name{$Symbol},
11369 "Old_Value"=>$Symbol,
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011370 "New_Value"=>$NewSymbol );
11371 }
11372 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011373 if($CompleteSignature{1}{$Symbol}{"Virt"} ne $CompleteSignature{2}{$NewSymbol}{"Virt"})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011374 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011375 if($CompleteSignature{2}{$NewSymbol}{"Virt"})
11376 {
11377 %{$CompatProblems{$Level}{$Symbol}{"Symbol_Became_Virtual"}{$tr_name{$Symbol}}}=(
11378 "Target"=>$tr_name{$Symbol},
11379 "Old_Value"=>$Symbol,
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011380 "New_Value"=>$NewSymbol );
11381 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011382 else
11383 {
11384 %{$CompatProblems{$Level}{$Symbol}{"Symbol_Became_NonVirtual"}{$tr_name{$Symbol}}}=(
11385 "Target"=>$tr_name{$Symbol},
11386 "Old_Value"=>$Symbol,
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011387 "New_Value"=>$NewSymbol );
11388 }
11389 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011390 my $ReturnTypeName1 = get_TypeName($CompleteSignature{1}{$Symbol}{"Return"}, 1);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011391 my $ReturnTypeName2 = get_TypeName($CompleteSignature{2}{$NewSymbol}{"Return"}, 2);
11392 if($ReturnTypeName1 ne $ReturnTypeName2)
11393 {
11394 my $ProblemType = "Symbol_Changed_Return";
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011395 if($CompleteSignature{1}{$Symbol}{"Data"}) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011396 $ProblemType = "Global_Data_Symbol_Changed_Type";
11397 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011398 %{$CompatProblems{$Level}{$Symbol}{$ProblemType}{$tr_name{$Symbol}}}=(
11399 "Target"=>$tr_name{$Symbol},
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011400 "Old_Type"=>$ReturnTypeName1,
11401 "New_Type"=>$ReturnTypeName2,
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011402 "Old_Value"=>$Symbol,
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011403 "New_Value"=>$NewSymbol );
11404 }
11405 }
11406 }
11407 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011408 if($Symbol=~/\A(_Z|\?)/)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011409 { # C++
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011410 my $Prefix = get_symbol_prefix($Symbol, 1);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011411 if(my @Overloads = sort keys(%{$AddedOverloads{$Prefix}})
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011412 and not $AddedOverloads{$Prefix}{get_symbol_suffix($Symbol, 1)})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011413 { # changed signature: params, "const"-qualifier
11414 my $NewSymbol = $AddedOverloads{$Prefix}{$Overloads[0]};
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011415 if($CompleteSignature{1}{$Symbol}{"Constructor"})
11416 {
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +040011417 if($Symbol=~/(C1E|C2E)/)
11418 {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011419 my $CtorType = $1;
11420 $NewSymbol=~s/(C1E|C2E)/$CtorType/g;
11421 }
11422 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011423 elsif($CompleteSignature{1}{$Symbol}{"Destructor"})
11424 {
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +040011425 if($Symbol=~/(D0E|D1E|D2E)/)
11426 {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011427 my $DtorType = $1;
11428 $NewSymbol=~s/(D0E|D1E|D2E)/$DtorType/g;
11429 }
11430 }
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040011431 my $NS1 = $CompleteSignature{1}{$Symbol}{"NameSpace"};
11432 my $NS2 = $CompleteSignature{2}{$NewSymbol}{"NameSpace"};
11433 if((not $NS1 and not $NS2) or ($NS1 and $NS2 and $NS1 eq $NS2))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011434 { # from the same class and namespace
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011435 if($CompleteSignature{1}{$Symbol}{"Const"}
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011436 and not $CompleteSignature{2}{$NewSymbol}{"Const"})
11437 { # "const" to non-"const"
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040011438 %{$CompatProblems{$Level}{$Symbol}{"Method_Became_NonConst"}{$tr_name{$Symbol}}}=(
11439 "Type_Name"=>get_TypeName($CompleteSignature{1}{$Symbol}{"Class"}, 1),
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011440 "Target"=>$tr_name{$Symbol},
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011441 "New_Signature"=>get_Signature($NewSymbol, 2),
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011442 "Old_Value"=>$Symbol,
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011443 "New_Value"=>$NewSymbol );
11444 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011445 elsif(not $CompleteSignature{1}{$Symbol}{"Const"}
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011446 and $CompleteSignature{2}{$NewSymbol}{"Const"})
11447 { # non-"const" to "const"
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040011448 %{$CompatProblems{$Level}{$Symbol}{"Method_Became_Const"}{$tr_name{$Symbol}}}=(
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011449 "Target"=>$tr_name{$Symbol},
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011450 "New_Signature"=>get_Signature($NewSymbol, 2),
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011451 "Old_Value"=>$Symbol,
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011452 "New_Value"=>$NewSymbol );
11453 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011454 if($CompleteSignature{1}{$Symbol}{"Volatile"}
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011455 and not $CompleteSignature{2}{$NewSymbol}{"Volatile"})
11456 { # "volatile" to non-"volatile"
11457
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040011458 %{$CompatProblems{$Level}{$Symbol}{"Method_Became_NonVolatile"}{$tr_name{$Symbol}}}=(
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011459 "Target"=>$tr_name{$Symbol},
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011460 "New_Signature"=>get_Signature($NewSymbol, 2),
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011461 "Old_Value"=>$Symbol,
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011462 "New_Value"=>$NewSymbol );
11463 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011464 elsif(not $CompleteSignature{1}{$Symbol}{"Volatile"}
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011465 and $CompleteSignature{2}{$NewSymbol}{"Volatile"})
11466 { # non-"volatile" to "volatile"
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040011467 %{$CompatProblems{$Level}{$Symbol}{"Method_Became_Volatile"}{$tr_name{$Symbol}}}=(
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011468 "Target"=>$tr_name{$Symbol},
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011469 "New_Signature"=>get_Signature($NewSymbol, 2),
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011470 "Old_Value"=>$Symbol,
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011471 "New_Value"=>$NewSymbol );
11472 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011473 if(get_symbol_suffix($Symbol, 0) ne get_symbol_suffix($NewSymbol, 0))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011474 { # params list
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011475 %{$CompatProblems{$Level}{$Symbol}{"Symbol_Changed_Parameters"}{$tr_name{$Symbol}}}=(
11476 "Target"=>$tr_name{$Symbol},
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011477 "New_Signature"=>get_Signature($NewSymbol, 2),
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011478 "Old_Value"=>$Symbol,
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011479 "New_Value"=>$NewSymbol );
11480 }
11481 }
11482 }
11483 }
11484 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011485 foreach my $Symbol (sort keys(%{$CompleteSignature{1}}))
11486 { # checking symbols
11487 my ($SN, $SS, $SV) = separate_symbol($Symbol);
11488 if($Level eq "Source")
11489 { # remove symbol version
11490 $Symbol=$SN;
11491 }
11492 else
11493 { # Binary
11494 if(not $SV)
11495 { # symbol without version
11496 if(my $VSym = $SymVer{1}{$Symbol})
11497 { # the symbol is linked with versioned symbol
11498 if($CompleteSignature{2}{$VSym}{"MnglName"})
11499 { # show report for symbol@ver only
11500 next;
11501 }
11502 elsif(not link_symbol($VSym, 2, "-Deps"))
11503 { # changed version: sym@v1 to sym@v2
11504 # do NOT show report for symbol
11505 next;
11506 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011507 }
11508 }
11509 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011510 my $PSymbol = $Symbol;
11511 if($Level eq "Source"
11512 and my $S = $SourceReplacement{$Symbol})
11513 { # take a source-compatible replacement function
11514 $PSymbol = $S;
11515 }
11516 if($CompleteSignature{1}{$Symbol}{"Private"})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011517 { # private symbols
11518 next;
11519 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011520 if(not defined $CompleteSignature{1}{$Symbol}
11521 or not defined $CompleteSignature{2}{$PSymbol})
11522 { # no info
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011523 next;
11524 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011525 if(not $CompleteSignature{1}{$Symbol}{"MnglName"}
11526 or not $CompleteSignature{2}{$PSymbol}{"MnglName"})
11527 { # no mangled name
11528 next;
11529 }
11530 if(not $CompleteSignature{1}{$Symbol}{"Header"}
11531 or not $CompleteSignature{2}{$PSymbol}{"Header"})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011532 { # without a header
11533 next;
11534 }
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040011535 if(checkDumpVersion(1, "2.13") and checkDumpVersion(2, "2.13"))
11536 {
11537 if($CompleteSignature{1}{$Symbol}{"Data"}
11538 and $CompleteSignature{2}{$PSymbol}{"Data"})
11539 {
11540 my $Value1 = $CompleteSignature{1}{$Symbol}{"Value"};
11541 my $Value2 = $CompleteSignature{2}{$PSymbol}{"Value"};
11542 if(defined $Value1)
11543 {
11544 $Value1 = showVal($Value1, $CompleteSignature{1}{$Symbol}{"Return"}, 1);
11545 if(defined $Value2)
11546 {
11547 $Value2 = showVal($Value2, $CompleteSignature{2}{$PSymbol}{"Return"}, 2);
11548 if($Value1 ne $Value2)
11549 {
11550 %{$CompatProblems{$Level}{$Symbol}{"Global_Data_Value_Changed"}{""}}=(
11551 "Old_Value"=>$Value1,
11552 "New_Value"=>$Value2,
11553 "Target"=>get_Signature($Symbol, 1) );
11554 }
11555 }
11556 }
11557 }
11558 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +040011559
11560 if(not $CompleteSignature{1}{$Symbol}{"PureVirt"}
11561 and $CompleteSignature{2}{$PSymbol}{"PureVirt"})
11562 { # became pure
11563 next;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011564 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +040011565 if($CompleteSignature{1}{$Symbol}{"PureVirt"}
11566 and not $CompleteSignature{2}{$PSymbol}{"PureVirt"})
11567 { # became non-pure
11568 next;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011569 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +040011570
11571 if(not symbolFilter($Symbol, 1, "Affected + InlineVirt", $Level))
11572 { # exported, target, inline virtual and pure virtual
11573 next;
11574 }
11575 if(not symbolFilter($PSymbol, 2, "Affected + InlineVirt", $Level))
11576 { # exported, target, inline virtual and pure virtual
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011577 next;
11578 }
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040011579
11580 if($CompleteSignature{2}{$PSymbol}{"Private"})
11581 {
11582 %{$CompatProblems{$Level}{$Symbol}{getSymKind($Symbol, 1)."_Became_Private"}{""}}=(
11583 "Target"=>get_Signature_M($PSymbol, 2) );
11584 }
11585 elsif(not $CompleteSignature{1}{$Symbol}{"Protected"}
11586 and $CompleteSignature{2}{$PSymbol}{"Protected"})
11587 {
11588 %{$CompatProblems{$Level}{$Symbol}{getSymKind($Symbol, 1)."_Became_Protected"}{""}}=(
11589 "Target"=>get_Signature_M($PSymbol, 2) );
11590 }
11591 elsif($CompleteSignature{1}{$Symbol}{"Protected"}
11592 and not $CompleteSignature{2}{$PSymbol}{"Protected"})
11593 {
11594 %{$CompatProblems{$Level}{$Symbol}{getSymKind($Symbol, 1)."_Became_Public"}{""}}=(
11595 "Target"=>get_Signature_M($PSymbol, 2) );
11596 }
11597
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011598 # checking virtual table
Andrey Ponomarenko16934472012-03-29 15:37:04 +040011599 mergeVirtualTables($Symbol, $Level);
11600
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011601 if($COMPILE_ERRORS)
11602 { # if some errors occurred at the compiling stage
11603 # then some false positives can be skipped here
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011604 if(not $CompleteSignature{1}{$Symbol}{"Data"} and $CompleteSignature{2}{$PSymbol}{"Data"}
11605 and not $CompleteSignature{2}{$Symbol}{"Object"})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011606 { # missed information about parameters in newer version
11607 next;
11608 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011609 if($CompleteSignature{1}{$Symbol}{"Data"} and not $CompleteSignature{1}{$Symbol}{"Object"}
11610 and not $CompleteSignature{2}{$PSymbol}{"Data"})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011611 {# missed information about parameters in older version
11612 next;
11613 }
11614 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011615 my ($MnglName, $VersionSpec, $SymbolVersion) = separate_symbol($Symbol);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011616 # checking attributes
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011617 if($CompleteSignature{2}{$PSymbol}{"Static"}
11618 and not $CompleteSignature{1}{$Symbol}{"Static"} and $Symbol=~/\A(_Z|\?)/) {
11619 %{$CompatProblems{$Level}{$Symbol}{"Method_Became_Static"}{""}}=(
11620 "Target"=>get_Signature($Symbol, 1)
11621 );
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011622 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011623 elsif(not $CompleteSignature{2}{$PSymbol}{"Static"}
11624 and $CompleteSignature{1}{$Symbol}{"Static"} and $Symbol=~/\A(_Z|\?)/) {
11625 %{$CompatProblems{$Level}{$Symbol}{"Method_Became_NonStatic"}{""}}=(
11626 "Target"=>get_Signature($Symbol, 1)
11627 );
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011628 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011629 if(($CompleteSignature{1}{$Symbol}{"Virt"} and $CompleteSignature{2}{$PSymbol}{"Virt"})
11630 or ($CompleteSignature{1}{$Symbol}{"PureVirt"} and $CompleteSignature{2}{$PSymbol}{"PureVirt"}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011631 { # relative position of virtual and pure virtual methods
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011632 if($Level eq "Binary")
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011633 {
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040011634 if(defined $CompleteSignature{1}{$Symbol}{"RelPos"} and defined $CompleteSignature{2}{$PSymbol}{"RelPos"}
11635 and $CompleteSignature{1}{$Symbol}{"RelPos"}!=$CompleteSignature{2}{$PSymbol}{"RelPos"})
11636 { # top-level virtual methods only
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011637 my $Class_Id = $CompleteSignature{1}{$Symbol}{"Class"};
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040011638 my $Class_Name = get_TypeName($Class_Id, 1);
11639 if(defined $VirtualTable{1}{$Class_Name} and defined $VirtualTable{2}{$Class_Name}
11640 and $VirtualTable{1}{$Class_Name}{$Symbol}!=$VirtualTable{2}{$Class_Name}{$Symbol})
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011641 { # check the absolute position of virtual method (including added and removed methods)
11642 my %Class_Type = get_Type($Tid_TDid{1}{$Class_Id}, $Class_Id, 1);
11643 my $ProblemType = "Virtual_Method_Position";
11644 if($CompleteSignature{1}{$Symbol}{"PureVirt"}) {
11645 $ProblemType = "Pure_Virtual_Method_Position";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011646 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011647 if(isUsedClass($Class_Id, 1, $Level))
11648 {
11649 my @Affected = ($Symbol, keys(%{$OverriddenMethods{1}{$Symbol}}));
11650 foreach my $AffectedInterface (@Affected)
11651 {
11652 %{$CompatProblems{$Level}{$AffectedInterface}{$ProblemType}{$tr_name{$MnglName}}}=(
11653 "Type_Name"=>$Class_Type{"Name"},
11654 "Type_Type"=>"Class",
11655 "Old_Value"=>$CompleteSignature{1}{$Symbol}{"RelPos"},
11656 "New_Value"=>$CompleteSignature{2}{$PSymbol}{"RelPos"},
11657 "Target"=>get_Signature($Symbol, 1) );
11658 }
Andrey Ponomarenko16934472012-03-29 15:37:04 +040011659 $VTableChanged_M{$Class_Type{"Name"}} = 1;
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011660 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011661 }
11662 }
11663 }
11664 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011665 if($CompleteSignature{1}{$Symbol}{"PureVirt"}
11666 or $CompleteSignature{2}{$PSymbol}{"PureVirt"})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011667 { # do NOT check type changes in pure virtuals
11668 next;
11669 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011670 $CheckedSymbols{$Level}{$Symbol}=1;
11671 if($Symbol=~/\A(_Z|\?)/
11672 or keys(%{$CompleteSignature{1}{$Symbol}{"Param"}})==keys(%{$CompleteSignature{2}{$PSymbol}{"Param"}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011673 { # C/C++: changes in parameters
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011674 foreach my $ParamPos (sort {int($a) <=> int($b)} keys(%{$CompleteSignature{1}{$Symbol}{"Param"}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011675 { # checking parameters
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011676 mergeParameters($Symbol, $PSymbol, $ParamPos, $ParamPos, $Level);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011677 }
11678 }
11679 else
11680 { # C: added/removed parameters
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011681 foreach my $ParamPos (sort {int($a) <=> int($b)} keys(%{$CompleteSignature{2}{$PSymbol}{"Param"}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011682 { # checking added parameters
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040011683 my $PType2_Id = $CompleteSignature{2}{$PSymbol}{"Param"}{$ParamPos}{"type"};
11684 last if(get_TypeName($PType2_Id, 2) eq "...");
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011685 my $Parameter_Name = $CompleteSignature{2}{$PSymbol}{"Param"}{$ParamPos}{"name"};
11686 my $Parameter_OldName = (defined $CompleteSignature{1}{$Symbol}{"Param"}{$ParamPos})?$CompleteSignature{1}{$Symbol}{"Param"}{$ParamPos}{"name"}:"";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011687 my $ParamPos_Prev = "-1";
11688 if($Parameter_Name=~/\Ap\d+\Z/i)
11689 { # added unnamed parameter ( pN )
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040011690 my @Positions1 = find_ParamPair_Pos_byTypeAndPos(get_TypeName($PType2_Id, 2), $ParamPos, "backward", $Symbol, 1);
11691 my @Positions2 = find_ParamPair_Pos_byTypeAndPos(get_TypeName($PType2_Id, 2), $ParamPos, "backward", $Symbol, 2);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011692 if($#Positions1==-1 or $#Positions2>$#Positions1) {
11693 $ParamPos_Prev = "lost";
11694 }
11695 }
11696 else {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011697 $ParamPos_Prev = find_ParamPair_Pos_byName($Parameter_Name, $Symbol, 1);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011698 }
11699 if($ParamPos_Prev eq "lost")
11700 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011701 if($ParamPos>keys(%{$CompleteSignature{1}{$Symbol}{"Param"}})-1)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011702 {
11703 my $ProblemType = "Added_Parameter";
11704 if($Parameter_Name=~/\Ap\d+\Z/) {
11705 $ProblemType = "Added_Unnamed_Parameter";
11706 }
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040011707 %{$CompatProblems{$Level}{$Symbol}{$ProblemType}{showPos($ParamPos)." Parameter"}}=(
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011708 "Target"=>$Parameter_Name,
11709 "Param_Pos"=>$ParamPos,
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040011710 "Param_Type"=>get_TypeName($PType2_Id, 2),
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011711 "New_Signature"=>get_Signature($Symbol, 2) );
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011712 }
11713 else
11714 {
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040011715 my %ParamType_Pure = get_PureType($Tid_TDid{2}{$PType2_Id}, $PType2_Id, 2);
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011716 my $ParamStraightPairType_Id = $CompleteSignature{1}{$Symbol}{"Param"}{$ParamPos}{"type"};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011717 my %ParamStraightPairType_Pure = get_PureType($Tid_TDid{1}{$ParamStraightPairType_Id}, $ParamStraightPairType_Id, 1);
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040011718 if(($ParamType_Pure{"Name"} eq $ParamStraightPairType_Pure{"Name"} or get_TypeName($PType2_Id, 2) eq get_TypeName($ParamStraightPairType_Id, 1))
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011719 and find_ParamPair_Pos_byName($Parameter_OldName, $Symbol, 2) eq "lost")
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011720 {
11721 if($Parameter_OldName!~/\Ap\d+\Z/ and $Parameter_Name!~/\Ap\d+\Z/)
11722 {
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040011723 %{$CompatProblems{$Level}{$Symbol}{"Renamed_Parameter"}{showPos($ParamPos)." Parameter"}}=(
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011724 "Target"=>$Parameter_OldName,
11725 "Param_Pos"=>$ParamPos,
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040011726 "Param_Type"=>get_TypeName($PType2_Id, 2),
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011727 "Old_Value"=>$Parameter_OldName,
11728 "New_Value"=>$Parameter_Name,
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011729 "New_Signature"=>get_Signature($Symbol, 2) );
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011730 }
11731 }
11732 else
11733 {
11734 my $ProblemType = "Added_Middle_Parameter";
11735 if($Parameter_Name=~/\Ap\d+\Z/) {
11736 $ProblemType = "Added_Middle_Unnamed_Parameter";
11737 }
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040011738 %{$CompatProblems{$Level}{$Symbol}{$ProblemType}{showPos($ParamPos)." Parameter"}}=(
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011739 "Target"=>$Parameter_Name,
11740 "Param_Pos"=>$ParamPos,
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040011741 "Param_Type"=>get_TypeName($PType2_Id, 2),
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011742 "New_Signature"=>get_Signature($Symbol, 2) );
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011743 }
11744 }
11745 }
11746 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011747 foreach my $ParamPos (sort {int($a) <=> int($b)} keys(%{$CompleteSignature{1}{$Symbol}{"Param"}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011748 { # check relevant parameters
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040011749 my $PType1_Id = $CompleteSignature{1}{$Symbol}{"Param"}{$ParamPos}{"type"};
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011750 my $ParamName1 = $CompleteSignature{1}{$Symbol}{"Param"}{$ParamPos}{"name"};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011751 # FIXME: find relevant parameter by name
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011752 if(defined $CompleteSignature{2}{$PSymbol}{"Param"}{$ParamPos})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011753 {
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040011754 my $PType2_Id = $CompleteSignature{2}{$PSymbol}{"Param"}{$ParamPos}{"type"};
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011755 my $ParamName2 = $CompleteSignature{2}{$PSymbol}{"Param"}{$ParamPos}{"name"};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011756 if(($ParamName1!~/\Ap\d+\Z/i and $ParamName1 eq $ParamName2)
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040011757 or get_TypeName($PType1_Id, 1) eq get_TypeName($PType2_Id, 2)) {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011758 mergeParameters($Symbol, $PSymbol, $ParamPos, $ParamPos, $Level);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011759 }
11760 }
11761 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011762 foreach my $ParamPos (sort {int($a) <=> int($b)} keys(%{$CompleteSignature{1}{$Symbol}{"Param"}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011763 { # checking removed parameters
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040011764 my $PType1_Id = $CompleteSignature{1}{$Symbol}{"Param"}{$ParamPos}{"type"};
11765 last if(get_TypeName($PType1_Id, 1) eq "...");
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011766 my $Parameter_Name = $CompleteSignature{1}{$Symbol}{"Param"}{$ParamPos}{"name"};
11767 my $Parameter_NewName = (defined $CompleteSignature{2}{$PSymbol}{"Param"}{$ParamPos})?$CompleteSignature{2}{$PSymbol}{"Param"}{$ParamPos}{"name"}:"";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011768 my $ParamPos_New = "-1";
11769 if($Parameter_Name=~/\Ap\d+\Z/i)
11770 { # removed unnamed parameter ( pN )
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040011771 my @Positions1 = find_ParamPair_Pos_byTypeAndPos(get_TypeName($PType1_Id, 1), $ParamPos, "forward", $Symbol, 1);
11772 my @Positions2 = find_ParamPair_Pos_byTypeAndPos(get_TypeName($PType1_Id, 1), $ParamPos, "forward", $Symbol, 2);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011773 if($#Positions2==-1 or $#Positions2<$#Positions1) {
11774 $ParamPos_New = "lost";
11775 }
11776 }
11777 else {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011778 $ParamPos_New = find_ParamPair_Pos_byName($Parameter_Name, $Symbol, 2);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011779 }
11780 if($ParamPos_New eq "lost")
11781 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011782 if($ParamPos>keys(%{$CompleteSignature{2}{$PSymbol}{"Param"}})-1)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011783 {
11784 my $ProblemType = "Removed_Parameter";
11785 if($Parameter_Name=~/\Ap\d+\Z/) {
11786 $ProblemType = "Removed_Unnamed_Parameter";
11787 }
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040011788 %{$CompatProblems{$Level}{$Symbol}{$ProblemType}{showPos($ParamPos)." Parameter"}}=(
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011789 "Target"=>$Parameter_Name,
11790 "Param_Pos"=>$ParamPos,
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040011791 "Param_Type"=>get_TypeName($PType1_Id, 1),
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011792 "New_Signature"=>get_Signature($Symbol, 2) );
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011793 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011794 elsif($ParamPos<keys(%{$CompleteSignature{1}{$Symbol}{"Param"}})-1)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011795 {
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040011796 my %ParamType_Pure = get_PureType($Tid_TDid{1}{$PType1_Id}, $PType1_Id, 1);
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011797 my $ParamStraightPairType_Id = $CompleteSignature{2}{$PSymbol}{"Param"}{$ParamPos}{"type"};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011798 my %ParamStraightPairType_Pure = get_PureType($Tid_TDid{2}{$ParamStraightPairType_Id}, $ParamStraightPairType_Id, 2);
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040011799 if(($ParamType_Pure{"Name"} eq $ParamStraightPairType_Pure{"Name"} or get_TypeName($PType1_Id, 1) eq get_TypeName($ParamStraightPairType_Id, 2))
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011800 and find_ParamPair_Pos_byName($Parameter_NewName, $Symbol, 1) eq "lost")
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011801 {
11802 if($Parameter_NewName!~/\Ap\d+\Z/ and $Parameter_Name!~/\Ap\d+\Z/)
11803 {
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040011804 %{$CompatProblems{$Level}{$Symbol}{"Renamed_Parameter"}{showPos($ParamPos)." Parameter"}}=(
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011805 "Target"=>$Parameter_Name,
11806 "Param_Pos"=>$ParamPos,
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040011807 "Param_Type"=>get_TypeName($PType1_Id, 1),
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011808 "Old_Value"=>$Parameter_Name,
11809 "New_Value"=>$Parameter_NewName,
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011810 "New_Signature"=>get_Signature($Symbol, 2) );
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011811 }
11812 }
11813 else
11814 {
11815 my $ProblemType = "Removed_Middle_Parameter";
11816 if($Parameter_Name=~/\Ap\d+\Z/) {
11817 $ProblemType = "Removed_Middle_Unnamed_Parameter";
11818 }
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040011819 %{$CompatProblems{$Level}{$Symbol}{$ProblemType}{showPos($ParamPos)." Parameter"}}=(
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011820 "Target"=>$Parameter_Name,
11821 "Param_Pos"=>$ParamPos,
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040011822 "Param_Type"=>get_TypeName($PType1_Id, 1),
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011823 "New_Signature"=>get_Signature($Symbol, 2) );
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011824 }
11825 }
11826 }
11827 }
11828 }
11829 # checking return type
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011830 my $ReturnType1_Id = $CompleteSignature{1}{$Symbol}{"Return"};
11831 my $ReturnType2_Id = $CompleteSignature{2}{$PSymbol}{"Return"};
11832 %SubProblems = detectTypeChange($ReturnType1_Id, $ReturnType2_Id, "Return", $Level);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011833 foreach my $SubProblemType (keys(%SubProblems))
11834 {
11835 my $New_Value = $SubProblems{$SubProblemType}{"New_Value"};
11836 my $Old_Value = $SubProblems{$SubProblemType}{"Old_Value"};
11837 my $NewProblemType = $SubProblemType;
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011838 if($Level eq "Binary" and $SubProblemType eq "Return_Type_Became_Void"
11839 and keys(%{$CompleteSignature{1}{$Symbol}{"Param"}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011840 { # parameters stack has been affected
11841 $NewProblemType = "Return_Type_Became_Void_And_Stack_Layout";
11842 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011843 elsif($Level eq "Binary"
11844 and $SubProblemType eq "Return_Type_From_Void")
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011845 { # parameters stack has been affected
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011846 if(keys(%{$CompleteSignature{1}{$Symbol}{"Param"}})) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011847 $NewProblemType = "Return_Type_From_Void_And_Stack_Layout";
11848 }
11849 else
11850 { # safe
11851 delete($SubProblems{$SubProblemType});
11852 next;
11853 }
11854 }
11855 elsif($SubProblemType eq "Return_Type_And_Size"
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011856 and $CompleteSignature{1}{$Symbol}{"Data"}) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011857 $NewProblemType = "Global_Data_Type_And_Size";
11858 }
11859 elsif($SubProblemType eq "Return_Type")
11860 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011861 if($CompleteSignature{1}{$Symbol}{"Data"})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011862 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011863 if(removedQual($Old_Value, $New_Value, "const"))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011864 { # const -> non-const global data
11865 $NewProblemType = "Global_Data_Became_Non_Const";
11866 }
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040011867 elsif(addedQual($Old_Value, $New_Value, "const"))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011868 { # non-const -> const global data
11869 $NewProblemType = "Global_Data_Became_Const";
11870 }
11871 else {
11872 $NewProblemType = "Global_Data_Type";
11873 }
11874 }
11875 else
11876 {
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040011877 if(addedQual($Old_Value, $New_Value, "const")) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011878 $NewProblemType = "Return_Type_Became_Const";
11879 }
11880 }
11881 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011882 elsif($SubProblemType eq "Return_Type_Format")
11883 {
11884 if($CompleteSignature{1}{$Symbol}{"Data"}) {
11885 $NewProblemType = "Global_Data_Type_Format";
11886 }
11887 }
11888 @{$CompatProblems{$Level}{$Symbol}{$NewProblemType}{"retval"}}{keys(%{$SubProblems{$SubProblemType}})} = values %{$SubProblems{$SubProblemType}};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011889 }
11890 if($ReturnType1_Id and $ReturnType2_Id)
11891 {
11892 @RecurTypes = ();
11893 %SubProblems = mergeTypes($ReturnType1_Id, $Tid_TDid{1}{$ReturnType1_Id},
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011894 $ReturnType2_Id, $Tid_TDid{2}{$ReturnType2_Id}, $Level);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011895 foreach my $SubProblemType (keys(%SubProblems))
11896 { # add "Global_Data_Size" problem
11897 my $New_Value = $SubProblems{$SubProblemType}{"New_Value"};
11898 my $Old_Value = $SubProblems{$SubProblemType}{"Old_Value"};
11899 if($SubProblemType eq "DataType_Size"
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011900 and $CompleteSignature{1}{$Symbol}{"Data"}
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011901 and get_PointerLevel($Tid_TDid{1}{$ReturnType1_Id}, $ReturnType1_Id, 1)==0)
11902 { # add a new problem
11903 %{$SubProblems{"Global_Data_Size"}} = %{$SubProblems{$SubProblemType}};
11904 }
11905 }
11906 foreach my $SubProblemType (keys(%SubProblems))
11907 {
11908 foreach my $SubLocation (keys(%{$SubProblems{$SubProblemType}}))
11909 {
11910 my $NewLocation = ($SubLocation)?"retval->".$SubLocation:"retval";
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011911 %{$CompatProblems{$Level}{$Symbol}{$SubProblemType}{$NewLocation}}=(
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011912 "Return_Type_Name"=>get_TypeName($ReturnType1_Id, 1) );
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011913 @{$CompatProblems{$Level}{$Symbol}{$SubProblemType}{$NewLocation}}{keys(%{$SubProblems{$SubProblemType}{$SubLocation}})} = values %{$SubProblems{$SubProblemType}{$SubLocation}};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011914 if($SubLocation!~/\-\>/) {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011915 $CompatProblems{$Level}{$Symbol}{$SubProblemType}{$NewLocation}{"Start_Type_Name"} = get_TypeName($ReturnType1_Id, 1);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011916 }
11917 }
11918 }
11919 }
11920
11921 # checking object type
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011922 my $ObjectType1_Id = $CompleteSignature{1}{$Symbol}{"Class"};
11923 my $ObjectType2_Id = $CompleteSignature{2}{$PSymbol}{"Class"};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011924 if($ObjectType1_Id and $ObjectType2_Id
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011925 and not $CompleteSignature{1}{$Symbol}{"Static"})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011926 {
11927 my $ThisPtr1_Id = getTypeIdByName(get_TypeName($ObjectType1_Id, 1)."*const", 1);
11928 my $ThisPtr2_Id = getTypeIdByName(get_TypeName($ObjectType2_Id, 2)."*const", 2);
11929 if($ThisPtr1_Id and $ThisPtr2_Id)
11930 {
11931 @RecurTypes = ();
11932 %SubProblems = mergeTypes($ThisPtr1_Id, $Tid_TDid{1}{$ThisPtr1_Id},
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011933 $ThisPtr2_Id, $Tid_TDid{2}{$ThisPtr2_Id}, $Level);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011934 foreach my $SubProblemType (keys(%SubProblems))
11935 {
11936 foreach my $SubLocation (keys(%{$SubProblems{$SubProblemType}}))
11937 {
11938 my $NewLocation = ($SubLocation)?"this->".$SubLocation:"this";
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011939 %{$CompatProblems{$Level}{$Symbol}{$SubProblemType}{$NewLocation}}=(
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011940 "Object_Type_Name"=>get_TypeName($ObjectType1_Id, 1) );
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011941 @{$CompatProblems{$Level}{$Symbol}{$SubProblemType}{$NewLocation}}{keys(%{$SubProblems{$SubProblemType}{$SubLocation}})} = values %{$SubProblems{$SubProblemType}{$SubLocation}};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011942 if($SubLocation!~/\-\>/) {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011943 $CompatProblems{$Level}{$Symbol}{$SubProblemType}{$NewLocation}{"Start_Type_Name"} = get_TypeName($ObjectType1_Id, 1);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011944 }
11945 }
11946 }
11947 }
11948 }
11949 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011950 if($Level eq "Binary") {
11951 mergeVTables($Level);
11952 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +040011953 foreach my $Symbol (keys(%{$CompatProblems{$Level}})) {
11954 $CheckedSymbols{$Level}{$Symbol} = 1;
11955 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011956}
11957
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040011958sub rmQuals($$)
11959{
11960 my ($Value, $Qual) = @_;
11961 if(not $Qual) {
11962 return $Value;
11963 }
11964 if($Qual eq "all")
11965 { # all quals
11966 $Qual = "const|volatile|restrict";
11967 }
11968 while($Value=~s/(\A|\W)($Qual)(\W|\Z)/$1$3/)
11969 {
11970 $Value=~s/(\A|\W)\s+(\W|\Z)//g;
11971 $Value = formatName($Value);
11972 }
11973 return $Value;
11974}
11975
11976sub cmpBTypes($$$$)
11977{
11978 my ($T1, $T2, $V1, $V2) = @_;
11979 $T1 = uncover_typedefs($T1, $V1);
11980 $T2 = uncover_typedefs($T2, $V2);
11981 return (rmQuals($T1, "all") eq rmQuals($T2, "all"));
11982}
11983
11984sub addedQual($$$)
11985{
11986 my ($Old_Value, $New_Value, $Qual) = @_;
Andrey Ponomarenko85043792012-05-14 16:48:07 +040011987 return removedQual_($New_Value, $Old_Value, 2, 1, $Qual);
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040011988}
11989
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011990sub removedQual($$$)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011991{
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011992 my ($Old_Value, $New_Value, $Qual) = @_;
Andrey Ponomarenko85043792012-05-14 16:48:07 +040011993 return removedQual_($Old_Value, $New_Value, 1, 2, $Qual);
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040011994}
11995
11996sub removedQual_($$$$$)
11997{
11998 my ($Old_Value, $New_Value, $V1, $V2, $Qual) = @_;
11999 $Old_Value = uncover_typedefs($Old_Value, $V1);
12000 $New_Value = uncover_typedefs($New_Value, $V2);
12001 if($Old_Value eq $New_Value)
12002 { # equal types
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012003 return 0;
12004 }
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040012005 if($Old_Value!~/(\A|\W)$Qual(\W|\Z)/)
12006 { # without a qual
12007 return 0;
12008 }
12009 elsif($New_Value!~/(\A|\W)$Qual(\W|\Z)/)
12010 { # became non-qual
12011 return 1;
12012 }
12013 else
12014 {
12015 my @BQ1 = getQualModel($Old_Value, $Qual);
12016 my @BQ2 = getQualModel($New_Value, $Qual);
12017 foreach (0 .. $#BQ1)
12018 { # removed qual
12019 if($BQ1[$_]==1
12020 and $BQ2[$_]!=1)
12021 {
12022 return 2;
12023 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012024 }
12025 }
12026 return 0;
12027}
12028
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040012029sub getQualModel($$)
12030{
12031 my ($Value, $Qual) = @_;
12032 if(not $Qual) {
12033 return $Value;
12034 }
12035
12036 # cleaning
12037 while($Value=~/(\w+)/ and $1 ne $Qual)
12038 {
12039 $Value=~s/(\A|\W)$1(\W|\Z)/$1$2/g;
12040 $Value=~s/(\A|\W)\s+(\W|\Z)//g;
12041 }
12042 $Value=~s/[^\*\&\w]+//g;
12043
12044 # modeling
12045 # int*const*const == 011
12046 # int**const == 001
12047 my @Model = ();
12048 my @Elems = split(/[\*\&]/, $Value);
12049 if(not @Elems) {
12050 return (0);
12051 }
12052 foreach (@Elems)
12053 {
12054 if($_ eq $Qual) {
12055 push(@Model, 1);
12056 }
12057 else {
12058 push(@Model, 0);
12059 }
12060 }
12061
12062 return @Model;
12063}
12064
12065sub showVal($$$)
12066{
12067 my ($Value, $TypeId, $LibVersion) = @_;
12068 my %PureType = get_PureType($Tid_TDid{$LibVersion}{$TypeId}, $TypeId, $LibVersion);
12069 if($PureType{"Name"}=~/\Achar(| const)\*\Z/)
12070 { # strings
12071 return "\"$Value\"";
12072 }
12073 elsif($PureType{"Name"}=~/\Achar(| const)\Z/)
12074 { # characters
12075 return "\'$Value\'";
12076 }
12077 return $Value;
12078}
12079
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012080sub mergeParameters($$$$$)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012081{
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012082 my ($Symbol, $PSymbol, $ParamPos1, $ParamPos2, $Level) = @_;
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040012083 if(not $Symbol) {
12084 return;
12085 }
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040012086 my $PType1_Id = $CompleteSignature{1}{$Symbol}{"Param"}{$ParamPos1}{"type"};
12087 my $PName1 = $CompleteSignature{1}{$Symbol}{"Param"}{$ParamPos1}{"name"};
12088 my $PType2_Id = $CompleteSignature{2}{$PSymbol}{"Param"}{$ParamPos2}{"type"};
12089 my $PName2 = $CompleteSignature{2}{$PSymbol}{"Param"}{$ParamPos2}{"name"};
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040012090 if(not $PType1_Id
12091 or not $PType2_Id) {
12092 return;
12093 }
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040012094 my %Type1 = get_Type($Tid_TDid{1}{$PType1_Id}, $PType1_Id, 1);
12095 my %Type2 = get_Type($Tid_TDid{2}{$PType2_Id}, $PType2_Id, 2);
12096 my %BaseType1 = get_BaseType($Tid_TDid{1}{$PType1_Id}, $PType1_Id, 1);
12097 my %BaseType2 = get_BaseType($Tid_TDid{2}{$PType2_Id}, $PType2_Id, 2);
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040012098 my $Parameter_Location = ($PName1)?$PName1:showPos($ParamPos1)." Parameter";
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012099 if($Level eq "Binary")
12100 {
12101 if(checkDumpVersion(1, "2.6.1") and checkDumpVersion(2, "2.6.1"))
12102 { # "reg" attribute added in ACC 1.95.1 (dump 2.6.1 format)
12103 if($CompleteSignature{1}{$Symbol}{"Param"}{$ParamPos1}{"reg"}
12104 and not $CompleteSignature{2}{$PSymbol}{"Param"}{$ParamPos2}{"reg"})
12105 {
12106 %{$CompatProblems{$Level}{$Symbol}{"Parameter_Became_Non_Register"}{$Parameter_Location}}=(
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040012107 "Target"=>$PName1,
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012108 "Param_Pos"=>$ParamPos1 );
12109 }
12110 elsif(not $CompleteSignature{1}{$Symbol}{"Param"}{$ParamPos1}{"reg"}
12111 and $CompleteSignature{2}{$PSymbol}{"Param"}{$ParamPos2}{"reg"})
12112 {
12113 %{$CompatProblems{$Level}{$Symbol}{"Parameter_Became_Register"}{$Parameter_Location}}=(
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040012114 "Target"=>$PName1,
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012115 "Param_Pos"=>$ParamPos1 );
12116 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012117 }
12118 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012119 if(checkDumpVersion(1, "2.0") and checkDumpVersion(2, "2.0"))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012120 { # "default" attribute added in ACC 1.22 (dump 2.0 format)
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040012121 my $Value_Old = $CompleteSignature{1}{$Symbol}{"Param"}{$ParamPos1}{"default"};
12122 my $Value_New = $CompleteSignature{2}{$PSymbol}{"Param"}{$ParamPos2}{"default"};
12123 if(not checkDumpVersion(1, "2.13")
12124 and checkDumpVersion(2, "2.13"))
12125 { # support for old ABI dumps
12126 if(defined $Value_Old and defined $Value_New)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012127 {
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040012128 if($Type1{"Name"} eq "bool"
12129 and $Value_Old eq "false" and $Value_New eq "0")
12130 { # int class::method ( bool p = 0 );
12131 # old ABI dumps: "false"
12132 # new ABI dumps: "0"
12133 $Value_Old = "0";
12134 }
12135 }
12136 }
12137 if(defined $Value_Old)
12138 {
12139 $Value_Old = showVal($Value_Old, $PType1_Id, 1);
12140 if(defined $Value_New)
12141 {
12142 $Value_New = showVal($Value_New, $PType2_Id, 2);
12143 if($Value_Old ne $Value_New)
12144 { # FIXME: how to distinguish "0" and 0 (NULL)
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012145 %{$CompatProblems{$Level}{$Symbol}{"Parameter_Default_Value_Changed"}{$Parameter_Location}}=(
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040012146 "Target"=>$PName1,
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012147 "Param_Pos"=>$ParamPos1,
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040012148 "Old_Value"=>$Value_Old,
12149 "New_Value"=>$Value_New );
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012150 }
12151 }
12152 else
12153 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012154 %{$CompatProblems{$Level}{$Symbol}{"Parameter_Default_Value_Removed"}{$Parameter_Location}}=(
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040012155 "Target"=>$PName1,
12156 "Param_Pos"=>$ParamPos1,
12157 "Old_Value"=>$Value_Old );
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012158 }
12159 }
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040012160 elsif(defined $Value_New)
12161 {
12162 $Value_New = showVal($Value_New, $PType2_Id, 2);
12163 %{$CompatProblems{$Level}{$Symbol}{"Parameter_Default_Value_Added"}{$Parameter_Location}}=(
12164 "Target"=>$PName1,
12165 "Param_Pos"=>$ParamPos1,
12166 "New_Value"=>$Value_New );
12167 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012168 }
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040012169 if($PName1 and $PName2 and $PName1 ne $PName2
12170 and $PType1_Id!=-1 and $PType2_Id!=-1
12171 and $PName1!~/\Ap\d+\Z/ and $PName2!~/\Ap\d+\Z/)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012172 { # except unnamed "..." value list (Id=-1)
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040012173 %{$CompatProblems{$Level}{$Symbol}{"Renamed_Parameter"}{showPos($ParamPos1)." Parameter"}}=(
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040012174 "Target"=>$PName1,
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012175 "Param_Pos"=>$ParamPos1,
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040012176 "Param_Type"=>get_TypeName($PType1_Id, 1),
12177 "Old_Value"=>$PName1,
12178 "New_Value"=>$PName2,
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012179 "New_Signature"=>get_Signature($Symbol, 2) );
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012180 }
12181 # checking type change (replace)
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040012182 my %SubProblems = detectTypeChange($PType1_Id, $PType2_Id, "Parameter", $Level);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012183 foreach my $SubProblemType (keys(%SubProblems))
12184 { # add new problems, remove false alarms
12185 my $New_Value = $SubProblems{$SubProblemType}{"New_Value"};
12186 my $Old_Value = $SubProblems{$SubProblemType}{"Old_Value"};
12187 if($SubProblemType eq "Parameter_Type")
12188 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012189 if(checkDumpVersion(1, "2.6") and checkDumpVersion(2, "2.6"))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012190 {
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040012191 if(my $RA = addedQual($Old_Value, $New_Value, "restrict"))
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012192 {
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040012193 %{$SubProblems{"Parameter_Became_Restrict"}} = %{$SubProblems{$SubProblemType}};
12194 if($Level eq "Source"
12195 and cmpBTypes($Old_Value, $New_Value, 1, 2)) {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012196 delete($SubProblems{$SubProblemType});
12197 }
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040012198 }
12199 elsif(my $RR = removedQual($Old_Value, $New_Value, "restrict"))
12200 {
12201 %{$SubProblems{"Parameter_Became_NonRestrict"}} = %{$SubProblems{$SubProblemType}};
12202 if($Level eq "Source"
12203 and cmpBTypes($Old_Value, $New_Value, 1, 2)) {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012204 delete($SubProblems{$SubProblemType});
12205 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012206 }
12207 }
12208 if($Type2{"Type"} eq "Const" and $BaseType2{"Name"} eq $Type1{"Name"}
12209 and $Type1{"Type"}=~/Intrinsic|Class|Struct|Union|Enum/)
12210 { # int to "int const"
12211 delete($SubProblems{$SubProblemType});
12212 }
12213 if($Type1{"Type"} eq "Const" and $BaseType1{"Name"} eq $Type2{"Name"}
12214 and $Type2{"Type"}=~/Intrinsic|Class|Struct|Union|Enum/)
12215 { # "int const" to int
12216 delete($SubProblems{$SubProblemType});
12217 }
12218 }
12219 }
12220 foreach my $SubProblemType (keys(%SubProblems))
12221 { # modify/register problems
12222 my $New_Value = $SubProblems{$SubProblemType}{"New_Value"};
12223 my $Old_Value = $SubProblems{$SubProblemType}{"Old_Value"};
12224 my $NewProblemType = $SubProblemType;
12225 if($Old_Value eq "..." and $New_Value ne "...")
12226 { # change from "..." to "int"
12227 if($ParamPos1==0)
12228 { # ISO C requires a named argument before "..."
12229 next;
12230 }
12231 $NewProblemType = "Parameter_Became_NonVaList";
12232 }
12233 elsif($New_Value eq "..." and $Old_Value ne "...")
12234 { # change from "int" to "..."
12235 if($ParamPos2==0)
12236 { # ISO C requires a named argument before "..."
12237 next;
12238 }
12239 $NewProblemType = "Parameter_Became_VaList";
12240 }
12241 elsif($SubProblemType eq "Parameter_Type"
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012242 and removedQual($Old_Value, $New_Value, "const"))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012243 { # parameter: "const" to non-"const"
12244 $NewProblemType = "Parameter_Became_Non_Const";
12245 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012246 elsif($Level eq "Binary" and ($SubProblemType eq "Parameter_Type_And_Size"
12247 or $SubProblemType eq "Parameter_Type"))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012248 {
12249 my ($Arch1, $Arch2) = (getArch(1), getArch(2));
12250 if($Arch1 eq "unknown" or $Arch2 eq "unknown")
12251 { # if one of the architectures is unknown
12252 # then set other arhitecture to unknown too
12253 ($Arch1, $Arch2) = ("unknown", "unknown");
12254 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012255 my ($Method1, $Passed1, $SizeOnStack1, $RegName1) = callingConvention($Symbol, $ParamPos1, 1, $Arch1);
12256 my ($Method2, $Passed2, $SizeOnStack2, $RegName2) = callingConvention($Symbol, $ParamPos2, 2, $Arch2);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012257 if($Method1 eq $Method2)
12258 {
12259 if($Method1 eq "stack" and $SizeOnStack1 ne $SizeOnStack2) {
12260 $NewProblemType = "Parameter_Type_And_Stack";
12261 }
12262 elsif($Method1 eq "register" and $RegName1 ne $RegName2) {
12263 $NewProblemType = "Parameter_Type_And_Register";
12264 }
12265 }
12266 else
12267 {
12268 if($Method1 eq "stack") {
12269 $NewProblemType = "Parameter_Type_And_Pass_Through_Register";
12270 }
12271 elsif($Method1 eq "register") {
12272 $NewProblemType = "Parameter_Type_And_Pass_Through_Stack";
12273 }
12274 }
12275 $SubProblems{$SubProblemType}{"Old_Reg"} = $RegName1;
12276 $SubProblems{$SubProblemType}{"New_Reg"} = $RegName2;
12277 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012278 %{$CompatProblems{$Level}{$Symbol}{$NewProblemType}{$Parameter_Location}}=(
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040012279 "Target"=>$PName1,
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012280 "Param_Pos"=>$ParamPos1,
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012281 "New_Signature"=>get_Signature($Symbol, 2) );
12282 @{$CompatProblems{$Level}{$Symbol}{$NewProblemType}{$Parameter_Location}}{keys(%{$SubProblems{$SubProblemType}})} = values %{$SubProblems{$SubProblemType}};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012283 }
12284 @RecurTypes = ();
12285 # checking type definition changes
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040012286 my %SubProblems_Merge = mergeTypes($PType1_Id, $Tid_TDid{1}{$PType1_Id}, $PType2_Id, $Tid_TDid{2}{$PType2_Id}, $Level);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012287 foreach my $SubProblemType (keys(%SubProblems_Merge))
12288 {
12289 foreach my $SubLocation (keys(%{$SubProblems_Merge{$SubProblemType}}))
12290 {
12291 my $NewProblemType = $SubProblemType;
12292 if($SubProblemType eq "DataType_Size")
12293 {
12294 my $InitialType_Type = $SubProblems_Merge{$SubProblemType}{$SubLocation}{"InitialType_Type"};
12295 if($InitialType_Type!~/\A(Pointer|Ref)\Z/ and $SubLocation!~/\-\>/)
12296 { # stack has been affected
12297 $NewProblemType = "DataType_Size_And_Stack";
12298 }
12299 }
12300 my $NewLocation = ($SubLocation)?$Parameter_Location."->".$SubLocation:$Parameter_Location;
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012301 %{$CompatProblems{$Level}{$Symbol}{$NewProblemType}{$NewLocation}}=(
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040012302 "Param_Type"=>get_TypeName($PType1_Id, 1),
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012303 "Param_Pos"=>$ParamPos1,
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040012304 "Param_Name"=>$PName1 );
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012305 @{$CompatProblems{$Level}{$Symbol}{$NewProblemType}{$NewLocation}}{keys(%{$SubProblems_Merge{$SubProblemType}{$SubLocation}})} = values %{$SubProblems_Merge{$SubProblemType}{$SubLocation}};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012306 if($SubLocation!~/\-\>/) {
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040012307 $CompatProblems{$Level}{$Symbol}{$NewProblemType}{$NewLocation}{"Start_Type_Name"} = get_TypeName($PType1_Id, 1);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012308 }
12309 }
12310 }
12311}
12312
12313sub callingConvention($$$$)
12314{ # calling conventions for different compilers and operating systems
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012315 my ($Symbol, $ParamPos, $LibVersion, $Arch) = @_;
12316 my $ParamTypeId = $CompleteSignature{$LibVersion}{$Symbol}{"Param"}{$ParamPos}{"type"};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012317 my %Type = get_PureType($Tid_TDid{$LibVersion}{$ParamTypeId}, $ParamTypeId, $LibVersion);
12318 my ($Method, $Alignment, $Passed, $Register) = ("", 0, "", "");
12319 if($OSgroup=~/\A(linux|macos|freebsd)\Z/)
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012320 { # GCC
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012321 if($Arch eq "x86")
12322 { # System V ABI Intel386 ("Function Calling Sequence")
12323 # The stack is word aligned. Although the architecture does not require any
12324 # alignment of the stack, software convention and the operating system
12325 # requires that the stack be aligned on a word boundary.
12326
12327 # Argument words are pushed onto the stack in reverse order (that is, the
12328 # rightmost argument in C call syntax has the highest address), preserving the
12329 # stack’s word alignment. All incoming arguments appear on the stack, residing
12330 # in the stack frame of the caller.
12331
12332 # An argument’s size is increased, if necessary, to make it a multiple of words.
12333 # This may require tail padding, depending on the size of the argument.
12334
12335 # Other areas depend on the compiler and the code being compiled. The stan-
12336 # dard calling sequence does not define a maximum stack frame size, nor does
12337 # it restrict how a language system uses the ‘‘unspecified’’ area of the stan-
12338 # dard stack frame.
12339 ($Method, $Alignment) = ("stack", 4);
12340 }
12341 elsif($Arch eq "x86_64")
12342 { # System V AMD64 ABI ("Function Calling Sequence")
12343 ($Method, $Alignment) = ("stack", 8);# eightbyte aligned
12344 }
12345 elsif($Arch eq "arm")
12346 { # Procedure Call Standard for the ARM Architecture
12347 # The stack must be double-word aligned
12348 ($Method, $Alignment) = ("stack", 8);# double-word
12349 }
12350 }
12351 elsif($OSgroup eq "windows")
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012352 { # MS C++ Compiler
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012353 if($Arch eq "x86")
12354 {
12355 if($ParamPos==0) {
12356 ($Method, $Register, $Passed) = ("register", "ecx", "value");
12357 }
12358 elsif($ParamPos==1) {
12359 ($Method, $Register, $Passed) = ("register", "edx", "value");
12360 }
12361 else {
12362 ($Method, $Alignment) = ("stack", 4);
12363 }
12364 }
12365 elsif($Arch eq "x86_64")
12366 {
12367 if($ParamPos<=3)
12368 {
12369 if($Type{"Name"}=~/\A(float|double|long double)\Z/) {
12370 ($Method, $Passed) = ("xmm".$ParamPos, "value");
12371 }
12372 elsif($Type{"Name"}=~/\A(unsigned |)(short|int|long|long long)\Z/
12373 or $Type{"Type"}=~/\A(Struct|Union|Enum|Array)\Z/
12374 or $Type{"Name"}=~/\A(__m64|__m128)\Z/)
12375 {
12376 if($ParamPos==0) {
12377 ($Method, $Register, $Passed) = ("register", "rcx", "value");
12378 }
12379 elsif($ParamPos==1) {
12380 ($Method, $Register, $Passed) = ("register", "rdx", "value");
12381 }
12382 elsif($ParamPos==2) {
12383 ($Method, $Register, $Passed) = ("register", "r8", "value");
12384 }
12385 elsif($ParamPos==3) {
12386 ($Method, $Register, $Passed) = ("register", "r9", "value");
12387 }
12388 if($Type{"Size"}>64
12389 or $Type{"Type"} eq "Array") {
12390 $Passed = "pointer";
12391 }
12392 }
12393 }
12394 else {
12395 ($Method, $Alignment) = ("stack", 8);# word alignment
12396 }
12397 }
12398 }
12399 if($Method eq "register") {
12400 return ("register", $Passed, "", $Register);
12401 }
12402 else
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012403 { # on the stack
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012404 if(not $Alignment)
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012405 { # default convention
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012406 $Alignment = $WORD_SIZE{$LibVersion};
12407 }
12408 if(not $Passed)
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012409 { # default convention
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012410 $Passed = "value";
12411 }
12412 my $SizeOnStack = $Type{"Size"};
12413 # FIXME: improve stack alignment
12414 if($SizeOnStack!=$Alignment) {
12415 $SizeOnStack = int(($Type{"Size"}+$Alignment)/$Alignment)*$Alignment;
12416 }
12417 return ("stack", $Passed, $SizeOnStack, "");
12418 }
12419}
12420
12421sub find_ParamPair_Pos_byName($$$)
12422{
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012423 my ($Name, $Symbol, $LibVersion) = @_;
12424 foreach my $ParamPos (sort {int($a)<=>int($b)} keys(%{$CompleteSignature{$LibVersion}{$Symbol}{"Param"}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012425 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012426 next if(not defined $CompleteSignature{$LibVersion}{$Symbol}{"Param"}{$ParamPos});
12427 if($CompleteSignature{$LibVersion}{$Symbol}{"Param"}{$ParamPos}{"name"} eq $Name)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012428 {
12429 return $ParamPos;
12430 }
12431 }
12432 return "lost";
12433}
12434
12435sub find_ParamPair_Pos_byTypeAndPos($$$$$)
12436{
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012437 my ($TypeName, $MediumPos, $Order, $Symbol, $LibVersion) = @_;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012438 my @Positions = ();
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012439 foreach my $ParamPos (sort {int($a)<=>int($b)} keys(%{$CompleteSignature{$LibVersion}{$Symbol}{"Param"}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012440 {
12441 next if($Order eq "backward" and $ParamPos>$MediumPos);
12442 next if($Order eq "forward" and $ParamPos<$MediumPos);
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012443 next if(not defined $CompleteSignature{$LibVersion}{$Symbol}{"Param"}{$ParamPos});
12444 my $PTypeId = $CompleteSignature{$LibVersion}{$Symbol}{"Param"}{$ParamPos}{"type"};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012445 if(get_TypeName($PTypeId, $LibVersion) eq $TypeName) {
12446 push(@Positions, $ParamPos);
12447 }
12448 }
12449 return @Positions;
12450}
12451
12452sub getTypeIdByName($$)
12453{
12454 my ($TypeName, $Version) = @_;
12455 return $TName_Tid{$Version}{formatName($TypeName)};
12456}
12457
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012458sub checkFormatChange($$$)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012459{
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012460 my ($Type1_Id, $Type2_Id, $Level) = @_;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012461 my $Type1_DId = $Tid_TDid{1}{$Type1_Id};
12462 my $Type2_DId = $Tid_TDid{2}{$Type2_Id};
12463 my %Type1_Pure = get_PureType($Type1_DId, $Type1_Id, 1);
12464 my %Type2_Pure = get_PureType($Type2_DId, $Type2_Id, 2);
12465 if($Type1_Pure{"Name"} eq $Type2_Pure{"Name"})
12466 { # equal types
12467 return 0;
12468 }
12469 if($Type1_Pure{"Name"}=~/\*/
12470 or $Type2_Pure{"Name"}=~/\*/)
12471 { # compared in detectTypeChange()
12472 return 0;
12473 }
12474 my %FloatType = map {$_=>1} (
12475 "float",
12476 "double",
12477 "long double"
12478 );
12479 if($Type1_Pure{"Type"} ne $Type2_Pure{"Type"})
12480 { # different types
12481 if($Type1_Pure{"Type"} eq "Intrinsic"
12482 and $Type2_Pure{"Type"} eq "Enum")
12483 { # "int" to "enum"
12484 return 0;
12485 }
12486 elsif($Type2_Pure{"Type"} eq "Intrinsic"
12487 and $Type1_Pure{"Type"} eq "Enum")
12488 { # "enum" to "int"
12489 return 0;
12490 }
12491 else
12492 { # "union" to "struct"
12493 # ...
12494 return 1;
12495 }
12496 }
12497 else
12498 {
12499 if($Type1_Pure{"Type"} eq "Intrinsic")
12500 {
12501 if($FloatType{$Type1_Pure{"Name"}}
12502 or $FloatType{$Type2_Pure{"Name"}})
12503 { # "float" to "double"
12504 # "float" to "int"
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012505 if($Level eq "Source")
12506 { # Safe
12507 return 0;
12508 }
12509 else {
12510 return 1;
12511 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012512 }
12513 }
12514 elsif($Type1_Pure{"Type"}=~/Class|Struct|Union|Enum/)
12515 {
12516 my @Membs1 = keys(%{$Type1_Pure{"Memb"}});
12517 my @Membs2 = keys(%{$Type2_Pure{"Memb"}});
12518 if($#Membs1!=$#Membs2)
12519 { # different number of elements
12520 return 1;
12521 }
12522 if($Type1_Pure{"Type"} eq "Enum")
12523 {
12524 foreach my $Pos (@Membs1)
12525 { # compare elements by name and value
12526 if($Type1_Pure{"Memb"}{$Pos}{"name"} ne $Type2_Pure{"Memb"}{$Pos}{"name"}
12527 or $Type1_Pure{"Memb"}{$Pos}{"value"} ne $Type2_Pure{"Memb"}{$Pos}{"value"})
12528 { # different names
12529 return 1;
12530 }
12531 }
12532 }
12533 else
12534 {
12535 foreach my $Pos (@Membs1)
12536 { # compare elements by type name
12537 my $MT1 = get_TypeName($Type1_Pure{"Memb"}{$Pos}{"type"}, 1);
12538 my $MT2 = get_TypeName($Type2_Pure{"Memb"}{$Pos}{"type"}, 2);
12539 if($MT1 ne $MT2)
12540 { # different types
12541 return 1;
12542 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012543 if($Level eq "Source")
12544 {
12545 if($Type1_Pure{"Memb"}{$Pos}{"name"} ne $Type2_Pure{"Memb"}{$Pos}{"name"})
12546 { # different names
12547 return 1;
12548 }
12549 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012550 }
12551 }
12552 }
12553 }
12554 return 0;
12555}
12556
12557sub isScalar($) {
12558 return ($_[0]=~/\A(unsigned |)(short|int|long|long long)\Z/);
12559}
12560
12561sub isFloat($) {
12562 return ($_[0]=~/\A(float|double|long double)\Z/);
12563}
12564
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012565sub detectTypeChange($$$$)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012566{
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012567 my ($Type1_Id, $Type2_Id, $Prefix, $Level) = @_;
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040012568 if(not $Type1_Id or not $Type2_Id) {
12569 return ();
12570 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012571 my %LocalProblems = ();
12572 my $Type1_DId = $Tid_TDid{1}{$Type1_Id};
12573 my $Type2_DId = $Tid_TDid{2}{$Type2_Id};
12574 my %Type1 = get_Type($Type1_DId, $Type1_Id, 1);
12575 my %Type2 = get_Type($Type2_DId, $Type2_Id, 2);
12576 my %Type1_Pure = get_PureType($Type1_DId, $Type1_Id, 1);
12577 my %Type2_Pure = get_PureType($Type2_DId, $Type2_Id, 2);
12578 my %Type1_Base = ($Type1_Pure{"Type"} eq "Array")?get_OneStep_BaseType($Type1_Pure{"TDid"}, $Type1_Pure{"Tid"}, 1):get_BaseType($Type1_DId, $Type1_Id, 1);
12579 my %Type2_Base = ($Type2_Pure{"Type"} eq "Array")?get_OneStep_BaseType($Type2_Pure{"TDid"}, $Type2_Pure{"Tid"}, 2):get_BaseType($Type2_DId, $Type2_Id, 2);
12580 my $Type1_PLevel = get_PointerLevel($Type1_DId, $Type1_Id, 1);
12581 my $Type2_PLevel = get_PointerLevel($Type2_DId, $Type2_Id, 2);
12582 return () if(not $Type1{"Name"} or not $Type2{"Name"});
12583 return () if(not $Type1_Base{"Name"} or not $Type2_Base{"Name"});
12584 return () if($Type1_PLevel eq "" or $Type2_PLevel eq "");
12585 if($Type1_Base{"Name"} ne $Type2_Base{"Name"}
12586 and ($Type1{"Name"} eq $Type2{"Name"} or ($Type1_PLevel>=1 and $Type1_PLevel==$Type2_PLevel
12587 and $Type1_Base{"Name"} ne "void" and $Type2_Base{"Name"} ne "void")))
12588 { # base type change
12589 if($Type1{"Type"} eq "Typedef" and $Type2{"Type"} eq "Typedef"
12590 and $Type1{"Name"} eq $Type2{"Name"})
12591 { # will be reported in mergeTypes() as typedef problem
12592 return ();
12593 }
12594 if($Type1_Base{"Name"}!~/anon\-/ and $Type2_Base{"Name"}!~/anon\-/)
12595 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012596 if($Level eq "Binary"
12597 and $Type1_Base{"Size"} ne $Type2_Base{"Size"}
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012598 and $Type1_Base{"Size"} and $Type2_Base{"Size"})
12599 {
12600 %{$LocalProblems{$Prefix."_BaseType_And_Size"}}=(
12601 "Old_Value"=>$Type1_Base{"Name"},
12602 "New_Value"=>$Type2_Base{"Name"},
12603 "Old_Size"=>$Type1_Base{"Size"}*$BYTE_SIZE,
12604 "New_Size"=>$Type2_Base{"Size"}*$BYTE_SIZE,
12605 "InitialType_Type"=>$Type1_Pure{"Type"});
12606 }
12607 else
12608 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012609 if(checkFormatChange($Type1_Base{"Tid"}, $Type2_Base{"Tid"}, $Level))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012610 { # format change
12611 %{$LocalProblems{$Prefix."_BaseType_Format"}}=(
12612 "Old_Value"=>$Type1_Base{"Name"},
12613 "New_Value"=>$Type2_Base{"Name"},
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012614 "InitialType_Type"=>$Type1_Pure{"Type"});
12615 }
12616 elsif(tNameLock($Type1_Base{"Tid"}, $Type2_Base{"Tid"}))
12617 {
12618 %{$LocalProblems{$Prefix."_BaseType"}}=(
12619 "Old_Value"=>$Type1_Base{"Name"},
12620 "New_Value"=>$Type2_Base{"Name"},
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012621 "InitialType_Type"=>$Type1_Pure{"Type"});
12622 }
12623 }
12624 }
12625 }
12626 elsif($Type1{"Name"} ne $Type2{"Name"})
12627 { # type change
12628 if($Type1{"Name"}!~/anon\-/ and $Type2{"Name"}!~/anon\-/)
12629 {
12630 if($Prefix eq "Return" and $Type1{"Name"} eq "void"
12631 and $Type2_Pure{"Type"}=~/Intrinsic|Enum/) {
12632 # safe change
12633 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012634 elsif($Level eq "Binary"
12635 and $Prefix eq "Return"
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012636 and $Type1_Pure{"Name"} eq "void")
12637 {
12638 %{$LocalProblems{"Return_Type_From_Void"}}=(
12639 "New_Value"=>$Type2{"Name"},
12640 "New_Size"=>$Type2{"Size"}*$BYTE_SIZE,
12641 "InitialType_Type"=>$Type1_Pure{"Type"});
12642 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012643 elsif($Level eq "Binary"
12644 and $Prefix eq "Return" and $Type1_Pure{"Type"}=~/Intrinsic|Enum/
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012645 and $Type2_Pure{"Type"}=~/Struct|Class|Union/)
12646 { # returns into hidden first parameter instead of a register
12647
12648 # System V ABI Intel386 ("Function Calling Sequence")
12649 # A function that returns an integral or pointer value places its result in register %eax.
12650
12651 # A floating-point return value appears on the top of the Intel387 register stack. The
12652 # caller then must remove the value from the Intel387 stack, even if it doesn’t use the
12653 # value.
12654
12655 # If a function returns a structure or union, then the caller provides space for the
12656 # return value and places its address on the stack as argument word zero. In effect,
12657 # this address becomes a ‘‘hidden’’ first argument.
12658
12659 %{$LocalProblems{"Return_Type_From_Register_To_Stack"}}=(
12660 "Old_Value"=>$Type1{"Name"},
12661 "New_Value"=>$Type2{"Name"},
12662 "Old_Size"=>$Type1{"Size"}*$BYTE_SIZE,
12663 "New_Size"=>$Type2{"Size"}*$BYTE_SIZE,
12664 "InitialType_Type"=>$Type1_Pure{"Type"});
12665 }
12666 elsif($Prefix eq "Return"
12667 and $Type2_Pure{"Name"} eq "void")
12668 {
12669 %{$LocalProblems{"Return_Type_Became_Void"}}=(
12670 "Old_Value"=>$Type1{"Name"},
12671 "Old_Size"=>$Type1{"Size"}*$BYTE_SIZE,
12672 "InitialType_Type"=>$Type1_Pure{"Type"});
12673 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012674 elsif($Level eq "Binary" and $Prefix eq "Return"
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012675 and ((isScalar($Type1_Pure{"Name"}) and isFloat($Type2_Pure{"Name"}))
12676 or (isScalar($Type2_Pure{"Name"}) and isFloat($Type1_Pure{"Name"}))))
12677 { # The scalar and floating-point values are passed in different registers
12678 %{$LocalProblems{"Return_Type_And_Register"}}=(
12679 "Old_Value"=>$Type1{"Name"},
12680 "New_Value"=>$Type2{"Name"},
12681 "Old_Size"=>$Type1{"Size"}*$BYTE_SIZE,
12682 "New_Size"=>$Type2{"Size"}*$BYTE_SIZE,
12683 "InitialType_Type"=>$Type1_Pure{"Type"});
12684 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012685 elsif($Level eq "Binary"
12686 and $Prefix eq "Return" and $Type2_Pure{"Type"}=~/Intrinsic|Enum/
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012687 and $Type1_Pure{"Type"}=~/Struct|Class|Union/)
12688 { # returns in a register instead of a hidden first parameter
12689 %{$LocalProblems{"Return_Type_From_Stack_To_Register"}}=(
12690 "Old_Value"=>$Type1{"Name"},
12691 "New_Value"=>$Type2{"Name"},
12692 "Old_Size"=>$Type1{"Size"}*$BYTE_SIZE,
12693 "New_Size"=>$Type2{"Size"}*$BYTE_SIZE,
12694 "InitialType_Type"=>$Type1_Pure{"Type"});
12695 }
12696 else
12697 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012698 if($Level eq "Binary"
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040012699 and $Type1{"Size"} and $Type2{"Size"}
12700 and $Type1{"Size"} ne $Type2{"Size"})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012701 {
12702 %{$LocalProblems{$Prefix."_Type_And_Size"}}=(
12703 "Old_Value"=>$Type1{"Name"},
12704 "New_Value"=>$Type2{"Name"},
12705 "Old_Size"=>$Type1{"Size"}*$BYTE_SIZE,
12706 "New_Size"=>$Type2{"Size"}*$BYTE_SIZE,
12707 "InitialType_Type"=>$Type1_Pure{"Type"});
12708 }
12709 else
12710 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012711 if(checkFormatChange($Type1_Id, $Type2_Id, $Level))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012712 { # format change
12713 %{$LocalProblems{$Prefix."_Type_Format"}}=(
12714 "Old_Value"=>$Type1{"Name"},
12715 "New_Value"=>$Type2{"Name"},
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012716 "InitialType_Type"=>$Type1_Pure{"Type"});
12717 }
12718 elsif(tNameLock($Type1_Id, $Type2_Id))
12719 { # FIXME: correct this condition
12720 %{$LocalProblems{$Prefix."_Type"}}=(
12721 "Old_Value"=>$Type1{"Name"},
12722 "New_Value"=>$Type2{"Name"},
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012723 "InitialType_Type"=>$Type1_Pure{"Type"});
12724 }
12725 }
12726 }
12727 }
12728 }
12729 if($Type1_PLevel!=$Type2_PLevel)
12730 {
12731 if($Type1{"Name"} ne "void" and $Type1{"Name"} ne "..."
12732 and $Type2{"Name"} ne "void" and $Type2{"Name"} ne "...")
12733 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012734 if($Level eq "Source")
12735 {
12736 %{$LocalProblems{$Prefix."_PointerLevel"}}=(
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012737 "Old_Value"=>$Type1_PLevel,
12738 "New_Value"=>$Type2_PLevel);
12739 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012740 else
12741 {
12742 if($Type2_PLevel>$Type1_PLevel) {
12743 %{$LocalProblems{$Prefix."_PointerLevel_Increased"}}=(
12744 "Old_Value"=>$Type1_PLevel,
12745 "New_Value"=>$Type2_PLevel);
12746 }
12747 else {
12748 %{$LocalProblems{$Prefix."_PointerLevel_Decreased"}}=(
12749 "Old_Value"=>$Type1_PLevel,
12750 "New_Value"=>$Type2_PLevel);
12751 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012752 }
12753 }
12754 }
12755 if($Type1_Pure{"Type"} eq "Array")
12756 { # base_type[N] -> base_type[N]
12757 # base_type: older_structure -> typedef to newer_structure
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012758 my %SubProblems = detectTypeChange($Type1_Base{"Tid"}, $Type2_Base{"Tid"}, $Prefix, $Level);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012759 foreach my $SubProblemType (keys(%SubProblems))
12760 {
12761 $SubProblemType=~s/_Type/_BaseType/g;
12762 next if(defined $LocalProblems{$SubProblemType});
12763 foreach my $Attr (keys(%{$SubProblems{$SubProblemType}})) {
12764 $LocalProblems{$SubProblemType}{$Attr} = $SubProblems{$SubProblemType}{$Attr};
12765 }
12766 }
12767 }
12768 return %LocalProblems;
12769}
12770
12771sub tNameLock($$)
12772{
12773 my ($Tid1, $Tid2) = @_;
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040012774 my $Changed = 0;
12775 if(differentDumps("G"))
12776 { # different GCC versions
12777 $Changed = 1;
12778 }
12779 elsif(differentDumps("V"))
12780 { # different versions of ABI dumps
12781 if(not checkDumpVersion(1, "2.13")
12782 or not checkDumpVersion(2, "2.13"))
12783 { # latest names update
12784 # 2.6: added restrict qualifier
12785 # 2.13: added missed typedefs to qualified types
12786 $Changed = 1;
12787 }
12788 }
12789 if($Changed)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012790 { # different formats
12791 if($UseOldDumps)
12792 { # old dumps
12793 return 0;
12794 }
12795 my $TN1 = get_TypeName($Tid1, 1);
12796 my $TN2 = get_TypeName($Tid2, 2);
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040012797
12798 my $TT1 = get_TypeAttr($Tid1, 1, "Type");
12799 my $TT2 = get_TypeAttr($Tid2, 2, "Type");
12800
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012801 my %Base1 = get_Type($Tid_TDid{1}{$Tid1}, $Tid1, 1);
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040012802 while(defined $Base1{"Type"} and $Base1{"Type"} eq "Typedef") {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012803 %Base1 = get_OneStep_BaseType($Base1{"TDid"}, $Base1{"Tid"}, 1);
12804 }
12805 my %Base2 = get_Type($Tid_TDid{2}{$Tid2}, $Tid2, 2);
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040012806 while(defined $Base2{"Type"} and $Base2{"Type"} eq "Typedef") {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012807 %Base2 = get_OneStep_BaseType($Base2{"TDid"}, $Base2{"Tid"}, 2);
12808 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +040012809 my $BName1 = uncover_typedefs($Base1{"Name"}, 1);
12810 my $BName2 = uncover_typedefs($Base2{"Name"}, 2);
12811 if($BName1 eq $BName2)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012812 { # equal base types
12813 return 0;
12814 }
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040012815
12816 if(not checkDumpVersion(1, "2.13")
12817 or not checkDumpVersion(2, "2.13"))
12818 { # broken array names in ABI dumps < 2.13
12819 if($TT1 eq "Array"
12820 and $TT2 eq "Array")
12821 {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012822 return 0;
12823 }
12824 }
12825
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040012826 if(not checkDumpVersion(1, "2.6")
12827 or not checkDumpVersion(2, "2.6"))
12828 { # added restrict attribute in 2.6
12829 if($TN1!~/(\A|\W)restrict(\W|\Z)/
12830 and $TN2=~/(\A|\W)restrict(\W|\Z)/)
12831 {
12832 return 0;
12833 }
12834 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012835 }
12836 return 1;
12837}
12838
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012839sub differentDumps($)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012840{
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012841 my $Check = $_[0];
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +040012842 if(defined $Cache{"differentDumps"}{$Check}) {
12843 return $Cache{"differentDumps"}{$Check};
12844 }
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040012845 if($UsedDump{1}{"V"} and $UsedDump{2}{"V"})
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012846 {
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040012847 if($Check eq "G")
12848 {
12849 if(getGccVersion(1) ne getGccVersion(2))
12850 { # different GCC versions
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +040012851 return ($Cache{"differentDumps"}{$Check}=1);
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040012852 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012853 }
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040012854 if($Check eq "V")
12855 {
12856 if(cmpVersions(formatVersion($UsedDump{1}{"V"}, 2),
12857 formatVersion($UsedDump{2}{"V"}, 2))!=0)
12858 { # different dump versions (skip micro version)
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +040012859 return ($Cache{"differentDumps"}{$Check}=1);
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040012860 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012861 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012862 }
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +040012863 return ($Cache{"differentDumps"}{$Check}=0);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012864}
12865
12866sub formatVersion($$)
12867{ # cut off version digits
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040012868 my ($V, $Digits) = @_;
12869 my @Elems = split(/\./, $V);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012870 return join(".", splice(@Elems, 0, $Digits));
12871}
12872
12873sub htmlSpecChars($)
12874{
12875 my $Str = $_[0];
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040012876 if($Str eq "") {
12877 return "";
12878 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012879 $Str=~s/\&([^#]|\Z)/&amp;$1/g;
12880 $Str=~s/</&lt;/g;
12881 $Str=~s/\-\>/&#45;&gt;/g; # &minus;
12882 $Str=~s/>/&gt;/g;
12883 $Str=~s/([^ ])( )([^ ])/$1\@ALONE_SP\@$3/g;
12884 $Str=~s/ /&#160;/g; # &nbsp;
12885 $Str=~s/\@ALONE_SP\@/ /g;
12886 $Str=~s/\n/<br\/>/g;
12887 $Str=~s/\"/&quot;/g;
12888 $Str=~s/\'/&#39;/g;
12889 return $Str;
12890}
12891
12892sub black_name($)
12893{
12894 my $Name = $_[0];
12895 return "<span class='iname_b'>".highLight_Signature($Name)."</span>";
12896}
12897
12898sub highLight_Signature($)
12899{
12900 my $Signature = $_[0];
12901 return highLight_Signature_PPos_Italic($Signature, "", 0, 0, 0);
12902}
12903
12904sub highLight_Signature_Italic_Color($)
12905{
12906 my $Signature = $_[0];
12907 return highLight_Signature_PPos_Italic($Signature, "", 1, 1, 1);
12908}
12909
12910sub separate_symbol($)
12911{
12912 my $Symbol = $_[0];
12913 my ($Name, $Spec, $Ver) = ($Symbol, "", "");
12914 if($Symbol=~/\A([^\@\$\?]+)([\@\$]+)([^\@\$]+)\Z/) {
12915 ($Name, $Spec, $Ver) = ($1, $2, $3);
12916 }
12917 return ($Name, $Spec, $Ver);
12918}
12919
12920sub cut_f_attrs($)
12921{
12922 if($_[0]=~s/(\))((| (const volatile|const|volatile))(| \[static\]))\Z/$1/) {
12923 return $2;
12924 }
12925 return "";
12926}
12927
12928sub highLight_Signature_PPos_Italic($$$$$)
12929{
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040012930 my ($FullSignature, $Param_Pos, $ItalicParams, $ColorParams, $ShowReturn) = @_;
12931 $Param_Pos = "" if(not defined $Param_Pos);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012932 if($CheckObjectsOnly) {
12933 $ItalicParams=$ColorParams=0;
12934 }
12935 my ($Signature, $VersionSpec, $SymbolVersion) = separate_symbol($FullSignature);
12936 my $Return = "";
12937 if($ShowRetVal and $Signature=~s/([^:]):([^:].+?)\Z/$1/g) {
12938 $Return = $2;
12939 }
Andrey Ponomarenko16934472012-03-29 15:37:04 +040012940 my $SCenter = find_center($Signature, "(");
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012941 if(not $SCenter)
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012942 { # global data
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012943 $Signature = htmlSpecChars($Signature);
12944 $Signature=~s!(\[data\])!<span style='color:Black;font-weight:normal;'>$1</span>!g;
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012945 $Signature .= (($SymbolVersion)?"<span class='sym_ver'>&#160;$VersionSpec&#160;$SymbolVersion</span>":"");
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012946 if($Return and $ShowReturn) {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012947 $Signature .= "<span class='sym_p nowrap'> &#160;<b>:</b>&#160;&#160;".htmlSpecChars($Return)."</span>";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012948 }
12949 return $Signature;
12950 }
12951 my ($Begin, $End) = (substr($Signature, 0, $SCenter), "");
12952 $Begin.=" " if($Begin!~/ \Z/);
12953 $End = cut_f_attrs($Signature);
12954 my @Parts = ();
12955 my @SParts = get_s_params($Signature, 1);
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040012956 foreach my $Pos (0 .. $#SParts)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012957 {
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040012958 my $Part = $SParts[$Pos];
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012959 $Part=~s/\A\s+|\s+\Z//g;
12960 my ($Part_Styled, $ParamName) = (htmlSpecChars($Part), "");
12961 if($Part=~/\([\*]+(\w+)\)/i) {
12962 $ParamName = $1;#func-ptr
12963 }
12964 elsif($Part=~/(\w+)[\,\)]*\Z/i) {
12965 $ParamName = $1;
12966 }
12967 if(not $ParamName) {
12968 push(@Parts, $Part_Styled);
12969 next;
12970 }
12971 if($ItalicParams and not $TName_Tid{1}{$Part}
12972 and not $TName_Tid{2}{$Part})
12973 {
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040012974 my $Style = "param";
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040012975 if($Param_Pos ne ""
12976 and $Pos==$Param_Pos) {
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040012977 $Style = "focus_p";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012978 }
12979 elsif($ColorParams) {
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040012980 $Style = "color_p";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012981 }
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040012982 $Part_Styled =~ s!(\W)$ParamName([\,\)]|\Z)!$1<span class=\'$Style\'>$ParamName</span>$2!ig;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012983 }
12984 $Part_Styled=~s/,(\w)/, $1/g;
12985 push(@Parts, $Part_Styled);
12986 }
12987 if(@Parts)
12988 {
12989 foreach my $Num (0 .. $#Parts)
12990 {
12991 if($Num==$#Parts)
12992 { # add ")" to the last parameter
12993 $Parts[$Num] = "<span class='nowrap'>".$Parts[$Num]." )</span>";
12994 }
12995 elsif(length($Parts[$Num])<=45) {
12996 $Parts[$Num] = "<span class='nowrap'>".$Parts[$Num]."</span>";
12997 }
12998 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012999 $Signature = htmlSpecChars($Begin)."<span class='sym_p'>(&#160;".join(" ", @Parts)."</span>".$End;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013000 }
13001 else {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040013002 $Signature = htmlSpecChars($Begin)."<span class='sym_p'>(&#160;)</span>".$End;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013003 }
13004 if($Return and $ShowReturn) {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040013005 $Signature .= "<span class='sym_p nowrap'> &#160;<b>:</b>&#160;&#160;".htmlSpecChars($Return)."</span>";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013006 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040013007 $Signature=~s!\[\]![&#160;]!g;
13008 $Signature=~s!operator=!operator&#160;=!g;
13009 $Signature=~s!(\[in-charge\]|\[not-in-charge\]|\[in-charge-deleting\]|\[static\])!<span class='sym_kind'>$1</span>!g;
13010 return $Signature.(($SymbolVersion)?"<span class='sym_ver'>&#160;$VersionSpec&#160;$SymbolVersion</span>":"");
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013011}
13012
13013sub get_s_params($$)
13014{
13015 my ($Signature, $Comma) = @_;
13016 my @Parts = ();
Andrey Ponomarenko16934472012-03-29 15:37:04 +040013017 my $ShortName = substr($Signature, 0, find_center($Signature, "("));
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013018 $Signature=~s/\A\Q$ShortName\E\(//g;
13019 cut_f_attrs($Signature);
13020 $Signature=~s/\)\Z//;
13021 return separate_params($Signature, $Comma);
13022}
13023
13024sub separate_params($$)
13025{
13026 my ($Params, $Comma) = @_;
13027 my @Parts = ();
Andrey Ponomarenko16934472012-03-29 15:37:04 +040013028 my %B = ( "("=>0, "<"=>0, ")"=>0, ">"=>0 );
13029 my $Part = 0;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013030 foreach my $Pos (0 .. length($Params) - 1)
13031 {
Andrey Ponomarenko16934472012-03-29 15:37:04 +040013032 my $S = substr($Params, $Pos, 1);
13033 if(defined $B{$S}) {
13034 $B{$S}+=1;
13035 }
13036 if($S eq "," and
13037 $B{"("}==$B{")"} and $B{"<"}==$B{">"})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013038 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040013039 if($Comma)
13040 { # include comma
Andrey Ponomarenko16934472012-03-29 15:37:04 +040013041 $Parts[$Part] .= $S;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013042 }
Andrey Ponomarenko16934472012-03-29 15:37:04 +040013043 $Part += 1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013044 }
13045 else {
Andrey Ponomarenko16934472012-03-29 15:37:04 +040013046 $Parts[$Part] .= $S;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013047 }
13048 }
13049 return @Parts;
13050}
13051
Andrey Ponomarenko16934472012-03-29 15:37:04 +040013052sub find_center($$)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013053{
13054 my ($Sign, $Target) = @_;
Andrey Ponomarenko16934472012-03-29 15:37:04 +040013055 my %B = ( "("=>0, "<"=>0, ")"=>0, ">"=>0 );
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013056 my $Center = 0;
Andrey Ponomarenko16934472012-03-29 15:37:04 +040013057 if($Sign=~s/(operator([^\w\s\(\)]+|\(\)))//g)
13058 { # operators
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013059 $Center+=length($1);
13060 }
13061 foreach my $Pos (0 .. length($Sign)-1)
13062 {
13063 my $S = substr($Sign, $Pos, 1);
13064 if($S eq $Target)
13065 {
13066 if($B{"("}==$B{")"}
13067 and $B{"<"}==$B{">"}) {
13068 return $Center;
13069 }
13070 }
13071 if(defined $B{$S}) {
13072 $B{$S}+=1;
13073 }
13074 $Center+=1;
13075 }
13076 return 0;
13077}
13078
13079sub appendFile($$)
13080{
13081 my ($Path, $Content) = @_;
13082 return if(not $Path);
13083 if(my $Dir = get_dirname($Path)) {
13084 mkpath($Dir);
13085 }
Andrey Ponomarenko16934472012-03-29 15:37:04 +040013086 open(FILE, ">>", $Path) || die ("can't open file \'$Path\': $!\n");
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013087 print FILE $Content;
13088 close(FILE);
13089}
13090
13091sub writeFile($$)
13092{
13093 my ($Path, $Content) = @_;
13094 return if(not $Path);
13095 if(my $Dir = get_dirname($Path)) {
13096 mkpath($Dir);
13097 }
Andrey Ponomarenko16934472012-03-29 15:37:04 +040013098 open(FILE, ">", $Path) || die ("can't open file \'$Path\': $!\n");
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013099 print FILE $Content;
13100 close(FILE);
13101}
13102
13103sub readFile($)
13104{
13105 my $Path = $_[0];
13106 return "" if(not $Path or not -f $Path);
Andrey Ponomarenko16934472012-03-29 15:37:04 +040013107 open(FILE, $Path);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013108 local $/ = undef;
13109 my $Content = <FILE>;
13110 close(FILE);
Andrey Ponomarenko85043792012-05-14 16:48:07 +040013111 if($Path!~/\.(tu|class|abi)\Z/) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013112 $Content=~s/\r/\n/g;
13113 }
13114 return $Content;
13115}
13116
13117sub get_filename($)
13118{ # much faster than basename() from File::Basename module
Andrey Ponomarenko85043792012-05-14 16:48:07 +040013119 if(defined $Cache{"get_filename"}{$_[0]}) {
13120 return $Cache{"get_filename"}{$_[0]};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013121 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +040013122 if($_[0] and $_[0]=~/([^\/\\]+)[\/\\]*\Z/) {
13123 return ($Cache{"get_filename"}{$_[0]}=$1);
13124 }
13125 return ($Cache{"get_filename"}{$_[0]}="");
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013126}
13127
13128sub get_dirname($)
13129{ # much faster than dirname() from File::Basename module
Andrey Ponomarenko85043792012-05-14 16:48:07 +040013130 if(defined $Cache{"get_dirname"}{$_[0]}) {
13131 return $Cache{"get_dirname"}{$_[0]};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013132 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +040013133 if($_[0] and $_[0]=~/\A(.*?)[\/\\]+[^\/\\]*[\/\\]*\Z/) {
13134 return ($Cache{"get_dirname"}{$_[0]}=$1);
13135 }
13136 return ($Cache{"get_dirname"}{$_[0]}="");
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013137}
13138
13139sub separate_path($) {
13140 return (get_dirname($_[0]), get_filename($_[0]));
13141}
13142
13143sub esc($)
13144{
13145 my $Str = $_[0];
13146 $Str=~s/([()\[\]{}$ &'"`;,<>\+])/\\$1/g;
13147 return $Str;
13148}
13149
13150sub readLineNum($$)
13151{
13152 my ($Path, $Num) = @_;
13153 return "" if(not $Path or not -f $Path);
Andrey Ponomarenko16934472012-03-29 15:37:04 +040013154 open(FILE, $Path);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013155 foreach (1 ... $Num) {
13156 <FILE>;
13157 }
13158 my $Line = <FILE>;
13159 close(FILE);
13160 return $Line;
13161}
13162
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040013163sub readAttributes($$)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013164{
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040013165 my ($Path, $Num) = @_;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013166 return () if(not $Path or not -f $Path);
13167 my %Attributes = ();
Andrey Ponomarenko85043792012-05-14 16:48:07 +040013168 if(readLineNum($Path, $Num)=~/<!--\s+(.+)\s+-->/)
13169 {
13170 foreach my $AttrVal (split(/;/, $1))
13171 {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013172 if($AttrVal=~/(.+):(.+)/)
13173 {
13174 my ($Name, $Value) = ($1, $2);
13175 $Attributes{$Name} = $Value;
13176 }
13177 }
13178 }
13179 return \%Attributes;
13180}
13181
13182sub is_abs($) {
13183 return ($_[0]=~/\A(\/|\w+:[\/\\])/);
13184}
13185
13186sub get_abs_path($)
13187{ # abs_path() should NOT be called for absolute inputs
13188 # because it can change them
13189 my $Path = $_[0];
13190 if(not is_abs($Path)) {
13191 $Path = abs_path($Path);
13192 }
13193 return $Path;
13194}
13195
13196sub get_OSgroup()
13197{
13198 $_ = $Config{"osname"};
13199 if(/macos|darwin|rhapsody/i) {
13200 return "macos";
13201 }
13202 elsif(/freebsd|openbsd|netbsd/i) {
13203 return "bsd";
13204 }
13205 elsif(/haiku|beos/i) {
13206 return "beos";
13207 }
13208 elsif(/symbian|epoc/i) {
13209 return "symbian";
13210 }
13211 elsif(/win/i) {
13212 return "windows";
13213 }
13214 else {
13215 return $_;
13216 }
13217}
13218
13219sub getGccVersion($)
13220{
13221 my $LibVersion = $_[0];
13222 if($GCC_VERSION{$LibVersion})
13223 { # dump version
13224 return $GCC_VERSION{$LibVersion};
13225 }
13226 elsif($UsedDump{$LibVersion}{"V"})
13227 { # old-version dumps
13228 return "unknown";
13229 }
13230 my $GccVersion = get_dumpversion($GCC_PATH); # host version
13231 if(not $GccVersion) {
13232 return "unknown";
13233 }
13234 return $GccVersion;
13235}
13236
13237sub showArch($)
13238{
13239 my $Arch = $_[0];
13240 if($Arch eq "arm"
13241 or $Arch eq "mips") {
13242 return uc($Arch);
13243 }
13244 return $Arch;
13245}
13246
13247sub getArch($)
13248{
13249 my $LibVersion = $_[0];
13250 if($CPU_ARCH{$LibVersion})
13251 { # dump version
13252 return $CPU_ARCH{$LibVersion};
13253 }
13254 elsif($UsedDump{$LibVersion}{"V"})
13255 { # old-version dumps
13256 return "unknown";
13257 }
13258 if(defined $Cache{"getArch"}{$LibVersion}) {
13259 return $Cache{"getArch"}{$LibVersion};
13260 }
13261 my $Arch = get_dumpmachine($GCC_PATH); # host version
13262 if(not $Arch) {
13263 return "unknown";
13264 }
13265 if($Arch=~/\A([\w]{3,})(-|\Z)/) {
13266 $Arch = $1;
13267 }
13268 $Arch = "x86" if($Arch=~/\Ai[3-7]86\Z/);
13269 if($OSgroup eq "windows") {
13270 $Arch = "x86" if($Arch=~/win32|mingw32/i);
13271 $Arch = "x86_64" if($Arch=~/win64|mingw64/i);
13272 }
13273 $Cache{"getArch"}{$LibVersion} = $Arch;
13274 return $Arch;
13275}
13276
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040013277sub get_Report_Header($)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013278{
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040013279 my $Level = $_[0];
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013280 my $ArchInfo = " on <span style='color:Blue;'>".showArch(getArch(1))."</span>";
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040013281 if(getArch(1) ne getArch(2)
13282 or getArch(1) eq "unknown"
13283 or $Level eq "Source")
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013284 { # don't show architecture in the header
13285 $ArchInfo="";
13286 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040013287 my $Report_Header = "<h1><span class='nowrap'>";
13288 if($Level eq "Source") {
13289 $Report_Header .= "Source compatibility";
13290 }
13291 elsif($Level eq "Binary") {
13292 $Report_Header .= "Binary compatibility";
13293 }
13294 else {
13295 $Report_Header .= "API compatibility";
13296 }
13297 $Report_Header .= " report for the <span style='color:Blue;'>$TargetLibraryFName</span> $TargetComponent</span>";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013298 $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>";
13299 if($AppPath) {
13300 $Report_Header .= " <span class='nowrap'>&#160;(relating to the portability of application <span style='color:Blue;'>".get_filename($AppPath)."</span>)</span>";
13301 }
13302 $Report_Header .= "</h1>\n";
13303 return $Report_Header;
13304}
13305
13306sub get_SourceInfo()
13307{
13308 my $CheckedHeaders = "<a name='Headers'></a><h2>Header Files (".keys(%{$Registered_Headers{1}}).")</h2><hr/>\n";
13309 $CheckedHeaders .= "<div class='h_list'>\n";
13310 foreach my $Header_Path (sort {lc($Registered_Headers{1}{$a}{"Identity"}) cmp lc($Registered_Headers{1}{$b}{"Identity"})} keys(%{$Registered_Headers{1}}))
13311 {
13312 my $Identity = $Registered_Headers{1}{$Header_Path}{"Identity"};
13313 my $Header_Name = get_filename($Identity);
13314 my $Dest_Comment = ($Identity=~/[\/\\]/)?" ($Identity)":"";
13315 $CheckedHeaders .= "$Header_Name$Dest_Comment<br/>\n";
13316 }
13317 $CheckedHeaders .= "</div>\n";
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040013318 $CheckedHeaders .= "<br/>$TOP_REF<br/>\n";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013319 my $CheckedLibs = "<a name='Libs'></a><h2>".ucfirst($SLIB_TYPE)." Libraries (".keys(%{$Library_Symbol{1}}).")</h2><hr/>\n";
13320 $CheckedLibs .= "<div class='lib_list'>\n";
13321 foreach my $Library (sort {lc($a) cmp lc($b)} keys(%{$Library_Symbol{1}}))
13322 {
13323 $Library.=" (.$LIB_EXT)" if($Library!~/\.\w+\Z/);
13324 $CheckedLibs .= "$Library<br/>\n";
13325 }
13326 $CheckedLibs .= "</div>\n";
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040013327 $CheckedLibs .= "<br/>$TOP_REF<br/>\n";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013328 if($CheckObjectsOnly) {
13329 $CheckedHeaders = "";
13330 }
13331 if($CheckHeadersOnly) {
13332 $CheckedLibs = "";
13333 }
13334 return $CheckedHeaders.$CheckedLibs;
13335}
13336
13337sub get_TypeProblems_Count($$$)
13338{
13339 my ($TypeChanges, $TargetPriority, $Level) = @_;
13340 my $Type_Problems_Count = 0;
13341 foreach my $Type_Name (sort keys(%{$TypeChanges}))
13342 {
13343 my %Kinds_Target = ();
13344 foreach my $Kind (keys(%{$TypeChanges->{$Type_Name}}))
13345 {
13346 foreach my $Location (keys(%{$TypeChanges->{$Type_Name}{$Kind}}))
13347 {
13348 my $Target = $TypeChanges->{$Type_Name}{$Kind}{$Location}{"Target"};
13349 my $Priority = getProblemSeverity($Level, $Kind);
13350 next if($Priority ne $TargetPriority);
13351 if($Kinds_Target{$Kind}{$Target}) {
13352 next;
13353 }
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040013354 if(cmpSeverities($Type_MaxSeverity{$Level}{$Type_Name}{$Kind}{$Target}, $Priority))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013355 { # select a problem with the highest priority
13356 next;
13357 }
13358 $Kinds_Target{$Kind}{$Target} = 1;
13359 $Type_Problems_Count += 1;
13360 }
13361 }
13362 }
13363 return $Type_Problems_Count;
13364}
13365
13366sub get_Summary($)
13367{
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040013368 my $Level = $_[0];
13369 my ($Added, $Removed, $I_Problems_High, $I_Problems_Medium, $I_Problems_Low, $T_Problems_High,
13370 $C_Problems_Low, $T_Problems_Medium, $T_Problems_Low, $I_Other, $T_Other) = (0,0,0,0,0,0,0,0,0,0,0);
13371 %{$RESULT{$Level}} = (
13372 "Problems"=>0,
13373 "Warnings"=>0,
13374 "Affected"=>0 );
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013375 # check rules
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040013376 foreach my $Interface (sort keys(%{$CompatProblems{$Level}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013377 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040013378 foreach my $Kind (keys(%{$CompatProblems{$Level}{$Interface}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013379 {
13380 if(not defined $CompatRules{$Level}{$Kind})
13381 { # unknown rule
13382 if(not $UnknownRules{$Level}{$Kind})
13383 { # only one warning
13384 printMsg("WARNING", "unknown rule \"$Kind\" (\"$Level\")");
13385 $UnknownRules{$Level}{$Kind}=1;
13386 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040013387 delete($CompatProblems{$Level}{$Interface}{$Kind});
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013388 }
13389 }
13390 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040013391 foreach my $Interface (sort keys(%{$CompatProblems{$Level}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013392 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040013393 foreach my $Kind (sort keys(%{$CompatProblems{$Level}{$Interface}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013394 {
13395 if($CompatRules{$Level}{$Kind}{"Kind"} eq "Symbols")
13396 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040013397 foreach my $Location (sort keys(%{$CompatProblems{$Level}{$Interface}{$Kind}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013398 {
13399 my $Priority = getProblemSeverity($Level, $Kind);
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040013400 if($Kind eq "Added_Symbol") {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013401 $Added += 1;
13402 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040013403 elsif($Kind eq "Removed_Symbol")
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013404 {
13405 $Removed += 1;
13406 $TotalAffected{$Level}{$Interface} = $Priority;
13407 }
13408 else
13409 {
13410 if($Priority eq "Safe") {
13411 $I_Other += 1;
13412 }
13413 elsif($Priority eq "High") {
13414 $I_Problems_High += 1;
13415 }
13416 elsif($Priority eq "Medium") {
13417 $I_Problems_Medium += 1;
13418 }
13419 elsif($Priority eq "Low") {
13420 $I_Problems_Low += 1;
13421 }
13422 if(($Priority ne "Low" or $StrictCompat)
13423 and $Priority ne "Safe") {
13424 $TotalAffected{$Level}{$Interface} = $Priority;
13425 }
13426 }
13427 }
13428 }
13429 }
13430 }
13431 my %TypeChanges = ();
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040013432 foreach my $Interface (sort keys(%{$CompatProblems{$Level}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013433 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040013434 foreach my $Kind (keys(%{$CompatProblems{$Level}{$Interface}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013435 {
13436 if($CompatRules{$Level}{$Kind}{"Kind"} eq "Types")
13437 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040013438 foreach my $Location (sort {cmp_locations($b, $a)} sort keys(%{$CompatProblems{$Level}{$Interface}{$Kind}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013439 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040013440 my $Type_Name = $CompatProblems{$Level}{$Interface}{$Kind}{$Location}{"Type_Name"};
13441 my $Target = $CompatProblems{$Level}{$Interface}{$Kind}{$Location}{"Target"};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013442 my $Priority = getProblemSeverity($Level, $Kind);
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040013443 if(cmpSeverities($Type_MaxSeverity{$Level}{$Type_Name}{$Kind}{$Target}, $Priority))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013444 { # select a problem with the highest priority
13445 next;
13446 }
13447 if(($Priority ne "Low" or $StrictCompat)
13448 and $Priority ne "Safe") {
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040013449 $TotalAffected{$Level}{$Interface} = maxSeverity($TotalAffected{$Level}{$Interface}, $Priority);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013450 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040013451 %{$TypeChanges{$Type_Name}{$Kind}{$Location}} = %{$CompatProblems{$Level}{$Interface}{$Kind}{$Location}};
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040013452 $Type_MaxSeverity{$Level}{$Type_Name}{$Kind}{$Target} = maxSeverity($Type_MaxSeverity{$Level}{$Type_Name}{$Kind}{$Target}, $Priority);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013453 }
13454 }
13455 }
13456 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040013457
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013458 $T_Problems_High = get_TypeProblems_Count(\%TypeChanges, "High", $Level);
13459 $T_Problems_Medium = get_TypeProblems_Count(\%TypeChanges, "Medium", $Level);
13460 $T_Problems_Low = get_TypeProblems_Count(\%TypeChanges, "Low", $Level);
13461 $T_Other = get_TypeProblems_Count(\%TypeChanges, "Safe", $Level);
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040013462
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013463 if($CheckObjectsOnly)
13464 { # only removed exported symbols
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040013465 $RESULT{$Level}{"Affected"} = $Removed*100/keys(%{$Symbol_Library{1}});
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013466 }
13467 else
13468 { # changed and removed public symbols
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040013469 my $SCount = keys(%{$CheckedSymbols{$Level}});
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013470 if($ExtendedCheck)
13471 { # don't count external_func_0 for constants
13472 $SCount-=1;
13473 }
13474 if($SCount)
13475 {
13476 my %Weight = (
13477 "High" => 100,
13478 "Medium" => 50,
13479 "Low" => 25
13480 );
13481 foreach (keys(%{$TotalAffected{$Level}})) {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040013482 $RESULT{$Level}{"Affected"}+=$Weight{$TotalAffected{$Level}{$_}};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013483 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040013484 $RESULT{$Level}{"Affected"} = $RESULT{$Level}{"Affected"}/$SCount;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013485 }
13486 else {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040013487 $RESULT{$Level}{"Affected"} = 0;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013488 }
13489 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040013490 $RESULT{$Level}{"Affected"} = show_number($RESULT{$Level}{"Affected"});
13491 if($RESULT{$Level}{"Affected"}>=100) {
13492 $RESULT{$Level}{"Affected"} = 100;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013493 }
13494
Andrey Ponomarenko85043792012-05-14 16:48:07 +040013495 $RESULT{$Level}{"Problems"} += $Removed;
13496 $RESULT{$Level}{"Problems"} += $T_Problems_High + $I_Problems_High;
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040013497 $RESULT{$Level}{"Problems"} += $T_Problems_Medium + $I_Problems_Medium;
Andrey Ponomarenko85043792012-05-14 16:48:07 +040013498 if($StrictCompat) {
13499 $RESULT{$Level}{"Problems"} += $T_Problems_Low + $I_Problems_Low;
13500 }
13501 else {
13502 $RESULT{$Level}{"Warnings"} += $T_Problems_Low + $I_Problems_Low;
13503 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013504
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040013505 if($C_Problems_Low = keys(%{$ProblemsWithConstants{$Level}}))
13506 {
Andrey Ponomarenko85043792012-05-14 16:48:07 +040013507 if(defined $CompatRules{$Level}{"Changed_Constant"})
13508 {
13509 if($StrictCompat) {
13510 $RESULT{$Level}{"Problems"} += $C_Problems_Low;
13511 }
13512 else {
13513 $RESULT{$Level}{"Warnings"} += $C_Problems_Low;
13514 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040013515 }
13516 else
13517 {
13518 printMsg("WARNING", "unknown rule \"Changed_Constant\" (\"$Level\")");
13519 $C_Problems_Low = 0;
13520 }
13521 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +040013522 if($CheckImpl and $Level eq "Binary")
13523 {
13524 if($StrictCompat) {
13525 $RESULT{$Level}{"Problems"} += keys(%ImplProblems);
13526 }
13527 else {
13528 $RESULT{$Level}{"Warnings"} += keys(%ImplProblems);
13529 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040013530 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +040013531 if($RESULT{$Level}{"Problems"}
13532 and $RESULT{$Level}{"Affected"}) {
13533 $RESULT{$Level}{"Verdict"} = "incompatible";
13534 }
13535 else {
13536 $RESULT{$Level}{"Verdict"} = "compatible";
13537 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040013538
13539 my $TotalTypes = keys(%{$CheckedTypes{$Level}});
13540 if(not $TotalTypes)
13541 { # list all the types
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013542 $TotalTypes = keys(%{$TName_Tid{1}});
13543 }
13544
13545 my ($Arch1, $Arch2) = (getArch(1), getArch(2));
13546 my ($GccV1, $GccV2) = (getGccVersion(1), getGccVersion(2));
13547
13548 my ($TestInfo, $TestResults, $Problem_Summary) = ();
13549
13550 if($ReportFormat eq "xml")
13551 { # XML
13552 # test info
13553 $TestInfo .= " <library>$TargetLibraryName</library>\n";
13554 $TestInfo .= " <version1>\n";
13555 $TestInfo .= " <number>".$Descriptor{1}{"Version"}."</number>\n";
13556 $TestInfo .= " <architecture>$Arch1</architecture>\n";
13557 $TestInfo .= " <gcc>$GccV1</gcc>\n";
13558 $TestInfo .= " </version1>\n";
13559
13560 $TestInfo .= " <version2>\n";
13561 $TestInfo .= " <number>".$Descriptor{2}{"Version"}."</number>\n";
13562 $TestInfo .= " <architecture>$Arch2</architecture>\n";
13563 $TestInfo .= " <gcc>$GccV2</gcc>\n";
13564 $TestInfo .= " </version2>\n";
13565 $TestInfo = "<test_info>\n".$TestInfo."</test_info>\n\n";
13566
13567 # test results
13568 $TestResults .= " <headers>\n";
13569 foreach my $Name (sort {lc($Registered_Headers{1}{$a}{"Identity"}) cmp lc($Registered_Headers{1}{$b}{"Identity"})} keys(%{$Registered_Headers{1}}))
13570 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040013571 my $Identity = $Registered_Headers{1}{$Name}{"Identity"};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013572 my $Comment = ($Identity=~/[\/\\]/)?" ($Identity)":"";
13573 $TestResults .= " <name>".get_filename($Name).$Comment."</name>\n";
13574 }
13575 $TestResults .= " </headers>\n";
13576
13577 $TestResults .= " <libs>\n";
13578 foreach my $Library (sort {lc($a) cmp lc($b)} keys(%{$Library_Symbol{1}}))
13579 {
13580 $Library.=" (.$LIB_EXT)" if($Library!~/\.\w+\Z/);
13581 $TestResults .= " <name>$Library</name>\n";
13582 }
13583 $TestResults .= " </libs>\n";
13584
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040013585 $TestResults .= " <symbols>".(keys(%{$CheckedSymbols{$Level}}) - keys(%GeneratedSymbols))."</symbols>\n";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013586 $TestResults .= " <types>".$TotalTypes."</types>\n";
13587
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040013588 $TestResults .= " <verdict>".$RESULT{$Level}{"Verdict"}."</verdict>\n";
13589 $TestResults .= " <affected>".$RESULT{$Level}{"Affected"}."</affected>\n";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013590 $TestResults = "<test_results>\n".$TestResults."</test_results>\n\n";
13591
13592 # problem summary
13593 $Problem_Summary .= " <added_symbols>".$Added."</added_symbols>\n";
13594 $Problem_Summary .= " <removed_symbols>".$Removed."</removed_symbols>\n";
13595
13596 $Problem_Summary .= " <problems_with_types>\n";
13597 $Problem_Summary .= " <high>$T_Problems_High</high>\n";
13598 $Problem_Summary .= " <medium>$T_Problems_Medium</medium>\n";
13599 $Problem_Summary .= " <low>$T_Problems_Low</low>\n";
13600 $Problem_Summary .= " <safe>$T_Other</safe>\n";
13601 $Problem_Summary .= " </problems_with_types>\n";
13602
13603 $Problem_Summary .= " <problems_with_symbols>\n";
13604 $Problem_Summary .= " <high>$I_Problems_High</high>\n";
13605 $Problem_Summary .= " <medium>$I_Problems_Medium</medium>\n";
13606 $Problem_Summary .= " <low>$I_Problems_Low</low>\n";
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040013607 $Problem_Summary .= " <safe>$I_Other</safe>\n";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013608 $Problem_Summary .= " </problems_with_symbols>\n";
13609
13610 $Problem_Summary .= " <problems_with_constants>\n";
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040013611 $Problem_Summary .= " <low>$C_Problems_Low</low>\n";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013612 $Problem_Summary .= " </problems_with_constants>\n";
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040013613 if($CheckImpl and $Level eq "Binary")
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013614 {
13615 $Problem_Summary .= " <impl>\n";
13616 $Problem_Summary .= " <low>".keys(%ImplProblems)."</low>\n";
13617 $Problem_Summary .= " </impl>\n";
13618 }
13619 $Problem_Summary = "<problem_summary>\n".$Problem_Summary."</problem_summary>\n\n";
13620
13621 return ($TestInfo.$TestResults.$Problem_Summary, "");
13622 }
13623 else
13624 { # HTML
13625 # test info
13626 $TestInfo = "<h2>Test Info</h2><hr/>\n";
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040013627 $TestInfo .= "<table class='summary'>\n";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013628 $TestInfo .= "<tr><th>".ucfirst($TargetComponent)." Name</th><td>$TargetLibraryFName</td></tr>\n";
13629
13630 my (@VInf1, @VInf2, $AddTestInfo) = ();
13631 if($Arch1 ne "unknown"
13632 and $Arch2 ne "unknown")
13633 { # CPU arch
13634 if($Arch1 eq $Arch2)
13635 { # go to the separate section
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040013636 $AddTestInfo .= "<tr><th>CPU Type</th><td>".showArch($Arch1)."</td></tr>\n";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013637 }
13638 else
13639 { # go to the version number
13640 push(@VInf1, showArch($Arch1));
13641 push(@VInf2, showArch($Arch2));
13642 }
13643 }
13644 if($GccV1 ne "unknown"
13645 and $GccV2 ne "unknown"
13646 and $OStarget ne "windows")
13647 { # GCC version
13648 if($GccV1 eq $GccV2)
13649 { # go to the separate section
13650 $AddTestInfo .= "<tr><th>GCC Version</th><td>$GccV1</td></tr>\n";
13651 }
13652 else
13653 { # go to the version number
13654 push(@VInf1, "gcc ".$GccV1);
13655 push(@VInf2, "gcc ".$GccV2);
13656 }
13657 }
13658 # show long version names with GCC version and CPU architecture name (if different)
13659 $TestInfo .= "<tr><th>Version #1</th><td>".$Descriptor{1}{"Version"}.(@VInf1?" (".join(", ", reverse(@VInf1)).")":"")."</td></tr>\n";
13660 $TestInfo .= "<tr><th>Version #2</th><td>".$Descriptor{2}{"Version"}.(@VInf2?" (".join(", ", reverse(@VInf2)).")":"")."</td></tr>\n";
13661 $TestInfo .= $AddTestInfo;
13662 #if($COMMON_LANGUAGE{1}) {
13663 # $TestInfo .= "<tr><th>Language</th><td>".$COMMON_LANGUAGE{1}."</td></tr>\n";
13664 #}
13665 if($ExtendedCheck) {
13666 $TestInfo .= "<tr><th>Mode</th><td>Extended</td></tr>\n";
13667 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040013668 if($JoinReport)
13669 {
13670 if($Level eq "Binary") {
Andrey Ponomarenko16934472012-03-29 15:37:04 +040013671 $TestInfo .= "<tr><th>Subject</th><td width='150px'>Binary Compatibility</td></tr>\n"; # Run-time
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040013672 }
13673 if($Level eq "Source") {
Andrey Ponomarenko16934472012-03-29 15:37:04 +040013674 $TestInfo .= "<tr><th>Subject</th><td width='150px'>Source Compatibility</td></tr>\n"; # Build-time
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040013675 }
13676 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013677 $TestInfo .= "</table>\n";
13678
13679 # test results
13680 $TestResults = "<h2>Test Results</h2><hr/>\n";
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040013681 $TestResults .= "<table class='summary'>";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013682
13683 my $Headers_Link = "0";
13684 $Headers_Link = "<a href='#Headers' style='color:Blue;'>".keys(%{$Registered_Headers{1}})."</a>" if(keys(%{$Registered_Headers{1}})>0);
13685 $TestResults .= "<tr><th>Total Header Files</th><td>".($CheckObjectsOnly?"0&#160;(not&#160;analyzed)":$Headers_Link)."</td></tr>\n";
13686
13687 if(not $ExtendedCheck)
13688 {
13689 my $Libs_Link = "0";
13690 $Libs_Link = "<a href='#Libs' style='color:Blue;'>".keys(%{$Library_Symbol{1}})."</a>" if(keys(%{$Library_Symbol{1}})>0);
13691 $TestResults .= "<tr><th>Total ".ucfirst($SLIB_TYPE)." Libraries</th><td>".($CheckHeadersOnly?"0&#160;(not&#160;analyzed)":$Libs_Link)."</td></tr>\n";
13692 }
13693
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040013694 $TestResults .= "<tr><th>Total Symbols / Types</th><td>".(keys(%{$CheckedSymbols{$Level}}) - keys(%GeneratedSymbols))." / ".$TotalTypes."</td></tr>\n";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013695
Andrey Ponomarenko85043792012-05-14 16:48:07 +040013696 my $META_DATA = "verdict:".$RESULT{$Level}{"Verdict"}.";";
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040013697 if($JoinReport) {
13698 $META_DATA = "kind:".lc($Level).";".$META_DATA;
13699 }
Andrey Ponomarenko16934472012-03-29 15:37:04 +040013700 $TestResults .= "<tr><th>Verdict</th>";
Andrey Ponomarenko85043792012-05-14 16:48:07 +040013701 if($RESULT{$Level}{"Verdict"} eq "incompatible") {
Andrey Ponomarenko16934472012-03-29 15:37:04 +040013702 $TestResults .= "<td><span style='color:Red;'><b>Incompatible<br/>(".$RESULT{$Level}{"Affected"}."%)</b></span></td>";
13703 }
13704 else {
13705 $TestResults .= "<td><span style='color:Green;'><b>Compatible</b></span></td>";
13706 }
13707 $TestResults .= "</tr>\n";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013708 $TestResults .= "</table>\n";
13709
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040013710 $META_DATA .= "affected:".$RESULT{$Level}{"Affected"}.";";# in percents
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013711 # problem summary
13712 $Problem_Summary = "<h2>Problem Summary</h2><hr/>\n";
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040013713 $Problem_Summary .= "<table class='summary'>";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013714 $Problem_Summary .= "<tr><th></th><th style='text-align:center;'>Severity</th><th style='text-align:center;'>Count</th></tr>";
13715
13716 my $Added_Link = "0";
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040013717 if($Added>0)
13718 {
13719 if($JoinReport) {
13720 $Added_Link = "<a href='#".$Level."_Added' style='color:Blue;'>$Added</a>";
13721 }
13722 else {
13723 $Added_Link = "<a href='#Added' style='color:Blue;'>$Added</a>";
13724 }
13725 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013726 $META_DATA .= "added:$Added;";
Andrey Ponomarenko16934472012-03-29 15:37:04 +040013727 $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 +040013728
13729 my $Removed_Link = "0";
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040013730 if($Removed>0)
13731 {
13732 if($JoinReport) {
13733 $Removed_Link = "<a href='#".$Level."_Removed' style='color:Blue;'>$Removed</a>"
13734 }
13735 else {
13736 $Removed_Link = "<a href='#Removed' style='color:Blue;'>$Removed</a>"
13737 }
13738 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013739 $META_DATA .= "removed:$Removed;";
Andrey Ponomarenko16934472012-03-29 15:37:04 +040013740 $Problem_Summary .= "<tr><th>Removed Symbols</th>";
13741 $Problem_Summary .= "<td>High</td><td".getStyle("I", "R", $Removed).">$Removed_Link</td></tr>\n";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013742
13743 my $TH_Link = "0";
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040013744 $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 +040013745 $TH_Link = "n/a" if($CheckObjectsOnly);
13746 $META_DATA .= "type_problems_high:$T_Problems_High;";
Andrey Ponomarenko16934472012-03-29 15:37:04 +040013747 $Problem_Summary .= "<tr><th rowspan='3'>Problems with<br/>Data Types</th>";
13748 $Problem_Summary .= "<td>High</td><td".getStyle("T", "H", $T_Problems_High).">$TH_Link</td></tr>\n";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013749
13750 my $TM_Link = "0";
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040013751 $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 +040013752 $TM_Link = "n/a" if($CheckObjectsOnly);
13753 $META_DATA .= "type_problems_medium:$T_Problems_Medium;";
Andrey Ponomarenko16934472012-03-29 15:37:04 +040013754 $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 +040013755
13756 my $TL_Link = "0";
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040013757 $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 +040013758 $TL_Link = "n/a" if($CheckObjectsOnly);
13759 $META_DATA .= "type_problems_low:$T_Problems_Low;";
Andrey Ponomarenko16934472012-03-29 15:37:04 +040013760 $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 +040013761
13762 my $IH_Link = "0";
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040013763 $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 +040013764 $IH_Link = "n/a" if($CheckObjectsOnly);
13765 $META_DATA .= "interface_problems_high:$I_Problems_High;";
Andrey Ponomarenko16934472012-03-29 15:37:04 +040013766 $Problem_Summary .= "<tr><th rowspan='3'>Problems with<br/>Symbols</th>";
13767 $Problem_Summary .= "<td>High</td><td".getStyle("I", "H", $I_Problems_High).">$IH_Link</td></tr>\n";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013768
13769 my $IM_Link = "0";
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040013770 $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 +040013771 $IM_Link = "n/a" if($CheckObjectsOnly);
13772 $META_DATA .= "interface_problems_medium:$I_Problems_Medium;";
Andrey Ponomarenko16934472012-03-29 15:37:04 +040013773 $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 +040013774
13775 my $IL_Link = "0";
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040013776 $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 +040013777 $IL_Link = "n/a" if($CheckObjectsOnly);
13778 $META_DATA .= "interface_problems_low:$I_Problems_Low;";
Andrey Ponomarenko16934472012-03-29 15:37:04 +040013779 $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 +040013780
13781 my $ChangedConstants_Link = "0";
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040013782 if(keys(%{$CheckedSymbols{$Level}}) and $C_Problems_Low)
13783 {
13784 if($JoinReport) {
13785 $ChangedConstants_Link = "<a href='#".$Level."_Changed_Constants' style='color:Blue;'>$C_Problems_Low</a>";
13786 }
13787 else {
13788 $ChangedConstants_Link = "<a href='#Changed_Constants' style='color:Blue;'>$C_Problems_Low</a>";
13789 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013790 }
13791 $ChangedConstants_Link = "n/a" if($CheckObjectsOnly);
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040013792 $META_DATA .= "changed_constants:$C_Problems_Low;";
Andrey Ponomarenko16934472012-03-29 15:37:04 +040013793 $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 +040013794
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040013795 if($CheckImpl and $Level eq "Binary")
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013796 {
13797 my $ChangedImpl_Link = "0";
13798 $ChangedImpl_Link = "<a href='#Changed_Implementation' style='color:Blue;'>".keys(%ImplProblems)."</a>" if(keys(%ImplProblems)>0);
13799 $ChangedImpl_Link = "n/a" if($CheckHeadersOnly);
13800 $META_DATA .= "changed_implementation:".keys(%ImplProblems).";";
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040013801 $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 +040013802 }
13803 # Safe Changes
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040013804 if($T_Other and not $CheckObjectsOnly)
13805 {
13806 my $TS_Link = "<a href='#".get_Anchor("Type", $Level, "Safe")."' style='color:Blue;'>$T_Other</a>";
Andrey Ponomarenko16934472012-03-29 15:37:04 +040013807 $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 +040013808 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040013809
13810 if($I_Other and not $CheckObjectsOnly)
13811 {
13812 my $IS_Link = "<a href='#".get_Anchor("Symbol", $Level, "Safe")."' style='color:Blue;'>$I_Other</a>";
Andrey Ponomarenko16934472012-03-29 15:37:04 +040013813 $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 +040013814 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013815
13816 $META_DATA .= "tool_version:$TOOL_VERSION";
13817 $Problem_Summary .= "</table>\n";
Andrey Ponomarenko16934472012-03-29 15:37:04 +040013818 # $TestInfo = getLegend().$TestInfo;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013819 return ($TestInfo.$TestResults.$Problem_Summary, $META_DATA);
13820 }
13821}
13822
Andrey Ponomarenko16934472012-03-29 15:37:04 +040013823sub getStyle($$$)
13824{
13825 my ($Subj, $Act, $Num) = @_;
13826 my %Style = (
13827 "A"=>"new",
13828 "R"=>"failed",
13829 "S"=>"passed",
13830 "L"=>"warning",
13831 "M"=>"failed",
13832 "H"=>"failed"
13833 );
13834 if($Num>0) {
13835 return " class='".$Style{$Act}."'";
13836 }
13837 return "";
13838}
13839
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013840sub show_number($)
13841{
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040013842 if($_[0])
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013843 {
Andrey Ponomarenko16934472012-03-29 15:37:04 +040013844 my $Num = cut_off_number($_[0], 2, 0);
13845 if($Num eq "0")
13846 {
13847 foreach my $P (3 .. 7)
13848 {
13849 $Num = cut_off_number($_[0], $P, 1);
13850 if($Num ne "0") {
13851 last;
13852 }
13853 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013854 }
13855 if($Num eq "0") {
13856 $Num = $_[0];
13857 }
13858 return $Num;
13859 }
13860 return $_[0];
13861}
13862
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040013863sub cut_off_number($$$)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013864{
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040013865 my ($num, $digs_to_cut, $z) = @_;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013866 if($num!~/\./)
13867 {
13868 $num .= ".";
13869 foreach (1 .. $digs_to_cut-1) {
13870 $num .= "0";
13871 }
13872 }
13873 elsif($num=~/\.(.+)\Z/ and length($1)<$digs_to_cut-1)
13874 {
13875 foreach (1 .. $digs_to_cut - 1 - length($1)) {
13876 $num .= "0";
13877 }
13878 }
13879 elsif($num=~/\d+\.(\d){$digs_to_cut,}/) {
13880 $num=sprintf("%.".($digs_to_cut-1)."f", $num);
13881 }
13882 $num=~s/\.[0]+\Z//g;
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040013883 if($z) {
13884 $num=~s/(\.[1-9]+)[0]+\Z/$1/g;
13885 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013886 return $num;
13887}
13888
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040013889sub get_Report_ChangedConstants($)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013890{
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040013891 my $Level = $_[0];
Andrey Ponomarenko16934472012-03-29 15:37:04 +040013892 my $CHANGED_CONSTANTS = "";
13893 my %ReportMap = ();
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040013894 foreach my $Constant (keys(%{$ProblemsWithConstants{$Level}})) {
Andrey Ponomarenko16934472012-03-29 15:37:04 +040013895 $ReportMap{$Constants{1}{$Constant}{"Header"}}{$Constant} = 1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013896 }
13897 my $Kind = "Changed_Constant";
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040013898 if(not defined $CompatRules{$Level}{$Kind}) {
13899 return "";
13900 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013901 if($ReportFormat eq "xml")
13902 { # XML
Andrey Ponomarenko16934472012-03-29 15:37:04 +040013903 foreach my $HeaderName (sort {lc($a) cmp lc($b)} keys(%ReportMap))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013904 {
13905 $CHANGED_CONSTANTS .= " <header name=\"$HeaderName\">\n";
Andrey Ponomarenko16934472012-03-29 15:37:04 +040013906 foreach my $Constant (sort {lc($a) cmp lc($b)} keys(%{$ReportMap{$HeaderName}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013907 {
13908 $CHANGED_CONSTANTS .= " <constant name=\"$Constant\">\n";
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040013909 my $Change = $CompatRules{$Level}{$Kind}{"Change"};
13910 my $Effect = $CompatRules{$Level}{$Kind}{"Effect"};
13911 my $Overcome = $CompatRules{$Level}{$Kind}{"Overcome"};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013912 $CHANGED_CONSTANTS .= " <problem id=\"$Kind\">\n";
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040013913 $CHANGED_CONSTANTS .= " <change".getXmlParams($Change, $ProblemsWithConstants{$Level}{$Constant}).">$Change</change>\n";
13914 $CHANGED_CONSTANTS .= " <effect".getXmlParams($Effect, $ProblemsWithConstants{$Level}{$Constant}).">$Effect</effect>\n";
13915 $CHANGED_CONSTANTS .= " <overcome".getXmlParams($Overcome, $ProblemsWithConstants{$Level}{$Constant}).">$Overcome</overcome>\n";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013916 $CHANGED_CONSTANTS .= " </problem>\n";
13917 $CHANGED_CONSTANTS .= " </constant>\n";
13918 }
13919 $CHANGED_CONSTANTS .= " </header>\n";
13920 }
13921 $CHANGED_CONSTANTS = "<problems_with_constants severity=\"Low\">\n".$CHANGED_CONSTANTS."</problems_with_constants>\n\n";
13922 }
13923 else
13924 { # HTML
13925 my $Number = 0;
Andrey Ponomarenko16934472012-03-29 15:37:04 +040013926 foreach my $HeaderName (sort {lc($a) cmp lc($b)} keys(%ReportMap))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013927 {
13928 $CHANGED_CONSTANTS .= "<span class='h_name'>$HeaderName</span><br/>\n";
Andrey Ponomarenko16934472012-03-29 15:37:04 +040013929 foreach my $Name (sort {lc($a) cmp lc($b)} keys(%{$ReportMap{$HeaderName}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013930 {
13931 $Number += 1;
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040013932 my $Change = applyMacroses($Level, $Kind, $CompatRules{$Level}{$Kind}{"Change"}, $ProblemsWithConstants{$Level}{$Name});
13933 my $Effect = $CompatRules{$Level}{$Kind}{"Effect"};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013934 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 +040013935 $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 +040013936 $Report = $ContentSpanStart."<span class='extendable'>[+]</span> ".$Name.$ContentSpanEnd."<br/>\n".$Report;
13937 $CHANGED_CONSTANTS .= insertIDs($Report);
13938 }
13939 $CHANGED_CONSTANTS .= "<br/>\n";
13940 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040013941 if($CHANGED_CONSTANTS)
13942 {
13943 my $Anchor = "<a name='Changed_Constants'></a>";
13944 if($JoinReport) {
13945 $Anchor = "<a name='".$Level."_Changed_Constants'></a>";
13946 }
13947 $CHANGED_CONSTANTS = $Anchor."<h2>Problems with Constants ($Number)</h2><hr/>\n".$CHANGED_CONSTANTS.$TOP_REF."<br/>\n";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013948 }
13949 }
13950 return $CHANGED_CONSTANTS;
13951}
13952
13953sub get_Report_Impl()
13954{
Andrey Ponomarenko16934472012-03-29 15:37:04 +040013955 my $CHANGED_IMPLEMENTATION = "";
13956 my %ReportMap = ();
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013957 foreach my $Interface (sort keys(%ImplProblems))
13958 {
13959 my $HeaderName = $CompleteSignature{1}{$Interface}{"Header"};
13960 my $DyLib = $Symbol_Library{1}{$Interface};
Andrey Ponomarenko16934472012-03-29 15:37:04 +040013961 $ReportMap{$HeaderName}{$DyLib}{$Interface} = 1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013962 }
13963 my $Changed_Number = 0;
Andrey Ponomarenko16934472012-03-29 15:37:04 +040013964 foreach my $HeaderName (sort {lc($a) cmp lc($b)} keys(%ReportMap))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013965 {
Andrey Ponomarenko16934472012-03-29 15:37:04 +040013966 foreach my $DyLib (sort {lc($a) cmp lc($b)} keys(%{$ReportMap{$HeaderName}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013967 {
13968 my $FDyLib=$DyLib.($DyLib!~/\.\w+\Z/?" (.$LIB_EXT)":"");
13969 if($HeaderName) {
13970 $CHANGED_IMPLEMENTATION .= "<span class='h_name'>$HeaderName</span>, <span class='lib_name'>$FDyLib</span><br/>\n";
13971 }
13972 else {
13973 $CHANGED_IMPLEMENTATION .= "<span class='lib_name'>$DyLib</span><br/>\n";
13974 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040013975 my %NameSpaceSymbols = ();
Andrey Ponomarenko16934472012-03-29 15:37:04 +040013976 foreach my $Interface (keys(%{$ReportMap{$HeaderName}{$DyLib}})) {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040013977 $NameSpaceSymbols{get_IntNameSpace($Interface, 2)}{$Interface} = 1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013978 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040013979 foreach my $NameSpace (sort keys(%NameSpaceSymbols))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013980 {
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040013981 $CHANGED_IMPLEMENTATION .= ($NameSpace)?"<span class='ns_title'>namespace</span> <span class='ns'>$NameSpace</span><br/>\n":"";
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040013982 my @SortedInterfaces = sort {lc(get_Signature($a, 1)) cmp lc(get_Signature($b, 1))} keys(%{$NameSpaceSymbols{$NameSpace}});
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013983 foreach my $Interface (@SortedInterfaces)
13984 {
13985 $Changed_Number += 1;
13986 my $Signature = get_Signature($Interface, 1);
13987 if($NameSpace) {
13988 $Signature=~s/(\W|\A)\Q$NameSpace\E\:\:(\w)/$1$2/g;
13989 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040013990 $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 +040013991 }
13992 }
13993 $CHANGED_IMPLEMENTATION .= "<br/>\n";
13994 }
13995 }
13996 if($CHANGED_IMPLEMENTATION) {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040013997 $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 +040013998 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +040013999
14000 # clean memory
14001 %ImplProblems = ();
14002
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014003 return $CHANGED_IMPLEMENTATION;
14004}
14005
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014006sub getTitle($$$)
14007{
14008 my ($Header, $Library, $NameSpace) = @_;
14009 my $Title = "";
14010 if($Library and $Library!~/\.\w+\Z/) {
14011 $Library .= " (.$LIB_EXT)";
14012 }
14013 if($Header and $Library)
14014 {
14015 $Title .= "<span class='h_name'>$Header</span>";
14016 $Title .= ", <span class='lib_name'>$Library</span><br/>\n";
14017 }
14018 elsif($Library) {
14019 $Title .= "<span class='lib_name'>$Library</span><br/>\n";
14020 }
14021 elsif($Header) {
14022 $Title .= "<span class='h_name'>$Header</span><br/>\n";
14023 }
14024 if($NameSpace) {
14025 $Title .= "<span class='ns_title'>namespace</span> <span class='ns'>$NameSpace</span><br/>\n";
14026 }
14027 return $Title;
14028}
14029
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014030sub get_Report_Added($)
14031{
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014032 my $Level = $_[0];
Andrey Ponomarenko16934472012-03-29 15:37:04 +040014033 my $ADDED_INTERFACES = "";
14034 my %ReportMap = ();
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014035 foreach my $Interface (sort keys(%{$CompatProblems{$Level}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014036 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014037 foreach my $Kind (sort keys(%{$CompatProblems{$Level}{$Interface}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014038 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014039 if($Kind eq "Added_Symbol")
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014040 {
14041 my $HeaderName = $CompleteSignature{2}{$Interface}{"Header"};
14042 my $DyLib = $Symbol_Library{2}{$Interface};
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014043 if($Level eq "Source" and $ReportFormat eq "html")
14044 { # do not show library name in HTML report
14045 $DyLib = "";
14046 }
14047 $ReportMap{$HeaderName}{$DyLib}{$Interface} = 1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014048 }
14049 }
14050 }
14051 if($ReportFormat eq "xml")
14052 { # XML
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014053 foreach my $HeaderName (sort {lc($a) cmp lc($b)} keys(%ReportMap))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014054 {
14055 $ADDED_INTERFACES .= " <header name=\"$HeaderName\">\n";
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014056 foreach my $DyLib (sort {lc($a) cmp lc($b)} keys(%{$ReportMap{$HeaderName}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014057 {
14058 $ADDED_INTERFACES .= " <library name=\"$DyLib\">\n";
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014059 foreach my $Interface (keys(%{$ReportMap{$HeaderName}{$DyLib}})) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014060 $ADDED_INTERFACES .= " <name>$Interface</name>\n";
14061 }
14062 $ADDED_INTERFACES .= " </library>\n";
14063 }
14064 $ADDED_INTERFACES .= " </header>\n";
14065 }
14066 $ADDED_INTERFACES = "<added_symbols>\n".$ADDED_INTERFACES."</added_symbols>\n\n";
14067 }
14068 else
14069 { # HTML
14070 my $Added_Number = 0;
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014071 foreach my $HeaderName (sort {lc($a) cmp lc($b)} keys(%ReportMap))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014072 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014073 foreach my $DyLib (sort {lc($a) cmp lc($b)} keys(%{$ReportMap{$HeaderName}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014074 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014075 my %NameSpaceSymbols = ();
14076 foreach my $Interface (keys(%{$ReportMap{$HeaderName}{$DyLib}})) {
14077 $NameSpaceSymbols{get_IntNameSpace($Interface, 2)}{$Interface} = 1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014078 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014079 foreach my $NameSpace (sort keys(%NameSpaceSymbols))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014080 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014081 $ADDED_INTERFACES .= getTitle($HeaderName, $DyLib, $NameSpace);
14082 my @SortedInterfaces = sort {lc(get_Signature($a, 2)) cmp lc(get_Signature($b, 2))} keys(%{$NameSpaceSymbols{$NameSpace}});
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014083 foreach my $Interface (@SortedInterfaces)
14084 {
14085 $Added_Number += 1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014086 my $Signature = get_Signature($Interface, 2);
14087 if($NameSpace) {
14088 $Signature=~s/(\W|\A)\Q$NameSpace\E\:\:(\w)/$1$2/g;
14089 }
14090 if($Interface=~/\A(_Z|\?)/) {
14091 if($Signature) {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014092 $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 +040014093 }
14094 else {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014095 $ADDED_INTERFACES .= "<span class=\"iname\">".$Interface."</span><br/>\n";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014096 }
14097 }
14098 else {
14099 if($Signature) {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014100 $ADDED_INTERFACES .= "<span class=\"iname\">".highLight_Signature_Italic_Color($Signature)."</span><br/>\n";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014101 }
14102 else {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014103 $ADDED_INTERFACES .= "<span class=\"iname\">".$Interface."</span><br/>\n";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014104 }
14105 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014106 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014107 $ADDED_INTERFACES .= "<br/>\n";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014108 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014109 }
14110 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014111 if($ADDED_INTERFACES)
14112 {
14113 my $Anchor = "<a name='Added'></a>";
14114 if($JoinReport) {
14115 $Anchor = "<a name='".$Level."_Added'></a>";
14116 }
14117 $ADDED_INTERFACES = $Anchor."<h2>Added Symbols ($Added_Number)</h2><hr/>\n".$ADDED_INTERFACES.$TOP_REF."<br/>\n";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014118 }
14119 }
14120 return $ADDED_INTERFACES;
14121}
14122
14123sub get_Report_Removed($)
14124{
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014125 my $Level = $_[0];
Andrey Ponomarenko16934472012-03-29 15:37:04 +040014126 my $REMOVED_INTERFACES = "";
14127 my %ReportMap = ();
Andrey Ponomarenko85043792012-05-14 16:48:07 +040014128 foreach my $Symbol (sort keys(%{$CompatProblems{$Level}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014129 {
Andrey Ponomarenko85043792012-05-14 16:48:07 +040014130 foreach my $Kind (sort keys(%{$CompatProblems{$Level}{$Symbol}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014131 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014132 if($Kind eq "Removed_Symbol")
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014133 {
Andrey Ponomarenko85043792012-05-14 16:48:07 +040014134 my $HeaderName = $CompleteSignature{1}{$Symbol}{"Header"};
14135 my $DyLib = $Symbol_Library{1}{$Symbol};
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014136 if($Level eq "Source" and $ReportFormat eq "html")
14137 { # do not show library name in HTML report
14138 $DyLib = "";
14139 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +040014140 $ReportMap{$HeaderName}{$DyLib}{$Symbol} = 1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014141 }
14142 }
14143 }
14144 if($ReportFormat eq "xml")
14145 { # XML
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014146 foreach my $HeaderName (sort {lc($a) cmp lc($b)} keys(%ReportMap))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014147 {
14148 $REMOVED_INTERFACES .= " <header name=\"$HeaderName\">\n";
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014149 foreach my $DyLib (sort {lc($a) cmp lc($b)} keys(%{$ReportMap{$HeaderName}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014150 {
14151 $REMOVED_INTERFACES .= " <library name=\"$DyLib\">\n";
Andrey Ponomarenko85043792012-05-14 16:48:07 +040014152 foreach my $Symbol (keys(%{$ReportMap{$HeaderName}{$DyLib}})) {
14153 $REMOVED_INTERFACES .= " <name>$Symbol</name>\n";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014154 }
14155 $REMOVED_INTERFACES .= " </library>\n";
14156 }
14157 $REMOVED_INTERFACES .= " </header>\n";
14158 }
14159 $REMOVED_INTERFACES = "<removed_symbols>\n".$REMOVED_INTERFACES."</removed_symbols>\n\n";
14160 }
14161 else
14162 { # HTML
14163 my $Removed_Number = 0;
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014164 foreach my $HeaderName (sort {lc($a) cmp lc($b)} keys(%ReportMap))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014165 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014166 foreach my $DyLib (sort {lc($a) cmp lc($b)} keys(%{$ReportMap{$HeaderName}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014167 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014168 my %NameSpaceSymbols = ();
14169 foreach my $Interface (keys(%{$ReportMap{$HeaderName}{$DyLib}})) {
14170 $NameSpaceSymbols{get_IntNameSpace($Interface, 1)}{$Interface} = 1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014171 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014172 foreach my $NameSpace (sort keys(%NameSpaceSymbols))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014173 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014174 $REMOVED_INTERFACES .= getTitle($HeaderName, $DyLib, $NameSpace);
14175 my @SortedInterfaces = sort {lc(get_Signature($a, 1)) cmp lc(get_Signature($b, 1))} keys(%{$NameSpaceSymbols{$NameSpace}});
Andrey Ponomarenko85043792012-05-14 16:48:07 +040014176 foreach my $Symbol (@SortedInterfaces)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014177 {
14178 $Removed_Number += 1;
14179 my $SubReport = "";
Andrey Ponomarenko85043792012-05-14 16:48:07 +040014180 my $Signature = get_Signature($Symbol, 1);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014181 if($NameSpace) {
14182 $Signature=~s/(\W|\A)\Q$NameSpace\E\:\:(\w)/$1$2/g;
14183 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +040014184 if($Symbol=~/\A(_Z|\?)/)
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014185 {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014186 if($Signature) {
Andrey Ponomarenko85043792012-05-14 16:48:07 +040014187 $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 +040014188 }
14189 else {
Andrey Ponomarenko85043792012-05-14 16:48:07 +040014190 $REMOVED_INTERFACES .= "<span class=\"iname\">".$Symbol."</span><br/>\n";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014191 }
14192 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014193 else
14194 {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014195 if($Signature) {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014196 $REMOVED_INTERFACES .= "<span class=\"iname\">".highLight_Signature_Italic_Color($Signature)."</span><br/>\n";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014197 }
14198 else {
Andrey Ponomarenko85043792012-05-14 16:48:07 +040014199 $REMOVED_INTERFACES .= "<span class=\"iname\">".$Symbol."</span><br/>\n";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014200 }
14201 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014202 }
14203 }
14204 $REMOVED_INTERFACES .= "<br/>\n";
14205 }
14206 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014207 if($REMOVED_INTERFACES)
14208 {
14209 my $Anchor = "<a name='Removed'></a><a name='Withdrawn'></a>";
14210 if($JoinReport) {
14211 $Anchor = "<a name='".$Level."_Removed'></a><a name='".$Level."_Withdrawn'></a>";
14212 }
14213 $REMOVED_INTERFACES = $Anchor."<h2>Removed Symbols ($Removed_Number)</h2><hr/>\n".$REMOVED_INTERFACES.$TOP_REF."<br/>\n";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014214 }
14215 }
14216 return $REMOVED_INTERFACES;
14217}
14218
14219sub getXmlParams($$)
14220{
14221 my ($Content, $Problem) = @_;
14222 return "" if(not $Content or not $Problem);
14223 my %XMLparams = ();
14224 foreach my $Attr (sort {$b cmp $a} keys(%{$Problem}))
14225 {
14226 my $Macro = "\@".lc($Attr);
14227 if($Content=~/\Q$Macro\E/) {
14228 $XMLparams{lc($Attr)} = $Problem->{$Attr};
14229 }
14230 }
14231 my @PString = ();
14232 foreach my $P (sort {$b cmp $a} keys(%XMLparams)) {
14233 push(@PString, $P."=\"".htmlSpecChars($XMLparams{$P})."\"");
14234 }
14235 if(@PString) {
14236 return " ".join(" ", @PString);
14237 }
14238 else {
14239 return "";
14240 }
14241}
14242
14243sub addMarkup($)
14244{
14245 my $Content = $_[0];
14246 # auto-markup
14247 $Content=~s/\n[ ]*//; # spaces
14248 $Content=~s!(\@\w+\s*\(\@\w+\))!<nowrap>$1</nowrap>!g; # @old_type (@old_size)
14249 $Content=~s!(... \(\w+\))!<nowrap><b>$1</b></nowrap>!g; # ... (va_list)
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040014250 $Content=~s!<nowrap>(.+?)</nowrap>!<span class='nowrap'>$1</span>!g;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014251 $Content=~s!([2-9]\))!<br/>$1!g; # 1), 2), ...
14252 if($Content=~/\ANOTE:/)
14253 { # notes
14254 $Content=~s!(NOTE):!<b>$1</b>:!g;
14255 }
14256 else {
14257 $Content=~s!(NOTE):!<br/><b>$1</b>:!g;
14258 }
14259 $Content=~s! (out)-! <b>$1</b>-!g; # out-parameters
14260 my @Keywords = (
14261 "void",
14262 "const",
14263 "static",
14264 "restrict",
14265 "volatile",
14266 "register",
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040014267 "virtual"
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014268 );
14269 my $MKeys = join("|", @Keywords);
14270 foreach (@Keywords) {
14271 $MKeys .= "|non-".$_;
14272 }
14273 $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 +040014274
14275 # Markdown
14276 $Content=~s!\*\*([\w\-]+)\*\*!<b>$1</b>!ig;
14277 $Content=~s!\*([\w\-]+)\*!<i>$1</i>!ig;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014278 return $Content;
14279}
14280
14281sub applyMacroses($$$$)
14282{
14283 my ($Level, $Kind, $Content, $Problem) = @_;
14284 return "" if(not $Content or not $Problem);
14285 $Problem->{"Word_Size"} = $WORD_SIZE{2};
14286 $Content = addMarkup($Content);
14287 # macros
14288 foreach my $Attr (sort {$b cmp $a} keys(%{$Problem}))
14289 {
14290 my $Macro = "\@".lc($Attr);
14291 my $Value = $Problem->{$Attr};
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040014292 if(not defined $Value
14293 or $Value eq "") {
14294 next;
14295 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014296 if($Value=~/\s\(/)
14297 { # functions
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014298 $Value=~s/\s*\[[\w\-]+\]//g; # remove quals
14299 $Value=~s/\s\w+(\)|,)/$1/g; # remove parameter names
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014300 $Value = black_name($Value);
14301 }
14302 elsif($Value=~/\s/) {
14303 $Value = "<span class='value'>".htmlSpecChars($Value)."</span>";
14304 }
14305 elsif($Value=~/\A\d+\Z/
14306 and ($Attr eq "Old_Size" or $Attr eq "New_Size"))
14307 { # bits to bytes
14308 if($Value % $BYTE_SIZE)
14309 { # bits
14310 if($Value==1) {
14311 $Value = "<b>".$Value."</b> bit";
14312 }
14313 else {
14314 $Value = "<b>".$Value."</b> bits";
14315 }
14316 }
14317 else
14318 { # bytes
14319 $Value /= $BYTE_SIZE;
14320 if($Value==1) {
14321 $Value = "<b>".$Value."</b> byte";
14322 }
14323 else {
14324 $Value = "<b>".$Value."</b> bytes";
14325 }
14326 }
14327 }
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040014328 else
14329 {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014330 $Value = "<b>".htmlSpecChars($Value)."</b>";
14331 }
14332 $Content=~s/\Q$Macro\E/$Value/g;
14333 }
14334
14335 if($Content=~/(\A|[^\@\w])\@\w/)
14336 {
14337 if(not $IncompleteRules{$Level}{$Kind})
14338 { # only one warning
14339 printMsg("WARNING", "incomplete rule \"$Kind\" (\"$Level\")");
14340 $IncompleteRules{$Level}{$Kind} = 1;
14341 }
14342 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014343 return $Content;
14344}
14345
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040014346sub get_Report_SymbolProblems($$)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014347{
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014348 my ($TargetSeverity, $Level) = @_;
Andrey Ponomarenko16934472012-03-29 15:37:04 +040014349 my $INTERFACE_PROBLEMS = "";
14350 my (%ReportMap, %SymbolChanges) = ();
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014351 foreach my $Symbol (sort keys(%{$CompatProblems{$Level}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014352 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014353 my ($SN, $SS, $SV) = separate_symbol($Symbol);
14354 if($SV and defined $CompatProblems{$Level}{$SN}) {
14355 next;
14356 }
14357 foreach my $Kind (sort keys(%{$CompatProblems{$Level}{$Symbol}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014358 {
14359 if($CompatRules{$Level}{$Kind}{"Kind"} eq "Symbols"
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014360 and $Kind ne "Added_Symbol" and $Kind ne "Removed_Symbol")
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014361 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014362 my $HeaderName = $CompleteSignature{1}{$Symbol}{"Header"};
14363 my $DyLib = $Symbol_Library{1}{$Symbol};
14364 if(not $DyLib and my $VSym = $SymVer{1}{$Symbol})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014365 { # Symbol with Version
14366 $DyLib = $Symbol_Library{1}{$VSym};
14367 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014368 if($Level eq "Source" and $ReportFormat eq "html")
14369 { # do not show library name in HTML report
14370 $DyLib = "";
14371 }
14372 %{$SymbolChanges{$Symbol}{$Kind}} = %{$CompatProblems{$Level}{$Symbol}{$Kind}};
14373 foreach my $Location (sort keys(%{$SymbolChanges{$Symbol}{$Kind}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014374 {
14375 my $Priority = getProblemSeverity($Level, $Kind);
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014376 if($Priority ne $TargetSeverity) {
14377 delete($SymbolChanges{$Symbol}{$Kind}{$Location});
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014378 }
14379 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014380 if(not keys(%{$SymbolChanges{$Symbol}{$Kind}}))
14381 {
14382 delete($SymbolChanges{$Symbol}{$Kind});
14383 next;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014384 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014385 $ReportMap{$HeaderName}{$DyLib}{$Symbol} = 1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014386 }
14387 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014388 if(not keys(%{$SymbolChanges{$Symbol}})) {
14389 delete($SymbolChanges{$Symbol});
14390 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014391 }
14392 if($ReportFormat eq "xml")
14393 { # XML
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014394 foreach my $HeaderName (sort {lc($a) cmp lc($b)} keys(%ReportMap))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014395 {
14396 $INTERFACE_PROBLEMS .= " <header name=\"$HeaderName\">\n";
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014397 foreach my $DyLib (sort {lc($a) cmp lc($b)} keys(%{$ReportMap{$HeaderName}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014398 {
14399 $INTERFACE_PROBLEMS .= " <library name=\"$DyLib\">\n";
14400 foreach my $Symbol (sort {lc($tr_name{$a}) cmp lc($tr_name{$b})} keys(%SymbolChanges))
14401 {
14402 $INTERFACE_PROBLEMS .= " <symbol name=\"$Symbol\">\n";
14403 foreach my $Kind (keys(%{$SymbolChanges{$Symbol}}))
14404 {
14405 foreach my $Location (sort keys(%{$SymbolChanges{$Symbol}{$Kind}}))
14406 {
14407 my %Problem = %{$SymbolChanges{$Symbol}{$Kind}{$Location}};
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040014408 $Problem{"Param_Pos"} = showPos($Problem{"Param_Pos"});
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014409 $INTERFACE_PROBLEMS .= " <problem id=\"$Kind\">\n";
14410 my $Change = $CompatRules{$Level}{$Kind}{"Change"};
14411 $INTERFACE_PROBLEMS .= " <change".getXmlParams($Change, \%Problem).">$Change</change>\n";
14412 my $Effect = $CompatRules{$Level}{$Kind}{"Effect"};
14413 $INTERFACE_PROBLEMS .= " <effect".getXmlParams($Effect, \%Problem).">$Effect</effect>\n";
14414 my $Overcome = $CompatRules{$Level}{$Kind}{"Overcome"};
14415 $INTERFACE_PROBLEMS .= " <overcome".getXmlParams($Overcome, \%Problem).">$Overcome</overcome>\n";
14416 $INTERFACE_PROBLEMS .= " </problem>\n";
14417 }
14418 }
14419 $INTERFACE_PROBLEMS .= " </symbol>\n";
14420 }
14421 $INTERFACE_PROBLEMS .= " </library>\n";
14422 }
14423 $INTERFACE_PROBLEMS .= " </header>\n";
14424 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014425 $INTERFACE_PROBLEMS = "<problems_with_symbols severity=\"$TargetSeverity\">\n".$INTERFACE_PROBLEMS."</problems_with_symbols>\n\n";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014426 }
14427 else
14428 { # HTML
14429 my $ProblemsNum = 0;
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014430 foreach my $HeaderName (sort {lc($a) cmp lc($b)} keys(%ReportMap))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014431 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014432 foreach my $DyLib (sort {lc($a) cmp lc($b)} keys(%{$ReportMap{$HeaderName}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014433 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014434 my (%NameSpaceSymbols, %NewSignature) = ();
14435 foreach my $Symbol (keys(%{$ReportMap{$HeaderName}{$DyLib}})) {
14436 $NameSpaceSymbols{get_IntNameSpace($Symbol, 1)}{$Symbol} = 1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014437 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014438 foreach my $NameSpace (sort keys(%NameSpaceSymbols))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014439 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014440 $INTERFACE_PROBLEMS .= getTitle($HeaderName, $DyLib, $NameSpace);
14441 my @SortedInterfaces = sort {lc($tr_name{$a}) cmp lc($tr_name{$b})} keys(%{$NameSpaceSymbols{$NameSpace}});
14442 foreach my $Symbol (@SortedInterfaces)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014443 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014444 my $Signature = get_Signature($Symbol, 1);
14445 my $SYMBOL_REPORT = "";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014446 my $ProblemNum = 1;
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014447 foreach my $Kind (keys(%{$SymbolChanges{$Symbol}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014448 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014449 foreach my $Location (sort keys(%{$SymbolChanges{$Symbol}{$Kind}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014450 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014451 my %Problem = %{$SymbolChanges{$Symbol}{$Kind}{$Location}};
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040014452 $Problem{"Param_Pos"} = showPos($Problem{"Param_Pos"});
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014453 if($Problem{"New_Signature"}) {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014454 $NewSignature{$Symbol} = $Problem{"New_Signature"};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014455 }
14456 if(my $Change = applyMacroses($Level, $Kind, $CompatRules{$Level}{$Kind}{"Change"}, \%Problem))
14457 {
14458 my $Effect = applyMacroses($Level, $Kind, $CompatRules{$Level}{$Kind}{"Effect"}, \%Problem);
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014459 $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 +040014460 $ProblemNum += 1;
14461 $ProblemsNum += 1;
14462 }
14463 }
14464 }
14465 $ProblemNum -= 1;
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014466 if($SYMBOL_REPORT)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014467 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014468 $INTERFACE_PROBLEMS .= $ContentSpanStart."<span class='extendable'>[+]</span> ";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014469 if($Signature) {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014470 $INTERFACE_PROBLEMS .= highLight_Signature_Italic_Color($Signature);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014471 }
14472 else {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014473 $INTERFACE_PROBLEMS .= $Symbol;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014474 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014475 $INTERFACE_PROBLEMS .= " ($ProblemNum)".$ContentSpanEnd."<br/>\n";
14476 $INTERFACE_PROBLEMS .= $ContentDivStart."\n";
14477 if($NewSignature{$Symbol})
14478 { # argument list changed to
14479 $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 +040014480 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014481 if($Symbol=~/\A(_Z|\?)/) {
14482 $INTERFACE_PROBLEMS .= "<span class='mangled'>&#160;&#160;&#160;&#160;[symbol: <b>$Symbol</b>]</span><br/>\n";
14483 }
14484 $INTERFACE_PROBLEMS .= "<table class='ptable'><tr><th width='2%'></th><th width='47%'>Change</th><th>Effect</th></tr>$SYMBOL_REPORT</table><br/>\n";
14485 $INTERFACE_PROBLEMS .= $ContentDivEnd;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014486 if($NameSpace) {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014487 $INTERFACE_PROBLEMS=~s/(\W|\A)\Q$NameSpace\E\:\:(\w)/$1$2/g;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014488 }
14489 }
14490 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014491 $INTERFACE_PROBLEMS .= "<br/>";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014492 }
14493 }
14494 }
14495 if($INTERFACE_PROBLEMS)
14496 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014497 $INTERFACE_PROBLEMS = insertIDs($INTERFACE_PROBLEMS);
14498 my $Title = "Problems with Symbols, $TargetSeverity Severity";
14499 if($TargetSeverity eq "Safe")
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014500 { # Safe Changes
14501 $Title = "Other Changes in Symbols";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014502 }
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040014503 $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 +040014504 }
14505 }
14506 return $INTERFACE_PROBLEMS;
14507}
14508
14509sub get_Report_TypeProblems($$)
14510{
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014511 my ($TargetSeverity, $Level) = @_;
Andrey Ponomarenko16934472012-03-29 15:37:04 +040014512 my $TYPE_PROBLEMS = "";
14513 my (%ReportMap, %TypeChanges, %TypeType) = ();
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014514 foreach my $Interface (sort keys(%{$CompatProblems{$Level}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014515 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014516 foreach my $Kind (keys(%{$CompatProblems{$Level}{$Interface}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014517 {
14518 if($CompatRules{$Level}{$Kind}{"Kind"} eq "Types")
14519 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014520 foreach my $Location (sort {cmp_locations($b, $a)} sort keys(%{$CompatProblems{$Level}{$Interface}{$Kind}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014521 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014522 my $TypeName = $CompatProblems{$Level}{$Interface}{$Kind}{$Location}{"Type_Name"};
14523 my $TypeType = $CompatProblems{$Level}{$Interface}{$Kind}{$Location}{"Type_Type"};
14524 my $Target = $CompatProblems{$Level}{$Interface}{$Kind}{$Location}{"Target"};
14525 $CompatProblems{$Level}{$Interface}{$Kind}{$Location}{"Type_Type"} = lc($TypeType);
14526 my $Severity = getProblemSeverity($Level, $Kind);
14527 if($Severity eq "Safe"
14528 and $TargetSeverity ne "Safe") {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014529 next;
14530 }
14531 if(not $TypeType{$TypeName}
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014532 or $TypeType{$TypeName} eq "struct")
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014533 { # register type of the type, select "class" if type has "class"- and "struct"-type changes
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014534 $TypeType{$TypeName} = $CompatProblems{$Level}{$Interface}{$Kind}{$Location}{"Type_Type"};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014535 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014536
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040014537 if(cmpSeverities($Type_MaxSeverity{$Level}{$TypeName}{$Kind}{$Target}, $Severity))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014538 { # select a problem with the highest priority
14539 next;
14540 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014541 %{$TypeChanges{$TypeName}{$Kind}{$Location}} = %{$CompatProblems{$Level}{$Interface}{$Kind}{$Location}};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014542 }
14543 }
14544 }
14545 }
14546 my %Kinds_Locations = ();
14547 foreach my $TypeName (keys(%TypeChanges))
14548 {
14549 my %Kinds_Target = ();
14550 foreach my $Kind (sort keys(%{$TypeChanges{$TypeName}}))
14551 {
14552 foreach my $Location (sort {cmp_locations($b, $a)} sort keys(%{$TypeChanges{$TypeName}{$Kind}}))
14553 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014554 my $Severity = getProblemSeverity($Level, $Kind);
14555 if($Severity ne $TargetSeverity)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014556 { # other priority
14557 delete($TypeChanges{$TypeName}{$Kind}{$Location});
14558 next;
14559 }
14560 $Kinds_Locations{$TypeName}{$Kind}{$Location} = 1;
14561 my $Target = $TypeChanges{$TypeName}{$Kind}{$Location}{"Target"};
14562 if($Kinds_Target{$Kind}{$Target})
14563 { # duplicate target
14564 delete($TypeChanges{$TypeName}{$Kind}{$Location});
14565 next;
14566 }
14567 $Kinds_Target{$Kind}{$Target} = 1;
14568 my $HeaderName = get_TypeAttr($TName_Tid{1}{$TypeName}, 1, "Header");
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014569 $ReportMap{$HeaderName}{$TypeName} = 1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014570 }
14571 if(not keys(%{$TypeChanges{$TypeName}{$Kind}})) {
14572 delete($TypeChanges{$TypeName}{$Kind});
14573 }
14574 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014575 if(not keys(%{$TypeChanges{$TypeName}})) {
14576 delete($TypeChanges{$TypeName});
14577 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014578 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +040014579 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 +040014580 if($ReportFormat eq "xml")
14581 { # XML
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014582 foreach my $HeaderName (sort {lc($a) cmp lc($b)} keys(%ReportMap))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014583 {
14584 $TYPE_PROBLEMS .= " <header name=\"$HeaderName\">\n";
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014585 foreach my $TypeName (keys(%{$ReportMap{$HeaderName}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014586 {
14587 $TYPE_PROBLEMS .= " <type name=\"".htmlSpecChars($TypeName)."\">\n";
14588 foreach my $Kind (sort {$b=~/Size/ <=> $a=~/Size/} sort keys(%{$TypeChanges{$TypeName}}))
14589 {
14590 foreach my $Location (sort {cmp_locations($b, $a)} sort keys(%{$TypeChanges{$TypeName}{$Kind}}))
14591 {
14592 my %Problem = %{$TypeChanges{$TypeName}{$Kind}{$Location}};
14593 $TYPE_PROBLEMS .= " <problem id=\"$Kind\">\n";
14594 my $Change = $CompatRules{$Level}{$Kind}{"Change"};
14595 $TYPE_PROBLEMS .= " <change".getXmlParams($Change, \%Problem).">$Change</change>\n";
14596 my $Effect = $CompatRules{$Level}{$Kind}{"Effect"};
14597 $TYPE_PROBLEMS .= " <effect".getXmlParams($Effect, \%Problem).">$Effect</effect>\n";
14598 my $Overcome = $CompatRules{$Level}{$Kind}{"Overcome"};
14599 $TYPE_PROBLEMS .= " <overcome".getXmlParams($Overcome, \%Problem).">$Overcome</overcome>\n";
14600 $TYPE_PROBLEMS .= " </problem>\n";
14601 }
14602 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +040014603 $TYPE_PROBLEMS .= getAffectedSymbols($Level, $TypeName, $Kinds_Locations{$TypeName}, \@Symbols);
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014604 if($Level eq "Binary" and grep {$_=~/Virtual|Base_Class/} keys(%{$Kinds_Locations{$TypeName}})) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014605 $TYPE_PROBLEMS .= showVTables($TypeName);
14606 }
14607 $TYPE_PROBLEMS .= " </type>\n";
14608 }
14609 $TYPE_PROBLEMS .= " </header>\n";
14610 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014611 $TYPE_PROBLEMS = "<problems_with_types severity=\"$TargetSeverity\">\n".$TYPE_PROBLEMS."</problems_with_types>\n\n";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014612 }
14613 else
14614 { # HTML
14615 my $ProblemsNum = 0;
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014616 foreach my $HeaderName (sort {lc($a) cmp lc($b)} keys(%ReportMap))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014617 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014618 my (%NameSpace_Type) = ();
14619 foreach my $TypeName (keys(%{$ReportMap{$HeaderName}})) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014620 $NameSpace_Type{parse_TypeNameSpace($TypeName, 1)}{$TypeName} = 1;
14621 }
14622 foreach my $NameSpace (sort keys(%NameSpace_Type))
14623 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014624 $TYPE_PROBLEMS .= getTitle($HeaderName, "", $NameSpace);
14625 my @SortedTypes = sort {$TypeType{$a}." ".lc($a) cmp $TypeType{$b}." ".lc($b)} keys(%{$NameSpace_Type{$NameSpace}});
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014626 foreach my $TypeName (@SortedTypes)
14627 {
14628 my $ProblemNum = 1;
14629 my $TYPE_REPORT = "";
14630 foreach my $Kind (sort {$b=~/Size/ <=> $a=~/Size/} sort keys(%{$TypeChanges{$TypeName}}))
14631 {
14632 foreach my $Location (sort {cmp_locations($b, $a)} sort keys(%{$TypeChanges{$TypeName}{$Kind}}))
14633 {
14634 my %Problem = %{$TypeChanges{$TypeName}{$Kind}{$Location}};
14635 if(my $Change = applyMacroses($Level, $Kind, $CompatRules{$Level}{$Kind}{"Change"}, \%Problem))
14636 {
14637 my $Effect = applyMacroses($Level, $Kind, $CompatRules{$Level}{$Kind}{"Effect"}, \%Problem);
14638 $TYPE_REPORT .= "<tr><th>$ProblemNum</th><td align='left' valign='top'>".$Change."</td><td align='left' valign='top'>$Effect</td></tr>\n";
14639 $ProblemNum += 1;
14640 $ProblemsNum += 1;
14641 }
14642 }
14643 }
14644 $ProblemNum -= 1;
14645 if($TYPE_REPORT)
14646 {
Andrey Ponomarenko85043792012-05-14 16:48:07 +040014647 my $Affected = getAffectedSymbols($Level, $TypeName, $Kinds_Locations{$TypeName}, \@Symbols);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014648 my $ShowVTables = "";
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014649 if($Level eq "Binary" and grep {$_=~/Virtual|Base_Class/} keys(%{$Kinds_Locations{$TypeName}})) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014650 $ShowVTables = showVTables($TypeName);
14651 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014652 $TYPE_PROBLEMS .= $ContentSpanStart."<span class='extendable'>[+]</span> <span class='ttype'>".$TypeType{$TypeName}."</span> ".htmlSpecChars($TypeName)." ($ProblemNum)".$ContentSpanEnd;
14653 $TYPE_PROBLEMS .= "<br/>\n".$ContentDivStart."<table class='ptable'><tr>\n";
14654 $TYPE_PROBLEMS .= "<th width='2%'></th><th width='47%'>Change</th>\n";
14655 $TYPE_PROBLEMS .= "<th>Effect</th></tr>".$TYPE_REPORT."</table>\n";
14656 $TYPE_PROBLEMS .= $ShowVTables.$Affected."<br/><br/>".$ContentDivEnd."\n";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014657 if($NameSpace) {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014658 $TYPE_PROBLEMS=~s/(\W|\A)\Q$NameSpace\E\:\:(\w|\~)/$1$2/g;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014659 }
14660 }
14661 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014662 $TYPE_PROBLEMS .= "<br/>";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014663 }
14664 }
14665 if($TYPE_PROBLEMS)
14666 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014667 $TYPE_PROBLEMS = insertIDs($TYPE_PROBLEMS);
14668 my $Title = "Problems with Data Types, $TargetSeverity Severity";
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014669 if($TargetSeverity eq "Safe")
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014670 { # Safe Changes
14671 $Title = "Other Changes in Data Types";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014672 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014673 $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 +040014674 }
14675 }
14676 return $TYPE_PROBLEMS;
14677}
14678
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014679sub get_Anchor($$$)
14680{
14681 my ($Kind, $Level, $Severity) = @_;
14682 if($JoinReport)
14683 {
14684 if($Severity eq "Safe") {
14685 return "Other_".$Level."_Changes_In_".$Kind."s";
14686 }
14687 else {
14688 return $Kind."_".$Level."_Problems_".$Severity;
14689 }
14690 }
14691 else
14692 {
14693 if($Severity eq "Safe") {
14694 return "Other_Changes_In_".$Kind."s";
14695 }
14696 else {
14697 return $Kind."_Problems_".$Severity;
14698 }
14699 }
14700}
14701
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014702sub showVTables($)
14703{
14704 my $TypeName = $_[0];
14705 my $TypeId1 = $TName_Tid{1}{$TypeName};
14706 my %Type1 = get_Type($Tid_TDid{1}{$TypeId1}, $TypeId1, 1);
14707 if(defined $Type1{"VTable"}
14708 and keys(%{$Type1{"VTable"}}))
14709 {
14710 my $TypeId2 = $TName_Tid{2}{$TypeName};
14711 my %Type2 = get_Type($Tid_TDid{2}{$TypeId2}, $TypeId2, 2);
14712 if(defined $Type2{"VTable"}
14713 and keys(%{$Type2{"VTable"}}))
14714 {
14715 my %Indexes = map {$_=>1} (keys(%{$Type1{"VTable"}}), keys(%{$Type2{"VTable"}}));
14716 my %Entries = ();
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014717 foreach my $Index (sort {int($a)<=>int($b)} (keys(%Indexes)))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014718 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014719 $Entries{$Index}{"E1"} = simpleVEntry($Type1{"VTable"}{$Index});
14720 $Entries{$Index}{"E2"} = simpleVEntry($Type2{"VTable"}{$Index});
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014721 }
14722 my $VTABLES = "";
14723 if($ReportFormat eq "xml")
14724 { # XML
14725 $VTABLES .= " <vtable>\n";
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014726 foreach my $Index (sort {int($a)<=>int($b)} (keys(%Entries)))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014727 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014728 $VTABLES .= " <entry offset=\"".$Index."\">\n";
14729 $VTABLES .= " <old>".htmlSpecChars($Entries{$Index}{"E1"})."</old>\n";
14730 $VTABLES .= " <new>".htmlSpecChars($Entries{$Index}{"E2"})."</new>\n";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014731 $VTABLES .= " </entry>\n";
14732 }
14733 $VTABLES .= " </vtable>\n\n";
14734 }
14735 else
14736 { # HTML
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014737 $VTABLES .= "<table class='vtable'>";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014738 $VTABLES .= "<tr><th width='2%'>Offset</th>";
14739 $VTABLES .= "<th width='45%'>Virtual Table (Old) - ".(keys(%{$Type1{"VTable"}}))." entries</th>";
14740 $VTABLES .= "<th>Virtual Table (New) - ".(keys(%{$Type2{"VTable"}}))." entries</th></tr>";
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014741 foreach my $Index (sort {int($a)<=>int($b)} (keys(%Entries)))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014742 {
14743 my ($Color1, $Color2) = ("", "");
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014744 if($Entries{$Index}{"E1"} ne $Entries{$Index}{"E2"})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014745 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014746 if($Entries{$Index}{"E1"})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014747 {
Andrey Ponomarenko16934472012-03-29 15:37:04 +040014748 $Color1 = " class='failed'";
14749 $Color2 = " class='failed'";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014750 }
14751 else {
Andrey Ponomarenko16934472012-03-29 15:37:04 +040014752 $Color2 = " class='warning'";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014753 }
14754 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014755 $VTABLES .= "<tr><th>".$Index."</th>\n";
14756 $VTABLES .= "<td$Color1>".htmlSpecChars($Entries{$Index}{"E1"})."</td>\n";
14757 $VTABLES .= "<td$Color2>".htmlSpecChars($Entries{$Index}{"E2"})."</td></tr>\n";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014758 }
14759 $VTABLES .= "</table><br/>\n";
14760 $VTABLES = $ContentDivStart.$VTABLES.$ContentDivEnd;
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014761 $VTABLES = $ContentSpanStart_Info."[+] show v-table (old and new)".$ContentSpanEnd."<br/>\n".$VTABLES;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014762 }
14763 return $VTABLES;
14764 }
14765 }
14766 return "";
14767}
14768
14769sub simpleVEntry($)
14770{
14771 my $VEntry = $_[0];
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040014772 if(not defined $VEntry
14773 or $VEntry eq "") {
14774 return "";
14775 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014776 $VEntry=~s/\A(.+)::(_ZThn.+)\Z/$2/; # thunks
14777 $VEntry=~s/_ZTI\w+/typeinfo/g; # typeinfo
14778 if($VEntry=~/\A_ZThn.+\Z/) {
14779 $VEntry = "non-virtual thunk";
14780 }
14781 $VEntry=~s/\A\(int \(\*\)\(...\)\)([^\(\d])/$1/i;
14782 # support for old GCC versions
14783 $VEntry=~s/\A0u\Z/(int (*)(...))0/;
14784 $VEntry=~s/\A4294967268u\Z/(int (*)(...))-0x000000004/;
14785 $VEntry=~s/\A&_Z\Z/& _Z/;
14786 # templates
14787 if($VEntry=~s/ \[with (\w+) = (.+?)(, [^=]+ = .+|])\Z//g)
14788 { # std::basic_streambuf<_CharT, _Traits>::imbue [with _CharT = char, _Traits = std::char_traits<char>]
14789 # become std::basic_streambuf<char, ...>::imbue
14790 my ($Pname, $Pval) = ($1, $2);
14791 if($Pname eq "_CharT" and $VEntry=~/\Astd::/)
14792 { # stdc++ typedefs
14793 $VEntry=~s/<$Pname(, [^<>]+|)>/<$Pval>/g;
14794 # FIXME: simplify names using stdcxx typedefs (StdCxxTypedef)
14795 # The typedef info should be added to ABI dumps
14796 }
14797 else
14798 {
14799 $VEntry=~s/<$Pname>/<$Pval>/g;
14800 $VEntry=~s/<$Pname, [^<>]+>/<$Pval, ...>/g;
14801 }
14802 }
14803 $VEntry=~s/([^:]+)::\~([^:]+)\Z/~$1/; # destructors
14804 return $VEntry;
14805}
14806
Andrey Ponomarenko85043792012-05-14 16:48:07 +040014807sub getAffectedSymbols($$$$)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014808{
Andrey Ponomarenko85043792012-05-14 16:48:07 +040014809 my ($Level, $Target_TypeName, $Kinds_Locations, $Syms) = @_;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014810 my $LIMIT = 1000;
Andrey Ponomarenko85043792012-05-14 16:48:07 +040014811 if($#{$Syms}>=10000)
14812 { # reduce size of the report
14813 $LIMIT = 10;
14814 }
14815 my %SProblems = ();
14816 foreach my $Symbol (@{$Syms})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014817 {
Andrey Ponomarenko85043792012-05-14 16:48:07 +040014818 if(keys(%SProblems)>$LIMIT) {
14819 last;
14820 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014821 if(($Symbol=~/C2E|D2E|D0E/))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014822 { # duplicated problems for C2 constructors, D2 and D0 destructors
14823 next;
14824 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014825 my ($SN, $SS, $SV) = separate_symbol($Symbol);
14826 if($Level eq "Source")
14827 { # remove symbol version
14828 $Symbol=$SN;
14829 }
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040014830 my ($MinPath_Length, $ProblemLocation_Last) = (-1, "");
14831 my $Severity_Max = 0;
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014832 my $Signature = get_Signature($Symbol, 1);
14833 foreach my $Kind (keys(%{$CompatProblems{$Level}{$Symbol}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014834 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014835 foreach my $Location (keys(%{$CompatProblems{$Level}{$Symbol}{$Kind}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014836 {
14837 if(not defined $Kinds_Locations->{$Kind}
14838 or not $Kinds_Locations->{$Kind}{$Location}) {
14839 next;
14840 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014841 if($SV and defined $CompatProblems{$Level}{$SN}
14842 and defined $CompatProblems{$Level}{$SN}{$Kind}{$Location})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014843 { # duplicated problems for versioned symbols
14844 next;
14845 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014846 my $Type_Name = $CompatProblems{$Level}{$Symbol}{$Kind}{$Location}{"Type_Name"};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014847 next if($Type_Name ne $Target_TypeName);
14848
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014849 my $Position = $CompatProblems{$Level}{$Symbol}{$Kind}{$Location}{"Param_Pos"};
14850 my $Param_Name = $CompatProblems{$Level}{$Symbol}{$Kind}{$Location}{"Param_Name"};
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040014851 my $Severity = getProblemSeverity($Level, $Kind);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014852 my $Path_Length = 0;
14853 my $ProblemLocation = $Location;
14854 if($Type_Name) {
14855 $ProblemLocation=~s/->\Q$Type_Name\E\Z//g;
14856 }
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040014857 while($ProblemLocation=~/\-\>/g) {
14858 $Path_Length += 1;
14859 }
14860 if($MinPath_Length==-1 or ($Path_Length<=$MinPath_Length and $Severity_Val{$Severity}>$Severity_Max)
14861 or (cmp_locations($ProblemLocation, $ProblemLocation_Last) and $Severity_Val{$Severity}==$Severity_Max))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014862 {
14863 $MinPath_Length = $Path_Length;
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040014864 $Severity_Max = $Severity_Val{$Severity};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014865 $ProblemLocation_Last = $ProblemLocation;
Andrey Ponomarenko85043792012-05-14 16:48:07 +040014866 %{$SProblems{$Symbol}} = (
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040014867 "Descr"=>getAffectDescription($Level, $Symbol, $Kind, $Location),
14868 "Severity_Max"=>$Severity_Max,
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014869 "Signature"=>$Signature,
14870 "Position"=>$Position,
14871 "Param_Name"=>$Param_Name,
14872 "Location"=>$Location
14873 );
14874 }
14875 }
14876 }
14877 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +040014878 my @Symbols = keys(%SProblems);
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014879 @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 +040014880 @Symbols = sort {$SProblems{$b}{"Severity_Max"}<=>$SProblems{$a}{"Severity_Max"}} @Symbols;
14881 if($#Symbols+1>$LIMIT)
14882 { # remove last element
14883 pop(@Symbols);
14884 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014885 my $Affected = "";
14886 if($ReportFormat eq "xml")
14887 { # XML
14888 $Affected .= " <affected>\n";
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014889 foreach my $Symbol (@Symbols)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014890 {
Andrey Ponomarenko85043792012-05-14 16:48:07 +040014891 my $Param_Name = $SProblems{$Symbol}{"Param_Name"};
14892 my $Description = $SProblems{$Symbol}{"Descr"};
14893 my $Location = $SProblems{$Symbol}{"Location"};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014894 my $Target = "";
14895 if($Param_Name) {
14896 $Target = " affected=\"param\" param_name=\"$Param_Name\"";
14897 }
14898 elsif($Location=~/\Aretval(\-|\Z)/i) {
14899 $Target = " affected=\"retval\"";
14900 }
14901 elsif($Location=~/\Athis(\-|\Z)/i) {
14902 $Target = " affected=\"this\"";
14903 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014904 $Affected .= " <symbol$Target name=\"$Symbol\">\n";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014905 $Affected .= " <comment>".htmlSpecChars($Description)."</comment>\n";
14906 $Affected .= " </symbol>\n";
14907 }
14908 $Affected .= " </affected>\n";
14909 }
14910 else
14911 { # HTML
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014912 foreach my $Symbol (@Symbols)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014913 {
Andrey Ponomarenko85043792012-05-14 16:48:07 +040014914 my $Description = $SProblems{$Symbol}{"Descr"};
14915 my $Signature = $SProblems{$Symbol}{"Signature"};
14916 my $Pos = $SProblems{$Symbol}{"Position"};
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040014917 $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 +040014918 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +040014919 if(keys(%SProblems)>$LIMIT) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014920 $Affected .= "and others ...<br/>";
14921 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +040014922 $Affected = "<div class='affected'>".$Affected."</div>";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014923 if($Affected)
14924 {
14925 $Affected = $ContentDivStart.$Affected.$ContentDivEnd;
Andrey Ponomarenko85043792012-05-14 16:48:07 +040014926 $Affected = $ContentSpanStart_Affected."[+] affected symbols (".(keys(%SProblems)>$LIMIT?">".$LIMIT:keys(%SProblems)).")".$ContentSpanEnd.$Affected;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014927 }
14928 }
14929 return $Affected;
14930}
14931
14932sub cmp_locations($$)
14933{
14934 my ($Location1, $Location2) = @_;
14935 if($Location2=~/(\A|\W)(retval|this)(\W|\Z)/
14936 and $Location1!~/(\A|\W)(retval|this)(\W|\Z)/ and $Location1!~/\-\>/) {
14937 return 1;
14938 }
14939 if($Location2=~/(\A|\W)(retval|this)(\W|\Z)/ and $Location2=~/\-\>/
14940 and $Location1!~/(\A|\W)(retval|this)(\W|\Z)/ and $Location1=~/\-\>/) {
14941 return 1;
14942 }
14943 return 0;
14944}
14945
14946sub getAffectDescription($$$$)
14947{
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014948 my ($Level, $Symbol, $Kind, $Location) = @_;
14949 my %Problem = %{$CompatProblems{$Level}{$Symbol}{$Kind}{$Location}};
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040014950 my $PPos = showPos($Problem{"Param_Pos"});
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014951 my @Sentence = ();
14952 $Location=~s/\A(.*)\-\>.+?\Z/$1/;
14953 if($Kind eq "Overridden_Virtual_Method"
14954 or $Kind eq "Overridden_Virtual_Method_B") {
14955 push(@Sentence, "The method '".$Problem{"New_Value"}."' will be called instead of this method.");
14956 }
14957 elsif($CompatRules{$Level}{$Kind}{"Kind"} eq "Types")
14958 {
14959 if($Location eq "this" or $Kind=~/(\A|_)Virtual(_|\Z)/)
14960 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014961 my $METHOD_TYPE = $CompleteSignature{1}{$Symbol}{"Constructor"}?"constructor":"method";
14962 my $ClassName = get_TypeName($CompleteSignature{1}{$Symbol}{"Class"}, 1);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014963 if($ClassName eq $Problem{"Type_Name"}) {
14964 push(@Sentence, "This $METHOD_TYPE is from \'".$Problem{"Type_Name"}."\' class.");
14965 }
14966 else {
14967 push(@Sentence, "This $METHOD_TYPE is from derived class \'".$ClassName."\'.");
14968 }
14969 }
14970 else
14971 {
14972 if($Location=~/retval/)
14973 { # return value
14974 if($Location=~/\-\>/) {
14975 push(@Sentence, "Field \'".$Location."\' in return value");
14976 }
14977 else {
14978 push(@Sentence, "Return value");
14979 }
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040014980 if(my $Init = $Problem{"InitialType_Type"})
14981 {
14982 if($Init eq "Pointer") {
14983 push(@Sentence, "(pointer)");
14984 }
14985 elsif($Init eq "Ref") {
14986 push(@Sentence, "(reference)");
14987 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014988 }
14989 }
14990 elsif($Location=~/this/)
14991 { # "this" pointer
14992 if($Location=~/\-\>/) {
14993 push(@Sentence, "Field \'".$Location."\' in the object of this method");
14994 }
14995 else {
14996 push(@Sentence, "\'this\' pointer");
14997 }
14998 }
14999 else
15000 { # parameters
15001 if($Location=~/\-\>/) {
15002 push(@Sentence, "Field \'".$Location."\' in $PPos parameter");
15003 }
15004 else {
15005 push(@Sentence, "$PPos parameter");
15006 }
15007 if($Problem{"Param_Name"}) {
15008 push(@Sentence, "\'".$Problem{"Param_Name"}."\'");
15009 }
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040015010 if(my $Init = $Problem{"InitialType_Type"})
15011 {
15012 if($Init eq "Pointer") {
15013 push(@Sentence, "(pointer)");
15014 }
15015 elsif($Init eq "Ref") {
15016 push(@Sentence, "(reference)");
15017 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015018 }
15019 }
15020 if($Location eq "this") {
15021 push(@Sentence, "has base type \'".$Problem{"Type_Name"}."\'.");
15022 }
15023 elsif($Problem{"Start_Type_Name"} eq $Problem{"Type_Name"}) {
15024 push(@Sentence, "has type \'".$Problem{"Type_Name"}."\'.");
15025 }
15026 else {
15027 push(@Sentence, "has base type \'".$Problem{"Type_Name"}."\'.");
15028 }
15029 }
15030 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015031 if($ExtendedFuncs{$Symbol}) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015032 push(@Sentence, " This is a symbol from an artificial external library that may use the \'$TargetLibraryName\' library and change its ABI after recompiling.");
15033 }
15034 return join(" ", @Sentence);
15035}
15036
15037sub get_XmlSign($$)
15038{
15039 my ($Symbol, $LibVersion) = @_;
15040 my $Info = $CompleteSignature{$LibVersion}{$Symbol};
15041 my $Report = "";
15042 foreach my $Pos (sort {int($a)<=>int($b)} keys(%{$Info->{"Param"}}))
15043 {
15044 my $Name = $Info->{"Param"}{$Pos}{"name"};
15045 my $TypeName = get_TypeName($Info->{"Param"}{$Pos}{"type"}, $LibVersion);
15046 foreach my $Typedef (keys(%ChangedTypedef))
15047 {
15048 my $Base = $Typedef_BaseName{$LibVersion}{$Typedef};
15049 $TypeName=~s/(\A|\W)\Q$Typedef\E(\W|\Z)/$1$Base$2/g;
15050 }
15051 $Report .= " <param pos=\"$Pos\">\n";
15052 $Report .= " <name>".$Name."</name>\n";
15053 $Report .= " <type>".htmlSpecChars($TypeName)."</type>\n";
15054 $Report .= " </param>\n";
15055 }
15056 if(my $Return = $Info->{"Return"})
15057 {
15058 my $RTName = get_TypeName($Return, $LibVersion);
15059 $Report .= " <retval>\n";
15060 $Report .= " <type>".htmlSpecChars($RTName)."</type>\n";
15061 $Report .= " </retval>\n";
15062 }
15063 return $Report;
15064}
15065
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015066sub get_Report_SymbolsInfo($)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015067{
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015068 my $Level = $_[0];
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015069 my $Report = "<symbols_info>\n";
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015070 foreach my $Symbol (sort keys(%{$CompatProblems{$Level}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015071 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015072 my ($SN, $SS, $SV) = separate_symbol($Symbol);
15073 if($SV and defined $CompatProblems{$Level}{$SN}) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015074 next;
15075 }
15076 $Report .= " <symbol name=\"$Symbol\">\n";
15077 my ($S1, $P1, $S2, $P2) = ();
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015078 if(not $AddedInt{$Level}{$Symbol})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015079 {
15080 if(defined $CompleteSignature{1}{$Symbol}
15081 and defined $CompleteSignature{1}{$Symbol}{"Header"})
15082 {
15083 $P1 = get_XmlSign($Symbol, 1);
15084 $S1 = get_Signature($Symbol, 1);
15085 }
15086 elsif($Symbol=~/\A(_Z|\?)/) {
15087 $S1 = $tr_name{$Symbol};
15088 }
15089 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015090 if(not $RemovedInt{$Level}{$Symbol})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015091 {
15092 if(defined $CompleteSignature{2}{$Symbol}
15093 and defined $CompleteSignature{2}{$Symbol}{"Header"})
15094 {
15095 $P2 = get_XmlSign($Symbol, 2);
15096 $S2 = get_Signature($Symbol, 2);
15097 }
15098 elsif($Symbol=~/\A(_Z|\?)/) {
15099 $S2 = $tr_name{$Symbol};
15100 }
15101 }
15102 if($S1)
15103 {
15104 $Report .= " <old signature=\"".htmlSpecChars($S1)."\">\n";
15105 $Report .= $P1;
15106 $Report .= " </old>\n";
15107 }
15108 if($S2 and $S2 ne $S1)
15109 {
15110 $Report .= " <new signature=\"".htmlSpecChars($S2)."\">\n";
15111 $Report .= $P2;
15112 $Report .= " </new>\n";
15113 }
15114 $Report .= " </symbol>\n";
15115 }
15116 $Report .= "</symbols_info>\n";
15117 return $Report;
15118}
15119
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015120sub writeReport($$)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015121{
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015122 my ($Level, $Report) = @_;
15123 if($ReportFormat eq "xml") {
15124 $Report = "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n".$Report;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015125 }
15126 if($StdOut)
15127 { # --stdout option
15128 print STDOUT $Report;
15129 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015130 else
15131 {
15132 my $RPath = getReportPath($Level);
Andrey Ponomarenko85043792012-05-14 16:48:07 +040015133 mkpath(get_dirname($RPath));
15134
15135 open(REPORT, ">", $RPath) || die ("can't open file \'$RPath\': $!\n");
15136 print REPORT $Report;
15137 close(REPORT);
15138
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015139 if($Browse)
15140 {
15141 system($Browse." $RPath >/dev/null 2>&1 &");
15142 if($JoinReport or $DoubleReport)
15143 {
15144 if($Level eq "Binary")
15145 { # wait to open a browser
15146 sleep(1);
15147 }
15148 }
15149 }
15150 }
15151}
15152
15153sub getReport($)
15154{
15155 my $Level = $_[0];
15156 if($ReportFormat eq "xml")
15157 { # XML
15158
15159 if($Level eq "Join")
15160 {
15161 my $Report = "<reports>\n";
15162 $Report .= getReport("Binary");
15163 $Report .= getReport("Source");
15164 $Report .= "</reports>\n";
15165 return $Report;
15166 }
15167 else
15168 {
15169 my $Report = "<report kind=\"".lc($Level)."\" version=\"$XML_REPORT_VERSION\">\n\n";
15170 my ($Summary, $MetaData) = get_Summary($Level);
15171 $Report .= $Summary."\n";
15172 $Report .= get_Report_Added($Level).get_Report_Removed($Level);
15173 $Report .= get_Report_Problems("High", $Level).get_Report_Problems("Medium", $Level).get_Report_Problems("Low", $Level).get_Report_Problems("Safe", $Level);
15174 $Report .= get_Report_SymbolsInfo($Level);
15175 $Report .= "</report>\n";
15176 return $Report;
15177 }
15178 }
15179 else
15180 { # HTML
15181 my $CssStyles = readModule("Styles", "Report.css");
15182 my $JScripts = readModule("Scripts", "Sections.js");
15183 if($Level eq "Join")
15184 {
15185 $CssStyles .= "\n".readModule("Styles", "Tabs.css");
15186 $JScripts .= "\n".readModule("Scripts", "Tabs.js");
15187 my $Title = "$TargetLibraryFName: ".$Descriptor{1}{"Version"}." to ".$Descriptor{2}{"Version"}." compatibility report";
15188 my $Keywords = "$TargetLibraryFName, compatibility, API, report";
15189 my $Description = "Compatibility report for the $TargetLibraryFName $TargetComponent between ".$Descriptor{1}{"Version"}." and ".$Descriptor{2}{"Version"}." versions";
15190 my ($BSummary, $BMetaData) = get_Summary("Binary");
15191 my ($SSummary, $SMetaData) = get_Summary("Source");
15192 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>";
15193 $Report .= get_Report_Header("Join")."
15194 <br/><div class='tabset'>
Andrey Ponomarenko16934472012-03-29 15:37:04 +040015195 <a id='BinaryID' href='#BinaryTab' class='tab active'>Binary<br/>Compatibility</a>
15196 <a id='SourceID' href='#SourceTab' style='margin-left:3px' class='tab disabled'>Source<br/>Compatibility</a>
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015197 </div>";
15198 $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>";
15199 $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>";
15200 $Report .= getReportFooter($TargetLibraryFName);
15201 $Report .= "\n<div style='height:999px;'></div>\n</body></html>";
15202 return $Report;
15203 }
15204 else
15205 {
15206 my ($Summary, $MetaData) = get_Summary($Level);
15207 my $Title = "$TargetLibraryFName: ".$Descriptor{1}{"Version"}." to ".$Descriptor{2}{"Version"}." ".lc($Level)." compatibility report";
15208 my $Keywords = "$TargetLibraryFName, ".lc($Level)." compatibility, API, report";
15209 my $Description = "$Level compatibility report for the $TargetLibraryFName $TargetComponent between ".$Descriptor{1}{"Version"}." and ".$Descriptor{2}{"Version"}." versions";
15210 if($Level eq "Binary")
15211 {
15212 if(getArch(1) eq getArch(2)
15213 and getArch(1) ne "unknown") {
15214 $Description .= " on ".showArch(getArch(1));
15215 }
15216 }
15217 my $Report = "<!-\- $MetaData -\->\n".composeHTML_Head($Title, $Keywords, $Description, $CssStyles, $JScripts)."\n<body>\n<div><a name='Top'></a>\n";
15218 $Report .= get_Report_Header($Level)."\n".$Summary."\n";
15219 $Report .= get_Report_Added($Level).get_Report_Removed($Level);
15220 $Report .= get_Report_Problems("High", $Level).get_Report_Problems("Medium", $Level).get_Report_Problems("Low", $Level).get_Report_Problems("Safe", $Level);
15221 $Report .= get_SourceInfo();
15222 $Report .= "</div>\n<br/><br/><br/><hr/>\n";
15223 $Report .= getReportFooter($TargetLibraryFName);
15224 $Report .= "\n<div style='height:999px;'></div>\n</body></html>";
15225 return $Report;
15226 }
15227 }
15228}
15229
Andrey Ponomarenko16934472012-03-29 15:37:04 +040015230sub getLegend()
15231{
15232 return "<br/>
15233<table class='summary'>
15234<tr>
15235 <td class='new'>added</td>
15236 <td class='passed'>compatible</td>
15237</tr>
15238<tr>
15239 <td class='warning'>warning</td>
15240 <td class='failed'>incompatible</td>
15241</tr></table>\n";
15242}
15243
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015244sub createReport()
15245{
15246 if($JoinReport)
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040015247 { # --stdout
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015248 writeReport("Join", getReport("Join"));
15249 }
15250 elsif($DoubleReport)
15251 { # default
15252 writeReport("Binary", getReport("Binary"));
15253 writeReport("Source", getReport("Source"));
15254 }
15255 elsif($BinaryOnly)
15256 { # --binary
15257 writeReport("Binary", getReport("Binary"));
15258 }
15259 elsif($SourceOnly)
15260 { # --source
15261 writeReport("Source", getReport("Source"));
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015262 }
15263}
15264
15265sub getReportFooter($)
15266{
15267 my $LibName = $_[0];
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015268 my $FooterStyle = (not $JoinReport)?"width:99%":"width:97%;padding-top:3px";
15269 my $Footer = "<div style='$FooterStyle;font-size:11px;' align='right'><i>Generated on ".(localtime time); # report date
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015270 $Footer .= " for <span style='font-weight:bold'>$LibName</span>"; # tested library/system name
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015271 $Footer .= " by <a href='".$HomePage{"Wiki"}."'>ABI Compliance Checker</a>"; # tool name
15272 my $ToolSummary = "<br/>A tool for checking backward compatibility of a C/C++ library API&#160;&#160;";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015273 $Footer .= " $TOOL_VERSION &#160;$ToolSummary</i></div>"; # tool version
15274 return $Footer;
15275}
15276
15277sub get_Report_Problems($$)
15278{
15279 my ($Priority, $Level) = @_;
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040015280 my $Report = get_Report_TypeProblems($Priority, $Level);
Andrey Ponomarenko16934472012-03-29 15:37:04 +040015281 if(my $SProblems = get_Report_SymbolProblems($Priority, $Level)) {
15282 $Report .= $SProblems;
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040015283 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015284 if($Priority eq "Low")
15285 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015286 $Report .= get_Report_ChangedConstants($Level);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015287 if($ReportFormat eq "html") {
15288 if($CheckImpl and $Level eq "Binary") {
15289 $Report .= get_Report_Impl();
15290 }
15291 }
15292 }
15293 if($ReportFormat eq "html")
15294 {
15295 if($Report)
15296 { # add anchor
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015297 if($JoinReport)
15298 {
15299 if($Priority eq "Safe") {
15300 $Report = "<a name=\'Other_".$Level."_Changes\'></a>".$Report;
15301 }
15302 else {
15303 $Report = "<a name=\'".$Priority."_Risk_".$Level."_Problems\'></a>".$Report;
15304 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015305 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015306 else
15307 {
15308 if($Priority eq "Safe") {
15309 $Report = "<a name=\'Other_Changes\'></a>".$Report;
15310 }
15311 else {
15312 $Report = "<a name=\'".$Priority."_Risk_Problems\'></a>".$Report;
15313 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015314 }
15315 }
15316 }
15317 return $Report;
15318}
15319
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015320sub composeHTML_Head($$$$$)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015321{
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015322 my ($Title, $Keywords, $Description, $Styles, $Scripts) = @_;
15323 return "<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.0 Transitional//EN\" \"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd\">
15324 <html xmlns=\"http://www.w3.org/1999/xhtml\" xml:lang=\"en\" lang=\"en\">
15325 <head>
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015326 <meta http-equiv=\"Content-Type\" content=\"text/html; charset=utf-8\" />
15327 <meta name=\"keywords\" content=\"$Keywords\" />
15328 <meta name=\"description\" content=\"$Description\" />
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015329 <title>
15330 $Title
15331 </title>
15332 <style type=\"text/css\">
15333 $Styles
15334 </style>
15335 <script type=\"text/javascript\" language=\"JavaScript\">
15336 <!--
15337 $Scripts
15338 -->
15339 </script>
15340 </head>";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015341}
15342
15343sub insertIDs($)
15344{
15345 my $Text = $_[0];
15346 while($Text=~/CONTENT_ID/)
15347 {
15348 if(int($Content_Counter)%2) {
15349 $ContentID -= 1;
15350 }
15351 $Text=~s/CONTENT_ID/c_$ContentID/;
15352 $ContentID += 1;
15353 $Content_Counter += 1;
15354 }
15355 return $Text;
15356}
15357
15358sub checkPreprocessedUnit($)
15359{
15360 my $Path = $_[0];
15361 my $CurHeader = "";
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015362 open(PREPROC, $Path) || die ("can't open file \'$Path\': $!\n");
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015363 while(<PREPROC>)
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015364 { # detecting public and private constants
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015365 next if(not /\A#/);
15366 chomp($_);
15367 if(/#[ \t]+\d+[ \t]+\"(.+)\"/) {
15368 $CurHeader=path_format($1, $OSgroup);
15369 }
15370 if(not $Include_Neighbors{$Version}{get_filename($CurHeader)}
15371 and not $Registered_Headers{$Version}{$CurHeader})
15372 { # not a target
15373 next;
15374 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +040015375 my $HName = get_filename($CurHeader);
15376 if(not is_target_header($HName, 1)
15377 and not is_target_header($HName, 2))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015378 { # user-defined header
15379 next;
15380 }
15381 if(/\#[ \t]*define[ \t]+([_A-Z0-9]+)[ \t]+(.+)[ \t]*\Z/)
15382 {
15383 my ($Name, $Value) = ($1, $2);
15384 if(not $Constants{$Version}{$Name}{"Access"})
15385 {
15386 $Constants{$Version}{$Name}{"Access"} = "public";
15387 $Constants{$Version}{$Name}{"Value"} = $Value;
15388 $Constants{$Version}{$Name}{"Header"} = get_filename($CurHeader);
15389 }
15390 }
15391 elsif(/\#[ \t]*undef[ \t]+([_A-Z]+)[ \t]*/) {
15392 $Constants{$Version}{$1}{"Access"} = "private";
15393 }
15394 }
15395 close(PREPROC);
15396 foreach my $Constant (keys(%{$Constants{$Version}}))
15397 {
15398 if($Constants{$Version}{$Constant}{"Access"} eq "private" or $Constant=~/_h\Z/i
15399 or isBuiltIn($Constants{$Version}{$Constant}{"Header"}))
15400 { # skip private constants
15401 delete($Constants{$Version}{$Constant});
15402 }
15403 else {
15404 delete($Constants{$Version}{$Constant}{"Access"});
15405 }
15406 }
15407}
15408
Andrey Ponomarenko16934472012-03-29 15:37:04 +040015409sub uncoverConstant($$)
15410{
15411 my ($LibVersion, $Constant) = @_;
15412 return "" if(not $LibVersion or not $Constant);
15413 return $Constant if(isCyclical(\@RecurConstant, $Constant));
15414 if(defined $Cache{"uncoverConstant"}{$LibVersion}{$Constant}) {
15415 return $Cache{"uncoverConstant"}{$LibVersion}{$Constant};
15416 }
15417 my $Value = $Constants{$LibVersion}{$Constant}{"Value"};
15418 if(defined $Value)
15419 {
15420 if($Value=~/\A[A-Z0-9_]+\Z/ and $Value=~/[A-Z]/)
15421 {
15422 push(@RecurConstant, $Constant);
15423 my $Uncovered = uncoverConstant($LibVersion, $Value);
15424 if($Uncovered ne "") {
15425 $Value = $Uncovered;
15426 }
15427 pop(@RecurConstant);
15428 }
15429 # FIXME: uncover $Value using all the enum constants
15430 # USECASE: change of define NC_LONG from NC_INT (enum value) to NC_INT (define)
15431 return ($Cache{"uncoverConstant"}{$LibVersion}{$Constant} = $Value);
15432 }
15433 return ($Cache{"uncoverConstant"}{$LibVersion}{$Constant} = "");
15434}
15435
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015436my %IgnoreConstant=(
15437 "VERSION"=>1,
15438 "VERSIONCODE"=>1,
15439 "VERNUM"=>1,
15440 "VERS_INFO"=>1,
15441 "PATCHLEVEL"=>1,
15442 "INSTALLPREFIX"=>1,
15443 "VBUILD"=>1,
15444 "VPATCH"=>1,
15445 "VMINOR"=>1,
15446 "BUILD_STRING"=>1,
15447 "BUILD_TIME"=>1,
15448 "PACKAGE_STRING"=>1,
15449 "PRODUCTION"=>1,
15450 "CONFIGURE_COMMAND"=>1,
15451 "INSTALLDIR"=>1,
15452 "BINDIR"=>1,
15453 "CONFIG_FILE_PATH"=>1,
15454 "DATADIR"=>1,
15455 "EXTENSION_DIR"=>1,
15456 "INCLUDE_PATH"=>1,
15457 "LIBDIR"=>1,
15458 "LOCALSTATEDIR"=>1,
15459 "SBINDIR"=>1,
15460 "SYSCONFDIR"=>1,
15461 "RELEASE"=>1,
15462 "SOURCE_ID"=>1,
15463 "SUBMINOR"=>1,
15464 "MINOR"=>1,
15465 "MINNOR"=>1,
15466 "MINORVERSION"=>1,
15467 "MAJOR"=>1,
15468 "MAJORVERSION"=>1,
15469 "MICRO"=>1,
15470 "MICROVERSION"=>1,
15471 "BINARY_AGE"=>1,
15472 "INTERFACE_AGE"=>1,
15473 "CORE_ABI"=>1,
15474 "PATCH"=>1,
15475 "COPYRIGHT"=>1,
15476 "TIMESTAMP"=>1,
15477 "REVISION"=>1,
15478 "PACKAGE_TAG"=>1,
15479 "PACKAGEDATE"=>1,
15480 "NUMVERSION"=>1
15481);
15482
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015483sub mergeConstants($)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015484{
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015485 my $Level = $_[0];
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015486 foreach my $Constant (keys(%{$Constants{1}}))
15487 {
15488 if($SkipConstants{1}{$Constant})
15489 { # skipped by the user
15490 next;
15491 }
Andrey Ponomarenko16934472012-03-29 15:37:04 +040015492 if(not defined $Constants{2}{$Constant}{"Value"}
15493 or $Constants{2}{$Constant}{"Value"} eq "")
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015494 { # empty value
15495 next;
15496 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +040015497 my $Header = $Constants{1}{$Constant}{"Header"};
15498 if(not is_target_header($Header, 1)
15499 and not is_target_header($Header, 2))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015500 { # user-defined header
15501 next;
15502 }
15503 my ($Old_Value, $New_Value, $Old_Value_Pure, $New_Value_Pure);
Andrey Ponomarenko16934472012-03-29 15:37:04 +040015504 $Old_Value = $Old_Value_Pure = uncoverConstant(1, $Constant);
15505 $New_Value = $New_Value_Pure = uncoverConstant(2, $Constant);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015506 $Old_Value_Pure=~s/(\W)\s+/$1/g;
15507 $Old_Value_Pure=~s/\s+(\W)/$1/g;
15508 $New_Value_Pure=~s/(\W)\s+/$1/g;
15509 $New_Value_Pure=~s/\s+(\W)/$1/g;
15510 next if($New_Value_Pure eq "" or $Old_Value_Pure eq "");
15511 if($New_Value_Pure ne $Old_Value_Pure)
15512 { # different values
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015513 if($Level eq "Binary")
15514 {
15515 if(grep {$Constant=~/(\A|_)$_(_|\Z)/} keys(%IgnoreConstant))
15516 { # ignore library version
15517 next;
15518 }
15519 if($Constant=~/(\A|_)(lib|open|)$TargetLibraryShortName(_|)(VERSION|VER|DATE|API|PREFIX)(_|\Z)/i)
15520 { # ignore library version
15521 next;
15522 }
15523 if($Old_Value=~/\A('|"|)[\/\\]\w+([\/\\]|:|('|"|)\Z)/ or $Old_Value=~/[\/\\]\w+[\/\\]\w+/)
15524 { # ignoring path defines:
Andrey Ponomarenko85043792012-05-14 16:48:07 +040015525 # /lib64:/usr/lib64:/lib:/usr/lib:/usr/X11R6/lib/Xaw3d ...
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015526 next;
15527 }
15528 if($Old_Value=~/\A\(*[a-z_]+(\s+|\|)/i)
15529 { # ignore source defines:
Andrey Ponomarenko85043792012-05-14 16:48:07 +040015530 # static int gcry_pth_init ( void) { return ...
15531 # (RE_BACKSLASH_ESCAPE_IN_LISTS | RE...
15532 next;
15533 }
15534 if($Old_Value=~/\(/i and $Old_Value!~/[\"\']/i)
15535 { # ignore source defines:
15536 # foo(p)
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015537 next;
15538 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015539 }
15540 if(convert_integer($Old_Value) eq convert_integer($New_Value))
15541 { # 0x0001 and 0x1, 0x1 and 1 equal constants
15542 next;
15543 }
15544 if($Old_Value eq "0" and $New_Value eq "NULL")
15545 { # 0 => NULL
15546 next;
15547 }
15548 if($Old_Value eq "NULL" and $New_Value eq "0")
15549 { # NULL => 0
15550 next;
15551 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015552 %{$ProblemsWithConstants{$Level}{$Constant}} = (
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015553 "Target"=>$Constant,
15554 "Old_Value"=>$Old_Value,
15555 "New_Value"=>$New_Value );
15556 }
15557 }
15558}
15559
15560sub convert_integer($)
15561{
15562 my $Value = $_[0];
15563 if($Value=~/\A0x[a-f0-9]+\Z/)
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015564 { # hexadecimal
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015565 return hex($Value);
15566 }
15567 elsif($Value=~/\A0[0-7]+\Z/)
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015568 { # octal
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015569 return oct($Value);
15570 }
15571 elsif($Value=~/\A0b[0-1]+\Z/)
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015572 { # binary
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015573 return oct($Value);
15574 }
15575 else {
15576 return $Value;
15577 }
15578}
15579
Andrey Ponomarenko16934472012-03-29 15:37:04 +040015580sub readSymbols($)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015581{
15582 my $LibVersion = $_[0];
Andrey Ponomarenko16934472012-03-29 15:37:04 +040015583 my @LibPaths = getSoPaths($LibVersion);
15584 if($#LibPaths==-1 and not $CheckHeadersOnly)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015585 {
15586 if($LibVersion==1)
15587 {
15588 printMsg("WARNING", "checking headers only");
15589 $CheckHeadersOnly = 1;
15590 }
15591 else {
15592 exitStatus("Error", "$SLIB_TYPE libraries are not found in ".$Descriptor{$LibVersion}{"Version"});
15593 }
15594 }
Andrey Ponomarenko16934472012-03-29 15:37:04 +040015595 my %GroupNames = map {parse_libname(get_filename($_), "name+ext", $OStarget)=>1} @LibPaths;
15596 foreach my $LibPath (sort {length($a)<=>length($b)} @LibPaths) {
15597 readSymbols_Lib($LibVersion, $LibPath, 0, \%GroupNames, "+Weak");
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015598 }
Andrey Ponomarenko16934472012-03-29 15:37:04 +040015599 if(not $CheckHeadersOnly)
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040015600 {
Andrey Ponomarenko16934472012-03-29 15:37:04 +040015601 if($#LibPaths!=-1)
15602 {
15603 if(not keys(%{$Symbol_Library{$LibVersion}}))
15604 {
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040015605 printMsg("WARNING", "the set of public symbols in library(ies) is empty ($LibVersion)");
Andrey Ponomarenko16934472012-03-29 15:37:04 +040015606 printMsg("WARNING", "checking headers only");
15607 $CheckHeadersOnly = 1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015608 }
15609 }
15610 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +040015611
15612 # clean memory
15613 %SystemObjects = ();
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015614}
15615
Andrey Ponomarenko16934472012-03-29 15:37:04 +040015616sub getSymbolSize($$)
15617{ # size from the shared library
15618 my ($Symbol, $LibVersion) = @_;
15619 return 0 if(not $Symbol);
15620 if(defined $Symbol_Library{$LibVersion}{$Symbol}
15621 and my $LibName = $Symbol_Library{$LibVersion}{$Symbol})
15622 {
15623 if(defined $Library_Symbol{$LibVersion}{$LibName}{$Symbol}
15624 and my $Size = $Library_Symbol{$LibVersion}{$LibName}{$Symbol})
15625 {
15626 if($Size<0) {
15627 return -$Size;
15628 }
15629 }
15630 }
15631 return 0;
15632}
15633
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015634sub canonifyName($)
15635{ # make TIFFStreamOpen(char const*, std::basic_ostream<char, std::char_traits<char> >*)
15636 # to be TIFFStreamOpen(char const*, std::basic_ostream<char>*)
15637 my $Name = $_[0];
15638 my $Rem = "std::(allocator|less|char_traits|regex_traits)";
Andrey Ponomarenko85043792012-05-14 16:48:07 +040015639 while($Name=~/([^<>,]+),\s*$Rem<([^<>,]+)>\s*/ and $1 eq $3)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015640 {
Andrey Ponomarenko85043792012-05-14 16:48:07 +040015641 my $P = $1;
15642 $Name=~s/\Q$P\E,\s*$Rem<\Q$P\E>\s*/$P/g;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015643 }
15644 return $Name;
15645}
15646
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040015647sub translateSymbols(@)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015648{
15649 my $LibVersion = pop(@_);
15650 my (@MnglNames1, @MnglNames2, @UnMnglNames) = ();
15651 foreach my $Interface (sort @_)
15652 {
15653 if($Interface=~/\A_Z/)
15654 {
15655 next if($tr_name{$Interface});
15656 $Interface=~s/[\@\$]+(.*)\Z//;
15657 push(@MnglNames1, $Interface);
15658 }
15659 elsif($Interface=~/\A\?/) {
15660 push(@MnglNames2, $Interface);
15661 }
15662 else
15663 { # not mangled
15664 $tr_name{$Interface} = $Interface;
15665 $mangled_name_gcc{$Interface} = $Interface;
15666 $mangled_name{$LibVersion}{$Interface} = $Interface;
15667 }
15668 }
15669 if($#MnglNames1 > -1)
15670 { # GCC names
15671 @UnMnglNames = reverse(unmangleArray(@MnglNames1));
15672 foreach my $MnglName (@MnglNames1)
15673 {
15674 my $Unmangled = $tr_name{$MnglName} = formatName(canonifyName(pop(@UnMnglNames)));
15675 if(not $mangled_name_gcc{$Unmangled}) {
15676 $mangled_name_gcc{$Unmangled} = $MnglName;
15677 }
15678 if($MnglName=~/\A_ZTV/ and $Unmangled=~/vtable for (.+)/)
15679 { # bind class name and v-table symbol
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040015680 my $ClassName = $1;
15681 $ClassVTable{$ClassName} = $MnglName;
15682 $VTableClass{$MnglName} = $ClassName;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015683 }
15684 }
15685 }
15686 if($#MnglNames2 > -1)
15687 { # MSVC names
15688 @UnMnglNames = reverse(unmangleArray(@MnglNames2));
15689 foreach my $MnglName (@MnglNames2)
15690 {
15691 $tr_name{$MnglName} = formatName(pop(@UnMnglNames));
15692 $mangled_name{$LibVersion}{$tr_name{$MnglName}} = $MnglName;
15693 }
15694 }
15695 return \%tr_name;
15696}
15697
15698sub link_symbol($$$)
15699{
15700 my ($Symbol, $RunWith, $Deps) = @_;
15701 if(link_symbol_internal($Symbol, $RunWith, \%Symbol_Library)) {
15702 return 1;
15703 }
15704 if($Deps eq "+Deps")
15705 { # check the dependencies
15706 if(link_symbol_internal($Symbol, $RunWith, \%DepSymbols)) {
15707 return 1;
15708 }
15709 }
15710 return 0;
15711}
15712
15713sub link_symbol_internal($$$)
15714{
15715 my ($Symbol, $RunWith, $Where) = @_;
15716 return 0 if(not $Where or not $Symbol);
15717 if($Where->{$RunWith}{$Symbol})
15718 { # the exact match by symbol name
15719 return 1;
15720 }
15721 if(my $VSym = $SymVer{$RunWith}{$Symbol})
15722 { # indirect symbol version, i.e.
15723 # foo_old and its symlink foo@v (or foo@@v)
15724 # foo_old may be in .symtab table
15725 if($Where->{$RunWith}{$VSym}) {
15726 return 1;
15727 }
15728 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015729 my ($Sym, $Spec, $Ver) = separate_symbol($Symbol);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015730 if($Sym and $Ver)
15731 { # search for the symbol with the same version
15732 # or without version
15733 if($Where->{$RunWith}{$Sym})
15734 { # old: foo@v|foo@@v
15735 # new: foo
15736 return 1;
15737 }
15738 if($Where->{$RunWith}{$Sym."\@".$Ver})
15739 { # old: foo|foo@@v
15740 # new: foo@v
15741 return 1;
15742 }
15743 if($Where->{$RunWith}{$Sym."\@\@".$Ver})
15744 { # old: foo|foo@v
15745 # new: foo@@v
15746 return 1;
15747 }
15748 }
15749 return 0;
15750}
15751
Andrey Ponomarenko16934472012-03-29 15:37:04 +040015752sub readSymbols_App($)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015753{
15754 my $Path = $_[0];
15755 return () if(not $Path or not -f $Path);
15756 my @Imported = ();
15757 if($OSgroup eq "macos")
15758 {
15759 my $OtoolCmd = get_CmdPath("otool");
15760 if(not $OtoolCmd) {
15761 exitStatus("Not_Found", "can't find \"otool\"");
15762 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015763 open(APP, "$OtoolCmd -IV \"".$Path."\" 2>$TMP_DIR/null |");
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015764 while(<APP>) {
15765 if(/[^_]+\s+_?([\w\$]+)\s*\Z/) {
15766 push(@Imported, $1);
15767 }
15768 }
15769 close(APP);
15770 }
15771 elsif($OSgroup eq "windows")
15772 {
15773 my $DumpBinCmd = get_CmdPath("dumpbin");
15774 if(not $DumpBinCmd) {
15775 exitStatus("Not_Found", "can't find \"dumpbin.exe\"");
15776 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015777 open(APP, "$DumpBinCmd /IMPORTS \"".$Path."\" 2>$TMP_DIR/null |");
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015778 while(<APP>) {
15779 if(/\s*\w+\s+\w+\s+\w+\s+([\w\?\@]+)\s*/) {
15780 push(@Imported, $1);
15781 }
15782 }
15783 close(APP);
15784 }
15785 else
15786 {
15787 my $ReadelfCmd = get_CmdPath("readelf");
15788 if(not $ReadelfCmd) {
15789 exitStatus("Not_Found", "can't find \"readelf\"");
15790 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015791 open(APP, "$ReadelfCmd -WhlSsdA \"".$Path."\" 2>$TMP_DIR/null |");
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015792 my $symtab=0; # indicates that we are processing 'symtab' section of 'readelf' output
15793 while(<APP>)
15794 {
15795 if( /'.dynsym'/ ) {
15796 $symtab=0;
15797 }
15798 elsif($symtab == 1) {
15799 # do nothing with symtab (but there are some plans for the future)
15800 next;
15801 }
15802 elsif( /'.symtab'/ ) {
15803 $symtab=1;
15804 }
15805 elsif(my ($fullname, $idx, $Ndx, $type, $size, $bind) = readline_ELF($_))
15806 {
15807 if( $Ndx eq "UND" ) {
15808 #only imported symbols
15809 push(@Imported, $fullname);
15810 }
15811 }
15812 }
15813 close(APP);
15814 }
15815 return @Imported;
15816}
15817
15818sub readline_ELF($)
15819{
15820 if($_[0]=~/\s*\d+:\s+(\w*)\s+(\w+)\s+(\w+)\s+(\w+)\s+(\w+)\s+(\w+)\s([^\s]+)/)
15821 { # the line of 'readelf' output corresponding to the interface
15822 # symbian-style: _ZN12CCTTokenType4NewLE4TUid3RFs@@ctfinder{000a0000}[102020e5].dll
15823 my ($value, $size, $type, $bind,
15824 $vis, $Ndx, $fullname)=($1, $2, $3, $4, $5, $6, $7);
15825 if($bind!~/\A(WEAK|GLOBAL)\Z/) {
15826 return ();
15827 }
15828 if($type!~/\A(FUNC|IFUNC|OBJECT|COMMON)\Z/) {
15829 return ();
15830 }
15831 if($vis!~/\A(DEFAULT|PROTECTED)\Z/) {
15832 return ();
15833 }
15834 if($Ndx eq "ABS" and $value!~/\D|1|2|3|4|5|6|7|8|9/) {
15835 return ();
15836 }
15837 if($OStarget eq "symbian")
15838 {
15839 if($fullname=~/_\._\.absent_export_\d+/)
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015840 { # "_._.absent_export_111"@@libstdcpp{00010001}[10282872].dll
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015841 return ();
15842 }
15843 my @Elems = separate_symbol($fullname);
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015844 $fullname = $Elems[0]; # remove internal version, {00020001}[10011235].dll
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015845 }
15846 return ($fullname, $value, $Ndx, $type, $size, $bind);
15847 }
15848 else {
15849 return ();
15850 }
15851}
15852
Andrey Ponomarenko16934472012-03-29 15:37:04 +040015853sub read_symlink($)
15854{
15855 my $Path = $_[0];
15856 return "" if(not $Path);
15857 return "" if(not -f $Path and not -l $Path);
15858 if(defined $Cache{"read_symlink"}{$Path}) {
15859 return $Cache{"read_symlink"}{$Path};
15860 }
15861 if(my $Res = readlink($Path)) {
15862 return ($Cache{"read_symlink"}{$Path} = $Res);
15863 }
15864 elsif(my $ReadlinkCmd = get_CmdPath("readlink")) {
15865 return ($Cache{"read_symlink"}{$Path} = `$ReadlinkCmd -n $Path`);
15866 }
15867 elsif(my $FileCmd = get_CmdPath("file"))
15868 {
15869 my $Info = `$FileCmd $Path`;
15870 if($Info=~/symbolic\s+link\s+to\s+['`"]*([\w\d\.\-\/\\]+)['`"]*/i) {
15871 return ($Cache{"read_symlink"}{$Path} = $1);
15872 }
15873 }
15874 return ($Cache{"read_symlink"}{$Path} = "");
15875}
15876
15877sub resolve_symlink($)
15878{
15879 my $Path = $_[0];
15880 return "" if(not $Path);
15881 return "" if(not -f $Path and not -l $Path);
15882 if(defined $Cache{"resolve_symlink"}{$Path}) {
15883 return $Cache{"resolve_symlink"}{$Path};
15884 }
15885 return $Path if(isCyclical(\@RecurSymlink, $Path));
15886 push(@RecurSymlink, $Path);
15887 if(-l $Path and my $Redirect=read_symlink($Path))
15888 {
15889 if(is_abs($Redirect))
15890 { # absolute path
15891 if($SystemRoot and $SystemRoot ne "/"
15892 and $Path=~/\A\Q$SystemRoot\E\//
15893 and (-f $SystemRoot.$Redirect or -l $SystemRoot.$Redirect))
15894 { # symbolic links from the sysroot
15895 # should be corrected to point to
15896 # the files inside sysroot
15897 $Redirect = $SystemRoot.$Redirect;
15898 }
15899 my $Res = resolve_symlink($Redirect);
15900 pop(@RecurSymlink);
15901 return ($Cache{"resolve_symlink"}{$Path} = $Res);
15902 }
15903 elsif($Redirect=~/\.\.[\/\\]/)
15904 { # relative path
15905 $Redirect = joinPath(get_dirname($Path),$Redirect);
15906 while($Redirect=~s&(/|\\)[^\/\\]+(\/|\\)\.\.(\/|\\)&$1&){};
15907 my $Res = resolve_symlink($Redirect);
15908 pop(@RecurSymlink);
15909 return ($Cache{"resolve_symlink"}{$Path} = $Res);
15910 }
15911 elsif(-f get_dirname($Path)."/".$Redirect)
15912 { # file name in the same directory
15913 my $Res = resolve_symlink(joinPath(get_dirname($Path),$Redirect));
15914 pop(@RecurSymlink);
15915 return ($Cache{"resolve_symlink"}{$Path} = $Res);
15916 }
15917 else
15918 { # broken link
15919 pop(@RecurSymlink);
15920 return ($Cache{"resolve_symlink"}{$Path} = "");
15921 }
15922 }
15923 pop(@RecurSymlink);
15924 return ($Cache{"resolve_symlink"}{$Path} = $Path);
15925}
15926
15927sub find_lib_path($$)
15928{
15929 my ($LibVersion, $DyLib) = @_;
15930 return "" if(not $DyLib or not $LibVersion);
15931 return $DyLib if(is_abs($DyLib));
15932 if(defined $Cache{"find_lib_path"}{$LibVersion}{$DyLib}) {
15933 return $Cache{"find_lib_path"}{$LibVersion}{$DyLib};
15934 }
15935 if(my @Paths = sort keys(%{$InputObject_Paths{$LibVersion}{$DyLib}})) {
15936 return ($Cache{"find_lib_path"}{$LibVersion}{$DyLib} = $Paths[0]);
15937 }
15938 elsif(my $DefaultPath = $DyLib_DefaultPath{$DyLib}) {
15939 return ($Cache{"find_lib_path"}{$LibVersion}{$DyLib} = $DefaultPath);
15940 }
15941 else
15942 {
15943 foreach my $Dir (sort keys(%DefaultLibPaths), sort keys(%{$SystemPaths{"lib"}}))
15944 { # search in default linker paths and then in all system paths
15945 if(-f $Dir."/".$DyLib) {
15946 return ($Cache{"find_lib_path"}{$LibVersion}{$DyLib} = joinPath($Dir,$DyLib));
15947 }
15948 }
15949 detectSystemObjects() if(not keys(%SystemObjects));
15950 if(my @AllObjects = keys(%{$SystemObjects{$DyLib}})) {
15951 return ($Cache{"find_lib_path"}{$LibVersion}{$DyLib} = $AllObjects[0]);
15952 }
15953 my $ShortName = parse_libname($DyLib, "name+ext", $OStarget);
15954 if($ShortName ne $DyLib
15955 and my $Path = find_lib_path($ShortName))
15956 { # FIXME: check this case
15957 return ($Cache{"find_lib_path"}{$LibVersion}{$DyLib} = $Path);
15958 }
15959 return ($Cache{"find_lib_path"}{$LibVersion}{$DyLib} = "");
15960 }
15961}
15962
15963sub readSymbols_Lib($$$$$)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015964{
15965 my ($LibVersion, $Lib_Path, $IsNeededLib, $GroupNames, $Weak) = @_;
15966 return if(not $Lib_Path or not -f $Lib_Path);
15967 my ($Lib_Dir, $Lib_Name) = separate_path(resolve_symlink($Lib_Path));
15968 return if($CheckedDyLib{$LibVersion}{$Lib_Name} and $IsNeededLib);
15969 return if(isCyclical(\@RecurLib, $Lib_Name) or $#RecurLib>=1);
15970 $CheckedDyLib{$LibVersion}{$Lib_Name} = 1;
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015971 if($CheckImpl and not $IsNeededLib) {
15972 getImplementations($LibVersion, $Lib_Path);
15973 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015974 push(@RecurLib, $Lib_Name);
15975 my (%Value_Interface, %Interface_Value, %NeededLib) = ();
15976 if(not $IsNeededLib)
15977 { # libstdc++ and libc are always used by other libs
15978 # if you test one of these libs then you not need
15979 # to find them in the system for reusing
15980 if(parse_libname($Lib_Name, "short", $OStarget) eq "libstdc++")
15981 { # libstdc++.so.6
15982 $STDCXX_TESTING = 1;
15983 }
15984 if(parse_libname($Lib_Name, "short", $OStarget) eq "libc")
15985 { # libc-2.11.3.so
15986 $GLIBC_TESTING = 1;
15987 }
15988 }
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040015989 my $DebugPath = "";
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015990 if($Debug)
15991 { # debug mode
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040015992 $DebugPath = $DEBUG_PATH{$LibVersion}."/libs/".get_filename($Lib_Path).".txt";
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015993 mkpath(get_dirname($DebugPath));
15994 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015995 if($OStarget eq "macos")
15996 { # Mac OS X: *.dylib, *.a
15997 my $OtoolCmd = get_CmdPath("otool");
15998 if(not $OtoolCmd) {
15999 exitStatus("Not_Found", "can't find \"otool\"");
16000 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040016001 $OtoolCmd .= " -TV \"".$Lib_Path."\" 2>$TMP_DIR/null";
16002 if($Debug)
16003 { # debug mode
Andrey Ponomarenko16934472012-03-29 15:37:04 +040016004 # write to file
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040016005 system($OtoolCmd." >".$DebugPath);
Andrey Ponomarenko16934472012-03-29 15:37:04 +040016006 open(LIB, $DebugPath);
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040016007 }
Andrey Ponomarenko16934472012-03-29 15:37:04 +040016008 else
16009 { # write to pipe
16010 open(LIB, $OtoolCmd." |");
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040016011 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040016012 while(<LIB>)
16013 {
16014 if(/[^_]+\s+_([\w\$]+)\s*\Z/)
16015 {
16016 my $realname = $1;
16017 if($IsNeededLib and $GroupNames
16018 and not $GroupNames->{parse_libname($Lib_Name, "name+ext", $OStarget)}) {
16019 $DepSymbols{$LibVersion}{$realname} = 1;
16020 }
16021 if(not $IsNeededLib)
16022 {
16023 $Symbol_Library{$LibVersion}{$realname} = $Lib_Name;
16024 $Library_Symbol{$LibVersion}{$Lib_Name}{$realname} = 1;
16025 if($COMMON_LANGUAGE{$LibVersion} ne "C++"
16026 and $realname=~/\A(_Z|\?)/) {
16027 setLanguage($LibVersion, "C++");
16028 }
16029 if($CheckObjectsOnly
16030 and $LibVersion==1) {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040016031 $CheckedSymbols{"Binary"}{$realname} = 1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040016032 }
16033 }
16034 }
16035 }
16036 close(LIB);
16037 if($LIB_TYPE eq "dynamic")
16038 { # dependencies
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040016039 open(LIB, "$OtoolCmd -L \"".$Lib_Path."\" 2>$TMP_DIR/null |");
16040 while(<LIB>)
16041 {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040016042 if(/\s*([\/\\].+\.$LIB_EXT)\s*/
16043 and $1 ne $Lib_Path) {
16044 $NeededLib{$1} = 1;
16045 }
16046 }
16047 close(LIB);
16048 }
16049 }
16050 elsif($OStarget eq "windows")
16051 { # Windows *.dll, *.lib
16052 my $DumpBinCmd = get_CmdPath("dumpbin");
16053 if(not $DumpBinCmd) {
16054 exitStatus("Not_Found", "can't find \"dumpbin\"");
16055 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040016056 $DumpBinCmd .= " /EXPORTS \"".$Lib_Path."\" 2>$TMP_DIR/null";
16057 if($Debug)
16058 { # debug mode
Andrey Ponomarenko16934472012-03-29 15:37:04 +040016059 # write to file
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040016060 system($DumpBinCmd." >".$DebugPath);
Andrey Ponomarenko16934472012-03-29 15:37:04 +040016061 open(LIB, $DebugPath);
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040016062 }
Andrey Ponomarenko16934472012-03-29 15:37:04 +040016063 else
16064 { # write to pipe
16065 open(LIB, $DumpBinCmd." |");
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040016066 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040016067 while(<LIB>)
16068 { # 1197 4AC 0000A620 SetThreadStackGuarantee
16069 # 1198 4AD SetThreadToken (forwarded to ...)
16070 # 3368 _o2i_ECPublicKey
16071 if(/\A\s*\d+\s+[a-f\d]+\s+[a-f\d]+\s+([\w\?\@]+)\s*\Z/i
16072 or /\A\s*\d+\s+[a-f\d]+\s+([\w\?\@]+)\s*\(\s*forwarded\s+/
16073 or /\A\s*\d+\s+_([\w\?\@]+)\s*\Z/)
16074 { # dynamic, static and forwarded symbols
16075 my $realname = $1;
16076 if($IsNeededLib and not $GroupNames->{parse_libname($Lib_Name, "name+ext", $OStarget)}) {
16077 $DepSymbols{$LibVersion}{$realname} = 1;
16078 }
16079 if(not $IsNeededLib)
16080 {
16081 $Symbol_Library{$LibVersion}{$realname} = $Lib_Name;
16082 $Library_Symbol{$LibVersion}{$Lib_Name}{$realname} = 1;
16083 if($COMMON_LANGUAGE{$LibVersion} ne "C++"
16084 and $realname=~/\A(_Z|\?)/) {
16085 setLanguage($LibVersion, "C++");
16086 }
16087 if($CheckObjectsOnly
16088 and $LibVersion==1) {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040016089 $CheckedSymbols{"Binary"}{$realname} = 1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040016090 }
16091 }
16092 }
16093 }
16094 close(LIB);
16095 if($LIB_TYPE eq "dynamic")
16096 { # dependencies
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040016097 open(LIB, "$DumpBinCmd /DEPENDENTS \"".$Lib_Path."\" 2>$TMP_DIR/null |");
16098 while(<LIB>)
16099 {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040016100 if(/\s*([^\s]+?\.$LIB_EXT)\s*/i
16101 and $1 ne $Lib_Path) {
16102 $NeededLib{path_format($1, $OSgroup)} = 1;
16103 }
16104 }
16105 close(LIB);
16106 }
16107 }
16108 else
16109 { # Unix; *.so, *.a
16110 # Symbian: *.dso, *.lib
16111 my $ReadelfCmd = get_CmdPath("readelf");
16112 if(not $ReadelfCmd) {
16113 exitStatus("Not_Found", "can't find \"readelf\"");
16114 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040016115 $ReadelfCmd .= " -WhlSsdA \"".$Lib_Path."\" 2>$TMP_DIR/null";
16116 if($Debug)
16117 { # debug mode
Andrey Ponomarenko16934472012-03-29 15:37:04 +040016118 # write to file
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040016119 system($ReadelfCmd." >".$DebugPath);
Andrey Ponomarenko16934472012-03-29 15:37:04 +040016120 open(LIB, $DebugPath);
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040016121 }
Andrey Ponomarenko16934472012-03-29 15:37:04 +040016122 else
16123 { # write to pipe
16124 open(LIB, $ReadelfCmd." |");
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040016125 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040016126 my $symtab=0; # indicates that we are processing 'symtab' section of 'readelf' output
16127 while(<LIB>)
16128 {
16129 if($LIB_TYPE eq "dynamic")
16130 { # dynamic library specifics
16131 if(/NEEDED.+\[([^\[\]]+)\]/)
16132 { # dependencies:
16133 # 0x00000001 (NEEDED) Shared library: [libc.so.6]
16134 $NeededLib{$1} = 1;
16135 next;
16136 }
16137 if(/'\.dynsym'/)
16138 { # dynamic table
16139 $symtab=0;
16140 next;
16141 }
16142 if($symtab == 1)
16143 { # do nothing with symtab
16144 next;
16145 }
16146 if(/'\.symtab'/)
16147 { # symbol table
16148 $symtab=1;
16149 next;
16150 }
16151 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040016152 if(my ($fullname, $idx, $Ndx, $type, $size, $bind) = readline_ELF($_))
16153 { # read ELF entry
16154 if( $Ndx eq "UND" )
16155 { # ignore interfaces that are imported from somewhere else
16156 next;
16157 }
16158 if($bind eq "WEAK"
16159 and $Weak eq "-Weak")
16160 { # skip WEAK symbols
16161 next;
16162 }
16163 my ($realname, $version_spec, $version) = separate_symbol($fullname);
16164 if($type eq "OBJECT")
16165 { # global data
16166 $CompleteSignature{$LibVersion}{$fullname}{"Object"} = 1;
16167 $CompleteSignature{$LibVersion}{$realname}{"Object"} = 1;
16168 }
16169 if($IsNeededLib and not $GroupNames->{parse_libname($Lib_Name, "name+ext", $OStarget)}) {
16170 $DepSymbols{$LibVersion}{$fullname} = 1;
16171 }
16172 if(not $IsNeededLib)
16173 {
16174 $Symbol_Library{$LibVersion}{$fullname} = $Lib_Name;
16175 $Library_Symbol{$LibVersion}{$Lib_Name}{$fullname} = ($type eq "OBJECT")?-$size:1;
16176 if($LIB_EXT eq "so")
16177 { # value
16178 $Interface_Value{$LibVersion}{$fullname} = $idx;
16179 $Value_Interface{$LibVersion}{$idx}{$fullname} = 1;
16180 }
16181 if($COMMON_LANGUAGE{$LibVersion} ne "C++"
16182 and $realname=~/\A(_Z|\?)/) {
16183 setLanguage($LibVersion, "C++");
16184 }
16185 if($CheckObjectsOnly
16186 and $LibVersion==1) {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040016187 $CheckedSymbols{"Binary"}{$fullname} = 1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040016188 }
16189 }
16190 }
16191 }
16192 close(LIB);
16193 }
16194 if(not $IsNeededLib and $LIB_EXT eq "so")
16195 { # get symbol versions
16196 foreach my $Symbol (keys(%{$Symbol_Library{$LibVersion}}))
16197 {
16198 next if($Symbol!~/\@/);
16199 my $Interface_SymName = "";
16200 foreach my $Symbol_SameValue (keys(%{$Value_Interface{$LibVersion}{$Interface_Value{$LibVersion}{$Symbol}}}))
16201 {
16202 if($Symbol_SameValue ne $Symbol
16203 and $Symbol_SameValue!~/\@/)
16204 {
16205 $SymVer{$LibVersion}{$Symbol_SameValue} = $Symbol;
16206 $Interface_SymName = $Symbol_SameValue;
16207 last;
16208 }
16209 }
16210 if(not $Interface_SymName)
16211 {
16212 if($Symbol=~/\A([^\@\$\?]*)[\@\$]+([^\@\$]*)\Z/
16213 and not $SymVer{$LibVersion}{$1}) {
16214 $SymVer{$LibVersion}{$1} = $Symbol;
16215 }
16216 }
16217 }
16218 }
16219 foreach my $DyLib (sort keys(%NeededLib))
16220 {
16221 my $DepPath = find_lib_path($LibVersion, $DyLib);
16222 if($DepPath and -f $DepPath) {
Andrey Ponomarenko16934472012-03-29 15:37:04 +040016223 readSymbols_Lib($LibVersion, $DepPath, 1, $GroupNames, "+Weak");
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040016224 }
16225 }
16226 pop(@RecurLib);
16227 return $Library_Symbol{$LibVersion};
16228}
16229
16230sub get_path_prefixes($)
16231{
16232 my $Path = $_[0];
16233 my ($Dir, $Name) = separate_path($Path);
16234 my %Prefixes = ();
16235 foreach my $Prefix (reverse(split(/[\/\\]+/, $Dir)))
16236 {
16237 $Prefixes{$Name} = 1;
16238 $Name = joinPath($Prefix, $Name);
16239 last if(keys(%Prefixes)>5 or $Prefix eq "include");
16240 }
16241 return keys(%Prefixes);
16242}
16243
16244sub detectSystemHeaders()
16245{
16246 my @SysHeaders = ();
16247 foreach my $DevelPath (keys(%{$SystemPaths{"include"}}))
16248 {
16249 next if(not -d $DevelPath);
16250 # search for all header files in the /usr/include
16251 # with or without extension (ncurses.h, QtCore, ...)
16252 @SysHeaders = (@SysHeaders, cmd_find($DevelPath,"f","",""));
16253 foreach my $Link (cmd_find($DevelPath,"l","",""))
16254 { # add symbolic links
16255 if(-f $Link) {
16256 push(@SysHeaders, $Link);
16257 }
16258 }
16259 }
16260 foreach my $DevelPath (keys(%{$SystemPaths{"lib"}}))
16261 {
16262 next if(not -d $DevelPath);
16263 # search for config headers in the /usr/lib
16264 @SysHeaders = (@SysHeaders, cmd_find($DevelPath,"f","*.h",""));
16265 foreach my $Dir (cmd_find($DevelPath,"d","include",""))
16266 { # search for all include directories
16267 # this is for headers that are installed to /usr/lib
16268 # Example: Qt4 headers in Mandriva (/usr/lib/qt4/include/)
16269 if($Dir=~/\/(gcc|jvm|syslinux|kdb)\//) {
16270 next;
16271 }
16272 @SysHeaders = (@SysHeaders, cmd_find($Dir,"f","",""));
16273 }
16274 }
16275 foreach my $Path (@SysHeaders)
16276 {
16277 foreach my $Part (get_path_prefixes($Path)) {
16278 $SystemHeaders{$Part}{$Path}=1;
16279 }
16280 }
16281}
16282
16283sub detectSystemObjects()
16284{
16285 foreach my $DevelPath (keys(%{$SystemPaths{"lib"}}))
16286 {
16287 next if(not -d $DevelPath);
16288 foreach my $Path (find_libs($DevelPath,"",""))
16289 { # search for shared libraries in the /usr/lib (including symbolic links)
16290 $SystemObjects{parse_libname(get_filename($Path), "name+ext", $OStarget)}{$Path}=1;
16291 }
16292 }
16293}
16294
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040016295sub getSoPaths($)
16296{
16297 my $LibVersion = $_[0];
16298 my @SoPaths = ();
16299 foreach my $Dest (split(/\s*\n\s*/, $Descriptor{$LibVersion}{"Libs"}))
16300 {
16301 if(not -e $Dest) {
16302 exitStatus("Access_Error", "can't access \'$Dest\'");
16303 }
16304 my @SoPaths_Dest = getSOPaths_Dest($Dest, $LibVersion);
16305 foreach (@SoPaths_Dest) {
16306 push(@SoPaths, $_);
16307 }
16308 }
16309 return @SoPaths;
16310}
16311
16312sub skip_lib($$)
16313{
16314 my ($Path, $LibVersion) = @_;
16315 return 1 if(not $Path or not $LibVersion);
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040016316 my $Name = get_filename($Path);
16317 if($SkipLibs{$LibVersion}{"Name"}{$Name}) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040016318 return 1;
16319 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040016320 my $ShortName = parse_libname($Name, "name+ext", $OStarget);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040016321 if($SkipLibs{$LibVersion}{"Name"}{$ShortName}) {
16322 return 1;
16323 }
16324 foreach my $Dir (keys(%{$SkipLibs{$LibVersion}{"Path"}}))
16325 {
16326 if($Path=~/\Q$Dir\E([\/\\]|\Z)/) {
16327 return 1;
16328 }
16329 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040016330 foreach my $P (keys(%{$SkipLibs{$LibVersion}{"Pattern"}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040016331 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040016332 if($Name=~/$P/) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040016333 return 1;
16334 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040016335 if($P=~/[\/\\]/ and $Path=~/$P/) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040016336 return 1;
16337 }
16338 }
16339 return 0;
16340}
16341
16342sub skip_header($$)
16343{ # returns:
16344 # 1 - if header should NOT be included and checked
16345 # 2 - if header should NOT be included, but should be checked
16346 my ($Path, $LibVersion) = @_;
16347 return 1 if(not $Path or not $LibVersion);
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040016348 my $Name = get_filename($Path);
16349 if(my $Kind = $SkipHeaders{$LibVersion}{"Name"}{$Name}) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040016350 return $Kind;
16351 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040016352 foreach my $D (keys(%{$SkipHeaders{$LibVersion}{"Path"}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040016353 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040016354 if($Path=~/\Q$D\E([\/\\]|\Z)/) {
16355 return $SkipHeaders{$LibVersion}{"Path"}{$D};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040016356 }
16357 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040016358 foreach my $P (keys(%{$SkipHeaders{$LibVersion}{"Pattern"}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040016359 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040016360 if($Name=~/$P/) {
16361 return $SkipHeaders{$LibVersion}{"Pattern"}{$P};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040016362 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040016363 if($P=~/[\/\\]/ and $Path=~/$P/) {
16364 return $SkipHeaders{$LibVersion}{"Pattern"}{$P};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040016365 }
16366 }
16367 return 0;
16368}
16369
16370sub register_objects($$)
16371{
16372 my ($Dir, $LibVersion) = @_;
16373 if($SystemPaths{"lib"}{$Dir})
16374 { # system directory
16375 return;
16376 }
16377 if($RegisteredObjDirs{$LibVersion}{$Dir})
16378 { # already registered
16379 return;
16380 }
16381 foreach my $Path (find_libs($Dir,"",1))
16382 {
16383 next if(ignore_path($Path));
16384 next if(skip_lib($Path, $LibVersion));
16385 $InputObject_Paths{$LibVersion}{get_filename($Path)}{$Path} = 1;
16386 }
16387 $RegisteredObjDirs{$LibVersion}{$Dir} = 1;
16388}
16389
16390sub getSOPaths_Dest($$)
16391{
16392 my ($Dest, $LibVersion) = @_;
16393 if(skip_lib($Dest, $LibVersion)) {
16394 return ();
16395 }
16396 if(-f $Dest)
16397 {
16398 if(not parse_libname($Dest, "name", $OStarget)) {
16399 exitStatus("Error", "incorrect format of library (should be *.$LIB_EXT): \'$Dest\'");
16400 }
16401 $InputObject_Paths{$LibVersion}{get_filename($Dest)}{$Dest} = 1;
16402 register_objects(get_dirname($Dest), $LibVersion);
16403 return ($Dest);
16404 }
16405 elsif(-d $Dest)
16406 {
16407 $Dest=~s/[\/\\]+\Z//g;
16408 my @AllObjects = ();
16409 if($SystemPaths{"lib"}{$Dest})
16410 { # you have specified /usr/lib as the search directory (<libs>) in the XML descriptor
16411 # and the real name of the library by -l option (bz2, stdc++, Xaw, ...)
16412 foreach my $Path (cmd_find($Dest,"","*".esc($TargetLibraryName)."*\.$LIB_EXT*",2))
16413 { # all files and symlinks that match the name of a library
16414 if(get_filename($Path)=~/\A(|lib)\Q$TargetLibraryName\E[\d\-]*\.$LIB_EXT[\d\.]*\Z/i)
16415 {
16416 $InputObject_Paths{$LibVersion}{get_filename($Path)}{$Path} = 1;
16417 push(@AllObjects, resolve_symlink($Path));
16418 }
16419 }
16420 }
16421 else
16422 { # search for all files and symlinks
16423 foreach my $Path (find_libs($Dest,"",""))
16424 {
16425 next if(ignore_path($Path));
16426 next if(skip_lib($Path, $LibVersion));
16427 $InputObject_Paths{$LibVersion}{get_filename($Path)}{$Path} = 1;
16428 push(@AllObjects, resolve_symlink($Path));
16429 }
16430 if($OSgroup eq "macos")
16431 { # shared libraries on MacOS X may have no extension
16432 foreach my $Path (cmd_find($Dest,"f","",""))
16433 {
16434 next if(ignore_path($Path));
16435 next if(skip_lib($Path, $LibVersion));
16436 if(get_filename($Path)!~/\./
Andrey Ponomarenko85043792012-05-14 16:48:07 +040016437 and cmd_file($Path)=~/(shared|dynamic)\s+library/i)
16438 {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040016439 $InputObject_Paths{$LibVersion}{get_filename($Path)}{$Path} = 1;
16440 push(@AllObjects, resolve_symlink($Path));
16441 }
16442 }
16443 }
16444 }
16445 return @AllObjects;
16446 }
16447 else {
16448 return ();
16449 }
16450}
16451
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040016452sub isCyclical($$)
16453{
16454 my ($Stack, $Value) = @_;
16455 return (grep {$_ eq $Value} @{$Stack});
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040016456}
16457
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040016458sub generateTemplate()
16459{
16460 writeFile("VERSION.xml", $DescriptorTemplate."\n");
16461 printMsg("INFO", "XML-descriptor template ./VERSION.xml has been generated");
16462}
16463
16464sub detectWordSize()
16465{
16466 return "" if(not $GCC_PATH);
16467 if($Cache{"detectWordSize"}) {
16468 return $Cache{"detectWordSize"};
16469 }
16470 writeFile("$TMP_DIR/empty.h", "");
16471 my $Defines = `$GCC_PATH -E -dD $TMP_DIR/empty.h`;
16472 unlink("$TMP_DIR/empty.h");
16473 my $WSize = 0;
16474 if($Defines=~/ __SIZEOF_POINTER__\s+(\d+)/)
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040016475 { # GCC 4
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040016476 $WSize = $1;
16477 }
16478 elsif($Defines=~/ __PTRDIFF_TYPE__\s+(\w+)/)
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040016479 { # GCC 3
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040016480 my $PTRDIFF = $1;
16481 if($PTRDIFF=~/long/) {
16482 $WSize = 8;
16483 }
16484 else {
16485 $WSize = 4;
16486 }
16487 }
16488 if(not int($WSize)) {
16489 exitStatus("Error", "can't check WORD size");
16490 }
16491 return ($Cache{"detectWordSize"} = $WSize);
16492}
16493
16494sub majorVersion($)
16495{
16496 my $V = $_[0];
16497 return 0 if(not $V);
16498 my @VParts = split(/\./, $V);
16499 return $VParts[0];
16500}
16501
16502sub cmpVersions($$)
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040016503{ # compare two versions in dotted-numeric format
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040016504 my ($V1, $V2) = @_;
16505 return 0 if($V1 eq $V2);
16506 return undef if($V1!~/\A\d+[\.\d+]*\Z/);
16507 return undef if($V2!~/\A\d+[\.\d+]*\Z/);
16508 my @V1Parts = split(/\./, $V1);
16509 my @V2Parts = split(/\./, $V2);
16510 for (my $i = 0; $i <= $#V1Parts && $i <= $#V2Parts; $i++) {
16511 return -1 if(int($V1Parts[$i]) < int($V2Parts[$i]));
16512 return 1 if(int($V1Parts[$i]) > int($V2Parts[$i]));
16513 }
16514 return -1 if($#V1Parts < $#V2Parts);
16515 return 1 if($#V1Parts > $#V2Parts);
16516 return 0;
16517}
16518
16519sub read_ABI_Dump($$)
16520{
16521 my ($LibVersion, $Path) = @_;
16522 return if(not $LibVersion or not -e $Path);
16523 my $FilePath = "";
16524 if($Path=~/\.abi\Z/)
16525 { # input *.abi
16526 $FilePath = $Path;
16527 }
16528 else
16529 { # input *.abi.tar.gz
16530 $FilePath = unpackDump($Path);
16531 }
16532 if($FilePath!~/\.abi\Z/) {
16533 exitStatus("Invalid_Dump", "specified ABI dump \'$Path\' is not valid, try to recreate it");
16534 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +040016535
16536 open(DUMP, $FilePath);
16537 local $/ = undef;
16538 my $Content = <DUMP>;
16539 close(DUMP);
16540
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040016541 if($Path!~/\.abi\Z/)
16542 { # remove temp file
16543 unlink($FilePath);
16544 }
16545 if($Content!~/};\s*\Z/) {
16546 exitStatus("Invalid_Dump", "specified ABI dump \'$Path\' is not valid, try to recreate it");
16547 }
16548 my $LibraryABI = eval($Content);
16549 if(not $LibraryABI) {
16550 exitStatus("Error", "internal error - eval() procedure seem to not working correctly, try to remove 'use strict' and try again");
16551 }
16552 # new dumps (>=1.22) have a personal versioning
16553 my $DumpVersion = $LibraryABI->{"ABI_DUMP_VERSION"};
16554 my $ToolVersion = $LibraryABI->{"ABI_COMPLIANCE_CHECKER_VERSION"};
16555 if(not $DumpVersion)
16556 { # old dumps (<=1.21.6) have been marked by the tool version
16557 $DumpVersion = $ToolVersion;
16558 }
16559 $UsedDump{$LibVersion}{"V"} = $DumpVersion;
16560 if(majorVersion($DumpVersion) ne majorVersion($ABI_DUMP_VERSION))
16561 { # should be compatible with dumps of the same major version
16562 if(cmpVersions($DumpVersion, $ABI_DUMP_VERSION)>0)
16563 { # Don't know how to parse future dump formats
16564 exitStatus("Dump_Version", "incompatible version $DumpVersion of specified ABI dump (newer than $ABI_DUMP_VERSION)");
16565 }
16566 elsif(cmpVersions($DumpVersion, $TOOL_VERSION)>0 and not $LibraryABI->{"ABI_DUMP_VERSION"})
16567 { # Don't know how to parse future dump formats
16568 exitStatus("Dump_Version", "incompatible version $DumpVersion of specified ABI dump (newer than $TOOL_VERSION)");
16569 }
16570 if($UseOldDumps)
16571 {
16572 if(cmpVersions($DumpVersion, $OLDEST_SUPPORTED_VERSION)<0) {
16573 exitStatus("Dump_Version", "incompatible version $DumpVersion of specified ABI dump (older than $OLDEST_SUPPORTED_VERSION)");
16574 }
16575 }
16576 else
16577 {
16578 my $Msg = "incompatible version $DumpVersion of specified ABI dump (allowed only ".majorVersion($ABI_DUMP_VERSION).".0<=V<=$ABI_DUMP_VERSION)";
16579 if(cmpVersions($DumpVersion, $OLDEST_SUPPORTED_VERSION)>=0) {
16580 $Msg .= "\nUse -old-dumps option to use old-version dumps ($OLDEST_SUPPORTED_VERSION<=V<".majorVersion($ABI_DUMP_VERSION).".0)";
16581 }
16582 exitStatus("Dump_Version", $Msg);
16583 }
16584 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040016585 if($LibraryABI->{"SrcBin"})
16586 { # default
16587 $UsedDump{$LibVersion}{"SrcBin"} = 1;
16588 }
16589 elsif($LibraryABI->{"BinOnly"})
16590 { # ABI dump created with --binary option
16591 $UsedDump{$LibVersion}{"BinOnly"} = 1;
16592 }
Andrey Ponomarenko16934472012-03-29 15:37:04 +040016593 if(defined $LibraryABI->{"Mode"}
16594 and $LibraryABI->{"Mode"} eq "Extended")
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040016595 { # --ext option
16596 $ExtendedCheck = 1;
16597 }
16598 if(my $Lang = $LibraryABI->{"Language"})
16599 {
16600 $UsedDump{$LibVersion}{"L"} = $Lang;
16601 setLanguage($LibVersion, $Lang);
16602 }
16603 $TypeInfo{$LibVersion} = $LibraryABI->{"TypeInfo"};
16604 if(not $TypeInfo{$LibVersion})
16605 { # support for old ABI dumps
16606 $TypeInfo{$LibVersion} = $LibraryABI->{"TypeDescr"};
16607 }
16608 read_Machine_DumpInfo($LibraryABI, $LibVersion);
16609 $SymbolInfo{$LibVersion} = $LibraryABI->{"SymbolInfo"};
16610 if(not $SymbolInfo{$LibVersion})
16611 { # support for old dumps
16612 $SymbolInfo{$LibVersion} = $LibraryABI->{"FuncDescr"};
16613 }
16614 if(not keys(%{$SymbolInfo{$LibVersion}}))
16615 { # validation of old-version dumps
16616 if(not $ExtendedCheck) {
16617 exitStatus("Invalid_Dump", "the input dump d$LibVersion is invalid");
16618 }
16619 }
16620 $Library_Symbol{$LibVersion} = $LibraryABI->{"Symbols"};
16621 if(not $Library_Symbol{$LibVersion})
16622 { # support for old dumps
16623 $Library_Symbol{$LibVersion} = $LibraryABI->{"Interfaces"};
16624 }
16625 $DepSymbols{$LibVersion} = $LibraryABI->{"DepSymbols"};
16626 if(not $DepSymbols{$LibVersion})
16627 { # support for old dumps
16628 $DepSymbols{$LibVersion} = $LibraryABI->{"DepInterfaces"};
16629 }
16630 if(not $DepSymbols{$LibVersion})
16631 { # support for old dumps
16632 # Cannot reconstruct DepSymbols. This may result in false
16633 # positives if the old dump is for library 2. Not a problem if
16634 # old dumps are only from old libraries.
16635 $DepSymbols{$LibVersion} = {};
16636 }
16637 $SymVer{$LibVersion} = $LibraryABI->{"SymbolVersion"};
16638 $Tid_TDid{$LibVersion} = $LibraryABI->{"Tid_TDid"};
16639 $Descriptor{$LibVersion}{"Version"} = $LibraryABI->{"LibraryVersion"};
16640 $SkipTypes{$LibVersion} = $LibraryABI->{"SkipTypes"};
16641 if(not $SkipTypes{$LibVersion})
16642 { # support for old dumps
16643 $SkipTypes{$LibVersion} = $LibraryABI->{"OpaqueTypes"};
16644 }
16645 $SkipSymbols{$LibVersion} = $LibraryABI->{"SkipSymbols"};
16646 if(not $SkipSymbols{$LibVersion})
16647 { # support for old dumps
16648 $SkipSymbols{$LibVersion} = $LibraryABI->{"SkipInterfaces"};
16649 }
16650 if(not $SkipSymbols{$LibVersion})
16651 { # support for old dumps
16652 $SkipSymbols{$LibVersion} = $LibraryABI->{"InternalInterfaces"};
16653 }
16654 $SkipNameSpaces{$LibVersion} = $LibraryABI->{"SkipNameSpaces"};
16655 $TargetHeaders{$LibVersion} = $LibraryABI->{"TargetHeaders"};
16656 foreach my $Path (keys(%{$LibraryABI->{"SkipHeaders"}}))
16657 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040016658 $SkipHeadersList{$LibVersion}{$Path} = $LibraryABI->{"SkipHeaders"}{$Path};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040016659 my ($CPath, $Type) = classifyPath($Path);
16660 $SkipHeaders{$LibVersion}{$Type}{$CPath} = $LibraryABI->{"SkipHeaders"}{$Path};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040016661 }
16662 read_Headers_DumpInfo($LibraryABI, $LibVersion);
16663 read_Libs_DumpInfo($LibraryABI, $LibVersion);
Andrey Ponomarenko85043792012-05-14 16:48:07 +040016664 if(cmpVersions($DumpVersion, "2.10.1")<0)
16665 { # support for old ABI dumps: added target headers
16666 foreach (keys(%{$Registered_Headers{$LibVersion}})) {
16667 $TargetHeaders{$LibVersion}{get_filename($_)}=1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040016668 }
16669 }
16670 $Constants{$LibVersion} = $LibraryABI->{"Constants"};
16671 $NestedNameSpaces{$LibVersion} = $LibraryABI->{"NameSpaces"};
16672 if(not $NestedNameSpaces{$LibVersion})
16673 { # support for old dumps
16674 # Cannot reconstruct NameSpaces. This may affect design
16675 # of the compatibility report.
16676 $NestedNameSpaces{$LibVersion} = {};
16677 }
16678 # target system type
16679 # needed to adopt HTML report
16680 if(not $DumpSystem)
16681 { # to use in createSymbolsList(...)
16682 $OStarget = $LibraryABI->{"Target"};
16683 }
16684 # recreate environment
16685 foreach my $Lib_Name (keys(%{$Library_Symbol{$LibVersion}}))
16686 {
16687 foreach my $Interface (keys(%{$Library_Symbol{$LibVersion}{$Lib_Name}}))
16688 {
16689 $Symbol_Library{$LibVersion}{$Interface} = $Lib_Name;
16690 if($Library_Symbol{$LibVersion}{$Lib_Name}{$Interface}<=-1)
16691 { # data marked as -size in the dump
16692 $CompleteSignature{$LibVersion}{$Interface}{"Object"} = 1;
16693 }
16694 if($COMMON_LANGUAGE{$LibVersion} ne "C++"
16695 and $Interface=~/\A(_Z|\?)/) {
16696 setLanguage($LibVersion, "C++");
16697 }
16698 }
16699 }
16700 my @VFunc = ();
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040016701 foreach my $InfoId (keys(%{$SymbolInfo{$LibVersion}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040016702 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040016703 my $MnglName = $SymbolInfo{$LibVersion}{$InfoId}{"MnglName"};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040016704 if(not $MnglName)
16705 { # C-functions
16706 next;
16707 }
16708 if(not $Symbol_Library{$LibVersion}{$MnglName}
16709 and not $DepSymbols{$LibVersion}{$MnglName}) {
16710 push(@VFunc, $MnglName);
16711 }
16712 }
16713 translateSymbols(@VFunc, $LibVersion);
16714 translateSymbols(keys(%{$Symbol_Library{$LibVersion}}), $LibVersion);
16715 translateSymbols(keys(%{$DepSymbols{$LibVersion}}), $LibVersion);
16716
Andrey Ponomarenko16934472012-03-29 15:37:04 +040016717 foreach my $TypeDeclId (sort keys(%{$TypeInfo{$LibVersion}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040016718 {
Andrey Ponomarenko16934472012-03-29 15:37:04 +040016719 foreach my $TypeId (sort keys(%{$TypeInfo{$LibVersion}{$TypeDeclId}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040016720 {
16721 if(defined $TypeInfo{$LibVersion}{$TypeDeclId}{$TypeId}{"BaseClass"})
16722 { # support for old ABI dumps < 2.0 (ACC 1.22)
16723 foreach my $BId (keys(%{$TypeInfo{$LibVersion}{$TypeDeclId}{$TypeId}{"BaseClass"}}))
16724 {
16725 if(my $Access = $TypeInfo{$LibVersion}{$TypeDeclId}{$TypeId}{"BaseClass"}{$BId})
16726 {
16727 if($Access ne "public") {
16728 $TypeInfo{$LibVersion}{$TypeDeclId}{$TypeId}{"Base"}{$BId}{"access"} = $Access;
16729 }
16730 }
16731 $TypeInfo{$LibVersion}{$TypeDeclId}{$TypeId}{"Base"}{$BId} = {};
16732 }
16733 delete($TypeInfo{$LibVersion}{$TypeDeclId}{$TypeId}{"BaseClass"});
16734 }
16735 my %TInfo = %{$TypeInfo{$LibVersion}{$TypeDeclId}{$TypeId}};
16736 if(defined $TInfo{"Base"})
16737 {
16738 foreach (keys(%{$TInfo{"Base"}})) {
16739 $Class_SubClasses{$LibVersion}{$_}{$TypeId}=1;
16740 }
16741 }
Andrey Ponomarenko16934472012-03-29 15:37:04 +040016742 if($TInfo{"Type"} eq "Typedef" and defined $TInfo{"BaseType"})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040016743 {
Andrey Ponomarenko16934472012-03-29 15:37:04 +040016744 if(my ($BTDid, $BTid) = ($TInfo{"BaseType"}{"TDid"}, $TInfo{"BaseType"}{"Tid"}))
16745 {
16746 $BTDid = "" if(not defined $BTDid);
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +040016747 if($TInfo{"Name"} eq $TypeInfo{$LibVersion}{$BTDid}{$BTid}{"Name"})
16748 { # typedef to "class Class"
16749 # should not be registered in TName_Tid
16750 next;
16751 }
Andrey Ponomarenko16934472012-03-29 15:37:04 +040016752 $Typedef_BaseName{$LibVersion}{$TInfo{"Name"}} = $TypeInfo{$LibVersion}{$BTDid}{$BTid}{"Name"};
16753 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040016754 }
16755 if(not $TName_Tid{$LibVersion}{$TInfo{"Name"}})
16756 { # classes: class (id1), typedef (artificial, id2 > id1)
16757 $TName_Tid{$LibVersion}{$TInfo{"Name"}} = $TypeId;
16758 }
16759 }
16760 }
16761
16762 $Descriptor{$LibVersion}{"Dump"} = 1;
16763}
16764
16765sub read_Machine_DumpInfo($$)
16766{
16767 my ($LibraryABI, $LibVersion) = @_;
16768 if($LibraryABI->{"Arch"}) {
16769 $CPU_ARCH{$LibVersion} = $LibraryABI->{"Arch"};
16770 }
16771 if($LibraryABI->{"WordSize"}) {
16772 $WORD_SIZE{$LibVersion} = $LibraryABI->{"WordSize"};
16773 }
16774 else
16775 { # support for old dumps
16776 $WORD_SIZE{$LibVersion} = $LibraryABI->{"SizeOfPointer"};
16777 }
16778 if(not $WORD_SIZE{$LibVersion})
16779 { # support for old dumps (<1.23)
16780 if(my $Tid = getTypeIdByName("char*", $LibVersion))
16781 { # size of char*
16782 $WORD_SIZE{$LibVersion} = get_TypeSize($Tid, $LibVersion);
16783 }
16784 else
16785 {
16786 my $PSize = 0;
16787 foreach my $TDid (keys(%{$TypeInfo{$LibVersion}}))
16788 {
16789 foreach my $Tid (keys(%{$TypeInfo{$LibVersion}{$TDid}}))
16790 {
16791 if(get_TypeAttr($Tid, $LibVersion, "Type") eq "Pointer")
16792 { # any "pointer"-type
16793 $PSize = get_TypeSize($Tid, $LibVersion);
16794 last;
16795 }
16796 }
16797 if($PSize) {
16798 last;
16799 }
16800 }
16801 if($PSize)
16802 { # a pointer type size
16803 $WORD_SIZE{$LibVersion} = $PSize;
16804 }
16805 else {
16806 printMsg("WARNING", "cannot identify a WORD size in the ABI dump (too old format)");
16807 }
16808 }
16809 }
16810 if($LibraryABI->{"GccVersion"}) {
16811 $GCC_VERSION{$LibVersion} = $LibraryABI->{"GccVersion"};
16812 }
16813}
16814
16815sub read_Libs_DumpInfo($$)
16816{
16817 my ($LibraryABI, $LibVersion) = @_;
16818 if(keys(%{$Library_Symbol{$LibVersion}})
16819 and not $DumpAPI) {
16820 $Descriptor{$LibVersion}{"Libs"} = "OK";
16821 }
16822}
16823
16824sub read_Headers_DumpInfo($$)
16825{
16826 my ($LibraryABI, $LibVersion) = @_;
16827 if(keys(%{$LibraryABI->{"Headers"}})
16828 and not $DumpAPI) {
16829 $Descriptor{$LibVersion}{"Headers"} = "OK";
16830 }
16831 foreach my $Identity (keys(%{$LibraryABI->{"Headers"}}))
16832 { # headers info is stored in the old dumps in the different way
16833 if($UseOldDumps
16834 and my $Name = $LibraryABI->{"Headers"}{$Identity}{"Name"})
16835 { # support for old dumps: headers info corrected in 1.22
16836 $Identity = $Name;
16837 }
16838 $Registered_Headers{$LibVersion}{$Identity}{"Identity"} = $Identity;
16839 }
16840}
16841
16842sub find_libs($$$)
16843{
16844 my ($Path, $Type, $MaxDepth) = @_;
16845 # FIXME: correct the search pattern
16846 return cmd_find($Path, $Type, ".*\\.$LIB_EXT\[0-9.]*", $MaxDepth);
16847}
16848
16849sub createDescriptor($$)
16850{
16851 my ($LibVersion, $Path) = @_;
16852 if(not $LibVersion or not $Path
16853 or not -e $Path) {
16854 return "";
16855 }
16856 if(-d $Path)
16857 { # directory with headers files and shared objects
16858 return "
16859 <version>
16860 ".$TargetVersion{$LibVersion}."
16861 </version>
16862
16863 <headers>
16864 $Path
16865 </headers>
16866
16867 <libs>
16868 $Path
16869 </libs>";
16870 }
16871 else
16872 { # files
16873 if($Path=~/\.xml\Z/i)
16874 { # standard XML-descriptor
16875 return readFile($Path);
16876 }
16877 elsif(is_header($Path, 2, $LibVersion))
16878 { # header file
16879 return "
16880 <version>
16881 ".$TargetVersion{$LibVersion}."
16882 </version>
16883
16884 <headers>
16885 $Path
16886 </headers>
16887
16888 <libs>
16889 none
16890 </libs>";
16891 }
16892 elsif(parse_libname($Path, "name", $OStarget))
16893 { # shared object
16894 return "
16895 <version>
16896 ".$TargetVersion{$LibVersion}."
16897 </version>
16898
16899 <headers>
16900 none
16901 </headers>
16902
16903 <libs>
16904 $Path
16905 </libs>";
16906 }
16907 else
16908 { # standard XML-descriptor
16909 return readFile($Path);
16910 }
16911 }
16912}
16913
16914sub detect_lib_default_paths()
16915{
16916 my %LPaths = ();
16917 if($OSgroup eq "bsd")
16918 {
16919 if(my $LdConfig = get_CmdPath("ldconfig")) {
16920 foreach my $Line (split(/\n/, `$LdConfig -r 2>$TMP_DIR/null`)) {
16921 if($Line=~/\A[ \t]*\d+:\-l(.+) \=\> (.+)\Z/) {
16922 $LPaths{"lib".$1} = $2;
16923 }
16924 }
16925 }
16926 else {
16927 printMsg("WARNING", "can't find ldconfig");
16928 }
16929 }
16930 else
16931 {
16932 if(my $LdConfig = get_CmdPath("ldconfig"))
16933 {
16934 if($SystemRoot and $OSgroup eq "linux")
16935 { # use host (x86) ldconfig with the target (arm) ld.so.conf
16936 if(-e $SystemRoot."/etc/ld.so.conf") {
16937 $LdConfig .= " -f ".$SystemRoot."/etc/ld.so.conf";
16938 }
16939 }
16940 foreach my $Line (split(/\n/, `$LdConfig -p 2>$TMP_DIR/null`)) {
16941 if($Line=~/\A[ \t]*([^ \t]+) .* \=\> (.+)\Z/)
16942 {
16943 my ($Name, $Path) = ($1, $2);
16944 $Path=~s/[\/]{2,}/\//;
16945 $LPaths{$Name} = $Path;
16946 }
16947 }
16948 }
16949 elsif($OSgroup=~/linux/i) {
16950 printMsg("WARNING", "can't find ldconfig");
16951 }
16952 }
16953 return \%LPaths;
16954}
16955
16956sub detect_bin_default_paths()
16957{
16958 my $EnvPaths = $ENV{"PATH"};
16959 if($OSgroup eq "beos") {
16960 $EnvPaths.=":".$ENV{"BETOOLS"};
16961 }
16962 my $Sep = ($OSgroup eq "windows")?";":":|;";
16963 foreach my $Path (sort {length($a)<=>length($b)} split(/$Sep/, $EnvPaths))
16964 {
16965 $Path = path_format($Path, $OSgroup);
16966 $Path=~s/[\/\\]+\Z//g;
16967 next if(not $Path);
16968 if($SystemRoot
16969 and $Path=~/\A\Q$SystemRoot\E\//)
16970 { # do NOT use binaries from target system
16971 next;
16972 }
16973 $DefaultBinPaths{$Path} = 1;
16974 }
16975}
16976
16977sub detect_inc_default_paths()
16978{
16979 return () if(not $GCC_PATH);
16980 my %DPaths = ("Cpp"=>{},"Gcc"=>{},"Inc"=>{});
16981 writeFile("$TMP_DIR/empty.h", "");
16982 foreach my $Line (split(/\n/, `$GCC_PATH -v -x c++ -E "$TMP_DIR/empty.h" 2>&1`))
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040016983 { # detecting GCC default include paths
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040016984 if($Line=~/\A[ \t]*((\/|\w+:\\).+)[ \t]*\Z/)
16985 {
16986 my $Path = simplify_path($1);
16987 $Path=~s/[\/\\]+\Z//g;
16988 $Path = path_format($Path, $OSgroup);
16989 if($Path=~/c\+\+|\/g\+\+\//)
16990 {
16991 $DPaths{"Cpp"}{$Path}=1;
16992 if(not defined $MAIN_CPP_DIR
16993 or get_depth($MAIN_CPP_DIR)>get_depth($Path)) {
16994 $MAIN_CPP_DIR = $Path;
16995 }
16996 }
16997 elsif($Path=~/gcc/) {
16998 $DPaths{"Gcc"}{$Path}=1;
16999 }
17000 else
17001 {
17002 next if($Path=~/local[\/\\]+include/);
17003 if($SystemRoot
17004 and $Path!~/\A\Q$SystemRoot\E(\/|\Z)/)
17005 { # The GCC include path for user headers is not a part of the system root
17006 # The reason: you are not specified the --cross-gcc option or selected a wrong compiler
17007 # or it is the internal cross-GCC path like arm-linux-gnueabi/include
17008 next;
17009 }
17010 $DPaths{"Inc"}{$Path}=1;
17011 }
17012 }
17013 }
17014 unlink("$TMP_DIR/empty.h");
17015 return %DPaths;
17016}
17017
17018sub detect_default_paths($)
17019{
17020 my ($HSearch, $LSearch, $BSearch, $GSearch) = (1, 1, 1, 1);
17021 my $Search = $_[0];
17022 if($Search!~/inc/) {
17023 $HSearch = 0;
17024 }
17025 if($Search!~/lib/) {
17026 $LSearch = 0;
17027 }
17028 if($Search!~/bin/) {
17029 $BSearch = 0;
17030 }
17031 if($Search!~/gcc/) {
17032 $GSearch = 0;
17033 }
17034 if(keys(%{$SystemPaths{"include"}}))
17035 { # <search_headers> section of the XML descriptor
17036 # do NOT search for systems headers
17037 $HSearch = 0;
17038 }
17039 if(keys(%{$SystemPaths{"lib"}}))
17040 { # <search_headers> section of the XML descriptor
17041 # do NOT search for systems headers
17042 $LSearch = 0;
17043 }
17044 foreach my $Type (keys(%{$OS_AddPath{$OSgroup}}))
17045 { # additional search paths
17046 next if($Type eq "include" and not $HSearch);
17047 next if($Type eq "lib" and not $LSearch);
17048 next if($Type eq "bin" and not $BSearch);
17049 foreach my $Path (keys(%{$OS_AddPath{$OSgroup}{$Type}}))
17050 {
17051 next if(not -d $Path);
17052 $SystemPaths{$Type}{$Path} = $OS_AddPath{$OSgroup}{$Type}{$Path};
17053 }
17054 }
17055 if($OSgroup ne "windows")
17056 { # unix-like
17057 foreach my $Type ("include", "lib", "bin")
17058 { # automatic detection of system "devel" directories
17059 next if($Type eq "include" and not $HSearch);
17060 next if($Type eq "lib" and not $LSearch);
17061 next if($Type eq "bin" and not $BSearch);
17062 my ($UsrDir, $RootDir) = ("/usr", "/");
17063 if($SystemRoot and $Type ne "bin")
17064 { # 1. search for target headers and libraries
17065 # 2. use host commands: ldconfig, readelf, etc.
17066 ($UsrDir, $RootDir) = ("$SystemRoot/usr", $SystemRoot);
17067 }
17068 foreach my $Path (cmd_find($RootDir,"d","*$Type*",1)) {
17069 $SystemPaths{$Type}{$Path} = 1;
17070 }
17071 if(-d $RootDir."/".$Type)
17072 { # if "/lib" is symbolic link
17073 if($RootDir eq "/") {
17074 $SystemPaths{$Type}{"/".$Type} = 1;
17075 }
17076 else {
17077 $SystemPaths{$Type}{$RootDir."/".$Type} = 1;
17078 }
17079 }
17080 if(-d $UsrDir) {
17081 foreach my $Path (cmd_find($UsrDir,"d","*$Type*",1)) {
17082 $SystemPaths{$Type}{$Path} = 1;
17083 }
17084 if(-d $UsrDir."/".$Type)
17085 { # if "/usr/lib" is symbolic link
17086 $SystemPaths{$Type}{$UsrDir."/".$Type} = 1;
17087 }
17088 }
17089 }
17090 }
17091 if($BSearch)
17092 {
17093 detect_bin_default_paths();
17094 foreach my $Path (keys(%DefaultBinPaths)) {
17095 $SystemPaths{"bin"}{$Path} = $DefaultBinPaths{$Path};
17096 }
17097 }
17098 # check environment variables
17099 if($OSgroup eq "beos")
17100 {
17101 foreach (keys(%{$SystemPaths{"bin"}}))
17102 {
17103 if($_ eq ".") {
17104 next;
17105 }
17106 foreach my $Path (cmd_find($_, "d", "bin", ""))
17107 { # search for /boot/develop/abi/x86/gcc4/tools/gcc-4.4.4-haiku-101111/bin/
17108 $SystemPaths{"bin"}{$Path} = 1;
17109 }
17110 }
17111 if($HSearch)
17112 {
17113 foreach my $Path (split(/:|;/, $ENV{"BEINCLUDES"}))
17114 {
17115 if(is_abs($Path)) {
17116 $DefaultIncPaths{$Path} = 1;
17117 }
17118 }
17119 }
17120 if($LSearch)
17121 {
17122 foreach my $Path (split(/:|;/, $ENV{"BELIBRARIES"}), split(/:|;/, $ENV{"LIBRARY_PATH"}))
17123 {
17124 if(is_abs($Path)) {
17125 $DefaultLibPaths{$Path} = 1;
17126 }
17127 }
17128 }
17129 }
17130 if($LSearch)
17131 { # using linker to get system paths
17132 if(my $LPaths = detect_lib_default_paths())
17133 { # unix-like
17134 foreach my $Name (keys(%{$LPaths}))
17135 {
17136 if($SystemRoot
17137 and $LPaths->{$Name}!~/\A\Q$SystemRoot\E\//)
17138 { # wrong ldconfig configuration
17139 # check your <sysroot>/etc/ld.so.conf
17140 next;
17141 }
17142 $DyLib_DefaultPath{$Name} = $LPaths->{$Name};
17143 $DefaultLibPaths{get_dirname($LPaths->{$Name})} = 1;
17144 }
17145 }
17146 foreach my $Path (keys(%DefaultLibPaths)) {
17147 $SystemPaths{"lib"}{$Path} = $DefaultLibPaths{$Path};
17148 }
17149 }
17150 if($BSearch)
17151 {
17152 if($CrossGcc)
17153 { # --cross-gcc=arm-linux-gcc
17154 if(-e $CrossGcc)
17155 { # absolute or relative path
17156 $GCC_PATH = get_abs_path($CrossGcc);
17157 }
17158 elsif($CrossGcc!~/\// and get_CmdPath($CrossGcc))
17159 { # command name
17160 $GCC_PATH = $CrossGcc;
17161 }
17162 else {
17163 exitStatus("Access_Error", "can't access \'$CrossGcc\'");
17164 }
17165 if($GCC_PATH=~/\s/) {
17166 $GCC_PATH = "\"".$GCC_PATH."\"";
17167 }
17168 }
17169 }
17170 if($GSearch)
17171 { # GCC path and default include dirs
17172 if(not $CrossGcc) {
17173 $GCC_PATH = get_CmdPath("gcc");
17174 }
17175 if(not $GCC_PATH) {
17176 exitStatus("Not_Found", "can't find GCC>=3.0 in PATH");
17177 }
17178 if(not $CheckObjectsOnly_Opt)
17179 {
17180 if(my $GCC_Ver = get_dumpversion($GCC_PATH))
17181 {
17182 my $GccTarget = get_dumpmachine($GCC_PATH);
17183 printMsg("INFO", "Using GCC $GCC_Ver ($GccTarget)");
17184 if($GccTarget=~/symbian/)
17185 {
17186 $OStarget = "symbian";
17187 $LIB_EXT = $OS_LibExt{$LIB_TYPE}{$OStarget};
17188 }
17189 }
17190 else {
17191 exitStatus("Error", "something is going wrong with the GCC compiler");
17192 }
17193 }
17194 if(not $NoStdInc)
17195 { # do NOT search in GCC standard paths
17196 my %DPaths = detect_inc_default_paths();
17197 %DefaultCppPaths = %{$DPaths{"Cpp"}};
17198 %DefaultGccPaths = %{$DPaths{"Gcc"}};
17199 %DefaultIncPaths = %{$DPaths{"Inc"}};
17200 foreach my $Path (keys(%DefaultIncPaths)) {
17201 $SystemPaths{"include"}{$Path} = $DefaultIncPaths{$Path};
17202 }
17203 }
17204 }
17205 if($HSearch)
17206 { # user include paths
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040017207 my $IncPath = "/usr/include";
17208 if($SystemRoot) {
17209 $IncPath = $SystemRoot.$IncPath;
17210 }
17211 if(-d $IncPath) {
17212 $UserIncPath{$IncPath}=1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017213 }
17214 }
17215}
17216
17217sub getLIB_EXT($)
17218{
17219 my $Target = $_[0];
17220 if(my $Ext = $OS_LibExt{$LIB_TYPE}{$Target}) {
17221 return $Ext;
17222 }
17223 return $OS_LibExt{$LIB_TYPE}{"default"};
17224}
17225
17226sub getAR_EXT($)
17227{
17228 my $Target = $_[0];
17229 if(my $Ext = $OS_Archive{$Target}) {
17230 return $Ext;
17231 }
17232 return $OS_Archive{"default"};
17233}
17234
17235sub get_dumpversion($)
17236{
17237 my $Cmd = $_[0];
17238 return "" if(not $Cmd);
17239 if($Cache{"get_dumpversion"}{$Cmd}) {
17240 return $Cache{"get_dumpversion"}{$Cmd};
17241 }
17242 my $V = `$Cmd -dumpversion 2>$TMP_DIR/null`;
17243 chomp($V);
17244 return ($Cache{"get_dumpversion"}{$Cmd} = $V);
17245}
17246
17247sub get_dumpmachine($)
17248{
17249 my $Cmd = $_[0];
17250 return "" if(not $Cmd);
17251 if($Cache{"get_dumpmachine"}{$Cmd}) {
17252 return $Cache{"get_dumpmachine"}{$Cmd};
17253 }
17254 my $Machine = `$Cmd -dumpmachine 2>$TMP_DIR/null`;
17255 chomp($Machine);
17256 return ($Cache{"get_dumpmachine"}{$Cmd} = $Machine);
17257}
17258
17259sub check_command($)
17260{
17261 my $Cmd = $_[0];
17262 return "" if(not $Cmd);
17263 my @Options = (
17264 "--version",
17265 "-help"
17266 );
17267 foreach my $Opt (@Options)
17268 {
17269 my $Info = `$Cmd $Opt 2>$TMP_DIR/null`;
17270 if($Info) {
17271 return 1;
17272 }
17273 }
17274 return 0;
17275}
17276
17277sub check_gcc_version($$)
17278{
17279 my ($Cmd, $Req_V) = @_;
17280 return 0 if(not $Cmd or not $Req_V);
17281 my $Gcc_V = get_dumpversion($Cmd);
17282 $Gcc_V=~s/(-|_)[a-z_]+.*\Z//; # remove suffix (like "-haiku-100818")
17283 if(cmpVersions($Gcc_V, $Req_V)>=0) {
17284 return $Cmd;
17285 }
17286 return "";
17287}
17288
17289sub get_depth($)
17290{
17291 if(defined $Cache{"get_depth"}{$_[0]}) {
17292 return $Cache{"get_depth"}{$_[0]}
17293 }
17294 return ($Cache{"get_depth"}{$_[0]} = ($_[0]=~tr![\/\\]|\:\:!!));
17295}
17296
17297sub find_gcc_cxx_headers($)
17298{
17299 my $LibVersion = $_[0];
17300 return if($Cache{"find_gcc_cxx_headers"});# this function should be called once
17301 # detecting system header paths
17302 foreach my $Path (sort {get_depth($b) <=> get_depth($a)} keys(%DefaultGccPaths))
17303 {
17304 foreach my $HeaderPath (sort {get_depth($a) <=> get_depth($b)} cmd_find($Path,"f","",""))
17305 {
17306 my $FileName = get_filename($HeaderPath);
17307 next if($DefaultGccHeader{$FileName});
17308 $DefaultGccHeader{$FileName} = $HeaderPath;
17309 }
17310 }
17311 if($COMMON_LANGUAGE{$LibVersion} eq "C++" and not $STDCXX_TESTING)
17312 {
17313 foreach my $CppDir (sort {get_depth($b)<=>get_depth($a)} keys(%DefaultCppPaths))
17314 {
17315 my @AllCppHeaders = cmd_find($CppDir,"f","","");
17316 foreach my $Path (sort {get_depth($a)<=>get_depth($b)} @AllCppHeaders)
17317 {
17318 my $FileName = get_filename($Path);
17319 next if($DefaultCppHeader{$FileName});
17320 $DefaultCppHeader{$FileName} = $Path;
17321 }
17322 }
17323 }
17324 $Cache{"find_gcc_cxx_headers"} = 1;
17325}
17326
17327sub parse_libname($$$)
17328{
17329 my ($Name, $Type, $Target) = @_;
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040017330 if(not $Name) {
17331 return "";
17332 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017333 if($Target eq "symbian") {
17334 return parse_libname_symbian($Name, $Type);
17335 }
17336 elsif($Target eq "windows") {
17337 return parse_libname_windows($Name, $Type);
17338 }
17339 my $Ext = getLIB_EXT($Target);
17340 if($Name=~/((((lib|).+?)([\-\_][\d\-\.\_]+|))\.$Ext)(\.(.+)|)\Z/)
17341 { # libSDL-1.2.so.0.7.1
17342 # libwbxml2.so.0.0.18
17343 if($Type eq "name")
17344 { # libSDL-1.2
17345 # libwbxml2
17346 return $2;
17347 }
17348 elsif($Type eq "name+ext")
17349 { # libSDL-1.2.so
17350 # libwbxml2.so
17351 return $1;
17352 }
17353 elsif($Type eq "version")
17354 {
17355 if($7 ne "")
17356 { # 0.7.1
17357 return $7;
17358 }
17359 else
17360 { # libc-2.5.so (=>2.5 version)
17361 my $MV = $5;
17362 $MV=~s/\A[\-\_]+//g;
17363 return $MV;
17364 }
17365 }
17366 elsif($Type eq "short")
17367 { # libSDL
17368 # libwbxml2
17369 return $3;
17370 }
17371 elsif($Type eq "shortest")
17372 { # SDL
17373 # wbxml
17374 return shortest_name($3);
17375 }
17376 }
17377 return "";# error
17378}
17379
17380sub parse_libname_symbian($$)
17381{
17382 my ($Name, $Type) = @_;
17383 my $Ext = getLIB_EXT("symbian");
17384 if($Name=~/(((.+?)(\{.+\}|))\.$Ext)\Z/)
17385 { # libpthread{00010001}.dso
17386 if($Type eq "name")
17387 { # libpthread{00010001}
17388 return $2;
17389 }
17390 elsif($Type eq "name+ext")
17391 { # libpthread{00010001}.dso
17392 return $1;
17393 }
17394 elsif($Type eq "version")
17395 { # 00010001
17396 my $V = $4;
17397 $V=~s/\{(.+)\}/$1/;
17398 return $V;
17399 }
17400 elsif($Type eq "short")
17401 { # libpthread
17402 return $3;
17403 }
17404 elsif($Type eq "shortest")
17405 { # pthread
17406 return shortest_name($3);
17407 }
17408 }
17409 return "";# error
17410}
17411
17412sub parse_libname_windows($$)
17413{
17414 my ($Name, $Type) = @_;
17415 my $Ext = getLIB_EXT("windows");
17416 if($Name=~/((.+?)\.$Ext)\Z/)
17417 { # netapi32.dll
17418 if($Type eq "name")
17419 { # netapi32
17420 return $2;
17421 }
17422 elsif($Type eq "name+ext")
17423 { # netapi32.dll
17424 return $1;
17425 }
17426 elsif($Type eq "version")
17427 { # DLL version embedded
17428 # at binary-level
17429 return "";
17430 }
17431 elsif($Type eq "short")
17432 { # netapi32
17433 return $2;
17434 }
17435 elsif($Type eq "shortest")
17436 { # netapi
17437 return shortest_name($2);
17438 }
17439 }
17440 return "";# error
17441}
17442
17443sub shortest_name($)
17444{
17445 my $Name = $_[0];
17446 # remove prefix
17447 $Name=~s/\A(lib|open)//;
17448 # remove suffix
17449 $Name=~s/[\W\d_]+\Z//i;
17450 $Name=~s/([a-z]{2,})(lib)\Z/$1/i;
17451 return $Name;
17452}
17453
17454sub getPrefix($)
17455{
17456 my $Str = $_[0];
17457 if($Str=~/\A(Get|get|Set|set)([A-Z]|_)/)
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040017458 { # GetError
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017459 return "";
17460 }
17461 if($Str=~/\A([_]*[A-Z][a-z]{1,5})[A-Z]/)
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040017462 { # XmuValidArea: Xmu
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017463 return $1;
17464 }
17465 elsif($Str=~/\A([_]*[a-z]+)[A-Z]/)
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040017466 { # snfReadFont: snf
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017467 return $1;
17468 }
17469 elsif($Str=~/\A([_]*[A-Z]{2,})[A-Z][a-z]+([A-Z][a-z]+|\Z)/)
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040017470 { # XRRTimes: XRR
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017471 return $1;
17472 }
17473 elsif($Str=~/\A([_]*[a-z0-9]{2,}_)[a-z]+/i)
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040017474 { # alarm_event_add: alarm_
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017475 return $1;
17476 }
17477 elsif($Str=~/\A(([a-z])\2{1,})/i)
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040017478 { # ffopen
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017479 return $1;
17480 }
17481 else {
17482 return "";
17483 }
17484}
17485
17486sub problem_title($)
17487{
17488 if($_[0]==1) {
17489 return "1 problem";
17490 }
17491 else {
17492 return $_[0]." problems";
17493 }
17494}
17495
17496sub warning_title($)
17497{
17498 if($_[0]==1) {
17499 return "1 warning";
17500 }
17501 else {
17502 return $_[0]." warnings";
17503 }
17504}
17505
17506sub createSymbolsList($$$$$)
17507{
17508 my ($DPath, $SaveTo, $LName, $LVersion, $ArchName) = @_;
17509 read_ABI_Dump(1, $DPath);
17510 if(not $CheckObjectsOnly) {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040017511 prepareSymbols(1);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017512 }
17513 my %SymbolHeaderLib = ();
17514 my $Total = 0;
17515 # Get List
17516 foreach my $Symbol (sort keys(%{$CompleteSignature{1}}))
17517 {
17518 if(not link_symbol($Symbol, 1, "-Deps"))
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040017519 { # skip src only and all external functions
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017520 next;
17521 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040017522 if(not symbolFilter($Symbol, 1, "Public", "Binary"))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017523 { # skip other symbols
17524 next;
17525 }
17526 my $HeaderName = $CompleteSignature{1}{$Symbol}{"Header"};
17527 if(not $HeaderName)
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040017528 { # skip src only and all external functions
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017529 next;
17530 }
17531 my $DyLib = $Symbol_Library{1}{$Symbol};
17532 if(not $DyLib)
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040017533 { # skip src only and all external functions
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017534 next;
17535 }
17536 $SymbolHeaderLib{$HeaderName}{$DyLib}{$Symbol} = 1;
17537 $Total+=1;
17538 }
17539 # Draw List
17540 my $SYMBOLS_LIST = "<h1>Public symbols in <span style='color:Blue;'>$LName</span> (<span style='color:Red;'>$LVersion</span>)";
17541 $SYMBOLS_LIST .= " on <span style='color:Blue;'>".showArch($ArchName)."</span><br/>Total: $Total</h1><br/>";
17542 foreach my $HeaderName (sort {lc($a) cmp lc($b)} keys(%SymbolHeaderLib))
17543 {
17544 foreach my $DyLib (sort {lc($a) cmp lc($b)} keys(%{$SymbolHeaderLib{$HeaderName}}))
17545 {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017546 my %NS_Symbol = ();
17547 foreach my $Symbol (keys(%{$SymbolHeaderLib{$HeaderName}{$DyLib}})) {
17548 $NS_Symbol{get_IntNameSpace($Symbol, 1)}{$Symbol} = 1;
17549 }
17550 foreach my $NameSpace (sort keys(%NS_Symbol))
17551 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040017552 $SYMBOLS_LIST .= getTitle($HeaderName, $DyLib, $NameSpace);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017553 my @SortedInterfaces = sort {lc(get_Signature($a, 1)) cmp lc(get_Signature($b, 1))} keys(%{$NS_Symbol{$NameSpace}});
17554 foreach my $Symbol (@SortedInterfaces)
17555 {
17556 my $SubReport = "";
17557 my $Signature = get_Signature($Symbol, 1);
17558 if($NameSpace) {
17559 $Signature=~s/(\W|\A)\Q$NameSpace\E\:\:(\w)/$1$2/g;
17560 }
17561 if($Symbol=~/\A(_Z|\?)/)
17562 {
17563 if($Signature) {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040017564 $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 +040017565 }# report_added
17566 else {
17567 $SubReport = "<span class='iname'>".$Symbol."</span><br/>\n";
17568 }
17569 }
17570 else
17571 {
17572 if($Signature) {
17573 $SubReport = "<span class='iname'>".highLight_Signature_Italic_Color($Signature)."</span><br/>\n";
17574 }
17575 else {
17576 $SubReport = "<span class='iname'>".$Symbol."</span><br/>\n";
17577 }
17578 }
17579 $SYMBOLS_LIST .= $SubReport;
17580 }
17581 }
17582 $SYMBOLS_LIST .= "<br/>\n";
17583 }
17584 }
17585 # Clear Info
17586 (%TypeInfo, %SymbolInfo, %Library_Symbol,
17587 %DepSymbols, %SymVer, %Tid_TDid, %SkipTypes,
17588 %SkipSymbols, %NestedNameSpaces, %ClassMethods,
Andrey Ponomarenko16934472012-03-29 15:37:04 +040017589 %AllocableClass, %ClassNames, %CompleteSignature,
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017590 %SkipNameSpaces, %Symbol_Library) = ();
17591 ($Content_Counter, $ContentID) = (0, 0);
17592 # Print Report
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040017593 my $CssStyles = readModule("Styles", "SymbolsList.css");
17594 my $JScripts = readModule("Scripts", "Sections.js");
17595 $SYMBOLS_LIST = "<a name='Top'></a>".$SYMBOLS_LIST.$TOP_REF."<br/>\n";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017596 my $Title = "$LName: public symbols";
17597 my $Keywords = "$LName, API, symbols";
17598 my $Description = "List of symbols in $LName ($LVersion) on ".showArch($ArchName);
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040017599 $SYMBOLS_LIST = composeHTML_Head($Title, $Keywords, $Description, $CssStyles, $JScripts)."
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017600 <body><div>\n$SYMBOLS_LIST</div>
17601 <br/><br/><hr/>\n".getReportFooter($LName)."
17602 <div style='height:999px;'></div></body></html>";
17603 writeFile($SaveTo, $SYMBOLS_LIST);
17604}
17605
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040017606sub readModule($$)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017607{
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040017608 my ($Module, $Name) = @_;
17609 my $Path = $MODULES_DIR."/Internals/$Module/".$Name;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017610 if(not -f $Path) {
17611 exitStatus("Module_Error", "can't access \'$Path\'");
17612 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040017613 return readFile($Path);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017614}
17615
17616sub is_target_lib($)
17617{
17618 my $LName = $_[0];
17619 if($TargetLibraryName
17620 and $LName!~/\Q$TargetLibraryName\E/) {
17621 return 0;
17622 }
17623 if(keys(%TargetLibs)
17624 and not $TargetLibs{$LName}
17625 and not $TargetLibs{parse_libname($LName, "name+ext", $OStarget)}) {
17626 return 0;
17627 }
17628 return 1;
17629}
17630
Andrey Ponomarenko85043792012-05-14 16:48:07 +040017631sub is_target_header($$)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017632{ # --header, --headers-list
Andrey Ponomarenko85043792012-05-14 16:48:07 +040017633 my ($H, $V) = @_;
17634 if(keys(%{$TargetHeaders{$V}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017635 {
Andrey Ponomarenko85043792012-05-14 16:48:07 +040017636 if($TargetHeaders{$V}{$H}) {
17637 return 1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017638 }
17639 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +040017640 return 0;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017641}
17642
17643sub checkVersionNum($$)
17644{
17645 my ($LibVersion, $Path) = @_;
17646 if(my $VerNum = $TargetVersion{$LibVersion}) {
17647 return $VerNum;
17648 }
17649 my $UsedAltDescr = 0;
17650 foreach my $Part (split(/\s*,\s*/, $Path))
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040017651 { # try to get version string from file path
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017652 next if($Part=~/\.xml\Z/i);
17653 next if(isDump($Part));
17654 if(parse_libname($Part, "version", $OStarget)
17655 or is_header($Part, 2, $LibVersion) or -d $Part)
17656 {
17657 $UsedAltDescr = 1;
17658 if(my $VerNum = readStringVersion($Part))
17659 {
17660 $TargetVersion{$LibVersion} = $VerNum;
17661 if($DumpAPI) {
17662 printMsg("WARNING", "setting version number to $VerNum (use -vnum <num> option to change it)");
17663 }
17664 else {
17665 printMsg("WARNING", "setting ".($LibVersion==1?"1st":"2nd")." version number to \"$VerNum\" (use -v$LibVersion <num> option to change it)");
17666 }
17667 return $TargetVersion{$LibVersion};
17668 }
17669 }
17670 }
17671 if($UsedAltDescr)
17672 {
17673 if($DumpAPI) {
17674 exitStatus("Error", "version number is not set (use -vnum <num> option)");
17675 }
17676 else {
17677 exitStatus("Error", ($LibVersion==1?"1st":"2nd")." version number is not set (use -v$LibVersion <num> option)");
17678 }
17679 }
17680}
17681
17682sub readStringVersion($)
17683{
17684 my $Str = $_[0];
17685 return "" if(not $Str);
17686 $Str=~s/\Q$TargetLibraryName\E//g;
17687 if($Str=~/(\/|\\|\w|\A)[\-\_]*(\d+[\d\.\-]+\d+|\d+)/)
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040017688 { # .../libssh-0.4.0/...
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017689 return $2;
17690 }
17691 elsif(my $V = parse_libname($Str, "version", $OStarget)) {
17692 return $V;
17693 }
17694 return "";
17695}
17696
17697sub readLibs($)
17698{
17699 my $LibVersion = $_[0];
17700 if($OStarget eq "windows")
17701 { # dumpbin.exe will crash
17702 # without VS Environment
17703 check_win32_env();
17704 }
Andrey Ponomarenko16934472012-03-29 15:37:04 +040017705 readSymbols($LibVersion);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017706 translateSymbols(keys(%{$Symbol_Library{$LibVersion}}), $LibVersion);
17707 translateSymbols(keys(%{$DepSymbols{$LibVersion}}), $LibVersion);
17708}
17709
17710sub dump_sorting($)
17711{
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +040017712 my $Hash = $_[0];
17713 return [] if(not $Hash);
17714 my @Keys = keys(%{$Hash});
17715 return [] if($#Keys<0);
17716 if($Keys[0]=~/\A\d+\Z/)
17717 { # numbers
17718 return [sort {int($a)<=>int($b)} @Keys];
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017719 }
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +040017720 else
17721 { # strings
17722 return [sort {$a cmp $b} @Keys];
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017723 }
17724}
17725
17726sub printMsg($$)
17727{
17728 my ($Type, $Msg) = @_;
17729 if($Type!~/\AINFO/) {
17730 $Msg = $Type.": ".$Msg;
17731 }
17732 if($Type!~/_C\Z/) {
17733 $Msg .= "\n";
17734 }
17735 if($Quiet)
17736 { # --quiet option
17737 appendFile($COMMON_LOG_PATH, $Msg);
17738 }
17739 else
17740 {
17741 if($Type eq "ERROR") {
17742 print STDERR $Msg;
17743 }
17744 else {
17745 print $Msg;
17746 }
17747 }
17748}
17749
17750sub exitStatus($$)
17751{
17752 my ($Code, $Msg) = @_;
17753 printMsg("ERROR", $Msg);
17754 exit($ERROR_CODE{$Code});
17755}
17756
17757sub exitReport()
17758{ # the tool has run without any errors
17759 printReport();
17760 if($COMPILE_ERRORS)
17761 { # errors in headers may add false positives/negatives
17762 exit($ERROR_CODE{"Compile_Error"});
17763 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040017764 if($BinaryOnly and $RESULT{"Binary"}{"Problems"})
17765 { # --binary
17766 exit($ERROR_CODE{"Incompatible"});
17767 }
17768 elsif($SourceOnly and $RESULT{"Source"}{"Problems"})
17769 { # --source
17770 exit($ERROR_CODE{"Incompatible"});
17771 }
17772 elsif($RESULT{"Source"}{"Problems"}
17773 or $RESULT{"Binary"}{"Problems"})
17774 { # default
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017775 exit($ERROR_CODE{"Incompatible"});
17776 }
17777 else {
17778 exit($ERROR_CODE{"Compatible"});
17779 }
17780}
17781
17782sub readRules($)
17783{
17784 my $Kind = $_[0];
17785 if(not -f $RULES_PATH{$Kind}) {
17786 exitStatus("Module_Error", "can't access \'".$RULES_PATH{$Kind}."\'");
17787 }
17788 my $Content = readFile($RULES_PATH{$Kind});
17789 while(my $Rule = parseTag(\$Content, "rule"))
17790 {
17791 my $RId = parseTag(\$Rule, "id");
17792 my @Properties = ("Severity", "Change", "Effect", "Overcome", "Kind");
17793 foreach my $Prop (@Properties) {
17794 if(my $Value = parseTag(\$Rule, lc($Prop)))
17795 {
17796 $Value=~s/\n[ ]*//;
17797 $CompatRules{$Kind}{$RId}{$Prop} = $Value;
17798 }
17799 }
17800 if($CompatRules{$Kind}{$RId}{"Kind"}=~/\A(Symbols|Parameters)\Z/) {
17801 $CompatRules{$Kind}{$RId}{"Kind"} = "Symbols";
17802 }
17803 else {
17804 $CompatRules{$Kind}{$RId}{"Kind"} = "Types";
17805 }
17806 }
17807}
17808
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040017809sub getReportPath($)
17810{
17811 my $Level = $_[0];
17812 my $Dir = "compat_reports/$TargetLibraryName/".$Descriptor{1}{"Version"}."_to_".$Descriptor{2}{"Version"};
17813 if($Level eq "Binary")
17814 {
17815 if($BinaryReportPath)
17816 { # --bin-report-path
17817 return $BinaryReportPath;
17818 }
17819 elsif($OutputReportPath)
17820 { # --report-path
17821 return $OutputReportPath;
17822 }
17823 else
17824 { # default
17825 return $Dir."/abi_compat_report.$ReportFormat";
17826 }
17827 }
17828 elsif($Level eq "Source")
17829 {
17830 if($SourceReportPath)
17831 { # --src-report-path
17832 return $SourceReportPath;
17833 }
17834 elsif($OutputReportPath)
17835 { # --report-path
17836 return $OutputReportPath;
17837 }
17838 else
17839 { # default
17840 return $Dir."/src_compat_report.$ReportFormat";
17841 }
17842 }
17843 else
17844 {
17845 if($OutputReportPath)
17846 { # --report-path
17847 return $OutputReportPath;
17848 }
17849 else
17850 { # default
17851 return $Dir."/compat_report.$ReportFormat";
17852 }
17853 }
17854}
17855
17856sub printStatMsg($)
17857{
17858 my $Level = $_[0];
17859 printMsg("INFO", "total \"$Level\" compatibility problems: ".$RESULT{$Level}{"Problems"}.", warnings: ".$RESULT{$Level}{"Warnings"});
17860}
17861
17862sub listAffected($)
17863{
17864 my $Level = $_[0];
17865 my $List = "";
17866 foreach (keys(%{$TotalAffected{$Level}}))
17867 {
17868 if($StrictCompat and $TotalAffected{$Level}{$_} eq "Low")
17869 { # skip "Low"-severity problems
17870 next;
17871 }
17872 $List .= "$_\n";
17873 }
17874 my $Dir = get_dirname(getReportPath($Level));
17875 if($Level eq "Binary") {
17876 writeFile($Dir."/abi_affected.txt", $List);
17877 }
17878 elsif($Level eq "Source") {
17879 writeFile($Dir."/src_affected.txt", $List);
17880 }
17881}
17882
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017883sub printReport()
17884{
17885 printMsg("INFO", "creating compatibility report ...");
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040017886 createReport();
17887 if($JoinReport or $DoubleReport)
17888 {
17889 if($RESULT{"Binary"}{"Problems"}
17890 or $RESULT{"Source"}{"Problems"}) {
17891 printMsg("INFO", "result: INCOMPATIBLE (Binary: ".$RESULT{"Binary"}{"Affected"}."\%, Source: ".$RESULT{"Source"}{"Affected"}."\%)");
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017892 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040017893 else {
17894 printMsg("INFO", "result: COMPATIBLE");
17895 }
17896 printStatMsg("Binary");
17897 printStatMsg("Source");
17898 if($ListAffected)
17899 { # --list-affected
17900 listAffected("Binary");
17901 listAffected("Source");
17902 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017903 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040017904 elsif($BinaryOnly)
17905 {
17906 if($RESULT{"Binary"}{"Problems"}) {
17907 printMsg("INFO", "result: INCOMPATIBLE (".$RESULT{"Binary"}{"Affected"}."\%)");
17908 }
17909 else {
17910 printMsg("INFO", "result: COMPATIBLE");
17911 }
17912 printStatMsg("Binary");
17913 if($ListAffected)
17914 { # --list-affected
17915 listAffected("Binary");
17916 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017917 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040017918 elsif($SourceOnly)
17919 {
17920 if($RESULT{"Source"}{"Problems"}) {
17921 printMsg("INFO", "result: INCOMPATIBLE (".$RESULT{"Source"}{"Affected"}."\%)");
17922 }
17923 else {
17924 printMsg("INFO", "result: COMPATIBLE");
17925 }
17926 printStatMsg("Source");
17927 if($ListAffected)
17928 { # --list-affected
17929 listAffected("Source");
17930 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017931 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040017932 if($StdOut)
17933 {
17934 if($JoinReport or not $DoubleReport)
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040017935 { # --binary or --source
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040017936 printMsg("INFO", "compatibility report has been generated to stdout");
17937 }
17938 else
17939 { # default
17940 printMsg("INFO", "compatibility reports have been generated to stdout");
17941 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017942 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040017943 else
17944 {
17945 if($JoinReport)
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040017946 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040017947 printMsg("INFO", "see detailed report:\n ".getReportPath("Join"));
17948 }
17949 elsif($DoubleReport)
17950 { # default
17951 printMsg("INFO", "see detailed reports:\n ".getReportPath("Binary")."\n ".getReportPath("Source"));
17952 }
17953 elsif($BinaryOnly)
17954 { # --binary
17955 printMsg("INFO", "see detailed report:\n ".getReportPath("Binary"));
17956 }
17957 elsif($SourceOnly)
17958 { # --source
17959 printMsg("INFO", "see detailed report:\n ".getReportPath("Source"));
17960 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017961 }
17962}
17963
17964sub check_win32_env()
17965{
17966 if(not $ENV{"DevEnvDir"}
17967 or not $ENV{"LIB"}) {
17968 exitStatus("Error", "can't start without VS environment (vsvars32.bat)");
17969 }
17970}
17971
17972sub create_ABI_Dump()
17973{
17974 if(not -e $DumpAPI) {
17975 exitStatus("Access_Error", "can't access \'$DumpAPI\'");
17976 }
17977 # check the archive utilities
17978 if($OSgroup eq "windows")
17979 { # using zip
17980 my $ZipCmd = get_CmdPath("zip");
17981 if(not $ZipCmd) {
17982 exitStatus("Not_Found", "can't find \"zip\"");
17983 }
17984 }
17985 else
17986 { # using tar and gzip
17987 my $TarCmd = get_CmdPath("tar");
17988 if(not $TarCmd) {
17989 exitStatus("Not_Found", "can't find \"tar\"");
17990 }
17991 my $GzipCmd = get_CmdPath("gzip");
17992 if(not $GzipCmd) {
17993 exitStatus("Not_Found", "can't find \"gzip\"");
17994 }
17995 }
17996 my @DParts = split(/\s*,\s*/, $DumpAPI);
17997 foreach my $Part (@DParts)
17998 {
17999 if(not -e $Part) {
18000 exitStatus("Access_Error", "can't access \'$Part\'");
18001 }
18002 }
18003 checkVersionNum(1, $DumpAPI);
18004 foreach my $Part (@DParts)
18005 {
18006 if(isDump($Part)) {
18007 read_ABI_Dump(1, $Part);
18008 }
18009 else {
18010 readDescriptor(1, createDescriptor(1, $Part));
18011 }
18012 }
18013 initLogging(1);
18014 detect_default_paths("inc|lib|bin|gcc"); # complete analysis
18015 if(not $CheckHeadersOnly) {
18016 readLibs(1);
18017 }
18018 if($CheckHeadersOnly) {
18019 setLanguage(1, "C++");
18020 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +040018021 if(not $CheckObjectsOnly) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040018022 searchForHeaders(1);
18023 }
18024 $WORD_SIZE{1} = detectWordSize();
18025 if($Descriptor{1}{"Headers"}
18026 and not $Descriptor{1}{"Dump"}) {
18027 readHeaders(1);
18028 }
18029 if($ExtendedCheck)
18030 { # --ext option
18031 addExtension(1);
18032 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +040018033 cleanDump(1);
18034 if($BinaryOnly)
18035 { # --binary
18036 removeUnused(1, "All");
18037 }
18038 else {
18039 removeUnused(1, "Derived");
18040 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040018041 if(not keys(%{$SymbolInfo{1}}))
18042 { # check if created dump is valid
18043 if(not $ExtendedCheck and not $CheckObjectsOnly)
18044 {
18045 if($CheckHeadersOnly) {
18046 exitStatus("Empty_Set", "the set of public symbols is empty");
18047 }
18048 else {
18049 exitStatus("Empty_Intersection", "the sets of public symbols in headers and libraries have empty intersection");
18050 }
18051 }
18052 }
18053 my %HeadersInfo = ();
18054 foreach my $HPath (keys(%{$Registered_Headers{1}}))
18055 { # headers info stored without paths in the dump
18056 $HeadersInfo{$Registered_Headers{1}{$HPath}{"Identity"}} = $Registered_Headers{1}{$HPath}{"Pos"};
18057 }
18058 printMsg("INFO", "creating library ABI dump ...");
18059 my %LibraryABI = (
18060 "TypeInfo" => $TypeInfo{1},
18061 "SymbolInfo" => $SymbolInfo{1},
18062 "Symbols" => $Library_Symbol{1},
18063 "DepSymbols" => $DepSymbols{1},
18064 "SymbolVersion" => $SymVer{1},
18065 "LibraryVersion" => $Descriptor{1}{"Version"},
18066 "LibraryName" => $TargetLibraryName,
18067 "Language" => $COMMON_LANGUAGE{1},
18068 "Tid_TDid" => $Tid_TDid{1},
18069 "SkipTypes" => $SkipTypes{1},
18070 "SkipSymbols" => $SkipSymbols{1},
18071 "SkipNameSpaces" => $SkipNameSpaces{1},
18072 "SkipHeaders" => $SkipHeadersList{1},
18073 "TargetHeaders" => $TargetHeaders{1},
18074 "Headers" => \%HeadersInfo,
18075 "Constants" => $Constants{1},
18076 "NameSpaces" => $NestedNameSpaces{1},
18077 "Target" => $OStarget,
18078 "Arch" => getArch(1),
18079 "WordSize" => $WORD_SIZE{1},
18080 "GccVersion" => get_dumpversion($GCC_PATH),
18081 "ABI_DUMP_VERSION" => $ABI_DUMP_VERSION,
18082 "ABI_COMPLIANCE_CHECKER_VERSION" => $TOOL_VERSION
18083 );
18084 if($ExtendedCheck)
18085 { # --ext option
18086 $LibraryABI{"Mode"} = "Extended";
18087 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040018088 if($BinaryOnly)
18089 { # --binary
18090 $LibraryABI{"BinOnly"} = 1;
18091 }
18092 else
18093 { # default
18094 $LibraryABI{"SrcBin"} = 1;
18095 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +040018096
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040018097 if($StdOut)
18098 { # --stdout option
18099 print STDOUT Dumper(\%LibraryABI);
18100 printMsg("INFO", "ABI dump has been generated to stdout");
18101 return;
18102 }
18103 else
18104 { # write to gzipped file
18105 my $DumpPath = "abi_dumps/$TargetLibraryName/".$TargetLibraryName."_".$Descriptor{1}{"Version"}.".abi.".$AR_EXT;
18106 if($OutputDumpPath)
18107 { # user defined path
18108 $DumpPath = $OutputDumpPath;
18109 }
18110 if(not $DumpPath=~s/\Q.$AR_EXT\E\Z//g) {
18111 exitStatus("Error", "the dump path (-dump-path option) should be the path to a *.$AR_EXT file");
18112 }
18113 my ($DDir, $DName) = separate_path($DumpPath);
18114 my $DPath = $TMP_DIR."/".$DName;
18115 mkpath($DDir);
Andrey Ponomarenko85043792012-05-14 16:48:07 +040018116
18117 open(DUMP, ">", $DPath) || die ("can't open file \'$DPath\': $!\n");
18118 print DUMP Dumper(\%LibraryABI);
18119 close(DUMP);
18120
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040018121 if(not -s $DPath) {
18122 exitStatus("Error", "can't create ABI dump because something is going wrong with the Data::Dumper module");
18123 }
18124 my $Pkg = createArchive($DPath, $DDir);
18125 printMsg("INFO", "library ABI has been dumped to:\n $Pkg");
18126 printMsg("INFO", "you can transfer this dump everywhere and use instead of the ".$Descriptor{1}{"Version"}." version descriptor");
18127 }
18128}
18129
18130sub quickEmptyReports()
18131{ # Quick "empty" reports
18132 # 4 times faster than merging equal dumps
18133 # NOTE: the dump contains the "LibraryVersion" attribute
18134 # if you change the version, then your dump will be different
18135 # OVERCOME: use -v1 and v2 options for comparing dumps
18136 # and don't change version in the XML descriptor (and dumps)
18137 # OVERCOME 2: separate meta info from the dumps in ACC 2.0
18138 if(-s $Descriptor{1}{"Path"} == -s $Descriptor{2}{"Path"})
18139 {
18140 my $FilePath1 = unpackDump($Descriptor{1}{"Path"});
18141 my $FilePath2 = unpackDump($Descriptor{2}{"Path"});
18142 if($FilePath1 and $FilePath2)
18143 {
Andrey Ponomarenko85043792012-05-14 16:48:07 +040018144 local $/ = undef;
18145
18146 open(DUMP1, $FilePath1);
18147 my $Content1 = <DUMP1>;
18148 close(DUMP1);
18149
18150 open(DUMP2, $FilePath2);
18151 my $Content2 = <DUMP2>;
18152 close(DUMP2);
18153
18154 if($Content1 eq $Content2)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040018155 {
Andrey Ponomarenko85043792012-05-14 16:48:07 +040018156 # clean memory
18157 undef $Content2;
18158
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040018159 # read a number of headers, libs, symbols and types
Andrey Ponomarenko85043792012-05-14 16:48:07 +040018160 my $ABIdump = eval($Content1);
18161
18162 # clean memory
18163 undef $Content1;
18164
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040018165 if(not $ABIdump) {
18166 exitStatus("Error", "internal error");
18167 }
18168 if(not $ABIdump->{"TypeInfo"})
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040018169 { # support for old dumps
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040018170 $ABIdump->{"TypeInfo"} = $ABIdump->{"TypeDescr"};
18171 }
18172 if(not $ABIdump->{"SymbolInfo"})
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040018173 { # support for old dumps
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040018174 $ABIdump->{"SymbolInfo"} = $ABIdump->{"FuncDescr"};
18175 }
18176 read_Headers_DumpInfo($ABIdump, 1);
18177 read_Libs_DumpInfo($ABIdump, 1);
18178 read_Machine_DumpInfo($ABIdump, 1);
18179 read_Machine_DumpInfo($ABIdump, 2);
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040018180
18181 %{$CheckedTypes{"Binary"}} = %{$ABIdump->{"TypeInfo"}};
18182 %{$CheckedTypes{"Source"}} = %{$ABIdump->{"TypeInfo"}};
18183
18184 %{$CheckedSymbols{"Binary"}} = %{$ABIdump->{"SymbolInfo"}};
18185 %{$CheckedSymbols{"Source"}} = %{$ABIdump->{"SymbolInfo"}};
18186
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040018187 $Descriptor{1}{"Version"} = $TargetVersion{1}?$TargetVersion{1}:$ABIdump->{"LibraryVersion"};
18188 $Descriptor{2}{"Version"} = $TargetVersion{2}?$TargetVersion{2}:$ABIdump->{"LibraryVersion"};
18189 exitReport();
18190 }
18191 }
18192 }
18193}
18194
18195sub initLogging($)
18196{
18197 my $LibVersion = $_[0];
18198 # create log directory
18199 my ($LOG_DIR, $LOG_FILE) = ("logs/$TargetLibraryName/".$Descriptor{$LibVersion}{"Version"}, "log.txt");
18200 if($OutputLogPath{$LibVersion})
18201 { # user-defined by -log-path option
18202 ($LOG_DIR, $LOG_FILE) = separate_path($OutputLogPath{$LibVersion});
18203 }
18204 if($LogMode ne "n") {
18205 mkpath($LOG_DIR);
18206 }
18207 $LOG_PATH{$LibVersion} = get_abs_path($LOG_DIR)."/".$LOG_FILE;
18208 resetLogging($LibVersion);
18209 if($Debug)
18210 { # debug directory
18211 $DEBUG_PATH{$LibVersion} = "debug/$TargetLibraryName/".$Descriptor{$LibVersion}{"Version"};
18212 rmtree($DEBUG_PATH{$LibVersion});
18213 }
18214}
18215
18216sub writeLog($$)
18217{
18218 my ($LibVersion, $Msg) = @_;
18219 if($LogMode ne "n") {
18220 appendFile($LOG_PATH{$LibVersion}, $Msg);
18221 }
18222}
18223
18224sub resetLogging($)
18225{
18226 my $LibVersion = $_[0];
18227 if($LogMode!~/a|n/)
18228 { # remove old log
18229 unlink($LOG_PATH{$LibVersion});
18230 }
18231}
18232
18233sub printErrorLog($)
18234{
18235 my $LibVersion = $_[0];
18236 if($LogMode ne "n") {
18237 printMsg("ERROR", "see log for details:\n ".$LOG_PATH{$LibVersion}."\n");
18238 }
18239}
18240
18241sub isDump($)
18242{
18243 if(get_filename($_[0])=~/\A(.+)\.abi(\Q.tar.gz\E|\Q.zip\E|)\Z/)
18244 { # returns a name of package
18245 return $1;
18246 }
18247 return 0;
18248}
18249
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040018250sub compareInit()
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040018251{
18252 # read input XML descriptors or ABI dumps
18253 if(not $Descriptor{1}{"Path"}) {
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040018254 exitStatus("Error", "-old option is not specified");
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040018255 }
18256 my @DParts1 = split(/\s*,\s*/, $Descriptor{1}{"Path"});
18257 foreach my $Part (@DParts1)
18258 {
18259 if(not -e $Part) {
18260 exitStatus("Access_Error", "can't access \'$Part\'");
18261 }
18262 }
18263 if(not $Descriptor{2}{"Path"}) {
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040018264 exitStatus("Error", "-new option is not specified");
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040018265 }
18266 my @DParts2 = split(/\s*,\s*/, $Descriptor{2}{"Path"});
18267 foreach my $Part (@DParts2)
18268 {
18269 if(not -e $Part) {
18270 exitStatus("Access_Error", "can't access \'$Part\'");
18271 }
18272 }
18273 detect_default_paths("bin"); # to extract dumps
18274 if($#DParts1==0 and $#DParts2==0
18275 and isDump($Descriptor{1}{"Path"})
18276 and isDump($Descriptor{2}{"Path"}))
18277 { # optimization: equal ABI dumps
18278 quickEmptyReports();
18279 }
18280 checkVersionNum(1, $Descriptor{1}{"Path"});
18281 checkVersionNum(2, $Descriptor{2}{"Path"});
18282 printMsg("INFO", "preparation, please wait ...");
18283 foreach my $Part (@DParts1)
18284 {
18285 if(isDump($Part)) {
18286 read_ABI_Dump(1, $Part);
18287 }
18288 else {
18289 readDescriptor(1, createDescriptor(1, $Part));
18290 }
18291 }
18292 foreach my $Part (@DParts2)
18293 {
18294 if(isDump($Part)) {
18295 read_ABI_Dump(2, $Part);
18296 }
18297 else {
18298 readDescriptor(2, createDescriptor(2, $Part));
18299 }
18300 }
18301 initLogging(1);
18302 initLogging(2);
18303 # check consistency
18304 if(not $Descriptor{1}{"Headers"}
18305 and not $Descriptor{1}{"Libs"}) {
18306 exitStatus("Error", "descriptor d1 does not contain both header files and libraries info");
18307 }
18308 if(not $Descriptor{2}{"Headers"}
18309 and not $Descriptor{2}{"Libs"}) {
18310 exitStatus("Error", "descriptor d2 does not contain both header files and libraries info");
18311 }
18312 if($Descriptor{1}{"Headers"} and not $Descriptor{1}{"Libs"}
18313 and not $Descriptor{2}{"Headers"} and $Descriptor{2}{"Libs"}) {
18314 exitStatus("Error", "can't compare headers with $SLIB_TYPE libraries");
18315 }
18316 elsif(not $Descriptor{1}{"Headers"} and $Descriptor{1}{"Libs"}
18317 and $Descriptor{2}{"Headers"} and not $Descriptor{2}{"Libs"}) {
18318 exitStatus("Error", "can't compare $SLIB_TYPE libraries with headers");
18319 }
18320 if(not $Descriptor{1}{"Headers"}) {
18321 if($CheckHeadersOnly_Opt) {
18322 exitStatus("Error", "can't find header files info in descriptor d1");
18323 }
18324 }
18325 if(not $Descriptor{2}{"Headers"}) {
18326 if($CheckHeadersOnly_Opt) {
18327 exitStatus("Error", "can't find header files info in descriptor d2");
18328 }
18329 }
18330 if(not $Descriptor{1}{"Headers"}
18331 or not $Descriptor{2}{"Headers"}) {
18332 if(not $CheckObjectsOnly_Opt) {
18333 printMsg("WARNING", "comparing $SLIB_TYPE libraries only");
18334 $CheckObjectsOnly = 1;
18335 }
18336 }
18337 if(not $Descriptor{1}{"Libs"}) {
18338 if($CheckObjectsOnly_Opt) {
18339 exitStatus("Error", "can't find $SLIB_TYPE libraries info in descriptor d1");
18340 }
18341 }
18342 if(not $Descriptor{2}{"Libs"}) {
18343 if($CheckObjectsOnly_Opt) {
18344 exitStatus("Error", "can't find $SLIB_TYPE libraries info in descriptor d2");
18345 }
18346 }
18347 if(not $Descriptor{1}{"Libs"}
18348 or not $Descriptor{2}{"Libs"})
18349 { # comparing standalone header files
18350 # comparing ABI dumps created with --headers-only
18351 if(not $CheckHeadersOnly_Opt)
18352 {
18353 printMsg("WARNING", "checking headers only");
18354 $CheckHeadersOnly = 1;
18355 }
18356 }
18357 if($UseDumps)
18358 { # --use-dumps
18359 # parallel processing
18360 my $pid = fork();
18361 if($pid)
18362 { # dump on two CPU cores
18363 my @PARAMS = ("-dump", $Descriptor{1}{"Path"}, "-l", $TargetLibraryName);
18364 if($RelativeDirectory{1}) {
18365 @PARAMS = (@PARAMS, "-relpath", $RelativeDirectory{1});
18366 }
18367 if($OutputLogPath{1}) {
18368 @PARAMS = (@PARAMS, "-log-path", $OutputLogPath{1});
18369 }
18370 if($CrossGcc) {
18371 @PARAMS = (@PARAMS, "-cross-gcc", $CrossGcc);
18372 }
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040018373 if($Quiet)
18374 {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040018375 @PARAMS = (@PARAMS, "-quiet");
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040018376 @PARAMS = (@PARAMS, "-logging-mode", "a");
18377 }
18378 elsif($LogMode and $LogMode ne "w")
18379 { # "w" is default
18380 @PARAMS = (@PARAMS, "-logging-mode", $LogMode);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040018381 }
18382 if($ExtendedCheck) {
18383 @PARAMS = (@PARAMS, "-extended");
18384 }
18385 if($UserLang) {
18386 @PARAMS = (@PARAMS, "-lang", $UserLang);
18387 }
18388 if($TargetVersion{1}) {
18389 @PARAMS = (@PARAMS, "-vnum", $TargetVersion{1});
18390 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +040018391 if($BinaryOnly) {
18392 @PARAMS = (@PARAMS, "-binary");
18393 }
18394 if($SourceOnly) {
18395 @PARAMS = (@PARAMS, "-source");
18396 }
18397 if($Debug)
18398 {
18399 @PARAMS = (@PARAMS, "-debug");
18400 printMsg("INFO", "perl $0 @PARAMS\n");
18401 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040018402 system("perl", $0, @PARAMS);
18403 if($?) {
18404 exit(1);
18405 }
18406 }
18407 else
18408 { # child
18409 my @PARAMS = ("-dump", $Descriptor{2}{"Path"}, "-l", $TargetLibraryName);
18410 if($RelativeDirectory{2}) {
18411 @PARAMS = (@PARAMS, "-relpath", $RelativeDirectory{2});
18412 }
18413 if($OutputLogPath{2}) {
18414 @PARAMS = (@PARAMS, "-log-path", $OutputLogPath{2});
18415 }
18416 if($CrossGcc) {
18417 @PARAMS = (@PARAMS, "-cross-gcc", $CrossGcc);
18418 }
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040018419 if($Quiet)
18420 {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040018421 @PARAMS = (@PARAMS, "-quiet");
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040018422 @PARAMS = (@PARAMS, "-logging-mode", "a");
18423 }
18424 elsif($LogMode and $LogMode ne "w")
18425 { # "w" is default
18426 @PARAMS = (@PARAMS, "-logging-mode", $LogMode);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040018427 }
18428 if($ExtendedCheck) {
18429 @PARAMS = (@PARAMS, "-extended");
18430 }
18431 if($UserLang) {
18432 @PARAMS = (@PARAMS, "-lang", $UserLang);
18433 }
18434 if($TargetVersion{2}) {
18435 @PARAMS = (@PARAMS, "-vnum", $TargetVersion{2});
18436 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +040018437 if($BinaryOnly) {
18438 @PARAMS = (@PARAMS, "-binary");
18439 }
18440 if($SourceOnly) {
18441 @PARAMS = (@PARAMS, "-source");
18442 }
18443 if($Debug)
18444 {
18445 @PARAMS = (@PARAMS, "-debug");
18446 printMsg("INFO", "perl $0 @PARAMS\n");
18447 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040018448 system("perl", $0, @PARAMS);
18449 if($?) {
18450 exit(1);
18451 }
18452 else {
18453 exit(0);
18454 }
18455 }
18456 waitpid($pid, 0);
18457 my @CMP_PARAMS = ("-l", $TargetLibraryName);
18458 @CMP_PARAMS = (@CMP_PARAMS, "-d1", "abi_dumps/$TargetLibraryName/".$TargetLibraryName."_".$Descriptor{1}{"Version"}.".abi.$AR_EXT");
18459 @CMP_PARAMS = (@CMP_PARAMS, "-d2", "abi_dumps/$TargetLibraryName/".$TargetLibraryName."_".$Descriptor{2}{"Version"}.".abi.$AR_EXT");
18460 if($TargetLibraryFName ne $TargetLibraryName) {
18461 @CMP_PARAMS = (@CMP_PARAMS, "-l-full", $TargetLibraryFName);
18462 }
18463 if($ShowRetVal) {
18464 @CMP_PARAMS = (@CMP_PARAMS, "-show-retval");
18465 }
18466 if($CrossGcc) {
18467 @CMP_PARAMS = (@CMP_PARAMS, "-cross-gcc", $CrossGcc);
18468 }
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040018469 if($Quiet)
18470 {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040018471 @CMP_PARAMS = (@CMP_PARAMS, "-quiet");
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040018472 @CMP_PARAMS = (@CMP_PARAMS, "-logging-mode", "a");
18473 }
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040018474 elsif($LogMode and $LogMode ne "w")
18475 { # "w" is default
18476 @CMP_PARAMS = (@CMP_PARAMS, "-logging-mode", $LogMode);
18477 }
18478 if($ReportFormat and $ReportFormat ne "html")
18479 { # HTML is default format
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040018480 @CMP_PARAMS = (@CMP_PARAMS, "-report-format", $ReportFormat);
18481 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040018482 if($OutputReportPath) {
18483 @CMP_PARAMS = (@CMP_PARAMS, "-report-path", $OutputReportPath);
18484 }
18485 if($BinaryReportPath) {
18486 @CMP_PARAMS = (@CMP_PARAMS, "-bin-report-path", $BinaryReportPath);
18487 }
18488 if($SourceReportPath) {
18489 @CMP_PARAMS = (@CMP_PARAMS, "-src-report-path", $SourceReportPath);
18490 }
18491 if($LoggingPath) {
18492 @CMP_PARAMS = (@CMP_PARAMS, "-log-path", $LoggingPath);
18493 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +040018494 if($Browse) {
18495 @CMP_PARAMS = (@CMP_PARAMS, "-browse", $Browse);
18496 }
18497 if($Debug) {
18498 printMsg("INFO", "perl $0 @CMP_PARAMS\n");
18499 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040018500 system("perl", $0, @CMP_PARAMS);
18501 exit($?>>8);
18502 }
18503 if(not $Descriptor{1}{"Dump"}
18504 or not $Descriptor{2}{"Dump"})
18505 { # need GCC toolchain to analyze
18506 # header files and libraries
18507 detect_default_paths("inc|lib|gcc");
18508 }
18509 if(not $Descriptor{1}{"Dump"})
18510 {
18511 if(not $CheckHeadersOnly) {
18512 readLibs(1);
18513 }
18514 if($CheckHeadersOnly) {
18515 setLanguage(1, "C++");
18516 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +040018517 if(not $CheckObjectsOnly) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040018518 searchForHeaders(1);
18519 }
18520 $WORD_SIZE{1} = detectWordSize();
18521 }
18522 if(not $Descriptor{2}{"Dump"})
18523 {
18524 if(not $CheckHeadersOnly) {
18525 readLibs(2);
18526 }
18527 if($CheckHeadersOnly) {
18528 setLanguage(2, "C++");
18529 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +040018530 if(not $CheckObjectsOnly) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040018531 searchForHeaders(2);
18532 }
18533 $WORD_SIZE{2} = detectWordSize();
18534 }
18535 if($WORD_SIZE{1} ne $WORD_SIZE{2})
18536 { # support for old ABI dumps
18537 # try to synch different WORD sizes
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040018538 if(not checkDumpVersion(1, "2.1"))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040018539 {
18540 $WORD_SIZE{1} = $WORD_SIZE{2};
18541 printMsg("WARNING", "set WORD size to ".$WORD_SIZE{2}." bytes");
18542 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040018543 elsif(not checkDumpVersion(2, "2.1"))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040018544 {
18545 $WORD_SIZE{2} = $WORD_SIZE{1};
18546 printMsg("WARNING", "set WORD size to ".$WORD_SIZE{1}." bytes");
18547 }
18548 }
18549 elsif(not $WORD_SIZE{1}
18550 and not $WORD_SIZE{2})
18551 { # support for old ABI dumps
18552 $WORD_SIZE{1} = 4;
18553 $WORD_SIZE{2} = 4;
18554 }
18555 if($Descriptor{1}{"Dump"})
18556 { # support for old ABI dumps
18557 prepareTypes(1);
18558 }
18559 if($Descriptor{2}{"Dump"})
18560 { # support for old ABI dumps
18561 prepareTypes(2);
18562 }
18563 if($AppPath and not keys(%{$Symbol_Library{1}})) {
18564 printMsg("WARNING", "the application ".get_filename($AppPath)." has no symbols imported from the $SLIB_TYPE libraries");
18565 }
18566 # started to process input data
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040018567 if(not $CheckObjectsOnly)
18568 {
18569 if($Descriptor{1}{"Headers"}
18570 and not $Descriptor{1}{"Dump"}) {
18571 readHeaders(1);
18572 }
18573 if($Descriptor{2}{"Headers"}
18574 and not $Descriptor{2}{"Dump"}) {
18575 readHeaders(2);
18576 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040018577 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +040018578
18579 # clean memory
18580 %SystemHeaders = ();
18581 %mangled_name_gcc = ();
18582
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040018583 prepareSymbols(1);
18584 prepareSymbols(2);
Andrey Ponomarenko16934472012-03-29 15:37:04 +040018585
Andrey Ponomarenko85043792012-05-14 16:48:07 +040018586 # clean memory
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040018587 %SymbolInfo = ();
Andrey Ponomarenko16934472012-03-29 15:37:04 +040018588
18589 # Virtual Tables
18590 registerVTable(1);
18591 registerVTable(2);
18592
18593 if(not checkDumpVersion(1, "1.22")
18594 and checkDumpVersion(2, "1.22"))
18595 { # support for old ABI dumps
18596 foreach my $ClassName (keys(%{$VirtualTable{2}}))
18597 {
18598 if($ClassName=~/</)
18599 { # templates
18600 if(not defined $VirtualTable{1}{$ClassName})
18601 { # synchronize
18602 delete($VirtualTable{2}{$ClassName});
18603 }
18604 }
18605 }
18606 }
18607
18608 registerOverriding(1);
18609 registerOverriding(2);
18610
18611 setVirtFuncPositions(1);
18612 setVirtFuncPositions(2);
18613
18614 # Other
18615 addParamNames(1);
18616 addParamNames(2);
18617
18618 detectChangedTypedefs();
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040018619}
18620
18621sub compareAPIs($)
18622{
18623 my $Level = $_[0];
18624 readRules($Level);
18625 if($Level eq "Binary") {
18626 printMsg("INFO", "comparing ABIs ...");
18627 }
18628 else {
18629 printMsg("INFO", "comparing APIs ...");
18630 }
18631 if($CheckHeadersOnly
18632 or $Level eq "Source")
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040018633 { # added/removed in headers
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040018634 detectAdded_H($Level);
18635 detectRemoved_H($Level);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040018636 }
18637 else
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040018638 { # added/removed in libs
18639 detectAdded($Level);
18640 detectRemoved($Level);
18641 }
18642 if(not $CheckObjectsOnly)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040018643 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040018644 mergeSignatures($Level);
18645 if(keys(%{$CheckedSymbols{$Level}})) {
18646 mergeConstants($Level);
18647 }
18648 }
18649 if($CheckHeadersOnly
18650 or $Level eq "Source")
18651 { # added/removed in headers
18652 mergeHeaders($Level);
18653 }
18654 else
18655 { # added/removed in libs
18656 mergeLibs($Level);
18657 if($CheckImpl
18658 and $Level eq "Binary") {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040018659 mergeImpl();
18660 }
18661 }
18662}
18663
18664sub optimize_set(@)
18665{
18666 my %Included = ();
18667 foreach my $Path (@_)
18668 {
18669 detect_header_includes($Path, 1);
18670 foreach my $Include (keys(%{$Header_Includes{1}{$Path}})) {
18671 $Included{get_filename($Include)}{$Include}=1;
18672 }
18673 }
18674 my @Res = ();
18675 foreach my $Path (@_)
18676 {
18677 my $Add = 1;
18678 foreach my $Inc (keys(%{$Included{get_filename($Path)}}))
18679 {
18680 if($Path=~/\/\Q$Inc\E\Z/)
18681 {
18682 $Add = 0;
18683 last;
18684 }
18685 }
18686 if($Add) {
18687 push(@Res, $Path);
18688 }
18689 }
18690 return @Res;
18691}
18692
18693sub writeOpts()
18694{
18695 my %Opts = (
18696 "OStarget"=>$OStarget,
18697 "Debug"=>$Debug,
18698 "Quiet"=>$Quiet,
18699 "LogMode"=>$LogMode,
18700 "CheckHeadersOnly"=>$CheckHeadersOnly,
18701
18702 "SystemRoot"=>$SystemRoot,
18703 "MODULES_DIR"=>$MODULES_DIR,
18704 "GCC_PATH"=>$GCC_PATH,
18705 "TargetSysInfo"=>$TargetSysInfo,
18706 "CrossPrefix"=>$CrossPrefix,
18707 "TargetLibraryName"=>$TargetLibraryName,
18708 "CrossGcc"=>$CrossGcc,
18709 "UseStaticLibs"=>$UseStaticLibs,
18710 "NoStdInc"=>$NoStdInc
18711 );
18712 return \%Opts;
18713}
18714
18715sub get_CoreError($)
18716{
18717 my %CODE_ERROR = reverse(%ERROR_CODE);
18718 return $CODE_ERROR{$_[0]};
18719}
18720
18721sub scenario()
18722{
18723 if($StdOut)
18724 { # enable quiet mode
18725 $Quiet = 1;
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040018726 $JoinReport = 1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040018727 }
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040018728 if(not $LogMode)
18729 { # default
18730 $LogMode = "w";
18731 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040018732 if($UserLang)
18733 { # --lang=C++
18734 $UserLang = uc($UserLang);
18735 $COMMON_LANGUAGE{1}=$UserLang;
18736 $COMMON_LANGUAGE{2}=$UserLang;
18737 }
18738 if($LoggingPath)
18739 {
18740 $OutputLogPath{1} = $LoggingPath;
18741 $OutputLogPath{2} = $LoggingPath;
18742 if($Quiet) {
18743 $COMMON_LOG_PATH = $LoggingPath;
18744 }
18745 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040018746 if($BinaryOnly and $SourceOnly)
18747 { # both --binary and --source
18748 # is the default mode
18749 $DoubleReport = 1;
18750 $JoinReport = 0;
18751 $BinaryOnly = 0;
18752 $SourceOnly = 0;
18753 if($OutputReportPath)
18754 { # --report-path
18755 $DoubleReport = 0;
18756 $JoinReport = 1;
18757 }
18758 }
18759 elsif($BinaryOnly or $SourceOnly)
18760 { # --binary or --source
18761 $DoubleReport = 0;
18762 $JoinReport = 0;
18763 }
18764 if($UseXML)
18765 { # --xml option
18766 $ReportFormat = "xml";
18767 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040018768 if($ReportFormat)
18769 { # validate
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040018770 $ReportFormat = lc($ReportFormat);
18771 if($ReportFormat!~/\A(xml|html|htm)\Z/) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040018772 exitStatus("Error", "unknown format \'$ReportFormat\'");
18773 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040018774 if($ReportFormat eq "htm")
18775 { # HTM == HTML
18776 $ReportFormat = "html";
18777 }
18778 elsif($ReportFormat eq "xml")
18779 { # --report-format=XML equal to --xml
18780 $UseXML = 1;
18781 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040018782 }
18783 else
18784 { # default: HTML
18785 $ReportFormat = "html";
18786 }
18787 if($Quiet and $LogMode!~/a|n/)
18788 { # --quiet log
18789 if(-f $COMMON_LOG_PATH) {
18790 unlink($COMMON_LOG_PATH);
18791 }
18792 }
18793 if($TestTool and $UseDumps)
18794 { # --test && --use-dumps == --test-dump
18795 $TestDump = 1;
18796 }
18797 if($Help) {
18798 HELP_MESSAGE();
18799 exit(0);
18800 }
18801 if($InfoMsg) {
18802 INFO_MESSAGE();
18803 exit(0);
18804 }
18805 if($ShowVersion) {
18806 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.");
18807 exit(0);
18808 }
18809 if($DumpVersion) {
18810 printMsg("INFO", $TOOL_VERSION);
18811 exit(0);
18812 }
18813 if($ExtendedCheck) {
18814 $CheckHeadersOnly = 1;
18815 }
18816 if($SystemRoot_Opt)
18817 { # user defined root
18818 if(not -e $SystemRoot_Opt) {
18819 exitStatus("Access_Error", "can't access \'$SystemRoot\'");
18820 }
18821 $SystemRoot = $SystemRoot_Opt;
18822 $SystemRoot=~s/[\/]+\Z//g;
18823 if($SystemRoot) {
18824 $SystemRoot = get_abs_path($SystemRoot);
18825 }
18826 }
18827 $Data::Dumper::Sortkeys = 1;
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +040018828
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040018829 # FIXME: can't pass \&dump_sorting - cause a segfault sometimes
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +040018830 # $Data::Dumper::Useperl = 1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040018831 # $Data::Dumper::Sortkeys = \&dump_sorting;
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +040018832
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040018833 if($TargetLibsPath)
18834 {
18835 if(not -f $TargetLibsPath) {
18836 exitStatus("Access_Error", "can't access file \'$TargetLibsPath\'");
18837 }
18838 foreach my $Lib (split(/\s*\n\s*/, readFile($TargetLibsPath))) {
18839 $TargetLibs{$Lib} = 1;
18840 }
18841 }
18842 if($TargetHeadersPath)
18843 { # --headers-list
18844 if(not -f $TargetHeadersPath) {
18845 exitStatus("Access_Error", "can't access file \'$TargetHeadersPath\'");
18846 }
18847 foreach my $Header (split(/\s*\n\s*/, readFile($TargetHeadersPath)))
18848 {
18849 $TargetHeaders{1}{$Header} = 1;
18850 $TargetHeaders{2}{$Header} = 1;
18851 }
18852 }
18853 if($TargetHeader)
18854 { # --header
18855 $TargetHeaders{1}{$TargetHeader} = 1;
18856 $TargetHeaders{2}{$TargetHeader} = 1;
18857 }
18858 if($TestTool
18859 or $TestDump)
18860 { # --test, --test-dump
18861 detect_default_paths("bin|gcc"); # to compile libs
18862 loadModule("RegTests");
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040018863 testTool($TestDump, $Debug, $Quiet, $ExtendedCheck,
18864 $LogMode, $ReportFormat, $LIB_EXT, $GCC_PATH, $Browse);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040018865 exit(0);
18866 }
18867 if($DumpSystem)
18868 { # --dump-system
18869 loadModule("SysCheck");
18870 if($DumpSystem=~/\.xml\Z/)
18871 { # system XML descriptor
18872 if(not -f $DumpSystem) {
18873 exitStatus("Access_Error", "can't access file \'$DumpSystem\'");
18874 }
18875 my $Ret = readSystemDescriptor(readFile($DumpSystem));
18876 foreach (@{$Ret->{"Tools"}}) {
18877 $SystemPaths{"bin"}{$_} = 1;
18878 $TargetTools{$_}=1;
18879 }
18880 if($Ret->{"CrossPrefix"}) {
18881 $CrossPrefix = $Ret->{"CrossPrefix"};
18882 }
18883 }
18884 elsif($SystemRoot_Opt)
18885 { # -sysroot "/" option
18886 # default target: /usr/lib, /usr/include
18887 # search libs: /usr/lib and /lib
18888 if(not -e $SystemRoot."/usr/lib") {
18889 exitStatus("Access_Error", "can't access '".$SystemRoot."/usr/lib'");
18890 }
18891 if(not -e $SystemRoot."/lib") {
18892 exitStatus("Access_Error", "can't access '".$SystemRoot."/lib'");
18893 }
18894 if(not -e $SystemRoot."/usr/include") {
18895 exitStatus("Access_Error", "can't access '".$SystemRoot."/usr/include'");
18896 }
18897 readSystemDescriptor("
18898 <name>
18899 $DumpSystem
18900 </name>
18901 <headers>
18902 $SystemRoot/usr/include
18903 </headers>
18904 <libs>
18905 $SystemRoot/usr/lib
18906 </libs>
18907 <search_libs>
18908 $SystemRoot/lib
18909 </search_libs>");
18910 }
18911 else {
18912 exitStatus("Error", "-sysroot <dirpath> option should be specified, usually it's \"/\"");
18913 }
18914 detect_default_paths("bin|gcc"); # to check symbols
18915 if($OStarget eq "windows")
18916 { # to run dumpbin.exe
18917 # and undname.exe
18918 check_win32_env();
18919 }
18920 dumpSystem(writeOpts());
18921 exit(0);
18922 }
18923 if($CmpSystems)
18924 { # --cmp-systems
18925 detect_default_paths("bin"); # to extract dumps
18926 loadModule("SysCheck");
18927 cmpSystems($Descriptor{1}{"Path"}, $Descriptor{2}{"Path"}, writeOpts());
18928 exit(0);
18929 }
18930 if($GenerateTemplate) {
18931 generateTemplate();
18932 exit(0);
18933 }
18934 if(not $TargetLibraryName) {
18935 exitStatus("Error", "library name is not selected (option -l <name>)");
18936 }
18937 else
18938 { # validate library name
18939 if($TargetLibraryName=~/[\*\/\\]/) {
18940 exitStatus("Error", "\"\\\", \"\/\" and \"*\" symbols are not allowed in the library name");
18941 }
18942 }
18943 if(not $TargetLibraryFName) {
18944 $TargetLibraryFName = $TargetLibraryName;
18945 }
18946 if($CheckHeadersOnly_Opt and $CheckObjectsOnly_Opt) {
18947 exitStatus("Error", "you can't specify both -headers-only and -objects-only options at the same time");
18948 }
18949 if($SymbolsListPath)
18950 {
18951 if(not -f $SymbolsListPath) {
18952 exitStatus("Access_Error", "can't access file \'$SymbolsListPath\'");
18953 }
18954 foreach my $Interface (split(/\s*\n\s*/, readFile($SymbolsListPath))) {
18955 $SymbolsList{$Interface} = 1;
18956 }
18957 }
18958 if($SkipHeadersPath)
18959 {
18960 if(not -f $SkipHeadersPath) {
18961 exitStatus("Access_Error", "can't access file \'$SkipHeadersPath\'");
18962 }
18963 foreach my $Path (split(/\s*\n\s*/, readFile($SkipHeadersPath)))
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040018964 { # register for both versions
18965 $SkipHeadersList{1}{$Path} = 1;
18966 $SkipHeadersList{2}{$Path} = 1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040018967 my ($CPath, $Type) = classifyPath($Path);
18968 $SkipHeaders{1}{$Type}{$CPath} = 1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040018969 $SkipHeaders{2}{$Type}{$CPath} = 1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040018970 }
18971 }
18972 if($ParamNamesPath)
18973 {
18974 if(not -f $ParamNamesPath) {
18975 exitStatus("Access_Error", "can't access file \'$ParamNamesPath\'");
18976 }
18977 foreach my $Line (split(/\n/, readFile($ParamNamesPath)))
18978 {
18979 if($Line=~s/\A(\w+)\;//)
18980 {
18981 my $Interface = $1;
18982 if($Line=~/;(\d+);/) {
18983 while($Line=~s/(\d+);(\w+)//) {
18984 $AddIntParams{$Interface}{$1}=$2;
18985 }
18986 }
18987 else {
18988 my $Num = 0;
18989 foreach my $Name (split(/;/, $Line)) {
18990 $AddIntParams{$Interface}{$Num++}=$Name;
18991 }
18992 }
18993 }
18994 }
18995 }
18996 if($AppPath)
18997 {
18998 if(not -f $AppPath) {
18999 exitStatus("Access_Error", "can't access file \'$AppPath\'");
19000 }
Andrey Ponomarenko16934472012-03-29 15:37:04 +040019001 foreach my $Interface (readSymbols_App($AppPath)) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040019002 $SymbolsList_App{$Interface} = 1;
19003 }
19004 }
19005 if($DumpAPI)
19006 { # --dump-abi
19007 # make an API dump
19008 create_ABI_Dump();
19009 exit($COMPILE_ERRORS);
19010 }
19011 # default: compare APIs
19012 # -d1 <path>
19013 # -d2 <path>
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040019014 compareInit();
19015 if($JoinReport or $DoubleReport)
19016 {
19017 compareAPIs("Binary");
19018 compareAPIs("Source");
19019 }
19020 elsif($BinaryOnly) {
19021 compareAPIs("Binary");
19022 }
19023 elsif($SourceOnly) {
19024 compareAPIs("Source");
19025 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040019026 exitReport();
19027}
19028
19029scenario();