blob: 48151f22c50ea9e4616668ef7eecd98ebc53849b [file] [log] [blame]
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04001#!/usr/bin/perl
2###########################################################################
Andrey Ponomarenko35c44fd2012-06-18 17:50:25 +04003# ABI Compliance Checker (ACC) 1.98.1
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 Ponomarenko35c44fd2012-06-18 17:50:25 +040058my $TOOL_VERSION = "1.98.1";
Andrey Ponomarenko5c09ef32012-06-14 18:17:33 +040059my $ABI_DUMP_VERSION = "2.17";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040060my $OLDEST_SUPPORTED_VERSION = "1.18";
61my $XML_REPORT_VERSION = "1.0";
Andrey Ponomarenko35c44fd2012-06-18 17:50:25 +040062my $XML_ABI_DUMP_VERSION = "1.1";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040063my $OSgroup = get_OSgroup();
64my $ORIG_DIR = cwd();
65my $TMP_DIR = tempdir(CLEANUP=>1);
66
67# Internal modules
68my $MODULES_DIR = get_Modules();
69push(@INC, get_dirname($MODULES_DIR));
70# Rules DB
71my %RULES_PATH = (
72 "Binary" => $MODULES_DIR."/RulesBin.xml",
73 "Source" => $MODULES_DIR."/RulesSrc.xml");
74
75my ($Help, $ShowVersion, %Descriptor, $TargetLibraryName, $GenerateTemplate,
76$TestTool, $DumpAPI, $SymbolsListPath, $CheckHeadersOnly_Opt, $UseDumps,
77$CheckObjectsOnly_Opt, $AppPath, $StrictCompat, $DumpVersion, $ParamNamesPath,
78%RelativeDirectory, $TargetLibraryFName, $TestDump, $CheckImpl, $LoggingPath,
79%TargetVersion, $InfoMsg, $UseOldDumps, %UsedDump, $CrossGcc, %OutputLogPath,
80$OutputReportPath, $OutputDumpPath, $ShowRetVal, $SystemRoot_Opt, $DumpSystem,
81$CmpSystems, $TargetLibsPath, $Debug, $CrossPrefix, $UseStaticLibs, $NoStdInc,
82$TargetComponent_Opt, $TargetSysInfo, $TargetHeader, $ExtendedCheck, $Quiet,
83$SkipHeadersPath, $Cpp2003, $LogMode, $StdOut, $ListAffected, $ReportFormat,
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040084$UserLang, $TargetHeadersPath, $BinaryOnly, $SourceOnly, $BinaryReportPath,
Andrey Ponomarenko5c09ef32012-06-14 18:17:33 +040085$SourceReportPath, $UseXML, $Browse, $OpenReport, $SortDump, $DumpFormat);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040086
87my $CmdName = get_filename($0);
88my %OS_LibExt = (
89 "dynamic" => {
90 "default"=>"so",
91 "macos"=>"dylib",
92 "windows"=>"dll",
93 "symbian"=>"dso"
94 },
95 "static" => {
96 "default"=>"a",
97 "windows"=>"lib",
98 "symbian"=>"lib"
99 }
100);
101
102my %OS_Archive = (
103 "windows"=>"zip",
104 "default"=>"tar.gz"
105);
106
107my %ERROR_CODE = (
108 # Compatible verdict
109 "Compatible"=>0,
110 "Success"=>0,
111 # Incompatible verdict
112 "Incompatible"=>1,
113 # Undifferentiated error code
114 "Error"=>2,
115 # System command is not found
116 "Not_Found"=>3,
117 # Cannot access input files
118 "Access_Error"=>4,
119 # Cannot compile header files
120 "Cannot_Compile"=>5,
121 # Header compiled with errors
122 "Compile_Error"=>6,
123 # Invalid input ABI dump
124 "Invalid_Dump"=>7,
125 # Incompatible version of ABI dump
126 "Dump_Version"=>8,
127 # Cannot find a module
128 "Module_Error"=>9,
129 # Empty intersection between
130 # headers and shared objects
131 "Empty_Intersection"=>10,
132 # Empty set of symbols in headers
133 "Empty_Set"=>11
134);
135
136my %HomePage = (
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +0400137 "Wiki"=>"http://ispras.linuxbase.org/index.php/ABI_compliance_checker",
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +0400138 "Dev1"=>"https://github.com/lvc/abi-compliance-checker",
139 "Dev2"=>"http://forge.ispras.ru/projects/abi-compliance-checker"
Andrey Ponomarenkoab282102012-03-11 11:57:02 +0400140);
141
142my $ShortUsage = "ABI Compliance Checker (ACC) $TOOL_VERSION
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +0400143A tool for checking backward compatibility of a C/C++ library API
Andrey Ponomarenkoab282102012-03-11 11:57:02 +0400144Copyright (C) 2012 ROSA Laboratory
145License: GNU LGPL or GNU GPL
146
147Usage: $CmdName [options]
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +0400148Example: $CmdName -lib NAME -old OLD.xml -new NEW.xml
Andrey Ponomarenkoab282102012-03-11 11:57:02 +0400149
150OLD.xml and NEW.xml are XML-descriptors:
151
152 <version>
153 1.0
154 </version>
155
156 <headers>
157 /path/to/headers/
158 </headers>
159
160 <libs>
161 /path/to/libraries/
162 </libs>
163
164More info: $CmdName --help\n";
165
166if($#ARGV==-1) {
167 printMsg("INFO", $ShortUsage);
168 exit(0);
169}
170
171foreach (2 .. $#ARGV)
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +0400172{ # correct comma separated options
Andrey Ponomarenkoab282102012-03-11 11:57:02 +0400173 if($ARGV[$_-1] eq ",") {
174 $ARGV[$_-2].=",".$ARGV[$_];
175 splice(@ARGV, $_-1, 2);
176 }
177 elsif($ARGV[$_-1]=~/,\Z/) {
178 $ARGV[$_-1].=$ARGV[$_];
179 splice(@ARGV, $_, 1);
180 }
181 elsif($ARGV[$_]=~/\A,/
182 and $ARGV[$_] ne ",") {
183 $ARGV[$_-1].=$ARGV[$_];
184 splice(@ARGV, $_, 1);
185 }
186}
187
188GetOptions("h|help!" => \$Help,
189 "i|info!" => \$InfoMsg,
190 "v|version!" => \$ShowVersion,
191 "dumpversion!" => \$DumpVersion,
192# general options
193 "l|lib|library=s" => \$TargetLibraryName,
194 "d1|old|o=s" => \$Descriptor{1}{"Path"},
195 "d2|new|n=s" => \$Descriptor{2}{"Path"},
196 "dump|dump-abi|dump_abi=s" => \$DumpAPI,
197 "old-dumps!" => \$UseOldDumps,
198# extra options
199 "d|descriptor-template!" => \$GenerateTemplate,
200 "app|application=s" => \$AppPath,
201 "static-libs!" => \$UseStaticLibs,
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +0400202 "cross-gcc|gcc-path=s" => \$CrossGcc,
203 "cross-prefix|gcc-prefix=s" => \$CrossPrefix,
Andrey Ponomarenkoab282102012-03-11 11:57:02 +0400204 "sysroot=s" => \$SystemRoot_Opt,
205 "v1|version1|vnum=s" => \$TargetVersion{1},
206 "v2|version2=s" => \$TargetVersion{2},
207 "s|strict!" => \$StrictCompat,
208 "symbols-list=s" => \$SymbolsListPath,
209 "skip-headers=s" => \$SkipHeadersPath,
210 "headers-only|headers_only!" => \$CheckHeadersOnly_Opt,
211 "objects-only!" => \$CheckObjectsOnly_Opt,
212 "check-impl|check-implementation!" => \$CheckImpl,
213 "show-retval!" => \$ShowRetVal,
214 "use-dumps!" => \$UseDumps,
215 "nostdinc!" => \$NoStdInc,
216 "dump-system=s" => \$DumpSystem,
217 "sysinfo=s" => \$TargetSysInfo,
218 "cmp-systems!" => \$CmpSystems,
219 "libs-list=s" => \$TargetLibsPath,
220 "headers-list=s" => \$TargetHeadersPath,
221 "header=s" => \$TargetHeader,
222 "ext|extended!" => \$ExtendedCheck,
223 "q|quiet!" => \$Quiet,
224 "stdout!" => \$StdOut,
225 "report-format=s" => \$ReportFormat,
Andrey Ponomarenko5c09ef32012-06-14 18:17:33 +0400226 "dump-format=s" => \$DumpFormat,
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +0400227 "xml!" => \$UseXML,
Andrey Ponomarenkoab282102012-03-11 11:57:02 +0400228 "lang=s" => \$UserLang,
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +0400229 "binary|bin|abi!" => \$BinaryOnly,
230 "source|src|api!" => \$SourceOnly,
Andrey Ponomarenkoab282102012-03-11 11:57:02 +0400231# other options
232 "test!" => \$TestTool,
233 "test-dump!" => \$TestDump,
234 "debug!" => \$Debug,
235 "cpp-compatible!" => \$Cpp2003,
236 "p|params=s" => \$ParamNamesPath,
237 "relpath1|relpath=s" => \$RelativeDirectory{1},
238 "relpath2=s" => \$RelativeDirectory{2},
239 "dump-path=s" => \$OutputDumpPath,
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +0400240 "sort!" => \$SortDump,
Andrey Ponomarenkoab282102012-03-11 11:57:02 +0400241 "report-path=s" => \$OutputReportPath,
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +0400242 "bin-report-path=s" => \$BinaryReportPath,
243 "src-report-path=s" => \$SourceReportPath,
Andrey Ponomarenkoab282102012-03-11 11:57:02 +0400244 "log-path=s" => \$LoggingPath,
245 "log1-path=s" => \$OutputLogPath{1},
246 "log2-path=s" => \$OutputLogPath{2},
247 "logging-mode=s" => \$LogMode,
248 "list-affected!" => \$ListAffected,
249 "l-full|lib-full=s" => \$TargetLibraryFName,
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +0400250 "component=s" => \$TargetComponent_Opt,
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +0400251 "b|browse=s" => \$Browse,
252 "open!" => \$OpenReport
Andrey Ponomarenkoab282102012-03-11 11:57:02 +0400253) or ERR_MESSAGE();
254
255sub ERR_MESSAGE()
256{
257 printMsg("INFO", "\n".$ShortUsage);
258 exit($ERROR_CODE{"Error"});
259}
260
261my $LIB_TYPE = $UseStaticLibs?"static":"dynamic";
262my $SLIB_TYPE = $LIB_TYPE;
263if($OSgroup!~/macos|windows/ and $SLIB_TYPE eq "dynamic")
264{ # show as "shared" library
265 $SLIB_TYPE = "shared";
266}
267my $LIB_EXT = getLIB_EXT($OSgroup);
268my $AR_EXT = getAR_EXT($OSgroup);
269my $BYTE_SIZE = 8;
270my $COMMON_LOG_PATH = "logs/run.log";
271
272my $HelpMessage="
273NAME:
274 ABI Compliance Checker ($CmdName)
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +0400275 Check backward compatibility of a C/C++ library API
Andrey Ponomarenkoab282102012-03-11 11:57:02 +0400276
277DESCRIPTION:
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +0400278 ABI Compliance Checker (ACC) is a tool for checking backward binary and
279 source-level compatibility of a $SLIB_TYPE C/C++ library. The tool checks
280 header files and $SLIB_TYPE libraries (*.$LIB_EXT) of old and new versions and
281 analyzes changes in API and ABI (ABI=API+compiler ABI) that may break binary
282 and/or source-level compatibility: changes in calling stack, v-table changes,
283 removed symbols, renamed fields, etc. Binary incompatibility may result in
284 crashing or incorrect behavior of applications built with an old version of
285 a library if they run on a new one. Source incompatibility may result in
286 recompilation errors with a new library version.
Andrey Ponomarenkoab282102012-03-11 11:57:02 +0400287
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +0400288 The tool is intended for developers of software libraries and maintainers
289 of operating systems who are interested in ensuring backward compatibility,
290 i.e. allow old applications to run or to be recompiled with newer library
291 versions.
292
293 Also the tool can be used by ISVs for checking applications portability to
294 new library versions. Found issues can be taken into account when adapting
295 the application to a new library version.
Andrey Ponomarenkoab282102012-03-11 11:57:02 +0400296
297 This tool is free software: you can redistribute it and/or modify it
298 under the terms of the GNU LGPL or GNU GPL.
299
300USAGE:
301 $CmdName [options]
302
303EXAMPLE:
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +0400304 $CmdName -lib NAME -old OLD.xml -new NEW.xml
Andrey Ponomarenkoab282102012-03-11 11:57:02 +0400305
306 OLD.xml and NEW.xml are XML-descriptors:
307
308 <version>
309 1.0
310 </version>
311
312 <headers>
313 /path1/to/header(s)/
314 /path2/to/header(s)/
315 ...
316 </headers>
317
318 <libs>
319 /path1/to/library(ies)/
320 /path2/to/library(ies)/
321 ...
322 </libs>
323
324INFORMATION OPTIONS:
325 -h|-help
326 Print this help.
327
328 -i|-info
329 Print complete info.
330
331 -v|-version
332 Print version information.
333
334 -dumpversion
335 Print the tool version ($TOOL_VERSION) and don't do anything else.
336
337GENERAL OPTIONS:
338 -l|-lib|-library <name>
339 Library name (without version).
340 It affects only on the path and the title of the report.
341
342 -d1|-old|-o <path>
343 Descriptor of 1st (old) library version.
344 It may be one of the following:
345
346 1. XML-descriptor (VERSION.xml file):
347
348 <version>
349 1.0
350 </version>
351
352 <headers>
353 /path1/to/header(s)/
354 /path2/to/header(s)/
355 ...
356 </headers>
357
358 <libs>
359 /path1/to/library(ies)/
360 /path2/to/library(ies)/
361 ...
362 </libs>
363
364 ... (XML-descriptor template
365 can be generated by -d option)
366
367 2. ABI dump generated by -dump option
368 3. Directory with headers and/or $SLIB_TYPE libraries
369 4. Single header file
370 5. Single $SLIB_TYPE library
371 6. Comma separated list of headers and/or libraries
372
373 If you are using an 2-6 descriptor types then you should
374 specify version numbers with -v1 <num> and -v2 <num> options too.
375
376 For more information, please see:
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +0400377 http://ispras.linuxbase.org/index.php/Library_Descriptor
Andrey Ponomarenkoab282102012-03-11 11:57:02 +0400378
379 -d2|-new|-n <path>
380 Descriptor of 2nd (new) library version.
381
382 -dump|-dump-abi <descriptor path(s)>
383 Dump library ABI to gzipped TXT format file. You can transfer it
384 anywhere and pass instead of the descriptor. Also it can be used
385 for debugging the tool. Compatible dump versions: ".majorVersion($ABI_DUMP_VERSION).".0<=V<=$ABI_DUMP_VERSION
386
387 -old-dumps
388 Enable support for old-version ABI dumps ($OLDEST_SUPPORTED_VERSION<=V<".majorVersion($ABI_DUMP_VERSION).".0).\n";
389
390sub HELP_MESSAGE() {
391 printMsg("INFO", $HelpMessage."
392MORE INFO:
393 $CmdName --info\n");
394}
395
396sub INFO_MESSAGE()
397{
398 printMsg("INFO", "$HelpMessage
399EXTRA OPTIONS:
400 -d|-descriptor-template
401 Create XML-descriptor template ./VERSION.xml
402
403 -app|-application <path>
404 This option allows to specify the application that should be checked
405 for portability to the new library version.
406
407 -static-libs
408 Check static libraries instead of the shared ones. The <libs> section
409 of the XML-descriptor should point to static libraries location.
410
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +0400411 -cross-gcc|-gcc-path <path>
Andrey Ponomarenkoab282102012-03-11 11:57:02 +0400412 Path to the cross GCC compiler to use instead of the usual (host) GCC.
413
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +0400414 -cross-prefix|-gcc-prefix <prefix>
Andrey Ponomarenkoab282102012-03-11 11:57:02 +0400415 GCC toolchain prefix.
416
417 -sysroot <dirpath>
418 Specify the alternative root directory. The tool will search for include
419 paths in the <dirpath>/usr/include and <dirpath>/usr/lib directories.
420
421 -v1|-version1 <num>
422 Specify 1st library version outside the descriptor. This option is needed
423 if you have prefered an alternative descriptor type (see -d1 option).
424
425 In general case you should specify it in the XML-descriptor:
426 <version>
427 VERSION
428 </version>
429
430 -v2|-version2 <num>
431 Specify 2nd library version outside the descriptor.
432
433 -s|-strict
434 Treat all compatibility warnings as problems. Add a number of \"Low\"
435 severity problems to the return value of the tool.
436
437 -headers-only
438 Check header files without $SLIB_TYPE libraries. It is easy to run, but may
439 provide a low quality compatibility report with false positives and
440 without detecting of added/removed symbols.
441
442 Alternatively you can write \"none\" word to the <libs> section
443 in the XML-descriptor:
444 <libs>
445 none
446 </libs>
447
448 -objects-only
449 Check $SLIB_TYPE libraries without header files. It is easy to run, but may
450 provide a low quality compatibility report with false positives and
451 without analysis of changes in parameters and data types.
452
453 Alternatively you can write \"none\" word to the <headers> section
454 in the XML-descriptor:
455 <headers>
456 none
457 </headers>
458
459 -check-impl|-check-implementation
460 Compare canonified disassembled binary code of $SLIB_TYPE libraries to
461 detect changes in the implementation. Add \'Problems with Implementation\'
462 section to the report.
463
464 -show-retval
465 Show the symbol's return type in the report.
466
467 -symbols-list <path>
468 This option allows to specify a file with a list of symbols (mangled
469 names in C++) that should be checked, other symbols will not be checked.
470
471 -skip-headers <path>
472 The file with the list of header files, that should not be checked.
473
474 -use-dumps
475 Make dumps for two versions of a library and compare dumps. This should
476 increase the performance of the tool and decrease the system memory usage.
477
478 -nostdinc
479 Do not search the GCC standard system directories for header files.
480
481 -dump-system <name> -sysroot <dirpath>
482 Find all the shared libraries and header files in <dirpath> directory,
483 create XML descriptors and make ABI dumps for each library. The result
484 set of ABI dumps can be compared (--cmp-systems) with the other one
485 created for other version of operating system in order to check them for
486 compatibility. Do not forget to specify -cross-gcc option if your target
487 system requires some specific version of GCC compiler (different from
488 the host GCC). The system ABI dump will be generated to:
489 sys_dumps/<name>/<arch>
490
491 -dump-system <descriptor.xml>
492 The same as the previous option but takes an XML descriptor of the target
493 system as input, where you should describe it:
494
495 /* Primary sections */
496
497 <name>
498 /* Name of the system */
499 </name>
500
501 <headers>
502 /* The list of paths to header files and/or
503 directories with header files, one per line */
504 </headers>
505
506 <libs>
507 /* The list of paths to shared libraries and/or
508 directories with shared libraries, one per line */
509 </libs>
510
511 /* Optional sections */
512
513 <search_headers>
514 /* List of directories to be searched
515 for header files to automatically
516 generate include paths, one per line */
517 </search_headers>
518
519 <search_libs>
520 /* List of directories to be searched
521 for shared libraries to resolve
522 dependencies, one per line */
523 </search_libs>
524
525 <tools>
526 /* List of directories with tools used
527 for analysis (GCC toolchain), one per line */
528 </tools>
529
530 <cross_prefix>
531 /* GCC toolchain prefix.
532 Examples:
533 arm-linux-gnueabi
534 arm-none-symbianelf */
535 </cross_prefix>
536
537 <gcc_options>
538 /* Additional GCC options, one per line */
539 </gcc_options>
540
541 -sysinfo <dir>
542 This option may be used with -dump-system to dump ABI of operating
543 systems and configure the dumping process.
544 Default:
545 modules/Targets/{unix, symbian, windows}
546
547 -cmp-systems -d1 sys_dumps/<name1>/<arch> -d2 sys_dumps/<name2>/<arch>
548 Compare two system ABI dumps. Create compatibility reports for each
549 library and the common HTML report including the summary of test
550 results for all checked libraries. Report will be generated to:
551 sys_compat_reports/<name1>_to_<name2>/<arch>
552
553 -libs-list <path>
554 The file with a list of libraries, that should be dumped by
555 the -dump-system option or should be checked by the -cmp-systems option.
556
557 -header <name>
558 Check/Dump ABI of this header only.
559
560 -headers-list <path>
561 The file with a list of headers, that should be checked/dumped.
562
563 -ext|-extended
564 If your library A is supposed to be used by other library B and you
565 want to control the ABI of B, then you should enable this option. The
566 tool will check for changes in all data types, even if they are not
567 used by any function in the library A. Such data types are not part
568 of the A library ABI, but may be a part of the ABI of the B library.
569
570 The short scheme is:
571 app C (broken) -> lib B (broken ABI) -> lib A (stable ABI)
572
573 -q|-quiet
574 Print all messages to the file instead of stdout and stderr.
575 Default path (can be changed by -log-path option):
576 $COMMON_LOG_PATH
577
578 -stdout
579 Print analysis results (compatibility reports and ABI dumps) to stdout
580 instead of creating a file. This would allow piping data to other programs.
581
582 -report-format <fmt>
583 Change format of compatibility report.
584 Formats:
585 htm - HTML format (default)
586 xml - XML format
587
Andrey Ponomarenko5c09ef32012-06-14 18:17:33 +0400588 -dump-format <fmt>
589 Change format of ABI dump.
590 Formats:
591 perl - Data::Dumper format (default)
592 xml - XML format
593
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +0400594 -xml
Andrey Ponomarenko5c09ef32012-06-14 18:17:33 +0400595 Alias for: --report-format=xml or --dump-format=xml
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +0400596
Andrey Ponomarenkoab282102012-03-11 11:57:02 +0400597 -lang <lang>
598 Set library language (C or C++). You can use this option if the tool
599 cannot auto-detect a language. This option may be useful for checking
600 C-library headers (--lang=C) in --headers-only or --extended modes.
601
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +0400602 -binary|-bin|-abi
603 Show \"Binary\" compatibility problems only.
604 Generate report to:
605 compat_reports/<library name>/<v1>_to_<v2>/abi_compat_report.html
606
607 -source|-src|-api
608 Show \"Source\" compatibility problems only.
609 Generate report to:
610 compat_reports/<library name>/<v1>_to_<v2>/src_compat_report.html
611
Andrey Ponomarenkoab282102012-03-11 11:57:02 +0400612OTHER OPTIONS:
613 -test
614 Run internal tests. Create two binary incompatible versions of a sample
615 library and run the tool to check them for compatibility. This option
616 allows to check if the tool works correctly in the current environment.
617
618 -test-dump
619 Test ability to create, read and compare ABI dumps.
620
621 -debug
622 Debugging mode. Print debug info on the screen. Save intermediate
623 analysis stages in the debug directory:
624 debug/<library>/<version>/
625
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +0400626 Also consider using --dump option for debugging the tool.
627
Andrey Ponomarenkoab282102012-03-11 11:57:02 +0400628 -cpp-compatible
629 If your header file is written in C language and can be compiled by
630 the C++ compiler (i.e. doesn't contain C++-keywords and other bad
631 things), then you can tell ACC about this and speedup the analysis.
632
633 -p|-params <path>
634 Path to file with the function parameter names. It can be used
635 for improving report view if the library header files have no
636 parameter names. File format:
637
638 func1;param1;param2;param3 ...
639 func2;param1;param2;param3 ...
640 ...
641
642 -relpath <path>
643 Replace {RELPATH} macros to <path> in the XML-descriptor used
644 for dumping the library ABI (see -dump option).
645
646 -relpath1 <path>
647 Replace {RELPATH} macros to <path> in the 1st XML-descriptor (-d1).
648
649 -relpath2 <path>
650 Replace {RELPATH} macros to <path> in the 2nd XML-descriptor (-d2).
651
652 -dump-path <path>
Andrey Ponomarenko5c09ef32012-06-14 18:17:33 +0400653 Specify a *.abi.$AR_EXT or *.abi file path where to generate an ABI dump.
Andrey Ponomarenkoab282102012-03-11 11:57:02 +0400654 Default:
655 abi_dumps/<library>/<library>_<version>.abi.$AR_EXT
656
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +0400657 -sort
658 Enable sorting of data in ABI dumps.
659
Andrey Ponomarenkoab282102012-03-11 11:57:02 +0400660 -report-path <path>
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +0400661 Path to compatibility report.
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +0400662 Default:
663 compat_reports/<library name>/<v1>_to_<v2>/compat_report.html
664
665 -bin-report-path <path>
666 Path to \"Binary\" compatibility report.
Andrey Ponomarenkoab282102012-03-11 11:57:02 +0400667 Default:
668 compat_reports/<library name>/<v1>_to_<v2>/abi_compat_report.html
669
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +0400670 -src-report-path <path>
671 Path to \"Source\" compatibility report.
672 Default:
673 compat_reports/<library name>/<v1>_to_<v2>/src_compat_report.html
674
Andrey Ponomarenkoab282102012-03-11 11:57:02 +0400675 -log-path <path>
676 Log path for all messages.
677 Default:
678 logs/<library>/<version>/log.txt
679
680 -log1-path <path>
681 Log path for 1st version of a library.
682 Default:
683 logs/<library name>/<v1>/log.txt
684
685 -log2-path <path>
686 Log path for 2nd version of a library.
687 Default:
688 logs/<library name>/<v2>/log.txt
689
690 -logging-mode <mode>
691 Change logging mode.
692 Modes:
693 w - overwrite old logs (default)
694 a - append old logs
695 n - do not write any logs
696
697 -list-affected
698 Generate file with the list of incompatible
699 symbols beside the HTML compatibility report.
700 Use 'c++filt \@file' command from GNU binutils
701 to unmangle C++ symbols in the generated file.
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +0400702 Default names:
Andrey Ponomarenkoab282102012-03-11 11:57:02 +0400703 abi_affected.txt
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +0400704 src_affected.txt
Andrey Ponomarenkoab282102012-03-11 11:57:02 +0400705
706 -component <name>
707 The component name in the title and summary of the HTML report.
708 Default:
709 library
710
711 -l-full|-lib-full <name>
712 Change library name in the report title to <name>. By default
713 will be displayed a name specified by -l option.
714
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +0400715 -b|-browse <program>
716 Open report(s) in the browser (firefox, opera, etc.).
717
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +0400718 -open
719 Open report(s) in the default browser.
720
Andrey Ponomarenkoab282102012-03-11 11:57:02 +0400721REPORT:
722 Compatibility report will be generated to:
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +0400723 compat_reports/<library name>/<v1>_to_<v2>/compat_report.html
Andrey Ponomarenkoab282102012-03-11 11:57:02 +0400724
725 Log will be generated to:
726 logs/<library name>/<v1>/log.txt
727 logs/<library name>/<v2>/log.txt
728
729EXIT CODES:
730 0 - Compatible. The tool has run without any errors.
731 non-zero - Incompatible or the tool has run with errors.
732
733REPORT BUGS TO:
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +0400734 Andrey Ponomarenko <aponomarenko\@rosalab.ru>
Andrey Ponomarenkoab282102012-03-11 11:57:02 +0400735
736MORE INFORMATION:
737 ".$HomePage{"Wiki"}."
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +0400738 ".$HomePage{"Dev1"}."\n");
Andrey Ponomarenkoab282102012-03-11 11:57:02 +0400739}
740
741my $DescriptorTemplate = "
742<?xml version=\"1.0\" encoding=\"utf-8\"?>
743<descriptor>
744
745/* Primary sections */
746
747<version>
748 /* Version of the library */
749</version>
750
751<headers>
752 /* The list of paths to header files and/or
753 directories with header files, one per line */
754</headers>
755
756<libs>
757 /* The list of paths to shared libraries (*.$LIB_EXT) and/or
758 directories with shared libraries, one per line */
759</libs>
760
761/* Optional sections */
762
763<include_paths>
764 /* The list of include paths that will be provided
765 to GCC to compile library headers, one per line.
766 NOTE: If you define this section then the tool
767 will not automatically generate include paths */
768</include_paths>
769
770<add_include_paths>
771 /* The list of include paths that will be added
772 to the automatically generated include paths, one per line */
773</add_include_paths>
774
775<skip_include_paths>
776 /* The list of include paths that will be removed from the
777 list of automatically generated include paths, one per line */
778</skip_include_paths>
779
780<gcc_options>
781 /* Additional GCC options, one per line */
782</gcc_options>
783
784<include_preamble>
785 /* The list of header files that will be
786 included before other headers, one per line.
787 Examples:
788 1) tree.h for libxml2
789 2) ft2build.h for freetype2 */
790</include_preamble>
791
792<defines>
793 /* The list of defines that will be added at the
794 headers compiling stage, one per line:
795 #define A B
796 #define C D */
797</defines>
798
Andrey Ponomarenkoa01311b2012-06-08 17:20:02 +0400799<add_namespaces>
800 /* The list of namespaces that should be added to the alanysis
801 if the tool cannot find them automatically, one per line */
802</add_namespaces>
803
Andrey Ponomarenkoab282102012-03-11 11:57:02 +0400804<skip_types>
805 /* The list of data types, that
806 should not be checked, one per line */
807</skip_types>
808
809<skip_symbols>
810 /* The list of functions (mangled/symbol names in C++),
811 that should not be checked, one per line */
812</skip_symbols>
813
814<skip_namespaces>
815 /* The list of C++ namespaces, that
816 should not be checked, one per line */
817</skip_namespaces>
818
819<skip_constants>
820 /* The list of constants that should
821 not be checked, one name per line */
822</skip_constants>
823
824<skip_headers>
825 /* The list of header files and/or directories
826 with header files that should not be checked, one per line */
827</skip_headers>
828
829<skip_libs>
830 /* The list of shared libraries and/or directories
831 with shared libraries that should not be checked, one per line */
832</skip_libs>
833
834<skip_including>
835 /* The list of header files, that cannot be included
836 directly (or non-self compiled ones), one per line */
837</skip_including>
838
839<search_headers>
840 /* List of directories to be searched
841 for header files to automatically
842 generate include paths, one per line. */
843</search_headers>
844
845<search_libs>
846 /* List of directories to be searched
847 for shared librariess to resolve
848 dependencies, one per line */
849</search_libs>
850
851<tools>
852 /* List of directories with tools used
853 for analysis (GCC toolchain), one per line */
854</tools>
855
856<cross_prefix>
857 /* GCC toolchain prefix.
858 Examples:
859 arm-linux-gnueabi
860 arm-none-symbianelf */
861</cross_prefix>
862
863</descriptor>";
864
865my %Operator_Indication = (
866 "not" => "~",
867 "assign" => "=",
868 "andassign" => "&=",
869 "orassign" => "|=",
870 "xorassign" => "^=",
871 "or" => "|",
872 "xor" => "^",
873 "addr" => "&",
874 "and" => "&",
875 "lnot" => "!",
876 "eq" => "==",
877 "ne" => "!=",
878 "lt" => "<",
879 "lshift" => "<<",
880 "lshiftassign" => "<<=",
881 "rshiftassign" => ">>=",
882 "call" => "()",
883 "mod" => "%",
884 "modassign" => "%=",
885 "subs" => "[]",
886 "land" => "&&",
887 "lor" => "||",
888 "rshift" => ">>",
889 "ref" => "->",
890 "le" => "<=",
891 "deref" => "*",
892 "mult" => "*",
893 "preinc" => "++",
894 "delete" => " delete",
895 "vecnew" => " new[]",
896 "vecdelete" => " delete[]",
897 "predec" => "--",
898 "postinc" => "++",
899 "postdec" => "--",
900 "plusassign" => "+=",
901 "plus" => "+",
902 "minus" => "-",
903 "minusassign" => "-=",
904 "gt" => ">",
905 "ge" => ">=",
906 "new" => " new",
907 "multassign" => "*=",
908 "divassign" => "/=",
909 "div" => "/",
910 "neg" => "-",
911 "pos" => "+",
912 "memref" => "->*",
913 "compound" => "," );
914
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +0400915my %UnknownOperator;
916
917my %NodeType= (
918 "array_type" => "Array",
919 "binfo" => "Other",
920 "boolean_type" => "Intrinsic",
921 "complex_type" => "Intrinsic",
922 "const_decl" => "Other",
923 "enumeral_type" => "Enum",
924 "field_decl" => "Other",
925 "function_decl" => "Other",
926 "function_type" => "FunctionType",
927 "identifier_node" => "Other",
928 "integer_cst" => "Other",
929 "integer_type" => "Intrinsic",
930 "method_type" => "MethodType",
931 "namespace_decl" => "Other",
932 "parm_decl" => "Other",
933 "pointer_type" => "Pointer",
934 "real_cst" => "Other",
935 "real_type" => "Intrinsic",
936 "record_type" => "Struct",
937 "reference_type" => "Ref",
938 "string_cst" => "Other",
939 "template_decl" => "Other",
940 "template_type_parm" => "Other",
941 "tree_list" => "Other",
942 "tree_vec" => "Other",
943 "type_decl" => "Other",
944 "union_type" => "Union",
945 "var_decl" => "Other",
946 "void_type" => "Intrinsic",
947 # "nop_expr" => "Other",
948 # "addr_expr" => "Other",
949 "offset_type" => "Other" );
950
Andrey Ponomarenkoab282102012-03-11 11:57:02 +0400951my %CppKeywords_C = map {$_=>1} (
952 # C++ 2003 keywords
953 "public",
954 "protected",
955 "private",
956 "default",
957 "template",
958 "new",
959 #"asm",
960 "dynamic_cast",
961 "auto",
962 "try",
963 "namespace",
964 "typename",
965 "using",
966 "reinterpret_cast",
967 "friend",
968 "class",
969 "virtual",
970 "const_cast",
971 "mutable",
972 "static_cast",
973 "export",
974 # C++0x keywords
975 "noexcept",
976 "nullptr",
977 "constexpr",
978 "static_assert",
979 "explicit",
980 # cannot be used as a macro name
981 # as it is an operator in C++
982 "and",
983 #"and_eq",
984 "not",
985 #"not_eq",
986 "or"
987 #"or_eq",
988 #"bitand",
989 #"bitor",
990 #"xor",
991 #"xor_eq",
992 #"compl"
993);
994
995my %CppKeywords_F = map {$_=>1} (
996 "delete",
997 "catch",
998 "alignof",
999 "thread_local",
1000 "decltype",
1001 "typeid"
1002);
1003
1004my %CppKeywords_O = map {$_=>1} (
1005 "bool",
1006 "register",
1007 "inline",
1008 "operator"
1009);
1010
1011my %CppKeywords_A = map {$_=>1} (
1012 "this",
1013 "throw"
1014);
1015
1016foreach (keys(%CppKeywords_C),
1017keys(%CppKeywords_F),
1018keys(%CppKeywords_O)) {
1019 $CppKeywords_A{$_}=1;
1020}
1021
1022# Header file extensions as described by gcc
1023my $HEADER_EXT = "h|hh|hp|hxx|hpp|h\\+\\+";
1024
1025my %IntrinsicMangling = (
1026 "void" => "v",
1027 "bool" => "b",
1028 "wchar_t" => "w",
1029 "char" => "c",
1030 "signed char" => "a",
1031 "unsigned char" => "h",
1032 "short" => "s",
1033 "unsigned short" => "t",
1034 "int" => "i",
1035 "unsigned int" => "j",
1036 "long" => "l",
1037 "unsigned long" => "m",
1038 "long long" => "x",
1039 "__int64" => "x",
1040 "unsigned long long" => "y",
1041 "__int128" => "n",
1042 "unsigned __int128" => "o",
1043 "float" => "f",
1044 "double" => "d",
1045 "long double" => "e",
1046 "__float80" => "e",
1047 "__float128" => "g",
1048 "..." => "z"
1049);
1050
1051my %StdcxxMangling = (
1052 "3std"=>"St",
1053 "3std9allocator"=>"Sa",
1054 "3std12basic_string"=>"Sb",
1055 "3std12basic_stringIcE"=>"Ss",
1056 "3std13basic_istreamIcE"=>"Si",
1057 "3std13basic_ostreamIcE"=>"So",
1058 "3std14basic_iostreamIcE"=>"Sd"
1059);
1060
1061my %ConstantSuffix = (
1062 "unsigned int"=>"u",
1063 "long"=>"l",
1064 "unsigned long"=>"ul",
1065 "long long"=>"ll",
1066 "unsigned long long"=>"ull"
1067);
1068
1069my %ConstantSuffixR =
1070reverse(%ConstantSuffix);
1071
1072my %OperatorMangling = (
1073 "~" => "co",
1074 "=" => "aS",
1075 "|" => "or",
1076 "^" => "eo",
1077 "&" => "an",#ad (addr)
1078 "==" => "eq",
1079 "!" => "nt",
1080 "!=" => "ne",
1081 "<" => "lt",
1082 "<=" => "le",
1083 "<<" => "ls",
1084 "<<=" => "lS",
1085 ">" => "gt",
1086 ">=" => "ge",
1087 ">>" => "rs",
1088 ">>=" => "rS",
1089 "()" => "cl",
1090 "%" => "rm",
1091 "[]" => "ix",
1092 "&&" => "aa",
1093 "||" => "oo",
1094 "*" => "ml",#de (deref)
1095 "++" => "pp",#
1096 "--" => "mm",#
1097 "new" => "nw",
1098 "delete" => "dl",
1099 "new[]" => "na",
1100 "delete[]" => "da",
1101 "+=" => "pL",
1102 "+" => "pl",#ps (pos)
1103 "-" => "mi",#ng (neg)
1104 "-=" => "mI",
1105 "*=" => "mL",
1106 "/=" => "dV",
1107 "&=" => "aN",
1108 "|=" => "oR",
1109 "%=" => "rM",
1110 "^=" => "eO",
1111 "/" => "dv",
1112 "->*" => "pm",
1113 "->" => "pt",#rf (ref)
1114 "," => "cm",
1115 "?" => "qu",
1116 "." => "dt",
1117 "sizeof"=> "sz"#st
1118);
1119
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04001120my %Intrinsic_Keywords = map {$_=>1} (
1121 "true",
1122 "false",
1123 "_Bool",
1124 "_Complex",
1125 "const",
1126 "int",
1127 "long",
1128 "void",
1129 "short",
1130 "float",
1131 "volatile",
1132 "restrict",
1133 "unsigned",
1134 "signed",
1135 "char",
1136 "double",
1137 "class",
1138 "struct",
1139 "union",
1140 "enum"
1141);
1142
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04001143my %GlibcHeader = map {$_=>1} (
1144 "aliases.h",
1145 "argp.h",
1146 "argz.h",
1147 "assert.h",
1148 "cpio.h",
1149 "ctype.h",
1150 "dirent.h",
1151 "envz.h",
1152 "errno.h",
1153 "error.h",
1154 "execinfo.h",
1155 "fcntl.h",
1156 "fstab.h",
1157 "ftw.h",
1158 "glob.h",
1159 "grp.h",
1160 "iconv.h",
1161 "ifaddrs.h",
1162 "inttypes.h",
1163 "langinfo.h",
1164 "limits.h",
1165 "link.h",
1166 "locale.h",
1167 "malloc.h",
1168 "math.h",
1169 "mntent.h",
1170 "monetary.h",
1171 "nl_types.h",
1172 "obstack.h",
1173 "printf.h",
1174 "pwd.h",
1175 "regex.h",
1176 "sched.h",
1177 "search.h",
1178 "setjmp.h",
1179 "shadow.h",
1180 "signal.h",
1181 "spawn.h",
1182 "stdarg.h",
1183 "stdint.h",
1184 "stdio.h",
1185 "stdlib.h",
1186 "string.h",
1187 "tar.h",
1188 "termios.h",
1189 "time.h",
1190 "ulimit.h",
1191 "unistd.h",
1192 "utime.h",
1193 "wchar.h",
1194 "wctype.h",
1195 "wordexp.h" );
1196
1197my %GlibcDir = map {$_=>1} (
1198 "arpa",
1199 "bits",
1200 "gnu",
1201 "netinet",
1202 "net",
1203 "nfs",
1204 "rpc",
1205 "sys",
1206 "linux" );
1207
1208my %LocalIncludes = map {$_=>1} (
1209 "/usr/local/include",
1210 "/usr/local" );
1211
1212my %OS_AddPath=(
1213# These paths are needed if the tool cannot detect them automatically
1214 "macos"=>{
1215 "include"=>{
1216 "/Library"=>1,
1217 "/Developer/usr/include"=>1
1218 },
1219 "lib"=>{
1220 "/Library"=>1,
1221 "/Developer/usr/lib"=>1
1222 },
1223 "bin"=>{
1224 "/Developer/usr/bin"=>1
1225 }
1226 },
1227 "beos"=>{
1228 # Haiku has GCC 2.95.3 by default
1229 # try to find GCC>=3.0 in /boot/develop/abi
1230 "include"=>{
1231 "/boot/common"=>1,
1232 "/boot/develop"=>1},
1233 "lib"=>{
1234 "/boot/common/lib"=>1,
1235 "/boot/system/lib"=>1,
1236 "/boot/apps"=>1},
1237 "bin"=>{
1238 "/boot/common/bin"=>1,
1239 "/boot/system/bin"=>1,
1240 "/boot/develop/abi"=>1
1241 }
1242}
1243);
1244
1245my %Slash_Type=(
1246 "default"=>"/",
1247 "windows"=>"\\"
1248);
1249
1250my $SLASH = $Slash_Type{$OSgroup}?$Slash_Type{$OSgroup}:$Slash_Type{"default"};
1251
1252# Global Variables
1253my %COMMON_LANGUAGE=(
1254 1 => "C",
1255 2 => "C" );
1256
1257my $MAX_COMMAND_LINE_ARGUMENTS = 4096;
1258my (%WORD_SIZE, %CPU_ARCH, %GCC_VERSION);
1259
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04001260my $STDCXX_TESTING = 0;
1261my $GLIBC_TESTING = 0;
1262
1263my $CheckHeadersOnly = $CheckHeadersOnly_Opt;
1264my $CheckObjectsOnly = $CheckObjectsOnly_Opt;
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04001265my $TargetComponent;
1266
1267# Set Target Component Name
1268if($TargetComponent_Opt) {
1269 $TargetComponent = lc($TargetComponent_Opt);
1270}
1271else
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04001272{ # default: library
1273 # other components: header, system, ...
1274 $TargetComponent = "library";
1275}
1276
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04001277my $TOP_REF = "<a style='font-size:11px;' href='#Top'>to the top</a>";
1278
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04001279my $SystemRoot;
1280
1281my $MAIN_CPP_DIR;
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04001282my %RESULT;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04001283my %LOG_PATH;
1284my %DEBUG_PATH;
1285my %Cache;
1286my %LibInfo;
1287my $COMPILE_ERRORS = 0;
1288my %CompilerOptions;
1289my %CheckedDyLib;
1290my $TargetLibraryShortName = parse_libname($TargetLibraryName, "shortest", $OSgroup);
1291
1292# Constants (#defines)
1293my %Constants;
1294my %SkipConstants;
1295
1296# Types
1297my %TypeInfo;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04001298my %TemplateInstance;
Andrey Ponomarenko85043792012-05-14 16:48:07 +04001299my %TemplateDecl;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04001300my %SkipTypes = (
1301 "1"=>{},
1302 "2"=>{} );
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04001303my %CheckedTypes;
1304my %TName_Tid;
1305my %EnumMembName_Id;
1306my %NestedNameSpaces = (
1307 "1"=>{},
1308 "2"=>{} );
1309my %UsedType;
1310my %VirtualTable;
Andrey Ponomarenko16934472012-03-29 15:37:04 +04001311my %VirtualTable_Model;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04001312my %ClassVTable;
1313my %ClassVTable_Content;
1314my %VTableClass;
1315my %AllocableClass;
1316my %ClassMethods;
Andrey Ponomarenko16934472012-03-29 15:37:04 +04001317my %ClassNames;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04001318my %Class_SubClasses;
1319my %OverriddenMethods;
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04001320my $MAX_ID = 0;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04001321
1322# Typedefs
1323my %Typedef_BaseName;
1324my %Typedef_Tr;
1325my %Typedef_Eq;
1326my %StdCxxTypedef;
1327my %MissedTypedef;
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04001328my %MissedBase;
1329my %MissedBase_R;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04001330
1331# Symbols
1332my %SymbolInfo;
1333my %tr_name;
1334my %mangled_name_gcc;
1335my %mangled_name;
1336my %SkipSymbols = (
1337 "1"=>{},
1338 "2"=>{} );
1339my %SkipNameSpaces = (
1340 "1"=>{},
1341 "2"=>{} );
Andrey Ponomarenkoa01311b2012-06-08 17:20:02 +04001342my %AddNameSpaces = (
1343 "1"=>{},
1344 "2"=>{} );
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04001345my %SymbolsList;
1346my %SymbolsList_App;
1347my %CheckedSymbols;
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04001348my %Symbol_Library = (
1349 "1"=>{},
1350 "2"=>{} );
1351my %Library_Symbol = (
1352 "1"=>{},
1353 "2"=>{} );
1354my %DepSymbol_Library = (
1355 "1"=>{},
1356 "2"=>{} );
1357my %DepLibrary_Symbol = (
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04001358 "1"=>{},
1359 "2"=>{} );
1360my %MangledNames;
1361my %AddIntParams;
1362my %Interface_Impl;
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04001363my %GlobalDataObject;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04001364
1365# Headers
1366my %Include_Preamble;
1367my %Registered_Headers;
1368my %HeaderName_Paths;
1369my %Header_Dependency;
1370my %Include_Neighbors;
1371my %Include_Paths;
1372my %INC_PATH_AUTODETECT = (
1373 "1"=>1,
1374 "2"=>1 );
1375my %Add_Include_Paths;
1376my %Skip_Include_Paths;
1377my %RegisteredDirs;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04001378my %Header_ErrorRedirect;
1379my %Header_Includes;
1380my %Header_ShouldNotBeUsed;
1381my %RecursiveIncludes;
1382my %Header_Include_Prefix;
1383my %SkipHeaders;
1384my %SkipHeadersList=(
1385 "1"=>{},
1386 "2"=>{} );
1387my %SkipLibs;
1388my %Include_Order;
1389my %TUnit_NameSpaces;
1390
1391my %C99Mode = (
1392 "1"=>0,
1393 "2"=>0 );
1394my %AutoPreambleMode = (
1395 "1"=>0,
1396 "2"=>0 );
1397my %MinGWMode = (
1398 "1"=>0,
1399 "2"=>0 );
1400
1401# Shared Objects
1402my %DyLib_DefaultPath;
1403my %InputObject_Paths;
1404my %RegisteredObjDirs;
1405
1406# System Objects
1407my %SystemObjects;
1408my %DefaultLibPaths;
1409
1410# System Headers
1411my %SystemHeaders;
1412my %DefaultCppPaths;
1413my %DefaultGccPaths;
1414my %DefaultIncPaths;
1415my %DefaultCppHeader;
1416my %DefaultGccHeader;
1417my %UserIncPath;
1418
1419# Merging
1420my %CompleteSignature;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04001421my $Version;
1422my %AddedInt;
1423my %RemovedInt;
1424my %AddedInt_Virt;
1425my %RemovedInt_Virt;
1426my %VirtualReplacement;
1427my %ChangedTypedef;
1428my %CompatRules;
1429my %IncompleteRules;
1430my %UnknownRules;
Andrey Ponomarenko16934472012-03-29 15:37:04 +04001431my %VTableChanged_M;
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04001432my %ExtendedSymbols;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04001433my %ReturnedClass;
1434my %ParamClass;
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04001435my %SourceAlternative;
1436my %SourceAlternative_B;
1437my %SourceReplacement;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04001438
1439# OS Compliance
1440my %TargetLibs;
1441my %TargetHeaders;
1442
1443# OS Specifics
1444my $OStarget = $OSgroup;
1445my %TargetTools;
1446
1447# Compliance Report
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04001448my %Type_MaxSeverity;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04001449
1450# Recursion locks
1451my @RecurLib;
1452my @RecurSymlink;
1453my @RecurTypes;
1454my @RecurInclude;
1455my @RecurConstant;
1456
1457# System
1458my %SystemPaths;
1459my %DefaultBinPaths;
1460my $GCC_PATH;
1461
1462# Symbols versioning
1463my %SymVer = (
1464 "1"=>{},
1465 "2"=>{} );
1466
1467# Problem descriptions
1468my %CompatProblems;
1469my %ProblemsWithConstants;
1470my %ImplProblems;
1471my %TotalAffected;
1472
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04001473# Reports
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04001474my $ContentID = 1;
1475my $ContentSpanStart = "<span class=\"section\" onclick=\"javascript:showContent(this, 'CONTENT_ID')\">\n";
1476my $ContentSpanStart_Affected = "<span class=\"section_affected\" onclick=\"javascript:showContent(this, 'CONTENT_ID')\">\n";
1477my $ContentSpanStart_Info = "<span class=\"section_info\" onclick=\"javascript:showContent(this, 'CONTENT_ID')\">\n";
1478my $ContentSpanEnd = "</span>\n";
1479my $ContentDivStart = "<div id=\"CONTENT_ID\" style=\"display:none;\">\n";
1480my $ContentDivEnd = "</div>\n";
1481my $Content_Counter = 0;
1482
Andrey Ponomarenko5c09ef32012-06-14 18:17:33 +04001483# XML Dump
1484my $TAG_ID = 0;
1485my $INDENT = " ";
1486
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04001487# Modes
1488my $JoinReport = 1;
1489my $DoubleReport = 0;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04001490
1491sub get_Modules()
1492{
1493 my $TOOL_DIR = get_dirname($0);
1494 if(not $TOOL_DIR)
1495 { # patch for MS Windows
1496 $TOOL_DIR = ".";
1497 }
1498 my @SEARCH_DIRS = (
1499 # tool's directory
1500 abs_path($TOOL_DIR),
1501 # relative path to modules
1502 abs_path($TOOL_DIR)."/../share/abi-compliance-checker",
1503 # system directory
1504 "ACC_MODULES_INSTALL_PATH"
1505 );
1506 foreach my $DIR (@SEARCH_DIRS)
1507 {
1508 if(not is_abs($DIR))
1509 { # relative path
1510 $DIR = abs_path($TOOL_DIR)."/".$DIR;
1511 }
1512 if(-d $DIR."/modules") {
1513 return $DIR."/modules";
1514 }
1515 }
1516 exitStatus("Module_Error", "can't find modules");
1517}
1518
1519sub loadModule($)
1520{
1521 my $Name = $_[0];
1522 my $Path = $MODULES_DIR."/Internals/$Name.pm";
1523 if(not -f $Path) {
1524 exitStatus("Module_Error", "can't access \'$Path\'");
1525 }
1526 require $Path;
1527}
1528
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04001529sub showPos($)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04001530{
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04001531 my $Number = $_[0];
1532 if(not $Number) {
1533 $Number = 1;
1534 }
1535 else {
1536 $Number = int($Number)+1;
1537 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04001538 if($Number>3) {
1539 return $Number."th";
1540 }
1541 elsif($Number==1) {
1542 return "1st";
1543 }
1544 elsif($Number==2) {
1545 return "2nd";
1546 }
1547 elsif($Number==3) {
1548 return "3rd";
1549 }
1550 else {
1551 return $Number;
1552 }
1553}
1554
1555sub search_Tools($)
1556{
1557 my $Name = $_[0];
1558 return "" if(not $Name);
1559 if(my @Paths = keys(%TargetTools))
1560 {
1561 foreach my $Path (@Paths)
1562 {
1563 if(-f joinPath($Path, $Name)) {
1564 return joinPath($Path, $Name);
1565 }
1566 if($CrossPrefix)
1567 { # user-defined prefix (arm-none-symbianelf, ...)
1568 my $Candidate = joinPath($Path, $CrossPrefix."-".$Name);
1569 if(-f $Candidate) {
1570 return $Candidate;
1571 }
1572 }
1573 }
1574 }
1575 else {
1576 return "";
1577 }
1578}
1579
1580sub synch_Cmd($)
1581{
1582 my $Name = $_[0];
1583 if(not $GCC_PATH)
1584 { # GCC was not found yet
1585 return "";
1586 }
1587 my $Candidate = $GCC_PATH;
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04001588 if($Candidate=~s/\bgcc(|\.\w+)\Z/$Name$1/) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04001589 return $Candidate;
1590 }
1591 return "";
1592}
1593
1594sub get_CmdPath($)
1595{
1596 my $Name = $_[0];
1597 return "" if(not $Name);
1598 if(defined $Cache{"get_CmdPath"}{$Name}) {
1599 return $Cache{"get_CmdPath"}{$Name};
1600 }
1601 my %BinUtils = map {$_=>1} (
1602 "c++filt",
1603 "objdump",
1604 "readelf"
1605 );
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04001606 if($BinUtils{$Name} and $GCC_PATH)
1607 {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04001608 if(my $Dir = get_dirname($GCC_PATH)) {
1609 $TargetTools{$Dir}=1;
1610 }
1611 }
1612 my $Path = search_Tools($Name);
1613 if(not $Path and $OSgroup eq "windows") {
1614 $Path = search_Tools($Name.".exe");
1615 }
1616 if(not $Path and $BinUtils{$Name})
1617 {
1618 if($CrossPrefix)
1619 { # user-defined prefix
1620 $Path = search_Cmd($CrossPrefix."-".$Name);
1621 }
1622 }
1623 if(not $Path and $BinUtils{$Name})
1624 {
1625 if(my $Candidate = synch_Cmd($Name))
1626 { # synch with GCC
1627 if($Candidate=~/[\/\\]/)
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04001628 { # command path
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04001629 if(-f $Candidate) {
1630 $Path = $Candidate;
1631 }
1632 }
1633 elsif($Candidate = search_Cmd($Candidate))
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04001634 { # command name
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04001635 $Path = $Candidate;
1636 }
1637 }
1638 }
1639 if(not $Path) {
1640 $Path = search_Cmd($Name);
1641 }
1642 if(not $Path and $OSgroup eq "windows")
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04001643 { # search for *.exe file
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04001644 $Path=search_Cmd($Name.".exe");
1645 }
1646 if($Path=~/\s/) {
1647 $Path = "\"".$Path."\"";
1648 }
1649 return ($Cache{"get_CmdPath"}{$Name}=$Path);
1650}
1651
1652sub search_Cmd($)
1653{
1654 my $Name = $_[0];
1655 return "" if(not $Name);
1656 if(defined $Cache{"search_Cmd"}{$Name}) {
1657 return $Cache{"search_Cmd"}{$Name};
1658 }
1659 if(my $DefaultPath = get_CmdPath_Default($Name)) {
1660 return ($Cache{"search_Cmd"}{$Name} = $DefaultPath);
1661 }
1662 foreach my $Path (sort {length($a)<=>length($b)} keys(%{$SystemPaths{"bin"}}))
1663 {
1664 my $CmdPath = joinPath($Path,$Name);
1665 if(-f $CmdPath)
1666 {
1667 if($Name=~/gcc/) {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04001668 next if(not check_gcc($CmdPath, "3"));
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04001669 }
1670 return ($Cache{"search_Cmd"}{$Name} = $CmdPath);
1671 }
1672 }
1673 return ($Cache{"search_Cmd"}{$Name} = "");
1674}
1675
1676sub get_CmdPath_Default($)
1677{ # search in PATH
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04001678 return "" if(not $_[0]);
1679 if(defined $Cache{"get_CmdPath_Default"}{$_[0]}) {
1680 return $Cache{"get_CmdPath_Default"}{$_[0]};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04001681 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04001682 return ($Cache{"get_CmdPath_Default"}{$_[0]} = get_CmdPath_Default_I($_[0]));
1683}
1684
1685sub get_CmdPath_Default_I($)
1686{ # search in PATH
1687 my $Name = $_[0];
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04001688 if($Name=~/find/)
1689 { # special case: search for "find" utility
Andrey Ponomarenkoa01311b2012-06-08 17:20:02 +04001690 if(`find \"$TMP_DIR\" -maxdepth 0 2>\"$TMP_DIR/null\"`) {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04001691 return "find";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04001692 }
1693 }
1694 elsif($Name=~/gcc/) {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04001695 return check_gcc($Name, "3");
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04001696 }
1697 if(check_command($Name)) {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04001698 return $Name;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04001699 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04001700 if($OSgroup eq "windows")
1701 {
Andrey Ponomarenkoa01311b2012-06-08 17:20:02 +04001702 if(`$Name /? 2>\"$TMP_DIR/null\"`) {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04001703 return $Name;
1704 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04001705 }
1706 if($Name!~/which/)
1707 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04001708 if(my $WhichCmd = get_CmdPath("which"))
1709 {
Andrey Ponomarenkoa01311b2012-06-08 17:20:02 +04001710 if(`$WhichCmd $Name 2>\"$TMP_DIR/null\"`) {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04001711 return $Name;
1712 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04001713 }
1714 }
1715 foreach my $Path (sort {length($a)<=>length($b)} keys(%DefaultBinPaths))
1716 {
1717 if(-f $Path."/".$Name) {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04001718 return joinPath($Path,$Name);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04001719 }
1720 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04001721 return "";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04001722}
1723
1724sub clean_path($)
1725{
1726 my $Path = $_[0];
1727 $Path=~s/[\/\\]+\Z//g;
1728 return $Path;
1729}
1730
1731sub classifyPath($)
1732{
1733 my $Path = $_[0];
1734 if($Path=~/[\*\[]/)
1735 { # wildcard
1736 $Path=~s/\*/.*/g;
1737 $Path=~s/\\/\\\\/g;
1738 return ($Path, "Pattern");
1739 }
1740 elsif($Path=~/[\/\\]/)
1741 { # directory or relative path
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04001742 $Path=~s/[\/\\]+\Z//g;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04001743 return (path_format($Path, $OSgroup), "Path");
1744 }
1745 else {
1746 return ($Path, "Name");
1747 }
1748}
1749
1750sub readDescriptor($$)
1751{
1752 my ($LibVersion, $Content) = @_;
1753 return if(not $LibVersion);
1754 my $DName = $DumpAPI?"descriptor":"descriptor \"d$LibVersion\"";
1755 if(not $Content) {
1756 exitStatus("Error", "$DName is empty");
1757 }
1758 if($Content!~/\</) {
Andrey Ponomarenko5c09ef32012-06-14 18:17:33 +04001759 exitStatus("Error", "incorrect descriptor (see -d1 option)");
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04001760 }
1761 $Content=~s/\/\*(.|\n)+?\*\///g;
1762 $Content=~s/<\!--(.|\n)+?-->//g;
1763 $Descriptor{$LibVersion}{"Version"} = parseTag(\$Content, "version");
1764 if($TargetVersion{$LibVersion}) {
1765 $Descriptor{$LibVersion}{"Version"} = $TargetVersion{$LibVersion};
1766 }
1767 if(not $Descriptor{$LibVersion}{"Version"}) {
1768 exitStatus("Error", "version in the $DName is not specified (<version> section)");
1769 }
1770 if($Content=~/{RELPATH}/)
1771 {
1772 if(my $RelDir = $RelativeDirectory{$LibVersion}) {
1773 $Content =~ s/{RELPATH}/$RelDir/g;
1774 }
1775 else
1776 {
1777 my $NeedRelpath = $DumpAPI?"-relpath":"-relpath$LibVersion";
1778 exitStatus("Error", "you have not specified $NeedRelpath option, but the $DName contains {RELPATH} macro");
1779 }
1780 }
1781
1782 if(not $CheckObjectsOnly_Opt)
1783 {
1784 my $DHeaders = parseTag(\$Content, "headers");
1785 if(not $DHeaders) {
1786 exitStatus("Error", "header files in the $DName are not specified (<headers> section)");
1787 }
1788 elsif(lc($DHeaders) ne "none")
1789 { # append the descriptor headers list
1790 if($Descriptor{$LibVersion}{"Headers"})
1791 { # multiple descriptors
1792 $Descriptor{$LibVersion}{"Headers"} .= "\n".$DHeaders;
1793 }
1794 else {
1795 $Descriptor{$LibVersion}{"Headers"} = $DHeaders;
1796 }
1797 foreach my $Path (split(/\s*\n\s*/, $DHeaders))
1798 {
1799 if(not -e $Path) {
1800 exitStatus("Access_Error", "can't access \'$Path\'");
1801 }
1802 }
1803 }
1804 }
1805 if(not $CheckHeadersOnly_Opt)
1806 {
1807 my $DObjects = parseTag(\$Content, "libs");
1808 if(not $DObjects) {
1809 exitStatus("Error", "$SLIB_TYPE libraries in the $DName are not specified (<libs> section)");
1810 }
1811 elsif(lc($DObjects) ne "none")
1812 { # append the descriptor libraries list
1813 if($Descriptor{$LibVersion}{"Libs"})
1814 { # multiple descriptors
1815 $Descriptor{$LibVersion}{"Libs"} .= "\n".$DObjects;
1816 }
1817 else {
1818 $Descriptor{$LibVersion}{"Libs"} .= $DObjects;
1819 }
1820 foreach my $Path (split(/\s*\n\s*/, $DObjects))
1821 {
1822 if(not -e $Path) {
1823 exitStatus("Access_Error", "can't access \'$Path\'");
1824 }
1825 }
1826 }
1827 }
1828 foreach my $Path (split(/\s*\n\s*/, parseTag(\$Content, "search_headers")))
1829 {
1830 $Path = clean_path($Path);
1831 if(not -d $Path) {
1832 exitStatus("Access_Error", "can't access directory \'$Path\'");
1833 }
1834 $Path = path_format($Path, $OSgroup);
1835 $SystemPaths{"include"}{$Path}=1;
1836 }
1837 foreach my $Path (split(/\s*\n\s*/, parseTag(\$Content, "search_libs")))
1838 {
1839 $Path = clean_path($Path);
1840 if(not -d $Path) {
1841 exitStatus("Access_Error", "can't access directory \'$Path\'");
1842 }
1843 $Path = path_format($Path, $OSgroup);
1844 $SystemPaths{"lib"}{$Path}=1;
1845 }
1846 foreach my $Path (split(/\s*\n\s*/, parseTag(\$Content, "tools")))
1847 {
1848 $Path=clean_path($Path);
1849 if(not -d $Path) {
1850 exitStatus("Access_Error", "can't access directory \'$Path\'");
1851 }
1852 $Path = path_format($Path, $OSgroup);
1853 $SystemPaths{"bin"}{$Path}=1;
1854 $TargetTools{$Path}=1;
1855 }
1856 if(my $Prefix = parseTag(\$Content, "cross_prefix")) {
1857 $CrossPrefix = $Prefix;
1858 }
1859 foreach my $Path (split(/\s*\n\s*/, parseTag(\$Content, "include_paths")))
1860 {
1861 $Path=clean_path($Path);
1862 if(not -d $Path) {
1863 exitStatus("Access_Error", "can't access directory \'$Path\'");
1864 }
1865 $Path = path_format($Path, $OSgroup);
1866 $Descriptor{$LibVersion}{"IncludePaths"}{$Path} = 1;
1867 }
1868 foreach my $Path (split(/\s*\n\s*/, parseTag(\$Content, "add_include_paths")))
1869 {
1870 $Path=clean_path($Path);
1871 if(not -d $Path) {
1872 exitStatus("Access_Error", "can't access directory \'$Path\'");
1873 }
1874 $Path = path_format($Path, $OSgroup);
1875 $Descriptor{$LibVersion}{"AddIncludePaths"}{$Path} = 1;
1876 }
1877 foreach my $Path (split(/\s*\n\s*/, parseTag(\$Content, "skip_include_paths")))
1878 {
1879 # skip some auto-generated include paths
1880 $Skip_Include_Paths{$LibVersion}{path_format($Path)}=1;
1881 }
1882 foreach my $Path (split(/\s*\n\s*/, parseTag(\$Content, "skip_including")))
1883 {
1884 # skip direct including of some headers
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04001885 $SkipHeadersList{$LibVersion}{$Path} = 2;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04001886 my ($CPath, $Type) = classifyPath($Path);
1887 $SkipHeaders{$LibVersion}{$Type}{$CPath} = 2;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04001888 }
1889 $Descriptor{$LibVersion}{"GccOptions"} = parseTag(\$Content, "gcc_options");
1890 foreach my $Option (split(/\s*\n\s*/, $Descriptor{$LibVersion}{"GccOptions"})) {
1891 $CompilerOptions{$LibVersion} .= " ".$Option;
1892 }
1893 $Descriptor{$LibVersion}{"SkipHeaders"} = parseTag(\$Content, "skip_headers");
1894 foreach my $Path (split(/\s*\n\s*/, $Descriptor{$LibVersion}{"SkipHeaders"}))
1895 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04001896 $SkipHeadersList{$LibVersion}{$Path} = 1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04001897 my ($CPath, $Type) = classifyPath($Path);
1898 $SkipHeaders{$LibVersion}{$Type}{$CPath} = 1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04001899 }
1900 $Descriptor{$LibVersion}{"SkipLibs"} = parseTag(\$Content, "skip_libs");
1901 foreach my $Path (split(/\s*\n\s*/, $Descriptor{$LibVersion}{"SkipLibs"}))
1902 {
1903 my ($CPath, $Type) = classifyPath($Path);
1904 $SkipLibs{$LibVersion}{$Type}{$CPath} = 1;
1905 }
1906 if(my $DDefines = parseTag(\$Content, "defines"))
1907 {
1908 if($Descriptor{$LibVersion}{"Defines"})
1909 { # multiple descriptors
1910 $Descriptor{$LibVersion}{"Defines"} .= "\n".$DDefines;
1911 }
1912 else {
1913 $Descriptor{$LibVersion}{"Defines"} = $DDefines;
1914 }
1915 }
1916 foreach my $Order (split(/\s*\n\s*/, parseTag(\$Content, "include_order")))
1917 {
1918 if($Order=~/\A(.+):(.+)\Z/) {
1919 $Include_Order{$LibVersion}{$1} = $2;
1920 }
1921 }
1922 foreach my $Type_Name (split(/\s*\n\s*/, parseTag(\$Content, "opaque_types")),
1923 split(/\s*\n\s*/, parseTag(\$Content, "skip_types")))
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04001924 { # opaque_types renamed to skip_types (1.23.4)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04001925 $SkipTypes{$LibVersion}{$Type_Name} = 1;
1926 }
1927 foreach my $Symbol (split(/\s*\n\s*/, parseTag(\$Content, "skip_interfaces")),
1928 split(/\s*\n\s*/, parseTag(\$Content, "skip_symbols")))
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04001929 { # skip_interfaces renamed to skip_symbols (1.22.1)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04001930 $SkipSymbols{$LibVersion}{$Symbol} = 1;
1931 }
1932 foreach my $NameSpace (split(/\s*\n\s*/, parseTag(\$Content, "skip_namespaces"))) {
1933 $SkipNameSpaces{$LibVersion}{$NameSpace} = 1;
1934 }
Andrey Ponomarenkoa01311b2012-06-08 17:20:02 +04001935 foreach my $NameSpace (split(/\s*\n\s*/, parseTag(\$Content, "add_namespaces"))) {
1936 $AddNameSpaces{$LibVersion}{$NameSpace} = 1;
1937 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04001938 foreach my $Constant (split(/\s*\n\s*/, parseTag(\$Content, "skip_constants"))) {
1939 $SkipConstants{$LibVersion}{$Constant} = 1;
1940 }
1941 if(my $DIncPreamble = parseTag(\$Content, "include_preamble"))
1942 {
1943 if($Descriptor{$LibVersion}{"IncludePreamble"})
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04001944 { # multiple descriptors
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04001945 $Descriptor{$LibVersion}{"IncludePreamble"} .= "\n".$DIncPreamble;
1946 }
1947 else {
1948 $Descriptor{$LibVersion}{"IncludePreamble"} = $DIncPreamble;
1949 }
1950 }
1951}
1952
1953sub parseTag($$)
1954{
1955 my ($CodeRef, $Tag) = @_;
1956 return "" if(not $CodeRef or not ${$CodeRef} or not $Tag);
1957 if(${$CodeRef}=~s/\<\Q$Tag\E\>((.|\n)+?)\<\/\Q$Tag\E\>//)
1958 {
1959 my $Content = $1;
1960 $Content=~s/(\A\s+|\s+\Z)//g;
1961 return $Content;
1962 }
1963 else {
1964 return "";
1965 }
1966}
1967
Andrey Ponomarenko35c44fd2012-06-18 17:50:25 +04001968sub addTag(@)
Andrey Ponomarenko5c09ef32012-06-14 18:17:33 +04001969{
Andrey Ponomarenko35c44fd2012-06-18 17:50:25 +04001970 my $Tag = shift(@_);
1971 my $Val = shift(@_);
1972 my @Ext = @_;
1973 my $Content = openTag($Tag, @Ext);
1974 chomp($Content);
Andrey Ponomarenko5c09ef32012-06-14 18:17:33 +04001975 $Content .= xmlSpecChars($Val);
1976 $Content .= "</$Tag>\n";
Andrey Ponomarenko35c44fd2012-06-18 17:50:25 +04001977 $TAG_ID-=1;
Andrey Ponomarenko5c09ef32012-06-14 18:17:33 +04001978
1979 return $Content;
1980}
1981
Andrey Ponomarenko35c44fd2012-06-18 17:50:25 +04001982sub openTag(@)
Andrey Ponomarenko5c09ef32012-06-14 18:17:33 +04001983{
1984 my $Tag = shift(@_);
1985 my @Ext = @_;
1986 my $Content = "";
1987 foreach (1 .. $TAG_ID) {
1988 $Content .= $INDENT;
1989 }
1990 $TAG_ID+=1;
Andrey Ponomarenko35c44fd2012-06-18 17:50:25 +04001991 if(@Ext)
Andrey Ponomarenko5c09ef32012-06-14 18:17:33 +04001992 {
Andrey Ponomarenko35c44fd2012-06-18 17:50:25 +04001993 $Content .= "<".$Tag;
1994 my $P = 0;
1995 while($P<=$#Ext-1)
1996 {
1997 $Content .= " ".$Ext[$P];
1998 $Content .= "=\"".xmlSpecChars($Ext[$P+1])."\"";
1999 $P+=2;
2000 }
2001 $Content .= ">\n";
Andrey Ponomarenko5c09ef32012-06-14 18:17:33 +04002002 }
Andrey Ponomarenko35c44fd2012-06-18 17:50:25 +04002003 else {
2004 $Content .= "<".$Tag.">\n";
2005 }
Andrey Ponomarenko5c09ef32012-06-14 18:17:33 +04002006 return $Content;
2007}
2008
2009sub closeTag($)
2010{
2011 my $Tag = $_[0];
2012 my $Content = "";
2013 $TAG_ID-=1;
2014 foreach (1 .. $TAG_ID) {
2015 $Content .= $INDENT;
2016 }
2017 $Content .= "</".$Tag.">\n";
2018 return $Content;
2019}
2020
2021sub checkTags()
2022{
2023 if($TAG_ID!=0) {
2024 printMsg("WARNING", "the number of opened tags is not equal to number of closed tags");
2025 }
2026}
2027
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002028sub getInfo($)
2029{
Andrey Ponomarenko85043792012-05-14 16:48:07 +04002030 my $DumpPath = $_[0];
2031 return if(not $DumpPath or not -f $DumpPath);
2032
2033 readTUDump($DumpPath);
2034
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002035 # processing info
2036 setTemplateParams_All();
2037 getTypeInfo_All();
2038 simplifyNames();
2039 getSymbolInfo_All();
2040 getVarInfo_All();
2041
Andrey Ponomarenko85043792012-05-14 16:48:07 +04002042 # clean memory
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002043 %LibInfo = ();
2044 %TemplateInstance = ();
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002045 %MangledNames = ();
Andrey Ponomarenko85043792012-05-14 16:48:07 +04002046 %TemplateDecl = ();
2047 %StdCxxTypedef = ();
2048 %MissedTypedef = ();
2049 %Typedef_Tr = ();
2050 %Typedef_Eq = ();
2051
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04002052 # clean cache
2053 delete($Cache{"getTypeAttr"});
2054 delete($Cache{"getTypeDeclId"});
2055
2056 # remove unused types
2057 if($BinaryOnly and not $ExtendedCheck)
2058 { # --binary
2059 removeUnused($Version, "All");
2060 }
2061 else {
2062 removeUnused($Version, "Derived");
2063 }
2064
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002065 if($Debug) {
2066 # debugMangling($Version);
2067 }
2068}
2069
Andrey Ponomarenko85043792012-05-14 16:48:07 +04002070sub readTUDump($)
2071{
2072 my $DumpPath = $_[0];
2073
2074 open(TU_DUMP, $DumpPath);
2075 local $/ = undef;
2076 my $Content = <TU_DUMP>;
2077 close(TU_DUMP);
2078
2079 unlink($DumpPath);
2080
2081 $Content=~s/\n[ ]+/ /g;
2082 my @Lines = split("\n", $Content);
2083
2084 # clean memory
2085 undef $Content;
2086
2087 $MAX_ID = $#Lines+1;
2088
2089 foreach (0 .. $#Lines)
2090 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04002091 if($Lines[$_]=~/\A\@(\d+)[ ]+([a-z_]+)[ ]+(.+)\Z/i)
Andrey Ponomarenko85043792012-05-14 16:48:07 +04002092 { # get a number and attributes of a node
2093 next if(not $NodeType{$2});
2094 $LibInfo{$Version}{"info_type"}{$1}=$2;
2095 $LibInfo{$Version}{"info"}{$1}=$3;
2096 }
2097
2098 # clean memory
2099 delete($Lines[$_]);
2100 }
2101
2102 # clean memory
2103 undef @Lines;
2104}
2105
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002106sub simplifyNames()
2107{
2108 foreach my $Base (keys(%{$Typedef_Tr{$Version}}))
2109 {
2110 my @Translations = keys(%{$Typedef_Tr{$Version}{$Base}});
2111 if($#Translations==0 and length($Translations[0])<=length($Base)) {
2112 $Typedef_Eq{$Version}{$Base} = $Translations[0];
2113 }
2114 }
Andrey Ponomarenkob8d203d2012-05-25 18:11:07 +04002115 foreach my $TypeId (keys(%{$TypeInfo{$Version}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002116 {
Andrey Ponomarenkob8d203d2012-05-25 18:11:07 +04002117 my $TypeName = $TypeInfo{$Version}{$TypeId}{"Name"};
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04002118 if(not $TypeName) {
2119 next;
2120 }
2121 next if(index($TypeName,"<")==-1);# template instances only
2122 if($TypeName=~/>(::\w+)+\Z/)
2123 { # skip unused types
2124 next;
2125 };
2126 foreach my $Base (sort {length($b)<=>length($a)}
2127 sort {$b cmp $a} keys(%{$Typedef_Eq{$Version}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002128 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04002129 next if(not $Base);
2130 next if(index($TypeName,$Base)==-1);
2131 next if(length($TypeName) - length($Base) <= 3);
2132 my $Typedef = $Typedef_Eq{$Version}{$Base};
2133 $TypeName=~s/(\<|\,)\Q$Base\E(\W|\Z)/$1$Typedef$2/g;
2134 $TypeName=~s/(\<|\,)\Q$Base\E(\w|\Z)/$1$Typedef $2/g;
Andrey Ponomarenkob8d203d2012-05-25 18:11:07 +04002135 if(defined $TypeInfo{$Version}{$TypeId}{"TParam"})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002136 {
Andrey Ponomarenkob8d203d2012-05-25 18:11:07 +04002137 foreach my $TPos (keys(%{$TypeInfo{$Version}{$TypeId}{"TParam"}}))
Andrey Ponomarenko85043792012-05-14 16:48:07 +04002138 {
Andrey Ponomarenkob8d203d2012-05-25 18:11:07 +04002139 my $TPName = $TypeInfo{$Version}{$TypeId}{"TParam"}{$TPos}{"name"};
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04002140 $TPName=~s/\A\Q$Base\E(\W|\Z)/$Typedef$1/g;
Andrey Ponomarenkob8d203d2012-05-25 18:11:07 +04002141 $TypeInfo{$Version}{$TypeId}{"TParam"}{$TPos}{"name"} = formatName($TPName);
Andrey Ponomarenko85043792012-05-14 16:48:07 +04002142 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002143 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002144 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04002145 $TypeName = formatName($TypeName);
Andrey Ponomarenkob8d203d2012-05-25 18:11:07 +04002146 $TypeInfo{$Version}{$TypeId}{"Name"} = $TypeName;
2147 $TName_Tid{$Version}{$TypeName} = $TypeId;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002148 }
2149}
2150
2151sub setTemplateParams_All()
2152{
2153 foreach (keys(%{$LibInfo{$Version}{"info"}}))
2154 {
2155 if($LibInfo{$Version}{"info_type"}{$_} eq "template_decl") {
2156 setTemplateParams($_);
2157 }
2158 }
2159}
2160
2161sub setTemplateParams($)
2162{
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04002163 if(my $Info = $LibInfo{$Version}{"info"}{$_[0]})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002164 {
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04002165 if($Info=~/(inst|spcs)[ ]*:[ ]*@(\d+) /)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002166 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04002167 my $TmplInst_Id = $2;
2168 setTemplateInstParams($TmplInst_Id);
2169 while($TmplInst_Id = getNextElem($TmplInst_Id)) {
2170 setTemplateInstParams($TmplInst_Id);
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04002171 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002172 }
2173 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04002174 if(my $TypeId = getTreeAttr_Type($_[0]))
Andrey Ponomarenko85043792012-05-14 16:48:07 +04002175 {
2176 if(my $IType = $LibInfo{$Version}{"info_type"}{$TypeId})
2177 {
2178 if($IType eq "record_type") {
2179 $TemplateDecl{$Version}{$TypeId}=1;
2180 }
2181 }
2182 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002183}
2184
2185sub setTemplateInstParams($)
2186{
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04002187 if(my $Info = $LibInfo{$Version}{"info"}{$_[0]})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002188 {
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04002189 my ($Params_InfoId, $ElemId) = ();
2190 if($Info=~/purp[ ]*:[ ]*@(\d+) /) {
2191 $Params_InfoId = $1;
2192 }
2193 if($Info=~/valu[ ]*:[ ]*@(\d+) /) {
2194 $ElemId = $1;
2195 }
2196 if($Params_InfoId and $ElemId)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002197 {
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04002198 my $Params_Info = $LibInfo{$Version}{"info"}{$Params_InfoId};
2199 while($Params_Info=~s/ (\d+)[ ]*:[ ]*\@(\d+) / /)
2200 {
2201 my ($PPos, $PTypeId) = ($1, $2);
2202 if(my $PType = $LibInfo{$Version}{"info_type"}{$PTypeId})
2203 {
Andrey Ponomarenko85043792012-05-14 16:48:07 +04002204 if($PType eq "template_type_parm")
2205 {
2206 $TemplateDecl{$Version}{$ElemId}=1;
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04002207 return;
2208 }
2209 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +04002210 if($LibInfo{$Version}{"info_type"}{$ElemId} eq "function_decl")
2211 { # functions
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04002212 $TemplateInstance{$Version}{"Func"}{$ElemId}{$PPos} = $PTypeId;
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04002213 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +04002214 else
2215 { # types
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04002216 $TemplateInstance{$Version}{"Type"}{$ElemId}{$PPos} = $PTypeId;
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04002217 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002218 }
2219 }
2220 }
2221}
2222
2223sub getTypeDeclId($)
2224{
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04002225 if($_[0])
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04002226 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04002227 if(defined $Cache{"getTypeDeclId"}{$Version}{$_[0]}) {
2228 return $Cache{"getTypeDeclId"}{$Version}{$_[0]};
2229 }
2230 if(my $Info = $LibInfo{$Version}{"info"}{$_[0]})
2231 {
2232 if($Info=~/name[ ]*:[ ]*@(\d+)/) {
2233 return ($Cache{"getTypeDeclId"}{$Version}{$_[0]} = $1);
2234 }
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04002235 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002236 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04002237 return ($Cache{"getTypeDeclId"}{$Version}{$_[0]} = 0);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002238}
2239
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002240sub getTypeInfo_All()
2241{
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04002242 if(not check_gcc($GCC_PATH, "4.5"))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002243 { # support for GCC < 4.5
2244 # missed typedefs: QStyle::State is typedef to QFlags<QStyle::StateFlag>
2245 # but QStyleOption.state is of type QFlags<QStyle::StateFlag> in the TU dump
2246 # FIXME: check GCC versions
2247 addMissedTypes_Pre();
2248 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04002249
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002250 foreach (sort {int($a)<=>int($b)} keys(%{$LibInfo{$Version}{"info"}}))
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04002251 { # forward order only
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002252 my $IType = $LibInfo{$Version}{"info_type"}{$_};
2253 if($IType=~/_type\Z/ and $IType ne "function_type"
2254 and $IType ne "method_type") {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04002255 getTypeInfo("$_");
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002256 }
2257 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04002258
2259 # add "..." type
2260 $TypeInfo{$Version}{-1} = {
2261 "Name" => "...",
2262 "Type" => "Intrinsic",
2263 "Tid" => -1
2264 };
2265 $TName_Tid{$Version}{"..."} = -1;
2266
2267 if(not check_gcc($GCC_PATH, "4.5"))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002268 { # support for GCC < 4.5
2269 addMissedTypes_Post();
2270 }
2271}
2272
2273sub addMissedTypes_Pre()
2274{
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04002275 my %MissedTypes = ();
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002276 foreach my $MissedTDid (sort {int($a)<=>int($b)} keys(%{$LibInfo{$Version}{"info"}}))
2277 { # detecting missed typedefs
2278 if($LibInfo{$Version}{"info_type"}{$MissedTDid} eq "type_decl")
2279 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04002280 my $TypeId = getTreeAttr_Type($MissedTDid);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002281 next if(not $TypeId);
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04002282 my $TypeType = getTypeType($TypeId);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002283 if($TypeType eq "Unknown")
2284 { # template_type_parm
2285 next;
2286 }
2287 my $TypeDeclId = getTypeDeclId($TypeId);
2288 next if($TypeDeclId eq $MissedTDid);#or not $TypeDeclId
2289 my $TypedefName = getNameByInfo($MissedTDid);
2290 next if(not $TypedefName);
2291 next if($TypedefName eq "__float80");
2292 next if(isAnon($TypedefName));
2293 if(not $TypeDeclId
2294 or getNameByInfo($TypeDeclId) ne $TypedefName) {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04002295 $MissedTypes{$Version}{$TypeId}{$MissedTDid} = 1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002296 }
2297 }
2298 }
Andrey Ponomarenkob8d203d2012-05-25 18:11:07 +04002299 my %AddTypes = ();
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04002300 foreach my $Tid (keys(%{$MissedTypes{$Version}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002301 { # add missed typedefs
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04002302 my @Missed = keys(%{$MissedTypes{$Version}{$Tid}});
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002303 if(not @Missed or $#Missed>=1) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002304 next;
2305 }
2306 my $MissedTDid = $Missed[0];
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002307 my ($TypedefName, $TypedefNS) = getTrivialName($MissedTDid, $Tid);
Andrey Ponomarenkob8d203d2012-05-25 18:11:07 +04002308 if(not $TypedefName) {
2309 next;
2310 }
2311 $MAX_ID++;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002312 my %MissedInfo = ( # typedef info
2313 "Name" => $TypedefName,
2314 "NameSpace" => $TypedefNS,
2315 "BaseType" => {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002316 "Tid" => $Tid
2317 },
2318 "Type" => "Typedef",
Andrey Ponomarenkob8d203d2012-05-25 18:11:07 +04002319 "Tid" => "$MAX_ID" );
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002320 my ($H, $L) = getLocation($MissedTDid);
2321 $MissedInfo{"Header"} = $H;
2322 $MissedInfo{"Line"} = $L;
Andrey Ponomarenkob8d203d2012-05-25 18:11:07 +04002323 if($TypedefName=~/\*|\&|\s/)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002324 { # other types
2325 next;
2326 }
Andrey Ponomarenkob8d203d2012-05-25 18:11:07 +04002327 if($TypedefName=~/>(::\w+)+\Z/)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002328 { # QFlags<Qt::DropAction>::enum_type
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002329 next;
2330 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04002331 if(getTypeType($Tid)=~/\A(Intrinsic|Union|Struct|Enum|Class)\Z/)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002332 { # double-check for the name of typedef
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04002333 my ($TName, $TNS) = getTrivialName(getTypeDeclId($Tid), $Tid); # base type info
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002334 next if(not $TName);
Andrey Ponomarenkob8d203d2012-05-25 18:11:07 +04002335 if(length($TypedefName)>=length($TName))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002336 { # too long typedef
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002337 next;
2338 }
Andrey Ponomarenkob8d203d2012-05-25 18:11:07 +04002339 if($TName=~/\A\Q$TypedefName\E</) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002340 next;
2341 }
Andrey Ponomarenkob8d203d2012-05-25 18:11:07 +04002342 if($TypedefName=~/\A\Q$TName\E/)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002343 { # QDateTimeEdit::Section and QDateTimeEdit::Sections::enum_type
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002344 next;
2345 }
Andrey Ponomarenkob8d203d2012-05-25 18:11:07 +04002346 if(get_depth($TypedefName)==0 and get_depth($TName)!=0)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002347 { # std::_Vector_base and std::vector::_Base
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002348 next;
2349 }
2350 }
Andrey Ponomarenkob8d203d2012-05-25 18:11:07 +04002351
2352 $AddTypes{$MissedInfo{"Tid"}} = \%MissedInfo;
2353
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002354 # register typedef
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002355 $MissedTypedef{$Version}{$Tid}{"Tid"} = $MissedInfo{"Tid"};
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04002356 $MissedTypedef{$Version}{$Tid}{"TDid"} = $MissedTDid;
Andrey Ponomarenkob8d203d2012-05-25 18:11:07 +04002357 $TName_Tid{$Version}{$TypedefName} = $MissedInfo{"Tid"};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002358 }
Andrey Ponomarenkob8d203d2012-05-25 18:11:07 +04002359
2360 # add missed & remove other
2361 $TypeInfo{$Version} = \%AddTypes;
2362 delete($Cache{"getTypeAttr"}{$Version});
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002363}
2364
2365sub addMissedTypes_Post()
2366{
2367 foreach my $BaseId (keys(%{$MissedTypedef{$Version}}))
2368 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04002369 if(my $Tid = $MissedTypedef{$Version}{$BaseId}{"Tid"})
2370 {
2371 $TypeInfo{$Version}{$Tid}{"Size"} = $TypeInfo{$Version}{$BaseId}{"Size"};
2372 if(my $TName = $TypeInfo{$Version}{$Tid}{"Name"}) {
2373 $Typedef_BaseName{$Version}{$TName} = $TypeInfo{$Version}{$BaseId}{"Name"};
2374 }
2375 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002376 }
2377}
2378
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04002379sub getTypeInfo($)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002380{
Andrey Ponomarenkob8d203d2012-05-25 18:11:07 +04002381 my $TypeId = $_[0];
2382 %{$TypeInfo{$Version}{$TypeId}} = getTypeAttr($TypeId);
2383 my $TName = $TypeInfo{$Version}{$TypeId}{"Name"};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002384 if(not $TName) {
Andrey Ponomarenkob8d203d2012-05-25 18:11:07 +04002385 delete($TypeInfo{$Version}{$TypeId});
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002386 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002387}
2388
2389sub getArraySize($$)
2390{
2391 my ($TypeId, $BaseName) = @_;
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04002392 if(my $Size = getSize($TypeId))
2393 {
2394 my $Elems = $Size/$BYTE_SIZE;
2395 while($BaseName=~s/\s*\[(\d+)\]//) {
2396 $Elems/=$1;
2397 }
2398 if(my $BasicId = $TName_Tid{$Version}{$BaseName})
2399 {
2400 if(my $BasicSize = $TypeInfo{$Version}{$BasicId}{"Size"}) {
2401 $Elems/=$BasicSize;
2402 }
2403 }
2404 return $Elems;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002405 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04002406 return 0;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002407}
2408
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04002409sub getTParams($$)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002410{
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04002411 my ($TypeId, $Kind) = @_;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002412 my @TmplParams = ();
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04002413 my @Positions = sort {int($a)<=>int($b)} keys(%{$TemplateInstance{$Version}{$Kind}{$TypeId}});
2414 foreach my $Pos (@Positions)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002415 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04002416 my $Param_TypeId = $TemplateInstance{$Version}{$Kind}{$TypeId}{$Pos};
2417 my $NodeType = $LibInfo{$Version}{"info_type"}{$Param_TypeId};
2418 if(not $NodeType)
2419 { # typename_type
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002420 return ();
2421 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04002422 if($NodeType eq "tree_vec")
2423 {
2424 if($Pos!=$#Positions)
2425 { # select last vector of parameters ( ns<P1>::type<P2> )
2426 next;
2427 }
2428 }
2429 my @Params = get_TemplateParam($Pos, $Param_TypeId);
2430 foreach my $P (@Params)
2431 {
2432 if($P eq "") {
2433 return ();
2434 }
2435 elsif($P ne "\@skip\@") {
2436 @TmplParams = (@TmplParams, $P);
2437 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002438 }
2439 }
2440 return @TmplParams;
2441}
2442
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04002443sub getTypeAttr($)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002444{
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04002445 my $TypeId = $_[0];
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04002446 my %TypeAttr = ();
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04002447 if(defined $TypeInfo{$Version}{$TypeId}
2448 and $TypeInfo{$Version}{$TypeId}{"Name"})
2449 { # already created
2450 return %{$TypeInfo{$Version}{$TypeId}};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002451 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04002452 elsif($Cache{"getTypeAttr"}{$Version}{$TypeId})
2453 { # incomplete type
2454 return ();
2455 }
2456 $Cache{"getTypeAttr"}{$Version}{$TypeId} = 1;
2457
2458 my $TypeDeclId = getTypeDeclId($TypeId);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002459 $TypeAttr{"Tid"} = $TypeId;
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04002460
2461 if(not $MissedBase{$Version}{$TypeId} and isTypedef($TypeId))
2462 {
2463 if(my $Info = $LibInfo{$Version}{"info"}{$TypeId})
2464 {
2465 if($Info=~/qual[ ]*:/)
2466 {
2467 if(my $NID = ++$MAX_ID)
2468 {
2469 $MissedBase{$Version}{$TypeId}="$NID";
2470 $MissedBase_R{$Version}{$NID}=$TypeId;
2471 $LibInfo{$Version}{"info"}{$NID} = $LibInfo{$Version}{"info"}{$TypeId};
2472 $LibInfo{$Version}{"info_type"}{$NID} = $LibInfo{$Version}{"info_type"}{$TypeId};
2473 }
2474 }
2475 }
2476 $TypeAttr{"Type"} = "Typedef";
2477 }
2478 else {
2479 $TypeAttr{"Type"} = getTypeType($TypeId);
2480 }
2481
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002482 if($TypeAttr{"Type"} eq "Unknown") {
2483 return ();
2484 }
2485 elsif($TypeAttr{"Type"}=~/(Func|Method|Field)Ptr/)
2486 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04002487 %TypeAttr = getMemPtrAttr(pointTo($TypeId), $TypeId, $TypeAttr{"Type"});
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04002488 if(my $TName = $TypeAttr{"Name"})
2489 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04002490 %{$TypeInfo{$Version}{$TypeId}} = %TypeAttr;
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04002491 $TName_Tid{$Version}{$TName} = $TypeId;
2492 return %TypeAttr;
2493 }
2494 else {
2495 return ();
2496 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002497 }
2498 elsif($TypeAttr{"Type"} eq "Array")
2499 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04002500 my ($BTid, $BTSpec) = selectBaseType($TypeId);
2501 if(not $BTid) {
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04002502 return ();
2503 }
2504 $TypeAttr{"BaseType"}{"Tid"} = $BTid;
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04002505 if(my %BTAttr = getTypeAttr($BTid))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002506 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04002507 if(not $BTAttr{"Name"}) {
2508 return ();
2509 }
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04002510 if(my $NElems = getArraySize($TypeId, $BTAttr{"Name"}))
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04002511 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04002512 if(my $Size = getSize($TypeId)) {
2513 $TypeAttr{"Size"} = $Size/$BYTE_SIZE;
2514 }
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04002515 if($BTAttr{"Name"}=~/\A([^\[\]]+)(\[(\d+|)\].*)\Z/) {
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04002516 $TypeAttr{"Name"} = $1."[$NElems]".$2;
2517 }
2518 else {
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04002519 $TypeAttr{"Name"} = $BTAttr{"Name"}."[$NElems]";
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04002520 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002521 }
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04002522 else
2523 {
2524 $TypeAttr{"Size"} = $WORD_SIZE{$Version}; # pointer
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04002525 if($BTAttr{"Name"}=~/\A([^\[\]]+)(\[(\d+|)\].*)\Z/) {
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04002526 $TypeAttr{"Name"} = $1."[]".$2;
2527 }
2528 else {
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04002529 $TypeAttr{"Name"} = $BTAttr{"Name"}."[]";
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04002530 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002531 }
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04002532 $TypeAttr{"Name"} = formatName($TypeAttr{"Name"});
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04002533 if($BTAttr{"Header"}) {
2534 $TypeAttr{"Header"} = $BTAttr{"Header"};
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04002535 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04002536 %{$TypeInfo{$Version}{$TypeId}} = %TypeAttr;
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04002537 $TName_Tid{$Version}{$TypeAttr{"Name"}} = $TypeId;
2538 return %TypeAttr;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002539 }
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04002540 return ();
2541 }
2542 elsif($TypeAttr{"Type"}=~/\A(Intrinsic|Union|Struct|Enum|Class)\Z/)
2543 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04002544 %TypeAttr = getTrivialTypeAttr($TypeId);
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04002545 if($TypeAttr{"Name"})
2546 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04002547 %{$TypeInfo{$Version}{$TypeId}} = %TypeAttr;
2548 if($TypeAttr{"Name"} ne "int" or getTypeDeclId($TypeAttr{"Tid"}))
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04002549 { # NOTE: register only one int: with built-in decl
2550 if(not $TName_Tid{$Version}{$TypeAttr{"Name"}}) {
2551 $TName_Tid{$Version}{$TypeAttr{"Name"}} = $TypeId;
2552 }
2553 }
2554 return %TypeAttr;
2555 }
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04002556 else {
2557 return ();
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002558 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002559 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002560 else
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04002561 { # derived types
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04002562 my ($BTid, $BTSpec) = selectBaseType($TypeId);
2563 if(not $BTid) {
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04002564 return ();
2565 }
2566 $TypeAttr{"BaseType"}{"Tid"} = $BTid;
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04002567 if(defined $MissedTypedef{$Version}{$BTid})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002568 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04002569 if(my $MissedTDid = $MissedTypedef{$Version}{$BTid}{"TDid"})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002570 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04002571 if($MissedTDid ne $TypeDeclId) {
2572 $TypeAttr{"BaseType"}{"Tid"} = $MissedTypedef{$Version}{$BTid}{"Tid"};
2573 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002574 }
2575 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04002576 my %BTAttr = getTypeAttr($TypeAttr{"BaseType"}{"Tid"});
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04002577 if(not $BTAttr{"Name"})
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04002578 { # templates
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002579 return ();
2580 }
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04002581 if($BTAttr{"Type"} eq "Typedef")
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002582 { # relinking typedefs
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04002583 my %BaseBase = get_Type($BTAttr{"BaseType"}{"Tid"}, $Version);
2584 if($BTAttr{"Name"} eq $BaseBase{"Name"}) {
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04002585 $TypeAttr{"BaseType"}{"Tid"} = $BaseBase{"Tid"};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002586 }
2587 }
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04002588 if($BTSpec)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002589 {
2590 if($TypeAttr{"Type"} eq "Pointer"
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04002591 and $BTAttr{"Name"}=~/\([\*]+\)/)
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04002592 {
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04002593 $TypeAttr{"Name"} = $BTAttr{"Name"};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002594 $TypeAttr{"Name"}=~s/\(([*]+)\)/($1*)/g;
2595 }
2596 else {
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04002597 $TypeAttr{"Name"} = $BTAttr{"Name"}." ".$BTSpec;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002598 }
2599 }
2600 else {
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04002601 $TypeAttr{"Name"} = $BTAttr{"Name"};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002602 }
2603 if($TypeAttr{"Type"} eq "Typedef")
2604 {
2605 $TypeAttr{"Name"} = getNameByInfo($TypeDeclId);
Andrey Ponomarenko85043792012-05-14 16:48:07 +04002606 if(isAnon($TypeAttr{"Name"}))
2607 { # anon typedef to anon type: ._N
2608 return ();
2609 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002610 if(my $NS = getNameSpace($TypeDeclId))
2611 {
2612 my $TypeName = $TypeAttr{"Name"};
2613 if($NS=~/\A(struct |union |class |)((.+)::|)\Q$TypeName\E\Z/)
2614 { # "some_type" is the typedef to "struct some_type" in C++
2615 if($3) {
2616 $TypeAttr{"Name"} = $3."::".$TypeName;
2617 }
2618 }
2619 else
2620 {
2621 $TypeAttr{"NameSpace"} = $NS;
2622 $TypeAttr{"Name"} = $TypeAttr{"NameSpace"}."::".$TypeAttr{"Name"};
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04002623
2624 if($TypeAttr{"NameSpace"}=~/\Astd(::|\Z)/
2625 and $TypeAttr{"Name"}!~/>(::\w+)+\Z/)
2626 {
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04002627 if($BTAttr{"NameSpace"}
2628 and $BTAttr{"NameSpace"}=~/\Astd(::|\Z)/ and $BTAttr{"Name"}=~/</)
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04002629 { # types like "std::fpos<__mbstate_t>" are
2630 # not covered by typedefs in the TU dump
2631 # so trying to add such typedefs manually
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04002632 $StdCxxTypedef{$Version}{$BTAttr{"Name"}}{$TypeAttr{"Name"}} = 1;
2633 if(length($TypeAttr{"Name"})<=length($BTAttr{"Name"}))
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04002634 {
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04002635 if(($BTAttr{"Name"}!~/\A(std|boost)::/ or $TypeAttr{"Name"}!~/\A[a-z]+\Z/))
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04002636 { # skip "other" in "std" and "type" in "boost"
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04002637 $Typedef_Eq{$Version}{$BTAttr{"Name"}} = $TypeAttr{"Name"};
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04002638 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002639 }
2640 }
2641 }
2642 }
2643 }
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04002644 if($TypeAttr{"Name"} ne $BTAttr{"Name"}
2645 and $TypeAttr{"Name"}!~/>(::\w+)+\Z/ and $BTAttr{"Name"}!~/>(::\w+)+\Z/)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002646 {
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04002647 if(not defined $Typedef_BaseName{$Version}{$TypeAttr{"Name"}})
2648 { # typedef int*const TYPEDEF; // first
2649 # int foo(TYPEDEF p); // const is optimized out
2650 $Typedef_BaseName{$Version}{$TypeAttr{"Name"}} = $BTAttr{"Name"};
2651 if($BTAttr{"Name"}=~/</)
2652 {
2653 if(($BTAttr{"Name"}!~/\A(std|boost)::/ or $TypeAttr{"Name"}!~/\A[a-z]+\Z/)) {
2654 $Typedef_Tr{$Version}{$BTAttr{"Name"}}{$TypeAttr{"Name"}} = 1;
2655 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002656 }
2657 }
2658 }
2659 ($TypeAttr{"Header"}, $TypeAttr{"Line"}) = getLocation($TypeDeclId);
2660 }
2661 if(not $TypeAttr{"Size"})
2662 {
2663 if($TypeAttr{"Type"} eq "Pointer") {
2664 $TypeAttr{"Size"} = $WORD_SIZE{$Version};
2665 }
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04002666 elsif($BTAttr{"Size"}) {
2667 $TypeAttr{"Size"} = $BTAttr{"Size"};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002668 }
2669 }
2670 $TypeAttr{"Name"} = formatName($TypeAttr{"Name"});
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04002671 if(not $TypeAttr{"Header"} and $BTAttr{"Header"}) {
2672 $TypeAttr{"Header"} = $BTAttr{"Header"};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002673 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04002674 %{$TypeInfo{$Version}{$TypeId}} = %TypeAttr;
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04002675 if($TypeAttr{"Name"} ne $BTAttr{"Name"})
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04002676 { # typedef to "class Class"
2677 # should not be registered in TName_Tid
2678 if(not $TName_Tid{$Version}{$TypeAttr{"Name"}}) {
2679 $TName_Tid{$Version}{$TypeAttr{"Name"}} = $TypeId;
2680 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002681 }
2682 return %TypeAttr;
2683 }
2684}
2685
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04002686sub getTreeVec($)
2687{
2688 my %Vector = ();
2689 if($_[0] and my $Info = $LibInfo{$Version}{"info"}{$_[0]})
2690 {
2691 while($Info=~s/ (\d+)[ ]*:[ ]*\@(\d+) / /)
2692 { # string length is N-1 because of the null terminator
2693 $Vector{$1} = $2;
2694 }
2695 }
2696 return \%Vector;
2697}
2698
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002699sub get_TemplateParam($$)
2700{
2701 my ($Pos, $Type_Id) = @_;
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04002702 return () if(not $Type_Id);
2703 my $NodeType = $LibInfo{$Version}{"info_type"}{$Type_Id};
2704 return () if(not $NodeType);
2705 if($NodeType eq "integer_cst")
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002706 { # int (1), unsigned (2u), char ('c' as 99), ...
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04002707 my $CstTid = getTreeAttr_Type($Type_Id);
Andrey Ponomarenkob8d203d2012-05-25 18:11:07 +04002708 my %CstType = getTypeAttr($CstTid); # without recursion
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002709 my $Num = getNodeIntCst($Type_Id);
2710 if(my $CstSuffix = $ConstantSuffix{$CstType{"Name"}}) {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04002711 return ($Num.$CstSuffix);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002712 }
2713 else {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04002714 return ("(".$CstType{"Name"}.")".$Num);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002715 }
2716 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04002717 elsif($NodeType eq "string_cst") {
2718 return (getNodeStrCst($Type_Id));
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002719 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04002720 elsif($NodeType eq "tree_vec")
2721 {
2722 my $Vector = getTreeVec($Type_Id);
2723 my @Params = ();
2724 foreach my $P1 (sort {int($a)<=>int($b)} keys(%{$Vector}))
2725 {
2726 foreach my $P2 (get_TemplateParam($Pos, $Vector->{$P1})) {
2727 push(@Params, $P2);
2728 }
2729 }
2730 return @Params;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002731 }
2732 else
2733 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04002734 my %ParamAttr = getTypeAttr($Type_Id);
Andrey Ponomarenkob8d203d2012-05-25 18:11:07 +04002735 my $PName = $ParamAttr{"Name"};
2736 if(not $PName) {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04002737 return ();
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002738 }
Andrey Ponomarenkob8d203d2012-05-25 18:11:07 +04002739 if($PName=~/\>/)
2740 {
2741 if(my $Cover = cover_stdcxx_typedef($PName)) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002742 $PName = $Cover;
2743 }
2744 }
2745 if($Pos>=1 and
2746 $PName=~/\Astd::(allocator|less|((char|regex)_traits)|((i|o)streambuf_iterator))\</)
2747 { # template<typename _Tp, typename _Alloc = std::allocator<_Tp> >
2748 # template<typename _Key, typename _Compare = std::less<_Key>
2749 # template<typename _CharT, typename _Traits = std::char_traits<_CharT> >
2750 # template<typename _Ch_type, typename _Rx_traits = regex_traits<_Ch_type> >
2751 # template<typename _CharT, typename _InIter = istreambuf_iterator<_CharT> >
2752 # template<typename _CharT, typename _OutIter = ostreambuf_iterator<_CharT> >
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04002753 return ("\@skip\@");
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002754 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04002755 return ($PName);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002756 }
2757}
2758
2759sub cover_stdcxx_typedef($)
2760{
2761 my $TypeName = $_[0];
2762 if(my @Covers = sort {length($a)<=>length($b)}
2763 sort keys(%{$StdCxxTypedef{$Version}{$TypeName}}))
2764 { # take the shortest typedef
2765 # FIXME: there may be more than
2766 # one typedefs to the same type
2767 return $Covers[0];
2768 }
2769 my $TypeName_Covered = $TypeName;
2770 while($TypeName=~s/(>)[ ]*(const|volatile|restrict| |\*|\&)\Z/$1/g){};
2771 if(my @Covers = sort {length($a)<=>length($b)} sort keys(%{$StdCxxTypedef{$Version}{$TypeName}}))
2772 {
2773 my $Cover = $Covers[0];
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04002774 $TypeName_Covered=~s/\b\Q$TypeName\E(\W|\Z)/$Cover$1/g;
2775 $TypeName_Covered=~s/\b\Q$TypeName\E(\w|\Z)/$Cover $1/g;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002776 }
2777 return formatName($TypeName_Covered);
2778}
2779
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002780sub getNodeIntCst($)
2781{
2782 my $CstId = $_[0];
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04002783 my $CstTypeId = getTreeAttr_Type($CstId);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002784 if($EnumMembName_Id{$Version}{$CstId}) {
2785 return $EnumMembName_Id{$Version}{$CstId};
2786 }
2787 elsif((my $Value = getTreeValue($CstId)) ne "")
2788 {
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04002789 if($Value eq "0")
2790 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04002791 if($LibInfo{$Version}{"info_type"}{$CstTypeId} eq "boolean_type") {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002792 return "false";
2793 }
2794 else {
2795 return "0";
2796 }
2797 }
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04002798 elsif($Value eq "1")
2799 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04002800 if($LibInfo{$Version}{"info_type"}{$CstTypeId} eq "boolean_type") {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002801 return "true";
2802 }
2803 else {
2804 return "1";
2805 }
2806 }
2807 else {
2808 return $Value;
2809 }
2810 }
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04002811 return "";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002812}
2813
2814sub getNodeStrCst($)
2815{
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04002816 if($_[0] and my $Info = $LibInfo{$Version}{"info"}{$_[0]})
2817 {
2818 if($Info=~/strg[ ]*: (.+) lngt:[ ]*(\d+)/)
2819 { # string length is N-1 because of the null terminator
2820 return substr($1, 0, $2-1);
2821 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002822 }
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04002823 return "";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002824}
2825
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04002826sub getMemPtrAttr($$$)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002827{ # function, method and field pointers
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04002828 my ($PtrId, $TypeId, $Type) = @_;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002829 my $MemInfo = $LibInfo{$Version}{"info"}{$PtrId};
2830 if($Type eq "FieldPtr") {
2831 $MemInfo = $LibInfo{$Version}{"info"}{$TypeId};
2832 }
2833 my $MemInfo_Type = $LibInfo{$Version}{"info_type"}{$PtrId};
2834 my $MemPtrName = "";
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04002835 my %TypeAttr = ("Size"=>$WORD_SIZE{$Version}, "Type"=>$Type, "Tid"=>$TypeId);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002836 if($Type eq "MethodPtr")
2837 { # size of "method pointer" may be greater than WORD size
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04002838 if(my $Size = getSize($TypeId)) {
2839 $TypeAttr{"Size"} = $Size/$BYTE_SIZE;
2840 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002841 }
2842 # Return
2843 if($Type eq "FieldPtr")
2844 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04002845 my %ReturnAttr = getTypeAttr($PtrId);
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04002846 if($ReturnAttr{"Name"}) {
2847 $MemPtrName .= $ReturnAttr{"Name"};
2848 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002849 $TypeAttr{"Return"} = $PtrId;
2850 }
2851 else
2852 {
2853 if($MemInfo=~/retn[ ]*:[ ]*\@(\d+) /)
2854 {
2855 my $ReturnTypeId = $1;
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04002856 my %ReturnAttr = getTypeAttr($ReturnTypeId);
2857 if(not $ReturnAttr{"Name"})
2858 { # templates
2859 return ();
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04002860 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04002861 $MemPtrName .= $ReturnAttr{"Name"};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002862 $TypeAttr{"Return"} = $ReturnTypeId;
2863 }
2864 }
2865 # Class
2866 if($MemInfo=~/(clas|cls)[ ]*:[ ]*@(\d+) /)
2867 {
2868 $TypeAttr{"Class"} = $2;
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04002869 my %Class = getTypeAttr($TypeAttr{"Class"});
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002870 if($Class{"Name"}) {
2871 $MemPtrName .= " (".$Class{"Name"}."\:\:*)";
2872 }
2873 else {
2874 $MemPtrName .= " (*)";
2875 }
2876 }
2877 else {
2878 $MemPtrName .= " (*)";
2879 }
2880 # Parameters
2881 if($Type eq "FuncPtr"
2882 or $Type eq "MethodPtr")
2883 {
2884 my @ParamTypeName = ();
2885 if($MemInfo=~/prms[ ]*:[ ]*@(\d+) /)
2886 {
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04002887 my $PTypeInfoId = $1;
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04002888 my $Pos = 0;
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04002889 while($PTypeInfoId)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002890 {
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04002891 my $PTypeInfo = $LibInfo{$Version}{"info"}{$PTypeInfoId};
2892 if($PTypeInfo=~/valu[ ]*:[ ]*@(\d+) /)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002893 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04002894 my $PTypeId = $1;
2895 my %ParamAttr = getTypeAttr($PTypeId);
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04002896 if(not $ParamAttr{"Name"})
2897 { # templates (template_type_parm), etc.
2898 return ();
2899 }
2900 if($ParamAttr{"Name"} eq "void") {
2901 last;
2902 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04002903 if($Pos!=0 or $Type ne "MethodPtr")
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04002904 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04002905 $TypeAttr{"Param"}{$Pos}{"type"} = $PTypeId;
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04002906 push(@ParamTypeName, $ParamAttr{"Name"});
2907 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04002908 if($PTypeInfoId = getNextElem($PTypeInfoId)) {
2909 $Pos+=1;
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04002910 }
2911 else {
2912 last;
2913 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002914 }
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04002915 else {
2916 last;
2917 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002918 }
2919 }
2920 $MemPtrName .= " (".join(", ", @ParamTypeName).")";
2921 }
2922 $TypeAttr{"Name"} = formatName($MemPtrName);
2923 return %TypeAttr;
2924}
2925
2926sub getTreeTypeName($)
2927{
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04002928 my $TypeId = $_[0];
2929 if(my $Info = $LibInfo{$Version}{"info"}{$TypeId})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002930 {
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04002931 if($LibInfo{$Version}{"info_type"}{$_[0]} eq "integer_type")
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002932 {
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04002933 if(my $Name = getNameByInfo($TypeId))
2934 { # bit_size_type
2935 return $Name;
2936 }
2937 elsif($Info=~/unsigned/) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002938 return "unsigned int";
2939 }
2940 else {
2941 return "int";
2942 }
2943 }
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04002944 elsif($Info=~/name[ ]*:[ ]*@(\d+) /)
2945 {
2946 return getNameByInfo($1);
2947 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002948 }
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04002949 return "";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002950}
2951
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04002952sub isFuncPtr($)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002953{
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04002954 my $Ptd = pointTo($_[0]);
2955 return 0 if(not $Ptd);
2956 if(my $Info = $LibInfo{$Version}{"info"}{$_[0]})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002957 {
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04002958 if($Info=~/unql[ ]*:/ and $Info!~/qual[ ]*:/) {
2959 return 0;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002960 }
2961 }
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04002962 if(my $InfoT1 = $LibInfo{$Version}{"info_type"}{$_[0]}
2963 and my $InfoT2 = $LibInfo{$Version}{"info_type"}{$Ptd})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002964 {
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04002965 if($InfoT1 eq "pointer_type"
2966 and $InfoT2 eq "function_type") {
2967 return 1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002968 }
2969 }
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04002970 return 0;
2971}
2972
2973sub isMethodPtr($)
2974{
2975 my $Ptd = pointTo($_[0]);
2976 return 0 if(not $Ptd);
2977 if(my $Info = $LibInfo{$Version}{"info"}{$_[0]})
2978 {
2979 if($LibInfo{$Version}{"info_type"}{$_[0]} eq "record_type"
2980 and $LibInfo{$Version}{"info_type"}{$Ptd} eq "method_type"
2981 and $Info=~/ ptrmem /) {
2982 return 1;
2983 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002984 }
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04002985 return 0;
2986}
2987
2988sub isFieldPtr($)
2989{
2990 if($_[0] and my $Info = $LibInfo{$Version}{"info"}{$_[0]})
2991 {
2992 if($LibInfo{$Version}{"info_type"}{$_[0]} eq "offset_type"
2993 and $Info=~/ ptrmem /) {
2994 return 1;
2995 }
2996 }
2997 return 0;
2998}
2999
3000sub pointTo($)
3001{
3002 if($_[0] and my $Info = $LibInfo{$Version}{"info"}{$_[0]})
3003 {
3004 if($Info=~/ptd[ ]*:[ ]*@(\d+)/) {
3005 return $1;
3006 }
3007 }
3008 return "";
3009}
3010
3011sub getTypeTypeByTypeId($)
3012{
3013 my $TypeId = $_[0];
3014 if(my $TType = $LibInfo{$Version}{"info_type"}{$TypeId})
3015 {
3016 my $NType = $NodeType{$TType};
3017 if($NType eq "Intrinsic") {
3018 return $NType;
3019 }
3020 elsif(isFuncPtr($TypeId)) {
3021 return "FuncPtr";
3022 }
3023 elsif(isMethodPtr($TypeId)) {
3024 return "MethodPtr";
3025 }
3026 elsif(isFieldPtr($TypeId)) {
3027 return "FieldPtr";
3028 }
3029 elsif($NType ne "Other") {
3030 return $NType;
3031 }
3032 }
3033 return "Unknown";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003034}
3035
3036sub getQual($)
3037{
3038 my $TypeId = $_[0];
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003039 my %UnQual = (
3040 "r"=>"restrict",
3041 "v"=>"volatile",
3042 "c"=>"const",
3043 "cv"=>"const volatile"
3044 );
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04003045 if(my $Info = $LibInfo{$Version}{"info"}{$TypeId})
3046 {
3047 my ($Qual, $To) = ();
3048 if($Info=~/qual[ ]*:[ ]*(r|c|v|cv) /) {
3049 $Qual = $UnQual{$1};
3050 }
3051 if($Info=~/unql[ ]*:[ ]*\@(\d+)/) {
3052 $To = $1;
3053 }
3054 if($Qual and $To) {
3055 return ($Qual, $To);
3056 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003057 }
3058 return ();
3059}
3060
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04003061sub getQualType($)
3062{
3063 if($_[0] eq "const volatile") {
3064 return "ConstVolatile";
3065 }
3066 return ucfirst($_[0]);
3067}
3068
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04003069sub getTypeType($)
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04003070{
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04003071 my $TypeId = $_[0];
3072 my $TypeDeclId = getTypeDeclId($TypeId);
3073 if(defined $MissedTypedef{$Version}{$TypeId})
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04003074 { # support for old GCC versions
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04003075 if($MissedTypedef{$Version}{$TypeId}{"TDid"} eq $TypeDeclId) {
3076 return "Typedef";
3077 }
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04003078 }
3079 my $Info = $LibInfo{$Version}{"info"}{$TypeId};
3080 my ($Qual, $To) = getQual($TypeId);
3081 if(($Qual or $To) and $Info=~/name[ ]*:[ ]*\@(\d+) /
3082 and (getTypeId($1) ne $TypeId))
3083 { # qualified types (special)
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04003084 return getQualType($Qual);
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04003085 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04003086 elsif(not $MissedBase_R{$Version}{$TypeId}
3087 and isTypedef($TypeId)) {
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04003088 return "Typedef";
3089 }
3090 elsif($Qual)
3091 { # qualified types
3092 return getQualType($Qual);
3093 }
3094 my $TypeType = getTypeTypeByTypeId($TypeId);
3095 if($TypeType eq "Struct")
3096 {
3097 if($TypeDeclId
3098 and $LibInfo{$Version}{"info_type"}{$TypeDeclId} eq "template_decl") {
3099 return "Template";
3100 }
3101 }
3102 return $TypeType;
3103}
3104
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04003105sub isTypedef($)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003106{
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04003107 if($_[0] and my $Info = $LibInfo{$Version}{"info"}{$_[0]})
3108 {
3109 my $TDid = getTypeDeclId($_[0]);
3110 if(getNameByInfo($TDid)
3111 and $Info=~/unql[ ]*:[ ]*\@(\d+) /
3112 and getTypeId($TDid) eq $_[0]) {
3113 return $1;
3114 }
3115 }
3116 return 0;
3117}
3118
3119sub selectBaseType($)
3120{
3121 my $TypeId = $_[0];
3122 if(defined $MissedTypedef{$Version}{$TypeId})
3123 { # add missed typedefs
3124 if($MissedTypedef{$Version}{$TypeId}{"TDid"} eq getTypeDeclId($TypeId)) {
3125 return ($TypeId, "");
3126 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003127 }
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04003128 my $Info = $LibInfo{$Version}{"info"}{$TypeId};
3129 my $InfoType = $LibInfo{$Version}{"info_type"}{$TypeId};
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04003130
3131 my $MB_R = $MissedBase_R{$Version}{$TypeId};
3132 my $MB = $MissedBase{$Version}{$TypeId};
3133
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04003134 my ($Qual, $To) = getQual($TypeId);
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04003135 if(($Qual or $To) and $Info=~/name[ ]*:[ ]*\@(\d+) /
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04003136 and (getTypeId($1) ne $TypeId)
3137 and (not $MB_R or getTypeId($1) ne $MB_R))
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04003138 { # qualified types (special)
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04003139 return (getTypeId($1), $Qual);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003140 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04003141 elsif($MB)
3142 { # add base
3143 return ($MB, "");
3144 }
3145 elsif(not $MB_R and my $Bid = isTypedef($TypeId))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003146 { # typedefs
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04003147 return ($Bid, "");
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003148 }
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04003149 elsif($Qual or $To)
3150 { # qualified types
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04003151 return ($To, $Qual);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003152 }
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04003153 elsif($InfoType eq "reference_type")
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003154 {
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04003155 if($Info=~/refd[ ]*:[ ]*@(\d+) /) {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04003156 return ($1, "&");
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003157 }
3158 else {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04003159 return (0, "");
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003160 }
3161 }
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04003162 elsif($InfoType eq "array_type")
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003163 {
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04003164 if($Info=~/elts[ ]*:[ ]*@(\d+) /) {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04003165 return ($1, "");
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003166 }
3167 else {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04003168 return (0, "");
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003169 }
3170 }
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04003171 elsif($InfoType eq "pointer_type")
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003172 {
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04003173 if($Info=~/ptd[ ]*:[ ]*@(\d+) /) {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04003174 return ($1, "*");
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003175 }
3176 else {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04003177 return (0, "");
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003178 }
3179 }
3180 else {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04003181 return (0, "");
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003182 }
3183}
3184
3185sub getSymbolInfo_All()
3186{
3187 foreach (sort {int($b)<=>int($a)} keys(%{$LibInfo{$Version}{"info"}}))
3188 { # reverse order
3189 if($LibInfo{$Version}{"info_type"}{$_} eq "function_decl") {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04003190 getSymbolInfo($_);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003191 }
3192 }
3193}
3194
3195sub getVarInfo_All()
3196{
3197 foreach (sort {int($b)<=>int($a)} keys(%{$LibInfo{$Version}{"info"}}))
3198 { # reverse order
3199 if($LibInfo{$Version}{"info_type"}{$_} eq "var_decl") {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04003200 getVarInfo($_);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003201 }
3202 }
3203}
3204
3205sub isBuiltIn($) {
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04003206 return ($_[0] and $_[0]=~/\<built\-in\>|\<internal\>|\A\./);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003207}
3208
3209sub getVarInfo($)
3210{
3211 my $InfoId = $_[0];
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04003212 if(my $NSid = getNameSpaceId($InfoId))
3213 {
3214 my $NSInfoType = $LibInfo{$Version}{"info_type"}{$NSid};
3215 if($NSInfoType and $NSInfoType eq "function_decl") {
3216 return;
3217 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003218 }
3219 ($SymbolInfo{$Version}{$InfoId}{"Header"}, $SymbolInfo{$Version}{$InfoId}{"Line"}) = getLocation($InfoId);
3220 if(not $SymbolInfo{$Version}{$InfoId}{"Header"}
3221 or isBuiltIn($SymbolInfo{$Version}{$InfoId}{"Header"})) {
3222 delete($SymbolInfo{$Version}{$InfoId});
3223 return;
3224 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04003225 my $ShortName = getTreeStr(getTreeAttr_Name($InfoId));
Andrey Ponomarenko85043792012-05-14 16:48:07 +04003226 if(not $ShortName) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003227 delete($SymbolInfo{$Version}{$InfoId});
3228 return;
3229 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +04003230 if($ShortName=~/\Atmp_add_class_\d+\Z/) {
3231 delete($SymbolInfo{$Version}{$InfoId});
3232 return;
3233 }
3234 $SymbolInfo{$Version}{$InfoId}{"ShortName"} = $ShortName;
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04003235 $SymbolInfo{$Version}{$InfoId}{"MnglName"} = getTreeStr(getTreeAttr_Mngl($InfoId));
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003236 if($SymbolInfo{$Version}{$InfoId}{"MnglName"}
3237 and $SymbolInfo{$Version}{$InfoId}{"MnglName"}!~/\A_Z/)
3238 { # validate mangled name
3239 delete($SymbolInfo{$Version}{$InfoId});
3240 return;
3241 }
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04003242 if(not $SymbolInfo{$Version}{$InfoId}{"MnglName"}
Andrey Ponomarenko85043792012-05-14 16:48:07 +04003243 and $ShortName=~/\A_Z/)
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04003244 { # _ZTS, etc.
Andrey Ponomarenko85043792012-05-14 16:48:07 +04003245 $SymbolInfo{$Version}{$InfoId}{"MnglName"} = $ShortName;
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04003246 }
3247 if(isPrivateData($SymbolInfo{$Version}{$InfoId}{"MnglName"}))
3248 { # non-public global data
3249 delete($SymbolInfo{$Version}{$InfoId});
3250 return;
3251 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003252 $SymbolInfo{$Version}{$InfoId}{"Data"} = 1;
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04003253 if(my $Rid = getTypeId($InfoId))
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04003254 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04003255 if(not $TypeInfo{$Version}{$Rid}{"Name"})
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04003256 { # typename_type
3257 delete($SymbolInfo{$Version}{$InfoId});
3258 return;
3259 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04003260 $SymbolInfo{$Version}{$InfoId}{"Return"} = $Rid;
3261 my $Val = getDataVal($InfoId, $Rid);
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04003262 if(defined $Val) {
3263 $SymbolInfo{$Version}{$InfoId}{"Value"} = $Val;
3264 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003265 }
3266 set_Class_And_Namespace($InfoId);
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04003267 if(my $ClassId = $SymbolInfo{$Version}{$InfoId}{"Class"})
3268 {
3269 if(not $TypeInfo{$Version}{$ClassId}{"Name"})
3270 { # templates
3271 delete($SymbolInfo{$Version}{$InfoId});
3272 return;
3273 }
3274 }
Andrey Ponomarenko35c44fd2012-06-18 17:50:25 +04003275 if($LibInfo{$Version}{"info"}{$InfoId}=~/ lang:[ ]*C /i)
3276 { # extern "C"
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003277 $SymbolInfo{$Version}{$InfoId}{"Lang"} = "C";
Andrey Ponomarenko35c44fd2012-06-18 17:50:25 +04003278 $SymbolInfo{$Version}{$InfoId}{"MnglName"} = $ShortName;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003279 }
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04003280 if($UserLang and $UserLang eq "C")
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003281 { # --lang=C option
Andrey Ponomarenko85043792012-05-14 16:48:07 +04003282 $SymbolInfo{$Version}{$InfoId}{"MnglName"} = $ShortName;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003283 }
Andrey Ponomarenko5c09ef32012-06-14 18:17:33 +04003284 if(not $CheckHeadersOnly)
3285 {
3286 if(not $SymbolInfo{$Version}{$InfoId}{"Class"})
3287 {
3288 if(not $SymbolInfo{$Version}{$InfoId}{"MnglName"}
3289 or not link_symbol($SymbolInfo{$Version}{$InfoId}{"MnglName"}, $Version, "-Deps"))
3290 {
3291 if(link_symbol($ShortName, $Version, "-Deps"))
3292 { # "const" global data is mangled as _ZL... in the TU dump
3293 # but not mangled when compiling a C shared library
3294 $SymbolInfo{$Version}{$InfoId}{"MnglName"} = $ShortName;
3295 }
3296 }
3297 }
3298 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003299 if($COMMON_LANGUAGE{$Version} eq "C++")
3300 {
3301 if(not $SymbolInfo{$Version}{$InfoId}{"MnglName"})
3302 { # for some symbols (_ZTI) the short name is the mangled name
3303 if($ShortName=~/\A_Z/) {
3304 $SymbolInfo{$Version}{$InfoId}{"MnglName"} = $ShortName;
3305 }
3306 }
3307 if(not $SymbolInfo{$Version}{$InfoId}{"MnglName"})
3308 { # try to mangle symbol (link with libraries)
3309 $SymbolInfo{$Version}{$InfoId}{"MnglName"} = linkSymbol($InfoId);
3310 }
3311 if($OStarget eq "windows")
3312 {
3313 if(my $Mangled = $mangled_name{$Version}{modelUnmangled($InfoId, "MSVC")})
3314 { # link MS C++ symbols from library with GCC symbols from headers
3315 $SymbolInfo{$Version}{$InfoId}{"MnglName"} = $Mangled;
3316 }
3317 }
3318 }
3319 if(not $SymbolInfo{$Version}{$InfoId}{"MnglName"}) {
3320 $SymbolInfo{$Version}{$InfoId}{"MnglName"} = $ShortName;
3321 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +04003322 if(my $Symbol = $SymbolInfo{$Version}{$InfoId}{"MnglName"})
3323 {
3324 if(not selectSymbol($Symbol, $SymbolInfo{$Version}{$InfoId}, "Dump", $Version))
3325 { # non-target symbols
3326 delete($SymbolInfo{$Version}{$InfoId});
3327 return;
3328 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003329 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04003330 if(my $Rid = $SymbolInfo{$Version}{$InfoId}{"Return"})
3331 {
3332 if(defined $MissedTypedef{$Version}{$Rid})
3333 {
3334 if(my $AddedTid = $MissedTypedef{$Version}{$Rid}{"Tid"}) {
3335 $SymbolInfo{$Version}{$InfoId}{"Return"} = $AddedTid;
3336 }
3337 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003338 }
3339 setFuncAccess($InfoId);
3340 if($SymbolInfo{$Version}{$InfoId}{"MnglName"}=~/\A_ZTV/) {
3341 delete($SymbolInfo{$Version}{$InfoId}{"Return"});
3342 }
3343 if($ShortName=~/\A(_Z|\?)/) {
3344 delete($SymbolInfo{$Version}{$InfoId}{"ShortName"});
3345 }
3346}
3347
Andrey Ponomarenko85043792012-05-14 16:48:07 +04003348sub isConstType($$)
3349{
3350 my ($TypeId, $LibVersion) = @_;
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04003351 my %Base = get_Type($TypeId, $LibVersion);
Andrey Ponomarenko85043792012-05-14 16:48:07 +04003352 while(defined $Base{"Type"} and $Base{"Type"} eq "Typedef") {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04003353 %Base = get_OneStep_BaseType($Base{"Tid"}, $LibVersion);
Andrey Ponomarenko85043792012-05-14 16:48:07 +04003354 }
3355 return ($Base{"Type"} eq "Const");
3356}
3357
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003358sub getTrivialName($$)
3359{
3360 my ($TypeInfoId, $TypeId) = @_;
3361 my %TypeAttr = ();
3362 $TypeAttr{"Name"} = getNameByInfo($TypeInfoId);
3363 if(not $TypeAttr{"Name"}) {
3364 $TypeAttr{"Name"} = getTreeTypeName($TypeId);
3365 }
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04003366 ($TypeAttr{"Header"}, $TypeAttr{"Line"}) = getLocation($TypeInfoId);
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04003367 $TypeAttr{"Type"} = getTypeType($TypeId);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003368 $TypeAttr{"Name"}=~s/<(.+)\Z//g; # GCC 3.4.4 add template params to the name
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04003369 if(isAnon($TypeAttr{"Name"}))
3370 {
3371 my $NameSpaceId = $TypeId;
3372 while(my $NSId = getNameSpaceId(getTypeDeclId($NameSpaceId)))
3373 { # searching for a first not anon scope
3374 if($NSId eq $NameSpaceId) {
3375 last;
3376 }
3377 else
3378 {
3379 $TypeAttr{"NameSpace"} = getNameSpace(getTypeDeclId($TypeId));
3380 if(not $TypeAttr{"NameSpace"}
3381 or isNotAnon($TypeAttr{"NameSpace"})) {
3382 last;
3383 }
3384 }
3385 $NameSpaceId=$NSId;
3386 }
3387 }
3388 else
3389 {
3390 if(my $NameSpaceId = getNameSpaceId($TypeInfoId))
3391 {
3392 if($NameSpaceId ne $TypeId) {
3393 $TypeAttr{"NameSpace"} = getNameSpace($TypeInfoId);
3394 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003395 }
3396 }
3397 if($TypeAttr{"NameSpace"} and isNotAnon($TypeAttr{"Name"})) {
3398 $TypeAttr{"Name"} = $TypeAttr{"NameSpace"}."::".$TypeAttr{"Name"};
3399 }
3400 $TypeAttr{"Name"} = formatName($TypeAttr{"Name"});
3401 if(isAnon($TypeAttr{"Name"}))
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04003402 { # anon-struct-header.h-line
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04003403 $TypeAttr{"Name"} = "anon-".lc($TypeAttr{"Type"})."-";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003404 $TypeAttr{"Name"} .= $TypeAttr{"Header"}."-".$TypeAttr{"Line"};
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04003405 if($TypeAttr{"NameSpace"}) {
3406 $TypeAttr{"Name"} = $TypeAttr{"NameSpace"}."::".$TypeAttr{"Name"};
3407 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003408 }
Andrey Ponomarenkob8d203d2012-05-25 18:11:07 +04003409 if(defined $TemplateInstance{$Version}{"Type"}{$TypeId}
3410 and getTypeDeclId($TypeId) eq $TypeInfoId)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003411 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04003412 my @TParams = getTParams($TypeId, "Type");
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003413 if(not @TParams)
3414 { # template declarations with abstract params
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003415 return ("", "");
3416 }
3417 $TypeAttr{"Name"} = formatName($TypeAttr{"Name"}."< ".join(", ", @TParams)." >");
3418 }
3419 return ($TypeAttr{"Name"}, $TypeAttr{"NameSpace"});
3420}
3421
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04003422sub getTrivialTypeAttr($)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003423{
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04003424 my $TypeId = $_[0];
3425 my $TypeInfoId = getTypeDeclId($_[0]);
Andrey Ponomarenko85043792012-05-14 16:48:07 +04003426
3427 if($TemplateDecl{$Version}{$TypeId})
3428 { # template_decl
3429 return ();
3430 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04003431 if(my $ScopeId = getTreeAttr_Scpe($TypeInfoId))
3432 {
3433 if($TemplateDecl{$Version}{$ScopeId})
3434 { # template_decl
3435 return ();
3436 }
3437 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +04003438
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003439 my %TypeAttr = ();
3440 if(getTypeTypeByTypeId($TypeId)!~/\A(Intrinsic|Union|Struct|Enum|Class)\Z/) {
3441 return ();
3442 }
3443 setTypeAccess($TypeId, \%TypeAttr);
3444 ($TypeAttr{"Header"}, $TypeAttr{"Line"}) = getLocation($TypeInfoId);
3445 if(isBuiltIn($TypeAttr{"Header"}))
3446 {
3447 delete($TypeAttr{"Header"});
3448 delete($TypeAttr{"Line"});
3449 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04003450 $TypeAttr{"Type"} = getTypeType($TypeId);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003451 ($TypeAttr{"Name"}, $TypeAttr{"NameSpace"}) = getTrivialName($TypeInfoId, $TypeId);
3452 if(not $TypeAttr{"Name"}) {
3453 return ();
3454 }
3455 if(not $TypeAttr{"NameSpace"}) {
3456 delete($TypeAttr{"NameSpace"});
3457 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04003458 if(defined $TemplateInstance{$Version}{"Type"}{$TypeId})
Andrey Ponomarenko16934472012-03-29 15:37:04 +04003459 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04003460 if(my @TParams = getTParams($TypeId, "Type"))
Andrey Ponomarenko16934472012-03-29 15:37:04 +04003461 {
3462 foreach my $Pos (0 .. $#TParams) {
3463 $TypeAttr{"TParam"}{$Pos}{"name"}=$TParams[$Pos];
3464 }
3465 }
3466 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003467 if(my $Size = getSize($TypeId)) {
3468 $TypeAttr{"Size"} = $Size/$BYTE_SIZE;
3469 }
3470 if($TypeAttr{"Type"} eq "Struct"
3471 and detect_lang($TypeId))
3472 {
3473 $TypeAttr{"Type"} = "Class";
Andrey Ponomarenko85043792012-05-14 16:48:07 +04003474 $TypeAttr{"Copied"} = 1; # default, will be changed in getSymbolInfo()
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003475 }
3476 if($TypeAttr{"Type"} eq "Struct"
Andrey Ponomarenko85043792012-05-14 16:48:07 +04003477 or $TypeAttr{"Type"} eq "Class")
3478 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04003479 my $Skip = setBaseClasses($TypeId, \%TypeAttr);
Andrey Ponomarenko85043792012-05-14 16:48:07 +04003480 if($Skip) {
3481 return ();
3482 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003483 }
3484 setSpec($TypeId, \%TypeAttr);
3485 setTypeMemb($TypeId, \%TypeAttr);
3486 $TypeAttr{"Tid"} = $TypeId;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003487 if(my $VTable = $ClassVTable_Content{$Version}{$TypeAttr{"Name"}})
3488 {
3489 my @Entries = split(/\n/, $VTable);
3490 foreach (1 .. $#Entries)
3491 {
3492 my $Entry = $Entries[$_];
3493 if($Entry=~/\A(\d+)\s+(.+)\Z/) {
3494 $TypeAttr{"VTable"}{$1} = $2;
3495 }
3496 }
3497 }
3498 return %TypeAttr;
3499}
3500
3501sub detect_lang($)
3502{
3503 my $TypeId = $_[0];
3504 my $Info = $LibInfo{$Version}{"info"}{$TypeId};
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04003505 if(check_gcc($GCC_PATH, "4"))
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04003506 { # GCC 4 fncs-node points to only non-artificial methods
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003507 return ($Info=~/(fncs)[ ]*:[ ]*@(\d+) /);
3508 }
3509 else
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04003510 { # GCC 3
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04003511 my $Fncs = getTreeAttr_Fncs($TypeId);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003512 while($Fncs)
3513 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04003514 if($LibInfo{$Version}{"info"}{$Fncs}!~/artificial/) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003515 return 1;
3516 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04003517 $Fncs = getTreeAttr_Chan($Fncs);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003518 }
3519 }
3520 return 0;
3521}
3522
3523sub setSpec($$)
3524{
3525 my ($TypeId, $TypeAttr) = @_;
3526 my $Info = $LibInfo{$Version}{"info"}{$TypeId};
3527 if($Info=~/\s+spec\s+/) {
3528 $TypeAttr->{"Spec"} = 1;
3529 }
3530}
3531
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04003532sub setBaseClasses($$)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003533{
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04003534 my ($TypeId, $TypeAttr) = @_;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003535 my $Info = $LibInfo{$Version}{"info"}{$TypeId};
3536 if($Info=~/binf[ ]*:[ ]*@(\d+) /)
3537 {
3538 $Info = $LibInfo{$Version}{"info"}{$1};
3539 my $Pos = 0;
3540 while($Info=~s/(pub|public|prot|protected|priv|private|)[ ]+binf[ ]*:[ ]*@(\d+) //)
3541 {
3542 my ($Access, $BInfoId) = ($1, $2);
3543 my $ClassId = getBinfClassId($BInfoId);
Andrey Ponomarenko85043792012-05-14 16:48:07 +04003544 my $CType = $LibInfo{$Version}{"info_type"}{$ClassId};
3545 if(not $CType or $CType eq "template_type_parm"
3546 or $CType eq "typename_type")
3547 { # skip
3548 return 1;
3549 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003550 my $BaseInfo = $LibInfo{$Version}{"info"}{$BInfoId};
3551 if($Access=~/prot/)
3552 {
3553 $TypeAttr->{"Base"}{$ClassId}{"access"} = "protected";
3554 }
3555 elsif($Access=~/priv/)
3556 {
3557 $TypeAttr->{"Base"}{$ClassId}{"access"} = "private";
3558 }
3559 $TypeAttr->{"Base"}{$ClassId}{"pos"} = $Pos++;
3560 if($BaseInfo=~/virt/)
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04003561 { # virtual base
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003562 $TypeAttr->{"Base"}{$ClassId}{"virtual"} = 1;
3563 }
3564 $Class_SubClasses{$Version}{$ClassId}{$TypeId}=1;
3565 }
3566 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +04003567 return 0;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003568}
3569
3570sub getBinfClassId($)
3571{
3572 my $Info = $LibInfo{$Version}{"info"}{$_[0]};
3573 $Info=~/type[ ]*:[ ]*@(\d+) /;
3574 return $1;
3575}
3576
3577sub unmangledFormat($$)
3578{
3579 my ($Name, $LibVersion) = @_;
3580 $Name = uncover_typedefs($Name, $LibVersion);
3581 while($Name=~s/([^\w>*])(const|volatile)(,|>|\Z)/$1$3/g){};
3582 $Name=~s/\(\w+\)(\d)/$1/;
3583 return $Name;
3584}
3585
3586sub modelUnmangled($$)
3587{
3588 my ($InfoId, $Compiler) = @_;
3589 if($Cache{"modelUnmangled"}{$Version}{$Compiler}{$InfoId}) {
3590 return $Cache{"modelUnmangled"}{$Version}{$Compiler}{$InfoId};
3591 }
3592 my $PureSignature = $SymbolInfo{$Version}{$InfoId}{"ShortName"};
3593 if($SymbolInfo{$Version}{$InfoId}{"Destructor"}) {
3594 $PureSignature = "~".$PureSignature;
3595 }
3596 if(not $SymbolInfo{$Version}{$InfoId}{"Data"})
3597 {
3598 my (@Params, @ParamTypes) = ();
3599 if(defined $SymbolInfo{$Version}{$InfoId}{"Param"}
3600 and not $SymbolInfo{$Version}{$InfoId}{"Destructor"}) {
3601 @Params = keys(%{$SymbolInfo{$Version}{$InfoId}{"Param"}});
3602 }
3603 foreach my $ParamPos (sort {int($a) <=> int($b)} @Params)
3604 { # checking parameters
3605 my $PId = $SymbolInfo{$Version}{$InfoId}{"Param"}{$ParamPos}{"type"};
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04003606 my %PType = get_PureType($PId, $Version);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003607 my $PTName = unmangledFormat($PType{"Name"}, $Version);
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04003608 $PTName=~s/\b(restrict|register)\b//g;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003609 if($Compiler eq "MSVC") {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04003610 $PTName=~s/\blong long\b/__int64/;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003611 }
3612 @ParamTypes = (@ParamTypes, $PTName);
3613 }
3614 if(@ParamTypes) {
3615 $PureSignature .= "(".join(", ", @ParamTypes).")";
3616 }
3617 else
3618 {
3619 if($Compiler eq "MSVC")
3620 {
3621 $PureSignature .= "(void)";
3622 }
3623 else
3624 { # GCC
3625 $PureSignature .= "()";
3626 }
3627 }
3628 $PureSignature = delete_keywords($PureSignature);
3629 }
3630 if(my $ClassId = $SymbolInfo{$Version}{$InfoId}{"Class"})
3631 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04003632 my $ClassName = unmangledFormat($TypeInfo{$Version}{$ClassId}{"Name"}, $Version);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003633 $PureSignature = $ClassName."::".$PureSignature;
3634 }
3635 elsif(my $NS = $SymbolInfo{$Version}{$InfoId}{"NameSpace"}) {
3636 $PureSignature = $NS."::".$PureSignature;
3637 }
3638 if($SymbolInfo{$Version}{$InfoId}{"Const"}) {
3639 $PureSignature .= " const";
3640 }
3641 if($SymbolInfo{$Version}{$InfoId}{"Volatile"}) {
3642 $PureSignature .= " volatile";
3643 }
3644 my $ShowReturn = 0;
3645 if($Compiler eq "MSVC"
3646 and $SymbolInfo{$Version}{$InfoId}{"Data"})
3647 {
3648 $ShowReturn=1;
3649 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04003650 elsif(defined $TemplateInstance{$Version}{"Func"}{$InfoId}
3651 and keys(%{$TemplateInstance{$Version}{"Func"}{$InfoId}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003652 {
3653 $ShowReturn=1;
3654 }
3655 if($ShowReturn)
3656 { # mangled names for template function specializations include return value
3657 if(my $ReturnId = $SymbolInfo{$Version}{$InfoId}{"Return"})
3658 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04003659 my %RType = get_PureType($ReturnId, $Version);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003660 my $ReturnName = unmangledFormat($RType{"Name"}, $Version);
3661 $PureSignature = $ReturnName." ".$PureSignature;
3662 }
3663 }
3664 return ($Cache{"modelUnmangled"}{$Version}{$Compiler}{$InfoId} = formatName($PureSignature));
3665}
3666
3667sub mangle_symbol($$$)
3668{ # mangling for simple methods
3669 # see gcc-4.6.0/gcc/cp/mangle.c
3670 my ($InfoId, $LibVersion, $Compiler) = @_;
3671 if($Cache{"mangle_symbol"}{$LibVersion}{$InfoId}{$Compiler}) {
3672 return $Cache{"mangle_symbol"}{$LibVersion}{$InfoId}{$Compiler};
3673 }
3674 my $Mangled = "";
3675 if($Compiler eq "GCC") {
Andrey Ponomarenko16934472012-03-29 15:37:04 +04003676 $Mangled = mangle_symbol_GCC($InfoId, $LibVersion);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003677 }
3678 elsif($Compiler eq "MSVC") {
Andrey Ponomarenko16934472012-03-29 15:37:04 +04003679 $Mangled = mangle_symbol_MSVC($InfoId, $LibVersion);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003680 }
3681 return ($Cache{"mangle_symbol"}{$LibVersion}{$InfoId}{$Compiler} = $Mangled);
3682}
3683
Andrey Ponomarenko16934472012-03-29 15:37:04 +04003684sub mangle_symbol_MSVC($$)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003685{
3686 my ($InfoId, $LibVersion) = @_;
3687 return "";
3688}
3689
Andrey Ponomarenko16934472012-03-29 15:37:04 +04003690sub mangle_symbol_GCC($$)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003691{ # see gcc-4.6.0/gcc/cp/mangle.c
3692 my ($InfoId, $LibVersion) = @_;
3693 my ($Mangled, $ClassId, $NameSpace) = ("_Z", 0, "");
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04003694 my $Return = $SymbolInfo{$LibVersion}{$InfoId}{"Return"};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003695 my %Repl = ();# SN_ replacements
3696 if($ClassId = $SymbolInfo{$LibVersion}{$InfoId}{"Class"})
3697 {
3698 my $MangledClass = mangle_param($ClassId, $LibVersion, \%Repl);
3699 if($MangledClass!~/\AN/) {
3700 $MangledClass = "N".$MangledClass;
3701 }
3702 else {
3703 $MangledClass=~s/E\Z//;
3704 }
3705 if($SymbolInfo{$LibVersion}{$InfoId}{"Volatile"}) {
3706 $MangledClass=~s/\AN/NV/;
3707 }
3708 if($SymbolInfo{$LibVersion}{$InfoId}{"Const"}) {
3709 $MangledClass=~s/\AN/NK/;
3710 }
3711 $Mangled .= $MangledClass;
3712 }
3713 elsif($NameSpace = $SymbolInfo{$LibVersion}{$InfoId}{"NameSpace"})
3714 { # mangled by name due to the absence of structured info
3715 my $MangledNS = mangle_ns($NameSpace, $LibVersion, \%Repl);
3716 if($MangledNS!~/\AN/) {
3717 $MangledNS = "N".$MangledNS;
3718 }
3719 else {
3720 $MangledNS=~s/E\Z//;
3721 }
3722 $Mangled .= $MangledNS;
3723 }
3724 my ($ShortName, $TmplParams) = template_base($SymbolInfo{$LibVersion}{$InfoId}{"ShortName"});
Andrey Ponomarenko16934472012-03-29 15:37:04 +04003725 my @TParams = ();
Andrey Ponomarenko35c44fd2012-06-18 17:50:25 +04003726 if(my @TPos = keys(%{$SymbolInfo{$LibVersion}{$InfoId}{"TParam"}}))
Andrey Ponomarenko16934472012-03-29 15:37:04 +04003727 { # parsing mode
Andrey Ponomarenko35c44fd2012-06-18 17:50:25 +04003728 foreach (@TPos) {
3729 push(@TParams, $SymbolInfo{$LibVersion}{$InfoId}{"TParam"}{$_}{"name"});
3730 }
Andrey Ponomarenko16934472012-03-29 15:37:04 +04003731 }
3732 elsif($TmplParams)
3733 { # remangling mode
3734 # support for old ABI dumps
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003735 @TParams = separate_params($TmplParams, 0);
3736 }
3737 if($SymbolInfo{$LibVersion}{$InfoId}{"Constructor"}) {
3738 $Mangled .= "C1";
3739 }
3740 elsif($SymbolInfo{$LibVersion}{$InfoId}{"Destructor"}) {
3741 $Mangled .= "D0";
3742 }
3743 elsif($ShortName)
3744 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04003745 if($SymbolInfo{$LibVersion}{$InfoId}{"Data"})
3746 {
Andrey Ponomarenko16934472012-03-29 15:37:04 +04003747 if(not $SymbolInfo{$LibVersion}{$InfoId}{"Class"}
Andrey Ponomarenko85043792012-05-14 16:48:07 +04003748 and isConstType($Return, $LibVersion))
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04003749 { # "const" global data is mangled as _ZL...
3750 $Mangled .= "L";
3751 }
3752 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003753 if($ShortName=~/\Aoperator(\W.*)\Z/)
3754 {
3755 my $Op = $1;
3756 $Op=~s/\A[ ]+//g;
3757 if(my $OpMngl = $OperatorMangling{$Op}) {
3758 $Mangled .= $OpMngl;
3759 }
3760 else { # conversion operator
3761 $Mangled .= "cv".mangle_param(getTypeIdByName($Op, $LibVersion), $LibVersion, \%Repl);
3762 }
3763 }
3764 else {
3765 $Mangled .= length($ShortName).$ShortName;
3766 }
3767 if(@TParams)
3768 { # templates
3769 $Mangled .= "I";
3770 foreach my $TParam (@TParams) {
3771 $Mangled .= mangle_template_param($TParam, $LibVersion, \%Repl);
3772 }
3773 $Mangled .= "E";
3774 }
3775 if(not $ClassId and @TParams) {
3776 add_substitution($ShortName, \%Repl, 0);
3777 }
3778 }
3779 if($ClassId or $NameSpace) {
3780 $Mangled .= "E";
3781 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +04003782 if(@TParams)
3783 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04003784 if($Return) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003785 $Mangled .= mangle_param($Return, $LibVersion, \%Repl);
3786 }
3787 }
3788 if(not $SymbolInfo{$LibVersion}{$InfoId}{"Data"})
3789 {
3790 my @Params = ();
3791 if(defined $SymbolInfo{$LibVersion}{$InfoId}{"Param"}
3792 and not $SymbolInfo{$LibVersion}{$InfoId}{"Destructor"}) {
3793 @Params = keys(%{$SymbolInfo{$LibVersion}{$InfoId}{"Param"}});
3794 }
3795 foreach my $ParamPos (sort {int($a) <=> int($b)} @Params)
3796 { # checking parameters
3797 my $ParamType_Id = $SymbolInfo{$LibVersion}{$InfoId}{"Param"}{$ParamPos}{"type"};
3798 $Mangled .= mangle_param($ParamType_Id, $LibVersion, \%Repl);
3799 }
3800 if(not @Params) {
3801 $Mangled .= "v";
3802 }
3803 }
3804 $Mangled = correct_incharge($InfoId, $LibVersion, $Mangled);
3805 $Mangled = write_stdcxx_substitution($Mangled);
3806 if($Mangled eq "_Z") {
3807 return "";
3808 }
3809 return $Mangled;
3810}
3811
3812sub correct_incharge($$$)
3813{
3814 my ($InfoId, $LibVersion, $Mangled) = @_;
3815 if($SymbolInfo{$LibVersion}{$InfoId}{"Constructor"})
3816 {
3817 if($MangledNames{$LibVersion}{$Mangled}) {
3818 $Mangled=~s/C1E/C2E/;
3819 }
3820 }
3821 elsif($SymbolInfo{$LibVersion}{$InfoId}{"Destructor"})
3822 {
3823 if($MangledNames{$LibVersion}{$Mangled}) {
3824 $Mangled=~s/D0E/D1E/;
3825 }
3826 if($MangledNames{$LibVersion}{$Mangled}) {
3827 $Mangled=~s/D1E/D2E/;
3828 }
3829 }
3830 return $Mangled;
3831}
3832
3833sub template_base($)
3834{ # NOTE: std::_Vector_base<mysqlpp::mysql_type_info>::_Vector_impl
Andrey Ponomarenko16934472012-03-29 15:37:04 +04003835 # NOTE: operators: >>, <<
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003836 my $Name = $_[0];
Andrey Ponomarenko16934472012-03-29 15:37:04 +04003837 if($Name!~/>\Z/ or $Name!~/</) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003838 return $Name;
3839 }
3840 my $TParams = $Name;
Andrey Ponomarenko16934472012-03-29 15:37:04 +04003841 while(my $CPos = find_center($TParams, "<"))
3842 { # search for the last <T>
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003843 $TParams = substr($TParams, $CPos);
3844 }
Andrey Ponomarenko16934472012-03-29 15:37:04 +04003845 if($TParams=~s/\A<(.+)>\Z/$1/) {
3846 $Name=~s/<\Q$TParams\E>\Z//;
3847 }
3848 else
3849 { # error
3850 $TParams = "";
3851 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003852 return ($Name, $TParams);
3853}
3854
3855sub get_sub_ns($)
3856{
3857 my $Name = $_[0];
3858 my @NS = ();
Andrey Ponomarenko16934472012-03-29 15:37:04 +04003859 while(my $CPos = find_center($Name, ":"))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003860 {
3861 push(@NS, substr($Name, 0, $CPos));
3862 $Name = substr($Name, $CPos);
3863 $Name=~s/\A:://;
3864 }
3865 return (join("::", @NS), $Name);
3866}
3867
3868sub mangle_ns($$$)
3869{
3870 my ($Name, $LibVersion, $Repl) = @_;
3871 if(my $Tid = $TName_Tid{$LibVersion}{$Name})
3872 {
3873 my $Mangled = mangle_param($Tid, $LibVersion, $Repl);
3874 $Mangled=~s/\AN(.+)E\Z/$1/;
3875 return $Mangled;
3876
3877 }
3878 else
3879 {
3880 my ($MangledNS, $SubNS) = ("", "");
3881 ($SubNS, $Name) = get_sub_ns($Name);
3882 if($SubNS) {
3883 $MangledNS .= mangle_ns($SubNS, $LibVersion, $Repl);
3884 }
3885 $MangledNS .= length($Name).$Name;
3886 add_substitution($MangledNS, $Repl, 0);
3887 return $MangledNS;
3888 }
3889}
3890
3891sub mangle_param($$$)
3892{
3893 my ($PTid, $LibVersion, $Repl) = @_;
3894 my ($MPrefix, $Mangled) = ("", "");
3895 my %ReplCopy = %{$Repl};
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04003896 my %BaseType = get_BaseType($PTid, $LibVersion);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003897 my $BaseType_Name = $BaseType{"Name"};
3898 if(not $BaseType_Name) {
3899 return "";
3900 }
3901 my ($ShortName, $TmplParams) = template_base($BaseType_Name);
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04003902 my $Suffix = get_BaseTypeQual($PTid, $LibVersion);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003903 while($Suffix=~s/\s*(const|volatile|restrict)\Z//g){};
3904 while($Suffix=~/(&|\*|const)\Z/)
3905 {
3906 if($Suffix=~s/[ ]*&\Z//) {
3907 $MPrefix .= "R";
3908 }
3909 if($Suffix=~s/[ ]*\*\Z//) {
3910 $MPrefix .= "P";
3911 }
3912 if($Suffix=~s/[ ]*const\Z//)
3913 {
3914 if($MPrefix=~/R|P/
3915 or $Suffix=~/&|\*/) {
3916 $MPrefix .= "K";
3917 }
3918 }
3919 if($Suffix=~s/[ ]*volatile\Z//) {
3920 $MPrefix .= "V";
3921 }
3922 #if($Suffix=~s/[ ]*restrict\Z//) {
3923 #$MPrefix .= "r";
3924 #}
3925 }
3926 if(my $Token = $IntrinsicMangling{$BaseType_Name}) {
3927 $Mangled .= $Token;
3928 }
3929 elsif($BaseType{"Type"}=~/(Class|Struct|Union|Enum)/)
3930 {
Andrey Ponomarenko16934472012-03-29 15:37:04 +04003931 my @TParams = ();
Andrey Ponomarenko35c44fd2012-06-18 17:50:25 +04003932 if(my @TPos = keys(%{$BaseType{"TParam"}}))
Andrey Ponomarenko16934472012-03-29 15:37:04 +04003933 { # parsing mode
Andrey Ponomarenko35c44fd2012-06-18 17:50:25 +04003934 foreach (@TPos) {
3935 push(@TParams, $BaseType{"TParam"}{$_}{"name"});
3936 }
Andrey Ponomarenko16934472012-03-29 15:37:04 +04003937 }
3938 elsif($TmplParams)
3939 { # remangling mode
3940 # support for old ABI dumps
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003941 @TParams = separate_params($TmplParams, 0);
3942 }
3943 my $MangledNS = "";
3944 my ($SubNS, $SName) = get_sub_ns($ShortName);
3945 if($SubNS) {
3946 $MangledNS .= mangle_ns($SubNS, $LibVersion, $Repl);
3947 }
3948 $MangledNS .= length($SName).$SName;
3949 if(@TParams) {
3950 add_substitution($MangledNS, $Repl, 0);
3951 }
3952 $Mangled .= "N".$MangledNS;
3953 if(@TParams)
3954 { # templates
3955 $Mangled .= "I";
3956 foreach my $TParam (@TParams) {
3957 $Mangled .= mangle_template_param($TParam, $LibVersion, $Repl);
3958 }
3959 $Mangled .= "E";
3960 }
3961 $Mangled .= "E";
3962 }
3963 elsif($BaseType{"Type"}=~/(FuncPtr|MethodPtr)/)
3964 {
3965 if($BaseType{"Type"} eq "MethodPtr") {
3966 $Mangled .= "M".mangle_param($BaseType{"Class"}, $LibVersion, $Repl)."F";
3967 }
3968 else {
3969 $Mangled .= "PF";
3970 }
3971 $Mangled .= mangle_param($BaseType{"Return"}, $LibVersion, $Repl);
3972 my @Params = keys(%{$BaseType{"Param"}});
3973 foreach my $Num (sort {int($a)<=>int($b)} @Params) {
3974 $Mangled .= mangle_param($BaseType{"Param"}{$Num}{"type"}, $LibVersion, $Repl);
3975 }
3976 if(not @Params) {
3977 $Mangled .= "v";
3978 }
3979 $Mangled .= "E";
3980 }
3981 elsif($BaseType{"Type"} eq "FieldPtr")
3982 {
3983 $Mangled .= "M".mangle_param($BaseType{"Class"}, $LibVersion, $Repl);
3984 $Mangled .= mangle_param($BaseType{"Return"}, $LibVersion, $Repl);
3985 }
3986 $Mangled = $MPrefix.$Mangled;# add prefix (RPK)
3987 if(my $Optimized = write_substitution($Mangled, \%ReplCopy))
3988 {
3989 if($Mangled eq $Optimized)
3990 {
3991 if($ShortName!~/::/)
3992 { # remove "N ... E"
3993 if($MPrefix) {
3994 $Mangled=~s/\A($MPrefix)N(.+)E\Z/$1$2/g;
3995 }
3996 else {
3997 $Mangled=~s/\AN(.+)E\Z/$1/g;
3998 }
3999 }
4000 }
4001 else {
4002 $Mangled = $Optimized;
4003 }
4004 }
4005 add_substitution($Mangled, $Repl, 1);
4006 return $Mangled;
4007}
4008
4009sub mangle_template_param($$$)
4010{ # types + literals
4011 my ($TParam, $LibVersion, $Repl) = @_;
4012 if(my $TPTid = $TName_Tid{$LibVersion}{$TParam}) {
4013 return mangle_param($TPTid, $LibVersion, $Repl);
4014 }
4015 elsif($TParam=~/\A(\d+)(\w+)\Z/)
4016 { # class_name<1u>::method(...)
4017 return "L".$IntrinsicMangling{$ConstantSuffixR{$2}}.$1."E";
4018 }
4019 elsif($TParam=~/\A\(([\w ]+)\)(\d+)\Z/)
4020 { # class_name<(signed char)1>::method(...)
4021 return "L".$IntrinsicMangling{$1}.$2."E";
4022 }
4023 elsif($TParam eq "true")
4024 { # class_name<true>::method(...)
4025 return "Lb1E";
4026 }
4027 elsif($TParam eq "false")
4028 { # class_name<true>::method(...)
4029 return "Lb0E";
4030 }
4031 else { # internal error
4032 return length($TParam).$TParam;
4033 }
4034}
4035
4036sub add_substitution($$$)
4037{
4038 my ($Value, $Repl, $Rec) = @_;
4039 if($Rec)
4040 { # subtypes
4041 my @Subs = ($Value);
4042 while($Value=~s/\A(R|P|K)//) {
4043 push(@Subs, $Value);
4044 }
4045 foreach (reverse(@Subs)) {
4046 add_substitution($_, $Repl, 0);
4047 }
4048 return;
4049 }
4050 return if($Value=~/\AS(\d*)_\Z/);
4051 $Value=~s/\AN(.+)E\Z/$1/g;
4052 return if(defined $Repl->{$Value});
4053 return if(length($Value)<=1);
4054 return if($StdcxxMangling{$Value});
4055 # check for duplicates
4056 my $Base = $Value;
4057 foreach my $Type (sort {$Repl->{$a}<=>$Repl->{$b}} sort keys(%{$Repl}))
4058 {
4059 my $Num = $Repl->{$Type};
4060 my $Replace = macro_mangle($Num);
4061 $Base=~s/\Q$Replace\E/$Type/;
4062 }
4063 if(my $OldNum = $Repl->{$Base})
4064 {
4065 $Repl->{$Value} = $OldNum;
4066 return;
4067 }
4068 my @Repls = sort {$b<=>$a} values(%{$Repl});
4069 if(@Repls) {
4070 $Repl->{$Value} = $Repls[0]+1;
4071 }
4072 else {
4073 $Repl->{$Value} = -1;
4074 }
4075 # register duplicates
4076 # upward
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04004077 $Base = $Value;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004078 foreach my $Type (sort {$Repl->{$a}<=>$Repl->{$b}} sort keys(%{$Repl}))
4079 {
4080 next if($Base eq $Type);
4081 my $Num = $Repl->{$Type};
4082 my $Replace = macro_mangle($Num);
4083 $Base=~s/\Q$Type\E/$Replace/;
4084 $Repl->{$Base} = $Repl->{$Value};
4085 }
4086}
4087
4088sub macro_mangle($)
4089{
4090 my $Num = $_[0];
4091 if($Num==-1) {
4092 return "S_";
4093 }
4094 else
4095 {
4096 my $Code = "";
4097 if($Num<10)
4098 { # S0_, S1_, S2_, ...
4099 $Code = $Num;
4100 }
4101 elsif($Num>=10 and $Num<=35)
4102 { # SA_, SB_, SC_, ...
4103 $Code = chr(55+$Num);
4104 }
4105 else
4106 { # S10_, S11_, S12_
4107 $Code = $Num-26; # 26 is length of english alphabet
4108 }
4109 return "S".$Code."_";
4110 }
4111}
4112
4113sub write_stdcxx_substitution($)
4114{
4115 my $Mangled = $_[0];
4116 if($StdcxxMangling{$Mangled}) {
4117 return $StdcxxMangling{$Mangled};
4118 }
4119 else
4120 {
4121 my @Repls = keys(%StdcxxMangling);
4122 @Repls = sort {length($b)<=>length($a)} sort {$b cmp $a} @Repls;
4123 foreach my $MangledType (@Repls)
4124 {
4125 my $Replace = $StdcxxMangling{$MangledType};
4126 #if($Mangled!~/$Replace/) {
4127 $Mangled=~s/N\Q$MangledType\EE/$Replace/g;
4128 $Mangled=~s/\Q$MangledType\E/$Replace/g;
4129 #}
4130 }
4131 }
4132 return $Mangled;
4133}
4134
4135sub write_substitution($$)
4136{
4137 my ($Mangled, $Repl) = @_;
4138 if(defined $Repl->{$Mangled}
4139 and my $MnglNum = $Repl->{$Mangled}) {
4140 $Mangled = macro_mangle($MnglNum);
4141 }
4142 else
4143 {
4144 my @Repls = keys(%{$Repl});
4145 #@Repls = sort {$Repl->{$a}<=>$Repl->{$b}} @Repls;
4146 # FIXME: how to apply replacements? by num or by pos
4147 @Repls = sort {length($b)<=>length($a)} sort {$b cmp $a} @Repls;
4148 foreach my $MangledType (@Repls)
4149 {
4150 my $Replace = macro_mangle($Repl->{$MangledType});
4151 if($Mangled!~/$Replace/) {
4152 $Mangled=~s/N\Q$MangledType\EE/$Replace/g;
4153 $Mangled=~s/\Q$MangledType\E/$Replace/g;
4154 }
4155 }
4156 }
4157 return $Mangled;
4158}
4159
4160sub delete_keywords($)
4161{
4162 my $TypeName = $_[0];
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04004163 $TypeName=~s/\b(enum|struct|union|class) //g;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004164 return $TypeName;
4165}
4166
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004167sub uncover_typedefs($$)
4168{
4169 my ($TypeName, $LibVersion) = @_;
4170 return "" if(not $TypeName);
4171 if(defined $Cache{"uncover_typedefs"}{$LibVersion}{$TypeName}) {
4172 return $Cache{"uncover_typedefs"}{$LibVersion}{$TypeName};
4173 }
4174 my ($TypeName_New, $TypeName_Pre) = (formatName($TypeName), "");
4175 while($TypeName_New ne $TypeName_Pre)
4176 {
4177 $TypeName_Pre = $TypeName_New;
4178 my $TypeName_Copy = $TypeName_New;
4179 my %Words = ();
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04004180 while($TypeName_Copy=~s/\b([a-z_]([\w:]*\w|))\b//io)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004181 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04004182 if(not $Intrinsic_Keywords{$1}) {
4183 $Words{$1} = 1;
4184 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004185 }
4186 foreach my $Word (keys(%Words))
4187 {
4188 my $BaseType_Name = $Typedef_BaseName{$LibVersion}{$Word};
4189 next if(not $BaseType_Name);
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04004190 next if($TypeName_New=~/\b(struct|union|enum)\s\Q$Word\E\b/);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004191 if($BaseType_Name=~/\([\*]+\)/)
4192 { # FuncPtr
4193 if($TypeName_New=~/\Q$Word\E(.*)\Z/)
4194 {
4195 my $Type_Suffix = $1;
4196 $TypeName_New = $BaseType_Name;
4197 if($TypeName_New=~s/\(([\*]+)\)/($1 $Type_Suffix)/) {
4198 $TypeName_New = formatName($TypeName_New);
4199 }
4200 }
4201 }
4202 else
4203 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04004204 if($TypeName_New=~s/\b\Q$Word\E\b/$BaseType_Name/g) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004205 $TypeName_New = formatName($TypeName_New);
4206 }
4207 }
4208 }
4209 }
4210 return ($Cache{"uncover_typedefs"}{$LibVersion}{$TypeName} = $TypeName_New);
4211}
4212
4213sub isInternal($)
4214{
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04004215 if($_[0] and my $Info = $LibInfo{$Version}{"info"}{$_[0]})
4216 {
4217 if($Info=~/mngl[ ]*:[ ]*@(\d+) /)
4218 {
4219 if($LibInfo{$Version}{"info"}{$1}=~/\*[ ]*INTERNAL[ ]*\*/)
4220 { # _ZN7mysqlpp8DateTimeC1ERKS0_ *INTERNAL*
4221 return 1;
4222 }
4223 }
4224 }
4225 return 0;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004226}
4227
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04004228sub getDataVal($$)
4229{
4230 my ($InfoId, $TypeId) = @_;
4231 if(my $Info = $LibInfo{$Version}{"info"}{$InfoId})
4232 {
4233 if($Info=~/init[ ]*:[ ]*@(\d+) /)
4234 {
4235 if(defined $LibInfo{$Version}{"info_type"}{$1}
4236 and $LibInfo{$Version}{"info_type"}{$1} eq "nop_expr")
4237 { # char const* data = "str"
4238 # NOTE: disabled
4239 if(my $NopExpr = $LibInfo{$Version}{"info"}{$1})
4240 {
4241 if($NopExpr=~/op 0[ ]*:[ ]*@(\d+) /)
4242 {
4243 if(defined $LibInfo{$Version}{"info_type"}{$1}
4244 and $LibInfo{$Version}{"info_type"}{$1} eq "addr_expr")
4245 {
4246 if(my $AddrExpr = $LibInfo{$Version}{"info"}{$1})
4247 {
4248 if($AddrExpr=~/op 0[ ]*:[ ]*@(\d+) /)
4249 {
4250 return getInitVal($1, $TypeId);
4251 }
4252 }
4253 }
4254 }
4255 }
4256 }
4257 else {
4258 return getInitVal($1, $TypeId);
4259 }
4260 }
4261 }
4262 return undef;
4263}
4264
4265sub getInitVal($$)
4266{
4267 my ($InfoId, $TypeId) = @_;
4268 if(my $Info = $LibInfo{$Version}{"info"}{$InfoId})
4269 {
4270 if(my $InfoType = $LibInfo{$Version}{"info_type"}{$InfoId})
4271 {
4272 if($InfoType eq "integer_cst")
4273 {
4274 my $Val = getNodeIntCst($InfoId);
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04004275 if($TypeId and $TypeInfo{$Version}{$TypeId}{"Name"}=~/\Achar(| const)\Z/)
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04004276 { # characters
4277 $Val = chr($Val);
4278 }
4279 return $Val;
4280 }
4281 elsif($InfoType eq "string_cst") {
4282 return getNodeStrCst($InfoId);
4283 }
4284 }
4285 }
4286 return undef;
4287}
4288
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004289sub set_Class_And_Namespace($)
4290{
4291 my $InfoId = $_[0];
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04004292 if(my $Info = $LibInfo{$Version}{"info"}{$InfoId})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004293 {
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04004294 if($Info=~/scpe[ ]*:[ ]*@(\d+) /)
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04004295 {
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04004296 my $NSInfoId = $1;
4297 if(my $InfoType = $LibInfo{$Version}{"info_type"}{$NSInfoId})
4298 {
4299 if($InfoType eq "namespace_decl") {
4300 $SymbolInfo{$Version}{$InfoId}{"NameSpace"} = getNameSpace($InfoId);
4301 }
4302 elsif($InfoType eq "record_type") {
4303 $SymbolInfo{$Version}{$InfoId}{"Class"} = $NSInfoId;
4304 }
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04004305 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004306 }
4307 }
4308 if($SymbolInfo{$Version}{$InfoId}{"Class"}
4309 or $SymbolInfo{$Version}{$InfoId}{"NameSpace"})
4310 { # identify language
4311 setLanguage($Version, "C++");
4312 }
4313}
4314
4315sub debugType($$)
4316{
4317 my ($Tid, $LibVersion) = @_;
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04004318 my %Type = get_Type($Tid, $LibVersion);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004319 printMsg("INFO", Dumper(\%Type));
4320}
4321
4322sub debugMangling($)
4323{
4324 my $LibVersion = $_[0];
4325 my %Mangled = ();
4326 foreach my $InfoId (keys(%{$SymbolInfo{$LibVersion}}))
4327 {
4328 if(my $Mngl = $SymbolInfo{$LibVersion}{$InfoId}{"MnglName"})
4329 {
4330 if($Mngl=~/\A(_Z|\?)/) {
4331 $Mangled{$Mngl}=$InfoId;
4332 }
4333 }
4334 }
4335 translateSymbols(keys(%Mangled), $LibVersion);
4336 foreach my $Mngl (keys(%Mangled))
4337 {
Andrey Ponomarenko85043792012-05-14 16:48:07 +04004338 my $U1 = modelUnmangled($Mangled{$Mngl}, "GCC");
4339 my $U2 = $tr_name{$Mngl};
4340 if($U1 ne $U2) {
4341 printMsg("INFO", "INCORRECT MANGLING:\n $Mngl\n $U1\n $U2\n");
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004342 }
4343 }
4344}
4345
4346sub linkSymbol($)
4347{ # link symbols from shared libraries
4348 # with the symbols from header files
4349 my $InfoId = $_[0];
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004350 # try to mangle symbol
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04004351 if((not check_gcc($GCC_PATH, "4") and $SymbolInfo{$Version}{$InfoId}{"Class"})
4352 or (check_gcc($GCC_PATH, "4") and not $SymbolInfo{$Version}{$InfoId}{"Class"}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004353 { # 1. GCC 3.x doesn't mangle class methods names in the TU dump (only functions and global data)
4354 # 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 +04004355 if(not $CheckHeadersOnly)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004356 {
4357 if(my $Mangled = $mangled_name_gcc{modelUnmangled($InfoId, "GCC")}) {
4358 return correct_incharge($InfoId, $Version, $Mangled);
4359 }
4360 }
Andrey Ponomarenko16934472012-03-29 15:37:04 +04004361 if($CheckHeadersOnly
4362 or not $BinaryOnly)
4363 { # 1. --headers-only mode
4364 # 2. not mangled src-only symbols
4365 if(my $Mangled = mangle_symbol($InfoId, $Version, "GCC")) {
4366 return $Mangled;
4367 }
4368 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004369 }
4370 return "";
4371}
4372
4373sub setLanguage($$)
4374{
4375 my ($LibVersion, $Lang) = @_;
4376 if(not $UserLang) {
4377 $COMMON_LANGUAGE{$LibVersion} = $Lang;
4378 }
4379}
4380
4381sub getSymbolInfo($)
4382{
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04004383 my $InfoId = $_[0];
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04004384 if(isInternal($InfoId)) {
4385 return;
4386 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04004387 ($SymbolInfo{$Version}{$InfoId}{"Header"}, $SymbolInfo{$Version}{$InfoId}{"Line"}) = getLocation($InfoId);
4388 if(not $SymbolInfo{$Version}{$InfoId}{"Header"}
Andrey Ponomarenkoa01311b2012-06-08 17:20:02 +04004389 or isBuiltIn($SymbolInfo{$Version}{$InfoId}{"Header"}))
4390 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04004391 delete($SymbolInfo{$Version}{$InfoId});
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004392 return;
4393 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04004394 setFuncAccess($InfoId);
4395 setFuncKind($InfoId);
Andrey Ponomarenkoa01311b2012-06-08 17:20:02 +04004396 if($SymbolInfo{$Version}{$InfoId}{"PseudoTemplate"})
4397 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04004398 delete($SymbolInfo{$Version}{$InfoId});
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004399 return;
4400 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04004401 $SymbolInfo{$Version}{$InfoId}{"Type"} = getFuncType($InfoId);
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04004402 if($SymbolInfo{$Version}{$InfoId}{"Return"} = getFuncReturn($InfoId))
4403 {
4404 if(not $TypeInfo{$Version}{$SymbolInfo{$Version}{$InfoId}{"Return"}}{"Name"})
4405 { # templates
4406 delete($SymbolInfo{$Version}{$InfoId});
4407 return;
4408 }
4409 }
4410 if(my $Rid = $SymbolInfo{$Version}{$InfoId}{"Return"})
4411 {
4412 if(defined $MissedTypedef{$Version}{$Rid})
4413 {
4414 if(my $AddedTid = $MissedTypedef{$Version}{$Rid}{"Tid"}) {
4415 $SymbolInfo{$Version}{$InfoId}{"Return"} = $AddedTid;
4416 }
4417 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004418 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04004419 if(not $SymbolInfo{$Version}{$InfoId}{"Return"}) {
4420 delete($SymbolInfo{$Version}{$InfoId}{"Return"});
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004421 }
Andrey Ponomarenkoa01311b2012-06-08 17:20:02 +04004422 my $Orig = getFuncOrig($InfoId);
4423 $SymbolInfo{$Version}{$InfoId}{"ShortName"} = getFuncShortName($Orig);
4424 if($SymbolInfo{$Version}{$InfoId}{"ShortName"}=~/\._/)
4425 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04004426 delete($SymbolInfo{$Version}{$InfoId});
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004427 return;
4428 }
Andrey Ponomarenkoa01311b2012-06-08 17:20:02 +04004429
4430 if(defined $TemplateInstance{$Version}{"Func"}{$Orig})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004431 {
Andrey Ponomarenkoa01311b2012-06-08 17:20:02 +04004432 my @TParams = getTParams($Orig, "Func");
4433 if(not @TParams)
4434 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04004435 delete($SymbolInfo{$Version}{$InfoId});
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004436 return;
4437 }
Andrey Ponomarenko16934472012-03-29 15:37:04 +04004438 foreach my $Pos (0 .. $#TParams) {
4439 $SymbolInfo{$Version}{$InfoId}{"TParam"}{$Pos}{"name"}=$TParams[$Pos];
4440 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004441 my $PrmsInLine = join(", ", @TParams);
Andrey Ponomarenko16934472012-03-29 15:37:04 +04004442 if($SymbolInfo{$Version}{$InfoId}{"ShortName"}=~/\Aoperator\W+\Z/)
4443 { # operator<< <T>, operator>> <T>
4444 $SymbolInfo{$Version}{$InfoId}{"ShortName"} .= " ";
4445 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04004446 $SymbolInfo{$Version}{$InfoId}{"ShortName"} .= "<".$PrmsInLine.">";
4447 $SymbolInfo{$Version}{$InfoId}{"ShortName"} = formatName($SymbolInfo{$Version}{$InfoId}{"ShortName"});
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004448 }
4449 else
4450 { # support for GCC 3.4
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04004451 $SymbolInfo{$Version}{$InfoId}{"ShortName"}=~s/<.+>\Z//;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004452 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04004453 $SymbolInfo{$Version}{$InfoId}{"MnglName"} = getTreeStr(getTreeAttr_Mngl($InfoId));
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04004454 # NOTE: mangling of some symbols may change depending on GCC version
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04004455 # GCC 4.6: _ZN28QExplicitlySharedDataPointerI11QPixmapDataEC2IT_EERKS_IT_E
4456 # GCC 4.7: _ZN28QExplicitlySharedDataPointerI11QPixmapDataEC2ERKS1_
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04004457
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04004458 if($SymbolInfo{$Version}{$InfoId}{"MnglName"}
4459 and $SymbolInfo{$Version}{$InfoId}{"MnglName"}!~/\A_Z/)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004460 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04004461 delete($SymbolInfo{$Version}{$InfoId});
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004462 return;
4463 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04004464 if(not $SymbolInfo{$Version}{$InfoId}{"Destructor"})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004465 { # destructors have an empty parameter list
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04004466 my $Skip = setFuncParams($InfoId);
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04004467 if($Skip) {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04004468 delete($SymbolInfo{$Version}{$InfoId});
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004469 return;
4470 }
4471 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04004472 set_Class_And_Namespace($InfoId);
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04004473 if(my $ClassId = $SymbolInfo{$Version}{$InfoId}{"Class"})
4474 {
4475 if(not $TypeInfo{$Version}{$ClassId}{"Name"})
4476 { # templates
4477 delete($SymbolInfo{$Version}{$InfoId});
4478 return;
4479 }
4480 }
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04004481 if(not $CheckHeadersOnly)
4482 {
4483 if($SymbolInfo{$Version}{$InfoId}{"Type"} eq "Function"
4484 and not $SymbolInfo{$Version}{$InfoId}{"Class"}
4485 and link_symbol($SymbolInfo{$Version}{$InfoId}{"ShortName"}, $Version, "-Deps"))
4486 { # functions (C++): not mangled in library, but are mangled in TU dump
4487 if(not $SymbolInfo{$Version}{$InfoId}{"MnglName"}
4488 or not link_symbol($SymbolInfo{$Version}{$InfoId}{"MnglName"}, $Version, "-Deps")) {
4489 $SymbolInfo{$Version}{$InfoId}{"MnglName"} = $SymbolInfo{$Version}{$InfoId}{"ShortName"};
4490 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004491 }
4492 }
Andrey Ponomarenko35c44fd2012-06-18 17:50:25 +04004493 if($LibInfo{$Version}{"info"}{$InfoId}=~/ lang:[ ]*C /i)
4494 { # extern "C"
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04004495 $SymbolInfo{$Version}{$InfoId}{"Lang"} = "C";
Andrey Ponomarenko35c44fd2012-06-18 17:50:25 +04004496 $SymbolInfo{$Version}{$InfoId}{"MnglName"} = $SymbolInfo{$Version}{$InfoId}{"ShortName"};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004497 }
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04004498 if($UserLang and $UserLang eq "C")
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004499 { # --lang=C option
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04004500 $SymbolInfo{$Version}{$InfoId}{"MnglName"} = $SymbolInfo{$Version}{$InfoId}{"ShortName"};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004501 }
4502 if($COMMON_LANGUAGE{$Version} eq "C++")
4503 { # correct mangled & short names
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04004504 # C++ or --headers-only mode
4505 if($SymbolInfo{$Version}{$InfoId}{"ShortName"}=~/\A__(comp|base|deleting)_(c|d)tor\Z/)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004506 { # support for old GCC versions: reconstruct real names for constructors and destructors
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04004507 $SymbolInfo{$Version}{$InfoId}{"ShortName"} = getNameByInfo(getTypeDeclId($SymbolInfo{$Version}{$InfoId}{"Class"}));
4508 $SymbolInfo{$Version}{$InfoId}{"ShortName"}=~s/<.+>\Z//;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004509 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04004510 if(not $SymbolInfo{$Version}{$InfoId}{"MnglName"})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004511 { # try to mangle symbol (link with libraries)
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04004512 if(my $Mangled = linkSymbol($InfoId)) {
4513 $SymbolInfo{$Version}{$InfoId}{"MnglName"} = $Mangled;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004514 }
4515 }
4516 if($OStarget eq "windows")
4517 { # link MS C++ symbols from library with GCC symbols from headers
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04004518 if(my $Mangled1 = $mangled_name{$Version}{modelUnmangled($InfoId, "MSVC")})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004519 { # exported symbols
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04004520 $SymbolInfo{$Version}{$InfoId}{"MnglName"} = $Mangled1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004521 }
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04004522 elsif(my $Mangled2 = mangle_symbol($InfoId, $Version, "MSVC"))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004523 { # pure virtual symbols
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04004524 $SymbolInfo{$Version}{$InfoId}{"MnglName"} = $Mangled2;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004525 }
4526 }
4527 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04004528 if(not $SymbolInfo{$Version}{$InfoId}{"MnglName"})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004529 { # can't detect symbol name
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04004530 delete($SymbolInfo{$Version}{$InfoId});
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004531 return;
4532 }
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04004533 if(not $SymbolInfo{$Version}{$InfoId}{"Constructor"}
Andrey Ponomarenkoa01311b2012-06-08 17:20:02 +04004534 and my $Spec = getVirtSpec($Orig))
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04004535 { # identify virtual and pure virtual functions
4536 # NOTE: constructors cannot be virtual
4537 # NOTE: in GCC 4.7 D1 destructors have no virtual spec
4538 # in the TU dump, so taking it from the original symbol
4539 if(not ($SymbolInfo{$Version}{$InfoId}{"Destructor"}
4540 and $SymbolInfo{$Version}{$InfoId}{"MnglName"}=~/D2E/))
4541 { # NOTE: D2 destructors are not present in a v-table
4542 $SymbolInfo{$Version}{$InfoId}{$Spec} = 1;
4543 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004544 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04004545 if(isInline($InfoId)) {
4546 $SymbolInfo{$Version}{$InfoId}{"InLine"} = 1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004547 }
Andrey Ponomarenkob8d203d2012-05-25 18:11:07 +04004548 if($LibInfo{$Version}{"info"}{$InfoId}=~/ artificial /i) {
4549 $SymbolInfo{$Version}{$InfoId}{"Artificial"} = 1;
4550 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04004551 if($SymbolInfo{$Version}{$InfoId}{"Constructor"}
4552 and my $ClassId = $SymbolInfo{$Version}{$InfoId}{"Class"})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004553 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04004554 if(not $SymbolInfo{$Version}{$InfoId}{"InLine"}
Andrey Ponomarenkob8d203d2012-05-25 18:11:07 +04004555 and not $SymbolInfo{$Version}{$InfoId}{"Artificial"})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004556 { # inline or auto-generated constructor
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04004557 delete($TypeInfo{$Version}{$ClassId}{"Copied"});
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004558 }
4559 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +04004560 if(my $Symbol = $SymbolInfo{$Version}{$InfoId}{"MnglName"})
4561 {
Andrey Ponomarenko35c44fd2012-06-18 17:50:25 +04004562 if(not selectSymbol($Symbol, $SymbolInfo{$Version}{$InfoId}, "Dump", $Version))
4563 { # non-target symbols
4564 delete($SymbolInfo{$Version}{$InfoId});
4565 return;
Andrey Ponomarenko85043792012-05-14 16:48:07 +04004566 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004567 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04004568 if($SymbolInfo{$Version}{$InfoId}{"Type"} eq "Method"
4569 or $SymbolInfo{$Version}{$InfoId}{"Constructor"}
4570 or $SymbolInfo{$Version}{$InfoId}{"Destructor"}
4571 or $SymbolInfo{$Version}{$InfoId}{"Class"})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004572 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04004573 if($SymbolInfo{$Version}{$InfoId}{"MnglName"}!~/\A(_Z|\?)/) {
4574 delete($SymbolInfo{$Version}{$InfoId});
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004575 return;
4576 }
4577 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04004578 if($SymbolInfo{$Version}{$InfoId}{"MnglName"})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004579 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04004580 if($MangledNames{$Version}{$SymbolInfo{$Version}{$InfoId}{"MnglName"}})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004581 { # one instance for one mangled name only
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04004582 delete($SymbolInfo{$Version}{$InfoId});
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004583 return;
4584 }
4585 else {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04004586 $MangledNames{$Version}{$SymbolInfo{$Version}{$InfoId}{"MnglName"}} = 1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004587 }
4588 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04004589 if($SymbolInfo{$Version}{$InfoId}{"Constructor"}
4590 or $SymbolInfo{$Version}{$InfoId}{"Destructor"}) {
4591 delete($SymbolInfo{$Version}{$InfoId}{"Return"});
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004592 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04004593 if($SymbolInfo{$Version}{$InfoId}{"MnglName"}=~/\A(_Z|\?)/
4594 and $SymbolInfo{$Version}{$InfoId}{"Class"})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004595 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04004596 if($SymbolInfo{$Version}{$InfoId}{"Type"} eq "Function")
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004597 { # static methods
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04004598 $SymbolInfo{$Version}{$InfoId}{"Static"} = 1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004599 }
4600 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04004601 if(getFuncLink($InfoId) eq "Static") {
4602 $SymbolInfo{$Version}{$InfoId}{"Static"} = 1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004603 }
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04004604 if($SymbolInfo{$Version}{$InfoId}{"MnglName"}=~/\A(_Z|\?)/)
4605 {
4606 if(my $Unmangled = $tr_name{$SymbolInfo{$Version}{$InfoId}{"MnglName"}})
4607 {
4608 if($Unmangled=~/\.\_\d/) {
4609 delete($SymbolInfo{$Version}{$InfoId});
4610 return;
4611 }
4612 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004613 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04004614 delete($SymbolInfo{$Version}{$InfoId}{"Type"});
4615 if($SymbolInfo{$Version}{$InfoId}{"MnglName"}=~/\A_ZN(V|)K/) {
4616 $SymbolInfo{$Version}{$InfoId}{"Const"} = 1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004617 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04004618 if($SymbolInfo{$Version}{$InfoId}{"MnglName"}=~/\A_ZN(K|)V/) {
4619 $SymbolInfo{$Version}{$InfoId}{"Volatile"} = 1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004620 }
4621}
4622
4623sub isInline($)
4624{ # "body: undefined" in the tree
4625 # -fkeep-inline-functions GCC option should be specified
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04004626 if($_[0] and my $Info = $LibInfo{$Version}{"info"}{$_[0]})
4627 {
4628 if($Info=~/ undefined /i) {
4629 return 0;
4630 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004631 }
4632 return 1;
4633}
4634
4635sub getTypeId($)
4636{
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04004637 if($_[0] and my $Info = $LibInfo{$Version}{"info"}{$_[0]})
4638 {
4639 if($Info=~/type[ ]*:[ ]*@(\d+) /) {
4640 return $1;
4641 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004642 }
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04004643 return "";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004644}
4645
4646sub setTypeMemb($$)
4647{
4648 my ($TypeId, $TypeAttr) = @_;
4649 my $TypeType = $TypeAttr->{"Type"};
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04004650 my ($Pos, $UnnamedPos) = (0, 0);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004651 if($TypeType eq "Enum")
4652 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04004653 my $TypeMembInfoId = getTreeAttr_Csts($TypeId);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004654 while($TypeMembInfoId)
4655 {
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04004656 $TypeAttr->{"Memb"}{$Pos}{"value"} = getEnumMembVal($TypeMembInfoId);
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04004657 my $MembName = getTreeStr(getTreeAttr_Purp($TypeMembInfoId));
4658 $TypeAttr->{"Memb"}{$Pos}{"name"} = $MembName;
4659 $EnumMembName_Id{$Version}{getTreeAttr_Valu($TypeMembInfoId)} = ($TypeAttr->{"NameSpace"})?$TypeAttr->{"NameSpace"}."::".$MembName:$MembName;
4660 $TypeMembInfoId = getNextElem($TypeMembInfoId);
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04004661 $Pos += 1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004662 }
4663 }
4664 elsif($TypeType=~/\A(Struct|Class|Union)\Z/)
4665 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04004666 my $TypeMembInfoId = getTreeAttr_Flds($TypeId);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004667 while($TypeMembInfoId)
4668 {
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04004669 my $IType = $LibInfo{$Version}{"info_type"}{$TypeMembInfoId};
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04004670 my $MInfo = $LibInfo{$Version}{"info"}{$TypeMembInfoId};
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04004671 if(not $IType or $IType ne "field_decl")
4672 { # search for fields, skip other stuff in the declaration
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04004673 $TypeMembInfoId = getNextElem($TypeMembInfoId);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004674 next;
4675 }
4676 my $StructMembName = getStructMembName($TypeMembInfoId);
4677 if($StructMembName=~/_vptr\./)
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04004678 { # virtual tables
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04004679 $TypeMembInfoId = getNextElem($TypeMembInfoId);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004680 next;
4681 }
4682 if(not $StructMembName)
4683 { # unnamed fields
4684 if($TypeAttr->{"Name"}!~/_type_info_pseudo/)
4685 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04004686 my $UnnamedTid = getTreeAttr_Type($TypeMembInfoId);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004687 my $UnnamedTName = getNameByInfo(getTypeDeclId($UnnamedTid));
4688 if(isAnon($UnnamedTName))
4689 { # rename unnamed fields to unnamed0, unnamed1, ...
4690 $StructMembName = "unnamed".($UnnamedPos++);
4691 }
4692 }
4693 }
4694 if(not $StructMembName)
4695 { # unnamed fields and base classes
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04004696 $TypeMembInfoId = getNextElem($TypeMembInfoId);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004697 next;
4698 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04004699 my $MembTypeId = getTreeAttr_Type($TypeMembInfoId);
4700 if(defined $MissedTypedef{$Version}{$MembTypeId})
4701 {
4702 if(my $AddedTid = $MissedTypedef{$Version}{$MembTypeId}{"Tid"}) {
4703 $MembTypeId = $AddedTid;
4704 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004705 }
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04004706 $TypeAttr->{"Memb"}{$Pos}{"type"} = $MembTypeId;
4707 $TypeAttr->{"Memb"}{$Pos}{"name"} = $StructMembName;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004708 if((my $Access = getTreeAccess($TypeMembInfoId)) ne "public")
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04004709 { # marked only protected and private, public by default
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04004710 $TypeAttr->{"Memb"}{$Pos}{"access"} = $Access;
4711 }
4712 if($MInfo=~/spec:\s*mutable /)
4713 { # mutable fields
4714 $TypeAttr->{"Memb"}{$Pos}{"mutable"} = 1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004715 }
4716 if(my $BFSize = getStructMembBitFieldSize($TypeMembInfoId)) {
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04004717 $TypeAttr->{"Memb"}{$Pos}{"bitfield"} = $BFSize;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004718 }
4719 else
4720 { # set alignment for non-bit fields
4721 # alignment for bitfields is always equal to 1 bit
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04004722 if(my $Algn = getAlgn($TypeMembInfoId)) {
4723 $TypeAttr->{"Memb"}{$Pos}{"algn"} = $Algn/$BYTE_SIZE;
4724 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004725 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04004726 $TypeMembInfoId = getNextElem($TypeMembInfoId);
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04004727 $Pos += 1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004728 }
4729 }
4730}
4731
4732sub setFuncParams($)
4733{
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04004734 my $InfoId = $_[0];
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04004735 my $ParamInfoId = getTreeAttr_Args($InfoId);
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04004736 if(getFuncType($InfoId) eq "Method")
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004737 { # check type of "this" pointer
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04004738 my $ObjectTypeId = getTreeAttr_Type($ParamInfoId);
4739 if(my $ObjectName = $TypeInfo{$Version}{$ObjectTypeId}{"Name"})
Andrey Ponomarenko85043792012-05-14 16:48:07 +04004740 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04004741 if($ObjectName=~/\bconst(| volatile)\*const\b/) {
Andrey Ponomarenko85043792012-05-14 16:48:07 +04004742 $SymbolInfo{$Version}{$InfoId}{"Const"} = 1;
4743 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04004744 if($ObjectName=~/\bvolatile\b/) {
Andrey Ponomarenko85043792012-05-14 16:48:07 +04004745 $SymbolInfo{$Version}{$InfoId}{"Volatile"} = 1;
4746 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004747 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +04004748 else
4749 { # skip
4750 return 1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004751 }
4752 $ParamInfoId = getNextElem($ParamInfoId);
4753 }
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04004754 my ($Pos, $Vtt_Pos) = (0, -1);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004755 while($ParamInfoId)
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04004756 { # formal args
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04004757 my $ParamTypeId = getTreeAttr_Type($ParamInfoId);
4758 my $ParamName = getTreeStr(getTreeAttr_Name($ParamInfoId));
4759 if(not $ParamName)
4760 { # unnamed
4761 $ParamName = "p".($Pos+1);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004762 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04004763 if(defined $MissedTypedef{$Version}{$ParamTypeId})
4764 {
4765 if(my $AddedTid = $MissedTypedef{$Version}{$ParamTypeId}{"Tid"}) {
4766 $ParamTypeId = $AddedTid;
4767 }
4768 }
4769 my $PType = $TypeInfo{$Version}{$ParamTypeId}{"Type"};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004770 if(not $PType or $PType eq "Unknown") {
4771 return 1;
4772 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04004773 my $PTName = $TypeInfo{$Version}{$ParamTypeId}{"Name"};
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04004774 if(not $PTName) {
4775 return 1;
4776 }
4777 if($PTName eq "void") {
4778 last;
4779 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004780 if($ParamName eq "__vtt_parm"
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04004781 and $TypeInfo{$Version}{$ParamTypeId}{"Name"} eq "void const**")
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004782 {
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04004783 $Vtt_Pos = $Pos;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004784 $ParamInfoId = getNextElem($ParamInfoId);
4785 next;
4786 }
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04004787 $SymbolInfo{$Version}{$InfoId}{"Param"}{$Pos}{"type"} = $ParamTypeId;
4788 $SymbolInfo{$Version}{$InfoId}{"Param"}{$Pos}{"name"} = $ParamName;
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04004789 if(my $Algn = getAlgn($ParamInfoId)) {
4790 $SymbolInfo{$Version}{$InfoId}{"Param"}{$Pos}{"algn"} = $Algn/$BYTE_SIZE;
4791 }
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04004792 if(not $SymbolInfo{$Version}{$InfoId}{"Param"}{$Pos}{"name"}) {
4793 $SymbolInfo{$Version}{$InfoId}{"Param"}{$Pos}{"name"} = "p".($Pos+1);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004794 }
4795 if($LibInfo{$Version}{"info"}{$ParamInfoId}=~/spec:\s*register /)
4796 { # foo(register type arg)
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04004797 $SymbolInfo{$Version}{$InfoId}{"Param"}{$Pos}{"reg"} = 1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004798 }
4799 $ParamInfoId = getNextElem($ParamInfoId);
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04004800 $Pos += 1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004801 }
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04004802 if(setFuncArgs($InfoId, $Vtt_Pos)) {
4803 $SymbolInfo{$Version}{$InfoId}{"Param"}{$Pos}{"type"} = -1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004804 }
4805 return 0;
4806}
4807
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04004808sub setFuncArgs($$)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004809{
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04004810 my ($InfoId, $Vtt_Pos) = @_;
4811 my $FuncTypeId = getFuncTypeId($InfoId);
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04004812 my $ParamListElemId = getTreeAttr_Prms($FuncTypeId);
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04004813 if(getFuncType($InfoId) eq "Method") {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004814 $ParamListElemId = getNextElem($ParamListElemId);
4815 }
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04004816 if(not $ParamListElemId)
4817 { # foo(...)
4818 return 1;
4819 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004820 my $HaveVoid = 0;
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04004821 my $Pos = 0;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004822 while($ParamListElemId)
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04004823 { # actual params: may differ from formal args
4824 # formal int*const
4825 # actual: int*
4826 if($Vtt_Pos!=-1 and $Pos==$Vtt_Pos)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004827 {
4828 $Vtt_Pos=-1;
4829 $ParamListElemId = getNextElem($ParamListElemId);
4830 next;
4831 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04004832 my $ParamTypeId = getTreeAttr_Valu($ParamListElemId);
4833 if($TypeInfo{$Version}{$ParamTypeId}{"Name"} eq "void")
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04004834 {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004835 $HaveVoid = 1;
4836 last;
4837 }
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04004838 elsif(not defined $SymbolInfo{$Version}{$InfoId}{"Param"}{$Pos}{"type"})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004839 {
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04004840 $SymbolInfo{$Version}{$InfoId}{"Param"}{$Pos}{"type"} = $ParamTypeId;
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04004841 if(not $SymbolInfo{$Version}{$InfoId}{"Param"}{$Pos}{"name"})
4842 { # unnamed
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04004843 $SymbolInfo{$Version}{$InfoId}{"Param"}{$Pos}{"name"} = "p".($Pos+1);
4844 }
4845 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04004846 if(my $PurpId = getTreeAttr_Purp($ParamListElemId))
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04004847 { # default arguments
4848 if(my $PurpType = $LibInfo{$Version}{"info_type"}{$PurpId}) {
4849 $SymbolInfo{$Version}{$InfoId}{"Param"}{$Pos}{"default"} = getInitVal($PurpId, $ParamTypeId);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004850 }
4851 }
4852 $ParamListElemId = getNextElem($ParamListElemId);
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04004853 $Pos += 1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004854 }
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04004855 return ($Pos>=1 and not $HaveVoid);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004856}
4857
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04004858sub getTreeAttr_Chan($)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004859{
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04004860 if($_[0] and my $Info = $LibInfo{$Version}{"info"}{$_[0]})
4861 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04004862 if($Info=~/chan[ ]*:[ ]*@(\d+) /) {
4863 return $1;
4864 }
4865 }
4866 return "";
4867}
4868
4869sub getTreeAttr_Chain($)
4870{
4871 if($_[0] and my $Info = $LibInfo{$Version}{"info"}{$_[0]})
4872 {
4873 if($Info=~/chain[ ]*:[ ]*@(\d+) /) {
4874 return $1;
4875 }
4876 }
4877 return "";
4878}
4879
4880sub getTreeAttr_Scpe($)
4881{
4882 if($_[0] and my $Info = $LibInfo{$Version}{"info"}{$_[0]})
4883 {
4884 if($Info=~/scpe[ ]*:[ ]*@(\d+) /) {
4885 return $1;
4886 }
4887 }
4888 return "";
4889}
4890
4891sub getTreeAttr_Type($)
4892{
4893 if($_[0] and my $Info = $LibInfo{$Version}{"info"}{$_[0]})
4894 {
4895 if($Info=~/type[ ]*:[ ]*@(\d+) /) {
4896 return $1;
4897 }
4898 }
4899 return "";
4900}
4901
4902sub getTreeAttr_Name($)
4903{
4904 if($_[0] and my $Info = $LibInfo{$Version}{"info"}{$_[0]})
4905 {
4906 if($Info=~/name[ ]*:[ ]*@(\d+) /) {
4907 return $1;
4908 }
4909 }
4910 return "";
4911}
4912
4913sub getTreeAttr_Mngl($)
4914{
4915 if($_[0] and my $Info = $LibInfo{$Version}{"info"}{$_[0]})
4916 {
4917 if($Info=~/mngl[ ]*:[ ]*@(\d+) /) {
4918 return $1;
4919 }
4920 }
4921 return "";
4922}
4923
4924sub getTreeAttr_Prms($)
4925{
4926 if($_[0] and my $Info = $LibInfo{$Version}{"info"}{$_[0]})
4927 {
4928 if($Info=~/prms[ ]*:[ ]*@(\d+) /) {
4929 return $1;
4930 }
4931 }
4932 return "";
4933}
4934
4935sub getTreeAttr_Fncs($)
4936{
4937 if($_[0] and my $Info = $LibInfo{$Version}{"info"}{$_[0]})
4938 {
4939 if($Info=~/fncs[ ]*:[ ]*@(\d+) /) {
4940 return $1;
4941 }
4942 }
4943 return "";
4944}
4945
4946sub getTreeAttr_Csts($)
4947{
4948 if($_[0] and my $Info = $LibInfo{$Version}{"info"}{$_[0]})
4949 {
4950 if($Info=~/csts[ ]*:[ ]*@(\d+) /) {
4951 return $1;
4952 }
4953 }
4954 return "";
4955}
4956
4957sub getTreeAttr_Purp($)
4958{
4959 if($_[0] and my $Info = $LibInfo{$Version}{"info"}{$_[0]})
4960 {
4961 if($Info=~/purp[ ]*:[ ]*@(\d+) /) {
4962 return $1;
4963 }
4964 }
4965 return "";
4966}
4967
4968sub getTreeAttr_Valu($)
4969{
4970 if($_[0] and my $Info = $LibInfo{$Version}{"info"}{$_[0]})
4971 {
4972 if($Info=~/valu[ ]*:[ ]*@(\d+) /) {
4973 return $1;
4974 }
4975 }
4976 return "";
4977}
4978
4979sub getTreeAttr_Flds($)
4980{
4981 if($_[0] and my $Info = $LibInfo{$Version}{"info"}{$_[0]})
4982 {
4983 if($Info=~/flds[ ]*:[ ]*@(\d+) /) {
4984 return $1;
4985 }
4986 }
4987 return "";
4988}
4989
4990sub getTreeAttr_Args($)
4991{
4992 if($_[0] and my $Info = $LibInfo{$Version}{"info"}{$_[0]})
4993 {
4994 if($Info=~/args[ ]*:[ ]*@(\d+) /) {
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04004995 return $1;
4996 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004997 }
4998 return "";
4999}
5000
5001sub getTreeValue($)
5002{
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04005003 if($_[0] and my $Info = $LibInfo{$Version}{"info"}{$_[0]})
5004 {
5005 if($Info=~/low[ ]*:[ ]*([^ ]+) /) {
5006 return $1;
5007 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005008 }
5009 return "";
5010}
5011
5012sub getTreeAccess($)
5013{
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04005014 if($_[0] and my $Info = $LibInfo{$Version}{"info"}{$_[0]})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005015 {
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04005016 if($Info=~/accs[ ]*:[ ]*([a-zA-Z]+) /)
5017 {
5018 my $Access = $1;
5019 if($Access eq "prot") {
5020 return "protected";
5021 }
5022 elsif($Access eq "priv") {
5023 return "private";
5024 }
5025 }
5026 elsif($Info=~/ protected /)
5027 { # support for old GCC versions
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005028 return "protected";
5029 }
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04005030 elsif($Info=~/ private /)
5031 { # support for old GCC versions
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005032 return "private";
5033 }
5034 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005035 return "public";
5036}
5037
5038sub setFuncAccess($)
5039{
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04005040 my $Access = getTreeAccess($_[0]);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005041 if($Access eq "protected") {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04005042 $SymbolInfo{$Version}{$_[0]}{"Protected"} = 1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005043 }
5044 elsif($Access eq "private") {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04005045 $SymbolInfo{$Version}{$_[0]}{"Private"} = 1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005046 }
5047}
5048
5049sub setTypeAccess($$)
5050{
5051 my ($TypeId, $TypeAttr) = @_;
5052 my $Access = getTreeAccess($TypeId);
5053 if($Access eq "protected") {
5054 $TypeAttr->{"Protected"} = 1;
5055 }
5056 elsif($Access eq "private") {
5057 $TypeAttr->{"Private"} = 1;
5058 }
5059}
5060
5061sub setFuncKind($)
5062{
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04005063 if($_[0] and my $Info = $LibInfo{$Version}{"info"}{$_[0]})
5064 {
5065 if($Info=~/pseudo tmpl/) {
5066 $SymbolInfo{$Version}{$_[0]}{"PseudoTemplate"} = 1;
5067 }
5068 elsif($Info=~/ constructor /) {
5069 $SymbolInfo{$Version}{$_[0]}{"Constructor"} = 1;
5070 }
5071 elsif($Info=~/ destructor /) {
5072 $SymbolInfo{$Version}{$_[0]}{"Destructor"} = 1;
5073 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005074 }
5075}
5076
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04005077sub getVirtSpec($)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005078{
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04005079 if($_[0] and my $Info = $LibInfo{$Version}{"info"}{$_[0]})
5080 {
5081 if($Info=~/spec[ ]*:[ ]*pure /) {
5082 return "PureVirt";
5083 }
5084 elsif($Info=~/spec[ ]*:[ ]*virt /) {
5085 return "Virt";
5086 }
5087 elsif($Info=~/ pure\s+virtual /)
5088 { # support for old GCC versions
5089 return "PureVirt";
5090 }
5091 elsif($Info=~/ virtual /)
5092 { # support for old GCC versions
5093 return "Virt";
5094 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005095 }
5096 return "";
5097}
5098
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005099sub getFuncLink($)
5100{
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04005101 if($_[0] and my $Info = $LibInfo{$Version}{"info"}{$_[0]})
5102 {
5103 if($Info=~/link[ ]*:[ ]*static /) {
5104 return "Static";
5105 }
5106 elsif($Info=~/link[ ]*:[ ]*([a-zA-Z]+) /) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005107 return $1;
5108 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005109 }
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04005110 return "";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005111}
5112
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005113sub get_IntNameSpace($$)
5114{
5115 my ($Interface, $LibVersion) = @_;
5116 return "" if(not $Interface or not $LibVersion);
5117 if(defined $Cache{"get_IntNameSpace"}{$Interface}{$LibVersion}) {
5118 return $Cache{"get_IntNameSpace"}{$Interface}{$LibVersion};
5119 }
5120 my $Signature = get_Signature($Interface, $LibVersion);
5121 if($Signature=~/\:\:/)
5122 {
5123 my $FounNameSpace = 0;
5124 foreach my $NameSpace (sort {get_depth($b)<=>get_depth($a)} keys(%{$NestedNameSpaces{$LibVersion}}))
5125 {
5126 if($Signature=~/(\A|\s+for\s+)\Q$NameSpace\E\:\:/) {
5127 return ($Cache{"get_IntNameSpace"}{$Interface}{$LibVersion} = $NameSpace);
5128 }
5129 }
5130 }
5131 else {
5132 return ($Cache{"get_IntNameSpace"}{$Interface}{$LibVersion} = "");
5133 }
5134}
5135
5136sub parse_TypeNameSpace($$)
5137{
5138 my ($TypeName, $LibVersion) = @_;
5139 return "" if(not $TypeName or not $LibVersion);
5140 if(defined $Cache{"parse_TypeNameSpace"}{$TypeName}{$LibVersion}) {
5141 return $Cache{"parse_TypeNameSpace"}{$TypeName}{$LibVersion};
5142 }
5143 if($TypeName=~/\:\:/)
5144 {
5145 my $FounNameSpace = 0;
5146 foreach my $NameSpace (sort {get_depth($b)<=>get_depth($a)} keys(%{$NestedNameSpaces{$LibVersion}}))
5147 {
5148 if($TypeName=~/\A\Q$NameSpace\E\:\:/) {
5149 return ($Cache{"parse_TypeNameSpace"}{$TypeName}{$LibVersion} = $NameSpace);
5150 }
5151 }
5152 }
5153 else {
5154 return ($Cache{"parse_TypeNameSpace"}{$TypeName}{$LibVersion} = "");
5155 }
5156}
5157
5158sub getNameSpace($)
5159{
5160 my $TypeInfoId = $_[0];
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04005161 if(my $NSInfoId = getTreeAttr_Scpe($TypeInfoId))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005162 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04005163 if(my $InfoType = $LibInfo{$Version}{"info_type"}{$NSInfoId})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005164 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04005165 if($InfoType eq "namespace_decl")
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04005166 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04005167 if($LibInfo{$Version}{"info"}{$NSInfoId}=~/name[ ]*:[ ]*@(\d+) /)
5168 {
5169 my $NameSpace = getTreeStr($1);
5170 if($NameSpace eq "::")
5171 { # global namespace
5172 return "";
5173 }
5174 if(my $BaseNameSpace = getNameSpace($NSInfoId)) {
5175 $NameSpace = $BaseNameSpace."::".$NameSpace;
5176 }
5177 $NestedNameSpaces{$Version}{$NameSpace} = 1;
5178 return $NameSpace;
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04005179 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04005180 else {
5181 return "";
5182 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005183 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04005184 elsif($InfoType eq "record_type")
5185 { # inside data type
5186 my ($Name, $NameNS) = getTrivialName(getTypeDeclId($NSInfoId), $NSInfoId);
5187 return $Name;
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04005188 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005189 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005190 }
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04005191 return "";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005192}
5193
5194sub getNameSpaceId($)
5195{
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04005196 if($_[0] and my $Info = $LibInfo{$Version}{"info"}{$_[0]})
5197 {
5198 if($Info=~/scpe[ ]*:[ ]*\@(\d+)/) {
5199 return $1;
5200 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005201 }
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04005202 return "";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005203}
5204
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005205sub getStructMembName($)
5206{
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04005207 if($_[0] and my $Info = $LibInfo{$Version}{"info"}{$_[0]})
5208 {
5209 if($Info=~/name[ ]*:[ ]*\@(\d+)/) {
5210 return getTreeStr($1);
5211 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005212 }
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04005213 return "";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005214}
5215
5216sub getEnumMembVal($)
5217{
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04005218 if($_[0] and my $Info = $LibInfo{$Version}{"info"}{$_[0]})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005219 {
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04005220 if($Info=~/valu[ ]*:[ ]*\@(\d+)/)
5221 {
5222 if(my $VInfo = $LibInfo{$Version}{"info"}{$1})
5223 {
5224 if($VInfo=~/cnst[ ]*:[ ]*\@(\d+)/)
5225 { # in newer versions of GCC the value is in the "const_decl->cnst" node
5226 return getTreeValue($1);
5227 }
5228 else
5229 { # some old versions of GCC (3.3) have the value in the "integer_cst" node
5230 return getTreeValue($1);
5231 }
5232 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005233 }
5234 }
5235 return "";
5236}
5237
5238sub getSize($)
5239{
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04005240 if($_[0] and my $Info = $LibInfo{$Version}{"info"}{$_[0]})
5241 {
5242 if($Info=~/size[ ]*:[ ]*\@(\d+)/) {
5243 return getTreeValue($1);
5244 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005245 }
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04005246 return 0;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005247}
5248
5249sub getAlgn($)
5250{
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04005251 if($_[0] and my $Info = $LibInfo{$Version}{"info"}{$_[0]})
5252 {
5253 if($Info=~/algn[ ]*:[ ]*(\d+) /) {
5254 return $1;
5255 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005256 }
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04005257 return "";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005258}
5259
5260sub getStructMembBitFieldSize($)
5261{
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04005262 if($_[0] and my $Info = $LibInfo{$Version}{"info"}{$_[0]})
5263 {
5264 if($Info=~/ bitfield /) {
5265 return getSize($_[0]);
5266 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005267 }
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04005268 return 0;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005269}
5270
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04005271sub getNextElem($)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005272{
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04005273 if(my $Chan = getTreeAttr_Chan($_[0])) {
5274 return $Chan;
5275 }
5276 elsif(my $Chain = getTreeAttr_Chain($_[0])) {
5277 return $Chain;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005278 }
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04005279 return "";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005280}
5281
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04005282sub registerHeader($$)
5283{ # input: absolute path of header, relative path or name
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005284 my ($Header, $LibVersion) = @_;
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04005285 if(not $Header) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005286 return "";
5287 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04005288 if(is_abs($Header) and not -f $Header)
5289 { # incorrect absolute path
5290 exitStatus("Access_Error", "can't access \'$Header\'");
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005291 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04005292 if(skipHeader($Header, $LibVersion))
5293 { # skip
5294 return "";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005295 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04005296 if(my $Header_Path = identifyHeader($Header, $LibVersion))
5297 {
5298 detect_header_includes($Header_Path, $LibVersion);
5299
5300 if(my $RHeader_Path = $Header_ErrorRedirect{$LibVersion}{$Header_Path})
5301 { # redirect
5302 if($Registered_Headers{$LibVersion}{$RHeader_Path}{"Identity"}
5303 or skipHeader($RHeader_Path, $LibVersion))
5304 { # skip
5305 return "";
5306 }
5307 $Header_Path = $RHeader_Path;
5308 }
5309 elsif($Header_ShouldNotBeUsed{$LibVersion}{$Header_Path})
5310 { # skip
5311 return "";
5312 }
5313
5314 if(my $HName = get_filename($Header_Path))
5315 { # register
5316 $Registered_Headers{$LibVersion}{$Header_Path}{"Identity"} = $HName;
5317 $HeaderName_Paths{$LibVersion}{$HName}{$Header_Path} = 1;
5318 }
5319
5320 if(($Header=~/\.(\w+)\Z/ and $1 ne "h")
5321 or $Header!~/\.(\w+)\Z/)
5322 { # hpp, hh
5323 setLanguage($LibVersion, "C++");
5324 }
5325
5326 if($CheckHeadersOnly
5327 and $Header=~/(\A|\/)c\+\+(\/|\Z)/)
5328 { # /usr/include/c++/4.6.1/...
5329 $STDCXX_TESTING = 1;
5330 }
5331
5332 return $Header_Path;
5333 }
5334 return "";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005335}
5336
5337sub register_directory($$$)
5338{
5339 my ($Dir, $WithDeps, $LibVersion) = @_;
5340 $Dir=~s/[\/\\]+\Z//g;
5341 return if(not $LibVersion or not $Dir or not -d $Dir);
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04005342 return if(skipHeader($Dir, $LibVersion));
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005343 $Dir = get_abs_path($Dir);
5344 my $Mode = "All";
Andrey Ponomarenko85043792012-05-14 16:48:07 +04005345 if($WithDeps)
5346 {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005347 if($RegisteredDirs{$LibVersion}{$Dir}{1}) {
5348 return;
5349 }
5350 elsif($RegisteredDirs{$LibVersion}{$Dir}{0}) {
5351 $Mode = "DepsOnly";
5352 }
5353 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +04005354 else
5355 {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005356 if($RegisteredDirs{$LibVersion}{$Dir}{1}
5357 or $RegisteredDirs{$LibVersion}{$Dir}{0}) {
5358 return;
5359 }
5360 }
5361 $Header_Dependency{$LibVersion}{$Dir} = 1;
5362 $RegisteredDirs{$LibVersion}{$Dir}{$WithDeps} = 1;
5363 if($Mode eq "DepsOnly")
5364 {
5365 foreach my $Path (cmd_find($Dir,"d","","")) {
5366 $Header_Dependency{$LibVersion}{$Path} = 1;
5367 }
5368 return;
5369 }
5370 foreach my $Path (sort {length($b)<=>length($a)} cmd_find($Dir,"f","",""))
5371 {
5372 if($WithDeps)
5373 {
5374 my $SubDir = $Path;
5375 while(($SubDir = get_dirname($SubDir)) ne $Dir)
5376 { # register all sub directories
5377 $Header_Dependency{$LibVersion}{$SubDir} = 1;
5378 }
5379 }
5380 next if(is_not_header($Path));
5381 next if(ignore_path($Path));
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04005382 next if(skipHeader($Path, $LibVersion));
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005383 # Neighbors
5384 foreach my $Part (get_path_prefixes($Path)) {
5385 $Include_Neighbors{$LibVersion}{$Part} = $Path;
5386 }
5387 }
5388 if(get_filename($Dir) eq "include")
5389 { # search for "lib/include/" directory
5390 my $LibDir = $Dir;
5391 if($LibDir=~s/([\/\\])include\Z/$1lib/g and -d $LibDir) {
5392 register_directory($LibDir, $WithDeps, $LibVersion);
5393 }
5394 }
5395}
5396
5397sub parse_redirect($$$)
5398{
5399 my ($Content, $Path, $LibVersion) = @_;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005400 my @Errors = ();
5401 while($Content=~s/#\s*error\s+([^\n]+?)\s*(\n|\Z)//) {
5402 push(@Errors, $1);
5403 }
5404 my $Redirect = "";
5405 foreach (@Errors)
5406 {
5407 s/\s{2,}/ /g;
5408 if(/(only|must\ include
5409 |update\ to\ include
5410 |replaced\ with
5411 |replaced\ by|renamed\ to
5412 |is\ in|use)\ (<[^<>]+>|[\w\-\/\\]+\.($HEADER_EXT))/ix)
5413 {
5414 $Redirect = $2;
5415 last;
5416 }
5417 elsif(/(include|use|is\ in)\ (<[^<>]+>|[\w\-\/\\]+\.($HEADER_EXT))\ instead/i)
5418 {
5419 $Redirect = $2;
5420 last;
5421 }
5422 elsif(/this\ header\ should\ not\ be\ used
5423 |programs\ should\ not\ directly\ include
5424 |you\ should\ not\ (include|be\ (including|using)\ this\ (file|header))
5425 |is\ not\ supported\ API\ for\ general\ use
5426 |do\ not\ use
5427 |should\ not\ be\ used
5428 |cannot\ be\ included\ directly/ix and not /\ from\ /i) {
5429 $Header_ShouldNotBeUsed{$LibVersion}{$Path} = 1;
5430 }
5431 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +04005432 if($Redirect)
5433 {
5434 $Redirect=~s/\A<//g;
5435 $Redirect=~s/>\Z//g;
5436 }
5437 return $Redirect;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005438}
5439
5440sub parse_includes($$)
5441{
5442 my ($Content, $Path) = @_;
5443 my %Includes = ();
5444 while($Content=~s/#([ \t]*)(include|include_next|import)([ \t]*)(<|")([^<>"]+)(>|")//)
Andrey Ponomarenko85043792012-05-14 16:48:07 +04005445 { # C/C++: include, Objective C/C++: import directive
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005446 my ($Header, $Method) = ($5, $4);
5447 $Header = path_format($Header, $OSgroup);
Andrey Ponomarenko85043792012-05-14 16:48:07 +04005448 if($Method eq "\"" or is_abs($Header))
5449 {
5450 if(-e joinPath(get_dirname($Path), $Header))
5451 { # relative path exists
5452 $Includes{$Header} = -1;
5453 }
5454 else
5455 { # include "..." that doesn't exist is equal to include <...>
5456 $Includes{$Header} = 2;
5457 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005458 }
5459 else {
5460 $Includes{$Header} = 1;
5461 }
5462 }
5463 return \%Includes;
5464}
5465
5466sub ignore_path($)
5467{
5468 my $Path = $_[0];
5469 if($Path=~/\~\Z/)
5470 {# skipping system backup files
5471 return 1;
5472 }
5473 if($Path=~/(\A|[\/\\]+)(\.(svn|git|bzr|hg)|CVS)([\/\\]+|\Z)/)
5474 {# skipping hidden .svn, .git, .bzr, .hg and CVS directories
5475 return 1;
5476 }
5477 return 0;
5478}
5479
5480sub sort_by_word($$)
5481{
5482 my ($ArrRef, $W) = @_;
5483 return if(length($W)<2);
5484 @{$ArrRef} = sort {get_filename($b)=~/\Q$W\E/i<=>get_filename($a)=~/\Q$W\E/i} @{$ArrRef};
5485}
5486
5487sub natural_sorting($$)
5488{
5489 my ($H1, $H2) = @_;
5490 $H1=~s/\.[a-z]+\Z//ig;
5491 $H2=~s/\.[a-z]+\Z//ig;
5492 my ($HDir1, $Hname1) = separate_path($H1);
5493 my ($HDir2, $Hname2) = separate_path($H2);
5494 my $Dirname1 = get_filename($HDir1);
5495 my $Dirname2 = get_filename($HDir2);
5496 if($H1 eq $H2) {
5497 return 0;
5498 }
5499 elsif($H1=~/\A\Q$H2\E/) {
5500 return 1;
5501 }
5502 elsif($H2=~/\A\Q$H1\E/) {
5503 return -1;
5504 }
5505 elsif($HDir1=~/\Q$Hname1\E/i
5506 and $HDir2!~/\Q$Hname2\E/i)
5507 {# include/glib-2.0/glib.h
5508 return -1;
5509 }
5510 elsif($HDir2=~/\Q$Hname2\E/i
5511 and $HDir1!~/\Q$Hname1\E/i)
5512 {# include/glib-2.0/glib.h
5513 return 1;
5514 }
5515 elsif($Hname1=~/\Q$Dirname1\E/i
5516 and $Hname2!~/\Q$Dirname2\E/i)
5517 {# include/hildon-thumbnail/hildon-thumbnail-factory.h
5518 return -1;
5519 }
5520 elsif($Hname2=~/\Q$Dirname2\E/i
5521 and $Hname1!~/\Q$Dirname1\E/i)
5522 {# include/hildon-thumbnail/hildon-thumbnail-factory.h
5523 return 1;
5524 }
5525 elsif($Hname1=~/(config|lib)/i
5526 and $Hname2!~/(config|lib)/i)
5527 {# include/alsa/asoundlib.h
5528 return -1;
5529 }
5530 elsif($Hname2=~/(config|lib)/i
5531 and $Hname1!~/(config|lib)/i)
5532 {# include/alsa/asoundlib.h
5533 return 1;
5534 }
5535 elsif(checkRelevance($H1)
5536 and not checkRelevance($H2))
5537 {# libebook/e-book.h
5538 return -1;
5539 }
5540 elsif(checkRelevance($H2)
5541 and not checkRelevance($H1))
5542 {# libebook/e-book.h
5543 return 1;
5544 }
5545 else {
5546 return (lc($H1) cmp lc($H2));
5547 }
5548}
5549
5550sub searchForHeaders($)
5551{
5552 my $LibVersion = $_[0];
5553 # gcc standard include paths
5554 find_gcc_cxx_headers($LibVersion);
5555 # processing header paths
5556 foreach my $Path (keys(%{$Descriptor{$LibVersion}{"IncludePaths"}}),
5557 keys(%{$Descriptor{$LibVersion}{"AddIncludePaths"}}))
5558 {
5559 my $IPath = $Path;
Andrey Ponomarenkoa01311b2012-06-08 17:20:02 +04005560 if($SystemRoot)
5561 {
5562 if(is_abs($Path)) {
5563 $Path = $SystemRoot.$Path;
5564 }
5565 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005566 if(not -e $Path) {
5567 exitStatus("Access_Error", "can't access \'$Path\'");
5568 }
5569 elsif(-f $Path) {
5570 exitStatus("Access_Error", "\'$Path\' - not a directory");
5571 }
5572 elsif(-d $Path)
5573 {
5574 $Path = get_abs_path($Path);
5575 register_directory($Path, 0, $LibVersion);
5576 if($Descriptor{$LibVersion}{"AddIncludePaths"}{$IPath}) {
5577 $Add_Include_Paths{$LibVersion}{$Path} = 1;
5578 }
5579 else {
5580 $Include_Paths{$LibVersion}{$Path} = 1;
5581 }
5582 }
5583 }
5584 if(keys(%{$Include_Paths{$LibVersion}})) {
5585 $INC_PATH_AUTODETECT{$LibVersion} = 0;
5586 }
5587 # registering directories
5588 foreach my $Path (split(/\s*\n\s*/, $Descriptor{$LibVersion}{"Headers"}))
5589 {
5590 next if(not -e $Path);
5591 $Path = get_abs_path($Path);
5592 $Path = path_format($Path, $OSgroup);
5593 if(-d $Path) {
5594 register_directory($Path, 1, $LibVersion);
5595 }
5596 elsif(-f $Path)
5597 {
5598 my $Dir = get_dirname($Path);
5599 if(not $SystemPaths{"include"}{$Dir}
5600 and not $LocalIncludes{$Dir})
5601 {
5602 register_directory($Dir, 1, $LibVersion);
5603 if(my $OutDir = get_dirname($Dir))
5604 { # registering the outer directory
5605 if(not $SystemPaths{"include"}{$OutDir}
5606 and not $LocalIncludes{$OutDir}) {
5607 register_directory($OutDir, 0, $LibVersion);
5608 }
5609 }
5610 }
5611 }
5612 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +04005613
5614 # clean memory
5615 %RegisteredDirs = ();
5616
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005617 # registering headers
5618 my $Position = 0;
5619 foreach my $Dest (split(/\s*\n\s*/, $Descriptor{$LibVersion}{"Headers"}))
5620 {
5621 if(is_abs($Dest) and not -e $Dest) {
5622 exitStatus("Access_Error", "can't access \'$Dest\'");
5623 }
5624 $Dest = path_format($Dest, $OSgroup);
5625 if(is_header($Dest, 1, $LibVersion))
5626 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04005627 if(my $HPath = registerHeader($Dest, $LibVersion)) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005628 $Registered_Headers{$LibVersion}{$HPath}{"Pos"} = $Position++;
5629 }
5630 }
5631 elsif(-d $Dest)
5632 {
5633 my @Registered = ();
5634 foreach my $Path (cmd_find($Dest,"f","",""))
5635 {
5636 next if(ignore_path($Path));
5637 next if(not is_header($Path, 0, $LibVersion));
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04005638 if(my $HPath = registerHeader($Path, $LibVersion)) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005639 push(@Registered, $HPath);
5640 }
5641 }
5642 @Registered = sort {natural_sorting($a, $b)} @Registered;
5643 sort_by_word(\@Registered, $TargetLibraryShortName);
5644 foreach my $Path (@Registered) {
5645 $Registered_Headers{$LibVersion}{$Path}{"Pos"} = $Position++;
5646 }
5647 }
5648 else {
5649 exitStatus("Access_Error", "can't identify \'$Dest\' as a header file");
5650 }
5651 }
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04005652 if(my $HList = $Descriptor{$LibVersion}{"IncludePreamble"})
5653 { # preparing preamble headers
5654 my $PPos=0;
5655 foreach my $Header (split(/\s*\n\s*/, $HList))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005656 {
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04005657 if(is_abs($Header) and not -f $Header) {
5658 exitStatus("Access_Error", "can't access file \'$Header\'");
5659 }
5660 $Header = path_format($Header, $OSgroup);
5661 if(my $Header_Path = is_header($Header, 1, $LibVersion))
5662 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04005663 next if(skipHeader($Header_Path, $LibVersion));
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04005664 $Include_Preamble{$LibVersion}{$Header_Path}{"Position"} = $PPos++;
5665 }
5666 else {
5667 exitStatus("Access_Error", "can't identify \'$Header\' as a header file");
5668 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005669 }
5670 }
5671 foreach my $Header_Name (keys(%{$HeaderName_Paths{$LibVersion}}))
5672 { # set relative paths (for duplicates)
5673 if(keys(%{$HeaderName_Paths{$LibVersion}{$Header_Name}})>=2)
5674 { # search for duplicates
5675 my $FirstPath = (keys(%{$HeaderName_Paths{$LibVersion}{$Header_Name}}))[0];
5676 my $Prefix = get_dirname($FirstPath);
5677 while($Prefix=~/\A(.+)[\/\\]+[^\/\\]+\Z/)
5678 { # detect a shortest distinguishing prefix
5679 my $NewPrefix = $1;
5680 my %Identity = ();
5681 foreach my $Path (keys(%{$HeaderName_Paths{$LibVersion}{$Header_Name}}))
5682 {
5683 if($Path=~/\A\Q$Prefix\E[\/\\]+(.*)\Z/) {
5684 $Identity{$Path} = $1;
5685 }
5686 }
5687 if(keys(%Identity)==keys(%{$HeaderName_Paths{$LibVersion}{$Header_Name}}))
5688 { # all names are differend with current prefix
5689 foreach my $Path (keys(%{$HeaderName_Paths{$LibVersion}{$Header_Name}})) {
5690 $Registered_Headers{$LibVersion}{$Path}{"Identity"} = $Identity{$Path};
5691 }
5692 last;
5693 }
5694 $Prefix = $NewPrefix; # increase prefix
5695 }
5696 }
5697 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +04005698
5699 # clean memory
5700 %HeaderName_Paths = ();
5701
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005702 foreach my $HeaderName (keys(%{$Include_Order{$LibVersion}}))
5703 { # ordering headers according to descriptor
5704 my $PairName=$Include_Order{$LibVersion}{$HeaderName};
5705 my ($Pos, $PairPos) = (-1, -1);
5706 my ($Path, $PairPath) = ();
5707 my @Paths = keys(%{$Registered_Headers{$LibVersion}});
5708 @Paths = sort {int($Registered_Headers{$LibVersion}{$a}{"Pos"})<=>int($Registered_Headers{$LibVersion}{$b}{"Pos"})} @Paths;
5709 foreach my $Header_Path (@Paths)
5710 {
5711 if(get_filename($Header_Path) eq $PairName)
5712 {
5713 $PairPos = $Registered_Headers{$LibVersion}{$Header_Path}{"Pos"};
5714 $PairPath = $Header_Path;
5715 }
5716 if(get_filename($Header_Path) eq $HeaderName)
5717 {
5718 $Pos = $Registered_Headers{$LibVersion}{$Header_Path}{"Pos"};
5719 $Path = $Header_Path;
5720 }
5721 }
5722 if($PairPos!=-1 and $Pos!=-1
5723 and int($PairPos)<int($Pos))
5724 {
5725 my %Tmp = %{$Registered_Headers{$LibVersion}{$Path}};
5726 %{$Registered_Headers{$LibVersion}{$Path}} = %{$Registered_Headers{$LibVersion}{$PairPath}};
5727 %{$Registered_Headers{$LibVersion}{$PairPath}} = %Tmp;
5728 }
5729 }
5730 if(not keys(%{$Registered_Headers{$LibVersion}})) {
5731 exitStatus("Error", "header files are not found in the ".$Descriptor{$LibVersion}{"Version"});
5732 }
5733}
5734
5735sub detect_real_includes($$)
5736{
5737 my ($AbsPath, $LibVersion) = @_;
5738 return () if(not $LibVersion or not $AbsPath or not -e $AbsPath);
5739 if($Cache{"detect_real_includes"}{$LibVersion}{$AbsPath}
5740 or keys(%{$RecursiveIncludes{$LibVersion}{$AbsPath}})) {
5741 return keys(%{$RecursiveIncludes{$LibVersion}{$AbsPath}});
5742 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +04005743 $Cache{"detect_real_includes"}{$LibVersion}{$AbsPath}=1;
5744
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005745 my $Path = callPreprocessor($AbsPath, "", $LibVersion);
5746 return () if(not $Path);
5747 open(PREPROC, $Path);
5748 while(<PREPROC>)
5749 {
5750 if(/#\s+\d+\s+"([^"]+)"[\s\d]*\n/)
5751 {
5752 my $Include = path_format($1, $OSgroup);
5753 if($Include=~/\<(built\-in|internal|command(\-|\s)line)\>|\A\./) {
5754 next;
5755 }
5756 if($Include eq $AbsPath) {
5757 next;
5758 }
5759 $RecursiveIncludes{$LibVersion}{$AbsPath}{$Include} = 1;
5760 }
5761 }
5762 close(PREPROC);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005763 return keys(%{$RecursiveIncludes{$LibVersion}{$AbsPath}});
5764}
5765
5766sub detect_header_includes($$)
5767{
5768 my ($Path, $LibVersion) = @_;
Andrey Ponomarenko85043792012-05-14 16:48:07 +04005769 return if(not $LibVersion or not $Path);
5770 if(defined $Cache{"detect_header_includes"}{$LibVersion}{$Path}) {
5771 return;
5772 }
5773 $Cache{"detect_header_includes"}{$LibVersion}{$Path}=1;
5774
5775 if(not -e $Path) {
5776 return;
5777 }
5778
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005779 my $Content = readFile($Path);
Andrey Ponomarenko85043792012-05-14 16:48:07 +04005780 if(my $Redirect = parse_redirect($Content, $Path, $LibVersion))
5781 { # detect error directive in headers
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04005782 if(my $RedirectPath = identifyHeader($Redirect, $LibVersion))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005783 {
5784 if($RedirectPath=~/\/usr\/include\// and $Path!~/\/usr\/include\//) {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04005785 $RedirectPath = identifyHeader(get_filename($Redirect), $LibVersion);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005786 }
5787 if($RedirectPath ne $Path) {
5788 $Header_ErrorRedirect{$LibVersion}{$Path} = $RedirectPath;
5789 }
5790 }
5791 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +04005792 if(my $Inc = parse_includes($Content, $Path))
5793 {
5794 foreach my $Include (keys(%{$Inc}))
5795 { # detect includes
Andrey Ponomarenko85043792012-05-14 16:48:07 +04005796 $Header_Includes{$LibVersion}{$Path}{$Include} = $Inc->{$Include};
5797 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005798 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005799}
5800
5801sub simplify_path($)
5802{
5803 my $Path = $_[0];
5804 while($Path=~s&([\/\\])[^\/\\]+[\/\\]\.\.[\/\\]&$1&){};
5805 return $Path;
5806}
5807
5808sub fromLibc($)
5809{ # GLIBC header
5810 my $Path = $_[0];
5811 my ($Dir, $Name) = separate_path($Path);
5812 if(get_filename($Dir)=~/\A(include|libc)\Z/ and $GlibcHeader{$Name})
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04005813 { # /usr/include/{stdio, ...}.h
5814 # epoc32/include/libc/{stdio, ...}.h
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005815 return 1;
5816 }
5817 if(isLibcDir($Dir)) {
5818 return 1;
5819 }
5820 return 0;
5821}
5822
5823sub isLibcDir($)
5824{ # GLIBC directory
5825 my $Dir = $_[0];
5826 my ($OutDir, $Name) = separate_path($Dir);
5827 if(get_filename($OutDir)=~/\A(include|libc)\Z/
5828 and ($Name=~/\Aasm(|-.+)\Z/ or $GlibcDir{$Name}))
5829 { # /usr/include/{sys,bits,asm,asm-*}/*.h
5830 return 1;
5831 }
5832 return 0;
5833}
5834
5835sub detect_recursive_includes($$)
5836{
5837 my ($AbsPath, $LibVersion) = @_;
5838 return () if(not $AbsPath);
5839 if(isCyclical(\@RecurInclude, $AbsPath)) {
5840 return keys(%{$RecursiveIncludes{$LibVersion}{$AbsPath}});
5841 }
5842 my ($AbsDir, $Name) = separate_path($AbsPath);
5843 if(isLibcDir($AbsDir))
5844 { # GLIBC internals
5845 return ();
5846 }
5847 if(keys(%{$RecursiveIncludes{$LibVersion}{$AbsPath}})) {
5848 return keys(%{$RecursiveIncludes{$LibVersion}{$AbsPath}});
5849 }
5850 return () if($OSgroup ne "windows" and $Name=~/windows|win32|win64/i);
5851 return () if($MAIN_CPP_DIR and $AbsPath=~/\A\Q$MAIN_CPP_DIR\E/ and not $STDCXX_TESTING);
5852 push(@RecurInclude, $AbsPath);
5853 if($DefaultGccPaths{$AbsDir}
5854 or fromLibc($AbsPath))
5855 { # check "real" (non-"model") include paths
5856 my @Paths = detect_real_includes($AbsPath, $LibVersion);
5857 pop(@RecurInclude);
5858 return @Paths;
5859 }
5860 if(not keys(%{$Header_Includes{$LibVersion}{$AbsPath}})) {
5861 detect_header_includes($AbsPath, $LibVersion);
5862 }
5863 foreach my $Include (keys(%{$Header_Includes{$LibVersion}{$AbsPath}}))
5864 {
Andrey Ponomarenko85043792012-05-14 16:48:07 +04005865 my $IncType = $Header_Includes{$LibVersion}{$AbsPath}{$Include};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005866 my $HPath = "";
Andrey Ponomarenko85043792012-05-14 16:48:07 +04005867 if($IncType<0)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005868 { # for #include "..."
5869 my $Candidate = joinPath($AbsDir, $Include);
5870 if(-f $Candidate) {
5871 $HPath = simplify_path($Candidate);
5872 }
5873 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +04005874 elsif($IncType>0
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04005875 and $Include=~/[\/\\]/) # and not find_in_defaults($Include)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005876 { # search for the nearest header
5877 # QtCore/qabstractanimation.h includes <QtCore/qobject.h>
5878 my $Candidate = joinPath(get_dirname($AbsDir), $Include);
5879 if(-f $Candidate) {
5880 $HPath = $Candidate;
5881 }
5882 }
5883 if(not $HPath) {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04005884 $HPath = identifyHeader($Include, $LibVersion);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005885 }
5886 next if(not $HPath);
5887 if($HPath eq $AbsPath) {
5888 next;
5889 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +04005890 $RecursiveIncludes{$LibVersion}{$AbsPath}{$HPath} = $IncType;
5891 if($IncType>0)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005892 { # only include <...>, skip include "..." prefixes
5893 $Header_Include_Prefix{$LibVersion}{$AbsPath}{$HPath}{get_dirname($Include)} = 1;
5894 }
5895 foreach my $IncPath (detect_recursive_includes($HPath, $LibVersion))
5896 {
5897 if($IncPath eq $AbsPath) {
5898 next;
5899 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +04005900 my $RIncType = $RecursiveIncludes{$LibVersion}{$HPath}{$IncPath};
5901 if($RIncType==-1)
5902 { # include "..."
5903 $RIncType = $IncType;
5904 }
5905 elsif($RIncType==2)
5906 {
5907 if($IncType!=-1) {
5908 $RIncType = $IncType;
5909 }
5910 }
5911 $RecursiveIncludes{$LibVersion}{$AbsPath}{$IncPath} = $RIncType;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005912 foreach my $Prefix (keys(%{$Header_Include_Prefix{$LibVersion}{$HPath}{$IncPath}})) {
5913 $Header_Include_Prefix{$LibVersion}{$AbsPath}{$IncPath}{$Prefix} = 1;
5914 }
5915 }
5916 foreach my $Dep (keys(%{$Header_Include_Prefix{$LibVersion}{$AbsPath}}))
5917 {
5918 if($GlibcHeader{get_filename($Dep)} and keys(%{$Header_Include_Prefix{$LibVersion}{$AbsPath}{$Dep}})>=2
5919 and defined $Header_Include_Prefix{$LibVersion}{$AbsPath}{$Dep}{""})
5920 { # distinguish math.h from glibc and math.h from the tested library
5921 delete($Header_Include_Prefix{$LibVersion}{$AbsPath}{$Dep}{""});
5922 last;
5923 }
5924 }
5925 }
5926 pop(@RecurInclude);
5927 return keys(%{$RecursiveIncludes{$LibVersion}{$AbsPath}});
5928}
5929
5930sub find_in_framework($$$)
5931{
5932 my ($Header, $Framework, $LibVersion) = @_;
5933 return "" if(not $Header or not $Framework or not $LibVersion);
5934 if(defined $Cache{"find_in_framework"}{$LibVersion}{$Framework}{$Header}) {
5935 return $Cache{"find_in_framework"}{$LibVersion}{$Framework}{$Header};
5936 }
5937 foreach my $Dependency (sort {get_depth($a)<=>get_depth($b)} keys(%{$Header_Dependency{$LibVersion}}))
5938 {
5939 if(get_filename($Dependency) eq $Framework
5940 and -f get_dirname($Dependency)."/".$Header) {
5941 return ($Cache{"find_in_framework"}{$LibVersion}{$Framework}{$Header} = get_dirname($Dependency));
5942 }
5943 }
5944 return ($Cache{"find_in_framework"}{$LibVersion}{$Framework}{$Header} = "");
5945}
5946
5947sub find_in_defaults($)
5948{
5949 my $Header = $_[0];
5950 return "" if(not $Header);
5951 if(defined $Cache{"find_in_defaults"}{$Header}) {
5952 return $Cache{"find_in_defaults"}{$Header};
5953 }
5954 foreach my $Dir (sort {get_depth($a)<=>get_depth($b)}
5955 (keys(%DefaultIncPaths), keys(%DefaultGccPaths), keys(%DefaultCppPaths), keys(%UserIncPath)))
5956 {
5957 next if(not $Dir);
5958 if(-f $Dir."/".$Header) {
5959 return ($Cache{"find_in_defaults"}{$Header}=$Dir);
5960 }
5961 }
5962 return ($Cache{"find_in_defaults"}{$Header}="");
5963}
5964
5965sub cmp_paths($$)
5966{
5967 my ($Path1, $Path2) = @_;
5968 my @Parts1 = split(/[\/\\]/, $Path1);
5969 my @Parts2 = split(/[\/\\]/, $Path2);
5970 foreach my $Num (0 .. $#Parts1)
5971 {
5972 my $Part1 = $Parts1[$Num];
5973 my $Part2 = $Parts2[$Num];
5974 if($GlibcDir{$Part1}
5975 and not $GlibcDir{$Part2}) {
5976 return 1;
5977 }
5978 elsif($GlibcDir{$Part2}
5979 and not $GlibcDir{$Part1}) {
5980 return -1;
5981 }
5982 elsif($Part1=~/glib/
5983 and $Part2!~/glib/) {
5984 return 1;
5985 }
5986 elsif($Part1!~/glib/
5987 and $Part2=~/glib/) {
5988 return -1;
5989 }
5990 elsif(my $CmpRes = ($Part1 cmp $Part2)) {
5991 return $CmpRes;
5992 }
5993 }
5994 return 0;
5995}
5996
5997sub checkRelevance($)
5998{
5999 my ($Path) = @_;
6000 return 0 if(not $Path);
6001 if($SystemRoot) {
Andrey Ponomarenkoa01311b2012-06-08 17:20:02 +04006002 $Path = cut_path_prefix($Path, $SystemRoot);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006003 }
6004 my ($Dir, $Name) = separate_path($Path);
Andrey Ponomarenkoa01311b2012-06-08 17:20:02 +04006005 $Name=~s/\.\w+\Z//g; # remove extension (.h)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006006 my @Tokens = split(/[_\d\W]+/, $Name);
6007 foreach (@Tokens)
6008 {
6009 next if(not $_);
6010 if($Dir=~/(\A|lib|[_\d\W])\Q$_\E([_\d\W]|lib|\Z)/i
6011 or length($_)>=4 and $Dir=~/\Q$_\E/i)
6012 { # include/gupnp-1.0/libgupnp/gupnp-context.h
6013 # include/evolution-data-server-1.4/libebook/e-book.h
6014 return 1;
6015 }
6016 }
6017 return 0;
6018}
6019
6020sub checkFamily(@)
6021{
6022 my @Paths = @_;
6023 return 1 if($#Paths<=0);
6024 my %Prefix = ();
6025 foreach my $Path (@Paths)
6026 {
6027 if($SystemRoot) {
6028 $Path = cut_path_prefix($Path, $SystemRoot);
6029 }
6030 if(my $Dir = get_dirname($Path))
6031 {
6032 $Dir=~s/(\/[^\/]+?)[\d\.\-\_]+\Z/$1/g; # remove version suffix
6033 $Prefix{$Dir} += 1;
6034 $Prefix{get_dirname($Dir)} += 1;
6035 }
6036 }
6037 foreach (sort keys(%Prefix))
6038 {
6039 if(get_depth($_)>=3
6040 and $Prefix{$_}==$#Paths+1) {
6041 return 1;
6042 }
6043 }
6044 return 0;
6045}
6046
6047sub isAcceptable($$$)
6048{
6049 my ($Header, $Candidate, $LibVersion) = @_;
6050 my $HName = get_filename($Header);
6051 if(get_dirname($Header))
6052 { # with prefix
6053 return 1;
6054 }
6055 if($HName=~/config|setup/i and $Candidate=~/[\/\\]lib\d*[\/\\]/)
6056 { # allow to search for glibconfig.h in /usr/lib/glib-2.0/include/
6057 return 1;
6058 }
6059 if(checkRelevance($Candidate))
6060 { # allow to search for atk.h in /usr/include/atk-1.0/atk/
6061 return 1;
6062 }
6063 if(checkFamily(getSystemHeaders($HName, $LibVersion)))
6064 { # /usr/include/qt4/QtNetwork/qsslconfiguration.h
6065 # /usr/include/qt4/Qt/qsslconfiguration.h
6066 return 1;
6067 }
6068 if($OStarget eq "symbian")
6069 {
6070 if($Candidate=~/[\/\\]stdapis[\/\\]/) {
6071 return 1;
6072 }
6073 }
6074 return 0;
6075}
6076
6077sub isRelevant($$$)
6078{ # disallow to search for "abstract" headers in too deep directories
6079 my ($Header, $Candidate, $LibVersion) = @_;
6080 my $HName = get_filename($Header);
6081 if($OStarget eq "symbian")
6082 {
6083 if($Candidate=~/[\/\\](tools|stlportv5)[\/\\]/) {
6084 return 0;
6085 }
6086 }
6087 if($OStarget ne "bsd") {
6088 if($Candidate=~/[\/\\]include[\/\\]bsd[\/\\]/)
6089 { # openssh: skip /usr/lib/bcc/include/bsd/signal.h
6090 return 0;
6091 }
6092 }
6093 if(not get_dirname($Header)
6094 and $Candidate=~/[\/\\]wx[\/\\]/)
6095 { # do NOT search in system /wx/ directory
6096 # for headers without a prefix: sstream.h
6097 return 0;
6098 }
6099 if($Candidate=~/c\+\+[\/\\]\d+/ and $MAIN_CPP_DIR
6100 and $Candidate!~/\A\Q$MAIN_CPP_DIR\E/)
6101 { # skip ../c++/3.3.3/ if using ../c++/4.5/
6102 return 0;
6103 }
6104 if($Candidate=~/[\/\\]asm-/
6105 and (my $Arch = getArch($LibVersion)) ne "unknown")
6106 { # arch-specific header files
6107 if($Candidate!~/[\/\\]asm-\Q$Arch\E/)
6108 {# skip ../asm-arm/ if using x86 architecture
6109 return 0;
6110 }
6111 }
6112 my @Candidates = getSystemHeaders($HName, $LibVersion);
6113 if($#Candidates==1)
6114 { # unique header
6115 return 1;
6116 }
6117 my @SCandidates = getSystemHeaders($Header, $LibVersion);
6118 if($#SCandidates==1)
6119 { # unique name
6120 return 1;
6121 }
6122 my $SystemDepth = $SystemRoot?get_depth($SystemRoot):0;
6123 if(get_depth($Candidate)-$SystemDepth>=5)
6124 { # abstract headers in too deep directories
6125 # sstream.h or typeinfo.h in /usr/include/wx-2.9/wx/
6126 if(not isAcceptable($Header, $Candidate, $LibVersion)) {
6127 return 0;
6128 }
6129 }
6130 if($Header eq "parser.h"
6131 and $Candidate!~/\/libxml2\//)
6132 { # select parser.h from xml2 library
6133 return 0;
6134 }
6135 if(not get_dirname($Header)
6136 and keys(%{$SystemHeaders{$HName}})>=3)
6137 { # many headers with the same name
6138 # like thread.h included without a prefix
6139 if(not checkFamily(@Candidates)) {
6140 return 0;
6141 }
6142 }
6143 return 1;
6144}
6145
6146sub selectSystemHeader($$)
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04006147{ # cache function
6148 if(defined $Cache{"selectSystemHeader"}{$_[1]}{$_[0]}) {
6149 return $Cache{"selectSystemHeader"}{$_[1]}{$_[0]};
6150 }
6151 return ($Cache{"selectSystemHeader"}{$_[1]}{$_[0]} = selectSystemHeader_I(@_));
6152}
6153
6154sub selectSystemHeader_I($$)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006155{
6156 my ($Header, $LibVersion) = @_;
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04006157 if(-f $Header) {
6158 return $Header;
6159 }
6160 if(is_abs($Header) and not -f $Header)
6161 { # incorrect absolute path
6162 return "";
6163 }
6164 if($Header=~/\A(atomic|config|configure|build|conf|setup)\.h\Z/i)
6165 { # too abstract configuration headers
6166 return "";
6167 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006168 if($OSgroup ne "windows")
6169 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04006170 if(get_filename($Header)=~/windows|win32|win64|\A(dos|process|winsock|config-win)\.h\Z/i)
6171 { # windows headers
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006172 return "";
6173 }
6174 elsif($Header=~/\A(mem)\.h\Z/)
6175 { # pngconf.h include mem.h for __MSDOS__
6176 return "";
6177 }
6178 }
6179 if($OSgroup ne "solaris")
6180 {
6181 if($Header=~/\A(thread)\.h\Z/)
6182 { # thread.h in Solaris
6183 return "";
6184 }
6185 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04006186
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006187 foreach my $Path (keys(%{$SystemPaths{"include"}}))
6188 { # search in default paths
6189 if(-f $Path."/".$Header) {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04006190 return joinPath($Path,$Header);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006191 }
6192 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04006193 if(not keys(%SystemHeaders))
6194 { # register all headers in system include dirs
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006195 detectSystemHeaders();
6196 }
6197 foreach my $Candidate (sort {get_depth($a)<=>get_depth($b)}
6198 sort {cmp_paths($b, $a)} getSystemHeaders($Header, $LibVersion))
6199 {
6200 if(isRelevant($Header, $Candidate, $LibVersion)) {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04006201 return $Candidate;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006202 }
6203 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04006204 # error
6205 return "";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006206}
6207
6208sub getSystemHeaders($$)
6209{
6210 my ($Header, $LibVersion) = @_;
6211 my @Candidates = ();
6212 foreach my $Candidate (sort keys(%{$SystemHeaders{$Header}}))
6213 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04006214 if(skipHeader($Candidate, $LibVersion)) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006215 next;
6216 }
6217 push(@Candidates, $Candidate);
6218 }
6219 return @Candidates;
6220}
6221
6222sub cut_path_prefix($$)
6223{
6224 my ($Path, $Prefix) = @_;
6225 return $Path if(not $Prefix);
6226 $Prefix=~s/[\/\\]+\Z//;
6227 $Path=~s/\A\Q$Prefix\E([\/\\]+|\Z)//;
6228 return $Path;
6229}
6230
6231sub is_default_include_dir($)
6232{
6233 my $Dir = $_[0];
6234 $Dir=~s/[\/\\]+\Z//;
6235 return ($DefaultGccPaths{$Dir} or $DefaultCppPaths{$Dir} or $DefaultIncPaths{$Dir});
6236}
6237
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04006238sub identifyHeader($$)
6239{ # cache function
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006240 my ($Header, $LibVersion) = @_;
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04006241 if(not $Header) {
6242 return "";
6243 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006244 $Header=~s/\A(\.\.[\\\/])+//g;
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04006245 if(defined $Cache{"identifyHeader"}{$LibVersion}{$Header}) {
6246 return $Cache{"identifyHeader"}{$LibVersion}{$Header};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006247 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04006248 return ($Cache{"identifyHeader"}{$LibVersion}{$Header} = identifyHeader_I($Header, $LibVersion));
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006249}
6250
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04006251sub identifyHeader_I($$)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006252{ # search for header by absolute path, relative path or name
6253 my ($Header, $LibVersion) = @_;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006254 if(-f $Header)
6255 { # it's relative or absolute path
6256 return get_abs_path($Header);
6257 }
6258 elsif($GlibcHeader{$Header} and not $GLIBC_TESTING
6259 and my $HeaderDir = find_in_defaults($Header))
6260 { # search for libc headers in the /usr/include
6261 # for non-libc target library before searching
6262 # in the library paths
6263 return joinPath($HeaderDir,$Header);
6264 }
6265 elsif(my $Path = $Include_Neighbors{$LibVersion}{$Header})
6266 { # search in the target library paths
6267 return $Path;
6268 }
6269 elsif($DefaultGccHeader{$Header})
6270 { # search in the internal GCC include paths
6271 return $DefaultGccHeader{$Header};
6272 }
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04006273 elsif(my $DefaultDir = find_in_defaults($Header))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006274 { # search in the default GCC include paths
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04006275 return joinPath($DefaultDir,$Header);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006276 }
6277 elsif($DefaultCppHeader{$Header})
6278 { # search in the default G++ include paths
6279 return $DefaultCppHeader{$Header};
6280 }
6281 elsif(my $AnyPath = selectSystemHeader($Header, $LibVersion))
6282 { # search everywhere in the system
6283 return $AnyPath;
6284 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04006285 elsif($OSgroup eq "macos")
6286 { # search in frameworks: "OpenGL/gl.h" is "OpenGL.framework/Headers/gl.h"
6287 if(my $Dir = get_dirname($Header))
6288 {
6289 my $RelPath = "Headers\/".get_filename($Header);
6290 if(my $HeaderDir = find_in_framework($RelPath, $Dir.".framework", $LibVersion)) {
6291 return joinPath($HeaderDir, $RelPath);
6292 }
6293 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006294 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04006295 # cannot find anything
6296 return "";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006297}
6298
6299sub getLocation($)
6300{
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04006301 if($_[0] and my $Info = $LibInfo{$Version}{"info"}{$_[0]})
6302 {
6303 if($Info=~/srcp[ ]*:[ ]*([\w\-\<\>\.\+\/\\]+):(\d+) /) {
6304 return ($1, $2);
6305 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006306 }
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04006307 return ();
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006308}
6309
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006310sub getNameByInfo($)
6311{
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04006312 if($_[0] and my $Info = $LibInfo{$Version}{"info"}{$_[0]})
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04006313 {
6314 if($Info=~/name[ ]*:[ ]*@(\d+) /)
6315 {
6316 if(my $NInfo = $LibInfo{$Version}{"info"}{$1})
6317 {
6318 if($NInfo=~/strg[ ]*:[ ]*(.*?)[ ]+lngt/)
6319 { # short unsigned int (may include spaces)
6320 return $1;
6321 }
6322 }
6323 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006324 }
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04006325 return "";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006326}
6327
6328sub getTreeStr($)
6329{
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04006330 if($_[0] and my $Info = $LibInfo{$Version}{"info"}{$_[0]})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006331 {
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04006332 if($Info=~/strg[ ]*:[ ]*([^ ]*)/)
6333 {
6334 my $Str = $1;
6335 if($C99Mode{$Version}
6336 and $Str=~/\Ac99_(.+)\Z/) {
6337 if($CppKeywords_A{$1}) {
6338 $Str=$1;
6339 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006340 }
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04006341 return $Str;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006342 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006343 }
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04006344 return "";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006345}
6346
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006347sub getFuncShortName($)
6348{
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04006349 if(my $Info = $LibInfo{$Version}{"info"}{$_[0]})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006350 {
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04006351 if($Info=~/ operator /)
6352 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04006353 if($Info=~/ conversion /)
6354 {
6355 if(my $Rid = $SymbolInfo{$Version}{$_[0]}{"Return"})
6356 {
6357 if(my $RName = $TypeInfo{$Version}{$Rid}{"Name"}) {
6358 return "operator ".$RName;
6359 }
6360 }
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04006361 }
6362 else
6363 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04006364 if($Info=~/ operator[ ]+([a-zA-Z]+) /)
6365 {
6366 if(my $Ind = $Operator_Indication{$1}) {
6367 return "operator".$Ind;
6368 }
6369 elsif(not $UnknownOperator{$1})
6370 {
6371 printMsg("WARNING", "unknown operator $1");
6372 $UnknownOperator{$1} = 1;
6373 }
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04006374 }
6375 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006376 }
6377 else
6378 {
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04006379 if($Info=~/name[ ]*:[ ]*@(\d+) /) {
6380 return getTreeStr($1);
6381 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006382 }
6383 }
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04006384 return "";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006385}
6386
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006387sub getFuncReturn($)
6388{
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04006389 if($_[0] and my $Info = $LibInfo{$Version}{"info"}{$_[0]})
6390 {
6391 if($Info=~/type[ ]*:[ ]*@(\d+) /)
6392 {
6393 if($LibInfo{$Version}{"info"}{$1}=~/retn[ ]*:[ ]*@(\d+) /) {
6394 return $1;
6395 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006396 }
6397 }
6398 return "";
6399}
6400
6401sub getFuncOrig($)
6402{
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04006403 if($_[0] and my $Info = $LibInfo{$Version}{"info"}{$_[0]})
6404 {
6405 if($Info=~/orig[ ]*:[ ]*@(\d+) /) {
6406 return $1;
6407 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006408 }
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04006409 return $_[0];
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006410}
6411
6412sub unmangleSymbol($)
6413{
6414 my $Symbol = $_[0];
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04006415 if(my @Unmngl = unmangleArray($Symbol)) {
6416 return $Unmngl[0];
6417 }
6418 return "";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006419}
6420
6421sub unmangleArray(@)
6422{
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04006423 if($_[0]=~/\A\?/)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006424 { # MSVC mangling
6425 my $UndNameCmd = get_CmdPath("undname");
6426 if(not $UndNameCmd) {
6427 exitStatus("Not_Found", "can't find \"undname\"");
6428 }
6429 writeFile("$TMP_DIR/unmangle", join("\n", @_));
Andrey Ponomarenkoa01311b2012-06-08 17:20:02 +04006430 return split(/\n/, `$UndNameCmd 0x8386 \"$TMP_DIR/unmangle\"`);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006431 }
6432 else
6433 { # GCC mangling
6434 my $CppFiltCmd = get_CmdPath("c++filt");
6435 if(not $CppFiltCmd) {
6436 exitStatus("Not_Found", "can't find c++filt in PATH");
6437 }
6438 my $Info = `$CppFiltCmd -h 2>&1`;
6439 if($Info=~/\@<file>/)
6440 {# new version of c++filt can take a file
6441 my $NoStrip = "";
6442 if($OSgroup eq "macos"
6443 or $OSgroup eq "windows") {
6444 $NoStrip = "-n";
6445 }
6446 writeFile("$TMP_DIR/unmangle", join("\n", @_));
6447 return split(/\n/, `$CppFiltCmd $NoStrip \@\"$TMP_DIR/unmangle\"`);
6448 }
6449 else
6450 { # old-style unmangling
6451 if($#_>$MAX_COMMAND_LINE_ARGUMENTS) {
6452 my @Half = splice(@_, 0, ($#_+1)/2);
6453 return (unmangleArray(@Half), unmangleArray(@_))
6454 }
6455 else
6456 {
6457 my $NoStrip = "";
6458 if($OSgroup eq "macos"
6459 or $OSgroup eq "windows") {
6460 $NoStrip = "-n";
6461 }
6462 my $Strings = join(" ", @_);
6463 return split(/\n/, `$CppFiltCmd $NoStrip $Strings`);
6464 }
6465 }
6466 }
6467}
6468
6469sub get_SignatureNoInfo($$)
6470{
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04006471 my ($Symbol, $LibVersion) = @_;
6472 if($Cache{"get_SignatureNoInfo"}{$LibVersion}{$Symbol}) {
6473 return $Cache{"get_SignatureNoInfo"}{$LibVersion}{$Symbol};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006474 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04006475 my ($MnglName, $VersionSpec, $SymbolVersion) = separate_symbol($Symbol);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006476 my $Signature = $tr_name{$MnglName}?$tr_name{$MnglName}:$MnglName;
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04006477 if($Symbol=~/\A(_Z|\?)/)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006478 { # C++
6479 $Signature=~s/\Qstd::basic_string<char, std::char_traits<char>, std::allocator<char> >\E/std::string/g;
6480 $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;
6481 }
6482 if(not $CheckObjectsOnly or $OSgroup=~/linux|bsd|beos/)
6483 { # ELF format marks data as OBJECT
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04006484 if($GlobalDataObject{$LibVersion}{$Symbol}) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006485 $Signature .= " [data]";
6486 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04006487 elsif($Symbol!~/\A(_Z|\?)/) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006488 $Signature .= " (...)";
6489 }
6490 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04006491 if(my $ChargeLevel = get_ChargeLevel($Symbol, $LibVersion))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006492 {
Andrey Ponomarenko16934472012-03-29 15:37:04 +04006493 my $ShortName = substr($Signature, 0, find_center($Signature, "("));
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006494 $Signature=~s/\A\Q$ShortName\E/$ShortName $ChargeLevel/g;
6495 }
6496 if($SymbolVersion) {
6497 $Signature .= $VersionSpec.$SymbolVersion;
6498 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04006499 return ($Cache{"get_SignatureNoInfo"}{$LibVersion}{$Symbol} = $Signature);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006500}
6501
6502sub get_ChargeLevel($$)
6503{
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04006504 my ($Symbol, $LibVersion) = @_;
6505 return "" if($Symbol!~/\A(_Z|\?)/);
6506 if(defined $CompleteSignature{$LibVersion}{$Symbol}
6507 and $CompleteSignature{$LibVersion}{$Symbol}{"Header"})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006508 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04006509 if($CompleteSignature{$LibVersion}{$Symbol}{"Constructor"})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006510 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04006511 if($Symbol=~/C1E/) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006512 return "[in-charge]";
6513 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04006514 elsif($Symbol=~/C2E/) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006515 return "[not-in-charge]";
6516 }
6517 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04006518 elsif($CompleteSignature{$LibVersion}{$Symbol}{"Destructor"})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006519 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04006520 if($Symbol=~/D1E/) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006521 return "[in-charge]";
6522 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04006523 elsif($Symbol=~/D2E/) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006524 return "[not-in-charge]";
6525 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04006526 elsif($Symbol=~/D0E/) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006527 return "[in-charge-deleting]";
6528 }
6529 }
6530 }
6531 else
6532 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04006533 if($Symbol=~/C1E/) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006534 return "[in-charge]";
6535 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04006536 elsif($Symbol=~/C2E/) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006537 return "[not-in-charge]";
6538 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04006539 elsif($Symbol=~/D1E/) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006540 return "[in-charge]";
6541 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04006542 elsif($Symbol=~/D2E/) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006543 return "[not-in-charge]";
6544 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04006545 elsif($Symbol=~/D0E/) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006546 return "[in-charge-deleting]";
6547 }
6548 }
6549 return "";
6550}
6551
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04006552sub get_Signature_M($$)
6553{
6554 my ($Symbol, $LibVersion) = @_;
6555 my $Signature_M = $tr_name{$Symbol};
6556 if(my $RTid = $CompleteSignature{$LibVersion}{$Symbol}{"Return"})
6557 { # add return type name
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04006558 $Signature_M = $TypeInfo{$LibVersion}{$RTid}{"Name"}." ".$Signature_M;
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04006559 }
6560 return $Signature_M;
6561}
6562
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006563sub get_Signature($$)
6564{
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04006565 my ($Symbol, $LibVersion) = @_;
6566 if($Cache{"get_Signature"}{$LibVersion}{$Symbol}) {
6567 return $Cache{"get_Signature"}{$LibVersion}{$Symbol};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006568 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04006569 my ($MnglName, $VersionSpec, $SymbolVersion) = separate_symbol($Symbol);
6570 if(isPrivateData($MnglName) or not $CompleteSignature{$LibVersion}{$Symbol}{"Header"})
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04006571 { # non-public global data
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04006572 return get_SignatureNoInfo($Symbol, $LibVersion);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006573 }
6574 my ($Func_Signature, @Param_Types_FromUnmangledName) = ();
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04006575 my $ShortName = $CompleteSignature{$LibVersion}{$Symbol}{"ShortName"};
6576 if($Symbol=~/\A(_Z|\?)/)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006577 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04006578 if(my $ClassId = $CompleteSignature{$LibVersion}{$Symbol}{"Class"}) {
6579 $Func_Signature = $TypeInfo{$LibVersion}{$ClassId}{"Name"}."::".(($CompleteSignature{$LibVersion}{$Symbol}{"Destructor"})?"~":"").$ShortName;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006580 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04006581 elsif(my $NameSpace = $CompleteSignature{$LibVersion}{$Symbol}{"NameSpace"}) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006582 $Func_Signature = $NameSpace."::".$ShortName;
6583 }
6584 else {
6585 $Func_Signature = $ShortName;
6586 }
6587 @Param_Types_FromUnmangledName = get_s_params($tr_name{$MnglName}, 0);
6588 }
6589 else {
6590 $Func_Signature = $MnglName;
6591 }
6592 my @ParamArray = ();
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04006593 foreach my $Pos (sort {int($a) <=> int($b)} keys(%{$CompleteSignature{$LibVersion}{$Symbol}{"Param"}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006594 {
6595 next if($Pos eq "");
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04006596 my $ParamTypeId = $CompleteSignature{$LibVersion}{$Symbol}{"Param"}{$Pos}{"type"};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006597 next if(not $ParamTypeId);
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04006598 my $ParamTypeName = $TypeInfo{$LibVersion}{$ParamTypeId}{"Name"};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006599 if(not $ParamTypeName) {
6600 $ParamTypeName = $Param_Types_FromUnmangledName[$Pos];
6601 }
6602 foreach my $Typedef (keys(%ChangedTypedef))
6603 {
6604 my $Base = $Typedef_BaseName{$LibVersion}{$Typedef};
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04006605 $ParamTypeName=~s/\b\Q$Typedef\E\b/$Base/g;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006606 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04006607 if(my $ParamName = $CompleteSignature{$LibVersion}{$Symbol}{"Param"}{$Pos}{"name"}) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006608 push(@ParamArray, create_member_decl($ParamTypeName, $ParamName));
6609 }
6610 else {
6611 push(@ParamArray, $ParamTypeName);
6612 }
6613 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04006614 if($CompleteSignature{$LibVersion}{$Symbol}{"Data"}
6615 or $GlobalDataObject{$LibVersion}{$Symbol}) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006616 $Func_Signature .= " [data]";
6617 }
6618 else
6619 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04006620 if(my $ChargeLevel = get_ChargeLevel($Symbol, $LibVersion))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006621 { # add [in-charge]
6622 $Func_Signature .= " ".$ChargeLevel;
6623 }
6624 $Func_Signature .= " (".join(", ", @ParamArray).")";
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04006625 if($CompleteSignature{$LibVersion}{$Symbol}{"Const"}
6626 or $Symbol=~/\A_ZN(V|)K/) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006627 $Func_Signature .= " const";
6628 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04006629 if($CompleteSignature{$LibVersion}{$Symbol}{"Volatile"}
6630 or $Symbol=~/\A_ZN(K|)V/) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006631 $Func_Signature .= " volatile";
6632 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04006633 if($CompleteSignature{$LibVersion}{$Symbol}{"Static"}
6634 and $Symbol=~/\A(_Z|\?)/)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006635 {# for static methods
6636 $Func_Signature .= " [static]";
6637 }
6638 }
6639 if(defined $ShowRetVal
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04006640 and my $ReturnTId = $CompleteSignature{$LibVersion}{$Symbol}{"Return"}) {
6641 $Func_Signature .= ":".$TypeInfo{$LibVersion}{$ReturnTId}{"Name"};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006642 }
6643 if($SymbolVersion) {
6644 $Func_Signature .= $VersionSpec.$SymbolVersion;
6645 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04006646 return ($Cache{"get_Signature"}{$LibVersion}{$Symbol} = $Func_Signature);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006647}
6648
6649sub create_member_decl($$)
6650{
6651 my ($TName, $Member) = @_;
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04006652 if($TName=~/\([\*]+\)/)
6653 {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006654 $TName=~s/\(([\*]+)\)/\($1$Member\)/;
6655 return $TName;
6656 }
6657 else
6658 {
6659 my @ArraySizes = ();
6660 while($TName=~s/(\[[^\[\]]*\])\Z//) {
6661 push(@ArraySizes, $1);
6662 }
6663 return $TName." ".$Member.join("", @ArraySizes);
6664 }
6665}
6666
6667sub getFuncType($)
6668{
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04006669 if($_[0] and my $Info = $LibInfo{$Version}{"info"}{$_[0]})
6670 {
6671 if($Info=~/type[ ]*:[ ]*@(\d+) /)
6672 {
6673 if(my $Type = $LibInfo{$Version}{"info_type"}{$1})
6674 {
6675 if($Type eq "method_type") {
6676 return "Method";
6677 }
6678 elsif($Type eq "function_type") {
6679 return "Function";
6680 }
6681 else {
6682 return "Other";
6683 }
6684 }
6685 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006686 }
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04006687 return ""
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006688}
6689
6690sub getFuncTypeId($)
6691{
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04006692 if($_[0] and my $Info = $LibInfo{$Version}{"info"}{$_[0]})
6693 {
6694 if($Info=~/type[ ]*:[ ]*@(\d+)( |\Z)/) {
6695 return $1;
6696 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006697 }
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04006698 return 0;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006699}
6700
6701sub isNotAnon($) {
6702 return (not isAnon($_[0]));
6703}
6704
6705sub isAnon($)
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04006706{ # "._N" or "$_N" in older GCC versions
6707 return ($_[0] and $_[0]=~/(\.|\$)\_\d+|anon\-/);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006708}
6709
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006710sub formatName($)
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04006711{ # type name correction
6712 if(defined $Cache{"formatName"}{$_[0]}) {
6713 return $Cache{"formatName"}{$_[0]};
6714 }
6715
6716 $_ = $_[0];
6717
6718 s/\A[ ]+|[ ]+\Z//g;
6719 s/[ ]{2,}/ /g;
6720 s/[ ]*(\W)[ ]*/$1/g;
6721
6722 s/\bvolatile const\b/const volatile/g;
6723
6724 s/\b(long long|short|long) unsigned\b/unsigned $1/g;
6725 s/\b(short|long) int\b/$1/g;
6726
6727 s/([\)\]])(const|volatile)\b/$1 $2/g;
6728
6729 while(s/>>/> >/g) {};
6730
6731 s/\b(operator[ ]*)> >/$1>>/;
6732
6733 return ($Cache{"formatName"}{$_[0]}=$_);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006734}
6735
6736sub get_HeaderDeps($$)
6737{
6738 my ($AbsPath, $LibVersion) = @_;
6739 return () if(not $AbsPath or not $LibVersion);
6740 if(defined $Cache{"get_HeaderDeps"}{$LibVersion}{$AbsPath}) {
6741 return @{$Cache{"get_HeaderDeps"}{$LibVersion}{$AbsPath}};
6742 }
6743 my %IncDir = ();
6744 detect_recursive_includes($AbsPath, $LibVersion);
6745 foreach my $HeaderPath (keys(%{$RecursiveIncludes{$LibVersion}{$AbsPath}}))
6746 {
6747 next if(not $HeaderPath);
6748 next if($MAIN_CPP_DIR and $HeaderPath=~/\A\Q$MAIN_CPP_DIR\E([\/\\]|\Z)/);
6749 my $Dir = get_dirname($HeaderPath);
6750 foreach my $Prefix (keys(%{$Header_Include_Prefix{$LibVersion}{$AbsPath}{$HeaderPath}}))
6751 {
6752 my $Dep = $Dir;
6753 if($Prefix)
6754 {
6755 if($OSgroup eq "windows")
6756 { # case insensitive seach on windows
6757 if(not $Dep=~s/[\/\\]+\Q$Prefix\E\Z//ig) {
6758 next;
6759 }
6760 }
6761 elsif($OSgroup eq "macos")
6762 { # seach in frameworks
6763 if(not $Dep=~s/[\/\\]+\Q$Prefix\E\Z//g)
6764 {
6765 if($HeaderPath=~/(.+\.framework)\/Headers\/([^\/]+)/)
6766 {# frameworks
6767 my ($HFramework, $HName) = ($1, $2);
6768 $Dep = $HFramework;
6769 }
6770 else
6771 {# mismatch
6772 next;
6773 }
6774 }
6775 }
6776 elsif(not $Dep=~s/[\/\\]+\Q$Prefix\E\Z//g)
6777 { # Linux, FreeBSD
6778 next;
6779 }
6780 }
6781 if(not $Dep)
6782 { # nothing to include
6783 next;
6784 }
6785 if(is_default_include_dir($Dep))
6786 { # included by the compiler
6787 next;
6788 }
6789 if(get_depth($Dep)==1)
6790 { # too short
6791 next;
6792 }
6793 if(isLibcDir($Dep))
6794 { # do NOT include /usr/include/{sys,bits}
6795 next;
6796 }
6797 $IncDir{$Dep}=1;
6798 }
6799 }
6800 $Cache{"get_HeaderDeps"}{$LibVersion}{$AbsPath} = sortIncPaths([keys(%IncDir)], $LibVersion);
6801 return @{$Cache{"get_HeaderDeps"}{$LibVersion}{$AbsPath}};
6802}
6803
6804sub sortIncPaths($$)
6805{
6806 my ($ArrRef, $LibVersion) = @_;
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04006807 if(not $ArrRef or $#{$ArrRef}<0) {
6808 return $ArrRef;
6809 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006810 @{$ArrRef} = sort {$b cmp $a} @{$ArrRef};
6811 @{$ArrRef} = sort {get_depth($a)<=>get_depth($b)} @{$ArrRef};
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04006812 @{$ArrRef} = sort {sortDeps($b, $a, $LibVersion)} @{$ArrRef};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006813 return $ArrRef;
6814}
6815
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04006816sub sortDeps($$$)
6817{
6818 if($Header_Dependency{$_[2]}{$_[0]}
6819 and not $Header_Dependency{$_[2]}{$_[1]}) {
6820 return 1;
6821 }
6822 elsif(not $Header_Dependency{$_[2]}{$_[0]}
6823 and $Header_Dependency{$_[2]}{$_[1]}) {
6824 return -1;
6825 }
6826 return 0;
6827}
6828
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006829sub joinPath($$) {
6830 return join($SLASH, @_);
6831}
6832
6833sub get_namespace_additions($)
6834{
6835 my $NameSpaces = $_[0];
6836 my ($Additions, $AddNameSpaceId) = ("", 1);
6837 foreach my $NS (sort {$a=~/_/ <=> $b=~/_/} sort {lc($a) cmp lc($b)} keys(%{$NameSpaces}))
6838 {
6839 next if($SkipNameSpaces{$Version}{$NS});
6840 next if(not $NS or $NameSpaces->{$NS}==-1);
6841 next if($NS=~/(\A|::)iterator(::|\Z)/i);
6842 next if($NS=~/\A__/i);
6843 next if(($NS=~/\Astd::/ or $NS=~/\A(std|tr1|rel_ops|fcntl)\Z/) and not $STDCXX_TESTING);
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04006844 $NestedNameSpaces{$Version}{$NS} = 1; # for future use in reports
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006845 my ($TypeDecl_Prefix, $TypeDecl_Suffix) = ();
6846 my @NS_Parts = split(/::/, $NS);
6847 next if($#NS_Parts==-1);
6848 next if($NS_Parts[0]=~/\A(random|or)\Z/);
6849 foreach my $NS_Part (@NS_Parts)
6850 {
6851 $TypeDecl_Prefix .= "namespace $NS_Part\{";
6852 $TypeDecl_Suffix .= "}";
6853 }
6854 my $TypeDecl = $TypeDecl_Prefix."typedef int tmp_add_type_$AddNameSpaceId;".$TypeDecl_Suffix;
6855 my $FuncDecl = "$NS\:\:tmp_add_type_$AddNameSpaceId tmp_add_func_$AddNameSpaceId(){return 0;};";
6856 $Additions.=" $TypeDecl\n $FuncDecl\n";
6857 $AddNameSpaceId+=1;
6858 }
6859 return $Additions;
6860}
6861
6862sub path_format($$)
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04006863{ # forward slash to pass into MinGW GCC
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006864 my ($Path, $Fmt) = @_;
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04006865 if($Fmt eq "windows")
6866 {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006867 $Path=~s/\//\\/g;
6868 $Path=lc($Path);
6869 }
6870 else {
6871 $Path=~s/\\/\//g;
6872 }
6873 return $Path;
6874}
6875
6876sub inc_opt($$)
6877{
6878 my ($Path, $Style) = @_;
6879 if($Style eq "GCC")
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04006880 { # GCC options
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006881 if($OSgroup eq "windows")
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04006882 { # to MinGW GCC
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006883 return "-I\"".path_format($Path, "unix")."\"";
6884 }
6885 elsif($OSgroup eq "macos"
6886 and $Path=~/\.framework\Z/)
6887 {# to Apple's GCC
6888 return "-F".esc(get_dirname($Path));
6889 }
6890 else {
6891 return "-I".esc($Path);
6892 }
6893 }
6894 elsif($Style eq "CL") {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04006895 return "/I \"".$Path."\"";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006896 }
6897 return "";
6898}
6899
6900sub platformSpecs($)
6901{
6902 my $LibVersion = $_[0];
6903 my $Arch = getArch($LibVersion);
6904 if($OStarget eq "symbian")
6905 { # options for GCCE compiler
6906 my %Symbian_Opts = map {$_=>1} (
6907 "-D__GCCE__",
6908 "-DUNICODE",
6909 "-fexceptions",
6910 "-D__SYMBIAN32__",
6911 "-D__MARM_INTERWORK__",
6912 "-D_UNICODE",
6913 "-D__S60_50__",
6914 "-D__S60_3X__",
6915 "-D__SERIES60_3X__",
6916 "-D__EPOC32__",
6917 "-D__MARM__",
6918 "-D__EABI__",
6919 "-D__MARM_ARMV5__",
6920 "-D__SUPPORT_CPP_EXCEPTIONS__",
6921 "-march=armv5t",
6922 "-mapcs",
6923 "-mthumb-interwork",
6924 "-DEKA2",
6925 "-DSYMBIAN_ENABLE_SPLIT_HEADERS"
6926 );
6927 return join(" ", keys(%Symbian_Opts));
6928 }
6929 elsif($OSgroup eq "windows"
6930 and get_dumpmachine($GCC_PATH)=~/mingw/i)
6931 { # add options to MinGW compiler
6932 # to simulate the MSVC compiler
6933 my %MinGW_Opts = map {$_=>1} (
6934 "-D_WIN32",
6935 "-D_STDCALL_SUPPORTED",
6936 "-D__int64=\"long long\"",
6937 "-D__int32=int",
6938 "-D__int16=short",
6939 "-D__int8=char",
6940 "-D__possibly_notnullterminated=\" \"",
6941 "-D__nullterminated=\" \"",
6942 "-D__nullnullterminated=\" \"",
6943 "-D__w64=\" \"",
6944 "-D__ptr32=\" \"",
6945 "-D__ptr64=\" \"",
6946 "-D__forceinline=inline",
6947 "-D__inline=inline",
6948 "-D__uuidof(x)=IID()",
6949 "-D__try=",
6950 "-D__except(x)=",
6951 "-D__declspec(x)=__attribute__((x))",
6952 "-D__pragma(x)=",
6953 "-D_inline=inline",
6954 "-D__forceinline=__inline",
6955 "-D__stdcall=__attribute__((__stdcall__))",
6956 "-D__cdecl=__attribute__((__cdecl__))",
6957 "-D__fastcall=__attribute__((__fastcall__))",
6958 "-D__thiscall=__attribute__((__thiscall__))",
6959 "-D_stdcall=__attribute__((__stdcall__))",
6960 "-D_cdecl=__attribute__((__cdecl__))",
6961 "-D_fastcall=__attribute__((__fastcall__))",
6962 "-D_thiscall=__attribute__((__thiscall__))",
6963 "-DSHSTDAPI_(x)=x",
6964 "-D_MSC_EXTENSIONS",
6965 "-DSECURITY_WIN32",
6966 "-D_MSC_VER=1500",
6967 "-D_USE_DECLSPECS_FOR_SAL",
6968 "-D__noop=\" \"",
6969 "-DDECLSPEC_DEPRECATED=\" \"",
6970 "-D__builtin_alignof(x)=__alignof__(x)",
6971 "-DSORTPP_PASS");
6972 if($Arch eq "x86") {
6973 $MinGW_Opts{"-D_M_IX86=300"}=1;
6974 }
6975 elsif($Arch eq "x86_64") {
6976 $MinGW_Opts{"-D_M_AMD64=300"}=1;
6977 }
6978 elsif($Arch eq "ia64") {
6979 $MinGW_Opts{"-D_M_IA64=300"}=1;
6980 }
6981 return join(" ", keys(%MinGW_Opts));
6982 }
6983 return "";
6984}
6985
6986my %C_Structure = map {$_=>1} (
6987# FIXME: Can't separate union and struct data types before dumping,
6988# so it sometimes cause compilation errors for unknown reason
6989# when trying to declare TYPE* tmp_add_class_N
6990# This is a list of such structures + list of other C structures
6991 "sigval",
6992 "sigevent",
6993 "sigaction",
6994 "sigvec",
6995 "sigstack",
6996 "timeval",
6997 "timezone",
6998 "rusage",
6999 "rlimit",
7000 "wait",
7001 "flock",
7002 "stat",
7003 "_stat",
7004 "stat32",
7005 "_stat32",
7006 "stat64",
7007 "_stat64",
7008 "_stati64",
7009 "if_nameindex",
7010 "usb_device",
7011 "sigaltstack",
7012 "sysinfo",
7013 "timeLocale",
7014 "tcp_debug",
7015 "rpc_createerr",
7016# Other C structures appearing in every dump
7017 "timespec",
7018 "random_data",
7019 "drand48_data",
7020 "_IO_marker",
7021 "_IO_FILE",
7022 "lconv",
7023 "sched_param",
7024 "tm",
7025 "itimerspec",
7026 "_pthread_cleanup_buffer",
7027 "fd_set",
7028 "siginfo"
7029);
7030
7031sub getCompileCmd($$$)
7032{
7033 my ($Path, $Opt, $Inc) = @_;
7034 my $GccCall = $GCC_PATH;
7035 if($Opt) {
7036 $GccCall .= " ".$Opt;
7037 }
7038 $GccCall .= " -x ";
7039 if($OSgroup eq "macos") {
7040 $GccCall .= "objective-";
7041 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04007042 if(check_gcc($GCC_PATH, "4"))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007043 { # compile as "C++" header
7044 # to obtain complete dump using GCC 4.0
7045 $GccCall .= "c++-header";
7046 }
7047 else
7048 { # compile as "C++" source
7049 # GCC 3.3 cannot compile headers
7050 $GccCall .= "c++";
7051 }
7052 if(my $Opts = platformSpecs($Version))
7053 {# platform-specific options
7054 $GccCall .= " ".$Opts;
7055 }
7056 # allow extra qualifications
7057 # and other nonconformant code
7058 $GccCall .= " -fpermissive -w";
7059 if($NoStdInc)
7060 {
7061 $GccCall .= " -nostdinc";
7062 $GccCall .= " -nostdinc++";
7063 }
7064 if($CompilerOptions{$Version})
7065 { # user-defined options
7066 $GccCall .= " ".$CompilerOptions{$Version};
7067 }
Andrey Ponomarenkoa01311b2012-06-08 17:20:02 +04007068 $GccCall .= " \"$Path\"";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007069 if($Inc)
7070 { # include paths
7071 $GccCall .= " ".$Inc;
7072 }
7073 return $GccCall;
7074}
7075
7076sub getDump()
7077{
7078 if(not $GCC_PATH) {
7079 exitStatus("Error", "internal error - GCC path is not set");
7080 }
7081 my %HeaderElems = (
7082 # Types
7083 "stdio.h" => ["FILE", "va_list"],
Andrey Ponomarenko85043792012-05-14 16:48:07 +04007084 "stddef.h" => ["NULL", "ptrdiff_t"],
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007085 "stdint.h" => ["uint32_t", "int32_t", "uint64_t"],
7086 "time.h" => ["time_t"],
7087 "sys/types.h" => ["ssize_t", "u_int32_t", "u_short", "u_char",
7088 "u_int", "off_t", "u_quad_t", "u_long", "size_t", "mode_t"],
7089 "unistd.h" => ["gid_t", "uid_t"],
7090 "stdbool.h" => ["_Bool"],
7091 "rpc/xdr.h" => ["bool_t"],
7092 "in_systm.h" => ["n_long", "n_short"],
7093 # Fields
Andrey Ponomarenkobede8372012-03-29 17:43:21 +04007094 "arpa/inet.h" => ["fw_src", "ip_src"],
7095 # Functions
7096 "stdlib.h" => ["free", "malloc"],
Andrey Ponomarenko85043792012-05-14 16:48:07 +04007097 "string.h" => ["memmove", "strcmp"]
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007098 );
7099 my %AutoPreamble = ();
Andrey Ponomarenko85043792012-05-14 16:48:07 +04007100 foreach (keys(%HeaderElems))
7101 {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007102 foreach my $Elem (@{$HeaderElems{$_}}) {
7103 $AutoPreamble{$Elem}=$_;
7104 }
7105 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04007106 my $TmpHeaderPath = $TMP_DIR."/dump".$Version.".h";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007107 my $MHeaderPath = $TmpHeaderPath;
Andrey Ponomarenko85043792012-05-14 16:48:07 +04007108 open(TMP_HEADER, ">", $TmpHeaderPath) || die ("can't open file \'$TmpHeaderPath\': $!\n");
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007109 if(my $AddDefines = $Descriptor{$Version}{"Defines"})
7110 {
7111 $AddDefines=~s/\n\s+/\n /g;
Andrey Ponomarenko85043792012-05-14 16:48:07 +04007112 print TMP_HEADER "\n // add defines\n ".$AddDefines."\n";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007113 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +04007114 print TMP_HEADER "\n // add includes\n";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007115 my @PreambleHeaders = keys(%{$Include_Preamble{$Version}});
7116 @PreambleHeaders = sort {int($Include_Preamble{$Version}{$a}{"Position"})<=>int($Include_Preamble{$Version}{$b}{"Position"})} @PreambleHeaders;
7117 foreach my $Header_Path (@PreambleHeaders) {
Andrey Ponomarenko85043792012-05-14 16:48:07 +04007118 print TMP_HEADER " #include \"".path_format($Header_Path, "unix")."\"\n";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007119 }
7120 my @Headers = keys(%{$Registered_Headers{$Version}});
7121 @Headers = sort {int($Registered_Headers{$Version}{$a}{"Pos"})<=>int($Registered_Headers{$Version}{$b}{"Pos"})} @Headers;
7122 foreach my $Header_Path (@Headers)
7123 {
7124 next if($Include_Preamble{$Version}{$Header_Path});
Andrey Ponomarenko85043792012-05-14 16:48:07 +04007125 print TMP_HEADER " #include \"".path_format($Header_Path, "unix")."\"\n";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007126 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +04007127 close(TMP_HEADER);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007128 my $IncludeString = getIncString(getIncPaths(@PreambleHeaders, @Headers), "GCC");
7129 if($Debug)
7130 { # debug mode
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04007131 writeFile($DEBUG_PATH{$Version}."/headers/direct-includes.txt", Dumper($Header_Includes{$Version}));
7132 writeFile($DEBUG_PATH{$Version}."/headers/recursive-includes.txt", Dumper($RecursiveIncludes{$Version}));
7133 writeFile($DEBUG_PATH{$Version}."/headers/include-paths.txt", Dumper($Cache{"get_HeaderDeps"}{$Version}));
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04007134 writeFile($DEBUG_PATH{$Version}."/headers/default-paths.txt", Dumper(\%DefaultIncPaths));
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007135 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +04007136
Andrey Ponomarenko5c09ef32012-06-14 18:17:33 +04007137 if(not keys(%{$TargetHeaders{$Version}}))
7138 { # Target headers
7139 addTargetHeaders($Version);
7140 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +04007141
7142 # clean memory
7143 %RecursiveIncludes = ();
7144 %Header_Include_Prefix = ();
7145 %Header_Includes = ();
7146
7147 # clean cache
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04007148 delete($Cache{"identifyHeader"});
Andrey Ponomarenko85043792012-05-14 16:48:07 +04007149 delete($Cache{"detect_header_includes"});
7150 delete($Cache{"selectSystemHeader"});
7151
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007152 # preprocessing stage
7153 checkPreprocessedUnit(callPreprocessor($TmpHeaderPath, $IncludeString, $Version));
Andrey Ponomarenko85043792012-05-14 16:48:07 +04007154
7155 # clean memory
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04007156 delete($Include_Neighbors{$Version});
Andrey Ponomarenko85043792012-05-14 16:48:07 +04007157
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007158 my $MContent = "";
7159 my $PreprocessCmd = getCompileCmd($TmpHeaderPath, "-E", $IncludeString);
7160 if($OStarget eq "windows"
7161 and get_dumpmachine($GCC_PATH)=~/mingw/i
7162 and $MinGWMode{$Version}!=-1)
7163 { # modify headers to compile by MinGW
7164 if(not $MContent)
7165 { # preprocessing
Andrey Ponomarenkoa01311b2012-06-08 17:20:02 +04007166 $MContent = `$PreprocessCmd 2>\"$TMP_DIR/null\"`;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007167 }
7168 if($MContent=~s/__asm\s*(\{[^{}]*?\}|[^{};]*)//g)
7169 { # __asm { ... }
7170 $MinGWMode{$Version}=1;
7171 }
7172 if($MContent=~s/\s+(\/ \/.*?)\n/\n/g)
7173 { # comments after preprocessing
7174 $MinGWMode{$Version}=1;
7175 }
7176 if($MContent=~s/(\W)(0x[a-f]+|\d+)(i|ui)(8|16|32|64)(\W)/$1$2$5/g)
7177 { # 0xffui8
7178 $MinGWMode{$Version}=1;
7179 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +04007180 if($MinGWMode{$Version})
7181 {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007182 printMsg("INFO", "Using MinGW compatibility mode");
Andrey Ponomarenkob8d203d2012-05-25 18:11:07 +04007183 $MHeaderPath = $TMP_DIR."/dump$Version.i";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007184 }
7185 }
7186 if(($COMMON_LANGUAGE{$Version} eq "C" or $CheckHeadersOnly)
7187 and $C99Mode{$Version}!=-1 and not $Cpp2003)
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04007188 { # rename C++ keywords in C code
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007189 if(not $MContent)
7190 { # preprocessing
Andrey Ponomarenkoa01311b2012-06-08 17:20:02 +04007191 $MContent = `$PreprocessCmd 2>\"$TMP_DIR/null\"`;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007192 }
7193 my $RegExp_C = join("|", keys(%CppKeywords_C));
7194 my $RegExp_F = join("|", keys(%CppKeywords_F));
7195 my $RegExp_O = join("|", keys(%CppKeywords_O));
7196 while($MContent=~s/(\A|\n[^\#\/\n][^\n]*?|\n)(\*\s*|\s+|\@|\,|\()($RegExp_C|$RegExp_F)(\s*(\,|\)|\;|\-\>|\.|\:\s*\d))/$1$2c99_$3$4/g)
7197 { # MATCH:
7198 # int foo(int new, int class, int (*new)(int));
7199 # unsigned private: 8;
7200 # DO NOT MATCH:
7201 # #pragma GCC visibility push(default)
7202 $C99Mode{$Version} = 1;
7203 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04007204 if($MContent=~s/([^\w\s]|\w\s+)(?<!operator )(delete)(\s*\()/$1c99_$2$3/g)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007205 { # MATCH:
7206 # int delete(...);
7207 # int explicit(...);
7208 # DO NOT MATCH:
7209 # void operator delete(...)
7210 $C99Mode{$Version} = 1;
7211 }
7212 if($MContent=~s/(\s+)($RegExp_O)(\s*(\;|\:))/$1c99_$2$3/g)
7213 { # MATCH:
7214 # int bool;
7215 # DO NOT MATCH:
7216 # bool X;
7217 # return *this;
7218 # throw;
7219 $C99Mode{$Version} = 1;
7220 }
7221 if($MContent=~s/(\s+)(operator)(\s*(\(\s*\)\s*[^\(\s]|\(\s*[^\)\s]))/$1c99_$2$3/g)
7222 { # MATCH:
7223 # int operator(...);
7224 # DO NOT MATCH:
7225 # int operator()(...);
7226 $C99Mode{$Version} = 1;
7227 }
7228 if($MContent=~s/([^\w\(\,\s]\s*|\s+)(operator)(\s*(\,\s*[^\(\s]|\)))/$1c99_$2$3/g)
7229 { # MATCH:
7230 # int foo(int operator);
7231 # int foo(int operator, int other);
7232 # DO NOT MATCH:
7233 # int operator,(...);
7234 $C99Mode{$Version} = 1;
7235 }
7236 if($MContent=~s/(\*\s*|\w\s+)(bool)(\s*(\,|\)))/$1c99_$2$3/g)
7237 { # MATCH:
7238 # int foo(gboolean *bool);
7239 # DO NOT MATCH:
7240 # void setTabEnabled(int index, bool);
7241 $C99Mode{$Version} = 1;
7242 }
7243 if($MContent=~s/(\w)([^\w\(\,\s]\s*|\s+)(this)(\s*(\,|\)))/$1$2c99_$3$4/g)
7244 { # MATCH:
7245 # int foo(int* this);
7246 # int bar(int this);
7247 # DO NOT MATCH:
7248 # baz(X, this);
7249 $C99Mode{$Version} = 1;
7250 }
7251 if($C99Mode{$Version}==1)
7252 { # try to change C++ "keyword" to "c99_keyword"
7253 printMsg("INFO", "Using C99 compatibility mode");
Andrey Ponomarenkob8d203d2012-05-25 18:11:07 +04007254 $MHeaderPath = $TMP_DIR."/dump$Version.i";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007255 }
7256 }
7257 if($C99Mode{$Version}==1
7258 or $MinGWMode{$Version}==1)
7259 { # compile the corrected preprocessor output
7260 writeFile($MHeaderPath, $MContent);
7261 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +04007262
7263 # clean memory
7264 undef $MContent;
7265
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007266 if($COMMON_LANGUAGE{$Version} eq "C++")
7267 { # add classes and namespaces to the dump
7268 my $CHdump = "-fdump-class-hierarchy -c";
7269 if($C99Mode{$Version}==1
7270 or $MinGWMode{$Version}==1) {
7271 $CHdump .= " -fpreprocessed";
7272 }
7273 my $ClassHierarchyCmd = getCompileCmd($MHeaderPath, $CHdump, $IncludeString);
7274 chdir($TMP_DIR);
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04007275 system($ClassHierarchyCmd." >null 2>&1");
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007276 chdir($ORIG_DIR);
7277 if(my $ClassDump = (cmd_find($TMP_DIR,"f","*.class",1))[0])
7278 {
7279 my %AddClasses = ();
7280 my $Content = readFile($ClassDump);
7281 foreach my $ClassInfo (split(/\n\n/, $Content))
7282 {
7283 if($ClassInfo=~/\AClass\s+(.+)\s*/i)
7284 {
7285 my $CName = $1;
7286 next if($CName=~/\A(__|_objc_|_opaque_)/);
7287 $TUnit_NameSpaces{$Version}{$CName} = -1;
7288 if($CName=~/\A[\w:]+\Z/)
7289 { # classes
7290 $AddClasses{$CName} = 1;
7291 }
7292 if($CName=~/(\w[\w:]*)::/)
7293 { # namespaces
7294 my $NS = $1;
7295 if(not defined $TUnit_NameSpaces{$Version}{$NS}) {
7296 $TUnit_NameSpaces{$Version}{$NS} = 1;
7297 }
7298 }
7299 }
7300 elsif($ClassInfo=~/\AVtable\s+for\s+(.+)\n((.|\n)+)\Z/i)
7301 { # read v-tables (advanced approach)
7302 my ($CName, $VTable) = ($1, $2);
7303 $ClassVTable_Content{$Version}{$CName} = $VTable;
7304 }
7305 }
Andrey Ponomarenkoa01311b2012-06-08 17:20:02 +04007306 foreach my $NS (keys(%{$AddNameSpaces{$Version}}))
7307 { # add user-defined namespaces
7308 $TUnit_NameSpaces{$Version}{$NS} = 1;
7309 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007310 if($Debug)
7311 { # debug mode
7312 mkpath($DEBUG_PATH{$Version});
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04007313 copy($ClassDump, $DEBUG_PATH{$Version}."/class-hierarchy-dump.txt");
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007314 }
7315 unlink($ClassDump);
7316 if(my $NS_Add = get_namespace_additions($TUnit_NameSpaces{$Version}))
7317 { # GCC on all supported platforms does not include namespaces to the dump by default
7318 appendFile($MHeaderPath, "\n // add namespaces\n".$NS_Add);
7319 }
7320 # some GCC versions don't include class methods to the TU dump by default
7321 my ($AddClass, $ClassNum) = ("", 0);
7322 foreach my $CName (sort keys(%AddClasses))
7323 {
7324 next if($C_Structure{$CName});
7325 next if(not $STDCXX_TESTING and $CName=~/\Astd::/);
7326 next if(($CName=~tr![:]!!)>2);
7327 next if($SkipTypes{$Version}{$CName});
7328 if($CName=~/\A(.+)::[^:]+\Z/
7329 and $AddClasses{$1}) {
7330 next;
7331 }
7332 $AddClass .= " $CName* tmp_add_class_".($ClassNum++).";\n";
7333 }
7334 appendFile($MHeaderPath, "\n // add classes\n".$AddClass);
7335 }
7336 }
7337 writeLog($Version, "Temporary header file \'$TmpHeaderPath\' with the following content will be compiled to create GCC translation unit dump:\n".readFile($TmpHeaderPath)."\n");
7338 # create TU dump
7339 my $TUdump = "-fdump-translation-unit -fkeep-inline-functions -c";
7340 if($C99Mode{$Version}==1
7341 or $MinGWMode{$Version}==1) {
7342 $TUdump .= " -fpreprocessed";
7343 }
7344 my $SyntaxTreeCmd = getCompileCmd($MHeaderPath, $TUdump, $IncludeString);
7345 writeLog($Version, "The GCC parameters:\n $SyntaxTreeCmd\n\n");
7346 chdir($TMP_DIR);
Andrey Ponomarenkoa01311b2012-06-08 17:20:02 +04007347 system($SyntaxTreeCmd." >\"$TMP_DIR/tu_errors\" 2>&1");
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007348 if($?)
7349 { # failed to compile, but the TU dump still can be created
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04007350 my $Errors = readFile($TMP_DIR."/tu_errors");
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007351 if($Errors=~/c99_/)
7352 { # disable c99 mode
7353 $C99Mode{$Version}=-1;
7354 printMsg("INFO", "Disabling C99 compatibility mode");
7355 resetLogging($Version);
7356 $TMP_DIR = tempdir(CLEANUP=>1);
7357 return getDump();
7358 }
7359 elsif($AutoPreambleMode{$Version}!=-1
7360 and my $TErrors = $Errors)
7361 {
7362 my %Types = ();
7363 while($TErrors=~s/error\:\s*(field\s*|)\W+(.+?)\W+//)
7364 { # error: 'FILE' has not been declared
7365 $Types{$2}=1;
7366 }
7367 my %AddHeaders = ();
7368 foreach my $Type (keys(%Types))
7369 {
7370 if(my $Header = $AutoPreamble{$Type}) {
7371 $AddHeaders{path_format($Header, $OSgroup)}=$Type;
7372 }
7373 }
7374 if(my @Headers = sort {$b cmp $a} keys(%AddHeaders))
7375 { # sys/types.h should be the first
7376 foreach my $Num (0 .. $#Headers)
7377 {
7378 my $Name = $Headers[$Num];
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04007379 if(my $Path = identifyHeader($Name, $Version))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007380 { # add automatic preamble headers
7381 if(defined $Include_Preamble{$Version}{$Path})
7382 { # already added
7383 next;
7384 }
7385 $Include_Preamble{$Version}{$Path}{"Position"} = keys(%{$Include_Preamble{$Version}});
7386 my $Type = $AddHeaders{$Name};
7387 printMsg("INFO", "Add \'$Name\' preamble header for \'$Type\'");
7388 }
7389 }
7390 $AutoPreambleMode{$Version}=-1;
7391 resetLogging($Version);
7392 $TMP_DIR = tempdir(CLEANUP=>1);
7393 return getDump();
7394 }
7395 }
7396 elsif($MinGWMode{$Version}!=-1)
7397 {
7398 $MinGWMode{$Version}=-1;
7399 resetLogging($Version);
7400 $TMP_DIR = tempdir(CLEANUP=>1);
7401 return getDump();
7402 }
7403 # FIXME: handle other errors and try to recompile
7404 writeLog($Version, $Errors);
7405 printMsg("ERROR", "some errors occurred when compiling headers");
7406 printErrorLog($Version);
7407 $COMPILE_ERRORS = $ERROR_CODE{"Compile_Error"};
7408 writeLog($Version, "\n");# new line
7409 }
7410 chdir($ORIG_DIR);
7411 unlink($TmpHeaderPath, $MHeaderPath);
7412 return (cmd_find($TMP_DIR,"f","*.tu",1))[0];
7413}
7414
7415sub cmd_file($)
7416{
7417 my $Path = $_[0];
7418 return "" if(not $Path or not -e $Path);
7419 if(my $CmdPath = get_CmdPath("file")) {
7420 return `$CmdPath -b \"$Path\"`;
7421 }
7422 return "";
7423}
7424
7425sub getIncString($$)
7426{
7427 my ($ArrRef, $Style) = @_;
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04007428 return "" if(not $ArrRef or $#{$ArrRef}<0);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007429 my $String = "";
7430 foreach (@{$ArrRef}) {
7431 $String .= " ".inc_opt($_, $Style);
7432 }
7433 return $String;
7434}
7435
7436sub getIncPaths(@)
7437{
7438 my @HeaderPaths = @_;
7439 my @IncPaths = ();
7440 if($INC_PATH_AUTODETECT{$Version})
7441 { # auto-detecting dependencies
7442 my %Includes = ();
7443 foreach my $HPath (@HeaderPaths)
7444 {
7445 foreach my $Dir (get_HeaderDeps($HPath, $Version))
7446 {
7447 if($Skip_Include_Paths{$Version}{$Dir}) {
7448 next;
7449 }
Andrey Ponomarenkoa01311b2012-06-08 17:20:02 +04007450 if($SystemRoot)
7451 {
7452 if($Skip_Include_Paths{$Version}{$SystemRoot.$Dir}) {
7453 next;
7454 }
7455 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007456 $Includes{$Dir}=1;
7457 }
7458 }
7459 foreach my $Dir (keys(%{$Add_Include_Paths{$Version}}))
7460 { # added by user
7461 next if($Includes{$Dir});
7462 push(@IncPaths, $Dir);
7463 }
7464 foreach my $Dir (@{sortIncPaths([keys(%Includes)], $Version)}) {
7465 push(@IncPaths, $Dir);
7466 }
7467 }
7468 else
7469 { # user-defined paths
7470 foreach my $Dir (sort {get_depth($a)<=>get_depth($b)}
7471 sort {$b cmp $a} keys(%{$Include_Paths{$Version}})) {
7472 push(@IncPaths, $Dir);
7473 }
7474 }
7475 return \@IncPaths;
7476}
7477
7478sub callPreprocessor($$$)
7479{
7480 my ($Path, $Inc, $LibVersion) = @_;
7481 return "" if(not $Path or not -f $Path);
7482 my $IncludeString=$Inc;
7483 if(not $Inc) {
7484 $IncludeString = getIncString(getIncPaths($Path), "GCC");
7485 }
7486 my $Cmd = getCompileCmd($Path, "-dD -E", $IncludeString);
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04007487 my $Out = $TMP_DIR."/preprocessed";
Andrey Ponomarenkoa01311b2012-06-08 17:20:02 +04007488 system($Cmd." >\"$Out\" 2>\"$TMP_DIR/null\"");
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04007489 return $Out;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007490}
7491
7492sub cmd_find($$$$)
7493{ # native "find" is much faster than File::Find (~6x)
7494 # also the File::Find doesn't support --maxdepth N option
7495 # so using the cross-platform wrapper for the native one
7496 my ($Path, $Type, $Name, $MaxDepth) = @_;
7497 return () if(not $Path or not -e $Path);
7498 if($OSgroup eq "windows")
7499 {
7500 my $DirCmd = get_CmdPath("dir");
7501 if(not $DirCmd) {
7502 exitStatus("Not_Found", "can't find \"dir\" command");
7503 }
7504 $Path=~s/[\\]+\Z//;
7505 $Path = get_abs_path($Path);
7506 $Path = path_format($Path, $OSgroup);
7507 my $Cmd = $DirCmd." \"$Path\" /B /O";
7508 if($MaxDepth!=1) {
7509 $Cmd .= " /S";
7510 }
7511 if($Type eq "d") {
7512 $Cmd .= " /AD";
7513 }
7514 my @Files = ();
7515 if($Name)
7516 { # FIXME: how to search file names in MS shell?
7517 $Name=~s/\*/.*/g if($Name!~/\]/);
7518 foreach my $File (split(/\n/, `$Cmd`))
7519 {
7520 if($File=~/$Name\Z/i) {
7521 push(@Files, $File);
7522 }
7523 }
7524 }
7525 else {
Andrey Ponomarenkoa01311b2012-06-08 17:20:02 +04007526 @Files = split(/\n/, `$Cmd 2>\"$TMP_DIR/null\"`);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007527 }
7528 my @AbsPaths = ();
7529 foreach my $File (@Files)
7530 {
7531 if(not is_abs($File)) {
7532 $File = joinPath($Path, $File);
7533 }
7534 if($Type eq "f" and not -f $File)
7535 { # skip dirs
7536 next;
7537 }
7538 push(@AbsPaths, path_format($File, $OSgroup));
7539 }
7540 if($Type eq "d") {
7541 push(@AbsPaths, $Path);
7542 }
7543 return @AbsPaths;
7544 }
7545 else
7546 {
7547 my $FindCmd = get_CmdPath("find");
7548 if(not $FindCmd) {
7549 exitStatus("Not_Found", "can't find a \"find\" command");
7550 }
7551 $Path = get_abs_path($Path);
7552 if(-d $Path and -l $Path
7553 and $Path!~/\/\Z/)
7554 { # for directories that are symlinks
7555 $Path.="/";
7556 }
7557 my $Cmd = $FindCmd." \"$Path\"";
7558 if($MaxDepth) {
7559 $Cmd .= " -maxdepth $MaxDepth";
7560 }
7561 if($Type) {
7562 $Cmd .= " -type $Type";
7563 }
7564 if($Name)
7565 { # file name
7566 if($Name=~/\]/) {
7567 $Cmd .= " -regex \"$Name\"";
7568 }
7569 else {
7570 $Cmd .= " -name \"$Name\"";
7571 }
7572 }
Andrey Ponomarenkoa01311b2012-06-08 17:20:02 +04007573 return split(/\n/, `$Cmd 2>\"$TMP_DIR/null\"`);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007574 }
7575}
7576
7577sub unpackDump($)
7578{
7579 my $Path = $_[0];
7580 return "" if(not $Path or not -e $Path);
7581 $Path = get_abs_path($Path);
7582 $Path = path_format($Path, $OSgroup);
7583 my ($Dir, $FileName) = separate_path($Path);
7584 my $UnpackDir = $TMP_DIR."/unpack";
7585 rmtree($UnpackDir);
7586 mkpath($UnpackDir);
7587 if($FileName=~s/\Q.zip\E\Z//g)
7588 { # *.zip
7589 my $UnzipCmd = get_CmdPath("unzip");
7590 if(not $UnzipCmd) {
7591 exitStatus("Not_Found", "can't find \"unzip\" command");
7592 }
7593 chdir($UnpackDir);
Andrey Ponomarenkoa01311b2012-06-08 17:20:02 +04007594 system("$UnzipCmd \"$Path\" >contents.txt");
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007595 if($?) {
7596 exitStatus("Error", "can't extract \'$Path\'");
7597 }
7598 chdir($ORIG_DIR);
7599 my @Contents = ();
7600 foreach (split("\n", readFile("$UnpackDir/contents.txt")))
7601 {
7602 if(/inflating:\s*([^\s]+)/) {
7603 push(@Contents, $1);
7604 }
7605 }
7606 if(not @Contents) {
7607 exitStatus("Error", "can't extract \'$Path\'");
7608 }
7609 return joinPath($UnpackDir, $Contents[0]);
7610 }
7611 elsif($FileName=~s/\Q.tar.gz\E\Z//g)
7612 { # *.tar.gz
7613 if($OSgroup eq "windows")
7614 { # -xvzf option is not implemented in tar.exe (2003)
7615 # use "gzip.exe -k -d -f" + "tar.exe -xvf" instead
7616 my $TarCmd = get_CmdPath("tar");
7617 if(not $TarCmd) {
7618 exitStatus("Not_Found", "can't find \"tar\" command");
7619 }
7620 my $GzipCmd = get_CmdPath("gzip");
7621 if(not $GzipCmd) {
7622 exitStatus("Not_Found", "can't find \"gzip\" command");
7623 }
7624 chdir($UnpackDir);
Andrey Ponomarenkoa01311b2012-06-08 17:20:02 +04007625 system("$GzipCmd -k -d -f \"$Path\""); # keep input files (-k)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007626 if($?) {
7627 exitStatus("Error", "can't extract \'$Path\'");
7628 }
Andrey Ponomarenkoa01311b2012-06-08 17:20:02 +04007629 system("$TarCmd -xvf \"$Dir\\$FileName.tar\" >contents.txt");
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007630 if($?) {
7631 exitStatus("Error", "can't extract \'$Path\'");
7632 }
7633 chdir($ORIG_DIR);
7634 unlink($Dir."/".$FileName.".tar");
7635 my @Contents = split("\n", readFile("$UnpackDir/contents.txt"));
7636 if(not @Contents) {
7637 exitStatus("Error", "can't extract \'$Path\'");
7638 }
7639 return joinPath($UnpackDir, $Contents[0]);
7640 }
7641 else
7642 { # Unix
7643 my $TarCmd = get_CmdPath("tar");
7644 if(not $TarCmd) {
7645 exitStatus("Not_Found", "can't find \"tar\" command");
7646 }
7647 chdir($UnpackDir);
Andrey Ponomarenkoa01311b2012-06-08 17:20:02 +04007648 system("$TarCmd -xvzf \"$Path\" >contents.txt");
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007649 if($?) {
7650 exitStatus("Error", "can't extract \'$Path\'");
7651 }
7652 chdir($ORIG_DIR);
7653 # The content file name may be different
7654 # from the package file name
7655 my @Contents = split("\n", readFile("$UnpackDir/contents.txt"));
7656 if(not @Contents) {
7657 exitStatus("Error", "can't extract \'$Path\'");
7658 }
7659 return joinPath($UnpackDir, $Contents[0]);
7660 }
7661 }
7662}
7663
7664sub createArchive($$)
7665{
7666 my ($Path, $To) = @_;
Andrey Ponomarenko5c09ef32012-06-14 18:17:33 +04007667 if(not $To) {
7668 $To = ".";
7669 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007670 if(not $Path or not -e $Path
7671 or not -d $To) {
7672 return "";
7673 }
7674 my ($From, $Name) = separate_path($Path);
7675 if($OSgroup eq "windows")
7676 { # *.zip
7677 my $ZipCmd = get_CmdPath("zip");
7678 if(not $ZipCmd) {
7679 exitStatus("Not_Found", "can't find \"zip\"");
7680 }
7681 my $Pkg = $To."/".$Name.".zip";
7682 unlink($Pkg);
7683 chdir($To);
Andrey Ponomarenkoa01311b2012-06-08 17:20:02 +04007684 system("$ZipCmd -j \"$Name.zip\" \"$Path\" >\"$TMP_DIR/null\"");
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007685 if($?)
7686 { # cannot allocate memory (or other problems with "zip")
7687 unlink($Path);
7688 exitStatus("Error", "can't pack the ABI dump: ".$!);
7689 }
7690 chdir($ORIG_DIR);
7691 unlink($Path);
7692 return $Pkg;
7693 }
7694 else
7695 { # *.tar.gz
7696 my $TarCmd = get_CmdPath("tar");
7697 if(not $TarCmd) {
7698 exitStatus("Not_Found", "can't find \"tar\"");
7699 }
7700 my $GzipCmd = get_CmdPath("gzip");
7701 if(not $GzipCmd) {
7702 exitStatus("Not_Found", "can't find \"gzip\"");
7703 }
7704 my $Pkg = abs_path($To)."/".$Name.".tar.gz";
7705 unlink($Pkg);
7706 chdir($From);
7707 system($TarCmd, "-czf", $Pkg, $Name);
7708 if($?)
7709 { # cannot allocate memory (or other problems with "tar")
7710 unlink($Path);
7711 exitStatus("Error", "can't pack the ABI dump: ".$!);
7712 }
7713 chdir($ORIG_DIR);
7714 unlink($Path);
7715 return $To."/".$Name.".tar.gz";
7716 }
7717}
7718
7719sub is_header_file($)
7720{
7721 if($_[0]=~/\.($HEADER_EXT)\Z/i) {
7722 return $_[0];
7723 }
7724 return 0;
7725}
7726
7727sub is_not_header($)
7728{
7729 if($_[0]=~/\.\w+\Z/
7730 and $_[0]!~/\.($HEADER_EXT)\Z/i) {
7731 return 1;
7732 }
7733 return 0;
7734}
7735
7736sub is_header($$$)
7737{
7738 my ($Header, $UserDefined, $LibVersion) = @_;
7739 return 0 if(-d $Header);
7740 if(-f $Header) {
7741 $Header = get_abs_path($Header);
7742 }
7743 else
7744 {
7745 if(is_abs($Header))
7746 { # incorrect absolute path
7747 return 0;
7748 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04007749 if(my $HPath = identifyHeader($Header, $LibVersion)) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007750 $Header = $HPath;
7751 }
7752 else
7753 { # can't find header
7754 return 0;
7755 }
7756 }
7757 if($Header=~/\.\w+\Z/)
7758 { # have an extension
7759 return is_header_file($Header);
7760 }
7761 else
7762 {
7763 if($UserDefined==2)
7764 { # specified on the command line
7765 if(cmd_file($Header)!~/HTML|XML/i) {
7766 return $Header;
7767 }
7768 }
7769 elsif($UserDefined)
7770 { # specified in the XML-descriptor
7771 # header file without an extension
7772 return $Header;
7773 }
7774 else
7775 {
Andrey Ponomarenko85043792012-05-14 16:48:07 +04007776 if($Header=~/\/include\//
7777 or cmd_file($Header)=~/C[\+]*\s+program/i)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007778 { # !~/HTML|XML|shared|dynamic/i
7779 return $Header;
7780 }
7781 }
7782 }
7783 return 0;
7784}
7785
Andrey Ponomarenko16934472012-03-29 15:37:04 +04007786sub addTargetHeaders($)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007787{
7788 my $LibVersion = $_[0];
7789 foreach my $RegHeader (keys(%{$Registered_Headers{$LibVersion}}))
7790 {
7791 my $RegDir = get_dirname($RegHeader);
7792 $TargetHeaders{$LibVersion}{get_filename($RegHeader)}=1;
7793 foreach my $RecInc (keys(%{$RecursiveIncludes{$LibVersion}{$RegHeader}}))
7794 {
7795 my $Dir = get_dirname($RecInc);
Andrey Ponomarenko85043792012-05-14 16:48:07 +04007796 if($Dir=~/\A\Q$RegDir\E([\/\\]|\Z)/
7797 or $RecursiveIncludes{$LibVersion}{$RegHeader}{$RecInc}!=1)
7798 { # in the same directory or included by #include "..."
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007799 $TargetHeaders{$LibVersion}{get_filename($RecInc)}=1;
7800 }
7801 }
7802 }
7803}
7804
7805sub readHeaders($)
7806{
7807 $Version = $_[0];
7808 printMsg("INFO", "checking header(s) ".$Descriptor{$Version}{"Version"}." ...");
7809 my $DumpPath = getDump();
7810 if(not $DumpPath) {
7811 exitStatus("Cannot_Compile", "can't compile header(s)");
7812 }
7813 if($Debug)
7814 { # debug mode
7815 mkpath($DEBUG_PATH{$Version});
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04007816 copy($DumpPath, $DEBUG_PATH{$Version}."/translation-unit-dump.txt");
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007817 }
7818 getInfo($DumpPath);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007819}
7820
7821sub prepareTypes($)
7822{
7823 my $LibVersion = $_[0];
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04007824 if(not checkDump($LibVersion, "2.0"))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007825 { # support for old ABI dumps
7826 # type names have been corrected in ACC 1.22 (dump 2.0 format)
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04007827 foreach my $TypeId (keys(%{$TypeInfo{$LibVersion}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007828 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04007829 my $TName = $TypeInfo{$LibVersion}{$TypeId}{"Name"};
7830 if($TName=~/\A(\w+)::(\w+)/) {
7831 my ($P1, $P2) = ($1, $2);
7832 if($P1 eq $P2) {
7833 $TName=~s/\A$P1:\:$P1(\W)/$P1$1/;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007834 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04007835 else {
7836 $TName=~s/\A(\w+:\:)$P2:\:$P2(\W)/$1$P2$2/;
7837 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007838 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04007839 $TypeInfo{$LibVersion}{$TypeId}{"Name"} = $TName;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007840 }
7841 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04007842 if(not checkDump($LibVersion, "2.5"))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007843 { # support for old ABI dumps
7844 # V < 2.5: array size == "number of elements"
7845 # V >= 2.5: array size in bytes
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04007846 foreach my $TypeId (sort {int($a)<=>int($b)} keys(%{$TypeInfo{$LibVersion}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007847 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04007848 my %Type = get_PureType($TypeId, $LibVersion);
7849 if($Type{"Type"} eq "Array")
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007850 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04007851 if($Type{"Size"})
7852 { # array[N]
7853 my %Base = get_OneStep_BaseType($Type{"Tid"}, $LibVersion);
7854 $TypeInfo{$LibVersion}{$TypeId}{"Size"} = $Type{"Size"}*$Base{"Size"};
7855 }
7856 else
7857 { # array[] is a pointer
7858 $TypeInfo{$LibVersion}{$TypeId}{"Size"} = $WORD_SIZE{$LibVersion};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007859 }
7860 }
7861 }
7862 }
7863 my $V2 = ($LibVersion==1)?2:1;
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04007864 if(not checkDump($LibVersion, "2.7"))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007865 { # support for old ABI dumps
7866 # size of "method ptr" corrected in 2.7
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04007867 foreach my $TypeId (sort {int($a)<=>int($b)} keys(%{$TypeInfo{$LibVersion}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007868 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04007869 my %PureType = get_PureType($TypeId, $LibVersion);
7870 if($PureType{"Type"} eq "MethodPtr")
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007871 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04007872 my %Type = get_Type($TypeId, $LibVersion);
7873 my $TypeId_2 = getTypeIdByName($PureType{"Name"}, $V2);
7874 my %Type2 = get_Type($TypeId_2, $V2);
7875 if($Type{"Size"} ne $Type2{"Size"}) {
7876 $TypeInfo{$LibVersion}{$TypeId}{"Size"} = $Type2{"Size"};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007877 }
7878 }
7879 }
7880 }
7881}
7882
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04007883sub prepareSymbols($)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007884{
7885 my $LibVersion = $_[0];
Andrey Ponomarenko16934472012-03-29 15:37:04 +04007886
7887 if(not keys(%{$SymbolInfo{$LibVersion}}))
7888 { # check if input is valid
7889 if(not $ExtendedCheck and not $CheckObjectsOnly)
7890 {
7891 if($CheckHeadersOnly) {
7892 exitStatus("Empty_Set", "the set of public symbols is empty (".$Descriptor{$LibVersion}{"Version"}.")");
7893 }
7894 else {
7895 exitStatus("Empty_Intersection", "the sets of public symbols in headers and libraries have empty intersection (".$Descriptor{$LibVersion}{"Version"}.")");
7896 }
7897 }
7898 }
7899
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007900 my $Remangle = 0;
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04007901 if(not checkDump(1, "2.10")
7902 or not checkDump(2, "2.10"))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007903 { # different formats
7904 $Remangle = 1;
7905 }
7906 if($CheckHeadersOnly)
7907 { # different languages
7908 if($UserLang)
7909 { # --lang=LANG for both versions
7910 if(($UsedDump{1}{"V"} and $UserLang ne $UsedDump{1}{"L"})
7911 or ($UsedDump{2}{"V"} and $UserLang ne $UsedDump{2}{"L"}))
7912 {
7913 if($UserLang eq "C++")
7914 { # remangle symbols
7915 $Remangle = 1;
7916 }
7917 elsif($UserLang eq "C")
7918 { # remove mangling
7919 $Remangle = -1;
7920 }
7921 }
7922 }
7923 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04007924
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04007925 foreach my $InfoId (sort {int($b)<=>int($a)} keys(%{$SymbolInfo{$LibVersion}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007926 { # reverse order: D0, D1, D2, D0 (artificial, GCC < 4.5), C1, C2
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04007927 if(not checkDump($LibVersion, "2.13"))
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04007928 { # support for old ABI dumps
7929 if(defined $SymbolInfo{$LibVersion}{$InfoId}{"Param"})
7930 {
7931 foreach my $P (keys(%{$SymbolInfo{$LibVersion}{$InfoId}{"Param"}}))
7932 {
7933 my $TypeId = $SymbolInfo{$LibVersion}{$InfoId}{"Param"}{$P}{"type"};
7934 my $DVal = $SymbolInfo{$LibVersion}{$InfoId}{"Param"}{$P}{"default"};
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04007935 my $TName = $TypeInfo{$LibVersion}{$TypeId}{"Name"};
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04007936 if(defined $DVal and $DVal ne "")
7937 {
7938 if($TName eq "char") {
7939 $SymbolInfo{$LibVersion}{$InfoId}{"Param"}{$P}{"default"} = chr($DVal);
7940 }
7941 elsif($TName eq "bool") {
7942 $SymbolInfo{$LibVersion}{$InfoId}{"Param"}{$P}{"default"} = $DVal?"true":"false";
7943 }
7944 }
7945 }
7946 }
7947 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04007948 if($SymbolInfo{$LibVersion}{$InfoId}{"Destructor"})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007949 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04007950 if(defined $SymbolInfo{$LibVersion}{$InfoId}{"Param"}
7951 and keys(%{$SymbolInfo{$LibVersion}{$InfoId}{"Param"}})
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04007952 and $SymbolInfo{$LibVersion}{$InfoId}{"Param"}{0}{"name"})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007953 { # support for old GCC < 4.5: skip artificial ~dtor(int __in_chrg)
7954 # + support for old ABI dumps
7955 next;
7956 }
7957 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04007958 my $MnglName = $SymbolInfo{$LibVersion}{$InfoId}{"MnglName"};
Andrey Ponomarenko85043792012-05-14 16:48:07 +04007959 my $ShortName = $SymbolInfo{$LibVersion}{$InfoId}{"ShortName"};
Andrey Ponomarenko16934472012-03-29 15:37:04 +04007960 my $ClassID = $SymbolInfo{$LibVersion}{$InfoId}{"Class"};
Andrey Ponomarenko85043792012-05-14 16:48:07 +04007961 my $Return = $SymbolInfo{$LibVersion}{$InfoId}{"Return"};
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04007962
7963 if(not $MnglName)
7964 { # ABI dumps have no mangled names for C-functions
Andrey Ponomarenko85043792012-05-14 16:48:07 +04007965 $MnglName = $ShortName;
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04007966 $SymbolInfo{$LibVersion}{$InfoId}{"MnglName"} = $MnglName;
7967 }
7968
Andrey Ponomarenko16934472012-03-29 15:37:04 +04007969 my $SRemangle = 0;
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04007970 if(not checkDump(1, "2.12")
7971 or not checkDump(2, "2.12"))
Andrey Ponomarenko16934472012-03-29 15:37:04 +04007972 { # support for old ABI dumps
Andrey Ponomarenko85043792012-05-14 16:48:07 +04007973 if($ShortName eq "operator>>")
7974 {
7975 if(not $SymbolInfo{$LibVersion}{$InfoId}{"Class"})
7976 { # corrected mangling of operator>>
7977 $SRemangle = 1;
7978 }
Andrey Ponomarenko16934472012-03-29 15:37:04 +04007979 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +04007980 if($SymbolInfo{$LibVersion}{$InfoId}{"Data"})
7981 {
7982 if(not $SymbolInfo{$LibVersion}{$InfoId}{"Class"}
7983 and isConstType($Return, $LibVersion) and $MnglName!~/L\d+$ShortName/)
7984 { # corrected mangling of const global data
7985 # some global data is not mangled in the TU dump: qt_sine_table (Qt 4.8)
7986 # and incorrectly mangled by old ACC versions
7987 $SRemangle = 1;
7988 }
Andrey Ponomarenko16934472012-03-29 15:37:04 +04007989 }
7990 }
Andrey Ponomarenko5c09ef32012-06-14 18:17:33 +04007991 if(not $CheckHeadersOnly)
7992 { # support for old ABI dumps
7993 if(not checkDump(1, "2.17")
7994 or not checkDump(2, "2.17"))
7995 {
7996 if($SymbolInfo{$LibVersion}{$InfoId}{"Data"})
7997 {
7998 if(not $SymbolInfo{$LibVersion}{$InfoId}{"Class"})
7999 {
8000 if(link_symbol($ShortName, $LibVersion, "-Deps"))
8001 {
8002 $MnglName = $ShortName;
8003 $SymbolInfo{$LibVersion}{$InfoId}{"MnglName"} = $MnglName;
8004 }
8005 }
8006 }
8007 }
8008 }
Andrey Ponomarenko16934472012-03-29 15:37:04 +04008009 if($Remangle==1 or $SRemangle==1)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008010 { # support for old ABI dumps: some symbols are not mangled in old dumps
8011 # mangle both sets of symbols (old and new)
8012 # NOTE: remangling all symbols by the same mangler
8013 if($MnglName=~/\A_ZN(V|)K/)
8014 { # mangling may be incorrect on old ABI dumps
8015 # because of absent "Const" attribute
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04008016 $SymbolInfo{$LibVersion}{$InfoId}{"Const"} = 1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008017 }
8018 if($MnglName=~/\A_ZN(K|)V/)
8019 { # mangling may be incorrect on old ABI dumps
8020 # because of absent "Volatile" attribute
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04008021 $SymbolInfo{$LibVersion}{$InfoId}{"Volatile"} = 1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008022 }
Andrey Ponomarenko16934472012-03-29 15:37:04 +04008023 if(($ClassID and $MnglName!~/\A(_Z|\?)/)
8024 or (not $ClassID and $CheckHeadersOnly)
8025 or (not $ClassID and not link_symbol($MnglName, $LibVersion, "-Deps")))
8026 { # support for old ABI dumps, GCC >= 4.0
8027 # remangling all manually mangled symbols
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04008028 if($MnglName = mangle_symbol($InfoId, $LibVersion, "GCC"))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008029 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04008030 $SymbolInfo{$LibVersion}{$InfoId}{"MnglName"} = $MnglName;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008031 $MangledNames{$LibVersion}{$MnglName} = 1;
8032 }
8033 }
8034 }
8035 elsif($Remangle==-1)
8036 { # remove mangling
8037 $MnglName = "";
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04008038 $SymbolInfo{$LibVersion}{$InfoId}{"MnglName"} = "";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008039 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008040 if(not $MnglName) {
8041 next;
8042 }
8043 if(not $CompleteSignature{$LibVersion}{$MnglName}{"MnglName"})
8044 { # NOTE: global data may enter here twice
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04008045 %{$CompleteSignature{$LibVersion}{$MnglName}} = %{$SymbolInfo{$LibVersion}{$InfoId}};
8046
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008047 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04008048 if(not checkDump($LibVersion, "2.6"))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008049 { # support for old dumps
8050 # add "Volatile" attribute
8051 if($MnglName=~/_Z(K|)V/) {
8052 $CompleteSignature{$LibVersion}{$MnglName}{"Volatile"}=1;
8053 }
8054 }
8055 # symbol and its symlink have same signatures
8056 if($SymVer{$LibVersion}{$MnglName}) {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04008057 %{$CompleteSignature{$LibVersion}{$SymVer{$LibVersion}{$MnglName}}} = %{$SymbolInfo{$LibVersion}{$InfoId}};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008058 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +04008059
8060 # clean memory
Andrey Ponomarenko16934472012-03-29 15:37:04 +04008061 delete($SymbolInfo{$LibVersion}{$InfoId});
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008062 }
8063 if($COMMON_LANGUAGE{$LibVersion} eq "C++" or $OSgroup eq "windows") {
8064 translateSymbols(keys(%{$CompleteSignature{$LibVersion}}), $LibVersion);
8065 }
8066 if($ExtendedCheck)
8067 { # --ext option
8068 addExtension($LibVersion);
8069 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +04008070
8071 # clean memory
8072 delete($SymbolInfo{$LibVersion});
8073
8074 foreach my $Symbol (keys(%{$CompleteSignature{$LibVersion}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008075 { # detect allocable classes with public exported constructors
8076 # or classes with auto-generated or inline-only constructors
Andrey Ponomarenko85043792012-05-14 16:48:07 +04008077 if(my $ClassId = $CompleteSignature{$LibVersion}{$Symbol}{"Class"})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008078 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04008079 my $ClassName = $TypeInfo{$LibVersion}{$ClassId}{"Name"};
Andrey Ponomarenko85043792012-05-14 16:48:07 +04008080 if($CompleteSignature{$LibVersion}{$Symbol}{"Constructor"}
8081 and not $CompleteSignature{$LibVersion}{$Symbol}{"InLine"})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008082 { # Class() { ... } will not be exported
Andrey Ponomarenko85043792012-05-14 16:48:07 +04008083 if(not $CompleteSignature{$LibVersion}{$Symbol}{"Private"})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008084 {
Andrey Ponomarenko85043792012-05-14 16:48:07 +04008085 if($CheckHeadersOnly or link_symbol($Symbol, $LibVersion, "-Deps")) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008086 $AllocableClass{$LibVersion}{$ClassName} = 1;
8087 }
8088 }
8089 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +04008090 if(not $CompleteSignature{$LibVersion}{$Symbol}{"Private"})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008091 { # all imported class methods
Andrey Ponomarenko85043792012-05-14 16:48:07 +04008092 if(symbolFilter($Symbol, $LibVersion, "Affected", "Binary"))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008093 {
Andrey Ponomarenko85043792012-05-14 16:48:07 +04008094 if($CheckHeadersOnly)
8095 {
8096 if(not $CompleteSignature{$LibVersion}{$Symbol}{"InLine"}
8097 or $CompleteSignature{$LibVersion}{$Symbol}{"Virt"})
8098 { # all symbols except non-virtual inline
8099 $ClassMethods{"Binary"}{$LibVersion}{$ClassName}{$Symbol} = 1;
8100 }
8101 }
8102 else {
8103 $ClassMethods{"Binary"}{$LibVersion}{$ClassName}{$Symbol} = 1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008104 }
8105 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04008106 if(symbolFilter($Symbol, $LibVersion, "Affected", "Source")) {
Andrey Ponomarenko85043792012-05-14 16:48:07 +04008107 $ClassMethods{"Source"}{$LibVersion}{$ClassName}{$Symbol} = 1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008108 }
8109 }
Andrey Ponomarenko16934472012-03-29 15:37:04 +04008110 $ClassNames{$LibVersion}{$ClassName} = 1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008111 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +04008112 if(my $RetId = $CompleteSignature{$LibVersion}{$Symbol}{"Return"})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008113 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04008114 my %Base = get_BaseType($RetId, $LibVersion);
Andrey Ponomarenko85043792012-05-14 16:48:07 +04008115 if(defined $Base{"Type"}
8116 and $Base{"Type"}=~/Struct|Class/)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008117 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04008118 my $Name = $TypeInfo{$LibVersion}{$Base{"Tid"}}{"Name"};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008119 if($Name=~/<([^<>\s]+)>/)
8120 {
8121 if(my $Tid = getTypeIdByName($1, $LibVersion)) {
8122 $ReturnedClass{$LibVersion}{$Tid} = 1;
8123 }
8124 }
8125 else {
8126 $ReturnedClass{$LibVersion}{$Base{"Tid"}} = 1;
8127 }
8128 }
8129 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +04008130 foreach my $Num (keys(%{$CompleteSignature{$LibVersion}{$Symbol}{"Param"}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008131 {
Andrey Ponomarenko85043792012-05-14 16:48:07 +04008132 my $PId = $CompleteSignature{$LibVersion}{$Symbol}{"Param"}{$Num}{"type"};
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04008133 if(get_PLevel($PId, $LibVersion)>=1)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008134 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04008135 if(my %Base = get_BaseType($PId, $LibVersion))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008136 {
Andrey Ponomarenko16934472012-03-29 15:37:04 +04008137 if($Base{"Type"}=~/Struct|Class/)
8138 {
Andrey Ponomarenko85043792012-05-14 16:48:07 +04008139 $ParamClass{$LibVersion}{$Base{"Tid"}}{$Symbol} = 1;
Andrey Ponomarenko16934472012-03-29 15:37:04 +04008140 foreach my $SubId (get_sub_classes($Base{"Tid"}, $LibVersion, 1))
8141 { # mark all derived classes
Andrey Ponomarenko85043792012-05-14 16:48:07 +04008142 $ParamClass{$LibVersion}{$SubId}{$Symbol} = 1;
Andrey Ponomarenko16934472012-03-29 15:37:04 +04008143 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008144 }
8145 }
8146 }
8147 }
8148 }
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04008149 foreach my $MnglName (keys(%VTableClass))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008150 { # reconstruct header name for v-tables
8151 if($MnglName=~/\A_ZTV/)
8152 {
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04008153 if(my $ClassName = $VTableClass{$MnglName})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008154 {
8155 if(my $ClassId = $TName_Tid{$LibVersion}{$ClassName}) {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04008156 $CompleteSignature{$LibVersion}{$MnglName}{"Header"} = $TypeInfo{$LibVersion}{$ClassId}{"Header"};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008157 }
8158 }
8159 }
8160 }
Andrey Ponomarenko16934472012-03-29 15:37:04 +04008161
8162 # types
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04008163 foreach my $TypeId (keys(%{$TypeInfo{$LibVersion}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008164 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04008165 if(my $TName = $TypeInfo{$LibVersion}{$TypeId}{"Name"})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008166 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04008167 if(defined $TypeInfo{$LibVersion}{$TypeId}{"VTable"}) {
8168 $ClassNames{$LibVersion}{$TName} = 1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008169 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04008170 if(defined $TypeInfo{$LibVersion}{$TypeId}{"Base"})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008171 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04008172 $ClassNames{$LibVersion}{$TName} = 1;
8173 foreach my $Bid (keys(%{$TypeInfo{$LibVersion}{$TypeId}{"Base"}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008174 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04008175 if(my $BName = $TypeInfo{$LibVersion}{$Bid}{"Name"}) {
8176 $ClassNames{$LibVersion}{$BName} = 1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008177 }
8178 }
8179 }
8180 }
8181 }
8182}
8183
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04008184sub register_TypeUsage($$)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008185{
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04008186 my ($TypeId, $LibVersion) = @_;
8187 if(not $TypeId) {
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04008188 return 0;
8189 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04008190 if($UsedType{$LibVersion}{$TypeId})
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04008191 { # already registered
8192 return 1;
8193 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04008194 my %TInfo = get_Type($TypeId, $LibVersion);
Andrey Ponomarenko85043792012-05-14 16:48:07 +04008195 if($TInfo{"Type"})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008196 {
Andrey Ponomarenko85043792012-05-14 16:48:07 +04008197 if($TInfo{"Type"}=~/\A(Struct|Union|Class|FuncPtr|MethodPtr|FieldPtr|Enum)\Z/)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008198 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04008199 $UsedType{$LibVersion}{$TypeId} = 1;
Andrey Ponomarenko85043792012-05-14 16:48:07 +04008200 if($TInfo{"Type"}=~/\A(Struct|Class)\Z/)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008201 {
Andrey Ponomarenko85043792012-05-14 16:48:07 +04008202 foreach my $BaseId (keys(%{$TInfo{"Base"}}))
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04008203 { # register base classes
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04008204 register_TypeUsage($BaseId, $LibVersion);
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04008205 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +04008206 foreach my $TPos (keys(%{$TInfo{"TParam"}}))
8207 {
8208 my $TPName = $TInfo{"TParam"}{$TPos}{"name"};
8209 if(my $TTid = $TName_Tid{$LibVersion}{$TPName}) {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04008210 register_TypeUsage($TTid, $LibVersion);
Andrey Ponomarenko85043792012-05-14 16:48:07 +04008211 }
8212 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008213 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +04008214 foreach my $Memb_Pos (keys(%{$TInfo{"Memb"}}))
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04008215 {
Andrey Ponomarenko85043792012-05-14 16:48:07 +04008216 if(my $MTid = $TInfo{"Memb"}{$Memb_Pos}{"type"}) {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04008217 register_TypeUsage($MTid, $LibVersion);
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04008218 }
8219 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +04008220 if($TInfo{"Type"} eq "FuncPtr"
8221 or $TInfo{"Type"} eq "MethodPtr")
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04008222 {
Andrey Ponomarenko85043792012-05-14 16:48:07 +04008223 if(my $RTid = $TInfo{"Return"}) {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04008224 register_TypeUsage($RTid, $LibVersion);
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04008225 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +04008226 foreach my $Memb_Pos (keys(%{$TInfo{"Param"}}))
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04008227 {
Andrey Ponomarenko85043792012-05-14 16:48:07 +04008228 if(my $MTid = $TInfo{"Param"}{$Memb_Pos}{"type"}) {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04008229 register_TypeUsage($MTid, $LibVersion);
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04008230 }
8231 }
8232 }
8233 return 1;
8234 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +04008235 elsif($TInfo{"Type"}=~/\A(Const|ConstVolatile|Volatile|Pointer|Ref|Restrict|Array|Typedef)\Z/)
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04008236 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04008237 $UsedType{$LibVersion}{$TypeId} = 1;
8238 register_TypeUsage($TInfo{"BaseType"}{"Tid"}, $LibVersion);
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04008239 return 1;
8240 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04008241 elsif($TInfo{"Type"} eq "Intrinsic")
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04008242 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04008243 $UsedType{$LibVersion}{$TypeId} = 1;
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04008244 return 1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008245 }
8246 }
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04008247 return 0;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008248}
8249
Andrey Ponomarenko85043792012-05-14 16:48:07 +04008250sub selectSymbol($$$$)
Andrey Ponomarenko35c44fd2012-06-18 17:50:25 +04008251{ # select symbol to check or to dump
Andrey Ponomarenko85043792012-05-14 16:48:07 +04008252 my ($Symbol, $SInfo, $Level, $LibVersion) = @_;
8253
Andrey Ponomarenko35c44fd2012-06-18 17:50:25 +04008254 if($Level eq "Dump")
8255 {
8256 if($SInfo->{"Virt"} or $SInfo->{"PureVirt"})
8257 { # TODO: check if this symbol is from
8258 # base classes of other target symbols
8259 return 1;
8260 }
8261 }
8262
Andrey Ponomarenko85043792012-05-14 16:48:07 +04008263 if(not $STDCXX_TESTING and $Symbol=~/\A(_ZS|_ZNS|_ZNKS)/)
8264 { # stdc++ interfaces
8265 return 0;
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04008266 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +04008267
8268 my $Target = 0;
8269 if(my $Header = $SInfo->{"Header"}) {
8270 $Target = (is_target_header($Header, 1) or is_target_header($Header, 2));
8271 }
8272 if($CheckHeadersOnly)
8273 {
8274 if($Target)
8275 {
8276 if($Level eq "Dump")
8277 { # dumped
8278 if($BinaryOnly)
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04008279 {
Andrey Ponomarenko85043792012-05-14 16:48:07 +04008280 if(not $SInfo->{"InLine"} or $SInfo->{"Data"}) {
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04008281 return 1;
8282 }
8283 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +04008284 else {
8285 return 1;
8286 }
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04008287 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +04008288 elsif($Level eq "Source")
8289 { # checked
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04008290 return 1;
8291 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +04008292 elsif($Level eq "Binary")
8293 { # checked
8294 if(not $SInfo->{"InLine"} or $SInfo->{"Data"}
8295 or $SInfo->{"Virt"} or $SInfo->{"PureVirt"}) {
8296 return 1;
8297 }
8298 }
8299 }
8300 }
8301 else
8302 { # library is available
8303 if(link_symbol($Symbol, $LibVersion, "-Deps"))
8304 { # exported symbols
8305 return 1;
8306 }
8307 if($Level eq "Dump")
8308 { # dumped
Andrey Ponomarenko35c44fd2012-06-18 17:50:25 +04008309 if($BinaryOnly)
8310 {
8311 if($SInfo->{"Data"})
8312 {
8313 if($Target) {
8314 return 1;
8315 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +04008316 }
8317 }
Andrey Ponomarenko35c44fd2012-06-18 17:50:25 +04008318 else
8319 { # SrcBin
Andrey Ponomarenko85043792012-05-14 16:48:07 +04008320 if($Target) {
8321 return 1;
8322 }
8323 }
8324 }
8325 elsif($Level eq "Source")
8326 { # checked
Andrey Ponomarenko35c44fd2012-06-18 17:50:25 +04008327 if($SInfo->{"PureVirt"} or $SInfo->{"Data"} or $SInfo->{"InLine"})
8328 { # skip LOCAL symbols
8329 if($Target) {
8330 return 1;
8331 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +04008332 }
8333 }
8334 elsif($Level eq "Binary")
8335 { # checked
8336 if($SInfo->{"PureVirt"} or $SInfo->{"Data"})
8337 {
8338 if($Target) {
8339 return 1;
8340 }
8341 }
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04008342 }
8343 }
8344 return 0;
8345}
8346
Andrey Ponomarenko85043792012-05-14 16:48:07 +04008347sub cleanDump($)
8348{ # clean data
Andrey Ponomarenko16934472012-03-29 15:37:04 +04008349 my $LibVersion = $_[0];
8350 foreach my $InfoId (keys(%{$SymbolInfo{$LibVersion}}))
8351 {
8352 my $MnglName = $SymbolInfo{$LibVersion}{$InfoId}{"MnglName"};
8353 if(not $MnglName) {
8354 delete($SymbolInfo{$LibVersion}{$InfoId});
8355 next;
8356 }
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04008357 my $ShortName = $SymbolInfo{$LibVersion}{$InfoId}{"ShortName"};
Andrey Ponomarenko85043792012-05-14 16:48:07 +04008358 if(not $ShortName) {
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04008359 delete($SymbolInfo{$LibVersion}{$InfoId});
8360 next;
Andrey Ponomarenko16934472012-03-29 15:37:04 +04008361 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +04008362 if($MnglName eq $ShortName)
8363 { # remove duplicate data
8364 delete($SymbolInfo{$LibVersion}{$InfoId}{"MnglName"});
Andrey Ponomarenko16934472012-03-29 15:37:04 +04008365 }
8366 if(not keys(%{$SymbolInfo{$LibVersion}{$InfoId}{"Param"}})) {
8367 delete($SymbolInfo{$LibVersion}{$InfoId}{"Param"});
8368 }
8369 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04008370 foreach my $Tid (keys(%{$TypeInfo{$LibVersion}}))
Andrey Ponomarenko85043792012-05-14 16:48:07 +04008371 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04008372 foreach my $Attr ("Header", "Line", "Size", "NameSpace")
Andrey Ponomarenko16934472012-03-29 15:37:04 +04008373 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04008374 if(not $TypeInfo{$LibVersion}{$Tid}{$Attr}) {
8375 delete($TypeInfo{$LibVersion}{$Tid}{$Attr});
8376 }
8377 }
8378 }
8379}
8380
8381sub selectType($$)
8382{
8383 my ($Tid, $LibVersion) = @_;
8384 if(my $THeader = $TypeInfo{$LibVersion}{$Tid}{"Header"})
8385 {
8386 if(not isBuiltIn($THeader))
8387 {
8388 if($TypeInfo{$LibVersion}{$Tid}{"Type"}=~/Class|Struct|Union|Enum|Typedef/)
Andrey Ponomarenko16934472012-03-29 15:37:04 +04008389 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04008390 if(not isAnon($TypeInfo{$LibVersion}{$Tid}{"Name"}))
8391 {
8392 if(is_target_header($THeader, $LibVersion))
8393 { # from target headers
8394 if(not selfTypedef($Tid, $LibVersion)) {
8395 return 1;
8396 }
8397 }
Andrey Ponomarenko16934472012-03-29 15:37:04 +04008398 }
8399 }
8400 }
8401 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04008402 return 0;
Andrey Ponomarenko16934472012-03-29 15:37:04 +04008403}
8404
Andrey Ponomarenko85043792012-05-14 16:48:07 +04008405sub removeUnused($$)
8406{ # remove unused data types from the ABI dump
8407 my ($LibVersion, $Kind) = @_;
8408 foreach my $InfoId (keys(%{$SymbolInfo{$LibVersion}}))
8409 {
8410 my %FuncInfo = %{$SymbolInfo{$LibVersion}{$InfoId}};
8411 if(my $RTid = $FuncInfo{"Return"}) {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04008412 register_TypeUsage($RTid, $LibVersion);
Andrey Ponomarenko85043792012-05-14 16:48:07 +04008413 }
8414 if(my $FCid = $FuncInfo{"Class"})
8415 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04008416 register_TypeUsage($FCid, $LibVersion);
8417 if(my $ThisId = getTypeIdByName($TypeInfo{$LibVersion}{$FCid}{"Name"}."*const", $LibVersion))
Andrey Ponomarenko85043792012-05-14 16:48:07 +04008418 { # register "this" pointer
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04008419 $UsedType{$LibVersion}{$ThisId} = 1;
8420 if(my %ThisType = get_Type($ThisId, $LibVersion)) {
8421 register_TypeUsage($ThisType{"BaseType"}{"Tid"}, $LibVersion);
Andrey Ponomarenko85043792012-05-14 16:48:07 +04008422 }
8423 }
8424 }
8425 foreach my $PPos (keys(%{$FuncInfo{"Param"}}))
8426 {
8427 if(my $PTid = $FuncInfo{"Param"}{$PPos}{"type"}) {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04008428 register_TypeUsage($PTid, $LibVersion);
Andrey Ponomarenko85043792012-05-14 16:48:07 +04008429 }
8430 }
8431 foreach my $TPos (keys(%{$FuncInfo{"TParam"}}))
8432 {
8433 my $TPName = $FuncInfo{"TParam"}{$TPos}{"name"};
8434 if(my $TTid = $TName_Tid{$LibVersion}{$TPName}) {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04008435 register_TypeUsage($TTid, $LibVersion);
Andrey Ponomarenko85043792012-05-14 16:48:07 +04008436 }
8437 }
8438 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04008439 foreach my $Tid (keys(%{$TypeInfo{$LibVersion}}))
8440 {
8441 if($UsedType{$LibVersion}{$Tid})
8442 { # All & Derived
8443 next;
8444 }
8445
8446 if($Kind eq "Derived")
Andrey Ponomarenko85043792012-05-14 16:48:07 +04008447 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04008448 if(selectType($Tid, $LibVersion)) {
8449 register_TypeUsage($Tid, $LibVersion);
Andrey Ponomarenko85043792012-05-14 16:48:07 +04008450 }
8451 }
8452 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04008453 foreach my $Tid (keys(%{$TypeInfo{$LibVersion}}))
8454 { # remove unused types
8455 if($UsedType{$LibVersion}{$Tid})
8456 { # All & Derived
8457 next;
8458 }
8459 # remove type
8460 delete($TypeInfo{$LibVersion}{$Tid});
8461 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +04008462
8463 # clean memory
8464 %UsedType = ();
8465}
8466
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04008467sub selfTypedef($$)
Andrey Ponomarenko85043792012-05-14 16:48:07 +04008468{
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04008469 my ($TypeId, $LibVersion) = @_;
8470 my %Type = get_Type($TypeId, $LibVersion);
Andrey Ponomarenko85043792012-05-14 16:48:07 +04008471 if($Type{"Type"} eq "Typedef")
8472 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04008473 my %Base = get_OneStep_BaseType($TypeId, $LibVersion);
Andrey Ponomarenko85043792012-05-14 16:48:07 +04008474 if($Base{"Type"}=~/Class|Struct/)
8475 {
8476 if($Type{"Name"} eq $Base{"Name"}) {
8477 return 1;
8478 }
8479 elsif($Type{"Name"}=~/::(\w+)\Z/)
8480 {
8481 if($Type{"Name"} eq $Base{"Name"}."::".$1)
8482 { # QPointer<QWidget>::QPointer
8483 return 1;
8484 }
8485 }
8486 }
8487 }
8488 return 0;
8489}
8490
Andrey Ponomarenko16934472012-03-29 15:37:04 +04008491sub addExtension($)
8492{
8493 my $LibVersion = $_[0];
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04008494 foreach my $Tid (keys(%{$TypeInfo{$LibVersion}}))
Andrey Ponomarenko16934472012-03-29 15:37:04 +04008495 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04008496 if(selectType($Tid, $LibVersion))
Andrey Ponomarenko16934472012-03-29 15:37:04 +04008497 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04008498 my $Symbol = "external_func_".$TypeInfo{$LibVersion}{$Tid}{"Name"};
8499
8500 %{$CompleteSignature{$LibVersion}{$Symbol}} = (
8501 "Header" => "extended.h",
8502 "ShortName" => $Symbol,
8503 "MnglName" => $Symbol,
8504 "Param" => { 0 => { "type"=>$Tid, "name"=>"p1" } }
8505 );
8506
8507 $ExtendedSymbols{$Symbol}=1;
8508 $CheckedSymbols{"Binary"}{$Symbol}=1;
8509 $CheckedSymbols{"Source"}{$Symbol}=1;
Andrey Ponomarenko16934472012-03-29 15:37:04 +04008510 }
8511 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04008512 $ExtendedSymbols{"external_func_0"}=1;
8513 $CheckedSymbols{"Binary"}{"external_func_0"}=1;
8514 $CheckedSymbols{"Source"}{"external_func_0"}=1;
Andrey Ponomarenko16934472012-03-29 15:37:04 +04008515}
8516
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008517sub findMethod($$$)
8518{
8519 my ($VirtFunc, $ClassId, $LibVersion) = @_;
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04008520 foreach my $BaseClass_Id (keys(%{$TypeInfo{$LibVersion}{$ClassId}{"Base"}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008521 {
8522 if(my $VirtMethodInClass = findMethod_Class($VirtFunc, $BaseClass_Id, $LibVersion)) {
8523 return $VirtMethodInClass;
8524 }
8525 elsif(my $VirtMethodInBaseClasses = findMethod($VirtFunc, $BaseClass_Id, $LibVersion)) {
8526 return $VirtMethodInBaseClasses;
8527 }
8528 }
8529 return "";
8530}
8531
8532sub findMethod_Class($$$)
8533{
8534 my ($VirtFunc, $ClassId, $LibVersion) = @_;
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04008535 my $ClassName = $TypeInfo{$LibVersion}{$ClassId}{"Name"};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008536 return "" if(not defined $VirtualTable{$LibVersion}{$ClassName});
8537 my $TargetSuffix = get_symbol_suffix($VirtFunc, 1);
8538 my $TargetShortName = $CompleteSignature{$LibVersion}{$VirtFunc}{"ShortName"};
8539 foreach my $Candidate (keys(%{$VirtualTable{$LibVersion}{$ClassName}}))
8540 { # search for interface with the same parameters suffix (overridden)
8541 if($TargetSuffix eq get_symbol_suffix($Candidate, 1))
8542 {
8543 if($CompleteSignature{$LibVersion}{$VirtFunc}{"Destructor"}) {
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04008544 if($CompleteSignature{$LibVersion}{$Candidate}{"Destructor"})
8545 {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008546 if(($VirtFunc=~/D0E/ and $Candidate=~/D0E/)
8547 or ($VirtFunc=~/D1E/ and $Candidate=~/D1E/)
8548 or ($VirtFunc=~/D2E/ and $Candidate=~/D2E/)) {
8549 return $Candidate;
8550 }
8551 }
8552 }
8553 else {
8554 if($TargetShortName eq $CompleteSignature{$LibVersion}{$Candidate}{"ShortName"}) {
8555 return $Candidate;
8556 }
8557 }
8558 }
8559 }
8560 return "";
8561}
8562
Andrey Ponomarenko16934472012-03-29 15:37:04 +04008563sub registerVTable($)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008564{
Andrey Ponomarenko16934472012-03-29 15:37:04 +04008565 my $LibVersion = $_[0];
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04008566 foreach my $Symbol (keys(%{$CompleteSignature{$LibVersion}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008567 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04008568 if($CompleteSignature{$LibVersion}{$Symbol}{"Virt"}
8569 or $CompleteSignature{$LibVersion}{$Symbol}{"PureVirt"})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008570 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04008571 my $ClassName = $TypeInfo{$LibVersion}{$CompleteSignature{$LibVersion}{$Symbol}{"Class"}}{"Name"};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008572 next if(not $STDCXX_TESTING and $ClassName=~/\A(std::|__cxxabi)/);
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04008573 if($CompleteSignature{$LibVersion}{$Symbol}{"Destructor"}
8574 and $Symbol=~/D2E/)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008575 { # pure virtual D2-destructors are marked as "virt" in the dump
8576 # virtual D2-destructors are NOT marked as "virt" in the dump
8577 # both destructors are not presented in the v-table
8578 next;
8579 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04008580 my ($MnglName, $VersionSpec, $SymbolVersion) = separate_symbol($Symbol);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008581 $VirtualTable{$LibVersion}{$ClassName}{$MnglName} = 1;
8582 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008583 }
8584}
8585
8586sub registerOverriding($)
8587{
8588 my $LibVersion = $_[0];
8589 my @Classes = keys(%{$VirtualTable{$LibVersion}});
Andrey Ponomarenko85043792012-05-14 16:48:07 +04008590 @Classes = sort {int($TName_Tid{$LibVersion}{$a})<=>int($TName_Tid{$LibVersion}{$b})} @Classes;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008591 foreach my $ClassName (@Classes)
8592 {
8593 foreach my $VirtFunc (keys(%{$VirtualTable{$LibVersion}{$ClassName}}))
8594 {
Andrey Ponomarenko16934472012-03-29 15:37:04 +04008595 if($CompleteSignature{$LibVersion}{$VirtFunc}{"PureVirt"})
8596 { # pure virtuals
8597 next;
8598 }
8599 my $ClassId = $TName_Tid{$LibVersion}{$ClassName};
8600 if(my $Overridden = findMethod($VirtFunc, $ClassId, $LibVersion))
Andrey Ponomarenko85043792012-05-14 16:48:07 +04008601 {
8602 if($CompleteSignature{$LibVersion}{$Overridden}{"Virt"}
8603 or $CompleteSignature{$LibVersion}{$Overridden}{"PureVirt"})
8604 { # both overridden virtual methods
8605 # and implemented pure virtual methods
8606 $CompleteSignature{$LibVersion}{$VirtFunc}{"Override"} = $Overridden;
8607 $OverriddenMethods{$LibVersion}{$Overridden}{$VirtFunc} = 1;
8608 delete($VirtualTable{$LibVersion}{$ClassName}{$VirtFunc}); # remove from v-table model
8609 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008610 }
8611 }
8612 if(not keys(%{$VirtualTable{$LibVersion}{$ClassName}})) {
8613 delete($VirtualTable{$LibVersion}{$ClassName});
8614 }
8615 }
8616}
8617
8618sub setVirtFuncPositions($)
8619{
8620 my $LibVersion = $_[0];
8621 foreach my $ClassName (keys(%{$VirtualTable{$LibVersion}}))
8622 {
8623 my ($Num, $RelPos, $AbsNum) = (1, 0, 1);
8624 foreach my $VirtFunc (sort {int($CompleteSignature{$LibVersion}{$a}{"Line"}) <=> int($CompleteSignature{$LibVersion}{$b}{"Line"})}
8625 sort keys(%{$VirtualTable{$LibVersion}{$ClassName}}))
8626 {
Andrey Ponomarenko16934472012-03-29 15:37:04 +04008627 $VirtualTable{$LibVersion}{$ClassName}{$VirtFunc}=$Num++;
8628
8629 # set relative positions
8630 if(defined $VirtualTable{1}{$ClassName} and defined $VirtualTable{1}{$ClassName}{$VirtFunc}
8631 and defined $VirtualTable{2}{$ClassName} and defined $VirtualTable{2}{$ClassName}{$VirtFunc})
8632 { # relative position excluding added and removed virtual functions
8633 if(not $CompleteSignature{1}{$VirtFunc}{"Override"}
8634 and not $CompleteSignature{2}{$VirtFunc}{"Override"}) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008635 $CompleteSignature{$LibVersion}{$VirtFunc}{"RelPos"} = $RelPos++;
8636 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008637 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008638 }
8639 }
Andrey Ponomarenko16934472012-03-29 15:37:04 +04008640 foreach my $ClassName (keys(%{$ClassNames{$LibVersion}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008641 {
8642 my $AbsNum = 1;
Andrey Ponomarenko16934472012-03-29 15:37:04 +04008643 foreach my $VirtFunc (getVTable_Model($TName_Tid{$LibVersion}{$ClassName}, $LibVersion)) {
8644 $VirtualTable_Model{$LibVersion}{$ClassName}{$VirtFunc}=$AbsNum++;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008645 }
8646 }
8647}
8648
8649sub get_sub_classes($$$)
8650{
8651 my ($ClassId, $LibVersion, $Recursive) = @_;
8652 return () if(not defined $Class_SubClasses{$LibVersion}{$ClassId});
8653 my @Subs = ();
8654 foreach my $SubId (keys(%{$Class_SubClasses{$LibVersion}{$ClassId}}))
8655 {
Andrey Ponomarenko16934472012-03-29 15:37:04 +04008656 if($Recursive)
8657 {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008658 foreach my $SubSubId (get_sub_classes($SubId, $LibVersion, $Recursive)) {
8659 push(@Subs, $SubSubId);
8660 }
8661 }
8662 push(@Subs, $SubId);
8663 }
8664 return @Subs;
8665}
8666
8667sub get_base_classes($$$)
8668{
8669 my ($ClassId, $LibVersion, $Recursive) = @_;
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04008670 my %ClassType = get_Type($ClassId, $LibVersion);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008671 return () if(not defined $ClassType{"Base"});
8672 my @Bases = ();
8673 foreach my $BaseId (sort {int($ClassType{"Base"}{$a}{"pos"})<=>int($ClassType{"Base"}{$b}{"pos"})}
8674 keys(%{$ClassType{"Base"}}))
8675 {
Andrey Ponomarenko16934472012-03-29 15:37:04 +04008676 if($Recursive)
8677 {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008678 foreach my $SubBaseId (get_base_classes($BaseId, $LibVersion, $Recursive)) {
8679 push(@Bases, $SubBaseId);
8680 }
8681 }
8682 push(@Bases, $BaseId);
8683 }
8684 return @Bases;
8685}
8686
Andrey Ponomarenko16934472012-03-29 15:37:04 +04008687sub getVTable_Model($$)
8688{ # return an ordered list of v-table elements
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008689 my ($ClassId, $LibVersion) = @_;
8690 my @Bases = get_base_classes($ClassId, $LibVersion, 1);
8691 my @Elements = ();
8692 foreach my $BaseId (@Bases, $ClassId)
8693 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04008694 if(my $BName = $TypeInfo{$LibVersion}{$BaseId}{"Name"})
Andrey Ponomarenko85043792012-05-14 16:48:07 +04008695 {
8696 if(defined $VirtualTable{$LibVersion}{$BName})
8697 {
8698 my @VFunctions = keys(%{$VirtualTable{$LibVersion}{$BName}});
8699 @VFunctions = sort {int($CompleteSignature{$LibVersion}{$a}{"Line"}) <=> int($CompleteSignature{$LibVersion}{$b}{"Line"})} @VFunctions;
8700 foreach my $VFunc (@VFunctions) {
8701 push(@Elements, $VFunc);
8702 }
8703 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008704 }
8705 }
8706 return @Elements;
8707}
8708
8709sub getVShift($$)
8710{
8711 my ($ClassId, $LibVersion) = @_;
8712 my @Bases = get_base_classes($ClassId, $LibVersion, 1);
8713 my $VShift = 0;
8714 foreach my $BaseId (@Bases)
8715 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04008716 if(my $BName = $TypeInfo{$LibVersion}{$BaseId}{"Name"})
Andrey Ponomarenko85043792012-05-14 16:48:07 +04008717 {
8718 if(defined $VirtualTable{$LibVersion}{$BName}) {
8719 $VShift+=keys(%{$VirtualTable{$LibVersion}{$BName}});
8720 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008721 }
8722 }
8723 return $VShift;
8724}
8725
8726sub getShift($$)
8727{
8728 my ($ClassId, $LibVersion) = @_;
8729 my @Bases = get_base_classes($ClassId, $LibVersion, 0);
8730 my $Shift = 0;
8731 foreach my $BaseId (@Bases)
8732 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04008733 if(my $Size = $TypeInfo{$LibVersion}{$BaseId}{"Size"})
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04008734 {
8735 if($Size!=1)
8736 { # not empty base class
8737 $Shift+=$Size;
8738 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008739 }
8740 }
8741 return $Shift;
8742}
8743
Andrey Ponomarenko16934472012-03-29 15:37:04 +04008744sub getVTable_Size($$)
8745{ # number of v-table elements
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008746 my ($ClassName, $LibVersion) = @_;
Andrey Ponomarenko16934472012-03-29 15:37:04 +04008747 my $Size = 0;
8748 # three approaches
8749 if(not $Size)
8750 { # real size
8751 if(my %VTable = getVTable_Real($ClassName, $LibVersion)) {
8752 $Size = keys(%VTable);
8753 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008754 }
Andrey Ponomarenko16934472012-03-29 15:37:04 +04008755 if(not $Size)
8756 { # shared library symbol size
8757 if($Size = getSymbolSize($ClassVTable{$ClassName}, $LibVersion)) {
8758 $Size /= $WORD_SIZE{$LibVersion};
8759 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008760 }
Andrey Ponomarenko16934472012-03-29 15:37:04 +04008761 if(not $Size)
8762 { # model size
8763 if(defined $VirtualTable_Model{$LibVersion}{$ClassName}) {
8764 $Size = keys(%{$VirtualTable_Model{$LibVersion}{$ClassName}}) + 2;
8765 }
8766 }
8767 return $Size;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008768}
8769
8770sub isCopyingClass($$)
8771{
8772 my ($TypeId, $LibVersion) = @_;
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04008773 return $TypeInfo{$LibVersion}{$TypeId}{"Copied"};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008774}
8775
8776sub isLeafClass($$)
8777{
8778 my ($ClassId, $LibVersion) = @_;
8779 return (not keys(%{$Class_SubClasses{$LibVersion}{$ClassId}}));
8780}
8781
8782sub havePubFields($)
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04008783{ # check structured type for public fields
8784 return isAccessible($_[0], {}, 0, -1);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008785}
8786
8787sub isAccessible($$$$)
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04008788{ # check interval in structured type for public fields
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008789 my ($TypePtr, $Skip, $Start, $End) = @_;
8790 return 0 if(not $TypePtr);
8791 if($End==-1) {
8792 $End = keys(%{$TypePtr->{"Memb"}})-1;
8793 }
8794 foreach my $MemPos (keys(%{$TypePtr->{"Memb"}}))
8795 {
8796 if($Skip and $Skip->{$MemPos})
8797 { # skip removed/added fields
8798 next;
8799 }
8800 if(int($MemPos)>=$Start and int($MemPos)<=$End)
8801 {
8802 if(isPublic($TypePtr, $MemPos)) {
8803 return ($MemPos+1);
8804 }
8805 }
8806 }
8807 return 0;
8808}
8809
8810sub getAlignment($$$)
8811{
8812 my ($Pos, $TypePtr, $LibVersion) = @_;
8813 my $Tid = $TypePtr->{"Memb"}{$Pos}{"type"};
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04008814 my %Type = get_PureType($Tid, $LibVersion);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008815 my $TSize = $Type{"Size"}*$BYTE_SIZE;
8816 my $MSize = $Type{"Size"}*$BYTE_SIZE;
8817 if(my $BSize = $TypePtr->{"Memb"}{$Pos}{"bitfield"})
8818 { # bitfields
8819 ($TSize, $MSize) = ($WORD_SIZE{$LibVersion}*$BYTE_SIZE, $BSize);
8820 }
8821 elsif($Type{"Type"} eq "Array")
8822 { # in the context of function parameter
8823 # it's passed through the pointer
8824 }
8825 # alignment
8826 my $Alignment = $WORD_SIZE{$LibVersion}*$BYTE_SIZE; # default
8827 if(my $Computed = $TypePtr->{"Memb"}{$Pos}{"algn"})
8828 { # computed by GCC
8829 $Alignment = $Computed*$BYTE_SIZE;
8830 }
8831 elsif($TypePtr->{"Memb"}{$Pos}{"bitfield"})
8832 { # bitfields are 1 bit aligned
8833 $Alignment = 1;
8834 }
8835 elsif($TSize and $TSize<$WORD_SIZE{$LibVersion}*$BYTE_SIZE)
8836 { # model
8837 $Alignment = $TSize;
8838 }
8839 return ($Alignment, $MSize);
8840}
8841
8842sub getOffset($$$)
8843{ # offset of the field including padding
8844 my ($FieldPos, $TypePtr, $LibVersion) = @_;
8845 my $Offset = 0;
8846 foreach my $Pos (0 .. keys(%{$TypePtr->{"Memb"}})-1)
8847 {
8848 my ($Alignment, $MSize) = getAlignment($Pos, $TypePtr, $LibVersion);
8849 # padding
8850 my $Padding = 0;
8851 if($Offset % $Alignment!=0)
8852 { # not aligned, add padding
8853 $Padding = $Alignment - $Offset % $Alignment;
8854 }
8855 $Offset += $Padding;
8856 if($Pos==$FieldPos)
8857 { # after the padding
8858 # before the field
8859 return $Offset;
8860 }
8861 $Offset += $MSize;
8862 }
8863 return $FieldPos;# if something is going wrong
8864}
8865
8866sub isMemPadded($$$$$)
8867{ # check if the target field can be added/removed/changed
8868 # without shifting other fields because of padding bits
8869 my ($FieldPos, $Size, $TypePtr, $Skip, $LibVersion) = @_;
8870 return 0 if($FieldPos==0);
8871 if(defined $TypePtr->{"Memb"}{""})
8872 {
8873 delete($TypePtr->{"Memb"}{""});
8874 if($Debug) {
8875 printMsg("WARNING", "internal error detected");
8876 }
8877 }
8878 my $Offset = 0;
8879 my (%Alignment, %MSize) = ();
8880 my $MaxAlgn = 0;
8881 my $End = keys(%{$TypePtr->{"Memb"}})-1;
8882 my $NextField = $FieldPos+1;
8883 foreach my $Pos (0 .. $End)
8884 {
8885 if($Skip and $Skip->{$Pos})
8886 { # skip removed/added fields
8887 if($Pos > $FieldPos)
8888 { # after the target
8889 $NextField += 1;
8890 next;
8891 }
8892 }
8893 ($Alignment{$Pos}, $MSize{$Pos}) = getAlignment($Pos, $TypePtr, $LibVersion);
8894 if($Alignment{$Pos}>$MaxAlgn) {
8895 $MaxAlgn = $Alignment{$Pos};
8896 }
8897 if($Pos==$FieldPos)
8898 {
8899 if($Size==-1)
8900 { # added/removed fields
8901 if($Pos!=$End)
8902 { # skip target field and see
8903 # if enough padding will be
8904 # created on the next step
8905 # to include this field
8906 next;
8907 }
8908 }
8909 }
8910 # padding
8911 my $Padding = 0;
8912 if($Offset % $Alignment{$Pos}!=0)
8913 { # not aligned, add padding
8914 $Padding = $Alignment{$Pos} - $Offset % $Alignment{$Pos};
8915 }
8916 if($Pos==$NextField)
8917 { # try to place target field in the padding
8918 if($Size==-1)
8919 { # added/removed fields
8920 my $TPadding = 0;
8921 if($Offset % $Alignment{$FieldPos}!=0)
8922 {# padding of the target field
8923 $TPadding = $Alignment{$FieldPos} - $Offset % $Alignment{$FieldPos};
8924 }
8925 if($TPadding+$MSize{$FieldPos}<=$Padding)
8926 { # enough padding to place target field
8927 return 1;
8928 }
8929 else {
8930 return 0;
8931 }
8932 }
8933 else
8934 { # changed fields
8935 my $Delta = $Size-$MSize{$FieldPos};
8936 if($Delta>=0)
8937 { # increased
8938 if($Size-$MSize{$FieldPos}<=$Padding)
8939 { # enough padding to change target field
8940 return 1;
8941 }
8942 else {
8943 return 0;
8944 }
8945 }
8946 else
8947 { # decreased
8948 $Delta = abs($Delta);
8949 if($Delta+$Padding>=$MSize{$Pos})
8950 { # try to place the next field
8951 if(($Offset-$Delta) % $Alignment{$Pos} != 0)
8952 { # padding of the next field in new place
8953 my $NPadding = $Alignment{$Pos} - ($Offset-$Delta) % $Alignment{$Pos};
8954 if($NPadding+$MSize{$Pos}<=$Delta+$Padding)
8955 { # enough delta+padding to store next field
8956 return 0;
8957 }
8958 }
8959 else
8960 {
8961 return 0;
8962 }
8963 }
8964 return 1;
8965 }
8966 }
8967 }
8968 elsif($Pos==$End)
8969 { # target field is the last field
8970 if($Size==-1)
8971 { # added/removed fields
8972 if($Offset % $MaxAlgn!=0)
8973 { # tail padding
8974 my $TailPadding = $MaxAlgn - $Offset % $MaxAlgn;
8975 if($Padding+$MSize{$Pos}<=$TailPadding)
8976 { # enough tail padding to place the last field
8977 return 1;
8978 }
8979 }
8980 return 0;
8981 }
8982 else
8983 { # changed fields
8984 # scenario #1
8985 my $Offset1 = $Offset+$Padding+$MSize{$Pos};
8986 if($Offset1 % $MaxAlgn != 0)
8987 { # tail padding
8988 $Offset1 += $MaxAlgn - $Offset1 % $MaxAlgn;
8989 }
8990 # scenario #2
8991 my $Offset2 = $Offset+$Padding+$Size;
8992 if($Offset2 % $MaxAlgn != 0)
8993 { # tail padding
8994 $Offset2 += $MaxAlgn - $Offset2 % $MaxAlgn;
8995 }
8996 if($Offset1!=$Offset2)
8997 { # different sizes of structure
8998 return 0;
8999 }
9000 return 1;
9001 }
9002 }
9003 $Offset += $Padding+$MSize{$Pos};
9004 }
9005 return 0;
9006}
9007
9008sub isReserved($)
9009{ # reserved fields == private
9010 my $MName = $_[0];
9011 if($MName=~/reserved|padding|f_spare/i) {
9012 return 1;
9013 }
9014 if($MName=~/\A[_]*(spare|pad|unused)[_]*\Z/i) {
9015 return 1;
9016 }
9017 if($MName=~/(pad\d+)/i) {
9018 return 1;
9019 }
9020 return 0;
9021}
9022
9023sub isPublic($$)
9024{
9025 my ($TypePtr, $FieldPos) = @_;
9026 return 0 if(not $TypePtr);
9027 return 0 if(not defined $TypePtr->{"Memb"}{$FieldPos});
9028 return 0 if(not defined $TypePtr->{"Memb"}{$FieldPos}{"name"});
9029 if(not $TypePtr->{"Memb"}{$FieldPos}{"access"})
9030 { # by name in C language
9031 # FIXME: add other methods to detect private members
9032 my $MName = $TypePtr->{"Memb"}{$FieldPos}{"name"};
9033 if($MName=~/priv|abidata|parent_object/i)
9034 { # C-styled private data
9035 return 0;
9036 }
9037 if(lc($MName) eq "abi")
9038 { # ABI information/reserved field
9039 return 0;
9040 }
9041 if(isReserved($MName))
9042 { # reserved fields
9043 return 0;
9044 }
9045 return 1;
9046 }
9047 elsif($TypePtr->{"Memb"}{$FieldPos}{"access"} ne "private")
9048 { # by access in C++ language
9049 return 1;
9050 }
9051 return 0;
9052}
9053
Andrey Ponomarenko16934472012-03-29 15:37:04 +04009054sub getVTable_Real($$)
9055{
9056 my ($ClassName, $LibVersion) = @_;
9057 if(my $ClassId = $TName_Tid{$LibVersion}{$ClassName})
9058 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04009059 my %Type = get_Type($ClassId, $LibVersion);
Andrey Ponomarenko16934472012-03-29 15:37:04 +04009060 if(defined $Type{"VTable"}) {
9061 return %{$Type{"VTable"}};
9062 }
9063 }
9064 return ();
9065}
9066
9067sub cmpVTables($)
9068{
9069 my $ClassName = $_[0];
9070 my $Res = cmpVTables_Real($ClassName, 1);
9071 if($Res==-1) {
9072 $Res = cmpVTables_Model($ClassName);
9073 }
9074 return $Res;
9075}
9076
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009077sub cmpVTables_Model($)
9078{
9079 my $ClassName = $_[0];
Andrey Ponomarenko16934472012-03-29 15:37:04 +04009080 foreach my $Symbol (keys(%{$VirtualTable_Model{1}{$ClassName}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009081 {
Andrey Ponomarenko16934472012-03-29 15:37:04 +04009082 if(not defined $VirtualTable_Model{2}{$ClassName}{$Symbol}) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009083 return 1;
9084 }
9085 }
9086 return 0;
9087}
9088
Andrey Ponomarenko16934472012-03-29 15:37:04 +04009089sub cmpVTables_Real($$)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009090{
9091 my ($ClassName, $Strong) = @_;
Andrey Ponomarenko16934472012-03-29 15:37:04 +04009092 if(defined $Cache{"cmpVTables_Real"}{$Strong}{$ClassName}) {
9093 return $Cache{"cmpVTables_Real"}{$Strong}{$ClassName};
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04009094 }
Andrey Ponomarenko16934472012-03-29 15:37:04 +04009095 my %VTable_Old = getVTable_Real($ClassName, 1);
9096 my %VTable_New = getVTable_Real($ClassName, 2);
9097 if(not %VTable_Old or not %VTable_New)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009098 { # old ABI dumps
Andrey Ponomarenko16934472012-03-29 15:37:04 +04009099 return ($Cache{"cmpVTables_Real"}{$Strong}{$ClassName} = -1);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009100 }
Andrey Ponomarenko16934472012-03-29 15:37:04 +04009101 my %Indexes = map {$_=>1} (keys(%VTable_Old), keys(%VTable_New));
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009102 foreach my $Offset (sort {int($a)<=>int($b)} keys(%Indexes))
9103 {
Andrey Ponomarenko16934472012-03-29 15:37:04 +04009104 if(not defined $VTable_Old{$Offset})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009105 { # v-table v.1 < v-table v.2
Andrey Ponomarenko16934472012-03-29 15:37:04 +04009106 return ($Cache{"cmpVTables_Real"}{$Strong}{$ClassName} = $Strong);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009107 }
Andrey Ponomarenko16934472012-03-29 15:37:04 +04009108 my $Entry1 = $VTable_Old{$Offset};
9109 if(not defined $VTable_New{$Offset})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009110 { # v-table v.1 > v-table v.2
Andrey Ponomarenko16934472012-03-29 15:37:04 +04009111 return ($Cache{"cmpVTables_Real"}{$Strong}{$ClassName} = ($Strong or $Entry1!~/__cxa_pure_virtual/));
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009112 }
Andrey Ponomarenko16934472012-03-29 15:37:04 +04009113 my $Entry2 = $VTable_New{$Offset};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009114 $Entry1 = simpleVEntry($Entry1);
9115 $Entry2 = simpleVEntry($Entry2);
9116 if($Entry1 ne $Entry2)
9117 { # register as changed
9118 if($Entry1=~/::([^:]+)\Z/)
9119 {
9120 my $M1 = $1;
9121 if($Entry2=~/::([^:]+)\Z/)
9122 {
9123 my $M2 = $1;
9124 if($M1 eq $M2)
9125 { # overridden
9126 next;
9127 }
9128 }
9129 }
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +04009130 if(differentDumps("G"))
9131 {
9132 if($Entry1=~/\A\-(0x|\d+)/ and $Entry2=~/\A\-(0x|\d+)/)
9133 {
9134 # GCC 4.6.1: -0x00000000000000010
9135 # GCC 4.7.0: -16
9136 next;
9137 }
9138 }
Andrey Ponomarenko16934472012-03-29 15:37:04 +04009139 return ($Cache{"cmpVTables_Real"}{$Strong}{$ClassName} = 1);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009140 }
9141 }
Andrey Ponomarenko16934472012-03-29 15:37:04 +04009142 return ($Cache{"cmpVTables_Real"}{$Strong}{$ClassName} = 0);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009143}
9144
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04009145sub mergeVTables($)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009146{ # merging v-tables without diagnostics
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04009147 my $Level = $_[0];
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009148 foreach my $ClassName (keys(%{$VirtualTable{1}}))
9149 {
Andrey Ponomarenko16934472012-03-29 15:37:04 +04009150 if($VTableChanged_M{$ClassName})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009151 { # already registered
9152 next;
9153 }
Andrey Ponomarenko16934472012-03-29 15:37:04 +04009154 if(cmpVTables_Real($ClassName, 0)==1)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009155 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04009156 my @Affected = (keys(%{$ClassMethods{$Level}{1}{$ClassName}}));
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009157 foreach my $Symbol (@Affected)
9158 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04009159 %{$CompatProblems{$Level}{$Symbol}{"Virtual_Table_Changed_Unknown"}{$ClassName}}=(
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009160 "Type_Name"=>$ClassName,
9161 "Type_Type"=>"Class",
9162 "Target"=>$ClassName);
9163 }
9164 }
9165 }
9166}
9167
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04009168sub mergeBases($)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009169{
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04009170 my $Level = $_[0];
Andrey Ponomarenko16934472012-03-29 15:37:04 +04009171 foreach my $ClassName (keys(%{$ClassNames{1}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009172 { # detect added and removed virtual functions
Andrey Ponomarenko16934472012-03-29 15:37:04 +04009173 my $ClassId = $TName_Tid{1}{$ClassName};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009174 next if(not $ClassId);
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04009175 if(defined $VirtualTable{2}{$ClassName})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009176 {
Andrey Ponomarenko16934472012-03-29 15:37:04 +04009177 foreach my $Symbol (keys(%{$VirtualTable{2}{$ClassName}}))
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04009178 {
Andrey Ponomarenko16934472012-03-29 15:37:04 +04009179 if($TName_Tid{1}{$ClassName}
9180 and not defined $VirtualTable{1}{$ClassName}{$Symbol})
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04009181 { # added to v-table
Andrey Ponomarenko16934472012-03-29 15:37:04 +04009182 if(defined $CompleteSignature{1}{$Symbol}
9183 and $CompleteSignature{1}{$Symbol}{"Virt"})
9184 { # override some method in v.1
9185 next;
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04009186 }
Andrey Ponomarenko16934472012-03-29 15:37:04 +04009187 $AddedInt_Virt{$Level}{$ClassName}{$Symbol} = 1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009188 }
9189 }
9190 }
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04009191 if(defined $VirtualTable{1}{$ClassName})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009192 {
Andrey Ponomarenko16934472012-03-29 15:37:04 +04009193 foreach my $Symbol (keys(%{$VirtualTable{1}{$ClassName}}))
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04009194 {
Andrey Ponomarenko16934472012-03-29 15:37:04 +04009195 if($TName_Tid{2}{$ClassName}
9196 and not defined $VirtualTable{2}{$ClassName}{$Symbol})
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04009197 { # removed from v-table
Andrey Ponomarenko16934472012-03-29 15:37:04 +04009198 if(defined $CompleteSignature{2}{$Symbol}
9199 and $CompleteSignature{2}{$Symbol}{"Virt"})
9200 { # override some method in v.2
9201 next;
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04009202 }
Andrey Ponomarenko16934472012-03-29 15:37:04 +04009203 $RemovedInt_Virt{$Level}{$ClassName}{$Symbol} = 1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009204 }
9205 }
9206 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04009207 if($Level eq "Binary")
9208 { # Binary-level
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04009209 my %Class_Type = get_Type($ClassId, 1);
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04009210 foreach my $AddedVFunc (keys(%{$AddedInt_Virt{$Level}{$ClassName}}))
9211 { # check replacements, including pure virtual methods
9212 my $AddedPos = $VirtualTable{2}{$ClassName}{$AddedVFunc};
9213 foreach my $RemovedVFunc (keys(%{$RemovedInt_Virt{$Level}{$ClassName}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009214 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04009215 my $RemovedPos = $VirtualTable{1}{$ClassName}{$RemovedVFunc};
9216 if($AddedPos==$RemovedPos)
9217 {
9218 $VirtualReplacement{$AddedVFunc} = $RemovedVFunc;
9219 $VirtualReplacement{$RemovedVFunc} = $AddedVFunc;
9220 last; # other methods will be reported as "added" or "removed"
9221 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009222 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04009223 if(my $RemovedVFunc = $VirtualReplacement{$AddedVFunc})
9224 {
9225 if(lc($AddedVFunc) eq lc($RemovedVFunc))
9226 { # skip: DomUi => DomUI parameter (Qt 4.2.3 to 4.3.0)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009227 next;
9228 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04009229 my $ProblemType = "Virtual_Replacement";
9230 my @Affected = ($RemovedVFunc);
9231 if($CompleteSignature{1}{$RemovedVFunc}{"PureVirt"})
9232 { # pure methods
9233 if(not isUsedClass($ClassId, 1, $Level))
9234 { # not a parameter of some exported method
9235 next;
9236 }
9237 $ProblemType = "Pure_Virtual_Replacement";
9238 @Affected = (keys(%{$ClassMethods{$Level}{1}{$ClassName}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009239 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04009240 foreach my $AffectedInt (@Affected)
9241 {
9242 if($CompleteSignature{1}{$AffectedInt}{"PureVirt"})
9243 { # affected exported methods only
9244 next;
9245 }
9246 %{$CompatProblems{$Level}{$AffectedInt}{$ProblemType}{$tr_name{$AddedVFunc}}}=(
9247 "Type_Name"=>$Class_Type{"Name"},
9248 "Type_Type"=>"Class",
9249 "Target"=>get_Signature($AddedVFunc, 2),
9250 "Old_Value"=>get_Signature($RemovedVFunc, 1));
9251 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009252 }
9253 }
9254 }
9255 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04009256 if(not checkDump(1, "2.0")
9257 or not checkDump(2, "2.0"))
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04009258 { # support for old ABI dumps
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009259 # "Base" attribute introduced in ACC 1.22 (dump 2.0 format)
9260 return;
9261 }
Andrey Ponomarenko16934472012-03-29 15:37:04 +04009262 foreach my $ClassName (sort keys(%{$ClassNames{1}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009263 {
Andrey Ponomarenko16934472012-03-29 15:37:04 +04009264 my $ClassId_Old = $TName_Tid{1}{$ClassName};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009265 next if(not $ClassId_Old);
9266 if(not isCreatable($ClassId_Old, 1))
9267 { # skip classes without public constructors (including auto-generated)
9268 # example: class has only a private exported or private inline constructor
9269 next;
9270 }
9271 if($ClassName=~/>/)
9272 { # skip affected template instances
9273 next;
9274 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04009275 my %Class_Old = get_Type($ClassId_Old, 1);
Andrey Ponomarenko16934472012-03-29 15:37:04 +04009276 my $ClassId_New = $TName_Tid{2}{$ClassName};
Andrey Ponomarenko85043792012-05-14 16:48:07 +04009277 if(not $ClassId_New) {
9278 next;
9279 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04009280 my %Class_New = get_Type($ClassId_New, 2);
Andrey Ponomarenko85043792012-05-14 16:48:07 +04009281 if($Class_New{"Type"}!~/Class|Struct/)
9282 { # became typedef
9283 if($Level eq "Binary") {
9284 next;
9285 }
9286 if($Level eq "Source")
9287 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04009288 %Class_New = get_PureType($ClassId_New, 2);
Andrey Ponomarenko85043792012-05-14 16:48:07 +04009289 if($Class_New{"Type"}!~/Class|Struct/) {
9290 next;
9291 }
9292 $ClassId_New = $Class_New{"Tid"};
9293 }
9294 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009295 my @Bases_Old = sort {$Class_Old{"Base"}{$a}{"pos"}<=>$Class_Old{"Base"}{$b}{"pos"}} keys(%{$Class_Old{"Base"}});
9296 my @Bases_New = sort {$Class_New{"Base"}{$a}{"pos"}<=>$Class_New{"Base"}{$b}{"pos"}} keys(%{$Class_New{"Base"}});
9297 my ($BNum1, $BNum2) = (1, 1);
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04009298 my %BasePos_Old = map {$TypeInfo{1}{$_}{"Name"} => $BNum1++} @Bases_Old;
9299 my %BasePos_New = map {$TypeInfo{2}{$_}{"Name"} => $BNum2++} @Bases_New;
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04009300 my %ShortBase_Old = map {get_ShortType($_, 1) => 1} @Bases_Old;
9301 my %ShortBase_New = map {get_ShortType($_, 2) => 1} @Bases_New;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009302 my $Shift_Old = getShift($ClassId_Old, 1);
9303 my $Shift_New = getShift($ClassId_New, 2);
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04009304 my %BaseId_New = map {$TypeInfo{2}{$_}{"Name"} => $_} @Bases_New;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009305 my ($Added, $Removed) = (0, 0);
9306 my @StableBases_Old = ();
9307 foreach my $BaseId (@Bases_Old)
9308 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04009309 my $BaseName = $TypeInfo{1}{$BaseId}{"Name"};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009310 if($BasePos_New{$BaseName}) {
9311 push(@StableBases_Old, $BaseId);
9312 }
9313 elsif(not $ShortBase_New{$BaseName}
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04009314 and not $ShortBase_New{get_ShortType($BaseId, 1)})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009315 { # removed base
9316 # excluding namespace::SomeClass to SomeClass renaming
9317 my $ProblemKind = "Removed_Base_Class";
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04009318 if($Level eq "Binary")
9319 { # Binary-level
9320 if($Shift_Old ne $Shift_New)
9321 { # affected fields
9322 if(havePubFields(\%Class_Old)) {
9323 $ProblemKind .= "_And_Shift";
9324 }
9325 elsif($Class_Old{"Size"} ne $Class_New{"Size"}) {
9326 $ProblemKind .= "_And_Size";
9327 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009328 }
Andrey Ponomarenko16934472012-03-29 15:37:04 +04009329 if(keys(%{$VirtualTable_Model{1}{$BaseName}})
9330 and cmpVTables($ClassName)==1)
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04009331 { # affected v-table
9332 $ProblemKind .= "_And_VTable";
Andrey Ponomarenko16934472012-03-29 15:37:04 +04009333 $VTableChanged_M{$ClassName}=1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009334 }
9335 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04009336 my @Affected = keys(%{$ClassMethods{$Level}{1}{$ClassName}});
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009337 foreach my $SubId (get_sub_classes($ClassId_Old, 1, 1))
9338 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04009339 my $SubName = $TypeInfo{1}{$SubId}{"Name"};
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04009340 push(@Affected, keys(%{$ClassMethods{$Level}{1}{$SubName}}));
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009341 if($ProblemKind=~/VTable/) {
Andrey Ponomarenko16934472012-03-29 15:37:04 +04009342 $VTableChanged_M{$SubName}=1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009343 }
9344 }
9345 foreach my $Interface (@Affected)
9346 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04009347 %{$CompatProblems{$Level}{$Interface}{$ProblemKind}{"this"}}=(
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009348 "Type_Name"=>$ClassName,
9349 "Type_Type"=>"Class",
9350 "Target"=>$BaseName,
9351 "Old_Size"=>$Class_Old{"Size"}*$BYTE_SIZE,
9352 "New_Size"=>$Class_New{"Size"}*$BYTE_SIZE,
9353 "Shift"=>abs($Shift_New-$Shift_Old) );
9354 }
9355 $Removed+=1;
9356 }
9357 }
9358 my @StableBases_New = ();
9359 foreach my $BaseId (@Bases_New)
9360 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04009361 my $BaseName = $TypeInfo{2}{$BaseId}{"Name"};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009362 if($BasePos_Old{$BaseName}) {
9363 push(@StableBases_New, $BaseId);
9364 }
9365 elsif(not $ShortBase_Old{$BaseName}
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04009366 and not $ShortBase_Old{get_ShortType($BaseId, 2)})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009367 { # added base
9368 # excluding namespace::SomeClass to SomeClass renaming
9369 my $ProblemKind = "Added_Base_Class";
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04009370 if($Level eq "Binary")
9371 { # Binary-level
9372 if($Shift_Old ne $Shift_New)
9373 { # affected fields
9374 if(havePubFields(\%Class_Old)) {
9375 $ProblemKind .= "_And_Shift";
9376 }
9377 elsif($Class_Old{"Size"} ne $Class_New{"Size"}) {
9378 $ProblemKind .= "_And_Size";
9379 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009380 }
Andrey Ponomarenko16934472012-03-29 15:37:04 +04009381 if(keys(%{$VirtualTable_Model{2}{$BaseName}})
9382 and cmpVTables($ClassName)==1)
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04009383 { # affected v-table
9384 $ProblemKind .= "_And_VTable";
Andrey Ponomarenko16934472012-03-29 15:37:04 +04009385 $VTableChanged_M{$ClassName}=1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009386 }
9387 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04009388 my @Affected = keys(%{$ClassMethods{$Level}{1}{$ClassName}});
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009389 foreach my $SubId (get_sub_classes($ClassId_Old, 1, 1))
9390 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04009391 my $SubName = $TypeInfo{1}{$SubId}{"Name"};
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04009392 push(@Affected, keys(%{$ClassMethods{$Level}{1}{$SubName}}));
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009393 if($ProblemKind=~/VTable/) {
Andrey Ponomarenko16934472012-03-29 15:37:04 +04009394 $VTableChanged_M{$SubName}=1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009395 }
9396 }
9397 foreach my $Interface (@Affected)
9398 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04009399 %{$CompatProblems{$Level}{$Interface}{$ProblemKind}{"this"}}=(
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009400 "Type_Name"=>$ClassName,
9401 "Type_Type"=>"Class",
9402 "Target"=>$BaseName,
9403 "Old_Size"=>$Class_Old{"Size"}*$BYTE_SIZE,
9404 "New_Size"=>$Class_New{"Size"}*$BYTE_SIZE,
9405 "Shift"=>abs($Shift_New-$Shift_Old) );
9406 }
9407 $Added+=1;
9408 }
9409 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04009410 if($Level eq "Binary")
9411 { # Binary-level
9412 ($BNum1, $BNum2) = (1, 1);
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04009413 my %BaseRelPos_Old = map {$TypeInfo{1}{$_}{"Name"} => $BNum1++} @StableBases_Old;
9414 my %BaseRelPos_New = map {$TypeInfo{2}{$_}{"Name"} => $BNum2++} @StableBases_New;
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04009415 foreach my $BaseId (@Bases_Old)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009416 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04009417 my $BaseName = $TypeInfo{1}{$BaseId}{"Name"};
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04009418 if(my $NewPos = $BaseRelPos_New{$BaseName})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009419 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04009420 my $BaseNewId = $BaseId_New{$BaseName};
9421 my $OldPos = $BaseRelPos_Old{$BaseName};
9422 if($NewPos!=$OldPos)
9423 { # changed position of the base class
9424 foreach my $Interface (keys(%{$ClassMethods{$Level}{1}{$ClassName}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009425 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04009426 %{$CompatProblems{$Level}{$Interface}{"Base_Class_Position"}{"this"}}=(
9427 "Type_Name"=>$ClassName,
9428 "Type_Type"=>"Class",
9429 "Target"=>$BaseName,
9430 "Old_Value"=>$OldPos-1,
9431 "New_Value"=>$NewPos-1 );
9432 }
9433 }
9434 if($Class_Old{"Base"}{$BaseId}{"virtual"}
9435 and not $Class_New{"Base"}{$BaseNewId}{"virtual"})
9436 { # became non-virtual base
9437 foreach my $Interface (keys(%{$ClassMethods{$Level}{1}{$ClassName}}))
9438 {
9439 %{$CompatProblems{$Level}{$Interface}{"Base_Class_Became_Non_Virtually_Inherited"}{"this->".$BaseName}}=(
9440 "Type_Name"=>$ClassName,
9441 "Type_Type"=>"Class",
9442 "Target"=>$BaseName );
9443 }
9444 }
9445 elsif(not $Class_Old{"Base"}{$BaseId}{"virtual"}
9446 and $Class_New{"Base"}{$BaseNewId}{"virtual"})
9447 { # became virtual base
9448 foreach my $Interface (keys(%{$ClassMethods{$Level}{1}{$ClassName}}))
9449 {
9450 %{$CompatProblems{$Level}{$Interface}{"Base_Class_Became_Virtually_Inherited"}{"this->".$BaseName}}=(
9451 "Type_Name"=>$ClassName,
9452 "Type_Type"=>"Class",
9453 "Target"=>$BaseName );
9454 }
9455 }
9456 }
9457 }
9458 # detect size changes in base classes
9459 if($Shift_Old!=$Shift_New)
9460 { # size of allocable class
9461 foreach my $BaseId (@StableBases_Old)
9462 { # search for changed base
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04009463 my %BaseType = get_Type($BaseId, 1);
9464 my $Size_Old = $TypeInfo{1}{$BaseId}{"Size"};
9465 my $Size_New = $TypeInfo{2}{$BaseId_New{$BaseType{"Name"}}}{"Size"};
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04009466 if($Size_Old ne $Size_New
9467 and $Size_Old and $Size_New)
9468 {
9469 my $ProblemType = "";
9470 if(isCopyingClass($BaseId, 1)) {
9471 $ProblemType = "Size_Of_Copying_Class";
9472 }
9473 elsif($AllocableClass{1}{$BaseType{"Name"}})
9474 {
9475 if($Size_New>$Size_Old)
9476 { # increased size
9477 $ProblemType = "Size_Of_Allocable_Class_Increased";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009478 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04009479 else
9480 { # decreased size
9481 $ProblemType = "Size_Of_Allocable_Class_Decreased";
9482 if(not havePubFields(\%Class_Old))
9483 { # affected class has no public members
9484 next;
9485 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009486 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04009487 }
9488 next if(not $ProblemType);
9489 foreach my $Interface (keys(%{$ClassMethods{$Level}{1}{$ClassName}}))
9490 { # base class size changes affecting current class
9491 %{$CompatProblems{$Level}{$Interface}{$ProblemType}{"this->".$BaseType{"Name"}}}=(
9492 "Type_Name"=>$BaseType{"Name"},
9493 "Type_Type"=>"Class",
9494 "Target"=>$BaseType{"Name"},
9495 "Old_Size"=>$Size_Old*$BYTE_SIZE,
9496 "New_Size"=>$Size_New*$BYTE_SIZE );
9497 }
9498 }
9499 }
9500 }
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04009501 if(defined $VirtualTable{1}{$ClassName}
Andrey Ponomarenko16934472012-03-29 15:37:04 +04009502 and cmpVTables_Real($ClassName, 1)==1
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04009503 and my @VFunctions = keys(%{$VirtualTable{1}{$ClassName}}))
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04009504 { # compare virtual tables size in base classes
9505 my $VShift_Old = getVShift($ClassId_Old, 1);
9506 my $VShift_New = getVShift($ClassId_New, 2);
9507 if($VShift_Old ne $VShift_New)
9508 { # changes in the base class or changes in the list of base classes
9509 my @AllBases_Old = get_base_classes($ClassId_Old, 1, 1);
9510 my @AllBases_New = get_base_classes($ClassId_New, 2, 1);
9511 ($BNum1, $BNum2) = (1, 1);
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04009512 my %StableBase = map {$TypeInfo{2}{$_}{"Name"} => $_} @AllBases_New;
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04009513 foreach my $BaseId (@AllBases_Old)
9514 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04009515 my %BaseType = get_Type($BaseId, 1);
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04009516 if(not $StableBase{$BaseType{"Name"}})
9517 { # lost base
9518 next;
9519 }
Andrey Ponomarenko16934472012-03-29 15:37:04 +04009520 my $VSize_Old = getVTable_Size($BaseType{"Name"}, 1);
9521 my $VSize_New = getVTable_Size($BaseType{"Name"}, 2);
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04009522 if($VSize_Old!=$VSize_New)
9523 {
Andrey Ponomarenko85043792012-05-14 16:48:07 +04009524 foreach my $Symbol (@VFunctions)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009525 {
Andrey Ponomarenko85043792012-05-14 16:48:07 +04009526 if(not defined $VirtualTable{2}{$ClassName}{$Symbol})
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04009527 { # Removed_Virtual_Method, will be registered in mergeVirtualTables()
9528 next;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009529 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +04009530 if($VirtualTable_Model{2}{$ClassName}{$Symbol}-$VirtualTable_Model{1}{$ClassName}{$Symbol}==0)
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04009531 { # skip interfaces that have not changed the absolute virtual position
9532 next;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009533 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +04009534 if(not symbolFilter($Symbol, 1, "Affected", $Level)) {
9535 next;
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04009536 }
Andrey Ponomarenko16934472012-03-29 15:37:04 +04009537 $VTableChanged_M{$BaseType{"Name"}} = 1;
9538 $VTableChanged_M{$ClassName} = 1;
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04009539 foreach my $VirtFunc (keys(%{$AddedInt_Virt{$Level}{$BaseType{"Name"}}}))
9540 { # the reason of the layout change: added virtual functions
9541 next if($VirtualReplacement{$VirtFunc});
9542 my $ProblemType = "Added_Virtual_Method";
9543 if($CompleteSignature{2}{$VirtFunc}{"PureVirt"}) {
9544 $ProblemType = "Added_Pure_Virtual_Method";
9545 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +04009546 %{$CompatProblems{$Level}{$Symbol}{$ProblemType}{get_Signature($VirtFunc, 2)}}=(
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04009547 "Type_Name"=>$BaseType{"Name"},
9548 "Type_Type"=>"Class",
9549 "Target"=>get_Signature($VirtFunc, 2) );
9550 }
9551 foreach my $VirtFunc (keys(%{$RemovedInt_Virt{$Level}{$BaseType{"Name"}}}))
9552 { # the reason of the layout change: removed virtual functions
9553 next if($VirtualReplacement{$VirtFunc});
9554 my $ProblemType = "Removed_Virtual_Method";
9555 if($CompleteSignature{1}{$VirtFunc}{"PureVirt"}) {
9556 $ProblemType = "Removed_Pure_Virtual_Method";
9557 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +04009558 %{$CompatProblems{$Level}{$Symbol}{$ProblemType}{get_Signature($VirtFunc, 1)}}=(
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04009559 "Type_Name"=>$BaseType{"Name"},
9560 "Type_Type"=>"Class",
9561 "Target"=>get_Signature($VirtFunc, 1) );
9562 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009563 }
9564 }
9565 }
9566 }
9567 }
9568 }
9569 }
9570}
9571
9572sub isCreatable($$)
9573{
9574 my ($ClassId, $LibVersion) = @_;
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04009575 if($AllocableClass{$LibVersion}{$TypeInfo{$LibVersion}{$ClassId}{"Name"}}
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009576 or isCopyingClass($ClassId, $LibVersion)) {
9577 return 1;
9578 }
9579 if(keys(%{$Class_SubClasses{$LibVersion}{$ClassId}}))
9580 { # Fix for incomplete data: if this class has
9581 # a base class then it should also has a constructor
9582 return 1;
9583 }
9584 if($ReturnedClass{$LibVersion}{$ClassId})
9585 { # returned by some method of this class
9586 # or any other class
9587 return 1;
9588 }
9589 return 0;
9590}
9591
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04009592sub isUsedClass($$$)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009593{
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04009594 my ($ClassId, $LibVersion, $Level) = @_;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009595 if(keys(%{$ParamClass{$LibVersion}{$ClassId}}))
9596 { # parameter of some exported method
9597 return 1;
9598 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04009599 my $CName = $TypeInfo{$LibVersion}{$ClassId}{"Name"};
9600 if(keys(%{$ClassMethods{$Level}{$LibVersion}{$CName}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009601 { # method from target class
9602 return 1;
9603 }
9604 return 0;
9605}
9606
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04009607sub mergeVirtualTables($$)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009608{ # check for changes in the virtual table
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04009609 my ($Interface, $Level) = @_;
Andrey Ponomarenko16934472012-03-29 15:37:04 +04009610 # affected methods:
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009611 # - virtual
9612 # - pure-virtual
9613 # - non-virtual
9614 if($CompleteSignature{1}{$Interface}{"Data"})
9615 { # global data is not affected
9616 return;
9617 }
9618 my $Class_Id = $CompleteSignature{1}{$Interface}{"Class"};
Andrey Ponomarenko16934472012-03-29 15:37:04 +04009619 if(not $Class_Id) {
9620 return;
9621 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04009622 my $CName = $TypeInfo{1}{$Class_Id}{"Name"};
Andrey Ponomarenko16934472012-03-29 15:37:04 +04009623 if(cmpVTables_Real($CName, 1)==0)
9624 { # no changes
9625 return;
9626 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04009627 $CheckedTypes{$Level}{$CName} = 1;
9628 if($Level eq "Binary")
9629 { # Binary-level
9630 if($CompleteSignature{1}{$Interface}{"PureVirt"}
9631 and not isUsedClass($Class_Id, 1, $Level))
9632 { # pure virtuals should not be affected
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04009633 # if there are no exported methods using this class
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04009634 return;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009635 }
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +04009636 }
9637 foreach my $Func (keys(%{$VirtualTable{1}{$CName}}))
9638 {
9639 if(defined $VirtualTable{2}{$CName}{$Func}
9640 and defined $CompleteSignature{2}{$Func})
9641 {
9642 if(not $CompleteSignature{1}{$Func}{"PureVirt"}
9643 and $CompleteSignature{2}{$Func}{"PureVirt"})
9644 { # became pure virtual
9645 %{$CompatProblems{$Level}{$Interface}{"Virtual_Method_Became_Pure"}{$tr_name{$Func}}}=(
9646 "Type_Name"=>$CName,
9647 "Type_Type"=>"Class",
9648 "Target"=>get_Signature_M($Func, 1) );
9649 $VTableChanged_M{$CName} = 1;
9650 }
9651 elsif($CompleteSignature{1}{$Func}{"PureVirt"}
9652 and not $CompleteSignature{2}{$Func}{"PureVirt"})
9653 { # became non-pure virtual
9654 %{$CompatProblems{$Level}{$Interface}{"Virtual_Method_Became_Non_Pure"}{$tr_name{$Func}}}=(
9655 "Type_Name"=>$CName,
9656 "Type_Type"=>"Class",
9657 "Target"=>get_Signature_M($Func, 1) );
9658 $VTableChanged_M{$CName} = 1;
9659 }
9660 }
9661 }
9662 if($Level eq "Binary")
9663 { # Binary-level
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04009664 # check virtual table structure
9665 foreach my $AddedVFunc (keys(%{$AddedInt_Virt{$Level}{$CName}}))
9666 {
9667 next if($Interface eq $AddedVFunc);
9668 next if($VirtualReplacement{$AddedVFunc});
9669 my $VPos_Added = $VirtualTable{2}{$CName}{$AddedVFunc};
9670 if($CompleteSignature{2}{$AddedVFunc}{"PureVirt"})
9671 { # pure virtual methods affect all others (virtual and non-virtual)
9672 %{$CompatProblems{$Level}{$Interface}{"Added_Pure_Virtual_Method"}{$tr_name{$AddedVFunc}}}=(
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009673 "Type_Name"=>$CName,
9674 "Type_Type"=>"Class",
9675 "Target"=>get_Signature($AddedVFunc, 2) );
Andrey Ponomarenko16934472012-03-29 15:37:04 +04009676 $VTableChanged_M{$CName} = 1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009677 }
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04009678 elsif(not defined $VirtualTable{1}{$CName}
9679 or $VPos_Added>keys(%{$VirtualTable{1}{$CName}}))
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04009680 { # added virtual function at the end of v-table
Andrey Ponomarenko16934472012-03-29 15:37:04 +04009681 if(not keys(%{$VirtualTable_Model{1}{$CName}}))
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04009682 { # became polymorphous class, added v-table pointer
9683 %{$CompatProblems{$Level}{$Interface}{"Added_First_Virtual_Method"}{$tr_name{$AddedVFunc}}}=(
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009684 "Type_Name"=>$CName,
9685 "Type_Type"=>"Class",
9686 "Target"=>get_Signature($AddedVFunc, 2) );
Andrey Ponomarenko16934472012-03-29 15:37:04 +04009687 $VTableChanged_M{$CName} = 1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009688 }
9689 else
9690 {
Andrey Ponomarenko16934472012-03-29 15:37:04 +04009691 my $VSize_Old = getVTable_Size($CName, 1);
9692 my $VSize_New = getVTable_Size($CName, 2);
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04009693 next if($VSize_Old==$VSize_New);# exception: register as removed and added virtual method
9694 if(isCopyingClass($Class_Id, 1))
9695 { # class has no constructors and v-table will be copied by applications, this may affect all methods
9696 my $ProblemType = "Added_Virtual_Method";
9697 if(isLeafClass($Class_Id, 1)) {
9698 $ProblemType = "Added_Virtual_Method_At_End_Of_Leaf_Copying_Class";
9699 }
9700 %{$CompatProblems{$Level}{$Interface}{$ProblemType}{$tr_name{$AddedVFunc}}}=(
9701 "Type_Name"=>$CName,
9702 "Type_Type"=>"Class",
9703 "Target"=>get_Signature($AddedVFunc, 2) );
Andrey Ponomarenko16934472012-03-29 15:37:04 +04009704 $VTableChanged_M{$CName} = 1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009705 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04009706 else
9707 {
9708 my $ProblemType = "Added_Virtual_Method";
9709 if(isLeafClass($Class_Id, 1)) {
9710 $ProblemType = "Added_Virtual_Method_At_End_Of_Leaf_Allocable_Class";
9711 }
9712 %{$CompatProblems{$Level}{$Interface}{$ProblemType}{$tr_name{$AddedVFunc}}}=(
9713 "Type_Name"=>$CName,
9714 "Type_Type"=>"Class",
9715 "Target"=>get_Signature($AddedVFunc, 2) );
Andrey Ponomarenko16934472012-03-29 15:37:04 +04009716 $VTableChanged_M{$CName} = 1;
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04009717 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009718 }
9719 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04009720 elsif($CompleteSignature{1}{$Interface}{"Virt"}
9721 or $CompleteSignature{1}{$Interface}{"PureVirt"})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009722 {
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04009723 if(defined $VirtualTable{1}{$CName}
9724 and defined $VirtualTable{2}{$CName})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009725 {
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04009726 my $VPos_Old = $VirtualTable{1}{$CName}{$Interface};
9727 my $VPos_New = $VirtualTable{2}{$CName}{$Interface};
9728 if($VPos_Added<=$VPos_Old and $VPos_Old!=$VPos_New)
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04009729 {
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04009730 my @Affected = ($Interface, keys(%{$OverriddenMethods{1}{$Interface}}));
9731 foreach my $ASymbol (@Affected)
9732 {
Andrey Ponomarenko85043792012-05-14 16:48:07 +04009733 if(not $CompleteSignature{1}{$ASymbol}{"PureVirt"})
9734 {
9735 if(symbolFilter($ASymbol, 1, "Affected", $Level)) {
9736 next;
9737 }
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04009738 }
9739 $CheckedSymbols{$Level}{$ASymbol} = 1;
9740 %{$CompatProblems{$Level}{$ASymbol}{"Added_Virtual_Method"}{$tr_name{$AddedVFunc}}}=(
9741 "Type_Name"=>$CName,
9742 "Type_Type"=>"Class",
9743 "Target"=>get_Signature($AddedVFunc, 2) );
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04009744 $VTableChanged_M{$TypeInfo{1}{$CompleteSignature{1}{$ASymbol}{"Class"}}{"Name"}} = 1;
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04009745 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009746 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009747 }
9748 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04009749 else {
9750 # safe
9751 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009752 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04009753 foreach my $RemovedVFunc (keys(%{$RemovedInt_Virt{$Level}{$CName}}))
9754 {
9755 next if($VirtualReplacement{$RemovedVFunc});
9756 if($RemovedVFunc eq $Interface
9757 and $CompleteSignature{1}{$RemovedVFunc}{"PureVirt"})
9758 { # This case is for removed virtual methods
9759 # implemented in both versions of a library
9760 next;
9761 }
Andrey Ponomarenko16934472012-03-29 15:37:04 +04009762 if(not keys(%{$VirtualTable_Model{2}{$CName}}))
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04009763 { # became non-polymorphous class, removed v-table pointer
9764 %{$CompatProblems{$Level}{$Interface}{"Removed_Last_Virtual_Method"}{$tr_name{$RemovedVFunc}}}=(
9765 "Type_Name"=>$CName,
9766 "Type_Type"=>"Class",
9767 "Target"=>get_Signature($RemovedVFunc, 1) );
Andrey Ponomarenko16934472012-03-29 15:37:04 +04009768 $VTableChanged_M{$CName} = 1;
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04009769 }
9770 elsif($CompleteSignature{1}{$Interface}{"Virt"}
9771 or $CompleteSignature{1}{$Interface}{"PureVirt"})
9772 {
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04009773 if(defined $VirtualTable{1}{$CName} and defined $VirtualTable{2}{$CName})
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04009774 {
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04009775 if(not defined $VirtualTable{1}{$CName}{$Interface}) {
9776 next;
9777 }
9778 my $VPos_New = -1;
9779 if(defined $VirtualTable{2}{$CName}{$Interface})
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04009780 {
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04009781 $VPos_New = $VirtualTable{2}{$CName}{$Interface};
9782 }
9783 else
9784 {
9785 if($Interface ne $RemovedVFunc) {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04009786 next;
9787 }
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04009788 }
9789 my $VPos_Removed = $VirtualTable{1}{$CName}{$RemovedVFunc};
9790 my $VPos_Old = $VirtualTable{1}{$CName}{$Interface};
9791 if($VPos_Removed<=$VPos_Old and $VPos_Old!=$VPos_New)
9792 {
9793 my @Affected = ($Interface, keys(%{$OverriddenMethods{1}{$Interface}}));
9794 foreach my $ASymbol (@Affected)
9795 {
Andrey Ponomarenko85043792012-05-14 16:48:07 +04009796 if(not $CompleteSignature{1}{$ASymbol}{"PureVirt"})
9797 {
9798 if(symbolFilter($ASymbol, 1, "Affected", $Level)) {
9799 next;
9800 }
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04009801 }
9802 my $ProblemType = "Removed_Virtual_Method";
9803 if($CompleteSignature{1}{$RemovedVFunc}{"PureVirt"}) {
9804 $ProblemType = "Removed_Pure_Virtual_Method";
9805 }
9806 $CheckedSymbols{$Level}{$ASymbol} = 1;
9807 %{$CompatProblems{$Level}{$ASymbol}{$ProblemType}{$tr_name{$RemovedVFunc}}}=(
9808 "Type_Name"=>$CName,
9809 "Type_Type"=>"Class",
9810 "Target"=>get_Signature($RemovedVFunc, 1) );
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04009811 $VTableChanged_M{$TypeInfo{1}{$CompleteSignature{1}{$ASymbol}{"Class"}}{"Name"}} = 1;
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04009812 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04009813 }
9814 }
9815 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009816 }
9817 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04009818 else
9819 { # Source-level
9820 foreach my $AddedVFunc (keys(%{$AddedInt_Virt{$Level}{$CName}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009821 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04009822 next if($Interface eq $AddedVFunc);
9823 if($CompleteSignature{2}{$AddedVFunc}{"PureVirt"})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009824 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04009825 %{$CompatProblems{$Level}{$Interface}{"Added_Pure_Virtual_Method"}{$tr_name{$AddedVFunc}}}=(
9826 "Type_Name"=>$CName,
9827 "Type_Type"=>"Class",
9828 "Target"=>get_Signature($AddedVFunc, 2) );
9829 }
9830 }
9831 foreach my $RemovedVFunc (keys(%{$RemovedInt_Virt{$Level}{$CName}}))
9832 {
9833 if($CompleteSignature{1}{$RemovedVFunc}{"PureVirt"})
9834 {
9835 %{$CompatProblems{$Level}{$Interface}{"Removed_Pure_Virtual_Method"}{$tr_name{$RemovedVFunc}}}=(
9836 "Type_Name"=>$CName,
9837 "Type_Type"=>"Class",
9838 "Target"=>get_Signature($RemovedVFunc, 1) );
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009839 }
9840 }
9841 }
9842}
9843
9844sub find_MemberPair_Pos_byName($$)
9845{
9846 my ($Member_Name, $Pair_Type) = @_;
9847 $Member_Name=~s/\A[_]+|[_]+\Z//g;
9848 foreach my $MemberPair_Pos (sort {int($a)<=>int($b)} keys(%{$Pair_Type->{"Memb"}}))
9849 {
9850 if(defined $Pair_Type->{"Memb"}{$MemberPair_Pos})
9851 {
9852 my $Name = $Pair_Type->{"Memb"}{$MemberPair_Pos}{"name"};
9853 $Name=~s/\A[_]+|[_]+\Z//g;
9854 if($Name eq $Member_Name) {
9855 return $MemberPair_Pos;
9856 }
9857 }
9858 }
9859 return "lost";
9860}
9861
9862sub find_MemberPair_Pos_byVal($$)
9863{
9864 my ($Member_Value, $Pair_Type) = @_;
9865 foreach my $MemberPair_Pos (sort {int($a)<=>int($b)} keys(%{$Pair_Type->{"Memb"}}))
9866 {
9867 if(defined $Pair_Type->{"Memb"}{$MemberPair_Pos}
9868 and $Pair_Type->{"Memb"}{$MemberPair_Pos}{"value"} eq $Member_Value) {
9869 return $MemberPair_Pos;
9870 }
9871 }
9872 return "lost";
9873}
9874
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04009875my %Severity_Val=(
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009876 "High"=>3,
9877 "Medium"=>2,
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04009878 "Low"=>1,
9879 "Safe"=>-1
9880);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009881
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04009882sub maxSeverity($$)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009883{
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04009884 my ($S1, $S2) = @_;
9885 if(cmpSeverities($S1, $S2)) {
9886 return $S1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009887 }
9888 else {
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04009889 return $S2;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009890 }
9891}
9892
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04009893sub cmpSeverities($$)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009894{
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04009895 my ($S1, $S2) = @_;
9896 if(not $S1) {
9897 return 0;
9898 }
9899 elsif(not $S2) {
9900 return 1;
9901 }
9902 return ($Severity_Val{$S1}>$Severity_Val{$S2});
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009903}
9904
9905sub getProblemSeverity($$)
9906{
9907 my ($Level, $Kind) = @_;
9908 return $CompatRules{$Level}{$Kind}{"Severity"};
9909}
9910
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04009911sub isRecurType($$)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009912{
9913 foreach (@RecurTypes)
9914 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04009915 if( $_->{"T1"} eq $_[0]
9916 and $_->{"T2"} eq $_[1] )
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009917 {
9918 return 1;
9919 }
9920 }
9921 return 0;
9922}
9923
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04009924sub pushType($$)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009925{
9926 my %TypeIDs=(
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04009927 "T1" => $_[0], #Tid1
9928 "T2" => $_[1] #Tid2
Andrey Ponomarenko16934472012-03-29 15:37:04 +04009929 );
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009930 push(@RecurTypes, \%TypeIDs);
9931}
9932
9933sub isRenamed($$$$$)
9934{
9935 my ($MemPos, $Type1, $LVersion1, $Type2, $LVersion2) = @_;
9936 my $Member_Name = $Type1->{"Memb"}{$MemPos}{"name"};
9937 my $MemberType_Id = $Type1->{"Memb"}{$MemPos}{"type"};
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04009938 my %MemberType_Pure = get_PureType($MemberType_Id, $LVersion1);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009939 if(not defined $Type2->{"Memb"}{$MemPos}) {
9940 return "";
9941 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04009942 my $PairType_Id = $Type2->{"Memb"}{$MemPos}{"type"};
9943 my %PairType_Pure = get_PureType($PairType_Id, $LVersion2);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009944
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04009945 my $Pair_Name = $Type2->{"Memb"}{$MemPos}{"name"};
9946 my $MemberPair_Pos_Rev = ($Member_Name eq $Pair_Name)?$MemPos:find_MemberPair_Pos_byName($Pair_Name, $Type1);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009947 if($MemberPair_Pos_Rev eq "lost")
9948 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04009949 if($MemberType_Pure{"Name"} eq $PairType_Pure{"Name"})
9950 { # base type match
9951 return $Pair_Name;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009952 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04009953 if($TypeInfo{$LVersion1}{$MemberType_Id}{"Name"} eq $TypeInfo{$LVersion2}{$PairType_Id}{"Name"})
9954 { # exact type match
9955 return $Pair_Name;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009956 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04009957 if($MemberType_Pure{"Size"} eq $PairType_Pure{"Size"})
9958 { # size match
9959 return $Pair_Name;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009960 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +04009961 if(isReserved($Pair_Name))
9962 { # reserved fields
9963 return $Pair_Name;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009964 }
9965 }
9966 return "";
9967}
9968
9969sub isLastElem($$)
9970{
9971 my ($Pos, $TypeRef) = @_;
9972 my $Name = $TypeRef->{"Memb"}{$Pos}{"name"};
9973 if($Name=~/last|count|max|total/i)
9974 { # GST_LEVEL_COUNT, GST_RTSP_ELAST
9975 return 1;
9976 }
9977 elsif($Name=~/END|NLIMITS\Z/)
9978 { # __RLIMIT_NLIMITS
9979 return 1;
9980 }
9981 elsif($Name=~/\AN[A-Z](.+)[a-z]+s\Z/
9982 and $Pos+1==keys(%{$TypeRef->{"Memb"}}))
9983 { # NImageFormats, NColorRoles
9984 return 1;
9985 }
9986 return 0;
9987}
9988
9989sub nonComparable($$)
9990{
9991 my ($T1, $T2) = @_;
9992 if($T1->{"Name"} ne $T2->{"Name"}
9993 and not isAnon($T1->{"Name"})
9994 and not isAnon($T2->{"Name"}))
9995 { # different names
9996 if($T1->{"Type"} ne "Pointer"
9997 or $T2->{"Type"} ne "Pointer")
9998 { # compare base types
9999 return 1;
10000 }
10001 if($T1->{"Name"}!~/\Avoid\s*\*/
10002 and $T2->{"Name"}=~/\Avoid\s*\*/)
10003 {
10004 return 1;
10005 }
10006 }
10007 elsif($T1->{"Type"} ne $T2->{"Type"})
10008 { # different types
10009 if($T1->{"Type"} eq "Class"
10010 and $T2->{"Type"} eq "Struct")
10011 { # "class" to "struct"
10012 return 0;
10013 }
10014 elsif($T2->{"Type"} eq "Class"
10015 and $T1->{"Type"} eq "Struct")
10016 { # "struct" to "class"
10017 return 0;
10018 }
10019 else
10020 { # "class" to "enum"
10021 # "union" to "class"
10022 # ...
10023 return 1;
10024 }
10025 }
10026 return 0;
10027}
10028
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040010029sub mergeTypes($$$)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010030{
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040010031 my ($Type1_Id, $Type2_Id, $Level) = @_;
10032 return () if(not $Type1_Id or not $Type2_Id);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010033 my (%Sub_SubProblems, %SubProblems) = ();
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040010034 if($Cache{"mergeTypes"}{$Level}{$Type1_Id}{$Type2_Id})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010035 { # already merged
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040010036 return %{$Cache{"mergeTypes"}{$Level}{$Type1_Id}{$Type2_Id}};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010037 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040010038 my %Type1 = get_Type($Type1_Id, 1);
10039 my %Type2 = get_Type($Type2_Id, 2);
Andrey Ponomarenko16934472012-03-29 15:37:04 +040010040 if(not $Type1{"Name"} or not $Type2{"Name"}) {
10041 return ();
10042 }
10043 $CheckedTypes{$Level}{$Type1{"Name"}}=1;
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040010044 my %Type1_Pure = get_PureType($Type1_Id, 1);
10045 my %Type2_Pure = get_PureType($Type2_Id, 2);
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040010046 $CheckedTypes{$Level}{$Type1_Pure{"Name"}}=1;
Andrey Ponomarenko85043792012-05-14 16:48:07 +040010047 if(not $Type1_Pure{"Size"} or not $Type2_Pure{"Size"})
10048 { # including a case when "class Class { ... };" changed to "class Class;"
10049 return ();
10050 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040010051 if(isRecurType($Type1_Pure{"Tid"}, $Type2_Pure{"Tid"}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010052 { # skip recursive declarations
10053 return ();
10054 }
10055 return () if(not $Type1_Pure{"Name"} or not $Type2_Pure{"Name"});
10056 return () if($SkipTypes{1}{$Type1_Pure{"Name"}});
10057 return () if($SkipTypes{1}{$Type1{"Name"}});
10058
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040010059 my %Typedef_1 = goToFirst($Type1{"Tid"}, 1, "Typedef");
10060 my %Typedef_2 = goToFirst($Type2{"Tid"}, 2, "Typedef");
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040010061 if(not $UseOldDumps and %Typedef_1 and %Typedef_2
10062 and $Typedef_1{"Type"} eq "Typedef" and $Typedef_2{"Type"} eq "Typedef"
10063 and $Typedef_1{"Name"} eq $Typedef_2{"Name"})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010064 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040010065 my %Base_1 = get_OneStep_BaseType($Typedef_1{"Tid"}, 1);
10066 my %Base_2 = get_OneStep_BaseType($Typedef_2{"Tid"}, 2);
Andrey Ponomarenko85043792012-05-14 16:48:07 +040010067 if($Base_1{"Name"} ne $Base_2{"Name"})
10068 {
10069 if(differentDumps("G")
10070 or differentDumps("V"))
10071 { # different GCC versions or different dumps
10072 $Base_1{"Name"} = uncover_typedefs($Base_1{"Name"}, 1);
10073 $Base_2{"Name"} = uncover_typedefs($Base_2{"Name"}, 2);
10074 # std::__va_list and __va_list
10075 $Base_1{"Name"}=~s/\A(\w+::)+//;
10076 $Base_2{"Name"}=~s/\A(\w+::)+//;
10077 $Base_1{"Name"} = formatName($Base_1{"Name"});
10078 $Base_2{"Name"} = formatName($Base_2{"Name"});
10079 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010080 }
10081 if($Base_1{"Name"}!~/anon\-/ and $Base_2{"Name"}!~/anon\-/
10082 and $Base_1{"Name"} ne $Base_2{"Name"})
10083 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040010084 if($Level eq "Binary"
10085 and $Type1{"Size"} ne $Type2{"Size"})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010086 {
10087 %{$SubProblems{"DataType_Size"}{$Typedef_1{"Name"}}}=(
10088 "Target"=>$Typedef_1{"Name"},
10089 "Type_Name"=>$Typedef_1{"Name"},
10090 "Type_Type"=>"Typedef",
10091 "Old_Size"=>$Type1{"Size"}*$BYTE_SIZE,
10092 "New_Size"=>$Type2{"Size"}*$BYTE_SIZE );
10093 }
10094 %{$SubProblems{"Typedef_BaseType"}{$Typedef_1{"Name"}}}=(
10095 "Target"=>$Typedef_1{"Name"},
10096 "Type_Name"=>$Typedef_1{"Name"},
10097 "Type_Type"=>"Typedef",
10098 "Old_Value"=>$Base_1{"Name"},
10099 "New_Value"=>$Base_2{"Name"} );
10100 }
10101 }
10102 if(nonComparable(\%Type1_Pure, \%Type2_Pure))
10103 { # different types (reported in detectTypeChange(...))
10104 if($Type1_Pure{"Name"} eq $Type2_Pure{"Name"}
10105 and $Type1_Pure{"Type"} ne $Type2_Pure{"Type"}
10106 and $Type1_Pure{"Type"}!~/Intrinsic|Pointer|Ref|Typedef/)
10107 { # different type of the type
10108 %{$SubProblems{"DataType_Type"}{$Type1_Pure{"Name"}}}=(
10109 "Target"=>$Type1_Pure{"Name"},
10110 "Type_Name"=>$Type1_Pure{"Name"},
10111 "Type_Type"=>$Type1_Pure{"Type"},
10112 "Old_Value"=>lc($Type1_Pure{"Type"}),
10113 "New_Value"=>lc($Type2_Pure{"Type"}) );
10114 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040010115 %{$Cache{"mergeTypes"}{$Level}{$Type1_Id}{$Type2_Id}} = %SubProblems;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010116 return %SubProblems;
10117 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040010118 pushType($Type1_Pure{"Tid"}, $Type2_Pure{"Tid"});
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010119 if(($Type1_Pure{"Name"} eq $Type2_Pure{"Name"}
10120 or (isAnon($Type1_Pure{"Name"}) and isAnon($Type2_Pure{"Name"})))
10121 and $Type1_Pure{"Type"}=~/\A(Struct|Class|Union)\Z/)
10122 { # checking size
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040010123 if($Level eq "Binary"
10124 and $Type1_Pure{"Size"} ne $Type2_Pure{"Size"})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010125 {
10126 my $ProblemKind = "DataType_Size";
10127 if($Type1_Pure{"Type"} eq "Class"
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040010128 and keys(%{$ClassMethods{$Level}{1}{$Type1_Pure{"Name"}}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010129 {
10130 if(isCopyingClass($Type1_Pure{"Tid"}, 1)) {
10131 $ProblemKind = "Size_Of_Copying_Class";
10132 }
10133 elsif($AllocableClass{1}{$Type1_Pure{"Name"}})
10134 {
10135 if(int($Type2_Pure{"Size"})>int($Type1_Pure{"Size"})) {
10136 $ProblemKind = "Size_Of_Allocable_Class_Increased";
10137 }
10138 else {
10139 # descreased size of allocable class
10140 # it has no special effects
10141 }
10142 }
10143 }
10144 %{$SubProblems{$ProblemKind}{$Type1_Pure{"Name"}}}=(
10145 "Target"=>$Type1_Pure{"Name"},
10146 "Type_Name"=>$Type1_Pure{"Name"},
10147 "Type_Type"=>$Type1_Pure{"Type"},
10148 "Old_Size"=>$Type1_Pure{"Size"}*$BYTE_SIZE,
10149 "New_Size"=>$Type2_Pure{"Size"}*$BYTE_SIZE,
10150 "InitialType_Type"=>$Type1_Pure{"Type"} );
10151 }
10152 }
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040010153 if(defined $Type1_Pure{"BaseType"} and $Type1_Pure{"BaseType"}{"Tid"}
10154 and defined $Type2_Pure{"BaseType"} and $Type2_Pure{"BaseType"}{"Tid"})
10155 { # checking base types
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040010156 %Sub_SubProblems = mergeTypes($Type1_Pure{"BaseType"}{"Tid"}, $Type2_Pure{"BaseType"}{"Tid"}, $Level);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010157 foreach my $Sub_SubProblemType (keys(%Sub_SubProblems))
10158 {
10159 foreach my $Sub_SubLocation (keys(%{$Sub_SubProblems{$Sub_SubProblemType}}))
10160 {
10161 foreach my $Attr (keys(%{$Sub_SubProblems{$Sub_SubProblemType}{$Sub_SubLocation}})) {
10162 $SubProblems{$Sub_SubProblemType}{$Sub_SubLocation}{$Attr} = $Sub_SubProblems{$Sub_SubProblemType}{$Sub_SubLocation}{$Attr};
10163 }
10164 $SubProblems{$Sub_SubProblemType}{$Sub_SubLocation}{"InitialType_Type"} = $Type1_Pure{"Type"};
10165 }
10166 }
10167 }
10168 my (%AddedField, %RemovedField, %RenamedField, %RenamedField_Rev, %RelatedField, %RelatedField_Rev) = ();
10169 my %NameToPosA = map {$Type1_Pure{"Memb"}{$_}{"name"}=>$_} keys(%{$Type1_Pure{"Memb"}});
10170 my %NameToPosB = map {$Type2_Pure{"Memb"}{$_}{"name"}=>$_} keys(%{$Type2_Pure{"Memb"}});
10171 foreach my $Member_Pos (sort {int($a) <=> int($b)} keys(%{$Type1_Pure{"Memb"}}))
10172 { # detect removed and renamed fields
10173 my $Member_Name = $Type1_Pure{"Memb"}{$Member_Pos}{"name"};
10174 next if(not $Member_Name);
10175 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);
10176 if($MemberPair_Pos eq "lost")
10177 {
10178 if($Type2_Pure{"Type"}=~/\A(Struct|Class|Union)\Z/)
10179 {
10180 if(isUnnamed($Member_Name))
10181 { # support for old-version dumps
10182 # unnamed fields have been introduced in the ACC 1.23 (dump 2.1 format)
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040010183 if(not checkDump(2, "2.1")) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010184 next;
10185 }
10186 }
10187 if(my $RenamedTo = isRenamed($Member_Pos, \%Type1_Pure, 1, \%Type2_Pure, 2))
10188 { # renamed
10189 $RenamedField{$Member_Pos}=$RenamedTo;
10190 $RenamedField_Rev{$NameToPosB{$RenamedTo}}=$Member_Name;
10191 }
10192 else
10193 { # removed
10194 $RemovedField{$Member_Pos}=1;
10195 }
10196 }
10197 elsif($Type1_Pure{"Type"} eq "Enum")
10198 {
10199 my $Member_Value1 = $Type1_Pure{"Memb"}{$Member_Pos}{"value"};
10200 next if($Member_Value1 eq "");
10201 $MemberPair_Pos = find_MemberPair_Pos_byVal($Member_Value1, \%Type2_Pure);
10202 if($MemberPair_Pos ne "lost")
10203 { # renamed
10204 my $RenamedTo = $Type2_Pure{"Memb"}{$MemberPair_Pos}{"name"};
10205 my $MemberPair_Pos_Rev = find_MemberPair_Pos_byName($RenamedTo, \%Type1_Pure);
10206 if($MemberPair_Pos_Rev eq "lost")
10207 {
10208 $RenamedField{$Member_Pos}=$RenamedTo;
10209 $RenamedField_Rev{$NameToPosB{$RenamedTo}}=$Member_Name;
10210 }
10211 else {
10212 $RemovedField{$Member_Pos}=1;
10213 }
10214 }
10215 else
10216 { # removed
10217 $RemovedField{$Member_Pos}=1;
10218 }
10219 }
10220 }
10221 else
10222 { # related
10223 $RelatedField{$Member_Pos} = $MemberPair_Pos;
10224 $RelatedField_Rev{$MemberPair_Pos} = $Member_Pos;
10225 }
10226 }
10227 foreach my $Member_Pos (sort {int($a) <=> int($b)} keys(%{$Type2_Pure{"Memb"}}))
10228 { # detect added fields
10229 my $Member_Name = $Type2_Pure{"Memb"}{$Member_Pos}{"name"};
10230 next if(not $Member_Name);
10231 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);
10232 if($MemberPair_Pos eq "lost")
10233 {
10234 if(isUnnamed($Member_Name))
10235 { # support for old-version dumps
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040010236 # unnamed fields have been introduced in the ACC 1.23 (dump 2.1 format)
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040010237 if(not checkDump(1, "2.1")) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010238 next;
10239 }
10240 }
10241 if($Type2_Pure{"Type"}=~/\A(Struct|Class|Union|Enum)\Z/)
10242 {
10243 if(not $RenamedField_Rev{$Member_Pos})
10244 { # added
10245 $AddedField{$Member_Pos}=1;
10246 }
10247 }
10248 }
10249 }
10250 if($Type2_Pure{"Type"}=~/\A(Struct|Class)\Z/)
10251 { # detect moved fields
10252 my (%RelPos, %RelPosName, %AbsPos) = ();
10253 my $Pos = 0;
10254 foreach my $Member_Pos (sort {int($a) <=> int($b)} keys(%{$Type1_Pure{"Memb"}}))
10255 { # relative positions in 1st version
10256 my $Member_Name = $Type1_Pure{"Memb"}{$Member_Pos}{"name"};
10257 next if(not $Member_Name);
10258 if(not $RemovedField{$Member_Pos})
10259 { # old type without removed fields
10260 $RelPos{1}{$Member_Name}=$Pos;
10261 $RelPosName{1}{$Pos} = $Member_Name;
10262 $AbsPos{1}{$Pos++} = $Member_Pos;
10263 }
10264 }
10265 $Pos = 0;
10266 foreach my $Member_Pos (sort {int($a) <=> int($b)} keys(%{$Type2_Pure{"Memb"}}))
10267 { # relative positions in 2nd version
10268 my $Member_Name = $Type2_Pure{"Memb"}{$Member_Pos}{"name"};
10269 next if(not $Member_Name);
10270 if(not $AddedField{$Member_Pos})
10271 { # new type without added fields
10272 $RelPos{2}{$Member_Name}=$Pos;
10273 $RelPosName{2}{$Pos} = $Member_Name;
10274 $AbsPos{2}{$Pos++} = $Member_Pos;
10275 }
10276 }
10277 foreach my $Member_Name (keys(%{$RelPos{1}}))
10278 {
10279 my $RPos1 = $RelPos{1}{$Member_Name};
10280 my $AbsPos1 = $NameToPosA{$Member_Name};
10281 my $Member_Name2 = $Member_Name;
10282 if(my $RenamedTo = $RenamedField{$AbsPos1})
10283 { # renamed
10284 $Member_Name2 = $RenamedTo;
10285 }
10286 my $RPos2 = $RelPos{2}{$Member_Name2};
10287 if($RPos2 ne "" and $RPos1 ne $RPos2)
10288 { # different relative positions
10289 my $AbsPos2 = $NameToPosB{$Member_Name2};
10290 if($AbsPos1 ne $AbsPos2)
10291 { # different absolute positions
10292 my $ProblemType = "Moved_Field";
10293 if(not isPublic(\%Type1_Pure, $AbsPos1))
10294 { # may change layout and size of type
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040010295 if($Level eq "Source") {
10296 next;
10297 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010298 $ProblemType = "Moved_Private_Field";
10299 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040010300 if($Level eq "Binary"
10301 and $Type1_Pure{"Size"} ne $Type2_Pure{"Size"})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010302 { # affected size
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040010303 my $MemSize1 = $TypeInfo{1}{$Type1_Pure{"Memb"}{$AbsPos1}{"type"}}{"Size"};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010304 my $MovedAbsPos = $AbsPos{1}{$RPos2};
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040010305 my $MemSize2 = $TypeInfo{1}{$Type1_Pure{"Memb"}{$MovedAbsPos}{"type"}}{"Size"};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010306 if($MemSize1 ne $MemSize2) {
10307 $ProblemType .= "_And_Size";
10308 }
10309 }
10310 if($ProblemType eq "Moved_Private_Field") {
10311 next;
10312 }
10313 %{$SubProblems{$ProblemType}{$Member_Name}}=(
10314 "Target"=>$Member_Name,
10315 "Type_Name"=>$Type1_Pure{"Name"},
10316 "Type_Type"=>$Type1_Pure{"Type"},
10317 "Old_Value"=>$RPos1,
10318 "New_Value"=>$RPos2 );
10319 }
10320 }
10321 }
10322 }
10323 foreach my $Member_Pos (sort {int($a) <=> int($b)} keys(%{$Type1_Pure{"Memb"}}))
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040010324 { # check older fields, public and private
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010325 my $Member_Name = $Type1_Pure{"Memb"}{$Member_Pos}{"name"};
10326 next if(not $Member_Name);
10327 if(my $RenamedTo = $RenamedField{$Member_Pos})
10328 { # renamed
10329 if($Type2_Pure{"Type"}=~/\A(Struct|Class|Union)\Z/)
10330 {
10331 if(isPublic(\%Type1_Pure, $Member_Pos))
10332 {
10333 %{$SubProblems{"Renamed_Field"}{$Member_Name}}=(
10334 "Target"=>$Member_Name,
10335 "Type_Name"=>$Type1_Pure{"Name"},
10336 "Type_Type"=>$Type1_Pure{"Type"},
10337 "Old_Value"=>$Member_Name,
10338 "New_Value"=>$RenamedTo );
10339 }
10340 }
10341 elsif($Type1_Pure{"Type"} eq "Enum")
10342 {
10343 %{$SubProblems{"Enum_Member_Name"}{$Type1_Pure{"Memb"}{$Member_Pos}{"value"}}}=(
10344 "Target"=>$Type1_Pure{"Memb"}{$Member_Pos}{"value"},
10345 "Type_Name"=>$Type1_Pure{"Name"},
10346 "Type_Type"=>$Type1_Pure{"Type"},
10347 "Old_Value"=>$Member_Name,
10348 "New_Value"=>$RenamedTo );
10349 }
10350 }
10351 elsif($RemovedField{$Member_Pos})
10352 { # removed
10353 if($Type2_Pure{"Type"}=~/\A(Struct|Class)\Z/)
10354 {
10355 my $ProblemType = "Removed_Field";
10356 if(not isPublic(\%Type1_Pure, $Member_Pos)
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040010357 or isUnnamed($Member_Name))
10358 {
10359 if($Level eq "Source") {
10360 next;
10361 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010362 $ProblemType = "Removed_Private_Field";
10363 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040010364 if($Level eq "Binary"
10365 and not isMemPadded($Member_Pos, -1, \%Type1_Pure, \%RemovedField, 1))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010366 {
10367 if(my $MNum = isAccessible(\%Type1_Pure, \%RemovedField, $Member_Pos+1, -1))
10368 { # affected fields
10369 if(getOffset($MNum-1, \%Type1_Pure, 1)!=getOffset($RelatedField{$MNum-1}, \%Type2_Pure, 2))
10370 { # changed offset
10371 $ProblemType .= "_And_Layout";
10372 }
10373 }
10374 if($Type1_Pure{"Size"} ne $Type2_Pure{"Size"})
10375 { # affected size
10376 $ProblemType .= "_And_Size";
10377 }
10378 }
10379 if($ProblemType eq "Removed_Private_Field") {
10380 next;
10381 }
10382 %{$SubProblems{$ProblemType}{$Member_Name}}=(
10383 "Target"=>$Member_Name,
10384 "Type_Name"=>$Type1_Pure{"Name"},
10385 "Type_Type"=>$Type1_Pure{"Type"} );
10386 }
10387 elsif($Type2_Pure{"Type"} eq "Union")
10388 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040010389 if($Level eq "Binary"
10390 and $Type1_Pure{"Size"} ne $Type2_Pure{"Size"})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010391 {
10392 %{$SubProblems{"Removed_Union_Field_And_Size"}{$Member_Name}}=(
10393 "Target"=>$Member_Name,
10394 "Type_Name"=>$Type1_Pure{"Name"},
10395 "Type_Type"=>$Type1_Pure{"Type"} );
10396 }
10397 else
10398 {
10399 %{$SubProblems{"Removed_Union_Field"}{$Member_Name}}=(
10400 "Target"=>$Member_Name,
10401 "Type_Name"=>$Type1_Pure{"Name"},
10402 "Type_Type"=>$Type1_Pure{"Type"} );
10403 }
10404 }
10405 elsif($Type1_Pure{"Type"} eq "Enum")
10406 {
10407 %{$SubProblems{"Enum_Member_Removed"}{$Member_Name}}=(
10408 "Target"=>$Member_Name,
10409 "Type_Name"=>$Type1_Pure{"Name"},
10410 "Type_Type"=>$Type1_Pure{"Type"},
10411 "Old_Value"=>$Member_Name );
10412 }
10413 }
10414 else
10415 { # changed
10416 my $MemberPair_Pos = $RelatedField{$Member_Pos};
10417 if($Type1_Pure{"Type"} eq "Enum")
10418 {
10419 my $Member_Value1 = $Type1_Pure{"Memb"}{$Member_Pos}{"value"};
10420 next if($Member_Value1 eq "");
10421 my $Member_Value2 = $Type2_Pure{"Memb"}{$MemberPair_Pos}{"value"};
10422 next if($Member_Value2 eq "");
10423 if($Member_Value1 ne $Member_Value2)
10424 {
10425 my $ProblemType = "Enum_Member_Value";
10426 if(isLastElem($Member_Pos, \%Type1_Pure)) {
10427 $ProblemType = "Enum_Last_Member_Value";
10428 }
10429 %{$SubProblems{$ProblemType}{$Member_Name}}=(
10430 "Target"=>$Member_Name,
10431 "Type_Name"=>$Type1_Pure{"Name"},
10432 "Type_Type"=>$Type1_Pure{"Type"},
10433 "Old_Value"=>$Member_Value1,
10434 "New_Value"=>$Member_Value2 );
10435 }
10436 }
10437 elsif($Type2_Pure{"Type"}=~/\A(Struct|Class|Union)\Z/)
10438 {
10439 my $MemberType1_Id = $Type1_Pure{"Memb"}{$Member_Pos}{"type"};
10440 my $MemberType2_Id = $Type2_Pure{"Memb"}{$MemberPair_Pos}{"type"};
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040010441 my $SizeV1 = $TypeInfo{1}{$MemberType1_Id}{"Size"}*$BYTE_SIZE;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010442 if(my $BSize1 = $Type1_Pure{"Memb"}{$Member_Pos}{"bitfield"}) {
10443 $SizeV1 = $BSize1;
10444 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040010445 my $SizeV2 = $TypeInfo{2}{$MemberType2_Id}{"Size"}*$BYTE_SIZE;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010446 if(my $BSize2 = $Type2_Pure{"Memb"}{$MemberPair_Pos}{"bitfield"}) {
10447 $SizeV2 = $BSize2;
10448 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040010449 my $MemberType1_Name = $TypeInfo{1}{$MemberType1_Id}{"Name"};
10450 my $MemberType2_Name = $TypeInfo{2}{$MemberType2_Id}{"Name"};
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040010451 if($Level eq "Binary"
10452 and $SizeV1 ne $SizeV2)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010453 {
10454 if($MemberType1_Name eq $MemberType2_Name or (isAnon($MemberType1_Name) and isAnon($MemberType2_Name))
10455 or ($Type1_Pure{"Memb"}{$Member_Pos}{"bitfield"} and $Type2_Pure{"Memb"}{$MemberPair_Pos}{"bitfield"}))
10456 { # field size change (including anon-structures and unions)
10457 # - same types
10458 # - unnamed types
10459 # - bitfields
10460 my $ProblemType = "Field_Size";
10461 if(not isPublic(\%Type1_Pure, $Member_Pos)
10462 or isUnnamed($Member_Name))
10463 { # should not be accessed by applications, goes to "Low Severity"
10464 # example: "abidata" members in GStreamer types
10465 $ProblemType = "Private_".$ProblemType;
10466 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040010467 if(not isMemPadded($Member_Pos, $TypeInfo{2}{$MemberType2_Id}{"Size"}*$BYTE_SIZE, \%Type1_Pure, \%RemovedField, 1))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010468 { # check an effect
10469 if(my $MNum = isAccessible(\%Type1_Pure, \%RemovedField, $Member_Pos+1, -1))
10470 { # public fields after the current
10471 if(getOffset($MNum-1, \%Type1_Pure, 1)!=getOffset($RelatedField{$MNum-1}, \%Type2_Pure, 2))
10472 { # changed offset
10473 $ProblemType .= "_And_Layout";
10474 }
10475 }
10476 if($Type1_Pure{"Size"} ne $Type2_Pure{"Size"}) {
10477 $ProblemType .= "_And_Type_Size";
10478 }
10479 }
10480 if($ProblemType eq "Private_Field_Size")
10481 { # private field size with no effect
10482 $ProblemType = "";
10483 }
10484 if($ProblemType)
10485 { # register a problem
10486 %{$SubProblems{$ProblemType}{$Member_Name}}=(
10487 "Target"=>$Member_Name,
10488 "Type_Name"=>$Type1_Pure{"Name"},
10489 "Type_Type"=>$Type1_Pure{"Type"},
10490 "Old_Size"=>$SizeV1,
10491 "New_Size"=>$SizeV2);
10492 }
10493 }
10494 }
10495 if($Type1_Pure{"Memb"}{$Member_Pos}{"bitfield"}
10496 or $Type2_Pure{"Memb"}{$MemberPair_Pos}{"bitfield"})
10497 { # do NOT check bitfield type changes
10498 next;
10499 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040010500 if(checkDump(1, "2.13") and checkDump(2, "2.13"))
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040010501 {
10502 if(not $Type1_Pure{"Memb"}{$Member_Pos}{"mutable"}
10503 and $Type2_Pure{"Memb"}{$MemberPair_Pos}{"mutable"})
10504 {
10505 %{$SubProblems{"Field_Became_Mutable"}{$Member_Name}}=(
10506 "Target"=>$Member_Name,
10507 "Type_Name"=>$Type1_Pure{"Name"},
10508 "Type_Type"=>$Type1_Pure{"Type"});
10509 }
10510 elsif($Type1_Pure{"Memb"}{$Member_Pos}{"mutable"}
10511 and not $Type2_Pure{"Memb"}{$MemberPair_Pos}{"mutable"})
10512 {
10513 %{$SubProblems{"Field_Became_NonMutable"}{$Member_Name}}=(
10514 "Target"=>$Member_Name,
10515 "Type_Name"=>$Type1_Pure{"Name"},
10516 "Type_Type"=>$Type1_Pure{"Type"});
10517 }
10518 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040010519 %Sub_SubProblems = detectTypeChange($MemberType1_Id, $MemberType2_Id, "Field", $Level);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010520 foreach my $ProblemType (keys(%Sub_SubProblems))
10521 {
10522 my $Old_Value = $Sub_SubProblems{$ProblemType}{"Old_Value"};
10523 my $New_Value = $Sub_SubProblems{$ProblemType}{"New_Value"};
10524 if($ProblemType eq "Field_Type"
10525 or $ProblemType eq "Field_Type_And_Size")
10526 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040010527 if(checkDump(1, "2.6") and checkDump(2, "2.6"))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010528 {
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040010529 if(my $RA = addedQual($Old_Value, $New_Value, "volatile"))
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040010530 {
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040010531 %{$Sub_SubProblems{"Field_Became_Volatile"}} = %{$Sub_SubProblems{$ProblemType}};
10532 if($Level eq "Source"
10533 and cmpBTypes($Old_Value, $New_Value, 1, 2)) {
10534 delete($Sub_SubProblems{$ProblemType});
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040010535 }
10536 }
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040010537 elsif(my $RR = removedQual($Old_Value, $New_Value, "volatile"))
10538 {
10539 %{$Sub_SubProblems{"Field_Became_NonVolatile"}} = %{$Sub_SubProblems{$ProblemType}};
10540 if($Level eq "Source"
10541 and cmpBTypes($Old_Value, $New_Value, 1, 2)) {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040010542 delete($Sub_SubProblems{$ProblemType});
10543 }
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040010544 }
10545 }
10546 if(my $RA = addedQual($Old_Value, $New_Value, "const"))
10547 {
10548 if($RA==2) {
10549 %{$Sub_SubProblems{"Field_Added_Const"}} = %{$Sub_SubProblems{$ProblemType}};
10550 }
10551 else {
10552 %{$Sub_SubProblems{"Field_Became_Const"}} = %{$Sub_SubProblems{$ProblemType}};
10553 }
10554 if($Level eq "Source"
10555 and cmpBTypes($Old_Value, $New_Value, 1, 2)) {
10556 delete($Sub_SubProblems{$ProblemType});
10557 }
10558 }
10559 elsif(my $RR = removedQual($Old_Value, $New_Value, "const"))
10560 {
10561 if($RR==2) {
10562 %{$Sub_SubProblems{"Field_Removed_Const"}} = %{$Sub_SubProblems{$ProblemType}};
10563 }
10564 else {
10565 %{$Sub_SubProblems{"Field_Became_NonConst"}} = %{$Sub_SubProblems{$ProblemType}};
10566 }
10567 if($Level eq "Source"
10568 and cmpBTypes($Old_Value, $New_Value, 1, 2)) {
10569 delete($Sub_SubProblems{$ProblemType});
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010570 }
10571 }
10572 }
10573 }
10574 foreach my $ProblemType (keys(%Sub_SubProblems))
10575 {
10576 my $ProblemType_Init = $ProblemType;
10577 if($ProblemType eq "Field_Type_And_Size")
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040010578 { # Binary
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010579 if(not isPublic(\%Type1_Pure, $Member_Pos)
10580 or isUnnamed($Member_Name)) {
10581 $ProblemType = "Private_".$ProblemType;
10582 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040010583 if(not isMemPadded($Member_Pos, $TypeInfo{2}{$MemberType2_Id}{"Size"}*$BYTE_SIZE, \%Type1_Pure, \%RemovedField, 1))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010584 { # check an effect
10585 if(my $MNum = isAccessible(\%Type1_Pure, \%RemovedField, $Member_Pos+1, -1))
10586 { # public fields after the current
10587 if(getOffset($MNum-1, \%Type1_Pure, 1)!=getOffset($RelatedField{$MNum-1}, \%Type2_Pure, 2))
10588 { # changed offset
10589 $ProblemType .= "_And_Layout";
10590 }
10591 }
10592 if($Type1_Pure{"Size"} ne $Type2_Pure{"Size"}) {
10593 $ProblemType .= "_And_Type_Size";
10594 }
10595 }
10596 }
10597 else
10598 {
10599 if(not isPublic(\%Type1_Pure, $Member_Pos)
10600 or isUnnamed($Member_Name)) {
10601 next;
10602 }
10603 }
10604 if($ProblemType eq "Private_Field_Type_And_Size")
10605 { # private field change with no effect
10606 next;
10607 }
10608 %{$SubProblems{$ProblemType}{$Member_Name}}=(
10609 "Target"=>$Member_Name,
10610 "Type_Name"=>$Type1_Pure{"Name"},
10611 "Type_Type"=>$Type1_Pure{"Type"} );
10612 foreach my $Attr (keys(%{$Sub_SubProblems{$ProblemType_Init}}))
10613 { # other properties
10614 $SubProblems{$ProblemType}{$Member_Name}{$Attr} = $Sub_SubProblems{$ProblemType_Init}{$Attr};
10615 }
10616 }
10617 if(not isPublic(\%Type1_Pure, $Member_Pos))
10618 { # do NOT check internal type changes
10619 next;
10620 }
10621 if($MemberType1_Id and $MemberType2_Id)
10622 {# checking member type changes (replace)
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040010623 %Sub_SubProblems = mergeTypes($MemberType1_Id, $MemberType2_Id, $Level);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010624 foreach my $Sub_SubProblemType (keys(%Sub_SubProblems))
10625 {
10626 foreach my $Sub_SubLocation (keys(%{$Sub_SubProblems{$Sub_SubProblemType}}))
10627 {
10628 my $NewLocation = ($Sub_SubLocation)?$Member_Name."->".$Sub_SubLocation:$Member_Name;
10629 $SubProblems{$Sub_SubProblemType}{$NewLocation}{"IsInTypeInternals"}=1;
10630 foreach my $Attr (keys(%{$Sub_SubProblems{$Sub_SubProblemType}{$Sub_SubLocation}})) {
10631 $SubProblems{$Sub_SubProblemType}{$NewLocation}{$Attr} = $Sub_SubProblems{$Sub_SubProblemType}{$Sub_SubLocation}{$Attr};
10632 }
10633 if($Sub_SubLocation!~/\-\>/) {
10634 $SubProblems{$Sub_SubProblemType}{$NewLocation}{"Start_Type_Name"} = $MemberType1_Name;
10635 }
10636 }
10637 }
10638 }
10639 }
10640 }
10641 }
10642 foreach my $Member_Pos (sort {int($a) <=> int($b)} keys(%{$Type2_Pure{"Memb"}}))
10643 { # checking added members, public and private
10644 my $Member_Name = $Type2_Pure{"Memb"}{$Member_Pos}{"name"};
10645 next if(not $Member_Name);
10646 if($AddedField{$Member_Pos})
10647 { # added
10648 if($Type2_Pure{"Type"}=~/\A(Struct|Class)\Z/)
10649 {
10650 my $ProblemType = "Added_Field";
10651 if(not isPublic(\%Type2_Pure, $Member_Pos)
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040010652 or isUnnamed($Member_Name))
10653 {
10654 if($Level eq "Source") {
10655 next;
10656 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010657 $ProblemType = "Added_Private_Field";
10658 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040010659 if($Level eq "Binary"
10660 and not isMemPadded($Member_Pos, -1, \%Type2_Pure, \%AddedField, 2))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010661 {
10662 if(my $MNum = isAccessible(\%Type2_Pure, \%AddedField, $Member_Pos, -1))
10663 { # public fields after the current
10664 if(getOffset($MNum-1, \%Type2_Pure, 2)!=getOffset($RelatedField_Rev{$MNum-1}, \%Type1_Pure, 1))
10665 { # changed offset
10666 $ProblemType .= "_And_Layout";
10667 }
10668 }
10669 if($Type1_Pure{"Size"} ne $Type2_Pure{"Size"}) {
10670 $ProblemType .= "_And_Size";
10671 }
10672 }
10673 if($ProblemType eq "Added_Private_Field")
10674 { # skip added private fields
10675 next;
10676 }
10677 %{$SubProblems{$ProblemType}{$Member_Name}}=(
10678 "Target"=>$Member_Name,
10679 "Type_Name"=>$Type1_Pure{"Name"},
10680 "Type_Type"=>$Type1_Pure{"Type"} );
10681 }
10682 elsif($Type2_Pure{"Type"} eq "Union")
10683 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040010684 if($Level eq "Binary"
10685 and $Type1_Pure{"Size"} ne $Type2_Pure{"Size"})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010686 {
10687 %{$SubProblems{"Added_Union_Field_And_Size"}{$Member_Name}}=(
10688 "Target"=>$Member_Name,
10689 "Type_Name"=>$Type1_Pure{"Name"},
10690 "Type_Type"=>$Type1_Pure{"Type"} );
10691 }
10692 else
10693 {
10694 %{$SubProblems{"Added_Union_Field"}{$Member_Name}}=(
10695 "Target"=>$Member_Name,
10696 "Type_Name"=>$Type1_Pure{"Name"},
10697 "Type_Type"=>$Type1_Pure{"Type"} );
10698 }
10699 }
10700 elsif($Type2_Pure{"Type"} eq "Enum")
10701 {
10702 my $Member_Value = $Type2_Pure{"Memb"}{$Member_Pos}{"value"};
10703 next if($Member_Value eq "");
10704 %{$SubProblems{"Added_Enum_Member"}{$Member_Name}}=(
10705 "Target"=>$Member_Name,
10706 "Type_Name"=>$Type2_Pure{"Name"},
10707 "Type_Type"=>$Type2_Pure{"Type"},
10708 "New_Value"=>$Member_Value );
10709 }
10710 }
10711 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040010712 %{$Cache{"mergeTypes"}{$Level}{$Type1_Id}{$Type2_Id}} = %SubProblems;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010713 pop(@RecurTypes);
10714 return %SubProblems;
10715}
10716
10717sub isUnnamed($) {
10718 return $_[0]=~/\Aunnamed\d+\Z/;
10719}
10720
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040010721sub get_ShortType($$)
10722{
10723 my ($TypeId, $LibVersion) = @_;
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040010724 my $TypeName = $TypeInfo{$LibVersion}{$TypeId}{"Name"};
10725 if(my $NameSpace = $TypeInfo{$LibVersion}{$TypeId}{"NameSpace"}) {
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040010726 $TypeName=~s/\A$NameSpace\:\://g;
10727 }
10728 return $TypeName;
10729}
10730
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040010731sub goToFirst($$$)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010732{
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040010733 my ($TypeId, $LibVersion, $Type_Type) = @_;
Andrey Ponomarenko16934472012-03-29 15:37:04 +040010734 return () if(not $TypeId);
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040010735 if(defined $Cache{"goToFirst"}{$TypeId}{$LibVersion}{$Type_Type}) {
10736 return %{$Cache{"goToFirst"}{$TypeId}{$LibVersion}{$Type_Type}};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010737 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040010738 return () if(not $TypeInfo{$LibVersion}{$TypeId});
10739 my %Type = %{$TypeInfo{$LibVersion}{$TypeId}};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010740 return () if(not $Type{"Type"});
10741 if($Type{"Type"} ne $Type_Type)
10742 {
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040010743 return () if(not defined $Type{"BaseType"});
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040010744 return () if(not $Type{"BaseType"}{"Tid"});
10745 %Type = goToFirst($Type{"BaseType"}{"Tid"}, $LibVersion, $Type_Type);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010746 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040010747 $Cache{"goToFirst"}{$TypeId}{$LibVersion}{$Type_Type} = \%Type;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010748 return %Type;
10749}
10750
10751my %TypeSpecAttributes = (
10752 "Const" => 1,
10753 "Volatile" => 1,
10754 "ConstVolatile" => 1,
10755 "Restrict" => 1,
10756 "Typedef" => 1
10757);
10758
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040010759sub get_PureType($$)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010760{
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040010761 my ($TypeId, $LibVersion) = @_;
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040010762 return () if(not $TypeId);
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040010763 if(defined $Cache{"get_PureType"}{$TypeId}{$LibVersion}) {
10764 return %{$Cache{"get_PureType"}{$TypeId}{$LibVersion}};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010765 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040010766 return () if(not $TypeInfo{$LibVersion}{$TypeId});
10767 my %Type = %{$TypeInfo{$LibVersion}{$TypeId}};
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040010768 return %Type if(not defined $Type{"BaseType"});
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040010769 return %Type if(not $Type{"BaseType"}{"Tid"});
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010770 if($TypeSpecAttributes{$Type{"Type"}}) {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040010771 %Type = get_PureType($Type{"BaseType"}{"Tid"}, $LibVersion);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010772 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040010773 $Cache{"get_PureType"}{$TypeId}{$LibVersion} = \%Type;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010774 return %Type;
10775}
10776
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040010777sub get_PLevel($$)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010778{
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040010779 my ($TypeId, $LibVersion) = @_;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010780 return 0 if(not $TypeId);
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040010781 if(defined $Cache{"get_PLevel"}{$TypeId}{$LibVersion}) {
10782 return $Cache{"get_PLevel"}{$TypeId}{$LibVersion};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010783 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040010784 return 0 if(not $TypeInfo{$LibVersion}{$TypeId});
10785 my %Type = %{$TypeInfo{$LibVersion}{$TypeId}};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010786 return 1 if($Type{"Type"}=~/FuncPtr|MethodPtr|FieldPtr/);
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040010787 return 0 if(not defined $Type{"BaseType"});
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040010788 return 0 if(not $Type{"BaseType"}{"Tid"});
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010789 my $PointerLevel = 0;
10790 if($Type{"Type"} =~/Pointer|Ref|FuncPtr|MethodPtr|FieldPtr/) {
10791 $PointerLevel += 1;
10792 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040010793 $PointerLevel += get_PLevel($Type{"BaseType"}{"Tid"}, $LibVersion);
10794 $Cache{"get_PLevel"}{$TypeId}{$LibVersion} = $PointerLevel;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010795 return $PointerLevel;
10796}
10797
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040010798sub get_BaseType($$)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010799{
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040010800 my ($TypeId, $LibVersion) = @_;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010801 return () if(not $TypeId);
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040010802 if(defined $Cache{"get_BaseType"}{$TypeId}{$LibVersion}) {
10803 return %{$Cache{"get_BaseType"}{$TypeId}{$LibVersion}};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010804 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040010805 return () if(not $TypeInfo{$LibVersion}{$TypeId});
10806 my %Type = %{$TypeInfo{$LibVersion}{$TypeId}};
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040010807 return %Type if(not defined $Type{"BaseType"});
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040010808 return %Type if(not $Type{"BaseType"}{"Tid"});
10809 %Type = get_BaseType($Type{"BaseType"}{"Tid"}, $LibVersion);
10810 $Cache{"get_BaseType"}{$TypeId}{$LibVersion} = \%Type;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010811 return %Type;
10812}
10813
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040010814sub get_BaseTypeQual($$)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010815{
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040010816 my ($TypeId, $LibVersion) = @_;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010817 return "" if(not $TypeId);
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040010818 return "" if(not $TypeInfo{$LibVersion}{$TypeId});
10819 my %Type = %{$TypeInfo{$LibVersion}{$TypeId}};
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040010820 return "" if(not defined $Type{"BaseType"});
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040010821 return "" if(not $Type{"BaseType"}{"Tid"});
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010822 my $Qual = "";
10823 if($Type{"Type"} eq "Pointer") {
10824 $Qual .= "*";
10825 }
10826 elsif($Type{"Type"} eq "Ref") {
10827 $Qual .= "&";
10828 }
10829 elsif($Type{"Type"} eq "ConstVolatile") {
10830 $Qual .= "const volatile";
10831 }
10832 elsif($Type{"Type"} eq "Const"
10833 or $Type{"Type"} eq "Volatile"
10834 or $Type{"Type"} eq "Restrict") {
10835 $Qual .= lc($Type{"Type"});
10836 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040010837 my $BQual = get_BaseTypeQual($Type{"BaseType"}{"Tid"}, $LibVersion);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010838 return $BQual.$Qual;
10839}
10840
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040010841sub get_OneStep_BaseType($$)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010842{
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040010843 my ($TypeId, $LibVersion) = @_;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010844 return () if(not $TypeId);
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040010845 return () if(not $TypeInfo{$LibVersion}{$TypeId});
10846 my %Type = %{$TypeInfo{$LibVersion}{$TypeId}};
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040010847 return %Type if(not defined $Type{"BaseType"});
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040010848 return %Type if(not $Type{"BaseType"}{"Tid"});
10849 return get_Type($Type{"BaseType"}{"Tid"}, $LibVersion);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010850}
10851
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040010852sub get_Type($$)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010853{
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040010854 my ($TypeId, $LibVersion) = @_;
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040010855 return () if(not $TypeId);
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040010856 return () if(not $TypeInfo{$LibVersion}{$TypeId});
10857 return %{$TypeInfo{$LibVersion}{$TypeId}};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010858}
10859
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +040010860sub isPrivateData($)
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040010861{ # non-public global data
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010862 my $Symbol = $_[0];
10863 return ($Symbol=~/\A(_ZGV|_ZTI|_ZTS|_ZTT|_ZTV|_ZTC|_ZThn|_ZTv0_n)/);
10864}
10865
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040010866sub isTemplateInstance($$)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010867{
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040010868 my ($Symbol, $LibVersion) = @_;
10869 if($CheckObjectsOnly)
10870 {
10871 if($Symbol!~/\A(_Z|\?)/) {
10872 return 0;
10873 }
10874 if(my $Signature = $tr_name{$Symbol})
10875 {
10876 if(index($Signature,">")==-1) {
10877 return 0;
10878 }
10879 if(my $ShortName = substr($Signature, 0, find_center($Signature, "(")))
10880 {
10881 if($ShortName=~/<.+>/) {
10882 return 1;
10883 }
10884 }
10885 }
10886 }
10887 else
10888 {
10889 if(my $ClassId = $CompleteSignature{$LibVersion}{$Symbol}{"Class"})
10890 {
10891 if(my $ClassName = $TypeInfo{$LibVersion}{$ClassId}{"Name"})
10892 {
10893 if(index($ClassName,"<")!=-1) {
10894 return 1;
10895 }
10896 }
10897 }
10898 if(my $ShortName = $CompleteSignature{$LibVersion}{$Symbol}{"ShortName"})
10899 {
10900 if($ShortName=~/<.+>/) {
10901 return 1;
10902 }
10903 }
10904 }
10905 return 0;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010906}
10907
10908sub isTemplateSpec($$)
10909{
10910 my ($Symbol, $LibVersion) = @_;
10911 if(my $ClassId = $CompleteSignature{$LibVersion}{$Symbol}{"Class"})
10912 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040010913 if($TypeInfo{$LibVersion}{$ClassId}{"Spec"})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010914 { # class specialization
10915 return 1;
10916 }
10917 elsif($CompleteSignature{$LibVersion}{$Symbol}{"Spec"})
10918 { # method specialization
10919 return 1;
10920 }
10921 }
10922 return 0;
10923}
10924
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040010925sub symbolFilter($$$$)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010926{ # some special cases when the symbol cannot be imported
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040010927 my ($Symbol, $LibVersion, $Type, $Level) = @_;
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +040010928 if(isPrivateData($Symbol))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010929 { # non-public global data
10930 return 0;
10931 }
10932 if($CheckObjectsOnly) {
10933 return 0 if($Symbol=~/\A(_init|_fini)\Z/);
10934 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040010935 if($CheckHeadersOnly and not checkDump($LibVersion, "2.7"))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010936 { # support for old ABI dumps in --headers-only mode
10937 foreach my $Pos (keys(%{$CompleteSignature{$LibVersion}{$Symbol}{"Param"}}))
10938 {
10939 if(my $Pid = $CompleteSignature{$LibVersion}{$Symbol}{"Param"}{$Pos}{"type"})
10940 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040010941 my $PType = $TypeInfo{$LibVersion}{$Pid}{"Type"};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010942 if(not $PType or $PType eq "Unknown") {
10943 return 0;
10944 }
10945 }
10946 }
10947 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +040010948 if($Type=~/Affected/)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010949 {
10950 my $ClassId = $CompleteSignature{$LibVersion}{$Symbol}{"Class"};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010951 if($SkipSymbols{$LibVersion}{$Symbol})
10952 { # user defined symbols to ignore
10953 return 0;
10954 }
10955 my $NameSpace = $CompleteSignature{$LibVersion}{$Symbol}{"NameSpace"};
10956 if(not $NameSpace and $ClassId)
10957 { # class methods have no "NameSpace" attribute
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040010958 $NameSpace = $TypeInfo{$LibVersion}{$ClassId}{"NameSpace"};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010959 }
10960 if($NameSpace)
10961 { # user defined namespaces to ignore
10962 if($SkipNameSpaces{$LibVersion}{$NameSpace}) {
10963 return 0;
10964 }
10965 foreach my $NS (keys(%{$SkipNameSpaces{$LibVersion}}))
10966 { # nested namespaces
10967 if($NameSpace=~/\A\Q$NS\E(\:\:|\Z)/) {
10968 return 0;
10969 }
10970 }
10971 }
10972 if(my $Header = $CompleteSignature{$LibVersion}{$Symbol}{"Header"})
10973 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040010974 if(my $Skip = skipHeader($Header, $LibVersion))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010975 { # --skip-headers or <skip_headers> (not <skip_including>)
10976 if($Skip==1) {
10977 return 0;
10978 }
10979 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010980 }
10981 if($SymbolsListPath and not $SymbolsList{$Symbol})
10982 { # user defined symbols
10983 return 0;
10984 }
10985 if($AppPath and not $SymbolsList_App{$Symbol})
10986 { # user defined symbols (in application)
10987 return 0;
10988 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +040010989 if(not selectSymbol($Symbol, $CompleteSignature{$LibVersion}{$Symbol}, $Level, $LibVersion))
10990 { # non-target symbols
10991 return 0;
10992 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040010993 if($Level eq "Binary")
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010994 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040010995 if($CheckObjectsOnly)
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040010996 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040010997 if(isTemplateInstance($Symbol, $LibVersion)) {
10998 return 0;
10999 }
11000 }
11001 else
11002 {
11003 if($CompleteSignature{$LibVersion}{$Symbol}{"InLine"}
11004 or (isTemplateInstance($Symbol, $LibVersion) and not isTemplateSpec($Symbol, $LibVersion)))
11005 {
11006 if($ClassId and $CompleteSignature{$LibVersion}{$Symbol}{"Virt"})
11007 { # inline virtual methods
11008 if($Type=~/InlineVirt/) {
11009 return 1;
11010 }
11011 my $Allocable = (not isCopyingClass($ClassId, $LibVersion));
11012 if(not $Allocable)
11013 { # check bases
11014 foreach my $DCId (get_sub_classes($ClassId, $LibVersion, 1))
11015 {
11016 if(not isCopyingClass($DCId, $LibVersion))
11017 { # exists a derived class without default c-tor
11018 $Allocable=1;
11019 last;
11020 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011021 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011022 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040011023 if(not $Allocable) {
11024 return 0;
11025 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011026 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040011027 else
11028 { # inline non-virtual methods
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011029 return 0;
11030 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011031 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011032 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011033 }
11034 }
11035 return 1;
11036}
11037
11038sub mergeImpl()
11039{
11040 my $DiffCmd = get_CmdPath("diff");
11041 if(not $DiffCmd) {
11042 exitStatus("Not_Found", "can't find \"diff\"");
11043 }
11044 foreach my $Interface (sort keys(%{$Symbol_Library{1}}))
11045 { # implementation changes
11046 next if($CompleteSignature{1}{$Interface}{"Private"});
11047 next if(not $CompleteSignature{1}{$Interface}{"Header"} and not $CheckObjectsOnly);
11048 next if(not $Symbol_Library{2}{$Interface} and not $Symbol_Library{2}{$SymVer{2}{$Interface}});
Andrey Ponomarenko85043792012-05-14 16:48:07 +040011049 if(not symbolFilter($Interface, 1, "Affected", "Binary")) {
11050 next;
11051 }
Andrey Ponomarenko16934472012-03-29 15:37:04 +040011052 my $Impl1 = canonifyImpl($Interface_Impl{1}{$Interface});
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011053 next if(not $Impl1);
Andrey Ponomarenko16934472012-03-29 15:37:04 +040011054 my $Impl2 = canonifyImpl($Interface_Impl{2}{$Interface});
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011055 next if(not $Impl2);
11056 if($Impl1 ne $Impl2)
11057 {
11058 writeFile("$TMP_DIR/impl1", $Impl1);
11059 writeFile("$TMP_DIR/impl2", $Impl2);
Andrey Ponomarenkoa01311b2012-06-08 17:20:02 +040011060 my $Diff = `$DiffCmd -rNau \"$TMP_DIR/impl1\" \"$TMP_DIR/impl2\"`;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011061 $Diff=~s/(---|\+\+\+).+\n//g;
11062 $Diff=~s/[ ]{3,}/ /g;
11063 $Diff=~s/\n\@\@/\n \n\@\@/g;
Andrey Ponomarenkoa01311b2012-06-08 17:20:02 +040011064 unlink("$TMP_DIR/impl1");
11065 unlink("$TMP_DIR/impl2");
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011066 %{$ImplProblems{$Interface}}=(
11067 "Diff" => get_CodeView($Diff) );
11068 }
11069 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +040011070
11071 # clean memory
11072 %Interface_Impl = ();
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011073}
11074
Andrey Ponomarenko16934472012-03-29 15:37:04 +040011075sub canonifyImpl($)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011076{
11077 my $FuncBody= $_[0];
11078 return "" if(not $FuncBody);
11079 $FuncBody=~s/0x[a-f\d]+/0x?/g;# addr
11080 $FuncBody=~s/((\A|\n)[a-z]+[\t ]+)[a-f\d]+([^x]|\Z)/$1?$3/g;# call, jump
11081 $FuncBody=~s/# [a-f\d]+ /# ? /g;# call, jump
11082 $FuncBody=~s/%([a-z]+[a-f\d]*)/\%reg/g;# registers
11083 while($FuncBody=~s/\nnop[ \t]*(\n|\Z)/$1/g){};# empty op
11084 $FuncBody=~s/<.+?\.cpp.+?>/<name.cpp>/g;
11085 $FuncBody=~s/(\A|\n)[a-f\d]+ </$1? </g;# 5e74 <_ZN...
11086 $FuncBody=~s/\.L\d+/.L/g;
11087 $FuncBody=~s/#(-?)\d+/#$1?/g;# r3, [r3, #120]
11088 $FuncBody=~s/[\n]{2,}/\n/g;
11089 return $FuncBody;
11090}
11091
11092sub get_CodeView($)
11093{
11094 my $Code = $_[0];
11095 my $View = "";
11096 foreach my $Line (split(/\n/, $Code))
11097 {
11098 if($Line=~s/\A(\+|-)/$1 /g)
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040011099 { # bold line
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011100 $View .= "<tr><td><b>".htmlSpecChars($Line)."</b></td></tr>\n";
11101 }
11102 else {
11103 $View .= "<tr><td>".htmlSpecChars($Line)."</td></tr>\n";
11104 }
11105 }
11106 return "<table class='code_view'>$View</table>\n";
11107}
11108
11109sub getImplementations($$)
11110{
11111 my ($LibVersion, $Path) = @_;
11112 return if(not $LibVersion or not -e $Path);
11113 if($OSgroup eq "macos")
11114 {
11115 my $OtoolCmd = get_CmdPath("otool");
11116 if(not $OtoolCmd) {
11117 exitStatus("Not_Found", "can't find \"otool\"");
11118 }
11119 my $CurInterface = "";
Andrey Ponomarenkoa01311b2012-06-08 17:20:02 +040011120 foreach my $Line (split(/\n/, `$OtoolCmd -tv \"$Path\" 2>\"$TMP_DIR/null\"`))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011121 {
11122 if($Line=~/\A\s*_(\w+)\s*:/i) {
11123 $CurInterface = $1;
11124 }
11125 elsif($Line=~/\A\s*[\da-z]+\s+(.+?)\Z/i) {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040011126 $Interface_Impl{$LibVersion}{$CurInterface} .= $1."\n";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011127 }
11128 }
11129 }
11130 else
11131 {
11132 my $ObjdumpCmd = get_CmdPath("objdump");
11133 if(not $ObjdumpCmd) {
11134 exitStatus("Not_Found", "can't find \"objdump\"");
11135 }
11136 my $CurInterface = "";
Andrey Ponomarenkoa01311b2012-06-08 17:20:02 +040011137 foreach my $Line (split(/\n/, `$ObjdumpCmd -d \"$Path\" 2>\"$TMP_DIR/null\"`))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011138 {
11139 if($Line=~/\A[\da-z]+\s+<(\w+)>/i) {
11140 $CurInterface = $1;
11141 }
11142 else
11143 { # x86: 51fa:(\t)89 e5 (\t)mov %esp,%ebp
11144 # arm: 5020:(\t)e24cb004(\t)sub(\t)fp, ip, #4(\t); 0x4
11145 if($Line=~/\A\s*[a-f\d]+:\s+([a-f\d]+\s+)+([a-z]+\s+.*?)\s*(;.*|)\Z/i) {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040011146 $Interface_Impl{$LibVersion}{$CurInterface} .= $2."\n";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011147 }
11148 }
11149 }
11150 }
11151}
11152
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011153sub detectAdded($)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011154{
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011155 my $Level = $_[0];
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011156 foreach my $Symbol (keys(%{$Symbol_Library{2}}))
11157 {
11158 if(link_symbol($Symbol, 1, "+Deps"))
11159 { # linker can find a new symbol
11160 # in the old-version library
11161 # So, it's not a new symbol
11162 next;
11163 }
11164 if(my $VSym = $SymVer{2}{$Symbol}
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040011165 and index($Symbol,"\@")==-1) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011166 next;
11167 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011168 $AddedInt{$Level}{$Symbol} = 1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011169 }
11170}
11171
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011172sub detectRemoved($)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011173{
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011174 my $Level = $_[0];
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011175 foreach my $Symbol (keys(%{$Symbol_Library{1}}))
11176 {
11177 if($CheckObjectsOnly) {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011178 $CheckedSymbols{"Binary"}{$Symbol} = 1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011179 }
11180 if(link_symbol($Symbol, 2, "+Deps"))
11181 { # linker can find an old symbol
11182 # in the new-version library
11183 next;
11184 }
11185 if(my $VSym = $SymVer{1}{$Symbol}
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040011186 and index($Symbol,"\@")==-1) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011187 next;
11188 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011189 $RemovedInt{$Level}{$Symbol} = 1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011190 }
11191}
11192
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011193sub mergeLibs($)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011194{
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011195 my $Level = $_[0];
11196 foreach my $Symbol (sort keys(%{$AddedInt{$Level}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011197 { # checking added symbols
11198 next if($CompleteSignature{2}{$Symbol}{"Private"});
11199 next if(not $CompleteSignature{2}{$Symbol}{"Header"} and not $CheckObjectsOnly);
Andrey Ponomarenko85043792012-05-14 16:48:07 +040011200 next if(not symbolFilter($Symbol, 2, "Affected", $Level));
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011201 %{$CompatProblems{$Level}{$Symbol}{"Added_Symbol"}{""}}=();
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011202 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011203 foreach my $Symbol (sort keys(%{$RemovedInt{$Level}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011204 { # checking removed symbols
11205 next if($CompleteSignature{1}{$Symbol}{"Private"});
11206 next if(not $CompleteSignature{1}{$Symbol}{"Header"} and not $CheckObjectsOnly);
11207 if($Symbol=~/\A_ZTV/)
11208 { # skip v-tables for templates, that should not be imported by applications
11209 next if($tr_name{$Symbol}=~/</);
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040011210 if(my $CName = $VTableClass{$Symbol})
11211 {
11212 if(not keys(%{$ClassMethods{$Level}{1}{$CName}}))
11213 { # vtables for "private" classes
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040011214 # use case: vtable for QDragManager (Qt 4.5.3 to 4.6.0) became HIDDEN symbol
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040011215 next;
11216 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011217 }
11218 }
11219 else {
Andrey Ponomarenko85043792012-05-14 16:48:07 +040011220 next if(not symbolFilter($Symbol, 1, "Affected", $Level));
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011221 }
11222 if($CompleteSignature{1}{$Symbol}{"PureVirt"})
11223 { # symbols for pure virtual methods cannot be called by clients
11224 next;
11225 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011226 %{$CompatProblems{$Level}{$Symbol}{"Removed_Symbol"}{""}}=();
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011227 }
11228}
11229
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040011230sub checkDump($$)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011231{
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040011232 my ($LibVersion, $V) = @_;
11233 if(defined $Cache{"checkDump"}{$LibVersion}{$V}) {
11234 return $Cache{"checkDump"}{$LibVersion}{$V};
11235 }
11236 return ($Cache{"checkDump"}{$LibVersion}{$V} = (not $UsedDump{$LibVersion}{"V"} or cmpVersions($UsedDump{$LibVersion}{"V"}, $V)>=0));
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011237}
11238
11239sub detectAdded_H($)
11240{
11241 my $Level = $_[0];
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011242 foreach my $Symbol (sort keys(%{$CompleteSignature{2}}))
11243 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011244 if($Level eq "Source")
11245 { # remove symbol version
11246 my ($SN, $SS, $SV) = separate_symbol($Symbol);
11247 $Symbol=$SN;
Andrey Ponomarenkob8d203d2012-05-25 18:11:07 +040011248
11249 if($CompleteSignature{2}{$Symbol}{"Artificial"})
11250 { # skip artificial constructors
11251 next;
11252 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011253 }
Andrey Ponomarenko16934472012-03-29 15:37:04 +040011254 if(not $CompleteSignature{2}{$Symbol}{"Header"}
11255 or not $CompleteSignature{2}{$Symbol}{"MnglName"}) {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011256 next;
11257 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040011258 if($ExtendedSymbols{$Symbol}) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011259 next;
11260 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011261 if(not defined $CompleteSignature{1}{$Symbol}
11262 or not $CompleteSignature{1}{$Symbol}{"MnglName"})
11263 {
Andrey Ponomarenko16934472012-03-29 15:37:04 +040011264 if($UsedDump{2}{"SrcBin"})
11265 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040011266 if($UsedDump{1}{"BinOnly"} or not checkDump(1, "2.11"))
Andrey Ponomarenko16934472012-03-29 15:37:04 +040011267 { # support for old and different (!) ABI dumps
11268 if(not $CompleteSignature{2}{$Symbol}{"Virt"}
11269 and not $CompleteSignature{2}{$Symbol}{"PureVirt"})
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011270 {
Andrey Ponomarenko16934472012-03-29 15:37:04 +040011271 if($CheckHeadersOnly)
Andrey Ponomarenko85043792012-05-14 16:48:07 +040011272 {
11273 if(my $Lang = $CompleteSignature{2}{$Symbol}{"Lang"})
11274 {
11275 if($Lang eq "C")
11276 { # support for old ABI dumps: missed extern "C" functions
11277 next;
11278 }
11279 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011280 }
Andrey Ponomarenko16934472012-03-29 15:37:04 +040011281 else
11282 {
11283 if(not link_symbol($Symbol, 2, "-Deps"))
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040011284 { # skip added inline symbols and const global data
Andrey Ponomarenko16934472012-03-29 15:37:04 +040011285 next;
11286 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011287 }
11288 }
11289 }
11290 }
11291 $AddedInt{$Level}{$Symbol} = 1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011292 }
11293 }
11294}
11295
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011296sub detectRemoved_H($)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011297{
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011298 my $Level = $_[0];
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011299 foreach my $Symbol (sort keys(%{$CompleteSignature{1}}))
11300 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011301 if($Level eq "Source")
11302 { # remove symbol version
11303 my ($SN, $SS, $SV) = separate_symbol($Symbol);
11304 $Symbol=$SN;
11305 }
Andrey Ponomarenko16934472012-03-29 15:37:04 +040011306 if(not $CompleteSignature{1}{$Symbol}{"Header"}
11307 or not $CompleteSignature{1}{$Symbol}{"MnglName"}) {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011308 next;
11309 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040011310 if($ExtendedSymbols{$Symbol}) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011311 next;
11312 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011313 if(not defined $CompleteSignature{2}{$Symbol}
11314 or not $CompleteSignature{2}{$Symbol}{"MnglName"})
Andrey Ponomarenko85043792012-05-14 16:48:07 +040011315 {
Andrey Ponomarenko16934472012-03-29 15:37:04 +040011316 if($UsedDump{1}{"SrcBin"})
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011317 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040011318 if($UsedDump{2}{"BinOnly"} or not checkDump(2, "2.11"))
Andrey Ponomarenko85043792012-05-14 16:48:07 +040011319 { # support for old and different (!) ABI dumps
Andrey Ponomarenko16934472012-03-29 15:37:04 +040011320 if(not $CompleteSignature{1}{$Symbol}{"Virt"}
11321 and not $CompleteSignature{1}{$Symbol}{"PureVirt"})
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011322 {
Andrey Ponomarenko16934472012-03-29 15:37:04 +040011323 if($CheckHeadersOnly)
11324 { # skip all removed symbols
Andrey Ponomarenko85043792012-05-14 16:48:07 +040011325 if(my $Lang = $CompleteSignature{1}{$Symbol}{"Lang"})
11326 {
11327 if($Lang eq "C")
11328 { # support for old ABI dumps: missed extern "C" functions
11329 next;
11330 }
11331 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011332 }
Andrey Ponomarenko16934472012-03-29 15:37:04 +040011333 else
11334 {
11335 if(not link_symbol($Symbol, 1, "-Deps"))
11336 { # skip removed inline symbols
11337 next;
11338 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011339 }
11340 }
11341 }
11342 }
Andrey Ponomarenkob8d203d2012-05-25 18:11:07 +040011343 if(not checkDump(1, "2.15"))
11344 {
11345 if($Symbol=~/_IT_E\Z/)
11346 { # _ZN28QExplicitlySharedDataPointerI22QSslCertificatePrivateEC1IT_EERKS_IT_E
11347 next;
11348 }
11349 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011350 $RemovedInt{$Level}{$Symbol} = 1;
11351 if($Level eq "Source")
11352 { # search for a source-compatible equivalent
11353 setAlternative($Symbol, $Level);
11354 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011355 }
11356 }
11357}
11358
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011359sub mergeHeaders($)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011360{
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011361 my $Level = $_[0];
11362 foreach my $Symbol (sort keys(%{$AddedInt{$Level}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011363 { # checking added symbols
11364 next if($CompleteSignature{2}{$Symbol}{"PureVirt"});
Andrey Ponomarenko85043792012-05-14 16:48:07 +040011365 if($Level eq "Binary")
11366 {
11367 if($CompleteSignature{2}{$Symbol}{"InLine"})
11368 {
11369 if(not $CompleteSignature{2}{$Symbol}{"Virt"})
11370 { # skip inline non-virtual functions
11371 next;
11372 }
11373 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011374 }
11375 else
11376 { # Source
11377 if($SourceAlternative_B{$Symbol}) {
11378 next;
11379 }
11380 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011381 next if($CompleteSignature{2}{$Symbol}{"Private"});
Andrey Ponomarenko85043792012-05-14 16:48:07 +040011382 next if(not symbolFilter($Symbol, 2, "Affected", $Level));
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011383 %{$CompatProblems{$Level}{$Symbol}{"Added_Symbol"}{""}}=();
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011384 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011385 foreach my $Symbol (sort keys(%{$RemovedInt{$Level}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011386 { # checking removed symbols
11387 next if($CompleteSignature{1}{$Symbol}{"PureVirt"});
Andrey Ponomarenko85043792012-05-14 16:48:07 +040011388 if($Level eq "Binary")
11389 {
11390 if($CompleteSignature{1}{$Symbol}{"InLine"})
11391 {
11392 if(not $CompleteSignature{1}{$Symbol}{"Virt"})
11393 { # skip inline non-virtual functions
11394 next;
11395 }
11396 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011397 }
11398 else
11399 { # Source
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040011400 if(my $Alt = $SourceAlternative{$Symbol})
11401 {
11402 if(defined $CompleteSignature{1}{$Alt}
11403 and $CompleteSignature{1}{$Symbol}{"Const"})
11404 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040011405 my $Cid = $CompleteSignature{1}{$Symbol}{"Class"};
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040011406 %{$CompatProblems{$Level}{$Symbol}{"Removed_Const_Overload"}{$tr_name{$Symbol}}}=(
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040011407 "Type_Name"=>$TypeInfo{1}{$Cid}{"Name"},
Andrey Ponomarenko85043792012-05-14 16:48:07 +040011408 "Type_Type"=>"Class",
11409 "Target"=>get_Signature($Alt, 1) );
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040011410 }
11411 else
11412 { # do NOT show removed symbol
11413 next;
11414 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011415 }
11416 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011417 next if($CompleteSignature{1}{$Symbol}{"Private"});
Andrey Ponomarenko85043792012-05-14 16:48:07 +040011418 next if(not symbolFilter($Symbol, 1, "Affected", $Level));
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011419 %{$CompatProblems{$Level}{$Symbol}{"Removed_Symbol"}{""}}=();
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011420 }
11421}
11422
11423sub addParamNames($)
11424{
11425 my $LibraryVersion = $_[0];
11426 return if(not keys(%AddIntParams));
11427 my $SecondVersion = $LibraryVersion==1?2:1;
11428 foreach my $Interface (sort keys(%{$CompleteSignature{$LibraryVersion}}))
11429 {
11430 next if(not keys(%{$AddIntParams{$Interface}}));
11431 foreach my $ParamPos (sort {int($a)<=>int($b)} keys(%{$CompleteSignature{$LibraryVersion}{$Interface}{"Param"}}))
Andrey Ponomarenko85043792012-05-14 16:48:07 +040011432 { # add absent parameter names
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011433 my $ParamName = $CompleteSignature{$LibraryVersion}{$Interface}{"Param"}{$ParamPos}{"name"};
11434 if($ParamName=~/\Ap\d+\Z/ and my $NewParamName = $AddIntParams{$Interface}{$ParamPos})
Andrey Ponomarenko85043792012-05-14 16:48:07 +040011435 { # names from the external file
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011436 if(defined $CompleteSignature{$SecondVersion}{$Interface}
11437 and defined $CompleteSignature{$SecondVersion}{$Interface}{"Param"}{$ParamPos})
11438 {
11439 if($CompleteSignature{$SecondVersion}{$Interface}{"Param"}{$ParamPos}{"name"}=~/\Ap\d+\Z/) {
11440 $CompleteSignature{$LibraryVersion}{$Interface}{"Param"}{$ParamPos}{"name"} = $NewParamName;
11441 }
11442 }
11443 else {
11444 $CompleteSignature{$LibraryVersion}{$Interface}{"Param"}{$ParamPos}{"name"} = $NewParamName;
11445 }
11446 }
11447 }
11448 }
11449}
11450
11451sub detectChangedTypedefs()
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +040011452{ # detect changed typedefs to show
11453 # correct function signatures
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011454 foreach my $Typedef (keys(%{$Typedef_BaseName{1}}))
11455 {
11456 next if(not $Typedef);
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +040011457 my $BName1 = $Typedef_BaseName{1}{$Typedef};
11458 if(not $BName1 or isAnon($BName1)) {
11459 next;
11460 }
11461 my $BName2 = $Typedef_BaseName{2}{$Typedef};
11462 if(not $BName2 or isAnon($BName2)) {
11463 next;
11464 }
11465 if($BName1 ne $BName2) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011466 $ChangedTypedef{$Typedef} = 1;
11467 }
11468 }
11469}
11470
11471sub get_symbol_suffix($$)
11472{
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011473 my ($Symbol, $Full) = @_;
11474 my ($SN, $SO, $SV) = separate_symbol($Symbol);
11475 $Symbol=$SN;# remove version
11476 my $Signature = $tr_name{$Symbol};
Andrey Ponomarenko16934472012-03-29 15:37:04 +040011477 my $Suffix = substr($Signature, find_center($Signature, "("));
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011478 if(not $Full) {
11479 $Suffix=~s/(\))\s*(const volatile|volatile const|const|volatile)\Z/$1/g;
11480 }
11481 return $Suffix;
11482}
11483
11484sub get_symbol_prefix($$)
11485{
11486 my ($Symbol, $LibVersion) = @_;
11487 my $ShortName = $CompleteSignature{$LibVersion}{$Symbol}{"ShortName"};
11488 if(my $ClassId = $CompleteSignature{$LibVersion}{$Symbol}{"Class"})
11489 { # methods
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040011490 $ShortName = $TypeInfo{$LibVersion}{$ClassId}{"Name"}."::".$ShortName;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011491 }
11492 return $ShortName;
11493}
11494
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011495sub setAlternative($)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011496{
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011497 my $Symbol = $_[0];
11498 my $PSymbol = $Symbol;
11499 if(not defined $CompleteSignature{2}{$PSymbol}
11500 or (not $CompleteSignature{2}{$PSymbol}{"MnglName"}
11501 and not $CompleteSignature{2}{$PSymbol}{"ShortName"}))
11502 { # search for a pair
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040011503 if(my $ShortName = $CompleteSignature{1}{$PSymbol}{"ShortName"})
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011504 {
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040011505 if($CompleteSignature{1}{$PSymbol}{"Data"})
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011506 {
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040011507 if($PSymbol=~s/L(\d+$ShortName(E)\Z)/$1/
11508 or $PSymbol=~s/(\d+$ShortName(E)\Z)/L$1/)
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011509 {
11510 if(defined $CompleteSignature{2}{$PSymbol}
11511 and $CompleteSignature{2}{$PSymbol}{"MnglName"})
11512 {
11513 $SourceAlternative{$Symbol} = $PSymbol;
11514 $SourceAlternative_B{$PSymbol} = $Symbol;
11515 if(not defined $CompleteSignature{1}{$PSymbol}
11516 or not $CompleteSignature{1}{$PSymbol}{"MnglName"}) {
11517 $SourceReplacement{$Symbol} = $PSymbol;
11518 }
11519 }
11520 }
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040011521 }
11522 else
11523 {
11524 foreach my $Sp ("KV", "VK", "K", "V")
11525 {
11526 if($PSymbol=~s/\A_ZN$Sp/_ZN/
11527 or $PSymbol=~s/\A_ZN/_ZN$Sp/)
11528 {
11529 if(defined $CompleteSignature{2}{$PSymbol}
11530 and $CompleteSignature{2}{$PSymbol}{"MnglName"})
11531 {
11532 $SourceAlternative{$Symbol} = $PSymbol;
11533 $SourceAlternative_B{$PSymbol} = $Symbol;
11534 if(not defined $CompleteSignature{1}{$PSymbol}
11535 or not $CompleteSignature{1}{$PSymbol}{"MnglName"}) {
11536 $SourceReplacement{$Symbol} = $PSymbol;
11537 }
11538 }
11539 }
11540 $PSymbol = $Symbol;
11541 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011542 }
11543 }
11544 }
11545 return "";
11546}
11547
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040011548sub getSymKind($$)
11549{
11550 my ($Symbol, $LibVersion) = @_;
11551 if($CompleteSignature{$LibVersion}{$Symbol}{"Data"})
11552 {
11553 return "Global_Data";
11554 }
11555 elsif($CompleteSignature{$LibVersion}{$Symbol}{"Class"})
11556 {
11557 return "Method";
11558 }
11559 return "Function";
11560}
11561
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011562sub mergeSignatures($)
11563{
11564 my $Level = $_[0];
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011565 my %SubProblems = ();
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011566
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011567 mergeBases($Level);
11568
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011569 my %AddedOverloads = ();
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011570 foreach my $Symbol (sort keys(%{$AddedInt{$Level}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011571 { # check all added exported symbols
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011572 if(not $CompleteSignature{2}{$Symbol}{"Header"}) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011573 next;
11574 }
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040011575 if(defined $CompleteSignature{1}{$Symbol}
11576 and $CompleteSignature{1}{$Symbol}{"Header"})
11577 { # double-check added symbol
11578 next;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011579 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +040011580 if(not symbolFilter($Symbol, 2, "Affected", $Level)) {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011581 next;
11582 }
11583 if($Symbol=~/\A(_Z|\?)/)
11584 { # C++
11585 $AddedOverloads{get_symbol_prefix($Symbol, 2)}{get_symbol_suffix($Symbol, 1)} = $Symbol;
11586 }
11587 if(my $OverriddenMethod = $CompleteSignature{2}{$Symbol}{"Override"})
11588 { # register virtual overridings
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040011589 my $Cid = $CompleteSignature{2}{$Symbol}{"Class"};
11590 my $AffectedClass_Name = $TypeInfo{2}{$Cid}{"Name"};
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040011591 if(defined $CompleteSignature{1}{$OverriddenMethod} and $CompleteSignature{1}{$OverriddenMethod}{"Virt"}
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011592 and not $CompleteSignature{1}{$OverriddenMethod}{"Private"})
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040011593 {
11594 if($TName_Tid{1}{$AffectedClass_Name})
11595 { # class should exist in previous version
11596 if(not isCopyingClass($TName_Tid{1}{$AffectedClass_Name}, 1))
11597 { # old v-table is NOT copied by old applications
11598 %{$CompatProblems{$Level}{$OverriddenMethod}{"Overridden_Virtual_Method"}{$tr_name{$Symbol}}}=(
11599 "Type_Name"=>$AffectedClass_Name,
11600 "Type_Type"=>"Class",
11601 "Target"=>get_Signature($Symbol, 2),
11602 "Old_Value"=>get_Signature($OverriddenMethod, 2),
11603 "New_Value"=>get_Signature($Symbol, 2) );
11604 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011605 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011606 }
11607 }
11608 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011609 foreach my $Symbol (sort keys(%{$RemovedInt{$Level}}))
11610 { # check all removed exported symbols
11611 if(not $CompleteSignature{1}{$Symbol}{"Header"}) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011612 next;
11613 }
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040011614 if(defined $CompleteSignature{2}{$Symbol}
11615 and $CompleteSignature{2}{$Symbol}{"Header"})
11616 { # double-check removed symbol
11617 next;
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011618 }
11619 if($CompleteSignature{1}{$Symbol}{"Private"})
11620 { # skip private methods
11621 next;
11622 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +040011623 if(not symbolFilter($Symbol, 1, "Affected", $Level)) {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011624 next;
11625 }
11626 $CheckedSymbols{$Level}{$Symbol} = 1;
11627 if(my $OverriddenMethod = $CompleteSignature{1}{$Symbol}{"Override"})
11628 { # register virtual overridings
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040011629 my $Cid = $CompleteSignature{1}{$Symbol}{"Class"};
11630 my $AffectedClass_Name = $TypeInfo{1}{$Cid}{"Name"};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011631 if(defined $CompleteSignature{2}{$OverriddenMethod}
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040011632 and $CompleteSignature{2}{$OverriddenMethod}{"Virt"})
11633 {
11634 if($TName_Tid{2}{$AffectedClass_Name})
11635 { # class should exist in newer version
11636 if(not isCopyingClass($CompleteSignature{1}{$Symbol}{"Class"}, 1))
11637 { # old v-table is NOT copied by old applications
11638 %{$CompatProblems{$Level}{$Symbol}{"Overridden_Virtual_Method_B"}{$tr_name{$OverriddenMethod}}}=(
11639 "Type_Name"=>$AffectedClass_Name,
11640 "Type_Type"=>"Class",
11641 "Target"=>get_Signature($OverriddenMethod, 1),
11642 "Old_Value"=>get_Signature($Symbol, 1),
11643 "New_Value"=>get_Signature($OverriddenMethod, 1) );
11644 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011645 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011646 }
11647 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011648 if($Level eq "Binary"
11649 and $OSgroup eq "windows")
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011650 { # register the reason of symbol name change
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040011651 if(my $NewSym = $mangled_name{2}{$tr_name{$Symbol}})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011652 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040011653 if($AddedInt{$Level}{$NewSym})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011654 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040011655 if($CompleteSignature{1}{$Symbol}{"Static"} ne $CompleteSignature{2}{$NewSym}{"Static"})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011656 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040011657 if($CompleteSignature{2}{$NewSym}{"Static"})
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011658 {
11659 %{$CompatProblems{$Level}{$Symbol}{"Symbol_Became_Static"}{$tr_name{$Symbol}}}=(
11660 "Target"=>$tr_name{$Symbol},
11661 "Old_Value"=>$Symbol,
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040011662 "New_Value"=>$NewSym );
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011663 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011664 else
11665 {
11666 %{$CompatProblems{$Level}{$Symbol}{"Symbol_Became_NonStatic"}{$tr_name{$Symbol}}}=(
11667 "Target"=>$tr_name{$Symbol},
11668 "Old_Value"=>$Symbol,
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040011669 "New_Value"=>$NewSym );
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011670 }
11671 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040011672 if($CompleteSignature{1}{$Symbol}{"Virt"} ne $CompleteSignature{2}{$NewSym}{"Virt"})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011673 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040011674 if($CompleteSignature{2}{$NewSym}{"Virt"})
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011675 {
11676 %{$CompatProblems{$Level}{$Symbol}{"Symbol_Became_Virtual"}{$tr_name{$Symbol}}}=(
11677 "Target"=>$tr_name{$Symbol},
11678 "Old_Value"=>$Symbol,
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040011679 "New_Value"=>$NewSym );
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011680 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011681 else
11682 {
11683 %{$CompatProblems{$Level}{$Symbol}{"Symbol_Became_NonVirtual"}{$tr_name{$Symbol}}}=(
11684 "Target"=>$tr_name{$Symbol},
11685 "Old_Value"=>$Symbol,
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040011686 "New_Value"=>$NewSym );
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011687 }
11688 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040011689 my $RTId1 = $CompleteSignature{1}{$Symbol}{"Return"};
11690 my $RTId2 = $CompleteSignature{2}{$NewSym}{"Return"};
11691 my $RTName1 = $TypeInfo{1}{$RTId1}{"Name"};
11692 my $RTName2 = $TypeInfo{2}{$RTId2}{"Name"};
11693 if($RTName1 ne $RTName2)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011694 {
11695 my $ProblemType = "Symbol_Changed_Return";
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011696 if($CompleteSignature{1}{$Symbol}{"Data"}) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011697 $ProblemType = "Global_Data_Symbol_Changed_Type";
11698 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011699 %{$CompatProblems{$Level}{$Symbol}{$ProblemType}{$tr_name{$Symbol}}}=(
11700 "Target"=>$tr_name{$Symbol},
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040011701 "Old_Type"=>$RTName1,
11702 "New_Type"=>$RTName2,
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011703 "Old_Value"=>$Symbol,
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040011704 "New_Value"=>$NewSym );
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011705 }
11706 }
11707 }
11708 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011709 if($Symbol=~/\A(_Z|\?)/)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011710 { # C++
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011711 my $Prefix = get_symbol_prefix($Symbol, 1);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011712 if(my @Overloads = sort keys(%{$AddedOverloads{$Prefix}})
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011713 and not $AddedOverloads{$Prefix}{get_symbol_suffix($Symbol, 1)})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011714 { # changed signature: params, "const"-qualifier
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040011715 my $NewSym = $AddedOverloads{$Prefix}{$Overloads[0]};
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011716 if($CompleteSignature{1}{$Symbol}{"Constructor"})
11717 {
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +040011718 if($Symbol=~/(C1E|C2E)/)
11719 {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011720 my $CtorType = $1;
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040011721 $NewSym=~s/(C1E|C2E)/$CtorType/g;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011722 }
11723 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011724 elsif($CompleteSignature{1}{$Symbol}{"Destructor"})
11725 {
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +040011726 if($Symbol=~/(D0E|D1E|D2E)/)
11727 {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011728 my $DtorType = $1;
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040011729 $NewSym=~s/(D0E|D1E|D2E)/$DtorType/g;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011730 }
11731 }
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040011732 my $NS1 = $CompleteSignature{1}{$Symbol}{"NameSpace"};
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040011733 my $NS2 = $CompleteSignature{2}{$NewSym}{"NameSpace"};
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040011734 if((not $NS1 and not $NS2) or ($NS1 and $NS2 and $NS1 eq $NS2))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011735 { # from the same class and namespace
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011736 if($CompleteSignature{1}{$Symbol}{"Const"}
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040011737 and not $CompleteSignature{2}{$NewSym}{"Const"})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011738 { # "const" to non-"const"
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040011739 %{$CompatProblems{$Level}{$Symbol}{"Method_Became_NonConst"}{$tr_name{$Symbol}}}=(
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040011740 "Type_Name"=>$TypeInfo{1}{$CompleteSignature{1}{$Symbol}{"Class"}}{"Name"},
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011741 "Target"=>$tr_name{$Symbol},
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040011742 "New_Signature"=>get_Signature($NewSym, 2),
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011743 "Old_Value"=>$Symbol,
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040011744 "New_Value"=>$NewSym );
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011745 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011746 elsif(not $CompleteSignature{1}{$Symbol}{"Const"}
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040011747 and $CompleteSignature{2}{$NewSym}{"Const"})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011748 { # non-"const" to "const"
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040011749 %{$CompatProblems{$Level}{$Symbol}{"Method_Became_Const"}{$tr_name{$Symbol}}}=(
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011750 "Target"=>$tr_name{$Symbol},
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040011751 "New_Signature"=>get_Signature($NewSym, 2),
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011752 "Old_Value"=>$Symbol,
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040011753 "New_Value"=>$NewSym );
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011754 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011755 if($CompleteSignature{1}{$Symbol}{"Volatile"}
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040011756 and not $CompleteSignature{2}{$NewSym}{"Volatile"})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011757 { # "volatile" to non-"volatile"
11758
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040011759 %{$CompatProblems{$Level}{$Symbol}{"Method_Became_NonVolatile"}{$tr_name{$Symbol}}}=(
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011760 "Target"=>$tr_name{$Symbol},
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040011761 "New_Signature"=>get_Signature($NewSym, 2),
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011762 "Old_Value"=>$Symbol,
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040011763 "New_Value"=>$NewSym );
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011764 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011765 elsif(not $CompleteSignature{1}{$Symbol}{"Volatile"}
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040011766 and $CompleteSignature{2}{$NewSym}{"Volatile"})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011767 { # non-"volatile" to "volatile"
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040011768 %{$CompatProblems{$Level}{$Symbol}{"Method_Became_Volatile"}{$tr_name{$Symbol}}}=(
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011769 "Target"=>$tr_name{$Symbol},
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040011770 "New_Signature"=>get_Signature($NewSym, 2),
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011771 "Old_Value"=>$Symbol,
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040011772 "New_Value"=>$NewSym );
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011773 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040011774 if(get_symbol_suffix($Symbol, 0) ne get_symbol_suffix($NewSym, 0))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011775 { # params list
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011776 %{$CompatProblems{$Level}{$Symbol}{"Symbol_Changed_Parameters"}{$tr_name{$Symbol}}}=(
11777 "Target"=>$tr_name{$Symbol},
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040011778 "New_Signature"=>get_Signature($NewSym, 2),
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011779 "Old_Value"=>$Symbol,
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040011780 "New_Value"=>$NewSym );
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011781 }
11782 }
11783 }
11784 }
11785 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011786 foreach my $Symbol (sort keys(%{$CompleteSignature{1}}))
11787 { # checking symbols
11788 my ($SN, $SS, $SV) = separate_symbol($Symbol);
11789 if($Level eq "Source")
11790 { # remove symbol version
11791 $Symbol=$SN;
11792 }
11793 else
11794 { # Binary
11795 if(not $SV)
11796 { # symbol without version
11797 if(my $VSym = $SymVer{1}{$Symbol})
11798 { # the symbol is linked with versioned symbol
11799 if($CompleteSignature{2}{$VSym}{"MnglName"})
11800 { # show report for symbol@ver only
11801 next;
11802 }
11803 elsif(not link_symbol($VSym, 2, "-Deps"))
11804 { # changed version: sym@v1 to sym@v2
11805 # do NOT show report for symbol
11806 next;
11807 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011808 }
11809 }
11810 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011811 my $PSymbol = $Symbol;
11812 if($Level eq "Source"
11813 and my $S = $SourceReplacement{$Symbol})
11814 { # take a source-compatible replacement function
11815 $PSymbol = $S;
11816 }
11817 if($CompleteSignature{1}{$Symbol}{"Private"})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011818 { # private symbols
11819 next;
11820 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011821 if(not defined $CompleteSignature{1}{$Symbol}
11822 or not defined $CompleteSignature{2}{$PSymbol})
11823 { # no info
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011824 next;
11825 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011826 if(not $CompleteSignature{1}{$Symbol}{"MnglName"}
11827 or not $CompleteSignature{2}{$PSymbol}{"MnglName"})
11828 { # no mangled name
11829 next;
11830 }
11831 if(not $CompleteSignature{1}{$Symbol}{"Header"}
11832 or not $CompleteSignature{2}{$PSymbol}{"Header"})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011833 { # without a header
11834 next;
11835 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040011836 if(checkDump(1, "2.13") and checkDump(2, "2.13"))
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040011837 {
11838 if($CompleteSignature{1}{$Symbol}{"Data"}
11839 and $CompleteSignature{2}{$PSymbol}{"Data"})
11840 {
11841 my $Value1 = $CompleteSignature{1}{$Symbol}{"Value"};
11842 my $Value2 = $CompleteSignature{2}{$PSymbol}{"Value"};
11843 if(defined $Value1)
11844 {
11845 $Value1 = showVal($Value1, $CompleteSignature{1}{$Symbol}{"Return"}, 1);
11846 if(defined $Value2)
11847 {
11848 $Value2 = showVal($Value2, $CompleteSignature{2}{$PSymbol}{"Return"}, 2);
11849 if($Value1 ne $Value2)
11850 {
11851 %{$CompatProblems{$Level}{$Symbol}{"Global_Data_Value_Changed"}{""}}=(
11852 "Old_Value"=>$Value1,
11853 "New_Value"=>$Value2,
11854 "Target"=>get_Signature($Symbol, 1) );
11855 }
11856 }
11857 }
11858 }
11859 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +040011860
11861 if(not $CompleteSignature{1}{$Symbol}{"PureVirt"}
11862 and $CompleteSignature{2}{$PSymbol}{"PureVirt"})
11863 { # became pure
11864 next;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011865 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +040011866 if($CompleteSignature{1}{$Symbol}{"PureVirt"}
11867 and not $CompleteSignature{2}{$PSymbol}{"PureVirt"})
11868 { # became non-pure
11869 next;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011870 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +040011871
11872 if(not symbolFilter($Symbol, 1, "Affected + InlineVirt", $Level))
11873 { # exported, target, inline virtual and pure virtual
11874 next;
11875 }
11876 if(not symbolFilter($PSymbol, 2, "Affected + InlineVirt", $Level))
11877 { # exported, target, inline virtual and pure virtual
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011878 next;
11879 }
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040011880
11881 if($CompleteSignature{2}{$PSymbol}{"Private"})
11882 {
11883 %{$CompatProblems{$Level}{$Symbol}{getSymKind($Symbol, 1)."_Became_Private"}{""}}=(
11884 "Target"=>get_Signature_M($PSymbol, 2) );
11885 }
11886 elsif(not $CompleteSignature{1}{$Symbol}{"Protected"}
11887 and $CompleteSignature{2}{$PSymbol}{"Protected"})
11888 {
11889 %{$CompatProblems{$Level}{$Symbol}{getSymKind($Symbol, 1)."_Became_Protected"}{""}}=(
11890 "Target"=>get_Signature_M($PSymbol, 2) );
11891 }
11892 elsif($CompleteSignature{1}{$Symbol}{"Protected"}
11893 and not $CompleteSignature{2}{$PSymbol}{"Protected"})
11894 {
11895 %{$CompatProblems{$Level}{$Symbol}{getSymKind($Symbol, 1)."_Became_Public"}{""}}=(
11896 "Target"=>get_Signature_M($PSymbol, 2) );
11897 }
11898
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011899 # checking virtual table
Andrey Ponomarenko16934472012-03-29 15:37:04 +040011900 mergeVirtualTables($Symbol, $Level);
11901
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011902 if($COMPILE_ERRORS)
11903 { # if some errors occurred at the compiling stage
11904 # then some false positives can be skipped here
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011905 if(not $CompleteSignature{1}{$Symbol}{"Data"} and $CompleteSignature{2}{$PSymbol}{"Data"}
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040011906 and not $GlobalDataObject{2}{$Symbol})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011907 { # missed information about parameters in newer version
11908 next;
11909 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040011910 if($CompleteSignature{1}{$Symbol}{"Data"} and not $GlobalDataObject{1}{$Symbol}
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011911 and not $CompleteSignature{2}{$PSymbol}{"Data"})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011912 {# missed information about parameters in older version
11913 next;
11914 }
11915 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011916 my ($MnglName, $VersionSpec, $SymbolVersion) = separate_symbol($Symbol);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011917 # checking attributes
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011918 if($CompleteSignature{2}{$PSymbol}{"Static"}
11919 and not $CompleteSignature{1}{$Symbol}{"Static"} and $Symbol=~/\A(_Z|\?)/) {
11920 %{$CompatProblems{$Level}{$Symbol}{"Method_Became_Static"}{""}}=(
11921 "Target"=>get_Signature($Symbol, 1)
11922 );
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011923 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011924 elsif(not $CompleteSignature{2}{$PSymbol}{"Static"}
11925 and $CompleteSignature{1}{$Symbol}{"Static"} and $Symbol=~/\A(_Z|\?)/) {
11926 %{$CompatProblems{$Level}{$Symbol}{"Method_Became_NonStatic"}{""}}=(
11927 "Target"=>get_Signature($Symbol, 1)
11928 );
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011929 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011930 if(($CompleteSignature{1}{$Symbol}{"Virt"} and $CompleteSignature{2}{$PSymbol}{"Virt"})
11931 or ($CompleteSignature{1}{$Symbol}{"PureVirt"} and $CompleteSignature{2}{$PSymbol}{"PureVirt"}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011932 { # relative position of virtual and pure virtual methods
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011933 if($Level eq "Binary")
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011934 {
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040011935 if(defined $CompleteSignature{1}{$Symbol}{"RelPos"} and defined $CompleteSignature{2}{$PSymbol}{"RelPos"}
11936 and $CompleteSignature{1}{$Symbol}{"RelPos"}!=$CompleteSignature{2}{$PSymbol}{"RelPos"})
11937 { # top-level virtual methods only
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011938 my $Class_Id = $CompleteSignature{1}{$Symbol}{"Class"};
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040011939 my $Class_Name = $TypeInfo{1}{$Class_Id}{"Name"};
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040011940 if(defined $VirtualTable{1}{$Class_Name} and defined $VirtualTable{2}{$Class_Name}
11941 and $VirtualTable{1}{$Class_Name}{$Symbol}!=$VirtualTable{2}{$Class_Name}{$Symbol})
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011942 { # check the absolute position of virtual method (including added and removed methods)
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040011943 my %Class_Type = get_Type($Class_Id, 1);
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011944 my $ProblemType = "Virtual_Method_Position";
11945 if($CompleteSignature{1}{$Symbol}{"PureVirt"}) {
11946 $ProblemType = "Pure_Virtual_Method_Position";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011947 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011948 if(isUsedClass($Class_Id, 1, $Level))
11949 {
11950 my @Affected = ($Symbol, keys(%{$OverriddenMethods{1}{$Symbol}}));
11951 foreach my $AffectedInterface (@Affected)
11952 {
11953 %{$CompatProblems{$Level}{$AffectedInterface}{$ProblemType}{$tr_name{$MnglName}}}=(
11954 "Type_Name"=>$Class_Type{"Name"},
11955 "Type_Type"=>"Class",
11956 "Old_Value"=>$CompleteSignature{1}{$Symbol}{"RelPos"},
11957 "New_Value"=>$CompleteSignature{2}{$PSymbol}{"RelPos"},
11958 "Target"=>get_Signature($Symbol, 1) );
11959 }
Andrey Ponomarenko16934472012-03-29 15:37:04 +040011960 $VTableChanged_M{$Class_Type{"Name"}} = 1;
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011961 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011962 }
11963 }
11964 }
11965 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011966 if($CompleteSignature{1}{$Symbol}{"PureVirt"}
11967 or $CompleteSignature{2}{$PSymbol}{"PureVirt"})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011968 { # do NOT check type changes in pure virtuals
11969 next;
11970 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011971 $CheckedSymbols{$Level}{$Symbol}=1;
11972 if($Symbol=~/\A(_Z|\?)/
11973 or keys(%{$CompleteSignature{1}{$Symbol}{"Param"}})==keys(%{$CompleteSignature{2}{$PSymbol}{"Param"}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011974 { # C/C++: changes in parameters
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011975 foreach my $ParamPos (sort {int($a) <=> int($b)} keys(%{$CompleteSignature{1}{$Symbol}{"Param"}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011976 { # checking parameters
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011977 mergeParameters($Symbol, $PSymbol, $ParamPos, $ParamPos, $Level);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011978 }
11979 }
11980 else
11981 { # C: added/removed parameters
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011982 foreach my $ParamPos (sort {int($a) <=> int($b)} keys(%{$CompleteSignature{2}{$PSymbol}{"Param"}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011983 { # checking added parameters
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040011984 my $PType2_Id = $CompleteSignature{2}{$PSymbol}{"Param"}{$ParamPos}{"type"};
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040011985 my $PType2_Name = $TypeInfo{2}{$PType2_Id}{"Name"};
11986 last if($PType2_Name eq "...");
11987 my $PName = $CompleteSignature{2}{$PSymbol}{"Param"}{$ParamPos}{"name"};
11988 my $PName_Old = (defined $CompleteSignature{1}{$Symbol}{"Param"}{$ParamPos})?$CompleteSignature{1}{$Symbol}{"Param"}{$ParamPos}{"name"}:"";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011989 my $ParamPos_Prev = "-1";
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040011990 if($PName=~/\Ap\d+\Z/i)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011991 { # added unnamed parameter ( pN )
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040011992 my @Positions1 = find_ParamPair_Pos_byTypeAndPos($PType2_Name, $ParamPos, "backward", $Symbol, 1);
11993 my @Positions2 = find_ParamPair_Pos_byTypeAndPos($PType2_Name, $ParamPos, "backward", $Symbol, 2);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011994 if($#Positions1==-1 or $#Positions2>$#Positions1) {
11995 $ParamPos_Prev = "lost";
11996 }
11997 }
11998 else {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040011999 $ParamPos_Prev = find_ParamPair_Pos_byName($PName, $Symbol, 1);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012000 }
12001 if($ParamPos_Prev eq "lost")
12002 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012003 if($ParamPos>keys(%{$CompleteSignature{1}{$Symbol}{"Param"}})-1)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012004 {
12005 my $ProblemType = "Added_Parameter";
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040012006 if($PName=~/\Ap\d+\Z/) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012007 $ProblemType = "Added_Unnamed_Parameter";
12008 }
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040012009 %{$CompatProblems{$Level}{$Symbol}{$ProblemType}{showPos($ParamPos)." Parameter"}}=(
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040012010 "Target"=>$PName,
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012011 "Param_Pos"=>$ParamPos,
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040012012 "Param_Type"=>$PType2_Name,
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012013 "New_Signature"=>get_Signature($Symbol, 2) );
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012014 }
12015 else
12016 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040012017 my %ParamType_Pure = get_PureType($PType2_Id, 2);
12018 my $PairType_Id = $CompleteSignature{1}{$Symbol}{"Param"}{$ParamPos}{"type"};
12019 my %PairType_Pure = get_PureType($PairType_Id, 1);
12020 if(($ParamType_Pure{"Name"} eq $PairType_Pure{"Name"} or $PType2_Name eq $TypeInfo{1}{$PairType_Id}{"Name"})
12021 and find_ParamPair_Pos_byName($PName_Old, $Symbol, 2) eq "lost")
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012022 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040012023 if($PName_Old!~/\Ap\d+\Z/ and $PName!~/\Ap\d+\Z/)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012024 {
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040012025 %{$CompatProblems{$Level}{$Symbol}{"Renamed_Parameter"}{showPos($ParamPos)." Parameter"}}=(
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040012026 "Target"=>$PName_Old,
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012027 "Param_Pos"=>$ParamPos,
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040012028 "Param_Type"=>$PType2_Name,
12029 "Old_Value"=>$PName_Old,
12030 "New_Value"=>$PName,
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012031 "New_Signature"=>get_Signature($Symbol, 2) );
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012032 }
12033 }
12034 else
12035 {
12036 my $ProblemType = "Added_Middle_Parameter";
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040012037 if($PName=~/\Ap\d+\Z/) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012038 $ProblemType = "Added_Middle_Unnamed_Parameter";
12039 }
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040012040 %{$CompatProblems{$Level}{$Symbol}{$ProblemType}{showPos($ParamPos)." Parameter"}}=(
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040012041 "Target"=>$PName,
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012042 "Param_Pos"=>$ParamPos,
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040012043 "Param_Type"=>$PType2_Name,
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012044 "New_Signature"=>get_Signature($Symbol, 2) );
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012045 }
12046 }
12047 }
12048 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012049 foreach my $ParamPos (sort {int($a) <=> int($b)} keys(%{$CompleteSignature{1}{$Symbol}{"Param"}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012050 { # check relevant parameters
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040012051 my $PType1_Id = $CompleteSignature{1}{$Symbol}{"Param"}{$ParamPos}{"type"};
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012052 my $ParamName1 = $CompleteSignature{1}{$Symbol}{"Param"}{$ParamPos}{"name"};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012053 # FIXME: find relevant parameter by name
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012054 if(defined $CompleteSignature{2}{$PSymbol}{"Param"}{$ParamPos})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012055 {
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040012056 my $PType2_Id = $CompleteSignature{2}{$PSymbol}{"Param"}{$ParamPos}{"type"};
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012057 my $ParamName2 = $CompleteSignature{2}{$PSymbol}{"Param"}{$ParamPos}{"name"};
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040012058 if($TypeInfo{1}{$PType1_Id}{"Name"} eq $TypeInfo{2}{$PType2_Id}{"Name"}
12059 or ($ParamName1!~/\Ap\d+\Z/i and $ParamName1 eq $ParamName2)) {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012060 mergeParameters($Symbol, $PSymbol, $ParamPos, $ParamPos, $Level);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012061 }
12062 }
12063 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012064 foreach my $ParamPos (sort {int($a) <=> int($b)} keys(%{$CompleteSignature{1}{$Symbol}{"Param"}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012065 { # checking removed parameters
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040012066 my $PType1_Id = $CompleteSignature{1}{$Symbol}{"Param"}{$ParamPos}{"type"};
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040012067 my $PType1_Name = $TypeInfo{1}{$PType1_Id}{"Name"};
12068 last if($PType1_Name eq "...");
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012069 my $Parameter_Name = $CompleteSignature{1}{$Symbol}{"Param"}{$ParamPos}{"name"};
12070 my $Parameter_NewName = (defined $CompleteSignature{2}{$PSymbol}{"Param"}{$ParamPos})?$CompleteSignature{2}{$PSymbol}{"Param"}{$ParamPos}{"name"}:"";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012071 my $ParamPos_New = "-1";
12072 if($Parameter_Name=~/\Ap\d+\Z/i)
12073 { # removed unnamed parameter ( pN )
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040012074 my @Positions1 = find_ParamPair_Pos_byTypeAndPos($PType1_Name, $ParamPos, "forward", $Symbol, 1);
12075 my @Positions2 = find_ParamPair_Pos_byTypeAndPos($PType1_Name, $ParamPos, "forward", $Symbol, 2);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012076 if($#Positions2==-1 or $#Positions2<$#Positions1) {
12077 $ParamPos_New = "lost";
12078 }
12079 }
12080 else {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012081 $ParamPos_New = find_ParamPair_Pos_byName($Parameter_Name, $Symbol, 2);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012082 }
12083 if($ParamPos_New eq "lost")
12084 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012085 if($ParamPos>keys(%{$CompleteSignature{2}{$PSymbol}{"Param"}})-1)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012086 {
12087 my $ProblemType = "Removed_Parameter";
12088 if($Parameter_Name=~/\Ap\d+\Z/) {
12089 $ProblemType = "Removed_Unnamed_Parameter";
12090 }
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040012091 %{$CompatProblems{$Level}{$Symbol}{$ProblemType}{showPos($ParamPos)." Parameter"}}=(
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012092 "Target"=>$Parameter_Name,
12093 "Param_Pos"=>$ParamPos,
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040012094 "Param_Type"=>$PType1_Name,
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012095 "New_Signature"=>get_Signature($Symbol, 2) );
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012096 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012097 elsif($ParamPos<keys(%{$CompleteSignature{1}{$Symbol}{"Param"}})-1)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012098 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040012099 my %ParamType_Pure = get_PureType($PType1_Id, 1);
12100 my $PairType_Id = $CompleteSignature{2}{$PSymbol}{"Param"}{$ParamPos}{"type"};
12101 my %PairType_Pure = get_PureType($PairType_Id, 2);
12102 if(($ParamType_Pure{"Name"} eq $PairType_Pure{"Name"} or $PType1_Name eq $TypeInfo{2}{$PairType_Id}{"Name"})
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012103 and find_ParamPair_Pos_byName($Parameter_NewName, $Symbol, 1) eq "lost")
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012104 {
12105 if($Parameter_NewName!~/\Ap\d+\Z/ and $Parameter_Name!~/\Ap\d+\Z/)
12106 {
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040012107 %{$CompatProblems{$Level}{$Symbol}{"Renamed_Parameter"}{showPos($ParamPos)." Parameter"}}=(
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012108 "Target"=>$Parameter_Name,
12109 "Param_Pos"=>$ParamPos,
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040012110 "Param_Type"=>$PType1_Name,
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012111 "Old_Value"=>$Parameter_Name,
12112 "New_Value"=>$Parameter_NewName,
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012113 "New_Signature"=>get_Signature($Symbol, 2) );
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012114 }
12115 }
12116 else
12117 {
12118 my $ProblemType = "Removed_Middle_Parameter";
12119 if($Parameter_Name=~/\Ap\d+\Z/) {
12120 $ProblemType = "Removed_Middle_Unnamed_Parameter";
12121 }
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040012122 %{$CompatProblems{$Level}{$Symbol}{$ProblemType}{showPos($ParamPos)." Parameter"}}=(
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012123 "Target"=>$Parameter_Name,
12124 "Param_Pos"=>$ParamPos,
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040012125 "Param_Type"=>$PType1_Name,
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012126 "New_Signature"=>get_Signature($Symbol, 2) );
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012127 }
12128 }
12129 }
12130 }
12131 }
12132 # checking return type
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012133 my $ReturnType1_Id = $CompleteSignature{1}{$Symbol}{"Return"};
12134 my $ReturnType2_Id = $CompleteSignature{2}{$PSymbol}{"Return"};
12135 %SubProblems = detectTypeChange($ReturnType1_Id, $ReturnType2_Id, "Return", $Level);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012136 foreach my $SubProblemType (keys(%SubProblems))
12137 {
12138 my $New_Value = $SubProblems{$SubProblemType}{"New_Value"};
12139 my $Old_Value = $SubProblems{$SubProblemType}{"Old_Value"};
12140 my $NewProblemType = $SubProblemType;
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012141 if($Level eq "Binary" and $SubProblemType eq "Return_Type_Became_Void"
12142 and keys(%{$CompleteSignature{1}{$Symbol}{"Param"}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012143 { # parameters stack has been affected
12144 $NewProblemType = "Return_Type_Became_Void_And_Stack_Layout";
12145 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012146 elsif($Level eq "Binary"
12147 and $SubProblemType eq "Return_Type_From_Void")
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012148 { # parameters stack has been affected
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012149 if(keys(%{$CompleteSignature{1}{$Symbol}{"Param"}})) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012150 $NewProblemType = "Return_Type_From_Void_And_Stack_Layout";
12151 }
12152 else
12153 { # safe
12154 delete($SubProblems{$SubProblemType});
12155 next;
12156 }
12157 }
12158 elsif($SubProblemType eq "Return_Type_And_Size"
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012159 and $CompleteSignature{1}{$Symbol}{"Data"}) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012160 $NewProblemType = "Global_Data_Type_And_Size";
12161 }
12162 elsif($SubProblemType eq "Return_Type")
12163 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012164 if($CompleteSignature{1}{$Symbol}{"Data"})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012165 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012166 if(removedQual($Old_Value, $New_Value, "const"))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012167 { # const -> non-const global data
12168 $NewProblemType = "Global_Data_Became_Non_Const";
12169 }
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040012170 elsif(addedQual($Old_Value, $New_Value, "const"))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012171 { # non-const -> const global data
12172 $NewProblemType = "Global_Data_Became_Const";
12173 }
12174 else {
12175 $NewProblemType = "Global_Data_Type";
12176 }
12177 }
12178 else
12179 {
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040012180 if(addedQual($Old_Value, $New_Value, "const")) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012181 $NewProblemType = "Return_Type_Became_Const";
12182 }
12183 }
12184 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012185 elsif($SubProblemType eq "Return_Type_Format")
12186 {
12187 if($CompleteSignature{1}{$Symbol}{"Data"}) {
12188 $NewProblemType = "Global_Data_Type_Format";
12189 }
12190 }
12191 @{$CompatProblems{$Level}{$Symbol}{$NewProblemType}{"retval"}}{keys(%{$SubProblems{$SubProblemType}})} = values %{$SubProblems{$SubProblemType}};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012192 }
12193 if($ReturnType1_Id and $ReturnType2_Id)
12194 {
12195 @RecurTypes = ();
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040012196 %SubProblems = mergeTypes($ReturnType1_Id, $ReturnType2_Id, $Level);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012197 foreach my $SubProblemType (keys(%SubProblems))
12198 { # add "Global_Data_Size" problem
12199 my $New_Value = $SubProblems{$SubProblemType}{"New_Value"};
12200 my $Old_Value = $SubProblems{$SubProblemType}{"Old_Value"};
12201 if($SubProblemType eq "DataType_Size"
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012202 and $CompleteSignature{1}{$Symbol}{"Data"}
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040012203 and get_PLevel($ReturnType1_Id, 1)==0)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012204 { # add a new problem
12205 %{$SubProblems{"Global_Data_Size"}} = %{$SubProblems{$SubProblemType}};
12206 }
12207 }
12208 foreach my $SubProblemType (keys(%SubProblems))
12209 {
12210 foreach my $SubLocation (keys(%{$SubProblems{$SubProblemType}}))
12211 {
12212 my $NewLocation = ($SubLocation)?"retval->".$SubLocation:"retval";
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012213 %{$CompatProblems{$Level}{$Symbol}{$SubProblemType}{$NewLocation}}=(
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040012214 "Return_Type_Name"=>$TypeInfo{1}{$ReturnType1_Id}{"Name"} );
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012215 @{$CompatProblems{$Level}{$Symbol}{$SubProblemType}{$NewLocation}}{keys(%{$SubProblems{$SubProblemType}{$SubLocation}})} = values %{$SubProblems{$SubProblemType}{$SubLocation}};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012216 if($SubLocation!~/\-\>/) {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040012217 $CompatProblems{$Level}{$Symbol}{$SubProblemType}{$NewLocation}{"Start_Type_Name"} = $TypeInfo{1}{$ReturnType1_Id}{"Name"};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012218 }
12219 }
12220 }
12221 }
12222
12223 # checking object type
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040012224 my $ObjTId1 = $CompleteSignature{1}{$Symbol}{"Class"};
12225 my $ObjTId2 = $CompleteSignature{2}{$PSymbol}{"Class"};
12226 if($ObjTId1 and $ObjTId2
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012227 and not $CompleteSignature{1}{$Symbol}{"Static"})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012228 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040012229 my $ThisPtr1_Id = getTypeIdByName($TypeInfo{1}{$ObjTId1}{"Name"}."*const", 1);
12230 my $ThisPtr2_Id = getTypeIdByName($TypeInfo{2}{$ObjTId2}{"Name"}."*const", 2);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012231 if($ThisPtr1_Id and $ThisPtr2_Id)
12232 {
12233 @RecurTypes = ();
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040012234 %SubProblems = mergeTypes($ThisPtr1_Id, $ThisPtr2_Id, $Level);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012235 foreach my $SubProblemType (keys(%SubProblems))
12236 {
12237 foreach my $SubLocation (keys(%{$SubProblems{$SubProblemType}}))
12238 {
12239 my $NewLocation = ($SubLocation)?"this->".$SubLocation:"this";
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012240 %{$CompatProblems{$Level}{$Symbol}{$SubProblemType}{$NewLocation}}=(
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040012241 "Object_Type_Name"=>$TypeInfo{1}{$ObjTId1}{"Name"} );
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012242 @{$CompatProblems{$Level}{$Symbol}{$SubProblemType}{$NewLocation}}{keys(%{$SubProblems{$SubProblemType}{$SubLocation}})} = values %{$SubProblems{$SubProblemType}{$SubLocation}};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012243 if($SubLocation!~/\-\>/) {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040012244 $CompatProblems{$Level}{$Symbol}{$SubProblemType}{$NewLocation}{"Start_Type_Name"} = $TypeInfo{1}{$ObjTId1}{"Name"};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012245 }
12246 }
12247 }
12248 }
12249 }
12250 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012251 if($Level eq "Binary") {
12252 mergeVTables($Level);
12253 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +040012254 foreach my $Symbol (keys(%{$CompatProblems{$Level}})) {
12255 $CheckedSymbols{$Level}{$Symbol} = 1;
12256 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012257}
12258
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040012259sub rmQuals($$)
12260{
12261 my ($Value, $Qual) = @_;
12262 if(not $Qual) {
12263 return $Value;
12264 }
12265 if($Qual eq "all")
12266 { # all quals
12267 $Qual = "const|volatile|restrict";
12268 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040012269 while($Value=~s/\b$Qual\b//) {
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040012270 $Value = formatName($Value);
12271 }
12272 return $Value;
12273}
12274
12275sub cmpBTypes($$$$)
12276{
12277 my ($T1, $T2, $V1, $V2) = @_;
12278 $T1 = uncover_typedefs($T1, $V1);
12279 $T2 = uncover_typedefs($T2, $V2);
12280 return (rmQuals($T1, "all") eq rmQuals($T2, "all"));
12281}
12282
12283sub addedQual($$$)
12284{
12285 my ($Old_Value, $New_Value, $Qual) = @_;
Andrey Ponomarenko85043792012-05-14 16:48:07 +040012286 return removedQual_($New_Value, $Old_Value, 2, 1, $Qual);
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040012287}
12288
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012289sub removedQual($$$)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012290{
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012291 my ($Old_Value, $New_Value, $Qual) = @_;
Andrey Ponomarenko85043792012-05-14 16:48:07 +040012292 return removedQual_($Old_Value, $New_Value, 1, 2, $Qual);
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040012293}
12294
12295sub removedQual_($$$$$)
12296{
12297 my ($Old_Value, $New_Value, $V1, $V2, $Qual) = @_;
12298 $Old_Value = uncover_typedefs($Old_Value, $V1);
12299 $New_Value = uncover_typedefs($New_Value, $V2);
12300 if($Old_Value eq $New_Value)
12301 { # equal types
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012302 return 0;
12303 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040012304 if($Old_Value!~/\b$Qual\b/)
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040012305 { # without a qual
12306 return 0;
12307 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040012308 elsif($New_Value!~/\b$Qual\b/)
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040012309 { # became non-qual
12310 return 1;
12311 }
12312 else
12313 {
12314 my @BQ1 = getQualModel($Old_Value, $Qual);
12315 my @BQ2 = getQualModel($New_Value, $Qual);
12316 foreach (0 .. $#BQ1)
12317 { # removed qual
12318 if($BQ1[$_]==1
12319 and $BQ2[$_]!=1)
12320 {
12321 return 2;
12322 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012323 }
12324 }
12325 return 0;
12326}
12327
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040012328sub getQualModel($$)
12329{
12330 my ($Value, $Qual) = @_;
12331 if(not $Qual) {
12332 return $Value;
12333 }
12334
12335 # cleaning
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040012336 while($Value=~/(\w+)/ and $1 ne $Qual) {
12337 $Value=~s/\b$1\b//g;
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040012338 }
12339 $Value=~s/[^\*\&\w]+//g;
12340
12341 # modeling
12342 # int*const*const == 011
12343 # int**const == 001
12344 my @Model = ();
12345 my @Elems = split(/[\*\&]/, $Value);
12346 if(not @Elems) {
12347 return (0);
12348 }
12349 foreach (@Elems)
12350 {
12351 if($_ eq $Qual) {
12352 push(@Model, 1);
12353 }
12354 else {
12355 push(@Model, 0);
12356 }
12357 }
12358
12359 return @Model;
12360}
12361
12362sub showVal($$$)
12363{
12364 my ($Value, $TypeId, $LibVersion) = @_;
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040012365 my %PureType = get_PureType($TypeId, $LibVersion);
Andrey Ponomarenkoa01311b2012-06-08 17:20:02 +040012366 my $TName = uncover_typedefs($PureType{"Name"}, $LibVersion);
12367 if($TName=~/\A(char(| const)\*|std::(string|basic_string<char>)(|&))\Z/)
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040012368 { # strings
12369 return "\"$Value\"";
12370 }
Andrey Ponomarenkoa01311b2012-06-08 17:20:02 +040012371 elsif($TName=~/\Achar(| const)\Z/)
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040012372 { # characters
12373 return "\'$Value\'";
12374 }
12375 return $Value;
12376}
12377
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012378sub mergeParameters($$$$$)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012379{
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012380 my ($Symbol, $PSymbol, $ParamPos1, $ParamPos2, $Level) = @_;
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040012381 if(not $Symbol) {
12382 return;
12383 }
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040012384 my $PType1_Id = $CompleteSignature{1}{$Symbol}{"Param"}{$ParamPos1}{"type"};
12385 my $PName1 = $CompleteSignature{1}{$Symbol}{"Param"}{$ParamPos1}{"name"};
12386 my $PType2_Id = $CompleteSignature{2}{$PSymbol}{"Param"}{$ParamPos2}{"type"};
12387 my $PName2 = $CompleteSignature{2}{$PSymbol}{"Param"}{$ParamPos2}{"name"};
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040012388 if(not $PType1_Id
12389 or not $PType2_Id) {
12390 return;
12391 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040012392 my %Type1 = get_Type($PType1_Id, 1);
12393 my %Type2 = get_Type($PType2_Id, 2);
12394 my %BaseType1 = get_BaseType($PType1_Id, 1);
12395 my %BaseType2 = get_BaseType($PType2_Id, 2);
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040012396 my $Parameter_Location = ($PName1)?$PName1:showPos($ParamPos1)." Parameter";
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012397 if($Level eq "Binary")
12398 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040012399 if(checkDump(1, "2.6.1") and checkDump(2, "2.6.1"))
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012400 { # "reg" attribute added in ACC 1.95.1 (dump 2.6.1 format)
12401 if($CompleteSignature{1}{$Symbol}{"Param"}{$ParamPos1}{"reg"}
12402 and not $CompleteSignature{2}{$PSymbol}{"Param"}{$ParamPos2}{"reg"})
12403 {
12404 %{$CompatProblems{$Level}{$Symbol}{"Parameter_Became_Non_Register"}{$Parameter_Location}}=(
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040012405 "Target"=>$PName1,
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012406 "Param_Pos"=>$ParamPos1 );
12407 }
12408 elsif(not $CompleteSignature{1}{$Symbol}{"Param"}{$ParamPos1}{"reg"}
12409 and $CompleteSignature{2}{$PSymbol}{"Param"}{$ParamPos2}{"reg"})
12410 {
12411 %{$CompatProblems{$Level}{$Symbol}{"Parameter_Became_Register"}{$Parameter_Location}}=(
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040012412 "Target"=>$PName1,
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012413 "Param_Pos"=>$ParamPos1 );
12414 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012415 }
12416 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040012417 if(checkDump(1, "2.0") and checkDump(2, "2.0"))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012418 { # "default" attribute added in ACC 1.22 (dump 2.0 format)
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040012419 my $Value_Old = $CompleteSignature{1}{$Symbol}{"Param"}{$ParamPos1}{"default"};
12420 my $Value_New = $CompleteSignature{2}{$PSymbol}{"Param"}{$ParamPos2}{"default"};
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040012421 if(not checkDump(1, "2.13")
12422 and checkDump(2, "2.13"))
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040012423 { # support for old ABI dumps
12424 if(defined $Value_Old and defined $Value_New)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012425 {
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040012426 if($Type1{"Name"} eq "bool"
12427 and $Value_Old eq "false" and $Value_New eq "0")
12428 { # int class::method ( bool p = 0 );
12429 # old ABI dumps: "false"
12430 # new ABI dumps: "0"
12431 $Value_Old = "0";
12432 }
12433 }
12434 }
12435 if(defined $Value_Old)
12436 {
12437 $Value_Old = showVal($Value_Old, $PType1_Id, 1);
12438 if(defined $Value_New)
12439 {
12440 $Value_New = showVal($Value_New, $PType2_Id, 2);
12441 if($Value_Old ne $Value_New)
12442 { # FIXME: how to distinguish "0" and 0 (NULL)
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012443 %{$CompatProblems{$Level}{$Symbol}{"Parameter_Default_Value_Changed"}{$Parameter_Location}}=(
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040012444 "Target"=>$PName1,
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012445 "Param_Pos"=>$ParamPos1,
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040012446 "Old_Value"=>$Value_Old,
12447 "New_Value"=>$Value_New );
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012448 }
12449 }
12450 else
12451 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012452 %{$CompatProblems{$Level}{$Symbol}{"Parameter_Default_Value_Removed"}{$Parameter_Location}}=(
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040012453 "Target"=>$PName1,
12454 "Param_Pos"=>$ParamPos1,
12455 "Old_Value"=>$Value_Old );
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012456 }
12457 }
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040012458 elsif(defined $Value_New)
12459 {
12460 $Value_New = showVal($Value_New, $PType2_Id, 2);
12461 %{$CompatProblems{$Level}{$Symbol}{"Parameter_Default_Value_Added"}{$Parameter_Location}}=(
12462 "Target"=>$PName1,
12463 "Param_Pos"=>$ParamPos1,
12464 "New_Value"=>$Value_New );
12465 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012466 }
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040012467 if($PName1 and $PName2 and $PName1 ne $PName2
12468 and $PType1_Id!=-1 and $PType2_Id!=-1
12469 and $PName1!~/\Ap\d+\Z/ and $PName2!~/\Ap\d+\Z/)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012470 { # except unnamed "..." value list (Id=-1)
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040012471 %{$CompatProblems{$Level}{$Symbol}{"Renamed_Parameter"}{showPos($ParamPos1)." Parameter"}}=(
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040012472 "Target"=>$PName1,
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012473 "Param_Pos"=>$ParamPos1,
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040012474 "Param_Type"=>$TypeInfo{1}{$PType1_Id}{"Name"},
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040012475 "Old_Value"=>$PName1,
12476 "New_Value"=>$PName2,
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012477 "New_Signature"=>get_Signature($Symbol, 2) );
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012478 }
12479 # checking type change (replace)
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040012480 my %SubProblems = detectTypeChange($PType1_Id, $PType2_Id, "Parameter", $Level);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012481 foreach my $SubProblemType (keys(%SubProblems))
12482 { # add new problems, remove false alarms
12483 my $New_Value = $SubProblems{$SubProblemType}{"New_Value"};
12484 my $Old_Value = $SubProblems{$SubProblemType}{"Old_Value"};
12485 if($SubProblemType eq "Parameter_Type")
12486 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040012487 if(checkDump(1, "2.6") and checkDump(2, "2.6"))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012488 {
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040012489 if(my $RA = addedQual($Old_Value, $New_Value, "restrict"))
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012490 {
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040012491 %{$SubProblems{"Parameter_Became_Restrict"}} = %{$SubProblems{$SubProblemType}};
12492 if($Level eq "Source"
12493 and cmpBTypes($Old_Value, $New_Value, 1, 2)) {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012494 delete($SubProblems{$SubProblemType});
12495 }
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040012496 }
12497 elsif(my $RR = removedQual($Old_Value, $New_Value, "restrict"))
12498 {
12499 %{$SubProblems{"Parameter_Became_NonRestrict"}} = %{$SubProblems{$SubProblemType}};
12500 if($Level eq "Source"
12501 and cmpBTypes($Old_Value, $New_Value, 1, 2)) {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012502 delete($SubProblems{$SubProblemType});
12503 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012504 }
12505 }
12506 if($Type2{"Type"} eq "Const" and $BaseType2{"Name"} eq $Type1{"Name"}
12507 and $Type1{"Type"}=~/Intrinsic|Class|Struct|Union|Enum/)
12508 { # int to "int const"
12509 delete($SubProblems{$SubProblemType});
12510 }
12511 if($Type1{"Type"} eq "Const" and $BaseType1{"Name"} eq $Type2{"Name"}
12512 and $Type2{"Type"}=~/Intrinsic|Class|Struct|Union|Enum/)
12513 { # "int const" to int
12514 delete($SubProblems{$SubProblemType});
12515 }
12516 }
12517 }
12518 foreach my $SubProblemType (keys(%SubProblems))
12519 { # modify/register problems
12520 my $New_Value = $SubProblems{$SubProblemType}{"New_Value"};
12521 my $Old_Value = $SubProblems{$SubProblemType}{"Old_Value"};
12522 my $NewProblemType = $SubProblemType;
12523 if($Old_Value eq "..." and $New_Value ne "...")
12524 { # change from "..." to "int"
12525 if($ParamPos1==0)
12526 { # ISO C requires a named argument before "..."
12527 next;
12528 }
12529 $NewProblemType = "Parameter_Became_NonVaList";
12530 }
12531 elsif($New_Value eq "..." and $Old_Value ne "...")
12532 { # change from "int" to "..."
12533 if($ParamPos2==0)
12534 { # ISO C requires a named argument before "..."
12535 next;
12536 }
12537 $NewProblemType = "Parameter_Became_VaList";
12538 }
12539 elsif($SubProblemType eq "Parameter_Type"
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012540 and removedQual($Old_Value, $New_Value, "const"))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012541 { # parameter: "const" to non-"const"
12542 $NewProblemType = "Parameter_Became_Non_Const";
12543 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012544 elsif($Level eq "Binary" and ($SubProblemType eq "Parameter_Type_And_Size"
12545 or $SubProblemType eq "Parameter_Type"))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012546 {
12547 my ($Arch1, $Arch2) = (getArch(1), getArch(2));
12548 if($Arch1 eq "unknown" or $Arch2 eq "unknown")
12549 { # if one of the architectures is unknown
12550 # then set other arhitecture to unknown too
12551 ($Arch1, $Arch2) = ("unknown", "unknown");
12552 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012553 my ($Method1, $Passed1, $SizeOnStack1, $RegName1) = callingConvention($Symbol, $ParamPos1, 1, $Arch1);
12554 my ($Method2, $Passed2, $SizeOnStack2, $RegName2) = callingConvention($Symbol, $ParamPos2, 2, $Arch2);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012555 if($Method1 eq $Method2)
12556 {
12557 if($Method1 eq "stack" and $SizeOnStack1 ne $SizeOnStack2) {
12558 $NewProblemType = "Parameter_Type_And_Stack";
12559 }
12560 elsif($Method1 eq "register" and $RegName1 ne $RegName2) {
12561 $NewProblemType = "Parameter_Type_And_Register";
12562 }
12563 }
12564 else
12565 {
12566 if($Method1 eq "stack") {
12567 $NewProblemType = "Parameter_Type_And_Pass_Through_Register";
12568 }
12569 elsif($Method1 eq "register") {
12570 $NewProblemType = "Parameter_Type_And_Pass_Through_Stack";
12571 }
12572 }
12573 $SubProblems{$SubProblemType}{"Old_Reg"} = $RegName1;
12574 $SubProblems{$SubProblemType}{"New_Reg"} = $RegName2;
12575 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012576 %{$CompatProblems{$Level}{$Symbol}{$NewProblemType}{$Parameter_Location}}=(
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040012577 "Target"=>$PName1,
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012578 "Param_Pos"=>$ParamPos1,
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012579 "New_Signature"=>get_Signature($Symbol, 2) );
12580 @{$CompatProblems{$Level}{$Symbol}{$NewProblemType}{$Parameter_Location}}{keys(%{$SubProblems{$SubProblemType}})} = values %{$SubProblems{$SubProblemType}};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012581 }
12582 @RecurTypes = ();
12583 # checking type definition changes
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040012584 my %SubProblems_Merge = mergeTypes($PType1_Id, $PType2_Id, $Level);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012585 foreach my $SubProblemType (keys(%SubProblems_Merge))
12586 {
12587 foreach my $SubLocation (keys(%{$SubProblems_Merge{$SubProblemType}}))
12588 {
12589 my $NewProblemType = $SubProblemType;
12590 if($SubProblemType eq "DataType_Size")
12591 {
12592 my $InitialType_Type = $SubProblems_Merge{$SubProblemType}{$SubLocation}{"InitialType_Type"};
12593 if($InitialType_Type!~/\A(Pointer|Ref)\Z/ and $SubLocation!~/\-\>/)
12594 { # stack has been affected
12595 $NewProblemType = "DataType_Size_And_Stack";
12596 }
12597 }
12598 my $NewLocation = ($SubLocation)?$Parameter_Location."->".$SubLocation:$Parameter_Location;
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012599 %{$CompatProblems{$Level}{$Symbol}{$NewProblemType}{$NewLocation}}=(
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040012600 "Param_Type"=>$TypeInfo{1}{$PType1_Id}{"Name"},
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012601 "Param_Pos"=>$ParamPos1,
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040012602 "Param_Name"=>$PName1 );
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012603 @{$CompatProblems{$Level}{$Symbol}{$NewProblemType}{$NewLocation}}{keys(%{$SubProblems_Merge{$SubProblemType}{$SubLocation}})} = values %{$SubProblems_Merge{$SubProblemType}{$SubLocation}};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012604 if($SubLocation!~/\-\>/) {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040012605 $CompatProblems{$Level}{$Symbol}{$NewProblemType}{$NewLocation}{"Start_Type_Name"} = $TypeInfo{1}{$PType1_Id}{"Name"};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012606 }
12607 }
12608 }
12609}
12610
12611sub callingConvention($$$$)
12612{ # calling conventions for different compilers and operating systems
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012613 my ($Symbol, $ParamPos, $LibVersion, $Arch) = @_;
12614 my $ParamTypeId = $CompleteSignature{$LibVersion}{$Symbol}{"Param"}{$ParamPos}{"type"};
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040012615 my %Type = get_PureType($ParamTypeId, $LibVersion);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012616 my ($Method, $Alignment, $Passed, $Register) = ("", 0, "", "");
12617 if($OSgroup=~/\A(linux|macos|freebsd)\Z/)
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012618 { # GCC
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012619 if($Arch eq "x86")
12620 { # System V ABI Intel386 ("Function Calling Sequence")
12621 # The stack is word aligned. Although the architecture does not require any
12622 # alignment of the stack, software convention and the operating system
12623 # requires that the stack be aligned on a word boundary.
12624
12625 # Argument words are pushed onto the stack in reverse order (that is, the
12626 # rightmost argument in C call syntax has the highest address), preserving the
12627 # stack’s word alignment. All incoming arguments appear on the stack, residing
12628 # in the stack frame of the caller.
12629
12630 # An argument’s size is increased, if necessary, to make it a multiple of words.
12631 # This may require tail padding, depending on the size of the argument.
12632
12633 # Other areas depend on the compiler and the code being compiled. The stan-
12634 # dard calling sequence does not define a maximum stack frame size, nor does
12635 # it restrict how a language system uses the ‘‘unspecified’’ area of the stan-
12636 # dard stack frame.
12637 ($Method, $Alignment) = ("stack", 4);
12638 }
12639 elsif($Arch eq "x86_64")
12640 { # System V AMD64 ABI ("Function Calling Sequence")
12641 ($Method, $Alignment) = ("stack", 8);# eightbyte aligned
12642 }
12643 elsif($Arch eq "arm")
12644 { # Procedure Call Standard for the ARM Architecture
12645 # The stack must be double-word aligned
12646 ($Method, $Alignment) = ("stack", 8);# double-word
12647 }
12648 }
12649 elsif($OSgroup eq "windows")
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012650 { # MS C++ Compiler
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012651 if($Arch eq "x86")
12652 {
12653 if($ParamPos==0) {
12654 ($Method, $Register, $Passed) = ("register", "ecx", "value");
12655 }
12656 elsif($ParamPos==1) {
12657 ($Method, $Register, $Passed) = ("register", "edx", "value");
12658 }
12659 else {
12660 ($Method, $Alignment) = ("stack", 4);
12661 }
12662 }
12663 elsif($Arch eq "x86_64")
12664 {
12665 if($ParamPos<=3)
12666 {
12667 if($Type{"Name"}=~/\A(float|double|long double)\Z/) {
12668 ($Method, $Passed) = ("xmm".$ParamPos, "value");
12669 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040012670 elsif(isScalar($Type{"Name"})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012671 or $Type{"Type"}=~/\A(Struct|Union|Enum|Array)\Z/
12672 or $Type{"Name"}=~/\A(__m64|__m128)\Z/)
12673 {
12674 if($ParamPos==0) {
12675 ($Method, $Register, $Passed) = ("register", "rcx", "value");
12676 }
12677 elsif($ParamPos==1) {
12678 ($Method, $Register, $Passed) = ("register", "rdx", "value");
12679 }
12680 elsif($ParamPos==2) {
12681 ($Method, $Register, $Passed) = ("register", "r8", "value");
12682 }
12683 elsif($ParamPos==3) {
12684 ($Method, $Register, $Passed) = ("register", "r9", "value");
12685 }
12686 if($Type{"Size"}>64
12687 or $Type{"Type"} eq "Array") {
12688 $Passed = "pointer";
12689 }
12690 }
12691 }
12692 else {
12693 ($Method, $Alignment) = ("stack", 8);# word alignment
12694 }
12695 }
12696 }
12697 if($Method eq "register") {
12698 return ("register", $Passed, "", $Register);
12699 }
12700 else
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012701 { # on the stack
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012702 if(not $Alignment)
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012703 { # default convention
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012704 $Alignment = $WORD_SIZE{$LibVersion};
12705 }
12706 if(not $Passed)
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012707 { # default convention
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012708 $Passed = "value";
12709 }
12710 my $SizeOnStack = $Type{"Size"};
12711 # FIXME: improve stack alignment
12712 if($SizeOnStack!=$Alignment) {
12713 $SizeOnStack = int(($Type{"Size"}+$Alignment)/$Alignment)*$Alignment;
12714 }
12715 return ("stack", $Passed, $SizeOnStack, "");
12716 }
12717}
12718
12719sub find_ParamPair_Pos_byName($$$)
12720{
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012721 my ($Name, $Symbol, $LibVersion) = @_;
12722 foreach my $ParamPos (sort {int($a)<=>int($b)} keys(%{$CompleteSignature{$LibVersion}{$Symbol}{"Param"}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012723 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012724 next if(not defined $CompleteSignature{$LibVersion}{$Symbol}{"Param"}{$ParamPos});
12725 if($CompleteSignature{$LibVersion}{$Symbol}{"Param"}{$ParamPos}{"name"} eq $Name)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012726 {
12727 return $ParamPos;
12728 }
12729 }
12730 return "lost";
12731}
12732
12733sub find_ParamPair_Pos_byTypeAndPos($$$$$)
12734{
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012735 my ($TypeName, $MediumPos, $Order, $Symbol, $LibVersion) = @_;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012736 my @Positions = ();
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012737 foreach my $ParamPos (sort {int($a)<=>int($b)} keys(%{$CompleteSignature{$LibVersion}{$Symbol}{"Param"}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012738 {
12739 next if($Order eq "backward" and $ParamPos>$MediumPos);
12740 next if($Order eq "forward" and $ParamPos<$MediumPos);
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012741 next if(not defined $CompleteSignature{$LibVersion}{$Symbol}{"Param"}{$ParamPos});
12742 my $PTypeId = $CompleteSignature{$LibVersion}{$Symbol}{"Param"}{$ParamPos}{"type"};
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040012743 if($TypeInfo{$LibVersion}{$PTypeId}{"Name"} eq $TypeName) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012744 push(@Positions, $ParamPos);
12745 }
12746 }
12747 return @Positions;
12748}
12749
12750sub getTypeIdByName($$)
12751{
12752 my ($TypeName, $Version) = @_;
12753 return $TName_Tid{$Version}{formatName($TypeName)};
12754}
12755
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012756sub checkFormatChange($$$)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012757{
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012758 my ($Type1_Id, $Type2_Id, $Level) = @_;
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040012759 my %Type1_Pure = get_PureType($Type1_Id, 1);
12760 my %Type2_Pure = get_PureType($Type2_Id, 2);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012761 if($Type1_Pure{"Name"} eq $Type2_Pure{"Name"})
12762 { # equal types
12763 return 0;
12764 }
12765 if($Type1_Pure{"Name"}=~/\*/
12766 or $Type2_Pure{"Name"}=~/\*/)
12767 { # compared in detectTypeChange()
12768 return 0;
12769 }
12770 my %FloatType = map {$_=>1} (
12771 "float",
12772 "double",
12773 "long double"
12774 );
12775 if($Type1_Pure{"Type"} ne $Type2_Pure{"Type"})
12776 { # different types
12777 if($Type1_Pure{"Type"} eq "Intrinsic"
12778 and $Type2_Pure{"Type"} eq "Enum")
12779 { # "int" to "enum"
12780 return 0;
12781 }
12782 elsif($Type2_Pure{"Type"} eq "Intrinsic"
12783 and $Type1_Pure{"Type"} eq "Enum")
12784 { # "enum" to "int"
12785 return 0;
12786 }
12787 else
12788 { # "union" to "struct"
12789 # ...
12790 return 1;
12791 }
12792 }
12793 else
12794 {
12795 if($Type1_Pure{"Type"} eq "Intrinsic")
12796 {
12797 if($FloatType{$Type1_Pure{"Name"}}
12798 or $FloatType{$Type2_Pure{"Name"}})
12799 { # "float" to "double"
12800 # "float" to "int"
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012801 if($Level eq "Source")
12802 { # Safe
12803 return 0;
12804 }
12805 else {
12806 return 1;
12807 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012808 }
12809 }
12810 elsif($Type1_Pure{"Type"}=~/Class|Struct|Union|Enum/)
12811 {
12812 my @Membs1 = keys(%{$Type1_Pure{"Memb"}});
12813 my @Membs2 = keys(%{$Type2_Pure{"Memb"}});
12814 if($#Membs1!=$#Membs2)
12815 { # different number of elements
12816 return 1;
12817 }
12818 if($Type1_Pure{"Type"} eq "Enum")
12819 {
12820 foreach my $Pos (@Membs1)
12821 { # compare elements by name and value
12822 if($Type1_Pure{"Memb"}{$Pos}{"name"} ne $Type2_Pure{"Memb"}{$Pos}{"name"}
12823 or $Type1_Pure{"Memb"}{$Pos}{"value"} ne $Type2_Pure{"Memb"}{$Pos}{"value"})
12824 { # different names
12825 return 1;
12826 }
12827 }
12828 }
12829 else
12830 {
12831 foreach my $Pos (@Membs1)
12832 { # compare elements by type name
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040012833 my $MT1 = $TypeInfo{1}{$Type1_Pure{"Memb"}{$Pos}{"type"}}{"Name"};
12834 my $MT2 = $TypeInfo{2}{$Type2_Pure{"Memb"}{$Pos}{"type"}}{"Name"};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012835 if($MT1 ne $MT2)
12836 { # different types
12837 return 1;
12838 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012839 if($Level eq "Source")
12840 {
12841 if($Type1_Pure{"Memb"}{$Pos}{"name"} ne $Type2_Pure{"Memb"}{$Pos}{"name"})
12842 { # different names
12843 return 1;
12844 }
12845 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012846 }
12847 }
12848 }
12849 }
12850 return 0;
12851}
12852
12853sub isScalar($) {
12854 return ($_[0]=~/\A(unsigned |)(short|int|long|long long)\Z/);
12855}
12856
12857sub isFloat($) {
12858 return ($_[0]=~/\A(float|double|long double)\Z/);
12859}
12860
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012861sub detectTypeChange($$$$)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012862{
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012863 my ($Type1_Id, $Type2_Id, $Prefix, $Level) = @_;
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040012864 if(not $Type1_Id or not $Type2_Id) {
12865 return ();
12866 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012867 my %LocalProblems = ();
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040012868 my %Type1 = get_Type($Type1_Id, 1);
12869 my %Type2 = get_Type($Type2_Id, 2);
12870 my %Type1_Pure = get_PureType($Type1_Id, 1);
12871 my %Type2_Pure = get_PureType($Type2_Id, 2);
12872 my %Type1_Base = ($Type1_Pure{"Type"} eq "Array")?get_OneStep_BaseType($Type1_Pure{"Tid"}, 1):get_BaseType($Type1_Id, 1);
12873 my %Type2_Base = ($Type2_Pure{"Type"} eq "Array")?get_OneStep_BaseType($Type2_Pure{"Tid"}, 2):get_BaseType($Type2_Id, 2);
12874 my $Type1_PLevel = get_PLevel($Type1_Id, 1);
12875 my $Type2_PLevel = get_PLevel($Type2_Id, 2);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012876 return () if(not $Type1{"Name"} or not $Type2{"Name"});
12877 return () if(not $Type1_Base{"Name"} or not $Type2_Base{"Name"});
12878 return () if($Type1_PLevel eq "" or $Type2_PLevel eq "");
12879 if($Type1_Base{"Name"} ne $Type2_Base{"Name"}
12880 and ($Type1{"Name"} eq $Type2{"Name"} or ($Type1_PLevel>=1 and $Type1_PLevel==$Type2_PLevel
12881 and $Type1_Base{"Name"} ne "void" and $Type2_Base{"Name"} ne "void")))
12882 { # base type change
12883 if($Type1{"Type"} eq "Typedef" and $Type2{"Type"} eq "Typedef"
12884 and $Type1{"Name"} eq $Type2{"Name"})
12885 { # will be reported in mergeTypes() as typedef problem
12886 return ();
12887 }
12888 if($Type1_Base{"Name"}!~/anon\-/ and $Type2_Base{"Name"}!~/anon\-/)
12889 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012890 if($Level eq "Binary"
12891 and $Type1_Base{"Size"} ne $Type2_Base{"Size"}
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012892 and $Type1_Base{"Size"} and $Type2_Base{"Size"})
12893 {
12894 %{$LocalProblems{$Prefix."_BaseType_And_Size"}}=(
12895 "Old_Value"=>$Type1_Base{"Name"},
12896 "New_Value"=>$Type2_Base{"Name"},
12897 "Old_Size"=>$Type1_Base{"Size"}*$BYTE_SIZE,
12898 "New_Size"=>$Type2_Base{"Size"}*$BYTE_SIZE,
12899 "InitialType_Type"=>$Type1_Pure{"Type"});
12900 }
12901 else
12902 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012903 if(checkFormatChange($Type1_Base{"Tid"}, $Type2_Base{"Tid"}, $Level))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012904 { # format change
12905 %{$LocalProblems{$Prefix."_BaseType_Format"}}=(
12906 "Old_Value"=>$Type1_Base{"Name"},
12907 "New_Value"=>$Type2_Base{"Name"},
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012908 "InitialType_Type"=>$Type1_Pure{"Type"});
12909 }
12910 elsif(tNameLock($Type1_Base{"Tid"}, $Type2_Base{"Tid"}))
12911 {
12912 %{$LocalProblems{$Prefix."_BaseType"}}=(
12913 "Old_Value"=>$Type1_Base{"Name"},
12914 "New_Value"=>$Type2_Base{"Name"},
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012915 "InitialType_Type"=>$Type1_Pure{"Type"});
12916 }
12917 }
12918 }
12919 }
12920 elsif($Type1{"Name"} ne $Type2{"Name"})
12921 { # type change
12922 if($Type1{"Name"}!~/anon\-/ and $Type2{"Name"}!~/anon\-/)
12923 {
12924 if($Prefix eq "Return" and $Type1{"Name"} eq "void"
12925 and $Type2_Pure{"Type"}=~/Intrinsic|Enum/) {
12926 # safe change
12927 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012928 elsif($Level eq "Binary"
12929 and $Prefix eq "Return"
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012930 and $Type1_Pure{"Name"} eq "void")
12931 {
12932 %{$LocalProblems{"Return_Type_From_Void"}}=(
12933 "New_Value"=>$Type2{"Name"},
12934 "New_Size"=>$Type2{"Size"}*$BYTE_SIZE,
12935 "InitialType_Type"=>$Type1_Pure{"Type"});
12936 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012937 elsif($Level eq "Binary"
12938 and $Prefix eq "Return" and $Type1_Pure{"Type"}=~/Intrinsic|Enum/
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012939 and $Type2_Pure{"Type"}=~/Struct|Class|Union/)
12940 { # returns into hidden first parameter instead of a register
12941
12942 # System V ABI Intel386 ("Function Calling Sequence")
12943 # A function that returns an integral or pointer value places its result in register %eax.
12944
12945 # A floating-point return value appears on the top of the Intel387 register stack. The
12946 # caller then must remove the value from the Intel387 stack, even if it doesn’t use the
12947 # value.
12948
12949 # If a function returns a structure or union, then the caller provides space for the
12950 # return value and places its address on the stack as argument word zero. In effect,
12951 # this address becomes a ‘‘hidden’’ first argument.
12952
12953 %{$LocalProblems{"Return_Type_From_Register_To_Stack"}}=(
12954 "Old_Value"=>$Type1{"Name"},
12955 "New_Value"=>$Type2{"Name"},
12956 "Old_Size"=>$Type1{"Size"}*$BYTE_SIZE,
12957 "New_Size"=>$Type2{"Size"}*$BYTE_SIZE,
12958 "InitialType_Type"=>$Type1_Pure{"Type"});
12959 }
12960 elsif($Prefix eq "Return"
12961 and $Type2_Pure{"Name"} eq "void")
12962 {
12963 %{$LocalProblems{"Return_Type_Became_Void"}}=(
12964 "Old_Value"=>$Type1{"Name"},
12965 "Old_Size"=>$Type1{"Size"}*$BYTE_SIZE,
12966 "InitialType_Type"=>$Type1_Pure{"Type"});
12967 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012968 elsif($Level eq "Binary" and $Prefix eq "Return"
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012969 and ((isScalar($Type1_Pure{"Name"}) and isFloat($Type2_Pure{"Name"}))
12970 or (isScalar($Type2_Pure{"Name"}) and isFloat($Type1_Pure{"Name"}))))
12971 { # The scalar and floating-point values are passed in different registers
12972 %{$LocalProblems{"Return_Type_And_Register"}}=(
12973 "Old_Value"=>$Type1{"Name"},
12974 "New_Value"=>$Type2{"Name"},
12975 "Old_Size"=>$Type1{"Size"}*$BYTE_SIZE,
12976 "New_Size"=>$Type2{"Size"}*$BYTE_SIZE,
12977 "InitialType_Type"=>$Type1_Pure{"Type"});
12978 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012979 elsif($Level eq "Binary"
12980 and $Prefix eq "Return" and $Type2_Pure{"Type"}=~/Intrinsic|Enum/
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012981 and $Type1_Pure{"Type"}=~/Struct|Class|Union/)
12982 { # returns in a register instead of a hidden first parameter
12983 %{$LocalProblems{"Return_Type_From_Stack_To_Register"}}=(
12984 "Old_Value"=>$Type1{"Name"},
12985 "New_Value"=>$Type2{"Name"},
12986 "Old_Size"=>$Type1{"Size"}*$BYTE_SIZE,
12987 "New_Size"=>$Type2{"Size"}*$BYTE_SIZE,
12988 "InitialType_Type"=>$Type1_Pure{"Type"});
12989 }
12990 else
12991 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012992 if($Level eq "Binary"
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040012993 and $Type1{"Size"} and $Type2{"Size"}
12994 and $Type1{"Size"} ne $Type2{"Size"})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012995 {
12996 %{$LocalProblems{$Prefix."_Type_And_Size"}}=(
12997 "Old_Value"=>$Type1{"Name"},
12998 "New_Value"=>$Type2{"Name"},
12999 "Old_Size"=>$Type1{"Size"}*$BYTE_SIZE,
13000 "New_Size"=>$Type2{"Size"}*$BYTE_SIZE,
13001 "InitialType_Type"=>$Type1_Pure{"Type"});
13002 }
13003 else
13004 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040013005 if(checkFormatChange($Type1_Id, $Type2_Id, $Level))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013006 { # format change
13007 %{$LocalProblems{$Prefix."_Type_Format"}}=(
13008 "Old_Value"=>$Type1{"Name"},
13009 "New_Value"=>$Type2{"Name"},
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013010 "InitialType_Type"=>$Type1_Pure{"Type"});
13011 }
13012 elsif(tNameLock($Type1_Id, $Type2_Id))
13013 { # FIXME: correct this condition
13014 %{$LocalProblems{$Prefix."_Type"}}=(
13015 "Old_Value"=>$Type1{"Name"},
13016 "New_Value"=>$Type2{"Name"},
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013017 "InitialType_Type"=>$Type1_Pure{"Type"});
13018 }
13019 }
13020 }
13021 }
13022 }
13023 if($Type1_PLevel!=$Type2_PLevel)
13024 {
13025 if($Type1{"Name"} ne "void" and $Type1{"Name"} ne "..."
13026 and $Type2{"Name"} ne "void" and $Type2{"Name"} ne "...")
13027 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040013028 if($Level eq "Source")
13029 {
13030 %{$LocalProblems{$Prefix."_PointerLevel"}}=(
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013031 "Old_Value"=>$Type1_PLevel,
13032 "New_Value"=>$Type2_PLevel);
13033 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040013034 else
13035 {
13036 if($Type2_PLevel>$Type1_PLevel) {
13037 %{$LocalProblems{$Prefix."_PointerLevel_Increased"}}=(
13038 "Old_Value"=>$Type1_PLevel,
13039 "New_Value"=>$Type2_PLevel);
13040 }
13041 else {
13042 %{$LocalProblems{$Prefix."_PointerLevel_Decreased"}}=(
13043 "Old_Value"=>$Type1_PLevel,
13044 "New_Value"=>$Type2_PLevel);
13045 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013046 }
13047 }
13048 }
13049 if($Type1_Pure{"Type"} eq "Array")
13050 { # base_type[N] -> base_type[N]
13051 # base_type: older_structure -> typedef to newer_structure
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040013052 my %SubProblems = detectTypeChange($Type1_Base{"Tid"}, $Type2_Base{"Tid"}, $Prefix, $Level);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013053 foreach my $SubProblemType (keys(%SubProblems))
13054 {
13055 $SubProblemType=~s/_Type/_BaseType/g;
13056 next if(defined $LocalProblems{$SubProblemType});
13057 foreach my $Attr (keys(%{$SubProblems{$SubProblemType}})) {
13058 $LocalProblems{$SubProblemType}{$Attr} = $SubProblems{$SubProblemType}{$Attr};
13059 }
13060 }
13061 }
13062 return %LocalProblems;
13063}
13064
13065sub tNameLock($$)
13066{
13067 my ($Tid1, $Tid2) = @_;
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040013068 my $Changed = 0;
13069 if(differentDumps("G"))
13070 { # different GCC versions
13071 $Changed = 1;
13072 }
13073 elsif(differentDumps("V"))
13074 { # different versions of ABI dumps
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040013075 if(not checkDump(1, "2.13")
13076 or not checkDump(2, "2.13"))
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040013077 { # latest names update
13078 # 2.6: added restrict qualifier
13079 # 2.13: added missed typedefs to qualified types
13080 $Changed = 1;
13081 }
13082 }
13083 if($Changed)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013084 { # different formats
13085 if($UseOldDumps)
13086 { # old dumps
13087 return 0;
13088 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040013089 my $TN1 = $TypeInfo{1}{$Tid1}{"Name"};
13090 my $TN2 = $TypeInfo{2}{$Tid2}{"Name"};
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040013091
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040013092 my $TT1 = $TypeInfo{1}{$Tid1}{"Type"};
13093 my $TT2 = $TypeInfo{2}{$Tid2}{"Type"};
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040013094
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040013095 my %Base1 = get_Type($Tid1, 1);
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040013096 while(defined $Base1{"Type"} and $Base1{"Type"} eq "Typedef") {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040013097 %Base1 = get_OneStep_BaseType($Base1{"Tid"}, 1);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013098 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040013099 my %Base2 = get_Type($Tid2, 2);
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040013100 while(defined $Base2{"Type"} and $Base2{"Type"} eq "Typedef") {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040013101 %Base2 = get_OneStep_BaseType($Base2{"Tid"}, 2);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013102 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +040013103 my $BName1 = uncover_typedefs($Base1{"Name"}, 1);
13104 my $BName2 = uncover_typedefs($Base2{"Name"}, 2);
13105 if($BName1 eq $BName2)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013106 { # equal base types
13107 return 0;
13108 }
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040013109
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040013110 if(not checkDump(1, "2.13")
13111 or not checkDump(2, "2.13"))
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040013112 { # broken array names in ABI dumps < 2.13
13113 if($TT1 eq "Array"
13114 and $TT2 eq "Array")
13115 {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013116 return 0;
13117 }
13118 }
13119
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040013120 if(not checkDump(1, "2.6")
13121 or not checkDump(2, "2.6"))
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040013122 { # added restrict attribute in 2.6
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040013123 if($TN1!~/\brestrict\b/
13124 and $TN2=~/\brestrict\b/)
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040013125 {
13126 return 0;
13127 }
13128 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013129 }
13130 return 1;
13131}
13132
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040013133sub differentDumps($)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013134{
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040013135 my $Check = $_[0];
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +040013136 if(defined $Cache{"differentDumps"}{$Check}) {
13137 return $Cache{"differentDumps"}{$Check};
13138 }
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040013139 if($UsedDump{1}{"V"} and $UsedDump{2}{"V"})
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040013140 {
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040013141 if($Check eq "G")
13142 {
13143 if(getGccVersion(1) ne getGccVersion(2))
13144 { # different GCC versions
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +040013145 return ($Cache{"differentDumps"}{$Check}=1);
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040013146 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040013147 }
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040013148 if($Check eq "V")
13149 {
13150 if(cmpVersions(formatVersion($UsedDump{1}{"V"}, 2),
13151 formatVersion($UsedDump{2}{"V"}, 2))!=0)
13152 { # different dump versions (skip micro version)
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +040013153 return ($Cache{"differentDumps"}{$Check}=1);
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040013154 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040013155 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013156 }
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +040013157 return ($Cache{"differentDumps"}{$Check}=0);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013158}
13159
13160sub formatVersion($$)
13161{ # cut off version digits
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040013162 my ($V, $Digits) = @_;
13163 my @Elems = split(/\./, $V);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013164 return join(".", splice(@Elems, 0, $Digits));
13165}
13166
13167sub htmlSpecChars($)
13168{
13169 my $Str = $_[0];
Andrey Ponomarenko5c09ef32012-06-14 18:17:33 +040013170 if(not $Str) {
13171 return $Str;
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040013172 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013173 $Str=~s/\&([^#]|\Z)/&amp;$1/g;
13174 $Str=~s/</&lt;/g;
13175 $Str=~s/\-\>/&#45;&gt;/g; # &minus;
13176 $Str=~s/>/&gt;/g;
13177 $Str=~s/([^ ])( )([^ ])/$1\@ALONE_SP\@$3/g;
13178 $Str=~s/ /&#160;/g; # &nbsp;
13179 $Str=~s/\@ALONE_SP\@/ /g;
13180 $Str=~s/\n/<br\/>/g;
13181 $Str=~s/\"/&quot;/g;
13182 $Str=~s/\'/&#39;/g;
13183 return $Str;
13184}
13185
Andrey Ponomarenko5c09ef32012-06-14 18:17:33 +040013186sub xmlSpecChars($)
13187{
13188 my $Str = $_[0];
13189 if(not $Str) {
13190 return $Str;
13191 }
13192
13193 $Str=~s/\&([^#]|\Z)/&amp;$1/g;
13194 $Str=~s/</&lt;/g;
13195 $Str=~s/>/&gt;/g;
13196
13197 $Str=~s/\"/&quot;/g;
13198 $Str=~s/\'/&#39;/g;
13199
13200 return $Str;
13201}
13202
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013203sub black_name($)
13204{
13205 my $Name = $_[0];
13206 return "<span class='iname_b'>".highLight_Signature($Name)."</span>";
13207}
13208
13209sub highLight_Signature($)
13210{
13211 my $Signature = $_[0];
13212 return highLight_Signature_PPos_Italic($Signature, "", 0, 0, 0);
13213}
13214
13215sub highLight_Signature_Italic_Color($)
13216{
13217 my $Signature = $_[0];
13218 return highLight_Signature_PPos_Italic($Signature, "", 1, 1, 1);
13219}
13220
13221sub separate_symbol($)
13222{
13223 my $Symbol = $_[0];
13224 my ($Name, $Spec, $Ver) = ($Symbol, "", "");
13225 if($Symbol=~/\A([^\@\$\?]+)([\@\$]+)([^\@\$]+)\Z/) {
13226 ($Name, $Spec, $Ver) = ($1, $2, $3);
13227 }
13228 return ($Name, $Spec, $Ver);
13229}
13230
13231sub cut_f_attrs($)
13232{
13233 if($_[0]=~s/(\))((| (const volatile|const|volatile))(| \[static\]))\Z/$1/) {
13234 return $2;
13235 }
13236 return "";
13237}
13238
13239sub highLight_Signature_PPos_Italic($$$$$)
13240{
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040013241 my ($FullSignature, $Param_Pos, $ItalicParams, $ColorParams, $ShowReturn) = @_;
13242 $Param_Pos = "" if(not defined $Param_Pos);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013243 if($CheckObjectsOnly) {
13244 $ItalicParams=$ColorParams=0;
13245 }
13246 my ($Signature, $VersionSpec, $SymbolVersion) = separate_symbol($FullSignature);
13247 my $Return = "";
13248 if($ShowRetVal and $Signature=~s/([^:]):([^:].+?)\Z/$1/g) {
13249 $Return = $2;
13250 }
Andrey Ponomarenko16934472012-03-29 15:37:04 +040013251 my $SCenter = find_center($Signature, "(");
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013252 if(not $SCenter)
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040013253 { # global data
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013254 $Signature = htmlSpecChars($Signature);
13255 $Signature=~s!(\[data\])!<span style='color:Black;font-weight:normal;'>$1</span>!g;
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040013256 $Signature .= (($SymbolVersion)?"<span class='sym_ver'>&#160;$VersionSpec&#160;$SymbolVersion</span>":"");
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013257 if($Return and $ShowReturn) {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040013258 $Signature .= "<span class='sym_p nowrap'> &#160;<b>:</b>&#160;&#160;".htmlSpecChars($Return)."</span>";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013259 }
13260 return $Signature;
13261 }
13262 my ($Begin, $End) = (substr($Signature, 0, $SCenter), "");
13263 $Begin.=" " if($Begin!~/ \Z/);
13264 $End = cut_f_attrs($Signature);
13265 my @Parts = ();
13266 my @SParts = get_s_params($Signature, 1);
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040013267 foreach my $Pos (0 .. $#SParts)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013268 {
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040013269 my $Part = $SParts[$Pos];
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013270 $Part=~s/\A\s+|\s+\Z//g;
13271 my ($Part_Styled, $ParamName) = (htmlSpecChars($Part), "");
13272 if($Part=~/\([\*]+(\w+)\)/i) {
13273 $ParamName = $1;#func-ptr
13274 }
13275 elsif($Part=~/(\w+)[\,\)]*\Z/i) {
13276 $ParamName = $1;
13277 }
13278 if(not $ParamName) {
13279 push(@Parts, $Part_Styled);
13280 next;
13281 }
13282 if($ItalicParams and not $TName_Tid{1}{$Part}
13283 and not $TName_Tid{2}{$Part})
13284 {
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040013285 my $Style = "param";
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040013286 if($Param_Pos ne ""
13287 and $Pos==$Param_Pos) {
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040013288 $Style = "focus_p";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013289 }
13290 elsif($ColorParams) {
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040013291 $Style = "color_p";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013292 }
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040013293 $Part_Styled =~ s!(\W)$ParamName([\,\)]|\Z)!$1<span class=\'$Style\'>$ParamName</span>$2!ig;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013294 }
13295 $Part_Styled=~s/,(\w)/, $1/g;
13296 push(@Parts, $Part_Styled);
13297 }
13298 if(@Parts)
13299 {
13300 foreach my $Num (0 .. $#Parts)
13301 {
13302 if($Num==$#Parts)
13303 { # add ")" to the last parameter
13304 $Parts[$Num] = "<span class='nowrap'>".$Parts[$Num]." )</span>";
13305 }
13306 elsif(length($Parts[$Num])<=45) {
13307 $Parts[$Num] = "<span class='nowrap'>".$Parts[$Num]."</span>";
13308 }
13309 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040013310 $Signature = htmlSpecChars($Begin)."<span class='sym_p'>(&#160;".join(" ", @Parts)."</span>".$End;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013311 }
13312 else {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040013313 $Signature = htmlSpecChars($Begin)."<span class='sym_p'>(&#160;)</span>".$End;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013314 }
13315 if($Return and $ShowReturn) {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040013316 $Signature .= "<span class='sym_p nowrap'> &#160;<b>:</b>&#160;&#160;".htmlSpecChars($Return)."</span>";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013317 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040013318 $Signature=~s!\[\]![&#160;]!g;
13319 $Signature=~s!operator=!operator&#160;=!g;
13320 $Signature=~s!(\[in-charge\]|\[not-in-charge\]|\[in-charge-deleting\]|\[static\])!<span class='sym_kind'>$1</span>!g;
13321 return $Signature.(($SymbolVersion)?"<span class='sym_ver'>&#160;$VersionSpec&#160;$SymbolVersion</span>":"");
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013322}
13323
13324sub get_s_params($$)
13325{
13326 my ($Signature, $Comma) = @_;
13327 my @Parts = ();
Andrey Ponomarenko16934472012-03-29 15:37:04 +040013328 my $ShortName = substr($Signature, 0, find_center($Signature, "("));
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013329 $Signature=~s/\A\Q$ShortName\E\(//g;
13330 cut_f_attrs($Signature);
13331 $Signature=~s/\)\Z//;
13332 return separate_params($Signature, $Comma);
13333}
13334
13335sub separate_params($$)
13336{
13337 my ($Params, $Comma) = @_;
13338 my @Parts = ();
Andrey Ponomarenko16934472012-03-29 15:37:04 +040013339 my %B = ( "("=>0, "<"=>0, ")"=>0, ">"=>0 );
13340 my $Part = 0;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013341 foreach my $Pos (0 .. length($Params) - 1)
13342 {
Andrey Ponomarenko16934472012-03-29 15:37:04 +040013343 my $S = substr($Params, $Pos, 1);
13344 if(defined $B{$S}) {
13345 $B{$S}+=1;
13346 }
13347 if($S eq "," and
13348 $B{"("}==$B{")"} and $B{"<"}==$B{">"})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013349 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040013350 if($Comma)
13351 { # include comma
Andrey Ponomarenko16934472012-03-29 15:37:04 +040013352 $Parts[$Part] .= $S;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013353 }
Andrey Ponomarenko16934472012-03-29 15:37:04 +040013354 $Part += 1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013355 }
13356 else {
Andrey Ponomarenko16934472012-03-29 15:37:04 +040013357 $Parts[$Part] .= $S;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013358 }
13359 }
13360 return @Parts;
13361}
13362
Andrey Ponomarenko16934472012-03-29 15:37:04 +040013363sub find_center($$)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013364{
13365 my ($Sign, $Target) = @_;
Andrey Ponomarenko16934472012-03-29 15:37:04 +040013366 my %B = ( "("=>0, "<"=>0, ")"=>0, ">"=>0 );
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013367 my $Center = 0;
Andrey Ponomarenko16934472012-03-29 15:37:04 +040013368 if($Sign=~s/(operator([^\w\s\(\)]+|\(\)))//g)
13369 { # operators
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013370 $Center+=length($1);
13371 }
13372 foreach my $Pos (0 .. length($Sign)-1)
13373 {
13374 my $S = substr($Sign, $Pos, 1);
13375 if($S eq $Target)
13376 {
13377 if($B{"("}==$B{")"}
13378 and $B{"<"}==$B{">"}) {
13379 return $Center;
13380 }
13381 }
13382 if(defined $B{$S}) {
13383 $B{$S}+=1;
13384 }
13385 $Center+=1;
13386 }
13387 return 0;
13388}
13389
13390sub appendFile($$)
13391{
13392 my ($Path, $Content) = @_;
13393 return if(not $Path);
13394 if(my $Dir = get_dirname($Path)) {
13395 mkpath($Dir);
13396 }
Andrey Ponomarenko16934472012-03-29 15:37:04 +040013397 open(FILE, ">>", $Path) || die ("can't open file \'$Path\': $!\n");
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013398 print FILE $Content;
13399 close(FILE);
13400}
13401
13402sub writeFile($$)
13403{
13404 my ($Path, $Content) = @_;
13405 return if(not $Path);
13406 if(my $Dir = get_dirname($Path)) {
13407 mkpath($Dir);
13408 }
Andrey Ponomarenko16934472012-03-29 15:37:04 +040013409 open(FILE, ">", $Path) || die ("can't open file \'$Path\': $!\n");
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013410 print FILE $Content;
13411 close(FILE);
13412}
13413
13414sub readFile($)
13415{
13416 my $Path = $_[0];
13417 return "" if(not $Path or not -f $Path);
Andrey Ponomarenko16934472012-03-29 15:37:04 +040013418 open(FILE, $Path);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013419 local $/ = undef;
13420 my $Content = <FILE>;
13421 close(FILE);
Andrey Ponomarenko85043792012-05-14 16:48:07 +040013422 if($Path!~/\.(tu|class|abi)\Z/) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013423 $Content=~s/\r/\n/g;
13424 }
13425 return $Content;
13426}
13427
13428sub get_filename($)
13429{ # much faster than basename() from File::Basename module
Andrey Ponomarenko85043792012-05-14 16:48:07 +040013430 if(defined $Cache{"get_filename"}{$_[0]}) {
13431 return $Cache{"get_filename"}{$_[0]};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013432 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +040013433 if($_[0] and $_[0]=~/([^\/\\]+)[\/\\]*\Z/) {
13434 return ($Cache{"get_filename"}{$_[0]}=$1);
13435 }
13436 return ($Cache{"get_filename"}{$_[0]}="");
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013437}
13438
13439sub get_dirname($)
13440{ # much faster than dirname() from File::Basename module
Andrey Ponomarenko85043792012-05-14 16:48:07 +040013441 if(defined $Cache{"get_dirname"}{$_[0]}) {
13442 return $Cache{"get_dirname"}{$_[0]};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013443 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +040013444 if($_[0] and $_[0]=~/\A(.*?)[\/\\]+[^\/\\]*[\/\\]*\Z/) {
13445 return ($Cache{"get_dirname"}{$_[0]}=$1);
13446 }
13447 return ($Cache{"get_dirname"}{$_[0]}="");
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013448}
13449
13450sub separate_path($) {
13451 return (get_dirname($_[0]), get_filename($_[0]));
13452}
13453
13454sub esc($)
13455{
13456 my $Str = $_[0];
13457 $Str=~s/([()\[\]{}$ &'"`;,<>\+])/\\$1/g;
13458 return $Str;
13459}
13460
13461sub readLineNum($$)
13462{
13463 my ($Path, $Num) = @_;
13464 return "" if(not $Path or not -f $Path);
Andrey Ponomarenko16934472012-03-29 15:37:04 +040013465 open(FILE, $Path);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013466 foreach (1 ... $Num) {
13467 <FILE>;
13468 }
13469 my $Line = <FILE>;
13470 close(FILE);
13471 return $Line;
13472}
13473
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040013474sub readAttributes($$)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013475{
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040013476 my ($Path, $Num) = @_;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013477 return () if(not $Path or not -f $Path);
13478 my %Attributes = ();
Andrey Ponomarenko85043792012-05-14 16:48:07 +040013479 if(readLineNum($Path, $Num)=~/<!--\s+(.+)\s+-->/)
13480 {
13481 foreach my $AttrVal (split(/;/, $1))
13482 {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013483 if($AttrVal=~/(.+):(.+)/)
13484 {
13485 my ($Name, $Value) = ($1, $2);
13486 $Attributes{$Name} = $Value;
13487 }
13488 }
13489 }
13490 return \%Attributes;
13491}
13492
13493sub is_abs($) {
13494 return ($_[0]=~/\A(\/|\w+:[\/\\])/);
13495}
13496
13497sub get_abs_path($)
13498{ # abs_path() should NOT be called for absolute inputs
13499 # because it can change them
13500 my $Path = $_[0];
13501 if(not is_abs($Path)) {
13502 $Path = abs_path($Path);
13503 }
13504 return $Path;
13505}
13506
13507sub get_OSgroup()
13508{
13509 $_ = $Config{"osname"};
13510 if(/macos|darwin|rhapsody/i) {
13511 return "macos";
13512 }
13513 elsif(/freebsd|openbsd|netbsd/i) {
13514 return "bsd";
13515 }
13516 elsif(/haiku|beos/i) {
13517 return "beos";
13518 }
13519 elsif(/symbian|epoc/i) {
13520 return "symbian";
13521 }
13522 elsif(/win/i) {
13523 return "windows";
13524 }
13525 else {
13526 return $_;
13527 }
13528}
13529
13530sub getGccVersion($)
13531{
13532 my $LibVersion = $_[0];
13533 if($GCC_VERSION{$LibVersion})
13534 { # dump version
13535 return $GCC_VERSION{$LibVersion};
13536 }
13537 elsif($UsedDump{$LibVersion}{"V"})
13538 { # old-version dumps
13539 return "unknown";
13540 }
13541 my $GccVersion = get_dumpversion($GCC_PATH); # host version
13542 if(not $GccVersion) {
13543 return "unknown";
13544 }
13545 return $GccVersion;
13546}
13547
13548sub showArch($)
13549{
13550 my $Arch = $_[0];
13551 if($Arch eq "arm"
13552 or $Arch eq "mips") {
13553 return uc($Arch);
13554 }
13555 return $Arch;
13556}
13557
13558sub getArch($)
13559{
13560 my $LibVersion = $_[0];
13561 if($CPU_ARCH{$LibVersion})
13562 { # dump version
13563 return $CPU_ARCH{$LibVersion};
13564 }
13565 elsif($UsedDump{$LibVersion}{"V"})
13566 { # old-version dumps
13567 return "unknown";
13568 }
13569 if(defined $Cache{"getArch"}{$LibVersion}) {
13570 return $Cache{"getArch"}{$LibVersion};
13571 }
13572 my $Arch = get_dumpmachine($GCC_PATH); # host version
13573 if(not $Arch) {
13574 return "unknown";
13575 }
13576 if($Arch=~/\A([\w]{3,})(-|\Z)/) {
13577 $Arch = $1;
13578 }
13579 $Arch = "x86" if($Arch=~/\Ai[3-7]86\Z/);
13580 if($OSgroup eq "windows") {
13581 $Arch = "x86" if($Arch=~/win32|mingw32/i);
13582 $Arch = "x86_64" if($Arch=~/win64|mingw64/i);
13583 }
13584 $Cache{"getArch"}{$LibVersion} = $Arch;
13585 return $Arch;
13586}
13587
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040013588sub get_Report_Header($)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013589{
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040013590 my $Level = $_[0];
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013591 my $ArchInfo = " on <span style='color:Blue;'>".showArch(getArch(1))."</span>";
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040013592 if(getArch(1) ne getArch(2)
13593 or getArch(1) eq "unknown"
13594 or $Level eq "Source")
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013595 { # don't show architecture in the header
13596 $ArchInfo="";
13597 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040013598 my $Report_Header = "<h1><span class='nowrap'>";
13599 if($Level eq "Source") {
13600 $Report_Header .= "Source compatibility";
13601 }
13602 elsif($Level eq "Binary") {
13603 $Report_Header .= "Binary compatibility";
13604 }
13605 else {
13606 $Report_Header .= "API compatibility";
13607 }
13608 $Report_Header .= " report for the <span style='color:Blue;'>$TargetLibraryFName</span> $TargetComponent</span>";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013609 $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>";
13610 if($AppPath) {
13611 $Report_Header .= " <span class='nowrap'>&#160;(relating to the portability of application <span style='color:Blue;'>".get_filename($AppPath)."</span>)</span>";
13612 }
13613 $Report_Header .= "</h1>\n";
13614 return $Report_Header;
13615}
13616
13617sub get_SourceInfo()
13618{
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040013619 my ($CheckedHeaders, $CheckedLibs) = ("", "");
13620 if(not $CheckObjectsOnly)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013621 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040013622 $CheckedHeaders = "<a name='Headers'></a><h2>Header Files (".keys(%{$Registered_Headers{1}}).")</h2><hr/>\n";
13623 $CheckedHeaders .= "<div class='h_list'>\n";
13624 foreach my $Header_Path (sort {lc($Registered_Headers{1}{$a}{"Identity"}) cmp lc($Registered_Headers{1}{$b}{"Identity"})} keys(%{$Registered_Headers{1}}))
13625 {
13626 my $Identity = $Registered_Headers{1}{$Header_Path}{"Identity"};
13627 my $Header_Name = get_filename($Identity);
13628 my $Dest_Comment = ($Identity=~/[\/\\]/)?" ($Identity)":"";
13629 $CheckedHeaders .= $Header_Name.$Dest_Comment."<br/>\n";
13630 }
13631 $CheckedHeaders .= "</div>\n";
13632 $CheckedHeaders .= "<br/>$TOP_REF<br/>\n";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013633 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040013634 if(not $CheckHeadersOnly)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013635 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040013636 $CheckedLibs = "<a name='Libs'></a><h2>".ucfirst($SLIB_TYPE)." Libraries (".keys(%{$Library_Symbol{1}}).")</h2><hr/>\n";
13637 $CheckedLibs .= "<div class='lib_list'>\n";
13638 foreach my $Library (sort {lc($a) cmp lc($b)} keys(%{$Library_Symbol{1}}))
13639 {
13640 $Library.=" (.$LIB_EXT)" if($Library!~/\.\w+\Z/);
13641 $CheckedLibs .= $Library."<br/>\n";
13642 }
13643 $CheckedLibs .= "</div>\n";
13644 $CheckedLibs .= "<br/>$TOP_REF<br/>\n";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013645 }
13646 return $CheckedHeaders.$CheckedLibs;
13647}
13648
13649sub get_TypeProblems_Count($$$)
13650{
13651 my ($TypeChanges, $TargetPriority, $Level) = @_;
13652 my $Type_Problems_Count = 0;
13653 foreach my $Type_Name (sort keys(%{$TypeChanges}))
13654 {
13655 my %Kinds_Target = ();
13656 foreach my $Kind (keys(%{$TypeChanges->{$Type_Name}}))
13657 {
13658 foreach my $Location (keys(%{$TypeChanges->{$Type_Name}{$Kind}}))
13659 {
13660 my $Target = $TypeChanges->{$Type_Name}{$Kind}{$Location}{"Target"};
13661 my $Priority = getProblemSeverity($Level, $Kind);
13662 next if($Priority ne $TargetPriority);
13663 if($Kinds_Target{$Kind}{$Target}) {
13664 next;
13665 }
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040013666 if(cmpSeverities($Type_MaxSeverity{$Level}{$Type_Name}{$Kind}{$Target}, $Priority))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013667 { # select a problem with the highest priority
13668 next;
13669 }
13670 $Kinds_Target{$Kind}{$Target} = 1;
13671 $Type_Problems_Count += 1;
13672 }
13673 }
13674 }
13675 return $Type_Problems_Count;
13676}
13677
13678sub get_Summary($)
13679{
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040013680 my $Level = $_[0];
13681 my ($Added, $Removed, $I_Problems_High, $I_Problems_Medium, $I_Problems_Low, $T_Problems_High,
13682 $C_Problems_Low, $T_Problems_Medium, $T_Problems_Low, $I_Other, $T_Other) = (0,0,0,0,0,0,0,0,0,0,0);
13683 %{$RESULT{$Level}} = (
13684 "Problems"=>0,
13685 "Warnings"=>0,
13686 "Affected"=>0 );
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013687 # check rules
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040013688 foreach my $Interface (sort keys(%{$CompatProblems{$Level}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013689 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040013690 foreach my $Kind (keys(%{$CompatProblems{$Level}{$Interface}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013691 {
13692 if(not defined $CompatRules{$Level}{$Kind})
13693 { # unknown rule
13694 if(not $UnknownRules{$Level}{$Kind})
13695 { # only one warning
13696 printMsg("WARNING", "unknown rule \"$Kind\" (\"$Level\")");
13697 $UnknownRules{$Level}{$Kind}=1;
13698 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040013699 delete($CompatProblems{$Level}{$Interface}{$Kind});
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013700 }
13701 }
13702 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040013703 foreach my $Interface (sort keys(%{$CompatProblems{$Level}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013704 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040013705 foreach my $Kind (sort keys(%{$CompatProblems{$Level}{$Interface}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013706 {
13707 if($CompatRules{$Level}{$Kind}{"Kind"} eq "Symbols")
13708 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040013709 foreach my $Location (sort keys(%{$CompatProblems{$Level}{$Interface}{$Kind}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013710 {
13711 my $Priority = getProblemSeverity($Level, $Kind);
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040013712 if($Kind eq "Added_Symbol") {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013713 $Added += 1;
13714 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040013715 elsif($Kind eq "Removed_Symbol")
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013716 {
13717 $Removed += 1;
13718 $TotalAffected{$Level}{$Interface} = $Priority;
13719 }
13720 else
13721 {
13722 if($Priority eq "Safe") {
13723 $I_Other += 1;
13724 }
13725 elsif($Priority eq "High") {
13726 $I_Problems_High += 1;
13727 }
13728 elsif($Priority eq "Medium") {
13729 $I_Problems_Medium += 1;
13730 }
13731 elsif($Priority eq "Low") {
13732 $I_Problems_Low += 1;
13733 }
13734 if(($Priority ne "Low" or $StrictCompat)
13735 and $Priority ne "Safe") {
13736 $TotalAffected{$Level}{$Interface} = $Priority;
13737 }
13738 }
13739 }
13740 }
13741 }
13742 }
13743 my %TypeChanges = ();
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040013744 foreach my $Interface (sort keys(%{$CompatProblems{$Level}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013745 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040013746 foreach my $Kind (keys(%{$CompatProblems{$Level}{$Interface}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013747 {
13748 if($CompatRules{$Level}{$Kind}{"Kind"} eq "Types")
13749 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040013750 foreach my $Location (sort {cmp_locations($b, $a)} sort keys(%{$CompatProblems{$Level}{$Interface}{$Kind}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013751 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040013752 my $Type_Name = $CompatProblems{$Level}{$Interface}{$Kind}{$Location}{"Type_Name"};
13753 my $Target = $CompatProblems{$Level}{$Interface}{$Kind}{$Location}{"Target"};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013754 my $Priority = getProblemSeverity($Level, $Kind);
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040013755 if(cmpSeverities($Type_MaxSeverity{$Level}{$Type_Name}{$Kind}{$Target}, $Priority))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013756 { # select a problem with the highest priority
13757 next;
13758 }
13759 if(($Priority ne "Low" or $StrictCompat)
13760 and $Priority ne "Safe") {
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040013761 $TotalAffected{$Level}{$Interface} = maxSeverity($TotalAffected{$Level}{$Interface}, $Priority);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013762 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040013763 %{$TypeChanges{$Type_Name}{$Kind}{$Location}} = %{$CompatProblems{$Level}{$Interface}{$Kind}{$Location}};
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040013764 $Type_MaxSeverity{$Level}{$Type_Name}{$Kind}{$Target} = maxSeverity($Type_MaxSeverity{$Level}{$Type_Name}{$Kind}{$Target}, $Priority);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013765 }
13766 }
13767 }
13768 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040013769
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013770 $T_Problems_High = get_TypeProblems_Count(\%TypeChanges, "High", $Level);
13771 $T_Problems_Medium = get_TypeProblems_Count(\%TypeChanges, "Medium", $Level);
13772 $T_Problems_Low = get_TypeProblems_Count(\%TypeChanges, "Low", $Level);
13773 $T_Other = get_TypeProblems_Count(\%TypeChanges, "Safe", $Level);
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040013774
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013775 if($CheckObjectsOnly)
13776 { # only removed exported symbols
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040013777 $RESULT{$Level}{"Affected"} = $Removed*100/keys(%{$Symbol_Library{1}});
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013778 }
13779 else
13780 { # changed and removed public symbols
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040013781 my $SCount = keys(%{$CheckedSymbols{$Level}});
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013782 if($ExtendedCheck)
13783 { # don't count external_func_0 for constants
13784 $SCount-=1;
13785 }
13786 if($SCount)
13787 {
13788 my %Weight = (
13789 "High" => 100,
13790 "Medium" => 50,
13791 "Low" => 25
13792 );
13793 foreach (keys(%{$TotalAffected{$Level}})) {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040013794 $RESULT{$Level}{"Affected"}+=$Weight{$TotalAffected{$Level}{$_}};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013795 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040013796 $RESULT{$Level}{"Affected"} = $RESULT{$Level}{"Affected"}/$SCount;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013797 }
13798 else {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040013799 $RESULT{$Level}{"Affected"} = 0;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013800 }
13801 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040013802 $RESULT{$Level}{"Affected"} = show_number($RESULT{$Level}{"Affected"});
13803 if($RESULT{$Level}{"Affected"}>=100) {
13804 $RESULT{$Level}{"Affected"} = 100;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013805 }
13806
Andrey Ponomarenko85043792012-05-14 16:48:07 +040013807 $RESULT{$Level}{"Problems"} += $Removed;
13808 $RESULT{$Level}{"Problems"} += $T_Problems_High + $I_Problems_High;
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040013809 $RESULT{$Level}{"Problems"} += $T_Problems_Medium + $I_Problems_Medium;
Andrey Ponomarenko85043792012-05-14 16:48:07 +040013810 if($StrictCompat) {
13811 $RESULT{$Level}{"Problems"} += $T_Problems_Low + $I_Problems_Low;
13812 }
13813 else {
13814 $RESULT{$Level}{"Warnings"} += $T_Problems_Low + $I_Problems_Low;
13815 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013816
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040013817 if($C_Problems_Low = keys(%{$ProblemsWithConstants{$Level}}))
13818 {
Andrey Ponomarenko85043792012-05-14 16:48:07 +040013819 if(defined $CompatRules{$Level}{"Changed_Constant"})
13820 {
13821 if($StrictCompat) {
13822 $RESULT{$Level}{"Problems"} += $C_Problems_Low;
13823 }
13824 else {
13825 $RESULT{$Level}{"Warnings"} += $C_Problems_Low;
13826 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040013827 }
13828 else
13829 {
13830 printMsg("WARNING", "unknown rule \"Changed_Constant\" (\"$Level\")");
13831 $C_Problems_Low = 0;
13832 }
13833 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +040013834 if($CheckImpl and $Level eq "Binary")
13835 {
13836 if($StrictCompat) {
13837 $RESULT{$Level}{"Problems"} += keys(%ImplProblems);
13838 }
13839 else {
13840 $RESULT{$Level}{"Warnings"} += keys(%ImplProblems);
13841 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040013842 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +040013843 if($RESULT{$Level}{"Problems"}
13844 and $RESULT{$Level}{"Affected"}) {
13845 $RESULT{$Level}{"Verdict"} = "incompatible";
13846 }
13847 else {
13848 $RESULT{$Level}{"Verdict"} = "compatible";
13849 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040013850
13851 my $TotalTypes = keys(%{$CheckedTypes{$Level}});
13852 if(not $TotalTypes)
13853 { # list all the types
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013854 $TotalTypes = keys(%{$TName_Tid{1}});
13855 }
13856
13857 my ($Arch1, $Arch2) = (getArch(1), getArch(2));
13858 my ($GccV1, $GccV2) = (getGccVersion(1), getGccVersion(2));
13859
13860 my ($TestInfo, $TestResults, $Problem_Summary) = ();
13861
13862 if($ReportFormat eq "xml")
13863 { # XML
13864 # test info
13865 $TestInfo .= " <library>$TargetLibraryName</library>\n";
13866 $TestInfo .= " <version1>\n";
13867 $TestInfo .= " <number>".$Descriptor{1}{"Version"}."</number>\n";
13868 $TestInfo .= " <architecture>$Arch1</architecture>\n";
13869 $TestInfo .= " <gcc>$GccV1</gcc>\n";
13870 $TestInfo .= " </version1>\n";
13871
13872 $TestInfo .= " <version2>\n";
13873 $TestInfo .= " <number>".$Descriptor{2}{"Version"}."</number>\n";
13874 $TestInfo .= " <architecture>$Arch2</architecture>\n";
13875 $TestInfo .= " <gcc>$GccV2</gcc>\n";
13876 $TestInfo .= " </version2>\n";
13877 $TestInfo = "<test_info>\n".$TestInfo."</test_info>\n\n";
13878
13879 # test results
13880 $TestResults .= " <headers>\n";
13881 foreach my $Name (sort {lc($Registered_Headers{1}{$a}{"Identity"}) cmp lc($Registered_Headers{1}{$b}{"Identity"})} keys(%{$Registered_Headers{1}}))
13882 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040013883 my $Identity = $Registered_Headers{1}{$Name}{"Identity"};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013884 my $Comment = ($Identity=~/[\/\\]/)?" ($Identity)":"";
13885 $TestResults .= " <name>".get_filename($Name).$Comment."</name>\n";
13886 }
13887 $TestResults .= " </headers>\n";
13888
13889 $TestResults .= " <libs>\n";
13890 foreach my $Library (sort {lc($a) cmp lc($b)} keys(%{$Library_Symbol{1}}))
13891 {
13892 $Library.=" (.$LIB_EXT)" if($Library!~/\.\w+\Z/);
13893 $TestResults .= " <name>$Library</name>\n";
13894 }
13895 $TestResults .= " </libs>\n";
13896
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040013897 $TestResults .= " <symbols>".(keys(%{$CheckedSymbols{$Level}}) - keys(%ExtendedSymbols))."</symbols>\n";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013898 $TestResults .= " <types>".$TotalTypes."</types>\n";
13899
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040013900 $TestResults .= " <verdict>".$RESULT{$Level}{"Verdict"}."</verdict>\n";
13901 $TestResults .= " <affected>".$RESULT{$Level}{"Affected"}."</affected>\n";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013902 $TestResults = "<test_results>\n".$TestResults."</test_results>\n\n";
13903
13904 # problem summary
13905 $Problem_Summary .= " <added_symbols>".$Added."</added_symbols>\n";
13906 $Problem_Summary .= " <removed_symbols>".$Removed."</removed_symbols>\n";
13907
13908 $Problem_Summary .= " <problems_with_types>\n";
13909 $Problem_Summary .= " <high>$T_Problems_High</high>\n";
13910 $Problem_Summary .= " <medium>$T_Problems_Medium</medium>\n";
13911 $Problem_Summary .= " <low>$T_Problems_Low</low>\n";
13912 $Problem_Summary .= " <safe>$T_Other</safe>\n";
13913 $Problem_Summary .= " </problems_with_types>\n";
13914
13915 $Problem_Summary .= " <problems_with_symbols>\n";
13916 $Problem_Summary .= " <high>$I_Problems_High</high>\n";
13917 $Problem_Summary .= " <medium>$I_Problems_Medium</medium>\n";
13918 $Problem_Summary .= " <low>$I_Problems_Low</low>\n";
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040013919 $Problem_Summary .= " <safe>$I_Other</safe>\n";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013920 $Problem_Summary .= " </problems_with_symbols>\n";
13921
13922 $Problem_Summary .= " <problems_with_constants>\n";
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040013923 $Problem_Summary .= " <low>$C_Problems_Low</low>\n";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013924 $Problem_Summary .= " </problems_with_constants>\n";
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040013925 if($CheckImpl and $Level eq "Binary")
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013926 {
13927 $Problem_Summary .= " <impl>\n";
13928 $Problem_Summary .= " <low>".keys(%ImplProblems)."</low>\n";
13929 $Problem_Summary .= " </impl>\n";
13930 }
13931 $Problem_Summary = "<problem_summary>\n".$Problem_Summary."</problem_summary>\n\n";
13932
13933 return ($TestInfo.$TestResults.$Problem_Summary, "");
13934 }
13935 else
13936 { # HTML
13937 # test info
13938 $TestInfo = "<h2>Test Info</h2><hr/>\n";
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040013939 $TestInfo .= "<table class='summary'>\n";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013940 $TestInfo .= "<tr><th>".ucfirst($TargetComponent)." Name</th><td>$TargetLibraryFName</td></tr>\n";
13941
13942 my (@VInf1, @VInf2, $AddTestInfo) = ();
13943 if($Arch1 ne "unknown"
13944 and $Arch2 ne "unknown")
13945 { # CPU arch
13946 if($Arch1 eq $Arch2)
13947 { # go to the separate section
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040013948 $AddTestInfo .= "<tr><th>CPU Type</th><td>".showArch($Arch1)."</td></tr>\n";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013949 }
13950 else
13951 { # go to the version number
13952 push(@VInf1, showArch($Arch1));
13953 push(@VInf2, showArch($Arch2));
13954 }
13955 }
13956 if($GccV1 ne "unknown"
13957 and $GccV2 ne "unknown"
13958 and $OStarget ne "windows")
13959 { # GCC version
13960 if($GccV1 eq $GccV2)
13961 { # go to the separate section
13962 $AddTestInfo .= "<tr><th>GCC Version</th><td>$GccV1</td></tr>\n";
13963 }
13964 else
13965 { # go to the version number
13966 push(@VInf1, "gcc ".$GccV1);
13967 push(@VInf2, "gcc ".$GccV2);
13968 }
13969 }
13970 # show long version names with GCC version and CPU architecture name (if different)
13971 $TestInfo .= "<tr><th>Version #1</th><td>".$Descriptor{1}{"Version"}.(@VInf1?" (".join(", ", reverse(@VInf1)).")":"")."</td></tr>\n";
13972 $TestInfo .= "<tr><th>Version #2</th><td>".$Descriptor{2}{"Version"}.(@VInf2?" (".join(", ", reverse(@VInf2)).")":"")."</td></tr>\n";
13973 $TestInfo .= $AddTestInfo;
13974 #if($COMMON_LANGUAGE{1}) {
13975 # $TestInfo .= "<tr><th>Language</th><td>".$COMMON_LANGUAGE{1}."</td></tr>\n";
13976 #}
13977 if($ExtendedCheck) {
13978 $TestInfo .= "<tr><th>Mode</th><td>Extended</td></tr>\n";
13979 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040013980 if($JoinReport)
13981 {
13982 if($Level eq "Binary") {
Andrey Ponomarenko16934472012-03-29 15:37:04 +040013983 $TestInfo .= "<tr><th>Subject</th><td width='150px'>Binary Compatibility</td></tr>\n"; # Run-time
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040013984 }
13985 if($Level eq "Source") {
Andrey Ponomarenko16934472012-03-29 15:37:04 +040013986 $TestInfo .= "<tr><th>Subject</th><td width='150px'>Source Compatibility</td></tr>\n"; # Build-time
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040013987 }
13988 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013989 $TestInfo .= "</table>\n";
13990
13991 # test results
13992 $TestResults = "<h2>Test Results</h2><hr/>\n";
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040013993 $TestResults .= "<table class='summary'>";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013994
13995 my $Headers_Link = "0";
13996 $Headers_Link = "<a href='#Headers' style='color:Blue;'>".keys(%{$Registered_Headers{1}})."</a>" if(keys(%{$Registered_Headers{1}})>0);
13997 $TestResults .= "<tr><th>Total Header Files</th><td>".($CheckObjectsOnly?"0&#160;(not&#160;analyzed)":$Headers_Link)."</td></tr>\n";
13998
13999 if(not $ExtendedCheck)
14000 {
14001 my $Libs_Link = "0";
14002 $Libs_Link = "<a href='#Libs' style='color:Blue;'>".keys(%{$Library_Symbol{1}})."</a>" if(keys(%{$Library_Symbol{1}})>0);
14003 $TestResults .= "<tr><th>Total ".ucfirst($SLIB_TYPE)." Libraries</th><td>".($CheckHeadersOnly?"0&#160;(not&#160;analyzed)":$Libs_Link)."</td></tr>\n";
14004 }
14005
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040014006 $TestResults .= "<tr><th>Total Symbols / Types</th><td>".(keys(%{$CheckedSymbols{$Level}}) - keys(%ExtendedSymbols))." / ".$TotalTypes."</td></tr>\n";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014007
Andrey Ponomarenko85043792012-05-14 16:48:07 +040014008 my $META_DATA = "verdict:".$RESULT{$Level}{"Verdict"}.";";
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014009 if($JoinReport) {
14010 $META_DATA = "kind:".lc($Level).";".$META_DATA;
14011 }
Andrey Ponomarenko16934472012-03-29 15:37:04 +040014012 $TestResults .= "<tr><th>Verdict</th>";
Andrey Ponomarenko85043792012-05-14 16:48:07 +040014013 if($RESULT{$Level}{"Verdict"} eq "incompatible") {
Andrey Ponomarenko16934472012-03-29 15:37:04 +040014014 $TestResults .= "<td><span style='color:Red;'><b>Incompatible<br/>(".$RESULT{$Level}{"Affected"}."%)</b></span></td>";
14015 }
14016 else {
14017 $TestResults .= "<td><span style='color:Green;'><b>Compatible</b></span></td>";
14018 }
14019 $TestResults .= "</tr>\n";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014020 $TestResults .= "</table>\n";
14021
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014022 $META_DATA .= "affected:".$RESULT{$Level}{"Affected"}.";";# in percents
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014023 # problem summary
14024 $Problem_Summary = "<h2>Problem Summary</h2><hr/>\n";
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014025 $Problem_Summary .= "<table class='summary'>";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014026 $Problem_Summary .= "<tr><th></th><th style='text-align:center;'>Severity</th><th style='text-align:center;'>Count</th></tr>";
14027
14028 my $Added_Link = "0";
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014029 if($Added>0)
14030 {
14031 if($JoinReport) {
14032 $Added_Link = "<a href='#".$Level."_Added' style='color:Blue;'>$Added</a>";
14033 }
14034 else {
14035 $Added_Link = "<a href='#Added' style='color:Blue;'>$Added</a>";
14036 }
14037 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014038 $META_DATA .= "added:$Added;";
Andrey Ponomarenko16934472012-03-29 15:37:04 +040014039 $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 +040014040
14041 my $Removed_Link = "0";
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014042 if($Removed>0)
14043 {
14044 if($JoinReport) {
14045 $Removed_Link = "<a href='#".$Level."_Removed' style='color:Blue;'>$Removed</a>"
14046 }
14047 else {
14048 $Removed_Link = "<a href='#Removed' style='color:Blue;'>$Removed</a>"
14049 }
14050 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014051 $META_DATA .= "removed:$Removed;";
Andrey Ponomarenko16934472012-03-29 15:37:04 +040014052 $Problem_Summary .= "<tr><th>Removed Symbols</th>";
14053 $Problem_Summary .= "<td>High</td><td".getStyle("I", "R", $Removed).">$Removed_Link</td></tr>\n";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014054
14055 my $TH_Link = "0";
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014056 $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 +040014057 $TH_Link = "n/a" if($CheckObjectsOnly);
14058 $META_DATA .= "type_problems_high:$T_Problems_High;";
Andrey Ponomarenko16934472012-03-29 15:37:04 +040014059 $Problem_Summary .= "<tr><th rowspan='3'>Problems with<br/>Data Types</th>";
14060 $Problem_Summary .= "<td>High</td><td".getStyle("T", "H", $T_Problems_High).">$TH_Link</td></tr>\n";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014061
14062 my $TM_Link = "0";
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014063 $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 +040014064 $TM_Link = "n/a" if($CheckObjectsOnly);
14065 $META_DATA .= "type_problems_medium:$T_Problems_Medium;";
Andrey Ponomarenko16934472012-03-29 15:37:04 +040014066 $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 +040014067
14068 my $TL_Link = "0";
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014069 $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 +040014070 $TL_Link = "n/a" if($CheckObjectsOnly);
14071 $META_DATA .= "type_problems_low:$T_Problems_Low;";
Andrey Ponomarenko16934472012-03-29 15:37:04 +040014072 $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 +040014073
14074 my $IH_Link = "0";
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014075 $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 +040014076 $IH_Link = "n/a" if($CheckObjectsOnly);
14077 $META_DATA .= "interface_problems_high:$I_Problems_High;";
Andrey Ponomarenko16934472012-03-29 15:37:04 +040014078 $Problem_Summary .= "<tr><th rowspan='3'>Problems with<br/>Symbols</th>";
14079 $Problem_Summary .= "<td>High</td><td".getStyle("I", "H", $I_Problems_High).">$IH_Link</td></tr>\n";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014080
14081 my $IM_Link = "0";
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014082 $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 +040014083 $IM_Link = "n/a" if($CheckObjectsOnly);
14084 $META_DATA .= "interface_problems_medium:$I_Problems_Medium;";
Andrey Ponomarenko16934472012-03-29 15:37:04 +040014085 $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 +040014086
14087 my $IL_Link = "0";
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014088 $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 +040014089 $IL_Link = "n/a" if($CheckObjectsOnly);
14090 $META_DATA .= "interface_problems_low:$I_Problems_Low;";
Andrey Ponomarenko16934472012-03-29 15:37:04 +040014091 $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 +040014092
14093 my $ChangedConstants_Link = "0";
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014094 if(keys(%{$CheckedSymbols{$Level}}) and $C_Problems_Low)
14095 {
14096 if($JoinReport) {
14097 $ChangedConstants_Link = "<a href='#".$Level."_Changed_Constants' style='color:Blue;'>$C_Problems_Low</a>";
14098 }
14099 else {
14100 $ChangedConstants_Link = "<a href='#Changed_Constants' style='color:Blue;'>$C_Problems_Low</a>";
14101 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014102 }
14103 $ChangedConstants_Link = "n/a" if($CheckObjectsOnly);
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014104 $META_DATA .= "changed_constants:$C_Problems_Low;";
Andrey Ponomarenko16934472012-03-29 15:37:04 +040014105 $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 +040014106
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014107 if($CheckImpl and $Level eq "Binary")
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014108 {
14109 my $ChangedImpl_Link = "0";
14110 $ChangedImpl_Link = "<a href='#Changed_Implementation' style='color:Blue;'>".keys(%ImplProblems)."</a>" if(keys(%ImplProblems)>0);
14111 $ChangedImpl_Link = "n/a" if($CheckHeadersOnly);
14112 $META_DATA .= "changed_implementation:".keys(%ImplProblems).";";
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040014113 $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 +040014114 }
14115 # Safe Changes
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014116 if($T_Other and not $CheckObjectsOnly)
14117 {
14118 my $TS_Link = "<a href='#".get_Anchor("Type", $Level, "Safe")."' style='color:Blue;'>$T_Other</a>";
Andrey Ponomarenko16934472012-03-29 15:37:04 +040014119 $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 +040014120 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014121
14122 if($I_Other and not $CheckObjectsOnly)
14123 {
14124 my $IS_Link = "<a href='#".get_Anchor("Symbol", $Level, "Safe")."' style='color:Blue;'>$I_Other</a>";
Andrey Ponomarenko16934472012-03-29 15:37:04 +040014125 $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 +040014126 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014127
14128 $META_DATA .= "tool_version:$TOOL_VERSION";
14129 $Problem_Summary .= "</table>\n";
Andrey Ponomarenko16934472012-03-29 15:37:04 +040014130 # $TestInfo = getLegend().$TestInfo;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014131 return ($TestInfo.$TestResults.$Problem_Summary, $META_DATA);
14132 }
14133}
14134
Andrey Ponomarenko16934472012-03-29 15:37:04 +040014135sub getStyle($$$)
14136{
14137 my ($Subj, $Act, $Num) = @_;
14138 my %Style = (
14139 "A"=>"new",
14140 "R"=>"failed",
14141 "S"=>"passed",
14142 "L"=>"warning",
14143 "M"=>"failed",
14144 "H"=>"failed"
14145 );
14146 if($Num>0) {
14147 return " class='".$Style{$Act}."'";
14148 }
14149 return "";
14150}
14151
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014152sub show_number($)
14153{
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014154 if($_[0])
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014155 {
Andrey Ponomarenko16934472012-03-29 15:37:04 +040014156 my $Num = cut_off_number($_[0], 2, 0);
14157 if($Num eq "0")
14158 {
14159 foreach my $P (3 .. 7)
14160 {
14161 $Num = cut_off_number($_[0], $P, 1);
14162 if($Num ne "0") {
14163 last;
14164 }
14165 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014166 }
14167 if($Num eq "0") {
14168 $Num = $_[0];
14169 }
14170 return $Num;
14171 }
14172 return $_[0];
14173}
14174
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014175sub cut_off_number($$$)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014176{
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014177 my ($num, $digs_to_cut, $z) = @_;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014178 if($num!~/\./)
14179 {
14180 $num .= ".";
14181 foreach (1 .. $digs_to_cut-1) {
14182 $num .= "0";
14183 }
14184 }
14185 elsif($num=~/\.(.+)\Z/ and length($1)<$digs_to_cut-1)
14186 {
14187 foreach (1 .. $digs_to_cut - 1 - length($1)) {
14188 $num .= "0";
14189 }
14190 }
14191 elsif($num=~/\d+\.(\d){$digs_to_cut,}/) {
14192 $num=sprintf("%.".($digs_to_cut-1)."f", $num);
14193 }
14194 $num=~s/\.[0]+\Z//g;
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014195 if($z) {
14196 $num=~s/(\.[1-9]+)[0]+\Z/$1/g;
14197 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014198 return $num;
14199}
14200
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014201sub get_Report_ChangedConstants($)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014202{
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014203 my $Level = $_[0];
Andrey Ponomarenko16934472012-03-29 15:37:04 +040014204 my $CHANGED_CONSTANTS = "";
14205 my %ReportMap = ();
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014206 foreach my $Constant (keys(%{$ProblemsWithConstants{$Level}})) {
Andrey Ponomarenko16934472012-03-29 15:37:04 +040014207 $ReportMap{$Constants{1}{$Constant}{"Header"}}{$Constant} = 1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014208 }
14209 my $Kind = "Changed_Constant";
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014210 if(not defined $CompatRules{$Level}{$Kind}) {
14211 return "";
14212 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014213 if($ReportFormat eq "xml")
14214 { # XML
Andrey Ponomarenko16934472012-03-29 15:37:04 +040014215 foreach my $HeaderName (sort {lc($a) cmp lc($b)} keys(%ReportMap))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014216 {
14217 $CHANGED_CONSTANTS .= " <header name=\"$HeaderName\">\n";
Andrey Ponomarenko16934472012-03-29 15:37:04 +040014218 foreach my $Constant (sort {lc($a) cmp lc($b)} keys(%{$ReportMap{$HeaderName}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014219 {
14220 $CHANGED_CONSTANTS .= " <constant name=\"$Constant\">\n";
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014221 my $Change = $CompatRules{$Level}{$Kind}{"Change"};
14222 my $Effect = $CompatRules{$Level}{$Kind}{"Effect"};
14223 my $Overcome = $CompatRules{$Level}{$Kind}{"Overcome"};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014224 $CHANGED_CONSTANTS .= " <problem id=\"$Kind\">\n";
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014225 $CHANGED_CONSTANTS .= " <change".getXmlParams($Change, $ProblemsWithConstants{$Level}{$Constant}).">$Change</change>\n";
14226 $CHANGED_CONSTANTS .= " <effect".getXmlParams($Effect, $ProblemsWithConstants{$Level}{$Constant}).">$Effect</effect>\n";
14227 $CHANGED_CONSTANTS .= " <overcome".getXmlParams($Overcome, $ProblemsWithConstants{$Level}{$Constant}).">$Overcome</overcome>\n";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014228 $CHANGED_CONSTANTS .= " </problem>\n";
14229 $CHANGED_CONSTANTS .= " </constant>\n";
14230 }
14231 $CHANGED_CONSTANTS .= " </header>\n";
14232 }
14233 $CHANGED_CONSTANTS = "<problems_with_constants severity=\"Low\">\n".$CHANGED_CONSTANTS."</problems_with_constants>\n\n";
14234 }
14235 else
14236 { # HTML
14237 my $Number = 0;
Andrey Ponomarenko16934472012-03-29 15:37:04 +040014238 foreach my $HeaderName (sort {lc($a) cmp lc($b)} keys(%ReportMap))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014239 {
14240 $CHANGED_CONSTANTS .= "<span class='h_name'>$HeaderName</span><br/>\n";
Andrey Ponomarenko16934472012-03-29 15:37:04 +040014241 foreach my $Name (sort {lc($a) cmp lc($b)} keys(%{$ReportMap{$HeaderName}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014242 {
14243 $Number += 1;
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014244 my $Change = applyMacroses($Level, $Kind, $CompatRules{$Level}{$Kind}{"Change"}, $ProblemsWithConstants{$Level}{$Name});
14245 my $Effect = $CompatRules{$Level}{$Kind}{"Effect"};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014246 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 +040014247 $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 +040014248 $Report = $ContentSpanStart."<span class='extendable'>[+]</span> ".$Name.$ContentSpanEnd."<br/>\n".$Report;
14249 $CHANGED_CONSTANTS .= insertIDs($Report);
14250 }
14251 $CHANGED_CONSTANTS .= "<br/>\n";
14252 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014253 if($CHANGED_CONSTANTS)
14254 {
14255 my $Anchor = "<a name='Changed_Constants'></a>";
14256 if($JoinReport) {
14257 $Anchor = "<a name='".$Level."_Changed_Constants'></a>";
14258 }
14259 $CHANGED_CONSTANTS = $Anchor."<h2>Problems with Constants ($Number)</h2><hr/>\n".$CHANGED_CONSTANTS.$TOP_REF."<br/>\n";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014260 }
14261 }
14262 return $CHANGED_CONSTANTS;
14263}
14264
14265sub get_Report_Impl()
14266{
Andrey Ponomarenko16934472012-03-29 15:37:04 +040014267 my $CHANGED_IMPLEMENTATION = "";
14268 my %ReportMap = ();
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014269 foreach my $Interface (sort keys(%ImplProblems))
14270 {
14271 my $HeaderName = $CompleteSignature{1}{$Interface}{"Header"};
14272 my $DyLib = $Symbol_Library{1}{$Interface};
Andrey Ponomarenko16934472012-03-29 15:37:04 +040014273 $ReportMap{$HeaderName}{$DyLib}{$Interface} = 1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014274 }
14275 my $Changed_Number = 0;
Andrey Ponomarenko16934472012-03-29 15:37:04 +040014276 foreach my $HeaderName (sort {lc($a) cmp lc($b)} keys(%ReportMap))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014277 {
Andrey Ponomarenko16934472012-03-29 15:37:04 +040014278 foreach my $DyLib (sort {lc($a) cmp lc($b)} keys(%{$ReportMap{$HeaderName}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014279 {
14280 my $FDyLib=$DyLib.($DyLib!~/\.\w+\Z/?" (.$LIB_EXT)":"");
14281 if($HeaderName) {
14282 $CHANGED_IMPLEMENTATION .= "<span class='h_name'>$HeaderName</span>, <span class='lib_name'>$FDyLib</span><br/>\n";
14283 }
14284 else {
14285 $CHANGED_IMPLEMENTATION .= "<span class='lib_name'>$DyLib</span><br/>\n";
14286 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014287 my %NameSpaceSymbols = ();
Andrey Ponomarenko16934472012-03-29 15:37:04 +040014288 foreach my $Interface (keys(%{$ReportMap{$HeaderName}{$DyLib}})) {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014289 $NameSpaceSymbols{get_IntNameSpace($Interface, 2)}{$Interface} = 1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014290 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014291 foreach my $NameSpace (sort keys(%NameSpaceSymbols))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014292 {
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040014293 $CHANGED_IMPLEMENTATION .= ($NameSpace)?"<span class='ns_title'>namespace</span> <span class='ns'>$NameSpace</span><br/>\n":"";
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014294 my @SortedInterfaces = sort {lc(get_Signature($a, 1)) cmp lc(get_Signature($b, 1))} keys(%{$NameSpaceSymbols{$NameSpace}});
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014295 foreach my $Interface (@SortedInterfaces)
14296 {
14297 $Changed_Number += 1;
14298 my $Signature = get_Signature($Interface, 1);
14299 if($NameSpace) {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040014300 $Signature=~s/\b\Q$NameSpace\E::\b//g;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014301 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014302 $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 +040014303 }
14304 }
14305 $CHANGED_IMPLEMENTATION .= "<br/>\n";
14306 }
14307 }
14308 if($CHANGED_IMPLEMENTATION) {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014309 $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 +040014310 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +040014311
14312 # clean memory
14313 %ImplProblems = ();
14314
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014315 return $CHANGED_IMPLEMENTATION;
14316}
14317
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014318sub getTitle($$$)
14319{
14320 my ($Header, $Library, $NameSpace) = @_;
14321 my $Title = "";
14322 if($Library and $Library!~/\.\w+\Z/) {
14323 $Library .= " (.$LIB_EXT)";
14324 }
14325 if($Header and $Library)
14326 {
14327 $Title .= "<span class='h_name'>$Header</span>";
14328 $Title .= ", <span class='lib_name'>$Library</span><br/>\n";
14329 }
14330 elsif($Library) {
14331 $Title .= "<span class='lib_name'>$Library</span><br/>\n";
14332 }
14333 elsif($Header) {
14334 $Title .= "<span class='h_name'>$Header</span><br/>\n";
14335 }
14336 if($NameSpace) {
14337 $Title .= "<span class='ns_title'>namespace</span> <span class='ns'>$NameSpace</span><br/>\n";
14338 }
14339 return $Title;
14340}
14341
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014342sub get_Report_Added($)
14343{
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014344 my $Level = $_[0];
Andrey Ponomarenko16934472012-03-29 15:37:04 +040014345 my $ADDED_INTERFACES = "";
14346 my %ReportMap = ();
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014347 foreach my $Interface (sort keys(%{$CompatProblems{$Level}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014348 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014349 foreach my $Kind (sort keys(%{$CompatProblems{$Level}{$Interface}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014350 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014351 if($Kind eq "Added_Symbol")
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014352 {
14353 my $HeaderName = $CompleteSignature{2}{$Interface}{"Header"};
14354 my $DyLib = $Symbol_Library{2}{$Interface};
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014355 if($Level eq "Source" and $ReportFormat eq "html")
14356 { # do not show library name in HTML report
14357 $DyLib = "";
14358 }
14359 $ReportMap{$HeaderName}{$DyLib}{$Interface} = 1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014360 }
14361 }
14362 }
14363 if($ReportFormat eq "xml")
14364 { # XML
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014365 foreach my $HeaderName (sort {lc($a) cmp lc($b)} keys(%ReportMap))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014366 {
14367 $ADDED_INTERFACES .= " <header name=\"$HeaderName\">\n";
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014368 foreach my $DyLib (sort {lc($a) cmp lc($b)} keys(%{$ReportMap{$HeaderName}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014369 {
14370 $ADDED_INTERFACES .= " <library name=\"$DyLib\">\n";
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014371 foreach my $Interface (keys(%{$ReportMap{$HeaderName}{$DyLib}})) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014372 $ADDED_INTERFACES .= " <name>$Interface</name>\n";
14373 }
14374 $ADDED_INTERFACES .= " </library>\n";
14375 }
14376 $ADDED_INTERFACES .= " </header>\n";
14377 }
14378 $ADDED_INTERFACES = "<added_symbols>\n".$ADDED_INTERFACES."</added_symbols>\n\n";
14379 }
14380 else
14381 { # HTML
14382 my $Added_Number = 0;
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014383 foreach my $HeaderName (sort {lc($a) cmp lc($b)} keys(%ReportMap))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014384 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014385 foreach my $DyLib (sort {lc($a) cmp lc($b)} keys(%{$ReportMap{$HeaderName}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014386 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014387 my %NameSpaceSymbols = ();
14388 foreach my $Interface (keys(%{$ReportMap{$HeaderName}{$DyLib}})) {
14389 $NameSpaceSymbols{get_IntNameSpace($Interface, 2)}{$Interface} = 1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014390 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014391 foreach my $NameSpace (sort keys(%NameSpaceSymbols))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014392 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014393 $ADDED_INTERFACES .= getTitle($HeaderName, $DyLib, $NameSpace);
14394 my @SortedInterfaces = sort {lc(get_Signature($a, 2)) cmp lc(get_Signature($b, 2))} keys(%{$NameSpaceSymbols{$NameSpace}});
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014395 foreach my $Interface (@SortedInterfaces)
14396 {
14397 $Added_Number += 1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014398 my $Signature = get_Signature($Interface, 2);
14399 if($NameSpace) {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040014400 $Signature=~s/\b\Q$NameSpace\E::\b//g;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014401 }
14402 if($Interface=~/\A(_Z|\?)/) {
14403 if($Signature) {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014404 $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 +040014405 }
14406 else {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014407 $ADDED_INTERFACES .= "<span class=\"iname\">".$Interface."</span><br/>\n";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014408 }
14409 }
14410 else {
14411 if($Signature) {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014412 $ADDED_INTERFACES .= "<span class=\"iname\">".highLight_Signature_Italic_Color($Signature)."</span><br/>\n";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014413 }
14414 else {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014415 $ADDED_INTERFACES .= "<span class=\"iname\">".$Interface."</span><br/>\n";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014416 }
14417 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014418 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014419 $ADDED_INTERFACES .= "<br/>\n";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014420 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014421 }
14422 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014423 if($ADDED_INTERFACES)
14424 {
14425 my $Anchor = "<a name='Added'></a>";
14426 if($JoinReport) {
14427 $Anchor = "<a name='".$Level."_Added'></a>";
14428 }
14429 $ADDED_INTERFACES = $Anchor."<h2>Added Symbols ($Added_Number)</h2><hr/>\n".$ADDED_INTERFACES.$TOP_REF."<br/>\n";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014430 }
14431 }
14432 return $ADDED_INTERFACES;
14433}
14434
14435sub get_Report_Removed($)
14436{
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014437 my $Level = $_[0];
Andrey Ponomarenko16934472012-03-29 15:37:04 +040014438 my $REMOVED_INTERFACES = "";
14439 my %ReportMap = ();
Andrey Ponomarenko85043792012-05-14 16:48:07 +040014440 foreach my $Symbol (sort keys(%{$CompatProblems{$Level}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014441 {
Andrey Ponomarenko85043792012-05-14 16:48:07 +040014442 foreach my $Kind (sort keys(%{$CompatProblems{$Level}{$Symbol}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014443 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014444 if($Kind eq "Removed_Symbol")
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014445 {
Andrey Ponomarenko85043792012-05-14 16:48:07 +040014446 my $HeaderName = $CompleteSignature{1}{$Symbol}{"Header"};
14447 my $DyLib = $Symbol_Library{1}{$Symbol};
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014448 if($Level eq "Source" and $ReportFormat eq "html")
14449 { # do not show library name in HTML report
14450 $DyLib = "";
14451 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +040014452 $ReportMap{$HeaderName}{$DyLib}{$Symbol} = 1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014453 }
14454 }
14455 }
14456 if($ReportFormat eq "xml")
14457 { # XML
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014458 foreach my $HeaderName (sort {lc($a) cmp lc($b)} keys(%ReportMap))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014459 {
14460 $REMOVED_INTERFACES .= " <header name=\"$HeaderName\">\n";
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014461 foreach my $DyLib (sort {lc($a) cmp lc($b)} keys(%{$ReportMap{$HeaderName}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014462 {
14463 $REMOVED_INTERFACES .= " <library name=\"$DyLib\">\n";
Andrey Ponomarenko85043792012-05-14 16:48:07 +040014464 foreach my $Symbol (keys(%{$ReportMap{$HeaderName}{$DyLib}})) {
14465 $REMOVED_INTERFACES .= " <name>$Symbol</name>\n";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014466 }
14467 $REMOVED_INTERFACES .= " </library>\n";
14468 }
14469 $REMOVED_INTERFACES .= " </header>\n";
14470 }
14471 $REMOVED_INTERFACES = "<removed_symbols>\n".$REMOVED_INTERFACES."</removed_symbols>\n\n";
14472 }
14473 else
14474 { # HTML
14475 my $Removed_Number = 0;
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014476 foreach my $HeaderName (sort {lc($a) cmp lc($b)} keys(%ReportMap))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014477 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014478 foreach my $DyLib (sort {lc($a) cmp lc($b)} keys(%{$ReportMap{$HeaderName}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014479 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014480 my %NameSpaceSymbols = ();
14481 foreach my $Interface (keys(%{$ReportMap{$HeaderName}{$DyLib}})) {
14482 $NameSpaceSymbols{get_IntNameSpace($Interface, 1)}{$Interface} = 1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014483 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014484 foreach my $NameSpace (sort keys(%NameSpaceSymbols))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014485 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014486 $REMOVED_INTERFACES .= getTitle($HeaderName, $DyLib, $NameSpace);
14487 my @SortedInterfaces = sort {lc(get_Signature($a, 1)) cmp lc(get_Signature($b, 1))} keys(%{$NameSpaceSymbols{$NameSpace}});
Andrey Ponomarenko85043792012-05-14 16:48:07 +040014488 foreach my $Symbol (@SortedInterfaces)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014489 {
14490 $Removed_Number += 1;
14491 my $SubReport = "";
Andrey Ponomarenko85043792012-05-14 16:48:07 +040014492 my $Signature = get_Signature($Symbol, 1);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014493 if($NameSpace) {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040014494 $Signature=~s/\b\Q$NameSpace\E::\b//g;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014495 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +040014496 if($Symbol=~/\A(_Z|\?)/)
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014497 {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014498 if($Signature) {
Andrey Ponomarenko85043792012-05-14 16:48:07 +040014499 $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 +040014500 }
14501 else {
Andrey Ponomarenko85043792012-05-14 16:48:07 +040014502 $REMOVED_INTERFACES .= "<span class=\"iname\">".$Symbol."</span><br/>\n";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014503 }
14504 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014505 else
14506 {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014507 if($Signature) {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014508 $REMOVED_INTERFACES .= "<span class=\"iname\">".highLight_Signature_Italic_Color($Signature)."</span><br/>\n";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014509 }
14510 else {
Andrey Ponomarenko85043792012-05-14 16:48:07 +040014511 $REMOVED_INTERFACES .= "<span class=\"iname\">".$Symbol."</span><br/>\n";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014512 }
14513 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014514 }
14515 }
14516 $REMOVED_INTERFACES .= "<br/>\n";
14517 }
14518 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014519 if($REMOVED_INTERFACES)
14520 {
14521 my $Anchor = "<a name='Removed'></a><a name='Withdrawn'></a>";
14522 if($JoinReport) {
14523 $Anchor = "<a name='".$Level."_Removed'></a><a name='".$Level."_Withdrawn'></a>";
14524 }
14525 $REMOVED_INTERFACES = $Anchor."<h2>Removed Symbols ($Removed_Number)</h2><hr/>\n".$REMOVED_INTERFACES.$TOP_REF."<br/>\n";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014526 }
14527 }
14528 return $REMOVED_INTERFACES;
14529}
14530
14531sub getXmlParams($$)
14532{
14533 my ($Content, $Problem) = @_;
14534 return "" if(not $Content or not $Problem);
14535 my %XMLparams = ();
14536 foreach my $Attr (sort {$b cmp $a} keys(%{$Problem}))
14537 {
14538 my $Macro = "\@".lc($Attr);
14539 if($Content=~/\Q$Macro\E/) {
14540 $XMLparams{lc($Attr)} = $Problem->{$Attr};
14541 }
14542 }
14543 my @PString = ();
14544 foreach my $P (sort {$b cmp $a} keys(%XMLparams)) {
Andrey Ponomarenko5c09ef32012-06-14 18:17:33 +040014545 push(@PString, $P."=\"".xmlSpecChars($XMLparams{$P})."\"");
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014546 }
14547 if(@PString) {
14548 return " ".join(" ", @PString);
14549 }
14550 else {
14551 return "";
14552 }
14553}
14554
14555sub addMarkup($)
14556{
14557 my $Content = $_[0];
14558 # auto-markup
14559 $Content=~s/\n[ ]*//; # spaces
14560 $Content=~s!(\@\w+\s*\(\@\w+\))!<nowrap>$1</nowrap>!g; # @old_type (@old_size)
14561 $Content=~s!(... \(\w+\))!<nowrap><b>$1</b></nowrap>!g; # ... (va_list)
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040014562 $Content=~s!<nowrap>(.+?)</nowrap>!<span class='nowrap'>$1</span>!g;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014563 $Content=~s!([2-9]\))!<br/>$1!g; # 1), 2), ...
14564 if($Content=~/\ANOTE:/)
14565 { # notes
14566 $Content=~s!(NOTE):!<b>$1</b>:!g;
14567 }
14568 else {
14569 $Content=~s!(NOTE):!<br/><b>$1</b>:!g;
14570 }
14571 $Content=~s! (out)-! <b>$1</b>-!g; # out-parameters
14572 my @Keywords = (
14573 "void",
14574 "const",
14575 "static",
14576 "restrict",
14577 "volatile",
14578 "register",
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040014579 "virtual"
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014580 );
14581 my $MKeys = join("|", @Keywords);
14582 foreach (@Keywords) {
14583 $MKeys .= "|non-".$_;
14584 }
14585 $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 +040014586
14587 # Markdown
14588 $Content=~s!\*\*([\w\-]+)\*\*!<b>$1</b>!ig;
14589 $Content=~s!\*([\w\-]+)\*!<i>$1</i>!ig;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014590 return $Content;
14591}
14592
14593sub applyMacroses($$$$)
14594{
14595 my ($Level, $Kind, $Content, $Problem) = @_;
14596 return "" if(not $Content or not $Problem);
14597 $Problem->{"Word_Size"} = $WORD_SIZE{2};
14598 $Content = addMarkup($Content);
14599 # macros
14600 foreach my $Attr (sort {$b cmp $a} keys(%{$Problem}))
14601 {
14602 my $Macro = "\@".lc($Attr);
14603 my $Value = $Problem->{$Attr};
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040014604 if(not defined $Value
14605 or $Value eq "") {
14606 next;
14607 }
Andrey Ponomarenko5c09ef32012-06-14 18:17:33 +040014608 if($Value=~/\s\(/ and $Value!~/['"]/)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014609 { # functions
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014610 $Value=~s/\s*\[[\w\-]+\]//g; # remove quals
14611 $Value=~s/\s\w+(\)|,)/$1/g; # remove parameter names
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014612 $Value = black_name($Value);
14613 }
14614 elsif($Value=~/\s/) {
14615 $Value = "<span class='value'>".htmlSpecChars($Value)."</span>";
14616 }
14617 elsif($Value=~/\A\d+\Z/
14618 and ($Attr eq "Old_Size" or $Attr eq "New_Size"))
14619 { # bits to bytes
14620 if($Value % $BYTE_SIZE)
14621 { # bits
14622 if($Value==1) {
14623 $Value = "<b>".$Value."</b> bit";
14624 }
14625 else {
14626 $Value = "<b>".$Value."</b> bits";
14627 }
14628 }
14629 else
14630 { # bytes
14631 $Value /= $BYTE_SIZE;
14632 if($Value==1) {
14633 $Value = "<b>".$Value."</b> byte";
14634 }
14635 else {
14636 $Value = "<b>".$Value."</b> bytes";
14637 }
14638 }
14639 }
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040014640 else
14641 {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014642 $Value = "<b>".htmlSpecChars($Value)."</b>";
14643 }
14644 $Content=~s/\Q$Macro\E/$Value/g;
14645 }
14646
14647 if($Content=~/(\A|[^\@\w])\@\w/)
14648 {
14649 if(not $IncompleteRules{$Level}{$Kind})
14650 { # only one warning
14651 printMsg("WARNING", "incomplete rule \"$Kind\" (\"$Level\")");
14652 $IncompleteRules{$Level}{$Kind} = 1;
14653 }
14654 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014655 return $Content;
14656}
14657
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040014658sub get_Report_SymbolProblems($$)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014659{
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014660 my ($TargetSeverity, $Level) = @_;
Andrey Ponomarenko16934472012-03-29 15:37:04 +040014661 my $INTERFACE_PROBLEMS = "";
14662 my (%ReportMap, %SymbolChanges) = ();
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014663 foreach my $Symbol (sort keys(%{$CompatProblems{$Level}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014664 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014665 my ($SN, $SS, $SV) = separate_symbol($Symbol);
14666 if($SV and defined $CompatProblems{$Level}{$SN}) {
14667 next;
14668 }
14669 foreach my $Kind (sort keys(%{$CompatProblems{$Level}{$Symbol}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014670 {
14671 if($CompatRules{$Level}{$Kind}{"Kind"} eq "Symbols"
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014672 and $Kind ne "Added_Symbol" and $Kind ne "Removed_Symbol")
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014673 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014674 my $HeaderName = $CompleteSignature{1}{$Symbol}{"Header"};
14675 my $DyLib = $Symbol_Library{1}{$Symbol};
14676 if(not $DyLib and my $VSym = $SymVer{1}{$Symbol})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014677 { # Symbol with Version
14678 $DyLib = $Symbol_Library{1}{$VSym};
14679 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040014680 if(not $DyLib)
14681 { # const global data
14682 $DyLib = "";
14683 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014684 if($Level eq "Source" and $ReportFormat eq "html")
14685 { # do not show library name in HTML report
14686 $DyLib = "";
14687 }
14688 %{$SymbolChanges{$Symbol}{$Kind}} = %{$CompatProblems{$Level}{$Symbol}{$Kind}};
14689 foreach my $Location (sort keys(%{$SymbolChanges{$Symbol}{$Kind}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014690 {
14691 my $Priority = getProblemSeverity($Level, $Kind);
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014692 if($Priority ne $TargetSeverity) {
14693 delete($SymbolChanges{$Symbol}{$Kind}{$Location});
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014694 }
14695 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014696 if(not keys(%{$SymbolChanges{$Symbol}{$Kind}}))
14697 {
14698 delete($SymbolChanges{$Symbol}{$Kind});
14699 next;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014700 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014701 $ReportMap{$HeaderName}{$DyLib}{$Symbol} = 1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014702 }
14703 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014704 if(not keys(%{$SymbolChanges{$Symbol}})) {
14705 delete($SymbolChanges{$Symbol});
14706 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014707 }
14708 if($ReportFormat eq "xml")
14709 { # XML
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014710 foreach my $HeaderName (sort {lc($a) cmp lc($b)} keys(%ReportMap))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014711 {
14712 $INTERFACE_PROBLEMS .= " <header name=\"$HeaderName\">\n";
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014713 foreach my $DyLib (sort {lc($a) cmp lc($b)} keys(%{$ReportMap{$HeaderName}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014714 {
14715 $INTERFACE_PROBLEMS .= " <library name=\"$DyLib\">\n";
14716 foreach my $Symbol (sort {lc($tr_name{$a}) cmp lc($tr_name{$b})} keys(%SymbolChanges))
14717 {
14718 $INTERFACE_PROBLEMS .= " <symbol name=\"$Symbol\">\n";
14719 foreach my $Kind (keys(%{$SymbolChanges{$Symbol}}))
14720 {
14721 foreach my $Location (sort keys(%{$SymbolChanges{$Symbol}{$Kind}}))
14722 {
14723 my %Problem = %{$SymbolChanges{$Symbol}{$Kind}{$Location}};
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040014724 $Problem{"Param_Pos"} = showPos($Problem{"Param_Pos"});
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014725 $INTERFACE_PROBLEMS .= " <problem id=\"$Kind\">\n";
14726 my $Change = $CompatRules{$Level}{$Kind}{"Change"};
14727 $INTERFACE_PROBLEMS .= " <change".getXmlParams($Change, \%Problem).">$Change</change>\n";
14728 my $Effect = $CompatRules{$Level}{$Kind}{"Effect"};
14729 $INTERFACE_PROBLEMS .= " <effect".getXmlParams($Effect, \%Problem).">$Effect</effect>\n";
14730 my $Overcome = $CompatRules{$Level}{$Kind}{"Overcome"};
14731 $INTERFACE_PROBLEMS .= " <overcome".getXmlParams($Overcome, \%Problem).">$Overcome</overcome>\n";
14732 $INTERFACE_PROBLEMS .= " </problem>\n";
14733 }
14734 }
14735 $INTERFACE_PROBLEMS .= " </symbol>\n";
14736 }
14737 $INTERFACE_PROBLEMS .= " </library>\n";
14738 }
14739 $INTERFACE_PROBLEMS .= " </header>\n";
14740 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014741 $INTERFACE_PROBLEMS = "<problems_with_symbols severity=\"$TargetSeverity\">\n".$INTERFACE_PROBLEMS."</problems_with_symbols>\n\n";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014742 }
14743 else
14744 { # HTML
14745 my $ProblemsNum = 0;
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014746 foreach my $HeaderName (sort {lc($a) cmp lc($b)} keys(%ReportMap))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014747 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014748 foreach my $DyLib (sort {lc($a) cmp lc($b)} keys(%{$ReportMap{$HeaderName}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014749 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014750 my (%NameSpaceSymbols, %NewSignature) = ();
14751 foreach my $Symbol (keys(%{$ReportMap{$HeaderName}{$DyLib}})) {
14752 $NameSpaceSymbols{get_IntNameSpace($Symbol, 1)}{$Symbol} = 1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014753 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014754 foreach my $NameSpace (sort keys(%NameSpaceSymbols))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014755 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014756 $INTERFACE_PROBLEMS .= getTitle($HeaderName, $DyLib, $NameSpace);
14757 my @SortedInterfaces = sort {lc($tr_name{$a}) cmp lc($tr_name{$b})} keys(%{$NameSpaceSymbols{$NameSpace}});
14758 foreach my $Symbol (@SortedInterfaces)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014759 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014760 my $Signature = get_Signature($Symbol, 1);
14761 my $SYMBOL_REPORT = "";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014762 my $ProblemNum = 1;
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014763 foreach my $Kind (keys(%{$SymbolChanges{$Symbol}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014764 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014765 foreach my $Location (sort keys(%{$SymbolChanges{$Symbol}{$Kind}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014766 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014767 my %Problem = %{$SymbolChanges{$Symbol}{$Kind}{$Location}};
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040014768 $Problem{"Param_Pos"} = showPos($Problem{"Param_Pos"});
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014769 if($Problem{"New_Signature"}) {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014770 $NewSignature{$Symbol} = $Problem{"New_Signature"};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014771 }
14772 if(my $Change = applyMacroses($Level, $Kind, $CompatRules{$Level}{$Kind}{"Change"}, \%Problem))
14773 {
14774 my $Effect = applyMacroses($Level, $Kind, $CompatRules{$Level}{$Kind}{"Effect"}, \%Problem);
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014775 $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 +040014776 $ProblemNum += 1;
14777 $ProblemsNum += 1;
14778 }
14779 }
14780 }
14781 $ProblemNum -= 1;
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014782 if($SYMBOL_REPORT)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014783 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014784 $INTERFACE_PROBLEMS .= $ContentSpanStart."<span class='extendable'>[+]</span> ";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014785 if($Signature) {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014786 $INTERFACE_PROBLEMS .= highLight_Signature_Italic_Color($Signature);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014787 }
14788 else {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014789 $INTERFACE_PROBLEMS .= $Symbol;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014790 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014791 $INTERFACE_PROBLEMS .= " ($ProblemNum)".$ContentSpanEnd."<br/>\n";
14792 $INTERFACE_PROBLEMS .= $ContentDivStart."\n";
14793 if($NewSignature{$Symbol})
14794 { # argument list changed to
14795 $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 +040014796 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014797 if($Symbol=~/\A(_Z|\?)/) {
14798 $INTERFACE_PROBLEMS .= "<span class='mangled'>&#160;&#160;&#160;&#160;[symbol: <b>$Symbol</b>]</span><br/>\n";
14799 }
14800 $INTERFACE_PROBLEMS .= "<table class='ptable'><tr><th width='2%'></th><th width='47%'>Change</th><th>Effect</th></tr>$SYMBOL_REPORT</table><br/>\n";
14801 $INTERFACE_PROBLEMS .= $ContentDivEnd;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014802 if($NameSpace) {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040014803 $INTERFACE_PROBLEMS=~s/\b\Q$NameSpace\E::\b//g;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014804 }
14805 }
14806 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014807 $INTERFACE_PROBLEMS .= "<br/>";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014808 }
14809 }
14810 }
14811 if($INTERFACE_PROBLEMS)
14812 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014813 $INTERFACE_PROBLEMS = insertIDs($INTERFACE_PROBLEMS);
14814 my $Title = "Problems with Symbols, $TargetSeverity Severity";
14815 if($TargetSeverity eq "Safe")
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014816 { # Safe Changes
14817 $Title = "Other Changes in Symbols";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014818 }
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040014819 $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 +040014820 }
14821 }
14822 return $INTERFACE_PROBLEMS;
14823}
14824
14825sub get_Report_TypeProblems($$)
14826{
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014827 my ($TargetSeverity, $Level) = @_;
Andrey Ponomarenko16934472012-03-29 15:37:04 +040014828 my $TYPE_PROBLEMS = "";
14829 my (%ReportMap, %TypeChanges, %TypeType) = ();
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014830 foreach my $Interface (sort keys(%{$CompatProblems{$Level}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014831 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014832 foreach my $Kind (keys(%{$CompatProblems{$Level}{$Interface}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014833 {
14834 if($CompatRules{$Level}{$Kind}{"Kind"} eq "Types")
14835 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014836 foreach my $Location (sort {cmp_locations($b, $a)} sort keys(%{$CompatProblems{$Level}{$Interface}{$Kind}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014837 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014838 my $TypeName = $CompatProblems{$Level}{$Interface}{$Kind}{$Location}{"Type_Name"};
14839 my $TypeType = $CompatProblems{$Level}{$Interface}{$Kind}{$Location}{"Type_Type"};
14840 my $Target = $CompatProblems{$Level}{$Interface}{$Kind}{$Location}{"Target"};
14841 $CompatProblems{$Level}{$Interface}{$Kind}{$Location}{"Type_Type"} = lc($TypeType);
14842 my $Severity = getProblemSeverity($Level, $Kind);
14843 if($Severity eq "Safe"
14844 and $TargetSeverity ne "Safe") {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014845 next;
14846 }
14847 if(not $TypeType{$TypeName}
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014848 or $TypeType{$TypeName} eq "struct")
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014849 { # register type of the type, select "class" if type has "class"- and "struct"-type changes
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014850 $TypeType{$TypeName} = $CompatProblems{$Level}{$Interface}{$Kind}{$Location}{"Type_Type"};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014851 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014852
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040014853 if(cmpSeverities($Type_MaxSeverity{$Level}{$TypeName}{$Kind}{$Target}, $Severity))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014854 { # select a problem with the highest priority
14855 next;
14856 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014857 %{$TypeChanges{$TypeName}{$Kind}{$Location}} = %{$CompatProblems{$Level}{$Interface}{$Kind}{$Location}};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014858 }
14859 }
14860 }
14861 }
14862 my %Kinds_Locations = ();
14863 foreach my $TypeName (keys(%TypeChanges))
14864 {
14865 my %Kinds_Target = ();
14866 foreach my $Kind (sort keys(%{$TypeChanges{$TypeName}}))
14867 {
14868 foreach my $Location (sort {cmp_locations($b, $a)} sort keys(%{$TypeChanges{$TypeName}{$Kind}}))
14869 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014870 my $Severity = getProblemSeverity($Level, $Kind);
14871 if($Severity ne $TargetSeverity)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014872 { # other priority
14873 delete($TypeChanges{$TypeName}{$Kind}{$Location});
14874 next;
14875 }
14876 $Kinds_Locations{$TypeName}{$Kind}{$Location} = 1;
14877 my $Target = $TypeChanges{$TypeName}{$Kind}{$Location}{"Target"};
14878 if($Kinds_Target{$Kind}{$Target})
14879 { # duplicate target
14880 delete($TypeChanges{$TypeName}{$Kind}{$Location});
14881 next;
14882 }
14883 $Kinds_Target{$Kind}{$Target} = 1;
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040014884 my $HeaderName = $TypeInfo{1}{$TName_Tid{1}{$TypeName}}{"Header"};
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014885 $ReportMap{$HeaderName}{$TypeName} = 1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014886 }
14887 if(not keys(%{$TypeChanges{$TypeName}{$Kind}})) {
14888 delete($TypeChanges{$TypeName}{$Kind});
14889 }
14890 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014891 if(not keys(%{$TypeChanges{$TypeName}})) {
14892 delete($TypeChanges{$TypeName});
14893 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014894 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +040014895 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 +040014896 if($ReportFormat eq "xml")
14897 { # XML
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014898 foreach my $HeaderName (sort {lc($a) cmp lc($b)} keys(%ReportMap))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014899 {
14900 $TYPE_PROBLEMS .= " <header name=\"$HeaderName\">\n";
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014901 foreach my $TypeName (keys(%{$ReportMap{$HeaderName}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014902 {
Andrey Ponomarenko5c09ef32012-06-14 18:17:33 +040014903 $TYPE_PROBLEMS .= " <type name=\"".xmlSpecChars($TypeName)."\">\n";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014904 foreach my $Kind (sort {$b=~/Size/ <=> $a=~/Size/} sort keys(%{$TypeChanges{$TypeName}}))
14905 {
14906 foreach my $Location (sort {cmp_locations($b, $a)} sort keys(%{$TypeChanges{$TypeName}{$Kind}}))
14907 {
14908 my %Problem = %{$TypeChanges{$TypeName}{$Kind}{$Location}};
14909 $TYPE_PROBLEMS .= " <problem id=\"$Kind\">\n";
14910 my $Change = $CompatRules{$Level}{$Kind}{"Change"};
14911 $TYPE_PROBLEMS .= " <change".getXmlParams($Change, \%Problem).">$Change</change>\n";
14912 my $Effect = $CompatRules{$Level}{$Kind}{"Effect"};
14913 $TYPE_PROBLEMS .= " <effect".getXmlParams($Effect, \%Problem).">$Effect</effect>\n";
14914 my $Overcome = $CompatRules{$Level}{$Kind}{"Overcome"};
14915 $TYPE_PROBLEMS .= " <overcome".getXmlParams($Overcome, \%Problem).">$Overcome</overcome>\n";
14916 $TYPE_PROBLEMS .= " </problem>\n";
14917 }
14918 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +040014919 $TYPE_PROBLEMS .= getAffectedSymbols($Level, $TypeName, $Kinds_Locations{$TypeName}, \@Symbols);
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014920 if($Level eq "Binary" and grep {$_=~/Virtual|Base_Class/} keys(%{$Kinds_Locations{$TypeName}})) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014921 $TYPE_PROBLEMS .= showVTables($TypeName);
14922 }
14923 $TYPE_PROBLEMS .= " </type>\n";
14924 }
14925 $TYPE_PROBLEMS .= " </header>\n";
14926 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014927 $TYPE_PROBLEMS = "<problems_with_types severity=\"$TargetSeverity\">\n".$TYPE_PROBLEMS."</problems_with_types>\n\n";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014928 }
14929 else
14930 { # HTML
14931 my $ProblemsNum = 0;
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014932 foreach my $HeaderName (sort {lc($a) cmp lc($b)} keys(%ReportMap))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014933 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014934 my (%NameSpace_Type) = ();
14935 foreach my $TypeName (keys(%{$ReportMap{$HeaderName}})) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014936 $NameSpace_Type{parse_TypeNameSpace($TypeName, 1)}{$TypeName} = 1;
14937 }
14938 foreach my $NameSpace (sort keys(%NameSpace_Type))
14939 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014940 $TYPE_PROBLEMS .= getTitle($HeaderName, "", $NameSpace);
14941 my @SortedTypes = sort {$TypeType{$a}." ".lc($a) cmp $TypeType{$b}." ".lc($b)} keys(%{$NameSpace_Type{$NameSpace}});
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014942 foreach my $TypeName (@SortedTypes)
14943 {
14944 my $ProblemNum = 1;
14945 my $TYPE_REPORT = "";
14946 foreach my $Kind (sort {$b=~/Size/ <=> $a=~/Size/} sort keys(%{$TypeChanges{$TypeName}}))
14947 {
14948 foreach my $Location (sort {cmp_locations($b, $a)} sort keys(%{$TypeChanges{$TypeName}{$Kind}}))
14949 {
14950 my %Problem = %{$TypeChanges{$TypeName}{$Kind}{$Location}};
14951 if(my $Change = applyMacroses($Level, $Kind, $CompatRules{$Level}{$Kind}{"Change"}, \%Problem))
14952 {
14953 my $Effect = applyMacroses($Level, $Kind, $CompatRules{$Level}{$Kind}{"Effect"}, \%Problem);
14954 $TYPE_REPORT .= "<tr><th>$ProblemNum</th><td align='left' valign='top'>".$Change."</td><td align='left' valign='top'>$Effect</td></tr>\n";
14955 $ProblemNum += 1;
14956 $ProblemsNum += 1;
14957 }
14958 }
14959 }
14960 $ProblemNum -= 1;
14961 if($TYPE_REPORT)
14962 {
Andrey Ponomarenko85043792012-05-14 16:48:07 +040014963 my $Affected = getAffectedSymbols($Level, $TypeName, $Kinds_Locations{$TypeName}, \@Symbols);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014964 my $ShowVTables = "";
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014965 if($Level eq "Binary" and grep {$_=~/Virtual|Base_Class/} keys(%{$Kinds_Locations{$TypeName}})) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014966 $ShowVTables = showVTables($TypeName);
14967 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014968 $TYPE_PROBLEMS .= $ContentSpanStart."<span class='extendable'>[+]</span> <span class='ttype'>".$TypeType{$TypeName}."</span> ".htmlSpecChars($TypeName)." ($ProblemNum)".$ContentSpanEnd;
14969 $TYPE_PROBLEMS .= "<br/>\n".$ContentDivStart."<table class='ptable'><tr>\n";
14970 $TYPE_PROBLEMS .= "<th width='2%'></th><th width='47%'>Change</th>\n";
14971 $TYPE_PROBLEMS .= "<th>Effect</th></tr>".$TYPE_REPORT."</table>\n";
14972 $TYPE_PROBLEMS .= $ShowVTables.$Affected."<br/><br/>".$ContentDivEnd."\n";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014973 if($NameSpace) {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040014974 $TYPE_PROBLEMS=~s/\b\Q$NameSpace\E::(\w|\~)/$1/g;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014975 }
14976 }
14977 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014978 $TYPE_PROBLEMS .= "<br/>";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014979 }
14980 }
14981 if($TYPE_PROBLEMS)
14982 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014983 $TYPE_PROBLEMS = insertIDs($TYPE_PROBLEMS);
14984 my $Title = "Problems with Data Types, $TargetSeverity Severity";
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014985 if($TargetSeverity eq "Safe")
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014986 { # Safe Changes
14987 $Title = "Other Changes in Data Types";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014988 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014989 $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 +040014990 }
14991 }
14992 return $TYPE_PROBLEMS;
14993}
14994
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014995sub get_Anchor($$$)
14996{
14997 my ($Kind, $Level, $Severity) = @_;
14998 if($JoinReport)
14999 {
15000 if($Severity eq "Safe") {
15001 return "Other_".$Level."_Changes_In_".$Kind."s";
15002 }
15003 else {
15004 return $Kind."_".$Level."_Problems_".$Severity;
15005 }
15006 }
15007 else
15008 {
15009 if($Severity eq "Safe") {
15010 return "Other_Changes_In_".$Kind."s";
15011 }
15012 else {
15013 return $Kind."_Problems_".$Severity;
15014 }
15015 }
15016}
15017
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015018sub showVTables($)
15019{
15020 my $TypeName = $_[0];
15021 my $TypeId1 = $TName_Tid{1}{$TypeName};
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040015022 my %Type1 = get_Type($TypeId1, 1);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015023 if(defined $Type1{"VTable"}
15024 and keys(%{$Type1{"VTable"}}))
15025 {
15026 my $TypeId2 = $TName_Tid{2}{$TypeName};
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040015027 my %Type2 = get_Type($TypeId2, 2);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015028 if(defined $Type2{"VTable"}
15029 and keys(%{$Type2{"VTable"}}))
15030 {
15031 my %Indexes = map {$_=>1} (keys(%{$Type1{"VTable"}}), keys(%{$Type2{"VTable"}}));
15032 my %Entries = ();
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015033 foreach my $Index (sort {int($a)<=>int($b)} (keys(%Indexes)))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015034 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015035 $Entries{$Index}{"E1"} = simpleVEntry($Type1{"VTable"}{$Index});
15036 $Entries{$Index}{"E2"} = simpleVEntry($Type2{"VTable"}{$Index});
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015037 }
15038 my $VTABLES = "";
15039 if($ReportFormat eq "xml")
15040 { # XML
15041 $VTABLES .= " <vtable>\n";
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015042 foreach my $Index (sort {int($a)<=>int($b)} (keys(%Entries)))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015043 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015044 $VTABLES .= " <entry offset=\"".$Index."\">\n";
Andrey Ponomarenko5c09ef32012-06-14 18:17:33 +040015045 $VTABLES .= " <old>".xmlSpecChars($Entries{$Index}{"E1"})."</old>\n";
15046 $VTABLES .= " <new>".xmlSpecChars($Entries{$Index}{"E2"})."</new>\n";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015047 $VTABLES .= " </entry>\n";
15048 }
15049 $VTABLES .= " </vtable>\n\n";
15050 }
15051 else
15052 { # HTML
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015053 $VTABLES .= "<table class='vtable'>";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015054 $VTABLES .= "<tr><th width='2%'>Offset</th>";
15055 $VTABLES .= "<th width='45%'>Virtual Table (Old) - ".(keys(%{$Type1{"VTable"}}))." entries</th>";
15056 $VTABLES .= "<th>Virtual Table (New) - ".(keys(%{$Type2{"VTable"}}))." entries</th></tr>";
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015057 foreach my $Index (sort {int($a)<=>int($b)} (keys(%Entries)))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015058 {
15059 my ($Color1, $Color2) = ("", "");
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015060 if($Entries{$Index}{"E1"} ne $Entries{$Index}{"E2"})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015061 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015062 if($Entries{$Index}{"E1"})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015063 {
Andrey Ponomarenko16934472012-03-29 15:37:04 +040015064 $Color1 = " class='failed'";
15065 $Color2 = " class='failed'";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015066 }
15067 else {
Andrey Ponomarenko16934472012-03-29 15:37:04 +040015068 $Color2 = " class='warning'";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015069 }
15070 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015071 $VTABLES .= "<tr><th>".$Index."</th>\n";
15072 $VTABLES .= "<td$Color1>".htmlSpecChars($Entries{$Index}{"E1"})."</td>\n";
15073 $VTABLES .= "<td$Color2>".htmlSpecChars($Entries{$Index}{"E2"})."</td></tr>\n";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015074 }
15075 $VTABLES .= "</table><br/>\n";
15076 $VTABLES = $ContentDivStart.$VTABLES.$ContentDivEnd;
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015077 $VTABLES = $ContentSpanStart_Info."[+] show v-table (old and new)".$ContentSpanEnd."<br/>\n".$VTABLES;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015078 }
15079 return $VTABLES;
15080 }
15081 }
15082 return "";
15083}
15084
15085sub simpleVEntry($)
15086{
15087 my $VEntry = $_[0];
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040015088 if(not defined $VEntry
15089 or $VEntry eq "") {
15090 return "";
15091 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015092 $VEntry=~s/\A(.+)::(_ZThn.+)\Z/$2/; # thunks
15093 $VEntry=~s/_ZTI\w+/typeinfo/g; # typeinfo
15094 if($VEntry=~/\A_ZThn.+\Z/) {
15095 $VEntry = "non-virtual thunk";
15096 }
15097 $VEntry=~s/\A\(int \(\*\)\(...\)\)([^\(\d])/$1/i;
15098 # support for old GCC versions
15099 $VEntry=~s/\A0u\Z/(int (*)(...))0/;
15100 $VEntry=~s/\A4294967268u\Z/(int (*)(...))-0x000000004/;
15101 $VEntry=~s/\A&_Z\Z/& _Z/;
15102 # templates
15103 if($VEntry=~s/ \[with (\w+) = (.+?)(, [^=]+ = .+|])\Z//g)
15104 { # std::basic_streambuf<_CharT, _Traits>::imbue [with _CharT = char, _Traits = std::char_traits<char>]
15105 # become std::basic_streambuf<char, ...>::imbue
15106 my ($Pname, $Pval) = ($1, $2);
15107 if($Pname eq "_CharT" and $VEntry=~/\Astd::/)
15108 { # stdc++ typedefs
15109 $VEntry=~s/<$Pname(, [^<>]+|)>/<$Pval>/g;
15110 # FIXME: simplify names using stdcxx typedefs (StdCxxTypedef)
15111 # The typedef info should be added to ABI dumps
15112 }
15113 else
15114 {
15115 $VEntry=~s/<$Pname>/<$Pval>/g;
15116 $VEntry=~s/<$Pname, [^<>]+>/<$Pval, ...>/g;
15117 }
15118 }
15119 $VEntry=~s/([^:]+)::\~([^:]+)\Z/~$1/; # destructors
15120 return $VEntry;
15121}
15122
Andrey Ponomarenko85043792012-05-14 16:48:07 +040015123sub getAffectedSymbols($$$$)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015124{
Andrey Ponomarenko85043792012-05-14 16:48:07 +040015125 my ($Level, $Target_TypeName, $Kinds_Locations, $Syms) = @_;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015126 my $LIMIT = 1000;
Andrey Ponomarenko85043792012-05-14 16:48:07 +040015127 if($#{$Syms}>=10000)
15128 { # reduce size of the report
15129 $LIMIT = 10;
15130 }
15131 my %SProblems = ();
15132 foreach my $Symbol (@{$Syms})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015133 {
Andrey Ponomarenko85043792012-05-14 16:48:07 +040015134 if(keys(%SProblems)>$LIMIT) {
15135 last;
15136 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015137 if(($Symbol=~/C2E|D2E|D0E/))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015138 { # duplicated problems for C2 constructors, D2 and D0 destructors
15139 next;
15140 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015141 my ($SN, $SS, $SV) = separate_symbol($Symbol);
15142 if($Level eq "Source")
15143 { # remove symbol version
15144 $Symbol=$SN;
15145 }
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040015146 my ($MinPath_Length, $ProblemLocation_Last) = (-1, "");
15147 my $Severity_Max = 0;
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015148 my $Signature = get_Signature($Symbol, 1);
15149 foreach my $Kind (keys(%{$CompatProblems{$Level}{$Symbol}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015150 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015151 foreach my $Location (keys(%{$CompatProblems{$Level}{$Symbol}{$Kind}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015152 {
15153 if(not defined $Kinds_Locations->{$Kind}
15154 or not $Kinds_Locations->{$Kind}{$Location}) {
15155 next;
15156 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015157 if($SV and defined $CompatProblems{$Level}{$SN}
15158 and defined $CompatProblems{$Level}{$SN}{$Kind}{$Location})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015159 { # duplicated problems for versioned symbols
15160 next;
15161 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015162 my $Type_Name = $CompatProblems{$Level}{$Symbol}{$Kind}{$Location}{"Type_Name"};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015163 next if($Type_Name ne $Target_TypeName);
15164
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015165 my $Position = $CompatProblems{$Level}{$Symbol}{$Kind}{$Location}{"Param_Pos"};
15166 my $Param_Name = $CompatProblems{$Level}{$Symbol}{$Kind}{$Location}{"Param_Name"};
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040015167 my $Severity = getProblemSeverity($Level, $Kind);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015168 my $Path_Length = 0;
15169 my $ProblemLocation = $Location;
15170 if($Type_Name) {
15171 $ProblemLocation=~s/->\Q$Type_Name\E\Z//g;
15172 }
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040015173 while($ProblemLocation=~/\-\>/g) {
15174 $Path_Length += 1;
15175 }
15176 if($MinPath_Length==-1 or ($Path_Length<=$MinPath_Length and $Severity_Val{$Severity}>$Severity_Max)
15177 or (cmp_locations($ProblemLocation, $ProblemLocation_Last) and $Severity_Val{$Severity}==$Severity_Max))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015178 {
15179 $MinPath_Length = $Path_Length;
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040015180 $Severity_Max = $Severity_Val{$Severity};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015181 $ProblemLocation_Last = $ProblemLocation;
Andrey Ponomarenko85043792012-05-14 16:48:07 +040015182 %{$SProblems{$Symbol}} = (
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040015183 "Descr"=>getAffectDescription($Level, $Symbol, $Kind, $Location),
15184 "Severity_Max"=>$Severity_Max,
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015185 "Signature"=>$Signature,
15186 "Position"=>$Position,
15187 "Param_Name"=>$Param_Name,
15188 "Location"=>$Location
15189 );
15190 }
15191 }
15192 }
15193 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +040015194 my @Symbols = keys(%SProblems);
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015195 @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 +040015196 @Symbols = sort {$SProblems{$b}{"Severity_Max"}<=>$SProblems{$a}{"Severity_Max"}} @Symbols;
15197 if($#Symbols+1>$LIMIT)
15198 { # remove last element
15199 pop(@Symbols);
15200 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015201 my $Affected = "";
15202 if($ReportFormat eq "xml")
15203 { # XML
15204 $Affected .= " <affected>\n";
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015205 foreach my $Symbol (@Symbols)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015206 {
Andrey Ponomarenko85043792012-05-14 16:48:07 +040015207 my $Param_Name = $SProblems{$Symbol}{"Param_Name"};
15208 my $Description = $SProblems{$Symbol}{"Descr"};
15209 my $Location = $SProblems{$Symbol}{"Location"};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015210 my $Target = "";
15211 if($Param_Name) {
15212 $Target = " affected=\"param\" param_name=\"$Param_Name\"";
15213 }
15214 elsif($Location=~/\Aretval(\-|\Z)/i) {
15215 $Target = " affected=\"retval\"";
15216 }
15217 elsif($Location=~/\Athis(\-|\Z)/i) {
15218 $Target = " affected=\"this\"";
15219 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015220 $Affected .= " <symbol$Target name=\"$Symbol\">\n";
Andrey Ponomarenko5c09ef32012-06-14 18:17:33 +040015221 $Affected .= " <comment>".xmlSpecChars($Description)."</comment>\n";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015222 $Affected .= " </symbol>\n";
15223 }
15224 $Affected .= " </affected>\n";
15225 }
15226 else
15227 { # HTML
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015228 foreach my $Symbol (@Symbols)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015229 {
Andrey Ponomarenko85043792012-05-14 16:48:07 +040015230 my $Description = $SProblems{$Symbol}{"Descr"};
15231 my $Signature = $SProblems{$Symbol}{"Signature"};
15232 my $Pos = $SProblems{$Symbol}{"Position"};
Andrey Ponomarenkoa01311b2012-06-08 17:20:02 +040015233 $Affected .= "<span class='iname_a'>".highLight_Signature_PPos_Italic($Signature, $Pos, 1, 0, 0)."</span><br/><div class='affect'>".htmlSpecChars($Description)."</div>\n";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015234 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +040015235 if(keys(%SProblems)>$LIMIT) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015236 $Affected .= "and others ...<br/>";
15237 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +040015238 $Affected = "<div class='affected'>".$Affected."</div>";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015239 if($Affected)
15240 {
15241 $Affected = $ContentDivStart.$Affected.$ContentDivEnd;
Andrey Ponomarenko85043792012-05-14 16:48:07 +040015242 $Affected = $ContentSpanStart_Affected."[+] affected symbols (".(keys(%SProblems)>$LIMIT?">".$LIMIT:keys(%SProblems)).")".$ContentSpanEnd.$Affected;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015243 }
15244 }
15245 return $Affected;
15246}
15247
15248sub cmp_locations($$)
15249{
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040015250 my ($L1, $L2) = @_;
15251 if($L2=~/\b(retval|this)\b/
15252 and $L1!~/\b(retval|this)\b/ and $L1!~/\-\>/) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015253 return 1;
15254 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040015255 if($L2=~/\b(retval|this)\b/ and $L2=~/\-\>/
15256 and $L1!~/\b(retval|this)\b/ and $L1=~/\-\>/) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015257 return 1;
15258 }
15259 return 0;
15260}
15261
15262sub getAffectDescription($$$$)
15263{
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015264 my ($Level, $Symbol, $Kind, $Location) = @_;
15265 my %Problem = %{$CompatProblems{$Level}{$Symbol}{$Kind}{$Location}};
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040015266 my $PPos = showPos($Problem{"Param_Pos"});
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015267 my @Sentence = ();
15268 $Location=~s/\A(.*)\-\>.+?\Z/$1/;
15269 if($Kind eq "Overridden_Virtual_Method"
15270 or $Kind eq "Overridden_Virtual_Method_B") {
15271 push(@Sentence, "The method '".$Problem{"New_Value"}."' will be called instead of this method.");
15272 }
15273 elsif($CompatRules{$Level}{$Kind}{"Kind"} eq "Types")
15274 {
15275 if($Location eq "this" or $Kind=~/(\A|_)Virtual(_|\Z)/)
15276 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015277 my $METHOD_TYPE = $CompleteSignature{1}{$Symbol}{"Constructor"}?"constructor":"method";
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040015278 my $ClassName = $TypeInfo{1}{$CompleteSignature{1}{$Symbol}{"Class"}}{"Name"};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015279 if($ClassName eq $Problem{"Type_Name"}) {
15280 push(@Sentence, "This $METHOD_TYPE is from \'".$Problem{"Type_Name"}."\' class.");
15281 }
15282 else {
15283 push(@Sentence, "This $METHOD_TYPE is from derived class \'".$ClassName."\'.");
15284 }
15285 }
15286 else
15287 {
15288 if($Location=~/retval/)
15289 { # return value
15290 if($Location=~/\-\>/) {
15291 push(@Sentence, "Field \'".$Location."\' in return value");
15292 }
15293 else {
15294 push(@Sentence, "Return value");
15295 }
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040015296 if(my $Init = $Problem{"InitialType_Type"})
15297 {
15298 if($Init eq "Pointer") {
15299 push(@Sentence, "(pointer)");
15300 }
15301 elsif($Init eq "Ref") {
15302 push(@Sentence, "(reference)");
15303 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015304 }
15305 }
15306 elsif($Location=~/this/)
15307 { # "this" pointer
15308 if($Location=~/\-\>/) {
15309 push(@Sentence, "Field \'".$Location."\' in the object of this method");
15310 }
15311 else {
15312 push(@Sentence, "\'this\' pointer");
15313 }
15314 }
15315 else
15316 { # parameters
15317 if($Location=~/\-\>/) {
15318 push(@Sentence, "Field \'".$Location."\' in $PPos parameter");
15319 }
15320 else {
15321 push(@Sentence, "$PPos parameter");
15322 }
15323 if($Problem{"Param_Name"}) {
15324 push(@Sentence, "\'".$Problem{"Param_Name"}."\'");
15325 }
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040015326 if(my $Init = $Problem{"InitialType_Type"})
15327 {
15328 if($Init eq "Pointer") {
15329 push(@Sentence, "(pointer)");
15330 }
15331 elsif($Init eq "Ref") {
15332 push(@Sentence, "(reference)");
15333 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015334 }
15335 }
15336 if($Location eq "this") {
15337 push(@Sentence, "has base type \'".$Problem{"Type_Name"}."\'.");
15338 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040015339 elsif(defined $Problem{"Start_Type_Name"}
15340 and $Problem{"Start_Type_Name"} eq $Problem{"Type_Name"}) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015341 push(@Sentence, "has type \'".$Problem{"Type_Name"}."\'.");
15342 }
15343 else {
15344 push(@Sentence, "has base type \'".$Problem{"Type_Name"}."\'.");
15345 }
15346 }
15347 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040015348 if($ExtendedSymbols{$Symbol}) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015349 push(@Sentence, " This is a symbol from an artificial external library that may use the \'$TargetLibraryName\' library and change its ABI after recompiling.");
15350 }
15351 return join(" ", @Sentence);
15352}
15353
15354sub get_XmlSign($$)
15355{
15356 my ($Symbol, $LibVersion) = @_;
15357 my $Info = $CompleteSignature{$LibVersion}{$Symbol};
15358 my $Report = "";
15359 foreach my $Pos (sort {int($a)<=>int($b)} keys(%{$Info->{"Param"}}))
15360 {
15361 my $Name = $Info->{"Param"}{$Pos}{"name"};
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040015362 my $Type = $Info->{"Param"}{$Pos}{"type"};
15363 my $TypeName = $TypeInfo{$LibVersion}{$Type}{"Name"};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015364 foreach my $Typedef (keys(%ChangedTypedef))
15365 {
15366 my $Base = $Typedef_BaseName{$LibVersion}{$Typedef};
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040015367 $TypeName=~s/\b\Q$Typedef\E\b/$Base/g;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015368 }
15369 $Report .= " <param pos=\"$Pos\">\n";
15370 $Report .= " <name>".$Name."</name>\n";
Andrey Ponomarenko5c09ef32012-06-14 18:17:33 +040015371 $Report .= " <type>".xmlSpecChars($TypeName)."</type>\n";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015372 $Report .= " </param>\n";
15373 }
15374 if(my $Return = $Info->{"Return"})
15375 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040015376 my $RTName = $TypeInfo{$LibVersion}{$Return}{"Name"};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015377 $Report .= " <retval>\n";
Andrey Ponomarenko5c09ef32012-06-14 18:17:33 +040015378 $Report .= " <type>".xmlSpecChars($RTName)."</type>\n";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015379 $Report .= " </retval>\n";
15380 }
15381 return $Report;
15382}
15383
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015384sub get_Report_SymbolsInfo($)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015385{
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015386 my $Level = $_[0];
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015387 my $Report = "<symbols_info>\n";
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015388 foreach my $Symbol (sort keys(%{$CompatProblems{$Level}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015389 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015390 my ($SN, $SS, $SV) = separate_symbol($Symbol);
15391 if($SV and defined $CompatProblems{$Level}{$SN}) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015392 next;
15393 }
15394 $Report .= " <symbol name=\"$Symbol\">\n";
15395 my ($S1, $P1, $S2, $P2) = ();
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015396 if(not $AddedInt{$Level}{$Symbol})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015397 {
15398 if(defined $CompleteSignature{1}{$Symbol}
15399 and defined $CompleteSignature{1}{$Symbol}{"Header"})
15400 {
15401 $P1 = get_XmlSign($Symbol, 1);
15402 $S1 = get_Signature($Symbol, 1);
15403 }
15404 elsif($Symbol=~/\A(_Z|\?)/) {
15405 $S1 = $tr_name{$Symbol};
15406 }
15407 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015408 if(not $RemovedInt{$Level}{$Symbol})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015409 {
15410 if(defined $CompleteSignature{2}{$Symbol}
15411 and defined $CompleteSignature{2}{$Symbol}{"Header"})
15412 {
15413 $P2 = get_XmlSign($Symbol, 2);
15414 $S2 = get_Signature($Symbol, 2);
15415 }
15416 elsif($Symbol=~/\A(_Z|\?)/) {
15417 $S2 = $tr_name{$Symbol};
15418 }
15419 }
15420 if($S1)
15421 {
Andrey Ponomarenko5c09ef32012-06-14 18:17:33 +040015422 $Report .= " <old signature=\"".xmlSpecChars($S1)."\">\n";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015423 $Report .= $P1;
15424 $Report .= " </old>\n";
15425 }
15426 if($S2 and $S2 ne $S1)
15427 {
Andrey Ponomarenko5c09ef32012-06-14 18:17:33 +040015428 $Report .= " <new signature=\"".xmlSpecChars($S2)."\">\n";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015429 $Report .= $P2;
15430 $Report .= " </new>\n";
15431 }
15432 $Report .= " </symbol>\n";
15433 }
15434 $Report .= "</symbols_info>\n";
15435 return $Report;
15436}
15437
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015438sub writeReport($$)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015439{
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015440 my ($Level, $Report) = @_;
15441 if($ReportFormat eq "xml") {
15442 $Report = "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n".$Report;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015443 }
15444 if($StdOut)
15445 { # --stdout option
15446 print STDOUT $Report;
15447 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015448 else
15449 {
15450 my $RPath = getReportPath($Level);
Andrey Ponomarenko85043792012-05-14 16:48:07 +040015451 mkpath(get_dirname($RPath));
15452
15453 open(REPORT, ">", $RPath) || die ("can't open file \'$RPath\': $!\n");
15454 print REPORT $Report;
15455 close(REPORT);
15456
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040015457 if($Browse or $OpenReport)
15458 { # open in browser
15459 openReport($RPath);
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015460 if($JoinReport or $DoubleReport)
15461 {
15462 if($Level eq "Binary")
15463 { # wait to open a browser
15464 sleep(1);
15465 }
15466 }
15467 }
15468 }
15469}
15470
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040015471sub openReport($)
15472{
15473 my $Path = $_[0];
15474 my $Cmd = "";
15475 if($Browse)
15476 { # user-defined browser
Andrey Ponomarenkoa01311b2012-06-08 17:20:02 +040015477 $Cmd = $Browse." \"$Path\"";
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040015478 }
15479 if(not $Cmd)
15480 { # default browser
15481 if($OSgroup eq "macos") {
Andrey Ponomarenkoa01311b2012-06-08 17:20:02 +040015482 system("open \"$Path\"");
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040015483 }
15484 elsif($OSgroup eq "windows") {
Andrey Ponomarenkoa01311b2012-06-08 17:20:02 +040015485 system("start \"$Path\"");
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040015486 }
15487 else
15488 { # linux, freebsd, solaris
15489 my @Browsers = (
15490 "x-www-browser",
15491 "sensible-browser",
15492 "firefox",
15493 "opera",
15494 "xdg-open",
15495 "lynx",
15496 "links"
15497 );
15498 foreach my $Br (@Browsers)
15499 {
15500 if($Br = get_CmdPath($Br))
15501 {
Andrey Ponomarenkoa01311b2012-06-08 17:20:02 +040015502 $Cmd = $Br." \"$Path\"";
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040015503 last;
15504 }
15505 }
15506 }
15507 }
15508 if($Cmd)
15509 {
15510 if($Debug) {
15511 printMsg("INFO", "running $Cmd");
15512 }
15513 if($Cmd!~/lynx|links/) {
Andrey Ponomarenkoa01311b2012-06-08 17:20:02 +040015514 $Cmd .= " >\"$TMP_DIR/null\" 2>&1 &";
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040015515 }
15516 system($Cmd);
15517 }
15518 else {
15519 printMsg("ERROR", "cannot open report in browser");
15520 }
15521}
15522
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015523sub getReport($)
15524{
15525 my $Level = $_[0];
15526 if($ReportFormat eq "xml")
15527 { # XML
15528
15529 if($Level eq "Join")
15530 {
15531 my $Report = "<reports>\n";
15532 $Report .= getReport("Binary");
15533 $Report .= getReport("Source");
15534 $Report .= "</reports>\n";
15535 return $Report;
15536 }
15537 else
15538 {
15539 my $Report = "<report kind=\"".lc($Level)."\" version=\"$XML_REPORT_VERSION\">\n\n";
15540 my ($Summary, $MetaData) = get_Summary($Level);
15541 $Report .= $Summary."\n";
15542 $Report .= get_Report_Added($Level).get_Report_Removed($Level);
15543 $Report .= get_Report_Problems("High", $Level).get_Report_Problems("Medium", $Level).get_Report_Problems("Low", $Level).get_Report_Problems("Safe", $Level);
15544 $Report .= get_Report_SymbolsInfo($Level);
15545 $Report .= "</report>\n";
15546 return $Report;
15547 }
15548 }
15549 else
15550 { # HTML
15551 my $CssStyles = readModule("Styles", "Report.css");
15552 my $JScripts = readModule("Scripts", "Sections.js");
15553 if($Level eq "Join")
15554 {
15555 $CssStyles .= "\n".readModule("Styles", "Tabs.css");
15556 $JScripts .= "\n".readModule("Scripts", "Tabs.js");
Andrey Ponomarenkob8d203d2012-05-25 18:11:07 +040015557 my $Title = $TargetLibraryFName.": ".$Descriptor{1}{"Version"}." to ".$Descriptor{2}{"Version"}." compatibility report";
15558 my $Keywords = $TargetLibraryFName.", compatibility, API, report";
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015559 my $Description = "Compatibility report for the $TargetLibraryFName $TargetComponent between ".$Descriptor{1}{"Version"}." and ".$Descriptor{2}{"Version"}." versions";
15560 my ($BSummary, $BMetaData) = get_Summary("Binary");
15561 my ($SSummary, $SMetaData) = get_Summary("Source");
15562 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>";
15563 $Report .= get_Report_Header("Join")."
15564 <br/><div class='tabset'>
Andrey Ponomarenko16934472012-03-29 15:37:04 +040015565 <a id='BinaryID' href='#BinaryTab' class='tab active'>Binary<br/>Compatibility</a>
15566 <a id='SourceID' href='#SourceTab' style='margin-left:3px' class='tab disabled'>Source<br/>Compatibility</a>
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015567 </div>";
15568 $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>";
15569 $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>";
15570 $Report .= getReportFooter($TargetLibraryFName);
15571 $Report .= "\n<div style='height:999px;'></div>\n</body></html>";
15572 return $Report;
15573 }
15574 else
15575 {
15576 my ($Summary, $MetaData) = get_Summary($Level);
Andrey Ponomarenkob8d203d2012-05-25 18:11:07 +040015577 my $Title = $TargetLibraryFName.": ".$Descriptor{1}{"Version"}." to ".$Descriptor{2}{"Version"}." ".lc($Level)." compatibility report";
15578 my $Keywords = $TargetLibraryFName.", ".lc($Level)." compatibility, API, report";
15579 my $Description = "$Level compatibility report for the ".$TargetLibraryFName." ".$TargetComponent." between ".$Descriptor{1}{"Version"}." and ".$Descriptor{2}{"Version"}." versions";
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015580 if($Level eq "Binary")
15581 {
15582 if(getArch(1) eq getArch(2)
15583 and getArch(1) ne "unknown") {
15584 $Description .= " on ".showArch(getArch(1));
15585 }
15586 }
15587 my $Report = "<!-\- $MetaData -\->\n".composeHTML_Head($Title, $Keywords, $Description, $CssStyles, $JScripts)."\n<body>\n<div><a name='Top'></a>\n";
15588 $Report .= get_Report_Header($Level)."\n".$Summary."\n";
15589 $Report .= get_Report_Added($Level).get_Report_Removed($Level);
15590 $Report .= get_Report_Problems("High", $Level).get_Report_Problems("Medium", $Level).get_Report_Problems("Low", $Level).get_Report_Problems("Safe", $Level);
15591 $Report .= get_SourceInfo();
15592 $Report .= "</div>\n<br/><br/><br/><hr/>\n";
15593 $Report .= getReportFooter($TargetLibraryFName);
15594 $Report .= "\n<div style='height:999px;'></div>\n</body></html>";
15595 return $Report;
15596 }
15597 }
15598}
15599
Andrey Ponomarenko16934472012-03-29 15:37:04 +040015600sub getLegend()
15601{
15602 return "<br/>
15603<table class='summary'>
15604<tr>
15605 <td class='new'>added</td>
15606 <td class='passed'>compatible</td>
15607</tr>
15608<tr>
15609 <td class='warning'>warning</td>
15610 <td class='failed'>incompatible</td>
15611</tr></table>\n";
15612}
15613
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015614sub createReport()
15615{
15616 if($JoinReport)
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040015617 { # --stdout
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015618 writeReport("Join", getReport("Join"));
15619 }
15620 elsif($DoubleReport)
15621 { # default
15622 writeReport("Binary", getReport("Binary"));
15623 writeReport("Source", getReport("Source"));
15624 }
15625 elsif($BinaryOnly)
15626 { # --binary
15627 writeReport("Binary", getReport("Binary"));
15628 }
15629 elsif($SourceOnly)
15630 { # --source
15631 writeReport("Source", getReport("Source"));
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015632 }
15633}
15634
15635sub getReportFooter($)
15636{
15637 my $LibName = $_[0];
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015638 my $FooterStyle = (not $JoinReport)?"width:99%":"width:97%;padding-top:3px";
15639 my $Footer = "<div style='$FooterStyle;font-size:11px;' align='right'><i>Generated on ".(localtime time); # report date
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015640 $Footer .= " for <span style='font-weight:bold'>$LibName</span>"; # tested library/system name
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015641 $Footer .= " by <a href='".$HomePage{"Wiki"}."'>ABI Compliance Checker</a>"; # tool name
15642 my $ToolSummary = "<br/>A tool for checking backward compatibility of a C/C++ library API&#160;&#160;";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015643 $Footer .= " $TOOL_VERSION &#160;$ToolSummary</i></div>"; # tool version
15644 return $Footer;
15645}
15646
15647sub get_Report_Problems($$)
15648{
15649 my ($Priority, $Level) = @_;
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040015650 my $Report = get_Report_TypeProblems($Priority, $Level);
Andrey Ponomarenko16934472012-03-29 15:37:04 +040015651 if(my $SProblems = get_Report_SymbolProblems($Priority, $Level)) {
15652 $Report .= $SProblems;
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040015653 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015654 if($Priority eq "Low")
15655 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015656 $Report .= get_Report_ChangedConstants($Level);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015657 if($ReportFormat eq "html") {
15658 if($CheckImpl and $Level eq "Binary") {
15659 $Report .= get_Report_Impl();
15660 }
15661 }
15662 }
15663 if($ReportFormat eq "html")
15664 {
15665 if($Report)
15666 { # add anchor
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015667 if($JoinReport)
15668 {
15669 if($Priority eq "Safe") {
15670 $Report = "<a name=\'Other_".$Level."_Changes\'></a>".$Report;
15671 }
15672 else {
15673 $Report = "<a name=\'".$Priority."_Risk_".$Level."_Problems\'></a>".$Report;
15674 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015675 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015676 else
15677 {
15678 if($Priority eq "Safe") {
15679 $Report = "<a name=\'Other_Changes\'></a>".$Report;
15680 }
15681 else {
15682 $Report = "<a name=\'".$Priority."_Risk_Problems\'></a>".$Report;
15683 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015684 }
15685 }
15686 }
15687 return $Report;
15688}
15689
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015690sub composeHTML_Head($$$$$)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015691{
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015692 my ($Title, $Keywords, $Description, $Styles, $Scripts) = @_;
15693 return "<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.0 Transitional//EN\" \"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd\">
15694 <html xmlns=\"http://www.w3.org/1999/xhtml\" xml:lang=\"en\" lang=\"en\">
15695 <head>
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015696 <meta http-equiv=\"Content-Type\" content=\"text/html; charset=utf-8\" />
15697 <meta name=\"keywords\" content=\"$Keywords\" />
15698 <meta name=\"description\" content=\"$Description\" />
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015699 <title>
15700 $Title
15701 </title>
15702 <style type=\"text/css\">
15703 $Styles
15704 </style>
15705 <script type=\"text/javascript\" language=\"JavaScript\">
15706 <!--
15707 $Scripts
15708 -->
15709 </script>
15710 </head>";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015711}
15712
15713sub insertIDs($)
15714{
15715 my $Text = $_[0];
15716 while($Text=~/CONTENT_ID/)
15717 {
15718 if(int($Content_Counter)%2) {
15719 $ContentID -= 1;
15720 }
15721 $Text=~s/CONTENT_ID/c_$ContentID/;
15722 $ContentID += 1;
15723 $Content_Counter += 1;
15724 }
15725 return $Text;
15726}
15727
15728sub checkPreprocessedUnit($)
15729{
15730 my $Path = $_[0];
Andrey Ponomarenkoa01311b2012-06-08 17:20:02 +040015731 my ($CurHeader, $CurHeaderName) = ("", "");
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015732 open(PREPROC, $Path) || die ("can't open file \'$Path\': $!\n");
Andrey Ponomarenkoa01311b2012-06-08 17:20:02 +040015733 while(my $Line = <PREPROC>)
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015734 { # detecting public and private constants
Andrey Ponomarenkoa01311b2012-06-08 17:20:02 +040015735
15736 if(substr($Line, 0, 1) eq "#")
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015737 {
Andrey Ponomarenkoa01311b2012-06-08 17:20:02 +040015738 chomp($Line);
15739 if($Line=~/\A\#\s+\d+\s+\"(.+)\"/)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015740 {
Andrey Ponomarenkoa01311b2012-06-08 17:20:02 +040015741 $CurHeader = path_format($1, $OSgroup);
15742 $CurHeaderName = get_filename($CurHeader);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015743 }
Andrey Ponomarenkoa01311b2012-06-08 17:20:02 +040015744 if(not $Include_Neighbors{$Version}{$CurHeaderName}
15745 and not $Registered_Headers{$Version}{$CurHeader})
15746 { # not a target
15747 next;
15748 }
15749 if(not is_target_header($CurHeaderName, 1)
15750 and not is_target_header($CurHeaderName, 2))
15751 { # user-defined header
15752 next;
15753 }
15754 if($Line=~/\A\#\s*define\s+([_A-Z0-9]+)\s+(.+)\s*\Z/)
15755 {
15756 my ($Name, $Value) = ($1, $2);
15757 if(not $Constants{$Version}{$Name}{"Access"})
15758 {
15759 $Constants{$Version}{$Name}{"Access"} = "public";
15760 $Constants{$Version}{$Name}{"Value"} = $Value;
15761 $Constants{$Version}{$Name}{"Header"} = $CurHeaderName;
15762 }
15763 }
15764 elsif($Line=~/\A\#[ \t]*undef[ \t]+([_A-Z]+)[ \t]*/) {
15765 $Constants{$Version}{$1}{"Access"} = "private";
15766 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015767 }
15768 }
15769 close(PREPROC);
15770 foreach my $Constant (keys(%{$Constants{$Version}}))
15771 {
Andrey Ponomarenkoa01311b2012-06-08 17:20:02 +040015772 if($Constants{$Version}{$Constant}{"Access"} eq "private"
15773 or $Constant=~/_h\Z/i
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015774 or isBuiltIn($Constants{$Version}{$Constant}{"Header"}))
15775 { # skip private constants
15776 delete($Constants{$Version}{$Constant});
15777 }
15778 else {
15779 delete($Constants{$Version}{$Constant}{"Access"});
15780 }
15781 }
Andrey Ponomarenkoa01311b2012-06-08 17:20:02 +040015782 if($Debug)
15783 {
15784 mkpath($DEBUG_PATH{$Version});
15785 copy($Path, $DEBUG_PATH{$Version}."/preprocessor.txt");
15786 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015787}
15788
Andrey Ponomarenko16934472012-03-29 15:37:04 +040015789sub uncoverConstant($$)
15790{
15791 my ($LibVersion, $Constant) = @_;
15792 return "" if(not $LibVersion or not $Constant);
15793 return $Constant if(isCyclical(\@RecurConstant, $Constant));
15794 if(defined $Cache{"uncoverConstant"}{$LibVersion}{$Constant}) {
15795 return $Cache{"uncoverConstant"}{$LibVersion}{$Constant};
15796 }
15797 my $Value = $Constants{$LibVersion}{$Constant}{"Value"};
15798 if(defined $Value)
15799 {
15800 if($Value=~/\A[A-Z0-9_]+\Z/ and $Value=~/[A-Z]/)
15801 {
15802 push(@RecurConstant, $Constant);
15803 my $Uncovered = uncoverConstant($LibVersion, $Value);
15804 if($Uncovered ne "") {
15805 $Value = $Uncovered;
15806 }
15807 pop(@RecurConstant);
15808 }
15809 # FIXME: uncover $Value using all the enum constants
15810 # USECASE: change of define NC_LONG from NC_INT (enum value) to NC_INT (define)
15811 return ($Cache{"uncoverConstant"}{$LibVersion}{$Constant} = $Value);
15812 }
15813 return ($Cache{"uncoverConstant"}{$LibVersion}{$Constant} = "");
15814}
15815
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015816my %IgnoreConstant=(
15817 "VERSION"=>1,
15818 "VERSIONCODE"=>1,
15819 "VERNUM"=>1,
15820 "VERS_INFO"=>1,
15821 "PATCHLEVEL"=>1,
15822 "INSTALLPREFIX"=>1,
15823 "VBUILD"=>1,
15824 "VPATCH"=>1,
15825 "VMINOR"=>1,
15826 "BUILD_STRING"=>1,
15827 "BUILD_TIME"=>1,
15828 "PACKAGE_STRING"=>1,
15829 "PRODUCTION"=>1,
15830 "CONFIGURE_COMMAND"=>1,
15831 "INSTALLDIR"=>1,
15832 "BINDIR"=>1,
15833 "CONFIG_FILE_PATH"=>1,
15834 "DATADIR"=>1,
15835 "EXTENSION_DIR"=>1,
15836 "INCLUDE_PATH"=>1,
15837 "LIBDIR"=>1,
15838 "LOCALSTATEDIR"=>1,
15839 "SBINDIR"=>1,
15840 "SYSCONFDIR"=>1,
15841 "RELEASE"=>1,
15842 "SOURCE_ID"=>1,
15843 "SUBMINOR"=>1,
15844 "MINOR"=>1,
15845 "MINNOR"=>1,
15846 "MINORVERSION"=>1,
15847 "MAJOR"=>1,
15848 "MAJORVERSION"=>1,
15849 "MICRO"=>1,
15850 "MICROVERSION"=>1,
15851 "BINARY_AGE"=>1,
15852 "INTERFACE_AGE"=>1,
15853 "CORE_ABI"=>1,
15854 "PATCH"=>1,
15855 "COPYRIGHT"=>1,
15856 "TIMESTAMP"=>1,
15857 "REVISION"=>1,
15858 "PACKAGE_TAG"=>1,
15859 "PACKAGEDATE"=>1,
15860 "NUMVERSION"=>1
15861);
15862
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015863sub mergeConstants($)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015864{
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015865 my $Level = $_[0];
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015866 foreach my $Constant (keys(%{$Constants{1}}))
15867 {
15868 if($SkipConstants{1}{$Constant})
15869 { # skipped by the user
15870 next;
15871 }
Andrey Ponomarenko16934472012-03-29 15:37:04 +040015872 if(not defined $Constants{2}{$Constant}{"Value"}
15873 or $Constants{2}{$Constant}{"Value"} eq "")
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015874 { # empty value
15875 next;
15876 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +040015877 my $Header = $Constants{1}{$Constant}{"Header"};
15878 if(not is_target_header($Header, 1)
15879 and not is_target_header($Header, 2))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015880 { # user-defined header
15881 next;
15882 }
15883 my ($Old_Value, $New_Value, $Old_Value_Pure, $New_Value_Pure);
Andrey Ponomarenko16934472012-03-29 15:37:04 +040015884 $Old_Value = $Old_Value_Pure = uncoverConstant(1, $Constant);
15885 $New_Value = $New_Value_Pure = uncoverConstant(2, $Constant);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015886 $Old_Value_Pure=~s/(\W)\s+/$1/g;
15887 $Old_Value_Pure=~s/\s+(\W)/$1/g;
15888 $New_Value_Pure=~s/(\W)\s+/$1/g;
15889 $New_Value_Pure=~s/\s+(\W)/$1/g;
15890 next if($New_Value_Pure eq "" or $Old_Value_Pure eq "");
15891 if($New_Value_Pure ne $Old_Value_Pure)
15892 { # different values
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015893 if($Level eq "Binary")
15894 {
15895 if(grep {$Constant=~/(\A|_)$_(_|\Z)/} keys(%IgnoreConstant))
15896 { # ignore library version
15897 next;
15898 }
15899 if($Constant=~/(\A|_)(lib|open|)$TargetLibraryShortName(_|)(VERSION|VER|DATE|API|PREFIX)(_|\Z)/i)
15900 { # ignore library version
15901 next;
15902 }
15903 if($Old_Value=~/\A('|"|)[\/\\]\w+([\/\\]|:|('|"|)\Z)/ or $Old_Value=~/[\/\\]\w+[\/\\]\w+/)
15904 { # ignoring path defines:
Andrey Ponomarenko85043792012-05-14 16:48:07 +040015905 # /lib64:/usr/lib64:/lib:/usr/lib:/usr/X11R6/lib/Xaw3d ...
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015906 next;
15907 }
15908 if($Old_Value=~/\A\(*[a-z_]+(\s+|\|)/i)
15909 { # ignore source defines:
Andrey Ponomarenko85043792012-05-14 16:48:07 +040015910 # static int gcry_pth_init ( void) { return ...
15911 # (RE_BACKSLASH_ESCAPE_IN_LISTS | RE...
15912 next;
15913 }
15914 if($Old_Value=~/\(/i and $Old_Value!~/[\"\']/i)
15915 { # ignore source defines:
15916 # foo(p)
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015917 next;
15918 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015919 }
15920 if(convert_integer($Old_Value) eq convert_integer($New_Value))
15921 { # 0x0001 and 0x1, 0x1 and 1 equal constants
15922 next;
15923 }
15924 if($Old_Value eq "0" and $New_Value eq "NULL")
15925 { # 0 => NULL
15926 next;
15927 }
15928 if($Old_Value eq "NULL" and $New_Value eq "0")
15929 { # NULL => 0
15930 next;
15931 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015932 %{$ProblemsWithConstants{$Level}{$Constant}} = (
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015933 "Target"=>$Constant,
15934 "Old_Value"=>$Old_Value,
15935 "New_Value"=>$New_Value );
15936 }
15937 }
15938}
15939
15940sub convert_integer($)
15941{
15942 my $Value = $_[0];
15943 if($Value=~/\A0x[a-f0-9]+\Z/)
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015944 { # hexadecimal
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015945 return hex($Value);
15946 }
15947 elsif($Value=~/\A0[0-7]+\Z/)
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015948 { # octal
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015949 return oct($Value);
15950 }
15951 elsif($Value=~/\A0b[0-1]+\Z/)
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015952 { # binary
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015953 return oct($Value);
15954 }
15955 else {
15956 return $Value;
15957 }
15958}
15959
Andrey Ponomarenko16934472012-03-29 15:37:04 +040015960sub readSymbols($)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015961{
15962 my $LibVersion = $_[0];
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040015963 my @LibPaths = getSOPaths($LibVersion);
Andrey Ponomarenko16934472012-03-29 15:37:04 +040015964 if($#LibPaths==-1 and not $CheckHeadersOnly)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015965 {
15966 if($LibVersion==1)
15967 {
15968 printMsg("WARNING", "checking headers only");
15969 $CheckHeadersOnly = 1;
15970 }
15971 else {
15972 exitStatus("Error", "$SLIB_TYPE libraries are not found in ".$Descriptor{$LibVersion}{"Version"});
15973 }
15974 }
Andrey Ponomarenko16934472012-03-29 15:37:04 +040015975 my %GroupNames = map {parse_libname(get_filename($_), "name+ext", $OStarget)=>1} @LibPaths;
15976 foreach my $LibPath (sort {length($a)<=>length($b)} @LibPaths) {
15977 readSymbols_Lib($LibVersion, $LibPath, 0, \%GroupNames, "+Weak");
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015978 }
Andrey Ponomarenko16934472012-03-29 15:37:04 +040015979 if(not $CheckHeadersOnly)
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040015980 {
Andrey Ponomarenko16934472012-03-29 15:37:04 +040015981 if($#LibPaths!=-1)
15982 {
15983 if(not keys(%{$Symbol_Library{$LibVersion}}))
15984 {
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040015985 printMsg("WARNING", "the set of public symbols in library(ies) is empty ($LibVersion)");
Andrey Ponomarenko16934472012-03-29 15:37:04 +040015986 printMsg("WARNING", "checking headers only");
15987 $CheckHeadersOnly = 1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015988 }
15989 }
15990 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +040015991
15992 # clean memory
15993 %SystemObjects = ();
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015994}
15995
Andrey Ponomarenko16934472012-03-29 15:37:04 +040015996sub getSymbolSize($$)
15997{ # size from the shared library
15998 my ($Symbol, $LibVersion) = @_;
15999 return 0 if(not $Symbol);
16000 if(defined $Symbol_Library{$LibVersion}{$Symbol}
16001 and my $LibName = $Symbol_Library{$LibVersion}{$Symbol})
16002 {
16003 if(defined $Library_Symbol{$LibVersion}{$LibName}{$Symbol}
16004 and my $Size = $Library_Symbol{$LibVersion}{$LibName}{$Symbol})
16005 {
16006 if($Size<0) {
16007 return -$Size;
16008 }
16009 }
16010 }
16011 return 0;
16012}
16013
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040016014sub canonifyName($)
16015{ # make TIFFStreamOpen(char const*, std::basic_ostream<char, std::char_traits<char> >*)
16016 # to be TIFFStreamOpen(char const*, std::basic_ostream<char>*)
16017 my $Name = $_[0];
16018 my $Rem = "std::(allocator|less|char_traits|regex_traits)";
Andrey Ponomarenko85043792012-05-14 16:48:07 +040016019 while($Name=~/([^<>,]+),\s*$Rem<([^<>,]+)>\s*/ and $1 eq $3)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040016020 {
Andrey Ponomarenko85043792012-05-14 16:48:07 +040016021 my $P = $1;
16022 $Name=~s/\Q$P\E,\s*$Rem<\Q$P\E>\s*/$P/g;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040016023 }
16024 return $Name;
16025}
16026
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040016027sub translateSymbols(@)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040016028{
16029 my $LibVersion = pop(@_);
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040016030 my (@MnglNames1, @MnglNames2, @UnmangledNames) = ();
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040016031 foreach my $Interface (sort @_)
16032 {
16033 if($Interface=~/\A_Z/)
16034 {
16035 next if($tr_name{$Interface});
16036 $Interface=~s/[\@\$]+(.*)\Z//;
16037 push(@MnglNames1, $Interface);
16038 }
16039 elsif($Interface=~/\A\?/) {
16040 push(@MnglNames2, $Interface);
16041 }
16042 else
16043 { # not mangled
16044 $tr_name{$Interface} = $Interface;
16045 $mangled_name_gcc{$Interface} = $Interface;
16046 $mangled_name{$LibVersion}{$Interface} = $Interface;
16047 }
16048 }
16049 if($#MnglNames1 > -1)
16050 { # GCC names
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040016051 @UnmangledNames = reverse(unmangleArray(@MnglNames1));
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040016052 foreach my $MnglName (@MnglNames1)
16053 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040016054 if(my $Unmangled = pop(@UnmangledNames))
16055 {
16056 $tr_name{$MnglName} = formatName(canonifyName($Unmangled));
16057 if(not $mangled_name_gcc{$tr_name{$MnglName}}) {
16058 $mangled_name_gcc{$tr_name{$MnglName}} = $MnglName;
16059 }
16060 if($MnglName=~/\A_ZTV/
16061 and $tr_name{$MnglName}=~/vtable for (.+)/)
16062 { # bind class name and v-table symbol
16063 my $ClassName = $1;
16064 $ClassVTable{$ClassName} = $MnglName;
16065 $VTableClass{$MnglName} = $ClassName;
16066 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040016067 }
16068 }
16069 }
16070 if($#MnglNames2 > -1)
16071 { # MSVC names
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040016072 @UnmangledNames = reverse(unmangleArray(@MnglNames2));
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040016073 foreach my $MnglName (@MnglNames2)
16074 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040016075 if(my $Unmangled = pop(@UnmangledNames))
16076 {
16077 $tr_name{$MnglName} = formatName($Unmangled);
16078 $mangled_name{$LibVersion}{$tr_name{$MnglName}} = $MnglName;
16079 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040016080 }
16081 }
16082 return \%tr_name;
16083}
16084
16085sub link_symbol($$$)
16086{
16087 my ($Symbol, $RunWith, $Deps) = @_;
16088 if(link_symbol_internal($Symbol, $RunWith, \%Symbol_Library)) {
16089 return 1;
16090 }
16091 if($Deps eq "+Deps")
16092 { # check the dependencies
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040016093 if(link_symbol_internal($Symbol, $RunWith, \%DepSymbol_Library)) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040016094 return 1;
16095 }
16096 }
16097 return 0;
16098}
16099
16100sub link_symbol_internal($$$)
16101{
16102 my ($Symbol, $RunWith, $Where) = @_;
16103 return 0 if(not $Where or not $Symbol);
16104 if($Where->{$RunWith}{$Symbol})
16105 { # the exact match by symbol name
16106 return 1;
16107 }
16108 if(my $VSym = $SymVer{$RunWith}{$Symbol})
16109 { # indirect symbol version, i.e.
16110 # foo_old and its symlink foo@v (or foo@@v)
16111 # foo_old may be in .symtab table
16112 if($Where->{$RunWith}{$VSym}) {
16113 return 1;
16114 }
16115 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040016116 my ($Sym, $Spec, $Ver) = separate_symbol($Symbol);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040016117 if($Sym and $Ver)
16118 { # search for the symbol with the same version
16119 # or without version
16120 if($Where->{$RunWith}{$Sym})
16121 { # old: foo@v|foo@@v
16122 # new: foo
16123 return 1;
16124 }
16125 if($Where->{$RunWith}{$Sym."\@".$Ver})
16126 { # old: foo|foo@@v
16127 # new: foo@v
16128 return 1;
16129 }
16130 if($Where->{$RunWith}{$Sym."\@\@".$Ver})
16131 { # old: foo|foo@v
16132 # new: foo@@v
16133 return 1;
16134 }
16135 }
16136 return 0;
16137}
16138
Andrey Ponomarenko16934472012-03-29 15:37:04 +040016139sub readSymbols_App($)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040016140{
16141 my $Path = $_[0];
16142 return () if(not $Path or not -f $Path);
16143 my @Imported = ();
16144 if($OSgroup eq "macos")
16145 {
16146 my $OtoolCmd = get_CmdPath("otool");
16147 if(not $OtoolCmd) {
16148 exitStatus("Not_Found", "can't find \"otool\"");
16149 }
Andrey Ponomarenkoa01311b2012-06-08 17:20:02 +040016150 open(APP, "$OtoolCmd -IV \"$Path\" 2>\"$TMP_DIR/null\" |");
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040016151 while(<APP>) {
16152 if(/[^_]+\s+_?([\w\$]+)\s*\Z/) {
16153 push(@Imported, $1);
16154 }
16155 }
16156 close(APP);
16157 }
16158 elsif($OSgroup eq "windows")
16159 {
16160 my $DumpBinCmd = get_CmdPath("dumpbin");
16161 if(not $DumpBinCmd) {
16162 exitStatus("Not_Found", "can't find \"dumpbin.exe\"");
16163 }
Andrey Ponomarenkoa01311b2012-06-08 17:20:02 +040016164 open(APP, "$DumpBinCmd /IMPORTS \"$Path\" 2>\"$TMP_DIR/null\" |");
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040016165 while(<APP>) {
16166 if(/\s*\w+\s+\w+\s+\w+\s+([\w\?\@]+)\s*/) {
16167 push(@Imported, $1);
16168 }
16169 }
16170 close(APP);
16171 }
16172 else
16173 {
16174 my $ReadelfCmd = get_CmdPath("readelf");
16175 if(not $ReadelfCmd) {
16176 exitStatus("Not_Found", "can't find \"readelf\"");
16177 }
Andrey Ponomarenkoa01311b2012-06-08 17:20:02 +040016178 open(APP, "$ReadelfCmd -WhlSsdA \"$Path\" 2>\"$TMP_DIR/null\" |");
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040016179 my $symtab=0; # indicates that we are processing 'symtab' section of 'readelf' output
16180 while(<APP>)
16181 {
16182 if( /'.dynsym'/ ) {
16183 $symtab=0;
16184 }
16185 elsif($symtab == 1) {
16186 # do nothing with symtab (but there are some plans for the future)
16187 next;
16188 }
16189 elsif( /'.symtab'/ ) {
16190 $symtab=1;
16191 }
16192 elsif(my ($fullname, $idx, $Ndx, $type, $size, $bind) = readline_ELF($_))
16193 {
16194 if( $Ndx eq "UND" ) {
16195 #only imported symbols
16196 push(@Imported, $fullname);
16197 }
16198 }
16199 }
16200 close(APP);
16201 }
16202 return @Imported;
16203}
16204
16205sub readline_ELF($)
16206{
16207 if($_[0]=~/\s*\d+:\s+(\w*)\s+(\w+)\s+(\w+)\s+(\w+)\s+(\w+)\s+(\w+)\s([^\s]+)/)
16208 { # the line of 'readelf' output corresponding to the interface
16209 # symbian-style: _ZN12CCTTokenType4NewLE4TUid3RFs@@ctfinder{000a0000}[102020e5].dll
16210 my ($value, $size, $type, $bind,
16211 $vis, $Ndx, $fullname)=($1, $2, $3, $4, $5, $6, $7);
16212 if($bind!~/\A(WEAK|GLOBAL)\Z/) {
16213 return ();
16214 }
16215 if($type!~/\A(FUNC|IFUNC|OBJECT|COMMON)\Z/) {
16216 return ();
16217 }
16218 if($vis!~/\A(DEFAULT|PROTECTED)\Z/) {
16219 return ();
16220 }
16221 if($Ndx eq "ABS" and $value!~/\D|1|2|3|4|5|6|7|8|9/) {
16222 return ();
16223 }
16224 if($OStarget eq "symbian")
16225 {
16226 if($fullname=~/_\._\.absent_export_\d+/)
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040016227 { # "_._.absent_export_111"@@libstdcpp{00010001}[10282872].dll
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040016228 return ();
16229 }
16230 my @Elems = separate_symbol($fullname);
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040016231 $fullname = $Elems[0]; # remove internal version, {00020001}[10011235].dll
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040016232 }
Andrey Ponomarenkoa01311b2012-06-08 17:20:02 +040016233 if(index($size, "0x")!=-1)
16234 { # 0x3d158
16235 $size = hex($size);
16236 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040016237 return ($fullname, $value, $Ndx, $type, $size, $bind);
16238 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040016239 return ();
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040016240}
16241
Andrey Ponomarenko16934472012-03-29 15:37:04 +040016242sub read_symlink($)
16243{
16244 my $Path = $_[0];
16245 return "" if(not $Path);
16246 return "" if(not -f $Path and not -l $Path);
16247 if(defined $Cache{"read_symlink"}{$Path}) {
16248 return $Cache{"read_symlink"}{$Path};
16249 }
16250 if(my $Res = readlink($Path)) {
16251 return ($Cache{"read_symlink"}{$Path} = $Res);
16252 }
16253 elsif(my $ReadlinkCmd = get_CmdPath("readlink")) {
Andrey Ponomarenkoa01311b2012-06-08 17:20:02 +040016254 return ($Cache{"read_symlink"}{$Path} = `$ReadlinkCmd -n \"$Path\"`);
Andrey Ponomarenko16934472012-03-29 15:37:04 +040016255 }
16256 elsif(my $FileCmd = get_CmdPath("file"))
16257 {
Andrey Ponomarenkoa01311b2012-06-08 17:20:02 +040016258 my $Info = `$FileCmd \"$Path\"`;
Andrey Ponomarenko16934472012-03-29 15:37:04 +040016259 if($Info=~/symbolic\s+link\s+to\s+['`"]*([\w\d\.\-\/\\]+)['`"]*/i) {
16260 return ($Cache{"read_symlink"}{$Path} = $1);
16261 }
16262 }
16263 return ($Cache{"read_symlink"}{$Path} = "");
16264}
16265
16266sub resolve_symlink($)
16267{
16268 my $Path = $_[0];
16269 return "" if(not $Path);
16270 return "" if(not -f $Path and not -l $Path);
16271 if(defined $Cache{"resolve_symlink"}{$Path}) {
16272 return $Cache{"resolve_symlink"}{$Path};
16273 }
16274 return $Path if(isCyclical(\@RecurSymlink, $Path));
16275 push(@RecurSymlink, $Path);
16276 if(-l $Path and my $Redirect=read_symlink($Path))
16277 {
16278 if(is_abs($Redirect))
16279 { # absolute path
16280 if($SystemRoot and $SystemRoot ne "/"
16281 and $Path=~/\A\Q$SystemRoot\E\//
16282 and (-f $SystemRoot.$Redirect or -l $SystemRoot.$Redirect))
16283 { # symbolic links from the sysroot
16284 # should be corrected to point to
16285 # the files inside sysroot
16286 $Redirect = $SystemRoot.$Redirect;
16287 }
16288 my $Res = resolve_symlink($Redirect);
16289 pop(@RecurSymlink);
16290 return ($Cache{"resolve_symlink"}{$Path} = $Res);
16291 }
16292 elsif($Redirect=~/\.\.[\/\\]/)
16293 { # relative path
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040016294 $Redirect = joinPath(get_dirname($Path), $Redirect);
Andrey Ponomarenko16934472012-03-29 15:37:04 +040016295 while($Redirect=~s&(/|\\)[^\/\\]+(\/|\\)\.\.(\/|\\)&$1&){};
16296 my $Res = resolve_symlink($Redirect);
16297 pop(@RecurSymlink);
16298 return ($Cache{"resolve_symlink"}{$Path} = $Res);
16299 }
16300 elsif(-f get_dirname($Path)."/".$Redirect)
16301 { # file name in the same directory
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040016302 my $Res = resolve_symlink(joinPath(get_dirname($Path), $Redirect));
Andrey Ponomarenko16934472012-03-29 15:37:04 +040016303 pop(@RecurSymlink);
16304 return ($Cache{"resolve_symlink"}{$Path} = $Res);
16305 }
16306 else
16307 { # broken link
16308 pop(@RecurSymlink);
16309 return ($Cache{"resolve_symlink"}{$Path} = "");
16310 }
16311 }
16312 pop(@RecurSymlink);
16313 return ($Cache{"resolve_symlink"}{$Path} = $Path);
16314}
16315
16316sub find_lib_path($$)
16317{
16318 my ($LibVersion, $DyLib) = @_;
16319 return "" if(not $DyLib or not $LibVersion);
16320 return $DyLib if(is_abs($DyLib));
16321 if(defined $Cache{"find_lib_path"}{$LibVersion}{$DyLib}) {
16322 return $Cache{"find_lib_path"}{$LibVersion}{$DyLib};
16323 }
16324 if(my @Paths = sort keys(%{$InputObject_Paths{$LibVersion}{$DyLib}})) {
16325 return ($Cache{"find_lib_path"}{$LibVersion}{$DyLib} = $Paths[0]);
16326 }
16327 elsif(my $DefaultPath = $DyLib_DefaultPath{$DyLib}) {
16328 return ($Cache{"find_lib_path"}{$LibVersion}{$DyLib} = $DefaultPath);
16329 }
16330 else
16331 {
16332 foreach my $Dir (sort keys(%DefaultLibPaths), sort keys(%{$SystemPaths{"lib"}}))
16333 { # search in default linker paths and then in all system paths
16334 if(-f $Dir."/".$DyLib) {
16335 return ($Cache{"find_lib_path"}{$LibVersion}{$DyLib} = joinPath($Dir,$DyLib));
16336 }
16337 }
16338 detectSystemObjects() if(not keys(%SystemObjects));
16339 if(my @AllObjects = keys(%{$SystemObjects{$DyLib}})) {
16340 return ($Cache{"find_lib_path"}{$LibVersion}{$DyLib} = $AllObjects[0]);
16341 }
16342 my $ShortName = parse_libname($DyLib, "name+ext", $OStarget);
16343 if($ShortName ne $DyLib
16344 and my $Path = find_lib_path($ShortName))
16345 { # FIXME: check this case
16346 return ($Cache{"find_lib_path"}{$LibVersion}{$DyLib} = $Path);
16347 }
16348 return ($Cache{"find_lib_path"}{$LibVersion}{$DyLib} = "");
16349 }
16350}
16351
16352sub readSymbols_Lib($$$$$)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040016353{
16354 my ($LibVersion, $Lib_Path, $IsNeededLib, $GroupNames, $Weak) = @_;
16355 return if(not $Lib_Path or not -f $Lib_Path);
16356 my ($Lib_Dir, $Lib_Name) = separate_path(resolve_symlink($Lib_Path));
16357 return if($CheckedDyLib{$LibVersion}{$Lib_Name} and $IsNeededLib);
16358 return if(isCyclical(\@RecurLib, $Lib_Name) or $#RecurLib>=1);
16359 $CheckedDyLib{$LibVersion}{$Lib_Name} = 1;
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040016360 my $Lib_SName = parse_libname($Lib_Name, "name+ext", $OStarget);
16361
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040016362 if($CheckImpl and not $IsNeededLib) {
16363 getImplementations($LibVersion, $Lib_Path);
16364 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040016365
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040016366 push(@RecurLib, $Lib_Name);
16367 my (%Value_Interface, %Interface_Value, %NeededLib) = ();
16368 if(not $IsNeededLib)
16369 { # libstdc++ and libc are always used by other libs
16370 # if you test one of these libs then you not need
16371 # to find them in the system for reusing
16372 if(parse_libname($Lib_Name, "short", $OStarget) eq "libstdc++")
16373 { # libstdc++.so.6
16374 $STDCXX_TESTING = 1;
16375 }
16376 if(parse_libname($Lib_Name, "short", $OStarget) eq "libc")
16377 { # libc-2.11.3.so
16378 $GLIBC_TESTING = 1;
16379 }
16380 }
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040016381 my $DebugPath = "";
Andrey Ponomarenkoa01311b2012-06-08 17:20:02 +040016382 if($Debug and not $DumpSystem)
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040016383 { # debug mode
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040016384 $DebugPath = $DEBUG_PATH{$LibVersion}."/libs/".get_filename($Lib_Path).".txt";
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040016385 mkpath(get_dirname($DebugPath));
16386 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040016387 if($OStarget eq "macos")
16388 { # Mac OS X: *.dylib, *.a
16389 my $OtoolCmd = get_CmdPath("otool");
16390 if(not $OtoolCmd) {
16391 exitStatus("Not_Found", "can't find \"otool\"");
16392 }
Andrey Ponomarenkoa01311b2012-06-08 17:20:02 +040016393 $OtoolCmd .= " -TV \"$Lib_Path\" 2>\"$TMP_DIR/null\"";
16394 if($DebugPath)
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040016395 { # debug mode
Andrey Ponomarenko16934472012-03-29 15:37:04 +040016396 # write to file
Andrey Ponomarenkoa01311b2012-06-08 17:20:02 +040016397 system($OtoolCmd." >\"$DebugPath\"");
Andrey Ponomarenko16934472012-03-29 15:37:04 +040016398 open(LIB, $DebugPath);
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040016399 }
Andrey Ponomarenko16934472012-03-29 15:37:04 +040016400 else
16401 { # write to pipe
16402 open(LIB, $OtoolCmd." |");
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040016403 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040016404 while(<LIB>)
16405 {
16406 if(/[^_]+\s+_([\w\$]+)\s*\Z/)
16407 {
16408 my $realname = $1;
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040016409 if($IsNeededLib)
16410 {
16411 if(not $GroupNames->{$Lib_SName})
16412 {
16413 $DepSymbol_Library{$LibVersion}{$realname} = $Lib_Name;
16414 $DepLibrary_Symbol{$LibVersion}{$Lib_Name}{$realname} = 1;
16415 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040016416 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040016417 else
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040016418 {
16419 $Symbol_Library{$LibVersion}{$realname} = $Lib_Name;
16420 $Library_Symbol{$LibVersion}{$Lib_Name}{$realname} = 1;
16421 if($COMMON_LANGUAGE{$LibVersion} ne "C++"
16422 and $realname=~/\A(_Z|\?)/) {
16423 setLanguage($LibVersion, "C++");
16424 }
16425 if($CheckObjectsOnly
16426 and $LibVersion==1) {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040016427 $CheckedSymbols{"Binary"}{$realname} = 1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040016428 }
16429 }
16430 }
16431 }
16432 close(LIB);
16433 if($LIB_TYPE eq "dynamic")
16434 { # dependencies
Andrey Ponomarenkoa01311b2012-06-08 17:20:02 +040016435 open(LIB, "$OtoolCmd -L \"$Lib_Path\" 2>\"$TMP_DIR/null\" |");
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040016436 while(<LIB>)
16437 {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040016438 if(/\s*([\/\\].+\.$LIB_EXT)\s*/
16439 and $1 ne $Lib_Path) {
16440 $NeededLib{$1} = 1;
16441 }
16442 }
16443 close(LIB);
16444 }
16445 }
16446 elsif($OStarget eq "windows")
16447 { # Windows *.dll, *.lib
16448 my $DumpBinCmd = get_CmdPath("dumpbin");
16449 if(not $DumpBinCmd) {
16450 exitStatus("Not_Found", "can't find \"dumpbin\"");
16451 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040016452 $DumpBinCmd .= " /EXPORTS \"".$Lib_Path."\" 2>$TMP_DIR/null";
Andrey Ponomarenkoa01311b2012-06-08 17:20:02 +040016453 if($DebugPath)
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040016454 { # debug mode
Andrey Ponomarenko16934472012-03-29 15:37:04 +040016455 # write to file
Andrey Ponomarenkoa01311b2012-06-08 17:20:02 +040016456 system($DumpBinCmd." >\"$DebugPath\"");
Andrey Ponomarenko16934472012-03-29 15:37:04 +040016457 open(LIB, $DebugPath);
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040016458 }
Andrey Ponomarenko16934472012-03-29 15:37:04 +040016459 else
16460 { # write to pipe
16461 open(LIB, $DumpBinCmd." |");
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040016462 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040016463 while(<LIB>)
16464 { # 1197 4AC 0000A620 SetThreadStackGuarantee
16465 # 1198 4AD SetThreadToken (forwarded to ...)
16466 # 3368 _o2i_ECPublicKey
16467 if(/\A\s*\d+\s+[a-f\d]+\s+[a-f\d]+\s+([\w\?\@]+)\s*\Z/i
16468 or /\A\s*\d+\s+[a-f\d]+\s+([\w\?\@]+)\s*\(\s*forwarded\s+/
16469 or /\A\s*\d+\s+_([\w\?\@]+)\s*\Z/)
16470 { # dynamic, static and forwarded symbols
16471 my $realname = $1;
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040016472 if($IsNeededLib)
16473 {
16474 if(not $GroupNames->{$Lib_SName})
16475 {
16476 $DepSymbol_Library{$LibVersion}{$realname} = $Lib_Name;
16477 $DepLibrary_Symbol{$LibVersion}{$Lib_Name}{$realname} = 1;
16478 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040016479 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040016480 else
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040016481 {
16482 $Symbol_Library{$LibVersion}{$realname} = $Lib_Name;
16483 $Library_Symbol{$LibVersion}{$Lib_Name}{$realname} = 1;
16484 if($COMMON_LANGUAGE{$LibVersion} ne "C++"
16485 and $realname=~/\A(_Z|\?)/) {
16486 setLanguage($LibVersion, "C++");
16487 }
16488 if($CheckObjectsOnly
16489 and $LibVersion==1) {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040016490 $CheckedSymbols{"Binary"}{$realname} = 1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040016491 }
16492 }
16493 }
16494 }
16495 close(LIB);
16496 if($LIB_TYPE eq "dynamic")
16497 { # dependencies
Andrey Ponomarenkoa01311b2012-06-08 17:20:02 +040016498 open(LIB, "$DumpBinCmd /DEPENDENTS \"$Lib_Path\" 2>\"$TMP_DIR/null\" |");
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040016499 while(<LIB>)
16500 {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040016501 if(/\s*([^\s]+?\.$LIB_EXT)\s*/i
16502 and $1 ne $Lib_Path) {
16503 $NeededLib{path_format($1, $OSgroup)} = 1;
16504 }
16505 }
16506 close(LIB);
16507 }
16508 }
16509 else
16510 { # Unix; *.so, *.a
16511 # Symbian: *.dso, *.lib
16512 my $ReadelfCmd = get_CmdPath("readelf");
16513 if(not $ReadelfCmd) {
16514 exitStatus("Not_Found", "can't find \"readelf\"");
16515 }
Andrey Ponomarenkoa01311b2012-06-08 17:20:02 +040016516 $ReadelfCmd .= " -WhlSsdA \"$Lib_Path\" 2>\"$TMP_DIR/null\"";
16517 if($DebugPath)
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040016518 { # debug mode
Andrey Ponomarenko16934472012-03-29 15:37:04 +040016519 # write to file
Andrey Ponomarenkoa01311b2012-06-08 17:20:02 +040016520 system($ReadelfCmd." >\"$DebugPath\"");
Andrey Ponomarenko16934472012-03-29 15:37:04 +040016521 open(LIB, $DebugPath);
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040016522 }
Andrey Ponomarenko16934472012-03-29 15:37:04 +040016523 else
16524 { # write to pipe
16525 open(LIB, $ReadelfCmd." |");
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040016526 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040016527 my $symtab=0; # indicates that we are processing 'symtab' section of 'readelf' output
16528 while(<LIB>)
16529 {
16530 if($LIB_TYPE eq "dynamic")
16531 { # dynamic library specifics
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040016532 if($symtab==1)
16533 {
16534 if(/'\.dynsym'/)
16535 { # dynamic table
16536 $symtab=0;
16537 next;
16538 }
16539 else
16540 { # do nothing with symtab
16541 next;
16542 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040016543 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040016544 elsif(/'\.symtab'/)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040016545 { # symbol table
16546 $symtab=1;
16547 next;
16548 }
16549 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040016550 if(my ($fullname, $idx, $Ndx, $type, $size, $bind) = readline_ELF($_))
16551 { # read ELF entry
16552 if( $Ndx eq "UND" )
16553 { # ignore interfaces that are imported from somewhere else
16554 next;
16555 }
16556 if($bind eq "WEAK"
16557 and $Weak eq "-Weak")
16558 { # skip WEAK symbols
16559 next;
16560 }
16561 my ($realname, $version_spec, $version) = separate_symbol($fullname);
16562 if($type eq "OBJECT")
16563 { # global data
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040016564 $GlobalDataObject{$LibVersion}{$fullname} = 1;
16565 $GlobalDataObject{$LibVersion}{$realname} = 1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040016566 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040016567 if($IsNeededLib)
16568 {
16569 if(not $GroupNames->{$Lib_SName})
16570 {
16571 $DepSymbol_Library{$LibVersion}{$fullname} = $Lib_Name;
16572 $DepLibrary_Symbol{$LibVersion}{$Lib_Name}{$fullname} = ($type eq "OBJECT")?-$size:1;
16573 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040016574 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040016575 else
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040016576 {
16577 $Symbol_Library{$LibVersion}{$fullname} = $Lib_Name;
16578 $Library_Symbol{$LibVersion}{$Lib_Name}{$fullname} = ($type eq "OBJECT")?-$size:1;
16579 if($LIB_EXT eq "so")
16580 { # value
16581 $Interface_Value{$LibVersion}{$fullname} = $idx;
16582 $Value_Interface{$LibVersion}{$idx}{$fullname} = 1;
16583 }
16584 if($COMMON_LANGUAGE{$LibVersion} ne "C++"
16585 and $realname=~/\A(_Z|\?)/) {
16586 setLanguage($LibVersion, "C++");
16587 }
16588 if($CheckObjectsOnly
16589 and $LibVersion==1) {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040016590 $CheckedSymbols{"Binary"}{$fullname} = 1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040016591 }
16592 }
16593 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040016594 elsif($LIB_TYPE eq "dynamic")
16595 { # dynamic library specifics
16596 if(/NEEDED.+\[([^\[\]]+)\]/)
16597 { # dependencies:
16598 # 0x00000001 (NEEDED) Shared library: [libc.so.6]
16599 $NeededLib{$1} = 1;
16600 }
16601 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040016602 }
16603 close(LIB);
16604 }
16605 if(not $IsNeededLib and $LIB_EXT eq "so")
16606 { # get symbol versions
16607 foreach my $Symbol (keys(%{$Symbol_Library{$LibVersion}}))
16608 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040016609 next if(index($Symbol,"\@")==-1);
Andrey Ponomarenkoa01311b2012-06-08 17:20:02 +040016610 if(my $Value = $Interface_Value{$LibVersion}{$Symbol})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040016611 {
Andrey Ponomarenkoa01311b2012-06-08 17:20:02 +040016612 my $Interface_SymName = "";
16613 foreach my $Symbol_SameValue (keys(%{$Value_Interface{$LibVersion}{$Value}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040016614 {
Andrey Ponomarenkoa01311b2012-06-08 17:20:02 +040016615 if($Symbol_SameValue ne $Symbol
16616 and index($Symbol_SameValue,"\@")==-1)
16617 {
16618 $SymVer{$LibVersion}{$Symbol_SameValue} = $Symbol;
16619 $Interface_SymName = $Symbol_SameValue;
16620 last;
16621 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040016622 }
Andrey Ponomarenkoa01311b2012-06-08 17:20:02 +040016623 if(not $Interface_SymName)
16624 {
16625 if($Symbol=~/\A([^\@\$\?]*)[\@\$]+([^\@\$]*)\Z/
16626 and not $SymVer{$LibVersion}{$1}) {
16627 $SymVer{$LibVersion}{$1} = $Symbol;
16628 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040016629 }
16630 }
16631 }
16632 }
16633 foreach my $DyLib (sort keys(%NeededLib))
16634 {
16635 my $DepPath = find_lib_path($LibVersion, $DyLib);
16636 if($DepPath and -f $DepPath) {
Andrey Ponomarenko16934472012-03-29 15:37:04 +040016637 readSymbols_Lib($LibVersion, $DepPath, 1, $GroupNames, "+Weak");
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040016638 }
16639 }
16640 pop(@RecurLib);
16641 return $Library_Symbol{$LibVersion};
16642}
16643
16644sub get_path_prefixes($)
16645{
16646 my $Path = $_[0];
16647 my ($Dir, $Name) = separate_path($Path);
16648 my %Prefixes = ();
16649 foreach my $Prefix (reverse(split(/[\/\\]+/, $Dir)))
16650 {
16651 $Prefixes{$Name} = 1;
16652 $Name = joinPath($Prefix, $Name);
16653 last if(keys(%Prefixes)>5 or $Prefix eq "include");
16654 }
16655 return keys(%Prefixes);
16656}
16657
16658sub detectSystemHeaders()
16659{
16660 my @SysHeaders = ();
16661 foreach my $DevelPath (keys(%{$SystemPaths{"include"}}))
16662 {
16663 next if(not -d $DevelPath);
16664 # search for all header files in the /usr/include
16665 # with or without extension (ncurses.h, QtCore, ...)
16666 @SysHeaders = (@SysHeaders, cmd_find($DevelPath,"f","",""));
16667 foreach my $Link (cmd_find($DevelPath,"l","",""))
16668 { # add symbolic links
16669 if(-f $Link) {
16670 push(@SysHeaders, $Link);
16671 }
16672 }
16673 }
16674 foreach my $DevelPath (keys(%{$SystemPaths{"lib"}}))
16675 {
16676 next if(not -d $DevelPath);
16677 # search for config headers in the /usr/lib
16678 @SysHeaders = (@SysHeaders, cmd_find($DevelPath,"f","*.h",""));
16679 foreach my $Dir (cmd_find($DevelPath,"d","include",""))
16680 { # search for all include directories
16681 # this is for headers that are installed to /usr/lib
16682 # Example: Qt4 headers in Mandriva (/usr/lib/qt4/include/)
16683 if($Dir=~/\/(gcc|jvm|syslinux|kdb)\//) {
16684 next;
16685 }
16686 @SysHeaders = (@SysHeaders, cmd_find($Dir,"f","",""));
16687 }
16688 }
16689 foreach my $Path (@SysHeaders)
16690 {
16691 foreach my $Part (get_path_prefixes($Path)) {
16692 $SystemHeaders{$Part}{$Path}=1;
16693 }
16694 }
16695}
16696
16697sub detectSystemObjects()
16698{
16699 foreach my $DevelPath (keys(%{$SystemPaths{"lib"}}))
16700 {
16701 next if(not -d $DevelPath);
16702 foreach my $Path (find_libs($DevelPath,"",""))
16703 { # search for shared libraries in the /usr/lib (including symbolic links)
16704 $SystemObjects{parse_libname(get_filename($Path), "name+ext", $OStarget)}{$Path}=1;
16705 }
16706 }
16707}
16708
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040016709sub getSOPaths($)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040016710{
16711 my $LibVersion = $_[0];
16712 my @SoPaths = ();
16713 foreach my $Dest (split(/\s*\n\s*/, $Descriptor{$LibVersion}{"Libs"}))
16714 {
16715 if(not -e $Dest) {
16716 exitStatus("Access_Error", "can't access \'$Dest\'");
16717 }
16718 my @SoPaths_Dest = getSOPaths_Dest($Dest, $LibVersion);
16719 foreach (@SoPaths_Dest) {
16720 push(@SoPaths, $_);
16721 }
16722 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040016723 return sort @SoPaths;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040016724}
16725
16726sub skip_lib($$)
16727{
16728 my ($Path, $LibVersion) = @_;
16729 return 1 if(not $Path or not $LibVersion);
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040016730 my $Name = get_filename($Path);
16731 if($SkipLibs{$LibVersion}{"Name"}{$Name}) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040016732 return 1;
16733 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040016734 my $ShortName = parse_libname($Name, "name+ext", $OStarget);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040016735 if($SkipLibs{$LibVersion}{"Name"}{$ShortName}) {
16736 return 1;
16737 }
16738 foreach my $Dir (keys(%{$SkipLibs{$LibVersion}{"Path"}}))
16739 {
16740 if($Path=~/\Q$Dir\E([\/\\]|\Z)/) {
16741 return 1;
16742 }
16743 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040016744 foreach my $P (keys(%{$SkipLibs{$LibVersion}{"Pattern"}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040016745 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040016746 if($Name=~/$P/) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040016747 return 1;
16748 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040016749 if($P=~/[\/\\]/ and $Path=~/$P/) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040016750 return 1;
16751 }
16752 }
16753 return 0;
16754}
16755
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040016756sub skipHeader($$)
16757{
16758 my ($Path, $LibVersion) = @_;
16759 return 1 if(not $Path or not $LibVersion);
16760 if(not keys(%{$SkipHeaders{$LibVersion}})) {
16761 return 0;
16762 }
16763 if(defined $Cache{"skipHeader"}{$Path}) {
16764 return $Cache{"skipHeader"}{$Path};
16765 }
16766 return ($Cache{"skipHeader"}{$Path} = skipHeader_I(@_));
16767}
16768
16769sub skipHeader_I($$)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040016770{ # returns:
16771 # 1 - if header should NOT be included and checked
16772 # 2 - if header should NOT be included, but should be checked
16773 my ($Path, $LibVersion) = @_;
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040016774 my $Name = get_filename($Path);
16775 if(my $Kind = $SkipHeaders{$LibVersion}{"Name"}{$Name}) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040016776 return $Kind;
16777 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040016778 foreach my $D (keys(%{$SkipHeaders{$LibVersion}{"Path"}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040016779 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040016780 if($Path=~/\Q$D\E([\/\\]|\Z)/) {
16781 return $SkipHeaders{$LibVersion}{"Path"}{$D};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040016782 }
16783 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040016784 foreach my $P (keys(%{$SkipHeaders{$LibVersion}{"Pattern"}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040016785 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040016786 if(my $Kind = $SkipHeaders{$LibVersion}{"Pattern"}{$P})
16787 {
16788 if($Name=~/$P/) {
16789 return $Kind;
16790 }
16791 if($P=~/[\/\\]/ and $Path=~/$P/) {
16792 return $Kind;
16793 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040016794 }
16795 }
16796 return 0;
16797}
16798
16799sub register_objects($$)
16800{
16801 my ($Dir, $LibVersion) = @_;
16802 if($SystemPaths{"lib"}{$Dir})
16803 { # system directory
16804 return;
16805 }
16806 if($RegisteredObjDirs{$LibVersion}{$Dir})
16807 { # already registered
16808 return;
16809 }
16810 foreach my $Path (find_libs($Dir,"",1))
16811 {
16812 next if(ignore_path($Path));
16813 next if(skip_lib($Path, $LibVersion));
16814 $InputObject_Paths{$LibVersion}{get_filename($Path)}{$Path} = 1;
16815 }
16816 $RegisteredObjDirs{$LibVersion}{$Dir} = 1;
16817}
16818
16819sub getSOPaths_Dest($$)
16820{
16821 my ($Dest, $LibVersion) = @_;
16822 if(skip_lib($Dest, $LibVersion)) {
16823 return ();
16824 }
16825 if(-f $Dest)
16826 {
16827 if(not parse_libname($Dest, "name", $OStarget)) {
16828 exitStatus("Error", "incorrect format of library (should be *.$LIB_EXT): \'$Dest\'");
16829 }
16830 $InputObject_Paths{$LibVersion}{get_filename($Dest)}{$Dest} = 1;
16831 register_objects(get_dirname($Dest), $LibVersion);
16832 return ($Dest);
16833 }
16834 elsif(-d $Dest)
16835 {
16836 $Dest=~s/[\/\\]+\Z//g;
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040016837 my %Libs = ();
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040016838 if($SystemPaths{"lib"}{$Dest})
16839 { # you have specified /usr/lib as the search directory (<libs>) in the XML descriptor
16840 # and the real name of the library by -l option (bz2, stdc++, Xaw, ...)
16841 foreach my $Path (cmd_find($Dest,"","*".esc($TargetLibraryName)."*\.$LIB_EXT*",2))
16842 { # all files and symlinks that match the name of a library
16843 if(get_filename($Path)=~/\A(|lib)\Q$TargetLibraryName\E[\d\-]*\.$LIB_EXT[\d\.]*\Z/i)
16844 {
16845 $InputObject_Paths{$LibVersion}{get_filename($Path)}{$Path} = 1;
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040016846 $Libs{resolve_symlink($Path)}=1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040016847 }
16848 }
16849 }
16850 else
16851 { # search for all files and symlinks
16852 foreach my $Path (find_libs($Dest,"",""))
16853 {
16854 next if(ignore_path($Path));
16855 next if(skip_lib($Path, $LibVersion));
16856 $InputObject_Paths{$LibVersion}{get_filename($Path)}{$Path} = 1;
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040016857 $Libs{resolve_symlink($Path)}=1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040016858 }
16859 if($OSgroup eq "macos")
16860 { # shared libraries on MacOS X may have no extension
16861 foreach my $Path (cmd_find($Dest,"f","",""))
16862 {
16863 next if(ignore_path($Path));
16864 next if(skip_lib($Path, $LibVersion));
16865 if(get_filename($Path)!~/\./
Andrey Ponomarenko85043792012-05-14 16:48:07 +040016866 and cmd_file($Path)=~/(shared|dynamic)\s+library/i)
16867 {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040016868 $InputObject_Paths{$LibVersion}{get_filename($Path)}{$Path} = 1;
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040016869 $Libs{resolve_symlink($Path)}=1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040016870 }
16871 }
16872 }
16873 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040016874 return keys(%Libs);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040016875 }
16876 else {
16877 return ();
16878 }
16879}
16880
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040016881sub isCyclical($$)
16882{
16883 my ($Stack, $Value) = @_;
16884 return (grep {$_ eq $Value} @{$Stack});
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040016885}
16886
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040016887sub generateTemplate()
16888{
16889 writeFile("VERSION.xml", $DescriptorTemplate."\n");
16890 printMsg("INFO", "XML-descriptor template ./VERSION.xml has been generated");
16891}
16892
16893sub detectWordSize()
16894{
16895 return "" if(not $GCC_PATH);
16896 if($Cache{"detectWordSize"}) {
16897 return $Cache{"detectWordSize"};
16898 }
16899 writeFile("$TMP_DIR/empty.h", "");
Andrey Ponomarenkoa01311b2012-06-08 17:20:02 +040016900 my $Defines = `$GCC_PATH -E -dD \"$TMP_DIR/empty.h\"`;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040016901 unlink("$TMP_DIR/empty.h");
16902 my $WSize = 0;
16903 if($Defines=~/ __SIZEOF_POINTER__\s+(\d+)/)
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040016904 { # GCC 4
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040016905 $WSize = $1;
16906 }
16907 elsif($Defines=~/ __PTRDIFF_TYPE__\s+(\w+)/)
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040016908 { # GCC 3
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040016909 my $PTRDIFF = $1;
16910 if($PTRDIFF=~/long/) {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040016911 $WSize = "8";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040016912 }
16913 else {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040016914 $WSize = "4";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040016915 }
16916 }
16917 if(not int($WSize)) {
16918 exitStatus("Error", "can't check WORD size");
16919 }
16920 return ($Cache{"detectWordSize"} = $WSize);
16921}
16922
16923sub majorVersion($)
16924{
16925 my $V = $_[0];
16926 return 0 if(not $V);
16927 my @VParts = split(/\./, $V);
16928 return $VParts[0];
16929}
16930
16931sub cmpVersions($$)
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040016932{ # compare two versions in dotted-numeric format
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040016933 my ($V1, $V2) = @_;
16934 return 0 if($V1 eq $V2);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040016935 my @V1Parts = split(/\./, $V1);
16936 my @V2Parts = split(/\./, $V2);
16937 for (my $i = 0; $i <= $#V1Parts && $i <= $#V2Parts; $i++) {
16938 return -1 if(int($V1Parts[$i]) < int($V2Parts[$i]));
16939 return 1 if(int($V1Parts[$i]) > int($V2Parts[$i]));
16940 }
16941 return -1 if($#V1Parts < $#V2Parts);
16942 return 1 if($#V1Parts > $#V2Parts);
16943 return 0;
16944}
16945
16946sub read_ABI_Dump($$)
16947{
16948 my ($LibVersion, $Path) = @_;
16949 return if(not $LibVersion or not -e $Path);
16950 my $FilePath = "";
16951 if($Path=~/\.abi\Z/)
16952 { # input *.abi
16953 $FilePath = $Path;
16954 }
16955 else
16956 { # input *.abi.tar.gz
16957 $FilePath = unpackDump($Path);
16958 }
16959 if($FilePath!~/\.abi\Z/) {
16960 exitStatus("Invalid_Dump", "specified ABI dump \'$Path\' is not valid, try to recreate it");
16961 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +040016962
Andrey Ponomarenko5c09ef32012-06-14 18:17:33 +040016963 my $Line = readLineNum($FilePath, 1);
16964 if($Line=~/xml/) {
16965 exitStatus("Invalid_Dump", "reading of XML-format ABI dumps is not implemented yet");
16966 }
16967
Andrey Ponomarenko85043792012-05-14 16:48:07 +040016968 open(DUMP, $FilePath);
16969 local $/ = undef;
16970 my $Content = <DUMP>;
16971 close(DUMP);
16972
Andrey Ponomarenko5c09ef32012-06-14 18:17:33 +040016973 if(get_dirname($FilePath) eq $TMP_DIR."/unpack")
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040016974 { # remove temp file
16975 unlink($FilePath);
16976 }
16977 if($Content!~/};\s*\Z/) {
16978 exitStatus("Invalid_Dump", "specified ABI dump \'$Path\' is not valid, try to recreate it");
16979 }
16980 my $LibraryABI = eval($Content);
16981 if(not $LibraryABI) {
16982 exitStatus("Error", "internal error - eval() procedure seem to not working correctly, try to remove 'use strict' and try again");
16983 }
16984 # new dumps (>=1.22) have a personal versioning
16985 my $DumpVersion = $LibraryABI->{"ABI_DUMP_VERSION"};
16986 my $ToolVersion = $LibraryABI->{"ABI_COMPLIANCE_CHECKER_VERSION"};
16987 if(not $DumpVersion)
16988 { # old dumps (<=1.21.6) have been marked by the tool version
16989 $DumpVersion = $ToolVersion;
16990 }
16991 $UsedDump{$LibVersion}{"V"} = $DumpVersion;
16992 if(majorVersion($DumpVersion) ne majorVersion($ABI_DUMP_VERSION))
16993 { # should be compatible with dumps of the same major version
16994 if(cmpVersions($DumpVersion, $ABI_DUMP_VERSION)>0)
16995 { # Don't know how to parse future dump formats
16996 exitStatus("Dump_Version", "incompatible version $DumpVersion of specified ABI dump (newer than $ABI_DUMP_VERSION)");
16997 }
16998 elsif(cmpVersions($DumpVersion, $TOOL_VERSION)>0 and not $LibraryABI->{"ABI_DUMP_VERSION"})
16999 { # Don't know how to parse future dump formats
17000 exitStatus("Dump_Version", "incompatible version $DumpVersion of specified ABI dump (newer than $TOOL_VERSION)");
17001 }
17002 if($UseOldDumps)
17003 {
17004 if(cmpVersions($DumpVersion, $OLDEST_SUPPORTED_VERSION)<0) {
17005 exitStatus("Dump_Version", "incompatible version $DumpVersion of specified ABI dump (older than $OLDEST_SUPPORTED_VERSION)");
17006 }
17007 }
17008 else
17009 {
17010 my $Msg = "incompatible version $DumpVersion of specified ABI dump (allowed only ".majorVersion($ABI_DUMP_VERSION).".0<=V<=$ABI_DUMP_VERSION)";
17011 if(cmpVersions($DumpVersion, $OLDEST_SUPPORTED_VERSION)>=0) {
17012 $Msg .= "\nUse -old-dumps option to use old-version dumps ($OLDEST_SUPPORTED_VERSION<=V<".majorVersion($ABI_DUMP_VERSION).".0)";
17013 }
17014 exitStatus("Dump_Version", $Msg);
17015 }
17016 }
Andrey Ponomarenko5c09ef32012-06-14 18:17:33 +040017017 if(not checkDump($LibVersion, "2.11"))
17018 { # old ABI dumps
17019 $UsedDump{$LibVersion}{"BinOnly"} = 1;
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040017020 }
17021 elsif($LibraryABI->{"BinOnly"})
17022 { # ABI dump created with --binary option
17023 $UsedDump{$LibVersion}{"BinOnly"} = 1;
17024 }
Andrey Ponomarenko5c09ef32012-06-14 18:17:33 +040017025 else
17026 { # default
17027 $UsedDump{$LibVersion}{"SrcBin"} = 1;
17028 }
Andrey Ponomarenko16934472012-03-29 15:37:04 +040017029 if(defined $LibraryABI->{"Mode"}
17030 and $LibraryABI->{"Mode"} eq "Extended")
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017031 { # --ext option
17032 $ExtendedCheck = 1;
17033 }
17034 if(my $Lang = $LibraryABI->{"Language"})
17035 {
17036 $UsedDump{$LibVersion}{"L"} = $Lang;
17037 setLanguage($LibVersion, $Lang);
17038 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040017039 if(checkDump($LibVersion, "2.15")) {
17040 $TypeInfo{$LibVersion} = $LibraryABI->{"TypeInfo"};
17041 }
17042 else
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017043 { # support for old ABI dumps
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040017044 my $TInfo = $LibraryABI->{"TypeInfo"};
17045 if(not $TInfo)
17046 { # support for older ABI dumps
17047 $TInfo = $LibraryABI->{"TypeDescr"};
17048 }
17049 my %Tid_TDid = ();
17050 foreach my $TDid (keys(%{$TInfo}))
17051 {
17052 foreach my $Tid (keys(%{$TInfo->{$TDid}}))
17053 {
17054 $MAX_ID = $Tid if($Tid>$MAX_ID);
17055 $MAX_ID = $TDid if($TDid and $TDid>$MAX_ID);
17056 $Tid_TDid{$Tid}{$TDid}=1;
17057 }
17058 }
17059 my %NewID = ();
17060 foreach my $Tid (keys(%Tid_TDid))
17061 {
17062 my @TDids = keys(%{$Tid_TDid{$Tid}});
17063 if($#TDids>=1)
17064 {
17065 foreach my $TDid (@TDids)
17066 {
17067 if($TDid) {
17068 %{$TypeInfo{$LibVersion}{$Tid}} = %{$TInfo->{$TDid}{$Tid}};
17069 }
17070 else
17071 {
17072 if(my $ID = ++$MAX_ID)
17073 {
17074 $NewID{$TDid}{$Tid} = $ID;
17075 %{$TypeInfo{$LibVersion}{$ID}} = %{$TInfo->{$TDid}{$Tid}};
17076 $TypeInfo{$LibVersion}{$ID}{"Tid"} = $ID;
17077 }
17078 }
17079 }
17080 }
17081 else
17082 {
17083 my $TDid = $TDids[0];
17084 %{$TypeInfo{$LibVersion}{$Tid}} = %{$TInfo->{$TDid}{$Tid}};
17085 }
17086 }
17087 foreach my $Tid (keys(%{$TypeInfo{$LibVersion}}))
17088 {
17089 my %Info = %{$TypeInfo{$LibVersion}{$Tid}};
17090 if(defined $Info{"BaseType"})
17091 {
17092 my $Bid = $Info{"BaseType"}{"Tid"};
17093 my $BDid = $Info{"BaseType"}{"TDid"};
17094 $BDid="" if(not defined $BDid);
17095 if(defined $NewID{$BDid} and my $ID = $NewID{$BDid}{$Bid}) {
17096 $TypeInfo{$LibVersion}{$Tid}{"BaseType"}{"Tid"} = $ID;
17097 }
17098 delete($TypeInfo{$LibVersion}{$Tid}{"BaseType"}{"TDid"});
17099 }
17100 delete($TypeInfo{$LibVersion}{$Tid}{"TDid"});
17101 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017102 }
17103 read_Machine_DumpInfo($LibraryABI, $LibVersion);
17104 $SymbolInfo{$LibVersion} = $LibraryABI->{"SymbolInfo"};
17105 if(not $SymbolInfo{$LibVersion})
17106 { # support for old dumps
17107 $SymbolInfo{$LibVersion} = $LibraryABI->{"FuncDescr"};
17108 }
17109 if(not keys(%{$SymbolInfo{$LibVersion}}))
17110 { # validation of old-version dumps
17111 if(not $ExtendedCheck) {
17112 exitStatus("Invalid_Dump", "the input dump d$LibVersion is invalid");
17113 }
17114 }
17115 $Library_Symbol{$LibVersion} = $LibraryABI->{"Symbols"};
17116 if(not $Library_Symbol{$LibVersion})
17117 { # support for old dumps
17118 $Library_Symbol{$LibVersion} = $LibraryABI->{"Interfaces"};
17119 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040017120 if(checkDump($LibVersion, "2.15")) {
17121 $DepLibrary_Symbol{$LibVersion} = $LibraryABI->{"DepSymbols"};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017122 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040017123 else
17124 { # support for old ABI dumps
17125 my $DepSymbols = $LibraryABI->{"DepSymbols"};
17126 if(not $DepSymbols) {
17127 $DepSymbols = $LibraryABI->{"DepInterfaces"};
17128 }
17129 if(not $DepSymbols)
17130 { # Cannot reconstruct DepSymbols. This may result in false
17131 # positives if the old dump is for library 2. Not a problem if
17132 # old dumps are only from old libraries.
17133 $DepSymbols = {};
17134 }
17135 foreach my $Symbol (keys(%{$DepSymbols})) {
17136 $DepSymbol_Library{$LibVersion}{$Symbol} = 1;
17137 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017138 }
17139 $SymVer{$LibVersion} = $LibraryABI->{"SymbolVersion"};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017140 $Descriptor{$LibVersion}{"Version"} = $LibraryABI->{"LibraryVersion"};
17141 $SkipTypes{$LibVersion} = $LibraryABI->{"SkipTypes"};
17142 if(not $SkipTypes{$LibVersion})
17143 { # support for old dumps
17144 $SkipTypes{$LibVersion} = $LibraryABI->{"OpaqueTypes"};
17145 }
17146 $SkipSymbols{$LibVersion} = $LibraryABI->{"SkipSymbols"};
17147 if(not $SkipSymbols{$LibVersion})
17148 { # support for old dumps
17149 $SkipSymbols{$LibVersion} = $LibraryABI->{"SkipInterfaces"};
17150 }
17151 if(not $SkipSymbols{$LibVersion})
17152 { # support for old dumps
17153 $SkipSymbols{$LibVersion} = $LibraryABI->{"InternalInterfaces"};
17154 }
17155 $SkipNameSpaces{$LibVersion} = $LibraryABI->{"SkipNameSpaces"};
17156 $TargetHeaders{$LibVersion} = $LibraryABI->{"TargetHeaders"};
17157 foreach my $Path (keys(%{$LibraryABI->{"SkipHeaders"}}))
17158 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040017159 $SkipHeadersList{$LibVersion}{$Path} = $LibraryABI->{"SkipHeaders"}{$Path};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017160 my ($CPath, $Type) = classifyPath($Path);
17161 $SkipHeaders{$LibVersion}{$Type}{$CPath} = $LibraryABI->{"SkipHeaders"}{$Path};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017162 }
17163 read_Headers_DumpInfo($LibraryABI, $LibVersion);
17164 read_Libs_DumpInfo($LibraryABI, $LibVersion);
Andrey Ponomarenko5c09ef32012-06-14 18:17:33 +040017165 if(not checkDump($LibVersion, "2.10.1")
17166 or not $TargetHeaders{$LibVersion})
Andrey Ponomarenko85043792012-05-14 16:48:07 +040017167 { # support for old ABI dumps: added target headers
17168 foreach (keys(%{$Registered_Headers{$LibVersion}})) {
17169 $TargetHeaders{$LibVersion}{get_filename($_)}=1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017170 }
17171 }
17172 $Constants{$LibVersion} = $LibraryABI->{"Constants"};
17173 $NestedNameSpaces{$LibVersion} = $LibraryABI->{"NameSpaces"};
17174 if(not $NestedNameSpaces{$LibVersion})
17175 { # support for old dumps
17176 # Cannot reconstruct NameSpaces. This may affect design
17177 # of the compatibility report.
17178 $NestedNameSpaces{$LibVersion} = {};
17179 }
17180 # target system type
17181 # needed to adopt HTML report
17182 if(not $DumpSystem)
17183 { # to use in createSymbolsList(...)
17184 $OStarget = $LibraryABI->{"Target"};
17185 }
17186 # recreate environment
17187 foreach my $Lib_Name (keys(%{$Library_Symbol{$LibVersion}}))
17188 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040017189 foreach my $Symbol (keys(%{$Library_Symbol{$LibVersion}{$Lib_Name}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017190 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040017191 $Symbol_Library{$LibVersion}{$Symbol} = $Lib_Name;
17192 if($Library_Symbol{$LibVersion}{$Lib_Name}{$Symbol}<=-1)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017193 { # data marked as -size in the dump
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040017194 $GlobalDataObject{$LibVersion}{$Symbol}=1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017195 }
17196 if($COMMON_LANGUAGE{$LibVersion} ne "C++"
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040017197 and $Symbol=~/\A(_Z|\?)/) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017198 setLanguage($LibVersion, "C++");
17199 }
17200 }
17201 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040017202 foreach my $Lib_Name (keys(%{$DepLibrary_Symbol{$LibVersion}}))
17203 {
17204 foreach my $Symbol (keys(%{$DepLibrary_Symbol{$LibVersion}{$Lib_Name}})) {
17205 $DepSymbol_Library{$LibVersion}{$Symbol} = $Lib_Name;
17206 }
17207 }
17208
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017209 my @VFunc = ();
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040017210 foreach my $InfoId (keys(%{$SymbolInfo{$LibVersion}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017211 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040017212 my $MnglName = $SymbolInfo{$LibVersion}{$InfoId}{"MnglName"};
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040017213 if($MnglName)
17214 {
17215 if(not $Symbol_Library{$LibVersion}{$MnglName}
17216 and not $DepSymbol_Library{$LibVersion}{$MnglName}) {
17217 push(@VFunc, $MnglName);
17218 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017219 }
17220 }
17221 translateSymbols(@VFunc, $LibVersion);
17222 translateSymbols(keys(%{$Symbol_Library{$LibVersion}}), $LibVersion);
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040017223 translateSymbols(keys(%{$DepSymbol_Library{$LibVersion}}), $LibVersion);
17224
17225 foreach my $TypeId (sort {int($a)<=>int($b)} keys(%{$TypeInfo{$LibVersion}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017226 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040017227 if(defined $TypeInfo{$LibVersion}{$TypeId}{"BaseClass"})
17228 { # support for old ABI dumps < 2.0 (ACC 1.22)
17229 foreach my $BId (keys(%{$TypeInfo{$LibVersion}{$TypeId}{"BaseClass"}}))
17230 {
17231 if(my $Access = $TypeInfo{$LibVersion}{$TypeId}{"BaseClass"}{$BId})
17232 {
17233 if($Access ne "public") {
17234 $TypeInfo{$LibVersion}{$TypeId}{"Base"}{$BId}{"access"} = $Access;
17235 }
17236 }
17237 $TypeInfo{$LibVersion}{$TypeId}{"Base"}{$BId} = {};
17238 }
17239 delete($TypeInfo{$LibVersion}{$TypeId}{"BaseClass"});
17240 }
17241 my %TInfo = %{$TypeInfo{$LibVersion}{$TypeId}};
17242 if(defined $TInfo{"Base"})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017243 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040017244 foreach (keys(%{$TInfo{"Base"}})) {
17245 $Class_SubClasses{$LibVersion}{$_}{$TypeId}=1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017246 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040017247 }
17248 if($TInfo{"Type"} eq "Typedef" and defined $TInfo{"BaseType"})
17249 {
17250 if(my $BTid = $TInfo{"BaseType"}{"Tid"})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017251 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040017252 my $BName = $TypeInfo{$LibVersion}{$BTid}{"Name"};
17253 if(not $BName)
17254 { # broken type
17255 next;
17256 }
17257 if($TInfo{"Name"} eq $BName)
17258 { # typedef to "class Class"
17259 # should not be registered in TName_Tid
17260 next;
17261 }
17262 if(not $Typedef_BaseName{$LibVersion}{$TInfo{"Name"}}) {
17263 $Typedef_BaseName{$LibVersion}{$TInfo{"Name"}} = $BName;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017264 }
17265 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040017266 }
17267 if(not $TName_Tid{$LibVersion}{$TInfo{"Name"}})
17268 { # classes: class (id1), typedef (artificial, id2 > id1)
17269 $TName_Tid{$LibVersion}{$TInfo{"Name"}} = $TypeId;
17270 }
17271 }
17272
17273 if(not checkDump($LibVersion, "2.15"))
17274 { # support for old ABI dumps
17275 my %Dups = ();
17276 foreach my $InfoId (keys(%{$SymbolInfo{$LibVersion}}))
17277 {
17278 if(my $ClassId = $SymbolInfo{$LibVersion}{$InfoId}{"Class"})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017279 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040017280 if(not defined $TypeInfo{$LibVersion}{$ClassId})
17281 { # remove template decls
17282 delete($SymbolInfo{$LibVersion}{$InfoId});
17283 next;
Andrey Ponomarenko16934472012-03-29 15:37:04 +040017284 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017285 }
Andrey Ponomarenkob8d203d2012-05-25 18:11:07 +040017286 my $MName = $SymbolInfo{$LibVersion}{$InfoId}{"MnglName"};
17287 if(not $MName and $SymbolInfo{$LibVersion}{$InfoId}{"Class"})
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040017288 { # templates
17289 delete($SymbolInfo{$LibVersion}{$InfoId});
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017290 }
17291 }
17292 }
17293
17294 $Descriptor{$LibVersion}{"Dump"} = 1;
17295}
17296
17297sub read_Machine_DumpInfo($$)
17298{
17299 my ($LibraryABI, $LibVersion) = @_;
17300 if($LibraryABI->{"Arch"}) {
17301 $CPU_ARCH{$LibVersion} = $LibraryABI->{"Arch"};
17302 }
17303 if($LibraryABI->{"WordSize"}) {
17304 $WORD_SIZE{$LibVersion} = $LibraryABI->{"WordSize"};
17305 }
17306 else
17307 { # support for old dumps
17308 $WORD_SIZE{$LibVersion} = $LibraryABI->{"SizeOfPointer"};
17309 }
17310 if(not $WORD_SIZE{$LibVersion})
17311 { # support for old dumps (<1.23)
17312 if(my $Tid = getTypeIdByName("char*", $LibVersion))
17313 { # size of char*
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040017314 $WORD_SIZE{$LibVersion} = $TypeInfo{$LibVersion}{$Tid}{"Size"};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017315 }
17316 else
17317 {
17318 my $PSize = 0;
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040017319 foreach my $Tid (keys(%{$TypeInfo{$LibVersion}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017320 {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040017321 if($TypeInfo{$LibVersion}{$Tid}{"Type"} eq "Pointer")
17322 { # any "pointer"-type
17323 $PSize = $TypeInfo{$LibVersion}{$Tid}{"Size"};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017324 last;
17325 }
17326 }
17327 if($PSize)
17328 { # a pointer type size
17329 $WORD_SIZE{$LibVersion} = $PSize;
17330 }
17331 else {
17332 printMsg("WARNING", "cannot identify a WORD size in the ABI dump (too old format)");
17333 }
17334 }
17335 }
17336 if($LibraryABI->{"GccVersion"}) {
17337 $GCC_VERSION{$LibVersion} = $LibraryABI->{"GccVersion"};
17338 }
17339}
17340
17341sub read_Libs_DumpInfo($$)
17342{
17343 my ($LibraryABI, $LibVersion) = @_;
17344 if(keys(%{$Library_Symbol{$LibVersion}})
17345 and not $DumpAPI) {
17346 $Descriptor{$LibVersion}{"Libs"} = "OK";
17347 }
17348}
17349
17350sub read_Headers_DumpInfo($$)
17351{
17352 my ($LibraryABI, $LibVersion) = @_;
17353 if(keys(%{$LibraryABI->{"Headers"}})
17354 and not $DumpAPI) {
17355 $Descriptor{$LibVersion}{"Headers"} = "OK";
17356 }
17357 foreach my $Identity (keys(%{$LibraryABI->{"Headers"}}))
17358 { # headers info is stored in the old dumps in the different way
17359 if($UseOldDumps
17360 and my $Name = $LibraryABI->{"Headers"}{$Identity}{"Name"})
17361 { # support for old dumps: headers info corrected in 1.22
17362 $Identity = $Name;
17363 }
17364 $Registered_Headers{$LibVersion}{$Identity}{"Identity"} = $Identity;
17365 }
17366}
17367
17368sub find_libs($$$)
17369{
17370 my ($Path, $Type, $MaxDepth) = @_;
17371 # FIXME: correct the search pattern
17372 return cmd_find($Path, $Type, ".*\\.$LIB_EXT\[0-9.]*", $MaxDepth);
17373}
17374
17375sub createDescriptor($$)
17376{
17377 my ($LibVersion, $Path) = @_;
17378 if(not $LibVersion or not $Path
17379 or not -e $Path) {
17380 return "";
17381 }
17382 if(-d $Path)
17383 { # directory with headers files and shared objects
17384 return "
17385 <version>
17386 ".$TargetVersion{$LibVersion}."
17387 </version>
17388
17389 <headers>
17390 $Path
17391 </headers>
17392
17393 <libs>
17394 $Path
17395 </libs>";
17396 }
17397 else
17398 { # files
17399 if($Path=~/\.xml\Z/i)
17400 { # standard XML-descriptor
17401 return readFile($Path);
17402 }
17403 elsif(is_header($Path, 2, $LibVersion))
17404 { # header file
17405 return "
17406 <version>
17407 ".$TargetVersion{$LibVersion}."
17408 </version>
17409
17410 <headers>
17411 $Path
17412 </headers>
17413
17414 <libs>
17415 none
17416 </libs>";
17417 }
17418 elsif(parse_libname($Path, "name", $OStarget))
17419 { # shared object
17420 return "
17421 <version>
17422 ".$TargetVersion{$LibVersion}."
17423 </version>
17424
17425 <headers>
17426 none
17427 </headers>
17428
17429 <libs>
17430 $Path
17431 </libs>";
17432 }
17433 else
17434 { # standard XML-descriptor
17435 return readFile($Path);
17436 }
17437 }
17438}
17439
17440sub detect_lib_default_paths()
17441{
17442 my %LPaths = ();
17443 if($OSgroup eq "bsd")
17444 {
Andrey Ponomarenkoa01311b2012-06-08 17:20:02 +040017445 if(my $LdConfig = get_CmdPath("ldconfig"))
17446 {
17447 foreach my $Line (split(/\n/, `$LdConfig -r 2>\"$TMP_DIR/null\"`))
17448 {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017449 if($Line=~/\A[ \t]*\d+:\-l(.+) \=\> (.+)\Z/) {
17450 $LPaths{"lib".$1} = $2;
17451 }
17452 }
17453 }
17454 else {
17455 printMsg("WARNING", "can't find ldconfig");
17456 }
17457 }
17458 else
17459 {
17460 if(my $LdConfig = get_CmdPath("ldconfig"))
17461 {
17462 if($SystemRoot and $OSgroup eq "linux")
17463 { # use host (x86) ldconfig with the target (arm) ld.so.conf
17464 if(-e $SystemRoot."/etc/ld.so.conf") {
17465 $LdConfig .= " -f ".$SystemRoot."/etc/ld.so.conf";
17466 }
17467 }
Andrey Ponomarenkoa01311b2012-06-08 17:20:02 +040017468 foreach my $Line (split(/\n/, `$LdConfig -p 2>\"$TMP_DIR/null\"`))
17469 {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017470 if($Line=~/\A[ \t]*([^ \t]+) .* \=\> (.+)\Z/)
17471 {
17472 my ($Name, $Path) = ($1, $2);
17473 $Path=~s/[\/]{2,}/\//;
17474 $LPaths{$Name} = $Path;
17475 }
17476 }
17477 }
17478 elsif($OSgroup=~/linux/i) {
17479 printMsg("WARNING", "can't find ldconfig");
17480 }
17481 }
17482 return \%LPaths;
17483}
17484
17485sub detect_bin_default_paths()
17486{
17487 my $EnvPaths = $ENV{"PATH"};
17488 if($OSgroup eq "beos") {
17489 $EnvPaths.=":".$ENV{"BETOOLS"};
17490 }
17491 my $Sep = ($OSgroup eq "windows")?";":":|;";
17492 foreach my $Path (sort {length($a)<=>length($b)} split(/$Sep/, $EnvPaths))
17493 {
17494 $Path = path_format($Path, $OSgroup);
17495 $Path=~s/[\/\\]+\Z//g;
17496 next if(not $Path);
17497 if($SystemRoot
17498 and $Path=~/\A\Q$SystemRoot\E\//)
17499 { # do NOT use binaries from target system
17500 next;
17501 }
17502 $DefaultBinPaths{$Path} = 1;
17503 }
17504}
17505
17506sub detect_inc_default_paths()
17507{
17508 return () if(not $GCC_PATH);
17509 my %DPaths = ("Cpp"=>{},"Gcc"=>{},"Inc"=>{});
17510 writeFile("$TMP_DIR/empty.h", "");
Andrey Ponomarenkoa01311b2012-06-08 17:20:02 +040017511 foreach my $Line (split(/\n/, `$GCC_PATH -v -x c++ -E \"$TMP_DIR/empty.h\" 2>&1`))
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040017512 { # detecting GCC default include paths
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017513 if($Line=~/\A[ \t]*((\/|\w+:\\).+)[ \t]*\Z/)
17514 {
17515 my $Path = simplify_path($1);
17516 $Path=~s/[\/\\]+\Z//g;
17517 $Path = path_format($Path, $OSgroup);
17518 if($Path=~/c\+\+|\/g\+\+\//)
17519 {
17520 $DPaths{"Cpp"}{$Path}=1;
17521 if(not defined $MAIN_CPP_DIR
17522 or get_depth($MAIN_CPP_DIR)>get_depth($Path)) {
17523 $MAIN_CPP_DIR = $Path;
17524 }
17525 }
17526 elsif($Path=~/gcc/) {
17527 $DPaths{"Gcc"}{$Path}=1;
17528 }
17529 else
17530 {
17531 next if($Path=~/local[\/\\]+include/);
17532 if($SystemRoot
17533 and $Path!~/\A\Q$SystemRoot\E(\/|\Z)/)
17534 { # The GCC include path for user headers is not a part of the system root
17535 # The reason: you are not specified the --cross-gcc option or selected a wrong compiler
17536 # or it is the internal cross-GCC path like arm-linux-gnueabi/include
17537 next;
17538 }
17539 $DPaths{"Inc"}{$Path}=1;
17540 }
17541 }
17542 }
17543 unlink("$TMP_DIR/empty.h");
17544 return %DPaths;
17545}
17546
17547sub detect_default_paths($)
17548{
17549 my ($HSearch, $LSearch, $BSearch, $GSearch) = (1, 1, 1, 1);
17550 my $Search = $_[0];
17551 if($Search!~/inc/) {
17552 $HSearch = 0;
17553 }
17554 if($Search!~/lib/) {
17555 $LSearch = 0;
17556 }
17557 if($Search!~/bin/) {
17558 $BSearch = 0;
17559 }
17560 if($Search!~/gcc/) {
17561 $GSearch = 0;
17562 }
17563 if(keys(%{$SystemPaths{"include"}}))
17564 { # <search_headers> section of the XML descriptor
17565 # do NOT search for systems headers
17566 $HSearch = 0;
17567 }
17568 if(keys(%{$SystemPaths{"lib"}}))
17569 { # <search_headers> section of the XML descriptor
17570 # do NOT search for systems headers
17571 $LSearch = 0;
17572 }
17573 foreach my $Type (keys(%{$OS_AddPath{$OSgroup}}))
17574 { # additional search paths
17575 next if($Type eq "include" and not $HSearch);
17576 next if($Type eq "lib" and not $LSearch);
17577 next if($Type eq "bin" and not $BSearch);
17578 foreach my $Path (keys(%{$OS_AddPath{$OSgroup}{$Type}}))
17579 {
17580 next if(not -d $Path);
17581 $SystemPaths{$Type}{$Path} = $OS_AddPath{$OSgroup}{$Type}{$Path};
17582 }
17583 }
17584 if($OSgroup ne "windows")
17585 { # unix-like
17586 foreach my $Type ("include", "lib", "bin")
17587 { # automatic detection of system "devel" directories
17588 next if($Type eq "include" and not $HSearch);
17589 next if($Type eq "lib" and not $LSearch);
17590 next if($Type eq "bin" and not $BSearch);
17591 my ($UsrDir, $RootDir) = ("/usr", "/");
17592 if($SystemRoot and $Type ne "bin")
17593 { # 1. search for target headers and libraries
17594 # 2. use host commands: ldconfig, readelf, etc.
17595 ($UsrDir, $RootDir) = ("$SystemRoot/usr", $SystemRoot);
17596 }
17597 foreach my $Path (cmd_find($RootDir,"d","*$Type*",1)) {
17598 $SystemPaths{$Type}{$Path} = 1;
17599 }
17600 if(-d $RootDir."/".$Type)
17601 { # if "/lib" is symbolic link
17602 if($RootDir eq "/") {
17603 $SystemPaths{$Type}{"/".$Type} = 1;
17604 }
17605 else {
17606 $SystemPaths{$Type}{$RootDir."/".$Type} = 1;
17607 }
17608 }
17609 if(-d $UsrDir) {
17610 foreach my $Path (cmd_find($UsrDir,"d","*$Type*",1)) {
17611 $SystemPaths{$Type}{$Path} = 1;
17612 }
17613 if(-d $UsrDir."/".$Type)
17614 { # if "/usr/lib" is symbolic link
17615 $SystemPaths{$Type}{$UsrDir."/".$Type} = 1;
17616 }
17617 }
17618 }
17619 }
17620 if($BSearch)
17621 {
17622 detect_bin_default_paths();
17623 foreach my $Path (keys(%DefaultBinPaths)) {
17624 $SystemPaths{"bin"}{$Path} = $DefaultBinPaths{$Path};
17625 }
17626 }
17627 # check environment variables
17628 if($OSgroup eq "beos")
17629 {
17630 foreach (keys(%{$SystemPaths{"bin"}}))
17631 {
17632 if($_ eq ".") {
17633 next;
17634 }
17635 foreach my $Path (cmd_find($_, "d", "bin", ""))
17636 { # search for /boot/develop/abi/x86/gcc4/tools/gcc-4.4.4-haiku-101111/bin/
17637 $SystemPaths{"bin"}{$Path} = 1;
17638 }
17639 }
17640 if($HSearch)
17641 {
17642 foreach my $Path (split(/:|;/, $ENV{"BEINCLUDES"}))
17643 {
17644 if(is_abs($Path)) {
17645 $DefaultIncPaths{$Path} = 1;
17646 }
17647 }
17648 }
17649 if($LSearch)
17650 {
17651 foreach my $Path (split(/:|;/, $ENV{"BELIBRARIES"}), split(/:|;/, $ENV{"LIBRARY_PATH"}))
17652 {
17653 if(is_abs($Path)) {
17654 $DefaultLibPaths{$Path} = 1;
17655 }
17656 }
17657 }
17658 }
17659 if($LSearch)
17660 { # using linker to get system paths
17661 if(my $LPaths = detect_lib_default_paths())
17662 { # unix-like
17663 foreach my $Name (keys(%{$LPaths}))
17664 {
17665 if($SystemRoot
17666 and $LPaths->{$Name}!~/\A\Q$SystemRoot\E\//)
17667 { # wrong ldconfig configuration
17668 # check your <sysroot>/etc/ld.so.conf
17669 next;
17670 }
17671 $DyLib_DefaultPath{$Name} = $LPaths->{$Name};
17672 $DefaultLibPaths{get_dirname($LPaths->{$Name})} = 1;
17673 }
17674 }
17675 foreach my $Path (keys(%DefaultLibPaths)) {
17676 $SystemPaths{"lib"}{$Path} = $DefaultLibPaths{$Path};
17677 }
17678 }
17679 if($BSearch)
17680 {
17681 if($CrossGcc)
17682 { # --cross-gcc=arm-linux-gcc
17683 if(-e $CrossGcc)
17684 { # absolute or relative path
17685 $GCC_PATH = get_abs_path($CrossGcc);
17686 }
17687 elsif($CrossGcc!~/\// and get_CmdPath($CrossGcc))
17688 { # command name
17689 $GCC_PATH = $CrossGcc;
17690 }
17691 else {
17692 exitStatus("Access_Error", "can't access \'$CrossGcc\'");
17693 }
17694 if($GCC_PATH=~/\s/) {
17695 $GCC_PATH = "\"".$GCC_PATH."\"";
17696 }
17697 }
17698 }
17699 if($GSearch)
17700 { # GCC path and default include dirs
17701 if(not $CrossGcc) {
17702 $GCC_PATH = get_CmdPath("gcc");
17703 }
17704 if(not $GCC_PATH) {
17705 exitStatus("Not_Found", "can't find GCC>=3.0 in PATH");
17706 }
17707 if(not $CheckObjectsOnly_Opt)
17708 {
17709 if(my $GCC_Ver = get_dumpversion($GCC_PATH))
17710 {
17711 my $GccTarget = get_dumpmachine($GCC_PATH);
17712 printMsg("INFO", "Using GCC $GCC_Ver ($GccTarget)");
17713 if($GccTarget=~/symbian/)
17714 {
17715 $OStarget = "symbian";
17716 $LIB_EXT = $OS_LibExt{$LIB_TYPE}{$OStarget};
17717 }
17718 }
17719 else {
17720 exitStatus("Error", "something is going wrong with the GCC compiler");
17721 }
17722 }
17723 if(not $NoStdInc)
17724 { # do NOT search in GCC standard paths
17725 my %DPaths = detect_inc_default_paths();
17726 %DefaultCppPaths = %{$DPaths{"Cpp"}};
17727 %DefaultGccPaths = %{$DPaths{"Gcc"}};
17728 %DefaultIncPaths = %{$DPaths{"Inc"}};
17729 foreach my $Path (keys(%DefaultIncPaths)) {
17730 $SystemPaths{"include"}{$Path} = $DefaultIncPaths{$Path};
17731 }
17732 }
17733 }
17734 if($HSearch)
17735 { # user include paths
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040017736 my $IncPath = "/usr/include";
17737 if($SystemRoot) {
17738 $IncPath = $SystemRoot.$IncPath;
17739 }
17740 if(-d $IncPath) {
17741 $UserIncPath{$IncPath}=1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017742 }
17743 }
17744}
17745
17746sub getLIB_EXT($)
17747{
17748 my $Target = $_[0];
17749 if(my $Ext = $OS_LibExt{$LIB_TYPE}{$Target}) {
17750 return $Ext;
17751 }
17752 return $OS_LibExt{$LIB_TYPE}{"default"};
17753}
17754
17755sub getAR_EXT($)
17756{
17757 my $Target = $_[0];
17758 if(my $Ext = $OS_Archive{$Target}) {
17759 return $Ext;
17760 }
17761 return $OS_Archive{"default"};
17762}
17763
17764sub get_dumpversion($)
17765{
17766 my $Cmd = $_[0];
17767 return "" if(not $Cmd);
17768 if($Cache{"get_dumpversion"}{$Cmd}) {
17769 return $Cache{"get_dumpversion"}{$Cmd};
17770 }
Andrey Ponomarenkoa01311b2012-06-08 17:20:02 +040017771 my $V = `$Cmd -dumpversion 2>\"$TMP_DIR/null\"`;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017772 chomp($V);
17773 return ($Cache{"get_dumpversion"}{$Cmd} = $V);
17774}
17775
17776sub get_dumpmachine($)
17777{
17778 my $Cmd = $_[0];
17779 return "" if(not $Cmd);
17780 if($Cache{"get_dumpmachine"}{$Cmd}) {
17781 return $Cache{"get_dumpmachine"}{$Cmd};
17782 }
Andrey Ponomarenkoa01311b2012-06-08 17:20:02 +040017783 my $Machine = `$Cmd -dumpmachine 2>\"$TMP_DIR/null\"`;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017784 chomp($Machine);
17785 return ($Cache{"get_dumpmachine"}{$Cmd} = $Machine);
17786}
17787
17788sub check_command($)
17789{
17790 my $Cmd = $_[0];
17791 return "" if(not $Cmd);
17792 my @Options = (
17793 "--version",
17794 "-help"
17795 );
17796 foreach my $Opt (@Options)
17797 {
Andrey Ponomarenkoa01311b2012-06-08 17:20:02 +040017798 my $Info = `$Cmd $Opt 2>\"$TMP_DIR/null\"`;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017799 if($Info) {
17800 return 1;
17801 }
17802 }
17803 return 0;
17804}
17805
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040017806sub check_gcc($$)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017807{
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040017808 my ($Cmd, $ReqVer) = @_;
17809 return 0 if(not $Cmd or not $ReqVer);
17810 if(defined $Cache{"check_gcc"}{$Cmd}{$ReqVer}) {
17811 return $Cache{"check_gcc"}{$Cmd}{$ReqVer};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017812 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040017813 if(my $GccVer = get_dumpversion($Cmd))
17814 {
17815 $GccVer=~s/(-|_)[a-z_]+.*\Z//; # remove suffix (like "-haiku-100818")
17816 if(cmpVersions($GccVer, $ReqVer)>=0) {
17817 return ($Cache{"check_gcc"}{$Cmd}{$ReqVer} = $Cmd);
17818 }
17819 }
17820 return ($Cache{"check_gcc"}{$Cmd}{$ReqVer} = "");
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017821}
17822
17823sub get_depth($)
17824{
17825 if(defined $Cache{"get_depth"}{$_[0]}) {
17826 return $Cache{"get_depth"}{$_[0]}
17827 }
17828 return ($Cache{"get_depth"}{$_[0]} = ($_[0]=~tr![\/\\]|\:\:!!));
17829}
17830
17831sub find_gcc_cxx_headers($)
17832{
17833 my $LibVersion = $_[0];
17834 return if($Cache{"find_gcc_cxx_headers"});# this function should be called once
17835 # detecting system header paths
17836 foreach my $Path (sort {get_depth($b) <=> get_depth($a)} keys(%DefaultGccPaths))
17837 {
17838 foreach my $HeaderPath (sort {get_depth($a) <=> get_depth($b)} cmd_find($Path,"f","",""))
17839 {
17840 my $FileName = get_filename($HeaderPath);
17841 next if($DefaultGccHeader{$FileName});
17842 $DefaultGccHeader{$FileName} = $HeaderPath;
17843 }
17844 }
17845 if($COMMON_LANGUAGE{$LibVersion} eq "C++" and not $STDCXX_TESTING)
17846 {
17847 foreach my $CppDir (sort {get_depth($b)<=>get_depth($a)} keys(%DefaultCppPaths))
17848 {
17849 my @AllCppHeaders = cmd_find($CppDir,"f","","");
17850 foreach my $Path (sort {get_depth($a)<=>get_depth($b)} @AllCppHeaders)
17851 {
17852 my $FileName = get_filename($Path);
17853 next if($DefaultCppHeader{$FileName});
17854 $DefaultCppHeader{$FileName} = $Path;
17855 }
17856 }
17857 }
17858 $Cache{"find_gcc_cxx_headers"} = 1;
17859}
17860
17861sub parse_libname($$$)
17862{
17863 my ($Name, $Type, $Target) = @_;
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040017864 if(not $Name) {
17865 return "";
17866 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017867 if($Target eq "symbian") {
17868 return parse_libname_symbian($Name, $Type);
17869 }
17870 elsif($Target eq "windows") {
17871 return parse_libname_windows($Name, $Type);
17872 }
17873 my $Ext = getLIB_EXT($Target);
Andrey Ponomarenkoa01311b2012-06-08 17:20:02 +040017874 if($Name=~/((((lib|).+?)([\-\_][\d\-\.\_]+.*?|))\.$Ext)(\.(.+)|)\Z/)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017875 { # libSDL-1.2.so.0.7.1
17876 # libwbxml2.so.0.0.18
Andrey Ponomarenkoa01311b2012-06-08 17:20:02 +040017877 # libopcodes-2.21.53-system.20110810.so
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017878 if($Type eq "name")
17879 { # libSDL-1.2
17880 # libwbxml2
17881 return $2;
17882 }
17883 elsif($Type eq "name+ext")
17884 { # libSDL-1.2.so
17885 # libwbxml2.so
17886 return $1;
17887 }
17888 elsif($Type eq "version")
17889 {
Andrey Ponomarenkoa01311b2012-06-08 17:20:02 +040017890 if(defined $7
17891 and $7 ne "")
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017892 { # 0.7.1
17893 return $7;
17894 }
17895 else
17896 { # libc-2.5.so (=>2.5 version)
17897 my $MV = $5;
17898 $MV=~s/\A[\-\_]+//g;
17899 return $MV;
17900 }
17901 }
17902 elsif($Type eq "short")
17903 { # libSDL
17904 # libwbxml2
17905 return $3;
17906 }
17907 elsif($Type eq "shortest")
17908 { # SDL
17909 # wbxml
17910 return shortest_name($3);
17911 }
17912 }
17913 return "";# error
17914}
17915
17916sub parse_libname_symbian($$)
17917{
17918 my ($Name, $Type) = @_;
17919 my $Ext = getLIB_EXT("symbian");
17920 if($Name=~/(((.+?)(\{.+\}|))\.$Ext)\Z/)
17921 { # libpthread{00010001}.dso
17922 if($Type eq "name")
17923 { # libpthread{00010001}
17924 return $2;
17925 }
17926 elsif($Type eq "name+ext")
17927 { # libpthread{00010001}.dso
17928 return $1;
17929 }
17930 elsif($Type eq "version")
17931 { # 00010001
17932 my $V = $4;
17933 $V=~s/\{(.+)\}/$1/;
17934 return $V;
17935 }
17936 elsif($Type eq "short")
17937 { # libpthread
17938 return $3;
17939 }
17940 elsif($Type eq "shortest")
17941 { # pthread
17942 return shortest_name($3);
17943 }
17944 }
17945 return "";# error
17946}
17947
17948sub parse_libname_windows($$)
17949{
17950 my ($Name, $Type) = @_;
17951 my $Ext = getLIB_EXT("windows");
17952 if($Name=~/((.+?)\.$Ext)\Z/)
17953 { # netapi32.dll
17954 if($Type eq "name")
17955 { # netapi32
17956 return $2;
17957 }
17958 elsif($Type eq "name+ext")
17959 { # netapi32.dll
17960 return $1;
17961 }
17962 elsif($Type eq "version")
17963 { # DLL version embedded
17964 # at binary-level
17965 return "";
17966 }
17967 elsif($Type eq "short")
17968 { # netapi32
17969 return $2;
17970 }
17971 elsif($Type eq "shortest")
17972 { # netapi
17973 return shortest_name($2);
17974 }
17975 }
17976 return "";# error
17977}
17978
17979sub shortest_name($)
17980{
17981 my $Name = $_[0];
17982 # remove prefix
17983 $Name=~s/\A(lib|open)//;
17984 # remove suffix
17985 $Name=~s/[\W\d_]+\Z//i;
17986 $Name=~s/([a-z]{2,})(lib)\Z/$1/i;
17987 return $Name;
17988}
17989
17990sub getPrefix($)
17991{
17992 my $Str = $_[0];
17993 if($Str=~/\A(Get|get|Set|set)([A-Z]|_)/)
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040017994 { # GetError
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017995 return "";
17996 }
17997 if($Str=~/\A([_]*[A-Z][a-z]{1,5})[A-Z]/)
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040017998 { # XmuValidArea: Xmu
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017999 return $1;
18000 }
18001 elsif($Str=~/\A([_]*[a-z]+)[A-Z]/)
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040018002 { # snfReadFont: snf
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040018003 return $1;
18004 }
18005 elsif($Str=~/\A([_]*[A-Z]{2,})[A-Z][a-z]+([A-Z][a-z]+|\Z)/)
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040018006 { # XRRTimes: XRR
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040018007 return $1;
18008 }
18009 elsif($Str=~/\A([_]*[a-z0-9]{2,}_)[a-z]+/i)
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040018010 { # alarm_event_add: alarm_
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040018011 return $1;
18012 }
18013 elsif($Str=~/\A(([a-z])\2{1,})/i)
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040018014 { # ffopen
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040018015 return $1;
18016 }
18017 else {
18018 return "";
18019 }
18020}
18021
18022sub problem_title($)
18023{
18024 if($_[0]==1) {
18025 return "1 problem";
18026 }
18027 else {
18028 return $_[0]." problems";
18029 }
18030}
18031
18032sub warning_title($)
18033{
18034 if($_[0]==1) {
18035 return "1 warning";
18036 }
18037 else {
18038 return $_[0]." warnings";
18039 }
18040}
18041
18042sub createSymbolsList($$$$$)
18043{
18044 my ($DPath, $SaveTo, $LName, $LVersion, $ArchName) = @_;
18045 read_ABI_Dump(1, $DPath);
18046 if(not $CheckObjectsOnly) {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040018047 prepareSymbols(1);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040018048 }
18049 my %SymbolHeaderLib = ();
18050 my $Total = 0;
18051 # Get List
18052 foreach my $Symbol (sort keys(%{$CompleteSignature{1}}))
18053 {
18054 if(not link_symbol($Symbol, 1, "-Deps"))
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040018055 { # skip src only and all external functions
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040018056 next;
18057 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040018058 if(not symbolFilter($Symbol, 1, "Public", "Binary"))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040018059 { # skip other symbols
18060 next;
18061 }
18062 my $HeaderName = $CompleteSignature{1}{$Symbol}{"Header"};
18063 if(not $HeaderName)
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040018064 { # skip src only and all external functions
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040018065 next;
18066 }
18067 my $DyLib = $Symbol_Library{1}{$Symbol};
18068 if(not $DyLib)
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040018069 { # skip src only and all external functions
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040018070 next;
18071 }
18072 $SymbolHeaderLib{$HeaderName}{$DyLib}{$Symbol} = 1;
18073 $Total+=1;
18074 }
18075 # Draw List
18076 my $SYMBOLS_LIST = "<h1>Public symbols in <span style='color:Blue;'>$LName</span> (<span style='color:Red;'>$LVersion</span>)";
18077 $SYMBOLS_LIST .= " on <span style='color:Blue;'>".showArch($ArchName)."</span><br/>Total: $Total</h1><br/>";
18078 foreach my $HeaderName (sort {lc($a) cmp lc($b)} keys(%SymbolHeaderLib))
18079 {
18080 foreach my $DyLib (sort {lc($a) cmp lc($b)} keys(%{$SymbolHeaderLib{$HeaderName}}))
18081 {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040018082 my %NS_Symbol = ();
18083 foreach my $Symbol (keys(%{$SymbolHeaderLib{$HeaderName}{$DyLib}})) {
18084 $NS_Symbol{get_IntNameSpace($Symbol, 1)}{$Symbol} = 1;
18085 }
18086 foreach my $NameSpace (sort keys(%NS_Symbol))
18087 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040018088 $SYMBOLS_LIST .= getTitle($HeaderName, $DyLib, $NameSpace);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040018089 my @SortedInterfaces = sort {lc(get_Signature($a, 1)) cmp lc(get_Signature($b, 1))} keys(%{$NS_Symbol{$NameSpace}});
18090 foreach my $Symbol (@SortedInterfaces)
18091 {
18092 my $SubReport = "";
18093 my $Signature = get_Signature($Symbol, 1);
18094 if($NameSpace) {
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040018095 $Signature=~s/\b\Q$NameSpace\E::\b//g;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040018096 }
18097 if($Symbol=~/\A(_Z|\?)/)
18098 {
18099 if($Signature) {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040018100 $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 +040018101 }# report_added
18102 else {
18103 $SubReport = "<span class='iname'>".$Symbol."</span><br/>\n";
18104 }
18105 }
18106 else
18107 {
18108 if($Signature) {
18109 $SubReport = "<span class='iname'>".highLight_Signature_Italic_Color($Signature)."</span><br/>\n";
18110 }
18111 else {
18112 $SubReport = "<span class='iname'>".$Symbol."</span><br/>\n";
18113 }
18114 }
18115 $SYMBOLS_LIST .= $SubReport;
18116 }
18117 }
18118 $SYMBOLS_LIST .= "<br/>\n";
18119 }
18120 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040018121 # clear info
18122 (%TypeInfo, %SymbolInfo, %Library_Symbol, %DepSymbol_Library,
18123 %DepLibrary_Symbol, %SymVer, %SkipTypes, %SkipSymbols,
18124 %NestedNameSpaces, %ClassMethods, %AllocableClass, %ClassNames,
18125 %CompleteSignature, %SkipNameSpaces, %Symbol_Library, %Library_Symbol) = ();
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040018126 ($Content_Counter, $ContentID) = (0, 0);
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040018127 # print report
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040018128 my $CssStyles = readModule("Styles", "SymbolsList.css");
18129 my $JScripts = readModule("Scripts", "Sections.js");
18130 $SYMBOLS_LIST = "<a name='Top'></a>".$SYMBOLS_LIST.$TOP_REF."<br/>\n";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040018131 my $Title = "$LName: public symbols";
18132 my $Keywords = "$LName, API, symbols";
18133 my $Description = "List of symbols in $LName ($LVersion) on ".showArch($ArchName);
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040018134 $SYMBOLS_LIST = composeHTML_Head($Title, $Keywords, $Description, $CssStyles, $JScripts)."
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040018135 <body><div>\n$SYMBOLS_LIST</div>
18136 <br/><br/><hr/>\n".getReportFooter($LName)."
18137 <div style='height:999px;'></div></body></html>";
18138 writeFile($SaveTo, $SYMBOLS_LIST);
18139}
18140
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040018141sub readModule($$)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040018142{
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040018143 my ($Module, $Name) = @_;
18144 my $Path = $MODULES_DIR."/Internals/$Module/".$Name;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040018145 if(not -f $Path) {
18146 exitStatus("Module_Error", "can't access \'$Path\'");
18147 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040018148 return readFile($Path);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040018149}
18150
18151sub is_target_lib($)
18152{
18153 my $LName = $_[0];
Andrey Ponomarenkoa01311b2012-06-08 17:20:02 +040018154 if(not $LName) {
18155 return 0;
18156 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040018157 if($TargetLibraryName
18158 and $LName!~/\Q$TargetLibraryName\E/) {
18159 return 0;
18160 }
18161 if(keys(%TargetLibs)
18162 and not $TargetLibs{$LName}
18163 and not $TargetLibs{parse_libname($LName, "name+ext", $OStarget)}) {
18164 return 0;
18165 }
18166 return 1;
18167}
18168
Andrey Ponomarenko85043792012-05-14 16:48:07 +040018169sub is_target_header($$)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040018170{ # --header, --headers-list
Andrey Ponomarenko85043792012-05-14 16:48:07 +040018171 my ($H, $V) = @_;
18172 if(keys(%{$TargetHeaders{$V}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040018173 {
Andrey Ponomarenko85043792012-05-14 16:48:07 +040018174 if($TargetHeaders{$V}{$H}) {
18175 return 1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040018176 }
18177 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +040018178 return 0;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040018179}
18180
18181sub checkVersionNum($$)
18182{
18183 my ($LibVersion, $Path) = @_;
18184 if(my $VerNum = $TargetVersion{$LibVersion}) {
18185 return $VerNum;
18186 }
18187 my $UsedAltDescr = 0;
18188 foreach my $Part (split(/\s*,\s*/, $Path))
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040018189 { # try to get version string from file path
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040018190 next if($Part=~/\.xml\Z/i);
18191 next if(isDump($Part));
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040018192 my $VerNum = "";
18193 if(parse_libname($Part, "name", $OStarget))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040018194 {
18195 $UsedAltDescr = 1;
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040018196 $VerNum = parse_libname($Part, "version", $OStarget);
18197 if(not $VerNum) {
18198 $VerNum = readStringVersion($Part);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040018199 }
18200 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040018201 elsif(is_header($Part, 2, $LibVersion) or -d $Part)
18202 {
18203 $UsedAltDescr = 1;
18204 $VerNum = readStringVersion($Part);
18205 }
18206 if($VerNum ne "")
18207 {
18208 $TargetVersion{$LibVersion} = $VerNum;
18209 if($DumpAPI) {
18210 printMsg("WARNING", "setting version number to $VerNum (use -vnum <num> option to change it)");
18211 }
18212 else {
18213 printMsg("WARNING", "setting ".($LibVersion==1?"1st":"2nd")." version number to \"$VerNum\" (use -v$LibVersion <num> option to change it)");
18214 }
18215 return $TargetVersion{$LibVersion};
18216 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040018217 }
18218 if($UsedAltDescr)
18219 {
18220 if($DumpAPI) {
18221 exitStatus("Error", "version number is not set (use -vnum <num> option)");
18222 }
18223 else {
18224 exitStatus("Error", ($LibVersion==1?"1st":"2nd")." version number is not set (use -v$LibVersion <num> option)");
18225 }
18226 }
18227}
18228
18229sub readStringVersion($)
18230{
18231 my $Str = $_[0];
18232 return "" if(not $Str);
18233 $Str=~s/\Q$TargetLibraryName\E//g;
18234 if($Str=~/(\/|\\|\w|\A)[\-\_]*(\d+[\d\.\-]+\d+|\d+)/)
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040018235 { # .../libssh-0.4.0/...
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040018236 return $2;
18237 }
18238 elsif(my $V = parse_libname($Str, "version", $OStarget)) {
18239 return $V;
18240 }
18241 return "";
18242}
18243
18244sub readLibs($)
18245{
18246 my $LibVersion = $_[0];
18247 if($OStarget eq "windows")
18248 { # dumpbin.exe will crash
18249 # without VS Environment
18250 check_win32_env();
18251 }
Andrey Ponomarenko16934472012-03-29 15:37:04 +040018252 readSymbols($LibVersion);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040018253 translateSymbols(keys(%{$Symbol_Library{$LibVersion}}), $LibVersion);
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040018254 translateSymbols(keys(%{$DepSymbol_Library{$LibVersion}}), $LibVersion);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040018255}
18256
18257sub dump_sorting($)
18258{
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +040018259 my $Hash = $_[0];
18260 return [] if(not $Hash);
18261 my @Keys = keys(%{$Hash});
18262 return [] if($#Keys<0);
18263 if($Keys[0]=~/\A\d+\Z/)
18264 { # numbers
18265 return [sort {int($a)<=>int($b)} @Keys];
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040018266 }
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +040018267 else
18268 { # strings
18269 return [sort {$a cmp $b} @Keys];
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040018270 }
18271}
18272
18273sub printMsg($$)
18274{
18275 my ($Type, $Msg) = @_;
18276 if($Type!~/\AINFO/) {
18277 $Msg = $Type.": ".$Msg;
18278 }
18279 if($Type!~/_C\Z/) {
18280 $Msg .= "\n";
18281 }
18282 if($Quiet)
18283 { # --quiet option
18284 appendFile($COMMON_LOG_PATH, $Msg);
18285 }
18286 else
18287 {
18288 if($Type eq "ERROR") {
18289 print STDERR $Msg;
18290 }
18291 else {
18292 print $Msg;
18293 }
18294 }
18295}
18296
18297sub exitStatus($$)
18298{
18299 my ($Code, $Msg) = @_;
18300 printMsg("ERROR", $Msg);
18301 exit($ERROR_CODE{$Code});
18302}
18303
18304sub exitReport()
18305{ # the tool has run without any errors
18306 printReport();
18307 if($COMPILE_ERRORS)
18308 { # errors in headers may add false positives/negatives
18309 exit($ERROR_CODE{"Compile_Error"});
18310 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040018311 if($BinaryOnly and $RESULT{"Binary"}{"Problems"})
18312 { # --binary
18313 exit($ERROR_CODE{"Incompatible"});
18314 }
18315 elsif($SourceOnly and $RESULT{"Source"}{"Problems"})
18316 { # --source
18317 exit($ERROR_CODE{"Incompatible"});
18318 }
18319 elsif($RESULT{"Source"}{"Problems"}
18320 or $RESULT{"Binary"}{"Problems"})
18321 { # default
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040018322 exit($ERROR_CODE{"Incompatible"});
18323 }
18324 else {
18325 exit($ERROR_CODE{"Compatible"});
18326 }
18327}
18328
18329sub readRules($)
18330{
18331 my $Kind = $_[0];
18332 if(not -f $RULES_PATH{$Kind}) {
18333 exitStatus("Module_Error", "can't access \'".$RULES_PATH{$Kind}."\'");
18334 }
18335 my $Content = readFile($RULES_PATH{$Kind});
18336 while(my $Rule = parseTag(\$Content, "rule"))
18337 {
18338 my $RId = parseTag(\$Rule, "id");
18339 my @Properties = ("Severity", "Change", "Effect", "Overcome", "Kind");
18340 foreach my $Prop (@Properties) {
18341 if(my $Value = parseTag(\$Rule, lc($Prop)))
18342 {
18343 $Value=~s/\n[ ]*//;
18344 $CompatRules{$Kind}{$RId}{$Prop} = $Value;
18345 }
18346 }
18347 if($CompatRules{$Kind}{$RId}{"Kind"}=~/\A(Symbols|Parameters)\Z/) {
18348 $CompatRules{$Kind}{$RId}{"Kind"} = "Symbols";
18349 }
18350 else {
18351 $CompatRules{$Kind}{$RId}{"Kind"} = "Types";
18352 }
18353 }
18354}
18355
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040018356sub getReportPath($)
18357{
18358 my $Level = $_[0];
18359 my $Dir = "compat_reports/$TargetLibraryName/".$Descriptor{1}{"Version"}."_to_".$Descriptor{2}{"Version"};
18360 if($Level eq "Binary")
18361 {
18362 if($BinaryReportPath)
18363 { # --bin-report-path
18364 return $BinaryReportPath;
18365 }
18366 elsif($OutputReportPath)
18367 { # --report-path
18368 return $OutputReportPath;
18369 }
18370 else
18371 { # default
18372 return $Dir."/abi_compat_report.$ReportFormat";
18373 }
18374 }
18375 elsif($Level eq "Source")
18376 {
18377 if($SourceReportPath)
18378 { # --src-report-path
18379 return $SourceReportPath;
18380 }
18381 elsif($OutputReportPath)
18382 { # --report-path
18383 return $OutputReportPath;
18384 }
18385 else
18386 { # default
18387 return $Dir."/src_compat_report.$ReportFormat";
18388 }
18389 }
18390 else
18391 {
18392 if($OutputReportPath)
18393 { # --report-path
18394 return $OutputReportPath;
18395 }
18396 else
18397 { # default
18398 return $Dir."/compat_report.$ReportFormat";
18399 }
18400 }
18401}
18402
18403sub printStatMsg($)
18404{
18405 my $Level = $_[0];
18406 printMsg("INFO", "total \"$Level\" compatibility problems: ".$RESULT{$Level}{"Problems"}.", warnings: ".$RESULT{$Level}{"Warnings"});
18407}
18408
18409sub listAffected($)
18410{
18411 my $Level = $_[0];
18412 my $List = "";
18413 foreach (keys(%{$TotalAffected{$Level}}))
18414 {
18415 if($StrictCompat and $TotalAffected{$Level}{$_} eq "Low")
18416 { # skip "Low"-severity problems
18417 next;
18418 }
18419 $List .= "$_\n";
18420 }
18421 my $Dir = get_dirname(getReportPath($Level));
18422 if($Level eq "Binary") {
18423 writeFile($Dir."/abi_affected.txt", $List);
18424 }
18425 elsif($Level eq "Source") {
18426 writeFile($Dir."/src_affected.txt", $List);
18427 }
18428}
18429
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040018430sub printReport()
18431{
18432 printMsg("INFO", "creating compatibility report ...");
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040018433 createReport();
18434 if($JoinReport or $DoubleReport)
18435 {
18436 if($RESULT{"Binary"}{"Problems"}
18437 or $RESULT{"Source"}{"Problems"}) {
18438 printMsg("INFO", "result: INCOMPATIBLE (Binary: ".$RESULT{"Binary"}{"Affected"}."\%, Source: ".$RESULT{"Source"}{"Affected"}."\%)");
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040018439 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040018440 else {
18441 printMsg("INFO", "result: COMPATIBLE");
18442 }
18443 printStatMsg("Binary");
18444 printStatMsg("Source");
18445 if($ListAffected)
18446 { # --list-affected
18447 listAffected("Binary");
18448 listAffected("Source");
18449 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040018450 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040018451 elsif($BinaryOnly)
18452 {
18453 if($RESULT{"Binary"}{"Problems"}) {
18454 printMsg("INFO", "result: INCOMPATIBLE (".$RESULT{"Binary"}{"Affected"}."\%)");
18455 }
18456 else {
18457 printMsg("INFO", "result: COMPATIBLE");
18458 }
18459 printStatMsg("Binary");
18460 if($ListAffected)
18461 { # --list-affected
18462 listAffected("Binary");
18463 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040018464 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040018465 elsif($SourceOnly)
18466 {
18467 if($RESULT{"Source"}{"Problems"}) {
18468 printMsg("INFO", "result: INCOMPATIBLE (".$RESULT{"Source"}{"Affected"}."\%)");
18469 }
18470 else {
18471 printMsg("INFO", "result: COMPATIBLE");
18472 }
18473 printStatMsg("Source");
18474 if($ListAffected)
18475 { # --list-affected
18476 listAffected("Source");
18477 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040018478 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040018479 if($StdOut)
18480 {
18481 if($JoinReport or not $DoubleReport)
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040018482 { # --binary or --source
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040018483 printMsg("INFO", "compatibility report has been generated to stdout");
18484 }
18485 else
18486 { # default
18487 printMsg("INFO", "compatibility reports have been generated to stdout");
18488 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040018489 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040018490 else
18491 {
18492 if($JoinReport)
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040018493 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040018494 printMsg("INFO", "see detailed report:\n ".getReportPath("Join"));
18495 }
18496 elsif($DoubleReport)
18497 { # default
18498 printMsg("INFO", "see detailed reports:\n ".getReportPath("Binary")."\n ".getReportPath("Source"));
18499 }
18500 elsif($BinaryOnly)
18501 { # --binary
18502 printMsg("INFO", "see detailed report:\n ".getReportPath("Binary"));
18503 }
18504 elsif($SourceOnly)
18505 { # --source
18506 printMsg("INFO", "see detailed report:\n ".getReportPath("Source"));
18507 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040018508 }
18509}
18510
18511sub check_win32_env()
18512{
18513 if(not $ENV{"DevEnvDir"}
18514 or not $ENV{"LIB"}) {
18515 exitStatus("Error", "can't start without VS environment (vsvars32.bat)");
18516 }
18517}
18518
Andrey Ponomarenko5c09ef32012-06-14 18:17:33 +040018519sub diffSets($$)
18520{
18521 my ($S1, $S2) = @_;
18522 my @SK1 = keys(%{$S1});
18523 my @SK2 = keys(%{$S2});
18524 if($#SK1!=$#SK2) {
18525 return 1;
18526 }
18527 foreach my $K1 (@SK1)
18528 {
18529 if(not defined $S2->{$K1}) {
18530 return 1;
18531 }
18532 }
18533 return 0;
18534}
18535
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040018536sub create_ABI_Dump()
18537{
18538 if(not -e $DumpAPI) {
18539 exitStatus("Access_Error", "can't access \'$DumpAPI\'");
18540 }
18541 # check the archive utilities
18542 if($OSgroup eq "windows")
18543 { # using zip
18544 my $ZipCmd = get_CmdPath("zip");
18545 if(not $ZipCmd) {
18546 exitStatus("Not_Found", "can't find \"zip\"");
18547 }
18548 }
18549 else
18550 { # using tar and gzip
18551 my $TarCmd = get_CmdPath("tar");
18552 if(not $TarCmd) {
18553 exitStatus("Not_Found", "can't find \"tar\"");
18554 }
18555 my $GzipCmd = get_CmdPath("gzip");
18556 if(not $GzipCmd) {
18557 exitStatus("Not_Found", "can't find \"gzip\"");
18558 }
18559 }
18560 my @DParts = split(/\s*,\s*/, $DumpAPI);
18561 foreach my $Part (@DParts)
18562 {
18563 if(not -e $Part) {
18564 exitStatus("Access_Error", "can't access \'$Part\'");
18565 }
18566 }
18567 checkVersionNum(1, $DumpAPI);
18568 foreach my $Part (@DParts)
18569 {
18570 if(isDump($Part)) {
18571 read_ABI_Dump(1, $Part);
18572 }
18573 else {
18574 readDescriptor(1, createDescriptor(1, $Part));
18575 }
18576 }
18577 initLogging(1);
18578 detect_default_paths("inc|lib|bin|gcc"); # complete analysis
18579 if(not $CheckHeadersOnly) {
18580 readLibs(1);
18581 }
18582 if($CheckHeadersOnly) {
18583 setLanguage(1, "C++");
18584 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +040018585 if(not $CheckObjectsOnly) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040018586 searchForHeaders(1);
18587 }
18588 $WORD_SIZE{1} = detectWordSize();
18589 if($Descriptor{1}{"Headers"}
18590 and not $Descriptor{1}{"Dump"}) {
18591 readHeaders(1);
18592 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +040018593 cleanDump(1);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040018594 if(not keys(%{$SymbolInfo{1}}))
18595 { # check if created dump is valid
18596 if(not $ExtendedCheck and not $CheckObjectsOnly)
18597 {
18598 if($CheckHeadersOnly) {
18599 exitStatus("Empty_Set", "the set of public symbols is empty");
18600 }
18601 else {
18602 exitStatus("Empty_Intersection", "the sets of public symbols in headers and libraries have empty intersection");
18603 }
18604 }
18605 }
18606 my %HeadersInfo = ();
18607 foreach my $HPath (keys(%{$Registered_Headers{1}}))
18608 { # headers info stored without paths in the dump
18609 $HeadersInfo{$Registered_Headers{1}{$HPath}{"Identity"}} = $Registered_Headers{1}{$HPath}{"Pos"};
18610 }
18611 printMsg("INFO", "creating library ABI dump ...");
18612 my %LibraryABI = (
18613 "TypeInfo" => $TypeInfo{1},
18614 "SymbolInfo" => $SymbolInfo{1},
18615 "Symbols" => $Library_Symbol{1},
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040018616 "DepSymbols" => $DepLibrary_Symbol{1},
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040018617 "SymbolVersion" => $SymVer{1},
18618 "LibraryVersion" => $Descriptor{1}{"Version"},
18619 "LibraryName" => $TargetLibraryName,
18620 "Language" => $COMMON_LANGUAGE{1},
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040018621 "SkipTypes" => $SkipTypes{1},
18622 "SkipSymbols" => $SkipSymbols{1},
18623 "SkipNameSpaces" => $SkipNameSpaces{1},
18624 "SkipHeaders" => $SkipHeadersList{1},
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040018625 "Headers" => \%HeadersInfo,
18626 "Constants" => $Constants{1},
18627 "NameSpaces" => $NestedNameSpaces{1},
18628 "Target" => $OStarget,
18629 "Arch" => getArch(1),
18630 "WordSize" => $WORD_SIZE{1},
18631 "GccVersion" => get_dumpversion($GCC_PATH),
18632 "ABI_DUMP_VERSION" => $ABI_DUMP_VERSION,
18633 "ABI_COMPLIANCE_CHECKER_VERSION" => $TOOL_VERSION
18634 );
Andrey Ponomarenko5c09ef32012-06-14 18:17:33 +040018635 if(diffSets($TargetHeaders{1}, \%HeadersInfo)) {
18636 $LibraryABI{"TargetHeaders"} = $TargetHeaders{1};
18637 }
18638 if($UseXML) {
18639 $LibraryABI{"XML_ABI_DUMP_VERSION"} = $XML_ABI_DUMP_VERSION;
18640 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040018641 if($ExtendedCheck)
18642 { # --ext option
18643 $LibraryABI{"Mode"} = "Extended";
18644 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040018645 if($BinaryOnly)
18646 { # --binary
18647 $LibraryABI{"BinOnly"} = 1;
18648 }
Andrey Ponomarenko5c09ef32012-06-14 18:17:33 +040018649
18650 my $ABI_DUMP = "";
18651 if($UseXML)
18652 {
18653 loadModule("XmlDump");
18654 $ABI_DUMP = createXmlDump(\%LibraryABI);
18655 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040018656 else
18657 { # default
Andrey Ponomarenko5c09ef32012-06-14 18:17:33 +040018658 $ABI_DUMP = Dumper(\%LibraryABI);
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040018659 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040018660 if($StdOut)
18661 { # --stdout option
Andrey Ponomarenko5c09ef32012-06-14 18:17:33 +040018662 print STDOUT $ABI_DUMP;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040018663 printMsg("INFO", "ABI dump has been generated to stdout");
18664 return;
18665 }
18666 else
18667 { # write to gzipped file
Andrey Ponomarenko5c09ef32012-06-14 18:17:33 +040018668 my $DumpPath = "abi_dumps/$TargetLibraryName/".$TargetLibraryName."_".$Descriptor{1}{"Version"}.".abi";
18669 $DumpPath .= ".".$AR_EXT; # gzipped by default
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040018670 if($OutputDumpPath)
18671 { # user defined path
18672 $DumpPath = $OutputDumpPath;
18673 }
Andrey Ponomarenko5c09ef32012-06-14 18:17:33 +040018674 my $Archive = ($DumpPath=~s/\Q.$AR_EXT\E\Z//g);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040018675 my ($DDir, $DName) = separate_path($DumpPath);
18676 my $DPath = $TMP_DIR."/".$DName;
Andrey Ponomarenko5c09ef32012-06-14 18:17:33 +040018677 if(not $Archive) {
18678 $DPath = $DumpPath;
18679 }
18680
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040018681 mkpath($DDir);
Andrey Ponomarenko85043792012-05-14 16:48:07 +040018682
18683 open(DUMP, ">", $DPath) || die ("can't open file \'$DPath\': $!\n");
Andrey Ponomarenko5c09ef32012-06-14 18:17:33 +040018684 print DUMP $ABI_DUMP;
Andrey Ponomarenko85043792012-05-14 16:48:07 +040018685 close(DUMP);
18686
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040018687 if(not -s $DPath) {
18688 exitStatus("Error", "can't create ABI dump because something is going wrong with the Data::Dumper module");
18689 }
Andrey Ponomarenko5c09ef32012-06-14 18:17:33 +040018690 if($Archive)
18691 {
18692 my $PkgPath = createArchive($DPath, $DDir);
18693 printMsg("INFO", "library ABI has been dumped to:\n $PkgPath");
18694 }
18695 else {
18696 printMsg("INFO", "library ABI has been dumped to:\n $DumpPath");
18697 }
18698
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040018699 printMsg("INFO", "you can transfer this dump everywhere and use instead of the ".$Descriptor{1}{"Version"}." version descriptor");
18700 }
18701}
18702
18703sub quickEmptyReports()
18704{ # Quick "empty" reports
18705 # 4 times faster than merging equal dumps
18706 # NOTE: the dump contains the "LibraryVersion" attribute
18707 # if you change the version, then your dump will be different
18708 # OVERCOME: use -v1 and v2 options for comparing dumps
18709 # and don't change version in the XML descriptor (and dumps)
18710 # OVERCOME 2: separate meta info from the dumps in ACC 2.0
18711 if(-s $Descriptor{1}{"Path"} == -s $Descriptor{2}{"Path"})
18712 {
18713 my $FilePath1 = unpackDump($Descriptor{1}{"Path"});
18714 my $FilePath2 = unpackDump($Descriptor{2}{"Path"});
18715 if($FilePath1 and $FilePath2)
18716 {
Andrey Ponomarenko85043792012-05-14 16:48:07 +040018717 local $/ = undef;
18718
18719 open(DUMP1, $FilePath1);
18720 my $Content1 = <DUMP1>;
18721 close(DUMP1);
18722
18723 open(DUMP2, $FilePath2);
18724 my $Content2 = <DUMP2>;
18725 close(DUMP2);
18726
18727 if($Content1 eq $Content2)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040018728 {
Andrey Ponomarenko85043792012-05-14 16:48:07 +040018729 # clean memory
18730 undef $Content2;
18731
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040018732 # read a number of headers, libs, symbols and types
Andrey Ponomarenko85043792012-05-14 16:48:07 +040018733 my $ABIdump = eval($Content1);
18734
18735 # clean memory
18736 undef $Content1;
18737
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040018738 if(not $ABIdump) {
18739 exitStatus("Error", "internal error");
18740 }
18741 if(not $ABIdump->{"TypeInfo"})
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040018742 { # support for old dumps
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040018743 $ABIdump->{"TypeInfo"} = $ABIdump->{"TypeDescr"};
18744 }
18745 if(not $ABIdump->{"SymbolInfo"})
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040018746 { # support for old dumps
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040018747 $ABIdump->{"SymbolInfo"} = $ABIdump->{"FuncDescr"};
18748 }
18749 read_Headers_DumpInfo($ABIdump, 1);
18750 read_Libs_DumpInfo($ABIdump, 1);
18751 read_Machine_DumpInfo($ABIdump, 1);
18752 read_Machine_DumpInfo($ABIdump, 2);
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040018753
18754 %{$CheckedTypes{"Binary"}} = %{$ABIdump->{"TypeInfo"}};
18755 %{$CheckedTypes{"Source"}} = %{$ABIdump->{"TypeInfo"}};
18756
18757 %{$CheckedSymbols{"Binary"}} = %{$ABIdump->{"SymbolInfo"}};
18758 %{$CheckedSymbols{"Source"}} = %{$ABIdump->{"SymbolInfo"}};
18759
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040018760 $Descriptor{1}{"Version"} = $TargetVersion{1}?$TargetVersion{1}:$ABIdump->{"LibraryVersion"};
18761 $Descriptor{2}{"Version"} = $TargetVersion{2}?$TargetVersion{2}:$ABIdump->{"LibraryVersion"};
18762 exitReport();
18763 }
18764 }
18765 }
18766}
18767
18768sub initLogging($)
18769{
18770 my $LibVersion = $_[0];
18771 # create log directory
18772 my ($LOG_DIR, $LOG_FILE) = ("logs/$TargetLibraryName/".$Descriptor{$LibVersion}{"Version"}, "log.txt");
18773 if($OutputLogPath{$LibVersion})
18774 { # user-defined by -log-path option
18775 ($LOG_DIR, $LOG_FILE) = separate_path($OutputLogPath{$LibVersion});
18776 }
18777 if($LogMode ne "n") {
18778 mkpath($LOG_DIR);
18779 }
18780 $LOG_PATH{$LibVersion} = get_abs_path($LOG_DIR)."/".$LOG_FILE;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040018781 if($Debug)
18782 { # debug directory
18783 $DEBUG_PATH{$LibVersion} = "debug/$TargetLibraryName/".$Descriptor{$LibVersion}{"Version"};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040018784 }
Andrey Ponomarenko35c44fd2012-06-18 17:50:25 +040018785 resetLogging($LibVersion);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040018786}
18787
18788sub writeLog($$)
18789{
18790 my ($LibVersion, $Msg) = @_;
18791 if($LogMode ne "n") {
18792 appendFile($LOG_PATH{$LibVersion}, $Msg);
18793 }
18794}
18795
18796sub resetLogging($)
18797{
18798 my $LibVersion = $_[0];
18799 if($LogMode!~/a|n/)
18800 { # remove old log
18801 unlink($LOG_PATH{$LibVersion});
Andrey Ponomarenko35c44fd2012-06-18 17:50:25 +040018802 if($Debug) {
18803 rmtree($DEBUG_PATH{$LibVersion});
18804 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040018805 }
18806}
18807
18808sub printErrorLog($)
18809{
18810 my $LibVersion = $_[0];
18811 if($LogMode ne "n") {
18812 printMsg("ERROR", "see log for details:\n ".$LOG_PATH{$LibVersion}."\n");
18813 }
18814}
18815
18816sub isDump($)
18817{
18818 if(get_filename($_[0])=~/\A(.+)\.abi(\Q.tar.gz\E|\Q.zip\E|)\Z/)
18819 { # returns a name of package
18820 return $1;
18821 }
18822 return 0;
18823}
18824
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040018825sub compareInit()
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040018826{
18827 # read input XML descriptors or ABI dumps
18828 if(not $Descriptor{1}{"Path"}) {
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040018829 exitStatus("Error", "-old option is not specified");
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040018830 }
18831 my @DParts1 = split(/\s*,\s*/, $Descriptor{1}{"Path"});
18832 foreach my $Part (@DParts1)
18833 {
18834 if(not -e $Part) {
18835 exitStatus("Access_Error", "can't access \'$Part\'");
18836 }
18837 }
18838 if(not $Descriptor{2}{"Path"}) {
Andrey Ponomarenko0d5917f2012-04-16 16:44:09 +040018839 exitStatus("Error", "-new option is not specified");
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040018840 }
18841 my @DParts2 = split(/\s*,\s*/, $Descriptor{2}{"Path"});
18842 foreach my $Part (@DParts2)
18843 {
18844 if(not -e $Part) {
18845 exitStatus("Access_Error", "can't access \'$Part\'");
18846 }
18847 }
18848 detect_default_paths("bin"); # to extract dumps
18849 if($#DParts1==0 and $#DParts2==0
18850 and isDump($Descriptor{1}{"Path"})
18851 and isDump($Descriptor{2}{"Path"}))
18852 { # optimization: equal ABI dumps
18853 quickEmptyReports();
18854 }
18855 checkVersionNum(1, $Descriptor{1}{"Path"});
18856 checkVersionNum(2, $Descriptor{2}{"Path"});
18857 printMsg("INFO", "preparation, please wait ...");
18858 foreach my $Part (@DParts1)
18859 {
18860 if(isDump($Part)) {
18861 read_ABI_Dump(1, $Part);
18862 }
18863 else {
18864 readDescriptor(1, createDescriptor(1, $Part));
18865 }
18866 }
18867 foreach my $Part (@DParts2)
18868 {
18869 if(isDump($Part)) {
18870 read_ABI_Dump(2, $Part);
18871 }
18872 else {
18873 readDescriptor(2, createDescriptor(2, $Part));
18874 }
18875 }
18876 initLogging(1);
18877 initLogging(2);
18878 # check consistency
18879 if(not $Descriptor{1}{"Headers"}
18880 and not $Descriptor{1}{"Libs"}) {
18881 exitStatus("Error", "descriptor d1 does not contain both header files and libraries info");
18882 }
18883 if(not $Descriptor{2}{"Headers"}
18884 and not $Descriptor{2}{"Libs"}) {
18885 exitStatus("Error", "descriptor d2 does not contain both header files and libraries info");
18886 }
18887 if($Descriptor{1}{"Headers"} and not $Descriptor{1}{"Libs"}
18888 and not $Descriptor{2}{"Headers"} and $Descriptor{2}{"Libs"}) {
18889 exitStatus("Error", "can't compare headers with $SLIB_TYPE libraries");
18890 }
18891 elsif(not $Descriptor{1}{"Headers"} and $Descriptor{1}{"Libs"}
18892 and $Descriptor{2}{"Headers"} and not $Descriptor{2}{"Libs"}) {
18893 exitStatus("Error", "can't compare $SLIB_TYPE libraries with headers");
18894 }
18895 if(not $Descriptor{1}{"Headers"}) {
18896 if($CheckHeadersOnly_Opt) {
18897 exitStatus("Error", "can't find header files info in descriptor d1");
18898 }
18899 }
18900 if(not $Descriptor{2}{"Headers"}) {
18901 if($CheckHeadersOnly_Opt) {
18902 exitStatus("Error", "can't find header files info in descriptor d2");
18903 }
18904 }
18905 if(not $Descriptor{1}{"Headers"}
18906 or not $Descriptor{2}{"Headers"}) {
18907 if(not $CheckObjectsOnly_Opt) {
18908 printMsg("WARNING", "comparing $SLIB_TYPE libraries only");
18909 $CheckObjectsOnly = 1;
18910 }
18911 }
18912 if(not $Descriptor{1}{"Libs"}) {
18913 if($CheckObjectsOnly_Opt) {
18914 exitStatus("Error", "can't find $SLIB_TYPE libraries info in descriptor d1");
18915 }
18916 }
18917 if(not $Descriptor{2}{"Libs"}) {
18918 if($CheckObjectsOnly_Opt) {
18919 exitStatus("Error", "can't find $SLIB_TYPE libraries info in descriptor d2");
18920 }
18921 }
18922 if(not $Descriptor{1}{"Libs"}
18923 or not $Descriptor{2}{"Libs"})
18924 { # comparing standalone header files
18925 # comparing ABI dumps created with --headers-only
18926 if(not $CheckHeadersOnly_Opt)
18927 {
18928 printMsg("WARNING", "checking headers only");
18929 $CheckHeadersOnly = 1;
18930 }
18931 }
18932 if($UseDumps)
18933 { # --use-dumps
18934 # parallel processing
18935 my $pid = fork();
18936 if($pid)
18937 { # dump on two CPU cores
18938 my @PARAMS = ("-dump", $Descriptor{1}{"Path"}, "-l", $TargetLibraryName);
18939 if($RelativeDirectory{1}) {
18940 @PARAMS = (@PARAMS, "-relpath", $RelativeDirectory{1});
18941 }
18942 if($OutputLogPath{1}) {
18943 @PARAMS = (@PARAMS, "-log-path", $OutputLogPath{1});
18944 }
18945 if($CrossGcc) {
18946 @PARAMS = (@PARAMS, "-cross-gcc", $CrossGcc);
18947 }
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040018948 if($Quiet)
18949 {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040018950 @PARAMS = (@PARAMS, "-quiet");
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040018951 @PARAMS = (@PARAMS, "-logging-mode", "a");
18952 }
18953 elsif($LogMode and $LogMode ne "w")
18954 { # "w" is default
18955 @PARAMS = (@PARAMS, "-logging-mode", $LogMode);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040018956 }
18957 if($ExtendedCheck) {
18958 @PARAMS = (@PARAMS, "-extended");
18959 }
18960 if($UserLang) {
18961 @PARAMS = (@PARAMS, "-lang", $UserLang);
18962 }
18963 if($TargetVersion{1}) {
18964 @PARAMS = (@PARAMS, "-vnum", $TargetVersion{1});
18965 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +040018966 if($BinaryOnly) {
18967 @PARAMS = (@PARAMS, "-binary");
18968 }
18969 if($SourceOnly) {
18970 @PARAMS = (@PARAMS, "-source");
18971 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040018972 if($SortDump) {
18973 @PARAMS = (@PARAMS, "-sort");
18974 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +040018975 if($Debug)
18976 {
18977 @PARAMS = (@PARAMS, "-debug");
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040018978 printMsg("INFO", "running perl $0 @PARAMS");
Andrey Ponomarenko85043792012-05-14 16:48:07 +040018979 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040018980 system("perl", $0, @PARAMS);
18981 if($?) {
18982 exit(1);
18983 }
18984 }
18985 else
18986 { # child
18987 my @PARAMS = ("-dump", $Descriptor{2}{"Path"}, "-l", $TargetLibraryName);
18988 if($RelativeDirectory{2}) {
18989 @PARAMS = (@PARAMS, "-relpath", $RelativeDirectory{2});
18990 }
18991 if($OutputLogPath{2}) {
18992 @PARAMS = (@PARAMS, "-log-path", $OutputLogPath{2});
18993 }
18994 if($CrossGcc) {
18995 @PARAMS = (@PARAMS, "-cross-gcc", $CrossGcc);
18996 }
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040018997 if($Quiet)
18998 {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040018999 @PARAMS = (@PARAMS, "-quiet");
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040019000 @PARAMS = (@PARAMS, "-logging-mode", "a");
19001 }
19002 elsif($LogMode and $LogMode ne "w")
19003 { # "w" is default
19004 @PARAMS = (@PARAMS, "-logging-mode", $LogMode);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040019005 }
19006 if($ExtendedCheck) {
19007 @PARAMS = (@PARAMS, "-extended");
19008 }
19009 if($UserLang) {
19010 @PARAMS = (@PARAMS, "-lang", $UserLang);
19011 }
19012 if($TargetVersion{2}) {
19013 @PARAMS = (@PARAMS, "-vnum", $TargetVersion{2});
19014 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +040019015 if($BinaryOnly) {
19016 @PARAMS = (@PARAMS, "-binary");
19017 }
19018 if($SourceOnly) {
19019 @PARAMS = (@PARAMS, "-source");
19020 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040019021 if($SortDump) {
19022 @PARAMS = (@PARAMS, "-sort");
19023 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +040019024 if($Debug)
19025 {
19026 @PARAMS = (@PARAMS, "-debug");
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040019027 printMsg("INFO", "running perl $0 @PARAMS");
Andrey Ponomarenko85043792012-05-14 16:48:07 +040019028 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040019029 system("perl", $0, @PARAMS);
19030 if($?) {
19031 exit(1);
19032 }
19033 else {
19034 exit(0);
19035 }
19036 }
19037 waitpid($pid, 0);
19038 my @CMP_PARAMS = ("-l", $TargetLibraryName);
19039 @CMP_PARAMS = (@CMP_PARAMS, "-d1", "abi_dumps/$TargetLibraryName/".$TargetLibraryName."_".$Descriptor{1}{"Version"}.".abi.$AR_EXT");
19040 @CMP_PARAMS = (@CMP_PARAMS, "-d2", "abi_dumps/$TargetLibraryName/".$TargetLibraryName."_".$Descriptor{2}{"Version"}.".abi.$AR_EXT");
19041 if($TargetLibraryFName ne $TargetLibraryName) {
19042 @CMP_PARAMS = (@CMP_PARAMS, "-l-full", $TargetLibraryFName);
19043 }
19044 if($ShowRetVal) {
19045 @CMP_PARAMS = (@CMP_PARAMS, "-show-retval");
19046 }
19047 if($CrossGcc) {
19048 @CMP_PARAMS = (@CMP_PARAMS, "-cross-gcc", $CrossGcc);
19049 }
Andrey Ponomarenko35c44fd2012-06-18 17:50:25 +040019050 @CMP_PARAMS = (@CMP_PARAMS, "-logging-mode", "a");
19051 if($Quiet) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040019052 @CMP_PARAMS = (@CMP_PARAMS, "-quiet");
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040019053 }
19054 if($ReportFormat and $ReportFormat ne "html")
19055 { # HTML is default format
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040019056 @CMP_PARAMS = (@CMP_PARAMS, "-report-format", $ReportFormat);
19057 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040019058 if($OutputReportPath) {
19059 @CMP_PARAMS = (@CMP_PARAMS, "-report-path", $OutputReportPath);
19060 }
19061 if($BinaryReportPath) {
19062 @CMP_PARAMS = (@CMP_PARAMS, "-bin-report-path", $BinaryReportPath);
19063 }
19064 if($SourceReportPath) {
19065 @CMP_PARAMS = (@CMP_PARAMS, "-src-report-path", $SourceReportPath);
19066 }
19067 if($LoggingPath) {
19068 @CMP_PARAMS = (@CMP_PARAMS, "-log-path", $LoggingPath);
19069 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +040019070 if($Browse) {
19071 @CMP_PARAMS = (@CMP_PARAMS, "-browse", $Browse);
19072 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040019073 if($OpenReport) {
19074 @CMP_PARAMS = (@CMP_PARAMS, "-open");
19075 }
19076 if($Debug)
19077 {
19078 @CMP_PARAMS = (@CMP_PARAMS, "-debug");
19079 printMsg("INFO", "running perl $0 @CMP_PARAMS");
Andrey Ponomarenko85043792012-05-14 16:48:07 +040019080 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040019081 system("perl", $0, @CMP_PARAMS);
19082 exit($?>>8);
19083 }
19084 if(not $Descriptor{1}{"Dump"}
19085 or not $Descriptor{2}{"Dump"})
19086 { # need GCC toolchain to analyze
19087 # header files and libraries
19088 detect_default_paths("inc|lib|gcc");
19089 }
19090 if(not $Descriptor{1}{"Dump"})
19091 {
19092 if(not $CheckHeadersOnly) {
19093 readLibs(1);
19094 }
19095 if($CheckHeadersOnly) {
19096 setLanguage(1, "C++");
19097 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +040019098 if(not $CheckObjectsOnly) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040019099 searchForHeaders(1);
19100 }
19101 $WORD_SIZE{1} = detectWordSize();
19102 }
19103 if(not $Descriptor{2}{"Dump"})
19104 {
19105 if(not $CheckHeadersOnly) {
19106 readLibs(2);
19107 }
19108 if($CheckHeadersOnly) {
19109 setLanguage(2, "C++");
19110 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +040019111 if(not $CheckObjectsOnly) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040019112 searchForHeaders(2);
19113 }
19114 $WORD_SIZE{2} = detectWordSize();
19115 }
19116 if($WORD_SIZE{1} ne $WORD_SIZE{2})
19117 { # support for old ABI dumps
19118 # try to synch different WORD sizes
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040019119 if(not checkDump(1, "2.1"))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040019120 {
19121 $WORD_SIZE{1} = $WORD_SIZE{2};
19122 printMsg("WARNING", "set WORD size to ".$WORD_SIZE{2}." bytes");
19123 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040019124 elsif(not checkDump(2, "2.1"))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040019125 {
19126 $WORD_SIZE{2} = $WORD_SIZE{1};
19127 printMsg("WARNING", "set WORD size to ".$WORD_SIZE{1}." bytes");
19128 }
19129 }
19130 elsif(not $WORD_SIZE{1}
19131 and not $WORD_SIZE{2})
19132 { # support for old ABI dumps
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040019133 $WORD_SIZE{1} = "4";
19134 $WORD_SIZE{2} = "4";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040019135 }
19136 if($Descriptor{1}{"Dump"})
19137 { # support for old ABI dumps
19138 prepareTypes(1);
19139 }
19140 if($Descriptor{2}{"Dump"})
19141 { # support for old ABI dumps
19142 prepareTypes(2);
19143 }
19144 if($AppPath and not keys(%{$Symbol_Library{1}})) {
19145 printMsg("WARNING", "the application ".get_filename($AppPath)." has no symbols imported from the $SLIB_TYPE libraries");
19146 }
19147 # started to process input data
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040019148 if(not $CheckObjectsOnly)
19149 {
19150 if($Descriptor{1}{"Headers"}
19151 and not $Descriptor{1}{"Dump"}) {
19152 readHeaders(1);
19153 }
19154 if($Descriptor{2}{"Headers"}
19155 and not $Descriptor{2}{"Dump"}) {
19156 readHeaders(2);
19157 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040019158 }
Andrey Ponomarenko85043792012-05-14 16:48:07 +040019159
19160 # clean memory
19161 %SystemHeaders = ();
19162 %mangled_name_gcc = ();
19163
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040019164 prepareSymbols(1);
19165 prepareSymbols(2);
Andrey Ponomarenko16934472012-03-29 15:37:04 +040019166
Andrey Ponomarenko85043792012-05-14 16:48:07 +040019167 # clean memory
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040019168 %SymbolInfo = ();
Andrey Ponomarenko16934472012-03-29 15:37:04 +040019169
19170 # Virtual Tables
19171 registerVTable(1);
19172 registerVTable(2);
19173
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040019174 if(not checkDump(1, "1.22")
19175 and checkDump(2, "1.22"))
Andrey Ponomarenko16934472012-03-29 15:37:04 +040019176 { # support for old ABI dumps
19177 foreach my $ClassName (keys(%{$VirtualTable{2}}))
19178 {
19179 if($ClassName=~/</)
19180 { # templates
19181 if(not defined $VirtualTable{1}{$ClassName})
19182 { # synchronize
19183 delete($VirtualTable{2}{$ClassName});
19184 }
19185 }
19186 }
19187 }
19188
19189 registerOverriding(1);
19190 registerOverriding(2);
19191
19192 setVirtFuncPositions(1);
19193 setVirtFuncPositions(2);
19194
19195 # Other
19196 addParamNames(1);
19197 addParamNames(2);
19198
19199 detectChangedTypedefs();
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040019200}
19201
19202sub compareAPIs($)
19203{
19204 my $Level = $_[0];
19205 readRules($Level);
19206 if($Level eq "Binary") {
19207 printMsg("INFO", "comparing ABIs ...");
19208 }
19209 else {
19210 printMsg("INFO", "comparing APIs ...");
19211 }
19212 if($CheckHeadersOnly
19213 or $Level eq "Source")
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040019214 { # added/removed in headers
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040019215 detectAdded_H($Level);
19216 detectRemoved_H($Level);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040019217 }
19218 else
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040019219 { # added/removed in libs
19220 detectAdded($Level);
19221 detectRemoved($Level);
19222 }
19223 if(not $CheckObjectsOnly)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040019224 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040019225 mergeSignatures($Level);
19226 if(keys(%{$CheckedSymbols{$Level}})) {
19227 mergeConstants($Level);
19228 }
19229 }
19230 if($CheckHeadersOnly
19231 or $Level eq "Source")
19232 { # added/removed in headers
19233 mergeHeaders($Level);
19234 }
19235 else
19236 { # added/removed in libs
19237 mergeLibs($Level);
19238 if($CheckImpl
19239 and $Level eq "Binary") {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040019240 mergeImpl();
19241 }
19242 }
19243}
19244
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040019245sub writeOpts()
19246{
19247 my %Opts = (
19248 "OStarget"=>$OStarget,
19249 "Debug"=>$Debug,
19250 "Quiet"=>$Quiet,
19251 "LogMode"=>$LogMode,
19252 "CheckHeadersOnly"=>$CheckHeadersOnly,
19253
19254 "SystemRoot"=>$SystemRoot,
19255 "MODULES_DIR"=>$MODULES_DIR,
19256 "GCC_PATH"=>$GCC_PATH,
19257 "TargetSysInfo"=>$TargetSysInfo,
19258 "CrossPrefix"=>$CrossPrefix,
19259 "TargetLibraryName"=>$TargetLibraryName,
19260 "CrossGcc"=>$CrossGcc,
19261 "UseStaticLibs"=>$UseStaticLibs,
19262 "NoStdInc"=>$NoStdInc
19263 );
19264 return \%Opts;
19265}
19266
19267sub get_CoreError($)
19268{
19269 my %CODE_ERROR = reverse(%ERROR_CODE);
19270 return $CODE_ERROR{$_[0]};
19271}
19272
19273sub scenario()
19274{
19275 if($StdOut)
19276 { # enable quiet mode
19277 $Quiet = 1;
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040019278 $JoinReport = 1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040019279 }
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040019280 if(not $LogMode)
19281 { # default
19282 $LogMode = "w";
19283 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040019284 if($UserLang)
19285 { # --lang=C++
19286 $UserLang = uc($UserLang);
19287 $COMMON_LANGUAGE{1}=$UserLang;
19288 $COMMON_LANGUAGE{2}=$UserLang;
19289 }
19290 if($LoggingPath)
19291 {
19292 $OutputLogPath{1} = $LoggingPath;
19293 $OutputLogPath{2} = $LoggingPath;
19294 if($Quiet) {
19295 $COMMON_LOG_PATH = $LoggingPath;
19296 }
19297 }
Andrey Ponomarenko5c09ef32012-06-14 18:17:33 +040019298 if($OutputDumpPath)
19299 { # validate
19300 if($OutputDumpPath!~/\.abi(\.\Q$AR_EXT\E|)\Z/) {
19301 exitStatus("Error", "the dump path should be a path to *.abi.$AR_EXT or *.abi file");
19302 }
19303 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040019304 if($BinaryOnly and $SourceOnly)
19305 { # both --binary and --source
19306 # is the default mode
19307 $DoubleReport = 1;
19308 $JoinReport = 0;
19309 $BinaryOnly = 0;
19310 $SourceOnly = 0;
19311 if($OutputReportPath)
19312 { # --report-path
19313 $DoubleReport = 0;
19314 $JoinReport = 1;
19315 }
19316 }
19317 elsif($BinaryOnly or $SourceOnly)
19318 { # --binary or --source
19319 $DoubleReport = 0;
19320 $JoinReport = 0;
19321 }
19322 if($UseXML)
19323 { # --xml option
19324 $ReportFormat = "xml";
Andrey Ponomarenko5c09ef32012-06-14 18:17:33 +040019325 $DumpFormat = "xml";
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040019326 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040019327 if($ReportFormat)
19328 { # validate
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040019329 $ReportFormat = lc($ReportFormat);
19330 if($ReportFormat!~/\A(xml|html|htm)\Z/) {
Andrey Ponomarenko5c09ef32012-06-14 18:17:33 +040019331 exitStatus("Error", "unknown report format \'$ReportFormat\'");
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040019332 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040019333 if($ReportFormat eq "htm")
19334 { # HTM == HTML
19335 $ReportFormat = "html";
19336 }
19337 elsif($ReportFormat eq "xml")
19338 { # --report-format=XML equal to --xml
19339 $UseXML = 1;
19340 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040019341 }
19342 else
19343 { # default: HTML
19344 $ReportFormat = "html";
19345 }
Andrey Ponomarenko5c09ef32012-06-14 18:17:33 +040019346 if($DumpFormat)
19347 { # validate
19348 $DumpFormat = lc($DumpFormat);
19349 if($DumpFormat!~/\A(xml|perl)\Z/) {
19350 exitStatus("Error", "unknown ABI dump format \'$DumpFormat\'");
19351 }
19352 if($DumpFormat eq "xml")
19353 { # --dump-format=XML equal to --xml
19354 $UseXML = 1;
19355 }
19356 }
19357 else
19358 { # default: HTML
19359 $DumpFormat = "perl";
19360 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040019361 if($Quiet and $LogMode!~/a|n/)
19362 { # --quiet log
19363 if(-f $COMMON_LOG_PATH) {
19364 unlink($COMMON_LOG_PATH);
19365 }
19366 }
19367 if($TestTool and $UseDumps)
19368 { # --test && --use-dumps == --test-dump
19369 $TestDump = 1;
19370 }
19371 if($Help) {
19372 HELP_MESSAGE();
19373 exit(0);
19374 }
19375 if($InfoMsg) {
19376 INFO_MESSAGE();
19377 exit(0);
19378 }
19379 if($ShowVersion) {
19380 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.");
19381 exit(0);
19382 }
19383 if($DumpVersion) {
19384 printMsg("INFO", $TOOL_VERSION);
19385 exit(0);
19386 }
19387 if($ExtendedCheck) {
19388 $CheckHeadersOnly = 1;
19389 }
19390 if($SystemRoot_Opt)
19391 { # user defined root
19392 if(not -e $SystemRoot_Opt) {
19393 exitStatus("Access_Error", "can't access \'$SystemRoot\'");
19394 }
19395 $SystemRoot = $SystemRoot_Opt;
19396 $SystemRoot=~s/[\/]+\Z//g;
19397 if($SystemRoot) {
19398 $SystemRoot = get_abs_path($SystemRoot);
19399 }
19400 }
19401 $Data::Dumper::Sortkeys = 1;
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +040019402
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040019403 if($SortDump)
19404 {
19405 $Data::Dumper::Useperl = 1;
19406 $Data::Dumper::Sortkeys = \&dump_sorting;
19407 }
Andrey Ponomarenko989a50b2012-04-03 12:24:22 +040019408
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040019409 if($TargetLibsPath)
19410 {
19411 if(not -f $TargetLibsPath) {
19412 exitStatus("Access_Error", "can't access file \'$TargetLibsPath\'");
19413 }
19414 foreach my $Lib (split(/\s*\n\s*/, readFile($TargetLibsPath))) {
19415 $TargetLibs{$Lib} = 1;
19416 }
19417 }
19418 if($TargetHeadersPath)
19419 { # --headers-list
19420 if(not -f $TargetHeadersPath) {
19421 exitStatus("Access_Error", "can't access file \'$TargetHeadersPath\'");
19422 }
19423 foreach my $Header (split(/\s*\n\s*/, readFile($TargetHeadersPath)))
19424 {
19425 $TargetHeaders{1}{$Header} = 1;
19426 $TargetHeaders{2}{$Header} = 1;
19427 }
19428 }
19429 if($TargetHeader)
19430 { # --header
19431 $TargetHeaders{1}{$TargetHeader} = 1;
19432 $TargetHeaders{2}{$TargetHeader} = 1;
19433 }
19434 if($TestTool
19435 or $TestDump)
19436 { # --test, --test-dump
19437 detect_default_paths("bin|gcc"); # to compile libs
19438 loadModule("RegTests");
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040019439 testTool($TestDump, $Debug, $Quiet, $ExtendedCheck, $LogMode,
19440 $ReportFormat, $LIB_EXT, $GCC_PATH, $Browse, $OpenReport, $SortDump);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040019441 exit(0);
19442 }
19443 if($DumpSystem)
19444 { # --dump-system
19445 loadModule("SysCheck");
19446 if($DumpSystem=~/\.xml\Z/)
19447 { # system XML descriptor
19448 if(not -f $DumpSystem) {
19449 exitStatus("Access_Error", "can't access file \'$DumpSystem\'");
19450 }
19451 my $Ret = readSystemDescriptor(readFile($DumpSystem));
19452 foreach (@{$Ret->{"Tools"}}) {
19453 $SystemPaths{"bin"}{$_} = 1;
19454 $TargetTools{$_}=1;
19455 }
19456 if($Ret->{"CrossPrefix"}) {
19457 $CrossPrefix = $Ret->{"CrossPrefix"};
19458 }
19459 }
19460 elsif($SystemRoot_Opt)
19461 { # -sysroot "/" option
19462 # default target: /usr/lib, /usr/include
19463 # search libs: /usr/lib and /lib
19464 if(not -e $SystemRoot."/usr/lib") {
19465 exitStatus("Access_Error", "can't access '".$SystemRoot."/usr/lib'");
19466 }
19467 if(not -e $SystemRoot."/lib") {
19468 exitStatus("Access_Error", "can't access '".$SystemRoot."/lib'");
19469 }
19470 if(not -e $SystemRoot."/usr/include") {
19471 exitStatus("Access_Error", "can't access '".$SystemRoot."/usr/include'");
19472 }
19473 readSystemDescriptor("
19474 <name>
19475 $DumpSystem
19476 </name>
19477 <headers>
19478 $SystemRoot/usr/include
19479 </headers>
19480 <libs>
19481 $SystemRoot/usr/lib
19482 </libs>
19483 <search_libs>
19484 $SystemRoot/lib
19485 </search_libs>");
19486 }
19487 else {
19488 exitStatus("Error", "-sysroot <dirpath> option should be specified, usually it's \"/\"");
19489 }
19490 detect_default_paths("bin|gcc"); # to check symbols
19491 if($OStarget eq "windows")
19492 { # to run dumpbin.exe
19493 # and undname.exe
19494 check_win32_env();
19495 }
19496 dumpSystem(writeOpts());
19497 exit(0);
19498 }
19499 if($CmpSystems)
19500 { # --cmp-systems
19501 detect_default_paths("bin"); # to extract dumps
19502 loadModule("SysCheck");
19503 cmpSystems($Descriptor{1}{"Path"}, $Descriptor{2}{"Path"}, writeOpts());
19504 exit(0);
19505 }
19506 if($GenerateTemplate) {
19507 generateTemplate();
19508 exit(0);
19509 }
19510 if(not $TargetLibraryName) {
19511 exitStatus("Error", "library name is not selected (option -l <name>)");
19512 }
19513 else
19514 { # validate library name
19515 if($TargetLibraryName=~/[\*\/\\]/) {
19516 exitStatus("Error", "\"\\\", \"\/\" and \"*\" symbols are not allowed in the library name");
19517 }
19518 }
19519 if(not $TargetLibraryFName) {
19520 $TargetLibraryFName = $TargetLibraryName;
19521 }
19522 if($CheckHeadersOnly_Opt and $CheckObjectsOnly_Opt) {
19523 exitStatus("Error", "you can't specify both -headers-only and -objects-only options at the same time");
19524 }
19525 if($SymbolsListPath)
19526 {
19527 if(not -f $SymbolsListPath) {
19528 exitStatus("Access_Error", "can't access file \'$SymbolsListPath\'");
19529 }
19530 foreach my $Interface (split(/\s*\n\s*/, readFile($SymbolsListPath))) {
19531 $SymbolsList{$Interface} = 1;
19532 }
19533 }
19534 if($SkipHeadersPath)
19535 {
19536 if(not -f $SkipHeadersPath) {
19537 exitStatus("Access_Error", "can't access file \'$SkipHeadersPath\'");
19538 }
19539 foreach my $Path (split(/\s*\n\s*/, readFile($SkipHeadersPath)))
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040019540 { # register for both versions
19541 $SkipHeadersList{1}{$Path} = 1;
19542 $SkipHeadersList{2}{$Path} = 1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040019543 my ($CPath, $Type) = classifyPath($Path);
19544 $SkipHeaders{1}{$Type}{$CPath} = 1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040019545 $SkipHeaders{2}{$Type}{$CPath} = 1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040019546 }
19547 }
19548 if($ParamNamesPath)
19549 {
19550 if(not -f $ParamNamesPath) {
19551 exitStatus("Access_Error", "can't access file \'$ParamNamesPath\'");
19552 }
19553 foreach my $Line (split(/\n/, readFile($ParamNamesPath)))
19554 {
19555 if($Line=~s/\A(\w+)\;//)
19556 {
19557 my $Interface = $1;
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040019558 if($Line=~/;(\d+);/)
19559 {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040019560 while($Line=~s/(\d+);(\w+)//) {
19561 $AddIntParams{$Interface}{$1}=$2;
19562 }
19563 }
Andrey Ponomarenko62ddcfa2012-05-23 13:13:15 +040019564 else
19565 {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040019566 my $Num = 0;
19567 foreach my $Name (split(/;/, $Line)) {
19568 $AddIntParams{$Interface}{$Num++}=$Name;
19569 }
19570 }
19571 }
19572 }
19573 }
19574 if($AppPath)
19575 {
19576 if(not -f $AppPath) {
19577 exitStatus("Access_Error", "can't access file \'$AppPath\'");
19578 }
Andrey Ponomarenko16934472012-03-29 15:37:04 +040019579 foreach my $Interface (readSymbols_App($AppPath)) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040019580 $SymbolsList_App{$Interface} = 1;
19581 }
19582 }
19583 if($DumpAPI)
19584 { # --dump-abi
19585 # make an API dump
19586 create_ABI_Dump();
19587 exit($COMPILE_ERRORS);
19588 }
19589 # default: compare APIs
19590 # -d1 <path>
19591 # -d2 <path>
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040019592 compareInit();
19593 if($JoinReport or $DoubleReport)
19594 {
19595 compareAPIs("Binary");
19596 compareAPIs("Source");
19597 }
19598 elsif($BinaryOnly) {
19599 compareAPIs("Binary");
19600 }
19601 elsif($SourceOnly) {
19602 compareAPIs("Source");
19603 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040019604 exitReport();
19605}
19606
19607scenario();